Browse Source

open ap when no successful wifi connection

Thomas Buck 11 months ago
parent
commit
4c9ccdbefa
7 changed files with 120 additions and 16 deletions
  1. 4
    0
      CMakeLists.txt
  2. 1
    0
      README.md
  3. 4
    0
      include/usb_descriptors.h
  4. 2
    2
      src/ota_shim.c
  5. 1
    0
      src/state_about.c
  6. 8
    1
      src/usb_descriptors.c
  7. 100
    13
      src/wifi.c

+ 4
- 0
CMakeLists.txt View File

129
     mcufont/decoder/mf_bwfont.c
129
     mcufont/decoder/mf_bwfont.c
130
     mcufont/decoder/mf_scaledfont.c
130
     mcufont/decoder/mf_scaledfont.c
131
     mcufont/decoder/mf_wordwrap.c
131
     mcufont/decoder/mf_wordwrap.c
132
+
133
+    picowota/dhcpserver/dhcpserver.c
132
 )
134
 )
133
 
135
 
134
 # external dependency include directories
136
 # external dependency include directories
141
 target_include_directories(gadget PUBLIC ${CMAKE_CURRENT_LIST_DIR}/data)
143
 target_include_directories(gadget PUBLIC ${CMAKE_CURRENT_LIST_DIR}/data)
142
 target_include_directories(gadget PUBLIC ${CMAKE_CURRENT_LIST_DIR}/build)
144
 target_include_directories(gadget PUBLIC ${CMAKE_CURRENT_LIST_DIR}/build)
143
 target_include_directories(gadget PUBLIC ${CMAKE_CURRENT_BINARY_DIR})
145
 target_include_directories(gadget PUBLIC ${CMAKE_CURRENT_BINARY_DIR})
146
+target_include_directories(gadget PUBLIC ${CMAKE_CURRENT_LIST_DIR}/picowota/dhcpserver)
144
 
147
 
145
 # compress source code and stuff we want to include
148
 # compress source code and stuff we want to include
146
 add_custom_target(pack bash -c "./pack_data.sh ${CMAKE_CURRENT_BINARY_DIR}"
149
 add_custom_target(pack bash -c "./pack_data.sh ${CMAKE_CURRENT_BINARY_DIR}"
211
     ${CMAKE_CURRENT_SOURCE_DIR}/src/workflow_default.c
214
     ${CMAKE_CURRENT_SOURCE_DIR}/src/workflow_default.c
212
     ${CMAKE_CURRENT_SOURCE_DIR}/src/buttons.c
215
     ${CMAKE_CURRENT_SOURCE_DIR}/src/buttons.c
213
     ${CMAKE_CURRENT_SOURCE_DIR}/src/util.c
216
     ${CMAKE_CURRENT_SOURCE_DIR}/src/util.c
217
+    ${CMAKE_CURRENT_SOURCE_DIR}/src/usb_descriptors.c
214
 
218
 
215
     ${CMAKE_CURRENT_SOURCE_DIR}/st7789/src/driver_st7789.c
219
     ${CMAKE_CURRENT_SOURCE_DIR}/st7789/src/driver_st7789.c
216
 
220
 

+ 1
- 0
README.md View File

124
 Also included are the [MCUFont library](https://github.com/mcufont/mcufont) and the [st7789 library](https://github.com/hepingood/st7789), both licensed under the MIT license.
124
 Also included are the [MCUFont library](https://github.com/mcufont/mcufont) and the [st7789 library](https://github.com/hepingood/st7789), both licensed under the MIT license.
125
 It also uses the [BTstack](https://github.com/bluekitchen/btstack/blob/master/LICENSE) included with the Pico SDK, following their [license terms](https://github.com/raspberrypi/pico-sdk/blob/master/src/rp2_common/pico_btstack/LICENSE.RP).
125
 It also uses the [BTstack](https://github.com/bluekitchen/btstack/blob/master/LICENSE) included with the Pico SDK, following their [license terms](https://github.com/raspberrypi/pico-sdk/blob/master/src/rp2_common/pico_btstack/LICENSE.RP).
126
 The included bootloader is [picowota](https://github.com/usedbytes/picowota), licensed as BSD 3-clause.
126
 The included bootloader is [picowota](https://github.com/usedbytes/picowota), licensed as BSD 3-clause.
127
+I'm also using the MicroPython DHCP server, licensed as MIT and included with picowota.
127
 
128
 
128
 The case design is also licensed as GPLv3.
129
 The case design is also licensed as GPLv3.
129
 It uses a [Pi Pico case model](https://www.printables.com/model/210898-raspberry-pi-pico-case) licensed as CC-BY-NC-SA.
130
 It uses a [Pi Pico case model](https://www.printables.com/model/210898-raspberry-pi-pico-case) licensed as CC-BY-NC-SA.

+ 4
- 0
include/usb_descriptors.h View File

19
 #ifndef USB_DESCRIPTORS_H_
19
 #ifndef USB_DESCRIPTORS_H_
20
 #define USB_DESCRIPTORS_H_
20
 #define USB_DESCRIPTORS_H_
21
 
21
 
22
+#include "pico/unique_id.h"
23
+
24
+extern char string_pico_serial[2 * PICO_UNIQUE_BOARD_ID_SIZE_BYTES + 1];
25
+
22
 void usb_descriptor_init_id(void);
26
 void usb_descriptor_init_id(void);
23
 
27
 
24
 #endif /* USB_DESCRIPTORS_H_ */
28
 #endif /* USB_DESCRIPTORS_H_ */

+ 2
- 2
src/ota_shim.c View File

29
 #include "textbox.h"
29
 #include "textbox.h"
30
 #include "mem.h"
30
 #include "mem.h"
31
 #include "util.h"
31
 #include "util.h"
32
+#include "usb_descriptors.h"
32
 #include "wifi.h"
33
 #include "wifi.h"
33
 
34
 
34
 static int16_t lcd_off = 0;
35
 static int16_t lcd_off = 0;
113
 }
114
 }
114
 
115
 
115
 int picowota_init(void) {
116
 int picowota_init(void) {
117
+    usb_descriptor_init_id();
116
     buttons_init();
118
     buttons_init();
117
     buttons_callback(ota_buttons);
119
     buttons_callback(ota_buttons);
118
     mem_load();
120
     mem_load();
144
         }
146
         }
145
 
147
 
146
         picowota_poll();
148
         picowota_poll();
147
-
148
-        // TODO open AP when timed out?
149
     }
149
     }
150
 
150
 
151
     debug("wifi ready");
151
     debug("wifi ready");

+ 1
- 0
src/state_about.c View File

55
     "hepingood/st7789\n"
55
     "hepingood/st7789\n"
56
     "usedbytes/picowota\n"
56
     "usedbytes/picowota\n"
57
     "lwip-tcpip/lwip\n"
57
     "lwip-tcpip/lwip\n"
58
+    "micropython/dhcpserver\n"
58
     "\n"
59
     "\n"
59
 
60
 
60
     "This program is free software: you can redistribute it and/or modify "
61
     "This program is free software: you can redistribute it and/or modify "

+ 8
- 1
src/usb_descriptors.c View File

27
  *
27
  *
28
  */
28
  */
29
 
29
 
30
-#include "pico/unique_id.h"
31
 #include "tusb.h"
30
 #include "tusb.h"
32
 
31
 
33
 #include "config.h"
32
 #include "config.h"
34
 #include "usb_descriptors.h"
33
 #include "usb_descriptors.h"
35
 
34
 
35
+#ifndef PICOWOTA
36
+
36
 /*
37
 /*
37
  * A combination of interfaces must have a unique product id,
38
  * A combination of interfaces must have a unique product id,
38
  * since PC will save device driver after the first plug.
39
  * since PC will save device driver after the first plug.
172
     return desc_configuration;
173
     return desc_configuration;
173
 }
174
 }
174
 
175
 
176
+#endif // PICOWOTA
177
+
175
 //--------------------------------------------------------------------+
178
 //--------------------------------------------------------------------+
176
 // String Descriptors
179
 // String Descriptors
177
 //--------------------------------------------------------------------+
180
 //--------------------------------------------------------------------+
182
     pico_get_unique_board_id_string(string_pico_serial, sizeof(string_pico_serial));
185
     pico_get_unique_board_id_string(string_pico_serial, sizeof(string_pico_serial));
183
 }
186
 }
184
 
187
 
188
+#ifndef PICOWOTA
189
+
185
 // array of pointer to string descriptors
190
 // array of pointer to string descriptors
186
 char const* string_desc_arr [] = {
191
 char const* string_desc_arr [] = {
187
     (const char[]) { 0x09, 0x04 }, // 0: is supported language is English (0x0409)
192
     (const char[]) { 0x09, 0x04 }, // 0: is supported language is English (0x0409)
227
 
232
 
228
     return _desc_str;
233
     return _desc_str;
229
 }
234
 }
235
+
236
+#endif // PICOWOTA

+ 100
- 13
src/wifi.c View File

19
 #include "pico/cyw43_arch.h"
19
 #include "pico/cyw43_arch.h"
20
 #include "lwip/netif.h"
20
 #include "lwip/netif.h"
21
 #include "lwip/ip4_addr.h"
21
 #include "lwip/ip4_addr.h"
22
+#include "dhcpserver.h"
22
 
23
 
23
 #include "config.h"
24
 #include "config.h"
24
 #include "log.h"
25
 #include "log.h"
25
 #include "mem.h"
26
 #include "mem.h"
27
+#include "usb_descriptors.h"
26
 #include "wifi.h"
28
 #include "wifi.h"
27
 
29
 
28
-#define CONNECT_TIMEOUT (5 * 1000)
30
+#define CONNECT_TIMEOUT_MS (8UL * 1000UL)
31
+#define SCAN_AP_TIMEOUT_MS (20UL * 1000UL)
32
+
33
+#define WIFI_AP_SSID_PREFIX "Volcano-"
34
+#define WIFI_AP_SSID_LEN 4
35
+#define WIFI_AP_PASS_LEN 8
36
+static_assert((WIFI_AP_SSID_LEN + WIFI_AP_PASS_LEN) <= (2 * PICO_UNIQUE_BOARD_ID_SIZE_BYTES),
37
+              "SSID and Password parts for AP need to fit Pico serial number");
29
 
38
 
30
 enum wifi_state {
39
 enum wifi_state {
31
     WS_IDLE = 0,
40
     WS_IDLE = 0,
36
 };
45
 };
37
 
46
 
38
 static enum wifi_state state = WS_IDLE;
47
 static enum wifi_state state = WS_IDLE;
39
-static uint32_t start_time = 0;
48
+static uint32_t start_scan_time = 0;
49
+static uint32_t start_connect_time = 0;
50
+static uint32_t start_ip_time = 0;
51
+static dhcp_server_t dhcp_server;
52
+static bool enabled_ap = false;
53
+static char curr_ssid[WIFI_MAX_NAME_LEN + 1] = {0};
54
+static char curr_pass[WIFI_MAX_PASS_LEN + 1] = {0};
55
+
56
+static void wifi_ap(void) {
57
+    cyw43_thread_enter();
58
+
59
+    // last N chars of serial for ssid and password
60
+    const size_t prefix_len = strlen(WIFI_AP_SSID_PREFIX);
61
+    char wifi_ssid[prefix_len + WIFI_AP_SSID_LEN + 1];
62
+    memcpy(wifi_ssid, WIFI_AP_SSID_PREFIX, prefix_len);
63
+    memcpy(wifi_ssid + prefix_len,
64
+           string_pico_serial + (2 * PICO_UNIQUE_BOARD_ID_SIZE_BYTES) - WIFI_AP_SSID_LEN,
65
+           WIFI_AP_SSID_LEN);
66
+    wifi_ssid[prefix_len + WIFI_AP_SSID_LEN] = '\0';
67
+    strncpy(curr_ssid, wifi_ssid, WIFI_MAX_NAME_LEN);
68
+
69
+    char wifi_pass[WIFI_AP_PASS_LEN + 1] = {0};
70
+    memcpy(wifi_pass,
71
+           string_pico_serial + (2 * PICO_UNIQUE_BOARD_ID_SIZE_BYTES) - WIFI_AP_SSID_LEN - WIFI_AP_PASS_LEN,
72
+           WIFI_AP_PASS_LEN);
73
+    strncpy(curr_pass, wifi_pass, WIFI_MAX_PASS_LEN);
74
+
75
+    debug("disable sta");
76
+    cyw43_arch_disable_sta_mode();
77
+
78
+    debug("enable ap '%s' '%s'", wifi_ssid, wifi_pass);
79
+    cyw43_arch_enable_ap_mode(wifi_ssid, wifi_pass, CYW43_AUTH_WPA2_AES_PSK);
80
+
81
+    ip4_addr_t gw, mask;
82
+    IP4_ADDR(&gw, 192, 168, 4, 1);
83
+    IP4_ADDR(&mask, 255, 255, 255, 0);
84
+
85
+    debug("enable dhcp");
86
+    dhcp_server_init(&dhcp_server, &gw, &mask);
87
+
88
+    state = WS_READY;
89
+    enabled_ap = true;
90
+
91
+    cyw43_thread_exit();
92
+}
40
 
93
 
41
 static void wifi_connect(const char *ssid, const char *pw, uint32_t auth) {
94
 static void wifi_connect(const char *ssid, const char *pw, uint32_t auth) {
95
+    cyw43_thread_enter();
96
+
42
     debug("connecting to '%s'", ssid);
97
     debug("connecting to '%s'", ssid);
43
-    start_time = to_ms_since_boot(get_absolute_time());
44
-    state = WS_CONNECT;
98
+    strncpy(curr_ssid, ssid, WIFI_MAX_NAME_LEN);
99
+    strncpy(curr_pass, pw, WIFI_MAX_PASS_LEN);
45
 
100
 
46
     // https://github.com/raspberrypi/pico-sdk/issues/1413
101
     // https://github.com/raspberrypi/pico-sdk/issues/1413
47
     uint32_t a = 0;
102
     uint32_t a = 0;
55
     if (r != 0) {
110
     if (r != 0) {
56
         debug("failed to connect %d", r);
111
         debug("failed to connect %d", r);
57
         state = WS_SCAN;
112
         state = WS_SCAN;
113
+    } else {
114
+        start_connect_time = to_ms_since_boot(get_absolute_time());
115
+        state = WS_CONNECT;
58
     }
116
     }
117
+
118
+    cyw43_thread_exit();
59
 }
119
 }
60
 
120
 
61
 static int scan_result(void *env, const cyw43_ev_scan_result_t *result) {
121
 static int scan_result(void *env, const cyw43_ev_scan_result_t *result) {
96
     }
156
     }
97
 
157
 
98
     cyw43_thread_enter();
158
     cyw43_thread_enter();
159
+
99
     cyw43_arch_enable_sta_mode();
160
     cyw43_arch_enable_sta_mode();
161
+
100
     wifi_scan();
162
     wifi_scan();
163
+    start_scan_time = to_ms_since_boot(get_absolute_time());
164
+
101
     cyw43_thread_exit();
165
     cyw43_thread_exit();
102
 }
166
 }
103
 
167
 
104
 void wifi_deinit(void) {
168
 void wifi_deinit(void) {
105
     cyw43_thread_enter();
169
     cyw43_thread_enter();
170
+
106
     cyw43_arch_disable_sta_mode();
171
     cyw43_arch_disable_sta_mode();
172
+    cyw43_arch_disable_ap_mode();
107
     state = WS_IDLE;
173
     state = WS_IDLE;
174
+
175
+    if (enabled_ap) {
176
+        enabled_ap = false;
177
+        dhcp_server_deinit(&dhcp_server);
178
+    }
179
+
108
     cyw43_thread_exit();
180
     cyw43_thread_exit();
109
 }
181
 }
110
 
182
 
131
         return "Waiting for IP";
203
         return "Waiting for IP";
132
 
204
 
133
     case WS_READY: {
205
     case WS_READY: {
134
-        cyw43_arch_lwip_begin();
135
-        const ip4_addr_t *ip = netif_ip4_addr(netif_default);
136
-        cyw43_arch_lwip_end();
137
-
138
-        return ip4addr_ntoa(ip);
206
+        uint32_t now = to_ms_since_boot(get_absolute_time()) % (enabled_ap ? 9000 : 6000);
207
+        if (now < 3000) {
208
+            // show SSID
209
+            return curr_ssid;
210
+        } else if (now < 6000) {
211
+            // show IP
212
+            cyw43_arch_lwip_begin();
213
+            const ip4_addr_t *ip = netif_ip4_addr(netif_default);
214
+            cyw43_arch_lwip_end();
215
+
216
+            return ip4addr_ntoa(ip);
217
+        } else {
218
+            // show Pass (only AP)
219
+            return curr_pass;
220
+        }
139
     }
221
     }
140
     }
222
     }
141
 
223
 
150
             debug("restarting scan");
232
             debug("restarting scan");
151
             wifi_scan();
233
             wifi_scan();
152
         }
234
         }
235
+
236
+        uint32_t now = to_ms_since_boot(get_absolute_time());
237
+        if ((now - start_scan_time) >= SCAN_AP_TIMEOUT_MS) {
238
+            debug("wifi sta timeout. opening ap.");
239
+            wifi_ap();
240
+        }
153
     } else if (state == WS_CONNECT) {
241
     } else if (state == WS_CONNECT) {
154
         int link = cyw43_wifi_link_status(&cyw43_state, CYW43_ITF_STA);
242
         int link = cyw43_wifi_link_status(&cyw43_state, CYW43_ITF_STA);
155
 
243
 
161
 
249
 
162
         if (link == CYW43_LINK_JOIN) {
250
         if (link == CYW43_LINK_JOIN) {
163
             debug("joined network");
251
             debug("joined network");
164
-            start_time = to_ms_since_boot(get_absolute_time());
252
+            start_ip_time = to_ms_since_boot(get_absolute_time());
165
             state = WS_WAIT_FOR_IP;
253
             state = WS_WAIT_FOR_IP;
166
         } else if (link < CYW43_LINK_DOWN) {
254
         } else if (link < CYW43_LINK_DOWN) {
167
             debug("net connection failed. retry.");
255
             debug("net connection failed. retry.");
169
         }
257
         }
170
 
258
 
171
         uint32_t now = to_ms_since_boot(get_absolute_time());
259
         uint32_t now = to_ms_since_boot(get_absolute_time());
172
-        if ((now - start_time) >= CONNECT_TIMEOUT) {
260
+        if ((now - start_connect_time) >= CONNECT_TIMEOUT_MS) {
173
             debug("net connection timeout. retry.");
261
             debug("net connection timeout. retry.");
174
             wifi_scan();
262
             wifi_scan();
175
         }
263
         }
184
         }
272
         }
185
 
273
 
186
         uint32_t now = to_ms_since_boot(get_absolute_time());
274
         uint32_t now = to_ms_since_boot(get_absolute_time());
187
-        if ((now - start_time) >= CONNECT_TIMEOUT) {
275
+        if ((now - start_ip_time) >= CONNECT_TIMEOUT_MS) {
188
             debug("net dhcp timeout. retry.");
276
             debug("net dhcp timeout. retry.");
189
-            start_time = now;
190
 
277
 
191
             //cyw43_arch_lwip_begin();
278
             //cyw43_arch_lwip_begin();
192
             //dhcp_renew(netif_default);
279
             //dhcp_renew(netif_default);

Loading…
Cancel
Save