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/>.
*/
2010-10-09 16:50:36 +00:00
/*
* scan matrix
*/
2010-10-27 11:51:45 +00:00
# include <stdint.h>
# include <stdbool.h>
2010-10-09 16:50:36 +00:00
# include <util/delay.h>
2012-10-17 12:43:44 +00:00
# include "print.h"
2012-12-15 17:32:07 +00:00
# include "debug.h"
2010-10-27 11:51:45 +00:00
# include "util.h"
2011-09-17 13:39:50 +00:00
# include "timer.h"
2011-02-21 16:21:53 +00:00
# include "matrix.h"
2014-07-09 06:31:52 +00:00
# include "hhkb_avr.h"
2015-01-16 01:21:18 +00:00
# include <avr/wdt.h>
# include "suspend.h"
# include "lufa.h"
2011-09-17 13:39:50 +00:00
2011-01-06 06:18:55 +00:00
2015-01-16 01:21:18 +00:00
// matrix power saving
# define MATRIX_POWER_SAVE 10000
static uint32_t matrix_last_modified = 0 ;
2011-01-06 06:18:55 +00:00
// matrix state buffer(1:on, 0:off)
2012-10-05 17:23:12 +00:00
static matrix_row_t * matrix ;
static matrix_row_t * matrix_prev ;
static matrix_row_t _matrix0 [ MATRIX_ROWS ] ;
static matrix_row_t _matrix1 [ MATRIX_ROWS ] ;
2011-01-06 06:18:55 +00:00
2010-10-23 16:17:26 +00:00
inline
2011-01-06 06:18:55 +00:00
uint8_t matrix_rows ( void )
2010-10-26 12:32:45 +00:00
{
2010-10-23 16:17:26 +00:00
return MATRIX_ROWS ;
}
inline
2011-01-06 06:18:55 +00:00
uint8_t matrix_cols ( void )
2010-10-26 12:32:45 +00:00
{
2010-10-23 16:17:26 +00:00
return MATRIX_COLS ;
}
2010-10-09 16:50:36 +00:00
void matrix_init ( void )
{
2012-12-15 17:32:07 +00:00
# ifdef DEBUG
debug_enable = true ;
debug_keyboard = true ;
# endif
2011-05-15 15:08:06 +00:00
KEY_INIT ( ) ;
2010-10-09 16:50:36 +00:00
// initialize matrix state: all keys off
2011-01-06 06:18:55 +00:00
for ( uint8_t i = 0 ; i < MATRIX_ROWS ; i + + ) _matrix0 [ i ] = 0x00 ;
for ( uint8_t i = 0 ; i < MATRIX_ROWS ; i + + ) _matrix1 [ i ] = 0x00 ;
2010-10-09 16:50:36 +00:00
matrix = _matrix0 ;
matrix_prev = _matrix1 ;
}
2011-01-06 06:18:55 +00:00
uint8_t matrix_scan ( void )
2010-10-09 16:50:36 +00:00
{
uint8_t * tmp ;
tmp = matrix_prev ;
matrix_prev = matrix ;
matrix = tmp ;
2015-01-16 01:21:18 +00:00
// power on
if ( ! KEY_POWER_STATE ( ) ) KEY_POWER_ON ( ) ;
2011-01-06 06:18:55 +00:00
for ( uint8_t row = 0 ; row < MATRIX_ROWS ; row + + ) {
for ( uint8_t col = 0 ; col < MATRIX_COLS ; col + + ) {
2011-05-15 15:08:06 +00:00
KEY_SELECT ( row , col ) ;
2014-07-09 06:31:52 +00:00
_delay_us ( 5 ) ;
2011-09-17 13:39:50 +00:00
// Not sure this is needed. This just emulates HHKB controller's behaviour.
2010-11-05 16:58:47 +00:00
if ( matrix_prev [ row ] & ( 1 < < col ) ) {
2011-05-15 15:08:06 +00:00
KEY_PREV_ON ( ) ;
2010-11-05 16:58:47 +00:00
}
2014-07-09 06:31:52 +00:00
_delay_us ( 10 ) ;
2011-09-17 13:39:50 +00:00
// NOTE: KEY_STATE is valid only in 20us after KEY_ENABLE.
// If V-USB interrupts in this section we could lose 40us or so
// and would read invalid value from KEY_STATE.
uint8_t last = TIMER_RAW ;
2011-05-15 15:08:06 +00:00
KEY_ENABLE ( ) ;
2013-07-08 05:38:03 +00:00
2011-09-17 13:39:50 +00:00
// Wait for KEY_STATE outputs its value.
// 1us was ok on one HHKB, but not worked on another.
2013-07-03 02:02:33 +00:00
// no wait doesn't work on Teensy++ with pro(1us works)
// no wait does work on tmk PCB(8MHz) with pro2
// 1us wait does work on both of above
2013-07-08 05:38:03 +00:00
// 1us wait doesn't work on tmk(16MHz)
// 5us wait does work on tmk(16MHz)
// 5us wait does work on tmk(16MHz/2)
// 5us wait does work on tmk(8MHz)
2013-07-03 02:02:33 +00:00
// 10us wait does work on Teensy++ with pro
// 10us wait does work on 328p+iwrap with pro
// 10us wait doesn't work on tmk PCB(8MHz) with pro2(very lagged scan)
2013-07-08 05:38:03 +00:00
_delay_us ( 5 ) ;
2011-05-15 15:08:06 +00:00
if ( KEY_STATE ( ) ) {
2010-10-26 12:32:45 +00:00
matrix [ row ] & = ~ ( 1 < < col ) ;
2010-11-05 16:58:47 +00:00
} else {
matrix [ row ] | = ( 1 < < col ) ;
2010-10-09 16:50:36 +00:00
}
2011-09-17 13:39:50 +00:00
// Ignore if this code region execution time elapses more than 20us.
2012-10-05 17:23:12 +00:00
// MEMO: 20[us] * (TIMER_RAW_FREQ / 1000000)[count per us]
// MEMO: then change above using this rule: a/(b/c) = a*1/(b/c) = a*(c/b)
2011-09-17 13:39:50 +00:00
if ( TIMER_DIFF_RAW ( TIMER_RAW , last ) > 20 / ( 1000000 / TIMER_RAW_FREQ ) ) {
matrix [ row ] = matrix_prev [ row ] ;
}
2011-05-15 15:08:06 +00:00
2014-07-09 06:31:52 +00:00
_delay_us ( 5 ) ;
2011-05-15 15:08:06 +00:00
KEY_PREV_OFF ( ) ;
KEY_UNABLE ( ) ;
2014-07-09 06:31:52 +00:00
2011-09-17 13:39:50 +00:00
// NOTE: KEY_STATE keep its state in 20us after KEY_ENABLE.
// This takes 25us or more to make sure KEY_STATE returns to idle state.
2015-05-13 07:53:32 +00:00
# ifdef HHKB_JP
// Looks like JP needs faster scan due to its twice larger matrix
// or it can drop keys in fast key typing
_delay_us ( 30 ) ;
# else
2014-07-09 06:31:52 +00:00
_delay_us ( 75 ) ;
2015-05-13 07:53:32 +00:00
# endif
2010-10-09 16:50:36 +00:00
}
2015-01-16 01:21:18 +00:00
if ( matrix [ row ] ^ matrix_prev [ row ] ) matrix_last_modified = timer_read32 ( ) ;
}
// power off
if ( KEY_POWER_STATE ( ) & &
( USB_DeviceState = = DEVICE_STATE_Suspended | |
USB_DeviceState = = DEVICE_STATE_Unattached ) & &
timer_elapsed32 ( matrix_last_modified ) > MATRIX_POWER_SAVE ) {
KEY_POWER_OFF ( ) ;
suspend_power_down ( ) ;
2010-10-09 16:50:36 +00:00
}
return 1 ;
}
2010-10-26 12:32:45 +00:00
bool matrix_is_modified ( void )
{
2011-01-06 06:18:55 +00:00
for ( uint8_t i = 0 ; i < MATRIX_ROWS ; i + + ) {
2010-10-09 16:50:36 +00:00
if ( matrix [ i ] ! = matrix_prev [ i ] )
return true ;
}
return false ;
}
2010-10-23 16:17:26 +00:00
inline
2010-10-26 12:32:45 +00:00
bool matrix_has_ghost ( void )
{
2010-10-09 16:50:36 +00:00
return false ;
}
2010-10-23 16:17:26 +00:00
inline
2011-01-06 06:18:55 +00:00
bool matrix_is_on ( uint8_t row , uint8_t col )
2010-10-26 12:32:45 +00:00
{
return ( matrix [ row ] & ( 1 < < col ) ) ;
}
inline
2013-05-14 14:06:07 +00:00
matrix_row_t matrix_get_row ( uint8_t row )
2010-10-26 12:32:45 +00:00
{
2010-10-23 16:17:26 +00:00
return matrix [ row ] ;
}
2012-10-17 12:43:44 +00:00
void matrix_print ( void )
2010-10-26 12:32:45 +00:00
{
2012-10-17 12:43:44 +00:00
print ( " \n r/c 01234567 \n " ) ;
2011-01-06 06:18:55 +00:00
for ( uint8_t row = 0 ; row < matrix_rows ( ) ; row + + ) {
2013-05-14 14:06:07 +00:00
xprintf ( " %02X: %08b \n " , row , bitrev ( matrix_get_row ( row ) ) ) ;
2010-10-23 18:27:43 +00:00
}
}
2015-01-16 01:21:18 +00:00
void matrix_power_up ( void ) {
KEY_POWER_ON ( ) ;
}
void matrix_power_down ( void ) {
KEY_POWER_OFF ( ) ;
}