logo

WARNING: JACDAC is very much still under development and subject to change. If you would like to contribute features and ideas, please visit the github repository and file an issue.



Download as PDF

Specification

Document History

Version Information

This specification document details the implementation of JACDAC version 0 (JACDAC v0). JACDAC v0 uses the CRC polynomial 0xF13.

Protocol Overview

JACDAC uses the built-in UART module common to most MCUs as its communication mechanism, but instead of separate wires for transmission and reception, JACDAC uses just one wire for both. Four baud rates are supported: 1Mbaud, 500Kbaud, 250Kbaud, 125Kbaud, allowing cheaper MCUs to be used.

Microcontrollers that run the JACDAC protocol are known as JACDAC devices. They communicate JACDAC Packets to each other across a shared bus in a bus topology. Devices signal a packet transmission by driving the bus lo for a period of time known as the lo pulse. The length of the lo pulse dictates the baud rate of the upcoming UART transmission of a JACDAC packet.

Conventionally in bus topologies there is the concept of a Master and Slave (widely regarded as outdated terminology; we use Host and Client instead). JACDAC devices are all Hosts on the bus and run Services that others devices can act as Clients to. Services allow other devices to configure and use resources that they would normally not have access to, examples include: an AccelerometerService, a DisplayService, or a NeopixelService. Other devices interact with a hosted service as part of a microcontrollers’ application.

A device can enumerate one or more Services on the bus using a ControlPacket, which is a JACDAC Packet that contains: a 64-bit unique device identifier, the allocated device address, and an array of ServiceInformation which details the Services available for use by the bus. Enumeration is only required if operating a Service for others to consume; unenumerated devices are free to use enumerated services without enumerating themselves. The presence or absence of device ControlPackets indicates whether a device has been connected or removed from the bus.

Each JACDAC device has a simple stack featuring: (1) a physical layer handling the transmission and reception of packets; (2) a control layer which performs the routing of packets; to (3) services running on the device.

picture of JACDAC devices in bus topology

Physical Layer Specifications

This section describes the hardware requirements, packet format, and the logic line level transmission process. Protocol timings are generally described in terms of bytes: a byte is 10 bits, as 1 UART start and stop bit are included in the total size.

Hardware Requirements

To operate on the JACDAC bus, an MCU must be capable of:

Hardware Organisation

A JACDAC device should feature one JACDAC capable microcontroller that is connected to zero or more sensors over an onboard communication protocol such as I2C or SPI. The JACDAC microcontroller should also have the capability to connect to the JACDAC bus to communicate with other JACDAC devices.

JACDAC Packet Format

The table below specifies the packet structure of JACDAC packets transmitted on the bus. Bytes are sent in little endian format.

Field Size (bits) Name Description
12 CRC The CRC field calculated using the polynomial 0xF13. When calculating the CRC for a JACDAC packet, the unique device identifier of the destination / source device must be included. When computing the CRC for a ControlPacket, the crc must be calculated with no unique device identifier.
4 service_number A number that identifies a service on a device. Discussed further in the Control Layer section.
8 device_address A number that identifies a device on the bus.
8 size The size of the data field. Values range from 0-255.
8 * size data An array of bytes, whose size is dictated by the size field above.

The packet structure is divided into two parts:

A frame refers to a packet that is sent on the bus and includes the bus arbitration process.

Transmission & Reception

When the JACDAC bus is in idle state, all MCUs on the bus must configure their TX/RX pin to be an input with a pull up to 3.3v. In this state, the bus will read high.

When an MCU wants to transmit a packet, it must drive the bus low for 10 bits (1 byte) at the desired baud rate and wait for a minimum of 6 bytes at 1Mbaud before transmitting data. This is known as the lo pulse, the duration of this pulse dictates the baud rate of the upcoming UART transmission:

Pulse Duration (us) UART Baud Rate (KBaud)
10 1000
20 500
40 250
80 125

When an MCU detects the beginning of a transmission (a low pulse), it has a minimum of 60 microseconds (6 bytes at 1Mbaud) to configure any hardware registers and software buffers to receive a JACDAC packet header. After receiving the header, an MCU should either receive the remainder or ignore a packet. If no data is received after 160 microseconds (2 bytes at the 125Kbaud), the receiving devices should enter an error recovery state (described later on in this document).

A JACDAC packet that is transmitted on the wire is known as a frame and includes the bus arbitration period as well as the packet itself.

Devices that communicate at baud rates faster than 125Kbaud must also be capable of communicating at all slower baud rates e.g. a device that communicates at 1Mbaud must also be able to communicate at 500, 250, and 125 Kbaud.

It should be noted that despite supporting lower baud rates, developers must achieve the maximum baud rate possible with their chosen MCU. This is for reasons of bus efficiency, as the presence of a large number of slower devices reduces the throughput of the bus.

The process described is visualised in the image below: the bus is high for a period of time, driven low for 10 microseconds (10 bits at 1Mbaud), data following 40 microseconds later.

picture of a low period followed by data

Physical Layer Timings

This section specifies expected and maximum timings at the physical layer. If any of the following timings are violated, devices must enter an error state and resume listening for frames once the bus idle period has been detected

Bus Idle Spacing

If a device chooses to ignore a packet or an error condition is detected when receiving a packet, a device needs to determine when the bus has entered an idle state.

An idle bus is defined as no activity (line hi) for 2 bytes at 125kbaud (160 microseconds).

InterLoData Spacing

The minimum time before data can be sent after a lo pulse is 60 microseconds, and the maximum gap before data begins is 160 microseconds (two bytes at the lowest baud); times are relative from the end of the lo pulse. All devices must enter an error state if a transmitting device exceeds this time.

diagram of the maximum spacing between bytes

Interbyte Spacing

The maximum permitted time between bytes is two bytes at the minimum baud rate (125KBaud). A transmitting device must never near the maximum interbyte spacing. All devices must enter an error state if a transmitting device exceeds this time.

diagram of the maximum spacing between bytes

Interframe Spacing

The minimum space between frames is two bytes at the minimum baud rate (125KBaud). JACDAC devices should capture the time after receiving the last byte of a packet and observe the minimum interframe spacing. To prevent transmission of a frame at the same time as another device, devices must implement a random backoff for transmission.

diagram of the maximum spacing between frames

Error Detection and Recovery

If any of the protocol timings are violated a device must enter an error state and wait until the bus is idle for the bus idle period.

To detect the idle period, a device must capture the time from when the bus last transitioned from lo to hi, resetting this time if the bus transitions again.

A state diagram for error detection when receiving a packet is shown below:

Error state state diagram

Preventing Bus Collisions

Bus arbitration is performed through pulsing the bus low for 10 bits at the desired baud rate. However, a device could disable GPIO interrupts and initiate the process of transmission by driving the bus low whilst another device is doing the same:

The diagram above exemplifies the race condition described previously showing two overlapping lo pulses and communications.

To prevent the race condition, JACDAC devices must check the bus state before beginning the lo pulse:

If the bus state is lo when performing this check, devices must enter an error state (as the lo pulse may be improperly measured) and wait for the bus to return to idle.

If two devices begin the lo pulse at exactly the same time, the UART module on the transmitting MCU will detect an error (most likely a framing error), and the received crc will be incorrect.

Control Layer

This section discusses the control layer and specifies: the purpose and implementation Control Packets, device address assignment, and the routing of packets to Services.

Each device must have a Control Layer responsible for sending a ControlPacket every 500 ms. A ControlPacket contains information about a device including: a unique device identifier (udid), device address, and available Services for use by the bus.

Control Packet Format

A ControlPacket has multiple purposes:

  1. To facilitate the allocation of device addresses on the bus.
  2. To reduce the overhead of standard JACDAC packets by providing meta data and addressing information for the routing of packets to services.
  3. To allow JACDAC devices to determine if a device has been connected or removed from the bus.

ControlPackets are embedded in the content of a standard JACDAC packet which has the device_address and service_number fields set to zero.

The address zero must never be used as the device_address by any device, and should be thought of as a reserved broadcast address for Control operations.

A ControlPacket has the following structure:

Field Size (bits) Name Description
64 udid The unique device identifier (udid) for the device.
8 device_address The address allocated to the device that occupies the address field of a JACDAC packet. If the address field is set to 255, then this packet was transmitted by a transmit only device. In this case, address collision handling can be skipped. See the transmit only devices section for more detail.
8 device_flags A field for the ControlService indicating the state of a device.
data[0] * 8 device_name (optional) An optional device name. The presence of the device_name field is indicated by the HAS_NAME bit of device_flags. The first byte of data contains the length of device name. Device names are not null terminated.
N * ServiceInformation data The data field is filled with an array of ServiceInformation structs advertising Services operating on the device for use by the bus.

The possible values of the device_flags field values are defined as follows:

Bit Mask (hex) Name Description
0x01 REJECT This bit indicates there is an address collision between devices.
0x02 PROPOSING This bit indicates that the device is in the proposal phase of address allocation.
0x04 HAS_NAME This bit indicates that a name is present before the ServiceInformation array in the data field.
0x08 NACK This bit can be used to indicate a negative acknowledgement of a ControlPacket
0x10 RESERVED Reserved for future emerging use cases
0x20 RESERVED Reserved for future emerging use cases
0x40 RESERVED Reserved for future emerging use cases
0x80 ERROR Indicates a device with an irrecoverable error; the error_code for such an error consumes the remaining 7 bits. In an error condition the data field should contain an error message with more information, the size of which is dictated by JDPacket->size - 10 (size of the ControlPacket header) field.

The data field of a ControlPacket contains one or more ServiceInformation structs which have the following structure:

Field Size (bits) Name Description
32 service_class This field identifies a specific service implementation. The allocation of these numbers is specified in the service class allocation section.
8 service_flags Flags for the service, optionally populated by a Service. If the top bit (bit 7) is set, the device has an irrecoverable hardware error; the error_code for such an error consumes the remaining 7 bits. In an error condition the advertisement_data field should contain an error message with more information, the size of which is dictated by the advertisement_size field.
8 advertisement_size A field that indicates the size of the upcoming advertisement_data field. The developer is responsible for ensuring that all services on a device are able to add advertisement_data if required.
8 * advertisement_size advertisement_data (optional) Optional advertisement data indicating additional runtime properties of the service.

Generating Unique Device Identifiers (UDID)

JACDAC uses the IETF EUI-64 specification for 64-bit unique device identifier generation.

There are two types of address that can be used:

1) Globally unique addresses 2) Locally unique addresses

Commonly microcontrollers ship with 64-bit serial numbers (or greater) flashed at the factory. In this case, the transformation to a JACDAC 64-bit UDID is simple: take or generate a 64-bit serial number and set the Universal/Local bit to 0 (bit 0x0200000000000000, 7th bit from the MSB)

There may be the allocation of globally unique device identifiers in the future, but for now every JACDAC device should be capable of producing a unique device identifier using the above algorithm given a factory flashed serial number or a random number.

Extracting ServiceInformation

The data field of a ControlPacket should be parsed as follows:

0) Is the ERROR bit set in the device_flags field? If so handle the error message and go to 4.

1) Inspect the size of the JACDAC Packet, and subtract the size of a ControlPacket header (10 bytes), the remainder will be the size of the data field called data_field_size. Create a variable called offset set to zero

2) Is offset == data_field_size? If yes go to 4.

3) Iterate over the ControlPacket->data field:

4) Finished

Device Address Allocation

When a device is first connected to the bus, it must obtain an address to use. The process to obtain an address is known as enumeration and a device is said to be enumerated when it has a confirmed address. Enumeration uses ControlPackets to obtain an address, and in normal operation devices must emit ControlPackets every 500 ms. Other devices must only use services that are offered by a device once it is enumerated.

When enumerating, devices must propose an address to use by setting the device_address and the PROPOSAL flag in its ControlPackets. If an enumerated device on the bus is already using the proposed address, the enumerated device must return the same ControlPacket with the REJECT flag set. If a proposing device receives the previously sent ControlPacket with the REJECT flag set, it must pick a new address and begin the proposal phase again. Similarly, if the proposing device receives a ControlPacket from another device using the proposed address, it must pick a new address and begin the proposal phase again (this may be the case if the proposing device communicates at an incompatible baud rate for another MCU). If two devices propose to use the same address, the address collision rules must be observed.

Some devices may maintain additional state of addresses used on the bus and can return a different address in the device_address field in the returned ControlPacket.

After two ControlPackets without rejection, a proposing device is considered bound to that address. A bound address is indicated by the absence of the PROPOSAL flag.

Reserved addresses

Addresses 0 and 255 are reserved and must not be allocated to any devices on the bus. Address 0 is exclusively used for control data, and address 255 is used for transmit only devices.

Device Address Collisions

Address collisions are identified by a device receiving a ControlPacket containing its device_address and a different udid. It is likely that there will be address collisions if two large, established buses are joined together.

On the occurrence of an address collision, the device that detected the colliding ControlPacket must begin the enumeration process again to establish a new address. In other words, the first device to communicate a ControlPacket when two buses are joined remains bound to that address.

Device Removal

If a ControlPacket is not seen from a device for 1 second (2 ControlPackets), the device is considered removed.

Routing Packets

On the reception of a JACDAC packet a packet must be routed to any corresponding services matching the JACDAC packet.

A JACDAC packet contains a device_address and service_number field, which when combined identify a service running on a device. Previously received ControlPackets contain the necessary metadata to map a JACDAC packet to a corresponding device and service. If a JACDAC device requires a packet to be routed to a service it must maintain the relevant state contained in a control packet.

The device_address can be directly obtained from the device_address field of a ControlPacket. However, the service_number must be calculated by determining the position of the relevant ServiceInformation in the array contained in the data payload of a ControlPacket:

ControlPacket:
  device_address: 3
  unique_device_id: 1235464738
  flags: 0
  data:
    Service:
      service_class: Button
      flags: 0
      status: 0
      advertisement_size: 0
    Service:
      service_class: Accelerometer
      flags: 0
      status: 0
      advertisement_size: 0
    Service:
      service_class: Servo
      flags: 0
      status: 0
      advertisement_size: 0

A JACDAC packet addressed to the Accelerometer service using the ControlPacket above would look as follows:

JACDAC Packet:
  crc: XXXX
  service_number: 1
  address: 3
  size: 6
  data:
    x: 999
    y: 20
    z: 500

By maintaining a small amount of state, minimal metadata is placed in a JACDAC packet allowing more space for service data.

Transmit Only Devices

Low cost, powerful, 4/8-bit microcontrollers are not going away anytime soon. The JACDAC protocol enables such microcontrollers to easily integrate into the ecosystem with only a small amount of control logic and no requirement for receiving packets.

Transmit only devices must transmit control packets every 500 ms, but they do not need to detect addressing collisions or negotiate addresses with other devices on the bus. All transmit only devices share the device_address 255.

Transmit only devices must be able to perform bus arbitration and error recovery.

Control Packets

For transmit only devices, control packets retain the same structure and addressing. To indicate that the device is transmit only, the device_address field in the control packet must be set to 255.

The computation of the service number for Services remains the same as in conventional JACDAC operation.

Data packets

As transmit only devices cannot receive, they must operate in a separate address space for the communication of normal data packets. All devices share the same address 255, and this address can be thought of as a broadcast channel.

JACDAC packets sent using address 255 must contain the UUID of the transmitting device as the first 8 bytes of the data payload so that the Control Layer can correctly route packets to corresponding services.

Packets emitted from services on a transmit only device should use the computed service_number as per normal JACDAC operation.

When is enumeration required?

Device enumeration is only required when a device is running a Service for others on the bus. If a device seeks to only consume / control a Service of another device, device enumeration is not required.

Services

Services are advertised by JACDAC devices on the bus and build on the Control Layer. They expose APIs for programmers to access, actuate, and network with other devices on the bus.

The ServiceInformation structure inside ControlPackets contain information about services running on the device, each containing:

For more detail on the ServiceInformation struct see the ControlPacket Format section.

At runtime, Services send JACDAC packets placing the service_offset and device_address allocated by the ControlLayer into each packet. The combination of these fields can be conceptually be thought of as either source or destination addresses depending on the context: If a service emits a packet, it is a source address. If another device emits a packet destined for a service it is a destination address.

The implementation of communication paradigm abstractions is left up to the stack developer, although the CODAL implementation is documented.

Packets emitted by a service must take the form of a JACDAC packet, but the data payload of the packet can be freely defined by a developer. A pull request must be made to the jacdac services respository and include a description of the functionality of the service and the specification of expected packet formats. This allows others to implement services in their preferred programming language. The developer should indicate whether their service is ready to have a class allocation in their pull request; a TypeScript implementation of a service can expedite adoption.

Compulsory Services

Control Service

Addressing Information  
Service Class 0
Compulsory Address 0
Compulsory Service Number 0

On every JACDAC device there must be a service responsible for routing control packets to corresponding services.

See the ControlPacket format for the expected packet layout.

More capable devices may choose to run a configuration service to provide a more usable device experience, and those with random number generators may operate a random number generator service for less capable devices to use.

Configuration Service

Addressing Information  
Service Class 2
Compulsory Address 0
Compulsory Service Number 1

The configuration service receives packets that modify the name of a device or triggers an identification of a device to its user. This enables users to configure deployed JACDAC networks remotely from a user interface… perhaps a Web page running a JACDAC WebUSB stack…

ConfigurationService packets have the following format:

Field Size (bits) Name Description
8 device_address The source address of the device performing the identification or naming request.
8 request_type This field identifies the layout of the data field. A request_type of 1 is a naming request, 2 is an identification request
variable data If the request_type is 2, there is no data payload and the device should simply identify itself to a user. A request type of 1 places the size of the new device_name at data[0], with the remaining bytes containing the new device_name.

Random Number Generator Service

Addressing Information  
Service Class 1
Compulsory Address 0
Compulsory Service Number 2

The purpose of the random number generator service is to return a random number when requested for less capable microcontrollers that do not have the ability to generate random numbers.

Random number generate service packets take the following form:

Field Size (bits) Name Description
32 request_type This field determines if the packet is a request or response. A request_type of 1 is a request, 2 is a response to a previous request.
32 random_number When request_type is set to 2, this field must contain a random 32 bit number.

Service Class Allocation

Service classes 0 to 4000 are reserved for core services and must not be allocated in this range by developers.

Classes 4000 to 65535 (0x0000FFFF) can be used dynamically, although there are no guarantees of the uniqueness of classes in this range. These classes must be used for local prototyping and should not be used for deployed products or services.

The remaining addresses are reserved for allocated service classes. Developers must ask for a class number before distributing a service or deploying their product. Service classes are allocated by submitting a pull request to the jacdac services repository.