This is the first rev of HW3 for IDD
Dependencies: MMA8451Q USBDevice mbed nRF24L01P
main.cpp
- Committer:
- shunshou
- Date:
- 2014-09-29
- Revision:
- 4:7012a2af25f6
- Parent:
- 3:99ed0483f868
File content as of revision 4:7012a2af25f6:
//NOTE: NORDIC BOARD ONLY WORKS W/ MBED 84! //Chose pin ordering from https://mbed.org/questions/1360/Using-nRF24L01-Module-with-FRDM-Board/ -- unused pins #include "mbed.h" #include "nRF24L01P.h" // nordic library #define DEBUG 0 // code debug mode #define BASE 0 // is base station #include "USBMouseKeyboard.h" // for the sword - mouse/keyboard combo #if(BASE == 1) USBMouseKeyboard MK; //Default is REL_MOUSE, bout could use ABS_MOUSE too #endif #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) // Accelerometer includes #include "MMA8451Q.h" #define MMA8451_I2C_ADDRESS (0x1d<<1) // define I2C Pins and address for KL25Z. Taken from default sample code. PinName const SDA = PTE25; PinName const SCL = PTE24; // Base station TX/RX #define RX_NRF24L01P_ADDRESS ((unsigned long long) 0xABABABABAB ) #define TX_NRF24L01P_ADDRESS ((unsigned long long) 0xCDCDCDCDCD ) // The nRF24L01+ supports transfers from 1 to 32 bytes // 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 // WASD = forward, left, back, right // From PC, only need (zero padded) 1 bit flag indicating if hit #define TRANSFER_SIZE 4 Serial pc(USBTX, USBRX); // PC communication PwmOut motor(D2); // Only specific pins have PWM capability nRF24L01P nordic(PTD2, PTD3, PTC5, PTD0, PTD5, PTA13); // mosi, miso, sck, csn, ce, irq DigitalIn modeSW(D15); // base station or sword mode can be selected w/ jumper DigitalOut greenLED(LED_GREEN); // Accelerometer MMA8451Q acc(PTE25, PTE24, MMA8451_I2C_ADDRESS); void Calibrate(void); void Acc_GetXY(void); int16_t x,y; // variables to hold acceleration data after call to Acc_Get_All float x_b, y_b; // acc bias // Debug //DigitalOut greenLED(LED_GREEN); //DigitalOut redLED(LED_RED); AnalogIn ATTACK(A0); // attack FSR AnalogIn SELECT(A1); // defense/mode FSR AnalogIn XJOY(A2); // joystick x axis AnalogIn YJOY(A3); // joystick y axis DigitalIn JOYSEL(D3); bool isBaseStation; bool motorOnFlag; int motorCycle = 0; int main() { int8_t mouse_x, mouse_y; Calibrate(); // Calibrate accelerometer modeSW.mode(PullUp); // Configure pull up to minimize wire on sword isBaseStation = (bool) !modeSW; // Detect device via jumper connection wait(5); // Power up wireless nordic.powerUp(); // Display + change the (default) setup of the nRF24L01+ chip // Addresses 5 bytes long if (isBaseStation){ nordic.setTxAddress(TX_NRF24L01P_ADDRESS ,5); nordic.setRxAddress(RX_NRF24L01P_ADDRESS ,5); } else{ nordic.setRxAddress(TX_NRF24L01P_ADDRESS ,5); nordic.setTxAddress(RX_NRF24L01P_ADDRESS ,5); } pc.printf( "nRF24L01+ Frequency : %d MHz\r\n", nordic.getRfFrequency() ); pc.printf( "nRF24L01+ Output power : %d dBm\r\n", nordic.getRfOutputPower() ); pc.printf( "nRF24L01+ Data Rate : %d kbps\r\n", nordic.getAirDataRate() ); // 1Mbps pc.printf( "nRF24L01+ TX Address : 0x%010llX\r\n", nordic.getTxAddress() ); pc.printf( "nRF24L01+ RX Address : 0x%010llX\r\n", nordic.getRxAddress() ); // Data packet length nordic.setTransferSize( TRANSFER_SIZE ); nordic.setReceiveMode(); nordic.enable(); // Set motor PWM period motor.period(0.001f); // 1ms period motor.write(0.0f); // initially not on // Status flags bool motorON = false; bool mouse1 = false; bool mouse2 = false; bool mouse3 = false; bool mouse4 = false; bool mouse5 = false; bool attackflag = false; int rxDataCnt = 0; // counting the mode uint8_t mode_count = 0; while (1) { // Only reads 1 byte from PC + sends to other mcu (pads w/ bytes) if base station if (isBaseStation){ // If we've received anything over the host serial link... if ( pc.readable() ) { char txData[TRANSFER_SIZE]; // ...add it to the transmit buffer -- only care about first byte txData[0] = pc.getc(); txData[1] = 100; txData[2] = 100; txData[3] = '\n'; // Send the transmitbuffer via the nRF24L01+ nordic.write( NRF24L01P_PIPE_P0, txData, TRANSFER_SIZE ); // Toggle LED1 (to help debug Host -> nRF24L01+ communication) /*if (txData[0] == 66) greenLED = !greenLED;*/ } // If we've received anything in the nRF24L01+... = sword if ( nordic.readable() ) { char rxData[TRANSFER_SIZE]; // ...read the data into the receive buffer rxDataCnt = nordic.read( NRF24L01P_PIPE_P0, rxData, TRANSFER_SIZE ); //Get data and convert to mouse x,y and key entry // 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 int8_t dx = rxData[0]; // change in x int8_t dy = rxData[1]; // change in y bool mode_stat = (rxData[2] >> 7) & 1; // checking flag bits bool joy_but = (rxData[2] >> 6) & 1; bool def_stat = (rxData[2] >> 5) & 1; bool attack_stat = (rxData[2] >> 4) & 1; bool key_w = (rxData[2] >> 3) & 1; bool key_s = (rxData[2] >> 2) & 1; bool key_d = (rxData[2] >> 1) & 1; bool key_a = (rxData[2] >> 0) & 1; bool roll = (rxData[3] >> 0) & 1; #if(BASE == 1) // Only if base station MK.move(dy, dx); // move mouse relative if(joy_but) // do keyboard events MK.putc(' '); if(attack_stat) { MK.press(MOUSE_LEFT); mouse1 = true; } if(!attack_stat && mouse1) { MK.release(MOUSE_LEFT); mouse1 = false; } if(key_a) // move left { MK.press(MOUSE_RIGHT); mouse2 = true; } if(!key_a && mouse2) { MK.release(MOUSE_RIGHT); mouse2 = false; } if(key_d) // move right { MK.press(MOUSE_MIDDLE); mouse3 = true; } if(!key_d && mouse3) { MK.release(MOUSE_MIDDLE); mouse3 = false; } // mouse 4, 5 have issues on windows if(key_w) // move forward { //MK.press(16); // mouse5 //mouse5 = true; MK.putc('w'); } /*if(!key_w && mouse5) { MK.release(16); mouse5 = false; }*/ if(key_s) // move backward { //MK.press(8); // mouse4 //mouse4 = true; MK.putc('s'); } /*if(!key_s && mouse4) { MK.release(8); mouse4 = false; }*/ // Single push commands if(def_stat) MK.putc('d'); if(mode_stat) { MK.putc('1'+mode_count); mode_count = (mode_count+1)%3; } if(roll) MK.putc('r'); #endif //pc.printf("x: %d y: %d \r\n",dx,dy); // Display the receive buffer contents via the host serial link /*for ( int i = 0; i < TRANSFER_SIZE; i++ ) { pc.putc( rxData[i] ); }*/ } } // sword else{ int ATTACKVAL = ATTACK.read_u16(); // attack FSR int SELECTVAL = SELECT.read_u16(); // mode/defense FSR int XJOYVAL = XJOY.read_u16(); // joystick x int YJOYVAL = YJOY.read_u16(); // joystick y int JOYSELVAL = (int) JOYSEL; // joystick select value // if joystick push/pulled all the way on axis, do roll/move faster in direction //bool roll = ((XJOYVAL > 64000) || (XJOYVAL < 1000) || (YJOYVAL > 64000) || (YJOYVAL < 1000)) ? true: 0; // Disable backward roll due to lack of continuous MOUSE buttons bool roll = ((XJOYVAL > 64000) || (XJOYVAL < 1000) || (YJOYVAL > 64000)) ? true: 0; // thresholding bool mode_stat = (SELECTVAL > 45000) ? true: 0; // 1, 2, 3 rotated (defense/mode FSR pressed all the way) bool joy_but = JOYSEL == 0? true: 0; bool def_stat = (SELECTVAL > 10000 && SELECTVAL < 45000) ? true: 0; // defend if defense/mode FSR slightly pressed bool attack_stat = ATTACKVAL > 10000? true: 0; // attack if attack FSR pressed bool key_d = XJOYVAL > 35000 ? true: 0; // if joystick moves in direction, direction key should be pressed bool key_a = XJOYVAL < 30000 ? true : 0; bool key_w = YJOYVAL > 35000 ? true: 0; bool key_s = YJOYVAL < 30000 ? true: 0; // turn on motor at start of attack if (attack_stat == true) attackflag = true; if (attackflag == true){ if (motorCycle < 250){ motorCycle++; motor.write(0.40f); // 40% duty cycle, relative to period } else { motorCycle = 0; attackflag = false; motor.write(0.00f); } } // make byte 2 of packet 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; //pc.printf("F1: %d \t F2: %d \t X: %d \t Y: %d \t SEL: %d \r\n", ATTACKVAL, SELECTVAL, XJOYVAL, YJOYVAL, JOYSELVAL); // Let serial read catch up on base station/PC side wait_us(150); char swordData[TRANSFER_SIZE]; Acc_GetXY(); // Get X, Y acceleration mouse_x = x; // x, y assigned in prev function mouse_y = y; char lowX = char(mouse_x & 0x00FF); // only use lowest 8 bits of data char lowY = char(mouse_y & 0x00FF); //pc.printf("x: %f \t y: %f \r\n", mouse_x,mouse_y); // left A, right D, back S, up W // MSB -- LSB send packet swordData[0] = lowX; swordData[1] = lowY; swordData[2] = char(key_stat); swordData[3] = char(roll); // cast bool into char // Send the transmitbuffer via the nRF24L01+ nordic.write( NRF24L01P_PIPE_P0, swordData, TRANSFER_SIZE ); // If we've received anything from base station if ( nordic.readable() ) { greenLED = !greenLED; char rxData[TRANSFER_SIZE]; // ...read the data into the receive buffer rxDataCnt = nordic.read( NRF24L01P_PIPE_P0, rxData, TRANSFER_SIZE ); #if DEBUG == 1 // Display the receive buffer contents via the host serial link for ( int i = 0; i < TRANSFER_SIZE; i++ ) { pc.putc( rxData[i] ); } #endif // From PC, only need (zero padded) 1 bit flag indicating if hit // In first byte motorON = (rxData[0] >> 0) & 1; // Motor ON when sword contact made if (motorON) motorOnFlag = true; } // if flag to turn motor on sent, run motor for a little while and then stop // period not extended if another motor on command sent in the middle of the count } } } // perform initial accelerometer calibration to zero stuff void Calibrate(void) { unsigned int count1; count1 = 0; float sstatex = 0; float sstatey = 0; do{ sstatex += acc.getAccX(); // Accumulate Samples sstatey += acc.getAccY(); count1++; }while(count1!=0x0400); // 1024 times x_b = sstatex/1024.0; // division between 1024 y_b = sstatey/1024.0; } // remove offset from calibration + scale for sensitivity when getting accelerometer data void Acc_GetXY(void) { x = (int16_t)((acc.getAccX()- x_b)*SCALING); y = (int16_t)((acc.getAccY()- y_b)*SCALING); } /* Processing code //sikuli-java.jar needed to keep track of HP/score for rumble + serial RX/TX import org.sikuli.script.*; import processing.serial.*; Serial myPort; // Serial port int lastTime = 0; // Time counter Region myHPReg = new Region(1,1,500,500); // HP watch regions x, y, w, h Region otherHPReg = new Region(500,500,500,500); // Specify event handler for detecting changes class hpChangeClass implements SikuliEventObserver { @Override void targetChanged(SikuliEventChange evnt1) { println( "changed!" ); for (int i = 0; i <100; i++){ myPort.write(3); // Rumble motor (LSB high) } //lastTime++; } void targetAppeared(SikuliEventAppear evnt2) { println("test"); } void targetVanished(SikuliEventVanish evnt3) { println("test"); } } hpChangeClass regionChange = new hpChangeClass(); void setup(){ size(1,1); // Don't care (out of focus) myPort = new Serial(this, "/dev/tty.usbmodem1422", 9600); // Serial setup myPort.clear(); //lastTime = millis(); myHPReg.highlight(5); // Show regions watched for 5 seconds otherHPReg.highlight(5); myHPReg.onChange(10, regionChange); // num of pixels for change detection, event handler myHPReg.observeInBackground((int)Float.POSITIVE_INFINITY); // watch forever otherHPReg.onChange(10, regionChange); // num of pixels for change detection, event handler otherHPReg.observeInBackground((int)Float.POSITIVE_INFINITY); // watch forever } void draw() { Wait if ( millis() - lastTime > 5000 ) { myPort.write(68); lastTime = millis(); } } */