sejf-ng/protocol.md

156 lines
3.0 KiB
Markdown

UBus
====
Minimal hdlc-over-half-duplex-rs485 bus protcol.
Bus
---
Bus is running half-duplex 115200bps UART over RS485 line.
Framing
-------
All frames transmitted over a bus are encoded using HDLC rules:
* Start byte (0x7e)
* Message payload
* 0x7d or 0x7e bytes in message payload are substituted with [0x7e, byte ^ 0x20]
* Last 2 bytes of message payload are CRC16 `CRC-CCITT` checksum
* NOTE: byte escaping applies here as well!
* NOTE: checksumming over all message bytes including the checksum should result in checksum 0... (this is a feature of pretty much all CRC algorithms, that, it seems, not many people are aware of)
* Message delimiter (end byte, 0x7e)
* Next message may follow immediately (but won't, see below...)
Addressing
----------
Bus supports 126 addresses
0x00 = bus master
0x01 - 0x3e = bus slave
Most significant bit indicates message direction. Slaves responsing to requests
need to set 0b10000000.
Messages
--------
### Master → slave
```
struct msg {
uint8_t target;
uint8_t request_type;
uint8_t request_payload[]; // depends on message type, may be ommitted
uint16_t checksum; // crc16 ccitt
}
```
### Slave → master
```
struct msg {
uint8_t source; // target ^ 0x80
uint8_t response_type;
uint8_t response_payload[]; // depends on message type, may be ommitted
uint16_t checksum; // crc16 ccitt
}
```
Broadcast messages
------------------
Broadcast messages (target 0xff) are handled TDMA-style. Receiving nodes get
assigned _broadcast_timeslot (20ms) each for their response. Every slave needs
to respond after (addr * _broadcast_timeslot) ms after final request delimiter
byte (0x7e). (TODO: this needs to be properly implemented in serial interrupt
by peeking at last byte received... This is impossible unless we patch standard
Arduino Serial implementation)
20ms is enough for approximately 200 bytes of effective application payload
response for every node.
Message type
------------
### 0x0x System Block
#### 0x00 - Status Poll
Basic bus status poll.
```
struct req { };
struct resp {
uint8_t status;
// 00h - ok
// 01h - ffh = error
};
```
#### 0x01 - Identify
Light up status LED for 0.5s.
```
struct req { };
struct resp { };
```
#### 0x02 - Query Supported Commands
```
struct req { };
struct resp {
uint8_t commands[]; // implemented message IDs
};
```
### 0x1x IO Block
#### 0x10 - GPIO Write
```
struct req {
struct {
uint8_t io_num;
uint8_t value;
} pins[];
};
struct resp {
uint8_t status;
// 00h = ok
// 01h - ffh error;
};
```
#### 0x11 - GPIO Read
```
struct req {
uint8_t pins[];
};
struct resp {
uint8_t values[];
};
```
#### 0x12 - WS2812 Write
```
struct req {
uint8_t pin;
uint8_t data; // packed RGB data, num_leds * 3
};
struct resp {
uint8_t status;
// 00h = ok
// 01h - ffh error;
};
```
### 0x2x Peripheral Block
#### 0x20 - NFC Read
Read NFC reader.
```
struct req { };
struct resp {
uint8_t uid[]; // empty if no card read
};
```