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

Dependencies:   mbed

main.cpp

Committer:
cbayley
Date:
2011-12-15
Revision:
0:65b9d8f621d2

File content as of revision 0:65b9d8f621d2:

#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
        }
    }

}