Logo Search packages:      
Sourcecode: hamlib version File versions  Download package

sdr1k.c

/*
 *  Hamlib backend - SDR-1000
 *  Copyright (c) 2003-2007 by Stephane Fillod
 *
 *    $Id: sdr1k.c,v 1.11 2008/10/26 13:35:41 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
 *   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 <stdlib.h>
#include <string.h>  /* String function definitions */
#include <unistd.h>  /* UNIX standard function definitions */
#include <math.h>

#include "hamlib/rig.h"
#include "parallel.h"
#include "misc.h"
#include "bandplan.h"
#include "register.h"

#include "flexradio.h"

static int sdr1k_set_freq(RIG *rig, vfo_t vfo, freq_t freq);
static int sdr1k_get_freq(RIG *rig, vfo_t vfo, freq_t *freq);
static int sdr1k_reset(RIG *rig, reset_t reset);
static int sdr1k_init(RIG *rig);
static int sdr1k_open(RIG *rig);
static int sdr1k_close(RIG *rig);
static int sdr1k_cleanup(RIG *rig);
static int sdr1k_set_ptt (RIG *rig, vfo_t vfo, ptt_t ptt);
static int sdr1k_set_level (RIG *rig, vfo_t vfo, setting_t level, value_t val);

typedef enum { L_EXT = 0, L_BAND = 1, L_DDS0 = 2, L_DDS1 = 3 } latch_t;

#define TR  0x40
#define MUTE      0x80
#define GAIN      0x80
#define WRB 0x40
#define RESET     0x80

/* DDS Control Constants */
#define COMP_PD         0x10  /* DDS Comparator power down */
#define DIG_PD          0x01  /* DDS Digital Power down */
#define BYPASS_PLL      0x20  /* Bypass DDS PLL */
#define INT_IOUD  0x01  /* Internal IO Update */
#define OSK_EN          0x20  /* Offset Shift Keying enable */
#define OSK_INT         0x10  /* Offset Shift Keying */
#define BYPASS_SINC     0x40  /* Bypass Inverse Sinc Filter */
#define PLL_RANGE 0x40  /* Set PLL Range */

static int write_latch (RIG *rig, latch_t which, unsigned value, unsigned mask);
static int dds_write_reg (RIG *rig, unsigned addr, unsigned data);
static int set_bit (RIG *rig, latch_t reg, unsigned bit, unsigned state);


#define DEFAULT_XTAL MHz(200)
#define DEFAULT_PLL_MULT 1
#define DEFAULT_DAC_MULT 4095

struct sdr1k_priv_data {
  unsigned  shadow[4];  /* shadow latches */
  freq_t    dds_freq;   /* current freq */
  freq_t    xtal;       /* base XTAL */
  int pll_mult;         /* PLL mult */
};


#define SDR1K_FUNC  RIG_FUNC_MUTE
#define SDR1K_LEVEL RIG_LEVEL_PREAMP
#define SDR1K_PARM  RIG_PARM_NONE

#define SDR1K_MODES (RIG_MODE_NONE)

#define SDR1K_VFO RIG_VFO_A

#define SDR1K_ANTS 0


/* ************************************************************************* */
/*
 * http://www.flex-radio.com
 * SDR-1000 rig capabilities.
 *
 *
 * TODO: RIG_FUNC_MUTE, set_external_pin?
 *
 *    def set_mute (self, mute = 1):
 *      self.set_bit(1, 7, mute)
 *
 *    def set_unmute (self):
 *      self.set_bit(1, 7, 0)
 *
 *    def set_external_pin (self, pin, on = 1):
 *      assert (pin < 8 and pin > 0), "Out of range 1..7"
 *      self.set_bit(0, pin-1, on)
 *
 *    def read_input_pin
 *
 *    set_conf(XTAL,PLL_mult,spur_red)
 *
 *    What about IOUD_Clock?
 */

const struct rig_caps sdr1k_rig_caps = {
  .rig_model =      RIG_MODEL_SDR1000,
  .model_name =     "SDR-1000",
  .mfg_name =       "Flex-radio",
  .version =        "0.2",
  .copyright =        "LGPL",
  .status =         RIG_STATUS_UNTESTED,
  .rig_type =       RIG_TYPE_TUNER,
  .targetable_vfo =      0,
  .ptt_type =       RIG_PTT_RIG,
  .dcd_type =       RIG_DCD_NONE,
  .port_type =      RIG_PORT_PARALLEL,

  .has_get_func =   SDR1K_FUNC,
  .has_set_func =   SDR1K_FUNC,
  .has_get_level =  SDR1K_LEVEL,
  .has_set_level =  RIG_LEVEL_SET(SDR1K_LEVEL),
  .has_get_parm =        SDR1K_PARM,
  .has_set_parm =        RIG_PARM_SET(SDR1K_PARM),
  .chan_list =     {
                  RIG_CHAN_END,
             },
  .scan_ops =      RIG_SCAN_NONE,
  .vfo_ops =       RIG_OP_NONE,
  .transceive =     RIG_TRN_OFF,
  .attenuator =     { RIG_DBLST_END, },
  .preamp =        { 14, RIG_DBLST_END, },

  .rx_range_list1 =  { {.start=Hz(1),.end=MHz(65),.modes=SDR1K_MODES,
                .low_power=-1,.high_power=-1,SDR1K_VFO},
                RIG_FRNG_END, },
  .tx_range_list1 =  {
            /* restricted to ham band */
            FRQ_RNG_HF(1,SDR1K_MODES, W(1),W(1),SDR1K_VFO,SDR1K_ANTS),
            FRQ_RNG_6m(1,SDR1K_MODES, W(1),W(1),SDR1K_VFO,SDR1K_ANTS),
            RIG_FRNG_END, },

  .rx_range_list2 =  { {.start=Hz(1),.end=MHz(65),.modes=SDR1K_MODES,
                .low_power=-1,.high_power=-1,SDR1K_VFO},
                RIG_FRNG_END, },
  .tx_range_list2 =  {
            /* restricted to ham band */
            FRQ_RNG_HF(2,SDR1K_MODES, W(1),W(1),SDR1K_VFO,SDR1K_ANTS),
            FRQ_RNG_6m(2,SDR1K_MODES, W(1),W(1),SDR1K_VFO,SDR1K_ANTS),
            RIG_FRNG_END, },

  .tuning_steps =  { {SDR1K_MODES,1},
                  RIG_TS_END,
  },
  .priv =  NULL,  /* priv */

  .rig_init =     sdr1k_init,
  .rig_open =     sdr1k_open,
  .rig_close =    sdr1k_close,
  .rig_cleanup =  sdr1k_cleanup,

  .set_freq =     sdr1k_set_freq,
  .get_freq =     sdr1k_get_freq,
  .set_ptt  =     sdr1k_set_ptt,
  .reset    =     sdr1k_reset,
  .set_level=     sdr1k_set_level,
//  .set_func =     sdr1k_set_func,

};


/* ************************************************************************* */

int sdr1k_init(RIG *rig)
{
      struct sdr1k_priv_data *priv;

      priv = (struct sdr1k_priv_data*)malloc(sizeof(struct sdr1k_priv_data));
      if (!priv) {
            /* whoops! memory shortage! */
            return -RIG_ENOMEM;
      }

      priv->dds_freq = RIG_FREQ_NONE;
      priv->xtal = DEFAULT_XTAL;
      priv->pll_mult = DEFAULT_PLL_MULT;

      rig->state.priv = (void*)priv;

      return RIG_OK;
}

static void pdelay(RIG *rig)
{
      unsigned char r;
      par_read_data(&rig->state.rigport, &r);   /* ~1us */
}

int sdr1k_open(RIG *rig)
{
      struct sdr1k_priv_data *priv = (struct sdr1k_priv_data *)rig->state.priv;

      priv->shadow[0] = 0;
      priv->shadow[1] = 0;
      priv->shadow[2] = 0;
      priv->shadow[3] = 0;

      sdr1k_reset(rig, 1);

      return RIG_OK;
}

int sdr1k_close(RIG *rig)
{
      /* TODO: release relays? */

      return RIG_OK;
}

int sdr1k_cleanup(RIG *rig)
{
      struct sdr1k_priv_data *priv = (struct sdr1k_priv_data *)rig->state.priv;

      if (priv) {
            free(priv);
      }
      rig->state.priv = NULL;

      return RIG_OK;
}

static int set_band(RIG *rig, freq_t freq)
{
      int band, ret;

      /* set_band */
        if (freq <= MHz(2.25))
            band = 0;
      else if ( freq <= MHz(5.5))
            band = 1;
      else if (freq <= MHz(11))
            band = 3;    /* due to wiring mistake on board */
      else if (freq <= MHz(22))
            band = 2;    /* due to wiring mistake on board */
      else if (freq <= MHz(37.5))
            band = 4;
      else
            band = 5;

      ret = write_latch (rig, L_BAND, 1 << band, 0x3f);

      rig_debug(RIG_DEBUG_VERBOSE, "%s %"PRIll" band %d\n", __FUNCTION__, (long long)freq, band);

      return ret;
}

/*
 * set DDS frequency.
 * NB: due to spur reduction, effective frequency might not be the expected one
 */
int sdr1k_set_freq(RIG *rig, vfo_t vfo, freq_t freq)
{
      struct sdr1k_priv_data *priv = (struct sdr1k_priv_data *)rig->state.priv;
      int i;
      double ftw;
      double DDS_step_size;
      freq_t frqval;
      int spur_red = 1;
      int ret;

      ret = set_band(rig, freq);
      if (ret != RIG_OK)
            return ret;

      /* Calculate DDS step for spu reduction
       * DDS steps = 3051.7578125Hz
       */
      DDS_step_size = ((double)priv->xtal * priv->pll_mult ) / 65536;
      rig_debug(RIG_DEBUG_VERBOSE, "%s DDS step size %g %g %g\n", __FUNCTION__, DDS_step_size, (double)freq / DDS_step_size,
                  rint((double)freq / DDS_step_size));
      if (spur_red)
            frqval = (freq_t) (DDS_step_size * rint((double)freq / DDS_step_size));
      else
            frqval = freq;

      rig_debug(RIG_DEBUG_VERBOSE, "%s curr %"PRIll" frqval %"PRIll"\n", __FUNCTION__, (long long)freq, (long long)frqval);

      if (priv->dds_freq == frqval) {
            return RIG_OK;
      }

      /*** */
      ftw = (double)frqval / priv->xtal ;

      for (i = 0; i<6; i++) {
            unsigned word;

            if (spur_red && i==2)
                  word = 128;
            else if (spur_red && i>2)
                  word = 0;
            else {
                  word = (unsigned)(ftw * 256);
                  ftw = ftw*256 - word;
            }
            rig_debug(RIG_DEBUG_TRACE, "DDS %d [%02x]\n", i, word);

            ret = dds_write_reg (rig, 4+i, word);
            if (ret != RIG_OK)
                  return ret;
      }

      priv->dds_freq = frqval;

      return ret;
}

int sdr1k_get_freq(RIG *rig, vfo_t vfo, freq_t *freq)
{
      struct sdr1k_priv_data *priv = (struct sdr1k_priv_data *)rig->state.priv;

      *freq = priv->dds_freq;
      rig_debug(RIG_DEBUG_TRACE,"%s: %"PRIll"\n", __FUNCTION__, (long long)priv->dds_freq);

      return RIG_OK;
}

/* Set DAC multiplier value */
static int DAC_mult(RIG *rig, unsigned mult)
{
      rig_debug(RIG_DEBUG_TRACE, "DAC [%02x,%02x]\n", mult>>8, mult&0xff);

      /* Output Shape Key I Mult */
      dds_write_reg (rig, 0x21, mult >> 8);
      dds_write_reg (rig, 0x22, mult & 0xff);

      /* Output Shape Key Q Mult */
      dds_write_reg (rig, 0x23, mult >> 8);
      dds_write_reg (rig, 0x24, mult & 0xff);

      return RIG_OK;
}

int sdr1k_reset (RIG *rig, reset_t reset)
{
  /* Reset all Latches (relays off) */
  write_latch (rig, L_BAND, 0x00, 0xff);
  write_latch (rig, L_DDS1, 0x00, 0xff);
  write_latch (rig, L_DDS0, 0x00, 0xff);
  write_latch (rig, L_EXT,  0x00, 0xff);

  /* Reset DDS */
  write_latch (rig, L_DDS1, RESET|WRB, 0xff);   /* reset the DDS chip */
  write_latch (rig, L_DDS1, WRB, 0xff);         /* leave WRB high */

  dds_write_reg (rig, 0x1d, COMP_PD);           /* Power down comparator */
  /* TODO: add PLL multiplier property and logic */
  dds_write_reg (rig, 0x1e, BYPASS_PLL);  /* Bypass PLL */

  dds_write_reg (rig, 0x20, BYPASS_SINC|OSK_EN);/* Bypass Inverse Sinc and enable DAC */
  DAC_mult(rig, DEFAULT_DAC_MULT);  /* Set DAC multiplier value */

  return RIG_OK;
}

int sdr1k_set_ptt (RIG *rig, vfo_t vfo, ptt_t ptt)
{
      return set_bit(rig, L_BAND, 6, ptt == RIG_PTT_ON);
}
  

int sdr1k_set_level (RIG *rig, vfo_t vfo, setting_t level, value_t val)
{
      rig_debug(RIG_DEBUG_TRACE,"%s: %s %d\n", __FUNCTION__, rig_strlevel(level), val.i);

      switch (level) {
      case RIG_LEVEL_PREAMP:
            return set_bit(rig, L_EXT, 7, !(val.i == rig->caps->preamp[0]));
            break;
      default:
            return -RIG_EINVAL;
      }
}
  

int
write_latch (RIG *rig, latch_t which, unsigned value, unsigned mask)
{
  struct sdr1k_priv_data *priv = (struct sdr1k_priv_data *)rig->state.priv;
  hamlib_port_t *pport = &rig->state.rigport;

  if (!(L_EXT <= which && which <= L_DDS1))
    return -RIG_EINVAL;
  
  par_lock (pport);
  priv->shadow[which] = (priv->shadow[which] & ~mask) | (value & mask);
  par_write_data (pport, priv->shadow[which]);
  pdelay(rig);
  par_write_control (pport, 0x0F ^ (1 << which));
  pdelay(rig);
  par_write_control (pport, 0x0F);
  pdelay(rig);
  par_unlock (pport);

  return RIG_OK;
}


int
dds_write_reg (RIG *rig, unsigned addr, unsigned data)
{
#if 0
      write_latch (rig, L_DDS1, addr & 0x3f, 0x3f);
      write_latch (rig, L_DDS0, data, 0xff);
      write_latch (rig, L_DDS1, 0x40, 0x40);
      write_latch (rig, L_DDS1, 0x00, 0x40);
#else
      /* set up data bits */
      write_latch (rig, L_DDS0, data, 0xff);

      /* set up address bits with WRB high */
      //write_latch (rig, L_DDS1, addr & 0x3f, 0x3f);
      write_latch (rig, L_DDS1, WRB | addr, 0xff);

      /* send write command with WRB low */
      write_latch (rig, L_DDS1, addr, 0xff);

      /* return WRB high */
      write_latch (rig, L_DDS1, WRB, 0xff);
#endif

      return RIG_OK;
}

int
set_bit (RIG *rig, latch_t reg, unsigned bit, unsigned state)
{
      unsigned val;
      
      val = state ? 1<<bit : 0;

      return write_latch (rig, reg, val, 1<<bit);
}


Generated by  Doxygen 1.6.0   Back to index