ubitx-v5x/TeensyDSP/RigState.h

226 lines
7.9 KiB
C
Raw Normal View History

#ifndef __RigState_h__
#define __RigState_h__
#include <Arduino.h>
#define UBITX_VFOB_FLAG 0x00000001
#define UBITX_SPLIT_FLAG 0x00000002
#define UBITX_RIT_FLAG 0x00000004
#define UBITX_XIT_FLAG 0x00000008
#define UBITX_CW_FLAG 0x00000010
#define UBITX_USB_FLAG 0x00000020
#define UBITX_TX_FLAG 0x00000040
2021-02-17 17:05:09 +00:00
enum RigStateWord {
DIRTY_WORD = 0,
VFOA_WORD,
VFOB_WORD,
OFFSETS_WORD,
FLAGS_WORD,
NUM_WORDS
};
struct UBitxRigState {
2021-02-17 17:05:09 +00:00
uint32_t data[RigStateWord.NUM_WORDS] = {0};
/*!
* @brief Set the dirty bit for for the specified word.
*/
inline void setDirty(RigStateWord w) {
data[i] |= w < NUM_WORDS ? 1 << w : 0;
}
inline void setClean(RigStateWord w) {
data[i] &= ~(w < NUM_WORDS ? 1 << w : 0);
}
inline bool isDirty(RigStateWord w) {
return (1 << w) & data[DIRTY_WORD] > 0 ? true : false;
}
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); }
};
2021-02-17 17:05:09 +00:00
#ifndef TEENSYDUINO
void mergeDirty(const RigState& r);
#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
extern RigState rigState;
#endif
/*
Protocol discussion:
- I2C master: Raduino
- I2C slave: TeensyDSP
Raduino state:
- Baseline uBITX variables
- I2C buffer
- On I2C transmit: make updates based on current variables
- On I2C receive:
- Update based on received I2C responses
- Update associated variables
TeensyDSP state:
- CAT buffer
- Used to receive command from CAT (when commands arrive via Serial)
- Used to transmit state to Raduino (when requested via Wire1)
- Raduino buffer
- Used to receive state from Raduino (when received via Wire1)
- Used to transmit responses to CAT (over Serial)
- Questions
- How can these be synchronized?
- At the tail end of an I2C request handler. Before sending the response to the Raduino via I2C:
- Copy updated CAT buffer items to the Raduino buffer.
- Copy updated Raduino buffer items to the CAT buffer.
- In the case of conflicts, CAT wins.
- Transmit the CAT buffer state to the Raduino.
- TeensyDSP updates 'outgoing' state based on CAT inputs.
- Make change to data.
- Mark data as dirty, if different than incoming state.
- When requested, Teensy DSP sends 'outgoing' state to Raduino.
- Send dirty data over I2C.
- Mark data as clean.
*/
#endif