rcbench
Servo and ESC test bench: panel, IOmcu and shared C
Loading...
Searching...
No Matches
wifi_access.c File Reference

The panel's Wi-Fi over esp_wifi, esp_http_server, esp_http_client and a UDP (user datagram protocol) socket for the mDNS name. More...

#include "wifi_access.h"
#include <fcntl.h>
#include <stdatomic.h>
#include <stdio.h>
#include <string.h>
#include <strings.h>
#include <unistd.h>
#include "esp_crt_bundle.h"
#include "esp_event.h"
#include "esp_http_client.h"
#include "esp_http_server.h"
#include "esp_heap_caps.h"
#include "esp_log.h"
#include "esp_netif.h"
#include "esp_random.h"
#include "esp_timer.h"
#include "esp_wifi.h"
#include "freertos/FreeRTOS.h"
#include "freertos/semphr.h"
#include "freertos/task.h"
#include "lwip/inet.h"
#include "lwip/sockets.h"
#include "nvs.h"
#include "storage.h"
#include "wa_mdns.h"
#include "wa_page.h"
#include "wa_send.h"
#include "wifi_dns.h"
#include "wifi_ntp.h"
#include "wifi_radio.h"
#include "wifi_req.h"
#include "wifi_sock.h"
#include "wa_text.h"
#include "wa_walk.h"
#include "wa_zip.h"
#include "wall_clock.h"

Data Structures

struct  bufs_t
struct  http_ctx_t
struct  [struct].s
 Driver state of the UART: the claimed machines and the pins. More...

Macros

#define NVS_NS   "wifi"
#define WORKER_STACK   6912u
 Stack of the wifi_ctl task, in bytes, from internal RAM. The deepest call chain, the radio stop down to snprintf(), is 3744 bytes; 6912 leaves 2144 above tools/stack_check.py's 1024-byte margin.
#define MDNS_STACK   4096u
#define HTTPD_STACK   8192u
#define HTTPD_WAIT_S   5u
 A receive or a send of the page's server waits this long at a time, s: esp_http_server's own default (HTTPD_DEFAULT_CONFIG()), written out. A request whose client goes quiet for it ends.
#define UPLOAD_WAITS   6u
 Waits of HTTPD_WAIT_S an upload rides out: 30s quiet.
#define NET_PRIORITY   1u
#define WORKER_PRIO   2u
#define NET_CORE   0
#define IO_CHUNK   4096u
#define SCAN_READ   24u
#define FETCH_STACK   8192u
#define FETCH_SLICE_MS   1000u
#define FETCH_GRACE_MS   1500u
 The radio goes off after this much, task ended or not, ms. A connection ends with the radio; a name lookup only when lwIP gives up on it, up to about 7s a DNS server, and the radio does not wait for that (wa_fetch_start_gate()).
#define FETCH_AGENT   "rcbench-panel"
#define DRAIN_MS   2000u
 How long the worker waits for the event loop to pass the radio's last events at its stop (drain()), ms.

Functions

 ESP_EVENT_DEFINE_BASE (WA_DRAIN_EVENT)
 The worker's marker in the default event loop (drain()).
static uint32_t ms (void)
static void lock (void)
static void unlock (void)
static void poke (void)
static uint32_t rand32 (void *ctx)
static bool nvs_conf_load (void *ctx, wa_conf_t *out)
static bool nvs_conf_save (void *ctx, const wa_conf_t *c)
static bool nvs_conf_erase (void *ctx)
static size_t card_path (char *out, size_t cap, const char *rel)
static bool card_stopped (void *ctx)
 wa_fs_t.stopped(): a request under way ends now (s.abort).
static void * card_opendir (void *ctx, const char *path)
static int card_readdir (void *ctx, void *dir, wa_dirent_t *out)
static void card_closedir (void *ctx, void *dir)
static void * card_open (void *ctx, const char *path)
static int32_t card_read (void *ctx, void *file, uint8_t *dst, uint32_t len)
static void card_close (void *ctx, void *file)
static bool req_begin (void)
static void req_end (void)
static bool req_guard (httpd_req_t *r, wa_req_kind_t kind, esp_err_t *e)
 wifi_req_guard() before anything else of a handler's.
static wa_code_t req_code (httpd_req_t *r)
static void page_info (wa_page_info_t *pi)
static bool sink_chunk (void *ctx, const void *data, size_t n)
static esp_err_t send_page (httpd_req_t *r, bool code_form, bool wrong)
static esp_err_t closed (httpd_req_t *r)
static esp_err_t h_root (httpd_req_t *r)
static esp_err_t h_code (httpd_req_t *r)
static esp_err_t refused (httpd_req_t *r, const char *status)
static bool upload_text (void *ctx, const void *data, size_t n)
static esp_err_t answer_upload (httpd_req_t *r, fw_err_t e, const fw_image_info_t *info, bool same, bool cut)
static esp_err_t h_update (httpd_req_t *r)
static wa_send_res_t raw_send (httpd_req_t *r, const void *data, size_t n)
static wa_send_res_t raw_head (httpd_req_t *r, uint64_t length, const char *name)
static esp_err_t h_file (httpd_req_t *r)
static esp_err_t h_zip (httpd_req_t *r)
 GET /card.zip: the whole card as one ZIP archive, its length announced before the first byte.
static esp_err_t httpd_up (void)
static void mdns_task (void *arg)
static esp_err_t on_http (esp_http_client_event_t *e)
static void h_close (void *ctx)
static bool h_open (void *ctx, const char *url, uint32_t timeout_ms, bool api, wa_http_head_t *head, char *loc, size_t loc_cap)
static int32_t h_read (void *ctx, uint8_t *dst, uint32_t n, uint32_t timeout_ms)
static uint32_t f_now (void *ctx)
static bool f_stopped (void *ctx)
static void f_report (void *ctx, wa_phase_t ph, uint32_t done, uint32_t total)
static uint8_t * f_alloc (void *ctx, uint32_t bytes)
static void fetch_task (void *arg)
static bool auth_refused (uint8_t reason)
static void scan_start (uint32_t tok, unsigned run)
 Start the scan of tok, all channels, the driver's default times, while it is still the scan under way; a refusal ends the session WA_OFF_FAILED only while it still is.
static void on_scan_done (const wifi_event_sta_scan_done_t *d)
 WIFI_EVENT_SCAN_DONE in a scan session: read the list of the scan under way, or start it again, or end the session.
static void on_event (void *arg, esp_event_base_t base, int32_t id, void *data)
static void start_failed (const char *step, esp_err_t e)
static void on_drain (void *arg, esp_event_base_t base, int32_t id, void *data)
 The marker drain() posts: every event posted before it is handled.
static void drain (void)
 Wait, DRAIN_MS at most, until the event loop has handled every event the radio posted before its stop.
static bool net_once (void)
static bool fetch_wait (uint32_t wait_ms)
static void radio_down (void)
 Take the radio down: mDNS, the fetch, the page's server, the driver and the interface.
static bool radio_bring_up (wa_mode_t mode, const wa_t *w, const wa_conf_t *c)
 Bring the radio up in mode: the C6's link, the interface, the driver, the configuration and, in AP and JOIN, the page's server.
static void radio_hold (void)
 Keep the radio up past its session's end for the clock's NTP answer (wifi_ntp.h): the page's requests under way and the mDNS name end now, the station and the interface stay until radio_down(). Logged once a radio.
static void worker (void *arg)
 The task that owns the radio: compares what the session wants with what runs, and brings the radio up or down; a failed C6 link takes it down. A session that ended and lingers (wa_lingers()) keeps the radio while the clock's NTP request asks.
esp_err_t wifi_access_init (uint32_t slot, const fw_image_info_t *running)
void wifi_access_set_german (bool de)
wa_off_t wifi_access_start (wa_mode_t mode, wa_off_t gate)
void wifi_access_close (wa_off_t why)
 Radio off for why; see wa_close().
bool wifi_access_tick (wa_off_t gate, bool stop, bool may_write)
 Once a frame: the gate, STOP pressed since the last call, the time-outs; and a change to what is kept written when may_write.
void wifi_access_get (wifi_access_state_t *out)
bool wifi_access_down (void)
 Whether the radio is wholly off and no start of it is asked for; from any task, without the lock.
void wifi_access_end_linger (void)
 The radio goes off without waiting for the clock's NTP answer: a session that ended and lingers (wa_lingers()) stops lingering; one that runs goes on. From any task, without the lock.
bool wifi_access_save_net (const char *ssid, const char *pass)
void wifi_access_forget (void)
void wifi_access_set_code (bool on)
void wifi_access_discard (void)
bool wifi_access_take (const uint8_t **img, uint32_t *bytes, fw_image_info_t *info)
void wifi_access_release (void)
wa_got_t wifi_access_fetch_start (wa_job_t job, fw_version_t want, wa_channel_t ch, wa_why_t gate)
void wifi_access_fetch_tick (wa_why_t abort)
void wifi_access_fetch_get (wa_fetch_t *out)
bool wifi_access_home (char *ssid, size_t n)

Variables

static const char * TAG = "wifi"
static struct  s
static bufs_t * b
static const wa_store_t k_store
static const wa_fs_t k_card
static http_ctx_t s_http
static const wa_http_t k_http = { h_open, h_read, h_close, &s_http }

Detailed Description

The panel's Wi-Fi over esp_wifi, esp_http_server, esp_http_client and a UDP (user datagram protocol) socket for the mDNS name.

The radio under esp_wifi is the board's ESP32-C6 on SDIO, brought up by wifi_radio.h.

Three tasks touch the session: the UI loop (start, close, tick), the event loop (what the radio reports) and the HTTP server (requests). Everything they share is under one mutex, held for copies and counters only, never across a socket or a card read. A fourth task, the worker, owns bringing the radio up and down: it compares what the session wants with what runs and acts, so a stop that waits for a download to end never waits on the UI loop. A fifth, the fetch task, runs one job's requests to GitHub (wa_fetch.h) and ends with it.

SPDX-License-Identifier: MIT

Function Documentation

◆ card_stopped()

bool card_stopped ( void * ctx)
static

wa_fs_t.stopped(): a request under way ends now (s.abort).

Parameters
ctxunused
Returns
true once the radio is going down or held

◆ drain()

void drain ( void )
static

Wait, DRAIN_MS at most, until the event loop has handled every event the radio posted before its stop.

Binds each scan's done report to its radio: the next radio's station start, which starts its scan (wa_scan_begin()), comes after the marker, so a done report of the radio taken down is never read as the next one's.

◆ h_zip()

esp_err_t h_zip ( httpd_req_t * r)
static

GET /card.zip: the whole card as one ZIP archive, its length announced before the first byte.

Parameters
rthe request
Returns
ESP_OK when the archive went out whole. A failure part way sends the bytes wa_zip_next() made up to it, then resets the connection (ESP_FAIL): the browser has fewer bytes than announced and reports the download failed.

◆ on_drain()

void on_drain ( void * arg,
esp_event_base_t base,
int32_t id,
void * data )
static

The marker drain() posts: every event posted before it is handled.

Parameters
argUnused.
baseWA_DRAIN_EVENT.
idUnused.
dataUnused.

◆ on_scan_done()

void on_scan_done ( const wifi_event_sta_scan_done_t * d)
static

WIFI_EVENT_SCAN_DONE in a scan session: read the list of the scan under way, or start it again, or end the session.

A done report with no scan of this session under way reads nothing: its list, if any, goes with the driver at the radio's stop. A failed scan, a list that cannot be read and a read that does not hold what the report counts each count as a failure (wa_scan_read_ok()), never as an empty list. The scan's token carries the report through the read, which runs without the lock.

Parameters
dThe event's data; NULL reads as a success that counts nothing.

◆ radio_bring_up()

bool radio_bring_up ( wa_mode_t mode,
const wa_t * w,
const wa_conf_t * c )
static

Bring the radio up in mode: the C6's link, the interface, the driver, the configuration and, in AP and JOIN, the page's server.

Parameters
modeThe session's mode.
wThe session, for the access point's password.
cThe kept home network, for JOIN and FETCH.
Returns
true when every step worked; false after the first that failed, logged by start_failed().

◆ radio_down()

void radio_down ( void )
static

Take the radio down: mDNS, the fetch, the page's server, the driver and the interface.

The fetch task gets FETCH_GRACE_MS. One still in a name lookup after it is not waited for: the radio counts as down once the interface is gone, and the task ends when lwIP gives up on the lookup. It reads no state the radio's end frees, its report is dropped by the job's generation, and no job starts while it lives (wa_fetch_start_gate()). A lookup that a next session's station answers leads to one connection over it, whose result is dropped; f_stopped() ends the job before any further request.

After a failed C6 link, esp_wifi_stop() and esp_wifi_deinit() are not called: each is a request to the C6, which is held in reset then, and would end only at esp_hosted's response time-out, 5s each.

◆ req_guard()

bool req_guard ( httpd_req_t * r,
wa_req_kind_t kind,
esp_err_t * e )
static

wifi_req_guard() before anything else of a handler's.

Parameters
rthe request
kindwhat it is
etakes the handler's return on a refusal
Returns
true when the request may be answered

◆ scan_start()

void scan_start ( uint32_t tok,
unsigned run )
static

Start the scan of tok, all channels, the driver's default times, while it is still the scan under way; a refusal ends the session WA_OFF_FAILED only while it still is.

Called with the lock not held, from the event loop: the request goes to the C6 and waits for its answer, and a session can end and another start meanwhile (wa_scan_begin()).

Parameters
tokThe scan's token.
runThe scan's number in the session, from 1.

◆ wifi_access_close()

void wifi_access_close ( wa_off_t why)

Radio off for why; see wa_close().

Parameters
whyThe reason.

◆ wifi_access_discard()

void wifi_access_discard ( void )

Drop a received or staged image. Nothing while one is taken.

◆ wifi_access_down()

bool wifi_access_down ( void )

Whether the radio is wholly off and no start of it is asked for; from any task, without the lock.

A start asked for counts as up from the call on, a close until the station or access point is stopped and its interface is gone. A GitHub fetch task still in a name lookup then does not hold it up: it sends nothing while the radio stays off, and no fetch job starts before it ends.

Returns
true when the radio is off and nothing asks for it

◆ wifi_access_fetch_get()

void wifi_access_fetch_get ( wa_fetch_t * out)

The job, as a copy.

◆ wifi_access_fetch_start()

wa_got_t wifi_access_fetch_start ( wa_job_t job,
fw_version_t want,
wa_channel_t ch,
wa_why_t gate )

Start job (wa_fetch_start()) for release want (DOWNLOAD only) on channel ch (CHECK: which releases it looks at) unless gate says why not. WA_GOT_NONE: the radio comes up in WA_MODE_FETCH and the job runs; otherwise it has ended at once. A DOWNLOAD drops an image the page left staged first; while one is taken, or the last job's task has not ended yet, it is BLOCKED for BUSY. Refused on a session another screen runs: the caller starts no job while WI-FI is open.

◆ wifi_access_fetch_tick()

void wifi_access_fetch_tick ( wa_why_t abort)

Once a frame, after wifi_access_tick(): abort as wa_fetch_tick() takes it. Moves the job on, ends it, switches the radio off when it has ended, and starts the task that talks to GitHub once joined.

◆ wifi_access_forget()

void wifi_access_forget ( void )

FORGET: no home network, the access code on.

◆ wifi_access_home()

bool wifi_access_home ( char * ssid,
size_t n )

Whether a home network is kept, and its name into ssid of n bytes (empty for none).

◆ wifi_access_init()

esp_err_t wifi_access_init ( uint32_t slot,
const fw_image_info_t * running )

Read the kept home network and set up the task. slot is the largest image taken, running the build that runs. The radio stays off. On a failure nothing is kept, and no other call of this file may be made: the panel runs without Wi-Fi until the next start.

◆ wifi_access_release()

void wifi_access_release ( void )

After a write that failed: the image is dropped.

◆ wifi_access_save_net()

bool wifi_access_save_net ( const char * ssid,
const char * pass )

Keep a home network; false when wa_conf_set_net() refuses it.

◆ wifi_access_set_german()

void wifi_access_set_german ( bool de)

The page's language.

◆ wifi_access_start()

wa_off_t wifi_access_start ( wa_mode_t mode,
wa_off_t gate )

Start in mode unless gate says why not; see wa_start().

◆ wifi_access_take()

bool wifi_access_take ( const uint8_t ** img,
uint32_t * bytes,
fw_image_info_t * info )

Take the staged image for the installer: it stays where it is, and nothing drops it, until wifi_access_release(). False when none waits.

◆ wifi_access_tick()

bool wifi_access_tick ( wa_off_t gate,
bool stop,
bool may_write )

Once a frame: the gate, STOP pressed since the last call, the time-outs; and a change to what is kept written when may_write.

Parameters
gatewa_gate()'s answer.
stopSTOP pressed since the last call.
may_writeFlash may be written now.
Returns
Whether this call switched the radio off or ended its linger (wa_tick()).

◆ worker()

void worker ( void * arg)
static

The task that owns the radio: compares what the session wants with what runs, and brings the radio up or down; a failed C6 link takes it down. A session that ended and lingers (wa_lingers()) keeps the radio while the clock's NTP request asks.

Parameters
argUnused.

Variable Documentation

◆ k_card

const wa_fs_t k_card
static
Initial value:
= {
card_opendir, card_readdir, card_closedir,
card_open, card_read, card_close, NULL, card_stopped,
}
static bool card_stopped(void *ctx)
wa_fs_t.stopped(): a request under way ends now (s.abort).
Definition wifi_access.c:287

◆ k_store

const wa_store_t k_store
static
Initial value:
= {
nvs_conf_load, nvs_conf_save, nvs_conf_erase, NULL,
}