Intal version with working trainoverlord

This commit is contained in:
uvos 2022-03-21 21:23:22 +01:00
parent a1f9fa172b
commit 872cc04a54
23 changed files with 992 additions and 46 deletions

View File

@ -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)

View File

@ -59,7 +59,7 @@ public:
virtual ~Item();
void informValue(int8_t value);
virtual void informValue(int8_t value);
};

View File

@ -22,7 +22,6 @@ void ItemStore::addItem(std::shared_ptr<Item> item)
items_.push_back(std::shared_ptr<Item>(item));
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)
@ -35,7 +34,7 @@ void ItemStore::addItems(const std::vector<std::shared_ptr<Item>>& 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<std::shared_ptr<Item>>& 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)));
}
}

View File

@ -30,7 +30,7 @@ signals:
public slots:
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 itemStateChanged(const ItemData& item);
};

View File

@ -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;
}

View File

@ -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<NfcUid> 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

View File

@ -1,4 +1,4 @@
#include "signal.h"
#include "trainsignal.h"
Microcontroller *Signal::micro = nullptr;

View File

@ -2,13 +2,12 @@
#include <chrono>
#include <thread>
#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()<<buffer;
if(_port != nullptr)
{
_port->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()<<buffer;
if(_port != nullptr)
{
_port->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__<<" :"<<buffer<<" list mode: "<<listMode;
if(bufferList.size() >= 10 && buffer.contains("NUMBER:"))
{
std::shared_ptr<Item> 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();
}

View File

@ -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

View File

@ -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"

View File

@ -4,7 +4,7 @@
#include <QDebug>
#include <QRadioButton>
#include <memory>
#include "../items/signal.h"
#include "trainsignal.h"
SignalWidget::SignalWidget(std::weak_ptr<Item> item, QWidget *parent) :
ItemWidget(item, parent),

View File

@ -3,7 +3,7 @@
#include <QWidget>
#include <memory>
#include <QShortcut>
#include "../items/signal.h"
#include "../items/trainsignal.h"
#include "itemwidget.h"
namespace Ui

View File

@ -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})

254
src/trainOverlord/block.cpp Normal file
View 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
View 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

View 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);
}
}
}

View 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

View 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";
}
}

View 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

View File

@ -10,17 +10,15 @@ void OverlordItemStore::gotNfcTag(NfcUid uid)
{
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)
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"<<train->getTrainId()<<"arrived at reader"<<uid.reader;
trainArrivedAtReader(uid.reader, train, owns);
return;
}
}
}

View File

@ -1,16 +1,16 @@
#pragma once
#include "itemstore.h"
#include <QTimer>
#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> train, int tagType);
};

View File

@ -3,20 +3,87 @@
#include <QIODevice>
#include <QTcpSocket>
#include <iostream>
#include <QJsonObject>
#include <QJsonDocument>
#include <QStandardPaths>
#include <QFile>
#include <QTimer>
#include <signal.h>
#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 "<<uid.reader<<" uid ";
for(size_t i = 0; i < uid.length; ++i)
QCoreApplication::quit();
}
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);
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(&microSocket);
QObject::connect(&micro, &Microcontroller::gotTag, gotTag);
QObject::connect(&micro, &Microcontroller::gotTag, &items, &OverlordItemStore::gotNfcTag);
QObject::connect(&micro, &Microcontroller::gotItemList, &items, &OverlordItemStore::addItems);
QObject::connect(&micro, &Microcontroller::itemChanged, &items, &OverlordItemStore::itemStateChanged);
@ -71,5 +143,27 @@ int main(int argc, char *argv[])
Turnout::micro = &micro;
Signal::micro = &micro;
return a.exec();
QTimer timer;
timer.setSingleShot(false);
QObject::connect(&timer, &QTimer::timeout, &timer, [&micro, &timer, &items](){getItemsCb(&timer, &items, &micro);});
getItemsCb(&timer, &items, &micro);
{
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;
}