diff --git a/Firmware/LoRaSerial/LoRaSerial.ino b/Firmware/LoRaSerial/LoRaSerial.ino index eb33984f..82561953 100644 --- a/Firmware/LoRaSerial/LoRaSerial.ino +++ b/Firmware/LoRaSerial/LoRaSerial.ino @@ -64,7 +64,7 @@ const int FIRMWARE_VERSION_MINOR = 0; #define UNIQUE_ID_BYTES 16 //Number of bytes in the unique ID //Frame lengths -#define MP_HEARTBEAT_BYTES 1 //Number of data bytes in the MP_HEARTBEAT frame +#define MP_HEARTBEAT_BYTES (sizeof(uint8_t) + sizeof(unsigned long)) //Number of data bytes in the MP_HEARTBEAT frame #define P2P_FIND_PARTNER_BYTES sizeof(unsigned long) //Number of data bytes in the FIND_PARTNER frame #define P2P_SYNC_CLOCKS_BYTES (sizeof(uint8_t) + sizeof(unsigned long)) //Number of data bytes in the SYNC_CLOCKS frame #define P2P_ZERO_ACKS_BYTES sizeof(unsigned long) //Number of data bytes in the ZERO_ACKS frame diff --git a/Firmware/LoRaSerial/Radio.ino b/Firmware/LoRaSerial/Radio.ino index 0b5e29b8..3c90a88c 100644 --- a/Firmware/LoRaSerial/Radio.ino +++ b/Firmware/LoRaSerial/Radio.ino @@ -931,8 +931,7 @@ bool xmitDatagramP2PSyncClocks() radioCallHistory[RADIO_CALL_xmitDatagramP2PSyncClocks] = currentMillis; startOfData = endOfTxData; - memcpy(endOfTxData, &channelNumber, sizeof(channelNumber)); - endOfTxData += sizeof(channelNumber); + *endOfTxData++ = channelNumber; memcpy(endOfTxData, ¤tMillis, sizeof(currentMillis)); endOfTxData += sizeof(unsigned long); @@ -1149,18 +1148,20 @@ bool xmitDatagramMpHeartbeat() radioCallHistory[RADIO_CALL_xmitDatagramMpHeartbeat] = millis(); startOfData = endOfTxData; - memcpy(endOfTxData, &channelNumber, sizeof(channelNumber)); - endOfTxData += sizeof(channelNumber); + *endOfTxData++ = channelNumber; + + memcpy(endOfTxData, ¤tMillis, sizeof(currentMillis)); + endOfTxData += sizeof(unsigned long); /* - endOfTxData ---. - | - V - +----------+---------+----------+------------+---------+----------+ - | Optional | | Optional | Optional | Channel | | - | NET ID | Control | C-Timer | SF6 Length | Number | Trailer | - | 8 bits | 8 bits | 2 bytes | 8 bits | 1 byte | n Bytes | - +----------+---------+----------+------------+---------+----------+ + endOfTxData ---. + | + V + +----------+---------+----------+------------+---------+---------+----------+ + | Optional | | Optional | Optional | Channel | | | + | NET ID | Control | C-Timer | SF6 Length | Number | Millis | Trailer | + | 8 bits | 8 bits | 2 bytes | 8 bits | 1 byte | 4 bytes | n Bytes | + +----------+---------+----------+------------+---------+---------+----------+ */ //Verify the data length @@ -3249,7 +3250,7 @@ void stopChannelTimer() //Given the remote unit's number of ms before its next hop, //adjust our own channelTimer interrupt to be synchronized with the remote unit -void syncChannelTimer(uint32_t frameAirTimeUsec) +void syncChannelTimer(uint32_t frameAirTimeUsec, bool clockStarting) { int16_t adjustment; uint8_t caseNumber; @@ -3317,6 +3318,48 @@ void syncChannelTimer(uint32_t frameAirTimeUsec) //timer update will add only microseconds to when the hop is done. delayedHopCount = timeToHop ? 1 : 0; + // 4800 BPS operation + // + // |<---------------- Millis to HOP ---------------->| + // _____ | |_____________ + // |_|_________________________________________________| + // | | | + // TX Start ^ TX Complete ^ |<-- rmtHopTimeMsec -->| + // RX Complete ^ + // + // + // 150 BPS operation + // + // |<--- Millis to HOP --->| + // _____ | |_________________________ + // |_|_______________________| | |_____________ + // | | | + // TX Start ^ TX Complete ^ | | + // RX Complete ^ | + // |<- ->| + // rmtHopTimeMsec + // + // Millis to HOP + // |<- ->| + // | |_________________________ __ + // ___________|_____| |_________________________| + // | | | + // TX Start ^ TX Complete ^ | | + // RX Complete ^ | + // |<---- ---->| + // rmtHopTimeMsec + // + //For low speed operation move the TX start into the current dwell time period + //to make the rest of the math look like the 4800 BPS operation. + frameAirTimeMsec = settings.maxDwellTime - msToNextHopRemote + + (frameAirTimeUsec + settings.txToRxUsec + micros() - transactionCompleteMicros) / 1000; + while (frameAirTimeMsec >= (settings.maxDwellTime + (settings.maxDwellTime >> 6))) + { + frameAirTimeMsec -= settings.maxDwellTime; + if (clockStarting) + delayedHopCount += 1; //Account for the missing hop when the timer is stopped + } + //The radios are using the same frequencies since the frame was successfully //received. The goal is to adjust the channel timer to fire in close proximity //to the firing of the remote sysstem's channel timer. The following cases @@ -3337,8 +3380,7 @@ void syncChannelTimer(uint32_t frameAirTimeUsec) //Compute the remote system's channel timer firing time offset in milliseconds //using the channel timer value and the adjustments for transmit and receive //time (time of flight) - frameAirTimeMsec = (frameAirTimeUsec + settings.txToRxUsec + micros() - transactionCompleteMicros) / 1000; - rmtHopTimeMsec = msToNextHopRemote - frameAirTimeMsec; + rmtHopTimeMsec = settings.maxDwellTime - frameAirTimeMsec; //Compute when the local system last hopped lclHopTimeMsec = currentMillis - channelTimerStart; diff --git a/Firmware/LoRaSerial/States.ino b/Firmware/LoRaSerial/States.ino index 071b3a5d..afdd09ef 100644 --- a/Firmware/LoRaSerial/States.ino +++ b/Firmware/LoRaSerial/States.ino @@ -750,7 +750,7 @@ void updateRadioState() COMPUTE_TIMESTAMP_OFFSET(rxData, 1, txDataAckUsec); //The datagram we are expecting - syncChannelTimer(txDataAckUsec); //Adjust freq hop ISR based on remote's remaining clock + syncChannelTimer(txDataAckUsec, 0); //Adjust freq hop ISR based on remote's remaining clock triggerEvent(TRIGGER_RX_ACK); @@ -1067,9 +1067,9 @@ void updateRadioState() //then skip active discovery and go to standby if (((frameAirTimeUsec + txDataAckUsec + settings.txToRxUsec) / 1000) > (settings.maxDwellTime / 2)) { - stopChannelTimer(); channelNumber = 0; setRadioFrequency(false); + stopChannelTimer(); changeState(RADIO_DISCOVER_STANDBY); } else @@ -1160,7 +1160,7 @@ void updateRadioState() //Start and adjust freq hop ISR based on remote's remaining clock startChannelTimer(); channelTimerStart -= settings.maxDwellTime; - syncChannelTimer(txSyncClocksUsec); + syncChannelTimer(txSyncClocksUsec, 1); triggerEvent(TRIGGER_RX_SYNC_CLOCKS); if (settings.debugSync) @@ -1304,8 +1304,7 @@ void updateRadioState() //Start and adjust freq hop ISR based on remote's remaining clock startChannelTimer(); channelTimerStart -= settings.maxDwellTime; - syncChannelTimer(txSyncClocksUsec); - triggerEvent(TRIGGER_RX_SYNC_CLOCKS); + syncChannelTimer(txSyncClocksUsec, 1); if (settings.debugSync) { @@ -1423,7 +1422,7 @@ void updateRadioState() if (settings.server == false) { //Adjust freq hop ISR based on server's remaining clock - syncChannelTimer(txHeartbeatUsec); + syncChannelTimer(txHeartbeatUsec, 0); //Received heartbeat - do not ack. triggerEvent(TRIGGER_RX_HEARTBEAT); @@ -3225,7 +3224,7 @@ void vcReceiveHeartbeat(uint32_t rxMillis) //Adjust freq hop ISR based on server's remaining clock if ((rxSrcVc == VC_SERVER) || (memcmp(rxVcData, myUniqueId, sizeof(myUniqueId)) == 0)) - syncChannelTimer(txHeartbeatUsec); + syncChannelTimer(txHeartbeatUsec, 0); //Update the timestamp offset if (rxSrcVc == VC_SERVER)