|
rcbench
Servo and ESC test bench: panel, IOmcu and shared C
|
Wi-Fi access: when the panel's radio runs, under which name, and who the page answers. More...
#include <stdbool.h>#include <stddef.h>#include <stdint.h>Go to the source code of this file.
Data Structures | |
| struct | wa_conf_t |
| What is kept: the home network and the code switch. More... | |
| struct | wa_store_t |
| The store a wa_conf_t is kept in. More... | |
| struct | wa_pending_t |
| The writes owed to the store. More... | |
| struct | wa_net_t |
| One network of the scan list. More... | |
| struct | wa_scan_t |
| The scan list, strongest first. More... | |
| struct | wa_t |
| A session: what the radio should do, and where it is. More... | |
Macros | |
| #define | WA_SCAN_MAX 16u |
| Networks the scan list holds. | |
Limits and times | |
| #define | WA_SECRET_LEN 8u |
| #define | WA_SECRET_CHARS "abcdefghjkmnpqrstuvwxyz23456789" |
| #define | WA_NAME_MAX 13u |
| #define | WA_SSID_MAX 32u |
| A home network's name, in bytes. | |
| #define | WA_PASS_MIN 8u |
| A WPA2/WPA3 passphrase's fewest characters. | |
| #define | WA_PASS_MAX 63u |
| A WPA2/WPA3 passphrase's most characters. | |
| #define | WA_IDLE_MS (10u * 60u * 1000u) |
| #define | WA_JOIN_MS 20000u |
| #define | WA_AUTH_TRIES 3u |
| Auth-class drops in a row that end a join as WA_JOIN_PASSWORD. | |
| #define | WA_ADDRESS_MS 15000u |
| #define | WA_START_MS 10000u |
| #define | WA_SCAN_TRIES 3u |
| Scans a scan session starts at most: the first, and one more after each scan the radio reports failed, all within WA_START_MS. | |
| #define | WA_GUESS_MAX 16u |
The writes owed to the store | |
A change lands in memory at once and in the store on a frame that may write flash (wa_pending_due()). A flag is cleared only by a write that succeeded and that no later change overtook. A failed write is shown (failed) and tried again WA_PENDING_RETRIES times, WA_PENDING_RETRY_MS apart; after that it waits for the next change, which tries at once and starts the count again. | |
| #define | WA_PENDING_RETRIES 3u |
| Automatic tries after a failed write. | |
| #define | WA_PENDING_RETRY_MS 10000u |
| The time between them, ms. | |
The ways the screen offers | |
| #define | WA_CAN_AP 0x1u |
| The access point, always. | |
| #define | WA_CAN_JOIN 0x2u |
| The home network, when one is kept. | |
Typedefs | |
| typedef uint32_t(*) | wa_rand_fn(void *ctx) |
| A source of random 32-bit words. | |
Functions | |
| void | wa_secret_make (char out[WA_SECRET_LEN+1u], wa_rand_fn rand, void *ctx) |
| WA_SECRET_LEN characters of WA_SECRET_CHARS and a terminator, each drawn evenly from the alphabet (words that would favour some characters are drawn again). | |
| void | wa_name (const uint8_t mac[6], char out[WA_NAME_MAX]) |
"rcbench-" and the last two bytes of mac in capital hex. | |
| void | wa_conf_defaults (wa_conf_t *c) |
| No home network, the code on: a fresh store, and what FORGET leaves. | |
| wa_conf_err_t | wa_conf_set_net (wa_conf_t *c, const char *ssid, size_t ssid_len, const char *pass, size_t pass_len) |
| Take a home network. | |
| void | wa_conf_load (const wa_store_t *s, wa_conf_t *out) |
| What the store holds, or the defaults when it holds nothing. | |
| bool | wa_conf_save (const wa_store_t *s, const wa_conf_t *c) |
Write c into the store. | |
| bool | wa_conf_forget (const wa_store_t *s, wa_conf_t *c) |
FORGET: erase the store and leave c at the defaults. | |
| void | wa_pending_init (wa_pending_t *p) |
| Nothing owed. | |
| void | wa_pending_change (wa_pending_t *p) |
| A change of the settings in memory: owe a save. | |
| void | wa_pending_forget (wa_pending_t *p) |
| FORGET: owe an erase; a save owed before it is void. | |
| bool | wa_pending_due (const wa_pending_t *p, bool may_write, uint32_t now_ms) |
| Whether a write is owed and due now. | |
| void | wa_pending_write (const wa_store_t *st, const wa_pending_t *snap, const wa_conf_t *c, bool *erase_ok, bool *save_ok) |
Write what snap owes – the erase, then c – into st. | |
| void | wa_pending_done (wa_pending_t *p, const wa_pending_t *snap, bool erase_ok, bool save_ok, uint32_t now_ms) |
Record the results of a write that started from snap. | |
| unsigned | wa_modes (const wa_conf_t *c) |
| Which ways the screen offers. | |
| void | wa_scan_clear (wa_scan_t *s) |
| Empty the scan list. | |
| void | wa_scan_add (wa_scan_t *s, const uint8_t *ssid, size_t len, int8_t rssi, bool usable) |
| One network a scan saw. | |
| const char * | wa_scan_pick (const wa_scan_t *s, unsigned i) |
The name at row i. | |
| void | wa_init (wa_t *w) |
| Off, nothing kept of any session. | |
| wa_off_t | wa_gate (bool armed, bool supply, bool run) |
| Why the radio may not run now. | |
| wa_off_t | wa_start (wa_t *w, wa_mode_t mode, wa_off_t gate, uint32_t now_ms, wa_rand_fn rand, void *ctx) |
Start in mode when gate is WA_OFF_NONE, with a fresh password and code. | |
| void | wa_close (wa_t *w, wa_off_t why) |
Switch off for why. | |
| bool | wa_radio (const wa_t *w) |
| Whether the platform's radio should be running. | |
| bool | wa_lingers (const wa_t *w) |
| Whether the radio may stay up past the session's end, for a request of the platform's own that is under way (the clock's NTP request, wall_ntp_holds()). | |
| void | wa_unlinger (wa_t *w) |
| The platform needs the radio off now: a linger ends; a session that runs goes on. | |
| bool | wa_serving (const wa_t *w) |
| Whether the page is being served. | |
| void | wa_on_ap_up (wa_t *w, uint32_t now_ms) |
| The access point came up. | |
| void | wa_on_scan_done (wa_t *w) |
| A scan session's list was read: the session ends, off WA_OFF_NONE. wa_on_scan_end() does it with the scan's result. | |
| void | wa_on_associated (wa_t *w, uint32_t now_ms) |
| The station reached the home network. | |
| void | wa_on_address (wa_t *w, uint32_t ip, uint32_t now_ms) |
| The station has an address. | |
| void | wa_on_join_failed (wa_t *w, wa_join_err_t why) |
| A join failed or a joined network went away. | |
| bool | wa_on_drop (wa_t *w, bool auth) |
| The radio dropped the station. | |
| void | wa_on_failed (wa_t *w) |
| The radio could not be started: off WA_OFF_FAILED. A refused scan is wa_scan_refused(). | |
| uint32_t | wa_scan_begin (wa_t *w) |
| The radio's station started in a scan session: the token of the scan the platform starts now, or 0 for none. | |
| uint32_t | wa_scan_pending (const wa_t *w) |
| The scan of this session under way, its done report still owed. | |
| bool | wa_scan_is (const wa_t *w, uint32_t tok) |
Whether the scan of tok is the one under way. | |
| bool | wa_scan_refused (wa_t *w, uint32_t tok) |
The radio refused to start the scan of tok: off WA_OFF_FAILED when it is the scan under way. | |
| bool | wa_scan_read_ok (uint32_t status, unsigned reported, bool read_ok, unsigned read, unsigned room) |
| Whether a scan reported done counts as done. | |
| wa_scan_step_t | wa_on_scan_end (wa_t *w, uint32_t tok, bool ok, uint32_t *next) |
The scan of tok reported done; ok as wa_scan_read_ok() says. | |
| bool | wa_tick (wa_t *w, uint32_t now_ms, wa_off_t gate, bool stop) |
| Once a frame: the gate, STOP and the time-outs. Off, a gate or STOP ends a linger (wa_lingers()). | |
| void | wa_request_begin (wa_t *w, uint32_t now_ms) |
| A request begins; one under way holds the idle time-out off. | |
| void | wa_request_end (wa_t *w, uint32_t now_ms) |
| A request ends; the idle time counts from now. | |
| uint32_t | wa_idle_left (const wa_t *w, uint32_t now_ms) |
| The time left before the idle time-out. | |
| wa_code_t | wa_code_check (wa_t *w, const char *given, bool code_on) |
Check given against this session's code. | |
Wi-Fi access: when the panel's radio runs, under which name, and who the page answers.
The panel offers a browser page for two jobs: a panel firmware upload and the card's files for download. It reaches the browser one of two ways:
ACCESS POINT its own network, 2.4GHz, WPA2 (Wi-Fi Protected Access 2), named "rcbench-" and 4 hex digits of the MAC (media access control) address, with a password of WA_SECRET_LEN characters made fresh at every start; one client at a time HOME NETWORK the network whose name and password the operator typed on the panel and the panel keeps
The radio runs only while the Wi-Fi screen asks for it, or while the panel asks GitHub for a release (WA_MODE_FETCH, wa_fetch.h). It is off at every start of the panel, and it goes off on its own: on ARM, on STOP, on the supply coming on, on a log run opening, after WA_IDLE_MS without a request, and after WA_GUESS_MAX wrong access codes. A joined session switched off by the operator or by WA_IDLE_MS may leave the radio up for the platform's last request on the network (wa_lingers()).
The access code: WA_SECRET_LEN characters shown on the panel, made fresh at every start, which the page asks for before it lists a file or takes an upload. A switch on the screen turns it off; it is on by default.
What is kept: the home network's name and password and the code switch (wa_conf_t), in a store the caller passes (NVS, non-volatile storage, on the panel). Nothing else about Wi-Fi is kept.
Pure C, no ESP-IDF (Espressif Internet-of-Things Development Framework): the platform reports what its radio did and asks what it should do.
SPDX-License-Identifier: MIT
| #define WA_ADDRESS_MS 15000u |
A join that reached the network and has no address after this long.
| #define WA_AUTH_TRIES 3u |
Auth-class drops in a row that end a join as WA_JOIN_PASSWORD.
The radio reports a refused key and a key handshake that ran out of time with the same reasons, and a correct key times out when the panel or the router answers late; one drop says nothing about the password.
| #define WA_GUESS_MAX 16u |
Wrong access codes before the radio goes off.
| #define WA_IDLE_MS (10u * 60u * 1000u) |
The radio goes off after this long without a request.
| #define WA_JOIN_MS 20000u |
A join that has not reached the network after this long failed.
| #define WA_NAME_MAX 13u |
"rcbench-1A2B" and its terminator.
| #define WA_SECRET_CHARS "abcdefghjkmnpqrstuvwxyz23456789" |
What a secret is made of: no 0, 1, i, l or o, which read alike.
| #define WA_SECRET_LEN 8u |
Characters of the access point's password and of the access code.
| #define WA_START_MS 10000u |
A start of the access point, or a scan, that has not come up.
| typedef uint32_t(*) wa_rand_fn(void *ctx) |
A source of random 32-bit words.
| ctx | The caller's context. |
| enum wa_code_t |
| enum wa_conf_err_t |
Why wa_conf_set_net() refused a home network.
| enum wa_join_err_t |
| enum wa_mode_t |
What a session is for.
| Enumerator | |
|---|---|
| WA_MODE_AP | the access point and the page |
| WA_MODE_JOIN | the home network and the page |
| WA_MODE_SCAN | a scan for the home network list, no page |
| WA_MODE_FETCH | The home network for the panel's own requests to GitHub (wa_fetch.h): no page, no name, no access code asked. |
| enum wa_off_t |
Why the radio is off.
| Enumerator | |
|---|---|
| WA_OFF_NONE | never started, or a scan finished |
| WA_OFF_ARMED | ARM, or an arm waiting |
| WA_OFF_SUPPLY | the supply's output on or queued on |
| WA_OFF_RUN | a log run is open |
| WA_OFF_STOP | STOP |
| WA_OFF_IDLE | WA_IDLE_MS without a request |
| WA_OFF_GUESSES | WA_GUESS_MAX wrong access codes |
| WA_OFF_ASKED | the operator switched it off |
| WA_OFF_INSTALL | an install is about to write the flash |
| WA_OFF_FAILED | the radio did not come up |
| WA_OFF_JOIN | a join failed: see wa_t.join_err |
| enum wa_scan_step_t |
What the platform does with a scan the radio reports done (wa_on_scan_end()).
| enum wa_state_t |
Where a session is.
Switch off for why.
A joined session switched off by the operator (WA_OFF_ASKED, which is also a release check's own end) or by WA_IDLE_MS lingers (wa_lingers()). Already off: only a reason that does not linger acts, and it ends the linger.
| w | The session. |
| why | The reason. |
Check given against this session's code.
A code from an earlier session is wrong. The WA_GUESS_MAX-th wrong one switches the session off.
| w | The session. |
| given | The code sent, NULL or terminated. |
| code_on | The code switch; false passes every request while the page is served. |
| void wa_conf_defaults | ( | wa_conf_t * | c | ) |
No home network, the code on: a fresh store, and what FORGET leaves.
| c | Receives the defaults. |
| bool wa_conf_forget | ( | const wa_store_t * | s, |
| wa_conf_t * | c ) |
FORGET: erase the store and leave c at the defaults.
| s | The store. |
| c | The settings. |
| void wa_conf_load | ( | const wa_store_t * | s, |
| wa_conf_t * | out ) |
What the store holds, or the defaults when it holds nothing.
A kept network that wa_conf_set_net() would refuse is dropped; the switch stays.
| s | The store. |
| out | Receives the settings. |
| bool wa_conf_save | ( | const wa_store_t * | s, |
| const wa_conf_t * | c ) |
Write c into the store.
| s | The store. |
| c | The settings. |
| wa_conf_err_t wa_conf_set_net | ( | wa_conf_t * | c, |
| const char * | ssid, | ||
| size_t | ssid_len, | ||
| const char * | pass, | ||
| size_t | pass_len ) |
Take a home network.
ssid of ssid_len bytes, 1 to WA_SSID_MAX, no NUL; pass of pass_len characters, WA_PASS_MIN to WA_PASS_MAX, each printable ASCII (American Standard Code for Information Interchange, 0x20 to 0x7E).
| c | The settings; unchanged unless WA_CONF_OK. |
| ssid | The network's name, not terminated. |
| ssid_len | Its bytes. |
| pass | The passphrase, not terminated. |
| pass_len | Its characters. |
| wa_off_t wa_gate | ( | bool | armed, |
| bool | supply, | ||
| bool | run ) |
Why the radio may not run now.
| armed | As flash_gate_open() takes it. |
| supply | Likewise. |
| run | A log run is open. |
| uint32_t wa_idle_left | ( | const wa_t * | w, |
| uint32_t | now_ms ) |
The time left before the idle time-out.
| w | The session. |
| now_ms | Now. |
| void wa_init | ( | wa_t * | w | ) |
Off, nothing kept of any session.
| w | The session. |
| bool wa_lingers | ( | const wa_t * | w | ) |
Whether the radio may stay up past the session's end, for a request of the platform's own that is under way (the clock's NTP request, wall_ntp_holds()).
Only a joined session switched off for WA_OFF_ASKED or WA_OFF_IDLE lingers. The linger ends at once with a gate (ARM, the supply, a log run), STOP, any other wa_close() reason (an install, a failed radio), a drop of the station and any wa_start(); a new session's start takes the radio down first.
| w | The session. |
| unsigned wa_modes | ( | const wa_conf_t * | c | ) |
Which ways the screen offers.
| c | The settings; NULL offers the access point only. |
| void wa_name | ( | const uint8_t | mac[6], |
| char | out[WA_NAME_MAX] ) |
"rcbench-" and the last two bytes of mac in capital hex.
| mac | The radio's MAC address. |
| out | Receives the name, terminated. |
| void wa_on_address | ( | wa_t * | w, |
| uint32_t | ip, | ||
| uint32_t | now_ms ) |
The station has an address.
| w | The session. |
| ip | The address, network byte order. |
| now_ms | Now. |
| void wa_on_ap_up | ( | wa_t * | w, |
| uint32_t | now_ms ) |
The access point came up.
| w | The session. |
| now_ms | Now. |
| void wa_on_associated | ( | wa_t * | w, |
| uint32_t | now_ms ) |
The station reached the home network.
| w | The session. |
| now_ms | Now. |
| bool wa_on_drop | ( | wa_t * | w, |
| bool | auth ) |
The radio dropped the station.
Joining: an auth-class drop counts, any other drop clears the count, and the WA_AUTH_TRIES-th auth-class drop in a row ends the join as WA_JOIN_PASSWORD. On the network, with or without an address: WA_JOIN_LOST. A join that reaches WA_JOIN_MS ends as WA_JOIN_PASSWORD when its last drop was auth-class, and as WA_JOIN_NOT_FOUND after any other drop or none (wa_tick()).
| w | The session. |
| auth | The platform reads the reason as auth-class (the key refused, a MIC (message integrity code) failure, the key handshake out of time). |
| void wa_on_failed | ( | wa_t * | w | ) |
The radio could not be started: off WA_OFF_FAILED. A refused scan is wa_scan_refused().
| w | The session. |
| void wa_on_join_failed | ( | wa_t * | w, |
| wa_join_err_t | why ) |
A join failed or a joined network went away.
| w | The session. |
| why | As the platform reads its reason code. |
| void wa_on_scan_done | ( | wa_t * | w | ) |
A scan session's list was read: the session ends, off WA_OFF_NONE. wa_on_scan_end() does it with the scan's result.
| w | The session. |
| wa_scan_step_t wa_on_scan_end | ( | wa_t * | w, |
| uint32_t | tok, | ||
| bool | ok, | ||
| uint32_t * | next ) |
The scan of tok reported done; ok as wa_scan_read_ok() says.
A report for a scan that is not the one under way changes nothing. A failed scan is started again while WA_SCAN_TRIES allows; the last one failed ends the session WA_OFF_FAILED, never as an empty list.
| w | The session. |
| tok | The token of the scan the report was read for. |
| ok | The scan worked and its list was read. |
| next | Receives the token of the scan to start with WA_SCAN_AGAIN, 0 otherwise. |
| void wa_pending_change | ( | wa_pending_t * | p | ) |
A change of the settings in memory: owe a save.
| p | The writes owed. |
| void wa_pending_done | ( | wa_pending_t * | p, |
| const wa_pending_t * | snap, | ||
| bool | erase_ok, | ||
| bool | save_ok, | ||
| uint32_t | now_ms ) |
Record the results of a write that started from snap.
| p | The writes owed. |
| snap | The copy the write started from. |
| erase_ok | The erase's result. |
| save_ok | The save's result. |
| now_ms | Now. |
| bool wa_pending_due | ( | const wa_pending_t * | p, |
| bool | may_write, | ||
| uint32_t | now_ms ) |
Whether a write is owed and due now.
| p | The writes owed. |
| may_write | This frame may write flash. |
| now_ms | Now. |
| void wa_pending_forget | ( | wa_pending_t * | p | ) |
FORGET: owe an erase; a save owed before it is void.
| p | The writes owed. |
| void wa_pending_init | ( | wa_pending_t * | p | ) |
Nothing owed.
| p | The writes owed. |
| void wa_pending_write | ( | const wa_store_t * | st, |
| const wa_pending_t * | snap, | ||
| const wa_conf_t * | c, | ||
| bool * | erase_ok, | ||
| bool * | save_ok ) |
Write what snap owes – the erase, then c – into st.
Runs without the caller's lock; snap and c are copies taken with wa_pending_due() under it.
| st | The store. |
| snap | The writes owed, a copy. |
| c | The settings, a copy. |
| erase_ok | Receives the erase's result; true for one not owed. |
| save_ok | Receives the save's result; true for one not owed. |
| bool wa_radio | ( | const wa_t * | w | ) |
Whether the platform's radio should be running.
| w | The session. |
| void wa_request_begin | ( | wa_t * | w, |
| uint32_t | now_ms ) |
A request begins; one under way holds the idle time-out off.
| w | The session. |
| now_ms | Now. |
| void wa_request_end | ( | wa_t * | w, |
| uint32_t | now_ms ) |
A request ends; the idle time counts from now.
| w | The session. |
| now_ms | Now. |
| void wa_scan_add | ( | wa_scan_t * | s, |
| const uint8_t * | ssid, | ||
| size_t | len, | ||
| int8_t | rssi, | ||
| bool | usable ) |
One network a scan saw.
Kept when usable (WPA2 or WPA3 personal) and named; a name already listed keeps the stronger signal. The list is held strongest first, and a full list keeps the WA_SCAN_MAX strongest.
| s | The list. |
| ssid | The name, len bytes, not terminated. |
| len | Its bytes. |
| rssi | Its signal, dBm. |
| usable | WPA2 or WPA3 personal. |
| uint32_t wa_scan_begin | ( | wa_t * | w | ) |
The radio's station started in a scan session: the token of the scan the platform starts now, or 0 for none.
One scan at a time: a second report of the station's start while a scan runs starts none, as a second esp_wifi_scan_start() would replace the first and report it done with nothing found. Each scan has its own token, never 0, which the platform carries through the calls that run outside its lock: a refusal (wa_scan_refused()), a done report (wa_on_scan_end()) and a retry (wa_scan_is()) act only on the scan under way, never on a session started after it.
| w | The session. |
| void wa_scan_clear | ( | wa_scan_t * | s | ) |
Empty the scan list.
| s | The list. |
| bool wa_scan_is | ( | const wa_t * | w, |
| uint32_t | tok ) |
Whether the scan of tok is the one under way.
| w | The session. |
| tok | A token wa_scan_begin() or wa_on_scan_end() gave. |
| uint32_t wa_scan_pending | ( | const wa_t * | w | ) |
The scan of this session under way, its done report still owed.
| w | The session. |
| const char * wa_scan_pick | ( | const wa_scan_t * | s, |
| unsigned | i ) |
The name at row i.
| s | The list; NULL reads as empty. |
| i | The row. |
| bool wa_scan_read_ok | ( | uint32_t | status, |
| unsigned | reported, | ||
| bool | read_ok, | ||
| unsigned | read, | ||
| unsigned | room ) |
Whether a scan reported done counts as done.
The read holds what the report counts, or fills the buffer when the report counts more than fit.
| status | The done report's status: 0 success, other a failure. |
| reported | The networks the done report counts. |
| read_ok | The list was read (esp_wifi_scan_get_ap_records()). |
| read | The networks read. |
| room | The records the read had room for. |
read equal to the smaller of reported and room. | bool wa_scan_refused | ( | wa_t * | w, |
| uint32_t | tok ) |
The radio refused to start the scan of tok: off WA_OFF_FAILED when it is the scan under way.
| w | The session. |
| tok | The scan's token. |
| void wa_secret_make | ( | char | out[WA_SECRET_LEN+1u], |
| wa_rand_fn | rand, | ||
| void * | ctx ) |
WA_SECRET_LEN characters of WA_SECRET_CHARS and a terminator, each drawn evenly from the alphabet (words that would favour some characters are drawn again).
| out | Receives the secret. |
| rand | The source of random words. |
| ctx | Passed to rand. |
| bool wa_serving | ( | const wa_t * | w | ) |
Whether the page is being served.
| w | The session. |
| wa_off_t wa_start | ( | wa_t * | w, |
| wa_mode_t | mode, | ||
| wa_off_t | gate, | ||
| uint32_t | now_ms, | ||
| wa_rand_fn | rand, | ||
| void * | ctx ) |
Start in mode when gate is WA_OFF_NONE, with a fresh password and code.
A start while the radio runs ends that session first.
| w | The session. |
| mode | What the session is for. |
| gate | wa_gate()'s answer. |
| now_ms | Now. |
| rand | The source of the secrets. |
| ctx | Passed to rand. |
Once a frame: the gate, STOP and the time-outs. Off, a gate or STOP ends a linger (wa_lingers()).
| w | The session. |
| now_ms | Now. |
| gate | wa_gate()'s answer. |
| stop | STOP pressed since the last call. |
| void wa_unlinger | ( | wa_t * | w | ) |
The platform needs the radio off now: a linger ends; a session that runs goes on.
| w | The session. |