refactoring
This commit is contained in:
1 parent
eb1c84cf05
commit
92423c52de
8 files changed
+655
-57
No files matched your search
+11
-11
@@ -8,12 +8,12 @@ class MqttChannel {
|
||||
: Config(cfg),
|
||||
IoStat(ioStat),
|
||||
Logger(log),
|
||||
runTopic(cfg.getStationPath() + "run"),
|
||||
cfgTopic(cfg.getStationPath() + "cfg"),
|
||||
verTopic(cfg.getStationPath() + "ver"),
|
||||
eventTopic(cfg.getStationPath() + "event"),
|
||||
statTopic(cfg.getStationPath() + "stat"),
|
||||
resetTopic(cfg.getStationPath() + "reset"),
|
||||
runTopic(cfg.StationPath + "run"),
|
||||
cfgTopic(cfg.StationPath + "cfg"),
|
||||
verTopic(cfg.StationPath + "ver"),
|
||||
eventTopic(cfg.StationPath + "event"),
|
||||
statTopic(cfg.StationPath + "stat"),
|
||||
resetTopic(cfg.StationPath + "reset"),
|
||||
|
||||
gameCommands({
|
||||
{"gameStarted", GameModeCommands_e::GameStarted},
|
||||
@@ -36,9 +36,9 @@ class MqttChannel {
|
||||
}),
|
||||
subTopics{{runTopic, cfgTopic, resetTopic}},
|
||||
client("Sword",
|
||||
cfg.getBrockerUrl(),
|
||||
cfg.BrockerUrl,
|
||||
subTopics,
|
||||
{cfg.getMqttUser(), cfg.getMqttPassword()}) {
|
||||
{cfg.MqttUser, cfg.MqttPassword}) {
|
||||
fmt::println("MQTT: Starting task:");
|
||||
mqttCall = [this](string topic, string payload) {
|
||||
if (topic == resetTopic ||
|
||||
@@ -134,13 +134,13 @@ class MqttChannel {
|
||||
instance.IoStat.SwordLatch.moveOut();
|
||||
} break;
|
||||
case ServiceCommands_e::PlaySoundPromo: {
|
||||
MediaPlayer::playWavFile(instance.Config.getSoundPromo());
|
||||
MediaPlayer::playWavFile(instance.Config.SoundPromo);
|
||||
} break;
|
||||
case ServiceCommands_e::PlaySoundDeny: {
|
||||
MediaPlayer::playWavFile(instance.Config.getSoundDeny());
|
||||
MediaPlayer::playWavFile(instance.Config.SoundDeny);
|
||||
} break;
|
||||
case ServiceCommands_e::PlaySoundChosen: {
|
||||
MediaPlayer::playWavFile(instance.Config.getSoundAllow());
|
||||
MediaPlayer::playWavFile(instance.Config.SoundAllow);
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
+16
-9
@@ -1,4 +1,5 @@
|
||||
#include "swordMain.hpp"
|
||||
|
||||
#include "defines.hpp"
|
||||
#include "mqttChannel.hpp"
|
||||
|
||||
@@ -11,7 +12,7 @@ constexpr uint8_t VersionArr[4] = {'V', 0, 8, 0};
|
||||
const string Version = "V 0.8.0";
|
||||
// const string Version = fmt::format("{} {}.{}.{}", VersionArr[0], VersionArr[1], VersionArr[2], VersionArr[3]);
|
||||
|
||||
SwordConfig SwordCfg{};
|
||||
unique_ptr<SwordConfig> SwordCfg;
|
||||
unique_ptr<DeviceIoState> IoStat;
|
||||
OpMode Mode = OpMode::Maintanance;
|
||||
|
||||
@@ -40,7 +41,7 @@ int main(int argc, char* argv[]) {
|
||||
CLI11_PARSE(app, argc, argv);
|
||||
|
||||
SeqLogger log(logUrl, logApiKey, "Sword");
|
||||
SwordCfg.setVar(assetsBasePath, brocker, topic, user, password);
|
||||
SwordCfg = make_unique<SwordConfig>(assetsBasePath, brocker, topic, user, password);
|
||||
|
||||
fmt::println("{}", app.get_description());
|
||||
if (modeArg == "promo") {
|
||||
@@ -79,7 +80,7 @@ int main(int argc, char* argv[]) {
|
||||
|
||||
IoStat = make_unique<DeviceIoState>(SwordEntry, SwordEnd, SwordPulled, SwordLatch);
|
||||
|
||||
MqttChannel mqtt(Version, SwordCfg, *IoStat, log);
|
||||
MqttChannel mqtt(Version, *SwordCfg, *IoStat, log);
|
||||
auto resetCall = [&]() {
|
||||
log.sendEvent("Reset", "");
|
||||
};
|
||||
@@ -118,7 +119,8 @@ int main(int argc, char* argv[]) {
|
||||
}
|
||||
|
||||
void processPromo(MqttChannel& mqtt, SeqLogger& log) {
|
||||
auto tn = chrono::steady_clock::now();
|
||||
Tick tn(1s);
|
||||
Tick tsf(30min);
|
||||
auto& serCmds = mqtt.getSerCommands();
|
||||
while (true) {
|
||||
Thread::sleep(10ms);
|
||||
@@ -126,14 +128,19 @@ void processPromo(MqttChannel& mqtt, SeqLogger& log) {
|
||||
if (IoStat->SwordPulled.isPosEdge()) {
|
||||
if (!IoStat->Mute) {
|
||||
log.sendEvent("Pull", "Start Audio");
|
||||
MediaPlayer::playWavFile(SwordCfg.getSoundPromo());
|
||||
|
||||
if (tsf.tick()) {
|
||||
MediaPlayer::playWavFile(SwordCfg->SoundPromo);
|
||||
} else {
|
||||
MediaPlayer::playWavFile(SwordCfg->SoundPromoShort);
|
||||
}
|
||||
|
||||
fmt::println("Waiting for {}", IoStat->PromoDelay);
|
||||
Thread::sleep(IoStat->PromoDelay);
|
||||
fmt::println("Waiting done");
|
||||
}
|
||||
}
|
||||
if (chrono::steady_clock::now() > (tn + 1s)) {
|
||||
tn = chrono::steady_clock::now();
|
||||
if (tn.tick()) {
|
||||
mqtt.sendStatusMessage(Mode);
|
||||
}
|
||||
}
|
||||
@@ -167,7 +174,7 @@ void processProduction(MqttChannel& mqtt, SeqLogger& log) {
|
||||
if (IoStat->SwordPulled.isPosEdge()) {
|
||||
mqtt.sendStatusMessage(Mode);
|
||||
// say: You are not the one
|
||||
MediaPlayer::playWavFile(SwordCfg.getSoundDeny());
|
||||
MediaPlayer::playWavFile(SwordCfg->SoundDeny);
|
||||
Thread::sleep(15s);
|
||||
log.sendEvent("Req", "Pulled");
|
||||
mqtt.sendEvent("pull");
|
||||
@@ -196,7 +203,7 @@ void processProduction(MqttChannel& mqtt, SeqLogger& log) {
|
||||
mqtt.sendEvent("pulled-out");
|
||||
log.sendEvent("Req", "Pulled Out");
|
||||
// say: You ARE the one
|
||||
MediaPlayer::playWavFile(SwordCfg.getSoundAllow());
|
||||
MediaPlayer::playWavFile(SwordCfg->SoundAllow);
|
||||
Thread::sleep(15s);
|
||||
mqtt.sendEvent("ceremonyDone");
|
||||
|
||||
|
||||
+21
-36
@@ -28,7 +28,6 @@
|
||||
#include "textUtils.hpp"
|
||||
#include "thread.hpp"
|
||||
|
||||
|
||||
class LinMot {
|
||||
public:
|
||||
LinMot(OutputPort& o1, OutputPort& o2)
|
||||
@@ -79,45 +78,31 @@ class DeviceIoState {
|
||||
bool Mute{false};
|
||||
};
|
||||
|
||||
class SwordConfig {
|
||||
public:
|
||||
std::string getSoundPromo() { return soundPromo; }
|
||||
std::string getSoundDeny() { return soundDeny; }
|
||||
std::string getSoundAllow() { return soundAllow; }
|
||||
std::string getBrockerUrl() { return brockerUrl; }
|
||||
std::string getMqttUser() { return mqttUser; }
|
||||
std::string getMqttPassword() { return mqttPassword; }
|
||||
std::string getStationPath() { return stationPath; }
|
||||
|
||||
void setVar(std::string base,
|
||||
struct SwordConfig {
|
||||
SwordConfig(std::string base,
|
||||
std::string brocker, std::string topic,
|
||||
std::string user, std::string passwd) {
|
||||
if (wasSet) {
|
||||
return;
|
||||
}
|
||||
soundPromo = base + soundPromo;
|
||||
soundDeny = base + soundDeny;
|
||||
soundAllow = base + soundAllow;
|
||||
std::string user, std::string passwd)
|
||||
: AssetBase(base),
|
||||
SoundPromo{base + "/promo.wav"},
|
||||
SoundPromoShort{base + "/promoShort.wav"},
|
||||
SoundDeny{base + "/deny.wav"},
|
||||
SoundAllow{base + "/allow.wav"},
|
||||
BrockerUrl(brocker),
|
||||
StationPath(topic),
|
||||
MqttUser(user),
|
||||
MqttPassword(passwd) {}
|
||||
|
||||
brockerUrl = brocker;
|
||||
stationPath = topic;
|
||||
mqttUser = user;
|
||||
mqttPassword = passwd;
|
||||
wasSet = true;
|
||||
}
|
||||
const std::string AssetBase;
|
||||
|
||||
private:
|
||||
bool wasSet{};
|
||||
std::string assetBase{};
|
||||
std::string soundPromo{"/promo.wav"};
|
||||
std::string soundPromoShort{"/promoShort.wav"};
|
||||
std::string soundDeny{"/deny.wav"};
|
||||
std::string soundAllow{"/allow.wav"};
|
||||
const std::string SoundPromo;
|
||||
const std::string SoundPromoShort;
|
||||
const std::string SoundDeny;
|
||||
const std::string SoundAllow;
|
||||
|
||||
std::string brockerUrl;
|
||||
std::string mqttUser;
|
||||
std::string mqttPassword;
|
||||
std::string stationPath;
|
||||
const std::string BrockerUrl;
|
||||
const std::string StationPath;
|
||||
const std::string MqttUser;
|
||||
const std::string MqttPassword;
|
||||
};
|
||||
|
||||
class MediaPlayer {
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
add_executable(ThroneBridgeMain throneBridgeMain.cpp)
|
||||
|
||||
target_link_libraries(ThroneBridgeMain
|
||||
PkgConfig::LIBGPIOD
|
||||
base
|
||||
palAdapt
|
||||
loRa
|
||||
os
|
||||
Mqtt
|
||||
fmt::fmt
|
||||
utils
|
||||
Ilogging
|
||||
)
|
||||
@@ -0,0 +1,92 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
static constexpr uint16_t UndefCmd = 0xFFFF;
|
||||
|
||||
enum IncommingCommands_e : uint16_t {
|
||||
Qurey = 0x00, // Qurey info
|
||||
SetMaintanance = 0x01, // Set Maintanance mode
|
||||
SetPromoMode = 0x02, // Enable PromoMode
|
||||
SetGamingMode = 0x03, // Enable in Game mode
|
||||
};
|
||||
|
||||
enum ServiceCommands_e {
|
||||
SetConfigVolume = 0x11, // Set Volume
|
||||
SetConfigPromoDelay, // Set Delay between Promo
|
||||
PlaySoundPromo,
|
||||
PlaySoundCoronation,
|
||||
};
|
||||
|
||||
enum GameModeCommands_e {
|
||||
GameStarted = 0x21, // One Game has started (mute Promo mode)
|
||||
GameFinished, // The Game is finished (resume to Promo mode)
|
||||
GameOpenCoinSlot, // Lock sword on next try
|
||||
GameCloseCoinSlot, // Release sword on next try
|
||||
};
|
||||
|
||||
enum OutgoingCommands_e {
|
||||
Status = 0x00, // Send Status
|
||||
Response = 0x01, // Confirm last command
|
||||
Error = 0x02, // Send error status
|
||||
PullHappend = 0x03 // Message if User tried to pull the sword
|
||||
};
|
||||
|
||||
struct StatusFrame {
|
||||
uint8_t cmd{OutgoingCommands_e::Status};
|
||||
uint8_t version[4];
|
||||
uint8_t mode;
|
||||
uint8_t healt;
|
||||
uint8_t sensors;
|
||||
};
|
||||
|
||||
struct ResponseFrame {
|
||||
uint8_t cmd{OutgoingCommands_e::Response};
|
||||
uint8_t resCmd;
|
||||
uint8_t status;
|
||||
};
|
||||
|
||||
struct RxMsg {
|
||||
RxMsg(uint16_t m)
|
||||
: code(m) {}
|
||||
uint16_t code;
|
||||
};
|
||||
|
||||
struct TxMsg {
|
||||
TxMsg(uint32_t m)
|
||||
: cmd(m) {}
|
||||
uint8_t cmd;
|
||||
};
|
||||
|
||||
struct MqttQe {
|
||||
MqttQe(std::string topic, std::string payload)
|
||||
: Topic(topic),
|
||||
Payload(payload) {}
|
||||
std::string Topic;
|
||||
std::string Payload;
|
||||
};
|
||||
|
||||
struct ResponseTxMsg : public TxMsg {
|
||||
ResponseTxMsg(uint16_t cmd, uint8_t stat)
|
||||
: TxMsg(OutgoingCommands_e::Response) {};
|
||||
uint16_t resCmd;
|
||||
uint8_t status;
|
||||
};
|
||||
struct StatusTxMsg : public TxMsg {
|
||||
StatusTxMsg(uint8_t mode, uint8_t swEnd, uint8_t swBeg, uint8_t swPull, uint8_t out)
|
||||
: TxMsg(OutgoingCommands_e::Status),
|
||||
_mode(mode),
|
||||
_inSwEnd(swEnd),
|
||||
_inSwBeg(swBeg),
|
||||
_inSwPull(swPull),
|
||||
_out(out) {
|
||||
}
|
||||
uint8_t _mode;
|
||||
bool _inSwEnd;
|
||||
bool _inSwBeg;
|
||||
bool _inSwPull;
|
||||
bool _out;
|
||||
};
|
||||
|
||||
constexpr int GPIO_RST_PIN = 1;
|
||||
constexpr int GPIO_DIO0_PIN = 27;
|
||||
@@ -0,0 +1,404 @@
|
||||
#include "throneBridgeMain.hpp"
|
||||
|
||||
using namespace pal;
|
||||
using namespace std::literals::string_view_literals;
|
||||
using namespace std::literals::chrono_literals;
|
||||
using namespace std;
|
||||
|
||||
constexpr uint8_t VersionArr[4] = {'V', 0, 8, 0};
|
||||
const string Version = "V 0.8.0";
|
||||
// const string Version = fmt::format("{} {}.{}.{}", VersionArr[0], VersionArr[1], VersionArr[2], VersionArr[3]);
|
||||
|
||||
SwordConfig SwordCfg{};
|
||||
unique_ptr<DeviceIoState> IoStat;
|
||||
OpMode Mode = OpMode::Maintanance;
|
||||
|
||||
void processMaintanence(MqttChannel& mqtt);
|
||||
void processPromo(MqttChannel& mqtt, SeqLogger& log);
|
||||
void processProduction(MqttChannel& mqtt, SeqLogger& log);
|
||||
|
||||
/// @brief MQTT-Service provider
|
||||
void MQttServiceTask(Thread::Context& ctx, Queue<RxMsg>& rxQueue, Queue<TxMsg>& txQueue) {
|
||||
string runTopic = SwordCfg.getStationPath() + "run";
|
||||
string intTopic = SwordCfg.getStationPath() + "int";
|
||||
string statTopic = SwordCfg.getStationPath() + "stat";
|
||||
|
||||
fmt::println("MQTT: Starting task:");
|
||||
fmt::println(" Topic: {}", runTopic);
|
||||
|
||||
auto mqttCallback = [&](string topic, string payload) {
|
||||
fmt::print("MQTT: on sendTrigger {}:{}'\n", topic, payload);
|
||||
|
||||
static std::map<string, IncommingCommands_e> commands = {
|
||||
{"Qurey", IncommingCommands_e::Qurey},
|
||||
{"SetMaintanance", IncommingCommands_e::SetMaintanance},
|
||||
{"SetPromoMode", IncommingCommands_e::SetPromoMode},
|
||||
{"SetGamingMode", IncommingCommands_e::SetGamingMode},
|
||||
};
|
||||
static std::map<string, ServiceCommands_e> serCommands = {
|
||||
{"ServiceOpen", ServiceCommands_e::Open},
|
||||
{"ServiceClose", ServiceCommands_e::Close},
|
||||
{"ServicePlay1", ServiceCommands_e::Play1},
|
||||
{"ServicePlay2", ServiceCommands_e::Play2},
|
||||
{"ServicePlay3", ServiceCommands_e::Play3},
|
||||
};
|
||||
static std::map<string, GameModeCommands_e> gameCommands = {
|
||||
{"GameStayLocked", GameModeCommands_e::GameNextTryLocked},
|
||||
{"GameReleaseLock", GameModeCommands_e::GameNextTryRelease},
|
||||
};
|
||||
|
||||
if (topic != runTopic) {
|
||||
fmt::print("MQTT: ignore invalid topic {}'\n", topic);
|
||||
return;
|
||||
}
|
||||
|
||||
if (commands.contains(payload)) {
|
||||
rxQueue.emplace<RxMsg>(commands.at(payload));
|
||||
return;
|
||||
}
|
||||
if (serCommands.contains(payload)) {
|
||||
auto code = serCommands.at(payload);
|
||||
rxQueue.emplace<RxMsg>(code);
|
||||
return;
|
||||
}
|
||||
if (gameCommands.contains(payload)) {
|
||||
rxQueue.emplace<RxMsg>(serCommands.at(payload));
|
||||
return;
|
||||
}
|
||||
|
||||
fmt::print("MQTT: unknown command {}:{}'\n", topic, payload);
|
||||
};
|
||||
|
||||
try {
|
||||
std::vector<string> topicsToRegister{runTopic};
|
||||
MqttClient client("Sword", SwordCfg.getBrockerUrl(), topicsToRegister, {SwordCfg.getMqttUser(), SwordCfg.getMqttPassword()});
|
||||
fmt::println("MQTT: service: successfully connected ...");
|
||||
client.registerCallback(mqttCallback);
|
||||
|
||||
client.send(statTopic, fmt::format("{} Mode={}, sE:0,sS:0,sP:0,lE:0",
|
||||
Version, (int)Mode));
|
||||
|
||||
int cnt = 0;
|
||||
fmt::println("MQTT: Running ...");
|
||||
while (!ctx.isCancelled()) {
|
||||
auto tx = txQueue.dequeue();
|
||||
|
||||
switch (tx->cmd) {
|
||||
case OutgoingCommands_e::Status: {
|
||||
auto& s = *IoStat;
|
||||
client.send(statTopic, fmt::format("{} Mode={}, sE:{},sS:{},sP:{},lE:{}",
|
||||
Version, (int)Mode,
|
||||
s.SwordEnd.isActive(),
|
||||
s.SwordEntry.isActive(),
|
||||
s.SwordPulled.isActive(),
|
||||
s.SwordLatch.isLocked()));
|
||||
} break;
|
||||
case OutgoingCommands_e::Response:
|
||||
client.send(intTopic, "some response");
|
||||
break;
|
||||
case OutgoingCommands_e::Error:
|
||||
client.send(intTopic, "some error");
|
||||
break;
|
||||
case OutgoingCommands_e::PullHappend:
|
||||
client.send(intTopic, "pulled");
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
client.send(intTopic, "sent");
|
||||
}
|
||||
} catch (const exception& exc) {
|
||||
fmt::println(stderr, "\nERROR: Unable to connect to Setup bridge: {}", exc.what());
|
||||
ctx.markFailed();
|
||||
}
|
||||
}
|
||||
|
||||
/// @brief LoRa-Service provider
|
||||
void LoRaServiceTask(Thread::Context& ctx, Queue<RxMsg>& rxQueue, Queue<TxMsg>& txQueue) {
|
||||
fmt::println("LoRa: Starting task:");
|
||||
|
||||
auto loraCallback = [&](std::vector<uint8_t> data) {
|
||||
auto hex = bytesToHex(data);
|
||||
auto str = bytesToPrintable(data);
|
||||
fmt::print("LoRa: Received Byts: {}\n 0x{}\n {}\n", data.size(), hex, str);
|
||||
|
||||
auto e = std::make_unique<RxMsg>(0);
|
||||
rxQueue.enqueue(std::move(e));
|
||||
return true;
|
||||
};
|
||||
auto spi = SpiPort({.mode = SpiPort::Mode0,
|
||||
.cs = SpiPort::Cs0,
|
||||
.frequ = 1'000'000});
|
||||
|
||||
LoRa loRa({
|
||||
.frequency = 868'000'000,
|
||||
.port = spi,
|
||||
.DioPin = GPIO_DIO0_PIN,
|
||||
.resetPin = GPIO_RST_PIN,
|
||||
},
|
||||
loraCallback);
|
||||
|
||||
fmt::println("LoRa: Running ...");
|
||||
while (!ctx.isCancelled()) {
|
||||
auto tx = txQueue.dequeue();
|
||||
loRa.send({0});
|
||||
// printf ("Message: %s %lu\n", msg->message.c_str(), msg->cnt);
|
||||
}
|
||||
|
||||
try {
|
||||
} catch (const exception& exc) {
|
||||
fmt::println(stderr, "\nERROR: Unable to connect to Setup bridge: {}", exc.what());
|
||||
ctx.markFailed();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
CLI::App app{"Sword Firmware"};
|
||||
string modeArg = "test";
|
||||
string assetsBasePath = "/home/user/assets";
|
||||
string brocker = "mqtts://nerdyssey.de:8883";
|
||||
string topic = "staging/outdoor/king-arthur/sword/";
|
||||
string user = "exodususer";
|
||||
string password = "awesomeexodusoutdooradventures";
|
||||
string logUrl = "log.nerdyssey.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("-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, "Sword");
|
||||
SwordCfg.setVar(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);
|
||||
|
||||
IoStat = make_unique<DeviceIoState>(SwordEntry, SwordEnd, SwordPulled, SwordLatch);
|
||||
|
||||
static Queue<RxMsg> rxQueue;
|
||||
static Queue<TxMsg> txQueue;
|
||||
MqttChannel mqtt(Version, SwordCfg, *IoStat, log);
|
||||
auto resetCall = [&]() {
|
||||
log.sendEvent("Reset", "");
|
||||
};
|
||||
|
||||
mqtt.flushInput();
|
||||
static auto conTask = Thread::createExplicit("MqttTask", MqttChannel::runMasterService, ref(mqtt), resetCall);
|
||||
|
||||
SwordLatch.moveOut();
|
||||
fmt::println("Running App");
|
||||
while (true) {
|
||||
switch (Mode) {
|
||||
case OpMode::Maintanance: {
|
||||
fmt::println("Running Maintanance");
|
||||
// txQueue.emplace<ResponseTxMsg>(msg->code, 0);
|
||||
processMaintanence(mqtt);
|
||||
// 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;
|
||||
}
|
||||
|
||||
void processMaintanenceCommand(enum ServiceCommands_e code) {
|
||||
switch (code) {
|
||||
case ServiceCommands_e::SetLockOpen: {
|
||||
IoStat->SwordLatch.moveIn();
|
||||
} break;
|
||||
case ServiceCommands_e::SetLockClose: {
|
||||
IoStat->SwordLatch.moveOut();
|
||||
} break;
|
||||
case ServiceCommands_e::PlaySoundPromo: {
|
||||
MediaPlayer::playWavFile(SwordCfg.getSoundPromo());
|
||||
} break;
|
||||
case ServiceCommands_e::PlaySoundDeny: {
|
||||
MediaPlayer::playWavFile(SwordCfg.getSoundDeny());
|
||||
} break;
|
||||
case ServiceCommands_e::PlaySoundChosen: {
|
||||
MediaPlayer::playWavFile(SwordCfg.getSoundAllow());
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void processMaintanence(MqttChannel& mqtt) {
|
||||
auto& serCmds = mqtt.getSerCommands();
|
||||
while (true) {
|
||||
auto msg = mqtt.tryDequeueFor(500ms);
|
||||
if (msg) {
|
||||
if (serCmds.contains(msg->Payload)) {
|
||||
auto code = serCmds.at(msg->Payload);
|
||||
processMaintanenceCommand(code);
|
||||
}
|
||||
}
|
||||
IoStat->tick();
|
||||
mqtt.sendStatusMessage(Mode);
|
||||
}
|
||||
}
|
||||
|
||||
void processPromo(MqttChannel& mqtt, SeqLogger& log) {
|
||||
auto tn = chrono::steady_clock::now();
|
||||
auto& serCmds = mqtt.getSerCommands();
|
||||
while (true) {
|
||||
auto msg = mqtt.tryDequeueFor(10ms);
|
||||
if (msg) {
|
||||
if (serCmds.contains(msg->Payload)) {
|
||||
auto code = serCmds.at(msg->Payload);
|
||||
processMaintanenceCommand(code);
|
||||
}
|
||||
}
|
||||
IoStat->tick();
|
||||
if (IoStat->SwordPulled.isPosEdge()) {
|
||||
log.sendEvent("Pull", "Start Audio");
|
||||
MediaPlayer::playWavFile(SwordCfg.getSoundPromo());
|
||||
fmt::println("Waiting for {}", IoStat->PromoDelay);
|
||||
Thread::sleep(IoStat->PromoDelay);
|
||||
fmt::println("Waiting done");
|
||||
}
|
||||
if (chrono::steady_clock::now() > (tn + 1s)) {
|
||||
tn = chrono::steady_clock::now();
|
||||
mqtt.sendStatusMessage(Mode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void processProduction(MqttChannel& mqtt, SeqLogger& log) {
|
||||
auto& serCmds = mqtt.getSerCommands();
|
||||
auto& gameCmds = mqtt.getGameCommands();
|
||||
while (true) {
|
||||
auto msg = mqtt.tryDeque();
|
||||
if (!msg) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (serCmds.contains(msg->Payload)) {
|
||||
auto code = serCmds.at(msg->Payload);
|
||||
processMaintanenceCommand(code);
|
||||
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.getSoundDeny());
|
||||
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.getSoundAllow());
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
#pragma once
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <fmt/core.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/poll.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <CLI/CLI.hpp>
|
||||
#include <chrono>
|
||||
#include <cinttypes>
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <functional>
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
|
||||
#include "MqttClient.hpp"
|
||||
#include "coreExcept.hpp"
|
||||
#include "gpioPort.hpp"
|
||||
#include "loRa.hpp"
|
||||
#include "logging.hpp"
|
||||
#include "mutex.hpp"
|
||||
#include "palHw.hpp"
|
||||
#include "queue.hpp"
|
||||
#include "semaphore.hpp"
|
||||
#include "spiPort.hpp"
|
||||
#include "textUtils.hpp"
|
||||
#include "thread.hpp"
|
||||
|
||||
// internal interfaces
|
||||
#include "defines.hpp"
|
||||
|
||||
class DeviceIoState {
|
||||
public:
|
||||
DeviceIoState(int& count,
|
||||
bool& protect)
|
||||
: CoinAccepted(count),
|
||||
CoinDenied(count),
|
||||
CoinProtector(protect) {
|
||||
}
|
||||
|
||||
int& CoinAccepted;
|
||||
int& CoinDenied;
|
||||
bool& CoinProtector;
|
||||
|
||||
std::chrono::seconds PromoDelay{60};
|
||||
int Volume{100};
|
||||
};
|
||||
|
||||
class ThroneConfig {
|
||||
public:
|
||||
std::string getSoundPromo() { return soundPromo; }
|
||||
std::string getSoundCoronation() { return soundCoronation; }
|
||||
std::string getBrockerUrl() { return brockerUrl; }
|
||||
std::string getMqttUser() { return mqttUser; }
|
||||
std::string getMqttPassword() { return mqttPassword; }
|
||||
std::string getStationPath() { return stationPath; }
|
||||
|
||||
void setVar(std::string base,
|
||||
std::string brocker, std::string topic,
|
||||
std::string user, std::string passwd) {
|
||||
if (wasSet) {
|
||||
return;
|
||||
}
|
||||
soundPromo = base + soundPromo;
|
||||
soundCoronation = base + soundCoronation;
|
||||
|
||||
brockerUrl = brocker;
|
||||
stationPath = topic;
|
||||
mqttUser = user;
|
||||
mqttPassword = passwd;
|
||||
wasSet = true;
|
||||
}
|
||||
|
||||
private:
|
||||
bool wasSet{};
|
||||
std::string soundPromo{"/promo.wav"};
|
||||
std::string soundCoronation{"/coronation.wav"};
|
||||
|
||||
std::string brockerUrl;
|
||||
std::string mqttUser;
|
||||
std::string mqttPassword;
|
||||
std::string stationPath;
|
||||
};
|
||||
|
||||
constexpr int CoinProtectPin = 16;
|
||||
constexpr int CoinCntPin = 6;
|
||||
constexpr int GPIO_RST_PIN = 1;
|
||||
constexpr int GPIO_DIO0_PIN = 27;
|
||||
|
||||
Reference in new issue
Block a user