From: Advaith Menon Date: Sat, 22 Nov 2025 22:36:15 +0000 (-0500) Subject: Add button support X-Git-Url: https://git.devinivas.org/?a=commitdiff_plain;h=7fa91b67b302f61ab167b60a8511003ec05761d0;p=smartwatch.git Add button support * Add button debouncing library * Print out single click and double click via ESP-IDF --- diff --git a/.gitignore b/.gitignore index ee59353..a43c206 100644 --- a/.gitignore +++ b/.gitignore @@ -16,3 +16,5 @@ pytest_embedded_log/ # idf-component-manager output dependencies.lock + +managed_components/ diff --git a/main/CMakeLists.txt b/main/CMakeLists.txt index e300e74..80ac656 100644 --- a/main/CMakeLists.txt +++ b/main/CMakeLists.txt @@ -1,7 +1,7 @@ idf_component_register(SRCS "hello_world_main.c" "goldeloxSerial.c" "task_lcd.c" + "task_button.c" INCLUDE_DIRS "." PRIV_REQUIRES esp_driver_gpio - esp_driver_uart - INCLUDE_DIRS "") + esp_driver_uart) diff --git a/main/goldeloxSerial.c b/main/goldeloxSerial.c index d4d7287..79f8f7c 100644 --- a/main/goldeloxSerial.c +++ b/main/goldeloxSerial.c @@ -1302,3 +1302,26 @@ gl_err_t gl_init(gl_display_t *disp, gl_serif_t *serif) { // return; // } +void gl_reset2(gl_display_t *disp) { + int k, tSave; + unsigned char ch; + //gl_word_t nBaud; + + TimeLimit4D = 2000; + + tSave = TimeLimit4D; + TimeLimit4D = 500; + for (k = 0 ; k < 10 ; k++) + { + ch = 'X'; + disp->serif->write_tx((void *)&ch, 1); + disp->serif->flush_tx(TimeLimit4D); + if (ReadSerPort(disp->serif, &ch, 1) == -1) + break; + if (ch == 0x15) + break ; + } + TimeLimit4D = tSave; + + disp->serif->flush_rx(); +} diff --git a/main/goldeloxSerial.h b/main/goldeloxSerial.h index eb073af..7407696 100644 --- a/main/goldeloxSerial.h +++ b/main/goldeloxSerial.h @@ -232,6 +232,7 @@ gl_word_t gl_joystick(gl_display_t *display) ; gl_word_t gl_peekB(gl_display_t *display, gl_word_t Address) ; gl_word_t gl_peekW(gl_display_t *display, gl_word_t Address) ; +void gl_reset2(gl_display_t *); diff --git a/main/hello_world_main.c b/main/hello_world_main.c index a823780..eb152a4 100644 --- a/main/hello_world_main.c +++ b/main/hello_world_main.c @@ -13,6 +13,7 @@ #include "pins.h" #include "task_lcd.h" +#include "task_button.h" @@ -47,6 +48,10 @@ void app_main(void) gpio_dump_io_configuration(stdout, (1ULL << PIN_VIBRATOR) | (1ULL << PIN_BUTTON_RED)); + /* initialize the buttons */ + gt_btn_setup(); + + /* start the main gui thread which starts all else */ lcd_task(); /* diff --git a/main/idf_component.yml b/main/idf_component.yml new file mode 100644 index 0000000..45aceb1 --- /dev/null +++ b/main/idf_component.yml @@ -0,0 +1,17 @@ +## IDF Component Manager Manifest File +dependencies: + ## Required IDF version + idf: + version: '>=4.1.0' + # # Put list of dependencies here + # # For components maintained by Espressif: + # component: "~1.0.0" + # # For 3rd party components: + # username/component: ">=1.0.0,<2.0.0" + # username2/component2: + # version: "~1.0.0" + # # For transient dependencies `public` flag can be set. + # # `public` flag doesn't have an effect dependencies of the `main` component. + # # All dependencies of `main` are public by default. + # public: true + espressif/button: '*' diff --git a/main/task_button.c b/main/task_button.c new file mode 100644 index 0000000..4d46c23 --- /dev/null +++ b/main/task_button.c @@ -0,0 +1,90 @@ +#include "freertos/FreeRTOS.h" +#include "iot_button.h" +#include "button_gpio.h" +#include "esp_log.h" + +#include "pins.h" + +#include "task_button.h" + +/* globals */ + +extern QueueHandle_t gt_btnq; + + +static struct gt_btn_msg_t btn_evts[10] = { + {GT_BTN_WHITE, BUTTON_SINGLE_CLICK}, + {GT_BTN_WHITE, BUTTON_DOUBLE_CLICK}, + {GT_BTN_GREEN, BUTTON_SINGLE_CLICK}, + {GT_BTN_GREEN, BUTTON_DOUBLE_CLICK}, + {GT_BTN_YELLOW, BUTTON_SINGLE_CLICK}, + {GT_BTN_YELLOW, BUTTON_DOUBLE_CLICK}, + {GT_BTN_BLUE, BUTTON_SINGLE_CLICK}, + {GT_BTN_BLUE, BUTTON_DOUBLE_CLICK}, + {GT_BTN_RED, BUTTON_SINGLE_CLICK}, + {GT_BTN_RED, BUTTON_DOUBLE_CLICK}, +}; + + +static const char* TAG = "task_button"; + + +/* local fn definitions */ + + +static void button_all_cb(void *, void *); + + +/* ========================================================================== */ +void gt_btn_setup(void) { + uint8_t i; + + const button_config_t btn_cfg_all = {0}; + + const button_gpio_config_t btn_gpio_cfg[5] = { + { + .gpio_num = PIN_BUTTON_WHITE, + .active_level = 0 + }, + { + .gpio_num = PIN_BUTTON_GREEN, + .active_level = 0 + }, + { + .gpio_num = PIN_BUTTON_YELLOW, + .active_level = 0 + }, + { + .gpio_num = PIN_BUTTON_BLUE, + .active_level = 0 + }, + { + .gpio_num = PIN_BUTTON_RED, + .active_level = 0 + } + }; + button_handle_t gpio_btn[5] = {NULL, NULL, NULL, NULL, NULL}; + + /* create buttons */ + for (i = 0; i < NUM_BUTTONS; ++i) { + ESP_ERROR_CHECK(iot_button_new_gpio_device( + &btn_cfg_all, &btn_gpio_cfg[i], &gpio_btn[i])); + } + + + /* register callbacks */ + for (i = 0; i < NUM_EVENTS; ++i) { + ESP_ERROR_CHECK(iot_button_register_cb(gpio_btn[btn_evts[i].btn], + btn_evts[i].evt, + NULL, + &button_all_cb, + &btn_evts[i])); + } +} + + +void button_all_cb(void *arg, void *user_data) { + struct gt_btn_msg_t *msg = (struct gt_btn_msg_t*) user_data; + ESP_LOGI(TAG, "Button pressed"); + ESP_LOGI(TAG, "The selected event: %d; and event %d", msg->btn, msg->evt); +} diff --git a/main/task_button.h b/main/task_button.h new file mode 100644 index 0000000..afb98ec --- /dev/null +++ b/main/task_button.h @@ -0,0 +1,37 @@ +/** + * @file task_button.h + * @brief Creates a queue to deal with button inputs. + */ + +#pragma once + +#ifndef __TASK_BUTTON_H__ +#define __TASK_BUTTON_H__ +#include "freertos/FreeRTOS.h" +#include "iot_button.h" + +#define NUM_BUTTONS 5 +#define NUM_EVENTS 10 +extern QueueHandle_t gt_btnq; + + +enum gt_btn_t { + GT_BTN_WHITE = 0, + GT_BTN_GREEN, + GT_BTN_YELLOW, + GT_BTN_BLUE, + GT_BTN_RED +}; + + +struct gt_btn_msg_t { + enum gt_btn_t btn; + button_event_t evt; +}; + + +/** + * @brief Setup button interrupts. + */ +void gt_btn_setup(void); +#endif diff --git a/main/task_lcd.c b/main/task_lcd.c index 933bf8f..3d1cf1c 100644 --- a/main/task_lcd.c +++ b/main/task_lcd.c @@ -7,11 +7,15 @@ #include "Goldelox_const4D.h" #include "goldeloxSerial.h" +#include "esp_system.h" #include "task_lcd.h" #include "pins.h" const uart_port_t uart_num = UART_NUM_1; +int g_time = 0; + +gl_display_t *error_disp = NULL; void lcd_clock_draw_face(gl_display_t *); @@ -19,6 +23,7 @@ void lcd_clock_draw_hand(gl_display_t *, uint16_t, uint16_t, uint8_t, gl_word_t) gl_word_t txt_strw(gl_display_t *, char *); + int write_tx(const void *data, size_t sz) { return uart_write_bytes(uart_num, data, sz); } @@ -70,6 +75,20 @@ void slower_baud() { ESP_ERROR_CHECK(uart_param_config(uart_num, &uart_config)); } +int Callback4DImpl (int, unsigned char) { + if (error_disp && g_time % 3 == 0) { + printf("resetting uLCD...\n"); + ESP_ERROR_CHECK(gpio_set_level(PIN_ULCD_RESET, 0)); + vTaskDelay(100 / portTICK_PERIOD_MS); + ESP_ERROR_CHECK(gpio_set_level(PIN_ULCD_RESET, 1)); + gl_reset2(error_disp); + //gl_setbaudWait(error_disp, BAUD_600000, &faster_baud); + } + if (g_time > 9) + esp_restart(); + g_time++; + return 10; +} /* ================================================================= */ void lcd_task(void) { @@ -77,6 +96,8 @@ void lcd_task(void) { const int uart_buffer_size = UART_HW_FIFO_LEN(uart_num) + 4; QueueHandle_t uart_queue; + Callback4D = &Callback4DImpl; + gl_serif_t serif_ulcd = { .write_tx = write_tx, .read_rx = read_rx, @@ -113,10 +134,13 @@ void lcd_task(void) { gl_init(&disp, &serif_ulcd); + //error_disp = &disp; + /* change baud rate */ gl_setbaudWait(&disp, BAUD_600000, &faster_baud); lcd_boot_flash(&disp); - lcd_clock_loop(&disp); + //lcd_clock_loop(&disp); + lcd_homepage_loop(&disp); } @@ -159,7 +183,10 @@ void lcd_boot_flash(gl_display_t *disp) { gl_putstr(disp, (uint8_t *) "Anish &"); gl_txt_MoveCursor(disp, 11, 10); gl_putstr(disp, (uint8_t *) "Advaith"); - vTaskDelay(pdMS_TO_TICKS(2000)); + ESP_ERROR_CHECK(gpio_set_level(PIN_VIBRATOR, 1)); + vTaskDelay(pdMS_TO_TICKS(500)); + ESP_ERROR_CHECK(gpio_set_level(PIN_VIBRATOR, 0)); + vTaskDelay(pdMS_TO_TICKS(1500)); } @@ -177,7 +204,7 @@ void lcd_clock_loop(gl_display_t *disp) { tm / (60 * 60) % 12, tm / 60 % 60, (tm / (60 * 60) % 24 > 12) ? "PM" : "AM"); - gl_txt_Italic(disp, 1); + /*gl_txt_Italic(disp, 1);*/ uint16_t chw = txt_strw(disp, txt); gl_gfx_MoveTo(disp, (LCD_WIDTH / 2) - (chw / 2), (LCD_HEIGHT / 2) + (CLOCKSCR_CIRCRAD / 2)); @@ -202,11 +229,14 @@ void lcd_clock_loop(gl_display_t *disp) { void lcd_homepage_loop(gl_display_t *disp) { + uint8_t num_rows = 3; + uint8_t num_cols = 2; + uint8_t num_padd = APPSCR_PAD; gl_gfx_BGcolour(disp, BLACK); gl_gfx_Cls(disp); - for (uint8_t i = 0; i < APPSCR_RCNUM; ++i) { - for (uint8_t j = 0; j < APPSCR_RCNUM; ++j) { + for (uint8_t i = 0; i < num_rows; ++i) { + for (uint8_t j = 0; j < num_cols; ++j) { /* printf("adding %d, %d [%d|%d|%d|%d]\n", i + 1, j + 1, @@ -219,8 +249,19 @@ void lcd_homepage_loop(gl_display_t *disp) { APPSCR_TOPCALCH(j + 1) + APPSCR_PADCALCH(0), WHITE); */ + gl_gfx_RectangleFilled(disp, + APPSCR_TOPCALCVW(num_cols, num_padd, j + 1), + APPSCR_TOPCALCVH(num_rows, num_padd, i + 1), + APPSCR_TOPCALCVW(num_cols, num_padd, j + 1) + + APPSCR_PADCALCVW(num_cols, num_padd), + APPSCR_TOPCALCVH(num_rows, num_padd, i + 1) + + APPSCR_PADCALCVH(num_rows, num_padd), + WHITE); } } + lcd_clock_loop(disp); + while(1) + vTaskDelay(pdMS_TO_TICKS(1000)); } diff --git a/main/task_lcd.h b/main/task_lcd.h index a6cde84..9bee7ab 100644 --- a/main/task_lcd.h +++ b/main/task_lcd.h @@ -28,8 +28,8 @@ #define APPSCR_TOPCALCH(x) ((x) * APPSCR_PAD) + (((x) - 1) * APPSCR_PADCALCH(0)) /* v stands for variale */ -#define APPSCR_PADCALCVW(n, pad) (LCD_WIDTH - (n) * (pad)) -#define APPSCR_PADCALCVH(n, pad) (LCD_HEIGHT - (n) * (pad)) +#define APPSCR_PADCALCVW(n, pad) (LCD_WIDTH - (n) * (pad)) / (n) +#define APPSCR_PADCALCVH(n, pad) (LCD_HEIGHT - (n) * (pad)) / (n) #define APPSCR_TOPCALCVW(n, pad, x) ((x) * (pad)) + \ (((x) - 1) * APPSCR_PADCALCVW(n, pad)) #define APPSCR_TOPCALCVH(n, pad, x) ((x) * (pad)) + \