Add Pico W examples
This commit is contained in:
parent
a7ce7007ff
commit
01e8128953
@ -41,6 +41,7 @@ add_subdirectory(i2c)
|
||||
add_subdirectory(interp)
|
||||
add_subdirectory(multicore)
|
||||
add_subdirectory(picoboard)
|
||||
add_subdirectory(pico_w)
|
||||
add_subdirectory(pio)
|
||||
add_subdirectory(pwm)
|
||||
add_subdirectory(reset)
|
||||
|
||||
26
README.md
26
README.md
@ -108,6 +108,32 @@ App|Description
|
||||
[blinky](picoboard/blinky)| Blink "hello, world" in Morse code on Pico's LED
|
||||
[button](picoboard/button)| Use Pico's BOOTSEL button as a regular button input, by temporarily suspending flash access.
|
||||
|
||||
### Pico W Networking
|
||||
|
||||
These eaxmples are for the Pico W, and are only available for `PICO_BOARD=pico_w`
|
||||
|
||||
App|Description
|
||||
---|---
|
||||
[picow_access_point](pico_w/picow_access_point)| Starts a WiFi access point, and fields DHCP requests.
|
||||
[picow_blink](pico_w/picow_blink)| Blinks the on-board LED (which is connected via the WiFi chip).
|
||||
[picow_iperf_server](pico_w/picow_iperf)| Runs an "iperf" server for WiFi speed testing.
|
||||
[picow_ntp_client](pico_w/picow_ntp_client)| Connects to an NTP server to fetch and display the current time.
|
||||
[picow_tcp_client](pico_w/picow_tcp_client)| A simple TCP client. You can run [python_test_tcp_server.py](pico_w/python_test_tcp/python_test_tcp_server.py) for it to connect to.
|
||||
[picow_tcp_server](pico_w/picow_tcp_server)| A simple TCP server. You can use [python_test_tcp_client.py](pico_w/python_test_tcp/python_test_tcp_client.py) to connect to it.
|
||||
[picow_wifi_scan](pico_w/picow_wifi_scan)| Scans for WiFi networks and prints the results.
|
||||
|
||||
#### FreeRTOS examples
|
||||
|
||||
These are examples of integrating Pico W networking under FreeRTOS, and require you to set the `FREERTOS_KERNEL_PATH`
|
||||
to point to the FreeRTOS Kernel.
|
||||
|
||||
App|Description
|
||||
---|---
|
||||
[picow_freertos_iperf_server_nosys](pico_w/freertos/picow_iperf)| Runs an "iperf" server for WiFi speed testing under FreeRTOS in NO_SYS=1 mode. The LED is blinked in another task
|
||||
[picow_freertos_iperf_server_sys](pico_w/freertos/picow_iperf)| Runs an "iperf" server for WiFi speed testing under FreeRTOS in NO_SYS=0 (i.e. full FreeRTOS integration) mode. The LED is blinked in another task
|
||||
[picow_freertos_ping_nosys](pico_w/freertos/ping)| Runs the lwip-contrib/apps/ping test app under FreeRTOS in NO_SYS=1 mode.
|
||||
[picow_freertos_iperf_server_sys](pico_w/freertos/picow_iperf)| Runs the lwip-contrib/apps/ping test app under FreeRTOS in NO_SYS=0 (i.e. full FreeRTOS integration) mode. The test app uses the lwIP \em socket API in this case.
|
||||
|
||||
### PIO
|
||||
|
||||
App|Description
|
||||
|
||||
26
pico_w/CMakeLists.txt
Normal file
26
pico_w/CMakeLists.txt
Normal file
@ -0,0 +1,26 @@
|
||||
cmake_minimum_required(VERSION 3.12)
|
||||
|
||||
if (PICO_CYW43_SUPPORTED) # set by BOARD=pico-w
|
||||
if (NOT TARGET pico_cyw43_arch)
|
||||
message("Skipping Pico W examples as support is not available")
|
||||
else()
|
||||
set(WIFI_SSID "${WIFI_SSID}" CACHE INTERNAL "WiFi SSID for examples")
|
||||
set(WIFI_PASSWORD "${WIFI_PASSWORD}" CACHE INTERNAL "WiFi password for examples")
|
||||
|
||||
add_subdirectory(blink)
|
||||
add_subdirectory(wifi_scan)
|
||||
add_subdirectory(access_point)
|
||||
|
||||
if ("${WIFI_SSID}" STREQUAL "")
|
||||
message("Skipping some Pico W examples as WIFI_SSID is not defined")
|
||||
elseif ("${WIFI_PASSWORD}" STREQUAL "")
|
||||
message("Skipping some Pico W examples as WIFI_PASSWORD is not defined")
|
||||
else()
|
||||
add_subdirectory(iperf)
|
||||
add_subdirectory(ntp_client)
|
||||
add_subdirectory(tcp_client)
|
||||
add_subdirectory(tcp_server)
|
||||
add_subdirectory(freertos)
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
33
pico_w/access_point/CMakeLists.txt
Normal file
33
pico_w/access_point/CMakeLists.txt
Normal file
@ -0,0 +1,33 @@
|
||||
add_executable(picow_access_point_background
|
||||
picow_access_point.c
|
||||
dhcpserver/dhcpserver.c
|
||||
)
|
||||
|
||||
target_include_directories(picow_access_point_background PRIVATE
|
||||
${CMAKE_CURRENT_LIST_DIR}
|
||||
${CMAKE_CURRENT_LIST_DIR}/.. # for our common lwipopts
|
||||
${CMAKE_CURRENT_LIST_DIR}/dhcpserver
|
||||
)
|
||||
|
||||
target_link_libraries(picow_access_point_background
|
||||
pico_cyw43_arch_lwip_threadsafe_background
|
||||
pico_stdlib
|
||||
)
|
||||
|
||||
pico_add_extra_outputs(picow_access_point_background)
|
||||
|
||||
add_executable(picow_access_point_poll
|
||||
picow_access_point.c
|
||||
dhcpserver/dhcpserver.c
|
||||
)
|
||||
target_include_directories(picow_access_point_poll PRIVATE
|
||||
${CMAKE_CURRENT_LIST_DIR}
|
||||
${CMAKE_CURRENT_LIST_DIR}/.. # for our common lwipopts
|
||||
${CMAKE_CURRENT_LIST_DIR}/dhcpserver
|
||||
)
|
||||
target_link_libraries(picow_access_point_poll
|
||||
pico_cyw43_arch_lwip_poll
|
||||
pico_stdlib
|
||||
)
|
||||
pico_add_extra_outputs(picow_access_point_poll)
|
||||
|
||||
21
pico_w/access_point/dhcpserver/LICENSE
Normal file
21
pico_w/access_point/dhcpserver/LICENSE
Normal file
@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2013-2022 Damien P. George
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
300
pico_w/access_point/dhcpserver/dhcpserver.c
Normal file
300
pico_w/access_point/dhcpserver/dhcpserver.c
Normal file
@ -0,0 +1,300 @@
|
||||
/*
|
||||
* This file is part of the MicroPython project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2018-2019 Damien P. George
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
// For DHCP specs see:
|
||||
// https://www.ietf.org/rfc/rfc2131.txt
|
||||
// https://tools.ietf.org/html/rfc2132 -- DHCP Options and BOOTP Vendor Extensions
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "cyw43_config.h"
|
||||
#include "dhcpserver.h"
|
||||
#include "lwip/udp.h"
|
||||
|
||||
#define DHCPDISCOVER (1)
|
||||
#define DHCPOFFER (2)
|
||||
#define DHCPREQUEST (3)
|
||||
#define DHCPDECLINE (4)
|
||||
#define DHCPACK (5)
|
||||
#define DHCPNACK (6)
|
||||
#define DHCPRELEASE (7)
|
||||
#define DHCPINFORM (8)
|
||||
|
||||
#define DHCP_OPT_PAD (0)
|
||||
#define DHCP_OPT_SUBNET_MASK (1)
|
||||
#define DHCP_OPT_ROUTER (3)
|
||||
#define DHCP_OPT_DNS (6)
|
||||
#define DHCP_OPT_HOST_NAME (12)
|
||||
#define DHCP_OPT_REQUESTED_IP (50)
|
||||
#define DHCP_OPT_IP_LEASE_TIME (51)
|
||||
#define DHCP_OPT_MSG_TYPE (53)
|
||||
#define DHCP_OPT_SERVER_ID (54)
|
||||
#define DHCP_OPT_PARAM_REQUEST_LIST (55)
|
||||
#define DHCP_OPT_MAX_MSG_SIZE (57)
|
||||
#define DHCP_OPT_VENDOR_CLASS_ID (60)
|
||||
#define DHCP_OPT_CLIENT_ID (61)
|
||||
#define DHCP_OPT_END (255)
|
||||
|
||||
#define PORT_DHCP_SERVER (67)
|
||||
#define PORT_DHCP_CLIENT (68)
|
||||
|
||||
#define DEFAULT_DNS MAKE_IP4(8, 8, 8, 8)
|
||||
#define DEFAULT_LEASE_TIME_S (24 * 60 * 60) // in seconds
|
||||
|
||||
#define MAC_LEN (6)
|
||||
#define MAKE_IP4(a, b, c, d) ((a) << 24 | (b) << 16 | (c) << 8 | (d))
|
||||
|
||||
typedef struct {
|
||||
uint8_t op; // message opcode
|
||||
uint8_t htype; // hardware address type
|
||||
uint8_t hlen; // hardware address length
|
||||
uint8_t hops;
|
||||
uint32_t xid; // transaction id, chosen by client
|
||||
uint16_t secs; // client seconds elapsed
|
||||
uint16_t flags;
|
||||
uint8_t ciaddr[4]; // client IP address
|
||||
uint8_t yiaddr[4]; // your IP address
|
||||
uint8_t siaddr[4]; // next server IP address
|
||||
uint8_t giaddr[4]; // relay agent IP address
|
||||
uint8_t chaddr[16]; // client hardware address
|
||||
uint8_t sname[64]; // server host name
|
||||
uint8_t file[128]; // boot file name
|
||||
uint8_t options[312]; // optional parameters, variable, starts with magic
|
||||
} dhcp_msg_t;
|
||||
|
||||
static int dhcp_socket_new_dgram(struct udp_pcb **udp, void *cb_data, udp_recv_fn cb_udp_recv) {
|
||||
// family is AF_INET
|
||||
// type is SOCK_DGRAM
|
||||
|
||||
*udp = udp_new();
|
||||
if (*udp == NULL) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
// Register callback
|
||||
udp_recv(*udp, cb_udp_recv, (void *)cb_data);
|
||||
|
||||
return 0; // success
|
||||
}
|
||||
|
||||
static void dhcp_socket_free(struct udp_pcb **udp) {
|
||||
if (*udp != NULL) {
|
||||
udp_remove(*udp);
|
||||
*udp = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static int dhcp_socket_bind(struct udp_pcb **udp, uint32_t ip, uint16_t port) {
|
||||
ip_addr_t addr;
|
||||
IP4_ADDR(&addr, ip >> 24 & 0xff, ip >> 16 & 0xff, ip >> 8 & 0xff, ip & 0xff);
|
||||
// TODO convert lwIP errors to errno
|
||||
return udp_bind(*udp, &addr, port);
|
||||
}
|
||||
|
||||
static int dhcp_socket_sendto(struct udp_pcb **udp, const void *buf, size_t len, uint32_t ip, uint16_t port) {
|
||||
if (len > 0xffff) {
|
||||
len = 0xffff;
|
||||
}
|
||||
|
||||
struct pbuf *p = pbuf_alloc(PBUF_TRANSPORT, len, PBUF_RAM);
|
||||
if (p == NULL) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
memcpy(p->payload, buf, len);
|
||||
|
||||
ip_addr_t dest;
|
||||
IP4_ADDR(&dest, ip >> 24 & 0xff, ip >> 16 & 0xff, ip >> 8 & 0xff, ip & 0xff);
|
||||
err_t err = udp_sendto(*udp, p, &dest, port);
|
||||
|
||||
pbuf_free(p);
|
||||
|
||||
if (err != ERR_OK) {
|
||||
return err;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static uint8_t *opt_find(uint8_t *opt, uint8_t cmd) {
|
||||
for (int i = 0; i < 308 && opt[i] != DHCP_OPT_END;) {
|
||||
if (opt[i] == cmd) {
|
||||
return &opt[i];
|
||||
}
|
||||
i += 2 + opt[i + 1];
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void opt_write_n(uint8_t **opt, uint8_t cmd, size_t n, void *data) {
|
||||
uint8_t *o = *opt;
|
||||
*o++ = cmd;
|
||||
*o++ = n;
|
||||
memcpy(o, data, n);
|
||||
*opt = o + n;
|
||||
}
|
||||
|
||||
static void opt_write_u8(uint8_t **opt, uint8_t cmd, uint8_t val) {
|
||||
uint8_t *o = *opt;
|
||||
*o++ = cmd;
|
||||
*o++ = 1;
|
||||
*o++ = val;
|
||||
*opt = o;
|
||||
}
|
||||
|
||||
static void opt_write_u32(uint8_t **opt, uint8_t cmd, uint32_t val) {
|
||||
uint8_t *o = *opt;
|
||||
*o++ = cmd;
|
||||
*o++ = 4;
|
||||
*o++ = val >> 24;
|
||||
*o++ = val >> 16;
|
||||
*o++ = val >> 8;
|
||||
*o++ = val;
|
||||
*opt = o;
|
||||
}
|
||||
|
||||
static void dhcp_server_process(void *arg, struct udp_pcb *upcb, struct pbuf *p, const ip_addr_t *src_addr, u16_t src_port) {
|
||||
dhcp_server_t *d = arg;
|
||||
(void)upcb;
|
||||
(void)src_addr;
|
||||
(void)src_port;
|
||||
|
||||
// This is around 548 bytes
|
||||
dhcp_msg_t dhcp_msg;
|
||||
|
||||
#define DHCP_MIN_SIZE (240 + 3)
|
||||
if (p->tot_len < DHCP_MIN_SIZE) {
|
||||
goto ignore_request;
|
||||
}
|
||||
|
||||
size_t len = pbuf_copy_partial(p, &dhcp_msg, sizeof(dhcp_msg), 0);
|
||||
if (len < DHCP_MIN_SIZE) {
|
||||
goto ignore_request;
|
||||
}
|
||||
|
||||
dhcp_msg.op = DHCPOFFER;
|
||||
memcpy(&dhcp_msg.yiaddr, &d->ip.addr, 4);
|
||||
|
||||
uint8_t *opt = (uint8_t *)&dhcp_msg.options;
|
||||
opt += 4; // assume magic cookie: 99, 130, 83, 99
|
||||
|
||||
switch (opt[2]) {
|
||||
case DHCPDISCOVER: {
|
||||
int yi = DHCPS_MAX_IP;
|
||||
for (int i = 0; i < DHCPS_MAX_IP; ++i) {
|
||||
if (memcmp(d->lease[i].mac, dhcp_msg.chaddr, MAC_LEN) == 0) {
|
||||
// MAC match, use this IP address
|
||||
yi = i;
|
||||
break;
|
||||
}
|
||||
if (yi == DHCPS_MAX_IP) {
|
||||
// Look for a free IP address
|
||||
if (memcmp(d->lease[i].mac, "\x00\x00\x00\x00\x00\x00", MAC_LEN) == 0) {
|
||||
// IP available
|
||||
yi = i;
|
||||
}
|
||||
uint32_t expiry = d->lease[i].expiry << 16 | 0xffff;
|
||||
if ((int32_t)(expiry - cyw43_hal_ticks_ms()) < 0) {
|
||||
// IP expired, reuse it
|
||||
memset(d->lease[i].mac, 0, MAC_LEN);
|
||||
yi = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (yi == DHCPS_MAX_IP) {
|
||||
// No more IP addresses left
|
||||
goto ignore_request;
|
||||
}
|
||||
dhcp_msg.yiaddr[3] = DHCPS_BASE_IP + yi;
|
||||
opt_write_u8(&opt, DHCP_OPT_MSG_TYPE, DHCPOFFER);
|
||||
break;
|
||||
}
|
||||
|
||||
case DHCPREQUEST: {
|
||||
uint8_t *o = opt_find(opt, DHCP_OPT_REQUESTED_IP);
|
||||
if (o == NULL) {
|
||||
// Should be NACK
|
||||
goto ignore_request;
|
||||
}
|
||||
if (memcmp(o + 2, &d->ip.addr, 3) != 0) {
|
||||
// Should be NACK
|
||||
goto ignore_request;
|
||||
}
|
||||
uint8_t yi = o[5] - DHCPS_BASE_IP;
|
||||
if (yi >= DHCPS_MAX_IP) {
|
||||
// Should be NACK
|
||||
goto ignore_request;
|
||||
}
|
||||
if (memcmp(d->lease[yi].mac, dhcp_msg.chaddr, MAC_LEN) == 0) {
|
||||
// MAC match, ok to use this IP address
|
||||
} else if (memcmp(d->lease[yi].mac, "\x00\x00\x00\x00\x00\x00", MAC_LEN) == 0) {
|
||||
// IP unused, ok to use this IP address
|
||||
memcpy(d->lease[yi].mac, dhcp_msg.chaddr, MAC_LEN);
|
||||
} else {
|
||||
// IP already in use
|
||||
// Should be NACK
|
||||
goto ignore_request;
|
||||
}
|
||||
d->lease[yi].expiry = (cyw43_hal_ticks_ms() + DEFAULT_LEASE_TIME_S * 1000) >> 16;
|
||||
dhcp_msg.yiaddr[3] = DHCPS_BASE_IP + yi;
|
||||
opt_write_u8(&opt, DHCP_OPT_MSG_TYPE, DHCPACK);
|
||||
printf("DHCPS: client connected: MAC=%02x:%02x:%02x:%02x:%02x:%02x IP=%u.%u.%u.%u\n",
|
||||
dhcp_msg.chaddr[0], dhcp_msg.chaddr[1], dhcp_msg.chaddr[2], dhcp_msg.chaddr[3], dhcp_msg.chaddr[4], dhcp_msg.chaddr[5],
|
||||
dhcp_msg.yiaddr[0], dhcp_msg.yiaddr[1], dhcp_msg.yiaddr[2], dhcp_msg.yiaddr[3]);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
goto ignore_request;
|
||||
}
|
||||
|
||||
opt_write_n(&opt, DHCP_OPT_SERVER_ID, 4, &d->ip.addr);
|
||||
opt_write_n(&opt, DHCP_OPT_SUBNET_MASK, 4, &d->nm.addr);
|
||||
opt_write_n(&opt, DHCP_OPT_ROUTER, 4, &d->ip.addr); // aka gateway; can have mulitple addresses
|
||||
opt_write_u32(&opt, DHCP_OPT_DNS, DEFAULT_DNS); // can have mulitple addresses
|
||||
opt_write_u32(&opt, DHCP_OPT_IP_LEASE_TIME, DEFAULT_LEASE_TIME_S);
|
||||
*opt++ = DHCP_OPT_END;
|
||||
dhcp_socket_sendto(&d->udp, &dhcp_msg, opt - (uint8_t *)&dhcp_msg, 0xffffffff, PORT_DHCP_CLIENT);
|
||||
|
||||
ignore_request:
|
||||
pbuf_free(p);
|
||||
}
|
||||
|
||||
void dhcp_server_init(dhcp_server_t *d, ip_addr_t *ip, ip_addr_t *nm) {
|
||||
ip_addr_copy(d->ip, *ip);
|
||||
ip_addr_copy(d->nm, *nm);
|
||||
memset(d->lease, 0, sizeof(d->lease));
|
||||
if (dhcp_socket_new_dgram(&d->udp, d, dhcp_server_process) != 0) {
|
||||
return;
|
||||
}
|
||||
dhcp_socket_bind(&d->udp, 0, PORT_DHCP_SERVER);
|
||||
}
|
||||
|
||||
void dhcp_server_deinit(dhcp_server_t *d) {
|
||||
dhcp_socket_free(&d->udp);
|
||||
}
|
||||
49
pico_w/access_point/dhcpserver/dhcpserver.h
Normal file
49
pico_w/access_point/dhcpserver/dhcpserver.h
Normal file
@ -0,0 +1,49 @@
|
||||
/*
|
||||
* This file is part of the MicroPython project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2018-2019 Damien P. George
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#ifndef MICROPY_INCLUDED_LIB_NETUTILS_DHCPSERVER_H
|
||||
#define MICROPY_INCLUDED_LIB_NETUTILS_DHCPSERVER_H
|
||||
|
||||
#include "lwip/ip_addr.h"
|
||||
|
||||
#define DHCPS_BASE_IP (16)
|
||||
#define DHCPS_MAX_IP (8)
|
||||
|
||||
typedef struct _dhcp_server_lease_t {
|
||||
uint8_t mac[6];
|
||||
uint16_t expiry;
|
||||
} dhcp_server_lease_t;
|
||||
|
||||
typedef struct _dhcp_server_t {
|
||||
ip_addr_t ip;
|
||||
ip_addr_t nm;
|
||||
dhcp_server_lease_t lease[DHCPS_MAX_IP];
|
||||
struct udp_pcb *udp;
|
||||
} dhcp_server_t;
|
||||
|
||||
void dhcp_server_init(dhcp_server_t *d, ip_addr_t *ip, ip_addr_t *nm);
|
||||
void dhcp_server_deinit(dhcp_server_t *d);
|
||||
|
||||
#endif // MICROPY_INCLUDED_LIB_NETUTILS_DHCPSERVER_H
|
||||
10
pico_w/access_point/lwipopts.h
Normal file
10
pico_w/access_point/lwipopts.h
Normal file
@ -0,0 +1,10 @@
|
||||
#ifndef _LWIPOPTS_H
|
||||
#define _LWIPOPTS_H
|
||||
|
||||
// Generally you would define your own explicit list of lwIP options
|
||||
// (see https://www.nongnu.org/lwip/2_1_x/group__lwip__opts.html)
|
||||
//
|
||||
// This example uses a common include to avoid repetition
|
||||
#include "lwipopts_examples_common.h"
|
||||
|
||||
#endif
|
||||
180
pico_w/access_point/picow_access_point.c
Normal file
180
pico_w/access_point/picow_access_point.c
Normal file
@ -0,0 +1,180 @@
|
||||
/**
|
||||
* Copyright (c) 2022 Raspberry Pi (Trading) Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "pico/stdlib.h"
|
||||
#include "pico/cyw43_arch.h"
|
||||
|
||||
#include "lwip/pbuf.h"
|
||||
#include "lwip/tcp.h"
|
||||
|
||||
#include "dhcpserver.h"
|
||||
|
||||
#ifndef USE_LED
|
||||
#define USE_LED 1
|
||||
#endif
|
||||
|
||||
#define TCP_PORT 80
|
||||
#define DEBUG_printf printf
|
||||
|
||||
typedef struct TCP_ASERVER_T_ {
|
||||
struct tcp_pcb *server_pcb;
|
||||
struct tcp_pcb *client_pcb;
|
||||
bool complete;
|
||||
} TCP_SERVER_T;
|
||||
|
||||
static err_t tcp_server_close(void *arg) {
|
||||
TCP_SERVER_T *state = (TCP_SERVER_T*)arg;
|
||||
err_t err = ERR_OK;
|
||||
if (state->client_pcb != NULL) {
|
||||
tcp_arg(state->client_pcb, NULL);
|
||||
tcp_poll(state->client_pcb, NULL, 0);
|
||||
tcp_sent(state->client_pcb, NULL);
|
||||
tcp_recv(state->client_pcb, NULL);
|
||||
tcp_err(state->client_pcb, NULL);
|
||||
err = tcp_close(state->client_pcb);
|
||||
if (err != ERR_OK) {
|
||||
DEBUG_printf("close failed %d, calling abort\n", err);
|
||||
tcp_abort(state->client_pcb);
|
||||
err = ERR_ABRT;
|
||||
}
|
||||
state->client_pcb = NULL;
|
||||
}
|
||||
if (state->server_pcb) {
|
||||
tcp_arg(state->server_pcb, NULL);
|
||||
tcp_close(state->server_pcb);
|
||||
state->server_pcb = NULL;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
static err_t tcp_ap_result(void *arg, int status) {
|
||||
TCP_SERVER_T *state = (TCP_SERVER_T*)arg;
|
||||
if (status == 0) {
|
||||
DEBUG_printf("test success\n");
|
||||
} else {
|
||||
DEBUG_printf("test failed %d\n", status);
|
||||
}
|
||||
state->complete = true;
|
||||
return tcp_server_close(arg);
|
||||
}
|
||||
|
||||
static err_t tcp_server_accept(void *arg, struct tcp_pcb *client_pcb, err_t err) {
|
||||
// TCP_SERVER_T *state = (TCP_SERVER_T*)arg;
|
||||
if (err != ERR_OK || client_pcb == NULL) {
|
||||
DEBUG_printf("Failure in accept\n");
|
||||
tcp_ap_result(arg, err);
|
||||
return ERR_VAL;
|
||||
}
|
||||
DEBUG_printf("Client connected\n");
|
||||
|
||||
/*state->client_pcb = client_pcb;
|
||||
tcp_arg(client_pcb, state);
|
||||
tcp_sent(client_pcb, tcp_server_sent);
|
||||
tcp_recv(client_pcb, tcp_server_recv);
|
||||
tcp_poll(client_pcb, tcp_server_poll, POLL_TIME_S * 2);
|
||||
tcp_err(client_pcb, tcp_server_err);
|
||||
|
||||
return tcp_server_send_data(arg, state->client_pcb);*/
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
static bool tcp_server_open(void *arg) {
|
||||
TCP_SERVER_T *state = (TCP_SERVER_T*)arg;
|
||||
DEBUG_printf("Starting server on port %u\n", TCP_PORT);
|
||||
|
||||
struct tcp_pcb *pcb = tcp_new_ip_type(IPADDR_TYPE_ANY);
|
||||
if (!pcb) {
|
||||
DEBUG_printf("failed to create pcb\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
err_t err = tcp_bind(pcb, NULL, TCP_PORT);
|
||||
if (err) {
|
||||
DEBUG_printf("failed to bind to port %d\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
state->server_pcb = tcp_listen_with_backlog(pcb, 1);
|
||||
if (!state->server_pcb) {
|
||||
DEBUG_printf("failed to listen\n");
|
||||
if (pcb) {
|
||||
tcp_close(pcb);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
tcp_arg(state->server_pcb, state);
|
||||
tcp_accept(state->server_pcb, tcp_server_accept);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int main() {
|
||||
stdio_init_all();
|
||||
|
||||
TCP_SERVER_T *state = calloc(1, sizeof(TCP_SERVER_T));
|
||||
if (!state) {
|
||||
DEBUG_printf("failed to allocate state\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (cyw43_arch_init()) {
|
||||
printf("failed to initialise\n");
|
||||
return 1;
|
||||
}
|
||||
const char *ap_name = "picow_test";
|
||||
#if 1
|
||||
const char *password = "password";
|
||||
#else
|
||||
const char *password = NULL;
|
||||
#endif
|
||||
|
||||
cyw43_arch_enable_ap_mode(ap_name, password, CYW43_AUTH_WPA2_AES_PSK);
|
||||
|
||||
ip4_addr_t gw, mask;
|
||||
IP4_ADDR(&gw, 192, 168, 4, 1);
|
||||
IP4_ADDR(&mask, 255, 255, 255, 0);
|
||||
|
||||
// Start the dhcp server
|
||||
dhcp_server_t dhcp_server;
|
||||
dhcp_server_init(&dhcp_server, &gw, &mask);
|
||||
|
||||
if (!tcp_server_open(state)) {
|
||||
tcp_ap_result(state, -1);
|
||||
}
|
||||
|
||||
while(!state->complete) {
|
||||
#if USE_LED
|
||||
static absolute_time_t led_time;
|
||||
static int led_on = true;
|
||||
|
||||
// Invert the led
|
||||
if (absolute_time_diff_us(get_absolute_time(), led_time) < 0) {
|
||||
led_on = !led_on;
|
||||
cyw43_arch_gpio_put(CYW43_WL_GPIO_LED_PIN, led_on);
|
||||
led_time = make_timeout_time_ms(1000);
|
||||
}
|
||||
#endif
|
||||
// the following #ifdef is only here so this same example can be used in multiple modes;
|
||||
// you do not need it in your code
|
||||
#if PICO_CYW43_ARCH_POLL
|
||||
// if you are using pico_cyw43_arch_poll, then you must poll periodically from your
|
||||
// main loop (not from a timer) to check for WiFi driver or lwIP work that needs to be done.
|
||||
cyw43_arch_poll();
|
||||
sleep_ms(1);
|
||||
#else
|
||||
// if you are not using pico_cyw43_arch_poll, then WiFI driver and lwIP work
|
||||
// is done via interrupt in the background. This sleep is just an example of some (blocking)
|
||||
// work you might be doing.
|
||||
sleep_ms(1000);
|
||||
#endif
|
||||
}
|
||||
dhcp_server_deinit(&dhcp_server);
|
||||
cyw43_arch_deinit();
|
||||
return 0;
|
||||
}
|
||||
14
pico_w/blink/CMakeLists.txt
Normal file
14
pico_w/blink/CMakeLists.txt
Normal file
@ -0,0 +1,14 @@
|
||||
add_executable(picow_blink
|
||||
picow_blink.c
|
||||
)
|
||||
|
||||
target_link_libraries(picow_blink
|
||||
pico_stdlib # for core functionality
|
||||
pico_cyw43_arch_none # we need Wifi to access the GPIO, but we don't need anything else
|
||||
)
|
||||
|
||||
# create map/bin/hex file etc.
|
||||
pico_add_extra_outputs(picow_blink)
|
||||
|
||||
# add url via pico_set_program_url
|
||||
example_auto_set_url(picow_blink)
|
||||
22
pico_w/blink/picow_blink.c
Normal file
22
pico_w/blink/picow_blink.c
Normal file
@ -0,0 +1,22 @@
|
||||
/**
|
||||
* Copyright (c) 2022 Raspberry Pi (Trading) Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#include "pico/stdlib.h"
|
||||
#include "pico/cyw43_arch.h"
|
||||
|
||||
int main() {
|
||||
stdio_init_all();
|
||||
if (cyw43_arch_init()) {
|
||||
printf("WiFi init failed");
|
||||
return -1;
|
||||
}
|
||||
while (true) {
|
||||
cyw43_arch_gpio_put(CYW43_WL_GPIO_LED_PIN, 1);
|
||||
sleep_ms(250);
|
||||
cyw43_arch_gpio_put(CYW43_WL_GPIO_LED_PIN, 0);
|
||||
sleep_ms(250);
|
||||
}
|
||||
}
|
||||
8
pico_w/freertos/CMakeLists.txt
Normal file
8
pico_w/freertos/CMakeLists.txt
Normal file
@ -0,0 +1,8 @@
|
||||
if (NOT FREERTOS_KERNEL_PATH AND NOT DEFINED ENV{FREERTOS_KERNEL_PATH})
|
||||
message("Skipping Pico W FreeRTOS examples as FREERTOS_KERNEL_PATH not defined")
|
||||
else()
|
||||
include(FreeRTOS_Kernel_import.cmake)
|
||||
|
||||
add_subdirectory(iperf)
|
||||
add_subdirectory(ping)
|
||||
endif()
|
||||
62
pico_w/freertos/FreeRTOS_Kernel_import.cmake
Normal file
62
pico_w/freertos/FreeRTOS_Kernel_import.cmake
Normal file
@ -0,0 +1,62 @@
|
||||
# This is a copy of <FREERTOS_KERNEL_PATH>/portable/ThirdParty/GCC/RP2040/FREERTOS_KERNEL_import.cmake
|
||||
|
||||
# This can be dropped into an external project to help locate the FreeRTOS kernel
|
||||
# It should be include()ed prior to project(). Alternatively this file may
|
||||
# or the CMakeLists.txt in this directory may be included or added via add_subdirectory
|
||||
# respectively.
|
||||
|
||||
if (DEFINED ENV{FREERTOS_KERNEL_PATH} AND (NOT FREERTOS_KERNEL_PATH))
|
||||
set(FREERTOS_KERNEL_PATH $ENV{FREERTOS_KERNEL_PATH})
|
||||
message("Using FREERTOS_KERNEL_PATH from environment ('${FREERTOS_KERNEL_PATH}')")
|
||||
endif ()
|
||||
|
||||
set(FREERTOS_KERNEL_RP2040_RELATIVE_PATH "portable/ThirdParty/GCC/RP2040")
|
||||
# undo the above
|
||||
set(FREERTOS_KERNEL_RP2040_BACK_PATH "../../../..")
|
||||
|
||||
if (NOT FREERTOS_KERNEL_PATH)
|
||||
# check if we are inside the FreeRTOS kernel tree (i.e. this file has been included directly)
|
||||
get_filename_component(_ACTUAL_PATH ${CMAKE_CURRENT_LIST_DIR} REALPATH)
|
||||
get_filename_component(_POSSIBLE_PATH ${CMAKE_CURRENT_LIST_DIR}/${FREERTOS_KERNEL_RP2040_BACK_PATH}/${FREERTOS_KERNEL_RP2040_RELATIVE_PATH} REALPATH)
|
||||
if (_ACTUAL_PATH STREQUAL _POSSIBLE_PATH)
|
||||
get_filename_component(FREERTOS_KERNEL_PATH ${CMAKE_CURRENT_LIST_DIR}/${FREERTOS_KERNEL_RP2040_BACK_PATH} REALPATH)
|
||||
endif()
|
||||
if (_ACTUAL_PATH STREQUAL _POSSIBLE_PATH)
|
||||
get_filename_component(FREERTOS_KERNEL_PATH ${CMAKE_CURRENT_LIST_DIR}/${FREERTOS_KERNEL_RP2040_BACK_PATH} REALPATH)
|
||||
message("Setting FREERTOS_KERNEL_PATH to ${FREERTOS_KERNEL_PATH} based on location of FreeRTOS-Kernel-import.cmake")
|
||||
elseif (PICO_SDK_PATH AND EXISTS "${PICO_SDK_PATH}/../FreeRTOS-Kernel")
|
||||
set(FREERTOS_KERNEL_PATH ${PICO_SDK_PATH}/../FreeRTOS-Kernel)
|
||||
message("Defaulting FREERTOS_KERNEL_PATH as sibling of PICO_SDK_PATH: ${FREERTOS_KERNEL_PATH}")
|
||||
endif()
|
||||
endif ()
|
||||
|
||||
if (NOT FREERTOS_KERNEL_PATH)
|
||||
foreach(POSSIBLE_SUFFIX Source FreeRTOS-Kernel FreeRTOS/Source)
|
||||
# check if FreeRTOS-Kernel exists under directory that included us
|
||||
set(SEARCH_ROOT ${CMAKE_CURRENT_SOURCE_DIR}})
|
||||
set(SEARCH_ROOT ../../../..)
|
||||
get_filename_component(_POSSIBLE_PATH ${SEARCH_ROOT}/${POSSIBLE_SUFFIX} REALPATH)
|
||||
if (EXISTS ${_POSSIBLE_PATH}/${FREERTOS_KERNEL_RP2040_RELATIVE_PATH}/CMakeLists.txt)
|
||||
get_filename_component(FREERTOS_KERNEL_PATH ${_POSSIBLE_PATH} REALPATH)
|
||||
message("Setting FREERTOS_KERNEL_PATH to '${FREERTOS_KERNEL_PATH}' found relative to enclosing project")
|
||||
break()
|
||||
endif()
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
if (NOT FREERTOS_KERNEL_PATH)
|
||||
message(FATAL_ERROR "FreeRTOS location was not specified. Please set FREERTOS_KERNEL_PATH.")
|
||||
endif()
|
||||
|
||||
set(FREERTOS_KERNEL_PATH "${FREERTOS_KERNEL_PATH}" CACHE PATH "Path to the FreeRTOS Kernel")
|
||||
|
||||
get_filename_component(FREERTOS_KERNEL_PATH "${FREERTOS_KERNEL_PATH}" REALPATH BASE_DIR "${CMAKE_BINARY_DIR}")
|
||||
if (NOT EXISTS ${FREERTOS_KERNEL_PATH})
|
||||
message(FATAL_ERROR "Directory '${FREERTOS_KERNEL_PATH}' not found")
|
||||
endif()
|
||||
if (NOT EXISTS ${FREERTOS_KERNEL_PATH}/${FREERTOS_KERNEL_RP2040_RELATIVE_PATH}/CMakeLists.txt)
|
||||
message(FATAL_ERROR "Directory '${FREERTOS_KERNEL_PATH}' does not contain an RP2040 port here: ${FREERTOS_KERNEL_RP2040_RELATIVE_PATH}")
|
||||
endif()
|
||||
set(FREERTOS_KERNEL_PATH ${FREERTOS_KERNEL_PATH} CACHE PATH "Path to the FreeRTOS_KERNEL" FORCE)
|
||||
|
||||
add_subdirectory(${FREERTOS_KERNEL_PATH}/${FREERTOS_KERNEL_RP2040_RELATIVE_PATH} FREERTOS_KERNEL)
|
||||
38
pico_w/freertos/iperf/CMakeLists.txt
Normal file
38
pico_w/freertos/iperf/CMakeLists.txt
Normal file
@ -0,0 +1,38 @@
|
||||
add_executable(picow_freertos_iperf_server_nosys
|
||||
picow_freertos_iperf.c
|
||||
)
|
||||
target_compile_definitions(picow_freertos_iperf_server_nosys PRIVATE
|
||||
WIFI_SSID=\"${WIFI_SSID}\"
|
||||
WIFI_PASSWORD=\"${WIFI_PASSWORD}\"
|
||||
)
|
||||
target_include_directories(picow_freertos_iperf_server_nosys PRIVATE
|
||||
${CMAKE_CURRENT_LIST_DIR}
|
||||
${CMAKE_CURRENT_LIST_DIR}/../.. # for our common lwipopts
|
||||
)
|
||||
target_link_libraries(picow_freertos_iperf_server_nosys
|
||||
pico_cyw43_arch_lwip_threadsafe_background
|
||||
pico_stdlib
|
||||
pico_lwip_iperf
|
||||
FreeRTOS-Kernel-Heap4 # FreeRTOS kernel and dynamic heap
|
||||
)
|
||||
pico_add_extra_outputs(picow_freertos_iperf_server_nosys)
|
||||
|
||||
add_executable(picow_freertos_iperf_server_sys
|
||||
picow_freertos_iperf.c
|
||||
)
|
||||
target_compile_definitions(picow_freertos_iperf_server_sys PRIVATE
|
||||
WIFI_SSID=\"${WIFI_SSID}\"
|
||||
WIFI_PASSWORD=\"${WIFI_PASSWORD}\"
|
||||
NO_SYS=0 # don't want NO_SYS (generally this would be in your lwipopts.h)
|
||||
)
|
||||
target_include_directories(picow_freertos_iperf_server_sys PRIVATE
|
||||
${CMAKE_CURRENT_LIST_DIR}
|
||||
${CMAKE_CURRENT_LIST_DIR}/../.. # for our common lwipopts
|
||||
)
|
||||
target_link_libraries(picow_freertos_iperf_server_sys
|
||||
pico_cyw43_arch_lwip_sys_freertos
|
||||
pico_stdlib
|
||||
pico_lwip_iperf
|
||||
FreeRTOS-Kernel-Heap4 # FreeRTOS kernel and dynamic heap
|
||||
)
|
||||
pico_add_extra_outputs(picow_freertos_iperf_server_sys)
|
||||
143
pico_w/freertos/iperf/FreeRTOSConfig.h
Normal file
143
pico_w/freertos/iperf/FreeRTOSConfig.h
Normal file
@ -0,0 +1,143 @@
|
||||
/*
|
||||
* FreeRTOS V202111.00
|
||||
* Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* http://www.FreeRTOS.org
|
||||
* http://aws.amazon.com/freertos
|
||||
*
|
||||
* 1 tab == 4 spaces!
|
||||
*/
|
||||
|
||||
#ifndef FREERTOS_CONFIG_H
|
||||
#define FREERTOS_CONFIG_H
|
||||
|
||||
/*-----------------------------------------------------------
|
||||
* Application specific definitions.
|
||||
*
|
||||
* These definitions should be adjusted for your particular hardware and
|
||||
* application requirements.
|
||||
*
|
||||
* THESE PARAMETERS ARE DESCRIBED WITHIN THE 'CONFIGURATION' SECTION OF THE
|
||||
* FreeRTOS API DOCUMENTATION AVAILABLE ON THE FreeRTOS.org WEB SITE.
|
||||
*
|
||||
* See http://www.freertos.org/a00110.html
|
||||
*----------------------------------------------------------*/
|
||||
|
||||
/* Scheduler Related */
|
||||
#define configUSE_PREEMPTION 1
|
||||
#define configUSE_TICKLESS_IDLE 0
|
||||
#define configUSE_IDLE_HOOK 0
|
||||
#define configUSE_TICK_HOOK 0
|
||||
#define configTICK_RATE_HZ ( ( TickType_t ) 1000 )
|
||||
#define configMAX_PRIORITIES 32
|
||||
#define configMINIMAL_STACK_SIZE ( configSTACK_DEPTH_TYPE ) 256
|
||||
#define configUSE_16_BIT_TICKS 0
|
||||
|
||||
#define configIDLE_SHOULD_YIELD 1
|
||||
|
||||
/* Synchronization Related */
|
||||
#define configUSE_MUTEXES 1
|
||||
#define configUSE_RECURSIVE_MUTEXES 1
|
||||
#define configUSE_APPLICATION_TASK_TAG 0
|
||||
#define configUSE_COUNTING_SEMAPHORES 1
|
||||
#define configQUEUE_REGISTRY_SIZE 8
|
||||
#define configUSE_QUEUE_SETS 1
|
||||
#define configUSE_TIME_SLICING 1
|
||||
#define configUSE_NEWLIB_REENTRANT 0
|
||||
// todo need this for lwip FreeRTOS sys_arch to compile
|
||||
#define configENABLE_BACKWARD_COMPATIBILITY 1
|
||||
#define configNUM_THREAD_LOCAL_STORAGE_POINTERS 5
|
||||
|
||||
/* System */
|
||||
#define configSTACK_DEPTH_TYPE uint32_t
|
||||
#define configMESSAGE_BUFFER_LENGTH_TYPE size_t
|
||||
|
||||
/* Memory allocation related definitions. */
|
||||
#define configSUPPORT_STATIC_ALLOCATION 0
|
||||
#define configSUPPORT_DYNAMIC_ALLOCATION 1
|
||||
#define configTOTAL_HEAP_SIZE (128*1024)
|
||||
#define configAPPLICATION_ALLOCATED_HEAP 0
|
||||
|
||||
/* Hook function related definitions. */
|
||||
#define configCHECK_FOR_STACK_OVERFLOW 0
|
||||
#define configUSE_MALLOC_FAILED_HOOK 0
|
||||
#define configUSE_DAEMON_TASK_STARTUP_HOOK 0
|
||||
|
||||
/* Run time and task stats gathering related definitions. */
|
||||
#define configGENERATE_RUN_TIME_STATS 0
|
||||
#define configUSE_TRACE_FACILITY 1
|
||||
#define configUSE_STATS_FORMATTING_FUNCTIONS 0
|
||||
|
||||
/* Co-routine related definitions. */
|
||||
#define configUSE_CO_ROUTINES 0
|
||||
#define configMAX_CO_ROUTINE_PRIORITIES 1
|
||||
|
||||
/* Software timer related definitions. */
|
||||
#define configUSE_TIMERS 1
|
||||
#define configTIMER_TASK_PRIORITY ( configMAX_PRIORITIES - 1 )
|
||||
#define configTIMER_QUEUE_LENGTH 10
|
||||
#define configTIMER_TASK_STACK_DEPTH 1024
|
||||
|
||||
/* Interrupt nesting behaviour configuration. */
|
||||
/*
|
||||
#define configKERNEL_INTERRUPT_PRIORITY [dependent of processor]
|
||||
#define configMAX_SYSCALL_INTERRUPT_PRIORITY [dependent on processor and application]
|
||||
#define configMAX_API_CALL_INTERRUPT_PRIORITY [dependent on processor and application]
|
||||
*/
|
||||
|
||||
#if FREE_RTOS_KERNEL_SMP // set by the RP2040 SMP port of FreeRTOS
|
||||
/* SMP port only */
|
||||
#define configNUM_CORES 2
|
||||
#define configTICK_CORE 0
|
||||
#define configRUN_MULTIPLE_PRIORITIES 1
|
||||
#define configUSE_CORE_AFFINITY 1
|
||||
#endif
|
||||
|
||||
/* RP2040 specific */
|
||||
#define configSUPPORT_PICO_SYNC_INTEROP 1
|
||||
#define configSUPPORT_PICO_TIME_INTEROP 1
|
||||
|
||||
#include <assert.h>
|
||||
/* Define to trap errors during development. */
|
||||
#define configASSERT(x) assert(x)
|
||||
|
||||
/* Set the following definitions to 1 to include the API function, or zero
|
||||
to exclude the API function. */
|
||||
#define INCLUDE_vTaskPrioritySet 1
|
||||
#define INCLUDE_uxTaskPriorityGet 1
|
||||
#define INCLUDE_vTaskDelete 1
|
||||
#define INCLUDE_vTaskSuspend 1
|
||||
#define INCLUDE_vTaskDelayUntil 1
|
||||
#define INCLUDE_vTaskDelay 1
|
||||
#define INCLUDE_xTaskGetSchedulerState 1
|
||||
#define INCLUDE_xTaskGetCurrentTaskHandle 1
|
||||
#define INCLUDE_uxTaskGetStackHighWaterMark 1
|
||||
#define INCLUDE_xTaskGetIdleTaskHandle 1
|
||||
#define INCLUDE_eTaskGetState 1
|
||||
#define INCLUDE_xTimerPendFunctionCall 1
|
||||
#define INCLUDE_xTaskAbortDelay 1
|
||||
#define INCLUDE_xTaskGetHandle 1
|
||||
#define INCLUDE_xTaskResumeFromISR 1
|
||||
#define INCLUDE_xQueueGetMutexHolder 1
|
||||
|
||||
/* A header file that defines trace macro can be included here. */
|
||||
|
||||
#endif /* FREERTOS_CONFIG_H */
|
||||
|
||||
21
pico_w/freertos/iperf/lwipopts.h
Normal file
21
pico_w/freertos/iperf/lwipopts.h
Normal file
@ -0,0 +1,21 @@
|
||||
#ifndef _LWIPOPTS_H
|
||||
#define _LWIPOPTS_H
|
||||
|
||||
// Generally you would define your own explicit list of lwIP options
|
||||
// (see https://www.nongnu.org/lwip/2_1_x/group__lwip__opts.html)
|
||||
//
|
||||
// This example uses a common include to avoid repetition
|
||||
#include "lwipopts_examples_common.h"
|
||||
|
||||
#if !NO_SYS
|
||||
#define TCPIP_THREAD_STACKSIZE 1024
|
||||
#define DEFAULT_THREAD_STACKSIZE 1024
|
||||
#define DEFAULT_RAW_RECVMBOX_SIZE 8
|
||||
#define TCPIP_MBOX_SIZE 8
|
||||
#define LWIP_TIMEVAL_PRIVATE 0
|
||||
|
||||
// not necessary, can be done either way
|
||||
#define LWIP_TCPIP_CORE_LOCKING_INPUT 1
|
||||
#endif
|
||||
|
||||
#endif
|
||||
132
pico_w/freertos/iperf/picow_freertos_iperf.c
Normal file
132
pico_w/freertos/iperf/picow_freertos_iperf.c
Normal file
@ -0,0 +1,132 @@
|
||||
/**
|
||||
* Copyright (c) 2022 Raspberry Pi (Trading) Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#include "pico/cyw43_arch.h"
|
||||
#include "pico/stdlib.h"
|
||||
|
||||
#include "lwip/netif.h"
|
||||
#include "lwip/ip4_addr.h"
|
||||
#include "lwip/apps/lwiperf.h"
|
||||
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
|
||||
#ifndef RUN_FREERTOS_ON_CORE
|
||||
#define RUN_FREERTOS_ON_CORE 0
|
||||
#endif
|
||||
|
||||
#define TEST_TASK_PRIORITY ( tskIDLE_PRIORITY + 2UL )
|
||||
#define BLINK_TASK_PRIORITY ( tskIDLE_PRIORITY + 1UL )
|
||||
|
||||
#if CLIENT_TEST && !defined(IPERF_SERVER_IP)
|
||||
#error IPERF_SERVER_IP not defined
|
||||
#endif
|
||||
|
||||
// Report IP results and exit
|
||||
static void iperf_report(void *arg, enum lwiperf_report_type report_type,
|
||||
const ip_addr_t *local_addr, u16_t local_port, const ip_addr_t *remote_addr, u16_t remote_port,
|
||||
u32_t bytes_transferred, u32_t ms_duration, u32_t bandwidth_kbitpsec) {
|
||||
static uint32_t total_iperf_megabytes = 0;
|
||||
uint32_t mbytes = bytes_transferred / 1024 / 1024;
|
||||
float mbits = bandwidth_kbitpsec / 1000.0;
|
||||
|
||||
total_iperf_megabytes += mbytes;
|
||||
|
||||
printf("Completed iperf transfer of %d MBytes @ %.1f Mbits/sec\n", mbytes, mbits);
|
||||
printf("Total iperf megabytes since start %d Mbytes\n", total_iperf_megabytes);
|
||||
}
|
||||
|
||||
void blink_task(__unused void *params) {
|
||||
bool on = false;
|
||||
printf("blink_task starts\n");
|
||||
while (true) {
|
||||
#if 0 && configNUM_CORES > 1
|
||||
static int last_core_id;
|
||||
if (portGET_CORE_ID() != last_core_id) {
|
||||
last_core_id = portGET_CORE_ID();
|
||||
printf("blinking now from core %d\n", last_core_id);
|
||||
}
|
||||
#endif
|
||||
cyw43_arch_gpio_put(0, on);
|
||||
on = !on;
|
||||
vTaskDelay(200);
|
||||
}
|
||||
}
|
||||
|
||||
void main_task(__unused void *params) {
|
||||
if (cyw43_arch_init()) {
|
||||
printf("failed to initialise\n");
|
||||
return;
|
||||
}
|
||||
cyw43_arch_enable_sta_mode();
|
||||
printf("Connecting to WiFi...\n");
|
||||
if (cyw43_arch_wifi_connect_timeout_ms(WIFI_SSID, WIFI_PASSWORD, CYW43_AUTH_WPA2_AES_PSK, 30000)) {
|
||||
printf("failed to connect.\n");
|
||||
exit(1);
|
||||
} else {
|
||||
printf("Connected.\n");
|
||||
}
|
||||
|
||||
xTaskCreate(blink_task, "BlinkThread", configMINIMAL_STACK_SIZE, NULL, BLINK_TASK_PRIORITY, NULL);
|
||||
|
||||
#if CLIENT_TEST
|
||||
printf("\nReady, running iperf client\n");
|
||||
ip_addr_t clientaddr;
|
||||
ip4_addr_set_u32(&clientaddr, ipaddr_addr(xstr(IPERF_SERVER_IP)));
|
||||
assert(lwiperf_start_tcp_client_default(&clientaddr, &iperf_report, NULL) != NULL);
|
||||
#else
|
||||
printf("\nReady, running iperf server at %s\n", ip4addr_ntoa(netif_ip4_addr(netif_list)));
|
||||
lwiperf_start_tcp_server_default(&iperf_report, NULL);
|
||||
#endif
|
||||
|
||||
while(true) {
|
||||
// not much to do as LED is in another task, and we're using RAW (callback) lwIP API
|
||||
vTaskDelay(100);
|
||||
}
|
||||
|
||||
cyw43_arch_deinit();
|
||||
}
|
||||
|
||||
void vLaunch( void) {
|
||||
TaskHandle_t task;
|
||||
xTaskCreate(main_task, "TestMainThread", configMINIMAL_STACK_SIZE, NULL, TEST_TASK_PRIORITY, &task);
|
||||
|
||||
#if NO_SYS && configUSE_CORE_AFFINITY && configNUM_CORES > 1
|
||||
// we must bind the main task to one core (well at least while the init is called)
|
||||
// (note we only do this in NO_SYS mode, because cyw43_arch_freertos
|
||||
// takes care of it otherwise)
|
||||
vTaskCoreAffinitySet(task, 1);
|
||||
#endif
|
||||
|
||||
/* Start the tasks and timer running. */
|
||||
vTaskStartScheduler();
|
||||
}
|
||||
|
||||
int main( void )
|
||||
{
|
||||
stdio_init_all();
|
||||
|
||||
/* Configure the hardware ready to run the demo. */
|
||||
const char *rtos_name;
|
||||
#if ( portSUPPORT_SMP == 1 )
|
||||
rtos_name = "FreeRTOS SMP";
|
||||
#else
|
||||
rtos_name = "FreeRTOS";
|
||||
#endif
|
||||
|
||||
#if ( portSUPPORT_SMP == 1 ) && ( configNUM_CORES == 2 )
|
||||
printf("Starting %s on both cores:\n", rtos_name);
|
||||
vLaunch();
|
||||
#elif ( RUN_FREE_RTOS_ON_CORE == 1 )
|
||||
printf("Starting %s on core 1:\n", rtos_name);
|
||||
multicore_launch_core1(vLaunch);
|
||||
while (true);
|
||||
#else
|
||||
printf("Starting %s on core 0:\n", rtos_name);
|
||||
vLaunch();
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
46
pico_w/freertos/ping/CMakeLists.txt
Normal file
46
pico_w/freertos/ping/CMakeLists.txt
Normal file
@ -0,0 +1,46 @@
|
||||
if (EXISTS ${PICO_LWIP_CONTRIB_PATH}/apps/ping/ping.c)
|
||||
add_executable(picow_freertos_ping_nosys
|
||||
picow_freertos_ping.c
|
||||
${PICO_LWIP_CONTRIB_PATH}/apps/ping/ping.c
|
||||
)
|
||||
target_compile_definitions(picow_freertos_ping_nosys PRIVATE
|
||||
WIFI_SSID=\"${WIFI_SSID}\"
|
||||
WIFI_PASSWORD=\"${WIFI_PASSWORD}\"
|
||||
)
|
||||
target_include_directories(picow_freertos_ping_nosys PRIVATE
|
||||
${CMAKE_CURRENT_LIST_DIR}
|
||||
${CMAKE_CURRENT_LIST_DIR}/../.. # for our common lwipopts
|
||||
${PICO_LWIP_CONTRIB_PATH}/apps/ping
|
||||
)
|
||||
target_link_libraries(picow_freertos_ping_nosys
|
||||
pico_cyw43_arch_lwip_threadsafe_background
|
||||
pico_stdlib
|
||||
pico_lwip_iperf
|
||||
FreeRTOS-Kernel-Heap4 # FreeRTOS kernel and dynamic heap
|
||||
)
|
||||
pico_add_extra_outputs(picow_freertos_ping_nosys)
|
||||
|
||||
add_executable(picow_freertos_ping_sys
|
||||
picow_freertos_ping.c
|
||||
${PICO_LWIP_CONTRIB_PATH}/apps/ping/ping.c
|
||||
)
|
||||
target_compile_definitions(picow_freertos_ping_sys PRIVATE
|
||||
WIFI_SSID=\"${WIFI_SSID}\"
|
||||
WIFI_PASSWORD=\"${WIFI_PASSWORD}\"
|
||||
NO_SYS=0 # don't want NO_SYS (generally this would be in your lwipopts.h)
|
||||
LWIP_SOCKET=1 # we need the socket API (generally this would be in your lwipopts.h)
|
||||
PING_USE_SOCKETS=1
|
||||
)
|
||||
target_include_directories(picow_freertos_ping_sys PRIVATE
|
||||
${CMAKE_CURRENT_LIST_DIR}
|
||||
${CMAKE_CURRENT_LIST_DIR}/../.. # for our common lwipopts
|
||||
${PICO_LWIP_CONTRIB_PATH}/apps/ping
|
||||
)
|
||||
target_link_libraries(picow_freertos_ping_sys
|
||||
pico_cyw43_arch_lwip_sys_freertos
|
||||
pico_stdlib
|
||||
pico_lwip_iperf
|
||||
FreeRTOS-Kernel-Heap4 # FreeRTOS kernel and dynamic heap
|
||||
)
|
||||
pico_add_extra_outputs(picow_freertos_ping_sys)
|
||||
endif()
|
||||
143
pico_w/freertos/ping/FreeRTOSConfig.h
Normal file
143
pico_w/freertos/ping/FreeRTOSConfig.h
Normal file
@ -0,0 +1,143 @@
|
||||
/*
|
||||
* FreeRTOS V202111.00
|
||||
* Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* http://www.FreeRTOS.org
|
||||
* http://aws.amazon.com/freertos
|
||||
*
|
||||
* 1 tab == 4 spaces!
|
||||
*/
|
||||
|
||||
#ifndef FREERTOS_CONFIG_H
|
||||
#define FREERTOS_CONFIG_H
|
||||
|
||||
/*-----------------------------------------------------------
|
||||
* Application specific definitions.
|
||||
*
|
||||
* These definitions should be adjusted for your particular hardware and
|
||||
* application requirements.
|
||||
*
|
||||
* THESE PARAMETERS ARE DESCRIBED WITHIN THE 'CONFIGURATION' SECTION OF THE
|
||||
* FreeRTOS API DOCUMENTATION AVAILABLE ON THE FreeRTOS.org WEB SITE.
|
||||
*
|
||||
* See http://www.freertos.org/a00110.html
|
||||
*----------------------------------------------------------*/
|
||||
|
||||
/* Scheduler Related */
|
||||
#define configUSE_PREEMPTION 1
|
||||
#define configUSE_TICKLESS_IDLE 0
|
||||
#define configUSE_IDLE_HOOK 0
|
||||
#define configUSE_TICK_HOOK 0
|
||||
#define configTICK_RATE_HZ ( ( TickType_t ) 1000 )
|
||||
#define configMAX_PRIORITIES 32
|
||||
#define configMINIMAL_STACK_SIZE ( configSTACK_DEPTH_TYPE ) 256
|
||||
#define configUSE_16_BIT_TICKS 0
|
||||
|
||||
#define configIDLE_SHOULD_YIELD 1
|
||||
|
||||
/* Synchronization Related */
|
||||
#define configUSE_MUTEXES 1
|
||||
#define configUSE_RECURSIVE_MUTEXES 1
|
||||
#define configUSE_APPLICATION_TASK_TAG 0
|
||||
#define configUSE_COUNTING_SEMAPHORES 1
|
||||
#define configQUEUE_REGISTRY_SIZE 8
|
||||
#define configUSE_QUEUE_SETS 1
|
||||
#define configUSE_TIME_SLICING 1
|
||||
#define configUSE_NEWLIB_REENTRANT 0
|
||||
// todo need this for lwip FreeRTOS sys_arch to compile
|
||||
#define configENABLE_BACKWARD_COMPATIBILITY 1
|
||||
#define configNUM_THREAD_LOCAL_STORAGE_POINTERS 5
|
||||
|
||||
/* System */
|
||||
#define configSTACK_DEPTH_TYPE uint32_t
|
||||
#define configMESSAGE_BUFFER_LENGTH_TYPE size_t
|
||||
|
||||
/* Memory allocation related definitions. */
|
||||
#define configSUPPORT_STATIC_ALLOCATION 0
|
||||
#define configSUPPORT_DYNAMIC_ALLOCATION 1
|
||||
#define configTOTAL_HEAP_SIZE (128*1024)
|
||||
#define configAPPLICATION_ALLOCATED_HEAP 0
|
||||
|
||||
/* Hook function related definitions. */
|
||||
#define configCHECK_FOR_STACK_OVERFLOW 0
|
||||
#define configUSE_MALLOC_FAILED_HOOK 0
|
||||
#define configUSE_DAEMON_TASK_STARTUP_HOOK 0
|
||||
|
||||
/* Run time and task stats gathering related definitions. */
|
||||
#define configGENERATE_RUN_TIME_STATS 0
|
||||
#define configUSE_TRACE_FACILITY 1
|
||||
#define configUSE_STATS_FORMATTING_FUNCTIONS 0
|
||||
|
||||
/* Co-routine related definitions. */
|
||||
#define configUSE_CO_ROUTINES 0
|
||||
#define configMAX_CO_ROUTINE_PRIORITIES 1
|
||||
|
||||
/* Software timer related definitions. */
|
||||
#define configUSE_TIMERS 1
|
||||
#define configTIMER_TASK_PRIORITY ( configMAX_PRIORITIES - 1 )
|
||||
#define configTIMER_QUEUE_LENGTH 10
|
||||
#define configTIMER_TASK_STACK_DEPTH 1024
|
||||
|
||||
/* Interrupt nesting behaviour configuration. */
|
||||
/*
|
||||
#define configKERNEL_INTERRUPT_PRIORITY [dependent of processor]
|
||||
#define configMAX_SYSCALL_INTERRUPT_PRIORITY [dependent on processor and application]
|
||||
#define configMAX_API_CALL_INTERRUPT_PRIORITY [dependent on processor and application]
|
||||
*/
|
||||
|
||||
#if FREE_RTOS_KERNEL_SMP // set by the RP2040 SMP port of FreeRTOS
|
||||
/* SMP port only */
|
||||
#define configNUM_CORES 2
|
||||
#define configTICK_CORE 0
|
||||
#define configRUN_MULTIPLE_PRIORITIES 1
|
||||
#define configUSE_CORE_AFFINITY 1
|
||||
#endif
|
||||
|
||||
/* RP2040 specific */
|
||||
#define configSUPPORT_PICO_SYNC_INTEROP 1
|
||||
#define configSUPPORT_PICO_TIME_INTEROP 1
|
||||
|
||||
#include <assert.h>
|
||||
/* Define to trap errors during development. */
|
||||
#define configASSERT(x) assert(x)
|
||||
|
||||
/* Set the following definitions to 1 to include the API function, or zero
|
||||
to exclude the API function. */
|
||||
#define INCLUDE_vTaskPrioritySet 1
|
||||
#define INCLUDE_uxTaskPriorityGet 1
|
||||
#define INCLUDE_vTaskDelete 1
|
||||
#define INCLUDE_vTaskSuspend 1
|
||||
#define INCLUDE_vTaskDelayUntil 1
|
||||
#define INCLUDE_vTaskDelay 1
|
||||
#define INCLUDE_xTaskGetSchedulerState 1
|
||||
#define INCLUDE_xTaskGetCurrentTaskHandle 1
|
||||
#define INCLUDE_uxTaskGetStackHighWaterMark 1
|
||||
#define INCLUDE_xTaskGetIdleTaskHandle 1
|
||||
#define INCLUDE_eTaskGetState 1
|
||||
#define INCLUDE_xTimerPendFunctionCall 1
|
||||
#define INCLUDE_xTaskAbortDelay 1
|
||||
#define INCLUDE_xTaskGetHandle 1
|
||||
#define INCLUDE_xTaskResumeFromISR 1
|
||||
#define INCLUDE_xQueueGetMutexHolder 1
|
||||
|
||||
/* A header file that defines trace macro can be included here. */
|
||||
|
||||
#endif /* FREERTOS_CONFIG_H */
|
||||
|
||||
21
pico_w/freertos/ping/lwipopts.h
Normal file
21
pico_w/freertos/ping/lwipopts.h
Normal file
@ -0,0 +1,21 @@
|
||||
#ifndef _LWIPOPTS_H
|
||||
#define _LWIPOPTS_H
|
||||
|
||||
// Generally you would define your own explicit list of lwIP options
|
||||
// (see https://www.nongnu.org/lwip/2_1_x/group__lwip__opts.html)
|
||||
//
|
||||
// This example uses a common include to avoid repetition
|
||||
#include "lwipopts_examples_common.h"
|
||||
|
||||
#if !NO_SYS
|
||||
#define TCPIP_THREAD_STACKSIZE 1024
|
||||
#define DEFAULT_THREAD_STACKSIZE 1024
|
||||
#define DEFAULT_RAW_RECVMBOX_SIZE 8
|
||||
#define TCPIP_MBOX_SIZE 8
|
||||
#define LWIP_TIMEVAL_PRIVATE 0
|
||||
|
||||
// not necessary, can be done either way
|
||||
#define LWIP_TCPIP_CORE_LOCKING_INPUT 1
|
||||
#endif
|
||||
|
||||
#endif
|
||||
90
pico_w/freertos/ping/picow_freertos_ping.c
Normal file
90
pico_w/freertos/ping/picow_freertos_ping.c
Normal file
@ -0,0 +1,90 @@
|
||||
/**
|
||||
* Copyright (c) 2022 Raspberry Pi (Trading) Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#include "pico/cyw43_arch.h"
|
||||
#include "pico/stdlib.h"
|
||||
|
||||
#include "lwip/ip4_addr.h"
|
||||
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
#include "ping.h"
|
||||
|
||||
#ifndef PING_ADDR
|
||||
#define PING_ADDR "142.251.35.196"
|
||||
#endif
|
||||
#ifndef RUN_FREERTOS_ON_CORE
|
||||
#define RUN_FREERTOS_ON_CORE 0
|
||||
#endif
|
||||
|
||||
#define TEST_TASK_PRIORITY ( tskIDLE_PRIORITY + 1UL )
|
||||
|
||||
void main_task(__unused void *params) {
|
||||
if (cyw43_arch_init()) {
|
||||
printf("failed to initialise\n");
|
||||
return;
|
||||
}
|
||||
cyw43_arch_enable_sta_mode();
|
||||
printf("Connecting to WiFi...\n");
|
||||
if (cyw43_arch_wifi_connect_timeout_ms(WIFI_SSID, WIFI_PASSWORD, CYW43_AUTH_WPA2_AES_PSK, 30000)) {
|
||||
printf("failed to connect.\n");
|
||||
exit(1);
|
||||
} else {
|
||||
printf("Connected.\n");
|
||||
}
|
||||
|
||||
ip_addr_t ping_addr;
|
||||
ip4_addr_set_u32(&ping_addr, ipaddr_addr(PING_ADDR));
|
||||
ping_init(&ping_addr);
|
||||
|
||||
while(true) {
|
||||
// not much to do as LED is in another task, and we're using RAW (callback) lwIP API
|
||||
vTaskDelay(100);
|
||||
}
|
||||
|
||||
cyw43_arch_deinit();
|
||||
}
|
||||
|
||||
void vLaunch( void) {
|
||||
TaskHandle_t task;
|
||||
xTaskCreate(main_task, "TestMainThread", configMINIMAL_STACK_SIZE, NULL, TEST_TASK_PRIORITY, &task);
|
||||
|
||||
#if NO_SYS && configUSE_CORE_AFFINITY && configNUM_CORES > 1
|
||||
// we must bind the main task to one core (well at least while the init is called)
|
||||
// (note we only do this in NO_SYS mode, because cyw43_arch_freertos
|
||||
// takes care of it otherwise)
|
||||
vTaskCoreAffinitySet(task, 1);
|
||||
#endif
|
||||
|
||||
/* Start the tasks and timer running. */
|
||||
vTaskStartScheduler();
|
||||
}
|
||||
|
||||
int main( void )
|
||||
{
|
||||
stdio_init_all();
|
||||
|
||||
/* Configure the hardware ready to run the demo. */
|
||||
const char *rtos_name;
|
||||
#if ( portSUPPORT_SMP == 1 )
|
||||
rtos_name = "FreeRTOS SMP";
|
||||
#else
|
||||
rtos_name = "FreeRTOS";
|
||||
#endif
|
||||
|
||||
#if ( portSUPPORT_SMP == 1 ) && ( configNUM_CORES == 2 )
|
||||
printf("Starting %s on both cores:\n", rtos_name);
|
||||
vLaunch();
|
||||
#elif ( RUN_FREE_RTOS_ON_CORE == 1 )
|
||||
printf("Starting %s on core 1:\n", rtos_name);
|
||||
multicore_launch_core1(vLaunch);
|
||||
while (true);
|
||||
#else
|
||||
printf("Starting %s on core 0:\n", rtos_name);
|
||||
vLaunch();
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
37
pico_w/iperf/CMakeLists.txt
Normal file
37
pico_w/iperf/CMakeLists.txt
Normal file
@ -0,0 +1,37 @@
|
||||
add_executable(picow_iperf_server_background
|
||||
picow_iperf.c
|
||||
)
|
||||
target_compile_definitions(picow_iperf_server_background PRIVATE
|
||||
WIFI_SSID=\"${WIFI_SSID}\"
|
||||
WIFI_PASSWORD=\"${WIFI_PASSWORD}\"
|
||||
)
|
||||
target_include_directories(picow_iperf_server_background PRIVATE
|
||||
${CMAKE_CURRENT_LIST_DIR}
|
||||
${CMAKE_CURRENT_LIST_DIR}/.. # for our common lwipopts
|
||||
)
|
||||
target_link_libraries(picow_iperf_server_background
|
||||
pico_cyw43_arch_lwip_threadsafe_background
|
||||
pico_stdlib
|
||||
pico_lwip_iperf
|
||||
)
|
||||
|
||||
pico_add_extra_outputs(picow_iperf_server_background)
|
||||
|
||||
add_executable(picow_iperf_server_poll
|
||||
picow_iperf.c
|
||||
)
|
||||
target_compile_definitions(picow_iperf_server_poll PRIVATE
|
||||
WIFI_SSID=\"${WIFI_SSID}\"
|
||||
WIFI_PASSWORD=\"${WIFI_PASSWORD}\"
|
||||
)
|
||||
target_include_directories(picow_iperf_server_poll PRIVATE
|
||||
${CMAKE_CURRENT_LIST_DIR}
|
||||
${CMAKE_CURRENT_LIST_DIR}/.. # for our common lwipopts
|
||||
)
|
||||
target_link_libraries(picow_iperf_server_poll
|
||||
pico_cyw43_arch_lwip_poll
|
||||
pico_stdlib
|
||||
pico_lwip_iperf
|
||||
)
|
||||
pico_add_extra_outputs(picow_iperf_server_poll)
|
||||
|
||||
10
pico_w/iperf/lwipopts.h
Normal file
10
pico_w/iperf/lwipopts.h
Normal file
@ -0,0 +1,10 @@
|
||||
#ifndef _LWIPOPTS_H
|
||||
#define _LWIPOPTS_H
|
||||
|
||||
// Generally you would define your own explicit list of lwIP options
|
||||
// (see https://www.nongnu.org/lwip/2_1_x/group__lwip__opts.html)
|
||||
//
|
||||
// This example uses a common include to avoid repetition
|
||||
#include "lwipopts_examples_common.h"
|
||||
|
||||
#endif
|
||||
99
pico_w/iperf/picow_iperf.c
Normal file
99
pico_w/iperf/picow_iperf.c
Normal file
@ -0,0 +1,99 @@
|
||||
/**
|
||||
* Copyright (c) 2022 Raspberry Pi (Trading) Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#include "pico/cyw43_arch.h"
|
||||
#include "pico/stdlib.h"
|
||||
|
||||
#include "lwip/netif.h"
|
||||
#include "lwip/ip4_addr.h"
|
||||
#include "lwip/apps/lwiperf.h"
|
||||
|
||||
#ifndef USE_LED
|
||||
#define USE_LED 1
|
||||
#endif
|
||||
|
||||
#if CLIENT_TEST && !defined(IPERF_SERVER_IP)
|
||||
#error IPERF_SERVER_IP not defined
|
||||
#endif
|
||||
|
||||
// Report IP results and exit
|
||||
static void iperf_report(void *arg, enum lwiperf_report_type report_type,
|
||||
const ip_addr_t *local_addr, u16_t local_port, const ip_addr_t *remote_addr, u16_t remote_port,
|
||||
u32_t bytes_transferred, u32_t ms_duration, u32_t bandwidth_kbitpsec) {
|
||||
static uint32_t total_iperf_megabytes = 0;
|
||||
uint32_t mbytes = bytes_transferred / 1024 / 1024;
|
||||
float mbits = bandwidth_kbitpsec / 1000.0;
|
||||
|
||||
total_iperf_megabytes += mbytes;
|
||||
|
||||
printf("Completed iperf transfer of %d MBytes @ %.1f Mbits/sec\n", mbytes, mbits);
|
||||
printf("Total iperf megabytes since start %d Mbytes\n", total_iperf_megabytes);
|
||||
#if CYW43_USE_STATS
|
||||
printf("packets in %u packets out %u\n", CYW43_STAT_GET(PACKET_IN_COUNT), CYW43_STAT_GET(PACKET_OUT_COUNT));
|
||||
#endif
|
||||
}
|
||||
|
||||
int main() {
|
||||
stdio_init_all();
|
||||
|
||||
if (cyw43_arch_init()) {
|
||||
printf("failed to initialise\n");
|
||||
return 1;
|
||||
}
|
||||
cyw43_arch_enable_sta_mode();
|
||||
printf("Connecting to WiFi...\n");
|
||||
if (cyw43_arch_wifi_connect_timeout_ms(WIFI_SSID, WIFI_PASSWORD, CYW43_AUTH_WPA2_AES_PSK, 30000)) {
|
||||
printf("failed to connect.\n");
|
||||
return 1;
|
||||
} else {
|
||||
printf("Connected.\n");
|
||||
}
|
||||
|
||||
#if CLIENT_TEST
|
||||
printf("\nReady, running iperf client\n");
|
||||
ip_addr_t clientaddr;
|
||||
ip4_addr_set_u32(&clientaddr, ipaddr_addr(xstr(IPERF_SERVER_IP)));
|
||||
assert(lwiperf_start_tcp_client_default(&clientaddr, &iperf_report, NULL) != NULL);
|
||||
#else
|
||||
printf("\nReady, running iperf server at %s\n", ip4addr_ntoa(netif_ip4_addr(netif_list)));
|
||||
lwiperf_start_tcp_server_default(&iperf_report, NULL);
|
||||
#endif
|
||||
|
||||
while(true) {
|
||||
#if USE_LED
|
||||
static absolute_time_t led_time;
|
||||
static int led_on = true;
|
||||
|
||||
// Invert the led
|
||||
if (absolute_time_diff_us(get_absolute_time(), led_time) < 0) {
|
||||
led_on = !led_on;
|
||||
cyw43_gpio_set(&cyw43_state, 0, led_on);
|
||||
led_time = make_timeout_time_ms(1000);
|
||||
|
||||
// Check we can read back the led value
|
||||
bool actual_led_val = !led_on;
|
||||
cyw43_gpio_get(&cyw43_state, 0, &actual_led_val);
|
||||
assert(led_on == actual_led_val);
|
||||
}
|
||||
#endif
|
||||
// the following #ifdef is only here so this same example can be used in multiple modes;
|
||||
// you do not need it in your code
|
||||
#if PICO_CYW43_ARCH_POLL
|
||||
// if you are using pico_cyw43_arch_poll, then you must poll periodically from your
|
||||
// main loop (not from a timer) to check for WiFi driver or lwIP work that needs to be done.
|
||||
cyw43_arch_poll();
|
||||
sleep_ms(1);
|
||||
#else
|
||||
// if you are not using pico_cyw43_arch_poll, then WiFI driver and lwIP work
|
||||
// is done via interrupt in the background. This sleep is just an example of some (blocking)
|
||||
// work you might be doing.
|
||||
sleep_ms(1000);
|
||||
#endif
|
||||
}
|
||||
|
||||
cyw43_arch_deinit();
|
||||
return 0;
|
||||
}
|
||||
90
pico_w/lwipopts_examples_common.h
Normal file
90
pico_w/lwipopts_examples_common.h
Normal file
@ -0,0 +1,90 @@
|
||||
#ifndef _LWIPOPTS_EXAMPLE_COMMONH_H
|
||||
#define _LWIPOPTS_EXAMPLE_COMMONH_H
|
||||
|
||||
|
||||
// Common settings used in most of the pico_w examples
|
||||
// (see https://www.nongnu.org/lwip/2_1_x/group__lwip__opts.html for details)
|
||||
|
||||
// allow override in some examples
|
||||
#ifndef NO_SYS
|
||||
#define NO_SYS 1
|
||||
#endif
|
||||
// allow override in some examples
|
||||
#ifndef LWIP_SOCKET
|
||||
#define LWIP_SOCKET 0
|
||||
#endif
|
||||
#if PICO_CYW43_ARCH_POLL
|
||||
#define MEM_LIBC_MALLOC 1
|
||||
#else
|
||||
// MEM_LIBC_MALLOC is incompatible with non polling versions
|
||||
#define MEM_LIBC_MALLOC 0
|
||||
#endif
|
||||
#define MEM_ALIGNMENT 4
|
||||
#define MEM_SIZE 4000
|
||||
#define MEMP_NUM_TCP_SEG 32
|
||||
#define MEMP_NUM_ARP_QUEUE 10
|
||||
#define PBUF_POOL_SIZE 24
|
||||
#define LWIP_ARP 1
|
||||
#define LWIP_ETHERNET 1
|
||||
#define LWIP_ICMP 1
|
||||
#define LWIP_RAW 1
|
||||
#define TCP_WND (8 * TCP_MSS)
|
||||
#define TCP_MSS 1460
|
||||
#define TCP_SND_BUF (8 * TCP_MSS)
|
||||
#define TCP_SND_QUEUELEN ((4 * (TCP_SND_BUF) + (TCP_MSS - 1)) / (TCP_MSS))
|
||||
#define LWIP_NETIF_STATUS_CALLBACK 1
|
||||
#define LWIP_NETIF_LINK_CALLBACK 1
|
||||
#define LWIP_NETIF_HOSTNAME 1
|
||||
#define LWIP_NETCONN 0
|
||||
#define MEM_STATS 0
|
||||
#define SYS_STATS 0
|
||||
#define MEMP_STATS 0
|
||||
#define LINK_STATS 0
|
||||
// #define ETH_PAD_SIZE 2
|
||||
#define LWIP_CHKSUM_ALGORITHM 3
|
||||
#define LWIP_DHCP 1
|
||||
#define LWIP_IPV4 1
|
||||
#define LWIP_TCP 1
|
||||
#define LWIP_UDP 1
|
||||
#define LWIP_DNS 1
|
||||
#define LWIP_TCP_KEEPALIVE 1
|
||||
#define LWIP_NETIF_TX_SINGLE_PBUF 1
|
||||
#define DHCP_DOES_ARP_CHECK 0
|
||||
#define LWIP_DHCP_DOES_ACD_CHECK 0
|
||||
|
||||
#ifndef NDEBUG
|
||||
#define LWIP_DEBUG 1
|
||||
#define LWIP_STATS 1
|
||||
#define LWIP_STATS_DISPLAY 1
|
||||
#endif
|
||||
|
||||
#define ETHARP_DEBUG LWIP_DBG_OFF
|
||||
#define NETIF_DEBUG LWIP_DBG_OFF
|
||||
#define PBUF_DEBUG LWIP_DBG_OFF
|
||||
#define API_LIB_DEBUG LWIP_DBG_OFF
|
||||
#define API_MSG_DEBUG LWIP_DBG_OFF
|
||||
#define SOCKETS_DEBUG LWIP_DBG_OFF
|
||||
#define ICMP_DEBUG LWIP_DBG_OFF
|
||||
#define INET_DEBUG LWIP_DBG_OFF
|
||||
#define IP_DEBUG LWIP_DBG_OFF
|
||||
#define IP_REASS_DEBUG LWIP_DBG_OFF
|
||||
#define RAW_DEBUG LWIP_DBG_OFF
|
||||
#define MEM_DEBUG LWIP_DBG_OFF
|
||||
#define MEMP_DEBUG LWIP_DBG_OFF
|
||||
#define SYS_DEBUG LWIP_DBG_OFF
|
||||
#define TCP_DEBUG LWIP_DBG_OFF
|
||||
#define TCP_INPUT_DEBUG LWIP_DBG_OFF
|
||||
#define TCP_OUTPUT_DEBUG LWIP_DBG_OFF
|
||||
#define TCP_RTO_DEBUG LWIP_DBG_OFF
|
||||
#define TCP_CWND_DEBUG LWIP_DBG_OFF
|
||||
#define TCP_WND_DEBUG LWIP_DBG_OFF
|
||||
#define TCP_FR_DEBUG LWIP_DBG_OFF
|
||||
#define TCP_QLEN_DEBUG LWIP_DBG_OFF
|
||||
#define TCP_RST_DEBUG LWIP_DBG_OFF
|
||||
#define UDP_DEBUG LWIP_DBG_OFF
|
||||
#define TCPIP_DEBUG LWIP_DBG_OFF
|
||||
#define PPP_DEBUG LWIP_DBG_OFF
|
||||
#define SLIP_DEBUG LWIP_DBG_OFF
|
||||
#define DHCP_DEBUG LWIP_DBG_OFF
|
||||
|
||||
#endif /* __LWIPOPTS_H__ */
|
||||
35
pico_w/ntp_client/CMakeLists.txt
Normal file
35
pico_w/ntp_client/CMakeLists.txt
Normal file
@ -0,0 +1,35 @@
|
||||
add_executable(picow_ntp_client_background
|
||||
picow_ntp_client.c
|
||||
)
|
||||
target_compile_definitions(picow_ntp_client_background PRIVATE
|
||||
WIFI_SSID=\"${WIFI_SSID}\"
|
||||
WIFI_PASSWORD=\"${WIFI_PASSWORD}\"
|
||||
)
|
||||
target_include_directories(picow_ntp_client_background PRIVATE
|
||||
${CMAKE_CURRENT_LIST_DIR}
|
||||
${CMAKE_CURRENT_LIST_DIR}/.. # for our common lwipopts
|
||||
)
|
||||
target_link_libraries(picow_ntp_client_background
|
||||
pico_cyw43_arch_lwip_threadsafe_background
|
||||
pico_stdlib
|
||||
)
|
||||
|
||||
pico_add_extra_outputs(picow_ntp_client_background)
|
||||
|
||||
add_executable(picow_ntp_client_poll
|
||||
picow_ntp_client.c
|
||||
)
|
||||
target_compile_definitions(picow_ntp_client_poll PRIVATE
|
||||
WIFI_SSID=\"${WIFI_SSID}\"
|
||||
WIFI_PASSWORD=\"${WIFI_PASSWORD}\"
|
||||
)
|
||||
target_include_directories(picow_ntp_client_poll PRIVATE
|
||||
${CMAKE_CURRENT_LIST_DIR}
|
||||
${CMAKE_CURRENT_LIST_DIR}/.. # for our common lwipopts
|
||||
)
|
||||
target_link_libraries(picow_ntp_client_poll
|
||||
pico_cyw43_arch_lwip_poll
|
||||
pico_stdlib
|
||||
)
|
||||
pico_add_extra_outputs(picow_ntp_client_poll)
|
||||
|
||||
10
pico_w/ntp_client/lwipopts.h
Normal file
10
pico_w/ntp_client/lwipopts.h
Normal file
@ -0,0 +1,10 @@
|
||||
#ifndef _LWIPOPTS_H
|
||||
#define _LWIPOPTS_H
|
||||
|
||||
// Generally you would define your own explicit list of lwIP options
|
||||
// (see https://www.nongnu.org/lwip/2_1_x/group__lwip__opts.html)
|
||||
//
|
||||
// This example uses a common include to avoid repetition
|
||||
#include "lwipopts_examples_common.h"
|
||||
|
||||
#endif
|
||||
185
pico_w/ntp_client/picow_ntp_client.c
Normal file
185
pico_w/ntp_client/picow_ntp_client.c
Normal file
@ -0,0 +1,185 @@
|
||||
/**
|
||||
* Copyright (c) 2022 Raspberry Pi (Trading) Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "pico/stdlib.h"
|
||||
#include "pico/cyw43_arch.h"
|
||||
|
||||
#include "lwip/dns.h"
|
||||
#include "lwip/pbuf.h"
|
||||
#include "lwip/udp.h"
|
||||
|
||||
typedef struct NTP_T_ {
|
||||
ip_addr_t ntp_server_address;
|
||||
bool dns_request_sent;
|
||||
struct udp_pcb *ntp_pcb;
|
||||
absolute_time_t ntp_test_time;
|
||||
alarm_id_t ntp_resend_alarm;
|
||||
} NTP_T;
|
||||
|
||||
#define NTP_SERVER "pool.ntp.org"
|
||||
#define NTP_MSG_LEN 48
|
||||
#define NTP_PORT 123
|
||||
#define NTP_DELTA 2208988800 // seconds between 1 Jan 1900 and 1 Jan 1970
|
||||
#define NTP_TEST_TIME (30 * 1000)
|
||||
#define NTP_RESEND_TIME (10 * 1000)
|
||||
|
||||
// Called with results of operation
|
||||
static void ntp_result(NTP_T* state, int status, time_t *result) {
|
||||
if (status == 0 && result) {
|
||||
struct tm *utc = gmtime(result);
|
||||
printf("got ntp response: %02d/%02d/%04d %02d:%02d:%02d\n", utc->tm_mday, utc->tm_mon + 1, utc->tm_year + 1900,
|
||||
utc->tm_hour, utc->tm_min, utc->tm_sec);
|
||||
}
|
||||
|
||||
if (state->ntp_resend_alarm > 0) {
|
||||
cancel_alarm(state->ntp_resend_alarm);
|
||||
state->ntp_resend_alarm = 0;
|
||||
}
|
||||
state->ntp_test_time = make_timeout_time_ms(NTP_TEST_TIME);
|
||||
state->dns_request_sent = false;
|
||||
}
|
||||
|
||||
static int64_t ntp_failed_handler(alarm_id_t id, void *user_data);
|
||||
|
||||
// Make an NTP request
|
||||
static void ntp_request(NTP_T *state) {
|
||||
// cyw43_arch_lwip_begin/end should be used around calls into lwIP to ensure correct locking.
|
||||
// You can omit them if you are in a callback from lwIP. Note that when using pico_cyw_arch_poll
|
||||
// these calls are a no-op and can be omitted, but it is a good practice to use them in
|
||||
// case you switch the cyw43_arch type later.
|
||||
cyw43_arch_lwip_begin();
|
||||
struct pbuf *p = pbuf_alloc(PBUF_TRANSPORT, NTP_MSG_LEN, PBUF_RAM);
|
||||
uint8_t *req = (uint8_t *) p->payload;
|
||||
memset(req, 0, NTP_MSG_LEN);
|
||||
req[0] = 0x1b;
|
||||
udp_sendto(state->ntp_pcb, p, &state->ntp_server_address, NTP_PORT);
|
||||
pbuf_free(p);
|
||||
cyw43_arch_lwip_end();
|
||||
}
|
||||
|
||||
static int64_t ntp_failed_handler(alarm_id_t id, void *user_data)
|
||||
{
|
||||
NTP_T* state = (NTP_T*)user_data;
|
||||
printf("ntp request failed\n");
|
||||
ntp_result(state, -1, NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Call back with a DNS result
|
||||
static void ntp_dns_found(const char *hostname, const ip_addr_t *ipaddr, void *arg) {
|
||||
NTP_T *state = (NTP_T*)arg;
|
||||
if (ipaddr) {
|
||||
state->ntp_server_address = *ipaddr;
|
||||
printf("ntp address %s\n", ip4addr_ntoa(ipaddr));
|
||||
ntp_request(state);
|
||||
} else {
|
||||
printf("ntp dns request failed\n");
|
||||
ntp_result(state, -1, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
// NTP data received
|
||||
static void ntp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *addr, u16_t port) {
|
||||
NTP_T *state = (NTP_T*)arg;
|
||||
uint8_t mode = pbuf_get_at(p, 0) & 0x7;
|
||||
uint8_t stratum = pbuf_get_at(p, 1);
|
||||
|
||||
// Check the result
|
||||
if (ip_addr_cmp(addr, &state->ntp_server_address) && port == NTP_PORT && p->tot_len == NTP_MSG_LEN &&
|
||||
mode == 0x4 && stratum != 0) {
|
||||
uint8_t seconds_buf[4] = {0};
|
||||
pbuf_copy_partial(p, seconds_buf, sizeof(seconds_buf), 40);
|
||||
uint32_t seconds_since_1900 = seconds_buf[0] << 24 | seconds_buf[1] << 16 | seconds_buf[2] << 8 | seconds_buf[3];
|
||||
uint32_t seconds_since_1970 = seconds_since_1900 - NTP_DELTA;
|
||||
time_t epoch = seconds_since_1970;
|
||||
ntp_result(state, 0, &epoch);
|
||||
} else {
|
||||
printf("invalid ntp response\n");
|
||||
ntp_result(state, -1, NULL);
|
||||
}
|
||||
pbuf_free(p);
|
||||
}
|
||||
|
||||
// Perform initialisation
|
||||
static NTP_T* ntp_init(void) {
|
||||
NTP_T *state = calloc(1, sizeof(NTP_T));
|
||||
if (!state) {
|
||||
printf("failed to allocate state\n");
|
||||
return NULL;
|
||||
}
|
||||
state->ntp_pcb = udp_new_ip_type(IPADDR_TYPE_ANY);
|
||||
if (!state->ntp_pcb) {
|
||||
printf("failed to create pcb\n");
|
||||
free(state);
|
||||
return NULL;
|
||||
}
|
||||
udp_recv(state->ntp_pcb, ntp_recv, state);
|
||||
return state;
|
||||
}
|
||||
|
||||
// Runs ntp test forever
|
||||
void run_ntp_test(void) {
|
||||
NTP_T *state = ntp_init();
|
||||
if (!state)
|
||||
return;
|
||||
while(true) {
|
||||
if (absolute_time_diff_us(get_absolute_time(), state->ntp_test_time) < 0 && !state->dns_request_sent) {
|
||||
|
||||
// Set alarm in case udp requests are lost
|
||||
state->ntp_resend_alarm = add_alarm_in_ms(NTP_RESEND_TIME, ntp_failed_handler, state, true);
|
||||
|
||||
// cyw43_arch_lwip_begin/end should be used around calls into lwIP to ensure correct locking.
|
||||
// You can omit them if you are in a callback from lwIP. Note that when using pico_cyw_arch_poll
|
||||
// these calls are a no-op and can be omitted, but it is a good practice to use them in
|
||||
// case you switch the cyw43_arch type later.
|
||||
cyw43_arch_lwip_begin();
|
||||
int err = dns_gethostbyname(NTP_SERVER, &state->ntp_server_address, ntp_dns_found, state);
|
||||
cyw43_arch_lwip_end();
|
||||
|
||||
state->dns_request_sent = true;
|
||||
if (err == ERR_OK) {
|
||||
ntp_request(state); // Cached result
|
||||
} else if (err != ERR_INPROGRESS) { // ERR_INPROGRESS means expect a callback
|
||||
printf("dns request failed\n");
|
||||
ntp_result(state, -1, NULL);
|
||||
}
|
||||
}
|
||||
#if PICO_CYW43_ARCH_POLL
|
||||
// if you are using pico_cyw43_arch_poll, then you must poll periodically from your
|
||||
// main loop (not from a timer) to check for WiFi driver or lwIP work that needs to be done.
|
||||
cyw43_arch_poll();
|
||||
sleep_ms(1);
|
||||
#else
|
||||
// if you are not using pico_cyw43_arch_poll, then WiFI driver and lwIP work
|
||||
// is done via interrupt in the background. This sleep is just an example of some (blocking)
|
||||
// work you might be doing.
|
||||
sleep_ms(1000);
|
||||
#endif
|
||||
}
|
||||
free(state);
|
||||
}
|
||||
|
||||
int main() {
|
||||
stdio_init_all();
|
||||
|
||||
if (cyw43_arch_init()) {
|
||||
printf("failed to initialise\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
cyw43_arch_enable_sta_mode();
|
||||
|
||||
if (cyw43_arch_wifi_connect_timeout_ms(WIFI_SSID, WIFI_PASSWORD, CYW43_AUTH_WPA2_AES_PSK, 10000)) {
|
||||
printf("failed to connect\n");
|
||||
return 1;
|
||||
}
|
||||
run_ntp_test();
|
||||
cyw43_arch_deinit();
|
||||
return 0;
|
||||
}
|
||||
71
pico_w/python_test_tcp/python_test_tcp_client.py
Normal file
71
pico_w/python_test_tcp/python_test_tcp_client.py
Normal file
@ -0,0 +1,71 @@
|
||||
import network
|
||||
import utime as time
|
||||
import usocket as socket
|
||||
|
||||
# Set your wifi ssid and password here
|
||||
WIFI_SSID = const('')
|
||||
WIFI_PASSWORD = const('')
|
||||
|
||||
# Set the server address here like 1.2.3.4
|
||||
SERVER_ADDR = const('')
|
||||
|
||||
# These constants should match the server
|
||||
BUF_SIZE = const(2048)
|
||||
SERVER_PORT = const(4242)
|
||||
TEST_ITERATIONS = const(10)
|
||||
|
||||
# Check if wifi details have been set
|
||||
if len(WIFI_SSID) == 0 or len(WIFI_PASSWORD) == 0:
|
||||
raise RuntimeError('set wifi ssid and password in this script')
|
||||
|
||||
# Check server ip address set
|
||||
if len(SERVER_ADDR) == 0:
|
||||
raise RuntimeError('set the IP address of the server')
|
||||
|
||||
# Start connection
|
||||
wlan = network.WLAN(network.STA_IF)
|
||||
wlan.active(True)
|
||||
wlan.connect(WIFI_SSID, WIFI_PASSWORD)
|
||||
|
||||
# Wait for connect success or failure
|
||||
max_wait = 20
|
||||
while max_wait > 0:
|
||||
if wlan.status() < 0 or wlan.status() >= 3:
|
||||
break
|
||||
max_wait -= 1
|
||||
print('waiting for connection...')
|
||||
time.sleep(1)
|
||||
|
||||
# Handle connection error
|
||||
if wlan.status() != 3:
|
||||
raise RuntimeError('wifi connection failed %d' % wlan.status())
|
||||
else:
|
||||
print('connected')
|
||||
status = wlan.ifconfig()
|
||||
print( 'ip = ' + status[0] )
|
||||
|
||||
# Open socket to the server
|
||||
sock = socket.socket()
|
||||
addr = (SERVER_ADDR, SERVER_PORT)
|
||||
sock.connect(addr)
|
||||
|
||||
# repeat test for a number of iterations
|
||||
for test_iteration in range(TEST_ITERATIONS):
|
||||
|
||||
# Read BUF_SIZE bytes from the server
|
||||
read_buf = sock.read(BUF_SIZE)
|
||||
print('read %d bytes from server' % len(read_buf))
|
||||
|
||||
# Check size of data received
|
||||
if len(read_buf) != BUF_SIZE:
|
||||
raise RuntimeError('wrong amount of data read')
|
||||
|
||||
# Send the data back to the server
|
||||
write_len = sock.write(read_buf)
|
||||
print('written %d bytes to server' % write_len)
|
||||
if write_len != BUF_SIZE:
|
||||
raise RuntimeError('wrong amount of data written')
|
||||
|
||||
# All done
|
||||
sock.close()
|
||||
print("test completed")
|
||||
85
pico_w/python_test_tcp/python_test_tcp_server.py
Normal file
85
pico_w/python_test_tcp/python_test_tcp_server.py
Normal file
@ -0,0 +1,85 @@
|
||||
import network
|
||||
import utime as time
|
||||
import usocket as socket
|
||||
import random
|
||||
|
||||
# Set your wifi ssid and password here
|
||||
WIFI_SSID = const('')
|
||||
WIFI_PASSWORD = const('')
|
||||
|
||||
# These constants should match the client
|
||||
BUF_SIZE = const(2048)
|
||||
SERVER_PORT = const(4242)
|
||||
TEST_ITERATIONS = const(10)
|
||||
|
||||
# Check if wifi details have been set
|
||||
if len(WIFI_SSID) == 0 or len(WIFI_PASSWORD) == 0:
|
||||
raise RuntimeError('Please set wifi ssid and password in this script')
|
||||
|
||||
# Start connection
|
||||
wlan = network.WLAN(network.STA_IF)
|
||||
wlan.active(True)
|
||||
wlan.connect(WIFI_SSID, WIFI_PASSWORD)
|
||||
|
||||
# Wait for connect success or failure
|
||||
max_wait = 20
|
||||
while max_wait > 0:
|
||||
if wlan.status() < 0 or wlan.status() >= 3:
|
||||
break
|
||||
max_wait -= 1
|
||||
print('waiting for connection...')
|
||||
time.sleep(1)
|
||||
|
||||
# Handle connection error
|
||||
if wlan.status() != 3:
|
||||
raise RuntimeError('wifi connection failed %d' % wlan.status())
|
||||
else:
|
||||
print('connected')
|
||||
status = wlan.ifconfig()
|
||||
print( 'ip = ' + status[0] )
|
||||
|
||||
# Open socket to the server
|
||||
sock = socket.socket()
|
||||
addr = ('0.0.0.0', SERVER_PORT)
|
||||
sock.bind(addr)
|
||||
sock.listen(1)
|
||||
print('server listening on', addr)
|
||||
|
||||
# Wait for the client
|
||||
con = None
|
||||
con, addr = sock.accept()
|
||||
print('client connected from', addr)
|
||||
|
||||
# repeat test for a number of iterations
|
||||
for test_iteration in range(TEST_ITERATIONS):
|
||||
|
||||
# Generate a buffer of random data
|
||||
random_list = []
|
||||
for n in range(BUF_SIZE):
|
||||
random_list.append(random.randint(0, 255))
|
||||
write_buf = bytearray(random_list)
|
||||
|
||||
# write BUF_SIZE bytes to the client
|
||||
write_len = con.send(bytearray(write_buf))
|
||||
print('Written %d bytes to client' % write_len)
|
||||
|
||||
# Check size of data written
|
||||
if write_len != BUF_SIZE:
|
||||
raise RuntimeError('wrong amount of data written')
|
||||
|
||||
# Read the data back from the client
|
||||
read_buf = con.read(BUF_SIZE)
|
||||
print('read %d bytes from client' % len(read_buf))
|
||||
|
||||
# Check size of data received
|
||||
if len(read_buf) != BUF_SIZE:
|
||||
raise RuntimeError('wrong amount of data read')
|
||||
|
||||
# Check the data sent and received
|
||||
if read_buf != write_buf:
|
||||
raise RuntimeError('buffer mismatch')
|
||||
|
||||
# All done
|
||||
con.close()
|
||||
sock.close()
|
||||
print("test completed")
|
||||
40
pico_w/tcp_client/CMakeLists.txt
Normal file
40
pico_w/tcp_client/CMakeLists.txt
Normal file
@ -0,0 +1,40 @@
|
||||
if (NOT TEST_TCP_SERVER_IP)
|
||||
message("Skipping tcp_client example as TEST_TCP_SERVER_IP is not defined")
|
||||
else()
|
||||
add_executable(picow_tcpip_client_background
|
||||
picow_tcp_client.c
|
||||
)
|
||||
target_compile_definitions(picow_tcpip_client_background PRIVATE
|
||||
WIFI_SSID=\"${WIFI_SSID}\"
|
||||
WIFI_PASSWORD=\"${WIFI_PASSWORD}\"
|
||||
TEST_TCP_SERVER_IP=\"${TEST_TCP_SERVER_IP}\"
|
||||
)
|
||||
target_include_directories(picow_tcpip_client_background PRIVATE
|
||||
${CMAKE_CURRENT_LIST_DIR}
|
||||
${CMAKE_CURRENT_LIST_DIR}/.. # for our common lwipopts
|
||||
)
|
||||
target_link_libraries(picow_tcpip_client_background
|
||||
pico_cyw43_arch_lwip_threadsafe_background
|
||||
pico_stdlib
|
||||
)
|
||||
|
||||
pico_add_extra_outputs(picow_tcpip_client_background)
|
||||
|
||||
add_executable(picow_tcpip_client_poll
|
||||
picow_tcp_client.c
|
||||
)
|
||||
target_compile_definitions(picow_tcpip_client_poll PRIVATE
|
||||
WIFI_SSID=\"${WIFI_SSID}\"
|
||||
WIFI_PASSWORD=\"${WIFI_PASSWORD}\"
|
||||
TEST_TCP_SERVER_IP=\"${TEST_TCP_SERVER_IP}\"
|
||||
)
|
||||
target_include_directories(picow_tcpip_client_poll PRIVATE
|
||||
${CMAKE_CURRENT_LIST_DIR}
|
||||
${CMAKE_CURRENT_LIST_DIR}/.. # for our common lwipopts
|
||||
)
|
||||
target_link_libraries(picow_tcpip_client_poll
|
||||
pico_cyw43_arch_lwip_poll
|
||||
pico_stdlib
|
||||
)
|
||||
pico_add_extra_outputs(picow_tcpip_client_poll)
|
||||
endif()
|
||||
10
pico_w/tcp_client/lwipopts.h
Normal file
10
pico_w/tcp_client/lwipopts.h
Normal file
@ -0,0 +1,10 @@
|
||||
#ifndef _LWIPOPTS_H
|
||||
#define _LWIPOPTS_H
|
||||
|
||||
// Generally you would define your own explicit list of lwIP options
|
||||
// (see https://www.nongnu.org/lwip/2_1_x/group__lwip__opts.html)
|
||||
//
|
||||
// This example uses a common include to avoid repetition
|
||||
#include "lwipopts_examples_common.h"
|
||||
|
||||
#endif
|
||||
254
pico_w/tcp_client/picow_tcp_client.c
Normal file
254
pico_w/tcp_client/picow_tcp_client.c
Normal file
@ -0,0 +1,254 @@
|
||||
/**
|
||||
* Copyright (c) 2022 Raspberry Pi (Trading) Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "pico/stdlib.h"
|
||||
#include "pico/cyw43_arch.h"
|
||||
|
||||
#include "lwip/pbuf.h"
|
||||
#include "lwip/tcp.h"
|
||||
|
||||
#if !defined(TEST_TCP_SERVER_IP)
|
||||
#error TEST_TCP_SERVER_IP not defined
|
||||
#endif
|
||||
|
||||
#define TCP_PORT 4242
|
||||
#define DEBUG_printf printf
|
||||
#define BUF_SIZE 2048
|
||||
|
||||
#define TEST_ITERATIONS 10
|
||||
#define POLL_TIME_S 5
|
||||
|
||||
#if 0
|
||||
static void dump_bytes(const uint8_t *bptr, uint32_t len) {
|
||||
unsigned int i = 0;
|
||||
|
||||
printf("dump_bytes %d", len);
|
||||
for (i = 0; i < len;) {
|
||||
if ((i & 0x0f) == 0) {
|
||||
printf("\n");
|
||||
} else if ((i & 0x07) == 0) {
|
||||
printf(" ");
|
||||
}
|
||||
printf("%02x ", bptr[i++]);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
#define DUMP_BYTES dump_bytes
|
||||
#else
|
||||
#define DUMP_BYTES(A,B)
|
||||
#endif
|
||||
|
||||
typedef struct TCP_CLIENT_T_ {
|
||||
struct tcp_pcb *tcp_pcb;
|
||||
ip_addr_t remote_addr;
|
||||
uint8_t buffer[BUF_SIZE];
|
||||
int buffer_len;
|
||||
int sent_len;
|
||||
bool complete;
|
||||
int run_count;
|
||||
bool connected;
|
||||
} TCP_CLIENT_T;
|
||||
|
||||
static err_t tcp_client_close(void *arg) {
|
||||
TCP_CLIENT_T *state = (TCP_CLIENT_T*)arg;
|
||||
err_t err = ERR_OK;
|
||||
if (state->tcp_pcb != NULL) {
|
||||
tcp_arg(state->tcp_pcb, NULL);
|
||||
tcp_poll(state->tcp_pcb, NULL, 0);
|
||||
tcp_sent(state->tcp_pcb, NULL);
|
||||
tcp_recv(state->tcp_pcb, NULL);
|
||||
tcp_err(state->tcp_pcb, NULL);
|
||||
err = tcp_close(state->tcp_pcb);
|
||||
if (err != ERR_OK) {
|
||||
DEBUG_printf("close failed %d, calling abort\n", err);
|
||||
tcp_abort(state->tcp_pcb);
|
||||
err = ERR_ABRT;
|
||||
}
|
||||
state->tcp_pcb = NULL;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
// Called with results of operation
|
||||
static err_t tcp_result(void *arg, int status) {
|
||||
TCP_CLIENT_T *state = (TCP_CLIENT_T*)arg;
|
||||
if (status == 0) {
|
||||
DEBUG_printf("test success\n");
|
||||
} else {
|
||||
DEBUG_printf("test failed %d\n", status);
|
||||
}
|
||||
state->complete = true;
|
||||
return tcp_client_close(arg);
|
||||
}
|
||||
|
||||
static err_t tcp_client_sent(void *arg, struct tcp_pcb *tpcb, u16_t len) {
|
||||
TCP_CLIENT_T *state = (TCP_CLIENT_T*)arg;
|
||||
DEBUG_printf("tcp_client_sent %u\n", len);
|
||||
state->sent_len += len;
|
||||
|
||||
if (state->sent_len >= BUF_SIZE) {
|
||||
|
||||
state->run_count++;
|
||||
if (state->run_count >= TEST_ITERATIONS) {
|
||||
tcp_result(arg, 0);
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
// We should receive a new buffer from the server
|
||||
state->buffer_len = 0;
|
||||
state->sent_len = 0;
|
||||
DEBUG_printf("Waiting for buffer from server\n");
|
||||
}
|
||||
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
static err_t tcp_client_connected(void *arg, struct tcp_pcb *tpcb, err_t err) {
|
||||
TCP_CLIENT_T *state = (TCP_CLIENT_T*)arg;
|
||||
if (err != ERR_OK) {
|
||||
printf("connect failed %d\n", err);
|
||||
return tcp_result(arg, err);
|
||||
}
|
||||
state->connected = true;
|
||||
DEBUG_printf("Waiting for buffer from server\n");
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
static err_t tcp_client_poll(void *arg, struct tcp_pcb *tpcb) {
|
||||
DEBUG_printf("tcp_client_poll\n");
|
||||
return tcp_result(arg, -1); // no response is an error?
|
||||
}
|
||||
|
||||
static void tcp_client_err(void *arg, err_t err) {
|
||||
if (err != ERR_ABRT) {
|
||||
DEBUG_printf("tcp_client_err %d\n", err);
|
||||
tcp_result(arg, err);
|
||||
}
|
||||
}
|
||||
|
||||
err_t tcp_client_recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err) {
|
||||
TCP_CLIENT_T *state = (TCP_CLIENT_T*)arg;
|
||||
if (!p) {
|
||||
return tcp_result(arg, -1);
|
||||
}
|
||||
// this method is callback from lwIP, so cyw43_arch_lwip_begin is not required, however you
|
||||
// can use this method to cause an assertion in debug mode, if this method is called when
|
||||
// cyw43_arch_lwip_begin IS needed
|
||||
cyw43_arch_lwip_check();
|
||||
if (p->tot_len > 0) {
|
||||
DEBUG_printf("recv %d err %d\n", p->tot_len, err);
|
||||
for (struct pbuf *q = p; q != NULL; q = q->next) {
|
||||
DUMP_BYTES(q->payload, q->len);
|
||||
}
|
||||
// Receive the buffer
|
||||
const uint16_t buffer_left = BUF_SIZE - state->buffer_len;
|
||||
state->buffer_len += pbuf_copy_partial(p, state->buffer + state->buffer_len,
|
||||
p->tot_len > buffer_left ? buffer_left : p->tot_len, 0);
|
||||
tcp_recved(tpcb, p->tot_len);
|
||||
}
|
||||
pbuf_free(p);
|
||||
|
||||
// If we have received the whole buffer, send it back to the server
|
||||
if (state->buffer_len == BUF_SIZE) {
|
||||
DEBUG_printf("Writing %d bytes to server\n", state->buffer_len);
|
||||
err_t err = tcp_write(tpcb, state->buffer, state->buffer_len, TCP_WRITE_FLAG_COPY);
|
||||
if (err != ERR_OK) {
|
||||
DEBUG_printf("Failed to write data %d\n", err);
|
||||
return tcp_result(arg, -1);
|
||||
}
|
||||
}
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
static bool tcp_client_open(void *arg) {
|
||||
TCP_CLIENT_T *state = (TCP_CLIENT_T*)arg;
|
||||
DEBUG_printf("Connecting to %s port %u\n", ip4addr_ntoa(&state->remote_addr), TCP_PORT);
|
||||
state->tcp_pcb = tcp_new_ip_type(IP_GET_TYPE(&state->remote_addr));
|
||||
if (!state->tcp_pcb) {
|
||||
DEBUG_printf("failed to create pcb\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
tcp_arg(state->tcp_pcb, state);
|
||||
tcp_poll(state->tcp_pcb, tcp_client_poll, POLL_TIME_S * 2);
|
||||
tcp_sent(state->tcp_pcb, tcp_client_sent);
|
||||
tcp_recv(state->tcp_pcb, tcp_client_recv);
|
||||
tcp_err(state->tcp_pcb, tcp_client_err);
|
||||
|
||||
state->buffer_len = 0;
|
||||
|
||||
// cyw43_arch_lwip_begin/end should be used around calls into lwIP to ensure correct locking.
|
||||
// You can omit them if you are in a callback from lwIP. Note that when using pico_cyw_arch_poll
|
||||
// these calls are a no-op and can be omitted, but it is a good practice to use them in
|
||||
// case you switch the cyw43_arch type later.
|
||||
cyw43_arch_lwip_begin();
|
||||
err_t err = tcp_connect(state->tcp_pcb, &state->remote_addr, TCP_PORT, tcp_client_connected);
|
||||
cyw43_arch_lwip_end();
|
||||
|
||||
return err == ERR_OK;
|
||||
}
|
||||
|
||||
// Perform initialisation
|
||||
static TCP_CLIENT_T* tcp_client_init(void) {
|
||||
TCP_CLIENT_T *state = calloc(1, sizeof(TCP_CLIENT_T));
|
||||
if (!state) {
|
||||
DEBUG_printf("failed to allocate state\n");
|
||||
return NULL;
|
||||
}
|
||||
ip4addr_aton(TEST_TCP_SERVER_IP, &state->remote_addr);
|
||||
return state;
|
||||
}
|
||||
|
||||
void run_tcp_client_test(void) {
|
||||
TCP_CLIENT_T *state = tcp_client_init();
|
||||
if (!state) {
|
||||
return;
|
||||
}
|
||||
if (!tcp_client_open(state)) {
|
||||
tcp_result(state, -1);
|
||||
return;
|
||||
}
|
||||
while(!state->complete) {
|
||||
// the following #ifdef is only here so this same example can be used in multiple modes;
|
||||
// you do not need it in your code
|
||||
#if PICO_CYW43_ARCH_POLL
|
||||
// if you are using pico_cyw43_arch_poll, then you must poll periodically from your
|
||||
// main loop (not from a timer) to check for WiFi driver or lwIP work that needs to be done.
|
||||
cyw43_arch_poll();
|
||||
sleep_ms(1);
|
||||
#else
|
||||
// if you are not using pico_cyw43_arch_poll, then WiFI driver and lwIP work
|
||||
// is done via interrupt in the background. This sleep is just an example of some (blocking)
|
||||
// work you might be doing.
|
||||
sleep_ms(1000);
|
||||
#endif
|
||||
}
|
||||
free(state);
|
||||
}
|
||||
|
||||
int main() {
|
||||
stdio_init_all();
|
||||
|
||||
if (cyw43_arch_init()) {
|
||||
DEBUG_printf("failed to initialise\n");
|
||||
return 1;
|
||||
}
|
||||
cyw43_arch_enable_sta_mode();
|
||||
|
||||
printf("Connecting to WiFi...\n");
|
||||
if (cyw43_arch_wifi_connect_timeout_ms(WIFI_SSID, WIFI_PASSWORD, CYW43_AUTH_WPA2_AES_PSK, 30000)) {
|
||||
printf("failed to connect.\n");
|
||||
return 1;
|
||||
} else {
|
||||
printf("Connected.\n");
|
||||
}
|
||||
run_tcp_client_test();
|
||||
cyw43_arch_deinit();
|
||||
return 0;
|
||||
}
|
||||
34
pico_w/tcp_server/CMakeLists.txt
Normal file
34
pico_w/tcp_server/CMakeLists.txt
Normal file
@ -0,0 +1,34 @@
|
||||
add_executable(picow_tcpip_server_background
|
||||
picow_tcp_server.c
|
||||
)
|
||||
target_compile_definitions(picow_tcpip_server_background PRIVATE
|
||||
WIFI_SSID=\"${WIFI_SSID}\"
|
||||
WIFI_PASSWORD=\"${WIFI_PASSWORD}\"
|
||||
)
|
||||
target_include_directories(picow_tcpip_server_background PRIVATE
|
||||
${CMAKE_CURRENT_LIST_DIR}
|
||||
${CMAKE_CURRENT_LIST_DIR}/.. # for our common lwipopts
|
||||
)
|
||||
target_link_libraries(picow_tcpip_server_background
|
||||
pico_cyw43_arch_lwip_threadsafe_background
|
||||
pico_stdlib
|
||||
)
|
||||
|
||||
pico_add_extra_outputs(picow_tcpip_server_background)
|
||||
|
||||
add_executable(picow_tcpip_server_poll
|
||||
picow_tcp_server.c
|
||||
)
|
||||
target_compile_definitions(picow_tcpip_server_poll PRIVATE
|
||||
WIFI_SSID=\"${WIFI_SSID}\"
|
||||
WIFI_PASSWORD=\"${WIFI_PASSWORD}\"
|
||||
)
|
||||
target_include_directories(picow_tcpip_server_poll PRIVATE
|
||||
${CMAKE_CURRENT_LIST_DIR}
|
||||
${CMAKE_CURRENT_LIST_DIR}/.. # for our common lwipopts
|
||||
)
|
||||
target_link_libraries(picow_tcpip_server_poll
|
||||
pico_cyw43_arch_lwip_poll
|
||||
pico_stdlib
|
||||
)
|
||||
pico_add_extra_outputs(picow_tcpip_server_poll)
|
||||
10
pico_w/tcp_server/lwipopts.h
Normal file
10
pico_w/tcp_server/lwipopts.h
Normal file
@ -0,0 +1,10 @@
|
||||
#ifndef _LWIPOPTS_H
|
||||
#define _LWIPOPTS_H
|
||||
|
||||
// Generally you would define your own explicit list of lwIP options
|
||||
// (see https://www.nongnu.org/lwip/2_1_x/group__lwip__opts.html)
|
||||
//
|
||||
// This example uses a common include to avoid repetition
|
||||
#include "lwipopts_examples_common.h"
|
||||
|
||||
#endif
|
||||
266
pico_w/tcp_server/picow_tcp_server.c
Normal file
266
pico_w/tcp_server/picow_tcp_server.c
Normal file
@ -0,0 +1,266 @@
|
||||
/**
|
||||
* Copyright (c) 2022 Raspberry Pi (Trading) Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "pico/stdlib.h"
|
||||
#include "pico/cyw43_arch.h"
|
||||
|
||||
#include "lwip/pbuf.h"
|
||||
#include "lwip/tcp.h"
|
||||
|
||||
#define TCP_PORT 4242
|
||||
#define DEBUG_printf printf
|
||||
#define BUF_SIZE 2048
|
||||
#define TEST_ITERATIONS 10
|
||||
#define POLL_TIME_S 5
|
||||
|
||||
typedef struct TCP_SERVER_T_ {
|
||||
struct tcp_pcb *server_pcb;
|
||||
struct tcp_pcb *client_pcb;
|
||||
bool complete;
|
||||
uint8_t buffer_sent[BUF_SIZE];
|
||||
uint8_t buffer_recv[BUF_SIZE];
|
||||
int sent_len;
|
||||
int recv_len;
|
||||
int run_count;
|
||||
} TCP_SERVER_T;
|
||||
|
||||
static TCP_SERVER_T* tcp_server_init(void) {
|
||||
TCP_SERVER_T *state = calloc(1, sizeof(TCP_SERVER_T));
|
||||
if (!state) {
|
||||
DEBUG_printf("failed to allocate state\n");
|
||||
return NULL;
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
||||
static err_t tcp_server_close(void *arg) {
|
||||
TCP_SERVER_T *state = (TCP_SERVER_T*)arg;
|
||||
err_t err = ERR_OK;
|
||||
if (state->client_pcb != NULL) {
|
||||
tcp_arg(state->client_pcb, NULL);
|
||||
tcp_poll(state->client_pcb, NULL, 0);
|
||||
tcp_sent(state->client_pcb, NULL);
|
||||
tcp_recv(state->client_pcb, NULL);
|
||||
tcp_err(state->client_pcb, NULL);
|
||||
err = tcp_close(state->client_pcb);
|
||||
if (err != ERR_OK) {
|
||||
DEBUG_printf("close failed %d, calling abort\n", err);
|
||||
tcp_abort(state->client_pcb);
|
||||
err = ERR_ABRT;
|
||||
}
|
||||
state->client_pcb = NULL;
|
||||
}
|
||||
if (state->server_pcb) {
|
||||
tcp_arg(state->server_pcb, NULL);
|
||||
tcp_close(state->server_pcb);
|
||||
state->server_pcb = NULL;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
static err_t tcp_server_result(void *arg, int status) {
|
||||
TCP_SERVER_T *state = (TCP_SERVER_T*)arg;
|
||||
if (status == 0) {
|
||||
DEBUG_printf("test success\n");
|
||||
} else {
|
||||
DEBUG_printf("test failed %d\n", status);
|
||||
}
|
||||
state->complete = true;
|
||||
return tcp_server_close(arg);
|
||||
}
|
||||
|
||||
static err_t tcp_server_sent(void *arg, struct tcp_pcb *tpcb, u16_t len) {
|
||||
TCP_SERVER_T *state = (TCP_SERVER_T*)arg;
|
||||
DEBUG_printf("tcp_server_sent %u\n", len);
|
||||
state->sent_len += len;
|
||||
|
||||
if (state->sent_len >= BUF_SIZE) {
|
||||
|
||||
// We should get the data back from the client
|
||||
state->recv_len = 0;
|
||||
DEBUG_printf("Waiting for buffer from client\n");
|
||||
}
|
||||
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
err_t tcp_server_send_data(void *arg, struct tcp_pcb *tpcb)
|
||||
{
|
||||
TCP_SERVER_T *state = (TCP_SERVER_T*)arg;
|
||||
for(int i=0; i< BUF_SIZE; i++) {
|
||||
state->buffer_sent[i] = rand();
|
||||
}
|
||||
|
||||
state->sent_len = 0;
|
||||
DEBUG_printf("Writing %ld bytes to client\n", BUF_SIZE);
|
||||
// this method is callback from lwIP, so cyw43_arch_lwip_begin is not required, however you
|
||||
// can use this method to cause an assertion in debug mode, if this method is called when
|
||||
// cyw43_arch_lwip_begin IS needed
|
||||
cyw43_arch_lwip_check();
|
||||
err_t err = tcp_write(tpcb, state->buffer_sent, BUF_SIZE, TCP_WRITE_FLAG_COPY);
|
||||
if (err != ERR_OK) {
|
||||
DEBUG_printf("Failed to write data %d\n", err);
|
||||
return tcp_server_result(arg, -1);
|
||||
}
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
err_t tcp_server_recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err) {
|
||||
TCP_SERVER_T *state = (TCP_SERVER_T*)arg;
|
||||
if (!p) {
|
||||
return tcp_server_result(arg, -1);
|
||||
}
|
||||
// this method is callback from lwIP, so cyw43_arch_lwip_begin is not required, however you
|
||||
// can use this method to cause an assertion in debug mode, if this method is called when
|
||||
// cyw43_arch_lwip_begin IS needed
|
||||
cyw43_arch_lwip_check();
|
||||
if (p->tot_len > 0) {
|
||||
DEBUG_printf("tcp_server_recv %d/%d err %d\n", p->tot_len, state->recv_len, err);
|
||||
|
||||
// Receive the buffer
|
||||
const uint16_t buffer_left = BUF_SIZE - state->recv_len;
|
||||
state->recv_len += pbuf_copy_partial(p, state->buffer_recv + state->recv_len,
|
||||
p->tot_len > buffer_left ? buffer_left : p->tot_len, 0);
|
||||
tcp_recved(tpcb, p->tot_len);
|
||||
}
|
||||
pbuf_free(p);
|
||||
|
||||
// Have we have received the whole buffer
|
||||
if (state->recv_len == BUF_SIZE) {
|
||||
|
||||
// check it matches
|
||||
if (memcmp(state->buffer_sent, state->buffer_recv, BUF_SIZE) != 0) {
|
||||
DEBUG_printf("buffer mismatch\n");
|
||||
return tcp_server_result(arg, -1);
|
||||
}
|
||||
DEBUG_printf("tcp_server_recv buffer ok\n");
|
||||
|
||||
// Test complete?
|
||||
state->run_count++;
|
||||
if (state->run_count >= TEST_ITERATIONS) {
|
||||
tcp_server_result(arg, 0);
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
// Send another buffer
|
||||
return tcp_server_send_data(arg, state->client_pcb);
|
||||
}
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
static err_t tcp_server_poll(void *arg, struct tcp_pcb *tpcb) {
|
||||
DEBUG_printf("tcp_server_poll_fn\n");
|
||||
return tcp_server_result(arg, -1); // no response is an error?
|
||||
}
|
||||
|
||||
static void tcp_server_err(void *arg, err_t err) {
|
||||
if (err != ERR_ABRT) {
|
||||
DEBUG_printf("tcp_client_err_fn %d\n", err);
|
||||
tcp_server_result(arg, err);
|
||||
}
|
||||
}
|
||||
|
||||
static err_t tcp_server_accept(void *arg, struct tcp_pcb *client_pcb, err_t err) {
|
||||
TCP_SERVER_T *state = (TCP_SERVER_T*)arg;
|
||||
if (err != ERR_OK || client_pcb == NULL) {
|
||||
DEBUG_printf("Failure in accept\n");
|
||||
tcp_server_result(arg, err);
|
||||
return ERR_VAL;
|
||||
}
|
||||
DEBUG_printf("Client connected\n");
|
||||
|
||||
state->client_pcb = client_pcb;
|
||||
tcp_arg(client_pcb, state);
|
||||
tcp_sent(client_pcb, tcp_server_sent);
|
||||
tcp_recv(client_pcb, tcp_server_recv);
|
||||
tcp_poll(client_pcb, tcp_server_poll, POLL_TIME_S * 2);
|
||||
tcp_err(client_pcb, tcp_server_err);
|
||||
|
||||
return tcp_server_send_data(arg, state->client_pcb);
|
||||
}
|
||||
|
||||
static bool tcp_server_open(void *arg) {
|
||||
TCP_SERVER_T *state = (TCP_SERVER_T*)arg;
|
||||
DEBUG_printf("Starting server at %s on port %u\n", ip4addr_ntoa(netif_ip4_addr(netif_list)), TCP_PORT);
|
||||
|
||||
struct tcp_pcb *pcb = tcp_new_ip_type(IPADDR_TYPE_ANY);
|
||||
if (!pcb) {
|
||||
DEBUG_printf("failed to create pcb\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
err_t err = tcp_bind(pcb, NULL, TCP_PORT);
|
||||
if (err) {
|
||||
DEBUG_printf("failed to bind to port %d\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
state->server_pcb = tcp_listen_with_backlog(pcb, 1);
|
||||
if (!state->server_pcb) {
|
||||
DEBUG_printf("failed to listen\n");
|
||||
if (pcb) {
|
||||
tcp_close(pcb);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
tcp_arg(state->server_pcb, state);
|
||||
tcp_accept(state->server_pcb, tcp_server_accept);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void run_tcp_server_test(void) {
|
||||
TCP_SERVER_T *state = tcp_server_init();
|
||||
if (!state) {
|
||||
return;
|
||||
}
|
||||
if (!tcp_server_open(state)) {
|
||||
tcp_server_result(state, -1);
|
||||
return;
|
||||
}
|
||||
while(!state->complete) {
|
||||
// the following #ifdef is only here so this same example can be used in multiple modes;
|
||||
// you do not need it in your code
|
||||
#if PICO_CYW43_ARCH_POLL
|
||||
// if you are using pico_cyw43_arch_poll, then you must poll periodically from your
|
||||
// main loop (not from a timer) to check for WiFi driver or lwIP work that needs to be done.
|
||||
cyw43_arch_poll();
|
||||
sleep_ms(1);
|
||||
#else
|
||||
// if you are not using pico_cyw43_arch_poll, then WiFI driver and lwIP work
|
||||
// is done via interrupt in the background. This sleep is just an example of some (blocking)
|
||||
// work you might be doing.
|
||||
sleep_ms(1000);
|
||||
#endif
|
||||
}
|
||||
free(state);
|
||||
}
|
||||
|
||||
int main() {
|
||||
stdio_init_all();
|
||||
|
||||
if (cyw43_arch_init()) {
|
||||
printf("failed to initialise\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
cyw43_arch_enable_sta_mode();
|
||||
|
||||
printf("Connecting to WiFi...\n");
|
||||
if (cyw43_arch_wifi_connect_timeout_ms(WIFI_SSID, WIFI_PASSWORD, CYW43_AUTH_WPA2_AES_PSK, 30000)) {
|
||||
printf("failed to connect.\n");
|
||||
return 1;
|
||||
} else {
|
||||
printf("Connected.\n");
|
||||
}
|
||||
run_tcp_server_test();
|
||||
cyw43_arch_deinit();
|
||||
return 0;
|
||||
}
|
||||
27
pico_w/wifi_scan/CMakeLists.txt
Normal file
27
pico_w/wifi_scan/CMakeLists.txt
Normal file
@ -0,0 +1,27 @@
|
||||
add_executable(picow_wifi_scan_background
|
||||
picow_wifi_scan.c
|
||||
)
|
||||
target_include_directories(picow_wifi_scan_background PRIVATE
|
||||
${CMAKE_CURRENT_LIST_DIR}
|
||||
${CMAKE_CURRENT_LIST_DIR}/.. # for our common lwipopts
|
||||
)
|
||||
target_link_libraries(picow_wifi_scan_background
|
||||
pico_cyw43_arch_lwip_threadsafe_background
|
||||
pico_stdlib
|
||||
)
|
||||
|
||||
pico_add_extra_outputs(picow_wifi_scan_background)
|
||||
|
||||
add_executable(picow_wifi_scan_poll
|
||||
picow_wifi_scan.c
|
||||
)
|
||||
target_include_directories(picow_wifi_scan_poll PRIVATE
|
||||
${CMAKE_CURRENT_LIST_DIR}
|
||||
${CMAKE_CURRENT_LIST_DIR}/.. # for our common lwipopts
|
||||
)
|
||||
target_link_libraries(picow_wifi_scan_poll
|
||||
pico_cyw43_arch_lwip_poll
|
||||
pico_stdlib
|
||||
)
|
||||
pico_add_extra_outputs(picow_wifi_scan_poll)
|
||||
|
||||
10
pico_w/wifi_scan/lwipopts.h
Normal file
10
pico_w/wifi_scan/lwipopts.h
Normal file
@ -0,0 +1,10 @@
|
||||
#ifndef _LWIPOPTS_H
|
||||
#define _LWIPOPTS_H
|
||||
|
||||
// Generally you would define your own explicit list of lwIP options
|
||||
// (see https://www.nongnu.org/lwip/2_1_x/group__lwip__opts.html)
|
||||
//
|
||||
// This example uses a common include to avoid repetition
|
||||
#include "lwipopts_examples_common.h"
|
||||
|
||||
#endif
|
||||
71
pico_w/wifi_scan/picow_wifi_scan.c
Normal file
71
pico_w/wifi_scan/picow_wifi_scan.c
Normal file
@ -0,0 +1,71 @@
|
||||
/**
|
||||
* Copyright (c) 2022 Raspberry Pi (Trading) Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "pico/stdlib.h"
|
||||
#include "pico/cyw43_arch.h"
|
||||
|
||||
static int scan_result(void *env, const cyw43_ev_scan_result_t *result) {
|
||||
if (result) {
|
||||
printf("ssid: %-32s rssi: %4d chan: %3d mac: %02x:%02x:%02x:%02x:%02x:%02x sec: %u\n",
|
||||
result->ssid, result->rssi, result->channel,
|
||||
result->bssid[0], result->bssid[1], result->bssid[2], result->bssid[3], result->bssid[4], result->bssid[5],
|
||||
result->auth_mode);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#include "hardware/vreg.h"
|
||||
#include "hardware/clocks.h"
|
||||
|
||||
int main() {
|
||||
stdio_init_all();
|
||||
|
||||
if (cyw43_arch_init()) {
|
||||
printf("failed to initialise\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
cyw43_arch_enable_sta_mode();
|
||||
|
||||
absolute_time_t scan_test = nil_time;
|
||||
bool scan_in_progress = false;
|
||||
while(true) {
|
||||
if (absolute_time_diff_us(get_absolute_time(), scan_test) < 0) {
|
||||
if (!scan_in_progress) {
|
||||
cyw43_wifi_scan_options_t scan_options = {0};
|
||||
int err = cyw43_wifi_scan(&cyw43_state, &scan_options, NULL, scan_result);
|
||||
if (err == 0) {
|
||||
printf("\nPerforming wifi scan\n");
|
||||
scan_in_progress = true;
|
||||
} else {
|
||||
printf("Failed to start scan: %d\n", err);
|
||||
scan_test = make_timeout_time_ms(10000); // wait 10s and scan again
|
||||
}
|
||||
} else if (!cyw43_wifi_scan_active(&cyw43_state)) {
|
||||
scan_test = make_timeout_time_ms(10000); // wait 10s and scan again
|
||||
scan_in_progress = false;
|
||||
}
|
||||
}
|
||||
// the following #ifdef is only here so this same example can be used in multiple modes;
|
||||
// you do not need it in your code
|
||||
#if PICO_CYW43_ARCH_POLL
|
||||
// if you are using pico_cyw43_arch_poll, then you must poll periodically from your
|
||||
// main loop (not from a timer) to check for WiFi driver or lwIP work that needs to be done.
|
||||
cyw43_arch_poll();
|
||||
sleep_ms(1);
|
||||
#else
|
||||
// if you are not using pico_cyw43_arch_poll, then WiFI driver and lwIP work
|
||||
// is done via interrupt in the background. This sleep is just an example of some (blocking)
|
||||
// work you might be doing.
|
||||
sleep_ms(1000);
|
||||
#endif
|
||||
}
|
||||
|
||||
cyw43_arch_deinit();
|
||||
return 0;
|
||||
}
|
||||
@ -1,10 +1,10 @@
|
||||
if (TARGET tinyusb_device)
|
||||
add_subdirectory(device)
|
||||
else ()
|
||||
message("Skipping TinyUSB device examples, as TinyUSB unavailable")
|
||||
message("Skipping TinyUSB device examples as TinyUSB is unavailable")
|
||||
endif ()
|
||||
if (TARGET tinyusb_host)
|
||||
add_subdirectory(host)
|
||||
else ()
|
||||
message("Skipping TinyUSB host examples, as TinyUSB unavailable")
|
||||
message("Skipping TinyUSB host examples as TinyUSB is unavailable")
|
||||
endif ()
|
||||
Reference in New Issue
Block a user