blob: f1b13eec1c78671d3fda675cea51b37caed25b1e [file] [log] [blame]
Brian Silverman26e4e522015-12-17 01:56:40 -05001/*----------------------------------------------------------------------------*/
Brian Silverman1a675112016-02-20 20:42:49 -05002/* Copyright (c) FIRST 2014-2016. All Rights Reserved. */
Brian Silverman26e4e522015-12-17 01:56:40 -05003/* Open Source Software - may be modified and shared by FRC teams. The code */
Brian Silverman1a675112016-02-20 20:42:49 -05004/* must be accompanied by the FIRST BSD license file in the root directory of */
5/* the project. */
Brian Silverman26e4e522015-12-17 01:56:40 -05006/*----------------------------------------------------------------------------*/
Brian Silverman1a675112016-02-20 20:42:49 -05007
Brian Silverman26e4e522015-12-17 01:56:40 -05008#include <stdio.h>
9#include <sys/types.h>
10#include <sys/stat.h>
11#include <unistd.h>
12#include <string.h>
13#include <math.h>
14#include <stdlib.h>
15#include <stdarg.h>
16
17#include "Vision/BaeUtilities.h"
18#include "Servo.h"
19#include "Timer.h"
20
21/** @file
22 * Utility functions
23 */
24
25/**
26 * debug output flag options:
27 * DEBUG_OFF, DEBUG_MOSTLY_OFF, DEBUG_SCREEN_ONLY, DEBUG_FILE_ONLY,
28 * DEBUG_SCREEN_AND_FILE
29 */
30static DebugOutputType dprintfFlag = DEBUG_OFF;
31
32/**
33 * Set the debug flag to print to screen, file on cRIO, both or neither
34 * @param tempString The format string.
35 */
36void SetDebugFlag(DebugOutputType flag) { dprintfFlag = flag; }
37
38/**
39 * Debug print to a file and/or a terminal window.
40 * Call like you would call printf.
41 * Set functionName in the function if you want the correct function name to
42 * print out.
43 * The file line number will also be printed.
44 * @param tempString The format string.
45 */
46void dprintf(const char *tempString, ...) /* Variable argument list */
47{
48 va_list args; /* Input argument list */
49 int line_number; /* Line number passed in argument */
50 int type;
51 const char *functionName; /* Format passed in argument */
52 const char *fmt; /* Format passed in argument */
53 char text[512]; /* Text string */
54 char outtext[512]; /* Text string */
55 FILE *outfile_fd; /* Output file pointer */
56 char filepath[128]; /* Text string */
57 int fatalFlag = 0;
58 const char *filename;
59 int index;
60 int tempStringLen;
61
62 if (dprintfFlag == DEBUG_OFF) {
63 return;
64 }
65
66 va_start(args, tempString);
67
68 tempStringLen = strlen(tempString);
69 filename = tempString;
70 for (index = 0; index < tempStringLen; index++) {
71 if (tempString[index] == ' ') {
72 printf("ERROR in dprintf: malformed calling sequence (%s)\n", tempString);
73 va_end(args);
74 return;
75 }
76 if (tempString[index] == '\\' || tempString[index] == '/')
77 filename = tempString + index + 1;
78 }
79
80 /* Extract function name */
81 functionName = va_arg(args, const char *);
82
83 /* Extract line number from argument list */
84 line_number = va_arg(args, int);
85
86 /* Extract information type from argument list */
87 type = va_arg(args, int);
88
89 /* Extract format from argument list */
90 fmt = va_arg(args, const char *);
91
92 vsprintf(text, fmt, args);
93
94 va_end(args);
95
96 /* Format output statement */
97 switch (type) {
98 case DEBUG_TYPE:
99 sprintf(outtext, "[%s:%s@%04d] DEBUG %s\n", filename, functionName,
100 line_number, text);
101 break;
102 case INFO_TYPE:
103 sprintf(outtext, "[%s:%s@%04d] INFO %s\n", filename, functionName,
104 line_number, text);
105 break;
106 case ERROR_TYPE:
107 sprintf(outtext, "[%s:%s@%04d] ERROR %s\n", filename, functionName,
108 line_number, text);
109 break;
110 case CRITICAL_TYPE:
111 sprintf(outtext, "[%s:%s@%04d] CRITICAL %s\n", filename, functionName,
112 line_number, text);
113 break;
114 case FATAL_TYPE:
115 fatalFlag = 1;
116 sprintf(outtext, "[%s:%s@%04d] FATAL %s\n", filename, functionName,
117 line_number, text);
118 break;
119 default:
120 printf("ERROR in dprintf: malformed calling sequence\n");
121 return;
122 break;
123 }
124
125 sprintf(filepath, "%s.debug", filename);
126
127 /* Write output statement */
128 switch (dprintfFlag) {
129 default:
130 case DEBUG_OFF:
131 break;
132 case DEBUG_MOSTLY_OFF:
133 if (fatalFlag) {
134 if ((outfile_fd = fopen(filepath, "a+")) != nullptr) {
135 fwrite(outtext, sizeof(char), strlen(outtext), outfile_fd);
136 fclose(outfile_fd);
137 }
138 }
139 break;
140 case DEBUG_SCREEN_ONLY:
141 printf("%s", outtext);
142 break;
143 case DEBUG_FILE_ONLY:
144 if ((outfile_fd = fopen(filepath, "a+")) != nullptr) {
145 fwrite(outtext, sizeof(char), strlen(outtext), outfile_fd);
146 fclose(outfile_fd);
147 }
148 break;
149 case DEBUG_SCREEN_AND_FILE: // BOTH
150 printf("%s", outtext);
151 if ((outfile_fd = fopen(filepath, "a+")) != nullptr) {
152 fwrite(outtext, sizeof(char), strlen(outtext), outfile_fd);
153 fclose(outfile_fd);
154 }
155 break;
156 }
157}
158
159/**
160 * @brief Normalizes a value in a range, used for drive input
161 * @param position The position in the range, starting at 0
162 * @param range The size of the range that position is in
163 * @return The normalized position from -1 to +1
164 */
165double RangeToNormalized(double position, int range) {
166 return (((position * 2.0) / (double)range) - 1.0);
167}
168
169/**
170 * @brief Convert a normalized value to the corresponding value in a range.
171 * This is used to convert normalized values to the servo command range.
172 * @param normalizedValue The normalized value (in the -1 to +1 range)
173 * @param minRange The minimum of the range (0 is default)
174 * @param maxRange The maximum of the range (1 is default)
175 * @return The value in the range corresponding to the input normalized value
176 */
177float NormalizeToRange(float normalizedValue, float minRange, float maxRange) {
178 float range = maxRange - minRange;
179 float temp = (float)((normalizedValue / 2.0) + 0.5) * range;
180 return (temp + minRange);
181}
182float NormalizeToRange(float normalizedValue) {
183 return (float)((normalizedValue / 2.0) + 0.5);
184}
185
186/**
187 * @brief Displays an activity indicator to console.
188 * Call this function like you would call printf.
189 * @param fmt The format string
190*/
191void ShowActivity(char *fmt, ...) {
192 static char activity_indication_string[] = "|/-\\";
193 static int ai = 3;
194 va_list args;
195 char text[1024];
196
197 va_start(args, fmt);
198
199 vsprintf(text, fmt, args);
200
201 ai = ai == 3 ? 0 : ai + 1;
202
203 printf("%c %s \r", activity_indication_string[ai], text);
204 fflush(stdout);
205
206 va_end(args);
207}
208
209#define PI 3.14159265358979
210/**
211 * @brief Calculate sine wave increments (-1.0 to 1.0).
212 * The first time this is called, it sets up the time increment. Subsequent
213 * calls
214 * will give values along the sine wave depending on current time. If the wave
215 * is
216 * stopped and restarted, it must be reinitialized with a new "first call".
217 *
218 * @param period length of time to complete a complete wave
219 * @param sinStart Where to start the sine wave (0.0 = 2 pi, pi/2 = 1.0, etc.)
220 */
221double SinPosition(double *period, double sinStart) {
222 double rtnVal;
223 static double sinePeriod = 0.0;
224 static double timestamp;
225 double sinArg;
226
227 // 1st call
228 if (period != nullptr) {
229 sinePeriod = *period;
230 timestamp = GetTime();
231 return 0.0;
232 }
233
234 // Multiplying by 2*pi to the time difference makes sinePeriod work if it's
235 // measured in seconds.
236 // Adding sinStart to the part multiplied by PI, but not by 2, allows it to
237 // work as described in the comments.
238 sinArg = PI * ((2.0 * (GetTime() - timestamp)) + sinStart) / sinePeriod;
239 rtnVal = sin(sinArg);
240 return (rtnVal);
241}
242
243/**
244 * @brief Find the elapsed time since a specified time.
245 * @param startTime The starting time
246 * @return How long it has been since the starting time
247 */
248double ElapsedTime(double startTime) {
249 double realTime = GetTime();
250 return (realTime - startTime);
251}
252
253/**
254 * @brief Initialize pan parameters
255 * @param period The number of seconds to complete one pan
256 */
257void panInit() {
258 double period = 3.0; // number of seconds for one complete pan
259 SinPosition(&period, 0.0); // initial call to set up time
260}
261
262void panInit(double period) {
263 if (period < 0.0) period = 3.0;
264 SinPosition(&period, 0.0); // initial call to set up time
265}
266
267/**
268 * @brief Move the horizontal servo back and forth.
269 * @param panServo The servo object to move
270 * @param sinStart The position on the sine wave to begin the pan
271 */
272void panForTarget(Servo *panServo) { panForTarget(panServo, 0.0); }
273
274void panForTarget(Servo *panServo, double sinStart) {
275 float normalizedSinPosition = (float)SinPosition(nullptr, sinStart);
276 float newServoPosition = NormalizeToRange(normalizedSinPosition);
277 panServo->Set(newServoPosition);
278 // ShowActivity ("pan x: normalized %f newServoPosition = %f" ,
279 // normalizedSinPosition, newServoPosition );
280}
281
282/** @brief Read a file and return non-comment output string
283
284Call the first time with 0 lineNumber to get the number of lines to read
285Then call with each lineNumber to get one camera parameter. There should
286be one property=value entry on each line, i.e. "exposure=auto"
287
288 * @param inputFile filename to read
289 * @param outputString one string
290 * @param lineNumber if 0, return number of lines; else return that line number
291 * @return int number of lines or -1 if error
292 **/
293int processFile(char *inputFile, char *outputString, int lineNumber) {
294 FILE *infile;
295 const int stringSize = 80; // max size of one line in file
296 char inputStr[stringSize];
297 inputStr[0] = '\0';
298 int lineCount = 0;
299
300 if (lineNumber < 0) return (-1);
301
302 if ((infile = fopen(inputFile, "r")) == nullptr) {
303 printf("Fatal error opening file %s\n", inputFile);
304 return (0);
305 }
306
307 while (!feof(infile)) {
308 if (fgets(inputStr, stringSize, infile) != nullptr) {
309 // Skip empty lines
310 if (emptyString(inputStr)) continue;
311 // Skip comment lines
312 if (inputStr[0] == '#' || inputStr[0] == '!') continue;
313
314 lineCount++;
315 if (lineNumber == 0)
316 continue;
317 else {
318 if (lineCount == lineNumber) break;
319 }
320 }
321 }
322
323 // close file
324 fclose(infile);
325 // if number lines requested return the count
326 if (lineNumber == 0) return (lineCount);
327 // check for input out of range
328 if (lineNumber > lineCount) return (-1);
329 // return the line selected; lineCount guaranteed to be greater than zero
330 stripString(inputStr);
331 strcpy(outputString, inputStr);
332 return (lineCount);
333}
334
335/** Ignore empty string
336 * @param string to check if empty
337 **/
338int emptyString(char *string) {
339 int i, len;
340
341 if (string == nullptr) return (1);
342
343 len = strlen(string);
344 for (i = 0; i < len; i++) {
345 // Ignore the following characters
346 if (string[i] == '\n' || string[i] == '\r' || string[i] == '\t' ||
347 string[i] == ' ')
348 continue;
349 return (0);
350 }
351 return (1);
352}
353
354/** Remove special characters from string
355 * @param string to process
356 **/
357void stripString(char *string) {
358 int i, j, len;
359
360 if (string == nullptr) return;
361
362 len = strlen(string);
363 for (i = 0, j = 0; i < len; i++) {
364 // Remove the following characters from the string
365 if (string[i] == '\n' || string[i] == '\r' || string[i] == '\"') continue;
366 // Copy anything else
367 string[j++] = string[i];
368 }
369 string[j] = '\0';
370}