RC_Simulator.....By Jafar Qutteineh with mods to connect my Futaba 9C to \'RC Helicopter\' by http://www.alphamacsoftware.com/

Dependencies:   mbed

Revision:
0:65b9d8f621d2
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Thu Dec 15 03:24:33 2011 +0000
@@ -0,0 +1,135 @@
+#include "mbed.h"
+#include "usbhid.h"
+
+
+/* RC_Simulator.....By Jafar Qutteineh*/
+/* This program takes the PPM Singal(Pulse Position Modulation) from your RC transmitter
+   and emulate it as a USB HID Joystick.
+   Currently, program configured to accept Throttle, Rudder, Elevator, Ailerons and 
+   2 buttons. It can be adjusted easily to read other channels as well.
+   The current state of code is just a proof of concept. It's rough and not clean,
+   once you understand how it work, customize to your like*/
+   
+/*Credit goes to Phil Wright for USB HID code and to Shinichiro Oba Joystiq work*/
+
+/*Setup: Just connect the GND and PPM singal of your transmitter to the GND and P5 respectivly.*/
+
+/*How it works: 
+    -P5 is configured as InturreptIn pin. whenever the PPM signal goes down Inturrept SignalFall() is fired.
+    -SignalFall keep track of timing:
+        a) If Pulse width is <300 uS it's most probably a glitch.
+        b) If pulse width is >300 uS but less than < 2000 uS this is a correct channel. Read it and wait for next channel
+        c) If Pulse width is >8000 uS this is a new frame, start again.
+        d) Timing will be different from transmitter to another, you may want to play a little bit here
+    -Once a complete frame is read the values are feedback to our USB HID Joysick class.
+*/   
+   
+
+
+InterruptIn PPMsignal(p5); // connect PPM signal to this, you can change to anyother pin
+Serial PC(USBTX,USBRX);   // I used this for debuging
+USBJoystick joystick;     /* This is basicly Shinichiro joystiq, I've only adjusted the Report descriptor to my needs.   
+                              for more help on this check:
+                              -http://frank.circleofcurrent.com/cache/hid_tutorial_1.htm
+                              -http://helmpcb.com/electronics/usb-joystick */
+                              
+
+int TimeElapsed =0; //Keeps track of time between inturrepts
+Timer timer;        
+unsigned char CurChannel=0; //This will point to the current channel in PPM frame. My PPM signal looks like 10 channels and 1 start frame
+                            // yours could be different
+unsigned char Channels[11]={0,0,0,0,0,0,0,0,0,0,0}; //This where channels value is stored until frame is complete.
+unsigned short Times[11]={0,0,0,0,0,0,0,0,0,0,0}; //This where channels value is stored until frame is complete.
+bool CanUpdate=false;       // Once PPM frame is complete this will be true
+
+//Raise_Error is just a function that helped me in development process. You can ignore it all togather.
+void Raise_Error (unsigned char Err_Code, int info) {
+    switch (Err_Code) {
+        case 0:
+            PC.printf ("%i\n",info);
+            break;
+        case 1:
+            PC.printf ("Broke@ %i\n",info);
+            break;
+        case 2:
+            PC.printf ("Set ok\n");
+            break;
+        case 3:
+            PC.printf ("%i\n",info);
+            break;
+        case 255:
+            PC.printf("Initalized sucessfully \n");
+            break;
+        default:
+            PC.printf("I shouldn't be here \n");
+    }
+
+}
+
+//Here were all the work takeplace
+void SignalFall() {
+    TimeElapsed = timer.read_us();
+    if (TimeElapsed <300) { 
+        //Raise_Error(0,TimeElapsed);
+        return; //ignore, it's a glitch. Dont move to the next channel
+    }
+    __disable_irq();
+    timer.reset();  
+     //Raise_Error(0,TimeElapsed);
+    if ((TimeElapsed > 8000 ) && (CurChannel != 0)) {   //somehow before reaching the end of PPM frame you read   "New" frame signal???
+                                                         //Ok, it happens. Just ignore this frame and start a new one        
+        //Raise_Error (1,CurChannel);          //incomplete channels set
+        CurChannel=0;              
+    }
+   if ((TimeElapsed < 8000 ) && (CurChannel == 0)) {
+        //Raise_Error (1,CurChannel);          //incomplete channels set
+      __enable_irq();       // This is good. You've received "New" frame signal as expected
+        return;
+    }
+
+    // Process current channel. This is a correct channel in a correct frame so far
+    //if (CurChannel==4) Raise_Error(3,TimeElapsed);
+    Channels[CurChannel]= (TimeElapsed-1000)*255/1000; // Normalize reading (Min: 900us Max: 1900 us). This is my readings, yours can be different
+    Times[CurChannel] = TimeElapsed;
+    CurChannel++;
+    
+    if (CurChannel==9 ) {      // great!, you've a complete correct frame. Update Joystick and star a new frame
+        CurChannel=0;
+        //Raise_Error(3,0);
+        CanUpdate= true;
+    }
+    __enable_irq();
+}
+
+void Initalize () {
+    __disable_irq();
+    PC.baud(115200); // set baude rate
+    PPMsignal.mode (PullUp);
+    PPMsignal.fall(&SignalFall); //Attach SignalFall routine to handle PPMsignal fall
+    timer.start();
+    Raise_Error(255,0); // return successful
+    timer.reset();
+    __enable_irq();
+
+}
+
+int main() {
+    //unsigned short *pOut = Times;
+    unsigned char *pOut = Channels;
+    
+    Initalize();
+    //wait(5);
+    
+
+    while (1) {
+        if (CanUpdate) {        // update joystick here
+            CanUpdate=false;
+            joystick.joystick(Channels[1],Channels[4],Channels[3],Channels[2],Channels[7],Channels[8]);  //update joystick state (Throttle, Rudder, X,Y, Button 1, Button 2)
+            PC.printf("% 4d,% 4d,% 4d,% 4d\r",pOut[1],pOut[2],pOut[3],pOut[4]); // Raise_Error(3,Channels[1]);
+              //Channel 5 : PIT
+              //Channel 6: PLT
+        }
+    }
+
+}
+