Crates.io | urap |
lib.rs | urap |
version | 0.2.1 |
source | src |
created_at | 2024-07-07 19:35:05.115428 |
updated_at | 2024-09-04 19:45:24.645534 |
description | Specification and library for the URAP protocol |
homepage | |
repository | https://github.com/Gip-Gip/urap |
max_upload_size | |
id | 1295098 |
size | 40,142 |
A simple protocol for accessing data across various transmission means.
The Universal Register Access Protocol, or URAP for short, is a lightweight, fast and simple protocol for accessing registers through a variety of data transmission standards, be it Unix Sockets, UART, RS-485, Ethernet IP or USB Serial, URAP is simple to implement and open to be used by all.
URAP is a data communication protocol where a primary client reads and writes data to a secondary server, which allows access to up to 2^16 registers, each 32 bits wide. It assumes that it is being trasmitted on a one to one stream where no other possible processes or devices can listen in or interpret the packets; in other words when communicating over multi-device RS-485 or Ethernet another transport protocol is required such as IPv4. It is not secure by any means nor is it intended to be.
There are 5 types of packets and they are all dead simple:
With these 5 packets you can have almost all the functionality you need for simple embedded and non-embedded applications, where you just want to exchange variables back and forth.
All integers, floats, and etc. past 8 bits are little endian, due to the fact that all modern architectures are little endian. This includes register addresses.
Note this makes the bit layout look unusual, but it forgoes having to do any conversion on 99% of processors. This results in the write bit actually being the 9th bit in the packet, but the highest bit when programming.
For example, the array data
in the following code actually contains the
bytes [0b0000_0000, 0b1000_0000]
.
let register: u16 = 0b1000_0000_0000_0000;
let data: [u8; 2] = register.to_le_bytes();
This seems baffling when you look at the data being transferred, but to the processor and the code written this is as simple as it gets.
URAP uses an 8 bit CRC with 0x1D as it's polynomial, the same polynomial used for OBD. It does not use any weird init values, it is not reflected, and it is not XOR'd with anything post calculation. See this link for more info on how it works.
It should be noted that ACK and NAK bytes are not CRC'd.
To check the health of a connection, it is standard to read register 0 of the secondary and await a healthy response. It is recommended that URAP secondaries have minimum of 1 register due to this otherwise this check will not work. Also ensure that if you implement any form of read protection that register zero remains readable.
URAP Secondaries are encouraged to use write protection on registers which are intended to be read-only, in case of the odd chance a primary sends an erronous command. If there is an attempt to write to a write-protected register, the secondary should respond with a NAK to indicate that no writes have been committed and that there should be a change of code to fix this issue.
Primary -> Secondary, write register zero with value 42
1 Write Bit
000 0000 Count -1
0000 0000 0000 0000 Register
0010 1010 0000 0000 0000 0000 0000 0000 Value
0000 1111 CRC
Secondary -> Primary, write-ack
1010 1010 ACK
Alternatively, if register 0 is write protected you will get a NAK
Secondary -> Primary, nak
0000 0101 NAK, IndexWriteProtected
Primary -> Secondary, read register zero
0 Write Bit
000 0000 Count -1
0000 0000 0000 0000 Register
0000 0000 CRC
Secondary -> Primary, read-ack with the value 42
1010 1010 ACK
0010 1010 0000 0000 0000 0000 0000 0000 Value
0100 1111 CRC
These specifications are under CC BY. The source code in this repository is under the MIT License, and you can see the LICENSE file for more details.