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