//https://tools.ietf.org/html/rfc8798 declare namespace senml { const MIME_TYPE = "application/senml+json" type Unit = | "m" | "kg" | "g" | "s" | "A" | "K" | "cd" | "mol" | "Hz" | "rad" | "sr" | "N" | "Pa" | "J" | "W" | "C" | "V" | "F" | "Ohm" | "S" | "Wb" | "T" | "H" | "Cel" | "lm" | "lx" | "Bq" | "Gy" | "Sv" | "kat" | "m2" | "m3" | "l" | "m/s" | "m/s2" | "m3/s" | "l/s" | "W/m2" | "cd/m2" | "bit" | "bit/s" | "lat" | "lon" | "pH" | "dB" | "dBW" | "Bspl" | "count" | "/" | "%RH" | "%EL" | "EL" | "1/s" | "1/min" | "beat/min" | "beats" | "S/m" | "B" | "VA" | "VAs" | "var" | "vars" | "J/m" | "kg/m3" | "deg" type SecondaryUnit = | "ms" | "min" | "h" | "MHz" | "kW" | "kVA" | "kvar" | "Ah" | "Wh" | "kWh" | "varh" | "kvarh" | "kVAh" | "Wh/km" | "KiB" | "GB" | "Mbit/s" | "B/s" | "MB/s" | "KB" | "mV" | "mA" | "dBm" | "ug/m3" | "mm/h" | "m/h" | "ppm" | "/100" | "/1000" | "hPa" | "mm" | "cm" | "km" | "km/h" | "AudHz" interface SenMLRecord { // Base Name bn?: string // Base Time bt?: number // Base Unit bu?: Unit | SecondaryUnit // Base Value bv?: number // Base Sum bs?: number // Base Version bver?: number // Name n?: string // Unit u?: Unit | SecondaryUnit // Value v?: number // String value vs?: string // Boolean value vb?: boolean // Data value (base64) vd?: string // Sum s?: number // Time (omit for "now") t?: number // Update time ut?: number } type SenMLPack = SenMLRecord[] } declare namespace jdspec { type SMap = { [v: string]: T } /** * How a type is stored in memory. Negative values signify signed integers, positive unsigned. * Magnitude is size in bytes. 0 means unspecified length (usually 'the rest of the packet'). */ type StorageType = number /** * Unit for a field. * * Many fields have no unit (e.g. they are identifiers); in that case empty string is used. Fields that represent counts use "#". * SenML (https://www.iana.org/assignments/senml/senml.xhtml) units and secondary unit are also supported. */ type Unit = | senml.Unit | senml.SecondaryUnit | "#" | "%" | "8ms" | "AQI" | "bpm" | "cm/s" | "frac" | "hsv" | "kg/cm" | "lux" | "mWh" | "mcd" | "nT" | "nm" | "ppb" | "px" | "rgb" | "rpm" | "s/60°" | "us" | "uv" | "°" | "°/s" | "°/s2" | "°C" /** * Indicates the enderlying encoding of a string or byte buffer */ type Encoding = "JSON" | "bitset" /** * Stability status of a feature */ type StabilityStatus = "stable" | "experimental" | "deprecated" | "rc" interface ServiceMarkdownSpec { /** * Short identifier for the service, from file name. */ shortId: string /** * When written in hex, it has the form 0x1xxxxxxx (except for control service). */ classIdentifier: number /** * Markdown source */ source: string } /** * Service specification. */ interface ServiceSpec { /** * Human-readable name of the service, extracted from first H1 in markdown */ name: string /** * Name of the service, in CamelCase. */ camelName: string /** * Short name of the service, to use in name prefixes. */ shortName: string /** * Short identifier for the service, from file name. */ shortId: string /** * When written in hex, it has the form 0x1xxxxxxx (except for control service). */ classIdentifier: number /** * List of extended service types (eg. 'sensor'). * * This is for reference only. Inherited registers/commands/etc are included * in our packets object. */ extends: string[] /** * Various descriptions extracted from markdown. * * Keys can include: * - short - short service description, after name, before any subsections * - long - any remaining service description * - events - note on top of ## Events section * - registers - note on top of ## Registers section * - commands - note on top of ## Commands section * * The idea for say registers note is to include it at the end of each register * description when displaying (maybe in smaller type). */ notes: SMap /** * Enumerations defined in the service. Key is the enum name. */ enums: SMap /** Constants * * Numberical constants defined in the service. */ constants: SMap<{ value: number hex?: boolean }> /** * Registers, commands, and events defined in service. */ packets: PacketInfo[] /** * The service uses commands/registers over 0x100/0x200 */ highCommands?: boolean /** * If parsing of markdown fails, this includes the parse errors. Set to null/undefined when no errors. */ errors?: Diagnostic[] /** * Specifies the stability status of this service. */ status: StabilityStatus /** * General purpose tags */ tags: string[] /** * Recommended grouping for APIs */ group?: string /** * Set if all packets are restricted. */ restricted?: boolean /** * For custom services, specify false or a separate catalog root that supports the same routing */ catalog?: false | string } /** * Describes an enumeration. */ interface EnumInfo { /** * Name in upper camel case. */ name: string /** * Member can be combined as bit-fields. */ isFlags?: boolean /** * Other members are possible (defined with 'type' syntax). */ isExtensible?: boolean /** * How is this enum to be stored. */ storage: StorageType /** * Map from enum member name to its value. */ members: SMap /** * If present, this packet was derived from a base class. */ derived?: string } /** * Various ways of interfacing with a service. * * commands are sent to the service, which responds with reports. * * rw register maps to two commands: one for getting its value (along with corresponding report) * and one for setting the value. * * ro registers cannot be written. * * const registers cannot be written, and also don't change at least until reset. * * events are passed inside of event report, and can be also piped via streams. */ type PacketKind = | "report" | "command" | "const" | "ro" | "rw" | "event" | "pipe_command" | "pipe_report" | "meta_pipe_command" | "meta_pipe_report" /** * Spec for a report/command/register or event. */ interface PacketInfo { /** * Kind of this packet. */ kind: PacketKind /** * Name in lower case snake case. */ name: string /** * Kind of pipe this packet establishes or is valid on. */ pipeType?: string /** * This either a command/report number, an identifier for event, or a register number, which is combined * with 0x1000/0x2000 to get command for reading/writing. */ identifier: number /** * If present, this packet has identifier named after base class. */ identifierName?: string /** * Text that follows the definition in markdown. */ description: string /** * Binary layout of arguments of this packet (if any). * * Many interfaces will have only a single field, named "_" - the spec language * has a shorthand syntax for that. */ fields: PacketMember[] /** * If present and true, the binary layout of fields does not follow natural alignment * and need to have PACKED C attribute or similar applied. * These packets need to be specially marked in the specs. */ packed?: boolean /** * If applicable, the pack/unpack string to decode the data */ packFormat?: string /** * If present and true, the handling of given packet is optional and can be left out by implementation. */ optional?: boolean /** * If present, this packet was derived from a base class. */ derived?: string /** * If present and true, this is a report that has the same identifier as preceding command. */ secondary?: boolean /** * If present and true, this command is followed by its report. */ hasReport?: boolean /** * This register supports the Jacdac infrastructure and is not meant to be reported outside the Jacdac bus. */ internal?: boolean /** * For registers, preffere interval (ms) to refresh the register */ preferredInterval?: number /** * For registers, is it volatile (changes without any prompting) */ volatile?: boolean /** * This packet is not to be allowed from the bus, nor should it be forwarded to the bus. */ restricted?: boolean /** * This member is not implemented on the server and typically is 'simulated' by clients */ client?: boolean /** * This member is designed to support small servers and typically is not exposed by high-level client. */ lowLevel?: boolean /** * This action is not idempotent. */ unique?: boolean } /** * Spec for a single entry in packet binary layout. */ interface PacketMember { /** * Name of member. Can be "_" if there's only a single member. */ name: string /** * Type specifying how to interpret data. All values are little endian. * * This can be one of: * - u8, u16, u32, u64, i8, i16, i32, i64, bytes, bool * - name of an enum defined in the current service * - string - UTF-8 encoded string * - string0 - NUL-terminated UTF-8 encoded string */ type: string /** * Type is one of u8, u16, u32, u64, i8, i16, i32, i64, bytes. */ isSimpleType?: boolean /** * If present and set, indicates that the number is IEEE little endian float (16, 32 or 64 bit long). */ isFloat?: boolean /** * If present and set, indicates that the number field can be skipped. */ isOptional?: boolean /** * If present, specifies the raw value should be divided by (1 << shift) before usage. * Always set when unit is 'frac'. */ shift?: number /** * A Unit helping to interpret value. */ unit?: Unit /** * An encoding helping to interpret the value */ encoding?: Encoding /** * Describes how the value is layed out in memory. */ storage: StorageType /** * If default value for a register is non-zero, it is specified here. */ defaultValue?: number /** * Minimum typical scaled (shifted) value when specified. */ typicalMin?: number /** * Maximum typical scaled (shifted) value when specified. */ typicalMax?: number /** * Minimum absolute scaled (shifted) value when specified. */ absoluteMin?: number /** * Maximum absolute scaled (shifted) value when specified. */ absoluteMax?: number /** * Maximum number of bytes in a given field (typically a string at the end of a packet). */ maxBytes?: number /** * If set, this and following fields repeat in order, to fill the packet. */ startRepeats?: boolean /** * If set, the payload of multiple consecutive packets should be concatenated together. */ segmented?: boolean /** * If set, the segmented packets are separated with a zero-length packets. */ multiSegmented?: boolean } /** * Possible error message from parsing specification markdown. */ interface Diagnostic { /** * Name of the file where the error occurred. */ file: string /** * 1-based line number of the error. */ line: number /** * Error message. */ message: string } interface DeviceClassSpec { /** * Friendly name of the device */ name: string /** * A few sentences about the device */ description?: string /** * Service class identifiers for services supported by this device. Leave empty for brain. */ services: number[] } type TransportType = "usb" | "serial" | "bluetooth" type JacdacConnectorType = | "noConnector" | "edgeIndependent" | "edgeConsumer" | "edgeLowCurrentProvider" | "edgeHighCurrentProvider" | "edgeLowCurrentProviderConsumer" | "edgeHighCurrentProviderConsumer" | "edgePassive" | "grove" | "qwiic" interface TransportSpec { vendorId?: number productId?: number type: TransportType requestDescription?: string } interface ShapeGeneric { grid: "ec30" width: number height: number } type ShapeWellKnown = | "ec30_1x2_l" | "ec30_2x2_l" | "ec30_2x2_lr" | "ec30_3x2_l" | "ec30_3x2_lr" | "ec30_3x3_l" | "ec30_3x3_lr" | "ec30_4x2_l" | "ec30_4x2_lr" | "ec30_4x3_lr" | "ec30_5x2_l" | "ec30_5x2_lr" | "ec30_5x3_lr" | "ec30_6x2_l" | "ec30_6x2_lr" | "ec30_6x3_lr" | "ec30_1x7_r7" type Shape = ShapeGeneric | ShapeWellKnown interface RepoSpec { target: string name: string slug: string } interface DeviceSpec extends DeviceClassSpec { /** * URL-friendly id. */ id: string /** * Manufacturer of the device */ company: string /** * A URL where the user can learn more about the device. */ link?: string /** * A URL where the device can be purchased */ storeLink?: string[] /** * A URL where the hardware design for the device resides */ hardwareDesign?: string /** * A URL (e.g., a deep link into a GitHub repo) where the source code for the device's firmware resides */ firmwareSource?: string /** * Product identifiers associated with different versions of this device. */ productIdentifiers: number[] /** * A unique id that identifies the hardware design */ designIdentifier?: string /** * A version for this particular hardware design */ version?: string /** * Github repository containing the firmware releases */ repo?: string /** * A set of additional MakeCode extension */ makeCodeRepo?: RepoSpec[] /** * Links image urls */ images?: { /** * Default image displayed to the user */ default: string /** * Square iconic image, max 128x128 */ icon?: string } /** * Specifies the stability status of this device. */ status?: StabilityStatus /** * Hooks for parser. */ errors?: Diagnostic[] /** * Supported bus transport if any */ transport?: TransportSpec /** * Optional list of tags */ tags?: string[] /** * Optiona list of firmware binaries */ firmwares?: { /** * Description of the firmware */ name: string /** * Location of the compiled firmware */ url: string /** * Unique product identifier for this firmware */ productIdentifier?: number }[] /** * Virtual drive that allows to upload new firmware */ bootloader?: { /** * Known bootloader drive name for flashing */ driveName?: string /** * Button sequence to enter bootloader mode. */ sequence?: "reset" | "reset-boot" | "boot-power" /** * File format of firmware files */ firmwareFormat?: "uf2" | "hex" | "bin" /** * URL of the tool that can upload the firmware */ firmwareUploader?: string /** * Led pattern when in bootloader mode */ ledAnimation?: "blue-glow" } /** * Type of PCB edge connector the device, default is "edge" */ connector?: JacdacConnectorType /** * Other devices needed to operate this device */ requiredDevices?: string[] /** * For kits, a list of device identifiers contained in the kit */ devices?: string[] /** * Other devices related to this device */ relatedDevices?: string[] /** * Information about the shape of the footprint and the holes */ shape?: Shape /** * Allows to specify a priority in the catalog */ order?: number } /** * Information about MakeCode support for a Jacdac service */ export interface MakeCodeServiceInfo { /** * Short id of the service */ service: string /** * Client information if any */ client: { /** project name */ name: string /** * Supported targets if restricted */ targets?: string[] /** * GitHub slub and path (OWNER/NAME[/PATH]) */ repo: string /** * The TypeScript fully qualified type name */ qName: string /** * Default fixed instance for this client */ default?: string /** * uses auto-generated client */ generated?: boolean } } }