diff --git a/docs/udp.md b/docs/udp.md new file mode 100644 index 0000000..58c23fd --- /dev/null +++ b/docs/udp.md @@ -0,0 +1,17 @@ +# 基于 UDP 的上、下位机通讯规则 + +## 报文格式 + +开始的一个字节是命令,剩余字节是数据。缓冲区长度设为 1024 字节,所以单个 UDP 报文的数据最多为 1023 字节。 + +## 命令 + +### 上位机在线 `1` + +### 更新灯带颜色 `2` + +| 数据 | 长度(字节) | 说明 | +| --- | --- | --- | +| 起始位置 | 2 | 0~65535 | +| 长度 | 2 | 0~65535 | +| 颜色 | 3 | RGB 顺序,$2^3 * 2^3 * 2^3 = 65535$ 真彩色 | diff --git a/main/light.c b/main/light.c index b976d37..f521461 100644 --- a/main/light.c +++ b/main/light.c @@ -126,6 +126,14 @@ void led_strip_set_color_calibration(float red, float green, float blue) { nvs_close(local_nvs_handle); } +void light_strip_transmit_task(void *pvParameter) { + while (1) { + ESP_ERROR_CHECK(rmt_transmit(led_chan, led_encoder, led_strip_pixels, + sizeof(led_strip_pixels), &tx_config)); + vTaskDelay(pdMS_TO_TICKS(10)); + } +} + /** * @brief Simple helper function, converting HSV color space to RGB color * space @@ -224,8 +232,6 @@ void light_for_init() { ESP_LOGI(LIGHT_TAG, "light_for_init"); memset(led_strip_pixels, 0, sizeof(led_strip_pixels)); - ESP_ERROR_CHECK(rmt_transmit(led_chan, led_encoder, led_strip_pixels, - sizeof(led_strip_pixels), &tx_config)); nvs_handle local_nvs_handle; esp_err_t err = nvs_open("storage", NVS_READWRITE, &local_nvs_handle); @@ -268,7 +274,7 @@ void light_for_init() { uint8_t init_r, init_g, init_b; do { - for (uint8_t i = 0; i < 50; i++) { + for (uint8_t i = 0; i < 200; i++) { init_r = (uint8_t)(r_f * (float)i); init_g = (uint8_t)(g_f * (float)i); init_b = (uint8_t)(b_f * (float)i); @@ -279,8 +285,6 @@ void light_for_init() { led_strip_pixels[j * 3 + 2] = init_b; } - ESP_ERROR_CHECK(rmt_transmit(led_chan, led_encoder, led_strip_pixels, - sizeof(led_strip_pixels), &tx_config)); vTaskDelay(pdMS_TO_TICKS(20)); } vTaskDelay(pdMS_TO_TICKS(100)); @@ -312,8 +316,6 @@ void light_for_connecting_wifi() { led_strip_pixels[5] = 0; } tick_tock = !tick_tock; - ESP_ERROR_CHECK(rmt_transmit(led_chan, led_encoder, led_strip_pixels, - sizeof(led_strip_pixels), &tx_config)); vTaskDelay(pdMS_TO_TICKS(200)); } while (light_mode == light_mode_connection_wifi); } @@ -345,8 +347,6 @@ void light_for_idle() { blue * display_ambient_light_brightness * led_strip_blue_calibration; } // update_desktop_connection_state(); - ESP_ERROR_CHECK(rmt_transmit(led_chan, led_encoder, led_strip_pixels, - sizeof(led_strip_pixels), &tx_config)); vTaskDelay(pdMS_TO_TICKS(10)); } } @@ -404,49 +404,49 @@ void light_init_strip() { xTaskCreate(light_strip_running_task, "LIGHT_STRIP_RUNNING_TASK", 4096, NULL, 1, NULL); + + xTaskCreate(light_strip_transmit_task, "LIGHT_STRIP_TRANSMIT_TASK", 4096, + NULL, 1, NULL); } void light_play_colors(uint16_t len, uint8_t *buffer) { - light_mode = light_mode_desktop_sending_colors; + // light_mode = light_mode_desktop_sending_colors; - uint16_t black_count = 0; // count of black pixels. r/g/b <= 10 + // uint16_t black_count = 0; // count of black pixels. r/g/b <= 10 - for (uint16_t led_index = 0, buffer_cursor = 0; - led_index < STRIP_LED_NUMBER && buffer_cursor < len; - led_index++, buffer_cursor += 3) { - uint8_t r = (uint8_t)((float)buffer[buffer_cursor] * - display_ambient_light_brightness * - led_strip_red_calibration), - g = (uint8_t)((float)buffer[buffer_cursor + 1] * - display_ambient_light_brightness * - led_strip_green_calibration), - b = (uint8_t)((float)buffer[buffer_cursor + 2] * - display_ambient_light_brightness * - led_strip_blue_calibration); - if (r <= 7 && g <= 7 && b <= 7) { - black_count++; - } - led_strip_pixels[led_index * 3 + 0] = g; - led_strip_pixels[led_index * 3 + 1] = r; - led_strip_pixels[led_index * 3 + 2] = b; - } + // for (uint16_t led_index = 0, buffer_cursor = 0; + // led_index < STRIP_LED_NUMBER && buffer_cursor < len; + // led_index++, buffer_cursor += 3) { + // uint8_t r = (uint8_t)((float)buffer[buffer_cursor] * + // display_ambient_light_brightness * + // led_strip_red_calibration), + // g = (uint8_t)((float)buffer[buffer_cursor + 1] * + // display_ambient_light_brightness * + // led_strip_green_calibration), + // b = (uint8_t)((float)buffer[buffer_cursor + 2] * + // display_ambient_light_brightness * + // led_strip_blue_calibration); + // if (r <= 7 && g <= 7 && b <= 7) { + // black_count++; + // } + // led_strip_pixels[led_index * 3 + 0] = g; + // led_strip_pixels[led_index * 3 + 1] = r; + // led_strip_pixels[led_index * 3 + 2] = b; + // } - if (black_count > STRIP_LED_NUMBER / 5 * 4) { - uint8_t r = (uint8_t)((float)50 * display_ambient_light_brightness * - led_strip_red_calibration), - g = (uint8_t)((float)40 * display_ambient_light_brightness * - led_strip_green_calibration), - b = (uint8_t)((float)20 * display_ambient_light_brightness * - led_strip_blue_calibration); - for (uint16_t led_index = 0; led_index < STRIP_LED_NUMBER; led_index++) { - led_strip_pixels[led_index * 3 + 0] = g; - led_strip_pixels[led_index * 3 + 1] = r; - led_strip_pixels[led_index * 3 + 2] = b; - } - } - - ESP_ERROR_CHECK(rmt_transmit(led_chan, led_encoder, led_strip_pixels, - sizeof(led_strip_pixels), &tx_config)); + // if (black_count > STRIP_LED_NUMBER / 5 * 4) { + // uint8_t r = (uint8_t)((float)50 * display_ambient_light_brightness * + // led_strip_red_calibration), + // g = (uint8_t)((float)40 * display_ambient_light_brightness * + // led_strip_green_calibration), + // b = (uint8_t)((float)20 * display_ambient_light_brightness * + // led_strip_blue_calibration); + // for (uint16_t led_index = 0; led_index < STRIP_LED_NUMBER; led_index++) { + // led_strip_pixels[led_index * 3 + 0] = g; + // led_strip_pixels[led_index * 3 + 1] = r; + // led_strip_pixels[led_index * 3 + 2] = b; + // } + // } vTaskDelay(pdMS_TO_TICKS(10)); } @@ -454,3 +454,53 @@ void light_play(light_mode_t mode) { ESP_LOGI(LIGHT_TAG, "light_play: %d", mode); light_mode = mode; } + +void set_display_ambient_light_colors(uint16_t offset, uint8_t *sub_pixels, + uint16_t len) { + // ESP_LOGI(LIGHT_TAG, "set_display_ambient_light_colors: offset: %d\t len: + // %d", + // offset, len); + light_mode = light_mode_desktop_sending_colors; + + uint16_t black_count = 0; // count of black pixels. r/g/b <= 7 + + uint16_t global_end = len + offset * 3; + + if (global_end > STRIP_LED_NUMBER * 3) { + global_end = STRIP_LED_NUMBER * 3; + } + + for (uint16_t global_index = offset * 3, local_index = 0; + global_index < global_end; global_index += 3, local_index += 3) { + uint8_t r = (uint8_t)((float)sub_pixels[local_index + 0] * + display_ambient_light_brightness * + led_strip_red_calibration), + g = (uint8_t)((float)sub_pixels[local_index + 1] * + display_ambient_light_brightness * + led_strip_green_calibration), + b = (uint8_t)((float)sub_pixels[local_index + 2] * + display_ambient_light_brightness * + led_strip_blue_calibration); + if (r <= 7 && g <= 7 && b <= 7) { + black_count++; + } + led_strip_pixels[global_index + 0] = g; + led_strip_pixels[global_index + 1] = r; + led_strip_pixels[global_index + 2] = b; + } + + if (black_count == len / 3) { + uint8_t r = (uint8_t)((float)10 * display_ambient_light_brightness * + led_strip_red_calibration), + g = (uint8_t)((float)7 * display_ambient_light_brightness * + led_strip_green_calibration), + b = (uint8_t)((float)7 * display_ambient_light_brightness * + led_strip_blue_calibration); + for (uint16_t global_index = offset * 3; global_index < global_end; + global_index += 3) { + led_strip_pixels[global_index + 0] = g; + led_strip_pixels[global_index + 1] = r; + led_strip_pixels[global_index + 2] = b; + } + } +} \ No newline at end of file diff --git a/main/main.c b/main/main.c index 5c5af00..261e221 100644 --- a/main/main.c +++ b/main/main.c @@ -12,10 +12,11 @@ #include "sdkconfig.h" #include "service_discovery.c" #include "temperature.c" +#include "udp_server.c" #include "ui_input.c" #include "wifi.c" -static const char *TAG = "DisplayAmbientLight"; +static const char *APP_TAG = "DisplayAmbientLight"; void app_main(void) { app_nvs_init(); @@ -28,28 +29,29 @@ void app_main(void) { init_display(); display_print8_str(0, 0, "Ambient Light"); - ci_03t_init(); - apds_9960_init(); - apds_9960_auto_fetch(); - auto_fetch_temperature(); - pca9555_init(); - ui_input_init(); - xTaskCreate(mqtt_publish_ui_input, "mqtt_publish_ui_input", 2048, NULL, 10, - NULL); - vTaskDelay(pdMS_TO_TICKS(10)); + // ci_03t_init(); + // apds_9960_init(); + // apds_9960_auto_fetch(); + // auto_fetch_temperature(); + // pca9555_init(); + // ui_input_init(); + // xTaskCreate(mqtt_publish_ui_input, "mqtt_publish_ui_input", 2048, NULL, 10, + // NULL); + // vTaskDelay(pdMS_TO_TICKS(10)); light_play(light_mode_connection_wifi); if (connect_wifi()) { light_play(light_mode_idle); } + udp_server_init(); service_discovery_init(); vTaskDelay(pdMS_TO_TICKS(1000)); mqtt_app_start(); - if (waiting_for_mqtt_connected()) { - light_play(light_mode_mqtt_connected); - } - if (waiting_for_desktop_online()) { - light_play(light_mode_desktop_online); - } + // if (waiting_for_mqtt_connected()) { + // light_play(light_mode_mqtt_connected); + // } + // if (waiting_for_desktop_online()) { + // light_play(light_mode_desktop_online); + // } while (waiting_and_get_colors()) { light_play_colors(NUMBER_OF_LEDS * 3, mqtt_colors_buffer); } diff --git a/main/udp_server.c b/main/udp_server.c new file mode 100644 index 0000000..e31d6fe --- /dev/null +++ b/main/udp_server.c @@ -0,0 +1,126 @@ +#include +#include +#include + +#include "esp_err.h" +#include "esp_event.h" +#include "esp_log.h" +#include "esp_netif.h" +#include "esp_system.h" +#include "esp_wifi.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "lwip/err.h" +#include "lwip/sockets.h" +#include "lwip/sys.h" +#include "nvs_flash.h" + +#define UDP_PORT 23042 + +static const char *UDP_SERVER_TAG = "UDP_SERVER"; + +static void udp_server_task(void *pvParameters) { + char rx_buffer[1024]; + char addr_str[128]; + int addr_family = (int)pvParameters; + int ip_protocol = 0; + struct sockaddr_in6 dest_addr; + + while (1) { + if (addr_family == AF_INET) { + struct sockaddr_in *dest_addr_ip4 = (struct sockaddr_in *)&dest_addr; + dest_addr_ip4->sin_addr.s_addr = htonl(INADDR_ANY); + dest_addr_ip4->sin_family = AF_INET; + dest_addr_ip4->sin_port = htons(UDP_PORT); + ip_protocol = IPPROTO_IP; + } + + int sock = socket(addr_family, SOCK_DGRAM, ip_protocol); + if (sock < 0) { + ESP_LOGE(UDP_SERVER_TAG, "Unable to create socket: errno %d. sock: %d", + errno, sock); + break; + } + ESP_LOGI(UDP_SERVER_TAG, "Socket created"); + + // Set timeout + struct timeval timeout; + timeout.tv_sec = 10; + timeout.tv_usec = 0; + setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof timeout); + + int err = bind(sock, (struct sockaddr *)&dest_addr, sizeof(dest_addr)); + if (err < 0) { + ESP_LOGE(UDP_SERVER_TAG, "Socket unable to bind: errno %d. sock: %d", + errno, sock); + } + ESP_LOGI(UDP_SERVER_TAG, "Socket bound, port %d", UDP_PORT); + + struct sockaddr_storage source_addr; // Large enough for both IPv4 or IPv6 + socklen_t socklen = sizeof(source_addr); + + while (1) { + // ESP_LOGI(UDP_SERVER_TAG, "Waiting for data"); + int len = recvfrom(sock, rx_buffer, sizeof(rx_buffer) - 1, 0, + (struct sockaddr *)&source_addr, &socklen); + // Error occurred during receiving + if (len < 0) { + if (errno == EAGAIN) { + continue; + } + ESP_LOGE(UDP_SERVER_TAG, "recvfrom failed: errno %d. len: %d", errno, + len); + } + // Data received + else { + // Get the sender's ip address as string + if (source_addr.ss_family == PF_INET) { + inet_ntoa_r(((struct sockaddr_in *)&source_addr)->sin_addr, addr_str, + sizeof(addr_str) - 1); + + rx_buffer[len] = 0; // Null-terminate whatever we received and treat + // like a string... + + switch (rx_buffer[0]) { + case 2: + set_display_ambient_light_colors( + ((uint16_t)rx_buffer[1] << 8 | (uint16_t)rx_buffer[2]), + (uint8_t *)&(rx_buffer[3]), len - 3); + break; + + default: + + ESP_LOGI(UDP_SERVER_TAG, "%s", rx_buffer); + break; + } + + int err = + sendto(sock, rx_buffer, len, 0, (struct sockaddr *)&source_addr, + sizeof(source_addr)); + if (err < 0) { + ESP_LOGI(UDP_SERVER_TAG, "Received %d bytes from %s:", len, + addr_str); + ESP_LOGE(UDP_SERVER_TAG, + "Error occurred during sending: errno %d. sock: %d", errno, + sock); + break; + } + } + } + + if (sock != -1 && len < 0) { + ESP_LOGE(UDP_SERVER_TAG, "Shutting down socket and restarting..."); + shutdown(sock, 0); + close(sock); + break; + } + } + } + vTaskDelete(NULL); +} + +void udp_server_init(void) { + ESP_ERROR_CHECK(nvs_flash_init()); + ESP_ERROR_CHECK(esp_netif_init()); + xTaskCreate(udp_server_task, "udp_server", 4096, (void *)AF_INET, 5, NULL); +} \ No newline at end of file