Intal version with working trainoverlord
This commit is contained in:
@ -12,11 +12,17 @@ find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Widgets Network SerialPort REQUIRE
|
|||||||
|
|
||||||
set(COMMON_SOURCES
|
set(COMMON_SOURCES
|
||||||
../common/microcontroller.cpp
|
../common/microcontroller.cpp
|
||||||
|
../common/microcontroller.h
|
||||||
../common/items/item.cpp
|
../common/items/item.cpp
|
||||||
|
../common/items/item.h
|
||||||
../common/items/itemstore.cpp
|
../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.cpp
|
||||||
|
../common/items/train.h
|
||||||
../common/items/turnout.cpp
|
../common/items/turnout.cpp
|
||||||
|
../common/items/turnout.h
|
||||||
)
|
)
|
||||||
|
|
||||||
include_directories(PRIVATE
|
include_directories(PRIVATE
|
||||||
@ -32,3 +38,4 @@ set(COMMON_LINK_LIBRARYS
|
|||||||
|
|
||||||
add_subdirectory(trainControllerUI)
|
add_subdirectory(trainControllerUI)
|
||||||
add_subdirectory(trainOverlord)
|
add_subdirectory(trainOverlord)
|
||||||
|
|
||||||
|
@ -59,7 +59,7 @@ public:
|
|||||||
|
|
||||||
virtual ~Item();
|
virtual ~Item();
|
||||||
|
|
||||||
void informValue(int8_t value);
|
virtual void informValue(int8_t value);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -22,7 +22,6 @@ void ItemStore::addItem(std::shared_ptr<Item> item)
|
|||||||
items_.push_back(std::shared_ptr<Item>(item));
|
items_.push_back(std::shared_ptr<Item>(item));
|
||||||
itemAdded(std::weak_ptr<Item>(items_.back()));
|
itemAdded(std::weak_ptr<Item>(items_.back()));
|
||||||
}
|
}
|
||||||
qDebug()<<"Got item: "<<item->id()<<" matched: "<<mached;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ItemStore::addItems(const std::vector<std::shared_ptr<Item>>& itemIn)
|
void ItemStore::addItems(const std::vector<std::shared_ptr<Item>>& itemIn)
|
||||||
@ -35,7 +34,7 @@ void ItemStore::addItems(const std::vector<std::shared_ptr<Item>>& itemIn)
|
|||||||
continue;
|
continue;
|
||||||
if(train->getTrainId() == 0)
|
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)));
|
train->tags.push_back(NfcUid(uidBytes, sizeof(uidBytes)));
|
||||||
}
|
}
|
||||||
else if(train->getTrainId() == 3)
|
else if(train->getTrainId() == 3)
|
||||||
@ -45,7 +44,7 @@ void ItemStore::addItems(const std::vector<std::shared_ptr<Item>>& itemIn)
|
|||||||
}
|
}
|
||||||
else if(train->getTrainId() == 4)
|
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)));
|
train->tags.push_back(NfcUid(uidBytes, sizeof(uidBytes)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -30,7 +30,7 @@ signals:
|
|||||||
public slots:
|
public slots:
|
||||||
|
|
||||||
void removeItem(const ItemData& item);
|
void removeItem(const ItemData& item);
|
||||||
void addItem(std::shared_ptr<Item> item);
|
virtual void addItem(std::shared_ptr<Item> item);
|
||||||
void addItems(const std::vector<std::shared_ptr<Item>>& itemsIn);
|
void addItems(const std::vector<std::shared_ptr<Item>>& itemsIn);
|
||||||
void itemStateChanged(const ItemData& item);
|
void itemStateChanged(const ItemData& item);
|
||||||
};
|
};
|
||||||
|
@ -19,13 +19,82 @@ void Train::setFunction(uint8_t funciton, bool value)
|
|||||||
void Train::setValue(int8_t value)
|
void Train::setValue(int8_t value)
|
||||||
{
|
{
|
||||||
Item::setValue(value);
|
Item::setValue(value);
|
||||||
|
if(suspended_ && value != 0)
|
||||||
|
{
|
||||||
|
suspended_ = false;
|
||||||
|
unsuspended(id(), getDirection());
|
||||||
|
}
|
||||||
if(micro)
|
if(micro)
|
||||||
micro->trainSetSpeed(train_id_, value);
|
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()
|
void Train::reverse()
|
||||||
{
|
{
|
||||||
if(micro)
|
if(micro)
|
||||||
micro->trainReverse(train_id_);
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -12,7 +12,16 @@ class Train : public Item
|
|||||||
uint8_t functionMask_;
|
uint8_t functionMask_;
|
||||||
uint8_t train_id_;
|
uint8_t train_id_;
|
||||||
int lastReader_ = -1;
|
int lastReader_ = -1;
|
||||||
|
int8_t suspendedSpeed_;
|
||||||
|
bool suspended_ = false;
|
||||||
public:
|
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;
|
static Microcontroller *micro;
|
||||||
std::vector<NfcUid> tags;
|
std::vector<NfcUid> tags;
|
||||||
|
|
||||||
@ -27,6 +36,13 @@ public slots:
|
|||||||
void reverse();
|
void reverse();
|
||||||
virtual void setFunction(uint8_t function, bool on);
|
virtual void setFunction(uint8_t function, bool on);
|
||||||
virtual void setValue(int8_t value);
|
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)
|
bool passedReader(const NfcUid &uid)
|
||||||
{
|
{
|
||||||
if(lastReader_ == uid.reader)
|
if(lastReader_ == uid.reader)
|
||||||
@ -38,6 +54,9 @@ public slots:
|
|||||||
{
|
{
|
||||||
return train_id_;
|
return train_id_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void unsuspended(uint32_t id, int direction);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // TRAIN_H
|
#endif // TRAIN_H
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
#include "signal.h"
|
#include "trainsignal.h"
|
||||||
|
|
||||||
Microcontroller *Signal::micro = nullptr;
|
Microcontroller *Signal::micro = nullptr;
|
||||||
|
|
@ -2,13 +2,12 @@
|
|||||||
|
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
#include "items/train.h"
|
#include "train.h"
|
||||||
#include "items/turnout.h"
|
#include "turnout.h"
|
||||||
#include "items/signal.h"
|
#include "trainsignal.h"
|
||||||
|
|
||||||
void Microcontroller::trainSetSpeed(uint8_t id, int8_t speed)
|
void Microcontroller::trainSetSpeed(uint8_t id, int8_t speed)
|
||||||
{
|
{
|
||||||
qDebug()<<__func__;
|
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
ss<<"train "<<(unsigned)id<<" speed "<<(int)speed<<'\n';
|
ss<<"train "<<(unsigned)id<<" speed "<<(int)speed<<'\n';
|
||||||
write(ss.str().c_str());
|
write(ss.str().c_str());
|
||||||
@ -54,18 +53,16 @@ void Microcontroller::estop()
|
|||||||
|
|
||||||
void Microcontroller::write(const QByteArray& buffer)
|
void Microcontroller::write(const QByteArray& buffer)
|
||||||
{
|
{
|
||||||
qDebug()<<buffer;
|
|
||||||
if(_port != nullptr)
|
if(_port != nullptr)
|
||||||
{
|
{
|
||||||
_port->write(buffer);
|
_port->write(buffer);
|
||||||
_port->waitForBytesWritten(1000);
|
//_port->waitForBytesWritten(1000);
|
||||||
}
|
}
|
||||||
std::this_thread::sleep_for(std::chrono::milliseconds(40));
|
std::this_thread::sleep_for(std::chrono::milliseconds(40));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Microcontroller::write(char* buffer, const size_t length)
|
void Microcontroller::write(char* buffer, const size_t length)
|
||||||
{
|
{
|
||||||
qDebug()<<buffer;
|
|
||||||
if(_port != nullptr)
|
if(_port != nullptr)
|
||||||
{
|
{
|
||||||
_port->write(buffer, length);
|
_port->write(buffer, length);
|
||||||
@ -86,6 +83,7 @@ void Microcontroller::requestState()
|
|||||||
write("train list\n");
|
write("train list\n");
|
||||||
write("turnout list\n");
|
write("turnout list\n");
|
||||||
write("signal list\n");
|
write("signal list\n");
|
||||||
|
write("nfc list\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
//housekeeping
|
//housekeeping
|
||||||
@ -154,14 +152,12 @@ void Microcontroller::processNfcLine(const QString& buffer)
|
|||||||
uid.length = tokens.length();
|
uid.length = tokens.length();
|
||||||
for(size_t i = 0; i < uid.length; ++i)
|
for(size_t i = 0; i < uid.length; ++i)
|
||||||
uid.bytes[i] = tokens[i].toInt();
|
uid.bytes[i] = tokens[i].toInt();
|
||||||
qDebug()<<"Got Tag";
|
|
||||||
gotTag(uid);
|
gotTag(uid);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Microcontroller::processList(const QString& buffer)
|
void Microcontroller::processList(const QString& buffer)
|
||||||
{
|
{
|
||||||
QStringList bufferList = buffer.split(' ');
|
QStringList bufferList = buffer.split(' ');
|
||||||
qDebug()<<__func__<<" :"<<buffer<<" list mode: "<<listMode;
|
|
||||||
if(bufferList.size() >= 10 && buffer.contains("NUMBER:"))
|
if(bufferList.size() >= 10 && buffer.contains("NUMBER:"))
|
||||||
{
|
{
|
||||||
std::shared_ptr<Item> item;
|
std::shared_ptr<Item> item;
|
||||||
@ -179,7 +175,6 @@ void Microcontroller::processList(const QString& buffer)
|
|||||||
listMode = false;
|
listMode = false;
|
||||||
if(!itemList.empty())
|
if(!itemList.empty())
|
||||||
{
|
{
|
||||||
qDebug()<<"got item list " << itemList.size();
|
|
||||||
gotItemList(itemList);
|
gotItemList(itemList);
|
||||||
itemList.clear();
|
itemList.clear();
|
||||||
}
|
}
|
||||||
|
@ -10,10 +10,10 @@
|
|||||||
#include "microcontroller.h"
|
#include "microcontroller.h"
|
||||||
#include "trainjs.h"
|
#include "trainjs.h"
|
||||||
#include "ui/mainwindow.h"
|
#include "ui/mainwindow.h"
|
||||||
#include "items/itemstore.h"
|
#include "itemstore.h"
|
||||||
#include "items/train.h"
|
#include "train.h"
|
||||||
#include "items/turnout.h"
|
#include "turnout.h"
|
||||||
#include "items/signal.h"
|
#include "trainsignal.h"
|
||||||
|
|
||||||
#define BAUD QSerialPort::Baud38400
|
#define BAUD QSerialPort::Baud38400
|
||||||
|
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
#include "itemscrollbox.h"
|
#include "itemscrollbox.h"
|
||||||
#include "ui_relayscrollbox.h"
|
#include "ui_relayscrollbox.h"
|
||||||
#include "ui_relayscrollbox.h"
|
#include "ui_relayscrollbox.h"
|
||||||
#include "../items/train.h"
|
#include "train.h"
|
||||||
#include "../items/turnout.h"
|
#include "turnout.h"
|
||||||
#include "../items/signal.h"
|
#include "trainsignal.h"
|
||||||
#include "../trainjs.h"
|
#include "trainjs.h"
|
||||||
#include "trainwidget.h"
|
#include "trainwidget.h"
|
||||||
#include "signalwidget.h"
|
#include "signalwidget.h"
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <QRadioButton>
|
#include <QRadioButton>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include "../items/signal.h"
|
#include "trainsignal.h"
|
||||||
|
|
||||||
SignalWidget::SignalWidget(std::weak_ptr<Item> item, QWidget *parent) :
|
SignalWidget::SignalWidget(std::weak_ptr<Item> item, QWidget *parent) :
|
||||||
ItemWidget(item, parent),
|
ItemWidget(item, parent),
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <QShortcut>
|
#include <QShortcut>
|
||||||
#include "../items/signal.h"
|
#include "../items/trainsignal.h"
|
||||||
#include "itemwidget.h"
|
#include "itemwidget.h"
|
||||||
|
|
||||||
namespace Ui
|
namespace Ui
|
||||||
|
@ -1,6 +1,13 @@
|
|||||||
set(UI_SOURCES
|
set(UI_SOURCES
|
||||||
trainoverlord.cpp
|
trainoverlord.cpp
|
||||||
overlorditemstore.cpp
|
overlorditemstore.cpp
|
||||||
|
overlorditemstore.h
|
||||||
|
blockborder.cpp
|
||||||
|
blockborder.h
|
||||||
|
block.cpp
|
||||||
|
block.h
|
||||||
|
layout.h
|
||||||
|
layout.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
add_executable(trainoverlord ${UI_SOURCES} ${COMMON_SOURCES})
|
add_executable(trainoverlord ${UI_SOURCES} ${COMMON_SOURCES})
|
||||||
|
254
src/trainOverlord/block.cpp
Normal file
254
src/trainOverlord/block.cpp
Normal file
@ -0,0 +1,254 @@
|
|||||||
|
#include "block.h"
|
||||||
|
#include <QJsonArray>
|
||||||
|
#include <layout.h>
|
||||||
|
|
||||||
|
Block::Block(uint32_t id):
|
||||||
|
id_(id)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void Block::addBorder(std::shared_ptr<BlockBorder> border)
|
||||||
|
{
|
||||||
|
borders_.push_back(border);
|
||||||
|
std::shared_ptr<Block> block = border->getOtherBlock(this);
|
||||||
|
if(!block || block.get() == this)
|
||||||
|
{
|
||||||
|
qWarning()<<__func__<<"no other block in border"<<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> train)
|
||||||
|
{
|
||||||
|
std::shared_ptr<Train> 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<BlockBorder> border)
|
||||||
|
{
|
||||||
|
if(!border)
|
||||||
|
return false;
|
||||||
|
for(std::shared_ptr<BlockBorder> borderTest : borders_)
|
||||||
|
{
|
||||||
|
if(borderTest == border)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Block::checkWaits(bool ign)
|
||||||
|
{
|
||||||
|
qDebug()<<__func__;
|
||||||
|
(void)ign;
|
||||||
|
bool wasBlocked = blocked();
|
||||||
|
for(std::vector<TrainWait>::iterator iter = waits_.begin(); iter != waits_.end();)
|
||||||
|
{
|
||||||
|
std::shared_ptr<Block> block = iter->targetBlock.lock();
|
||||||
|
std::shared_ptr<Train> train = iter->train.lock();
|
||||||
|
qDebug()<<__func__<<"trying to push train"<<train->getTrainId()<<"to block"<<block->id();
|
||||||
|
if(block && train && train->suspendend() && block->pushTrain(iter->train))
|
||||||
|
{
|
||||||
|
train->resume();
|
||||||
|
std::shared_ptr<BlockBorder> 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<BlockBorder> broder : borders_)
|
||||||
|
{
|
||||||
|
broder->updateSignals();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Block::pushTrain(std::weak_ptr<Train> train)
|
||||||
|
{
|
||||||
|
if(blocked())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
addTrain(train);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Block::addTrain(std::weak_ptr<Train> train)
|
||||||
|
{
|
||||||
|
std::shared_ptr<Train> trainPtr = train.lock();
|
||||||
|
if(!trainPtr)
|
||||||
|
return;
|
||||||
|
qDebug()<<"Train"<<trainPtr->getTrainId()<<"added to block"<<id_;
|
||||||
|
bool wasBlocked = blocked();
|
||||||
|
trains_.push_back(train);
|
||||||
|
if(wasBlocked != blocked())
|
||||||
|
blockedChanged(!wasBlocked);
|
||||||
|
updateBorders();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Block::unsuspendedTrain(uint32_t id, int direction)
|
||||||
|
{
|
||||||
|
qDebug()<<"Train with item id"<<id<<"reports unsuspended";
|
||||||
|
bool wasBlocked = blocked();
|
||||||
|
for(std::vector<TrainWait>::iterator iter = waits_.begin(); iter != waits_.end(); ++iter)
|
||||||
|
{
|
||||||
|
std::shared_ptr<Train> workTrain = iter->train.lock();
|
||||||
|
if(!workTrain)
|
||||||
|
{
|
||||||
|
waits_.erase(iter);
|
||||||
|
unsuspendedTrain(id, direction);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if(workTrain->id() == id)
|
||||||
|
{
|
||||||
|
std::shared_ptr<Block> 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> train)
|
||||||
|
{
|
||||||
|
std::shared_ptr<Train> trainPtr = train.lock();
|
||||||
|
if(!trainPtr)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for(std::vector<std::weak_ptr<Train>>::iterator iter = trains_.begin(); iter != trains_.end(); ++iter)
|
||||||
|
{
|
||||||
|
if(iter->lock() == trainPtr)
|
||||||
|
{
|
||||||
|
qDebug()<<"Train"<<trainPtr->getTrainId()<<"removed from to block"<<id_;
|
||||||
|
trains_.erase(iter);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Block::trainArrivedAtBorder(std::weak_ptr<BlockBorder> borderIn, std::weak_ptr<Train> trainIn)
|
||||||
|
{
|
||||||
|
qDebug()<<__func__<<"block"<<id();
|
||||||
|
bool wasBlocked = blocked();
|
||||||
|
std::shared_ptr<BlockBorder> border = borderIn.lock();
|
||||||
|
if(!border)
|
||||||
|
{
|
||||||
|
qWarning()<<"border has expired in"<<__func__;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!ownsBorder(border))
|
||||||
|
return;
|
||||||
|
|
||||||
|
qDebug()<<"Block"<<id_<<"owns subject border";
|
||||||
|
|
||||||
|
if(!ownsTrain(trainIn))
|
||||||
|
return;
|
||||||
|
|
||||||
|
qDebug()<<"Block"<<id_<<"owns subject train";
|
||||||
|
|
||||||
|
std::shared_ptr block = border->getOtherBlock(this);
|
||||||
|
if(block)
|
||||||
|
{
|
||||||
|
std::shared_ptr<Train> 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"<<workTrain->getTrainId()<<"is wating at border for block"<<block->id();
|
||||||
|
if(!block->trains_.empty() && block->trains_[0].lock())
|
||||||
|
qDebug()<<"for train"<<block->trains_[0].lock()->getTrainId()<<"to leave";
|
||||||
|
}
|
||||||
|
removeTrain(workTrain);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(wasBlocked != blocked())
|
||||||
|
blockedChanged(blocked());
|
||||||
|
updateBorders();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Block::store(QJsonObject &json)
|
||||||
|
{
|
||||||
|
json["Id"] = static_cast<double>(id_);
|
||||||
|
QJsonArray borders;
|
||||||
|
for(auto& border : borders_)
|
||||||
|
{
|
||||||
|
QJsonObject borderObject;
|
||||||
|
borderObject["BorderId"] = static_cast<double>(border->id());
|
||||||
|
borders.append(borderObject);
|
||||||
|
}
|
||||||
|
json["Borders"] = borders;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Block::load(const QJsonObject &json)
|
||||||
|
{
|
||||||
|
id_ = static_cast<uint32_t>(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<uint32_t>(arrayObj.toObject()["BorderId"].toDouble(INT32_MAX));
|
||||||
|
std::shared_ptr<BlockBorder> border = layout->getBorder(borderId);
|
||||||
|
if(border)
|
||||||
|
addBorder(border);
|
||||||
|
else if(borderId == INT32_MAX)
|
||||||
|
qWarning()<<"BorderId field is missing in border array for block"<<id_;
|
||||||
|
else
|
||||||
|
qWarning()<<"border"<<borderId<<"dosent exist but is needed by block"<<id_;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
65
src/trainOverlord/block.h
Normal file
65
src/trainOverlord/block.h
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
#ifndef BLOCK_H
|
||||||
|
#define BLOCK_H
|
||||||
|
#include <vector>
|
||||||
|
#include <memory>
|
||||||
|
#include <QObject>
|
||||||
|
#include <QRandomGenerator>
|
||||||
|
#include <QJsonObject>
|
||||||
|
#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> train;
|
||||||
|
std::weak_ptr<Block> targetBlock;
|
||||||
|
std::weak_ptr<BlockBorder> border;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::vector< std::shared_ptr<BlockBorder> > borders_;
|
||||||
|
std::vector< std::weak_ptr<Train> > trains_;
|
||||||
|
std::vector<TrainWait> 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<BlockBorder> border);
|
||||||
|
bool blocked();
|
||||||
|
bool ownsTrain(std::weak_ptr<Train> train);
|
||||||
|
bool ownsBorder(std::shared_ptr<BlockBorder> border);
|
||||||
|
std::vector< std::shared_ptr<BlockBorder> > getBorders(){return borders_;}
|
||||||
|
uint32_t id(){return id_;}
|
||||||
|
void removeTrain(std::weak_ptr<Train> 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> train);
|
||||||
|
void addTrain(std::weak_ptr<Train> train);
|
||||||
|
void trainArrivedAtBorder(std::weak_ptr<BlockBorder> border, std::weak_ptr<Train> train);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void blockedChanged(bool blocked);
|
||||||
|
void trainAddedToBlock(int blockId, std::weak_ptr<Train> train);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // BLOCK_H
|
137
src/trainOverlord/blockborder.cpp
Normal file
137
src/trainOverlord/blockborder.cpp
Normal file
@ -0,0 +1,137 @@
|
|||||||
|
#include "blockborder.h"
|
||||||
|
#include <QJsonArray>
|
||||||
|
#include <layout.h>
|
||||||
|
|
||||||
|
BlockBorder::BlockBorder(uint8_t reader, std::pair<std::weak_ptr<Block>, std::weak_ptr<Block>> 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<Signal> signalWeak, int8_t value)
|
||||||
|
{
|
||||||
|
std::shared_ptr<Signal> signal = signalWeak.lock();
|
||||||
|
if(signal)
|
||||||
|
{
|
||||||
|
signal->setValue(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void BlockBorder::updateSignals()
|
||||||
|
{
|
||||||
|
for(size_t i = 0; i < signals_.size(); ++i)
|
||||||
|
{
|
||||||
|
std::shared_ptr<Signal> signal = signals_[i].lock();
|
||||||
|
if(signal)
|
||||||
|
{
|
||||||
|
std::shared_ptr<Block> block = signalDirections_[i] ? blocks_.first.lock() : blocks_.second.lock();
|
||||||
|
if(block && block->blocked())
|
||||||
|
{
|
||||||
|
if(signal->getValue() != Signal::STOP)
|
||||||
|
{
|
||||||
|
std::weak_ptr<Signal> signalWeak = signal;
|
||||||
|
QTimer::singleShot(500, signal.get(), [signalWeak](){BlockBorder::setSignal(signalWeak, Signal::STOP);});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(signal->getValue() != Signal::GO)
|
||||||
|
{
|
||||||
|
std::weak_ptr<Signal> 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> signal, std::shared_ptr<Block> block)
|
||||||
|
{
|
||||||
|
signals_.push_back(signal);
|
||||||
|
signalDirections_.push_back(block == blocks_.first.lock());
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<Block> BlockBorder::getOtherBlock(Block* block)
|
||||||
|
{
|
||||||
|
std::shared_ptr<Block> first = blocks_.first.lock();
|
||||||
|
std::shared_ptr<Block> second = blocks_.second.lock();
|
||||||
|
|
||||||
|
if(first && first.get() == block)
|
||||||
|
return second;
|
||||||
|
if(second && second.get() == block)
|
||||||
|
return first;
|
||||||
|
return std::shared_ptr<Block>();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<Block> 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<Block>();
|
||||||
|
}
|
||||||
|
|
||||||
|
void BlockBorder::store(QJsonObject& json)
|
||||||
|
{
|
||||||
|
json["Id"] = static_cast<double>(id_);
|
||||||
|
json["Reader"] = static_cast<double>(reader_);
|
||||||
|
QJsonArray signalArray;
|
||||||
|
for(size_t i = 0; i < signals_.size(); ++i)
|
||||||
|
{
|
||||||
|
std::shared_ptr<Signal> signalPtr = signals_[i].lock();
|
||||||
|
if(signalPtr)
|
||||||
|
{
|
||||||
|
QJsonObject signalObject;
|
||||||
|
signalObject["SignalId"] = static_cast<double>(signalPtr->getSignalId());
|
||||||
|
signalObject["Direction"] = static_cast<double>(signalDirections_[i]);
|
||||||
|
signalArray.append(signalObject);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
json["Signals"] = signalArray;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BlockBorder::load(const QJsonObject& json)
|
||||||
|
{
|
||||||
|
id_ = static_cast<uint32_t>(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<uint32_t, bool>(static_cast<uint32_t>(json["SignalId"].toDouble(INT32_MAX)), static_cast<bool>(json["Direction"].toDouble(0))));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void BlockBorder::informOfSignal(std::shared_ptr<Signal> signal)
|
||||||
|
{
|
||||||
|
for(const std::pair<uint32_t, bool>& signalPair : signalIds_)
|
||||||
|
{
|
||||||
|
if(signalPair.first == signal->getSignalId())
|
||||||
|
{
|
||||||
|
signals_.push_back(signal);
|
||||||
|
signalDirections_.push_back(signalPair.second);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
38
src/trainOverlord/blockborder.h
Normal file
38
src/trainOverlord/blockborder.h
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
#ifndef BLOCKBORDER_H
|
||||||
|
#define BLOCKBORDER_H
|
||||||
|
#include "trainsignal.h"
|
||||||
|
#include "block.h"
|
||||||
|
#include <QJsonObject>
|
||||||
|
|
||||||
|
class Block;
|
||||||
|
class Layout;
|
||||||
|
|
||||||
|
class BlockBorder
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
uint64_t reader_;
|
||||||
|
uint32_t id_;
|
||||||
|
std::vector<std::pair<uint32_t, bool>> signalIds_;
|
||||||
|
std::vector<std::weak_ptr<Signal>> signals_;
|
||||||
|
std::vector<bool> signalDirections_;
|
||||||
|
std::pair<std::weak_ptr<Block>, std::weak_ptr<Block>> blocks_;
|
||||||
|
|
||||||
|
static void setSignal(std::weak_ptr<Signal> signalWeak, int8_t value);
|
||||||
|
|
||||||
|
public:
|
||||||
|
BlockBorder(uint8_t reader = 0, std::pair<std::weak_ptr<Block>, std::weak_ptr<Block>> blocks = std::pair<std::weak_ptr<Block>, std::weak_ptr<Block>>(), uint32_t id = QRandomGenerator::global()->generate());
|
||||||
|
bool isReader(uint8_t reader);
|
||||||
|
uint8_t getReader();
|
||||||
|
void updateSignals();
|
||||||
|
std::shared_ptr<Block> getOtherBlock(Block* block);
|
||||||
|
std::pair<std::weak_ptr<Block>, std::weak_ptr<Block>> getBlocks(){return blocks_;}
|
||||||
|
void setBlocks(std::pair<std::weak_ptr<Block>, std::weak_ptr<Block>> blocks){blocks_ = blocks;}
|
||||||
|
void addSignal(std::weak_ptr<Signal> signal, std::shared_ptr<Block> block);
|
||||||
|
void informOfSignal(std::shared_ptr<Signal> signal);
|
||||||
|
std::shared_ptr<Block> getOverlap(BlockBorder* border);
|
||||||
|
uint32_t id() {return id_;}
|
||||||
|
void store(QJsonObject& json);
|
||||||
|
void load(const QJsonObject& json);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // BLOCKBORDER_H
|
221
src/trainOverlord/layout.cpp
Normal file
221
src/trainOverlord/layout.cpp
Normal file
@ -0,0 +1,221 @@
|
|||||||
|
#include "layout.h"
|
||||||
|
#include <memory>
|
||||||
|
#include <QJsonArray>
|
||||||
|
|
||||||
|
Layout::Layout(QObject *parent): QObject{parent}
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void Layout::itemAdded(std::weak_ptr<Item> itemIn)
|
||||||
|
{
|
||||||
|
std::shared_ptr<Item> item = itemIn.lock();
|
||||||
|
if(!item)
|
||||||
|
return;
|
||||||
|
std::shared_ptr<Train> train = std::dynamic_pointer_cast<Train>(item);
|
||||||
|
std::shared_ptr<Signal> signal = std::dynamic_pointer_cast<Signal>(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Layout::removeTrainFromAllBlocks(std::shared_ptr<Train> train)
|
||||||
|
{
|
||||||
|
for(std::shared_ptr<Block> block : blocks_)
|
||||||
|
block->removeTrain(train);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Layout::registerTrainInLimbo(std::shared_ptr<Train> train, std::shared_ptr<BlockBorder> border)
|
||||||
|
{
|
||||||
|
for(auto iter = trainLimbo_.begin(); iter != trainLimbo_.end(); ++iter)
|
||||||
|
{
|
||||||
|
std::shared_ptr<Train> limboTrain = iter->first.lock();
|
||||||
|
std::shared_ptr<BlockBorder> limboBorder = iter->second.lock();
|
||||||
|
if(!limboTrain || !limboBorder)
|
||||||
|
{
|
||||||
|
trainLimbo_.erase(iter);
|
||||||
|
registerTrainInLimbo(train, border);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(*train == *limboTrain)
|
||||||
|
{
|
||||||
|
if(border == limboBorder)
|
||||||
|
return;
|
||||||
|
|
||||||
|
std::shared_ptr<Block> overlap = border->getOverlap(limboBorder.get());
|
||||||
|
if(overlap)
|
||||||
|
{
|
||||||
|
qDebug()<<"Train"<<train->getTrainId()<<"removed from limbo and added to block"<<overlap->id()<<"while crossing border"<<border->id();
|
||||||
|
overlap->addTrain(train);
|
||||||
|
overlap->trainArrivedAtBorder(border, train);
|
||||||
|
trainLimbo_.erase(iter);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
iter->second = border;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
std::shared_ptr<Block> first = border->getBlocks().first.lock();
|
||||||
|
std::shared_ptr<Block> second = border->getBlocks().second.lock();
|
||||||
|
|
||||||
|
qDebug()<<"Train"<<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>, std::weak_ptr<BlockBorder>>(train, border));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Layout::trainArrivedAtReader(uint8_t reader, std::shared_ptr<Train> train, int tagType)
|
||||||
|
{
|
||||||
|
std::shared_ptr<BlockBorder> border;
|
||||||
|
for(std::shared_ptr<BlockBorder> borderTest : borders_)
|
||||||
|
{
|
||||||
|
if(borderTest->getReader() == reader)
|
||||||
|
{
|
||||||
|
border = borderTest;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(!border)
|
||||||
|
{
|
||||||
|
qWarning()<<"reader "<<reader<<"is not registerd with any border";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
qDebug()<<"Train"<<train->getTrainId()<<"arrived at border"<<border->id();
|
||||||
|
|
||||||
|
bool trainHandled = false;
|
||||||
|
for(std::shared_ptr<Block> 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> block)
|
||||||
|
{
|
||||||
|
blocks_.push_back(block);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Layout::addBorder(std::shared_ptr<BlockBorder> border)
|
||||||
|
{
|
||||||
|
borders_.push_back(border);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<BlockBorder> Layout::getBorder(uint32_t id)
|
||||||
|
{
|
||||||
|
for(const std::shared_ptr<BlockBorder>& border : borders_)
|
||||||
|
{
|
||||||
|
if(border->id() == id)
|
||||||
|
return border;
|
||||||
|
}
|
||||||
|
return std::shared_ptr<BlockBorder>();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<Block> Layout::getBlock(uint32_t id)
|
||||||
|
{
|
||||||
|
for(const std::shared_ptr<Block>& block : blocks_)
|
||||||
|
{
|
||||||
|
if(block->id() == id)
|
||||||
|
return block;
|
||||||
|
}
|
||||||
|
return std::shared_ptr<Block>();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Layout::store(QJsonObject& json)
|
||||||
|
{
|
||||||
|
QJsonArray blockArray;
|
||||||
|
for(const std::shared_ptr<Block>& block : blocks_)
|
||||||
|
{
|
||||||
|
QJsonObject object;
|
||||||
|
block->store(object);
|
||||||
|
blockArray.append(object);
|
||||||
|
}
|
||||||
|
json["Blocks"] = blockArray;
|
||||||
|
|
||||||
|
QJsonArray borderArray;
|
||||||
|
for(const std::shared_ptr<BlockBorder>& border : borders_)
|
||||||
|
{
|
||||||
|
QJsonObject object;
|
||||||
|
border->store(object);
|
||||||
|
borderArray.append(object);
|
||||||
|
}
|
||||||
|
json["Borders"] = borderArray;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Layout::load(const QJsonObject& json)
|
||||||
|
{
|
||||||
|
std::vector<QJsonObject> 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> block(new Block);
|
||||||
|
block->load(jsonObject);
|
||||||
|
blocks_.push_back(block);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<QJsonObject> 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<BlockBorder> 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<BlockBorder>& border : borders_)
|
||||||
|
{
|
||||||
|
std::shared_ptr<Block> first;
|
||||||
|
std::shared_ptr<Block> second;
|
||||||
|
for(std::shared_ptr<Block>& block : blocks_)
|
||||||
|
{
|
||||||
|
if(block->ownsBorder(border))
|
||||||
|
{
|
||||||
|
if(!first)
|
||||||
|
first = block;
|
||||||
|
else if(!second)
|
||||||
|
second = block;
|
||||||
|
else if(!second)
|
||||||
|
qWarning()<<"border with id"<<border->id()<<"is assigned to more than 2 blocks";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(!first || !second)
|
||||||
|
qWarning()<<"border with id"<<border->id()<<"is assigned to less than than 2 blocks";
|
||||||
|
border->setBlocks(std::pair<std::weak_ptr<Block>, std::weak_ptr<Block>>(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"<<blocks_[i]->id()<<"doset have at least one border";
|
||||||
|
}
|
||||||
|
}
|
43
src/trainOverlord/layout.h
Normal file
43
src/trainOverlord/layout.h
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
#ifndef BLOCKSTORE_H
|
||||||
|
#define BLOCKSTORE_H
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <memory>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "block.h"
|
||||||
|
#include "blockborder.h"
|
||||||
|
#include "microcontroller.h"
|
||||||
|
#include "itemstore.h"
|
||||||
|
|
||||||
|
class Layout : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
private:
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::vector<std::shared_ptr<Block>> blocks_;
|
||||||
|
std::vector<std::shared_ptr<BlockBorder>> borders_;
|
||||||
|
std::vector<std::pair<std::weak_ptr<Train>, std::weak_ptr<BlockBorder>>> trainLimbo_;
|
||||||
|
|
||||||
|
void removeTrainFromAllBlocks(std::shared_ptr<Train> train);
|
||||||
|
void registerTrainInLimbo(std::shared_ptr<Train> train, std::shared_ptr<BlockBorder>);
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit Layout(QObject *parent = nullptr);
|
||||||
|
void addBlock(std::shared_ptr<Block> block);
|
||||||
|
void addBorder(std::shared_ptr<BlockBorder> border);
|
||||||
|
void store(QJsonObject& json);
|
||||||
|
void load(const QJsonObject& json);
|
||||||
|
std::shared_ptr<BlockBorder> getBorder(uint32_t id);
|
||||||
|
std::shared_ptr<Block> getBlock(uint32_t id);
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void trainArrivedAtReader(uint8_t reader, std::shared_ptr<Train> train, int tagType);
|
||||||
|
void itemAdded(std::weak_ptr<Item> item);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void trainArrivedAtBorder(std::weak_ptr<BlockBorder>, std::weak_ptr<Train> train, int tagType);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // BLOCKSTORE_H
|
@ -10,17 +10,15 @@ void OverlordItemStore::gotNfcTag(NfcUid uid)
|
|||||||
{
|
{
|
||||||
for(std::shared_ptr<Item> item : items_)
|
for(std::shared_ptr<Item> item : items_)
|
||||||
{
|
{
|
||||||
Train* train = dynamic_cast<Train*>(item.get());
|
std::shared_ptr<Train> train = std::dynamic_pointer_cast<Train>(item);
|
||||||
if(!train)
|
if(!train)
|
||||||
continue;
|
continue;
|
||||||
for(const NfcUid& trainUid : train->tags)
|
int owns = train->ownsTag(uid);
|
||||||
|
if(owns == Train::TAG_FRONT || owns == Train::TAG_BACK)
|
||||||
{
|
{
|
||||||
if(trainUid == uid)
|
qDebug()<<"Train"<<train->getTrainId()<<"arrived at reader"<<uid.reader;
|
||||||
{
|
trainArrivedAtReader(uid.reader, train, owns);
|
||||||
if(train->passedReader(uid))
|
return;
|
||||||
train->setValue(0-train->getValue());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,16 +1,16 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "itemstore.h"
|
#include "itemstore.h"
|
||||||
#include <QTimer>
|
#include "train.h"
|
||||||
|
|
||||||
class OverlordItemStore: public ItemStore
|
class OverlordItemStore: public ItemStore
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
private:
|
|
||||||
QTimer timer;
|
|
||||||
public:
|
public:
|
||||||
OverlordItemStore(QObject *parent = nullptr);
|
OverlordItemStore(QObject *parent = nullptr);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
|
|
||||||
void gotNfcTag(NfcUid);
|
void gotNfcTag(NfcUid);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void trainArrivedAtReader(uint8_t reader, std::shared_ptr<Train> train, int tagType);
|
||||||
};
|
};
|
||||||
|
@ -3,20 +3,87 @@
|
|||||||
#include <QIODevice>
|
#include <QIODevice>
|
||||||
#include <QTcpSocket>
|
#include <QTcpSocket>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <QJsonObject>
|
||||||
|
#include <QJsonDocument>
|
||||||
|
#include <QStandardPaths>
|
||||||
|
#include <QFile>
|
||||||
|
#include <QTimer>
|
||||||
|
#include <signal.h>
|
||||||
|
|
||||||
#include "microcontroller.h"
|
#include "microcontroller.h"
|
||||||
#include "nfcuid.h"
|
#include "nfcuid.h"
|
||||||
#include "overlorditemstore.h"
|
#include "overlorditemstore.h"
|
||||||
#include "train.h"
|
#include "train.h"
|
||||||
#include "turnout.h"
|
#include "turnout.h"
|
||||||
#include "signal.h"
|
#include "layout.h"
|
||||||
|
|
||||||
void gotTag(NfcUid uid)
|
void sigHandler(int sig)
|
||||||
{
|
{
|
||||||
std::cout<<"Got tag from "<<uid.reader<<" uid ";
|
QCoreApplication::quit();
|
||||||
for(size_t i = 0; i < uid.length; ++i)
|
}
|
||||||
|
|
||||||
|
QJsonObject getJsonObjectFromDisk(const QString& filePath, bool* error)
|
||||||
|
{
|
||||||
|
QFile file;
|
||||||
|
|
||||||
|
if(filePath.size() > 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: "<<filePath.toLatin1().data()<<std::endl;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
QJsonParseError qerror;
|
||||||
|
QJsonDocument document(QJsonDocument::fromJson(file.readAll(), &qerror));
|
||||||
|
file.close();
|
||||||
|
if(qerror.error != QJsonParseError::NoError)
|
||||||
|
{
|
||||||
|
qDebug()<<filePath<<" "<<qerror.errorString();
|
||||||
|
if(error)
|
||||||
|
(*error) = true;
|
||||||
|
}
|
||||||
|
return document.object();
|
||||||
|
}
|
||||||
|
return QJsonObject();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool storeJsonObjectToDisk(const QJsonObject& json, QString filePath = QString())
|
||||||
|
{
|
||||||
|
if(filePath.size() == 0)
|
||||||
|
{
|
||||||
|
filePath = QStandardPaths::writableLocation(QStandardPaths::ConfigLocation) + "/trainoverloard.json";
|
||||||
|
}
|
||||||
|
QFile file(filePath + ".out");
|
||||||
|
|
||||||
|
qDebug()<<"config file: "<<filePath;
|
||||||
|
file.open(QIODevice::WriteOnly);
|
||||||
|
if(!file.isOpen())
|
||||||
|
{
|
||||||
|
std::cerr<<"Can not open config file: "<<filePath.toLatin1().data()<<std::endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
QJsonDocument document(json);
|
||||||
|
file.write(document.toJson());
|
||||||
|
file.close();
|
||||||
|
QFile::remove(filePath);
|
||||||
|
file.rename(filePath);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void getItemsCb(QTimer* timer, ItemStore* items, Microcontroller* micro)
|
||||||
|
{
|
||||||
|
if(items->getItems()->empty())
|
||||||
|
{
|
||||||
|
micro->requestState();
|
||||||
|
timer->start(1000);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -24,6 +91,8 @@ int main(int argc, char *argv[])
|
|||||||
{
|
{
|
||||||
QCoreApplication a(argc, argv);
|
QCoreApplication a(argc, argv);
|
||||||
|
|
||||||
|
signal(SIGINT, &sigHandler);
|
||||||
|
|
||||||
//set info
|
//set info
|
||||||
QCoreApplication::setOrganizationName("UVOS");
|
QCoreApplication::setOrganizationName("UVOS");
|
||||||
QCoreApplication::setOrganizationDomain("uvos.xyz");
|
QCoreApplication::setOrganizationDomain("uvos.xyz");
|
||||||
@ -60,9 +129,12 @@ int main(int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
|
|
||||||
OverlordItemStore items;
|
OverlordItemStore items;
|
||||||
|
Layout layout;
|
||||||
|
|
||||||
|
QObject::connect(&items, &OverlordItemStore::itemAdded, &layout, &Layout::itemAdded);
|
||||||
|
QObject::connect(&items, &OverlordItemStore::trainArrivedAtReader, &layout, &Layout::trainArrivedAtReader);
|
||||||
|
|
||||||
Microcontroller micro(µSocket);
|
Microcontroller micro(µSocket);
|
||||||
QObject::connect(µ, &Microcontroller::gotTag, gotTag);
|
|
||||||
QObject::connect(µ, &Microcontroller::gotTag, &items, &OverlordItemStore::gotNfcTag);
|
QObject::connect(µ, &Microcontroller::gotTag, &items, &OverlordItemStore::gotNfcTag);
|
||||||
QObject::connect(µ, &Microcontroller::gotItemList, &items, &OverlordItemStore::addItems);
|
QObject::connect(µ, &Microcontroller::gotItemList, &items, &OverlordItemStore::addItems);
|
||||||
QObject::connect(µ, &Microcontroller::itemChanged, &items, &OverlordItemStore::itemStateChanged);
|
QObject::connect(µ, &Microcontroller::itemChanged, &items, &OverlordItemStore::itemStateChanged);
|
||||||
@ -71,5 +143,27 @@ int main(int argc, char *argv[])
|
|||||||
Turnout::micro = µ
|
Turnout::micro = µ
|
||||||
Signal::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;
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user