I have small project where I am passing structured data over serial to a PC app. The data is used to provide a visual topology of my nr24L01+ star network. My question is in regards to best practice and data integrity when passing structured data over serial.
As an example, I have the following struct:
typedef struct __attribute__ ((packed)) { uint8_t start_checksum; uint8_t end_checksum; uint8_t id; uint16_t data; uint16_t data2; } nrf24_packet_t; nrf24_packet_t pck;
My first two bytes of the struct are "Checksums" to check for data integrity when the data is received on the PC app:
pck.id = node_number; // nrf24 node id pck.data = fakeval++; // dummy data pck.data2 = 350; // dummy node // add a check sum pck.start_checksum = 255; pck.end_checksum = 7;
In my project, the packet (nrf24_packet_t ) is passed from node to node until it gets the "Base Node". The Base Node will then send the data to the PC like this:
void receive_data(void){ if(nrf24_dataReady()) { nrf24_flushTx(); uint8_t payLoadsize = nrf24_getPayloadLength(); if(payLoadsize > 32){ return; } uint8_t pipeNo = nrf24_getPayLoad(&pck, sizeof(nrf24_packet_t)); memcpy(temp, &pck, sizeof temp ); for(uint8_t i = 0; i < sizeof(temp); i++){ printf("%d\n", temp[i]); //tokenize each value with a \n } printf("\n\r"); delay_s(2); // give at least 2 seconds to let the PC app handle the load } }
I tokenize the bytes in the buffer with a newLine '\n' and on the PC side validate the incoming data. The incoming packet looks something like this:
[0]: "255" - start check sum [1]: "7" - end check sum [2]: "2" - node id [3]: "12" - next 4 bytes are data [4]: "0" [5]: "94" [6]: "1" [7]: "" [8]: "\r"
As mentioned, the first 2 bytes are used to verify the packet. The below is some c# code, but is pretty straight forward used to verify the packet data:
private void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e) { SerialPort sp = (SerialPort)sender; try { string indata = sp.ReadExisting(); string[] dataArray = indata.Split('\n'); if (dataArray.Length > 5) { Packet pck = new Packet { StartCheckSum = Convert.ToInt32(dataArray[0]), EndCheckSum = Convert.ToInt32(dataArray[1]), Id = Convert.ToInt32(dataArray[2]), Value = Convert.ToInt32(dataArray[3]), }; // verify the data here if (pck.StartCheckSum == 255 && pck.EndCheckSum == 7 && pck.Id > 0 && pck.Id < 252) { RenderNodeDelegate d = new RenderNodeDelegate(renderNode); this.Invoke(d, new object[] { pck.Id.ToString() }); } else { PacketCountDelegate pd = new PacketCountDelegate(packetCountHandler); this.Invoke(pd, new object[] { false }); } } } catch (Exception ex) { PacketCountDelegate pd = new PacketCountDelegate(packetCountHandler); this.Invoke(pd, new object[] { false }); } sp.DiscardInBuffer(); // clear any incoming data until we update the UI }
My questions is; is this the best approach or is there a better way to send structured data over serial and verify its integrity?
My approach works and the final outcome is a nice topology of my network, but perhaps there is a better way: