Add device interface specification#215
Conversation
|
We should also address #214 Documention on heterogenous registers here(harp-tech/generators#87) |
3e6f4a9 to
ce8a1f6
Compare
banchan86
left a comment
There was a problem hiding this comment.
Looks pretty good to me! I thought it was well written and clear with the accompanying examples. Just minor suggestions for clarity and one stumbling block regarding the bitmasks.
|
|
||
| ## Document Structure Overview | ||
|
|
||
| A device interface file is a YAML document whose schema is defined by `./schema/device.json`. The root level of the document contains metadata fields describing the device and a `registers` map that declares all application registers. Optional `bitMasks` and `groupMasks` sections define named masks that can be referenced by registers. |
There was a problem hiding this comment.
So the first line duplicates/contradicts the "Schema Reference" at the end of the file, which states that it's defined by a set of 3 files (device.json, core.json, registers.json). I think it might help to bring the "Schema Reference" section with the table up here and delete this line, as I also find that section is a little out of place at the end of the article.
I also realize the term device.yml is never used anywhere, while core.yml is mentioned. I feel like it can be brought in here.
| A device interface file is a YAML document whose schema is defined by `./schema/device.json`. The root level of the document contains metadata fields describing the device and a `registers` map that declares all application registers. Optional `bitMasks` and `groupMasks` sections define named masks that can be referenced by registers. | |
| The root level of the device interface file (`device.yml`) contains metadata fields describing the device and a `registers` map that declares all application registers. Optional `bitMasks` and `groupMasks` sections define named masks that can be referenced by registers. |
| A YAML language-server schema directive SHOULD be placed at the top of the file to enable editor validation and autocompletion: | ||
|
|
||
| ```yaml | ||
| # yaml-language-server: $schema=https://harp-tech.org/draft-02/schema/device.json |
There was a problem hiding this comment.
| # yaml-language-server: $schema=https://harp-tech.org/draft-02/schema/device.json | |
| %YAML 1.1 | |
| --- | |
| # yaml-language-server: $schema=https://harp-tech.org/draft-03/schema/device.json |
Add yaml version directive and update the schema directive link which is now on draft-03
|
|
||
| The file MUST declare all four metadata fields (`device`, `whoAmI`, `firmwareVersion`, `hardwareTargets`) and the `registers` map. The `bitMasks` and `groupMasks` sections are OPTIONAL and SHOULD be included when registers reference named masks. | ||
|
|
||
| A YAML language-server schema directive SHOULD be placed at the top of the file to enable editor validation and autocompletion: |
There was a problem hiding this comment.
| A YAML language-server schema directive SHOULD be placed at the top of the file to enable editor validation and autocompletion: | |
| A YAML version and language-server schema directive SHOULD be placed at the top of the file to enable editor validation and autocompletion: |
Include the YAML version directive here?
|
|
||
| ## Core Registers | ||
|
|
||
| Every Harp device also exposes a set of core registers (addresses 0–31) that are common to all devices. These registers are defined in a separate file (`core.yml`) and follow the same YAML schema described in this document. Core registers handle device identification, timestamping, operation mode control, and other shared functionality. See [Device Registers and Operation](Device.md#core-registers) for the full specification of core register behavior. |
There was a problem hiding this comment.
| Every Harp device also exposes a set of core registers (addresses 0–31) that are common to all devices. These registers are defined in a separate file (`core.yml`) and follow the same YAML schema described in this document. Core registers handle device identification, timestamping, operation mode control, and other shared functionality. See [Device Registers and Operation](Device.md#core-registers) for the full specification of core register behavior. | |
| Every Harp device also exposes a set of core registers (addresses 0–31) defined in a separate [`core.yml`](./schema/core.yml) file that follows the same YAML schema described in this document. Core registers handle device identification, timestamping, operation mode control, and other shared functionality. As these registers are common to all devices, `core.yml` does not need to be included alongside `device.yml`. See [Device Registers and Operation](Device.md#core-registers) for the full specification of core register behavior. |
I feel like one thing that is not obvious to people is whether or not they should include core.yml in the device repository, so I suggested edits here, and added link to schema/core.yml.
|
|
||
| A register that specifies only `Event` as its access mode is implicitly read-only from the Controller's perspective — the Controller cannot write to it, and the device pushes data when events occur. | ||
|
|
||
| When multiple access modes are needed, they SHOULD be expressed as a YAML sequence (1–3 unique values): |
There was a problem hiding this comment.
| When multiple access modes are needed, they SHOULD be expressed as a YAML sequence (1–3 unique values): | |
| When multiple access modes are needed, they MUST be expressed as a YAML sequence (1–3 unique values): |
Is there another way of expressing multiple access modes? If not, should it be a MUST?
| | `ushort` | 16-bit unsigned integer. | | ||
| | `float` | Floating-point value. | | ||
| | `string` | Text, typically over a span of byte elements. When using interfaceType, the `length` parameter MUST be defined | | ||
| | `HarpVersion` | Custom type composed from multiple elements that describes a SemVer-like version. When using this `interfaceType`, the `length` MUST be equal to 3 | |
There was a problem hiding this comment.
| | `HarpVersion` | Custom type composed from multiple elements that describes a SemVer-like version. When using this `interfaceType`, the `length` MUST be equal to 3 | | |
| | `HarpVersion` | Custom type composed from multiple elements that describes a [semantic version](https://semver.org/). When using this `interfaceType`, the `length` MUST be equal to 3 | |
Changed text and added link, similar to what was done in Device.MD
| A member is located within the payload using two **independent** coordinates, either or both of which MAY be present: | ||
|
|
||
| - `offset` (with optional `length`) selects *which element(s)* of the payload array the member occupies. | ||
| - `mask` selects *which bits* within a payload word the member occupies. |
There was a problem hiding this comment.
So one thing that really tripped me up is I am not sure when one should define the bitmask in the payloadSpec and when one should define it in the "bitMask" section of the device.yml. Are these reasons correct?
Define bitmask in payloadSpec:
- When combining offset and bitmask to locate a member?
- When separating heterogenous type members with different-sized bitfields?
Define bitmask in bitMasks section:
- When defining the same type members, with equal-size bitfields?
I also think I may have the wrong mental model and might be completely off about the distinction between the two 😆 A note about the differences between the two might help other confused readers like me.
| | `int` | Signed integer. | | ||
| | `uint` | Unsigned integer. | |
There was a problem hiding this comment.
| | `int` | Signed integer. | | |
| | `uint` | Unsigned integer. | | |
| | `int` | 32-bit signed integer. | | |
| | `uint` | 32-bit unsigned integer. | |
| ### Private registers | ||
|
|
||
| Registers that are not meant to be exposed in high-level interfaces (e.g. code-generated classes) can be marked with `visibility: private`. This is commonly used for reserved registers that fill gaps in the address space to maintain contiguity. | ||
|
|
||
| ```yaml | ||
| Reserved0: &reserved | ||
| address: 33 | ||
| type: U8 | ||
| access: Read | ||
| description: Reserved for future use | ||
| visibility: private | ||
| Reserved1: | ||
| <<: *reserved | ||
| address: 84 | ||
| ``` |
There was a problem hiding this comment.
Hmm, I feel like this section might be better placed in the walkthrough of the properties in the "Registers" section. The example will have to be changed to get rid of the yaml anchors and aliases.
| ## Schema Reference | ||
|
|
||
| The device interface YAML format is formally defined by a set of JSON Schema files: | ||
|
|
||
| | Schema | Description | | ||
| | :--------------- | :---------------------------------------------------------------------------------------------------------- | | ||
| | `device.json` | Top-level schema for device interface files. Requires device metadata and references `core.json`. | | ||
| | `core.json` | Schema for core device properties. Requires `protocolVersion` and references `registers.json`. | | ||
| | `registers.json` | Defines the structure of registers, bit masks, group masks, payload members, and all associated properties. | | ||
|
|
||
| Editors supporting the [YAML Language Server](https://github.com/redhat-developer/yaml-language-server) can validate device interface files by adding the schema directive shown in the [Document Structure Overview](#document-structure-overview). |
There was a problem hiding this comment.
As mentioned there is some overlap with this and the document overview section so might be better to move this up there.
This is a first stab at describing the device interface,
device.ymlspecification.It provides a high-level description on how the document is organized, validated and used by downstream tooling. I also provides a few examples.
I think we could add more detail in the following points:
interfaceTypeThe way that @glopesdev ended up resolving the heterogeneous registers Heterogenous register types in yaml schema #40