v1 Stable

Dependencies:   F401RE-USBHost USBHostXpad mbed

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;
+            }
+        }
     }
 }