Перейти к содержанию
    

Плавный переход C -> C++ под МК

43 минуты назад, one_eight_seven сказал:

Непонятна задача полностью, вы показываете фрагмент...

Я сейчас занимаюсь разработкой небольшого протокола поверх CAN для своих устройств. Основная идея заключается в том, что девайсы разные и имеют разную логическую репрезентацию для пользователя. Например, какой-нибудь датчик, внутри которого можно выделить следующие логические блоки: модуль семплирования, модуль самодиагностики, модуль настроек и управления поведением датчика. Каждый логический блок (который с точки зрения протокола я называю Node) имеет свой набор CAN-ID, в который входят рабочие ID (по которым, собственно, девайс выдает и принимает информацию в штатном режиме в соответствии со своей задачей), и сервисные, которые позволяют узнать имя того или иного узла или ассоциированного ID. Это нужно для того, чтобы (в будущем) на ПК-шной программе я мог запустить кнопкой "Поиск устройств на шине" процедуру обнаружения девайсов с заранее неизвестным наличием тех или иных. И в результате должен увидеть графическое дерево, сначала глобальное, на котором узлами являются сами устройства, а кликая на девайс - я должен видеть его логическую структуру с маркированными адекватными понятными именами модулями, составом рабочих ID, кто за что отвечает. Это основная идея. CANOpen не предлагайте:smile:

Но для того, чтобы изолировать логику самого протокола от юзер-зависимых данных (на текущий момент это таблица всех ID, прошиваемых пользователем на этапе конфигурации конкретного экземпляра девайса), приходится делать небольшие "прослойки" в виде дополнительных таблиц, которые, помимо содержания тех самых "имен" CAN-ID, должны иметь одинаковый интерфейс для кода самого протокола при смене порядка следования/добавлении новых ID в настроечной таблице (CANIDTbl). Поэтому протокол опирается именно на эту "промежуточную" таблицу, чтобы в 10 разных местах не править логику ассоциации CAN-ID-интерфейсов, а только при необходимости в одном. Пока что как-то так. Я пока в процессе больше художественном, так что за день может поменяться многое.

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

30 minutes ago, Arlleex said:

CANOpen не предлагайте

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

Тут наверно что-то военное/секретное )))

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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(). Уберите его и будет льзя.  :wink:

А с конструктором инициализации типа: type array[] = {...};  запрещены. Любые. Даже не выборочные. Тут уж "трусы надень или крестик сними".  :unknw:

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

54 минуты назад, Forger сказал:

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

Г*вно потому что этот CANOpen. Не нравится мне. Аргументировать не буду - протокол "для своих":smile:
 

47 минут назад, jcxz сказал:

Почему это нельзя?

Вот и я не знаю, почему комитет так решил.

Цитата

IAR проглатывает это молча...

Keil тоже проглатывает, но выдает Warning, мол такая инициализация только в C99 разрешена. Нет ее в C++. Но это я про структуры. В Вашем примере массив u8 - а это не структура и там правила инициализации несколько другие, так что может и работать...

Цитата

В Вашем коде "нельзя" потому, что есть конструктор sCANIDTbl()...

Из-за умников в комитете, а не из-за конструктора. В моем случае пользовательский конструктор по умолчанию нужно объявить, иначе - ошибка компиляции. Вчера выяснили. __no_init, скорее всего, снимает требование объявить конструктор у IAR, поэтому там работает.

Цитата

А с конструктором инициализации типа: type array[] = {...};  запрещены. Любые...

Так у меня в той структуре нет конструкторов.

P.S. Это я на ARM Compiler 6.14 сейчас. Попробовал ради интереса на 6.12 скомпилировать - съел без предупреждений:to_take_umbrage:

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

11 минут назад, Arlleex сказал:

Так у меня в той структуре нет конструкторов.

Скормил ваш код IAR-у: скомпился молча и без варнингов (код вставил "как есть", только добавил #define MAX_CANID_QNT 3).

И ещё откорректировал на: __root volatile const sCANIFDesc CANIFDesc[MAX_CANID_QNT] = ...

чтоб не выкидывал за неиспользованием.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

6 минут назад, jcxz сказал:

Скормил ваш код IAR-у: скомпился молча и без варнингов (код вставил "как есть", только добавил #define MAX_CANID_QNT 3).

Вверху дописал только что.

Видимо, от версии к версии различные взгляды на "правильность" Стандарта, и чем свежее компилятор, тем строже соблюдение правил...

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

26 minutes ago, Arlleex said:

Keil тоже проглатывает, но выдает Warning, мол такая инициализация только в C99 разрешена

Какой компилятор? Версия.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Я тут снова всех приветствую! Дисклеймер: :dash3:

Кусочек для примера

#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;

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Комитет не избавлялся ни от чего. Напомню что ++ ответивились от C98. И потом комитет лишь добавлял то что появлялось в последующих сях, а иногда не добавлял. Вопрос насчет разницы между конструкциями С и С++ очень интересный и в нём много интересных мозгокрутящих моментов. Но с практической точкии зрения мало нужный, считайте что ++ почти совместимы (за исключением именованных инициализаций, массивов переменной длинны в аргментах и тд). По поводу именовванных инициалзаций, понять комитет вполне возможно. Вместо них используйте конструкторы. Еще советую навсегда забыть про битовые поля (особенно в комбинации с volatile), если нет желания прыгать на граблях.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

2 часа назад, Kabdim сказал:

Еще советую навсегда забыть про битовые поля

От я дурак! Битовую арифметику компилятору доверяю. Оказывается солнце-то вручную закатывать надо! Пойду перелопачивать свои исходники... :cray:

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

 

5 hours ago, Kabdim said:

Еще советую навсегда забыть про битовые поля (особенно в комбинации с volatile), если нет желания прыгать на граблях.

Давно успешно пользую union/struct в комбинированном составе и при этом все работает чотко и одинаково на любом компиляторе и в любом проце.

Может дело и не в битовых полях, а в неудачно разложенных в исходниках граблях? ;)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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 навигации по коду не вылезает анонимная структура.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

46 минут назад, esaulenka сказал:

Я невнимательно читал тему. Это у вас настройки такие, что-ли? Иначе зачем так делать?

Да, хранятся отдельной таблицей в отведенном секторе Flash-памяти.
В дальнейшем указатель ссылается либо на настройки из Flash (когда заданы), либо на дефолтные.

Цитата

Микро-совет...

Это я знаю, просто в .h-никах из-за такой записи редактор подсвечивает синтаксис красным, показывая, мол, что перед Name должно быть ключевое слово 'struct'. Когда .h переименовываешь в .hpp, то косяк исчезает. Конечно, оно компилируется и так, и так. Сейчас у меня .h переименовался в .hpp, так что там это исправлено. Для себя сделал небольшое отличие .h- от .hpp-файлов: если никаких плюсовых фишек не используется, то это .h, чтобы можно было его подключить к пуре .c-исходнику. Как только появляются какие-то плюсовые штучки, то файл становится .hpp:smile:

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

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

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...