]> git.rkrishnan.org Git - dttsp.git/blobdiff - pyhw2/hardware.c
New hardware control code
[dttsp.git] / pyhw2 / hardware.c
diff --git a/pyhw2/hardware.c b/pyhw2/hardware.c
new file mode 100644 (file)
index 0000000..0cdfca9
--- /dev/null
@@ -0,0 +1,1011 @@
+// hardware.c
+// version 2
+
+#include <hardware.h>
+
+// Register memory for IC11
+int ic11_memory;               
+
+// Register memory for IC7
+int ic7_memory;                
+
+BOOL rfe_enabled;              // True if RFE board is enabled
+BOOL xvtr_enabled;             // Transverter is enabled
+BOOL pa_enabled;               // Transverter is enabled
+
+// Latch Memories
+BandSetting band_relay = bs0;
+int external_output    = 0;
+int mute_relay         = 0;
+int transmit_relay     = 0;
+int gain_relay         = 0;
+int latch_delay                = 0;    // measured in 100ns steps (10 = 1us)
+
+// DDS Clock properties
+double dds_clock               = 0.0;  // DDS Clock oscillator in MHz
+int pll_mult                   = 0;    // DDS PLL multiplier
+double dds_clock_correction    = 0.0;  // Oscillator dds_clock_correction in MHz
+double sysClock                        = 0.0;  // DDS Internal System Clock in MHz
+int ioud_clock                 = 0;    // IO Update clock period
+ushort dac_mult                        = 0;    // DAC Multiplier setting
+
+// DDS Frequency Control properties
+double dds_freq                = 0.0;  // Last VFO Setting in MHz
+double if_freq         = 0.0;  // IF Frequency Offset in MHz
+BOOL if_shift          = FALSE;// Turns Offset Baseband IF Shift On
+BOOL spur_reduction    = FALSE;// Eliminates Phase Truncation Spurs
+double dds_step_size   = 0.0;  // DDS Step in MHz for spur removal
+int sample_rate                = 0;    // ADC Sampling Rate in Hz
+int fft_length         = 0;    // Length of FFT in bins
+double FFT_Bin_Size    = 0.0;  // Bandwidth of FFT bin
+int tune_fft           = 0;    // Offset tuning of FFT bins
+double tune_frac_rel   = 0.0;  // In relative frequency (frequency/m_Sample_Rate)
+double vfo_offset      = 0.0;
+//double last_VFO      = 0.0;  // temp store for last VFO frequency
+
+double min_freq = 0.012;       // minimum allowable tuning frequency
+double max_freq = 65.0;                // maximum allowable tuning frequency
+
+// PIO register base address
+u_short baseAdr = 0x378;
+
+// Current Bandplan
+BandPlan curBandPlan = IARU1;
+
+double TWO_TO_THE_48_DIVIDED_BY_200 = 1407374883553.28;
+long last_tuning_word = 0;
+// private Mutex parallel_mutex = new Mutex();
+// private Mutex dataline_mutex = new Mutex();
+
+BOOL usb_enabled = FALSE;
+
+//------------------------------------------------------------------------
+
+PRIVATE int parportfd = -1;
+
+PUBLIC BOOL openPort(char *port) {
+  int mode = IEEE1284_MODE_COMPAT;
+  if (!port) port = "/dev/parport0";
+  if ((parportfd = open(port, O_RDWR)) < 0) {
+    perror("open parallel port");
+    return FALSE;
+  }
+  ioctl(parportfd, PPCLAIM);
+  ioctl(parportfd, PPSETMODE, &mode);
+  return TRUE;
+}
+  
+PUBLIC void closePort(void) {
+  ioctl(parportfd, PPRELEASE);
+  close(parportfd);
+}
+
+double DttSP_SampleRate = 48000.0;
+
+PUBLIC void USB_Sdr1kLatch(int l, BYTE b) {}
+PUBLIC BYTE USB_Sdr1kGetStatusPort(void) { return 0; }
+PUBLIC int  USB_Sdr1kGetADC(void) { return 0; }
+PUBLIC void USB_Sdr1kDDSReset(void) {}
+PUBLIC void USB_Sdr1kDDSWrite(BYTE addr, BYTE data) {}
+PUBLIC void USB_Sdr1kSRLoad(BYTE reg, BYTE data) {}
+PUBLIC void DttSP_ChangeOsc(double val) {}
+
+PRIVATE void Delay(void) {
+  usleep(1000 * latch_delay);
+}
+
+PRIVATE void Sleep(int ms) {
+  usleep(1000 * ms);
+}
+
+PRIVATE void PWrite(BYTE data) {
+  //Write data Byte to parallel port
+  ioctl(parportfd, PPWDATA, &data);
+  //Delay to allow data line setup
+  Delay();
+}
+
+PRIVATE void Latch(CtrlPin vCtrlPin) {
+  //Strobe the specified pin to latch data
+  unsigned char mask;
+  switch (vCtrlPin) {
+  case EXT:
+    mask = 0xA, ioctl(parportfd, PPWCONTROL, &mask);
+    Delay();
+    mask = 0xB, ioctl(parportfd, PPWCONTROL, &mask);
+    break;
+  case BPF:
+    mask = 0x9, ioctl(parportfd, PPWCONTROL, &mask);
+    Delay();
+    mask = 0xB, ioctl(parportfd, PPWCONTROL, &mask);
+    break;
+  case DAT:
+    mask = 0xF, ioctl(parportfd, PPWCONTROL, &mask);
+    Delay();
+    mask = 0xB, ioctl(parportfd, PPWCONTROL, &mask);
+    break;
+  case ADR:
+    mask = 0x3, ioctl(parportfd, PPWCONTROL, &mask);
+    Delay();
+    mask = 0xB, ioctl(parportfd, PPWCONTROL, &mask);
+    break;
+  }
+}
+
+PRIVATE void ResetLatches(void)        {
+  //Set all latch outputs to logic zero (relays off)
+  if (usb_enabled) {
+    gain_relay = GAIN;
+    external_output = 0;
+    USB_Sdr1kLatch(SDR1K_LATCH_EXT, (BYTE) (external_output + gain_relay));
+    setBandRelay(bsnone);
+    transmit_relay = 0;
+    mute_relay = MUTE;
+    USB_Sdr1kLatch(SDR1K_LATCH_BPF, (BYTE) (band_relay + transmit_relay + mute_relay));
+  } else {
+    PWrite(0);
+    Latch(ADR);
+    Latch(DAT);
+    gain_relay = GAIN;
+    external_output = 0;
+    PWrite((BYTE) (external_output + gain_relay));
+    Latch(EXT);
+    setBandRelay(bsnone);
+    transmit_relay = 0;
+    mute_relay = MUTE;
+    PWrite((BYTE) (band_relay + transmit_relay + mute_relay));
+    Latch(BPF);
+  }                    
+}
+
+PRIVATE void DDSWrite(BYTE data, BYTE addr) {
+  if (usb_enabled)
+    USB_Sdr1kDDSWrite(addr, data);
+  else {
+    PWrite(data);
+    Latch(DAT);
+    PWrite((BYTE) (addr + WRB));
+    Latch(ADR);
+    PWrite(addr);
+    Latch(ADR);
+    PWrite(WRB);
+    Latch(ADR);
+  }
+}
+
+PRIVATE void ResetDDS(void) {
+  if(usb_enabled)
+    USB_Sdr1kDDSReset();
+  else {
+    PWrite(RESET + WRB);
+    Latch(ADR);
+    PWrite(WRB);
+    Latch(ADR);
+  }
+  DDSWrite(COMP_PD, 29);               //Power down comparator
+  if(pll_mult == 1)
+    DDSWrite(BYPASS_PLL, 30);
+  else
+    DDSWrite((BYTE) pll_mult, 30);
+  DDSWrite(BYPASS_SINC, 32);
+}
+
+
+PRIVATE void CalcClock(void) {
+  sysClock = 200.0 + dds_clock_correction;
+  dds_step_size = sysClock / pow(2.0, 48.0);
+}
+
+PRIVATE void SetRadioFreq(double f) {
+  double vfoFreq = f;
+  long tuning_word;
+
+  // calculate software frequency to program
+  if(xvtr_enabled && f >= 144 && f <= 146)
+    f -= 116;                                                                  //Subtract 116MHz (144-28) from VFO display frequency
+
+  if (if_shift)
+    f -= if_freq;                                                              // adjust for IF shift
+  
+  f += vfo_offset;                                                             // adjust for vfo offset
+
+  tuning_word = (long) (f / sysClock * pow(2.0, 48.0));
+
+  if (spur_reduction) {
+    // start with current tuning word
+    // clear first bit, low 31 bits; set bit 31
+    unsigned long long
+      sr_tuning_word = (tuning_word & ~(0x80007fffffffLL)) | 0x000080000000LL;
+    double software_offset = (sr_tuning_word - tuning_word) * dds_step_size;
+
+    if (if_shift)                                                              //Convert the tuning fraction to rel frq
+      tune_frac_rel = 1000000.0 * (software_offset) - 11025.0;
+    else
+      tune_frac_rel = 1000000.0 * (software_offset);
+    DttSP_ChangeOsc(tune_frac_rel);
+
+    tuning_word = sr_tuning_word;
+  }
+
+  // program hardware
+  SetBPF(vfoFreq);
+
+  if (tuning_word != last_tuning_word) {
+    int i;
+    last_tuning_word = tuning_word;               //save new tuning word    
+                               
+    //parallel_mutex.WaitOne();
+    for(i = 0; i < 6; i++) {
+      BYTE b = (BYTE) (tuning_word >> (40 - i * 8));
+      DDSWrite(b, (BYTE) (4 + i));
+    }
+    //parallel_mutex.ReleaseMutex();
+  }
+}
+
+PUBLIC BOOL IsHamBand(BandPlan b) {
+  if (getExtended()) return TRUE;
+  switch (b) {
+  case IARU1:
+    if      (dds_freq >= 1.8 && dds_freq <= 2.0)       return TRUE;
+    else if (dds_freq >= 3.5 && dds_freq <= 4.0)       return TRUE;
+    else if (dds_freq == 5.3305)                       return TRUE;
+    else if (dds_freq == 5.3465)                       return TRUE;
+    else if (dds_freq == 5.3665)                       return TRUE;
+    else if (dds_freq == 5.3715)                       return TRUE;
+    else if (dds_freq == 5.4035)                       return TRUE;
+    else if (dds_freq >= 7.0 && dds_freq <= 7.3)       return TRUE;
+    else if (dds_freq >= 10.1 && dds_freq <= 10.15)    return TRUE;
+    else if (dds_freq >= 14.0 && dds_freq <= 14.35)    return TRUE;
+    else if (dds_freq >= 18.068 && dds_freq <= 18.168) return TRUE;
+    else if (dds_freq >= 21.0 && dds_freq <= 21.45)    return TRUE;
+    else if (dds_freq >= 24.89 && dds_freq <= 24.99)   return TRUE;
+    else if (dds_freq >= 21.0 && dds_freq <= 21.45)    return TRUE;
+    else if (dds_freq >= 28.0 && dds_freq <= 29.7)     return TRUE;
+    else if (dds_freq >= 50.0 && dds_freq <= 54.0)     return TRUE;
+    else if (dds_freq >= 144.0 && dds_freq <= 146.0) {
+      if (rfe_enabled && xvtr_enabled) return TRUE;
+      else                             return FALSE;
+    } else return FALSE;
+    default:
+      return FALSE;
+      // TODO: Implement other bandplans here
+  }
+}
+
+//------------------------------------------------------------------------
+// Properties
+//
+
+PRIVATE BOOL enable_LPF0 = FALSE;
+PUBLIC  BOOL getEnableLPF0       (void) { return enable_LPF0; }
+PUBLIC  void setEnableLPF0 (BOOL value) { enable_LPF0 = value; };
+
+PRIVATE BOOL extended = FALSE;
+PUBLIC  BOOL getExtended       (void) { return extended; }
+PUBLIC  void setExtended (BOOL value) { extended = value; }
+
+PRIVATE BOOL x2_enabled = FALSE;
+PUBLIC  BOOL getX2Enabled       (void) { return x2_enabled; }
+PUBLIC  void setX2Enabled (BOOL value) { x2_enabled = value; }
+
+PRIVATE int  x2_delay = 500;
+PUBLIC  int  getX2Delay      (void) { return x2_delay; }
+PUBLIC  void setX2Delay (int value) { x2_delay = value; }
+
+PUBLIC BOOL getRFE_Enabled       (void) { return rfe_enabled; }
+PUBLIC void setRFE_Enabled (BOOL value) {
+  rfe_enabled = value;
+  SetRadioFreq(dds_freq);
+}
+
+PUBLIC BOOL getPA_Enabled       (void) { return pa_enabled; }
+PUBLIC void setPA_Enabled (BOOL value) { pa_enabled = value; }
+
+PUBLIC BOOL getXVTR_Enabled       (void) { return xvtr_enabled; }
+PUBLIC BOOL setXVTR_Enabled (BOOL value) {
+  xvtr_enabled = value;
+  if (xvtr_enabled) max_freq = 146.0;
+  else              max_freq = 65.0;
+}
+
+PUBLIC BOOL getUSB_Enabled       (void) { return usb_enabled; }
+PUBLIC void setUSB_Enabled (BOOL value) { usb_enabled = value; }
+
+PRIVATE XVTRTRMode current_xvtr_tr_mode = NEGATIVE;
+PUBLIC  XVTRTRMode getCurrentXVTRTRMode             (void) { return current_xvtr_tr_mode; }
+PUBLIC  void       setCurrentXVTRTRMode (XVTRTRMode value) {
+  current_xvtr_tr_mode = value;
+  switch (current_xvtr_tr_mode) {
+  case NEGATIVE: setXVTR_TR_Relay(TRUE);  break;       // Set to receive
+  case POSITIVE: setXVTR_TR_Relay(FALSE); break;       // Set to receive
+  case NONE:                              break;
+  }
+}
+
+PUBLIC int  getLatchDelay      (void) { return latch_delay; }
+PUBLIC void setLatchDelay (int value) { latch_delay = value; }
+
+PUBLIC double getMinFreq (void) { return min_freq; }
+PUBLIC double getMaxFreq (void) { return max_freq; }
+
+PUBLIC u_short getBaseAddr          (void) { return baseAdr; }
+PUBLIC u_short setBaseAddr (u_short value) { baseAdr = value; }
+
+PUBLIC BandSetting getBandRelay              (void) { return band_relay; }
+PUBLIC void        setBandRelay (BandSetting value) {
+  band_relay = value;
+  if (usb_enabled)
+    USB_Sdr1kLatch(SDR1K_LATCH_BPF,
+                  (BYTE) (band_relay + transmit_relay + mute_relay));
+  else {
+    PWrite((BYTE) (band_relay + transmit_relay + mute_relay));
+    Latch(BPF);
+  }
+}
+
+PUBLIC BOOL getTransmitRelay (void) {
+  //Get state of TR relay on BPF board
+  if (transmit_relay == TR) return TRUE;
+  else                      return FALSE;
+}
+PUBLIC void setTransmitRelay (BOOL value) {
+  BYTE tmpLatch = 0;
+  BOOL tmpATTN = FALSE;
+  //If in valid Amateur BandRelay Save and output new TR Relay setting
+  if (value == TRUE) {
+    //if (IsHamBand(curBandPlan) == TRUE)
+    {
+      if (x2_enabled) {
+       SetExt(P7);             // set X2-7
+       Sleep(x2_delay);        // pause for ext. relays
+      }
+      transmit_relay = TR;     // Set to TX
+      if (rfe_enabled == TRUE) {
+       tmpATTN = getATTN_Relay();
+       if (xvtr_enabled && dds_freq >= 144) {
+         switch (current_xvtr_tr_mode) {
+         case NEGATIVE: setXVTR_TR_Relay(FALSE); break;
+         case POSITIVE: setXVTR_TR_Relay(TRUE);  break;
+         case NONE:                              break;
+         }
+       } else setAMP_Relay(TRUE);                                      //Switch RFE to transmit
+       tmpLatch = (BYTE) (transmit_relay + mute_relay + DCDR_NE);// DCDR_NE for 2-4 Decoder to stay high
+      }        else
+       tmpLatch = (BYTE) (band_relay + transmit_relay + mute_relay);
+    }
+  } else {
+    transmit_relay = 0;       // Set to RX
+    if (rfe_enabled) {
+      setAMP_Relay(FALSE);
+      tmpLatch = (BYTE) (transmit_relay + mute_relay + DCDR_NE);
+      if (xvtr_enabled) {
+       switch(current_xvtr_tr_mode) {
+       case NEGATIVE: setXVTR_TR_Relay(TRUE);  break;
+       case POSITIVE: setXVTR_TR_Relay(FALSE); break;
+       case NONE:                              break;
+       }
+      }
+      setATTN_Relay(tmpATTN);
+    } else
+      tmpLatch = (BYTE) (band_relay + transmit_relay + mute_relay);
+  }
+  if (usb_enabled)
+    USB_Sdr1kLatch(SDR1K_LATCH_BPF, tmpLatch);
+  else {
+    PWrite(tmpLatch);
+    Latch(BPF);
+  }
+  if (!value && x2_enabled) {
+    Sleep(x2_delay);   // pause for ext. relays
+    ResExt(P7);                // clear X2-7 
+  }
+  if (pa_enabled) {    // set PA transmit/bias
+    if (dds_freq >= 1.8 && dds_freq <= 29.7) {
+      if (value) {     // TX
+       setPA_TransmitRelay(TRUE);
+       setPA_BiasOn(TRUE);
+      } else {         // RX
+       setPA_BiasOn(FALSE);
+       setPA_TransmitRelay(FALSE);
+      }
+    }
+  }
+}
+
+PUBLIC BOOL getMuteRelay (void) {
+  // Get state of MUTE relay on TRX board
+  if (mute_relay == MUTE) return FALSE;
+  else                    return TRUE;
+}
+PUBLIC void setMuteRelay (BOOL value) {
+  BYTE data = 0;
+  // Mute the speaker relay if TRUE
+  if (value == TRUE) mute_relay = 0;
+  else               mute_relay = MUTE;
+  if (rfe_enabled)
+    data = (BYTE) (transmit_relay + mute_relay + DCDR_NE);
+  else
+    data = (BYTE) (band_relay + transmit_relay + mute_relay);
+  if (usb_enabled) {
+    USB_Sdr1kLatch(SDR1K_LATCH_BPF, data);
+  } else {
+    PWrite(data);
+    Latch(BPF);
+  }
+}
+
+PUBLIC BOOL getGainRelay (void) {
+  // Get state of GAIN relay on TRX board
+  if (gain_relay == GAIN) return FALSE;
+  else                    return TRUE;
+}
+PUBLIC void setGainRelay (BOOL value) {
+  // Save and output state of GAIN relay on TRX board
+  if (value == TRUE) gain_relay = 0;   // 40dB or 0dB w/RFE
+  else               gain_relay = GAIN;        // 26dB
+  if (usb_enabled)
+    USB_Sdr1kLatch(SDR1K_LATCH_EXT, (BYTE) (external_output + gain_relay));
+  else {
+    PWrite((BYTE) (external_output + gain_relay));
+    Latch(EXT);
+  }
+}
+
+PUBLIC int  getExternalOutput      (void) { return external_output; }
+PUBLIC void setExternalOutput (int value) {
+  //Save and output state of External Control outputs on PIO board
+  external_output = value;
+  if (usb_enabled)
+      USB_Sdr1kLatch(SDR1K_LATCH_EXT, (BYTE) (external_output + gain_relay));
+  else {
+    PWrite((BYTE) (external_output + gain_relay));
+    Latch(EXT);
+  }
+}
+
+PUBLIC double getDDSClockCorrection         (void) { return dds_clock_correction; }
+PUBLIC void   setDDSClockCorrection (double value) {
+  dds_clock_correction = value;
+  CalcClock();
+  SetRadioFreq(dds_freq);
+}
+
+PUBLIC int  getPLLMult      (void) { return pll_mult; }
+PUBLIC void setPLLMult (int value) {
+  pll_mult = value;
+  if (pll_mult == 1) DDSWrite(BYPASS_PLL, 30);     // Bypass PLL if multiplier value is 1
+  else               DDSWrite((BYTE) pll_mult, 30); // Set for External Clock
+  CalcClock();
+}
+
+PUBLIC double getDDSClock         (void) { return dds_clock; }
+PUBLIC void   setDDSClock (double value) {
+  //Compute internal DDS System Clock and Phase Truncation Elimination Step
+  dds_clock = value;
+  CalcClock();
+}
+
+PUBLIC BOOL getIFShift       (void) { return if_shift; }
+PUBLIC void setIFShift (BOOL value) {
+  // Turns IF shift on and off
+  if_shift = value;
+  if (!spur_reduction) {
+    if (if_shift) DttSP_ChangeOsc(-11025.0);
+    else          DttSP_ChangeOsc(0.0);
+  }
+  SetRadioFreq(dds_freq);
+}
+
+PUBLIC BOOL getSpurReduction       (void) { return spur_reduction; }
+PUBLIC BOOL setSpurReduction (BOOL value) {
+  // Turns DDS Phase Truncation Spur reduction on and off
+  spur_reduction = value;
+  if (!spur_reduction) {
+      if (if_shift) DttSP_ChangeOsc(-11025.0);
+      else          DttSP_ChangeOsc(0.0);
+  }
+  SetRadioFreq(dds_freq);
+}
+
+PUBLIC double getIFFreq         (void) { return if_freq; }
+PUBLIC void   setIFFreq (double value) { if_freq = value; }
+
+PUBLIC double getDDSFreq         (void) { return dds_freq; }
+PUBLIC void   setDDSFreq (double value) {
+  dds_freq = value;
+  SetRadioFreq(dds_freq);
+}
+
+PUBLIC int  getSampleRate      (void) { return sample_rate; }
+PUBLIC void setSampleRate (int value) {
+  sample_rate = value;
+  if (fft_length > 0)
+    FFT_Bin_Size = (sample_rate / fft_length) * 1e-6;
+}
+
+PUBLIC int  getFFTLength      (void) { return fft_length; }
+PUBLIC void setFFTLength (int value) {
+  fft_length = value;
+  //Compute bandwidth of FFT bin
+  if (fft_length > 0)
+    FFT_Bin_Size = (sample_rate / fft_length) * 1e-6;
+}
+
+PUBLIC int getTuneFFT (void) { return tune_fft; }
+
+PUBLIC double getTuneFracRel (void) { return tune_frac_rel; }
+
+PUBLIC double getVFOOffset         (void) { return vfo_offset; }
+PUBLIC void   setVFOOffset (double value) {
+  vfo_offset = value;
+  SetRadioFreq(dds_freq);
+}
+
+PUBLIC int  getIOUDClock      (void) { return ioud_clock; }
+PUBLIC void setIOUDClock (int value) {
+  double bitVal, bytVal;
+  BYTE lWord;
+  int i;
+  ioud_clock = value;                  //Save value
+  bitVal = value;                      //Compute Numeric Value
+  for (i = 24; i >= 0; i -= 8) {               //Convert to binary strings
+      bytVal = bitVal / (01 << i);     //Compute binary byte Value
+      lWord = (BYTE) bytVal;           //Truncate fractional portion
+      bitVal -= lWord * (01 << i);     //Reduce value
+      switch (i) {                     //Write to byte position
+       case 32: DDSWrite(lWord, 22); break;
+       case 16: DDSWrite(lWord, 23); break;
+       case 8:  DDSWrite(lWord, 24); break;
+       case 0:  DDSWrite(lWord, 25); break;
+       }
+    }
+}
+
+PUBLIC u_short getDACMult          (void) { return dac_mult; }
+PUBLIC void    setDACMult (u_short value) {
+  double bitVal, bytVal;
+  BYTE lWord;
+  int i;
+  dac_mult = value;
+  bitVal = value;                      //Compute Numeric Value
+  for (i = 8; i >= 0; i -= 8) {                //Convert to binary strings
+    bytVal = bitVal / (01 << i);       //Compute binary byte Value
+    BYTE lWord = (BYTE) bytVal;        //Truncate fractional portion
+    bitVal -= lWord * (01 << i);       //Reduce value
+    switch (i) {
+    case 8: DDSWrite(lWord, 33); break;
+    case 0: DDSWrite(lWord, 34); break;
+    }
+  }
+  //Send new I DAC Multiplier value to DDS
+  bitVal = value;                      //Compute Numeric Value
+  for (i = 8; i >= 0; i -= 8) {                //Convert to binary strings.
+    bytVal = bitVal / (01 << i);       //Compute binary byte Value
+    lWord = (BYTE) bytVal;             //Truncate fractional portion
+    bitVal -= lWord * (01 << i);       //Reduce value
+      switch (i) {                     //Write to byte position
+       case 8: DDSWrite(lWord, 35); break;
+       case 0: DDSWrite(lWord, 36); break;
+      }
+  }
+}
+
+PUBLIC BYTE StatusPort(void) { 
+  if (usb_enabled)
+    return (BYTE) USB_Sdr1kGetStatusPort();
+  else {
+    BYTE status;
+    ioctl(parportfd, PPRSTATUS, (char *) &status);
+    return status;
+  }
+}
+
+PUBLIC void Init(void) {
+  setIFShift(TRUE);
+  // user setable through the setup form
+  // DDSClockCorrection = 0.000;
+  setPLLMult(1);
+  setDDSClock(200);
+  setIFFreq(0.011025);
+  setSampleRate((int) DttSP_SampleRate);
+  setFFTLength(4096);
+  //setDACMult(4095);
+}
+
+PUBLIC void PowerOn(void) {
+  if (rfe_enabled) {
+    // set mute/gain relays based on console
+    if (xvtr_enabled && current_xvtr_tr_mode == NEGATIVE)
+      setXVTR_TR_Relay(TRUE);
+    else
+      setXVTR_TR_Relay(FALSE);
+    //DDSFreq = dds_freq;
+    ic11_memory |= ADC_CS_NOT;         // set CS_NOT high
+    ic11_memory |= ATUCTL;
+    ic7_memory  |= PA_BIAS_NOT;
+    SRLoad(IC11, ic11_memory);                         
+    SRLoad(IC7,  ic7_memory);
+  }
+}
+
+PUBLIC void StandBy(void) {
+  ResetLatches();
+  if (rfe_enabled) ResetRFE();
+  if (xvtr_enabled) setXVTR_TR_Relay(FALSE);
+  // TODO: Fix bias glitch on reset w/hardware rewrite
+  if (rfe_enabled) {
+      SRLoad(IC7, PA_BIAS_NOT);
+      SRLoad(IC11, ADC_CS_NOT);
+  }
+  ResetDDS();
+}
+
+PUBLIC void SetExt(ExtPin pin) {
+  //Set the designated external pin high
+  external_output |= (BYTE) pin;
+  if (usb_enabled)
+    USB_Sdr1kLatch(SDR1K_LATCH_EXT, (BYTE) (external_output + gain_relay));
+  else {
+    PWrite((BYTE) (external_output + gain_relay));
+    Latch(EXT);
+  }
+}
+
+PUBLIC void ResExt(ExtPin pin) {
+  //Reset the designated external pin high
+  external_output &= ~(BYTE) pin;
+  if (usb_enabled)
+    USB_Sdr1kLatch(SDR1K_LATCH_EXT, (BYTE) (external_output + gain_relay));
+  else {
+    PWrite((BYTE) (external_output + gain_relay));
+    Latch(EXT);
+  }
+}
+
+PUBLIC BOOL PinValue(ExtPin pin) {
+  //Return TRUE if Pin is set
+  if ((external_output & (int) pin) != 0)
+    return TRUE;
+  else
+    return FALSE;
+}
+
+PUBLIC void SetBPF(double vfo_value) {
+  if (rfe_enabled) {
+      if (vfo_value <= 2.5) {
+       if (pa_enabled) PA_SetLPF(PA_LPF_160);
+       if (vfo_value <= 0.3 && enable_LPF0) {
+         SRLoad(IC10, BPF0);
+         SRLoad(IC9, LPF0);                                            
+       } else {
+         SRLoad(IC10, LPF9 + BPF0);
+         SRLoad(IC9, 0);
+       }
+      } else if (vfo_value <= 4) {
+       if (pa_enabled) PA_SetLPF(PA_LPF_80);
+       SRLoad(IC10, BPF1);
+       SRLoad(IC9,  LPF7);
+      } else if (vfo_value <= 6) {
+       if (pa_enabled) PA_SetLPF(PA_LPF_60_40);
+       SRLoad(IC10, BPF1);
+       SRLoad(IC9,  LPF2);
+      } else if (vfo_value <= 7.3) {
+       if (pa_enabled) PA_SetLPF(PA_LPF_60_40);
+       SRLoad(IC10, BPF2);
+       SRLoad(IC9,  LPF5);
+      } else if (vfo_value <= 10.2) {
+       if (pa_enabled) PA_SetLPF(PA_LPF_30_20);
+       SRLoad(IC10, BPF2);
+       SRLoad(IC9,  LPF4);
+      } else if (vfo_value <= 12) {
+       if (pa_enabled) PA_SetLPF(PA_LPF_OFF);
+       SRLoad(IC10, BPF2);
+       SRLoad(IC9,  LPF3);
+      } else if (vfo_value <= 14.5) {
+       if (pa_enabled) PA_SetLPF(PA_LPF_30_20);
+       SRLoad(IC10, BPF3);
+       SRLoad(IC9,  LPF3);
+      } else if (vfo_value <= 21.5) {
+       if (pa_enabled) PA_SetLPF(PA_LPF_17_15);
+       SRLoad(IC10, BPF3 + LPF8);
+       SRLoad(IC9,  0);
+      } else if (vfo_value <= 24) {
+       if (pa_enabled) PA_SetLPF(PA_LPF_12_10);
+       SRLoad(IC10, BPF3);
+       SRLoad(IC9,  LPF6);
+      } else if (vfo_value <= 30) {
+       if (pa_enabled) PA_SetLPF(PA_LPF_12_10);
+       SRLoad(IC10, BPF4);
+       SRLoad(IC9,  LPF6);
+      } else if (vfo_value <= 36) {
+       if (pa_enabled) PA_SetLPF(PA_LPF_OFF);
+       SRLoad(IC10, BPF4);
+       SRLoad(IC9,  LPF1);
+      } else if (vfo_value <= 65) {
+       if (pa_enabled) PA_SetLPF(PA_LPF_OFF);
+       SRLoad(IC10, BPF5);
+       SRLoad(IC9,  LPF1);
+      } else if (xvtr_enabled && vfo_value >= 144 && vfo_value <= 146) {
+       if (pa_enabled) PA_SetLPF(PA_LPF_OFF);
+       SRLoad(IC10, BPF4);
+       SRLoad(IC9,  LPF6);
+       setXVTR_Relay(TRUE);
+      }
+      if (xvtr_enabled && vfo_value < 144)
+       setXVTR_Relay(FALSE);
+    } else {
+      if      (vfo_value < 2.5)        setBandRelay(bs0);
+      else if (vfo_value < 6)  setBandRelay(bs1);
+      else if (vfo_value < 12) setBandRelay(bs2);
+      else if (vfo_value < 24) setBandRelay(bs3);
+      else if (vfo_value < 36) setBandRelay(bs4);
+      else                     setBandRelay(bs5);
+    }
+}
+
+PUBLIC void TestPort(void) {
+  //Toggle 1 and 0 to each of the four parallel port latches
+  if (usb_enabled) {
+    USB_Sdr1kLatch(SDR1K_LATCH_BPF, 0);
+    USB_Sdr1kLatch(SDR1K_LATCH_EXT, 0);
+    USB_Sdr1kLatch(SDR1K_LATCH_BPF, 255);
+    USB_Sdr1kLatch(SDR1K_LATCH_EXT, 255);
+  } else {
+    PWrite(0);
+    Latch(BPF);
+    Latch(ADR);
+    Latch(DAT);
+    Latch(EXT);
+    PWrite(255);
+    Latch(BPF);
+    Latch(ADR);
+    Latch(DAT);
+    Latch(EXT);
+  }
+}
+
+PUBLIC void RCKStrobe(BOOL ClearReg, RFE_RCK Reg) {
+  // Strobe the RFE 1:4 decoder output to transfer contents
+  // of shift register to output latches
+  BYTE data = 0;
+  if (ClearReg) data = (BYTE) (Reg);
+  else data = (BYTE) (SCLR_NOT + Reg + transmit_relay + mute_relay);
+  if (usb_enabled) {
+    USB_Sdr1kLatch(SDR1K_LATCH_BPF, data);
+    USB_Sdr1kLatch(SDR1K_LATCH_BPF, (BYTE) (SCLR_NOT + DCDR_NE + transmit_relay + mute_relay));
+  } else {
+    PWrite(data);
+    Latch(BPF);
+    PWrite((BYTE) (SCLR_NOT + DCDR_NE + transmit_relay + mute_relay));
+    Latch(BPF);
+  }
+}
+
+PUBLIC void SRLoad(RFE_RCK Reg, int Data) {
+  if (usb_enabled)
+    USB_Sdr1kSRLoad((BYTE) Reg, (BYTE) Data);
+  else {
+    static int choose[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
+    int i;
+    //Shift data into registers on RFE
+    //parallel_mutex.WaitOne();
+    for (i = 0; i < 8; i++) {
+      int mask = choose[i];                                                                                            // Mask the current bit
+      if ((mask & Data) == 0) {
+       PWrite((BYTE) (SCLR_NOT + DCDR_NE + transmit_relay + mute_relay));
+       Latch(BPF);
+       PWrite((BYTE) (SCLR_NOT + DCDR_NE + SCK + transmit_relay + mute_relay));
+      } else {                                                                                                                         // Current bit = 1          {
+       PWrite((BYTE) (SCLR_NOT + DCDR_NE + SER + transmit_relay + mute_relay));
+       Latch(BPF);
+       PWrite((BYTE) (SCLR_NOT + DCDR_NE + SER + SCK + transmit_relay + mute_relay));
+      }
+      Latch(BPF);
+      PWrite((BYTE) (SCLR_NOT + DCDR_NE + transmit_relay + mute_relay));
+      Latch(BPF);
+    }
+    RCKStrobe(FALSE, Reg);                                                                                                     // Strobe Register Clock
+    //parallel_mutex.ReleaseMutex();
+  }
+}
+
+PUBLIC void ResetRFE(void) {
+  //Reset all RFE shift registers to zero output
+  //parallel_mutex.WaitOne();
+  RCKStrobe(TRUE, IC11);
+  RCKStrobe(TRUE, IC7);
+  RCKStrobe(TRUE, IC10);
+  RCKStrobe(TRUE, IC9);
+  //parallel_mutex.ReleaseMutex();
+}
+
+PUBLIC BOOL getAMP_Relay       (void) { return (ic7_memory & AMP_RLYS) != 0; }
+PUBLIC BOOL setAMP_Relay (BOOL value) {
+  //Set or reset LNA relay
+  if (value)  ic7_memory |= AMP_RLYS;
+  else        ic7_memory &= ~(AMP_RLYS);
+  SRLoad(IC7, ic7_memory);
+}
+
+PUBLIC BOOL getATTN_Relay       (void) { return (ic7_memory & ATTN_RLY) != 0; }
+PUBLIC void setATTN_Relay (BOOL value) {
+  if (value)  ic7_memory |= ATTN_RLY;
+  else        ic7_memory &= ~(ATTN_RLY);
+  SRLoad(IC7, ic7_memory);
+}
+
+PUBLIC BOOL getXVTR_TR_Relay       (void) { return (ic7_memory & XVTR_TR_RLY) != 0; }
+PUBLIC BOOL setXVTR_TR_Relay (BOOL value) {
+  if (value)  ic7_memory |= XVTR_TR_RLY;
+  else        ic7_memory &= ~(XVTR_TR_RLY);
+  SRLoad(IC7, ic7_memory);
+}
+
+PUBLIC BOOL getXVTR_Relay       (void) { return (ic7_memory & XVTR_RLY) != 0; }
+PUBLIC BOOL setXVTR_Relay (BOOL value) {
+  if (value)  ic7_memory |= XVTR_RLY;
+  else        ic7_memory &= ~(XVTR_RLY);
+  SRLoad(IC7, ic7_memory);
+}
+
+PUBLIC BOOL getIMPULSE_Relay       (void) { return (ic7_memory & IMPULSE_RLY) != 0; }
+PUBLIC BOOL setIMPULSE_Relay (BOOL value) {
+  if (value)  ic7_memory |= IMPULSE_RLY;
+  else        ic7_memory &= ~(IMPULSE_RLY);
+  SRLoad(IC7, ic7_memory);
+}
+
+PUBLIC void Impulse(void) {
+  //Send a single impulse to the QSD
+  SRLoad(IC7, (ic7_memory | IMPULSE));
+  SRLoad(IC7, ic7_memory);
+}
+
+PUBLIC void PA_SetLPF(int i) {
+  int temp = ic11_memory;
+  switch(i) {
+    case PA_LPF_OFF:   // 0
+      ic11_memory &= ~(0x07);                          // clear bits 0, 1 and 2
+      break;
+    case PA_LPF_12_10: // 1
+      ic11_memory  = (ic11_memory | 0x01) & ~(0x06);   // set bit 0, clear bits 1,2
+      break;
+    case PA_LPF_17_15: // 2
+      ic11_memory  = (ic11_memory | 0x02) & ~(0x05);   // set bit 1, clear bits 0,2
+      break;
+    case PA_LPF_30_20: // 3
+      ic11_memory  = (ic11_memory | 0x03) & ~(0x04);   // set bits 0,1, clear bit 2
+      break;
+    case PA_LPF_60_40: // 4
+      ic11_memory  = (ic11_memory | 0x04) & ~(0x03);   // set bit 2, clear bits 0,1
+      break;
+    case PA_LPF_80:    // 5
+      ic11_memory  = (ic11_memory | 0x05) & ~(0x02);   // set bits 0,2, clear bit 1
+      break;
+    case PA_LPF_160:   // 6
+      ic11_memory  = (ic11_memory | 0x06) & ~(0x01);   // set bits 1,2, clear bit 0
+      break;
+    }
+  if (temp != ic11_memory)
+    SRLoad(IC11, ic11_memory);
+}
+
+PUBLIC BOOL getPA_TransmitRelay       (void) { return ((ic11_memory & PATR) != 0); }
+PUBLIC BOOL setPA_TransmitRelay (BOOL value) {
+  int temp = ic11_memory;
+  if (value) ic11_memory |= PATR;
+  else       ic11_memory &= ~(PATR);
+  if (temp != ic11_memory)
+    SRLoad(IC11, ic11_memory);
+}
+
+PUBLIC BOOL getPA_BiasOn       (void) { return ((ic7_memory & PA_BIAS_NOT) != 0); }
+PUBLIC BOOL setPA_BiasOn (BOOL value) {
+  int temp = ic7_memory;
+  if (value) ic7_memory &= ~(PA_BIAS_NOT);
+  else       ic7_memory |= PA_BIAS_NOT;
+  if (temp != ic7_memory)
+    SRLoad(IC7, ic7_memory);
+}
+
+PUBLIC BYTE PA_GetADC(int chan)        {
+  short num = 0;
+  int i;
+  // get ADC on amplifier
+  // 0 for forward power, 1 for reverse
+
+  if (usb_enabled) {
+    int data = USB_Sdr1kGetADC();
+    if (chan == 0) return (BYTE) (data & 255);
+    else           return (BYTE) (data >> 8);
+  }
+  
+  //dataline_mutex.WaitOne();
+  //parallel_mutex.WaitOne();
+  
+  ic11_memory &= ~(ADC_CS_NOT);                // CS not goes low
+  SRLoad(IC11, ic11_memory);
+  
+  ic11_memory |= ADC_DI;                               // set DI bit high for start bit
+  SRLoad(IC11, ic11_memory);
+  
+  ic11_memory |= ADC_CLK;                              // clock it into shift register
+  SRLoad(IC11, ic11_memory);
+  ic11_memory &= ~(ADC_CLK);
+  SRLoad(IC11, ic11_memory);
+  
+  // set DI bit high for single ended -- done since DI is already high
+  ic11_memory |= ADC_CLK;                              // clock it into shift register
+  SRLoad(IC11, ic11_memory);
+  ic11_memory &= ~(ADC_CLK);
+  SRLoad(IC11, ic11_memory);
+  
+  if (chan == PA_FORWARD_PWR) {
+    ic11_memory &= ~(ADC_DI);          // set DI bit low for Channel 0
+    SRLoad(IC11, ic11_memory);
+  } else {
+    // set DI bit high for Channel 1 -- done since DI is already high
+  }
+  
+  ic11_memory |= ADC_CLK;              // clock it into shift register
+  SRLoad(IC11, ic11_memory);
+  ic11_memory &= ~(ADC_CLK);
+  SRLoad(IC11, ic11_memory);
+  
+  for(i = 0; i < 8; i++) {             // read 15 bits out of DO
+    ic11_memory |= ADC_CLK;                    // clock high
+    SRLoad(IC11, ic11_memory);
+    ic11_memory &= ~(ADC_CLK);         // clock low
+    SRLoad(IC11, ic11_memory);
+      
+    if ((StatusPort() & (BYTE) PA_DATA) != 0)  // read DO 
+      num++;   // add bit              
+      
+    if (i != 7) num <<= 1;
+  }
+  
+  ic11_memory |= ADC_CS_NOT;           // CS not goes high
+  SRLoad(IC11, ic11_memory);
+  
+  //dataline_mutex.ReleaseMutex();
+  //parallel_mutex.ReleaseMutex();
+  
+  return (BYTE) (num);
+}
+
+PUBLIC BOOL PA_ATUTune(ATUTuneMode mode) {
+  int count = 0, delay = 0;
+
+  //dataline_mutex.WaitOne();
+
+  ic11_memory &= ~(ATUCTL);
+
+  SRLoad(IC11, ic11_memory);
+  switch (mode) {
+  case BYPASS: delay =  250; break;
+  case MEMORY: delay = 2000; break;
+  case FULL:   delay = 3250; break;
+  }
+  
+  Sleep(delay);
+  ic11_memory |= ATUCTL;
+  SRLoad(IC11, ic11_memory);
+  
+  if (mode == MEMORY || mode == FULL) {
+    while ((StatusPort() & (BYTE) PA_DATA) != 0)       { // wait for low output from ATU
+      Sleep(50);
+      if (count++ > 100) return FALSE;
+    }
+    count = 0;
+    while ((StatusPort() & (BYTE) PA_DATA) == 0)       { // wait for high output from ATU
+      Sleep(50);
+      if (count++ > 100) return FALSE;
+    }
+    Sleep(1000);
+  }
+  
+  //dataline_mutex.ReleaseMutex();
+  
+  return TRUE;
+}