Remote Procedure Call (RPC) over Websockets (uses MbedJSONValue)

Dependents:   RPC_mbed_client RPC_Wifly_HelloWorld RPC_Ethernet_HelloWorld

Files at this revision

API Documentation at this revision

Comitter:
samux
Date:
Thu Sep 22 10:14:52 2011 +0000
Child:
1:7b7230760e0c
Commit message:

Changed in this revision

MbedJSONRpc.cpp Show annotated file Show diff for this revision Revisions of this file
MbedJSONRpc.h Show annotated file Show diff for this revision Revisions of this file
MbedJSONRpcValue.cpp Show annotated file Show diff for this revision Revisions of this file
MbedJSONRpcValue.h Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MbedJSONRpc.cpp	Thu Sep 22 10:14:52 2011 +0000
@@ -0,0 +1,164 @@
+#include "MbedJSONRpc.h"
+
+RPC_TYPE MbedJSONRpc::call(char * fn, char * dest, MbedRpcValue& val, MbedRpcValue& resp) {
+
+    char json[150];
+    RPC_TYPE t;
+    string str = val.serialize();
+    int id = rand() % 100;
+    MbedRpcValue tmp;
+
+
+    sprintf(json, (const char *)MSG_CALL, my_id, dest, id, fn, str.c_str());
+    webs->Send(json);
+    t = waitAnswer(tmp, id, json);
+    if (t != CALL_OK)
+        return t;
+    resp = tmp["res"];
+    return CALL_OK;
+}
+
+RPC_TYPE MbedJSONRpc::waitAnswer(MbedRpcValue& v, int id, char * json) {
+    Timer tmr;
+
+    tmr.start();
+    while (1) {
+        if (tmr.read() > 5.0) {
+        #ifdef DEBUG
+            printf("timeout\r\n");
+        #endif
+            return SERVER_NOT_CONNECTED;
+        }
+        if (webs->read(json)) {
+        #ifdef DEBUG
+            printf("receive: %s\r\n", json);
+        #endif
+            parse(v, json);
+            return decodeMsg(v, id);
+        }
+    }
+}
+
+int MbedJSONRpc::methodAlreadyRegistered(char * s) {
+    for (int i = 0; i < index; i++)
+        if (!strcmp(name[i], s))
+            return i;
+    return -1;
+}
+
+
+int MbedJSONRpc::procAlreadyRegistered(char * s) {
+    for (int i = 0; i < index_proc; i++)
+        if (!strcmp(name_proc[i], s))
+            return i;
+    return -1;
+}
+
+void MbedJSONRpc::checkMethods(char * dest) {
+    char json[150];
+    char name[5];
+    MbedRpcValue tmp;
+    int id = rand() % 100;
+
+    sprintf(json, (const char *)MSG_INFO_METHODS, my_id, dest, id);
+    webs->Send(json);
+    waitAnswer(tmp, id, json);
+    printf("methods available on %s: ", dest);
+    for (int i = 0; i < tmp.size() - 1; i++) {
+        sprintf(name, "fn%d", i);
+        printf("%s%c ", tmp[name].get<string>().c_str(), (i == tmp.size() - 2) ? ' ' : ',');
+    }
+    printf("\r\n");
+}
+
+RPC_TYPE MbedJSONRpc::decodeMsg(MbedRpcValue& v, int id) {
+
+    if (v.hasMember("id_msg"))
+        if (v["id_msg"].get<int>() != -1 && id != v["id_msg"].get<int>()) {
+        #ifdef DEBUG
+            printf("bad id: %d\r\n",v["id_msg"].get<int>() );
+        #endif
+            return ERR_ID;
+        }
+
+    if (v.hasMember("msg")) {
+        std::string s = v["msg"].get<std::string>();
+        if (!strcmp(s.c_str(), "RESULT")) {
+            return CALL_OK;
+        }
+        if (!strcmp(s.c_str(), "REGISTER_OK")) {
+            return REGISTER_OK;
+        }
+    }
+
+    //there is an error
+    if (v.hasMember("cause")) {
+        std::string s = v["cause"].get<std::string>();
+        if (!strcmp(s.c_str(), "JSON_PARSE_ERROR"))
+            return JSON_PARSE_ERROR;
+        if (!strcmp(s.c_str(), "JSON_RPC_ERROR"))
+            return RPC_PARSE_ERROR;
+        else if (!strcmp(s.c_str(), "METHOD_NOT_FOUND"))
+            return PROC_NOT_FOUND;
+        else if (!strcmp(s.c_str(), "CLIENT_NOT_CONNECTED"))
+            return CLIENT_NOT_CONNECTED;
+    }
+    return RPC_PARSE_ERROR;
+
+}
+
+
+RPC_TYPE MbedJSONRpc::registerMethod(const char * public_name, void (*fn)(MbedRpcValue& val, MbedRpcValue& res) ) {
+    char json[100];
+    int id = rand() % 100;
+    MbedRpcValue tmp;
+    RPC_TYPE t;
+
+    sprintf(json, (const char *)MSG_REGISTER, my_id, id, public_name);
+    webs->Send(json);
+    t = waitAnswer(tmp, id, json);
+    if (t != REGISTER_OK)
+        return t;
+    if( index_proc == NB_METH )
+        index_proc = NB_METH - 1;
+    proc[index_proc] = fn;
+    name_proc[index_proc++] = public_name;
+    return REGISTER_OK;
+}
+
+
+void MbedJSONRpc::work() {
+    char json_recv[150];
+    DigitalOut led4(LED4);
+    MbedRpcValue v, r;
+    int i = -1;
+    while (1) {
+        wait(0.2);
+        if (webs->read(json_recv)) {
+            parse(v, json_recv);
+            if (v.hasMember("method") && v.hasMember("from") && v.hasMember("id_msg") && v.hasMember("params") && v.hasMember("msg") && !strcmp(v["msg"].get<std::string>().c_str(), "CALL")) {
+            
+                string s = v["method"].get<std::string>();
+                
+                if ((i = methodAlreadyRegistered((char *)s.c_str())) != -1) {
+                
+                    obj[i]->execute(v["params"], r);
+                    sprintf(json_recv, (const char *)MSG_RESULT, my_id,
+                            v["from"].get<std::string>().c_str(), v["id_msg"].get<int>(), r.serialize().c_str());
+                    webs->Send(json_recv);
+                    
+                } else if ((i = procAlreadyRegistered((char *)s.c_str())) != -1) {
+                
+                    proc[i](v["params"], r);
+                    sprintf(json_recv, (const char *)MSG_RESULT, my_id,
+                            v["from"].get<std::string>().c_str(), v["id_msg"].get<int>(), r.serialize().c_str());
+                    webs->Send(json_recv);
+                    
+                }
+            }
+
+        }
+        //show that we are alive
+        led4 = !led4;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MbedJSONRpc.h	Thu Sep 22 10:14:52 2011 +0000
@@ -0,0 +1,377 @@
+/**
+* @author Samuel Mokrani
+*
+* @section LICENSE
+*
+* Copyright (c) 2011 mbed
+*
+* Permission is hereby granted, free of charge, to any person obtaining a copy
+* of this software and associated documentation files (the "Software"), to deal
+* in the Software without restriction, including without limitation the rights
+* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the Software is
+* furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in
+* all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+* THE SOFTWARE.
+*
+* @section DESCRIPTION
+*       Main part of MbedJSONRpc: you can register methods or procedures, call a registered method or procedure
+*       on a client over a websocket communication, see all methods available on a certain client, listen for 
+*       CALL incoming messages to execute a method or procedure.
+*
+*/
+
+
+#ifndef _MbedJSONRPC_H_
+#define _MbedJSONRPC_H_
+
+#include "Websocket.h"
+#include "Wifly.h"
+#include "mbed.h"
+#include "MbedJSONRpcValue.h"
+#include <string>
+
+#define NB_METH 30
+
+#define MSG_CALL                    "{\"from\": \"%s\",\"to\": \"%s\",\"msg\": \"CALL\",\"id_msg\": %d,\"method\": \"%s\",\"params\":%s}"
+/**< Message skeleton which will be use for a call */
+#define MSG_RESULT                  "{\"from\": \"%s\",\"to\": \"%s\",\"msg\": \"RESULT\",\"id_msg\": %d,\"res\":%s}"
+/**< Message skeleton which will be use for a result  */
+#define MSG_REGISTER                "{\"from\": \"%s\",\"to\": \"gateway\",\"msg\": \"REGISTER\",\"id_msg\": %d,\"fn\":\"%s\"}"
+/**< Message skeleton which will be use for register a method or a procedure */
+#define MSG_INFO_METHODS            "{\"from\": \"%s\",\"to\": \"%s\",\"msg\": \"INFO_METHODS\",\"id_msg\": %d}"
+/**< Message skeleton which will be send to see all methods available of a certain client */
+
+
+/**
+* \enum RPC_TYPE
+* \brief Type of an RPC transaction
+*/
+enum RPC_TYPE {
+    JSON_PARSE_ERROR,       /*!< Json parse error */
+    RPC_PARSE_ERROR,        /*!< rpc parse error (the message doesn't contain good identifiers in a TypeObject MbedRpcValue)*/ 
+    PROC_NOT_FOUND,         /*!< The user wants to call an inexisting method or procedure */
+    CLIENT_NOT_CONNECTED,   /*!< The user wants to call a method or procedure on a client not connected (no response from the client within 3s) */
+    SERVER_NOT_CONNECTED,   /*!< No response from the server within 5s */
+    ERR_ID,                 /*!< Each messages have an id, if the id of the answer doesn't match with the id of the request, there is an id error */
+    CALL_OK,                /*!< A call has been successfully executed */
+    REGISTER_OK             /*!< A request to register a method or procedure is successful */
+};
+
+
+
+class ObjBase {
+public:
+    virtual void execute(MbedRpcValue& val, MbedRpcValue& res) = 0;
+};
+
+template <class T>
+class Obj : public ObjBase {
+public:
+
+    Obj(T * ptr, void (T::*fn_ptr)(MbedRpcValue& , MbedRpcValue& )) {
+        obj_ptr = ptr;
+        fn = fn_ptr;
+    };
+
+    virtual void execute(MbedRpcValue& val, MbedRpcValue& res) {
+        ((*obj_ptr).*fn)(val, res);
+    }
+
+    //obj
+    T * obj_ptr;
+
+    //method
+    void (T::*fn)(MbedRpcValue& , MbedRpcValue& );
+
+};
+
+
+/** MbedJSONRpc class
+ *
+ * Warning: you must use a wifi module (Wifly RN131-C) or an ethernet network to use this class
+ *
+ * Example (client which registers one method):
+ * @code
+ * #include "mbed.h"
+ * #include "MbedJSONRpc.h"
+ * #include "MbedJSONRpcValue.h"
+ * #include "Websocket.h"
+ *
+ * #define ETHERNET
+ *
+ * #ifdef WIFI
+ * #include "Wifly.h"
+ * #endif
+ *
+ * DigitalOut led1(LED1);
+ * Serial pc(USBTX, USBRX);
+ *
+ *
+ * class Test {
+ * public:
+ *   Test() {};
+ *   void fn(JSONRpcValue& val, JSONRpcValue& res) {
+ *       printf("first arg: %s\r\n", val[0].get<string>().c_str());
+ *       res[0] = "coucou";
+ *       led1 = 1;
+ *   }
+ * };
+ * 
+ *
+ * #ifdef WIFI
+ * //wifi and websocket
+ *  Wifly wifly(p9, p10, p30, "mbed", "mbedapm2011", true);
+ *  Websocket webs("ws://sockets.mbed.org:888/ws/samux/server",&wifly);
+ * #endif
+ *
+ * #ifdef ETHERNET
+ *  Websocket webs("ws://sockets.mbed.org:888/ws/samux/server");
+ * #endif
+ *
+ * //RPC object identified with the name "server" on the network and attached to the websocket server
+ * MbedJSONRpc rpc("server", &webs);
+ * 
+ * Test test;
+ *
+ * int main() {
+ *   
+ *   RPC_TYPE t;
+ *
+ *
+ *   //connection to the router and to the websocket server
+ *   #ifdef WIFI
+ *   while (1) {
+ *
+ *       while (!wifly.Join())  //we connect to the network
+ *           wifly.reset();
+ *
+ *       if (!webs.connect())    //we connect to the server
+ *           wifly.reset();
+ *       else
+ *           break;
+ *   }
+ *   #endif
+ *  
+ *   #ifdef ETHERNET
+ *   while(!webs.connect())
+ *       pc.printf("cannot connect websocket, retrying\r\n");
+ *   #endif
+ *
+ *   //register the method Test::fn as "fn1"
+ *   if((t = rpc.registerMethod("fn1", &test, &Test::fn)) == REGISTER_OK)
+ *       printf("register ok\r\n");
+ *   else
+ *       printType(t);
+ *   
+ *   //Listen CALL requests
+ *   rpc.work();
+ * }
+ * @endcode
+ *
+ *
+ *
+ * Example (client which calls the previous registered method):
+ * @code
+ * #include "mbed.h"
+ * #include "MbedJSONRpc.h"
+ * #include "MbedJSONRpcValue.h"
+ * #include "Websocket.h"
+ *
+ * #define WIFI
+ *
+ * #ifdef WIFI
+ *   #include "Wifly.h"
+ * #endif
+ *
+ * Serial pc(USBTX, USBRX);
+ *
+ * #ifdef WIFI
+ *   //wifi and websocket
+ *   Wifly wifly(p9, p10, p21, "mbed", "mbedapm2011", true);
+ *   Websocket webs("ws://sockets.mbed.org:888/ws/samux/client",&wifly);
+ * #endif
+ *
+ * #ifdef ETHERNET
+ *   Websocket webs("ws://sockets.mbed.org:888/ws/samux/client");
+ * #endif
+ * 
+ * //RPC object identified by the name "client" on the network and attached to the websocket server
+ * MbedJSONRpc rpc("client", &webs);
+ *
+ * int main() {
+ *
+ *   //connection to the router and to the websocket server
+ *   #ifdef WIFI
+ *   while (1) {
+ *
+ *       while (!wifly.Join())  //we connect to the network
+ *           wifly.reset();
+ *
+ *       if (!webs.connect())    //we connect to the server
+ *           wifly.reset();
+ *       else
+ *           break;
+ *   }
+ *   #endif
+ *  
+ *   #ifdef ETHERNET
+ *   while(!webs.connect())
+ *       pc.printf("cannot connect websocket, retrying\r\n");
+ *   #endif
+ *   
+ *   RPC_TYPE t;
+ *   MbedRpcValue arg, resp;
+ *   arg[0] = "Hello";
+ *
+ *   // print all methods and procedure available on the client "server"
+ *   rpc.checkMethods("server");
+ *       
+ *   // Try to call the function "fn1" registered by server previously
+ *   if((t = rpc.call("fn1", "server", arg, resp)) == CALL_OK)
+ *   {
+ *       printf("call success\r\n");
+ *       printf("res: %s\r\n", resp[0].get<string>().c_str());
+ *   }
+ *   else
+ *       printType(t);
+ * }
+ * @endcode
+ */
+class MbedJSONRpc {
+public:
+
+    /**
+    *   Constructor
+    *
+    * @param id Name of the client on the network
+    * @param ws All communication between clients will be established over this websocket
+    */
+    MbedJSONRpc(Websocket * webs) : webs(webs), index(0), index_proc(0) {
+        std::string path = webs->getPath();
+        std::string token = "/";
+        size_t found;
+        found = path.find(token, 3);
+        if (found != std::string::npos)
+            path = path.substr(found + 1, std::string::npos);
+        strcpy(my_id, path.c_str());
+    };
+
+    /**
+    * Register a method of an object
+    *
+    * @param public_name the method will be seen and called by this name
+    * @param obj_ptr a pointeur on the object which contains the method to register
+    * @param fn the method to register (this method must have this signature: void fn(MbedRpcValue& val, MbedRpcValue& res)
+    * @return if REGISTER_OK, the method is registered, otherwise, there is an error
+    *
+    */
+    template<typename T> RPC_TYPE registerMethod(const char * public_name, T * obj_ptr, void (T::*fn)(MbedRpcValue& val, MbedRpcValue& res)) {
+        char json[100];
+        RPC_TYPE t;
+        Timer tmr;
+        int id = rand() % 100;
+        MbedRpcValue tmp;
+
+        sprintf(json, (const char *)MSG_REGISTER, my_id, id, public_name);
+        webs->Send(json);
+        tmr.start();
+        t = waitAnswer(tmp, id, json);
+        if (t != REGISTER_OK)
+            return t;
+        if( index == NB_METH )
+            index = NB_METH - 1;
+        obj[index] = new Obj<T>(obj_ptr, fn);
+        name[index++] = public_name;
+        return REGISTER_OK;
+    }
+
+
+    /**
+    * Register a procedure
+    *
+    * @param public_name the method will be seen and called by this name
+    * @param fn the procedure to register (this procedure must have this signature: void fn(MbedRpcValue& val, MbedRpcValue& res)
+    * @return if REGISTER_OK, the procedure is registered, otherwise, there is an error
+    *
+    */
+    RPC_TYPE registerMethod(const char * public_name, void (*fn)(MbedRpcValue& val, MbedRpcValue& res) );
+    
+    
+    /**
+    * Call a method or procedure on a client
+    *
+    * @param fn name of the method or procedure to be called
+    * @param dest name of the client where will be executed the method or procedure
+    * @param val Input parameters of the method or procedure "fn"
+    * @param resp Once the method or procedure executed, the result will be stored in the "resp" variable
+    * @return If CALL_OK, the method has been executed and you can access the result with the "resp" variable. 
+    *         If CLIENT_NOT_CONNECTED, means that the client hasn't answered within 3s.
+    *         If SERVER_NOT_CONNECTED, means that the server hasn't answered within 5s.
+    *         Refer to the RPC_TYPE description
+    *
+    */
+    RPC_TYPE call(char * fn, char * dest,  MbedRpcValue& val, MbedRpcValue& resp);
+    
+    
+    /**
+    * Listen for CALL requests
+    * Warning: infinite loop
+    */
+    void work();
+    
+    /**
+    * Print by the usb serial port all methods or procedure available on "dest" client
+    */
+    void checkMethods(char * dest);
+
+private:
+
+    typedef void (*FNPTR)(MbedRpcValue& , MbedRpcValue& );
+
+    int methodAlreadyRegistered(char *);
+    int procAlreadyRegistered(char *);
+    RPC_TYPE decodeMsg(MbedRpcValue& , int);
+    RPC_TYPE waitAnswer(MbedRpcValue& , int, char *);
+
+    Websocket * webs;
+
+    ObjBase * obj[NB_METH];
+    const char * name[NB_METH];
+    int index;
+
+    FNPTR proc[NB_METH];
+    const char * name_proc[NB_METH];
+    int index_proc;
+
+
+    char my_id[20];
+
+};
+
+
+inline void printType(RPC_TYPE t)
+{
+    switch(t)
+    {
+        case JSON_PARSE_ERROR: printf("json parse error\r\n"); break;
+        case RPC_PARSE_ERROR: printf("rpc parse error\r\n"); break;
+        case PROC_NOT_FOUND: printf("proc or method not found\r\n"); break;
+        case CLIENT_NOT_CONNECTED: printf("client not connected\r\n"); break;
+        case SERVER_NOT_CONNECTED: printf("server not connected\r\n"); break;
+        case ERR_ID: printf("id error\r\n"); break;
+        case CALL_OK: printf("call ok\r\n"); break;
+        case REGISTER_OK: printf("register ok\r\n"); break;
+    }
+}
+
+#endif
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MbedJSONRpcValue.cpp	Thu Sep 22 10:14:52 2011 +0000
@@ -0,0 +1,245 @@
+#include "MbedJSONRpcValue.h"
+
+# include <stdlib.h>
+# include <stdio.h>
+
+// Clean up
+void MbedRpcValue::clean() {
+    switch (_type) {
+        case TypeString:
+            delete _value.asString;
+            break;
+        case TypeArray:
+            for (int i = 0; i < index_array; i++)
+                delete array[i];
+            index_array = 0;
+            break;
+        case TypeObject:
+            for (int i = 0; i < index_token; i++) {
+                delete token[i];
+                delete token_name[i];
+            }
+            index_token = 0;
+            break;
+        default:
+            break;
+    }
+    _type = TypeNull;
+    _type = TypeNull;
+}
+
+bool MbedRpcValue::hasMember(char * name)
+{
+    for(int i = 0; i < index_token; i++)
+        if( !strcmp(name, (*(token_name[i])).c_str() ))
+            return true;
+    return false;
+}
+
+
+void copy(const std::string& s, std::back_insert_iterator<std::string> oi) {
+    std::copy(s.begin(), s.end(), oi);
+}
+
+void serialize_str(const std::string& s, std::back_insert_iterator<std::string> oi) {
+    *oi++ = '"';
+    for (std::string::const_iterator i = s.begin(); i != s.end(); ++i) {
+        switch (*i) {
+#define MAP(val, sym) case val: copy(sym, oi); break
+                MAP('"', "\\\"");
+                MAP('\\', "\\\\");
+                MAP('/', "\\/");
+                MAP('\b', "\\b");
+                MAP('\f', "\\f");
+                MAP('\n', "\\n");
+                MAP('\r', "\\r");
+                MAP('\t', "\\t");
+#undef MAP
+            default:
+                if ((unsigned char)*i < 0x20 || *i == 0x7f) {
+                    char buf[7];
+                    sprintf(buf, "\\u%04x", *i & 0xff);
+                    copy(buf, buf + 6, oi);
+                } else {
+                    *oi++ = *i;
+                }
+                break;
+        }
+    }
+    *oi++ = '"';
+}
+
+std::string MbedRpcValue::serialize(){
+    std::string s;
+    serialize(std::back_inserter(s));
+    return s;
+}
+
+std::string MbedRpcValue::to_str(){
+    switch (_type) {
+        case TypeNull:
+            return "null";
+        case TypeBoolean:
+            return _value.asBool ? "true" : "false";
+        case TypeInt:    {
+            char buf[10];
+            sprintf(buf, "%d", _value.asInt);
+            return buf;
+        }
+        case TypeDouble:    {
+            char buf[10];
+            sprintf(buf, "%f", _value.asDouble);
+            return buf;
+        }
+        default:
+            break;
+    }
+    return NULL;
+}
+
+
+
+void MbedRpcValue::serialize(std::back_insert_iterator<std::string> oi) {
+    switch (_type) {
+        case TypeString:
+            serialize_str(*_value.asString, oi);
+            break;
+        case TypeArray: {
+            *oi++ = '[';
+            for (int i = 0; i < index_array; i++) {
+                if (i)
+                    *oi++ = ',';
+                (*this)[i].serialize(oi);
+            }
+            *oi++ = ']';
+            break;
+        }
+        case TypeObject: {
+            *oi++ = '{';
+            for (int i = 0; i < index_token; i++) {
+                if (i)
+                    *oi++ = ',';
+                serialize_str(*(token_name[i]), oi);
+                *oi++ = ':';
+                (*(token[i])).serialize(oi);
+            }
+            *oi++ = '}';
+            break;
+        }
+        default:
+            copy(to_str(), oi);
+            break;
+    }
+}
+
+
+
+MbedRpcValue& MbedRpcValue::operator[](int i) {
+    _type = TypeArray;
+    if (i < NB_TOKEN && index_array == i ) {
+#ifdef DEBUG
+        printf("will add an element to the array\r\n");
+#endif
+        array[i] = new MbedRpcValue();
+        index_array++;
+        return *(array[i]);
+    }
+    if (i < NB_TOKEN && index_array > i)
+        return *(array[i]);
+
+    //if the user is not doing something wrong, this code is never executed!!
+    return *(new MbedRpcValue());
+}
+
+MbedRpcValue& MbedRpcValue::operator[](std::string k) {
+    _type = TypeObject;
+    for (int i = 0; i < index_token; i++) {
+#ifdef DEBUG
+        printf("k: %s\r\n", k.c_str());
+        printf("str: %s\r\n", token_name[i]->c_str());
+#endif
+        //existing token
+        if (!strcmp(k.c_str(), token_name[i]->c_str())) {
+#ifdef DEBUG
+            printf("token found: %d\r\n", i);
+#endif
+            return *(token[i]);
+        }
+    }
+
+    if(index_token >= NB_TOKEN)
+        index_token = NB_TOKEN - 1;
+    //non existing token
+    token_name[index_token] = new std::string(k);
+    token[index_token] = new MbedRpcValue();
+    index_token++;
+    return *(token[index_token - 1]);
+}
+
+MbedRpcValue& MbedRpcValue::operator[](std::string k) const
+{
+    for (int i = 0; i < index_token; i++) {
+#ifdef DEBUG
+        printf("k: %s\r\n", k.c_str());
+        printf("str: %s\r\n", token_name[i]->c_str());
+#endif
+        if (!strcmp(k.c_str(), token_name[i]->c_str())) {
+#ifdef DEBUG
+            printf("token found: %d\r\n", i);
+#endif
+            return *(token[i]);
+        }
+    }
+    
+    //if the user is not doing something wrong, this code is never executed!!
+    return *(new MbedRpcValue());
+}
+
+
+// Operators
+MbedRpcValue& MbedRpcValue::operator=(MbedRpcValue const& rhs) {
+    if (this != &rhs) {
+        clean();
+        _type = rhs._type;
+        switch (_type) {
+            case TypeBoolean:
+                _value.asBool = rhs._value.asBool;
+                break;
+            case TypeInt:
+                _value.asInt = rhs._value.asInt;
+                break;
+            case TypeDouble:
+                _value.asDouble = rhs._value.asDouble;
+                break;
+            case TypeString:
+                _value.asString = new std::string(*rhs._value.asString);
+                break;
+            case TypeArray:
+                for (int i = 0; i < rhs.index_array; i++)
+                    (*this)[i] = rhs[i];
+            case TypeObject:
+                for (int i = 0; i < rhs.index_token; i++)
+                    (*this)[*(rhs.token_name[i])] = rhs[*(rhs.token_name[i])];
+            default:
+                break;
+        }
+    }
+    return *this;
+}
+
+
+// Works for strings, arrays, and structs.
+int MbedRpcValue::size() const {
+    switch (_type) {
+        case TypeString:
+            return int(_value.asString->size());
+        case TypeArray:
+            return index_array;
+        case TypeObject:
+            return index_token;
+        default:
+            break;
+    }
+    return -1;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MbedJSONRpcValue.h	Thu Sep 22 10:14:52 2011 +0000
@@ -0,0 +1,582 @@
+/**
+* @author Samuel Mokrani
+*
+* @section LICENSE
+*
+* Copyright (c) 2011 mbed
+*
+* Permission is hereby granted, free of charge, to any person obtaining a copy
+* of this software and associated documentation files (the "Software"), to deal
+* in the Software without restriction, including without limitation the rights
+* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the Software is
+* furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in
+* all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+* THE SOFTWARE.
+*
+* @section DESCRIPTION
+*    Types Abstraction for the RPC communication
+*
+*/
+
+#ifndef _MbedJSON_RPC_VALUE_H_
+#define _MbedJSON_RPC_VALUE_H_
+
+#define NB_TOKEN 20
+/*!< Number maximum of MbedRpcValue in an array or an object */
+
+#include <string>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/** MbedRpcValue class
+ *
+ * Example:
+ *    - creation of an MbedRpcValue of type TypeObject containing two others MbedRpcValue: 
+ *         -one array of one string and one integer identified by "my_array"
+ *         -a boolean identified by "my_boolean"
+ *    - serialization in JSON format of this object
+ * @code
+ *     MbedRpcValue demo;
+ *     std::string s;
+ *
+ *     //fill the object
+ *     demo["my_array"][0] = "demo_string";
+ *     demo["my_array"][1] = 10;
+ *     demo["my_boolean"] = true;
+ *
+ *     //serialize it into a JSON string
+ *     s = demo.serialize();
+ *
+ *  
+ * @endcode
+ *
+ * Example:
+ *     - creation of an MbedRpcValue from a JSON string
+ *     - extraction of different values from this existing MbedRpcValue
+ * @code
+ *
+ *     MbedRpcValue demo;
+ *
+ *     const  char * json = "{\"my_array\": [\"demo_string\", 10], \"my_boolean\": true}";
+ *
+ *     //parse the previous string and fill the object demo
+ *     parse(demo, json);
+ *
+ *     std::string my_str;
+ *     int my_int;
+ *     bool my_bool;
+ *
+ *     my_str = demo["my_array"][0];
+ *     my_int = demo["my_array"][1];
+ *     my_bool = demo["my_boolean"];
+ *
+ * @endcode
+ */
+class MbedRpcValue {
+public:
+
+    /**
+    * \enum Type
+    * \brief All types which can be used
+    */
+    enum Type {
+        TypeNull,     /*!< Null type */
+        TypeBoolean,  /*!< Boolean */
+        TypeInt,      /*!< Integer */
+        TypeDouble,   /*!< Double */
+        TypeString,   /*!< String */
+        TypeArray,    /*!< Array of Type */
+        TypeObject    /*!< Object */
+    };
+
+    /**
+    * MbedRpcValue constructor of type TypeNull
+    */
+    MbedRpcValue() : _type(TypeNull), index_array(0), index_token(0) {}
+    
+    /**
+    * MbedRpcValue constructor of type TypeBoolean
+    *
+    * @param value the object created will be initialized with this boolean
+    */
+    MbedRpcValue(bool value) : _type(TypeBoolean), index_array(0), index_token(0) {
+        _value.asBool = value;
+    }
+    
+    /**
+    * MbedRpcValue constructor of type TypeInt
+    *
+    * @param value the object created will be initialized with this integer
+    */
+    MbedRpcValue(int value)  : _type(TypeInt), index_array(0), index_token(0) {
+        _value.asInt = value;
+    }
+    
+    /**
+    * MbedRpcValue constructor of type TypeDouble
+    *
+    * @param value the object created will be initialized with this double
+    */
+    MbedRpcValue(double value)  : _type(TypeDouble), index_array(0), index_token(0) {
+        _value.asDouble = value;
+    }
+
+    /**
+    * MbedRpcValue constructor of type TypeString
+    *
+    * @param value the object created will be initialized with this string
+    */
+    MbedRpcValue(std::string const& value) : _type(TypeString), index_array(0), index_token(0) {
+        _value.asString = new std::string(value);
+    }
+
+    /**
+    * MbedRpcValue constructor of type TypeString
+    *
+    * @param value the object created will be initialized with this string
+    */
+    MbedRpcValue(const char* value)  : _type(TypeString), index_array(0), index_token(0) {
+        _value.asString = new std::string(value);
+    }
+
+    /**
+    * Copy constructor
+    *
+    * @param rhs object which will be copied
+    */
+    MbedRpcValue(MbedRpcValue const& rhs) : _type(TypeNull) {  *this = rhs;  }
+
+    /**
+    * Destructor
+    */
+    ~MbedRpcValue() {  clean();  }
+
+    /**
+    * = Operator overloading for an MbedRpcValue from an MbedRpcValue
+    *
+    * @param rhs object
+    * @return a reference on the MbedRpcValue affected
+    */
+    MbedRpcValue& operator=(MbedRpcValue const & rhs);
+    
+    /**
+    * = Operator overloading for an MbedRpcValue from an int
+    *
+    * @param rhs
+    * @return a reference on the MbedRpcValue affected
+    */
+    MbedRpcValue& operator=(int const& rhs) { return operator=(MbedRpcValue(rhs));  }
+    
+    /**
+    * = Operator overloading for an MbedRpcValue from a double
+    *
+    * @param rhs
+    * @return a reference on the MbedRpcValue affected
+    */
+    MbedRpcValue& operator=(double const& rhs) {  return operator=(MbedRpcValue(rhs));  }
+    
+    /**
+    * = Operator overloading for an MbedRpcValue from a string
+    *
+    * @param rhs
+    * @return a reference on the MbedRpcValue affected
+    */
+    MbedRpcValue& operator=(const char* rhs) {  return operator=(MbedRpcValue(std::string(rhs))); }
+    
+    
+    /**
+    * [] Operator overloading for an MbedRpcValue.
+    * Each TypeObject object can contain an array of NB_TOKEN MbedRpcvalue. 
+    * This operator is useful to create an array or to retrieve an MbedRpcValue of an existing array.
+    *
+    * For instance, the following code creates an MbedRpcValue of type TypeArray and the first object 
+    * of this array is an MbedRpcValue of type TypeString: 
+    *       MbedRpcValue my_mbed_rpc_value; 
+    *       my_mbed_rpc_value[0] = "hello";
+    *
+    * Once an array is created, you access each elements by my_mbed_rpc_value[i]
+    *
+    * @param i index of the array
+    * @return a reference on the MbedRpcValue created or retrieved
+    */
+    MbedRpcValue& operator[](int i);
+    
+    /**
+    * [] Operator overloading for an MbedRpcValue.
+    * Each TypeObject MbedRpcValue can contain NB_TOKEN MbedRpcValue IDENTIFIED BY A NAME 
+    * This operator is useful to create a TypeObject MbedRpcValue or to retrieve an MbedRpcValue of an existing TypeObject.
+    *
+    * For instance, the following code creates an MbedRpcValue of type TypeObject and the first object 
+    * of this "map" is an MbedRpcValue of type TypeString identified with the name "my_string": 
+    *       MbedRpcValue my_mbed_rpc_value; 
+    *       my_mbed_rpc_value["my_string"] = "hello";
+    *
+    * Once an Object is created, you access each elements by my_mbed_rpc_value["my_identifier"]
+    *
+    *
+    * @param str identifier of the sub MbedRpcValue
+    * @return a reference on the MbedRpcValue created or retrieved
+    */
+    MbedRpcValue& operator[](std::string str);
+
+    /**
+    * Retrieve the value of an MbedRpcValue object.
+    *
+    * Let's suppose that we have an MbedRpcValue of type TypeString.
+    * To retrieve this string, we have to do:
+    *   my_obj.get<std::string>();
+    *
+    * @return A contant reference on the value of the object
+    */
+    template <typename T> const T& get() const;
+    
+    /**
+    * Retrieve the value of an MbedRpcValue object.
+    *
+    * Let's suppose that we have an MbedRpcValue of type TypeInt.
+    * To retrieve this integer, we have to do:
+    *   my_obj.get<int>();
+    *
+    * @return A reference on the value of the object
+    */
+    template <typename T> T& get();
+
+
+    /**
+    * Return the type of the MbedRpcValue object
+    *
+    * @return type of the MbedRpcValue object
+    */
+    Type const &getType() const {
+        return _type;
+    }
+
+    /**
+    * Return the size of an MbedRpcValue object (works for TypeString, TypeArray or TypeObject) 
+    *
+    * @param size
+    */
+    int size() const;
+
+    /**
+    * Check for the existence in a TypeObject object of member identified by name
+    *
+    * @param name Identifier
+    * @return true if the object is of type TypeObject AND contains a member named "name", false otherwise
+    */
+    bool hasMember(char * name);
+
+    /**
+    * Convert an MbedRpcValue in a JSON frame
+    *
+    * @return JSON string
+    */
+    std::string serialize();
+
+protected:
+
+    // object type
+    Type _type;
+    
+    //indexes of TypeObject and TypeArray
+    int index_array;
+    int index_token;
+
+    //an object can contain NB_TOKEN tokens. Each token have a name
+    MbedRpcValue * token[NB_TOKEN];
+    std::string * token_name[NB_TOKEN];
+
+    //an object can contain an array of NB_TOKEN elements
+    MbedRpcValue * array[NB_TOKEN];
+
+    // Clean up
+    void clean();
+
+    union {
+        bool          asBool;
+        int           asInt;
+        double        asDouble;
+        std::string*  asString;
+    } _value;
+
+
+    MbedRpcValue& operator[](int i) const { return *(array[i]); }
+    MbedRpcValue& operator[](std::string k) const;
+    
+    std::string to_str();
+    void serialize(std::back_insert_iterator<std::string> os);
+
+};
+
+
+#define GET(ctype, var)                          \
+  template <> inline const ctype& MbedRpcValue::get<ctype>() const { \
+    return var;                              \
+  }                                  \
+  template <> inline ctype& MbedRpcValue::get<ctype>() {          \
+    return var;                              \
+  }
+GET(bool, _value.asBool)
+GET(double, _value.asDouble)
+GET(int, _value.asInt)
+GET(std::string, *_value.asString)
+#undef GET
+
+
+//Input class for JSON parser
+class input {
+protected:
+    const char * cur_;
+    const char * end_;
+    int last_ch_;
+    bool ungot_;
+    int line_;
+public:
+    input(const char * first, const char * last) : cur_(first), end_(last), last_ch_(-1), ungot_(false), line_(1) {};
+
+    int getc() {
+        if (ungot_) {
+            ungot_ = false;
+            return last_ch_;
+        }
+        if (cur_ == end_) {
+            last_ch_ = -1;
+            return -1;
+        }
+        if (last_ch_ == '\n') {
+            line_++;
+        }
+        last_ch_ = *cur_++ & 0xff;
+        return last_ch_;
+    }
+
+    void ungetc() {
+        if (last_ch_ != -1) {
+            ungot_ = true;
+        }
+    }
+
+    const char * cur() const {
+        return cur_;
+    }
+    int line() const {
+        return line_;
+    }
+    void skip_ws() {
+        while (1) {
+            int ch = getc();
+            if (! (ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r')) {
+                ungetc();
+                break;
+            }
+        }
+    }
+    int expect(int expect) {
+        skip_ws();
+        if (getc() != expect) {
+            ungetc();
+            return false;
+        }
+        return true;
+    }
+    bool match(const std::string& pattern) {
+        for (std::string::const_iterator pi(pattern.begin());
+                pi != pattern.end();
+                ++pi) {
+            if (getc() != *pi) {
+                ungetc();
+                return false;
+            }
+        }
+        return true;
+    }
+};
+
+
+
+inline const char * parse(MbedRpcValue& out, const char * first, const char * last, std::string* err);
+
+/**
+* JSON string parser and creation of an MbedRpcValue
+*
+* @param out reference of an MbedRpcValue which will be filled according to the JSON string
+* @param str JSON string
+* @return A non empty string if there is a parsing error
+*
+*/
+
+inline std::string parse(MbedRpcValue& out, const char * str);
+inline bool _parse(MbedRpcValue& out, input& in);
+inline bool _parse_number(MbedRpcValue& out, input& in);
+inline bool _parse_string(MbedRpcValue& out, input& in);
+inline bool _parse_array(MbedRpcValue& out, input& in);
+inline bool _parse_object(MbedRpcValue& out, input& in);
+
+
+inline bool _parse_string(MbedRpcValue& out, input& in) {
+#ifdef DEBUG
+    printf("string detected\r\n");
+#endif
+    out = MbedRpcValue(std::string(""));
+    std::string& s = out.get<std::string>();
+    while (1) {
+        int ch = in.getc();
+        if (ch < ' ') {
+            in.ungetc();
+            return false;
+        } else if (ch == '"') {
+            return true;
+        } else if (ch == '\\') {
+            if ((ch = in.getc()) == -1) {
+                return false;
+            }
+            switch (ch) {
+#define MAP(sym, val) case sym: s.push_back(val); break
+                    MAP('"', '\"');
+                    MAP('\\', '\\');
+                    MAP('/', '/');
+                    MAP('b', '\b');
+                    MAP('f', '\f');
+                    MAP('n', '\n');
+                    MAP('r', '\r');
+                    MAP('t', '\t');
+#undef MAP
+                default:
+                    return false;
+            }
+        } else {
+            s.push_back(ch);
+        }
+    }
+}
+
+inline bool _parse_array(MbedRpcValue& out, input& in) {
+#ifdef DEBUG
+    printf("array detected\r\n");
+#endif
+    int i = 0;
+    if (in.expect(']')) {
+        return true;
+    }
+    do {
+        if (! _parse(out[i], in)) {
+            return false;
+        }
+        i++;
+    } while (in.expect(','));
+    return in.expect(']');
+}
+
+inline bool _parse_object(MbedRpcValue& out, input& in) {
+#ifdef DEBUG
+    printf("object detected\r\n");
+#endif
+    if (in.expect('}')) {
+        return true;
+    }
+    do {
+        MbedRpcValue key, val;
+        if (in.expect('"') && _parse_string(key, in) && in.expect(':') && _parse(val, in)) {
+            out[key.get<std::string>().c_str()] = val;
+#ifdef DEBUG
+            printf("key: %s \r\n", key.get<std::string>().c_str());
+#endif
+        } else {
+            return false;
+        }
+    } while (in.expect(','));
+    return in.expect('}');
+}
+
+inline bool _parse_number(MbedRpcValue& out, input& in) {
+#ifdef DEBUG
+    printf("number detected\r\n");
+#endif
+    std::string num_str;
+    while (1) {
+        int ch = in.getc();
+        if (('0' <= ch && ch <= '9') || ch == '+' || ch == '-' || ch == '.'
+                || ch == 'e' || ch == 'E') {
+            num_str.push_back(ch);
+        } else {
+            in.ungetc();
+            break;
+        }
+    }
+    char* endp;
+    if (strchr(num_str.c_str(), '.') != NULL || strchr(num_str.c_str(), 'e') != NULL || strchr(num_str.c_str(), '+') != NULL)
+        out = MbedRpcValue(strtod(num_str.c_str(), &endp));
+    else
+        out = MbedRpcValue((int)strtod(num_str.c_str(), &endp));
+    return endp == num_str.c_str() + num_str.size();
+}
+
+inline bool _parse(MbedRpcValue& out, input& in) {
+    in.skip_ws();
+    int ch = in.getc();
+    switch (ch) {
+#define IS(ch, text, val) case ch: \
+      if (in.match(text)) { \
+    out = val; \
+    return true; \
+      } else { \
+    return false; \
+      }
+            IS('n', "ull", MbedRpcValue());
+            IS('f', "alse", MbedRpcValue(false));
+            IS('t', "rue", MbedRpcValue(true));
+#undef IS
+        case '"':
+            return _parse_string(out, in);
+        case '[':
+            return _parse_array(out, in);
+        case '{':
+            return _parse_object(out, in);
+        default:
+            if (('0' <= ch && ch <= '9') || ch == '-') {
+                in.ungetc();
+                return _parse_number(out, in);
+            }
+            break;
+    }
+    in.ungetc();
+    return false;
+}
+
+inline std::string parse(MbedRpcValue& out, const char * pos) {
+    const char * last = pos + strlen(pos);
+    std::string err;
+    pos = parse(out, pos, last, &err);
+    return err;
+}
+
+inline const char * parse(MbedRpcValue& out, const char * first, const char * last, std::string* err) {
+    input in = input(first, last);
+    if (! _parse(out, in) && err != NULL) {
+        char buf[64];
+        sprintf(buf, "syntax error at line %d near: ", in.line());
+        *err = buf;
+        while (1) {
+            int ch = in.getc();
+            if (ch == -1 || ch == '\n') {
+                break;
+            } else if (ch >= ' ') {
+                err->push_back(ch);
+            }
+        }
+    }
+    return in.cur();
+}
+
+#endif // _MbedMbedRpcValue_H_