1 /*
2  * Copyright (c) 2022 Raspberry Pi (Trading) Ltd.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  */
6 
7 #ifndef _PICO_CYW43_ARCH_H
8 #define _PICO_CYW43_ARCH_H
9 
10 #include "pico.h"
11 
12 #ifdef __cplusplus
13 extern "C" {
14 #endif
15 
16 #include "cyw43.h"
17 #include "cyw43_country.h"
18 #include "pico/async_context.h"
19 
20 #ifdef PICO_CYW43_ARCH_HEADER
21 #include __XSTRING(PICO_CYW43_ARCH_HEADER)
22 #else
23 #if PICO_CYW43_ARCH_POLL
24 #include "pico/cyw43_arch/arch_poll.h"
25 #elif PICO_CYW43_ARCH_THREADSAFE_BACKGROUND
26 #include "pico/cyw43_arch/arch_threadsafe_background.h"
27 #elif PICO_CYW43_ARCH_FREERTOS
28 #include "pico/cyw43_arch/arch_freertos.h"
29 #else
30 #error must specify support pico_cyw43_arch architecture type or set PICO_CYW43_ARCH_HEADER
31 #endif
32 #endif
33 
34 /**
35  * \defgroup cyw43_driver cyw43_driver
36  * \ingroup pico_cyw43_arch
37  * \brief Driver used for Pico W wireless
38 */
39 
40 /**
41  * \defgroup cyw43_ll cyw43_ll
42  * \ingroup cyw43_driver
43  * \brief Low Level CYW43 driver interface
44 */
45 
46 /** \file pico/cyw43_arch.h
47  *  \defgroup pico_cyw43_arch pico_cyw43_arch
48  *
49  * \brief Architecture for integrating the CYW43 driver (for the wireless on Pico W) and lwIP (for TCP/IP stack) into the SDK. It is also necessary for accessing the on-board LED on Pico W
50  *
51  * Both the low level \c cyw43_driver and the lwIP stack require periodic servicing, and have limitations
52  * on whether they can be called from multiple cores/threads.
53  *
54  * \c pico_cyw43_arch attempts to abstract these complications into several behavioral groups:
55  *
56  * * \em 'poll' - This not multi-core/IRQ safe, and requires the user to call \ref cyw43_arch_poll periodically from their main loop
57  * * \em 'thread_safe_background' - This is multi-core/thread/task safe, and maintenance of the driver and TCP/IP stack is handled automatically in the background
58  * * \em 'freertos' - This is multi-core/thread/task safe, and uses a separate FreeRTOS task to handle lwIP and and driver work.
59  *
60  * As of right now, lwIP is the only supported TCP/IP stack, however the use of \c pico_cyw43_arch is intended to be independent of
61  * the particular TCP/IP stack used (and possibly Bluetooth stack used) in the future. For this reason, the integration of lwIP
62  * is handled in the base (\c pico_cyw43_arch) library based on the #define \ref CYW43_LWIP used by the \c cyw43_driver.
63  *
64  * \note As of version 1.5.0 of the Raspberry Pi Pico SDK, the \c pico_cyw43_arch library no longer directly implements
65  * the distinct behavioral abstractions. This is now handled by the more general \ref pico_async_context library. The
66  * user facing behavior of pico_cyw43_arch has not changed as a result of this implementation detail, however pico_cyw43_arch
67  * is now just a thin wrapper which creates an appropriate async_context and makes a simple call to add lwIP or cyw43_driver support
68  * as appropriate. You are free to perform this context creation and adding of lwIP, cyw43_driver or indeed any other additional
69  * future protocol/driver support to your async_context, however for now pico_cyw43_arch does still provide a few cyw43_ specific (i.e. Pico W)
70  * APIs for connection management, locking and GPIO interaction.
71  *
72  * \note The connection management APIs at least may be moved
73  * to a more generic library in a future release. The locking methods are now backed by their \ref pico_async_context equivalents, and
74  * those methods may be used interchangeably (see \ref cyw43_arch_lwip_begin, \ref cyw43_arch_lwip_end and \ref cyw43_arch_lwip_check for more details).
75  *
76  * \note For examples of creating of your own async_context and addition of \c cyw43_driver and \c lwIP support, please
77  * refer to the specific source files \c cyw43_arch_poll.c, \c cyw43_arch_threadsafe_background.c and \c cyw43_arch_freertos.c.
78  *
79  * Whilst you can use the \c pico_cyw43_arch library directly and specify \ref CYW43_LWIP (and other defines) yourself, several
80  * other libraries are made available to the build which aggregate the defines and other dependencies for you:
81  *
82  * * \b pico_cyw43_arch_lwip_poll - For using the RAW lwIP API (in `NO_SYS=1` mode) without any background processing or multi-core/thread safety.
83  *
84  *    The user must call \ref cyw43_arch_poll periodically from their main loop.
85  *
86  *    This wrapper library:
87  *    - Sets \c CYW43_LWIP=1 to enable lwIP support in \c pico_cyw43_arch and \c cyw43_driver.
88  *    - Sets \c PICO_CYW43_ARCH_POLL=1 to select the polling behavior.
89  *    - Adds the \c pico_lwip as a dependency to pull in lwIP.
90  *
91  * * \b pico_cyw43_arch_lwip_threadsafe_background - For using the RAW lwIP API (in `NO_SYS=1` mode) with multi-core/thread safety, and automatic servicing of the \c cyw43_driver and
92  * lwIP in background.
93  *
94  *    Calls into the \c cyw43_driver high level API (cyw43.h) may be made from either core or from lwIP callbacks, however calls into lwIP (which
95  * is not thread-safe) other than those made from lwIP callbacks, must be bracketed with \ref cyw43_arch_lwip_begin and \ref cyw43_arch_lwip_end. It is fine to bracket
96  * calls made from within lwIP callbacks too; you just don't have to.
97  *
98  *    \note lwIP callbacks happen in a (low priority) IRQ context (similar to an alarm callback), so care should be taken when interacting
99  *    with other code.
100  *
101  *    This wrapper library:
102  *    - Sets \c CYW43_LWIP=1 to enable lwIP support in \c pico_cyw43_arch and \c cyw43_driver
103  *    - Sets \c PICO_CYW43_ARCH_THREADSAFE_BACKGROUND=1 to select the thread-safe/non-polling behavior.
104  *    - Adds the pico_lwip as a dependency to pull in lwIP.
105  *
106  *
107  *    This library \em can also be used under the RP2040 port of FreeRTOS with lwIP in `NO_SYS=1` mode (allowing you to call \c cyw43_driver APIs
108  * from any task, and to call lwIP from lwIP callbacks, or from any task if you bracket the calls with \ref cyw43_arch_lwip_begin and \ref cyw43_arch_lwip_end. Again, you should be
109  * careful about what you do in lwIP callbacks, as you cannot call most FreeRTOS APIs from within an IRQ context. Unless you have good reason, you should probably
110  * use the full FreeRTOS integration (with `NO_SYS=0`) provided by \c pico_cyw43_arch_lwip_sys_freertos.
111  *
112  * * \b pico_cyw43_arch_lwip_sys_freertos - For using the full lwIP API including blocking sockets in OS (`NO_SYS=0`) mode, along with with multi-core/task/thread safety, and automatic servicing of the \c cyw43_driver and
113  * the lwIP stack.
114  *
115  *    This wrapper library:
116  *    - Sets \c CYW43_LWIP=1 to enable lwIP support in \c pico_cyw43_arch and \c cyw43_driver.
117  *    - Sets \c PICO_CYW43_ARCH_FREERTOS=1 to select the NO_SYS=0 lwip/FreeRTOS integration
118  *    - Sets \c LWIP_PROVIDE_ERRNO=1 to provide error numbers needed for compilation without an OS
119  *    - Adds the \c pico_lwip as a dependency to pull in lwIP.
120  *    - Adds the lwIP/FreeRTOS code from lwip-contrib (in the contrib directory of lwIP)
121  *
122  *    Calls into the \c cyw43_driver high level API (cyw43.h) may be made from any task or from lwIP callbacks, but not from IRQs. Calls into the lwIP RAW API (which is not thread safe)
123  *    must be bracketed with \ref cyw43_arch_lwip_begin and \ref cyw43_arch_lwip_end. It is fine to bracket calls made from within lwIP callbacks too; you just don't have to.
124  *
125  *    \note this wrapper library requires you to link FreeRTOS functionality with your application yourself.
126  *
127  * * \b pico_cyw43_arch_none - If you do not need the TCP/IP stack but wish to use the on-board LED.
128  *
129  *    This wrapper library:
130  *    - Sets \c CYW43_LWIP=0 to disable lwIP support in \c pico_cyw43_arch and \c cyw43_driver
131  */
132 
133 // PICO_CONFIG: PARAM_ASSERTIONS_ENABLED_PICO_CYW43_ARCH, Enable/disable assertions in the pico_cyw43_arch module, type=bool, default=0, group=pico_cyw43_arch
134 #ifndef PARAM_ASSERTIONS_ENABLED_PICO_CYW43_ARCH
135 #ifdef PARAM_ASSERTIONS_ENABLED_CYW43_ARCH // backwards compatibility with SDK < 2.0.0
136 #define PARAM_ASSERTIONS_ENABLED_PICO_CYW43_ARCH PARAM_ASSERTIONS_ENABLED_CYW43_ARCH
137 #else
138 #define PARAM_ASSERTIONS_ENABLED_PICO_CYW43_ARCH 0
139 #endif
140 #endif
141 
142 // PICO_CONFIG: PICO_CYW43_ARCH_DEBUG_ENABLED, Enable/disable some debugging output in the pico_cyw43_arch module, type=bool, default=1 in debug builds, group=pico_cyw43_arch
143 #ifndef PICO_CYW43_ARCH_DEBUG_ENABLED
144 #ifndef NDEBUG
145 #define PICO_CYW43_ARCH_DEBUG_ENABLED 1
146 #else
147 #define PICO_CYW43_ARCH_DEBUG_ENABLED 0
148 #endif
149 #endif
150 
151 // PICO_CONFIG: PICO_CYW43_ARCH_DEFAULT_COUNTRY_CODE, Default country code for the cyw43 wireless driver, default=CYW43_COUNTRY_WORLDWIDE, group=pico_cyw43_arch
152 #ifndef PICO_CYW43_ARCH_DEFAULT_COUNTRY_CODE
153 #define PICO_CYW43_ARCH_DEFAULT_COUNTRY_CODE CYW43_COUNTRY_WORLDWIDE
154 #endif
155 
156 /*!
157  * \brief Initialize the CYW43 architecture
158  * \ingroup pico_cyw43_arch
159  *
160  * This method initializes the `cyw43_driver` code and initializes the lwIP stack (if it
161  * was enabled at build time). This method must be called prior to using any other \c pico_cyw43_arch,
162  * \c cyw43_driver or lwIP functions.
163  *
164  * \note this method initializes wireless with a country code of \c PICO_CYW43_ARCH_DEFAULT_COUNTRY_CODE
165  * which defaults to \c CYW43_COUNTRY_WORLDWIDE. Worldwide settings may not give the best performance; consider
166  * setting PICO_CYW43_ARCH_DEFAULT_COUNTRY_CODE to a different value or calling \ref cyw43_arch_init_with_country
167  *
168  * By default this method initializes the cyw43_arch code's own async_context by calling
169  * \ref cyw43_arch_init_default_async_context, however the user can specify use of their own async_context
170  * by calling \ref cyw43_arch_set_async_context() before calling this method
171  *
172  * \return 0 if the initialization is successful, an error code otherwise \see pico_error_codes
173  */
174 int cyw43_arch_init(void);
175 
176 /*!
177  * \brief Initialize the CYW43 architecture for use in a specific country
178  * \ingroup pico_cyw43_arch
179  *
180  * This method initializes the `cyw43_driver` code and initializes the lwIP stack (if it
181  * was enabled at build time). This method must be called prior to using any other \c pico_cyw43_arch,
182  * \c cyw43_driver or lwIP functions.
183  *
184  * By default this method initializes the cyw43_arch code's own async_context by calling
185  * \ref cyw43_arch_init_default_async_context, however the user can specify use of their own async_context
186  * by calling \ref cyw43_arch_set_async_context() before calling this method
187  *
188  * \param country the country code to use (see \ref CYW43_COUNTRY_)
189  * \return 0 if the initialization is successful, an error code otherwise \see pico_error_codes
190  */
191 int cyw43_arch_init_with_country(uint32_t country);
192 
193 /*!
194  * \brief De-initialize the CYW43 architecture
195  * \ingroup pico_cyw43_arch
196  *
197  * This method de-initializes the `cyw43_driver` code and de-initializes the lwIP stack (if it
198  * was enabled at build time). Note this method should always be called from the same core (or RTOS
199  * task, depending on the environment) as \ref cyw43_arch_init.
200  *
201  * Additionally if the cyw43_arch is using its own async_context instance, then that instance is de-initialized.
202  */
203 void cyw43_arch_deinit(void);
204 
205 /*!
206  * \brief Return the current async_context currently in use by the cyw43_arch code
207  * \ingroup pico_cyw43_arch
208  *
209  * \return the async_context.
210  */
211 async_context_t *cyw43_arch_async_context(void);
212 
213 /*!
214  * \brief Set the async_context to be used by the cyw43_arch_init
215  * \ingroup pico_cyw43_arch
216  *
217  * \note This method must be called before calling cyw43_arch_init or cyw43_arch_init_with_country
218  * if you wish to use a custom async_context instance.
219  *
220  * \param context the async_context to be used
221  */
222 void cyw43_arch_set_async_context(async_context_t *context);
223 
224 /*!
225  * \brief Initialize the default async_context for the current cyw43_arch type
226  * \ingroup pico_cyw43_arch
227  *
228  * This method initializes and returns a pointer to the static async_context associated
229  * with cyw43_arch. This method is called by \ref cyw43_arch_init automatically
230  * if a different async_context has not been set by \ref cyw43_arch_set_async_context
231  *
232  * \return the context or NULL if initialization failed.
233  */
234 async_context_t *cyw43_arch_init_default_async_context(void);
235 
236 /*!
237  * \brief Perform any processing required by the \c cyw43_driver or the TCP/IP stack
238  * \ingroup pico_cyw43_arch
239  *
240  * This method must be called periodically from the main loop when using a
241  * \em polling style \c pico_cyw43_arch (e.g. \c pico_cyw43_arch_lwip_poll ). It
242  * may be called in other styles, but it is unnecessary to do so.
243  */
244 void cyw43_arch_poll(void);
245 
246 /*!
247  * \brief Sleep until there is cyw43_driver work to be done
248  * \ingroup pico_cyw43_arch
249  *
250  * This method may be called by code that is waiting for an event to
251  * come from the cyw43_driver, and has no work to do, but would like
252  * to sleep without blocking any background work associated with the cyw43_driver.
253  *
254  * \param until the time to wait until if there is no work to do.
255  */
256 void cyw43_arch_wait_for_work_until(absolute_time_t until);
257 
258 /*!
259  * \fn cyw43_arch_lwip_begin
260  * \brief Acquire any locks required to call into lwIP
261  * \ingroup pico_cyw43_arch
262  *
263  * The lwIP API is not thread safe. You should surround calls into the lwIP API
264  * with calls to this method and \ref cyw43_arch_lwip_end. Note these calls are not
265  * necessary (but harmless) when you are calling back into the lwIP API from an lwIP callback.
266  * If you are using single-core polling only (pico_cyw43_arch_poll) then these calls are no-ops
267  * anyway it is good practice to call them anyway where they are necessary.
268  *
269  * \note as of SDK release 1.5.0, this is now equivalent to calling \ref async_context_acquire_lock_blocking
270  * on the async_context associated with cyw43_arch and lwIP.
271  *
272  * \sa cyw43_arch_lwip_end
273  * \sa cyw43_arch_lwip_protect
274  * \sa async_context_acquire_lock_blocking
275  * \sa cyw43_arch_async_context
276  */
cyw43_arch_lwip_begin(void)277 static inline void cyw43_arch_lwip_begin(void) {
278     cyw43_thread_enter();
279 }
280 
281 /*!
282  * \fn void cyw43_arch_lwip_end(void)
283  * \brief Release any locks required for calling into lwIP
284  * \ingroup pico_cyw43_arch
285  *
286  * The lwIP API is not thread safe. You should surround calls into the lwIP API
287  * with calls to \ref cyw43_arch_lwip_begin and this method. Note these calls are not
288  * necessary (but harmless) when you are calling back into the lwIP API from an lwIP callback.
289  * If you are using single-core polling only (pico_cyw43_arch_poll) then these calls are no-ops
290  * anyway it is good practice to call them anyway where they are necessary.
291  *
292  * \note as of SDK release 1.5.0, this is now equivalent to calling \ref async_context_release_lock
293  * on the async_context associated with cyw43_arch and lwIP.
294  *
295  * \sa cyw43_arch_lwip_begin
296  * \sa cyw43_arch_lwip_protect
297  * \sa async_context_release_lock
298  * \sa cyw43_arch_async_context
299  */
cyw43_arch_lwip_end(void)300 static inline void cyw43_arch_lwip_end(void) {
301     cyw43_thread_exit();
302 }
303 
304 /*!
305  * \fn int cyw43_arch_lwip_protect(int (*func)(void *param), void *param)
306  * \brief sad Release any locks required for calling into lwIP
307  * \ingroup pico_cyw43_arch
308  *
309  * The lwIP API is not thread safe. You can use this method to wrap a function
310  * with any locking required to call into the lwIP API. If you are using
311  * single-core polling only (pico_cyw43_arch_poll) then there are no
312  * locks to required, but it is still good practice to use this function.
313  *
314  * \param func the function ta call with any required locks held
315  * \param param parameter to pass to \c func
316  * \return the return value from \c func
317  * \sa cyw43_arch_lwip_begin
318  * \sa cyw43_arch_lwip_end
319  */
cyw43_arch_lwip_protect(int (* func)(void * param),void * param)320 static inline int cyw43_arch_lwip_protect(int (*func)(void *param), void *param) {
321     cyw43_arch_lwip_begin();
322     int rc = func(param);
323     cyw43_arch_lwip_end();
324     return rc;
325 }
326 
327 /*!
328  * \fn void cyw43_arch_lwip_check(void)
329  * \brief Checks the caller has any locks required for calling into lwIP
330  * \ingroup pico_cyw43_arch
331  *
332  * The lwIP API is not thread safe. You should surround calls into the lwIP API
333  * with calls to \ref cyw43_arch_lwip_begin and this method. Note these calls are not
334  * necessary (but harmless) when you are calling back into the lwIP API from an lwIP callback.
335  *
336  * This method will assert in debug mode, if the above conditions are not met (i.e. it is not safe to
337  * call into the lwIP API)
338  *
339  * \note as of SDK release 1.5.0, this is now equivalent to calling \ref async_context_lock_check
340  * on the async_context associated with cyw43_arch and lwIP.
341  *
342  * \sa cyw43_arch_lwip_begin
343  * \sa cyw43_arch_lwip_protect
344  * \sa async_context_lock_check
345  * \sa cyw43_arch_async_context
346  */
347 
348 /*!
349  * \brief Return the country code used to initialize cyw43_arch
350  * \ingroup pico_cyw43_arch
351  *
352  * \return the country code (see \ref CYW43_COUNTRY_)
353  */
354 uint32_t cyw43_arch_get_country_code(void);
355 
356 /*!
357  * \brief Enables Wi-Fi STA (Station) mode.
358  * \ingroup pico_cyw43_arch
359  *
360  * This enables the Wi-Fi in \em Station mode such that connections can be made to other Wi-Fi Access Points
361  */
362 void cyw43_arch_enable_sta_mode(void);
363 
364 /*!
365  * \brief Disables Wi-Fi STA (Station) mode.
366  * \ingroup pico_cyw43_arch
367  *
368  * This disables the Wi-Fi in \em Station mode, disconnecting any active connection.
369  * You should subsequently check the status by calling \ref cyw43_wifi_link_status.
370  */
371 void cyw43_arch_disable_sta_mode(void);
372 
373 /*!
374  * \brief Enables Wi-Fi AP (Access point) mode.
375  * \ingroup pico_cyw43_arch
376  *
377  * This enables the Wi-Fi in \em Access \em Point mode such that connections can be made to the device by other Wi-Fi clients
378  * \param ssid the name for the access point
379  * \param password the password to use or NULL for no password.
380  * \param auth the authorization type to use when the password is enabled. Values are \ref CYW43_AUTH_WPA_TKIP_PSK,
381  *             \ref CYW43_AUTH_WPA2_AES_PSK, or \ref CYW43_AUTH_WPA2_MIXED_PSK (see \ref CYW43_AUTH_)
382  */
383 void cyw43_arch_enable_ap_mode(const char *ssid, const char *password, uint32_t auth);
384 
385 /*!
386  * \brief Disables Wi-Fi AP (Access point) mode.
387  * \ingroup pico_cyw43_arch
388  *
389  * This Disbles the Wi-Fi in \em Access \em Point mode.
390  */
391 void cyw43_arch_disable_ap_mode(void);
392 
393 /*!
394  * \brief Attempt to connect to a wireless access point, blocking until the network is joined or a failure is detected.
395  * \ingroup pico_cyw43_arch
396  *
397  * \param ssid the network name to connect to
398  * \param pw the network password or NULL if there is no password required
399  * \param auth the authorization type to use when the password is enabled. Values are \ref CYW43_AUTH_WPA_TKIP_PSK,
400  *             \ref CYW43_AUTH_WPA2_AES_PSK, or \ref CYW43_AUTH_WPA2_MIXED_PSK (see \ref CYW43_AUTH_)
401  *
402  * \return 0 if the initialization is successful, an error code otherwise \see pico_error_codes
403  */
404 int cyw43_arch_wifi_connect_blocking(const char *ssid, const char *pw, uint32_t auth);
405 
406 /*!
407  * \brief Attempt to connect to a wireless access point specified by SSID and BSSID, blocking until the network is joined or a failure is detected.
408  * \ingroup pico_cyw43_arch
409  *
410  * \param ssid the network name to connect to
411  * \param bssid the network BSSID to connect to or NULL if ignored
412  * \param pw the network password or NULL if there is no password required
413  * \param auth the authorization type to use when the password is enabled. Values are \ref CYW43_AUTH_WPA_TKIP_PSK,
414  *             \ref CYW43_AUTH_WPA2_AES_PSK, or \ref CYW43_AUTH_WPA2_MIXED_PSK (see \ref CYW43_AUTH_)
415  *
416  * \return 0 if the initialization is successful, an error code otherwise \see pico_error_codes
417  */
418 int cyw43_arch_wifi_connect_bssid_blocking(const char *ssid, const uint8_t *bssid, const char *pw, uint32_t auth);
419 
420 /*!
421  * \brief Attempt to connect to a wireless access point, blocking until the network is joined, a failure is detected or a timeout occurs
422  * \ingroup pico_cyw43_arch
423  *
424  * \param ssid the network name to connect to
425  * \param pw the network password or NULL if there is no password required
426  * \param auth the authorization type to use when the password is enabled. Values are \ref CYW43_AUTH_WPA_TKIP_PSK,
427  *             \ref CYW43_AUTH_WPA2_AES_PSK, or \ref CYW43_AUTH_WPA2_MIXED_PSK (see \ref CYW43_AUTH_)
428  * \param timeout how long to wait in milliseconds for a connection to succeed before giving up
429  *
430  * \return 0 if the initialization is successful, an error code otherwise \see pico_error_codes
431  */
432 int cyw43_arch_wifi_connect_timeout_ms(const char *ssid, const char *pw, uint32_t auth, uint32_t timeout);
433 
434 /*!
435  * \brief Attempt to connect to a wireless access point specified by SSID and BSSID, blocking until the network is joined, a failure is detected or a timeout occurs
436  * \ingroup pico_cyw43_arch
437  *
438  * \param ssid the network name to connect to
439  * \param bssid the network BSSID to connect to or NULL if ignored
440  * \param pw the network password or NULL if there is no password required
441  * \param auth the authorization type to use when the password is enabled. Values are \ref CYW43_AUTH_WPA_TKIP_PSK,
442  *             \ref CYW43_AUTH_WPA2_AES_PSK, or \ref CYW43_AUTH_WPA2_MIXED_PSK (see \ref CYW43_AUTH_)
443  * \param timeout how long to wait in milliseconds for a connection to succeed before giving up
444  *
445  * \return 0 if the initialization is successful, an error code otherwise \see pico_error_codes
446  */
447 int cyw43_arch_wifi_connect_bssid_timeout_ms(const char *ssid, const uint8_t *bssid, const char *pw, uint32_t auth, uint32_t timeout);
448 
449 /*!
450  * \brief Start attempting to connect to a wireless access point
451  * \ingroup pico_cyw43_arch
452  *
453  * This method tells the CYW43 driver to start connecting to an access point. You should subsequently check the
454  * status by calling \ref cyw43_wifi_link_status.
455  *
456  * \param ssid the network name to connect to
457  * \param pw the network password or NULL if there is no password required
458  * \param auth the authorization type to use when the password is enabled. Values are \ref CYW43_AUTH_WPA_TKIP_PSK,
459  *             \ref CYW43_AUTH_WPA2_AES_PSK, or \ref CYW43_AUTH_WPA2_MIXED_PSK (see \ref CYW43_AUTH_)
460  *
461  * \return 0 if the scan was started successfully, an error code otherwise \see pico_error_codes
462  */
463 int cyw43_arch_wifi_connect_async(const char *ssid, const char *pw, uint32_t auth);
464 
465 /*!
466  * \brief Start attempting to connect to a wireless access point specified by SSID and BSSID
467  * \ingroup pico_cyw43_arch
468  *
469  * This method tells the CYW43 driver to start connecting to an access point. You should subsequently check the
470  * status by calling \ref cyw43_wifi_link_status.
471  *
472  * \param ssid the network name to connect to
473  * \param bssid the network BSSID to connect to or NULL if ignored
474  * \param pw the network password or NULL if there is no password required
475  * \param auth the authorization type to use when the password is enabled. Values are \ref CYW43_AUTH_WPA_TKIP_PSK,
476  *             \ref CYW43_AUTH_WPA2_AES_PSK, or \ref CYW43_AUTH_WPA2_MIXED_PSK (see \ref CYW43_AUTH_)
477  *
478  * \return 0 if the scan was started successfully, an error code otherwise \see pico_error_codes
479  */
480 int cyw43_arch_wifi_connect_bssid_async(const char *ssid, const uint8_t *bssid, const char *pw, uint32_t auth);
481 
482 /*!
483  * \brief Set a GPIO pin on the wireless chip to a given value
484  * \ingroup pico_cyw43_arch
485  * \note this method does not check for errors setting the GPIO. You can use the lower level \ref cyw43_gpio_set instead if you wish
486  * to check for errors.
487  *
488  * \param wl_gpio the GPIO number on the wireless chip
489  * \param value true to set the GPIO, false to clear it.
490  */
491 void cyw43_arch_gpio_put(uint wl_gpio, bool value);
492 
493 /*!
494  * \brief Read the value of a GPIO pin on the wireless chip
495  * \ingroup pico_cyw43_arch
496  * \note this method does not check for errors setting the GPIO. You can use the lower level \ref cyw43_gpio_get instead if you wish
497  * to check for errors.
498  *
499  * \param wl_gpio the GPIO number on the wireless chip
500  * \return true if the GPIO is high, false otherwise
501  */
502 bool cyw43_arch_gpio_get(uint wl_gpio);
503 
504 #ifdef __cplusplus
505 }
506 #endif
507 
508 #endif
509