/* * ft1000.c - (C) Stephane Fillod 2002-2003 (fillods@users.sourceforge.net) * * This shared library provides an API for communicating * via serial interface to an FT-1000MP using the "CAT" interface * * $Id: ft1000mp.c,v 1.2 2003-04-07 22:42:00 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. * */ /* * Right now, this FT-1000MP implementation is a big mess. * This is actually a fast copy past (from ft920.c), * just to make get_freq/set_freq and co to work for a friend of mine. * I wouln't mind if someone could take over the maintenance * of this piece of code, and eventually rewrite it. * '02, Stephane */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include /* String function definitions */ #include /* UNIX standard function definitions */ #include "hamlib/rig.h" #include "bandplan.h" #include "serial.h" #include "misc.h" #include "cal.h" #include "yaesu.h" #include "ft1000mp.h" /* Private helper function prototypes */ static int ft1000mp_get_update_data(RIG *rig, unsigned char ci, unsigned char rl); static int ft1000mp_send_priv_cmd(RIG *rig, unsigned char ci); /* * Native ft1000mp cmd set prototypes. These are READ ONLY as each * rig instance will copy from these and modify if required. * Complete sequences (1) can be read and used directly as a cmd sequence. * Incomplete sequences (0) must be completed with extra parameters * eg: mem number, or freq etc.. * */ static const yaesu_cmd_set_t ncmd[] = { { 1, { 0x00, 0x00, 0x00, 0x00, 0x01 } }, /* split = off */ { 1, { 0x00, 0x00, 0x00, 0x01, 0x01 } }, /* split = on */ { 0, { 0x00, 0x00, 0x00, 0x00, 0x02 } }, /* recall memory */ { 0, { 0x00, 0x00, 0x00, 0x00, 0x03 } }, /* memory operations */ { 1, { 0x00, 0x00, 0x00, 0x00, 0x05 } }, /* select vfo A */ { 1, { 0x00, 0x00, 0x00, 0x01, 0x05 } }, /* select vfo B */ { 0, { 0x00, 0x00, 0x00, 0x00, 0x06 } }, /* copy memory data to vfo A */ { 0, { 0x00, 0x00, 0x00, 0x00, 0x09 } }, /* RX clarifier on */ { 1, { 0x00, 0x00, 0x00, 0x01, 0x09 } }, /* RX clarifier off */ { 1, { 0x00, 0x00, 0x00, 0x80, 0x09 } }, /* TX clarifier on */ { 1, { 0x00, 0x00, 0x00, 0x81, 0x09 } }, /* TX clarifier off */ { 0, { 0x00, 0x00, 0x00, 0x00, 0x0a } }, /* set VFOA freq */ { 0, { 0x00, 0x00, 0x00, 0x00, 0x8a } }, /* set VFOB freq */ { 1, { 0x00, 0x00, 0x00, 0x00, 0x0c } }, /* vfo A mode set LSB */ { 1, { 0x00, 0x00, 0x00, 0x01, 0x0c } }, /* vfo A mode set USB */ { 1, { 0x00, 0x00, 0x00, 0x02, 0x0c } }, /* vfo A mode set CW-USB */ { 1, { 0x00, 0x00, 0x00, 0x03, 0x0c } }, /* vfo A mode set CW-LSB */ { 1, { 0x00, 0x00, 0x00, 0x04, 0x0c } }, /* vfo A mode set AM */ { 1, { 0x00, 0x00, 0x00, 0x05, 0x0c } }, /* vfo A mode set AM sync */ { 1, { 0x00, 0x00, 0x00, 0x06, 0x0c } }, /* vfo A mode set FM */ { 1, { 0x00, 0x00, 0x00, 0x07, 0x0c } }, /* vfo A mode set FMW? */ { 1, { 0x00, 0x00, 0x00, 0x08, 0x0c } }, /* vfo A mode set RTTY-LSB */ { 1, { 0x00, 0x00, 0x00, 0x09, 0x0c } }, /* vfo A mode set RTTY-USB */ { 1, { 0x00, 0x00, 0x00, 0x0a, 0x0c } }, /* vfo A mode set DATA-LSB */ { 1, { 0x00, 0x00, 0x00, 0x0b, 0x0c } }, /* vfo A mode set DATA-FM */ /* { 1, { 0x00, 0x00, 0x00, 0x80, 0x0c } }, */ /* vfo B mode set LSB */ /* { 1, { 0x00, 0x00, 0x00, 0x81, 0x0c } }, */ /* vfo B mode set USB */ /* { 1, { 0x00, 0x00, 0x00, 0x82, 0x0c } }, */ /* vfo B mode set CW-USB */ /* { 1, { 0x00, 0x00, 0x00, 0x83, 0x0c } }, */ /* vfo B mode set CW-LSB */ /* { 1, { 0x00, 0x00, 0x00, 0x84, 0x0c } }, */ /* vfo B mode set AM */ /* { 1, { 0x00, 0x00, 0x00, 0x85, 0x0c } }, */ /* vfo B mode set AM */ /* { 1, { 0x00, 0x00, 0x00, 0x86, 0x0c } }, */ /* vfo B mode set FM */ /* { 1, { 0x00, 0x00, 0x00, 0x87, 0x0c } }, */ /* vfo B mode set FMN */ /* { 1, { 0x00, 0x00, 0x00, 0x88, 0x0c } }, */ /* vfo B mode set DATA-LSB */ /* { 1, { 0x00, 0x00, 0x00, 0x89, 0x0c } }, */ /* vfo B mode set DATA-LSB */ /* { 1, { 0x00, 0x00, 0x00, 0x8a, 0x0c } }, */ /* vfo B mode set DATA-USB */ /* { 1, { 0x00, 0x00, 0x00, 0x8b, 0x0c } }, */ /* vfo B mode set DATA-FM */ { 0, { 0x00, 0x00, 0x00, 0x00, 0x0e } }, /* update interval/pacing */ { 1, { 0x00, 0x00, 0x00, 0x03, 0x10 } }, /* status update VFO A & B update */ { 1, { 0x00, 0x00, 0x00, 0x02, 0x10 } }, /* status update operating data */ { 1, { 0x00, 0x00, 0x00, 0x01, 0xFA } }, /* Read status flags */ { 1, { 0x00, 0x00, 0x00, 0x00, 0xF0 } }, /* PTT OFF */ { 1, { 0x00, 0x00, 0x00, 0x01, 0xF0 } }, /* PTT ON */ /* { 0, { 0x00, 0x00, 0x00, 0x00, 0x70 } }, */ /* keyer commands */ /* { 1, { 0x00, 0x00, 0x00, 0x00, 0x81 } }, */ /* tuner off */ /* { 1, { 0x00, 0x00, 0x00, 0x01, 0x81 } }, */ /* tuner on */ /* { 1, { 0x00, 0x00, 0x00, 0x00, 0x82 } }, */ /* tuner start*/ }; #define FT1000MP_ALL_RX_MODES (RIG_MODE_CW|RIG_MODE_SSB|RIG_MODE_RTTY|RIG_MODE_AM|RIG_MODE_FM) /* * TX caps */ #define FT1000MP_OTHER_TX_MODES (RIG_MODE_CW| RIG_MODE_SSB|RIG_MODE_RTTY|RIG_MODE_FM) /* 100 W class */ #define FT1000MP_AM_TX_MODES (RIG_MODE_AM ) /* set 25W max */ #define FT1000MP_FUNC_ALL (RIG_FUNC_FAGC|RIG_FUNC_NB|RIG_FUNC_COMP|RIG_FUNC_VOX|RIG_FUNC_TONE|RIG_FUNC_TSQL|RIG_FUNC_SBKIN|RIG_FUNC_FBKIN|RIG_FUNC_LOCK /* |RIG_FUNC_TUNER */) /* FIXME */ #define FT1000MP_LEVEL_GET (RIG_LEVEL_STRENGTH|RIG_LEVEL_ALC|RIG_LEVEL_SWR|RIG_LEVEL_RFPOWER|RIG_LEVEL_COMP|RIG_LEVEL_MICGAIN|RIG_LEVEL_CWPITCH) #define FT1000MP_VFOS (RIG_VFO_A|RIG_VFO_B) #define FT1000MP_ANTS 0 /* FIXME: declare antenna connectors: ANT-A, ANT-B, RX ANT */ #define FT1000MP_VFO_OPS (RIG_OP_TO_VFO|RIG_OP_FROM_VFO|RIG_OP_CPY|RIG_OP_UP|RIG_OP_DOWN) /** * 33 CTCSS sub-audible tones */ const tone_t ft1000mp_ctcss_list[] = { 670, 719, 770, 825, 885, 948, 1000, 1035, 1072, 1109, 1148, 1188, 1230, 1273, 1318, 1365, 1413, 1462, 1514, 1567, 1598, 1622, 1679, 1738, 1799, 1862, 1928, 2035, 2107, 2181, 2257, 2336, 2418, 2503, 0, }; #define FT1000MP_MEM_CAP { \ .freq = 1, \ .mode = 1, \ .width = 1, \ .ant = 1, \ .rit = 1, \ .xit = 1, \ .rptr_shift = 1, \ .flags = 1, \ } #define FT1000MP_STR_CAL { 12, \ { \ { 0, -60 }, \ { 17, -54 }, /* S0 */ \ { 17, -48 }, \ { 34, -42 }, \ { 51, -36 }, \ { 68, -30 }, \ { 85, -24 }, \ { 102, -18 }, \ { 119, -12 }, \ { 136, -6 }, \ { 160, 0 }, /* S9 */ \ { 255, 60 } /* +60 */ \ } } /* * future - private data * */ struct ft1000mp_priv_data { unsigned char pacing; /* pacing value */ unsigned int read_update_delay; /* depends on pacing value */ unsigned char current_vfo; /* active VFO from last cmd */ unsigned char p_cmd[YAESU_CMD_LENGTH]; /* private copy of 1 constructed CAT cmd */ yaesu_cmd_set_t pcs[FT1000MP_NATIVE_SIZE]; /* private cmd set */ unsigned char update_data[2*FT1000MP_STATUS_UPDATE_LENGTH];/* returned data--max value, some are less */ cal_table_t str_cal; }; /* * ft1000mp rigs capabilities. * Also this struct is READONLY! * */ const struct rig_caps ft1000mp_caps = { .rig_model = RIG_MODEL_FT1000MP, .model_name = "MARK-V FT-1000MP", .mfg_name = "Yaesu", .version = "0.0.5", .copyright = "LGPL", .status = RIG_STATUS_ALPHA, .rig_type = RIG_TYPE_TRANSCEIVER, .ptt_type = RIG_PTT_RIG, .dcd_type = RIG_DCD_RIG, .port_type = RIG_PORT_SERIAL, .serial_rate_min = 4800, .serial_rate_max = 4800, .serial_data_bits = 8, .serial_stop_bits = 2, .serial_parity = RIG_PARITY_NONE, .serial_handshake = RIG_HANDSHAKE_NONE, .write_delay = FT1000MP_WRITE_DELAY, .post_write_delay = FT1000MP_POST_WRITE_DELAY, .timeout = 2000, .retry = 0, .has_get_func = FT1000MP_FUNC_ALL, .has_set_func = FT1000MP_FUNC_ALL, .has_get_level = FT1000MP_LEVEL_GET, .has_set_level = RIG_LEVEL_NONE, /* as strange as it could be */ .has_get_parm = RIG_PARM_NONE, .has_set_parm = RIG_PARM_NONE, .ctcss_list = ft1000mp_ctcss_list, .dcs_list = NULL, .vfo_ops = FT1000MP_VFO_OPS, .preamp = { RIG_DBLST_END, }, .attenuator = { RIG_DBLST_END, }, .max_rit = Hz(9999), .max_xit = Hz(9999), .max_ifshift = kHz(1.12), .targetable_vfo = RIG_TARGETABLE_FREQ, .transceive = RIG_TRN_OFF, .bank_qty = 0, .chan_desc_sz = 0, .chan_list = { { 1, 99, RIG_MTYPE_MEM, FT1000MP_MEM_CAP }, { 100, 108, RIG_MTYPE_EDGE }, /* P1 .. P9 */ { 109, 113, RIG_MTYPE_MEMOPAD }, /* Q1 .. Q5 */ RIG_CHAN_END, }, .rx_range_list1 = { {kHz(100), MHz(30), FT1000MP_ALL_RX_MODES, -1, -1, FT1000MP_VFOS, FT1000MP_ANTS }, /* General coverage + ham */ RIG_FRNG_END, }, /* Region 1 rx ranges */ .tx_range_list1 = { FRQ_RNG_HF(1,FT1000MP_OTHER_TX_MODES, W(5),W(100),FT1000MP_VFOS,FT1000MP_ANTS), FRQ_RNG_HF(1,FT1000MP_AM_TX_MODES, W(2),W(25),FT1000MP_VFOS,FT1000MP_ANTS), /* AM class */ RIG_FRNG_END, }, /* region 1 TX ranges */ .rx_range_list2 = { {kHz(100), MHz(30), FT1000MP_ALL_RX_MODES, -1, -1, FT1000MP_VFOS, FT1000MP_ANTS }, /* General coverage + ham */ RIG_FRNG_END, }, /* Region 2 rx ranges */ .tx_range_list2 = { FRQ_RNG_HF(1,FT1000MP_OTHER_TX_MODES, W(5),W(100),FT1000MP_VFOS,FT1000MP_ANTS), FRQ_RNG_HF(1,FT1000MP_AM_TX_MODES, W(2),W(25),FT1000MP_VFOS,FT1000MP_ANTS), /* AM class */ RIG_FRNG_END, }, /* region 2 TX ranges */ .tuning_steps = { {RIG_MODE_CW|RIG_MODE_SSB|RIG_MODE_RTTY, Hz(10)}, /* Normal */ {RIG_MODE_CW|RIG_MODE_SSB|RIG_MODE_RTTY, Hz(100)}, /* Fast */ {RIG_MODE_AM, Hz(100)}, /* Normal */ {RIG_MODE_AM, kHz(1)}, /* Fast */ {RIG_MODE_FM, Hz(100)}, /* Normal */ {RIG_MODE_FM, kHz(1)}, /* Fast */ RIG_TS_END, /* * The FT-1000MP has a Fine tuning step which increments in 1 Hz steps * for SSB_CW_RX_MODES, and 10 Hz steps for AM_RX_MODES and * FM_RX_MODES. It doesn't appear that anything finer than 10 Hz * is available through the CAT interface, however. -N0NB * */ }, /* mode/filter list, .remember = order matters! */ .filters = { {RIG_MODE_SSB|RIG_MODE_CW|RIG_MODE_RTTY|RIG_MODE_AM, kHz(2.4)}, {RIG_MODE_SSB|RIG_MODE_CW|RIG_MODE_RTTY, kHz(2.0)}, {RIG_MODE_CW|RIG_MODE_RTTY, Hz(500)}, {RIG_MODE_CW|RIG_MODE_RTTY, Hz(250)}, {RIG_MODE_AM, kHz(5)}, /* wide */ {RIG_MODE_FM, kHz(8)}, /* FM */ RIG_FLT_END, }, .priv = NULL, /* private data */ .rig_init = ft1000mp_init, .rig_cleanup = ft1000mp_cleanup, .rig_open = ft1000mp_open, /* port opened */ .set_freq = ft1000mp_set_freq, /* set freq */ .get_freq = ft1000mp_get_freq, /* get freq */ .set_mode = ft1000mp_set_mode, /* set mode */ .get_mode = ft1000mp_get_mode, /* get mode */ .set_vfo = ft1000mp_set_vfo, /* set vfo */ .get_vfo = ft1000mp_get_vfo, /* get vfo */ .get_rit = ft1000mp_get_rit, .set_rit = ft1000mp_set_rit, .get_xit = ft1000mp_get_xit, .set_xit = ft1000mp_set_xit, .get_level = ft1000mp_get_level, .set_ptt = ft1000mp_set_ptt, /* TODO: the remaining ... */ }; /* * _init * */ int ft1000mp_init(RIG *rig) { struct ft1000mp_priv_data *p; cal_table_t cal = FT1000MP_STR_CAL; rig_debug(RIG_DEBUG_TRACE,"ft1000mp: ft1000mp_init called \n"); p = (struct ft1000mp_priv_data*)malloc(sizeof(struct ft1000mp_priv_data)); if (!p) /* whoops! memory shortage! */ return -RIG_ENOMEM; /* * Copy native cmd set to private cmd storage area */ memcpy(p->pcs,ncmd,sizeof(ncmd)); /* TODO: read pacing from preferences */ p->pacing = FT1000MP_PACING_DEFAULT_VALUE; /* set pacing to minimum for now */ p->read_update_delay = FT1000MP_DEFAULT_READ_TIMEOUT; /* set update timeout to safe value */ p->current_vfo = RIG_VFO_A; /* default to VFO_A ? */ memcpy(&p->str_cal, &cal, sizeof(cal)); rig->state.priv = (void*)p; return RIG_OK; } /* * ft1000mp_cleanup routine * the serial port is closed by the frontend * */ int ft1000mp_cleanup(RIG *rig) { rig_debug(RIG_DEBUG_VERBOSE, "ft1000mp: ft1000mp_cleanup called\n"); if (rig->state.priv) free(rig->state.priv); rig->state.priv = NULL; return RIG_OK; } /* * ft1000mp_open routine * */ int ft1000mp_open(RIG *rig) { struct rig_state *rig_s; struct ft1000mp_priv_data *p; unsigned char *cmd; /* points to sequence to send */ rig_debug(RIG_DEBUG_VERBOSE, "ft1000mp: ft1000mp_open called\n"); rig_s = &rig->state; p = (struct ft1000mp_priv_data *)rig_s->priv; rig_debug(RIG_DEBUG_TRACE,"ft1000mp: rig_open: write_delay = %i msec \n", rig_s->rigport.write_delay); rig_debug(RIG_DEBUG_TRACE,"ft1000mp: rig_open: post_write_delay = %i msec \n", rig_s->rigport.post_write_delay); /* * Copy native cmd PACING to private cmd storage area */ memcpy(&p->p_cmd, &ncmd[FT1000MP_NATIVE_PACING].nseq, YAESU_CMD_LENGTH); p->p_cmd[3] = p->pacing; /* get pacing value, and store in private cmd */ rig_debug(RIG_DEBUG_TRACE,"ft1000mp: read pacing = %i\n",p->pacing); /* send PACING cmd to rig */ cmd = p->p_cmd; write_block(&rig_s->rigport, cmd, YAESU_CMD_LENGTH); /* TODO */ return RIG_OK; } int ft1000mp_set_freq(RIG *rig, vfo_t vfo, freq_t freq) { struct rig_state *rig_s; struct ft1000mp_priv_data *p; unsigned char *cmd; /* points to sequence to send */ int cmd_index = 0; rig_debug(RIG_DEBUG_TRACE,"ft1000mp: ft1000mp_set_freq called\n"); p = (struct ft1000mp_priv_data*)rig->state.priv; rig_s = &rig->state; rig_debug(RIG_DEBUG_TRACE,"ft1000mp: requested freq = %lli Hz \n", freq); if (vfo == RIG_VFO_CURR) vfo = p->current_vfo; switch (vfo) { case RIG_VFO_A: cmd_index = FT1000MP_NATIVE_FREQA_SET; break; case RIG_VFO_B: cmd_index = FT1000MP_NATIVE_FREQB_SET; break; case RIG_VFO_MEM: /* TODO, hint: store current memory number */ return -RIG_ENIMPL; default: rig_debug(RIG_DEBUG_WARN,"ft1000mp: unknown VFO %d\n", vfo); return -RIG_EINVAL; } /* * Copy native cmd freq_set to private cmd storage area */ memcpy(&p->p_cmd,&ncmd[cmd_index].nseq,YAESU_CMD_LENGTH); to_bcd(p->p_cmd,freq/10,8); /* store bcd format in in p_cmd */ /* TODO -- fix 10Hz resolution -- FS */ rig_debug(RIG_DEBUG_TRACE,"ft1000mp: requested freq after conversion = %lli Hz\n", from_bcd(p->p_cmd,8)* 10 ); cmd = p->p_cmd; /* get native sequence */ write_block(&rig_s->rigport, cmd, YAESU_CMD_LENGTH); return RIG_OK; } /* * Return Freq for a given VFO * */ int ft1000mp_get_freq(RIG *rig, vfo_t vfo, freq_t *freq) { struct ft1000mp_priv_data *priv; unsigned char *p; freq_t f; int cmd_index, len, retval; rig_debug(RIG_DEBUG_VERBOSE,"ft1000mp: ft1000mp_get_freq called\n"); priv = (struct ft1000mp_priv_data*)rig->state.priv; if (vfo == RIG_VFO_A || vfo == RIG_VFO_B) { cmd_index = FT1000MP_NATIVE_VFO_UPDATE; len = 2*FT1000MP_STATUS_UPDATE_LENGTH; } else { /* RIG_VFO_CURR or RIG_VFO_MEM */ cmd_index = FT1000MP_NATIVE_CURR_VFO_UPDATE; len = FT1000MP_STATUS_UPDATE_LENGTH; } /* * get record from rig */ retval = ft1000mp_get_update_data(rig, cmd_index, len); if (retval < 0) return retval; if (vfo == RIG_VFO_B) p = &priv->update_data[FT1000MP_SUMO_VFO_B_FREQ]; else p = &priv->update_data[FT1000MP_SUMO_VFO_A_FREQ]; /* CURR_VFO has VFOA offset */ /* big endian integer, kinda */ f = ((((((p[0]<<8) + p[1])<<8) + p[2])<<8) + p[3])*10/16; rig_debug(RIG_DEBUG_TRACE,"ft1000mp: freq = %lli Hz for VFO [%x]\n", f, vfo); *freq = f; /* return diplayed frequency */ return RIG_OK; } /* * set mode : eg AM, CW etc for a given VFO * */ int ft1000mp_set_mode(RIG *rig, vfo_t vfo, rmode_t mode, pbwidth_t width ) { unsigned char cmd_index = 0; /* index of sequence to send */ rig_debug(RIG_DEBUG_VERBOSE,"ft1000mp: ft1000mp_set_mode called\n"); /* frontend sets VFO for us */ rig_debug(RIG_DEBUG_TRACE,"ft1000mp: generic mode = %x\n", mode); /* * translate mode from generic to ft1000mp specific */ switch(mode) { case RIG_MODE_AM: cmd_index = FT1000MP_NATIVE_MODE_SET_AM; break; case RIG_MODE_CW: cmd_index = FT1000MP_NATIVE_MODE_SET_CW; break; case RIG_MODE_USB: cmd_index = FT1000MP_NATIVE_MODE_SET_USB; break; case RIG_MODE_LSB: cmd_index = FT1000MP_NATIVE_MODE_SET_LSB; break; case RIG_MODE_FM: cmd_index = FT1000MP_NATIVE_MODE_SET_FM; break; case RIG_MODE_RTTY: cmd_index = FT1000MP_NATIVE_MODE_SET_RTTY_LSB; break; default: return -RIG_EINVAL; /* sorry, wrong MODE */ } /* * Now set width * FIXME: so far setting passband is buggy, only 0 is accepted */ /* * phew! now send cmd to rig */ ft1000mp_send_priv_cmd(rig,cmd_index); rig_debug(RIG_DEBUG_TRACE,"ft1000mp: cmd_index = %i\n", cmd_index); return RIG_OK; /* good */ } /* * get mode : eg AM, CW etc for a given VFO * */ int ft1000mp_get_mode(RIG *rig, vfo_t vfo, rmode_t *mode, pbwidth_t *width) { struct ft1000mp_priv_data *priv; unsigned char mymode; /* ft1000mp mode */ int cmd_index, len, retval; rig_debug(RIG_DEBUG_VERBOSE,"ft1000mp: ft1000mp_get_mode called\n"); priv = (struct ft1000mp_priv_data*)rig->state.priv; if (vfo == RIG_VFO_A || vfo == RIG_VFO_B) { cmd_index = FT1000MP_NATIVE_VFO_UPDATE; len = 2*FT1000MP_STATUS_UPDATE_LENGTH; } else { /* RIG_VFO_CURR or RIG_VFO_MEM */ cmd_index = FT1000MP_NATIVE_CURR_VFO_UPDATE; len = FT1000MP_STATUS_UPDATE_LENGTH; } /* * get record from rig */ retval = ft1000mp_get_update_data(rig, cmd_index, len); if (retval < 0) return retval; if (vfo == RIG_VFO_B) mymode = priv->update_data[FT1000MP_SUMO_VFO_B_MODE]; else mymode = priv->update_data[FT1000MP_SUMO_VFO_A_MODE]; /* CURR_VFO is VFOA offset */ rig_debug(RIG_DEBUG_TRACE,"ft1000mp: mymode = %x (before)\n", mymode); mymode &= MODE_MASK; rig_debug(RIG_DEBUG_TRACE,"ft1000mp: mymode = %x (after)\n", mymode); /* * translate mode from ft1000mp to generic. * TODO: Add DATA, and Narrow modes. CW on LSB? -N0NB */ switch(mymode) { case MODE_CW: *mode = RIG_MODE_CW; break; case MODE_USB: *mode = RIG_MODE_USB; break; case MODE_LSB: *mode = RIG_MODE_LSB; break; case MODE_AM: *mode = RIG_MODE_AM; break; case MODE_FM: *mode = RIG_MODE_FM; break; case MODE_RTTY: *mode = RIG_MODE_RTTY; break; default: return -RIG_EINVAL; /* sorry, wrong mode */ break; } rig_debug(RIG_DEBUG_TRACE,"ft1000mp: mode = %s\n", strrmode(*mode)); /* TODO: set real IF filter selection */ *width = RIG_PASSBAND_NORMAL; return RIG_OK; } /* * set vfo and store requested vfo for later RIG_VFO_CURR * requests. * */ int ft1000mp_set_vfo(RIG *rig, vfo_t vfo) { struct rig_state *rig_s; struct ft1000mp_priv_data *p; unsigned char cmd_index = 0; /* index of sequence to send */ rig_debug(RIG_DEBUG_TRACE,"ft1000mp: ft1000mp_set_vfo called %s\n", strvfo(vfo)); p = (struct ft1000mp_priv_data*)rig->state.priv; rig_s = &rig->state; /* * RIG_VFO_VFO/RIG_VFO_MEM are not available * so try to emulate them. * looks like there's no RIG_VFO_MEM, maybe setting mem# * switch to it automatically? */ if (vfo == RIG_VFO_VFO) { vfo = p->current_vfo; } switch(vfo) { case RIG_VFO_A: cmd_index = FT1000MP_NATIVE_VFO_A; p->current_vfo = vfo; /* update active VFO */ rig_debug(RIG_DEBUG_TRACE,"ft1000mp: vfo == RIG_VFO_A\n"); break; case RIG_VFO_B: cmd_index = FT1000MP_NATIVE_VFO_B; p->current_vfo = vfo; /* update active VFO */ rig_debug(RIG_DEBUG_TRACE,"ft1000mp: vfo == RIG_VFO_B\n"); break; case RIG_VFO_CURR: /* do nothing, we're already at it! */ return RIG_OK; default: rig_debug(RIG_DEBUG_VERBOSE,"ft1000mp: Unknown default VFO %d\n", vfo); return -RIG_EINVAL; /* sorry, wrong VFO */ } /* * phew! now send cmd to rig */ ft1000mp_send_priv_cmd(rig,cmd_index); return RIG_OK; } /* * get vfo and store requested vfo for later RIG_VFO_CURR * requests. * */ int ft1000mp_get_vfo(RIG *rig, vfo_t *vfo) { struct ft1000mp_priv_data *p; int retval; rig_debug(RIG_DEBUG_VERBOSE,"ft1000mp: ft1000mp_get_vfo called\n"); p = (struct ft1000mp_priv_data*)rig->state.priv; /* Get flags for VFO status */ retval = ft1000mp_get_update_data(rig, FT1000MP_NATIVE_UPDATE, FT1000MP_STATUS_FLAGS_LENGTH); if (retval < 0) return retval; if (p->update_data[1] & 0x40) *vfo = RIG_VFO_MEM; else if (p->update_data[FT1000MP_SUMO_DISPLAYED_STATUS] & SF_VFOAB) *vfo = p->current_vfo = RIG_VFO_B; else *vfo = p->current_vfo = RIG_VFO_A; rig_debug(RIG_DEBUG_TRACE,"ft1000mp: vfo status = %x %x\n", p->update_data[0], p->update_data[1]); return RIG_OK; } /* * set_rit only support vfo = RIG_VFO_CURR */ int ft1000mp_set_rit(RIG *rig, vfo_t vfo, shortfreq_t rit) { struct rig_state *rs; struct ft1000mp_priv_data *priv; unsigned char *cmd; /* points to sequence to send */ rig_debug(RIG_DEBUG_TRACE,"ft1000mp: ft1000mp_set_rit called\n"); rs = &rig->state; priv = (struct ft1000mp_priv_data*)rs->priv; rig_debug(RIG_DEBUG_TRACE,"ft1000mp: requested freq = %li Hz \n", rit); /* * Copy native cmd freq_set to private cmd storage area */ memcpy(&priv->p_cmd,&ncmd[FT1000MP_NATIVE_RIT_ON].nseq,YAESU_CMD_LENGTH); to_bcd(priv->p_cmd, labs(rit)/10, 4); /* store bcd format in in p_cmd */ priv->p_cmd[2] = rit >= 0 ? 0x00 : 0xff; cmd = priv->p_cmd; /* get native sequence */ write_block(&rs->rigport, cmd, YAESU_CMD_LENGTH); return RIG_OK; } /* * Return RIT for a given VFO * */ int ft1000mp_get_rit(RIG *rig, vfo_t vfo, shortfreq_t *rit) { struct ft1000mp_priv_data *priv; unsigned char *p; shortfreq_t f; int cmd_index, len, retval; rig_debug(RIG_DEBUG_VERBOSE,"ft1000mp: ft1000mp_get_rit called\n"); priv = (struct ft1000mp_priv_data*)rig->state.priv; if (vfo == RIG_VFO_CURR) vfo = priv->current_vfo; if (vfo == RIG_VFO_A || vfo == RIG_VFO_B) { cmd_index = FT1000MP_NATIVE_VFO_UPDATE; len = 2*FT1000MP_STATUS_UPDATE_LENGTH; } else { /* RIG_VFO_CURR or RIG_VFO_MEM */ cmd_index = FT1000MP_NATIVE_CURR_VFO_UPDATE; len = FT1000MP_STATUS_UPDATE_LENGTH; } /* * get record from rig */ retval = ft1000mp_get_update_data(rig, cmd_index, len); if (retval < 0) return retval; if (vfo == RIG_VFO_B) p = &priv->update_data[FT1000MP_SUMO_VFO_B_CLAR]; else p = &priv->update_data[FT1000MP_SUMO_VFO_A_CLAR]; /* CURR_VFO has VFOA offset */ /* big endian integer, kinda */ if (p[0] & 0x80) f = (p[0]<<8) + p[1] - 65536; else f = (p[0]<<8) + p[1]; f = f*10/16; rig_debug(RIG_DEBUG_TRACE,"ft1000mp: freq = %lli Hz for VFO [%x]\n", f, vfo); *rit = f; /* return diplayed frequency */ return RIG_OK; } /* * set_xit only support vfo = RIG_VFO_CURR */ int ft1000mp_set_xit(RIG *rig, vfo_t vfo, shortfreq_t xit) { struct rig_state *rs; struct ft1000mp_priv_data *priv; unsigned char *cmd; /* points to sequence to send */ rig_debug(RIG_DEBUG_TRACE,"ft1000mp: ft1000mp_set_xit called\n"); rs = &rig->state; priv = (struct ft1000mp_priv_data*)rs->priv; rig_debug(RIG_DEBUG_TRACE,"ft1000mp: requested freq = %li Hz \n", xit); /* * Copy native cmd freq_set to private cmd storage area */ memcpy(&priv->p_cmd,&ncmd[FT1000MP_NATIVE_XIT_ON].nseq,YAESU_CMD_LENGTH); to_bcd(priv->p_cmd, labs(xit)/10, 4); /* store bcd format in in p_cmd */ priv->p_cmd[2] = xit >= 0 ? 0x00 : 0xff; cmd = priv->p_cmd; /* get native sequence */ write_block(&rs->rigport, cmd, YAESU_CMD_LENGTH); return RIG_OK; } /* * Return XIT for a given VFO * */ int ft1000mp_get_xit(RIG *rig, vfo_t vfo, shortfreq_t *xit) { struct ft1000mp_priv_data *priv; unsigned char *p; shortfreq_t f; int cmd_index, len, retval; rig_debug(RIG_DEBUG_VERBOSE,"ft1000mp: ft1000mp_get_xit called\n"); priv = (struct ft1000mp_priv_data*)rig->state.priv; if (vfo == RIG_VFO_CURR) vfo = priv->current_vfo; if (vfo == RIG_VFO_A || vfo == RIG_VFO_B) { cmd_index = FT1000MP_NATIVE_VFO_UPDATE; len = 2*FT1000MP_STATUS_UPDATE_LENGTH; } else { /* RIG_VFO_CURR or RIG_VFO_MEM */ cmd_index = FT1000MP_NATIVE_CURR_VFO_UPDATE; len = FT1000MP_STATUS_UPDATE_LENGTH; } /* * get record from rig */ retval = ft1000mp_get_update_data(rig, cmd_index, len); if (retval < 0) return retval; if (vfo == RIG_VFO_B) p = &priv->update_data[FT1000MP_SUMO_VFO_B_CLAR]; else p = &priv->update_data[FT1000MP_SUMO_VFO_A_CLAR]; /* CURR_VFO has VFOA offset */ /* big endian integer, kinda */ if (p[0] & 0x80) f = (p[0]<<8) + p[1] - 65536; else f = (p[0]<<8) + p[1]; f = f*10/16; rig_debug(RIG_DEBUG_TRACE,"ft1000mp: freq = %lli Hz for VFO [%x]\n", f, vfo); *xit = f; /* return diplayed frequency */ return RIG_OK; } int ft1000mp_get_level(RIG *rig, vfo_t vfo, setting_t level, value_t *val) { struct ft1000mp_priv_data *priv; struct rig_state *rs; unsigned char lvl_data[YAESU_CMD_LENGTH]; int m; int retval; rs = &rig->state; priv = (struct ft1000mp_priv_data*)rs->priv; /* Optimize: * sort the switch cases with the most frequent first */ switch (level) { case RIG_LEVEL_STRENGTH: if (vfo == RIG_VFO_CURR) vfo = priv->current_vfo; m = vfo == RIG_VFO_B ? 0x01 : 0x00; break; case RIG_LEVEL_RFPOWER: m = 0x80; break; case RIG_LEVEL_ALC: m = 0x81; break; case RIG_LEVEL_COMP: m = 0x83; break; case RIG_LEVEL_SWR: m = 0x85; break; case RIG_LEVEL_MICGAIN: /* not sure ... */ m = 0x86; break; case RIG_LEVEL_CWPITCH: m = 0xf1; break; case RIG_LEVEL_IF: /* not sure ... */ m = 0xf3; break; default: rig_debug(RIG_DEBUG_ERR,"Unsupported get_level %d", level); return -RIG_EINVAL; } memset(&priv->p_cmd, m, YAESU_CMD_LENGTH-1); priv->p_cmd[4] = 0xf7; write_block(&rs->rigport, priv->p_cmd, YAESU_CMD_LENGTH); retval = read_block(&rs->rigport, lvl_data, YAESU_CMD_LENGTH); if (retval != YAESU_CMD_LENGTH) { rig_debug(RIG_DEBUG_ERR,"ft1000mp_get_level: ack NG %d", retval); return retval; } switch (level) { case RIG_LEVEL_STRENGTH: val->i = rig_raw2val(lvl_data[0], &priv->str_cal); break; default: if (RIG_LEVEL_IS_FLOAT(level)) val->f = (float)lvl_data[0]/255; else val->i = lvl_data[0]; } rig_debug(RIG_DEBUG_TRACE,"ft1000mp_get_level: %d %d %f\n", lvl_data[0], val->i, val->f); return RIG_OK; } int ft1000mp_set_ptt(RIG *rig, vfo_t vfo, ptt_t ptt) { unsigned char cmd_index; /* index of sequence to send */ rig_debug(RIG_DEBUG_TRACE,"ft1000mp: ft1000mp_set_ptt called %d\n", ptt); cmd_index = ptt ? FT1000MP_NATIVE_PTT_ON : FT1000MP_NATIVE_PTT_OFF; ft1000mp_send_priv_cmd(rig,cmd_index); return RIG_OK; } /* * private helper function. Retrieves update data from rig. * using buffer indicated in *priv struct. * Extended to be command agnostic as 1000mp has several ways to * get data and several ways to return it. * * need to use this when doing ft1000mp_get_* stuff * * Variables: ci = command index, rl = read length of returned data * */ static int ft1000mp_get_update_data(RIG *rig, unsigned char ci, unsigned char rl) { struct rig_state *rig_s; struct ft1000mp_priv_data *p; int n; /* for read_ */ rig_debug(RIG_DEBUG_VERBOSE,"ft1000mp: ft1000mp_get_update_data called\n"); p = (struct ft1000mp_priv_data*)rig->state.priv; rig_s = &rig->state; /* send UPDATE comand to fetch data*/ ft1000mp_send_priv_cmd(rig, ci); n = read_block(&rig_s->rigport, p->update_data, rl); return n; } /* * private helper function to send a private command * sequence . Must only be complete sequences. * TODO: place variant of this in yaesu.c * */ static int ft1000mp_send_priv_cmd(RIG *rig, unsigned char ci) { struct rig_state *rig_s; struct ft1000mp_priv_data *p; unsigned char *cmd; /* points to sequence to send */ unsigned char cmd_index; /* index of sequence to send */ rig_debug(RIG_DEBUG_VERBOSE,"ft1000mp: ft1000mp_send_priv_cmd called\n"); p = (struct ft1000mp_priv_data*)rig->state.priv; rig_s = &rig->state; cmd_index = ci; /* get command */ if (! p->pcs[cmd_index].ncomp) { rig_debug(RIG_DEBUG_TRACE,"ft1000mp: Attempt to send incomplete sequence\n"); return -RIG_EINVAL; } cmd = (unsigned char *) p->pcs[cmd_index].nseq; /* get native sequence */ write_block(&rig_s->rigport, cmd, YAESU_CMD_LENGTH); return RIG_OK; }