diff options
| -rw-r--r-- | firmware/notes | 9 | ||||
| -rw-r--r-- | firmware/src/assets/frame.png | bin | 0 -> 128 bytes | |||
| -rw-r--r-- | firmware/src/assets/full.png | bin | 0 -> 294 bytes | |||
| -rw-r--r-- | firmware/src/assets/light1.png | bin | 0 -> 137 bytes | |||
| -rw-r--r-- | firmware/src/assets/light2.png | bin | 0 -> 176 bytes | |||
| -rw-r--r-- | firmware/src/assets/wifi.png | bin | 0 -> 117 bytes | |||
| m--------- | firmware/src/components/esp32-ssd1306 | 0 | ||||
| -rw-r--r-- | firmware/src/main/CMakeLists.txt | 3 | ||||
| -rw-r--r-- | firmware/src/main/main.c | 295 |
9 files changed, 282 insertions, 25 deletions
diff --git a/firmware/notes b/firmware/notes new file mode 100644 index 0000000..3795e63 --- /dev/null +++ b/firmware/notes @@ -0,0 +1,9 @@ +V_GS,LOW = V_DD - (V_DD - V_CC - V_TVS) * (R2 / (R1 + R2)) +V_GS,HIGH = V_DD - V_DD * (R2 / (R1 + R2)) + +V_DD = 0.6 * (1 + R1 / R2) = 0.6 * (1 + 100 / 5.1) = 12.4 +V_GS,LOW = 12.4 - (12.4 - 5 - 0.7) * (100 / (100 + 10)) = 0.6 V +V_GS,HIGH = 12.4 - 12.4 * (100 / (100 + 10)) = 1.13 V + +Default stdio driver flushes after newline. May sleep for 50ms +when the tx fifo is full, but generally unbuffered. diff --git a/firmware/src/assets/frame.png b/firmware/src/assets/frame.png Binary files differnew file mode 100644 index 0000000..0a50470 --- /dev/null +++ b/firmware/src/assets/frame.png diff --git a/firmware/src/assets/full.png b/firmware/src/assets/full.png Binary files differnew file mode 100644 index 0000000..37fc7f1 --- /dev/null +++ b/firmware/src/assets/full.png diff --git a/firmware/src/assets/light1.png b/firmware/src/assets/light1.png Binary files differnew file mode 100644 index 0000000..70588d8 --- /dev/null +++ b/firmware/src/assets/light1.png diff --git a/firmware/src/assets/light2.png b/firmware/src/assets/light2.png Binary files differnew file mode 100644 index 0000000..57ff6db --- /dev/null +++ b/firmware/src/assets/light2.png diff --git a/firmware/src/assets/wifi.png b/firmware/src/assets/wifi.png Binary files differnew file mode 100644 index 0000000..082f0b9 --- /dev/null +++ b/firmware/src/assets/wifi.png diff --git a/firmware/src/components/esp32-ssd1306 b/firmware/src/components/esp32-ssd1306 -Subproject b94130e71b44c4b60f396f611b9e73d48cdd3e9 +Subproject bc62290bc58c1ceaa13c95c82420a5292785b85 diff --git a/firmware/src/main/CMakeLists.txt b/firmware/src/main/CMakeLists.txt index 55218ea..ecce39d 100644 --- a/firmware/src/main/CMakeLists.txt +++ b/firmware/src/main/CMakeLists.txt @@ -1,3 +1,4 @@ idf_component_register(SRCS "main.c" INCLUDE_DIRS "" - REQUIRES "esp32-ssd1306") + REQUIRES "esp32-ssd1306" "esp_driver_gpio" "esp_driver_uart" "esp_wifi" "nvs_flash") +#component_compile_options("-O0") diff --git a/firmware/src/main/main.c b/firmware/src/main/main.c index 034c844..51e6c36 100644 --- a/firmware/src/main/main.c +++ b/firmware/src/main/main.c @@ -1,11 +1,34 @@ +#include "esp_netif_ip_addr.h" +#include "esp_wifi_types_generic.h" +#include "freertos/idf_additions.h" +#include "ssd1306.h" + #include "freertos/FreeRTOS.h" #include "freertos/task.h" +#include "portmacro.h" #include "driver/gpio.h" #include "hal/gpio_types.h" -#include "ssd1306.h" +#include "esp_wifi.h" +#include "esp_log.h" +#include "nvs_flash.h" +#include <string.h> #include <stdio.h> +#define TICKS_MS(x) ((x) / portTICK_PERIOD_MS) +#define LOG(...) ESP_LOGI("desk-andon", __VA_ARGS__) + +/* The event group allows multiple bits for each event, but we only care about two events: + * - we are connected to the AP with an IP + * - we failed to connect after the maximum amount of retries */ +#define WIFI_CONNECTED_BIT BIT0 +#define WIFI_FAIL_BIT BIT1 + +#define WIFI_ATTEMPT_MAX 5 + +#define WIFI_SSID "andon-net" +#define WIFI_PASS "uzw00ystu1" + enum Lane { RED, ORANGE, @@ -13,40 +36,264 @@ enum Lane { BLUE, WHITE, SPEAKER, - PIN_COUNT }; -const static int ANDON_PINS[PIN_COUNT] = { 10, 3, 7, 6, 5, 4 }; +static const uint8_t bitmap_frame[] = { +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +0xc0, 0x00, 0x00, 0x20, 0x00, 0x00, 0x10, 0x00, 0x00, 0x08, 0x00, 0x00, 0x04, 0x00, 0x00, 0x03, +0xc0, 0x00, 0x00, 0x20, 0x00, 0x00, 0x10, 0x00, 0x00, 0x08, 0x00, 0x00, 0x04, 0x00, 0x00, 0x03, +0xc0, 0x00, 0x00, 0x20, 0x00, 0x00, 0x10, 0x00, 0x00, 0x08, 0x00, 0x00, 0x04, 0x00, 0x00, 0x03, +0xc0, 0x00, 0x00, 0x20, 0x00, 0x00, 0x10, 0x00, 0x00, 0x08, 0x00, 0x00, 0x04, 0x00, 0x00, 0x03, +0xc0, 0x00, 0x00, 0x20, 0x00, 0x00, 0x10, 0x00, 0x00, 0x08, 0x00, 0x00, 0x04, 0x00, 0x00, 0x03, +0xc0, 0x00, 0x00, 0x20, 0x00, 0x00, 0x10, 0x00, 0x00, 0x08, 0x00, 0x00, 0x04, 0x00, 0x00, 0x03, +0xc0, 0x00, 0x00, 0x20, 0x00, 0x00, 0x10, 0x00, 0x00, 0x08, 0x00, 0x00, 0x04, 0x00, 0x00, 0x03, +0xc0, 0x00, 0x00, 0x20, 0x00, 0x00, 0x10, 0x00, 0x00, 0x08, 0x00, 0x00, 0x04, 0x00, 0x00, 0x03, +0xc0, 0x00, 0x00, 0x20, 0x00, 0x00, 0x10, 0x00, 0x00, 0x08, 0x00, 0x00, 0x04, 0x00, 0x00, 0x03, +0xc0, 0x00, 0x00, 0x20, 0x00, 0x00, 0x10, 0x00, 0x00, 0x08, 0x00, 0x00, 0x04, 0x00, 0x00, 0x03, +0xc0, 0x00, 0x00, 0x20, 0x00, 0x00, 0x10, 0x00, 0x00, 0x08, 0x00, 0x00, 0x04, 0x00, 0x00, 0x03, +0xc0, 0x00, 0x00, 0x20, 0x00, 0x00, 0x10, 0x00, 0x00, 0x08, 0x00, 0x00, 0x04, 0x00, 0x00, 0x03, +0xc0, 0x00, 0x00, 0x20, 0x00, 0x00, 0x10, 0x00, 0x00, 0x08, 0x00, 0x00, 0x04, 0x00, 0x00, 0x03, +0xc0, 0x00, 0x00, 0x20, 0x00, 0x00, 0x10, 0x00, 0x00, 0x08, 0x00, 0x00, 0x04, 0x00, 0x00, 0x03, +0xc0, 0x00, 0x00, 0x20, 0x00, 0x00, 0x10, 0x00, 0x00, 0x08, 0x00, 0x00, 0x04, 0x00, 0x00, 0x03, +0xc0, 0x00, 0x00, 0x20, 0x00, 0x00, 0x10, 0x00, 0x00, 0x08, 0x00, 0x00, 0x04, 0x00, 0x00, 0x03, +0xc0, 0x00, 0x00, 0x20, 0x00, 0x00, 0x10, 0x00, 0x00, 0x08, 0x00, 0x00, 0x04, 0x00, 0x00, 0x03, +0xc0, 0x00, 0x00, 0x20, 0x00, 0x00, 0x10, 0x00, 0x00, 0x08, 0x00, 0x00, 0x04, 0x00, 0x00, 0x03, +0xc0, 0x00, 0x00, 0x20, 0x00, 0x00, 0x10, 0x00, 0x00, 0x08, 0x00, 0x00, 0x04, 0x00, 0x00, 0x03, +0xc0, 0x00, 0x00, 0x20, 0x00, 0x00, 0x10, 0x00, 0x00, 0x08, 0x00, 0x00, 0x04, 0x00, 0x00, 0x03, +0xc0, 0x00, 0x00, 0x20, 0x00, 0x00, 0x10, 0x00, 0x00, 0x08, 0x00, 0x00, 0x04, 0x00, 0x00, 0x03, +0xc0, 0x00, 0x00, 0x20, 0x00, 0x00, 0x10, 0x00, 0x00, 0x08, 0x00, 0x00, 0x04, 0x00, 0x00, 0x03, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff +}; + +static const uint8_t bitmap_light1[] = { +0x07, 0x00, 0x0e, 0x0e, 0x00, 0x1c, 0x1c, 0x00, 0x38, 0x38, 0x00, 0x70, 0x70, 0x00, 0xe0, 0xe0, +0x01, 0xc0, 0xc0, 0x03, 0x80, 0x80, 0x07, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x38, +0x00, 0x00, 0x70, 0x00, 0x00, 0xe0, 0x01, 0x01, 0xc0, 0x03, 0x03, 0x80, 0x07, 0x07, 0x00, 0x0e, +0x0e, 0x00, 0x1c, 0x1c, 0x00, 0x38, 0x38, 0x00, 0x70, 0x70, 0x00, 0xe0, 0xe0, 0x01, 0xc0, 0xc0, +0x03, 0x80 +}; + +static const uint8_t bitmap_light2[] = { +0x00, 0x1c, 0x00, 0x00, 0x38, 0x00, 0x00, 0x70, 0x00, 0x00, 0xe0, 0x00, 0x01, 0xc0, 0x00, 0x03, +0x80, 0x00, 0x07, 0x00, 0x01, 0x0e, 0x00, 0x03, 0x1c, 0x00, 0x07, 0x38, 0x00, 0x0e, 0x70, 0x00, +0x1c, 0xe0, 0x00, 0x38, 0xc0, 0x00, 0x70, 0x80, 0x00, 0xe0, 0x00, 0x01, 0xc0, 0x00, 0x03, 0x80, +0x00, 0x07, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x38, 0x00, 0x00, 0x70, 0x00, 0x00, +0xe0, 0x00 +}; + +const static int ANDON_PINS[SPEAKER+1] = { 10, 6, 3, 5, 7, 4 }; + +static uint8_t state = 0; + +static SSD1306_t display = { 0 }; +static bool lcd_init = false; + +static char mac_str[16] = { 0 }; +static char ip_str[17] = { 0 }; +static bool wifi_connected = false; +static int wifi_connect_attempt = 0; -void app_main(void) +static EventGroupHandle_t wifi_event_group; + +static void +lcd_task_main(void *_p) { - SSD1306_t display; - int i, tick = 0; + bool frame_state[SPEAKER] = { 0 }; + char mac_str_old[16] = { 0 }; + char mac_str_new[16] = { 0 }; + char ip_str_old[17] = { 0 }; + char ip_str_new[17] = { 0 }; - ssd1306_init(&display); - ssd1306_clear_screen(&display, false); - ssd1306_display_text(&display, 0, "testing", 7, false); + TickType_t last = 0; + while (1) { + TickType_t now = xTaskGetTickCount(); + if (!last || (now - last) * portTICK_PERIOD_MS >= 500) { + uint8_t current = state; + memcpy(ip_str_new, ip_str, sizeof(ip_str)); + memcpy(mac_str_new, mac_str, sizeof(mac_str)); + bool connected = wifi_connected; + + for (int i = 0; i < SPEAKER; i++) { + if (current & (1 << i)) { + frame_state[i] ^= true; + } + } + last = now; + + if (!lcd_init) { + _ssd1306_clear(&display, false); + _ssd1306_bitmaps(&display, 0, 0, bitmap_frame, 128, 28, false); + lcd_init = true; + } + + const int xoff = (128 - 24 * 5 - 4) / 2; + for (int i = 0; i < SPEAKER; i++) { + if (current & (1 << i)) { + _ssd1306_bitmaps(&display, xoff + i * 25, 3, + frame_state[i] ? bitmap_light2 : bitmap_light1, + 24, 22, false); + } else { + _ssd1306_clear_rect(&display, xoff + i * 25, 3, 24, 22, false); + } + } + + + if (strcmp(mac_str_old, mac_str_new)) { + _ssd1306_display_text(&display, 4, 40, + mac_str_new, strlen(mac_str_new), false); + strncpy(mac_str_old, mac_str_new, sizeof(mac_str)); + } - for (i = 0; i < PIN_COUNT; i++) { + if (strcmp(ip_str_old, ip_str_new)) { + _ssd1306_display_text(&display, connected ? 4 : 0, 52, + ip_str_new, strlen(ip_str_new), false); + strncpy(ip_str_old, ip_str_new, sizeof(ip_str)); + } + + ssd1306_next_frame(&display); + } + + vTaskDelay(TICKS_MS(50)); + } +} + +static void +set_output(uint8_t bv) +{ + state = bv; + for (int i = 0; i <= SPEAKER; i++) { + gpio_set_level(ANDON_PINS[i], !(state & (1 << i))); + vTaskDelay(10); + } +} + +static void +wifi_event_handler(void *arg, esp_event_base_t event_base, + int32_t event_id, void *event_data) +{ + if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) { + snprintf(ip_str, sizeof(ip_str), " connecting.. "); + vTaskDelay(1); + wifi_connected = false; + esp_wifi_connect(); + } else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) { + wifi_connected = false; + if (wifi_connect_attempt < WIFI_ATTEMPT_MAX) { + esp_wifi_connect(); + wifi_connect_attempt++; + LOG("retry to connect to the AP"); + snprintf(ip_str, sizeof(ip_str), " connecting..%c ", + '0' + wifi_connect_attempt); + } else { + snprintf(ip_str, sizeof(ip_str), " no wifi "); + xEventGroupSetBits(wifi_event_group, WIFI_FAIL_BIT); + } + LOG("connect to the AP fail"); + } else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) { + ip_event_got_ip_t* event = (ip_event_got_ip_t*) event_data; + LOG("got ip:" IPSTR, IP2STR(&event->ip_info.ip)); + snprintf(ip_str, sizeof(ip_str), IPSTR, IP2STR(&event->ip_info.ip)); + wifi_connect_attempt = 0; + wifi_connected = true; + xEventGroupSetBits(wifi_event_group, WIFI_CONNECTED_BIT); + } +} + +static void +wifi_init(void) +{ + esp_err_t ret = nvs_flash_init(); + if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) { + ESP_ERROR_CHECK(nvs_flash_erase()); + ret = nvs_flash_init(); + } + ESP_ERROR_CHECK(ret); + + wifi_event_group = xEventGroupCreate(); + ESP_ERROR_CHECK(esp_netif_init()); + + ESP_ERROR_CHECK(esp_event_loop_create_default()); + esp_netif_create_default_wifi_sta(); + + wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); + ESP_ERROR_CHECK(esp_wifi_init(&cfg)); + + uint8_t mac[6] = { 0 }; + esp_wifi_get_mac(WIFI_IF_STA, mac); + snprintf(mac_str, sizeof(mac_str), ":%02X:%02X:%02X:%02X:%02X", + mac[1], mac[2], mac[3], mac[4], mac[5]); + + esp_event_handler_instance_t instance_any_id; + esp_event_handler_instance_t instance_got_ip; + ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT, + ESP_EVENT_ANY_ID, &wifi_event_handler, NULL, &instance_any_id)); + ESP_ERROR_CHECK(esp_event_handler_instance_register(IP_EVENT, + IP_EVENT_STA_GOT_IP, &wifi_event_handler, NULL, &instance_got_ip)); + + wifi_config_t wifi_config = { + .sta = { + .ssid = WIFI_SSID, + .password = WIFI_PASS, + .threshold.authmode = WIFI_AUTH_WPA2_PSK, + .sae_pwe_h2e = WPA3_SAE_PWE_BOTH, + .sae_h2e_identifier = "", + }, + }; + ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA) ); + ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config) ); + ESP_ERROR_CHECK(esp_wifi_start() ); + + LOG("wifi_init_sta finished."); + + /* Waiting until either the connection is established (WIFI_CONNECTED_BIT) + * or connection failed for the maximum number of re-tries (WIFI_FAIL_BIT). + * The bits are set by event_handler() (see above) */ + EventBits_t bits = xEventGroupWaitBits(wifi_event_group, + WIFI_CONNECTED_BIT | WIFI_FAIL_BIT, pdFALSE, pdFALSE, portMAX_DELAY); + + /* xEventGroupWaitBits() returns the bits before the call returned, + * hence we can test which event actually happened. */ + if (bits & WIFI_CONNECTED_BIT) { + LOG("connected to ap SSID:%s password:%s", WIFI_SSID, WIFI_PASS); + } else if (bits & WIFI_FAIL_BIT) { + LOG("Failed to connect to SSID:%s, password:%s", WIFI_SSID, WIFI_PASS); + } else { + LOG("UNEXPECTED EVENT"); + } +} + +void +app_main(void) +{ + for (int i = 0; i <= SPEAKER; i++) { gpio_reset_pin(ANDON_PINS[i]); - gpio_set_level(ANDON_PINS[i], 1); gpio_set_direction(ANDON_PINS[i], GPIO_MODE_OUTPUT_OD); + gpio_set_level(ANDON_PINS[i], 1); } + printf("DESK ANDON\n"); + i2c_master_init(&display, 0, 1, -1); + ssd1306_init(&display, 128, 64); + ssd1306_clear_screen(&display, false); + ssd1306_display_text(&display, 3, 24, "DESK ANDON", 10, false); + vTaskDelay(TICKS_MS(500)); + + TaskHandle_t lcd_task = NULL; + xTaskCreate(lcd_task_main, "lcd", 16 * 1024, NULL, tskIDLE_PRIORITY, &lcd_task); + vTaskDelay(TICKS_MS(500)); + + wifi_init(); + + int tick = 0; + uint8_t b = 0; while (1) { printf("Tick %i\n", ++tick); - fflush(stdout); - for (i = 0; i < PIN_COUNT; i++) { - gpio_set_level(ANDON_PINS[i], 0); - vTaskDelay(1000 / portTICK_PERIOD_MS); - gpio_set_level(ANDON_PINS[i], 1); - } - // for (i = 0; i < PIN_COUNT; i++) { - // gpio_set_level(ANDON_PINS[i], 0); - // } - // vTaskDelay(1000 / portTICK_PERIOD_MS); - // for (i = 0; i < PIN_COUNT; i++) { - // gpio_set_level(ANDON_PINS[i], 1); - // } + set_output(b); + b = (b + 1) & ((1 << SPEAKER) - 1); + vTaskDelay(TICKS_MS(1000)); } } |
