2021-02-19 02:39:25 -05:00
|
|
|
/*!
|
|
|
|
* @file RigState.h
|
|
|
|
*/
|
|
|
|
|
2021-02-05 23:59:31 -05:00
|
|
|
#ifndef __RigState_h__
|
|
|
|
#define __RigState_h__
|
|
|
|
|
2021-02-07 00:45:19 -05:00
|
|
|
#include <Arduino.h>
|
|
|
|
|
2021-02-09 23:58:07 -05:00
|
|
|
#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-05 23:59:31 -05:00
|
|
|
|
2021-02-19 02:39:25 -05:00
|
|
|
#ifdef TEENSYDUINO
|
|
|
|
#define DISABLEINTS(CMD) do { noInterrupts(); CMD; interrupts(); } while (0)
|
|
|
|
#else
|
|
|
|
#define DISABLEINTS(CMD) do { CMD; } while (0)
|
|
|
|
#endif
|
|
|
|
|
2021-02-17 12:05:09 -05:00
|
|
|
enum RigStateWord {
|
|
|
|
DIRTY_WORD = 0,
|
|
|
|
VFOA_WORD,
|
|
|
|
VFOB_WORD,
|
|
|
|
OFFSETS_WORD,
|
|
|
|
FLAGS_WORD,
|
|
|
|
NUM_WORDS
|
|
|
|
};
|
|
|
|
|
2021-02-19 02:39:25 -05:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2021-02-05 23:59:31 -05:00
|
|
|
struct UBitxRigState {
|
2021-02-19 02:39:25 -05:00
|
|
|
volatile uint32_t data[NUM_WORDS] = {0};
|
|
|
|
|
|
|
|
void begin();
|
|
|
|
|
|
|
|
void send_RIGINF();
|
|
|
|
void receive_RIGINF(int numBytes = sizeof(data));
|
2021-02-17 12:05:09 -05:00
|
|
|
|
|
|
|
/*!
|
2021-02-19 02:39:25 -05:00
|
|
|
* @brief Set the dirty bit for the specified word.
|
|
|
|
*
|
|
|
|
* @param w
|
|
|
|
* The word to mark as dirty.
|
2021-02-17 12:05:09 -05:00
|
|
|
*/
|
|
|
|
inline void setDirty(RigStateWord w) {
|
2021-02-19 02:39:25 -05:00
|
|
|
data[DIRTY_WORD] |= w < NUM_WORDS ? 1 << w : 0;
|
2021-02-17 12:05:09 -05:00
|
|
|
}
|
|
|
|
|
2021-02-19 02:39:25 -05:00
|
|
|
/*!
|
|
|
|
* @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.
|
|
|
|
*/
|
2021-02-17 12:05:09 -05:00
|
|
|
inline void setClean(RigStateWord w) {
|
2021-02-19 02:39:25 -05:00
|
|
|
data[DIRTY_WORD] &= ~(w < NUM_WORDS ? 1 << w : 0);
|
2021-02-17 12:05:09 -05:00
|
|
|
}
|
|
|
|
|
2021-02-19 02:39:25 -05:00
|
|
|
/*!
|
|
|
|
* @brief Clear the dirty bits for all words.
|
|
|
|
*/
|
|
|
|
inline void setClean() { DISABLEINTS( data[DIRTY_WORD] = 0 ); }
|
2021-02-17 12:05:09 -05:00
|
|
|
|
2021-02-19 02:39:25 -05:00
|
|
|
/*!
|
|
|
|
* @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;
|
|
|
|
}
|
2021-02-11 23:00:24 -05:00
|
|
|
|
2021-02-19 02:39:25 -05:00
|
|
|
/*!
|
|
|
|
* @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;
|
|
|
|
}
|
2021-02-15 00:04:29 -05:00
|
|
|
|
|
|
|
/*!
|
2021-02-19 02:39:25 -05:00
|
|
|
* @brief Check whether the specified word is dirty.
|
|
|
|
*
|
|
|
|
* @param w
|
|
|
|
* The word to check for dirty status.
|
|
|
|
*
|
|
|
|
* @return True if the word is dirty.
|
2021-02-15 00:04:29 -05:00
|
|
|
*/
|
2021-02-19 02:39:25 -05:00
|
|
|
inline bool isDirty(RigStateWord w) {
|
|
|
|
bool dirty;
|
|
|
|
DISABLEINTS( dirty = ((1 << w) & data[DIRTY_WORD]) > 0 ? true : false );
|
|
|
|
return dirty;
|
|
|
|
}
|
|
|
|
|
2021-02-15 00:04:29 -05:00
|
|
|
/*!
|
2021-02-19 02:39:25 -05:00
|
|
|
* @brief Check whether the data is dirty (as a whole).
|
|
|
|
*
|
|
|
|
* @return True if the data is dirty (at least one dirty field).
|
2021-02-15 00:04:29 -05:00
|
|
|
*/
|
2021-02-19 02:39:25 -05:00
|
|
|
inline bool isDirty() {
|
|
|
|
bool dirty;
|
|
|
|
DISABLEINTS( dirty = data[DIRTY_WORD] != 0 );
|
|
|
|
return dirty;
|
|
|
|
}
|
2021-02-14 01:35:38 -05:00
|
|
|
|
|
|
|
/*!
|
2021-02-19 02:39:25 -05:00
|
|
|
* @brief Set the VFO A frequency.
|
|
|
|
*
|
|
|
|
* @param freq
|
|
|
|
* The new frequency in Hz.
|
2021-02-14 01:35:38 -05:00
|
|
|
*/
|
2021-02-19 02:39:25 -05:00
|
|
|
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;
|
2021-02-14 01:35:38 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
2021-02-19 02:39:25 -05:00
|
|
|
* @brief Set the VFO B frequency.
|
|
|
|
*
|
|
|
|
* @param freq
|
|
|
|
* The new frequency in Hz.
|
2021-02-14 01:35:38 -05:00
|
|
|
*/
|
2021-02-19 02:39:25 -05:00
|
|
|
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;
|
2021-02-14 01:35:38 -05:00
|
|
|
}
|
2021-02-11 23:00:24 -05:00
|
|
|
|
2021-02-19 02:39:25 -05:00
|
|
|
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;
|
2021-02-11 23:00:24 -05:00
|
|
|
}
|
|
|
|
|
2021-02-19 02:39:25 -05:00
|
|
|
inline void setVFOA(bool mark = true) {
|
|
|
|
DISABLEINTS( data[FLAGS_WORD] &= ~UBITX_VFOB_FLAG;
|
|
|
|
if (mark) setDirty(FLAGS_WORD) );
|
2021-02-11 23:00:24 -05:00
|
|
|
}
|
|
|
|
|
2021-02-19 02:39:25 -05:00
|
|
|
inline void setVFOB(bool mark = true) {
|
|
|
|
DISABLEINTS( data[FLAGS_WORD] |= UBITX_VFOB_FLAG;
|
|
|
|
if (mark) setDirty(FLAGS_WORD) );
|
2021-02-11 23:00:24 -05:00
|
|
|
}
|
2021-02-15 00:04:29 -05:00
|
|
|
|
2021-02-19 02:39:25 -05:00
|
|
|
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;
|
2021-02-11 23:00:24 -05:00
|
|
|
}
|
|
|
|
|
2021-02-19 02:39:25 -05:00
|
|
|
inline void setSplitOn(bool mark = true) {
|
|
|
|
DISABLEINTS( data[FLAGS_WORD] |= UBITX_SPLIT_FLAG;
|
|
|
|
if (mark) setDirty(FLAGS_WORD) );
|
2021-02-11 23:00:24 -05:00
|
|
|
}
|
|
|
|
|
2021-02-19 02:39:25 -05:00
|
|
|
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;
|
|
|
|
}
|
2021-02-15 00:04:29 -05:00
|
|
|
|
2021-02-19 02:39:25 -05:00
|
|
|
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;
|
|
|
|
}
|
2021-02-15 00:04:29 -05:00
|
|
|
|
2021-02-19 02:39:25 -05:00
|
|
|
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
|
|
|
|
|
|
|
|
#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
|
2021-02-15 00:04:29 -05:00
|
|
|
};
|
2021-02-14 01:35:38 -05:00
|
|
|
|
2021-02-15 00:04:29 -05:00
|
|
|
#ifndef TEENSYDUINO
|
2021-02-14 01:35:38 -05:00
|
|
|
|
2021-02-19 02:39:25 -05:00
|
|
|
extern UBitxRigState& rigState;
|
2021-02-14 01:35:38 -05:00
|
|
|
|
|
|
|
#endif
|
|
|
|
|
2021-02-11 23:00:24 -05:00
|
|
|
/*
|
2021-02-19 02:39:25 -05:00
|
|
|
NOTE: This is all currently OBE, leaving it here for reference/future cleanup.
|
|
|
|
|
2021-02-11 23:00:24 -05:00
|
|
|
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.
|
|
|
|
*/
|
2021-02-19 02:39:25 -05:00
|
|
|
|
2021-02-05 23:59:31 -05:00
|
|
|
#endif
|
2021-02-19 02:39:25 -05:00
|
|
|
|
|
|
|
/***********************************************************************
|
|
|
|
* EOF
|
|
|
|
**********************************************************************/
|