diff --git a/src/rp2_common/wifi_settings_connect/README.md b/src/rp2_common/wifi_settings_connect/README.md index ba800d0..d694b2d 100644 --- a/src/rp2_common/wifi_settings_connect/README.md +++ b/src/rp2_common/wifi_settings_connect/README.md @@ -3,20 +3,39 @@ This is a library to manage WiFi connections. It provides Flash storage for WiFi passwords and hotspot names, and a background async\_context service to automatically connect to them. You can store details for -up to 16 hotspots and update them using `picotool` or a setup +up to 100 hotspots and update them using `picotool` or a setup application. This avoids any need to specify build-time flags such as `WIFI_SSID` and `WIFI_PASSWORD`. -The Flash storage location for hotspot details is specified in -`include/wifi_settings/wifi_settings_configuration.h`. It is at -`0x101ff000` (for Pico W) and `0x103fe000` (for Pico 2 W). To add your -WiFi details at this location, please [see these -instructions](https://github.com/jwhitham/pico-wifi-settings/blob/master/doc/SETTINGS_FILE.md). -You can edit the settings as a text file and transfer it with `picotool`, -or install a [setup application](https://github.com/jwhitham/pico-wifi-settings/blob/master/doc/SETUP_APP.md) -to add or update WiFi details. +WiFi hotspot details are stored in a Flash sector that isn't normally used by programs, +normally located near the end of Flash memory. This +[wifi-settings file](doc/SETTINGS_FILE.md) is a simple text file which +can be updated by USB or by installing a setup app from the +[pico-wifi-settings home page](https://github.com/jwhitham/pico-wifi-settings) +on Github. -This wifi\_settings\_connect library is a subset of a larger -library, [wifi\_settings](https://github.com/jwhitham/pico-wifi-settings/), -which adds remote update functions for both the WiFi settings -and (optionally) your Pico application too. +## Requirements + + - Raspberry Pi Pico W or Pico 2 W hardware + - a "bare metal" C/C++ application for Pico W (not FreeRTOS) + using the `cyw43` driver and `lwip` network stack + which are provided with the [Pico SDK](https://github.com/raspberrypi/pico-sdk/). + - between 2kb and 13kb of code space depending on options used + - WiFi network(s) with a DHCP server and WPA authentication + +## How to use it + +First, you need to configure the WiFi settings file +in Flash. See the [wifi-settings file documentation](doc/SETTINGS_FILE.md). + +Next, you need to modify your application to use wifi\_settings\_connect. +There is an [integration guide which explains what you need to do +to add wifi\_settings\_connect to your application](doc/INTEGRATION.md). + +## Enabling remote updates + +wifi\_settings\_connect is a subset of a larger library (wifi\_settings) which +also has support for remote updates of WiFi settings and over-the-air (OTA) +firmware updates. Visit the +[pico-wifi-settings home page](https://github.com/jwhitham/pico-wifi-settings) +for more information. diff --git a/src/rp2_common/wifi_settings_connect/doc/INTEGRATION.md b/src/rp2_common/wifi_settings_connect/doc/INTEGRATION.md new file mode 100644 index 0000000..49bbe5c --- /dev/null +++ b/src/rp2_common/wifi_settings_connect/doc/INTEGRATION.md @@ -0,0 +1,120 @@ +# Integrating wifi\_settings\_connect into your own Pico application + +You can integrate wifi\_settings\_connect into your own Pico application +with just a few lines of code: +``` + #include "wifi_settings.h" // << add this + int main() { + stdio_init_all(); + if (wifi_settings_init() != 0) { // << and add this + panic(...); + } + wifi_settings_connect(); // << and add this + // and that's it... + } +``` +The following steps go through the process in more detail for +a [CMake](https://cmake.org) project stored in Git, +similar to all of the official Pico projects. + +You may find it useful to look at [the example app for wifi\_settings\_connect in +the pico-playground repository](https://github.com/raspberrypi/pico-playground/tree/master/wifi_settings_connect/example). + +## Modify CMakeLists.txt to use the library + +The `target_link_libraries` rule for your project should be extended to +add `wifi_settings_connect`. +``` + target_link_libraries(your_app + wifi_settings_connect + pico_stdlib + ) +``` +If your project does not include the `pico-extras` repository, then this +must also be added. +``` + include(pico_extras_import.cmake) +``` +You can copy the `pico_extras_import.cmake` file from [the root of +the pico-playground repository](https://github.com/raspberrypi/pico-playground). + +### Additional configuration for LwIP and mbedtls + +If your project has not previously used WiFi you will also need +to add one of the WiFi driver targets to `target_link_libraries`, e.g. +`pico_cyw43_arch_lwip_background` or `pico_cyw43_arch_lwip_poll`. + +You will also need `lwipopts.h` in the project directory (this configures +LwIP). You can copy an example from +[here](https://github.com/raspberrypi/pico-playground/tree/master/wifi_settings_connect/example). + +## Include the header file + +Your main C/C++ source file (containing `main()`) should be modified to include +`wifi_settings/wifi_settings_connect.h`: +``` + #include "wifi_settings/wifi_settings_connect.h" +``` + +## Modify your main function + +Your `main()` function should be modified to call `wifi_settings_init()` once on startup. + + - This must *replace* any call to `cyw43` initialisation functions, because + these are called from `wifi_settings_init()` (with the correct country code). + - The call should be after `stdio_init_all()`. + - If the call returns a non-zero value, an error has occurred. You do not have + to handle this error; it is still safe to call other `wifi_settings` functions, + but they will not work and will return error codes where appropriate. + +Your application should also call `wifi_settings_connect()` when it wishes to connect +to WiFi. This can be called immediately after `wifi_settings_init()` or at any later +time. `wifi_settings_connect()` does not block, as the connection takes +place in the background. + +All other modifications are optional. You can now rebuild your application +and it will include the wifi\_settings\_connect features. + +## CMake command line + +When running `cmake`, you need to provide the location of the `pico-extras` +repository as well as the `pico-sdk` repository. This is typically done +with `-DPICO_EXTRAS_PATH`, e.g.: +``` + cmake -DPICO_BOARD=pico_w \ + -DPICO_SDK_PATH=/home/user/pico-sdk \ + -DPICO_EXTRAS_PATH=/home/user/pico-extras \ + .. +``` + +# Optional modifications + +Your application can call `wifi_settings_is_connected()` at any time +to determine if the WiFi connection is available or not. + +Your application can call various status functions at any time +to get a text report on the connection status. This can be useful for debugging. +Each function should be passed a `char[]` buffer for the output, along with the +size of the buffer. + + - `wifi_settings_get_connect_status_text()` produces a line of + text showing the connection status, e.g. `WiFi is connected to ssid1=MyHomeWiFi`. + - `wifi_settings_get_hw_status_text()` produces a line of + text describing the status of the `cyw43` hardware driver; this will be empty + if the hardware is not initialised. + - `wifi_settings_get_ip_status_text()` produces a line of + text describing the status of the `lwip` network stack e.g. IP address; this will be empty + if unconnected. + +There is also a function to report the current connection state +`wifi_settings_get_ssid_status()` returns +a pointer to a static string, indicating the status of a connection attempt to +an SSID, e.g. `SUCCESS`, `NOT FOUND`. + +Your application can call `wifi_settings_disconnect()` to force disconnect, +or `wifi_settings_deinit()` to deinitialise the driver, but this is never necessary +and these steps can be left out. They exist to allow the application to shut down WiFi, +e.g. to save power, or in order to control the WiFi hardware directly for some other +purpose. For example, the +[setup app](https://github.com/jwhitham/pico-wifi-settings/tree/master/doc/SETUP_APP.md) +uses this feature to perform its own WiFi scan. diff --git a/src/rp2_common/wifi_settings_connect/doc/SETTINGS_FILE.md b/src/rp2_common/wifi_settings_connect/doc/SETTINGS_FILE.md new file mode 100644 index 0000000..11eb832 --- /dev/null +++ b/src/rp2_common/wifi_settings_connect/doc/SETTINGS_FILE.md @@ -0,0 +1,160 @@ +# Creating and updating a WiFi settings file + +wifi\_settings\_connect stores WiFi hotspot names and passwords +in a Flash sector that isn't normally used by programs. This +is called the "WiFi settings file". It is similar to a file on a disk, +except that it is always at the same location, and the size is +limited to 4096 bytes. + +The file can be updated over USB by using [picotool](https://github.com/raspberrypi/picotool). +It is a text file which can be edited with any text editor. +Here is an example of typical contents: +``` + ssid1=MyHomeWiFi + pass1=mypassword1234 + ssid2=MyPhoneHotspot + pass2=secretpassword + country=GB +``` +wifi\_settings\_connect will automatically scan for hotspots and connect to +hotspots matching the SSID names and passwords in the file. + +- On the [pico-wifi-settings home page](https://github.com/jwhitham/pico-wifi-settings) + you can also find a setup app which runs on your Pico and automates much of the + setup process. The pico-wifi-settings library is a superset of + wifi\_settings\_connect. It includes a remote update feature that allows + a new wifi-settings file to be installed via WiFi. + +# Creating the file on a computer + +Use any text editor to create a text file similar to the example above. + +Each line in the file should contain a key and a value, separated by `=`, +with no spaces around `=`, or at the beginning or end of each line. + +The file must have at least `ssid1` or `bssid1`, otherwise there will +be no connection attempts, and wifi\_settings\_connect will stay in the +STORAGE\_EMPTY\_ERROR state. + +You can also use the following: + + - `ssid` - SSID name for hotspot N (a number from 1 to 100) + - `pass` - Password for hotspot N + - `country` - Your two-letter country code from [ISO-3166-1](https://en.wikipedia.org/wiki/List_of_ISO_3166_country_codes) + - `bssid` - The BSSID ID for hotspot N + - `name` - The hostname of the Pico (sent to DHCP servers) + +# Copying the WiFi settings file by USB + +You can use [picotool](https://github.com/raspberrypi/picotool) to copy the +file from your PC to your Pico via USB. + +picotool is part of the Pico SDK. +You need to build picotool with USB support for your OS (or download a pre-built copy). + +To use picotool, +boot the Pico in bootloader mode by holding down the BOOTSEL button while plugging it +into USB. In bootloader mode, you can upload files with picotool. +The default address is 16kb before the final address in Flash: + + - On Pico W, use `0x101fc000` as the address. + - On Pico 2 W, use `0x103fc000` as the address. + +You must also rename your WiFi settings file so that it ends with `.bin` as +picotool is not able to upload files unless they are `.bin`, `.elf` or `.uf2`. + +Here is a sample upload command for Pico W (RP2040): +``` + picotool load -o 0x101fc000 mywifisettings.bin +``` +and the equivalent for Pico 2 W (RP2350): +``` + picotool load -o 0x103fc000 mywifisettings.bin +``` + +## Location of the wifi-settings file + +The default location of the file (16kb before the final address in Flash) +has been chosen because the final three 4kb Flash sectors are already assigned +a function by the Pico SDK. The Bluetooth library uses two 4kb sectors for storage of +devices that have been paired by Bluetooth. The final 4kb sector is used for a workaround +for the RP2350-E10 bug - this sector may be erased when copying a UF2 file to a Pico 2 +via drag-and-drop. Therefore, these three sectors are avoided. + +If you wish to store the wifi-settings file at a specific address you can +do so by setting `-DWIFI_SETTINGS_FILE_ADDRESS=0x....` when running `cmake`. +The value `0x...` should be an address relative to the start of Flash, so Flash address +`0x1fc000` corresponds to absolute address `0x101fc000`. + +## Backing up a WiFi settings file + +picotool can be used to download WiFi settings files from a Pico W: +``` + picotool save -r 0x101fc000 0x101fd000 backup.bin +``` +and Pico 2 W (RP2350): +``` + picotool save -r 0x103fc000 0x103fd000 backup.bin +``` +Characters after the end of the file will be copied (usually either 0x00 or 0xff). +These can be safely deleted using your text editor. The backup is restored by +using `picotool load` as described in "Copying the WiFi settings file by USB". + +These examples use the default location for the wifi-settings file. If you +are using a custom location, e.g. building with +`-DWIFI_SETTINGS_FILE_ADDRESS=0x...`, then +you would need to substitute the actual address. + +# File format details + +The file format is very simple so that it can be read by a simple algorithm +that doesn't require much code space. The parser ignores any line that it +doesn't understand, and skips any keys that are not known. Here are the rules: + + - The key and the value should be separated only by an `=` character, e.g. `ssid1=HomeWiFi`. + - Lines that don't match the form `key=value` are completely ignored; + you can add text, comments etc. in order to help you manage your configuration. + - On a line that does match `key=value`, whitespace is NOT ignored. + Be careful to avoid adding extra spaces around `=`. + A space before `=` will be part of the key, and a space after `=` will be part of the value. + - Unix and Windows line endings are supported. + - The maximum size of the file is 4096 bytes. + - Values can contain any printable UTF-8 character. + - Keys can also contain any printable UTF-8 character except for '='. + - There is no maximum size for a key or a value (except for the file size). + - Values can be zero length. + - Keys must be at least 1 byte. + - If a key appears more than once in the file, the first value is used. + - The end of the file is the first byte with value 0x00, 0xff or 0x1a, or the 4097th byte, + whichever comes first. + +# WiFi settings + + - `ssid` is only checked if `ssid` is present. + - The number reflects the priority. Lower numbers take priority over higher + numbers when more than one SSID is found. + - If `pass` is not specified then wifi\_settings\_connect will assume + an open WiFi hotspot. + - If both `bssid` and `ssid` are specified, then the BSSID is used + and the SSID is ignored. + - If you don't specify a country, the default worldwide settings are used, which might work + slightly less well (e.g. fewer WiFi channels are supported). + - `bssid` should be specified as + a `:`-separated lower-case MAC address, e.g. `01:23:45:67:89:ab`. BSSIDs are + not normally required and should only be used if you have a special requirement + e.g. a "hidden" hotspot without an SSID name. + +# Custom keys and values + +The WiFi settings file can have keys which are not used by the wifi\_settings\_connect library. +Your application can obtain their values using the `wifi_settings_get_value_for_key()` function. +This can be a useful way to store additional configuration data for your Pico application. +For example you might use it to store encryption keys, server addresses, user names +or any other setting that you may wish to update without rebuilding your application. + +`wifi_settings_get_value_for_key` uses a linear search, starting at the beginning +of the file. This search does not backtrack and is fast because of the simplistic +nature of the file format. However, in algorithmic terms, this is not the best way +to implement or search a key/value store, and if you need frequent access to keys/values, +you may wish to implement something better (e.g. use a hash table to implement a dictionary) +or just load the values when your application starts up and then store them elsewhere.