From a6db04c201d1fad97508dc2a06409386c088952e Mon Sep 17 00:00:00 2001 From: Dirk Jahnke Date: Thu, 15 Nov 2018 13:01:09 +0100 Subject: [PATCH] Sends broadcast of time messages. --- platformio.ini | 8 ++- src/client.cpp | 143 +++++++++++++++++++++++++++++++++++++++---------- src/client.h | 23 ++++++-- src/config.h | 2 +- src/main.cpp | 95 +++++++++++++++++++++++++------- src/master.cpp | 141 +++++++++++++++++++++++++++++++++++++++++------- src/master.h | 17 +++++- 7 files changed, 356 insertions(+), 73 deletions(-) diff --git a/platformio.ini b/platformio.ini index 22e5d58..77f7adc 100644 --- a/platformio.ini +++ b/platformio.ini @@ -22,7 +22,13 @@ build_flags = -D WITH_DISPLAY platform = atmelavr board = nanoatmega168 framework = arduino -lib_deps = ArduinoJson, RadioHead +# lib_deps = ArduinoJson, RadioHead +lib_deps = ArduinoJson, RF24 +# build_flags = -D FCRF_RadioHead +build_flags = -D FCRF_RF24 +#upload_port = /dev/cu.wchusbserial1410 +#upload_speed = 38400 +#upload_protocol = [env:nanoatmega328] platform = atmelavr diff --git a/src/client.cpp b/src/client.cpp index 4e7ed73..723d5e8 100644 --- a/src/client.cpp +++ b/src/client.cpp @@ -3,6 +3,7 @@ #include "clockMsg.h" #include "client.h" + static struct clockMsg_s clockMsg; int holdRelay_ms = DEFAULT_HOLD_RELAY_MS; int minRelayOffTime_ms = DEFAULT_MIN_RELAY_OFF_TIME_MS; @@ -97,43 +98,129 @@ static void updateRelays(struct clockMsg_s currentTime) { } } -#if WITH_DISPLAY -void clientLoop(RHDatagram Datagram, Adafruit_SSD1306 display) -#else -void clientLoop(RHDatagram Datagram) -#endif -{ - // if (nrf24.available()) - if (Datagram.available()) +#ifdef FCRF_RadioHead + #if WITH_DISPLAY + void clientLoop(RHDatagram Datagram, Adafruit_SSD1306 display) + #else + void clientLoop(RHDatagram Datagram) + #endif { - // Should be a message for us now - uint8_t buf[RH_MAX_MESSAGE_LEN]; + // if (nrf24.available()) + if (Datagram.available()) + { + // Should be a message for us now + uint8_t buf[RH_MAX_MESSAGE_LEN]; + uint8_t len = sizeof(buf); + uint8_t from, to, id, flags; + if (Datagram.recvfrom(buf, &len, &from, &to, &id, &flags)) { + if (len == sizeof(clockMsg) && buf[0]==msgType_Clock) { + Serial.print("Clock Msg: "); + memcpy(&clockMsg, buf, sizeof(clockMsg)); + Serial.print(" h:m:s="); Serial.print(clockMsg.hour); Serial.print(":"); Serial.print(clockMsg.minute); Serial.print(":"); Serial.println(clockMsg.second); + updateRelays(clockMsg); + } else { + Serial.print("got request: "); Serial.print(len); Serial.println(" bytes"); + Serial.print(buf[0], HEX); Serial.print(" "); + Serial.print(buf[1], HEX); Serial.print(" "); + Serial.print(buf[2], HEX); Serial.print(" "); + Serial.print(buf[3], HEX); Serial.print(" "); + Serial.print(buf[4], HEX); Serial.print(" "); + Serial.print(buf[5], HEX); Serial.print(" "); + Serial.print(buf[6], HEX); Serial.print(" "); + Serial.println(buf[7], HEX); + } + } + else + { + Serial.println("*** Datagram.recvfrom failed"); + } + } + + #if WITH_DISPLAY + display.clearDisplay(); + display.setTextSize(1); + display.setTextColor(WHITE); + display.setCursor(0,0); + display.println("FREMO FastClock 1.0"); + display.print(displayedTime.hour); display.print(":"); + display.print(displayedTime.minute); + #endif + } +#endif + +#ifdef FCRF_RF24 + #define RF24_MAX_MESSAGE_LEN 32 + extern const byte *addresses[]; + static bool TX=1,RX=0,role=TX; + + /* + static void switchToSenderRole(RF24 radio) + { + Serial.println("*** client: CHANGING TO TRANSMIT ROLE"); + radio.openWritingPipe(addresses[1]); + radio.openReadingPipe(1,addresses[0]); + radio.stopListening(); + role = TX; // Become the primary transmitter (ping out) + } + */ + + static void switchToReceiverRole(RF24 radio) + { + Serial.println("*** client: CHANGING TO RECEIVER ROLE"); + radio.openWritingPipe(addresses[0]); + radio.openReadingPipe(1,addresses[1]); + radio.startListening(); + role = RX; // Become the primary receiver (pong back) + } + + static unsigned long rxTimer=0, receivedCounter=0; + + #if WITH_DISPLAY + void clientLoop(RF24 radio, Adafruit_SSD1306 display) + #else + void clientLoop(RF24 radio) + #endif + { + //Serial.println("*** RF Rcf loop"); + uint8_t buf[RF24_MAX_MESSAGE_LEN]; uint8_t len = sizeof(buf); - uint8_t from, to, id, flags; - if (Datagram.recvfrom(buf, &len, &from, &to, &id, &flags)) { + unsigned int counter=0; + + switchToReceiverRole(radio); + if (radio.available()) { + radio.read(buf, len); + counter++; + Serial.print(counter); Serial.print(": "); + Serial.print(buf[0], HEX); Serial.print(" "); + Serial.print(buf[1], HEX); Serial.print(" "); + Serial.print(buf[2], HEX); Serial.print(" "); + Serial.print(buf[3], HEX); Serial.print(" "); + Serial.print(buf[4], HEX); Serial.print(" "); + Serial.print(buf[5], HEX); Serial.println(" "); if (len == sizeof(clockMsg) && buf[0]==msgType_Clock) { Serial.print("Clock Msg: "); memcpy(&clockMsg, buf, sizeof(clockMsg)); Serial.print(" h:m:s="); Serial.print(clockMsg.hour); Serial.print(":"); Serial.print(clockMsg.minute); Serial.print(":"); Serial.println(clockMsg.second); updateRelays(clockMsg); } else { - Serial.print("got request: "); - Serial.println((char*)buf); + Serial.print("got request: "); Serial.print(len); Serial.println(" bytes"); + Serial.print(buf[0], HEX); Serial.print(" "); + Serial.print(buf[1], HEX); Serial.print(" "); + Serial.print(buf[2], HEX); Serial.print(" "); + Serial.print(buf[3], HEX); Serial.print(" "); + Serial.print(buf[4], HEX); Serial.print(" "); + Serial.print(buf[5], HEX); Serial.print(" "); + Serial.print(buf[6], HEX); Serial.print(" "); + Serial.println(buf[7], HEX); } } - else - { - Serial.println("*** Datagram.recvfrom failed"); + if (millis() - rxTimer > 1000) { + rxTimer = millis(); + receivedCounter += counter; + unsigned long numBytes = counter*len; + Serial.print("Bytes: "); Serial.print(numBytes); + Serial.print(", Msg count: "); Serial.println(counter); + counter = 0; } } - - #if WITH_DISPLAY - display.clearDisplay(); - display.setTextSize(1); - display.setTextColor(WHITE); - display.setCursor(0,0); - display.println("FREMO FastClock 1.0"); - display.print(displayedTime.hour); display.print(":"); - display.print(displayedTime.minute); - #endif -} +#endif diff --git a/src/client.h b/src/client.h index 3ddcf6f..c4cfe39 100644 --- a/src/client.h +++ b/src/client.h @@ -1,13 +1,30 @@ #ifndef CLIENT_H_INCLUDED #define CLIENT_H_INCLUDED -#include +#ifdef FCRF_RadioHead + #include + #include +#endif +#ifdef FCRF_RF24 + #include + #include +#endif extern void clientInit(); +#ifdef FCRF_RadioHead + #if WITH_DISPLAY + extern void clientLoop(RHDatagram Datagram, Adafruit_SSD1306 display); + #else + extern void clientLoop(RHDatagram Datagram); + #endif +#endif + +#ifdef FCRF_RF24 #if WITH_DISPLAY - extern void clientLoop(RHDatagram Datagram, Adafruit_SSD1306 display); + extern void clientLoop(RF24 radio, Adafruit_SSD1306 display); #else - extern void clientLoop(RHDatagram Datagram); + extern void clientLoop(RF24 radio); +#endif #endif #endif diff --git a/src/config.h b/src/config.h index a7ad86b..321f48b 100644 --- a/src/config.h +++ b/src/config.h @@ -5,7 +5,7 @@ #define ROLE_MASTER LOW #define ROLE_CLIENT HIGH #define PIN_NRF24_CE 10 -#define PIN_NRF24_CSN 8 +#define PIN_NRF24_CSN 7 #define PIN_RELAY1 5 #define PIN_RELAY2 6 diff --git a/src/main.cpp b/src/main.cpp index d0ba209..c6c7847 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,31 +1,47 @@ #include #include -#include -#include +#ifdef FCRF_RadioHead + #include + #include +#endif +#ifdef FCRF_RF24 + #include +#endif #include "config.h" #include "clockMsg.h" #include "master.h" #include "client.h" #if WITH_DISPLAY -#include -#include + #include + #include -#define OLED_RESET /*4*/ -Adafruit_SSD1306 display(OLED_RESET); + #define OLED_RESET /*4*/ + Adafruit_SSD1306 display(OLED_RESET); #endif -// Singleton instance of the radio driver -RH_NRF24 nrf24(PIN_NRF24_CSN, PIN_NRF24_CE); +#ifdef FCRF_RadioHead + // Singleton instance of the radio driver + RH_NRF24 nrf24(PIN_NRF24_CSN, PIN_NRF24_CE); + // Address RH_BROADCAST_ADDRESS can be used for broadcasts as destination + RHDatagram Datagram(nrf24, THIS_ADRESS); +#endif -// Address RH_BROADCAST_ADDRESS can be used for broadcasts as destination -RHDatagram Datagram(nrf24, THIS_ADRESS); +#ifdef FCRF_RF24 + RF24 radio(PIN_NRF24_CE, PIN_NRF24_CSN); + // const uint64_t pipes[2] = { 0xABCDABCD71LL, 0x544d52687CLL }; + const byte *addresses[] = {"1Mstr","2Mstr"}; + byte data[32]; + unsigned long sendFailedCounter=0, rxTimer; //Counter and timer for keeping track transfer info + unsigned long receivedCounter=0; + unsigned long startTime, stopTime, pauseTime; +#endif int masterConfigPin = PIN_MASTER_CLIENT_SELECT; static boolean isMaster = true; void setup() { - Serial.begin(9600); + Serial.begin(115200); while (!Serial) ; // wait for serial port to connect. Needed for Leonardo only @@ -42,8 +58,33 @@ void setup() { Serial.println("In Client-Mode"); } +#ifdef FCRF_RadioHead if (!Datagram.init()) Serial.println("Init datagram with nrf24 failed"); +#endif + +#ifdef FCRF_RF24 + radio.begin(); + if (radio.isChipConnected()) { Serial.println("*** RF chip found"); } + else { Serial.println("*** ERROR: RF chip not found!"); } + radio.setChannel(1); + radio.setPALevel(RF24_PA_MAX); + radio.setDataRate(RF24_2MBPS); + radio.setAutoAck(0); + //radio.setRetries(2,15); // Optionally, increase the delay between retries & # of retries + radio.setCRCLength(RF24_CRC_8); + radio.openWritingPipe(addresses[0]); + radio.openReadingPipe(1,addresses[1]); + radio.startListening(); + radio.printDetails(); + // @TODO: real random seed! + randomSeed(analogRead(0)); + //randomSeed(22); + radio.powerUp(); + Serial.print("*** RF payload size="); Serial.print(radio.getPayloadSize()); Serial.println(" bytes"); + if (radio.testCarrier() || radio.testRPD()) { Serial.println("*** Carrier/RPD seen on radio"); } + if (radio.failureDetected) { Serial.println("*** Radio error detected!"); } +#endif #if WITH_DISPLAY display.begin(SSD1306_SWITCHCAPVCC, 0x3C); @@ -69,13 +110,27 @@ void setup() { } void loop() { - if (isMaster) { - masterLoop(Datagram); - } else { - #if WITH_DISPLAY - clientLoop(Datagram, display); - #else - clientLoop(Datagram); - #endif - } + #ifdef FCRF_RadioHead + if (isMaster) { + masterLoop(Datagram); + } else { + #if WITH_DISPLAY + clientLoop(Datagram, display); + #else + clientLoop(Datagram); + #endif + } + #endif + + #ifdef FCRF_RF24 + if (isMaster) { + masterLoop(radio); + } else { + #if WITH_DISPLAY + clientLoop(radio, display); + #else + clientLoop(radio); + #endif + } + #endif } diff --git a/src/master.cpp b/src/master.cpp index fd88e02..2305c66 100644 --- a/src/master.cpp +++ b/src/master.cpp @@ -3,20 +3,86 @@ #include "clockMsg.h" #include "master.h" + static struct clockMsg_s clockMsg; +static unsigned long lastSentTimeTick = 0; +static unsigned long sendFastclockTimer_ms = 3000; +static unsigned long msPerModelSecond = 50; // 500 = real time +static unsigned long sendFailedCounter = 0, pauseTime = 0, stopTime = 0; +static struct clock_s { + uint8_t day; + uint8_t hour; + uint8_t minute; + uint8_t second; + uint16_t millisecond; +} fastclock; void masterInit() { clockMsg.hour = 0; clockMsg.minute = 0; clockMsg.second = 0; + lastSentTimeTick = millis(); + Serial.print("*** Setting up master, init lastSentTimeTick="); Serial.println(lastSentTimeTick); + fastclock.day = 0; + fastclock.hour = 0; + fastclock.minute = 0; + fastclock.second = 0; + fastclock.millisecond = 0; } + +static void incrementClockByMilliseconds(int amount) { + fastclock.millisecond += amount; + if (fastclock.millisecond >= 1000) { + int carryover = fastclock.millisecond / 1000; + fastclock.millisecond = fastclock.millisecond % 1000; + fastclock.second += carryover; + if (fastclock.second >= 60) { + carryover = fastclock.second / 60; + fastclock.second = fastclock.second % 60; + fastclock.minute += carryover; + if (fastclock.minute >= 60) { + carryover = fastclock.minute / 60; + fastclock.minute = fastclock.minute % 60; + fastclock.hour += carryover; + if (fastclock.hour >= 24) { + carryover = fastclock.hour / 24; + fastclock.hour = fastclock.hour % 24; + fastclock.day += carryover; + if (fastclock.day >= 7) { + fastclock.day = fastclock.day % 7; + } + } + } + } + } + Serial.print("*** new clock: "); + Serial.print(fastclock.hour); Serial.print(":"); + Serial.print(fastclock.minute); Serial.print(":"); + Serial.print(fastclock.second); Serial.print("."); + Serial.print(fastclock.millisecond); + Serial.print(" day "); Serial.print(fastclock.day); + Serial.print(", incBy_ms="); Serial.print(amount); +} + +static void timeTick(void) { + long newTimeTick = millis(); + int fastclockTimeAdvance = (newTimeTick - lastSentTimeTick) * 1000 / msPerModelSecond; + + incrementClockByMilliseconds(fastclockTimeAdvance); + lastSentTimeTick = newTimeTick; + Serial.print("*** tick (adv="); Serial.print(fastclockTimeAdvance); Serial.println("%d)"); +} + + +#ifdef FCRF_RadioHead void masterLoop(RHDatagram Datagram) { static unsigned long nextTimeTick_ms = millis(); static unsigned long updateEvery_ms = 1000; static uint8_t hour=0, minute=0, second=0; + timeTick(); if (Datagram.available()) { // Should be a message for us now @@ -33,25 +99,10 @@ void masterLoop(RHDatagram Datagram) Serial.println("*** Datagram.recvfrom failed"); } } else { - // prepare clock info - if (nextTimeTick_ms < millis()) { - nextTimeTick_ms += updateEvery_ms; - second++; - if (second >= 60) { - second -= 60; - minute++; - if (minute >= 60) { - minute -= 60; - hour++; - if (hour >= 24) { - hour -= 24; - } - } - } clockMsg.msgType = msgType_Clock; - clockMsg.hour = hour; - clockMsg.minute = minute; - clockMsg.second = second; + clockMsg.hour = fastclock.hour; + clockMsg.minute = fastclock.minute; + clockMsg.second = fastclock.second; // send clock info as a broadcast message @@ -64,3 +115,57 @@ void masterLoop(RHDatagram Datagram) } } } +#endif + +#ifdef FCRF_RF24 +extern const byte *addresses[]; +static bool TX=1,RX=0,role=RX; + +static void switchToSenderRole(RF24 radio) +{ + Serial.println("*** master: CHANGING TO TRANSMIT ROLE"); + radio.openWritingPipe(addresses[1]); + radio.openReadingPipe(1,addresses[0]); + radio.stopListening(); + role = TX; // Become the primary transmitter (ping out) +} + +/* +static void switchToReceiverRole(RF24 radio) +{ + Serial.println("*** master: CHANGING TO RECEIVER ROLE"); + radio.openWritingPipe(addresses[0]); + radio.openReadingPipe(1,addresses[1]); + radio.startListening(); + role = RX; // Become the primary receiver (pong back) +} +*/ + +void masterLoop(RF24 radio) { + timeTick(); + + if (millis() - lastSentTimeTick > sendFastclockTimer_ms) { + lastSentTimeTick = millis(); + clockMsg.msgType = msgType_Clock; + clockMsg.hour = fastclock.hour; + clockMsg.minute = fastclock.minute; + clockMsg.second = fastclock.second; + switchToSenderRole(radio); + if (!radio.write(&clockMsg, sizeof(clockMsg), true /*multicast*/)) { + sendFailedCounter++; + } + //This is only required when NO ACK ( enableAutoAck(0) ) payloads are used + if (millis() - pauseTime > 3) { + pauseTime = millis(); + radio.txStandBy(); // Need to drop out of TX mode every 4ms if sending a steady stream of multicast data + //delayMicroseconds(130); // This gives the PLL time to sync back up + } + stopTime = millis(); + //This should be called to wait for completion and put the radio in standby mode after transmission, returns 0 if data still in FIFO (timed out), 1 if success + if (!radio.txStandBy()) { sendFailedCounter += 3; } //Standby, block only until FIFO empty or auto-retry timeout. Flush TX FIFO if failed + //radio.txStandBy(1000); //Standby, using extended timeout period of 1 second + + Serial.println("*** send finished"); + } +} +#endif diff --git a/src/master.h b/src/master.h index 8acf0c7..5027502 100644 --- a/src/master.h +++ b/src/master.h @@ -1,8 +1,21 @@ #ifndef MASTER_H_INCLUDED #define MASTER_H_INCLUDED -#include +#ifdef FCRF_RadioHead + #include + #include +#endif +#ifdef FCRF_RF24 + #include + #include +#endif + extern void masterInit(); -extern void masterLoop(RHDatagram Datagram); +#ifdef FCRF_RadioHead + extern void masterLoop(RHDatagram Datagram); +#endif +#ifdef FCRF_RF24 + extern void masterLoop(RF24 radio); +#endif #endif