diff --git a/src/animations/program.c b/src/animations/program.c index c964731..ec10ba7 100644 --- a/src/animations/program.c +++ b/src/animations/program.c @@ -1,4 +1,5 @@ +#include #include "../config.h" #include "../compat/pgmspace.h" #include "../random/prng.h" @@ -9,38 +10,43 @@ #ifdef ANIMATION_TESTS -void test_level(unsigned char level){ +void test_level(unsigned char level, bool debug){ for (unsigned char y=NUM_ROWS;y--;){ for (unsigned char x=NUM_COLS;x--;){ setpixel((pixel){x,y}, level); wait(5); } } - wait(2000); + if (!debug) { + wait(2000); + } } -void test_palette(){ +void test_palette(bool debug){ for (unsigned char y=NUM_ROWS;y--;){ for (unsigned char x=NUM_COLS;x--;){ setpixel((pixel){x,y}, y%4); // wait(1); } } - wait(2000); + if (!debug) { + wait(2000); + } } -void test_palette2(){ +void test_palette2(bool debug){ for (unsigned char x=NUM_COLS;x--;){ for (unsigned char y=NUM_ROWS;y--;){ setpixel((pixel){x,y}, x%4); - // wait(1); } } - wait(1000); - for (unsigned char x=NUM_COLS;x--;){ - // shift image right - shift_pixmap_l(); - wait(30); + if (!debug) { + wait(1000); + for (unsigned char x=NUM_COLS;x--;){ + // shift image right + shift_pixmap_l(); + wait(30); + } } } #endif diff --git a/src/animations/program.h b/src/animations/program.h index 9c002d2..c5e525f 100644 --- a/src/animations/program.h +++ b/src/animations/program.h @@ -1,13 +1,14 @@ #ifndef PROGRAMM_H_ #define PROGRAMM_H_ +#include #include "../pixel.h" #include "../util.h" -void test_level(unsigned char level); -void test_palette(); -void test_palette2(); +void test_level(unsigned char level, bool debug); +void test_palette(bool debug); +void test_palette2(bool debug); #ifdef ANIMATION_OFF inline static void off() diff --git a/src/display_loop.c b/src/display_loop.c index 58ff68f..a8ae3a4 100644 --- a/src/display_loop.c +++ b/src/display_loop.c @@ -268,20 +268,20 @@ void display_loop(){ #ifdef ANIMATION_TESTS case 31: - test_level(1); + test_level(1, false); break; case 32: - test_level(2); + test_level(2, false); break; case 33: - test_level(3); + test_level(3, false); break; case 35: - test_palette(); - test_palette2(); + test_palette(false); + test_palette2(false); break; #endif diff --git a/src/uart/uart_commands.c b/src/uart/uart_commands.c index 5deaba9..347614d 100644 --- a/src/uart/uart_commands.c +++ b/src/uart/uart_commands.c @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -14,6 +15,7 @@ extern unsigned char waitForFire; #endif #include "../scrolltext/scrolltext.h" +#include "../animations/program.h" #include "uart.h" #include "uart_commands.h" @@ -39,8 +41,9 @@ extern volatile unsigned char reverseMode; #define CR "\r\n" -#if !(defined(eeprom_update_block) && \ - ((E2PAGESIZE == 2) || (E2PAGESIZE == 4) || (E2PAGESIZE == 8))) +#if (!(defined(eeprom_update_block) && \ + ((E2PAGESIZE == 2) || (E2PAGESIZE == 4) || (E2PAGESIZE == 8)))) || \ + !(defined(ANIMATION_TESTS)) char const UART_STR_NOTIMPL[] PROGMEM = "Not implemented."CR; #endif @@ -55,17 +58,22 @@ char const UART_STR_UART_ERR[] PROGMEM = "Transmission error."CR; char const UART_STR_UNKNOWN[] PROGMEM = "Unknown command or syntax error."CR; char const UART_STR_TOOLONG[] PROGMEM = CR"Command is too long."CR; char const UART_STR_HELP[] PROGMEM = "Allowed commands: erase help mode " - "msg next prev reset scroll"CR; + "msg next prev reset scroll test"CR; char const UART_CMD_ERASE[] PROGMEM = "erase"; char const UART_CMD_HELP[] PROGMEM = "help"; char const UART_CMD_MODE[] PROGMEM = "mode"; -char const UART_CMD_MODE_ARG[] PROGMEM = "mode "; char const UART_CMD_MSG[] PROGMEM = "msg "; char const UART_CMD_NEXT[] PROGMEM = "next"; char const UART_CMD_PREV[] PROGMEM = "prev"; char const UART_CMD_RESET[] PROGMEM = "reset"; char const UART_CMD_SCROLL[] PROGMEM = "scroll "; +char const UART_CMD_TEST[] PROGMEM = "test"; + +#ifdef ANIMATION_TESTS +char const UART_STR_TEST_EXIT[] PROGMEM = "Press ENTER to exit test."CR; +char const UART_STR_TEST_ERR[] PROGMEM = "Range is between 0 and %d."CR; +#endif bool g_uartcmd_permit_processing = 1; @@ -207,6 +215,33 @@ static void uartcmd_prev_anim(void) { } +/** + * Extracts a positive number from an ASCII string (up to INT_MAX). + * @param buffer String to be examined. Preceding whitespaces are skipped. + * ASCII control characters and [Space] act as delimiters. + * @return The extracted number or -1 if a conversion error occurred. + */ +int uartcmd_extract_num_arg(char *buffer) { + int res = -1; + uint8_t i = 0; + while (buffer[i] <= ' ' && buffer[i] != 0) ++i; // skip whitespaces + for (; buffer[i] > 0x20; ++i) { + if (res < 0) { + res = 0; + } + int const d = buffer[i] - '0'; + if (isdigit(buffer[i]) && (res <= (INT_MAX / 10)) && + ((res * 10) <= (INT_MAX - d))) { + res = res * 10 + d; + } else { + res = -1; + break; + } + } + return res; +} + + /** * Outputs current mode number via UART. */ @@ -220,35 +255,59 @@ static void uartcmd_print_mode(void) { /** * Retrieves desired mode number from command line and switches to that mode. */ -static void uartcmd_read_mode(void) { - int res = 0; - for (uint8_t i = 5; (i < 8) && (g_rx_buffer[i] != 0); ++i) { - if (isdigit(g_rx_buffer[i])) { - res = res * 10 + g_rx_buffer[i] - '0'; - } else { - res = UINT8_MAX + 1; - break; - } - } - - if ((res <= UINT8_MAX) && (g_rx_buffer[8] == 0)) { +static void uartcmd_mode(void) { + if (g_rx_buffer[4] != 0) { + int new_mode = uartcmd_extract_num_arg(&g_rx_buffer[4]); + if (new_mode <= UINT8_MAX) { #ifdef JOYSTICK_SUPPORT - if (waitForFire) { + if (waitForFire) { #endif - UART_PUTS_P(UART_STR_PROMPT); - uartcmd_clear_buffer(); - longjmp(newmode_jmpbuf, res); + UART_PUTS_P(UART_STR_PROMPT); + uartcmd_clear_buffer(); + longjmp(newmode_jmpbuf, new_mode); #ifdef JOYSTICK_SUPPORT + } else { + UART_PUTS_P(UART_STR_GAMEMO_ERR); + } +#endif } else { - UART_PUTS_P(UART_STR_GAMEMO_ERR); + UART_PUTS_P(UART_STR_MODE_ERR); } -#endif } else { - UART_PUTS_P(UART_STR_MODE_ERR); + uartcmd_print_mode(); } } +/** + * Draws test patterns for display inspection. + */ +static void uartcmd_test(void) { +#ifdef ANIMATION_TESTS + uartcmd_forbid(); + int pattern_no = uartcmd_extract_num_arg(&g_rx_buffer[4]); + if (pattern_no >= 0 && pattern_no <= NUMPLANE + 2) { + UART_PUTS_P(UART_STR_TEST_EXIT); + if (pattern_no <= NUMPLANE) { + test_level(pattern_no, true); + } else if (pattern_no == (NUMPLANE + 1)) { + test_palette(true); + } else if (pattern_no == (NUMPLANE + 2)) { + test_palette2(true); + } + while (UART_GETC() >= 0x20); // wait for any control character + } else { + char msg[36] = ""; + snprintf_P(msg, sizeof(msg), UART_STR_TEST_ERR, NUMPLANE + 2); + UART_PUTS(msg); + } + uartcmd_permit(); +#else + UART_PUTS_P(UART_STR_NOTIMPL); +#endif +} + + /** * Perform a MCU reset by triggering the watchdog. */ @@ -327,6 +386,7 @@ static bool uartcmd_read_until_enter(void) { return false; } + /** * Checks for entered commands and dispatches them to the appropriate handler. */ @@ -336,11 +396,8 @@ void uartcmd_process(void) { uartcmd_erase_eeprom(); } else if (!strncmp_P(g_rx_buffer, UART_CMD_HELP, UART_BUFFER_SIZE)) { UART_PUTS_P(UART_STR_HELP); - } else if (!strncmp_P(g_rx_buffer, UART_CMD_MODE, UART_BUFFER_SIZE) || - !strncmp_P(g_rx_buffer, UART_CMD_MODE_ARG, UART_BUFFER_SIZE)) { - uartcmd_print_mode(); - } else if (!strncmp_P(g_rx_buffer, UART_CMD_MODE_ARG, 5)) { - uartcmd_read_mode(); + } else if (!strncmp_P(g_rx_buffer, UART_CMD_MODE, 4)) { + uartcmd_mode(); } else if (!strncmp_P(g_rx_buffer, UART_CMD_MSG, 4)) { uartcmd_simple_message(); } else if (!strncmp_P(g_rx_buffer, UART_CMD_NEXT, UART_BUFFER_SIZE)) { @@ -351,6 +408,8 @@ void uartcmd_process(void) { uartcmd_reset_borg(); } else if (!strncmp_P(g_rx_buffer, UART_CMD_SCROLL, 7)) { uartcmd_scroll_message(); + } else if (!strncmp_P(g_rx_buffer, UART_CMD_TEST, 4)) { + uartcmd_test(); } else if (g_rx_buffer[0] != 0) { UART_PUTS_P(UART_STR_UNKNOWN); }