Add Pico W examples

This commit is contained in:
graham sanderson 2022-06-29 22:53:50 -05:00
parent a7ce7007ff
commit 01e8128953
40 changed files with 2732 additions and 2 deletions

View File

@ -41,6 +41,7 @@ add_subdirectory(i2c)
add_subdirectory(interp) add_subdirectory(interp)
add_subdirectory(multicore) add_subdirectory(multicore)
add_subdirectory(picoboard) add_subdirectory(picoboard)
add_subdirectory(pico_w)
add_subdirectory(pio) add_subdirectory(pio)
add_subdirectory(pwm) add_subdirectory(pwm)
add_subdirectory(reset) add_subdirectory(reset)

View File

@ -108,6 +108,32 @@ App|Description
[blinky](picoboard/blinky)| Blink "hello, world" in Morse code on Pico's LED [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. [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 ### PIO
App|Description App|Description

26
pico_w/CMakeLists.txt Normal file
View 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()

View 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)

View 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.

View 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);
}

View 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

View 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

View 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;
}

View 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)

View 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);
}
}

View 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()

View 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)

View 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)

View 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 */

View 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

View 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;
}

View 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()

View 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 */

View 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

View 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;
}

View 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
View 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

View 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;
}

View 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__ */

View 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)

View 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

View 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;
}

View 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")

View 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")

View 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()

View 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

View 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;
}

View 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)

View 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

View 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;
}

View 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)

View 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

View 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;
}

View File

@ -1,10 +1,10 @@
if (TARGET tinyusb_device) if (TARGET tinyusb_device)
add_subdirectory(device) add_subdirectory(device)
else () else ()
message("Skipping TinyUSB device examples, as TinyUSB unavailable") message("Skipping TinyUSB device examples as TinyUSB is unavailable")
endif () endif ()
if (TARGET tinyusb_host) if (TARGET tinyusb_host)
add_subdirectory(host) add_subdirectory(host)
else () else ()
message("Skipping TinyUSB host examples, as TinyUSB unavailable") message("Skipping TinyUSB host examples as TinyUSB is unavailable")
endif () endif ()