Framework for reading and writing variables in real time on any MBED platform.

DistantIO

This is the C implementation of the DistantIO slave framework.

Library is working but slight API breaks may occur in the future. C++ version is also in development.

To get the master-side implementation, see https://github.com/Overdrivr/DistantIO

Revision:
0:c4676d32d381
Child:
1:aaffeb93f99b
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/distantio.cpp	Tue Sep 15 15:27:55 2015 +0000
@@ -0,0 +1,358 @@
+/*
+ * distantio.c
+ *
+ *  Created on: Oct 13, 2014
+ *      Author: B48923
+ */
+
+#include "distantio.h"
+#include "crc.h"
+#include "string.h"
+#include "protocol.h"
+
+/*
+ * WARNING : IMPLEMENTATION FOR LITTLE-ENDIAN PROCESSOR
+ * TODO : HANDLE BOTH
+ */
+
+static log Log;
+uint32_t tmp;
+
+void send_variable(uint16_t index);
+uint16_t get_size(dio_type type);
+void send_descriptor(uint16_t index);
+void send_group_descriptor(uint16_t index);
+
+/**
+ * Inits the distant io framework
+ */
+void init_distantio()
+{
+	uint16_t i;
+	char default_name[] = {"undef.  "};
+	Log.amount = 0;
+	for(i = 0 ; i < VARIABLES_AMOUNT ; i++)
+	{
+		Log.variables[i].size = 0;
+		Log.variables[i].ptr = 0;
+		Log.variables[i].writeable = 0;
+		Log.variables[i].id = i;
+		strcpy(Log.variables[i].name,default_name);
+		Log.variables[i].send = 0;
+		Log.variables[i].groupID = 0;
+	}
+	tmp=0;
+	Log.current_group_id = 0;
+	strcpy(Log.groups[0].name,"default");
+}
+
+/**
+ * Register a variable exchanged with the computer
+ */
+uint8_t register_var(void* ptr, uint16_t size, dio_type type, uint8_t writeable, char* name)
+{
+	// Too many variables, aborting
+	if(Log.amount >= VARIABLES_AMOUNT)
+		return 1;
+
+	Log.variables[Log.amount].ptr = (uint8_t*) ptr;
+	Log.variables[Log.amount].size = get_size(type);
+	Log.variables[Log.amount].writeable = writeable;
+	Log.variables[Log.amount].type = type;
+	Log.variables[Log.amount].groupID = Log.current_group_id;
+	strcpy(Log.variables[Log.amount].name,name);
+
+	Log.amount++;
+
+	return 0;
+}
+
+void start_group(char* groupname)
+{
+	Log.current_group_id++;
+	strcpy(Log.groups[Log.current_group_id].name,groupname);
+}
+
+/**
+ * Send var descriptor
+ */
+
+void send_descriptor(uint16_t index)
+{
+	if(index >= Log.amount)
+		return;
+
+	static uint8_t buffer[PAYLOAD_SIZE];
+	uint8_t type;
+
+	// Respond returned-descriptor
+	buffer[0] = 0x00;
+
+	// Write id
+	uint16_t ID = ((Log.variables[index].groupID & 0x003F) << 10) + (index & 0x3FF);
+	uint8_t * temp_ptr = (uint8_t*)(&ID);
+	buffer[1] = *(temp_ptr + 1);
+	buffer[2] = *(temp_ptr    );
+
+	// Write type & writeable
+
+	type = (uint8_t)(Log.variables[index].type);
+
+	if(Log.variables[index].writeable)
+		type += 0xF0;
+
+	buffer[3] = type;
+
+	//Write name
+	uint16_t i = 4;
+	for(uint16_t k = 0 ; k < 8 ; k++)
+	{
+		if(k < strlen(Log.variables[index].name))
+		{
+			buffer[i] = Log.variables[index].name[k];
+			i++;
+		}
+		else
+			buffer[i++] = 0;
+	}
+
+	// Compute crc
+	uint16_t crc_value = crc16(buffer,i);
+
+	// Write crc into buffer's last byte
+	buffer[i++] = (crc_value >> 8) & 0xFF;
+	buffer[i++] = crc_value & 0xFF;
+
+	// Encode frame
+	encode(buffer,i);
+}
+
+void send_group_descriptor(uint16_t index)
+{
+	if(index > Log.current_group_id)
+		return;
+
+	static uint8_t buffer[PAYLOAD_SIZE];
+
+	// Respond returned-descriptor
+	buffer[0] = 0x00;
+
+	// Write id
+	uint16_t ID = (index & 0x3F) << 10;
+	uint8_t * temp_ptr = (uint8_t*)(&ID);
+	buffer[1] = *(temp_ptr + 1);
+	buffer[2] = *(temp_ptr);
+
+	// Write type
+	buffer[3] = 0x07;
+
+	//Write name
+	uint16_t i = 4;
+	for(uint16_t k = 0 ; k < 8 ; k++)
+	{
+		if(k < strlen(Log.groups[index].name))
+		{
+			buffer[i] = Log.groups[index].name[k];
+			i++;
+		}
+		else
+			buffer[i++] = 0;
+	}
+
+	// Compute crc
+	uint16_t crc_value = crc16(buffer,i);
+
+	// Write crc into buffer's last byte
+	buffer[i++] = (crc_value >> 8) & 0xFF;
+	buffer[i++] = crc_value & 0xFF;
+
+	// Encode frame
+	encode(buffer,i);
+}
+
+void distantio_decode(uint8_t* data,uint16_t datasize)
+{
+	// First check data size
+	// 1 byte cmd + 2 bytes id + 1 byte type + FRAME_SIZE + 2 byte CRC
+	if(datasize != PAYLOAD_SIZE)
+		return;
+
+	// Second, check CRC
+	uint16_t crc_value = crc16(data,PAYLOAD_SIZE-2);
+	uint16_t crc_rx = ((uint16_t)data[PAYLOAD_SIZE-2] << 8) | data[PAYLOAD_SIZE-1];
+
+	if(crc_value != crc_rx)
+		return;
+	
+	// Process frame
+	// First, identify command
+	uint8_t command = data[0];
+	
+	// Second, identify variable ID
+	uint16_t ID = data[2] + (data[1] << 8);
+	ID = (ID & 0x3FF);
+	
+	// Third, identify data type
+	uint8_t type = data[3];
+
+	switch(command)
+	{
+		// User requested descriptors
+		case 0x02:
+			// Send variables
+			for(uint16_t i = 0 ; i < Log.amount ; i++)
+				send_descriptor(i);
+			// Send groups
+			for(uint16_t i = 0 ; i <= Log.current_group_id ; i++)
+				send_group_descriptor(i);
+			break;
+
+		// User provided value to write
+		case 0x04:
+			if(ID >= Log.amount)
+				return;
+
+			if(Log.variables[ID].writeable == 0x00)
+				return;
+
+			if(Log.variables[ID].type != type)
+				return;
+
+			uint16_t start_address = 4 + DATA_SIZE - 1;
+
+			// Copy contents directly into variable
+			for(uint16_t i = 0 ; i < Log.variables[ID].size ; i++)
+			{
+				// Packet is big-endian, convert to little-endian
+				uint8_t offset = start_address - i;
+				*(Log.variables[ID].ptr + i) = *(data + offset);
+			}
+			break;
+
+		// User requested variable read
+		case 0x05:
+			if(ID >= Log.amount)
+				return;
+
+			Log.variables[ID].send = 1;
+			break;
+
+		// User requested stop variable read
+		case 0x06:
+			if(ID >= Log.amount)
+				return;
+			Log.variables[ID].send = 0;
+			break;
+		
+	}
+}
+
+void send_variables()
+{
+	for(uint16_t i = 0 ; i < Log.amount ; i++)
+	{
+		if(Log.variables[i].send == 0)
+			continue;
+
+		send_variable(i);
+	}
+}
+
+void send_variable(uint16_t index)
+{
+	if(index >= Log.amount)
+		return;
+
+	static uint8_t buffer[PAYLOAD_SIZE];
+
+	// Response code 0x01
+	buffer[0] = 0x01;
+	
+	// Write variable ID
+	uint16_t ID = ((Log.variables[index].groupID & 0x003F) << 10) + (index & 0x3FF);
+	uint8_t * temp_ptr = (uint8_t*)(&ID);
+	buffer[1] = *(temp_ptr + 1);
+	buffer[2] = *(temp_ptr);
+	
+	// Write variable type
+	buffer[3] = Log.variables[index].type;
+	//TODO writeable
+
+	uint16_t i = 4;
+
+	// Write data
+	for(uint16_t k = 0 ; k < DATA_SIZE ; k++)
+	{
+		uint16_t off = DATA_SIZE - 1 - k;
+
+		// Fill buffer with data
+		if(off < Log.variables[index].size)
+		{
+			temp_ptr = Log.variables[index].ptr + off ;
+			buffer[i++] = *temp_ptr;
+		}
+		// Fill remaining bits with 0
+		else
+		{
+			buffer[i++] = 0;
+		}
+	}
+	
+	// Compute crc
+	uint16_t crc_value = crc16(buffer,i);
+
+	// Write crc into buffer's last byte
+	buffer[i++] = (crc_value >> 8) & 0xFF;
+	buffer[i++] = crc_value & 0xFF;
+
+	// Encode frame
+	encode(buffer,i);
+}
+
+void send_alive()
+{
+	static uint8_t buffer[PAYLOAD_SIZE] = {0x03,0x00,0x10,0x00,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x00,0x00};
+	
+	uint16_t index = 1;
+	uint16_t group = 0;
+	uint16_t ID = ((group & 0x003F) << 10) + (index & 0x3FF);
+	uint8_t * temp_ptr = (uint8_t*)(&ID);
+	buffer[1] = *(temp_ptr + 1);
+	buffer[2] = *(temp_ptr    );
+
+	// Compute crc
+	uint16_t crc_value = crc16(buffer,PAYLOAD_SIZE - 2);
+
+	// Write crc into buffer's last byte
+	buffer[PAYLOAD_SIZE - 1] = crc_value & 0xFF;
+	buffer[PAYLOAD_SIZE - 2] = (crc_value >> 8) & 0xFF;
+
+	// Send frame to encoding
+	encode(buffer,PAYLOAD_SIZE);
+}
+
+
+/**
+ * Returns the size in byte for each variable
+ */
+
+uint16_t get_size(dio_type type)
+{
+	switch(type)
+	{
+		case dio_type_FLOAT:
+		case dio_type_UINT32:
+		case dio_type_INT32:
+			return 4;
+
+		case dio_type_UINT16:
+		case dio_type_INT16:
+			return 2;
+
+		case dio_type_UINT8:
+		case dio_type_INT8:
+		default:
+			return 1;
+	}
+}
+