blob: 55f724d3e4712b742678cb82934edb9d202a582b [file] [log] [blame]
jerrymf1579332013-02-07 01:56:28 +00001/*----------------------------------------------------------------------------*/
2/* Copyright (c) FIRST 2008. All Rights Reserved. */
3/* Open Source Software - may be modified and shared by FRC teams. The code */
4/* must be accompanied by the FIRST BSD license file in $(WIND_BASE)/WPILib. */
5/*----------------------------------------------------------------------------*/
6
7#include "Utility.h"
8
9#include "NetworkCommunication/FRCComm.h"
10#include "ChipObject.h"
11#include "Task.h"
12#include <dbgLib.h>
13#include <stdio.h>
14#include <sysSymTbl.h>
15#include "nivision.h"
16
17#define DBG_DEMANGLE_PRINT_LEN 256 /* Num chars of demangled names to print */
18
19extern "C"
20{
21 extern char * cplusDemangle (char *source, char *dest, INT32 n);
22}
23
24char *wpi_getLabel(UINT addr, INT32 *found)
25{
26 INT32 pVal;
27 SYM_TYPE pType;
28 char name[MAX_SYS_SYM_LEN + 1];
29 static char label[DBG_DEMANGLE_PRINT_LEN + 1 + 11];
30 bzero(label, DBG_DEMANGLE_PRINT_LEN + 1 + 11);
31
32 if (symFindByValue(sysSymTbl, addr, name, &pVal, &pType) == OK)
33 {
34 cplusDemangle(name, label, sizeof(label) - 11);
35 if ((UINT)pVal != addr)
36 {
37 sprintf(&label[strlen(label)], "+0x%04x", addr-pVal);
38 if (found) *found = 2;
39 }
40 else
41 {
42 if (found) *found = 1;
43 }
44 }
45 else
46 {
47 sprintf(label, "0x%04x", addr);
48 if (found) *found = 0;
49 }
50
51 return label;
52}
53/*
54static void wpiTracePrint(INSTR *caller, INT32 func, INT32 nargs, INT32 *args, INT32 taskId, BOOL isKernelAdrs)
55{
56 char buf [MAX_SYS_SYM_LEN * 2];
57 INT32 ix;
58 INT32 len = 0;
59 len += sprintf (&buf [len], "%s <%#010x>: ", wpi_getLabel((UINT)caller), (INT32)caller);
60 len += sprintf (&buf [len], "%s <%#010x> (", wpi_getLabel((UINT)func), func);
61 for (ix = 0; ix < nargs; ix++)
62 {
63 if (ix != 0)
64 len += sprintf (&buf [len], ", ");
65 len += sprintf (&buf [len], "%#x", args [ix]);
66 }
67 len += sprintf (&buf [len], ")\n");
68
69 printf(buf);
70}
71*/
72static void wpiCleanTracePrint(INSTR *caller, INT32 func, INT32 nargs, INT32 *args, INT32 taskId, BOOL isKernelAdrs)
73{
74 char buf [MAX_SYS_SYM_LEN];
75 INT32 ix;
76 INT32 len = 0;
77 INT32 nameFound = 0;
78 INT32 params = 0;
79 INT32 totalnargs = nargs;
80 char *funcName = wpi_getLabel((UINT)func, &nameFound);
81 // Ignore names that are not exact symbol address matches.
82 if (nameFound != 1) return;
83
84 // Ignore internal function name matches.
85 if (strncmp(funcName, "wpi_assert", 10) == 0) return;
86 if (strncmp(funcName, "wpi_fatal", 9) == 0) return;
87 if (strncmp(funcName, "wpi_selfTrace", 13) == 0) return;
88 if (strncmp(funcName, "Error::Set", 10) == 0) return;
89 if (strncmp(funcName, "ErrorBase::SetError", 19) == 0) return;
90 if (strncmp(funcName, "Error::Report", 13) == 0) return;
91
92 // Find the number of arguments in the name string.
93 char *start = strchr(funcName, '(');
94 char *end = strrchr(funcName, ')');
95 if (start + 1 != end && start != NULL)
96 {
97 do
98 {
99 params++;
100 if(strncmp(start+1, "bool", 4) == 0 || strncmp(start+2, "bool", 4) == 0)
101 {
102 totalnargs++;
103 }
104 start = strchr(start + 1, ',');
105 }
106 while(start < end && start != NULL);
107 }
108 char *funcNameEnd = strchr(funcName, '(');
109 *funcNameEnd = 0;
110 len += sprintf (&buf [len], funcName);
111
112 // If this is a member function, print out the this pointer value.
113 if (totalnargs - params == 1)
114 {
115 len += sprintf (&buf [len], "<this=%#x>", args [0]);
116 }
117
118 // Print out the argument values.
119 len += sprintf (&buf [len], "(");
120 for (ix = totalnargs - params; ix < nargs; ix++)
121 {
122 if (ix != totalnargs - params)
123 len += sprintf (&buf [len], ", ");
124 len += sprintf (&buf [len], "%#x", args [ix]);
125 }
126 len += sprintf (&buf [len], ")\n");
127
128 printf(buf);
129}
130
131extern "C"
132{
133 extern void trcStack(REG_SET* pRegs, FUNCPTR printRtn, INT32 tid);
134}
135
136static INT32 wpiStackTask(INT32 taskId)
137{
138 taskDelay(1);
139 //tt(taskId);
140
141 REG_SET regs;
142 taskRegsGet(taskId, &regs);
143 trcStack(&regs, (FUNCPTR) wpiCleanTracePrint, taskId);
144 printf("\n");
145
146 // The task should be resumed because it had to be suspended to get the stack trace.
147 taskResume(taskId);
148 return 0;
149}
150
151void wpi_selfTrace()
152{
153 INT32 priority=100;
154 taskPriorityGet(0, &priority);
155 // Lower priority than the calling task.
156 Task traceTask("StackTrace", (FUNCPTR)wpiStackTask, priority + 1);
157 traceTask.Start(taskIdSelf());
158
159 // Task to be traced must be suspended for the stack trace to work.
160 taskSuspend(0);
161}
162
163static bool stackTraceEnabled = false;
164static bool suspendOnAssertEnabled = false;
165
166/**
167 * Enable Stack trace after asserts.
168 */
169void wpi_stackTraceOnAssertEnable(bool enabled)
170{
171 stackTraceEnabled = enabled;
172}
173
174/**
175 * Enable suspend on asssert.
176 * If enabled, the user task will be suspended whenever an assert fails. This
177 * will allow the user to attach to the task with the debugger and examine variables
178 * around the failure.
179 */
180void wpi_suspendOnAssertEnabled(bool enabled)
181{
182 suspendOnAssertEnabled = enabled;
183}
184
185static void wpi_handleTracing()
186{
187 if (stackTraceEnabled)
188 {
189 printf("\n-----------<Stack Trace>----------------\n");
190 wpi_selfTrace();
191 }
192 printf("\n");
193}
194
195/**
196 * Assert implementation.
197 * This allows breakpoints to be set on an assert.
198 * The users don't call this, but instead use the wpi_assert macros in Utility.h.
199 */
200bool wpi_assert_impl(bool conditionValue,
201 const char *conditionText,
202 const char *message,
203 const char *fileName,
204 UINT32 lineNumber,
205 const char *funcName)
206{
207 if (!conditionValue)
208 {
209 // Error string buffer
210 char error[256];
211
212 // If an error message was specified, include it
213 // Build error string
214 if(message != NULL) {
215 sprintf(error, "Assertion failed: \"%s\", \"%s\" failed in %s() in %s at line %d\n",
216 message, conditionText, funcName, fileName, lineNumber);
217 } else {
218 sprintf(error, "Assertion failed: \"%s\" in %s() in %s at line %d\n",
219 conditionText, funcName, fileName, lineNumber);
220 }
221
222 // Print to console and send to remote dashboard
223 printf("\n\n>>>>%s", error);
224 setErrorData(error, strlen(error), 100);
225
226 wpi_handleTracing();
227 if (suspendOnAssertEnabled) taskSuspend(0);
228 }
229 return conditionValue;
230}
231
232/**
233 * Common error routines for wpi_assertEqual_impl and wpi_assertNotEqual_impl
234 * This should not be called directly; it should only be used by wpi_assertEqual_impl
235 * and wpi_assertNotEqual_impl.
236 */
237void wpi_assertEqual_common_impl(int valueA,
238 int valueB,
239 const char *equalityType,
240 const char *message,
241 const char *fileName,
242 UINT32 lineNumber,
243 const char *funcName)
244{
245 // Error string buffer
246 char error[256];
247
248 // If an error message was specified, include it
249 // Build error string
250 if(message != NULL) {
251 sprintf(error, "Assertion failed: \"%s\", \"%d\" %s \"%d\" in %s() in %s at line %d\n",
252 message, valueA, equalityType, valueB, funcName, fileName, lineNumber);
253 } else {
254 sprintf(error, "Assertion failed: \"%d\" %s \"%d\" in %s() in %s at line %d\n",
255 valueA, equalityType, valueB, funcName, fileName, lineNumber);
256 }
257
258 // Print to console and send to remote dashboard
259 printf("\n\n>>>>%s", error);
260 setErrorData(error, strlen(error), 100);
261
262 wpi_handleTracing();
263 if (suspendOnAssertEnabled) taskSuspend(0);
264}
265
266/**
267 * Assert equal implementation.
268 * This determines whether the two given integers are equal. If not,
269 * the value of each is printed along with an optional message string.
270 * The users don't call this, but instead use the wpi_assertEqual macros in Utility.h.
271 */
272bool wpi_assertEqual_impl(int valueA,
273 int valueB,
274 const char *message,
275 const char *fileName,
276 UINT32 lineNumber,
277 const char *funcName)
278{
279 if(!(valueA == valueB))
280 {
281 wpi_assertEqual_common_impl(valueA, valueB, "!=", message, fileName, lineNumber, funcName);
282 }
283 return valueA == valueB;
284}
285
286/**
287 * Assert not equal implementation.
288 * This determines whether the two given integers are equal. If so,
289 * the value of each is printed along with an optional message string.
290 * The users don't call this, but instead use the wpi_assertNotEqual macros in Utility.h.
291 */
292bool wpi_assertNotEqual_impl(int valueA,
293 int valueB,
294 const char *message,
295 const char *fileName,
296 UINT32 lineNumber,
297 const char *funcName)
298{
299 if(!(valueA != valueB))
300 {
301 wpi_assertEqual_common_impl(valueA, valueB, "==", message, fileName, lineNumber, funcName);
302 }
303 return valueA != valueB;
304}
305
306
307/**
308 * Return the FPGA Version number.
309 * For now, expect this to be competition year.
310 * @return FPGA Version number.
311 */
312UINT16 GetFPGAVersion()
313{
314 tRioStatusCode status = 0;
315 tGlobal *global = tGlobal::create(&status);
316 UINT16 version = global->readVersion(&status);
317 delete global;
318 wpi_setGlobalError(status);
319 return version;
320}
321
322/**
323 * Return the FPGA Revision number.
324 * The format of the revision is 3 numbers.
325 * The 12 most significant bits are the Major Revision.
326 * the next 8 bits are the Minor Revision.
327 * The 12 least significant bits are the Build Number.
328 * @return FPGA Revision number.
329 */
330UINT32 GetFPGARevision()
331{
332 tRioStatusCode status = 0;
333 tGlobal *global = tGlobal::create(&status);
334 UINT32 revision = global->readRevision(&status);
335 delete global;
336 wpi_setGlobalError(status);
337 return revision;
338}
339
340/**
341 * Read the microsecond-resolution timer on the FPGA.
342 *
343 * @return The current time in microseconds according to the FPGA (since FPGA reset).
344 */
345UINT32 GetFPGATime()
346{
347 tRioStatusCode status = 0;
348 tGlobal *global = tGlobal::create(&status);
349 UINT32 time = global->readLocalTime(&status);
350 delete global;
351 wpi_setGlobalError(status);
352 return time;
353}
354
355// RT hardware access functions exported from ni_emb.out
356extern "C"
357{
358 INT32 UserSwitchInput(INT32 nSwitch);
359 INT32 LedInput(INT32 led);
360 INT32 LedOutput(INT32 led, INT32 value);
361}
362
363/**
364 * Read the value of the USER1 DIP switch on the cRIO.
365 */
366INT32 GetRIOUserSwitch()
367{
368 INT32 switchValue = UserSwitchInput(0);
369 wpi_assert(switchValue >= 0);
370 return switchValue > 0;
371}
372
373/**
374 * Set the state of the USER1 status LED on the cRIO.
375 */
376void SetRIOUserLED(UINT32 state)
377{
378 LedOutput(0, state > 0);
379}
380
381/**
382 * Get the current state of the USER1 status LED on the cRIO.
383 * @return The curent state of the USER1 LED.
384 */
385INT32 GetRIOUserLED()
386{
387 return LedInput(0);
388}
389
390/**
391 * Toggle the state of the USER1 status LED on the cRIO.
392 * @return The new state of the USER1 LED.
393 */
394INT32 ToggleRIOUserLED()
395{
396 INT32 ledState = !GetRIOUserLED();
397 SetRIOUserLED(ledState);
398 return ledState;
399}
400
401/**
402 * Set the state of the FPGA status LED on the cRIO.
403 */
404void SetRIO_FPGA_LED(UINT32 state)
405{
406 tRioStatusCode status = 0;
407 tGlobal *global = tGlobal::create(&status);
408 global->writeFPGA_LED(state, &status);
409 wpi_setGlobalError(status);
410 delete global;
411}
412
413/**
414 * Get the current state of the FPGA status LED on the cRIO.
415 * @return The curent state of the FPGA LED.
416 */
417INT32 GetRIO_FPGA_LED()
418{
419 tRioStatusCode status = 0;
420 tGlobal *global = tGlobal::create(&status);
421 bool ledValue = global->readFPGA_LED(&status);
422 wpi_setGlobalError(status);
423 delete global;
424 return ledValue;
425}
426
427/**
428 * Toggle the state of the FPGA status LED on the cRIO.
429 * @return The new state of the FPGA LED.
430 */
431INT32 ToggleRIO_FPGA_LED()
432{
433 INT32 ledState = !GetRIO_FPGA_LED();
434 SetRIO_FPGA_LED(ledState);
435 return ledState;
436}
437
438