diff options
Diffstat (limited to 'keyboards/converter/palm_usb/stowaway')
-rw-r--r-- | keyboards/converter/palm_usb/stowaway/config.h | 56 | ||||
-rw-r--r-- | keyboards/converter/palm_usb/stowaway/keyboard.json | 17 | ||||
-rw-r--r-- | keyboards/converter/palm_usb/stowaway/matrix.c | 382 | ||||
-rw-r--r-- | keyboards/converter/palm_usb/stowaway/readme.md | 97 | ||||
-rw-r--r-- | keyboards/converter/palm_usb/stowaway/rules.mk | 5 |
5 files changed, 557 insertions, 0 deletions
diff --git a/keyboards/converter/palm_usb/stowaway/config.h b/keyboards/converter/palm_usb/stowaway/config.h new file mode 100644 index 0000000000..84394b9f71 --- /dev/null +++ b/keyboards/converter/palm_usb/stowaway/config.h @@ -0,0 +1,56 @@ +/* +Copyright 2012 Jun Wako <[email protected]> + +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 <http://www.gnu.org/licenses/>. +*/ + +/* This code makes use of cy384's Arduino USB HID adapter for the Palm Portable + Keyboard, released under the BSD licence */ + + + + +#pragma once + +// IO pins to serial +// https://deskthority.net/wiki/Arduino_Pro_Micro for pin lookup +#define VCC_PIN D1 // pro micro 2 +#define RX_PIN D0 //pro micro 3 , was 8 on cy384 +#define RTS_PIN C6 // 5 //[ was D4 // 4 on the cy384 +#define DCD_PIN E6 //7 + +// if using the particular arduino pinout of CY384 +#ifdef CY384 + #define GND_PIN D7 //6 + #define PULLDOWN_PIN B1 // 15 +#endif + +#ifndef HANDSPRING +// Set to 1 for Handspring or to disable RTS/DCD based handshake. + #define HANDSPRING 0 +#endif + +#define MAXDROP 10 // check if keyboard is connected every X polling cycles +#define SLEEP_TIMEOUT 500000 // check keyboard/reset this many millis + + +#define MATRIX_ROWS 12 +#define MATRIX_COLS 8 + +/* key combination for command */ +#define IS_COMMAND() ( \ + get_mods() == (MOD_BIT(KC_LALT) | MOD_BIT(KC_RALT)) || \ + get_mods() == (MOD_BIT(KC_LGUI) | MOD_BIT(KC_RGUI)) || \ + get_mods() == (MOD_BIT(KC_LSFT) | MOD_BIT(KC_RSFT)) \ +) diff --git a/keyboards/converter/palm_usb/stowaway/keyboard.json b/keyboards/converter/palm_usb/stowaway/keyboard.json index 9a263327ad..6488b5c23c 100644 --- a/keyboards/converter/palm_usb/stowaway/keyboard.json +++ b/keyboards/converter/palm_usb/stowaway/keyboard.json @@ -1,4 +1,21 @@ { + "keyboard_name": "Stowaway Converter", + "manufacturer": "QMK", + "maintainer": "qmk", + "usb": { + "vid": "0xFEED", + "pid": "0x0001", + "device_version": "1.0.0" + }, + "processor": "atmega32u4", + "bootloader": "caterina", + "features": { + "bootmagic": false, + "mousekey": false, + "extrakey": false, + "console": true, + "command": true + }, "layouts": { "LAYOUT": { "layout": [ diff --git a/keyboards/converter/palm_usb/stowaway/matrix.c b/keyboards/converter/palm_usb/stowaway/matrix.c new file mode 100644 index 0000000000..db3784df19 --- /dev/null +++ b/keyboards/converter/palm_usb/stowaway/matrix.c @@ -0,0 +1,382 @@ +/* +Copyright 2018 milestogo +with elements Copyright 2014 cy384 under a modified BSD license +building on qmk structure Copyright 2012 Jun Wako <[email protected]> + +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 <http://www.gnu.org/licenses/>. +*/ + +#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<<COL(code)); + last_upKey=code; + } + } else { + // press + if (!matrix_is_on(ROW(code), COL(code))) { + matrix[ROW(code)] |= (1<<COL(code)); + + } + } + + matrix_scan_kb(); + return code; +} + +inline +bool matrix_has_ghost(void) +{ + return false; +} + +inline +bool matrix_is_on(uint8_t row, uint8_t col) +{ + return (matrix[row] & (1<<col)); +} + +inline +uint8_t matrix_get_row(uint8_t row) +{ + return matrix[row]; +} + +void matrix_print(void) +{ + print("\nr/c 01234567\n"); + for (uint8_t row = 0; row < matrix_rows(); row++) { + print_hex8(row); print(": "); + print_bin_reverse8(matrix_get_row(row)); + print("\n"); + } +} diff --git a/keyboards/converter/palm_usb/stowaway/readme.md b/keyboards/converter/palm_usb/stowaway/readme.md new file mode 100644 index 0000000000..850005d9ea --- /dev/null +++ b/keyboards/converter/palm_usb/stowaway/readme.md @@ -0,0 +1,97 @@ +# Stowaway Serial keyboard to USB protocol converter + +A converter for Palm Pilot era Stowaway serial keyboards. + +Makes extensive use of the code from [cy384](https://github.com/cy384/ppk_usb). Ported to QMK by [milestogo](https://github.com/milestogo). + +Hardware Supported: See hardware section below +Hardware Availability: self-built + +Make example for this keyboard (after setting up your build environment): + + make converter/palm_usb/stowaway:default + +See the [build environment setup](https://docs.qmk.fm/#/getting_started_build_tools) and the [make instructions](https://docs.qmk.fm/#/getting_started_make_guide) for more information. Brand new to QMK? Start with our [Complete Newbs Guide](https://docs.qmk.fm/#/newbs). + + +## Hardware + +Target MCU is ATMega32u4 but other USB capable AVRs should also work. + +cy843 has a very specific way of wiring in order to fit all pins in sequence. It breaks +qmk because the Arduino softserial library uses different pins from QMK. + +I've wired the pro micro hardware as follows. + +| Label | TX0 | RX1 | GND | GND | 2 | 3 | 4 | 5 | 6 | 7 | +| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | +| Palm | | | * | GND | VCC | RX | NC | RTS | NC | DCD | +| MCU | | | | | D1 | D0 | | C6 | | E6 | + +\* The RX line from the keyboard should be conected to a ~10K ohm pull down resistor to ground. +RX --|--3 + 10K + | + GND + + +Power management is not implemented yet, this just reboots the keyboard frequently. + +### Keyboards: + +Think Outside Stowaway Keyboards +There are at least 5 different versions of these keyboards out there. + +Group 1: Palm 3, Palm 5 & HP Journada 540, and Compaq iPaq keyboards. These share +the same RTS protocol, but with different pinouts for each device. + +Group 2: Handspring keyboards. These don't do handshaking protocol, and use TTL signal. +Set HANDSPRING to 1 in config.h + +Group 3: IRDA models. Untested but theoretically serial. + +### Connectors + +See https://github.com/cy384/ppk_usb for wiring & sample 3d printable sockets. + +Only Palm3 wiring has been tested. +RXD pin is output from keyboard to MCU's RX. + +Viewed from left to right with the keyboard in typing position. + +Palm3: [NC, VCC, RXD, RTS, NC, NC, DCD, NC, NC, GND] +Palm5: [NC, VCC, RXD, RTS, NC, NC, DCD, NC, NC, GND] (same order, different connector) +Handspring: [VCC/TXD, NC, NC, NC, GND, NC, NC, RXD] +Journada: [NC, NC, NC, GND, NC, RTS, NC, DTR/VCC, RXD, DCD, NC] [GND-IN, VCC-IN] +Ipaq: [NC, NC, DTR/VCC, NC, NC, RTS, NC, RXD, DCD, GND, NC, NC] + +### Protocol + + Signal: Asynchronous, Negative logic, 9600baud, No Flow control + Frame format: 1-Start bit, 8-Data bits, No-Parity, 1-Stop bit + + AVR USART engine expects positive logic while stowaway keyboard signal is negative. + To use AVR UART engine you need external inverter in front of RX and TX pin. + Otherwise you can software serial routine to communicate the keyboard. + +This converter uses software method, you doesn't need any inverter part. + + +Commands From System To Keyboard + none + +Commands From Keyboard To System + + 0xFA Reset/Ready Response(followed by 0xFD) + +References + +* http://www.splorp.com/pdf/stowawayhwref.pdf + +### Todo +- Test on anything but a palm 3 model keyboard. +- Change all of the soft serial to match the new Helix based code so that it is easier +to switch pins. +- The driver should check for a keyboard that pressed the delete key then disconnected. +Check every MAXDROP scans that the keyboard is there, and if not, clear the matrix. +Not implemented yet, since matrix scan is so much faster than serial. diff --git a/keyboards/converter/palm_usb/stowaway/rules.mk b/keyboards/converter/palm_usb/stowaway/rules.mk new file mode 100644 index 0000000000..ccb8eb9ecc --- /dev/null +++ b/keyboards/converter/palm_usb/stowaway/rules.mk @@ -0,0 +1,5 @@ +#HARDWARE_SERIAL = yes +CUSTOM_MATRIX = yes + +SRC += matrix.c +UART_DRIVER_REQUIRED = yes |