diff options
-rw-r--r-- | include/sockbuf.h | 39 | ||||
-rw-r--r-- | include/ws2812b_writer.h | 2 | ||||
-rw-r--r-- | main/CMakeLists.txt | 7 | ||||
-rw-r--r-- | main/sockbuf.c | 43 | ||||
-rw-r--r-- | main/tcp_server.c | 230 |
5 files changed, 319 insertions, 2 deletions
diff --git a/include/sockbuf.h b/include/sockbuf.h new file mode 100644 index 0000000..664e134 --- /dev/null +++ b/include/sockbuf.h @@ -0,0 +1,39 @@ +#pragma once +#ifndef SOCKBUF_H_ +#define SOCKBUF_H_ + +#include <inttypes.h> + +#define SOCKBUF_BUFLEN 128 +#define SOCKBUF_CLOSED 1 + +typedef struct { + uint8_t buf[SOCKBUF_BUFLEN]; + + uint8_t next; + uint8_t last; + + int socket; + uint8_t flags; +} sockbuf_t; + +/* Initialize a sockbuf from the provided file descriptor. */ +sockbuf_t* init_sockbuf(sockbuf_t* sockbuf, int socket); + +/* Writes a null-terminated string to the socket. */ +void sockbuf_write(sockbuf_t* sockbuf, const char* value); + +/* + * Return the next character of the sockbuf or -1 if EOF was reached. + * + * This does not advance the pointer. + */ +int peek_char(sockbuf_t* sockbuf); + +/* + * Return and consume the next character of the sockbuf or -1 if EOF was + * reached. + */ +int get_char(sockbuf_t* sockbuf); + +#endif /* SOCKBUF_H_ */ diff --git a/include/ws2812b_writer.h b/include/ws2812b_writer.h index 2252230..9da9345 100644 --- a/include/ws2812b_writer.h +++ b/include/ws2812b_writer.h @@ -11,7 +11,7 @@ typedef struct { struct { uint32_t time; - int32_t timetick; + int timetick; uint8_t brightness; uint8_t off; uint8_t n_snow; diff --git a/main/CMakeLists.txt b/main/CMakeLists.txt index 60434ca..9ecb402 100644 --- a/main/CMakeLists.txt +++ b/main/CMakeLists.txt @@ -1,2 +1,7 @@ -idf_component_register(SRCS "main.c" "station.c" "ws2812b_writer.c" "tcp_server.c" +idf_component_register(SRCS + "main.c" + "station.c" + "ws2812b_writer.c" + "tcp_server.c" + "sockbuf.c" INCLUDE_DIRS "../include") diff --git a/main/sockbuf.c b/main/sockbuf.c new file mode 100644 index 0000000..0fede63 --- /dev/null +++ b/main/sockbuf.c @@ -0,0 +1,43 @@ +#include "sockbuf.h" + +#include <unistd.h> +#include <string.h> + +void sockbuf_write(sockbuf_t* sockbuf, const char* value) +{ + write(sockbuf->socket, value, strlen(value)); +} + +sockbuf_t* init_sockbuf(sockbuf_t* sockbuf, int socket) +{ + memset(sockbuf, 0, sizeof(sockbuf_t)); + sockbuf->socket = socket; + + return sockbuf; +} + +int peek_char(sockbuf_t* sockbuf) +{ + if (sockbuf->next == sockbuf->last) { + sockbuf->next = 0; + int size = read(sockbuf->socket, sockbuf->buf, sizeof(sockbuf->buf)); + sockbuf->last = (uint8_t) size; + + if (size <= 0) { + return size - 1; + } + } + + return sockbuf->buf[sockbuf->next]; +} + +int get_char(sockbuf_t* sockbuf) +{ + int ret = peek_char(sockbuf); + + if (ret >= 0) { + sockbuf->next ++; + } + + return ret; +} diff --git a/main/tcp_server.c b/main/tcp_server.c index f50dc21..7bfaa61 100644 --- a/main/tcp_server.c +++ b/main/tcp_server.c @@ -1,8 +1,226 @@ +#include <ctype.h> + #include "tcp_server.h" +#include "sockbuf.h" #include "lwip/sockets.h" #include "station.h" +static int strcmp_(const char* s1, const char* s2) +{ + if (!s1) { + return !s2; + } + + if (!s2) { + return !s1; + } + + return strcmp(s1, s2); +} + +static char* read_token(sockbuf_t* sockbuf, char* into, size_t sz) +{ + int cur = 0; + + int ch = get_char(sockbuf); + + while (ch >= 0 && isspace(ch)) { + ch = get_char(sockbuf); + } + + while (ch >= 0 && !isspace(ch)) { + if (sz > 1) { + into[cur++] = (char) ch; + sz --; + } + ch = get_char(sockbuf); + } + + if (ch < 0) { + return NULL; + } + + if (sz >= 1) { + into[cur] = 0; + } + return into; +} + +static void handle_int_option( + const char* attr, + sockbuf_t* sockbuf, + int* ptr) +{ + char op_[8]; + char buf_[32]; + + char* op = read_token(sockbuf, op_, sizeof(op_)); + char* value = read_token(sockbuf, buf_, sizeof(buf_)); + + int curval = *ptr; + int ivalue = atoi(value); + if (!strcmp_(op, "+=")) { + curval += ivalue; + } else if (!strcmp_(op, "-=")) { + curval -= ivalue; + } else if (!strcmp_(op, "=")) { + curval = ivalue; + } else { + sockbuf_write(sockbuf, "Unknown operation: '"); + sockbuf_write(sockbuf, op); + sockbuf_write(sockbuf, "'\n"); + return; + } + + snprintf(buf_, sizeof(buf_), "%s = %d\n", attr, curval); + *ptr = curval; + sockbuf_write(sockbuf, buf_); +} + +static void handle_uint8_option( + const char* attr, + sockbuf_t* sockbuf, + uint8_t* ptr) +{ + int tmp = *ptr; + handle_int_option(attr, sockbuf, &tmp); + *ptr = tmp; +} + +static void handle_uint32_option( + const char* attr, + sockbuf_t* sockbuf, + uint32_t* ptr) +{ + int tmp = *ptr; + handle_int_option(attr, sockbuf, &tmp); + *ptr = tmp; +} + +static void handle_bool_option( + const char* attr, + sockbuf_t* sockbuf, + bool* ptr) +{ + char buf_[32]; + char* op = read_token(sockbuf, buf_, sizeof(buf_)); + + bool curval = *ptr; + if (!strcmp(op, "on")) { + curval = 1; + } else if (!strcmp(op, "off")) { + curval = 0; + } else if (!strcmp(op, "toggle")) { + curval = !curval; + } else { + sockbuf_write(sockbuf, "Invalid value: '"); + sockbuf_write(sockbuf, op); + sockbuf_write(sockbuf, "'\n"); + return; + } + + *ptr = curval; + snprintf(buf_, sizeof(buf_), "%s = %s\n", attr, curval ? "on" : "off"); + sockbuf_write(sockbuf, buf_); +} + +#define HANDLE_UINT8_OPTION(attr) \ + else if (!strcmp_(key, #attr)) { \ + handle_uint8_option(#attr, sockbuf, &ws_params->state. attr); \ + } + +#define HANDLE_INT_OPTION(attr) \ + else if (!strcmp_(key, #attr)) { \ + handle_int_option(#attr, sockbuf, &ws_params->state. attr); \ + } + +#define HANDLE_UINT32_OPTION(attr) \ + else if (!strcmp_(key, #attr)) { \ + handle_uint32_option(#attr, sockbuf, &ws_params->state. attr); \ + } + +#define HANDLE_BOOL_OPTION(attr) \ + else if (!strcmp_(key, #attr)) { \ + handle_bool_option(#attr, sockbuf, &ws_params->state. attr); \ + } + +static void handle_set_cmd( + sockbuf_t* sockbuf, ws_params_t* ws_params, const char* key) +{ + if (false) {} + + HANDLE_UINT8_OPTION(brightness) + HANDLE_UINT8_OPTION(n_snow) + HANDLE_UINT8_OPTION(n_red) + + HANDLE_INT_OPTION(timetick) + HANDLE_UINT32_OPTION(time) + + HANDLE_BOOL_OPTION(sleep) + HANDLE_BOOL_OPTION(power) + HANDLE_BOOL_OPTION(cool) + + else { + sockbuf_write(sockbuf, "Unknown attribute: '"); + sockbuf_write(sockbuf, key); + sockbuf_write(sockbuf, "'\n"); + } +} + +#define PRINT_INT(attr) \ + snprintf(buf, sizeof(buf), #attr ": %d\n", (int) ws_params->state. attr); \ + sockbuf_write(sockbuf, buf) +#define PRINT_BOOL(attr) \ + snprintf(buf, sizeof(buf), #attr ": %s\n", \ + ws_params->state. attr ? "on" : "off"); \ + sockbuf_write(sockbuf, buf) +static void handle_print_cmd(sockbuf_t* sockbuf, ws_params_t* ws_params) +{ + char buf[128]; + + PRINT_INT(time); + PRINT_INT(timetick); + PRINT_INT(brightness); + PRINT_INT(off); + PRINT_INT(n_snow); + PRINT_INT(n_red); + + PRINT_BOOL(sleep); + PRINT_BOOL(power); + PRINT_BOOL(cool); +} + +static void run_sockbuf(sockbuf_t* sockbuf, ws_params_t* ws_params) +{ + char buf[128]; + + while (true) { + char* cmd = read_token(sockbuf, buf, sizeof(buf)); + + if (!cmd) { + break; + } + + if (!strcmp_(cmd, "set")) { + char* key = read_token(sockbuf, buf, sizeof(buf)); + + if (key) { + handle_set_cmd(sockbuf, ws_params, key); + } + } else if (!strcmp_(cmd, "print")) { + handle_print_cmd(sockbuf, ws_params); + } else if (!strcmp_(cmd, "end")) { + close(sockbuf->socket); + return; + } else { + sockbuf_write(sockbuf, "Unknown command: '"); + sockbuf_write(sockbuf, cmd); + sockbuf_write(sockbuf, "'\n"); + } + } +} + portTASK_FUNCTION(tcp_server, params) { ws_params_t* ws_params = (ws_params_t*) params; @@ -32,6 +250,10 @@ portTASK_FUNCTION(tcp_server, params) int sock = accept(s, (struct sockaddr*)&client_addr, &size); printf("Accepted connection\n"); + sockbuf_t sockbuf; + init_sockbuf(&sockbuf, sock); + run_sockbuf(&sockbuf, ws_params); + ssize_t len; char buf[128]; @@ -40,6 +262,14 @@ portTASK_FUNCTION(tcp_server, params) buf[len] = 0; printf("Read %s\n", buf); + if (!strcmp_(buf, "off\n")) { + ws_params->state.power = 0; + } + + if (!strcmp_(buf, "on\n")) { + ws_params->state.power = 1; + } + for (int i = 0; i < len; ++ i) { switch (buf[i]) { case '+': |