v1 Stable
Dependencies: F401RE-USBHost USBHostXpad mbed
Diff: main.cpp
- Revision:
- 6:21365f733399
- Parent:
- 5:32c8b316582a
- Child:
- 7:65d1a7a3948b
--- a/main.cpp Mon Dec 12 01:07:48 2016 +0000 +++ b/main.cpp Mon Dec 26 01:23:55 2016 +0000 @@ -1,5 +1,3 @@ -//TODO: save controller layout to sram - #include "mbed.h" #include "USBHostXpad.h" #include "stm32f4xx_flash.h" @@ -26,7 +24,6 @@ @param LB - given as a 1 @param R - given as a 2 @param X - given as a 4 - */ uint8_t XLBRB=0x0; @@ -104,7 +101,10 @@ @brief makes the range of the triggers 0 to 10 */ const float tN=0.03921568627;//(10/255) -const int DEADZONE = 3; +const int dead_zone = 20; +const int joy_range = 100; +//const int DEADZONE = 5; +const int TRIGGER_THRESHOLD = 5; char reverse(char b) { @@ -114,7 +114,33 @@ return b; } +enum STATE {NORMAL=0, DPAD_UP, DPAD_DOWN, DPAD_LEFT, DPAD_RIGHT, BUTTON_START, BUTTON_B, BUTTON_A, C_UP, C_DOWN, C_LEFT, C_RIGHT, BUTTON_L, BUTTON_R, BUTTON_Z}; +enum XPAD_BUTTON {XPAD_DUP, XPAD_DDOWN, XPAD_DLEFT, XPAD_DRIGHT, XPAD_X, XPAD_Y, XPAD_A, XPAD_B, XPAD_LB, XPAD_RB, XPAD_LT, XPAD_RT, XPAD_BACK, XPAD_START, XPAD_LAB, XPAD_RAB}; + +uint8_t state = NORMAL; +bool XpadButtonPressed = false; + +const uint64_t A_MASK = 0x00001000, + B_MASK = 0x00002000, + X_MASK = 0x00004000, + Y_MASK = 0x00008000, + LB_MASK = 0x00000100, + RB_MASK = 0x00000200, + START_MASK = 0x00000010, + BACK_MASK = 0x00000020, + LAB_MASK = 0x00000040, + RAB_MASK = 0x00000080, + DUP_MASK = 0x00000001, + DDOWN_MASK = 0x00000002, + DLEFT_MASK = 0x00000004, + DRIGHT_MASK = 0x00000008, + // the next two masks are special extensions to support triggers + LT_MASK = 0x00010000, + RT_MASK = 0x00020000; + extern "C" void my_wait_us_asm (int n); +void LoadControls(); +void SaveControls(); struct __attribute__((packed)) N64ControllerData // all bits are in the correct order... except for the analog { @@ -129,7 +155,7 @@ unsigned int dummy1 : 1; unsigned int dummy2 : 1; - unsigned int l :1 ; + unsigned int l : 1; unsigned int r : 1; unsigned int c_up : 1; unsigned int c_down : 1; @@ -142,6 +168,222 @@ } n64_data; +struct __attribute__((packed)) XpadControls +{ + uint64_t a; + uint64_t b; + uint64_t z; + uint64_t start; + uint64_t up; + uint64_t down; + uint64_t left; + uint64_t right; + uint64_t l; + uint64_t r; + uint64_t c_up; + uint64_t c_down; + uint64_t c_left; + uint64_t c_right; + + XpadControls() + { + LoadControls(); + } + + void PrintControls() + { + pc.printf("The mask for a is: 0x%X\r\n",a); + pc.printf("The mask for start is: 0x%X\r\n",start); + } +} xpc; + +const int SAVE_ADDR = 0x0800C000; // sector 3 +XpadControls* saveData = (XpadControls*)SAVE_ADDR; + +// linear search, find first button pressed +// if the user pressed 2 buttons, its the user's fault +uint64_t DetectButton() +{ + if(AXYB != 0) + { + if(AXYB & 0x01) // a + { + return A_MASK; + } + else if((AXYB >> 1) & 0x01) // b + { + return B_MASK; + } + else if((AXYB >> 2) & 0x01) // x + { + return X_MASK; + } + else if((AXYB >> 3) & 0x01) // y + { + return Y_MASK; + } + } + else if(XLBRB != 0) + { + if((XLBRB >> 1) & 0x01) // right bumper + { + return RB_MASK; + } + else if(XLBRB & 0x01) // left bumper + { + return LB_MASK; + } + // the Xbox ("X") button is ignored in this firmware + } + else if(bkStrtLCRC != 0) + { + if(bkStrtLCRC & 0x01) // start + { + return START_MASK; + } + else if(bkStrtLCRC & 0x02) // back + { + return BACK_MASK; + } + else if(bkStrtLCRC & 0x04) // L analog button + { + return LAB_MASK; + } + else if(bkStrtLCRC & 0x08) // R analog button + { + return RAB_MASK; + } + } + else if(DPad != 0) + { + if(DPad & 0x01) // DPad Up + { + return DUP_MASK; + } + else if(DPad & 0x02) // DPad Down + { + return DDOWN_MASK; + } + else if(DPad & 0x04) // DPad Left + { + return DLEFT_MASK; + } + else if(DPad & 0x08) // DPad Right + { + return DRIGHT_MASK; + } + } + else if(Lt > TRIGGER_THRESHOLD) + { + return LT_MASK; + } + else if(Rt > TRIGGER_THRESHOLD) + { + return RT_MASK; + } + + return 0; // no button was pressed +} + +void ChangeButtonMapping(uint64_t bt) +{ + // analog settings must be hardcoded, cannot change on the fly + + if(state == DPAD_UP) // state = 1 --> dpad up + { + xpc.up = bt; + } + else if(state == DPAD_DOWN) // state = 2 --> dpad down + { + xpc.down = bt; + } + else if(state == DPAD_LEFT) // state = 3 --> dpad left + { + xpc.left = bt; + } + else if(state == DPAD_RIGHT) // state = 4 --> dpad right + { + xpc.right = bt; + } + else if(state == BUTTON_START) // state = 5 --> start + { + xpc.start = bt; + } + else if(state == BUTTON_B) // state = 6 --> B + { + xpc.b = bt; + } + else if(state == BUTTON_A) // state = 7 --> A + { + xpc.a = bt; + } + else if(state == C_UP) // state = 8 --> c up + { + xpc.c_up = bt; + } + else if(state == C_DOWN) // state = 9 --> c down + { + xpc.c_down = bt; + } + else if(state == C_LEFT) // state = 10 --> c left + { + xpc.c_left = bt; + } + else if(state == C_RIGHT) // state = 11 --> c right + { + xpc.c_right = bt; + } + else if(state == BUTTON_L) // state = 12 --> L + { + xpc.l = bt; + } + else if(state == BUTTON_R) // state = 13 --> R + { + xpc.r = bt; + } + else if(state == BUTTON_Z) // state = 14 --> Z + { + xpc.z = bt; + } +} + +void SaveControls() +{ + FLASH_Unlock(); //unlock flash writing + FLASH_ClearFlag(FLASH_FLAG_EOP | FLASH_FLAG_OPERR | FLASH_FLAG_WRPERR | + FLASH_FLAG_PGAERR | FLASH_FLAG_PGPERR|FLASH_FLAG_PGSERR); + FLASH_EraseSector(FLASH_Sector_3,VoltageRange_3); // 0x0800C000 - 0x0800FFFF + + uint32_t* data = (uint32_t*)&xpc; + + // Total size is 112 bytes + // Each word is 4 bytes, so the total size is 28 words + // Note: ProgramDoubleWord requires a higher voltage, so we must do one word at a time + for(int ct = 0;ct < 28;ct++) + { + FLASH_ProgramWord(SAVE_ADDR+(ct*4),*data); //each SAVE_ADDR+4 is 4 bytes because it is a memory address + data++; // each data+1 is 4 bytes because it is a 32 bit data type + } + + FLASH_Lock(); // lock it back up +} + +void LoadControls() +{ + memcpy(&xpc,saveData,sizeof(XpadControls)); + pc.printf("Controls have been loaded!\r\n"); +} + +void AdvanceState() +{ + state++; + if(state >= 15) // we're done mapping the controls + { + SaveControls(); // write directly to flash + state = NORMAL; // back to normal controller operation + } +} + void onXpadEvent (int buttons, int stick_lx, int stick_ly, int stick_rx, int stick_ry, int trigger_l, int trigger_r) { AXYB=buttons>>12; @@ -152,8 +394,8 @@ //pc.printf("AXYB: %u, XLBRB, %u, bkStrtLCRC %u, DPad, %u\r\n",AXYB,XLBRB,bkStrtLCRC,DPad); // normalize the analog stick values to be 80 max - LSY=(char)((int)(stick_ly*sN)); - LSX=(char)((int)(stick_lx*sN)); + //LSY=(char)((int)(stick_ly*sN)); + //LSX=(char)((int)(stick_lx*sN)); RSY=stick_ry*sN; RSX=stick_rx*sN; @@ -161,188 +403,148 @@ Lt=trigger_l*tN; Rt=trigger_r*tN; - memset(&n64_data,0,4); // clear controller state - - // Owna's Controls - if(AXYB & 0x01) // a - { - n64_data.a = 1; - } - if((AXYB >> 2) & 0x01) // x - { - n64_data.b = 1; - } - if((AXYB >> 1) & 0x01) // b - { - n64_data.z = 1; - } - if((AXYB >> 3) & 0x01) // y - { - n64_data.c_up = 1; - } - if(bkStrtLCRC & 0x01) // start - { - n64_data.start = 1; - } - if((XLBRB >> 1) & 0x01) // right bumper - { - n64_data.r = 1; - } - if(XLBRB & 0x01) // left bumper - { - n64_data.l = 1; - } - - // Supa's Controls - /*if(AXYB & 0x01) // a - { - n64_data.a = 1; - } - if((AXYB >> 2) & 0x01) // x - { - n64_data.b = 1; - } - if((AXYB >> 1) & 0x01) // b + if(state == 0) { - n64_data.c_down = 1; - } - if((AXYB >> 3) & 0x01) // y - { - n64_data.z = 1; - } - if(bkStrtLCRC & 0x01) // start - { - n64_data.start = 1; - } - if((XLBRB >> 1) & 0x01) // right bumper - { - n64_data.r = 1; - } - if(XLBRB & 0x01) // left bumper - { - n64_data.l = 1; - } - if(DPad & 0x01) // DPad Up - { - n64_data.c_up = 1; - } - if(DPad & 0x02) // DPad Down - { - n64_data.c_down = 1; - } - if(DPad & 0x04) // DPad Left - { - n64_data.c_left = 1; - } - if(DPad & 0x08) // DPad Right - { - n64_data.c_right = 1; - }*/ - - // LD's Controls - /*if(AXYB & 0x01) // a - { - n64_data.a = 1; - } - if((AXYB >> 2) & 0x01) // x - { - n64_data.b = 1; - } - if((AXYB >> 3) & 0x01) // y - { - n64_data.c_up = 1; + memset(&n64_data,0,4); // clear controller state + + uint64_t buttons_and_triggers = buttons; + + if(Lt > TRIGGER_THRESHOLD) + { + buttons_and_triggers |= LT_MASK; + } + if(Rt > TRIGGER_THRESHOLD) + { + buttons_and_triggers |= RT_MASK; + } + + if(buttons_and_triggers & xpc.up) + { + n64_data.up = 1; + } + if(buttons_and_triggers & xpc.down) + { + n64_data.down = 1; + } + if(buttons_and_triggers & xpc.left) + { + n64_data.left = 1; + } + if(buttons_and_triggers & xpc.right) + { + n64_data.right = 1; + } + if(buttons_and_triggers & xpc.c_up) + { + n64_data.c_up = 1; + } + if(buttons_and_triggers & xpc.c_down) + { + n64_data.c_down = 1; + } + if(buttons_and_triggers & xpc.c_left) + { + n64_data.c_left = 1; + } + if(buttons_and_triggers & xpc.c_right) + { + n64_data.c_right = 1; + } + if(buttons_and_triggers & xpc.l) + { + n64_data.l = 1; + } + if(buttons_and_triggers & xpc.r) + { + n64_data.r = 1; + } + if(buttons_and_triggers & xpc.z) + { + n64_data.z = 1; + } + if(buttons_and_triggers & xpc.a) + { + n64_data.a = 1; + } + if(buttons_and_triggers & xpc.b) + { + n64_data.b = 1; + } + if(buttons_and_triggers & xpc.start) + { + n64_data.start = 1; + } + + // LD code, val is the x_axis value from -32k to +32k + // seems pretty inefficient but hopefully its fast enough + int val = stick_lx; + float X1_norm; + if(val > 0) + { + X1_norm = val / 32767.f; + X1_norm = (X1_norm - dead_zone / 100.0) * 100.0 / (100.0 - dead_zone); + if (X1_norm < 0) X1_norm = 0; + + char ans = (char)(127 * X1_norm * joy_range / 100); + n64_data.x_axis = reverse(ans); + } + else + { + X1_norm = val / 32768.f; + X1_norm = (X1_norm + dead_zone / 100.0) * 100.0 / (100.0 - dead_zone); + if (X1_norm > 0) X1_norm = 0; + + char ans = (char)(128 * X1_norm * joy_range / 100); + n64_data.x_axis = reverse(ans); + } + + // repeat for y values + val = stick_ly; + if(val > 0) + { + X1_norm = val / 32767.f; + X1_norm = (X1_norm - dead_zone / 100.0) * 100.0 / (100.0 - dead_zone); + if (X1_norm < 0) X1_norm = 0; + + char ans = (char)(127 * X1_norm * joy_range / 100); + n64_data.y_axis = reverse(ans); + } + else + { + X1_norm = val / 32768.f; + X1_norm = (X1_norm + dead_zone / 100.0) * 100.0 / (100.0 - dead_zone); + if (X1_norm > 0) X1_norm = 0; + + char ans = (char)(128 * X1_norm * joy_range / 100); + n64_data.y_axis = reverse(ans); + } + + // Generic analog stick + /*if(LSX > DEADZONE) + { + n64_data.x_axis = reverse(LSX); + } + if(LSY > DEADZONE) + { + n64_data.y_axis = reverse(LSY); + }*/ } - if(bkStrtLCRC & 0x01) // start - { - n64_data.start = 1; - } - if((XLBRB >> 1) & 0x01) // right bumper - { - n64_data.r = 1; - } - if(XLBRB & 0x01) // left bumper - { - n64_data.l = 1; - } - if(DPad & 0x01) // DPad Up - { - n64_data.c_up = 1; - } - if(DPad & 0x02) // DPad Down - { - n64_data.c_down = 1; - } - if(DPad & 0x04) // DPad Left - { - n64_data.c_left = 1; - } - if(DPad & 0x08) // DPad Right - { - n64_data.c_right = 1; - } - if(Rt > 5) // Right trigger greater than threshold - { - n64_data.z = 1; - }*/ - - // JJ's Controls - /*if(AXYB & 0x01) // a - { - n64_data.a = 1; - } - if((AXYB >> 2) & 0x01) // x - { - n64_data.b = 1; - } - if((AXYB >> 3) & 0x01) // y + else // state > 0 so we are in the process of changing controls { - n64_data.c_left = 1; - } - if((AXYB >> 1) & 0x01) // b - { - n64_data.c_right = 1; - } - if(bkStrtLCRC & 0x01) // start - { - n64_data.start = 1; - } - if((XLBRB >> 1) & 0x01) // right bumper - { - n64_data.r = 1; - } - if(XLBRB & 0x01) // left bumper - { - n64_data.z = 1; - } - if(DPad & 0x01) // DPad Up - { - n64_data.up = 1; - } - if(DPad & 0x02) // DPad Down - { - n64_data.down = 1; - } - if(DPad & 0x04) // DPad Left - { - n64_data.left = 1; - } - if(DPad & 0x08) // DPad Right - { - n64_data.right = 1; - } - if(Lt > 2 || Rt > 2) // Triggers greater than threshold - { - n64_data.z = 1; - }*/ - - // Generic analog stick - if(LSX > DEADZONE) - { - n64_data.x_axis = reverse(LSX); - } - if(LSY > DEADZONE) - { - n64_data.y_axis = reverse(LSY); + uint64_t b = DetectButton(); // read for button presses (just do linear search) + if(b != 0) /*button was actually is pressed*/ + { + if(XpadButtonPressed == false) + { + XpadButtonPressed = true; + ChangeButtonMapping(b); + AdvanceState(); + } + } + else + { + XpadButtonPressed = false; + } } } @@ -472,7 +674,7 @@ int main() { - //Timer t; + bool buttonPressed = false; pc.printf("\r\nNow loaded! SystemCoreClock = %d Hz\r\n", SystemCoreClock); @@ -486,40 +688,79 @@ while(1) { - //t.start(); - // Set pin mode to input - data.input(); - - USBHost::poll(); - - __disable_irq(); // Disable Interrupts - // Read 64 command - unsigned int cmd = readCommand(); - - my_wait_us_asm(2); // wait a small amount of time before replying - - //-------- SEND RESPONSE - // Set pin mode to output - data.output(); - - switch(cmd) + if(state == NORMAL) { - case 0x00: // identity - case 0xFF: // reset - SendIdentity(); - break; - case 0x01: // poll for state - SendControllerData(); - break; - default: - // we do not process the read and write commands (memory pack) - break; + if(!button) // user wants to change controls + { + if(!buttonPressed) // make sure it's a separate button press + { + buttonPressed = true; + state++; + continue; + } + } + else + { + buttonPressed = false; + } + + // Set pin mode to input + data.input(); + + USBHost::poll(); + + __disable_irq(); // Disable Interrupts + + // Read 64 command + unsigned int cmd = readCommand(); + + my_wait_us_asm(2); // wait a small amount of time before replying + + //-------- SEND RESPONSE + // Set pin mode to output + data.output(); + + switch(cmd) + { + case 0x00: // identity + case 0xFF: // reset + SendIdentity(); + break; + case 0x01: // poll for state + SendControllerData(); + break; + default: + // we do not process the read and write commands (memory pack) + break; + } + __enable_irq(); // Enable Interrupts + //-------- DONE SENDING RESPOSE } - __enable_irq(); // Enable Interrupts - //-------- DONE SENDING RESPOSE - - //t.stop(); - pc.printf("Time: %d\r\n",t.read_us()); - //t.reset(); + else + { + if(!button) // user wants to cancel and return to regular mode + { + if(!buttonPressed) // make sure it's a separate button press + { + state++; + buttonPressed = true; + continue; + } + } + else + { + buttonPressed = false; + } + + myled = !myled; + USBHost::poll(); + wait(0.1); + + if(state == NORMAL) // about to return to normal operation, make sure the LED remains off + { + myled = false; + XpadButtonPressed = false; + } + } } }