kopia lustrzana https://github.com/Hamlib/Hamlib
				
				
				
			
		
			
				
	
	
		
			2955 wiersze
		
	
	
		
			69 KiB
		
	
	
	
		
			C
		
	
	
			
		
		
	
	
			2955 wiersze
		
	
	
		
			69 KiB
		
	
	
	
		
			C
		
	
	
| /*
 | |
|  *  Hamlib Kenwood backend - TS2000 description
 | |
|  *  Copyright (c) 2000-2002 by Stephane Fillod
 | |
|  *
 | |
|  *		$Id: ts2k.c,v 1.6 2008-02-13 20:59:15 fillods Exp $
 | |
|  *
 | |
|  *   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.
 | |
|  *
 | |
|  *   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.
 | |
|  *
 | |
|  *   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 02139, USA.
 | |
|  *
 | |
|  */
 | |
| 
 | |
| /*
 | |
|  * This code is has been substatiantially altered from the original
 | |
|  * author's.  Also, many new functions have been added and are
 | |
|  * (C) Copyrighted 2002 by Dale E. Edmons (KD7ENI).  The license
 | |
|  * is unchanged, and fitness disclaimers still apply.
 | |
|  */
 | |
| 
 | |
| /*
 | |
|  * Copied kenwood.c to end of this file.  When I change a function for the
 | |
|  * ts2000 I will already have the kenwood version with the function prefix
 | |
|  * changed to ts2k.  Unique functions will be pointed to in this file,
 | |
|  * whereas the unmodified version will be in kenwood.c.  This simplifies
 | |
|  * things during development and unused ts2k_() functions should go away
 | |
|  * as soon as possible.
 | |
|  *
 | |
|  *	Dale KD7ENI
 | |
|  */
 | |
| 
 | |
| #ifdef HAVE_CONFIG_H
 | |
| #include "config.h"
 | |
| #endif
 | |
| 
 | |
| #include <ctype.h>
 | |
| #include <hamlib/rig.h>
 | |
| #include "kenwood.h"
 | |
| #include "ts2k.h"
 | |
| 
 | |
| 
 | |
| /*
 | |
|  * I just read in kenwood.c and will modify the functions here.  This way,
 | |
|  * kenwood functions that actually work on other rigs won't be broken by
 | |
|  * my hacks.  Anything that works for all can be sent back over to kenwood.c
 | |
|  *
 | |
|  * Note: due to my compulsive laziness, I often abbreviate Kenwood TS-2000
 | |
|  *	as simply ts2k, especially for code!
 | |
|  *
 | |
|  * Dale kd7eni
 | |
|  */
 | |
| 
 | |
| /*
 | |
|  *  Hamlib Kenwood backend - main file
 | |
|  *  Copyright (c) 2000-2002 by Stephane Fillod
 | |
|  *
 | |
|  *		$Id: ts2k.c,v 1.6 2008-02-13 20:59:15 fillods Exp $
 | |
|  */
 | |
| 
 | |
| 
 | |
| #include <stdlib.h>
 | |
| #include <stdio.h>		/* Standard input/output definitions */
 | |
| #include <string.h>		/* String function definitions */
 | |
| #include <unistd.h>		/* UNIX standard function definitions */
 | |
| #include <fcntl.h>		/* File control definitions */
 | |
| #include <errno.h>		/* Error number definitions */
 | |
| #include <termios.h>		/* POSIX terminal control definitions */
 | |
| #include <sys/ioctl.h>
 | |
| #include <math.h>
 | |
| 
 | |
| #include <serial.h>
 | |
| #include <misc.h>
 | |
| 
 | |
| 
 | |
| /*
 | |
|  * modes in use by the "MD" command
 | |
|  */
 | |
| #define MD_NONE	'0'
 | |
| #define MD_LSB	'1'
 | |
| #define MD_USB	'2'
 | |
| #define MD_CW	'3'
 | |
| #define MD_FM	'4'
 | |
| #define MD_AM	'5'
 | |
| #define MD_FSK	'6'
 | |
| #define MD_CWR	'7'
 | |
| #define MD_FSKR	'9'
 | |
| 
 | |
| 
 | |
| // Added the following two lists --Dale, kd7eni
 | |
| // FIXME: RIG_MODE_[FSKR|CWR] undefined in rig.h
 | |
| const int ts2k_mode_list[] = {
 | |
| 	RIG_MODE_NONE, RIG_MODE_LSB, RIG_MODE_USB, RIG_MODE_CW,
 | |
| 	RIG_MODE_FM, RIG_MODE_AM, RIG_MODE_RTTY, RIG_MODE_CW,
 | |
| 	RIG_MODE_RTTY
 | |
| };
 | |
| 
 | |
| long int ts2k_steps[2][10] = {
 | |
| 	{1000, 2500, 5000, 10000, 0, 0, 0, 0, 0, 0},	// ssb, cw, fsk
 | |
| 	{5000, 6250, 10000, 12500, 15000, 20000,
 | |
| 	 25000, 30000, 50000, 100000}	// am/fm
 | |
| };
 | |
| 
 | |
| 
 | |
| struct ts2k_id {
 | |
| 	rig_model_t model;
 | |
| 	int id;
 | |
| };
 | |
| 
 | |
| struct ts2k_id_string {
 | |
| 	rig_model_t model;
 | |
| 	const char *id;
 | |
| };
 | |
| 
 | |
| 
 | |
| #define UNKNOWN_ID -1
 | |
| 
 | |
| /*
 | |
|  * Identification number as returned by "ID;"
 | |
|  * Please, if the model number of your rig is listed as UNKNOWN_ID,
 | |
|  * send the value to <fillods@users.sourceforge.net> for inclusion. Thanks --SF
 | |
|  *
 | |
|  * TODO: sort this list with most frequent rigs first.
 | |
|  */
 | |
| static const struct ts2k_id ts2k_id_list[] = {
 | |
| 	{RIG_MODEL_R5000, 5},
 | |
| 	{RIG_MODEL_TS870S, 15},
 | |
| 	{RIG_MODEL_TS570D, 17},
 | |
| 	{RIG_MODEL_TS570S, 18},
 | |
| 	{RIG_MODEL_TS2000, 19},	/* correct --kd7eni */
 | |
| 	{RIG_MODEL_NONE, UNKNOWN_ID},	/* end marker */
 | |
| };
 | |
| 
 | |
| static const struct ts2k_id_string ts2k_id_string_list[] = {
 | |
| 	{RIG_MODEL_THD7A, "TH-D7"},
 | |
| 	{RIG_MODEL_THD7AG, "TH-D7G"},
 | |
| 	{RIG_MODEL_THF6A, "TH-F6"},
 | |
| 	{RIG_MODEL_THF7E, "TH-F7"},
 | |
| 	{RIG_MODEL_NONE, NULL},	/* end marker */
 | |
| };
 | |
| 
 | |
| 
 | |
| /*
 | |
|  * 38 CTCSS sub-audible tones  (17500 invalid for ctcss --kd7eni)
 | |
|   */
 | |
| const int ts2k_ctcss_list[] = {
 | |
| 	670, 719, 744, 770, 797, 825, 854, 885, 915, 948,
 | |
| 	974, 1000, 1035, 1072, 1109, 1148, 1188, 1230, 1273, 1318,
 | |
| 	1365, 1413, 1462, 1514, 1567, 1622, 1679, 1738, 1799, 1862,
 | |
| 	1928, 2035, 2107, 2181, 2257, 2336, 2418, 2503, // 17500,
 | |
| 	/* Note: 17500 is not available as ctcss, only tone. --kd7eni */
 | |
| 	0,
 | |
| };
 | |
| 
 | |
| #define cmd_trm(rig) ((struct ts2k_priv_caps *)(rig)->caps->priv)->cmdtrm
 | |
| #define ta_quit	rs->hold_decode = 0; return retval
 | |
| 
 | |
| /**
 | |
|  * kenwood_transaction
 | |
|  * Assumes rig!=NULL rig->state!=NULL rig->caps!=NULL
 | |
|  *
 | |
|  * cmdstr - Command to be sent to the rig. Cmdstr can also be NULL, indicating
 | |
|  *          that only a reply is needed (nothing will be send).
 | |
|  * data - Buffer for reply string.  Can be NULL, indicating that no reply is
 | |
|  *        is needed and will return with RIG_OK after command was sent.
 | |
|  * datasize - in: Size of buffer. It is the caller's responsibily to provide
 | |
|  *            a large enough buffer for all possible replies for a command.
 | |
|  *            out: location where to store number of bytes read.
 | |
|  *
 | |
|  * returns:
 | |
|  *   RIG_OK  -  if no error occured.
 | |
|  *   RIG_EIO  -  if an I/O error occured while sending/receiving data.
 | |
|  *   RIG_ETIMEOUT  -  if timeout expires without any characters received.
 | |
|  *   RIG_REJECTED  -  if a negative acknowledge was received or command not
 | |
|  *                    recognized by rig.
 | |
|  */
 | |
| 
 | |
| /* FIXME: cmd_len appears to change and needs set every invocation? --Dale */
 | |
| 
 | |
| int
 | |
| ts2k_transaction(RIG * rig, const char *cmdstr, int cmd_len,
 | |
| 		 char *data, size_t * datasize)
 | |
| {
 | |
| //      return kenwood_transaction(rig, cmdstr, cmd_len, data, datasize);
 | |
| 
 | |
| 	struct rig_state *rs;
 | |
| 	int retval;
 | |
| 	const char *cmdtrm = EOM_KEN;	/* Default Command/Reply termination char */
 | |
| 	int retry_read = 0;
 | |
| 	char *errtxt;
 | |
| 
 | |
| #define MAX_RETRY_READ 5 
 | |
| 
 | |
| 	rs = &rig->state;
 | |
| 	rs->hold_decode = 1;
 | |
| 
 | |
| 	serial_flush(&rs->rigport);
 | |
| 
 | |
| 	cmdtrm = cmd_trm(rig);
 | |
| 
 | |
| 	if (cmdstr != NULL) {
 | |
| 		//      rig_debug(RIG_DEBUG_ERR, __FUNCTION__": 1) sending '%s'\n\n", cmdstr);
 | |
| 		retval = write_block(&rs->rigport, cmdstr, strlen(cmdstr));
 | |
| 		if (retval != RIG_OK)
 | |
| 			{ ta_quit; }
 | |
| #undef	TH_ADD_CMDTRM
 | |
| #ifdef	TH_ADD_CMDTRM
 | |
| 		//      rig_debug(RIG_DEBUG_ERR, __FUNCTION__": 2) sending '%s'\n\n", cmdtrm);
 | |
| 		retval = write_block(&rs->rigport, cmdtrm, strlen(cmdtrm));
 | |
| 		if (retval != RIG_OK)
 | |
| 			{ ta_quit; }
 | |
| #endif
 | |
| 	}
 | |
| 
 | |
| /* FIXME: Everything below this line wants to be completely rewritten!!!! */
 | |
| 
 | |
| 	if (data == NULL || datasize <= 0) {
 | |
| 		rig->state.hold_decode = 0;
 | |
| 		return RIG_OK;	/* don't want a reply */
 | |
| 	}
 | |
| 
 | |
|       transaction_read:
 | |
| 	/* FIXME : TS-2000 gets alot of 'timedout' on read_string()! */
 | |
| 	//rig_debug(RIG_DEBUG_ERR, __FUNCTION__": 3a) reading %u bytes...\n", *datasize);
 | |
| 	retval =
 | |
| 	    read_string(&rs->rigport, data, *datasize, cmdtrm,
 | |
| 			strlen(cmdtrm));
 | |
| 	//rig_debug(RIG_DEBUG_ERR, __FUNCTION__": 3b) read '%s', retval=%u\n\n", data, retval);
 | |
| 	*datasize = retval;
 | |
| 	if (retval > 0) {
 | |
| 		//rig_debug(RIG_DEBUG_ERR, __FUNCTION__": 3b) read cmd '%s', retval=%u\n\n", data, retval);
 | |
| 		retval = RIG_OK;
 | |
| 		goto transaction_check;
 | |
| 	}
 | |
| 
 | |
| 	/* Check that command termination is correct */
 | |
| 	if (!strchr(cmdtrm, data[strlen(data)])) {
 | |
| 		if (retry_read++ < MAX_RETRY_READ)
 | |
| 			goto transaction_read;
 | |
| 		rig_debug(RIG_DEBUG_ERR,
 | |
| 			  __FUNCTION__
 | |
| 			  ": Command is not correctly terminated '%s'\n",
 | |
| 			  data);
 | |
| 		retval = -RIG_EPROTO;
 | |
| 		ta_quit;
 | |
| 	}
 | |
| 
 | |
| 	/* Errors */
 | |
| 	if (strlen(data) == 2 && data[0] == 'E') {
 | |
| 		switch (data[0]) {
 | |
| 		case 'E':
 | |
| 			rig_debug(RIG_DEBUG_ERR,
 | |
| 				  __FUNCTION__
 | |
| 				  ": Communication Error for '%s'\n",
 | |
| 				  cmdstr);
 | |
| 			break;
 | |
| 
 | |
| 		case 'O':
 | |
| 			rig_debug(RIG_DEBUG_ERR,
 | |
| 				  __FUNCTION__
 | |
| 				  ": Communication Error for '%s'\n",
 | |
| 				  cmdstr);
 | |
| 			break;
 | |
| 
 | |
| 		case '?':
 | |
| 			rig_debug(RIG_DEBUG_ERR,
 | |
| 				  __FUNCTION__
 | |
| 				  ": Communication Error for '%s'\n",
 | |
| 				  cmdstr);
 | |
| 			break;
 | |
| 
 | |
| 		default:
 | |
| 			rig_debug(RIG_DEBUG_ERR,
 | |
| 				  __FUNCTION__ ": Hamlib Error for '%s'\n",
 | |
| 				  cmdstr);
 | |
| 			break;
 | |
| 
 | |
| 		}
 | |
| 		retval = -RIG_ERJCTED;
 | |
| 		ta_quit;
 | |
| 	}
 | |
| #undef	CONFIG_STRIP_CMDTRM
 | |
| #ifdef	CONFIG_STRIP_CMDTRM
 | |
| 	if (strlen(data) > 0)
 | |
| 		data[strlen(data) - 1] = '\0';	/* not very elegant, but should work. */
 | |
| 	else
 | |
| 		data[0] = '\0';
 | |
| #endif
 | |
| 	/*
 | |
| 	 * Check that received the correct reply. The first two characters
 | |
| 	 * should be the same as command.
 | |
| 	 */
 | |
|       transaction_check:
 | |
| 	if (cmdstr && (toupper(data[0]) != toupper(cmdstr[0])
 | |
| 		       || toupper(data[1]) != toupper(cmdstr[1]))) {
 | |
| 		/*
 | |
| 		 * TODO: When RIG_TRN is enabled, we can pass the string
 | |
| 		 *       to the decoder for callback. That way we don't ignore
 | |
| 		 *       any commands.
 | |
| 		 */
 | |
| 		if (retry_read++ < MAX_RETRY_READ)
 | |
| 			goto transaction_read;
 | |
| 
 | |
| 		rig_debug(RIG_DEBUG_ERR,
 | |
| 			  __FUNCTION__ ": Unexpected reply '%s'\n", data);
 | |
| 		retval = -RIG_EPROTO;
 | |
| 		{ ta_quit; }
 | |
| 	}
 | |
| 
 | |
| 	retval = RIG_OK;
 | |
| 
 | |
|       transaction_quit:
 | |
| 	{ ta_quit; }
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * kenwood_set_vfo
 | |
|  * Assumes rig!=NULL
 | |
|  *
 | |
|  *	status:		VFOA, VFOB, VFOC, Main, Sub,
 | |
|  *			MEMA, MEMC, CALLA, CALLC 
 | |
|  *			VFO_AB, VFO_BA, ...
 | |
|  *		They all work!		--Dale
 | |
|  */
 | |
| int ts2k_set_vfo(RIG * rig, vfo_t vfo)
 | |
| {
 | |
| 	unsigned char cmdbuf[10];
 | |
| 	int ptt, ctrl, v,cmd_len, retval;
 | |
| 	static int sat_on;	// temporary! to be removed!
 | |
| 	char vfo_function;
 | |
| 
 | |
| 	// trivial case, but needs checked if enabled
 | |
| /*//	if( (vfo == RIG_CTRL_MODE(RIG_CTRL_MAIN,RIG_VFO_ALL))
 | |
| //		|| (vfo == RIG_CTRL_MODE(RIG_CTRL_SUB,RIG_VFO_ALL)) ) {
 | |
| //		rig_debug(RIG_DEBUG_ERR, __FUNCTION__ \
 | |
| //			  ": Geez, you can't set *all* VFO's!\n");
 | |
| //		return -RIG_EINVAL;
 | |
| //	}
 | |
| */
 | |
| 	cmd_len = 10;
 | |
| 	ptt = ctrl = v = 0;
 | |
| 
 | |
| 	// be optimistic (and ensure initialization)
 | |
| 	retval = RIG_OK;
 | |
| 
 | |
| 	// Main/Sub Active Transceiver
 | |
| 	switch (vfo) {
 | |
| 	case RIG_VFO_A:
 | |
| 	case RIG_VFO_B:
 | |
| 	case RIG_VFO_AB:	// split
 | |
| 	case RIG_VFO_BA:
 | |
| 	case RIG_CTRL_SAT:	// FIXME: Not even close to correct
 | |
| 	case RIG_VFO_MAIN:
 | |
| 	case RIG_VFO_MEM_A:
 | |
| 	case RIG_VFO_CALL_A:
 | |
| 		ctrl = TS2K_CTRL_ON_MAIN;	// FIXME : these are independent!
 | |
| 		ptt = TS2K_PTT_ON_MAIN;
 | |
| 		break;
 | |
| 	case RIG_VFO_C:
 | |
| 	case RIG_VFO_SUB:
 | |
| 	case RIG_VFO_MEM_C:
 | |
| 	case RIG_VFO_CALL_C:
 | |
| 		ctrl = TS2K_CTRL_ON_SUB;
 | |
| 		ptt = TS2K_PTT_ON_SUB;
 | |
| 		break;
 | |
| 
 | |
| 	default:
 | |
| 		break;
 | |
| 	}
 | |
| 
 | |
| 	// set now so "ft...;" and "fr...;" don't fail
 | |
| 	retval = ts2k_set_ctrl(rig, ptt, ctrl);
 | |
| 	if (retval != RIG_OK)
 | |
| 		return -RIG_EINVAL;
 | |
| 
 | |
| 	// check if we need to skip the remainder
 | |
| 	v  = (vfo == RIG_VFO_SUB)
 | |
| 		|| (vfo == RIG_VFO_MAIN)
 | |
| 		|| (vfo == RIG_VFO_CURR)
 | |
| 		|| (vfo == RIG_VFO_VFO)
 | |
| //		|| (vfo == RIG_VFO_ALL)		// yea, I know
 | |
| 		/* bit mask checks */
 | |
| 		|| (vfo & RIG_CTRL_SAT)	// "fr...;", "ft...;" won't do!
 | |
| 		;
 | |
| 
 | |
| 	rig_debug(RIG_DEBUG_ERR, __FUNCTION__ \
 | |
| 		  ": starting check.... vfo = 0x%X, v=%d\n", vfo, v);
 | |
| 
 | |
| 	if (!v) {	// start check
 | |
| 
 | |
| 		// FIXME: this is a speed-up kludge but won't *always* work!
 | |
| 		if(sat_on) {
 | |
| 			retval = ts2k_sat_off(rig, vfo);	// we gotta do it.
 | |
| 			if(retval != RIG_OK)
 | |
| 				return retval;
 | |
| 			sat_on = 0;
 | |
| 		}
 | |
| 
 | |
| 		// RX Active Tuning
 | |
| 		switch (vfo) {
 | |
| 		case RIG_VFO_AB:	// TX is opposite
 | |
| 		case RIG_VFO_A:
 | |
| 		case RIG_VFO_C:
 | |
| 			vfo_function = '0';
 | |
| 			break;
 | |
| 		case RIG_VFO_BA:	// TX is opposite
 | |
| 		case RIG_VFO_B:
 | |
| 			vfo_function = '1';
 | |
| 			break;
 | |
| 		case RIG_VFO_MEM_A:
 | |
| 		case RIG_VFO_MEM_C:
 | |
| 			vfo_function = '2';
 | |
| 			break;
 | |
| 		case RIG_VFO_CALL_A:
 | |
| 		case RIG_VFO_CALL_C:
 | |
| 			vfo_function = '3';
 | |
| 			break;
 | |
| 
 | |
| 		default:
 | |
| 			rig_debug(RIG_DEBUG_ERR, __FUNCTION__
 | |
| 				  ": unsupported VFO %u\n", vfo);
 | |
| 			return -RIG_EINVAL;
 | |
| 			break;
 | |
| 		}
 | |
| 
 | |
| 		// ack_len is tmp
 | |
| 		cmd_len =
 | |
| 		    sprintf(cmdbuf, "fr%c%s", vfo_function, cmd_trm(rig));
 | |
| 
 | |
| 		/* set RX VFO */
 | |
| 		retval =
 | |
| 		    ts2k_transaction(rig, cmdbuf, cmd_len, NULL, NULL);
 | |
| 		if (retval != RIG_OK)
 | |
| 			return -RIG_EINVAL;
 | |
| 
 | |
| 		// TX Active tuning
 | |
| 		switch (vfo) {
 | |
| 		case RIG_VFO_A:
 | |
| 		case RIG_VFO_C:
 | |
| 		case RIG_VFO_BA:	// opposite of above
 | |
| 			vfo_function = '0';
 | |
| 			break;
 | |
| 		case RIG_VFO_AB:	// opposite of above
 | |
| 		case RIG_VFO_B:
 | |
| 			vfo_function = '1';
 | |
| 			break;
 | |
| 		case RIG_VFO_MEM_A:
 | |
| 		case RIG_VFO_MEM_C:	// FIXME: need to handle vfo/mem split
 | |
| 			vfo_function = '2';
 | |
| 			break;
 | |
| 		case RIG_VFO_CALL_A:
 | |
| 		case RIG_VFO_CALL_C:
 | |
| 			vfo_function = '3';
 | |
| 			break;
 | |
| 
 | |
| 		default:
 | |
| 			rig_debug(RIG_DEBUG_ERR, __FUNCTION__
 | |
| 				  ": unsupported VFO %u\n",
 | |
| 				  vfo);
 | |
| 			return -RIG_EINVAL;
 | |
| 		}
 | |
| 
 | |
| 		/* set TX VFO */
 | |
| 		cmdbuf[1] = 't';
 | |
| 
 | |
| 		// removing this causes split to not function!!!!
 | |
| 		cmd_len =
 | |
| 		    sprintf(cmdbuf, "ft%c%s", vfo_function, cmd_trm(rig));
 | |
| 
 | |
| 		retval =
 | |
| 		    ts2k_transaction(rig, cmdbuf, cmd_len, NULL, NULL);
 | |
| 		if (retval != RIG_OK)
 | |
| 			return retval;
 | |
| 
 | |
| 	} else {	// Check further for special modes not using "fr...;", "ft...;"
 | |
| 		if(vfo & RIG_CTRL_SAT) {	// test the SAT bit
 | |
| 			retval = ts2k_sat_on(rig, vfo);
 | |
| 				if (retval != RIG_OK)
 | |
| 					return retval;
 | |
| 			sat_on = 1;			
 | |
| 		} else {
 | |
| 			rig_debug(RIG_DEBUG_ERR, __FUNCTION__ \
 | |
| 				  ": VFO not changed, only PTT/CTRL\n");
 | |
| 		}
 | |
| 	}
 | |
| /*
 | |
|  * FIXME: some items like scan, satellite need checked and turned off here.
 | |
|  *	I've got a simple kludge to turn SAT *off* but it wants to be done
 | |
|  *	here.  It's a bit expensive though and I'm trying to find a better
 | |
|  *	way to do SAT as well as others.  ts2k_sat_off() reads the current,
 | |
|  *	sets it off, then writes it back so the user selected stuff don't
 | |
|  *	change unexpectedly.  Now, SAT won't get turned off if first turned
 | |
|  *	on via the front panel.  MEM and SCAN have similar quirks.
 | |
|  *							--Dale
 | |
|  */
 | |
| 	return retval;
 | |
| }
 | |
| 
 | |
| /* we just turn SAT on here. It'll take some doing to run it! */
 | |
| int ts2k_sat_on(RIG *rig, vfo_t vfo)
 | |
| {
 | |
| 	char cmd[20], ack[20];
 | |
| 	int cmdlen, acklen;
 | |
| 
 | |
| 	acklen = 20;
 | |
| 
 | |
| 	if(!(vfo & RIG_CTRL_SAT))
 | |
| 		return -RIG_EINTERNAL;	// All right.  Who called us!?
 | |
| 
 | |
| //	cmdlen = sprintf(cmd, "sa%07u;", 0);	// Initial string to modify
 | |
| 	acklen = ts2k_transaction(rig, "sa;", 3, ack, &acklen);
 | |
| 
 | |
| 	// Sat mode ON
 | |
| 	ack[2] = '1';	// Everything below is *nice*, this is *required*
 | |
| 
 | |
| 	goto STest;	// testing
 | |
| 
 | |
| /* cmd is already full of '0's, but we set them again explicitly */
 | |
| 	// SAT_VFO or SAT_MEM?
 | |
| 	if(vfo & RIG_CTRL_MEM)
 | |
| 		ack[8] = '1';	// sat mem ch 0-9
 | |
| 	else
 | |
| 		ack[8] = '0';	// sat vfo
 | |
| 
 | |
| 	/* Main or Sub as uplink? */
 | |
| 	// Note: if both are set, Main is still uplink
 | |
| 	if(vfo & RIG_CTRL_MAIN) {
 | |
| 		ack[4] = '0';	// sat main=uplink
 | |
| 	} else if(vfo & RIG_CTRL_SUB) {
 | |
| 		ack[4] = '1';	// sat sub=uplink
 | |
| 	}
 | |
| 
 | |
| 	// FIXME: Add Sat Trace here!
 | |
| 
 | |
| 	// Trace REV
 | |
| 	if(vfo & RIG_CTRL_REV) 
 | |
| 		ack[7] = '1';	// sat trace REV 
 | |
| 	else
 | |
| 		ack[7] = '0';
 | |
| 
 | |
| 	// CTRL to main or sub?
 | |
| 	if ((vfo & RIG_VFO_CTRL) && (vfo & RIG_CTRL_SUB)) 	
 | |
| 		ack[5] = '1';	// sat CTRL on sub
 | |
| 	else
 | |
| 		ack[5] = '0';	// sat CTRL on main
 | |
| 
 | |
| STest:
 | |
| 	rig_debug(RIG_DEBUG_ERR, __FUNCTION__ \
 | |
| 		  ": sat = %s, vfo = 0x%X\n", cmd, vfo);
 | |
| 	// of coure, this is *required* too!
 | |
| 	return ts2k_transaction(rig, ack, acklen, NULL, NULL);
 | |
| }
 | |
| 
 | |
| int ts2k_sat_off(RIG *rig, vfo_t vfo)
 | |
| {
 | |
| 	char cmd[20], ack[20];
 | |
| 	int cmdlen, acklen, retval;
 | |
| 
 | |
| 	acklen = 10;
 | |
| 
 | |
| 	cmdlen = sprintf(cmd, "sa;");
 | |
| 	retval = ts2k_transaction(rig, cmd, cmdlen, ack, &acklen);
 | |
| 	if(retval != RIG_OK)
 | |
| 		return retval;
 | |
| 
 | |
| 	ack[2] = '0';
 | |
| 	cmdlen = 20;
 | |
| 	return ts2k_transaction(rig, ack, acklen, NULL, NULL);
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * kenwood_get_vfo
 | |
|  * Assumes rig!=NULL, !vfo
 | |
|  *
 | |
|  *	status:	works perfect for implemented modes!  --Dale
 | |
|  *		code's getting a little ugly.  okay, real ugly.
 | |
|  */
 | |
| int ts2k_get_vfo(RIG * rig, vfo_t * vfo)
 | |
| {
 | |
| 	char vfobuf[50], r_vfo;
 | |
| 	char *ctrl_ptt;
 | |
| 	int vfo_len, retval, tmp;
 | |
| 
 | |
| 	/*
 | |
| 	 * FIXME: if FR != FT && rcvr==main, the mode = split!  --kd7eni
 | |
| 	 */
 | |
| 
 | |
| 	// Check which receiver so VFO_C may be detected (PTT/CTRL)
 | |
| 
 | |
| 	ctrl_ptt = ts2k_get_ctrl(rig);
 | |
| 	if (ctrl_ptt == NULL)
 | |
| 		return -RIG_EINVAL;
 | |
| //	rig_debug(RIG_DEBUG_ERR, "ts2k_get_vfo: PTT/CTRL is %s\n", ctrl_ptt);
 | |
| 
 | |
| 	/* query RX VFO */
 | |
| 	vfo_len = 50;
 | |
| 	rig_debug(RIG_DEBUG_ERR, __FUNCTION__
 | |
| 		": sending fr; cmd/checking SAT.  Expect TIMEDOUT if in SAT mode!\n");
 | |
| 	retval = ts2k_transaction(rig, "fr;", 3, vfobuf, &vfo_len);
 | |
| 
 | |
| 							/* "fr;" fails in satellite mode; interesting... */
 | |
| 	if (retval != RIG_OK) {
 | |
| 		rig_debug(RIG_DEBUG_ERR, __FUNCTION__": kenwood/ts2k.c\n"
 | |
| 			"FIXME: ts2k.c,\tThis is timeout cannot be prevented.\n");
 | |
| 		tmp = retval;
 | |
| 		retval = ts2k_transaction(rig, "sa;", 3, vfobuf, &vfo_len);
 | |
| 		if (retval == RIG_OK) {
 | |
| 			rig_debug(RIG_DEBUG_ERR, __FUNCTION__": SAT=%s\n", vfobuf);
 | |
| 			if(vfobuf[2] == '1') {
 | |
| 							/* yes, we're in satellite mode! */
 | |
| 				*vfo = RIG_CTRL_SAT;	// FIXME: set the rest!
 | |
| 							/* TODO: write get_sat() and let it do the work */
 | |
| 				return RIG_OK;
 | |
| 			}
 | |
| 		}
 | |
| 		return tmp;	// return original "fr;" error!
 | |
| 	}
 | |
| 
 | |
| //	rig_debug(RIG_DEBUG_ERR, __FUNCTION__": checking fr; cmd.\n");
 | |
| 	r_vfo = vfobuf[2];
 | |
| 
 | |
| 	//if (vfo_len != 4 || vfobuf[1] != 'R') {
 | |
| 	if (vfobuf[1] != 'R') {
 | |
| 		rig_debug(RIG_DEBUG_ERR, __FUNCTION__
 | |
| 			  ": unexpected answer %s, "
 | |
| 			  "len=%u\n", vfobuf, vfo_len);
 | |
| 		return -RIG_ERJCTED;
 | |
| 	}
 | |
| 
 | |
| 	rig_debug(RIG_DEBUG_ERR, __FUNCTION__": sending ft; cmd.\n");
 | |
| 	vfo_len = 50;
 | |
| 	retval = ts2k_transaction(rig, "ft;", 3, vfobuf, &vfo_len);
 | |
| 	if (retval != RIG_OK)
 | |
| 		return retval;
 | |
| 
 | |
| 	rig_debug(RIG_DEBUG_ERR, __FUNCTION__": checking ft; cmd.\n");
 | |
| 	if (vfobuf[2] == r_vfo) {	// check most common first
 | |
| 		rig_debug(RIG_DEBUG_ERR, "ts2k_get_vfo: Non-Split.\n");
 | |
| 
 | |
| 		/* TODO: replace 0,1,2,.. constants by defines */
 | |
| 		/* FIXME: return based on RIG_PTT_ON_???? or RIG_CTRL_ON_????
 | |
| 		 * may be different.  We need to specify actual status.
 | |
| 		 * Right now we pretend things are simpler. --kd7eni
 | |
| 		 */
 | |
| 		switch (vfobuf[2]) {
 | |
| 		case '0':
 | |
| 			if (ctrl_ptt[3] == '0')	// we use CTRL as Active Transceiver
 | |
| 				*vfo = RIG_VFO_A;
 | |
| 			else if (ctrl_ptt[3] == '1')
 | |
| 				*vfo = RIG_VFO_C;
 | |
| 			else {	// "There be errors here!"
 | |
| 				rig_debug(RIG_DEBUG_ERR,
 | |
| 					  "ts2k_get_vfo: VFO1 on erroneous xcvr %c\n",
 | |
| 					  vfobuf[2]);
 | |
| 				return -RIG_EPROTO;
 | |
| 			}
 | |
| 			break;
 | |
| 		case '1':
 | |
| 			// only valid on Main--no checks required.
 | |
| 			*vfo = RIG_VFO_B;
 | |
| 			break;
 | |
| 		case '2':
 | |
| 			if (ctrl_ptt[3] == '0')	// we use CTRL as Active Transceiver. 
 | |
| 				*vfo = RIG_VFO_MEM_A;
 | |
| 			else if (ctrl_ptt[3] == '1')
 | |
| 				*vfo = RIG_VFO_MEM_C;
 | |
| 			else
 | |
| 				return -RIG_EPROTO;
 | |
| 			break;
 | |
| 		case '3':
 | |
| 			if (ctrl_ptt[3] == '0')	// we use CTRL as current
 | |
| 				*vfo = RIG_VFO_CALL_A;
 | |
| 			else if (ctrl_ptt[3] == '1')	// we use CTRL as current
 | |
| 				*vfo = RIG_VFO_CALL_C;
 | |
| 			else
 | |
| 				return -RIG_EPROTO;
 | |
| 			break;
 | |
| 
 | |
| 		default:	// Different or newer rig types...
 | |
| 			rig_debug(RIG_DEBUG_ERR,
 | |
| 				  "ts2k_get_vfo: unsupported VFO %c\n",
 | |
| 				  vfobuf[2]);
 | |
| 			return -RIG_EPROTO;
 | |
| 
 | |
| 		}		// end switch
 | |
| 	} else {		// end rx == tx; start split checks. 
 | |
| 		rig_debug(RIG_DEBUG_ERR, "ts2k_get_vfo: Split.\n");
 | |
| 
 | |
| 		if (r_vfo == '0' && vfobuf[2] == '1')
 | |
| 			*vfo = RIG_VFO_AB;
 | |
| 		else if (r_vfo == '1' && vfobuf[2] == '0')
 | |
| 			*vfo = RIG_VFO_BA;
 | |
| 		else {		// FIXME: need vfo <--> mem split
 | |
| 			rig_debug(RIG_DEBUG_ERR,
 | |
| 				  __FUNCTION__
 | |
| 				  ":FIXME: vfo<->mem split! -kd7eni!\n");
 | |
| 			return -RIG_EPROTO;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	return RIG_OK;
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * kenwood_set_freq
 | |
|  * Assumes rig!=NULL
 | |
|  *
 | |
|  *	status:	correctly sets FA, FB, FC	--Dale
 | |
|  */
 | |
| int ts2k_set_freq(RIG * rig, vfo_t vfo, freq_t freq)
 | |
| {
 | |
| 	unsigned char freqbuf[16];
 | |
| 	int freq_len, ack_len = 0, retval;
 | |
| 	char vfo_letter;
 | |
| 
 | |
| 	/*
 | |
| 	 * better FIXME: vfo==RIG_VFO_CURR
 | |
| 	 */
 | |
| 	if (vfo == RIG_VFO_CURR) {
 | |
| 		retval = ts2k_get_vfo(rig, &vfo);
 | |
| 		if (retval != RIG_OK)
 | |
| 			return retval;
 | |
| 	}
 | |
| 
 | |
| 	switch (vfo) {
 | |
| 	case RIG_VFO_A:
 | |
| 		vfo_letter = 'A';
 | |
| 		break;
 | |
| 	case RIG_VFO_B:
 | |
| 		vfo_letter = 'B';
 | |
| 		break;
 | |
| 	case RIG_VFO_C:
 | |
| 		vfo_letter = 'C';
 | |
| 		break;
 | |
| 	default:
 | |
| 		rig_debug(RIG_DEBUG_ERR,
 | |
| 			  "ts2k_set_freq: unsupported VFO %u\n", vfo);
 | |
| 		return -RIG_EINVAL;
 | |
| 	}
 | |
| 	freq_len = sprintf(freqbuf, "F%c%011"PRIll";", vfo_letter, freq);
 | |
| 
 | |
| 	ack_len = 14;
 | |
| 	retval = ts2k_transaction(rig, freqbuf, freq_len, NULL, NULL);
 | |
| 
 | |
| 	return retval;
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * kenwood_get_freq
 | |
|  * Assumes rig!=NULL, freq!=NULL
 | |
|  */
 | |
| int ts2k_get_freq(RIG * rig, vfo_t vfo, freq_t * freq)
 | |
| {
 | |
| 	unsigned char freqbuf[50];
 | |
| 	unsigned char cmdbuf[4];
 | |
| 	int cmd_len, freq_len, retval;
 | |
| 	char vfo_letter;
 | |
| 
 | |
| 	/*
 | |
| 	 * FIXME: need to handle RIG_VFO_MEM, etc...
 | |
| 	 */
 | |
| 	if (vfo == RIG_VFO_CURR) {
 | |
| 		retval = ts2k_get_vfo(rig, &vfo);
 | |
| 		if (retval != RIG_OK)
 | |
| 			return retval;
 | |
| 	}
 | |
| 
 | |
| 	switch (vfo) {
 | |
| 	case RIG_VFO_A:
 | |
| 		vfo_letter = 'a';
 | |
| 		break;
 | |
| 	case RIG_VFO_B:
 | |
| 		vfo_letter = 'b';
 | |
| 		break;
 | |
| 	case RIG_VFO_C:
 | |
| 		vfo_letter = 'c';
 | |
| 		break;
 | |
| 	default:
 | |
| 		rig_debug(RIG_DEBUG_ERR,
 | |
| 			  __FUNCTION__": unsupported VFO %u\n", vfo);
 | |
| 		return -RIG_EPROTO;
 | |
| 	}
 | |
| 
 | |
| 	cmd_len = sprintf(cmdbuf, "f%c%s", vfo_letter, cmd_trm(rig));
 | |
| 
 | |
| 	freq_len = 15;
 | |
| 	retval =
 | |
| 	    ts2k_transaction(rig, cmdbuf, cmd_len, freqbuf, &freq_len);
 | |
| 	//rig_debug(RIG_DEBUG_ERR,"__FUNCTION__: received %s\n", cmdbuf);
 | |
| 	if (retval != RIG_OK)
 | |
| 		return retval;
 | |
| 
 | |
| 	//if (freq_len != 14 || freqbuf[0] != 'F') {
 | |
| 	if (freqbuf[0] != 'F') {
 | |
| 		rig_debug(RIG_DEBUG_ERR,
 | |
| 			  __FUNCTION__": unexpected answer '%s', "
 | |
| 			  "len=%u\n", freqbuf, freq_len);
 | |
| 		return -RIG_ERJCTED;
 | |
| 	}
 | |
| 
 | |
| 	sscanf(freqbuf + 2, "%"SCNll, freq);
 | |
| 
 | |
| 	return RIG_OK;
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * kenwood_set_mode
 | |
|  * Assumes rig!=NULL
 | |
|  */
 | |
| int ts2k_set_mode(RIG * rig, vfo_t vfo, rmode_t mode, pbwidth_t width)
 | |
| {
 | |
| 	unsigned char mdbuf[16], ackbuf[16];
 | |
| 	int mdbuf_len, ack_len = 0, kmode, retval;
 | |
| 
 | |
| 	switch (mode) {
 | |
| 	case RIG_MODE_CW:
 | |
| 		kmode = MD_CW;
 | |
| 		break;
 | |
| 	case RIG_MODE_USB:
 | |
| 		kmode = MD_USB;
 | |
| 		break;
 | |
| 	case RIG_MODE_LSB:
 | |
| 		kmode = MD_LSB;
 | |
| 		break;
 | |
| 	case RIG_MODE_FM:
 | |
| 		kmode = MD_FM;
 | |
| 		break;
 | |
| 	case RIG_MODE_AM:
 | |
| 		kmode = MD_AM;
 | |
| 		break;
 | |
| 	case RIG_MODE_RTTY:
 | |
| 		kmode = MD_FSK;
 | |
| 		break;
 | |
| 	default:
 | |
| 		rig_debug(RIG_DEBUG_ERR, "ts2k_set_mode: "
 | |
| 			  "unsupported mode %u\n", mode);
 | |
| 		return -RIG_EINVAL;
 | |
| 	}
 | |
| 	mdbuf_len = sprintf(mdbuf, "MD%c;", kmode);
 | |
| 	ack_len = 16;
 | |
| 	rig_debug(RIG_DEBUG_ERR, "ts2k_set_mode: sending %s\n", mdbuf);
 | |
| 	retval = ts2k_transaction(rig, mdbuf, mdbuf_len, NULL, NULL);
 | |
| 
 | |
| 	return retval;
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * kenwood_get_mode
 | |
|  * Assumes rig!=NULL, mode!=NULL
 | |
|  */
 | |
| int ts2k_get_mode(RIG * rig, vfo_t vfo, rmode_t * mode, pbwidth_t * width)
 | |
| {
 | |
| 	unsigned char modebuf[50];
 | |
| 	int mode_len, retval;
 | |
| 
 | |
| 
 | |
| 	mode_len = 50;
 | |
| 	retval = ts2k_transaction(rig, "MD;", 3, modebuf, &mode_len);
 | |
| 	if (retval != RIG_OK)
 | |
| 		return retval;
 | |
| 
 | |
| 	if (mode_len != 4 || modebuf[1] != 'D') {
 | |
| 		rig_debug(RIG_DEBUG_ERR,
 | |
| 			  "ts2k_get_mode: unexpected answer, len=%u\n",
 | |
| 			  mode_len);
 | |
| 		return -RIG_ERJCTED;
 | |
| 	}
 | |
| 
 | |
| 	*width = RIG_PASSBAND_NORMAL;	/* FIXME */
 | |
| 	switch (modebuf[2]) {
 | |
| 	case MD_CW:
 | |
| 		*mode = RIG_MODE_CW;
 | |
| 		break;
 | |
| 	case MD_USB:
 | |
| 		*mode = RIG_MODE_USB;
 | |
| 		break;
 | |
| 	case MD_LSB:
 | |
| 		*mode = RIG_MODE_LSB;
 | |
| 		break;
 | |
| 	case MD_FM:
 | |
| 		*mode = RIG_MODE_FM;
 | |
| 		break;
 | |
| 	case MD_AM:
 | |
| 		*mode = RIG_MODE_AM;
 | |
| 		break;
 | |
| 	case MD_FSK:
 | |
| 		*mode = RIG_MODE_RTTY;
 | |
| 		break;
 | |
| #ifdef RIG_MODE_CWR
 | |
| 	case MD_CWR:
 | |
| 		*mode = RIG_MODE_CWR;
 | |
| 		break;
 | |
| #endif
 | |
| #ifdef RIG_MODE_RTTYR
 | |
| 	case MD_FSKR:
 | |
| 		*mode = RIG_MODE_RTTY;
 | |
| 		break;
 | |
| #endif
 | |
| 	case MD_NONE:
 | |
| 		*mode = RIG_MODE_NONE;
 | |
| 		break;
 | |
| 	default:
 | |
| 		rig_debug(RIG_DEBUG_ERR, "ts2k_get_mode: "
 | |
| 			  "unsupported mode '%c'\n", modebuf[2]);
 | |
| 		return -RIG_EINVAL;
 | |
| 	}
 | |
| 
 | |
| 	return RIG_OK;
 | |
| }
 | |
| 
 | |
| /* added a whole buch of stuff --Dale */
 | |
| int ts2k_set_level(RIG * rig, vfo_t vfo, setting_t level, value_t val)
 | |
| {
 | |
| 	unsigned char levelbuf[16], ackbuf[16], ctrl;
 | |
| 	char *dc;	// to be replaced.
 | |
| //	char dc[10];	// use this when ts2k_get_ctrl() is fixed.
 | |
| //	int dc_len;	// use this when ts2k_get_ctrl() is fixed.
 | |
| 	int level_len, ack_len = 0, retval, reply;
 | |
| 	int ts2k_val;
 | |
| 
 | |
| 	if (RIG_LEVEL_IS_FLOAT(level))
 | |
| 		ts2k_val = val.f * 255;
 | |
| 	else
 | |
| 		ts2k_val = val.i;
 | |
| 
 | |
| /* Several commands need to know status of CTRL */
 | |
| 
 | |
| //	dc_len = 10;	// these are to be used when ts2k_get_ctrl() is changed.
 | |
| //	if( ts2k_get_ctrl(rig, dc, 10) != RIG_OK)
 | |
| //		return -RIG_EINVAL;
 | |
| // we shouldn't really change dc; its a static and will get changed.
 | |
| 	dc = ts2k_get_ctrl(rig);	// will get fixed
 | |
| //	m = dc[2]; s = dc[3];		// set defaults
 | |
| 
 | |
| // FIXME: Just handles simple stuff RIG_VFO_CURR,VFOA,VFOB,VFOC; *may* work as intended. 
 | |
| 	ctrl = '0';			// Assume Main
 | |
| 	if(vfo & RIG_CTRL_SUB)		// Change only if sub (bitwise, not logical)
 | |
| 		ctrl = '1';
 | |
| 
 | |
| 	// assume no replies
 | |
| 	reply = 0;
 | |
| 	switch (level) {
 | |
| 	case RIG_LEVEL_RFPOWER:
 | |
| 		level_len = sprintf(levelbuf, "pc%03d;", ts2k_val);
 | |
| 		break;
 | |
| 
 | |
| 	case RIG_LEVEL_AF:	// I call this volume.  :)
 | |
| 		level_len = sprintf(levelbuf, "ag%c%03u;", ctrl, ts2k_val);
 | |
| 		break;
 | |
| 
 | |
| 	case RIG_LEVEL_RF:
 | |
| 		level_len = sprintf(levelbuf, "rg%03d;", ts2k_val);
 | |
| 		break;
 | |
| 
 | |
| 	case RIG_LEVEL_SQL:	// fixed: uses main/sub	--Dale
 | |
| 		level_len = sprintf(levelbuf, "sq%c%03u;", ctrl, ts2k_val);
 | |
| 		break;
 | |
| 
 | |
| 
 | |
| 	/* I added the following levels --Dale */
 | |
| 	case RIG_LEVEL_PREAMP:
 | |
| 		level_len = sprintf(levelbuf, "pa%c;", (ts2k_val==0)? '0' : '1');
 | |
| 		break;
 | |
| 
 | |
| 	case RIG_LEVEL_ATT:
 | |
| 		if(ts2k_val<1 || ts2k_val>2)	// only 1 or 2, 0=read
 | |
| 			return -RIG_EINVAL;
 | |
| 		level_len = sprintf(levelbuf, "an%01u;", ts2k_val);
 | |
| 		break;
 | |
| 
 | |
| 	case RIG_LEVEL_NR:
 | |
| 		if(ts2k_val<0 || ts2k_val>2)	// only 1 or 2, 0=read
 | |
| 			return -RIG_EINVAL;
 | |
| 		level_len = sprintf(levelbuf, "nr%01u;", ts2k_val);
 | |
| 		break;
 | |
| 
 | |
| 	/* FIXME: FM mic gain is low/mid/high; cmd="ex0410000n;" 0=low --Dale */
 | |
| 	case RIG_LEVEL_MICGAIN:
 | |
| 		level_len = sprintf(levelbuf, "mg%03u;", (ts2k_val>100)? 100 : ts2k_val);
 | |
| 		break;
 | |
| 
 | |
| 	/* no rig error on invalid values */
 | |
| 	case RIG_LEVEL_KEYSPD:
 | |
| 		if(ts2k_val<10 || ts2k_val>60)	// only 1 or 2, 0=read
 | |
| 			return -RIG_EINVAL;
 | |
| 		level_len = sprintf(levelbuf, "ks%03u;", ts2k_val);
 | |
| 		break;
 | |
| 
 | |
| 	case RIG_LEVEL_NOTCHF:	// actually, this is autonotch--same thing?
 | |
| 		level_len = sprintf(levelbuf, "al%03u;", (ts2k_val>4)? 4 : ts2k_val);
 | |
| 		break;
 | |
| 
 | |
| 	case RIG_LEVEL_AGC:
 | |
| 		level_len = sprintf(levelbuf, "gt%03u;", (ts2k_val>20)? 20 : ts2k_val);
 | |
| 		break;
 | |
| 
 | |
| 	case RIG_LEVEL_BKINDL:	// 0-1000ms in 50ms steps; this'll be good 'nuff.
 | |
| 		level_len = sprintf(levelbuf, "sd%04u;",(int)((float) ts2k_val*1000.0/255.0));
 | |
| 		break;
 | |
| 
 | |
| 	case RIG_LEVEL_VOXGAIN:
 | |
| 		level_len = sprintf(levelbuf, "vg%03u;",(ts2k_val>9)? 9 : ts2k_val);
 | |
| // alternate
 | |
| //		level_len = sprintf(levelbuf, "vg%03u;",(int)((float) ts2k_val*9.0/255.0));
 | |
| 		break;
 | |
| 
 | |
| //	case RIG_LEVEL_VOX:	// header file declares these the same
 | |
| 	case RIG_LEVEL_VOXDELAY:
 | |
| 		level_len = sprintf(levelbuf, "vg%03u;",(int)((float) ts2k_val*3000.0/255.0));
 | |
| 		break;
 | |
| // vox on/off
 | |
| //		level_len = sprintf(levelbuf, "vx%c;", (ts2k_val==0)? '0' : '1');
 | |
| //		break;
 | |
| 
 | |
| 	/* Check unsupported just so we can complain if one is found.  :) */
 | |
| 	case RIG_LEVEL_APF:
 | |
| 
 | |
| 	/* readonly */
 | |
| 	case RIG_LEVEL_SWR:
 | |
| 	case RIG_LEVEL_ALC:
 | |
| 	case RIG_LEVEL_STRENGTH:
 | |
| 		return -RIG_EINTERNAL;	// and complain loud!
 | |
| 
 | |
| 	/* not currently implemented */
 | |
| 	case RIG_LEVEL_METER:	// readonly + needs rechecked.
 | |
| 	case RIG_LEVEL_PBT_IN:	// nnn
 | |
| 	case RIG_LEVEL_PBT_OUT: // NNN; "plnnnNNN;"
 | |
| 	case RIG_LEVEL_IF:	// hmmmm....
 | |
| 	case RIG_LEVEL_CWPITCH:	// "ex0310000n;" and a fair bit of programming...
 | |
| 	case RIG_LEVEL_COMP:	// available?, processor's not the same is it?
 | |
| 	case RIG_LEVEL_BALANCE:	// AF R/L balance?  See "ex01600002;" for similar(?)
 | |
| 	case RIG_LEVEL_SQLSTAT:	// need more info; avail?
 | |
| 		return -RIG_ENIMPL;
 | |
| 
 | |
| 	default:
 | |
| 		rig_debug(RIG_DEBUG_ERR,
 | |
| 			  "Unsupported set_level %u", level);
 | |
| 		return -RIG_EINVAL;
 | |
| 	}
 | |
| 	// The following might make a nifty macro	--Dale
 | |
| 	ack_len = reply? 16 : 0;	// This'd work by itself wouldn't it?  --Dale
 | |
| 	retval = ts2k_transaction(rig, levelbuf, level_len,
 | |
| 			reply? ackbuf : NULL, reply? &ack_len : NULL);
 | |
| 
 | |
| 	if (retval != RIG_OK)
 | |
| 		return retval;
 | |
| 
 | |
| 	return RIG_OK;
 | |
| }
 | |
| 
 | |
| /* 
 | |
|  * assumes f!=NULL
 | |
|  */
 | |
| static int
 | |
| get_ts2k_level(RIG * rig, const char *cmd, int cmd_len, float *f)
 | |
| {
 | |
| 	unsigned char lvlbuf[50];
 | |
| 	int lvl_len, retval;
 | |
| 	int lvl;
 | |
| 
 | |
| 	lvl_len = 50;
 | |
| 	retval = ts2k_transaction(rig, cmd, cmd_len, lvlbuf, &lvl_len);
 | |
| 	if (retval != RIG_OK)
 | |
| 		return retval;
 | |
| 
 | |
| 	if (lvl_len != 6) {
 | |
| 		rig_debug(RIG_DEBUG_ERR,
 | |
| 			  "ts2k_get_level: wrong answer len=%u\n",
 | |
| 			  lvl_len);
 | |
| 		return -RIG_ERJCTED;
 | |
| 	}
 | |
| 
 | |
| 	/*
 | |
| 	 * 000..255
 | |
| 	 */
 | |
| 	sscanf(lvlbuf + 2, "%u", &lvl);
 | |
| 	*f = (float) lvl / 255.0;
 | |
| 
 | |
| 	return RIG_OK;
 | |
| };
 | |
| 
 | |
| 
 | |
| /*
 | |
|  * kenwood_get_level
 | |
|  * Assumes rig!=NULL, val!=NULL
 | |
|  */
 | |
| int ts2k_get_level(RIG * rig, vfo_t vfo, setting_t level, value_t * val)
 | |
| {
 | |
| 	unsigned char lvlbuf[50];
 | |
| 	int lvl_len, retval;
 | |
| 	int lvl;
 | |
| 	int i;
 | |
| 
 | |
| 	lvl_len = 50;
 | |
| 	/* Optimize:
 | |
| 	 *   sort the switch cases with the most frequent first
 | |
| 	 */
 | |
| 	switch (level) {
 | |
| 	case RIG_LEVEL_STRENGTH:
 | |
| 		// fixme: "sm0;" VFO must be specified!  --kd7eni
 | |
| 		retval = ts2k_transaction(rig, "SM;", 3, lvlbuf, &lvl_len);
 | |
| 		if (retval != RIG_OK)
 | |
| 			return retval;
 | |
| 
 | |
| 		if (lvl_len != 7 || lvlbuf[1] != 'M') {
 | |
| 			rig_debug(RIG_DEBUG_ERR, "ts2k_get_level: "
 | |
| 				  "wrong answer len=%u\n", lvl_len);
 | |
| 			return -RIG_ERJCTED;
 | |
| 		}
 | |
| 
 | |
| 		/*
 | |
| 		 * Frontend expects:
 | |
| 		 *    -54 = S0
 | |
| 		 *              0 = S9
 | |
| 		 */
 | |
| 		sscanf(lvlbuf + 2, "%u", &val->i);
 | |
| 		val->i = (val->i * 4) - 54;
 | |
| 		break;
 | |
| 
 | |
| 	case RIG_LEVEL_SQLSTAT:
 | |
| 		return -RIG_ENIMPL;	/* get_dcd ? */
 | |
| 
 | |
| 	case RIG_LEVEL_PREAMP:
 | |
| 		return -RIG_ENIMPL;
 | |
| 
 | |
| 	case RIG_LEVEL_ATT:
 | |
| 		retval = ts2k_transaction(rig, "RA;", 3, lvlbuf, &lvl_len);
 | |
| 		if (retval != RIG_OK)
 | |
| 			return retval;
 | |
| 
 | |
| 		if (lvl_len != 5) {
 | |
| 			rig_debug(RIG_DEBUG_ERR, "ts2k_get_level: "
 | |
| 				  "unexpected answer len=%u\n", lvl_len);
 | |
| 			return -RIG_ERJCTED;
 | |
| 		}
 | |
| 
 | |
| 		sscanf(lvlbuf + 2, "%u", &lvl);
 | |
| 		if (lvl == 0) {
 | |
| 			val->i = 0;
 | |
| 		} else {
 | |
| 			for (i = 0; i < lvl && i < MAXDBLSTSIZ; i++)
 | |
| 				if (rig->state.attenuator[i] == 0) {
 | |
| 					rig_debug(RIG_DEBUG_ERR,
 | |
| 						  "ts2k_get_level: "
 | |
| 						  "unexpected att level %u\n",
 | |
| 						  lvl);
 | |
| 					return -RIG_EPROTO;
 | |
| 				}
 | |
| 			if (i != lvl)
 | |
| 				return -RIG_EINTERNAL;
 | |
| 			val->i = rig->state.attenuator[i - 1];
 | |
| 		}
 | |
| 		break;
 | |
| 	case RIG_LEVEL_RFPOWER:
 | |
| 		return get_ts2k_level(rig, "PC;", 3, &val->f);
 | |
| 
 | |
| 	case RIG_LEVEL_AF:
 | |
| 		return get_ts2k_level(rig, "AG;", 3, &val->f);
 | |
| 
 | |
| 	case RIG_LEVEL_RF:
 | |
| 		return get_ts2k_level(rig, "RG;", 3, &val->f);
 | |
| 
 | |
| 	case RIG_LEVEL_SQL:
 | |
| 		return get_ts2k_level(rig, "SQ;", 3, &val->f);
 | |
| 
 | |
| 	case RIG_LEVEL_MICGAIN:
 | |
| 		return get_ts2k_level(rig, "MG;", 3, &val->f);
 | |
| 
 | |
| 	case RIG_LEVEL_AGC:
 | |
| 		return get_ts2k_level(rig, "GT;", 3, &val->f);
 | |
| 
 | |
| 	case RIG_LEVEL_IF:
 | |
| 	case RIG_LEVEL_APF:
 | |
| 	case RIG_LEVEL_NR:
 | |
| 	case RIG_LEVEL_PBT_IN:
 | |
| 	case RIG_LEVEL_PBT_OUT:
 | |
| 	case RIG_LEVEL_CWPITCH:
 | |
| 	case RIG_LEVEL_KEYSPD:
 | |
| 	case RIG_LEVEL_NOTCHF:
 | |
| 	case RIG_LEVEL_COMP:
 | |
| 	case RIG_LEVEL_BKINDL:
 | |
| 	case RIG_LEVEL_BALANCE:
 | |
| 		return -RIG_ENIMPL;
 | |
| 
 | |
| 	default:
 | |
| 		rig_debug(RIG_DEBUG_ERR,
 | |
| 			  "Unsupported get_level %u", level);
 | |
| 		return -RIG_EINVAL;
 | |
| 	}
 | |
| 
 | |
| 	return RIG_OK;
 | |
| }
 | |
| 
 | |
| 
 | |
| int ts2k_set_func(RIG * rig, vfo_t vfo, setting_t func, int status)
 | |
| {
 | |
| 	unsigned char fctbuf[16], ackbuf[16];
 | |
| 	int fct_len, ack_len = 16;
 | |
| 
 | |
| 	/* Optimize:
 | |
| 	 *   sort the switch cases with the most frequent first
 | |
| 	 */
 | |
| 	switch (func) {
 | |
| 	case RIG_FUNC_NB:
 | |
| 		fct_len =
 | |
| 		    sprintf(fctbuf, "NB%c;",
 | |
| 			    status == RIG_FUNC_NB ? '0' : '1');
 | |
| 		return ts2k_transaction(rig, fctbuf, fct_len, NULL, NULL);
 | |
| 
 | |
| 	case RIG_FUNC_ABM:
 | |
| 		fct_len =
 | |
| 		    sprintf(fctbuf, "AM%c;",
 | |
| 			    status == RIG_FUNC_ABM ? '0' : '1');
 | |
| 		return ts2k_transaction(rig, fctbuf, fct_len, NULL, NULL);
 | |
| 
 | |
| 	case RIG_FUNC_COMP:
 | |
| 		fct_len =
 | |
| 		    sprintf(fctbuf, "PR%c;",
 | |
| 			    status == RIG_FUNC_COMP ? '0' : '1');
 | |
| 		return ts2k_transaction(rig, fctbuf, fct_len, NULL, NULL);
 | |
| 
 | |
| 	case RIG_FUNC_TONE:
 | |
| 		fct_len =
 | |
| 		    sprintf(fctbuf, "TO%c;",
 | |
| 			    status == RIG_FUNC_TONE ? '0' : '1');
 | |
| 		return ts2k_transaction(rig, fctbuf, fct_len, NULL, NULL);
 | |
| 
 | |
| 	case RIG_FUNC_TSQL:
 | |
| 		// fixme: see ts2000.doc and follow the proceedure!  --kdeni
 | |
| 		// rigbug!
 | |
| 		fct_len =
 | |
| 		    sprintf(fctbuf, "CT%c;",
 | |
| 			    status == RIG_FUNC_TSQL ? '0' : '1');
 | |
| 		return ts2k_transaction(rig, fctbuf, fct_len,
 | |
| 					ackbuf, &ack_len);
 | |
| 
 | |
| 	case RIG_FUNC_VOX:
 | |
| 		fct_len =
 | |
| 		    sprintf(fctbuf, "VX%c;",
 | |
| 			    status == RIG_FUNC_VOX ? '0' : '1');
 | |
| 		return ts2k_transaction(rig, fctbuf, fct_len, NULL, NULL);
 | |
| 
 | |
| 	case RIG_FUNC_NR:
 | |
| 		fct_len =
 | |
| 		    sprintf(fctbuf, "NR%c;",
 | |
| 			    status == RIG_FUNC_NR ? '0' : '1');
 | |
| 		return ts2k_transaction(rig, fctbuf, fct_len, NULL, NULL);
 | |
| 
 | |
| 	case RIG_FUNC_BC:
 | |
| 		fct_len =
 | |
| 		    sprintf(fctbuf, "BC%c;",
 | |
| 			    status == RIG_FUNC_BC ? '0' : '1');
 | |
| 		return ts2k_transaction(rig, fctbuf, fct_len, NULL, NULL);
 | |
| 
 | |
| 	case RIG_FUNC_ANF:
 | |
| 		fct_len =
 | |
| 		    sprintf(fctbuf, "NT%c;",
 | |
| 			    status == RIG_FUNC_ANF ? '0' : '1');
 | |
| 		return ts2k_transaction(rig, fctbuf, fct_len, NULL, NULL);
 | |
| 
 | |
| 	case RIG_FUNC_LOCK:
 | |
| 		fct_len =
 | |
| 		    sprintf(fctbuf, "LK%c0;",
 | |
| 			    status == RIG_FUNC_LOCK ? '0' : '1');
 | |
| 		return ts2k_transaction(rig, fctbuf, fct_len, NULL, NULL);
 | |
| 
 | |
| 	default:
 | |
| 		rig_debug(RIG_DEBUG_ERR, "Unsupported set_func %#x", func);
 | |
| 		return -RIG_EINVAL;
 | |
| 	}
 | |
| 	return RIG_OK;
 | |
| }
 | |
| 
 | |
| 
 | |
| /* 
 | |
|  * assumes status!=NULL
 | |
|  * works for any 'format 1' command
 | |
|  */
 | |
| static int
 | |
| get_ts2k_func(RIG * rig, const char *cmd, int cmd_len, int *status)
 | |
| {
 | |
| 	unsigned char fctbuf[50];
 | |
| 	int fct_len, retval;
 | |
| 
 | |
| 	fct_len = 50;
 | |
| 	retval = ts2k_transaction(rig, cmd, cmd_len, fctbuf, &fct_len);
 | |
| 	if (retval != RIG_OK)
 | |
| 		return retval;
 | |
| 
 | |
| 	if (fct_len != 4) {
 | |
| 		rig_debug(RIG_DEBUG_ERR,
 | |
| 			  __FUNCTION__": wrong answer len=%u\n", fct_len);
 | |
| 		return -RIG_ERJCTED;
 | |
| 	}
 | |
| 
 | |
| 	*status = fctbuf[2] == '0' ? 0 : 1;
 | |
| 
 | |
| 	return RIG_OK;
 | |
| };
 | |
| 
 | |
| 
 | |
| /*
 | |
|  * kenwood_get_func
 | |
|  * Assumes rig!=NULL, val!=NULL
 | |
|  */
 | |
| int ts2k_get_func(RIG * rig, vfo_t vfo, setting_t func, int *status)
 | |
| {
 | |
| 	unsigned char fctbuf[50];
 | |
| 	int fct_len, retval;
 | |
| 
 | |
| 	fct_len = 50;
 | |
| 	/* Optimize:
 | |
| 	 *   sort the switch cases with the most frequent first
 | |
| 	 */
 | |
| 	switch (func) {
 | |
| 	case RIG_FUNC_FAGC:
 | |
| 		retval = ts2k_transaction(rig, "GT;", 3, fctbuf, &fct_len);
 | |
| 		if (retval != RIG_OK)
 | |
| 			return retval;
 | |
| 
 | |
| 		if (fct_len != 6) {
 | |
| 			rig_debug(RIG_DEBUG_ERR, "ts2k_get_func: "
 | |
| 				  "wrong answer len=%u\n", fct_len);
 | |
| 			return -RIG_ERJCTED;
 | |
| 		}
 | |
| 
 | |
| 		*status = fctbuf[4] != '4' ? 1 : 0;
 | |
| 		break;
 | |
| 
 | |
| 	case RIG_FUNC_NB:
 | |
| 		return get_ts2k_func(rig, "NB;", 3, status);
 | |
| 
 | |
| 	case RIG_FUNC_ABM:
 | |
| 		return get_ts2k_func(rig, "AM;", 3, status);
 | |
| 
 | |
| 	case RIG_FUNC_COMP:
 | |
| 		return get_ts2k_func(rig, "PR;", 3, status);
 | |
| 
 | |
| 	case RIG_FUNC_TONE:
 | |
| 		return get_ts2k_func(rig, "TO;", 3, status);
 | |
| 
 | |
| 	case RIG_FUNC_TSQL:
 | |
| 		return get_ts2k_func(rig, "CT;", 3, status);
 | |
| 
 | |
| 	case RIG_FUNC_VOX:
 | |
| 		return get_ts2k_func(rig, "VX;", 3, status);
 | |
| 
 | |
| 	case RIG_FUNC_NR:
 | |
| 		return get_ts2k_func(rig, "NR;", 3, status);
 | |
| 
 | |
| 		/* FIXME on TS2000 */
 | |
| 	case RIG_FUNC_BC:
 | |
| 		return get_ts2k_func(rig, "BC;", 3, status);
 | |
| 
 | |
| 	case RIG_FUNC_ANF:
 | |
| 		return get_ts2k_func(rig, "NT;", 3, status);
 | |
| 
 | |
| 	case RIG_FUNC_LOCK:
 | |
| 		return get_ts2k_func(rig, "LK;", 3, status);
 | |
| 
 | |
| 	default:
 | |
| 		rig_debug(RIG_DEBUG_ERR, "Unsupported get_func %#x", func);
 | |
| 		return -RIG_EINVAL;
 | |
| 	}
 | |
| 
 | |
| 	return RIG_OK;
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * kenwood_set_ctcss_tone
 | |
|  * Assumes rig!=NULL, rig->caps->ctcss_list != NULL
 | |
|  *
 | |
|  * Warning! This is untested stuff! May work at least on TS-870S
 | |
|  * 	Please owners report to me <fillods@users.sourceforge.net>, thanks. --SF
 | |
|  *
 | |
|  * TODO: TS-2000 uses CN/CT
 | |
|  *	ex057 menu is AutoPower off for TS-2000	--kd7eni
 | |
|  */
 | |
| int ts2k_set_ctcss_tone(RIG * rig, vfo_t vfo, tone_t tone)
 | |
| {
 | |
| 	return ts2k_set_Tones(rig, vfo, tone, (char)'c');
 | |
| }
 | |
| 
 | |
| int ts2k_set_tone(RIG * rig, vfo_t vfo, tone_t tone)
 | |
| {
 | |
| 	return ts2k_set_Tones(rig, vfo, tone, (char)'t');
 | |
| }
 | |
| 
 | |
| int ts2k_set_Tones(RIG * rig, vfo_t vfo, tone_t tone, const char ct)
 | |
| {
 | |
| 	const struct rig_caps *caps;
 | |
| 	unsigned char tonebuf[16], ackbuf[16];
 | |
| 	int tone_len, ack_len = 0;
 | |
| 	int i;
 | |
| 
 | |
| 	caps = rig->caps;
 | |
| 
 | |
| /* TODO: replace 200 by something like RIGTONEMAX */
 | |
| 	for (i = 0; ts2k_ctcss_list[i] != 0 && i < 38; i++) {
 | |
| 		if ((ts2k_ctcss_list[i] >= tone)
 | |
| 			&& (ts2k_ctcss_list[i-1] < tone))	// at least get close
 | |
| 			break;
 | |
| 	}
 | |
| 	if (ts2k_ctcss_list[i-1] == tone)
 | |
| 		i--;
 | |
| 	if (ts2k_ctcss_list[i] > tone)
 | |
| 		return -RIG_EINVAL;
 | |
| 
 | |
| 	tone_len = sprintf(tonebuf, "%cn%02u;", ct, i+1);
 | |
| 
 | |
| 	ack_len = 16;
 | |
| 	return ts2k_transaction(rig, tonebuf, tone_len, NULL, NULL);
 | |
| 	rig_debug(RIG_DEBUG_ERR, __FUNCTION__": sent %s", tonebuf);
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * kenwood_get_ctcss_tone
 | |
|  * Assumes rig!=NULL, rig->state.priv!=NULL
 | |
|  */
 | |
| int ts2k_get_ctcss_tone(RIG * rig, vfo_t vfo, tone_t * tone)
 | |
| {
 | |
| 	return ts2k_get_Tones(rig, vfo, tone, "cn;");
 | |
| }
 | |
| 
 | |
| int ts2k_get_tone(RIG * rig, vfo_t vfo, tone_t * tone)
 | |
| {
 | |
| 	return ts2k_get_Tones(rig, vfo, tone, "tn;");
 | |
| }
 | |
| 
 | |
| int ts2k_get_Tones(RIG * rig, vfo_t vfo, tone_t * tone, const char *ct)
 | |
| {
 | |
| 	const struct rig_caps *caps;
 | |
| 	unsigned char tonebuf[10];
 | |
| 	int tone_len, i, retval;
 | |
| 	unsigned int tone_idx;
 | |
| 
 | |
| 	caps = rig->caps;
 | |
| 
 | |
| 	tone_len = 10;
 | |
| 	retval = ts2k_transaction(rig, ct, 3, tonebuf, &tone_len);
 | |
| 	if (retval != RIG_OK)
 | |
| 		return retval;
 | |
| 
 | |
| 	if (tone_len != 5) {
 | |
| 		rig_debug(RIG_DEBUG_ERR,
 | |
| 			  __FUNCTION__": unexpected reply "
 | |
| 			  "'%s', len=%u\n", tonebuf, tone_len);
 | |
| 		return -RIG_ERJCTED;
 | |
| 	}
 | |
| 
 | |
| 	sscanf(tonebuf + 2, "%u", (int *) &tone_idx);
 | |
| 
 | |
| 	if (tone_idx == 0) {
 | |
| 		rig_debug(RIG_DEBUG_ERR,
 | |
| 			  __FUNCTION__": Unexpected Tone "
 | |
| 			  "no (%04d)\n", tone_idx);
 | |
| 		return -RIG_EPROTO;
 | |
| 	}
 | |
| 
 | |
| 	/* check this tone exists. That's better than nothing. */
 | |
| 	for (i = 0; i < tone_idx; i++) {
 | |
| 		if (caps->ctcss_list[i] == 0) {
 | |
| 			rig_debug(RIG_DEBUG_ERR,
 | |
| 				  __FUNCTION__": Tone NG "
 | |
| 				  "(%04d)\n", tone_idx);
 | |
| 			return -RIG_EPROTO;
 | |
| 		}
 | |
| 	}
 | |
| 	*tone = caps->ctcss_list[tone_idx - 1];
 | |
| 
 | |
| 	return RIG_OK;
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * kenwood_get_ptt
 | |
|  * Assumes rig!=NULL, ptt!=NULL
 | |
|  */
 | |
| int ts2k_get_ptt(RIG * rig, vfo_t vfo, ptt_t * ptt)
 | |
| {
 | |
| 	unsigned char infobuf[50];
 | |
| 	int info_len, retval;
 | |
| 
 | |
| 	info_len = 50;
 | |
| 	retval = ts2k_transaction(rig, "IF;", 3, infobuf, &info_len);
 | |
| 	if (retval != RIG_OK)
 | |
| 		return retval;
 | |
| 
 | |
| 	if (info_len != 38 || infobuf[1] != 'F') {
 | |
| 		rig_debug(RIG_DEBUG_ERR,
 | |
| 			  "ts2k_get_ptt: wrong answer len=%u\n", info_len);
 | |
| 		return -RIG_ERJCTED;
 | |
| 	}
 | |
| 
 | |
| 	*ptt = infobuf[28] == '0' ? RIG_PTT_OFF : RIG_PTT_ON;
 | |
| 
 | |
| 	return RIG_OK;
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * kenwood_set_ptt
 | |
|  * Assumes rig!=NULL
 | |
|  */
 | |
| int ts2k_set_ptt(RIG * rig, vfo_t vfo, ptt_t ptt)
 | |
| {
 | |
| 	unsigned char ackbuf[16];
 | |
| 	int ack_len = 16;
 | |
| 
 | |
| 
 | |
| 	return ts2k_transaction(rig,
 | |
| 				ptt ==
 | |
| 				RIG_PTT_ON ? "TX;" : "RX;", 3, NULL, NULL);
 | |
| }
 | |
| /*
 | |
|  * kenwood_get_dcd
 | |
|  * Assumes rig!=NULL, dcd!=NULL
 | |
|  */
 | |
| int ts2k_get_dcd(RIG * rig, vfo_t vfo, dcd_t * dcd)
 | |
| {
 | |
| 	unsigned char busybuf[50];
 | |
| 	int busy_len, retval;
 | |
| 
 | |
| 	busy_len = 50;
 | |
| 	retval = ts2k_transaction(rig, "BY;", 3, busybuf, &busy_len);
 | |
| 	if (retval != RIG_OK)
 | |
| 		return retval;
 | |
| 
 | |
| 	if (busy_len != 4) {
 | |
| 		rig_debug(RIG_DEBUG_ERR,
 | |
| 			  "ts2k_get_dcd: wrong answer len=%u\n", busy_len);
 | |
| 		return -RIG_ERJCTED;
 | |
| 	}
 | |
| 
 | |
| 	*dcd = (busybuf[2] == 0x01) ? RIG_DCD_ON : RIG_DCD_OFF;
 | |
| 
 | |
| 	return RIG_OK;
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * kenwood_set_trn
 | |
|  * Assumes rig!=NULL
 | |
|  */
 | |
| int ts2k_set_trn(RIG * rig, int trn)
 | |
| {
 | |
| 	unsigned char trnbuf[16], ackbuf[16];
 | |
| 	int trn_len, ack_len = 16;
 | |
| 
 | |
| 	/* changed to TS-2000 --D.E. kd7eni */
 | |
| 
 | |
| 	trn_len = sprintf(trnbuf, "AI%c;", trn == RIG_TRN_RIG ? '2' : '0');
 | |
| 
 | |
| 	return ts2k_transaction(rig, trnbuf, trn_len, NULL, NULL);
 | |
| 	// No reply on "ai2;"--how quaint!
 | |
| }
 | |
| /*
 | |
|  * kenwood_get_trn
 | |
|  * Assumes rig!=NULL, trn!=NULL
 | |
|  */ int ts2k_get_trn(RIG * rig, int *trn)
 | |
| {
 | |
| 	unsigned char trnbuf[50];
 | |
| 	int trn_len, retval;
 | |
| 
 | |
| 	trn_len = 50;
 | |
| 	retval = ts2k_transaction(rig, "AI;", 3, trnbuf, &trn_len);
 | |
| 	if (retval != RIG_OK)
 | |
| 		return retval;
 | |
| 
 | |
| 	if (trn_len != 4) {
 | |
| 		rig_debug(RIG_DEBUG_ERR,
 | |
| 			  "ts2k_get_trn: wrong answer" "len=%u\n",
 | |
| 			  trn_len);
 | |
| 		return -RIG_ERJCTED;
 | |
| 	}
 | |
| 	*trn = trnbuf[2] != '0' ? RIG_TRN_RIG : RIG_TRN_OFF;
 | |
| 
 | |
| 	return RIG_OK;
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * kenwood_set_powerstat
 | |
|  * Assumes rig!=NULL
 | |
|  */
 | |
| int ts2k_set_powerstat(RIG * rig, powerstat_t status)
 | |
| {
 | |
| 	unsigned char pwrbuf[16], ackbuf[16];
 | |
| 	int pwr_len, ack_len = 16;
 | |
| 
 | |
| 	pwr_len =
 | |
| 	    sprintf(pwrbuf, "PS%c;", status == RIG_POWER_ON ? '1' : '0');
 | |
| 
 | |
| 	return ts2k_transaction(rig, pwrbuf, pwr_len, ackbuf, &ack_len);
 | |
| }
 | |
| /*
 | |
|  * kenwood_get_powerstat
 | |
|  * Assumes rig!=NULL, trn!=NULL
 | |
|  */
 | |
| int ts2k_get_powerstat(RIG * rig, powerstat_t * status)
 | |
| {
 | |
| 	unsigned char pwrbuf[50];
 | |
| 	int pwr_len = 50, retval;
 | |
| 
 | |
| 	// No reply when powered off, 1=power on.  Geez!
 | |
| 	retval = ts2k_transaction(rig, "PS;", 3, pwrbuf, &pwr_len);
 | |
| 	if (retval != RIG_OK)
 | |
| 		return retval;
 | |
| 
 | |
| 	if (pwr_len != 4) {
 | |
| 		rig_debug(RIG_DEBUG_ERR,
 | |
| 			  "ts2k_get_powerstat: wrong answer "
 | |
| 			  "len=%u\n", pwr_len);
 | |
| 		return -RIG_ERJCTED;
 | |
| 	}
 | |
| 	*status = pwrbuf[2] == '0' ? RIG_POWER_OFF : RIG_POWER_ON;
 | |
| 
 | |
| 	return RIG_OK;
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * kenwood_reset
 | |
|  * Assumes rig!=NULL
 | |
|  */
 | |
| int ts2k_reset(RIG * rig, reset_t reset)
 | |
| {
 | |
| 	unsigned char rstbuf[16], ackbuf[16];
 | |
| 	int rst_len, ack_len = 16;
 | |
| 	char rst;
 | |
| 
 | |
| 	switch (reset) {
 | |
| 	case RIG_RESET_VFO:
 | |
| 		rst = '1';
 | |
| 		break;
 | |
| 	case RIG_RESET_MASTER:
 | |
| 		rst = '2';
 | |
| 		break;
 | |
| 	default:
 | |
| 		rig_debug(RIG_DEBUG_ERR,
 | |
| 			  "ts2k_reset: unsupported reset %u\n", reset);
 | |
| 		return -RIG_EINVAL;
 | |
| 	}
 | |
| 	rst_len = sprintf(rstbuf, "SR%c;", rst);
 | |
| 
 | |
| 	// Largely untested!    ;)      --kd7eni
 | |
| 	return ts2k_transaction(rig, rstbuf, rst_len, ackbuf, &ack_len);
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * kenwood_send_morse
 | |
|  * Assumes rig!=NULL
 | |
|  */
 | |
| int ts2k_send_morse(RIG * rig, vfo_t vfo, const char *msg)
 | |
| {
 | |
| 	unsigned char morsebuf[30], ackbuf[16];
 | |
| 	int morse_len, ack_len = 0;
 | |
| 	int msg_len, buff_len, retval;
 | |
| 	const char *p;
 | |
| 
 | |
| 	p = msg;
 | |
| 	msg_len = strlen(msg);
 | |
| 
 | |
| 	while (msg_len > 0) {
 | |
| 		/*
 | |
| 		 * TODO: check with "KY;" if char buffer is available.
 | |
| 		 *              if not, sleep.
 | |
| 		 */
 | |
| 		buff_len = msg_len > 24 ? 24 : msg_len;
 | |
| 
 | |
| 		strcpy(morsebuf, "KY ");
 | |
| 		strncat(morsebuf, p, buff_len);
 | |
| 		strcat(morsebuf, ";");
 | |
| 		morse_len = 4 + buff_len;
 | |
| 		ack_len = 16;
 | |
| 		retval =
 | |
| 		    ts2k_transaction(rig, morsebuf, morse_len,
 | |
| 				     ackbuf, &ack_len);
 | |
| 		if (retval != RIG_OK)
 | |
| 			return retval;
 | |
| 
 | |
| 		msg_len -= buff_len;
 | |
| 		p += buff_len;
 | |
| 	}
 | |
| 	return RIG_OK;
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * kenwood_vfo_op
 | |
|  * Assumes rig!=NULL
 | |
|  */
 | |
| int ts2k_vfo_op(RIG * rig, vfo_t vfo, vfo_op_t op)
 | |
| {
 | |
| 	unsigned char *cmd, ackbuf[16];
 | |
| 	int ack_len = 0;
 | |
| 
 | |
| 	switch (op) {
 | |
| 	case RIG_OP_UP:
 | |
| 		cmd = "UP;";
 | |
| 		break;
 | |
| 	case RIG_OP_DOWN:
 | |
| 		cmd = "DN;";
 | |
| 		break;
 | |
| 	case RIG_OP_BAND_UP:
 | |
| 		cmd = "BD;";
 | |
| 		break;
 | |
| 	case RIG_OP_BAND_DOWN:
 | |
| 		cmd = "BU;";
 | |
| 		break;
 | |
| 	default:
 | |
| 		rig_debug(RIG_DEBUG_ERR,
 | |
| 			  "ts2k_vfo_op: unsupported op %#x\n", op);
 | |
| 		return -RIG_EINVAL;
 | |
| 	}
 | |
| 	ack_len = 16;
 | |
| 	return ts2k_transaction(rig, cmd, 3, NULL, NULL);
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * kenwood_set_mem
 | |
|  * Assumes rig!=NULL
 | |
|  */
 | |
| int ts2k_set_mem(RIG * rig, vfo_t vfo, int ch)
 | |
| {
 | |
| 	unsigned char membuf[16], ackbuf[16];
 | |
| 	int mem_len, ack_len = 16;
 | |
| 
 | |
| 	/*
 | |
| 	 * "MCbmm;"
 | |
| 	 * where b is the bank number, mm the memory number.
 | |
| 	 * b can be a space ( *not*! manual wrong. --kd7eni
 | |
| 	 */
 | |
| 	mem_len = sprintf(membuf, "MC%03d;", ch);
 | |
| 
 | |
| 	return ts2k_transaction(rig, membuf, mem_len, NULL, NULL);
 | |
| }
 | |
| /*
 | |
|  * kenwood_get_mem
 | |
|  * Assumes rig!=NULL
 | |
|  */ int ts2k_get_mem(RIG * rig, vfo_t vfo, int *ch)
 | |
| {
 | |
| 	unsigned char membuf[50];
 | |
| 	int retval, mem_len;
 | |
| 
 | |
| 	/*
 | |
| 	 * "MCbmm;"
 | |
| 	 * where b is the bank number, mm the memory number.
 | |
| 	 * b can be a space (*not* --kd7eni)
 | |
| 	 */
 | |
| 
 | |
| 	mem_len = 10;
 | |
| 	retval = ts2k_transaction(rig, "MC;", 3, membuf, &mem_len);
 | |
| 	if (retval != RIG_OK)
 | |
| 		return retval;
 | |
| 
 | |
| 	if (mem_len != 6) {
 | |
| 		rig_debug(RIG_DEBUG_ERR,
 | |
| 			  "ts2k_get_mem: wrong answer " "len=%u\n",
 | |
| 			  mem_len);
 | |
| 		return -RIG_ERJCTED;
 | |
| 	}
 | |
| 	membuf[5] = '\0';
 | |
| 	*ch = atoi(membuf + 2);
 | |
| 
 | |
| 	return RIG_OK;
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * kenwood_get_info
 | |
|  * supposed to work only for TS2000...
 | |
|  * Assumes rig!=NULL
 | |
|  */
 | |
| const char *ts2k_get_info(RIG * rig)
 | |
| {
 | |
| 	unsigned char firmbuf[50];
 | |
| 	int firm_len, retval;
 | |
| 
 | |
| 	firm_len = 50;
 | |
| 	retval = ts2k_transaction(rig, "TY;", 3, firmbuf, &firm_len);
 | |
| 	if (retval != RIG_OK)
 | |
| 		return NULL;
 | |
| 
 | |
| 	if (firm_len != 6) {
 | |
| 		rig_debug(RIG_DEBUG_ERR,
 | |
| 			  "ts2k_get_info: wrong answer len=%u\n",
 | |
| 			  firm_len);
 | |
| 		return NULL;
 | |
| 	}
 | |
| 
 | |
| 	switch (firmbuf[4]) {
 | |
| 	case '0':
 | |
| 		return "Firmware: Overseas type";
 | |
| 	case '1':
 | |
| 		return "Firmware: Japanese 100W type";
 | |
| 	case '2':
 | |
| 		return "Firmware: Japanese 20W type";
 | |
| 	default:
 | |
| 		return "Firmware: unknown";
 | |
| 	}
 | |
| }
 | |
| 
 | |
| #define IDBUFSZ 16
 | |
| 
 | |
| /*
 | |
|  * probe_kenwood
 | |
|  */
 | |
| rig_model_t probe_ts2k(port_t * port)
 | |
| {
 | |
| 	unsigned char idbuf[IDBUFSZ];
 | |
| 	int id_len, i, k_id;
 | |
| 	int retval;
 | |
| 
 | |
| 	if (!port)
 | |
| 		return RIG_MODEL_NONE;
 | |
| 
 | |
| 	port->write_delay = port->post_write_delay = 0;
 | |
| 	port->timeout = 50;
 | |
| 	port->retry = 1;
 | |
| 
 | |
| 	retval = serial_open(port);
 | |
| 	if (retval != RIG_OK)
 | |
| 		return RIG_MODEL_NONE;
 | |
| 
 | |
| 	retval = write_block(port, "ID;", 3);
 | |
| 	id_len = read_string(port, idbuf, IDBUFSZ, EOM_KEN EOM_TH, 2);
 | |
| 
 | |
| 	close(port->fd);
 | |
| 
 | |
| 	if (retval != RIG_OK)
 | |
| 		return RIG_MODEL_NONE;
 | |
| 
 | |
| 	/* 
 | |
| 	 * reply should be something like 'IDxxx;'
 | |
| 	 */
 | |
| 	if (id_len != 5 || id_len != 6) {
 | |
| 		idbuf[7] = '\0';
 | |
| 		rig_debug(RIG_DEBUG_VERBOSE,
 | |
| 			  "probe_ts2k: protocol error,"
 | |
| 			  " expected %u, received %u: %s\n", 6,
 | |
| 			  id_len, idbuf);
 | |
| 		return RIG_MODEL_NONE;
 | |
| 	}
 | |
| 
 | |
| 
 | |
| 	/* first, try ID string */
 | |
| 	for (i = 0; ts2k_id_string_list[i].model != RIG_MODEL_NONE; i++) {
 | |
| 		if (!strncmp(ts2k_id_string_list[i].id, idbuf + 2, 16)) {
 | |
| 			rig_debug(RIG_DEBUG_VERBOSE,
 | |
| 				  "probe_ts2k: " "found %s\n", idbuf + 2);
 | |
| 			return ts2k_id_string_list[i].model;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	/* then, try ID numbers */
 | |
| 
 | |
| 	k_id = atoi(idbuf + 2);
 | |
| 
 | |
| 	for (i = 0; ts2k_id_list[i].model != RIG_MODEL_NONE; i++) {
 | |
| 		if (ts2k_id_list[i].id == k_id) {
 | |
| 			rig_debug(RIG_DEBUG_VERBOSE,
 | |
| 				  "probe_ts2k: " "found %03d\n", k_id);
 | |
| 			return ts2k_id_list[i].model;
 | |
| 		}
 | |
| 	}
 | |
| 	/*
 | |
| 	 * not found in known table.... 
 | |
| 	 * update ts2k_id_list[]!
 | |
| 	 */
 | |
| 	rig_debug(RIG_DEBUG_WARN,
 | |
| 		  "probe_ts2k: found unknown device "
 | |
| 		  "with ID %03d, please report to Hamlib "
 | |
| 		  "developers.\n", k_id);
 | |
| 
 | |
| 	return RIG_MODEL_NONE;
 | |
| }
 | |
| 
 | |
| 
 | |
| /* kenwood_init
 | |
|  *
 | |
|  * Basically, it sets up *priv
 | |
|  * REM: serial port is already open (rig->state.rigport.fd)
 | |
|  */
 | |
| int ts2k_init(RIG * rig)
 | |
| {
 | |
| 	const struct rig_caps *caps;
 | |
| 	const struct ts2k_priv_caps *priv_caps;
 | |
| 	rig_debug(RIG_DEBUG_TRACE, __FUNCTION__ ": called\n");
 | |
| 
 | |
| 	if (!rig || !rig->caps)
 | |
| 		return -RIG_EINVAL;
 | |
| 
 | |
| 	caps = rig->caps;
 | |
| 	if (!caps->priv)
 | |
| 		return -RIG_ECONF;
 | |
| 
 | |
| 	priv_caps = (const struct ts2k_priv_caps *) caps->priv;
 | |
| 
 | |
| #if 0				/* No private data for Kenwood backends */
 | |
| 	priv = (struct ts2k_priv_data *)
 | |
| 	    malloc(sizeof(struct ts2k_priv_data));
 | |
| 	if (!priv) {
 | |
| 		/* whoops! memory shortage! */
 | |
| 		return -RIG_ENOMEM;
 | |
| 	}
 | |
| 
 | |
| 	rig->state.priv = (void *) priv;
 | |
| 	/* Assign default values */
 | |
| 	priv->dummy = -1;	// placeholder for real entries.
 | |
| #endif
 | |
| 
 | |
| 	return RIG_OK;
 | |
| }
 | |
| 
 | |
| /* kenwood_cleanup
 | |
|  * the serial port is closed by the frontend
 | |
|  */
 | |
| int ts2k_cleanup(RIG * rig)
 | |
| {
 | |
| 	rig_debug(RIG_DEBUG_TRACE, __FUNCTION__ ": called\n");
 | |
| 
 | |
| 	if (!rig)
 | |
| 		return -RIG_EINVAL;
 | |
| 
 | |
| 	if (rig->state.priv)
 | |
| 		free(rig->state.priv);
 | |
| 	rig->state.priv = NULL;
 | |
| 
 | |
| 	return RIG_OK;
 | |
| }
 | |
| /*
 | |
|  * initrigs_kenwood is called by rig_backend_load
 | |
|  */ int initrigs_ts2k(void *be_handle)
 | |
| {
 | |
| 	rig_debug(RIG_DEBUG_VERBOSE, "ts2k: _init called\n");
 | |
| 
 | |
| 	rig_register(&ts950sdx_caps);
 | |
| 	rig_register(&ts50s_caps);
 | |
| 	rig_register(&ts450s_caps);
 | |
| 	rig_register(&ts570d_caps);
 | |
| 	rig_register(&ts570s_caps);
 | |
| 	rig_register(&ts790_caps);
 | |
| 	rig_register(&ts850_caps);
 | |
| 	rig_register(&ts870s_caps);
 | |
| 	rig_register(&ts2000_caps);
 | |
| 	rig_register(&thd7a_caps);
 | |
| 	rig_register(&thf7e_caps);
 | |
| 
 | |
| 	return RIG_OK;
 | |
| }
 | |
| 
 | |
| /*****************************************************************************
 | |
| 	Added the following functions.
 | |
|  	(C) Copyright 2002 by Dale E. Edmons.   All rights Reserved.
 | |
| 	License:	Identical to all other Hamlib code.
 | |
| *****************************************************************************/
 | |
| 
 | |
| #define CHKERR(c)	if((c) != RIG_OK) return c
 | |
| #define STUFF(c)	int retval, acklen=(c); char ack[c]
 | |
| //#define STUFF(c)	static int retval, acklen=(c); static char ack[c]
 | |
| 
 | |
| // The following two are expensive but convenient!
 | |
| 
 | |
| int ncpy(char *tmp, char *src, int cnt)
 | |
| {
 | |
| 	strncpy(tmp, src, cnt);
 | |
| 	tmp[cnt] = '\0';
 | |
| 	return RIG_OK;
 | |
| }
 | |
| 
 | |
| int int_n(char *tmp, char *src, const int cnt)
 | |
| {
 | |
| 	ncpy(tmp, src, cnt);
 | |
| 	return atoi(tmp);
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * ts2k_get_ctrl() ts2000 transceiver check.  Tests and returns the value of the current
 | |
|  *	PTT/CTRL (using "dc;") for main and sub transceivers.  The settings are:
 | |
|  *
 | |
|  *	    PTT	__    __ CTRL	'0' = main; '1' = sub
 | |
|  *		   \ /
 | |
|  *		"dc00;"	PTT && CTRL both on main
 | |
|  *		"dc01;"	PTT on main; CTRL on sub 
 | |
|  *		"dc10;"	PTT on sub; CTRL both on main
 | |
|  *		"dc11;"	PTT && CTRL both on sub
 | |
|  */
 | |
| //int ts2k_get_ctrl(RIG * rig, char *dc_buf, int dc_len)	// use this when static removed.
 | |
| char *ts2k_get_ctrl(RIG * rig)
 | |
| {
 | |
| 	// FIXME: I guess this shouldn't be static for re-entrancy --Dale
 | |
| 	static char dc_buf[16];
 | |
| 	static int dc_len;
 | |
| 
 | |
| 	static int retval;
 | |
| 	dc_len = 16;
 | |
| 
 | |
|  //	rig_debug(RIG_DEBUG_VERBOSE, "ts2k_get_ctrl: getting PTT/CTRL bytes\n");
 | |
| 
 | |
| 	retval = ts2k_transaction(rig, "dc;", 3, dc_buf, &dc_len);
 | |
| 	if (retval != RIG_OK) {
 | |
| 		rig_debug(RIG_DEBUG_VERBOSE,
 | |
| 			  "ts2k_get_ctrl:error: retval=%u, dc_buf=%s\n",
 | |
| 			  retval, dc_buf);
 | |
| 		return NULL;
 | |
| 	}
 | |
| //      rig_debug(RIG_DEBUG_VERBOSE, "ts2k_get_ctrl: returning %u PTT/CTRL bytes\n", dc_len);
 | |
| 
 | |
| //	return RIG_OK;	// use this when static variable removed and all other code changed.
 | |
| 	return dc_buf;
 | |
| }
 | |
| 
 | |
| /* NOTE: PTT/CTRL enable is set only if ptt != 0 (or ctrl) */
 | |
| int ts2k_set_ctrl(RIG * rig, int ptt, int ctrl)
 | |
| {
 | |
| 	STUFF(10);
 | |
| 	char *buf;
 | |
| 	int buflen = 10;
 | |
| 
 | |
| 	buf = ts2k_get_ctrl(rig);
 | |
| 	if(buf==NULL) {
 | |
| 		rig_debug(RIG_DEBUG_VERBOSE, __FUNCTION__ \
 | |
| 			": returned NULL!\n"); 
 | |
| 		return -RIG_EINVAL;
 | |
| 	}
 | |
| 	rig_debug(RIG_DEBUG_VERBOSE, __FUNCTION__": curr='%s',"
 | |
| 			"ptt=%u, ctrl=%u\n", buf, ptt, ctrl);
 | |
| 
 | |
| 	if (ptt != 0)
 | |
| 		buf[2] = (TS2K_PTT_ON_SUB == ptt) ? '1' : '0';
 | |
| 	if (ctrl != 0)
 | |
| 		buf[3] = (TS2K_CTRL_ON_SUB == ctrl) ? '1' : '0';
 | |
| 
 | |
| 	buf[4] = ';';
 | |
| 	buf[5] = '\0';	// just for printing debug
 | |
| 
 | |
| 	acklen=10;
 | |
| 	retval = ts2k_transaction(rig, buf, 5, NULL, NULL);
 | |
| 	CHKERR(retval);
 | |
| 
 | |
| 	return RIG_OK;
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * FIXME: simple ascii to integer converter--expensive!
 | |
|  *	Prevents trashing original string, otherwise
 | |
|  *	just drop a (char)0 where you need it.
 | |
|  */
 | |
| int ts2k_get_int(char *src, int cnt)
 | |
| {
 | |
| 	static char buf[20];
 | |
| 
 | |
| 	strncpy(buf, src, cnt);
 | |
| 	buf[cnt] = (char) 0;
 | |
| 
 | |
| 	return atoi(buf);
 | |
| }
 | |
| 
 | |
| int ts2k_get_rit(RIG * rig, vfo_t vfo, shortfreq_t * rit)
 | |
| {
 | |
| 	int retval, acklen;
 | |
| 	char ack[40];
 | |
| 	char *ctrl;
 | |
| 
 | |
| 	ctrl = ts2k_get_ctrl(rig);
 | |
| 	if (ctrl == NULL)	// do we have valid "dc;" ?
 | |
| 		return -RIG_EINVAL;	// don't know proper errors yet!
 | |
| 
 | |
| 	// sub shows main's rit!  We return 0 if subreceiver.
 | |
| 	if (ctrl[3] == '1') {
 | |
| 		*rit = 0;
 | |
| 		return RIG_OK;	// not really, but it's paid for...
 | |
| 	}
 | |
| 	retval = ts2k_transaction(rig, "if;", 3, ack, &acklen);
 | |
| 	CHKERR(retval);
 | |
| 
 | |
| 	ack[23] = (char) 0;
 | |
| 	*rit = atoi(&ack[17]);
 | |
| 
 | |
| 	return RIG_OK;
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * ts2k_get_xit()  We just call ts2k_get_rit()
 | |
|  * On the ts2k, they're the same.  The rig
 | |
|  * acts this way.
 | |
| */
 | |
| int ts2k_get_xit(RIG * rig, vfo_t vfo, shortfreq_t * rit)
 | |
| {
 | |
| 	return ts2k_get_rit(rig, vfo, rit);
 | |
| }
 | |
| 
 | |
| int ts2k_set_rit(RIG * rig, vfo_t vfo, shortfreq_t rit)
 | |
| {
 | |
| 	char buf[40], c;
 | |
| 	int retval, i, len;
 | |
| 
 | |
| 	// Clear current rit/xit.
 | |
| 	retval = ts2k_transaction(rig, "rc;", 3, NULL, NULL);
 | |
| 	CHKERR(retval);
 | |
| 
 | |
| 	// Execute up/down request.
 | |
| 	if (rit > 0) {
 | |
| 		c = 'u';
 | |
| 		i = rit;
 | |
| 	} else {
 | |
| 		c = 'd';
 | |
| 		i = -rit;
 | |
| 	}
 | |
| 
 | |
| 	len = sprintf(buf, "r%c%6d;", c, i);
 | |
| 
 | |
| 	return ts2k_transaction(rig, buf, len, NULL, NULL);
 | |
| }
 | |
| 
 | |
| int ts2k_set_xit(RIG * rig, vfo_t vfo, shortfreq_t rit)
 | |
| {
 | |
| 	return ts2k_set_rit(rig, vfo, rit);
 | |
| }
 | |
| 
 | |
| int ts2k_get_ts(RIG * rig, vfo_t vfo, shortfreq_t * ts)
 | |
| {
 | |
| 	STUFF(10);
 | |
| 	int m, s;
 | |
| 
 | |
| 	retval = ts2k_transaction(rig, "ST;", 5, ack, &acklen);
 | |
| 	CHKERR(retval);
 | |
| 
 | |
| 	ack[4] = '\0';
 | |
| 	s = atoi(&ack[2]);
 | |
| 
 | |
| 	rig_debug(RIG_DEBUG_VERBOSE, __FUNCTION__": received: '%s', %u\n", ack, s);
 | |
| 
 | |
| 	retval = ts2k_transaction(rig, "MD;", 5, ack, &acklen);
 | |
| 	CHKERR(retval);
 | |
| 
 | |
| 	// fm or am mode selects 1
 | |
| 	m = (ack[2] == '4' || ack[2] == '5') ? 1 : 0;
 | |
| 
 | |
| 	rig_debug(RIG_DEBUG_VERBOSE, __FUNCTION__": received: '%s', %u\n", ack, m);
 | |
| 
 | |
| 	*ts = ts2k_steps[m][s];
 | |
| 	return RIG_OK;
 | |
| }
 | |
| 
 | |
| // FIXME: should get nearest, not easiest.  :)
 | |
| /*
 | |
|  *	status:	working.  fixed timeout.	--Dale
 | |
|  */
 | |
| int ts2k_set_ts(RIG * rig, vfo_t vfo, shortfreq_t ts)
 | |
| {
 | |
| 	STUFF(10);
 | |
| 	char st[10];
 | |
| 	int m, s, k;
 | |
| 	long int aver, diff[2];
 | |
| 
 | |
| 	retval = ts2k_transaction(rig, "md;", 5, ack, &acklen);
 | |
| 	CHKERR(retval);
 | |
| 
 | |
| 	// fm or am mode selects 1
 | |
| 	m = (ack[2] == '4' || ack[2] == '5') ? 1 : 0;
 | |
| 
 | |
| 	// fm or am selects 10 step freq. else 4.
 | |
| 	k = ( m )? 10 : 4;
 | |
| 
 | |
| 	s=0;
 | |
| 	if( ts < ts2k_steps[m][0] ) {
 | |
| 		k=s;
 | |
| 	}
 | |
| 
 | |
| 	if( ts > ts2k_steps[m][9] ) {
 | |
| 		s=9;
 | |
| 	}
 | |
| 
 | |
| 	for ( s=1 ; s<k; s++) {
 | |
| 		if ( ts2k_steps[m][s-1] <= ts && ts <= ts2k_steps[m][s]) {
 | |
| 			diff[0] = ts - ts2k_steps[m][s-1];
 | |
| 			diff[1] = ts2k_steps[m][s] - ts;
 | |
| 			if( diff[0] > diff[1] ) {	// closer to [s]
 | |
| 				break;
 | |
| 			} else {			// closer to [s-1]
 | |
| 				s--;
 | |
| 				break;
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 	// m is tmp now
 | |
| 	m = sprintf(st, "st0%1u;", s);
 | |
| 
 | |
| 	// no reply!
 | |
| 	retval = ts2k_transaction(rig, st, m, NULL, NULL);
 | |
| 	CHKERR(retval);
 | |
| 
 | |
| 	return RIG_OK;
 | |
| }
 | |
| 
 | |
| /* Rig truncates in kHz(50) steps, so we don't. */
 | |
| int ts2k_get_rptr_offs(RIG * rig, vfo_t vfo, shortfreq_t * rptr_offs)
 | |
| {
 | |
| 	STUFF(20);
 | |
| 
 | |
| 	retval = ts2k_transaction(rig, "of;", 3, ack, &acklen);
 | |
| 	CHKERR(retval);
 | |
| 
 | |
| 	if (ack[0] != 'O' || ack[1] != 'F')
 | |
| 		return -RIG_EINVAL;
 | |
| 	if (acklen != 12)
 | |
| 		return -RIG_EINVAL;
 | |
| 
 | |
| 	ack[11] = '\0';
 | |
| 	*rptr_offs = atoi(&ack[2]);
 | |
| 
 | |
| 	return RIG_OK;
 | |
| }
 | |
| 
 | |
| /* Rig truncates in kHz(50) steps, so we don't. */
 | |
| int ts2k_set_rptr_offs(RIG * rig, vfo_t vfo, shortfreq_t rptr_offs)
 | |
| {
 | |
| 	STUFF(20);
 | |
| 	char buf[20];
 | |
| 	int buflen = 20, i;
 | |
| 
 | |
| 	i = sprintf(buf, "of%09u;", (unsigned int) rptr_offs);
 | |
| 
 | |
| 	retval = ts2k_transaction(rig, buf, i, NULL, NULL);
 | |
| 	CHKERR(retval);
 | |
| 
 | |
| 	return RIG_OK;
 | |
| }
 | |
| 
 | |
| /*
 | |
|  *	status:	working, leaves vfo intact.
 | |
|  */
 | |
| int ts2k_get_rptr_shift(RIG * rig, vfo_t vfo, rptr_shift_t * rptr_shift)
 | |
| {
 | |
| 	STUFF(20);
 | |
| 	vfo_t vfo_tmp;
 | |
| 
 | |
| 	// FIXME: I don't know if I should change back to currVFO, but I do.
 | |
| 	retval = ts2k_get_vfo(rig, &vfo_tmp);
 | |
| 	CHKERR(retval);
 | |
| 
 | |
| 	retval = ts2k_transaction(rig, "os;", 3, ack, &acklen);
 | |
| 	CHKERR(retval);
 | |
| 
 | |
| 	retval = ts2k_vfo_ctrl(rig, vfo);
 | |
| 
 | |
| 	if (ack[0] != 'O' || ack[1] != 'S')
 | |
| 		return -RIG_EINVAL;
 | |
| 	//if(acklen != 4) return -RIG_EINVAL;
 | |
| 
 | |
| 	switch (ack[2]) {
 | |
| 	case '0':
 | |
| 		*rptr_shift = RIG_RPT_SHIFT_NONE;
 | |
| 		break;
 | |
| 	case '1':
 | |
| 		*rptr_shift = RIG_RPT_SHIFT_MINUS;
 | |
| 		break;
 | |
| 	case '2':
 | |
| 		*rptr_shift = RIG_RPT_SHIFT_PLUS;
 | |
| 		break;
 | |
| 	case '3':
 | |
| 		*rptr_shift = RIG_RPT_SHIFT_1750;
 | |
| 		break;
 | |
| 
 | |
| 	default:
 | |
| 		return -RIG_EINVAL;
 | |
| 		break;
 | |
| 	}
 | |
| 
 | |
| 	// FIXME: I don't know if I should change back to currVFO, but I do.
 | |
| 	retval = ts2k_set_vfo(rig, vfo_tmp);
 | |
| 	CHKERR(retval);
 | |
| 
 | |
| 	return RIG_OK;
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * ts2k_set_rptr_shift()
 | |
|  *
 | |
|  *	status:		doesn't check VFO yet	--Dale
 | |
|  */
 | |
| int ts2k_set_rptr_shift(RIG * rig, vfo_t vfo, rptr_shift_t rptr_shift)
 | |
| {
 | |
| 	STUFF(10);
 | |
| 	char c;
 | |
| 
 | |
| 	switch (rptr_shift) {
 | |
| 	case RIG_RPT_SHIFT_NONE:
 | |
| 		c = '0';
 | |
| 		break;
 | |
| 	case RIG_RPT_SHIFT_PLUS:
 | |
| 		c = '1';
 | |
| 		break;
 | |
| 	case RIG_RPT_SHIFT_MINUS:
 | |
| 		c = '2';
 | |
| 		break;
 | |
| 	case RIG_RPT_SHIFT_1750:	// FIXME: invalid for mine! (non-Etype)
 | |
| 		c = '3';
 | |
| 		break;
 | |
| 
 | |
| 	default:
 | |
| 		return -RIG_EINVAL;
 | |
| 		break;
 | |
| 	}
 | |
| 	acklen = sprintf(ack, "os%c;", c);
 | |
| 
 | |
| 	retval = ts2k_transaction(rig, ack, 4, NULL, NULL);
 | |
| 	CHKERR(retval);
 | |
| 
 | |
| 	return RIG_OK;
 | |
| }
 | |
| 
 | |
| int ts2k_get_split(RIG * rig, vfo_t vfo, split_t * split)
 | |
| {
 | |
| 	STUFF(10);
 | |
| 	char ack2[10];
 | |
| 	int ack2len = 10;
 | |
| 
 | |
| 	retval = ts2k_transaction(rig, "fr;", 3, ack, &acklen);
 | |
| 	CHKERR(retval);
 | |
| 
 | |
| 	retval = ts2k_transaction(rig, "ft;", 3, ack2, &ack2len);
 | |
| 	CHKERR(retval);
 | |
| 
 | |
| 	if (ack[2] != ack2[2])
 | |
| 		*split = RIG_SPLIT_ON;
 | |
| 	else
 | |
| 		*split = RIG_SPLIT_OFF;
 | |
| 
 | |
| 	return RIG_OK;
 | |
| }
 | |
| 
 | |
| /* no VFO check, and no mem.  Yet. */
 | |
| int ts2k_set_split(RIG * rig, vfo_t vfo, split_t split)
 | |
| {
 | |
| 	STUFF(10);
 | |
| 	char ack2[10];
 | |
| 	int ack2len = 10;
 | |
| 
 | |
| 	retval = ts2k_transaction(rig, "fr;", 3, ack, &acklen);
 | |
| 	CHKERR(retval);
 | |
| 
 | |
| 	retval = ts2k_transaction(rig, "ft;", 3, ack2, &ack2len);
 | |
| 	CHKERR(retval);
 | |
| 
 | |
| 	if (split == RIG_SPLIT_ON) {	// RX/TX on different vfo's
 | |
| 		if (ack[2] == '0')
 | |
| 			ack2[2] = '1';
 | |
| 		else if (ack[2] == '1')
 | |
| 			ack2[2] = '0';
 | |
| 
 | |
| 		/* FIXME: mem split.  mem/vfo split must enable menu 6a
 | |
| 		 * with the "ex...;" or mem/vfo won't work.  A split
 | |
| 		 * memory operates simply by storing a memory with the
 | |
| 		 * freq with RX != TX then recalling it.  Don't know if
 | |
| 		 * if two separate memories can be used (e.g. 100/101)
 | |
| 		 */
 | |
| 		else
 | |
| 			return -RIG_EINVAL;
 | |
| 	} else {		// RX/TX on same vfo (or mem etc...)
 | |
| 		ack2[2] = ack[2];
 | |
| 	}
 | |
| 
 | |
| 	// now, just send back the rig's strings :)
 | |
| 	retval = ts2k_transaction(rig, ack, acklen, NULL, NULL);
 | |
| 	CHKERR(retval);
 | |
| 
 | |
| 	retval = ts2k_transaction(rig, ack2, ack2len, NULL, NULL);
 | |
| 	CHKERR(retval);
 | |
| 
 | |
| 	return RIG_OK;
 | |
| }
 | |
| 
 | |
| int ts2k_get_split_freq(RIG * rig, vfo_t vfo, freq_t * tx_freq)
 | |
| {
 | |
| 	// FIXME : This makes too many assumptions--I'll fix it later...d PTT/CTRL bytes\n", dc_len);*//* The following are functions I've added for the TS-2000.  (C) 2002 D. Edmons and all that. *//*-------------------------------------------------------------------------------------------*/
 | |
| 	return ts2k_get_freq(rig, vfo, tx_freq);
 | |
| }
 | |
| 
 | |
| int ts2k_set_split_freq(RIG * rig, vfo_t vfo, freq_t tx_freq)
 | |
| {
 | |
| 	// FIXME : This makes too many assumptions--I'll fix it later...d PTT/CTRL bytes\n", dc_len);*//* The following are functions I've added for the TS-2000.  (C) 2002 D. Edmons and all that. *//*-------------------------------------------------------------------------------------------*/
 | |
| 	return ts2k_set_freq(rig, vfo, tx_freq);
 | |
| }
 | |
| 
 | |
| /* ts2k_get_channel()
 | |
|  *
 | |
|  *	status:	working!  reading unset memory is an error.  this
 | |
|  *		is the rig.  vfo_t is not needed for regular memory
 | |
|  *		and we don't check it now.  when we start to access
 | |
|  *		other memory we'll split into multiple functions
 | |
|  *		each dedicated to the unique type (e.g. quick/tmp).
 | |
|  *
 | |
|  *		memory range not checked.
 | |
|  *
 | |
|  *	Note: the manual erroneously states bank should be ' ' if
 | |
|  *		memory is <100.  The "correct" way is to *never*
 | |
|  *		send a ' ' or you'll get a "?;" response.  Always
 | |
|  *		set memory with (e.g.) "mc1020;".	--kd7eni
 | |
|  */
 | |
| int ts2k_get_channel(RIG * rig, channel_t *chan)
 | |
| {
 | |
| //	channel_t tch;	// needed?
 | |
| 	char rxtx, mrtxt[2][60], mrcmd[15], ack[60], tmp[20];
 | |
| 	int i, check, retval, curr_mem, mrtxt_len, mrcmd_len, ack_len;
 | |
| 	vfo_t curr_vfo;
 | |
| #ifdef _USEVFO
 | |
| 	vfo_t v;
 | |
| 
 | |
| 	v = vfo;
 | |
| 	// check the memory bit
 | |
| 	if( !(v & RIG_VFO_MEM) ) {
 | |
| 		rig_debug(RIG_DEBUG_ERR, __FUNCTION__
 | |
| 			": Non Memory VFO='%u', v=%u\n", vfo, v);
 | |
| 		return -RIG_EINVAL;	// not a channel!
 | |
| 	}
 | |
| 
 | |
| // get needed info if rig's mem pointers used
 | |
| 	if( (	vfo == RIG_VFO_MEM_A
 | |
| 		|| vfo == RIG_VFO_MEM_C ) ) {
 | |
| 		rig_debug(RIG_DEBUG_ERR, __FUNCTION__": using rig's ptr\n");
 | |
| 		retval = ts2k_get_vfo(rig, &curr_vfo);
 | |
| 		CHKERR(retval);
 | |
| 		retval = ts2k_get_mem(rig, curr_vfo, &curr_mem);
 | |
| 		CHKERR(retval);
 | |
| 		chan->channel_num = curr_mem;
 | |
| 	}
 | |
| #endif
 | |
| 
 | |
| 	mrtxt_len = ack_len = 60;
 | |
| 	mrcmd_len=15;
 | |
| 
 | |
| 	if(chan==NULL)
 | |
| 		return -RIG_EINVAL;
 | |
| 
 | |
| // send request for both rx mem and tx mem
 | |
| 	for(i=0; i<2; i++) {	// 0=rx; 1=tx
 | |
| 
 | |
| 		mrcmd_len = sprintf(mrcmd, "mr%01d%03u;", i, chan->channel_num); 
 | |
| 		ack_len = 60;	// must be reset inside loop!
 | |
| 		retval = ts2k_transaction(rig, mrcmd, mrcmd_len, ack, &ack_len); 
 | |
| 		CHKERR(retval);
 | |
| 
 | |
| 		rig_debug(RIG_DEBUG_ERR, __FUNCTION__": read \n\t'%s'\n", ack);
 | |
| 
 | |
| 		ack[50] = '\0';		// May be too far, but helps.
 | |
| 
 | |
| 		// watch out.  |= and != look the same!
 | |
| 		// Perform checks on data.
 | |
| 		check = (ack[0] != 'M');
 | |
| 		check |= (ack[1] != 'R');
 | |
| 		check |= (ack[2] != ((i == 0)? '0' : '1'));
 | |
| 		check |= (chan->channel_num != int_n(tmp, &ack[3], 3));
 | |
| 		if( check ) {
 | |
| 			rig_debug(RIG_DEBUG_ERR, __FUNCTION__
 | |
| 				":check failed!\n");
 | |
| 			return -RIG_EINVAL;	// correct error type?
 | |
| 		}
 | |
| 
 | |
| 		// all is well, save string
 | |
| 		strncpy( &mrtxt[i][0], ack, 52);
 | |
| 	}
 | |
| 	// FIXME: handle mem split
 | |
| 	// final check on data. (if RX!=TX mem split, or limit!)
 | |
| 	if( strncmp( &mrtxt[0][3], &mrtxt[1][3], 41-3) != 0 ) {
 | |
| 		rig_debug(RIG_DEBUG_ERR, "\n"__FUNCTION__
 | |
| 			": MEM split and band limits not yet supported!\n");
 | |
| 		return -RIG_EINVAL;	// FIXME: sending proper error?
 | |
| 	}
 | |
| 
 | |
| 	// FIXME: 1) Since chan is not an array, we fudge and only do TX!
 | |
| 	//		even if split!!!!!!!!
 | |
| 	// FIXME: 2) we only handle regular memories, not everything
 | |
| 	// FIXME: 3) I store only data ts2k actually saves in memory
 | |
| 	//		some values are the ts2k value, not the hamlib value!
 | |
| 
 | |
| 	// (keep same order as channel struct to ease debugging!)
 | |
| //	chan->channel_num = ;	// already set?
 | |
| 
 | |
| // The following may be used to indicate we're reading limits (290-299).
 | |
| // At any rate, it's currently unused. 
 | |
| 	chan->bank_num = 0;	// I merge the two--do not use! --Dale
 | |
| 
 | |
| 	chan->lock = int_n(tmp, &mrtxt[0][18], 1);
 | |
| 	chan->freq = int_n(tmp, &mrtxt[0][06], 11);
 | |
| 	chan->mode = ts2k_mode_list[ int_n(tmp, &mrtxt[0][17], 1) ];
 | |
| 	if(chan->mode == RIG_MODE_AM || chan->tx_mode == RIG_MODE_FM)
 | |
| 		i = 1;
 | |
| 	else
 | |
| 		i = 0;
 | |
| 	chan->width = 0;
 | |
| 	chan->tx_freq = int_n(tmp, &mrtxt[1][06], 11);
 | |
| 	chan->tx_mode = ts2k_mode_list[ int_n(tmp, &mrtxt[1][17], 1)];
 | |
| 	chan->tx_width = 0;
 | |
| 	chan->split = 0;
 | |
| 	chan->rptr_shift = int_n(tmp, &mrtxt[1][28], 1);
 | |
| 	chan->rptr_offs = int_n(tmp, &mrtxt[1][29], 9);
 | |
| 	if(chan->tx_mode == RIG_MODE_AM || chan->tx_mode == RIG_MODE_FM)
 | |
| 		i = 1;
 | |
| 	else
 | |
| 		i = 0;
 | |
| 	chan->tuning_step = ts2k_steps[i][ int_n(tmp,& mrtxt[1][38], 2) ];
 | |
| 	chan->rit = 0;
 | |
| 	chan->xit = 0;
 | |
| 	chan->funcs = 0;
 | |
| 	for( i=0; i<RIG_SETTING_MAX; i++) {
 | |
| 		// the following shamelessly stolen from rigctl.c  --Dale
 | |
| 		setting_t level = rig_idx2setting(i);	// now, I understand
 | |
| 		if(RIG_LEVEL_IS_FLOAT(level))
 | |
| 			chan->levels[i].f = 0.0;	// I'd figured this out.
 | |
| 		else
 | |
| 			chan->levels[i].f = 0.0;
 | |
| 	}
 | |
| 	chan->ctcss_tone = ts2k_ctcss_list[ int_n(tmp, &mrtxt[1][22], 2) + 1 ];
 | |
| 	chan->ctcss_sql = int_n(tmp, &mrtxt[1][19], 1);
 | |
| 	chan->dcs_code = ts2k_dcs_list[ int_n(tmp, &mrtxt[1][24], 3) ];
 | |
| 	chan->dcs_sql = int_n(tmp, &mrtxt[1][19], 1);
 | |
| 	chan->scan_group = int_n(tmp, &mrtxt[1][40], 1);
 | |
| //	chan->flags = curr_vfo;	// n/a
 | |
| 	// FIXME : The following may have trailing garbage
 | |
| 	strncpy( chan->channel_desc, &mrtxt[1][41], 8);
 | |
| 	chan->channel_desc[8] = '\0';
 | |
| 
 | |
| #ifdef _USEVFO
 | |
| // if curr mem is changed at top, this'll restore it
 | |
| 	if( (	vfo == RIG_VFO_MEM_A
 | |
| 		|| vfo == RIG_VFO_MEM_C ) ) {
 | |
| 	}
 | |
| 
 | |
| 	rig_debug(RIG_DEBUG_ERR, __FUNCTION__": restoring mem=%i\n", curr_mem);
 | |
| 	retval = ts2k_set_mem(rig, curr_vfo, curr_mem);
 | |
| 	CHKERR(retval);
 | |
| #endif
 | |
| 
 | |
| 	return RIG_OK;
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * ts2k_set_channel()	Here I read a channel_t and memory data.  I'm
 | |
|  *	assuming this is correct.  Anyway, this is a useful function.
 | |
|  *	The only quirk is that the TS-2000 saves both TX as well
 | |
|  *	as RX data separately.  This function can easily be modified
 | |
|  *	to write as if there were 600 memories but that would lead
 | |
|  *	to confusion and the rig certainly don't operate that way.
 | |
|  *	I hope to channel_t *chan changed to channel_t *chan[2].
 | |
|  *	(As well as vfo_t too.)  Much thanks to Stephane for already
 | |
|  *	having the most important stuff working from the start
 | |
|  *	(mostly anyway).
 | |
|  *
 | |
|  *	From here on out I'm gonna try to use hamlib-1.1.0.pdf
 | |
|  *	for the design document and hopefully I'll know which way
 | |
|  *	to go when things aren't the way they should be.  We'll
 | |
|  *	see how things go.
 | |
|  *						--Dale kd7e
 | |
|  */
 | |
| int ts2k_set_channel(RIG * rig, const channel_t *chan)
 | |
| {
 | |
| 	char mrtxt[2][60], mrcmd[10], ack[60];
 | |
| 	int retval, i, j, mr_len[2], ack_len;
 | |
| 
 | |
| 	// the following are the actual memory data to be written.
 | |
| 	unsigned int
 | |
| 		p1,	// RX/TX (bool)
 | |
| 		p2p3,	// this is not a bug--I combine bank/channel
 | |
| 		p4,	// freq
 | |
| 		p5,	// mode
 | |
| 		p6,	// lockout
 | |
| 		p7,	// tone, ctcss, dcs
 | |
| 		p8,	// tone #
 | |
| 		p9,	// CTCSS #
 | |
| 		p10,	// DCS code
 | |
| 		p11,	// revers status
 | |
| 		p12,	// repeater shift
 | |
| 		p13,	// offset freq
 | |
| 		p14,	// step size
 | |
| 		p15;	// memory group (0-9)
 | |
| 	char	*p16;	// 8 char + 1 null byte
 | |
| 
 | |
| 	ack_len = 10;
 | |
| 	/*
 | |
| 	 * Write everthing in order.  We only set things that
 | |
| 	 * the rig actually puts in memory.  This way, a set
 | |
| 	 * followed by a get will match exactly.  Otherwise,
 | |
| 	 * we'll have to fudge and won't know when we have
 | |
| 	 * a valid save.  (FIXME: delete all this useless
 | |
| 	 * comment stuff after the code is working. --Dale)
 | |
| 	 */
 | |
| 
 | |
| 	/* FIXME: we are required to have RX/TX match */
 | |
| 	if(chan->freq != chan->tx_freq)
 | |
| 		return -RIG_EINVAL;	// should be 'unimplemented'
 | |
| 
 | |
| 	for(i=0; i<2; i++) {
 | |
| 		p1 = (unsigned int) i; // 0=RX, 1=TX
 | |
| 
 | |
| 		p2p3 = (unsigned int) chan->channel_num;	// we'll compare 'em later
 | |
| 		if( i == 0 )
 | |
| 			p4 = (unsigned int) chan->freq;
 | |
| 		else
 | |
| 			p4 = (unsigned int) chan->tx_freq;
 | |
| 
 | |
| 		for(j=0; j<(sizeof(ts2k_mode_list)/sizeof(int)); j++) {
 | |
| 			if(chan->mode == ts2k_mode_list[j])
 | |
| 				break;
 | |
| 		}
 | |
| 		p5 = (unsigned int) j;	// FIXME: either not found, or last!
 | |
| 		p6 = (unsigned int) chan->lock;
 | |
| 		p7 = 0;	// FIXME: to lazy to sort this out right now
 | |
| 		p8 = 0; //	"	"	"	"	"
 | |
| 		p9 = 0; //	"	"	"	"	"
 | |
| 		p10 = 0; //	"	"	"	"	"
 | |
| 		p11 = 0; //	"	"	"	"	"
 | |
| 		p12 = 0; //	"	"	"	"	"
 | |
| 		p13 = 0; //	"	"	"	"	"
 | |
| 		p14 = 0; //	"	"	"	"	"
 | |
| 		p15 = (unsigned int) chan->scan_group;
 | |
| 		p16 = &(chan->channel_desc[0]);
 | |
| 
 | |
| 		mr_len[i] = sprintf( &(mrtxt[i][0]),
 | |
| 			"mr%1u%3u%11u%1u%1u%1u%2u%2u%3u%1u%1u%9u%2u%1u%s;",
 | |
| 			p1, p2p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13,
 | |
| 			p14, p15,
 | |
| 			p16
 | |
| 			);	// yikes!
 | |
| 		retval = ts2k_transaction(rig, &mrtxt[i][0], mr_len[i],
 | |
| 				 ack, &ack_len);
 | |
| 		CHKERR(retval);
 | |
| 
 | |
| 		// FIXME: now readback the string and make sure it worked!
 | |
| 	}
 | |
| 	
 | |
| 	return retval;
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * ts2k_vfo_ctrl()	set PTT/CTRL based on VFO arg
 | |
|  *
 | |
|  *	(Taken from my revision of ts2k_set_vfo())
 | |
|  *
 | |
|  *	status:		VFOA, VFOB, VFOC, Main, Sub,
 | |
|  *			MEMA, MEMC, CALLA, CALLC 
 | |
|  *			VFO_AB, VFO_BA, ...
 | |
|  *		They all work!		--Dale
 | |
|  */
 | |
| int ts2k_vfo_ctrl(RIG * rig, vfo_t vfo)
 | |
| {
 | |
| 	int ptt, ctrl;
 | |
| 	int retval;
 | |
| 
 | |
| 	ptt = ctrl = 0;
 | |
| 
 | |
| 	// Main/Sub Active Transceiver
 | |
| 	switch (vfo) {
 | |
| 	case RIG_VFO_A:
 | |
| 	case RIG_VFO_B:
 | |
| 	case RIG_VFO_AB:	// split
 | |
| 	case RIG_VFO_BA:
 | |
| 	case RIG_CTRL_SAT:	// Should be PTT on main CTRL on sub (?)
 | |
| 	case RIG_VFO_MAIN:
 | |
| 	case RIG_VFO_MEM_A:
 | |
| 	case RIG_VFO_CALL_A:
 | |
| 		ctrl = TS2K_CTRL_ON_MAIN;	// FIXME : these are independent!
 | |
| 		ptt = TS2K_PTT_ON_MAIN;
 | |
| 		break;
 | |
| 	case RIG_VFO_C:
 | |
| 	case RIG_VFO_SUB:
 | |
| 	case RIG_VFO_MEM_C:
 | |
| 	case RIG_VFO_CALL_C:
 | |
| 		ctrl = TS2K_CTRL_ON_SUB;
 | |
| 		ptt = TS2K_PTT_ON_SUB;
 | |
| 		break;
 | |
| 
 | |
| 	default:
 | |
| 		break;
 | |
| 	}
 | |
| 
 | |
| 	// set PTT/CTRL
 | |
| 	retval = ts2k_set_ctrl(rig, ptt, ctrl);
 | |
| 	if (retval != RIG_OK)
 | |
| 		return -RIG_EINVAL;
 | |
| 
 | |
| 	return retval;
 | |
| }
 | |
| 
 | |
| /*
 | |
|  *	status:	ok, no vfo checks
 | |
|  */
 | |
| int ts2k_get_dcs_code(RIG * rig, vfo_t vfo, tone_t *code)
 | |
| {
 | |
| 	char ack[10], tmp[10];
 | |
| 	int retval, acklen, i;
 | |
| 
 | |
| 	acklen = 10;
 | |
| 	retval = ts2k_transaction(rig, "qc;", 6, ack, &acklen);
 | |
| 	CHKERR(retval);
 | |
| 
 | |
| 	i = int_n(tmp, &ack[2], 3);
 | |
| 	*code = ts2k_dcs_list[i];
 | |
| 
 | |
| 	return RIG_OK;
 | |
| }
 | |
| 
 | |
| /*
 | |
|  *	status:	ok, no vfo checks
 | |
|  */
 | |
| int ts2k_set_dcs_code(RIG * rig, vfo_t vfo, tone_t code)
 | |
| {
 | |
| 	char ack[10], cmd[10], tmp[10];
 | |
| 	int retval, acklen, cmdlen, i;
 | |
| 
 | |
| 	// we only allow exact matches here
 | |
| 	i=0;
 | |
| 	while(code != ts2k_dcs_list[i]) {
 | |
| 		if(ts2k_dcs_list[i] == 0)
 | |
| 			return -RIG_EINVAL;
 | |
| 		i++;
 | |
| 	}
 | |
| 	cmdlen = sprintf(cmd, "qc%03u;", i);
 | |
| 	return ts2k_transaction(rig, cmd, cmdlen, NULL, NULL);
 | |
| }
 | |
| 
 | |
| /*
 | |
|  *	status:	new, all guesses and assumptions!
 | |
|  *		know nothing about txwidth (which one?)
 | |
|  *		or tx = rx + txwidth?
 | |
|  */
 | |
| int ts2k_set_split_mode(RIG * rig,
 | |
| 	vfo_t vfo, rmode_t txmode, pbwidth_t txwidth)
 | |
| {
 | |
| 	vfo_t vtmp;
 | |
| 
 | |
| 	switch(vfo) {
 | |
| 	case RIG_VFO_AB:
 | |
| 		vtmp = RIG_VFO_B; break;
 | |
| 	case RIG_VFO_BA:
 | |
| 		vtmp = RIG_VFO_A; break;
 | |
| 	default:
 | |
| 		return -RIG_EINVAL;
 | |
| 	}
 | |
| 	return ts2k_set_mode(rig, vtmp, txmode, txwidth);
 | |
| }
 | |
| 
 | |
| int ts2k_get_split_mode(RIG *rig,
 | |
| 	vfo_t vfo, rmode_t *txmode, pbwidth_t *txwidth)
 | |
| {
 | |
| 	vfo_t vtmp;
 | |
| 	switch(vfo) {
 | |
| 	case RIG_VFO_AB:
 | |
| 		vtmp = RIG_VFO_B; break;
 | |
| 	case RIG_VFO_BA:
 | |
| 		vtmp = RIG_VFO_A; break;
 | |
| 	default:
 | |
| 		return -RIG_EINVAL;
 | |
| 	}
 | |
| 	return ts2k_get_mode(rig, vtmp, txmode, txwidth);
 | |
| }
 | |
| 
 | |
| /*
 | |
|  *	status:	new
 | |
|  */
 | |
| int ts2k_scan(RIG *rig, vfo_t vfo, scan_t scan, int ch)
 | |
| {
 | |
| 	int retval;
 | |
| 	vfo_t v;
 | |
| 
 | |
| 	rig_debug(RIG_DEBUG_ERR, __FUNCTION__": starting...\n");
 | |
| 
 | |
| 	if(vfo==RIG_VFO_CURR) {
 | |
| 		retval = ts2k_get_vfo(rig, &v);
 | |
| 		CHKERR(retval);
 | |
| 	} else
 | |
| 		v = vfo;
 | |
| 
 | |
| 	// hopefully, this'll work.  rig does nothing if already in scan!
 | |
| 	retval = ts2k_scan_off(rig);
 | |
| 	CHKERR(retval);
 | |
| 
 | |
| 	rig_debug(RIG_DEBUG_ERR, __FUNCTION__": got VFO = %x\n", v);
 | |
| 	// set proper vfo first (already done?)
 | |
| 	switch(v) {
 | |
| 	case RIG_VFO_MEM:	// Currently selected Main/Sub
 | |
| 	case RIG_VFO_MEM_A:	// Main
 | |
| 	case RIG_VFO_MEM_C:	// Sub
 | |
| 		// FIXME: we should set the group and fall through
 | |
| 		/* nobreak */
 | |
| //	case RIG_VFO_VFO:	// Currently selected Main/Sub
 | |
| 	case RIG_VFO_A:		// Main
 | |
| 	case RIG_VFO_B:		// Main
 | |
| 	case RIG_VFO_C:		// Sub
 | |
| 		retval = ts2k_set_vfo(rig, v);	// already set?
 | |
| 		CHKERR(retval);
 | |
| 		break;
 | |
| 		
 | |
| 	case RIG_VFO_CALL_A:	// 
 | |
| 	case RIG_VFO_CALL_C:
 | |
| 	default:
 | |
| 		rig_debug(RIG_DEBUG_ERR, __FUNCTION__": vfo 'defaulted'\n");
 | |
| 		return -RIG_ENIMPL;	// unimplemented, but valid scan
 | |
| 	}
 | |
| 
 | |
| 	rig_debug(RIG_DEBUG_ERR, __FUNCTION__": VFO set!\n");
 | |
| 	retval = ts2k_scan_off(rig);
 | |
| 	CHKERR(retval);
 | |
| 
 | |
| 	switch(scan) {
 | |
| 
 | |
| 	case RIG_SCAN_STOP: 
 | |
| 		return ts2k_scan_off(rig);
 | |
| 		break;
 | |
| 
 | |
| 	case RIG_SCAN_PROG:
 | |
| 		if(ch<290)
 | |
| 			return -RIG_EINVAL;
 | |
| 		retval = ts2k_set_mem(rig, vfo, ch);
 | |
| 		CHKERR(retval);
 | |
| 		/* nobreak */
 | |
| 	case RIG_SCAN_MEM:
 | |
| 		/* nobreak */
 | |
| 	case RIG_SCAN_VFO:
 | |
| 		return ts2k_scan_on(rig, '1');	// Look Ma, I'm scanning!
 | |
| 		break;
 | |
| 
 | |
| 	case RIG_SCAN_SLCT:
 | |
| 		/* nobreak */
 | |
| 	case RIG_SCAN_PRIO:
 | |
| 		/* nobreak */
 | |
| 	default:
 | |
| 		rig_debug(RIG_DEBUG_ERR, __FUNCTION__": scan 'defaulted'\n");
 | |
| 		return -RIG_ENIMPL;	// unimplemented, but valid scan
 | |
| 	}
 | |
| }
 | |
| 
 | |
| int ts2k_scan_on(RIG *rig, char sc)
 | |
| {
 | |
| 	char cmd[]="sc0;", ack[10];
 | |
| 	int retval, cmdlen, acklen, i;
 | |
| 
 | |
| 	rig_debug(RIG_DEBUG_ERR, __FUNCTION__": turning scan on\n");
 | |
| 	cmd[2] = sc;
 | |
| 	retval = ts2k_transaction(rig, cmd, 4, NULL, NULL);
 | |
| 	CHKERR(retval);
 | |
| 
 | |
| 	rig_debug(RIG_DEBUG_ERR, __FUNCTION__": turned scan on\n");
 | |
| 	// force reply when turning scan on
 | |
| 	if(sc != '0') {
 | |
| 		cmd[2] = ';'; cmd[3] = '\0';
 | |
| 		retval = ts2k_transaction(rig, cmd, 3, ack, &acklen);
 | |
| 		CHKERR(retval);
 | |
| 
 | |
| 		if(ack[2] != sc)
 | |
| 			return -RIG_EINVAL;
 | |
| 	}
 | |
| 
 | |
| 	return RIG_OK;
 | |
| }
 | |
| 
 | |
| int ts2k_scan_off(RIG *rig)
 | |
| {
 | |
| 	rig_debug(RIG_DEBUG_ERR, __FUNCTION__": turning scan off\n");
 | |
| 	return ts2k_scan_on(rig, '0');
 | |
| }
 | |
| 
 | |
| 
 | |
| int ts2k_get_parm(RIG *rig, setting_t parm, value_t *val)
 | |
| {
 | |
| 	int retval, acklen, cmdlen;
 | |
| 	char ack[30], cmd[30];
 | |
| 
 | |
| 	switch( parm ) {
 | |
| 	case RIG_PARM_BEEP:
 | |
| 		cmdlen = sprintf(cmd, "ex0120000;"); break;
 | |
| 	case RIG_PARM_BACKLIGHT:
 | |
| 		cmdlen = sprintf(cmd, "ex0000000;"); break;
 | |
| 	case RIG_PARM_KEYLIGHT:
 | |
| 		cmdlen = sprintf(cmd, "ex0010000;"); break;
 | |
| 	case RIG_PARM_APO:
 | |
| 		cmdlen = sprintf(cmd, "ex0570000;"); break;
 | |
| 	case RIG_PARM_ANN:
 | |
| 		return -RIG_ENIMPL;
 | |
| 	case RIG_PARM_TIME:
 | |
| 		return -RIG_ENAVAIL;
 | |
| 	default:
 | |
| 		return -RIG_EINTERNAL;	
 | |
| 	}
 | |
| 	acklen = 30;
 | |
| 	retval = ts2k_transaction(rig, cmd, cmdlen, ack, &acklen);
 | |
| 	if(retval == RIG_OK) {
 | |
| 		switch( parm ) {
 | |
| 		case RIG_PARM_BEEP:
 | |
| 			val->i = (int)(ack[9] - '0');
 | |
| 			break;
 | |
| 		case RIG_PARM_BACKLIGHT:
 | |
| 		case RIG_PARM_KEYLIGHT:
 | |
| 			val->f = (float)(ack[9] - '0');
 | |
| 			break;
 | |
| 		case RIG_PARM_APO:
 | |
| 			val->i = (int) int_n(cmd, &ack[9], 2);	// cmd is TMP now
 | |
| 			break;
 | |
| 		default:
 | |
| 			return -RIG_EINTERNAL;
 | |
| 		}
 | |
| 	}
 | |
| 	return retval;
 | |
| }
 | |
| 
 | |
| int ts2k_set_parm(RIG *rig, setting_t parm, value_t val)
 | |
| {
 | |
| 	char cmd[30];
 | |
| 	int retval, cmdlen, i;
 | |
| 
 | |
| 	rig_debug(RIG_DEBUG_ERR, __FUNCTION__": val.i = %u\n", val.i);
 | |
| 	rig_debug(RIG_DEBUG_ERR, __FUNCTION__": val.f = %f\n", val.f);
 | |
| 
 | |
| 	switch( parm ) {
 | |
| 	case RIG_PARM_APO:
 | |
| 		cmdlen = sprintf(cmd, "ex0570000%01u;",
 | |
| 					(val.i>180)? 3: val.i/60);
 | |
| 		break;
 | |
| 	case RIG_PARM_BEEP:
 | |
| 		cmdlen = sprintf(cmd, "ex0120000%01u;", (val.i>9)? 9: val.i);
 | |
| 		break;
 | |
| 
 | |
| 	case RIG_PARM_BACKLIGHT:
 | |
| 		cmdlen = sprintf(cmd, "ex0000000%01u;",
 | |
| 				(int) ((val.f>1.0)? 4.0 : val.f*4.0) );
 | |
| 		break;
 | |
| 
 | |
| 	case RIG_PARM_KEYLIGHT:
 | |
| 		cmdlen = sprintf(cmd, "ex0010000%01u;", (val.i==0)? 0: 1);
 | |
| 		break;
 | |
| 
 | |
| 	case RIG_PARM_ANN:
 | |
| 		return -RIG_ENIMPL;
 | |
| 
 | |
| 	case RIG_PARM_TIME:
 | |
| 	case RIG_PARM_BAT:
 | |
| 		return -RIG_ENAVAIL;
 | |
| 
 | |
| 	default:
 | |
| 		return -RIG_EINTERNAL;
 | |
| 	}
 | |
| 
 | |
| 	retval = ts2k_transaction(rig, cmd, cmdlen, NULL, NULL);
 | |
| 
 | |
| 	return retval;
 | |
| }
 | |
| 
 | |
| #undef CHKERR
 | |
| #undef STUFF
 | |
| 
 | |
| // End
 |