#include "" /**********************************************************************/ // Raduino externs -- generally defined in Raduino.ino or ubitx.h #ifndef TEENSYDUINO #include "ubitx_eemap.h" 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); /*! * @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)) { if (vfoActive == VFO_A) { setFrequency(r.getFreqA()); } else { vfoA = r.getFreqA(); } } // VFO B frequency if (r.isDirty(VFOB_WORD)) { if (vfoActive == VFO_B) { setFrequency(r.getFreqB()); } else { vfoB = r.getFreqB(); } } // RIT and XIT frequencies if (r.isDirty(OFFSETS_WORD)) { // RIT ritRxFrequency = r.getRIT() + ritTxFrequency; if ((ritOn == 1) && (inTx == 0)) { setFrequency(ritRxFrequency); } // XIT - TODO } // VFO A/B selection if (r.isDirty(FLAGS_WORD)) { char prev = vfoActive; vfoActive = r.isVFOA() ? VFO_A : VFO_B; if (vfoActive != prev) { if (vfoActive == VFO_A) { if (vfoA != frequency) { setFrequency(vfoA); } } else if (vfoActive == VFO_B) { if (vfoB != frequency) { setFrequency(vfoB); } } } // Split on/off splitOn = r.isSplit() ? 1 : 0; // RIT on/off prev = ritOn; ritOn = r.isRIT() ? 1 : 0; if (ritOn != prev) { if ((ritOn == 1) && (inTx == 0)) { setFrequency(ritRxFrequency); } } // 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 } else { cwMode = 0; // 0 = no cw } if ((cwMode << 1) | isUSB != prev) { setFrequency(frequency); } } } /*! * @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); } #endif /**********************************************************************/ BaseField* raduinoFields[WIREBUS_NUM_FIELDS] = { new Field(), new Field(), new Field(), new Field(), new Field(), new Field(), }; /**********************************************************************/ 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 updateRaduinoState(RigState& r) { writeDirty(r); Wire.beginTransmission(I2CMETER_ADDR); Wire.write(I2CMETER_RIGINF); for (RigStateWord i = 0; i < NUM_WORDS; i++) { Wire.write((byte*)&r.data, sizeof(r.data)); // - write the field data r.setClean(i); } Wire.endTransmission(); delay(1); // 1ms - 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 * **********************************************************************/