Add RPC to Firmware 3002

From WPI Automation and Interventional Medicine (AIM) Robotics Laboratory

Jump to: navigation, search


For information on the protocol see:

In this How To I will be describing how to register a new RPC in the Bowler firmware. See

for SDK integration of RPC.

Contents

Overview Of Bowler RPC

The RPC system is the use of unique 4 byte codes to denote actions taken by the controller. These codes can have one of 4 method types, GET, POST, CRITICAL, and STATUS. POST methods are for sending volatile data. GET methods are a request for volatile or static data. CRITICAL methods are used for sending non-volatile data or for shutdown/keep alive codes. STATUS methods are return codes only, and the only valid codes are "_rdy" or "_err". RPC's can be overloaded across POST and GET. Any RPC can have a valid POST and GET but not CRITICAL, likewise any CRITICAL can not also have POST or GET.

Data sent with packets is expected to be in integer form. If numbers smaller then one are to be sent, then they must be converted to a fixed point integer and scaled in the SDK. Valid data types are 8,16 or 32 signed or unsigned integers. Data is sent with the most significant byte first, then the second most significant byte and so on.

The number 200 would be in represented in 8 bit as :

   [0xC8]

The number 200 would be in represented in 16 bit as :

   [0x00,0xC8]

The number 200 would be in represented in 32 bit as :

   [0x00,0x00,0x00,0xC8]

Picking an RPC

Before deciding on a 4 byte RPC make sure that that code is not in use already. 4 bytes beans there is a possible 2^32 possible combinations, so collisions are unlikely but, of course possible. For this exercise we will be working with an RPC that has an ascii representation of:

   "_tst"

also known as:

   0x7473745F

Since there are enough codes to go around, I try to use codes that have ascii representations. This makes the debug process easier for me, but is not necessary. Any 4 byte code will work. For this exercise we will have the POST method push down a 16 bit number and have the GET method return a 32 bit unsigned number.

To generate the #define string for use in the C header, please use the RPC_Gen tool found in the SVN under tools. It is a stand alone .jar that can be run without eclipse.

Sending data to the Firmware

The first thing we need to do is to make the firmware aware of the new RPC. We do this by making a #define of the 4 byte code as a 32 bit unsigned int inside UserApp.h. Note that the byte order of the #define is reverse of reading, that is the order the bytes are sent, and the equivalent 32 bit int representation of it.

   #define _TST					0x7473745F// Test RPC

The RPC processor will check for system RPC's first and if the RPC of an incoming packet is not a core system RPC, as with a User RPC, it will pass the RPC to the User RPC processors. Since we want to send data to the firmware we need to alter the UserPostRPCs. This function is passed the header struct and the packet array. It returns a true if the RPC was found and a false if the RPC was not found.

BYTE UserPostRPCs(BowlerPacket *Packet){
	WORD_VAL v;
	int zone = 2;
	switch (Packet->use.head.RPC){
	case _TST:
		v.byte.HB = Packet->use.data[0];
		v.byte.LB = Packet->use.data[1]];
		TestPost(v.Val);
		READY(Packet,zone,9);
		break;
	default:
		return FALSE;
	}
	return TRUE;
}

WORD_VAL is a union of a 16 bit unsigned word and a struct of named bytes. We also see the value we passes in being passed to a function.

Getting data from the Firmware

We will now overload "_tst" with a GET method. The get method will be returning a 32 bit signed int to the SDK. We see the 32 bit long get broken up into Bytes. Note tht the user must specify what type of packet they are generating with the method type byte, and set the data size byte. Also note that data size includes the RPC. In this case there are 4 bytes of RPC and 4 bytes of data, totalling 8;

BYTE UserGetRPCs(BowlerPacket *Packet){
	extern LONG_VAL l;
	int zone = 1;
	switch (Packet->use.head.RPC){
	case _TST:
		Packet->use.head.Method = POST;// Set the method type
		// Set the 4 bytes of the RPC
		Packet->use.head.RPC = GetRPCValue("_TST");
		// Set the 4 bytes of data
		Packet->use.data[0]=l.byte.MB;
		Packet->use.data[1]=l.byte.UB;
		Packet->use.data[2]=l.byte.HB;
		Packet->use.data[3]=l.byte.LB;
		Packet->use.head.DataLegnth = 8;// Set the data size
		break;
	default:
		return FALSE;
	}
	return TRUE;
}
Personal tools