From 8bf9bbb375e57776d7d93515d4a9ca23d3a9a491 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Fillod=2C=20F8CFE?= Date: Wed, 5 Jan 2011 21:59:48 +0000 Subject: [PATCH] Skeleton for IC-E92D model. Let icom generic transaction routines to work with true full duplex and alternate controler ID. git-svn-id: https://hamlib.svn.sourceforge.net/svnroot/hamlib/trunk@3017 7ae35d74-ebe9-4afe-98af-79ac388436b8 --- icom/Makefile.am | 2 +- icom/frame.c | 129 +++++++++++++------------ icom/frame.h | 6 +- icom/ic92d.c | 243 +++++++++++++++++++++++++++++++++++++++++++++++ icom/icom.c | 9 +- icom/icom.h | 2 + 6 files changed, 320 insertions(+), 71 deletions(-) create mode 100644 icom/ic92d.c diff --git a/icom/Makefile.am b/icom/Makefile.am index a2a90756f..59fd68986 100644 --- a/icom/Makefile.am +++ b/icom/Makefile.am @@ -1,7 +1,7 @@ ICOMSRCLIST = ic706.c icr8500.c ic735.c ic775.c ic756.c \ ic275.c ic475.c ic820h.c ic821h.c \ icr7000.c ic910.c ic970.c ic725.c ic737.c ic718.c \ - os535.c os456.c omni.c delta2.c \ + os535.c os456.c omni.c delta2.c ic92d.c \ ic736.c ic738.c ic746.c ic703.c ic726.c ic271.c \ ic765.c ic781.c ic471.c id1.c icr9000.c \ icr10.c icr20.c icr71.c icr72.c icr75.c \ diff --git a/icom/frame.c b/icom/frame.c index 897aad502..ab59650e3 100644 --- a/icom/frame.c +++ b/icom/frame.c @@ -1,8 +1,7 @@ /* * Hamlib CI-V backend - low level communication routines - * Copyright (c) 2000-2006 by Stephane Fillod + * Copyright (c) 2000-2010 by Stephane Fillod * - * $Id: frame.c,v 1.35 2008-11-09 15:17:49 y32kn 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 @@ -48,10 +47,8 @@ * * NB: the frame array must be big enough to hold the frame. * The smallest frame is 6 bytes, the biggest is at least 13 bytes. - * - * TODO: inline the function? */ -int make_cmd_frame(char frame[], char re_id, char cmd, int subcmd, const unsigned char *data, int data_len) +int make_cmd_frame(char frame[], char re_id, char ctrl_id, char cmd, int subcmd, const unsigned char *data, int data_len) { int i = 0; @@ -61,7 +58,7 @@ int make_cmd_frame(char frame[], char re_id, char cmd, int subcmd, const unsigne frame[i++] = PR; /* Preamble code */ frame[i++] = PR; frame[i++] = re_id; - frame[i++] = CTRLID; + frame[i++] = ctrl_id; frame[i++] = cmd; if (subcmd != -1) { #ifdef MULTIB_SUBCMD @@ -99,16 +96,21 @@ int make_cmd_frame(char frame[], char re_id, char cmd, int subcmd, const unsigne int icom_one_transaction (RIG *rig, int cmd, int subcmd, const unsigned char *payload, int payload_len, unsigned char *data, int *data_len) { struct icom_priv_data *priv; + const struct icom_priv_caps *priv_caps; struct rig_state *rs; unsigned char buf[MAXFRAMELEN]; unsigned char sendbuf[MAXFRAMELEN]; int frm_len, retval; + int ctrl_id; rs = &rig->state; priv = (struct icom_priv_data*)rs->priv; + priv_caps = (struct icom_priv_caps*)rig->caps->priv; - frm_len = make_cmd_frame((char *) sendbuf, priv->re_civ_addr, cmd, subcmd, - payload, payload_len); + ctrl_id = priv_caps->serial_full_duplex == 0 ? CTRLID : 0x80; + + frm_len = make_cmd_frame((char *) sendbuf, priv->re_civ_addr, ctrl_id, cmd, + subcmd, payload, payload_len); /* * should check return code and that write wrote cmd_len chars! @@ -123,61 +125,64 @@ int icom_one_transaction (RIG *rig, int cmd, int subcmd, const unsigned char *pa return retval; } - /* - * read what we just sent, because TX and RX are looped, - * and discard it... - * - if what we read is not what we sent, then it means - * a collision on the CI-V bus occured! - * - if we get a timeout, then retry to send the frame, - * up to rs->retry times. - */ + if (priv_caps->serial_full_duplex == 0) { - retval = read_icom_frame(&rs->rigport, buf); - if (retval == -RIG_ETIMEOUT || retval == 0) - { - /* Nothing recieved, CI-V interface is not echoing */ - Unhold_Decode(rig); - return -RIG_BUSERROR; - } - if (retval < 0) - { - /* Other error, return it */ - Unhold_Decode(rig); - return retval; - } - - switch (buf[retval-1]) - { - case COL: - /* Collision */ - Unhold_Decode(rig); - return -RIG_BUSBUSY; - case FI: - /* Ok, normal frame */ - break; - default: - /* Timeout after reading at least one character */ - /* Problem on ci-v bus? */ - Unhold_Decode(rig); - return -RIG_BUSERROR; - } - - if (retval != frm_len) - { - /* Not the same length??? */ - /* Problem on ci-v bus? */ - /* Someone else got a packet in? */ - Unhold_Decode(rig); - return -RIG_EPROTO; - } - if (memcmp(buf,sendbuf,frm_len)) - { - /* Frames are different? */ - /* Problem on ci-v bus? */ - /* Someone else got a packet in? */ - Unhold_Decode(rig); - return -RIG_EPROTO; - } + /* + * read what we just sent, because TX and RX are looped, + * and discard it... + * - if what we read is not what we sent, then it means + * a collision on the CI-V bus occured! + * - if we get a timeout, then retry to send the frame, + * up to rs->retry times. + */ + + retval = read_icom_frame(&rs->rigport, buf); + if (retval == -RIG_ETIMEOUT || retval == 0) + { + /* Nothing recieved, CI-V interface is not echoing */ + Unhold_Decode(rig); + return -RIG_BUSERROR; + } + if (retval < 0) + { + /* Other error, return it */ + Unhold_Decode(rig); + return retval; + } + + switch (buf[retval-1]) + { + case COL: + /* Collision */ + Unhold_Decode(rig); + return -RIG_BUSBUSY; + case FI: + /* Ok, normal frame */ + break; + default: + /* Timeout after reading at least one character */ + /* Problem on ci-v bus? */ + Unhold_Decode(rig); + return -RIG_BUSERROR; + } + + if (retval != frm_len) + { + /* Not the same length??? */ + /* Problem on ci-v bus? */ + /* Someone else got a packet in? */ + Unhold_Decode(rig); + return -RIG_EPROTO; + } + if (memcmp(buf,sendbuf,frm_len)) + { + /* Frames are different? */ + /* Problem on ci-v bus? */ + /* Someone else got a packet in? */ + Unhold_Decode(rig); + return -RIG_EPROTO; + } + } /* * expect an answer? diff --git a/icom/frame.h b/icom/frame.h index b06f261f3..e192feb65 100644 --- a/icom/frame.h +++ b/icom/frame.h @@ -1,8 +1,7 @@ /* * Hamlib CI-V backend - low level communication header - * Copyright (c) 2000-2005 by Stephane Fillod + * Copyright (c) 2000-2010 by Stephane Fillod * - * $Id: frame.h,v 1.16 2006-09-22 19:55:58 n0nb 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 @@ -28,7 +27,7 @@ /* * helper functions */ -int make_cmd_frame(char frame[], char re_id, char cmd, int subcmd, const unsigned char *data, int data_len); +int make_cmd_frame(char frame[], char re_id, char ctrl_id, char cmd, int subcmd, const unsigned char *data, int data_len); int icom_transaction (RIG *rig, int cmd, int subcmd, const unsigned char *payload, int payload_len, unsigned char *data, int *data_len); int read_icom_frame(hamlib_port_t *p, unsigned char rxbuffer[]); @@ -37,4 +36,3 @@ int rig2icom_mode(RIG *rig, rmode_t mode, pbwidth_t width, unsigned char *md, si void icom2rig_mode(RIG *rig, unsigned char md, int pd, rmode_t *mode, pbwidth_t *width); #endif /* _FRAME_H */ - diff --git a/icom/ic92d.c b/icom/ic92d.c new file mode 100644 index 000000000..93dbe3134 --- /dev/null +++ b/icom/ic92d.c @@ -0,0 +1,243 @@ +/* + * Hamlib CI-V backend - description of IC-E92D/IC-92AD and variations + * Copyright (c) 2000-2010 by Stephane Fillod + * + * + * 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. + * + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +#include "hamlib/rig.h" +#include "idx_builtin.h" +#include "icom.h" +#include "frame.h" +#include "icom_defs.h" + +/* TODO: DV (GMSK 4.8 kbps voice) */ +#define IC92D_MODES (RIG_MODE_FM) +#define IC92D_MODES_TX (RIG_MODE_AM|RIG_MODE_FM|RIG_MODE_WFM) + +#define IC92D_FUNC_ALL (RIG_FUNC_MUTE|RIG_FUNC_MON|RIG_FUNC_TONE|RIG_FUNC_TSQL|RIG_FUNC_LOCK|RIG_FUNC_AFC) + +#define IC92D_LEVEL_ALL (RIG_LEVEL_AF|RIG_LEVEL_SQL|RIG_LEVEL_RFPOWER|RIG_LEVEL_PREAMP|RIG_LEVEL_ATT|RIG_LEVEL_RAWSTR) + +#define IC92D_PARM_ALL (RIG_PARM_BEEP|RIG_PARM_BACKLIGHT) + +#define IC92D_VFO_ALL (RIG_VFO_A|RIG_VFO_B|RIG_VFO_MEM) + +#define IC92D_VFO_OPS (RIG_OP_FROM_VFO|RIG_OP_TO_VFO|RIG_OP_MCL) +#define IC92D_SCAN_OPS (RIG_SCAN_VFO|RIG_SCAN_MEM) + +/* + * FIXME: real measurement + */ +#define IC92D_STR_CAL UNKNOWN_IC_STR_CAL + +/* FIXME */ +#define IC92D_MEM_CAP { \ + .freq = 1, \ + .mode = 1, \ + .width = 1, \ + .rptr_offs = 1, \ + .rptr_shift = 1, \ + .funcs = IC92D_FUNC_ALL, \ + .levels = RIG_LEVEL_SET(IC92D_LEVEL_ALL), \ +} + +static const char *ic92d_get_info(RIG *rig); + +/* FIXME: tuning step sub-commands */ +const struct ts_sc_list ic92d_ts_sc_list[] = { + { kHz(5), 0x00 }, + { kHz(6.25), 0x01 }, + { kHz(8.33), 0x02 }, + { kHz(9), 0x03 }, + { kHz(10), 0x04 }, + { kHz(12.5), 0x05 }, + { kHz(15), 0x06 }, + { kHz(20), 0x07 }, + { kHz(25), 0x08 }, + { kHz(30), 0x09 }, + { kHz(50), 0x0a }, + { kHz(100), 0x0b }, + { kHz(125), 0x0c }, + { kHz(200), 0x0d }, + { 0, 0 }, +}; + + +/* + */ +static const struct icom_priv_caps ic92d_priv_caps = { + 0x01, /* default address */ + 0, /* 731 mode */ + ic92d_ts_sc_list, + .serial_full_duplex = 1 +}; + +const struct rig_caps ic92d_caps = { +.rig_model = RIG_MODEL_IC92D, +.model_name = "IC-92D", /* IC-E92D/IC-92AD */ +.mfg_name = "Icom", +.version = BACKEND_VER, +.copyright = "LGPL", +.status = RIG_STATUS_UNTESTED, +.rig_type = RIG_TYPE_HANDHELD, +.ptt_type = RIG_PTT_NONE, +.dcd_type = RIG_DCD_NONE, +.port_type = RIG_PORT_SERIAL, +.serial_rate_min = 38400, +.serial_rate_max = 38400, +.serial_data_bits = 8, +.serial_stop_bits = 1, +.serial_parity = RIG_PARITY_NONE, +.serial_handshake = RIG_HANDSHAKE_NONE, +.write_delay = 0, +.post_write_delay = 0, +.timeout = 200, +.retry = 3, +.has_get_func = IC92D_FUNC_ALL, +.has_set_func = IC92D_FUNC_ALL, +.has_get_level = IC92D_LEVEL_ALL, +.has_set_level = RIG_LEVEL_SET(IC92D_LEVEL_ALL), +.has_get_parm = IC92D_PARM_ALL, +.has_set_parm = IC92D_PARM_ALL, +.level_gran = { + [LVL_RAWSTR] = { .min = { .i = 0 }, .max = { .i = 255 } }, +}, +.parm_gran = {}, +.ctcss_list = common_ctcss_list, +.dcs_list = full_dcs_list, +.preamp = { RIG_DBLST_END, }, +.attenuator = { 10, RIG_DBLST_END, }, +.max_rit = Hz(0), +.max_xit = Hz(0), +.max_ifshift = Hz(0), +.targetable_vfo = 0, +.vfo_ops = IC92D_VFO_OPS, +.scan_ops = IC92D_SCAN_OPS, +.transceive = RIG_TRN_OFF, +.bank_qty = 26, +.chan_desc_sz = 8, + + /* The IC-E92D has a total 1304 memory channels with 26 memory banks. + * The VFO A has 800 regular channels, 50 scan edges and 2 call channels, + * while the VFO B has 400 regular, 50 scan edges and 2 call channels. + */ +.chan_list = { + { 1,1200, RIG_MTYPE_MEM, IC92D_MEM_CAP }, + { 1201,1300, RIG_MTYPE_EDGE, IC92D_MEM_CAP }, + { 1301,1304, RIG_MTYPE_CALL, IC92D_MEM_CAP }, + RIG_CHAN_END, + }, + + /* IC-E92D */ +.rx_range_list1 = { + {kHz(495),MHz(999.99),RIG_MODE_AM|RIG_MODE_FM|RIG_MODE_WFM,-1,-1,RIG_VFO_A}, + {MHz(118),MHz(174),RIG_MODE_AM|RIG_MODE_FM,-1,-1,RIG_VFO_B}, // TODO: MODE_DV + {MHz(350),MHz(470),RIG_MODE_AM|RIG_MODE_FM,-1,-1,RIG_VFO_B}, // TODO: MODE_DV + RIG_FRNG_END, }, +.tx_range_list1 = { + {MHz(144),MHz(146)-1,IC92D_MODES_TX,mW(100),W(5),IC92D_VFO_ALL}, + {MHz(430),MHz(440)-1,IC92D_MODES_TX,mW(100),W(5),IC92D_VFO_ALL}, + RIG_FRNG_END, }, + + /* IC-92AD */ +.rx_range_list2 = { + {kHz(495),MHz(999.99),RIG_MODE_AM|RIG_MODE_FM|RIG_MODE_WFM,-1,-1,RIG_VFO_A}, + {MHz(118),MHz(174),RIG_MODE_AM|RIG_MODE_FM,-1,-1,RIG_VFO_B}, // TODO: MODE_DV + {MHz(350),MHz(470),RIG_MODE_AM|RIG_MODE_FM,-1,-1,RIG_VFO_B}, // TODO: MODE_DV + RIG_FRNG_END, }, +.tx_range_list2 = { + {MHz(144),MHz(148)-1,IC92D_MODES_TX,mW(100),W(5),IC92D_VFO_ALL}, + {MHz(430),MHz(440)-1,IC92D_MODES_TX,mW(100),W(5),IC92D_VFO_ALL}, + RIG_FRNG_END, }, + +.tuning_steps = { + {IC92D_MODES,kHz(5)}, + {IC92D_MODES,kHz(6.25)}, + {IC92D_MODES,kHz(8.33)}, + {IC92D_MODES,kHz(9)}, + {IC92D_MODES,kHz(10)}, + {IC92D_MODES,12500}, + {IC92D_MODES,kHz(15)}, + {IC92D_MODES,kHz(20)}, + {IC92D_MODES,kHz(25)}, + {IC92D_MODES,kHz(50)}, + {IC92D_MODES,kHz(100)}, + {IC92D_MODES,kHz(125)}, + {IC92D_MODES,kHz(200)}, + RIG_TS_END, + }, + /* FIXME: mode/filter list, remember: order matters! */ +.filters = { + {RIG_MODE_FM, kHz(12)}, + {RIG_MODE_FM|RIG_MODE_AM, kHz(9)}, /* N-FM & AM */ + {RIG_MODE_WFM, kHz(230)}, + RIG_FLT_END, + }, +.str_cal = IC92D_STR_CAL, + +.cfgparams = icom_cfg_params, +.set_conf = icom_set_conf, +.get_conf = icom_get_conf, + +.priv = (void*)&ic92d_priv_caps, +.rig_init = icom_init, +.rig_cleanup = icom_cleanup, +.rig_open = NULL, +.rig_close = NULL, + +.get_info = ic92d_get_info, + +}; + +const char *ic92d_get_info(RIG *rig) +{ + struct icom_priv_data *priv; + struct rig_state *rs; + unsigned char ackbuf[16]; + int ack_len, retval; + static char info[64]; + + rs = &rig->state; + priv = (struct icom_priv_data*)rs->priv; + + // 018019fd + + priv->re_civ_addr = 0x01; + + retval = icom_transaction (rig, C_RD_TRXID, -1, + NULL, 0, ackbuf, &ack_len); + if (retval != RIG_OK) + return NULL; + + if (ack_len <= 3) { + rig_debug(RIG_DEBUG_ERR,"%s: ack NG (%#.2x), " + "len=%d\n", __func__, ackbuf[0], ack_len); + return NULL; + } + + sprintf(info, "ID %02x%02x%02x\n", ackbuf[1], ackbuf[2], ackbuf[3]); + + return info; +} + diff --git a/icom/icom.c b/icom/icom.c index a3a0f4505..bdad1370b 100644 --- a/icom/icom.c +++ b/icom/icom.c @@ -2999,8 +2999,8 @@ DECLARE_PROBERIG_BACKEND(icom) */ for (civ_addr=0x01; civ_addr<=0x7f; civ_addr++) { - frm_len = make_cmd_frame((char *) buf, civ_addr, C_RD_TRXID, S_RD_TRXID, - NULL, 0); + frm_len = make_cmd_frame((char *) buf, civ_addr, CTRLID, + C_RD_TRXID, S_RD_TRXID, NULL, 0); serial_flush(port); write_block(port, (char *) buf, frm_len); @@ -3058,8 +3058,8 @@ DECLARE_PROBERIG_BACKEND(icom) */ for (civ_addr=0x80; civ_addr<=0x8f; civ_addr++) { - frm_len = make_cmd_frame((char *) buf, civ_addr, C_CTL_MISC, S_OPTO_RDID, - NULL, 0); + frm_len = make_cmd_frame((char *) buf, civ_addr, CTRLID, + C_CTL_MISC, S_OPTO_RDID, NULL, 0); serial_flush(port); write_block(port, (char *) buf, frm_len); @@ -3177,6 +3177,7 @@ DECLARE_INITRIG_BACKEND(icom) rig_register(&omnivip_caps); rig_register(&delta2_caps); + rig_register(&ic92d_caps); rig_register(&id1_caps); return RIG_OK; diff --git a/icom/icom.h b/icom/icom.h index 99cfaf87e..17fe6efc8 100644 --- a/icom/icom.h +++ b/icom/icom.h @@ -108,6 +108,7 @@ struct icom_priv_caps { to convert response tokens to bandwidth and mode */ + int serial_full_duplex; /*!< Whether RXD&TXD are not tied together */ }; @@ -238,6 +239,7 @@ extern const struct rig_caps delta2_caps; extern const struct rig_caps os456_caps; extern const struct rig_caps os535_caps; +extern const struct rig_caps ic92d_caps; extern const struct rig_caps id1_caps; #endif /* _ICOM_H */