step: Implementing maintanance logic, preparing production
This commit is contained in:
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,6 @@
|
|||||||
|
# Commands
|
||||||
|
|
||||||
|
```sh
|
||||||
|
# set audio volume
|
||||||
|
alsamixer
|
||||||
|
```
|
||||||
+1
-1
Submodule platform updated: 92c57ba83f...0dbf21f25c
@@ -0,0 +1,89 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
static constexpr uint16_t UndefCmd = 0xFFFF;
|
||||||
|
enum ConMode_e {
|
||||||
|
ModeMqtt,
|
||||||
|
ModeLoRa
|
||||||
|
};
|
||||||
|
|
||||||
|
enum IncommingCommands_e : uint16_t {
|
||||||
|
Qurey, // Qurey info
|
||||||
|
SetMaintanance, // Set Maintanance mode
|
||||||
|
SetPromoMode, // Enable PromoMode
|
||||||
|
SetGamingMode, // Enable in Game mode
|
||||||
|
};
|
||||||
|
|
||||||
|
enum ServiceCommands_e {
|
||||||
|
Open,
|
||||||
|
Close,
|
||||||
|
Play1,
|
||||||
|
Play2,
|
||||||
|
Play3,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum GameModeCommands_e {
|
||||||
|
GameNextTryLocked, // Lock sword on next try
|
||||||
|
GameNextTryRelease // Release sword on next try
|
||||||
|
};
|
||||||
|
|
||||||
|
enum OutgoingCommands_e {
|
||||||
|
Status, // Send Status
|
||||||
|
Response, // Confirm last command
|
||||||
|
Error, // Send error status
|
||||||
|
PullHappend // Message if User tried to pull the sword
|
||||||
|
};
|
||||||
|
|
||||||
|
enum GameModeResponses_e {
|
||||||
|
SwordPullHappend, // Message if User tried to pull the sword
|
||||||
|
SwordReleased, // Message that User pulled the sword
|
||||||
|
SwordReturned // Message that User returned 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 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;
|
||||||
|
};
|
||||||
+345
-110
@@ -1,101 +1,199 @@
|
|||||||
#include "swordMain.hpp"
|
#include "swordMain.hpp"
|
||||||
|
|
||||||
|
#include "interface.hpp"
|
||||||
|
|
||||||
using namespace pal;
|
using namespace pal;
|
||||||
using namespace std::literals::string_view_literals;
|
using namespace std::literals::string_view_literals;
|
||||||
using namespace std::literals::chrono_literals;
|
using namespace std::literals::chrono_literals;
|
||||||
|
using namespace std;
|
||||||
// using namespace std::literals;
|
// using namespace std::literals;
|
||||||
|
|
||||||
constexpr int OutPin = 23;
|
const string BrockerUrl = "mqtts://nerdyssey.de:8883";
|
||||||
|
const string StationPath = "outdoor/king-arthur/sword/";
|
||||||
|
|
||||||
enum IncommingCommands_e {
|
constexpr uint8_t VersionArr[4] = {'T', 0, 5, 0};
|
||||||
Qurey, // Qurey info
|
const string Version = "T0.5.0";
|
||||||
Disable, // Disable Station
|
|
||||||
Maintanance, // Set Maintanance mode
|
|
||||||
SetPromoMode, // Enable PromoMode
|
|
||||||
SetGamingMode, // Enable in Game mode
|
|
||||||
NextTryLock, // Lock sword on next try
|
|
||||||
NextTryRelease // Release sword on next try
|
|
||||||
};
|
|
||||||
enum OutgoingCommands_e {
|
|
||||||
Version, // Send Version
|
|
||||||
Status, // Send Status
|
|
||||||
TryHappend, // Message if User tried to pull the sword
|
|
||||||
SwordReleased, // Message that User pulled the sword
|
|
||||||
SwordReturned // Message that User returned the sword
|
|
||||||
};
|
|
||||||
|
|
||||||
/// @brief incomming / outgoing message codes
|
constexpr int SwordEntryPin = 5;
|
||||||
struct TxMsg {
|
constexpr int SwordEndPin = 0;
|
||||||
TxMsg(std::uint32_t m)
|
constexpr int SwordPulledPin = 25;
|
||||||
: message(m) {};
|
|
||||||
uint32_t message;
|
|
||||||
};
|
|
||||||
// struct RsrsCtx {
|
|
||||||
// std::string name;
|
|
||||||
// Mutex& mtx;
|
|
||||||
// decltype(std::chrono::steady_clock::duration()) duration;
|
|
||||||
// };
|
|
||||||
|
|
||||||
|
constexpr int LinMotPin1 = 13;
|
||||||
|
constexpr int LinMotPin2 = 12;
|
||||||
|
|
||||||
|
constexpr int GPIO_RST_PIN = 4;
|
||||||
|
constexpr int GPIO_DIO0_PIN = 27;
|
||||||
|
constexpr ConMode_e ConMode{ConMode_e::ModeMqtt};
|
||||||
|
|
||||||
|
const string soundPromo = "/home/gustice/workspace/kingArth/swordStation/assets/promo.wav";
|
||||||
|
const string soundDeny = "/home/gustice/workspace/kingArth/swordStation/assets/deny.wav";
|
||||||
|
const string soundAllow = "/home/gustice/workspace/kingArth/swordStation/assets/allow.wav";
|
||||||
|
|
||||||
|
void playWavFile(const string& filePath) {
|
||||||
|
if (filePath.empty()) {
|
||||||
|
fmt::println(stderr, "ERROR: Empty file path");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
thread audioThread([filePath]() {
|
||||||
|
string cmd = "aplay \"" + filePath + "\" 2>/dev/null";
|
||||||
|
int result = system(cmd.c_str());
|
||||||
|
if (result != 0) {
|
||||||
|
fmt::println(stderr, "ERROR: Failed to play audio file: {}", filePath);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
audioThread.detach();
|
||||||
|
}
|
||||||
|
|
||||||
|
enum class OpMode {
|
||||||
|
Undefined, // Enable in Game mode
|
||||||
|
Maintanance = 1, // Set Maintanance mode
|
||||||
|
PromoMode, // Enable PromoMode
|
||||||
|
GamingMode, // Enable in Game mode
|
||||||
|
};
|
||||||
|
OpMode Mode = OpMode::Maintanance;
|
||||||
|
|
||||||
|
unique_ptr<DeviceIoState> IoStat;
|
||||||
|
|
||||||
/// @brief MQTT-Service provider
|
/// @brief MQTT-Service provider
|
||||||
// void LoRaServiceTask(Thread::Context& ctx, Queue<TxMsg>& queue) {
|
void MQttServiceTask(Thread::Context& ctx, Queue<RxMsg>& rxQueue, Queue<TxMsg>& txQueue) {
|
||||||
void MQttServiceTask(Thread::Context& ctx) {
|
string runTopic = StationPath + "run";
|
||||||
printf("MQTT service: Starting\n");
|
string intTopic = StationPath + "int";
|
||||||
// uint32_t cnt{};
|
string statTopic = StationPath + "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", BrockerUrl, topicsToRegister);
|
||||||
|
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()) {
|
while (!ctx.isCancelled()) {
|
||||||
Thread::sleep(2s);
|
auto tx = txQueue.dequeue();
|
||||||
// blinkSem.give();
|
|
||||||
// auto e = std::make_unique<TxMsg>(cnt++, "tick");
|
switch (tx->cmd) {
|
||||||
// queue.enqueue(std::move(e));
|
case OutgoingCommands_e::Status: {
|
||||||
std::cout << "MQTT service: Running ...\n";
|
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
|
/// @brief LoRa-Service provider
|
||||||
// void LoRaServiceTask(Thread::Context& ctx, Queue<TxMsg>& queue) {
|
void LoRaServiceTask(Thread::Context& ctx, Queue<RxMsg>& rxQueue, Queue<TxMsg>& txQueue) {
|
||||||
void LoRaServiceTask(Thread::Context& ctx) {
|
fmt::println("LoRa: Starting task:");
|
||||||
printf("LoRa service: Starting\n");
|
|
||||||
// uint32_t cnt{};
|
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()) {
|
while (!ctx.isCancelled()) {
|
||||||
Thread::sleep(2s);
|
auto tx = txQueue.dequeue();
|
||||||
// blinkSem.give();
|
loRa.send({0});
|
||||||
// auto e = std::make_unique<TxMsg>(cnt++, "tick");
|
|
||||||
// queue.enqueue(std::move(e));
|
|
||||||
std::cout << "LoRa service: Running ...\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
// while (!ctx.isCancelled()) {
|
|
||||||
// auto msg = queue.dequeue(); // Wait with infinit timeout, guaranteed to succeed
|
|
||||||
// printf ("Message: %s %lu\n", msg->message.c_str(), msg->cnt);
|
// printf ("Message: %s %lu\n", msg->message.c_str(), msg->cnt);
|
||||||
// }
|
|
||||||
// while (!ctx.isCancelled()) {
|
|
||||||
// blinkSem.take();
|
|
||||||
// led.write(true); // execute blink event
|
|
||||||
// Thread::sleep(100ms);
|
|
||||||
// led.write(false); // execute blink event
|
|
||||||
// printf("Blink tick\n");
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// void RessourceAccessor(Thread::Context& tCtx, RsrsCtx& ctx) {
|
try {
|
||||||
// using namespace std::chrono;
|
} catch (const exception& exc) {
|
||||||
// fmt::println("starting Ressource Accessor {}", ctx.name);
|
fmt::println(stderr, "\nERROR: Unable to connect to Setup bridge: {}", exc.what());
|
||||||
// while (!tCtx.isCancelled()) {
|
ctx.markFailed();
|
||||||
// {
|
}
|
||||||
// StopWatch sw;
|
}
|
||||||
// ctx.mtx.claim();
|
|
||||||
// auto e = duration_cast<milliseconds>(sw.getEleapsed());
|
|
||||||
// auto d = duration_cast<milliseconds>(ctx.duration);
|
|
||||||
// fmt::println("took {}ms to quire, now access ressource for {}ms",
|
|
||||||
// (int)e.count(), (int)d.count());
|
|
||||||
// Thread::sleep(ctx.duration);
|
|
||||||
// ctx.mtx.release();
|
|
||||||
// }
|
|
||||||
// Thread::sleep(100ms);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
void itrHandler() {
|
int main(int argc, char* argv[]) {
|
||||||
|
fmt::println("Sword Firmware");
|
||||||
|
|
||||||
|
auto itrHandler = [&]() {
|
||||||
TriggeredInput itr(26, "PItr");
|
TriggeredInput itr(26, "PItr");
|
||||||
while (true) {
|
while (true) {
|
||||||
std::cout << "Await next interrupt\n";
|
std::cout << "Await next interrupt\n";
|
||||||
@@ -103,46 +201,183 @@ void itrHandler() {
|
|||||||
std::cout << "Interrupt Event\n";
|
std::cout << "Interrupt Event\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
int main(int argc, char* argv[]) {
|
|
||||||
printf("Sword Firmware\n");
|
|
||||||
|
|
||||||
OutputPort out(OutPin, "POut");
|
|
||||||
InputPort in(20, "PIn");
|
|
||||||
std::cout << "setting GPIO21 as Out and GPIO20 as input: ";
|
|
||||||
|
|
||||||
std::thread interruptThread(itrHandler);
|
std::thread interruptThread(itrHandler);
|
||||||
|
|
||||||
// Semaphore blinkSem;
|
InputPort spPort(SwordPulledPin, "PInSPull");
|
||||||
auto mqttTask = Thread::createExplicit("MqttTask", MQttServiceTask);
|
InputPort sbPort(SwordEntryPin, "PinSEntry");
|
||||||
auto loraTask = Thread::createExplicit("LoRaTask", LoRaServiceTask);
|
InputPort sePort(SwordEndPin, "PInSEnd");
|
||||||
// static Queue<TxMsg> txQueue;
|
OutputPort mOut1(LinMotPin1, "M1:1");
|
||||||
// auto mqttTask = Thread::createExplicit("MqttTask", MQttServiceTask, std::ref(txQueue));
|
OutputPort mOut2(LinMotPin2, "M1:2");
|
||||||
// auto loraTask = Thread::createExplicit("LoRaTask", LoRaServiceTask, std::ref(txQueue));
|
InputTransAware SwordEntry(sbPort);
|
||||||
|
InputTransAware SwordEnd(sePort);
|
||||||
|
InputTransAware SwordPulled(spPort);
|
||||||
|
LinMot SwordLatch(mOut1, mOut2);
|
||||||
|
|
||||||
// Mutex rsrMtx;
|
IoStat = make_unique<DeviceIoState>(SwordEntry, SwordEnd, SwordPulled, SwordLatch);
|
||||||
// RsrsCtx rsCtx1{
|
|
||||||
// .name = "intense",
|
|
||||||
// .mtx = rsrMtx,
|
|
||||||
// .duration = 3000ms};
|
|
||||||
// RsrsCtx rsCtx2{
|
|
||||||
// .name = "light",
|
|
||||||
// .mtx = rsrMtx,
|
|
||||||
// .duration = 1000ms};
|
|
||||||
// auto ressourceAccess1 = Thread::createExplicit("IntenseAccess", RessourceAccessor, std::ref(rsCtx1));
|
|
||||||
// auto ressourceAccess2 = Thread::createExplicit("LightAccess", RessourceAccessor, std::ref(rsCtx2));
|
|
||||||
|
|
||||||
fmt::print("Running App\n");
|
auto tick = [&]() {
|
||||||
|
SwordEntry.sample();
|
||||||
|
SwordEnd.sample();
|
||||||
|
SwordPulled.sample();
|
||||||
|
};
|
||||||
|
|
||||||
|
static Queue<RxMsg> rxQueue;
|
||||||
|
static Queue<TxMsg> txQueue;
|
||||||
|
static auto conTask = (ConMode == ModeMqtt) ? Thread::createExplicit("MqttTask", MQttServiceTask, std::ref(rxQueue), std::ref(txQueue))
|
||||||
|
: Thread::createExplicit("LoRaTask", LoRaServiceTask, std::ref(rxQueue), std::ref(txQueue));
|
||||||
|
|
||||||
|
SwordLatch.moveOut();
|
||||||
|
|
||||||
|
const static map<IncommingCommands_e, OpMode> opCodes = {
|
||||||
|
{SetMaintanance, OpMode::Maintanance},
|
||||||
|
{SetPromoMode, OpMode::PromoMode},
|
||||||
|
{SetGamingMode, OpMode::GamingMode},
|
||||||
|
};
|
||||||
|
|
||||||
|
fmt::println("Running App");
|
||||||
|
while (true) {
|
||||||
|
auto msg = rxQueue.dequeue();
|
||||||
|
fmt::println("MAIN: Got message {}", msg->code);
|
||||||
|
|
||||||
|
auto code = static_cast<IncommingCommands_e>(msg->code);
|
||||||
|
if (opCodes.contains(code)) {
|
||||||
|
Mode == opCodes.at(code);
|
||||||
|
} else {
|
||||||
|
Mode = OpMode::Undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (Mode) {
|
||||||
|
case OpMode::Maintanance: {
|
||||||
|
fmt::println("Got Maintanance");
|
||||||
|
auto e = std::make_unique<ResponseTxMsg>(msg->code, 0);
|
||||||
|
txQueue.enqueue(std::move(e));
|
||||||
|
// txQueue.emplace<ResponseTxMsg>(msg->code, 0);
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
std::cout << "in=" << in.read() << "\n";
|
auto serMsg = rxQueue.tryDequeueFor(1000ms);
|
||||||
out.write(0);
|
if (serMsg) {
|
||||||
std::this_thread::sleep_for(std::chrono::milliseconds(500));
|
auto code = static_cast<ServiceCommands_e>(serMsg->code);
|
||||||
std::cout << "in=" << in.read() << "\n";
|
switch (code) {
|
||||||
out.write(1);
|
case ServiceCommands_e::Open: {
|
||||||
std::this_thread::sleep_for(std::chrono::milliseconds(500));
|
IoStat->SwordLatch.moveIn();
|
||||||
// std::this_thread::sleep_for(1s);
|
} break;
|
||||||
|
case ServiceCommands_e::Close: {
|
||||||
|
IoStat->SwordLatch.moveOut();
|
||||||
|
} break;
|
||||||
|
case ServiceCommands_e::Play1: {
|
||||||
|
playWavFile(soundPromo);
|
||||||
|
} break;
|
||||||
|
case ServiceCommands_e::Play2: {
|
||||||
|
playWavFile(soundDeny);
|
||||||
|
} break;
|
||||||
|
case ServiceCommands_e::Play3: {
|
||||||
|
playWavFile(soundAllow);
|
||||||
|
} break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto e = std::make_unique<StatusTxMsg>(
|
||||||
|
(uint8_t)Mode,
|
||||||
|
IoStat->SwordEnd.get(),
|
||||||
|
IoStat->SwordEntry.get(),
|
||||||
|
IoStat->SwordPulled.get(),
|
||||||
|
IoStat->SwordLatch.isLocked());
|
||||||
|
txQueue.enqueue(std::move(e));
|
||||||
|
}
|
||||||
|
e = std::make_unique<ResponseTxMsg>(msg->code, 0);
|
||||||
|
txQueue.enqueue(std::move(e));
|
||||||
|
} break;
|
||||||
|
case OpMode::PromoMode: {
|
||||||
|
fmt::println("Got SetPromoMode");
|
||||||
|
auto e = std::make_unique<ResponseTxMsg>(msg->code, 0);
|
||||||
|
txQueue.enqueue(std::move(e));
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
SwordPulled.sample();
|
||||||
|
auto rx = txQueue.tryDequeueFor(10ms);
|
||||||
|
if (SwordPulled.isPosEdge()) {
|
||||||
|
// say: Play our tours
|
||||||
|
Thread::sleep(5s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
case OpMode::GamingMode: {
|
||||||
|
fmt::println("Got SetGamingMode");
|
||||||
|
auto e = std::make_unique<ResponseTxMsg>(msg->code, 0);
|
||||||
|
txQueue.enqueue(std::move(e));
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
auto gameMsg = txQueue.dequeue();
|
||||||
|
auto code = static_cast<GameModeCommands_e>(msg->code);
|
||||||
|
switch (code) {
|
||||||
|
case GameModeCommands_e::GameNextTryLocked: {
|
||||||
|
auto e = std::make_unique<ResponseTxMsg>(msg->code, 0);
|
||||||
|
txQueue.enqueue(std::move(e));
|
||||||
|
|
||||||
|
fmt::println("Got NextTryLock");
|
||||||
|
while (true) {
|
||||||
|
SwordPulled.sample();
|
||||||
|
auto rx = txQueue.tryDequeueFor(20ms);
|
||||||
|
bool pulled = SwordPulled.read();
|
||||||
|
if (SwordPulled.isPosEdge()) {
|
||||||
|
// say: You are not the one
|
||||||
|
Thread::sleep(5s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
case GameModeCommands_e::GameNextTryRelease: {
|
||||||
|
auto e = std::make_unique<ResponseTxMsg>(msg->code, 0);
|
||||||
|
txQueue.enqueue(std::move(e));
|
||||||
|
SwordLatch.moveIn();
|
||||||
|
|
||||||
|
fmt::println("Got NextTryRelease");
|
||||||
|
while (true) {
|
||||||
|
SwordEnd.sample();
|
||||||
|
auto rx = txQueue.tryDequeueFor(20ms);
|
||||||
|
if (SwordEnd.isNegEdge()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while (true) {
|
||||||
|
SwordEntry.sample();
|
||||||
|
auto rx = txQueue.tryDequeueFor(20ms);
|
||||||
|
if (SwordEntry.isNegEdge()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// say: The prophecy is fulfilled
|
||||||
|
e = std::make_unique<ResponseTxMsg>(msg->code, 0);
|
||||||
|
txQueue.enqueue(std::move(e));
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
SwordEnd.sample();
|
||||||
|
auto rx = txQueue.tryDequeueFor(20ms);
|
||||||
|
if (SwordEnd.isNegEdge()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while (true) {
|
||||||
|
SwordEntry.sample();
|
||||||
|
auto rx = txQueue.tryDequeueFor(20ms);
|
||||||
|
if (SwordEntry.isNegEdge()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
e = std::make_unique<ResponseTxMsg>(msg->code, 0);
|
||||||
|
txQueue.enqueue(std::move(e));
|
||||||
|
|
||||||
|
} break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
interruptThread.join();
|
interruptThread.join();
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
|
|||||||
@@ -12,6 +12,7 @@
|
|||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <map>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
@@ -27,3 +28,57 @@
|
|||||||
#include "spiPort.hpp"
|
#include "spiPort.hpp"
|
||||||
#include "textUtils.hpp"
|
#include "textUtils.hpp"
|
||||||
#include "thread.hpp"
|
#include "thread.hpp"
|
||||||
|
|
||||||
|
#include "palHw.hpp"
|
||||||
|
|
||||||
|
class LinMot {
|
||||||
|
public:
|
||||||
|
LinMot(OutputPort& o1, OutputPort& o2)
|
||||||
|
: _out1(o1),
|
||||||
|
_out2(o2) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void moveOut() {
|
||||||
|
_out2.write(false);
|
||||||
|
_out1.write(true);
|
||||||
|
_locked = true;
|
||||||
|
}
|
||||||
|
void moveIn() {
|
||||||
|
_out2.write(true);
|
||||||
|
_out1.write(false);
|
||||||
|
_locked = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isLocked() {
|
||||||
|
return _locked;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
OutputPort& _out1;
|
||||||
|
OutputPort& _out2;
|
||||||
|
bool _locked;
|
||||||
|
};
|
||||||
|
|
||||||
|
class DeviceIoState {
|
||||||
|
public:
|
||||||
|
DeviceIoState(pal::InputTransAware& entry,
|
||||||
|
pal::InputTransAware& end,
|
||||||
|
pal::InputTransAware& pulled,
|
||||||
|
LinMot& latch)
|
||||||
|
: SwordEntry(entry),
|
||||||
|
SwordEnd(end),
|
||||||
|
SwordPulled(pulled),
|
||||||
|
SwordLatch(latch) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void tick() {
|
||||||
|
SwordEntry.sample();
|
||||||
|
SwordEnd.sample();
|
||||||
|
SwordPulled.sample();
|
||||||
|
}
|
||||||
|
|
||||||
|
pal::InputTransAware& SwordEntry;
|
||||||
|
pal::InputTransAware& SwordEnd;
|
||||||
|
pal::InputTransAware& SwordPulled;
|
||||||
|
LinMot& SwordLatch;
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user