RC_Simulator.....By Jafar Qutteineh with mods to connect my Futaba 9C to \'RC Helicopter\' by http://www.alphamacsoftware.com/
main.cpp@0:65b9d8f621d2, 2011-12-15 (annotated)
- Committer:
- cbayley
- Date:
- Thu Dec 15 03:24:33 2011 +0000
- Revision:
- 0:65b9d8f621d2
Initial
Who changed what in which revision?
User | Revision | Line number | New 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 |