156 lines
3.0 KiB
Markdown
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
|
|
};
|
|
```
|