From 872cc04a548be56ad0e7c083f9557d298ddb6a83 Mon Sep 17 00:00:00 2001 From: uvos Date: Mon, 21 Mar 2022 21:23:22 +0100 Subject: [PATCH] Intal version with working trainoverlord --- src/CMakeLists.txt | 9 +- src/common/items/item.h | 2 +- src/common/items/itemstore.cpp | 5 +- src/common/items/itemstore.h | 2 +- src/common/items/train.cpp | 69 +++++ src/common/items/train.h | 19 ++ .../items/{signal.cpp => trainsignal.cpp} | 2 +- src/common/items/{signal.h => trainsignal.h} | 0 src/common/microcontroller.cpp | 15 +- src/trainControllerUI/traincontrollerui.cpp | 8 +- src/trainControllerUI/ui/itemscrollbox.cpp | 8 +- src/trainControllerUI/ui/signalwidget.cpp | 2 +- src/trainControllerUI/ui/signalwidget.h | 2 +- src/trainOverlord/CMakeLists.txt | 7 + src/trainOverlord/block.cpp | 254 ++++++++++++++++++ src/trainOverlord/block.h | 65 +++++ src/trainOverlord/blockborder.cpp | 137 ++++++++++ src/trainOverlord/blockborder.h | 38 +++ src/trainOverlord/layout.cpp | 221 +++++++++++++++ src/trainOverlord/layout.h | 43 +++ src/trainOverlord/overlorditemstore.cpp | 14 +- src/trainOverlord/overlorditemstore.h | 8 +- src/trainOverlord/trainoverlord.cpp | 108 +++++++- 23 files changed, 992 insertions(+), 46 deletions(-) rename src/common/items/{signal.cpp => trainsignal.cpp} (96%) rename src/common/items/{signal.h => trainsignal.h} (100%) create mode 100644 src/trainOverlord/block.cpp create mode 100644 src/trainOverlord/block.h create mode 100644 src/trainOverlord/blockborder.cpp create mode 100644 src/trainOverlord/blockborder.h create mode 100644 src/trainOverlord/layout.cpp create mode 100644 src/trainOverlord/layout.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 842991e..11a92ee 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -12,11 +12,17 @@ find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Widgets Network SerialPort REQUIRE set(COMMON_SOURCES ../common/microcontroller.cpp + ../common/microcontroller.h ../common/items/item.cpp + ../common/items/item.h ../common/items/itemstore.cpp - ../common/items/signal.cpp + ../common/items/itemstore.h + ../common/items/trainsignal.cpp + ../common/items/trainsignal.h ../common/items/train.cpp + ../common/items/train.h ../common/items/turnout.cpp + ../common/items/turnout.h ) include_directories(PRIVATE @@ -32,3 +38,4 @@ set(COMMON_LINK_LIBRARYS add_subdirectory(trainControllerUI) add_subdirectory(trainOverlord) + diff --git a/src/common/items/item.h b/src/common/items/item.h index 9034be5..54c843a 100644 --- a/src/common/items/item.h +++ b/src/common/items/item.h @@ -59,7 +59,7 @@ public: virtual ~Item(); - void informValue(int8_t value); + virtual void informValue(int8_t value); }; diff --git a/src/common/items/itemstore.cpp b/src/common/items/itemstore.cpp index 523d2ce..faf769a 100644 --- a/src/common/items/itemstore.cpp +++ b/src/common/items/itemstore.cpp @@ -22,7 +22,6 @@ void ItemStore::addItem(std::shared_ptr item) items_.push_back(std::shared_ptr(item)); itemAdded(std::weak_ptr(items_.back())); } - qDebug()<<"Got item: "<id()<<" matched: "<>& itemIn) @@ -35,7 +34,7 @@ void ItemStore::addItems(const std::vector>& itemIn) continue; if(train->getTrainId() == 0) { - const uint8_t uidBytes[] = {12, 154, 110, 34}; + const uint8_t uidBytes[] = {154, 110, 34, 218}; train->tags.push_back(NfcUid(uidBytes, sizeof(uidBytes))); } else if(train->getTrainId() == 3) @@ -45,7 +44,7 @@ void ItemStore::addItems(const std::vector>& itemIn) } else if(train->getTrainId() == 4) { - const uint8_t uidBytes[] = {76, 55, 220, 31}; + const uint8_t uidBytes[] = {55, 220, 31, 184}; train->tags.push_back(NfcUid(uidBytes, sizeof(uidBytes))); } } diff --git a/src/common/items/itemstore.h b/src/common/items/itemstore.h index 7a542b9..ff2ce79 100644 --- a/src/common/items/itemstore.h +++ b/src/common/items/itemstore.h @@ -30,7 +30,7 @@ signals: public slots: void removeItem(const ItemData& item); - void addItem(std::shared_ptr item); + virtual void addItem(std::shared_ptr item); void addItems(const std::vector>& itemsIn); void itemStateChanged(const ItemData& item); }; diff --git a/src/common/items/train.cpp b/src/common/items/train.cpp index 2929df9..38eb6b3 100644 --- a/src/common/items/train.cpp +++ b/src/common/items/train.cpp @@ -19,13 +19,82 @@ void Train::setFunction(uint8_t funciton, bool value) void Train::setValue(int8_t value) { Item::setValue(value); + if(suspended_ && value != 0) + { + suspended_ = false; + unsuspended(id(), getDirection()); + } if(micro) micro->trainSetSpeed(train_id_, value); } +void Train::informValue(int8_t value) +{ + if(suspended_ && value != 0) + { + suspended_ = false; + unsuspended(id(), getDirection()); + } + Item::informValue(value); +} + void Train::reverse() { if(micro) micro->trainReverse(train_id_); } +int Train::ownsTag(NfcUid uid) +{ + for(size_t i = 0; i < tags.size(); ++i) + { + if(uid == tags[i]) + { + if(i == 0) + return getDirection() == FORWARD ? TAG_FRONT : TAG_BACK; + else if(i == tags.size()-1) + return getDirection() == REVERSE ? TAG_FRONT : TAG_BACK; + else + return TAG_CENTER; + } + } + return TAG_NONE; +} + +bool Train::suspend() +{ + if(suspended_) + return false; + suspendedSpeed_ = value_; + setValue(0); + suspended_ = true; + return true; +} + +bool Train::resume() +{ + if(!suspended_) + return false; + suspended_ = false; + setValue(suspendedSpeed_); + return true; +} + +bool Train::hasBackTag() +{ + return tags.size() > 1; +} + +bool Train::suspendend() +{ + return suspended_; +} + +int Train::getDirection() +{ + if(!suspended_) + return value_ < 0 ? REVERSE : FORWARD; + else + return suspendedSpeed_ < 0 ? REVERSE : FORWARD; +} + diff --git a/src/common/items/train.h b/src/common/items/train.h index e1d23ba..1d63e58 100644 --- a/src/common/items/train.h +++ b/src/common/items/train.h @@ -12,7 +12,16 @@ class Train : public Item uint8_t functionMask_; uint8_t train_id_; int lastReader_ = -1; + int8_t suspendedSpeed_; + bool suspended_ = false; public: + static constexpr int FORWARD = 1; + static constexpr int REVERSE = -1; + static constexpr int TAG_FRONT = 0; + static constexpr int TAG_BACK = 1; + static constexpr int TAG_CENTER = 2; + static constexpr int TAG_NONE = -1; + static Microcontroller *micro; std::vector tags; @@ -27,6 +36,13 @@ public slots: void reverse(); virtual void setFunction(uint8_t function, bool on); virtual void setValue(int8_t value); + virtual void informValue(int8_t value); + bool suspend(); + bool resume(); + bool suspendend(); + int getDirection(); + int ownsTag(NfcUid uid); + bool hasBackTag(); bool passedReader(const NfcUid &uid) { if(lastReader_ == uid.reader) @@ -38,6 +54,9 @@ public slots: { return train_id_; } + +signals: + void unsuspended(uint32_t id, int direction); }; #endif // TRAIN_H diff --git a/src/common/items/signal.cpp b/src/common/items/trainsignal.cpp similarity index 96% rename from src/common/items/signal.cpp rename to src/common/items/trainsignal.cpp index f5b4c08..c8178ec 100644 --- a/src/common/items/signal.cpp +++ b/src/common/items/trainsignal.cpp @@ -1,4 +1,4 @@ -#include "signal.h" +#include "trainsignal.h" Microcontroller *Signal::micro = nullptr; diff --git a/src/common/items/signal.h b/src/common/items/trainsignal.h similarity index 100% rename from src/common/items/signal.h rename to src/common/items/trainsignal.h diff --git a/src/common/microcontroller.cpp b/src/common/microcontroller.cpp index ae8b1ab..553e867 100644 --- a/src/common/microcontroller.cpp +++ b/src/common/microcontroller.cpp @@ -2,13 +2,12 @@ #include #include -#include "items/train.h" -#include "items/turnout.h" -#include "items/signal.h" +#include "train.h" +#include "turnout.h" +#include "trainsignal.h" void Microcontroller::trainSetSpeed(uint8_t id, int8_t speed) { - qDebug()<<__func__; std::stringstream ss; ss<<"train "<<(unsigned)id<<" speed "<<(int)speed<<'\n'; write(ss.str().c_str()); @@ -54,18 +53,16 @@ void Microcontroller::estop() void Microcontroller::write(const QByteArray& buffer) { - qDebug()<write(buffer); - _port->waitForBytesWritten(1000); + //_port->waitForBytesWritten(1000); } std::this_thread::sleep_for(std::chrono::milliseconds(40)); } void Microcontroller::write(char* buffer, const size_t length) { - qDebug()<write(buffer, length); @@ -86,6 +83,7 @@ void Microcontroller::requestState() write("train list\n"); write("turnout list\n"); write("signal list\n"); + write("nfc list\n"); } //housekeeping @@ -154,14 +152,12 @@ void Microcontroller::processNfcLine(const QString& buffer) uid.length = tokens.length(); for(size_t i = 0; i < uid.length; ++i) uid.bytes[i] = tokens[i].toInt(); - qDebug()<<"Got Tag"; gotTag(uid); } void Microcontroller::processList(const QString& buffer) { QStringList bufferList = buffer.split(' '); - qDebug()<<__func__<<" :"<= 10 && buffer.contains("NUMBER:")) { std::shared_ptr item; @@ -179,7 +175,6 @@ void Microcontroller::processList(const QString& buffer) listMode = false; if(!itemList.empty()) { - qDebug()<<"got item list " << itemList.size(); gotItemList(itemList); itemList.clear(); } diff --git a/src/trainControllerUI/traincontrollerui.cpp b/src/trainControllerUI/traincontrollerui.cpp index 86cb846..6541439 100644 --- a/src/trainControllerUI/traincontrollerui.cpp +++ b/src/trainControllerUI/traincontrollerui.cpp @@ -10,10 +10,10 @@ #include "microcontroller.h" #include "trainjs.h" #include "ui/mainwindow.h" -#include "items/itemstore.h" -#include "items/train.h" -#include "items/turnout.h" -#include "items/signal.h" +#include "itemstore.h" +#include "train.h" +#include "turnout.h" +#include "trainsignal.h" #define BAUD QSerialPort::Baud38400 diff --git a/src/trainControllerUI/ui/itemscrollbox.cpp b/src/trainControllerUI/ui/itemscrollbox.cpp index 2810781..50f4d7b 100644 --- a/src/trainControllerUI/ui/itemscrollbox.cpp +++ b/src/trainControllerUI/ui/itemscrollbox.cpp @@ -1,10 +1,10 @@ #include "itemscrollbox.h" #include "ui_relayscrollbox.h" #include "ui_relayscrollbox.h" -#include "../items/train.h" -#include "../items/turnout.h" -#include "../items/signal.h" -#include "../trainjs.h" +#include "train.h" +#include "turnout.h" +#include "trainsignal.h" +#include "trainjs.h" #include "trainwidget.h" #include "signalwidget.h" diff --git a/src/trainControllerUI/ui/signalwidget.cpp b/src/trainControllerUI/ui/signalwidget.cpp index 17550ec..6bb722b 100644 --- a/src/trainControllerUI/ui/signalwidget.cpp +++ b/src/trainControllerUI/ui/signalwidget.cpp @@ -4,7 +4,7 @@ #include #include #include -#include "../items/signal.h" +#include "trainsignal.h" SignalWidget::SignalWidget(std::weak_ptr item, QWidget *parent) : ItemWidget(item, parent), diff --git a/src/trainControllerUI/ui/signalwidget.h b/src/trainControllerUI/ui/signalwidget.h index f0fbfca..6cc36f3 100644 --- a/src/trainControllerUI/ui/signalwidget.h +++ b/src/trainControllerUI/ui/signalwidget.h @@ -3,7 +3,7 @@ #include #include #include -#include "../items/signal.h" +#include "../items/trainsignal.h" #include "itemwidget.h" namespace Ui diff --git a/src/trainOverlord/CMakeLists.txt b/src/trainOverlord/CMakeLists.txt index c6ec6c9..ce7f463 100644 --- a/src/trainOverlord/CMakeLists.txt +++ b/src/trainOverlord/CMakeLists.txt @@ -1,6 +1,13 @@ set(UI_SOURCES trainoverlord.cpp overlorditemstore.cpp + overlorditemstore.h + blockborder.cpp + blockborder.h + block.cpp + block.h + layout.h + layout.cpp ) add_executable(trainoverlord ${UI_SOURCES} ${COMMON_SOURCES}) diff --git a/src/trainOverlord/block.cpp b/src/trainOverlord/block.cpp new file mode 100644 index 0000000..63da753 --- /dev/null +++ b/src/trainOverlord/block.cpp @@ -0,0 +1,254 @@ +#include "block.h" +#include +#include + +Block::Block(uint32_t id): + id_(id) +{ + +} + +void Block::addBorder(std::shared_ptr border) +{ + borders_.push_back(border); + std::shared_ptr block = border->getOtherBlock(this); + if(!block || block.get() == this) + { + qWarning()<<__func__<<"no other block in border"<id(); + return; + } + connect(block.get(), &Block::blockedChanged, this, &Block::checkWaits); +} + +bool Block::blocked() +{ + if(trains_.empty() && waits_.empty()) + return false; + return true; +} + +bool Block::ownsTrain(std::weak_ptr train) +{ + std::shared_ptr trainPtr = train.lock(); + if(!trainPtr) + return false; + + for(auto ownedTrain : trains_) + { + if(ownedTrain.lock() == trainPtr) + return true; + } + return false; +} + +bool Block::ownsBorder(std::shared_ptr border) +{ + if(!border) + return false; + for(std::shared_ptr borderTest : borders_) + { + if(borderTest == border) + return true; + } + return false; +} + +void Block::checkWaits(bool ign) +{ + qDebug()<<__func__; + (void)ign; + bool wasBlocked = blocked(); + for(std::vector::iterator iter = waits_.begin(); iter != waits_.end();) + { + std::shared_ptr block = iter->targetBlock.lock(); + std::shared_ptr train = iter->train.lock(); + qDebug()<<__func__<<"trying to push train"<getTrainId()<<"to block"<id(); + if(block && train && train->suspendend() && block->pushTrain(iter->train)) + { + train->resume(); + std::shared_ptr border = iter->border.lock(); + if(border) + border->updateSignals(); + iter = waits_.erase(iter); + } + else if(!block || !train || !train->suspendend()) + { + iter = waits_.erase(iter); + } + else + { + ++iter; + } + } + if(wasBlocked != blocked()) + blockedChanged(!wasBlocked); +} + +void Block::updateBorders() +{ + for(std::shared_ptr broder : borders_) + { + broder->updateSignals(); + } +} + +bool Block::pushTrain(std::weak_ptr train) +{ + if(blocked()) + return false; + + addTrain(train); + return true; +} + +void Block::addTrain(std::weak_ptr train) +{ + std::shared_ptr trainPtr = train.lock(); + if(!trainPtr) + return; + qDebug()<<"Train"<getTrainId()<<"added to block"<::iterator iter = waits_.begin(); iter != waits_.end(); ++iter) + { + std::shared_ptr workTrain = iter->train.lock(); + if(!workTrain) + { + waits_.erase(iter); + unsuspendedTrain(id, direction); + break; + } + if(workTrain->id() == id) + { + std::shared_ptr block = iter->targetBlock.lock(); + disconnect(workTrain.get(), &Train::unsuspended, this, &Block::unsuspendedTrain); + if(iter->direction == direction) + { + if(block) + block->addTrain(workTrain); + } + else + { + addTrain(workTrain); + } + waits_.erase(iter); + break; + } + } + if(wasBlocked != blocked()) + blockedChanged(!wasBlocked); + updateBorders(); +} + +void Block::removeTrain(std::weak_ptr train) +{ + std::shared_ptr trainPtr = train.lock(); + if(!trainPtr) + return; + + for(std::vector>::iterator iter = trains_.begin(); iter != trains_.end(); ++iter) + { + if(iter->lock() == trainPtr) + { + qDebug()<<"Train"<getTrainId()<<"removed from to block"< borderIn, std::weak_ptr trainIn) +{ + qDebug()<<__func__<<"block"< border = borderIn.lock(); + if(!border) + { + qWarning()<<"border has expired in"<<__func__; + return; + } + + if(!ownsBorder(border)) + return; + + qDebug()<<"Block"<getOtherBlock(this); + if(block) + { + std::shared_ptr workTrain = trainIn.lock(); + if(workTrain) + { + if(!block->pushTrain(trainIn)) + { + workTrain->suspend(); + TrainWait wait; + wait.train = trainIn; + wait.direction = workTrain->getDirection(); + wait.targetBlock = block; + wait.border = border; + connect(workTrain.get(), &Train::unsuspended, this, &Block::unsuspendedTrain); + waits_.push_back(wait); + qDebug()<<"Train"<getTrainId()<<"is wating at border for block"<id(); + if(!block->trains_.empty() && block->trains_[0].lock()) + qDebug()<<"for train"<trains_[0].lock()->getTrainId()<<"to leave"; + } + removeTrain(workTrain); + } + } + if(wasBlocked != blocked()) + blockedChanged(blocked()); + updateBorders(); +} + +void Block::store(QJsonObject &json) +{ + json["Id"] = static_cast(id_); + QJsonArray borders; + for(auto& border : borders_) + { + QJsonObject borderObject; + borderObject["BorderId"] = static_cast(border->id()); + borders.append(borderObject); + } + json["Borders"] = borders; +} + +void Block::load(const QJsonObject &json) +{ + id_ = static_cast(json["Id"].toDouble(0)); +} + +void Block::populate(const QJsonObject& json, Layout* layout) +{ + borders_.clear(); + const QJsonArray bordersArray(json["Borders"].toArray(QJsonArray())); + for(const auto& arrayObj : bordersArray) + { + if(arrayObj.isObject()) + { + uint32_t borderId = static_cast(arrayObj.toObject()["BorderId"].toDouble(INT32_MAX)); + std::shared_ptr border = layout->getBorder(borderId); + if(border) + addBorder(border); + else if(borderId == INT32_MAX) + qWarning()<<"BorderId field is missing in border array for block"< +#include +#include +#include +#include +#include "blockborder.h" +#include "train.h" + +class BlockBorder; +class Layout; + +class Block: public QObject +{ + Q_OBJECT +protected: + static constexpr int WAIT_TYPE_BLOCK = 0; + static constexpr int WAIT_TYPE_TRAVERSE = 1; + + struct TrainWait + { + int type; + int direction; + std::weak_ptr train; + std::weak_ptr targetBlock; + std::weak_ptr border; + }; + + std::vector< std::shared_ptr > borders_; + std::vector< std::weak_ptr > trains_; + std::vector waits_; + uint32_t id_; + +protected slots: + void unsuspendedTrain(uint32_t id, int direction); + +protected: + void checkWaits(bool blocked = false); + void updateBorders(); + +public: + Block(uint32_t id = QRandomGenerator::global()->generate()); + void addBorder(std::shared_ptr border); + bool blocked(); + bool ownsTrain(std::weak_ptr train); + bool ownsBorder(std::shared_ptr border); + std::vector< std::shared_ptr > getBorders(){return borders_;} + uint32_t id(){return id_;} + void removeTrain(std::weak_ptr train); + void store(QJsonObject& json); + void load(const QJsonObject& json); + void populate(const QJsonObject& json, Layout* layout); + +public slots: + bool pushTrain(std::weak_ptr train); + void addTrain(std::weak_ptr train); + void trainArrivedAtBorder(std::weak_ptr border, std::weak_ptr train); + +signals: + void blockedChanged(bool blocked); + void trainAddedToBlock(int blockId, std::weak_ptr train); +}; + +#endif // BLOCK_H diff --git a/src/trainOverlord/blockborder.cpp b/src/trainOverlord/blockborder.cpp new file mode 100644 index 0000000..13d77af --- /dev/null +++ b/src/trainOverlord/blockborder.cpp @@ -0,0 +1,137 @@ +#include "blockborder.h" +#include +#include + +BlockBorder::BlockBorder(uint8_t reader, std::pair, std::weak_ptr> blocks, uint32_t id): reader_(reader), blocks_(blocks), id_(id) +{ + +} + +bool BlockBorder::isReader(uint8_t reader) +{ + return reader == reader_; +} + +uint8_t BlockBorder::getReader() +{ + return reader_; +} + +void BlockBorder::setSignal(std::weak_ptr signalWeak, int8_t value) +{ + std::shared_ptr signal = signalWeak.lock(); + if(signal) + { + signal->setValue(value); + } +} + +void BlockBorder::updateSignals() +{ + for(size_t i = 0; i < signals_.size(); ++i) + { + std::shared_ptr signal = signals_[i].lock(); + if(signal) + { + std::shared_ptr block = signalDirections_[i] ? blocks_.first.lock() : blocks_.second.lock(); + if(block && block->blocked()) + { + if(signal->getValue() != Signal::STOP) + { + std::weak_ptr signalWeak = signal; + QTimer::singleShot(500, signal.get(), [signalWeak](){BlockBorder::setSignal(signalWeak, Signal::STOP);}); + } + } + else + { + if(signal->getValue() != Signal::GO) + { + std::weak_ptr signalWeak = signal; + QTimer::singleShot(500, signal.get(), [signalWeak](){BlockBorder::setSignal(signalWeak, Signal::GO);}); + } + } + } + else + { + signals_.erase(signals_.begin()+i); + updateSignals(); + break; + } + } +} + +void BlockBorder::addSignal(std::weak_ptr signal, std::shared_ptr block) +{ + signals_.push_back(signal); + signalDirections_.push_back(block == blocks_.first.lock()); +} + +std::shared_ptr BlockBorder::getOtherBlock(Block* block) +{ + std::shared_ptr first = blocks_.first.lock(); + std::shared_ptr second = blocks_.second.lock(); + + if(first && first.get() == block) + return second; + if(second && second.get() == block) + return first; + return std::shared_ptr(); +} + +std::shared_ptr BlockBorder::getOverlap(BlockBorder* border) +{ + if(border->getBlocks().first.lock() == blocks_.first.lock() || border->getBlocks().first.lock() == blocks_.second.lock()) + { + return border->getBlocks().first.lock(); + } + else if(border->getBlocks().second.lock() == blocks_.first.lock() || border->getBlocks().second.lock() == blocks_.second.lock()) + { + return border->getBlocks().second.lock(); + } + return std::shared_ptr(); +} + +void BlockBorder::store(QJsonObject& json) +{ + json["Id"] = static_cast(id_); + json["Reader"] = static_cast(reader_); + QJsonArray signalArray; + for(size_t i = 0; i < signals_.size(); ++i) + { + std::shared_ptr signalPtr = signals_[i].lock(); + if(signalPtr) + { + QJsonObject signalObject; + signalObject["SignalId"] = static_cast(signalPtr->getSignalId()); + signalObject["Direction"] = static_cast(signalDirections_[i]); + signalArray.append(signalObject); + } + } + json["Signals"] = signalArray; +} + +void BlockBorder::load(const QJsonObject& json) +{ + id_ = static_cast(json["Id"].toDouble(0)); + reader_ = json["Reader"].toDouble(0); + const QJsonArray signalArray(json["Signals"].toArray(QJsonArray())); + for(const auto& arrayObj : signalArray) + { + if(arrayObj.isObject()) + { + signalIds_.push_back(std::pair(static_cast(json["SignalId"].toDouble(INT32_MAX)), static_cast(json["Direction"].toDouble(0)))); + } + } +} + +void BlockBorder::informOfSignal(std::shared_ptr signal) +{ + for(const std::pair& signalPair : signalIds_) + { + if(signalPair.first == signal->getSignalId()) + { + signals_.push_back(signal); + signalDirections_.push_back(signalPair.second); + } + } +} diff --git a/src/trainOverlord/blockborder.h b/src/trainOverlord/blockborder.h new file mode 100644 index 0000000..8c4bca2 --- /dev/null +++ b/src/trainOverlord/blockborder.h @@ -0,0 +1,38 @@ +#ifndef BLOCKBORDER_H +#define BLOCKBORDER_H +#include "trainsignal.h" +#include "block.h" +#include + +class Block; +class Layout; + +class BlockBorder +{ +private: + uint64_t reader_; + uint32_t id_; + std::vector> signalIds_; + std::vector> signals_; + std::vector signalDirections_; + std::pair, std::weak_ptr> blocks_; + + static void setSignal(std::weak_ptr signalWeak, int8_t value); + +public: + BlockBorder(uint8_t reader = 0, std::pair, std::weak_ptr> blocks = std::pair, std::weak_ptr>(), uint32_t id = QRandomGenerator::global()->generate()); + bool isReader(uint8_t reader); + uint8_t getReader(); + void updateSignals(); + std::shared_ptr getOtherBlock(Block* block); + std::pair, std::weak_ptr> getBlocks(){return blocks_;} + void setBlocks(std::pair, std::weak_ptr> blocks){blocks_ = blocks;} + void addSignal(std::weak_ptr signal, std::shared_ptr block); + void informOfSignal(std::shared_ptr signal); + std::shared_ptr getOverlap(BlockBorder* border); + uint32_t id() {return id_;} + void store(QJsonObject& json); + void load(const QJsonObject& json); +}; + +#endif // BLOCKBORDER_H diff --git a/src/trainOverlord/layout.cpp b/src/trainOverlord/layout.cpp new file mode 100644 index 0000000..39e32a9 --- /dev/null +++ b/src/trainOverlord/layout.cpp @@ -0,0 +1,221 @@ +#include "layout.h" +#include +#include + +Layout::Layout(QObject *parent): QObject{parent} +{ +} + +void Layout::itemAdded(std::weak_ptr itemIn) +{ + std::shared_ptr item = itemIn.lock(); + if(!item) + return; + std::shared_ptr train = std::dynamic_pointer_cast(item); + std::shared_ptr signal = std::dynamic_pointer_cast(item); +} + +void Layout::removeTrainFromAllBlocks(std::shared_ptr train) +{ + for(std::shared_ptr block : blocks_) + block->removeTrain(train); +} + +void Layout::registerTrainInLimbo(std::shared_ptr train, std::shared_ptr border) +{ + for(auto iter = trainLimbo_.begin(); iter != trainLimbo_.end(); ++iter) + { + std::shared_ptr limboTrain = iter->first.lock(); + std::shared_ptr limboBorder = iter->second.lock(); + if(!limboTrain || !limboBorder) + { + trainLimbo_.erase(iter); + registerTrainInLimbo(train, border); + return; + } + + if(*train == *limboTrain) + { + if(border == limboBorder) + return; + + std::shared_ptr overlap = border->getOverlap(limboBorder.get()); + if(overlap) + { + qDebug()<<"Train"<getTrainId()<<"removed from limbo and added to block"<id()<<"while crossing border"<id(); + overlap->addTrain(train); + overlap->trainArrivedAtBorder(border, train); + trainLimbo_.erase(iter); + return; + } + else + { + iter->second = border; + return; + } + + } + } + std::shared_ptr first = border->getBlocks().first.lock(); + std::shared_ptr second = border->getBlocks().second.lock(); + + qDebug()<<"Train"<getTrainId()<<"added to limbo between block"<< + (first ? QString::number(first->id()) : "invalid")<<"and block"<<(second ? QString::number(second->id()) : "invalid"); + trainLimbo_.push_back(std::pair, std::weak_ptr>(train, border)); +} + +void Layout::trainArrivedAtReader(uint8_t reader, std::shared_ptr train, int tagType) +{ + std::shared_ptr border; + for(std::shared_ptr borderTest : borders_) + { + if(borderTest->getReader() == reader) + { + border = borderTest; + break; + } + } + if(!border) + { + qWarning()<<"reader "<getTrainId()<<"arrived at border"<id(); + + bool trainHandled = false; + for(std::shared_ptr block : blocks_) + { + if(block->ownsTrain(train)) + { + trainHandled = true; + if(block->ownsBorder(border)) + { + block->trainArrivedAtBorder(border, train); + } + else + { + removeTrainFromAllBlocks(train); + registerTrainInLimbo(train, border); + } + break; + } + } + + if(!trainHandled) + registerTrainInLimbo(train, border); +} + +void Layout::addBlock(std::shared_ptr block) +{ + blocks_.push_back(block); +} + +void Layout::addBorder(std::shared_ptr border) +{ + borders_.push_back(border); +} + +std::shared_ptr Layout::getBorder(uint32_t id) +{ + for(const std::shared_ptr& border : borders_) + { + if(border->id() == id) + return border; + } + return std::shared_ptr(); +} + +std::shared_ptr Layout::getBlock(uint32_t id) +{ + for(const std::shared_ptr& block : blocks_) + { + if(block->id() == id) + return block; + } + return std::shared_ptr(); +} + +void Layout::store(QJsonObject& json) +{ + QJsonArray blockArray; + for(const std::shared_ptr& block : blocks_) + { + QJsonObject object; + block->store(object); + blockArray.append(object); + } + json["Blocks"] = blockArray; + + QJsonArray borderArray; + for(const std::shared_ptr& border : borders_) + { + QJsonObject object; + border->store(object); + borderArray.append(object); + } + json["Borders"] = borderArray; +} + +void Layout::load(const QJsonObject& json) +{ + std::vector blockJsonObjects; + const QJsonArray blockArray(json["Blocks"].toArray(QJsonArray())); + for(const auto& object : blockArray) + { + if(object.isObject()) + { + const QJsonObject jsonObject = object.toObject(); + blockJsonObjects.push_back(jsonObject); + std::shared_ptr block(new Block); + block->load(jsonObject); + blocks_.push_back(block); + } + } + + std::vector borderJsonObjects; + const QJsonArray borderArray(json["Borders"].toArray(QJsonArray())); + for(const auto& object : borderArray) + { + if(object.isObject()) + { + const QJsonObject jsonObject = object.toObject(); + borderJsonObjects.push_back(jsonObject); + std::shared_ptr border(new BlockBorder); + border->load(object.toObject()); + borders_.push_back(border); + } + } + + for(size_t i = 0; i < blocks_.size(); ++i) + { + blocks_[i]->populate(blockJsonObjects[i], this); + } + + for(std::shared_ptr& border : borders_) + { + std::shared_ptr first; + std::shared_ptr second; + for(std::shared_ptr& block : blocks_) + { + if(block->ownsBorder(border)) + { + if(!first) + first = block; + else if(!second) + second = block; + else if(!second) + qWarning()<<"border with id"<id()<<"is assigned to more than 2 blocks"; + } + } + if(!first || !second) + qWarning()<<"border with id"<id()<<"is assigned to less than than 2 blocks"; + border->setBlocks(std::pair, std::weak_ptr>(first, second)); + } + + for(size_t i = 0; i < blocks_.size(); ++i) + { + blocks_[i]->populate(blockJsonObjects[i], this); + if(blocks_[i]->getBorders().empty()) + qWarning()<<"block with id"<id()<<"doset have at least one border"; + } +} diff --git a/src/trainOverlord/layout.h b/src/trainOverlord/layout.h new file mode 100644 index 0000000..fcb8ab3 --- /dev/null +++ b/src/trainOverlord/layout.h @@ -0,0 +1,43 @@ +#ifndef BLOCKSTORE_H +#define BLOCKSTORE_H + +#include +#include +#include + +#include "block.h" +#include "blockborder.h" +#include "microcontroller.h" +#include "itemstore.h" + +class Layout : public QObject +{ + Q_OBJECT +private: + +private: + std::vector> blocks_; + std::vector> borders_; + std::vector, std::weak_ptr>> trainLimbo_; + + void removeTrainFromAllBlocks(std::shared_ptr train); + void registerTrainInLimbo(std::shared_ptr train, std::shared_ptr); + +public: + explicit Layout(QObject *parent = nullptr); + void addBlock(std::shared_ptr block); + void addBorder(std::shared_ptr border); + void store(QJsonObject& json); + void load(const QJsonObject& json); + std::shared_ptr getBorder(uint32_t id); + std::shared_ptr getBlock(uint32_t id); + +public slots: + void trainArrivedAtReader(uint8_t reader, std::shared_ptr train, int tagType); + void itemAdded(std::weak_ptr item); + +signals: + void trainArrivedAtBorder(std::weak_ptr, std::weak_ptr train, int tagType); +}; + +#endif // BLOCKSTORE_H diff --git a/src/trainOverlord/overlorditemstore.cpp b/src/trainOverlord/overlorditemstore.cpp index f367f5b..9222d9a 100644 --- a/src/trainOverlord/overlorditemstore.cpp +++ b/src/trainOverlord/overlorditemstore.cpp @@ -10,17 +10,15 @@ void OverlordItemStore::gotNfcTag(NfcUid uid) { for(std::shared_ptr item : items_) { - Train* train = dynamic_cast(item.get()); + std::shared_ptr train = std::dynamic_pointer_cast(item); if(!train) continue; - for(const NfcUid& trainUid : train->tags) + int owns = train->ownsTag(uid); + if(owns == Train::TAG_FRONT || owns == Train::TAG_BACK) { - if(trainUid == uid) - { - if(train->passedReader(uid)) - train->setValue(0-train->getValue()); - return; - } + qDebug()<<"Train"<getTrainId()<<"arrived at reader"< +#include "train.h" class OverlordItemStore: public ItemStore { Q_OBJECT -private: - QTimer timer; public: OverlordItemStore(QObject *parent = nullptr); public slots: - void gotNfcTag(NfcUid); + +signals: + void trainArrivedAtReader(uint8_t reader, std::shared_ptr train, int tagType); }; diff --git a/src/trainOverlord/trainoverlord.cpp b/src/trainOverlord/trainoverlord.cpp index 1dc590d..eee419a 100644 --- a/src/trainOverlord/trainoverlord.cpp +++ b/src/trainOverlord/trainoverlord.cpp @@ -3,20 +3,87 @@ #include #include #include +#include +#include +#include +#include +#include +#include #include "microcontroller.h" #include "nfcuid.h" #include "overlorditemstore.h" #include "train.h" #include "turnout.h" -#include "signal.h" +#include "layout.h" -void gotTag(NfcUid uid) +void sigHandler(int sig) { - std::cout<<"Got tag from "< 0) + file.setFileName(filePath); + else + file.setFileName(QStandardPaths::writableLocation(QStandardPaths::ConfigLocation) + "/trainoverloard.json"); + + file.open(QIODevice::ReadOnly); + if(!file.isOpen()) { - std::cout<<(int)uid.bytes[i]<<(i == uid.length-1 ? "" : ":"); + std::cerr<<"Can not open config file: "<getItems()->empty()) + { + micro->requestState(); + timer->start(1000); } } @@ -24,6 +91,8 @@ int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); + signal(SIGINT, &sigHandler); + //set info QCoreApplication::setOrganizationName("UVOS"); QCoreApplication::setOrganizationDomain("uvos.xyz"); @@ -60,9 +129,12 @@ int main(int argc, char *argv[]) } OverlordItemStore items; + Layout layout; + + QObject::connect(&items, &OverlordItemStore::itemAdded, &layout, &Layout::itemAdded); + QObject::connect(&items, &OverlordItemStore::trainArrivedAtReader, &layout, &Layout::trainArrivedAtReader); Microcontroller micro(µSocket); - QObject::connect(µ, &Microcontroller::gotTag, gotTag); QObject::connect(µ, &Microcontroller::gotTag, &items, &OverlordItemStore::gotNfcTag); QObject::connect(µ, &Microcontroller::gotItemList, &items, &OverlordItemStore::addItems); QObject::connect(µ, &Microcontroller::itemChanged, &items, &OverlordItemStore::itemStateChanged); @@ -71,5 +143,27 @@ int main(int argc, char *argv[]) Turnout::micro = µ Signal::micro = µ - return a.exec(); + QTimer timer; + timer.setSingleShot(false); + QObject::connect(&timer, &QTimer::timeout, &timer, [µ, &timer, &items](){getItemsCb(&timer, &items, µ);}); + getItemsCb(&timer, &items, µ); + + { + bool err = false; + QJsonObject json = getJsonObjectFromDisk(QString(), &err); + if(err) + { + std::cerr<<"Could not load config file\n"; + return -1; + } + layout.load(json); + } + + int ret = a.exec(); + /* + QJsonObject jsonStore; + layout.store(jsonStore); + storeJsonObjectToDisk(jsonStore); + */ + return ret; }