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(void)31 void cyw43_arch_enable_sta_mode(void) {
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_disable_sta_mode(void)36 void cyw43_arch_disable_sta_mode(void) {
37 assert(cyw43_is_initialized(&cyw43_state));
38 if (cyw43_state.itf_state & (1 << CYW43_ITF_STA)) {
39 cyw43_cb_tcpip_deinit(&cyw43_state, CYW43_ITF_STA);
40 cyw43_state.itf_state &= ~(1 << CYW43_ITF_STA);
41 }
42 if (cyw43_state.wifi_join_state) {
43 cyw43_wifi_leave(&cyw43_state, CYW43_ITF_STA);
44 }
45 }
46
cyw43_arch_enable_ap_mode(const char * ssid,const char * password,uint32_t auth)47 void cyw43_arch_enable_ap_mode(const char *ssid, const char *password, uint32_t auth) {
48 assert(cyw43_is_initialized(&cyw43_state));
49 cyw43_wifi_ap_set_ssid(&cyw43_state, strlen(ssid), (const uint8_t *) ssid);
50 if (password) {
51 cyw43_wifi_ap_set_password(&cyw43_state, strlen(password), (const uint8_t *) password);
52 cyw43_wifi_ap_set_auth(&cyw43_state, auth);
53 } else {
54 cyw43_wifi_ap_set_auth(&cyw43_state, CYW43_AUTH_OPEN);
55 }
56 cyw43_wifi_set_up(&cyw43_state, CYW43_ITF_AP, true, cyw43_arch_get_country_code());
57 }
58
cyw43_arch_disable_ap_mode(void)59 void cyw43_arch_disable_ap_mode(void) {
60 assert(cyw43_is_initialized(&cyw43_state));
61 cyw43_wifi_set_up(&cyw43_state, CYW43_ITF_AP, false, cyw43_arch_get_country_code());
62 cyw43_state.itf_state &= ~(1 << CYW43_ITF_AP);
63 }
64
65 #if PICO_CYW43_ARCH_DEBUG_ENABLED
66 // Return a string for the wireless state
cyw43_tcpip_link_status_name(int status)67 static const char* cyw43_tcpip_link_status_name(int status)
68 {
69 switch (status) {
70 case CYW43_LINK_DOWN:
71 return "link down";
72 case CYW43_LINK_JOIN:
73 return "joining";
74 case CYW43_LINK_NOIP:
75 return "no ip";
76 case CYW43_LINK_UP:
77 return "link up";
78 case CYW43_LINK_FAIL:
79 return "link fail";
80 case CYW43_LINK_NONET:
81 return "network fail";
82 case CYW43_LINK_BADAUTH:
83 return "bad auth";
84 }
85 return "unknown";
86 }
87 #endif
88
89
cyw43_arch_wifi_connect_bssid_async(const char * ssid,const uint8_t * bssid,const char * pw,uint32_t auth)90 int cyw43_arch_wifi_connect_bssid_async(const char *ssid, const uint8_t *bssid, const char *pw, uint32_t auth) {
91 if (!pw) auth = CYW43_AUTH_OPEN;
92 // Connect to wireless
93 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);
94 }
95
cyw43_arch_wifi_connect_async(const char * ssid,const char * pw,uint32_t auth)96 int cyw43_arch_wifi_connect_async(const char *ssid, const char *pw, uint32_t auth) {
97 return cyw43_arch_wifi_connect_bssid_async(ssid, NULL, pw, auth);
98 }
99
cyw43_arch_wifi_connect_bssid_until(const char * ssid,const uint8_t * bssid,const char * pw,uint32_t auth,absolute_time_t until)100 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) {
101 int err = cyw43_arch_wifi_connect_bssid_async(ssid, bssid, pw, auth);
102 if (err) return err;
103
104 int status = CYW43_LINK_UP + 1;
105 while(status >= 0 && status != CYW43_LINK_UP) {
106 int new_status = cyw43_tcpip_link_status(&cyw43_state, CYW43_ITF_STA);
107 // If there was no network, keep trying
108 if (new_status == CYW43_LINK_NONET) {
109 new_status = CYW43_LINK_JOIN;
110 err = cyw43_arch_wifi_connect_bssid_async(ssid, bssid, pw, auth);
111 if (err) return err;
112 }
113 if (new_status != status) {
114 status = new_status;
115 CYW43_ARCH_DEBUG("connect status: %s\n", cyw43_tcpip_link_status_name(status));
116 }
117 if (time_reached(until)) {
118 return PICO_ERROR_TIMEOUT;
119 }
120 // Do polling
121 cyw43_arch_poll();
122 cyw43_arch_wait_for_work_until(until);
123 }
124 // Turn status into a pico_error_codes, CYW43_LINK_NONET shouldn't happen as we fail with PICO_ERROR_TIMEOUT instead
125 assert(status == CYW43_LINK_UP || status == CYW43_LINK_BADAUTH || status == CYW43_LINK_FAIL);
126 if (status == CYW43_LINK_UP) {
127 return PICO_OK; // success
128 } else if (status == CYW43_LINK_BADAUTH) {
129 return PICO_ERROR_BADAUTH;
130 } else {
131 return PICO_ERROR_CONNECT_FAILED;
132 }
133 }
134
135 // 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)136 static int cyw43_arch_wifi_connect_until(const char *ssid, const char *pw, uint32_t auth, absolute_time_t until) {
137 return cyw43_arch_wifi_connect_bssid_until(ssid, NULL, pw, auth, until);
138 }
139
cyw43_arch_wifi_connect_blocking(const char * ssid,const char * pw,uint32_t auth)140 int cyw43_arch_wifi_connect_blocking(const char *ssid, const char *pw, uint32_t auth) {
141 return cyw43_arch_wifi_connect_until(ssid, pw, auth, at_the_end_of_time);
142 }
143
cyw43_arch_wifi_connect_bssid_blocking(const char * ssid,const uint8_t * bssid,const char * pw,uint32_t auth)144 int cyw43_arch_wifi_connect_bssid_blocking(const char *ssid, const uint8_t *bssid, const char *pw, uint32_t auth) {
145 return cyw43_arch_wifi_connect_bssid_until(ssid, bssid, pw, auth, at_the_end_of_time);
146 }
147
cyw43_arch_wifi_connect_timeout_ms(const char * ssid,const char * pw,uint32_t auth,uint32_t timeout_ms)148 int cyw43_arch_wifi_connect_timeout_ms(const char *ssid, const char *pw, uint32_t auth, uint32_t timeout_ms) {
149 return cyw43_arch_wifi_connect_until(ssid, pw, auth, make_timeout_time_ms(timeout_ms));
150 }
151
cyw43_arch_wifi_connect_bssid_timeout_ms(const char * ssid,const uint8_t * bssid,const char * pw,uint32_t auth,uint32_t timeout_ms)152 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) {
153 return cyw43_arch_wifi_connect_bssid_until(ssid, bssid, pw, auth, make_timeout_time_ms(timeout_ms));
154 }
155
cyw43_arch_get_country_code(void)156 uint32_t cyw43_arch_get_country_code(void) {
157 return country_code;
158 }
159
cyw43_arch_init_with_country(uint32_t country)160 int cyw43_arch_init_with_country(uint32_t country) {
161 country_code = country;
162 return cyw43_arch_init();
163 }
164
cyw43_arch_gpio_put(uint wl_gpio,bool value)165 void cyw43_arch_gpio_put(uint wl_gpio, bool value) {
166 invalid_params_if(PICO_CYW43_ARCH, wl_gpio >= CYW43_WL_GPIO_COUNT);
167 cyw43_gpio_set(&cyw43_state, (int)wl_gpio, value);
168 }
169
cyw43_arch_gpio_get(uint wl_gpio)170 bool cyw43_arch_gpio_get(uint wl_gpio) {
171 invalid_params_if(PICO_CYW43_ARCH, wl_gpio >= CYW43_WL_GPIO_COUNT);
172 bool value = false;
173 cyw43_gpio_get(&cyw43_state, (int)wl_gpio, &value);
174 return value;
175 }
176
cyw43_arch_async_context(void)177 async_context_t *cyw43_arch_async_context(void) {
178 return async_context;
179 }
180
cyw43_arch_poll(void)181 void cyw43_arch_poll(void)
182 {
183 async_context_poll(async_context);
184 }
185
cyw43_arch_wait_for_work_until(absolute_time_t until)186 void cyw43_arch_wait_for_work_until(absolute_time_t until) {
187 async_context_wait_for_work_until(async_context, until);
188 }
189