Logo Search packages:      
Sourcecode: hamlib version File versions

ar3000.c

/*
 *  Hamlib AOR backend - AR3000 description
 *  Copyright (c) 2000-2005 by Stephane Fillod
 *
 *    $Id: ar3000.c,v 1.10 2006/10/07 21:10:11 csete 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.
 *
 */

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include <stdio.h>
#include <string.h>

#include <hamlib/rig.h>
#include <serial.h>
#include <misc.h>

#include "aor.h"

static int ar3k_set_freq(RIG *rig, vfo_t vfo, freq_t freq);
static int ar3k_get_freq(RIG *rig, vfo_t vfo, freq_t *freq);
static int ar3k_set_mode(RIG *rig, vfo_t vfo, rmode_t mode, pbwidth_t width);
static int ar3k_get_mode(RIG *rig, vfo_t vfo, rmode_t *mode, pbwidth_t *width);
static int ar3k_set_ts(RIG *rig, vfo_t vfo, shortfreq_t ts);
static int ar3k_get_ts(RIG *rig, vfo_t vfo, shortfreq_t *ts);
static int ar3k_set_mem(RIG *rig, vfo_t vfo, int ch);
static int ar3k_set_bank(RIG *rig, vfo_t vfo, int bank);
static int ar3k_set_level(RIG *rig, vfo_t vfo, setting_t level, value_t val);
static int ar3k_get_level(RIG *rig, vfo_t vfo, setting_t level, value_t *val);


#define AR3000A_MODES (RIG_MODE_AM|RIG_MODE_CW|RIG_MODE_SSB|RIG_MODE_FM|RIG_MODE_WFM)

#define AR3000A_FUNC_ALL (RIG_FUNC_MUTE|RIG_FUNC_SQL)

#define AR3000A_LEVEL (RIG_LEVEL_ATT|RIG_LEVEL_RAWSTR)

#define AR3000A_VFO_OPS (RIG_OP_NONE)

#define AR3000A_VFO (RIG_VFO_A)

#define AR3000A_STR_CAL { 3, \
      { \
            { '%', -60 }, /* mute */ \
            { 'A', -54 }, /* S1 */  \
            { 'P', 20 }   /* +20 */ \
      } }

/*
 * AR3000A rig capabilities.
 *
 * info coming from A3000A pdf manual from http://www.aoruk.com/
 *
 * TODO:
 * set_channel, get_channel, set_func MUTE,SQL, get_dcd, ...
 */
const struct rig_caps ar3000a_caps = {
.rig_model =  RIG_MODEL_AR3000A,
.model_name = "AR3000A",
.mfg_name =  "AOR",
.version =  "0.5",
.copyright =  "LGPL",
.status =  RIG_STATUS_BETA,
.rig_type =  RIG_TYPE_SCANNER,
.ptt_type =  RIG_PTT_NONE,
.dcd_type =  RIG_DCD_NONE,
.port_type =  RIG_PORT_SERIAL,
.serial_rate_min =  4800,
.serial_rate_max =  9600,
.serial_data_bits =  8,
.serial_stop_bits =  2,
.serial_parity =  RIG_PARITY_NONE,
.serial_handshake =  RIG_HANDSHAKE_HARDWARE,
.write_delay =  0,
.post_write_delay =  0,
.timeout =  200,
.retry =  3,
.has_get_func =  RIG_FUNC_NONE,
.has_set_func =  AR3000A_FUNC_ALL,
.has_get_level =  AR3000A_LEVEL,
.has_set_level =  RIG_LEVEL_SET(AR3000A_LEVEL),
.has_get_parm =  RIG_PARM_NONE,
.has_set_parm =  RIG_PARM_NONE,
.level_gran =  {},                 /* FIXME: granularity */
.parm_gran =  {},
.ctcss_list =  NULL,
.dcs_list =  NULL,
.preamp =   { RIG_DBLST_END, },
.attenuator =   { 20, RIG_DBLST_END, },   /* TBC */
.max_rit =  Hz(0),
.max_xit =  Hz(0),
.max_ifshift =  Hz(0),
.targetable_vfo =  0,
.transceive =  RIG_TRN_OFF,
.bank_qty =   4,
.chan_desc_sz =  0,
.vfo_ops =  AR3000A_VFO_OPS,

.chan_list =  { RIG_CHAN_END, },    /* FIXME: memory channel list: 4x100 memories */

.rx_range_list1 =  {
      {kHz(100),MHz(2036),AR3000A_MODES,-1,-1,AR3000A_VFO},
      RIG_FRNG_END,
      },
.tx_range_list1 =  { RIG_FRNG_END, },

.rx_range_list2 =  {
      {kHz(100),MHz(2036),AR3000A_MODES,-1,-1,AR3000A_VFO},
      RIG_FRNG_END,
  }, /* rx range */
.tx_range_list2 =  { RIG_FRNG_END, },     /* no tx range, this is a scanner! */

.tuning_steps =  {
       {AR3000A_MODES,50},
       {AR3000A_MODES,kHz(999.95)},
#if 0 
       {AR3000A_MODES,0},     /* any tuning step */
#endif
       RIG_TS_END,
      },
        /* mode/filter list, .remember =  order matters! */
.filters =  {
        /* mode/filter list, .remember =  order matters! */
            {RIG_MODE_SSB|RIG_MODE_CW, kHz(2.4)}, 
            {RIG_MODE_FM|RIG_MODE_AM, kHz(12)}, 
            {RIG_MODE_WFM, kHz(180)},
            RIG_FLT_END,
      },

.str_cal = AR3000A_STR_CAL,
.priv =  NULL,
.rig_init =  NULL,
.rig_cleanup =  NULL,
.rig_open =  NULL,
.rig_close =  NULL,

.set_freq =  ar3k_set_freq,
.get_freq =  ar3k_get_freq,
.set_mode =  ar3k_set_mode,
.get_mode =  ar3k_get_mode,

.set_ts =  ar3k_set_ts,
.get_ts =  ar3k_get_ts,
.set_mem = ar3k_set_mem,
.set_bank = ar3k_set_bank,

.set_level = ar3k_set_level,
.get_level = ar3k_get_level,

};

/*
 * Function definitions below
 */




/*
 * acknowledge is CR
 * Is \r portable enough?
 */
#define CR '\r'
#define EOM "\x0a\x0d"

#define BUFSZ 64

/*
 * ar3k_transaction
 * We assume that rig!=NULL, rig->state!= NULL
 * Otherwise, you'll get a nice seg fault. You've been warned!
 * return value: RIG_OK if everything's fine, negative value otherwise
 * TODO: error case handling
 */
static int ar3k_transaction(RIG *rig, const char *cmd, int cmd_len, char *data, int *data_len)
{
      int retval;
      struct rig_state *rs;

      rs = &rig->state;

      serial_flush(&rs->rigport);

      retval = write_block(&rs->rigport, cmd, cmd_len);
      if (retval != RIG_OK)
            return retval;

      /* will flush data on next transaction */
      if (!data || !data_len)
            return RIG_OK;

      retval = read_string(&rs->rigport, data, BUFSZ, EOM, strlen(EOM));
      if (retval == -RIG_ETIMEOUT)
            retval = 0;
      if (retval < 0)
            return retval;

      *data_len = retval;

      return RIG_OK;
}

/*
 * ar3k_set_freq
 * Assumes rig!=NULL
 */
int ar3k_set_freq(RIG *rig, vfo_t vfo, freq_t freq)
{
      char freqbuf[BUFSZ];
      int freq_len, retval;
      unsigned lowhz;

      /*
       * actually, frequency must be like nnnn.nnnnm, 
       * where m must be 0 or 5 (for 50Hz).
       */
      lowhz = ((unsigned)freq) % 100;
      freq /= 100;
      if (lowhz < 25)
            lowhz = 0;
      else if (lowhz < 75)
            lowhz = 50;
      else 
            lowhz = 100;
      freq = freq*100 + lowhz;

      freq_len = sprintf(freqbuf,"%04.5f" EOM, ((double)freq)/MHz(1));

      retval = ar3k_transaction (rig, freqbuf, freq_len, NULL, NULL);
      if (retval != RIG_OK)
            return retval;

      return RIG_OK;
}

/*
 * ar3k_get_freq
 * Assumes rig!=NULL, freq!=NULL
 */
int ar3k_get_freq(RIG *rig, vfo_t vfo, freq_t *freq)
{
      char *rfp;
      int freq_len, retval;
      char freqbuf[BUFSZ];

      /*
       * #--J0WZ-----Y---------Q
       *      X                R,S,T,U,V
       */
      retval = ar3k_transaction (rig, "D" EOM, 3, freqbuf, &freq_len);
      if (retval != RIG_OK)
            return retval;

      rfp = strchr(freqbuf, 'Y');
      if (!rfp)
            return -RIG_EPROTO;
      sscanf(rfp+1,"%"SCNfreq, freq);
      *freq *= 10;

      return RIG_OK;
}

/*
 * ar3k_set_mode
 * Assumes rig!=NULL
 */
int ar3k_set_mode(RIG *rig, vfo_t vfo, rmode_t mode, pbwidth_t width)
{
      char mdbuf[BUFSZ];
      int mdbuf_len, aormode, retval;

      switch (mode) {
      case RIG_MODE_AM:       aormode = 'A'; break;
      case RIG_MODE_CW:       aormode = 'C'; break;
      case RIG_MODE_USB:      aormode = 'U'; break;
      case RIG_MODE_LSB:      aormode = 'L'; break;
      case RIG_MODE_WFM:      aormode = 'W'; break;
      case RIG_MODE_FM: aormode = 'N'; break;
      default:
            rig_debug(RIG_DEBUG_ERR,"ar3k_set_mode: unsupported mode %d\n",
                                    mode);
            return -RIG_EINVAL;
      }

      mdbuf_len = sprintf(mdbuf, "%c" EOM, aormode);
      retval = ar3k_transaction (rig, mdbuf, mdbuf_len, NULL, NULL);

      return retval;
}

/*
 * ar3k_get_mode
 * Assumes rig!=NULL, mode!=NULL
 */
int ar3k_get_mode(RIG *rig, vfo_t vfo, rmode_t *mode, pbwidth_t *width)
{
      char *rfp;
      int buf_len, retval;
      char buf[BUFSZ];

      /*
       * #--J0WZ-----Y---------Q
       *      X                R,S,T,U,V
       */
      retval = ar3k_transaction (rig, "D" EOM, 3, buf, &buf_len);
      if (retval != RIG_OK)
            return retval;

      rfp = strchr(buf, 'Y');
      if (!rfp)
            return -RIG_EPROTO;
      rfp += 11;

      switch (*rfp) {
      case 'Q':   *mode = RIG_MODE_FM; break;
      case 'R':   *mode = RIG_MODE_WFM; break;
      case 'S':   *mode = RIG_MODE_AM; break;
      case 'T':   *mode = RIG_MODE_LSB; break;
      case 'U':   *mode = RIG_MODE_USB; break;
      case 'V':   *mode = RIG_MODE_CW; break;
      default:
            rig_debug(RIG_DEBUG_ERR,"ar3k_get_mode: unsupported mode '%c'\n",
                                          *rfp);
            return -RIG_EPROTO;
      }
      *width = rig_passband_normal(rig, *mode);

      return RIG_OK;
}

/*
 * ar3k_set_ts
 * Assumes rig!=NULL
 */
int ar3k_set_ts(RIG *rig, vfo_t vfo, shortfreq_t ts)
{
      char freqbuf[BUFSZ];
      int freq_len, retval;
      int lowhz;

      /*
       * actually, frequency must be like nnn.nm, 
       * where m must be 0 or 5 (for 50Hz).
       */
      lowhz = ts % 100;
      ts /= 100;
      if (lowhz < 25)
            lowhz = 0;
      else if (lowhz < 75)
            lowhz = 50;
      else 
            lowhz = 100;
      ts = ts*100 + lowhz;

      freq_len = sprintf(freqbuf,"%03.2fS" EOM, ((double)ts)/kHz(1));

      retval = ar3k_transaction (rig, freqbuf, freq_len, NULL, NULL);
      if (retval != RIG_OK)
            return retval;

      return RIG_OK;
}

/*
 * ar3k_get_ts
 * Assumes rig!=NULL, ts!=NULL
 */
int ar3k_get_ts(RIG *rig, vfo_t vfo, shortfreq_t *ts)
{
      char *rfp;
      int freq_len, retval;
      char freqbuf[BUFSZ];

      /*
       * #--J0WZ-----Y---------Q
       *      X                R,S,T,U,V
       */
      retval = ar3k_transaction (rig, "D" EOM, 3, freqbuf, &freq_len);
      if (retval != RIG_OK)
            return retval;

      rfp = strchr(freqbuf, 'Z');
      if (!rfp)
            return -RIG_EPROTO;
      sscanf(rfp+1,"%ld", ts);
      *ts *= 10;

      return RIG_OK;
}


int ar3k_set_mem(RIG *rig, vfo_t vfo, int ch)
{
      char cmdbuf[BUFSZ];
      int cmd_len, retval;

      cmd_len = sprintf(cmdbuf, "%02dM" EOM, ch);
      retval = ar3k_transaction (rig, cmdbuf, cmd_len, NULL, NULL);

      return retval;
}

int ar3k_set_bank(RIG *rig, vfo_t vfo, int bank)
{
      char cmdbuf[BUFSZ];
      int cmd_len, retval;

      cmd_len = sprintf(cmdbuf, "%dX" EOM, bank);
      retval = ar3k_transaction (rig, cmdbuf, cmd_len, NULL, NULL);

      return retval;
}


int ar3k_set_level(RIG *rig, vfo_t vfo, setting_t level, value_t val)
{
      char *cmd;
      int retval;

      switch(level) {
      case RIG_LEVEL_ATT:
            cmd = val.i ? "R" EOM : "T" EOM;
            break;
      default:
            return -RIG_EINVAL;
      }

      retval = ar3k_transaction (rig, cmd, strlen(cmd), NULL, NULL);
      if (retval != RIG_OK)
            return retval;

      return RIG_OK;
}

int ar3k_get_level(RIG *rig, vfo_t vfo, setting_t level, value_t *val)
{
      int info_len, retval;
      char infobuf[BUFSZ];

      switch(level) {
      case RIG_LEVEL_ATT:
            /*
            * #--J0WZ-----Y---------Q
            *      X                R,S,T,U,V
            */
            retval = ar3k_transaction (rig, "D" EOM, 3, infobuf, &info_len);
            if (retval != RIG_OK)
                  return retval;

            val->i = strchr(infobuf, 'W') ? rig->caps->attenuator[1] : 0;
            return RIG_OK;

      case RIG_LEVEL_RAWSTR:
            retval = ar3k_transaction (rig, "Y" EOM, 3, infobuf, &info_len);
            if (retval != RIG_OK)
                  return retval;

            val->i = infobuf[0];
            return RIG_OK;

      default:
            return -RIG_EINVAL;
      }

      return RIG_OK;
}


Generated by  Doxygen 1.6.0   Back to index