}\r
return l;\r
}\r
+\r
+char* strncat(char *dest, const char *src, unsigned int n)\r
+{\r
+ unsigned int dest_len = strlen(dest);\r
+ unsigned int i;\r
+ \r
+ for (i = 0 ; i < n && src[i] != '\0' ; i++)\r
+ dest[dest_len + i] = src[i];\r
+ dest[dest_len + i] = '\0';\r
+ \r
+ return dest;\r
+}\r
+\r
+\r
+void LEDsoff()\r
+{\r
+ LED_A_OFF();\r
+ LED_B_OFF();\r
+ LED_C_OFF();\r
+ LED_D_OFF();\r
+}\r
+\r
+// LEDs: R(C) O(A) G(B) -- R(D) [1, 2, 4 and 8]\r
+void LED(int led, int ms)\r
+{\r
+ if (led & LED_RED)\r
+ LED_C_ON();\r
+ if (led & LED_ORANGE)\r
+ LED_A_ON();\r
+ if (led & LED_GREEN)\r
+ LED_B_ON();\r
+ if (led & LED_RED2)\r
+ LED_D_ON();\r
+\r
+ if (!ms)\r
+ return;\r
+\r
+ SpinDelay(ms);\r
+\r
+ if (led & LED_RED)\r
+ LED_C_OFF();\r
+ if (led & LED_ORANGE)\r
+ LED_A_OFF();\r
+ if (led & LED_GREEN)\r
+ LED_B_OFF();\r
+ if (led & LED_RED2)\r
+ LED_D_OFF();\r
+}\r
+\r
+\r
+// Determine if a button is double clicked, single clicked,\r
+// not clicked, or held down (for ms || 1sec)\r
+// In general, don't use this function unless you expect a\r
+// double click, otherwise it will waste 500ms -- use BUTTON_HELD instead\r
+int BUTTON_CLICKED(int ms)\r
+{\r
+ // Up to 500ms in between clicks to mean a double click\r
+ int ticks = (48000 * (ms ? ms : 1000)) >> 10;\r
+\r
+ // If we're not even pressed, forget about it!\r
+ if (!BUTTON_PRESS())\r
+ return BUTTON_NO_CLICK;\r
+\r
+ // Borrow a PWM unit for my real-time clock\r
+ PWM_ENABLE = PWM_CHANNEL(0);\r
+ // 48 MHz / 1024 gives 46.875 kHz\r
+ PWM_CH_MODE(0) = PWM_CH_MODE_PRESCALER(10);\r
+ PWM_CH_DUTY_CYCLE(0) = 0;\r
+ PWM_CH_PERIOD(0) = 0xffff;\r
+\r
+ WORD start = (WORD)PWM_CH_COUNTER(0);\r
+\r
+ int letoff = 0;\r
+ for(;;)\r
+ {\r
+ WORD now = (WORD)PWM_CH_COUNTER(0);\r
+\r
+ // We haven't let off the button yet\r
+ if (!letoff)\r
+ {\r
+ // We just let it off!\r
+ if (!BUTTON_PRESS())\r
+ {\r
+ letoff = 1;\r
+\r
+ // reset our timer for 500ms\r
+ start = (WORD)PWM_CH_COUNTER(0);\r
+ ticks = (48000 * (500)) >> 10;\r
+ }\r
+\r
+ // Still haven't let it off\r
+ else\r
+ // Have we held down a full second?\r
+ if (now == (WORD)(start + ticks))\r
+ return BUTTON_HOLD;\r
+ }\r
+\r
+ // We already let off, did we click again?\r
+ else\r
+ // Sweet, double click!\r
+ if (BUTTON_PRESS())\r
+ return BUTTON_DOUBLE_CLICK;\r
+\r
+ // Have we ran out of time to double click?\r
+ else\r
+ if (now == (WORD)(start + ticks))\r
+ // At least we did a single click\r
+ return BUTTON_SINGLE_CLICK;\r
+\r
+ WDT_HIT();\r
+ }\r
+\r
+ // We should never get here\r
+ return BUTTON_ERROR;\r
+}\r
+\r
+// Determine if a button is held down\r
+int BUTTON_HELD(int ms)\r
+{\r
+ // If button is held for one second\r
+ int ticks = (48000 * (ms ? ms : 1000)) >> 10;\r
+\r
+ // If we're not even pressed, forget about it!\r
+ if (!BUTTON_PRESS())\r
+ return BUTTON_NO_CLICK;\r
+\r
+ // Borrow a PWM unit for my real-time clock\r
+ PWM_ENABLE = PWM_CHANNEL(0);\r
+ // 48 MHz / 1024 gives 46.875 kHz\r
+ PWM_CH_MODE(0) = PWM_CH_MODE_PRESCALER(10);\r
+ PWM_CH_DUTY_CYCLE(0) = 0;\r
+ PWM_CH_PERIOD(0) = 0xffff;\r
+\r
+ WORD start = (WORD)PWM_CH_COUNTER(0);\r
+\r
+ for(;;)\r
+ {\r
+ WORD now = (WORD)PWM_CH_COUNTER(0);\r
+\r
+ // As soon as our button let go, we didn't hold long enough\r
+ if (!BUTTON_PRESS())\r
+ return BUTTON_SINGLE_CLICK;\r
+\r
+ // Have we waited the full second?\r
+ else\r
+ if (now == (WORD)(start + ticks))\r
+ return BUTTON_HOLD;\r
+\r
+ WDT_HIT();\r
+ }\r
+\r
+ // We should never get here\r
+ return BUTTON_ERROR;\r
+}\r
+\r
+// attempt at high resolution microsecond timer\r
+// beware: timer counts in 21.3uS increments (1024/48Mhz)\r
+void SpinDelayUs(int us)\r
+{\r
+ int ticks = (48*us) >> 10;\r
+\r
+ // Borrow a PWM unit for my real-time clock\r
+ PWM_ENABLE = PWM_CHANNEL(0);\r
+ // 48 MHz / 1024 gives 46.875 kHz\r
+ PWM_CH_MODE(0) = PWM_CH_MODE_PRESCALER(10);\r
+ PWM_CH_DUTY_CYCLE(0) = 0;\r
+ PWM_CH_PERIOD(0) = 0xffff;\r
+\r
+ WORD start = (WORD)PWM_CH_COUNTER(0);\r
+\r
+ for(;;) {\r
+ WORD now = (WORD)PWM_CH_COUNTER(0);\r
+ if (now == (WORD)(start + ticks))\r
+ return;\r
+\r
+ WDT_HIT();\r
+ }\r
+}\r
+\r
+void SpinDelay(int ms)\r
+{\r
+ // convert to uS and call microsecond delay function\r
+ SpinDelayUs(ms*1000);\r
+}\r
+\r
+/* Similar to FpgaGatherVersion this formats stored version information\r
+ * into a string representation. It takes a pointer to the struct version_information,\r
+ * verifies the magic properties, then stores a formatted string, prefixed by\r
+ * prefix in dst.
+ */\r
+void FormatVersionInformation(char *dst, int len, const char *prefix, void *version_information)\r
+{\r
+ struct version_information *v = (struct version_information*)version_information;\r
+ dst[0] = 0;\r
+ strncat(dst, prefix, len);\r
+ if(v->magic != VERSION_INFORMATION_MAGIC) {\r
+ strncat(dst, "Missing/Invalid version information", len);\r
+ return;\r
+ }\r
+ if(v->versionversion != 1) {\r
+ strncat(dst, "Version information not understood", len);\r
+ return;\r
+ }\r
+ if(!v->present) {\r
+ strncat(dst, "Version information not available", len);\r
+ return;\r
+ }\r
+ \r
+ strncat(dst, v->svnversion, len);\r
+ if(v->clean == 0) {\r
+ strncat(dst, "-unclean", len);\r
+ } else if(v->clean == 2) {\r
+ strncat(dst, "-suspect", len);\r
+ }\r
+ \r
+ strncat(dst, " ", len);\r
+ strncat(dst, v->buildtime, len);\r
+}\r