Compare commits

...

2 Commits

5 changed files with 170 additions and 73 deletions

View File

@@ -62,15 +62,74 @@ void Display::begin(void) {
setLargeTextSize();
u8g2.drawStr(0,16,"Booting FastClock");
u8g2.sendBuffer();
delay(200);
delay(400);
//addLogMessage("Display initialized");
}
#define BOOT_CLOCK_WIDTH 16
#define BOOT_CLOCK_PIXEL_WIDTH 2
#define BOOT_CLOCK_PIXELS_PER_SIDE (BOOT_CLOCK_WIDTH / BOOT_CLOCK_PIXEL_WIDTH - 1)
#define BOOT_CLOCK_PIXELS (BOOT_CLOCK_PIXELS_PER_SIDE * 4)
#define BOOT_CLOCK_FORWARD_AFTER_ms 200
// Example: WIDTH=16, PIXEL_WIDTH = 4 --> 3 pixels per side (4 seen, but one would be counted double)
// Result: Pixels a / b / c / d
// a1 a2 a3 b1
// d3 b2
// d2 b3
// d1 c3 c2 c1
//
void Display::showBootClock(void) {
static unsigned long lastClockUpdate_ts = 0;
static int tick = 0;
if (millis() - lastClockUpdate_ts >= BOOT_CLOCK_FORWARD_AFTER_ms) {
++tick;
if (tick >= BOOT_CLOCK_PIXELS) {
tick = 0;
/*
u8g2.setDrawColor(0);
u8g2.drawBox(u8g2.getDisplayWidth()-BOOT_CLOCK_WIDTH, 0, BOOT_CLOCK_WIDTH, BOOT_CLOCK_WIDTH);
u8g2.setDrawColor(1);
*/
}
}
u8g2.setDrawColor(2); // XOR
// draw appropriate pixels
int x=0, y=0, side, pixelOnSide; // side = 0, 1, 2, 3 for a, b, c, d
side = tick / BOOT_CLOCK_PIXELS_PER_SIDE;
pixelOnSide = tick % BOOT_CLOCK_PIXELS_PER_SIDE;
switch (side) {
case 0: // top
x = u8g2.getDisplayWidth() - BOOT_CLOCK_WIDTH + pixelOnSide * BOOT_CLOCK_PIXEL_WIDTH;
y = 0;
break;
case 1: // right
x = u8g2.getDisplayWidth() - BOOT_CLOCK_PIXEL_WIDTH;
y = pixelOnSide * BOOT_CLOCK_PIXEL_WIDTH;
break;
case 2: // bottom
x = u8g2.getDisplayWidth() - (1 + pixelOnSide) * BOOT_CLOCK_PIXEL_WIDTH;
y = BOOT_CLOCK_WIDTH - BOOT_CLOCK_PIXEL_WIDTH;
break;
case 3: // left
x = u8g2.getDisplayWidth() - BOOT_CLOCK_WIDTH;
y = BOOT_CLOCK_WIDTH - (1 + pixelOnSide) * BOOT_CLOCK_PIXEL_WIDTH;
}
u8g2.drawBox(x, y, BOOT_CLOCK_PIXEL_WIDTH, BOOT_CLOCK_PIXEL_WIDTH);
u8g2.setDrawColor(1);
u8g2.drawCircle(u8g2.getDisplayWidth()-BOOT_CLOCK_WIDTH/2, BOOT_CLOCK_WIDTH/2, BOOT_CLOCK_PIXEL_WIDTH, U8G2_DRAW_ALL);
u8g2.setDrawColor(1);
u8g2.sendBuffer();
}
bool Display::showBootSequenceFinished(unsigned int ms_per_step) {
static int step = 0;
static unsigned long lastStep_ms = 0;
if (step > 4) return true; // all is done; the value "4" corresponds to the number of steps in following case statement!
showBootClock();
if (ms_per_step > millis() - lastStep_ms) return false; // do nothing, if last step execution is not long enough ago
Serial.print("showBootSequence: step="); Serial.println(step);
lastStep_ms = millis();
@@ -80,20 +139,12 @@ bool Display::showBootSequenceFinished(unsigned int ms_per_step) {
currentScreen = BootSequenceScreen;
break;
case 1:
u8g2.drawPixel(100, 10);
u8g2.drawPixel(102, 12);
u8g2.drawPixel(104, 14);
u8g2.drawPixel(106, 16);
u8g2.sendBuffer();
break;
case 2:
u8g2.drawLine(100, u8g2.getDisplayHeight()-1, u8g2.getDisplayWidth()-1, u8g2.getDisplayHeight()/2);
u8g2.drawCircle(u8g2.getDisplayWidth()-20, u8g2.getDisplayHeight()-10, 10, U8G2_DRAW_UPPER_LEFT | U8G2_DRAW_LOWER_RIGHT);
u8g2.sendBuffer();
break;
case 3:
u8g2.drawXBMP(60, 0, 16, 16, logo16_glcd_bmp);
u8g2.sendBuffer();
//u8g2.drawXBMP(60, 0, 16, 16, logo16_glcd_bmp);
//u8g2.sendBuffer();
break;
case 4:
break; // empty step to be sure, that last step is displayed long enough
@@ -141,7 +192,6 @@ void Display::showDashboard(void) {
lastBlinkChange_ms = lastDisplayUpdate_ms;
blinkOnCycle = !blinkOnCycle;
}
u8g2.clearBuffer();
u8g2.setDrawColor(1);

View File

@@ -4,7 +4,7 @@
#include "config.h"
// avoid flickering of the display:
#define TIME_BETWEEN_DISPLAY_UPDATES_ms 200
#define TIME_BETWEEN_DISPLAY_UPDATES_ms 300
#define BLINK_ON_OFF_TIME_ms 1000
@@ -58,5 +58,6 @@ private:
int getTextCharsPerLine(void);
void setNormalTextSize(void);
void setLargeTextSize(void);
void showBootClock(void);
};
#endif

View File

@@ -28,7 +28,7 @@ char static_ip[16] = "10.0.1.56";
char static_gw[16] = "10.0.1.1";
char static_sn[16] = "255.255.255.0";
char clockName[MAX_CLOCK_NAME_LEN] = "fastclk";
char clockName[MAX_CLOCK_NAME_LEN+1] = "fastclk";
uint8_t clockChannel = DEFAULT_CLOCK_CHANNEL;
//flag for saving data
@@ -230,6 +230,7 @@ void checkForPowerOffRequest() {
}
if (millis() - powerOffButtonPressed_ts > 2000) {
// pressed for longer than 2 seconds, now turn off
Serial.println(F("OFF"));
ESP.deepSleep(ESP.deepSleepMax());
delay(200);
}
@@ -246,7 +247,7 @@ void checkForPowerOffRequest() {
void loop(void)
{
if (!display.showBootSequenceFinished(1000)) {
if (!display.showBootSequenceFinished(4000)) {
return;
}
@@ -266,8 +267,20 @@ void loop(void)
#endif
#endif
fastclock.loop();
radio.loop();
display.showDashboard();
// we do not want to call every task on every cycle:
switch (millis() & 0x03) {
case 0:
fastclock.loop();
break;
case 1:
break;
case 2:
display.showDashboard();
break;
case 3:
break;
}
yield();
radio.loop(); // called always
}

View File

@@ -9,43 +9,39 @@ static RF24 rf24(PIN_NRF24_CE, PIN_NRF24_CSN); // 10, 8
static byte addresses[][6] = {NETWORK_ADDRESS_MASTER_SEND, NETWORK_ADDRESS_MASTER_RECEIVE};
static int sendFailedCounter = 0;
static unsigned long stopTime = 0, pauseTime = 0;
//static unsigned long stopTime = 0;
static unsigned long pauseTime = 0;
static char thisClockName[MAX_CLOCK_NAME_LEN];
#define MAX_CLIENTS_MANAGED 20
static uint8_t numberOfKnownClients = 0;
static struct {
uint8_t clientNetworkAddress;
char clientName[MAX_CLIENT_NAME_LEN];
char clientName[MAX_CLIENT_NAME_LEN+1];
} client[MAX_CLIENTS_MANAGED];
static uint8_t nextClientNetworkAddress = 1;
void Radio::switchToSenderRole(void)
{
Serial.println("*** changing to Tx role");
rf24.openWritingPipe(addresses[1]);
rf24.openReadingPipe(1,addresses[0]);
rf24.stopListening();
role = inTX; // Become the primary transmitter (ping out)
void Radio::checkRadioFailure(void) {
if (rf24.failureDetected) {
Serial.println(F("Radio failure detected!"));
rf24.failureDetected = 0;
radioInit();
}
}
void Radio::switchToReceiverRole(void)
{
Serial.println("*** changing to Rx role");
rf24.openWritingPipe(addresses[0]);
rf24.openReadingPipe(1,addresses[1]);
rf24.startListening();
role = inRX; // Become the primary receiver (pong back)
}
void Radio::begin(void) {
void Radio::radioInit(void) {
display->addLogMessage("Start RF24 radio");
pinMode(PIN_NRF24_CSN, OUTPUT);
pinMode(PIN_NRF24_CE, OUTPUT);
rf24.begin();
if (rf24.isChipConnected()) { display->addLogMessage("*** RF chip found"); }
else { display->addLogMessage("*** ERROR: RF chip not found!"); }
if (rf24.isChipConnected()) {
display->addLogMessage("*** RF chip found");
Serial.println(F("*** RF chip found"));
} else {
display->addLogMessage("*** ERROR: RF chip not found!");
Serial.println(F("*** ERROR: RF chip not found!"));
}
rf24.setChannel(clockChannel);
rf24.setPALevel(RF24_PA_MAX);
rf24.setDataRate(RF24_2MBPS);
@@ -55,69 +51,103 @@ void Radio::begin(void) {
rf24.openWritingPipe(addresses[0]);
rf24.openReadingPipe(1, addresses[1]);
rf24.startListening();
Serial.println("*** Check");
//rf24.printDetails();
rf24.powerUp();
// @TODO: real random seed!
//randomSeed(analogRead(0));
//randomSeed(22);
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.failureDetected) { display->addLogMessage("*** Radio error detected!"); }
}
void Radio::powerDown(void) {
rf24.powerDown();
}
void Radio::switchToSenderRole(void)
{
Serial.println(F("# Tx"));
rf24.openWritingPipe(addresses[1]);
rf24.openReadingPipe(1,addresses[0]);
rf24.stopListening();
role = inTX; // Become the primary transmitter (ping out)
pauseTime = millis();
checkRadioFailure();
}
void Radio::switchToReceiverRole(void)
{
Serial.println(F("# Rx"));
rf24.openWritingPipe(addresses[0]);
rf24.openReadingPipe(1,addresses[1]);
rf24.startListening();
role = inRX; // Become the primary receiver (pong back)
checkRadioFailure();
}
void Radio::begin(void) {
display->addLogMessage("Start RF24 radio");
pinMode(PIN_NRF24_CSN, OUTPUT);
pinMode(PIN_NRF24_CE, OUTPUT);
radioInit();
Serial.print(F("*** RF payload size=")); Serial.print(rf24.getPayloadSize()); Serial.println(F(" bytes"));
if (rf24.testCarrier() || rf24.testRPD()) {
display->addLogMessage("*** Carrier/RPD seen on radio");
Serial.println(F("*** Carrier/RPD seen on radio"));
}
if (rf24.failureDetected) {
display->addLogMessage("*** Radio error detected!");
Serial.println(F("*** ERROR: Radio error detected!"));
}
// Start the radio listening for data
//rf24.startListening();
switchToReceiverRole();
}
void Radio::broadcastMessageOnChannel(void *msg, int len, uint8_t channel) {
Serial.print("# set channel "); Serial.println(channel);
Serial.print(F("# set channel ")); Serial.println(channel);
rf24.setChannel(channel);
broadcastMessage(msg, len);
Serial.print("# set channel "); Serial.println(clockChannel);
Serial.print(F("# set channel ")); Serial.println(clockChannel);
rf24.setChannel(clockChannel); // switch back
Serial.println("# done");
Serial.println(F("# done"));
}
void Radio::broadcastMessage(void *msg, int len) {
uint8_t *m = (uint8_t *) msg;
Serial.print("*** Tx: ts="); Serial.print(millis());
Serial.print(", len="); Serial.print(len);
Serial.print(", typ=");
Serial.print((uint8_t) m[0], HEX); Serial.print(" ("); Serial.print((char) m[0]);
Serial.print("), to="); Serial.print((uint8_t) m[1], HEX);
Serial.print(", from="); Serial.print((uint8_t) m[2], HEX);
Serial.print(", msg="); Serial.print((uint8_t) m[3], HEX);
Serial.print(", "); Serial.print((uint8_t) m[4], HEX);
Serial.print(", "); Serial.print((uint8_t) m[5], HEX);
Serial.print(", "); Serial.print((uint8_t) m[6], HEX);
Serial.print(", "); Serial.print((uint8_t) m[7], HEX);
Serial.print(", "); Serial.println((uint8_t) m[8], HEX);
Serial.print(F("ts=")); Serial.println(millis());
switchToSenderRole();
Serial.print("#1");
if (!rf24.writeFast(msg, len, true /*multicast*/)) {
sendFailedCounter++;
Serial.print("*** ERROR: failed to send msg type=");
Serial.print(*((char *) msg));
Serial.print(" for to=0x");
Serial.println(m[1], HEX);
Serial.println(F("*** ERROR: failed to send msg"));
}
Serial.print("ts="); Serial.println(millis());
Serial.print(F("ts=")); Serial.println(millis());
//This is only required when NO ACK ( enableAutoAck(0) ) payloads are used
if (millis() - pauseTime > 3) {
pauseTime = millis();
Serial.print("pauseTime="); Serial.println(pauseTime);
Serial.println(F("@TODO: tx-pause"));
//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();
Serial.print("stopTime="); Serial.println(stopTime);
//stopTime = millis();
//Serial.print(F("stopTime=")); Serial.println(stopTime);
//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, failed="); Serial.println(sendFailedCounter);
listenOnlyFor_ms(MIN_TIME_BETWEEN_TRANSMISSIONS_ms);
switchToReceiverRole();
Serial.print(F("*** sent: len=")); Serial.print(len);
Serial.print(F(", typ="));
Serial.print((uint8_t) m[0], HEX); Serial.print(" ("); Serial.print((char) m[0]);
Serial.print(F("), to=")); Serial.print((uint8_t) m[1], HEX);
Serial.print(F(", from=")); Serial.print((uint8_t) m[2], HEX);
Serial.print(F(", msg=")); Serial.print((uint8_t) m[3], HEX);
Serial.print(' '); Serial.print((uint8_t) m[4], HEX);
Serial.print(' '); Serial.print((uint8_t) m[5], HEX);
Serial.print(' '); Serial.print((uint8_t) m[6], HEX);
Serial.print(' '); Serial.print((uint8_t) m[7], HEX);
Serial.print(' '); Serial.println((uint8_t) m[8], HEX);
Serial.print(F("*** send failed=")); Serial.println(sendFailedCounter);
}
void Radio::broadcastClockAdvertisement(const char *clockName, uint8_t channel) {

View File

@@ -75,7 +75,7 @@ public:
clockChannel = DEFAULT_CLOCK_CHANNEL;
strncpy(clockName, "defclk", MAX_CLOCK_NAME_LEN);
};
void setClockName(const char *_clockName) {
strncpy(clockName, _clockName, MAX_CLOCK_NAME_LEN);
};
@@ -94,13 +94,16 @@ public:
void avoidChannelSwitchesFor_ms(unsigned int duration_ms);
void listenOnlyFor_ms(unsigned int duration_ms);
bool allowedToSendNow(void);
void checkRadioFailure(void);
void powerDown(void);
private:
Display *display;
bool isMaster;
void radioInit(void);
void switchToSenderRole(void);
void switchToReceiverRole(void);
bool inTX, inRX, role;
char clockName[MAX_CLOCK_NAME_LEN];
char clockName[MAX_CLOCK_NAME_LEN+1];
void broadcastMessage(void *msg, int len);
void broadcastMessageOnChannel(void *msg, int len, uint8_t channel);
void broadcastClockAdvertisement(const char *clockName, uint8_t channel);