fastclockClient/doc/ClockServer_cpp.txt

229 lines
7.7 KiB
Plaintext

//
// FILE: ClockServer.cpp
// PURPOSE: UDP broadcast sender for fastclock (FREMO clock)
//
//
#include "ClockServer.h"
#include <ESP8266WiFi.h>
#include <WiFiUdp.h>
#include <DjFastclockScanner.h>
#ifdef ESP8266
extern "C" {
#include "user_interface.h"
}
#endif
const char * const PROGMEM clockServerConfig[] = {
"clockServerName:string:DefaultClock",
"waitBeforeStartingClockServer_ms:int:5000",
"timeToCollectOtherClocks_ms:int:20000",
"autoActivateAfter_ms:int:0",
"sendClockUpdateEvery_ms:int:2000",
"ipMulticast:string:239.50.50.20",
"clientListenPort:int:2000",
};
static WiFiUDP udp;
#define CLOCK_PACKET_SIZE 1024
static byte packetBuffer[CLOCK_PACKET_SIZE+1]; //buffer to hold outgoing packets
String ClockServer::name{""};
IPAddress ClockServer::ipMulticast; //.fromString("239.50.50.20");
int ClockServer::clientListenPort{2000};
String ClockServer::text{""};
boolean ClockServer::active{false};
float ClockServer::clockSpeed{1.0};
String ClockServer::clockString{""};
String ClockServer::weekdayName{""};
int ClockServer::weekday{0};
int ClockServer::clockHours{0};
int ClockServer::clockMinutes{0};
int ClockServer::clockSeconds{0};
ClockServerStatus ClockServer::serverStatus = ClockServerStatus::ServerNotStarted;
uint32_t ClockServer::nextServerStatusTime;
int ClockServer::sendClockUpdateEvery_ms;
int ClockServer::autoActivateAfter_ms;
void ClockServer::begin() {
config.loadFile("clockserver.cfg", clockServerConfig, sizeof(clockServerConfig)/sizeof(clockServerConfig[0]));
name = config.getString("clockServerName");
ipMulticast.fromString(config.getString("ipMulticast"));
clientListenPort = config.getInt("clientListenPort");
sendClockUpdateEvery_ms = config.getInt("sendClockUpdateEvery_ms");
autoActivateAfter_ms = config.getInt("autoActivateAfter_ms");
nextServerStatusTime = millis() + config.getInt("waitBeforeStartingClockServer_ms");
logHeap();
}
void ClockServer::clockTick() {
if (ClockServer::active == false) return;
//Debug::outln(F("> Tick"));
ClockServer::clockSeconds++;
if (ClockServer::clockSeconds >= 60) {
ClockServer::clockSeconds = 0;
ClockServer::clockMinutes++;
if (ClockServer::clockMinutes >= 60) {
ClockServer::clockMinutes = 0;
ClockServer::clockHours++;
if (ClockServer::clockHours >= 24) {
ClockServer::clockHours = 0;
weekday++;
if (weekday >= 7) {
weekday = 0;
}
}
}
}
}
static void clockTick() {
ClockServer::clockTick();
}
void ClockServer::activateClock() {
active = true;
if (clockSpeed < 0.1) {
clockSpeed = 0.1;
debug.outln(F("ERROR: clockSpeed was too small, set to 0.1 which still is very small"));
}
clockTrigger.attach_ms(1000.0 / clockSpeed, clockTick);
logHeap();
}
void ClockServer::deactivateClock() {
active = false;
clockTrigger.detach();
logHeap();
}
void ClockServer::setSpeed(float newSpeed) {
clockSpeed = newSpeed;
if (active) {
deactivateClock();
activateClock();
}
logHeap();
}
void ClockServer::sendFastclockMessage() {
IPAddress ip = WiFi.localIP();
static String nl = String("\r\n");
String msg = String("fastclock") + nl + "version=2" + nl;
msg += "name=" + name + nl;
msg += "ip-address=" + ip.toString() + nl;
msg += "ip-port=" + String(clientListenPort) + nl;
msg += "text=" + text + nl;
msg += "clocktype=fastclock" + nl;
msg += "active=" + (active?String("yes"):String("no")) + nl;
msg += "speed=" + String(clockSpeed) + nl;
msg += "clock=" + String(clockHours) + ":" + String(clockMinutes) + ":" + String(clockSeconds) + nl;
msg += "weekday=" + String(weekday) + nl;
uint8_t result = udp.beginPacketMulticast(ipMulticast, clientListenPort, ip);
debug.outln(result?"udp.begin":"ERROR on udp.begin");
size_t sentBytes = udp.write(msg.c_str(),msg.length());
debug.outln(String(sentBytes) + " bytes sent"); //,sizeof(msg));
result = udp.endPacket();
debug.outln(result?"send was OK":"send FAILED");
debug.out(F("*** ")); debug.outln(msg);
delay(1);
}
void ClockServer::loop() {
static String *knownClocks;
switch (serverStatus) {
case ClockServerStatus::ServerNotStarted:
if (millis() > nextServerStatusTime) {
serverStatus = ClockServerStatus::CollectingExistingClocks;
nextServerStatusTime = millis() + config.getInt("timeToCollectOtherClocks_ms");
if (!udp.beginMulticast(WiFi.localIP(), ipMulticast, clientListenPort)) {
debug.outln(F("ERROR: failed to begin UDP"));
debug.out(F("local IP=")); debug.out(WiFi.localIP().toString());
debug.out(F(", multicast IP=")); debug.out(ipMulticast.toString());
debug.out(F(", Port=")); debug.outln(clientListenPort);
}
logHeap();
}
break;
case ClockServerStatus::CollectingExistingClocks:
// do nothing, we wait for the client to collect the clocks for us
if (millis() > nextServerStatusTime) {
serverStatus = ClockServerStatus::StartingServer;
nextServerStatusTime = millis()-1; // be sure, this will go through the next section on next loop() call
logHeap();
} else {
int length = udp.parsePacket();
if (length > 0) {
// debug.out(F("ClockServer received: ")); debug.out(length); debug.outln(F(" bytes."));
udp.read(packetBuffer, CLOCK_PACKET_SIZE);
packetBuffer[length] = '\0';
// interpret Clock Message
// debug.out(F("> ")); debug.outln( (char *) packetBuffer);
String msg = String((char *) packetBuffer);
if (!msg.startsWith("fastclock\r\n")) {
debug.out(F("ERROR: This is not a fastclock message! Got message=")); debug.outln(msg.substring(0,30));
}
msg = msg.substring(11);
if (!msg.startsWith("version=2\r\n")) {
debug.out(F("WARNING: Version of fastclock not supported! Got ")); debug.outln(msg.substring(0,10));
}
msg = msg.substring(msg.indexOf('\n')+1);
String checkName{""};
if (msg.startsWith("name=")) {
checkName = msg.substring(msg.indexOf('=')+1, msg.indexOf('\r'));
fastclockScanner.addClock(checkName);
} else { debug.outln(F("ERROR: Clock Message Format invalid! Expected name field.")); return; }
msg = String(""); // release string
}
}
break;
case ClockServerStatus::StartingServer:
// debug: output the clocks seen during collectingExistingClocks time
knownClocks = fastclockScanner.getKnownClocks();
debug.outln(F("--- Following Clocks have been seen during bootup: ---"));
for (int i=0; i<fastclockScanner.getNumberOfKnownClocks(); ++i) {
debug.outln(knownClocks[i]);
}
debug.outln(F("--- end of list of known clocks"));
delay(10);
if (autoActivateAfter_ms > 0) {
nextServerStatusTime = millis() + autoActivateAfter_ms;
serverStatus = ClockServerStatus::WaitForAutoActivate;
} else {
serverStatus = ClockServerStatus::ServerStarted;
nextServerStatusTime = millis() + sendClockUpdateEvery_ms;
}
break;
case ClockServerStatus::WaitForAutoActivate:
if (millis() > nextServerStatusTime) {
serverStatus = ClockServerStatus::ServerStarted;
activateClock();
logHeap();
}
break;
case ClockServerStatus::ServerStarted:
if (millis() > nextServerStatusTime) {
if (active) sendFastclockMessage();
nextServerStatusTime = millis() + sendClockUpdateEvery_ms;
logHeap();
}
break;
default:
// this is an error case
debug.outln(F("ERROR: Unknown server state in ClockServer.cpp. Resetting to ServerNotStarted."));
serverStatus = ClockServerStatus::ServerNotStarted;
break;
}
}