Before I forget – I now have a generic logger running on a Mac, written in Go.
It listens on a specified IP address + TCP port number, and if the format is ok, writes it to a mySQL table. I can send from any wifi enable project, like from an ESP-01, for example.
The format (today) is composed of pairs of values, to 24 bytes long (so, 12 pairs). The two parameters are called opr (operator) and prm (parameter). The byte layout is:
|0,1||Source Network (opr) could be RF, WiFi, wired I2C, SPI, etc
Source Node ID (prm) the node ID on that network
|2,3||Destination Network (opr)
Destination Node ID (prm)
|4,5||Payload Type (opr) – actually – split into 16 media types + 16 payload types
Payload Version (prm) – for any media+payload, also a version to support mixed version environments to allow for graceful / rolling upgrades of equipment firmware
|6,7||MAC – Message Authentication / Challenge – Lo (opr) : 16 bits of message authentication
MAC – Message Authentication / Challenge – Hi (prm)
The choice of length might seem arbitrary (and REALLY short) but it’s to allow for nodes connected via RF (i.e. a Nordic radio, like the nRF24l01) to send at an optimal packet size. Some of the tests I’ve seen but not yet replicated suggest that good performance can be had with 24 byte packets, but loss/corruption seems to be more of an issue at 32 bytes.
To maintain flexibility for true WiFi connections it shouldn’t be too much of a stretch to specify a different Payload Type which could extend the packet to hundreds of byte pairs, probably 1k is a good limit if the ESP-8266 is going to have to buffer any of this.
I specify the networks and node ID’s separately from the IP info because it’s likely that some nodes are only connected via I2C/UART or IR links. In this way intermediate nodes can act as routers to forward the packets, hopefully to some kind of hub or handler.
The data section, for logging, can be viewed two ways, depending on log type.
The first version is to send register values; so the opr is the register #, and the prm is that registers value. This means I don’t have to send sequential register space, but it’s twice as slow to send. It does mean I can send ANY register space in any order, however.
The other version is to send specific formats, where every byte from 8..23 has a specific meaning for that node. It’s less flexible, but might be quicker for sending mid-rate data blocks, like compressed audio.
I’m leaving encryption out of this spec. Adding it would mean simply a prior encryption exchange, and then probably encrypting only the data bytes. I suspect I’ll use offline updates of one-time pad tables – but that’s another post.
The last note (and probably kinda important) is why the bytes are labeled as OPERATOR and PARAMETER. Not written (quite this way, anyway) is an interpreter that basically looks like assembly language, and consumes ONLY two byte instructions; one byte for opcode, on byte for parameter (literal, offset, etc).
So this means that while I can use the transport right away for logging, it can also carry command and configuration instructions later, in different payload types.