/* Copyright 2018 milestogo with elements Copyright 2014 cy384 under a modified BSD license building on qmk structure Copyright 2012 Jun Wako This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "matrix.h" #include "debug.h" #include "wait.h" #include "uart.h" #include "timer.h" /* * Matrix Array usage: * * ROW: 12(4bits) * COL: 8(3bits) * * +---------+ * 0|00 ... 07| * 1|00 ... 07| * :| ... | * :| ... | * A| | * B| | * +---------+ */ static uint8_t matrix[MATRIX_ROWS]; // we're going to need a sleep timer static uint16_t last_activity ; // and a byte to track duplicate up events signalling all keys up. static uint16_t last_upKey ; // serial device can disconnect. Check every MAXDROP characters. static uint16_t disconnect_counter = 0; // bitmath masks. #define KEY_MASK 0b10000000 #define COL_MASK 0b00000111 #define ROW_MASK 0b01111000 #define ROW(code) (( code & ROW_MASK ) >>3) #define COL(code) ((code & COL_MASK) ) #define KEYUP(code) ((code & KEY_MASK) >>7 ) __attribute__ ((weak)) void matrix_init_kb(void) { matrix_init_user(); } __attribute__ ((weak)) void matrix_scan_kb(void) { matrix_scan_user(); } __attribute__ ((weak)) void matrix_init_user(void) { } __attribute__ ((weak)) void matrix_scan_user(void) { } inline uint8_t matrix_rows(void) { return MATRIX_ROWS; } inline uint8_t matrix_cols(void) { return MATRIX_COLS; } void pins_init(void) { // set pins for pullups, Rts , power &etc. //print ("pins setup\n"); gpio_set_pin_output(VCC_PIN); gpio_write_pin_low(VCC_PIN); #if ( HANDSPRING == 0) #ifdef CY835 gpio_set_pin_output(GND_PIN); gpio_write_pin_low(GND_PIN); gpio_set_pin_output(PULLDOWN_PIN); gpio_write_pin_low(PULLDOWN_PIN); #endif gpio_set_pin_input(DCD_PIN); gpio_set_pin_input(RTS_PIN); #endif /* check that the other side isn't powered up. test=gpio_read_pin(DCD_PIN); xprintf("b%02X:", test); test=gpio_read_pin(RTS_PIN); xprintf("%02X\n", test); */ } uint8_t rts_reset(void) { static uint8_t firstread ; /* bounce RTS so device knows it is rebooted */ // On boot, we keep rts as input, then switch roles here // on leaving sleep, we toggle the same way firstread=gpio_read_pin(RTS_PIN); // printf("r%02X:", firstread); gpio_set_pin_output(RTS_PIN); if (firstread) { gpio_write_pin_low(RTS_PIN); } wait_ms(10); gpio_write_pin_high(RTS_PIN); /* the future is Arm if (!palReadPad(RTS_PIN_IOPRT)) { wait_ms(10); palSetPadMode(RTS_PINn_IOPORT, PinDirectionOutput_PUSHPULL); palSetPad(RTS_PORT, RTS_PIN); } else { palSetPadMode(RTS_PIN_RTS_PORT, PinDirectionOutput_PUSHPULL); palSetPad(RTS_PORT, RTS_PIN); palClearPad(RTS_PORT, RTS_PIN); wait_ms(10); palSetPad(RTS_PORT, RTS_PIN); } */ wait_ms(5); //print("rts\n"); return 1; } uint8_t get_serial_byte(void) { static uint8_t code; while(1) { code = uart_read(); if (code) { dprintf("%02X ", code); return code; } } } uint8_t palm_handshake(void) { // assumes something has seen DCD go high, we've toggled RTS // and we now need to verify handshake. // listen for up to 4 packets before giving up. // usually I get the sequence FF FA FD static uint8_t codeA=0; for (uint8_t i=0; i < 5; i++) { codeA=get_serial_byte(); if ( 0xFA == codeA) { if( 0xFD == get_serial_byte()) { return 1; } } } return 0; } uint8_t palm_reset(void) { print("@"); rts_reset(); // shouldn't need to power cycle. if ( palm_handshake() ) { last_activity = timer_read(); return 1; } else { print("failed reset"); return 0; } } uint8_t handspring_handshake(void) { // should be sent 15 ms after power up. // listen for up to 4 packets before giving up. static uint8_t codeA=0; for (uint8_t i=0; i < 5; i++) { codeA=get_serial_byte(); if ( 0xF9 == codeA) { if( 0xFB == get_serial_byte()) { return 1; } } } return 0; } uint8_t handspring_reset(void) { gpio_write_pin_low(VCC_PIN); wait_ms(5); gpio_write_pin_high(VCC_PIN); if ( handspring_handshake() ) { last_activity = timer_read(); disconnect_counter=0; return 1; } else { print("-HSreset"); return 0; } } void matrix_init(void) { debug_enable = true; //debug_matrix =true; uart_init(9600); // arguments all #defined #if (HANDSPRING == 0) pins_init(); // set all inputs and outputs. #endif print("power up\n"); gpio_write_pin_high(VCC_PIN); // wait for DCD strobe from keyboard - it will do this // up to 3 times, then the board needs the RTS toggled to try again #if ( HANDSPRING == 1) if ( handspring_handshake() ) { last_activity = timer_read(); } else { print("failed handshake"); wait_ms(1000); //BUG /should/ power cycle or toggle RTS & reset, but this usually works. } #else /// Palm / HP device with DCD while( !gpio_read_pin(DCD_PIN) ) {;} print("dcd\n"); rts_reset(); // at this point the keyboard should think all is well. if ( palm_handshake() ) { last_activity = timer_read(); } else { print("failed handshake"); wait_ms(1000); //BUG /should/ power cycle or toggle RTS & reset, but this usually works. } #endif // initialize matrix state: all keys off for (uint8_t i=0; i < MATRIX_ROWS; i++) matrix[i] = 0x00; matrix_init_kb(); return; } uint8_t matrix_scan(void) { uint8_t code; code = uart_read(); if (!code) { /* disconnect_counter ++; if (disconnect_counter > MAXDROP) { // set all keys off for (uint8_t i=0; i < MATRIX_ROWS; i++) matrix[i] = 0x00; } */ // check if the keyboard is asleep. if (timer_elapsed(last_activity) > SLEEP_TIMEOUT) { #if(HANDSPRING ==0 ) palm_reset(); #else handspring_reset(); #endif return 0; } } last_activity = timer_read(); disconnect_counter=0; // if we are getting serial data, we're connected. dprintf("%02X ", code); switch (code) { case 0xFD: // unexpected reset byte 2 print("rstD "); return 0; case 0xFA: // unexpected reset print("rstA "); return 0; } if (KEYUP(code)) { if (code == last_upKey) { // all keys are not pressed. // Manual says to disable all modifiers left open now. // but that could defeat sticky keys. // BUG? dropping this byte. last_upKey=0; return 0; } // release if (matrix_is_on(ROW(code), COL(code))) { matrix[ROW(code)] &= ~(1<