2011-07-18 22:33:40 +02:00
/*
2011-07-23 21:32:08 +02:00
* ( c ) 2011 Siegen , Germany by Nils Faerber < nils . faerber @ kernelconcepts . de >
2011-07-18 22:33:40 +02:00
*
2011-07-23 19:08:06 +02:00
* license LGPL
2011-07-18 22:33:40 +02:00
*/
2011-07-23 21:32:08 +02:00
2011-07-18 22:33:40 +02:00
# include <stdio.h>
# include <sys/types.h>
# include <sys/stat.h>
# include <fcntl.h>
2011-07-19 14:13:11 +02:00
# include <unistd.h>
# include <stdlib.h>
2011-07-19 12:31:32 +02:00
# include <string.h>
# include <time.h>
2011-07-19 14:13:11 +02:00
# include <termios.h>
2011-07-23 21:32:08 +02:00
# include <ctype.h>
2011-07-18 22:33:40 +02:00
2011-07-24 17:27:28 +02:00
# include "metawatch.h"
2011-07-18 22:33:40 +02:00
# include "metawatch_protocol.h"
2011-07-19 12:31:32 +02:00
# include "crc16ccitt.h"
2011-07-24 17:27:28 +02:00
# ifdef DEBUG
const char * mw_screen_mode_names [ ] = {
" idle screen " ,
" application screen " ,
" notification screen " ,
" scroll "
} ;
const char * mw_status_string [ ] = {
" Reserved " ,
" Mode Change " ,
" Display Timeout "
} ;
# endif
2011-07-23 19:08:06 +02:00
# define MW_FRAME_DELAY 0x00
2011-07-19 12:31:32 +02:00
void dump_frame ( unsigned char * frame , int len )
{
2011-07-23 17:56:24 +02:00
int i ;
for ( i = 0 ; i < len ; i + + )
fprintf ( stderr , " 0x%02x " , frame [ i ] ) ;
fprintf ( stderr , " \n " ) ;
2011-07-19 12:31:32 +02:00
}
2011-07-23 18:26:16 +02:00
int mw_send_frame ( int mw_fd , unsigned char msg_type , unsigned char options , unsigned char * data , unsigned char len )
2011-07-19 12:31:32 +02:00
{
2011-07-23 17:56:24 +02:00
unsigned short crc ;
unsigned char frame [ 64 ] ;
int tlen = len + 6 ; /* payload + 6 bytes frameing */
int ret ;
memset ( frame , 0 , 64 ) ;
frame [ 0 ] = MW_SOF ;
frame [ 1 ] = len + 6 ;
frame [ 2 ] = msg_type ;
frame [ 3 ] = options ;
if ( data ! = NULL & & len > 0 )
memcpy ( frame + 4 , data , len ) ;
2011-07-19 12:31:32 +02:00
2011-07-23 17:56:24 +02:00
crc = crc16ccitt ( frame , len + 4 ) ;
* ( unsigned short * ) ( frame + len + 4 ) = crc ;
2011-07-19 12:31:32 +02:00
2011-07-23 21:32:08 +02:00
# ifdef DEBUG
2011-07-23 17:56:24 +02:00
dump_frame ( frame , tlen ) ;
2011-07-23 21:32:08 +02:00
# endif
2011-07-19 14:13:11 +02:00
2011-07-23 17:56:24 +02:00
while ( ( ( ret = write ( mw_fd , frame , tlen ) ) > = 0 ) & & ( tlen > 0 ) )
tlen - = ret ;
2011-07-23 19:08:06 +02:00
if ( MW_FRAME_DELAY )
usleep ( MW_FRAME_DELAY ) ;
2011-07-23 17:56:24 +02:00
if ( tlen = = 0 & & ret > = 0 )
return 0 ;
else
return ret ;
2011-07-19 12:31:32 +02:00
}
2011-07-24 17:27:28 +02:00
/* ----------------------------------------------------------------------
* Host to watch commands
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
2011-07-23 17:56:24 +02:00
2011-07-19 12:31:32 +02:00
void mw_set_rtc ( int mw_fd , unsigned char clk1224 , unsigned char date_fmt )
{
2011-07-23 17:56:24 +02:00
time_t mtime ;
struct tm mtm ;
unsigned short year ;
unsigned char data [ 32 ] ;
mtime = time ( NULL ) ;
localtime_r ( & mtime , & mtm ) ;
year = mtm . tm_year + 1900 ;
data [ 0 ] = ( year & 0x0f00 ) > > 8 ;
data [ 1 ] = ( year & 0x00ff ) ;
data [ 2 ] = mtm . tm_mon + 1 ;
data [ 3 ] = mtm . tm_mday ;
data [ 4 ] = mtm . tm_wday ;
data [ 5 ] = mtm . tm_hour ;
data [ 6 ] = mtm . tm_min ;
data [ 7 ] = mtm . tm_sec ;
data [ 8 ] = clk1224 ;
data [ 9 ] = date_fmt ;
2011-07-23 18:26:16 +02:00
mw_send_frame ( mw_fd , MW_SET_REAL_TIME_CLOCK , 0 , data , 10 ) ;
}
void mw_set_vibrate_mode ( int mw_fd , unsigned char enable , unsigned short on_time , unsigned short off_time , unsigned char cycles )
{
unsigned char mdata [ 7 ] ;
mdata [ 0 ] = enable ;
* ( unsigned short * ) ( mdata + 1 ) = on_time ; /* miliseconds */
* ( unsigned short * ) ( mdata + 3 ) = off_time ; /* miliseconds */
mdata [ 5 ] = cycles ;
mw_send_frame ( mw_fd , MW_SET_VIBRATE_MODE , 0 , mdata , 6 ) ;
}
void mw_configure_watch_mode ( int mw_fd , unsigned char mode , unsigned char save , unsigned char timeout , unsigned char invert )
{
unsigned char mdata [ 3 ] ;
mdata [ 0 ] = timeout ; /* seconds */
mdata [ 1 ] = invert ; /* 0=normal, 1=invert */
2011-07-23 21:32:08 +02:00
mw_send_frame ( mw_fd , MW_CONFIGURE_MODE , ( mode & 0x0f ) | ( ( save & 0x01 ) < < 4 ) , mdata , 2 ) ;
2011-07-23 18:26:16 +02:00
}
void mw_update_display ( int mw_fd , unsigned char mode , unsigned char copy )
{
2011-07-23 21:32:08 +02:00
mw_send_frame ( mw_fd , MW_UPDATE_DISPLAY , ( mode & 0x0f ) | ( ( copy & 0x01 ) < < 4 ) , NULL , 0 ) ;
2011-07-23 17:56:24 +02:00
}
2011-07-23 19:08:06 +02:00
void mw_load_template ( int mw_fd , unsigned char mode , unsigned char template_select )
{
mw_send_frame ( mw_fd , MW_LOAD_TEMPLATE , ( mode & 0x0f ) , & template_select , 1 ) ;
}
/*
* send line for screen - mode mode from * buffer to watch , starting at display row row_offset
*/
void mw_write_buffer ( int mw_fd ,
unsigned char mode ,
2011-07-23 21:32:08 +02:00
unsigned char numlines , /* number of lines, 0=two lines or 1=one line */
2011-07-23 19:08:06 +02:00
unsigned char row_offset , /* start at row_offset in display, e.g. lower part in idle @31 */
unsigned char * buffer , int buflen )
{
unsigned char mdata [ 32 ] ;
buflen = 12 * ( buflen / 12 ) ; /* crop to 12 bytes */
if ( ( numlines = = 0 & & buflen < 12 ) | | ( numlines = = 1 & & buflen < 24 ) ) {
fprintf ( stderr , " mw_write_buffer: bufferlen does not match number of lines \n " ) ;
return ;
} ;
memset ( mdata , 0 , 32 ) ;
mdata [ 0 ] = row_offset ;
memcpy ( ( mdata + 1 ) , buffer , 12 ) ;
2011-07-23 21:32:08 +02:00
if ( numlines = = 0 ) {
mdata [ 13 ] = row_offset + 1 ;
memcpy ( ( mdata + 14 ) , ( buffer + 12 ) , 12 ) ;
2011-07-23 19:08:06 +02:00
} ;
2011-07-23 21:32:08 +02:00
mw_send_frame ( mw_fd , MW_WRITE_BUFFER , ( mode & 0x0f ) | ( ( ( numlines & 0x01 ) < < 4 ) & 0x10 ) , mdata , numlines ? 13 : 26 ) ;
2011-07-23 19:08:06 +02:00
}
2011-07-24 17:27:28 +02:00
/* ----------------------------------------------------------------------
* Watch responses , events or notifications
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
2011-07-23 19:08:06 +02:00
2011-07-23 17:56:24 +02:00
void mw_get_real_time_clock_response ( int mw_fd , unsigned char * rtcrsp , int len )
{
struct tm mtm ;
unsigned short year ;
unsigned char clk1224 , date_fmt ;
if ( len ! = 10 ) {
fprintf ( stderr , " get real time clock response too short %d != 10 \n " , len ) ;
return ;
}
year = * ( unsigned short * ) rtcrsp ;
mtm . tm_year = year - 1900 ;
mtm . tm_mon = rtcrsp [ 2 ] - 1 ;
mtm . tm_mday = rtcrsp [ 3 ] ;
mtm . tm_wday = rtcrsp [ 4 ] ;
mtm . tm_hour = rtcrsp [ 5 ] ;
mtm . tm_min = rtcrsp [ 6 ] ;
mtm . tm_sec = rtcrsp [ 7 ] ;
clk1224 = rtcrsp [ 8 ] ;
date_fmt = rtcrsp [ 9 ] ;
fprintf ( stderr , " watch RTC is %s, clock format is %s, date format is %s \n " , asctime ( & mtm ) , clk1224 ? " 24h " : " AM/PM " , date_fmt ? " DD/MM " : " MM/DD " ) ;
}
void mw_get_battery_voltage_response ( int mw_fd , unsigned char * batrsp , int len )
{
unsigned short voltage = * ( unsigned short * ) batrsp ;
unsigned char power_good = batrsp [ 2 ] ;
unsigned char bat_charging = batrsp [ 3 ] ;
fprintf ( stderr , " battery is at %dV, %s and %s \n " , voltage , power_good ? " power is good " : " power fault " , bat_charging ? " charging " : " not charging " ) ;
}
2011-07-30 17:22:05 +02:00
void mw_read_light_sensor_response ( int mw_fd , unsigned char * lightrsp , int len )
{
unsigned char power_good = lightrsp [ 0 ] ;
unsigned char bat_charging = lightrsp [ 1 ] ;
unsigned short voltage = * ( unsigned short * ) ( lightrsp + 2 ) ;
fprintf ( stderr , " light sensor is at %d, power stat: %s and %s \n " , voltage , power_good ? " power is good " : " power fault " , bat_charging ? " charging " : " not charging " ) ;
}
2011-07-23 21:32:08 +02:00
void mw_status_change_event ( int mw_fd , unsigned char option , unsigned char * statrsp , int len )
{
2011-07-30 17:22:05 +02:00
# ifdef DEBUG
2011-07-23 21:32:08 +02:00
fprintf ( stderr , " Status change event for mode %s: %s \n " , mw_screen_mode_names [ option & 0x0f ] , mw_status_string [ statrsp [ 0 ] ] ) ;
2011-07-30 17:22:05 +02:00
# endif
2011-07-23 21:32:08 +02:00
}
2011-07-24 17:27:28 +02:00
/* ----------------------------------------------------------------------
* Protocol handling
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
2011-07-23 18:26:16 +02:00
2011-07-23 17:56:24 +02:00
int decode_frame ( int mw_fd , unsigned char * buf , int len )
{
unsigned short crc ;
unsigned char msglen ;
unsigned char msgtype ;
unsigned char msgopt ;
unsigned char * msgdata ;
/* check frame */
crc = * ( unsigned short * ) ( buf + len - 2 ) ;
if ( crc ! = crc16ccitt ( buf , len - 2 ) ) {
fprintf ( stderr , " decode frame CRC error \n " ) ;
return 1 ;
2011-07-30 17:22:05 +02:00
}
# ifdef DEBUG
else
2011-07-23 17:56:24 +02:00
fprintf ( stderr , " decode frame CRC OK \n " ) ;
2011-07-30 17:22:05 +02:00
# endif
2011-07-23 17:56:24 +02:00
if ( buf [ 0 ] ! = MW_SOF ) {
fprintf ( stderr , " decode frame SOF not found \n " ) ;
return 1 ;
2011-07-30 17:22:05 +02:00
}
# ifdef DEBUG
else
2011-07-23 17:56:24 +02:00
fprintf ( stderr , " decode frame found SOF \n " ) ;
2011-07-30 17:22:05 +02:00
# endif
2011-07-23 17:56:24 +02:00
msglen = buf [ 1 ] ;
msgtype = buf [ 2 ] ;
msgopt = buf [ 3 ] ;
msgdata = ( buf + 4 ) ;
switch ( msgtype ) {
2011-07-30 17:22:05 +02:00
case MW_GET_DEVICE_TYPE_RSP :
fprintf ( stderr , " Got device type " ) ;
switch ( msgdata [ 0 ] ) {
case 0 :
fprintf ( stderr , " Reserved \n " ) ;
break ;
case 1 :
fprintf ( stderr , " Ana-Digi \n " ) ;
break ;
case 2 :
fprintf ( stderr , " Digital \n " ) ;
break ;
case 3 :
fprintf ( stderr , " Development Board Digital \n " ) ;
break ;
case 4 :
fprintf ( stderr , " Development Board Ana-Digi \n " ) ;
break ;
default :
fprintf ( stderr , " unknown %d \n " , msgdata [ 0 ] ) ;
break ;
} ;
2011-07-23 17:56:24 +02:00
break ;
case MW_GET_INFORMATION_STRING_RSP :
2011-07-30 17:22:05 +02:00
msgdata [ len - 2 ] = 0 ;
fprintf ( stderr , " Got info string '%s' \n " , msgdata ) ;
break ;
case MW_GET_REAL_TIME_CLOCK_RSP :
mw_get_real_time_clock_response ( mw_fd , msgdata , len - 2 ) ;
2011-07-23 17:56:24 +02:00
break ;
case MW_READ_BATTERY_VOLTAGE_RSP :
2011-07-30 17:22:05 +02:00
mw_get_battery_voltage_response ( mw_fd , msgdata , len - 2 ) ;
break ;
case MW_READ_LIGHT_SENSOR_RSP :
mw_read_light_sensor_response ( mw_fd , msgdata , len - 2 ) ;
2011-07-23 17:56:24 +02:00
break ;
case MW_LOW_BATTERY_WARNING_MSG :
fprintf ( stderr , " Watch battery low, please connect charger \n " ) ;
break ;
case MW_LOW_BATTERY_BT_OFF_MSG :
fprintf ( stderr , " Watch battery extremely low - radio will turn off \n " ) ;
break ;
2011-07-23 21:32:08 +02:00
case MW_STATUS_CHANGE_EVENT :
2011-07-30 17:22:05 +02:00
mw_status_change_event ( mw_fd , msgopt , msgdata , len - 2 ) ;
2011-07-23 21:32:08 +02:00
break ;
2011-07-23 17:56:24 +02:00
default :
fprintf ( stderr , " Unkown msgtype 0x%02x \n " , msgtype ) ;
break ;
} ;
return 0 ;
2011-07-19 12:31:32 +02:00
}
2011-07-18 22:33:40 +02:00
2011-07-24 17:27:28 +02:00
/* ----------------------------------------------------------------------
* Convenience functions not strictly part of the protocol
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
2011-07-23 21:32:08 +02:00
2011-07-24 17:27:28 +02:00
/* if flip=1 bits in each byte are inverted 7->1, 6->2, 5->3,...
if invert = 1 each byte is inverted
*/
void bmap_buffer_flipinvert ( unsigned char flip , unsigned char invert , unsigned char * buf , int len )
2011-07-23 21:32:08 +02:00
{
int i ;
unsigned char tmp ;
while ( len - - ) {
tmp = 0 ;
2011-07-24 17:27:28 +02:00
if ( flip ) {
for ( i = 0 ; i < 8 ; i + + )
tmp | = ( ( * buf & ( 1 < < i ) ) > > i ) < < ( 7 - i ) ;
// fprintf(stderr, "0x%02x -> 0x%02x\n", *buf, tmp);
} else
tmp = * buf ;
2011-07-23 21:32:08 +02:00
* buf = invert ? ~ tmp : tmp ;
buf + + ;
}
}
2011-07-24 17:27:28 +02:00
void mw_send_bitmap ( int mw_fd , unsigned char mode , int width , int height , int offset , unsigned char * bmapbuf , int buflen )
2011-07-23 21:32:08 +02:00
{
2011-07-30 17:22:05 +02:00
# ifdef DEBUG
unsigned int i , x ;
# endif
unsigned int y , rowlength ;
2011-07-23 21:32:08 +02:00
unsigned char mw_buf [ 24 ] ;
rowlength = ( ( width / 8 ) + 1 ) ;
2011-07-24 17:27:28 +02:00
if ( ( height + offset ) > 96 )
height = 96 - offset ;
2011-07-23 21:32:08 +02:00
2011-07-24 17:27:28 +02:00
# ifdef DEBUG
fprintf ( stderr , " row length = %d bytes \n " , rowlength ) ;
fprintf ( stderr , " bitmap resolution is %d x %d \n " , width , height ) ;
2011-07-23 21:32:08 +02:00
fprintf ( stderr , " \n " ) ;
for ( y = 0 ; y < height ; y + + ) {
for ( x = 0 ; x < rowlength ; x + + ) {
for ( i = 0 ; i < 8 ; i + + )
fprintf ( stderr , " %c " , ( bmapbuf [ ( y * rowlength ) + x ] & ( 1 < < ( 7 - i ) ) ) ? ' . ' : ' ' ) ;
}
fprintf ( stderr , " \n " ) ;
}
fprintf ( stderr , " \n " ) ;
# endif
for ( y = 0 ; y < height ; y + = 2 ) {
memset ( mw_buf , 0 , 24 ) ;
memcpy ( mw_buf , ( bmapbuf + ( y * rowlength ) ) , ( rowlength > 12 ) ? 12 : rowlength ) ;
memcpy ( ( mw_buf + 12 ) , ( bmapbuf + ( ( y + 1 ) * rowlength ) ) , ( rowlength > 12 ) ? 12 : rowlength ) ;
2011-07-24 17:27:28 +02:00
mw_write_buffer ( mw_fd , mode , 0 , 31 + y , mw_buf , 24 ) ;
2011-07-23 17:56:24 +02:00
}
2011-07-19 14:13:11 +02:00
}