организация программы для протокола

switch
Offline
Зарегистрирован: 07.12.2015

Добрый день! Нужен совет опытных программистов на С++ под ардуино. В общем ситуация такая:

Есть основной контроллер на esp8266, к нему через программный UART подключено некоторое количество ATMEGA168. Соединены цепочкой. Т.е.  esp8266 -> ATMEGA168 -> ATMEGA168 -> ATMEGA168 -> обратно в esp8266 . Адресация относительная. Т.е. центральный передает на адрес 0x02, девайсы в цепочке последовательно отнимают от поля адрес единицу и так доходит до конца. Так сделал чтоб можно было просто расширять возможности девайса дополнительными блоками. Хотел общую шину, но не придумал как сделать арбитраж передачи.

Ладно, суть в том что периферийных девайсов на ATMEGA168 может быть много, и они могут быть разными. Какой-то просто GPIO, какой-то отвечает за 1wire сеть, другой - дисплей и тп. У каждого устройства есть свой тип и набор функций. примерно так:

Формат пакета данных
0  1  2  3 4 5 6  8 9  10
AA BB СС DDDDDDDD EEEE ZZ
 
AA - адрес получателя. Для центрального процессора всегда FF
BB - тип устройства. Для центрального процессора всегда 0
CC - код функции
DD - Параметры для функции произвольной длинны. Количество данных определяется кодом функции
EE - номер транзакции для подтверждения передачи
ZZ - контрольная сумма за исключением адреса устройства
 
данные могут быть произвольного размера, приемник понимает это по номеру функции. В базовом варианте передаются четыре байта, но в иных случаях может и килобайт засылаться.
 
Собственно весь вопрос в грамотной организации со стороны контроллера этого всего дела. Я хочу чтобы заданные события на портах периферии отрабатывались ей самой и на центр передавалось только само событие. Чтоб не задрачивать центр опросом портов и не тратить на это время. Тем более UART и так асинхронный. 
 
Вопрос как это все красиво организовать. Мне представляется класс, который при инициализации получает указатель на поток UART, далее мы можем передать в порт команду перечисления устройств. Каждое вернет нам тип и свой порядковый номер на шине. И вот тут самое интересное: устройства могут быть разных типов. Разные структуры описывают их состояния, у них есть разные методы управления. 
Что-то я заплутал в этом всем. Наверно слишком путано объясняю.
andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

Неудачное решение.

switch пишет:

Соединены цепочкой. Т.е.  esp8266 -> ATMEGA168 -> ATMEGA168 -> ATMEGA168 -> обратно в esp8266 ... Так сделал чтоб можно было просто расширять возможности девайса дополнительными блоками.

...У каждого устройства есть свой тип и набор функций. примерно так:

...
данные могут быть произвольного размера, приемник понимает это по номеру функции.

Надеюсь, Вы понимаете, что ВСЕ команды должны быть заранее известны ВСЕМ устройствам. Т.е. просто придумать новое устройство и вставить его в уже существующую цепочку окажется невозможным.

wdrakula
wdrakula аватар
Онлайн
Зарегистрирован: 15.03.2016

Каждый первый, даже не каждый второй, программист, столкнувшись с миром микроконтроллеров, начинает писать "Общую систему всего". ;))) Это не плохо, это как детская болезнь, типа ветрянки, лучше переболеть раньше, избежать все-равно не выйдет.

Никто никогда не дописывает до конца, потому, что никому не надо, но в процессе создания часто рождается много хорошего кода, в основном - велосипеды, но, как бы сказать? - Вот: "Крафтовые"! ;))))))))

--------------

Пока в заголовок длину пакета добавь, тогда ретранслирующим устройствам не нужно будет парсить структуру дальше заголовка.

asam
asam аватар
Offline
Зарегистрирован: 12.12.2018

Ну, если хочется "кольцо", то все придумано до нас - https://ru.wikipedia.org/wiki/Token_ring

Но вылет одной ноды валит всю сеть напрочь. Так что лучше подумать в сторону шинной топологии.

UPD A чем I2C (aka TWI) не устраивает?

switch
Offline
Зарегистрирован: 07.12.2015

> Ну, если хочется "кольцо", то все придумано до нас - https://ru.wikipedia.org/wiki/Token_ring

> Но вылет одной ноды валит всю сеть напрочь. Так что лучше подумать в сторону шинной топологии.

> UPD A чем I2C (aka TWI) не устраивает?

i2C на меге занимает ADC, а мне их 8 штук надо. Вообще мегу ставлю только потому что в одном корпусе 8ADC и около 14 GPIO, чего для задачи в самый раз. И это получается дешевле чем i2C микросхемы ставить. Плюс разгружу центральный контроллер от опроса ног, хотя в этом особого смысла нет. Больше потребность в расширении портов. Токен Ринг тут мне не нужен, т.к. периферия между собой не обменивается данными никак.

 

как тут цитировать-то?

switch
Offline
Зарегистрирован: 07.12.2015

> Надеюсь, Вы понимаете, что ВСЕ команды должны быть заранее известны ВСЕМ устройствам. Т.е. просто придумать новое устройство и вставить его в уже существующую цепочку окажется невозможным.

безусловно понимаю. Пока у меня один тип устройства, на примете еще пара. Добавление нового типа устройств должно сопровождаться обновлением ПО. Но устройства не вникают в содержимое пакета если он не предназначен для него непосредственно. Разбирает заголовок и пересылает дальше

>Каждый первый, даже не каждый второй, программист, столкнувшись с миром микроконтроллеров, начинает писать "Общую систему всего". ;))) Это не плохо, это как детская болезнь, типа ветрянки, лучше переболеть раньше, избежать все-равно не выйдет.

> Никто никогда не дописывает до конца, потому, что никому не надо, но в процессе создания часто рождается много хорошего кода, в основном - велосипеды, но, как бы сказать?

я не новичок в программировании ;)  Интересно что всегда я придерживался больше строительства костылей, чем велосипедов (их я готовые использовал), ибо считал "пока вы там на жаве свой шедевр точите, мы запилили на пхп из говна и палок и деньги зарабатываем". Просто конкретно в этом случае я хочу углубиться в C++ и сделать по-человечески. Не потому что так надо, а потому что так хочу (я художник, я так вижу ;))))

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

switch пишет:

безусловно понимаю. Пока у меня один тип устройства, на примете еще пара. Добавление нового типа устройств должно сопровождаться обновлением ПО.

Причем, ПО нужно будет обновлять для ВСЕХ входящих в цепочку устройств, а не только для головного.

Цитата:

Но устройства не вникают в содержимое пакета если он не предназначен для него непосредственно. Разбирает заголовок и пересылает дальше

Чтобы переслать дальше, нужно знать длину пакета, а в явном виде она в заголовке не содержится.

wdrakula Вам верно посоветовал: включите длину пакета в заголовок.

switch
Offline
Зарегистрирован: 07.12.2015

суть вопроса  не в протоколе, не в длинах пакета, не в алгоритме передачи, это все детали. Суть вопроса в организации программы для работы с этими сущностями. 

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

В процедурном программировании просто делаем кучку IF и обрабатываем все по-своему. С классами как это правильно организовать?

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

А в классе создаем метод обработать и указатель(*void) где полученый пакет лежит.

switch
Offline
Зарегистрирован: 07.12.2015

это понятно. Ладно, думаю сложно так вот объяснить...

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

Освежите в памяти операцию приведение типов. похоже вы о существовании ее даже не догадываетесь.

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

switch пишет:

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

Зачем? Если по условию задачи после каждого изменения цепочки подразумевается перекомпиляция прошивки.

Цитата:

Дальше в коде должно как-то появиться несколько классов с методами, определенными для этого типа устройств. Это массив классов? Как это делается?

Ну, вообще-то, можно массив указателей.

Цитата:

В процедурном программировании просто делаем кучку IF и обрабатываем все по-своему. С классами как это правильно организовать?

Никто не мешает сделать здесь точно так же. 

IMHO wdrakula с самого начала поставил верный диагноз: Вы пытаетесь придумать сверхуниверсальное решение там, где по другим признакам даже малой степенью универсальности и не пахнет. По крайней мере, структура заголовка пакета полностью исключает всякую универсальность.

Начните с малого - с того, что можете самостоятельно сделать прямо сейчас. А потом уже думайте, что нужно, для того, чтобы это обобщить и универсализировать.

Опять же, протокол - более консервативная вещь, чем прошивка. Вот с универсального протокола и начните. А универсальностью прошивки будете заниматься потом. Если в этом возникнет необходимость.

switch
Offline
Зарегистрирован: 07.12.2015
 
qwone пишет:
Освежите в памяти операцию приведение типов. похоже вы о существовании ее даже не догадываетесь.
вы даже не догадываетесь о чем я могу догадываться. Давайте оставим менторский тон и прибавим уважения?
andriano пишет:
Зачем? Если по условию задачи после каждого изменения цепочки подразумевается перекомпиляция прошивки.
Нет, не подразумевается перекомпиляция. Если добавляется периферия, она определяется и добавляется в интерфейс настроек, портами можно пользоваться.
andriano пишет:
Ну, вообще-то, можно массив указателей.
Это дельный совет. Когда устройство определено, для него создавать экземпляр класса с методами управления, а указатель на экземпляр хранить в массиве для перечисления в случае групповой обработки
andriano пишет:
Никто не мешает сделать здесь точно так же.IMHO wdrakula с самого начала поставил верный диагноз: Вы пытаетесь придумать сверхуниверсальное решение там, где по другим признакам даже малой степенью универсальности и не пахнет. По крайней мере, структура заголовка пакета полностью исключает всякую универсальность.Начните с малого - с того, что можете самостоятельно сделать прямо сейчас. А потом уже думайте, что нужно, для того, чтобы это обобщить и универсализировать.Опять же, протокол - более консервативная вещь, чем прошивка. Вот с универсального протокола и начните. А универсальностью прошивки будете заниматься потом. Если в этом возникнет необходимость.
 
не, я не хочу универсальное делать. Просто нужно оставить задел на будущее, чтобы не много переделывать и чтоб код существующий был изящнее. Хочу изолировать обработку периферии от основного кода и работать с интерфейсами. Я на ардуине уже делал проекты на 10 тыщ строк, но по большей части это привычное мне процедурное программирование со всеми вытекающими. В протоколе ничего сложного нет, я его уже реализовал, но хочу человеческую имплементацию. Потому и спрашиваю совета. Возможно спрашиваю совета слишком рано ;)
 

 

Logik
Offline
Зарегистрирован: 05.08.2014

switch пишет:

я не новичок в программировании ;)  Интересно что всегда я придерживался больше строительства костылей, чем велосипедов (их я готовые использовал), ибо считал "пока вы там на жаве свой шедевр точите, мы запилили на пхп из говна и палок и деньги зарабатываем". Просто конкретно в этом случае я хочу углубиться в C++ и сделать по-человечески. Не потому что так надо, а потому что так хочу (я художник, я так вижу ;))))

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

По существу. Тебе тут правильно писали идея отстой полностю. От выбора контроллеров и уарта и до кольца и протокола. Но с последним проще всего, по крайней мере обозначеная проблема - отсутствие явной длинны переменной части тех самых DDDDD легко решаема, пусть будет LL. Еще полезно добавить контрольную сумму отдельно для заглавия. Почему так? Потому что ошибки в нем имеют большие необратимые последствия. Например прием команд с ошибкой в СС (или в LL) приведет к ожиданию неверной длинны сообщения (кол-ва DDDD) и рассинхронизации всей сети. Потому уж лучше так AA BB СС LL zz DDDDDDDD EEEE ZZ, где zz, ZZ - контрольные суммы заглавя и данных соответственно. Хотя остается вопрос, а что делать если на заданом AA нет указаного BB? Или думаете на одной ATMEGA168 много ВВ влезет? Ща! Дай бог чтоб сам протокол уместился нормально.  Кстати чего хоть не ATMEGA328? Вобщем ВВ убрать, если вдруг потребуется - передаватьв составе DD. И архитектурно оно верней. Важный вопрос - размер места под DDDD зарезервированого в контроллере. Поясняю, вебдизайнеру сложно сразу вехать.  В сети экран и датчик температуры. Для экрана нужно много DDDDDD например 1КБ для оледки например или 240*320*2 байт для покрупней (оно конечно можна и по частям, но скорость сразу сильно падает), а для датчика достаточно и 1-2 байт. Протокол должен эту проблему позволять решать без обявления больших буферов тем устройствам, которым оно не нужно. Вобще тут писать можна много, но пусть сразу хоть это услышано будет.

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

switch пишет:
не, я не хочу универсальное делать. Просто нужно оставить задел на будущее, чтобы не много переделывать и чтоб код существующий был изящнее. Хочу изолировать обработку периферии от основного кода и работать с интерфейсами. Я на ардуине уже делал проекты на 10 тыщ строк, но по большей части это привычное мне процедурное программирование со всеми вытекающими. В протоколе ничего сложного нет, я его уже реализовал, но хочу человеческую имплементацию. Потому и спрашиваю совета. Возможно спрашиваю совета слишком рано ;)

Альтернативой процедурного программирования  есть объектное оринтированое программирование. Но как нет единого стандарта понимать что такое процедурное программирование. Что "правильное " процедурное програмирование а что "неверное" или еретическое. Вот так и с ООП. есть куча сектантов и адептов правильного и единственно верного ООП.   Но вернемся к ООП и классам.  1- класс это не объект. И объект не класс.  Класс это комплект чертежей по которым можно собрать объект . Можно один , можно много , а можно и не собирать, если в конкретной программе этого не надо. Вот этим и занимается компилятор.  Вроде это заезженая мысль. Но почему-то у народа не находит понимания. Тут вроде понимает, а как только начинает использовать , не может. 

Теперь ближе к теме. Пакет это что? Объект.  Да у него есть общая схема (класс), здесь пишем адрес куда, здесь размер, здесь вес, здесь отметка о целостости и так далее. А так же в классе описаны методы как вскрывать, как пеносить как передавать и прочее. 

  Что бы передать пакет надо его отнести на почту . И почта его передает . Почта это что ? Вы удивитесь . Это тоже объект. И что для объекта почты объект посылка - это просто некий объем,вес,размер который надо передать  без ущерба другому пункту почты. 

 И все.

switch
Offline
Зарегистрирован: 07.12.2015

Logik пишет:

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

вам тоже всего хорошего!

switch
Offline
Зарегистрирован: 07.12.2015

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

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

Допустим Вася решил отправить Пете  сапоги.  Конечно у Васи есть не только сапоги, а Петя получает не только сапоги. Понятно что все это байты и желательно создать пользовательский тип - предметы. А то Петя получив сапоги начнет готовить из них борщ.  То есть программист должен создать структуру данных сапоги. И присвоть им пользовательский тип 0х01. А для структуры свекла тип 0х02.  И теперь Вася должен переслать Пете не только данные но и их тип, что бы Вася их одел на ноги, а не варил борщ.

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

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

sadman41
Offline
Зарегистрирован: 19.10.2016

Вот, что бывает, если отведать сапогов вместо борща...

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

sadman41 пишет:

Вот, что бывает, если отведать сапогов вместо борща...

Так никто не предлагает есть сапоги. Исключительно: изрубить сапоги в капусту, добавить свеклы и варить борщ.

sadman41
Offline
Зарегистрирован: 19.10.2016

Борщ впоследствии отправить в Тобольск дедушке Ангелины пока его не забрали в армию джедаем третьего ударного полка.

switch
Offline
Зарегистрирован: 07.12.2015

Про борщ хорошо конечно, но радиус кривизны рук пока не позволяет до сопог добраться ;)

Ошибка на строке 78

exit status 1
expected initializer before 'device'
 

#include <SoftwareSerial.h>

#include <Ticker.h>
//include <extension.ino>

#define STX 13  //scl
#define SRX 12 //D6
//rxPin, txPin, inverse_logic, buffer size

SoftwareSerial serialPort(SRX, STX, false, 128);
Ticker Send;


  // на разных процессорах длина данных разная. Тут под АРМ, под АВР будет другая
    struct Packet {
      uint16_t Start = 0xAABB;//  Стартовая последовательность
      byte Addr = 0xFF;//  Адрес устройства
      byte Type = 0x01;  //  тип устройства
      byte Func = 0x02;  //  функция
      byte Port = 0x03;  //  порт
      byte Trig = 0x04;  //  триггер
      unsigned int Value = 0x00000005;  //  значение
      unsigned int Trans = 0x00000006;  //  номер транзцакции
      byte CRC = 0x07;  //  контрольная сумма
    };

    //тип указатель на функцию c аргументом в виде пакета
    typedef void (*PHandler)(Packet param);

//место для хранения данных
Packet pack;

class cExtension
{
  private:
    //указатель на последовательный порт
    Stream *serialPort;
    PHandler handler;
  
  public:
    //конструктор класса, передаем указатель на последовательный порт
    cExtension(Stream *_s): serialPort(_s){}

    //зададим функцию приема сообщения
    void setup(PHandler h, Packet p)
    {
      if(!h)
        return;
      h(p);
    }
    //тут отрабатываем прием сообщений и вызов callback процедуры
    void loop1()
    { 
      Packet pack;
      byte* ptr28 = (byte* )&pack;
    
      if (serialPort->available()) 
      {     
          // If anything comes in Serial
          Packet* packPtr = &pack;
          serialPort->readBytes((char*)packPtr, sizeof(Packet)) == sizeof(Packet);
          PHandler(pack);
      }
    }    
    //Отправка пакета
    void send()
    {
      static unsigned int counter=0;
      counter++;
      Packet pack;
      pack.Trans=counter;
      Serial.println("Send... ");
      Packet* packPtr = &pack;
      serialPort->write((const char*)packPtr, sizeof(Packet));
    }
}

cExtension device(serialPort);

void setup() {

  Serial.begin(115200);
  extension.begin(115200);    //Initialize software serial with baudrate of 115200
  device.setup(RecievePacket,pack);

  //назначим отправку пакетов каждые 100 мсек
  Send.attach_ms(100, SendPacket);
}

void SendPacket()
{
  device.send();
}

void RecievePacket(Packet pack)
{
    Serial.print("Start: ");
    Serial.println(pack.Start, HEX);
    Serial.print("Addr: ");
    Serial.println(pack.Addr, HEX);
    Serial.print("Type: ");
    Serial.println(pack.Type, HEX);
    Serial.print("Func: ");
    Serial.println(pack.Func, HEX);
    Serial.print("Port: ");
    Serial.println(pack.Port, HEX);
    Serial.print("Trig: ");
    Serial.println(pack.Trig, HEX);
    Serial.print("Value: ");
    Serial.println(pack.Value, HEX);
    Serial.print("Trans: ");
    Serial.println(pack.Trans, DEC);
    Serial.print("CRC: ");
    Serial.println(pack.CRC, HEX);   
}

void loop() 
{
  device.loop1();
}

Что не так делаю?

Единственное что в голову приходит это у параметра неверный тип, от чего конструктор не может инициализировать объект, а значит нет определения для этого объекта. Но пробовал конструктор без параметров сделать - тоже самое.

sadman41
Offline
Зарегистрирован: 19.10.2016

Может объявление класса вынести в .h ? Это же Wiring, в нем много чудес.

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

Понятно что "Города" находятся на разных МК. Но скорее всего надо начинать со строительства почты.

/**/
enum class enumCity : byte {
  MOSCOW = 1,
  PETERSBURG,
  VLADIVOSTOK
};
class Cl_Post {
  protected:
    enumCity city;
  public:
    Cl_Post (enumCity c): city(c) {};
    void init() {}
    void run() {}
};
//----------------------------------
Cl_Post Moscow(enumCity::MOSCOW);

//----------------------------------------
void setup() {
  Moscow.init();

}

void loop() {
  Moscow.run();
}

 

switch
Offline
Зарегистрирован: 07.12.2015

sadman41 пишет:

Может объявление класса вынести в .h ? Это же Wiring, в нем много чудес.

не думаю что поможет. Ведь объявление непосредственно в коде происходит. Но попробую...

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

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

/**/
//----------------------------------
enum class enumCity : byte {/*перечень городов*/
  MOSCOW = 1,
  PETERSBURG,
  VLADIVOSTOK
};
enum class enumMan : byte {/*перечень людей*/
  VASYA = 1,
  PETER,
  MISHA
};
template <typename T> struct parcel { /*структура посылки*/
  T data;
  unsigned int size;
  unsigned long time;
  enumCity fromCity;
  enumMan  fromMan;
  enumCity toCity;
  enumMan  toMan;
};
class Cl_Post {/*класс почта города*/
  protected:
    enumCity city;
  public:
    Cl_Post (enumCity c): city(c) {};
    void init() {}
    void run() {}
};
class Cl_Man {/*класс человек города*/
  protected:
    enumMan name;
  public:
    Cl_Man(enumMan n): name(n) {};
    void init() {}
    void run() {}
};
//----------------------------------
Cl_Post Moscow(enumCity::MOSCOW);
Cl_Man Vasya(enumMan::VASYA);
//----------------------------------------
void setup() {
  Moscow.init();
  Vasya.init();
}
void loop() {
  Moscow.run();
  Vasya.init();
}
/**/

 

switch
Offline
Зарегистрирован: 07.12.2015

Населять города человечками на ардуино это конечно хорошо. Прям Sim City. Только вот ошибка была тривиальна: описание класса должно заканчиваться точкой с запятой. Но от компилятора сообщение непонятное (для меня-то). Теперь прошу помощи с конструктором. Ругается так:

cannot declare parameter '_s' to be of abstract type 'Stream'

на строчку 042 из моего листинга выше. Я не могу понять где накосячил. Уж очень много неочевидных тонкостей в С++

nik182
Offline
Зарегистрирован: 04.05.2015
switch
Offline
Зарегистрирован: 07.12.2015

Хорошая статья, правда после нее идет статья "почему стоит писать на С++". Я придерживаюсь принципа KISS. Пару лет назад запилил некую платформу для приложений, Что-то типа фреймворка. Без единого объекта. Сидели потом с программерами думали, может стоит переделать на ООП. Получалось вдвое больше кода...  А если сравнить с предыдущим фреймворком где одни объекты...

nik182
Offline
Зарегистрирован: 04.05.2015

Наверно это моя профессиональная деформация. Мне приходится бороться за скорость выполнения кода микроконтроллером. Там ООП никогда не давал приимуществ, а как раз наоборот. Это потом на большом компе  ООП применияю для обработки и визуализации данных. 

wdrakula
wdrakula аватар
Онлайн
Зарегистрирован: 15.03.2016

switch пишет:

Но от компилятора сообщение непонятное (для меня-то). Теперь прошу помощи с конструктором. Ругается так:

cannot declare parameter '_s' to be of abstract type 'Stream'

на строчку 042 из моего листинга выше. Я не могу понять где накосячил. Уж очень много неочевидных тонкостей в С++


Я, конечно, дико извиняюсь, но что именно непонятно в сообщении? Требуется помощь с переводом? Написано, что нельзя создавать экземпляр абстрактного класса. И таки правда нельзя!

switch
Offline
Зарегистрирован: 07.12.2015

Спасибо, капитан очевидность ;)

Было бы неплохо объяснить что не так. 

wdrakula
wdrakula аватар
Онлайн
Зарегистрирован: 15.03.2016

switch пишет:

Спасибо, капитан очевидность ;)

Было бы неплохо объяснить что не так. 

В Вики даже есть статья "абстрактный класс". Ты принципиально не ищешь информацию сам, предпочитая ответы неизвестных людей с форума?

Прочти и всё поймешь. Потом, для проверки понимания, посмотри, как в ядре определен класс Stream.

================

ЗЫ:Прости стариковское ворчание, но я не думаю, что ты уж прям так на много моложе меня. Как, при наличии Инета можно разучиться учиться? Ведь ради нового учебника я, в 80-е годы, пробегал все известные букинисты, сидел в библиотеках, а теперь - два нажатия кнопки и у тебя на экране ответ НА ЛЮБОЙ ВОПРОС, только научиться фильтровать чушь от правды!

ЗЗЫ:Первый мой экземпляр КиР был отпечатан на огромном барабанном АЦПУ с СМ-4, в 84 году.

switch
Offline
Зарегистрирован: 07.12.2015

wdrakula, я тоже на форумах присутствую, только у меня другие компетенции, так же новичкам объясняю. Это круговорот информации и помощи в природе, так сказать. Обычно я ищу информацию по ошибке, вычитываю все что мне покажется подходящим. В любом случае я как-то разобрался. Сменил Stream на SoftwareSerial, я знал что он и HardwareSerial наследники от Stream. Просто хотел чтоб была независимость от типа подключения. Объяснения прошу от опытных людей, потому что в обилии литературы можно заблудиться. Хоть знать что читать. Стандарт C++ он же больше 700 стр, это только стандарт. К сожалению (или к счастью) это не мой основной язык, на котором программирую.

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

смени лучше Stream на Print, он памойму не абстрактный. 

wdrakula
wdrakula аватар
Онлайн
Зарегистрирован: 15.03.2016

Срач на тему "программисты против веб-говнокодеров" уже всем поднадоел, но все же:

Если художника, любого ульра-пост-... современного, попросить нарисовать лошадку, или мастрера супер-трэш-металла попросить сыграть "к Элизе" или токкату Ре-минор, или математика тополога попросить решить квадратное уравнение - НИКТО из них не скажет, что у него "другие компетенции".

Вот так и С/С++ - это как обязательное сольфеджио для музыканта, или основы мат анализа для математика. То, что не может быть "вне компетенции". Как-то так ;))))))))))))))).

wdrakula
wdrakula аватар
Онлайн
Зарегистрирован: 15.03.2016

DetSimen пишет:

смени лучше Stream на Print, он памойму не абстрактный. 

...ну, ...какбэ   ...вот:

virtual size_t write(uint8_t) = 0;

На этой-самой "врайте" весь класс построен. Сорри.

sadman41
Offline
Зарегистрирован: 19.10.2016

wdrakula пишет:

Если художника, любого ульра-пост-... современного, попросить нарисовать лошадку, 

Живо представил себе результат: уши вместо хвоста, цвет - оранж с черными полосами.

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

wdrakula пишет:

DetSimen пишет:

смени лучше Stream на Print, он памойму не абстрактный. 

...ну, ...какбэ   ...вот:

virtual size_t write(uint8_t) = 0;

На этой-самой "врайте" весь класс построен. Сорри.

Ну дак ты прав.  Не надо шило на мыло менять.  

Хотя странно, я могу обьявить указатель на абстрактный класс и присвоить ему любого потомка (не абстрактного), не должен компилятор ругаться, я ж экземпляр не создаю.  

switch
Offline
Зарегистрирован: 07.12.2015

wdrakula пишет:

Срач на тему "программисты против веб-говнокодеров" уже всем поднадоел, но все же:

Если художника, любого ульра-пост-... современного, попросить нарисовать лошадку, или мастрера супер-трэш-металла попросить сыграть "к Элизе" или токкату Ре-минор, или математика тополога попросить решить квадратное уравнение - НИКТО из них не скажет, что у него "другие компетенции".

Вот так и С/С++ - это как обязательное сольфеджио для музыканта, или основы мат анализа для математика. То, что не может быть "вне компетенции". Как-то так ;))))))))))))))).

Так-то я когда-то и на ассемблере писал по пики, в начале жизненного пути на паскале, потом дельфи. Но плотно с C++ начал только на ардуино работать. А чтоб было привычно нужно лет 5 постоянно пользоваться. 

b707
Offline
Зарегистрирован: 26.05.2017

switch пишет:

Так-то я когда-то и на ассемблере писал по пики, в начале жизненного пути на паскале, потом дельфи. Но плотно с C++ начал только на ардуино работать. А чтоб было привычно нужно лет 5 постоянно пользоваться. 

имхо, проблема не в отсуствии "привычки к С++" - а в отсутсвии привычки искать ответы самостоятельно в гугле, вместо того чтоб задавать элементарные вопросы на форуме...

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

"Привычка к С++" у меня примерно на вашем уровне, а вот гугль я люблю :)

switch
Offline
Зарегистрирован: 07.12.2015

b707 пишет:

switch пишет:

Так-то я когда-то и на ассемблере писал по пики, в начале жизненного пути на паскале, потом дельфи. Но плотно с C++ начал только на ардуино работать. А чтоб было привычно нужно лет 5 постоянно пользоваться. 

имхо, проблема не в отсуствии "привычки к С++" - а в отсутсвии привычки искать ответы самостоятельно в гугле, вместо того чтоб задавать элементарные вопросы на форуме...

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

"Привычка к С++" у меня примерно на вашем уровне, а вот гугль я люблю :)

ох любят тут попинать, любят. Наверное не все еще отписались на тему что я такой растакой гуглом пользоваться не умею? 

Logik
Offline
Зарегистрирован: 05.08.2014

switch пишет:

 Наверное не все еще отписались на тему что я такой растакой гуглом пользоваться не умею? 

Ну я пропустил отписатся, извини. Исправлюсь. Неумееш и это.

switch пишет:

ох любят тут попинать

А чё еще делать с челом, который на словах - в медалях из прошитых PIC на деле не архитектуру продумать, ни протокол составить ни, простигосподи, точку с запятой поставить без гугла и форума. С ними тоже вобщем не очень.

switch
Offline
Зарегистрирован: 07.12.2015

Logik пишет:

switch пишет:

 Наверное не все еще отписались на тему что я такой растакой гуглом пользоваться не умею? 

Ну я пропустил отписатся, извини. Исправлюсь. Неумееш и это.

switch пишет:

ох любят тут попинать

А чё еще делать с челом, который на словах - в медалях из прошитых PIC на деле не архитектуру продумать, ни протокол составить ни, простигосподи, точку с запятой поставить без гугла и форума. С ними тоже вобщем не очень.

ну пики я сразу не взлюбил, поэтому и проектов на них было мало. И было это 17 лет назад. Потом я программировал в основном напаскале, потом на Дельфи, фоксе. Потом уже VB, пых, js, node, perl и немного С.  Есть еще несколько языков, но все они специфические. Если с ними столкнетесь и придете на форум где я есть, то вас не будут так тыкать носом. В данном конкретном случае я хочу научиться новому для меня подходу. Сделать чтоб работало - не проблема. Я хочу научиться.

У каждого человека, который встречается вам на пути есть своя битва, о которой вы не знаете ничего. Будьте вежливы. Всегда.

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

wdrakula пишет:

Если художника, любого ульра-пост-... современного, попросить нарисовать лошадку...

wdrakula
wdrakula аватар
Онлайн
Зарегистрирован: 15.03.2016

Супер!!!

Logik
Offline
Зарегистрирован: 05.08.2014

Одну явно костылями подняли до требований заказчика.

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

Logik пишет:

Одну явно костылями подняли до требований заказчика.

А что такое. Современная цивилизация только на костылях и держится. Ведь кругом деградация ума.

Logik
Offline
Зарегистрирован: 05.08.2014

qwone пишет:

Logik пишет:

Одну явно костылями подняли до требований заказчика.

А что такое. Современная цивилизация только на костылях и держится. Ведь кругом деградация ума.

Вот не скажу что это пост не по теме ;)

switch
Offline
Зарегистрирован: 07.12.2015
товарищи, продолжая тему, подскажите, пожалуйста следующее: есть класс, реализующий работу с периферией. По сути он отвечает за нумерацию устройств, разбор заголовков, формирование пакетов, проверку контрольных сумм и т.п. При нумерации периферии он посылает пакет специальный, периферия отвечает пакетами с типом. На этом этапе в этом значит классе (вернее в экземпляре объекта) должны создаться экземпляры объектов для каждого из периферийных устройств.
В коде примерно так:
 
class cExtensionMaster
{
  private:
  public:
    //массив указателей на объекты
    void *extDevs[];  //в этой строке вопрос и есть. Нужно создать массив который потом наполним. Типы тоже не известны заранее
    //конструктор класса
    cExtensionMaster();
 
    //запустить процедуру обнаружения устройств
    void SendDiscovery();
    //обработка пакетов обнраужения от периферии
    void RecvDiscovery();
};
    void cExtensionMaster::RecvDiscovery()
    {
          //вот тут нам прилетают пакеты от разных девайсов и нам нужно создать кучку экземпляров объектов устройств. 
          //Причем они могут быть разных типов, т.к. функции у периферии могут быть разные.
          //типа так:
          if(device.type=0x01)
             extDevs[device.addr]=new cDeviceTye01;
 
          if(device.type=0x02)
             extDevs[device.addr]=new cDeviceTye02
    }
 
Как это правильно сделать?
В идеале хочется потом обращаться к портам и функциям периферии как-то так:
Extensions->Device[1]->port[1].value(2).onTrigger(callBackFunc).send().