first release for keyboard
Dependencies: F401RE-USBHost2 mbed
Diff: main.cpp
- Revision:
- 2:77b20c9b1933
- Parent:
- 1:3c21da72660d
- Child:
- 4:dbb0d3d2ad8b
--- a/main.cpp Mon Oct 31 19:26:40 2016 +0000 +++ b/main.cpp Wed Dec 28 23:22:18 2016 +0000 @@ -1,12 +1,23 @@ -//TODO: save controller layout to sram -// finish and make 100% functional for keyboard players -// duplicate program and modify to work with x360 +// TODO: work off controler 3.3v if possible #include "mbed.h" #include "USBHostKeyboard.h" +#include "stm32f4xx_flash.h" + +DigitalOut myled(LED1); +Serial pc(USBTX, USBRX); // tx, rx +DigitalInOut data(PA_8); +DigitalIn button(PC_13); // eventually code to set controls extern "C" void my_wait_us_asm (int n); +enum STATE {NORMAL=0, A_UP, A_DOWN, A_LEFT, A_RIGHT, 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}; +uint8_t state = NORMAL; //done remapping when >= 19 + +bool KeyboardButtonPressed = false; +void LoadControls(); +void SaveControls(); + struct __attribute__((packed)) N64ControllerData // all bits are in the correct order { unsigned int a : 1; // 1 bit wide @@ -33,29 +44,85 @@ } n64_data; -const uint8_t KEYBOARD_a = 0x0E; -const uint8_t KEYBOARD_b = 0x0D; -const uint8_t KEYBOARD_z = 0x0F; -const uint8_t KEYBOARD_start = 0x0B; -const uint8_t KEYBOARD_d_up = 0x1D; -const uint8_t KEYBOARD_d_down = 0x1B; -const uint8_t KEYBOARD_d_left = 0x06; -const uint8_t KEYBOARD_d_right = 0x19; -const uint8_t KEYBOARD_l = 0x1A; -const uint8_t KEYBOARD_r = 0x12; -const uint8_t KEYBOARD_c_up = 0x17; -const uint8_t KEYBOARD_c_down = 0x1C; -const uint8_t KEYBOARD_c_left = 0x18; -const uint8_t KEYBOARD_c_right = 0x0C; -const uint8_t KEYBOARD_a_up = 0x08; -const uint8_t KEYBOARD_a_down = 0x07; -const uint8_t KEYBOARD_a_left = 0x16; -const uint8_t KEYBOARD_a_right = 0x09; +struct __attribute__((packed)) KeyboardControls +{ + uint8_t KEYBOARD_a; + uint8_t KEYBOARD_b; + uint8_t KEYBOARD_z; + uint8_t KEYBOARD_start; + + uint8_t KEYBOARD_d_up; + uint8_t KEYBOARD_d_down; + uint8_t KEYBOARD_d_left; + uint8_t KEYBOARD_d_right; + + uint8_t KEYBOARD_l; + uint8_t KEYBOARD_r; + uint8_t KEYBOARD_c_up; + uint8_t KEYBOARD_c_down; + + uint8_t KEYBOARD_c_left; + uint8_t KEYBOARD_c_right; + uint8_t KEYBOARD_a_up; + uint8_t KEYBOARD_a_down; + + uint8_t KEYBOARD_a_left; + uint8_t KEYBOARD_a_right; + + KeyboardControls() + { + LoadDefault(); + } + + void LoadDefault() + { + KEYBOARD_a = 0x0E; + KEYBOARD_b = 0x0D; + KEYBOARD_z = 0x0F; + KEYBOARD_start = 0x0B; + KEYBOARD_d_up = 0x1D; + KEYBOARD_d_down = 0x1B; + KEYBOARD_d_left = 0x06; + KEYBOARD_d_right = 0x19; + KEYBOARD_l = 0x1A; + KEYBOARD_r = 0x12; + KEYBOARD_c_up = 0x17; + KEYBOARD_c_down = 0x1C; + KEYBOARD_c_left = 0x18; + KEYBOARD_c_right = 0x0C; + KEYBOARD_a_up = 0x08; + KEYBOARD_a_down = 0x07; + KEYBOARD_a_left = 0x16; + KEYBOARD_a_right = 0x09; + } + + void LoadBlank() + { + KEYBOARD_a = 0x00; + KEYBOARD_b = 0x00; + KEYBOARD_z = 0x00; + KEYBOARD_start = 0x00; + KEYBOARD_d_up = 0x00; + KEYBOARD_d_down = 0x00; + KEYBOARD_d_left = 0x00; + KEYBOARD_d_right = 0x00; + KEYBOARD_l = 0x00; + KEYBOARD_r = 0x00; + KEYBOARD_c_up = 0x00; + KEYBOARD_c_down = 0x00; + KEYBOARD_c_left = 0x00; + KEYBOARD_c_right = 0x00; + KEYBOARD_a_up = 0x00; + KEYBOARD_a_down = 0x00; + KEYBOARD_a_left = 0x00; + KEYBOARD_a_right = 0x00; + } +}; -DigitalOut myled(LED1); -Serial pc(USBTX, USBRX); // tx, rx -DigitalInOut data(PA_8); -//DigitalIn button(PC_13); // eventually code to set controlls +KeyboardControls kc; + +const int SAVE_ADDR = 0x0800C000; // sector 3 +KeyboardControls* saveData = (KeyboardControls*)SAVE_ADDR; // 0 is 3 microseconds low followed by 1 microsecond high // 1 is 1 microsecond low followed by 3 microseconds high @@ -181,93 +248,279 @@ SendStop(); } -// keyboard buttons are stored in cells 2 3 4 5 6 7? cell 0 and 1 are modifiers? cell8 is an F? -// the buttons all become 1 if overflow, i think. or in short, [2] == [3] +char reverse(char b) +{ + b = (b & 0xF0) >> 4 | (b & 0x0F) << 4; + b = (b & 0xCC) >> 2 | (b & 0x33) << 2; + b = (b & 0xAA) >> 1 | (b & 0x55) << 1; + return b; +} + +void ChangeButtonMapping(uint8_t bt) +{ + // analog settings must be hardcoded, cannot change on the fly + if(state == A_UP) // state = 1 --> analog up + { + kc.KEYBOARD_a_up = bt; + } + else if(state == A_DOWN) // state = 2 --> analog up + { + kc.KEYBOARD_a_down = bt; + } + else if(state == A_LEFT) // state = 3 --> analog up + { + kc.KEYBOARD_a_left = bt; + } + else if(state == A_RIGHT) // state = 4 --> analog up + { + kc.KEYBOARD_a_right = bt; + } + else if(state == DPAD_UP) // state = 5 --> dpad up + { + kc.KEYBOARD_d_up = bt; + } + else if(state == DPAD_DOWN) // state = 6 --> dpad down + { + kc.KEYBOARD_d_down = bt; + } + else if(state == DPAD_LEFT) // state = 7 --> dpad left + { + kc.KEYBOARD_d_left = bt; + } + else if(state == DPAD_RIGHT) // state = 8 --> dpad right + { + kc.KEYBOARD_d_right = bt; + } + else if(state == BUTTON_START) // state = 9 --> start + { + kc.KEYBOARD_start = bt; + } + else if(state == BUTTON_B) // state = 10 --> B + { + kc.KEYBOARD_b = bt; + } + else if(state == BUTTON_A) // state = 11 --> A + { + kc.KEYBOARD_a = bt; + } + else if(state == C_UP) // state = 12 --> c up + { + kc.KEYBOARD_c_up = bt; + } + else if(state == C_DOWN) // state = 13 --> c down + { + kc.KEYBOARD_c_down = bt; + } + else if(state == C_LEFT) // state = 14 --> c left + { + kc.KEYBOARD_c_left = bt; + } + else if(state == C_RIGHT) // state = 15 --> c right + { + kc.KEYBOARD_c_right = bt; + } + else if(state == BUTTON_L) // state = 16 --> L + { + kc.KEYBOARD_l = bt; + } + else if(state == BUTTON_R) // state = 17 --> R + { + kc.KEYBOARD_r = bt; + } + else if(state == BUTTON_Z) // state = 18 --> Z + { + kc.KEYBOARD_z = bt; + } +} + +void AdvanceState() +{ + state++; + if(state >= 19) // we're done mapping the controls + { + SaveControls(); // write directly to flash + state = NORMAL; // back to normal controller operation + } +} + void onKeyboardEvent(uint8_t rep[9]) { - /*printf("Report = ["); - for(int i = 0;i < 8;i++) - { - printf("%X, ", rep[i]); - } - printf("%X]\r\n", rep[8]);*/ + // the buttons all become 1 if overflow, i think. or in short, [2] == [3] + if(rep[2] == rep[3] && rep[2] == 1) + return; - memset(&n64_data,0,4); // clear controller state - - bool leaveLoop = false; - - for(int index = 2;index < 8;index++) + if(state == NORMAL) { - switch(rep[index]) // the key code + memset(&n64_data,0,4); // clear controller state + + // keyboard buttons are stored in cells 2 3 4 5 6 7? cell 0 and 1 are modifiers? cell8 is an F? + for(int index = 2;index < 8;index++) { - case 0: // no more keys to process - leaveLoop = true; - break; - case KEYBOARD_a: - n64_data.a = 1; - break; - case KEYBOARD_b: - n64_data.b = 1; - break; - case KEYBOARD_z: - n64_data.z = 1; - break; - case KEYBOARD_start: - n64_data.start = 1; - break; - case KEYBOARD_d_up: - n64_data.up = 1; - break; - case KEYBOARD_d_down: - n64_data.down = 1; - break; - case KEYBOARD_d_left: - n64_data.left = 1; + if(rep[index] == 0) // no more keys to process + { break; - case KEYBOARD_d_right: + } + if(rep[index] == kc.KEYBOARD_a) + { + n64_data.a = 1; + continue; + } + if(rep[index] == kc.KEYBOARD_b) + { + n64_data.b = 1; + continue; + } + if(rep[index] == kc.KEYBOARD_z) + { + n64_data.z = 1; + continue; + } + if(rep[index] == kc.KEYBOARD_start) + { + n64_data.start = 1; + continue; + } + if(rep[index] == kc.KEYBOARD_d_up) + { + n64_data.up = 1; + continue; + } + if(rep[index] == kc.KEYBOARD_d_down) + { + n64_data.down = 1; + continue; + } + if(rep[index] == kc.KEYBOARD_d_left) + { + n64_data.left = 1; + continue; + } + if(rep[index] == kc.KEYBOARD_d_right) + { n64_data.right = 1; - break; - case KEYBOARD_l: + continue; + } + if(rep[index] == kc.KEYBOARD_l) + { n64_data.l = 1; - break; - case KEYBOARD_r: + continue; + } + if(rep[index] == kc.KEYBOARD_r) + { n64_data.r = 1; - break; - case KEYBOARD_c_up: + continue; + } + if(rep[index] == kc.KEYBOARD_c_up) + { n64_data.c_up = 1; - break; - case KEYBOARD_c_down: + continue; + } + if(rep[index] == kc.KEYBOARD_c_down) + { n64_data.c_down = 1; - break; - case KEYBOARD_c_left: + continue; + } + if(rep[index] == kc.KEYBOARD_c_left) + { n64_data.c_left = 1; - break; - case KEYBOARD_c_right: + continue; + } + if(rep[index] == kc.KEYBOARD_c_right) + { n64_data.c_right = 1; - break; + continue; + } // NOTE: THESE BITS MUST BE WRITTEN IN REVERSE ORDER. HIGH BIT IS IN THE LOW POSITION - case KEYBOARD_a_up: - n64_data.y_axis = 0x0A; - break; - case KEYBOARD_a_down: - n64_data.y_axis = 0x0D; - break; - case KEYBOARD_a_left: + if(rep[index] == kc.KEYBOARD_a_up) + { + n64_data.y_axis = 0x0A; // 80(dec) bit reversed + continue; + } + if(rep[index] == kc.KEYBOARD_a_down) + { + n64_data.y_axis = 0x0D; // -80(dec) bit reversed + continue; + } + if(rep[index] == kc.KEYBOARD_a_left) + { n64_data.x_axis = 0x0D; - break; - case KEYBOARD_a_right: + continue; + } + if(rep[index] == kc.KEYBOARD_a_right) + { n64_data.x_axis = 0x0A; - break; + continue; + } + } + } + else // state > 0 so we are in the process of changing controls + { + uint8_t b = rep[2]; // read for button presses (just take first pressed if many are pressed) + if(b != 0) /*button was actually is pressed*/ + { + if(KeyboardButtonPressed == false) + { + KeyboardButtonPressed = true; + ChangeButtonMapping(b); + AdvanceState(); + } + } + else + { + KeyboardButtonPressed = false; } + } +} + +void PrintBytes(char *ptr, int numBytes) +{ + pc.printf("["); + for(int i=0;i < numBytes;i++) + { + pc.printf(" %X ",*ptr); + ptr++; + } + pc.printf("]\r\n"); +} + +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*)&kc; + + // total size is 18 bytes + // Note: ProgramDoubleWord requires a higher voltage + FLASH_ProgramWord(SAVE_ADDR,*data); // write word 1 (4 bytes) + data++; + FLASH_ProgramWord(SAVE_ADDR+0x04,*data); // write word 2 (4 bytes) + data++; + FLASH_ProgramWord(SAVE_ADDR+0x08,*data); // write word 3 (4 bytes) + data++; + FLASH_ProgramWord(SAVE_ADDR+0x0C,*data); // write word 4 (4 bytes) + data++; + FLASH_ProgramHalfWord(SAVE_ADDR+0x10,*data); // write final half word (2 bytes) - if(leaveLoop) break; - } + FLASH_Lock(); // lock it back up +} + + + +void LoadControls() +{ + memcpy(&kc,saveData,sizeof(KeyboardControls)); + pc.printf("Controls have been loaded!\r\n"); } int main() { - pc.printf("Now loaded! SystemCoreClock = %d Hz\r\n", SystemCoreClock); - memset(&n64_data,0,4); // start controller in the neutral state + bool buttonPressed = false; + + pc.printf("\r\nNow loaded! SystemCoreClock = %d Hz\r\n", SystemCoreClock); + LoadControls(); USBHostKeyboard kb; if (!kb.connect()) { @@ -278,36 +531,79 @@ while(1) { - // Set pin mode to input - data.input(); - - // Read keyboard state? - 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 + else + { + if(!button) // user wants to cancel and return to regular mode + { + if(!buttonPressed) // make sure it's a separate button press + { + state = NORMAL; + 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; + KeyboardButtonPressed = false; + } + } } }