This is the first rev of HW3 for IDD

Dependencies:   MMA8451Q USBDevice mbed nRF24L01P

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers main.cpp Source File

main.cpp

00001 //NOTE: NORDIC BOARD ONLY WORKS W/ MBED 84!
00002 //Chose pin ordering from https://mbed.org/questions/1360/Using-nRF24L01-Module-with-FRDM-Board/ -- unused pins
00003 
00004 #include "mbed.h"
00005 #include "nRF24L01P.h"                              // nordic library
00006 
00007 #define DEBUG 0                                     // code debug mode
00008 #define BASE 0                                      // is base station
00009 
00010 
00011 #include "USBMouseKeyboard.h"                       // for the sword - mouse/keyboard combo
00012 #if(BASE == 1)
00013     USBMouseKeyboard MK;                            //Default is REL_MOUSE, bout could use ABS_MOUSE too
00014 #endif
00015 
00016 #define SCALING 50                                  // factor to multiply the accelerometer reading by (usually it is in the scale of g's. Decides sensitivity of mouse. Keep it less 100 (mouse is assigned an int8)
00017  
00018 // Accelerometer includes
00019 #include "MMA8451Q.h" 
00020 #define MMA8451_I2C_ADDRESS (0x1d<<1)
00021 
00022 // define I2C Pins and address for KL25Z. Taken from default sample code.
00023 PinName const SDA = PTE25;
00024 PinName const SCL = PTE24;
00025 
00026 // Base station TX/RX
00027 #define RX_NRF24L01P_ADDRESS       ((unsigned long long) 0xABABABABAB )
00028 #define TX_NRF24L01P_ADDRESS       ((unsigned long long) 0xCDCDCDCDCD )
00029 
00030 // The nRF24L01+ supports transfers from 1 to 32 bytes 
00031 // To base station: roll | cycle 1 2 3 | space = jump | left click = attack | right click = defend | w | s | d | a | 8-bit Y mouse movement | 8-bit X mouse movement
00032 // WASD = forward, left, back, right
00033 // From PC, only need (zero padded) 1 bit flag indicating if hit
00034 #define TRANSFER_SIZE   4
00035 
00036 Serial pc(USBTX, USBRX);                                    // PC communication
00037 
00038 PwmOut motor(D2);                                           // Only specific pins have PWM capability
00039 
00040 nRF24L01P nordic(PTD2, PTD3, PTC5, PTD0, PTD5, PTA13);      // mosi, miso, sck, csn, ce, irq
00041 
00042 DigitalIn modeSW(D15);                                      // base station or sword mode can be selected w/ jumper
00043 
00044 DigitalOut greenLED(LED_GREEN);
00045 
00046 // Accelerometer
00047 MMA8451Q acc(PTE25, PTE24, MMA8451_I2C_ADDRESS);
00048 
00049 void Calibrate(void);
00050 void Acc_GetXY(void);
00051 
00052     int16_t x,y;                                            // variables to hold acceleration data after call to Acc_Get_All
00053 float x_b, y_b;                                             // acc bias
00054 
00055 // Debug
00056 //DigitalOut greenLED(LED_GREEN);
00057 //DigitalOut redLED(LED_RED);
00058 
00059 AnalogIn ATTACK(A0);                                        // attack FSR
00060 AnalogIn SELECT(A1);                                        // defense/mode FSR
00061 AnalogIn XJOY(A2);                                          // joystick x axis
00062 AnalogIn YJOY(A3);                                          // joystick y axis
00063 
00064 DigitalIn JOYSEL(D3);
00065 
00066 bool isBaseStation;
00067 bool motorOnFlag;
00068 int motorCycle = 0;
00069 
00070 int main() {
00071     int8_t mouse_x, mouse_y;
00072     Calibrate();                                            // Calibrate accelerometer
00073 
00074     modeSW.mode(PullUp);                                    // Configure pull up to minimize wire on sword
00075     
00076     isBaseStation = (bool) !modeSW;                         // Detect device via jumper connection
00077     
00078     wait(5);
00079 
00080     // Power up wireless
00081     nordic.powerUp();
00082 
00083     // Display + change the (default) setup of the nRF24L01+ chip
00084     
00085     // Addresses 5 bytes long
00086     
00087     if (isBaseStation){
00088         nordic.setTxAddress(TX_NRF24L01P_ADDRESS ,5); 
00089         nordic.setRxAddress(RX_NRF24L01P_ADDRESS ,5); 
00090     }
00091     else{
00092         nordic.setRxAddress(TX_NRF24L01P_ADDRESS ,5); 
00093         nordic.setTxAddress(RX_NRF24L01P_ADDRESS ,5); 
00094     }
00095     
00096     pc.printf( "nRF24L01+ Frequency    : %d MHz\r\n",  nordic.getRfFrequency() );
00097     pc.printf( "nRF24L01+ Output power : %d dBm\r\n",  nordic.getRfOutputPower() );
00098     pc.printf( "nRF24L01+ Data Rate    : %d kbps\r\n", nordic.getAirDataRate() );       // 1Mbps
00099     pc.printf( "nRF24L01+ TX Address   : 0x%010llX\r\n", nordic.getTxAddress() );
00100     pc.printf( "nRF24L01+ RX Address   : 0x%010llX\r\n", nordic.getRxAddress() );
00101 
00102     // Data packet length
00103     nordic.setTransferSize( TRANSFER_SIZE );
00104 
00105     nordic.setReceiveMode();
00106     nordic.enable();
00107     
00108     // Set motor PWM period
00109     motor.period(0.001f);       // 1ms period
00110     motor.write(0.0f);          // initially not on
00111     
00112     // Status flags
00113     bool motorON = false; 
00114     bool mouse1 = false;
00115     bool mouse2 = false;
00116     bool mouse3 = false;
00117     bool mouse4 = false;
00118     bool mouse5 = false;
00119     bool attackflag = false;
00120 
00121     int rxDataCnt = 0;
00122     
00123     // counting the mode
00124     uint8_t mode_count = 0;
00125 
00126     while (1) {
00127         // Only reads 1 byte from PC + sends to other mcu (pads w/ bytes) if base station
00128         if (isBaseStation){
00129 
00130             // If we've received anything over the host serial link...
00131             if ( pc.readable() ) {
00132                 char txData[TRANSFER_SIZE];
00133                 // ...add it to the transmit buffer -- only care about first byte
00134                 txData[0] = pc.getc();
00135                 txData[1] = 100;
00136                 txData[2] = 100;
00137                 txData[3] = '\n';
00138                 
00139                 // Send the transmitbuffer via the nRF24L01+
00140                 nordic.write( NRF24L01P_PIPE_P0, txData, TRANSFER_SIZE );
00141 
00142                 // Toggle LED1 (to help debug Host -> nRF24L01+ communication)
00143                 /*if (txData[0] == 66)
00144                     greenLED = !greenLED;*/
00145             }
00146 
00147             // If we've received anything in the nRF24L01+... = sword
00148             if ( nordic.readable() ) {
00149                 char rxData[TRANSFER_SIZE];
00150                 // ...read the data into the receive buffer
00151                 rxDataCnt = nordic.read( NRF24L01P_PIPE_P0, rxData, TRANSFER_SIZE );
00152 
00153                 //Get data and convert to mouse x,y and key entry
00154                 // To base station: roll | cycle 1 2 3 | space = jump | left click = attack | right click = defend | w | s | d | a | 8-bit Y mouse movement | 8-bit X mouse movement
00155                 
00156                 int8_t dx = rxData[0];                      // change in x
00157                 int8_t dy = rxData[1];                      // change in y
00158                 
00159                 bool mode_stat = (rxData[2] >> 7) & 1;      // checking flag bits
00160                 bool joy_but = (rxData[2] >> 6) & 1;
00161                 bool def_stat = (rxData[2] >> 5) & 1;
00162                 bool attack_stat = (rxData[2] >> 4) & 1;
00163                 bool key_w = (rxData[2] >> 3) & 1;
00164                 bool key_s = (rxData[2] >> 2) & 1;
00165                 bool key_d = (rxData[2] >> 1) & 1;
00166                 bool key_a = (rxData[2] >> 0) & 1;
00167 
00168                 bool roll = (rxData[3] >> 0) & 1;
00169 
00170                 #if(BASE == 1)                              // Only if base station
00171                     MK.move(dy, dx);                        // move mouse relative                  
00172                     
00173                     if(joy_but)                             // do keyboard events
00174                         MK.putc(' ');  
00175                         
00176                     if(attack_stat)
00177                     {
00178                         MK.press(MOUSE_LEFT);
00179                         mouse1 = true;
00180                     }
00181                     if(!attack_stat && mouse1)
00182                     {
00183                         MK.release(MOUSE_LEFT);
00184                         mouse1 = false;
00185                     }
00186                     if(key_a)                       // move left
00187                     {
00188                         MK.press(MOUSE_RIGHT);
00189                         mouse2 = true;
00190                     }
00191                     if(!key_a && mouse2)
00192                     {
00193                         MK.release(MOUSE_RIGHT);
00194                         mouse2 = false;
00195                     }
00196                     if(key_d)                       // move right
00197                     {
00198                         MK.press(MOUSE_MIDDLE);
00199                         mouse3 = true;
00200                     }
00201                     if(!key_d && mouse3)
00202                     {
00203                         MK.release(MOUSE_MIDDLE);
00204                         mouse3 = false;
00205                     }
00206                     // mouse 4, 5 have issues on windows
00207                     if(key_w)                       // move forward
00208                     {
00209                         //MK.press(16);               // mouse5
00210                         //mouse5 = true;
00211                         MK.putc('w');
00212                     }
00213                     /*if(!key_w && mouse5)
00214                     {
00215                         MK.release(16);
00216                         mouse5 = false;
00217                     }*/
00218                     if(key_s)                       // move backward
00219                     {
00220                         //MK.press(8);                // mouse4
00221                         //mouse4 = true;
00222                         MK.putc('s');
00223                     }
00224                     /*if(!key_s && mouse4)
00225                     {
00226                         MK.release(8);
00227                         mouse4 = false;
00228                     }*/
00229                     
00230                     // Single push commands
00231                     if(def_stat)
00232                         MK.putc('d');
00233                         
00234                     if(mode_stat)
00235                     {
00236                         MK.putc('1'+mode_count);
00237                         mode_count = (mode_count+1)%3;
00238                     }
00239                     if(roll)
00240                         MK.putc('r'); 
00241                                         
00242                 #endif
00243 
00244                 //pc.printf("x: %d y: %d \r\n",dx,dy);
00245 
00246                 // Display the receive buffer contents via the host serial link
00247                 /*for ( int i = 0; i < TRANSFER_SIZE; i++ ) {
00248 
00249                     pc.putc( rxData[i] );
00250                 }*/
00251             }
00252         }
00253 
00254         // sword
00255         else{
00256             int ATTACKVAL = ATTACK.read_u16();          // attack FSR
00257             int SELECTVAL = SELECT.read_u16();          // mode/defense FSR
00258             int XJOYVAL = XJOY.read_u16();              // joystick x
00259             int YJOYVAL = YJOY.read_u16();              // joystick y
00260             int JOYSELVAL = (int) JOYSEL;               // joystick select value
00261             
00262             // if joystick push/pulled all the way on axis, do roll/move faster in direction
00263             //bool roll = ((XJOYVAL > 64000) || (XJOYVAL < 1000) ||  (YJOYVAL > 64000) || (YJOYVAL < 1000)) ? true: 0;
00264             // Disable backward roll due to lack of continuous MOUSE buttons
00265             bool roll = ((XJOYVAL > 64000) || (XJOYVAL < 1000) ||  (YJOYVAL > 64000)) ? true: 0;
00266 
00267             // thresholding
00268             bool mode_stat = (SELECTVAL > 45000) ? true: 0;                     // 1, 2, 3 rotated (defense/mode FSR pressed all the way)
00269             bool joy_but = JOYSEL == 0? true: 0;
00270             bool def_stat = (SELECTVAL > 10000 && SELECTVAL < 45000) ? true: 0; // defend if defense/mode FSR slightly pressed
00271             bool attack_stat = ATTACKVAL > 10000? true: 0;                      // attack if attack FSR pressed
00272             bool key_d = XJOYVAL > 35000 ? true: 0;                             // if joystick moves in direction, direction key should be pressed
00273             bool key_a = XJOYVAL < 30000 ? true : 0;
00274             bool key_w = YJOYVAL > 35000 ? true: 0;
00275             bool key_s = YJOYVAL < 30000 ? true: 0;
00276             
00277             // turn on motor at start of attack
00278             
00279             if (attack_stat == true)
00280                 attackflag = true;
00281             if (attackflag == true){
00282                 if (motorCycle < 250){
00283                     motorCycle++;
00284                     motor.write(0.40f);                         // 40% duty cycle, relative to period
00285 
00286                 }
00287                 else {
00288                     motorCycle = 0;
00289                     attackflag = false;
00290                     motor.write(0.00f);                         
00291                 }
00292             }
00293             
00294             
00295             
00296             // make byte 2 of packet
00297             uint8_t key_stat = mode_stat<<7|joy_but<<6|def_stat<<5|attack_stat<<4|key_w<<3|key_s<<2|key_d<<1|key_a<<0;
00298             
00299             //pc.printf("F1: %d \t F2: %d \t X: %d \t Y: %d \t SEL: %d \r\n", ATTACKVAL, SELECTVAL, XJOYVAL, YJOYVAL, JOYSELVAL);
00300 
00301             // Let serial read catch up on base station/PC side
00302             wait_us(150);
00303 
00304             char swordData[TRANSFER_SIZE]; 
00305             
00306             Acc_GetXY();                                // Get X, Y acceleration
00307         
00308             mouse_x = x;                                // x, y assigned in prev function
00309             mouse_y = y;
00310         
00311             char lowX = char(mouse_x & 0x00FF);         // only use lowest 8 bits of data
00312             char lowY = char(mouse_y & 0x00FF);
00313             
00314             //pc.printf("x: %f \t y: %f \r\n", mouse_x,mouse_y);
00315             
00316             // left A, right D, back S, up W
00317             
00318             // MSB -- LSB send packet
00319             swordData[0] = lowX;
00320             swordData[1] = lowY; 
00321             swordData[2] = char(key_stat); 
00322             swordData[3] = char(roll);                  // cast bool into char
00323             
00324             // Send the transmitbuffer via the nRF24L01+
00325             nordic.write( NRF24L01P_PIPE_P0, swordData, TRANSFER_SIZE );
00326 
00327             // If we've received anything from base station 
00328             if ( nordic.readable() ) {
00329                 
00330                 greenLED = !greenLED;
00331                 
00332                 char rxData[TRANSFER_SIZE];
00333                 // ...read the data into the receive buffer
00334                 rxDataCnt = nordic.read( NRF24L01P_PIPE_P0, rxData, TRANSFER_SIZE );
00335 
00336                 #if DEBUG == 1
00337                     // Display the receive buffer contents via the host serial link
00338                     for ( int i = 0; i < TRANSFER_SIZE; i++ ) {
00339                         pc.putc( rxData[i] );
00340                     }
00341                 #endif
00342 
00343                 // From PC, only need (zero padded) 1 bit flag indicating if hit 
00344                 // In first byte
00345                 motorON = (rxData[0] >> 0) & 1;                 // Motor ON when sword contact made
00346                 if (motorON)
00347                     motorOnFlag = true;
00348             }
00349             
00350             // if flag to turn motor on sent, run motor for a little while and then stop
00351             // period not extended if another motor on command sent in the middle of the count
00352 
00353         }
00354     }
00355 }
00356 
00357 // perform initial accelerometer calibration to zero stuff
00358 void Calibrate(void) 
00359 {
00360      unsigned int count1;
00361      count1 = 0;
00362      float sstatex = 0;
00363      float sstatey = 0;
00364      
00365      do{ 
00366      sstatex += acc.getAccX();  // Accumulate Samples
00367      sstatey += acc.getAccY();
00368      count1++;
00369      }while(count1!=0x0400);    // 1024 times
00370      x_b = sstatex/1024.0;      // division between 1024
00371      y_b = sstatey/1024.0;
00372 }
00373 
00374 // remove offset from calibration + scale for sensitivity when getting accelerometer data
00375 void Acc_GetXY(void)
00376 {
00377     x = (int16_t)((acc.getAccX()- x_b)*SCALING);
00378     y = (int16_t)((acc.getAccY()- y_b)*SCALING);
00379 }
00380 
00381 /* Processing code
00382 
00383 //sikuli-java.jar needed to keep track of HP/score for rumble + serial RX/TX
00384 
00385 import org.sikuli.script.*;
00386 import processing.serial.*;
00387 
00388 Serial myPort;                                      // Serial port
00389 int lastTime = 0;                                   // Time counter
00390 
00391 Region myHPReg = new Region(1,1,500,500);           // HP watch regions x, y, w, h
00392 Region otherHPReg = new Region(500,500,500,500);
00393 
00394 // Specify event handler for detecting changes
00395 class hpChangeClass implements SikuliEventObserver {
00396     @Override
00397     void targetChanged(SikuliEventChange evnt1) {
00398       println( "changed!" );
00399       for (int i = 0; i <100; i++){
00400         myPort.write(3);                    // Rumble motor (LSB high)
00401       }
00402       //lastTime++;               
00403     }
00404             
00405     void targetAppeared(SikuliEventAppear evnt2) {
00406       println("test");
00407     }
00408             
00409     void targetVanished(SikuliEventVanish evnt3) {
00410       println("test");
00411     }
00412     
00413 }
00414 
00415 hpChangeClass regionChange = new hpChangeClass();
00416 
00417 void setup(){
00418   size(1,1);                                                    // Don't care (out of focus)
00419   myPort = new Serial(this, "/dev/tty.usbmodem1422", 9600);     // Serial setup
00420   myPort.clear();
00421   //lastTime = millis();
00422   myHPReg.highlight(5);                                         // Show regions watched for 5 seconds
00423   otherHPReg.highlight(5);
00424 
00425   myHPReg.onChange(10, regionChange);                           // num of pixels for change detection, event handler
00426   myHPReg.observeInBackground((int)Float.POSITIVE_INFINITY);    // watch forever
00427   
00428   otherHPReg.onChange(10, regionChange);                        // num of pixels for change detection, event handler
00429   otherHPReg.observeInBackground((int)Float.POSITIVE_INFINITY); // watch forever
00430 }
00431 
00432 void draw() {
00433   
00434   Wait
00435   if ( millis() - lastTime > 5000 ) {
00436     myPort.write(68);
00437     lastTime = millis();
00438   }
00439 
00440 }
00441 
00442 */
00443 
00444