Compare commits

...

10 Commits

82 changed files with 3324 additions and 2544 deletions

5
CMakeLists.txt Normal file
View File

@ -0,0 +1,5 @@
cmake_minimum_required(VERSION 3.5)
project(trainController LANGUAGES CXX)
add_subdirectory(src)

42
src/CMakeLists.txt Normal file
View File

@ -0,0 +1,42 @@
set(CMAKE_INCLUDE_CURRENT_DIR ON)
set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
find_package(QT NAMES Qt6 Qt5 COMPONENTS Widgets Network SerialPort REQUIRED)
find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Widgets Network SerialPort REQUIRED)
set(COMMON_SOURCES
../common/microcontroller.cpp
../common/microcontroller.h
../common/items/item.cpp
../common/items/item.h
../common/items/itemstore.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
../common/nfcuid.h
)
include_directories(PRIVATE
./common/items/
./common
)
set(COMMON_LINK_LIBRARYS
Qt${QT_VERSION_MAJOR}::Network
Qt${QT_VERSION_MAJOR}::SerialPort
)
add_subdirectory(trainControllerUI)
add_subdirectory(trainOverlord)

View File

@ -1,479 +0,0 @@
/*
* Copyright (c) 2015-2017 Alex Spataru <alex_spataru@outlook.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <QDebug>
#include <QSettings>
#include "QJoysticks.h"
#include "jsbackend/SDL_Joysticks.h"
#include "jsbackend/VirtualJoystick.h"
QJoysticks::QJoysticks()
{
/* Initialize input methods */
m_sdlJoysticks = new SDL_Joysticks(this);
m_virtualJoystick = new VirtualJoystick(this);
/* Configure SDL joysticks */
connect(sdlJoysticks(), &SDL_Joysticks::POVEvent, this, &QJoysticks::POVEvent);
connect(sdlJoysticks(), &SDL_Joysticks::axisEvent, this, &QJoysticks::axisEvent);
connect(sdlJoysticks(), &SDL_Joysticks::buttonEvent, this, &QJoysticks::buttonEvent);
connect(sdlJoysticks(), &SDL_Joysticks::countChanged, this, &QJoysticks::updateInterfaces);
/* Configure virtual joysticks */
connect(virtualJoystick(), &VirtualJoystick::povEvent, this, &QJoysticks::POVEvent);
connect(virtualJoystick(), &VirtualJoystick::axisEvent, this, &QJoysticks::axisEvent);
connect(virtualJoystick(), &VirtualJoystick::buttonEvent, this, &QJoysticks::buttonEvent);
connect(virtualJoystick(), &VirtualJoystick::enabledChanged, this, &QJoysticks::updateInterfaces);
/* React to own signals to create QML signals */
connect(this, &QJoysticks::POVEvent, this, &QJoysticks::onPOVEvent);
connect(this, &QJoysticks::axisEvent, this, &QJoysticks::onAxisEvent);
connect(this, &QJoysticks::buttonEvent, this, &QJoysticks::onButtonEvent);
/* Configure the settings */
m_sortJoyticks = 0;
m_settings = new QSettings(qApp->organizationName(), qApp->applicationName());
m_settings->beginGroup("Blacklisted Joysticks");
}
QJoysticks::~QJoysticks()
{
delete m_settings;
delete m_sdlJoysticks;
delete m_virtualJoystick;
}
/**
* Returns the one and only instance of this class
*/
QJoysticks *QJoysticks::getInstance()
{
static QJoysticks joysticks;
return &joysticks;
}
/**
* Returns the number of joysticks that are attached to the computer and/or
* registered with the \c QJoysticks system.
*
* \note This count also includes the virtual joystick (if its enabled)
*/
int QJoysticks::count() const
{
return inputDevices().count();
}
/**
* Returns the number of joysticks that are not blacklisted.
* This can be considered the "effective" number of joysticks.
*/
int QJoysticks::nonBlacklistedCount()
{
int cnt = count();
for (int i = 0; i < count(); ++i)
if (isBlacklisted(i))
--cnt;
return cnt;
}
/**
* Returns a list with the names of all registered joystick.
*
* \note This list also includes the blacklisted joysticks
* \note This list also includes the virtual joystick (if its enabled)
*/
QStringList QJoysticks::deviceNames() const
{
QStringList names;
foreach (QJoystickDevice *joystick, inputDevices())
names.append(joystick->name);
return names;
}
/**
* Returns the POV value for the given joystick \a index and \a pov ID
*/
int QJoysticks::getPOV(const int index, const int pov)
{
if (joystickExists(index))
return getInputDevice(index)->povs.at(pov);
return -1;
}
/**
* Returns the axis value for the given joystick \a index and \a axis ID
*/
double QJoysticks::getAxis(const int index, const int axis)
{
if (joystickExists(index))
return getInputDevice(index)->axes.at(axis);
return 0;
}
/**
* Returns the button value for the given joystick \a index and \a button ID
*/
bool QJoysticks::getButton(const int index, const int button)
{
if (joystickExists(index))
return getInputDevice(index)->buttons.at(button);
return false;
}
/**
* Returns the number of axes that the joystick at the given \a index has.
*/
int QJoysticks::getNumAxes(const int index)
{
if (joystickExists(index))
return getInputDevice(index)->axes.count();
return -1;
}
/**
* Returns the number of POVs that the joystick at the given \a index has.
*/
int QJoysticks::getNumPOVs(const int index)
{
if (joystickExists(index))
return getInputDevice(index)->povs.count();
return -1;
}
/**
* Returns the number of buttons that the joystick at the given \a index has.
*/
int QJoysticks::getNumButtons(const int index)
{
if (joystickExists(index))
return getInputDevice(index)->buttons.count();
return -1;
}
/**
* Returns \c true if the joystick at the given \a index is blacklisted.
*/
bool QJoysticks::isBlacklisted(const int index)
{
if (joystickExists(index))
return inputDevices().at(index)->blacklisted;
return true;
}
/**
* Returns \c true if the joystick at the given \a index is valid, otherwise,
* the function returns \c false and warns the user through the console.
*/
bool QJoysticks::joystickExists(const int index)
{
return (index >= 0) && (count() > index);
}
/**
* Returns the name of the given joystick
*/
QString QJoysticks::getName(const int index)
{
if (joystickExists(index))
return m_devices.at(index)->name;
return "Invalid Joystick";
}
/**
* Returns a pointer to the SDL joysticks system.
* This can be used if you need to get more information regarding the joysticks
* registered and managed with SDL.
*/
SDL_Joysticks *QJoysticks::sdlJoysticks() const
{
return m_sdlJoysticks;
}
/**
* Returns a pointer to the virtual joystick system.
* This can be used if you need to get more information regarding the virtual
* joystick or want to change its properties directly.
*
* \note You can also change the properties of the virtual joysticks using the
* functions of the \c QJoysticks system class
*/
VirtualJoystick *QJoysticks::virtualJoystick() const
{
return m_virtualJoystick;
}
/**
* Returns a pointer to the device at the given \a index.
*/
QJoystickDevice *QJoysticks::getInputDevice(const int index)
{
if (joystickExists(index))
return inputDevices().at(index);
return Q_NULLPTR;
}
/**
* Returns a pointer to a list containing all registered joysticks.
* This can be used for advanced hacks or just to get all properties of each
* joystick.
*/
QList<QJoystickDevice *> QJoysticks::inputDevices() const
{
return m_devices;
}
/**
* If \a sort is set to true, then the device list will put all blacklisted
* joysticks at the end of the list
*/
void QJoysticks::setSortJoysticksByBlacklistState(bool sort)
{
if (m_sortJoyticks != sort)
{
m_sortJoyticks = sort;
updateInterfaces();
}
}
/**
* Blacklists or whitelists the joystick at the given \a index.
*
* \note This function does not have effect if the given joystick does not exist
* \note Once the joystick is blacklisted, the joystick list will be updated
*/
void QJoysticks::setBlacklisted(const int index, bool blacklisted)
{
Q_ASSERT(joystickExists(index));
/* Netrualize the joystick */
if (blacklisted)
{
for (int i = 0; i < getNumAxes(index); ++i)
emit axisChanged(index, i, 0);
for (int i = 0; i < getNumButtons(index); ++i)
emit buttonChanged(index, i, false);
for (int i = 0; i < getNumPOVs(index); ++i)
emit povChanged(index, i, 0);
}
/* See if blacklist value was actually changed */
bool changed = m_devices.at(index)->blacklisted != blacklisted;
/* Save settings */
m_devices.at(index)->blacklisted = blacklisted;
m_settings->setValue(getName(index), blacklisted);
/* Re-scan joysticks if blacklist value has changed */
if (changed)
updateInterfaces();
}
/**
* 'Rescans' for new/removed joysticks and registers them again.
*/
void QJoysticks::updateInterfaces()
{
m_devices.clear();
/* Put blacklisted joysticks at the bottom of the list */
if (m_sortJoyticks)
{
/* Register non-blacklisted SDL joysticks */
foreach (QJoystickDevice *joystick, sdlJoysticks()->joysticks())
{
joystick->blacklisted = m_settings->value(joystick->name, false).toBool();
if (!joystick->blacklisted)
addInputDevice(joystick);
}
/* Register the virtual joystick (if its not blacklisted) */
if (virtualJoystick()->joystickEnabled())
{
QJoystickDevice *joystick = virtualJoystick()->joystick();
joystick->blacklisted = m_settings->value(joystick->name, false).toBool();
if (!joystick->blacklisted)
{
addInputDevice(joystick);
virtualJoystick()->setJoystickID(inputDevices().count() - 1);
}
}
/* Register blacklisted SDL joysticks */
foreach (QJoystickDevice *joystick, sdlJoysticks()->joysticks())
{
joystick->blacklisted = m_settings->value(joystick->name, false).toBool();
if (joystick->blacklisted)
addInputDevice(joystick);
}
/* Register the virtual joystick (if its blacklisted) */
if (virtualJoystick()->joystickEnabled())
{
QJoystickDevice *joystick = virtualJoystick()->joystick();
joystick->blacklisted = m_settings->value(joystick->name, false).toBool();
if (joystick->blacklisted)
{
addInputDevice(joystick);
virtualJoystick()->setJoystickID(inputDevices().count() - 1);
}
}
}
/* Sort normally */
else
{
/* Register SDL joysticks */
foreach (QJoystickDevice *joystick, sdlJoysticks()->joysticks())
{
addInputDevice(joystick);
joystick->blacklisted = m_settings->value(joystick->name, false).toBool();
}
/* Register virtual joystick */
if (virtualJoystick()->joystickEnabled())
{
QJoystickDevice *joystick = virtualJoystick()->joystick();
joystick->blacklisted = m_settings->value(joystick->name, false).toBool();
addInputDevice(joystick);
virtualJoystick()->setJoystickID(inputDevices().count() - 1);
}
}
emit countChanged();
}
/**
* Changes the axis value range of the virtual joystick.
*
* Take into account that maximum axis values supported by the \c QJoysticks
* system is from \c -1 to \c 1.
*/
void QJoysticks::setVirtualJoystickRange(qreal range)
{
virtualJoystick()->setAxisRange(range);
}
/**
* Enables or disables the virtual joystick
*/
void QJoysticks::setVirtualJoystickEnabled(bool enabled)
{
virtualJoystick()->setJoystickEnabled(enabled);
}
void QJoysticks::setVirtualJoystickAxisSensibility(qreal sensibility)
{
virtualJoystick()->setAxisSensibility(sensibility);
}
/**
* Removes all the registered joysticks and emits appropriate signals.
*/
void QJoysticks::resetJoysticks()
{
m_devices.clear();
emit countChanged();
}
/**
* Registers the given \a device to the \c QJoysticks system
*/
void QJoysticks::addInputDevice(QJoystickDevice *device)
{
Q_ASSERT(device);
m_devices.append(device);
}
/**
* Configures the QML-friendly signal based on the information given by the
* \a event data and updates the joystick values
*/
void QJoysticks::onPOVEvent(const QJoystickPOVEvent &e)
{
if (e.joystick == nullptr)
return;
if (!isBlacklisted(e.joystick->id))
{
if (e.pov < getInputDevice(e.joystick->id)->povs.count())
{
getInputDevice(e.joystick->id)->povs[e.pov] = e.angle;
emit povChanged(e.joystick->id, e.pov, e.angle);
}
}
}
/**
* Configures the QML-friendly signal based on the information given by the
* \a event data and updates the joystick values
*/
void QJoysticks::onAxisEvent(const QJoystickAxisEvent &e)
{
if (e.joystick == nullptr)
return;
if (!isBlacklisted(e.joystick->id))
{
if (e.axis < getInputDevice(e.joystick->id)->axes.count())
{
getInputDevice(e.joystick->id)->axes[e.axis] = e.value;
emit axisChanged(e.joystick->id, e.axis, e.value);
}
}
}
/**
* Configures the QML-friendly signal based on the information given by the
* \a event data and updates the joystick values
*/
void QJoysticks::onButtonEvent(const QJoystickButtonEvent &e)
{
if (e.joystick == nullptr)
return;
if (!isBlacklisted(e.joystick->id))
{
if (e.button < getInputDevice(e.joystick->id)->buttons.count())
{
getInputDevice(e.joystick->id)->buttons[e.button] = e.pressed;
emit buttonChanged(e.joystick->id, e.button, e.pressed);
}
}
}

View File

@ -1,18 +0,0 @@
#include "auxitem.h"
AuxItem::AuxItem(Microcontroller* micro, uint32_t itemIdIn, QString name, uint8_t value, QObject* parent): Item(itemIdIn, name, value, parent), micro_(micro)
{
}
void AuxItem::setValue(uint8_t value)
{
Item::setValue(value);
micro_->setAuxPwm(value);
}
void AuxItem::store(QJsonObject &json)
{
json["Type"] = "Aux";
Item::store(json);
}

View File

@ -1,20 +0,0 @@
#pragma once
#include "item.h"
#include "../microcontroller.h"
class AuxItem: public Item
{
Q_OBJECT
private:
Microcontroller* micro_;
public slots:
virtual void setValue(uint8_t value);
public:
AuxItem(Microcontroller* micro, uint32_t itemIdIn = QRandomGenerator::global()->generate(), QString name = "", uint8_t value = 0, QObject* parent = nullptr);
virtual void store(QJsonObject& json);
};

View File

@ -10,28 +10,29 @@ ItemData::ItemData(uint32_t itemIdIn, QString name, int8_t value): name_(name),
QString ItemData::getName() const
{
return name_;
return name_;
}
void ItemData::setName(QString name)
{
name_ = name;
name_ = name;
}
int8_t ItemData::getValue() const
{
return value_;
return value_;
}
uint32_t ItemData::id() const
{
return itemId_;
return itemId_;
}
//item
Item::Item(uint32_t itemIdIn, QString name, int8_t value, QObject *parent): QObject(parent), ItemData (itemIdIn, name, value)
Item::Item(uint32_t itemIdIn, QString name, int8_t value, QObject *parent): QObject(parent), ItemData (itemIdIn, name,
value)
{
}
@ -47,16 +48,16 @@ Item::~Item()
void Item::setFunction(uint8_t function, bool on)
{
functionChanged(function, on);
functionChanged(function, on);
}
void Item::setValue(int8_t value)
{
value_ = value;
valueChanged(value_);
value_ = value;
valueChanged(value_);
}
void Item::informValue(int8_t value)
{
Item::setValue(value);
Item::setValue(value);
}

View File

@ -11,28 +11,34 @@ class Actor;
class ItemData
{
protected:
QString name_;
QString name_;
int8_t value_;
uint32_t itemId_;
uint32_t itemId_;
public:
ItemData(uint32_t itemIdIn = QRandomGenerator::global()->generate(), QString name = "Item", int8_t value = 0);
inline bool operator==(const ItemData& in) const{ return itemId_==in.itemId_; }
inline bool operator!=(const ItemData& in) const{ return itemId_!=in.itemId_; }
inline bool operator==(const ItemData& in) const
{
return itemId_==in.itemId_;
}
inline bool operator!=(const ItemData& in) const
{
return itemId_!=in.itemId_;
}
uint32_t id() const;
uint32_t id() const;
void setName(QString name);
void setName(QString name);
int8_t getValue() const;
virtual QString getName() const;
virtual QString getName() const;
};
class Item: public QObject, public ItemData
{
Q_OBJECT
Q_OBJECT
private:
signals:
@ -43,16 +49,17 @@ signals:
public slots:
virtual void setValue(int8_t value);
virtual void setFunction(uint8_t funciton, bool value);
virtual void setFunction(uint8_t funciton, bool value);
public:
Item(uint32_t itemIdIn = QRandomGenerator::global()->generate(), QString name = "Item", int8_t value = 0, QObject *parent = nullptr);
Item(const ItemData& itemData, QObject *parent = nullptr);
Item(uint32_t itemIdIn = QRandomGenerator::global()->generate(), QString name = "Item", int8_t value = 0,
QObject *parent = nullptr);
Item(const ItemData& itemData, QObject *parent = nullptr);
virtual ~Item();
virtual ~Item();
void informValue(int8_t value);
virtual void informValue(int8_t value);
};

View File

@ -0,0 +1,87 @@
#include "itemstore.h"
#include <QJsonArray>
#include <QDebug>
#include "train.h"
ItemStore::ItemStore(QObject *parent): QObject(parent)
{
}
void ItemStore::addItem(std::shared_ptr<Item> item)
{
if(!item)
{
qWarning()<<"invalid item";
return;
}
bool mached = false;
for(unsigned i = 0; i < items_.size(); i++ )
if(*items_[i] == *item) mached = true;
if(!mached)
{
items_.push_back(std::shared_ptr<Item>(item));
itemAdded(std::weak_ptr<Item>(items_.back()));
}
}
void ItemStore::addItems(const std::vector<std::shared_ptr<Item>>& itemIn)
{
for(unsigned j = 0; j < itemIn.size(); j++)
{
addItem(itemIn[j]);
Train* train = dynamic_cast<Train*>(itemIn[j].get());
if(!train)
continue;
if(train->getTrainId() == 0)
{
const uint8_t uidBytes[] = {154, 110, 34, 218};
train->tags.push_back(NfcUid(uidBytes, sizeof(uidBytes)));
}
else if(train->getTrainId() == 1)
{
const uint8_t uidBytes[] = {83, 118, 122, 215};
train->tags.push_back(NfcUid(uidBytes, sizeof(uidBytes)));
}
else if(train->getTrainId() == 3)
{
train->tags.push_back(NfcUid({83, 111, 26, 174}));
train->tags.push_back(NfcUid({83, 63, 78, 170}));
}
else if(train->getTrainId() == 4)
{
const uint8_t uidBytes[] = {55, 220, 31, 184};
train->tags.push_back(NfcUid(uidBytes, sizeof(uidBytes)));
}
}
}
void ItemStore::removeItem(const ItemData& item)
{
for(unsigned j = 0; j < items_.size(); j++)
{
if(item == *items_[j])
{
items_.erase(items_.begin()+j);
--j;
}
}
}
void ItemStore::clear()
{
for(size_t i = 0; i < items_.size(); ++i) itemDeleted(*items_[i]);
items_.clear();
}
void ItemStore::itemStateChanged(const ItemData& item)
{
for(unsigned i = 0; i < items_.size(); i++ )
{
if(items_[i]->operator==(item))
{
if(items_[i]->getValue() != item.getValue())
items_[i]->informValue(item.getValue());
}
}
}

View File

@ -0,0 +1,36 @@
#pragma once
#include <vector>
#include <memory>
#include "item.h"
#include "../nfcuid.h"
class ItemStore: public QObject
{
Q_OBJECT
protected:
std::vector< std::shared_ptr<Item> > items_;
public:
ItemStore(QObject *parent = nullptr);
virtual ~ItemStore() {}
inline std::vector< std::shared_ptr<Item> >* getItems()
{
return &items_;
}
void clear();
signals:
void itemDeleted(ItemData item);
void itemAdded(std::weak_ptr<Item> Item);
public slots:
void removeItem(const ItemData& 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

@ -0,0 +1,93 @@
#include "train.h"
Train::Train(uint8_t id, uint8_t address, uint8_t functionMask, int8_t initalValue):
Item(address, QString("Train ")+QString::number(id), initalValue),
functionMask_(functionMask),
train_id_(id)
{
}
Microcontroller *Train::micro = nullptr;
void Train::setFunction(uint8_t funciton, bool value)
{
Item::setFunction(funciton, value);
if(micro)
micro->trainSetFunction(train_id_, funciton, 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_);
}
bool Train::ownsTag(NfcUid uid)
{
for(size_t i = 0; i < tags.size(); ++i)
{
if(uid == tags[i])
return true;
}
return false;
}
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;
}

51
src/common/items/train.h Normal file
View File

@ -0,0 +1,51 @@
#ifndef TRAIN_H
#define TRAIN_H
#include <vector>
#include "item.h"
#include "microcontroller.h"
#include "nfcuid.h"
class Train : public Item
{
Q_OBJECT
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 Microcontroller *micro;
std::vector<NfcUid> tags;
Train(uint8_t id = 0, uint8_t address = 0, uint8_t functionMask = 0, int8_t initalValue = 0);
uint8_t getFunctionMask()
{
return functionMask_;
}
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();
bool ownsTag(NfcUid uid);
bool hasBackTag();
uint8_t getTrainId()
{
return train_id_;
}
signals:
void unsuspended(uint32_t id, int direction);
};
#endif // TRAIN_H

View File

@ -0,0 +1,28 @@
#include "trainsignal.h"
Microcontroller *Signal::micro = nullptr;
Signal::Signal(uint8_t id, uint8_t address, uint8_t subaddress, uint8_t type, int8_t initalValue)
: Item(address | (subaddress << 8), QString("Turnout ")+QString::number(id), initalValue),
subaddress_(subaddress), signalId_(id), type_(type)
{
itemId_ = address | (subaddress << 8);
name_ = QString("Signal ")+QString::number(id);
}
void Signal::setValue(int8_t value)
{
Item::setValue(value);
if(micro)
micro->signalSetValue(signalId_, value);
}
bool Signal::hasSlow()
{
return type_ & TYPE_HAS_SLOW;
}
bool Signal::hasExpect()
{
return type_ & TYPE_HAS_EXPECT;
}

View File

@ -0,0 +1,38 @@
#ifndef SIGNAL_H
#define SIGNAL_H
#include "item.h"
#include "../microcontroller.h"
class Signal : public Item
{
public:
static constexpr int GO = 0;
static constexpr int STOP = 1;
static constexpr int SLOW = 2;
static constexpr int EXPECT_GO = 1 << 3;
static constexpr int EXPECT_STOP = 2 << 3;
static constexpr int EXPECT_SLOW = 3 << 3;
static constexpr uint8_t TYPE_NORMAL = 0;
static constexpr uint8_t TYPE_RELAY = 1;
static constexpr uint8_t TYPE_HAS_SLOW = 1 << 1;
static constexpr uint8_t TYPE_HAS_EXPECT = 1 << 2;
private:
uint8_t subaddress_;
uint8_t signalId_;
uint8_t type_;
public:
static Microcontroller *micro;
explicit Signal(uint8_t id = 0, uint8_t address = 0, uint8_t subaddress = 0, uint8_t type = 0, int8_t initalValue = 0);
virtual void setValue(int8_t value);
bool hasSlow();
bool hasExpect();
uint8_t getSignalId()
{
return signalId_;
}
};
#endif // SIGNAL_H

View File

@ -6,13 +6,13 @@ Turnout::Turnout(uint8_t id, uint8_t address, uint8_t subaddress, int8_t initalV
: Item(address | (subaddress << 8), QString("Turnout ")+QString::number(id), initalValue),
subaddress_(subaddress), turnoutId_(id)
{
itemId_ = address | (subaddress << 8);
name_ = QString("Turnout ")+QString::number(id);
itemId_ = address | (subaddress << 8);
name_ = QString("Turnout ")+QString::number(id);
}
void Turnout::setValue(int8_t value)
{
Item::setValue(value);
if(micro)
Item::setValue(value);
if(micro)
micro->tunoutSetDirection(turnoutId_, value > 0);
}

View File

@ -6,14 +6,17 @@
class Turnout : public Item
{
uint8_t subaddress_;
uint8_t turnoutId_;
uint8_t subaddress_;
uint8_t turnoutId_;
public:
static Microcontroller *micro;
static Microcontroller *micro;
explicit Turnout(uint8_t id = 0, uint8_t address = 0, uint8_t subaddress = 0, int8_t initalValue = 0);
virtual void setValue(int8_t value);
uint8_t getTurnoutId(){return turnoutId_;}
uint8_t getTurnoutId()
{
return turnoutId_;
}
};
#endif // TURNOUT_H

View File

@ -0,0 +1,253 @@
#include "microcontroller.h"
#include <chrono>
#include <thread>
#include "train.h"
#include "turnout.h"
#include "trainsignal.h"
void Microcontroller::trainSetSpeed(uint8_t id, int8_t speed)
{
std::stringstream ss;
ss<<"train "<<(unsigned)id<<" speed "<<(int)speed<<'\n';
write(ss.str().c_str());
}
void Microcontroller::trainReverse(uint8_t id)
{
std::stringstream ss;
ss<<"train "<<(unsigned)id<<" reverse\n";
write(ss.str().c_str());
}
void Microcontroller::trainSetFunction(uint8_t id, uint8_t function, bool on)
{
std::stringstream ss;
ss<<"train "<<(unsigned)id<<" function "<<(unsigned)function<<' '<<(on ? "on" : "off")<<'\n';
write(ss.str().c_str());
}
void Microcontroller::tunoutSetDirection(uint8_t id, bool direction)
{
std::stringstream ss;
ss<<"turnout "<<(unsigned)id<<" set "<<(!direction ? "left" : "right")<<'\n';
write(ss.str().c_str());
}
void Microcontroller::signalSetValue(uint8_t id, uint8_t state)
{
std::stringstream ss;
ss<<"signal "<<(unsigned)id<<" set "<<(unsigned)state<<'\n';
write(ss.str().c_str());
}
void Microcontroller::setPower(bool on)
{
write(on ? "power on\n" : "power off\n");
}
void Microcontroller::estop()
{
write("stop\n");
}
void Microcontroller::write(const QByteArray& buffer)
{
if(_port != nullptr)
{
_port->write(buffer);
//_port->waitForBytesWritten(1000);
}
std::this_thread::sleep_for(std::chrono::milliseconds(40));
}
void Microcontroller::write(char* buffer, const size_t length)
{
if(_port != nullptr)
{
_port->write(buffer, length);
//_port->waitForBytesWritten(1000);
}
std::this_thread::sleep_for(std::chrono::milliseconds(40));
}
bool Microcontroller::connected()
{
if(_port != nullptr)
return _port->isOpen();
else return false;
}
void Microcontroller::requestState()
{
write("train list\n");
write("turnout list\n");
write("signal list\n");
write("nfc list\n");
}
//housekeeping
Microcontroller::Microcontroller(QIODevice* port)
{
setIODevice(port);
}
Microcontroller::Microcontroller()
{
}
Microcontroller::~Microcontroller()
{
}
void Microcontroller::setIODevice(QIODevice* port)
{
_port = port;
QObject::connect(_port, &QIODevice::readyRead, this, &Microcontroller::isReadyRead);
}
std::shared_ptr<Item> Microcontroller::processTrainLine(const QString& buffer)
{
QStringList bufferList = buffer.split(' ');
if(bufferList.size() >= 14 && buffer.startsWith("TRAIN NUMBER:"))
{
return std::shared_ptr<Item>(new Train(bufferList[2].toInt(), bufferList[4].toInt(), bufferList[13].toInt(nullptr, 2),
bufferList[9].toInt()));
}
return nullptr;
}
std::shared_ptr<Item> Microcontroller::processTurnoutLine(const QString& buffer)
{
QStringList bufferList = buffer.split(' ');
if(bufferList.size() >= 11 && buffer.startsWith("TURNOUT NUMBER:"))
{
return std::shared_ptr<Item>(new Turnout(bufferList[2].toInt(), bufferList[4].toInt(), bufferList[6].toInt(),
bufferList[11].toInt()));
}
return nullptr;
}
std::shared_ptr<Item> Microcontroller::processSignalLine(const QString& buffer)
{
QStringList bufferList = buffer.split(' ');
if(bufferList.size() >= 13 && buffer.startsWith("SIGNAL NUMBER:"))
{
return std::shared_ptr<Item>(new Signal(bufferList[2].toInt(), bufferList[4].toInt(), bufferList[6].toInt(),
bufferList[8].toInt(), bufferList[13].toInt()));
}
return nullptr;
}
void Microcontroller::processNfcLine(const QString& buffer)
{
QStringList tokens = buffer.split(" ");
if(tokens.size() < 4)
return;
if(tokens[1].startsWith("NUMBER"))
return;
NfcUid uid;
uint8_t reader = tokens[1].toUInt();
tokens = tokens[3].split(':');
uid.length = tokens.length();
for(size_t i = 0; i < uid.length; ++i)
uid.bytes[i] = tokens[i].toInt();
gotTag(reader, uid);
}
void Microcontroller::processList(const QString& buffer)
{
QStringList bufferList = buffer.split(' ');
if(bufferList.size() >= 10 && buffer.contains("NUMBER:"))
{
std::shared_ptr<Item> item;
if(listMode == TRAIN_LIST)
item = processTrainLine(buffer);
else if(listMode == TURNOUT_LIST)
item = processTurnoutLine(buffer);
else if(listMode == SIGNAL_LIST)
item = processSignalLine(buffer);
if(item)
itemList.push_back(item);
}
else
{
listMode = false;
if(!itemList.empty())
{
gotItemList(itemList);
itemList.clear();
}
}
}
void Microcontroller::processItemState(const QString& buffer)
{
std::shared_ptr<Item> item = processTrainLine(buffer);
if(_buffer.startsWith("TRAIN NUMBER:"))
item = processTrainLine(buffer);
else if(_buffer.startsWith("TURNOUT NUMBER:"))
item = processTurnoutLine(buffer);
else if(_buffer.startsWith("SIGNAL NUMBER:"))
item = processSignalLine(buffer);
if(item)
itemChanged(static_cast<ItemData>(*item));
else
qWarning()<<__func__<<"failed to process status line";
}
void Microcontroller::processMicroReturn()
{
if(listMode)
processList(_buffer);
else
{
if(_buffer.startsWith("Trains:"))
{
listMode = TRAIN_LIST;
itemList.clear();
}
else if(_buffer.startsWith("Turnouts:"))
{
listMode = TURNOUT_LIST;
}
else if(_buffer.startsWith("Signals:"))
{
listMode = SIGNAL_LIST;
}
else if(_buffer.startsWith("TRAIN NUMBER:") || _buffer.startsWith("TURNOUT NUMBER:") ||
_buffer.startsWith("SIGNAL NUMBER:"))
{
processItemState(_buffer);
}
else if(_buffer.startsWith("NFC"))
{
processNfcLine(_buffer);
}
else if(_buffer.startsWith("TrainController"))
{
requestState();
}
}
}
void Microcontroller::isReadyRead()
{
char charBuf;
while(_port->getChar(&charBuf))
{
_buffer.push_back(charBuf);
if( _buffer.endsWith('\n') )
{
_buffer.remove('\n');
processMicroReturn();
textRecived(_buffer);
_buffer.clear();
}
}
}

View File

@ -0,0 +1,80 @@
#ifndef MICROCONTROLLER_H
#define MICROCONTROLLER_H
#include <iostream>
#include <QObject>
#include <QIODevice>
#include <QString>
#include <QRunnable>
#include <QDebug>
#include <QEventLoop>
#include <QTimer>
#include <vector>
#include <memory>
#include <sstream>
#include "items/item.h"
#include "nfcuid.h"
class Microcontroller : public QObject
{
Q_OBJECT
private:
static constexpr int TRAIN_LIST = 1;
static constexpr int TURNOUT_LIST = 2;
static constexpr int SIGNAL_LIST = 3;
int listMode = 0;
//uint8_t _auxState = 0;
QIODevice* _port = nullptr;
std::vector< std::shared_ptr<Item> > itemList;
QScopedPointer<QEventLoop> loop;
QString _buffer;
void processMicroReturn();
void processList(const QString& buffer);
void processItemState(const QString& buffer);
std::shared_ptr<Item> processTrainLine(const QString& buffer);
std::shared_ptr<Item> processTurnoutLine(const QString& buffer);
std::shared_ptr<Item> processSignalLine(const QString& buffer);
void processNfcLine(const QString& buffer);
void write(char *buffer, const size_t length);
void write(const QByteArray& buffer);
public:
Microcontroller(QIODevice* port);
Microcontroller();
~Microcontroller();
bool connected();
void setIODevice(QIODevice* port);
public slots:
void requestState();
void trainSetSpeed(uint8_t id, int8_t speed);
void trainReverse(uint8_t id);
void trainSetFunction(uint8_t id, uint8_t function, bool on);
void tunoutSetDirection(uint8_t id, bool direction);
void signalSetValue(uint8_t id, uint8_t state);
void estop();
void setPower(bool on);
private slots:
void isReadyRead();
signals:
void textRecived(const QString string);
void itemChanged(ItemData relay);
void auxStateChanged(int value);
void gotItemList(std::vector<std::shared_ptr<Item>>&);
void gotTag(uint8_t reader, NfcUid uid);
};
#endif // MICROCONTROLLER_H

53
src/common/nfcuid.h Normal file
View File

@ -0,0 +1,53 @@
#ifndef NFCUID_H
#define NFCUID_H
#include <cstdint>
#include <string>
class NfcUid
{
public:
uint8_t bytes[10];
uint8_t length;
bool operator==(const NfcUid& in) const
{
if(length != in.length)
return false;
for(uint8_t i = 0; i < length; ++i)
{
if(bytes[i] != in.bytes[i])
return false;
}
return true;
}
bool operator!=(const NfcUid& in) const
{
return !operator==(in);
}
NfcUid(){}
NfcUid(const std::initializer_list<const uint8_t> list)
{
length = list.size();
uint8_t i = 0;
for(std::initializer_list<const uint8_t>::iterator iter = list.begin(); iter != list.end(); ++iter)
bytes[i++] = *iter;
}
NfcUid(const uint8_t* const bytesIn, uint8_t lengthIn): length(lengthIn)
{
for(uint8_t i = 0; i < length; ++i)
bytes[i] = bytesIn[i];
}
std::string toString() const
{
std::string str;
for(uint8_t i = 0; i < length; ++i)
{
str.append(std::to_string((int)bytes[i]));
if(i != length-1)
str.push_back(':');
}
return str;
}
};
#endif // NFCUID_H

View File

@ -1,18 +0,0 @@
#include "auxitem.h"
AuxItem::AuxItem(Microcontroller* micro, uint32_t itemIdIn, QString name, uint8_t value, QObject* parent): Item(itemIdIn, name, value, parent), micro_(micro)
{
}
void AuxItem::setValue(uint8_t value)
{
Item::setValue(value);
micro_->setAuxPwm(value);
}
void AuxItem::store(QJsonObject &json)
{
json["Type"] = "Aux";
Item::store(json);
}

View File

@ -1,20 +0,0 @@
#pragma once
#include "item.h"
#include "../microcontroller.h"
class AuxItem: public Item
{
Q_OBJECT
private:
Microcontroller* micro_;
public slots:
virtual void setValue(uint8_t value);
public:
AuxItem(Microcontroller* micro, uint32_t itemIdIn = QRandomGenerator::global()->generate(), QString name = "", uint8_t value = 0, QObject* parent = nullptr);
virtual void store(QJsonObject& json);
};

View File

@ -1,111 +0,0 @@
#include "itemstore.h"
#include <QJsonArray>
#include <QDebug>
#include "train.h"
#include "../trainjs.h"
ItemStore::ItemStore(QObject *parent): QObject(parent)
{
}
void ItemStore::addItem(std::shared_ptr<Item> item)
{
if(!item)
{
qWarning()<<"invalid item";
return;
}
bool mached = false;
for(unsigned i = 0; i < items_.size(); i++ )
if(*items_[i] == *item) mached = true;
if(!mached)
{
items_.push_back(std::shared_ptr<Item>(item));
if(dynamic_cast<Train*>(item.get()))
{
std::vector<std::shared_ptr<TrainJs>> joysticks = TrainJs::getJsDevices();
for(auto joystick: joysticks)
{
if(!joystick->itemIsSet())
{
joystick->setItem(item);
connect(joystick.get(), &TrainJs::reqNewItem, this, &ItemStore::jsReqNewItem);
break;
}
}
}
itemAdded(std::weak_ptr<Item>(items_.back()));
}
qDebug()<<"Got item: "<<item->id()<<" matched: "<<mached;
}
void ItemStore::jsReqNewItem()
{
if(items_.empty())
return;
std::vector<std::shared_ptr<TrainJs>> joysticks = TrainJs::getJsDevices();
for(auto joystick: joysticks)
{
if(joystick->getWantsNewItem())
{
std::shared_ptr<Item> oldItem = joystick->getItem().lock();
for(size_t i = 0; i < items_.size(); ++i)
{
if(!oldItem || *items_[i] == *oldItem)
{
if(i+1 < items_.size())
joystick->setItem(items_[i+1]);
else
joystick->setItem(items_[0]);
break;
}
}
}
}
}
void ItemStore::addItems(const std::vector<std::shared_ptr<Item>>& itemIn)
{
for(unsigned j = 0; j < itemIn.size(); j++)
addItem(itemIn[j]);
}
void ItemStore::removeItem(const ItemData& item)
{
for(unsigned j = 0; j < items_.size(); j++)
{
if(item == *items_[j])
{
items_.erase(items_.begin()+j);
--j;
}
}
}
void ItemStore::clear()
{
for(size_t i = 0; i < items_.size(); ++i) itemDeleted(*items_[i]);
items_.clear();
}
void ItemStore::itemStateChanged(const ItemData& item)
{
for(unsigned i = 0; i < items_.size(); i++ )
{
if(items_[i]->operator==(item))
{
if(items_[i]->getValue() != item.getValue())items_[i]->informValue(item.getValue());
}
}
}

View File

@ -1,38 +0,0 @@
#pragma once
#include <vector>
#include <memory>
#include "item.h"
#include <QJsonObject>
class ItemStore: public QObject
{
Q_OBJECT
private:
std::vector< std::shared_ptr<Item> > items_;
public:
ItemStore(QObject *parent = nullptr);
virtual ~ItemStore(){}
inline std::vector< std::shared_ptr<Item> >* getItems(){ return &items_; }
void clear();
private slots:
void jsReqNewItem();
signals:
void itemDeleted(ItemData item);
void itemAdded(std::weak_ptr<Item> Item);
public slots:
void removeItem(const ItemData& item);
void addItem(std::shared_ptr<Item> item);
void addItems(const std::vector<std::shared_ptr<Item>>& itemsIn);
void itemStateChanged(const ItemData& item);
};

View File

@ -1,31 +0,0 @@
#include "train.h"
Train::Train(uint8_t id, uint8_t address, uint8_t functionMask, int8_t initalValue):
Item(address, QString("Train ")+QString::number(id), initalValue),
functionMask_(functionMask),
train_id_(id)
{
}
Microcontroller *Train::micro = nullptr;
void Train::setFunction(uint8_t funciton, bool value)
{
Item::setFunction(funciton, value);
if(micro)
micro->trainSetFunction(train_id_, funciton, value);
}
void Train::setValue(int8_t value)
{
Item::setValue(value);
if(micro)
micro->trainSetSpeed(train_id_, value);
}
void Train::reverse()
{
if(micro)
micro->trainReverse(train_id_);
}

View File

@ -1,26 +0,0 @@
#ifndef TRAIN_H
#define TRAIN_H
#include "item.h"
#include "../microcontroller.h"
class Train : public Item
{
Q_OBJECT
uint8_t functionMask_;
uint8_t train_id_;
public:
static Microcontroller *micro;
Train(uint8_t id = 0, uint8_t address = 0, uint8_t functionMask = 0, int8_t initalValue = 0);
uint8_t getFunctionMask() {return functionMask_;}
public slots:
void reverse();
virtual void setFunction(uint8_t function, bool on);
virtual void setValue(int8_t value);
uint8_t getTrainId(){return train_id_;}
};
#endif // TRAIN_H

View File

@ -1,111 +0,0 @@
#include <QtWidgets/QApplication>
#include <stdio.h>
#include <QDebug>
#include <QTcpSocket>
#include <QMessageBox>
#include <QtSerialPort/QtSerialPort>
#include <QtSerialPort/QSerialPortInfo>
#include <QCommandLineParser>
#include "microcontroller.h"
#include "trainjs.h"
#include "ui/mainwindow.h"
#include "items/itemstore.h"
#include "items/train.h"
#include "items/turnout.h"
#define BAUD QSerialPort::Baud38400
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
//set info
QCoreApplication::setOrganizationName("UVOS");
QCoreApplication::setOrganizationDomain("uvos.xyz");
QCoreApplication::setApplicationName("traincontrollerui");
QCoreApplication::setApplicationVersion("0.1");
QDir::setCurrent(a.applicationDirPath());
//parse comand line
QCommandLineParser parser;
parser.setApplicationDescription("Smart Home Interface");
parser.addHelpOption();
parser.addVersionOption();
QCommandLineOption tcpOption(QStringList() << "t" << "tcp", QCoreApplication::translate("main", "Use Tcp connection"));
parser.addOption(tcpOption);
QCommandLineOption hostOption(QStringList() << "H" << "host", QCoreApplication::translate("main", "Set server host ip addres"), "adress");
parser.addOption(hostOption);
QCommandLineOption portOption(QStringList() << "p" << "port", QCoreApplication::translate("main", "Set server Port in TCP mode or Serial port in serial mode"), "port");
parser.addOption(portOption);
QCommandLineOption serialOption(QStringList() << "s" << "serial", QCoreApplication::translate("main", "Use serial connection"));
parser.addOption(serialOption);
QCommandLineOption baudOption(QStringList() << "b" << "baud", QCoreApplication::translate("main", "Set Baud Rate"));
parser.addOption(baudOption);
parser.process(a);
QIODevice* masterIODevice = nullptr;
if(parser.isSet(tcpOption))
{
QTcpSocket* microSocket = new QTcpSocket;
int port = 6856;
if(parser.isSet(portOption)) port = parser.value(portOption).toInt();
QString host("127.0.0.1");
if(parser.isSet(hostOption)) host = parser.value(hostOption);
std::cout<<"connecting to "<<host.toStdString()<<':'<<port<<'\n';
microSocket->connectToHost(host, port, QIODevice::ReadWrite);
if(!microSocket->waitForConnected(3000))
{
std::cout<<"Can not connect to to Server.\n";
QMessageBox::critical(nullptr, "Error", "Can not connect to to Server");
return 1;
}
masterIODevice = microSocket;
}
else
{
QSerialPort* microPort = new QSerialPort;
if(parser.isSet(portOption)) microPort->setPortName(parser.value(portOption));
else microPort->setPortName("ttyUSB0");
if(parser.isSet(portOption)) microPort->setBaudRate(parser.value(baudOption).toInt());
else microPort->setBaudRate(BAUD);
if(!microPort->open(QIODevice::ReadWrite))
{
QMessageBox::critical(nullptr, "Error", QString("Can not open serial port ")+microPort->portName());
std::cout<<"Can not open serial port "<<microPort->portName().toStdString()<<". Continueing in demo mode"<<'\n';
return 1;
}
masterIODevice = microPort;
}
Microcontroller micro(masterIODevice);
micro.setPower(true);
TrainJs::init();
Train::micro = &micro;
Turnout::micro = &micro;
ItemStore items;
QObject::connect(&micro, &Microcontroller::gotItemList, &items, &ItemStore::addItems);
QObject::connect(&micro, &Microcontroller::itemChanged, &items, &ItemStore::itemStateChanged);
//mainwindow
MainWindow w(&micro, &items);
w.show();
int retVal = a.exec();
micro.setPower(false);
if(masterIODevice)
delete masterIODevice;
return retVal;
}

View File

@ -1,14 +0,0 @@
#include "mainobject.h"
MainObject::MainObject(QIODevice* ioDevice) :
masterIODevice(ioDevice),
micro(masterIODevice)
{
//connect item store
QObject::connect(&micro, &Microcontroller::gotItemList, &items, &ItemStore::addItems);
}
MainObject::~MainObject()
{
}

View File

@ -1,199 +0,0 @@
#include "microcontroller.h"
#include <chrono>
#include <thread>
#include "items/train.h"
#include "items/turnout.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());
}
void Microcontroller::trainReverse(uint8_t id)
{
std::stringstream ss;
ss<<"train "<<(unsigned)id<<" reverse\n";
write(ss.str().c_str());
}
void Microcontroller::trainSetFunction(uint8_t id, uint8_t function, bool on)
{
std::stringstream ss;
ss<<"train "<<(unsigned)id<<" function "<<(unsigned)function<<' '<<(on ? "on" : "off")<<'\n';
write(ss.str().c_str());
}
void Microcontroller::tunoutSetDirection(uint8_t id, bool direction)
{
std::stringstream ss;
ss<<"turnout "<<(unsigned)id<<" set "<<(!direction ? "left" : "right")<<'\n';
write(ss.str().c_str());
}
void Microcontroller::setPower(bool on)
{
write(on ? "power on\n" : "power off\n");
}
void Microcontroller::estop()
{
write("stop\n");
}
void Microcontroller::write(const QByteArray& buffer)
{
qDebug()<<buffer;
if(_port != nullptr)
{
_port->write(buffer);
_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);
//_port->waitForBytesWritten(1000);
}
std::this_thread::sleep_for(std::chrono::milliseconds(40));
}
bool Microcontroller::connected()
{
if(_port != nullptr)
return _port->isOpen();
else return false;
}
void Microcontroller::requestState()
{
write("train list\n");
write("turnout list\n");
}
//housekeeping
Microcontroller::Microcontroller(QIODevice* port)
{
setIODevice(port);
}
Microcontroller::Microcontroller()
{
}
Microcontroller::~Microcontroller()
{
}
void Microcontroller::setIODevice(QIODevice *port)
{
_port = port;
QObject::connect(_port, &QIODevice::readyRead, this, &Microcontroller::isReadyRead);
}
std::shared_ptr<Item> Microcontroller::processTrainLine(const QString& buffer)
{
QStringList bufferList = buffer.split(' ');
if(bufferList.size() >= 14 && buffer.startsWith("TRAIN NUMBER:"))
{
return std::shared_ptr<Item>(new Train(bufferList[2].toInt(), bufferList[4].toInt(), bufferList[13].toInt(nullptr, 2), bufferList[9].toInt()));
}
return nullptr;
}
std::shared_ptr<Item> Microcontroller::processTurnoutLine(const QString& buffer)
{
QStringList bufferList = buffer.split(' ');
if(bufferList.size() >= 11 && buffer.startsWith("TURNOUT NUMBER:"))
{
return std::shared_ptr<Item>(new Turnout(bufferList[2].toInt(), bufferList[4].toInt(), bufferList[6].toInt(), bufferList[11].toInt()));
}
return nullptr;
}
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;
if(listMode == TRAIN_LIST)
item = processTrainLine(buffer);
else if(listMode == TURNOUT_LIST)
item = processTurnoutLine(buffer);
if(item)
itemList.push_back(item);
}
else
{
listMode = false;
if(!itemList.empty())
{
qDebug()<<"got item list " << itemList.size();
gotItemList(itemList);
itemList.clear();
}
}
}
void Microcontroller::processItemState(const QString& buffer)
{
if(_buffer.startsWith("TRAIN NUMBER:"))
itemChanged(static_cast<ItemData>(*processTrainLine(buffer)));
else if(_buffer.startsWith("TURNOUT NUMBER:"))
itemChanged(static_cast<ItemData>(*processTurnoutLine(buffer)));
}
void Microcontroller::processMicroReturn()
{
if(listMode)
processList(_buffer);
else
{
if(_buffer.startsWith("Trains:"))
{
listMode = TRAIN_LIST;
itemList.clear();
}
else if(_buffer.startsWith("Turnouts:"))
{
listMode = TURNOUT_LIST;
}
else if(_buffer.startsWith("TRAIN NUMBER:") || _buffer.startsWith("TURNOUT NUMBER:"))
{
processItemState(_buffer);
}
else if(_buffer.startsWith("TrainController"))
{
requestState();
}
}
}
void Microcontroller::isReadyRead()
{
char charBuf;
while(_port->getChar(&charBuf))
{
_buffer.push_back(charBuf);
if( _buffer.endsWith('\n') )
{
_buffer.remove('\n');
processMicroReturn();
textRecived(_buffer);
_buffer.clear();
}
}
}

View File

@ -1,83 +0,0 @@
#ifndef MICROCONTROLLER_H
#define MICROCONTROLLER_H
#include <iostream>
#include <QObject>
#include <QColor>
#include <QIODevice>
#include <QString>
#include <QRunnable>
#include <QDebug>
#include <QEventLoop>
#include <QTimer>
#include <QAbstractButton>
#include <vector>
#include <memory>
#include <sstream>
#include "items/item.h"
class Microcontroller : public QObject
{
Q_OBJECT
public:
static constexpr char AMP_RELAY = 0;
static constexpr char SENSOR_TEMPERATURE = 1;
static constexpr char SENSOR_DOOR = 0 ;
private:
static constexpr int TRAIN_LIST = 1;
static constexpr int TURNOUT_LIST = 2;
int listMode = 0;
//uint8_t _auxState = 0;
QIODevice* _port = nullptr;
std::vector< std::shared_ptr<Item> > itemList;
QScopedPointer<QEventLoop> loop;
QString _buffer;
void processMicroReturn();
void processList(const QString& buffer);
void processItemState(const QString& buffer);
std::shared_ptr<Item> processTrainLine(const QString& buffer);
std::shared_ptr<Item> processTurnoutLine(const QString& buffer);
void write(char *buffer, const size_t length);
void write(const QByteArray& buffer);
public:
Microcontroller(QIODevice* port);
Microcontroller();
~Microcontroller();
bool connected();
void setIODevice(QIODevice* port);
public slots:
void requestState();
void trainSetSpeed(uint8_t id, int8_t speed);
void trainReverse(uint8_t id);
void trainSetFunction(uint8_t id, uint8_t function, bool on);
void tunoutSetDirection(uint8_t id, bool direction);
void estop();
void setPower(bool on);
private slots:
void isReadyRead();
signals:
void textRecived(const QString string);
void itemChanged(ItemData relay);
void auxStateChanged(int value);
void gotItemList(std::vector< std::shared_ptr<Item> >&);
};
#endif // MICROCONTROLLER_H

View File

@ -0,0 +1,28 @@
set(UI_SOURCES
traincontrollerui.cpp
mainobject.cpp
QJoysticks.cpp
trainjs.cpp
ui/itemscrollbox.cpp
ui/itemscrollbox.h
ui/itemwidget.cpp
ui/itemwidget.h
ui/mainwindow.cpp
ui/mainwindow.h
ui/mainwindow.ui
ui/relayscrollbox.ui
ui/signalwidget.cpp
ui/signalwidget.h
ui/signalwidget.ui
ui/trainwidget.cpp
ui/trainwidget.h
ui/trainwidget.ui
jsbackend/SDL_Joysticks.cpp
jsbackend/VirtualJoystick.cpp
)
find_package(SDL2 REQUIRED)
add_executable(traincontrollerui ${UI_SOURCES} ${COMMON_SOURCES})
target_link_libraries(traincontrollerui PRIVATE ${COMMON_LINK_LIBRARYS} Qt${QT_VERSION_MAJOR}::Widgets ${SDL2_LIBRARIES})
target_include_directories(traincontrollerui PRIVATE ./ ./ui ./jsbackend ${SDL2_INCLUDE_DIRS})

View File

@ -0,0 +1,479 @@
/*
* Copyright (c) 2015-2017 Alex Spataru <alex_spataru@outlook.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <QDebug>
#include <QSettings>
#include "QJoysticks.h"
#include "jsbackend/SDL_Joysticks.h"
#include "jsbackend/VirtualJoystick.h"
QJoysticks::QJoysticks()
{
/* Initialize input methods */
m_sdlJoysticks = new SDL_Joysticks(this);
m_virtualJoystick = new VirtualJoystick(this);
/* Configure SDL joysticks */
connect(sdlJoysticks(), &SDL_Joysticks::POVEvent, this, &QJoysticks::POVEvent);
connect(sdlJoysticks(), &SDL_Joysticks::axisEvent, this, &QJoysticks::axisEvent);
connect(sdlJoysticks(), &SDL_Joysticks::buttonEvent, this, &QJoysticks::buttonEvent);
connect(sdlJoysticks(), &SDL_Joysticks::countChanged, this, &QJoysticks::updateInterfaces);
/* Configure virtual joysticks */
connect(virtualJoystick(), &VirtualJoystick::povEvent, this, &QJoysticks::POVEvent);
connect(virtualJoystick(), &VirtualJoystick::axisEvent, this, &QJoysticks::axisEvent);
connect(virtualJoystick(), &VirtualJoystick::buttonEvent, this, &QJoysticks::buttonEvent);
connect(virtualJoystick(), &VirtualJoystick::enabledChanged, this, &QJoysticks::updateInterfaces);
/* React to own signals to create QML signals */
connect(this, &QJoysticks::POVEvent, this, &QJoysticks::onPOVEvent);
connect(this, &QJoysticks::axisEvent, this, &QJoysticks::onAxisEvent);
connect(this, &QJoysticks::buttonEvent, this, &QJoysticks::onButtonEvent);
/* Configure the settings */
m_sortJoyticks = 0;
m_settings = new QSettings(qApp->organizationName(), qApp->applicationName());
m_settings->beginGroup("Blacklisted Joysticks");
}
QJoysticks::~QJoysticks()
{
delete m_settings;
delete m_sdlJoysticks;
delete m_virtualJoystick;
}
/**
* Returns the one and only instance of this class
*/
QJoysticks *QJoysticks::getInstance()
{
static QJoysticks joysticks;
return &joysticks;
}
/**
* Returns the number of joysticks that are attached to the computer and/or
* registered with the \c QJoysticks system.
*
* \note This count also includes the virtual joystick (if its enabled)
*/
int QJoysticks::count() const
{
return inputDevices().count();
}
/**
* Returns the number of joysticks that are not blacklisted.
* This can be considered the "effective" number of joysticks.
*/
int QJoysticks::nonBlacklistedCount()
{
int cnt = count();
for (int i = 0; i < count(); ++i)
if (isBlacklisted(i))
--cnt;
return cnt;
}
/**
* Returns a list with the names of all registered joystick.
*
* \note This list also includes the blacklisted joysticks
* \note This list also includes the virtual joystick (if its enabled)
*/
QStringList QJoysticks::deviceNames() const
{
QStringList names;
foreach (QJoystickDevice *joystick, inputDevices())
names.append(joystick->name);
return names;
}
/**
* Returns the POV value for the given joystick \a index and \a pov ID
*/
int QJoysticks::getPOV(const int index, const int pov)
{
if (joystickExists(index))
return getInputDevice(index)->povs.at(pov);
return -1;
}
/**
* Returns the axis value for the given joystick \a index and \a axis ID
*/
double QJoysticks::getAxis(const int index, const int axis)
{
if (joystickExists(index))
return getInputDevice(index)->axes.at(axis);
return 0;
}
/**
* Returns the button value for the given joystick \a index and \a button ID
*/
bool QJoysticks::getButton(const int index, const int button)
{
if (joystickExists(index))
return getInputDevice(index)->buttons.at(button);
return false;
}
/**
* Returns the number of axes that the joystick at the given \a index has.
*/
int QJoysticks::getNumAxes(const int index)
{
if (joystickExists(index))
return getInputDevice(index)->axes.count();
return -1;
}
/**
* Returns the number of POVs that the joystick at the given \a index has.
*/
int QJoysticks::getNumPOVs(const int index)
{
if (joystickExists(index))
return getInputDevice(index)->povs.count();
return -1;
}
/**
* Returns the number of buttons that the joystick at the given \a index has.
*/
int QJoysticks::getNumButtons(const int index)
{
if (joystickExists(index))
return getInputDevice(index)->buttons.count();
return -1;
}
/**
* Returns \c true if the joystick at the given \a index is blacklisted.
*/
bool QJoysticks::isBlacklisted(const int index)
{
if (joystickExists(index))
return inputDevices().at(index)->blacklisted;
return true;
}
/**
* Returns \c true if the joystick at the given \a index is valid, otherwise,
* the function returns \c false and warns the user through the console.
*/
bool QJoysticks::joystickExists(const int index)
{
return (index >= 0) && (count() > index);
}
/**
* Returns the name of the given joystick
*/
QString QJoysticks::getName(const int index)
{
if (joystickExists(index))
return m_devices.at(index)->name;
return "Invalid Joystick";
}
/**
* Returns a pointer to the SDL joysticks system.
* This can be used if you need to get more information regarding the joysticks
* registered and managed with SDL.
*/
SDL_Joysticks *QJoysticks::sdlJoysticks() const
{
return m_sdlJoysticks;
}
/**
* Returns a pointer to the virtual joystick system.
* This can be used if you need to get more information regarding the virtual
* joystick or want to change its properties directly.
*
* \note You can also change the properties of the virtual joysticks using the
* functions of the \c QJoysticks system class
*/
VirtualJoystick *QJoysticks::virtualJoystick() const
{
return m_virtualJoystick;
}
/**
* Returns a pointer to the device at the given \a index.
*/
QJoystickDevice *QJoysticks::getInputDevice(const int index)
{
if (joystickExists(index))
return inputDevices().at(index);
return Q_NULLPTR;
}
/**
* Returns a pointer to a list containing all registered joysticks.
* This can be used for advanced hacks or just to get all properties of each
* joystick.
*/
QList<QJoystickDevice *> QJoysticks::inputDevices() const
{
return m_devices;
}
/**
* If \a sort is set to true, then the device list will put all blacklisted
* joysticks at the end of the list
*/
void QJoysticks::setSortJoysticksByBlacklistState(bool sort)
{
if (m_sortJoyticks != sort)
{
m_sortJoyticks = sort;
updateInterfaces();
}
}
/**
* Blacklists or whitelists the joystick at the given \a index.
*
* \note This function does not have effect if the given joystick does not exist
* \note Once the joystick is blacklisted, the joystick list will be updated
*/
void QJoysticks::setBlacklisted(const int index, bool blacklisted)
{
Q_ASSERT(joystickExists(index));
/* Netrualize the joystick */
if (blacklisted)
{
for (int i = 0; i < getNumAxes(index); ++i)
emit axisChanged(index, i, 0);
for (int i = 0; i < getNumButtons(index); ++i)
emit buttonChanged(index, i, false);
for (int i = 0; i < getNumPOVs(index); ++i)
emit povChanged(index, i, 0);
}
/* See if blacklist value was actually changed */
bool changed = m_devices.at(index)->blacklisted != blacklisted;
/* Save settings */
m_devices.at(index)->blacklisted = blacklisted;
m_settings->setValue(getName(index), blacklisted);
/* Re-scan joysticks if blacklist value has changed */
if (changed)
updateInterfaces();
}
/**
* 'Rescans' for new/removed joysticks and registers them again.
*/
void QJoysticks::updateInterfaces()
{
m_devices.clear();
/* Put blacklisted joysticks at the bottom of the list */
if (m_sortJoyticks)
{
/* Register non-blacklisted SDL joysticks */
foreach (QJoystickDevice *joystick, sdlJoysticks()->joysticks())
{
joystick->blacklisted = m_settings->value(joystick->name, false).toBool();
if (!joystick->blacklisted)
addInputDevice(joystick);
}
/* Register the virtual joystick (if its not blacklisted) */
if (virtualJoystick()->joystickEnabled())
{
QJoystickDevice *joystick = virtualJoystick()->joystick();
joystick->blacklisted = m_settings->value(joystick->name, false).toBool();
if (!joystick->blacklisted)
{
addInputDevice(joystick);
virtualJoystick()->setJoystickID(inputDevices().count() - 1);
}
}
/* Register blacklisted SDL joysticks */
foreach (QJoystickDevice *joystick, sdlJoysticks()->joysticks())
{
joystick->blacklisted = m_settings->value(joystick->name, false).toBool();
if (joystick->blacklisted)
addInputDevice(joystick);
}
/* Register the virtual joystick (if its blacklisted) */
if (virtualJoystick()->joystickEnabled())
{
QJoystickDevice *joystick = virtualJoystick()->joystick();
joystick->blacklisted = m_settings->value(joystick->name, false).toBool();
if (joystick->blacklisted)
{
addInputDevice(joystick);
virtualJoystick()->setJoystickID(inputDevices().count() - 1);
}
}
}
/* Sort normally */
else
{
/* Register SDL joysticks */
foreach (QJoystickDevice *joystick, sdlJoysticks()->joysticks())
{
addInputDevice(joystick);
joystick->blacklisted = m_settings->value(joystick->name, false).toBool();
}
/* Register virtual joystick */
if (virtualJoystick()->joystickEnabled())
{
QJoystickDevice *joystick = virtualJoystick()->joystick();
joystick->blacklisted = m_settings->value(joystick->name, false).toBool();
addInputDevice(joystick);
virtualJoystick()->setJoystickID(inputDevices().count() - 1);
}
}
emit countChanged();
}
/**
* Changes the axis value range of the virtual joystick.
*
* Take into account that maximum axis values supported by the \c QJoysticks
* system is from \c -1 to \c 1.
*/
void QJoysticks::setVirtualJoystickRange(qreal range)
{
virtualJoystick()->setAxisRange(range);
}
/**
* Enables or disables the virtual joystick
*/
void QJoysticks::setVirtualJoystickEnabled(bool enabled)
{
virtualJoystick()->setJoystickEnabled(enabled);
}
void QJoysticks::setVirtualJoystickAxisSensibility(qreal sensibility)
{
virtualJoystick()->setAxisSensibility(sensibility);
}
/**
* Removes all the registered joysticks and emits appropriate signals.
*/
void QJoysticks::resetJoysticks()
{
m_devices.clear();
emit countChanged();
}
/**
* Registers the given \a device to the \c QJoysticks system
*/
void QJoysticks::addInputDevice(QJoystickDevice *device)
{
Q_ASSERT(device);
m_devices.append(device);
}
/**
* Configures the QML-friendly signal based on the information given by the
* \a event data and updates the joystick values
*/
void QJoysticks::onPOVEvent(const QJoystickPOVEvent &e)
{
if (e.joystick == nullptr)
return;
if (!isBlacklisted(e.joystick->id))
{
if (e.pov < getInputDevice(e.joystick->id)->povs.count())
{
getInputDevice(e.joystick->id)->povs[e.pov] = e.angle;
emit povChanged(e.joystick->id, e.pov, e.angle);
}
}
}
/**
* Configures the QML-friendly signal based on the information given by the
* \a event data and updates the joystick values
*/
void QJoysticks::onAxisEvent(const QJoystickAxisEvent &e)
{
if (e.joystick == nullptr)
return;
if (!isBlacklisted(e.joystick->id))
{
if (e.axis < getInputDevice(e.joystick->id)->axes.count())
{
getInputDevice(e.joystick->id)->axes[e.axis] = e.value;
emit axisChanged(e.joystick->id, e.axis, e.value);
}
}
}
/**
* Configures the QML-friendly signal based on the information given by the
* \a event data and updates the joystick values
*/
void QJoysticks::onButtonEvent(const QJoystickButtonEvent &e)
{
if (e.joystick == nullptr)
return;
if (!isBlacklisted(e.joystick->id))
{
if (e.button < getInputDevice(e.joystick->id)->buttons.count())
{
getInputDevice(e.joystick->id)->buttons[e.button] = e.pressed;
emit buttonChanged(e.joystick->id, e.button, e.pressed);
}
}
}

View File

@ -50,73 +50,73 @@ class VirtualJoystick;
*/
class QJoysticks : public QObject
{
Q_OBJECT
Q_PROPERTY(int count READ count NOTIFY countChanged)
Q_PROPERTY(int nonBlacklistedCount READ nonBlacklistedCount NOTIFY countChanged)
Q_PROPERTY(QStringList deviceNames READ deviceNames NOTIFY countChanged)
Q_OBJECT
Q_PROPERTY(int count READ count NOTIFY countChanged)
Q_PROPERTY(int nonBlacklistedCount READ nonBlacklistedCount NOTIFY countChanged)
Q_PROPERTY(QStringList deviceNames READ deviceNames NOTIFY countChanged)
friend class Test_QJoysticks;
friend class Test_QJoysticks;
signals:
void countChanged();
void enabledChanged(const bool enabled);
void POVEvent(const QJoystickPOVEvent &event);
void axisEvent(const QJoystickAxisEvent &event);
void buttonEvent(const QJoystickButtonEvent &event);
void povChanged(const int js, const int pov, const int angle);
void axisChanged(const int js, const int axis, const qreal value);
void buttonChanged(const int js, const int button, const bool pressed);
void countChanged();
void enabledChanged(const bool enabled);
void POVEvent(const QJoystickPOVEvent &event);
void axisEvent(const QJoystickAxisEvent &event);
void buttonEvent(const QJoystickButtonEvent &event);
void povChanged(const int js, const int pov, const int angle);
void axisChanged(const int js, const int axis, const qreal value);
void buttonChanged(const int js, const int button, const bool pressed);
public:
static QJoysticks *getInstance();
static QJoysticks *getInstance();
int count() const;
int nonBlacklistedCount();
QStringList deviceNames() const;
int count() const;
int nonBlacklistedCount();
QStringList deviceNames() const;
Q_INVOKABLE int getPOV(const int index, const int pov);
Q_INVOKABLE double getAxis(const int index, const int axis);
Q_INVOKABLE bool getButton(const int index, const int button);
Q_INVOKABLE int getPOV(const int index, const int pov);
Q_INVOKABLE double getAxis(const int index, const int axis);
Q_INVOKABLE bool getButton(const int index, const int button);
Q_INVOKABLE int getNumAxes(const int index);
Q_INVOKABLE int getNumPOVs(const int index);
Q_INVOKABLE int getNumButtons(const int index);
Q_INVOKABLE bool isBlacklisted(const int index);
Q_INVOKABLE bool joystickExists(const int index);
Q_INVOKABLE QString getName(const int index);
Q_INVOKABLE int getNumAxes(const int index);
Q_INVOKABLE int getNumPOVs(const int index);
Q_INVOKABLE int getNumButtons(const int index);
Q_INVOKABLE bool isBlacklisted(const int index);
Q_INVOKABLE bool joystickExists(const int index);
Q_INVOKABLE QString getName(const int index);
SDL_Joysticks *sdlJoysticks() const;
VirtualJoystick *virtualJoystick() const;
QJoystickDevice *getInputDevice(const int index);
QList<QJoystickDevice *> inputDevices() const;
SDL_Joysticks *sdlJoysticks() const;
VirtualJoystick *virtualJoystick() const;
QJoystickDevice *getInputDevice(const int index);
QList<QJoystickDevice *> inputDevices() const;
public slots:
void updateInterfaces();
void setVirtualJoystickRange(qreal range);
void setVirtualJoystickEnabled(bool enabled);
void setVirtualJoystickAxisSensibility(qreal sensibility);
void setSortJoysticksByBlacklistState(bool sort);
void setBlacklisted(int index, bool blacklisted);
void updateInterfaces();
void setVirtualJoystickRange(qreal range);
void setVirtualJoystickEnabled(bool enabled);
void setVirtualJoystickAxisSensibility(qreal sensibility);
void setSortJoysticksByBlacklistState(bool sort);
void setBlacklisted(int index, bool blacklisted);
protected:
explicit QJoysticks();
~QJoysticks();
explicit QJoysticks();
~QJoysticks();
private slots:
void resetJoysticks();
void addInputDevice(QJoystickDevice *device);
void onPOVEvent(const QJoystickPOVEvent &e);
void onAxisEvent(const QJoystickAxisEvent &e);
void onButtonEvent(const QJoystickButtonEvent &e);
void resetJoysticks();
void addInputDevice(QJoystickDevice *device);
void onPOVEvent(const QJoystickPOVEvent &e);
void onAxisEvent(const QJoystickAxisEvent &e);
void onButtonEvent(const QJoystickButtonEvent &e);
private:
bool m_sortJoyticks;
bool m_sortJoyticks;
QSettings *m_settings;
SDL_Joysticks *m_sdlJoysticks;
VirtualJoystick *m_virtualJoystick;
QSettings *m_settings;
SDL_Joysticks *m_sdlJoysticks;
VirtualJoystick *m_virtualJoystick;
QList<QJoystickDevice *> m_devices;
QList<QJoystickDevice *> m_devices;
};
#endif

View File

@ -44,7 +44,7 @@ SDL_Joysticks::SDL_Joysticks(QObject *parent)
for (int i = 0; i < count; ++i)
configureJoystick(i);
QTimer::singleShot(100, Qt::PreciseTimer, this, SLOT(update()));
QTimer::singleShot(10, Qt::PreciseTimer, this, SLOT(update()));
}
SDL_Joysticks::~SDL_Joysticks()

View File

@ -0,0 +1,14 @@
#include "mainobject.h"
MainObject::MainObject(QIODevice* ioDevice) :
masterIODevice(ioDevice),
micro(masterIODevice)
{
//connect item store
QObject::connect(&micro, &Microcontroller::gotItemList, &items, &ItemStore::addItems);
}
MainObject::~MainObject()
{
}

View File

@ -7,9 +7,6 @@
#include <QDebug>
#include <QString>
#include <QTcpSocket>
#include <QFileInfo>
#include <QJsonDocument>
#include <QStandardPaths>
#include <memory>
@ -22,26 +19,25 @@
#include "microcontroller.h"
#include "ui/mainwindow.h"
#include "items/itemstore.h"
#include "items/auxitem.h"
class MainObject : public QObject
{
Q_OBJECT
Q_OBJECT
public:
//io
QIODevice * const masterIODevice = nullptr;
//io
QIODevice * const masterIODevice = nullptr;
Microcontroller micro;
Microcontroller micro;
const QString settingsPath;
const QString settingsPath;
//items
ItemStore items;
//items
ItemStore items;
public:
explicit MainObject(QIODevice* ioDevice);
~MainObject();
explicit MainObject(QIODevice* ioDevice);
~MainObject();
};
#endif // MAINOBJECT_H

View File

@ -0,0 +1,116 @@
#include <QtWidgets/QApplication>
#include <stdio.h>
#include <QDebug>
#include <QTcpSocket>
#include <QMessageBox>
#include <QtSerialPort/QtSerialPort>
#include <QtSerialPort/QSerialPortInfo>
#include <QCommandLineParser>
#include "microcontroller.h"
#include "trainjs.h"
#include "ui/mainwindow.h"
#include "itemstore.h"
#include "train.h"
#include "turnout.h"
#include "trainsignal.h"
#define BAUD QSerialPort::Baud38400
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
//set info
QCoreApplication::setOrganizationName("UVOS");
QCoreApplication::setOrganizationDomain("uvos.xyz");
QCoreApplication::setApplicationName("traincontrollerui");
QCoreApplication::setApplicationVersion("0.1");
QDir::setCurrent(a.applicationDirPath());
//parse comand line
QCommandLineParser parser;
parser.setApplicationDescription("Train control gui");
parser.addHelpOption();
parser.addVersionOption();
QCommandLineOption tcpOption(QStringList() << "t" << "tcp", QCoreApplication::translate("main", "Use Tcp connection"));
parser.addOption(tcpOption);
QCommandLineOption hostOption(QStringList() << "H" << "host", QCoreApplication::translate("main",
"Set server host ip addres"), "adress");
parser.addOption(hostOption);
QCommandLineOption portOption(QStringList() << "p" << "port", QCoreApplication::translate("main",
"Set server Port in TCP mode or Serial port in serial mode"), "port");
parser.addOption(portOption);
QCommandLineOption serialOption(QStringList() << "s" << "serial", QCoreApplication::translate("main",
"Use serial connection"));
parser.addOption(serialOption);
QCommandLineOption baudOption(QStringList() << "b" << "baud", QCoreApplication::translate("main", "Set Baud Rate"));
parser.addOption(baudOption);
parser.process(a);
QIODevice* masterIODevice = nullptr;
if(parser.isSet(tcpOption))
{
QTcpSocket* microSocket = new QTcpSocket;
int port = 6856;
if(parser.isSet(portOption)) port = parser.value(portOption).toInt();
QString host("127.0.0.1");
if(parser.isSet(hostOption)) host = parser.value(hostOption);
std::cout<<"connecting to "<<host.toStdString()<<':'<<port<<'\n';
microSocket->connectToHost(host, port, QIODevice::ReadWrite);
if(!microSocket->waitForConnected(3000))
{
std::cout<<"Can not connect to to Server.\n";
QMessageBox::critical(nullptr, "Error", "Can not connect to to Server");
return 1;
}
masterIODevice = microSocket;
}
else
{
QSerialPort* microPort = new QSerialPort;
if(parser.isSet(portOption)) microPort->setPortName(parser.value(portOption));
else microPort->setPortName("ttyUSB0");
if(parser.isSet(portOption)) microPort->setBaudRate(parser.value(baudOption).toInt());
else microPort->setBaudRate(BAUD);
if(!microPort->open(QIODevice::ReadWrite))
{
QMessageBox::critical(nullptr, "Error", QString("Can not open serial port ")+microPort->portName());
std::cout<<"Can not open serial port "<<microPort->portName().toStdString()<<". Continueing in demo mode"<<'\n';
return 1;
}
masterIODevice = microPort;
}
Microcontroller micro(masterIODevice);
micro.setPower(true);
TrainJs::init();
Train::micro = &micro;
Turnout::micro = &micro;
Signal::micro = &micro;
ItemStore items;
QObject::connect(&micro, &Microcontroller::gotItemList, &items, &ItemStore::addItems);
QObject::connect(&micro, &Microcontroller::itemChanged, &items, &ItemStore::itemStateChanged);
//mainwindow
MainWindow w(&micro, &items);
w.show();
int retVal = a.exec();
micro.setPower(false);
if(masterIODevice)
delete masterIODevice;
return retVal;
}

View File

@ -41,7 +41,10 @@ public:
std::weak_ptr<Item> getItem();
void setItem(std::weak_ptr<Item>);
bool itemIsSet();
bool getWantsNewItem() {return wantsNewItem;}
bool getWantsNewItem()
{
return wantsNewItem;
}
};
#endif // TRAINJS_H

View File

@ -0,0 +1,140 @@
#include "itemscrollbox.h"
#include "ui_relayscrollbox.h"
#include "ui_relayscrollbox.h"
#include "train.h"
#include "turnout.h"
#include "trainsignal.h"
#include "trainjs.h"
#include "trainwidget.h"
#include "signalwidget.h"
ItemScrollBox::ItemScrollBox(QWidget *parent) :
QWidget(parent),
ui(new Ui::RelayScrollBox)
{
ui->setupUi(this);
QScroller::grabGesture(ui->scrollArea, QScroller::TouchGesture);
QScroller::grabGesture(ui->scrollArea, QScroller::LeftMouseButtonGesture);
}
ItemScrollBox::~ItemScrollBox()
{
delete ui;
}
void ItemScrollBox::addItem(std::weak_ptr<Item> item)
{
if(auto workItem = item.lock())
{
Train* train = dynamic_cast<Train*>(workItem.get());
Turnout* turnout = dynamic_cast<Turnout*>(workItem.get());
Signal* signal = dynamic_cast<Signal*>(workItem.get());
if(train)
{
TrainWidget *widget = new TrainWidget(item, this);
widgets_.push_back(widget);
if(train->getTrainId() == 0)
widget->setShortcuts(QKeySequence(Qt::Key_Q), QKeySequence(Qt::Key_A), QKeySequence(Qt::Key_Z));
else if(train->getTrainId() == 1)
widget->setShortcuts(QKeySequence(Qt::Key_W), QKeySequence(Qt::Key_S), QKeySequence(Qt::Key_X));
else if(train->getTrainId() == 2)
widget->setShortcuts(QKeySequence(Qt::Key_E), QKeySequence(Qt::Key_D), QKeySequence(Qt::Key_C));
else if(train->getTrainId() == 3)
widget->setShortcuts(QKeySequence(Qt::Key_R), QKeySequence(Qt::Key_F), QKeySequence(Qt::Key_V));
else if(train->getTrainId() == 4)
widget->setShortcuts(QKeySequence(Qt::Key_T), QKeySequence(Qt::Key_G), QKeySequence(Qt::Key_B));
std::vector<std::shared_ptr<TrainJs>> joysticks = TrainJs::getJsDevices();
for(auto joystick: joysticks)
{
if(!joystick->itemIsSet())
{
joystick->setItem(item);
connect(joystick.get(), &TrainJs::reqNewItem, this, &ItemScrollBox::jsReqNewItem);
break;
}
}
}
else if(turnout)
{
TrainWidget *widget = new TrainWidget(item, this);
widgets_.push_back(widget);
if(turnout->getTurnoutId() == 0)
widget->setShortcuts(QKeySequence(), QKeySequence(), QKeySequence(Qt::Key_1));
else if(turnout->getTurnoutId() == 1)
widget->setShortcuts(QKeySequence(), QKeySequence(), QKeySequence(Qt::Key_2));
else if(turnout->getTurnoutId() == 2)
widget->setShortcuts(QKeySequence(), QKeySequence(), QKeySequence(Qt::Key_3));
else if(turnout->getTurnoutId() == 3)
widget->setShortcuts(QKeySequence(), QKeySequence(), QKeySequence(Qt::Key_4));
else if(turnout->getTurnoutId() == 4)
widget->setShortcuts(QKeySequence(), QKeySequence(), QKeySequence(Qt::Key_5));
else if(turnout->getTurnoutId() == 5)
widget->setShortcuts(QKeySequence(), QKeySequence(), QKeySequence(Qt::Key_6));
else if(turnout->getTurnoutId() == 6)
widget->setShortcuts(QKeySequence(), QKeySequence(), QKeySequence(Qt::Key_7));
else if(turnout->getTurnoutId() == 7)
widget->setShortcuts(QKeySequence(), QKeySequence(), QKeySequence(Qt::Key_8));
else if(turnout->getTurnoutId() == 8)
widget->setShortcuts(QKeySequence(), QKeySequence(), QKeySequence(Qt::Key_9));
else if(turnout->getTurnoutId() == 9)
widget->setShortcuts(QKeySequence(), QKeySequence(), QKeySequence(Qt::Key_0));
}
else if(signal)
{
SignalWidget *widget = new SignalWidget(item, this);
widgets_.push_back(widget);
}
ui->relayWidgetVbox->addWidget(widgets_.back());
connect(widgets_.back(), &ItemWidget::deleteRequest, this, &ItemScrollBox::deleteRequest);
connect(widgets_.back(), &ItemWidget::deleteRequest, this, &ItemScrollBox::removeItem);
}
}
void ItemScrollBox::jsReqNewItem()
{
if(widgets_.empty())
return;
std::vector<std::shared_ptr<TrainJs>> joysticks = TrainJs::getJsDevices();
for(auto joystick: joysticks)
{
if(joystick->getWantsNewItem())
{
std::shared_ptr<Item> oldItem = joystick->getItem().lock();
for(size_t i = 0; i < widgets_.size(); ++i)
{
std::shared_ptr<Item> item = widgets_[i]->getItem().lock();
if(item && (!oldItem || *item == *oldItem))
{
for(size_t j = 1; j < widgets_.size(); ++j)
{
ItemWidget* widget = widgets_[(i+j) % widgets_.size()];
std::shared_ptr<Item> item = widgets_[i]->getItem().lock();
if(item && dynamic_cast<Train*>(item.get()))
{
joystick->setItem(item);
break;
}
}
break;
}
}
}
}
}
void ItemScrollBox::removeItem(const ItemData& item)
{
for(unsigned i = 0; i < widgets_.size(); i++)
{
if(widgets_[i]->controles(item))
{
ui->relayWidgetVbox->removeWidget(widgets_[i]);
delete widgets_[i];
widgets_.erase(widgets_.begin()+i);
}
}
}

View File

@ -10,32 +10,32 @@
#include "../items/itemstore.h"
namespace Ui {
namespace Ui
{
class RelayScrollBox;
}
class ItemScrollBox : public QWidget
{
Q_OBJECT
Q_OBJECT
private:
std::vector< ItemWidget* > widgets_;
std::vector< ItemWidget* > widgets_;
signals:
void deleteRequest(const ItemData& item);
void deleteRequest(const ItemData& item);
public:
explicit ItemScrollBox(QWidget *parent = nullptr);
~ItemScrollBox();
void setItemStore(ItemStore* itemStore);
explicit ItemScrollBox(QWidget *parent = nullptr);
~ItemScrollBox();
public slots:
void addItem(std::weak_ptr<Item> item);
void removeItem(const ItemData& item);
void addItem(std::weak_ptr<Item> item);
void removeItem(const ItemData& item);
void jsReqNewItem();
private:
Ui::RelayScrollBox *ui;
Ui::RelayScrollBox *ui;
};
#endif // RELAYSCROLLBOX_H

View File

@ -0,0 +1,36 @@
#include "itemwidget.h"
#include <QCheckBox>
#include <QDebug>
#include <QSlider>
#include "../items/train.h"
#include "../items/turnout.h"
ItemWidget::ItemWidget(std::weak_ptr<Item> item, QWidget *parent) :
QWidget(parent),
item_(item)
{
qDebug()<<__func__<<" "<<(bool)item_.lock();
}
bool ItemWidget::controles(const ItemData& relay)
{
if(auto workingRelay = item_.lock())
{
if(relay == *workingRelay)
return true;
else
return false;
}
return true;
}
std::weak_ptr<Item> ItemWidget::getItem()
{
return item_;
}
ItemWidget::~ItemWidget()
{
}

View File

@ -0,0 +1,30 @@
#pragma once
#include <QWidget>
#include <memory>
#include <QShortcut>
#include "../items/item.h"
class ItemWidget : public QWidget
{
Q_OBJECT
protected:
std::weak_ptr<Item> item_;
virtual void disable(){}
signals:
void deleteRequest(const ItemData& item);
public:
explicit ItemWidget(std::weak_ptr<Item> item, QWidget *parent);
std::weak_ptr<Item> getItem();
bool controles(const ItemData& relay);
~ItemWidget();
public slots:
virtual void stateChanged(int state){(void)state;}
};

View File

@ -0,0 +1,45 @@
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "itemscrollbox.h"
MainWindow::MainWindow(Microcontroller * const micro, ItemStore* items, QWidget *parent) :
QMainWindow(parent),
stopShort(QKeySequence(Qt::Key_Space), this),
ui(new Ui::MainWindow),
_micro(micro)
{
ui->setupUi(this);
connect(&stopShort, &QShortcut::activated, _micro, &Microcontroller::estop);
connect(ui->pushButton_stop, &QPushButton::clicked, _micro, &Microcontroller::estop);
connect(ui->pushButton_refesh, &QPushButton::clicked, _micro, &Microcontroller::requestState);
connect(items, &ItemStore::itemAdded, ui->relayList, &ItemScrollBox::addItem);
connect(items, &ItemStore::itemDeleted, ui->relayList, &ItemScrollBox::removeItem);
for(size_t i = 0; i < items->getItems()->size(); ++i)
{
ui->relayList->addItem(items->getItems()->at(i));
}
connect(ui->relayList, &ItemScrollBox::deleteRequest, items, &ItemStore::removeItem);
ui->pushButton_addItem->hide();
}
MainWindow::~MainWindow()
{
delete ui;
}
/*
void MainWindow::showItemCreationDialog()
{
ItemCreationDialog diag(this);
diag.show();
if(diag.exec())
{
createdItem(diag.item);
}
}
*/

View File

@ -20,25 +20,25 @@ class MainWindow;
class MainWindow : public QMainWindow
{
Q_OBJECT
QShortcut stopShort;
Q_OBJECT
QShortcut stopShort;
public:
explicit MainWindow(Microcontroller * const micro, ItemStore* items, QWidget *parent = nullptr);
~MainWindow();
explicit MainWindow(Microcontroller * const micro, ItemStore* items, QWidget *parent = nullptr);
~MainWindow();
private:
Ui::MainWindow *ui;
Ui::MainWindow *ui;
Microcontroller *_micro;
Microcontroller *_micro;
signals:
void createdItem(std::shared_ptr<Item> item);
void createdItem(std::shared_ptr<Item> item);
private slots:
//void showItemCreationDialog();
//void showItemCreationDialog();
};

View File

@ -0,0 +1,96 @@
#include "signalwidget.h"
#include "ui_signalwidget.h"
#include <QDebug>
#include <QRadioButton>
#include <memory>
#include "trainsignal.h"
SignalWidget::SignalWidget(std::weak_ptr<Item> item, QWidget *parent) :
ItemWidget(item, parent),
ui(new Ui::SignalWidget)
{
ui->setupUi(this);
if(auto workingItem = item_.lock())
{
std::shared_ptr<Signal> signal = std::dynamic_pointer_cast<Signal>(workingItem);
if(signal)
{
ui->label->setText(workingItem->getName());
connect(ui->radioButton_go, &QRadioButton::clicked, this, [this]()
{
setValue(Signal::GO);
});
connect(ui->radioButton_slow, &QRadioButton::clicked, this, [this]()
{
setValue(Signal::SLOW);
});
connect(ui->radioButton_stop, &QRadioButton::clicked, this, [this]()
{
setValue(Signal::STOP);
});
connect(signal.get(), &Item::valueChanged, this, &SignalWidget::moveToValue);
if(!signal->hasSlow())
ui->radioButton_slow->hide();
}
}
else
{
qWarning("SignalWidget got invalid item");
SignalWidget::disable();
}
}
void SignalWidget::deleteItem()
{
if(auto workingItem = item_.lock())
{
deleteRequest(*workingItem);
}
}
void SignalWidget::setValue(int8_t value)
{
if(auto workingItem = item_.lock())
workingItem->setValue(value);
else
disable();
}
void SignalWidget::moveToValue(int8_t value)
{
qDebug()<<"got value"<<value;
ui->radioButton_go->blockSignals(true);
ui->radioButton_slow->blockSignals(true);
ui->radioButton_stop->blockSignals(true);
ui->radioButton_go->setChecked(value == Signal::GO);
ui->radioButton_slow->setChecked(value == Signal::SLOW);
ui->radioButton_stop->setChecked(value == Signal::STOP);
ui->radioButton_go->blockSignals(false);
ui->radioButton_slow->blockSignals(false);
ui->radioButton_stop->blockSignals(false);
}
void SignalWidget::disable()
{
ui->radioButton_go->setEnabled(false);
ui->radioButton_slow->setEnabled(false);
ui->radioButton_stop->setEnabled(false);
}
void SignalWidget::stateChanged(int state)
{
moveToValue(state);
}
SignalWidget::~SignalWidget()
{
delete ui;
}

View File

@ -0,0 +1,36 @@
#pragma once
#include <QWidget>
#include <memory>
#include <QShortcut>
#include "../items/trainsignal.h"
#include "itemwidget.h"
namespace Ui
{
class SignalWidget;
}
class SignalWidget : public ItemWidget
{
Q_OBJECT
protected:
virtual void disable();
private slots:
void moveToValue(int8_t value);
void setValue(int8_t value);
void deleteItem();
public:
explicit SignalWidget(std::weak_ptr<Item> item, QWidget *parent);
~SignalWidget();
public slots:
virtual void stateChanged(int state);
private:
Ui::SignalWidget *ui;
};

View File

@ -0,0 +1,98 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>SignalWidget</class>
<widget class="QWidget" name="SignalWidget">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>312</width>
<height>78</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<property name="spacing">
<number>0</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<property name="spacing">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>TextLabel</string>
</property>
</widget>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QRadioButton" name="radioButton_go">
<property name="text">
<string>Go</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="radioButton_slow">
<property name="text">
<string>Slow</string>
</property>
<property name="checked">
<bool>false</bool>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="radioButton_stop">
<property name="text">
<string>Stop</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
</layout>
</item>
<item>
<widget class="Line" name="line_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

View File

@ -0,0 +1,194 @@
#include "trainwidget.h"
#include "ui_trainwidget.h"
#include <QCheckBox>
#include <QDebug>
#include <QSlider>
#include "../items/train.h"
#include "../items/turnout.h"
TrainWidget::TrainWidget(std::weak_ptr<Item> item, QWidget *parent) :
ItemWidget(item, parent),
ui(new Ui::TrainWidget)
{
ui->setupUi(this);
if(auto workingItem = item_.lock())
{
ui->label->setText(workingItem->getName());
connect(ui->slider, &QSlider::valueChanged, this, &TrainWidget::setValue);
connect(ui->checkBox_f1, &QCheckBox::stateChanged, this, &TrainWidget::f1);
connect(ui->checkBox_f2, &QCheckBox::stateChanged, this, &TrainWidget::f2);
connect(ui->checkBox_f3, &QCheckBox::stateChanged, this, &TrainWidget::f3);
connect(ui->checkBox_f4, &QCheckBox::stateChanged, this, &TrainWidget::f4);
connect(ui->pushButton_reverse, &QPushButton::clicked, this, &TrainWidget::reverse);
connect(ui->radioButton_left, &QRadioButton::clicked, this, [this]()
{
setValue(0);
});
connect(ui->radioButton_right, &QRadioButton::clicked, this, [this]()
{
setValue(1);
});
connect(workingItem.get(), &Item::valueChanged, this, &TrainWidget::moveToValue);
Train* train = dynamic_cast<Train*>(workingItem.get());
Turnout* turnout = dynamic_cast<Turnout*>(workingItem.get());
if(turnout)
{
ui->checkBox_f1->hide();
ui->checkBox_f2->hide();
ui->checkBox_f3->hide();
ui->checkBox_f4->hide();
ui->slider->hide();
}
if(!train)
{
ui->pushButton_reverse->hide();
}
else
{
ui->radioButton_left->hide();
ui->radioButton_right->hide();
uint8_t functionMask = train->getFunctionMask();
qDebug()<<"functionMask: "<<(int)functionMask;
if(!(functionMask & (1 << 0)))
ui->checkBox_f1->hide();
if(!(functionMask & (1 << 1)))
ui->checkBox_f2->hide();
if(!(functionMask & (1 << 2)))
ui->checkBox_f3->hide();
if(!(functionMask & (1 << 3)))
ui->checkBox_f4->hide();
}
}
else
{
qWarning("TrainWidget got invalid item");
TrainWidget::disable();
}
}
void TrainWidget::deleteItem()
{
if(auto workingItem = item_.lock())
{
deleteRequest(*workingItem);
}
}
void TrainWidget::setValue(int8_t value)
{
if(auto workingItem = item_.lock())
workingItem->setValue(value);
else
disable();
}
void TrainWidget::moveToValue(int8_t value)
{
ui->slider->blockSignals(true);
ui->radioButton_left->blockSignals(true);
ui->radioButton_right->blockSignals(true);
ui->pushButton_reverse->setText(value == 0 ? "Reverse" : "Stop");
ui->slider->setValue(value);
ui->radioButton_left->setChecked(!value);
ui->radioButton_right->setChecked(value);
ui->slider->blockSignals(false);
ui->radioButton_left->blockSignals(false);
ui->radioButton_right->blockSignals(false);
}
void TrainWidget::f1(int value)
{
if(auto workingItem = item_.lock())
workingItem->setFunction(0, value == Qt::Checked);
else disable();
}
void TrainWidget::f2(int value)
{
if(auto workingItem = item_.lock())
workingItem->setFunction(1, value == Qt::Checked);
else disable();
}
void TrainWidget::f3(int value)
{
if(auto workingItem = item_.lock())
workingItem->setFunction(2, value == Qt::Checked);
else disable();
}
void TrainWidget::f4(int value)
{
if(auto workingItem = item_.lock())
workingItem->setFunction(3, value == Qt::Checked);
else disable();
}
void TrainWidget::reverse()
{
if(auto workingItem = item_.lock())
{
Train* train = dynamic_cast<Train*>(workingItem.get());
if(train && workingItem->getValue() == 0)
train->reverse();
else
{
setValue(!((bool)workingItem->getValue()));
}
}
else disable();
}
void TrainWidget::disable()
{
ui->checkBox_f1->setEnabled(false);
ui->checkBox_f2->setEnabled(false);
ui->checkBox_f3->setEnabled(false);
ui->checkBox_f4->setEnabled(false);
ui->label->setEnabled(false);
ui->slider->setEnabled(false);
ui->pushButton_reverse->setEnabled(false);
}
void TrainWidget::stepUp()
{
setValue(ui->slider->value()+1);
}
void TrainWidget::stepDown()
{
setValue(ui->slider->value()-1);
}
void TrainWidget::setShortcuts(QKeySequence up, QKeySequence down, QKeySequence rev)
{
shortcuts_.clear();
shortcuts_.push_back(std::unique_ptr<QShortcut>(new QShortcut(up, this)));
connect(shortcuts_.back().get(), &QShortcut::activated, this, &TrainWidget::stepUp);
shortcuts_.push_back(std::unique_ptr<QShortcut>(new QShortcut(down, this)));
connect(shortcuts_.back().get(), &QShortcut::activated, this, &TrainWidget::stepDown);
shortcuts_.push_back(std::unique_ptr<QShortcut>(new QShortcut(rev, this)));
connect(shortcuts_.back().get(), &QShortcut::activated, this, &TrainWidget::reverse);
}
void TrainWidget::stateChanged(int state)
{
qDebug()<<"widget got state "<<state;
ui->slider->blockSignals(true);
ui->slider->setValue(state);
ui->slider->blockSignals(false);
}
TrainWidget::~TrainWidget()
{
delete ui;
}

View File

@ -0,0 +1,48 @@
#pragma once
#include <QWidget>
#include <memory>
#include <QShortcut>
#include "../items/item.h"
#include "itemwidget.h"
namespace Ui
{
class TrainWidget;
}
class TrainWidget : public ItemWidget
{
Q_OBJECT
protected:
std::vector< std::unique_ptr<QShortcut> > shortcuts_;
void disable();
private slots:
void setValue(int8_t value);
void moveToValue(int8_t value);
void deleteItem();
void stepUp();
void stepDown();
void f1(int state);
void f2(int state);
void f3(int state);
void f4(int state);
void reverse();
public:
explicit TrainWidget(std::weak_ptr<Item> item, QWidget *parent);
~TrainWidget();
void setShortcuts(QKeySequence up, QKeySequence down, QKeySequence rev);
public slots:
virtual void stateChanged(int state);
private:
Ui::TrainWidget *ui;
};

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>ItemWidget</class>
<widget class="QWidget" name="ItemWidget">
<class>TrainWidget</class>
<widget class="QWidget" name="TrainWidget">
<property name="geometry">
<rect>
<x>0</x>

View File

@ -0,0 +1,15 @@
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})
target_link_libraries(trainoverlord PRIVATE ${COMMON_LINK_LIBRARYS})
target_include_directories(trainoverlord PRIVATE ./)

308
src/trainOverlord/block.cpp Normal file
View File

@ -0,0 +1,308 @@
#include "block.h"
#include <QJsonArray>
#include <QTimer>
#include <layout.h>
#include "nfcuid.h"
Block::Block(OverlordItemStore* items, uint32_t id):
items_(items), 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)
return;
connect(block.get(), &Block::blockedChanged, this, &Block::checkWaits);
}
bool Block::blocked()
{
if(tags_.empty() && waits_.empty())
return false;
return true;
}
bool Block::ownsTag(const NfcUid& tag)
{
for(const NfcUid& candiate : tags_)
{
if(candiate == tag)
return true;
}
return false;
}
bool Block::tagIsOfOwnedTrain(const NfcUid& tag)
{
std::shared_ptr<Train> train = items_->getTrainThatOwns(tag);
if(!train)
return false;
for(const NfcUid& canidate : tags_)
{
std::shared_ptr<Train> canidateTrain = items_->getTrainThatOwns(canidate);
if(*canidateTrain == *train)
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 isBlocked)
{
if(isBlocked)
return;
bool wasBlocked = blocked();
for(std::vector<Wait>::iterator iter = waits_.begin(); iter != waits_.end();)
{
if(iter->type != WAIT_TYPE_BLOCK)
{
++iter;
continue;
}
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->pushTag(iter->tag))
{
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);
}
bool Block::pushTag(const NfcUid& tag)
{
if(!blocked() || tagIsOfOwnedTrain(tag))
{
addTag(tag);
return true;
}
return false;
}
void Block::removeTraverse(std::shared_ptr<Train> train)
{
bool wasBlocked = blocked();
for(std::vector<Wait>::iterator iter = waits_.begin(); iter != waits_.end();)
{
if(iter->type == WAIT_TYPE_TIMED_TRAVERSE)
{
std::shared_ptr<Train> iterTrain = iter->train.lock();
if(!iterTrain)
{
iter = waits_.erase(iter);
continue;
}
if(*iterTrain == *train)
{
qDebug()<<"Train"<<iterTrain->getTrainId()<<"removed from traverse wait for block"<<id_;
iter = waits_.erase(iter);
continue;
}
}
++iter;
}
if(wasBlocked != blocked())
blockedChanged(!wasBlocked);
}
void Block::addTraverseWait(const NfcUid& tag)
{
std::shared_ptr<Train> train = items_->getTrainThatOwns(tag);
if(!train)
return;
if(!train->hasBackTag())
{
qDebug()<<"Train"<<train->getTrainId()<<"added as timed traverse wait for block"<<id_;
Wait wait;
wait.tag = tag;
wait.train = train;
wait.type = WAIT_TYPE_TIMED_TRAVERSE;
waits_.push_back(wait);
QTimer::singleShot(5000, this, [this, train](){removeTraverse(train);});
}
}
void Block::addBlockWait(const NfcUid& tag, std::shared_ptr<Block> block, std::shared_ptr<BlockBorder> border)
{
std::shared_ptr<Train> train = items_->getTrainThatOwns(tag);
if(!train)
return;
Wait wait;
wait.type = WAIT_TYPE_BLOCK;
wait.train = train;
wait.direction = train->getDirection();
wait.targetBlock = block;
wait.border = border;
wait.tag = tag;
connect(train.get(), &Train::unsuspended, this, &Block::unsuspendedTrain);
waits_.push_back(wait);
qDebug()<<"Train"<<train->getTrainId()<<"is wating at border for block"<<block->id();
}
void Block::addTag(const NfcUid& tag)
{
bool wasBlocked = blocked();
tags_.push_back(tag);
if(wasBlocked != blocked())
blockedChanged(!wasBlocked);
}
void Block::unsuspendedTrain(uint32_t id, int direction)
{
qDebug()<<"Train with item id"<<id<<"reports unsuspended";
bool wasBlocked = blocked();
for(std::vector<Wait>::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(block)
block->addTag(iter->tag);
waits_.erase(iter);
break;
}
}
if(wasBlocked != blocked())
blockedChanged(!wasBlocked);
}
void Block::removeTag(const NfcUid& tag)
{
for(std::vector<NfcUid>::iterator iter = tags_.begin(); iter != tags_.end(); ++iter)
{
if(*iter == tag)
{
tags_.erase(iter);
break;
}
}
}
void Block::purgeTag(const NfcUid& tag)
{
bool wasBlocked = blocked();
removeTag(tag);
std::shared_ptr<Train> train = items_->getTrainThatOwns(tag);
if(train)
removeTraverse(train);
if(wasBlocked != blocked())
blockedChanged(!wasBlocked);
}
void Block::tagArrivedAtBorder(NfcUid tag, std::weak_ptr<BlockBorder> borderIn)
{
bool wasBlocked = blocked();
qDebug()<<__func__<<"block"<<id();
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(!ownsTag(tag))
return;
qDebug()<<"Block"<<id_<<"owns subject tag";
std::shared_ptr block = border->getOtherBlock(this);
if(block)
{
if(!block->pushTag(tag))
{
std::shared_ptr<Train> train = items_->getTrainThatOwns(tag);
train->suspend();
addBlockWait(tag, block, border);
}
else
{
addTraverseWait(tag);
}
removeTag(tag);
}
if(wasBlocked != blocked())
blockedChanged(!wasBlocked);
}
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_;
}
}
}

75
src/trainOverlord/block.h Normal file
View File

@ -0,0 +1,75 @@
#ifndef BLOCK_H
#define BLOCK_H
#include <vector>
#include <memory>
#include <QObject>
#include <QRandomGenerator>
#include <QJsonObject>
#include "blockborder.h"
#include "train.h"
#include "overlorditemstore.h"
class BlockBorder;
class Layout;
class Block: public QObject
{
Q_OBJECT
protected:
static constexpr int WAIT_TYPE_BLOCK = 0;
static constexpr int WAIT_TYPE_TIMED_TRAVERSE = 1;
struct Wait
{
int type;
int direction;
NfcUid tag;
std::weak_ptr<Train> train;
std::weak_ptr<Block> targetBlock;
std::weak_ptr<BlockBorder> border;
};
std::vector< std::shared_ptr<BlockBorder> > borders_;
std::vector<NfcUid> tags_;
std::vector<Wait> waits_;
uint32_t id_;
OverlordItemStore* items_;
protected slots:
void unsuspendedTrain(uint32_t id, int direction);
void removeTraverse(std::shared_ptr<Train> train);
protected:
void checkWaits(bool blocked = false);
void addTraverseWait(const NfcUid& tag);
void addBlockWait(const NfcUid& tag, std::shared_ptr<Block> block, std::shared_ptr<BlockBorder> border);
void removeTag(const NfcUid& tag);
bool tagIsOfOwnedTrain(const NfcUid& tag);
public:
Block(OverlordItemStore* items, uint32_t id = QRandomGenerator::global()->generate());
uint32_t id(){return id_;}
void addBorder(std::shared_ptr<BlockBorder> border);
std::vector< std::shared_ptr<BlockBorder> > getBorders(){return borders_;}
bool ownsBorder(std::shared_ptr<BlockBorder> border);
bool pushTag(const NfcUid& tag);
void addTag(const NfcUid& tag);
void purgeTag(const NfcUid& tag);
bool ownsTag(const NfcUid& tag);
bool blocked();
void store(QJsonObject& json);
void load(const QJsonObject& json);
void populate(const QJsonObject& json, Layout* layout);
public slots:
void tagArrivedAtBorder(NfcUid tag, std::weak_ptr<BlockBorder> border);
signals:
void blockedChanged(bool blocked);
};
#endif // BLOCK_H

View File

@ -0,0 +1,172 @@
#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), id_(id)
{
setBlocks(blocks);
}
bool BlockBorder::isReader(uint8_t reader)
{
return reader == reader_;
}
uint8_t BlockBorder::getReader()
{
return reader_;
}
void BlockBorder::setBlocks(std::pair<std::weak_ptr<Block>, std::weak_ptr<Block>> blocks)
{
blocks_ = blocks;
std::shared_ptr<Block> first = blocks.first.lock();
if(first)
connect(first.get(), &Block::blockedChanged, this, &BlockBorder::blockedChanged);
std::shared_ptr<Block> second = blocks.second.lock();
if(second)
connect(second.get(), &Block::blockedChanged, this, &BlockBorder::blockedChanged);
}
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::blockedChanged(bool blocked)
{
(void)blocked;
updateSignals();
}
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())
{
QJsonObject arrayObjObj = arrayObj.toObject();
signalIds_.push_back(std::pair<uint32_t, bool>(static_cast<uint32_t>(arrayObjObj["SignalId"].toDouble(INT32_MAX)), static_cast<bool>(arrayObjObj["Direction"].toDouble(0))));
}
}
}
bool BlockBorder::hasMissingSingal()
{
for(auto& signal : signalIds_)
{
qDebug()<<"Missing signal id:"<<signal.first<<"Direction:"<<signal.second;
}
return !signalIds_.empty();
}
void BlockBorder::informOfItem(std::weak_ptr<Item> item)
{
std::shared_ptr<Item> workItem = item.lock();
if(!workItem)
return;
std::shared_ptr<Signal> signal = std::dynamic_pointer_cast<Signal>(workItem);
if(!signal)
return;
for(const std::pair<uint32_t, bool>& signalPair : signalIds_)
{
if(signalPair.first == signal->getSignalId())
{
signals_.push_back(signal);
signalDirections_.push_back(signalPair.second);
qDebug()<<"Border"<<id_<<"got Signal"<<signal->getSignalId();
}
}
std::erase_if(signalIds_, [signal](std::pair<uint32_t, bool> pair) -> bool{return pair.first == signal->getSignalId();});
}

View File

@ -0,0 +1,44 @@
#ifndef BLOCKBORDER_H
#define BLOCKBORDER_H
#include "trainsignal.h"
#include "block.h"
#include <QJsonObject>
#include <QObject>
class Block;
class Layout;
class BlockBorder: public QObject
{
Q_OBJECT
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);
void addSignal(std::weak_ptr<Signal> signal, std::shared_ptr<Block> block);
void informOfItem(std::weak_ptr<Item> item);
bool hasMissingSingal();
std::shared_ptr<Block> getOverlap(BlockBorder* border);
uint32_t id() {return id_;}
void store(QJsonObject& json);
void load(const QJsonObject& json);
public slots:
void blockedChanged(bool blocked);
};
#endif // BLOCKBORDER_H

View File

@ -0,0 +1,221 @@
#include "layout.h"
#include <memory>
#include <QJsonArray>
Layout::Layout(OverlordItemStore* items, QObject *parent): QObject{parent}, items_(items)
{
}
void Layout::removeTagFromAllBlocks(const NfcUid& tag)
{
for(std::shared_ptr<Block> block : blocks_)
{
block->purgeTag(tag);
}
}
void Layout::registerTagInLimbo(const NfcUid& tag, std::shared_ptr<BlockBorder> border)
{
for(auto iter = limbo_.begin(); iter != limbo_.end(); ++iter)
{
NfcUid limboTag = iter->first;
std::shared_ptr<BlockBorder> limboBorder = iter->second.lock();
if(!limboBorder)
{
limbo_.erase(iter);
registerTagInLimbo(tag, border);
return;
}
if(limboTag == tag)
{
if(border == limboBorder)
return;
std::shared_ptr<Block> overlap = border->getOverlap(limboBorder.get());
if(overlap)
{
qDebug()<<"Tag"<<tag.toString().c_str()<<"removed from limbo and added to block"<<overlap->id()<<"while crossing border"<<border->id();
overlap->addTag(tag);
overlap->tagArrivedAtBorder(tag, border);
limbo_.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()<<"Tag"<<tag.toString().c_str()<<"added to limbo between block"<<
(first ? QString::number(first->id()) : "invalid")<<"and block"<<(second ? QString::number(second->id()) : "invalid");
limbo_.push_back(std::pair<NfcUid, std::weak_ptr<BlockBorder>>(tag, border));
}
void Layout::tagArrivedAtReader(uint8_t reader, NfcUid tag)
{
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;
}
std::shared_ptr<Train> train = items_->getTrainThatOwns(tag);
qDebug()<<"Train"<<(train ? train->getTrainId() : -1)<<"Tag"<<tag.toString().c_str()<<"arrived at border"<<border->id();
bool tagHandled = false;
for(std::shared_ptr<Block>& block : blocks_)
{
if(block->ownsTag(tag))
{
tagHandled = true;
if(block->ownsBorder(border))
{
block->tagArrivedAtBorder(tag, border);
}
else
{
removeTagFromAllBlocks(tag);
registerTagInLimbo(tag, border);
}
break;
}
}
if(!tagHandled)
registerTagInLimbo(tag, 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(items_));
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
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(std::shared_ptr<Item>& item : *items_->getItems())
border->informOfItem(item);
connect(items_, &ItemStore::itemAdded, border.get(), &BlockBorder::informOfItem);
}
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,42 @@
#ifndef BLOCKSTORE_H
#define BLOCKSTORE_H
#include <QObject>
#include <memory>
#include <vector>
#include "block.h"
#include "overlorditemstore.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<NfcUid, std::weak_ptr<BlockBorder>>> limbo_;
void removeTagFromAllBlocks(const NfcUid& tag);
void registerTagInLimbo(const NfcUid& tag, std::shared_ptr<BlockBorder>);
OverlordItemStore *items_;
public:
explicit Layout(OverlordItemStore *items, 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 tagArrivedAtReader(uint8_t reader, NfcUid tag);
};
#endif // BLOCKSTORE_H

View File

@ -0,0 +1,20 @@
#include "overlorditemstore.h"
#include <QDebug>
#include "train.h"
OverlordItemStore::OverlordItemStore(QObject *parent): ItemStore(parent)
{
}
std::shared_ptr<Train> OverlordItemStore::getTrainThatOwns(const NfcUid& uid)
{
for(std::shared_ptr<Item> item : items_)
{
std::shared_ptr<Train> train = std::dynamic_pointer_cast<Train>(item);
if(!train)
continue;
if(train->ownsTag(uid))
return train;
}
return std::shared_ptr<Train>();
}

View File

@ -0,0 +1,11 @@
#pragma once
#include "itemstore.h"
#include "train.h"
class OverlordItemStore: public ItemStore
{
Q_OBJECT
public:
OverlordItemStore(QObject *parent = nullptr);
std::shared_ptr<Train> getTrainThatOwns(const NfcUid& uid);
};

View File

@ -0,0 +1,166 @@
#include <QCoreApplication>
#include <QCommandLineParser>
#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 "layout.h"
void sigHandler(int sig)
{
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::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);
}
}
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
signal(SIGINT, &sigHandler);
//set info
QCoreApplication::setOrganizationName("UVOS");
QCoreApplication::setOrganizationDomain("uvos.xyz");
QCoreApplication::setApplicationName("TrainOverlord");
QCoreApplication::setApplicationVersion("0.1");
//parse comand line
QCommandLineParser parser;
parser.setApplicationDescription("Train control application");
parser.addHelpOption();
parser.addVersionOption();
QCommandLineOption hostOption(QStringList() << "H" << "host", QCoreApplication::translate("main",
"Set server host ip addres"), "adress");
parser.addOption(hostOption);
QCommandLineOption portOption(QStringList() << "p" << "port", QCoreApplication::translate("main",
"Set server Port in TCP mode or Serial port in serial mode"), "port");
parser.addOption(portOption);
parser.process(a);
QTcpSocket microSocket;
int port = 6856;
if(parser.isSet(portOption))
port = parser.value(portOption).toInt();
QString host("127.0.0.1");
if(parser.isSet(hostOption)) host = parser.value(hostOption);
std::cout<<"connecting to "<<host.toStdString()<<':'<<port<<'\n';
microSocket.connectToHost(host, port, QIODevice::ReadWrite);
if(!microSocket.waitForConnected(3000))
{
std::cout<<"Can not connect to to Server.\n";
return 1;
}
OverlordItemStore items;
Layout layout(&items);
Microcontroller micro(&microSocket);
QObject::connect(&micro, &Microcontroller::gotTag, &layout, &Layout::tagArrivedAtReader);
QObject::connect(&micro, &Microcontroller::gotItemList, &items, &OverlordItemStore::addItems);
QObject::connect(&micro, &Microcontroller::itemChanged, &items, &OverlordItemStore::itemStateChanged);
Train::micro = &micro;
Turnout::micro = &micro;
Signal::micro = &micro;
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;
}

View File

@ -1,142 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>AlarmSettingsDialog</class>
<widget class="QDialog" name="AlarmSettingsDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>423</width>
<height>281</height>
</rect>
</property>
<property name="windowTitle">
<string>Dialog</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>Sound File:</string>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<item>
<widget class="QLineEdit" name="lineEdit">
<property name="enabled">
<bool>false</bool>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pushButton">
<property name="text">
<string>Change</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<property name="topMargin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="label_2">
<property name="text">
<string>Sunrise</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QCheckBox" name="checkBox">
<property name="text">
<string>Enable</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>AlarmSettingsDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>AlarmSettingsDialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View File

@ -1,30 +0,0 @@
#include "itemcreationdialog.h"
#include "ui_itemcreationdialog.h"
ItemCreationDialog::ItemCreationDialog(QWidget *parent) :
QDialog(parent),
ui(new Ui::ItemCreationDialog)
{
ui->setupUi(this);
connect(ui->comboBox, &QComboBox::currentTextChanged, this, &ItemCreationDialog::itemTypeChanged);
connect(ui->lineEdit, &QLineEdit::textChanged, this, &ItemCreationDialog::itemNameChanged);
}
ItemCreationDialog::~ItemCreationDialog()
{
delete ui;
}
void ItemCreationDialog::itemTypeChanged(const QString& type)
{
ui->verticalLayout->removeWidget(widget);
}
void ItemCreationDialog::itemNameChanged(const QString& name)
{
if(item)
{
item->setName(name);
}
}

View File

@ -1,33 +0,0 @@
#ifndef ITEMCREATIONDIALOG_H
#define ITEMCREATIONDIALOG_H
#include <QDialog>
#include <memory>
#include "../items/item.h"
namespace Ui {
class ItemCreationDialog;
}
class ItemCreationDialog : public QDialog
{
Q_OBJECT
QWidget* widget;
public:
explicit ItemCreationDialog(QWidget *parent = nullptr);
~ItemCreationDialog();
std::shared_ptr<Item> item;
private slots:
void itemTypeChanged(const QString& type);
void itemNameChanged(const QString& name);
private:
Ui::ItemCreationDialog *ui;
};
#endif // ITEMCREATIONDIALOG_H

View File

@ -1,116 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>ItemCreationDialog</class>
<widget class="QDialog" name="ItemCreationDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>140</height>
</rect>
</property>
<property name="windowTitle">
<string>Create Item</string>
</property>
<property name="windowIcon">
<iconset resource="../../resources.qrc">
<normaloff>:/images/UVOSicon.bmp</normaloff>:/images/UVOSicon.bmp</iconset>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>Type</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="comboBox">
<item>
<property name="text">
<string>Message</string>
</property>
</item>
<item>
<property name="text">
<string>System</string>
</property>
</item>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QLabel" name="label_2">
<property name="text">
<string>Name</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="lineEdit">
<property name="text">
<string>Item</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout"/>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources>
<include location="../../resources.qrc"/>
</resources>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>ItemCreationDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>ItemCreationDialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View File

@ -1,84 +0,0 @@
#include "itemscrollbox.h"
#include "ui_relayscrollbox.h"
#include "ui_relayscrollbox.h"
#include "../items/train.h"
#include "../items/turnout.h"
#include "../trainjs.h"
ItemScrollBox::ItemScrollBox(QWidget *parent) :
QWidget(parent),
ui(new Ui::RelayScrollBox)
{
ui->setupUi(this);
QScroller::grabGesture(ui->scrollArea, QScroller::TouchGesture);
QScroller::grabGesture(ui->scrollArea, QScroller::LeftMouseButtonGesture);
}
ItemScrollBox::~ItemScrollBox()
{
delete ui;
}
void ItemScrollBox::addItem(std::weak_ptr<Item> item)
{
if(auto workItem = item.lock())
{
widgets_.push_back(new ItemWidget(item, this));
Train* train = dynamic_cast<Train*>(workItem.get());
Turnout* turnout = dynamic_cast<Turnout*>(workItem.get());
if(train)
{
if(train->getTrainId() == 0)
widgets_.back()->setShortcuts(QKeySequence(Qt::Key_Q), QKeySequence(Qt::Key_A), QKeySequence(Qt::Key_Z));
else if(train->getTrainId() == 1)
widgets_.back()->setShortcuts(QKeySequence(Qt::Key_W), QKeySequence(Qt::Key_S), QKeySequence(Qt::Key_X));
else if(train->getTrainId() == 2)
widgets_.back()->setShortcuts(QKeySequence(Qt::Key_E), QKeySequence(Qt::Key_D), QKeySequence(Qt::Key_C));
else if(train->getTrainId() == 3)
widgets_.back()->setShortcuts(QKeySequence(Qt::Key_R), QKeySequence(Qt::Key_F), QKeySequence(Qt::Key_V));
else if(train->getTrainId() == 4)
widgets_.back()->setShortcuts(QKeySequence(Qt::Key_T), QKeySequence(Qt::Key_G), QKeySequence(Qt::Key_B));
}
else if(turnout)
{
if(turnout->getTurnoutId() == 0)
widgets_.back()->setShortcuts(QKeySequence(), QKeySequence(), QKeySequence(Qt::Key_1));
else if(turnout->getTurnoutId() == 1)
widgets_.back()->setShortcuts(QKeySequence(), QKeySequence(), QKeySequence(Qt::Key_2));
else if(turnout->getTurnoutId() == 2)
widgets_.back()->setShortcuts(QKeySequence(), QKeySequence(), QKeySequence(Qt::Key_3));
else if(turnout->getTurnoutId() == 3)
widgets_.back()->setShortcuts(QKeySequence(), QKeySequence(), QKeySequence(Qt::Key_4));
else if(turnout->getTurnoutId() == 4)
widgets_.back()->setShortcuts(QKeySequence(), QKeySequence(), QKeySequence(Qt::Key_5));
else if(turnout->getTurnoutId() == 5)
widgets_.back()->setShortcuts(QKeySequence(), QKeySequence(), QKeySequence(Qt::Key_6));
else if(turnout->getTurnoutId() == 6)
widgets_.back()->setShortcuts(QKeySequence(), QKeySequence(), QKeySequence(Qt::Key_7));
else if(turnout->getTurnoutId() == 7)
widgets_.back()->setShortcuts(QKeySequence(), QKeySequence(), QKeySequence(Qt::Key_8));
else if(turnout->getTurnoutId() == 8)
widgets_.back()->setShortcuts(QKeySequence(), QKeySequence(), QKeySequence(Qt::Key_9));
else if(turnout->getTurnoutId() == 9)
widgets_.back()->setShortcuts(QKeySequence(), QKeySequence(), QKeySequence(Qt::Key_0));
}
ui->relayWidgetVbox->addWidget(widgets_.back());
connect(widgets_.back(), &ItemWidget::deleteRequest, this, &ItemScrollBox::deleteRequest);
connect(widgets_.back(), &ItemWidget::deleteRequest, this, &ItemScrollBox::removeItem);
}
}
void ItemScrollBox::removeItem(const ItemData& item)
{
for(unsigned i = 0; i < widgets_.size(); i++)
{
if(widgets_[i]->controles(item))
{
ui->relayWidgetVbox->removeWidget(widgets_[i]);
delete widgets_[i];
widgets_.erase(widgets_.begin()+i);
}
}
}

View File

@ -1,176 +0,0 @@
#include "itemsettingsdialog.h"
#include "ui_itemsettingsdialog.h"
#include<memory>
ItemSettingsDialog::ItemSettingsDialog(std::shared_ptr<Item> item, QWidget *parent) :
QDialog(parent),
item_(item),
ui(new Ui::ItemSettingsDialog)
{
ui->setupUi(this);
setModal(false);
ui->label_name->setText(item_->getName());
ui->checkBox_Override->setChecked(item_->getOverride());
if(std::shared_ptr<Relay> relay = std::dynamic_pointer_cast<Relay>(item_))
{
itemSpecificWidget_ = new RelayItemSettingsWidget(relay);
}
else if(std::shared_ptr<MessageItem> msgItem = std::dynamic_pointer_cast<MessageItem>(item_))
{
itemSpecificWidget_ = new MessageItemSettingsWidget(msgItem);
}
else if(std::shared_ptr<SystemItem> sysItem = std::dynamic_pointer_cast<SystemItem>(item_))
{
itemSpecificWidget_ = new SystemItemSettingsWidget(sysItem);
}
if(itemSpecificWidget_)
{
ui->verticalLayout_2->addWidget(itemSpecificWidget_);
}
connect(ui->pushButton_add, &QPushButton::clicked, this, &ItemSettingsDialog::addActor);
connect(ui->pushButton_remove, &QPushButton::clicked, this, &ItemSettingsDialog::removeActor);
connect(ui->pushButton_edit, &QPushButton::clicked, this, &ItemSettingsDialog::editActor);
connect(ui->checkBox_Override, &QPushButton::clicked, this, &ItemSettingsDialog::changeOverride);
ui->tableWidget->setHorizontalHeaderItem(0, new QTableWidgetItem("Actor"));
ui->tableWidget->setHorizontalHeaderItem(1, new QTableWidgetItem("Action"));
ui->tableWidget->setHorizontalHeaderItem(2, new QTableWidgetItem("Enabled"));
ui->tableWidget->horizontalHeader()->setSectionResizeMode(0, QHeaderView::Stretch);
ui->tableWidget->horizontalHeader()->resizeSection(1, 60);
ui->tableWidget->horizontalHeader()->resizeSection(2, 75);
loadActorList();
}
ItemSettingsDialog::~ItemSettingsDialog()
{
if(itemSpecificWidget_) delete itemSpecificWidget_;
delete ui;
}
void ItemSettingsDialog::changeOverride()
{
item_->setOverride(ui->checkBox_Override->isChecked());
}
void ItemSettingsDialog::loadActorList()
{
//ui->listWidget->clear();
ui->tableWidget->setRowCount(item_->getActors().size());
for(unsigned i = 0; i < item_->getActors().size(); i++)
{
ui->tableWidget->setItem(i, 0, new QTableWidgetItem(item_->getActors()[i]->getName()));
ui->tableWidget->setItem(i, 1, new QTableWidgetItem(item_->getActors()[i]->actionName()));
ui->tableWidget->setItem(i, 2, new QTableWidgetItem(item_->getActors()[i]->isActive() ? "Y" : "N"));
}
}
void ItemSettingsDialog::addActor()
{
ActorSettingsDialog* dialog = nullptr;
std::shared_ptr<Actor> actor = nullptr;
if(ui->comboBox->currentText() == "Alarm")
{
std::shared_ptr<AlarmTime> alarm = std::shared_ptr<AlarmTime>(new AlarmTime);
actor = alarm;
dialog = new ActorSettingsDialog(alarm, this);
}
else if(ui->comboBox->currentText() == "Sensor")
{
std::shared_ptr<SensorActor> sensorActor = std::shared_ptr<SensorActor>(new SensorActor);
actor = sensorActor;
dialog = new ActorSettingsDialog(sensorActor, this);
}
else if(ui->comboBox->currentText() == "Timer" )
{
std::shared_ptr<TimerActor> timerActor = std::shared_ptr<TimerActor>(new TimerActor);
actor = timerActor;
dialog = new ActorSettingsDialog(timerActor, this);
}
else if(ui->comboBox->currentText() == "Regulator")
{
std::shared_ptr<Regulator> regulator = std::shared_ptr<Regulator>(new Regulator);
actor = regulator;
dialog = new ActorSettingsDialog(regulator, this);
}
else if(ui->comboBox->currentText() == "Polynomal")
{
std::shared_ptr<PolynomalActor> polynomalActor = std::shared_ptr<PolynomalActor>(new PolynomalActor);
actor = polynomalActor;
dialog = new ActorSettingsDialog(polynomalActor, this);
}
else if(ui->comboBox->currentText() == "Multi Factor")
{
std::shared_ptr<MultiFactorActor> polynomalActor = std::shared_ptr<MultiFactorActor>(new MultiFactorActor);
actor = polynomalActor;
dialog = new ActorSettingsDialog(polynomalActor, this);
}
if(dialog != nullptr)
{
dialog->setParent(this);
dialog->show();
if(dialog->exec() == QDialog::Accepted)
{
item_->addActor(actor);
loadActorList();
}
delete dialog;
}
}
void ItemSettingsDialog::removeActor()
{
if(item_->getActors().size() > ui->tableWidget->currentRow())
{
item_->removeActor(item_->getActors().at(ui->tableWidget->currentRow()));
loadActorList();
}
}
void ItemSettingsDialog::editActor()
{
if(item_->getActors().size() > ui->tableWidget->currentRow())
{
std::shared_ptr<Actor> actor = item_->getActors()[ui->tableWidget->currentRow()];
std::shared_ptr<AlarmTime> alarmTime = std::dynamic_pointer_cast<AlarmTime>(actor);
std::shared_ptr<Regulator> regulator = std::dynamic_pointer_cast<Regulator>(actor);
std::shared_ptr<SensorActor> sensorActor = std::dynamic_pointer_cast<SensorActor>(actor);
std::shared_ptr<TimerActor> timerActor = std::dynamic_pointer_cast<TimerActor>(actor);
std::shared_ptr<PolynomalActor> polynomalActor = std::dynamic_pointer_cast<PolynomalActor>(actor);
std::shared_ptr<MultiFactorActor> factorActor = std::dynamic_pointer_cast<MultiFactorActor>(actor);
ActorSettingsDialog* dialog;
if(alarmTime) dialog = new ActorSettingsDialog(alarmTime, this);
else if(regulator) dialog = new ActorSettingsDialog(regulator, this);
else if(sensorActor) dialog = new ActorSettingsDialog(sensorActor, this);
else if(timerActor) dialog = new ActorSettingsDialog(timerActor, this);
else if(polynomalActor) dialog = new ActorSettingsDialog(polynomalActor, this);
else if(factorActor) dialog = new ActorSettingsDialog(factorActor, this);
else dialog = new ActorSettingsDialog(actor, this);
dialog->setParent(this);
dialog->show();
dialog->exec();
for(int i = 0; i < ui->tableWidget->rowCount() && i < item_->getActors().size(); ++i)
{
ui->tableWidget->item(i, 0)->setText(item_->getActors()[i]->getName());
ui->tableWidget->item(i, 1)->setText(item_->getActors()[i]->actionName());
ui->tableWidget->item(i, 2)->setText(item_->getActors()[i]->isActive() ? "Y" : "N");
}
}
}

View File

@ -1,37 +0,0 @@
#ifndef RELAYSETTINGSDIALOG_H
#define RELAYSETTINGSDIALOG_H
#include <QDialog>
#include <QSettings>
#include <memory>
#include "../items/item.h"
namespace Ui {
class ItemSettingsDialog;
}
class ItemSettingsDialog : public QDialog
{
Q_OBJECT
std::shared_ptr<Item> item_;
QWidget* itemSpecificWidget_ = nullptr;
private:
void loadActorList();
public:
explicit ItemSettingsDialog(std::shared_ptr<Item> item, QWidget *parent = nullptr);
~ItemSettingsDialog();
private slots:
void removeActor();
void addActor();
void editActor();
void changeOverride();
private:
Ui::ItemSettingsDialog *ui;
};
#endif // RELAYSETTINGSDIALOG_H

View File

@ -1,274 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>ItemSettingsDialog</class>
<widget class="QDialog" name="ItemSettingsDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>577</width>
<height>390</height>
</rect>
</property>
<property name="windowTitle">
<string>Item Settings</string>
</property>
<property name="windowIcon">
<iconset resource="../../resources.qrc">
<normaloff>:/images/UVOSicon.bmp</normaloff>:/images/UVOSicon.bmp</iconset>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QFormLayout" name="formLayout">
<property name="fieldGrowthPolicy">
<enum>QFormLayout::AllNonFixedFieldsGrow</enum>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>10</number>
</property>
<item row="1" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Name:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLabel" name="label_name">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>5</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="layoutDirection">
<enum>Qt::LeftToRight</enum>
</property>
<property name="text">
<string>TextLabel</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout_2"/>
</item>
<item>
<widget class="QCheckBox" name="checkBox_Override">
<property name="text">
<string>Override</string>
</property>
</widget>
</item>
<item>
<widget class="QTableWidget" name="tableWidget">
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
</property>
<property name="verticalScrollBarPolicy">
<enum>Qt::ScrollBarAsNeeded</enum>
</property>
<property name="horizontalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOff</enum>
</property>
<property name="autoScroll">
<bool>false</bool>
</property>
<property name="editTriggers">
<set>QAbstractItemView::NoEditTriggers</set>
</property>
<property name="tabKeyNavigation">
<bool>false</bool>
</property>
<property name="showDropIndicator" stdset="0">
<bool>false</bool>
</property>
<property name="dragDropOverwriteMode">
<bool>false</bool>
</property>
<property name="selectionBehavior">
<enum>QAbstractItemView::SelectRows</enum>
</property>
<property name="showGrid">
<bool>false</bool>
</property>
<property name="gridStyle">
<enum>Qt::SolidLine</enum>
</property>
<property name="cornerButtonEnabled">
<bool>false</bool>
</property>
<property name="rowCount">
<number>0</number>
</property>
<property name="columnCount">
<number>3</number>
</property>
<attribute name="horizontalHeaderVisible">
<bool>false</bool>
</attribute>
<attribute name="horizontalHeaderMinimumSectionSize">
<number>32</number>
</attribute>
<attribute name="horizontalHeaderHighlightSections">
<bool>true</bool>
</attribute>
<attribute name="verticalHeaderVisible">
<bool>false</bool>
</attribute>
<attribute name="verticalHeaderDefaultSectionSize">
<number>32</number>
</attribute>
<column/>
<column/>
<column/>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<item>
<widget class="QPushButton" name="pushButton_remove">
<property name="text">
<string>Remove</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pushButton_edit">
<property name="text">
<string>Edit</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLabel" name="label_3">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Act on</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="comboBox">
<item>
<property name="text">
<string>Sensor</string>
</property>
</item>
<item>
<property name="text">
<string>Polynomal</string>
</property>
</item>
<item>
<property name="text">
<string>Regulator</string>
</property>
</item>
<item>
<property name="text">
<string>Alarm</string>
</property>
</item>
<item>
<property name="text">
<string>Timer</string>
</property>
</item>
<item>
<property name="text">
<string>Multi Factor</string>
</property>
</item>
</widget>
</item>
<item>
<widget class="QPushButton" name="pushButton_add">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Add</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources>
<include location="../../resources.qrc"/>
</resources>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>ItemSettingsDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>ItemSettingsDialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View File

@ -1,203 +0,0 @@
#include "itemwidget.h"
#include "ui_itemwidget.h"
#include <QCheckBox>
#include <QDebug>
#include <QSlider>
#include "../items/train.h"
#include "../items/turnout.h"
ItemWidget::ItemWidget(std::weak_ptr<Item> item, QWidget *parent) :
QWidget(parent),
item_(item),
ui(new Ui::ItemWidget)
{
ui->setupUi(this);
if(auto workingItem = item_.lock())
{
ui->label->setText(workingItem->getName());
connect(ui->slider, &QSlider::valueChanged, this, &ItemWidget::setValue);
connect(ui->checkBox_f1, &QCheckBox::stateChanged, this, &ItemWidget::f1);
connect(ui->checkBox_f2, &QCheckBox::stateChanged, this, &ItemWidget::f2);
connect(ui->checkBox_f3, &QCheckBox::stateChanged, this, &ItemWidget::f3);
connect(ui->checkBox_f4, &QCheckBox::stateChanged, this, &ItemWidget::f4);
connect(ui->pushButton_reverse, &QPushButton::clicked, this, &ItemWidget::reverse);
connect(ui->radioButton_left, &QRadioButton::clicked, this, [this](){setValue(0);});
connect(ui->radioButton_right, &QRadioButton::clicked, this, [this](){setValue(1);});
connect(workingItem.get(), &Item::valueChanged, this, &ItemWidget::moveToValue);
Train* train = dynamic_cast<Train*>(workingItem.get());
Turnout* turnout = dynamic_cast<Turnout*>(workingItem.get());
if(turnout)
{
ui->checkBox_f1->hide();
ui->checkBox_f2->hide();
ui->checkBox_f3->hide();
ui->checkBox_f4->hide();
ui->slider->hide();
}
if(!train)
{
ui->pushButton_reverse->hide();
}
else
{
ui->radioButton_left->hide();
ui->radioButton_right->hide();
uint8_t functionMask = train->getFunctionMask();
qDebug()<<"functionMask: "<<(int)functionMask;
if(!(functionMask & (1 << 0)))
ui->checkBox_f1->hide();
if(!(functionMask & (1 << 1)))
ui->checkBox_f2->hide();
if(!(functionMask & (1 << 2)))
ui->checkBox_f3->hide();
if(!(functionMask & (1 << 3)))
ui->checkBox_f4->hide();
}
}
else disable();
}
void ItemWidget::deleteItem()
{
if(auto workingItem = item_.lock())
{
deleteRequest(*workingItem);
}
}
void ItemWidget::setValue(int8_t value)
{
if(auto workingItem = item_.lock())
workingItem->setValue(value);
else
disable();
}
void ItemWidget::moveToValue(int8_t value)
{
ui->slider->blockSignals(true);
ui->radioButton_left->blockSignals(true);
ui->radioButton_right->blockSignals(true);
ui->pushButton_reverse->setText(value == 0 ? "Reverse" : "Stop");
ui->slider->setValue(value);
ui->radioButton_left->setChecked(!value);
ui->radioButton_right->setChecked(value);
ui->slider->blockSignals(false);
ui->radioButton_left->blockSignals(false);
ui->radioButton_right->blockSignals(false);
}
void ItemWidget::f1(int value)
{
if(auto workingItem = item_.lock())
workingItem->setFunction(0, value == Qt::Checked);
else disable();
}
void ItemWidget::f2(int value)
{
if(auto workingItem = item_.lock())
workingItem->setFunction(1, value == Qt::Checked);
else disable();
}
void ItemWidget::f3(int value)
{
if(auto workingItem = item_.lock())
workingItem->setFunction(2, value == Qt::Checked);
else disable();
}
void ItemWidget::f4(int value)
{
if(auto workingItem = item_.lock())
workingItem->setFunction(3, value == Qt::Checked);
else disable();
}
void ItemWidget::reverse()
{
if(auto workingItem = item_.lock())
{
Train* train = dynamic_cast<Train*>(workingItem.get());
if(train && workingItem->getValue() == 0)
train->reverse();
else
{
setValue(!((bool)workingItem->getValue()));
}
}
else disable();
}
void ItemWidget::disable()
{
ui->checkBox_f1->setEnabled(false);
ui->checkBox_f2->setEnabled(false);
ui->checkBox_f3->setEnabled(false);
ui->checkBox_f4->setEnabled(false);
ui->label->setEnabled(false);
ui->slider->setEnabled(false);
ui->pushButton_reverse->setEnabled(false);
}
bool ItemWidget::controles(const ItemData& relay)
{
if(auto workingRelay = item_.lock())
{
if(relay == *workingRelay)
return true;
else
return false;
}
return true;
}
void ItemWidget::stepUp()
{
setValue(ui->slider->value()+1);
}
void ItemWidget::stepDown()
{
setValue(ui->slider->value()-1);
}
void ItemWidget::setShortcuts(QKeySequence up, QKeySequence down, QKeySequence rev)
{
shortcuts_.clear();
shortcuts_.push_back(std::unique_ptr<QShortcut>(new QShortcut(up, this)));
connect(shortcuts_.back().get(), &QShortcut::activated, this, &ItemWidget::stepUp);
shortcuts_.push_back(std::unique_ptr<QShortcut>(new QShortcut(down, this)));
connect(shortcuts_.back().get(), &QShortcut::activated, this, &ItemWidget::stepDown);
shortcuts_.push_back(std::unique_ptr<QShortcut>(new QShortcut(rev, this)));
connect(shortcuts_.back().get(), &QShortcut::activated, this, &ItemWidget::reverse);
}
std::weak_ptr<Item> ItemWidget::getItem()
{
return item_;
}
void ItemWidget::stateChanged(int state)
{
qDebug()<<"widget got state "<<state;
ui->slider->blockSignals(true);
ui->slider->setValue(state);
ui->slider->blockSignals(false);
}
ItemWidget::~ItemWidget()
{
delete ui;
}

View File

@ -1,57 +0,0 @@
#ifndef RELAYWIDGET_H
#define RELAYWIDGET_H
#include <QWidget>
#include <memory>
#include <QShortcut>
#include "itemsettingsdialog.h"
#include "../items/item.h"
namespace Ui {
class ItemWidget;
}
class ItemWidget : public QWidget
{
Q_OBJECT
private:
std::weak_ptr<Item> item_;
std::vector< std::unique_ptr<QShortcut> > shortcuts_;
void disable();
signals:
void deleteRequest(const ItemData& item);
private slots:
void setValue(int8_t value);
void moveToValue(int8_t value);
void deleteItem();
void stepUp();
void stepDown();
void f1(int state);
void f2(int state);
void f3(int state);
void f4(int state);
void reverse();
public:
explicit ItemWidget(std::weak_ptr<Item> item, QWidget *parent);
std::weak_ptr<Item> getItem();
bool controles(const ItemData& relay);
~ItemWidget();
void setShortcuts(QKeySequence up, QKeySequence down, QKeySequence rev);
public slots:
void stateChanged(int state);
private:
Ui::ItemWidget *ui;
};
#endif // RELAYWIDGET_H

View File

@ -1,45 +0,0 @@
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "itemscrollbox.h"
#include "itemsettingsdialog.h"
#include "itemcreationdialog.h"
MainWindow::MainWindow(Microcontroller * const micro, ItemStore* items, QWidget *parent) :
QMainWindow(parent),
stopShort(QKeySequence(Qt::Key_Space), this),
ui(new Ui::MainWindow),
_micro(micro)
{
ui->setupUi(this);
connect(&stopShort, &QShortcut::activated, _micro, &Microcontroller::estop);
connect(ui->pushButton_stop, &QPushButton::clicked, _micro, &Microcontroller::estop);
connect(ui->pushButton_refesh, &QPushButton::clicked, _micro, &Microcontroller::requestState);
connect(items, &ItemStore::itemAdded, ui->relayList, &ItemScrollBox::addItem);
connect(items, &ItemStore::itemDeleted, ui->relayList, &ItemScrollBox::removeItem);
for(size_t i = 0; i < items->getItems()->size(); ++i)
{
ui->relayList->addItem(items->getItems()->at(i));
}
connect(ui->relayList, &ItemScrollBox::deleteRequest, items, &ItemStore::removeItem);
}
MainWindow::~MainWindow()
{
delete ui;
}
/*
void MainWindow::showItemCreationDialog()
{
ItemCreationDialog diag(this);
diag.show();
if(diag.exec())
{
createdItem(diag.item);
}
}
*/

View File

@ -1,65 +0,0 @@
#-------------------------------------------------
#
# Project created by QtCreator 2017-06-01T22:31:38
#
#-------------------------------------------------
QT += core gui widgets network serialport
TARGET = traincontrollerui
TEMPLATE = app
INCLUDEPATH += /usr/include/libnl3/
INCLUDEPATH += /usr/include/SDL2/
LIBS += -lnl-3 -lnl-genl-3 -lSDL2
# The following define makes your compiler emit warnings if you use
# any feature of Qt which as been marked as deprecated (the exact warnings
# depend on your compiler). Please consult the documentation of the
# deprecated API in order to know how to port your code away from it.
DEFINES += QT_DEPRECATED_WARNINGS
DEFINES += SDL_SUPPORTED
QMAKE_CXXFLAGS += -std=c++17 -O2
SOURCES += \
src/items/train.cpp \
src/items/turnout.cpp \
src/mainobject.cpp \
src/trainjs.cpp \
src/QJoysticks.cpp \
src/jsbackend/SDL_Joysticks.cpp \
src/jsbackend/VirtualJoystick.cpp \
src/ui/itemwidget.cpp \
src/ui/itemscrollbox.cpp \
src/ui/mainwindow.cpp \
src/items/item.cpp \
src/items/itemstore.cpp\
src/main.cpp \
src/microcontroller.cpp
HEADERS += \
src/items/train.h \
src/items/turnout.h \
src/mainobject.h \
src/trainjs.h \
src/QJoysticks.h \
src/jsbackend/SDL_Joysticks.h \
src/jsbackend/VirtualJoystick.h \
src/jsbackend/JoysticksCommon.h \
src/ui/itemwidget.h \
src/ui/itemscrollbox.h \
src/ui/mainwindow.h \
src/items/item.h \
src/items/itemstore.h
HEADERS += \
src/microcontroller.h \
INCLUDEPATH += src/ui/
FORMS += \
src/ui/mainwindow.ui \
src/ui/relayscrollbox.ui \
src/ui/itemwidget.ui