[{"classIdentifier":536870897,"shortId":"_system","source":"# Common registers and commands\n\n    camel: system\n\nThis file describes common register and command codes.\n\nThese are defined in ranges separate from the per-service ones.\nNo service actually derives from this file, but services can include packets\ndefined here.\nTheir code is listed as say `@ intensity` and not `@ 0x01` (the spectool enforces that).\n\n## Commands\n\nCommand codes are subdivided as follows:\n\n-   Commands `0x000-0x07f` - common to all services\n-   Commands `0x080-0xeff` - defined per-service\n-   Commands `0xf00-0xfff` - reserved for implementation\n\nCommands follow.\n\n    define announce_interval 500\n    command announce @ 0x00 { }\n    report { ... }\n\nEnumeration data for control service; service-specific advertisement data otherwise.\nControl broadcasts it automatically every `announce_interval`ms, but other service have to be queried to provide it.\n\n    command get_register @ 0x1000 {}\n    report { ... }\n\nRegisters number `N` is fetched by issuing command `0x1000 | N`.\nThe report format is the same as the format of the register.\n\n    command set_register @ 0x2000 { ... }\n\nRegisters number `N` is set by issuing command `0x2000 | N`, with the format\nthe same as the format of the register.\n\n    command calibrate @ 0x02 { }\n    report { }\n\nRequest to calibrate a sensor. The report indicates the calibration is done.\n\n    report command_not_implemented @ 0x03 {\n        service_command: u16\n        packet_crc: u16\n    }\n\nThis report may be emitted by a server in response to a command (action or register operation)\nthat it does not understand.\nThe `service_command` and `packet_crc` fields are copied from the command packet that was unhandled.\nNote that it's possible to get an ACK, followed by such an error report.\n\n## Registers\n\nRegister codes are subdivided as follows:\n\n-   Registers `0x001-0x07f` - r/w common to all services\n-   Registers `0x080-0x0ff` - r/w defined per-service\n-   Registers `0x100-0x17f` - r/o common to all services\n-   Registers `0x180-0x1ff` - r/o defined per-service\n-   Registers `0x200-0xeff` - custom, defined per-service\n-   Registers `0xf00-0xfff` - reserved for implementation, should not be seen on the wire\n\nThe types listed are typical. Check spec for particular service for exact type,\nand a service-specific name for a register (eg. `value` could be `pulse_length`).\nAll registers default to `0` unless otherwise indicated.\n\n    rw intensity: u32 @ 0x01\n\nThis is either binary on/off (0 or non-zero), or can be gradual (eg. brightness of an RGB LED strip).\n\n    rw value: i32 @ 0x02\n\nThe primary value of actuator (eg. servo pulse length, or motor duty cycle).\n\n    const min_value: i32 @ 0x110\n\nThe lowest value that can be reported for the value register.\n\n    const max_value: i32 @ 0x111\n\nThe highest value that can be reported for the value register.\n\n    rw max_power = 500: u16 mA {typical_max = 500} @ 0x07\n\nLimit the power drawn by the service, in mA.\n\n    rw streaming_samples: u8 # @ 0x03\n\nAsks device to stream a given number of samples\n(clients will typically write `255` to this register every second or so, while streaming is required).\n\n    rw streaming_interval = 100: u32 ms @ 0x04\n\nPeriod between packets of data when streaming in milliseconds.\n\n    ro volatile reading: i32 @ 0x101\n\nRead-only value of the sensor, also reported in streaming.\n\n    rw reading_range: u32 @ 0x08\n\nFor sensors that support it, sets the range (sometimes also described `min`/`max_reading`).\nTypically only a small set of values is supported.\nSetting it to `X` will select the smallest possible range that is at least `X`,\nor if it doesn't exist, the largest supported range.\n\n    const supported_ranges @ 0x10a {\n    repeats:\n        range: u32\n    }\n\nLists the values supported as `reading_range`.\n\n    const min_reading: i32 @ 0x104\n\nThe lowest value that can be reported by the sensor.\n\n    const max_reading: i32 @ 0x105\n\nThe highest value that can be reported by the sensor.\n\n    ro volatile reading_error: u32 @ 0x106\n\nThe real value of whatever is measured is between `reading - reading_error` and `reading + reading_error`. It should be computed from the internal state of the sensor. This register is often, but not always `const`. If the register value is modified,\nsend a report in the same frame of the `reading` report.\n\n    const reading_resolution: u32 @ 0x108\n\nSmallest, yet distinguishable change in reading.\n\n    enum ReadingThreshold: u8 {\n        Neutral = 1\n        Inactive = 2\n        Active = 3\n    }\n    rw inactive_threshold: i32 @ 0x05\n\nThreshold when reading data gets inactive and triggers a `inactive`.\n\n    rw active_threshold: i32 @ 0x06\n\nThresholds when reading data gets active and triggers a `active` event.\n\n    const streaming_preferred_interval: u32 ms @ 0x102\n\nPreferred default streaming interval for sensor in milliseconds.\n\n    const variant: u32 @ 0x107\n\nThe hardware variant of the service.\nFor services which support this, there's an enum defining the meaning.\n\n    rw client_variant: string @ 0x09\n\nAn optional register in the format of a URL query string where the client can provide hints how\nthe device twin should be rendered. If the register is not implemented, the client library can simulate the register client side.\n\n    enum StatusCodes: u16 {\n        Ready = 0\n\n        Initializing = 1\n        Calibrating = 2\n\n        Sleeping = 3\n        WaitingForInput = 4\n\n        CalibrationNeeded = 100\n    }\n    ro status_code? @ 0x103 {\n        code: StatusCodes\n        vendor_code: u16\n    }\n\nReports the current state or error status of the device. `code` is a standardized value from\nthe Jacdac status/error codes. `vendor_code` is any vendor specific error code describing the device\nstate. This report is typically not queried, when a device has an error, it will typically\nadd this report in frame along with the announce packet.\n\n    const instance_name?: string @ 0x109\n\nA friendly name that describes the role of this service instance in the device.\n\n## Events\n\nEvents codes are 8-bit and are subdivided as follows:\n\n-   Events `0x00-0x7f` - common to all services\n-   Events `0x80-0xff` - defined per-service\n\n    event active @ 0x01 { }\n\nNotifies that the service has been activated (eg. button pressed, network connected, etc.)\n\n    event inactive @ 0x02 { }\n\nNotifies that the service has been dis-activated.\n\n    event change @ 0x03 { }\n\nNotifies that the some state of the service changed.\n\n    event status_code_changed @ 0x04 {\n        code: StatusCodes\n        vendor_code: u16\n    }\n\nNotifies that the status code of the service changed.\n\n    event neutral @ 0x07 {}\n\nNotifies that the threshold is back between `low` and `high`.\n"},{"classIdentifier":536870899,"shortId":"_base","source":"# Base service\n\n    camel: base\n    status: stable\n\nBase class for all services.\n\n## Commands\n\n    report command_not_implemented @ command_not_implemented {\n        service_command: u16\n        packet_crc: u16\n    }\n\nThis report may be emitted by a server in response to a command (action or register operation)\nthat it does not understand.\nThe `service_command` and `packet_crc` fields are copied from the command packet that was unhandled.\nNote that it's possible to get an ACK, followed by such an error report.\n\n\n## Registers\n\n    const instance_name?: string @ instance_name\n\nA friendly name that describes the role of this service instance in the device.\nIt often corresponds to what's printed on the device:\nfor example, `A` for button A, or `S0` for servo channel 0.\nWords like `left` should be avoided because of localization issues (unless they are printed on the device).\n\n    ro status_code? @ status_code {\n        code: u16\n        vendor_code: u16\n    }\n\nReports the current state or error status of the device. ``code`` is a standardized value from \nthe Jacdac status/error codes. ``vendor_code`` is any vendor specific error code describing the device\nstate. This report is typically not queried, when a device has an error, it will typically\nadd this report in frame along with the announce packet. If a service implements this register,\nit should also support the ``status_code_changed`` event defined below.\n\n    rw client_variant?: string @ client_variant\n\nAn optional register in the format of a URL query string where the client can provide hints how\nthe device twin should be rendered. If the register is not implemented, the client library can simulate the register client side.\n\n## Events\n\n    event status_code_changed? @ status_code_changed {\n        code: u16\n        vendor_code: u16\n    }\n\nNotifies that the status code of the service changed.\n"},{"classIdentifier":536870898,"shortId":"_sensor","source":"# Sensor\n\n    camel: sensor\n    status: stable\n\nBase class for sensors.\n\n## Registers\n\n    rw internal streaming_samples: u8 # @ streaming_samples\n\nAsks device to stream a given number of samples\n(clients will typically write `255` to this register every second or so, while streaming is required).\n\n    rw streaming_interval = 100: u32 ms {typical_min = 1, typical_max = 60000} @ streaming_interval\n\nPeriod between packets of data when streaming in milliseconds.\n\n    const internal streaming_preferred_interval?: u32 ms @ streaming_preferred_interval\n\nPreferred default streaming interval for sensor in milliseconds.\n"},{"classIdentifier":521405449,"shortId":"accelerometer","source":"# Accelerometer\n\n    identifier: 0x1f140409\n    extends: _sensor\n    tags: C\n    group: movement\n    status: stable\n\nA 3-axis accelerometer.\n\n## Orientation\n\nAn accelerometer module should translate acceleration values as follows:\n\n| Orientation           \t| X value (g) \t| Y value (g) \t| Z value (g) \t|\n|-----------------------\t|-------------\t|-------------\t|-------------\t|\n| Module lying flat     \t| 0           \t| 0           \t| -1          \t|\n| Module on left edge   \t| -1          \t| 0           \t| 0           \t|\n| Module on bottom edge \t| 0           \t| 1           \t| 0           \t|\n\nWe recommend an orientation marking on the PCB so that users can mount modules without having to experiment with the device. Left/bottom can be determined by assuming text on silk runs left-to-right.\n\n## Registers\n\n    ro forces @ reading {\n        x: i12.20 g\n        y: i12.20 g\n        z: i12.20 g\n    }\n\nIndicates the current forces acting on accelerometer.\n\n    ro forces_error?: u12.20 g @ reading_error\n\nError on the reading value.\n\n    rw max_force?: u12.20 g @ reading_range\n\nConfigures the range forces detected.\nThe value will be \"rounded up\" to one of `max_forces_supported`.\n\n    const max_forces_supported? @ supported_ranges {\n    repeats:\n        max_force: u12.20 g\n    }\n\nLists values supported for writing `max_force`.\n\n## Events\n\nAll events are debounced.\n\n    event tilt_up @ 0x81\n    event tilt_down @ 0x82\n    event tilt_left @ 0x83\n    event tilt_right @ 0x84\n\nEmitted when accelerometer is tilted in the given direction.\n\n    event face_up @ 0x85\n    event face_down @ 0x86\n\nEmitted when accelerometer is laying flat in the given direction.\n\n    event freefall @ 0x87\n\nEmitted when total force acting on accelerometer is much less than 1g.\n\n    event shake @ 0x8b\n\nEmitted when forces change violently a few times.\n\n    event force_2g @ 0x8c\n    event force_3g @ 0x88\n    event force_6g @ 0x89\n    event force_8g @ 0x8a\n\nEmitted when force in any direction exceeds given threshold.\n"},{"classIdentifier":513243333,"shortId":"acidity","source":"# Acidity\n\n    identifier: 0x1e9778c5\n    extends: _sensor\n    tags: C, 8bit\n    group: environment\n\nA sensor measuring water acidity, commonly called pH.\n\n## Registers\n\n    ro acidity: u4.12 pH { absolute_min=0, absolute_max=15, typical_min=2.5, typical_max=10.5, preferred_interval=5000 } @ reading\n\nThe acidity, pH, of water.\n\n    ro acidity_error?: u4.12 pH @ reading_error\n\nError on the acidity reading.\n\n    const min_acidity?: u4.12 pH @ min_reading\n\nLowest acidity that can be reported.\n\n    const max_humidity?: u4.12 pH @ max_reading\n\nHighest acidity that can be reported.\n"},{"classIdentifier":504462570,"shortId":"airpressure","source":"# Air Pressure\n\n    identifier: 0x1e117cea\n    extends: _sensor\n    group: environment\n    tags: 8bit\n    status: rc\n\nA sensor measuring air pressure of outside environment.\n\n## Registers\n\nDefault streaming interval is 1s.\n\n    ro pressure: u22.10 hPa { typical_min = 150, typical_max = 1150, preferred_interval=1000 } @ reading\n\nThe air pressure.\n\n    ro pressure_error?: u22.10 hPa @ reading_error\n\nThe real pressure is between `pressure - pressure_error` and `pressure + pressure_error`.\n\n    const min_pressure?: u22.10 hPa @ min_reading\n\nLowest air pressure that can be reported.\n\n    const max_pressure?: u22.10 hPa @ max_reading\n\nHighest air pressure that can be reported.\n"},{"classIdentifier":346844886,"shortId":"airqualityindex","source":"# Air Quality Index\n\n    identifier: 0x14ac6ed6\n    extends: _sensor\n    camel: airQualityIndex\n    group: environment\n    status: experimental\n\nThe Air Quality Index is a measure of how clean or polluted air is. From min, good quality, to high, low quality.\nThe range of AQI may vary between countries (https://en.wikipedia.org/wiki/Air_quality_index).\n\n## Registers\n\n    ro aqi_index: u16.16 AQI { preferred_interval=60000, typical_max=500 } @ reading\n\nAir quality index, typically refreshed every second.\n\n    ro aqi_index_error?: u16.16 AQI @ reading_error\n\nError on the AQI measure.\n\n    const min_aqi_index: u16.16 AQI @ min_reading\n\nMinimum AQI reading, representing a good air quality. Typically 0.\n\n    const max_aqi_index: u16.16 AQI @ max_reading\n\nMaximum AQI reading, representing a very poor air quality.\n"},{"classIdentifier":501915758,"shortId":"arcadegamepad","source":"# Arcade Gamepad\n\n    identifier: 0x1deaa06e\n    extends: _sensor\n    group: button\n    status: deprecated\n\nThis service is deprecated in favor of `gamepad` (although it is currently used by the micro:bit Arcade smart shield).\nA gamepad with direction and action buttons for one player.\nIf a device has multiple controllers, it should have multiple gamepad services, using consecutive service identifiers.\n\n## Registers\n\n    enum Button : u8 {\n        Left = 1\n        Up = 2\n        Right = 3\n        Down = 4\n        A = 5\n        B = 6\n        Menu = 7\n        Select = 8\n        Reset = 9        \n        Exit = 10\n    }\n    ro buttons @ reading {\n    repeats:\n        button: Button\n        pressure: u0.8 /\n    }\n\nIndicates which buttons are currently active (pressed).\n`pressure` should be `0xff` for digital buttons, and proportional for analog ones.\n\n    const available_buttons @ 0x180 {\n    repeats:\n        button: Button\n    }\n\nIndicates number of players supported and which buttons are present on the controller.\n\n## Events\n\n    event down @ active {\n        button: Button\n    }\n\nEmitted when button goes from inactive to active.\n\n    event up @ inactive {\n        button: Button\n    }\n\nEmitted when button goes from active to inactive.\n"},{"classIdentifier":533083654,"shortId":"arcadesound","source":"# Arcade Sound\n\n    identifier: 0x1fc63606\n    tags: SPI\n\nA sound playing device.\n\nThis is typically run over an SPI connection, not regular single-wire Jacdac.\n\n## Commands\n\n    command play @ 0x80 {\n        samples: bytes\n    }\n\nPlay samples, which are single channel, signed 16-bit little endian values.\n\n## Registers\n\n    rw sample_rate = 44100: u22.10 Hz @ 0x80\n\nGet or set playback sample rate (in samples per second).\nIf you set it, read it back, as the value may be rounded up or down.\n\n    const buffer_size: u32 B @ 0x180\n\nThe size of the internal audio buffer.\n\n    ro buffer_pending: u32 B @ 0x181\n\nHow much data is still left in the buffer to play.\nClients should not send more data than `buffer_size - buffer_pending`,\nbut can keep the `buffer_pending` as low as they want to ensure low latency\nof audio playback.\n"},{"classIdentifier":477339244,"shortId":"barcodereader","source":"# Barcode reader\n\n    identifier: 0x1c739e6c\n    status: experimental\n\nA device that reads various barcodes, like QR codes. For the web, see [BarcodeDetector](https://developer.mozilla.org/en-US/docs/Web/API/BarcodeDetector).\n\n## Registers\n\n    rw enabled: bool @ intensity\n    \nTurns on or off the detection of barcodes.\n\n    enum Format: u8 {\n        Aztec = 1\n        Code128 = 2\n        Code39 = 3\n        Code93 = 4\n        Codabar = 5\n        DataMatrix = 6\n        Ean13 = 8\n        Ean8 = 9\n        ITF = 10\n        Pdf417 = 11\n        QrCode = 12\n        UpcA = 13\n        UpcE = 14\n    }\n    const formats? @ 0x180 {\n        repeats:\n            format: Format;  \n    }\n    \nReports the list of supported barcode formats, as documented in https://developer.mozilla.org/en-US/docs/Web/API/Barcode_Detection_API.\n\n## Events\n\n    event detect @ active {\n        format: Format\n        data: string\n    }\n    \nRaised when a bar code is detected and decoded. If the reader detects multiple codes, it will issue multiple events.\nIn case of numeric barcodes, the `data` field should contain the ASCII (which is the same as UTF8 in that case) representation of the number.\n"},{"classIdentifier":449414863,"shortId":"bitradio","source":"# bit:radio\n\n    identifier: 0x1ac986cf\n    camel: bitRadio\n    status: stable\n\nSupport for sending and receiving packets using the [Bit Radio protocol](https://github.com/microsoft/pxt-common-packages/blob/master/libs/radio/docs/reference/radio.md), typically used between micro:bit devices.\n\n## Registers\n\n    rw enabled: bool @ intensity\n\nTurns on/off the radio antenna.\n\n    rw group: u8 @ 0x80\n\nGroup used to filter packets\n\n    rw transmission_power = 6: u8 { absolute_min=1, absolute_max=7 } @ 0x81\n\nAntenna power to increase or decrease range.\n\n    rw frequency_band=7: u8 { absolute_max=83 } @ 0x82\n\nChange the transmission and reception band of the radio to the given channel.\n\n## Commands\n\n    unique command send_string @ 0x80 {\n        message: string\n    }\n\nSends a string payload as a radio message, maximum 18 characters.\n\n    unique command send_number @ 0x81 {\n        value: f64\n    }\n\nSends a double precision number payload as a radio message\n\n    unique command send_value @ 0x82 {\n        value: f64\n        name: string\n    }\n\nSends a double precision number and a name payload as a radio message\n\n    unique command send_buffer @ 0x83 {\n        data: bytes\n    }\n\nSends a payload of bytes as a radio message\n\n    report string_received @ 0x90 {\n        time: u32 ms\n        device_serial_number: u32\n        rssi: i8 dB\n        padding: u8[1]\n        message: string\n    }\n\nRaised when a string packet is received\n\n    packed report number_received @ 0x91 {\n        time: u32 ms\n        device_serial_number: u32\n        rssi: i8 dB\n        padding: u8[3]\n        value: f64\n        name: string\n    }\n\nRaised when a number packet is received\n\n    report buffer_received @ 0x92 {\n        time: u32 ms\n        device_serial_number: u32\n        rssi: i8 dB\n        padding: u8[1]\n        data: bytes\n    }\n\nRaised when a buffer packet is received\n"},{"classIdentifier":536516936,"shortId":"bootloader","source":"# Bootloader\n\n    identifier: 0x1ffa9948\n    tags: C, management\n    status: stable\n\nAllows flashing (reprogramming) devices over Jacdac.\n\nThis is typically implemented by having a separate _bootloader_ mode, as opposed to _application_ mode\non the module to be flashed.\nThe bootloader mode is entered on every device reset, for about 300ms.\nThe bootloader will generally not announce itself, until it gets some command.\nOnce it gets the command, it will stay in application mode.\n\nTypically, you ask the module (in application mode) to reset, while sending broadcast\n`info` commands to all bootloaders every 100ms or so.\nAlternatively, you ask the the user to disconnect and re-connect the module, while\nbroadcasting `info` commands.\nThe second method works even if the application is damaged (eg., due to an aborted flash).\n\nWhen device is in bootloader mode, the device ID may change compared to application mode,\nby flipping the first bit in the first byte of the device identifier.\n\n## Commands\n\n    command info @ announce { }\n    report {\n        service_class: u32\n        page_size: u32 B\n        flashable_size: u32 B\n        product_identifier: u32\n    }\n\nThe `service_class` is always `0x1ffa9948`. The `product_identifier` identifies the kind of firmware\nthat \"fits\" this device.\n\n    command set_session @ 0x81 {\n        session_id: u32\n    }\n    report {\n        session_id: u32\n    }\n\nThe flashing server should generate a random id, and use this command to set it.\n\n    enum Error : u32 {\n        NoError = 0\n        PacketTooSmall = 1\n        OutOfFlashableRange = 2\n        InvalidPageOffset = 3\n        NotPageAligned = 4\n    }\n    unique command page_data @ 0x80 {\n        page_address: u32\n        page_offset: u16\n        chunk_no: u8\n        chunk_max: u8\n        session_id: u32\n        reserved0: u32\n        reserved1: u32\n        reserved2: u32\n        reserved3: u32\n        page_data: bytes { max_bytes = 208}\n    }\n    report {\n        session_id: u32\n        page_error: Error\n        page_address: u32\n    }\n\nUse to send flashing data. A physical page is split into `chunk_max + 1` chunks, where `chunk_no = 0 ... chunk_max`.\nEach chunk is stored at `page_address + page_offset`. `page_address` has to be equal in all chunks,\nand is included in response.\nOnly the last chunk causes writing to flash and elicits response.\n\nErrors not listed are also possible. Errors larger than `0xffff` indicate de-synchronization on chunk numbers.\n\nWhile this command is technically `unique`, the bootloader client will retry failed pages.\nBootloaders typically will not support reliable commands delivered over pipes.\n"},{"classIdentifier":331331532,"shortId":"brailledisplay","source":"# Braille display\n\n    identifier: 0x13bfb7cc\n    group: display\n    status: stable\n\nA Braille pattern display module. This module display [unicode braille patterns](https://www.unicode.org/charts/PDF/U2800.pdf), country specific encoding have to be implemented by the clients.\n\n## Registers\n\n    rw enabled: bool @ intensity\n    \nDetermines if the braille display is active.\n\n    lowlevel rw patterns: string @ value\n\nBraille patterns to show. Must be unicode characters between `0x2800` and `0x28ff`.\n\n    const length: u8 # @ 0x181\n\nGets the number of patterns that can be displayed.\n"},{"classIdentifier":535147631,"shortId":"bridge","source":"# Bridge\n\n    identifier: 0x1fe5b46f\n    tags: infrastructure\n    status: rc\n\nIndicates that the device acts as a bridge to the Jacdac bus.\n\n## Registers\n\n    rw enabled: bool @ intensity\n\nEnables or disables the bridge.\n"},{"classIdentifier":343122531,"shortId":"button","source":"# Button\n\n    identifier: 0x1473a263\n    extends: _sensor\n    group: button\n    tags: C, 8bit, padauk, input\n    status: stable\n\nA push-button, which returns to inactive position when not operated anymore.\n\n## Registers\n\n    ro pressure: u0.16 / @ reading\n\nIndicates the pressure state of the button, where `0` is open.\n\n    const analog?: bool @ 0x180\n\nIndicates if the button provides analog `pressure` readings.\n\n    client volatile ro pressed: bool @ 0x181\n\nDetermines if the button is pressed currently.\n\nIf the event `down` or `hold` is observed, `pressed` becomes true; if `up` is observed, `pressed` becomes false.\nThe client should initialize `pressed` to false.\n\n## Events\n\n    event down @ active\n\nEmitted when button goes from inactive to active.\n\n    event up @ inactive {\n        time: u32 ms\n    }\n\nEmitted when button goes from active to inactive. The 'time' parameter\nrecords the amount of time between the down and up events.\n\n    event hold @ 0x81 {\n         time: u32 ms\n    }\n\nEmitted when the press time is greater than 500ms, and then at least every 500ms\nas long as the button remains pressed. The 'time' parameter records the the amount of time\nthat the button has been held (since the down event).\n"},{"classIdentifier":458731991,"shortId":"buzzer","source":"# Buzzer\n\n    identifier: 0x1b57b1d7\n    camel: buzzer\n    group: sound\n    tags: C, 8bit\n    status: rc\n\nA simple buzzer.\n\n## Registers\n\n    rw volume = 1: u0.8 / @ intensity\n\nThe volume (duty cycle) of the buzzer.\n\n## Commands\n\n    lowlevel command play_tone @ 0x80 {\n        period: u16 us\n        duty: u16 us\n        duration: u16 ms\n    }\n\nPlay a PWM tone with given period and duty for given duration.\nThe duty is scaled down with `volume` register.\nTo play tone at frequency `F` Hz and volume `V` (in `0..1`) you will want\nto send `P = 1000000 / F` and `D = P * V / 2`.\n\n    client command play_note @ 0x81 {\n        frequency: u16 AudHz\n        volume: u0.16 /\n        duration: u16 ms\n    }\n\nPlay a note at the given frequency and volume.\n"},{"classIdentifier":677752265,"shortId":"capacitivebutton","source":"# Capacitive Button\n\n    identifier: 0x2865adc9\n    tags: 8bit\n    group: button\n    status: rc\n\nA configuration service for a capacitive push-button.\n\n## Registers\n\n    rw threshold: u0.16 / @ active_threshold\n    \nIndicates the threshold for ``up`` events.\n\n## Commands\n\n    command calibrate @ calibrate { }\n    report { }\n\nRequest to calibrate the capactive. When calibration is requested, the device expects that no object is touching the button. \nThe report indicates the calibration is done.\n"},{"classIdentifier":523748714,"shortId":"characterscreen","source":"# Character Screen\n\n    identifier: 0x1f37c56a\n    group: display\n    status: rc\n\nA screen that displays characters, typically a LCD/OLED character screen.\n\n## Registers\n\n    rw message: string @ value\n\nText to show. Use `\\n` to break lines.\n\n    rw brightness?: u0.16 / @ intensity\n\nBrightness of the screen. `0` means off.\n\n    enum Variant : u8 {\n        LCD = 1,\n        OLED = 2,\n        Braille = 3,\n    }\n    const variant?: Variant @ variant\n\nDescribes the type of character LED screen.\n\n    enum TextDirection : u8 {\n        LeftToRight = 1,\n        RightToLeft = 2\n    }\n    rw text_direction?: TextDirection @ 0x82\n\nSpecifies the RTL or LTR direction of the text.\n\n    const rows: u8 # @ 0x180\n\nGets the number of rows.\n\n    const columns: u8 # @ 0x181\n\nGets the number of columns.\n"},{"classIdentifier":341864092,"shortId":"cloudadapter","source":"# Cloud Adapter\n\n    identifier: 0x14606e9c\n    group: iot\n    tags: infrastructure, devicescript\n    restricted: true\n\nSupports cloud connections to upload and download data.\nNote that `f64` values following a label are not necessarily aligned.\n\n## Commands\n\n    command upload_json @ 0x80 {\n        topic: string0\n        json: string\n    }\n\nUpload a JSON-encoded message to the cloud.\n\n    command upload_binary @ 0x81 {\n        topic: string0\n        payload: bytes\n    }\n\nUpload a binary message to the cloud.\n\n## Registers\n\n    ro connected: bool @ 0x180\n\nIndicate whether we're currently connected to the cloud server.\nWhen offline, `upload` commands are queued.\n\n    ro connection_name: string @ 0x181\n\nUser-friendly name of the connection, typically includes name of the server\nand/or type of cloud service (`\"something.cloud.net (Provider IoT)\"`).\n\n## Events\n\n    event on_json @ 0x80 {\n        topic: string0\n        json: string\n    }\n\nEmitted when cloud send us a JSON message.\n\n    event on_binary @ 0x81 {\n        topic: string0\n        payload: bytes\n    }\n\nEmitted when cloud send us a binary message.\n\n    event change @ change\n\nEmitted when we connect or disconnect from the cloud.\n"},{"classIdentifier":342028028,"shortId":"cloudconfiguration","source":"# Cloud Configuration\n\n    identifier: 0x1462eefc\n    group: iot\n    status: rc\n    tags: management\n\nConnection and diagnostics information about the cloud connection.\n\n## Registers\n\n    ro server_name?: string @ 0x180\n\nSomething like `my-iot-hub.azure-devices.net` if available.\n\n    ro cloud_device_id?: string @ 0x181\n\nDevice identifier for the device in the cloud if available.\n\n    const cloud_type?: string @ 0x183\n\nCloud provider identifier.\n\n    enum ConnectionStatus: u16 {\n        Connected = 1\n        Disconnected = 2\n        Connecting = 3\n        Disconnecting = 4\n    }\n    ro connection_status: ConnectionStatus @ 0x182\n\nIndicates the status of connection. A message beyond the [0..3] range represents an HTTP error code.\n\n    rw push_period = 5000: u32 ms @ 0x80\n\nHow often to push data to the cloud.\n\n    rw push_watchdog_period: u32 ms @ 0x81\n\nIf no message is published within given period, the device resets.\nThis can be due to connectivity problems or due to the device having nothing to publish.\nForced to be at least `2 * flush_period`.\nSet to `0` to disable (default).\n\n## Commands\n\n    restricted command connect @ 0x81 { }\n\nStarts a connection to the cloud service\n\n    restricted command disconnect @ 0x82 { }\n\nStarts disconnecting from the cloud service\n\n    restricted command set_connection_string @ 0x86 {\n        connection_string: string\n    }\n\nRestricted command to override the existing connection string to cloud.\n\n## Events\n\n    event connection_status_change @ change {\n        connection_status: ConnectionStatus\n    }\n\nRaised when the connection status changes\n\n    event message_sent @ 0x80\n\nRaised when a message has been sent to the hub.\n"},{"classIdentifier":304085021,"shortId":"codalmessagebus","source":"# CODAL Message Bus\n\n    identifier: 0x121ff81d\n    camel: codalMessageBus\n    \nA service that uses the [CODAL message bus](https://lancaster-university.github.io/microbit-docs/ubit/messageBus/) to send and receive small messages.\n\nYou can find known values for `source` in [CODAL repository](https://github.com/lancaster-university/codal-core/blob/master/inc/core/CodalComponent.h)\nIn MakeCode, you can listen for custom `source`, `value` values using [control.onEvent](https://makecode.microbit.org/reference/control/on-event].\n\n## Commands\n\n    unique command send @ 0x80 {\n       source: u16\n       value: u16\n    }\n\nSend a message on the CODAL bus. If `source` is `0`, it is treated as wildcard.\n\n## Events\n\n    event message @ 0x80 {\n       source: u16\n       value: u16\n    }\n\nRaised by the server is triggered by the server. The filtering logic of which event to send over Jacdac is up to the server implementation.\n"},{"classIdentifier":372299111,"shortId":"color","source":"# Color\n\n    identifier: 0x1630d567\n    extends: _sensor\n    group: environment\n    tags: 8bit\n\nSenses RGB colors\n\n## Registers\n\n    ro color @ reading {\n        red: u0.16 /\n        green: u0.16 /\n        blue: u0.16 /\n    }\n\nDetected color in the RGB color space.\n"},{"classIdentifier":364362175,"shortId":"compass","source":"# Compass\n\nA sensor that measures the heading.\n\n    identifier: 0x15b7b9bf\n    extends: _sensor\n    status: rc\n\n## Registers\n\n    ro heading: u16.16 ° { absolute_min=0, absolute_max=359, preferred_interval=1000 } @ reading\n\nThe heading with respect to the magnetic north.\n\n    rw enabled: bool @ intensity\n\nTurn on or off the sensor. Turning on the sensor may start a calibration sequence.\n\n    ro heading_error?: u16.16 ° @ reading_error\n\nError on the heading reading\n\n## Commands\n\n    command calibrate @ calibrate { }\n    \nStarts a calibration sequence for the compass.\n"},{"classIdentifier":0,"shortId":"control","source":"# Control\n\n    identifier: 0x00000000\n    tags: C, 8bit\n    status: stable\n\nControl service is always service index `0`.\nIt handles actions common to all services on a device.\n\nNote: some of the optional features (including `flood_ping`, `mcu_temperature`, and all string registers)\nare not implemented in `8bit` version.\n\n## Commands\n\n    flags AnnounceFlags : u16 {\n        RestartCounterSteady =        0x000F,\n        RestartCounter1 =             0x0001,\n        RestartCounter2 =             0x0002,\n        RestartCounter4 =             0x0004,\n        RestartCounter8 =             0x0008,\n        StatusLightNone =             0x0000,\n        StatusLightMono =             0x0010,\n        StatusLightRgbNoFade =        0x0020,\n        StatusLightRgbFade =          0x0030,\n        SupportsACK =                 0x0100,\n        SupportsBroadcast =           0x0200,\n        SupportsFrames =              0x0400,\n        IsClient =                    0x0800,\n        SupportsReliableCommands =    0x1000,\n    }\n    command services @ announce { }\n    report {\n        flags: AnnounceFlags\n        packet_count: u8\n        reserved: u8\n    repeats:\n        service_class: u32\n    }\n\nThe `restart_counter` is computed from the `flags & RestartCounterSteady`, starts at `0x1` and increments by one until it reaches `0xf`, then it stays at `0xf`.\nIf this number ever goes down, it indicates that the device restarted.\n`service_class` indicates class identifier for each service index (service index `0` is always control, so it's\nskipped in this enumeration).\n`packet_count` indicates the number of reports sent by the current device since last announce,\nincluding the current announce packet (it is always 0 if this feature is not supported).\nThe command form can be used to induce report, which is otherwise broadcast every 500ms.\n\n    command noop @ 0x80 { }\n\nDo nothing. Always ignored. Can be used to test ACKs.\n\n    command identify? @ 0x81 { }\n\nBlink the status LED (262ms on, 262ms off, four times, with the blue LED) or otherwise draw user's attention to device with no status light.\nFor devices with status light (this can be discovered in the announce flags), the client should\nsend the sequence of status light command to generate the identify animation.\n\n    command reset? @ 0x82 { }\n\nReset device. ACK may or may not be sent.\n\n    unique command flood_ping? @ 0x83 {\n        num_responses: u32\n        start_counter: u32\n        size: u8 B\n    }\n    report {\n        counter: u32\n        dummy_payload: bytes\n    }\n\nThe device will respond `num_responses` times, as fast as it can, setting the `counter` field in the report\nto `start_counter`, then `start_counter + 1`, ..., and finally `start_counter + num_responses - 1`.\nThe `dummy_payload` is `size` bytes long and contains bytes `0, 1, 2, ...`.\n\n    command set_status_light @ 0x84 {\n        to_red: u8\n        to_green: u8\n        to_blue: u8\n        speed: u8\n    }\n\nInitiates a color transition of the status light from its current color to the one specified.\nThe transition will complete in about `512 / speed` frames\n(each frame is currently 100ms, so speed of `51` is about 1 second and `26` 0.5 second).\nAs a special case, if speed is `0` the transition is immediate.\nIf MCU is not capable of executing transitions, it can consider `speed` to be always `0`.\nIf a monochrome LEDs is fitted, the average value of `red`, `green`, `blue` is used.\nIf intensity of a monochrome LED cannot be controlled, any value larger than `0` should be considered\non, and `0` (for all three channels) should be considered off.\n\n    command proxy? @ 0x85 {}\n\nForce client device into proxy mode.\n\n    command reliable_commands? @ 0x86 {\n        seed: u32\n    }\n    report {\n        commands: pipe\n    }\n    pipe command wrapped_command {\n        service_size: u8\n        service_index: u8\n        service_command: u16\n        payload: bytes\n    }\n\nThis opens a pipe to the device to provide an alternative, reliable transport of actions\n(and possibly other commands).\nThe commands are wrapped as pipe data packets.\nMultiple invocations of this command with the same `seed` are dropped\n(and thus the command is not `unique`); otherwise `seed` carries no meaning\nand should be set to a random value by the client.\nNote that while the commands sends this way are delivered exactly once, the\nresponses might get lost.\n\n    command standby? @ 0x87 {\n        duration: u32 ms\n    }\n\nAttempt to put devices into lowest power sleep mode for a specified time - most likely involving a full reset on wake-up.\n\n## Registers\n\n    rw internal reset_in? : u32 us @ 0x80\n\nWhen set to value other than `0`, it asks the device to reset after specified number of microseconds.\nThis is typically used to implement watchdog functionality, where a brain device sets `reset_in` to\nsay 1.6s every 0.5s.\n\n    const device_description?: string @ 0x180\n\nIdentifies the type of hardware (eg., ACME Corp. Servo X-42 Rev C)\n\n    const product_identifier? : u32 { absolute_min = 0x3000_0000, absolute_max = 0x3fff_ffff } @ 0x181\n\nA numeric code for the string above; used to identify firmware images and devices.\n\n    const bootloader_product_identifier?: u32 { absolute_min = 0x3000_0000, absolute_max = 0x3fff_ffff } @ 0x184\n\nTypically the same as `product_identifier` unless device was flashed by hand; the bootloader will respond to that code.\n\n    const firmware_version?: string @ 0x185\n\nA string describing firmware version; typically semver.\n\n    ro volatile mcu_temperature?: i16 °C { preferred_interval=60000, typical_min = -10, typical_max = 150 } @ 0x182\n\nMCU temperature in degrees Celsius (approximate).\n\n    ro volatile uptime?: u64 us { preferred_interval=60000 } @ 0x186\n\nNumber of microseconds since boot.\n"},{"classIdentifier":468029703,"shortId":"dashboard","source":"# Dashboard\n\n    identifier: 0x1be59107\n    tags: infrastructure\n    status: stable\n\nDevice that interacts, configure or inspects with the services on the bus. While a dashboard is on the bus, heuristics like device reset should be disabled.\n"},{"classIdentifier":420661422,"shortId":"dccurrentmeasurement","source":"# DC Current Measurement\n\n    identifier: 0x1912c8ae\n    status: experimental\n    extends: _sensor\n    camel: dcCurrentMeasurement\n    \nA service that reports a current measurement.\n\n## Registers\n\n    const measurement_name: string @ 0x182\nA string containing the net name that is being measured e.g. `POWER_DUT` or a reference e.g. `DIFF_DEV1_DEV2`. These constants can be used to identify a measurement from client code.\n\n    ro measurement: f64 A @ reading\n    \nThe current measurement.\n\n    ro measurement_error?: f64 A @ reading_error\n\nAbsolute error on the reading value.\n\n    const min_measurement?: f64 A @ min_reading\n\nMinimum measurable current\n\n    const max_measurement?: f64 A @ max_reading\n\nMaximum measurable current\n"},{"classIdentifier":372485145,"shortId":"dcvoltagemeasurement","source":"# DC Voltage Measurement\n\n    identifier: 0x1633ac19\n    status: experimental\n    extends: _sensor\n    camel: dcVoltageMeasurement\n    \nA service that reports a voltage measurement.\n\n## Registers\n\n    enum VoltageMeasurementType:u8 {\n        Absolute = 0,\n        Differential = 1\n    }\n\n    const measurement_type: VoltageMeasurementType @ 0x181\nThe type of measurement that is taking place. Absolute results are measured with respect to ground, whereas differential results are measured against another signal that is not ground.\n\n    const measurement_name: string @ 0x182\nA string containing the net name that is being measured e.g. `POWER_DUT` or a reference e.g. `DIFF_DEV1_DEV2`. These constants can be used to identify a measurement from client code.\n\n    ro measurement: f64 V @ reading\n    \nThe voltage measurement.\n\n    ro measurement_error?: f64 V @ reading_error\n\nAbsolute error on the reading value.\n\n    const min_measurement?: f64 V @ min_reading\n\nMinimum measurable current\n\n    const max_measurement?: f64 V @ max_reading\n\nMaximum measurable current\n"},{"classIdentifier":295074157,"shortId":"devicescriptcondition","source":"# DeviceScript Condition\n\n    identifier: 0x1196796d\n    tags: infrastructure, devicescript\n    restricted: true\n    status: deprecated\n\nConditions are synthetic services used to synchronize threads of executions of a DeviceScript VM.\n**This is no longer used**.\n\n## Commands\n\n    command signal @ 0x80 {}\n\nTriggers a `signalled` event.\n\n## Events\n\n    event signalled @ change {}\n\nTriggered by `signal` command.\n"},{"classIdentifier":358308672,"shortId":"devicescriptdebugger","source":"# DeviceScript Debugger\n\n    identifier: 0x155b5b40\n    tags: management, devicescript\n    restricted: true\n    camel: devsDbg\n\nAllows for inspecting and affecting the state of a running DeviceScript program.\n\n## Commands\n\n    enum ValueTag : u8 {\n        Number = 0x01         // v0:v1 - f64\n        Special = 0x02        // v0 - ValueSpecial\n        Fiber = 0x03          // v0 - FiberHandle\n        BuiltinObject = 0x05  // v0 - DEVS_BUILTIN_OBJECT_*\n\n        Exotic = 0x06\n        Unhandled = 0x07\n\n        // index in v0\n        ImgBuffer = 0x20\n        ImgStringBuiltin = 0x21\n        ImgStringAscii = 0x22\n        ImgStringUTF8 = 0x23\n        ImgRole = 0x30          // v1 has number of attached properties\n        ImgFunction = 0x31      // never returned, can be used in read_*\n        ImgRoleMember = 0x32    // v0 has role in low DEVS_ROLE_BITS (15) and offset into embedded specs in the high bits\n\n        // pointer in v0\n        // v1 has number of properties (for map) or indexed length (otherwise)\n        //   if highest bit of v1 is set, named properties are also present\n        ObjArray = 0x51\n        ObjMap = 0x52\n        ObjBuffer = 0x53\n        ObjString = 0x54\n        ObjStackFrame = 0x55\n        ObjPacket = 0x56\n        ObjBoundFunction = 0x57\n        ObjOpaque = 0x58\n\n        ObjAny = 0x50    // never returned, can be used in read_*\n        ObjMask = 0xF0\n\n        User1 = 0xF1\n        User2 = 0xF2\n        User3 = 0xF3\n        User4 = 0xF4\n    }\n\n    enum ValueSpecial : u8 {\n        Undefined = 0\n        True = 1\n        False = 2\n        Null = 3\n\n        // These can be used in read_* and are never returned\n        Globals = 100\n        CurrentException = 101\n    }\n\n    type FunIdx : u16 {\n        None = 0\n        Main = 49999\n        FirstBuiltIn = 50000\n    }\n\n    type FiberHandle : u32 {\n        None = 0\n    }\n    type ProgramCounter : u32\n\n    type ObjStackFrame : u32 {\n        Null = 0\n    }\n\n    // either ObjString or one of ImgString*\n    type String : u32 {\n        StaticIndicatorMask = 0x8000_0001\n        StaticTagMask = 0x7f00_0000\n        StaticIndexMask = 0x00ff_fffe\n\n        Unhandled = 0\n    }\n\n    command read_fibers @ 0x80 {\n        results: pipe\n    }\n    pipe report fiber {\n        handle: FiberHandle\n        initial_fn: FunIdx\n        curr_fn: FunIdx\n    }\n\nList the currently running fibers (threads).\n\n    command read_stack @ 0x81 {\n        results: pipe\n        fiber_handle: FiberHandle\n    }\n    pipe report stackframe {\n        self: ObjStackFrame\n        pc: ProgramCounter\n        closure: ObjStackFrame\n        fn_idx: FunIdx\n        reserved: u16\n    }\n\nList stack frames in a fiber.\n\n    command read_indexed_values @ 0x82 {\n        results: pipe\n        v0: u32\n        tag: ValueTag\n        reserved: u8\n        start: u16\n        length: u16\n    }\n    pipe report value {\n        v0: u32\n        v1: u32\n        fn_idx: FunIdx\n        tag: ValueTag\n    }\n\nRead variable slots in a stack frame, elements of an array, etc.\n\n    command read_named_values @ 0x83 {\n        results: pipe\n        v0: u32\n        tag: ValueTag\n    }\n    pipe report key_value {\n        key: String\n        v0: u32\n        v1: u32\n        fn_idx: FunIdx\n        tag: ValueTag\n    }\n\nRead variable slots in an object.\n\n    command read_value @ 0x84 {\n        v0: u32\n        tag: ValueTag\n    }\n    report {\n        v0: u32\n        v1: u32\n        fn_idx: FunIdx\n        tag: ValueTag\n    }\n\nRead a specific value.\n\n    command read_bytes @ 0x85 {\n        results: pipe\n        v0: u32\n        tag: ValueTag\n        reserved: u8\n        start: u16\n        length: u16\n    }\n    pipe report bytes_value {\n        data: bytes\n    }\n\nRead bytes of a string (UTF8) or buffer value.\n\n    command set_breakpoints @ 0x90 {\n    repeats:\n        break_pc: ProgramCounter\n    }\n\nSet breakpoint(s) at a location(s).\n\n    command clear_breakpoints @ 0x91 {\n    repeats:\n        break_pc: ProgramCounter\n    }\n\nClear breakpoint(s) at a location(s).\n\n    command clear_all_breakpoints @ 0x92 {}\n\nClear all breakpoints.\n\n    command resume @ 0x93 {}\n\nResume program execution after a breakpoint was hit.\n\n    command halt @ 0x94 {}\n\nTry suspending current program. Client needs to wait for `suspended` event afterwards.\n\n    command restart_and_halt @ 0x95 {}\n\nRun the program from the beginning and halt on first instruction.\n\n    flags StepFlags: u16 {\n        StepOut = 0x0001 // also stop when the stackframe returns\n        StepIn = 0x0002  // also stop when the stackframe calls something\n        Throw = 0x0004   // also stop on throw which would pop the stackframe\n    }\n    command step @ 0x96 {\n        stackframe: ObjStackFrame\n        flags: StepFlags\n        reserved: u16\n    repeats:\n        break_pc: ProgramCounter\n    }\n\nSet breakpoints that only trigger in the specified stackframe and resume program.\nThe breakpoints are cleared automatically on next suspension (regardless of the reason).\n\n## Registers\n\n    rw enabled: bool @ intensity\n\nTurn on/off the debugger interface.\n\n    rw break_at_unhandled_exn: bool @ 0x80\n\nWheather to place breakpoint at unhandled exception.\n\n    rw break_at_handled_exn: bool @ 0x81\n\nWheather to place breakpoint at handled exception.\n\n    ro is_suspended: bool @ 0x180\n\nIndicates if the program is currently suspended.\nMost commands can only be executed when the program is suspended.\n\n## Events\n\n    enum SuspensionType : u8 {\n        None = 0\n        Breakpoint = 1\n        UnhandledException = 2\n        HandledException = 3\n        Halt = 4\n        Panic = 5\n        Restart = 6\n        DebuggerStmt = 7\n        Step = 8\n    }\n\n    event suspended @ 0x80 {\n        fiber: FiberHandle\n        type: SuspensionType\n    }\n\nEmitted when the program hits a breakpoint or similar event in the specified fiber.\n"},{"classIdentifier":288680491,"shortId":"devicescriptmanager","source":"# DeviceScript Manager\n\n    identifier: 0x1134ea2b\n    tags: management, devicescript\n    restricted: true\n\nAllows for deployment and control over DeviceScript virtual machine.\n\nPrograms start automatically after device restart or uploading of new program.\nYou can stop programs until next reset by setting the `running` and `autostart` registers to `false`.\n\n## Commands\n\n    unique command deploy_bytecode @ 0x80 {\n        bytecode_size: u32 B\n    }\n    report {\n        bytecode_port: pipe_port\n    }\n\nOpen pipe for streaming in the bytecode of the program. The size of the bytecode has to be declared upfront.\nTo clear the program, use `bytecode_size == 0`.\nThe bytecode is streamed over regular pipe data packets.\nThe bytecode shall be fully written into flash upon closing the pipe.\nIf `autostart` is true, the program will start after being deployed.\nThe data payloads, including the last one, should have a size that is a multiple of 32 bytes.\nThus, the initial bytecode_size also needs to be a multiple of 32.\n\n    command read_bytecode @ 0x81 {\n        bytecode: pipe\n    }\n    pipe report bytecode {\n        data: bytes\n    }\n\nGet the current bytecode deployed on device.\n\n\n## Registers\n\n    rw running: bool @ 0x80\n\nIndicates if the program is currently running.\nTo restart the program, stop it (write `0`), read back the register to make sure it's stopped,\nstart it, and read back.\n\n    rw autostart: bool @ 0x81\n\nIndicates wheather the program should be re-started upon `reboot()` or `panic()`.\nDefaults to `true`.\n\n    ro program_size: u32 @ 0x180\n\nThe size of current program.\n\n    ro program_hash: u32 @ 0x181\n\nReturn FNV1A hash of the current bytecode.\n\n    ro program_sha256: bytes { max_bytes = 32 } @ 0x182\n\nReturn 32-byte long SHA-256 hash of the current bytecode.\n\n    const runtime_version? @ 0x183 {\n        patch: u16\n        minor: u8\n        major: u8\n    }\n\nReturns the runtime version number compatible with [Semver](https://semver.org/).\nWhen read as 32-bit little endian integer a version `7.15.500` would be `0x07_0F_01F4`.\n\n    ro program_name: string @ 0x184\n\nThe name of currently running program. The compiler takes is from `package.json`.\n\n    ro program_version: string @ 0x185\n\nThe version number of currently running program. The compiler takes is from `package.json`\nand `git`.\n\n\n## Events\n\nWhen program is running, `status_code == Ready`.\nWhen there is a valid program, but it is not running, `status_code == Sleeping`.\nWhen there is no valid program, `status_code == WaitingForInput`.\n\n    event program_panic @ 0x80 {\n        panic_code: u32\n        program_counter: u32\n    }\n\nEmitted when the program calls `panic(panic_code)` or `reboot()` (`panic_code == 0` in that case).\nThe byte offset in byte code of the call is given in `program_counter`.\nThe program will restart immediately when `panic_code == 0` or in a few seconds otherwise.\n\n    event program_change @ change\n\nEmitted after bytecode of the program has changed.\n"},{"classIdentifier":337275786,"shortId":"distance","source":"# Distance\n\nA sensor that determines the distance of an object without any physical contact involved.\n\n    identifier:  0x141a6b8a\n    extends: _sensor\n    tags: 8bit\n    status: stable\n\n## Registers\n\n    ro distance: u16.16 m { typical_min=0.02, typical_max=4 } @ reading\n\nCurrent distance from the object\n\n    ro distance_error?: u16.16 m @ reading_error\n\nAbsolute error on the reading value.\n\n    const min_range?: u16.16 m @ min_reading\n\nMinimum measurable distance\n\n    const max_range?: u16.16 m @ max_reading\n\nMaximum measurable distance\n\n    enum Variant: u8 {\n        Ultrasonic = 1,\n        Infrared = 2,\n        LiDAR = 3,\n        Laser = 4,\n    }\n    const variant?: Variant @ variant\n\nDetermines the type of sensor used.\n"},{"classIdentifier":298814469,"shortId":"dmx","source":"#  DMX\n\n    identifier: 0x11cf8c05\n    camel: dmx\n    status: experimental\n\nA service that can send DMX512-A packets with limited size. This service is designed to allow tinkering with a few DMX devices, but only allows 235 channels. More about DMX at https://en.wikipedia.org/wiki/DMX512.\n\n## Registers\n\n    rw enabled: bool @ intensity\n\nDetermines if the DMX bridge is active.\n\n## Commands\n\n    unique command send @ 0x80 {\n        channels: bytes\n    }\n\nSend a DMX packet, up to 236bytes long, including the start code.\n"},{"classIdentifier":286070091,"shortId":"dotmatrix","source":"# Dot Matrix\n\n    identifier: 0x110d154b\n    group: display\n    status: rc\n\nA rectangular dot matrix display, made of monochrome LEDs or Braille pins.\n\n## Registers\n\n    rw dots : bytes @ value\n\nThe state of the screen where dot on/off state is\nstored as a bit, column by column. The column should be byte aligned.\n\nFor example, if the display has no more than 8 rows in each column, then each byte contains bits corresponding\nto a single column. Least-significant bit is on top.\nIf display has 10 rows, then each column is represented by two bytes.\nThe top-most 8 rows sit in the first byte (with the least significant bit being on top),\nand the remainign 2 row sit in the second byte.\n\nThe following C expression can be used to check if a given `column, row` coordinate is set:\n`dots[column * column_size + (row >> 3)] & (1 << (row & 7))`, where\n`column_size` is `(number_of_rows + 7) >> 3` (note that if number of rows is 8 or less then `column_size` is `1`),\nand `dots` is of `uint8_t*` type.\n\nThe size of this register is `number_of_columns * column_size` bytes.\n\n    rw brightness?: u0.8 / @ intensity\n\nReads the general brightness of the display, brightness for LEDs. `0` when the screen is off.\n\n    const rows: u16 # @ 0x181\n\nNumber of rows on the screen\n\n    const columns: u16 # @ 0x182\n\nNumber of columns on the screen\n\n    enum Variant: u8 {\n        LED = 1,\n        Braille = 2,\n    }\n    const variant?: Variant @ variant\n\nDescribes the type of matrix used.\n"},{"classIdentifier":355063095,"shortId":"dualmotors","source":"# Dual Motors\n\n    identifier: 0x1529d537\n    group: motor\n\nA synchronized pair of motors.\n\n## Registers\n\n    rw speed @ value {\n        left: i1.15 /\n        right: i1.15 /\n    }\n\nRelative speed of the motors. Use positive/negative values to run the motor forwards and backwards.\nA speed of ``0`` while ``enabled`` acts as brake.\n\n    rw enabled: bool @ intensity\n\nTurn the power to the motors on/off.\n\n    const load_torque?: u16.16 kg/cm @ 0x180\n\nTorque required to produce the rated power of an each electrical motor at load speed.\n\n    const load_rotation_speed?: u16.16 rpm @ 0x181\n\nRevolutions per minute of the motor under full load.\n\n    const reversible?: bool @ 0x182\n\nIndicates if the motors can run backwards.\n\n"},{"classIdentifier":379362758,"shortId":"eco2","source":"# Equivalent CO₂\n\nMeasures equivalent CO₂ levels.\n\n    identifier: 0x169c9dc6\n    extends: _sensor\n    camel: eCO2\n    group: environment\n    tags: 8bit\n    status: rc\n\n## Registers\n\n    ro e_CO2: u22.10 ppm { typical_min=400, typical_max=8192, preferred_interval=1000 }  @ reading\n\nEquivalent CO₂ (eCO₂) readings.\n\n    ro e_CO2_error?: u22.10 ppm @ reading_error\n\nError on the reading value.\n\n    const min_e_CO2: u22.10 ppm @ min_reading\n\nMinimum measurable value\n\n    const max_e_CO2: u22.10 ppm @ max_reading\n\nMinimum measurable value\n\n    enum Variant: u8 {\n        VOC = 1,\n        NDIR = 2\n    }\n    const variant?: Variant @ variant\n\nType of physical sensor and capabilities.\n"},{"classIdentifier":524797638,"shortId":"flex","source":"# Flex\n\n    identifier: 0x1f47c6c6\n    extends: _sensor\n    group: sensor\n    tags: C, 8bit\n    status: rc\n\nA bending or deflection sensor.\n\n## Registers\n\n    ro bending: i1.15 / @ reading\n\nA measure of the bending.\n\n    const length?: u16 mm @ 0x180\n\nLength of the flex sensor"},{"classIdentifier":277836886,"shortId":"gamepad","source":"# Gamepad\n\n    identifier: 0x108f7456\n    extends: _sensor\n    group: button\n    tags: 8bit, padauk\n    status: rc\n\nA two axis directional gamepad with optional buttons.\n\n## Registers\n\n    flags Buttons : u32 {\n        Left      = 0x0000_0001\n        Up        = 0x0000_0002\n        Right     = 0x0000_0004\n        Down      = 0x0000_0008\n        A         = 0x0000_0010\n        B         = 0x0000_0020\n        Menu      = 0x0000_0040\n        Select    = 0x0000_0080\n        Reset     = 0x0000_0100\n        Exit      = 0x0000_0200\n        X         = 0x0000_0400\n        Y         = 0x0000_0800\n    }\n    ro direction @ reading {\n        buttons: Buttons\n        x: i1.15 /\n        y: i1.15 /\n    }\n\nIf the gamepad is analog, the directional buttons should be \"simulated\", based on gamepad position\n(`Left` is `{ x = -1, y = 0 }`, `Up` is `{ x = 0, y = -1}`).\nIf the gamepad is digital, then each direction will read as either `-1`, `0`, or `1` (in fixed representation).\nThe primary button on the gamepad is `A`.\n\n    enum Variant : u8 {\n        Thumb = 1\n        ArcadeBall = 2\n        ArcadeStick = 3\n        Gamepad = 4\n    }\n    const variant?: Variant @ variant\n\nThe type of physical gamepad.\n\n    const buttons_available: Buttons @ 0x180\n\nIndicates a bitmask of the buttons that are mounted on the gamepad.\nIf the `Left`/`Up`/`Right`/`Down` buttons are marked as available here, the gamepad is digital.\nEven when marked as not available, they will still be simulated based on the analog gamepad.\n\n## Events\n\n    event buttons_changed @ change {\n        buttons: Buttons\n    }\n\nEmitted whenever the state of buttons changes.\n"},{"classIdentifier":282614377,"shortId":"gpio","source":"# GPIO\n\n    identifier: 0x10d85a69\n    tags: io\n    camel: GPIO\n    extends: _sensor\n\nAccess to General Purpose Input/Output (GPIO) pins on a board.\nThe pins are indexed `0 ... num_pins-1`.\nThe indexing does not correspond to hardware pin names, nor labels on the board (see `get_pin_info` command for that),\nand should **not** be exposed to the user.\n\n## Registers\n\n    ro state @ reading {\n        digital_values: bytes\n    }\n\nFor every pin set to `Input*` the corresponding **bit** in `digital_values` will be `1` if and only if\nthe pin is high.\nFor other pins, the bit is `0`.\nThis is normally streamed at low-ish speed, but it's also automatically reported whenever\na digital input pin changes value (throttled to ~100Hz).\nThe analog values can be read with the `ADC` service.\n\n    ro num_pins: u8 # { absolute_max=128 } @ 0x180\n\nNumber of pins that can be operated through this service.\n\n\n## Commands\n\n    enum Mode : u8 {\n        Off            = 0x00\n        OffPullUp      = 0x10\n        OffPullDown    = 0x20\n        Input          = 0x01\n        InputPullUp    = 0x11\n        InputPullDown  = 0x21\n        Output         = 0x02\n        OutputHigh     = 0x12\n        OutputLow      = 0x22\n        AnalogIn       = 0x03\n        Alternative    = 0x04\n        BaseModeMask   = 0x0F\n    }\n    command configure @ 0x80 {\n    repeats:\n        pin: u8\n        mode: Mode\n    }\n\nConfigure (including setting the value) zero or more pins.\n`Alternative` settings means the pin is controlled by other service (SPI, I2C, UART, PWM, etc.).\n\n    flags Capabilities : u16 {\n        PullUp     = 0x0001\n        PullDown   = 0x0002\n        Input      = 0x0004\n        Output     = 0x0008\n        Analog     = 0x0010\n    }\n    command pin_info @ 0x81 {\n        pin: u8\n    }\n    report {\n        pin: u8\n        hw_pin: u8\n        capabilities: Capabilities\n        mode: Mode\n        label: string\n    }\n\nReport capabilities and name of a pin.\n\n    command pin_by_label @ 0x83 {\n        label: string\n    }\n    report {\n        pin: u8\n        hw_pin: u8\n        capabilities: Capabilities\n        mode: Mode\n        label: string\n    }\n\nThis responds with `pin_info` report.\n\n    command pin_by_hw_pin @ 0x84 {\n        hw_pin: u8\n    }\n    report {\n        pin: u8\n        hw_pin: u8\n        capabilities: Capabilities\n        mode: Mode\n        label: string\n    }\n\nThis responds with `pin_info` report.\n"},{"classIdentifier":505087730,"shortId":"gyroscope","source":"# Gyroscope\n\n    identifier: 0x1e1b06f2\n    extends: _sensor\n    group: movement\n    status: rc\n\nA 3-axis gyroscope.\n\n## Registers\n\n    ro rotation_rates @ reading {\n        x: i12.20 °/s\n        y: i12.20 °/s\n        z: i12.20 °/s\n    }\n\nIndicates the current rates acting on gyroscope.\n\n    ro rotation_rates_error?: u12.20 °/s @ reading_error\n\nError on the reading value.\n\n    rw max_rate?: u12.20 °/s @ reading_range\n\nConfigures the range of rotation rates.\nThe value will be \"rounded up\" to one of `max_rates_supported`.\n\n    const max_rates_supported? @ supported_ranges {\n    repeats:\n        max_rate: u12.20 °/s\n    }\n\nLists values supported for writing `max_rate`.\n"},{"classIdentifier":376204740,"shortId":"heartrate","source":"#  Heart Rate\n\nA sensor approximating the heart rate. \n\n    identifier: 0x166c6dc4\n    extends: _sensor\n    group: biometric\n    tags: 8bit\n    status: experimental\n\n**Jacdac is NOT suitable for medical devices and should NOT be used in any kind of device to diagnose or treat any medical conditions.**\n\n## Registers\n\n    ro heart_rate: u16.16 bpm { typical_min=30, typical_max=200, preferred_interval=1000 } @ reading\n\nThe estimated heart rate.\n\n    ro heart_rate_error?: u16.16 bpm @ reading_error\n\nThe estimated error on the reported sensor data.\n\n    enum Variant: u8 {\n        Finger = 1\n        Chest = 2\n        Wrist = 3\n        Pump = 4\n        WebCam = 5\n    }\n    const variant?: Variant @ variant\n\nThe type of physical sensor\n"},{"classIdentifier":437330261,"shortId":"hidjoystick","source":"# HID Joystick\n\n    identifier: 0x1a112155\n    status: experimental\n    camel: hidJoystick\n\nControls a HID joystick.\n\n## Registers\n\n    const button_count: u8 @ 0x180\n\nNumber of button report supported\n\n    const buttons_analog: u32 @ 0x181\n\nA bitset that indicates which button is analog.\n\n    const axis_count: u8 @ 0x182\n\nNumber of analog input supported\n\n## Commands\n\n    unique command set_buttons @ 0x80 {\n    repeats: \n        pressure: u0.8 /\n    }\n\nSets the up/down button state, one byte per button, supports analog buttons. For digital buttons, use `0` for released, `1` for pressed.\n\n    unique command set_axis @ 0x81 {\n    repeats:\n        position: i1.15 /\n    }\n\nSets the state of analog inputs."},{"classIdentifier":414210922,"shortId":"hidkeyboard","source":"# HID Keyboard\n\n    identifier: 0x18b05b6a\n    camel: hidKeyboard\n    tags: 8bit\n    status: stable\n\nControl a HID keyboard.\n\nThe codes for the key (selectors) is defined in the [HID Keyboard\nspecification](https://usb.org/sites/default/files/hut1_21.pdf), chapter 10 Keyboard/Keypad Page, page 81.\nModifiers are in page 87.\n\nThe device keeps tracks of the key state and is able to clear it all with the clear command.\n\n## Commands\n\n    enum Selector : u16 {\n        None = 0x00\n        ErrorRollOver = 0x01\n        PostFail = 0x02\n        ErrorUndefined = 0x03\n        A = 0x04\n        B = 0x05\n        C = 0x06\n        D = 0x07\n        E = 0x08\n        F = 0x09\n        G = 0x0A\n        H = 0x0B\n        I = 0x0C\n        J = 0x0D\n        K = 0x0E\n        L = 0x0F\n        M = 0x10\n        N = 0x11\n        O = 0x12\n        P = 0x13\n        Q = 0x14\n        R = 0x15\n        S = 0x16\n        T = 0x17\n        U = 0x18\n        V = 0x19\n        W = 0x1A\n        X = 0x1B\n        Y = 0x1C\n        Z = 0x1D\n        _1 = 0x1E\n        _2 = 0x1F\n        _3 = 0x20\n        _4 = 0x21\n        _5 = 0x22\n        _6 = 0x23\n        _7 = 0x24\n        _8 = 0x25\n        _9 = 0x26\n        _0 = 0x27\n        Return = 0x28\n        Escape = 0x29\n        Backspace = 0x2A\n        Tab = 0x2B\n        Spacebar = 0x2C\n        Minus = 0x2D\n        Equals = 0x2E\n        LeftSquareBracket = 0x2F\n        RightSquareBracket = 0x30\n        Backslash = 0x31\n        NonUsHash = 0x32\n        Semicolon = 0x33\n        Quote = 0x34\n        GraveAccent = 0x35\n        Comma = 0x36\n        Period = 0x37\n        Slash = 0x38\n        CapsLock = 0x39\n        F1 = 0x3A\n        F2 = 0x3B\n        F3 = 0x3C\n        F4 = 0x3D\n        F5 = 0x3E\n        F6 = 0x3F\n        F7 = 0x40\n        F8 = 0x41\n        F9 = 0x42\n        F10 = 0x43\n        F11 = 0x44\n        F12 = 0x45\n        PrintScreen = 0x46\n        ScrollLock = 0x47\n        Pause = 0x48\n        Insert = 0x49\n        Home = 0x4A\n        PageUp = 0x4B\n        Delete = 0x4C\n        End = 0x4D\n        PageDown = 0x4E\n        RightArrow = 0x4F\n        LeftArrow = 0x50\n        DownArrow = 0x51\n        UpArrow = 0x52\n        KeypadNumLock = 0x53\n        KeypadDivide = 0x54\n        KeypadMultiply = 0x55\n        KeypadAdd = 0x56\n        KeypadSubtrace = 0x57\n        KeypadReturn = 0x58\n        Keypad1 = 0x59\n        Keypad2 = 0x5A\n        Keypad3 = 0x5B\n        Keypad4 = 0x5C\n        Keypad5 = 0x5D\n        Keypad6 = 0x5E\n        Keypad7 = 0x5F\n        Keypad8 = 0x60\n        Keypad9 = 0x61\n        Keypad0 = 0x62\n        KeypadDecimalPoint = 0x63\n        NonUsBackslash = 0x64\n        Application = 0x65\n        Power = 0x66\n        KeypadEquals = 0x67\n        F13 = 0x68\n        F14 = 0x69\n        F15 = 0x6A\n        F16 = 0x6B\n        F17 = 0x6C\n        F18 = 0x6D\n        F19 = 0x6E\n        F20 = 0x6F\n        F21 = 0x70\n        F22 = 0x71\n        F23 = 0x72\n        F24 = 0x73\n        Execute = 0x74\n        Help = 0x75\n        Menu = 0x76\n        Select = 0x77\n        Stop = 0x78\n        Again = 0x79\n        Undo = 0x7A\n        Cut = 0x7B\n        Copy = 0x7C\n        Paste = 0x7D\n        Find = 0x7E\n        Mute = 0x7F\n        VolumeUp = 0x80\n        VolumeDown = 0x81\n    }\n\n    flags Modifiers : u8 {\n        None = 0x0\n        LeftControl = 0x01\n        LeftShift = 0x02\n        LeftAlt = 0x04\n        LeftGUI = 0x08\n        RightControl = 0x10\n        RightShift = 0x20\n        RightAlt = 0x40\n        RightGUI = 0x80\n    }\n    enum Action : u8 {\n        Press = 0\n        Up = 1\n        Down = 2\n    }\n    lowlevel unique command key @ 0x80 {\n    repeats:\n        selector: Selector\n        modifiers: Modifiers\n        action: Action\n    }\n\nPresses a key or a sequence of keys down.\n\n    command clear @ 0x81 {}\n\nClears all pressed keys.\n"},{"classIdentifier":411425820,"shortId":"hidmouse","source":"# HID Mouse\n\n    identifier: 0x1885dc1c\n    camel: hidMouse\n    tags: 8bit\n    status: stable\n\nControls a HID mouse.\n\n## Commands\n\n    flags Button : u16 {\n        Left = 0x01\n        Right = 0x02\n        Middle = 0x04\n    }\n    enum ButtonEvent : u8 {\n        Up = 0x01\n        Down = 0x02\n        Click = 0x03\n        DoubleClick = 0x04\n    }\n    unique command set_button @ 0x80 {\n        buttons: Button\n        ev: ButtonEvent\n    }\n\nSets the up/down state of one or more buttons.\nA `Click` is the same as `Down` followed by `Up` after 100ms.\nA `DoubleClick` is two clicks with `150ms` gap between them (that is, `100ms` first click, `150ms` gap, `100ms` second click).\n\n    unique command move @ 0x81 {\n      dx: i16 #\n      dy: i16 #\n      time: u16 ms\n    }\n\nMoves the mouse by the distance specified.\nIf the time is positive, it specifies how long to make the move.\n\n    unique command wheel @ 0x82 {\n        dy: i16 #\n        time: u16 ms\n    }\n\nTurns the wheel up or down. Positive if scrolling up.\nIf the time is positive, it specifies how long to make the move.\n"},{"classIdentifier":382210232,"shortId":"humidity","source":"# Humidity\n\n    identifier: 0x16c810b8\n    extends: _sensor\n    tags: C, 8bit\n    group: environment\n    status: stable\n\nA sensor measuring humidity of outside environment.\n\n## Registers\n\n    ro humidity: u22.10 %RH { preferred_interval=5000 } @ reading\n\nThe relative humidity in percentage of full water saturation.\n\n    ro humidity_error?: u22.10 %RH @ reading_error\n\nThe real humidity is between `humidity - humidity_error` and `humidity + humidity_error`.\n\n    const min_humidity: u22.10 %RH @ min_reading\n\nLowest humidity that can be reported.\n\n    const max_humidity: u22.10 %RH @ max_reading\n\nHighest humidity that can be reported.\n"},{"classIdentifier":471386691,"shortId":"i2c","source":"# I2C\n\n    identifier: 0x1c18ca43\n    tags: io\n    camel: I2C\n\nInter-Integrated Circuit (I2C, I²C, IIC) serial communication bus lets you communicate with\nmany sensors and actuators.\n\n## Registers\n\n    ro ok: bool @ 0x180\n\nIndicates whether the I2C is working.\n\n## Commands\n\n    enum Status : u8 {\n        OK = 0\n        NAckAddr = 1\n        NAckData = 2\n        NoI2C = 3\n    }\n    unique command transaction @ 0x80 {\n        address: u8\n        num_read: u8 B\n        write_buf: bytes\n    }\n    report {\n        status: Status\n        read_buf: bytes\n    }\n\n`address` is 7-bit.\n`num_read` can be 0 if nothing needs to be read.\nThe `write_buf` includes the register address if required (first one or two bytes).\n"},{"classIdentifier":510577394,"shortId":"illuminance","source":"# Illuminance\n\n    identifier: 0x1e6ecaf2\n    extends: _sensor\n    group: environment\n    tags: 8bit, padauk\n    status: rc\n\nDetects the amount of light falling onto a given surface area.\n\nNote that this is different from _luminance_, the amount of light that passes through, emits from, or reflects off an object.\n\n## Registers\n\n    ro illuminance: u22.10 lux { typical_max=100000 } @ reading\n\nThe amount of illuminance, as lumens per square metre.\n\n    ro illuminance_error?: u22.10 lux @ reading_error\n\nError on the reported sensor value.\n"},{"classIdentifier":385496805,"shortId":"indexedscreen","source":"# Indexed screen\n\n    identifier: 0x16fa36e5\n    tags: SPI\n    status: rc\n\nA screen with indexed colors from a palette.\n\nThis is often run over an SPI connection or directly on the MCU, not regular single-wire Jacdac.\n\n## Commands\n\n    command start_update @ 0x81 {\n        x: u16 px\n        y: u16 px\n        width: u16 px\n        height: u16 px\n    }\n\nSets the update window for subsequent `set_pixels` commands.\n\n    unique command set_pixels @ 0x83 {\n        pixels: bytes\n    }\n\nSet pixels in current window, according to current palette.\nEach \"line\" of data is aligned to a byte.\n\n## Registers\n\n    rw brightness: u0.8 / @ intensity\n\nSet backlight brightness.\nIf set to `0` the display may go to sleep.\n\n    rw palette: bytes @ 0x80\n\nThe current palette. The colors are `[r,g,b, padding]` 32bit color entries.\nThe color entry repeats `1 << bits_per_pixel` times.\nThis register may be write-only.\n\n    const bits_per_pixel: u8 bit @ 0x180\n\nDetermines the number of palette entries.\nTypical values are 1 or 4.\n\n    const width: u16 px @ 0x181\n\nScreen width in \"natural\" orientation.\n\n    const height: u16 px @ 0x182\n\nScreen height in \"natural\" orientation.\n\n    rw width_major?: bool @ 0x81\n\nIf true, consecutive pixels in the \"width\" direction are sent next to each other (this is typical for graphics cards).\nIf false, consecutive pixels in the \"height\" direction are sent next to each other.\nFor embedded screen controllers, this is typically true iff `width < height`\n(in other words, it's only true for portrait orientation screens).\nSome controllers may allow the user to change this (though the refresh order may not be optimal then).\nThis is independent of the `rotation` register.\n\n    rw up_sampling?: u8 px @ 0x82\n\nEvery pixel sent over wire is represented by `up_sampling x up_sampling` square of physical pixels.\nSome displays may allow changing this (which will also result in changes to `width` and `height`).\nTypical values are 1 and 2.\n\n    rw rotation?: u16 ° @ 0x83\n\nPossible values are 0, 90, 180 and 270 only.\nWrite to this register do not affect `width` and `height` registers,\nand may be ignored by some screens.\n"},{"classIdentifier":504728043,"shortId":"infrastructure","source":"# Infrastructure\n\nA service that tags a device as purely infrastructure device.\n\n    identifier: 0x1e1589eb\n    tags: infrastructure\n    status: stable\n\nA Jacdac user interface can hide any device that hosts this service.\n"},{"classIdentifier":289210942,"shortId":"keyboardclient","source":"# Keyboard client\n\n    identifier: 0x113d023e\n    status: experimental\n\nMeasures KeyboardClient.\n\n## Events\n\n    event down @ active {\n        key: u16\n    }\n\nEmitted when a key is pressed.\n\n    event hold @ 0x81 {\n        key: u16\n    }\n\nEmitted when a key is held.\n"},{"classIdentifier":369743088,"shortId":"led","source":"# LED\n\n    identifier: 0x1609d4f0\n    camel: led\n    group: light\n    status: stable\n\nA controller for displays of individually controlled RGB LEDs.\n\nFor 64 or less LEDs, the service should support the pack the pixels in the pixels register.\nBeyond this size, the register should return an empty payload as the amount of data exceeds\nthe size of a packet. Typically services that use more than 64 LEDs\nwill run on the same MCU and will maintain the pixels buffer internally.\n\n## Registers\n\n    define max_pixels_length 64\n    rw pixels: bytes @ value\n\nA buffer of 24bit RGB color entries for each LED, in R, G, B order.\nWhen writing, if the buffer is too short, the remaining pixels are set to `#000000`;\nIf the buffer is too long, the write may be ignored, or the additional pixels may be ignored.\nIf the number of pixels is greater than `max_pixels_length`, the read should return an empty payload.\n\n    rw brightness = 0.05: u0.8 / @ intensity\n\nSet the luminosity of the strip.\nAt `0` the power to the strip is completely shut down.\n\n    ro actual_brightness: u0.8 / @ 0x180\n\nThis is the luminosity actually applied to the strip.\nMay be lower than `brightness` if power-limited by the `max_power` register.\nIt will rise slowly (few seconds) back to `brightness` is limits are no longer required.\n\n    const num_pixels: u16 # @ 0x182\n\nSpecifies the number of pixels in the strip.\n\n    const num_columns?: u16 # @ 0x183\n\nIf the LED pixel strip is a matrix, specifies the number of columns.\n\n    rw max_power? = 200: u16 mA @ max_power\n\nLimit the power drawn by the light-strip (and controller).\n\n    const leds_per_pixel?: u16 # @ 0x184\n\nIf known, specifies the number of LEDs in parallel on this device.\nThe actual number of LEDs is `num_pixels * leds_per_pixel`.\n\n    const wave_length?: u16 nm { typical_min=365, typical_max=885 } @ 0x185\n\nIf monochrome LED, specifies the wave length of the LED.\nRegister is missing for RGB LEDs.\n\n    const luminous_intensity?: u16 mcd { typical_min=10, typical_max=5000 } @ 0x186\n\nThe luminous intensity of all the LEDs, at full brightness, in micro candella.\n\n    enum Variant: u8 {\n        Strip = 1,\n        Ring = 2,\n        Stick = 3,\n        Jewel = 4,\n        Matrix = 5\n    }\n    const variant?: Variant @ variant\n\nSpecifies the shape of the light strip.\n"},{"classIdentifier":506480888,"shortId":"ledsingle","source":"# LED Single\n\n    identifier: 0x1e3048f8\n    camel: ledSingle\n    group: light\n    tags: 8bit, padauk\n    status: deprecated\n\nA controller for 1 or more monochrome or RGB LEDs connected in parallel.\n\n## Commands\n\n    command animate @ 0x80 {\n        to_red: u8\n        to_green: u8\n        to_blue: u8\n        speed: u8\n    }\n\nThis has the same semantics as `set_status_light` in the control service.\n\n## Registers\n\n    ro color @ 0x180 {\n        red: u8\n        green: u8\n        blue: u8\n    }\n\nThe current color of the LED.\n\n    rw max_power? = 100: u16 mA @ max_power\n\nLimit the power drawn by the light-strip (and controller).\n\n    const led_count?: u16 @ 0x183\n\nIf known, specifies the number of LEDs in parallel on this device.\n\n    const wave_length?: u16 nm { typical_min=365, typical_max=885 } @ 0x181\n\nIf monochrome LED, specifies the wave length of the LED.\n\n    const luminous_intensity?: u16 mcd { typical_min=10, typical_max=5000 } @ 0x182\n\nThe luminous intensity of the LED, at full value, in micro candella.\n\n    enum Variant: u8 {\n        ThroughHole = 1\n        SMD = 2\n        Power = 3\n        Bead = 4\n    }\n    const variant?: Variant @ variant\n\nThe physical type of LED.\n"},{"classIdentifier":309264608,"shortId":"ledstrip","source":"# LED Strip\n\n    identifier: 0x126f00e0\n    camel: ledStrip\n    tags: C\n    group: light\n    status: stable\n\nA controller for strips of individually controlled RGB LEDs.\n\n## Light programs\n\nWith 1 mbit Jacdac, we can transmit under 2k of data per animation frame (at 20fps).\nIf transmitting raw data that would be around 500 pixels, which is not enough for many\ninstallations and it would completely clog the network.\n\nThus, light service defines a domain-specific language for describing light animations\nand efficiently transmitting them over wire. For short LED displays, less than 64 LEDs, \nyou can also use the [LED service](/services/led).\n\nLight commands are not Jacdac commands.\nLight commands are efficiently encoded as sequences of bytes and typically sent as payload\nof `run` command.\n\nDefinitions:\n\n-   `P` - position in the strip\n-   `R` - number of repetitions of the command\n-   `N` - number of pixels affected by the command\n-   `C` - single color designation\n-   `C+` - sequence of color designations\n\nUpdate modes:\n\n-   `0` - replace\n-   `1` - add RGB\n-   `2` - subtract RGB\n-   `3` - multiply RGB (by c/128); each pixel value will change by at least 1\n\nProgram commands:\n\n-   `0xD0: setall C+` - set all pixels in current range to given color pattern\n-   `0xD1: fade C+` - set pixels in current range to colors between colors in sequence\n-   `0xD2: fadehsv C+` - similar to `fade()`, but colors are specified and faded in HSV\n-   `0xD3: rotfwd K` - rotate (shift) pixels by `K` positions away from the connector\n-   `0xD4: rotback K` - same, but towards the connector\n-   `0xD5: show M=50` - send buffer to strip and wait `M` milliseconds\n-   `0xD6: range P=0 N=length W=1 S=0` - range from pixel `P`, `N` pixels long (currently unsupported: every `W` pixels skip `S` pixels)\n-   `0xD7: mode K=0` - set update mode\n-   `0xD8: tmpmode K=0` - set update mode for next command only\n-   `0xCF: setone P C` - set one pixel at `P` (in current range) to given color\n-   `mult V` - macro to multiply current range by given value (float)\n\nA number `k` is encoded as follows:\n\n-   `0 <= k < 128` -> `k`\n-   `128 <= k < 16383` -> `0x80 | (k >> 8), k & 0xff`\n-   bigger and negative numbers are not supported\n\nThus, bytes `0xC0-0xFF` are free to use for commands.\n\nFormats:\n\n-   `0xC1, R, G, B` - single color parameter\n-   `0xC2, R0, G0, B0, R1, G1, B1` - two color parameter\n-   `0xC3, R0, G0, B0, R1, G1, B1, R2, G2, B2` - three color parameter\n-   `0xC0, N, R0, G0, B0, ..., R(N-1), G(N-1), B(N-1)` - `N` color parameter\n-   `0xCF, <number>, R, G, B` - `set1` special format\n\nCommands are encoded as command byte, followed by parameters in the order\nfrom the command definition.\n\nThe `setone()` command has irregular encoding to save space - it is byte `0xCF` followed by encoded\nnumber, and followed by 3 bytes of color.\n\n## Registers\n\n    rw brightness = 0.05: u0.8 / @ intensity\n\nSet the luminosity of the strip.\nAt `0` the power to the strip is completely shut down.\n\n    ro actual_brightness: u0.8 / @ 0x180\n\nThis is the luminosity actually applied to the strip.\nMay be lower than `brightness` if power-limited by the `max_power` register.\nIt will rise slowly (few seconds) back to `brightness` is limits are no longer required.\n\n    enum LightType : u8 {\n        WS2812B_GRB = 0x00\n        APA102 = 0x10\n        SK9822 = 0x11\n    }\n    rw light_type: LightType @ 0x80\n\nSpecifies the type of light strip connected to controller.\nControllers which are sold with lights should default to the correct type\nand could not allow change.\n\n    rw num_pixels = 15: u16 # @ 0x81\n\nSpecifies the number of pixels in the strip.\nControllers which are sold with lights should default to the correct length\nand could not allow change. Increasing length at runtime leads to ineffective use of memory and may lead to controller reboot.\n\n    rw num_columns?: u16 # @ 0x83\n\nIf the LED pixel strip is a matrix, specifies the number of columns. Otherwise, a square shape is assumed. Controllers which are sold with lights should default to the correct length\nand could not allow change. Increasing length at runtime leads to ineffective use of memory and may lead to controller reboot.\n\n    rw max_power = 200: u16 mA @ max_power\n\nLimit the power drawn by the light-strip (and controller).\n\n    const max_pixels: u16 # @ 0x181\n\nThe maximum supported number of pixels.\nAll writes to `num_pixels` are clamped to `max_pixels`.\n\n    rw num_repeats = 1: u16 # @ 0x82\n\nHow many times to repeat the program passed in `run` command.\nShould be set before the `run` command.\nSetting to `0` means to repeat forever.\n\n    enum Variant: u8 {\n        Strip = 1,\n        Ring = 2,\n        Stick = 3,\n        Jewel = 4,\n        Matrix = 5\n    }\n    const variant?: Variant @ variant\n\nSpecifies the shape of the light strip.\n\n## Commands\n\n    unique command run @ 0x81 {\n        program: bytes\n    }\n\nRun the given light \"program\". See service description for details.\n"},{"classIdentifier":480970060,"shortId":"lightbulb","source":"# Light bulb\n\n    identifier: 0x1cab054c\n    group: light\n    status: rc\n\nA light bulb controller.\n\n## Registers\n\n    rw brightness: u0.16 / @ intensity\n\nIndicates the brightness of the light bulb. Zero means completely off and 0xffff means completely on.\nFor non-dimmable lights, the value should be clamp to 0xffff for any non-zero value.\n\n    const dimmable?: bool @ 0x180\n\nIndicates if the light supports dimming.\n"},{"classIdentifier":400333340,"shortId":"lightlevel","source":"# Light level\n\nA sensor that measures luminosity level.\n\n    identifier: 0x17dc9a1c\n    extends: _sensor\n    group: environment\n    tags: 8bit, padauk, input\n    status: stable\n\n## Registers\n\n    ro light_level: u0.16 / @ reading\n\nDetect light level\n\n    ro light_level_error?: u0.16 / @ reading_error\n\nAbsolute estimated error of the reading value\n\n    enum Variant: u8 {\n        PhotoResistor = 1,\n        ReverseBiasedLED = 2\n    }\n    const variant?: Variant @ variant\n\nThe type of physical sensor.\n"},{"classIdentifier":316415946,"shortId":"logger","source":"# Logger\n\n    identifier: 0x12dc1fca\n    tags: infrastructure, C\n    status: stable\n\nA service which can report messages to the bus.\n\n## Registers\n\n    enum Priority : u8 {\n        Debug = 0,\n        Log = 1,\n        Warning = 2,\n        Error = 3,\n        Silent = 4\n    }\n    rw min_priority = 1: Priority @ 0x80\n\nMessages with level lower than this won't be emitted. The default setting may vary.\nLoggers should revert this to their default setting if the register has not been\nupdated in 3000ms, and also keep the lowest setting they have seen in the last 1500ms.\nThus, clients should write this register every 1000ms and ignore messages which are\ntoo verbose for them.\n\n## Commands\n\n    report debug @ 0x80 {\n        message: string\n    }\n    report log @ 0x81 {\n        message: string\n    }\n    report warn @ 0x82 {\n        message: string\n    }\n    report error @ 0x83 {\n        message: string\n    }\n\nReport a message.\n"},{"classIdentifier":318642191,"shortId":"magneticfieldlevel","source":"# Magnetic field level\n\n    identifier: 0x12fe180f\n    extends: _sensor\n    group: environment\n    tags: 8bit, padauk, input\n    status: stable\n\nA sensor that measures strength and polarity of magnetic field.\n\n## Registers\n\n    ro strength: i1.15 / @ reading\n\nIndicates the strength of magnetic field between -1 and 1.\nWhen no magnet is present the value should be around 0.\nFor analog sensors,\nwhen the north pole of the magnet is on top of the module\nand closer than south pole, then the value should be positive.\nFor digital sensors,\nthe value should either `0` or `1`, regardless of polarity.\n\n    client ro detected : bool @ 0x181\n\nDetermines if the magnetic field is present.\nIf the event `active` is observed, `detected` is true; if `inactive` is observed, `detected` is false.\n\n    enum Variant: u8 {\n        AnalogNS = 1,\n        AnalogN = 2,\n        AnalogS = 3,\n        DigitalNS = 4,\n        DigitalN = 5,\n        DigitalS = 6,\n    }\n    const variant?: Variant @ variant\n\nDetermines which magnetic poles the sensor can detected,\nand whether or not it can measure their strength or just presence.\n\n## Events\n\n    event active @ active\n\nEmitted when strong-enough magnetic field is detected.\n\n    event inactive @ inactive\n\nEmitted when strong-enough magnetic field is no longer detected.\n"},{"classIdentifier":318935176,"shortId":"magnetomer","source":"# Magnetometer\n\n    identifier: 0x13029088\n    extends: _sensor\n    status: rc\n\nA 3-axis magnetometer.\n\n## Registers\n\n    ro forces @ reading {\n        x: i32 nT\n        y: i32 nT\n        z: i32 nT\n    }\n\nIndicates the current magnetic field on magnetometer.\nFor reference: `1 mgauss` is `100 nT` (and `1 gauss` is `100 000 nT`).\n\n    ro forces_error?: i32 nT @ reading_error\n\nAbsolute estimated error on the readings.\n\n## Commands\n\n    command calibrate @ calibrate { }\n\nForces a calibration sequence where the user/device\nmight have to rotate to be calibrated.\n"},{"classIdentifier":319172040,"shortId":"matrixkeypad","source":"# Matrix Keypad\n\n    identifier: 0x13062dc8\n    extends: _sensor\n    group: button\n    status: experimental\n\nA matrix of buttons connected as a keypad\n\n## Registers\n\n    ro pressed @ reading {\n        repeats:\n          index: u8\n    }\n\nThe coordinate of the button currently pressed. Keys are zero-indexed from left to right, top to bottom:\n``row = index / columns``, ``column = index % columns``.\n\n    const rows: u8 # @ 0x180\n\nNumber of rows in the matrix\n\n    const columns: u8 # @ 0x181\n\nNumber of columns in the matrix\n\n    const labels? @ 0x182 {\n        repeats:\n            label: string0\n    }\n\nThe characters printed on the keys if any, in indexing sequence.\n\n    enum Variant: u8 {\n        Membrane = 1\n        Keyboard = 2\n        Elastomer = 3\n        ElastomerLEDPixel = 4\n    }\n    const variant?: Variant @ variant\n\nThe type of physical keypad. If the variant is ``ElastomerLEDPixel``\nand the next service on the device is a ``LEDPixel`` service, it is considered\nas the service controlling the LED pixel on the keypad.\n## Events\n\n    event down: u8 @ active\n\nEmitted when a key, at the given index, goes from inactive (`pressed == 0`) to active.\n\n    event up: u8 @ inactive\n\nEmitted when a key, at the given index, goes from active (`pressed == 1`) to inactive.\n\n    event click: u8 @ 0x80\n\nEmitted together with `up` when the press time was not longer than 500ms.\n\n    event long_click: u8 @ 0x81\n\nEmitted together with `up` when the press time was more than 500ms.\n"},{"classIdentifier":289254534,"shortId":"microphone","source":"# Microphone\n\n    identifier: 0x113dac86\n    group: sound\n    status: experimental\n\nA single-channel microphone.\n\n## Commands\n\n    command sample @ 0x81 {\n        samples: pipe\n        num_samples: u32\n    }\n\nThe samples will be streamed back over the `samples` pipe.\nIf `num_samples` is `0`, streaming will only stop when the pipe is closed.\nOtherwise the specified number of samples is streamed.\nSamples are sent as `i16`.\n\n## Registers\n\n    rw sampling_period: u32 us @ 0x80\n\nGet or set microphone sampling period.\nSampling rate is `1_000_000 / sampling_period Hz`.\n\n"},{"classIdentifier":444894423,"shortId":"midioutput","source":"# MIDI output\n\n    identifier: 0x1a848cd7\n    camel: midiOutput\n    group: sound\n    status: experimental\n\nA MIDI output device.\n\n## Registers\n\n    rw enabled: bool @ intensity\n\nOpens or closes the port to the MIDI device\n\n## Commands\n\n    command clear @ 0x80 { }\n\nClears any pending send data that has not yet been sent from the MIDIOutput's queue.\n\n    unique command send @ 0x81 {\n        data: bytes\n    }\n\nEnqueues the message to be sent to the corresponding MIDI port\n "},{"classIdentifier":336566904,"shortId":"modelrunner","source":"# Model Runner\n\n    identifier: 0x140f9a78\n    status: experimental\n\nRuns machine learning models.\n\nOnly models with a single input tensor and a single output tensor are supported at the moment.\nInput is provided by Sensor Aggregator service on the same device.\nMultiple instances of this service may be present, if more than one model format is supported by a device.\n\n## Commands\n\n    unique command set_model @ 0x80 {\n        model_size: u32 B\n    }\n    report {\n        model_port: pipe_port\n    }\n\nOpen pipe for streaming in the model. The size of the model has to be declared upfront.\nThe model is streamed over regular pipe data packets.\nThe format supported by this instance of the service is specified in `format` register.\nWhen the pipe is closed, the model is written all into flash, and the device running the service may reset.\n\n    command predict @ 0x81 {\n        outputs: pipe\n    }\n    report {\n        inputs: pipe_port\n    }\n\nOpen channel that can be used to manually invoke the model. When enough data is sent over the `inputs` pipe, the model is invoked,\nand results are send over the `outputs` pipe.\n\n## Registers\n\n    rw auto_invoke_every: u16 @ 0x80\n\nWhen register contains `N > 0`, run the model automatically every time new `N` samples are collected.\nModel may be run less often if it takes longer to run than `N * sampling_interval`.\nThe `outputs` register will stream its value after each run.\nThis register is not stored in flash.\n\n    ro outputs @ reading {\n    repeats:\n        output: f32\n    }\n\nResults of last model invocation as `float32` array.\n\n    ro input_shape @ 0x180 {\n    repeats:\n        dimension: u16\n    }\n\nThe shape of the input tensor.\n\n    ro output_shape @ 0x181 {\n    repeats:\n        dimension: u16\n    }\n\nThe shape of the output tensor.\n\n    ro last_run_time: u32 us @ 0x182\n\nThe time consumed in last model execution.\n\n    ro allocated_arena_size: u32 B @ 0x183\n\nNumber of RAM bytes allocated for model execution.\n\n    ro model_size: u32 B @ 0x184\n\nThe size of the model in bytes.\n\n    ro last_error: string @ 0x185\n\nTextual description of last error when running or loading model (if any).\n\n    enum ModelFormat: u32 {\n        TFLite = 0x334c4654,\n        ML4F = 0x30470f62,\n        EdgeImpulseCompiled = 0x30564945,\n    }\n    const format: ModelFormat @ 0x186\n\nThe type of ML models supported by this service.\n`TFLite` is flatbuffer `.tflite` file.\n`ML4F` is compiled machine code model for Cortex-M4F.\nThe format is typically present as first or second little endian word of model file.\n\n    const format_version: u32 @ 0x187\n\nA version number for the format.\n\n    const parallel?: bool @ 0x188\n\nIf present and true this service can run models independently of other\ninstances of this service on the device.\n"},{"classIdentifier":293185353,"shortId":"motion","source":"# Motion\n\nA sensor, typically PIR, that detects object motion within a certain range\n\n    identifier: 0x1179a749\n    extends: _sensor\n    group: movement\n    tags: 8bit\n    status: experimental\n\n## Registers\n\n    ro moving: bool { preferred_interval=1000 } @ reading\n\nReports is movement is currently detected by the sensor.\n\n    const max_distance?: u16.16 m @ 0x180\n\nMaximum distance where objects can be detected.\n\n    const angle?: u16 ° @ 0x181\n\nOpening of the field of view\n\n    enum Variant: u8 {\n      PIR = 1\n    }\n    const variant?: Variant @ variant\n\nType of physical sensor\n\n## Events\n\n    event movement @ active { }\n\nA movement was detected."},{"classIdentifier":385895640,"shortId":"motor","source":"# Motor\n\n    identifier: 0x17004cd8\n    tags: C, 8bit\n    status: rc\n\nA DC motor.\n\n## Registers\n\n    rw speed: i1.15 / @ value\n\nRelative speed of the motor. Use positive/negative values to run the motor forwards and backwards.\nPositive is recommended to be clockwise rotation and negative counterclockwise. A speed of ``0`` \nwhile ``enabled`` acts as brake.\n\n    rw enabled: bool @ intensity\n\nTurn the power to the motor on/off.\n\n    const load_torque?: u16.16 kg/cm @ 0x180\n\nTorque required to produce the rated power of an electrical motor at load speed.\n\n    const load_rotation_speed?: u16.16 rpm @ 0x181\n\nRevolutions per minute of the motor under full load.\n\n    const reversible?: bool @ 0x182\n\nIndicates if the motor can run backwards."},{"classIdentifier":487664309,"shortId":"multitouch","source":"# Multitouch\n\n    identifier: 0x1d112ab5\n    extends: _sensor\n    group: button\n    status: experimental\n\nA capacitive touch sensor with multiple inputs.\n\n## Registers\n\n    ro capacity @ reading {\n    repeats:\n        capacitance: i16\n    }\n\nCapacitance of channels. The capacitance is continuously calibrated, and a value of `0` indicates\nno touch, wheres a value of around `100` or more indicates touch.\nIt's best to ignore this (unless debugging), and use events.\n\nDigital sensors will use `0` or `0xffff` on each channel.\n\n## Events\n\nMost events include the channel number of the input.\n\n    event touch @ active {\n        channel: u8\n    }\n\nEmitted when an input is touched.\n\n    event release @ inactive {\n        channel: u8\n    }\n\nEmitted when an input is no longer touched.\n\n    event tap @ 0x80 {\n        channel: u8\n    }\n\nEmitted when an input is briefly touched. TODO Not implemented.\n\n    event long_press @ 0x81 {\n        channel: u8\n    }\n\nEmitted when an input is touched for longer than 500ms. TODO Not implemented.\n\n    event swipe_pos @ 0x90 {\n        duration: u16 ms\n        start_channel: u8\n        end_channel: u8\n    }\n\nEmitted when input channels are successively touched in order of increasing channel numbers.\n\n    event swipe_neg @ 0x91 {\n        duration: u16 ms\n        start_channel: u8\n        end_channel: u8\n    }\n\nEmitted when input channels are successively touched in order of decreasing channel numbers."},{"classIdentifier":289212807,"shortId":"pccontroller","source":"# PC controller\n\n    identifier: 0x113d0987\n    status: experimental\n    camel: PCController\n\nSend various events to PC, including opening a URL, start an app, sending text, etc.\n\n## Commands\n\n    command open_url @ 0x80 {\n        url: string\n    }\n\nOpen a URL in the default browser.\n\n    command start_app @ 0x81 {\n        name: string\n    }\n\nStart an app.\n\n    command send_text @ 0x82 {\n        text: string\n    }\n\nSend text to the active window.\n\n    command run_script @ 0x83 {\n        script: string\n    }\n\nRun a script.\n"},{"classIdentifier":409107221,"shortId":"pcmonitor","source":"# PC monitor\n\n    identifier: 0x18627b15\n    status: experimental\n    camel: PCMonitor\n\nMeasures PC monitor.\n\n## Registers\n\n    ro cpu_usage: u8 % @ 0x190\n\nCPU usage in percent.\n\n    ro cpu_temperature: u8 °C @ 0x191\n\nCPU temperature in Celsius.\n\n    ro ram_usage: u8 % @ 0x192\n\nRAM usage in percent.\n\n    ro gpu_information @ 0x193 {\n        usage: u8 %\n        temperature: u8 °C\n    }\n\nGPU info.\n\n    ro network_information @ 0x195 {\n        tx: u16 KB\n        rx: u16 KB\n    }\n\nNetwork transmit/receive speed in Kbytes per second.\n\nA measure of PC monitor.\n"},{"classIdentifier":499351381,"shortId":"planarposition","source":"# Planar position\n\n    identifier: 0x1dc37f55\n    status: experimental\n    extends: _sensor\n    group: movement\n\nA sensor that repors 2D position, typically an optical mouse tracking sensor.\n\nThe sensor starts at an arbitrary origin (0,0) and reports the distance from that origin.\n\nThe `streaming_interval` is respected when the position is changing. When the position is not changing, the streaming interval may be throttled to `500ms`.\n\n# Registers\n\n    ro position @ reading {\n        x: i22.10 mm\n        y: i22.10 mm\n    }\n\nThe current position of the sensor.\n\n    enum Variant : u8 {\n        OpticalMousePosition = 1,\n    }\n    const variant? : Variant @ variant\n    \nSpecifies the type of physical sensor.\n"},{"classIdentifier":522667846,"shortId":"potentiometer","source":"# Potentiometer\n\n    identifier: 0x1f274746\n    extends: _sensor\n    group: slider\n    tags: C, 8bit, input\n    status: stable\n\nA slider or rotary potentiometer.\n\n## Registers\n\n    ro position: u0.16 / @ reading\n\nThe relative position of the slider.\n\n    enum Variant: u8 {\n        Slider = 1,\n        Rotary = 2,\n        Hall = 3,\n    }\n    const variant?: Variant @ variant\n\nSpecifies the physical layout of the potentiometer.\n"},{"classIdentifier":530893146,"shortId":"power","source":"# Power\n\n    identifier: 0x1fa4c95a\n    status: experimental\n\nA power-provider service.\n\n## Power negotiation protocol\n\nThe purpose of the power negotiation is to ensure that there is no more than [I<sub>out_hc(max)</sub>](https://microsoft.github.io/jacdac-docs/reference/electrical-spec/#power-providers) delivered to the power rail.\nThis is realized by limiting the number of enabled power provider services to one.\n\nNote, that it's also possible to have low-current power providers,\nwhich are limited to [I<sub>out_lc(max)</sub>](https://microsoft.github.io/jacdac-docs/reference/electrical-spec/#power-providers) and do not run a power provider service.\nThese are **not** accounted for in the power negotiation protocol.\n\nPower providers can have multiple _channels_, typically multiple Jacdac ports on the provider.\nEach channel can be limited to [I<sub>out_hc(max)</sub>](https://microsoft.github.io/jacdac-docs/reference/electrical-spec/#power-providers) separately.\nIn normal operation, the data lines of each channels are connected together.\nThe ground lines are always connected together.\nMulti-channel power providers are also called _powered hubs_.\n\nWhile channels have separate current limits, there's nothing to prevent the user\nfrom joining two or more channels outside of the provider using a passive hub.\nThis would allow more than [I<sub>out_hc(max)</sub>](https://microsoft.github.io/jacdac-docs/reference/electrical-spec/#power-providers) of current to be drawn, resulting in cables or components\ngetting hot and/or malfunctioning.\nThus, the power negotiation protocol seeks to detect situations where\nmultiple channels of power provider(s) are bridged together\nand shut down all but one of the channels involved.\n\nThe protocol is built around the power providers periodically sending specially crafted\n`shutdown` commands in broadcast mode.\nNote that this is unusual - services typically only send reports.\n\nThe `shutdown` commands can be reliably identified based on their first half (more details below).\nWhen a power provider starts receiving a `shutdown` command, it needs to take\nsteps to identify which of its channels the command is coming from.\nThis is typically realized with analog switches between the data lines of channels.\nThe delivery of power over the channel which received the `shutdown` command is then shut down.\nNote that in the case of a single-channel provider, any received `shutdown` command will cause a shut down.\n\nA multi-channel provider needs to also identify when a `shutdown` command it sent from one channel\nis received on any of its other channels and shut down one of the channels involved.\n\nIt is also possible to build a _data bridge_ device, with two or more ports.\nIt passes through all data except for `shutdown` commands,\nbut **does not** connect the power lines.\n\n### Protocol details\n\nThe `shutdown` commands follow a very narrow format:\n* they need to be the only packet in the frame (and thus we can also call them `shutdown` frames)\n* the second word of `device_id` needs to be set to `0xAA_AA_AA_AA` (alternating 0 and 1)\n* the service index is set to `0x3d`\n* the CRC is therefore fixed\n* therefore, the packet can be recognized by reading the first 8 bytes (total length is 16 bytes)\n\nThe exact byte structure of `shutdown` command is:\n`15 59 04 05 5A C9 A4 1F AA AA AA AA 00 3D 80 00`\n\nThere is one power service per channel.\nA multi-channel power provider can be implemented as one device with multiple services (typically with one MCU),\nor many devices with one service each (typically multiple MCUs).\nThe first option is preferred as it fixes the order of channels,\nbut the second option may be cheaper to implement.\n\nAfter queuing a `shutdown` command, the service enters a grace period\nuntil the report has been sent on the wire.\nDuring the grace period incoming `shutdown` commands are ignored.\n\n* Upon reset, a power service enables itself, and then only after 0-300ms (random)\n  sends the first `shutdown` command\n* Every enabled power service emits `shutdown` commands every 400-600ms (random; first few packets can be even sent more often)\n* If an enabled power service sees a `shutdown` command from somebody else,\n  it disables itself (unless in grace period)\n* If a disabled power service sees no `shutdown` command for more than ~1200ms, it enables itself\n  (this is when the previous power source is unplugged or otherwise malfunctions)\n* If a power service has been disabled for around 10s, it enables itself.\n\nAdditionally:\n* While the `allowed` register is set to `0`, the service will not enable itself (nor send `shutdown` commands)\n* When a current overdraw is detected, the service stop providing power and enters `Overload` state for around 2 seconds,\n  while still sending `shutdown` commands.\n\n### Client notes\n\nIf a client hears a `shutdown` command it just means it's on a branch of the\nnetwork with a (high) power provider.\nAs clients (brains) typically do not consume much current (as opposed to, say, servos),\nthe `shutdown` commands are typically irrelevant to them.\n\nFor power monitoring, the `power_status_changed` event (and possibly `power_status` register)\ncan be used.\nIn particular, user interfaces may alert the user to `Overload` status.\nThe `Overprovision` status is generally considered normal (eg. when two multi-channel power providers are linked together).\n\n### Server implementation notes\n\n#### A dedicated MCU per channel\n\nEvery channel has:\n* a cheap 8-bit MCU (e.g. PMS150C, PFS122),\n* a current limiter with FAULT output and ENABLE input, and\n* an analog switch.\n\nThe MCU here needs at least 4 pins per channel.\nIt is connected to data line of the channel, the control input of the switch, and to the current limiter's FAULT and ENABLE pins.\n\nThe switch connects the data line of the channel (JD_DATA_CHx) with the internal shared data bus, common to all channels (JD_DATA_COM).\nBoth the switch and the limiter are controlled by the MCU.\nA latching circuit is not needed for the limiter because the MCU will detect an overcurrent fault and shut it down immediately. \n\nDuring reception, after the beginning of `shutdown` frame is detected,\nthe switch is opened for a brief period.\nIf the `shutdown` frame is received correctly, it means it was on MCU's channel.\n\nIn the case of only one power delivery channel that's controlled by a dedicated MCU, the analog switch is not necessary. \n\n#### A shared MCU for multiple channels\n\nEvery channel has:\n* a current limiter with FAULT output and ENABLE input, \n* an analog switch, and\n* a wiggle-detection line connecting the MCU to data line of the channel\n\nThe MCU again needs at least 4 pins per channel.\nSwitches and limiters are set up like in the configuration above.\nThe Jacdac data line of the MCU is connected to internal data bus.\n\nWhile a Jacdac packet is being received, the MCU keeps checking if it is a \nbeginning of the `shutdown` frame.\nIf that is the case, it opens all switches and checks which one(s) of the channel\ndata lines wiggle (via the wiggle lines; this can be done with EXTI latches).\nThe one(s) that wiggle received the `shutdown` frame and need to be disabled.\n\nAlso, while sending the `shutdown` frames itself, it needs to be done separately\nfor each channel, with all the other switches open.\nIf during that operation we detect wiggle on other channels, then we have detected\na loop, and the respective channels needs to be disabled.\n\n#### A brain-integrated power supply\n\nHere, there's only one channel of power and we don't have hard real time requirements,\nso user-programmable brain can control it.\nThere is no need for analog switch or wiggle-detection line,\nbut a current limiter with a latching circuit is needed.\n\nThere is nothing special to do during reception of `shutdown` packet.\nWhen it is received, the current limiter should just be disabled.\n\nIdeally, exception/hard-fault handlers on the MCU should also disable the current limiter.\nSimilarly, the limiter should be disabled while the MCU is in bootloader mode,\nor otherwise unaware of the power negotiation protocol. \n\n### Rationale for the grace period\n\nConsider the following scenario:\n\n* device A queues `shutdown` command for sending\n* A receives external `shutdown` packet from B (thus disabling A)\n* the A `shutdown` command is sent from the queue (thus eventually disabling B)\n\nTo avoid that, we make sure that at the precise instant when `shutdown` command is sent,\nthe power is enabled (and thus will stay enabled until another `shutdown` command arrives).\nThis could be achieved by inspecting the enable bit, aftering acquiring the line\nand before starting UART transmission, however that would require breaking abstraction layers.\nSo instead, we never disable the service, while the `shutdown` packet is queued.\nThis may lead to delays in disabling power services, but these should be limited due to the\nrandom nature of the `shutdown` packet spacing.\n\n### Rationale for timings\n\nThe initial 0-300ms delay is set to spread out the `shutdown` periods of power services,\nto minimize collisions.\nThe `shutdown` periods are randomized 400-600ms, instead of a fixed 500ms used for regular\nservices, for the same reason.\n\nThe 1200ms period is set so that droping two `shutdown` packets in a row\nfrom the current provider will not cause power switch, while missing 3 will.\n\nThe 50-60s power switch period is arbitrary, but chosen to limit amount of switching between supplies,\nwhile keeping it short enough for user to notice any problems such switching may cause.\n\n## Registers\n\n    rw allowed = 1: bool @ intensity\n\nCan be used to completely disable the service.\nWhen allowed, the service may still not be providing power, see \n`power_status` for the actual current state.\n\n    rw max_power? = 900: u16 mA {typical_max = 900} @ max_power\n\nLimit the power provided by the service. The actual maximum limit will depend on hardware.\nThis field may be read-only in some implementations - you should read it back after setting.\n\n    enum PowerStatus : u8 {\n        Disallowed = 0\n        Powering = 1\n        Overload = 2\n        Overprovision = 3\n    }\n    ro volatile power_status: PowerStatus @ 0x181\n\nIndicates whether the power provider is currently providing power (`Powering` state), and if not, why not.\n`Overprovision` means there was another power provider, and we stopped not to overprovision the bus.\n\n    ro current_draw?: u16 mA @ reading\n\nPresent current draw from the bus.\n\n    ro volatile battery_voltage?: u16 mV {typical_min = 4500, typical_max = 5500} @ 0x180\n\nVoltage on input.\n\n    ro volatile battery_charge?: u0.16 / @ 0x182\n\nFraction of charge in the battery.\n\n    const battery_capacity?: u32 mWh @ 0x183\n\nEnergy that can be delivered to the bus when battery is fully charged.\nThis excludes conversion overheads if any.\n\n    rw keep_on_pulse_duration? = 600: u16 ms @ 0x80\n    rw keep_on_pulse_period? = 20000: u16 ms @ 0x81\n\nMany USB power packs need current to be drawn from time to time to prevent shutdown.\nThis regulates how often and for how long such current is drawn.\nTypically a 1/8W 22 ohm resistor is used as load. This limits the duty cycle to 10%.\n\n## Commands\n\n    command shutdown @ 0x80 {}\n\nSent by the power service periodically, as broadcast.\n\n## Events\n\n    event power_status_changed @ change {\n        power_status: PowerStatus\n    }\n\nEmitted whenever `power_status` changes.\n"},{"classIdentifier":524302175,"shortId":"powersupply","source":"# Power supply\n    \n    identifier: 0x1f40375f\n    status: experimental\n    \nA power supply with a fixed or variable voltage range\n\n## Registers\n\n    rw enabled: bool @ intensity;\n\nTurns the power supply on with `true`, off with `false`. \n    \n    rw output_voltage: f64 V @ value\n    \nThe current output voltage of the power supply. Values provided must be in the range `minimum_voltage` to `maximum_voltage`\n\n    const minimum_voltage: f64 V @ min_value\n    \nThe minimum output voltage of the power supply. For fixed power supplies, `minimum_voltage` should be equal to `maximum_voltage`.\n\n    const maximum_voltage: f64 V @ max_value\n    \nThe maximum output voltage of the power supply. For fixed power supplies, `minimum_voltage` should be equal to `maximum_voltage`.\n\n"},{"classIdentifier":672612547,"shortId":"pressurebutton","source":"# Pressure Button\n\n    identifier: 0x281740c3\n    tags: 8bit\n    group: button\n    status: rc\n\nA pressure sensitive push-button.\n\n## Registers\n\n    rw threshold: u0.16 / @ active_threshold\n    \nIndicates the threshold for ``up`` events.\n"},{"classIdentifier":382158442,"shortId":"prototest","source":"# Protocol Test\n\n    identifier: 0x16c7466a\n    camel: protoTest\n    tags: infrastructure\n\nThis is test service to validate the protocol packet transmissions between the browser and a MCU.\nUse this page if you are porting Jacdac to a new platform.\n\n### Test procedure\n\nFor each ``rw`` registers, set a random value ``x``\n  * read ``rw`` and check value is equal to ``x``\n  * read ``ro`` and check value is equal to ``x``\n  * listen to ``e`` event and check that data is equal to ``x``\n  * call ``c`` command with new random value ``y``\n  * read ``rw`` and check value is equal to ``y``\n  * do all the above steps with acks\n\nFor each ``rw`` registers, there shall also\nbe an ``event`` and a ``command``. The event\nshould get raised when the value changes;\nand the command should set the value.\n  \n## Registers\n\nEvery ``rw`` register has a corresponding ``ro`` regisrer\nand a corresponding ``set_...`` command to also set the value.\n\n    rw rw_bool : bool @ 0x081\n\nA read write bool register.\n\n    ro ro_bool : bool @ 0x181\n\nA read only bool register. Mirrors rw_bool.\n\n    rw rw_u32 : u32 @ 0x082\n\nA read write u32 register.\n\n    ro ro_u32 : u32 @ 0x182\n\nA read only u32 register.. Mirrors rw_u32.\n\n    rw rw_i32 : i32 @ 0x083\n\nA read write i32 register.\n\n    ro ro_i32 : i32 @ 0x183\n\nA read only i32 register.. Mirrors rw_i32.\n\n    rw rw_string : string @ 0x084\n\nA read write string register.\n\n    ro ro_string : string @ 0x184\n\nA read only string register. Mirrors rw_string.\n\n    rw rw_bytes : bytes @ 0x085\n\nA read write string register.\n\n    ro ro_bytes : bytes @ 0x185\n\nA read only string register. Mirrors ro_bytes.\n\n    rw rw_i8_u8_u16_i32 @ 0x86 {\n        i8: i8\n        u8: u8\n        u16: u16\n        i32: i32\n    }\n\nA read write i8, u8, u16, i32 register.\n\n    ro ro_i8_u8_u16_i32 @ 0x186 {\n        i8: i8\n        u8: u8\n        u16: u16\n        i32: i32\n    }\n\nA read only i8, u8, u16, i32 register.. Mirrors rw_i8_u8_u16_i32.\n\n    rw rw_u8_string @ 0x87 {\n        u8: u8\n        str: string\n    }\n\nA read write u8, string register.\n\n    ro ro_u8_string @ 0x187 {\n        u8: u8\n        str: string\n    }\n\nA read only u8, string register.. Mirrors rw_u8_string.\n\n## Events\n\n    event e_bool @ 0x81 { \n        bo: bool \n    }\n\nAn event raised when rw_bool is modified\n\n    event e_u32 @ 0x82 { \n        u32: u32 \n    }\n\nAn event raised when rw_u32 is modified\n\n    event e_i32 @ 0x83 { \n        i32: i32 \n    }\n\nAn event raised when rw_i32 is modified\n\n    event e_string @ 0x84 { \n        str: string \n    }\n\nAn event raised when rw_string is modified\n\n    event e_bytes @ 0x85 { \n        bytes: bytes \n    }\n\nAn event raised when rw_bytes is modified\n\n    event e_i8_u8_u16_i32 @ 0x86 { \n        i8: i8\n        u8: u8\n        u16: u16\n        i32: i32\n    }\n\nAn event raised when rw_i8_u8_u16_i32 is modified\n\n    event e_u8_string @ 0x87 { \n        u8: u8\n        str: string\n    }\n\nAn event raised when rw_u8_string is modified\n\n## Commands\n\n    command c_bool @ 0x81 {\n        bo: bool\n    }\n\nA command to set rw_bool.\n\n    command c_u32 @ 0x82 {\n        u32: u32\n    }\n\nA command to set rw_u32.\n\n    command c_i32 @ 0x83 {\n        i32: i32\n    }\n\nA command to set rw_i32.\n\n    command c_string @ 0x84 {\n        str: string\n    }\n\nA command to set rw_string.\n\n    command c_bytes @ 0x85 {\n        bytes: bytes\n    }\n\nA command to set rw_string.\n\n    command c_i8_u8_u16_i32 @ 0x86 {\n        i8: i8\n        u8: u8\n        u16: u16\n        i32: i32\n    }\n\nA command to set rw_bytes.\n\n    command c_u8_string @ 0x87 {\n        u8: u8\n        str: string\n    }\n\nA command to set rw_u8_string.\n\n    command c_report_pipe @ 0x90 {\n        p_bytes: pipe\n    }\n    pipe report p_bytes {\n        byte: u8\n    }\n\nA command to read the content of rw_bytes, byte per byte, as a pipe."},{"classIdentifier":384932169,"shortId":"proxy","source":"# Proxy\n\n    identifier: 0x16f19949\n    status: stable\n    tags: infrastructure\n\nA service that tags a device as a packet proxy.\nA device in proxy mode will proxy Jacdac packets and typically has its core logic halted.\n"},{"classIdentifier":280710838,"shortId":"pulseoximeter","source":"# Pulse Oximeter\n\n    identifier: 0x10bb4eb6\n    extends: _sensor\n    group: biometric\n    tags: 8bit\n    status: experimental\n\nA sensor approximating the oxygen level.\n\n**Jacdac is not suitable for medical devices and should NOT be used in any kind of device to diagnose or treat any medical conditions.**\n\n## Registers\n\n    ro oxygen: u8.8 % { typical_min=80, typical_max=100 } @ reading\n\nThe estimated oxygen level in blood.\n\n    ro oxygen_error?: u8.8 % @ reading_error\n\nThe estimated error on the reported sensor data.\n"},{"classIdentifier":326323349,"shortId":"raingauge","source":"# Rain gauge\n\n    identifier: 0x13734c95\n    extends: _sensor\n    group: environment\n    tags: 8bit\n    status: rc\n\nMeasures the amount of liquid precipitation over an area in a predefined period of time.\n\n## Registers\n\n    ro precipitation: u16.16 mm { preferred_interval=60000 } @ reading\n\nTotal precipitation recorded so far.\n\n    const precipitation_precision?: u16.16 mm @ reading_resolution\n\nTypically the amount of rain needed for tipping the bucket.\n"},{"classIdentifier":445323816,"shortId":"realtimeclock","source":"# Real time clock\n\n    identifier: 0x1a8b1a28\n    extends: _sensor\n    tags: 8bit\n    status: rc\n\nReal time clock to support collecting data with precise time stamps.\n\n## Registers\n\n    ro local_time @ reading {\n        year: u16 { preferred_interval=1000 }\n        month: u8 { absolute_min=1, absolute_max=12 }\n        day_of_month: u8 { absolute_min=0, absolute_max=31 }\n        day_of_week: u8 { absolute_min=1, absolute_max=7 }\n        hour: u8 { absolute_min=0, absolute_max=23 }\n        min: u8 { absolute_min=0, absolute_max=59 }\n        sec: u8 { absolute_min=0, absolute_max=60 }\n    }\n\nCurrent time in 24h representation. Default streaming period is 1 second.\n\n-   `day_of_month` is day of the month, starting at `1`\n-   `day_of_week` is day of the week, starting at `1` as monday. Leave at 0 if unsupported.\n\n        ro volatile drift?: u16.16 s @ 0x180\n\nTime drift since the last call to the `set_time` command.\n\n    const precision?: u16.16 ppm @ 0x181\n\nError on the clock, in parts per million of seconds.\n\n    enum Variant: u8 {\n        Computer = 1\n        Crystal = 2\n        Cuckoo = 3\n    }\n    const variant?: Variant @ variant\n\nThe type of physical clock used by the sensor.\n\n## Commands\n\n    command set_time @ 0x80 {\n        year: u16\n        month: u8 { absolute_min=1, absolute_max=12 }\n        day_of_month: u8 { absolute_min=1, absolute_max=31 }\n        day_of_week: u8 { absolute_min=1, absolute_max=7 }\n        hour: u8 { absolute_min=0, absolute_max=23 }\n        min: u8 { absolute_min=0, absolute_max=59 }\n        sec: u8 { absolute_min=0, absolute_max=60 }\n    }\n\nSets the current time and resets the error.\n"},{"classIdentifier":309087410,"shortId":"reflectedlight","source":"# Reflected light\n\n    identifier: 0x126c4cb2\n    extends: _sensor\n    group: environment\n    tags: 8bit\n    status: rc\n\nA sensor that detects light and dark surfaces, commonly used for line following robots.\n\n## Registers\n\n    ro brightness: u0.16 / @ reading\n\nReports the reflected brightness. It may be a digital value or, for some sensor, analog value.\n\n    enum Variant: u8 {\n        InfraredDigital = 1,\n        InfraredAnalog = 2\n    }\n    const variant?: Variant @ variant\n\nType of physical sensor used\n"},{"classIdentifier":406840918,"shortId":"relay","source":"# Relay\n\n    identifier: 0x183fe656\n    tags: 8bit\n    status: stable\n\nA switching relay.\n\nThe contacts should be labelled `NO` (normally open), `COM` (common), and `NC` (normally closed).\nWhen relay is energized it connects `NO` and `COM`.\nWhen relay is not energized it connects `NC` and `COM`.\nSome relays may be missing `NO` or `NC` contacts.\nWhen relay module is not powered, or is in bootloader mode, it is not energized (connects `NC` and `COM`).\n\n## Registers\n\n    rw active: bool @ intensity\n\nIndicates whether the relay circuit is currently energized or not.\n\n    enum Variant: u8 {\n        Electromechanical = 1,\n        SolidState = 2,\n        Reed = 3\n    }\n    const variant?: Variant @ variant\n\nDescribes the type of relay used.\n\n    const max_switching_current?: u32 mA @ 0x180\n\nMaximum switching current for a resistive load.\n"},{"classIdentifier":394916002,"shortId":"rng","source":"# Random Number Generator\n\n    identifier: 0x1789f0a2\n    camel: rng\n    status: rc\n\nGenerates random numbers using entropy sourced from physical processes.\n\nThis typically uses a cryptographical pseudo-random number generator (for example [Fortuna](<https://en.wikipedia.org/wiki/Fortuna_(PRNG)>)),\nwhich is periodically re-seeded with entropy coming from some hardware source.\n\n## Registers\n\n    ro volatile random: bytes @ 0x180\n\nA register that returns a 64 bytes random buffer on every request.\nThis never blocks for a long time. If you need additional random bytes, keep querying the register.\n\n    enum Variant: u8 {\n         Quantum = 1\n         ADCNoise = 2\n         WebCrypto = 3\n    }\n    const variant?: Variant @ variant\n\nThe type of algorithm/technique used to generate the number.\n`Quantum` refers to dedicated hardware device generating random noise due to quantum effects.\n`ADCNoise` is the noise from quick readings of analog-digital converter, which reads temperature of the MCU or some floating pin.\n`WebCrypto` refers is used in simulators, where the source of randomness comes from an advanced operating system.\n"},{"classIdentifier":508264038,"shortId":"rolemanager","source":"# Role Manager\n\nAssign roles to services on the Jacdac bus.\n\n    identifier: 0x1e4b7e66\n    tags: infrastructure\n\n## Role allocation\n\nInternally, the role manager stores a mapping from role name to `(device_id, service_idx)`.\nUsers refer to services by using role names (eg., they instantiate an accelerometer client with a given role name).\nEach client has a role, and roles are unique to clients\n(ie., one should not have both a gyro and accelerometer service with role `left_leg`).\n\nThe simplest recommended automatic role assignment algorithm is as follows:\n\n```text\nroles.sort(strcmp() on UTF-8 representation of role name)\ndevices.sort(by device identifier (lexicographic on 8 byte string))\nmove self device to beginning of devices list\nfor every role\n  if role is not assigned\n    for every device\n      for every service on device\n        if serviceClass matches role\n          if service is not assigned to any role\n            assign service to role\n```\n\nDue to sorting, role names sharing a prefix will tend to be co-located on the single device.\nFor example, one can have roles `left_leg_acc`, `left_leg_gyro`, `right_leg_acc`, `right_leg_gyro`,\nand assuming combined gyro+accelerometer sensors, the pairs will tend to be allocated to a single leg,\nhowever the legs may be reversed.\nIn such a case the user can swap the physical sensors (note that left leg will always be assigned to\nsensor with smaller device identifier).\nAlternatively, the user can manually modify assignment using `set_role` command.\n\n\n## Registers\n\n    rw auto_bind = 1: bool @ 0x80\n\nNormally, if some roles are unfilled, and there are idle services that can fulfill them,\nthe brain device will assign roles (bind) automatically.\nSuch automatic assignment happens every second or so, and is trying to be smart about\nco-locating roles that share \"host\" (part before first slash),\nas well as reasonably stable assignments.\nOnce user start assigning roles manually using this service, auto-binding should be disabled to avoid confusion.\n\n    ro all_roles_allocated: bool @ 0x181\n\nIndicates if all required roles have been allocated to devices.\n\n## Commands\n\n    command set_role @ 0x81 {\n        device_id: devid\n        service_idx: u8\n        role: string\n    }\n\nSet role. Can set to empty to remove role binding.\n\n    command clear_all_roles @ 0x84 {}\n\nRemove all role bindings.\n\n    command list_roles @ 0x83 {\n        roles: pipe\n    }\n    pipe report roles {\n        device_id: devid\n        service_class: u32\n        service_idx: u8\n        role: string\n    }\n\nList all roles and bindings required by the current program. `device_id` and `service_idx` are `0` if role is unbound.\n\n## Events\n\n    event change @ change { }\n\nNotifies that role bindings have changed.\n"},{"classIdentifier":354743340,"shortId":"ros","source":"# ROS\n\n    identifier: 0x1524f42c\n    tags: robotics\n    camel: ros\n    \nA ROS (Robot Operating System https://www.ros.org/) controller that can act as a broker for messages.\n\n## Commands\n\n    command publish_message @ 0x81 {\n        node: string0\n        topic: string0\n        message: string\n    }\n\nPublishes a JSON-encoded message to the given topic.\n\n    command subscribe_message @ 0x82 {\n        node: string0\n        topic: string\n    }\n\nSubscribes to a message topic. Subscribed topics will emit message reports.\n\n    report message @ 0x83 {\n        node: string0\n        topic: string0\n        message: string\n    }\n\nA message published on the bus. Message is JSON encoded."},{"classIdentifier":284830153,"shortId":"rotaryencoder","source":"# Rotary encoder\n\n    identifier: 0x10fa29c9\n    extends: _sensor\n    group: slider\n    tags: C, 8bit, input\n    status: stable\n\nAn incremental rotary encoder - converts angular motion of a shaft to digital signal.\n\n## Registers\n\n    ro position: i32 # @ reading\n\nUpon device reset starts at `0` (regardless of the shaft position).\nIncreases by `1` for a clockwise \"click\", by `-1` for counter-clockwise.\n\n    const clicks_per_turn: u16 # @ 0x180\n\nThis specifies by how much `position` changes when the crank does 360 degree turn. Typically 12 or 24.\n\n    const clicker?: bool @ 0x181\n\nThe encoder is combined with a clicker. If this is the case, the clicker button service\nshould follow this service in the service list of the device."},{"classIdentifier":435474539,"shortId":"rover","source":"# Rover\n\nA roving robot.\n\n    identifier: 0x19f4d06b\n    extends: _sensor\n    status: experimental\n\n## Registers\n\n    ro kinematics @ reading {\n        x: i16.16 cm\n        y: i16.16 cm\n        vx: i16.16 cm/s\n        vy: i16.16 cm/s\n        heading: i16.16 °\t\t\n    }\n    \nThe current position and orientation of the robot.\n"},{"classIdentifier":433938742,"shortId":"satelittenavigationsystem","source":"# Satellite Navigation System\n\n    identifier: 0x19dd6136\n    extends: _sensor\n    camel: satNav\n    status: experimental\n\nA satellite-based navigation system like GPS, Gallileo, ...\n\n## Registers\n\n    ro position @ reading {\n        timestamp: u64 ms\n        latitude: i9.23 lat { absolute_min=-90, absolute_max=90 }\n        longitude: i9.23 lon { absolute_min=-180, absolute_max=180 }\n        accuracy: u16.16 m\n        altitude: i26.6 m\n        altitudeAccuracy: u16.16 m\n    }\n\nReported coordinates, geometric altitude and time of position. Altitude accuracy is 0 if not available.\n\n    rw enabled: bool @ intensity\n\nEnables or disables the GPS module\n\n## Events\n\n    event inactive @ inactive\n\nThe module is disabled or lost connection with satellites.\n"},{"classIdentifier":496034245,"shortId":"sensoraggregator","source":"# Sensor Aggregator\n\n    identifier: 0x1d90e1c5\n    status: experimental\n\nAggregate data from multiple sensors into a single stream\n(often used as input to machine learning models on the same device, see model runner service).\n\n## Registers\n\n    enum SampleType : u8 {\n        U8 = 0x08\n        I8 = 0x88\n        U16 = 0x10\n        I16 = 0x90\n        U32 = 0x20\n        I32 = 0xA0\n    }\n    rw inputs @ 0x80 {\n        sampling_interval: u16 ms\n        samples_in_window: u16\n        reserved: u32\n    repeats:\n        device_id: devid\n        service_class: u32\n        service_num: u8\n        sample_size: u8 B\n        sample_type: SampleType\n        sample_shift: i8\n    }\n\nSet automatic input collection.\nThese settings are stored in flash.\n\n    ro num_samples: u32 @ 0x180\n\nNumber of input samples collected so far.\n\n    ro sample_size: u8 B @ 0x181\n\nSize of a single sample.\n\n    rw streaming_samples: u32 # @ 0x81\n\nWhen set to `N`, will stream `N` samples as `current_sample` reading.\n\n    ro current_sample: bytes @ reading\n\nLast collected sample.\n"},{"classIdentifier":297461188,"shortId":"serial","source":"# Serial\n\n    identifier: 0x11bae5c4\n    tags: io\n    \nAn asynchronous serial communication service capable of sending and receiving buffers of data.\nSettings default to 115200 baud 8N1.\n\n## Registers\n\n    rw connected: bool @ intensity\n    \nIndicates if the serial connection is active.\n\n    ro connection_name?: string @ 0x181\n\nUser-friendly name of the connection.\n\n    rw baud_rate = 115200: u32 baud @ 0x80\n    \nA positive, non-zero value indicating the baud rate at which serial communication is be established.\n\n    rw data_bits = 8: u8 { absolute_min: 7, absolute_max: 8 } # @ 0x81\n    \nThe number of data bits per frame. Either 7 or 8.\n\n    rw stop_bits = 1: u8 # { absolute_min: 1, absolute_max: 2 } @ 0x82\n    \nThe number of stop bits at the end of a frame. Either 1 or 2.\n\n    enum ParityType: u8 {\n      None = 0,\n      Even = 1,\n      Odd = 2\n    }\n    rw parity_mode = 0: ParityType @ 0x83\n\nThe parity mode.\n\n    rw buffer_size: u8 # @ 0x84\n    \nA positive, non-zero value indicating the size of the read and write buffers that should be created.\n\n## Commands\n\n    unique command send @ 0x80 {\n        data: bytes\n    }\n\nSend a buffer of data over the serial transport.\n\n    report received @ 0x80 {\n       data: bytes\n    }\n    \nRaised when a buffer of data is received.\n"},{"classIdentifier":318542083,"shortId":"servo","source":"# Servo\n\n    identifier: 0x12fc9103\n    tags: C\n    status: stable\n\nServo is a small motor with arm that can be pointing at a specific direction.\nTypically a servo angle is between 0° and 180° where 90° is the middle resting position.\n\nThe `min_pulse/max_pulse` may be read-only if the servo is permanently affixed to its Jacdac controller.\n\n## Registers\n\n    rw angle: i16.16 ° { typical_min=0, typical_max=180 } @ value\n\nSpecifies the angle of the arm (request).\n\n    rw enabled: bool @ intensity\n\nTurn the power to the servo on/off.\n\n    rw offset: i16.16 ° @ 0x81\n\nCorrection applied to the angle to account for the servo arm drift.\n\n    const min_angle: i16.16 ° @ min_value\n\nLowest angle that can be set, typically 0 °.\n\n    rw min_pulse? = 500: u16 us @ 0x83\n\nThe length of pulse corresponding to lowest angle.\n\n    const max_angle: i16.16 ° @ max_value\n\nHighest angle that can be set, typically 180°.\n\n    rw max_pulse? = 2500: u16 us @ 0x85\n\nThe length of pulse corresponding to highest angle.\n\n    const stall_torque?: u16.16 kg/cm @ 0x180\n\nThe servo motor will stop rotating when it is trying to move a `stall_torque` weight at a radial distance of `1.0` cm.\n\n    const response_speed?: u16.16 s/60° @ 0x181\n\nTime to move 60°.\n\n    ro actual_angle?: i16.16 ° @ reading\n\nThe current physical position of the arm, if the device has a way to sense the position.\n"},{"classIdentifier":285727818,"shortId":"settings","source":"# Settings\n\n    identifier: 0x1107dc4a\n    camel: settings\n    status: experimental\n\nNon-volatile key-value storage interface for storing settings.\n\n## Secrets\n\nEntries with keys starting with `$` are considered secret.\nThey can be written normally, but they read as a single `0` byte,\nunless they are empty, in which case the value returned is also empty.\nThese are typically used by other services on the same device.\n\n## Commands\n\n    command get @ 0x80 {\n        key: string\n    }\n    report {\n        key: string0\n        value: bytes\n    }\n\nGet the value of given setting. If no such entry exists, the value returned is empty.\n\n    restricted command set @ 0x81 {\n        key: string0\n        value: bytes\n    }\n\nSet the value of a given setting.\n\n    restricted command delete @ 0x84 {\n        key: string\n    }\n\nDelete a given setting.\n\n    command list_keys @ 0x82 {\n        results: pipe\n    }\n    pipe report listed_key {\n        key: string\n    }\n\nReturn keys of all settings.\n\n    command list @ 0x83 {\n        results: pipe\n    }\n    pipe report listed_entry {\n        key: string0\n        value: bytes\n    }\n\nReturn keys and values of all settings.\n\n    restricted command clear @ 0x85 { }\n\nClears all keys.\n\n## Events\n\n    event change @ change\n\nNotifies that some setting have been modified.\n"},{"classIdentifier":425810167,"shortId":"sevensegmentdisplay","source":"# 7-segment display\n\n    identifier: 0x196158f7\n    camel:sevenSegmentDisplay\n    group: display\n    tags: 8bit\n    status: rc\n\nA 7-segment numeric display, with one or more digits.\n\n## Registers\n\n    lowlevel rw digits: bytes bitset @ value\n\nEach byte encodes the display status of a digit using,\nwhere lowest bit 0 encodes segment `A`, bit 1 encodes segments `B`, ..., bit 6 encodes segments `G`, and bit 7 encodes the decimal point (if present).\nIf incoming `digits` data is smaller than `digit_count`, the remaining digits will be cleared.\nThus, sending an empty `digits` payload clears the screen.\n\n```text\nGFEDCBA DP\n - A -\n F   B\n |   |\n - G -\n |   |\n E   C   _\n |   |  |DP|\n - D -   -\n```\n\n    rw brightness?: u0.16 / @ intensity\n\nControls the brightness of the LEDs. `0` means off.\n\n    rw double_dots?: bool @ 0x80\n\nTurn on or off the column LEDs (separating minutes from hours, etc.) in of the segment.\nIf the column LEDs is not supported, the value remains false.\n\n    const digit_count: u8 @ 0x180\n\nThe number of digits available on the display.\n\n    const decimal_point?: bool @ 0x181\n\nTrue if decimal points are available (on all digits).\n\n## Commands\n\n    client command set_number @ 0x80 {\n        value: f64\n    }\n\nShows the number on the screen using the decimal dot if available.\n"},{"classIdentifier":491430835,"shortId":"soilmoisture","source":"# Soil moisture\n\n    identifier: 0x1d4aa3b3\n    extends: _sensor\n    tags: 8bit\n    group: environment\n    status: stable\n\nA soil moisture sensor.\n\n## Registers\n\n    ro moisture: u0.16 / { preferred_interval=1000 } @ reading\n\nIndicates the wetness of the soil, from `dry` to `wet`.\n\n    ro moisture_error?: u0.16 /  @ reading_error\n\nThe error on the moisture reading.\n\n    enum Variant: u8 {\n         Resistive = 1\n         Capacitive = 2\n    }\n    const variant?: Variant @ variant\n\nDescribe the type of physical sensor.\n"},{"classIdentifier":387392458,"shortId":"solenoid","source":"# Solenoid\n\n    identifier: 0x171723ca\n    tags: 8bit\n    status: rc\n\nA push-pull solenoid is a type of relay that pulls a coil when activated.\n\n## Registers\n\n    rw pulled: bool @ intensity\n\nIndicates whether the solenoid is energized and pulled (on) or pushed (off).\n\n    enum Variant: u8 {\n        PushPull = 1,\n        Valve = 2,\n        Latch = 3\n    }\n    const variant?: Variant @ variant\n\nDescribes the type of solenoid used.\n"},{"classIdentifier":346888797,"shortId":"soundlevel","source":"# Sound level\n\n     identifier: 0x14ad1a5d\n     extends: _sensor\n     group: sound\n     tags: 8bit\n     status: rc\n\nA sound level detector sensor, gives a relative indication of the sound level.\n\n## Registers\n\n    ro sound_level: u0.16 / @ reading\n\nThe sound level detected by the microphone\n\n    rw enabled: bool @ intensity\n\nTurn on or off the microphone.\n\n    rw loud_threshold: u0.16 / @ active_threshold\n\nSet level at which the `loud` event is generated.\n\n    rw quiet_threshold: u0.16 / @ inactive_threshold\n\nSet level at which the `quiet` event is generated.\n\n## Events\n\n    event loud @ active\n\nGenerated when a loud sound is detected.\n\n    event quiet @ inactive\n\nGenerated low level of sound is detected.\n"},{"classIdentifier":335795000,"shortId":"soundplayer","source":"# Sound player\n\nA device that can play various sounds stored locally. This service is typically paired with a ``storage`` service for storing sounds.\n\n    identifier: 0x1403d338\n    group: sound\n    status: rc\n\n## Registers\n\n    rw volume?: u0.16 / @ intensity\n\nGlobal volume of the output. ``0`` means completely off. This volume is mixed with each play volumes.\n\n## Commands\n\n    command play @ 0x80 {\n        name: string\n    }\n\nStarts playing a sound.\n\n    command cancel @ 0x81 {}\n\nCancel any sound playing.\n\n    command list_sounds @ 0x82 {\n        sounds_port: pipe\n    }\n    pipe report list_sounds_pipe {\n       duration: u32 ms\n       name: string\n    }\n\nReturns the list of sounds available to play.\n"},{"classIdentifier":460504912,"shortId":"soundrecorderwithplayback","source":"# Sound Recorder with Playback\n\n    identifier: 0x1b72bf50\n    group: sound\n    tags: 8bit, padauk\n    \nA record and replay module. You can record a few seconds of audio and play it back.\n\n## Commands\n\n    command play @ 0x80 {}\n    \nReplay recorded audio.\n    \n    command record @ 0x81 {\n        duration: u16 ms\n    }\n    \nRecord audio for N milliseconds.\n\n    command cancel @ 0x82 {}\n    \nCancel record, the `time` register will be updated by already cached data.\n\n## Registers\n\n    enum Status: u8 {\n        Idle = 0\n        Recording = 1\n        Playing = 2\n    }\n    ro status: Status @ 0x180\n\nIndicate the current status \n\n    ro time: u16 ms @ 0x181\n    \nMilliseconds of audio recorded.\n\n    rw volume?: u0.8 / @ intensity\n\nPlayback volume control \n\n"},{"classIdentifier":360365086,"shortId":"soundspectrum","source":"# Sound Spectrum\n\n    identifier: 0x157abc1e\n    extends: _sensor\n    group: sound\n    status: experimental\n\nA microphone that analyzes the sound specturm\n\n## Registers\n\n    ro frequency_bins: bytes @ reading\n\nThe computed frequency data.\n\n    rw enabled: bool @ intensity\n\nTurns on/off the micropohone.\n\n    rw fft_pow2_size = 5: u8 { absolute_min=2, absolute_max=7 } @ 0x80\n\nThe power of 2 used as the size of the FFT to be used to determine the frequency domain.\n\n    rw min_decibels: i16 dB @ 0x81\n\nThe minimum power value in the scaling range for the FFT analysis data\n\n    rw max_decibels: i16 dB @ 0x82\n\nThe maximum power value in the scaling range for the FFT analysis data\n\n    rw smoothing_time_constant = 0.8: u0.8 / @ 0x83\n\nThe averaging constant with the last analysis frame.\nIf `0` is set, there is no averaging done, whereas a value of `1` means \"overlap the previous and current buffer quite a lot while computing the value\".\n"},{"classIdentifier":302307733,"shortId":"speechsynthesis","source":"# Speech synthesis\n\n     identifier: 0x1204d995\n     status: rc\n\nA speech synthesizer\n\n## Registers\n\n    rw enabled: bool @ intensity\n\nDetermines if the speech engine is in a non-paused state.\n\n    rw lang?: string @ 0x80\n\nLanguage used for utterances as defined in https://www.ietf.org/rfc/bcp/bcp47.txt.\n\n    rw volume? = 1: u0.8 / @ 0x81\n\nVolume for utterances.\n\n    rw pitch? = 1: u16.16 { absolute_max=2 } @ 0x82\n\nPitch for utterances\n\n    rw rate? = 1: u16.16 { absolute_min=0.1, absolute_max=10 } @ 0x83\n\nRate for utterances\n\n## Commands\n\n    unique command speak @ 0x80 {\n        text: string\n    }\n\nAdds an utterance to the utterance queue; it will be spoken when any other utterances queued before it have been spoken.\n\n    command cancel @ 0x81 {}\n\nCancels current utterance and all utterances from the utterance queue.\n"},{"classIdentifier":450008066,"shortId":"switch","source":"# Switch\n\n    identifier: 0x1ad29402\n    extends: _sensor\n    group: button\n    tags: 8bit, input\n    status: rc\n\nA switch, which keeps its position.\n\n## Registers\n\n    ro active: bool @ reading\n\nIndicates whether the switch is currently active (on).\n\n    enum Variant: u8 {\n        Slide = 1\n        Tilt = 2\n        PushButton = 3\n        Tactile = 4\n        Toggle = 5\n        Proximity = 6\n        Magnetic = 7\n        FootButton = 8\n    }\n    const variant?: Variant @ variant\n\nDescribes the type of switch used.\n\n## Events\n\n    event on @ active\n\nEmitted when switch goes from `off` to `on`.\n\n    event off @ inactive\n\nEmitted when switch goes from `on` to `off`.\n"},{"classIdentifier":457422603,"shortId":"tcp","source":"# TCP\n\n    identifier: 0x1b43b70b\n    camel: tcp\n    status: experimental\n\nData transfer over TCP/IP and TLS stream sockets.\n\n## Commands\n\n    command open @ 0x80 {\n        inbound: pipe\n    }\n    report {\n        outbound_port: pipe_port\n    }\n\nOpen pair of pipes between network peripheral and a controlling device. In/outbound refers to direction from/to internet.\n\n## Pipes\n\n    meta pipe command open_ssl @ 0x01 {\n        tcp_port: u16\n        hostname: string\n    }\n\nOpen an SSL connection to a given host:port pair. Can be issued only once on given pipe.\nAfter the connection is established, an empty data report is sent.\nConnection is closed by closing the pipe.\n\n    pipe command outdata {\n        data: bytes\n    }\n\nBytes to be sent directly over an established TCP or SSL connection.\n\n    pipe report indata {\n        data: bytes\n    }\n\nBytes read directly from directly over an established TCP or SSL connection.\n\n    enum TcpError : i32 {\n        InvalidCommand = 1\n        InvalidCommandPayload = 2\n    }\n    meta pipe report error @ 0x00 {\n        error: TcpError\n    }\n\nReported when an error is encountered. Negative error codes come directly from the SSL implementation.\n"},{"classIdentifier":337754823,"shortId":"temperature","source":"# Temperature\n\n    identifier: 0x1421bac7\n    extends: _sensor\n    tags: C, 8bit\n    group: environment\n    status: stable\n\nA thermometer measuring outside or inside environment.\n\n## Registers\n\n    ro temperature: i22.10 °C { preferred_interval=1000 } @ reading\n\nThe temperature.\n\n    const min_temperature: i22.10 °C @ min_reading\n\nLowest temperature that can be reported.\n\n    const max_temperature: i22.10 °C @ max_reading\n\nHighest temperature that can be reported.\n\n    ro temperature_error?: u22.10 °C  @ reading_error\n\nThe real temperature is between `temperature - temperature_error` and `temperature + temperature_error`.\n\n    enum Variant: u8 {\n        Outdoor = 1,\n        Indoor = 2,\n        Body = 3,\n    }\n    const variant?: Variant @ variant\n\nSpecifies the type of thermometer.\n"},{"classIdentifier":294829516,"shortId":"timeseriesaggregator","source":"# Timeseries Aggregator\n\n    identifier: 0x1192bdcc\n    group: iot\n    tags: infrastructure, devicescript\n    restricted: true\n    status: experimental\n\nSupports aggregating timeseries data (especially sensor readings)\nand sending them to a cloud/storage service.\nUsed in DeviceScript.\n\nNote that `f64` values are not necessarily aligned.\n\n## Commands\n\n    command clear @ 0x80 {}\n\nRemove all pending timeseries.\n\n    command update @ 0x83 {\n        value: f64\n        label: string\n    }\n\nAdd a data point to a timeseries.\n\n    command set_window @ 0x84 {\n        duration: u32 ms\n        label: string\n    }\n\nSet aggregation window.\nSetting to `0` will restore default.\n\n    command set_upload @ 0x85 {\n        upload: bool\n        label: string\n    }\n\nSet whether or not the timeseries will be uploaded to the cloud.\nThe `stored` reports are generated regardless.\n\n    report stored @ 0x90 {\n        num_samples: u32 #\n        padding: u8[4]\n        avg: f64\n        min: f64\n        max: f64\n        start_time: u32 ms\n        end_time: u32 ms\n        label: string\n    }\n\nIndicates that the average, minimum and maximum value of a given\ntimeseries are as indicated.\nIt also says how many samples were collected, and the collection period.\nTimestamps are given using device's internal clock, which will wrap around.\nTypically, `end_time` can be assumed to be \"now\".\n`end_time - start_time == window`\n\n# Registers\n\n    volatile ro now: u32 us @ 0x180\n\nThis can queried to establish local time on the device.\n\n    rw fast_start = 1: bool @ 0x80\n\nWhen `true`, the windows will be shorter after service reset and gradually extend to requested length.\nThis is ensure valid data is being streamed in program development.\n\n    rw default_window = 60000: u32 ms @ 0x81\n\nWindow for timeseries for which `set_window` was never called.\nNote that windows returned initially may be shorter if `fast_start` is enabled.\n\n    rw default_upload = 1: bool @ 0x82\n\nWhether labelled timeseries for which `set_upload` was never called should be automatically uploaded.\n\n    rw upload_unlabelled = 1: bool @ 0x83\n\nWhether automatically created timeseries not bound in role manager should be uploaded.\n\n    rw sensor_watchdog_period: u32 ms @ 0x84\n\nIf no data is received from any sensor within given period, the device is rebooted.\nSet to `0` to disable (default).\nUpdating user-provided timeseries does not reset the watchdog.\n"},{"classIdentifier":365137307,"shortId":"trafficlight","source":"# Traffic Light\n\n    identifier: 0x15c38d9b\n    tags: 8bit\n    status: rc\n\nControls a mini traffic with a red, orange and green LED.\n\n## Registers\n\n    rw red: bool @ 0x80\n\nThe on/off state of the red light.\n\n    rw yellow: bool @ 0x81\n\nThe on/off state of the yellow light.\n\n    rw green: bool @ 0x82\n\nThe on/off state of the green light.\n"},{"classIdentifier":312849815,"shortId":"tvoc","source":"# Total Volatile organic compound\n\nMeasures equivalent Total Volatile Organic Compound levels.\n\n    identifier: 0x12a5b597\n    extends: _sensor\n    camel: tvoc\n    group: environment\n    tags: 8bit\n    status: stable\n\n## Registers\n\n    ro TVOC: u22.10 ppb { absolute_min=0, typical_max=1187 }  @ reading\n\nTotal volatile organic compound readings in parts per billion.\n\n    ro TVOC_error?: u22.10 ppb @ reading_error\n\nError on the reading data\n\n    const min_TVOC: u22.10 ppb @ min_reading\n\nMinimum measurable value\n\n    const max_TVOC: u22.10 ppb @ max_reading\n\nMinimum measurable value.\n"},{"classIdentifier":272387813,"shortId":"uniquebrain","source":"# Unique Brain\n\n    identifier: 0x103c4ee5\n    tags: infrastructure\n    status: stable\n\nThe presence of this service indicates that this device is a client that controls sensors and actuators.\nIf a unique brain detects another younger unique brain (determined by reset counter in announce packets),\nthen the older brain should switch into proxy mode.\n"},{"classIdentifier":418781770,"shortId":"usbbridge","source":"# USB Bridge\n\n    identifier: 0x18f61a4a\n    camel: usbBridge\n    tags: infrastructure\n    status: rc\n\nThis service is normally not announced or otherwise exposed on the serial bus.\nIt is used to communicate with a USB-Jacdac bridge at the USB layer.\nThe host sends broadcast packets to this service to control the link layer.\nThe device responds with broadcast reports (no-one else does that).\nThese packets are not forwarded to the UART Jacdac line.\n\nPackets are sent over USB Serial (CDC).\nThe host shall set the CDC to 1Mbaud 8N1\n(even though in some cases the USB interface is connected directly to the MCU and line settings are\nignored).\n\nThe CDC line carries both Jacdac frames and serial logging output.\nJacdac frames have valid CRC and are framed by delimeter characters and possibly fragmented.\n\n`0xFE` is used as a framing byte.\nNote that bytes `0xF8`-`0xFF` are always invalid UTF-8.\n`0xFF` occurs relatively often in Jacdac packets, so is not used for framing.\n\nThe following sequences are supported:\n\n* `0xFE 0xF8` - literal 0xFE\n* `0xFE 0xF9` - reserved; ignore\n* `0xFE 0xFA` - indicates that some serial logs were dropped at this point\n* `0xFE 0xFB` - indicates that some Jacdac frames were dropped at this point\n* `0xFE 0xFC` - Jacdac frame start\n* `0xFE 0xFD` - Jacdac frame end\n\n0xFE followed by any other byte:\n* in serial, should be treated as literal 0xFE (and the byte as itself, unless it's 0xFE)\n* in frame data, should terminate the current frame fragment,\n  and ideally have all data (incl. fragment start) in the current frame fragment treated as serial\n\n    enum QByte: u8 {\n        Magic = 0xFE\n        LiteralMagic = 0xF8\n        Reserved = 0xF9\n        SerialGap = 0xFA\n        FrameGap = 0xFB\n        FrameStart = 0xFC\n        FrameEnd = 0xFD\n    }\n\n## Commands\n\n    command disable_packets @ 0x80 {}\n    report {}\n\nDisables forwarding of Jacdac packets.\n\n    command enable_packets @ 0x81 {}\n    report {}\n\nEnables forwarding of Jacdac packets.\n\n    command disable_log @ 0x82 {}\n    report {}\n\nDisables forwarding of serial log messages.\n\n    command enable_log @ 0x83 {}\n    report {}\n\nEnables forwarding of serial log messages.\n"},{"classIdentifier":527306128,"shortId":"uvindex","source":"# UV index\n\n    identifier: 0x1f6e0d90\n    extends: _sensor\n    camel: uvIndex\n    group: environment\n    tags: 8bit\n    status: stable\n\nThe UV Index is a measure of the intensity of ultraviolet (UV) rays from the Sun.\n\n## Registers\n\n    ro uv_index: u16.16 uv { preferred_interval=1000, typical_max=11 } @ reading\n\nUltraviolet index, typically refreshed every second.\n\n    ro uv_index_error?: u16.16 uv @ reading_error\n\nError on the UV measure.\n\n    enum Variant: u8 {\n        UVA_UVB = 1,\n        Visible_IR = 2\n    }\n    const variant?: Variant @ variant\n\nThe type of physical sensor and capabilities.\n"},{"classIdentifier":563381279,"shortId":"verifiedtelemetrysensor","source":"# Verified Telemetry\n\n    identifier: 0x2194841f\n    status: deprecated\n\nA mixin service that exposes verified telemetry information for a sensor (see https://github.com/Azure/Verified-Telemetry/tree/main/PnPModel).\n\n## Registers\n\n    enum Status : u8 {\n        Unknown = 0\n        Working = 1\n        Faulty = 2        \n    }\n    ro telemetry_status: Status @ 0x180\n    \nReads the telemetry working status, where ``true`` is working and ``false`` is faulty.\n\n    rw telemetry_status_interval?: u32 ms @ 0x080\n\nSpecifies the interval between computing the fingerprint information.\n\n    enum FingerprintType: u8 {\n        FallCurve = 1\n        CurrentSense = 2\n        Custom = 3\n    }\n    const fingerprint_type: FingerprintType @ 0x181\n\nType of the fingerprint.\n\n    ro fingerprint_template @ 0x182 {\n        confidence: u16 %\n        template: bytes\n    }\n\nTemplate Fingerprint information of a working sensor.\n\n## Commands\n\n    command reset_fingerprint_template @ 0x080 {}\n\nThis command will clear the template fingerprint of a sensor and collect a new template fingerprint of the attached sensor.\n\n    unique command retrain_fingerprint_template @ 0x081 {}\n\nThis command will append a new template fingerprint to the `fingerprintTemplate`. Appending more fingerprints will increase the accuracy in detecting the telemetry status.\n\n## Events\n\n    event telemetry_status_change @ change { \n        telemetry_status: Status\n    }\n    \nThe telemetry status of the device was updated.\n\n    event fingerprint_template_change @ 0x80 { }\n    \nThe fingerprint template was updated\n"},{"classIdentifier":406832290,"shortId":"vibrationmotor","source":"# Vibration motor\n\n    identifier: 0x183fc4a2\n    status: stable\n\nA vibration motor.\n\n## Commands\n\n    command vibrate @ 0x80 {\n    repeats:\n        duration: u8 8ms,\n        intensity: u0.8 /\n    }\n\nStarts a sequence of vibration and pauses. To stop any existing vibration, send an empty payload.\n\n## Registers\n\n    const max_vibrations?: u8 @ 0x180\n\nThe maximum number of vibration sequences supported in a single packet.\n\n"},{"classIdentifier":343630573,"shortId":"waterlevel","source":"# Water level\n\n    identifier: 0x147b62ed\n    extends: _sensor\n    tags: 8bit\n    status: rc\n\nA sensor that measures liquid/water level.\n\n## Registers\n\n    ro level: u0.16 / @ reading\n\nThe reported water level.\n\n    ro level_error?: u0.16 / @ reading_error\n\nThe error rage on the current reading\n\n    enum Variant: u8 {\n        Resistive = 1\n        ContactPhotoElectric = 2\n        NonContactPhotoElectric = 3\n    }\n    const variant?: Variant @ variant\n\nThe type of physical sensor.\n"},{"classIdentifier":525160512,"shortId":"weightscale","source":"# Weight Scale\n\n    identifier: 0x1f4d5040\n    extends: _sensor\n    tags: 8bit\n    status: rc\n\nA weight measuring sensor.\n\n## Registers\n\n    ro weight: u16.16 kg @ reading\n\nThe reported weight.\n\n    ro weight_error?: u16.16 kg @ reading_error\n\nThe estimate error on the reported reading.\n\n    rw zero_offset?: u16.16 kg @ 0x80\n    \nCalibrated zero offset error on the scale, i.e. the measured weight when nothing is on the scale.\nYou do not need to subtract that from the reading, it has already been done.\n\n    rw gain?: u16.16 @ 0x81\n\nCalibrated gain on the weight scale error.\n\n    const max_weight?: u16.16 kg @ max_reading\n\nMaximum supported weight on the scale.\n\n    const min_weight?: u16.16 kg @ min_reading\n\nMinimum recommend weight on the scale.\n\n    const weight_resolution?: u16.16 kg @ reading_resolution\n\nSmallest, yet distinguishable change in reading.\n\n    enum Variant: u8 {\n        Body = 1\n        Food = 2\n        Jewelry = 3\n    }\n    const variant?: Variant @ variant\n\nThe type of physical scale\n\n## Commands\n\n    command calibrate_zero_offset @ 0x80 { }\n\nCall this command when there is nothing on the scale. If supported, the module should save the calibration data.\n\n    command calibrate_gain @ 0x81 {\n        weight: u22.10 g\n    }\n\nCall this command with the weight of the thing on the scale.\n"},{"classIdentifier":413852154,"shortId":"wifi","source":"# WIFI\n\n    identifier: 0x18aae1fa\n    camel: wifi\n    group: iot\n    status: rc\n\nDiscovery and connection to WiFi networks. Separate TCP service can be used for data transfer.\n\n## Connection\n\nThe device controlled by this service is meant to connect automatically, once configured.\nTo that end, it keeps a list of known WiFi networks, with priorities and passwords.\nIt will connect to the available network with numerically highest priority,\nbreaking ties in priority by signal strength (typically all known networks have priority of `0`).\nIf the connection fails (due to wrong password, radio failure, or other problem)\nan `connection_failed` event is emitted, and the device will try to connect to the next eligible network.\nWhen networks are exhausted, the scan is performed again and the connection process restarts.\n\nUpdating networks (setting password, priorties, forgetting) does not trigger an automatic reconnect.\n\n## Captive portals\n\nIf the Wifi is not able to join an AP because it needs to receive a password, it may decide to enter a mode\nwhere it waits for user input. Typical example of this mode would be a captive portal or waiting for a BLE interaction.\nIn that situation, the `status_code` should set to `WaitingForInput`.\n\n## Commands\n\n    flags APFlags : u32 {\n        HasPassword = 0x0001\n        WPS = 0x0002\n        HasSecondaryChannelAbove = 0x0004\n        HasSecondaryChannelBelow = 0x0008\n        IEEE_802_11B = 0x0100\n        IEEE_802_11A = 0x0200\n        IEEE_802_11G = 0x0400\n        IEEE_802_11N = 0x0800\n        IEEE_802_11AC = 0x1000\n        IEEE_802_11AX = 0x2000\n        IEEE_802_LongRange = 0x8000\n    }\n    command last_scan_results @ 0x80 {\n        results: pipe\n    }\n    pipe report results {\n        flags: APFlags\n        reserved: u32\n        rssi: i8 dB {typical_min = -100, typical_max = -20}\n        channel: u8 {typical_min = 1, typical_max = 13}\n        bssid: u8[6]\n        ssid: string {max_bytes = 33}\n    }\n\nReturn list of WiFi network from the last scan.\nScans are performed periodically while not connected (in particular, on startup and after current connection drops),\nas well as upon `reconnect` and `scan` commands.\n\n    command add_network @ 0x81 {\n        ssid: string0\n        password?: string0\n    }\n\nAutomatically connect to named network if available. Also set password if network is not open.\n\n    command reconnect @ 0x82 {}\n\nEnable the WiFi (if disabled), initiate a scan, wait for results, disconnect from current WiFi network if any,\nand then reconnect (using regular algorithm, see `set_network_priority`).\n\n    command forget_network @ 0x83 {\n        ssid: string\n    }\n\nPrevent from automatically connecting to named network in future.\nForgetting a network resets its priority to `0`.\n\n    command forget_all_networks @ 0x84 {}\n\nClear the list of known networks.\n\n    command set_network_priority @ 0x85 {\n        priority: i16\n        ssid: string\n    }\n\nSet connection priority for a network.\nBy default, all known networks have priority of `0`.\n\n    command scan @ 0x86 {}\n\nInitiate search for WiFi networks. Generates `scan_complete` event.\n\n    command list_known_networks @ 0x87 {\n        results: pipe\n    }\n    pipe report network_results {\n        priority: i16\n        flags: i16\n        ssid: string\n    }\n\nReturn list of known WiFi networks.\n`flags` is currently always 0.\n\n## Registers\n\n    ro rssi: i8 dB {typical_min = -128, typical_max = -20, preferred_interval=15000 } @ reading\n\nCurrent signal strength. Returns -128 when not connected.\n\n    rw enabled: bool @ intensity\n\nDetermines whether the WiFi radio is enabled. It starts enabled upon reset.\n\n    ro ip_address: bytes {max_bytes = 16} @ 0x181\n\n0, 4 or 16 byte buffer with the IPv4 or IPv6 address assigned to device if any.\n\n    const eui_48: bytes {max_bytes = 6} @ 0x182\n\nThe 6-byte MAC address of the device. If a device does MAC address randomization it will have to \"restart\".\n\n    ro ssid: string {max_bytes = 32} @ 0x183\n\nSSID of the access-point to which device is currently connected.\nEmpty string if not connected.\n\n## Events\n\n    event got_ip @ active\n\nEmitted upon successful join and IP address assignment.\n\n    event lost_ip @ inactive\n\nEmitted when disconnected from network.\n\n    event scan_complete @ 0x80 {\n        num_networks: u16\n        num_known_networks: u16\n    }\n\nA WiFi network scan has completed. Results can be read with the `last_scan_results` command.\nThe event indicates how many networks where found, and how many are considered\nas candidates for connection.\n\n    event networks_changed @ 0x81\n\nEmitted whenever the list of known networks is updated.\n\n    event connection_failed @ 0x82 {\n        ssid: string\n    }\n\nEmitted when when a network was detected in scan, the device tried to connect to it\nand failed.\nThis may be because of wrong password or other random failure.\n"},{"classIdentifier":409725227,"shortId":"winddirection","source":"# Wind direction\n\nA sensor that measures wind direction.\n\n    identifier: 0x186be92b\n    extends: _sensor\n    tags: 8bit\n    status: rc\n    group: environment\n\n## Registers\n\n    ro wind_direction: u16 ° { absolute_min=0, absolute_max=359, preferred_interval=1000 } @ reading\n\nThe direction of the wind.\n\n    ro wind_direction_error?: u16 ° @ reading_error\n\nError on the wind direction reading\n\n"},{"classIdentifier":458824639,"shortId":"windspeed","source":"# Wind speed\n\nA sensor that measures wind speed.\n\n    identifier: 0x1b591bbf\n    extends: _sensor\n    tags: 8bit\n    status: rc\n    group: environment\n\n## Registers\n\n    ro wind_speed: u16.16 m/s { preferred_interval=60000 } @ reading\n\nThe velocity of the wind.\n\n    ro wind_speed_error?: u16.16 m/s @ reading_error\n\nError on the reading\n\n    const max_wind_speed?: u16.16 m/s @ max_reading\n\nMaximum speed that can be measured by the sensor.\n"},{"classIdentifier":330775038,"shortId":"wssk","source":"# WSSK\n\n    identifier: 0x13b739fe\n    group: iot\n    tags: infrastructure, devicescript\n    camel: wssk\n\nDefines a binary protocol for IoT devices to talk to DeviceScript gateway over encrypted websockets.\nThis is not used as a regular Jacdac service.\n\n## Commands\n\n    report error @ 0xff {\n        message: string\n    }\n\nIssued when a command fails.\n\n    enum StreamingType : u16 {\n        Jacdac = 0x0001\n        Dmesg = 0x0002\n        Exceptions = 0x0100\n        TemporaryMask = 0x00ff\n        PermamentMask = 0xff00\n        DefaultMask = 0x0100\n    }\n\n    command set_streaming @ 0x90 {\n        status: StreamingType\n    }\n\nEnable/disable forwarding of all Jacdac frames, exception reporting, and `dmesg` streaming.\n\n    command ping_device @ 0x91 {\n        payload: bytes\n    }\n    report {\n        payload: bytes // currently not supported\n    }\n\nSend from gateway when it wants to see if the device is alive.\nThe device currently only support 0-length payload.\n\n    command ping_cloud @ 0x92 {\n        payload: bytes\n    }\n    report {\n        payload: bytes\n    }\n\nSend from device to gateway to test connection.\n\n    command get_hash @ 0x93 {}\n    report {\n        sha256: u8[32]\n    }\n\nGet SHA256 of the currently deployed program.\n\n    command deploy_start @ 0x94 {\n        size: u32 B\n    }\n    report {}\n\nStart deployment of a new program.\n\n    command deploy_write @ 0x95 {\n        payload: bytes\n    }\n    report {}\n\nPayload length must be multiple of 32 bytes.\n\n    command deploy_finish @ 0x96 {}\n    report {}\n\nFinish deployment.\n\n    enum DataType : u8 {\n        Binary = 1\n        JSON = 2\n    }\n    command c2d @ 0x97 {\n        datatype: DataType\n        topic: string0\n        payload: bytes\n    }\n\nUpload a labelled tuple of values to the cloud.\nThe tuple will be automatically tagged with timestamp and originating device.\n\n    report d2c @ 0x98 {\n        datatype: DataType\n        topic: string0\n        payload: bytes\n    }\n\nUpload a binary message to the cloud.\n\n    command jacdac_packet @ 0x99 {\n        frame: bytes\n    }\n    report {\n        frame: bytes\n    }\n\nSent both ways.\n\n    report dmesg @ 0x9a {\n        logs: bytes\n    }\n\nThe `logs` field is string in UTF-8 encoding, however it can be split in the middle of UTF-8 code point.\nControlled via `dmesg_en`.\n\n    report exception_report @ 0x9b {\n        logs: bytes\n    }\n\nThe format is the same as `dmesg` but this is sent on exceptions only and is controlled separately via `exception_en`.\n"}]