#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(), new Field(), new Field(), new Field(), new Field(), new Field(), }; /**********************************************************************/ RaduinoState::RaduinoState(): RigState(raduinoFields, WIREBUS_NUM_FIELDS) {} void RaduinoState::begin() { for (byte i = 0; i < numFields; i++) { if (read(i)) { makeDirty(i); } } } void RaduinoState::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. The expected response is the number of fields // (in bytes) that the TeensyDSP needs to send in response. Wire.beginTransmission(I2CMETER_ADDR); Wire.write(I2CMETER_RIGINF); // NOTE - I don't think I actually need to do this line, i.e. I don't think the slave cares... it'll read what is sent to it. //Wire.write(numDirty * (sizeof(byte) + sizeof(uint32_t)), 1); // Write the number of dirty fields (in bytes). 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(); // Now we're going to read the response from the TeensyDSP. All // fields should be marked as clean at this point (unless there's // something that has been updated via interrupt???). Wire.requestFrom(I2CMETER_ADDR, 1); byte numBytes; while (Wire.available()) { numBytes = Wire.read(); // Should only get executed for one byte... but just in case. } if (numBytes == 0) return; // Let the TeensyDSP know that we want it to send its deltas now. Wire.beginTransmission(I2CMETER_ADDR); Wire.write(I2CMETER_RIGREQ); Wire.endTransmission(); // 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 RaduinoState::receiveRIGINF() { // 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 RaduinoState::respondRIGINF(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 * **********************************************************************/