diff options
| author | Your Name <you@example.com> | 2026-05-19 01:44:11 +0530 |
|---|---|---|
| committer | Your Name <you@example.com> | 2026-05-19 01:44:11 +0530 |
| commit | 58a0b5fd115d9687a1292e5e82e6b9fa8454b930 (patch) | |
| tree | dd9f18903d0237edcf5844c58fcb88bcf737b22c | |
| parent | 699fc6c03899c3b1ff853d8c7c6cf32173436354 (diff) | |
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)
| -rw-r--r-- | components/axs15231b/axs15231b.c | 32 | ||||
| -rw-r--r-- | components/axs15231b/include/axs15231b.h | 1 | ||||
| -rw-r--r-- | main/display.c | 164 | ||||
| -rw-r--r-- | main/keyboard.c | 72 | ||||
| -rw-r--r-- | main/keyboard.h | 26 | ||||
| -rw-r--r-- | main/touch.c | 25 | ||||
| -rw-r--r-- | main/touch.h | 1 | ||||
| -rwxr-xr-x | tests/unit/test_keyboard | bin | 0 -> 35416 bytes | |||
| -rw-r--r-- | tests/unit/test_keyboard.c | 22 | ||||
| -rwxr-xr-x | tests/unit/test_touch | bin | 0 -> 30304 bytes | |||
| -rwxr-xr-x | tests/unit/test_wifi_setup | bin | 0 -> 33336 bytes |
11 files changed, 261 insertions, 82 deletions
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; | |||
| 37 | static uint16_t *s_fb = NULL; | 37 | static uint16_t *s_fb = NULL; |
| 38 | static int s_width = AXS15231B_WIDTH; | 38 | static int s_width = AXS15231B_WIDTH; |
| 39 | static int s_height = AXS15231B_HEIGHT; | 39 | static int s_height = AXS15231B_HEIGHT; |
| 40 | static int s_rotation = 0; | ||
| 40 | static uint8_t *s_swap_buf = NULL; | 41 | static uint8_t *s_swap_buf = NULL; |
| 41 | #define SWAP_BUF_PIXELS 2048 | 42 | #define SWAP_BUF_PIXELS 2048 |
| 42 | 43 | ||
| @@ -354,3 +355,34 @@ void axs15231b_flush(void) { | |||
| 354 | 355 | ||
| 355 | int axs15231b_get_width(void) { return s_width; } | 356 | int axs15231b_get_width(void) { return s_width; } |
| 356 | int axs15231b_get_height(void) { return s_height; } | 357 | int axs15231b_get_height(void) { return s_height; } |
| 358 | |||
| 359 | void axs15231b_set_rotation(int rotation) { | ||
| 360 | uint8_t madctl = MADCTL_RGB; | ||
| 361 | switch (rotation) { | ||
| 362 | case 0: | ||
| 363 | madctl = MADCTL_RGB; | ||
| 364 | s_width = AXS15231B_WIDTH; | ||
| 365 | s_height = AXS15231B_HEIGHT; | ||
| 366 | break; | ||
| 367 | case 1: | ||
| 368 | madctl = MADCTL_MX | MADCTL_MV; | ||
| 369 | s_width = AXS15231B_HEIGHT; | ||
| 370 | s_height = AXS15231B_WIDTH; | ||
| 371 | break; | ||
| 372 | case 2: | ||
| 373 | madctl = MADCTL_MX | MADCTL_MY; | ||
| 374 | s_width = AXS15231B_WIDTH; | ||
| 375 | s_height = AXS15231B_HEIGHT; | ||
| 376 | break; | ||
| 377 | case 3: | ||
| 378 | madctl = MADCTL_MY | MADCTL_MV; | ||
| 379 | s_width = AXS15231B_HEIGHT; | ||
| 380 | s_height = AXS15231B_WIDTH; | ||
| 381 | break; | ||
| 382 | default: | ||
| 383 | return; | ||
| 384 | } | ||
| 385 | s_rotation = rotation; | ||
| 386 | qspi_write_cmd_data8(MADCTL, madctl); | ||
| 387 | ESP_LOGI(TAG, "Rotation set to %d (%dx%d)", rotation, s_width, s_height); | ||
| 388 | } | ||
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); | |||
| 23 | void axs15231b_flush(void); | 23 | void axs15231b_flush(void); |
| 24 | int axs15231b_get_width(void); | 24 | int axs15231b_get_width(void); |
| 25 | int axs15231b_get_height(void); | 25 | int axs15231b_get_height(void); |
| 26 | void axs15231b_set_rotation(int rotation); | ||
| 26 | 27 | ||
| 27 | #endif | 28 | #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; | |||
| 46 | #define COLOR_GRAY 0x8410 | 46 | #define COLOR_GRAY 0x8410 |
| 47 | #define COLOR_DARKGRAY 0x4208 | 47 | #define COLOR_DARKGRAY 0x4208 |
| 48 | #define COLOR_LIGHTBLUE 0xA5FF | 48 | #define COLOR_LIGHTBLUE 0xA5FF |
| 49 | #define COLOR_HIGHLIGHT 0x07E0 | ||
| 49 | 50 | ||
| 50 | static wifi_setup_t s_wifi_setup; | 51 | static wifi_setup_t s_wifi_setup; |
| 51 | static kb_state_t s_kb_state; | 52 | static kb_state_t s_kb_state; |
| 52 | static bool s_wifi_setup_active = false; | 53 | static bool s_wifi_setup_active = false; |
| 53 | static bool s_touch_initialized = false; | 54 | static bool s_touch_initialized = false; |
| 54 | static bool s_wifi_scan_pending = false; | 55 | static bool s_wifi_scan_pending = false; |
| 56 | static int s_display_rotation = 0; | ||
| 55 | 57 | ||
| 56 | #define SETUP_BTN_X 240 | 58 | #define SETUP_BTN_X 240 |
| 57 | #define SETUP_BTN_Y 440 | 59 | #define SETUP_BTN_Y 440 |
| 58 | #define SETUP_BTN_W 72 | 60 | #define SETUP_BTN_W 72 |
| 59 | #define SETUP_BTN_H 30 | 61 | #define SETUP_BTN_H 30 |
| 60 | 62 | ||
| 63 | static void enter_wifi_setup_rotation(void) { | ||
| 64 | if (s_display_rotation != 1) { | ||
| 65 | s_display_rotation = 1; | ||
| 66 | axs15231b_set_rotation(1); | ||
| 67 | touch_set_rotation(1); | ||
| 68 | kb_layout_t landscape = { | ||
| 69 | .key_w = 38, | ||
| 70 | .key_h = 40, | ||
| 71 | .key_gap = 2, | ||
| 72 | .start_y = 170, | ||
| 73 | .screen_w = 480, | ||
| 74 | .row_count = 4, | ||
| 75 | }; | ||
| 76 | kb_set_layout(&landscape); | ||
| 77 | } | ||
| 78 | } | ||
| 79 | |||
| 80 | static void exit_wifi_setup_rotation(void) { | ||
| 81 | if (s_display_rotation != 0) { | ||
| 82 | s_display_rotation = 0; | ||
| 83 | axs15231b_set_rotation(0); | ||
| 84 | touch_set_rotation(0); | ||
| 85 | kb_layout_t portrait = { | ||
| 86 | .key_w = 28, | ||
| 87 | .key_h = 36, | ||
| 88 | .key_gap = 2, | ||
| 89 | .start_y = 70, | ||
| 90 | .screen_w = 320, | ||
| 91 | .row_count = 4, | ||
| 92 | }; | ||
| 93 | kb_set_layout(&portrait); | ||
| 94 | } | ||
| 95 | } | ||
| 96 | |||
| 61 | static void render_setup_button(int x, int y, int w, int h) { | 97 | static void render_setup_button(int x, int y, int w, int h) { |
| 62 | axs15231b_fill_rect(x, y, w, h, COLOR_DARKGRAY); | 98 | axs15231b_fill_rect(x, y, w, h, COLOR_DARKGRAY); |
| 63 | const char *label = "Setup"; | 99 | 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) | |||
| 69 | return tx >= x && tx < x + w && ty >= y && ty < y + h; | 105 | return tx >= x && tx < x + w && ty >= y && ty < y + h; |
| 70 | } | 106 | } |
| 71 | 107 | ||
| 108 | static void highlight_rect(int x, int y, int w, int h) { | ||
| 109 | axs15231b_fill_rect(x, y, w, h, COLOR_HIGHLIGHT); | ||
| 110 | axs15231b_flush(); | ||
| 111 | vTaskDelay(pdMS_TO_TICKS(80)); | ||
| 112 | axs15231b_fill_rect(x, y, w, h, COLOR_DARKGRAY); | ||
| 113 | axs15231b_flush(); | ||
| 114 | } | ||
| 115 | |||
| 72 | static int qr_version_from_strlen(int len) { | 116 | static int qr_version_from_strlen(int len) { |
| 73 | if (len <= 17) return 1; | 117 | if (len <= 17) return 1; |
| 74 | if (len <= 32) return 2; | 118 | if (len <= 32) return 2; |
| @@ -357,6 +401,7 @@ static void render_wifi_setup_scanning(void) { | |||
| 357 | 401 | ||
| 358 | static void render_wifi_setup_list(void) { | 402 | static void render_wifi_setup_list(void) { |
| 359 | int screen_w = axs15231b_get_width(); | 403 | int screen_w = axs15231b_get_width(); |
| 404 | int screen_h = axs15231b_get_height(); | ||
| 360 | axs15231b_fill_screen(COLOR_BG); | 405 | axs15231b_fill_screen(COLOR_BG); |
| 361 | 406 | ||
| 362 | const char *title = "Select Network"; | 407 | const char *title = "Select Network"; |
| @@ -365,47 +410,51 @@ static void render_wifi_setup_list(void) { | |||
| 365 | 410 | ||
| 366 | int y = 25; | 411 | int y = 25; |
| 367 | int visible = wifi_setup_visible_count(&s_wifi_setup); | 412 | int visible = wifi_setup_visible_count(&s_wifi_setup); |
| 413 | int item_w = screen_w - 20; | ||
| 414 | int max_y = screen_h - 40; | ||
| 368 | 415 | ||
| 369 | for (int i = 0; i < visible && y < 295; i++) { | 416 | for (int i = 0; i < visible && y < max_y; i++) { |
| 370 | const wifi_ap_info_t *ap = wifi_setup_get_visible(&s_wifi_setup, i); | 417 | const wifi_ap_info_t *ap = wifi_setup_get_visible(&s_wifi_setup, i); |
| 371 | if (!ap) break; | 418 | if (!ap) break; |
| 372 | 419 | ||
| 373 | char line[40]; | ||
| 374 | int rssi_bars = 0; | 420 | int rssi_bars = 0; |
| 375 | if (ap->rssi >= -30) rssi_bars = 4; | 421 | if (ap->rssi >= -30) rssi_bars = 4; |
| 376 | else if (ap->rssi >= -50) rssi_bars = 3; | 422 | else if (ap->rssi >= -50) rssi_bars = 3; |
| 377 | else if (ap->rssi >= -70) rssi_bars = 2; | 423 | else if (ap->rssi >= -70) rssi_bars = 2; |
| 378 | else rssi_bars = 1; | 424 | else rssi_bars = 1; |
| 379 | 425 | ||
| 380 | snprintf(line, sizeof(line), "%s", ap->ssid); | 426 | axs15231b_fill_rect(10, y, item_w, 26, COLOR_DARKGRAY); |
| 381 | axs15231b_fill_rect(5, y, 260, 26, COLOR_DARKGRAY); | 427 | display_render_text(15, y + 4, ap->ssid, COLOR_WHITE, COLOR_DARKGRAY, 1); |
| 382 | display_render_text(10, y + 4, line, COLOR_WHITE, COLOR_DARKGRAY, 1); | ||
| 383 | 428 | ||
| 429 | int bar_x = 10 + item_w - 50; | ||
| 384 | for (int b = 0; b < rssi_bars; b++) { | 430 | for (int b = 0; b < rssi_bars; b++) { |
| 385 | axs15231b_fill_rect(270 + b * 8, y + 16 - (b + 1) * 4, 6, (b + 1) * 4, COLOR_GREEN); | 431 | axs15231b_fill_rect(bar_x + b * 10, y + 16 - (b + 1) * 4, 8, (b + 1) * 4, COLOR_GREEN); |
| 386 | } | 432 | } |
| 387 | 433 | ||
| 388 | if (ap->secured) { | 434 | if (ap->secured) { |
| 389 | const char *lock = "*"; | 435 | display_render_text(bar_x - 12, y + 4, "*", COLOR_YELLOW, COLOR_DARKGRAY, 1); |
| 390 | display_render_text(254, y + 4, lock, COLOR_YELLOW, COLOR_DARKGRAY, 1); | ||
| 391 | } | 436 | } |
| 392 | 437 | ||
| 393 | y += 30; | 438 | y += 30; |
| 394 | } | 439 | } |
| 395 | 440 | ||
| 396 | render_setup_button(5, 440, 50, 28); | 441 | int btn_y = screen_h - 30; |
| 397 | display_render_text(10, 444, "X", COLOR_WHITE, COLOR_DARKGRAY, 1); | 442 | axs15231b_fill_rect(10, btn_y, 50, 26, COLOR_DARKGRAY); |
| 443 | display_render_text(25, btn_y + 5, "X", COLOR_WHITE, COLOR_DARKGRAY, 1); | ||
| 398 | 444 | ||
| 399 | axs15231b_flush(); | 445 | axs15231b_flush(); |
| 400 | } | 446 | } |
| 401 | 447 | ||
| 402 | static void render_wifi_setup_password(void) { | 448 | static void render_wifi_setup_password(void) { |
| 449 | int screen_w = axs15231b_get_width(); | ||
| 450 | const kb_layout_t *kb = kb_get_layout(); | ||
| 403 | axs15231b_fill_screen(COLOR_BG); | 451 | axs15231b_fill_screen(COLOR_BG); |
| 404 | 452 | ||
| 405 | display_render_text(10, 5, s_wifi_setup.selected_ssid, COLOR_CYAN, COLOR_BG, 1); | 453 | display_render_text(10, 5, s_wifi_setup.selected_ssid, COLOR_CYAN, COLOR_BG, 1); |
| 406 | display_render_text(10, 25, "Password:", COLOR_DIM, COLOR_BG, 1); | 454 | display_render_text(10, 25, "Password:", COLOR_DIM, COLOR_BG, 1); |
| 407 | 455 | ||
| 408 | axs15231b_fill_rect(10, 40, 220, 20, COLOR_DARKGRAY); | 456 | int field_w = screen_w - 80; |
| 457 | axs15231b_fill_rect(10, 40, field_w, 20, COLOR_DARKGRAY); | ||
| 409 | 458 | ||
| 410 | char masked[KB_INPUT_MAX + 1]; | 459 | char masked[KB_INPUT_MAX + 1]; |
| 411 | if (s_kb_state.reveal) { | 460 | if (s_kb_state.reveal) { |
| @@ -413,30 +462,40 @@ static void render_wifi_setup_password(void) { | |||
| 413 | masked[sizeof(masked) - 1] = '\0'; | 462 | masked[sizeof(masked) - 1] = '\0'; |
| 414 | } else { | 463 | } else { |
| 415 | int len = s_kb_state.cursor; | 464 | int len = s_kb_state.cursor; |
| 416 | if (len > 27) len = 27; | 465 | int max_chars = (field_w - 8) / 8; |
| 466 | if (len > max_chars) len = max_chars; | ||
| 417 | for (int i = 0; i < len; i++) masked[i] = '*'; | 467 | for (int i = 0; i < len; i++) masked[i] = '*'; |
| 418 | masked[len] = '\0'; | 468 | masked[len] = '\0'; |
| 419 | } | 469 | } |
| 420 | display_render_text(14, 43, masked, COLOR_WHITE, COLOR_DARKGRAY, 1); | 470 | display_render_text(14, 43, masked, COLOR_WHITE, COLOR_DARKGRAY, 1); |
| 421 | 471 | ||
| 472 | int eye_x = 10 + field_w + 5; | ||
| 422 | const char *eye_label = s_kb_state.reveal ? "H" : "S"; | 473 | const char *eye_label = s_kb_state.reveal ? "H" : "S"; |
| 423 | axs15231b_fill_rect(235, 40, 24, 20, COLOR_GRAY); | 474 | axs15231b_fill_rect(eye_x, 40, 24, 20, COLOR_GRAY); |
| 424 | display_render_text(241, 43, eye_label, COLOR_WHITE, COLOR_GRAY, 1); | 475 | display_render_text(eye_x + 8, 43, eye_label, COLOR_WHITE, COLOR_GRAY, 1); |
| 425 | 476 | ||
| 426 | int kb_y = 70; | 477 | int kb_y = kb->start_y; |
| 427 | for (int row = 0; row < KB_ROW_COUNT; row++) { | 478 | for (int row = 0; row < kb->row_count; row++) { |
| 428 | const char *row_str; | 479 | const char *row_str; |
| 429 | int key_count = kb_get_row_keys(row, s_kb_state.layer, &row_str); | 480 | int key_count = kb_get_row_keys(row, s_kb_state.layer, &row_str); |
| 430 | int x_off = (row == 0) ? 5 : (row == 1) ? 14 : (row == 2) ? 23 : 5; | 481 | const char *tmp; |
| 482 | int total_keys = kb_get_row_keys(row, s_kb_state.layer, &tmp); | ||
| 483 | int x_off = (row == 0) ? (screen_w - total_keys * kb->key_w - (total_keys - 1) * kb->key_gap) / 2 | ||
| 484 | : (row == 1) ? (screen_w - total_keys * kb->key_w - (total_keys - 1) * kb->key_gap) / 2 + kb->key_w / 2 | ||
| 485 | : (row == 2) ? (screen_w - total_keys * kb->key_w - (total_keys - 1) * kb->key_gap) / 2 + kb->key_w | ||
| 486 | : (screen_w - total_keys * kb->key_w - (total_keys - 1) * kb->key_gap) / 2; | ||
| 431 | 487 | ||
| 432 | int cx = x_off; | 488 | int cx = x_off; |
| 433 | for (int col = 0; col < key_count; col++) { | 489 | for (int col = 0; col < key_count; col++) { |
| 434 | char c = row_str[col]; | 490 | char c = row_str[col]; |
| 435 | int kw = 28; | 491 | int kw = kb->key_w; |
| 436 | if (row == 3) { | 492 | if (row == 3) { |
| 437 | if (col == 0) kw = 42; | 493 | int margin = (screen_w - total_keys * kb->key_w - (total_keys - 1) * kb->key_gap) / 2; |
| 438 | else if (col == key_count - 1) kw = 50; | 494 | int available = screen_w - margin * 2; |
| 439 | else kw = 168; | 495 | int side_w = (available - kb->key_gap) / 4; |
| 496 | if (col == 0) kw = side_w; | ||
| 497 | else if (col == key_count - 1) kw = side_w; | ||
| 498 | else kw = available - side_w * 2 - kb->key_gap * 2; | ||
| 440 | } | 499 | } |
| 441 | 500 | ||
| 442 | uint16_t bg = COLOR_DARKGRAY; | 501 | uint16_t bg = COLOR_DARKGRAY; |
| @@ -461,12 +520,12 @@ static void render_wifi_setup_password(void) { | |||
| 461 | label[0] = c; | 520 | label[0] = c; |
| 462 | } | 521 | } |
| 463 | 522 | ||
| 464 | axs15231b_fill_rect(cx, kb_y, kw, 30, bg); | 523 | axs15231b_fill_rect(cx, kb_y, kw, kb->key_h, bg); |
| 465 | int lw = 8; | 524 | int lw = 8; |
| 466 | display_render_text(cx + (kw - lw) / 2, kb_y + 8, label, fg, bg, 1); | 525 | display_render_text(cx + (kw - lw) / 2, kb_y + (kb->key_h - 8) / 2, label, fg, bg, 1); |
| 467 | cx += kw + 2; | 526 | cx += kw + kb->key_gap; |
| 468 | } | 527 | } |
| 469 | kb_y += 34; | 528 | kb_y += kb->key_h + kb->key_gap; |
| 470 | } | 529 | } |
| 471 | 530 | ||
| 472 | axs15231b_flush(); | 531 | axs15231b_flush(); |
| @@ -492,53 +551,65 @@ static void render_wifi_setup_connecting(void) { | |||
| 492 | 551 | ||
| 493 | static void render_wifi_setup_result(void) { | 552 | static void render_wifi_setup_result(void) { |
| 494 | int screen_w = axs15231b_get_width(); | 553 | int screen_w = axs15231b_get_width(); |
| 554 | int screen_h = axs15231b_get_height(); | ||
| 495 | axs15231b_fill_screen(COLOR_BG); | 555 | axs15231b_fill_screen(COLOR_BG); |
| 496 | 556 | ||
| 497 | if (s_wifi_setup.state == SETUP_SUCCESS) { | 557 | if (s_wifi_setup.state == SETUP_SUCCESS) { |
| 498 | const char *msg = "Connected!"; | 558 | const char *msg = "Connected!"; |
| 499 | int mw = strlen(msg) * 8 * 2; | 559 | int mw = strlen(msg) * 8 * 2; |
| 500 | display_render_text((screen_w - mw) / 2, 180, msg, COLOR_WHITE, COLOR_GREEN, 2); | 560 | display_render_text((screen_w - mw) / 2, screen_h / 2 - 40, msg, COLOR_WHITE, COLOR_GREEN, 2); |
| 501 | 561 | ||
| 502 | if (s_wifi_setup.connect_ip[0]) { | 562 | if (s_wifi_setup.connect_ip[0]) { |
| 503 | char ip_line[32]; | 563 | char ip_line[32]; |
| 504 | snprintf(ip_line, sizeof(ip_line), "IP: %s", s_wifi_setup.connect_ip); | 564 | snprintf(ip_line, sizeof(ip_line), "IP: %s", s_wifi_setup.connect_ip); |
| 505 | int iw = strlen(ip_line) * 8; | 565 | int iw = strlen(ip_line) * 8; |
| 506 | display_render_text((screen_w - iw) / 2, 240, ip_line, COLOR_WHITE, COLOR_BG, 1); | 566 | display_render_text((screen_w - iw) / 2, screen_h / 2, ip_line, COLOR_WHITE, COLOR_BG, 1); |
| 507 | } | 567 | } |
| 508 | } else { | 568 | } else { |
| 509 | const char *msg = "Connection failed"; | 569 | const char *msg = "Connection failed"; |
| 510 | int mw = strlen(msg) * 8 * 2; | 570 | int mw = strlen(msg) * 8 * 2; |
| 511 | display_render_text((screen_w - mw) / 2, 180, msg, COLOR_WHITE, COLOR_RED, 2); | 571 | display_render_text((screen_w - mw) / 2, screen_h / 2 - 40, msg, COLOR_WHITE, COLOR_RED, 2); |
| 512 | 572 | ||
| 513 | const char *hint = "Wrong password?"; | 573 | const char *hint = "Wrong password?"; |
| 514 | int hw = strlen(hint) * 8; | 574 | int hw = strlen(hint) * 8; |
| 515 | display_render_text((screen_w - hw) / 2, 240, hint, COLOR_YELLOW, COLOR_BG, 1); | 575 | display_render_text((screen_w - hw) / 2, screen_h / 2, hint, COLOR_YELLOW, COLOR_BG, 1); |
| 516 | 576 | ||
| 517 | axs15231b_fill_rect(30, 280, 120, 30, COLOR_DARKGRAY); | 577 | int btn_y = screen_h / 2 + 30; |
| 518 | display_render_text(50, 288, "Retry", COLOR_WHITE, COLOR_DARKGRAY, 1); | 578 | int btn_w = (screen_w - 40) / 2; |
| 519 | axs15231b_fill_rect(170, 280, 120, 30, COLOR_DARKGRAY); | 579 | axs15231b_fill_rect(10, btn_y, btn_w, 30, COLOR_DARKGRAY); |
| 520 | display_render_text(180, 288, "Change", COLOR_WHITE, COLOR_DARKGRAY, 1); | 580 | display_render_text(10 + (btn_w - 40) / 2, btn_y + 8, "Retry", COLOR_WHITE, COLOR_DARKGRAY, 1); |
| 581 | axs15231b_fill_rect(20 + btn_w, btn_y, btn_w, 30, COLOR_DARKGRAY); | ||
| 582 | display_render_text(20 + btn_w + (btn_w - 50) / 2, btn_y + 8, "Change", COLOR_WHITE, COLOR_DARKGRAY, 1); | ||
| 521 | } | 583 | } |
| 522 | 584 | ||
| 523 | axs15231b_flush(); | 585 | axs15231b_flush(); |
| 524 | } | 586 | } |
| 525 | 587 | ||
| 526 | static void handle_wifi_setup_touch(uint16_t tx, uint16_t ty) { | 588 | static void handle_wifi_setup_touch(uint16_t tx, uint16_t ty) { |
| 589 | int screen_w = axs15231b_get_width(); | ||
| 590 | int screen_h = axs15231b_get_height(); | ||
| 591 | |||
| 527 | switch (s_wifi_setup.state) { | 592 | switch (s_wifi_setup.state) { |
| 528 | case SETUP_SCAN: | 593 | case SETUP_SCAN: |
| 529 | break; | 594 | break; |
| 530 | 595 | ||
| 531 | case SETUP_LIST: { | 596 | case SETUP_LIST: { |
| 532 | if (touch_in_rect(tx, ty, 5, 440, 50, 28)) { | 597 | int btn_y = screen_h - 30; |
| 598 | if (touch_in_rect(tx, ty, 10, btn_y, 50, 26)) { | ||
| 599 | highlight_rect(10, btn_y, 50, 26); | ||
| 533 | wifi_setup_handle_cancel(&s_wifi_setup); | 600 | wifi_setup_handle_cancel(&s_wifi_setup); |
| 534 | s_wifi_setup_active = false; | 601 | s_wifi_setup_active = false; |
| 602 | exit_wifi_setup_rotation(); | ||
| 535 | s_state = DISPLAY_ERROR; | 603 | s_state = DISPLAY_ERROR; |
| 536 | return; | 604 | return; |
| 537 | } | 605 | } |
| 606 | int item_w = screen_w - 20; | ||
| 538 | int y = 25; | 607 | int y = 25; |
| 608 | int max_y = screen_h - 40; | ||
| 539 | int visible = wifi_setup_visible_count(&s_wifi_setup); | 609 | int visible = wifi_setup_visible_count(&s_wifi_setup); |
| 540 | for (int i = 0; i < visible; i++) { | 610 | for (int i = 0; i < visible && y < max_y; i++) { |
| 541 | if (touch_in_rect(tx, ty, 5, y, 300, 26)) { | 611 | if (touch_in_rect(tx, ty, 10, y, item_w, 26)) { |
| 612 | highlight_rect(10, y, item_w, 26); | ||
| 542 | wifi_setup_handle_select(&s_wifi_setup, i); | 613 | wifi_setup_handle_select(&s_wifi_setup, i); |
| 543 | kb_state_init(&s_kb_state); | 614 | kb_state_init(&s_kb_state); |
| 544 | return; | 615 | return; |
| @@ -549,12 +620,17 @@ static void handle_wifi_setup_touch(uint16_t tx, uint16_t ty) { | |||
| 549 | } | 620 | } |
| 550 | 621 | ||
| 551 | case SETUP_PASSWORD: { | 622 | case SETUP_PASSWORD: { |
| 552 | if (touch_in_rect(tx, ty, 235, 40, 24, 20)) { | 623 | int field_w = screen_w - 80; |
| 624 | int eye_x = 10 + field_w + 5; | ||
| 625 | if (touch_in_rect(tx, ty, eye_x, 40, 24, 20)) { | ||
| 553 | s_kb_state.reveal = !s_kb_state.reveal; | 626 | s_kb_state.reveal = !s_kb_state.reveal; |
| 554 | return; | 627 | return; |
| 555 | } | 628 | } |
| 556 | kb_result_t r = kb_hit_test(tx, ty, s_kb_state.layer); | 629 | kb_result_t r = kb_hit_test(tx, ty, s_kb_state.layer); |
| 557 | if (r.action != KB_ACTION_NONE) { | 630 | if (r.action != KB_ACTION_NONE) { |
| 631 | axs15231b_fill_rect(tx - 20, ty - 20, 40, 40, COLOR_HIGHLIGHT); | ||
| 632 | axs15231b_flush(); | ||
| 633 | vTaskDelay(pdMS_TO_TICKS(60)); | ||
| 558 | if (r.action == KB_ACTION_DONE && s_kb_state.cursor > 0) { | 634 | if (r.action == KB_ACTION_DONE && s_kb_state.cursor > 0) { |
| 559 | wifi_setup_handle_connect(&s_wifi_setup); | 635 | wifi_setup_handle_connect(&s_wifi_setup); |
| 560 | wifi_config_t wifi_cfg = {0}; | 636 | wifi_config_t wifi_cfg = {0}; |
| @@ -578,15 +654,20 @@ static void handle_wifi_setup_touch(uint16_t tx, uint16_t ty) { | |||
| 578 | case SETUP_SUCCESS: { | 654 | case SETUP_SUCCESS: { |
| 579 | wifi_setup_handle_cancel(&s_wifi_setup); | 655 | wifi_setup_handle_cancel(&s_wifi_setup); |
| 580 | s_wifi_setup_active = false; | 656 | s_wifi_setup_active = false; |
| 657 | exit_wifi_setup_rotation(); | ||
| 581 | s_state = DISPLAY_READY; | 658 | s_state = DISPLAY_READY; |
| 582 | return; | 659 | return; |
| 583 | } | 660 | } |
| 584 | 661 | ||
| 585 | case SETUP_FAILED: { | 662 | case SETUP_FAILED: { |
| 586 | if (touch_in_rect(tx, ty, 30, 280, 120, 30)) { | 663 | int btn_y = screen_h / 2 + 30; |
| 664 | int btn_w = (screen_w - 40) / 2; | ||
| 665 | if (touch_in_rect(tx, ty, 10, btn_y, btn_w, 30)) { | ||
| 666 | highlight_rect(10, btn_y, btn_w, 30); | ||
| 587 | wifi_setup_handle_retry(&s_wifi_setup); | 667 | wifi_setup_handle_retry(&s_wifi_setup); |
| 588 | kb_state_init(&s_kb_state); | 668 | kb_state_init(&s_kb_state); |
| 589 | } else if (touch_in_rect(tx, ty, 170, 280, 120, 30)) { | 669 | } else if (touch_in_rect(tx, ty, 20 + btn_w, btn_y, btn_w, 30)) { |
| 670 | highlight_rect(20 + btn_w, btn_y, btn_w, 30); | ||
| 590 | wifi_setup_handle_change_network(&s_wifi_setup); | 671 | wifi_setup_handle_change_network(&s_wifi_setup); |
| 591 | } | 672 | } |
| 592 | break; | 673 | break; |
| @@ -618,6 +699,7 @@ static void display_task(void *pvParameters) { | |||
| 618 | state = s_state; | 699 | state = s_state; |
| 619 | } else if (state == DISPLAY_ERROR || state == DISPLAY_READY) { | 700 | } else if (state == DISPLAY_ERROR || state == DISPLAY_READY) { |
| 620 | if (touch_in_rect(tp.x, tp.y, SETUP_BTN_X, SETUP_BTN_Y, SETUP_BTN_W, SETUP_BTN_H)) { | 701 | if (touch_in_rect(tp.x, tp.y, SETUP_BTN_X, SETUP_BTN_Y, SETUP_BTN_W, SETUP_BTN_H)) { |
| 702 | enter_wifi_setup_rotation(); | ||
| 621 | s_wifi_setup_active = true; | 703 | s_wifi_setup_active = true; |
| 622 | wifi_setup_init(&s_wifi_setup); | 704 | wifi_setup_init(&s_wifi_setup); |
| 623 | kb_state_init(&s_kb_state); | 705 | kb_state_init(&s_kb_state); |
| @@ -710,6 +792,7 @@ static void display_task(void *pvParameters) { | |||
| 710 | vTaskDelay(pdMS_TO_TICKS(3000)); | 792 | vTaskDelay(pdMS_TO_TICKS(3000)); |
| 711 | wifi_setup_handle_cancel(&s_wifi_setup); | 793 | wifi_setup_handle_cancel(&s_wifi_setup); |
| 712 | s_wifi_setup_active = false; | 794 | s_wifi_setup_active = false; |
| 795 | exit_wifi_setup_rotation(); | ||
| 713 | s_state = DISPLAY_READY; | 796 | s_state = DISPLAY_READY; |
| 714 | break; | 797 | break; |
| 715 | case SETUP_FAILED: | 798 | case SETUP_FAILED: |
| @@ -804,6 +887,7 @@ void display_notify_wifi_disconnected(void) { | |||
| 804 | 887 | ||
| 805 | void display_enter_wifi_setup(void) { | 888 | void display_enter_wifi_setup(void) { |
| 806 | if (!s_initialized) return; | 889 | if (!s_initialized) return; |
| 890 | enter_wifi_setup_rotation(); | ||
| 807 | s_wifi_setup_active = true; | 891 | s_wifi_setup_active = true; |
| 808 | wifi_setup_init(&s_wifi_setup); | 892 | wifi_setup_init(&s_wifi_setup); |
| 809 | kb_state_init(&s_kb_state); | 893 | 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[] = { | |||
| 28 | #define CTRL_DONE '\004' | 28 | #define CTRL_DONE '\004' |
| 29 | #define CTRL_BS '\b' | 29 | #define CTRL_BS '\b' |
| 30 | 30 | ||
| 31 | static kb_layout_t s_layout = { | ||
| 32 | .key_w = 28, | ||
| 33 | .key_h = 36, | ||
| 34 | .key_gap = 2, | ||
| 35 | .start_y = 70, | ||
| 36 | .screen_w = 320, | ||
| 37 | .row_count = 4, | ||
| 38 | }; | ||
| 39 | |||
| 31 | void kb_state_init(kb_state_t *st) { | 40 | void kb_state_init(kb_state_t *st) { |
| 32 | if (!st) return; | 41 | if (!st) return; |
| 33 | memset(st, 0, sizeof(*st)); | 42 | memset(st, 0, sizeof(*st)); |
| @@ -35,6 +44,14 @@ void kb_state_init(kb_state_t *st) { | |||
| 35 | st->reveal = false; | 44 | st->reveal = false; |
| 36 | } | 45 | } |
| 37 | 46 | ||
| 47 | void kb_set_layout(const kb_layout_t *layout) { | ||
| 48 | if (layout) s_layout = *layout; | ||
| 49 | } | ||
| 50 | |||
| 51 | const kb_layout_t *kb_get_layout(void) { | ||
| 52 | return &s_layout; | ||
| 53 | } | ||
| 54 | |||
| 38 | static const char **get_layer(kb_layer_t layer) { | 55 | static const char **get_layer(kb_layer_t layer) { |
| 39 | switch (layer) { | 56 | switch (layer) { |
| 40 | case KB_ALPHA_UPPER: return s_alpha_upper; | 57 | case KB_ALPHA_UPPER: return s_alpha_upper; |
| @@ -43,12 +60,8 @@ static const char **get_layer(kb_layer_t layer) { | |||
| 43 | } | 60 | } |
| 44 | } | 61 | } |
| 45 | 62 | ||
| 46 | static int key_is_ctrl(char c) { | ||
| 47 | return c == CTRL_SHIFT || c == CTRL_LAYER || c == CTRL_SPACE || c == CTRL_DONE || c == CTRL_BS; | ||
| 48 | } | ||
| 49 | |||
| 50 | int kb_get_row_keys(int row, kb_layer_t layer, const char **keys_out) { | 63 | int kb_get_row_keys(int row, kb_layer_t layer, const char **keys_out) { |
| 51 | if (row < 0 || row >= KB_ROW_COUNT) { | 64 | if (row < 0 || row >= s_layout.row_count) { |
| 52 | *keys_out = NULL; | 65 | *keys_out = NULL; |
| 53 | return 0; | 66 | return 0; |
| 54 | } | 67 | } |
| @@ -58,46 +71,59 @@ int kb_get_row_keys(int row, kb_layer_t layer, const char **keys_out) { | |||
| 58 | return (int)strlen(row_str); | 71 | return (int)strlen(row_str); |
| 59 | } | 72 | } |
| 60 | 73 | ||
| 61 | static int row_x_offset(int row) { | 74 | static int row_x_offset(int row, int total_keys) { |
| 75 | int kw = s_layout.key_w; | ||
| 76 | int gap = s_layout.key_gap; | ||
| 77 | int total_w = total_keys * kw + (total_keys - 1) * gap; | ||
| 78 | int margin = (s_layout.screen_w - total_w) / 2; | ||
| 79 | if (margin < 2) margin = 2; | ||
| 62 | switch (row) { | 80 | switch (row) { |
| 63 | case 0: return 5; | 81 | case 0: return margin; |
| 64 | case 1: return 14; | 82 | case 1: return margin + kw / 2; |
| 65 | case 2: return 23; | 83 | case 2: return margin + kw; |
| 66 | case 3: return 5; | 84 | case 3: return margin; |
| 67 | default: return 0; | 85 | default: return margin; |
| 68 | } | 86 | } |
| 69 | } | 87 | } |
| 70 | 88 | ||
| 71 | static int key_width_at(int row, int col, int total_keys) { | 89 | static int key_width_at(int row, int col, int total_keys) { |
| 72 | (void)col; | 90 | int kw = s_layout.key_w; |
| 73 | if (row == 3) { | 91 | if (row == 3) { |
| 74 | if (col == 0) return 42; | 92 | int gap = s_layout.key_gap; |
| 75 | if (col == total_keys - 1) return 50; | 93 | int margin = row_x_offset(3, total_keys); |
| 76 | return 168; | 94 | int available = s_layout.screen_w - margin * 2; |
| 95 | int side_w = (available - gap) / 4; | ||
| 96 | if (col == 0) return side_w; | ||
| 97 | if (col == total_keys - 1) return side_w; | ||
| 98 | return available - side_w * 2 - gap * 2; | ||
| 77 | } | 99 | } |
| 78 | return KB_KEY_W; | 100 | return kw; |
| 79 | } | 101 | } |
| 80 | 102 | ||
| 81 | kb_result_t kb_hit_test(int tx, int ty, kb_layer_t layer) { | 103 | kb_result_t kb_hit_test(int tx, int ty, kb_layer_t layer) { |
| 82 | kb_result_t result = {KB_ACTION_NONE, 0}; | 104 | kb_result_t result = {KB_ACTION_NONE, 0}; |
| 105 | int sy = s_layout.start_y; | ||
| 106 | int kw = s_layout.key_w; | ||
| 107 | int kh = s_layout.key_h; | ||
| 108 | int gap = s_layout.key_gap; | ||
| 83 | 109 | ||
| 84 | if (ty < KB_START_Y || ty >= KB_START_Y + KB_ROW_COUNT * (KB_KEY_H + KB_KEY_GAP)) { | 110 | if (ty < sy || ty >= sy + s_layout.row_count * (kh + gap)) { |
| 85 | return result; | 111 | return result; |
| 86 | } | 112 | } |
| 87 | 113 | ||
| 88 | int row = (ty - KB_START_Y) / (KB_KEY_H + KB_KEY_GAP); | 114 | int row = (ty - sy) / (kh + gap); |
| 89 | if (row < 0 || row >= KB_ROW_COUNT) return result; | 115 | if (row < 0 || row >= s_layout.row_count) return result; |
| 90 | 116 | ||
| 91 | const char *row_str; | 117 | const char *row_str; |
| 92 | int total_keys = kb_get_row_keys(row, layer, &row_str); | 118 | int total_keys = kb_get_row_keys(row, layer, &row_str); |
| 93 | if (total_keys == 0) return result; | 119 | if (total_keys == 0) return result; |
| 94 | 120 | ||
| 95 | int x_off = row_x_offset(row); | 121 | int x_off = row_x_offset(row, total_keys); |
| 96 | int cx = x_off; | 122 | int cx = x_off; |
| 97 | 123 | ||
| 98 | for (int col = 0; col < total_keys; col++) { | 124 | for (int col = 0; col < total_keys; col++) { |
| 99 | int kw = key_width_at(row, col, total_keys); | 125 | int key_w = key_width_at(row, col, total_keys); |
| 100 | if (tx >= cx && tx < cx + kw) { | 126 | if (tx >= cx && tx < cx + key_w) { |
| 101 | char c = row_str[col]; | 127 | char c = row_str[col]; |
| 102 | if (c == CTRL_SHIFT) { | 128 | if (c == CTRL_SHIFT) { |
| 103 | result.action = KB_ACTION_SHIFT; | 129 | result.action = KB_ACTION_SHIFT; |
| @@ -116,7 +142,7 @@ kb_result_t kb_hit_test(int tx, int ty, kb_layer_t layer) { | |||
| 116 | } | 142 | } |
| 117 | return result; | 143 | return result; |
| 118 | } | 144 | } |
| 119 | cx += kw + KB_KEY_GAP; | 145 | cx += key_w + gap; |
| 120 | } | 146 | } |
| 121 | 147 | ||
| 122 | return result; | 148 | 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 @@ | |||
| 5 | #include <stdbool.h> | 5 | #include <stdbool.h> |
| 6 | 6 | ||
| 7 | #define KB_INPUT_MAX 64 | 7 | #define KB_INPUT_MAX 64 |
| 8 | #define KB_KEY_W 28 | ||
| 9 | #define KB_KEY_H 36 | ||
| 10 | #define KB_KEY_GAP 2 | ||
| 11 | #define KB_ROW_COUNT 4 | ||
| 12 | #define KB_START_Y 70 | ||
| 13 | 8 | ||
| 14 | typedef enum { | 9 | typedef enum { |
| 15 | KB_ALPHA_LOWER, | 10 | KB_ALPHA_LOWER, |
| @@ -28,18 +23,29 @@ typedef enum { | |||
| 28 | } kb_action_t; | 23 | } kb_action_t; |
| 29 | 24 | ||
| 30 | typedef struct { | 25 | typedef struct { |
| 31 | kb_action_t action; | ||
| 32 | char ch; | ||
| 33 | } kb_result_t; | ||
| 34 | |||
| 35 | typedef struct { | ||
| 36 | char input[KB_INPUT_MAX + 1]; | 26 | char input[KB_INPUT_MAX + 1]; |
| 37 | int cursor; | 27 | int cursor; |
| 38 | bool reveal; | 28 | bool reveal; |
| 39 | kb_layer_t layer; | 29 | kb_layer_t layer; |
| 40 | } kb_state_t; | 30 | } kb_state_t; |
| 41 | 31 | ||
| 32 | typedef struct { | ||
| 33 | kb_action_t action; | ||
| 34 | char ch; | ||
| 35 | } kb_result_t; | ||
| 36 | |||
| 37 | typedef struct { | ||
| 38 | int key_w; | ||
| 39 | int key_h; | ||
| 40 | int key_gap; | ||
| 41 | int start_y; | ||
| 42 | int screen_w; | ||
| 43 | int row_count; | ||
| 44 | } kb_layout_t; | ||
| 45 | |||
| 42 | void kb_state_init(kb_state_t *st); | 46 | void kb_state_init(kb_state_t *st); |
| 47 | void kb_set_layout(const kb_layout_t *layout); | ||
| 48 | const kb_layout_t *kb_get_layout(void); | ||
| 43 | int kb_get_row_keys(int row, kb_layer_t layer, const char **keys_out); | 49 | int kb_get_row_keys(int row, kb_layer_t layer, const char **keys_out); |
| 44 | kb_result_t kb_hit_test(int tx, int ty, kb_layer_t layer); | 50 | kb_result_t kb_hit_test(int tx, int ty, kb_layer_t layer); |
| 45 | void kb_apply(kb_state_t *st, kb_result_t result); | 51 | 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"; | |||
| 11 | static i2c_master_bus_handle_t s_bus = NULL; | 11 | static i2c_master_bus_handle_t s_bus = NULL; |
| 12 | static i2c_master_dev_handle_t s_dev = NULL; | 12 | static i2c_master_dev_handle_t s_dev = NULL; |
| 13 | static bool s_initialized = false; | 13 | static bool s_initialized = false; |
| 14 | static int s_rotation = 0; | ||
| 14 | 15 | ||
| 15 | static const uint8_t s_read_cmd[11] = { | 16 | static const uint8_t s_read_cmd[11] = { |
| 16 | 0xb5, 0xab, 0xa5, 0x5a, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00 | 17 | 0xb5, 0xab, 0xa5, 0x5a, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00 |
| @@ -115,9 +116,33 @@ bool touch_read(touch_point_t *pt) { | |||
| 115 | } | 116 | } |
| 116 | 117 | ||
| 117 | touch_parse_raw(data, pt); | 118 | touch_parse_raw(data, pt); |
| 119 | |||
| 120 | if (pt->touched && s_rotation != 0) { | ||
| 121 | uint16_t raw_x = pt->x; | ||
| 122 | uint16_t raw_y = pt->y; | ||
| 123 | switch (s_rotation) { | ||
| 124 | case 1: | ||
| 125 | pt->x = raw_y; | ||
| 126 | pt->y = TOUCH_MAX_X - raw_x; | ||
| 127 | break; | ||
| 128 | case 2: | ||
| 129 | pt->x = TOUCH_MAX_X - raw_x; | ||
| 130 | pt->y = TOUCH_MAX_Y - raw_y; | ||
| 131 | break; | ||
| 132 | case 3: | ||
| 133 | pt->x = TOUCH_MAX_Y - raw_y; | ||
| 134 | pt->y = raw_x; | ||
| 135 | break; | ||
| 136 | } | ||
| 137 | } | ||
| 138 | |||
| 118 | return pt->touched; | 139 | return pt->touched; |
| 119 | } | 140 | } |
| 120 | 141 | ||
| 142 | void touch_set_rotation(int rotation) { | ||
| 143 | s_rotation = rotation; | ||
| 144 | } | ||
| 145 | |||
| 121 | void touch_deinit(void) { | 146 | void touch_deinit(void) { |
| 122 | if (s_dev) { | 147 | if (s_dev) { |
| 123 | i2c_master_bus_rm_device(s_dev); | 148 | 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 { | |||
| 22 | esp_err_t touch_init(void); | 22 | esp_err_t touch_init(void); |
| 23 | bool touch_read(touch_point_t *pt); | 23 | bool touch_read(touch_point_t *pt); |
| 24 | void touch_deinit(void); | 24 | void touch_deinit(void); |
| 25 | void touch_set_rotation(int rotation); | ||
| 25 | 26 | ||
| 26 | void touch_parse_raw(const uint8_t *data, touch_point_t *pt); | 27 | void touch_parse_raw(const uint8_t *data, touch_point_t *pt); |
| 27 | 28 | ||
diff --git a/tests/unit/test_keyboard b/tests/unit/test_keyboard new file mode 100755 index 0000000..61cc9f5 --- /dev/null +++ b/tests/unit/test_keyboard | |||
| Binary files 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) | |||
| 41 | kb_result_t r = kb_hit_test(160, 10, KB_ALPHA_LOWER); | 41 | kb_result_t r = kb_hit_test(160, 10, KB_ALPHA_LOWER); |
| 42 | ASSERT(r.action == KB_ACTION_NONE, "Touch above keyboard = NONE"); | 42 | ASSERT(r.action == KB_ACTION_NONE, "Touch above keyboard = NONE"); |
| 43 | 43 | ||
| 44 | r = kb_hit_test(160, KB_START_Y + KB_ROW_COUNT * (KB_KEY_H + KB_KEY_GAP) + 10, KB_ALPHA_LOWER); | 44 | r = kb_hit_test(160, 70 + 4 * (36 + 2) + 10, KB_ALPHA_LOWER); |
| 45 | ASSERT(r.action == KB_ACTION_NONE, "Touch below keyboard = NONE"); | 45 | ASSERT(r.action == KB_ACTION_NONE, "Touch below keyboard = NONE"); |
| 46 | } | 46 | } |
| 47 | 47 | ||
| 48 | { | 48 | { |
| 49 | int mid_x = 5 + KB_KEY_W / 2; | 49 | int margin_r0 = (320 - (10 * 28 + 9 * 2)) / 2; |
| 50 | int mid_y = KB_START_Y + KB_KEY_H / 2; | 50 | int mid_x = margin_r0 + 28 / 2; |
| 51 | int mid_y = 70 + 36 / 2; | ||
| 51 | kb_result_t r = kb_hit_test(mid_x, mid_y, KB_ALPHA_LOWER); | 52 | kb_result_t r = kb_hit_test(mid_x, mid_y, KB_ALPHA_LOWER); |
| 52 | ASSERT(r.action == KB_ACTION_CHAR, "Row 0 first key is a char"); | 53 | ASSERT(r.action == KB_ACTION_CHAR, "Row 0 first key is a char"); |
| 53 | ASSERT_EQ_INT('q', r.ch, "Row 0 first key = 'q'"); | 54 | ASSERT_EQ_INT('q', r.ch, "Row 0 first key = 'q'"); |
| 54 | } | 55 | } |
| 55 | 56 | ||
| 56 | { | 57 | { |
| 57 | int x = 5 + KB_KEY_W + KB_KEY_GAP + KB_KEY_W / 2; | 58 | int margin_r0 = (320 - (10 * 28 + 9 * 2)) / 2; |
| 58 | int y = KB_START_Y + KB_KEY_H / 2; | 59 | int x = margin_r0 + 28 + 2 + 28 / 2; |
| 60 | int y = 70 + 36 / 2; | ||
| 59 | kb_result_t r = kb_hit_test(x, y, KB_ALPHA_LOWER); | 61 | kb_result_t r = kb_hit_test(x, y, KB_ALPHA_LOWER); |
| 60 | ASSERT(r.action == KB_ACTION_CHAR, "Row 0 second key is a char"); | 62 | ASSERT(r.action == KB_ACTION_CHAR, "Row 0 second key is a char"); |
| 61 | ASSERT_EQ_INT('w', r.ch, "Row 0 second key = 'w'"); | 63 | ASSERT_EQ_INT('w', r.ch, "Row 0 second key = 'w'"); |
| 62 | } | 64 | } |
| 63 | 65 | ||
| 64 | { | 66 | { |
| 65 | int y_row1 = KB_START_Y + (KB_KEY_H + KB_KEY_GAP) + KB_KEY_H / 2; | 67 | int margin_r1 = (320 - (9 * 28 + 8 * 2)) / 2; |
| 66 | int x_row1 = 14 + KB_KEY_W / 2; | 68 | int y_row1 = 70 + (36 + 2) + 36 / 2; |
| 69 | int x_row1 = margin_r1 + 28 / 2 + 28 / 2; | ||
| 67 | kb_result_t r = kb_hit_test(x_row1, y_row1, KB_ALPHA_LOWER); | 70 | kb_result_t r = kb_hit_test(x_row1, y_row1, KB_ALPHA_LOWER); |
| 68 | ASSERT(r.action == KB_ACTION_CHAR, "Row 1 first key is a char"); | 71 | ASSERT(r.action == KB_ACTION_CHAR, "Row 1 first key is a char"); |
| 69 | ASSERT_EQ_INT('a', r.ch, "Row 1 first key = 'a'"); | 72 | ASSERT_EQ_INT('a', r.ch, "Row 1 first key = 'a'"); |
| 70 | } | 73 | } |
| 71 | 74 | ||
| 72 | { | 75 | { |
| 73 | int y_row2 = KB_START_Y + 2 * (KB_KEY_H + KB_KEY_GAP) + KB_KEY_H / 2; | 76 | int margin_r2 = (320 - (9 * 28 + 8 * 2)) / 2 + 28; |
| 74 | int x_row2 = 23 + 42 / 2; | 77 | int y_row2 = 70 + 2 * (36 + 2) + 36 / 2; |
| 78 | int x_row2 = margin_r2 + 28 / 2; | ||
| 75 | kb_result_t r = kb_hit_test(x_row2, y_row2, KB_ALPHA_LOWER); | 79 | kb_result_t r = kb_hit_test(x_row2, y_row2, KB_ALPHA_LOWER); |
| 76 | ASSERT(r.action == KB_ACTION_SHIFT, "Row 2 first key = SHIFT"); | 80 | ASSERT(r.action == KB_ACTION_SHIFT, "Row 2 first key = SHIFT"); |
| 77 | } | 81 | } |
diff --git a/tests/unit/test_touch b/tests/unit/test_touch new file mode 100755 index 0000000..43c8790 --- /dev/null +++ b/tests/unit/test_touch | |||
| Binary files differ | |||
diff --git a/tests/unit/test_wifi_setup b/tests/unit/test_wifi_setup new file mode 100755 index 0000000..aa0e0b4 --- /dev/null +++ b/tests/unit/test_wifi_setup | |||
| Binary files differ | |||