sejf-ng/protocol.md

3.0 KiB

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
};