Browse Source

Merge pull request #1 from vajr8/main

Add WiFi AP mode
Brian Starkey 2 years ago
parent
commit
42fdcd358b
No account linked to committer's email address
6 changed files with 435 additions and 25 deletions
  1. 25
    10
      CMakeLists.txt
  2. 11
    12
      README.md
  3. 21
    0
      dhcpserver/LICENSE
  4. 300
    0
      dhcpserver/dhcpserver.c
  5. 49
    0
      dhcpserver/dhcpserver.h
  6. 29
    3
      main.c

+ 25
- 10
CMakeLists.txt View File

36
 add_executable(picowota
36
 add_executable(picowota
37
 	main.c
37
 	main.c
38
 	tcp_comm.c
38
 	tcp_comm.c
39
+	dhcpserver/dhcpserver.c
39
 )
40
 )
40
 
41
 
41
 function(target_cl_options option)
42
 function(target_cl_options option)
51
 
52
 
52
 pico_add_extra_outputs(picowota)
53
 pico_add_extra_outputs(picowota)
53
 
54
 
54
-# Needed so that lwip can find lwipopts.h
55
-target_include_directories(picowota PRIVATE ${CMAKE_CURRENT_LIST_DIR})
55
+target_include_directories(picowota PRIVATE
56
+	${CMAKE_CURRENT_LIST_DIR} # Needed so that lwip can find lwipopts.h
57
+	${CMAKE_CURRENT_LIST_DIR}/dhcpserver)
56
 
58
 
57
 pico_enable_stdio_usb(picowota 1)
59
 pico_enable_stdio_usb(picowota 1)
58
 
60
 
71
 	picowota_reboot
73
 	picowota_reboot
72
 )
74
 )
73
 
75
 
74
-if (DEFINED ENV{PICOWOTA_WIFI_SSID} AND (NOT PICOWOTA_WIFI_SSID))
75
-	set(PICOWOTA_WIFI_SSID $ENV{PICOWOTA_WIFI_SSID})
76
-	message("Using PICOWOTA_WIFI_SSID from environment ('${PICOWOTA_WIFI_SSID}')")
77
-endif ()
76
+# Retrieves build variables from the environment if present
77
+function(picowota_retrieve_variable name hidden)
78
+	if (DEFINED ENV{${name}} AND (NOT ${name}))
79
+		set(${name} $ENV{${name}} PARENT_SCOPE)
80
+		if (hidden)
81
+			set(log_value "hidden")
82
+		else()
83
+			set(log_value "'$ENV{${name}}'")
84
+		endif()
85
+		message("Using ${name} from environment (${log_value})")
86
+	endif()
87
+endfunction()
78
 
88
 
79
-if (DEFINED ENV{PICOWOTA_WIFI_PASS} AND (NOT PICOWOTA_WIFI_PASS))
80
-	set(PICOWOTA_WIFI_PASS $ENV{PICOWOTA_WIFI_PASS})
81
-	message("Using PICOWOTA_WIFI_PASS from environment (hidden)")
82
-endif ()
89
+picowota_retrieve_variable(PICOWOTA_WIFI_SSID false)
90
+picowota_retrieve_variable(PICOWOTA_WIFI_PASS true)
91
+picowota_retrieve_variable(PICOWOTA_WIFI_AP false)
83
 
92
 
84
 if ((NOT PICOWOTA_WIFI_SSID) OR (NOT PICOWOTA_WIFI_PASS))
93
 if ((NOT PICOWOTA_WIFI_SSID) OR (NOT PICOWOTA_WIFI_PASS))
85
         message(FATAL_ERROR
94
         message(FATAL_ERROR
92
 target_compile_definitions(picowota PUBLIC PICOWOTA_WIFI_SSID=${PICOWOTA_WIFI_SSID})
101
 target_compile_definitions(picowota PUBLIC PICOWOTA_WIFI_SSID=${PICOWOTA_WIFI_SSID})
93
 target_compile_definitions(picowota PUBLIC PICOWOTA_WIFI_PASS=${PICOWOTA_WIFI_PASS})
102
 target_compile_definitions(picowota PUBLIC PICOWOTA_WIFI_PASS=${PICOWOTA_WIFI_PASS})
94
 
103
 
104
+# Use the WiFi AP mode upon request
105
+if (PICOWOTA_WIFI_AP)
106
+	target_compile_definitions(picowota PUBLIC PICOWOTA_WIFI_AP=1)
107
+	message("Building in WiFi AP mode.")
108
+endif()
109
+
95
 # Provide a helper to build a standalone target
110
 # Provide a helper to build a standalone target
96
 function(picowota_build_standalone NAME)
111
 function(picowota_build_standalone NAME)
97
 	get_target_property(PICOWOTA_SRC_DIR picowota SOURCE_DIR)
112
 	get_target_property(PICOWOTA_SRC_DIR picowota SOURCE_DIR)

+ 11
- 12
README.md View File

25
 add_subdirectory(picowota)
25
 add_subdirectory(picowota)
26
 ```
26
 ```
27
 
27
 
28
-`picowota` (currently) connects to an existing WiFi network, so you need to
29
-set the SSID and password for the network to connect to.
28
+`picowota` either connects to an existing WiFi network (by default) or
29
+creates one, in both cases with the given SSID and password.
30
 
30
 
31
-You can either export the `PICOWOTA_WIFI_SSID` and `PICOWOTA_WIFI_PASS`
32
-environment variables, or set the CMake variables with the same name:
31
+You can either provide the following as environment variables, or set them
32
+as CMake variables:
33
 
33
 
34
 ```
34
 ```
35
-set(PICOWOTA_WIFI_SSID MyNetworkName)
36
-set(PICOWOTA_WIFI_PASS MyPassw0rd)
35
+PICOWOTA_WIFI_SSID # The WiFi network SSID
36
+PICOWOTA_WIFI_PASS # The WiFi network password
37
+PICOWOTA_WIFI_AP # Optional; 0 = connect to the network, 1 = create it
37
 ```
38
 ```
38
 
39
 
39
 Then, you can either build just your standalone app binary (suitable for
40
 Then, you can either build just your standalone app binary (suitable for
90
 valid app code uploaded yet, or your app called `picowota_reboot(true);`), you
91
 valid app code uploaded yet, or your app called `picowota_reboot(true);`), you
91
 can upload an app `.elf` file which was built by `picowota_build_standalone()`:
92
 can upload an app `.elf` file which was built by `picowota_build_standalone()`:
92
 
93
 
94
+If using the AP mode, the Pico's IP address will be (at the time of writing)
95
+192.168.4.1/24, and the connected device's something in the same subnet.
96
+Otherwise it depends on your network settings.
97
+
93
 (Assuming your Pico's IP address is 192.168.1.123):
98
 (Assuming your Pico's IP address is 192.168.1.123):
94
 ```
99
 ```
95
 serial-flash tcp:192.168.1.123:4242 my_executable_name.elf
100
 serial-flash tcp:192.168.1.123:4242 my_executable_name.elf
122
 libraries don't give a mechanism to do so.
127
 libraries don't give a mechanism to do so.
123
 
128
 
124
 I've raised https://github.com/raspberrypi/pico-sdk/issues/928 for consideration.
129
 I've raised https://github.com/raspberrypi/pico-sdk/issues/928 for consideration.
125
-
126
-### Expose an access point, rather than connecting to one
127
-
128
-It would perhaps be better if the bootloader set up an access point, rather than
129
-trying to connect to an existing network - or even better, provide the option.
130
-I expect that wouldn't be too hard to do.

+ 21
- 0
dhcpserver/LICENSE View File

1
+The MIT License (MIT)
2
+
3
+Copyright (c) 2013-2022 Damien P. George
4
+
5
+Permission is hereby granted, free of charge, to any person obtaining a copy
6
+of this software and associated documentation files (the "Software"), to deal
7
+in the Software without restriction, including without limitation the rights
8
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+copies of the Software, and to permit persons to whom the Software is
10
+furnished to do so, subject to the following conditions:
11
+
12
+The above copyright notice and this permission notice shall be included in
13
+all copies or substantial portions of the Software.
14
+
15
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+THE SOFTWARE.

+ 300
- 0
dhcpserver/dhcpserver.c View File

1
+/*
2
+ * This file is part of the MicroPython project, http://micropython.org/
3
+ *
4
+ * The MIT License (MIT)
5
+ *
6
+ * Copyright (c) 2018-2019 Damien P. George
7
+ *
8
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
9
+ * of this software and associated documentation files (the "Software"), to deal
10
+ * in the Software without restriction, including without limitation the rights
11
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12
+ * copies of the Software, and to permit persons to whom the Software is
13
+ * furnished to do so, subject to the following conditions:
14
+ *
15
+ * The above copyright notice and this permission notice shall be included in
16
+ * all copies or substantial portions of the Software.
17
+ *
18
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24
+ * THE SOFTWARE.
25
+ */
26
+
27
+// For DHCP specs see:
28
+//  https://www.ietf.org/rfc/rfc2131.txt
29
+//  https://tools.ietf.org/html/rfc2132 -- DHCP Options and BOOTP Vendor Extensions
30
+
31
+#include <stdio.h>
32
+#include <string.h>
33
+#include <errno.h>
34
+
35
+#include "cyw43_config.h"
36
+#include "dhcpserver.h"
37
+#include "lwip/udp.h"
38
+
39
+#define DHCPDISCOVER    (1)
40
+#define DHCPOFFER       (2)
41
+#define DHCPREQUEST     (3)
42
+#define DHCPDECLINE     (4)
43
+#define DHCPACK         (5)
44
+#define DHCPNACK        (6)
45
+#define DHCPRELEASE     (7)
46
+#define DHCPINFORM      (8)
47
+
48
+#define DHCP_OPT_PAD                (0)
49
+#define DHCP_OPT_SUBNET_MASK        (1)
50
+#define DHCP_OPT_ROUTER             (3)
51
+#define DHCP_OPT_DNS                (6)
52
+#define DHCP_OPT_HOST_NAME          (12)
53
+#define DHCP_OPT_REQUESTED_IP       (50)
54
+#define DHCP_OPT_IP_LEASE_TIME      (51)
55
+#define DHCP_OPT_MSG_TYPE           (53)
56
+#define DHCP_OPT_SERVER_ID          (54)
57
+#define DHCP_OPT_PARAM_REQUEST_LIST (55)
58
+#define DHCP_OPT_MAX_MSG_SIZE       (57)
59
+#define DHCP_OPT_VENDOR_CLASS_ID    (60)
60
+#define DHCP_OPT_CLIENT_ID          (61)
61
+#define DHCP_OPT_END                (255)
62
+
63
+#define PORT_DHCP_SERVER (67)
64
+#define PORT_DHCP_CLIENT (68)
65
+
66
+#define DEFAULT_DNS MAKE_IP4(8, 8, 8, 8)
67
+#define DEFAULT_LEASE_TIME_S (24 * 60 * 60) // in seconds
68
+
69
+#define MAC_LEN (6)
70
+#define MAKE_IP4(a, b, c, d) ((a) << 24 | (b) << 16 | (c) << 8 | (d))
71
+
72
+typedef struct {
73
+    uint8_t op; // message opcode
74
+    uint8_t htype; // hardware address type
75
+    uint8_t hlen; // hardware address length
76
+    uint8_t hops;
77
+    uint32_t xid; // transaction id, chosen by client
78
+    uint16_t secs; // client seconds elapsed
79
+    uint16_t flags;
80
+    uint8_t ciaddr[4]; // client IP address
81
+    uint8_t yiaddr[4]; // your IP address
82
+    uint8_t siaddr[4]; // next server IP address
83
+    uint8_t giaddr[4]; // relay agent IP address
84
+    uint8_t chaddr[16]; // client hardware address
85
+    uint8_t sname[64]; // server host name
86
+    uint8_t file[128]; // boot file name
87
+    uint8_t options[312]; // optional parameters, variable, starts with magic
88
+} dhcp_msg_t;
89
+
90
+static int dhcp_socket_new_dgram(struct udp_pcb **udp, void *cb_data, udp_recv_fn cb_udp_recv) {
91
+    // family is AF_INET
92
+    // type is SOCK_DGRAM
93
+
94
+    *udp = udp_new();
95
+    if (*udp == NULL) {
96
+        return -ENOMEM;
97
+    }
98
+
99
+    // Register callback
100
+    udp_recv(*udp, cb_udp_recv, (void *)cb_data);
101
+
102
+    return 0; // success
103
+}
104
+
105
+static void dhcp_socket_free(struct udp_pcb **udp) {
106
+    if (*udp != NULL) {
107
+        udp_remove(*udp);
108
+        *udp = NULL;
109
+    }
110
+}
111
+
112
+static int dhcp_socket_bind(struct udp_pcb **udp, uint32_t ip, uint16_t port) {
113
+    ip_addr_t addr;
114
+    IP4_ADDR(&addr, ip >> 24 & 0xff, ip >> 16 & 0xff, ip >> 8 & 0xff, ip & 0xff);
115
+    // TODO convert lwIP errors to errno
116
+    return udp_bind(*udp, &addr, port);
117
+}
118
+
119
+static int dhcp_socket_sendto(struct udp_pcb **udp, const void *buf, size_t len, uint32_t ip, uint16_t port) {
120
+    if (len > 0xffff) {
121
+        len = 0xffff;
122
+    }
123
+
124
+    struct pbuf *p = pbuf_alloc(PBUF_TRANSPORT, len, PBUF_RAM);
125
+    if (p == NULL) {
126
+        return -ENOMEM;
127
+    }
128
+
129
+    memcpy(p->payload, buf, len);
130
+
131
+    ip_addr_t dest;
132
+    IP4_ADDR(&dest, ip >> 24 & 0xff, ip >> 16 & 0xff, ip >> 8 & 0xff, ip & 0xff);
133
+    err_t err = udp_sendto(*udp, p, &dest, port);
134
+
135
+    pbuf_free(p);
136
+
137
+    if (err != ERR_OK) {
138
+        return err;
139
+    }
140
+
141
+    return len;
142
+}
143
+
144
+static uint8_t *opt_find(uint8_t *opt, uint8_t cmd) {
145
+    for (int i = 0; i < 308 && opt[i] != DHCP_OPT_END;) {
146
+        if (opt[i] == cmd) {
147
+            return &opt[i];
148
+        }
149
+        i += 2 + opt[i + 1];
150
+    }
151
+    return NULL;
152
+}
153
+
154
+static void opt_write_n(uint8_t **opt, uint8_t cmd, size_t n, void *data) {
155
+    uint8_t *o = *opt;
156
+    *o++ = cmd;
157
+    *o++ = n;
158
+    memcpy(o, data, n);
159
+    *opt = o + n;
160
+}
161
+
162
+static void opt_write_u8(uint8_t **opt, uint8_t cmd, uint8_t val) {
163
+    uint8_t *o = *opt;
164
+    *o++ = cmd;
165
+    *o++ = 1;
166
+    *o++ = val;
167
+    *opt = o;
168
+}
169
+
170
+static void opt_write_u32(uint8_t **opt, uint8_t cmd, uint32_t val) {
171
+    uint8_t *o = *opt;
172
+    *o++ = cmd;
173
+    *o++ = 4;
174
+    *o++ = val >> 24;
175
+    *o++ = val >> 16;
176
+    *o++ = val >> 8;
177
+    *o++ = val;
178
+    *opt = o;
179
+}
180
+
181
+static void dhcp_server_process(void *arg, struct udp_pcb *upcb, struct pbuf *p, const ip_addr_t *src_addr, u16_t src_port) {
182
+    dhcp_server_t *d = arg;
183
+    (void)upcb;
184
+    (void)src_addr;
185
+    (void)src_port;
186
+
187
+    // This is around 548 bytes
188
+    dhcp_msg_t dhcp_msg;
189
+
190
+    #define DHCP_MIN_SIZE (240 + 3)
191
+    if (p->tot_len < DHCP_MIN_SIZE) {
192
+        goto ignore_request;
193
+    }
194
+
195
+    size_t len = pbuf_copy_partial(p, &dhcp_msg, sizeof(dhcp_msg), 0);
196
+    if (len < DHCP_MIN_SIZE) {
197
+        goto ignore_request;
198
+    }
199
+
200
+    dhcp_msg.op = DHCPOFFER;
201
+    memcpy(&dhcp_msg.yiaddr, &d->ip.addr, 4);
202
+
203
+    uint8_t *opt = (uint8_t *)&dhcp_msg.options;
204
+    opt += 4; // assume magic cookie: 99, 130, 83, 99
205
+
206
+    switch (opt[2]) {
207
+        case DHCPDISCOVER: {
208
+            int yi = DHCPS_MAX_IP;
209
+            for (int i = 0; i < DHCPS_MAX_IP; ++i) {
210
+                if (memcmp(d->lease[i].mac, dhcp_msg.chaddr, MAC_LEN) == 0) {
211
+                    // MAC match, use this IP address
212
+                    yi = i;
213
+                    break;
214
+                }
215
+                if (yi == DHCPS_MAX_IP) {
216
+                    // Look for a free IP address
217
+                    if (memcmp(d->lease[i].mac, "\x00\x00\x00\x00\x00\x00", MAC_LEN) == 0) {
218
+                        // IP available
219
+                        yi = i;
220
+                    }
221
+                    uint32_t expiry = d->lease[i].expiry << 16 | 0xffff;
222
+                    if ((int32_t)(expiry - cyw43_hal_ticks_ms()) < 0) {
223
+                        // IP expired, reuse it
224
+                        memset(d->lease[i].mac, 0, MAC_LEN);
225
+                        yi = i;
226
+                    }
227
+                }
228
+            }
229
+            if (yi == DHCPS_MAX_IP) {
230
+                // No more IP addresses left
231
+                goto ignore_request;
232
+            }
233
+            dhcp_msg.yiaddr[3] = DHCPS_BASE_IP + yi;
234
+            opt_write_u8(&opt, DHCP_OPT_MSG_TYPE, DHCPOFFER);
235
+            break;
236
+        }
237
+
238
+        case DHCPREQUEST: {
239
+            uint8_t *o = opt_find(opt, DHCP_OPT_REQUESTED_IP);
240
+            if (o == NULL) {
241
+                // Should be NACK
242
+                goto ignore_request;
243
+            }
244
+            if (memcmp(o + 2, &d->ip.addr, 3) != 0) {
245
+                // Should be NACK
246
+                goto ignore_request;
247
+            }
248
+            uint8_t yi = o[5] - DHCPS_BASE_IP;
249
+            if (yi >= DHCPS_MAX_IP) {
250
+                // Should be NACK
251
+                goto ignore_request;
252
+            }
253
+            if (memcmp(d->lease[yi].mac, dhcp_msg.chaddr, MAC_LEN) == 0) {
254
+                // MAC match, ok to use this IP address
255
+            } else if (memcmp(d->lease[yi].mac, "\x00\x00\x00\x00\x00\x00", MAC_LEN) == 0) {
256
+                // IP unused, ok to use this IP address
257
+                memcpy(d->lease[yi].mac, dhcp_msg.chaddr, MAC_LEN);
258
+            } else {
259
+                // IP already in use
260
+                // Should be NACK
261
+                goto ignore_request;
262
+            }
263
+            d->lease[yi].expiry = (cyw43_hal_ticks_ms() + DEFAULT_LEASE_TIME_S * 1000) >> 16;
264
+            dhcp_msg.yiaddr[3] = DHCPS_BASE_IP + yi;
265
+            opt_write_u8(&opt, DHCP_OPT_MSG_TYPE, DHCPACK);
266
+            printf("DHCPS: client connected: MAC=%02x:%02x:%02x:%02x:%02x:%02x IP=%u.%u.%u.%u\n",
267
+                dhcp_msg.chaddr[0], dhcp_msg.chaddr[1], dhcp_msg.chaddr[2], dhcp_msg.chaddr[3], dhcp_msg.chaddr[4], dhcp_msg.chaddr[5],
268
+                dhcp_msg.yiaddr[0], dhcp_msg.yiaddr[1], dhcp_msg.yiaddr[2], dhcp_msg.yiaddr[3]);
269
+            break;
270
+        }
271
+
272
+        default:
273
+            goto ignore_request;
274
+    }
275
+
276
+    opt_write_n(&opt, DHCP_OPT_SERVER_ID, 4, &d->ip.addr);
277
+    opt_write_n(&opt, DHCP_OPT_SUBNET_MASK, 4, &d->nm.addr);
278
+    opt_write_n(&opt, DHCP_OPT_ROUTER, 4, &d->ip.addr); // aka gateway; can have mulitple addresses
279
+    opt_write_u32(&opt, DHCP_OPT_DNS, DEFAULT_DNS); // can have mulitple addresses
280
+    opt_write_u32(&opt, DHCP_OPT_IP_LEASE_TIME, DEFAULT_LEASE_TIME_S);
281
+    *opt++ = DHCP_OPT_END;
282
+    dhcp_socket_sendto(&d->udp, &dhcp_msg, opt - (uint8_t *)&dhcp_msg, 0xffffffff, PORT_DHCP_CLIENT);
283
+
284
+ignore_request:
285
+    pbuf_free(p);
286
+}
287
+
288
+void dhcp_server_init(dhcp_server_t *d, ip_addr_t *ip, ip_addr_t *nm) {
289
+    ip_addr_copy(d->ip, *ip);
290
+    ip_addr_copy(d->nm, *nm);
291
+    memset(d->lease, 0, sizeof(d->lease));
292
+    if (dhcp_socket_new_dgram(&d->udp, d, dhcp_server_process) != 0) {
293
+        return;
294
+    }
295
+    dhcp_socket_bind(&d->udp, 0, PORT_DHCP_SERVER);
296
+}
297
+
298
+void dhcp_server_deinit(dhcp_server_t *d) {
299
+    dhcp_socket_free(&d->udp);
300
+}

+ 49
- 0
dhcpserver/dhcpserver.h View File

1
+/*
2
+ * This file is part of the MicroPython project, http://micropython.org/
3
+ *
4
+ * The MIT License (MIT)
5
+ *
6
+ * Copyright (c) 2018-2019 Damien P. George
7
+ *
8
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
9
+ * of this software and associated documentation files (the "Software"), to deal
10
+ * in the Software without restriction, including without limitation the rights
11
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12
+ * copies of the Software, and to permit persons to whom the Software is
13
+ * furnished to do so, subject to the following conditions:
14
+ *
15
+ * The above copyright notice and this permission notice shall be included in
16
+ * all copies or substantial portions of the Software.
17
+ *
18
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24
+ * THE SOFTWARE.
25
+ */
26
+#ifndef MICROPY_INCLUDED_LIB_NETUTILS_DHCPSERVER_H
27
+#define MICROPY_INCLUDED_LIB_NETUTILS_DHCPSERVER_H
28
+
29
+#include "lwip/ip_addr.h"
30
+
31
+#define DHCPS_BASE_IP (16)
32
+#define DHCPS_MAX_IP (8)
33
+
34
+typedef struct _dhcp_server_lease_t {
35
+    uint8_t mac[6];
36
+    uint16_t expiry;
37
+} dhcp_server_lease_t;
38
+
39
+typedef struct _dhcp_server_t {
40
+    ip_addr_t ip;
41
+    ip_addr_t nm;
42
+    dhcp_server_lease_t lease[DHCPS_MAX_IP];
43
+    struct udp_pcb *udp;
44
+} dhcp_server_t;
45
+
46
+void dhcp_server_init(dhcp_server_t *d, ip_addr_t *ip, ip_addr_t *nm);
47
+void dhcp_server_deinit(dhcp_server_t *d);
48
+
49
+#endif // MICROPY_INCLUDED_LIB_NETUTILS_DHCPSERVER_H

+ 29
- 3
main.c View File

40
 #define DBG_PRINTF(...) { }
40
 #define DBG_PRINTF(...) { }
41
 #endif
41
 #endif
42
 
42
 
43
+#if PICOWOTA_WIFI_AP == 1
44
+#include "dhcpserver.h"
45
+static dhcp_server_t dhcp_server;
46
+#endif
47
+
43
 #define QUOTE(name) #name
48
 #define QUOTE(name) #name
44
 #define STR(macro) QUOTE(macro)
49
 #define STR(macro) QUOTE(macro)
45
 
50
 
557
 	return !gpio_get(BOOTLOADER_ENTRY_PIN) || wd_says_so;
562
 	return !gpio_get(BOOTLOADER_ENTRY_PIN) || wd_says_so;
558
 }
563
 }
559
 
564
 
565
+static void network_deinit()
566
+{
567
+#if PICOWOTA_WIFI_AP == 1
568
+	dhcp_server_deinit(&dhcp_server);
569
+#endif
570
+	cyw43_arch_deinit();
571
+}
572
+
560
 int main()
573
 int main()
561
 {
574
 {
562
 	err_t err;
575
 	err_t err;
585
 		return 1;
598
 		return 1;
586
 	}
599
 	}
587
 
600
 
601
+#if PICOWOTA_WIFI_AP == 1
602
+	cyw43_arch_enable_ap_mode(wifi_ssid, wifi_pass, CYW43_AUTH_WPA2_AES_PSK);
603
+	DBG_PRINTF("Enabled the WiFi AP.\n");
604
+
605
+	ip4_addr_t gw, mask;
606
+	IP4_ADDR(&gw, 192, 168, 4, 1);
607
+	IP4_ADDR(&mask, 255, 255, 255, 0);
608
+
609
+	dhcp_server_t dhcp_server;
610
+	dhcp_server_init(&dhcp_server, &gw, &mask);
611
+	DBG_PRINTF("Started the DHCP server.\n");
612
+#else
588
 	cyw43_arch_enable_sta_mode();
613
 	cyw43_arch_enable_sta_mode();
589
 
614
 
590
 	DBG_PRINTF("Connecting to WiFi...\n");
615
 	DBG_PRINTF("Connecting to WiFi...\n");
594
 	} else {
619
 	} else {
595
 		DBG_PRINTF("Connected.\n");
620
 		DBG_PRINTF("Connected.\n");
596
 	}
621
 	}
622
+#endif
597
 
623
 
598
 	critical_section_init(&critical_section);
624
 	critical_section_init(&critical_section);
599
 
625
 
629
 				break;
655
 				break;
630
 			case EVENT_TYPE_REBOOT:
656
 			case EVENT_TYPE_REBOOT:
631
 				tcp_comm_server_close(tcp);
657
 				tcp_comm_server_close(tcp);
632
-				cyw43_arch_deinit();
658
+				network_deinit();
633
 				picowota_reboot(ev.reboot.to_bootloader);
659
 				picowota_reboot(ev.reboot.to_bootloader);
634
 				/* Should never get here */
660
 				/* Should never get here */
635
 				break;
661
 				break;
636
 			case EVENT_TYPE_GO:
662
 			case EVENT_TYPE_GO:
637
 				tcp_comm_server_close(tcp);
663
 				tcp_comm_server_close(tcp);
638
-				cyw43_arch_deinit();
664
+				network_deinit();
639
 				disable_interrupts();
665
 				disable_interrupts();
640
 				reset_peripherals();
666
 				reset_peripherals();
641
 				jump_to_vtor(ev.go.vtor);
667
 				jump_to_vtor(ev.go.vtor);
648
 		sleep_ms(5);
674
 		sleep_ms(5);
649
 	}
675
 	}
650
 
676
 
651
-	cyw43_arch_deinit();
677
+	network_deinit();
652
 	return 0;
678
 	return 0;
653
 }
679
 }

Loading…
Cancel
Save