#include #include #include #include #include #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "esp_system.h" #include "esp_log.h" #include "esp_netif_sntp.h" #include "nvs.h" #include "epd7in5.h" #include "wifi_manager.h" #include "OverpassMono_Bitmaps.h" #include "esp_tls.h" #include "esp_log.h" #include #include "driver/i2s_std.h" static const char TAG[] = "main"; enum { WIFI_CONNECTED, WIFI_LOST, ACCESS_POINT, } WifiState; struct { bool radio; } GlobalState; typedef struct { uint8_t event_id; uint32_t time; } TimerEvent; typedef struct { uint8_t event_id; } AlarmEvent; QueueHandle_t wifiQueue; QueueHandle_t timerEinkQueue; QueueHandle_t timerAlarmQueue; QueueHandle_t alarmQueue; void draw_char(uint8_t *image, int x, int y, char c) { uint32_t char_offset = (c - '0') * 16 * 176; for(int i=0; i<176; ++i) { memcpy(&image[x + (y+i)*EPD_WIDTH/8], &OverpassMono_Bitmaps[i*16+char_offset], 16); } } void draw_text(uint8_t *image, int x, int y, const char *text, int length) { //89x130 for(int i=0; i '9') { ESP_LOGE(TAG, "Invalid character '%c' in text: %s", text[i], text); return; } draw_char(image, x + i * 17, y, text[i]); } } void eink_task(void *pvParameter) { static uint8_t image[EPD_WIDTH * EPD_HEIGHT / 8]; memset(image, 0x00, sizeof(image)); epd7in5_v3_t epd; epd7in5_v3_create(&epd, SPI2_HOST); while(true) { // Wait for time update from timerQueue TimerEvent event; if (xQueueReceive(timerEinkQueue, &event, portMAX_DELAY) != pdTRUE) { ESP_LOGE(TAG, "Failed to receive timer event from queue"); continue; } char buffer[5] = {0}; memcpy(buffer, &event.time, sizeof(event.time)); memset(image, 0x00, sizeof(image)); epd7in5_v3_init(&epd); draw_text(image, 0, 0, buffer, 4); epd7in5_v3_busy_wait(&epd); epd7in5_v3_display(&epd, image); epd7in5_v3_busy_wait(&epd); epd7in5_v3_sleep(&epd); vTaskDelay( pdMS_TO_TICKS(500) ); } } #include "audio.h" #define SAMPLE_RATE 44100 #define TONE_HZ 853 #define TONE_2_HZ 960 #define I2S_NUM 0 #define PI 3.14159265 #define BITS_PER_SAMPLE 16 #define CHANNELS 2 #define BUFFER_SAMPLES 2048*4 static i2s_chan_handle_t tx_handle; void radio_task(void *pvParameter) { bool radioActive = false; i2s_chan_config_t chan_cfg = I2S_CHANNEL_DEFAULT_CONFIG(I2S_NUM, I2S_ROLE_MASTER); ESP_ERROR_CHECK(i2s_new_channel(&chan_cfg, &tx_handle, NULL)); // --- Clock configuration --- i2s_std_clk_config_t clk_cfg = I2S_STD_CLK_DEFAULT_CONFIG(SAMPLE_RATE); // --- Slot configuration --- i2s_std_slot_config_t slot_cfg = I2S_STD_PHILIPS_SLOT_DEFAULT_CONFIG( BITS_PER_SAMPLE, I2S_SLOT_MODE_MONO ); slot_cfg.slot_mask = I2S_STD_SLOT_LEFT | I2S_STD_SLOT_RIGHT; // --- GPIO configuration --- i2s_std_gpio_config_t gpio_cfg = { .mclk = I2S_GPIO_UNUSED, .bclk = GPIO_NUM_35, .ws = GPIO_NUM_36, .dout = GPIO_NUM_37, .din = I2S_GPIO_UNUSED, .invert_flags = { .mclk_inv = false, .bclk_inv = false, .ws_inv = false } }; // --- Initialize the TX channel in STD mode --- i2s_std_config_t std_cfg = { .clk_cfg = clk_cfg, .slot_cfg = slot_cfg, .gpio_cfg = gpio_cfg }; ESP_ERROR_CHECK(i2s_channel_init_std_mode(tx_handle, &std_cfg)); ESP_ERROR_CHECK(i2s_channel_enable(tx_handle)); // --- Generate and send sine wave --- int16_t *samples = malloc(BUFFER_SAMPLES * sizeof(int16_t)); if (!samples) { ESP_LOGE("I2S", "Failed to allocate memory for samples"); return; } uint32_t offset = 0; size_t level_up_size = sizeof(level_up) / sizeof(level_up[0]); AlarmEvent event; while(true) { if(!radioActive) { if(xQueueReceive(alarmQueue, &event, portMAX_DELAY) && event.event_id == 1) { ESP_LOGI(TAG, "Alarm activated, starting radio"); radioActive = true; } } else { if(xQueueReceive(alarmQueue, &event, 0) && event.event_id == 0) { ESP_LOGI(TAG, "Alarm deactivated, stopping radio"); radioActive = false; } //Do radio shit for (int i = 0; i < BUFFER_SAMPLES; ++i) { int16_t sample = level_up[(i+offset) % level_up_size]; samples[i] = sample / 4; } size_t bytes_to_write = BUFFER_SAMPLES * sizeof(int16_t); size_t bytes_written = 0; ESP_ERROR_CHECK(i2s_channel_write(tx_handle, samples, bytes_to_write, &bytes_written, portMAX_DELAY)); offset += bytes_written/2; vTaskDelay(1); } } free(samples); } void alarm_task(void *pvParameter) { bool alarmActive = false; int alarmStart = 830; // 20:55 in HHMM format int alarmEnd = 900; // 20:56 in HHMM format TimerEvent event; while(true) { if (xQueueReceive(timerAlarmQueue, &event, portMAX_DELAY) == pdTRUE) { ESP_LOGI(TAG, "Time event received"); int time = atoi((const char *)&event.time); if (time >= alarmStart && time < alarmEnd && !alarmActive) { alarmActive = true; AlarmEvent alarm_event; alarm_event.event_id = 1; // or any other event ID you want to use if (xQueueSend(alarmQueue, &alarm_event, portMAX_DELAY) != pdTRUE) { ESP_LOGE(TAG, "Failed to send alarm event to queue"); } else { ESP_LOGI(TAG, "Alarm event pushed to queue"); } } else if (time >= alarmEnd && alarmActive) { alarmActive = false; AlarmEvent alarm_event; alarm_event.event_id = 0; // or any other event ID you want to use if (xQueueSend(alarmQueue, &alarm_event, portMAX_DELAY) != pdTRUE) { ESP_LOGE(TAG, "Failed to send alarm event to queue"); } else { ESP_LOGI(TAG, "Alarm event pushed to queue"); } } } } } static bool timeSet = false; void time_update_task(void *pvParameter) { TimerEvent event; char lastMinute = '-'; while(!timeSet) { // Wait for time to be set by SNTP vTaskDelay(pdMS_TO_TICKS(1000)); } while(true) { // check if the last minute has changed and push to queue if so time_t now; struct tm timeinfo = { 0 }; time(&now); localtime_r(&now, &timeinfo); char buffer[5]; strftime(buffer, sizeof(buffer), "%H%M", &timeinfo); if (buffer[3] != lastMinute) { lastMinute = buffer[3]; event.event_id = WIFI_CONNECTED; // or any other event ID you want to use memcpy(&event.time, buffer, sizeof(event.time)); if (xQueueSend(timerEinkQueue, &event, portMAX_DELAY) != pdTRUE) { ESP_LOGE(TAG, "Failed to send timer event to queue"); } else { ESP_LOGI(TAG, "Pushed time update to queue: %s", buffer); } if (xQueueSend(timerAlarmQueue, &event, portMAX_DELAY) != pdTRUE) { ESP_LOGE(TAG, "Failed to send timer event to queue"); } else { ESP_LOGI(TAG, "Pushed time update to queue: %s", buffer); } } vTaskDelay(pdMS_TO_TICKS(500)); //Check every half second } } void time_sync_notification_cb(struct timeval *tv) { timeSet = true; ESP_LOGI(TAG, "Notification of a time synchronization event"); } //RTC_DATA_ATTR static int boot_count = 0; static void obtain_time(void* pvParameter) { ESP_LOGI(TAG, "Initializing SNTP"); esp_sntp_config_t config = ESP_NETIF_SNTP_DEFAULT_CONFIG("pool.ntp.org"); config.start = false; config.server_from_dhcp = false; config.renew_servers_after_new_IP = false; config.index_of_first_server = 1; config.ip_event_to_renew = IP_EVENT_STA_GOT_IP; config.sync_cb = time_sync_notification_cb; esp_netif_sntp_init(&config); setenv("TZ", "EST5EDT,M3.2.0/2,M11.1.0", 1); tzset(); while(true) { ESP_LOGI(TAG, "Starting SNTP"); esp_netif_sntp_start(); time_t now = 0; struct tm timeinfo = { 0 }; int retry = 0; const int retry_count = 15; while (esp_netif_sntp_sync_wait(2000 / portTICK_PERIOD_MS) == ESP_ERR_TIMEOUT && ++retry < retry_count) { ESP_LOGI(TAG, "Waiting for system time to be set... (%d/%d)", retry, retry_count); } time(&now); localtime_r(&now, &timeinfo); vTaskDelay(pdMS_TO_TICKS(60 * 60 * 1000)); } } void cb_connection_ok(void *pvParameter){ ip_event_got_ip_t* param = (ip_event_got_ip_t*)pvParameter; char str_ip[16]; esp_ip4addr_ntoa(¶m->ip_info.ip, str_ip, IP4ADDR_STRLEN_MAX); ESP_LOGI(TAG, "I have a connection and my IP is %s!", str_ip); // Notify the radio task that we have a connection int wifi_event = WIFI_CONNECTED; if (xQueueSend(wifiQueue, &wifi_event, portMAX_DELAY) != pdTRUE) { ESP_LOGE(TAG, "Failed to send WIFI_CONNECTED event to queue"); } else { ESP_LOGI(TAG, "Sent WIFI_CONNECTED event to queue"); } } //void audio_task(void* pvParameter); //void http_stream_task(void *pvParameter); //void https_insecure_task(void *pv); void app_main() { esp_log_level_set("esp-tls-mbedtls", ESP_LOG_DEBUG); esp_log_level_set("TLSv1", ESP_LOG_DEBUG); //mbedtls_debug_set_threshold(4); wifiQueue = xQueueCreate(2, sizeof(int)); timerEinkQueue = xQueueCreate(2, sizeof(TimerEvent)); timerAlarmQueue = xQueueCreate(2, sizeof(TimerEvent)); alarmQueue = xQueueCreate(2, sizeof(AlarmEvent)); wifi_manager_start(); wifi_manager_set_callback(WM_EVENT_STA_GOT_IP, &cb_connection_ok); xTaskCreatePinnedToCore(&radio_task, "radio", 3072, NULL, 1, NULL, 1); xTaskCreatePinnedToCore(&eink_task, "eink", 3072, NULL, 1, NULL, 1); xTaskCreate(&obtain_time, "sntp", 3072, NULL, 10, NULL); xTaskCreate(&time_update_task, "timer", 3072, NULL, 10, NULL); //xTaskCreate(&audio_task, "timer", 3072, NULL, 10, NULL); xTaskCreate(&alarm_task, "timer", 3072, NULL, 10, NULL); //xTaskCreate(https_insecure_task, "https_insec", 8192, NULL, 5, NULL); } // HTTP test code // //void https_get_insecure(const char *host, const char *path) //{ // const int port = 443; // // // 1) Allocate the TLS handle // esp_tls_t *tls = esp_tls_init(); // if (!tls) { // ESP_LOGE(TAG, "Failed to init TLS handle"); // return; // } // // // Insecure TLS config: no CA, skip CN // esp_tls_cfg_t tls_cfg = { // .cacert_buf = NULL, // .cacert_bytes = 0, // .skip_common_name = true, // // Force TLS 1.2 only: // .tls_version = ESP_TLS_VER_TLS_1_2, // // Advertise HTTP/1.1 via ALPN (many servers require this for HTTPS): // .alpn_protos = (const char*[]){"http/1.1", NULL}, // }; // // // This will send the SNI extension = host // int ret = esp_tls_conn_new_sync(host, strlen(host), port, &tls_cfg, tls); // if (ret != 1) { // ESP_LOGE(TAG, "TLS handshake failed, esp_tls_conn_new_sync returned %d", ret); // esp_tls_conn_destroy(tls); // return; // } // ESP_LOGI(TAG, "TLS handshake succeeded (insecure)"); // // // Send a minimal GET // char req[256]; // int len = snprintf(req, sizeof(req), // "GET %s HTTP/1.1\r\n" // "Host: %s\r\n" // "Connection: close\r\n\r\n", // path, host); // esp_tls_conn_write(tls, (const unsigned char *)req, len); // // Read and print // char buf[128]; // int r; // do { // r = esp_tls_conn_read(tls, (unsigned char*)buf, sizeof(buf)-1); // if (r > 0) { // buf[r] = '\0'; // printf("%s", buf); // } // } while (r > 0 || r == ESP_TLS_ERR_SSL_WANT_READ); // esp_tls_conn_destroy(tls); //} // //void https_insecure_task(void *pv) //{ // // Wait for WiFi to be connected (from wifiqueue) // int event; // if( xQueueReceive(wifiQueue, &event, portMAX_DELAY) != pdTRUE ) { // ESP_LOGE(TAG, "Failed to receive WIFI_CONNECTED event from queue"); // return; // } // // https_get_insecure("listen.moe", "/stream"); //}