A test of creating custom classes for control over RPC. Creates an LED class with member functions callable over serial.

Dependencies:   mbed

main.cpp

Committer:
JimmyTheHack
Date:
2010-09-29
Revision:
3:d70703d85ff9
Parent:
2:fe4c1d5a97fa
Child:
4:840f6002b8c2

File content as of revision 3:d70703d85ff9:

/*  Test of custom RPC classes.   An introduction to the RPC environment.

Based heavily off of code from iva2k
http://mbed.org/users/iva2k/programs/pub_iva2k_ethrpc/gpdz3x
in turn based off of servo library
http://mbed.org/projects/cookbook/svn/Servo/trunk/Servo.h
http://mbed.org/projects/cookbook/svn/Servo/trunk/Servo.cpp

This code features heavy copy-pasting, so I take little credit for the content.  My goal was not to create original code, but to put together a basic introduction
to help myself and others understand how to implement custom classes in RPC.

This code creates a custom RPC class called LED.   The LED class contains two member functions, toggle and blink.
Normally when compiling a program the original names of the objects are lost.  In order to be able to call these functions by name after compiling, we must save the name in a string.
The name of our object and necessary arguments for the initialization function are saved using the get_rpc_class() function.    The name of each member function and their arguments must also be
registered using get_rpc_methods().




From: http://mbed.org/cookbook/Interfacing-Using-RPC

RPC Commands are in the format: "/<Object name>/<Method name> <Arguments separated by spaces>
If you send just "/" mbed will return a list of objects that can be used
If you send "/<object name>/" then mbed will return the methods which can be used on this object.

I haven't finished digging through this yet, but I think most of the documentation for the RPC functions is in the files:
http://mbed.org/projects/libraries/svn/mbed/trunk/Base.h
http://mbed.org/projects/libraries/svn/mbed/trunk/rpc.h


*/
/** Includes

*
*/
#include "mbed.h"
#include "rpc.h"


/**Class: LED
*
*attached to an LED pin, contains simple blink functionality over serial
*/
class LED :public Base { //make sure to define the class with inheritance from the Base RPC class.
public:
    /**
    *Constructor
    */
    LED(PinName mypin, const char *name=NULL);
    /**Blink LED*/
    void blink(int n);
    /** switch state of LED*/
    int toggle();
    /** pin LED is attached to*/
    DigitalOut LEDpin;
    /**state of LED
    */
    int state;

#ifdef MBED_RPC  //this code will not compile unless we have included the rpc.h file.    So this class can also be used without RPC.
    virtual const struct rpc_method *get_rpc_methods();
    static struct rpc_class *get_rpc_class();
#endif    // MBED_RPC  
};


/**Initialization Function**/
LED::LED(PinName mypin, const char *name) : Base(name), LEDpin(mypin) { //initialize pin    
    LEDpin.write(0);
    state=false;  //set LED to off
}
/**switch the state of the LED**/
int LED::toggle() {    
    if (state==0) {
        state=1;
    } else {
        state=0;
    }
    LEDpin=state;
    return state; //print the current state of the LED
}

/**blink the LED n times**/
void LED::blink(int n=1) {   
    do { //blink at least once
        toggle(); //toggle LED state
        wait(.2);
        toggle(); //return LED to original state
        wait(.2);
        n--;
    } while (n>=1);
}


#ifdef MBED_RPC 
/**Create a list of the available methods which can be called for this class**/
const rpc_method *LED::get_rpc_methods() {    
    static const rpc_method rpc_methods[] = {
        { "toggle", rpc_method_caller<int, LED, &LED::toggle> },  //first specify the name string.   The arguments to rpc_method_caller appear to be <outputs, RPC class, inputs, reference to function>.
        //In this case, we have one output and no inputs so they are skipped.   We must only specify the class of the object the method belongs to and the address of the method.

        { "blink", rpc_method_caller<LED, int, &LED::blink> },  //this method has no outputs so they are skipped, but we must specify the input to be of type int.
        RPC_METHOD_SUPER(Base), 
    };
    return rpc_methods;
}
/**Register the class itself as an RPC-callable class**/
rpc_class *LED::get_rpc_class() {    
    static const rpc_function funcs[] = {
        { "new", rpc_function_caller<const char*, PinName, const char*, &Base::construct<LED,PinName,const char*> > },  //still don't fully understand the arguments in this line. I suppose the first argument may just be an output echo of the name.
        RPC_METHOD_END
    };
    static rpc_class c = { "LED", funcs, NULL };
    return &c;
}
#endif    // MBED_RPC


/* end LED class definition */





Serial pc(USBTX, USBRX); //set up serial communication
/**Wait for RPC commands and then call the interpreter**/
int main() {   
    // specify which classes we would like to be able to call over LED
    Base::add_rpc_class<Timer>();  //a class included in the core mbed RPC library
    Base::add_rpc_class<LED>();    //my own custom LED class

    // receive commands, and send back the responses
    char buf[256], outbuf[256];
    while (1) {
        pc.gets(buf, 256); //grab serial commands
        rpc(buf, outbuf);  //interpret the RPC commands
        //this function only requires an input string and output string, so we can obtain RPC commands via a different interface than serial if desired.
        pc.printf("%s\n", outbuf); //print back over serial
    }
}