RPC Interface Library

The RPC interface can be really useful because it makes it possible to interface with mbed without having to worry about the communication method. However, Many projects require more than just Digital and Analog I/O and want to make use of the mbeds interfaces or work with many of the libraries which have already been written for various sensors and actuators. This library provides a method of adding RPC functionality without you having to write any of the communication or RPC code. It is made up of 3 parts:

  • RPCFunction - A class which can be used to call user defined functions over RPC
  • RPCVariable - A class which allows you to read and write the value of a variable on mbed using RPC
  • SerialRPCInterface - A class which will set up RPC over Serial

» Import this library into a programRPCInterface

Library to provide a mechanism to make it easier to add RPC to custom code by using RPCFunction and RPCVariable objects. Also includes a class to receive and process RPC over serial.

The mbedRPC software libraries such as for Java, Matlab and LABVIEW also support the RPCFunction and RPCVariable so as to simplify the connection on both the mbed and computer software.

RPCFunction

The RPCFunction object makes it possible to call a custom function over RPC. The function must be of the form void foo(char * input, char * output). To use you first create the function, you then create the RPCFunction object when you attach the function and give it a name by which it will be called over RPC. You might use the input and ouput strings to pass several numeric values by using sscanf and sprintf to read and write the input and output strings. Alternativly you might not need the strings and instead just call the function.

//Create a function of the required format
void foo(char * input, char * output);
//Attach it to an RPC object
RPCFunction rpc_foo(&foo, "foo");

void foo(char * input, char * output){
   int x,y;
   sscanf(input, "%i, %i", &x, &y);

   //Do something here......

   sprintf(output, "%i, %i", x, y );
}

To run this function over RPC you then call the run method on the RPCFunction object. The function you define can be used to wrap the common interactions with class methods that you wish to call over RPC.

Here is an example of it being used to return the value from an I2C Range finder. Using the RPCFunction has made the Rangefinder avaliable over RPC as its library doesn't include support for RPC.

» Import this program

00001 /**
00002 * Copyright (c)2010 ARM Ltd.
00003 * Released under the MIT License: http://mbed.org/license/mit
00004 */
00005 #include "mbed.h"
00006 #include "SerialRPCInterface.h"
00007 #include "SRF08.h"
00008 
00009 using namespace mbed;
00010 
00011 //Create the interface on the USB Serial Port
00012 SerialRPCInterface RPC(USBTX, USBRX);
00013 void ReadRange(char * input, char * output);
00014 RPCFunction RangeFinder(&ReadRange, "RangeFinder");
00015 SRF08 srf08(p9, p10, 0xE0);      // Define SDA, SCL pin and I2C address 
00016 DigitalOut myled(LED1);
00017 
00018 int main() {
00019 
00020     while(1) {
00021         
00022     
00023         myled = 1;
00024         wait(0.2);
00025         myled = 0;
00026         wait(0.2);
00027     }
00028 }
00029 
00030 //As neither I2C nor the SRF08 library is avalible directly over RPC we create a Custom Function which we make RPCable by attaching to an RPCFunction
00031 void ReadRange(char * input, char * output){
00032     //Format the output of the srf08 into the output string
00033     sprintf(output, "%f", srf08.read());
00034 }

Information

RPC command to read the range: /RangeFinder/run

A complete example using the range finder and software on a computer will be written up soon

» Import this library into a program

Public Member Functions

  RPCFunction (void(*f)(char *, char *), const char *=NULL)
  Constructor.
char *  run (char *str)
  run
char *  read ()
  Reads the value of the output string.

RPC variable

RPCVariable allows you to read and write the value of any variable on mbed. You do this by creating an RPCVariable object and then attaching the variable you want to access over RPC.

//First create the variables you wish to use
float f;
int i;
char c;
//Then attach them to an RPCVariable Object
RPCVariable<float> rpc_f(&f, "f");
RPCVariable<int> rpc_i(&i, "i");
RPCVariable<char> rpc_c(&c, "c");

Information

The RPC commands to read and write the float f would be:

  • /f/write 0.123
  • /f/read

Here is an example of this being used to control a Motor taking feedback from a QEI. None of the control is implemented on mbed, this must be done on the computer however this method has qucikly given the computer access to the Motor and QEI class neither of which are otherwise not avaliable over RPC

» Import this program

00001 /**
00002 * Copyright (c)2010 ARM Ltd.
00003 * Released under the MIT License: http://mbed.org/license/mit
00004 */
00005 
00006 #include "mbed.h"
00007 #include "QEI.h"
00008 #include "Motor.h"
00009 #include "SerialRPCInterface.h"
00010 
00011 //Create the interface on the USB Serial Port
00012 SerialRPCInterface SerialInterface(USBTX, USBRX);
00013 
00014 QEI Encoder(p29 ,p30, NC, 48);
00015 Motor Wheel(p23, p21, p22);
00016 
00017 //Create float variables
00018 float MotorOutput = 50;
00019 float Percentage = 0;
00020 
00021 //Make these variables accessible over RPC by attaching them to an RPCVariable
00022 RPCVariable<float> RPCMotorOut(&MotorOutput, "MotorOutput");
00023 RPCVariable<float> RPCPercentage(&Percentage, "Percentage");
00024 
00025 int main(){
00026 
00027     Encoder.reset();
00028     float NoPulses;
00029     
00030     while(1){ 
00031          NoPulses = Encoder.getPulses();
00032         Percentage = ((NoPulses / 48) * 100);
00033         //RPC will be used to set the value of MotorOutput.
00034         Wheel.speed((MotorOutput - 50) * 2 / 100);
00035         wait(0.005);
00036     }
00037 }

Information

  • rpc command to get the position: /percentage/read
  • rpc command to set the motor speed: /MotorOutput/write 0.8

A complete example of closed loop motor control using the code above and a computer running a software package will be written up soon.

Note that this is entirly asynchronous and so you could get unexpected results if the code on mbed and an interupt driven RPC handler both try to write different values to the variable at the same time.It won't be possible to predict which value has been written into the variable. As such it would be advisable to consider some variables as only written to over RPC and only read by mbed code and other variables the opposite.

The RPCVariable is well suited to the motor and QEI which can be updated whenever however the I2C Range Finder is better suited to the RPCFunction as every reading has to be requested from the device.

These two classes should help you to add RPC to projects which go beyond just reading and writing to mbed's pins. RPCFunction and RPCVariable interfaces are included in the software libraries so as with the rest of the RPC interface you can communicate with mbed without having to design and implement the communication protocol etc.

To avoid having to format your data into and out of strings both on mbed and in your software on the computer, but still have synchronous communication you could combine the RPCvariables and RPCFunctions. Here is the Range finder example using this approach:

float Range = 0;
RPCVariable rpc_range(&Range, "Range");

void RangeFinder(char * input, char * output){
 Range = srf08.read();
}

RPCFunction rpc_GetRange(&RangeFinder, "RangeFinder");

Information

To get the Range now requires 2 RPC commands:

  • /RangeFinder/run
  • /Range/read

This does mean that you have to make a few more RPC requests (and so your communication will be slower) but it could be useful if you want to avoid parsing strings either on mbed or in the software you are working with.

» Import this library into a program

Public Member Functions

template<class A >
  RPCVariable (A *ptr, const char *name)
  Constructor.
read ()
  Read the variable over RPC.
void  write (T value)
  Write a value to the variable over RPC.

SerialRPCInterface

SerialRPCInterface will set up RPC for serial by registering all the base classes and setting up the serial port on an intterupt. When a serial communication is recevied it will pass the commands to the RPC and return the response. This leaves your own code to run on mbed.

To use all you have to do is create it at the top of your program

SerialRPCInterface SerialInterface(USBTX, USBRX);

You can then write the rest of your code as required.

» Import this library into a program

Public Member Functions

  SerialRPCInterface (PinName tx, PinName rx, int baud=9600)
  Constructor.
void  Disable (void)
  Disable the RPC.
void  Enable (void)
  Enable the RPC.



2 related questions:


21 comments:

02 Oct 2010

this sounds like what i need: amethod to communicate with my MBED over ethernet - wiggle pins etc, but how can i get my PC to send / recive messages?

i REALY want to use DELPHI to do the clever stuff

how do i communicate with MBED,

Cheers CERI

04 Oct 2010

Is it me or are the library files listed here currently unavaiable?

04 Oct 2010

Hi Joe,

If you hit 'enable beta' at the top of the page, this page will make a lot more sense! Libraries as discussed here are only available in beta right now. The beta version will become 'live' very soon now - in the next couple of days hopefully.

Dan

04 Oct 2010

Hi Dan,

Cheers. I thought I'd seen the libraries appear on this page correctly before, just forgot that beta mode resets on new sessions. I'll just have to remember for the next few days until the beta goes 'live'.

Joe

17 Oct 2010

I can't work out what to #include to be able to use RPCFunction in my code. "SerialRPCInterface.h" can't be found. There's no "enable beta" at the top of the page, so I assume the beta is now live?

I tried clicking on the RPCInterface link and then the "Import into Compiler" button, and that opens the Import pane in the Compiler with http://mbed.org/users/MichaelW/libraries/RPCInterface/lfctbw in the Source URL box, but the Import button is greyed-out.

Help!

Rob.

29 Dec 2010

You have to click on the library button or whatevery you call where it says import as

15 Jan 2011

This is what the first code snippet should look like to actually work:

//Create a function of the required format
void foo(char * input, char * output);
//Attach it to an RPC object
RPCFunction rpc_foo(&foo, "foo");

void foo(char * input, char * output){
   int x,y;
   sscanf(input, "%i, %i", &x, &y);

   //Do something here......

   sprintf(ouput, "%i, %i", x, y );
}

One semicolon was missing, and the asterisk after the name of the actual foo function implementation has no business being there.

23 Jun 2011

This is cool!!

04 Jul 2011

Hiya

Attached is a link to a simple program where the required RPC command length seems to affect the stability of the program. If the last custom command is changed from:

"LED4_Off_LONG_NAME" to "LED4_Off_LONG" then the program seems to work in a stable manner. However, if this is not changed then the mbed will hang if there are multiple non-ideal inputs i.e. multiple backslashes. Is there any reason for this and if so can some find a way around this. I do realise that the program attached can use shorter commands, however this bug seems to affect other programs with long command names which are required. Any help will be appreciated.

http://mbed.org/users/NathanWhitaker/programs/TestRPC/ltrx2p

A last note, I am using Tera Term to connect to the mbed with CR+LW forced.

Nathan

11 Aug 2011

Hi Michael,

Thanks for the RPC library. It has become my favorite channel for controlling and getting data off the mbed. There are times, though, that the serial and timer interrupts will clash, especially if you have really frequent Tickers in your code. The symptom is that the code just hangs in the middle of an RPC transaction, especially if an RPCFunction is returning a large string.

The solution is quite simple give the serial interrupt a low priority and the timer a higher one. So, wherever I've used SerialRPCInterface, I also add the following lines to my main:

    NVIC_SetPriority(UART0_IRQn, 2);
    NVIC_SetPriority(TIMER3_IRQn, 0);

Hope this helps someone.

Zainul.

11 Aug 2011

My mbed regularly easily hangs somewhere in the webserver since I'm using RPC. When I request a log file for example http://ip_of_my_mbed/log.txt my mbed also easily hangs. It helps a bit to use little and short RPC commands and to use fast code. Because my mbed hangs so easy in the webserver library, I am using a watchdogtimer to restart the mbed. This helps often but not always.

14 Aug 2011

Hi, Just a question : would it be possible to have an example of adding a RPC command with RPC Interface Library working with the HTTPServer ? The RPC "classic" library works perfect with HTTP but it's very complicated to add a command. Whith RPC Interface Library, simple to add command, but no example with HTTP !

I'm a bit lost within all of this, so it could be very helpfull ! ^^

Thanks a lot.

FX

04 Sep 2011

Hello, How would you declare a string RPC-Variable? I have tried the following but it returns an error indicating that the type is not valid :

char SomeString[20] = "this is a string"; .. RPCVariable<char *> rpc_String(SomeString, "MyString");

Thanks, Louis

23 Sep 2011

Jasper Sikken,

I am also a victim of the hanging problem you mentioned above. My mbed regularly easily hangs somewhere in the webserver. I'm using RPC to control the Digital outs and Digital ins. I can't use watchdogtimer also as it is critical system. Jasper, Do you think RPC variables inside mbed program can make it hang? Have you solved this issue? If yes, please share with me. I am ready to send you my code if it is ok. I use HTTPServer in static ip mode. pl. reply. Thanks joby jobyiuac@gmail.com

30 Sep 2011

joby antony, did disabling interrupts help to solve the hanging problem?

__disable_irq(); 	// Disable Interrupts
// do something that can't be interrupted
__enable_irq(); 	// Enable Interrupts

Did you disable interrupts for the webserver part?

24 Nov 2011

Hi,

I´m new to c++ and so on I´m the best in coding ;-) but I need a bit help. My problem is:

I would like to use the rpc funktion to send command to the mbed. BUT the mbed should look if the ip or mac is one I stored in programm. Cause I don´t want that anyone else could gibve the commands to the mbed rather than me :-( Is there any way to check Mac or ip adress within a RPCFuntion call like the one in eth.read(buf, size); printf("Destination: %02X:%02X:%02X:%02X:%02X:%02X\n",buf[0], buf[1], buf[2], buf[3], buf[4], buf[5]); printf("Source: %02X:%02X:%02X:%02X:%02X:%02X\n",buf[6], buf[7], buf[8], buf[9], buf[10], buf[11]);

???????????? I mean this way.....

mymac="00:01:02:03:04:05"; myip="192.168.178.33"; Create a function of the required format void foo(char * input, char * output); Attach it to an RPC object RPCFunction rpc_foo(&foo, "foo"); void foo(char * input, char * output){ int x,y; sscanf(input, "%i, %i", &x, &y);

get MACadress from sender and test against mymac or get IPadress from sender and test against myip if same then set variable else do nothing sprintf(ouput, "%i, %i", x, y ); }

Please help me, regards, Thomas

27 Mar 2012

Hello!

Thanks for the library, but I need some clarification.

I can use this only on SerialRPC?

There is no way of using this over HTTP???

28 Mar 2012

Hi Ernesto,

The RPCFuntion and RPCVariable classes can be used with RPC over HTTP, or RPC over any other transport method. They can both be used without using the serialRPCInterface class. Theres a demo using RPCFunctions over HTTP on this page (remote sensing demo at the bottom) which uses this code (see main.cpp)

» Import this programRPC_RemoteSensing

Remote Sensing demo. This is the code that runs on mbed to interface with the Remote Sensing Applet Demo

The SerialRPCInterface class just handles RPC commands received over serial. For more information on how RPC works go here

The RPCVariable and RPCFunctions will work over HTTP in the same way as any other object that can be used over RPC; though you cannot create new instances of them over RPC, ie you can only call ones which are created in code.

Hope this helps

Michael

28 Mar 2012

@Michael Walker

Thanks a lot for the quick response!

Maybe you should include this example in the cookbook page, it would really help newbies like myself.

I'm working in some interesting code to interface with LabVIEW over HTTP, once I'm done I'll also publish it here. Thanks again!!

04 Oct 2012

Hi

Are there any way to add security to the RPC communuication via HTTP? I mean is it possible to add a password to "set" functions, otherwise any one would be able to able to change settings.

Or maybe i misunderstand something :-)

Best regards

Tue

03 Dec 2012

How large are the input and output blocks passed by *input and *output It seems as if they're declared and passed by the RPC handler mechanism. I'm concerned that the output buffer could get overrun. It might be different if the called function was responsible for creating the buffer and could size it accordingly, but that's not what appears to be happening.

Also is the function called in an "interrupt" context? I'm thinking that it must be as it can be called asynchronously at any time. If it is an interrupt context then there must be a whole bunch of I/O operations that cannot be called safely, either due to blocking or due to locks. If all that's happening is setting and reading variables then no problem but this is remote *procedure* call, and if I wanted the procedure to access an external device I think I might have problems?

Alternatively if it uses the RTOS and a "Worker" thread then its probably a much safer context, and can perform complex I/O activities. I don't see any mention of a RTOS. Even with workers there still might be an issue with I/O operations and russian roulette scheduling though.

FWIW I've tried out a couple of demos and the serial handler appears "unsafe" in so far as it appears to block indefinitely if a character or string is received without a terminating character. Its a shame though, it looked like a real alternative to cooking up my own I/O handler from scratch.