radio_esp32::adapter
Filling in [crate::osi::WifiOsiFuncs].
Each function here is a translation between FreeRTOS’s conventions and FlintOS’s, and the translations are where the bugs are. The three that matter most, written down once rather than at every call site:
Return codes are inverted. FreeRTOS returns pdTRUE (1) for success
and pdFALSE (0) for failure. FlintOS returns bool. Getting this
backwards makes every blocking call appear to time out, which looks like a
dead radio rather than a wrong constant.
Priorities are inverted. FreeRTOS counts up to more urgent; FlintOS
counts down. A blob task created at the number it asks for would run at
the opposite end of the system. See [priority_from_freertos].
Timeouts are in ticks, not milliseconds. The blob speaks ticks and
dynobj speaks milliseconds. OSI_FUNCS_TIME_BLOCKING maps to
dynobj::FOREVER; anything else is converted.
Two kinds of symbol, one file
Section titled “Two kinds of symbol, one file”The table is what Espressif made replaceable. Further down, under
by_name, are the symbols the archives call directly instead — malloc,
the logging hooks, the mesh stubs. That distinction is Espressif’s rather
than a real one, and keeping the two in separate files is what let malloc
end up implemented twice.
Handles
Section titled “Handles”The blob holds void* handles it never dereferences. Each object is
allocated on the radio heap and the pointer handed back, so the handle is
the object. That keeps _delete honest — it frees what it was given —
and means a stale handle is a use-after-free rather than an index into a
table that has been reused, which is the easier of the two to catch under
a debugger.
Modules
Section titled “Modules”calls— How often the blob has used the entries its start path leans on.
Structs
Section titled “Structs”struct Alloc { pub kind: u8, pub phase: u8, pub size: u32, pub ptr: usize, pub freed: bool,}One allocation, as the driver asked for it and as it was answered.
Counts alone hide what matters: they are cumulative, so they cannot say
what is still held, and they merge entries that the driver chose between
deliberately. _malloc_internal and _wifi_malloc mean different things
to the caller even where they mean the same thing to us, and which one was
asked for is evidence about what the memory was for.
Bounded, and the overflow is counted rather than silently dropped: a trace that quietly stops is worse than one that says where it stopped.
Implements: Clone, Copy
ObjectId
Section titled “ObjectId”struct ObjectId { pub kind: &'static str, pub nth: u32,}Implements: Clone, Copy, Eq, PartialEq, StructuralPartialEq
Functions
Section titled “Functions”alloc_totals
Section titled “alloc_totals”fn alloc_totals() -> (u32, u32, u32, u32, u32)Recorded, still held, bytes still held, records lost to the table filling, and frees that matched nothing.
describe
Section titled “describe”fn describe(addr: usize) -> Option<ObjectId>What was created at addr, if the adapter made it.
References: ObjectId
for_each_live_alloc
Section titled “for_each_live_alloc”fn for_each_live_alloc<impl FnMut(&Alloc)>(f: impl FnMut)Every allocation still outstanding, oldest first.
forget_thread_semaphore
Section titled “forget_thread_semaphore”fn forget_thread_semaphore(task: u32)Release the per-task semaphore belonging to task, if it has one.
Called from [crate::tasks] when a blob task is deleted. A task FlintOS
did not create for the blob never reaches here, which matches esp-idf: its
destructor is a pthread key’s, and only pthreads have one.
ms_from_ticks
Section titled “ms_from_ticks”fn ms_from_ticks(ticks: u32) -> u32Blob ticks to FlintOS milliseconds.
The blob’s tick is esp-idf’s portTICK_PERIOD_MS, which is 1 ms in every
configuration Espressif ships for the ESP32 — CONFIG_FREERTOS_HZ is 100
by default but the Wi-Fi driver requires 1000. Treating a tick as a
millisecond is therefore exact rather than approximate, and this function
exists so that assumption has one home if it ever stops being true.
mutex_unlock_failures
Section titled “mutex_unlock_failures”fn mutex_unlock_failures() -> u32How many unlocks have been refused. See MUTEX_UNLOCK_FAILED.
priority_from_freertos
Section titled “priority_from_freertos”const fn priority_from_freertos(prio: u32) -> hal::types::PriorityFreeRTOS priority to FlintOS priority.
FreeRTOS counts up: 0 is idle and configMAX_PRIORITIES - 1 is the most
urgent. FlintOS counts down: 0 is the most urgent. So the two are mirror
images and a value passed straight through lands at the opposite end of the
system — a Wi-Fi task that must pre-empt everything would instead run below
the idle-adjacent background work, and the symptom is dropped frames under
load rather than anything that points here.
Espressif creates its tasks between 18 and 23 out of 25. Those map to the urgent end here, which is what they are asking for.
References: Priority
report_unimplemented
Section titled “report_unimplemented”fn report_unimplemented(t: &crate::osi::WifiOsiFuncs) -> usizeLog every entry the table still leaves null, by name.
The list this replaced was prose and went a year out of date. This is the
same question asked of the table itself, and it is what turned the gap from
something discovered one epc=0x00000000 at a time into a list printed
before the blob is ever handed the table.
Returns the count, so a caller can decide whether to go on.
References: WifiOsiFuncs
set_alloc_phase
Section titled “set_alloc_phase”fn set_alloc_phase(phase: u8)Mark which stage of bring-up the records that follow belong to.
fn table() -> crate::osi::WifiOsiFuncsBuild the table the blob is given.
On the target this fills all 115. On a host it leaves the entries that
need silicon null — see NEEDS_HARDWARE in the tests, which is the list
that has to stay true.
References: WifiOsiFuncs
Constants
Section titled “Constants”ALLOC_NAMES
Section titled “ALLOC_NAMES”const ALLOC_NAMES: [&str; 7];A_CALLOC_INTERNAL
Section titled “A_CALLOC_INTERNAL”const A_CALLOC_INTERNAL: u8;A_MALLOC
Section titled “A_MALLOC”const A_MALLOC: u8;A_MALLOC_INTERNAL
Section titled “A_MALLOC_INTERNAL”const A_MALLOC_INTERNAL: u8;A_WIFI_CALLOC
Section titled “A_WIFI_CALLOC”const A_WIFI_CALLOC: u8;A_WIFI_MALLOC
Section titled “A_WIFI_MALLOC”const A_WIFI_MALLOC: u8;A_WIFI_ZALLOC
Section titled “A_WIFI_ZALLOC”const A_WIFI_ZALLOC: u8;A_ZALLOC_INTERNAL
Section titled “A_ZALLOC_INTERNAL”const A_ZALLOC_INTERNAL: u8;PD_FALSE
Section titled “PD_FALSE”const PD_FALSE: i32;FreeRTOS pdFALSE.
PD_TRUE
Section titled “PD_TRUE”const PD_TRUE: i32;FreeRTOS pdTRUE.