diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 283fd79..0a9d66c 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -21,6 +21,7 @@ target_sources(tests ${CMAKE_SOURCE_DIR}/project/Core/Src/llfs_data.c ${CMAKE_SOURCE_DIR}/project/Core/Src/llfs.c ${CMAKE_SOURCE_DIR}/project/Core/Src/tftp.c + ${CMAKE_SOURCE_DIR}/project/Core/Src/tcp_cmd.c ) target_compile_options(tests PRIVATE $<$: diff --git a/tests/mocs.c b/tests/mocs.c index 43c9f47..a5a5d9d 100644 --- a/tests/mocs.c +++ b/tests/mocs.c @@ -1,5 +1,11 @@ #include "mocs.h" #include "tftp.h" +#include "mocs.h" +#ifdef DEBUG +#define dprint(fmt, ...) printf(fmt, ##__VA_ARGS__) +#else +#define dprint(fmt, ...) +#endif void tftp_cleanup(void) { } @@ -22,28 +28,38 @@ void lcd_display_text(const char* text, UNUSED(bg_color); UNUSED(font); - printf("lcd_display_text @ %d %d with color 0x%08X bg color 0x%08X\n%s\n", x_pos, y_pos, color, bg_color, text); + dprint("lcd_display_text @ %d %d with color 0x%08X bg color 0x%08X\n%s\n", x_pos, y_pos, color, bg_color, text); } void lcd_draw_img_from_fs(char* filename, uint32_t x_pos, uint32_t y_pos) { - printf("lcd_draw_img_from_fs\n%s @%d %d\n", filename, x_pos, y_pos); + UNUSED(filename); + UNUSED(x_pos); + UNUSED(y_pos); + + dprint("lcd_draw_img_from_fs\n%s @%d %d\n", filename, x_pos, y_pos); } void lcd_draw_gif_from_fs(char* filename, uint32_t x_pos, uint32_t y_pos) { - printf("lcd_draw_gif_from_fs\n%s @%d %d\n", filename, x_pos, y_pos); + UNUSED(filename); + UNUSED(x_pos); + UNUSED(y_pos); + + dprint("lcd_draw_gif_from_fs\n%s @%d %d\n", filename, x_pos, y_pos); } void lcd_clear_images(void) { - printf("lcd_clear_images\n"); + dprint("lcd_clear_images\n"); } void lcd_clear_text(void) { - printf("lcd_clear_text\n"); + dprint("lcd_clear_text\n"); } void lcd_draw_bmp_img(uint8_t* bmp_buff, uint32_t x_pos, uint32_t y_pos) { UNUSED(bmp_buff); + UNUSED(x_pos); + UNUSED(y_pos); - printf("lcd_draw_bmp_img @ %d %d\n", x_pos, y_pos); + dprint("lcd_draw_bmp_img @ %d %d\n", x_pos, y_pos); } void lcd_draw_gif(uint8_t* gif_buff, size_t len, uint32_t x_pos, uint32_t y_pos) { @@ -52,7 +68,7 @@ void lcd_draw_gif(uint8_t* gif_buff, size_t len, uint32_t x_pos, uint32_t y_pos) UNUSED(x_pos); UNUSED(y_pos); - printf("lcd_draw_gif @ %d %d\n", x_pos, y_pos); + dprint("lcd_draw_gif @ %d %d\n", x_pos, y_pos); } struct tcp_pcb* tcp_new(void) { @@ -112,7 +128,8 @@ void tcp_write(void* pcb, const char* data, size_t len, uint8_t apiflags) { UNUSED(apiflags); UNUSED(len); - printf("tcp_write:\n%s\n", data); + dprint("tcp_write:\n"); + printf("%s\n", data); } void tcp_output(void* pcb) { diff --git a/tests/mocs.h b/tests/mocs.h index 0aaf4b0..2c214cc 100644 --- a/tests/mocs.h +++ b/tests/mocs.h @@ -13,6 +13,15 @@ extern "C" { #define LWIP_UNUSED_ARG(x) UNUSED(x) +typedef void sFONT; + +#define LCD_COLOR_BLACK 0 +#define LCD_COLOR_WHITE 1 +#define LCD_TRANSPARENT 2 + +#define LCD_FONT16 0 +#define LCD_FONT24 (void*)1 + typedef int8_t err_t; /** Definitions for error constants. */ typedef enum { diff --git a/tests/tcp.h b/tests/tcp.h new file mode 100644 index 0000000..e69de29 diff --git a/tests/tcp_cmd.cpp b/tests/tcp_cmd.cpp new file mode 100644 index 0000000..00ed0fa --- /dev/null +++ b/tests/tcp_cmd.cpp @@ -0,0 +1,270 @@ +#include +#include +#include +#include +#include + +#include "mocs.h" +extern "C" { +#include "tcp_cmd.h" +} + +#define MAX_TOKENS 10 + +static uint32_t color_txt = 0; +static uint32_t color_bg = 0; +static const char* TAG = "tcp_cmd"; + +static void tcp_cmd_close(struct tcp_pcb* pcb) { + tcp_arg(pcb, NULL); + tcp_sent(pcb, NULL); + tcp_recv(pcb, NULL); + tcp_close(pcb); +} + +void remove_newline(char* str) { + int i = 0; + while (str[i] != '\0') { + if (str[i] == '\n' || str[i] == '\r') { + str[i] = '\0'; + } + i++; + } +} + +void str_tolower(char* str) { + int i = 0; + while (str[i] != '\0') { + str[i] = (char)tolower((int)str[i]); + i++; + } +} + +char* get_filename_ext(char* filename) { + char* dot = strrchr(filename, '.'); + if (!dot || dot == filename) + return NULL; + return dot + 1; +} + +// Function to find the next token in the input string +// If the token is between quotes, return the whole string between quotes +char* get_next_token(char* input, const char* delimiters, char** next) { + if (input == NULL) { + input = *next; + } + + // Skip leading delimiters + input += strspn(input, delimiters); + if (*input == '\0') { + return NULL; + } + + // If the token is between quotes, return the whole string between quotes + if (*input == '"') { + char* end = strchr(++input, '"'); + if (end == NULL) { + return NULL; + } + *end = '\0'; + *next = end + 1; + return input; + } + + // Find the end of the token + char* end = input + strcspn(input, delimiters); + if (*end == '\0') { + *next = end; + } else { + *end = '\0'; + *next = end + 1; + } + return input; +} + +static void tcp_cmd_parser(struct tcp_pcb* pcb, int argc, char** argv) { + char* ext; + if (argc == 0) { + LOG_WARN(TAG, "No command given"); + return; + } + str_tolower(argv[0]); + if (strcmp(argv[0], "help") == 0) { + tcp_cmd_print_help(pcb); + return; + } if (strcmp(argv[0], "text") == 0) { + if (argc == 2) { + lcd_clear_text(); + lcd_display_text((uint8_t*)argv[1], 10, 10, color_txt, color_bg, LCD_FONT24); + return; + } + tcp_cmd_write(pcb, "Usage: text \"\"\n"); + tcp_cmd_write(pcb, "Usage: text \n"); + return; + } if (strcmp(argv[0], "bgcolor") == 0) { + if (argc == 2) { + color_bg = (uint32_t)strtol(argv[1], NULL, 16); + color_bg |= 0xff000000; + return; + } if (argc == 4) { + color_bg = 0xff000000; + color_bg |= (uint32_t)(atoi(argv[1]) && 0xff) << 16; + color_bg |= (uint32_t)(atoi(argv[2]) && 0xff) << 8; + color_bg |= (uint32_t)(atoi(argv[3]) && 0xff); + return; + } + tcp_cmd_write(pcb, "Usage: bgcolor \n"); + tcp_cmd_write(pcb, "Usage: bgcolor r g b\n"); + return; + + } if (strcmp(argv[0], "color") == 0) { + if (argc == 2) { + color_txt = (uint32_t)strtol(argv[1], NULL, 16); + color_txt |= 0xff000000; + return; + } if (argc == 4) { + color_txt = 0xff000000; + color_txt |= (uint32_t)(atoi(argv[1]) && 0xff) << 16; + color_txt |= (uint32_t)(atoi(argv[2]) && 0xff) << 8; + color_txt |= (uint32_t)(atoi(argv[3]) && 0xff); + return; + } + tcp_cmd_write(pcb, "Usage: color 0x\n"); + tcp_cmd_write(pcb, "Usage: color \n"); + return; + } if (strcmp(argv[0], "listimages") == 0) { + void* mem = NULL; // Pointer for internal use by the llfs library + llfs_file_t* file; + while ((file = llfs_next_file(&mem, NULL)) != NULL) { + tcp_cmd_write(pcb, file->name); + tcp_cmd_write(pcb, "\r\n"); + } + return; + } if (strcmp(argv[0], "setimage") == 0) { + if (argc >= 2) { + ext = get_filename_ext(argv[1]); + if (strcmp(ext, "bmp") != 0) { + tcp_cmd_write(pcb, "File is not a bmp\n"); + return; + } + } + if (argc == 2) { + lcd_clear_images(); + lcd_draw_img_from_fs(argv[1], 0, 0); + return; + } if (argc == 4) { + lcd_clear_images(); + lcd_draw_img_from_fs(argv[1], (uint32_t)atoi(argv[2]), (uint32_t)atoi(argv[3])); + return; + } + tcp_cmd_write(pcb, "Usage: setimage \n"); + tcp_cmd_write(pcb, "Usage: setimage \n"); + return; + } else if (strcmp(argv[0], "setgif") == 0) { + if (argc >= 2) { + char* ext = get_filename_ext(argv[1]); + if (strcmp(ext, "gif") != 0) { + tcp_cmd_write(pcb, "File is not a gif\n"); + return; + } + } + if (argc == 2) { + lcd_clear_images(); + lcd_draw_gif_from_fs(argv[1], 0, 0); + return; + } if (argc == 4) { + lcd_clear_images(); + lcd_draw_gif_from_fs(argv[1], (uint32_t)atoi(argv[2]), (uint32_t)atoi(argv[3])); + return; + } + tcp_cmd_write(pcb, "Usage: setgif \n"); + tcp_cmd_write(pcb, "Usage: setgif \n"); + return; + } if (strcmp(argv[0], "exit") == 0) { + tcp_cmd_write(pcb, "Exiting...\n"); + lcd_clear_images(); + lcd_clear_text(); + tcp_close(pcb); + return; + } + tcp_cmd_write(pcb, "Unknown command: "); + tcp_cmd_write(pcb, argv[0]); + tcp_cmd_write(pcb, "\n"); + tcp_cmd_write(pcb, "Type help for list of commands\r\n"); +} + +static err_t tcp_cmd_recv_new(void* arg, struct tcp_pcb* pcb, struct pbuf* p, err_t err) { + int argc = 0; + char* argv[MAX_TOKENS]; + + LWIP_UNUSED_ARG(arg); + if (err == ERR_OK && p != NULL) { + tcp_recved(pcb, p->tot_len); + char* next; + + remove_newline((char*)(p->payload)); + // Split string into tokens by delimiter (space) + argv[0] = get_next_token((char*)(p->payload), " ", &next); + argc = 1; + while (argv[argc - 1] != NULL && argc < MAX_TOKENS) { + argv[argc] = get_next_token(NULL, " ", &next); + if (argv[argc] == NULL) { + break; + } + argc++; + } + + tcp_cmd_parser(pcb, argc, argv); + } else { + pbuf_free(p); + } + + if (err == ERR_OK && p == NULL) { + tcp_cmd_close(pcb); + } + + tcp_cmd_write(pcb, "$> "); + return ERR_OK; +} + +TEST(TCP_CMD, tcp_data_cb) { + char* cmd = (char*)calloc(50, 1); + pbuf p = {.next = NULL, .payload = (void*)cmd, .tot_len = 4, .len = 0, .type_internal = 0, .flags = 0, .if_idx = 0}; + strcpy(cmd, "help"); + tcp_cmd_recv_new(NULL, NULL, &p, ERR_OK); + EXPECT_EQ(0, strcmp("help", (char*)p.payload)); + + strcpy(cmd, "text \"This is printed on the display\""); + tcp_cmd_recv_new(NULL, NULL, &p, ERR_OK); + EXPECT_EQ(0, strcmp("text", (char*)p.payload)); + + strcpy(cmd, "color 0xffffff"); + tcp_cmd_recv_new(NULL, NULL, &p, ERR_OK); + EXPECT_EQ(0, strcmp("color", (char*)p.payload)); + + strcpy(cmd, "text \"This is printed on the display\""); + tcp_cmd_recv_new(NULL, NULL, &p, ERR_OK); + EXPECT_EQ(0, strcmp("text", (char*)p.payload)); + + strcpy(cmd, "setImage \"test.bmp\""); + tcp_cmd_recv_new(NULL, NULL, &p, ERR_OK); + EXPECT_EQ(0, strcmp("setimage", (char*)p.payload)); + + strcpy(cmd, "setImage \"test.gif\""); + tcp_cmd_recv_new(NULL, NULL, &p, ERR_OK); + EXPECT_EQ(0, strcmp("setimage", (char*)p.payload)); + + strcpy(cmd, "setGif \"test.gif\""); + tcp_cmd_recv_new(NULL, NULL, &p, ERR_OK); + EXPECT_EQ(0, strcmp("setgif", (char*)p.payload)); + + strcpy(cmd, "setGif \"test.bmp\""); + tcp_cmd_recv_new(NULL, NULL, &p, ERR_OK); + EXPECT_EQ(0, strcmp("setgif", (char*)p.payload)); + + strcpy(cmd, "exit"); + tcp_cmd_recv_new(NULL, NULL, &p, ERR_OK); + EXPECT_EQ(0, strcmp("exit", (char*)p.payload)); + + free(cmd); +} \ No newline at end of file