LoRa gw to LoRa gw time transfer, time master tracking

pull/142/head
Jeff Lehman 1 year ago
parent 30dc85bfa4
commit 83c12cce94

@ -222,6 +222,10 @@ void loopFDRS()
handleSerial();
#ifdef USE_LORA
handleLoRa();
// Ping LoRa time master to estimate time delay in radio link
if(timeMasterLoRa != 0x0000 && netTimeOffset == UINT32_MAX) {
pingLoRaTimeMaster();
}
#endif
#ifdef USE_WIFI
handleMQTT();

@ -20,10 +20,12 @@ const uint8_t broadcast_mac[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
const uint8_t mac_prefix[] = {MAC_PREFIX};
uint8_t selfAddress[] = {MAC_PREFIX, UNIT_MAC};
uint8_t incMAC[6];
uint8_t timeMasterEspNow[6];
uint8_t ESPNOW1[] = {MAC_PREFIX, ESPNOW_NEIGHBOR_1};
uint8_t ESPNOW2[] = {MAC_PREFIX, ESPNOW_NEIGHBOR_2};
extern time_t now;
bool pingFlag = false;
// Set ESP-NOW send and receive callbacks for either ESP8266 or ESP32
@ -46,6 +48,15 @@ void OnDataRecv(const uint8_t *mac, const uint8_t *incomingData, int len)
DBG("Incoming ESP-NOW System Packet from 0x" + String(incMAC[5], HEX));
memcpy(&theCmd, incomingData, sizeof(theCmd));
memcpy(&incMAC, mac, sizeof(incMAC));
switch (theCmd.cmd)
{
case cmd_ping:
pingFlag = true;
break;
case cmd_time:
setTime(theCmd.param);
break;
}
return;
}
memcpy(&theData, incomingData, sizeof(theData));
@ -247,12 +258,16 @@ esp_err_t pingback_espnow()
// Sends time to both neighbors and all peers
esp_err_t sendTimeESPNow() {
esp_err_t result1, result2, result3;
esp_err_t result1 = ESP_OK, result2 = ESP_OK, result3 = ESP_OK;
DBG("Sending time via ESP-NOW");
SystemPacket sys_packet = { .cmd = cmd_time, .param = now };
result1 = sendESPNow(ESPNOW1, &sys_packet);
result2 = sendESPNow(ESPNOW2, &sys_packet);
if(ESPNOW1 != timeMasterEspNow) {
result1 = sendESPNow(ESPNOW1, &sys_packet);
}
if(ESPNOW2 != timeMasterEspNow) {
result2 = sendESPNow(ESPNOW2, &sys_packet);
}
result3 = sendESPNow(nullptr, &sys_packet);
if(result1 != ESP_OK || result2 != ESP_OK || result3 != ESP_OK){
@ -379,6 +394,30 @@ esp_err_t sendESPNow(uint8_t address) {
void recvTimeEspNow() {
memcpy(timeMasterEspNow, incMAC, sizeof(timeMasterEspNow));
setTime(theCmd.param);
DBG("Received time via ESP-NOW from 0x" + String(incMAC[5], HEX));
}
// FDRS node pings gateway and listens for a defined amount of time for a reply
// Blocking function for timeout amount of time (up to timeout time waiting for reply)(IE no callback)
// Returns the amount of time in ms that the ping takes or predefined value if ping fails within timeout
uint32_t pingFDRSEspNow(uint8_t *address, uint32_t timeout) {
SystemPacket sys_packet = {.cmd = cmd_ping, .param = 0};
esp_now_send(address, (uint8_t *)&sys_packet, sizeof(SystemPacket));
DBG(" ESP-NOW ping sent.");
uint32_t ping_start = millis();
pingFlag = false;
while ((millis() - ping_start) <= timeout)
{
yield(); // do I need to yield or does it automatically?
if (pingFlag)
{
DBG("ESP-NOW Ping Reply in " + String(millis() - ping_start) + "ms from 0x" + String(address[5], HEX));
return (millis() - ping_start);
}
}
DBG("No ESP-NOW ping returned within " + String(timeout) + "ms.");
return UINT32_MAX;
}

@ -100,11 +100,14 @@ volatile bool operationDone = false; // flag to indicate that a packet was sent
uint16_t LoRa1 = ((mac_prefix[4] << 8) | LORA_NEIGHBOR_1); // Use 2 bytes for LoRa addressing instead of previous 3 bytes
uint16_t LoRa2 = ((mac_prefix[4] << 8) | LORA_NEIGHBOR_2);
uint16_t timeMasterLoRa = 0x0000;
uint16_t loraGwAddress = ((selfAddress[4] << 8) | selfAddress[5]); // last 2 bytes of gateway address
uint16_t loraBroadcast = 0xFFFF;
unsigned long receivedLoRaMsg = 0; // Number of total LoRa packets destined for us and of valid size
unsigned long ackOkLoRaMsg = 0; // Number of total LoRa packets with valid CRC
extern time_t now;
time_t lastTimeMasterPing = 0;
time_t netTimeOffset = UINT32_MAX; // One direction of LoRa Ping time in units of seconds (1/2 full ping time)
typedef struct DataBuffer
{
@ -432,6 +435,12 @@ crcResult getLoRa()
transmitLoRa(&sourceMAC, &pingReply, 1);
}
}
else if (ln == 1 && receiveData[0].cmd == cmd_time) {
timeMasterLoRa = sourceMAC;
setTime(receiveData[0].param);
DBG("Time rcv from LoRa 0x" + String(sourceMAC, HEX));
adjTimeforNetDelay(netTimeOffset);
}
else
{ // data we have received is not yet programmed. How we handle is future enhancement.
DBG("Received some LoRa SystemPacket data that is not yet handled. To be handled in future enhancement.");
@ -461,6 +470,12 @@ crcResult getLoRa()
transmitLoRa(&sourceMAC, &pingReply, 1);
}
}
else if (ln == 1 && receiveData[0].cmd == cmd_time) {
timeMasterLoRa = sourceMAC;
setTime(receiveData[0].param);
DBG("Time rcv from LoRa 0x" + String(sourceMAC, HEX));
adjTimeforNetDelay(netTimeOffset);
}
else
{ // data we have received is not yet programmed. How we handle is future enhancement.
DBG("Received some LoRa SystemPacket data that is not yet handled. To be handled in future enhancement.");
@ -656,14 +671,59 @@ void sendTimeLoRa() {
SystemPacket spTimeLoRa = {.cmd = cmd_time, .param = now};
transmitLoRa(&loraBroadcast, &spTimeLoRa, 1);
// Do not send to LoRa peers if their address is 0x..00
if((LoRa1 & 0x00FF) != 0x0000) {
if(((LoRa1 & 0x00FF) != 0x0000) && (LoRa1 != timeMasterLoRa)) {
spTimeLoRa.param = now;
// add LoRa neighbor 1
transmitLoRa(&LoRa1, &spTimeLoRa, 1);
}
if((LoRa2 & 0x00FF) != 0x0000) {
if(((LoRa2 & 0x00FF) != 0x0000) && (LoRa2 != timeMasterLoRa)) {
spTimeLoRa.param = now;
// add LoRa neighbor 2
transmitLoRa(&LoRa2, &spTimeLoRa, 1);
}
}
// FDRS Sensor pings gateway and listens for a defined amount of time for a reply
// Blocking function for timeout amount of time (up to timeout time waiting for reply)(IE no callback)
// Returns the amount of time in ms that the ping takes or predefined value if ping fails within timeout
uint32_t pingFDRSLoRa(uint16_t *address, uint32_t timeout)
{
SystemPacket sys_packet = {.cmd = cmd_ping, .param = 0};
transmitLoRa(address, &sys_packet, 1);
DBG("LoRa ping sent to address: 0x" + String(*address, HEX));
uint32_t ping_start = millis();
pingFlag = false;
while ((millis() - ping_start) <= timeout)
{
handleLoRa();
#ifdef ESP8266
yield();
#endif
if (pingFlag)
{
DBG("LoRa Ping Returned: " + String(millis() - ping_start) + "ms.");
pingFlag = false;
return (millis() - ping_start);
}
}
DBG("No LoRa ping returned within " + String(timeout) + "ms.");
return UINT32_MAX;
}
// Pings the LoRa time master periodically to calculate the time delay in the LoRa radio link
// Returns success or failure of the ping result
bool pingLoRaTimeMaster() {
if(millis() - lastTimeMasterPing > (60000 + random(0,2000))) {
time_t pingTimeMs;
pingTimeMs = pingFDRSLoRa(&timeMasterLoRa,4000);
if(pingTimeMs != UINT32_MAX) {
netTimeOffset = pingTimeMs/2/1000;
adjTimeforNetDelay(netTimeOffset);
lastTimeMasterPing = millis();
return true;
}
lastTimeMasterPing = millis();
}
return false;
}

@ -251,6 +251,19 @@ void checkDST() {
return;
}
// Periodically send time to ESP-NOW or LoRa nodes associated with this gateway/controller
void sendTime() {
if(validTime()) { // Only send time if it is valid
DBG("Sending out time");
// Only send via Serial interface if WiFi is enabled to prevent loops
#ifdef USE_WIFI // do not remove this line
sendTimeSerial();
#endif // do not remove this line
sendTimeLoRa();
sendTimeESPNow();
}
}
bool setTime(time_t currentTime) {
slewSecs = 0;
time_t previousTime = now;
@ -291,18 +304,6 @@ bool setTime(time_t currentTime) {
}
}
// Periodically send time to ESP-NOW or LoRa nodes associated with this gateway/controller
void sendTime() {
if(validTime()) { // Only send time if it is valid
DBG("Sending out time");
// Only send via Serial interface if WiFi is enabled to prevent loops
#ifdef USE_WIFI // do not remove this line
sendTimeSerial();
#endif // do not remove this line
sendTimeLoRa();
sendTimeESPNow();
}
}
void updateTime() {
@ -319,4 +320,15 @@ void updateTime() {
sendTime();
lastTimeSend = millis();
}
}
void adjTimeforNetDelay(time_t newOffset) {
static time_t previousOffset = 0;
updateTime();
// check to see if offset and current time are valid
if(newOffset < UINT32_MAX && validTimeFlag) {
now = now + newOffset - previousOffset;
previousOffset = newOffset;
DBG("Time adj by " + String(newOffset) + " secs");
}
}

@ -153,7 +153,11 @@ void sendNTPpacket(const char * address) {
void fetchNtpTime() {
//DBG("GetTime Function");
if(WiFi.status() == WL_CONNECTED || eth_connected ) {
#ifdef USE_ETHERNET
if(eth_connected) {
#else
if(WiFi.status() == WL_CONNECTED) {
#endif
//DBG("Calling .begin function");
FDRSNtp.begin(localPort);

Loading…
Cancel
Save