From 1e6e8a2062923b434b2f4f5f2a9f8c0098135b01 Mon Sep 17 00:00:00 2001
From: jaseg <git-bigdata-wsl-arch@jaseg.de>
Date: Sun, 28 Jun 2020 16:09:04 +0200
Subject: hid fw working as intended

---
 hid-dials/Src/main.c | 197 +++++++++++++++++++++++++++++++++++++++++++--------
 1 file changed, 167 insertions(+), 30 deletions(-)

(limited to 'hid-dials')

diff --git a/hid-dials/Src/main.c b/hid-dials/Src/main.c
index 0aa694f..4ccbca0 100644
--- a/hid-dials/Src/main.c
+++ b/hid-dials/Src/main.c
@@ -15,10 +15,38 @@ PCD_HandleTypeDef hpcd_USB_FS;
 
 void SystemClock_Config(void);
 static void MX_GPIO_Init(void);
+static void key_matrix_select(int row);
+static int key_matrix_query(int debounce_time);
+static uint32_t poll_encoders(void);
+static uint32_t poll_keys(void);
 
 enum keybits {
-    KEYBITS_VOL_UP = 0x20,
-    KEYBITS_VOL_DOWN = 0x40,
+    /* These match up with the record descriptor in usbd_hid.c */
+    KEYBITS_NEXT        = 0x01,
+    KEYBITS_PREV        = 0x02,
+    KEYBITS_STOP        = 0x04,
+    KEYBITS_PLAY_PAUSE  = 0x08,
+    KEYBITS_MUTE        = 0x10,
+    KEYBITS_VOL_UP      = 0x20,
+    KEYBITS_VOL_DOWN    = 0x40,
+};
+
+enum key_names {
+    KEY_2   = 0,
+    KEY_3   = 1,
+    KEY_1   = 2,
+    KEY_ENC = 3,
+    KEY_4   = 4
+};
+
+enum keymap_rows {
+    KEYMAP_BOTTOM_LEFT_ENC = 0,
+    KEYMAP_TOP_RIGHT_ENC = 1,
+};
+
+enum key_matrix_params {
+    KEY_MATRIX_ROWS = 5,
+    KEY_MATRIX_COLS = 2,
 };
 
 void sendKeybits(uint8_t keybits);
@@ -67,39 +95,69 @@ int main(void)
     TIM3->EGR = 1;           // Generate an update event
     TIM3->CR1 = 1;           // Enable the counter
 
-    uint16_t tim1_last = TIM1->CNT, tim3_last = TIM3->CNT;
-    int vol_delta = 0;
-    bool tx_vol_reset = 0;
     while (1) {
-        uint16_t tim1_now = TIM1->CNT, tim3_now = TIM3->CNT;
-        int16_t tim1_delta = (int16_t)(tim1_now - tim1_last);
-        int16_t tim3_delta = (int16_t)(tim3_now - tim3_last);
+        uint32_t keybits = poll_encoders();
+        for (int i=0; i<10; i++) {
+            keybits |= poll_keys();
+            HAL_Delay(1);
+        }
+        sendKeybits(keybits);
+    }
+}
+
+static uint32_t poll_encoders() {
+    static bool tx_vol_reset = 0;
+    static uint16_t tim1_last = 0, tim3_last = 0; /* timers init to 0 */
+    static int vol_delta = 0;
+
+    uint16_t tim1_now = TIM1->CNT, tim3_now = TIM3->CNT;
+    int16_t tim1_delta = (int16_t)(tim1_now - tim1_last);
+    int16_t tim3_delta = (int16_t)(tim3_now - tim3_last);
 
-        vol_delta += tim3_delta - tim1_delta;
+    /* Gang both encoders */
+    vol_delta += tim3_delta - tim1_delta;
 
 #define VOL_DELTA_INC 4
-        uint8_t keybits = 0;
-        if (!tx_vol_reset) {
-            if (vol_delta >= VOL_DELTA_INC) {
-                keybits |= KEYBITS_VOL_UP;
-                vol_delta -= VOL_DELTA_INC;
-                tx_vol_reset = 1;
-            } else if (vol_delta <= -VOL_DELTA_INC) {
-                keybits |= KEYBITS_VOL_DOWN;
-                vol_delta += VOL_DELTA_INC;
-                tx_vol_reset = 1;
-            }
-        } else {
-            tx_vol_reset = 0;
+    uint8_t keybits = 0;
+    if (!tx_vol_reset) {
+        /* Customize encoder action here */
+        if (vol_delta >= VOL_DELTA_INC) {
+            keybits |= KEYBITS_VOL_UP;
+            vol_delta -= VOL_DELTA_INC;
+            tx_vol_reset = 1;
+        } else if (vol_delta <= -VOL_DELTA_INC) {
+            keybits |= KEYBITS_VOL_DOWN;
+            vol_delta += VOL_DELTA_INC;
+            tx_vol_reset = 1;
         }
-        sendKeybits(keybits);
-
-        tim1_last = tim1_now;
-        tim3_last = tim3_now;
-        HAL_Delay(10);
+    } else {
+        tx_vol_reset = 0;
     }
+
+    tim1_last = tim1_now;
+    tim3_last = tim3_now;
+    return keybits;
 }
 
+static uint32_t poll_keys() {
+    int debounce_time = 5; /* 5 * 10 ms loop timing increments */
+    uint32_t val = key_matrix_query(debounce_time);
+    uint32_t state = val&0xffff, edges = val>>16;
+    uint32_t pressed = state & edges;
+    (void)edges; /* unused */
+    uint32_t keybits = 0;
+
+    if (pressed & (1 << KEY_3))
+        keybits |= KEYBITS_PLAY_PAUSE;
+    if (pressed & (1 << KEY_3 << KEY_MATRIX_ROWS))
+        keybits |= KEYBITS_PREV;
+    if (pressed & (1 << KEY_4 << KEY_MATRIX_ROWS))
+        keybits |= KEYBITS_NEXT;
+    if (pressed & (1 << KEY_ENC << KEY_MATRIX_ROWS))
+        keybits |= KEYBITS_MUTE;
+
+    return keybits;
+}
 
 const uint8_t _asciimap[128] =
 {
@@ -308,14 +366,93 @@ static void MX_GPIO_Init(void) {
     __HAL_RCC_GPIOB_CLK_ENABLE();
     __HAL_RCC_GPIOA_CLK_ENABLE();
 
-    GPIOA->MODER = 0x28000000 | (2<<(8*2)) | (2<<(9*2));
-    GPIOB->MODER =              (2<<(4*2)) | (2<<(5*2));
-    GPIOA->PUPDR = 0x24000000 | (1<<(8*2)) | (1<<(9*2));
+    /* Left  encoder (SW2) A/B inputs: PA9/PA8 (TIM1 CH1/2)
+     * Right encoder (SW7) A/B inputs: PB4/PB5 (TIM3 CH1/2)
+     * Key matrix:  PB2  -> encoder switches left/right
+     *              PB8  -> SW3/8
+     *              PB1  -> SW4/9
+     *              PA15 -> SW5/10
+     *              PA0  -> SW6/11
+     *              key matrix inputs: PA1/PA4
+     *
+     * Physical key layout:
+     *
+     * +------------|USB|------------+
+     * | SW9     SW11    SW10    SW8 |
+     * |     SW2             SW7     |
+     * | SW4     SW6     SW5     SW3 |
+     * +-----------------------------+
+     *
+     * Logical key layout:
+     *
+     * +------------|USB|------------+
+     * |  KT1    KT2     KT3    KT4  |
+     * |      EL             ER      |
+     * |  KB1    KB2     KB3    KB4  |
+     * +-----------------------------+
+     *
+     */
+    GPIOA->MODER = 0x28000000 | (2<<(8*2)) | (2<<(9*2)) | (1<<(15*2))| (1<<(0*2));
+    GPIOB->MODER =              (2<<(4*2)) | (2<<(5*2)) | (1<<(1*2)) | (1<<(2*2)) | (1<<(8*2));
+    GPIOA->PUPDR = 0x24000000 | (1<<(8*2)) | (1<<(9*2)) | (2<<(1*2)) | (2<<(4*2));
     GPIOB->PUPDR =              (1<<(4*2)) | (1<<(5*2));
     GPIOA->AFR[1]=              0x00000022;
     GPIOB->AFR[0]=              0x00110000;
 }
 
+static void key_matrix_select(int row) {
+    uint16_t bsrr_a = 0, bsrr_b = 0;
+    /* A0 -> A15 -> B1 -> B2 -> B8 */
+    switch (row) {
+        case 0: bsrr_a = 1<<0; break;
+        case 1: bsrr_a = 1<<15; break;
+        case 2: bsrr_b = 1<<1; break;
+        case 3: bsrr_b = 1<<2; break;
+        case 4: bsrr_b = 1<<8; break;
+    }
+    uint16_t mask_a = (1<<15) | (1<<0), mask_b = (1<<1) | (1<<2) | (1<<8);
+    /* Reset all pins except for selected pin */
+    GPIOA->BSRR = (mask_a<<16) ^ ((bsrr_a<<16) | bsrr_a) ;
+    GPIOB->BSRR = (mask_b<<16) ^ ((bsrr_b<<16) | bsrr_b) ;
+}
+
+static int key_matrix_query(int debounce_time) {
+    static int debounce_states[KEY_MATRIX_COLS][KEY_MATRIX_ROWS] = {0};
+    static int key_matrix_row = -1;
+    static uint32_t matrix_state = 0;
+    uint32_t matrix_state_edges = 0;
+    if (key_matrix_row < 0) { /* On first iteration just set outputs and return */
+        key_matrix_row = 0;
+        key_matrix_select(0);
+        return 0;
+    }
+
+    int input = GPIOA->IDR;
+    int pressed[KEY_MATRIX_COLS] = { input & (1<<4), input & (1<<1) };
+    for (int i=0; i<KEY_MATRIX_COLS; i++) {
+        if (debounce_states[i][key_matrix_row] > 0) {
+            /* debounce timer running */
+            debounce_states[i][key_matrix_row]--;
+        } else {
+            uint32_t bit = 1 << key_matrix_row << (KEY_MATRIX_ROWS * i); 
+            uint32_t old_matrix_state = matrix_state;
+            if (pressed[i])
+                matrix_state |= bit;
+            else
+                matrix_state &= ~bit;
+
+            uint32_t edge = old_matrix_state ^ matrix_state;
+            if (edge)
+                debounce_states[i][key_matrix_row] = debounce_time;
+            matrix_state_edges |= edge;
+        }
+    }
+
+    key_matrix_row = (key_matrix_row+1) % KEY_MATRIX_ROWS;
+    key_matrix_select(key_matrix_row);
+    return (matrix_state_edges<<16) | matrix_state;
+}
+
 void Error_Handler(void)
 {
     while(1){
-- 
cgit