xwhatsit keyboards: attempt to enable solenoid. To be tested by people with solenoid.
[jackhill/qmk/firmware.git] / keyboards / xwhatsit / matrix.c
index 5409a61..310c78c 100644 (file)
 #define CAPSENSE_SHIFT_STCP_IO _SFR_IO_ADDR(PORTC)
 #define CAPSENSE_SHIFT_STCP_BIT 7
 
+#define CAPSENSE_READ_ROWS_NUMBER_OF_BYTES_PER_SAMPLE 2
 #define CAPSENSE_READ_ROWS_PIN_1 _SFR_IO_ADDR(PIND)
 #define CAPSENSE_READ_ROWS_PIN_2 _SFR_IO_ADDR(PIND)
 #define CAPSENSE_READ_ROWS_ASM_INSTRUCTIONS "in %[dest_row_1], %[ioreg_row_1]\n\tin %[dest_row_2], %[ioreg_row_2]"
+#define CAPSENSE_READ_ROWS_STORE_TO_ARRAY_INSTRUCTIONS \
+    "st %a[arr]+, %[dest_row_1]"       "\n\t" \
+    "st %a[arr]+, %[dest_row_2]"
+#define CAPSENSE_READ_ROWS_STORE_TO_ARRAY_INSTRUCTIONS_FAKE \
+    "st %a[arr], %[dest_row_1]"       "\n\t" \
+    "st %a[arr], %[dest_row_2]"
 #define CAPSENSE_READ_ROWS_OUTPUT_CONSTRAINTS [dest_row_1] "=&r" (dest_row_1), [dest_row_2] "=&r" (dest_row_2)
 #define CAPSENSE_READ_ROWS_INPUT_CONSTRAINTS [ioreg_row_1] "I" (CAPSENSE_READ_ROWS_PIN_1), [ioreg_row_2] "I" (CAPSENSE_READ_ROWS_PIN_2)
 #define CAPSENSE_READ_ROWS_LOCAL_VARS uint8_t dest_row_1, dest_row_2
 #define CAPSENSE_READ_ROWS_VALUE (dest_row_1 & 0xf)
+#define CAPSENSE_READ_ROWS_EXTRACT_FROM_ARRAY do { dest_row_1 = array[p0++]; dest_row_2 = array[p0++]; } while (0)
+
 // Note: for now Beamspring reads PIND twice to match model F timings. We might change that in the future
 
 #define CAPSENSE_KEYMAP_ROW_TO_PHYSICAL_ROW(row) (row)
@@ -45,6 +54,7 @@
 #ifndef CAPSENSE_KEYMAP_COL_TO_PHYSICAL_COL
 #define CAPSENSE_KEYMAP_COL_TO_PHYSICAL_COL(col) (col)
 #endif
+
 #define CAPSENSE_CONDUCTIVE_PLASTIC_IS_PULLED_UP_ON_KEYPRESS
 
 #elif defined(CONTROLLER_IS_XWHATSIT_MODEL_F_OR_WCASS_MODEL_F)
 #define CAPSENSE_SHIFT_STCP_IO _SFR_IO_ADDR(PORTD)
 #define CAPSENSE_SHIFT_STCP_BIT 6
 
+#define CAPSENSE_READ_ROWS_NUMBER_OF_BYTES_PER_SAMPLE 2
 #define CAPSENSE_READ_ROWS_PIN_1 _SFR_IO_ADDR(PINC)
 #define CAPSENSE_READ_ROWS_PIN_2 _SFR_IO_ADDR(PIND)
 #define CAPSENSE_READ_ROWS_ASM_INSTRUCTIONS "in %[dest_row_1], %[ioreg_row_1]\n\tin %[dest_row_2], %[ioreg_row_2]"
+#define CAPSENSE_READ_ROWS_STORE_TO_ARRAY_INSTRUCTIONS \
+    "st %a[arr]+, %[dest_row_1]"       "\n\t" \
+    "st %a[arr]+, %[dest_row_2]"
+#define CAPSENSE_READ_ROWS_STORE_TO_ARRAY_INSTRUCTIONS_FAKE \
+    "st %a[arr], %[dest_row_1]"       "\n\t" \
+    "st %a[arr], %[dest_row_2]"
 #define CAPSENSE_READ_ROWS_OUTPUT_CONSTRAINTS [dest_row_1] "=&r" (dest_row_1), [dest_row_2] "=&r" (dest_row_2)
 #define CAPSENSE_READ_ROWS_INPUT_CONSTRAINTS [ioreg_row_1] "I" (CAPSENSE_READ_ROWS_PIN_1), [ioreg_row_2] "I" (CAPSENSE_READ_ROWS_PIN_2)
 #define CAPSENSE_READ_ROWS_LOCAL_VARS uint8_t dest_row_1, dest_row_2
 #define CAPSENSE_READ_ROWS_VALUE ((dest_row_1 >> 4) | (dest_row_2 << 4))
+#define CAPSENSE_READ_ROWS_EXTRACT_FROM_ARRAY do { dest_row_1 = array[p0++]; dest_row_2 = array[p0++]; } while (0)
 
 #define CAPSENSE_KEYMAP_ROW_TO_PHYSICAL_ROW(row) (7-(row))
 #define CAPSENSE_PHYSICAL_ROW_TO_KEYMAP_ROW(row) (7-(row))
 #ifndef CAPSENSE_KEYMAP_COL_TO_PHYSICAL_COL
 #define CAPSENSE_KEYMAP_COL_TO_PHYSICAL_COL(col) (col)
 #endif
+
 #define CAPSENSE_CONDUCTIVE_PLASTIC_IS_PUSHED_DOWN_ON_KEYPRESS
 
-#elif defined(CONTROLLER_IS_THROUGHT_HOLE_BEAMSPRING)
+#elif defined(CONTROLLER_IS_THROUGHT_HOLE_BEAMSPRING) || defined(CONTROLLER_IS_THROUGHT_HOLE_MODEL_F)
 
 #define CAPSENSE_DAC_MCP4921
 #define CAPSENSE_DAC_NCS F6
 #define CAPSENSE_SHIFT_STCP_IO _SFR_IO_ADDR(PORTF)
 #define CAPSENSE_SHIFT_STCP_BIT 7
 
-
-// TODO
 // Rows:
 // Physical position from left to right: (only the right-most are used for beamspring)
 // 1    2    3    4    5    6    7    8
 // TH schematic numbering (sense/row lines)
 // 8    6    7    5    4    3    2    1
 // F5,  B5,  F4,  B4,  D4,  C6,  D1,  D0
+
+#if MATRIX_ROWS <= 4
+#define CAPSENSE_READ_ROWS_NUMBER_OF_BYTES_PER_SAMPLE 2
 #define CAPSENSE_READ_ROWS_PIN_1 _SFR_IO_ADDR(PINC)
 #define CAPSENSE_READ_ROWS_PIN_2 _SFR_IO_ADDR(PIND)
 #define CAPSENSE_READ_ROWS_ASM_INSTRUCTIONS "in %[dest_row_1], %[ioreg_row_1]\n\tin %[dest_row_2], %[ioreg_row_2]"
+#define CAPSENSE_READ_ROWS_STORE_TO_ARRAY_INSTRUCTIONS \
+    "st %a[arr]+, %[dest_row_1]"       "\n\t" \
+    "st %a[arr]+, %[dest_row_2]"
+#define CAPSENSE_READ_ROWS_STORE_TO_ARRAY_INSTRUCTIONS_FAKE \
+    "st %a[arr], %[dest_row_1]"       "\n\t" \
+    "st %a[arr], %[dest_row_2]"
 #define CAPSENSE_READ_ROWS_OUTPUT_CONSTRAINTS [dest_row_1] "=&r" (dest_row_1), [dest_row_2] "=&r" (dest_row_2)
 #define CAPSENSE_READ_ROWS_INPUT_CONSTRAINTS [ioreg_row_1] "I" (CAPSENSE_READ_ROWS_PIN_1), [ioreg_row_2] "I" (CAPSENSE_READ_ROWS_PIN_2)
 #define CAPSENSE_READ_ROWS_LOCAL_VARS uint8_t dest_row_1, dest_row_2
 #define CAPSENSE_READ_ROWS_VALUE (((dest_row_1 >> 4) & 0x04) | (dest_row_2 & 0x03) | ((dest_row_2 >> 1) & 0x08))
+#define CAPSENSE_READ_ROWS_EXTRACT_FROM_ARRAY do { dest_row_1 = array[p0++]; dest_row_2 = array[p0++]; } while (0)
+#else
+#define CAPSENSE_READ_ROWS_NUMBER_OF_BYTES_PER_SAMPLE 4
+#define CAPSENSE_READ_ROWS_PIN_1 _SFR_IO_ADDR(PINC)
+#define CAPSENSE_READ_ROWS_PIN_2 _SFR_IO_ADDR(PIND)
+#define CAPSENSE_READ_ROWS_PIN_3 _SFR_IO_ADDR(PINB)
+#define CAPSENSE_READ_ROWS_PIN_4 _SFR_IO_ADDR(PINF)
+#define CAPSENSE_READ_ROWS_ASM_INSTRUCTIONS "in %[dest_row_1], %[ioreg_row_1]\n\tin %[dest_row_2], %[ioreg_row_2]\n\tin %[dest_row_3], %[ioreg_row_3]\n\tin %[dest_row_4], %[ioreg_row_4]"
+#define CAPSENSE_READ_ROWS_STORE_TO_ARRAY_INSTRUCTIONS \
+    "st %a[arr]+, %[dest_row_1]"       "\n\t" \
+    "st %a[arr]+, %[dest_row_2]"       "\n\t" \
+    "st %a[arr]+, %[dest_row_3]"       "\n\t" \
+    "st %a[arr]+, %[dest_row_4]"
+#define CAPSENSE_READ_ROWS_STORE_TO_ARRAY_INSTRUCTIONS_FAKE \
+    "st %a[arr], %[dest_row_1]"       "\n\t" \
+    "st %a[arr], %[dest_row_2]"       "\n\t" \
+    "st %a[arr], %[dest_row_3]"       "\n\t" \
+    "st %a[arr], %[dest_row_4]"
+#define CAPSENSE_READ_ROWS_OUTPUT_CONSTRAINTS [dest_row_1] "=&r" (dest_row_1), [dest_row_2] "=&r" (dest_row_2), [dest_row_3] "=&r" (dest_row_3), [dest_row_4] "=&r" (dest_row_4)
+#define CAPSENSE_READ_ROWS_INPUT_CONSTRAINTS [ioreg_row_1] "I" (CAPSENSE_READ_ROWS_PIN_1), [ioreg_row_2] "I" (CAPSENSE_READ_ROWS_PIN_2), [ioreg_row_3] "I" (CAPSENSE_READ_ROWS_PIN_3), [ioreg_row_4] "I" (CAPSENSE_READ_ROWS_PIN_4)
+#define CAPSENSE_READ_ROWS_LOCAL_VARS uint8_t dest_row_1, dest_row_2, dest_row_3, dest_row_4
+#define CAPSENSE_READ_ROWS_VALUE (((dest_row_1 >> 4) & 0x04) | (dest_row_2 & 0x03) | ((dest_row_2 >> 1) & 0x08) | (dest_row_3 & 0x10) | ((dest_row_3 << 1) & 0x40) | ((dest_row_4 << 1) & 0x20) | ((dest_row_4 << 2) & 0x80))
+#define CAPSENSE_READ_ROWS_EXTRACT_FROM_ARRAY do { dest_row_1 = array[p0++]; dest_row_2 = array[p0++]; dest_row_3 = array[p0++]; dest_row_4 = array[p0++]; } while (0)
+#endif
 
-#define CAPSENSE_KEYMAP_ROW_TO_PHYSICAL_ROW(row) (3-(row))
-#define CAPSENSE_PHYSICAL_ROW_TO_KEYMAP_ROW(row) (3-(row))
+#define CAPSENSE_KEYMAP_ROW_TO_PHYSICAL_ROW(row) (MATRIX_ROWS-1-(row))
+#define CAPSENSE_PHYSICAL_ROW_TO_KEYMAP_ROW(row) (MATRIX_ROWS-1-(row))
 #ifndef CAPSENSE_KEYMAP_COL_TO_PHYSICAL_COL
 #define CAPSENSE_KEYMAP_COL_TO_PHYSICAL_COL(col) (col)
 #endif
-//#define CAPSENSE_CONDUCTIVE_PLASTIC_IS_PUSHED_DOWN_ON_KEYPRESS
+
+#if defined(CONTROLLER_IS_THROUGHT_HOLE_BEAMSPRING)
 #define CAPSENSE_CONDUCTIVE_PLASTIC_IS_PULLED_UP_ON_KEYPRESS
-// TODO END
+#else
+#define CAPSENSE_CONDUCTIVE_PLASTIC_IS_PUSHED_DOWN_ON_KEYPRESS
+#endif
 
 #else
 
 #error "Please specify whether the flyplate is pushed down or pulled up on keypress!"
 #endif
 
+/* Notes on Expansion Header:
+
+Pinout:
+--1--O   O--2--
+--3--O   O--4--
+--5--O   O--6--
+
+Pin 1 is always VCC
+Pin 6 in always GND
+
+When using xwhatsit's solenoid controller board,
+pin 2 is connected to the ENABLE input of the current
+limiter, and pin 4 drives the solenoid.
+
+On original xwhatsit controllers:
+pin 2 = PB7
+pin 3 = PB4
+pin 4 = PB6
+pin 5 = PB5
+
+On the TH xwhatsit controller:
+pin 2 = HEADER3 = TXO        = PD3
+pin 3 = HEADER1 = D(igital)6 = PD7
+pin 4 = HEADER4 = RXI        = PD2
+pin 5 = HEADER2 = D(igital)7 = PE6
+*/
+
+#ifdef USING_SOLENOID_ENABLE_PIN
+// ^^ this must be defined in config.h if you are using and xwhatsit type solenoid
+#endif
+
+
 static inline uint8_t read_rows(void)
 {
     CAPSENSE_READ_ROWS_LOCAL_VARS;
@@ -249,6 +334,20 @@ void shift_select_nothing(void)
     writePin(CAPSENSE_SHIFT_STCP, 0);
 }
 
+void shift_data(uint32_t data)
+{
+    int i;
+    for (i=SHIFT_BITS-1; i>=0; i--)
+    {
+        writePin(CAPSENSE_SHIFT_DIN, (data >> (SHIFT_BITS - 1)) & 1);
+        writePin(CAPSENSE_SHIFT_SHCP, 1);
+        writePin(CAPSENSE_SHIFT_SHCP, 0);
+        data <<= 1;
+    }
+    writePin(CAPSENSE_SHIFT_STCP, 1);
+    writePin(CAPSENSE_SHIFT_STCP, 0);
+}
+
 void shift_select_col_no_strobe(uint8_t col)
 {
     int i;
@@ -279,7 +378,21 @@ void shift_init(void)
     wait_us(CAPSENSE_KEYBOARD_SETTLE_TIME_US);
 }
 
-// the following function requires storage for 2 * (time + 1) bytes
+// Timing:
+// IN instructions (1 * CAPSENSE_READ_ROWS_NUMBER_OF_BYTES_PER_SAMPLE)
+// Store to array instructions (2 * number of bytes)
+// adiw: 1 cycle
+// cp: 1 cycle
+// cpc: 1 cycle
+// brlo: 2 cycles (when jumping)
+// --- Total loop length:
+// 3 * CAPSENSE_READ_ROWS_NUMBER_OF_BYTES_PER_SAMPLE + 5 cycles
+// first sample elements will be taken after [1..CAPSENSE_READ_ROWS_NUMBER_OF_BYTES_PER_SAMPLE-1] cycles
+// second sample elements will be taken after
+//       [3 * CAPSENSE_READ_ROWS_NUMBER_OF_BYTES_PER_SAMPLE + 5 + 1..
+//        3 * CAPSENSE_READ_ROWS_NUMBER_OF_BYTES_PER_SAMPLE + 5 + CAPSENSE_READ_ROWS_NUMBER_OF_BYTES_PER_SAMPLE-1] cycles
+
+// the following function requires storage for CAPSENSE_READ_ROWS_NUMBER_OF_BYTES_PER_SAMPLE * (time + 1) bytes
 // but returns valid data only in the first (time + 1) bytes
 void test_multiple(uint8_t col, uint16_t time, uint8_t *array)
 {
@@ -292,9 +405,8 @@ void test_multiple(uint8_t col, uint16_t time, uint8_t *array)
              "ldi %B[index], 0"                 "\n\t"
              "cli"                              "\n\t"
              "sbi %[stcp_regaddr], %[stcp_bit]" "\n\t"
-        "1:" CAPSENSE_READ_ROWS_ASM_INSTRUCTIONS         "\n\t"
-             "st %a[arr]+, %[dest_row_1]"       "\n\t"
-             "st %a[arr]+, %[dest_row_2]"       "\n\t"
+        "1:" CAPSENSE_READ_ROWS_ASM_INSTRUCTIONS            "\n\t"
+             CAPSENSE_READ_ROWS_STORE_TO_ARRAY_INSTRUCTIONS "\n\t"
              "adiw %A[index], 0x01"             "\n\t"
              "cp %A[index], %A[time]"           "\n\t"
              "cpc %B[index], %B[time]"          "\n\t"
@@ -314,8 +426,7 @@ void test_multiple(uint8_t col, uint16_t time, uint8_t *array)
     p0 = p1 = 0;
     for (i=0; i<=time; i++)
     {
-        dest_row_1 = array[p0++];
-        dest_row_2 = array[p0++];
+        CAPSENSE_READ_ROWS_EXTRACT_FROM_ARRAY;
         array[p1++] = CAPSENSE_READ_ROWS_VALUE;
     }
     shift_select_nothing();
@@ -334,9 +445,8 @@ uint8_t test_single(uint8_t col, uint16_t time)
              "ldi %B[index], 0"                 "\n\t"
              "cli"                              "\n\t"
              "sbi %[stcp_regaddr], %[stcp_bit]" "\n\t"
-        "1:" CAPSENSE_READ_ROWS_ASM_INSTRUCTIONS         "\n\t"
-             "st %a[arr], %[dest_row_1]"       "\n\t"
-             "st %a[arr], %[dest_row_2]"       "\n\t"
+        "1:" CAPSENSE_READ_ROWS_ASM_INSTRUCTIONS                 "\n\t"
+             CAPSENSE_READ_ROWS_STORE_TO_ARRAY_INSTRUCTIONS_FAKE "\n\t"
              "adiw %A[index], 0x01"             "\n\t"
              "cp %A[index], %A[time]"           "\n\t"
              "cpc %B[index], %B[time]"          "\n\t"
@@ -364,7 +474,7 @@ uint8_t test_single(uint8_t col, uint16_t time)
 void test_col_print_data_v2(uint8_t col)
 {
     uprintf("%d: ", col);
-    static uint8_t data[NRTIMES*2];
+    static uint8_t data[NRTIMES*CAPSENSE_READ_ROWS_NUMBER_OF_BYTES_PER_SAMPLE];
     static uint8_t sums[(TESTATONCE+1) * MATRIX_ROWS];
     uint8_t to_time = NRTIMES-1;
     uint8_t from_time = 0;
@@ -587,7 +697,7 @@ uint16_t calibration_measure_all_valid_keys(uint8_t time, uint8_t reps, bool loo
             uint8_t row;
             for (row=0; row < MATRIX_ROWS; row++)
             {
-                if (pgm_read_byte(&keymaps[0][row][col]) != KC_NO)
+                if (pgm_read_word(&keymaps[0][row][col]) != KC_NO)
                 {
                     valid_physical_rows |= (((matrix_row_t)1) << CAPSENSE_KEYMAP_ROW_TO_PHYSICAL_ROW(row)); // convert keymap row to physical row
                 }
@@ -652,7 +762,7 @@ void calibration(void)
         uint8_t physical_col = CAPSENSE_KEYMAP_COL_TO_PHYSICAL_COL(col);
         uint8_t row;
         for (row = 0; row < MATRIX_ROWS; row++) {
-            if (pgm_read_byte(&keymaps[0][row][col]) != KC_NO) {
+            if (pgm_read_word(&keymaps[0][row][col]) != KC_NO) {
                 uint16_t threshold = measure_middle(physical_col, CAPSENSE_KEYMAP_ROW_TO_PHYSICAL_ROW(row), CAPSENSE_HARDCODED_SAMPLE_TIME, CAPSENSE_CAL_EACHKEY_REPS);
                 uint8_t besti = 0;
                 uint16_t best_diff = (uint16_t)abs(threshold - cal_thresholds[besti]);
@@ -671,19 +781,27 @@ void calibration(void)
         }
     }
     for (i=0;i<CAPSENSE_CAL_BINS;i++) {
+        uint16_t bin_signal_level;
         if ((cal_thresholds_max[i] == 0xFFFFU) || (cal_thresholds_min[i] == 0xFFFFU)) {
-            #ifdef CAPSENSE_CONDUCTIVE_PLASTIC_IS_PUSHED_DOWN_ON_KEYPRESS
-            cal_thresholds[i] += CAPSENSE_CAL_THRESHOLD_OFFSET;
-            #else
-            cal_thresholds[i] -= CAPSENSE_CAL_THRESHOLD_OFFSET;
-            #endif
+            bin_signal_level = cal_thresholds[i];
+        } else {
+            bin_signal_level = (cal_thresholds_max[i] + cal_thresholds_min[i]) / 2;
+        }
+        #ifdef CAPSENSE_CONDUCTIVE_PLASTIC_IS_PUSHED_DOWN_ON_KEYPRESS
+        if ((bin_signal_level + CAPSENSE_CAL_THRESHOLD_OFFSET) > CAPSENSE_DAC_MAX)
+        {
+            cal_thresholds[i] = CAPSENSE_DAC_MAX;
+        } else {
+            cal_thresholds[i] = bin_signal_level + CAPSENSE_CAL_THRESHOLD_OFFSET;
+        }
+        #else
+        if (bin_signal_level < CAPSENSE_CAL_THRESHOLD_OFFSET)
+        {
+            cal_thresholds[i] = 0;
         } else {
-            #ifdef CAPSENSE_CONDUCTIVE_PLASTIC_IS_PUSHED_DOWN_ON_KEYPRESS
-            cal_thresholds[i] = (cal_thresholds_max[i] + cal_thresholds_min[i]) / 2 + CAPSENSE_CAL_THRESHOLD_OFFSET;
-            #else
-            cal_thresholds[i] = (cal_thresholds_max[i] + cal_thresholds_min[i]) / 2 - CAPSENSE_CAL_THRESHOLD_OFFSET;
-            #endif
+            cal_thresholds[i] = bin_signal_level - CAPSENSE_CAL_THRESHOLD_OFFSET;
         }
+        #endif
     }
 }
 
@@ -715,6 +833,11 @@ void real_keyboard_init_basic(void)
         setPinOutput(B0);
         writePin(B0, 1);
     #endif
+    #ifdef USING_SOLENOID_ENABLE_PIN
+        // ^^ this must be defined in config.h if you are using and xwhatsit type solenoid
+        setPinOutput(USING_SOLENOID_ENABLE_PIN);
+        writePin(USING_SOLENOID_ENABLE_PIN, 1);
+    #endif
 }
 
 void matrix_init_custom(void) {