Compare commits
2 Commits
672d5baf23
...
2eda00c694
Author | SHA1 | Date |
---|---|---|
Dirk Jahnke | 2eda00c694 | |
Dirk Jahnke | fbf8af5684 |
|
@ -8,15 +8,18 @@
|
||||||
; Please visit documentation for the other options and examples
|
; Please visit documentation for the other options and examples
|
||||||
; https://docs.platformio.org/page/projectconf.html
|
; https://docs.platformio.org/page/projectconf.html
|
||||||
|
|
||||||
[env:d1_mini_pro]
|
[platformio]
|
||||||
platform = espressif8266
|
env_default = heltec_wifi_kit_8
|
||||||
board = d1_mini_pro
|
|
||||||
framework = arduino
|
|
||||||
|
|
||||||
[env:heltec_wifi_kit_8]
|
[env:heltec_wifi_kit_8]
|
||||||
platform = espressif8266
|
platform = espressif8266
|
||||||
board = heltec_wifi_kit_8
|
board = heltec_wifi_kit_8
|
||||||
framework = arduino
|
framework = arduino
|
||||||
|
|
||||||
|
[env:d1_mini_pro]
|
||||||
|
platform = espressif8266
|
||||||
|
board = d1_mini_pro
|
||||||
|
framework = arduino
|
||||||
|
|
||||||
[lib_deps]
|
[lib_deps]
|
||||||
library = WifiManager, RF24, U8g2
|
library = WifiManager, RF24, U8g2
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
#ifndef clockMsg_h_included
|
||||||
|
#define clockMsg_h_included
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
|
||||||
|
struct clockMsg_s {
|
||||||
|
uint8_t msgType;
|
||||||
|
uint8_t day;
|
||||||
|
uint8_t hour;
|
||||||
|
uint8_t minute;
|
||||||
|
uint8_t second;
|
||||||
|
uint8_t speed; // msPerModelSecond / 4 --> 0..250
|
||||||
|
};
|
||||||
|
#define msgType_Clock 'c' /* clock update, sent by master using broadcast */
|
||||||
|
#define msgType_ReqReg 'R' /* Request Registration, sent by Master using broadcast; ask clients to register */
|
||||||
|
#define msgType_Reg 'r' /* Registration message, sent by Client using 1:1 message to master */
|
||||||
|
|
||||||
|
#endif
|
|
@ -18,4 +18,8 @@
|
||||||
#define DEFAULT_MIN_RELAY_OFF_TIME_MS 80
|
#define DEFAULT_MIN_RELAY_OFF_TIME_MS 80
|
||||||
#define DEFAULT_RELAY_ACTIVE_LOW true
|
#define DEFAULT_RELAY_ACTIVE_LOW true
|
||||||
|
|
||||||
|
// field sizes
|
||||||
|
#define MAX_CLOCK_NAME_LEN 8
|
||||||
|
#define MAX_CLIENT_NAME_LEN 10
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -4,7 +4,6 @@
|
||||||
|
|
||||||
#include "display.h"
|
#include "display.h"
|
||||||
|
|
||||||
|
|
||||||
// display
|
// display
|
||||||
//U8G2_SSD1306_128X32_UNIVISION_F_HW_I2C u8g2(U8G2_R0, /* reset=*/ 16, /* clock=*/ 5, /* data=*/ 4);
|
//U8G2_SSD1306_128X32_UNIVISION_F_HW_I2C u8g2(U8G2_R0, /* reset=*/ 16, /* clock=*/ 5, /* data=*/ 4);
|
||||||
U8G2_SSD1306_128X32_UNIVISION_F_HW_I2C u8g2(U8G2_R0, /* reset=16*/ -1, /* clock=*/ 5, /* data=*/ 4);
|
U8G2_SSD1306_128X32_UNIVISION_F_HW_I2C u8g2(U8G2_R0, /* reset=16*/ -1, /* clock=*/ 5, /* data=*/ 4);
|
||||||
|
|
|
@ -1,15 +1,16 @@
|
||||||
#ifndef display_h_included
|
#ifndef display_h_included
|
||||||
#define display_h_included
|
#define display_h_included
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
// avoid flickering of the display:
|
// avoid flickering of the display:
|
||||||
#define TIME_BETWEEN_DISPLAY_UPDATES_ms 200
|
#define TIME_BETWEEN_DISPLAY_UPDATES_ms 200
|
||||||
#define BLINK_ON_OFF_TIME_ms 1000
|
#define BLINK_ON_OFF_TIME_ms 1000
|
||||||
|
|
||||||
#define MAX_CLOCK_NAME_LEN 8
|
|
||||||
#define MAX_CLOCK_SPEED_LEN 8
|
#define MAX_CLOCK_SPEED_LEN 8
|
||||||
#define MAX_CLOCK_WEEKDAY_LEN 4
|
#define MAX_CLOCK_WEEKDAY_LEN 4
|
||||||
#define MAX_NUMBER_CLIENTS_DISPLAYED 5
|
#define MAX_NUMBER_CLIENTS_DISPLAYED 5
|
||||||
#define MAX_CLIENT_NAME_LEN 10
|
|
||||||
#define MAX_LOG_MESSAGE_LEN 30
|
#define MAX_LOG_MESSAGE_LEN 30
|
||||||
#define MAX_NUMBER_LOG_LINES 5
|
#define MAX_NUMBER_LOG_LINES 5
|
||||||
|
|
||||||
|
|
|
@ -67,6 +67,7 @@ void Fastclock::loop(void) {
|
||||||
// time has changed, send an update via rf
|
// time has changed, send an update via rf
|
||||||
// @TODO implement sending radio message
|
// @TODO implement sending radio message
|
||||||
Serial.println("Would send new time");
|
Serial.println("Would send new time");
|
||||||
|
radio->broadcastClock(weekday, hour, minute, second, msPerModelSecond);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,14 +1,16 @@
|
||||||
#ifndef fastclock_h_included
|
#ifndef fastclock_h_included
|
||||||
#define fastclock_h_included
|
#define fastclock_h_included
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
#include "display.h"
|
#include "display.h"
|
||||||
|
#include "radio.h"
|
||||||
|
|
||||||
#define MIN_TIME_ms_BETWEEN_CLOCK_UPDATES 200
|
#define MIN_TIME_ms_BETWEEN_CLOCK_UPDATES 200
|
||||||
#define DEFAULT_ms_PER_MODEL_SECOND 250
|
#define DEFAULT_ms_PER_MODEL_SECOND 250
|
||||||
|
|
||||||
class Fastclock {
|
class Fastclock {
|
||||||
public:
|
public:
|
||||||
Fastclock(Display *d): display(d) { weekday=0; hour=0; minute=0; second=0; millisecond=0; msPerModelSecond=DEFAULT_ms_PER_MODEL_SECOND; halted = true; };
|
Fastclock(Display *d, Radio *r): display(d), radio(r) { weekday=0; hour=0; minute=0; second=0; millisecond=0; msPerModelSecond=DEFAULT_ms_PER_MODEL_SECOND; halted = true; };
|
||||||
void begin(void);
|
void begin(void);
|
||||||
void loop(void);
|
void loop(void);
|
||||||
void incrementClockByMilliseconds(int amount);
|
void incrementClockByMilliseconds(int amount);
|
||||||
|
@ -20,6 +22,7 @@ public:
|
||||||
void setClockHalted(bool setToHalt) { halted = setToHalt; display->setClockHalted(halted); };
|
void setClockHalted(bool setToHalt) { halted = setToHalt; display->setClockHalted(halted); };
|
||||||
private:
|
private:
|
||||||
Display *display;
|
Display *display;
|
||||||
|
Radio *radio;
|
||||||
unsigned long lastTimeTickUsed; // used to calculate model time
|
unsigned long lastTimeTickUsed; // used to calculate model time
|
||||||
unsigned long msPerModelSecond; // 500 = twice as fast as real time
|
unsigned long msPerModelSecond; // 500 = twice as fast as real time
|
||||||
uint8_t weekday;
|
uint8_t weekday;
|
||||||
|
|
10
src/main.cpp
10
src/main.cpp
|
@ -34,8 +34,8 @@ bool shouldSaveConfig = false;
|
||||||
bool isMaster = true;
|
bool isMaster = true;
|
||||||
|
|
||||||
Display display;
|
Display display;
|
||||||
Fastclock fastclock(&display);
|
|
||||||
Radio radio(&display, true /*isMaster*/);
|
Radio radio(&display, true /*isMaster*/);
|
||||||
|
Fastclock fastclock(&display, &radio);
|
||||||
|
|
||||||
//callback notifying us of the need to save config
|
//callback notifying us of the need to save config
|
||||||
void saveConfigCallback () {
|
void saveConfigCallback () {
|
||||||
|
@ -207,12 +207,20 @@ void setup() {
|
||||||
fastclock.begin();
|
fastclock.begin();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool requestToRegisterSent = false;
|
||||||
|
|
||||||
void loop(void)
|
void loop(void)
|
||||||
{
|
{
|
||||||
if (!display.showBootSequenceFinished(1000)) {
|
if (!display.showBootSequenceFinished(1000)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!requestToRegisterSent) {
|
||||||
|
radio.broadcastRequestRegistration("testClock");
|
||||||
|
requestToRegisterSent = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
#if defined(AUTOSTART_CLOCK_AFTER_ms)
|
#if defined(AUTOSTART_CLOCK_AFTER_ms)
|
||||||
#if AUTOSTART_CLOCK_AFTER_ms > 0
|
#if AUTOSTART_CLOCK_AFTER_ms > 0
|
||||||
static unsigned long autostart_ms = 0;
|
static unsigned long autostart_ms = 0;
|
||||||
|
|
143
src/radio.cpp
143
src/radio.cpp
|
@ -3,6 +3,8 @@
|
||||||
#include <RF24.h>
|
#include <RF24.h>
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "radio.h"
|
#include "radio.h"
|
||||||
|
#include "clockMsg.h"
|
||||||
|
|
||||||
|
|
||||||
static RF24 rf24(PIN_NRF24_CE, PIN_NRF24_CSN); // 10, 8
|
static RF24 rf24(PIN_NRF24_CE, PIN_NRF24_CSN); // 10, 8
|
||||||
static byte addresses[][6] = {NETWORK_ADDRESS_MASTER_SEND, NETWORK_ADDRESS_MASTER_RECEIVE};
|
static byte addresses[][6] = {NETWORK_ADDRESS_MASTER_SEND, NETWORK_ADDRESS_MASTER_RECEIVE};
|
||||||
|
@ -11,7 +13,7 @@ void Radio::begin(void) {
|
||||||
display->addLogMessage("Start RF24 radio");
|
display->addLogMessage("Start RF24 radio");
|
||||||
pinMode(PIN_NRF24_CSN, OUTPUT);
|
pinMode(PIN_NRF24_CSN, OUTPUT);
|
||||||
pinMode(PIN_NRF24_CE, OUTPUT);
|
pinMode(PIN_NRF24_CE, OUTPUT);
|
||||||
return;
|
|
||||||
rf24.begin();
|
rf24.begin();
|
||||||
if (rf24.isChipConnected()) { display->addLogMessage("*** RF chip found"); }
|
if (rf24.isChipConnected()) { display->addLogMessage("*** RF chip found"); }
|
||||||
else { display->addLogMessage("*** ERROR: RF chip not found!"); }
|
else { display->addLogMessage("*** ERROR: RF chip not found!"); }
|
||||||
|
@ -24,11 +26,12 @@ void Radio::begin(void) {
|
||||||
rf24.openWritingPipe(addresses[0]);
|
rf24.openWritingPipe(addresses[0]);
|
||||||
rf24.openReadingPipe(1, addresses[1]);
|
rf24.openReadingPipe(1, addresses[1]);
|
||||||
rf24.startListening();
|
rf24.startListening();
|
||||||
rf24.printDetails();
|
Serial.println("*** Check");
|
||||||
|
//rf24.printDetails();
|
||||||
|
rf24.powerUp();
|
||||||
// @TODO: real random seed!
|
// @TODO: real random seed!
|
||||||
//randomSeed(analogRead(0));
|
//randomSeed(analogRead(0));
|
||||||
//randomSeed(22);
|
//randomSeed(22);
|
||||||
rf24.powerUp();
|
|
||||||
Serial.print("*** RF payload size="); Serial.print(rf24.getPayloadSize()); Serial.println(" bytes");
|
Serial.print("*** RF payload size="); Serial.print(rf24.getPayloadSize()); Serial.println(" bytes");
|
||||||
if (rf24.testCarrier() || rf24.testRPD()) { display->addLogMessage("*** Carrier/RPD seen on radio"); }
|
if (rf24.testCarrier() || rf24.testRPD()) { display->addLogMessage("*** Carrier/RPD seen on radio"); }
|
||||||
if (rf24.failureDetected) { display->addLogMessage("*** Radio error detected!"); }
|
if (rf24.failureDetected) { display->addLogMessage("*** Radio error detected!"); }
|
||||||
|
@ -50,57 +53,109 @@ void Radio::begin(void) {
|
||||||
rf24.startListening();
|
rf24.startListening();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool inTX=1, inRX=0, role=inRX;
|
||||||
|
|
||||||
|
static void switchToSenderRole(RF24 radio)
|
||||||
|
{
|
||||||
|
Serial.println("*** master: CHANGING TO TRANSMIT ROLE");
|
||||||
|
radio.openWritingPipe(addresses[1]);
|
||||||
|
radio.openReadingPipe(1,addresses[0]);
|
||||||
|
radio.stopListening();
|
||||||
|
role = inTX; // 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 = inRX; // Become the primary receiver (pong back)
|
||||||
|
}
|
||||||
|
|
||||||
|
static int sendFailedCounter = 0;
|
||||||
|
static unsigned long stopTime = 0, pauseTime = 0;
|
||||||
|
|
||||||
|
void Radio::broadcastRequestRegistration(const char *clockName) {
|
||||||
|
char sendBuffer[32];
|
||||||
|
|
||||||
|
memset(sendBuffer, 0, 32);
|
||||||
|
sendBuffer[0] = msgType_ReqReg;
|
||||||
|
strncpy(sendBuffer+1, clockName, MAX_CLOCK_NAME_LEN);
|
||||||
|
int msgLength = MAX_CLOCK_NAME_LEN + 1;
|
||||||
|
|
||||||
|
switchToSenderRole(rf24);
|
||||||
|
if (!rf24.writeFast(sendBuffer, msgLength, true /*multicast*/)) {
|
||||||
|
sendFailedCounter++;
|
||||||
|
Serial.print("*** ERROR: failed to send ReqRegistration msg for "); Serial.println(clockName);
|
||||||
|
}
|
||||||
|
//This is only required when NO ACK ( enableAutoAck(0) ) payloads are used
|
||||||
|
if (millis() - pauseTime > 3) {
|
||||||
|
pauseTime = millis();
|
||||||
|
rf24.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 (!rf24.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.print("*** send finished, fail-counter="); Serial.println(sendFailedCounter);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Radio::broadcastClock(int day, int hour, int minute, int second, int msPerModelSecond) {
|
||||||
|
struct clockMsg_s clockMsg;
|
||||||
|
|
||||||
|
clockMsg.msgType = msgType_Clock;
|
||||||
|
clockMsg.day = day;
|
||||||
|
clockMsg.hour = hour;
|
||||||
|
clockMsg.minute = minute;
|
||||||
|
clockMsg.second = second;
|
||||||
|
clockMsg.speed = (msPerModelSecond >> 2) & 0xff; // divide by 4
|
||||||
|
switchToSenderRole(rf24);
|
||||||
|
if (!rf24.writeFast(&clockMsg, sizeof(clockMsg), true /*multicast*/)) {
|
||||||
|
sendFailedCounter++;
|
||||||
|
Serial.print("*** ERROR: failed to send clock msg for "); Serial.print(hour); Serial.print(":"); Serial.print(minute); Serial.print(":"); Serial.println(second);
|
||||||
|
}
|
||||||
|
//This is only required when NO ACK ( enableAutoAck(0) ) payloads are used
|
||||||
|
if (millis() - pauseTime > 3) {
|
||||||
|
pauseTime = millis();
|
||||||
|
rf24.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 (!rf24.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.print("*** send finished, fail-counter="); Serial.println(sendFailedCounter);
|
||||||
|
}
|
||||||
|
|
||||||
void Radio::loop(void) {
|
void Radio::loop(void) {
|
||||||
#if 0
|
|
||||||
// put your main code here, to run repeatedly:
|
// put your main code here, to run repeatedly:
|
||||||
/****************** Ping Out Role ***************************/
|
/****************** Ping Out Role ***************************/
|
||||||
if (isMaster) {
|
if (isMaster) {
|
||||||
|
switchToReceiverRole(rf24);
|
||||||
|
if (rf24.available()) {
|
||||||
|
char buffer[32];
|
||||||
|
rf24.read(buffer, 32);
|
||||||
|
|
||||||
radio.stopListening();
|
// Spew it
|
||||||
|
Serial.print(F("Received new message, type="));
|
||||||
Serial.println(F("Now sending"));
|
Serial.print(buffer[0]);
|
||||||
|
Serial.print(F(", bytes 1="));
|
||||||
unsigned long start_time = micros();
|
Serial.print(buffer[1]);
|
||||||
if (!radio.write(&start_time, sizeof(unsigned long))) {
|
Serial.print(", 2=");
|
||||||
Serial.println(F("failed"));
|
Serial.print(buffer[2]);
|
||||||
}
|
Serial.print(", 3=");
|
||||||
|
Serial.println(buffer[3]);
|
||||||
radio.startListening();
|
|
||||||
|
|
||||||
unsigned long started_waiting_at = micros();
|
|
||||||
boolean timeout = false;
|
|
||||||
|
|
||||||
while (!radio.available()) {
|
|
||||||
if (micros() - started_waiting_at > 200000 ) { // If waited longer than 200ms, indicate timeout and exit while loop
|
|
||||||
timeout = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (timeout) {
|
|
||||||
Serial.println(F("Failed, response timed out."));
|
|
||||||
} else {
|
|
||||||
unsigned long got_time;
|
|
||||||
radio.read( &got_time, sizeof(unsigned long) );
|
|
||||||
unsigned long end_time = micros();
|
|
||||||
|
|
||||||
// Spew it
|
|
||||||
Serial.print(F("Sent "));
|
|
||||||
Serial.print(start_time);
|
|
||||||
Serial.print(F(", Got response "));
|
|
||||||
Serial.print(got_time);
|
|
||||||
Serial.print(F(", Round-trip delay "));
|
|
||||||
Serial.print(end_time-start_time);
|
|
||||||
Serial.println(F(" microseconds"));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Try again 1s later
|
|
||||||
delay(1000);
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
|
||||||
/****************** Pong Back Role ***************************/
|
/****************** Pong Back Role ***************************/
|
||||||
|
|
||||||
if (!isMaster)
|
if (!isMaster)
|
||||||
|
|
|
@ -8,6 +8,8 @@ public:
|
||||||
Radio(Display *d, bool _isMaster):display(d), isMaster(_isMaster) { };
|
Radio(Display *d, bool _isMaster):display(d), isMaster(_isMaster) { };
|
||||||
void begin(void);
|
void begin(void);
|
||||||
void loop(void);
|
void loop(void);
|
||||||
|
void broadcastClock(int day, int hour, int minute, int second, int msPerModelSecond);
|
||||||
|
void broadcastRequestRegistration(const char *clockName);
|
||||||
private:
|
private:
|
||||||
Display *display;
|
Display *display;
|
||||||
bool isMaster;
|
bool isMaster;
|
||||||
|
|
Loading…
Reference in New Issue