summaryrefslogtreecommitdiff
path: root/fw/hid-dials/Src/main.c
diff options
context:
space:
mode:
Diffstat (limited to 'fw/hid-dials/Src/main.c')
-rw-r--r--fw/hid-dials/Src/main.c465
1 files changed, 465 insertions, 0 deletions
diff --git a/fw/hid-dials/Src/main.c b/fw/hid-dials/Src/main.c
new file mode 100644
index 0000000..4ccbca0
--- /dev/null
+++ b/fw/hid-dials/Src/main.c
@@ -0,0 +1,465 @@
+
+#include <stdbool.h>
+
+#include "main.h"
+#include "usb_device.h"
+#include "usbd_hid.h"
+
+#define HID_MEDIA_REPORT 2
+#define HYSTERESIS 200
+
+ADC_HandleTypeDef hadc;
+DMA_HandleTypeDef hdma_adc;
+
+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 {
+ /* 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);
+
+struct key_t
+{
+ uint8_t id;
+ uint8_t modifier;
+ uint8_t reserved;
+ uint8_t keycode[6];
+} key;
+
+uint16_t ADCreg[8];
+uint16_t ADCval[8];
+uint16_t ADClast[8];
+
+/* FIXME debug remove */
+TIM_TypeDef *tim1 = TIM1;
+TIM_TypeDef *tim3 = TIM3;
+
+int main(void)
+{
+ HAL_Init();
+
+ SystemClock_Config();
+
+ MX_GPIO_Init();
+ MX_USB_HID_INIT();
+
+ __HAL_RCC_TIM1_CLK_ENABLE();
+ __HAL_RCC_TIM3_CLK_ENABLE();
+
+ TIM1->SMCR = 3; // Encoder mode 3
+ TIM1->CCER = 0; // rising edge polarity
+ TIM1->ARR = 0xFFFF; // count from 0-ARR or ARR-0
+ TIM1->CCMR1 = 0x0101; // f_DTS/16, N=8, IC1->TI1, IC2->TI2
+ TIM1->CNT = 0; // Initialize counter
+ TIM1->EGR = 1; // Generate an update event
+ TIM1->CR1 = 1; // Enable the counter
+
+ TIM3->SMCR = 3; // Encoder mode 3
+ TIM3->CCER = 0; // rising edge polarity
+ TIM3->ARR = 0xFFFF; // count from 0-ARR or ARR-0
+ TIM3->CCMR1 = 0x0101; // f_DTS/16, N=8, IC1->TI1, IC2->TI2
+ TIM3->CNT = 0; // Initialize counter
+ TIM3->EGR = 1; // Generate an update event
+ TIM3->CR1 = 1; // Enable the counter
+
+ while (1) {
+ 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);
+
+ /* Gang both encoders */
+ vol_delta += tim3_delta - tim1_delta;
+
+#define VOL_DELTA_INC 4
+ 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;
+ }
+ } 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] =
+{
+ 0x00, // NUL
+ 0x00, // SOH
+ 0x00, // STX
+ 0x00, // ETX
+ 0x00, // EOT
+ 0x00, // ENQ
+ 0x00, // ACK
+ 0x00, // BEL
+ 0x2a, // BS Backspace
+ 0x2b, // TAB Tab
+ 0x28, // LF Enter
+ 0x00, // VT
+ 0x00, // FF
+ 0x00, // CR
+ 0x00, // SO
+ 0x00, // SI
+ 0x00, // DEL
+ 0x00, // DC1
+ 0x00, // DC2
+ 0x00, // DC3
+ 0x00, // DC4
+ 0x00, // NAK
+ 0x00, // SYN
+ 0x00, // ETB
+ 0x00, // CAN
+ 0x00, // EM
+ 0x00, // SUB
+ 0x00, // ESC
+ 0x00, // FS
+ 0x00, // GS
+ 0x00, // RS
+ 0x00, // US
+
+ 0x2c, // ' '
+ 0x1e|0x80, // !
+ 0x34|0x80, // "
+ 0x20|0x80, // #
+ 0x21|0x80, // $
+ 0x22|0x80, // %
+ 0x24|0x80, // &
+ 0x34, // '
+ 0x26|0x80, // (
+ 0x27|0x80, // )
+ 0x25|0x80, // *
+ 0x2e|0x80, // +
+ 0x36, // ,
+ 0x2d, // -
+ 0x37, // .
+ 0x38, // /
+ 0x27, // 0
+ 0x1e, // 1
+ 0x1f, // 2
+ 0x20, // 3
+ 0x21, // 4
+ 0x22, // 5
+ 0x23, // 6
+ 0x24, // 7
+ 0x25, // 8
+ 0x26, // 9
+ 0x33|0x80, // :
+ 0x33, // ;
+ 0x36|0x80, // <
+ 0x2e, // =
+ 0x37|0x80, // >
+ 0x38|0x80, // ?
+ 0x1f|0x80, // @
+ 0x04|0x80, // A
+ 0x05|0x80, // B
+ 0x06|0x80, // C
+ 0x07|0x80, // D
+ 0x08|0x80, // E
+ 0x09|0x80, // F
+ 0x0a|0x80, // G
+ 0x0b|0x80, // H
+ 0x0c|0x80, // I
+ 0x0d|0x80, // J
+ 0x0e|0x80, // K
+ 0x0f|0x80, // L
+ 0x10|0x80, // M
+ 0x11|0x80, // N
+ 0x12|0x80, // O
+ 0x13|0x80, // P
+ 0x14|0x80, // Q
+ 0x15|0x80, // R
+ 0x16|0x80, // S
+ 0x17|0x80, // T
+ 0x18|0x80, // U
+ 0x19|0x80, // V
+ 0x1a|0x80, // W
+ 0x1b|0x80, // X
+ 0x1c|0x80, // Y
+ 0x1d|0x80, // Z
+ 0x2f, // [
+ 0x31, // bslash
+ 0x30, // ]
+ 0x23|0x80, // ^
+ 0x2d|0x80, // _
+ 0x35, // `
+ 0x04, // a
+ 0x05, // b
+ 0x06, // c
+ 0x07, // d
+ 0x08, // e
+ 0x09, // f
+ 0x0a, // g
+ 0x0b, // h
+ 0x0c, // i
+ 0x0d, // j
+ 0x0e, // k
+ 0x0f, // l
+ 0x10, // m
+ 0x11, // n
+ 0x12, // o
+ 0x13, // p
+ 0x14, // q
+ 0x15, // r
+ 0x16, // s
+ 0x17, // t
+ 0x18, // u
+ 0x19, // v
+ 0x1a, // w
+ 0x1b, // x
+ 0x1c, // y
+ 0x1d, // z
+ 0x2f|0x80, // {
+ 0x31|0x80, // |
+ 0x30|0x80, // }
+ 0x35|0x80, // ~
+ 0 // DEL
+};
+
+
+void sendChar(uint8_t ch){
+ if( ch > 128 ) ch -=128;
+
+ key.id = 1;
+ key.keycode[0]=_asciimap[ch]&0x7F;
+ key.keycode[1]=0;
+
+ if ( _asciimap[ch] & 0x80) key.modifier |= 0x02;
+
+ for(int i=0; i< 4;i++){
+ USBD_HID_SendReport(&hUsbDeviceFS, (uint8_t *)&key, sizeof(key));
+ HAL_Delay(10);
+ }
+ memset(key.keycode, 0 , sizeof(key.keycode));
+ key.modifier = 0;
+ USBD_HID_SendReport(&hUsbDeviceFS, (uint8_t *)&key, sizeof(key));
+ HAL_Delay(10);
+}
+
+void sendCharWrong(uint8_t ch){
+ key.id = 1;
+ key.keycode[0]=ch&0x7F;
+ key.keycode[1]=0;
+
+ if ( _asciimap[ch] & 0x80) key.modifier |= 0x02;
+
+ for(int i=0; i< 4;i++){
+ USBD_HID_SendReport(&hUsbDeviceFS, (uint8_t *)&key, sizeof(key));
+ HAL_Delay(10);
+ }
+ memset(key.keycode, 0 , sizeof(key.keycode));
+ key.modifier = 0;
+ USBD_HID_SendReport(&hUsbDeviceFS, (uint8_t *)&key, sizeof(key));
+ HAL_Delay(10);
+}
+
+void sendKeybits(uint8_t keybits){
+ uint8_t report[2];
+ report[0]= HID_MEDIA_REPORT;
+ report[1]= keybits;
+ USBD_HID_SendReport(&hUsbDeviceFS, report, 2);
+}
+
+void SystemClock_Config(void)
+{
+ RCC_OscInitTypeDef RCC_OscInitStruct = {0};
+ RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
+ RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};
+
+ RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI14|RCC_OSCILLATORTYPE_HSI48;
+ RCC_OscInitStruct.HSI48State = RCC_HSI48_ON;
+ RCC_OscInitStruct.HSI14State = RCC_HSI14_ON;
+ RCC_OscInitStruct.HSI14CalibrationValue = 16;
+ RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
+ HAL_RCC_OscConfig(&RCC_OscInitStruct);
+
+ RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
+ |RCC_CLOCKTYPE_PCLK1;
+ RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI48;
+ RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
+ RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
+ HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_1);
+
+ PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USB;
+ PeriphClkInit.UsbClockSelection = RCC_USBCLKSOURCE_HSI48;
+ HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit);
+
+}
+
+static void MX_GPIO_Init(void) {
+ __HAL_RCC_GPIOB_CLK_ENABLE();
+ __HAL_RCC_GPIOA_CLK_ENABLE();
+
+ /* 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){
+ HAL_GPIO_WritePin(GPIOB,GPIO_PIN_13,1);
+ HAL_Delay(100);
+ HAL_GPIO_WritePin(GPIOB,GPIO_PIN_13,0);
+ HAL_Delay(100);
+ }
+}
+