ubitx-v5x/TeensyDSP/RigState.h

229 lines
6.0 KiB
C
Raw Normal View History

#ifndef __RigState_h__
#define __RigState_h__
#include <Arduino.h>
#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 Field {
bool dirty;
uint32_t data;
/*
template<typename STREAM> void writeChanges() {
if (dirty) {
STREAM().write(id);
STREAM().write((byte*)&data, sizeof(T));
}
}
template<typename STREAM> int read() {
size_t len = 0;
byte* ptr = (byte*)&data;
while (STREAM().available() && len < sizeof(T)) {
ptr[len++] = STREAM().read();
}
return len;
}
*/
inline void merge(Field& f) {
if (dirty) {
f.data = data;
f.dirty = true;
} else if (f.dirty) {
data = f.data;
dirty = true;
}
}
inline void markClean() { dirty = false; }
};
#define WIREBUS_NONE 0
#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
typedef bool (*readfunc)(uint32_t*);
typedef void (*writefunc)(uint32_t);
struct RigState {
Field field[WIREBUS_NUM_FIELDS];
readfunc readFunc[WIREBUS_NUM_FIELDS];
writefunc writeFunc[WIREBUS_NUM_FIELDS;
int numDirty;
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 readFunc[i](&field[i].data);
}
/*!
* @brief Use the specified (vy index) rig state field to update the
* external value.
*/
inline void write(byte i) {
writeFunc[i](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; }
/*
inline size_t sizeOfWrite() {
size_t size = 0;
size += vfoA.sizeOfWrite();
size += vfoB.sizeOfWrite();
size += rit.sizeOfWrite();
size += xit.sizeOfWrite();
size += flags.sizeOfWrite();
return size;
}
template<typename STREAM> void writeChanges() {
vfoA.writeChanges<STREAM>();
vfoB.writeChanges<STREAM>();
rit.writeChanges<STREAM>();
xit.writeChanges<STREAM>();
flags.writeChanges<STREAM>();
}
template<typename STREAM> void readChanges(size_t size) {
size_t len = 0;
while (STREAM().available() && len < size) {
switch(STREAM().read()) {
case 0:
len += vfoA.read<STREAM>();
break;
case 1:
len += vfoB.read<STREAM>();
break;
case 2:
len += rit.read<STREAM>();
break;
case 3:
len += xit.read<STREAM>();
break;
case 4:
len += flags.read<STREAM>();
break;
default:
;
}
}
}
inline void merge(RigState& r) {
vfoA.merge(r.vfoA);
vfoB.merge(r.vfoB);
rit.merge(r.rit);
xit.merge(r.xit);
flags.merge(r.flags);
}
inline void markClean(RigState& r) {
vfoA.markClean();
vfoB.markClean();
rit.markClean();
xit.markClean();
flags.markClean();
}
*/
};
#ifdef TEENSYDUINO
extern RigState inState; // the state as received from the Raduino
extern RigState outState; // the state as commanded via CAT
#else
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