2021-02-15 05:04:29 +00:00
|
|
|
#include ""
|
2021-02-14 06:35:38 +00:00
|
|
|
|
|
|
|
/**********************************************************************/
|
2021-02-15 05:04:29 +00:00
|
|
|
// Raduino externs -- generally defined in Raduino.ino or ubitx.h
|
2021-02-14 06:35:38 +00:00
|
|
|
|
2021-02-15 05:04:29 +00:00
|
|
|
#ifndef TEENSYDUINO
|
|
|
|
|
2021-02-17 17:05:09 +00:00
|
|
|
#include "ubitx_eemap.h"
|
|
|
|
|
2021-02-15 05:04:29 +00:00
|
|
|
extern unsigned long frequency;
|
|
|
|
extern unsigned long vfoA;
|
|
|
|
extern unsigned long vfoB;
|
|
|
|
extern char cwMode;
|
|
|
|
extern char isUSB;
|
|
|
|
extern char vfoActive;
|
|
|
|
extern char ritOn;
|
|
|
|
extern char splitOn;
|
|
|
|
void setFrequency(unsigned long);
|
|
|
|
|
2021-02-17 17:05:09 +00:00
|
|
|
/*!
|
|
|
|
* @brief Write dirty fields from the provided rig state, out to the
|
|
|
|
* Raduino variables.
|
|
|
|
* @param r
|
|
|
|
* Reference to a RigState object that will be used to update
|
|
|
|
* the Raduino variables.
|
|
|
|
*/
|
|
|
|
void writeDirty(const RigState& r) {
|
|
|
|
// VFO A frequency
|
|
|
|
if (r.isDirty(VFOA_WORD)) {
|
2021-02-15 05:04:29 +00:00
|
|
|
if (vfoActive == VFO_A) {
|
2021-02-17 17:05:09 +00:00
|
|
|
setFrequency(r.getFreqA());
|
2021-02-15 05:04:29 +00:00
|
|
|
} else {
|
2021-02-17 17:05:09 +00:00
|
|
|
vfoA = r.getFreqA();
|
|
|
|
}
|
2021-02-14 06:35:38 +00:00
|
|
|
}
|
|
|
|
|
2021-02-17 17:05:09 +00:00
|
|
|
// VFO B frequency
|
|
|
|
if (r.isDirty(VFOB_WORD)) {
|
2021-02-15 05:04:29 +00:00
|
|
|
if (vfoActive == VFO_B) {
|
2021-02-17 17:05:09 +00:00
|
|
|
setFrequency(r.getFreqB());
|
2021-02-15 05:04:29 +00:00
|
|
|
} else {
|
2021-02-17 17:05:09 +00:00
|
|
|
vfoB = r.getFreqB();
|
|
|
|
}
|
2021-02-14 06:35:38 +00:00
|
|
|
}
|
|
|
|
|
2021-02-17 17:05:09 +00:00
|
|
|
// RIT and XIT frequencies
|
|
|
|
if (r.isDirty(OFFSETS_WORD)) {
|
|
|
|
// RIT
|
|
|
|
ritRxFrequency = r.getRIT() + ritTxFrequency;
|
2021-02-15 05:04:29 +00:00
|
|
|
if ((ritOn == 1) && (inTx == 0)) {
|
|
|
|
setFrequency(ritRxFrequency);
|
|
|
|
}
|
2021-02-17 17:05:09 +00:00
|
|
|
// XIT - TODO
|
2021-02-15 05:04:29 +00:00
|
|
|
}
|
|
|
|
|
2021-02-17 17:05:09 +00:00
|
|
|
// VFO A/B selection
|
|
|
|
if (r.isDirty(FLAGS_WORD)) {
|
2021-02-15 05:04:29 +00:00
|
|
|
char prev = vfoActive;
|
2021-02-17 17:05:09 +00:00
|
|
|
vfoActive = r.isVFOA() ? VFO_A : VFO_B;
|
2021-02-15 05:04:29 +00:00
|
|
|
if (vfoActive != prev) {
|
|
|
|
if (vfoActive == VFO_A) {
|
|
|
|
if (vfoA != frequency) {
|
|
|
|
setFrequency(vfoA);
|
|
|
|
}
|
|
|
|
} else if (vfoActive == VFO_B) {
|
|
|
|
if (vfoB != frequency) {
|
|
|
|
setFrequency(vfoB);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-02-17 17:05:09 +00:00
|
|
|
|
|
|
|
// Split on/off
|
|
|
|
splitOn = r.isSplit() ? 1 : 0;
|
|
|
|
|
|
|
|
// RIT on/off
|
|
|
|
prev = ritOn;
|
|
|
|
ritOn = r.isRIT() ? 1 : 0;
|
2021-02-15 05:04:29 +00:00
|
|
|
if (ritOn != prev) {
|
|
|
|
if ((ritOn == 1) && (inTx == 0)) {
|
|
|
|
setFrequency(ritRxFrequency);
|
2021-02-14 06:35:38 +00:00
|
|
|
}
|
|
|
|
}
|
2021-02-17 17:05:09 +00:00
|
|
|
|
|
|
|
// XIT on/off
|
|
|
|
// TODO
|
|
|
|
|
|
|
|
// Mode
|
|
|
|
prev = (cwMode << 1) | isUSB;
|
|
|
|
isUSB = r.isUSB() ? 1 : 0;
|
|
|
|
if (r.isCW()) {
|
|
|
|
cwMode = 2; // 2 = cwu
|
|
|
|
} else if (r.isCWR()) {
|
|
|
|
cwMode = 1; // 1 = cwl
|
2021-02-15 05:04:29 +00:00
|
|
|
} else {
|
2021-02-17 17:05:09 +00:00
|
|
|
cwMode = 0; // 0 = no cw
|
2021-02-15 05:04:29 +00:00
|
|
|
}
|
|
|
|
if ((cwMode << 1) | isUSB != prev) {
|
2021-02-17 17:05:09 +00:00
|
|
|
setFrequency(frequency);
|
2021-02-14 06:35:38 +00:00
|
|
|
}
|
|
|
|
}
|
2021-02-17 17:05:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* @brief Read current Raduino variables into the provided RigState
|
|
|
|
* (if they are dirty) and set the appropriate dirty flags.
|
|
|
|
* @param r
|
|
|
|
* RigState reference to put the values into.
|
|
|
|
*/
|
|
|
|
void readDirty(RigState& r) {
|
|
|
|
unsigned freq;
|
|
|
|
short offset;
|
|
|
|
|
|
|
|
// VFO A frequency
|
|
|
|
freq = (vfoActive == VFO_A) ? frequency : vfoA;
|
|
|
|
if (r.getFreqA() != freq) {
|
|
|
|
r.setFreqA(freq);
|
|
|
|
r.setDirty(VFOA_WORD);
|
|
|
|
}
|
|
|
|
|
|
|
|
// VFO B frequency
|
|
|
|
freq = (vfoActive == VFO_B) ? frequency : vfoB;
|
|
|
|
if (r.getFreqB() != freq) {
|
|
|
|
r.setFreqB(freq);
|
|
|
|
r.setDirty(VFOB_WORD);
|
|
|
|
}
|
|
|
|
|
|
|
|
// RIT frequency
|
|
|
|
offset = ritRxFrequency - frequency;
|
|
|
|
if (r.getRIT() != offset) {
|
|
|
|
r.setRIT(offset);
|
|
|
|
r.setDirty(OFFSETS_WORD);
|
|
|
|
}
|
|
|
|
|
|
|
|
// XIT frequency
|
|
|
|
offset = 0; // xitRxFrequency - frequency;
|
|
|
|
if (r.getXIT() != offset) {
|
|
|
|
r.setXIT(offset);
|
|
|
|
r.setDirty(OFFSETS_WORD);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool dirty = false;
|
|
|
|
|
|
|
|
// VFO A/B selection
|
|
|
|
if (r.isVFOA() && vfoActive == VFO_B) {
|
|
|
|
r.setVFOB();
|
|
|
|
dirty = true;
|
|
|
|
} else if (r.isVFOB() && vfoActive == VFO_A) {
|
|
|
|
r.setVFOA();
|
|
|
|
dirty = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Split selection
|
|
|
|
if (r.isSplit() && splitOn == 0) {
|
|
|
|
r.setSplitOff();
|
|
|
|
dirty = true;
|
|
|
|
} else if (!r.isSplit() && splitOn != 0) {
|
|
|
|
r.setSplitOn();
|
|
|
|
dirty = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// RIT selection
|
|
|
|
if (r.isRIT() && ritOn == 0) {
|
|
|
|
r.setRITOff();
|
|
|
|
dirty = true;
|
|
|
|
} else if (!r.isRIT() && ritOn != 0) {
|
|
|
|
r.setRITOn();
|
|
|
|
dirty = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// XIT selection
|
|
|
|
r.setXITOff();
|
|
|
|
// TODO
|
|
|
|
|
|
|
|
// Mode
|
|
|
|
char prev = (r.isCW() ? 4 : 0) | (r.isCWR() ? 2 : 0) | (r.isUSB() ? 1 : 0);
|
|
|
|
char curr = (cwMode << 1) | isUSB;
|
|
|
|
if (curr != prev) {
|
|
|
|
if (cwMode == 2) {
|
|
|
|
r.setCW();
|
|
|
|
} else if (cwMode == 1) {
|
|
|
|
r.setCWR();
|
|
|
|
} else {
|
|
|
|
if (isUSB) {
|
|
|
|
r.setUSB();
|
|
|
|
} else {
|
|
|
|
r.setLSB();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
dirty = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (dirty) r.setDirty(FLAGS_WORD);
|
|
|
|
}
|
2021-02-14 06:35:38 +00:00
|
|
|
|
2021-02-15 05:04:29 +00:00
|
|
|
#endif
|
2021-02-14 06:35:38 +00:00
|
|
|
|
|
|
|
/**********************************************************************/
|
|
|
|
|
2021-02-15 05:04:29 +00:00
|
|
|
BaseField* raduinoFields[WIREBUS_NUM_FIELDS] = {
|
|
|
|
new Field<readNone, writeNone>(),
|
|
|
|
new Field<readVFOA, writeVFOA>(),
|
|
|
|
new Field<readVFOB, writeVFOB>(),
|
|
|
|
new Field<readRIT, writeRIT>(),
|
|
|
|
new Field<readXIT, writeXIT>(),
|
|
|
|
new Field<readFlags, writeFlags>(),
|
|
|
|
};
|
2021-02-14 06:35:38 +00:00
|
|
|
|
2021-02-15 05:04:29 +00:00
|
|
|
/**********************************************************************/
|
|
|
|
|
2021-02-16 04:38:05 +00:00
|
|
|
RigState::RigState(): RigState(raduinoFields, WIREBUS_NUM_FIELDS) {}
|
2021-02-15 05:04:29 +00:00
|
|
|
|
2021-02-16 04:38:05 +00:00
|
|
|
/*!
|
|
|
|
* @brief Begin using the RigState object. In order to force an
|
|
|
|
* update (e.g. sending current state to the remote device),
|
|
|
|
* all fields are marked dirty.
|
|
|
|
*/
|
|
|
|
void RigState::begin() {
|
2021-02-15 05:04:29 +00:00
|
|
|
for (byte i = 0; i < numFields; i++) {
|
|
|
|
if (read(i)) {
|
|
|
|
makeDirty(i);
|
|
|
|
}
|
|
|
|
}
|
2021-02-14 06:35:38 +00:00
|
|
|
}
|
|
|
|
|
2021-02-17 17:05:09 +00:00
|
|
|
void updateRaduinoState(RigState& r) {
|
|
|
|
writeDirty(r);
|
2021-02-14 06:35:38 +00:00
|
|
|
Wire.beginTransmission(I2CMETER_ADDR);
|
|
|
|
Wire.write(I2CMETER_RIGINF);
|
2021-02-17 17:05:09 +00:00
|
|
|
for (RigStateWord i = 0; i < NUM_WORDS; i++) {
|
|
|
|
Wire.write((byte*)&r.data, sizeof(r.data)); // - write the field data
|
|
|
|
r.setClean(i);
|
2021-02-14 06:35:38 +00:00
|
|
|
}
|
|
|
|
Wire.endTransmission();
|
|
|
|
|
2021-02-17 17:05:09 +00:00
|
|
|
delay(1); // 1ms - some delay required between ending transmission and requesting?
|
2021-02-14 06:35:38 +00:00
|
|
|
|
|
|
|
// Retrieve all of the deltas. Mark any received field as dirty.
|
|
|
|
Wire.requestFrom(I2CMETER_ADDR, numBytes);
|
2021-02-15 05:04:29 +00:00
|
|
|
bool doRead = true;
|
2021-02-14 06:35:38 +00:00
|
|
|
int index = -1;
|
|
|
|
byte* ptr;
|
|
|
|
while (Wire.available()) {
|
|
|
|
byte b = Wire.read();
|
2021-02-15 05:04:29 +00:00
|
|
|
if (index == -1) {
|
|
|
|
if (numFields > b) {
|
|
|
|
ptr = data(b);
|
|
|
|
field[b].dirty = true;
|
|
|
|
numDirty++;
|
|
|
|
index = 0;
|
|
|
|
} else {
|
|
|
|
doRead = false;
|
|
|
|
}
|
2021-02-14 06:35:38 +00:00
|
|
|
} else {
|
2021-02-15 05:04:29 +00:00
|
|
|
if (doRead) {
|
|
|
|
ptr[index] = b;
|
|
|
|
}
|
|
|
|
if (++index == 4) {
|
2021-02-14 06:35:38 +00:00
|
|
|
index = -1;
|
2021-02-15 05:04:29 +00:00
|
|
|
doRead = true;
|
2021-02-14 06:35:38 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Perform the corresponding update for each dirty field.
|
2021-02-15 05:04:29 +00:00
|
|
|
for (byte i = 0; i < numFields; i++) {
|
2021-02-14 06:35:38 +00:00
|
|
|
if (field[i].dirty) {
|
|
|
|
write(i);
|
|
|
|
field[i].dirty = false;
|
|
|
|
numDirty--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**********************************************************************/
|
2021-02-15 05:04:29 +00:00
|
|
|
/*!
|
|
|
|
* @brief Handle a RIGINF signal from the Raduino. This method should
|
|
|
|
* be called on the TeensyDSP 'radState' (Raduino state)
|
|
|
|
* instance, when a RIGINF signal is received via I2C. It
|
|
|
|
* receives the incoming data from the Raduino.
|
|
|
|
*/
|
2021-02-16 04:38:05 +00:00
|
|
|
void RigState::receive_RIGINF() {
|
2021-02-15 05:04:29 +00:00
|
|
|
// 1st (-1) byte read should be a field index.
|
|
|
|
// 2nd (0) thru 5th (3) bytes are bytes of the field.
|
|
|
|
// We'll read as many fields as the Raduino sends.
|
|
|
|
bool doRead = true;
|
|
|
|
int index = -1;
|
|
|
|
byte* ptr;
|
|
|
|
while (Wire1.available()) {
|
|
|
|
byte b = Wire1.read();
|
|
|
|
if (index == -1) {
|
|
|
|
if (numFields > b) {
|
|
|
|
ptr = data(b);
|
|
|
|
makeDirty(b);
|
|
|
|
index = 0;
|
|
|
|
} else {
|
|
|
|
doRead = false;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (doRead) {
|
|
|
|
ptr[index] = b;
|
|
|
|
}
|
|
|
|
if (++index == 4) {
|
|
|
|
index = -1;
|
|
|
|
doRead = true;
|
|
|
|
}
|
|
|
|
}
|
2021-02-14 06:35:38 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-15 05:04:29 +00:00
|
|
|
/**********************************************************************/
|
|
|
|
/*!
|
|
|
|
* @brief Handle a RIGINF signal from the Raduino. This method should
|
|
|
|
* be called on the TeensyDSP 'radState' (Raduino state)
|
|
|
|
* instance, when a RIGINF signal is received via I2C. It
|
|
|
|
* sends a response to the Raduino
|
|
|
|
*/
|
2021-02-16 04:38:05 +00:00
|
|
|
void RigState::send_RIGINF(byte numBytes, RigState& catState) {
|
2021-02-15 05:04:29 +00:00
|
|
|
// Now we need to determine the differences from the other state (i.e.
|
|
|
|
// from the catState) and send those differences.
|
|
|
|
byte rigRegBytes = 0;
|
|
|
|
for (byte i = 0; i < numFields; i++) {
|
|
|
|
if (isDirty(i) && !catState.isDirty(i)) {
|
|
|
|
catState.field[i]->data = field[i]->data;
|
|
|
|
makeClean(i);
|
|
|
|
} else if (catState.isDirty(i)) {
|
|
|
|
field[i]->data = catState.field[i]->data;
|
|
|
|
makeClean(i);
|
|
|
|
rigRegBytes += (sizeof(byte) + sizeof(uint32_t)); // size of field ID and data
|
|
|
|
}
|
2021-02-14 06:35:38 +00:00
|
|
|
}
|
|
|
|
|
2021-02-15 05:04:29 +00:00
|
|
|
for (byte i = 0; i < numBytes; i++) {
|
|
|
|
Wire1.write(rigReqBytes);
|
2021-02-14 06:35:38 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-15 05:04:29 +00:00
|
|
|
/**********************************************************************/
|
|
|
|
/*!
|
|
|
|
* @brief Handle a RIGREQ signal from the Raduino. This method should
|
|
|
|
* be called on the TeensyDSP 'catState' (CAT state) instance,
|
|
|
|
* when a RIGREQ signal is received via I2C. It handles
|
|
|
|
* sending the changed fields.
|
|
|
|
*/
|
|
|
|
void RigState::respondRIGREQ(byte numBytes) {
|
|
|
|
byte bytesSent = 0;
|
2021-02-14 06:35:38 +00:00
|
|
|
|
2021-02-15 05:04:29 +00:00
|
|
|
for (byte i = 0; i < numFields; i++) {
|
|
|
|
if (isDirty(i) && (dataSize(i) + sizeof(byte) <= numBytes - bytesSent)) { // Write each field that is dirty to the bus.
|
|
|
|
Wire1.write(i); // - write the field number/ID
|
|
|
|
Wire1.write(data(i), dataSize(i)); // - write the field data
|
|
|
|
makeClean(i);
|
|
|
|
bytesSent += dataSize(i) + sizeof(byte);
|
|
|
|
}
|
2021-02-14 06:35:38 +00:00
|
|
|
}
|
|
|
|
|
2021-02-15 05:04:29 +00:00
|
|
|
// Don't know if this is necessary, but if we haven't written enough
|
|
|
|
// bytes yet, we'll write out some zeroes.
|
|
|
|
for (byte i = bytesSent; i < numBytes; i++) {
|
|
|
|
Wire1.write(0);
|
2021-02-14 06:35:38 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**********************************************************************/
|
|
|
|
|
2021-02-15 05:04:29 +00:00
|
|
|
#ifndef TEENSYDUINO
|
2021-02-14 06:35:38 +00:00
|
|
|
|
2021-02-15 05:04:29 +00:00
|
|
|
RigState rigState;
|
2021-02-14 06:35:38 +00:00
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/**********************************************************************
|
|
|
|
* EOF *
|
|
|
|
**********************************************************************/
|
|
|
|
|