• Система автоматизации с открытым исходным кодом на базе esp8266/esp32 микроконтроллеров и приложения IoT Manager. Наша группа в Telegram

Вопрос при обращении this->var esp8266 валится

switch07

New member
Добрый день!
Возникла странная проблема, которую не знаю как диагностировать.
Код:
    bool cExtensionDevice10::onRecieve(byte vAddr, byte vType, byte vFunc, byte vSize, char buf[])
    {
      //если адрес на наш и тип устройства не подходит то ничего не делаем
      if(vAddr != this->Addr || vType!= EXTDEV_TYPE_10)
при обращении к this->Addr проц вываливается в
Код:
Exception (28):
epc1=0x40201f30 epc2=0x00000000 epc3=0x00000000 excvaddr=0x0000000d depc=0x00000000

ctx: cont 
sp: 3ffef5a0 end: 3ffef830 offset: 01a0
сама переменная this->Addr в конструкторе задается, но в этом методе вываливается в ошибку. Что может быть не так?
 

Юрий Ботов

Moderator
Команда форума
Покажите кусок класса и место где создается объект этого класса...
 

switch07

New member
Объявляется это дело вот так:
Код:
public:
    //массив для устройств типа cExtensionDevice10, максимум 8 штук
    cExtensionDevice10 * Dev10[EXTDEV_TYPE_10_MAXCOUNT];
    byte Dev10Count=0;
т.е. создается массив указателей типа это класса, потом во время процедуры обнаружения девайсов создаются экземпляры под каждый найденный тип.
Подозреваю что неправильно:
Код:
              if(Dev10Count < EXTDEV_TYPE_10_MAXCOUNT)
              //создаем экземпляр объекта устройства типа 10 и передаем указатель на этот объект для правильной работы
              this->Dev10[Dev10Count] = new cExtensionDevice10(Header.Src,this);
              Dev10Count++;
Тут вообще большой вопрос кроется. Если в кратце:

[cExtension]->[cDevice]->[cPort]
класс cExtension обеспечивает базовые функции обмена: обнаружение на шине, адресацию, контроль, в общем формирует хеадер, принимает и отправляет бинарные данные. При обнаружении устройств создает внутри себя экземпляры класса cDevice.
Класс cDevice реализует работу с конкретным типом устройств. Принимает от cExtension пакет данных (все кроме хеадера), декодирует в соответствии со своим типом. Разные типы устройств имеют разные возможности: набор портов, интерфейсов. Имеет какое-то количество портов разного типа (вход, выход, шим, аналог и тп). Для каждого порта создается экземпляр класса типа cPort. Который уже реализует все функции работы с портом.

Так вот типов cDevice может быть много разных. И как эти разные типы уложить в один массив? Или они все должны быть наследником какого то абстрактного класса, потомки которого уже реализуют свой набор возможностей, а в массиве тип элементов будет этот абстрактный класс? Просто я в С++ новичок, прошу не пинать сильно ;)

Все это задумывается для того чтоб сделать расширитель портов для 8266 из обычных мег168. Эти расширители можно цеплять последовательно и получать нужное количество портов. Хотел сделать универсальнее, получилось как всегда. Могу выложить весь код, если интересно. Хотя ничего выдающегося там нет.
 

Юрий Ботов

Moderator
Команда форума
И как эти разные типы уложить в один массив?
Уложить в связанный список (где у итема поле enum ТИП ссылка void* на экземпляр, а при использовании, приведение типа в зависимости от ТИПа), либо да, наследование. Я бы тупо использовал список, с наследованием (если по всем правилам) слишком ветвисто получится (device/(digital/analog)/(in/out)/(bit/byte/word/block)...).
this->Dev10[Dev10Count] = new cExtensionDevice10(Header.Src,this);
А вот тут проверьте, не возвращает ли оно NULL
 

switch07

New member
Уложить в связанный список (где у итема поле enum ТИП ссылка void* на экземпляр, а при использовании, приведение типа в зависимости от ТИПа),
не могли бы дать ссылку на пример, или кусок кода? А то я не знаю что искать толком. Мне с С++ очень непривычно работать. Буду очень признателен за помощь
либо да, наследование. Я бы тупо использовал список, с наследованием (если по всем правилам) слишком ветвисто получится (device/(digital/analog)/(in/out)/(bit/byte/word/block)...).
наследники могут ведь иметь другие методы и свойства, а не только те которые имеет родитель? если да, то мне этого будет достаточно.

А вот тут проверьте, не возвращает ли оно NULL
сделал вот так
Код:
              this->Dev10[Dev10Count] = new cExtensionDevice10(Header.Src,this);
              if(this->Dev10[Dev10Count]==NULL)
                    Serial.println("####### NULLNULL #######");
не печатает, значит !NULL
Пробовал еще так сделать:
Код:
              cExtensionDevice10 * ptrdev = new cExtensionDevice10(Header.Src,this);
              this->Dev10[Dev10Count] = ptrdev;
но не компилится, говорит ptrdev не определен.[/QUOTE]
 

Юрий Ботов

Moderator
Команда форума
Видимо все таки придется выкладывать весь код... только оберните его в тэг "код" (на полосе редактора рядом мужиком в шляпе)
 

Юрий Ботов

Moderator
Команда форума
Просьба не воспринимать как злую насмешку :) но я кажется смог классифицировать проблему:
"Невнимательность при прочтении трудов Бьерна Страустрапа отягощенная склонностью к копи-пасту". Все мы через подобное прошли...
1. Перечитайте правила использования "." (точки) и "->" (стрелки) при обращении к членам экземпляра класса - это основная проблема у вас.
2. В Ардуино зайдите Файл/Настройки и включите "Показать подробный вывод - Компиляция и Сообщения компилятора - Все" - к сожалению по умолчанию их нередко выключают
А если серьезно, то:
- this.b внутри члена класса нужен только если у вас есть другая переменная с тем же именем, а в иных случаях достаточно просто b
то есть:
Код:
cExtensionDevice10::cExtensionDevice10(byte vAddr, cExtensionMaster * pExtensionMaster)

{
  ...
  //сохраняем адрес устройства
  Addr=vAddr;
  ...
}
ну и т.п. А у вас везде -> где надо и где не надо. Внутри себя класс НЕ ЗНАЕТ о том что вы будете обращаться к его экземпляру через указатель.
 

switch07

New member
Спасибо за ответ! Страуструпа читал 20 лет назад в институте ;)
Так сложилось что на С/С++ почти не программировал, осваивать его начал вот с ардуино. Задачи были простыми, поэтому реализовывал все функциональным программированием. В этом проекте решил сделать все красиво (как я это понимаю), заодно научиться. Поэтому любая конструктивная критика приветствуется ;)
ну и т.п. А у вас везде -> где надо и где не надо. Внутри себя класс НЕ ЗНАЕТ о том что вы будете обращаться к его экземпляру через указатель.
я читал что это правильная практика. Мне и самому удобнее так делать, понятно что обращаюсь к своим переменным и методам. Ну и в других языках программирования это распространенная практика (php, nodejs,js). Полагаете проблема из-за этого?

PS: я включил вывод всех ошибок. Нового мало: предупреждения об объявлении неиспользуемых переменных, да еще сотни ошибок от сторонних библиотек, которые даже не используются в проекте. Ну и еще одна ошибка в функции которая что-то возвращает, а в коде нет return
 
Последнее редактирование:

Юрий Ботов

Moderator
Команда форума
проблема действительно в том что вы в классе объявляете "byte Addr;" А потом обращаетесь к нему везде, даже в конструкторе! как this->Addr; В результате, кусок созданного объекта воспринимается как адрес, к нему добавляется смещение и туда процессор пытается читать/писать - а это вовсе не адрес, это указатель неизвестно куда.
 

Алексей.

Active member
switch07,
на строке 652
if(Header.Type==0x10 && Header.Src < EXTDEV_TYPE_10_MAXCOUNT)
вы принимаете решение выполнить метод cExtensionDevice10:: onRecieve, указатели на классы храните в cExtensionMaster:: Dev10[] и не проверяете перед вызовом, хотя и проверка тут не поможет, вы не инициализируете их в начале и заполняете только в "обслуживание discovery пакетов".
Если в "обслуживание discovery пакетов" для заданного Header.Src указатель this->Dev10[Header.Src] ещё не заполнялся, то вызовом this->Dev10[Header.Src]->onRecieve вы попадаете в "черную дыру".

П.С.
Предположим Header.Src = 1 и при обслуживании первого "discovery пакета" был заполнен this->Dev10[Dev10Count], Dev10Count был равен 0
фактически this->Dev10[0] = new cExtensionDevice10(Header.Src,this);
после этого вы, проверив условие if(Header.Type==0x10 && Header.Src < EXTDEV_TYPE_10_MAXCOUNT) выполняете this->Dev10[Header.Src]->onRecieve, т.е. this->Dev10[1]->onRecieve, а this->Dev10[1] ещё и не инициализировался.
 
Последнее редактирование:

switch07

New member
Алексей, Юрий, спасибо большое!
Я сейчас попробую разобраться в этом всем, исправлю.
 

switch07

New member
Добрый день!
Я изменил немного код программы, теперь все работает. Все что сказал Алексей - так и сделал. Большое спасибо за помощь!
 
Сверху Снизу