Intal version with working trainoverlord
This commit is contained in:
		
							parent
							
								
									a1f9fa172b
								
							
						
					
					
						commit
						872cc04a54
					
				
					 23 changed files with 992 additions and 46 deletions
				
			
		| 
						 | 
				
			
			@ -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)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -59,7 +59,7 @@ public:
 | 
			
		|||
 | 
			
		||||
	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));
 | 
			
		||||
		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)));
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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);
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,4 +1,4 @@
 | 
			
		|||
#include "signal.h"
 | 
			
		||||
#include "trainsignal.h"
 | 
			
		||||
 | 
			
		||||
Microcontroller *Signal::micro = nullptr;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -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();
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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"
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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),
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,7 +3,7 @@
 | 
			
		|||
#include <QWidget>
 | 
			
		||||
#include <memory>
 | 
			
		||||
#include <QShortcut>
 | 
			
		||||
#include "../items/signal.h"
 | 
			
		||||
#include "../items/trainsignal.h"
 | 
			
		||||
#include "itemwidget.h"
 | 
			
		||||
 | 
			
		||||
namespace Ui
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
									
								
							
							
						
						
									
										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_)
 | 
			
		||||
	{
 | 
			
		||||
		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());
 | 
			
		||||
			qDebug()<<"Train"<<train->getTrainId()<<"arrived at reader"<<uid.reader;
 | 
			
		||||
			trainArrivedAtReader(uid.reader, train, owns);
 | 
			
		||||
			return;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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);
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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)
 | 
			
		||||
{
 | 
			
		||||
		std::cout<<(int)uid.bytes[i]<<(i == uid.length-1 ? "" : ":");
 | 
			
		||||
	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::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(µ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;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue