Skip to content

Add device interface specification#215

Open
bruno-f-cruz wants to merge 4 commits into
mainfrom
feat-add-device-interface-spec
Open

Add device interface specification#215
bruno-f-cruz wants to merge 4 commits into
mainfrom
feat-add-device-interface-spec

Conversation

@bruno-f-cruz

@bruno-f-cruz bruno-f-cruz commented Apr 25, 2026

Copy link
Copy Markdown
Member

This is a first stab at describing the device interface, device.yml specification.
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:

@bruno-f-cruz bruno-f-cruz requested review from a team, banchan86 and glopesdev April 25, 2026 18:05
@bruno-f-cruz

bruno-f-cruz commented Apr 26, 2026

Copy link
Copy Markdown
Member Author

We should also address #214
One idea is that scalar registers should NEVER specify length. If length is specied (even if 0) the register interface must always return a array type

Documention on heterogenous registers here(harp-tech/generators#87)

@bruno-f-cruz bruno-f-cruz force-pushed the feat-add-device-interface-spec branch from 3e6f4a9 to ce8a1f6 Compare June 21, 2026 12:12

@banchan86 banchan86 left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Comment thread DeviceInterface.md

## 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.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Suggested change
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.

Comment thread DeviceInterface.md
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

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
# 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

Comment thread DeviceInterface.md

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:

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
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?

Comment thread DeviceInterface.md

## 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.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
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.

Comment thread DeviceInterface.md

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):

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
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?

Comment thread DeviceInterface.md
| `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 |

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
| `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

Comment thread DeviceInterface.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.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Comment thread DeviceInterface.md
Comment on lines +324 to +325
| `int` | Signed integer. |
| `uint` | Unsigned integer. |

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
| `int` | Signed integer. |
| `uint` | Unsigned integer. |
| `int` | 32-bit signed integer. |
| `uint` | 32-bit unsigned integer. |

Comment thread DeviceInterface.md
Comment on lines +531 to +545
### 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
```

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Comment thread DeviceInterface.md
Comment on lines +547 to +557
## 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).

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As mentioned there is some overlap with this and the document overview section so might be better to move this up there.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants