kopia lustrzana https://github.com/Hamlib/Hamlib
				
				
				
			
		
			
				
	
	
		
			547 wiersze
		
	
	
		
			11 KiB
		
	
	
	
		
			C
		
	
	
			
		
		
	
	
			547 wiersze
		
	
	
		
			11 KiB
		
	
	
	
		
			C
		
	
	
| #include <stdlib.h>
 | |
| 
 | |
| #include <stdio.h>
 | |
| #include <stdlib.h>
 | |
| #include <string.h>
 | |
| 
 | |
| #include "hamlib/rig.h"
 | |
| #include "iofunc.h"
 | |
| #include "misc.h"
 | |
| #include "num_stdio.h"
 | |
| 
 | |
| #include "xk852.h"
 | |
| 
 | |
| #define RESPSZ 64
 | |
| 
 | |
| #define LF "\x0a"
 | |
| #define CR "\x0d"
 | |
| #define BOM LF
 | |
| #define EOM CR
 | |
| 
 | |
| #define XK852_MODES (RIG_MODE_USB|RIG_MODE_LSB|RIG_MODE_CW|RIG_MODE_AM)
 | |
| 
 | |
| #define XK852_FUNC (RIG_FUNC_NONE)
 | |
| 
 | |
| #define XK852_LEVEL_ALL (RIG_LEVEL_SQL | RIG_LEVEL_RFPOWER)
 | |
| 
 | |
| #define XK852_PARM_ALL (RIG_PARM_NONE)
 | |
| 
 | |
| #define XK852_VFO (RIG_VFO_A)
 | |
| 
 | |
| #define XK852_VFO_OPS (RIG_OP_NONE)
 | |
| 
 | |
| #define XK852_ANTS (RIG_ANT_1)
 | |
| 
 | |
| #define XK852_MEM_CAP {    \
 | |
|         .freq = 1,      \
 | |
|         .mode = 1,      \
 | |
|         .width = 1,     \
 | |
|         .ant = 1,     \
 | |
|         .funcs = XK852_FUNC, \
 | |
|         .levels = RIG_LEVEL_SET(XK852_LEVEL_ALL), \
 | |
|         .channel_desc=1, \
 | |
|         .flags = RIG_CHFLAG_SKIP, \
 | |
| }
 | |
| 
 | |
| int
 | |
| xk852_transaction(RIG *rig, const char *cmd, int cmd_len, char *data,
 | |
|                   int *data_len)
 | |
| {
 | |
|     int retval;
 | |
|     hamlib_port_t *rp = RIGPORT(rig);
 | |
| 
 | |
|     rig_debug(RIG_DEBUG_VERBOSE, "%s: len=%d,cmd=%s\n", __func__, cmd_len,
 | |
|               cmd);
 | |
| 
 | |
|     rig_flush(rp);
 | |
| 
 | |
|     rig_debug(RIG_DEBUG_VERBOSE, "xk852_transaction: len=%d,cmd=%s\n",
 | |
|               cmd_len, cmd);
 | |
|     retval = write_block(rp, (unsigned char *) cmd, cmd_len);
 | |
| 
 | |
|     if (retval != RIG_OK)
 | |
|     {
 | |
|         return retval;
 | |
|     }
 | |
| 
 | |
|     /* no data expected */
 | |
|     if (!data || !data_len)
 | |
|     {
 | |
|         return RIG_OK;
 | |
|     }
 | |
| 
 | |
|     retval = read_string(rp, (unsigned char *) data, RESPSZ,
 | |
|                          CR, 1, 0, 1);
 | |
| 
 | |
|     if (retval < 0)
 | |
|     {
 | |
|         return retval;
 | |
|     }
 | |
| 
 | |
|     *data_len = retval;
 | |
| 
 | |
|     return RIG_OK;
 | |
| }
 | |
| 
 | |
| // Send command discard return
 | |
| int
 | |
| xk852_send_command(RIG *rig, const char *cmd, int cmd_len)
 | |
| {
 | |
|     char buf[RESPSZ];
 | |
|     int len;
 | |
|     int retval = 0;
 | |
|     retval = xk852_transaction(rig, cmd, cmd_len, buf, &len);
 | |
|     return retval;
 | |
| }
 | |
| 
 | |
| int
 | |
| xk852_parse_state(const char *msg, xk852_state *state)
 | |
| {
 | |
|     int ret;
 | |
| 
 | |
|     ret = sscanf(msg, BOM "*F%7u" SCNfreq, &state -> freq);
 | |
| 
 | |
|     if (ret != 1)
 | |
|     {
 | |
|         rig_debug(RIG_DEBUG_ERR, "%s: unable to parse frequency from '%s'\n", __func__,
 | |
|                   msg);
 | |
|         return -RIG_EPROTO;
 | |
|     };
 | |
| 
 | |
|     ret = sscanf(msg, "%*13cI%1u", &state -> mode);
 | |
| 
 | |
|     if (ret != 1)
 | |
|     {
 | |
|         rig_debug(RIG_DEBUG_ERR, "%s: unable to parse mode from '%s'\n", __func__, msg);
 | |
|         return -RIG_EPROTO;
 | |
|     };
 | |
| 
 | |
|     ret = sscanf(msg, "%*23cN%1u", &state -> noise_blank);
 | |
| 
 | |
|     if (ret != 1)
 | |
|     {
 | |
|         rig_debug(RIG_DEBUG_ERR, "%s: unable to parse noise blanker state from '%s'\n",
 | |
|                   __func__, msg);
 | |
|         return -RIG_EPROTO;
 | |
|     };
 | |
| 
 | |
|     ret = sscanf(msg, "%*31cS%1u", &state -> op_mode);
 | |
| 
 | |
|     if (ret != 1)
 | |
|     {
 | |
|         rig_debug(RIG_DEBUG_ERR, "%s: unable to parse op mode state from '%s'\n",
 | |
|                   __func__, msg);
 | |
|         return -RIG_EPROTO;
 | |
|     };
 | |
| 
 | |
|     return RIG_OK;
 | |
| };
 | |
| 
 | |
| int
 | |
| xk852_query_state(RIG *rig, xk852_state *state)
 | |
| {
 | |
|     char buf[RESPSZ];
 | |
|     int buf_len, ret;
 | |
| #define STATE_QUERY   BOM "*O1" EOM
 | |
|     ret = xk852_transaction(rig, STATE_QUERY, strlen(STATE_QUERY), buf, &buf_len);
 | |
| 
 | |
|     if (ret < 0)
 | |
|     {
 | |
|         return ret;
 | |
|     }
 | |
| 
 | |
|     ret = xk852_parse_state(buf, state);
 | |
| 
 | |
|     return ret;
 | |
| };
 | |
| 
 | |
| /*
 | |
|  * xk852_set_freq
 | |
|  * Assumes rig!=NULL
 | |
|  */
 | |
| int
 | |
| xk852_set_freq(RIG *rig, vfo_t vfo, freq_t freq)
 | |
| {
 | |
|     char freqbuf[32];
 | |
|     int retval;
 | |
|     char *fmt = BOM "*F%.7" PRIll EOM;
 | |
| 
 | |
|     rig_debug(RIG_DEBUG_VERBOSE, "%s: vfo=%s,freq=%.0f\n", __func__,
 | |
|               rig_strvfo(vfo), freq);
 | |
| 
 | |
|     SNPRINTF(freqbuf, sizeof(freqbuf), fmt, (int64_t)((freq + 5) / 10));
 | |
|     retval = xk852_send_command(rig, freqbuf, strlen(freqbuf));
 | |
| 
 | |
|     return retval;
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * xk852_get_freq
 | |
|  * Assumes rig!=NULL
 | |
|  */
 | |
| int
 | |
| xk852_get_freq(RIG *rig, vfo_t vfo, freq_t *freq)
 | |
| {
 | |
|     xk852_state state;
 | |
|     int ret;
 | |
| 
 | |
|     ret = xk852_query_state(rig, &state);
 | |
| 
 | |
|     *freq = (freq_t)(state.freq * 10);
 | |
|     return ret;
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * xk852_set_mode
 | |
|  * Assumes rig!=NULL
 | |
|  */
 | |
| int
 | |
| xk852_set_mode(RIG *rig, vfo_t vfo, rmode_t mode, pbwidth_t width)
 | |
| {
 | |
|     char buf[32];
 | |
|     xk852_mode smode;
 | |
|     int retval;
 | |
| 
 | |
|     rig_debug(RIG_DEBUG_VERBOSE, "%s: vfo=%s, mode=%s, width=%d\n", __func__,
 | |
|               rig_strvfo(vfo), rig_strvfo(mode), (int)width);
 | |
| 
 | |
|     switch (mode)
 | |
|     {
 | |
|     case RIG_MODE_AM:
 | |
|         smode = XK852_MODE_AME;
 | |
|         break;
 | |
| 
 | |
|     case RIG_MODE_USB:
 | |
|         smode = XK852_MODE_USB;
 | |
|         break;
 | |
| 
 | |
|     case RIG_MODE_LSB:
 | |
|         smode = XK852_MODE_LSB;
 | |
|         break;
 | |
| 
 | |
|     case RIG_MODE_CW:
 | |
|         smode = XK852_MODE_CW;
 | |
|         break;
 | |
| 
 | |
|     default:
 | |
|         return -RIG_EINVAL;
 | |
|     }
 | |
| 
 | |
|     SNPRINTF(buf, sizeof(buf), BOM "*I%1u" EOM, smode);
 | |
|     retval = xk852_send_command(rig, buf, strlen(buf));
 | |
| 
 | |
|     return retval;
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * xk852_get_mode
 | |
|  * Assumes rig!=NULL
 | |
|  */
 | |
| int
 | |
| xk852_get_mode(RIG *rig, vfo_t vfo, rmode_t *mode, pbwidth_t *width)
 | |
| {
 | |
|     xk852_state state;
 | |
|     int ret;
 | |
| 
 | |
|     ret = xk852_query_state(rig, &state);
 | |
| 
 | |
|     if (ret != RIG_OK)
 | |
|     {
 | |
|         return ret;
 | |
|     }
 | |
| 
 | |
|     switch (state.mode)
 | |
|     {
 | |
|     case XK852_MODE_AME: *mode = RIG_MODE_AM; break;
 | |
| 
 | |
|     case XK852_MODE_USB: *mode = RIG_MODE_USB; break;
 | |
| 
 | |
|     case XK852_MODE_LSB: *mode = RIG_MODE_LSB; break;
 | |
| 
 | |
|     case XK852_MODE_CW: *mode = RIG_MODE_CW; break;
 | |
| 
 | |
|     default:
 | |
|         return -RIG_EINVAL;
 | |
|     }
 | |
| 
 | |
|     return RIG_OK;
 | |
| }
 | |
| 
 | |
| int
 | |
| xk852_set_level(RIG *rig, vfo_t vfo, setting_t level, value_t val)
 | |
| {
 | |
|     char buf[64];
 | |
|     int retval;
 | |
| 
 | |
|     rig_debug(RIG_DEBUG_VERBOSE, "%s: vfo=%s\n", __func__, rig_strvfo(vfo));
 | |
| 
 | |
|     switch (level)
 | |
|     {
 | |
|     case RIG_LEVEL_RFPOWER:
 | |
|         if (val.f >= 0.5)
 | |
|             SNPRINTF(buf, sizeof(buf), BOM "*S4" EOM)
 | |
|             else if (val.f >= 0.1)
 | |
|                 SNPRINTF(buf, sizeof(buf), BOM "*S3" EOM)
 | |
|                 else if (val.f >= 0.001)
 | |
|                     SNPRINTF(buf, sizeof(buf), BOM "*S2" EOM)
 | |
|                     else
 | |
|                     {
 | |
|                         SNPRINTF(buf, sizeof(buf), BOM "*S1" EOM);
 | |
|                     }
 | |
| 
 | |
|         break;
 | |
| 
 | |
|     case RIG_LEVEL_SQL:
 | |
|         if (val.f <= 0.5)
 | |
|             SNPRINTF(buf, sizeof(buf), BOM "*N0" EOM)
 | |
|             else
 | |
|             {
 | |
|                 SNPRINTF(buf, sizeof(buf), BOM "*N1" EOM);
 | |
|             }
 | |
| 
 | |
|         break;
 | |
| 
 | |
|     case RIG_LEVEL_AGC:
 | |
|     case RIG_LEVEL_AF:
 | |
|         return -RIG_ENIMPL;
 | |
| 
 | |
|     default:
 | |
|         return -RIG_EINVAL;
 | |
|     }
 | |
| 
 | |
|     retval = xk852_send_command(rig, buf, strlen(buf));
 | |
| 
 | |
|     return retval;
 | |
| }
 | |
| 
 | |
| int
 | |
| xk852_get_level(RIG *rig, vfo_t vfo, setting_t level, value_t *val)
 | |
| {
 | |
|     int ret;
 | |
|     xk852_state state;
 | |
| 
 | |
|     ret = xk852_query_state(rig, &state);
 | |
| 
 | |
|     if (ret != RIG_OK)
 | |
|     {
 | |
|         return ret;
 | |
|     }
 | |
| 
 | |
|     switch (level)
 | |
|     {
 | |
|     case RIG_LEVEL_SQL:
 | |
|         switch (state.noise_blank)
 | |
|         {
 | |
|         case XK852_NOISE_BLANK_OFF:
 | |
|             val->f = 1;
 | |
|             return RIG_OK;
 | |
|             break;
 | |
| 
 | |
|         case XK852_NOISE_BLANK_ON:
 | |
|             val->f = 0;
 | |
|             return RIG_OK;
 | |
|             break;
 | |
|         }
 | |
| 
 | |
|     case RIG_LEVEL_RFPOWER:
 | |
|         switch (state.op_mode)
 | |
|         {
 | |
|         case XK852_OP_MODE_OFF:
 | |
|             val->f = 0;
 | |
|             return RIG_OK;
 | |
|             break;
 | |
| 
 | |
|         case XK852_OP_MODE_RX:
 | |
|             val->f = 0;
 | |
|             return RIG_OK;
 | |
|             break;
 | |
| 
 | |
|         case XK852_OP_MODE_TX_LOW:
 | |
|             val->f = 0.099;
 | |
|             return RIG_OK;
 | |
|             break;
 | |
| 
 | |
|         case XK852_OP_MODE_TX_MID:
 | |
|             val->f = 0.499;
 | |
|             return RIG_OK;
 | |
|             break;
 | |
| 
 | |
|         case XK852_OP_MODE_TX_FULL:
 | |
|             val->f = 1;
 | |
|             return RIG_OK;
 | |
|             break;
 | |
|         }
 | |
| 
 | |
|     default:
 | |
|         return -RIG_ENIMPL;
 | |
|         break;
 | |
|     }
 | |
| 
 | |
|     return -RIG_EINVAL;
 | |
| }
 | |
| 
 | |
| int
 | |
| xk852_set_ptt(RIG *rig, vfo_t vfo, ptt_t ptt)
 | |
| {
 | |
|     int retval = 0;
 | |
|     char cmd[32];
 | |
| 
 | |
|     int ptt_code = 2;
 | |
| 
 | |
|     switch (ptt)
 | |
|     {
 | |
|     case RIG_PTT_OFF:
 | |
|         ptt_code = 2;
 | |
|         break;
 | |
| 
 | |
|     case RIG_PTT_ON:
 | |
|         ptt_code = 1;
 | |
|         break;
 | |
| 
 | |
|     case RIG_PTT_ON_MIC:
 | |
|         ptt_code = 1;
 | |
|         break;
 | |
| 
 | |
|     case RIG_PTT_ON_DATA:
 | |
|         ptt_code = 1;
 | |
|         break;
 | |
| 
 | |
|     default:
 | |
|         return -RIG_EINVAL;
 | |
|     }
 | |
| 
 | |
|     rig_debug(RIG_DEBUG_VERBOSE, "%s: vfo=%s\n", __func__, rig_strvfo(vfo));
 | |
| 
 | |
|     SNPRINTF(cmd, sizeof(cmd), BOM "*X%1d" EOM, ptt_code);
 | |
|     retval = xk852_transaction(rig, cmd, strlen(cmd), NULL, NULL);
 | |
|     return retval;
 | |
| }
 | |
| 
 | |
| int
 | |
| xk852_get_ptt(RIG *rig, vfo_t vfo, ptt_t *ptt)
 | |
| {
 | |
|     //    int retval = 0;
 | |
|     //  int len;
 | |
|     //  char buf[RESPSZ];
 | |
|     //  char *cmd = BOM "X?" EOM;
 | |
| 
 | |
|     //    rig_debug(RIG_DEBUG_VERBOSE, "%s: vfo=%s\n", __func__, rig_strvfo(vfo));
 | |
| 
 | |
|     //    retval = xk852_transaction(rig, cmd, strlen(cmd), buf, &len);
 | |
| 
 | |
|     //    if (retval < 0)
 | |
|     //    {
 | |
|     //        return retval;
 | |
|     //    }
 | |
| 
 | |
|     //    retval = (sscanf(buf, "%*cX%1u", ptt) == 1) ? RIG_OK : -RIG_EPROTO;
 | |
| 
 | |
|     *ptt = RIG_PTT_OFF;
 | |
|     return RIG_OK;
 | |
| }
 | |
| 
 | |
| 
 | |
| /*
 | |
|  * XK852 rig capabilities.
 | |
|  */
 | |
| 
 | |
| struct rig_caps xk852_caps =
 | |
| {
 | |
|     RIG_MODEL(RIG_MODEL_XK852),
 | |
|     .model_name = "XK852",
 | |
|     .mfg_name = "Rohde&Schwarz",
 | |
|     .version = BACKEND_VER ".0",
 | |
|     .copyright = "LGPL",
 | |
|     .status = RIG_STATUS_ALPHA,
 | |
|     .rig_type = RIG_TYPE_TRANSCEIVER,
 | |
|     .ptt_type = RIG_PTT_RIG,
 | |
|     // Need to set RTS on for some reason
 | |
|     // And HANDSHAKE_NONE even though HARDWARE is what is called for
 | |
|     .dcd_type = RIG_DCD_NONE,
 | |
|     .port_type = RIG_PORT_SERIAL,
 | |
|     .serial_rate_min = 9600,
 | |
|     .serial_rate_max = 9600, /* 7E1, RTS/CTS */
 | |
|     .serial_data_bits = 7,
 | |
|     .serial_stop_bits = 1,
 | |
|     .serial_parity = RIG_PARITY_EVEN,
 | |
|     .serial_handshake = RIG_HANDSHAKE_NONE,
 | |
|     .write_delay = 0,
 | |
|     .post_write_delay = 200, //nach senden warten // also see post_ptt_delay (in manpage)
 | |
|     .timeout = 200,
 | |
|     .retry = 3,
 | |
|     .has_get_func = XK852_FUNC,
 | |
|     .has_set_func = XK852_FUNC,
 | |
|     .has_get_level = XK852_LEVEL_ALL,
 | |
|     .has_set_level = RIG_LEVEL_SET(XK852_LEVEL_ALL),
 | |
|     .has_get_parm = XK852_PARM_ALL,
 | |
|     .has_set_parm = RIG_PARM_SET(XK852_PARM_ALL),
 | |
|     .level_gran = {},
 | |
|     .parm_gran = {},
 | |
|     .ctcss_list = NULL,
 | |
|     .dcs_list = NULL,
 | |
|     .preamp = {RIG_DBLST_END},
 | |
|     .attenuator = {RIG_DBLST_END},
 | |
|     .max_rit = Hz(0),
 | |
|     .max_xit = Hz(0),
 | |
|     .max_ifshift = Hz(0),
 | |
|     .targetable_vfo = 0,
 | |
|     .transceive = RIG_TRN_RIG,
 | |
|     .bank_qty = 0,
 | |
|     .chan_desc_sz = 7,        /* FIXME */
 | |
|     .vfo_ops = XK852_VFO_OPS,
 | |
| 
 | |
|     .chan_list = {
 | |
|         {0, 99, RIG_MTYPE_MEM, XK852_MEM_CAP},
 | |
|         RIG_CHAN_END,
 | |
|     },
 | |
| 
 | |
|     .rx_range_list1 = {
 | |
|         {
 | |
|             kHz(1500), MHz(30), XK852_MODES, -1, -1, XK852_VFO,
 | |
|             XK852_ANTS
 | |
|         },
 | |
|         RIG_FRNG_END,
 | |
|     },
 | |
|     .tx_range_list1 = {
 | |
|         {
 | |
|             kHz(1500), MHz(30), XK852_MODES, 0, 150000, XK852_VFO,
 | |
|             XK852_ANTS
 | |
|         },
 | |
|         RIG_FRNG_END,
 | |
|     },
 | |
| 
 | |
|     .tuning_steps =     {
 | |
|         {RIG_MODE_ALL, 10},
 | |
|         RIG_TS_END,
 | |
|     },
 | |
| 
 | |
|     /* mode/filter list, remember: order matters! */
 | |
|     .filters = {
 | |
|         {RIG_MODE_WFM, kHz(150)},
 | |
|         {RIG_MODE_FM | RIG_MODE_AM, kHz(15)},
 | |
|         {XK852_MODES, kHz(2.4)},
 | |
|         {XK852_MODES, kHz(1.5)},
 | |
|         {XK852_MODES, Hz(150)},
 | |
|         {XK852_MODES, Hz(300)},
 | |
|         {XK852_MODES, Hz(600)},
 | |
|         {XK852_MODES, kHz(6)},
 | |
|         {XK852_MODES, kHz(9)},
 | |
|         {XK852_MODES, kHz(15)},
 | |
|         {XK852_MODES, kHz(30)},
 | |
|         {XK852_MODES, kHz(50)},
 | |
|         {XK852_MODES, kHz(120)},
 | |
|         RIG_FLT_END,
 | |
|     },
 | |
|     .priv = NULL,
 | |
| 
 | |
|     .set_ptt = xk852_set_ptt,
 | |
|     .get_ptt = xk852_get_ptt,
 | |
|     .set_freq = xk852_set_freq,
 | |
|     .get_freq = xk852_get_freq,
 | |
|     .set_mode =  xk852_set_mode,
 | |
|     .get_mode =  xk852_get_mode,
 | |
|     .set_level =  xk852_set_level,
 | |
|     .get_level =  xk852_get_level,
 | |
|     .hamlib_check_rig_caps = HAMLIB_CHECK_RIG_CAPS
 | |
| };
 |