#include "matrix_manipulate.h"
#include <string.h>
-#if defined(CONTROLLER_IS_XWHATSIT_BEAMSPRING_REV_4)
-#define CAPSENSE_DAC_SCLK B1
-#define CAPSENSE_DAC_DIN B2
-#define CAPSENSE_DAC_SYNC_N B0
-#define CAPSENSE_DAC_MAX 1023
-
-#define CAPSENSE_SHIFT_DIN C4
-#define CAPSENSE_SHIFT_OE C6
-#define CAPSENSE_SHIFT_SHCP C5
-#define CAPSENSE_SHIFT_STCP C7
-#define CAPSENSE_SHIFT_STCP_IO _SFR_IO_ADDR(PORTC)
-#define CAPSENSE_SHIFT_STCP_BIT 7
-
-#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_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)
-// 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)
-#define CAPSENSE_PHYSICAL_ROW_TO_KEYMAP_ROW(row) (row)
-#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_DAC_SCLK B1
-#define CAPSENSE_DAC_DIN B2
-#define CAPSENSE_DAC_SYNC_N B0
-#define CAPSENSE_DAC_MAX 1023
-
-#define CAPSENSE_SHIFT_DIN D4
-#define CAPSENSE_SHIFT_OE D5
-#define CAPSENSE_SHIFT_SHCP D7
-#define CAPSENSE_SHIFT_STCP D6
-#define CAPSENSE_SHIFT_STCP_IO _SFR_IO_ADDR(PORTD)
-#define CAPSENSE_SHIFT_STCP_BIT 6
-
-#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_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_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)
-
-#define CAPSENSE_DAC_MCP4921
-#define CAPSENSE_DAC_NCS F6
-#define CAPSENSE_DAC_SCK B1
-#define CAPSENSE_DAC_SDI B2
-#define CAPSENSE_DAC_MAX 4095
-
-#define CAPSENSE_SHIFT_DIN B2
-#define CAPSENSE_SHIFT_OE B6
-#define CAPSENSE_SHIFT_SHCP B1
-#define CAPSENSE_SHIFT_STCP F7
-#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
-#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_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_KEYMAP_ROW_TO_PHYSICAL_ROW(row) (3-(row))
-#define CAPSENSE_PHYSICAL_ROW_TO_KEYMAP_ROW(row) (3-(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
-#define CAPSENSE_CONDUCTIVE_PLASTIC_IS_PULLED_UP_ON_KEYPRESS
-// TODO END
+/* Notes on Expansion Header:
-#else
+Pinout:
+--1--O O--2--
+--3--O O--4--
+--5--O O--6--
-#ifndef CAPSENSE_DAC_SCLK
-#error "Please select controller type in config.h, or please define each macro that is defined when selecting a particular macro type in matrix.c"
-#endif
-#endif
+Pin 1 is always VCC
+Pin 6 in always GND
-#ifndef CAPSENSE_KEYBOARD_SETTLE_TIME_US
-#error "Please define CAPSENSE_KEYBOARD_SETTLE_TIME_US in config.h"
-#endif
-#ifndef CAPSENSE_DAC_SETTLE_TIME_US
-#error "Please define CAPSENSE_DAC_SETTLE_TIME_US in config.h"
-#endif
-#ifndef CAPSENSE_HARDCODED_SAMPLE_TIME
-#error "Please define CAPSENSE_HARDCODED_SAMPLE_TIME in config.h"
-#endif
+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.
-#ifndef CAPSENSE_CAL_ENABLED
-#error "Please define CAPSENSE_CAL_ENABLED as 1/0 in config.h"
-#endif
-#ifndef CAPSENSE_CAL_DEBUG
-#error "Please define CAPSENSE_CAL_DEBUG as 1/0 in config.h"
-#endif
-#ifndef CAPSENSE_CAL_INIT_REPS
-#define CAPSENSE_CAL_INIT_REPS 16
-#endif
-#ifndef CAPSENSE_CAL_EACHKEY_REPS
-#define CAPSENSE_CAL_EACHKEY_REPS 16
-#endif
-#ifndef CAPSENSE_CAL_BINS
-#error "Please define CAPSENSE_CAL_BINS in config.h"
-#endif
-#ifndef CAPSENSE_CAL_THRESHOLD_OFFSET
-#error "Please define CAPSENSE_CAL_THRESHOLD_OFFSET in config.h"
-#endif
+On original xwhatsit controllers:
+pin 2 = PB7
+pin 3 = PB4
+pin 4 = PB6
+pin 5 = PB5
-#if (!defined(CAPSENSE_CONDUCTIVE_PLASTIC_IS_PULLED_UP_ON_KEYPRESS)) && (!defined(CAPSENSE_CONDUCTIVE_PLASTIC_IS_PUSHED_DOWN_ON_KEYPRESS))
-#error "Please specify whether the flyplate is pushed down or pulled up on keypress!"
-#endif
+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
+*/
+
+// USING_SOLENOID_ENABLE_PIN must be defined in config.h if you are using and xwhatsit type solenoid
static inline uint8_t read_rows(void)
{
#endif
-#define SHIFT_BITS ((MATRIX_COLS > 16) ? 24 : 16)
+#define SHIFT_BITS (((CAPSENSE_KEYMAP_COL_TO_PHYSICAL_COL(MATRIX_COLS - 1) >= 16) || \
+ (CAPSENSE_KEYMAP_COL_TO_PHYSICAL_COL(0) >= 16)) ? 24 : 16)
void shift_select_nothing(void)
{
writePin(CAPSENSE_SHIFT_STCP, 0);
}
-void shift_data(uint32_t data)
+void shift_data(uint32_t data, int data_idle, int shcp_idle, int stcp_idle)
{
int i;
+ writePin(CAPSENSE_SHIFT_SHCP, 0);
+ writePin(CAPSENSE_SHIFT_STCP, 0);
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);
+ if (!((i == 0) && (shcp_idle))) {
+ writePin(CAPSENSE_SHIFT_SHCP, 0);
+ }
data <<= 1;
}
writePin(CAPSENSE_SHIFT_STCP, 1);
- writePin(CAPSENSE_SHIFT_STCP, 0);
+ if (!stcp_idle) {
+ writePin(CAPSENSE_SHIFT_STCP, 0);
+ }
+ writePin(CAPSENSE_SHIFT_DIN, !!data_idle);
}
void shift_select_col_no_strobe(uint8_t col)
setPinOutput(CAPSENSE_SHIFT_OE);
setPinOutput(CAPSENSE_SHIFT_STCP);
setPinOutput(CAPSENSE_SHIFT_SHCP);
+ writePin(CAPSENSE_SHIFT_OE, 0);
writePin(CAPSENSE_SHIFT_STCP, 0);
writePin(CAPSENSE_SHIFT_SHCP, 0);
shift_select_nothing();
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)
{
"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"
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();
wait_us(CAPSENSE_KEYBOARD_SETTLE_TIME_US);
}
-uint8_t test_single(uint8_t col, uint16_t time)
+uint8_t test_single(uint8_t col, uint16_t time, uint8_t *interference_ptr)
{
shift_select_col_no_strobe(col);
uint16_t index;
CAPSENSE_READ_ROWS_LOCAL_VARS;
- uint8_t dummy_data;
- uint8_t *arrayp = &dummy_data;
+ uint8_t array[CAPSENSE_READ_ROWS_NUMBER_OF_BYTES_PER_SAMPLE + 1]; // one sample before triggering, and one dummy byte
+ uint8_t *arrayp = array;
asm volatile (
"ldi %A[index], 0" "\n\t"
"ldi %B[index], 0" "\n\t"
"cli" "\n\t"
+ CAPSENSE_READ_ROWS_ASM_INSTRUCTIONS "\n\t"
+ CAPSENSE_READ_ROWS_STORE_TO_ARRAY_INSTRUCTIONS "\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"
: "memory" );
shift_select_nothing();
wait_us(CAPSENSE_KEYBOARD_SETTLE_TIME_US);
- return CAPSENSE_READ_ROWS_VALUE;
+ uint8_t value_at_time = CAPSENSE_READ_ROWS_VALUE;
+ if (interference_ptr)
+ {
+ uint16_t p0 = 0;
+ CAPSENSE_READ_ROWS_EXTRACT_FROM_ARRAY;
+ uint8_t interference = CAPSENSE_READ_ROWS_VALUE;
+ *interference_ptr = interference;
+ }
+ return value_at_time;
}
#ifndef NO_PRINT
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;
uint8_t i;
for (i=0;i<reps;i++)
{
- sum += (test_single(col, time) >> row) & 1;
+ sum += (test_single(col, time, NULL) >> row) & 1;
}
if (sum < reps_div2)
{
for (i=0;i<reps;i++) {
if (looking_for_all_zero)
{
- uint8_t all_zero = (test_single(physical_col, time) & valid_physical_rows) == 0;
+ uint8_t all_zero = (test_single(physical_col, time, NULL) & valid_physical_rows) == 0;
if (!all_zero) {
min = mid + 1;
goto next_binary_search;
}
} else {
- uint8_t all_ones = (test_single(physical_col, time) & valid_physical_rows) == valid_physical_rows;
+ uint8_t all_ones = (test_single(physical_col, time, NULL) & valid_physical_rows) == valid_physical_rows;
if (!all_ones) {
max = mid - 1;
goto next_binary_search;
}
}
+void set_leds(int num_lock, int caps_lock, int scroll_lock)
+{
+ #if defined(LED_NUM_LOCK_PIN)
+ #if defined(LED_NUM_LOCK_ACTIVE_LOW)
+ writePin(LED_NUM_LOCK_PIN, !num_lock);
+ #else
+ writePin(LED_NUM_LOCK_PIN, num_lock);
+ #endif
+ #endif
+ #if defined(LED_CAPS_LOCK_PIN)
+ #if defined(LED_CAPS_LOCK_ACTIVE_LOW)
+ writePin(LED_CAPS_LOCK_PIN, !caps_lock);
+ #else
+ writePin(LED_CAPS_LOCK_PIN, caps_lock);
+ #endif
+ #endif
+ #if defined(LED_SCROLL_LOCK_PIN)
+ #if defined(LED_SCROLL_LOCK_ACTIVE_LOW)
+ writePin(LED_SCROLL_LOCK_PIN, !scroll_lock);
+ #else
+ writePin(LED_SCROLL_LOCK_PIN, scroll_lock);
+ #endif
+ #endif
+}
+
void real_keyboard_init_basic(void)
{
+ SETUP_UNUSED_PINS();
+
+ #if defined(LED_NUM_LOCK_PIN)
+ setPinOutput(LED_NUM_LOCK_PIN);
+ #endif
+ #if defined(LED_CAPS_LOCK_PIN)
+ setPinOutput(LED_CAPS_LOCK_PIN);
+ #endif
+ #if defined(LED_SCROLL_LOCK_PIN)
+ setPinOutput(LED_SCROLL_LOCK_PIN);
+ #endif
+ set_leds(0, 0, 0);
+
#ifndef NO_PRINT
uprintf("shift_init()");
#endif
#ifndef NO_PRINT
uprintf(" DONE\n");
#endif
+ SETUP_ROW_GPIOS();
#if CAPSENSE_CAL_ENABLED
calibration();
#else
dac_write_threshold(CAPSENSE_HARDCODED_THRESHOLD);
dac_write_threshold(CAPSENSE_HARDCODED_THRESHOLD);
#endif
- #if defined(CONTROLLER_IS_THROUGHT_HOLE_BEAMSPRING)
+ #if defined(CONTROLLER_IS_THROUGH_HOLE_BEAMSPRING) || defined(CONTROLLER_IS_THROUGH_HOLE_MODEL_F)
// Disable on-board leds.
setPinOutput(D5);
writePin(D5, 1);
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
+}
+
+
+bool led_update_kb(led_t led_state) {
+ bool res = led_update_user(led_state);
+ if(res) {
+ set_leds(led_state.num_lock, led_state.caps_lock, led_state.scroll_lock);
+ }
+ return res;
}
void matrix_init_custom(void) {
+
+
//test_v2();
//tracking_test();
real_keyboard_init_basic();
dac_write_threshold(cal_thresholds[cal]);
for (col=0;col<MATRIX_COLS;col++) {
uint8_t real_col = CAPSENSE_KEYMAP_COL_TO_PHYSICAL_COL(col);
- uint8_t d;
+ uint8_t d, interference;
uint8_t d_tested = 0;
for (row=0;row<MATRIX_ROWS;row++) {
if (assigned_to_threshold[cal][row] & (((matrix_row_t)1) << col))
{
if (!d_tested)
{
- d = test_single(real_col, CAPSENSE_HARDCODED_SAMPLE_TIME);
+ d = test_single(real_col, CAPSENSE_HARDCODED_SAMPLE_TIME, &interference);
#ifdef CAPSENSE_CONDUCTIVE_PLASTIC_IS_PULLED_UP_ON_KEYPRESS
d = ~d;
#endif
d_tested = 1;
}
uint8_t physical_row = CAPSENSE_KEYMAP_ROW_TO_PHYSICAL_ROW(row);
- current_matrix[row] |= ((matrix_row_t)((d >> physical_row) & 1)) << col;
+ if (!((interference >> physical_row) & 1))
+ {
+ current_matrix[row] |= ((matrix_row_t)((d >> physical_row) & 1)) << col;
+ }
}
}
}
for (col=0;col<MATRIX_COLS;col++)
{
uint8_t real_col = CAPSENSE_KEYMAP_COL_TO_PHYSICAL_COL(col);
- uint8_t d = test_single(real_col, CAPSENSE_HARDCODED_SAMPLE_TIME);
+ uint8_t interference;
+ uint8_t d = test_single(real_col, CAPSENSE_HARDCODED_SAMPLE_TIME, &interference);
#ifdef CAPSENSE_CONDUCTIVE_PLASTIC_IS_PULLED_UP_ON_KEYPRESS
d = ~d;
#endif