Комплект для разработки электрических схем

Раздел посвящен обсуждению вопросов разработки DLL-модулей подвижного состава
andreykod
Сообщения: 50
Зарегистрирован: 17 фев 2020, 11:21
Город: Москва
Настоящее имя: Андрей

Комплект для разработки электрических схем

Сообщение andreykod » 09 мар 2020, 14:39

Объявляю о запуске бета теста моего комплекта разработки электрических схем!

И так,
У нас имеется 4 класса для облегчения работы со схемами и 3 программы.
Начнем с программ:
  • Официальный билд
  • Debugger
  • Viewer
Что очень удобно, мы рисуем схемы в любом официальном билде, на любой платформе. Нам нужен лишь файл проекта схемы для интеграции в симулятор.

Дебаггер нужен для отлова ошибок связанных именованием сегментов общей памяти, к тому-же дебаггер скомпилирован с закомментированной функцией, необходимой для работы алгоритма оптимизации, поэтому не следует включать в комплект вашего локомотива дебаггер.

Для работы схемы на стороне пользователя используется viewer, урезанный по гуи и редактированию схем дебаггер с алгоритмом оптимизации.

А теперь передем к программной реализации всего этого.
Как это работает? Очень просто, во viewere, вместе с созданием экземпляра класса, создается сегмент общей памяти с, внимание ID, нет не именем, а id.
Изображение
Его нельзя менять, но определяется при инициализации объекта, вытащив его с панельки или открыв файл готовой схемы, и тут есть загвоздка. Дело в том, что если мы схему изменили, а при открытии из файла объекты инициализируются хаотично, то все ID смещаются, поэтому есть ограничения и добавить элемент в схему, не проинформировав главную программу (наш локомотив) измененными именами, нельзя. Важно так-же переоткрыть схему над которой мы работаем, ибо при редактировании объекты инициализируются в порядке их вытаскивания. Еще одна проблема, это самопроизвольное открытие схемы из backup файла, каждые несколько минут программа сохраняет изменения в неком буферном backup файле, но даже если мы прямо укажем открыть конкретный файл, то программа полезет за бэкапом сначала. Это порождает очень нехороший, нельзя назвать это багом, но при повторном открытии сразу после сохранения данного файла программа инициализирует элементы с совсем другими id, сначала вообще кажется, что id присваиваются рандомно, но долго переоткрывать не придется. Закономерность прослеживается уже после повторного переоткрытия файла: все встает на свои места, id становятся как при первом открытии, сразу после запуска.

Какой вывод можно сделать? Viewer не читает бэкап, в локомотиве ID (они же Key для памяти) прописывайте те, что даются при первом открытии файла (запускаем оф. билд -> открываем наш файл -> смотрим ID -> запоминаем -> выходим без сохранения)

Так же во вьювере нет интерфейса, только схема. Запускает симуляцию автоматически и файл открывает тоже автоматически. Управлять им можно из ini, который лежит около него. В path прописываем полный путь до файла проекта (схемы) включая имя. Остальные переменные трогать не надо! Раасскажу о них потом.

Рассмотрим базовый класс для работы с памятью.
Как уже писал выше инициализация памяти происходит автоматически, на стороне симулятора схем. Соответственно, имя задается тоже там, по ID.
Описывать, что я делал во viewere не буду, расскажу только как с ним работать, но если кому-то нужно или интересно, то пишите, я выложу измененные исходники viewera.
Смотрим header базового класса:

Код: Выделить всё

#ifndef SHAREDMEMGETSET_H
#define SHAREDMEMGETSET_H
#include <QSharedMemory>

class SharedMemGetSet
{
public:
    SharedMemGetSet(QString memname);
    ~SharedMemGetSet();

    template <typename T>
    T getFromMem(){
        m_sharedmem.lock();
        T value = 0;
        T *from = (T*)m_sharedmem.data();
        value = *from;
        m_sharedmem.unlock();
        return value;
    }
    template <typename K>
    void setMem(K valtoset){
        m_sharedmem.lock();
        K *to = (K*)m_sharedmem.data();
        *to = valtoset;
        m_sharedmem.unlock();
    }
private:

    QSharedMemory m_sharedmem;

};

#endif // SHAREDMEMGETSET_H
Видим две шаблонные функции. Если со второй все понятно, то первая настораживает использованием доп. переменной, зачем? Все очень просто: Прежде чем мы должны совершать какие-либо операции, мы должны закрыть семафор, иначе ничего работать не будет, поэтому обратиться с разыменованием указателя можно только после семафора, поэтому я сделал return доп значения уже после открытия семафора. Ну и, если кто не понял, мы в шаблоне указываем тип данных.
Как работать?
( создаем экземпляр -> кидаем в конструктор стринг ключа (тот самый ID) -> работаем с памятью с помощью этих функций)

Рассмотрим два более сложных класса: пакетник и multiswitch:

Multiswitch лежит в основе, поэтому смотрим его хедер первым:

Код: Выделить всё

#ifndef MULTISWITCH_H
#define MULTISWITCH_H

#include <QObject>
#include "SharedMemGetSet.h"

class MultiSwitch : public QObject
{
    Q_OBJECT
public:
    MultiSwitch(const QList<QString>& arg, int rows, int cols, const bool* arr, QObject *parent);     //  конструктор для карты положений
    ~MultiSwitch();

    bool setPos(int pos);                                        //  единственная функция, меняет положение пакетника по аргументу
private:


    int m_rows;
    int m_cols;
    const bool* arr_ptr;
    const QList<QString>* m_ids;

};

#endif // MULTISWITCH_H
Начнем по порядку
Первый параметр конструктора принимает массив QList<QString> , в котором по порядку обозначаем ID переключателей.
Второй параметр принимает значения рядов (количество положений нашего переключателя) главной карты положений или просто двумерного массива.
Далее следует параметр колонок (количество контактов) главной карты положений или просто двумерного массива.
А теперь уже следует наша главная карта положений переключателя. Что она из себя представляет? Простой двумерный bool массив. Возможности не ограничены! Как это работает? Очень просто! В конструктор мы передаем указатель на нулевое значение! &arr[0][0] Далее единственной функцией кидаем по порядку из заданного ряда значения в общюю память каждого переключателя по циклу, попутно хватая значения ID из первого массива.
Для большего понимания картиника:
Изображение
Где id1, 2...4 ID выключателей на которые мы отошлем соответствующее ряду (положению) bool значение.
Еще нужно отметить, что лучше инициализировать массив как показано на рисунке, еще бы я объявил не bool а static inline const bool прямо в хедере класса в котором мы бы инициализировали этот, но inline требует включения C++17, что можно с легкостью сделать в qt. Передал бы указатель через &, а в параметры rows и cols, Xrows и Xcols соответственно. В механизме нет защиты от неверных параметров, в частности rows и cols, неверные значения которых будут приводить к падению программы! Но присутствуют механизмы защиты от неверного аргумента для функции изменения положения, да она сама bool и возвращает false, если аргумент меньше нуля или больше чем рядов в массиве. Здесь еще нужно сказать, что нумерация в массиве начинается с нуля, а в аргумент мы передаем на основе нумерации с одного. То есть программно первое положение преключателя это 0, а в аргумент мы передаем именно 1 как первое положение, а не ноль!
Методы:

Код: Выделить всё

#include "multiswitch.h"
#include "SharedMemGetSet.h"
#include <QList>



MultiSwitch::MultiSwitch(const QList<QString>& arg, int rows, int cols, const bool* arr, QObject *parent) :
    QObject(parent), m_rows(rows), m_cols(cols), arr_ptr(arr), m_ids(&arg)
{
}
bool MultiSwitch::setPos(int pos){
    if(pos <= 0 || pos > m_rows){ return false;}
    pos--;
    for(int i = 0; i < m_cols; i++){
    SharedMemGetSet mem((*m_ids)[i]);
    mem.setMem(*((arr_ptr+i)+(m_cols*pos)));

    }
    return true;
}
MultiSwitch::~MultiSwitch(){}
Использование данного класса оптимально только в модулях.

Для клавиатурной обработки есть спец класс:

Передем к "Пакетнику"
Смотрим хедер:

Код: Выделить всё

class Paketnik : private MultiSwitch
{
    Q_OBJECT
public:
    explicit Paketnik(const QList<QString>& arg, int xn, int xm, const bool* xA ,QObject *parent = nullptr);
    int getCurrPos() {return m_currpos;};
    void setPosition(int pos);
private:
    QTimer *tmr;
    bool m_allowed;
    int m_currpos;
public slots:
    void chngUP();
    void chngDW();
    void allow();
signals:

};

#endif // PAKETNIK_H
Можете сами посмотреть работу механизма, предотвращающего звонковую работу клавиш.
А сейчас я расскажу про слоты.

Код: Выделить всё

#include "paketnik.h"

Paketnik::Paketnik(const QList<QString>& arg, int xn, int xm, const bool* xA, QObject *parent) :
    MultiSwitch( arg,xn,xm, xA, parent)
  , m_allowed(true)
  , m_currpos(1)
{
    tmr = new QTimer();
    tmr->setInterval(500);
    connect(tmr, SIGNAL(timeout()), this, SLOT(Allow()));
}


void Paketnik::chngUP(){
    if(m_allowed){
    if(setPos(m_currpos + 1)){
       m_currpos++;
    }
    m_allowed = false;
    tmr->start();
    }
}
void Paketnik::chngDW(){
    if(m_allowed){
    if(setPos(m_currpos - 1)){
       m_currpos--;
    }
    m_allowed = false;
    tmr->start();
    }
}
void Paketnik::allow(){
      tmr->stop();
      m_allowed = true;

}
void Paketnik::setPosition(int pos){
    setPos(pos);
    m_currpos = pos;

}
Слот chngUP, при вызове переключает пакетник на одно положение вверх, слот chngDW, в прочем здесь и так понятно. Слоты снабжены защитой от переключения за пределы положений пакетника и защитой от звонковой работы.
Конструктор идентичен multiswitch.

Передем к самому сырому классу азв:
Данный класс симлирует работу азв. Симулирует довольно примитивно, но работает стабильно. Подробнее я уже его описывал в видео. В симуляторе схем он реализуется как амперметр и выключатель. В конструктор принимает несколоко параметров:
Либо два стринга либо массив из них, зависит от конструкора, но на первом месте всегда ID амперметра, а на втором ID переключателя.
Далее следует номинал в амперах.
Далее следует множитель, во сколько раз нужно превысить номинал для срабатывания быстрой защиты.
Далее следует время отключения когда номинал превышен незначительно. Сделано простой ступенькой, без функций.

Вот хедер:

Код: Выделить всё

#ifndef AZV_H
#define AZV_H

#include "SharedMemGetSet.h"
#include <QObject>
#include <QTimer>

class Azv : public QObject
{
    Q_OBJECT
public:
    Azv(QString idAmper, QString idSwitch, int nomcurr, int fastoffmultiplier,  int timetooff,  QObject *parent = 0);
    Azv(const QList<QString>& arg, int nomcurr, int fastoffmultiplier, int timetooff, QObject *parent = 0);



    bool getState(){ return sw.getFromMem<bool>();};
    double getCurr(){ return amper.getFromMem<double>();};
    void check();
public slots:
    void setON();
    void setOFF();
    void changeVal();

protected:
    SharedMemGetSet amper;
    SharedMemGetSet sw;
    QTimer *tmr;
    int m_fastoffmult;

    int m_expmult;
    int m_nomcurr;

    bool m_tmrstarted;

};

#endif // AZV_H
Имеет слоты для отключения, включения и смены положения. Есть функции возврящающие значения амперметра и выключателя.


Вот и все!
Это своеобразная бета комплекта. Багов будет немеренно! Выкладываю, потому как нету времени самому тестить очень много.
Конечно-же приветствуется критика, особенно если еще и с советами!

--------------------------- Перезалив!---------------------------

https://drive.google.com/file/d/1mzpM0H ... sp=sharing 7z
--------------------------- Теперь исходник доступен на github!---------------------------
https://github.com/asafran/simulide-rrs-viewer
В архиве 5 папок
viewer
debugger
оф билд
и програмка, ужасно кривая, основанная на официальном примере sharedmem
elements - папка с хедерами и методами

Пойду покушаю и потом еще пример применения этого всего опишу!
Последний раз редактировалось andreykod 18 апр 2020, 14:10, всего редактировалось 9 раз.

Аватара пользователя
PeRLouD
Сообщения: 60
Зарегистрирован: 06 фев 2020, 20:13
Город: Минск
Настоящее имя: Тимур
Контактная информация:

Re: Комплект для разработки электрических схем

Сообщение PeRLouD » 09 мар 2020, 17:07

Есть вопрос: что дают эти схемы? Возможно ли будет генерировать неисправности как в zdsim, которые будут отражаться на работе локомотива?

andreykod
Сообщения: 50
Зарегистрирован: 17 фев 2020, 11:21
Город: Москва
Настоящее имя: Андрей

Re: Комплект для разработки электрических схем

Сообщение andreykod » 09 мар 2020, 19:41

PeRLouD писал(а):
09 мар 2020, 17:07
Есть вопрос: что дают эти схемы? Возможно ли будет генерировать неисправности как в zdsim, которые будут отражаться на работе локомотива?
Конечно возможно! Все ограничивается только возможностями c++! Я планирую реализовать и это.
Последний раз редактировалось andreykod 15 мар 2020, 15:18, всего редактировалось 1 раз.

andreykod
Сообщения: 50
Зарегистрирован: 17 фев 2020, 11:21
Город: Москва
Настоящее имя: Андрей

Re: Комплект для разработки электрических схем

Сообщение andreykod » 10 мар 2020, 21:08

Простите, баг исправил, но я уже тестирую обновление для вьювера. Все уже готово, но не протестил, боюсь положу что не то в комплект, утро вечера мудренее. Завтра выложу бетку!

andreykod
Сообщения: 50
Зарегистрирован: 17 фев 2020, 11:21
Город: Москва
Настоящее имя: Андрей

Re: Комплект для разработки электрических схем

Сообщение andreykod » 11 мар 2020, 19:56

Обновление! В этой версии реализовал все, что хотел: возможность зафорсить положение переключателя, даже если память пытается сделать обратное, отключил возможность всячески изменять схему, удалять линии, двигать компоненты, можно только рисовать. Можно это все отключить, я добавил в ini еще два параметра: buttonallowed и delallowed, первый включает единицей возможность зафиксировать положение любого выключателя, а нулем - выключает, то же самое и со вторым, только речь идет о возможности удалять соединения. Здесь еще не описал параметр upd и rate, второй не трогаем, а первый изменяет частоту опроса схемы (больше -> медленнее, меньше нагрузка), лучше не менять, так как уже говорил про механизм оптимизации, когда если не происходит ничего в схеме, то она не пересчитывается, и нагрузка минимальная.

Аватара пользователя
maisvendoo
Модератор
Сообщения: 339
Зарегистрирован: 13 авг 2019, 10:25
Город: Ростов-на-Дону
Настоящее имя: Дмитрий
VK: https://vk.com/maisvendoo
Контактная информация:

Re: Комплект для разработки электрических схем

Сообщение maisvendoo » 13 мар 2020, 08:22

Отлично, я посмотрю всё это, но предупреждаю - не быстро. Занят сейчас более общими вопросами по проекту, но обязательно все изучу и отпишусь тут с замечаниями и соображениями
Возврата к деспотии Ситхов не будет!

andreykod
Сообщения: 50
Зарегистрирован: 17 фев 2020, 11:21
Город: Москва
Настоящее имя: Андрей

Re: Комплект для разработки электрических схем

Сообщение andreykod » 13 мар 2020, 20:11

maisvendoo писал(а):
13 мар 2020, 08:22
Отлично, я посмотрю всё это, но предупреждаю - не быстро. Занят сейчас более общими вопросами по проекту, но обязательно все изучу и отпишусь тут с замечаниями и соображениями
Большое спасибо за обратную связь, но эта сборка только лишь бета, с момента последнего обновления уже исправлено десятки глупейших ошибок и больших багов. По части вьювера полностью завершена работа, осталось допиливать и оптимизировать код на стороне dll. Я не в коем случае не отговариваю Вас, но мы все понимаем, что в симуляторе еще много чего нужно сделать, причем в приоритете, например сигнализацию и редактор карт. К чему я клоню? К тому, что если у Вас не очень много времени, ни в коем случае не прошу сразу все забыть и перейти к моему комплекту, наоборот, в процессе создания находится этакий мегагайд, в котором я изложу все быстро и понятно. Немного неудобно писать это, но все же очень не хочется, что бы моя, пока что бета, тормозила основную ветвь симулятора, но в любом случае спасибо за обратную связь!

А для кого-же тогда сборка? Наверное, найдутся среди нас те, кто хочет покапаться во всем этом. Мне нужна именно живая бета, я даже не замечаю как делаю некоторые нюансы, вроде заранее заполненных конфигов, не ставлю запредельных параметров, мне интересно, какой именно информации не хватает и где повысить, как это говорится, юзерфрендли, даже просто отлов багов и крашей.

Ну а гайд в процессе создания.

Аватара пользователя
maisvendoo
Модератор
Сообщения: 339
Зарегистрирован: 13 авг 2019, 10:25
Город: Ростов-на-Дону
Настоящее имя: Дмитрий
VK: https://vk.com/maisvendoo
Контактная информация:

Re: Комплект для разработки электрических схем

Сообщение maisvendoo » 13 мар 2020, 20:25

Гайд это хорошо. Качественная документация всегда нужна, жаль на неё тоже бывает мало времени. Я вот пока дальше гайда для самых новичков не ушел
Возврата к деспотии Ситхов не будет!

andreykod
Сообщения: 50
Зарегистрирован: 17 фев 2020, 11:21
Город: Москва
Настоящее имя: Андрей

Re: Комплект для разработки электрических схем

Сообщение andreykod » 14 мар 2020, 16:18

Багфикс:
Переделан вьювер, по причине неработающей инициализации переключателей, приводящей к невозможности управления ими из общей памяти, добавлен класс PS, симулирующий пневмодвигатель переменных чехов.
Ссылки обновлены!

andreykod
Сообщения: 50
Зарегистрирован: 17 фев 2020, 11:21
Город: Москва
Настоящее имя: Андрей

Re: Комплект для разработки электрических схем

Сообщение andreykod » 16 мар 2020, 10:19

Багфикс:
Добавлен флаг в общей памяти, по которому можно точно определить загрузилась схема или еще нельзя кидать в общую память значения. Если кто не понял, то сегменты памяти создаются на стороне симулятора схем, а ррс запускается быстрее него, поэтому если инициализировать выключатели их дефолтным состоянием в конструкторе локомотива, то значения просто игнорируются, как записать что-то в память, если нет ее сегмента? Поэтому я добавил флаг, вернее bool переменную в общей памяти, которая возвращает true, только когда все элементы схемы, а вместе с ними и сегменты общей памяти инициализируются! Ее ID "check"

Ответить

Вернуться в «Программирование модулей подвижного состава и оборудования (C++ API)»