282 lines
9.7 KiB
C++
282 lines
9.7 KiB
C++
#include "swordMain.hpp"
|
|
|
|
#include "defines.hpp"
|
|
#include "mqttChannel.hpp"
|
|
|
|
using namespace pal;
|
|
using namespace std::literals::string_view_literals;
|
|
using namespace std::literals::chrono_literals;
|
|
using namespace std;
|
|
|
|
const string Version = "V 0.9.0";
|
|
|
|
unique_ptr<SwordConfig> SwordCfg;
|
|
unique_ptr<DeviceIoState> IoStat;
|
|
OpMode Mode = OpMode::Maintanance;
|
|
|
|
void processPromo(MqttChannel& mqtt, SeqLogger& log);
|
|
void processProduction(MqttChannel& mqtt, SeqLogger& log);
|
|
|
|
int main(int argc, char* argv[]) {
|
|
CLI::App app{"Sword Firmware"};
|
|
string appName = "SwordDebug";
|
|
string modeArg = "test";
|
|
string assetsBasePath = "/home/user/assets/sword";
|
|
string brocker = "mqtts://excaliburs-erben.de:8883";
|
|
string topic = "staging/outdoor/king-arthur/sword/";
|
|
string user = "exodususer";
|
|
string password = "awesomeexodusoutdooradventures";
|
|
string logUrl = "log.excaliburs-erben.de";
|
|
string logApiKey = "uYpJC6WyZAbFK2MUgwNH";
|
|
app.add_option("startmode", modeArg, "Startup mode")->required();
|
|
app.add_option("basepath", assetsBasePath, "Base bath for assets")->required();
|
|
app.add_option("-n,--name", appName, "Name of App");
|
|
app.add_option("-b,--brocker", brocker, "MQTT Topic URL");
|
|
app.add_option("-t,--topic", topic, "MQTT Topic");
|
|
app.add_option("-p,--passwd", password, "MQTT Brocker password");
|
|
app.add_option("-u,--user", user, "MQTT Brocker user");
|
|
app.add_option("-l,--log", logUrl, "Logging Service");
|
|
app.add_option("-k,--key", logApiKey, "Logging API Key");
|
|
|
|
CLI11_PARSE(app, argc, argv);
|
|
|
|
SeqLogger log(logUrl, logApiKey, appName);
|
|
SwordCfg = make_unique<SwordConfig>(assetsBasePath, brocker, topic, user, password);
|
|
|
|
fmt::println("{}", app.get_description());
|
|
if (modeArg == "promo") {
|
|
fmt::println("starting with promo");
|
|
Mode = OpMode::PromoMode;
|
|
} else if (modeArg == "game") {
|
|
fmt::println("starting with promo");
|
|
Mode = OpMode::GamingMode;
|
|
} else {
|
|
fmt::println("unknown {}", modeArg);
|
|
}
|
|
constexpr array<const char*, 4> modes = {"Undefined", "Maintanance", "PromoMode", "Production"};
|
|
log.sendBootUp(Version, modes[static_cast<int>(Mode)]);
|
|
|
|
auto itrHandler = [&]() {
|
|
TriggeredInput itr(26, "PItr");
|
|
while (true) {
|
|
cout << "Await next interrupt\n";
|
|
if (itr.await()) {
|
|
cout << "Interrupt Event\n";
|
|
}
|
|
}
|
|
};
|
|
thread interruptThread(itrHandler);
|
|
|
|
InputPort sbPort(SwordEntryPin, "PinSEntry");
|
|
InputPort sePort(SwordEndPin, "PInSEnd");
|
|
InputPort spPort(SwordPulledPin, "PInSPull");
|
|
InputPort sparePort(sparePin, "spare");
|
|
OutputPort mOut1(LinMotPin1, "M1:1");
|
|
OutputPort mOut2(LinMotPin2, "M1:2");
|
|
InputTransAware SwordEntry(sbPort);
|
|
InputTransAware SwordEnd(sePort);
|
|
InputTransAware SwordPulled(spPort);
|
|
LinMot SwordLatch(mOut1, mOut2);
|
|
|
|
I2cMaster i2cDev(II2cMaster::ClockRate::_400k);
|
|
AdcAds1115 adc(i2cDev, AdcAds1115::I2CAddress::Gnd);
|
|
// Check if the ADC is connected
|
|
if (!adc.isConnected()) {
|
|
fmt::println("Failed to connect ot Sensor {}", modeArg);
|
|
}
|
|
CurrMon mon(adc);
|
|
|
|
IoStat = make_unique<DeviceIoState>(SwordEntry, SwordEnd, SwordPulled, SwordLatch);
|
|
|
|
MqttChannel mqtt(appName, Version, *SwordCfg, *IoStat, log);
|
|
auto resetCall = [&]() {
|
|
log.sendEvent("Reset", "");
|
|
};
|
|
|
|
mqtt.flushInput();
|
|
static auto conTask = Thread::createExplicit("MqttTask", MqttChannel::runMasterService, ref(mqtt), resetCall, ref(mon));
|
|
|
|
SwordLatch.moveOut();
|
|
fmt::println("Running App");
|
|
while (true) {
|
|
switch (Mode) {
|
|
case OpMode::Maintanance: {
|
|
fmt::println("Running Maintanance");
|
|
// txQueue.emplace<ResponseTxMsg>(msg->code, 0);
|
|
Thread::sleep(500ms);
|
|
IoStat->tick();
|
|
mqtt.sendStatusMessage(Mode);
|
|
// auto e = make_unique<ResponseTxMsg>(msg->code, 0);
|
|
// txQueue.enqueue(move(e));
|
|
} break;
|
|
case OpMode::PromoMode: {
|
|
fmt::println("Running PromoMode");
|
|
processPromo(mqtt, log);
|
|
} break;
|
|
case OpMode::GamingMode: {
|
|
fmt::println("Running GamingMode");
|
|
processProduction(mqtt, log);
|
|
} break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
interruptThread.join();
|
|
return EXIT_SUCCESS;
|
|
}
|
|
|
|
enum MuteState {
|
|
WaitForUnmute,
|
|
WaitForMute,
|
|
WaitForNextDay,
|
|
};
|
|
void processPromo(MqttChannel& mqtt, SeqLogger& log) {
|
|
auto muterS = MuteState::WaitForUnmute;
|
|
Tick tmu(1min);
|
|
Tick tn(1s);
|
|
Tick tsf(30min);
|
|
Waiter dP;
|
|
auto& serCmds = mqtt.getSerCommands();
|
|
while (true) {
|
|
Thread::sleep(10ms);
|
|
IoStat->tick();
|
|
if (IoStat->SwordPulled.isPosEdge()) {
|
|
if (!IoStat->Mute) {
|
|
if (dP.tick(IoStat->PromoDelay)) {
|
|
log.sendEvent("Pull", "Start Audio");
|
|
|
|
if (tsf.tick()) {
|
|
MediaPlayer::playWavFile(SwordCfg->SoundPromo);
|
|
} else {
|
|
MediaPlayer::playWavFile(SwordCfg->SoundPromoShort);
|
|
}
|
|
dP.sample();
|
|
fmt::println("Muting next for {}", IoStat->PromoDelay);
|
|
} else {
|
|
fmt::println("still muted");
|
|
}
|
|
}
|
|
}
|
|
if (tn.tick()) {
|
|
mqtt.sendStatusMessage(Mode);
|
|
}
|
|
if (tmu.tick()) {
|
|
auto now = std::chrono::system_clock::now();
|
|
std::time_t time = std::chrono::system_clock::to_time_t(now);
|
|
std::tm* lTime = std::localtime(&time);
|
|
int current_hour = lTime->tm_hour;
|
|
|
|
switch (muterS) {
|
|
case WaitForUnmute:
|
|
if (current_hour >= 9) {
|
|
fmt::println("[09:00 Threshold] Unmute");
|
|
log.sendEvent("Unmute", "Time for unmute");
|
|
IoStat->Mute = false;
|
|
muterS = WaitForMute;
|
|
}
|
|
break;
|
|
case WaitForMute:
|
|
if (current_hour >= 21) {
|
|
fmt::println("[21:00 Threshold] Mute");
|
|
log.sendEvent("Mute", "Time for mute");
|
|
IoStat->Mute = true;
|
|
muterS = WaitForNextDay;
|
|
}
|
|
break;
|
|
case WaitForNextDay:
|
|
if (current_hour < 1) {
|
|
fmt::println("[01:00 Threshold] new day");
|
|
muterS = WaitForUnmute;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void processProduction(MqttChannel& mqtt, SeqLogger& log) {
|
|
auto& serCmds = mqtt.getSerCommands();
|
|
auto& gameCmds = mqtt.getGameCommands();
|
|
while (true) {
|
|
auto msg = mqtt.tryDeque();
|
|
if (!msg) {
|
|
continue;
|
|
}
|
|
|
|
auto code = gameCmds.at(msg->Payload);
|
|
switch (code) {
|
|
case GameModeCommands_e::GameStarted: {
|
|
fmt::println("Got GameStarted");
|
|
log.sendEvent("Req", "GameStarted");
|
|
}
|
|
case GameModeCommands_e::GameFinished: {
|
|
fmt::println("Got GameFinished");
|
|
log.sendEvent("Req", "GameFinished");
|
|
}
|
|
|
|
case GameModeCommands_e::GameNextTryLocked: {
|
|
fmt::println("Got NextTryLock");
|
|
log.sendEvent("Req", "StayLockded");
|
|
while (true) {
|
|
IoStat->SwordPulled.sample();
|
|
if (IoStat->SwordPulled.isPosEdge()) {
|
|
mqtt.sendStatusMessage(Mode);
|
|
// say: You are not the one
|
|
MediaPlayer::playWavFile(SwordCfg->SoundDeny);
|
|
Thread::sleep(15s);
|
|
log.sendEvent("Req", "Pulled");
|
|
mqtt.sendEvent("pull");
|
|
}
|
|
}
|
|
} break;
|
|
|
|
case GameModeCommands_e::GameNextTryRelease: {
|
|
fmt::println("NextTryRelease");
|
|
log.sendEvent("Req", "UnlockSword");
|
|
IoStat->SwordLatch.moveIn();
|
|
while (true) {
|
|
IoStat->SwordEnd.sample();
|
|
if (IoStat->SwordEnd.isNegEdge()) {
|
|
mqtt.sendStatusMessage(Mode);
|
|
break;
|
|
}
|
|
}
|
|
while (true) {
|
|
IoStat->SwordEntry.sample();
|
|
if (IoStat->SwordEntry.isNegEdge()) {
|
|
mqtt.sendStatusMessage(Mode);
|
|
break;
|
|
}
|
|
}
|
|
mqtt.sendEvent("pulled-out");
|
|
log.sendEvent("Req", "Pulled Out");
|
|
// say: You ARE the one
|
|
MediaPlayer::playWavFile(SwordCfg->SoundAllow);
|
|
Thread::sleep(15s);
|
|
mqtt.sendEvent("ceremonyDone");
|
|
|
|
while (true) {
|
|
IoStat->SwordEnd.sample();
|
|
if (IoStat->SwordEnd.isNegEdge()) {
|
|
mqtt.sendStatusMessage(Mode);
|
|
break;
|
|
}
|
|
}
|
|
while (true) {
|
|
IoStat->SwordEntry.sample();
|
|
if (IoStat->SwordEntry.isNegEdge()) {
|
|
mqtt.sendStatusMessage(Mode);
|
|
break;
|
|
}
|
|
}
|
|
log.sendEvent("Req", "Put Back");
|
|
mqtt.sendEvent("put-in");
|
|
} break;
|
|
}
|
|
}
|
|
}
|