{
  "name": "Control",
  "status": "stable",
  "shortId": "control",
  "camelName": "control",
  "shortName": "control",
  "extends": [
    "_base"
  ],
  "notes": {
    "short": "Control 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."
  },
  "classIdentifier": 0,
  "enums": {
    "AnnounceFlags": {
      "name": "AnnounceFlags",
      "storage": 2,
      "isFlags": true,
      "members": {
        "RestartCounterSteady": 15,
        "RestartCounter1": 1,
        "RestartCounter2": 2,
        "RestartCounter4": 4,
        "RestartCounter8": 8,
        "StatusLightNone": 0,
        "StatusLightMono": 16,
        "StatusLightRgbNoFade": 32,
        "StatusLightRgbFade": 48,
        "SupportsACK": 256,
        "SupportsBroadcast": 512,
        "SupportsFrames": 1024,
        "IsClient": 2048,
        "SupportsReliableCommands": 4096
      }
    }
  },
  "constants": {},
  "packets": [
    {
      "kind": "report",
      "name": "command_not_implemented",
      "identifier": 3,
      "description": "This 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.",
      "fields": [
        {
          "name": "service_command",
          "type": "u16",
          "storage": 2,
          "isSimpleType": true
        },
        {
          "name": "packet_crc",
          "type": "u16",
          "storage": 2,
          "isSimpleType": true
        }
      ],
      "identifierName": "command_not_implemented",
      "packFormat": "u16 u16",
      "derived": "_base"
    },
    {
      "kind": "const",
      "name": "instance_name",
      "identifier": 265,
      "description": "A 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).",
      "fields": [
        {
          "name": "_",
          "type": "string",
          "storage": 0
        }
      ],
      "optional": true,
      "identifierName": "instance_name",
      "packFormat": "s",
      "derived": "_base"
    },
    {
      "kind": "ro",
      "name": "status_code",
      "identifier": 259,
      "description": "Reports 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.",
      "fields": [
        {
          "name": "code",
          "type": "u16",
          "storage": 2,
          "isSimpleType": true
        },
        {
          "name": "vendor_code",
          "type": "u16",
          "storage": 2,
          "isSimpleType": true
        }
      ],
      "optional": true,
      "identifierName": "status_code",
      "packFormat": "u16 u16",
      "derived": "_base"
    },
    {
      "kind": "rw",
      "name": "client_variant",
      "identifier": 9,
      "description": "An 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.",
      "fields": [
        {
          "name": "_",
          "type": "string",
          "storage": 0
        }
      ],
      "optional": true,
      "identifierName": "client_variant",
      "packFormat": "s",
      "derived": "_base"
    },
    {
      "kind": "event",
      "name": "status_code_changed",
      "identifier": 4,
      "description": "Notifies that the status code of the service changed.",
      "fields": [
        {
          "name": "code",
          "type": "u16",
          "storage": 2,
          "isSimpleType": true
        },
        {
          "name": "vendor_code",
          "type": "u16",
          "storage": 2,
          "isSimpleType": true
        }
      ],
      "optional": true,
      "identifierName": "status_code_changed",
      "packFormat": "u16 u16",
      "derived": "_base"
    },
    {
      "kind": "command",
      "name": "services",
      "identifier": 0,
      "description": "The `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.",
      "fields": [],
      "identifierName": "announce",
      "hasReport": true
    },
    {
      "kind": "report",
      "name": "services",
      "identifier": 0,
      "description": "The `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.",
      "fields": [
        {
          "name": "flags",
          "type": "AnnounceFlags",
          "storage": 2
        },
        {
          "name": "packet_count",
          "type": "u8",
          "storage": 1,
          "isSimpleType": true
        },
        {
          "name": "reserved",
          "type": "u8",
          "storage": 1,
          "isSimpleType": true
        },
        {
          "name": "service_class",
          "type": "u32",
          "storage": 4,
          "isSimpleType": true,
          "startRepeats": true
        }
      ],
      "secondary": true,
      "packFormat": "u16 u8 u8 r: u32"
    },
    {
      "kind": "command",
      "name": "noop",
      "identifier": 128,
      "description": "Do nothing. Always ignored. Can be used to test ACKs.",
      "fields": []
    },
    {
      "kind": "command",
      "name": "identify",
      "identifier": 129,
      "description": "Blink 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.",
      "fields": [],
      "optional": true
    },
    {
      "kind": "command",
      "name": "reset",
      "identifier": 130,
      "description": "Reset device. ACK may or may not be sent.",
      "fields": [],
      "optional": true
    },
    {
      "kind": "command",
      "name": "flood_ping",
      "identifier": 131,
      "description": "The 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, ...`.",
      "fields": [
        {
          "name": "num_responses",
          "type": "u32",
          "storage": 4,
          "isSimpleType": true
        },
        {
          "name": "start_counter",
          "type": "u32",
          "storage": 4,
          "isSimpleType": true
        },
        {
          "name": "size",
          "unit": "B",
          "type": "u8",
          "storage": 1,
          "isSimpleType": true
        }
      ],
      "unique": true,
      "optional": true,
      "hasReport": true,
      "packFormat": "u32 u32 u8"
    },
    {
      "kind": "report",
      "name": "flood_ping",
      "identifier": 131,
      "description": "The 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, ...`.",
      "fields": [
        {
          "name": "counter",
          "type": "u32",
          "storage": 4,
          "isSimpleType": true
        },
        {
          "name": "dummy_payload",
          "type": "bytes",
          "storage": 0,
          "isSimpleType": true
        }
      ],
      "secondary": true,
      "packFormat": "u32 b"
    },
    {
      "kind": "command",
      "name": "set_status_light",
      "identifier": 132,
      "description": "Initiates 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.",
      "fields": [
        {
          "name": "to_red",
          "type": "u8",
          "storage": 1,
          "isSimpleType": true
        },
        {
          "name": "to_green",
          "type": "u8",
          "storage": 1,
          "isSimpleType": true
        },
        {
          "name": "to_blue",
          "type": "u8",
          "storage": 1,
          "isSimpleType": true
        },
        {
          "name": "speed",
          "type": "u8",
          "storage": 1,
          "isSimpleType": true
        }
      ],
      "packFormat": "u8 u8 u8 u8"
    },
    {
      "kind": "command",
      "name": "proxy",
      "identifier": 133,
      "description": "Force client device into proxy mode.",
      "fields": [],
      "optional": true
    },
    {
      "kind": "command",
      "name": "reliable_commands",
      "identifier": 134,
      "description": "This 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.",
      "fields": [
        {
          "name": "seed",
          "type": "u32",
          "storage": 4,
          "isSimpleType": true
        }
      ],
      "optional": true,
      "hasReport": true,
      "packFormat": "u32"
    },
    {
      "kind": "report",
      "name": "reliable_commands",
      "identifier": 134,
      "description": "This 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.",
      "fields": [
        {
          "name": "commands",
          "type": "pipe",
          "storage": 12
        }
      ],
      "secondary": true,
      "pipeType": "reliable_commands",
      "packFormat": "b[12]"
    },
    {
      "kind": "pipe_command",
      "name": "wrapped_command",
      "identifier": 0,
      "description": "This 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.",
      "fields": [
        {
          "name": "service_size",
          "type": "u8",
          "storage": 1,
          "isSimpleType": true
        },
        {
          "name": "service_index",
          "type": "u8",
          "storage": 1,
          "isSimpleType": true
        },
        {
          "name": "service_command",
          "type": "u16",
          "storage": 2,
          "isSimpleType": true
        },
        {
          "name": "payload",
          "type": "bytes",
          "storage": 0,
          "isSimpleType": true
        }
      ],
      "pipeType": "reliable_commands",
      "packFormat": "u8 u8 u16 b"
    },
    {
      "kind": "command",
      "name": "standby",
      "identifier": 135,
      "description": "Attempt to put devices into lowest power sleep mode for a specified time - most likely involving a full reset on wake-up.",
      "fields": [
        {
          "name": "duration",
          "unit": "ms",
          "type": "u32",
          "storage": 4,
          "isSimpleType": true
        }
      ],
      "optional": true,
      "packFormat": "u32"
    },
    {
      "kind": "rw",
      "name": "reset_in",
      "identifier": 128,
      "description": "When 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.",
      "fields": [
        {
          "name": "_",
          "unit": "us",
          "type": "u32",
          "storage": 4,
          "isSimpleType": true
        }
      ],
      "internal": true,
      "optional": true,
      "packFormat": "u32"
    },
    {
      "kind": "const",
      "name": "device_description",
      "identifier": 384,
      "description": "Identifies the type of hardware (eg., ACME Corp. Servo X-42 Rev C)",
      "fields": [
        {
          "name": "_",
          "type": "string",
          "storage": 0
        }
      ],
      "optional": true,
      "packFormat": "s"
    },
    {
      "kind": "const",
      "name": "product_identifier",
      "identifier": 385,
      "description": "A numeric code for the string above; used to identify firmware images and devices.",
      "fields": [
        {
          "name": "_",
          "type": "u32",
          "storage": 4,
          "isSimpleType": true,
          "absoluteMin": 805306368,
          "absoluteMax": 1073741823
        }
      ],
      "optional": true,
      "packFormat": "u32"
    },
    {
      "kind": "const",
      "name": "bootloader_product_identifier",
      "identifier": 388,
      "description": "Typically the same as `product_identifier` unless device was flashed by hand; the bootloader will respond to that code.",
      "fields": [
        {
          "name": "_",
          "type": "u32",
          "storage": 4,
          "isSimpleType": true,
          "absoluteMin": 805306368,
          "absoluteMax": 1073741823
        }
      ],
      "optional": true,
      "packFormat": "u32"
    },
    {
      "kind": "const",
      "name": "firmware_version",
      "identifier": 389,
      "description": "A string describing firmware version; typically semver.",
      "fields": [
        {
          "name": "_",
          "type": "string",
          "storage": 0
        }
      ],
      "optional": true,
      "packFormat": "s"
    },
    {
      "kind": "ro",
      "name": "mcu_temperature",
      "identifier": 386,
      "description": "MCU temperature in degrees Celsius (approximate).",
      "fields": [
        {
          "name": "_",
          "unit": "°C",
          "type": "i16",
          "storage": -2,
          "isSimpleType": true,
          "typicalMin": -10,
          "typicalMax": 150
        }
      ],
      "volatile": true,
      "optional": true,
      "preferredInterval": 60000,
      "packFormat": "i16"
    },
    {
      "kind": "ro",
      "name": "uptime",
      "identifier": 390,
      "description": "Number of microseconds since boot.",
      "fields": [
        {
          "name": "_",
          "unit": "us",
          "type": "u64",
          "storage": 8,
          "isSimpleType": true
        }
      ],
      "volatile": true,
      "optional": true,
      "preferredInterval": 60000,
      "packFormat": "u64"
    }
  ],
  "tags": [
    "C",
    "8bit"
  ]
}