2011-07-20 15:32:52 +00:00
/*
Copyright 2011 Jun Wako < wakojun @ gmail . com >
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/>.
*/
2011-01-12 16:26:33 +00:00
/*
* scan matrix
*/
# include <stdint.h>
# include <stdbool.h>
# include <avr/io.h>
# include <util/delay.h>
# include "print.h"
# include "util.h"
# include "debug.h"
# include "adb.h"
2011-02-21 14:05:28 +00:00
# include "matrix.h"
2015-04-26 06:08:54 +00:00
# include "report.h"
# include "host.h"
2011-01-12 16:26:33 +00:00
# if (MATRIX_COLS > 16)
# error "MATRIX_COLS must not exceed 16"
# endif
# if (MATRIX_ROWS > 255)
# error "MATRIX_ROWS must not exceed 255"
# endif
2016-05-19 07:26:01 +00:00
static bool is_iso_layout = false ;
2012-09-20 03:52:45 +00:00
static bool is_modified = false ;
2015-04-26 06:08:54 +00:00
static report_mouse_t mouse_report = { } ;
2011-01-12 16:26:33 +00:00
// matrix state buffer(1:on, 0:off)
# if (MATRIX_COLS <= 8)
2012-09-20 03:52:45 +00:00
static uint8_t matrix [ MATRIX_ROWS ] ;
2011-01-12 16:26:33 +00:00
# else
2012-09-20 03:52:45 +00:00
static uint16_t matrix [ MATRIX_ROWS ] ;
2011-01-12 16:26:33 +00:00
# endif
# ifdef MATRIX_HAS_GHOST
static bool matrix_has_ghost_in_row ( uint8_t row ) ;
# endif
2012-09-20 03:52:45 +00:00
static void register_key ( uint8_t key ) ;
2011-01-12 16:26:33 +00:00
inline
uint8_t matrix_rows ( void )
{
return MATRIX_ROWS ;
}
inline
uint8_t matrix_cols ( void )
{
return MATRIX_COLS ;
}
void matrix_init ( void )
{
adb_host_init ( ) ;
2013-10-14 14:37:05 +00:00
// wait for keyboard to boot up and receive command
_delay_ms ( 1000 ) ;
2016-05-19 07:26:01 +00:00
// Determine ISO keyboard by handle id
// http://lxr.free-electrons.com/source/drivers/macintosh/adbhid.c?v=4.4#L815
uint16_t handle_id = adb_host_talk ( ADB_ADDR_KEYBOARD , 3 ) ;
switch ( handle_id ) {
case 0x04 : case 0x05 : case 0x07 : case 0x09 : case 0x0D :
case 0x11 : case 0x14 : case 0x19 : case 0x1D : case 0xC1 :
case 0xC4 : case 0xC7 :
is_iso_layout = true ;
break ;
default :
is_iso_layout = false ;
break ;
}
2013-10-14 14:37:05 +00:00
// Enable keyboard left/right modifier distinction
// Addr:Keyboard(0010), Cmd:Listen(10), Register3(11)
// upper byte: reserved bits 0000, device address 0010
// lower byte: device handler 00000011
adb_host_listen ( 0x2B , 0x02 , 0x03 ) ;
2011-01-12 16:26:33 +00:00
// initialize matrix state: all keys off
2012-09-20 03:52:45 +00:00
for ( uint8_t i = 0 ; i < MATRIX_ROWS ; i + + ) matrix [ i ] = 0x00 ;
2011-01-12 16:26:33 +00:00
debug_enable = true ;
2013-11-07 19:33:13 +00:00
//debug_matrix = true;
//debug_keyboard = true;
//debug_mouse = true;
2011-01-12 16:26:33 +00:00
print ( " debug enabled. \n " ) ;
2016-01-08 01:39:23 +00:00
// LED flash
DDRD | = ( 1 < < 6 ) ; PORTD | = ( 1 < < 6 ) ;
_delay_ms ( 500 ) ;
DDRD | = ( 1 < < 6 ) ; PORTD & = ~ ( 1 < < 6 ) ;
2016-05-19 07:26:01 +00:00
uint16_t handle_id2 = adb_host_talk ( ADB_ADDR_KEYBOARD , 3 ) ;
xprintf ( " handle_id: %02X -> %02X \n " , handle_id & 0xff , handle_id2 & 0xff ) ;
2011-01-12 16:26:33 +00:00
return ;
}
2015-04-26 06:08:54 +00:00
# ifdef ADB_MOUSE_ENABLE
# ifdef MAX
# undef MAX
# endif
# define MAX(X, Y) ((X) > (Y) ? (X) : (Y))
void adb_mouse_task ( void )
{
uint16_t codes ;
int16_t x , y ;
2016-05-19 07:26:01 +00:00
static int8_t mouseacc ;
2015-04-26 06:08:54 +00:00
_delay_ms ( 12 ) ; // delay for preventing overload of poor ADB keyboard controller
codes = adb_host_mouse_recv ( ) ;
2016-05-19 07:26:01 +00:00
// If nothing received reset mouse acceleration, and quit.
2015-04-26 06:08:54 +00:00
if ( ! codes ) {
mouseacc = 1 ;
return ;
} ;
// Bit sixteen is button.
if ( ~ codes & ( 1 < < 15 ) )
mouse_report . buttons | = MOUSE_BTN1 ;
if ( codes & ( 1 < < 15 ) )
mouse_report . buttons & = ~ MOUSE_BTN1 ;
2016-05-19 07:26:01 +00:00
// lower seven bits are movement, as signed int_7.
// low byte is X-axis, high byte is Y.
2015-04-26 06:08:54 +00:00
y = ( codes > > 8 & 0x3F ) ;
x = ( codes > > 0 & 0x3F ) ;
// bit seven and fifteen is negative
2016-05-19 07:26:01 +00:00
// usb does not use int_8, but int_7 (measuring distance) with sign-bit.
2015-04-26 06:08:54 +00:00
if ( codes & ( 1 < < 6 ) )
x = ( x - 0x40 ) ;
if ( codes & ( 1 < < 14 ) )
y = ( y - 0x40 ) ;
// Accelerate mouse. (They weren't meant to be used on screens larger than 320x200).
x * = mouseacc ;
y * = mouseacc ;
2016-05-19 07:26:01 +00:00
// Cap our two bytes per axis to one byte.
2015-04-26 06:08:54 +00:00
// Easier with a MIN-function, but since -MAX(-a,-b) = MIN(a,b)...
// I.E. MIN(MAX(x,-127),127) = -MAX(-MAX(x, -127), -127) = MIN(-MIN(-x,127),127)
mouse_report . x = - MAX ( - MAX ( x , - 127 ) , - 127 ) ;
mouse_report . y = - MAX ( - MAX ( y , - 127 ) , - 127 ) ;
if ( debug_mouse ) {
print ( " adb_host_mouse_recv: " ) ; print_bin16 ( codes ) ; print ( " \n " ) ;
print ( " adb_mouse raw: [ " ) ;
phex ( mouseacc ) ; print ( " " ) ;
phex ( mouse_report . buttons ) ; print ( " | " ) ;
print_decs ( mouse_report . x ) ; print ( " " ) ;
print_decs ( mouse_report . y ) ; print ( " ] \n " ) ;
}
2016-05-19 07:26:01 +00:00
// Send result by usb.
2015-04-26 06:08:54 +00:00
host_mouse_send ( & mouse_report ) ;
// increase acceleration of mouse
mouseacc + = ( mouseacc < ADB_MOUSE_MAXACC ? 1 : 0 ) ;
return ;
}
# endif
2011-01-12 16:26:33 +00:00
uint8_t matrix_scan ( void )
{
2013-11-26 21:21:43 +00:00
/* extra_key is volatile and more convoluted than necessary because gcc refused
to generate valid code otherwise . Making extra_key uint8_t and constructing codes
here via codes = extra_key < < 8 | 0xFF ; would consistently fail to even LOAD
extra_key from memory , and leave garbage in the high byte of codes . I tried
dozens of code variations and it kept generating broken assembly output . So
beware if attempting to make extra_key code more logical and efficient . */
static volatile uint16_t extra_key = 0xFFFF ;
2011-01-12 16:26:33 +00:00
uint16_t codes ;
uint8_t key0 , key1 ;
2012-09-20 03:52:45 +00:00
is_modified = false ;
2013-11-26 21:21:43 +00:00
codes = extra_key ;
extra_key = 0xFFFF ;
if ( codes = = 0xFFFF )
{
_delay_ms ( 12 ) ; // delay for preventing overload of poor ADB keyboard controller
codes = adb_host_kbd_recv ( ) ;
}
2011-01-12 16:26:33 +00:00
key0 = codes > > 8 ;
key1 = codes & 0xFF ;
2012-09-20 03:52:45 +00:00
if ( debug_matrix & & codes ) {
2012-06-18 03:23:17 +00:00
print ( " adb_host_kbd_recv: " ) ; phex16 ( codes ) ; print ( " \n " ) ;
}
2011-01-12 16:26:33 +00:00
if ( codes = = 0 ) { // no keys
return 0 ;
2012-09-20 03:52:45 +00:00
} else if ( codes = = 0x7F7F ) { // power key press
register_key ( 0x7F ) ;
} else if ( codes = = 0xFFFF ) { // power key release
register_key ( 0xFF ) ;
} else if ( key0 = = 0xFF ) { // error
2013-11-07 19:33:13 +00:00
xprintf ( " adb_host_kbd_recv: ERROR(%d) \n " , codes ) ;
2016-05-19 18:30:46 +00:00
// something wrong or plug-in
matrix_init ( ) ;
2012-09-20 03:52:45 +00:00
return key1 ;
2011-01-12 16:26:33 +00:00
} else {
2016-05-19 07:26:01 +00:00
/* Swap codes for ISO keyboard
*
* ANSI
* , - - - - - - - - - - - - - - - - - - - - - .
* | * a | 1 | 2 = | Backspa |
* | - - - - - - - - - - - - - - - - - - - - - |
* | Tab | Q | | ] | * c |
* | - - - - - - - - - - - - - - - - - - - - - |
* | CapsLo | A | ' | Return |
* | - - - - - - - - - - - - - - - - - - - - - |
* | Shift | Shift |
* ` - - - - - - - - - - - - - - - - - - - - - '
*
* ISO
* , - - - - - - - - - - - - - - - - - - - - - .
* | * a | 1 | 2 = | Backspa |
* | - - - - - - - - - - - - - - - - - - - - - |
* | Tab | Q | | ] | Retur |
* | - - - - - - - - - - - - - - - - ` |
* | CapsLo | A | ' | * c | |
* | - - - - - - - - - - - - - - - - - - - - - |
* | Shif | * b | Shift |
* ` - - - - - - - - - - - - - - - - - - - - - '
*
* ADB scan code USB usage
* - - - - - - - - - - - - - - - - - - - - - -
* Key ANSI ISO ANSI ISO
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* * a 0x32 0x0A 0x35 0x35
* * b - - - - 0x32 - - - - 0x64
* * c 0x2A 0x2A 0x31 0x31 ( or 0x32 )
*/
if ( is_iso_layout ) {
if ( key0 = = 0x32 ) {
key0 = 0x0A ;
} else if ( key0 = = 0x0A ) {
key0 = 0x32 ;
}
}
2012-09-20 03:52:45 +00:00
register_key ( key0 ) ;
2011-01-12 16:26:33 +00:00
if ( key1 ! = 0xFF ) // key1 is 0xFF when no second key.
2013-11-26 21:21:43 +00:00
extra_key = key1 < < 8 | 0xFF ; // process in a separate call
2011-01-12 16:26:33 +00:00
}
return 1 ;
}
bool matrix_is_modified ( void )
{
2012-09-20 03:52:45 +00:00
return is_modified ;
2011-01-12 16:26:33 +00:00
}
inline
bool matrix_has_ghost ( void )
{
# ifdef MATRIX_HAS_GHOST
for ( uint8_t i = 0 ; i < MATRIX_ROWS ; i + + ) {
if ( matrix_has_ghost_in_row ( i ) )
return true ;
}
# endif
return false ;
}
inline
bool matrix_is_on ( uint8_t row , uint8_t col )
{
return ( matrix [ row ] & ( 1 < < col ) ) ;
}
inline
# if (MATRIX_COLS <= 8)
uint8_t matrix_get_row ( uint8_t row )
# else
uint16_t matrix_get_row ( uint8_t row )
# endif
{
return matrix [ row ] ;
}
void matrix_print ( void )
{
2012-09-20 03:52:45 +00:00
if ( ! debug_matrix ) return ;
2011-01-12 16:26:33 +00:00
# if (MATRIX_COLS <= 8)
2012-06-18 03:23:17 +00:00
print ( " r/c 01234567 \n " ) ;
2011-01-12 16:26:33 +00:00
# else
2012-06-18 03:23:17 +00:00
print ( " r/c 0123456789ABCDEF \n " ) ;
2011-01-12 16:26:33 +00:00
# endif
for ( uint8_t row = 0 ; row < matrix_rows ( ) ; row + + ) {
phex ( row ) ; print ( " : " ) ;
# if (MATRIX_COLS <= 8)
pbin_reverse ( matrix_get_row ( row ) ) ;
# else
pbin_reverse16 ( matrix_get_row ( row ) ) ;
# endif
# ifdef MATRIX_HAS_GHOST
if ( matrix_has_ghost_in_row ( row ) ) {
print ( " <ghost " ) ;
}
# endif
print ( " \n " ) ;
}
}
uint8_t matrix_key_count ( void )
{
uint8_t count = 0 ;
for ( uint8_t i = 0 ; i < MATRIX_ROWS ; i + + ) {
# if (MATRIX_COLS <= 8)
count + = bitpop ( matrix [ i ] ) ;
# else
count + = bitpop16 ( matrix [ i ] ) ;
# endif
}
return count ;
}
# ifdef MATRIX_HAS_GHOST
inline
static bool matrix_has_ghost_in_row ( uint8_t row )
{
// no ghost exists in case less than 2 keys on
if ( ( ( matrix [ row ] - 1 ) & matrix [ row ] ) = = 0 )
return false ;
// ghost exists in case same state as other row
for ( uint8_t i = 0 ; i < MATRIX_ROWS ; i + + ) {
if ( i ! = row & & ( matrix [ i ] & matrix [ row ] ) = = matrix [ row ] )
return true ;
}
return false ;
}
# endif
inline
2012-09-20 03:52:45 +00:00
static void register_key ( uint8_t key )
2011-01-12 16:26:33 +00:00
{
uint8_t col , row ;
col = key & 0x07 ;
row = ( key > > 3 ) & 0x0F ;
if ( key & 0x80 ) {
matrix [ row ] & = ~ ( 1 < < col ) ;
} else {
matrix [ row ] | = ( 1 < < col ) ;
}
2012-09-20 03:52:45 +00:00
is_modified = true ;
2011-01-12 16:26:33 +00:00
}