#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; }; /**********************************************************************/ template struct Field { byte id = ID; bool dirty; T data; inline size_t sizeOfWrite() { return dirty ? sizeof(byte) + sizeof(T) : 0; } template void writeChanges() { if (dirty) { STREAM().write(id); STREAM().write((byte*)&data, sizeof(T)); } } template 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; } }; struct RigState { Field vfoA; Field vfoB; Field rit; Field xit; Field flags; 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 void writeChanges() { vfoA.writeChanges(); vfoB.writeChanges(); rit.writeChanges(); xit.writeChanges(); flags.writeChanges(); } template void readChanges(size_t size) { size_t len = 0; while (STREAM().available() && len < size) { switch(STREAM().read()) { case 0: len += vfoA.read(); break; case 1: len += vfoB.read(); break; case 2: len += rit.read(); break; case 3: len += xit.read(); break; case 4: len += flags.read(); 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(); } }; /* 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