ubitx-v5x/TeensyDSP/RigState.cpp

362 lines
8.9 KiB
C++

#include ""
/**********************************************************************/
// Raduino externs -- generally defined in Raduino.ino or ubitx.h
#ifndef TEENSYDUINO
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);
#endif
/**********************************************************************/
// Raduino functors - used to read/write from Raduino state
#ifndef TEENSYDUINO
struct readNone {
bool operator()(uint32_t* d) {
return false;
}
}
struct writeNone {
void operator()(uint32_t d) {
}
}
struct readVFOA {
bool operator()(uint32_t* d) {
unsigned freq = (vfoActive == VFO_A) ? frequency : vfoA;
if (*d == freq) {
return false;
} else {
*d = freq;
return true;
}
}
};
struct writeVFOA {
void operator()(uint32_t d) {
if (vfoActive == VFO_A) {
setFrequency(d);
} else {
vfoA = frequency;
}
}
};
struct readVFOB {
bool operator()(uint32_t* d) {
unsigned freq = (vfoActive == VFO_B) ? frequency : vfoB;
if (*d == freq) {
return false
} else {
*d = freq;
return true;
}
}
};
struct writeVFOB {
void operator()(uint32_t d) {
if (vfoActive == VFO_B) {
setFrequency(d);
} else {
vfoB = frequency;
}
}
};
struct readRIT {
bool operator()(uint32_t* d) {
int freq = ritRxFrequency - frequency;
if (*d == (uint32_t)freq) {
return false;
} else {
*d = (uint32_t)freq;
return true;
}
}
};
struct writeRIT {
void operator()(uint32_t d) {
ritRxFrequency = (int)d + ritTxFrequency;
if ((ritOn == 1) && (inTx == 0)) {
setFrequency(ritRxFrequency);
}
}
};
struct readXIT {
bool operator()(uint32_t* d) {
return false;
}
};
struct writeXIT {
void operator()(uint32_t d) {
}
};
struct readFlags {
bool operator()(uint32_t* d) {
uint32_t flags = 0
flags = 0;
flags |= (vfoActive == VFO_B ? UBITX_VFOB_FLAG : 0);
flags |= (cwMode != 0 ? UBITX_CW_FLAG : 0);
flags |= (isUSB != 0 ? UBITX_USB_FLAG : 0);
flags |= (splitOn != 0 ? UBITX_SPLIT_FLAG : 0);
flags |= (ritOn != 0 ? UBITX_RIT_FLAG : 0);
//flags |= (xitOn != 0 ? UBITX_XIT_FLAG : 0);
if (*d == flags) {
return false;
} else {
*d = flags;
return true;
}
}
};
struct writeFlags {
void operator()(uint32_t d) {
char prev = vfoActive;
vfoActive = (d & UBITX_VFOB_FLAG ? VFO_B : VFO_A);
if (vfoActive != prev) {
if (vfoActive == VFO_A) {
if (vfoA != frequency) {
setFrequency(vfoA);
}
} else if (vfoActive == VFO_B) {
if (vfoB != frequency) {
setFrequency(vfoB);
}
}
}
splitOn = d & UBITX_SPLIT_FLAG ? 1 : 0;
prev = ritOn;
ritOn = d & UBITX_RIT_FLAG ? 1 : 0;
if (ritOn != prev) {
if ((ritOn == 1) && (inTx == 0)) {
setFrequency(ritRxFrequency);
}
}
char prev = (cwMode << 1) | isUSB;
isUSB = d.flags & UBITX_USB_FLAG ? 1 : 0;
if (d.flags & UBITX_CW_FLAG) {
cwMode = isUSB ? 2 : 1; // 2 = cwu / 1 = cwl
} else {
cwMode = 0;
}
if ((cwMode << 1) | isUSB != prev) {
setFrequency(frequency);
}
}
};
#endif
/**********************************************************************/
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>(),
};
/**********************************************************************/
RigState::RigState(): RigState(raduinoFields, WIREBUS_NUM_FIELDS) {}
/*!
* @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() {
for (byte i = 0; i < numFields; i++) {
if (read(i)) {
makeDirty(i);
}
}
}
void RigState::update() {
// First we need to determine which fields have changed (and are
// thus dirty and need to be sent to the TeensyDSP).
for (byte i = 0; i < numFields; i++) {
if (read(i)) {
makeDirty(i);
}
}
// Next we need to send the current (changed) Raduino information
// to the TeensyDSP.
Wire.beginTransmission(I2CMETER_ADDR);
Wire.write(I2CMETER_RIGINF);
for (byte i = 0; i < numFields; i++) {
if (isDirty(i)) { // Write each field that is dirty to the bus.
Wire.write(i); // - write the field number/ID
Wire.write(data(i), dataSize(i)); // - write the field data
makeClean(i);
}
}
Wire.endTransmission();
delay(1); // some delay required between ending transmission and requesting?
// Retrieve all of the deltas. Mark any received field as dirty.
Wire.requestFrom(I2CMETER_ADDR, numBytes);
bool doRead = true;
int index = -1;
byte* ptr;
while (Wire.available()) {
byte b = Wire.read();
if (index == -1) {
if (numFields > b) {
ptr = data(b);
field[b].dirty = true;
numDirty++;
index = 0;
} else {
doRead = false;
}
} else {
if (doRead) {
ptr[index] = b;
}
if (++index == 4) {
index = -1;
doRead = true;
}
}
}
// Perform the corresponding update for each dirty field.
for (byte i = 0; i < numFields; i++) {
if (field[i].dirty) {
write(i);
field[i].dirty = false;
numDirty--;
}
}
}
/**********************************************************************/
/*!
* @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.
*/
void RigState::receive_RIGINF() {
// 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;
}
}
}
}
/**********************************************************************/
/*!
* @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
*/
void RigState::send_RIGINF(byte numBytes, RigState& catState) {
// 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
}
}
for (byte i = 0; i < numBytes; i++) {
Wire1.write(rigReqBytes);
}
}
/**********************************************************************/
/*!
* @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;
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);
}
}
// 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);
}
}
/**********************************************************************/
#ifndef TEENSYDUINO
RigState rigState;
#endif
/**********************************************************************
* EOF *
**********************************************************************/