Skip to content

Commit 3bba4a6

Browse files
Some example improvements (#634)
* Use async context for led in iperf example Improve led handling by using the async context to turn the led on and off. Fix assert in poll mode when cyw43_arch_disable_sta_mode is called in interrupt context. * Improve wifi scan example Use async context to initiate a scan in future instead of keeping track of time in the main loop. Detect a key press to exit the example. * Improve NTP example Use async context NTP requests, rather than keeping track of time in the main loop. Detect a key press to exit the example.
1 parent f652cd5 commit 3bba4a6

File tree

3 files changed

+91
-84
lines changed

3 files changed

+91
-84
lines changed

pico_w/wifi/iperf/picow_iperf.c

Lines changed: 23 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,17 @@
1919
#error IPERF_SERVER_IP not defined
2020
#endif
2121

22+
#if USE_LED
23+
// Invert led
24+
static void led_worker_fn(async_context_t *context, async_at_time_worker_t *worker) {
25+
// Invert the led
26+
static int led_on = true;
27+
led_on = !led_on;
28+
cyw43_arch_gpio_put(CYW43_WL_GPIO_LED_PIN, led_on);
29+
async_context_add_at_time_worker_in_ms(context, worker, 1000);
30+
}
31+
#endif
32+
2233
// Report IP results and exit
2334
static void iperf_report(void *arg, enum lwiperf_report_type report_type,
2435
const ip_addr_t *local_addr, u16_t local_port, const ip_addr_t *remote_addr, u16_t remote_port,
@@ -36,12 +47,12 @@ static void iperf_report(void *arg, enum lwiperf_report_type report_type,
3647
#endif
3748
}
3849

50+
// Note: This is called from an interrupt handler
3951
void key_pressed_func(void *param) {
4052
int key = getchar_timeout_us(0); // get any pending key press but don't wait
4153
if (key == 'd' || key == 'D') {
42-
cyw43_arch_lwip_begin();
43-
cyw43_arch_disable_sta_mode();
44-
cyw43_arch_lwip_end();
54+
bool *exit = (bool*)param;
55+
*exit = true;
4556
}
4657
}
4758

@@ -53,9 +64,6 @@ int main() {
5364
return 1;
5465
}
5566

56-
// Get notified if the user presses a key
57-
stdio_set_chars_available_callback(key_pressed_func, cyw43_arch_async_context());
58-
5967
cyw43_arch_enable_sta_mode();
6068
printf("Connecting to Wi-Fi... (press 'd' to disconnect)\n");
6169
if (cyw43_arch_wifi_connect_timeout_ms(WIFI_SSID, WIFI_PASSWORD, CYW43_AUTH_WPA2_AES_PSK, 30000)) {
@@ -77,23 +85,15 @@ int main() {
7785
#endif
7886
cyw43_arch_lwip_end();
7987

80-
while(cyw43_wifi_link_status(&cyw43_state, CYW43_ITF_STA) != CYW43_LINK_DOWN) {
88+
bool exit = false;
89+
stdio_set_chars_available_callback(key_pressed_func, &exit);
90+
8191
#if USE_LED
82-
static absolute_time_t led_time;
83-
static int led_on = true;
84-
85-
// Invert the led
86-
if (absolute_time_diff_us(get_absolute_time(), led_time) < 0) {
87-
led_on = !led_on;
88-
cyw43_gpio_set(&cyw43_state, 0, led_on);
89-
led_time = make_timeout_time_ms(1000);
90-
91-
// Check we can read back the led value
92-
bool actual_led_val = !led_on;
93-
cyw43_gpio_get(&cyw43_state, 0, &actual_led_val);
94-
assert(led_on == actual_led_val);
95-
}
92+
// start the led flashing
93+
async_at_time_worker_t led_worker = { .do_work = led_worker_fn };
94+
async_context_add_at_time_worker_in_ms(cyw43_arch_async_context(), &led_worker, 0);
9695
#endif
96+
while(!exit && cyw43_wifi_link_status(&cyw43_state, CYW43_ITF_STA) != CYW43_LINK_DOWN) {
9797
// the following #ifdef is only here so this same example can be used in multiple modes;
9898
// you do not need it in your code
9999
#if PICO_CYW43_ARCH_POLL
@@ -102,14 +102,15 @@ int main() {
102102
cyw43_arch_poll();
103103
// you can poll as often as you like, however if you have nothing else to do you can
104104
// choose to sleep until either a specified time, or cyw43_arch_poll() has work to do:
105-
cyw43_arch_wait_for_work_until(led_time);
105+
cyw43_arch_wait_for_work_until(at_the_end_of_time);
106106
#else
107107
// if you are not using pico_cyw43_arch_poll, then WiFI driver and lwIP work
108108
// is done via interrupt in the background. This sleep is just an example of some (blocking)
109109
// work you might be doing.
110110
sleep_ms(1000);
111111
#endif
112112
}
113+
cyw43_arch_disable_sta_mode();
113114

114115
cyw43_arch_deinit();
115116
printf("Test complete\n");

pico_w/wifi/ntp_client/picow_ntp_client.c

Lines changed: 38 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -16,18 +16,17 @@
1616

1717
typedef struct NTP_T_ {
1818
ip_addr_t ntp_server_address;
19-
bool dns_request_sent;
2019
struct udp_pcb *ntp_pcb;
21-
absolute_time_t ntp_test_time;
22-
alarm_id_t ntp_resend_alarm;
20+
async_at_time_worker_t request_worker;
21+
async_at_time_worker_t resend_worker;
2322
} NTP_T;
2423

2524
#define NTP_SERVER "pool.ntp.org"
2625
#define NTP_MSG_LEN 48
2726
#define NTP_PORT 123
2827
#define NTP_DELTA 2208988800 // seconds between 1 Jan 1900 and 1 Jan 1970
29-
#define NTP_TEST_TIME (30 * 1000)
30-
#define NTP_RESEND_TIME (10 * 1000)
28+
#define NTP_TEST_TIME_MS (30 * 1000)
29+
#define NTP_RESEND_TIME_MS (10 * 1000)
3130

3231
// Called with results of operation
3332
static void ntp_result(NTP_T* state, int status, time_t *result) {
@@ -36,17 +35,11 @@ static void ntp_result(NTP_T* state, int status, time_t *result) {
3635
printf("got ntp response: %02d/%02d/%04d %02d:%02d:%02d\n", utc->tm_mday, utc->tm_mon + 1, utc->tm_year + 1900,
3736
utc->tm_hour, utc->tm_min, utc->tm_sec);
3837
}
39-
40-
if (state->ntp_resend_alarm > 0) {
41-
cancel_alarm(state->ntp_resend_alarm);
42-
state->ntp_resend_alarm = 0;
43-
}
44-
state->ntp_test_time = make_timeout_time_ms(NTP_TEST_TIME);
45-
state->dns_request_sent = false;
38+
async_context_remove_at_time_worker(cyw43_arch_async_context(), &state->resend_worker);
39+
hard_assert(async_context_add_at_time_worker_in_ms(cyw43_arch_async_context(), &state->request_worker, NTP_TEST_TIME_MS)); // repeat the request in future
40+
printf("Next request in %ds\n", NTP_TEST_TIME_MS / 1000);
4641
}
4742

48-
static int64_t ntp_failed_handler(alarm_id_t id, void *user_data);
49-
5043
// Make an NTP request
5144
static void ntp_request(NTP_T *state) {
5245
// cyw43_arch_lwip_begin/end should be used around calls into lwIP to ensure correct locking.
@@ -63,14 +56,6 @@ static void ntp_request(NTP_T *state) {
6356
cyw43_arch_lwip_end();
6457
}
6558

66-
static int64_t ntp_failed_handler(alarm_id_t id, void *user_data)
67-
{
68-
NTP_T* state = (NTP_T*)user_data;
69-
printf("ntp request failed\n");
70-
ntp_result(state, -1, NULL);
71-
return 0;
72-
}
73-
7459
// Call back with a DNS result
7560
static void ntp_dns_found(const char *hostname, const ip_addr_t *ipaddr, void *arg) {
7661
NTP_T *state = (NTP_T*)arg;
@@ -106,6 +91,26 @@ static void ntp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, const ip_ad
10691
pbuf_free(p);
10792
}
10893

94+
// Called to make a NTP request
95+
static void request_worker_fn(__unused async_context_t *context, async_at_time_worker_t *worker) {
96+
NTP_T* state = (NTP_T*)worker->user_data;
97+
hard_assert(async_context_add_at_time_worker_in_ms(cyw43_arch_async_context(), &state->resend_worker, NTP_RESEND_TIME_MS)); // in case UDP request is lost
98+
int err = dns_gethostbyname(NTP_SERVER, &state->ntp_server_address, ntp_dns_found, state);
99+
if (err == ERR_OK) {
100+
ntp_request(state); // Cached DNS result, make NTP request
101+
} else if (err != ERR_INPROGRESS) { // ERR_INPROGRESS means expect a callback
102+
printf("dns request failed\n");
103+
ntp_result(state, -1, NULL);
104+
}
105+
}
106+
107+
// Called to resend an NTP request if it appears to get lost
108+
static void resend_worker_fn(__unused async_context_t *context, async_at_time_worker_t *worker) {
109+
NTP_T* state = (NTP_T*)worker->user_data;
110+
printf("ntp request failed\n");
111+
ntp_result(state, -1, NULL);
112+
}
113+
109114
// Perform initialisation
110115
static NTP_T* ntp_init(void) {
111116
NTP_T *state = (NTP_T*)calloc(1, sizeof(NTP_T));
@@ -120,6 +125,10 @@ static NTP_T* ntp_init(void) {
120125
return NULL;
121126
}
122127
udp_recv(state->ntp_pcb, ntp_recv, state);
128+
state->request_worker.do_work = request_worker_fn;
129+
state->request_worker.user_data = state;
130+
state->resend_worker.do_work = resend_worker_fn;
131+
state->resend_worker.user_data = state;
123132
return state;
124133
}
125134

@@ -128,34 +137,20 @@ void run_ntp_test(void) {
128137
NTP_T *state = ntp_init();
129138
if (!state)
130139
return;
140+
printf("Press 'q' to quit\n");
141+
hard_assert(async_context_add_at_time_worker_in_ms(cyw43_arch_async_context(), &state->request_worker, 0)); // make the first request
131142
while(true) {
132-
if (absolute_time_diff_us(get_absolute_time(), state->ntp_test_time) < 0 && !state->dns_request_sent) {
133-
// Set alarm in case udp requests are lost
134-
state->ntp_resend_alarm = add_alarm_in_ms(NTP_RESEND_TIME, ntp_failed_handler, state, true);
135-
136-
// cyw43_arch_lwip_begin/end should be used around calls into lwIP to ensure correct locking.
137-
// You can omit them if you are in a callback from lwIP. Note that when using pico_cyw_arch_poll
138-
// these calls are a no-op and can be omitted, but it is a good practice to use them in
139-
// case you switch the cyw43_arch type later.
140-
cyw43_arch_lwip_begin();
141-
int err = dns_gethostbyname(NTP_SERVER, &state->ntp_server_address, ntp_dns_found, state);
142-
cyw43_arch_lwip_end();
143-
144-
state->dns_request_sent = true;
145-
if (err == ERR_OK) {
146-
ntp_request(state); // Cached result
147-
} else if (err != ERR_INPROGRESS) { // ERR_INPROGRESS means expect a callback
148-
printf("dns request failed\n");
149-
ntp_result(state, -1, NULL);
150-
}
143+
int key = getchar_timeout_us(0);
144+
if (key == 'q' || key == 'Q') {
145+
break;
151146
}
152147
#if PICO_CYW43_ARCH_POLL
153148
// if you are using pico_cyw43_arch_poll, then you must poll periodically from your
154149
// main loop (not from a timer interrupt) to check for Wi-Fi driver or lwIP work that needs to be done.
155150
cyw43_arch_poll();
156151
// you can poll as often as you like, however if you have nothing else to do you can
157152
// choose to sleep until either a specified time, or cyw43_arch_poll() has work to do:
158-
cyw43_arch_wait_for_work_until(state->dns_request_sent ? at_the_end_of_time : state->ntp_test_time);
153+
cyw43_arch_wait_for_work_until(at_the_end_of_time);
159154
#else
160155
// if you are not using pico_cyw43_arch_poll, then WiFI driver and lwIP work
161156
// is done via interrupt in the background. This sleep is just an example of some (blocking)
@@ -176,7 +171,7 @@ int main() {
176171

177172
cyw43_arch_enable_sta_mode();
178173

179-
if (cyw43_arch_wifi_connect_timeout_ms(WIFI_SSID, WIFI_PASSWORD, CYW43_AUTH_WPA2_AES_PSK, 10000)) {
174+
if (cyw43_arch_wifi_connect_timeout_ms(WIFI_SSID, WIFI_PASSWORD, CYW43_AUTH_WPA2_AES_PSK, 30000)) {
180175
printf("failed to connect\n");
181176
return 1;
182177
}

pico_w/wifi/wifi_scan/picow_wifi_scan.c

Lines changed: 30 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,19 @@ static int scan_result(void *env, const cyw43_ev_scan_result_t *result) {
1919
return 0;
2020
}
2121

22+
// Start a wifi scan
23+
static void scan_worker_fn(async_context_t *context, async_at_time_worker_t *worker) {
24+
cyw43_wifi_scan_options_t scan_options = {0};
25+
int err = cyw43_wifi_scan(&cyw43_state, &scan_options, NULL, scan_result);
26+
if (err == 0) {
27+
bool *scan_started = (bool*)worker->user_data;
28+
*scan_started = true;
29+
printf("\nPerforming wifi scan\n");
30+
} else {
31+
printf("Failed to start scan: %d\n", err);
32+
}
33+
}
34+
2235
#include "hardware/vreg.h"
2336
#include "hardware/clocks.h"
2437

@@ -30,26 +43,24 @@ int main() {
3043
return 1;
3144
}
3245

46+
printf("Press 'q' to quit\n");
3347
cyw43_arch_enable_sta_mode();
3448

35-
absolute_time_t scan_time = nil_time;
36-
bool scan_in_progress = false;
37-
while(true) {
38-
if (absolute_time_diff_us(get_absolute_time(), scan_time) < 0) {
39-
if (!scan_in_progress) {
40-
cyw43_wifi_scan_options_t scan_options = {0};
41-
int err = cyw43_wifi_scan(&cyw43_state, &scan_options, NULL, scan_result);
42-
if (err == 0) {
43-
printf("\nPerforming wifi scan\n");
44-
scan_in_progress = true;
45-
} else {
46-
printf("Failed to start scan: %d\n", err);
47-
scan_time = make_timeout_time_ms(10000); // wait 10s and scan again
48-
}
49-
} else if (!cyw43_wifi_scan_active(&cyw43_state)) {
50-
scan_time = make_timeout_time_ms(10000); // wait 10s and scan again
51-
scan_in_progress = false;
52-
}
49+
// Start a scan immediately
50+
bool scan_started = false;
51+
async_at_time_worker_t scan_worker = { .do_work = scan_worker_fn, .user_data = &scan_started };
52+
hard_assert(async_context_add_at_time_worker_in_ms(cyw43_arch_async_context(), &scan_worker, 0));
53+
54+
bool exit = false;
55+
while(!exit) {
56+
int key = getchar_timeout_us(0);
57+
if (key == 'q' || key == 'Q') {
58+
exit = true;
59+
}
60+
if (!cyw43_wifi_scan_active(&cyw43_state) && scan_started) {
61+
// Start a scan in 10s
62+
scan_started = false;
63+
hard_assert(async_context_add_at_time_worker_in_ms(cyw43_arch_async_context(), &scan_worker, 10000));
5364
}
5465
// the following #ifdef is only here so this same example can be used in multiple modes;
5566
// you do not need it in your code
@@ -59,7 +70,7 @@ int main() {
5970
cyw43_arch_poll();
6071
// you can poll as often as you like, however if you have nothing else to do you can
6172
// choose to sleep until either a specified time, or cyw43_arch_poll() has work to do:
62-
cyw43_arch_wait_for_work_until(scan_time);
73+
cyw43_arch_wait_for_work_until(at_the_end_of_time);
6374
#else
6475
// if you are not using pico_cyw43_arch_poll, then WiFI driver and lwIP work
6576
// is done via interrupt in the background. This sleep is just an example of some (blocking)

0 commit comments

Comments
 (0)