diff --git a/firmware/lux.cpp b/firmware/lux.cpp index 8b775c4..19b89b0 100644 --- a/firmware/lux.cpp +++ b/firmware/lux.cpp @@ -3,10 +3,18 @@ // #include "lux.h" +#include "log.h" #include #include #include +#include + +extern "C" { +#include +#include +#include +} #include @@ -20,13 +28,169 @@ extern "C" void signal_led(bool state) { gpio_write(signal_led_pin, !state); } +enum class parse_status { + ERROR, + SET_PIXEL_RGB, + SET_PIXEL_RGBW, + GET_PIXEL, + GET_DIMENSIONS, + GET_HELP +}; + + +parse_status parse_pixelflut_message(const char *msg, size_t len, + uint16_t &x, uint16_t &y, uint8_t &r, uint8_t &g, uint8_t &b, uint8_t &w) { + if(len < 4) + return parse_status::ERROR; + + if(msg[0] == 'P' && msg[1] == 'X' && msg[2] == ' ') { + size_t i = 3; + size_t j = 0; + char buf[5]; + while (i < len && msg[i] != ' ' && j < 4) { + buf[j++] = msg[i++]; + } + buf[j] = 0; + x = atoi(buf); + while(i < len && msg[i] == ' ') + i++; + j = 0; + while (i < len && msg[i] != ' ' && j < 4) { + buf[j++] = msg[i++]; + } + buf[j] = 0; + y = atoi(buf); + while(i < len && msg[i] == ' ') + i++; + if(i >= len) + return parse_status::GET_PIXEL; + j = 0; + while (i < len && msg[i] != ' ' && j < 4) { + buf[j++] = msg[i++]; + } + buf[j] = 0; + r = atoi(buf); + while(i < len && msg[i] == ' ') + i++; + j = 0; + while (i < len && msg[i] != ' ' && j < 4) { + buf[j++] = msg[i++]; + } + buf[j] = 0; + g = atoi(buf); + while(i < len && msg[i] == ' ') + i++; + j = 0; + while (i < len && msg[i] != ' ' && j < 4) { + buf[j++] = msg[i++]; + } + buf[j] = 0; + b = atoi(buf); + while(i < len && msg[i] == ' ') + i++; + if(i >= len) + return parse_status::SET_PIXEL_RGB; + j = 0; + while (i < len && msg[i] != ' ' && j < 4) { + buf[j++] = msg[i++]; + } + buf[j] = 0; + w = atoi(buf); + return parse_status::SET_PIXEL_RGBW; + } else if(msg[0] == 'S' && msg[1] == 'I' && msg[2] == 'Z' && msg[3] == 'E') { + return parse_status::GET_DIMENSIONS; + } else if(msg[0] == 'H' && msg[1] == 'E' && msg[2] == 'L' && msg[3] == 'P') { + return parse_status::GET_HELP; + } else { + return parse_status::ERROR; + } + +} + + +[[noreturn]] static void pixelflut_task(void *pvParameters) { + //char *wifi_ap_ip_addr = nullptr; + //sysparam_get_string("wifi_ap_ip_addr", &wifi_ap_ip_addr); + //if(!wifi_ap_ip_addr) { + // syslog("dns: no ip address\n"); + // vTaskDelete(nullptr); + //} + //ip4_addr_t server_addr; + //server_addr.addr = ipaddr_addr(wifi_ap_ip_addr); + +#if LWIP_IPV6 + int fd = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP); + sockaddr_in6 serv_addr; + memset(&serv_addr, '0', sizeof(serv_addr)); + serv_addr.sin6_family = AF_INET6; + serv_addr.sin6_port = htons(53); + serv_addr.sin6_flowinfo = 0; + serv_addr.sin6_addr = in6addr_any; + serv_addr.sin6_scope_id = IP6_NO_ZONE; +#else + int fd = lwip_socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + sockaddr_in serv_addr{}; + serv_addr.sin_family = AF_INET; + serv_addr.sin_addr.s_addr = lwip_htonl(INADDR_ANY); + serv_addr.sin_port = lwip_htons(2342); +#endif + lwip_bind(fd, (sockaddr *) &serv_addr, sizeof(serv_addr)); + + printf("pixelflut: listening on port 2342\n"); + + const ifreq ifreq0 = {"en0"}; + const ifreq ifreq1 = {"en1"}; + lwip_setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, + sdk_wifi_get_opmode() == STATIONAP_MODE ? &ifreq1 : &ifreq0, + sizeof(ifreq0)); + + int width = 23; + int height = 42; + + char buffer[96] = {0}; + sockaddr_storage src_addr{}; + for (;;) { + socklen_t src_addr_len = sizeof(src_addr); + ssize_t count = lwip_recvfrom(fd, buffer, sizeof(buffer), 0, (sockaddr *) &src_addr, &src_addr_len); + + + uint16_t x, y; + uint8_t r, g, b, w; + parse_status status = parse_pixelflut_message((char *) buffer, count, x, y, r, g, b, w); + if(status == parse_status::SET_PIXEL_RGB) { + printf("set pixel %d %d to %d %d %d\n", x, y, r, g, b); + } else if(status == parse_status::SET_PIXEL_RGBW) { + printf("set pixel %d %d to %d %d %d %d\n", x, y, r, g, b, w); + } else if(status == parse_status::GET_PIXEL) { + uint32_t reply_len = snprintf((char *) buffer, 96, "PX %d %d %d %d %d %d", x, y, r, g, b, w); + lwip_sendto(fd, buffer, reply_len, 0, (sockaddr *) &src_addr, src_addr_len); + } else if(status == parse_status::GET_DIMENSIONS) { + uint32_t reply_len = snprintf((char *) buffer, 96, "SIZE %d %d", width, height); + lwip_sendto(fd, buffer, reply_len, 0, (sockaddr *) &src_addr, src_addr_len); + } else if(status == parse_status::GET_HELP) { + uint32_t reply_len = snprintf((char *) buffer, 96, "HELP"); + lwip_sendto(fd, buffer, reply_len, 0, (sockaddr *) &src_addr, src_addr_len); + } else { + uint32_t reply_len = snprintf((char *) buffer, 96, "ERR"); + lwip_sendto(fd, buffer, reply_len, 0, (sockaddr *) &src_addr, src_addr_len); + printf("error parsing message [%d bytes]: \n", count); + for (int i = 0; i < count; i++) { + printf("%c", buffer[i]); + } + printf("\n"); + } + } +} + extern "C" void lux_task(void *pvParameters) { gpio_enable(signal_led_pin, GPIO_OUTPUT); gpio_enable(cs0, GPIO_OUTPUT); gpio_enable(gpio4, GPIO_OUTPUT); gpio_enable(gpio5, GPIO_OUTPUT); - spi_init(1, SPI_MODE0, SPI_FREQ_DIV_1M, 1, SPI_BIG_ENDIAN, 1); + spi_init(1, SPI_MODE0, SPI_FREQ_DIV_1M, true, SPI_BIG_ENDIAN, true); + + xTaskCreate(&pixelflut_task, "pixelflut_task", 512, nullptr, 2, nullptr); vTaskDelete(nullptr); } \ No newline at end of file diff --git a/firmware/web.cpp b/firmware/web.cpp index ed55e2d..b927ad8 100644 --- a/firmware/web.cpp +++ b/firmware/web.cpp @@ -65,6 +65,14 @@ void websocket_task(void *pvParameter) { //Global Info if(has_changed.global) { + + //while (1) { + // vTaskDelay(10000 / portTICK_PERIOD_MS); + // time_t ts = time(NULL); + // long long t = ts; + // printf("TIME: %ld %s", (long int) t, ctime(&ts)); + //} + timeval tv{}; gettimeofday(&tv, nullptr); size_t uptime = xTaskGetTickCount() * portTICK_PERIOD_MS / 1000;