#ifndef __RigState_h__ #define __RigState_h__ #include #define UBITX_VFOA_UPDATE 0x00000001 #define UBITX_VFOB_UPDATE 0x00000002 #define UBITX_RIT_UPDATE 0x00000004 #define UBITX_XIT_UPDATE 0x00000008 #define UBITX_FLAGS_UPDATE 0x00000010 #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 struct UBitxRigState { uint32_t header = 0; uint32_t vfo[2]; int32_t rit; int32_t xit; uint32_t flags = 0; }; /**********************************************************************/ // 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 struct Field : public BaesField { /*! * @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_NULL 0 // an empty field #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