2000-10-01 12:31:20 +00:00
/*
2001-07-13 19:08:15 +00:00
* Hamlib CI - V backend - low level communication routines
2006-02-26 18:48:07 +00:00
* Copyright ( c ) 2000 - 2006 by Stephane Fillod
2000-10-01 12:31:20 +00:00
*
2006-09-22 19:55:59 +00:00
* $ Id : frame . c , v 1.30 2006 - 09 - 22 19 : 55 : 58 n0nb Exp $
2000-10-01 12:31:20 +00:00
*
2001-07-13 19:08:15 +00:00
* This library is free software ; you can redistribute it and / or modify
* it under the terms of the GNU Library General Public License as
* published by the Free Software Foundation ; either version 2 of
* the License , or ( at your option ) any later version .
2000-10-01 12:31:20 +00:00
*
2001-07-13 19:08:15 +00:00
* 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 Library General Public License for more details .
2000-10-01 12:31:20 +00:00
*
2001-07-13 19:08:15 +00:00
* You should have received a copy of the GNU Library General Public
* License along with this library ; if not , write to the Free Software
* Foundation , Inc . , 675 Mass Ave , Cambridge , MA 0213 9 , USA .
2000-10-01 12:31:20 +00:00
*
*/
2001-07-13 19:08:15 +00:00
# ifdef HAVE_CONFIG_H
# include "config.h"
# endif
2000-10-01 12:31:20 +00:00
# include <stdlib.h>
# include <string.h> /* String function definitions */
# include <unistd.h> /* UNIX standard function definitions */
2003-04-07 22:42:11 +00:00
# include "hamlib/rig.h"
# include "serial.h"
# include "misc.h"
2000-10-01 12:31:20 +00:00
# include "icom.h"
# include "icom_defs.h"
# include "frame.h"
/*
* Build a CI - V frame .
* The whole frame is placed in frame [ ] ,
* " re_id " is the transceiver ' s CI - V address ,
* " cmd " is the Command number ,
* " subcmd " is the Sub command number , set to - 1 if not present in frame ,
* if the frame has no data , then the " data " pointer must be NULL ,
* and data_len = = 0.
* " data_len " holds the Data area length pointed by the " data " pointer .
* REM : if " data " is NULL , then " data_len " MUST be 0.
*
* NB : the frame array must be big enough to hold the frame .
2006-07-18 22:51:43 +00:00
* The smallest frame is 6 bytes , the biggest is at least 13 bytes .
2000-10-01 12:31:20 +00:00
*
* TODO : inline the function ?
*/
2006-07-18 22:51:43 +00:00
int make_cmd_frame ( char frame [ ] , char re_id , char cmd , int subcmd , const unsigned char * data , int data_len )
2000-10-01 12:31:20 +00:00
{
int i = 0 ;
2002-03-18 23:04:27 +00:00
#if 0
2000-10-01 12:31:20 +00:00
frame [ i + + ] = PAD ; /* give old rigs a chance to flush their rx buffers */
2002-03-18 23:04:27 +00:00
# endif
2000-10-01 12:31:20 +00:00
frame [ i + + ] = PR ; /* Preamble code */
frame [ i + + ] = PR ;
frame [ i + + ] = re_id ;
frame [ i + + ] = CTRLID ;
frame [ i + + ] = cmd ;
2006-09-22 19:55:59 +00:00
if ( subcmd ! = - 1 ) {
# ifdef MULTIB_SUBCMD
register int j ;
if ( j = subcmd & 0xff0000 ) { /* allows multi-byte subcmd for dsp rigs */
frame [ i + + ] = j > > 16 ;
frame [ i + + ] = ( subcmd & 0xff00 ) > > 8 ;
}
else if ( j = subcmd & 0xff00 ) frame [ i + + ] = j > > 8 ;
# endif
2006-07-18 22:51:43 +00:00
frame [ i + + ] = subcmd & 0xff ;
2006-09-22 19:55:59 +00:00
}
2000-10-01 12:31:20 +00:00
if ( data_len ! = 0 ) {
memcpy ( frame + i , data , data_len ) ;
i + = data_len ;
}
frame [ i + + ] = FI ; /* EOM code */
return i ;
}
/*
2003-05-03 13:34:16 +00:00
* icom_one_transaction
2000-10-01 12:31:20 +00:00
*
* We assume that rig ! = NULL , rig - > state ! = NULL , payload ! = NULL , data ! = NULL , data_len ! = NULL
* Otherwise , you ' ll get a nice seg fault . You ' ve been warned !
* payload can be NULL if payload_len = = 0
* subcmd can be equal to - 1 ( no subcmd wanted )
2003-08-17 22:39:07 +00:00
* if no answer is to be expected , data_len must be set to NULL to tell so
2001-06-10 22:25:50 +00:00
*
* return RIG_OK if transaction completed ,
* or a negative value otherwise indicating the error .
2000-10-01 12:31:20 +00:00
*/
2006-07-18 22:51:43 +00:00
int icom_one_transaction ( RIG * rig , int cmd , int subcmd , const unsigned char * payload , int payload_len , unsigned char * data , int * data_len )
2000-10-01 12:31:20 +00:00
{
2005-04-20 15:31:26 +00:00
struct icom_priv_data * priv ;
struct rig_state * rs ;
unsigned char buf [ MAXFRAMELEN ] ;
unsigned char sendbuf [ MAXFRAMELEN ] ;
int frm_len , retval ;
rs = & rig - > state ;
priv = ( struct icom_priv_data * ) rs - > priv ;
frm_len = make_cmd_frame ( sendbuf , priv - > re_civ_addr , cmd , subcmd ,
payload , payload_len ) ;
/*
* should check return code and that write wrote cmd_len chars !
*/
Hold_Decode ( rig ) ;
serial_flush ( & rs - > rigport ) ;
retval = write_block ( & rs - > rigport , sendbuf , frm_len ) ;
if ( retval ! = RIG_OK ) {
Unhold_Decode ( rig ) ;
return retval ;
}
/*
* read what we just sent , because TX and RX are looped ,
* and discard it . . .
* - if what we read is not what we sent , then it means
* a collision on the CI - V bus occured !
* - if we get a timeout , then retry to send the frame ,
* up to rs - > retry times .
*/
retval = read_icom_frame ( & rs - > rigport , buf ) ;
if ( retval = = - RIG_ETIMEOUT | | retval = = 0 )
{
/* Nothing recieved, CI-V interface is not echoing */
Unhold_Decode ( rig ) ;
return - RIG_BUSERROR ;
}
if ( retval < 0 )
{
/* Other error, return it */
Unhold_Decode ( rig ) ;
return retval ;
}
switch ( buf [ retval - 1 ] )
{
case COL :
/* Collision */
Unhold_Decode ( rig ) ;
return - RIG_BUSBUSY ;
case FI :
/* Ok, normal frame */
break ;
default :
/* Timeout after reading at least one character */
/* Problem on ci-v bus? */
Unhold_Decode ( rig ) ;
return - RIG_BUSERROR ;
}
if ( retval ! = frm_len )
{
/* Not the same length??? */
/* Problem on ci-v bus? */
/* Someone else got a packet in? */
Unhold_Decode ( rig ) ;
return - RIG_EPROTO ;
}
if ( memcmp ( buf , sendbuf , frm_len ) )
{
/* Frames are different? */
/* Problem on ci-v bus? */
/* Someone else got a packet in? */
Unhold_Decode ( rig ) ;
return - RIG_EPROTO ;
}
/*
* expect an answer ?
*/
if ( data_len = = NULL ) {
Unhold_Decode ( rig ) ;
return RIG_OK ;
}
/*
* wait for ACK . . .
* FIXME : handle pading / collisions
* ACKFRMLEN is the smallest frame we can expect from the rig
*/
frm_len = read_icom_frame ( & rs - > rigport , buf ) ;
Unhold_Decode ( rig ) ;
if ( frm_len < 0 )
{
/* RIG_TIMEOUT: timeout getting response, return timeout */
/* other error: return it */
return frm_len ;
}
switch ( buf [ frm_len - 1 ] )
{
case COL :
/* Collision */
return - RIG_BUSBUSY ;
case FI :
/* Ok, normal frame */
break ;
default :
/* Timeout after reading at least one character */
/* Problem on ci-v bus? */
return - RIG_EPROTO ;
}
if ( frm_len < ACKFRMLEN ) {
return - RIG_EPROTO ;
}
* data_len = frm_len - ( ACKFRMLEN - 1 ) ;
memcpy ( data , buf + 4 , * data_len ) ;
/*
* TODO : check addresses in reply frame
*/
return RIG_OK ;
2000-10-01 12:31:20 +00:00
}
2003-05-03 13:34:16 +00:00
/*
* icom_transaction
*
* This function honors rigport . retry count .
*
* We assume that rig ! = NULL , rig - > state ! = NULL , payload ! = NULL , data ! = NULL , data_len ! = NULL
* Otherwise , you ' ll get a nice seg fault . You ' ve been warned !
* payload can be NULL if payload_len = = 0
* subcmd can be equal to - 1 ( no subcmd wanted )
*
* return RIG_OK if transaction completed ,
* or a negative value otherwise indicating the error .
*/
2006-07-18 22:51:43 +00:00
int icom_transaction ( RIG * rig , int cmd , int subcmd , const unsigned char * payload , int payload_len , unsigned char * data , int * data_len )
2003-05-03 13:34:16 +00:00
{
int retval , retry ;
retry = rig - > state . rigport . retry ;
do {
retval = icom_one_transaction ( rig , cmd , subcmd , payload , payload_len , data , data_len ) ;
if ( retval = = RIG_OK )
break ;
} while ( retry - - > 0 ) ;
return retval ;
}
2002-03-11 23:28:45 +00:00
/* used in read_icom_frame as end of block */
static const char icom_block_end [ 2 ] = { FI , COL } ;
# define icom_block_end_length 2
2000-10-01 12:31:20 +00:00
2000-10-08 21:26:33 +00:00
/*
* read_icom_frame
* read a whole CI - V frame ( until 0xfd is encountered )
2000-11-01 23:21:47 +00:00
* TODO : strips padding / collisions
2000-10-08 21:26:33 +00:00
* FIXME : check return codes / bytes read
*/
2005-04-03 12:27:17 +00:00
int read_icom_frame ( hamlib_port_t * p , unsigned char rxbuffer [ ] )
2000-10-08 21:26:33 +00:00
{
2005-04-20 15:31:26 +00:00
int i ;
2000-10-08 21:26:33 +00:00
2005-04-20 15:31:26 +00:00
i = read_string ( p , rxbuffer , MAXFRAMELEN ,
icom_block_end , icom_block_end_length ) ;
2000-10-08 21:26:33 +00:00
2005-04-20 15:31:26 +00:00
return i ;
2000-10-08 21:26:33 +00:00
}
2000-12-04 23:39:18 +00:00
/*
2002-03-10 23:44:24 +00:00
* convert mode and width as expressed by Hamlib frontend
* to mode and passband data understandable by a CI - V rig
*
* if pd = = - 1 , no passband data is to be sent
*
* return RIG_OK if everything ' s fine , negative value otherwise
*
2000-12-04 23:39:18 +00:00
* TODO : be more exhaustive
2001-04-26 21:32:54 +00:00
* assumes rig ! = NULL
2000-12-04 23:39:18 +00:00
*/
2002-03-10 23:44:24 +00:00
int rig2icom_mode ( RIG * rig , rmode_t mode , pbwidth_t width ,
2006-09-22 19:55:59 +00:00
unsigned char * md , signed char * pd )
2000-10-08 21:26:33 +00:00
{
2005-04-20 15:31:26 +00:00
unsigned char icmode ;
signed char icmode_ext ;
pbwidth_t medium_width ;
icmode_ext = - 1 ;
switch ( mode ) {
case RIG_MODE_AM : icmode = S_AM ; break ;
case RIG_MODE_AMS : icmode = S_AMS ; break ;
case RIG_MODE_CW : icmode = S_CW ; break ;
case RIG_MODE_CWR : icmode = S_CWR ; break ;
case RIG_MODE_USB : icmode = S_USB ; break ;
case RIG_MODE_LSB : icmode = S_LSB ; break ;
case RIG_MODE_RTTY : icmode = S_RTTY ; break ;
case RIG_MODE_RTTYR : icmode = S_RTTYR ; break ;
case RIG_MODE_FM : icmode = S_FM ; break ;
case RIG_MODE_WFM : icmode = S_WFM ; break ;
default :
rig_debug ( RIG_DEBUG_ERR , " icom: Unsupported Hamlib mode %d \n " , mode ) ;
return - RIG_EINVAL ;
}
medium_width = rig_passband_normal ( rig , mode ) ;
if ( width = = medium_width | | width = = RIG_PASSBAND_NORMAL )
2006-07-18 22:51:43 +00:00
icmode_ext = - 1 ; /* medium, no passband data-> rig default. Is medium always the default? */
2005-04-20 15:31:26 +00:00
else if ( width < medium_width )
icmode_ext = PD_NARROW ;
else
icmode_ext = PD_WIDE ;
if ( rig - > caps - > rig_model = = RIG_MODEL_ICR7000 ) {
if ( mode = = RIG_MODE_USB | | mode = = RIG_MODE_LSB ) {
icmode = S_R7000_SSB ;
icmode_ext = 0x00 ;
} else if ( mode = = RIG_MODE_AM & & icmode_ext = = - 1 ) {
icmode_ext = PD_WIDE ; /* default to Wide */
}
}
* md = icmode ;
* pd = icmode_ext ;
return RIG_OK ;
2000-10-08 21:26:33 +00:00
}
2001-04-26 21:32:54 +00:00
/*
* assumes rig ! = NULL , mode ! = NULL , width ! = NULL
*/
2003-04-26 09:54:49 +00:00
void icom2rig_mode ( RIG * rig , unsigned char md , int pd , rmode_t * mode , pbwidth_t * width )
2000-10-08 21:26:33 +00:00
{
2005-04-20 15:31:26 +00:00
* width = RIG_PASSBAND_NORMAL ;
switch ( md ) {
case S_AM : * mode = RIG_MODE_AM ; break ;
case S_AMS : * mode = RIG_MODE_AMS ; break ;
case S_CW : * mode = RIG_MODE_CW ; break ;
case S_CWR : * mode = RIG_MODE_CWR ; break ;
case S_FM : if ( rig - > caps - > rig_model = = RIG_MODEL_ICR7000
& & pd = = 0x00 ) {
* mode = RIG_MODE_USB ;
* width = rig_passband_normal ( rig , RIG_MODE_USB ) ;
return ;
} else
* mode = RIG_MODE_FM ;
break ;
case S_WFM : * mode = RIG_MODE_WFM ; break ;
case S_USB : * mode = RIG_MODE_USB ; break ;
case S_LSB : * mode = RIG_MODE_LSB ; break ;
case S_RTTY : * mode = RIG_MODE_RTTY ; break ;
case S_RTTYR : * mode = RIG_MODE_RTTYR ; break ;
2006-09-22 19:55:59 +00:00
case S_PSK : * mode = RIG_MODE_PKTUSB ; break ; /* IC-7800 */
case S_PSKR : * mode = RIG_MODE_PKTLSB ; break ;
2005-04-20 15:31:26 +00:00
case 0xff : * mode = RIG_MODE_NONE ; break ; /* blank mem channel */
default :
rig_debug ( RIG_DEBUG_ERR , " icom: Unsupported Icom mode %#.2x \n " ,
md ) ;
* mode = RIG_MODE_NONE ;
}
2006-09-22 19:55:59 +00:00
/* Most rigs return 1-wide, 2-narrow; or if it has 3 filters: 1-wide, 2-middle, 3-narrow. (Except for the 706 mkIIg 0-wide, 1-middle, 2-narrow.) For DSP rigs these are presets, which can be programmed for 30 - 41 bandwidths, depending on mode */
if ( rig - > caps - > rig_model = = RIG_MODEL_IC706MKIIG | | rig - > caps - > rig_model = = RIG_MODEL_IC706 | | rig - > caps - > rig_model = = RIG_MODEL_IC706MKII ) pd - - ;
2005-04-20 15:31:26 +00:00
switch ( pd ) {
2006-09-22 19:55:59 +00:00
case 0x01 : if ( ! ( * width = rig_passband_wide ( rig , * mode ) ) ) /* if no wide filter defined it's the default */
* width = rig_passband_normal ( rig , * mode ) ;
break ;
case 0x02 : if ( * width = rig_passband_wide ( rig , * mode ) )
* width = rig_passband_normal ( rig , * mode ) ;
else * width = rig_passband_narrow ( rig , * mode ) ; /* This really just depends on how you program the table. */
break ;
2006-07-18 22:51:43 +00:00
case 0x03 : * width = rig_passband_narrow ( rig , * mode ) ; break ;
2005-04-20 15:31:26 +00:00
case - 1 : break ; /* no passband data */
2006-07-18 22:51:43 +00:00
2005-04-20 15:31:26 +00:00
default :
2006-09-22 19:55:59 +00:00
rig_debug ( RIG_DEBUG_ERR , " icom: Unsupported Icom mode width %#.2x \n " , pd ) ;
2005-04-20 15:31:26 +00:00
}
2006-09-22 19:55:59 +00:00
return ;
2000-10-08 21:26:33 +00:00
}
2000-10-01 12:31:20 +00:00