feat: 使用 UDP 接收颜色。

This commit is contained in:
Ivan Li 2023-04-28 00:26:41 +08:00
parent 7bff8e2c17
commit 101103de03
4 changed files with 257 additions and 62 deletions

17
docs/udp.md Normal file
View File

@ -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$ 真彩色 |

View File

@ -126,6 +126,14 @@ void led_strip_set_color_calibration(float red, float green, float blue) {
nvs_close(local_nvs_handle); 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 * @brief Simple helper function, converting HSV color space to RGB color
* space * space
@ -224,8 +232,6 @@ void light_for_init() {
ESP_LOGI(LIGHT_TAG, "light_for_init"); ESP_LOGI(LIGHT_TAG, "light_for_init");
memset(led_strip_pixels, 0, sizeof(led_strip_pixels)); 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; nvs_handle local_nvs_handle;
esp_err_t err = nvs_open("storage", NVS_READWRITE, &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; uint8_t init_r, init_g, init_b;
do { 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_r = (uint8_t)(r_f * (float)i);
init_g = (uint8_t)(g_f * (float)i); init_g = (uint8_t)(g_f * (float)i);
init_b = (uint8_t)(b_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; 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(20));
} }
vTaskDelay(pdMS_TO_TICKS(100)); vTaskDelay(pdMS_TO_TICKS(100));
@ -312,8 +316,6 @@ void light_for_connecting_wifi() {
led_strip_pixels[5] = 0; led_strip_pixels[5] = 0;
} }
tick_tock = !tick_tock; 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)); vTaskDelay(pdMS_TO_TICKS(200));
} while (light_mode == light_mode_connection_wifi); } while (light_mode == light_mode_connection_wifi);
} }
@ -345,8 +347,6 @@ void light_for_idle() {
blue * display_ambient_light_brightness * led_strip_blue_calibration; blue * display_ambient_light_brightness * led_strip_blue_calibration;
} }
// update_desktop_connection_state(); // 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)); vTaskDelay(pdMS_TO_TICKS(10));
} }
} }
@ -404,49 +404,49 @@ void light_init_strip() {
xTaskCreate(light_strip_running_task, "LIGHT_STRIP_RUNNING_TASK", 4096, NULL, xTaskCreate(light_strip_running_task, "LIGHT_STRIP_RUNNING_TASK", 4096, NULL,
1, 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) { 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; // for (uint16_t led_index = 0, buffer_cursor = 0;
led_index < STRIP_LED_NUMBER && buffer_cursor < len; // led_index < STRIP_LED_NUMBER && buffer_cursor < len;
led_index++, buffer_cursor += 3) { // led_index++, buffer_cursor += 3) {
uint8_t r = (uint8_t)((float)buffer[buffer_cursor] * // uint8_t r = (uint8_t)((float)buffer[buffer_cursor] *
display_ambient_light_brightness * // display_ambient_light_brightness *
led_strip_red_calibration), // led_strip_red_calibration),
g = (uint8_t)((float)buffer[buffer_cursor + 1] * // g = (uint8_t)((float)buffer[buffer_cursor + 1] *
display_ambient_light_brightness * // display_ambient_light_brightness *
led_strip_green_calibration), // led_strip_green_calibration),
b = (uint8_t)((float)buffer[buffer_cursor + 2] * // b = (uint8_t)((float)buffer[buffer_cursor + 2] *
display_ambient_light_brightness * // display_ambient_light_brightness *
led_strip_blue_calibration); // led_strip_blue_calibration);
if (r <= 7 && g <= 7 && b <= 7) { // if (r <= 7 && g <= 7 && b <= 7) {
black_count++; // black_count++;
} // }
led_strip_pixels[led_index * 3 + 0] = g; // led_strip_pixels[led_index * 3 + 0] = g;
led_strip_pixels[led_index * 3 + 1] = r; // led_strip_pixels[led_index * 3 + 1] = r;
led_strip_pixels[led_index * 3 + 2] = b; // led_strip_pixels[led_index * 3 + 2] = b;
} // }
if (black_count > STRIP_LED_NUMBER / 5 * 4) { // if (black_count > STRIP_LED_NUMBER / 5 * 4) {
uint8_t r = (uint8_t)((float)50 * display_ambient_light_brightness * // uint8_t r = (uint8_t)((float)50 * display_ambient_light_brightness *
led_strip_red_calibration), // led_strip_red_calibration),
g = (uint8_t)((float)40 * display_ambient_light_brightness * // g = (uint8_t)((float)40 * display_ambient_light_brightness *
led_strip_green_calibration), // led_strip_green_calibration),
b = (uint8_t)((float)20 * display_ambient_light_brightness * // b = (uint8_t)((float)20 * display_ambient_light_brightness *
led_strip_blue_calibration); // led_strip_blue_calibration);
for (uint16_t led_index = 0; led_index < STRIP_LED_NUMBER; led_index++) { // 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 + 0] = g;
led_strip_pixels[led_index * 3 + 1] = r; // led_strip_pixels[led_index * 3 + 1] = r;
led_strip_pixels[led_index * 3 + 2] = b; // 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));
vTaskDelay(pdMS_TO_TICKS(10)); vTaskDelay(pdMS_TO_TICKS(10));
} }
@ -454,3 +454,53 @@ void light_play(light_mode_t mode) {
ESP_LOGI(LIGHT_TAG, "light_play: %d", mode); ESP_LOGI(LIGHT_TAG, "light_play: %d", mode);
light_mode = 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;
}
}
}

View File

@ -12,10 +12,11 @@
#include "sdkconfig.h" #include "sdkconfig.h"
#include "service_discovery.c" #include "service_discovery.c"
#include "temperature.c" #include "temperature.c"
#include "udp_server.c"
#include "ui_input.c" #include "ui_input.c"
#include "wifi.c" #include "wifi.c"
static const char *TAG = "DisplayAmbientLight"; static const char *APP_TAG = "DisplayAmbientLight";
void app_main(void) { void app_main(void) {
app_nvs_init(); app_nvs_init();
@ -28,28 +29,29 @@ void app_main(void) {
init_display(); init_display();
display_print8_str(0, 0, "Ambient Light"); display_print8_str(0, 0, "Ambient Light");
ci_03t_init(); // ci_03t_init();
apds_9960_init(); // apds_9960_init();
apds_9960_auto_fetch(); // apds_9960_auto_fetch();
auto_fetch_temperature(); // auto_fetch_temperature();
pca9555_init(); // pca9555_init();
ui_input_init(); // ui_input_init();
xTaskCreate(mqtt_publish_ui_input, "mqtt_publish_ui_input", 2048, NULL, 10, // xTaskCreate(mqtt_publish_ui_input, "mqtt_publish_ui_input", 2048, NULL, 10,
NULL); // NULL);
vTaskDelay(pdMS_TO_TICKS(10)); // vTaskDelay(pdMS_TO_TICKS(10));
light_play(light_mode_connection_wifi); light_play(light_mode_connection_wifi);
if (connect_wifi()) { if (connect_wifi()) {
light_play(light_mode_idle); light_play(light_mode_idle);
} }
udp_server_init();
service_discovery_init(); service_discovery_init();
vTaskDelay(pdMS_TO_TICKS(1000)); vTaskDelay(pdMS_TO_TICKS(1000));
mqtt_app_start(); mqtt_app_start();
if (waiting_for_mqtt_connected()) { // if (waiting_for_mqtt_connected()) {
light_play(light_mode_mqtt_connected); // light_play(light_mode_mqtt_connected);
} // }
if (waiting_for_desktop_online()) { // if (waiting_for_desktop_online()) {
light_play(light_mode_desktop_online); // light_play(light_mode_desktop_online);
} // }
while (waiting_and_get_colors()) { while (waiting_and_get_colors()) {
light_play_colors(NUMBER_OF_LEDS * 3, mqtt_colors_buffer); light_play_colors(NUMBER_OF_LEDS * 3, mqtt_colors_buffer);
} }

126
main/udp_server.c Normal file
View File

@ -0,0 +1,126 @@
#include <lwip/netdb.h>
#include <string.h>
#include <sys/param.h>
#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);
}