Skip to content

Some example improvements #634

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 23 additions & 22 deletions pico_w/wifi/iperf/picow_iperf.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,17 @@
#error IPERF_SERVER_IP not defined
#endif

#if USE_LED
// Invert led
static void led_worker_fn(async_context_t *context, async_at_time_worker_t *worker) {
// Invert the led
static int led_on = true;
led_on = !led_on;
cyw43_arch_gpio_put(CYW43_WL_GPIO_LED_PIN, led_on);
async_context_add_at_time_worker_in_ms(context, worker, 1000);
}
#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,
Expand All @@ -36,12 +47,12 @@ static void iperf_report(void *arg, enum lwiperf_report_type report_type,
#endif
}

// Note: This is called from an interrupt handler
void key_pressed_func(void *param) {
int key = getchar_timeout_us(0); // get any pending key press but don't wait
if (key == 'd' || key == 'D') {
cyw43_arch_lwip_begin();
cyw43_arch_disable_sta_mode();
cyw43_arch_lwip_end();
bool *exit = (bool*)param;
*exit = true;
}
}

Expand All @@ -53,9 +64,6 @@ int main() {
return 1;
}

// Get notified if the user presses a key
stdio_set_chars_available_callback(key_pressed_func, cyw43_arch_async_context());

cyw43_arch_enable_sta_mode();
printf("Connecting to Wi-Fi... (press 'd' to disconnect)\n");
if (cyw43_arch_wifi_connect_timeout_ms(WIFI_SSID, WIFI_PASSWORD, CYW43_AUTH_WPA2_AES_PSK, 30000)) {
Expand All @@ -77,23 +85,15 @@ int main() {
#endif
cyw43_arch_lwip_end();

while(cyw43_wifi_link_status(&cyw43_state, CYW43_ITF_STA) != CYW43_LINK_DOWN) {
bool exit = false;
stdio_set_chars_available_callback(key_pressed_func, &exit);

#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);
}
// start the led flashing
async_at_time_worker_t led_worker = { .do_work = led_worker_fn };
async_context_add_at_time_worker_in_ms(cyw43_arch_async_context(), &led_worker, 0);
#endif
while(!exit && cyw43_wifi_link_status(&cyw43_state, CYW43_ITF_STA) != CYW43_LINK_DOWN) {
// 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
Expand All @@ -102,14 +102,15 @@ int main() {
cyw43_arch_poll();
// you can poll as often as you like, however if you have nothing else to do you can
// choose to sleep until either a specified time, or cyw43_arch_poll() has work to do:
cyw43_arch_wait_for_work_until(led_time);
cyw43_arch_wait_for_work_until(at_the_end_of_time);
#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_disable_sta_mode();

cyw43_arch_deinit();
printf("Test complete\n");
Expand Down
81 changes: 38 additions & 43 deletions pico_w/wifi/ntp_client/picow_ntp_client.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,18 +16,17 @@

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;
async_at_time_worker_t request_worker;
async_at_time_worker_t resend_worker;
} 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)
#define NTP_TEST_TIME_MS (30 * 1000)
#define NTP_RESEND_TIME_MS (10 * 1000)

// Called with results of operation
static void ntp_result(NTP_T* state, int status, time_t *result) {
Expand All @@ -36,17 +35,11 @@ static void ntp_result(NTP_T* state, int status, time_t *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;
async_context_remove_at_time_worker(cyw43_arch_async_context(), &state->resend_worker);
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
printf("Next request in %ds\n", NTP_TEST_TIME_MS / 1000);
}

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.
Expand All @@ -63,14 +56,6 @@ static void ntp_request(NTP_T *state) {
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;
Expand Down Expand Up @@ -106,6 +91,26 @@ static void ntp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, const ip_ad
pbuf_free(p);
}

// Called to make a NTP request
static void request_worker_fn(__unused async_context_t *context, async_at_time_worker_t *worker) {
NTP_T* state = (NTP_T*)worker->user_data;
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
int err = dns_gethostbyname(NTP_SERVER, &state->ntp_server_address, ntp_dns_found, state);
if (err == ERR_OK) {
ntp_request(state); // Cached DNS result, make NTP request
} else if (err != ERR_INPROGRESS) { // ERR_INPROGRESS means expect a callback
printf("dns request failed\n");
ntp_result(state, -1, NULL);
}
}

// Called to resend an NTP request if it appears to get lost
static void resend_worker_fn(__unused async_context_t *context, async_at_time_worker_t *worker) {
NTP_T* state = (NTP_T*)worker->user_data;
printf("ntp request failed\n");
ntp_result(state, -1, NULL);
}

// Perform initialisation
static NTP_T* ntp_init(void) {
NTP_T *state = (NTP_T*)calloc(1, sizeof(NTP_T));
Expand All @@ -120,6 +125,10 @@ static NTP_T* ntp_init(void) {
return NULL;
}
udp_recv(state->ntp_pcb, ntp_recv, state);
state->request_worker.do_work = request_worker_fn;
state->request_worker.user_data = state;
state->resend_worker.do_work = resend_worker_fn;
state->resend_worker.user_data = state;
return state;
}

Expand All @@ -128,34 +137,20 @@ void run_ntp_test(void) {
NTP_T *state = ntp_init();
if (!state)
return;
printf("Press 'q' to quit\n");
hard_assert(async_context_add_at_time_worker_in_ms(cyw43_arch_async_context(), &state->request_worker, 0)); // make the first request
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);
}
int key = getchar_timeout_us(0);
if (key == 'q' || key == 'Q') {
break;
}
#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 interrupt) to check for Wi-Fi driver or lwIP work that needs to be done.
cyw43_arch_poll();
// you can poll as often as you like, however if you have nothing else to do you can
// choose to sleep until either a specified time, or cyw43_arch_poll() has work to do:
cyw43_arch_wait_for_work_until(state->dns_request_sent ? at_the_end_of_time : state->ntp_test_time);
cyw43_arch_wait_for_work_until(at_the_end_of_time);
#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)
Expand All @@ -176,7 +171,7 @@ int main() {

cyw43_arch_enable_sta_mode();

if (cyw43_arch_wifi_connect_timeout_ms(WIFI_SSID, WIFI_PASSWORD, CYW43_AUTH_WPA2_AES_PSK, 10000)) {
if (cyw43_arch_wifi_connect_timeout_ms(WIFI_SSID, WIFI_PASSWORD, CYW43_AUTH_WPA2_AES_PSK, 30000)) {
printf("failed to connect\n");
return 1;
}
Expand Down
49 changes: 30 additions & 19 deletions pico_w/wifi/wifi_scan/picow_wifi_scan.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,19 @@ static int scan_result(void *env, const cyw43_ev_scan_result_t *result) {
return 0;
}

// Start a wifi scan
static void scan_worker_fn(async_context_t *context, async_at_time_worker_t *worker) {
cyw43_wifi_scan_options_t scan_options = {0};
int err = cyw43_wifi_scan(&cyw43_state, &scan_options, NULL, scan_result);
if (err == 0) {
bool *scan_started = (bool*)worker->user_data;
*scan_started = true;
printf("\nPerforming wifi scan\n");
} else {
printf("Failed to start scan: %d\n", err);
}
}

#include "hardware/vreg.h"
#include "hardware/clocks.h"

Expand All @@ -30,26 +43,24 @@ int main() {
return 1;
}

printf("Press 'q' to quit\n");
cyw43_arch_enable_sta_mode();

absolute_time_t scan_time = nil_time;
bool scan_in_progress = false;
while(true) {
if (absolute_time_diff_us(get_absolute_time(), scan_time) < 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_time = make_timeout_time_ms(10000); // wait 10s and scan again
}
} else if (!cyw43_wifi_scan_active(&cyw43_state)) {
scan_time = make_timeout_time_ms(10000); // wait 10s and scan again
scan_in_progress = false;
}
// Start a scan immediately
bool scan_started = false;
async_at_time_worker_t scan_worker = { .do_work = scan_worker_fn, .user_data = &scan_started };
hard_assert(async_context_add_at_time_worker_in_ms(cyw43_arch_async_context(), &scan_worker, 0));

bool exit = false;
while(!exit) {
int key = getchar_timeout_us(0);
if (key == 'q' || key == 'Q') {
exit = true;
}
if (!cyw43_wifi_scan_active(&cyw43_state) && scan_started) {
// Start a scan in 10s
scan_started = false;
hard_assert(async_context_add_at_time_worker_in_ms(cyw43_arch_async_context(), &scan_worker, 10000));
}
// the following #ifdef is only here so this same example can be used in multiple modes;
// you do not need it in your code
Expand All @@ -59,7 +70,7 @@ int main() {
cyw43_arch_poll();
// you can poll as often as you like, however if you have nothing else to do you can
// choose to sleep until either a specified time, or cyw43_arch_poll() has work to do:
cyw43_arch_wait_for_work_until(scan_time);
cyw43_arch_wait_for_work_until(at_the_end_of_time);
#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)
Expand Down