1 /*
2 * Copyright (c) 2022 Raspberry Pi (Trading) Ltd.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7 #include <stdlib.h>
8 #include <stdio.h>
9 #include <string.h>
10
11 #include "pico/unique_id.h"
12 #include "cyw43.h"
13 #include "pico/cyw43_arch.h"
14 #include "cyw43_ll.h"
15 #include "cyw43_stats.h"
16
17 #if PICO_CYW43_ARCH_DEBUG_ENABLED
18 #define CYW43_ARCH_DEBUG(...) printf(__VA_ARGS__)
19 #else
20 #define CYW43_ARCH_DEBUG(...) ((void)0)
21 #endif
22
23 static uint32_t country_code = PICO_CYW43_ARCH_DEFAULT_COUNTRY_CODE;
24
25 static async_context_t *async_context;
26
cyw43_arch_set_async_context(async_context_t * context)27 void cyw43_arch_set_async_context(async_context_t *context) {
28 async_context = context;
29 }
30
cyw43_arch_enable_sta_mode()31 void cyw43_arch_enable_sta_mode() {
32 assert(cyw43_is_initialized(&cyw43_state));
33 cyw43_wifi_set_up(&cyw43_state, CYW43_ITF_STA, true, cyw43_arch_get_country_code());
34 }
35
cyw43_arch_enable_ap_mode(const char * ssid,const char * password,uint32_t auth)36 void cyw43_arch_enable_ap_mode(const char *ssid, const char *password, uint32_t auth) {
37 assert(cyw43_is_initialized(&cyw43_state));
38 cyw43_wifi_ap_set_ssid(&cyw43_state, strlen(ssid), (const uint8_t *) ssid);
39 if (password) {
40 cyw43_wifi_ap_set_password(&cyw43_state, strlen(password), (const uint8_t *) password);
41 cyw43_wifi_ap_set_auth(&cyw43_state, auth);
42 } else {
43 cyw43_wifi_ap_set_auth(&cyw43_state, CYW43_AUTH_OPEN);
44 }
45 cyw43_wifi_set_up(&cyw43_state, CYW43_ITF_AP, true, cyw43_arch_get_country_code());
46 }
47
48 #if PICO_CYW43_ARCH_DEBUG_ENABLED
49 // Return a string for the wireless state
cyw43_tcpip_link_status_name(int status)50 static const char* cyw43_tcpip_link_status_name(int status)
51 {
52 switch (status) {
53 case CYW43_LINK_DOWN:
54 return "link down";
55 case CYW43_LINK_JOIN:
56 return "joining";
57 case CYW43_LINK_NOIP:
58 return "no ip";
59 case CYW43_LINK_UP:
60 return "link up";
61 case CYW43_LINK_FAIL:
62 return "link fail";
63 case CYW43_LINK_NONET:
64 return "network fail";
65 case CYW43_LINK_BADAUTH:
66 return "bad auth";
67 }
68 return "unknown";
69 }
70 #endif
71
72
cyw43_arch_wifi_connect_bssid_async(const char * ssid,const uint8_t * bssid,const char * pw,uint32_t auth)73 int cyw43_arch_wifi_connect_bssid_async(const char *ssid, const uint8_t *bssid, const char *pw, uint32_t auth) {
74 if (!pw) auth = CYW43_AUTH_OPEN;
75 // Connect to wireless
76 return cyw43_wifi_join(&cyw43_state, strlen(ssid), (const uint8_t *)ssid, pw ? strlen(pw) : 0, (const uint8_t *)pw, auth, bssid, CYW43_CHANNEL_NONE);
77 }
78
cyw43_arch_wifi_connect_async(const char * ssid,const char * pw,uint32_t auth)79 int cyw43_arch_wifi_connect_async(const char *ssid, const char *pw, uint32_t auth) {
80 return cyw43_arch_wifi_connect_bssid_async(ssid, NULL, pw, auth);
81 }
82
cyw43_arch_wifi_connect_bssid_until(const char * ssid,const uint8_t * bssid,const char * pw,uint32_t auth,absolute_time_t until)83 static int cyw43_arch_wifi_connect_bssid_until(const char *ssid, const uint8_t *bssid, const char *pw, uint32_t auth, absolute_time_t until) {
84 int err = cyw43_arch_wifi_connect_bssid_async(ssid, bssid, pw, auth);
85 if (err) return err;
86
87 int status = CYW43_LINK_UP + 1;
88 while(status >= 0 && status != CYW43_LINK_UP) {
89 int new_status = cyw43_tcpip_link_status(&cyw43_state, CYW43_ITF_STA);
90 // If there was no network, keep trying
91 if (new_status == CYW43_LINK_NONET) {
92 new_status = CYW43_LINK_JOIN;
93 err = cyw43_arch_wifi_connect_bssid_async(ssid, bssid, pw, auth);
94 if (err) return err;
95 }
96 if (new_status != status) {
97 status = new_status;
98 CYW43_ARCH_DEBUG("connect status: %s\n", cyw43_tcpip_link_status_name(status));
99 }
100 if (time_reached(until)) {
101 return PICO_ERROR_TIMEOUT;
102 }
103 // Do polling
104 cyw43_arch_poll();
105 cyw43_arch_wait_for_work_until(until);
106 }
107 // Turn status into a pico_error_codes, CYW43_LINK_NONET shouldn't happen as we fail with PICO_ERROR_TIMEOUT instead
108 assert(status == CYW43_LINK_UP || status == CYW43_LINK_BADAUTH || status == CYW43_LINK_FAIL);
109 if (status == CYW43_LINK_UP) {
110 return PICO_OK; // success
111 } else if (status == CYW43_LINK_BADAUTH) {
112 return PICO_ERROR_BADAUTH;
113 } else {
114 return PICO_ERROR_CONNECT_FAILED;
115 }
116 }
117
118 // Connect to wireless, return with success when an IP address has been assigned
cyw43_arch_wifi_connect_until(const char * ssid,const char * pw,uint32_t auth,absolute_time_t until)119 static int cyw43_arch_wifi_connect_until(const char *ssid, const char *pw, uint32_t auth, absolute_time_t until) {
120 return cyw43_arch_wifi_connect_bssid_until(ssid, NULL, pw, auth, until);
121 }
122
cyw43_arch_wifi_connect_blocking(const char * ssid,const char * pw,uint32_t auth)123 int cyw43_arch_wifi_connect_blocking(const char *ssid, const char *pw, uint32_t auth) {
124 return cyw43_arch_wifi_connect_until(ssid, pw, auth, at_the_end_of_time);
125 }
126
cyw43_arch_wifi_connect_bssid_blocking(const char * ssid,const uint8_t * bssid,const char * pw,uint32_t auth)127 int cyw43_arch_wifi_connect_bssid_blocking(const char *ssid, const uint8_t *bssid, const char *pw, uint32_t auth) {
128 return cyw43_arch_wifi_connect_bssid_until(ssid, bssid, pw, auth, at_the_end_of_time);
129 }
130
cyw43_arch_wifi_connect_timeout_ms(const char * ssid,const char * pw,uint32_t auth,uint32_t timeout_ms)131 int cyw43_arch_wifi_connect_timeout_ms(const char *ssid, const char *pw, uint32_t auth, uint32_t timeout_ms) {
132 return cyw43_arch_wifi_connect_until(ssid, pw, auth, make_timeout_time_ms(timeout_ms));
133 }
134
cyw43_arch_wifi_connect_bssid_timeout_ms(const char * ssid,const uint8_t * bssid,const char * pw,uint32_t auth,uint32_t timeout_ms)135 int cyw43_arch_wifi_connect_bssid_timeout_ms(const char *ssid, const uint8_t *bssid, const char *pw, uint32_t auth, uint32_t timeout_ms) {
136 return cyw43_arch_wifi_connect_bssid_until(ssid, bssid, pw, auth, make_timeout_time_ms(timeout_ms));
137 }
138
cyw43_arch_get_country_code(void)139 uint32_t cyw43_arch_get_country_code(void) {
140 return country_code;
141 }
142
cyw43_arch_init_with_country(uint32_t country)143 int cyw43_arch_init_with_country(uint32_t country) {
144 country_code = country;
145 return cyw43_arch_init();
146 }
147
cyw43_arch_gpio_put(uint wl_gpio,bool value)148 void cyw43_arch_gpio_put(uint wl_gpio, bool value) {
149 invalid_params_if(CYW43_ARCH, wl_gpio >= CYW43_WL_GPIO_COUNT);
150 cyw43_gpio_set(&cyw43_state, (int)wl_gpio, value);
151 }
152
cyw43_arch_gpio_get(uint wl_gpio)153 bool cyw43_arch_gpio_get(uint wl_gpio) {
154 invalid_params_if(CYW43_ARCH, wl_gpio >= CYW43_WL_GPIO_COUNT);
155 bool value = false;
156 cyw43_gpio_get(&cyw43_state, (int)wl_gpio, &value);
157 return value;
158 }
159
cyw43_arch_async_context(void)160 async_context_t *cyw43_arch_async_context(void) {
161 return async_context;
162 }
163
cyw43_arch_poll(void)164 void cyw43_arch_poll(void)
165 {
166 async_context_poll(async_context);
167 }
168
cyw43_arch_wait_for_work_until(absolute_time_t until)169 void cyw43_arch_wait_for_work_until(absolute_time_t until) {
170 async_context_wait_for_work_until(async_context, until);
171 }
172