This is the first rev of HW3 for IDD
Dependencies: MMA8451Q USBDevice mbed nRF24L01P
main.cpp
- Committer:
- shunshou
- Date:
- 2014-09-29
- Revision:
- 3:99ed0483f868
- Parent:
- 2:c3b748d86642
- Child:
- 4:7012a2af25f6
File content as of revision 3:99ed0483f868:
//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.80f); // 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();
}
}
*/