2011-09-17 13:39:50 +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/>.
*/
/* host driver for Bulegiga iWRAP */
/* Bluegiga BT12
* Connections
* Hardware UART Software UART BlueTooth
* PC = = = = = UART = = = = = = = AVR = = = = = SUART = = = = iWRAP ( BT12 ) - - - - - - - - - - - PC
*
* - Hardware UART for Debug Console to communicate iWRAP
* - Software UART for iWRAP control to send keyboard / mouse data
*/
# include <stdint.h>
# include <string.h>
# include <avr/interrupt.h>
# include <util/delay.h>
2012-10-17 12:43:44 +00:00
# include "keycode.h"
2011-09-17 13:39:50 +00:00
# include "suart.h"
# include "uart.h"
# include "report.h"
# include "host_driver.h"
# include "iwrap.h"
# include "print.h"
/* iWRAP MUX mode utils. 3.10 HID raw mode(iWRAP_HID_Application_Note.pdf) */
# define MUX_HEADER(LINK, LENGTH) do { \
xmit ( 0xbf ) ; /* SOF */ \
xmit ( LINK ) ; /* Link */ \
xmit ( 0x00 ) ; /* Flags */ \
xmit ( LENGTH ) ; /* Length */ \
} while ( 0 )
# define MUX_FOOTER(LINK) xmit(LINK^0xff)
static uint8_t connected = 0 ;
//static uint8_t channel = 1;
/* iWRAP buffer */
# define MUX_BUF_SIZE 64
static char buf [ MUX_BUF_SIZE ] ;
static uint8_t snd_pos = 0 ;
# define MUX_RCV_BUF_SIZE 256
static char rcv_buf [ MUX_RCV_BUF_SIZE ] ;
static uint8_t rcv_head = 0 ;
static uint8_t rcv_tail = 0 ;
/* receive buffer */
static void rcv_enq ( char c )
{
uint8_t next = ( rcv_head + 1 ) % MUX_RCV_BUF_SIZE ;
if ( next ! = rcv_tail ) {
rcv_buf [ rcv_head ] = c ;
rcv_head = next ;
}
}
static char rcv_deq ( void )
{
char c = 0 ;
if ( rcv_head ! = rcv_tail ) {
c = rcv_buf [ rcv_tail + + ] ;
rcv_tail % = MUX_RCV_BUF_SIZE ;
}
return c ;
}
/*
static char rcv_peek ( void )
{
if ( rcv_head = = rcv_tail )
return 0 ;
return rcv_buf [ rcv_tail ] ;
}
*/
static void rcv_clear ( void )
{
rcv_tail = rcv_head = 0 ;
}
/* iWRAP response */
ISR ( PCINT1_vect , ISR_BLOCK ) // recv() runs away in case of ISR_NOBLOCK
{
if ( ( SUART_IN_PIN & ( 1 < < SUART_IN_BIT ) ) )
return ;
static volatile uint8_t mux_state = 0xff ;
static volatile uint8_t mux_link = 0xff ;
uint8_t c = recv ( ) ;
switch ( mux_state ) {
case 0xff : // SOF
if ( c = = 0xbf )
mux_state - - ;
break ;
case 0xfe : // Link
mux_state - - ;
mux_link = c ;
break ;
case 0xfd : // Flags
mux_state - - ;
break ;
case 0xfc : // Length
mux_state = c ;
break ;
case 0x00 :
mux_state = 0xff ;
mux_link = 0xff ;
break ;
default :
if ( mux_state - - ) {
uart_putchar ( c ) ;
rcv_enq ( c ) ;
}
}
}
/*------------------------------------------------------------------*
* iWRAP communication
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
void iwrap_init ( void )
{
// reset iWRAP if in already MUX mode after AVR software-reset
iwrap_send ( " RESET " ) ;
iwrap_mux_send ( " RESET " ) ;
_delay_ms ( 3000 ) ;
iwrap_send ( " \r \n SET CONTROL MUX 1 \r \n " ) ;
_delay_ms ( 500 ) ;
iwrap_check_connection ( ) ;
}
void iwrap_mux_send ( const char * s )
{
rcv_clear ( ) ;
MUX_HEADER ( 0xff , strlen ( ( char * ) s ) ) ;
iwrap_send ( s ) ;
MUX_FOOTER ( 0xff ) ;
}
void iwrap_send ( const char * s )
{
while ( * s )
xmit ( * s + + ) ;
}
/* send buffer */
void iwrap_buf_add ( uint8_t c )
{
// need space for '\0'
if ( snd_pos < MUX_BUF_SIZE - 1 )
buf [ snd_pos + + ] = c ;
}
void iwrap_buf_del ( void )
{
if ( snd_pos )
snd_pos - - ;
}
void iwrap_buf_send ( void )
{
buf [ snd_pos ] = ' \0 ' ;
snd_pos = 0 ;
iwrap_mux_send ( buf ) ;
}
void iwrap_call ( void )
{
char * p ;
iwrap_mux_send ( " SET BT PAIR " ) ;
_delay_ms ( 500 ) ;
p = rcv_buf + rcv_tail ;
while ( ! strncmp ( p , " SET BT PAIR " , 11 ) ) {
p + = 7 ;
strncpy ( p , " CALL " , 4 ) ;
strncpy ( p + 22 , " 11 HID \n \0 " , 9 ) ;
print_S ( p ) ;
iwrap_mux_send ( p ) ;
// TODO: skip to next line
p + = 57 ;
DEBUG_LED_CONFIG ;
DEBUG_LED_ON ;
_delay_ms ( 500 ) ;
DEBUG_LED_OFF ;
_delay_ms ( 500 ) ;
DEBUG_LED_ON ;
_delay_ms ( 500 ) ;
DEBUG_LED_OFF ;
_delay_ms ( 500 ) ;
DEBUG_LED_ON ;
_delay_ms ( 500 ) ;
DEBUG_LED_OFF ;
_delay_ms ( 500 ) ;
DEBUG_LED_ON ;
_delay_ms ( 500 ) ;
DEBUG_LED_OFF ;
_delay_ms ( 500 ) ;
DEBUG_LED_ON ;
_delay_ms ( 500 ) ;
DEBUG_LED_OFF ;
_delay_ms ( 500 ) ;
}
iwrap_check_connection ( ) ;
}
void iwrap_kill ( void )
{
char c ;
iwrap_mux_send ( " LIST " ) ;
_delay_ms ( 500 ) ;
while ( ( c = rcv_deq ( ) ) & & c ! = ' \n ' ) ;
if ( strncmp ( rcv_buf + rcv_tail , " LIST " , 5 ) ) {
print ( " no connection to kill. \n " ) ;
return ;
}
// skip 10 'space' chars
for ( uint8_t i = 10 ; i ; i - - )
while ( ( c = rcv_deq ( ) ) & & c ! = ' ' ) ;
char * p = rcv_buf + rcv_tail - 5 ;
strncpy ( p , " KILL " , 5 ) ;
strncpy ( p + 22 , " \n \0 " , 2 ) ;
print_S ( p ) ;
iwrap_mux_send ( p ) ;
_delay_ms ( 500 ) ;
iwrap_check_connection ( ) ;
}
void iwrap_unpair ( void )
{
iwrap_mux_send ( " SET BT PAIR " ) ;
_delay_ms ( 500 ) ;
char * p = rcv_buf + rcv_tail ;
if ( ! strncmp ( p , " SET BT PAIR " , 11 ) ) {
strncpy ( p + 29 , " \n \0 " , 2 ) ;
print_S ( p ) ;
iwrap_mux_send ( p ) ;
}
}
void iwrap_sleep ( void )
{
iwrap_mux_send ( " SLEEP " ) ;
}
void iwrap_sniff ( void )
{
}
void iwrap_subrate ( void )
{
}
bool iwrap_failed ( void )
{
if ( strncmp ( rcv_buf , " SYNTAX ERROR " , 12 ) )
return true ;
else
return false ;
}
uint8_t iwrap_connected ( void )
{
return connected ;
}
uint8_t iwrap_check_connection ( void )
{
iwrap_mux_send ( " LIST " ) ;
_delay_ms ( 100 ) ;
if ( strncmp ( rcv_buf , " LIST " , 5 ) | | ! strncmp ( rcv_buf , " LIST 0 " , 6 ) )
connected = 0 ;
else
connected = 1 ;
return connected ;
}
/*------------------------------------------------------------------*
* Host driver
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
static uint8_t keyboard_leds ( void ) ;
static void send_keyboard ( report_keyboard_t * report ) ;
static void send_mouse ( report_mouse_t * report ) ;
static void send_system ( uint16_t data ) ;
static void send_consumer ( uint16_t data ) ;
static host_driver_t driver = {
keyboard_leds ,
send_keyboard ,
send_mouse ,
send_system ,
send_consumer
} ;
host_driver_t * iwrap_driver ( void )
{
return & driver ;
}
static uint8_t keyboard_leds ( void ) {
return 0 ;
}
static void send_keyboard ( report_keyboard_t * report )
{
if ( ! iwrap_connected ( ) & & ! iwrap_check_connection ( ) ) return ;
MUX_HEADER ( 0x01 , 0x0c ) ;
// HID raw mode header
xmit ( 0x9f ) ;
xmit ( 0x0a ) ; // Length
2013-04-18 06:51:14 +00:00
xmit ( 0xa1 ) ; // DATA(Input)
2013-04-19 14:43:52 +00:00
xmit ( 0x01 ) ; // Report ID
2011-09-17 13:39:50 +00:00
xmit ( report - > mods ) ;
xmit ( 0x00 ) ; // reserved byte(always 0)
xmit ( report - > keys [ 0 ] ) ;
xmit ( report - > keys [ 1 ] ) ;
xmit ( report - > keys [ 2 ] ) ;
xmit ( report - > keys [ 3 ] ) ;
xmit ( report - > keys [ 4 ] ) ;
xmit ( report - > keys [ 5 ] ) ;
MUX_FOOTER ( 0x01 ) ;
}
static void send_mouse ( report_mouse_t * report )
{
# if defined(MOUSEKEY_ENABLE) || defined(PS2_MOUSE_ENABLE)
if ( ! iwrap_connected ( ) & & ! iwrap_check_connection ( ) ) return ;
2013-04-19 14:43:52 +00:00
MUX_HEADER ( 0x01 , 0x09 ) ;
2011-09-17 13:39:50 +00:00
// HID raw mode header
xmit ( 0x9f ) ;
2013-04-19 14:43:52 +00:00
xmit ( 0x07 ) ; // Length
2013-04-18 06:51:14 +00:00
xmit ( 0xa1 ) ; // DATA(Input)
2013-04-19 14:43:52 +00:00
xmit ( 0x02 ) ; // Report ID
xmit ( report - > buttons ) ;
2011-09-17 13:39:50 +00:00
xmit ( report - > x ) ;
xmit ( report - > y ) ;
2013-04-19 14:43:52 +00:00
xmit ( report - > v ) ;
xmit ( report - > h ) ;
2011-09-17 13:39:50 +00:00
MUX_FOOTER ( 0x01 ) ;
# endif
}
static void send_system ( uint16_t data )
{
/* not supported */
}
static void send_consumer ( uint16_t data )
{
# ifdef EXTRAKEY_ENABLE
static uint16_t last_data = 0 ;
uint8_t bits1 = 0 ;
uint8_t bits2 = 0 ;
uint8_t bits3 = 0 ;
if ( ! iwrap_connected ( ) & & ! iwrap_check_connection ( ) ) return ;
if ( data = = last_data ) return ;
last_data = data ;
// 3.10 HID raw mode(iWRAP_HID_Application_Note.pdf)
switch ( data ) {
case AUDIO_VOL_UP :
bits1 = 0x01 ;
break ;
case AUDIO_VOL_DOWN :
bits1 = 0x02 ;
break ;
case AUDIO_MUTE :
bits1 = 0x04 ;
break ;
case TRANSPORT_PLAY_PAUSE :
bits1 = 0x08 ;
break ;
case TRANSPORT_NEXT_TRACK :
bits1 = 0x10 ;
break ;
case TRANSPORT_PREV_TRACK :
bits1 = 0x20 ;
break ;
case TRANSPORT_STOP :
bits1 = 0x40 ;
break ;
case TRANSPORT_EJECT :
bits1 = 0x80 ;
break ;
case AL_EMAIL :
bits2 = 0x01 ;
break ;
case AC_SEARCH :
bits2 = 0x02 ;
break ;
case AC_BOOKMARKS :
bits2 = 0x04 ;
break ;
case AC_HOME :
bits2 = 0x08 ;
break ;
case AC_BACK :
bits2 = 0x10 ;
break ;
case AC_FORWARD :
bits2 = 0x20 ;
break ;
case AC_STOP :
bits2 = 0x40 ;
break ;
case AC_REFRESH :
bits2 = 0x80 ;
break ;
case AL_CC_CONFIG :
bits3 = 0x01 ;
break ;
case AL_CALCULATOR :
bits3 = 0x04 ;
break ;
case AL_LOCK :
bits3 = 0x08 ;
break ;
case AL_LOCAL_BROWSER :
bits3 = 0x10 ;
break ;
case AC_MINIMIZE :
bits3 = 0x20 ;
break ;
case TRANSPORT_RECORD :
bits3 = 0x40 ;
break ;
case TRANSPORT_REWIND :
bits3 = 0x80 ;
break ;
}
MUX_HEADER ( 0x01 , 0x07 ) ;
xmit ( 0x9f ) ;
xmit ( 0x05 ) ; // Length
2013-04-18 06:51:14 +00:00
xmit ( 0xa1 ) ; // DATA(Input)
2013-04-19 14:43:52 +00:00
xmit ( 0x03 ) ; // Report ID
2011-09-17 13:39:50 +00:00
xmit ( bits1 ) ;
xmit ( bits2 ) ;
xmit ( bits3 ) ;
MUX_FOOTER ( 0x01 ) ;
# endif
}