RPC Over UDP Command format is same as serial RPC (not HTTP RPC). Please find attached Test Program(processing & ActionScript3) at end of this file.

Dependencies:   EthernetNetIf mbed

main.cpp

Committer:
xshige
Date:
2010-11-16
Revision:
1:918ffa99c345
Parent:
0:797742779818

File content as of revision 1:918ffa99c345:

/*
 *
 * RPC Over UDP
 *
 * Command format is same as serial RPC (not HTTP RPC)
 *
 * (example)
 * So you can control mbed by sending the followng command (over UDP)
 * /DigitalOut/new LED1 myled
 * /myled/write 1
 * /AnalogIn/new p20 ain
 * /ain/read
 *
 * Please find attached Test Programs(processing & ActionScript3) at end of this file as comment "#if 0"
 *
 */

// 2010/11/16
// Fixed test program(processing)
// to run it in both windows and linux.

// 2010/11/15
// written by: xshige


#define DEBUG

// Send Port (RPC output)
#define OUTPUT_PORT 8001
// Receive Port (RPC input)
#define INPUT_PORT 8000

#define DEBUG

// please comment out if you want two way unicast
#define SENDBACK_UNICAST

#define DHCP

#include "mbed.h"
#include "EthernetNetIf.h"
#include "UDPSocket.h"

#include "rpc.h"
Serial pc(USBTX, USBRX);

#ifdef DHCP
EthernetNetIf eth;
#else
EthernetNetIf eth(
  IpAddr(192,168,0,25), //IP Address
  IpAddr(255,255,255,0), //Network Mask
  IpAddr(192,168,0,1), //Gateway
  IpAddr(192,168,0,1)  //DNS
);
#endif

UDPSocket udpRec;
UDPSocket udpSend;


// mulitcast UDP
#ifdef SENDBACK_UNICAST
Host recHost(IpAddr(239, 255, 0, 1), INPUT_PORT, NULL);  // Receive Port (RPC input)
// multicast IP
// "224.0.0.1" works correctly.
// "224.0.0.2" does not work(can Not receive)
// "239.255.0.0"-"239.255.255.255" (Site-Local Scope) maybe work
#else
// please change IP address to fit your enviroment
// unicast IUDP
Host sendHost(IpAddr(192, 168, 0, 7), OUTPUT_PORT, NULL); // Send Port (RPC output)
Host recHost(IpAddr(192, 168, 0, 7), INPUT_PORT, NULL);  // Receive Port (RPC input)
//Host sendHost(IpAddr(239, 255, 0, 1), OUTPUT_PORT, NULL); // Send Port (RPC output)
//Host recHost(IpAddr(239, 255, 0, 1), INPUT_PORT, NULL);  // Receive Port (RPC input)
#endif
  
// receive commands, and send back the responses
char inbuf[512], outbuf[512];

void onUDPSocketEvent(UDPSocketEvent e)
{

  switch(e)
  {
  case UDPSOCKET_READABLE: //The only event for now

    Host host;
    while( int len = udpRec.recvfrom( inbuf, 512, &host ) )
    {
      if( len <= 0 )
        break;
      inbuf[len]=0;
#ifdef DEBUG
      printf("\r\nFrom %d.%d.%d.%d: %s\r\n", 
      host.getIp()[0], host.getIp()[1], host.getIp()[2], host.getIp()[3], inbuf);
#endif

#ifdef SENDBACK_UNICAST
    Host sendHost(IpAddr(
            host.getIp()[0], host.getIp()[1], host.getIp()[2], host.getIp()[3]),
            OUTPUT_PORT, NULL); // Send Port (RPC output)
#endif

        udpSend.bind(sendHost);

#ifdef DEBUG
        printf("debug1:%d %s\r\n",len,inbuf);
#endif
        if (len>0) {
            rpc(inbuf, outbuf); 
            udpSend.sendto( outbuf, strlen(outbuf), &sendHost);
        }
#ifdef DEBUG
        printf("debug2:%s\r\n", outbuf);
#endif
    }
    break;
  }
}

int main() {
// make debug port Fast
   Serial pc(USBTX, USBRX);
//    pc.baud(9600);
    pc.baud(115200);
//  pc.baud(230400);

    // setup the classes that can be created dynamically
    Base::add_rpc_class<AnalogIn>();
    Base::add_rpc_class<AnalogOut>();
    Base::add_rpc_class<DigitalIn>();
    Base::add_rpc_class<DigitalOut>();
    Base::add_rpc_class<DigitalInOut>();
    Base::add_rpc_class<PwmOut>();
    Base::add_rpc_class<Timer>();
    Base::add_rpc_class<SPI>();
    Base::add_rpc_class<BusOut>();
    Base::add_rpc_class<BusIn>();
    Base::add_rpc_class<BusInOut>();
    Base::add_rpc_class<Serial>();
    
    // setup network
    printf("Setting up...\r\n");
    EthernetErr ethErr = eth.setup();
    if(ethErr) {
        printf("Error %d in setup.\r\n", ethErr);
        return -1;
    }

    printf("UDP RPC Setup OK\r\n");
    
    udpRec.setOnEvent(&onUDPSocketEvent);
  
    udpRec.bind(recHost);
    
  
    while(1) {
        Net::poll();
 #if 0
 // debug code
        Host host;
        int len = udpRec.recvfrom( inbuf, 512, &host );   
        printf("debug:%d %s\r\n",len,inbuf);
  len=1;
        if (len>0) {
            rpc(inbuf, outbuf); 
  strcpy(outbuf,"RPC UDP Test");
            udpSend.sendto( outbuf, strlen(outbuf), &sendHost );
            memset(inbuf,0,512);
        }
        printf("debug:%s\r\n", outbuf);
        memset(outbuf,0,512);
        wait(1);
#endif
   }    

}

#if 0
//------------------------------------------------------------------------
// Test Program (written in processing)

// Important Note:
//  this program can NOT work in windows enviroment (only Linux enviroment)
//
//  2010/11/16:
//    Above bug fixed. Now it can work in both windows and linux.
//    Note: Please set your host IP.

/**
 * RCP over UDP (by mbed)
 * Test Program
 *
 * you can get UDP library from:
 * http://ubaa.net/shared/processing/udp/
 *
 */

// import UDP library
import hypermedia.net.*;

String remoteIP = "239.255.0.1"; // multicast IP
String localIP = "192.168.0.7"; // please set your host IP (2010/11/16)
int INPUT_PORT = 8000;
int OUTPUT_PORT = 8001;

UDP udp;  // define the UDP object

/**
 * init
 */
void setup() {
  // create a new datagram connection on port OUTPUT_PORT
  // and wait for incomming message
  udp = new UDP( this, OUTPUT_PORT, localIP ); // (2010/11/16)
// udp.log( true ); // <-- printout the connection activity
  udp.listen( true );
}

//process events
void draw() {;}

/* 
 * on key pressed event:
 * pressing a key sends predefined command
 */
void keyPressed() {
    String cmd="";
    if (key == '1') cmd="/";
    //
    if (key == '2') cmd="/AnalogIn/new p20 ain";
    if (key == '3') cmd="/ain/read";
    //
    if (key == '4') cmd="/AnalogOut/new p18 aout";
    if (key == '5') cmd="/aout/";
    if (key == '6') cmd="/aout/write_u16 4123";    
//   if (key == '4') cmd="/BusIn/new bin p23 p22 p21";
//   if (key == '5') cmd="/bin/read";
    //   
    if (key == '8') cmd="/DigitalOut/new LED4 myled4";
    if (key == '9') cmd="/myled4/write 1";
    if (key == '0') cmd="/myled4/write 0";    

    // send the command
    udp.send( cmd, remoteIP, INPUT_PORT );
 
}

/*
 * To perform any action on datagram reception
 */

void receive( byte[] data, String ip, int port ) {

  data = subset(data, 0, data.length);
  String message = new String( data );
  
  // print the result
  println( "received: \""+message+"\" from "+ip+" on port "+port );
}
//----------------------------------------------------------------------------
#endif

#if 0
//------------------------------------------------------------------------
// Test Program (written in ActionScript3)

// Important Note:
//  this program can work in both windows and Linux enviroment.

// DatagramSocketExample.as
//
// This program is comming from:
// http://help.adobe.com/en_US/FlashPlatform/beta/reference/actionscript/3/flash/net/DatagramSocket.html
//
// I changed some parameters(IP address, port# etc ) for testing mbed HTTP over UDP
// You can send command over UDP by changing "message:" field
//
//  You must build it as AIR application to utilize UDP capability.
//  localIP should be changed to fit your enviroment.
//
package
{
    import flash.display.Sprite;
    import flash.events.DatagramSocketDataEvent;
    import flash.events.Event;
    import flash.events.MouseEvent;
    import flash.events.TimerEvent;
    import flash.net.DatagramSocket;
    import flash.text.TextField;
    import flash.text.TextFieldAutoSize;
    import flash.text.TextFieldType;
    import flash.utils.ByteArray;
    import flash.utils.Timer;
    
    public class DatagramSocketExample extends Sprite
    {
        private var datagramSocket:DatagramSocket = new DatagramSocket();;

        private var localIP:TextField;
        private var localPort:TextField;
        private var logField:TextField;
        private var targetIP:TextField;
        private var targetPort:TextField;
        private var message:TextField;
        
        public function DatagramSocketExample()
        {
            setupUI();
        }

        private function bind( event:Event ):void
        {
            if( datagramSocket.bound ) 
            {
                datagramSocket.close();
                datagramSocket = new DatagramSocket();
                
            }
            datagramSocket.bind( parseInt( localPort.text ), localIP.text );
            datagramSocket.addEventListener( DatagramSocketDataEvent.DATA, dataReceived );
            datagramSocket.receive();
            log( "Bound to: " + datagramSocket.localAddress + ":" + datagramSocket.localPort );
        }
        
        private function dataReceived( event:DatagramSocketDataEvent ):void
        {
            //Read the data from the datagram
            log("Received from " + event.srcAddress + ":" + event.srcPort + "> " + 
                event.data.readUTFBytes( event.data.bytesAvailable ) );
        }
        
        private function send( event:Event ):void
        {
            //Create a message in a ByteArray
            var data:ByteArray = new ByteArray();
            data.writeUTFBytes( message.text );
            
            //Send a datagram to the target
            try
            {
                datagramSocket.send( data, 0, 0, targetIP.text, parseInt( targetPort.text )); 
                log( "Sent message to " + targetIP.text + ":" + targetPort.text );
            }
            catch ( error:Error )
            {
                log( error.message );
            }
        }
        
        private function log( text:String ):void
        {
            logField.appendText( text + "\n" );
            logField.scrollV = logField.maxScrollV;
            trace( text );
        }
        private function setupUI():void
        {
//            targetIP = createTextField( 10, 10, "Target IP:", "192.168.0.1" );
//            targetPort = createTextField( 10, 35, "Target port:", "8989" );

            targetIP = createTextField( 10, 10, "Target IP:", "239.255.0.1" ); 
            targetPort = createTextField( 10, 35, "Target port:", "8000" );
            
            message = createTextField( 10, 60, "Message:", "/AnalogIn/new p20 ain" );
//          localIP = createTextField( 10, 85, "Local IP", "0.0.0.0");
//           localPort = createTextField( 10, 110, "Local port:", "0" );

            localIP = createTextField( 10, 85, "Local IP", "192.168.0.7"); // set your host IP
            localPort = createTextField( 10, 110, "Local port:", "8001" );

            createTextButton( 250, 135, "Bind", bind );
            createTextButton( 300, 135, "Send", send );
            logField = createTextField( 10, 160, "Log:", "", false, 200 )
                
            this.stage.nativeWindow.activate();
        }
        
        private function createTextField( x:int, y:int, label:String, defaultValue:String = '', editable:Boolean = true, height:int = 20 ):TextField
        {
            var labelField:TextField = new TextField();
            labelField.text = label;
            labelField.type = TextFieldType.DYNAMIC;
            labelField.width = 180;
            labelField.x = x;
            labelField.y = y;
            
            var input:TextField = new TextField();
            input.text = defaultValue;
            input.type = TextFieldType.INPUT;
            input.border = editable;
            input.selectable = editable;
            input.width = 280;
            input.height = height;
            input.x = x + labelField.width;
            input.y = y;
            
            this.addChild( labelField );
            this.addChild( input );
            
            return input;
        }
        
        private function createTextButton( x:int, y:int, label:String, clickHandler:Function ):TextField
        {
            var button:TextField = new TextField();
            button.htmlText = "<u><b>" + label + "</b></u>";
            button.type = TextFieldType.DYNAMIC;
            button.selectable = false;
            button.width = 180;
            button.x = x;
            button.y = y;
            button.addEventListener( MouseEvent.CLICK, clickHandler );
            
            this.addChild( button );
            return button;
            
        }
    }
}
//------------------------------------------------------------------------
#endif