diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..b71f98e --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,5 @@ +cmake_minimum_required(VERSION 3.5) + +project(trainController LANGUAGES CXX) + +add_subdirectory(src) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt new file mode 100644 index 0000000..fae25ab --- /dev/null +++ b/src/CMakeLists.txt @@ -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) + diff --git a/src/QJoysticks.cpp b/src/QJoysticks.cpp deleted file mode 100644 index 2deb989..0000000 --- a/src/QJoysticks.cpp +++ /dev/null @@ -1,479 +0,0 @@ -/* - * Copyright (c) 2015-2017 Alex Spataru - * - * 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 -#include -#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 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); - } - } -} diff --git a/src/auxitem.cpp b/src/auxitem.cpp deleted file mode 100644 index 8f104c5..0000000 --- a/src/auxitem.cpp +++ /dev/null @@ -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); -} diff --git a/src/auxitem.h b/src/auxitem.h deleted file mode 100644 index a1e6765..0000000 --- a/src/auxitem.h +++ /dev/null @@ -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); -}; diff --git a/src/items/item.cpp b/src/common/items/item.cpp similarity index 73% rename from src/items/item.cpp rename to src/common/items/item.cpp index 36756b9..6a8dd2f 100644 --- a/src/items/item.cpp +++ b/src/common/items/item.cpp @@ -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); } diff --git a/src/items/item.h b/src/common/items/item.h similarity index 53% rename from src/items/item.h rename to src/common/items/item.h index be563d7..54c843a 100644 --- a/src/items/item.h +++ b/src/common/items/item.h @@ -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); }; diff --git a/src/common/items/itemstore.cpp b/src/common/items/itemstore.cpp new file mode 100644 index 0000000..5f0a0cb --- /dev/null +++ b/src/common/items/itemstore.cpp @@ -0,0 +1,87 @@ +#include "itemstore.h" +#include +#include +#include "train.h" + +ItemStore::ItemStore(QObject *parent): QObject(parent) +{ +} + +void ItemStore::addItem(std::shared_ptr 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)); + itemAdded(std::weak_ptr(items_.back())); + } +} + +void ItemStore::addItems(const std::vector>& itemIn) +{ + for(unsigned j = 0; j < itemIn.size(); j++) + { + addItem(itemIn[j]); + Train* train = dynamic_cast(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()); + } + } +} + diff --git a/src/common/items/itemstore.h b/src/common/items/itemstore.h new file mode 100644 index 0000000..ff2ce79 --- /dev/null +++ b/src/common/items/itemstore.h @@ -0,0 +1,36 @@ +#pragma once +#include +#include +#include "item.h" +#include "../nfcuid.h" + +class ItemStore: public QObject +{ + Q_OBJECT +protected: + std::vector< std::shared_ptr > items_; + +public: + + ItemStore(QObject *parent = nullptr); + virtual ~ItemStore() {} + + inline std::vector< std::shared_ptr >* getItems() + { + return &items_; + } + + void clear(); + +signals: + + void itemDeleted(ItemData item); + void itemAdded(std::weak_ptr Item); + +public slots: + + void removeItem(const ItemData& item); + virtual void addItem(std::shared_ptr item); + void addItems(const std::vector>& itemsIn); + void itemStateChanged(const ItemData& item); +}; diff --git a/src/common/items/train.cpp b/src/common/items/train.cpp new file mode 100644 index 0000000..cfa815a --- /dev/null +++ b/src/common/items/train.cpp @@ -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; +} + diff --git a/src/common/items/train.h b/src/common/items/train.h new file mode 100644 index 0000000..3b749f0 --- /dev/null +++ b/src/common/items/train.h @@ -0,0 +1,51 @@ +#ifndef TRAIN_H +#define TRAIN_H + +#include +#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 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 diff --git a/src/common/items/trainsignal.cpp b/src/common/items/trainsignal.cpp new file mode 100644 index 0000000..c8178ec --- /dev/null +++ b/src/common/items/trainsignal.cpp @@ -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; +} diff --git a/src/common/items/trainsignal.h b/src/common/items/trainsignal.h new file mode 100644 index 0000000..876437f --- /dev/null +++ b/src/common/items/trainsignal.h @@ -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 diff --git a/src/items/turnout.cpp b/src/common/items/turnout.cpp similarity index 73% rename from src/items/turnout.cpp rename to src/common/items/turnout.cpp index a2d3133..df82938 100644 --- a/src/items/turnout.cpp +++ b/src/common/items/turnout.cpp @@ -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); } diff --git a/src/items/turnout.h b/src/common/items/turnout.h similarity index 69% rename from src/items/turnout.h rename to src/common/items/turnout.h index 27cd975..6f203c2 100644 --- a/src/items/turnout.h +++ b/src/common/items/turnout.h @@ -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 diff --git a/src/common/microcontroller.cpp b/src/common/microcontroller.cpp new file mode 100644 index 0000000..a650895 --- /dev/null +++ b/src/common/microcontroller.cpp @@ -0,0 +1,253 @@ +#include "microcontroller.h" + +#include +#include +#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 Microcontroller::processTrainLine(const QString& buffer) +{ + QStringList bufferList = buffer.split(' '); + if(bufferList.size() >= 14 && buffer.startsWith("TRAIN NUMBER:")) + { + return std::shared_ptr(new Train(bufferList[2].toInt(), bufferList[4].toInt(), bufferList[13].toInt(nullptr, 2), + bufferList[9].toInt())); + } + return nullptr; +} + +std::shared_ptr Microcontroller::processTurnoutLine(const QString& buffer) +{ + QStringList bufferList = buffer.split(' '); + if(bufferList.size() >= 11 && buffer.startsWith("TURNOUT NUMBER:")) + { + return std::shared_ptr(new Turnout(bufferList[2].toInt(), bufferList[4].toInt(), bufferList[6].toInt(), + bufferList[11].toInt())); + } + return nullptr; +} + +std::shared_ptr Microcontroller::processSignalLine(const QString& buffer) +{ + QStringList bufferList = buffer.split(' '); + if(bufferList.size() >= 13 && buffer.startsWith("SIGNAL NUMBER:")) + { + return std::shared_ptr(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; + 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 = 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(*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(); + } + } +} diff --git a/src/common/microcontroller.h b/src/common/microcontroller.h new file mode 100644 index 0000000..fa28075 --- /dev/null +++ b/src/common/microcontroller.h @@ -0,0 +1,80 @@ +#ifndef MICROCONTROLLER_H +#define MICROCONTROLLER_H + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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 > itemList; + + QScopedPointer loop; + QString _buffer; + + void processMicroReturn(); + void processList(const QString& buffer); + void processItemState(const QString& buffer); + std::shared_ptr processTrainLine(const QString& buffer); + std::shared_ptr processTurnoutLine(const QString& buffer); + std::shared_ptr 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>&); + void gotTag(uint8_t reader, NfcUid uid); +}; + +#endif // MICROCONTROLLER_H diff --git a/src/common/nfcuid.h b/src/common/nfcuid.h new file mode 100644 index 0000000..90cf3fd --- /dev/null +++ b/src/common/nfcuid.h @@ -0,0 +1,53 @@ +#ifndef NFCUID_H +#define NFCUID_H +#include +#include + +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 list) + { + length = list.size(); + uint8_t i = 0; + for(std::initializer_list::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 + diff --git a/src/items/auxitem.cpp b/src/items/auxitem.cpp deleted file mode 100644 index 8f104c5..0000000 --- a/src/items/auxitem.cpp +++ /dev/null @@ -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); -} diff --git a/src/items/auxitem.h b/src/items/auxitem.h deleted file mode 100644 index a1e6765..0000000 --- a/src/items/auxitem.h +++ /dev/null @@ -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); -}; diff --git a/src/items/itemstore.cpp b/src/items/itemstore.cpp deleted file mode 100644 index 61b41eb..0000000 --- a/src/items/itemstore.cpp +++ /dev/null @@ -1,111 +0,0 @@ -#include "itemstore.h" -#include -#include -#include "train.h" -#include "../trainjs.h" - -ItemStore::ItemStore(QObject *parent): QObject(parent) -{ -} - -void ItemStore::addItem(std::shared_ptr 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)); - - if(dynamic_cast(item.get())) - { - std::vector> 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(items_.back())); - } - qDebug()<<"Got item: "<id()<<" matched: "<> joysticks = TrainJs::getJsDevices(); - for(auto joystick: joysticks) - { - if(joystick->getWantsNewItem()) - { - std::shared_ptr 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>& 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()); - } - - } - -} - diff --git a/src/items/itemstore.h b/src/items/itemstore.h deleted file mode 100644 index 6148027..0000000 --- a/src/items/itemstore.h +++ /dev/null @@ -1,38 +0,0 @@ -#pragma once -#include -#include -#include "item.h" - -#include - -class ItemStore: public QObject -{ - Q_OBJECT -private: - std::vector< std::shared_ptr > items_; - -public: - - ItemStore(QObject *parent = nullptr); - virtual ~ItemStore(){} - - inline std::vector< std::shared_ptr >* getItems(){ return &items_; } - - void clear(); - -private slots: - - void jsReqNewItem(); - -signals: - - void itemDeleted(ItemData item); - void itemAdded(std::weak_ptr Item); - -public slots: - - void removeItem(const ItemData& item); - void addItem(std::shared_ptr item); - void addItems(const std::vector>& itemsIn); - void itemStateChanged(const ItemData& item); -}; diff --git a/src/items/train.cpp b/src/items/train.cpp deleted file mode 100644 index 09266de..0000000 --- a/src/items/train.cpp +++ /dev/null @@ -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_); -} - diff --git a/src/items/train.h b/src/items/train.h deleted file mode 100644 index 41bbf0e..0000000 --- a/src/items/train.h +++ /dev/null @@ -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 diff --git a/src/main.cpp b/src/main.cpp deleted file mode 100644 index 4464629..0000000 --- a/src/main.cpp +++ /dev/null @@ -1,111 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include - -#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 "<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 "<portName().toStdString()<<". Continueing in demo mode"<<'\n'; - return 1; - } - masterIODevice = microPort; - } - - Microcontroller micro(masterIODevice); - micro.setPower(true); - - TrainJs::init(); - - Train::micro = µ - Turnout::micro = µ - ItemStore items; - - QObject::connect(µ, &Microcontroller::gotItemList, &items, &ItemStore::addItems); - QObject::connect(µ, &Microcontroller::itemChanged, &items, &ItemStore::itemStateChanged); - - //mainwindow - MainWindow w(µ, &items); - - w.show(); - - int retVal = a.exec(); - micro.setPower(false); - - if(masterIODevice) - delete masterIODevice; - return retVal; -} - diff --git a/src/mainobject.cpp b/src/mainobject.cpp deleted file mode 100644 index 4af15c0..0000000 --- a/src/mainobject.cpp +++ /dev/null @@ -1,14 +0,0 @@ -#include "mainobject.h" - -MainObject::MainObject(QIODevice* ioDevice) : - masterIODevice(ioDevice), - micro(masterIODevice) -{ - //connect item store - QObject::connect(µ, &Microcontroller::gotItemList, &items, &ItemStore::addItems); -} - -MainObject::~MainObject() -{ -} - diff --git a/src/microcontroller.cpp b/src/microcontroller.cpp deleted file mode 100644 index 093be50..0000000 --- a/src/microcontroller.cpp +++ /dev/null @@ -1,199 +0,0 @@ -#include "microcontroller.h" - -#include -#include -#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()<write(buffer); - _port->waitForBytesWritten(1000); - } - std::this_thread::sleep_for(std::chrono::milliseconds(40)); -} - -void Microcontroller::write(char* buffer, const size_t length) -{ - qDebug()<write(buffer, length); - //_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 Microcontroller::processTrainLine(const QString& buffer) -{ - QStringList bufferList = buffer.split(' '); - if(bufferList.size() >= 14 && buffer.startsWith("TRAIN NUMBER:")) - { - return std::shared_ptr(new Train(bufferList[2].toInt(), bufferList[4].toInt(), bufferList[13].toInt(nullptr, 2), bufferList[9].toInt())); - } - return nullptr; -} - -std::shared_ptr Microcontroller::processTurnoutLine(const QString& buffer) -{ - QStringList bufferList = buffer.split(' '); - if(bufferList.size() >= 11 && buffer.startsWith("TURNOUT NUMBER:")) - { - return std::shared_ptr(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__<<" :"<= 10 && buffer.contains("NUMBER:")) - { - std::shared_ptr 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(*processTrainLine(buffer))); - else if(_buffer.startsWith("TURNOUT NUMBER:")) - itemChanged(static_cast(*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(); - } - } -} diff --git a/src/microcontroller.h b/src/microcontroller.h deleted file mode 100644 index cddfe2e..0000000 --- a/src/microcontroller.h +++ /dev/null @@ -1,83 +0,0 @@ -#ifndef MICROCONTROLLER_H -#define MICROCONTROLLER_H - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#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 > itemList; - - QScopedPointer loop; - QString _buffer; - - void processMicroReturn(); - void processList(const QString& buffer); - void processItemState(const QString& buffer); - std::shared_ptr processTrainLine(const QString& buffer); - std::shared_ptr 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 >&); -}; - -#endif // MICROCONTROLLER_H diff --git a/src/trainControllerUI/CMakeLists.txt b/src/trainControllerUI/CMakeLists.txt new file mode 100644 index 0000000..b201225 --- /dev/null +++ b/src/trainControllerUI/CMakeLists.txt @@ -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}) diff --git a/src/trainControllerUI/QJoysticks.cpp b/src/trainControllerUI/QJoysticks.cpp new file mode 100644 index 0000000..2d6e964 --- /dev/null +++ b/src/trainControllerUI/QJoysticks.cpp @@ -0,0 +1,479 @@ +/* + * Copyright (c) 2015-2017 Alex Spataru + * + * 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 +#include +#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 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); + } + } +} diff --git a/src/QJoysticks.h b/src/trainControllerUI/QJoysticks.h similarity index 50% rename from src/QJoysticks.h rename to src/trainControllerUI/QJoysticks.h index 819e092..6988a82 100644 --- a/src/QJoysticks.h +++ b/src/trainControllerUI/QJoysticks.h @@ -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 inputDevices() const; + SDL_Joysticks *sdlJoysticks() const; + VirtualJoystick *virtualJoystick() const; + QJoystickDevice *getInputDevice(const int index); + QList 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 m_devices; + QList m_devices; }; #endif diff --git a/src/jsbackend/JoysticksCommon.h b/src/trainControllerUI/jsbackend/JoysticksCommon.h similarity index 100% rename from src/jsbackend/JoysticksCommon.h rename to src/trainControllerUI/jsbackend/JoysticksCommon.h diff --git a/src/jsbackend/JoysticksCommon.h.orig b/src/trainControllerUI/jsbackend/JoysticksCommon.h.orig similarity index 100% rename from src/jsbackend/JoysticksCommon.h.orig rename to src/trainControllerUI/jsbackend/JoysticksCommon.h.orig diff --git a/src/jsbackend/SDL_Joysticks.cpp b/src/trainControllerUI/jsbackend/SDL_Joysticks.cpp similarity index 95% rename from src/jsbackend/SDL_Joysticks.cpp rename to src/trainControllerUI/jsbackend/SDL_Joysticks.cpp index 4b2bdd0..b78c4ef 100644 --- a/src/jsbackend/SDL_Joysticks.cpp +++ b/src/trainControllerUI/jsbackend/SDL_Joysticks.cpp @@ -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() diff --git a/src/jsbackend/SDL_Joysticks.cpp.orig b/src/trainControllerUI/jsbackend/SDL_Joysticks.cpp.orig similarity index 100% rename from src/jsbackend/SDL_Joysticks.cpp.orig rename to src/trainControllerUI/jsbackend/SDL_Joysticks.cpp.orig diff --git a/src/jsbackend/SDL_Joysticks.h b/src/trainControllerUI/jsbackend/SDL_Joysticks.h similarity index 100% rename from src/jsbackend/SDL_Joysticks.h rename to src/trainControllerUI/jsbackend/SDL_Joysticks.h diff --git a/src/jsbackend/SDL_Joysticks.h.orig b/src/trainControllerUI/jsbackend/SDL_Joysticks.h.orig similarity index 100% rename from src/jsbackend/SDL_Joysticks.h.orig rename to src/trainControllerUI/jsbackend/SDL_Joysticks.h.orig diff --git a/src/jsbackend/VirtualJoystick.cpp b/src/trainControllerUI/jsbackend/VirtualJoystick.cpp similarity index 100% rename from src/jsbackend/VirtualJoystick.cpp rename to src/trainControllerUI/jsbackend/VirtualJoystick.cpp diff --git a/src/jsbackend/VirtualJoystick.cpp.orig b/src/trainControllerUI/jsbackend/VirtualJoystick.cpp.orig similarity index 100% rename from src/jsbackend/VirtualJoystick.cpp.orig rename to src/trainControllerUI/jsbackend/VirtualJoystick.cpp.orig diff --git a/src/jsbackend/VirtualJoystick.h b/src/trainControllerUI/jsbackend/VirtualJoystick.h similarity index 100% rename from src/jsbackend/VirtualJoystick.h rename to src/trainControllerUI/jsbackend/VirtualJoystick.h diff --git a/src/jsbackend/VirtualJoystick.h.orig b/src/trainControllerUI/jsbackend/VirtualJoystick.h.orig similarity index 100% rename from src/jsbackend/VirtualJoystick.h.orig rename to src/trainControllerUI/jsbackend/VirtualJoystick.h.orig diff --git a/src/trainControllerUI/mainobject.cpp b/src/trainControllerUI/mainobject.cpp new file mode 100644 index 0000000..3a0558b --- /dev/null +++ b/src/trainControllerUI/mainobject.cpp @@ -0,0 +1,14 @@ +#include "mainobject.h" + +MainObject::MainObject(QIODevice* ioDevice) : + masterIODevice(ioDevice), + micro(masterIODevice) +{ + //connect item store + QObject::connect(µ, &Microcontroller::gotItemList, &items, &ItemStore::addItems); +} + +MainObject::~MainObject() +{ +} + diff --git a/src/mainobject.h b/src/trainControllerUI/mainobject.h similarity index 59% rename from src/mainobject.h rename to src/trainControllerUI/mainobject.h index 234bd16..9c00769 100644 --- a/src/mainobject.h +++ b/src/trainControllerUI/mainobject.h @@ -7,9 +7,6 @@ #include #include #include -#include -#include -#include #include @@ -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 diff --git a/src/trainControllerUI/traincontrollerui.cpp b/src/trainControllerUI/traincontrollerui.cpp new file mode 100644 index 0000000..6541439 --- /dev/null +++ b/src/trainControllerUI/traincontrollerui.cpp @@ -0,0 +1,116 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#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 "<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 "<portName().toStdString()<<". Continueing in demo mode"<<'\n'; + return 1; + } + masterIODevice = microPort; + } + + Microcontroller micro(masterIODevice); + micro.setPower(true); + + TrainJs::init(); + + Train::micro = µ + Turnout::micro = µ + Signal::micro = µ + ItemStore items; + + QObject::connect(µ, &Microcontroller::gotItemList, &items, &ItemStore::addItems); + QObject::connect(µ, &Microcontroller::itemChanged, &items, &ItemStore::itemStateChanged); + + //mainwindow + MainWindow w(µ, &items); + + w.show(); + + int retVal = a.exec(); + micro.setPower(false); + + if(masterIODevice) + delete masterIODevice; + return retVal; +} + diff --git a/src/trainjs.cpp b/src/trainControllerUI/trainjs.cpp similarity index 100% rename from src/trainjs.cpp rename to src/trainControllerUI/trainjs.cpp diff --git a/src/trainjs.h b/src/trainControllerUI/trainjs.h similarity index 94% rename from src/trainjs.h rename to src/trainControllerUI/trainjs.h index fb5f94f..f8a325b 100644 --- a/src/trainjs.h +++ b/src/trainControllerUI/trainjs.h @@ -41,7 +41,10 @@ public: std::weak_ptr getItem(); void setItem(std::weak_ptr); bool itemIsSet(); - bool getWantsNewItem() {return wantsNewItem;} + bool getWantsNewItem() + { + return wantsNewItem; + } }; #endif // TRAINJS_H diff --git a/src/trainControllerUI/ui/itemscrollbox.cpp b/src/trainControllerUI/ui/itemscrollbox.cpp new file mode 100644 index 0000000..50f4d7b --- /dev/null +++ b/src/trainControllerUI/ui/itemscrollbox.cpp @@ -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) +{ + if(auto workItem = item.lock()) + { + Train* train = dynamic_cast(workItem.get()); + Turnout* turnout = dynamic_cast(workItem.get()); + Signal* signal = dynamic_cast(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> 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> joysticks = TrainJs::getJsDevices(); + for(auto joystick: joysticks) + { + if(joystick->getWantsNewItem()) + { + std::shared_ptr oldItem = joystick->getItem().lock(); + for(size_t i = 0; i < widgets_.size(); ++i) + { + std::shared_ptr 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 = widgets_[i]->getItem().lock(); + if(item && dynamic_cast(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); + } + } +} + + diff --git a/src/ui/itemscrollbox.h b/src/trainControllerUI/ui/itemscrollbox.h similarity index 50% rename from src/ui/itemscrollbox.h rename to src/trainControllerUI/ui/itemscrollbox.h index 2d78f2a..444e608 100644 --- a/src/ui/itemscrollbox.h +++ b/src/trainControllerUI/ui/itemscrollbox.h @@ -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); - void removeItem(const ItemData& item); + void addItem(std::weak_ptr item); + void removeItem(const ItemData& item); + void jsReqNewItem(); private: - Ui::RelayScrollBox *ui; + Ui::RelayScrollBox *ui; }; #endif // RELAYSCROLLBOX_H diff --git a/src/trainControllerUI/ui/itemwidget.cpp b/src/trainControllerUI/ui/itemwidget.cpp new file mode 100644 index 0000000..b780b09 --- /dev/null +++ b/src/trainControllerUI/ui/itemwidget.cpp @@ -0,0 +1,36 @@ +#include "itemwidget.h" + +#include +#include +#include +#include "../items/train.h" +#include "../items/turnout.h" + +ItemWidget::ItemWidget(std::weak_ptr 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 ItemWidget::getItem() +{ + return item_; +} + +ItemWidget::~ItemWidget() +{ +} diff --git a/src/trainControllerUI/ui/itemwidget.h b/src/trainControllerUI/ui/itemwidget.h new file mode 100644 index 0000000..f4093d9 --- /dev/null +++ b/src/trainControllerUI/ui/itemwidget.h @@ -0,0 +1,30 @@ +#pragma once + +#include +#include +#include +#include "../items/item.h" + +class ItemWidget : public QWidget +{ + Q_OBJECT +protected: + std::weak_ptr item_; + + virtual void disable(){} + +signals: + + void deleteRequest(const ItemData& item); + +public: + explicit ItemWidget(std::weak_ptr item, QWidget *parent); + std::weak_ptr getItem(); + bool controles(const ItemData& relay); + ~ItemWidget(); + +public slots: + + virtual void stateChanged(int state){(void)state;} +}; + diff --git a/src/trainControllerUI/ui/mainwindow.cpp b/src/trainControllerUI/ui/mainwindow.cpp new file mode 100644 index 0000000..b2d6b13 --- /dev/null +++ b/src/trainControllerUI/ui/mainwindow.cpp @@ -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); + } +} +*/ diff --git a/src/ui/mainwindow.h b/src/trainControllerUI/ui/mainwindow.h similarity index 57% rename from src/ui/mainwindow.h rename to src/trainControllerUI/ui/mainwindow.h index 890b84b..17a9071 100644 --- a/src/ui/mainwindow.h +++ b/src/trainControllerUI/ui/mainwindow.h @@ -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); + void createdItem(std::shared_ptr item); private slots: - //void showItemCreationDialog(); + //void showItemCreationDialog(); }; diff --git a/src/ui/mainwindow.ui b/src/trainControllerUI/ui/mainwindow.ui similarity index 100% rename from src/ui/mainwindow.ui rename to src/trainControllerUI/ui/mainwindow.ui diff --git a/src/ui/relayscrollbox.ui b/src/trainControllerUI/ui/relayscrollbox.ui similarity index 100% rename from src/ui/relayscrollbox.ui rename to src/trainControllerUI/ui/relayscrollbox.ui diff --git a/src/trainControllerUI/ui/signalwidget.cpp b/src/trainControllerUI/ui/signalwidget.cpp new file mode 100644 index 0000000..6bb722b --- /dev/null +++ b/src/trainControllerUI/ui/signalwidget.cpp @@ -0,0 +1,96 @@ +#include "signalwidget.h" +#include "ui_signalwidget.h" + +#include +#include +#include +#include "trainsignal.h" + +SignalWidget::SignalWidget(std::weak_ptr item, QWidget *parent) : + ItemWidget(item, parent), + ui(new Ui::SignalWidget) +{ + ui->setupUi(this); + + if(auto workingItem = item_.lock()) + { + std::shared_ptr signal = std::dynamic_pointer_cast(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"<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; +} diff --git a/src/trainControllerUI/ui/signalwidget.h b/src/trainControllerUI/ui/signalwidget.h new file mode 100644 index 0000000..6cc36f3 --- /dev/null +++ b/src/trainControllerUI/ui/signalwidget.h @@ -0,0 +1,36 @@ +#pragma once + +#include +#include +#include +#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, QWidget *parent); + ~SignalWidget(); + +public slots: + + virtual void stateChanged(int state); + +private: + Ui::SignalWidget *ui; +}; diff --git a/src/trainControllerUI/ui/signalwidget.ui b/src/trainControllerUI/ui/signalwidget.ui new file mode 100644 index 0000000..2f6a4ed --- /dev/null +++ b/src/trainControllerUI/ui/signalwidget.ui @@ -0,0 +1,98 @@ + + + SignalWidget + + + + 0 + 0 + 312 + 78 + + + + + 0 + 0 + + + + Form + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 0 + + + + + TextLabel + + + + + + + + + + + Go + + + true + + + + + + + Slow + + + false + + + + + + + Stop + + + + + + + + + + + + + Qt::Horizontal + + + + + + + + diff --git a/src/trainControllerUI/ui/trainwidget.cpp b/src/trainControllerUI/ui/trainwidget.cpp new file mode 100644 index 0000000..59bd65c --- /dev/null +++ b/src/trainControllerUI/ui/trainwidget.cpp @@ -0,0 +1,194 @@ +#include "trainwidget.h" +#include "ui_trainwidget.h" + +#include +#include +#include +#include "../items/train.h" +#include "../items/turnout.h" + +TrainWidget::TrainWidget(std::weak_ptr 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(workingItem.get()); + Turnout* turnout = dynamic_cast(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(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(new QShortcut(up, this))); + connect(shortcuts_.back().get(), &QShortcut::activated, this, &TrainWidget::stepUp); + shortcuts_.push_back(std::unique_ptr(new QShortcut(down, this))); + connect(shortcuts_.back().get(), &QShortcut::activated, this, &TrainWidget::stepDown); + shortcuts_.push_back(std::unique_ptr(new QShortcut(rev, this))); + connect(shortcuts_.back().get(), &QShortcut::activated, this, &TrainWidget::reverse); +} + +void TrainWidget::stateChanged(int state) +{ + qDebug()<<"widget got state "<slider->blockSignals(true); + ui->slider->setValue(state); + ui->slider->blockSignals(false); +} + +TrainWidget::~TrainWidget() +{ + delete ui; +} diff --git a/src/trainControllerUI/ui/trainwidget.h b/src/trainControllerUI/ui/trainwidget.h new file mode 100644 index 0000000..d2edca4 --- /dev/null +++ b/src/trainControllerUI/ui/trainwidget.h @@ -0,0 +1,48 @@ +#pragma once + +#include +#include +#include +#include "../items/item.h" +#include "itemwidget.h" + +namespace Ui +{ +class TrainWidget; +} + +class TrainWidget : public ItemWidget +{ + Q_OBJECT +protected: + std::vector< std::unique_ptr > 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, QWidget *parent); + ~TrainWidget(); + void setShortcuts(QKeySequence up, QKeySequence down, QKeySequence rev); + +public slots: + + virtual void stateChanged(int state); + +private: + Ui::TrainWidget *ui; +}; + diff --git a/src/ui/itemwidget.ui b/src/trainControllerUI/ui/trainwidget.ui similarity index 98% rename from src/ui/itemwidget.ui rename to src/trainControllerUI/ui/trainwidget.ui index 8fb7574..eec9954 100644 --- a/src/ui/itemwidget.ui +++ b/src/trainControllerUI/ui/trainwidget.ui @@ -1,7 +1,7 @@ - ItemWidget - + TrainWidget + 0 diff --git a/src/trainOverlord/CMakeLists.txt b/src/trainOverlord/CMakeLists.txt new file mode 100644 index 0000000..ce7f463 --- /dev/null +++ b/src/trainOverlord/CMakeLists.txt @@ -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 ./) diff --git a/src/trainOverlord/block.cpp b/src/trainOverlord/block.cpp new file mode 100644 index 0000000..0c9b23d --- /dev/null +++ b/src/trainOverlord/block.cpp @@ -0,0 +1,308 @@ +#include "block.h" +#include +#include +#include +#include "nfcuid.h" + + +Block::Block(OverlordItemStore* items, uint32_t id): + items_(items), id_(id) +{ + +} + +void Block::addBorder(std::shared_ptr border) +{ + borders_.push_back(border); + std::shared_ptr block = border->getOtherBlock(this); + if(!block || block.get() == this) + 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 = items_->getTrainThatOwns(tag); + if(!train) + return false; + for(const NfcUid& canidate : tags_) + { + std::shared_ptr canidateTrain = items_->getTrainThatOwns(canidate); + if(*canidateTrain == *train) + return true; + } + return false; +} + +bool Block::ownsBorder(std::shared_ptr border) +{ + if(!border) + return false; + for(std::shared_ptr borderTest : borders_) + { + if(borderTest == border) + return true; + } + return false; +} + +void Block::checkWaits(bool isBlocked) +{ + if(isBlocked) + return; + bool wasBlocked = blocked(); + for(std::vector::iterator iter = waits_.begin(); iter != waits_.end();) + { + if(iter->type != WAIT_TYPE_BLOCK) + { + ++iter; + continue; + } + + std::shared_ptr block = iter->targetBlock.lock(); + std::shared_ptr train = iter->train.lock(); + qDebug()<<__func__<<"trying to push train"<getTrainId()<<"to block"<id(); + if(block && train && train->suspendend() && block->pushTag(iter->tag)) + { + train->resume(); + std::shared_ptr border = iter->border.lock(); + if(border) + border->updateSignals(); + iter = waits_.erase(iter); + } + else if(!block || !train || !train->suspendend()) + { + iter = waits_.erase(iter); + } + else + { + ++iter; + } + } + if(wasBlocked != blocked()) + blockedChanged(!wasBlocked); +} + +bool Block::pushTag(const NfcUid& tag) +{ + if(!blocked() || tagIsOfOwnedTrain(tag)) + { + addTag(tag); + return true; + } + return false; +} + +void Block::removeTraverse(std::shared_ptr train) +{ + bool wasBlocked = blocked(); + for(std::vector::iterator iter = waits_.begin(); iter != waits_.end();) + { + if(iter->type == WAIT_TYPE_TIMED_TRAVERSE) + { + std::shared_ptr iterTrain = iter->train.lock(); + if(!iterTrain) + { + iter = waits_.erase(iter); + continue; + } + if(*iterTrain == *train) + { + qDebug()<<"Train"<getTrainId()<<"removed from traverse wait for block"< train = items_->getTrainThatOwns(tag); + if(!train) + return; + if(!train->hasBackTag()) + { + qDebug()<<"Train"<getTrainId()<<"added as timed traverse wait for block"< block, std::shared_ptr border) +{ + std::shared_ptr 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"<getTrainId()<<"is wating at border for 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"<::iterator iter = waits_.begin(); iter != waits_.end(); ++iter) + { + std::shared_ptr workTrain = iter->train.lock(); + if(!workTrain) + { + waits_.erase(iter); + unsuspendedTrain(id, direction); + break; + } + if(workTrain->id() == id) + { + std::shared_ptr block = iter->targetBlock.lock(); + disconnect(workTrain.get(), &Train::unsuspended, this, &Block::unsuspendedTrain); + if(block) + block->addTag(iter->tag); + waits_.erase(iter); + break; + } + } + if(wasBlocked != blocked()) + blockedChanged(!wasBlocked); +} + +void Block::removeTag(const NfcUid& tag) +{ + for(std::vector::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 = items_->getTrainThatOwns(tag); + if(train) + removeTraverse(train); + if(wasBlocked != blocked()) + blockedChanged(!wasBlocked); +} + +void Block::tagArrivedAtBorder(NfcUid tag, std::weak_ptr borderIn) +{ + bool wasBlocked = blocked(); + qDebug()<<__func__<<"block"< border = borderIn.lock(); + if(!border) + { + qWarning()<<"border has expired in"<<__func__; + return; + } + + if(!ownsBorder(border)) + return; + + qDebug()<<"Block"<getOtherBlock(this); + if(block) + { + if(!block->pushTag(tag)) + { + std::shared_ptr 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(id_); + QJsonArray borders; + for(auto& border : borders_) + { + QJsonObject borderObject; + borderObject["BorderId"] = static_cast(border->id()); + borders.append(borderObject); + } + json["Borders"] = borders; +} + +void Block::load(const QJsonObject &json) +{ + id_ = static_cast(json["Id"].toDouble(0)); +} + +void Block::populate(const QJsonObject& json, Layout* layout) +{ + borders_.clear(); + const QJsonArray bordersArray(json["Borders"].toArray(QJsonArray())); + for(const auto& arrayObj : bordersArray) + { + if(arrayObj.isObject()) + { + uint32_t borderId = static_cast(arrayObj.toObject()["BorderId"].toDouble(INT32_MAX)); + std::shared_ptr border = layout->getBorder(borderId); + if(border) + addBorder(border); + else if(borderId == INT32_MAX) + qWarning()<<"BorderId field is missing in border array for block"< +#include +#include +#include +#include +#include "blockborder.h" +#include "train.h" +#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; + std::weak_ptr targetBlock; + std::weak_ptr border; + }; + + std::vector< std::shared_ptr > borders_; + std::vector tags_; + std::vector waits_; + uint32_t id_; + OverlordItemStore* items_; + +protected slots: + void unsuspendedTrain(uint32_t id, int direction); + void removeTraverse(std::shared_ptr train); + +protected: + void checkWaits(bool blocked = false); + void addTraverseWait(const NfcUid& tag); + void addBlockWait(const NfcUid& tag, std::shared_ptr block, std::shared_ptr 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 border); + std::vector< std::shared_ptr > getBorders(){return borders_;} + bool ownsBorder(std::shared_ptr 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 border); + +signals: + void blockedChanged(bool blocked); +}; + +#endif // BLOCK_H diff --git a/src/trainOverlord/blockborder.cpp b/src/trainOverlord/blockborder.cpp new file mode 100644 index 0000000..f6ec684 --- /dev/null +++ b/src/trainOverlord/blockborder.cpp @@ -0,0 +1,172 @@ +#include "blockborder.h" +#include +#include + +BlockBorder::BlockBorder(uint8_t reader, std::pair, std::weak_ptr> 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> blocks) +{ + blocks_ = blocks; + std::shared_ptr first = blocks.first.lock(); + if(first) + connect(first.get(), &Block::blockedChanged, this, &BlockBorder::blockedChanged); + std::shared_ptr second = blocks.second.lock(); + if(second) + connect(second.get(), &Block::blockedChanged, this, &BlockBorder::blockedChanged); +} + +void BlockBorder::setSignal(std::weak_ptr signalWeak, int8_t value) +{ + std::shared_ptr 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 = signals_[i].lock(); + if(signal) + { + std::shared_ptr block = signalDirections_[i] ? blocks_.first.lock() : blocks_.second.lock(); + if(block && block->blocked()) + { + if(signal->getValue() != Signal::STOP) + { + std::weak_ptr signalWeak = signal; + QTimer::singleShot(500, signal.get(), [signalWeak](){BlockBorder::setSignal(signalWeak, Signal::STOP);}); + } + } + else + { + if(signal->getValue() != Signal::GO) + { + std::weak_ptr signalWeak = signal; + QTimer::singleShot(500, signal.get(), [signalWeak](){BlockBorder::setSignal(signalWeak, Signal::GO);}); + } + } + } + else + { + signals_.erase(signals_.begin()+i); + updateSignals(); + break; + } + } +} + +void BlockBorder::addSignal(std::weak_ptr signal, std::shared_ptr block) +{ + signals_.push_back(signal); + signalDirections_.push_back(block == blocks_.first.lock()); +} + +std::shared_ptr BlockBorder::getOtherBlock(Block* block) +{ + std::shared_ptr first = blocks_.first.lock(); + std::shared_ptr second = blocks_.second.lock(); + + if(first && first.get() == block) + return second; + if(second && second.get() == block) + return first; + return std::shared_ptr(); +} + +std::shared_ptr BlockBorder::getOverlap(BlockBorder* border) +{ + if(border->getBlocks().first.lock() == blocks_.first.lock() || border->getBlocks().first.lock() == blocks_.second.lock()) + { + return border->getBlocks().first.lock(); + } + else if(border->getBlocks().second.lock() == blocks_.first.lock() || border->getBlocks().second.lock() == blocks_.second.lock()) + { + return border->getBlocks().second.lock(); + } + return std::shared_ptr(); +} + +void BlockBorder::store(QJsonObject& json) +{ + json["Id"] = static_cast(id_); + json["Reader"] = static_cast(reader_); + QJsonArray signalArray; + for(size_t i = 0; i < signals_.size(); ++i) + { + std::shared_ptr signalPtr = signals_[i].lock(); + if(signalPtr) + { + QJsonObject signalObject; + signalObject["SignalId"] = static_cast(signalPtr->getSignalId()); + signalObject["Direction"] = static_cast(signalDirections_[i]); + signalArray.append(signalObject); + } + } + json["Signals"] = signalArray; +} + +void BlockBorder::load(const QJsonObject& json) +{ + id_ = static_cast(json["Id"].toDouble(0)); + reader_ = json["Reader"].toDouble(0); + const QJsonArray signalArray(json["Signals"].toArray(QJsonArray())); + for(const auto& arrayObj : signalArray) + { + if(arrayObj.isObject()) + { + QJsonObject arrayObjObj = arrayObj.toObject(); + signalIds_.push_back(std::pair(static_cast(arrayObjObj["SignalId"].toDouble(INT32_MAX)), static_cast(arrayObjObj["Direction"].toDouble(0)))); + } + } +} + +bool BlockBorder::hasMissingSingal() +{ + for(auto& signal : signalIds_) + { + qDebug()<<"Missing signal id:"< item) +{ + std::shared_ptr workItem = item.lock(); + if(!workItem) + return; + std::shared_ptr signal = std::dynamic_pointer_cast(workItem); + if(!signal) + return; + for(const std::pair& signalPair : signalIds_) + { + if(signalPair.first == signal->getSignalId()) + { + signals_.push_back(signal); + signalDirections_.push_back(signalPair.second); + qDebug()<<"Border"<getSignalId(); + } + } + std::erase_if(signalIds_, [signal](std::pair pair) -> bool{return pair.first == signal->getSignalId();}); +} diff --git a/src/trainOverlord/blockborder.h b/src/trainOverlord/blockborder.h new file mode 100644 index 0000000..8d72457 --- /dev/null +++ b/src/trainOverlord/blockborder.h @@ -0,0 +1,44 @@ +#ifndef BLOCKBORDER_H +#define BLOCKBORDER_H +#include "trainsignal.h" +#include "block.h" +#include +#include + +class Block; +class Layout; + +class BlockBorder: public QObject +{ +Q_OBJECT +private: + uint64_t reader_; + uint32_t id_; + std::vector> signalIds_; + std::vector> signals_; + std::vector signalDirections_; + std::pair, std::weak_ptr> blocks_; + + static void setSignal(std::weak_ptr signalWeak, int8_t value); + +public: + BlockBorder(uint8_t reader = 0, std::pair, std::weak_ptr> blocks = std::pair, std::weak_ptr>(), uint32_t id = QRandomGenerator::global()->generate()); + bool isReader(uint8_t reader); + uint8_t getReader(); + void updateSignals(); + std::shared_ptr getOtherBlock(Block* block); + std::pair, std::weak_ptr> getBlocks(){return blocks_;} + void setBlocks(std::pair, std::weak_ptr> blocks); + void addSignal(std::weak_ptr signal, std::shared_ptr block); + void informOfItem(std::weak_ptr item); + bool hasMissingSingal(); + std::shared_ptr 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 diff --git a/src/trainOverlord/layout.cpp b/src/trainOverlord/layout.cpp new file mode 100644 index 0000000..8c27735 --- /dev/null +++ b/src/trainOverlord/layout.cpp @@ -0,0 +1,221 @@ +#include "layout.h" +#include +#include + +Layout::Layout(OverlordItemStore* items, QObject *parent): QObject{parent}, items_(items) +{ +} + +void Layout::removeTagFromAllBlocks(const NfcUid& tag) +{ + for(std::shared_ptr block : blocks_) + { + block->purgeTag(tag); + } +} + +void Layout::registerTagInLimbo(const NfcUid& tag, std::shared_ptr border) +{ + for(auto iter = limbo_.begin(); iter != limbo_.end(); ++iter) + { + NfcUid limboTag = iter->first; + std::shared_ptr limboBorder = iter->second.lock(); + if(!limboBorder) + { + limbo_.erase(iter); + registerTagInLimbo(tag, border); + return; + } + + if(limboTag == tag) + { + if(border == limboBorder) + return; + + std::shared_ptr overlap = border->getOverlap(limboBorder.get()); + if(overlap) + { + qDebug()<<"Tag"<id()<<"while crossing border"<id(); + overlap->addTag(tag); + overlap->tagArrivedAtBorder(tag, border); + limbo_.erase(iter); + return; + } + else + { + iter->second = border; + return; + } + + } + } + std::shared_ptr first = border->getBlocks().first.lock(); + std::shared_ptr second = border->getBlocks().second.lock(); + + qDebug()<<"Tag"<id()) : "invalid")<<"and block"<<(second ? QString::number(second->id()) : "invalid"); + limbo_.push_back(std::pair>(tag, border)); +} + +void Layout::tagArrivedAtReader(uint8_t reader, NfcUid tag) +{ + std::shared_ptr border; + for(std::shared_ptr borderTest : borders_) + { + if(borderTest->getReader() == reader) + { + border = borderTest; + break; + } + } + if(!border) + { + qWarning()<<"reader "< train = items_->getTrainThatOwns(tag); + qDebug()<<"Train"<<(train ? train->getTrainId() : -1)<<"Tag"<id(); + + bool tagHandled = false; + for(std::shared_ptr& 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) +{ + blocks_.push_back(block); +} + +void Layout::addBorder(std::shared_ptr border) +{ + borders_.push_back(border); +} + +std::shared_ptr Layout::getBorder(uint32_t id) +{ + for(const std::shared_ptr& border : borders_) + { + if(border->id() == id) + return border; + } + return std::shared_ptr(); +} + +std::shared_ptr Layout::getBlock(uint32_t id) +{ + for(const std::shared_ptr& block : blocks_) + { + if(block->id() == id) + return block; + } + return std::shared_ptr(); +} + +void Layout::store(QJsonObject& json) +{ + QJsonArray blockArray; + for(const std::shared_ptr& block : blocks_) + { + QJsonObject object; + block->store(object); + blockArray.append(object); + } + json["Blocks"] = blockArray; + + QJsonArray borderArray; + for(const std::shared_ptr& border : borders_) + { + QJsonObject object; + border->store(object); + borderArray.append(object); + } + json["Borders"] = borderArray; +} + +void Layout::load(const QJsonObject& json) +{ + std::vector blockJsonObjects; + const QJsonArray blockArray(json["Blocks"].toArray(QJsonArray())); + for(const auto& object : blockArray) + { + if(object.isObject()) + { + const QJsonObject jsonObject = object.toObject(); + blockJsonObjects.push_back(jsonObject); + std::shared_ptr block(new Block(items_)); + block->load(jsonObject); + blocks_.push_back(block); + } + } + + std::vector borderJsonObjects; + const QJsonArray borderArray(json["Borders"].toArray(QJsonArray())); + for(const auto& object : borderArray) + { + if(object.isObject()) + { + const QJsonObject jsonObject = object.toObject(); + borderJsonObjects.push_back(jsonObject); + std::shared_ptr border(new BlockBorder); + border->load(object.toObject()); + borders_.push_back(border); + } + } + + for(size_t i = 0; i < blocks_.size(); ++i) + { + blocks_[i]->populate(blockJsonObjects[i], this); + } + + for(std::shared_ptr& border : borders_) + { + std::shared_ptr first; + std::shared_ptr second; + for(std::shared_ptr& block : blocks_) + { + if(block->ownsBorder(border)) + { + if(!first) + first = block; + else if(!second) + second = block; + else + qWarning()<<"border with id"<id()<<"is assigned to more than 2 blocks"; + } + } + if(!first || !second) + qWarning()<<"border with id"<id()<<"is assigned to less than than 2 blocks"; + border->setBlocks(std::pair, std::weak_ptr>(first, second)); + + for(std::shared_ptr& 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"<id()<<"doset have at least one border"; + } +} diff --git a/src/trainOverlord/layout.h b/src/trainOverlord/layout.h new file mode 100644 index 0000000..7bbe6fe --- /dev/null +++ b/src/trainOverlord/layout.h @@ -0,0 +1,42 @@ +#ifndef BLOCKSTORE_H +#define BLOCKSTORE_H + +#include +#include +#include + +#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> blocks_; + std::vector> borders_; + std::vector>> limbo_; + + void removeTagFromAllBlocks(const NfcUid& tag); + void registerTagInLimbo(const NfcUid& tag, std::shared_ptr); + + OverlordItemStore *items_; + +public: + explicit Layout(OverlordItemStore *items, QObject *parent = nullptr); + void addBlock(std::shared_ptr block); + void addBorder(std::shared_ptr border); + void store(QJsonObject& json); + void load(const QJsonObject& json); + std::shared_ptr getBorder(uint32_t id); + std::shared_ptr getBlock(uint32_t id); + +public slots: + void tagArrivedAtReader(uint8_t reader, NfcUid tag); +}; + +#endif // BLOCKSTORE_H diff --git a/src/trainOverlord/overlorditemstore.cpp b/src/trainOverlord/overlorditemstore.cpp new file mode 100644 index 0000000..4e3c0f3 --- /dev/null +++ b/src/trainOverlord/overlorditemstore.cpp @@ -0,0 +1,20 @@ +#include "overlorditemstore.h" +#include +#include "train.h" + +OverlordItemStore::OverlordItemStore(QObject *parent): ItemStore(parent) +{ +} + +std::shared_ptr OverlordItemStore::getTrainThatOwns(const NfcUid& uid) +{ + for(std::shared_ptr item : items_) + { + std::shared_ptr train = std::dynamic_pointer_cast(item); + if(!train) + continue; + if(train->ownsTag(uid)) + return train; + } + return std::shared_ptr(); +} diff --git a/src/trainOverlord/overlorditemstore.h b/src/trainOverlord/overlorditemstore.h new file mode 100644 index 0000000..92f3954 --- /dev/null +++ b/src/trainOverlord/overlorditemstore.h @@ -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 getTrainThatOwns(const NfcUid& uid); +}; diff --git a/src/trainOverlord/trainoverlord.cpp b/src/trainOverlord/trainoverlord.cpp new file mode 100644 index 0000000..5202293 --- /dev/null +++ b/src/trainOverlord/trainoverlord.cpp @@ -0,0 +1,166 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "microcontroller.h" +#include "nfcuid.h" +#include "overlorditemstore.h" +#include "train.h" +#include "turnout.h" +#include "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: "<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 "< - - AlarmSettingsDialog - - - - 0 - 0 - 423 - 281 - - - - Dialog - - - - - - Sound File: - - - - - - - 0 - - - 0 - - - - - false - - - - - - - Change - - - - - - - - - 0 - - - - - Sunrise - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - Enable - - - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - Qt::Horizontal - - - QDialogButtonBox::Cancel|QDialogButtonBox::Ok - - - - - - - - - buttonBox - accepted() - AlarmSettingsDialog - accept() - - - 248 - 254 - - - 157 - 274 - - - - - buttonBox - rejected() - AlarmSettingsDialog - reject() - - - 316 - 260 - - - 286 - 274 - - - - - diff --git a/src/ui/itemcreationdialog.cpp b/src/ui/itemcreationdialog.cpp deleted file mode 100644 index 55b26ca..0000000 --- a/src/ui/itemcreationdialog.cpp +++ /dev/null @@ -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); - } -} - diff --git a/src/ui/itemcreationdialog.h b/src/ui/itemcreationdialog.h deleted file mode 100644 index 57421ae..0000000 --- a/src/ui/itemcreationdialog.h +++ /dev/null @@ -1,33 +0,0 @@ -#ifndef ITEMCREATIONDIALOG_H -#define ITEMCREATIONDIALOG_H - -#include -#include -#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; - -private slots: - - void itemTypeChanged(const QString& type); - void itemNameChanged(const QString& name); - -private: - Ui::ItemCreationDialog *ui; -}; - -#endif // ITEMCREATIONDIALOG_H diff --git a/src/ui/itemcreationdialog.ui b/src/ui/itemcreationdialog.ui deleted file mode 100644 index 4b55d6d..0000000 --- a/src/ui/itemcreationdialog.ui +++ /dev/null @@ -1,116 +0,0 @@ - - - ItemCreationDialog - - - - 0 - 0 - 400 - 140 - - - - Create Item - - - - :/images/UVOSicon.bmp:/images/UVOSicon.bmp - - - - - - - - Type - - - - - - - - Message - - - - - System - - - - - - - - - - - - Name - - - - - - - Item - - - - - - - - - - - - Qt::Horizontal - - - QDialogButtonBox::Cancel|QDialogButtonBox::Ok - - - - - - - - - - - buttonBox - accepted() - ItemCreationDialog - accept() - - - 248 - 254 - - - 157 - 274 - - - - - buttonBox - rejected() - ItemCreationDialog - reject() - - - 316 - 260 - - - 286 - 274 - - - - - diff --git a/src/ui/itemscrollbox.cpp b/src/ui/itemscrollbox.cpp deleted file mode 100644 index a83b7e0..0000000 --- a/src/ui/itemscrollbox.cpp +++ /dev/null @@ -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) -{ - if(auto workItem = item.lock()) - { - widgets_.push_back(new ItemWidget(item, this)); - Train* train = dynamic_cast(workItem.get()); - Turnout* turnout = dynamic_cast(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); - } - } -} - - diff --git a/src/ui/itemsettingsdialog.cpp b/src/ui/itemsettingsdialog.cpp deleted file mode 100644 index 179ce19..0000000 --- a/src/ui/itemsettingsdialog.cpp +++ /dev/null @@ -1,176 +0,0 @@ - #include "itemsettingsdialog.h" -#include "ui_itemsettingsdialog.h" -#include - -ItemSettingsDialog::ItemSettingsDialog(std::shared_ptr 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 = std::dynamic_pointer_cast(item_)) - { - itemSpecificWidget_ = new RelayItemSettingsWidget(relay); - } - else if(std::shared_ptr msgItem = std::dynamic_pointer_cast(item_)) - { - itemSpecificWidget_ = new MessageItemSettingsWidget(msgItem); - } - else if(std::shared_ptr sysItem = std::dynamic_pointer_cast(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 = nullptr; - - if(ui->comboBox->currentText() == "Alarm") - { - std::shared_ptr alarm = std::shared_ptr(new AlarmTime); - actor = alarm; - dialog = new ActorSettingsDialog(alarm, this); - } - else if(ui->comboBox->currentText() == "Sensor") - { - std::shared_ptr sensorActor = std::shared_ptr(new SensorActor); - actor = sensorActor; - dialog = new ActorSettingsDialog(sensorActor, this); - } - else if(ui->comboBox->currentText() == "Timer" ) - { - std::shared_ptr timerActor = std::shared_ptr(new TimerActor); - actor = timerActor; - dialog = new ActorSettingsDialog(timerActor, this); - } - else if(ui->comboBox->currentText() == "Regulator") - { - std::shared_ptr regulator = std::shared_ptr(new Regulator); - actor = regulator; - dialog = new ActorSettingsDialog(regulator, this); - } - - else if(ui->comboBox->currentText() == "Polynomal") - { - std::shared_ptr polynomalActor = std::shared_ptr(new PolynomalActor); - actor = polynomalActor; - dialog = new ActorSettingsDialog(polynomalActor, this); - } - - else if(ui->comboBox->currentText() == "Multi Factor") - { - std::shared_ptr polynomalActor = std::shared_ptr(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 = item_->getActors()[ui->tableWidget->currentRow()]; - - std::shared_ptr alarmTime = std::dynamic_pointer_cast(actor); - std::shared_ptr regulator = std::dynamic_pointer_cast(actor); - std::shared_ptr sensorActor = std::dynamic_pointer_cast(actor); - std::shared_ptr timerActor = std::dynamic_pointer_cast(actor); - std::shared_ptr polynomalActor = std::dynamic_pointer_cast(actor); - std::shared_ptr factorActor = std::dynamic_pointer_cast(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"); - } - } -} diff --git a/src/ui/itemsettingsdialog.h b/src/ui/itemsettingsdialog.h deleted file mode 100644 index ca12f21..0000000 --- a/src/ui/itemsettingsdialog.h +++ /dev/null @@ -1,37 +0,0 @@ -#ifndef RELAYSETTINGSDIALOG_H -#define RELAYSETTINGSDIALOG_H - -#include -#include -#include -#include "../items/item.h" - -namespace Ui { -class ItemSettingsDialog; -} - -class ItemSettingsDialog : public QDialog -{ - Q_OBJECT - std::shared_ptr item_; - QWidget* itemSpecificWidget_ = nullptr; - -private: - void loadActorList(); - -public: - explicit ItemSettingsDialog(std::shared_ptr item, QWidget *parent = nullptr); - ~ItemSettingsDialog(); - -private slots: - - void removeActor(); - void addActor(); - void editActor(); - void changeOverride(); - -private: - Ui::ItemSettingsDialog *ui; -}; - -#endif // RELAYSETTINGSDIALOG_H diff --git a/src/ui/itemsettingsdialog.ui b/src/ui/itemsettingsdialog.ui deleted file mode 100644 index 871bb9f..0000000 --- a/src/ui/itemsettingsdialog.ui +++ /dev/null @@ -1,274 +0,0 @@ - - - ItemSettingsDialog - - - - 0 - 0 - 577 - 390 - - - - Item Settings - - - - :/images/UVOSicon.bmp:/images/UVOSicon.bmp - - - - - - QFormLayout::AllNonFixedFieldsGrow - - - 0 - - - 10 - - - - - Name: - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - - 5 - 0 - - - - Qt::LeftToRight - - - TextLabel - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - - - - - - Override - - - - - - - QFrame::StyledPanel - - - Qt::ScrollBarAsNeeded - - - Qt::ScrollBarAlwaysOff - - - false - - - QAbstractItemView::NoEditTriggers - - - false - - - false - - - false - - - QAbstractItemView::SelectRows - - - false - - - Qt::SolidLine - - - false - - - 0 - - - 3 - - - false - - - 32 - - - true - - - false - - - 32 - - - - - - - - - - 0 - - - 0 - - - - - Remove - - - - - - - Edit - - - - - - - - - - - - 0 - 0 - - - - Act on - - - - - - - - Sensor - - - - - Polynomal - - - - - Regulator - - - - - Alarm - - - - - Timer - - - - - Multi Factor - - - - - - - - - 0 - 0 - - - - Add - - - - - - - - - Qt::Horizontal - - - QDialogButtonBox::Ok - - - - - - - - - - - buttonBox - accepted() - ItemSettingsDialog - accept() - - - 248 - 254 - - - 157 - 274 - - - - - buttonBox - rejected() - ItemSettingsDialog - reject() - - - 316 - 260 - - - 286 - 274 - - - - - diff --git a/src/ui/itemwidget.cpp b/src/ui/itemwidget.cpp deleted file mode 100644 index af6426e..0000000 --- a/src/ui/itemwidget.cpp +++ /dev/null @@ -1,203 +0,0 @@ -#include "itemwidget.h" -#include "ui_itemwidget.h" - -#include -#include -#include -#include "../items/train.h" -#include "../items/turnout.h" - -ItemWidget::ItemWidget(std::weak_ptr 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(workingItem.get()); - Turnout* turnout = dynamic_cast(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(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(new QShortcut(up, this))); - connect(shortcuts_.back().get(), &QShortcut::activated, this, &ItemWidget::stepUp); - shortcuts_.push_back(std::unique_ptr(new QShortcut(down, this))); - connect(shortcuts_.back().get(), &QShortcut::activated, this, &ItemWidget::stepDown); - shortcuts_.push_back(std::unique_ptr(new QShortcut(rev, this))); - connect(shortcuts_.back().get(), &QShortcut::activated, this, &ItemWidget::reverse); -} - -std::weak_ptr ItemWidget::getItem() -{ - return item_; -} - -void ItemWidget::stateChanged(int state) -{ - qDebug()<<"widget got state "<slider->blockSignals(true); - ui->slider->setValue(state); - ui->slider->blockSignals(false); -} - -ItemWidget::~ItemWidget() -{ - delete ui; -} diff --git a/src/ui/itemwidget.h b/src/ui/itemwidget.h deleted file mode 100644 index c0eb45b..0000000 --- a/src/ui/itemwidget.h +++ /dev/null @@ -1,57 +0,0 @@ -#ifndef RELAYWIDGET_H -#define RELAYWIDGET_H - -#include -#include -#include -#include "itemsettingsdialog.h" -#include "../items/item.h" - -namespace Ui { -class ItemWidget; -} - -class ItemWidget : public QWidget -{ - Q_OBJECT -private: - std::weak_ptr item_; - - std::vector< std::unique_ptr > 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, QWidget *parent); - std::weak_ptr 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 diff --git a/src/ui/mainwindow.cpp b/src/ui/mainwindow.cpp deleted file mode 100644 index 93187a4..0000000 --- a/src/ui/mainwindow.cpp +++ /dev/null @@ -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); - } -} -*/ diff --git a/trainControllerUI.pro b/trainControllerUI.pro deleted file mode 100644 index 992cae3..0000000 --- a/trainControllerUI.pro +++ /dev/null @@ -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