From 58a0b5fd115d9687a1292e5e82e6b9fa8454b930 Mon Sep 17 00:00:00 2001 From: Your Name Date: Tue, 19 May 2026 01:44:11 +0530 Subject: Dynamic layout for WiFi setup: landscape rotation, responsive render, highlight feedback - Render functions use axs15231b_get_width/height() instead of hardcoded coords - render_wifi_setup_list: dynamic item widths, screen-relative cancel button - render_wifi_setup_password: dynamic field/eye/keyboard from kb_get_layout() - render_wifi_setup_result: centered on screen, dynamic button placement - handle_wifi_setup_touch: matching dynamic hit areas, highlight_rect() feedback - Rotation lifecycle: enter_wifi_setup_rotation/exit wired into all entry/exit paths - display_enter_wifi_setup + READY/ERROR touch + SUCCESS auto-return + LIST cancel - Added kb_result_t typedef to keyboard.h (was only in .c) - Fixed test_keyboard.c: use computed offsets from kb_layout_t defaults - All 101 unit tests pass (touch:19, keyboard:46, wifi_setup:36) --- components/axs15231b/axs15231b.c | 32 ++++++ components/axs15231b/include/axs15231b.h | 1 + main/display.c | 164 +++++++++++++++++++++++-------- main/keyboard.c | 72 +++++++++----- main/keyboard.h | 26 +++-- main/touch.c | 25 +++++ main/touch.h | 1 + tests/unit/test_keyboard | Bin 0 -> 35416 bytes tests/unit/test_keyboard.c | 22 +++-- tests/unit/test_touch | Bin 0 -> 30304 bytes tests/unit/test_wifi_setup | Bin 0 -> 33336 bytes 11 files changed, 261 insertions(+), 82 deletions(-) create mode 100755 tests/unit/test_keyboard create mode 100755 tests/unit/test_touch create mode 100755 tests/unit/test_wifi_setup diff --git a/components/axs15231b/axs15231b.c b/components/axs15231b/axs15231b.c index 7424a20..77708dd 100644 --- a/components/axs15231b/axs15231b.c +++ b/components/axs15231b/axs15231b.c @@ -37,6 +37,7 @@ static spi_device_handle_t s_spi = NULL; static uint16_t *s_fb = NULL; static int s_width = AXS15231B_WIDTH; static int s_height = AXS15231B_HEIGHT; +static int s_rotation = 0; static uint8_t *s_swap_buf = NULL; #define SWAP_BUF_PIXELS 2048 @@ -354,3 +355,34 @@ void axs15231b_flush(void) { int axs15231b_get_width(void) { return s_width; } int axs15231b_get_height(void) { return s_height; } + +void axs15231b_set_rotation(int rotation) { + uint8_t madctl = MADCTL_RGB; + switch (rotation) { + case 0: + madctl = MADCTL_RGB; + s_width = AXS15231B_WIDTH; + s_height = AXS15231B_HEIGHT; + break; + case 1: + madctl = MADCTL_MX | MADCTL_MV; + s_width = AXS15231B_HEIGHT; + s_height = AXS15231B_WIDTH; + break; + case 2: + madctl = MADCTL_MX | MADCTL_MY; + s_width = AXS15231B_WIDTH; + s_height = AXS15231B_HEIGHT; + break; + case 3: + madctl = MADCTL_MY | MADCTL_MV; + s_width = AXS15231B_HEIGHT; + s_height = AXS15231B_WIDTH; + break; + default: + return; + } + s_rotation = rotation; + qspi_write_cmd_data8(MADCTL, madctl); + ESP_LOGI(TAG, "Rotation set to %d (%dx%d)", rotation, s_width, s_height); +} diff --git a/components/axs15231b/include/axs15231b.h b/components/axs15231b/include/axs15231b.h index cddea98..a8c1a37 100644 --- a/components/axs15231b/include/axs15231b.h +++ b/components/axs15231b/include/axs15231b.h @@ -23,5 +23,6 @@ void axs15231b_fill_rect(int x, int y, int w, int h, uint16_t color); void axs15231b_flush(void); int axs15231b_get_width(void); int axs15231b_get_height(void); +void axs15231b_set_rotation(int rotation); #endif diff --git a/main/display.c b/main/display.c index e5e31c4..77b911d 100644 --- a/main/display.c +++ b/main/display.c @@ -46,18 +46,54 @@ static int64_t s_last_allotment_ms = 0; #define COLOR_GRAY 0x8410 #define COLOR_DARKGRAY 0x4208 #define COLOR_LIGHTBLUE 0xA5FF +#define COLOR_HIGHLIGHT 0x07E0 static wifi_setup_t s_wifi_setup; static kb_state_t s_kb_state; static bool s_wifi_setup_active = false; static bool s_touch_initialized = false; static bool s_wifi_scan_pending = false; +static int s_display_rotation = 0; #define SETUP_BTN_X 240 #define SETUP_BTN_Y 440 #define SETUP_BTN_W 72 #define SETUP_BTN_H 30 +static void enter_wifi_setup_rotation(void) { + if (s_display_rotation != 1) { + s_display_rotation = 1; + axs15231b_set_rotation(1); + touch_set_rotation(1); + kb_layout_t landscape = { + .key_w = 38, + .key_h = 40, + .key_gap = 2, + .start_y = 170, + .screen_w = 480, + .row_count = 4, + }; + kb_set_layout(&landscape); + } +} + +static void exit_wifi_setup_rotation(void) { + if (s_display_rotation != 0) { + s_display_rotation = 0; + axs15231b_set_rotation(0); + touch_set_rotation(0); + kb_layout_t portrait = { + .key_w = 28, + .key_h = 36, + .key_gap = 2, + .start_y = 70, + .screen_w = 320, + .row_count = 4, + }; + kb_set_layout(&portrait); + } +} + static void render_setup_button(int x, int y, int w, int h) { axs15231b_fill_rect(x, y, w, h, COLOR_DARKGRAY); const char *label = "Setup"; @@ -69,6 +105,14 @@ static bool touch_in_rect(uint16_t tx, uint16_t ty, int x, int y, int w, int h) return tx >= x && tx < x + w && ty >= y && ty < y + h; } +static void highlight_rect(int x, int y, int w, int h) { + axs15231b_fill_rect(x, y, w, h, COLOR_HIGHLIGHT); + axs15231b_flush(); + vTaskDelay(pdMS_TO_TICKS(80)); + axs15231b_fill_rect(x, y, w, h, COLOR_DARKGRAY); + axs15231b_flush(); +} + static int qr_version_from_strlen(int len) { if (len <= 17) return 1; if (len <= 32) return 2; @@ -357,6 +401,7 @@ static void render_wifi_setup_scanning(void) { static void render_wifi_setup_list(void) { int screen_w = axs15231b_get_width(); + int screen_h = axs15231b_get_height(); axs15231b_fill_screen(COLOR_BG); const char *title = "Select Network"; @@ -365,47 +410,51 @@ static void render_wifi_setup_list(void) { int y = 25; int visible = wifi_setup_visible_count(&s_wifi_setup); + int item_w = screen_w - 20; + int max_y = screen_h - 40; - for (int i = 0; i < visible && y < 295; i++) { + for (int i = 0; i < visible && y < max_y; i++) { const wifi_ap_info_t *ap = wifi_setup_get_visible(&s_wifi_setup, i); if (!ap) break; - char line[40]; int rssi_bars = 0; if (ap->rssi >= -30) rssi_bars = 4; else if (ap->rssi >= -50) rssi_bars = 3; else if (ap->rssi >= -70) rssi_bars = 2; else rssi_bars = 1; - snprintf(line, sizeof(line), "%s", ap->ssid); - axs15231b_fill_rect(5, y, 260, 26, COLOR_DARKGRAY); - display_render_text(10, y + 4, line, COLOR_WHITE, COLOR_DARKGRAY, 1); + axs15231b_fill_rect(10, y, item_w, 26, COLOR_DARKGRAY); + display_render_text(15, y + 4, ap->ssid, COLOR_WHITE, COLOR_DARKGRAY, 1); + int bar_x = 10 + item_w - 50; for (int b = 0; b < rssi_bars; b++) { - axs15231b_fill_rect(270 + b * 8, y + 16 - (b + 1) * 4, 6, (b + 1) * 4, COLOR_GREEN); + axs15231b_fill_rect(bar_x + b * 10, y + 16 - (b + 1) * 4, 8, (b + 1) * 4, COLOR_GREEN); } if (ap->secured) { - const char *lock = "*"; - display_render_text(254, y + 4, lock, COLOR_YELLOW, COLOR_DARKGRAY, 1); + display_render_text(bar_x - 12, y + 4, "*", COLOR_YELLOW, COLOR_DARKGRAY, 1); } y += 30; } - render_setup_button(5, 440, 50, 28); - display_render_text(10, 444, "X", COLOR_WHITE, COLOR_DARKGRAY, 1); + int btn_y = screen_h - 30; + axs15231b_fill_rect(10, btn_y, 50, 26, COLOR_DARKGRAY); + display_render_text(25, btn_y + 5, "X", COLOR_WHITE, COLOR_DARKGRAY, 1); axs15231b_flush(); } static void render_wifi_setup_password(void) { + int screen_w = axs15231b_get_width(); + const kb_layout_t *kb = kb_get_layout(); axs15231b_fill_screen(COLOR_BG); display_render_text(10, 5, s_wifi_setup.selected_ssid, COLOR_CYAN, COLOR_BG, 1); display_render_text(10, 25, "Password:", COLOR_DIM, COLOR_BG, 1); - axs15231b_fill_rect(10, 40, 220, 20, COLOR_DARKGRAY); + int field_w = screen_w - 80; + axs15231b_fill_rect(10, 40, field_w, 20, COLOR_DARKGRAY); char masked[KB_INPUT_MAX + 1]; if (s_kb_state.reveal) { @@ -413,30 +462,40 @@ static void render_wifi_setup_password(void) { masked[sizeof(masked) - 1] = '\0'; } else { int len = s_kb_state.cursor; - if (len > 27) len = 27; + int max_chars = (field_w - 8) / 8; + if (len > max_chars) len = max_chars; for (int i = 0; i < len; i++) masked[i] = '*'; masked[len] = '\0'; } display_render_text(14, 43, masked, COLOR_WHITE, COLOR_DARKGRAY, 1); + int eye_x = 10 + field_w + 5; const char *eye_label = s_kb_state.reveal ? "H" : "S"; - axs15231b_fill_rect(235, 40, 24, 20, COLOR_GRAY); - display_render_text(241, 43, eye_label, COLOR_WHITE, COLOR_GRAY, 1); + axs15231b_fill_rect(eye_x, 40, 24, 20, COLOR_GRAY); + display_render_text(eye_x + 8, 43, eye_label, COLOR_WHITE, COLOR_GRAY, 1); - int kb_y = 70; - for (int row = 0; row < KB_ROW_COUNT; row++) { + int kb_y = kb->start_y; + for (int row = 0; row < kb->row_count; row++) { const char *row_str; int key_count = kb_get_row_keys(row, s_kb_state.layer, &row_str); - int x_off = (row == 0) ? 5 : (row == 1) ? 14 : (row == 2) ? 23 : 5; + const char *tmp; + int total_keys = kb_get_row_keys(row, s_kb_state.layer, &tmp); + int x_off = (row == 0) ? (screen_w - total_keys * kb->key_w - (total_keys - 1) * kb->key_gap) / 2 + : (row == 1) ? (screen_w - total_keys * kb->key_w - (total_keys - 1) * kb->key_gap) / 2 + kb->key_w / 2 + : (row == 2) ? (screen_w - total_keys * kb->key_w - (total_keys - 1) * kb->key_gap) / 2 + kb->key_w + : (screen_w - total_keys * kb->key_w - (total_keys - 1) * kb->key_gap) / 2; int cx = x_off; for (int col = 0; col < key_count; col++) { char c = row_str[col]; - int kw = 28; + int kw = kb->key_w; if (row == 3) { - if (col == 0) kw = 42; - else if (col == key_count - 1) kw = 50; - else kw = 168; + int margin = (screen_w - total_keys * kb->key_w - (total_keys - 1) * kb->key_gap) / 2; + int available = screen_w - margin * 2; + int side_w = (available - kb->key_gap) / 4; + if (col == 0) kw = side_w; + else if (col == key_count - 1) kw = side_w; + else kw = available - side_w * 2 - kb->key_gap * 2; } uint16_t bg = COLOR_DARKGRAY; @@ -461,12 +520,12 @@ static void render_wifi_setup_password(void) { label[0] = c; } - axs15231b_fill_rect(cx, kb_y, kw, 30, bg); + axs15231b_fill_rect(cx, kb_y, kw, kb->key_h, bg); int lw = 8; - display_render_text(cx + (kw - lw) / 2, kb_y + 8, label, fg, bg, 1); - cx += kw + 2; + display_render_text(cx + (kw - lw) / 2, kb_y + (kb->key_h - 8) / 2, label, fg, bg, 1); + cx += kw + kb->key_gap; } - kb_y += 34; + kb_y += kb->key_h + kb->key_gap; } axs15231b_flush(); @@ -492,53 +551,65 @@ static void render_wifi_setup_connecting(void) { static void render_wifi_setup_result(void) { int screen_w = axs15231b_get_width(); + int screen_h = axs15231b_get_height(); axs15231b_fill_screen(COLOR_BG); if (s_wifi_setup.state == SETUP_SUCCESS) { const char *msg = "Connected!"; int mw = strlen(msg) * 8 * 2; - display_render_text((screen_w - mw) / 2, 180, msg, COLOR_WHITE, COLOR_GREEN, 2); + display_render_text((screen_w - mw) / 2, screen_h / 2 - 40, msg, COLOR_WHITE, COLOR_GREEN, 2); if (s_wifi_setup.connect_ip[0]) { char ip_line[32]; snprintf(ip_line, sizeof(ip_line), "IP: %s", s_wifi_setup.connect_ip); int iw = strlen(ip_line) * 8; - display_render_text((screen_w - iw) / 2, 240, ip_line, COLOR_WHITE, COLOR_BG, 1); + display_render_text((screen_w - iw) / 2, screen_h / 2, ip_line, COLOR_WHITE, COLOR_BG, 1); } } else { const char *msg = "Connection failed"; int mw = strlen(msg) * 8 * 2; - display_render_text((screen_w - mw) / 2, 180, msg, COLOR_WHITE, COLOR_RED, 2); + display_render_text((screen_w - mw) / 2, screen_h / 2 - 40, msg, COLOR_WHITE, COLOR_RED, 2); const char *hint = "Wrong password?"; int hw = strlen(hint) * 8; - display_render_text((screen_w - hw) / 2, 240, hint, COLOR_YELLOW, COLOR_BG, 1); - - axs15231b_fill_rect(30, 280, 120, 30, COLOR_DARKGRAY); - display_render_text(50, 288, "Retry", COLOR_WHITE, COLOR_DARKGRAY, 1); - axs15231b_fill_rect(170, 280, 120, 30, COLOR_DARKGRAY); - display_render_text(180, 288, "Change", COLOR_WHITE, COLOR_DARKGRAY, 1); + display_render_text((screen_w - hw) / 2, screen_h / 2, hint, COLOR_YELLOW, COLOR_BG, 1); + + int btn_y = screen_h / 2 + 30; + int btn_w = (screen_w - 40) / 2; + axs15231b_fill_rect(10, btn_y, btn_w, 30, COLOR_DARKGRAY); + display_render_text(10 + (btn_w - 40) / 2, btn_y + 8, "Retry", COLOR_WHITE, COLOR_DARKGRAY, 1); + axs15231b_fill_rect(20 + btn_w, btn_y, btn_w, 30, COLOR_DARKGRAY); + display_render_text(20 + btn_w + (btn_w - 50) / 2, btn_y + 8, "Change", COLOR_WHITE, COLOR_DARKGRAY, 1); } axs15231b_flush(); } static void handle_wifi_setup_touch(uint16_t tx, uint16_t ty) { + int screen_w = axs15231b_get_width(); + int screen_h = axs15231b_get_height(); + switch (s_wifi_setup.state) { case SETUP_SCAN: break; case SETUP_LIST: { - if (touch_in_rect(tx, ty, 5, 440, 50, 28)) { + int btn_y = screen_h - 30; + if (touch_in_rect(tx, ty, 10, btn_y, 50, 26)) { + highlight_rect(10, btn_y, 50, 26); wifi_setup_handle_cancel(&s_wifi_setup); s_wifi_setup_active = false; + exit_wifi_setup_rotation(); s_state = DISPLAY_ERROR; return; } + int item_w = screen_w - 20; int y = 25; + int max_y = screen_h - 40; int visible = wifi_setup_visible_count(&s_wifi_setup); - for (int i = 0; i < visible; i++) { - if (touch_in_rect(tx, ty, 5, y, 300, 26)) { + for (int i = 0; i < visible && y < max_y; i++) { + if (touch_in_rect(tx, ty, 10, y, item_w, 26)) { + highlight_rect(10, y, item_w, 26); wifi_setup_handle_select(&s_wifi_setup, i); kb_state_init(&s_kb_state); return; @@ -549,12 +620,17 @@ static void handle_wifi_setup_touch(uint16_t tx, uint16_t ty) { } case SETUP_PASSWORD: { - if (touch_in_rect(tx, ty, 235, 40, 24, 20)) { + int field_w = screen_w - 80; + int eye_x = 10 + field_w + 5; + if (touch_in_rect(tx, ty, eye_x, 40, 24, 20)) { s_kb_state.reveal = !s_kb_state.reveal; return; } kb_result_t r = kb_hit_test(tx, ty, s_kb_state.layer); if (r.action != KB_ACTION_NONE) { + axs15231b_fill_rect(tx - 20, ty - 20, 40, 40, COLOR_HIGHLIGHT); + axs15231b_flush(); + vTaskDelay(pdMS_TO_TICKS(60)); if (r.action == KB_ACTION_DONE && s_kb_state.cursor > 0) { wifi_setup_handle_connect(&s_wifi_setup); wifi_config_t wifi_cfg = {0}; @@ -578,15 +654,20 @@ static void handle_wifi_setup_touch(uint16_t tx, uint16_t ty) { case SETUP_SUCCESS: { wifi_setup_handle_cancel(&s_wifi_setup); s_wifi_setup_active = false; + exit_wifi_setup_rotation(); s_state = DISPLAY_READY; return; } case SETUP_FAILED: { - if (touch_in_rect(tx, ty, 30, 280, 120, 30)) { + int btn_y = screen_h / 2 + 30; + int btn_w = (screen_w - 40) / 2; + if (touch_in_rect(tx, ty, 10, btn_y, btn_w, 30)) { + highlight_rect(10, btn_y, btn_w, 30); wifi_setup_handle_retry(&s_wifi_setup); kb_state_init(&s_kb_state); - } else if (touch_in_rect(tx, ty, 170, 280, 120, 30)) { + } else if (touch_in_rect(tx, ty, 20 + btn_w, btn_y, btn_w, 30)) { + highlight_rect(20 + btn_w, btn_y, btn_w, 30); wifi_setup_handle_change_network(&s_wifi_setup); } break; @@ -618,6 +699,7 @@ static void display_task(void *pvParameters) { state = s_state; } else if (state == DISPLAY_ERROR || state == DISPLAY_READY) { if (touch_in_rect(tp.x, tp.y, SETUP_BTN_X, SETUP_BTN_Y, SETUP_BTN_W, SETUP_BTN_H)) { + enter_wifi_setup_rotation(); s_wifi_setup_active = true; wifi_setup_init(&s_wifi_setup); kb_state_init(&s_kb_state); @@ -710,6 +792,7 @@ static void display_task(void *pvParameters) { vTaskDelay(pdMS_TO_TICKS(3000)); wifi_setup_handle_cancel(&s_wifi_setup); s_wifi_setup_active = false; + exit_wifi_setup_rotation(); s_state = DISPLAY_READY; break; case SETUP_FAILED: @@ -804,6 +887,7 @@ void display_notify_wifi_disconnected(void) { void display_enter_wifi_setup(void) { if (!s_initialized) return; + enter_wifi_setup_rotation(); s_wifi_setup_active = true; wifi_setup_init(&s_wifi_setup); kb_state_init(&s_kb_state); diff --git a/main/keyboard.c b/main/keyboard.c index 33365de..d16135f 100644 --- a/main/keyboard.c +++ b/main/keyboard.c @@ -28,6 +28,15 @@ static const char *s_numsym[] = { #define CTRL_DONE '\004' #define CTRL_BS '\b' +static kb_layout_t s_layout = { + .key_w = 28, + .key_h = 36, + .key_gap = 2, + .start_y = 70, + .screen_w = 320, + .row_count = 4, +}; + void kb_state_init(kb_state_t *st) { if (!st) return; memset(st, 0, sizeof(*st)); @@ -35,6 +44,14 @@ void kb_state_init(kb_state_t *st) { st->reveal = false; } +void kb_set_layout(const kb_layout_t *layout) { + if (layout) s_layout = *layout; +} + +const kb_layout_t *kb_get_layout(void) { + return &s_layout; +} + static const char **get_layer(kb_layer_t layer) { switch (layer) { case KB_ALPHA_UPPER: return s_alpha_upper; @@ -43,12 +60,8 @@ static const char **get_layer(kb_layer_t layer) { } } -static int key_is_ctrl(char c) { - return c == CTRL_SHIFT || c == CTRL_LAYER || c == CTRL_SPACE || c == CTRL_DONE || c == CTRL_BS; -} - int kb_get_row_keys(int row, kb_layer_t layer, const char **keys_out) { - if (row < 0 || row >= KB_ROW_COUNT) { + if (row < 0 || row >= s_layout.row_count) { *keys_out = NULL; return 0; } @@ -58,46 +71,59 @@ int kb_get_row_keys(int row, kb_layer_t layer, const char **keys_out) { return (int)strlen(row_str); } -static int row_x_offset(int row) { +static int row_x_offset(int row, int total_keys) { + int kw = s_layout.key_w; + int gap = s_layout.key_gap; + int total_w = total_keys * kw + (total_keys - 1) * gap; + int margin = (s_layout.screen_w - total_w) / 2; + if (margin < 2) margin = 2; switch (row) { - case 0: return 5; - case 1: return 14; - case 2: return 23; - case 3: return 5; - default: return 0; + case 0: return margin; + case 1: return margin + kw / 2; + case 2: return margin + kw; + case 3: return margin; + default: return margin; } } static int key_width_at(int row, int col, int total_keys) { - (void)col; + int kw = s_layout.key_w; if (row == 3) { - if (col == 0) return 42; - if (col == total_keys - 1) return 50; - return 168; + int gap = s_layout.key_gap; + int margin = row_x_offset(3, total_keys); + int available = s_layout.screen_w - margin * 2; + int side_w = (available - gap) / 4; + if (col == 0) return side_w; + if (col == total_keys - 1) return side_w; + return available - side_w * 2 - gap * 2; } - return KB_KEY_W; + return kw; } kb_result_t kb_hit_test(int tx, int ty, kb_layer_t layer) { kb_result_t result = {KB_ACTION_NONE, 0}; + int sy = s_layout.start_y; + int kw = s_layout.key_w; + int kh = s_layout.key_h; + int gap = s_layout.key_gap; - if (ty < KB_START_Y || ty >= KB_START_Y + KB_ROW_COUNT * (KB_KEY_H + KB_KEY_GAP)) { + if (ty < sy || ty >= sy + s_layout.row_count * (kh + gap)) { return result; } - int row = (ty - KB_START_Y) / (KB_KEY_H + KB_KEY_GAP); - if (row < 0 || row >= KB_ROW_COUNT) return result; + int row = (ty - sy) / (kh + gap); + if (row < 0 || row >= s_layout.row_count) return result; const char *row_str; int total_keys = kb_get_row_keys(row, layer, &row_str); if (total_keys == 0) return result; - int x_off = row_x_offset(row); + int x_off = row_x_offset(row, total_keys); int cx = x_off; for (int col = 0; col < total_keys; col++) { - int kw = key_width_at(row, col, total_keys); - if (tx >= cx && tx < cx + kw) { + int key_w = key_width_at(row, col, total_keys); + if (tx >= cx && tx < cx + key_w) { char c = row_str[col]; if (c == CTRL_SHIFT) { result.action = KB_ACTION_SHIFT; @@ -116,7 +142,7 @@ kb_result_t kb_hit_test(int tx, int ty, kb_layer_t layer) { } return result; } - cx += kw + KB_KEY_GAP; + cx += key_w + gap; } return result; diff --git a/main/keyboard.h b/main/keyboard.h index 495c499..9c4118f 100644 --- a/main/keyboard.h +++ b/main/keyboard.h @@ -5,11 +5,6 @@ #include #define KB_INPUT_MAX 64 -#define KB_KEY_W 28 -#define KB_KEY_H 36 -#define KB_KEY_GAP 2 -#define KB_ROW_COUNT 4 -#define KB_START_Y 70 typedef enum { KB_ALPHA_LOWER, @@ -27,11 +22,6 @@ typedef enum { KB_ACTION_SPACE } kb_action_t; -typedef struct { - kb_action_t action; - char ch; -} kb_result_t; - typedef struct { char input[KB_INPUT_MAX + 1]; int cursor; @@ -39,7 +29,23 @@ typedef struct { kb_layer_t layer; } kb_state_t; +typedef struct { + kb_action_t action; + char ch; +} kb_result_t; + +typedef struct { + int key_w; + int key_h; + int key_gap; + int start_y; + int screen_w; + int row_count; +} kb_layout_t; + void kb_state_init(kb_state_t *st); +void kb_set_layout(const kb_layout_t *layout); +const kb_layout_t *kb_get_layout(void); int kb_get_row_keys(int row, kb_layer_t layer, const char **keys_out); kb_result_t kb_hit_test(int tx, int ty, kb_layer_t layer); void kb_apply(kb_state_t *st, kb_result_t result); diff --git a/main/touch.c b/main/touch.c index 5a1eec9..a28d13e 100644 --- a/main/touch.c +++ b/main/touch.c @@ -11,6 +11,7 @@ static const char *TAG = "touch"; static i2c_master_bus_handle_t s_bus = NULL; static i2c_master_dev_handle_t s_dev = NULL; static bool s_initialized = false; +static int s_rotation = 0; static const uint8_t s_read_cmd[11] = { 0xb5, 0xab, 0xa5, 0x5a, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00 @@ -115,9 +116,33 @@ bool touch_read(touch_point_t *pt) { } touch_parse_raw(data, pt); + + if (pt->touched && s_rotation != 0) { + uint16_t raw_x = pt->x; + uint16_t raw_y = pt->y; + switch (s_rotation) { + case 1: + pt->x = raw_y; + pt->y = TOUCH_MAX_X - raw_x; + break; + case 2: + pt->x = TOUCH_MAX_X - raw_x; + pt->y = TOUCH_MAX_Y - raw_y; + break; + case 3: + pt->x = TOUCH_MAX_Y - raw_y; + pt->y = raw_x; + break; + } + } + return pt->touched; } +void touch_set_rotation(int rotation) { + s_rotation = rotation; +} + void touch_deinit(void) { if (s_dev) { i2c_master_bus_rm_device(s_dev); diff --git a/main/touch.h b/main/touch.h index a4a5aa4..b9e3ccd 100644 --- a/main/touch.h +++ b/main/touch.h @@ -22,6 +22,7 @@ typedef struct { esp_err_t touch_init(void); bool touch_read(touch_point_t *pt); void touch_deinit(void); +void touch_set_rotation(int rotation); void touch_parse_raw(const uint8_t *data, touch_point_t *pt); diff --git a/tests/unit/test_keyboard b/tests/unit/test_keyboard new file mode 100755 index 0000000..61cc9f5 Binary files /dev/null and b/tests/unit/test_keyboard differ diff --git a/tests/unit/test_keyboard.c b/tests/unit/test_keyboard.c index e069f28..81ca328 100644 --- a/tests/unit/test_keyboard.c +++ b/tests/unit/test_keyboard.c @@ -41,37 +41,41 @@ int main(void) kb_result_t r = kb_hit_test(160, 10, KB_ALPHA_LOWER); ASSERT(r.action == KB_ACTION_NONE, "Touch above keyboard = NONE"); - r = kb_hit_test(160, KB_START_Y + KB_ROW_COUNT * (KB_KEY_H + KB_KEY_GAP) + 10, KB_ALPHA_LOWER); + r = kb_hit_test(160, 70 + 4 * (36 + 2) + 10, KB_ALPHA_LOWER); ASSERT(r.action == KB_ACTION_NONE, "Touch below keyboard = NONE"); } { - int mid_x = 5 + KB_KEY_W / 2; - int mid_y = KB_START_Y + KB_KEY_H / 2; + int margin_r0 = (320 - (10 * 28 + 9 * 2)) / 2; + int mid_x = margin_r0 + 28 / 2; + int mid_y = 70 + 36 / 2; kb_result_t r = kb_hit_test(mid_x, mid_y, KB_ALPHA_LOWER); ASSERT(r.action == KB_ACTION_CHAR, "Row 0 first key is a char"); ASSERT_EQ_INT('q', r.ch, "Row 0 first key = 'q'"); } { - int x = 5 + KB_KEY_W + KB_KEY_GAP + KB_KEY_W / 2; - int y = KB_START_Y + KB_KEY_H / 2; + int margin_r0 = (320 - (10 * 28 + 9 * 2)) / 2; + int x = margin_r0 + 28 + 2 + 28 / 2; + int y = 70 + 36 / 2; kb_result_t r = kb_hit_test(x, y, KB_ALPHA_LOWER); ASSERT(r.action == KB_ACTION_CHAR, "Row 0 second key is a char"); ASSERT_EQ_INT('w', r.ch, "Row 0 second key = 'w'"); } { - int y_row1 = KB_START_Y + (KB_KEY_H + KB_KEY_GAP) + KB_KEY_H / 2; - int x_row1 = 14 + KB_KEY_W / 2; + int margin_r1 = (320 - (9 * 28 + 8 * 2)) / 2; + int y_row1 = 70 + (36 + 2) + 36 / 2; + int x_row1 = margin_r1 + 28 / 2 + 28 / 2; kb_result_t r = kb_hit_test(x_row1, y_row1, KB_ALPHA_LOWER); ASSERT(r.action == KB_ACTION_CHAR, "Row 1 first key is a char"); ASSERT_EQ_INT('a', r.ch, "Row 1 first key = 'a'"); } { - int y_row2 = KB_START_Y + 2 * (KB_KEY_H + KB_KEY_GAP) + KB_KEY_H / 2; - int x_row2 = 23 + 42 / 2; + int margin_r2 = (320 - (9 * 28 + 8 * 2)) / 2 + 28; + int y_row2 = 70 + 2 * (36 + 2) + 36 / 2; + int x_row2 = margin_r2 + 28 / 2; kb_result_t r = kb_hit_test(x_row2, y_row2, KB_ALPHA_LOWER); ASSERT(r.action == KB_ACTION_SHIFT, "Row 2 first key = SHIFT"); } diff --git a/tests/unit/test_touch b/tests/unit/test_touch new file mode 100755 index 0000000..43c8790 Binary files /dev/null and b/tests/unit/test_touch differ diff --git a/tests/unit/test_wifi_setup b/tests/unit/test_wifi_setup new file mode 100755 index 0000000..aa0e0b4 Binary files /dev/null and b/tests/unit/test_wifi_setup differ -- cgit v1.2.3