Browse Source

add Bitty HTTP server and some other tweaks

Thomas Buck 1 year ago
parent
commit
8210ddce33
31 changed files with 871 additions and 71 deletions
  1. 3
    0
      .gitmodules
  2. 1
    0
      BittyHTTP
  3. 19
    1
      CMakeLists.txt
  4. 47
    0
      conf/Options.h
  5. 0
    0
      conf/ffconf.h
  6. 0
    0
      conf/lwipopts.h
  7. 0
    0
      conf/memmap_custom.ld
  8. 0
    0
      conf/tusb_config.h
  9. 1
    1
      include/console.h
  10. 26
    0
      include/http.h
  11. 1
    1
      include/log.h
  12. 4
    0
      include/main.h
  13. 10
    8
      include/ring.h
  14. 1
    1
      include/serial.h
  15. 1
    1
      include/usb_cdc.h
  16. 9
    0
      include/venty.h
  17. 1
    0
      pack_data.sh
  18. 1
    1
      src/console.c
  19. 43
    0
      src/http.c
  20. 101
    0
      src/http_files.c
  21. 392
    0
      src/http_socket.c
  22. 5
    5
      src/log.c
  23. 25
    2
      src/main.c
  24. 24
    14
      src/ring.c
  25. 12
    7
      src/serial.c
  26. 3
    2
      src/state_settings.c
  27. 1
    1
      src/state_string.c
  28. 51
    14
      src/state_venty.c
  29. 1
    1
      src/usb_cdc.c
  30. 87
    8
      src/venty.c
  31. 1
    3
      src/wifi.c

+ 3
- 0
.gitmodules View File

@@ -13,3 +13,6 @@
13 13
 [submodule "picowota"]
14 14
 	path = picowota
15 15
 	url = https://github.com/usedbytes/picowota
16
+[submodule "BittyHTTP"]
17
+	path = BittyHTTP
18
+	url = https://github.com/TheBeef/BittyHTTP

+ 1
- 0
BittyHTTP

@@ -0,0 +1 @@
1
+Subproject commit 0c531a062fe44ce9ee372361e14906924737ced1

+ 19
- 1
CMakeLists.txt View File

@@ -24,6 +24,11 @@ execute_process(COMMAND make
24 24
     WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/mcufont/fonts
25 25
 )
26 26
 
27
+# remove Options.h from BittyHTTP so we can use our own (TODO ugly)
28
+execute_process(COMMAND rm Options.h
29
+    WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/BittyHTTP/src
30
+)
31
+
27 32
 # initialize pico-sdk from submodule
28 33
 include(pico-sdk/pico_sdk_init.cmake)
29 34
 
@@ -101,6 +106,9 @@ target_sources(gadget PUBLIC
101 106
     src/state_wifi.c
102 107
     src/state_wifi_edit.c
103 108
     src/state_string.c
109
+    src/http.c
110
+    src/http_socket.c
111
+    src/http_files.c
104 112
 
105 113
     ${CMAKE_CURRENT_BINARY_DIR}/fatfs/ff.c
106 114
     ${CMAKE_CURRENT_BINARY_DIR}/fatfs/ffunicode.c
@@ -115,9 +123,12 @@ target_sources(gadget PUBLIC
115 123
     mcufont/decoder/mf_bwfont.c
116 124
     mcufont/decoder/mf_scaledfont.c
117 125
     mcufont/decoder/mf_wordwrap.c
126
+
127
+    BittyHTTP/src/WebServer.c
118 128
 )
119 129
 
120 130
 # external dependency include directories
131
+target_include_directories(gadget PUBLIC ${CMAKE_CURRENT_LIST_DIR}/conf)
121 132
 target_include_directories(gadget PUBLIC ${CMAKE_CURRENT_LIST_DIR}/include)
122 133
 target_include_directories(gadget PUBLIC ${CMAKE_CURRENT_BINARY_DIR}/fatfs)
123 134
 target_include_directories(gadget PUBLIC ${CMAKE_CURRENT_LIST_DIR}/st7789/src)
@@ -125,6 +136,7 @@ target_include_directories(gadget PUBLIC ${CMAKE_CURRENT_LIST_DIR}/st7789/interf
125 136
 target_include_directories(gadget PUBLIC ${CMAKE_CURRENT_LIST_DIR}/mcufont/decoder)
126 137
 target_include_directories(gadget PUBLIC ${CMAKE_CURRENT_LIST_DIR}/data)
127 138
 target_include_directories(gadget PUBLIC ${CMAKE_CURRENT_LIST_DIR}/build)
139
+target_include_directories(gadget PUBLIC ${CMAKE_CURRENT_LIST_DIR}/BittyHTTP/src)
128 140
 
129 141
 # compress source code and stuff we want to include
130 142
 add_custom_target(pack bash -c "./pack_data.sh"
@@ -148,6 +160,9 @@ set_source_files_properties(pico-sdk/lib/btstack/src/classic/avdtp_util.c PROPER
148 160
 set_source_files_properties(pico-sdk/lib/btstack/src/classic/goep_client.c PROPERTIES COMPILE_FLAGS -Wno-unused-parameter)
149 161
 set_source_files_properties(pico-sdk/lib/btstack/src/classic/goep_server.c PROPERTIES COMPILE_FLAGS -Wno-unused-parameter)
150 162
 
163
+# suppress warnings for BittyHTTP
164
+set_source_files_properties(BittyHTTP/src/WebServer.c PROPERTIES COMPILE_FLAGS "-Wno-sign-compare -Wno-unused-parameter -Wno-maybe-uninitialized")
165
+
151 166
 # pull in common dependencies
152 167
 target_link_libraries(gadget
153 168
     pico_stdlib
@@ -166,7 +181,7 @@ target_link_libraries(gadget
166 181
     picowota_reboot
167 182
 )
168 183
 
169
-pico_set_linker_script(gadget ${CMAKE_CURRENT_SOURCE_DIR}/src/memmap_custom.ld)
184
+pico_set_linker_script(gadget ${CMAKE_CURRENT_SOURCE_DIR}/conf/memmap_custom.ld)
170 185
 
171 186
 # fix for Errata RP2040-E5 (the fix requires use of GPIO 15)
172 187
 target_compile_definitions(gadget PUBLIC PICO_RP2040_USB_DEVICE_ENUMERATION_FIX=1)
@@ -175,10 +190,13 @@ set(PICOWOTA_WIFI_SSID "WIFI_SSID_HERE")
175 190
 set(PICOWOTA_WIFI_PASS "WIFI_PASS_HERE")
176 191
 set(PICOWOTA_WIFI_AP 0)
177 192
 
193
+# TODO set DOCVER to hash of static http files?
194
+
178 195
 target_compile_definitions(gadget PUBLIC
179 196
     RUNNING_AS_CLIENT=1
180 197
     DEFAULT_WIFI_SSID="${PICOWOTA_WIFI_SSID}"
181 198
     DEFAULT_WIFI_PASS="${PICOWOTA_WIFI_PASS}"
199
+    DOCVER="1.0.0.0"
182 200
 )
183 201
 
184 202
 add_subdirectory(picowota)

+ 47
- 0
conf/Options.h View File

@@ -0,0 +1,47 @@
1
+/*
2
+ * Options.h
3
+ *
4
+ * Copyright (c) 2023 Thomas Buck (thomas@xythobuz.de)
5
+ * Copyright (c) 2019 Paul Hutchinson
6
+ *
7
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
8
+ * of this software and associated documentation files (the "Software"), to deal
9
+ * in the Software without restriction, including without limitation the rights
10
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
+ * copies of the Software, and to permit persons to whom the Software is
12
+ * furnished to do so, subject to the following conditions:
13
+ *
14
+ * The above copyright notice and this permission notice shall be included in all
15
+ * copies or substantial portions of the Software.
16
+ *
17
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23
+ * SOFTWARE.
24
+ */
25
+
26
+#ifndef __OPTIONS_H_
27
+#define __OPTIONS_H_
28
+
29
+#ifndef DOCVER
30
+#define DOCVER "1.0.0.0"
31
+#endif
32
+
33
+// The max number of connections we can handle at the same time
34
+// (this will include buffers needed for each connection)
35
+#define WS_OPT_MAX_CONNECTIONS              2
36
+
37
+// The memory block to use to store the cookies, get args, and post args
38
+#define WS_OPT_ARG_MEMORY_SIZE              100
39
+
40
+// How many seconds to wait after a connection stops sending to us before we hang up
41
+#define WS_SECONDS_UNTIL_CONNECTION_RELEASE 5
42
+
43
+// The max number of bytes we can handle a single header line can be (including the GET line).
44
+// This is normally in the order of 16K - 128K (we default to a lot less)
45
+#define WS_LINE_BUFFER_SIZE                 256
46
+
47
+#endif // __OPTIONS_H_

include/ffconf.h → conf/ffconf.h View File


include/lwipopts.h → conf/lwipopts.h View File


src/memmap_custom.ld → conf/memmap_custom.ld View File


include/tusb_config.h → conf/tusb_config.h View File


+ 1
- 1
include/console.h View File

@@ -21,6 +21,6 @@
21 21
 
22 22
 void cnsl_init(void);
23 23
 void cnsl_run(void);
24
-void cnsl_handle_input(const uint8_t *buf, size_t len);
24
+void cnsl_handle_input(const void *buf, size_t len);
25 25
 
26 26
 #endif // __CONSOLE_H__

+ 26
- 0
include/http.h View File

@@ -0,0 +1,26 @@
1
+/*
2
+ * http.h
3
+ *
4
+ * Copyright (c) 2023 Thomas Buck (thomas@xythobuz.de)
5
+ *
6
+ * This program is free software: you can redistribute it and/or modify
7
+ * it under the terms of the GNU General Public License as published by
8
+ * the Free Software Foundation, either version 3 of the License, or
9
+ * (at your option) any later version.
10
+ *
11
+ * This program is distributed in the hope that it will be useful,
12
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
+ * GNU General Public License for more details.
15
+ *
16
+ * See <http://www.gnu.org/licenses/>.
17
+ */
18
+
19
+#ifndef __HTTP_H__
20
+#define __HTTP_H__
21
+
22
+void http_init(void);
23
+void http_deinit(void);
24
+void http_run(void);
25
+
26
+#endif // __HTTP_H__

+ 1
- 1
include/log.h View File

@@ -43,6 +43,6 @@ void log_dump_to_usb(void);
43 43
 void log_dump_to_uart(void);
44 44
 void log_dump_to_disk(void);
45 45
 
46
-void debug_handle_input(const uint8_t *buff, size_t len);
46
+void debug_handle_input(const void *buff, size_t len);
47 47
 
48 48
 #endif // __LOG_H__

+ 4
- 0
include/main.h View File

@@ -21,4 +21,8 @@
21 21
 
22 22
 void main_loop_hw(void);
23 23
 
24
+void networking_init(void);
25
+void networking_deinit(void);
26
+void networking_run(void);
27
+
24 28
 #endif // __MAIN_H__

+ 10
- 8
include/ring.h View File

@@ -24,20 +24,22 @@
24 24
 #include <stdbool.h>
25 25
 
26 26
 struct ring_buffer {
27
-    uint8_t *buffer;
27
+    void *buffer;
28 28
     size_t size;
29
+    size_t el_len;
29 30
     size_t head, tail;
30 31
     bool full;
31 32
 };
32
-#define RB_INIT(b, s) { .buffer = b, .size = s, .head = 0, .tail = 0, .full = false }
33
+#define RB_INIT(b, s, e) { .buffer = b, .size = s, .el_len = e, .head = 0, .tail = 0, .full = false }
33 34
 
34
-void rb_add(struct ring_buffer *rb, const uint8_t *data, size_t length);
35
-#define rb_push(rb, v) rb_add(rb, &v, 1)
35
+void rb_add(struct ring_buffer *rb, const void *data, size_t length);
36
+#define rb_push(rb, v) rb_add(rb, v, 1)
36 37
 size_t rb_len(struct ring_buffer *rb);
37 38
 #define rb_space(rb) ((rb)->size - rb_len(rb))
38
-void rb_dump(struct ring_buffer *rb, void (*write)(const uint8_t *, size_t));
39
-void rb_move(struct ring_buffer *rb, void (*write)(const uint8_t *, size_t));
40
-uint8_t rb_peek(struct ring_buffer *rb);
41
-uint8_t rb_pop(struct ring_buffer *rb);
39
+void rb_dump(struct ring_buffer *rb, void (*write)(const void *, size_t));
40
+void rb_move(struct ring_buffer *rb, void (*write)(const void *, size_t));
41
+void rb_peek(struct ring_buffer *rb, void *buf);
42
+void rb_pop(struct ring_buffer *rb, void *buf);
43
+size_t rb_get(struct ring_buffer *rb, void *data, size_t length);
42 44
 
43 45
 #endif // __RING_BUFFER_H__

+ 1
- 1
include/serial.h View File

@@ -24,7 +24,7 @@
24 24
 #include <stdbool.h>
25 25
 
26 26
 void serial_init(void);
27
-void serial_write(const uint8_t *buf, size_t count);
27
+void serial_write(const void *buf, size_t count);
28 28
 void serial_set_reroute(bool reroute);
29 29
 void serial_run(void);
30 30
 

+ 1
- 1
include/usb_cdc.h View File

@@ -23,7 +23,7 @@
23 23
 #include <stdint.h>
24 24
 #include <stdbool.h>
25 25
 
26
-void usb_cdc_write(const uint8_t *buf, size_t count);
26
+void usb_cdc_write(const void *buf, size_t count);
27 27
 void usb_cdc_set_reroute(bool reroute);
28 28
 
29 29
 #endif // __USB_CDC_H__

+ 9
- 0
include/venty.h View File

@@ -32,12 +32,21 @@ int8_t venty_set_target_temp(uint16_t value);
32 32
 int8_t venty_set_heater_state(bool value);
33 33
 int8_t venty_set_eco_current(bool value);
34 34
 int8_t venty_set_eco_voltage(bool value);
35
+int8_t venty_set_vibration(bool value);
36
+
37
+// v from 1 to 9, returns < 0 on error
38
+int8_t venty_set_brightness(uint8_t value);
35 39
 
36 40
 // in percent, or < 0 on error
37 41
 int8_t venty_get_battery_state(void);
38 42
 
39 43
 // bool, or < 0 on error
44
+int8_t venty_get_heater_state(void);
40 45
 int8_t venty_get_eco_current(void);
41 46
 int8_t venty_get_eco_voltage(void);
47
+int8_t venty_get_vibration(void);
48
+
49
+// returns 1 to 9, or < 0 on error
50
+int8_t venty_get_brightness(void);
42 51
 
43 52
 #endif // __VENTY_H__

+ 1
- 0
pack_data.sh View File

@@ -28,6 +28,7 @@ cp README.md build/src
28 28
 cp CMakeLists.txt build/src
29 29
 cp .gitmodules build/src/gitmodules
30 30
 cp -r include build/src
31
+cp -r conf build/src
31 32
 cp -r src build/src
32 33
 
33 34
 cd build

+ 1
- 1
src/console.c View File

@@ -600,7 +600,7 @@ void cnsl_run(void) {
600 600
     }
601 601
 }
602 602
 
603
-void cnsl_handle_input(const uint8_t *buf, size_t len) {
603
+void cnsl_handle_input(const void *buf, size_t len) {
604 604
     if ((cnsl_buff_pos + len) > CNSL_BUFF_SIZE) {
605 605
         debug("error: console input buffer overflow! %lu > %u", cnsl_buff_pos + len, CNSL_BUFF_SIZE);
606 606
         cnsl_init();

+ 43
- 0
src/http.c View File

@@ -0,0 +1,43 @@
1
+/*
2
+ * http.c
3
+ *
4
+ * Copyright (c) 2023 Thomas Buck (thomas@xythobuz.de)
5
+ *
6
+ * This program is free software: you can redistribute it and/or modify
7
+ * it under the terms of the GNU General Public License as published by
8
+ * the Free Software Foundation, either version 3 of the License, or
9
+ * (at your option) any later version.
10
+ *
11
+ * This program is distributed in the hope that it will be useful,
12
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
+ * GNU General Public License for more details.
15
+ *
16
+ * See <http://www.gnu.org/licenses/>.
17
+ */
18
+
19
+#include "WebServer.h"
20
+
21
+#include "config.h"
22
+#include "log.h"
23
+#include "http.h"
24
+
25
+void http_init(void) {
26
+    SocketsCon_InitSocketConSystem();
27
+    WS_Init();
28
+
29
+    if (!WS_Start(80)) {
30
+        debug("failed to start web server");
31
+    } else {
32
+        debug("listening on :80");
33
+    }
34
+}
35
+
36
+void http_deinit(void) {
37
+    WS_Shutdown();
38
+    SocketsCon_ShutdownSocketConSystem();
39
+}
40
+
41
+void http_run(void) {
42
+    WS_Tick();
43
+}

+ 101
- 0
src/http_files.c View File

@@ -0,0 +1,101 @@
1
+/*
2
+ * http_files.c
3
+ *
4
+ * Based on BittyHTTP example.
5
+ *
6
+ * Copyright (c) 2023 Thomas Buck (thomas@xythobuz.de)
7
+ * Copyright (c) 2019 Paul Hutchinson
8
+ *
9
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
10
+ * of this software and associated documentation files (the "Software"), to deal
11
+ * in the Software without restriction, including without limitation the rights
12
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13
+ * copies of the Software, and to permit persons to whom the Software is
14
+ * furnished to do so, subject to the following conditions:
15
+ *
16
+ * The above copyright notice and this permission notice shall be included in all
17
+ * copies or substantial portions of the Software.
18
+ *
19
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25
+ * SOFTWARE.
26
+ */
27
+
28
+#include <string.h>
29
+
30
+#include "WebServer.h"
31
+
32
+#include "config.h"
33
+#include "log.h"
34
+#include "http.h"
35
+
36
+struct FileInfo {
37
+    const char *Filename; // With Path
38
+    bool Dynamic;
39
+    const char **Cookies;
40
+    const char **Gets;
41
+    const char **Posts;
42
+    void (*WriteFile)(struct WebServer *Web);
43
+};
44
+
45
+void File_Root(struct WebServer *Web);
46
+
47
+static struct FileInfo m_Files[] =  {
48
+    // Filename, Dynamic, Cookies, Gets, Posts, Callback
49
+    {       "/",   false,    NULL, NULL,  NULL, File_Root },
50
+};
51
+
52
+bool FS_GetFileProperties(const char *Filename, struct WSPageProp *PageProp) {
53
+    PageProp->FileID = 0;
54
+
55
+    for (size_t r = 0; r < sizeof(m_Files) / sizeof(struct FileInfo); r++) {
56
+        if (strcmp(Filename, m_Files[r].Filename) != 0) {
57
+            continue;
58
+        }
59
+
60
+        PageProp->FileID = (uintptr_t)&m_Files[r];
61
+        PageProp->DynamicFile = m_Files[r].Dynamic;
62
+        PageProp->Cookies = m_Files[r].Cookies;
63
+        PageProp->Gets = m_Files[r].Gets;
64
+        PageProp->Posts = m_Files[r].Posts;
65
+
66
+        debug("serving '%s'", Filename);
67
+        return true;
68
+    }
69
+
70
+    debug("unknown file '%s'", Filename);
71
+    return false;
72
+}
73
+
74
+void FS_SendFile(struct WebServer *Web, uintptr_t FileID) {
75
+    struct FileInfo *File = (struct FileInfo *)FileID;
76
+    if ((Web == NULL) || (File == NULL)) {
77
+        debug("invalid param");
78
+        return;
79
+    }
80
+
81
+    File->WriteFile(Web);
82
+}
83
+
84
+t_ElapsedTime ReadElapsedClock(void) {
85
+    return to_ms_since_boot(get_absolute_time()) / 1000;
86
+}
87
+
88
+const char RootHTML[]=
89
+"<!DOCTYPE html>"
90
+"<html>"
91
+"<head>"
92
+    "<title>Volcano Remote</title>"
93
+"</head>"
94
+"<body>"
95
+    "<h1>Hello World</h1>"
96
+"</body>"
97
+"</html>";
98
+
99
+void File_Root(struct WebServer *Web) {
100
+    WS_WriteWhole(Web,RootHTML, sizeof(RootHTML) - 1);
101
+}

+ 392
- 0
src/http_socket.c View File

@@ -0,0 +1,392 @@
1
+/*
2
+ * http_socket.c
3
+ *
4
+ * Based on BittyHTTP example socket interface.
5
+ *
6
+ * Copyright (c) 2023 Thomas Buck (thomas@xythobuz.de)
7
+ *
8
+ * This program is free software: you can redistribute it and/or modify
9
+ * it under the terms of the GNU General Public License as published by
10
+ * the Free Software Foundation, either version 3 of the License, or
11
+ * (at your option) any later version.
12
+ *
13
+ * This program is distributed in the hope that it will be useful,
14
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
+ * GNU General Public License for more details.
17
+ *
18
+ * See <http://www.gnu.org/licenses/>.
19
+ */
20
+
21
+#include <string.h>
22
+
23
+#include "lwip/tcp.h"
24
+#include "lwip/dns.h"
25
+#include "SocketsCon.h"
26
+
27
+#include "config.h"
28
+#include "log.h"
29
+#include "main.h"
30
+#include "ring.h"
31
+#include "http.h"
32
+
33
+#define MAX_SOCK 4
34
+#define SOCK_RECV_BUFF 512
35
+
36
+#define HTTP_DNS_TIMEOUT_MS 5000
37
+#define HTTP_CONNECT_TIMEOUT_MS 5000
38
+
39
+struct tcp_sock {
40
+    bool set;
41
+    struct tcp_pcb *pcb;
42
+
43
+    // TODO listening server socket has unused buffer
44
+    uint8_t rx_buf[SOCK_RECV_BUFF];
45
+    struct ring_buffer rx_rb;
46
+
47
+    struct tcp_pcb *child_buf[MAX_SOCK];
48
+    struct ring_buffer child_rb;
49
+};
50
+
51
+static struct tcp_sock sock[MAX_SOCK] = {0};
52
+
53
+bool SocketsCon_InitSocketConSystem(void) {
54
+    return true;
55
+}
56
+
57
+void SocketsCon_ShutdownSocketConSystem(void) { }
58
+
59
+static void tcp_server_err(void *arg, err_t err) {
60
+    debug("tcp error %d", err);
61
+
62
+    struct SocketCon *Con = arg;
63
+    Con->ErrorCode = e_ConnectErrorMAX;
64
+    Con->State = e_ConnectState_Error;
65
+}
66
+
67
+static err_t tcp_server_recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err) {
68
+    (void)tpcb;
69
+    debug("tcp recv %d %d", p->len, err);
70
+
71
+    struct SocketCon *Con = arg;
72
+    size_t idx = Con->SocketFD;
73
+
74
+    if (rb_space(&sock[idx].rx_rb) < p->len) {
75
+        debug("not enough space (%d < %d)", rb_space(&sock[idx].rx_rb), p->len);
76
+        tcp_abort(sock[idx].pcb);
77
+        Con->ErrorCode = e_ConnectErrorMAX;
78
+        Con->State = e_ConnectState_Error;
79
+        return ERR_ABRT;
80
+    }
81
+
82
+    rb_add(&sock[idx].rx_rb, p->payload, p->len);
83
+    return ERR_OK;
84
+}
85
+
86
+bool SocketsCon_InitSockCon(struct SocketCon *Con) {
87
+    if (!Con) {
88
+        debug("invalid param");
89
+        return false;
90
+    }
91
+
92
+    ssize_t next = -1;
93
+    for (size_t i = 0; i < MAX_SOCK; i++) {
94
+        if (!sock[i].set) {
95
+            next = i;
96
+            break;
97
+        }
98
+    }
99
+
100
+    if (next < 0) {
101
+        debug("error: too many sockets");
102
+        return false;
103
+    }
104
+
105
+    debug("new socket at %d", next);
106
+
107
+    sock[next].pcb = tcp_new_ip_type(IPADDR_TYPE_ANY);
108
+    if (sock[next].pcb == NULL) {
109
+        debug("error allocating new socket");
110
+        return false;
111
+    }
112
+
113
+    tcp_arg(sock[next].pcb, Con);
114
+    tcp_err(sock[next].pcb, tcp_server_err);
115
+    tcp_recv(sock[next].pcb, tcp_server_recv);
116
+
117
+    Con->SocketFD = next;
118
+    sock[next].set = true;
119
+
120
+    struct ring_buffer tmp = RB_INIT(sock[next].rx_buf, SOCK_RECV_BUFF, sizeof(uint8_t));
121
+    sock[next].rx_rb = tmp;
122
+
123
+    struct ring_buffer tmp2 = RB_INIT(sock[next].child_buf, MAX_SOCK, sizeof(struct tcp_pcb *));
124
+    sock[next].child_rb = tmp2;
125
+
126
+    Con->ErrorCode = e_ConnectError_AllOk;
127
+    Con->State = e_ConnectState_Idle;
128
+    Con->ReadInProgress = false;
129
+
130
+    return true;
131
+}
132
+
133
+static err_t tcp_server_connected(void *arg, struct tcp_pcb *tpcb, err_t err) {
134
+    (void)tpcb;
135
+    debug("tcp connected");
136
+
137
+    struct SocketCon *Con = arg;
138
+    Con->State = (err == ERR_OK) ? e_ConnectState_Connected : e_ConnectState_Idle;
139
+    return ERR_OK;
140
+}
141
+
142
+bool SocketsCon_Connect(struct SocketCon *Con,
143
+                        const char *ServerName, int portNo) {
144
+    if ((!Con) || (!ServerName)) {
145
+        debug("invalid param");
146
+        return false;
147
+    }
148
+
149
+    ip_addr_t ipaddr;
150
+    err_t err;
151
+    uint32_t start_time = to_ms_since_boot(get_absolute_time());
152
+    do {
153
+        err = dns_gethostbyname(ServerName, &ipaddr, NULL, NULL);
154
+        main_loop_hw();
155
+
156
+        uint32_t now = to_ms_since_boot(get_absolute_time());
157
+        if ((now - start_time) >= HTTP_DNS_TIMEOUT_MS) {
158
+            break;
159
+        }
160
+    } while (err == ERR_INPROGRESS);
161
+    if (err != ERR_OK) {
162
+        debug("error getting IP for '%s'", ServerName);
163
+        return false;
164
+    } else {
165
+        debug("IP %s for '%s'", ip4addr_ntoa(&ipaddr), ServerName);
166
+    }
167
+
168
+    Con->State = e_ConnectState_Connecting;
169
+
170
+    size_t idx = Con->SocketFD;
171
+    err = tcp_connect(sock[idx].pcb,
172
+                            &ipaddr, portNo,
173
+                            tcp_server_connected);
174
+    if (err != ERR_OK) {
175
+        debug("error connecting (%d)", err);
176
+        Con->State = e_ConnectState_Idle;
177
+        return false;
178
+    }
179
+
180
+    start_time = to_ms_since_boot(get_absolute_time());
181
+    while (Con->State == e_ConnectState_Connecting) {
182
+        main_loop_hw();
183
+
184
+        uint32_t now = to_ms_since_boot(get_absolute_time());
185
+        if ((now - start_time) >= HTTP_CONNECT_TIMEOUT_MS) {
186
+            break;
187
+        }
188
+    }
189
+
190
+    // TODO ?
191
+    //if (Con->State == e_ConnectState_Error) {
192
+    //    Con->State = e_ConnectState_Idle;
193
+    //}
194
+
195
+    return (Con->State == e_ConnectState_Connected);
196
+}
197
+
198
+bool SocketsCon_EnableAddressReuse(struct SocketCon *Con, bool Enable) {
199
+    (void)Con;
200
+    (void)Enable;
201
+    return true;
202
+}
203
+
204
+void SocketsCon_Tick(struct SocketCon *Con) { (void)Con; }
205
+
206
+bool SocketsCon_Write(struct SocketCon *Con, const void *buf, int num) {
207
+    if ((!Con) || (!buf) || (num <= 0)) {
208
+        debug("invalid param");
209
+        return false;
210
+    }
211
+
212
+    size_t idx = Con->SocketFD;
213
+    err_t err = tcp_write(sock[idx].pcb,
214
+                          buf, num, TCP_WRITE_FLAG_COPY);
215
+    if (err != ERR_OK) {
216
+        debug("error writing to socket");
217
+        return false;
218
+    }
219
+
220
+    return true;
221
+}
222
+
223
+int SocketsCon_Read(struct SocketCon *Con, void *buf, int num) {
224
+    if ((!Con) || (!buf) || (num <= 0)) {
225
+        debug("invalid param");
226
+        return false;
227
+    }
228
+
229
+    // TODO irq disable?
230
+
231
+    size_t idx = Con->SocketFD;
232
+    size_t len = rb_get(&sock[idx].rx_rb, buf, num);
233
+
234
+    // TODO irq enable?
235
+
236
+    return len;
237
+}
238
+
239
+void SocketsCon_Close(struct SocketCon *Con) {
240
+    if (!Con) {
241
+        debug("invalid param");
242
+        return;
243
+    }
244
+
245
+    size_t idx = Con->SocketFD;
246
+    sock[idx].set = false;
247
+
248
+    err_t err = tcp_close(sock[idx].pcb);
249
+    if (err != ERR_OK) {
250
+        debug("error closing socket (%d)", err);
251
+        // TODO retry?
252
+    }
253
+}
254
+
255
+static err_t tcp_server_accept(void *arg, struct tcp_pcb *newpcb, err_t err) {
256
+    (void)err; // TODO?
257
+
258
+    struct SocketCon *Con = arg;
259
+    size_t idx = Con->SocketFD;
260
+    if (rb_space(&sock[idx].child_rb) <= 0) {
261
+        debug("no space for new connection");
262
+        tcp_abort(newpcb);
263
+        return ERR_ABRT;
264
+    }
265
+
266
+    debug("new connection");
267
+
268
+    rb_push(&sock[idx].child_rb, &newpcb);
269
+    return ERR_OK;
270
+}
271
+
272
+bool SocketsCon_Listen(struct SocketCon *Con, const char *bindadd, int PortNo) {
273
+    if (!Con) {
274
+        debug("invalid param");
275
+        return false;
276
+    }
277
+
278
+    ip_addr_t ipaddr;
279
+    err_t err;
280
+    if (bindadd) {
281
+        uint32_t start_time = to_ms_since_boot(get_absolute_time());
282
+        do {
283
+            err = dns_gethostbyname(bindadd, &ipaddr, NULL, NULL);
284
+            main_loop_hw();
285
+
286
+            uint32_t now = to_ms_since_boot(get_absolute_time());
287
+            if ((now - start_time) >= HTTP_DNS_TIMEOUT_MS) {
288
+                break;
289
+            }
290
+        } while (err == ERR_INPROGRESS);
291
+        if (err != ERR_OK) {
292
+            debug("error getting IP for '%s'", bindadd);
293
+            return false;
294
+        } else {
295
+            debug("IP %s for '%s'", ip4addr_ntoa(&ipaddr), bindadd);
296
+        }
297
+    }
298
+
299
+    size_t idx = Con->SocketFD;
300
+    err = tcp_bind(sock[idx].pcb,
301
+                   bindadd ? &ipaddr : IP_ANY_TYPE,
302
+                   PortNo);
303
+    if (err != ERR_OK) {
304
+        debug("error binding to '%s'", bindadd);
305
+        return false;
306
+    }
307
+
308
+    struct tcp_pcb *tmp = tcp_listen(sock[idx].pcb);
309
+    if (tmp == NULL) {
310
+        debug("error listening on socket");
311
+        return false;
312
+    }
313
+    sock[idx].pcb = tmp;
314
+
315
+    tcp_accept(sock[idx].pcb, tcp_server_accept);
316
+
317
+    return true;
318
+}
319
+
320
+bool SocketsCon_Accept(struct SocketCon *Con, struct SocketCon *NewCon) {
321
+    if ((!Con) || (!NewCon)) {
322
+        debug("invalid param");
323
+        return false;
324
+    }
325
+
326
+    size_t idx = Con->SocketFD;
327
+    size_t new_idx = NewCon->SocketFD;
328
+
329
+    if (rb_len(&sock[idx].child_rb) <= 0) {
330
+        return false;
331
+    }
332
+
333
+    debug("accepting new connection");
334
+
335
+    struct tcp_pcb *new_pcb;
336
+    rb_pop(&sock[idx].child_rb, &new_pcb);
337
+
338
+    err_t err = tcp_close(sock[new_idx].pcb);
339
+    if (err != ERR_OK) {
340
+        debug("error closing prev new socket");
341
+    }
342
+
343
+    sock[new_idx].pcb = new_pcb;
344
+    return true;
345
+}
346
+
347
+bool SocketsCon_HasError(struct SocketCon *Con) {
348
+    if (!Con) {
349
+        debug("invalid param");
350
+        return true;
351
+    }
352
+    return Con->State == e_ConnectState_Error;
353
+}
354
+
355
+bool SocketsCon_IsConnected(struct SocketCon *Con) {
356
+    if (!Con) {
357
+        debug("invalid param");
358
+        return false;
359
+    }
360
+    return Con->State == e_ConnectState_Connected;
361
+}
362
+
363
+int SocketsCon_GetLastErrNo(struct SocketCon *Con) {
364
+    if (!Con) {
365
+        debug("invalid param");
366
+        return -1;
367
+    }
368
+    return Con->Last_errno;
369
+}
370
+
371
+e_ConnectErrorType SocketsCon_GetErrorCode(struct SocketCon *Con) {
372
+    if (!Con) {
373
+        debug("invalid param");
374
+        return e_ConnectErrorMAX;
375
+    }
376
+    return Con->ErrorCode;
377
+}
378
+
379
+bool SocketsCon_GetSocketHandle(struct SocketCon *Con,
380
+                                t_ConSocketHandle *RetHandle) {
381
+    if (!Con) {
382
+        debug("invalid param");
383
+        return false;
384
+    }
385
+
386
+    if (Con->SocketFD < 0) {
387
+        return false;
388
+    }
389
+
390
+    *RetHandle = Con->SocketFD;
391
+    return true;
392
+}

+ 5
- 5
src/log.c View File

@@ -29,17 +29,17 @@
29 29
 #include "log.h"
30 30
 
31 31
 static uint8_t log_buff[4096] = {0};
32
-static struct ring_buffer log = RB_INIT(log_buff, sizeof(log_buff));
32
+static struct ring_buffer log = RB_INIT(log_buff, sizeof(log_buff), 1);
33 33
 
34 34
 static uint8_t line_buff[256] = {0};
35 35
 static volatile bool got_input = false;
36 36
 static FIL log_file_fat;
37 37
 
38
-static void add_to_log(const uint8_t *buff, size_t len) {
38
+static void add_to_log(const void *buff, size_t len) {
39 39
     rb_add(&log, buff, len);
40 40
 }
41 41
 
42
-static void log_dump_to_x(void (*write)(const uint8_t *, size_t)) {
42
+static void log_dump_to_x(void (*write)(const void *, size_t)) {
43 43
     if (rb_len(&log) == 0) {
44 44
         return;
45 45
     }
@@ -67,7 +67,7 @@ void log_dump_to_uart(void) {
67 67
 #endif
68 68
 }
69 69
 
70
-static void log_file_write_callback(const uint8_t *data, size_t len) {
70
+static void log_file_write_callback(const void *data, size_t len) {
71 71
     UINT bw;
72 72
     FRESULT res = f_write(&log_file_fat, data, len, &bw);
73 73
     if ((res != FR_OK) || (bw != len)) {
@@ -120,7 +120,7 @@ void debug_log(bool log, const char* format, ...) {
120 120
     va_end(args);
121 121
 }
122 122
 
123
-void debug_handle_input(const uint8_t *buff, size_t len) {
123
+void debug_handle_input(const void *buff, size_t len) {
124 124
     (void)buff;
125 125
 
126 126
     if (len > 0) {

+ 25
- 2
src/main.c View File

@@ -39,6 +39,8 @@
39 39
 #include "serial.h"
40 40
 #include "workflow.h"
41 41
 #include "wifi.h"
42
+#include "http.h"
43
+#include "main.h"
42 44
 
43 45
 void main_loop_hw(void) {
44 46
     watchdog_update();
@@ -50,6 +52,27 @@ void main_loop_hw(void) {
50 52
         lcd_set_backlight(mem_data()->backlight);
51 53
     }
52 54
 
55
+    networking_run();
56
+}
57
+
58
+void networking_init(void) {
59
+    debug("wifi_init");
60
+    wifi_init();
61
+
62
+    debug("http_init");
63
+    http_init();
64
+}
65
+
66
+void networking_deinit(void) {
67
+    debug("http_deinit");
68
+    http_deinit();
69
+
70
+    debug("wifi_deinit");
71
+    wifi_deinit();
72
+}
73
+
74
+void networking_run(void) {
75
+    http_run();
53 76
     wifi_run();
54 77
 }
55 78
 
@@ -124,8 +147,8 @@ int main(void) {
124 147
     }
125 148
 
126 149
     if (mem_data()->enable_wifi) {
127
-        debug("wifi_init");
128
-        wifi_init();
150
+        debug("networking_init");
151
+        networking_init();
129 152
     } else {
130 153
         debug("wifi not enabled");
131 154
     }

+ 24
- 14
src/ring.c View File

@@ -16,12 +16,14 @@
16 16
  * See <http://www.gnu.org/licenses/>.
17 17
  */
18 18
 
19
+#include <string.h>
20
+
19 21
 #include "config.h"
20 22
 #include "ring.h"
21 23
 
22
-void rb_add(struct ring_buffer *rb, const uint8_t *data, size_t length) {
24
+void rb_add(struct ring_buffer *rb, const void *data, size_t length) {
23 25
     for (size_t i = 0; i < length; i++) {
24
-        rb->buffer[rb->head] = data[i];
26
+        memcpy(rb->buffer + rb->head * rb->el_len, data + i * rb->el_len, rb->el_len);
25 27
 
26 28
         if (rb->full && (++(rb->tail) == rb->size)) {
27 29
             rb->tail = 0;
@@ -49,44 +51,52 @@ size_t rb_len(struct ring_buffer *rb) {
49 51
     }
50 52
 }
51 53
 
52
-void rb_dump(struct ring_buffer *rb, void (*write)(const uint8_t *, size_t)) {
54
+void rb_dump(struct ring_buffer *rb, void (*write)(const void *, size_t)) {
53 55
     if (rb_len(rb) == 0) {
54 56
         return;
55 57
     }
56 58
 
57 59
     if (rb->head > rb->tail) {
58
-        write(rb->buffer + rb->tail, rb->head - rb->tail);
60
+        write(rb->buffer + rb->tail * rb->el_len, rb->head - rb->tail);
59 61
     } else {
60
-        write(rb->buffer + rb->tail, rb->size - rb->tail);
62
+        write(rb->buffer + rb->tail * rb->el_len, rb->size - rb->tail);
61 63
         write(rb->buffer, rb->head);
62 64
     }
63 65
 }
64 66
 
65
-void rb_move(struct ring_buffer *rb, void (*write)(const uint8_t *, size_t)) {
67
+void rb_move(struct ring_buffer *rb, void (*write)(const void *, size_t)) {
66 68
     rb_dump(rb, write);
67 69
     rb->head = 0;
68 70
     rb->tail = 0;
69 71
     rb->full = false;
70 72
 }
71 73
 
72
-uint8_t rb_peek(struct ring_buffer *rb) {
74
+void rb_peek(struct ring_buffer *rb, void *buf) {
73 75
     if (rb_len(rb) == 0) {
74
-        return 0;
76
+        return;
75 77
     }
76 78
 
77
-    uint8_t v = rb->buffer[rb->tail];
78
-    return v;
79
+    memcpy(buf, rb->buffer + rb->tail * rb->el_len, rb->el_len);
79 80
 }
80 81
 
81
-uint8_t rb_pop(struct ring_buffer *rb) {
82
+void rb_pop(struct ring_buffer *rb, void *buf) {
82 83
     if (rb_len(rb) == 0) {
83
-        return 0;
84
+        return;
84 85
     }
85 86
 
86
-    uint8_t v = rb->buffer[rb->tail++];
87
+    memcpy(buf, rb->buffer + rb->tail * rb->el_len, rb->el_len);
88
+    rb->tail++;
87 89
     if (rb->tail >= rb->size) {
88 90
         rb->tail = 0;
89 91
     }
92
+}
90 93
 
91
-    return v;
94
+size_t rb_get(struct ring_buffer *rb, void *data, size_t length) {
95
+    size_t count = 0;
96
+    while ((length > 0) && (rb_len(rb) > 0)) {
97
+        rb_pop(rb, data + count * rb->el_len);
98
+        count++;
99
+        length--;
100
+    }
101
+    return count;
92 102
 }

+ 12
- 7
src/serial.c View File

@@ -45,10 +45,10 @@
45 45
 #include "serial.h"
46 46
 
47 47
 static uint8_t rx_buff[UART_RX_BUFF_LEN] = {0};
48
-static struct ring_buffer rx = RB_INIT(rx_buff, sizeof(rx_buff));
48
+static struct ring_buffer rx = RB_INIT(rx_buff, sizeof(rx_buff), 1);
49 49
 
50 50
 static uint8_t tx_buff[UART_TX_BUFF_LEN] = {0};
51
-static struct ring_buffer tx = RB_INIT(tx_buff, sizeof(tx_buff));
51
+static struct ring_buffer tx = RB_INIT(tx_buff, sizeof(tx_buff), 1);
52 52
 
53 53
 static bool reroute_serial_debug = false;
54 54
 static bool tx_irq_state = false;
@@ -70,13 +70,15 @@ static void serial_irq(void) {
70 70
     // Rx - read from UART FIFO to local buffer
71 71
     while (uart_is_readable(UART_ID) && (rb_space(&rx) > 0)) {
72 72
         uint8_t ch = uart_getc(UART_ID);
73
-        rb_push(&rx, ch);
73
+        rb_push(&rx, &ch);
74 74
     }
75 75
 
76 76
     // Tx - write to UART FIFO if needed
77 77
     while (uart_is_writable(UART_ID)) {
78 78
         if (rb_len(&tx) > 0) {
79
-            uart_putc_raw(UART_ID, rb_pop(&tx));
79
+            uint8_t c;
80
+            rb_pop(&tx, &c);
81
+            uart_putc_raw(UART_ID, c);
80 82
         } else {
81 83
             SET_TX_IRQ(false);
82 84
             break;
@@ -102,11 +104,12 @@ void serial_init(void) {
102 104
     SET_TX_IRQ(false);
103 105
 }
104 106
 
105
-void serial_write(const uint8_t *buf, size_t count) {
107
+void serial_write(const void *buf, size_t count) {
106 108
     SET_TX_IRQ(false);
107 109
 
108 110
     while ((rb_len(&tx) == 0) && uart_is_writable(UART_ID) && (count > 0)) {
109
-        uart_putc_raw(UART_ID, *buf++);
111
+        uart_putc_raw(UART_ID, *(uint8_t *)buf);
112
+        buf++;
110 113
         count--;
111 114
     }
112 115
 
@@ -144,7 +147,9 @@ void serial_run(void) {
144 147
     SET_RX_IRQ(false);
145 148
 
146 149
     if (rb_len(&rx) >= 1) {
147
-        if (rb_peek(&rx) == ENTER_BOOTLOADER_MAGIC) {
150
+        uint8_t c;
151
+        rb_peek(&rx, &c);
152
+        if (c == ENTER_BOOTLOADER_MAGIC) {
148 153
             reset_to_bootloader();
149 154
         } else if (reroute_serial_debug) {
150 155
             rb_move(&rx, debug_handle_input);

+ 3
- 2
src/state_settings.c View File

@@ -23,6 +23,7 @@
23 23
 
24 24
 #include "config.h"
25 25
 #include "log.h"
26
+#include "main.h"
26 27
 #include "menu.h"
27 28
 #include "mem.h"
28 29
 #include "state.h"
@@ -104,11 +105,11 @@ void state_settings_exit(void) {
104 105
     // apply changed wifi state
105 106
     if (mem_data()->enable_wifi) {
106 107
         if (!wifi_initialized()) {
107
-            wifi_init();
108
+            networking_init();
108 109
         }
109 110
     } else {
110 111
         if (wifi_initialized()) {
111
-            wifi_deinit();
112
+            networking_deinit();
112 113
         }
113 114
     }
114 115
 }

+ 1
- 1
src/state_string.c View File

@@ -102,7 +102,7 @@ static void string_buttons(enum buttons btn, bool state) {
102 102
     while (edit < offset) {
103 103
         offset -= 1;
104 104
     }
105
-    while (edit >= (offset + (LCD_WIDTH / 10 - 2))) {
105
+    while (edit >= (offset + (LCD_WIDTH / 10 - 3))) {
106 106
         offset += 1;
107 107
     }
108 108
 

+ 51
- 14
src/state_venty.c View File

@@ -38,6 +38,8 @@ static int16_t target_temp = 0;
38 38
 static int8_t battery = 0;
39 39
 static int8_t eco_current = 0;
40 40
 static int8_t eco_voltage = 0;
41
+static int8_t vibration = 0;
42
+static int8_t brightness = 0;
41 43
 
42 44
 void state_venty_target(bd_addr_t addr, bd_addr_type_t type) {
43 45
     memcpy(ble_addr, addr, sizeof(bd_addr_t));
@@ -46,9 +48,19 @@ void state_venty_target(bd_addr_t addr, bd_addr_type_t type) {
46 48
     connected = false;
47 49
 }
48 50
 
51
+static void exit_cb(void) {
52
+    debug("venty disconnect");
53
+    ble_disconnect();
54
+    wait_for_disconnect = true;
55
+}
56
+
49 57
 static void enter_cb(int selection) {
50 58
     switch (selection) {
51 59
     case 0:
60
+        // Battery
61
+        break;
62
+
63
+    case 1:
52 64
         // Target
53 65
         state_value_set(&target_temp,
54 66
                         sizeof(target_temp),
@@ -58,7 +70,7 @@ static void enter_cb(int selection) {
58 70
         state_switch(STATE_VALUE);
59 71
         break;
60 72
 
61
-    case 1:
73
+    case 2:
62 74
         // Heater
63 75
         state_value_set(&heater_state,
64 76
                         sizeof(heater_state),
@@ -68,7 +80,7 @@ static void enter_cb(int selection) {
68 80
         state_switch(STATE_VALUE);
69 81
         break;
70 82
 
71
-    case 2:
83
+    case 3:
72 84
         // Eco Current
73 85
         state_value_set(&eco_current,
74 86
                         sizeof(eco_current),
@@ -78,7 +90,7 @@ static void enter_cb(int selection) {
78 90
         state_switch(STATE_VALUE);
79 91
         break;
80 92
 
81
-    case 3:
93
+    case 4:
82 94
         // Eco Voltage
83 95
         state_value_set(&eco_voltage,
84 96
                         sizeof(eco_voltage),
@@ -87,6 +99,30 @@ static void enter_cb(int selection) {
87 99
         state_value_return(STATE_VENTY);
88 100
         state_switch(STATE_VALUE);
89 101
         break;
102
+
103
+    case 5:
104
+        // Vibration
105
+        state_value_set(&vibration,
106
+                        sizeof(vibration),
107
+                        0, 1, VAL_STEP_INCREMENT, 1,
108
+                        "Vibration");
109
+        state_value_return(STATE_VENTY);
110
+        state_switch(STATE_VALUE);
111
+        break;
112
+
113
+    case 6:
114
+        // Brightness
115
+        state_value_set(&brightness,
116
+                        sizeof(brightness),
117
+                        1, 9, VAL_STEP_INCREMENT, 1,
118
+                        "Brightness");
119
+        state_value_return(STATE_VENTY);
120
+        state_switch(STATE_VALUE);
121
+        break;
122
+
123
+    default:
124
+        exit_cb();
125
+        break;
90 126
     }
91 127
 }
92 128
 
@@ -98,23 +134,20 @@ static void send_values(void) {
98 134
     venty_set_eco_current(eco_current);
99 135
     sleep_ms(250);
100 136
     venty_set_eco_voltage(eco_voltage);
137
+    sleep_ms(250);
138
+    venty_set_vibration(vibration);
139
+    sleep_ms(250);
140
+    venty_set_brightness(brightness);
101 141
 }
102 142
 
103
-
104 143
 static void fetch_values(void) {
105
-    venty_set_heater_state(false);
106
-    heater_state = false;
107
-
144
+    heater_state = venty_get_heater_state();
108 145
     target_temp = venty_get_target_temp();
109 146
     battery = venty_get_battery_state();
110 147
     eco_current = venty_get_eco_current();
111 148
     eco_voltage = venty_get_eco_voltage();
112
-}
113
-
114
-static void exit_cb(void) {
115
-    debug("venty disconnect");
116
-    ble_disconnect();
117
-    wait_for_disconnect = true;
149
+    vibration = venty_get_vibration();
150
+    brightness = venty_get_brightness();
118 151
 }
119 152
 
120 153
 void state_venty_enter(void) {
@@ -148,11 +181,15 @@ static void draw(struct menu_state *menu) {
148 181
     int pos = 0;
149 182
     menu->length = 0;
150 183
 
184
+    ADD_STATIC_ELEMENT("Battery: %d %%", battery);
151 185
     ADD_STATIC_ELEMENT("Target (%d C)", target_temp / 10);
152 186
     ADD_STATIC_ELEMENT("Heater (%d)", heater_state);
153 187
     ADD_STATIC_ELEMENT("Eco Amps (%d)", eco_current);
154 188
     ADD_STATIC_ELEMENT("Eco Volt (%d)", eco_voltage);
155
-    ADD_STATIC_ELEMENT("Battery: %d %%", battery);
189
+    ADD_STATIC_ELEMENT("Vibration (%d)", vibration);
190
+    ADD_STATIC_ELEMENT("Brightness (%d)", brightness);
191
+
192
+    ADD_STATIC_ELEMENT("... go back");
156 193
 
157 194
     if (menu->selection < 0) {
158 195
         menu->selection = 0;

+ 1
- 1
src/usb_cdc.c View File

@@ -39,7 +39,7 @@
39 39
 
40 40
 static bool reroute_cdc_debug = false;
41 41
 
42
-void usb_cdc_write(const uint8_t *buf, size_t count) {
42
+void usb_cdc_write(const void *buf, size_t count) {
43 43
 #ifndef DISABLE_CDC_DTR_CHECK
44 44
     if (!tud_cdc_connected()) {
45 45
         return;

+ 87
- 8
src/venty.c View File

@@ -24,6 +24,11 @@
24 24
 
25 25
 #define VENTY_READ_TIMEOUT_MS 500
26 26
 
27
+enum venty_commands {
28
+    CMD_SETTINGS  = 1,
29
+    CMD_INTERFACE = 6,
30
+};
31
+
27 32
 enum venty_values {
28 33
     MASK_SET_TEMPERATURE = 1 << 1,
29 34
     MASK_SET_BOOST       = 1 << 2,
@@ -42,6 +47,11 @@ enum venty_settings {
42 47
     SETTING_BOOST_VISUALIZATION = 1 << 6,
43 48
 };
44 49
 
50
+enum venty_interface {
51
+    UI_BRIGHTNESS = 1 << 0,
52
+    UI_VIBRATION  = 1 << 3,
53
+};
54
+
45 55
 // "00000000-5354-4f52-5a26-4249434b454c"
46 56
 static uint8_t uuid_service[16] = {
47 57
     0x00, 0x00, 0x00, 0x00, 0x53, 0x54, 0x4f, 0x52,
@@ -100,7 +110,7 @@ int16_t venty_get_target_temp(void) {
100 110
     uint8_t cmd[20] = {0};
101 111
     uint8_t buff[20] = {0};
102 112
 
103
-    cmd[0] = 1;
113
+    cmd[0] = CMD_SETTINGS;
104 114
 
105 115
     int8_t r = venty_cmd(buff, sizeof(buff), cmd, sizeof(cmd));
106 116
     if (r < 0) {
@@ -115,7 +125,7 @@ int8_t venty_set_target_temp(uint16_t value) {
115 125
     uint8_t cmd[20] = {0};
116 126
     uint8_t buff[20] = {0};
117 127
 
118
-    cmd[0] = 1;
128
+    cmd[0] = CMD_SETTINGS;
119 129
     cmd[1] = MASK_SET_TEMPERATURE;
120 130
     uint16_t *val = (uint16_t *)(cmd + 4);
121 131
     *val = value;
@@ -124,11 +134,26 @@ int8_t venty_set_target_temp(uint16_t value) {
124 134
     return r;
125 135
 }
126 136
 
137
+int8_t venty_get_heater_state(void) {
138
+    uint8_t cmd[20] = {0};
139
+    uint8_t buff[20] = {0};
140
+
141
+    cmd[0] = CMD_SETTINGS;
142
+
143
+    int8_t r = venty_cmd(buff, sizeof(buff), cmd, sizeof(cmd));
144
+    if (r < 0) {
145
+        return r;
146
+    }
147
+
148
+    int8_t *val = (int8_t *)(buff + 11);
149
+    return *val;
150
+}
151
+
127 152
 int8_t venty_set_heater_state(bool value) {
128 153
     uint8_t cmd[20] = {0};
129 154
     uint8_t buff[20] = {0};
130 155
 
131
-    cmd[0] = 1;
156
+    cmd[0] = CMD_SETTINGS;
132 157
     cmd[1] = MASK_HEATER;
133 158
     cmd[11] = value ? 1 : 0;
134 159
 
@@ -140,7 +165,7 @@ int8_t venty_get_battery_state(void) {
140 165
     uint8_t cmd[20] = {0};
141 166
     uint8_t buff[20] = {0};
142 167
 
143
-    cmd[0] = 1;
168
+    cmd[0] = CMD_SETTINGS;
144 169
 
145 170
     int8_t r = venty_cmd(buff, sizeof(buff), cmd, sizeof(cmd));
146 171
     if (r < 0) {
@@ -155,7 +180,7 @@ int8_t venty_get_eco_current(void) {
155 180
     uint8_t cmd[20] = {0};
156 181
     uint8_t buff[20] = {0};
157 182
 
158
-    cmd[0] = 1;
183
+    cmd[0] = CMD_SETTINGS;
159 184
 
160 185
     int8_t r = venty_cmd(buff, sizeof(buff), cmd, sizeof(cmd));
161 186
     if (r < 0) {
@@ -171,7 +196,7 @@ int8_t venty_get_eco_voltage(void) {
171 196
     uint8_t cmd[20] = {0};
172 197
     uint8_t buff[20] = {0};
173 198
 
174
-    cmd[0] = 1;
199
+    cmd[0] = CMD_SETTINGS;
175 200
 
176 201
     int8_t r = venty_cmd(buff, sizeof(buff), cmd, sizeof(cmd));
177 202
     if (r < 0) {
@@ -186,7 +211,7 @@ int8_t venty_set_eco_current(bool value) {
186 211
     uint8_t cmd[20] = {0};
187 212
     uint8_t buff[20] = {0};
188 213
 
189
-    cmd[0] = 1;
214
+    cmd[0] = CMD_SETTINGS;
190 215
     cmd[1] = MASK_SETTINGS;
191 216
     cmd[14] = value ? SETTING_ECOMODE_CHARGE : 0;
192 217
     cmd[15] = SETTING_ECOMODE_CHARGE;
@@ -199,7 +224,7 @@ int8_t venty_set_eco_voltage(bool value) {
199 224
     uint8_t cmd[20] = {0};
200 225
     uint8_t buff[20] = {0};
201 226
 
202
-    cmd[0] = 1;
227
+    cmd[0] = CMD_SETTINGS;
203 228
     cmd[1] = MASK_SETTINGS;
204 229
     cmd[14] = value ? SETTING_ECOMODE_VOLTAGE : 0;
205 230
     cmd[15] = SETTING_ECOMODE_VOLTAGE;
@@ -207,3 +232,57 @@ int8_t venty_set_eco_voltage(bool value) {
207 232
     int8_t r = venty_cmd(buff, sizeof(buff), cmd, sizeof(cmd));
208 233
     return r;
209 234
 }
235
+
236
+int8_t venty_get_vibration(void) {
237
+    uint8_t cmd[6] = {0};
238
+    uint8_t buff[6] = {0};
239
+
240
+    cmd[0] = CMD_INTERFACE;
241
+
242
+    int8_t r = venty_cmd(buff, sizeof(buff), cmd, sizeof(cmd));
243
+    if (r < 0) {
244
+        return r;
245
+    }
246
+
247
+    int8_t *val = (int8_t *)(buff + 5);
248
+    return *val;
249
+}
250
+
251
+int8_t venty_get_brightness(void) {
252
+    uint8_t cmd[6] = {0};
253
+    uint8_t buff[6] = {0};
254
+
255
+    cmd[0] = CMD_INTERFACE;
256
+
257
+    int8_t r = venty_cmd(buff, sizeof(buff), cmd, sizeof(cmd));
258
+    if (r < 0) {
259
+        return r;
260
+    }
261
+
262
+    int8_t *val = (int8_t *)(buff + 2);
263
+    return *val;
264
+}
265
+
266
+int8_t venty_set_vibration(bool value) {
267
+    uint8_t cmd[6] = {0};
268
+    uint8_t buff[6] = {0};
269
+
270
+    cmd[0] = CMD_INTERFACE;
271
+    cmd[1] = UI_VIBRATION;
272
+    cmd[5] = value ? 1 : 0;
273
+
274
+    int8_t r = venty_cmd(buff, sizeof(buff), cmd, sizeof(cmd));
275
+    return r;
276
+}
277
+
278
+int8_t venty_set_brightness(uint8_t value) {
279
+    uint8_t cmd[6] = {0};
280
+    uint8_t buff[6] = {0};
281
+
282
+    cmd[0] = CMD_INTERFACE;
283
+    cmd[1] = UI_BRIGHTNESS;
284
+    cmd[2] = MIN(MAX(value, 1), 9);
285
+
286
+    int8_t r = venty_cmd(buff, sizeof(buff), cmd, sizeof(cmd));
287
+    return r;
288
+}

+ 1
- 3
src/wifi.c View File

@@ -1,8 +1,6 @@
1 1
 /*
2 2
  * wifi.c
3 3
  *
4
- * https://github.com/raspberrypi/pico-examples/blob/master/adc/read_vsys/power_status.c
5
- *
6 4
  * Copyright (c) 2023 Thomas Buck (thomas@xythobuz.de)
7 5
  *
8 6
  * This program is free software: you can redistribute it and/or modify
@@ -120,7 +118,7 @@ const char *wifi_state(void) {
120 118
         return "Connecting";
121 119
 
122 120
     case WS_READY:
123
-        return "Connected";
121
+        return ip4addr_ntoa(netif_ip4_addr(netif_default));
124 122
     }
125 123
 
126 124
     return NULL;

Loading…
Cancel
Save