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();
  }

}

*/