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

Dependencies:   mbed

Committer:
cbayley
Date:
Thu Dec 15 03:24:33 2011 +0000
Revision:
0:65b9d8f621d2
Initial

Who changed what in which revision?

UserRevisionLine numberNew contents of line
cbayley 0:65b9d8f621d2 1 #include "mbed.h"
cbayley 0:65b9d8f621d2 2 #include "usbhid.h"
cbayley 0:65b9d8f621d2 3
cbayley 0:65b9d8f621d2 4
cbayley 0:65b9d8f621d2 5 /* RC_Simulator.....By Jafar Qutteineh*/
cbayley 0:65b9d8f621d2 6 /* This program takes the PPM Singal(Pulse Position Modulation) from your RC transmitter
cbayley 0:65b9d8f621d2 7 and emulate it as a USB HID Joystick.
cbayley 0:65b9d8f621d2 8 Currently, program configured to accept Throttle, Rudder, Elevator, Ailerons and
cbayley 0:65b9d8f621d2 9 2 buttons. It can be adjusted easily to read other channels as well.
cbayley 0:65b9d8f621d2 10 The current state of code is just a proof of concept. It's rough and not clean,
cbayley 0:65b9d8f621d2 11 once you understand how it work, customize to your like*/
cbayley 0:65b9d8f621d2 12
cbayley 0:65b9d8f621d2 13 /*Credit goes to Phil Wright for USB HID code and to Shinichiro Oba Joystiq work*/
cbayley 0:65b9d8f621d2 14
cbayley 0:65b9d8f621d2 15 /*Setup: Just connect the GND and PPM singal of your transmitter to the GND and P5 respectivly.*/
cbayley 0:65b9d8f621d2 16
cbayley 0:65b9d8f621d2 17 /*How it works:
cbayley 0:65b9d8f621d2 18 -P5 is configured as InturreptIn pin. whenever the PPM signal goes down Inturrept SignalFall() is fired.
cbayley 0:65b9d8f621d2 19 -SignalFall keep track of timing:
cbayley 0:65b9d8f621d2 20 a) If Pulse width is <300 uS it's most probably a glitch.
cbayley 0:65b9d8f621d2 21 b) If pulse width is >300 uS but less than < 2000 uS this is a correct channel. Read it and wait for next channel
cbayley 0:65b9d8f621d2 22 c) If Pulse width is >8000 uS this is a new frame, start again.
cbayley 0:65b9d8f621d2 23 d) Timing will be different from transmitter to another, you may want to play a little bit here
cbayley 0:65b9d8f621d2 24 -Once a complete frame is read the values are feedback to our USB HID Joysick class.
cbayley 0:65b9d8f621d2 25 */
cbayley 0:65b9d8f621d2 26
cbayley 0:65b9d8f621d2 27
cbayley 0:65b9d8f621d2 28
cbayley 0:65b9d8f621d2 29 InterruptIn PPMsignal(p5); // connect PPM signal to this, you can change to anyother pin
cbayley 0:65b9d8f621d2 30 Serial PC(USBTX,USBRX); // I used this for debuging
cbayley 0:65b9d8f621d2 31 USBJoystick joystick; /* This is basicly Shinichiro joystiq, I've only adjusted the Report descriptor to my needs.
cbayley 0:65b9d8f621d2 32 for more help on this check:
cbayley 0:65b9d8f621d2 33 -http://frank.circleofcurrent.com/cache/hid_tutorial_1.htm
cbayley 0:65b9d8f621d2 34 -http://helmpcb.com/electronics/usb-joystick */
cbayley 0:65b9d8f621d2 35
cbayley 0:65b9d8f621d2 36
cbayley 0:65b9d8f621d2 37 int TimeElapsed =0; //Keeps track of time between inturrepts
cbayley 0:65b9d8f621d2 38 Timer timer;
cbayley 0:65b9d8f621d2 39 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
cbayley 0:65b9d8f621d2 40 // yours could be different
cbayley 0:65b9d8f621d2 41 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.
cbayley 0:65b9d8f621d2 42 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.
cbayley 0:65b9d8f621d2 43 bool CanUpdate=false; // Once PPM frame is complete this will be true
cbayley 0:65b9d8f621d2 44
cbayley 0:65b9d8f621d2 45 //Raise_Error is just a function that helped me in development process. You can ignore it all togather.
cbayley 0:65b9d8f621d2 46 void Raise_Error (unsigned char Err_Code, int info) {
cbayley 0:65b9d8f621d2 47 switch (Err_Code) {
cbayley 0:65b9d8f621d2 48 case 0:
cbayley 0:65b9d8f621d2 49 PC.printf ("%i\n",info);
cbayley 0:65b9d8f621d2 50 break;
cbayley 0:65b9d8f621d2 51 case 1:
cbayley 0:65b9d8f621d2 52 PC.printf ("Broke@ %i\n",info);
cbayley 0:65b9d8f621d2 53 break;
cbayley 0:65b9d8f621d2 54 case 2:
cbayley 0:65b9d8f621d2 55 PC.printf ("Set ok\n");
cbayley 0:65b9d8f621d2 56 break;
cbayley 0:65b9d8f621d2 57 case 3:
cbayley 0:65b9d8f621d2 58 PC.printf ("%i\n",info);
cbayley 0:65b9d8f621d2 59 break;
cbayley 0:65b9d8f621d2 60 case 255:
cbayley 0:65b9d8f621d2 61 PC.printf("Initalized sucessfully \n");
cbayley 0:65b9d8f621d2 62 break;
cbayley 0:65b9d8f621d2 63 default:
cbayley 0:65b9d8f621d2 64 PC.printf("I shouldn't be here \n");
cbayley 0:65b9d8f621d2 65 }
cbayley 0:65b9d8f621d2 66
cbayley 0:65b9d8f621d2 67 }
cbayley 0:65b9d8f621d2 68
cbayley 0:65b9d8f621d2 69 //Here were all the work takeplace
cbayley 0:65b9d8f621d2 70 void SignalFall() {
cbayley 0:65b9d8f621d2 71 TimeElapsed = timer.read_us();
cbayley 0:65b9d8f621d2 72 if (TimeElapsed <300) {
cbayley 0:65b9d8f621d2 73 //Raise_Error(0,TimeElapsed);
cbayley 0:65b9d8f621d2 74 return; //ignore, it's a glitch. Dont move to the next channel
cbayley 0:65b9d8f621d2 75 }
cbayley 0:65b9d8f621d2 76 __disable_irq();
cbayley 0:65b9d8f621d2 77 timer.reset();
cbayley 0:65b9d8f621d2 78 //Raise_Error(0,TimeElapsed);
cbayley 0:65b9d8f621d2 79 if ((TimeElapsed > 8000 ) && (CurChannel != 0)) { //somehow before reaching the end of PPM frame you read "New" frame signal???
cbayley 0:65b9d8f621d2 80 //Ok, it happens. Just ignore this frame and start a new one
cbayley 0:65b9d8f621d2 81 //Raise_Error (1,CurChannel); //incomplete channels set
cbayley 0:65b9d8f621d2 82 CurChannel=0;
cbayley 0:65b9d8f621d2 83 }
cbayley 0:65b9d8f621d2 84 if ((TimeElapsed < 8000 ) && (CurChannel == 0)) {
cbayley 0:65b9d8f621d2 85 //Raise_Error (1,CurChannel); //incomplete channels set
cbayley 0:65b9d8f621d2 86 __enable_irq(); // This is good. You've received "New" frame signal as expected
cbayley 0:65b9d8f621d2 87 return;
cbayley 0:65b9d8f621d2 88 }
cbayley 0:65b9d8f621d2 89
cbayley 0:65b9d8f621d2 90 // Process current channel. This is a correct channel in a correct frame so far
cbayley 0:65b9d8f621d2 91 //if (CurChannel==4) Raise_Error(3,TimeElapsed);
cbayley 0:65b9d8f621d2 92 Channels[CurChannel]= (TimeElapsed-1000)*255/1000; // Normalize reading (Min: 900us Max: 1900 us). This is my readings, yours can be different
cbayley 0:65b9d8f621d2 93 Times[CurChannel] = TimeElapsed;
cbayley 0:65b9d8f621d2 94 CurChannel++;
cbayley 0:65b9d8f621d2 95
cbayley 0:65b9d8f621d2 96 if (CurChannel==9 ) { // great!, you've a complete correct frame. Update Joystick and star a new frame
cbayley 0:65b9d8f621d2 97 CurChannel=0;
cbayley 0:65b9d8f621d2 98 //Raise_Error(3,0);
cbayley 0:65b9d8f621d2 99 CanUpdate= true;
cbayley 0:65b9d8f621d2 100 }
cbayley 0:65b9d8f621d2 101 __enable_irq();
cbayley 0:65b9d8f621d2 102 }
cbayley 0:65b9d8f621d2 103
cbayley 0:65b9d8f621d2 104 void Initalize () {
cbayley 0:65b9d8f621d2 105 __disable_irq();
cbayley 0:65b9d8f621d2 106 PC.baud(115200); // set baude rate
cbayley 0:65b9d8f621d2 107 PPMsignal.mode (PullUp);
cbayley 0:65b9d8f621d2 108 PPMsignal.fall(&SignalFall); //Attach SignalFall routine to handle PPMsignal fall
cbayley 0:65b9d8f621d2 109 timer.start();
cbayley 0:65b9d8f621d2 110 Raise_Error(255,0); // return successful
cbayley 0:65b9d8f621d2 111 timer.reset();
cbayley 0:65b9d8f621d2 112 __enable_irq();
cbayley 0:65b9d8f621d2 113
cbayley 0:65b9d8f621d2 114 }
cbayley 0:65b9d8f621d2 115
cbayley 0:65b9d8f621d2 116 int main() {
cbayley 0:65b9d8f621d2 117 //unsigned short *pOut = Times;
cbayley 0:65b9d8f621d2 118 unsigned char *pOut = Channels;
cbayley 0:65b9d8f621d2 119
cbayley 0:65b9d8f621d2 120 Initalize();
cbayley 0:65b9d8f621d2 121 //wait(5);
cbayley 0:65b9d8f621d2 122
cbayley 0:65b9d8f621d2 123
cbayley 0:65b9d8f621d2 124 while (1) {
cbayley 0:65b9d8f621d2 125 if (CanUpdate) { // update joystick here
cbayley 0:65b9d8f621d2 126 CanUpdate=false;
cbayley 0:65b9d8f621d2 127 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)
cbayley 0:65b9d8f621d2 128 PC.printf("% 4d,% 4d,% 4d,% 4d\r",pOut[1],pOut[2],pOut[3],pOut[4]); // Raise_Error(3,Channels[1]);
cbayley 0:65b9d8f621d2 129 //Channel 5 : PIT
cbayley 0:65b9d8f621d2 130 //Channel 6: PLT
cbayley 0:65b9d8f621d2 131 }
cbayley 0:65b9d8f621d2 132 }
cbayley 0:65b9d8f621d2 133
cbayley 0:65b9d8f621d2 134 }
cbayley 0:65b9d8f621d2 135