Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

radio

rfkill: soft and hard block state per radio kind; nil without /dev/rfkill.

Toggle airplane mode with one call, and show which radios are blocked:

rect {
    on_click = function()
        local radio = mantle.radio:get()
        if radio then
            local blocked = false
            for _, r in ipairs(radio.radios) do
                blocked = blocked or r.soft_blocked
            end
            mantle.radio:set_all_blocked(not blocked)
        end
    end,
    children = {
        text {
            content = mantle.radio:map(function(radio)
                for _, r in ipairs(radio.radios) do
                    if r.hard_blocked then return "airplane (switch)" end
                end
                return "radios"
            end, ""),
        },
    },
}

rfkill is the airplane layer: set_blocked and set_all_blocked flip the kernel’s soft block, which switches the radios themselves off. network.set_wifi_enabled and bluetooth.set_enabled are separate and unchanged. There is no airplane field: compute it from radios.

State

mantle.radio:get() returns RadioState, nil before the first push. A field marked ? may be absent.

mantle.radio’s payload; the capability stays nil without /dev/rfkill or until a radio exists.

FieldTypeDescription
radiosRadio[]One entry per kind with at least one device, ordered by kernel type id.

Radio

One radio class and the rfkill block state of its devices.

FieldTypeDescription
hard_blockedbooleanHardware switch block, which software cannot clear: any device of this kind is blocked.
kindRadioKind
soft_blockedbooleanSoftware block, which set_blocked changes: any device of this kind is blocked.

RadioKind

A radio class, named as the kernel’s rfkill type; discriminants are the kernel type ids.

One of "wlan", "bluetooth", "uwb", "wimax", "wwan", "gps", "fm", "nfc".

Actions

Call each as mantle.radio:<action>(arguments...); ? marks an argument you may omit.

ActionArgumentsDescription
set_blockedkind: RadioKind, blocked: booleanSoft-blocks or unblocks every device of kind. A hardware block stays.
set_all_blockedblocked: booleanSoft-blocks or unblocks every radio (airplane mode).

Backend

ContractBehavior
Source/dev/rfkill only: one event per existing device at start, then live changes. No polling
KindsOne entry per kind with a device, ordered by kernel type id. A kind counts as blocked when any of its devices is. Unknown kernel types are skipped
No device nodeStays nil for good; actions are logged and ignored
No radiosStays nil until one appears: the kernel sends nothing to read
WritesOne CHANGE_ALL request to the same fd; the kernel also applies it to radios plugged in later. State updates when the kernel reports the change

Gotchas

TrapFix
set_blocked(kind, false) leaves hard_blocked = trueA hardware switch overrides software. Only the switch clears it; show it instead
A session without a seat cannot write /dev/rfkillState is still reported; actions are logged and ignored

Source: supervisor/src/capabilities/radio/