File
Blob: archive/legacy-c/firmware/main/main.c
| 1 | #include <stdio.h> |
| 2 | #include <stdlib.h> |
| 3 | #include <string.h> |
| 4 | #include "esp_event.h" |
| 5 | #include "esp_heap_caps.h" |
| 6 | #include "esp_log.h" |
| 7 | #include "esp_netif.h" |
| 8 | #include "esp_psram.h" |
| 9 | #include "esp_wifi.h" |
| 10 | #include "freertos/FreeRTOS.h" |
| 11 | #include "freertos/event_groups.h" |
| 12 | #include "freertos/task.h" |
| 13 | #include "led_strip.h" |
| 14 | #include "radio.h" |
| 15 | #include "signaling.h" |
| 16 | #include "wifi_private.h" |
| 17 | |
| 18 | static EventGroupHandle_t wifi_events; |
| 19 | static led_strip_handle_t led; |
| 20 | |
| 21 | void radio_emit(cJSON *message) |
| 22 | { |
| 23 | if (!message) return; |
| 24 | if (signaling_observe(message)) { cJSON_Delete(message); return; } |
| 25 | char *text = cJSON_PrintUnformatted(message); |
| 26 | if (text) { printf("PROBE %s\n", text); free(text); } |
| 27 | cJSON_Delete(message); |
| 28 | } |
| 29 | |
| 30 | int radio_set_led(unsigned r, unsigned g, unsigned b) |
| 31 | { |
| 32 | esp_err_t err = led_strip_set_pixel(led, 0, r, g, b); |
| 33 | return err == ESP_OK ? led_strip_refresh(led) : err; |
| 34 | } |
| 35 | |
| 36 | static void wifi_event(void *arg, esp_event_base_t base, int32_t id, void *data) |
| 37 | { |
| 38 | if (base == IP_EVENT && id == IP_EVENT_STA_GOT_IP) xEventGroupSetBits(wifi_events, BIT0); |
| 39 | else if (base == WIFI_EVENT && id == WIFI_EVENT_STA_DISCONNECTED) { |
| 40 | xEventGroupClearBits(wifi_events, BIT0); |
| 41 | esp_wifi_connect(); |
| 42 | } |
| 43 | } |
| 44 | |
| 45 | bool radio_network_ready(void) |
| 46 | { |
| 47 | return wifi_events && (xEventGroupGetBits(wifi_events) & BIT0); |
| 48 | } |
| 49 | |
| 50 | void app_main(void) |
| 51 | { |
| 52 | setvbuf(stdout, NULL, _IONBF, 0); |
| 53 | esp_log_level_set("wifi", ESP_LOG_WARN); |
| 54 | led_strip_config_t strip = {.strip_gpio_num = 38, .max_leds = 1}; |
| 55 | led_strip_rmt_config_t rmt = {.resolution_hz = 10000000}; |
| 56 | ESP_ERROR_CHECK(led_strip_new_rmt_device(&strip, &rmt, &led)); |
| 57 | radio_set_led(8, 4, 0); |
| 58 | ESP_ERROR_CHECK(esp_netif_init()); |
| 59 | ESP_ERROR_CHECK(esp_event_loop_create_default()); |
| 60 | esp_netif_create_default_wifi_sta(); |
| 61 | wifi_events = xEventGroupCreate(); |
| 62 | wifi_init_config_t init = WIFI_INIT_CONFIG_DEFAULT(); |
| 63 | init.nvs_enable = 0; |
| 64 | ESP_ERROR_CHECK(esp_wifi_init(&init)); |
| 65 | ESP_ERROR_CHECK(esp_wifi_set_storage(WIFI_STORAGE_RAM)); |
| 66 | ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, wifi_event, NULL)); |
| 67 | ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, wifi_event, NULL)); |
| 68 | wifi_config_t config = {0}; |
| 69 | memcpy(config.sta.ssid, WIFI_SSID, sizeof(WIFI_SSID) - 1); |
| 70 | memcpy(config.sta.password, WIFI_PASSWORD, sizeof(WIFI_PASSWORD) - 1); |
| 71 | config.sta.threshold.authmode = WIFI_AUTH_WPA2_PSK; |
| 72 | config.sta.sae_pwe_h2e = WPA3_SAE_PWE_BOTH; |
| 73 | ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA)); |
| 74 | ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &config)); |
| 75 | ESP_ERROR_CHECK(esp_wifi_start()); |
| 76 | ESP_ERROR_CHECK(esp_wifi_set_ps(WIFI_PS_NONE)); |
| 77 | ESP_ERROR_CHECK(esp_wifi_connect()); |
| 78 | xEventGroupWaitBits(wifi_events, BIT0, false, false, portMAX_DELAY); |
| 79 | radio_set_led(0, 12, 4); |
| 80 | cJSON *ready = cJSON_CreateObject(); |
| 81 | cJSON_AddStringToObject(ready, "event", "hardware_ready"); |
| 82 | cJSON_AddBoolToObject(ready, "wifi", true); |
| 83 | cJSON_AddNumberToObject(ready, "psram_bytes", esp_psram_get_size()); |
| 84 | cJSON_AddNumberToObject(ready, "internal_free", heap_caps_get_free_size(MALLOC_CAP_INTERNAL)); |
| 85 | radio_emit(ready); |
| 86 | radio_init(); |
| 87 | signaling_start(); |
| 88 | char *line = calloc(1, 16384); |
| 89 | if (!line) abort(); |
| 90 | size_t used = 0; |
| 91 | bool overflow = false; |
| 92 | for (;;) { |
| 93 | int ch = getchar(); |
| 94 | if (ch == EOF) { clearerr(stdin); vTaskDelay(pdMS_TO_TICKS(10)); } |
| 95 | else if (ch == '\n') { |
| 96 | line[used] = 0; |
| 97 | cJSON *command = overflow ? NULL : cJSON_Parse(line); |
| 98 | if (command) { radio_command(command); cJSON_Delete(command); } |
| 99 | used = 0; |
| 100 | overflow = false; |
| 101 | } else if (ch != '\r' && !overflow) { |
| 102 | if (used < 16383) line[used++] = ch; |
| 103 | else overflow = true; |
| 104 | } |
| 105 | } |
| 106 | } |