Arlleex 183 11 июня, 2021 Опубликовано 11 июня, 2021 · Жалоба 43 минуты назад, one_eight_seven сказал: Непонятна задача полностью, вы показываете фрагмент... Я сейчас занимаюсь разработкой небольшого протокола поверх CAN для своих устройств. Основная идея заключается в том, что девайсы разные и имеют разную логическую репрезентацию для пользователя. Например, какой-нибудь датчик, внутри которого можно выделить следующие логические блоки: модуль семплирования, модуль самодиагностики, модуль настроек и управления поведением датчика. Каждый логический блок (который с точки зрения протокола я называю Node) имеет свой набор CAN-ID, в который входят рабочие ID (по которым, собственно, девайс выдает и принимает информацию в штатном режиме в соответствии со своей задачей), и сервисные, которые позволяют узнать имя того или иного узла или ассоциированного ID. Это нужно для того, чтобы (в будущем) на ПК-шной программе я мог запустить кнопкой "Поиск устройств на шине" процедуру обнаружения девайсов с заранее неизвестным наличием тех или иных. И в результате должен увидеть графическое дерево, сначала глобальное, на котором узлами являются сами устройства, а кликая на девайс - я должен видеть его логическую структуру с маркированными адекватными понятными именами модулями, составом рабочих ID, кто за что отвечает. Это основная идея. CANOpen не предлагайте Но для того, чтобы изолировать логику самого протокола от юзер-зависимых данных (на текущий момент это таблица всех ID, прошиваемых пользователем на этапе конфигурации конкретного экземпляра девайса), приходится делать небольшие "прослойки" в виде дополнительных таблиц, которые, помимо содержания тех самых "имен" CAN-ID, должны иметь одинаковый интерфейс для кода самого протокола при смене порядка следования/добавлении новых ID в настроечной таблице (CANIDTbl). Поэтому протокол опирается именно на эту "промежуточную" таблицу, чтобы в 10 разных местах не править логику ассоциации CAN-ID-интерфейсов, а только при необходимости в одном. Пока что как-то так. Я пока в процессе больше художественном, так что за день может поменяться многое. Поэтому я еще не приступая к непосредственной логике протокола (обработка запросов, выдача сервисных данных и т.д.) должен ввести некоторые константные структуры и таблицы с синтаксической возможностью задавать некоторые связи "парами", т.е. заранее определенными числами. Тут нет никакого ООП - банальное размещение объектов и ручная инициализация. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Forger 26 11 июня, 2021 Опубликовано 11 июня, 2021 · Жалоба 30 minutes ago, Arlleex said: CANOpen не предлагайте Почему надо обязательно изобрести лисапед придумать заново уже готовое существующее решение, причем, исходники и дока валяются на каждом углу? Тут наверно что-то военное/секретное ))) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 241 11 июня, 2021 Опубликовано 11 июня, 2021 · Жалоба 1 час назад, Arlleex сказал: Т.е. смотрим ITEM(): индексы идут (и могут идти) не по порядку. Чуть позже я хотел создать #define-ны с осмысленными названиями индексов. Но, раз в C++ (по стандарту, что ли, получается?) нельзя выборочно инициализировать элементы массива (а также в любом синтаксически указанном порядке), Почему это нельзя? Вот: enum { TEMP_CHA_NTC1, TEMP_CHA_NTC2, TEMP_CHA_NTC3, TEMP_CHA_PT1, TEMP_CHA_PT2, TEMP_CHA_IRED, TEMP_CHA_n }; static u8 const defTyp[TEMP_CHA_n] = { [TEMP_CHA_NTC2] = TYP_BOSCH_NTC, [TEMP_CHA_NTC1] = TYP_BOSCH_NTC, [TEMP_CHA_NTC3] = TYP_BOSCH_NTC, // [TEMP_CHA_PT1] = TYP_PT1000, [TEMP_CHA_PT2] = TYP_PT1000, [TEMP_CHA_IRED] = TYP_YASA_P400}; IAR проглатывает это молча. c++ PS: В Вашем коде "нельзя" потому, что есть конструктор sCANIDTbl(). Уберите его и будет льзя. А с конструктором инициализации типа: type array[] = {...}; запрещены. Любые. Даже не выборочные. Тут уж "трусы надень или крестик сними". Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Arlleex 183 11 июня, 2021 Опубликовано 11 июня, 2021 · Жалоба 54 минуты назад, Forger сказал: Почему надо обязательно изобрести лисапед придумать заново уже готовое существующее решение... Г*вно потому что этот CANOpen. Не нравится мне. Аргументировать не буду - протокол "для своих" 47 минут назад, jcxz сказал: Почему это нельзя? Вот и я не знаю, почему комитет так решил. Цитата IAR проглатывает это молча... Keil тоже проглатывает, но выдает Warning, мол такая инициализация только в C99 разрешена. Нет ее в C++. Но это я про структуры. В Вашем примере массив u8 - а это не структура и там правила инициализации несколько другие, так что может и работать... Цитата В Вашем коде "нельзя" потому, что есть конструктор sCANIDTbl()... Из-за умников в комитете, а не из-за конструктора. В моем случае пользовательский конструктор по умолчанию нужно объявить, иначе - ошибка компиляции. Вчера выяснили. __no_init, скорее всего, снимает требование объявить конструктор у IAR, поэтому там работает. Цитата А с конструктором инициализации типа: type array[] = {...}; запрещены. Любые... Так у меня в той структуре нет конструкторов. P.S. Это я на ARM Compiler 6.14 сейчас. Попробовал ради интереса на 6.12 скомпилировать - съел без предупреждений Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 241 11 июня, 2021 Опубликовано 11 июня, 2021 · Жалоба 11 минут назад, Arlleex сказал: Так у меня в той структуре нет конструкторов. Скормил ваш код IAR-у: скомпился молча и без варнингов (код вставил "как есть", только добавил #define MAX_CANID_QNT 3). И ещё откорректировал на: __root volatile const sCANIFDesc CANIFDesc[MAX_CANID_QNT] = ... чтоб не выкидывал за неиспользованием. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Arlleex 183 11 июня, 2021 Опубликовано 11 июня, 2021 · Жалоба 6 минут назад, jcxz сказал: Скормил ваш код IAR-у: скомпился молча и без варнингов (код вставил "как есть", только добавил #define MAX_CANID_QNT 3). Вверху дописал только что. Видимо, от версии к версии различные взгляды на "правильность" Стандарта, и чем свежее компилятор, тем строже соблюдение правил... Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Forger 26 11 июня, 2021 Опубликовано 11 июня, 2021 · Жалоба 26 minutes ago, Arlleex said: Keil тоже проглатывает, но выдает Warning, мол такая инициализация только в C99 разрешена Какой компилятор? Версия. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Arlleex 183 11 июня, 2021 Опубликовано 11 июня, 2021 · Жалоба 1 минуту назад, Forger сказал: Какой компилятор? Версия. ARM CLang V6.14. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Forger 26 11 июня, 2021 Опубликовано 11 июня, 2021 · Жалоба Вот тут это описано: https://stackoverflow.com/questions/18731707/why-does-c11-not-support-designated-initializer-lists-as-c99 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Arlleex 183 16 июня, 2021 Опубликовано 16 июня, 2021 · Жалоба Я тут снова всех приветствую! Дисклеймер: Кусочек для примера #define MAX_CANIF_QNT 3 typedef struct { u32 id : 29; u32 ext : 1; #define CAN_IDDIR_RX 0 #define CAN_IDDIR_TX 1 u32 dir : 1; #define CAN_IDTYPE_SVC 0 #define CAN_IDTYPE_WORK 1 u32 type : 1; }sCANID; typedef struct { const char *const name; const void *const hnd; volatile const sCANID *const id; }sCANIF; ... static const sCANID CANIDTbl[MAX_CANIF_QNT] = { {0, 0, CAN_IDDIR_RX, CAN_IDTYPE_SVC}, #ifdef PROJSET_CAN_RXID_STD {PROJSET_CAN_RXID, 0, CAN_IDDIR_RX, CAN_IDTYPE_SVC}, #else {PROJSET_CAN_RXID, 1, CAN_IDDIR_RX, CAN_IDTYPE_SVC}, #endif #ifdef PROJSET_CAN_TXID_STD {PROJSET_CAN_TXID, 0, CAN_IDDIR_TX, CAN_IDTYPE_SVC} #else {PROJSET_CAN_TXID, 1, CAN_IDDIR_TX, CAN_IDTYPE_SVC} #endif }; const sCANIF CANIFTbl[MAX_CANIF_QNT] = { #define ITEM(p, n, h) {n, (const void *const)h, &CANIDTbl[p]} ITEM(0, "XCAN RESERVED ID", NULL), ITEM(1, "ROOT:UHMIM:SVC RX IF", &RootNode), ITEM(2, "ROOT:UHMIM:SVC TX IF", NULL) #undef ITEM }; ... u32 can_SendMsg(sCANID id, u8 msg[], u8 len) { ... } // использую void my_func(void) { can_SendMsg(*CANIFTbl[1].id, ...); } Выдает Цитата error: no matching constructor for initialization of 'sCANID' note: candidate constructor (the implicit copy constructor) not viable: 1st argument ('const volatile sCANID') would lose volatile qualifier note: candidate constructor (the implicit move constructor) not viable: 1st argument ('const volatile sCANID') would lose const and volatile qualifiers note: candidate constructor (the implicit default constructor) not viable: requires 0 arguments, but 1 was provided Я так полагаю, что нужно предоставить конструктор копирования, только вот каким образом? P.S. Решение (нашел для себя, читая про конструкторы копирования) typedef struct sCANID { u32 id : 29; u32 ext : 1; #define CAN_IDDIR_RX 0 #define CAN_IDDIR_TX 1 u32 dir : 1; #define CAN_IDTYPE_SVC 0 #define CAN_IDTYPE_WORK 1 u32 type : 1; sCANID() {} sCANID(u32 id, u32 ext, u32 dir, u32 type) : id(id), ext(ext), dir(dir), type(type) {} sCANID(volatile const sCANID &i) : id(i.id), ext(i.ext), dir(i.dir), type(i.type) {} }sCANID; Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Kabdim 0 16 июня, 2021 Опубликовано 16 июня, 2021 · Жалоба Комитет не избавлялся ни от чего. Напомню что ++ ответивились от C98. И потом комитет лишь добавлял то что появлялось в последующих сях, а иногда не добавлял. Вопрос насчет разницы между конструкциями С и С++ очень интересный и в нём много интересных мозгокрутящих моментов. Но с практической точкии зрения мало нужный, считайте что ++ почти совместимы (за исключением именованных инициализаций, массивов переменной длинны в аргментах и тд). По поводу именовванных инициалзаций, понять комитет вполне возможно. Вместо них используйте конструкторы. Еще советую навсегда забыть про битовые поля (особенно в комбинации с volatile), если нет желания прыгать на граблях. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Сергей Борщ 141 16 июня, 2021 Опубликовано 16 июня, 2021 · Жалоба 2 часа назад, Kabdim сказал: Еще советую навсегда забыть про битовые поля От я дурак! Битовую арифметику компилятору доверяю. Оказывается солнце-то вручную закатывать надо! Пойду перелопачивать свои исходники... Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Forger 26 16 июня, 2021 Опубликовано 16 июня, 2021 · Жалоба 5 hours ago, Kabdim said: Еще советую навсегда забыть про битовые поля (особенно в комбинации с volatile), если нет желания прыгать на граблях. Давно успешно пользую union/struct в комбинированном составе и при этом все работает чотко и одинаково на любом компиляторе и в любом проце. Может дело и не в битовых полях, а в неудачно разложенных в исходниках граблях? ;) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
esaulenka 7 16 июня, 2021 Опубликовано 16 июня, 2021 · Жалоба On 6/11/2021 at 3:05 PM, jcxz said: Почему это нельзя? Потому что инициализация выборочных полей массива описана в стандарте C99 (вот тут), но не описана ни в каком стандарте C++. Каких-то черновиков для включения в стандарт вроде б нет (но я очень невнимательно слежу за деятельностью комитета по стандартизации). В прошлом году (наконец-то!) подобный механизм для структур перетащили из C99 в C++20 (см. пункты 3, 4). Так что iar молодцы, конечно, но при перетаскивании этого кода куда-то ещё будут приключения. 8 hours ago, Arlleex said: volatile const sCANID *const id; Я невнимательно читал тему. Это у вас настройки такие, что-ли? Иначе зачем так делать? 8 hours ago, Arlleex said: typedef struct { ... }sCANID; Микро-совет. Если пишете на плюсах, пишите просто struct Name { ... }; То же самое по смыслу, но а) букв меньше б) в IDE навигации по коду не вылезает анонимная структура. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Arlleex 183 16 июня, 2021 Опубликовано 16 июня, 2021 · Жалоба 46 минут назад, esaulenka сказал: Я невнимательно читал тему. Это у вас настройки такие, что-ли? Иначе зачем так делать? Да, хранятся отдельной таблицей в отведенном секторе Flash-памяти. В дальнейшем указатель ссылается либо на настройки из Flash (когда заданы), либо на дефолтные. Цитата Микро-совет... Это я знаю, просто в .h-никах из-за такой записи редактор подсвечивает синтаксис красным, показывая, мол, что перед Name должно быть ключевое слово 'struct'. Когда .h переименовываешь в .hpp, то косяк исчезает. Конечно, оно компилируется и так, и так. Сейчас у меня .h переименовался в .hpp, так что там это исправлено. Для себя сделал небольшое отличие .h- от .hpp-файлов: если никаких плюсовых фишек не используется, то это .h, чтобы можно было его подключить к пуре .c-исходнику. Как только появляются какие-то плюсовые штучки, то файл становится .hpp Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться