2012-02-10 16:56:31 +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/>.
*/
# include <stdint.h>
# include <stdbool.h>
# include <avr/io.h>
# include <util/delay.h>
# include "print.h"
# include "util.h"
# include "debug.h"
# include "ps2.h"
# include "matrix.h"
static void matrix_make ( uint8_t code ) ;
static void matrix_break ( uint8_t code ) ;
# ifdef MATRIX_HAS_GHOST
static bool matrix_has_ghost_in_row ( uint8_t row ) ;
# endif
/*
* Matrix Array usage :
* ' Scan Code Set 3 ' is assigned into 17 x8 cell matrix .
*
* 8 bit wide
* + - - - - - - - - - +
* 0 | |
* : | | 0x00 - 0x87
* ; | |
* 17 | |
* + - - - - - - - - - +
*/
static uint8_t matrix [ MATRIX_ROWS ] ;
# define ROW(code) (code>>3)
# define COL(code) (code&0x07)
static bool is_modified = false ;
inline
uint8_t matrix_rows ( void )
{
return MATRIX_ROWS ;
}
inline
uint8_t matrix_cols ( void )
{
return MATRIX_COLS ;
}
void matrix_init ( void )
{
debug_enable = true ;
//debug_matrix = true;
//debug_keyboard = true;
//debug_mouse = false;
ps2_host_init ( ) ;
// initialize matrix state: all keys off
for ( uint8_t i = 0 ; i < MATRIX_ROWS ; i + + ) matrix [ i ] = 0x00 ;
return ;
}
uint8_t matrix_scan ( void )
{
// scan code reading states
static enum {
2013-05-04 05:46:42 +00:00
RESET ,
RESET_RESPONSE ,
KBD_ID0 ,
KBD_ID1 ,
CONFIG ,
READY ,
2012-02-10 16:56:31 +00:00
F0 ,
2013-05-04 05:46:42 +00:00
} state = RESET ;
2012-02-10 16:56:31 +00:00
is_modified = false ;
uint8_t code ;
2013-05-04 05:46:42 +00:00
if ( ( code = ps2_host_recv ( ) ) ) {
debug ( " r " ) ; debug_hex ( code ) ; debug ( " " ) ;
}
switch ( state ) {
case RESET :
debug ( " wFF " ) ;
if ( ps2_host_send ( 0xFF ) = = 0xFA ) {
debug ( " [ack] \n RESET_RESPONSE: " ) ;
state = RESET_RESPONSE ;
}
break ;
case RESET_RESPONSE :
if ( code = = 0xAA ) {
debug ( " [ok] \n KBD_ID: " ) ;
state = KBD_ID0 ;
} else if ( code ) {
debug ( " err \n RESET: " ) ;
state = RESET ;
}
break ;
// after reset receive keyboad ID(2 bytes)
case KBD_ID0 :
if ( code ) {
state = KBD_ID1 ;
}
break ;
case KBD_ID1 :
if ( code ) {
debug ( " \n CONFIG: " ) ;
state = CONFIG ;
}
break ;
case CONFIG :
debug ( " wF8 " ) ;
if ( ps2_host_send ( 0xF8 ) = = 0xFA ) {
debug ( " [ack] \n READY \n " ) ;
state = READY ;
}
break ;
case READY :
switch ( code ) {
case 0x00 :
break ;
case 0xF0 :
state = F0 ;
debug ( " " ) ;
break ;
default : // normal key make
if ( code < 0x88 ) {
matrix_make ( code ) ;
} else {
debug ( " unexpected scan code at READY: " ) ; debug_hex ( code ) ; debug ( " \n " ) ;
}
state = READY ;
debug ( " \n " ) ;
}
break ;
case F0 : // Break code
switch ( code ) {
case 0x00 :
break ;
default :
2012-02-10 16:56:31 +00:00
if ( code < 0x88 ) {
matrix_break ( code ) ;
} else {
debug ( " unexpected scan code at F0: " ) ; debug_hex ( code ) ; debug ( " \n " ) ;
}
2013-05-04 05:46:42 +00:00
state = READY ;
2012-02-10 16:56:31 +00:00
debug ( " \n " ) ;
2013-05-04 05:46:42 +00:00
}
break ;
2012-02-10 16:56:31 +00:00
}
return 1 ;
}
bool matrix_is_modified ( void )
{
return is_modified ;
}
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
uint8_t matrix_get_row ( uint8_t row )
{
return matrix [ row ] ;
}
void matrix_print ( void )
{
print ( " \n r/c 01234567 \n " ) ;
for ( uint8_t row = 0 ; row < matrix_rows ( ) ; row + + ) {
phex ( row ) ; print ( " : " ) ;
pbin_reverse ( matrix_get_row ( row ) ) ;
# 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 + + ) {
count + = bitpop ( matrix [ i ] ) ;
}
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
static void matrix_make ( uint8_t code )
{
if ( ! matrix_is_on ( ROW ( code ) , COL ( code ) ) ) {
matrix [ ROW ( code ) ] | = 1 < < COL ( code ) ;
is_modified = true ;
}
}
inline
static void matrix_break ( uint8_t code )
{
if ( matrix_is_on ( ROW ( code ) , COL ( code ) ) ) {
matrix [ ROW ( code ) ] & = ~ ( 1 < < COL ( code ) ) ;
is_modified = true ;
}
}