Significant updates. Compiles and works, though not test significantly nor assumed to be particularly robust. I2C comms between Raduino and TeensyDSP. Some amount of functioning CAT. Haven't tried with any applications e.g. WSJT-X.
This commit is contained in:
parent
1bca18c3e1
commit
119902b1e0
1
Raduino/Debug.h
Symbolic link
1
Raduino/Debug.h
Symbolic link
|
@ -0,0 +1 @@
|
|||
../TeensyDSP/Debug.h
|
|
@ -337,7 +337,7 @@ byte delay_background(unsigned delayTime, byte fromType){ //fromType : 4 autoCWK
|
|||
return 1;
|
||||
|
||||
//Check PTT while auto Sending
|
||||
autoSendPTTCheck();
|
||||
//autoSendPTTCheck();
|
||||
|
||||
//Check_Cat(3);
|
||||
}
|
||||
|
@ -1449,6 +1449,7 @@ void setup()
|
|||
factory_alignment();
|
||||
#endif
|
||||
|
||||
rigState.begin();
|
||||
}
|
||||
|
||||
//Auto save Frequency and Mode with Protected eeprom life by KD8CEC
|
||||
|
@ -1473,8 +1474,6 @@ void checkAutoSaveFreqMode()
|
|||
saveCheckTime = 0; //for reduce cpu use rate
|
||||
}
|
||||
}
|
||||
|
||||
rigState.begin();
|
||||
}
|
||||
|
||||
void loop(){
|
||||
|
|
|
@ -296,7 +296,7 @@ void cwKeyer(void){
|
|||
return; //Tx stop control by Main Loop
|
||||
}
|
||||
|
||||
Check_Cat(2);
|
||||
//Check_Cat(2);
|
||||
} //end of while
|
||||
// } //end of elese
|
||||
}
|
||||
|
|
|
@ -994,7 +994,9 @@ char checkCountSMeter = 0;
|
|||
void idle_process()
|
||||
{
|
||||
// KC4UPR 2021-02-05 added update process for Raduino-TeensyDSP coordination
|
||||
rigState.update();
|
||||
rigState.send_RIGINF();
|
||||
delay(1);
|
||||
rigState.receive_RIGINF();
|
||||
//updateStateFromRaduino(rigState);
|
||||
//doRaduinoToTeensy(&rigState);
|
||||
//updateRaduinoFromState(rigState);
|
||||
|
|
|
@ -263,7 +263,7 @@ void menuCHMemory(int btn, byte isMemoryToVfo){
|
|||
}
|
||||
}
|
||||
|
||||
Check_Cat(0); //To prevent disconnections
|
||||
//Check_Cat(0); //To prevent disconnections
|
||||
} //end of while (knob)
|
||||
|
||||
if (selectChannel < 20 && selectChannel >= 0)
|
||||
|
@ -697,7 +697,7 @@ int getValueByKnob(int valueType, int targetValue, int minKnobValue, int maxKnob
|
|||
}
|
||||
}
|
||||
|
||||
Check_Cat(0); //To prevent disconnections
|
||||
//Check_Cat(0); //To prevent disconnections
|
||||
}
|
||||
|
||||
return targetValue;
|
||||
|
@ -1290,7 +1290,7 @@ void doMenu(){
|
|||
default :
|
||||
menuExit(btnState); break;
|
||||
} //end of switch
|
||||
Check_Cat(0); //To prevent disconnections
|
||||
//Check_Cat(0); //To prevent disconnections
|
||||
} //end of while
|
||||
|
||||
//****************************************************************************
|
||||
|
@ -1690,7 +1690,7 @@ void menuSetupCarrier(int btn){
|
|||
si5351bx_setfreq(0, usbCarrier);
|
||||
printCarrierFreq(usbCarrier);
|
||||
|
||||
Check_Cat(0); //To prevent disconnections
|
||||
//Check_Cat(0); //To prevent disconnections
|
||||
delay(100);
|
||||
}
|
||||
|
||||
|
|
BIN
Schematics/SW_Architecture.odg
Normal file
BIN
Schematics/SW_Architecture.odg
Normal file
Binary file not shown.
|
@ -28,18 +28,19 @@ UBitxDSP DSP;
|
|||
//static struct {
|
||||
|
||||
// GUItool: begin automatically generated code
|
||||
AudioInputUSB usbIn; //xy=227,290
|
||||
AudioInputI2S lineIn; //xy=235,182
|
||||
AudioAnalyzeRMS usbInRMS_R; //xy=350,380
|
||||
AudioAnalyzeRMS usbInRMS_L; //xy=409,341
|
||||
AudioAnalyzeRMS lineInRMS; //xy=461,222
|
||||
AudioMixer4 rxAudio; //xy=492,96
|
||||
AudioMixer4 txAudio; //xy=496,284
|
||||
AudioFilterFIR rxFilter; //xy=657,88
|
||||
AudioAmplifier usbOutAmp; //xy=822,84
|
||||
AudioAmplifier lineOutAmp; //xy=823,147
|
||||
AudioOutputI2S lineOut; //xy=1040,279
|
||||
AudioOutputUSB usbOut; //xy=1042,240
|
||||
AudioInputUSB usbIn; //xy=153,341
|
||||
AudioInputI2S lineIn; //xy=161,233
|
||||
AudioAnalyzeRMS usbInRMS_R; //xy=276,431
|
||||
AudioAnalyzeRMS usbInRMS_L; //xy=335,392
|
||||
AudioAnalyzeRMS lineInRMS; //xy=387,273
|
||||
AudioMixer4 rxAudio; //xy=418,147
|
||||
AudioMixer4 txAudio; //xy=422,335
|
||||
AudioFilterFIR rxFilter; //xy=583,139
|
||||
AudioAmplifier usbOutAmp; //xy=748,135
|
||||
AudioAmplifier lineOutAmp; //xy=749,198
|
||||
AudioAmplifier usbBypassAmp; //xy=756,261
|
||||
AudioOutputI2S lineOut; //xy=966,330
|
||||
AudioOutputUSB usbOut; //xy=968,291
|
||||
AudioConnection patchCord1(usbIn, 0, txAudio, 1);
|
||||
AudioConnection patchCord2(usbIn, 0, usbInRMS_L, 0);
|
||||
AudioConnection patchCord3(usbIn, 1, usbInRMS_R, 0);
|
||||
|
@ -47,13 +48,14 @@ AudioConnection patchCord4(lineIn, 0, rxAudio, 0);
|
|||
AudioConnection patchCord5(lineIn, 1, txAudio, 0);
|
||||
AudioConnection patchCord6(lineIn, 1, lineInRMS, 0);
|
||||
AudioConnection patchCord7(rxAudio, rxFilter);
|
||||
AudioConnection patchCord8(rxAudio, 0, usbOut, 1);
|
||||
AudioConnection patchCord8(rxAudio, usbBypassAmp);
|
||||
AudioConnection patchCord9(txAudio, 0, lineOut, 1);
|
||||
AudioConnection patchCord10(rxFilter, usbOutAmp);
|
||||
AudioConnection patchCord11(rxFilter, lineOutAmp);
|
||||
AudioConnection patchCord12(usbOutAmp, 0, usbOut, 0);
|
||||
AudioConnection patchCord13(lineOutAmp, 0, lineOut, 0);
|
||||
AudioControlSGTL5000 audioCtrl; //xy=501,425
|
||||
AudioConnection patchCord14(usbBypassAmp, 0, usbOut, 1);
|
||||
AudioControlSGTL5000 audioCtrl; //xy=427,476
|
||||
// GUItool: end automatically generated code
|
||||
|
||||
//} audio;
|
||||
|
@ -99,10 +101,11 @@ void UBitxDSP::begin() {
|
|||
// SETUP THE AUDIO OUTPUTS
|
||||
|
||||
// Line Output (RX)
|
||||
lineOutAmp.gain(0.0);
|
||||
lineOutAmp.gain(1.0);
|
||||
|
||||
// USB Output (RX)
|
||||
usbOutAmp.gain(0.0);
|
||||
usbOutAmp.gain(1.0);
|
||||
usbBypassAmp.gain(1.0);
|
||||
|
||||
// Rig (Line) Output (TX)
|
||||
|
||||
|
@ -123,6 +126,9 @@ void UBitxDSP::begin() {
|
|||
state.voxDelay[TX_USB_IN_R_VOX] = TX_USB_IN_R_VOX_DELAY;
|
||||
state.voxTimeout[TX_USB_IN_R_VOX] = 0;
|
||||
|
||||
// Setup the RX Filter.
|
||||
setRxFilter(300, 3000);
|
||||
|
||||
sinceLastUpdate = 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -8,11 +8,13 @@
|
|||
#define DBGPRINTLN(MSG) do { Serial.print("DBG: "); Serial.println(MSG); } while (0)
|
||||
#define DBGNEWLINE() do { Serial.println(); } while (0)
|
||||
#define DBGCMD(CMD) do { Serial.print("DBG: "); Serial.println(#CMD); CMD; } while (0)
|
||||
#define IFDEBUG(CMD) do { CMD; } while (0)
|
||||
#else
|
||||
#define DBGPRINT(MSG) do {} while (0)
|
||||
#define DBGPRINTLN(MSG) do {} while (0)
|
||||
#define DBGNEWLINE() do {} while (0)
|
||||
#define DBGCMD(CMD) do { CMD; } while (0)
|
||||
#define IFDEBUG(CMD) do {} while (0)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
|
@ -15,31 +15,31 @@ class UBitxRig {
|
|||
inline bool isVFOA() const { return radState.isVFOA(); }
|
||||
inline bool isVFOB() const { return radState.isVFOB(); }
|
||||
inline bool isSplit() const { return radState.isSplit(); }
|
||||
inline bool isRITOn() const { return radState.isRITOn(); }
|
||||
inline bool isXITOn() const { return radState.isXITOn(); }
|
||||
inline bool isModeCW() const { return radState.isCW() && radState.isUSB(); }
|
||||
inline bool isModeCWR() const { return radState.isCW() && radState.isLSB(); }
|
||||
inline bool isModeUSB() const { return radState.isUSB() && !radState.isCW(); }
|
||||
inline bool isModeLSB() const { return radState.isLSB() && !radState.isCW(); }
|
||||
inline bool isRIT() const { return radState.isRIT(); }
|
||||
inline bool isXIT() const { return radState.isXIT(); }
|
||||
inline bool isModeCWAny() const { return radState.isModeCWAny(); }
|
||||
inline bool isModeCW() const { return radState.isModeCW(); }
|
||||
inline bool isModeCWR() const { return radState.isModeCWR(); }
|
||||
inline bool isModeUSB() const { return radState.isModeUSB(); }
|
||||
inline bool isModeLSB() const { return radState.isModeLSB(); }
|
||||
inline bool isAI() const { return autoInfo; }
|
||||
|
||||
inline void setFreqA(unsigned freq) { catState.setFreqA(freq); }
|
||||
inline void setFreqB(unsigned freq) { catState.setFreqB(freq); }
|
||||
inline void setRIT(int freq) { catState.setRIT(freq); }
|
||||
inline void setXIT(int freq) { catState.setXIT(freq); }
|
||||
inline void selectVFOA() { catState.selectVFOA(); }
|
||||
inline void selectVFOB() { catState.selectVFOA(); }
|
||||
inline void toggleVFO() { catState.toggleVFO(); }
|
||||
inline void setVFOA() { catState.setVFOA(); }
|
||||
inline void setVFOB() { catState.setVFOB(); }
|
||||
inline void setSplitOn() { catState.setSplitOn(); }
|
||||
inline void setSplitOff() { catState.setSplitOff(); }
|
||||
inline void setRITOn() { catState.setRITOn(); }
|
||||
inline void setRITOff() { catState.setRITOff(); }
|
||||
inline void setXITOn() { catState.setXITOn(); }
|
||||
inline void setXITOff() { catState.setXITOff(); }
|
||||
inline void setModeCW() { catState.setUSB(); catState.setCW(); }
|
||||
inline void setModeCWR() { catState.setLSB(); catState.setCW(); }
|
||||
inline void setModeUSB() { catState.setUSB(); catState.setCW(); }
|
||||
inline void setModeLSB() { catState.setLSB(); catState.setCW(); }
|
||||
inline void setCW() { catState.setCW(); }
|
||||
inline void setCWR() { catState.setCWR(); }
|
||||
inline void setUSB() { catState.setUSB(); }
|
||||
inline void setLSB() { catState.setLSB(); }
|
||||
|
||||
inline void aiOn() { autoInfo = true; }
|
||||
inline void aiOff() { autoInfo = false; }
|
||||
|
|
|
@ -1,13 +1,62 @@
|
|||
#include ""
|
||||
/*!
|
||||
* @file RigState.cpp
|
||||
*
|
||||
* @mainpage uBITX V5X Software - RigState
|
||||
*
|
||||
* @section introsec Introduction
|
||||
*
|
||||
* TBD
|
||||
*
|
||||
* @section dependencies Dependencies
|
||||
*
|
||||
* TBD
|
||||
*
|
||||
* @section author Author
|
||||
*
|
||||
* Written by Rob "Scrape" French, KC4UPR
|
||||
*
|
||||
* @section license License
|
||||
*
|
||||
* TBD
|
||||
*/
|
||||
|
||||
/**********************************************************************/
|
||||
// Raduino externs -- generally defined in Raduino.ino or ubitx.h
|
||||
#include "Debug.h"
|
||||
#include "RigState.h"
|
||||
|
||||
/***********************************************************************
|
||||
* COMMON FUNCTIONS
|
||||
*
|
||||
* The following are all common to RigState objects, whether on the
|
||||
* Raduino or on the TeensyDSP.
|
||||
**********************************************************************/
|
||||
|
||||
static uint32_t zeroes[1] = {0}; // used to transmit zeroes
|
||||
|
||||
/*!
|
||||
* @brief Begin using the RigState object. In order to force an
|
||||
* initial update (i.e. sending current state to the remote
|
||||
* device), all fields are initially marked dirty.
|
||||
*/
|
||||
void UBitxRigState::begin() {
|
||||
setDirty();
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* RADUINO FUNCTIONS
|
||||
*
|
||||
* The following are specific to the Raduino implementation. Note that
|
||||
* this depends on the use of the TEENSYDUINO #define, which may result
|
||||
* in a fragile implementation for other development environments (e.g.
|
||||
* if the normal Arduino IDE is not being used).
|
||||
**********************************************************************/
|
||||
|
||||
#ifndef TEENSYDUINO
|
||||
|
||||
#include <Wire.h>
|
||||
#include "ubitx.h"
|
||||
#include "ubitx_eemap.h"
|
||||
|
||||
extern unsigned long frequency;
|
||||
extern unsigned long frequency, ritRxFrequency, ritTxFrequency;
|
||||
extern unsigned long vfoA;
|
||||
extern unsigned long vfoB;
|
||||
extern char cwMode;
|
||||
|
@ -15,48 +64,115 @@ extern char isUSB;
|
|||
extern char vfoActive;
|
||||
extern char ritOn;
|
||||
extern char splitOn;
|
||||
extern char inTx;
|
||||
void setFrequency(unsigned long);
|
||||
|
||||
/*!
|
||||
* @brief Write dirty fields from the provided rig state, out to the
|
||||
* Raduino variables.
|
||||
* @param r
|
||||
* Reference to a RigState object that will be used to update
|
||||
* the Raduino variables.
|
||||
* @brief Send the RigState from the Raduino to the TeensyDSP. The
|
||||
* basic process is: (1) read in any updated (dirty) data
|
||||
* from the Raduino's state variables; (2) transmit the dirty
|
||||
* data to the TeensyDSP; (2a) for clean data, zeroes are
|
||||
* transmitted; (3) mark all data as clean.
|
||||
*/
|
||||
void writeDirty(const RigState& r) {
|
||||
// VFO A frequency
|
||||
if (r.isDirty(VFOA_WORD)) {
|
||||
if (vfoActive == VFO_A) {
|
||||
setFrequency(r.getFreqA());
|
||||
void UBitxRigState::send_RIGINF() {
|
||||
readDirty();
|
||||
Wire.beginTransmission(I2CMETER_ADDR);
|
||||
Wire.write(I2CMETER_RIGINF);
|
||||
for (RigStateWord i = DIRTY_WORD; i < NUM_WORDS; i++) {
|
||||
if (i == DIRTY_WORD || isDirty(i)) {
|
||||
// always send the current dirty bits
|
||||
// or, bytes for updated (dirty) fields
|
||||
Wire.write((byte*)&data[i], sizeof(uint32_t));
|
||||
} else {
|
||||
vfoA = r.getFreqA();
|
||||
// otherwise, send out zeroes
|
||||
Wire.write((byte*)&zeroes, sizeof(uint32_t));
|
||||
//----------------------------------------------------------------
|
||||
// NOTE: I am sending these zeroed out fields under a possibly
|
||||
// mistaken assumption that in doing so, I will be sending a
|
||||
// constant voltage on the SDA line most of the time, i.e. no
|
||||
// bit changes, and so this will help reduce noise generated by
|
||||
// I2C traffic (since most of the time there will be no updates.)
|
||||
//----------------------------------------------------------------
|
||||
}
|
||||
}
|
||||
Wire.endTransmission();
|
||||
IFDEBUG( serialHexState("Sent") );
|
||||
//IFDEBUG( serialPrettyState("Sent") );
|
||||
setClean();
|
||||
}
|
||||
|
||||
// delay(1); // 1ms - some delay required between ending transmission and requesting?
|
||||
|
||||
/*!
|
||||
* @brief Receive the RigState from the TeensyDSP. This generally
|
||||
* reflects changes due to CAT transmission to the TeensyDSP.
|
||||
* @param numBytes
|
||||
* Number of bytes received from the TeensyDSP.
|
||||
*/
|
||||
void UBitxRigState::receive_RIGINF(int numBytes) {
|
||||
// Retrieve all of the deltas. Mark any received fields as dirty. It
|
||||
// is assumed that send_RIGINF() was called immedaitely before this,
|
||||
// so the fields are already clean.
|
||||
byte* ptr = (byte*)&data;
|
||||
Wire.requestFrom(I2CMETER_ADDR, sizeof(data));
|
||||
for (RigStateWord i = DIRTY_WORD; i < NUM_WORDS && Wire.available(); i++) {
|
||||
for (size_t j = 0; j < sizeof(uint32_t) && Wire.available(); j++) {
|
||||
byte incomingByte = Wire.read();
|
||||
if (i == DIRTY_WORD || isDirty(i)) {
|
||||
// always overwrite the dirty bits
|
||||
// and, update bytes for fields marked dirty
|
||||
*ptr = incomingByte;
|
||||
}
|
||||
ptr++;
|
||||
}
|
||||
}
|
||||
writeDirty();
|
||||
IFDEBUG( serialHexState("Rcvd") );
|
||||
//IFDEBUG( serialPrettyState("Rcvd") );
|
||||
setClean(); // They get marked dirty as req'd during readDirty().
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Write dirty fields from the RigState out to the Raduino
|
||||
* variables.
|
||||
*/
|
||||
void UBitxRigState::writeDirty() {
|
||||
// VFO A frequency
|
||||
if (isDirty(VFOA_WORD)) {
|
||||
if (vfoActive == VFO_A) {
|
||||
setFrequency(getFreqA());
|
||||
} else {
|
||||
vfoA = getFreqA();
|
||||
}
|
||||
}
|
||||
|
||||
// VFO B frequency
|
||||
if (r.isDirty(VFOB_WORD)) {
|
||||
if (isDirty(VFOB_WORD)) {
|
||||
if (vfoActive == VFO_B) {
|
||||
setFrequency(r.getFreqB());
|
||||
setFrequency(getFreqB());
|
||||
} else {
|
||||
vfoB = r.getFreqB();
|
||||
vfoB = getFreqB();
|
||||
}
|
||||
}
|
||||
|
||||
// RIT and XIT frequencies
|
||||
if (r.isDirty(OFFSETS_WORD)) {
|
||||
if (isDirty(OFFSETS_WORD)) {
|
||||
// RIT
|
||||
ritRxFrequency = r.getRIT() + ritTxFrequency;
|
||||
if ((ritOn == 1) && (inTx == 0)) {
|
||||
setFrequency(ritRxFrequency);
|
||||
ritRxFrequency = getRIT() + ritTxFrequency;
|
||||
if (ritOn == 1) {
|
||||
if (inTx == 0) {
|
||||
setFrequency(ritRxFrequency);
|
||||
} else {
|
||||
setFrequency(ritTxFrequency);
|
||||
}
|
||||
}
|
||||
// XIT - TODO
|
||||
}
|
||||
|
||||
// VFO A/B selection
|
||||
if (r.isDirty(FLAGS_WORD)) {
|
||||
if (isDirty(FLAGS_WORD)) {
|
||||
char prev = vfoActive;
|
||||
vfoActive = r.isVFOA() ? VFO_A : VFO_B;
|
||||
vfoActive = isVFOA() ? VFO_A : VFO_B;
|
||||
if (vfoActive != prev) {
|
||||
if (vfoActive == VFO_A) {
|
||||
if (vfoA != frequency) {
|
||||
|
@ -70,11 +186,11 @@ void writeDirty(const RigState& r) {
|
|||
}
|
||||
|
||||
// Split on/off
|
||||
splitOn = r.isSplit() ? 1 : 0;
|
||||
splitOn = isSplit() ? 1 : 0;
|
||||
|
||||
// RIT on/off
|
||||
prev = ritOn;
|
||||
ritOn = r.isRIT() ? 1 : 0;
|
||||
ritOn = isRIT() ? 1 : 0;
|
||||
if (ritOn != prev) {
|
||||
if ((ritOn == 1) && (inTx == 0)) {
|
||||
setFrequency(ritRxFrequency);
|
||||
|
@ -86,10 +202,10 @@ void writeDirty(const RigState& r) {
|
|||
|
||||
// Mode
|
||||
prev = (cwMode << 1) | isUSB;
|
||||
isUSB = r.isUSB() ? 1 : 0;
|
||||
if (r.isCW()) {
|
||||
isUSB = isModeUSB() ? 1 : 0;
|
||||
if (isModeCW()) {
|
||||
cwMode = 2; // 2 = cwu
|
||||
} else if (r.isCWR()) {
|
||||
} else if (isModeCWR()) {
|
||||
cwMode = 1; // 1 = cwl
|
||||
} else {
|
||||
cwMode = 0; // 0 = no cw
|
||||
|
@ -101,274 +217,200 @@ void writeDirty(const RigState& r) {
|
|||
}
|
||||
|
||||
/*!
|
||||
* @brief Read current Raduino variables into the provided RigState
|
||||
* (if they are dirty) and set the appropriate dirty flags.
|
||||
* @brief Read current Raduino variables into the RigState
|
||||
* (if they are changed) and set the appropriate dirty flags.
|
||||
* @param r
|
||||
* RigState reference to put the values into.
|
||||
*/
|
||||
void readDirty(RigState& r) {
|
||||
unsigned freq;
|
||||
void UBitxRigState::readDirty() {
|
||||
unsigned long freq;
|
||||
short offset;
|
||||
|
||||
// VFO A frequency
|
||||
freq = (vfoActive == VFO_A) ? frequency : vfoA;
|
||||
if (r.getFreqA() != freq) {
|
||||
r.setFreqA(freq);
|
||||
r.setDirty(VFOA_WORD);
|
||||
if (getFreqA() != freq) {
|
||||
setFreqA(freq);
|
||||
}
|
||||
|
||||
// VFO B frequency
|
||||
freq = (vfoActive == VFO_B) ? frequency : vfoB;
|
||||
if (r.getFreqB() != freq) {
|
||||
r.setFreqB(freq);
|
||||
r.setDirty(VFOB_WORD);
|
||||
if (getFreqB() != freq) {
|
||||
setFreqB(freq);
|
||||
}
|
||||
|
||||
// RIT frequency
|
||||
offset = ritRxFrequency - frequency;
|
||||
if (r.getRIT() != offset) {
|
||||
r.setRIT(offset);
|
||||
r.setDirty(OFFSETS_WORD);
|
||||
if (inTx) {
|
||||
offset = ritRxFrequency - ritTxFrequency;
|
||||
} else {
|
||||
offset = frequency - ritTxFrequency;
|
||||
}
|
||||
if (getRIT() != offset) {
|
||||
setRIT(offset);
|
||||
}
|
||||
|
||||
// XIT frequency
|
||||
offset = 0; // xitRxFrequency - frequency;
|
||||
if (r.getXIT() != offset) {
|
||||
r.setXIT(offset);
|
||||
r.setDirty(OFFSETS_WORD);
|
||||
if (getXIT() != offset) {
|
||||
setXIT(offset);
|
||||
}
|
||||
|
||||
bool dirty = false;
|
||||
|
||||
|
||||
// VFO A/B selection
|
||||
if (r.isVFOA() && vfoActive == VFO_B) {
|
||||
r.setVFOB();
|
||||
dirty = true;
|
||||
} else if (r.isVFOB() && vfoActive == VFO_A) {
|
||||
r.setVFOA();
|
||||
dirty = true;
|
||||
if (isVFOA() && vfoActive == VFO_B) {
|
||||
setVFOB();
|
||||
} else if (isVFOB() && vfoActive == VFO_A) {
|
||||
setVFOA();
|
||||
}
|
||||
|
||||
// Split selection
|
||||
if (r.isSplit() && splitOn == 0) {
|
||||
r.setSplitOff();
|
||||
dirty = true;
|
||||
} else if (!r.isSplit() && splitOn != 0) {
|
||||
r.setSplitOn();
|
||||
dirty = true;
|
||||
if (isSplit() && splitOn == 0) {
|
||||
setSplitOff();
|
||||
} else if (!isSplit() && splitOn != 0) {
|
||||
setSplitOn();
|
||||
}
|
||||
|
||||
// RIT selection
|
||||
if (r.isRIT() && ritOn == 0) {
|
||||
r.setRITOff();
|
||||
dirty = true;
|
||||
} else if (!r.isRIT() && ritOn != 0) {
|
||||
r.setRITOn();
|
||||
dirty = true;
|
||||
if (isRIT() && ritOn == 0) {
|
||||
setRITOff();
|
||||
} else if (!isRIT() && ritOn != 0) {
|
||||
setRITOn();
|
||||
}
|
||||
|
||||
// XIT selection
|
||||
r.setXITOff();
|
||||
//setXITOff();
|
||||
// TODO
|
||||
|
||||
// Mode
|
||||
char prev = (r.isCW() ? 4 : 0) | (r.isCWR() ? 2 : 0) | (r.isUSB() ? 1 : 0);
|
||||
char prev = (isModeCW() ? 4 : 0) | (isModeCWR() ? 2 : 0) | (isModeUSB() ? 1 : 0);
|
||||
char curr = (cwMode << 1) | isUSB;
|
||||
if (curr != prev) {
|
||||
if (cwMode == 2) {
|
||||
r.setCW();
|
||||
setCW();
|
||||
} else if (cwMode == 1) {
|
||||
r.setCWR();
|
||||
setCWR();
|
||||
} else {
|
||||
if (isUSB) {
|
||||
r.setUSB();
|
||||
setUSB();
|
||||
} else {
|
||||
r.setLSB();
|
||||
setLSB();
|
||||
}
|
||||
}
|
||||
dirty = true;
|
||||
}
|
||||
|
||||
if (dirty) r.setDirty(FLAGS_WORD);
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* TEENSYDSP FUNCTIONS
|
||||
*
|
||||
* The following are specific to the TeensyDSP implementation. Note
|
||||
* that this depends on the use of the TEENSYDUINO #define, which may
|
||||
* result in a fragile implementation for other development environments
|
||||
* (e.g. if the normal Arduino IDE is not being used).
|
||||
**********************************************************************/
|
||||
|
||||
#else
|
||||
|
||||
#include <i2c_t3.h>
|
||||
|
||||
/*!
|
||||
* @brief Receive RIGINF data from the Raduino. This method should
|
||||
* be called on the TeensyDSP 'radState' (Raduino state)
|
||||
* instance, when a RIGINF signal is received via I2C. It
|
||||
* receives the incoming data from the Raduino and updates the
|
||||
* state.
|
||||
*/
|
||||
void UBitxRigState::receive_RIGINF(int numBytes) {
|
||||
byte* ptr = (byte*)&data;
|
||||
setClean(); // we'll get new dirty bits via the I2C message
|
||||
for (RigStateWord i = DIRTY_WORD; i < NUM_WORDS && Wire1.available(); i++) {
|
||||
for (size_t j = 0; j < sizeof(uint32_t) && Wire1.available(); j++) {
|
||||
byte incomingByte = Wire1.read();
|
||||
if (i == DIRTY_WORD || isDirty(i)) {
|
||||
// always overwrite the dirty bits
|
||||
// and, update bytes for fields marked dirty
|
||||
*ptr = incomingByte;
|
||||
}
|
||||
ptr++;
|
||||
}
|
||||
}
|
||||
|
||||
IFDEBUG( serialHexState("Rcvd") );
|
||||
IFDEBUG( serialPrettyState("Rcvd") );
|
||||
}
|
||||
|
||||
/**********************************************************************/
|
||||
/*!
|
||||
* @brief Handle a RIGINF signal from the Raduino. This method should
|
||||
* be called on the TeensyDSP 'catState' (CAT state)
|
||||
* instance, when a RIGINF signal is received via I2C. It
|
||||
* sends a response to the Raduino via I2C, using the Wire1
|
||||
* interface.
|
||||
*/
|
||||
void UBitxRigState::send_RIGINF() {
|
||||
for (RigStateWord i = DIRTY_WORD; i < NUM_WORDS; i++) {
|
||||
if (i == DIRTY_WORD || isDirty(i)) {
|
||||
// always send the current dirty bits
|
||||
// or, bytes for updated (dirty) fields
|
||||
Wire1.write((byte*)&data[i], sizeof(uint32_t));
|
||||
} else {
|
||||
// otherwise, send out zeroes
|
||||
Wire1.write((byte*)&zeroes, sizeof(uint32_t));
|
||||
//----------------------------------------------------------------
|
||||
// NOTE: I am sending these zeroed out fields under a possibly
|
||||
// mistaken assumption that in doing so, I will be sending a
|
||||
// constant voltage on the SDA line most of the time, i.e. no
|
||||
// bit changes, and so this will help reduce noise generated by
|
||||
// I2C traffic (since most of the time there will be no updates.)
|
||||
//----------------------------------------------------------------
|
||||
}
|
||||
}
|
||||
IFDEBUG( serialHexState("Sent") );
|
||||
IFDEBUG( serialPrettyState("Sent") );
|
||||
setClean(); // now that we've sent them, they're clean
|
||||
//--------------------------------------------------------------------
|
||||
// TODO: Need to look at possibly merging the two states together at
|
||||
// this point. The purpose would be to minimize the turnaround time
|
||||
// for getting the most recent data to a CAT response.
|
||||
//--------------------------------------------------------------------
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/**********************************************************************/
|
||||
#ifdef DEBUG
|
||||
|
||||
BaseField* raduinoFields[WIREBUS_NUM_FIELDS] = {
|
||||
new Field<readNone, writeNone>(),
|
||||
new Field<readVFOA, writeVFOA>(),
|
||||
new Field<readVFOB, writeVFOB>(),
|
||||
new Field<readRIT, writeRIT>(),
|
||||
new Field<readXIT, writeXIT>(),
|
||||
new Field<readFlags, writeFlags>(),
|
||||
};
|
||||
char debugString[81] = {'\0'};
|
||||
|
||||
/**********************************************************************/
|
||||
|
||||
RigState::RigState(): RigState(raduinoFields, WIREBUS_NUM_FIELDS) {}
|
||||
|
||||
/*!
|
||||
* @brief Begin using the RigState object. In order to force an
|
||||
* update (e.g. sending current state to the remote device),
|
||||
* all fields are marked dirty.
|
||||
*/
|
||||
void RigState::begin() {
|
||||
for (byte i = 0; i < numFields; i++) {
|
||||
if (read(i)) {
|
||||
makeDirty(i);
|
||||
}
|
||||
}
|
||||
void UBitxRigState::serialHexState(const char* label = "RigState") {
|
||||
Serial.print(label);
|
||||
sprintf(debugString, ": %#010lx, %#010lx, %#010lx, %#010lx, %#010lx",
|
||||
data[DIRTY_WORD], data[VFOA_WORD], data[VFOB_WORD], data[OFFSETS_WORD], data[FLAGS_WORD]);
|
||||
Serial.println(debugString);
|
||||
}
|
||||
|
||||
void updateRaduinoState(RigState& r) {
|
||||
writeDirty(r);
|
||||
Wire.beginTransmission(I2CMETER_ADDR);
|
||||
Wire.write(I2CMETER_RIGINF);
|
||||
for (RigStateWord i = 0; i < NUM_WORDS; i++) {
|
||||
Wire.write((byte*)&r.data, sizeof(r.data)); // - write the field data
|
||||
r.setClean(i);
|
||||
}
|
||||
Wire.endTransmission();
|
||||
|
||||
delay(1); // 1ms - some delay required between ending transmission and requesting?
|
||||
|
||||
// Retrieve all of the deltas. Mark any received field as dirty.
|
||||
Wire.requestFrom(I2CMETER_ADDR, numBytes);
|
||||
bool doRead = true;
|
||||
int index = -1;
|
||||
byte* ptr;
|
||||
while (Wire.available()) {
|
||||
byte b = Wire.read();
|
||||
if (index == -1) {
|
||||
if (numFields > b) {
|
||||
ptr = data(b);
|
||||
field[b].dirty = true;
|
||||
numDirty++;
|
||||
index = 0;
|
||||
} else {
|
||||
doRead = false;
|
||||
}
|
||||
} else {
|
||||
if (doRead) {
|
||||
ptr[index] = b;
|
||||
}
|
||||
if (++index == 4) {
|
||||
index = -1;
|
||||
doRead = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Perform the corresponding update for each dirty field.
|
||||
for (byte i = 0; i < numFields; i++) {
|
||||
if (field[i].dirty) {
|
||||
write(i);
|
||||
field[i].dirty = false;
|
||||
numDirty--;
|
||||
}
|
||||
}
|
||||
void UBitxRigState::serialPrettyState(const char* label = "RigState") {
|
||||
Serial.println(label);
|
||||
sprintf(debugString, "VFO A : %011ld %1c / VFO B : %011ld %1c",
|
||||
getFreqA(), isDirty(VFOA_WORD) ? 'D' : ' ', getFreqB(), isDirty(VFOB_WORD) ? 'D' : ' ');
|
||||
Serial.println(debugString);
|
||||
sprintf(debugString, "RIT : %011ld %1c / XIT : %011ld %1c",
|
||||
getRIT(), isDirty(OFFSETS_WORD) ? 'D' : ' ', getXIT(), isDirty(OFFSETS_WORD) ? 'D' : ' ');
|
||||
Serial.println(debugString);
|
||||
sprintf(debugString, "Split? %1c / VFO? %1c / RIT? %1c / XIT? %1c / Mode? %3s",
|
||||
isSplit() ? 'Y' : 'N', isVFOA() ? 'A' : 'B', isRIT() ? 'Y' : 'N', isXIT() ? 'Y' : 'N',
|
||||
isModeUSB() ? "USB" : (isModeLSB() ? "LSB" : (isModeCW() ? "CW " : (isModeCWR() ? "CWR" : " "))));
|
||||
Serial.println(debugString);
|
||||
}
|
||||
|
||||
/**********************************************************************/
|
||||
/*!
|
||||
* @brief Handle a RIGINF signal from the Raduino. This method should
|
||||
* be called on the TeensyDSP 'radState' (Raduino state)
|
||||
* instance, when a RIGINF signal is received via I2C. It
|
||||
* receives the incoming data from the Raduino.
|
||||
*/
|
||||
void RigState::receive_RIGINF() {
|
||||
// 1st (-1) byte read should be a field index.
|
||||
// 2nd (0) thru 5th (3) bytes are bytes of the field.
|
||||
// We'll read as many fields as the Raduino sends.
|
||||
bool doRead = true;
|
||||
int index = -1;
|
||||
byte* ptr;
|
||||
while (Wire1.available()) {
|
||||
byte b = Wire1.read();
|
||||
if (index == -1) {
|
||||
if (numFields > b) {
|
||||
ptr = data(b);
|
||||
makeDirty(b);
|
||||
index = 0;
|
||||
} else {
|
||||
doRead = false;
|
||||
}
|
||||
} else {
|
||||
if (doRead) {
|
||||
ptr[index] = b;
|
||||
}
|
||||
if (++index == 4) {
|
||||
index = -1;
|
||||
doRead = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/**********************************************************************/
|
||||
/*!
|
||||
* @brief Handle a RIGINF signal from the Raduino. This method should
|
||||
* be called on the TeensyDSP 'radState' (Raduino state)
|
||||
* instance, when a RIGINF signal is received via I2C. It
|
||||
* sends a response to the Raduino
|
||||
*/
|
||||
void RigState::send_RIGINF(byte numBytes, RigState& catState) {
|
||||
// Now we need to determine the differences from the other state (i.e.
|
||||
// from the catState) and send those differences.
|
||||
byte rigRegBytes = 0;
|
||||
for (byte i = 0; i < numFields; i++) {
|
||||
if (isDirty(i) && !catState.isDirty(i)) {
|
||||
catState.field[i]->data = field[i]->data;
|
||||
makeClean(i);
|
||||
} else if (catState.isDirty(i)) {
|
||||
field[i]->data = catState.field[i]->data;
|
||||
makeClean(i);
|
||||
rigRegBytes += (sizeof(byte) + sizeof(uint32_t)); // size of field ID and data
|
||||
}
|
||||
}
|
||||
|
||||
for (byte i = 0; i < numBytes; i++) {
|
||||
Wire1.write(rigReqBytes);
|
||||
}
|
||||
}
|
||||
|
||||
/**********************************************************************/
|
||||
/*!
|
||||
* @brief Handle a RIGREQ signal from the Raduino. This method should
|
||||
* be called on the TeensyDSP 'catState' (CAT state) instance,
|
||||
* when a RIGREQ signal is received via I2C. It handles
|
||||
* sending the changed fields.
|
||||
*/
|
||||
void RigState::respondRIGREQ(byte numBytes) {
|
||||
byte bytesSent = 0;
|
||||
|
||||
for (byte i = 0; i < numFields; i++) {
|
||||
if (isDirty(i) && (dataSize(i) + sizeof(byte) <= numBytes - bytesSent)) { // Write each field that is dirty to the bus.
|
||||
Wire1.write(i); // - write the field number/ID
|
||||
Wire1.write(data(i), dataSize(i)); // - write the field data
|
||||
makeClean(i);
|
||||
bytesSent += dataSize(i) + sizeof(byte);
|
||||
}
|
||||
}
|
||||
|
||||
// Don't know if this is necessary, but if we haven't written enough
|
||||
// bytes yet, we'll write out some zeroes.
|
||||
for (byte i = bytesSent; i < numBytes; i++) {
|
||||
Wire1.write(0);
|
||||
}
|
||||
}
|
||||
|
||||
/**********************************************************************/
|
||||
|
||||
#ifndef TEENSYDUINO
|
||||
|
||||
RigState rigState;
|
||||
UBitxRigState _rigState;
|
||||
UBitxRigState& rigState = _rigState;
|
||||
|
||||
#endif
|
||||
|
||||
/**********************************************************************
|
||||
* EOF *
|
||||
/***********************************************************************
|
||||
* EOF
|
||||
**********************************************************************/
|
||||
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
/*!
|
||||
* @file RigState.h
|
||||
*/
|
||||
|
||||
#ifndef __RigState_h__
|
||||
#define __RigState_h__
|
||||
|
||||
|
@ -11,6 +15,12 @@
|
|||
#define UBITX_USB_FLAG 0x00000020
|
||||
#define UBITX_TX_FLAG 0x00000040
|
||||
|
||||
#ifdef TEENSYDUINO
|
||||
#define DISABLEINTS(CMD) do { noInterrupts(); CMD; interrupts(); } while (0)
|
||||
#else
|
||||
#define DISABLEINTS(CMD) do { CMD; } while (0)
|
||||
#endif
|
||||
|
||||
enum RigStateWord {
|
||||
DIRTY_WORD = 0,
|
||||
VFOA_WORD,
|
||||
|
@ -20,174 +30,307 @@ enum RigStateWord {
|
|||
NUM_WORDS
|
||||
};
|
||||
|
||||
inline RigStateWord& operator++(RigStateWord& orig) {
|
||||
orig = static_cast<RigStateWord>(orig + 1);
|
||||
// NOTE: Will overflow...
|
||||
return orig;
|
||||
}
|
||||
|
||||
inline RigStateWord operator++(RigStateWord& orig, int) {
|
||||
RigStateWord rVal = orig;
|
||||
++orig;
|
||||
return rVal;
|
||||
}
|
||||
|
||||
struct UBitxRigState {
|
||||
uint32_t data[RigStateWord.NUM_WORDS] = {0};
|
||||
volatile uint32_t data[NUM_WORDS] = {0};
|
||||
|
||||
void begin();
|
||||
|
||||
void send_RIGINF();
|
||||
void receive_RIGINF(int numBytes = sizeof(data));
|
||||
|
||||
/*!
|
||||
* @brief Set the dirty bit for for the specified word.
|
||||
* @brief Set the dirty bit for the specified word.
|
||||
*
|
||||
* @param w
|
||||
* The word to mark as dirty.
|
||||
*/
|
||||
inline void setDirty(RigStateWord w) {
|
||||
data[i] |= w < NUM_WORDS ? 1 << w : 0;
|
||||
data[DIRTY_WORD] |= w < NUM_WORDS ? 1 << w : 0;
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Set the dirty bits for all words.
|
||||
*/
|
||||
inline void setDirty() { DISABLEINTS( data[DIRTY_WORD] = 0xFFFFFFFF ); }
|
||||
|
||||
/*!
|
||||
* @brief Clear the dirty bit for the specified word.
|
||||
*
|
||||
* @param w
|
||||
* The word to mark as clean.
|
||||
*/
|
||||
inline void setClean(RigStateWord w) {
|
||||
data[i] &= ~(w < NUM_WORDS ? 1 << w : 0);
|
||||
data[DIRTY_WORD] &= ~(w < NUM_WORDS ? 1 << w : 0);
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Clear the dirty bits for all words.
|
||||
*/
|
||||
inline void setClean() { DISABLEINTS( data[DIRTY_WORD] = 0 ); }
|
||||
|
||||
/*!
|
||||
* @brief Check whether the specified word is clean.
|
||||
*
|
||||
* @param w
|
||||
* The word to check for clean status.
|
||||
*
|
||||
* @return True if the word is clean.
|
||||
*/
|
||||
inline bool isClean(RigStateWord w) {
|
||||
bool clean;
|
||||
DISABLEINTS( clean = ((1 << w) & data[DIRTY_WORD]) > 0 ? false : true );
|
||||
return clean;
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Check whether the data is clean (as a whole).
|
||||
*
|
||||
* @return True if the data is clean (no dirty fields).
|
||||
*/
|
||||
inline bool isClean() {
|
||||
bool clean;
|
||||
DISABLEINTS( clean = data[DIRTY_WORD] == 0 );
|
||||
return clean;
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Check whether the specified word is dirty.
|
||||
*
|
||||
* @param w
|
||||
* The word to check for dirty status.
|
||||
*
|
||||
* @return True if the word is dirty.
|
||||
*/
|
||||
inline bool isDirty(RigStateWord w) {
|
||||
return (1 << w) & data[DIRTY_WORD] > 0 ? true : false;
|
||||
bool dirty;
|
||||
DISABLEINTS( dirty = ((1 << w) & data[DIRTY_WORD]) > 0 ? true : false );
|
||||
return dirty;
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Check whether the data is dirty (as a whole).
|
||||
*
|
||||
* @return True if the data is dirty (at least one dirty field).
|
||||
*/
|
||||
inline bool isDirty() {
|
||||
bool dirty;
|
||||
DISABLEINTS( dirty = data[DIRTY_WORD] != 0 );
|
||||
return dirty;
|
||||
}
|
||||
|
||||
inline void setFreqA(uint32_t freq) { data[VFOA_WORD] = freq; }
|
||||
inline uint32_t getFreqA() const { return data[VFOA_WORD]; }
|
||||
inline void getFreqB(uint32_r freq) { data[VFOB_WORD] = freq; }
|
||||
inline uint32_t getFreqB() const { return data[VFOB_WORD]; }
|
||||
inline void setRIT(int16_t offset) { data[OFFSETS_WORD] = (offset << 16) | (0x0000FFFF & data[OFFSETS_WORD]); }
|
||||
inline int16_t getRIT() const { return data[OFFSETS_WORD] >> 16; }
|
||||
inline void setXIT(int16_t offset) { data[OFFSETS_WORD] = (0xFFFF0000 & data[OFFSETS_WORD]) | offset;
|
||||
inline int16_t getXIT() const { return 0x0000FFFF & data[OFFSETS_WORD]; }
|
||||
inline void setVFOA() { data[FLAGS_WORD] &= ~UBITX_VFOB_FLAG; }
|
||||
inline void setVFOB() { data[FLAGS_WORD] |= UBITX_VFOB_FLAG; }
|
||||
inline bool isVFOA() const { return data[FLAGS_WORD] & UBITX_VFOB_FLAG ? false : true; }
|
||||
inline bool isVFOB() const { return data[FLAGS_WORD] & UBITX_VFOB_FLAG ? true : false; }
|
||||
inline void setSplitOn() { data[FLAGS_WORD] |= UBITX_SPLIT_FLAG; }
|
||||
inline void setSplitOff() { data[FLAGS_WORD] &= ~UBITX_SPLIT_FLAG; }
|
||||
inline bool isSplit() const { data[FLAGS_WORD] & UBITX_SPLIT_FLAG ? true : false; }
|
||||
inline void setRITOn() { data[FLAGS_WORD] |= UBITX_RIT_FLAG; }
|
||||
inline void setRITOff() { data[FLAGS_WORD] &= ~UBITX_RIT_FLAG; }
|
||||
inline bool isRIT() const { data[FLAGS_WORD] & UBITX_RIT_FLAG ? true : false; }
|
||||
inline void setXITOn() { data[FLAGS_WORD] |= UBITX_XIT_FLAG; }
|
||||
inline void setXITOff() { data[FLAGS_WORD] &= ~UBITX_XIT_FLAG; }
|
||||
inline bool isXIT() const { data[FLAGS_WORD] & UBITX_XIT_FLAG ? true : false; }
|
||||
inline void setUSB() { data[FLAGS_WORD] |= UBITX_USB_FLAG; data[FLAGS_WORD] &= ~UBITX_CW_FLAG; }
|
||||
inline void setLSB() { data[FLAGS_WORD] &= ~UBITX_USB_FLAG; data[FLAGS_WORD] &= ~UBITX_CW_FLAG; }
|
||||
inline void setCW() { data[FLAGS_WORD] |= UBITX_USB_FLAG; data[FLAGS_WORD] |= UBITX_CW_FLAG; }
|
||||
inline void setCWR() { data[FLAGS_WORD] &= ~UBITX_USB_FLAG; data[FLAGS_WORD] |= UBITX_CW_FLAG; }
|
||||
inline bool isUSB() { return (data[FLAGS_WORD] & UBITX_USB_FLAG > 0) && (data[FLAGS_WORD] & UBITX_CW_FLAG == 0); }
|
||||
inline bool isLSB() { return (data[FLAGS_WORD] & UBITX_USB_FLAG == 0) && (data[FLAGS_WORD] & UBITX_CW_FLAG == 0); }
|
||||
inline bool isCW() { return (data[FLAGS_WORD] & UBITX_USB_FLAG > 0) && (data[FLAGS_WORD] & UBITX_CW_FLAG > 0); }
|
||||
inline bool isCWR() { return (data[FLAGS_WORD] & UBITX_USB_FLAG == 0) && (data[FLAGS_WORD] & UBITX_CW_FLAG > 0); }
|
||||
};
|
||||
/*!
|
||||
* @brief Set the VFO A frequency.
|
||||
*
|
||||
* @param freq
|
||||
* The new frequency in Hz.
|
||||
*/
|
||||
inline void setFreqA(uint32_t freq, bool mark = true) {
|
||||
DISABLEINTS( data[VFOA_WORD] = freq;
|
||||
if (mark) setDirty(VFOA_WORD) );
|
||||
}
|
||||
|
||||
inline uint32_t getFreqA() const {
|
||||
uint32_t result;
|
||||
DISABLEINTS( result = data[VFOA_WORD] );
|
||||
return result;
|
||||
}
|
||||
|
||||
#ifndef TEENSYDUINO
|
||||
void mergeDirty(const RigState& r);
|
||||
/*!
|
||||
* @brief Set the VFO B frequency.
|
||||
*
|
||||
* @param freq
|
||||
* The new frequency in Hz.
|
||||
*/
|
||||
inline void setFreqB(uint32_t freq, bool mark = true) {
|
||||
DISABLEINTS( data[VFOB_WORD] = freq );
|
||||
}
|
||||
|
||||
inline uint32_t getFreqB() const {
|
||||
uint32_t result;
|
||||
DISABLEINTS( result = data[VFOB_WORD] );
|
||||
return result;
|
||||
}
|
||||
|
||||
inline void setRIT(int16_t offset, bool mark = true) {
|
||||
DISABLEINTS( data[OFFSETS_WORD] = (int32_t(offset) << 16) | (0x0000FFFF & data[OFFSETS_WORD]);
|
||||
if (mark) setDirty(OFFSETS_WORD) );
|
||||
}
|
||||
|
||||
inline int16_t getRIT() const {
|
||||
int16_t result;
|
||||
DISABLEINTS( result = data[OFFSETS_WORD] >> 16 );
|
||||
return result;
|
||||
}
|
||||
|
||||
inline void setXIT(int16_t offset, bool mark = true) {
|
||||
DISABLEINTS( data[OFFSETS_WORD] = (0xFFFF0000 & data[OFFSETS_WORD]) | offset;
|
||||
if (mark) setDirty(OFFSETS_WORD) );
|
||||
}
|
||||
|
||||
inline int16_t getXIT() const {
|
||||
int16_t result;
|
||||
DISABLEINTS( result = 0x0000FFFF & data[OFFSETS_WORD] );
|
||||
return result;
|
||||
}
|
||||
|
||||
inline void setVFOA(bool mark = true) {
|
||||
DISABLEINTS( data[FLAGS_WORD] &= ~UBITX_VFOB_FLAG;
|
||||
if (mark) setDirty(FLAGS_WORD) );
|
||||
}
|
||||
|
||||
inline void setVFOB(bool mark = true) {
|
||||
DISABLEINTS( data[FLAGS_WORD] |= UBITX_VFOB_FLAG;
|
||||
if (mark) setDirty(FLAGS_WORD) );
|
||||
}
|
||||
|
||||
inline bool isVFOA() const {
|
||||
bool result;
|
||||
DISABLEINTS( result = data[FLAGS_WORD] & UBITX_VFOB_FLAG ? false : true );
|
||||
return result;
|
||||
}
|
||||
|
||||
inline bool isVFOB() const {
|
||||
bool result;
|
||||
DISABLEINTS( result = data[FLAGS_WORD] & UBITX_VFOB_FLAG ? true : false );
|
||||
return result;
|
||||
}
|
||||
|
||||
inline void setSplitOn(bool mark = true) {
|
||||
DISABLEINTS( data[FLAGS_WORD] |= UBITX_SPLIT_FLAG;
|
||||
if (mark) setDirty(FLAGS_WORD) );
|
||||
}
|
||||
|
||||
inline void setSplitOff(bool mark = true) {
|
||||
DISABLEINTS( data[FLAGS_WORD] &= ~UBITX_SPLIT_FLAG;
|
||||
if (mark) setDirty(FLAGS_WORD) );
|
||||
}
|
||||
|
||||
inline bool isSplit() const {
|
||||
bool result;
|
||||
DISABLEINTS( result = data[FLAGS_WORD] & UBITX_SPLIT_FLAG ? true : false );
|
||||
return result;
|
||||
}
|
||||
|
||||
inline void setRITOn(bool mark = true) {
|
||||
DISABLEINTS( data[FLAGS_WORD] |= UBITX_RIT_FLAG;
|
||||
if (mark) setDirty(FLAGS_WORD) );
|
||||
}
|
||||
|
||||
inline void setRITOff(bool mark = true) {
|
||||
DISABLEINTS( data[FLAGS_WORD] &= ~UBITX_RIT_FLAG;
|
||||
if (mark) setDirty(FLAGS_WORD) );
|
||||
}
|
||||
|
||||
inline bool isRIT() const {
|
||||
bool result;
|
||||
DISABLEINTS( result = data[FLAGS_WORD] & UBITX_RIT_FLAG ? true : false );
|
||||
return result;
|
||||
}
|
||||
|
||||
inline void setXITOn(bool mark = true) {
|
||||
DISABLEINTS( data[FLAGS_WORD] |= UBITX_XIT_FLAG;
|
||||
if (mark) setDirty(FLAGS_WORD) );
|
||||
}
|
||||
|
||||
inline void setXITOff(bool mark = true) {
|
||||
DISABLEINTS( data[FLAGS_WORD] &= ~UBITX_XIT_FLAG;
|
||||
if (mark) setDirty(FLAGS_WORD) );
|
||||
}
|
||||
|
||||
inline bool isXIT() const {
|
||||
bool result;
|
||||
DISABLEINTS( result = data[FLAGS_WORD] & UBITX_XIT_FLAG ? true : false );
|
||||
return result;
|
||||
}
|
||||
|
||||
inline void setUSB(bool mark = true) {
|
||||
DISABLEINTS( data[FLAGS_WORD] |= UBITX_USB_FLAG;
|
||||
data[FLAGS_WORD] &= ~UBITX_CW_FLAG;
|
||||
if (mark) setDirty(FLAGS_WORD) );
|
||||
}
|
||||
|
||||
inline void setLSB(bool mark = true) {
|
||||
DISABLEINTS( data[FLAGS_WORD] &= ~UBITX_USB_FLAG;
|
||||
data[FLAGS_WORD] &= ~UBITX_CW_FLAG;
|
||||
if (mark) setDirty(FLAGS_WORD) );
|
||||
}
|
||||
|
||||
inline void setCW(bool mark = true) {
|
||||
DISABLEINTS( data[FLAGS_WORD] |= UBITX_USB_FLAG;
|
||||
data[FLAGS_WORD] |= UBITX_CW_FLAG;
|
||||
if (mark) setDirty(FLAGS_WORD) );
|
||||
}
|
||||
|
||||
inline void setCWR(bool mark = true) {
|
||||
DISABLEINTS( data[FLAGS_WORD] &= ~UBITX_USB_FLAG;
|
||||
data[FLAGS_WORD] |= UBITX_CW_FLAG;
|
||||
if (mark) setDirty(FLAGS_WORD) );
|
||||
}
|
||||
|
||||
inline bool isModeUSB() const {
|
||||
bool result;
|
||||
DISABLEINTS( result = ((data[FLAGS_WORD] & UBITX_USB_FLAG) > 0) && ((data[FLAGS_WORD] & UBITX_CW_FLAG) == 0) );
|
||||
return result;
|
||||
}
|
||||
|
||||
inline bool isModeLSB() const {
|
||||
bool result;
|
||||
DISABLEINTS( result = ((data[FLAGS_WORD] & UBITX_USB_FLAG) == 0) && ((data[FLAGS_WORD] & UBITX_CW_FLAG) == 0) );
|
||||
return result;
|
||||
}
|
||||
|
||||
inline bool isModeCWAny() const {
|
||||
bool result;
|
||||
DISABLEINTS( result = (data[FLAGS_WORD] & UBITX_CW_FLAG) > 0 );
|
||||
return result;
|
||||
}
|
||||
|
||||
inline bool isModeCW() const {
|
||||
bool result;
|
||||
DISABLEINTS( result = ((data[FLAGS_WORD] & UBITX_USB_FLAG) > 0) && ((data[FLAGS_WORD] & UBITX_CW_FLAG) > 0) );
|
||||
return result;
|
||||
}
|
||||
|
||||
inline bool isModeCWR() const {
|
||||
bool result;
|
||||
DISABLEINTS( result = ((data[FLAGS_WORD] & UBITX_USB_FLAG) == 0) && ((data[FLAGS_WORD] & UBITX_CW_FLAG) > 0) );
|
||||
return result;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
void serialHexState(const char* label);
|
||||
void serialPrettyState(const char* label);
|
||||
#endif
|
||||
|
||||
/**********************************************************************/
|
||||
// NEW IMPLEMENTATION
|
||||
|
||||
struct BaseField {
|
||||
BaseField(): dirty(false), data(0) {}
|
||||
virtual ~BaseField() = 0;
|
||||
|
||||
bool dirty;
|
||||
uint32_t data;
|
||||
|
||||
virtual bool read() = 0;
|
||||
virtual void write() const = 0;
|
||||
};
|
||||
|
||||
template<typename R, typename W>
|
||||
struct Field : public BaseField {
|
||||
/*!
|
||||
* @brief Using the supplied read function, which should take a
|
||||
* pointer to data as its input, read from (some source) and
|
||||
* update the value of data as appropriate. The read
|
||||
* function should true if the new value is new and hence
|
||||
* the dirty bit should be marked, false otherwise.
|
||||
* @return True if data was updated (dirty), false otherwise.
|
||||
*/
|
||||
virtual bool read() { return R(&data); }
|
||||
|
||||
/*!
|
||||
* @brief Using the supplied write function, which should take
|
||||
* data as its input, write data to some destination.
|
||||
*/
|
||||
virtual void write() const { W(data); }
|
||||
};
|
||||
|
||||
#define WIREBUS_VFO_A 1
|
||||
#define WIREBUS_VFO_B 2
|
||||
#define WIREBUS_RIT_OFS 3
|
||||
#define WIREBUS_XIT_OFS 4
|
||||
#define WIREBUS_FLAGS 5
|
||||
#define WIREBUS_NUM_FIELDS 6
|
||||
|
||||
class RigState {
|
||||
public:
|
||||
RigState(BaseField** f = NULL, int numf = 0): field(f), numFields(numf), numDirty(0) {}
|
||||
void begin();
|
||||
void update();
|
||||
|
||||
/*!
|
||||
* @brief Read in the specified (by index) external value, and use
|
||||
* it to update the rig state.
|
||||
*/
|
||||
inline bool read(byte i) {
|
||||
return field[i]->read();
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Use the specified (vy index) rig state field to update the
|
||||
* external value.
|
||||
*/
|
||||
inline void write(byte i) {
|
||||
field[i]->write();
|
||||
}
|
||||
|
||||
inlie bool isDirty(byte i) {
|
||||
return field[i]->dirty();
|
||||
}
|
||||
|
||||
inline void makeDirty(byte i) {
|
||||
if (!field[i]->dirty) {
|
||||
field[i]->dirty = true;
|
||||
numDirty++;
|
||||
}
|
||||
}
|
||||
|
||||
inline void makeClean(byte i) {
|
||||
if (field[i]->dirty) {
|
||||
field[i]->dirty = false;
|
||||
numDirty--;
|
||||
}
|
||||
}
|
||||
|
||||
inline byte* data(byte i) {
|
||||
return (byte*)(&(field[i]->data));
|
||||
}
|
||||
|
||||
inline int dataSize(byte i) {
|
||||
return sizeof(field[i]->data);
|
||||
}
|
||||
|
||||
inline unsigned getFreqA() const { return field[WIREBUS_VFO_A]->data; }
|
||||
inline unsigned getFreqB() const { return field[WIREBUS_VFO_B]->data; }
|
||||
inline int getRIT() const { return int(field[WIREBUS_VFO_A]->data); }
|
||||
inline int getXIT() const { return int(field[WIREBUS_VFO_B]->data); }
|
||||
inline bool isVFOA() const { return (field[WIREBUS_FLAGS]->data & UBITX_VFOB_FLAG) != UBITX_VFOB_FLAG; }
|
||||
inline bool isVFOB() const { return (field[WIREBUS_FLAGS]->data & UBITX_VFOB_FLAG) == UBITX_VFOB_FLAG; }
|
||||
inline bool isSplit() const { return (field[WIREBUS_FLAGS]->data & UBITX_SPLIT_FLAG) == UBITX_SPLIT_FLAG; }
|
||||
inline bool isRITOn() const { return (field[WIREBUS_FLAGS]->data & UBITX_RIT_FLAG) == UBITX_RIT_FLAG; }
|
||||
inline bool isXITOn() const { return (field[WIREBUS_FLAGS]->data & UBITX_XIT_FLAG) == UBITX_XIT_FLAG; }
|
||||
inline bool isCW() const { return (field[WIREBUS_FLAGS]->data & UBITX_CW_FLAG) == UBITX_CW_FLAG; }
|
||||
inline bool isLSB() const { return (field[WIREBUS_FLAGS]->data & UBITX_USB_FLAG) != UBITX_USB_FLAG; }
|
||||
inline bool isUSB() const { return (field[WIREBUS_FLAGS]->data & UBITX_USB_FLAG) == UBITX_USB_FLAG; }
|
||||
|
||||
static void merge(RigState& a, RigState& b);
|
||||
|
||||
BaseField** field;
|
||||
byte numFields;
|
||||
byte numDirty;
|
||||
#ifndef TEENSYDUINO
|
||||
// These methods are only defined in the Raduino (Arduino) case of the
|
||||
// RigState, not in the TeensyDSP (Teensy) case.
|
||||
void writeDirty(); // write fields FROM RigState TO Raduino
|
||||
void readDirty(); // read variables FROM Raduino TO RigState
|
||||
#endif
|
||||
};
|
||||
|
||||
#ifndef TEENSYDUINO
|
||||
|
||||
extern RigState rigState;
|
||||
extern UBitxRigState& rigState;
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
NOTE: This is all currently OBE, leaving it here for reference/future cleanup.
|
||||
|
||||
Protocol discussion:
|
||||
- I2C master: Raduino
|
||||
- I2C slave: TeensyDSP
|
||||
|
@ -221,5 +364,9 @@ TeensyDSP state:
|
|||
- Send dirty data over I2C.
|
||||
- Mark data as clean.
|
||||
*/
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
/***********************************************************************
|
||||
* EOF
|
||||
**********************************************************************/
|
||||
|
|
|
@ -149,13 +149,13 @@ void TS590_FR::handleCommand(const char* cmd) {
|
|||
if (strlen(cmd) == 3) {
|
||||
switch (cmd[2]) {
|
||||
case '0':
|
||||
rig()->selectVFOA();
|
||||
rig()->splitOff();
|
||||
rig()->setVFOA();
|
||||
rig()->setSplitOff();
|
||||
break;
|
||||
|
||||
case '1':
|
||||
rig()->selectVFOB();
|
||||
rig()->splitOff();
|
||||
rig()->setVFOB();
|
||||
rig()->setSplitOff();
|
||||
break;
|
||||
|
||||
case '2':
|
||||
|
@ -187,9 +187,9 @@ void TS590_FT::handleCommand(const char* cmd) {
|
|||
switch (cmd[2]) {
|
||||
case '0':
|
||||
if (rig()->isVFOA()) {
|
||||
rig()->splitOff();
|
||||
rig()->setSplitOff();
|
||||
} else if (rig()->isVFOB()) {
|
||||
rig()->splitOn();
|
||||
rig()->setSplitOn();
|
||||
} else {
|
||||
setSyntaxError();
|
||||
}
|
||||
|
@ -197,9 +197,9 @@ void TS590_FT::handleCommand(const char* cmd) {
|
|||
|
||||
case '1':
|
||||
if (rig()->isVFOA()) {
|
||||
rig()->splitOn();
|
||||
rig()->setSplitOn();
|
||||
} else if (rig()->isVFOB()) {
|
||||
rig()->splitOff();
|
||||
rig()->setSplitOff();
|
||||
} else {
|
||||
setSyntaxError();
|
||||
}
|
||||
|
@ -238,19 +238,19 @@ void TS590_MD::handleCommand(const char* cmd) {
|
|||
break;
|
||||
|
||||
case '1': // LSB
|
||||
rig()->setModeLSB();
|
||||
rig()->setLSB();
|
||||
break;
|
||||
|
||||
case '2': // USB
|
||||
rig()->setModeUSB();
|
||||
rig()->setUSB();
|
||||
break;
|
||||
|
||||
case '3': // CW
|
||||
rig()->setModeCW();
|
||||
rig()->setCW();
|
||||
break;
|
||||
|
||||
case '7': // CW-R
|
||||
rig()->setModeCWR();
|
||||
rig()->setCWR();
|
||||
break;
|
||||
|
||||
default:
|
||||
|
|
|
@ -438,6 +438,7 @@ void i2cRequestEvent(void)
|
|||
// NEEDS TO GET UPDATED
|
||||
break;
|
||||
|
||||
/*
|
||||
case I2CMETER_REQCAT:
|
||||
// Provide latest CAT updates, if any.
|
||||
//Wire1.write(catState.header); // temporary - just writing a single, null byte
|
||||
|
@ -457,7 +458,7 @@ void i2cRequestEvent(void)
|
|||
Wire1.write(0);
|
||||
}
|
||||
break;
|
||||
|
||||
*/
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -526,9 +527,9 @@ void loop()
|
|||
}
|
||||
|
||||
// If CW mode, we need to update keying a lot...
|
||||
if (Rig.isCW()) {
|
||||
if (Rig.isCW()) Keyer.doPaddles();
|
||||
TR.update(Rig.isCW(), Keyer.isDown());
|
||||
if (Rig.isModeCWAny()) {
|
||||
if (Rig.isModeCWAny()) Keyer.doPaddles();
|
||||
TR.update(Rig.isModeCWAny(), Keyer.isDown());
|
||||
//if (TR.transmitting()) return;
|
||||
}
|
||||
|
||||
|
@ -543,11 +544,11 @@ void loop()
|
|||
|
||||
// Update each of the subsystems, beginning with CAT control.
|
||||
TS590.update();
|
||||
TR.update(Rig.isCW(), Keyer.isDown());
|
||||
TR.update(Rig.isModeCWAny(), Keyer.isDown());
|
||||
Rig.update();
|
||||
DSP.update();
|
||||
|
||||
//if (Rig.isCW()) return;
|
||||
//if (Rig.isModeCWAny()) return;
|
||||
|
||||
#ifdef DEBUG
|
||||
// For debugging, output some debug info every 1.0" (40 frames @ 40 Hz).
|
||||
|
@ -670,7 +671,7 @@ void loop()
|
|||
forwardData();
|
||||
}
|
||||
|
||||
if (Rig.isCW()) return; // In CW, the ADC measurement messes with the timing. So need to use interrupts on the Keyer, and/or continuous ADC.
|
||||
if (Rig.isModeCWAny()) return; // In CW, the ADC measurement messes with the timing. So need to use interrupts on the Keyer, and/or continuous ADC.
|
||||
|
||||
if (sinceADCMillis > adcIntervalMillis) {
|
||||
// Do stuff that we do once per ADC interval--ADC colllection.
|
||||
|
@ -688,7 +689,7 @@ void loop()
|
|||
//forwardData();
|
||||
}
|
||||
|
||||
//if (Rig.isCW()) return;
|
||||
//if (Rig.isModeCWAny()) return;
|
||||
|
||||
// Check Response Command
|
||||
if (responseCommand > 0 && sinceForward > LAST_TIME_INTERVAL)
|
||||
|
|
Loading…
Reference in New Issue
Block a user