From 3e65c70da770fa31fc8acc6ab9374d908cf1ed17 Mon Sep 17 00:00:00 2001 From: lonkaars Date: Tue, 7 Jun 2022 21:27:16 +0200 Subject: implement orders --- client/i18n/en_us.h | 39 +++++++++++------ client/main.c | 6 ++- client/main.h | 3 ++ client/setup.c | 3 +- client/strings.c | 2 + client/ui.c | 4 +- client/ui.h | 14 ++++++- client/ui_errcatch.c | 8 +--- client/ui_modes.c | 10 +++++ client/ui_orders.c | 116 +++++++++++++++++++++++++++++++++++++++++++++++++++ client/ui_tabbar.c | 4 ++ readme.md | 6 ++- shared/consts.h | 4 ++ shared/util.c | 8 ++++ shared/util.h | 4 ++ 15 files changed, 205 insertions(+), 26 deletions(-) create mode 100644 client/ui_modes.c create mode 100644 client/ui_orders.c diff --git a/client/i18n/en_us.h b/client/i18n/en_us.h index 47debd7..ceca215 100644 --- a/client/i18n/en_us.h +++ b/client/i18n/en_us.h @@ -24,7 +24,7 @@ #define W2_UI_TAB_LABEL_ERRCATCH "logs" #define W2_UI_TAB_LABEL_MCFG "map" #define W2_UI_TAB_LABEL_ORDERS "orders" -#define W2_UI_TAB_LABEL_MODE "set mode" +#define W2_UI_TAB_LABEL_MODES "set mode" #define W2_UI_TAB_START_MESSAGE "" \ "welcome to the wall-e2 console application!\n" \ @@ -33,18 +33,9 @@ "this application is functionally similar to a BIOS.\n" \ "here's a brief summary of keyboard commands:\n" \ "\n" \ - " switch to next tab\n" \ - "/, / select option\n" \ - ", edit option\n" \ - ", scroll to top\n" \ - ", scroll to bottom\n" \ - " back\n" \ - " exit\n" \ + " switch to next tab\n" \ + " exit\n" \ "\n" \ - "tab shortcuts:\n" \ - " info orders\n" \ - " logs set mode\n" \ - " direct control map\n" #define W2_UI_ERROR_SEVERITY_CRIT "CRIT" #define W2_UI_ERROR_SEVERITY_WARN "WARN" @@ -86,3 +77,27 @@ #define W2_UI_ERROR_USR_W2_E_WARN_SERIAL_NOISY "invalid serial data received (noisy channel / check connection?)" #define W2_UI_ERROR_USR_W2_E_WARN_MODE_HISTORY_BUFFER_IOB "mode history buffer index out of bounds" #define W2_UI_ERROR_USR_W2_E_WARN_PING_TIMEOUT "ping timed out" + +#define W2_UI_ORDER_CMD_HELP "help" +#define W2_UI_ORDER_CMD_START "start" +#define W2_UI_ORDER_CMD_COORDINATE "coordinate" +#define W2_UI_ORDER_CMD_DONE "done" +#define W2_UI_ORDER_CMD_SEND "send" + +#define W2_UI_ORDER_MSG_ERROR "unknown command, type 'help' to see a list of valid commands\n\n" +#define W2_UI_ORDER_MSG_HELP \ + "commands:\n" \ + "\n" \ + W2_UI_ORDER_CMD_HELP ": print this list\n" \ + W2_UI_ORDER_CMD_START ": start an order\n" \ + W2_UI_ORDER_CMD_COORDINATE " : add a coordinate to the current order\n" \ + W2_UI_ORDER_CMD_DONE ": finish the current order\n" \ + W2_UI_ORDER_CMD_SEND ": send the latest completed order to robot\n\n" +#define W2_UI_ORDER_MSG_ORDER_START_OK "order started\n\n" +#define W2_UI_ORDER_MSG_ORDER_START_ERR "order already started\n\n" +#define W2_UI_ORDER_MSG_ORDER_APPEND_OK "appended coordinate to order\n\n" +#define W2_UI_ORDER_MSG_ORDER_APPEND_ERR "no order active\n\n" +#define W2_UI_ORDER_MSG_ORDER_DONE_OK "order saved\n\n" +#define W2_UI_ORDER_MSG_ORDER_DONE_ERR "no order active\n\n" +#define W2_UI_ORDER_MSG_ORDER_SENT "order sent to robot\n\n" + diff --git a/client/main.c b/client/main.c index b5af0e8..dcbc16a 100644 --- a/client/main.c +++ b/client/main.c @@ -7,7 +7,11 @@ #include "time.h" #include "ui.h" -w2_s_client_state g_w2_state = {.ping_received = true}; +w2_s_client_state g_w2_state = { + .ping_received = true, + .map_height = W2_MAP_DEFAULT_HEIGHT, + .map_width = W2_MAP_DEFAULT_WIDTH, +}; int main(int argc, char **argv) { w2_client_setup(argc, argv); diff --git a/client/main.h b/client/main.h index cc4c728..cd81348 100644 --- a/client/main.h +++ b/client/main.h @@ -13,6 +13,9 @@ typedef struct { uint8_t mode; + uint8_t map_width; + uint8_t map_height; + w2_s_cmd_info_tx info; w2_s_cmd_sens_tx io; } w2_s_client_state; diff --git a/client/setup.c b/client/setup.c index 8b5d07a..43ed135 100644 --- a/client/setup.c +++ b/client/setup.c @@ -33,6 +33,7 @@ void w2_client_setup(int argc, char **argv) { noecho(); curs_set(false); nodelay(g_w2_ui_win, true); + keypad(g_w2_ui_win, true); w2_strings_init(); w2_cmd_setup_handlers(); @@ -46,7 +47,7 @@ void w2_client_setup(int argc, char **argv) { g_w2_ui_pad_tabbar = newpad(1, g_w2_ui_width); g_w2_ui_pad_body = newpad(g_w2_ui_height - 5, g_w2_ui_width); g_w2_ui_pad_statusbar = newpad(2, g_w2_ui_width); - g_w2_ui_pad_seperator = newpad(1, g_w2_ui_width); + g_w2_ui_pad_seperator = newpad(1, g_w2_ui_width + 1); scrollok(g_w2_ui_pad_body, true); // check endianness diff --git a/client/strings.c b/client/strings.c index 0ab260e..8d63fcb 100644 --- a/client/strings.c +++ b/client/strings.c @@ -21,6 +21,8 @@ void w2_strings_tabs_init() { g_w2_tab_strings[W2_UI_TAB_START] = W2_UI_TAB_LABEL_START; g_w2_tab_strings[W2_UI_TAB_ERRCATCH] = W2_UI_TAB_LABEL_ERRCATCH; g_w2_tab_strings[W2_UI_TAB_DIRC] = W2_UI_TAB_LABEL_DIRC; + g_w2_tab_strings[W2_UI_TAB_ORDERS] = W2_UI_TAB_LABEL_ORDERS; + g_w2_tab_strings[W2_UI_TAB_MODES] = W2_UI_TAB_LABEL_MODES; } void w2_strings_errors_types() { diff --git a/client/ui.c b/client/ui.c index c45259e..13bcfb2 100644 --- a/client/ui.c +++ b/client/ui.c @@ -34,6 +34,7 @@ void w2_wmvaddnstr(WINDOW *win, unsigned int y, unsigned int x, char *str, unsig void w2_ui_switch_tab(w2_e_ui_tabs next_tab) { g_w2_ui_current_tab = next_tab % W2_UI_TAB_COUNT; wclear(g_w2_ui_pad_body); + curs_set(false); } void w2_ui_key_handler() { @@ -94,7 +95,6 @@ void w2_ui_paint_statusbar() { void w2_ui_paint_seperator() { char temp[g_w2_ui_width]; - for (unsigned int i = 0; i < g_w2_ui_width; i++) temp[i] = '-'; - w2_wmvaddnstr(g_w2_ui_pad_seperator, 0, 0, temp, g_w2_ui_width); + w2_wmvaddnstr(g_w2_ui_pad_seperator, 0, 0, temp, g_w2_ui_width - 1); } diff --git a/client/ui.h b/client/ui.h index a003cfc..c169401 100644 --- a/client/ui.h +++ b/client/ui.h @@ -3,13 +3,19 @@ #include #include -#define W2_UI_UPDATE_FPS (60) +#define W2_UI_UPDATE_FPS 60 +/** order tab current command buffer (char[]) */ +#define W2_UI_ORDER_CMD_BUFFER_SIZE 80 +/** order tab current command buffer (uint16_t[]) */ +#define W2_UI_ORDER_BUFFER_SIZE 16 -#define W2_UI_TAB_COUNT 3 +#define W2_UI_TAB_COUNT 5 typedef enum { W2_UI_TAB_START = 0, W2_UI_TAB_ERRCATCH = 1, W2_UI_TAB_DIRC = 2, + W2_UI_TAB_ORDERS = 3, + W2_UI_TAB_MODES = 4, } w2_e_ui_tabs; extern WINDOW *g_w2_ui_win; @@ -47,8 +53,12 @@ void w2_ui_tabbar_init(); void w2_ui_tab_dirc(bool first); void w2_ui_tab_start(bool first); void w2_ui_tab_errcatch(bool first); +void w2_ui_tab_modes(bool first); +void w2_ui_tab_orders(bool first); void w2_ui_onkey_dirc(int ch); void w2_ui_onkey_errcatch(int ch); +void w2_ui_onkey_modes(int ch); +void w2_ui_onkey_orders(int ch); void w2_wmvaddstr(WINDOW *win, unsigned int y, unsigned int x, char *str); void w2_wmvaddnstr(WINDOW *win, unsigned int y, unsigned int x, char *str, unsigned int len); diff --git a/client/ui_errcatch.c b/client/ui_errcatch.c index 5c9cf34..c25f787 100644 --- a/client/ui_errcatch.c +++ b/client/ui_errcatch.c @@ -5,16 +5,10 @@ #include "i18n.h" #include "strings.h" #include "ui.h" +#include "../shared/util.h" unsigned int g_w2_errcatch_log_line = 0; -unsigned int w2_newline_count(char *str, unsigned int len) { - unsigned int newlines = 0; - for (unsigned int i = 0; i < len; i++) - if (str[i] == '\n') newlines++; - return newlines; -} - char *w2_err_format(w2_s_error *error) { const char *type = g_w2_error_type_strings[error->code >> 6]; const char *internal = g_w2_error_internal_strings[error->code]; diff --git a/client/ui_modes.c b/client/ui_modes.c new file mode 100644 index 0000000..933f47b --- /dev/null +++ b/client/ui_modes.c @@ -0,0 +1,10 @@ +#include "ui.h" + +void w2_ui_onkey_modes(int ch) { + +} + +void w2_ui_tab_modes(bool first) { + +} + diff --git a/client/ui_orders.c b/client/ui_orders.c new file mode 100644 index 0000000..4951ba6 --- /dev/null +++ b/client/ui_orders.c @@ -0,0 +1,116 @@ +#include +#include +#include + +#include "ui.h" +#include "errcatch.h" +#include "../shared/util.h" +#include "../shared/bin.h" +#include "../shared/protocol.h" +#include "i18n.h" +#include "commands.h" +#include "main.h" + +#define W2_IS_CMD(cmd) strncmp(g_w2_command_buffer, cmd, sizeof(cmd) - 1) == 0 +#define W2_UI_ORDERS_PRINT_CONST(text) \ + w2_wmvaddstr(g_w2_ui_pad_body, g_w2_order_line, 0, text); \ + g_w2_order_line += w2_newline_count(text, sizeof(text)); + +char g_w2_command_buffer[W2_UI_ORDER_CMD_BUFFER_SIZE] = { 0x00 }; +int g_w2_command_buffer_index = 0; +int g_w2_order_line = 0; +bool g_w2_order_recording = false; +bool g_w2_order_saved = false; +uint16_t g_w2_order_buffer[W2_UI_ORDER_BUFFER_SIZE] = { 0 }; +int g_w2_order_buffer_index = 0; + +void w2_ui_orders_cmd_error() { + W2_UI_ORDERS_PRINT_CONST(W2_UI_ORDER_MSG_ERROR); +} + +void w2_ui_orders_cmd_help() { + W2_UI_ORDERS_PRINT_CONST(W2_UI_ORDER_MSG_HELP); +} + +void w2_ui_orders_cmd_start() { + if (g_w2_order_recording) { + W2_UI_ORDERS_PRINT_CONST(W2_UI_ORDER_MSG_ORDER_START_ERR); + } else { + W2_UI_ORDERS_PRINT_CONST(W2_UI_ORDER_MSG_ORDER_START_OK); + g_w2_order_buffer_index = 0; + } + g_w2_order_recording = true; +} + +void w2_ui_orders_cmd_coordinate() { + if (!g_w2_order_recording) { + W2_UI_ORDERS_PRINT_CONST(W2_UI_ORDER_MSG_ORDER_APPEND_ERR); + return; + } + unsigned int x, y; + if (sscanf(g_w2_command_buffer, W2_UI_ORDER_CMD_COORDINATE " %u %u", &x, &y) != 2) + return w2_ui_orders_cmd_error(); + g_w2_order_buffer[g_w2_order_buffer_index++] = y * g_w2_state.map_width + x; + W2_UI_ORDERS_PRINT_CONST(W2_UI_ORDER_MSG_ORDER_APPEND_OK); +} + +void w2_ui_orders_cmd_done() { + if (g_w2_order_recording) { + W2_UI_ORDERS_PRINT_CONST(W2_UI_ORDER_MSG_ORDER_DONE_OK); + } else { + W2_UI_ORDERS_PRINT_CONST(W2_UI_ORDER_MSG_ORDER_DONE_ERR); + } + g_w2_order_saved = true; + g_w2_order_recording = false; +} + +void w2_ui_orders_cmd_send() { + for (int i = 0; i < g_w2_order_buffer_index; i++) { + W2_CREATE_MSG_BIN(w2_s_cmd_bomd_rx, msg, bin); + + msg->position = w2_bin_hton16(g_w2_order_buffer[i]); + msg->id = rand(); + + w2_send_bin(bin); + free(bin); + } + W2_UI_ORDERS_PRINT_CONST(W2_UI_ORDER_MSG_ORDER_SENT); +} + +void w2_ui_orders_process_cmd() { + if (g_w2_command_buffer_index == 0) return w2_ui_orders_cmd_error(); + if (W2_IS_CMD(W2_UI_ORDER_CMD_HELP)) return w2_ui_orders_cmd_help(); + if (W2_IS_CMD(W2_UI_ORDER_CMD_START)) return w2_ui_orders_cmd_start(); + if (W2_IS_CMD(W2_UI_ORDER_CMD_COORDINATE)) return w2_ui_orders_cmd_coordinate(); + if (W2_IS_CMD(W2_UI_ORDER_CMD_DONE)) return w2_ui_orders_cmd_done(); + if (W2_IS_CMD(W2_UI_ORDER_CMD_SEND)) return w2_ui_orders_cmd_send(); + return w2_ui_orders_cmd_error(); +} + +void w2_ui_onkey_orders(int ch) { + if (ch >= 'A' && ch <= 'Z') ch += 0x20; // convert uppercase to lowercase + if ((ch >= 'a' && ch <= 'z') || (ch >= '0' && ch <= '9') || (ch == ' ')) { + g_w2_command_buffer[g_w2_command_buffer_index] = ch; + g_w2_command_buffer_index = W2_MIN(g_w2_command_buffer_index + 1, W2_UI_ORDER_CMD_BUFFER_SIZE - 1); + } else if (ch == KEY_BACKSPACE) { + g_w2_command_buffer_index = W2_MAX(g_w2_command_buffer_index - 1, 0); + g_w2_command_buffer[g_w2_command_buffer_index] = 0x00; + } else if (ch == 0x0a) { + // clear cursor + wmove(g_w2_ui_pad_body, g_w2_order_line, g_w2_command_buffer_index + 2); + waddstr(g_w2_ui_pad_body, " "); + + g_w2_order_line += 1; + w2_ui_orders_process_cmd(); + memset(g_w2_command_buffer, 0x00, W2_UI_ORDER_CMD_BUFFER_SIZE); + g_w2_command_buffer_index = 0; + } +} + +void w2_ui_tab_orders(bool first) { + if (first) g_w2_order_line = 0; + char temp[100]; + sprintf(temp, "> %s_ ", g_w2_command_buffer); + w2_wmvaddstr(g_w2_ui_pad_body, g_w2_order_line, 0, temp); +} + diff --git a/client/ui_tabbar.c b/client/ui_tabbar.c index 87e3f06..1baf559 100644 --- a/client/ui_tabbar.c +++ b/client/ui_tabbar.c @@ -15,6 +15,10 @@ void w2_ui_tabbar_init() { g_w2_keyhndl_ptrs[W2_UI_TAB_START] = &w2_ui_onkey_errcatch; g_w2_tab_ptrs[W2_UI_TAB_DIRC] = &w2_ui_tab_dirc; g_w2_keyhndl_ptrs[W2_UI_TAB_DIRC] = &w2_ui_onkey_dirc; + g_w2_tab_ptrs[W2_UI_TAB_ORDERS] = &w2_ui_tab_orders; + g_w2_keyhndl_ptrs[W2_UI_TAB_ORDERS] = &w2_ui_onkey_orders; + g_w2_tab_ptrs[W2_UI_TAB_MODES] = &w2_ui_tab_modes; + g_w2_keyhndl_ptrs[W2_UI_TAB_MODES] = &w2_ui_onkey_modes; } void w2_ui_paint_tabbar() { diff --git a/readme.md b/readme.md index 610f99d..6072c0d 100644 --- a/readme.md +++ b/readme.md @@ -15,10 +15,14 @@ are only supported on linux: |-|:-:|:-:| |robot code compilation (avr)|yes|yes| |robot exec upload|yes|yes| -|client code compilation|yes|yes| +|client code compilation| |yes| |robot code simulation (x86)| |yes| |use client with robot sim| |yes| +the client only compiles and runs on linux due to time constraints. because +package names vary from distribution to distribution, no scripts are included +to install the necessary build tools for linux. + ## toolchain installation on windows > look in the scripts/ subdirectory if you're concerned about what these diff --git a/shared/consts.h b/shared/consts.h index cd6dff1..11e6d14 100644 --- a/shared/consts.h +++ b/shared/consts.h @@ -35,6 +35,10 @@ /** max time between ping and answer */ #define W2_PING_TIMEOUT (5e3) +/** default map width/height */ +#define W2_MAP_DEFAULT_HEIGHT 5 +#define W2_MAP_DEFAULT_WIDTH 5 + /** front-facing distance sensor pinout */ #define W2_FRONT_SENSOR_PIN 5 /** battery voltage sensor pinout */ diff --git a/shared/util.c b/shared/util.c index 68503e8..641b4d9 100644 --- a/shared/util.c +++ b/shared/util.c @@ -6,3 +6,11 @@ unsigned long w2_util_exp_mov_avg(unsigned long current_avg, unsigned long new_m } int w2_sign(int n) { return (n > 0) - (n < 0); } + +unsigned int w2_newline_count(char *str, unsigned int len) { + unsigned int newlines = 0; + for (unsigned int i = 0; i < len; i++) + if (str[i] == '\n') newlines++; + return newlines; +} + diff --git a/shared/util.h b/shared/util.h index 230c3e4..806af3a 100644 --- a/shared/util.h +++ b/shared/util.h @@ -6,5 +6,9 @@ #define W2_MAX(a, b) (((a) > (b)) ? (a) : (b)) #define W2_RANGE(min, val, max) W2_MIN(max, W2_MAX(val, min)) +/** calculate exponential moving average */ unsigned long w2_util_exp_mov_avg(unsigned long current_avg, unsigned long new_meas); +/** return the sign of a number (-1 or 1) */ int w2_sign(int n); +/** return amount of newline characters */ +unsigned int w2_newline_count(char *str, unsigned int len); -- cgit v1.2.3