Jump to content

    

Конвертация блока настроек/калибровки, устройства

34 минуты назад, pokk сказал:

AlexandrY, jcxz, какие библиотеки используете для JSON или что-то свое?

Всё сам, всё сам... Там всё просто, в JSON-е.

34 минуты назад, pokk сказал:

А как дальше использование сохраненных настроек в формате JSON ? С кажем нужен коэффициент параметра который высчитывается каждую секунду. По включению/изменению конвертируем все настройки JSON в структуру в RAM  и работаем через структуру?

Я не храню в JSON. Писал выше.

34 минуты назад, pokk сказал:

Да видал уже его, но для web все равно использую JSON, по этому думаю на нём остановиться, что бы не тянуть лишнее библиотеки.

У меня он тоже из-за веб. А внутри символьный поток сразу на лету парсится в бинарный образ JSON. Ну и обратно - так же.

34 минуты назад, pokk сказал:

А можно по подробнее, как это по таблице соответствий применяете ?

Есть такой базовый описатель (генерится макросами):

//контейнер для CfgMain
#define EntityObjCfg \
  GOBJ_FUNC(JK_title, title, BOX_FID_TITLE),                 \
  GOBJ_BOOL(JK_enable, enable),                              \
  GOBJ_OBJ_MAIN(JK_power, power, ObjCfgPower),               \
  ...                                                        \
  GOBJ_OBJ_MAIN(JK_tle, tle, ObjCfgTle)
ENTITY_END(ObjCfg)

Я такие описатели привязки JSON-объектов к член-данным структуры конфигурации называю "контейнерами".

Этот контейнер описывает в исходнике самый верхний уровень привязки корневого объекта конфигурации {"config":{...}} к полям структуры конфигурации устройства (struct CfgMain).

Из него идут ссылки на вложенные контейнеры (JSON-объекты внутри "config"{}):

//объект CfgMain:\power\voltDC
#define EntityObjCfgVoltDC \
  GOBJ_LIST(JK_action, power.voltDC.act, sensAct),   \
  GOBJ_INUM(JK_min, power.voltDC.min, U16),          \
  GOBJ_INUM(JK_max, power.voltDC.max, U16),          \
  GOBJ_INUM(JK_zero, power.voltDC.zero, U16),        \
  GOBJ_QNUM(JK_scale, power.voltDC.scale, U16, 2, D)
ENTITY_END(ObjCfgVoltDC)

//объект CfgMain:\power
#define EntityObjCfgPower \
  GOBJ_OBJ(JK_ampUVW, power.ampUVW, ObjCfgAmpUVW),   \
  GOBJ_OBJ(JK_ampDC, power.ampDC, ObjCfgAmpDC),      \
  GOBJ_OBJ(JK_voltDC, power.voltDC, ObjCfgVoltDC)
ENTITY_END(ObjCfgPower)

Вложенные объекты (например: {"config":{"power":{...}}} - описываются отдельными контейнерами в исходнике. Например {"config":{"power":{"voltDC":{...}}}} описывается контейнером ObjCfgVoltDC. А в нём уже как видно идут описатели членов CfgMain базовых типов U8, U16, U32, U64, S8, S16, S32, S64, UQ16, UQ32, SQ16, SQ32, FLOAT, DOUBLE, BOOL, LIST и т.п. Также есть описатели массивов этих типов, описатели типов со своими уникальными обработчиками (функциями) и т.п.

В конце концов есть:

//Описатель (контейнер) формата содержимого пространства конфигурации из JSON-сообщения.
static u8 const containerObjCfg[] = {EntityObjCfg};

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

Например в макросе для целочисленных типов (GOBJ_INUM) первый аргумент - ID элемента из массива ключей:

enum {
  JK_zero, JK_scale, JK_action, JK_min, JK_max, JK_offset, JK_curve, JK_decrease, ..., JK_n};

char const apiKeys[] __align4 =
  "zero        " //JK_zero
  "scale       " //JK_scale
  "action      " //JK_action
  "min         " //JK_min
  "max         " //JK_max
  "offset      " //JK_offset
  "curve       " //JK_curve
  "decrease    " //JK_decrease
; 

второй аргумент - имя члена CfgMain:

__packed struct CfgMain {
  __packed struct Power {
    __packed VoltDC {
      u8 act;       
      u16 min, max;
      u16 zero;
      u16 scale;
      ...
    };
    ...
  };
  ...
};

3-й член и далее - тип и список аргументов, зависящий от типа.

 

как-то так. Если очень упрощенно рассказывать.  :smile:

Share this post


Link to post
Share on other sites
10 hours ago, AlexandrY said:

Сами параметры  после десериализации из JSON хранятся в виде переменных в разных местах и модулях.

Это типа в каждом модуле по включени происходи десерилизация нужные ему настроек и заполнение статических перименных ими.

А как их переинициализировать, при измении конфигурации ? Запускать заного функцию иницилизацию данного модуля при измении конфига?

 

10 hours ago, AlexandrY said:

Сериализатор имеет доступ к переменным через массив связывающий имена переменных и указатели на них.

Непонял, это это как ?

jcxz, как все смутно представляю грубо говоря у вас на выходе есть два массива, один типа string с ключами а другой указатели на элементы структуры (power.voltDC.max) , а макросами вы задаете инкапсуляцию обьектов (структур), и создание соответствий двух этим массивов?   

 

 

 

Share this post


Link to post
Share on other sites
4 hours ago, pokk said:

Это типа в каждом модуле по включени происходи десерилизация нужные ему настроек и заполнение статических перименных ими.
А как их переинициализировать, при измении конфигурации ? Запускать заного функцию иницилизацию данного модуля при измении конфига?

Да, при десериализации происходит перенос данных из динамического дерева JSON в статические переменные. 
Мог бы и не делать этого,  jansson предоставляет удобное API для извлечения значений параметров по путям и именам в своем дереве построенном в динамической памяти. 
Но у меня приложения с жестким риалтаймом во-первых , а во-вторых есть некоторое количество других независимых сервисов работы с параметрами. 
В частности теми же параметрами можно управлять через SNMP и MIB базу, через WEB и HTML страницы, через встроенный FTP и файлы, через USB MSD,  через Telnet и VT100 терминал, через движок FreeMASTER и MATLAB, через  GATT базу Bluetooth и т.д. 
И все это требует отдельных мапингов. (т.е. механизмов отображения данных в структуры  разных протоколов) и простыми макросами не отделаться. 
Поэтому у меня отдельная утилита автогенерации исходников с мапингом параметров под разные протоколы.
.   

Share this post


Link to post
Share on other sites
9 часов назад, pokk сказал:

jcxz, как все смутно представляю грубо говоря у вас на выходе есть два массива, один типа string с ключами а другой указатели на элементы структуры (power.voltDC.max) , а макросами вы задаете инкапсуляцию обьектов (структур), и создание соответствий двух этим массивов?

Нет. У меня на выходе один единый массив. Он описывает общую структуру "config"-объекта из JSON-сообщения. И привязку отдельных элементов этого "config"-объекта к членам CfgMain.

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

Если сильно упрощённо, то: после раскрутки всех этих макросов получается результирующий массив содержащий в себе что-то типа:

static u8 const containerObjCfg[] = {BID(JK_config), BTYP(BOX_T_OBJ), WBVAL(sizeof(ObjCfg)), {содержимое_ObjCfg}};

где {содержимое_ObjCfg} - описание содержимое объекта \"config":

BID(JK_title), BTYP(BOX_T_FUNC), WBVAL(offsetof(CfgMain, title)), BOX_FID_TITLE,
BID(JK_enable), BTYP(BOX_T_BOOL), WBVAL(offsetof(CfgMain, enable)),
BID(JK_power), BTYP(BOX_T_OBJ), WBVAL(offsetof(CfgMain, power)), WBVAL(sizeof(ObjCfgPower)), {содержимое_ObjCfgPower}

где {содержимое_ObjCfgPower} - описание содержимое объекта \"config"\"power":

BID(JK_ampUVW), BTYP(BOX_T_OBJ), WBVAL(offsetof(CfgMain, power.ampUVW)), WBVAL(sizeof(ObjCfgPowerAmpUVW)), {содержимое_ObjCfgPowerAmpUVW},
BID(JK_ampDC), BTYP(BOX_T_OBJ), WBVAL(offsetof(CfgMain, power.ampDC)), WBVAL(sizeof(ObjCfgPowerAmpDC)), {содержимое_ObjCfgPowerAmpDC},
BID(JK_voltDC), BTYP(BOX_T_OBJ), WBVAL(offsetof(CfgMain, power.voltDC)), WBVAL(sizeof(ObjCfgPowerVoltDC)), {содержимое_ObjCfgPowerVoltDC},

где {содержимое_ObjCfgVoltDC} - описание содержимое объекта \"config"\"power"\"voltDC":

BID(JK_action), BTYP(BOX_T_LIST), WBVAL(offsetof(CfgMain, power.voltDC.act), WBVAL(offsetof(JApiLList, sensAct)),
BID(JK_min), BTYP(BOX_T_INUM_U16), WBVAL(offsetof(CfgMain, power.voltDC.min),
BID(JK_max), BTYP(BOX_T_INUM_U16), WBVAL(offsetof(CfgMain, power.voltDC.max),
...

где:

#define offsetof(typ, member) (size_t)&(((typ *)NULL)->member)

#define WBVAL(x) (u8)(u32)(x), (u8)((u32)(x) >> 8 * assert_static((u32)(x) < B16))

#define DBVAL(x) (u8)(u32)(x), (u8)((u32)(x) >> 8), (u8)((u32)(x) >> 16), (u8)((u32)(x) >> 24)

#if BOX_TYPNB == 1
#define BTYP(typ) typ
#else
#define BTYP(typ) WBVAL(typ)
#endif

#if JSON_ID_NB == 1
#define BID(id) id
#else
#define BID(id) WBVAL(id)
#endif

Т.е. - этот массив (containerObjCfg) состоит из множества описателей элементов, первым в котором идёт ID элемента (JK_...); вторым - его тип (BOX_T_...); третьим - смещение привязанного к нему члена CfgMain от начала CfgMain (offsetof(CfgMain, член)); далее - опциональный хвост аргументов, определяемый конкретным типов BOX_T_... .

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

 

Обработчик входящего бинарного образа JSON проходит по массиву контейнеров containerObjCfg, проверяя по нему:

соответствие структуры полученного JSON шаблону заданному containerObjCfg;

соответствие всех типов входящего JSON типам описанным в containerObjCfg;

соответствие дерева объектов/массивов входящего JSON дереву описанному в containerObjCfg;

выполняет декодирование и присваивание значений элементов входящего JSON соответствующим переменным описанным в containerObjCfg;

в отдельном массиве отпечатка JSON создаёт отпечаток (бит-карту) элементов CfgMain, тех которые встретились во входящем JSON.

Share this post


Link to post
Share on other sites

Появилось время,  продолжил копание в этом направлении, но пока  какая то каша в голове.

On 12/3/2019 at 8:09 PM, jcxz said:

Если сильно упрощённо, то: после раскрутки всех этих макросов получается результирующий массив содержащий в себе что-то типа:

static u8 const containerObjCfg[] = {BID(JK_config), BTYP(BOX_T_OBJ), WBVAL(sizeof(ObjCfg)), {содержимое_ObjCfg}}; 

 Как вы по такому объекту все ключи перебираете ?

On 12/3/2019 at 8:09 PM, jcxz said:

третьим - смещение привязанного к нему члена CfgMain от начала CfgMain (offsetof(CfgMain, член));

а можно сделать не от начала CfgMain, а скажем от voltDC если допустим voltDC 3 штуки.

что бы получилось  Power.voltDC.adc.act; Power.voltDC1.adc.act; Power.voltDC2.adc.act;  c одним описателем  adc.act

BID(JK_voltDC), BTYP(BOX_T_OBJ), WBVAL(offsetof(CfgMain, power.voltDC)), WBVAL(sizeof(ObjCfgPowerVoltDC)), {содержимое_ObjCfgPowerVoltDC},
BID(JK_voltDC), BTYP(BOX_T_OBJ), WBVAL(offsetof(CfgMain, power.voltDC1)), WBVAL(sizeof(ObjCfgPowerVoltDC)), {содержимое_ObjCfgPowerVoltDC},
BID(JK_voltDC), BTYP(BOX_T_OBJ), WBVAL(offsetof(CfgMain, power.voltDC2)), WBVAL(sizeof(ObjCfgPowerVoltDC)), {содержимое_ObjCfgPowerVoltDC},

где содержимое_ObjCfgPowerVoltDC

BID(JK_action), BTYP(BOX_T_LIST), WBVAL(offsetof(CfgMain,  adc.act), WBVAL(offsetof(JApiLList, sensAct)),
BID(JK_min), BTYP(BOX_T_INUM_U16), WBVAL(offsetof(CfgMain, adc.min),
BID(JK_max), BTYP(BOX_T_INUM_U16), WBVAL(offsetof(CfgMain, adc.max),

 

Share this post


Link to post
Share on other sites
8 минут назад, pokk сказал:

 Как вы по такому объекту все ключи перебираете ?

Чтобы ответить, мне пришлось бы привести всё содержимое файла исходника, где это делается. А это - почти 3 тыс. строк.  :wink:

Если кратко: Этот массив (containerObjCfg) описывает как бы общую древовидную структуру всего JSON о всеми возможными полями. При парсинге, функция разбирающая входящий JSON, проходит по этому массиву, анализируя каждый его узел, сравнивая со входящим JSON, где надо - опускаясь ниже на уровень древовидной структуры, где надо - поднимаясь выше.

8 минут назад, pokk сказал:

а можно сделать не от начала CfgMain, а скажем от voltDC если допустим voltDC 3 штуки.

Можно. Для таких объектов (которых есть несколько одинаковых экземпляров (с одинаковой внутренней сложной структурой) в разных местах) у меня есть специальные отдельные массивы контейнеров, внутри которых своё адресное пространство. Когда функция парсинга обнаруживает во входящем JSON такой объект, и знает что нужно погрузиться внутрь него, она запоминает на стеке текущую позицию в containerObjCfg и переходит внутрь нового массива (переключает адресное пространство). Когда она дойдёт до конца при парсинге этого нового массива - выйдет из него в сохранённую позицию родительского containerObjCfg.

Такие области со своим адресным пространством у меня называются areas. И вот как они выглядят:

Спойлер

//Макросы создающие контейнеры описателей формата для areas.
#define AOBJ_FUNC(id, r, v, func)                  BID(id), BTYP(BOX_T_FUNC), WBVAL(offsetof(r, v)), func
#define AARR_FUNC(r, v, func)                               BTYP(BOX_T_FUNC), WBVAL(offsetof(r, v)), func
#define AOBJ_FUNC_IX(id, r, v, func, ix)           BID(id), BTYP(BOX_T_FUNC_IX), WBVAL(offsetof(r, v)), func, ix
#define AARR_FUNC_IX(r, v, func, ix)                        BTYP(BOX_T_FUNC_IX), WBVAL(offsetof(r, v)), func, ix
#define AOBJ_BOOL(id, r, v)                        BID(id), BTYP(BOX_T_BOOL), WBVAL(offsetof(r, v))
#define AARR_BOOL(r, v)                                     BTYP(BOX_T_BOOL), WBVAL(offsetof(r, v))
#define AOBJ_INUM(id, r, v, typ)                   BID(id), BTYP(concat(BOX_T_INUM_, typ)), WBVAL(offsetof(r, v))
#define AARR_INUM(r, v, typ)                                BTYP(concat(BOX_T_INUM_, typ)), WBVAL(offsetof(r, v))
#define AOBJ_QNUM(id, r, v, typ, norm, tra)        BID(id), BTYP(concat(BOX_T_QNUM_, typ)), WBVAL(offsetof(r, v)), WBVAL(norm), concat(BOX_T_QNUM_TRA, tra)
#define AARR_QNUM(r, v, typ, norm, tra)                     BTYP(concat(BOX_T_QNUM_, typ)), WBVAL(offsetof(r, v)), WBVAL(norm), concat(BOX_T_QNUM_TRA, tra)
#define AOBJ_FNUM(id, r, v, typ)                   BID(id), BTYP(concat(BOX_T_FNUM_, typ)), WBVAL(offsetof(r, v))
#define AARR_FNUM(r, v, typ)                                BTYP(concat(BOX_T_FNUM_, typ)), WBVAL(offsetof(r, v))
#define AOBJ_LIST(id, r, v, list)                  BID(id), BTYP(BOX_T_LIST), WBVAL(offsetof(r, v)), WBVAL(offsetof(JApiLList, list))
#define AARR_LIST(r, v, list)                               BTYP(BOX_T_LIST), WBVAL(offsetof(r, v)), WBVAL(offsetof(JApiLList, list))
#define AOBJ_ARR_FUNC(id, r, v, func)              BID(id), BTYP(BOX_T_ARR_FUNC), WBVAL(offsetof(r, v)), func
#define AARR_ARR_FUNC(r, v, func)                           BTYP(BOX_T_ARR_FUNC), WBVAL(offsetof(r, v)), func
#define AOBJ_ARR_FUNC_IX(id, r, v, func, ix)       BID(id), BTYP(BOX_T_ARR_FUNC_IX), WBVAL(offsetof(r, v)), func, ix
#define AARR_ARR_FUNC_IX(r, v, func, ix)                    BTYP(BOX_T_ARR_FUNC_IX), WBVAL(offsetof(r, v)), func, ix
#define AOBJ_ARR_INUM(id, r, v, typ, n)            BID(id), BTYP(BOX_T_ARR_NUM), WBVAL(offsetof(r, v)), concat(BOX_T_INUM_, typ), n
#define AARR_ARR_INUM(r, v, typ, n)                         BTYP(BOX_T_ARR_NUM), WBVAL(offsetof(r, v)), concat(BOX_T_INUM_, typ), n
#define AOBJ_ARR_FNUM(id, r, v, typ, n)            BID(id), BTYP(BOX_T_ARR_NUM), WBVAL(offsetof(r, v)), concat(BOX_T_FNUM_, typ), n
#define AARR_ARR_FNUM(r, v, typ, n)                         BTYP(BOX_T_ARR_NUM), WBVAL(offsetof(r, v)), concat(BOX_T_FNUM_, typ), n
#define AOBJ_ARR_QNUM(id, r, v, typ, n, norm, tra) BID(id), BTYP(BOX_T_ARR_QNUM), WBVAL(offsetof(r, v)), concat(BOX_T_QNUM_, typ), n, WBVAL(norm), concat(BOX_T_QNUM_TRA, tra)
#define AARR_ARR_QNUM(r, v, typ, n, norm, tra)              BTYP(BOX_T_ARR_QNUM), WBVAL(offsetof(r, v)), concat(BOX_T_QNUM_, typ), n, WBVAL(norm), concat(BOX_T_QNUM_TRA, tra)
#define AOBJ_ARR_LIST(id, r, v, list, n)           BID(id), BTYP(BOX_T_ARR_LIST), WBVAL(offsetof(r, v)), WBVAL(offsetof(JApiLList, list)), n
#define AARR_ARR_LIST(r, v, list, n)                        BTYP(BOX_T_ARR_LIST), WBVAL(offsetof(r, v)), WBVAL(offsetof(JApiLList, list)), n
#define AOBJ_ARR_BIT(id, r, v, ofs, n)             BID(id), BTYP(BOX_T_ARR_BIT), WBVAL(offsetof(r, v)), ofs, n
#define AARR_ARR_BIT(r, v, ofs, n)                          BTYP(BOX_T_ARR_BIT), WBVAL(offsetof(r, v)), ofs, n
#define AOBJ_OBJ(id, r, v, child)                  BID(id), BTYP(BOX_T_OBJ), WBVAL(offsetof(r, v)), WBVAL(sizeof(body##child)), Entity##child
#define AARR_OBJ(r, v, child)                               BTYP(BOX_T_OBJ), WBVAL(offsetof(r, v)), WBVAL(sizeof(body##child)), Entity##child
#define AOBJ_ARR(id, r, v, child)                  BID(id), BTYP(BOX_T_ARR), WBVAL(offsetof(r, v)), WBVAL(sizeof(body##child)), Entity##child
#define AARR_ARR(r, v, child)                               BTYP(BOX_T_ARR), WBVAL(offsetof(r, v)), WBVAL(sizeof(body##child)), Entity##child
#define AOBJ_AREA(id, r, v, area)                  BID(id), BTYP(BOX_T_AREA), WBVAL(offsetof(r, v)), WBVAL(offsetof(Areas, entity##area))
#define AARR_AREA(r, v, area)                               BTYP(BOX_T_AREA), WBVAL(offsetof(r, v)), WBVAL(offsetof(Areas, entity##area))

#define EntityAreaTermoAdc \
  AOBJ_LIST(JK_action, CfgTermo::Adc, act, sensAct),                     \
  AOBJ_LIST(JK_type, CfgTermo::Adc, typ, termoTyp),                      \
  AOBJ_INUM(JK_min, CfgTermo::Adc, min, S16),                            \
  AOBJ_INUM(JK_max, CfgTermo::Adc, max, S16),                            \
  AOBJ_ARR_FUNC(JK_reduce, CfgTermo::Adc, reduce, BOX_FID_TERMO_REDUCE), \
  AOBJ_ARR_FUNC(JK_curve, CfgTermo::Adc, curve, BOX_FID_TERMO_CURVE)
ENTITY_END(AreaTermoAdc)

#define EntityAreaTermoAdcPt \
  AOBJ_LIST(JK_action, CfgTermo::Adc, act, sensAct),                     \
  AOBJ_LIST(JK_type, CfgTermo::Adc, typ, termoTyp),                      \
  AOBJ_INUM(JK_min, CfgTermo::Adc, min, S16),                            \
  AOBJ_INUM(JK_max, CfgTermo::Adc, max, S16),                            \
  AOBJ_ARR_FUNC(JK_reduce, CfgTermo::Adc, reduce, BOX_FID_TERMO_REDUCE), \
  AOBJ_ARR_FUNC(JK_curve, CfgTermo::Adc, curve, BOX_FID_TERMO_CURVE),    \
  AOBJ_ARR_FUNC(JK_calibr, CfgTermo::Adc, typ, BOX_FID_TERMO_CALIBR)
ENTITY_END(AreaTermoAdcPt)

#define EntityAreaTermoMlx \
  AOBJ_LIST(JK_action, CfgTermo::Mlx, act, sensAct),                     \
  AOBJ_INUM(JK_min, CfgTermo::Mlx, min, S16),                            \
  AOBJ_INUM(JK_max, CfgTermo::Mlx, max, S16),                            \
  AOBJ_ARR_FUNC(JK_reduce, CfgTermo::Mlx, reduce, BOX_FID_TERMO_REDUCE)
ENTITY_END(AreaTermoMlx)

#define EntityAreaPedal \
  AOBJ_LIST(JK_type, CfgPedal::Pedal, typ, pedalTyp),                    \
  AOBJ_QNUM(JK_pull, CfgPedal::Pedal, pull, U16, 1, D),                  \
  AOBJ_QNUM(JK_push, CfgPedal::Pedal, push, U16, 1, D)
ENTITY_END(AreaPedal)

#define EntityAreaPid \
  AOBJ_QNUM(JK_kp, CfgPid::Pid, kp, U16, CONFIG_MAX_PID_kp, D),       \
  AOBJ_QNUM(JK_ki, CfgPid::Pid, ki, U16, 1. / CONFIG_MAX_PID_ki, M),  \
  AOBJ_QNUM(JK_limI, CfgPid::Pid, limI, U16, CONFIG_MAX_PID_limI, D), \
  AOBJ_QNUM(JK_lim, CfgPid::Pid, lim, U16, CONFIG_MAX_PID_lim, D)
ENTITY_END(AreaPid)

#define EntityAreaTleOut \
  AOBJ_LIST(JK_source, CfgTle::Dout, src, tleSrc), \
  AOBJ_INUM(JK_on, CfgTle::Dout, on, S16),         \
  AOBJ_INUM(JK_off, CfgTle::Dout, off, S16)
ENTITY_END(AreaTleOut)

struct Areas {
  u8 entityAreaTermoAdc[2 + sizeof(concat(body, AreaTermoAdc))];
  u8 entityAreaTermoAdcPt[2 + sizeof(concat(body, AreaTermoAdcPt))];
  u8 entityAreaTermoMlx[2 + sizeof(concat(body, AreaTermoMlx))];
  u8 entityAreaPedal[2 + sizeof(concat(body, AreaPedal))];
  u8 entityAreaPid[2 + sizeof(concat(body, AreaPid))];
  u8 entityAreaTleOut[2 + sizeof(concat(body, AreaTleOut))];
} static const areas = {
  .entityAreaTermoAdc = WBVAL(sizeof(bodyAreaTermoAdc)), EntityAreaTermoAdc,
  .entityAreaTermoAdcPt = WBVAL(sizeof(bodyAreaTermoAdcPt)), EntityAreaTermoAdcPt,
  .entityAreaTermoMlx = WBVAL(sizeof(bodyAreaTermoMlx)), EntityAreaTermoMlx,
  .entityAreaPedal = WBVAL(sizeof(bodyAreaPedal)), EntityAreaPedal,
  .entityAreaPid = WBVAL(sizeof(bodyAreaPid)), EntityAreaPid,
  .entityAreaTleOut = WBVAL(sizeof(bodyAreaTleOut)), EntityAreaTleOut
};

 

Экземпляр struct Areas содержит тела всех таких массивов контейнеров. А главный массив контейнеров (containerObjCfg) имеет ссылки в нужных местах на члены Areas (ссылка - смещение (16бит) внутри Areas).

Share this post


Link to post
Share on other sites
В 02.12.2019 в 11:27, Forger сказал:

Это позволит заложить в саму прошивку правильную конвертацию старого формата настроек и нового.

Так и делаю. В блоке настроек есть поле "версия". По нему прошивка определяет, подходит ли ей текущий набор настроек. Если версия отличается - конвертирует. Один минус - невозможно без потери настроек поверх записать ПО с более старой версией блока. С этим боролся только в одном изделии, там во внешней флешке была организована FAT12 и настройки хранились в текстовом файле. Более старая версия просто вычитывала из этого файла только нужные ей настройки.

В 02.12.2019 в 12:03, pokk сказал:

А сам алгоритм конвертации примерно такой?

В ОЗУ создаю образ новых настроек со значениями по-умолчанию. Таким образом, одним вызовом memcpy() или приваиванием структуры все новые настройки получают значения по-умолчанию. Потом, вычитывая настройки из блока старой версии, заменяю ими одноименные в новом блоке. Далее, записываю этот новый блок на свое место во флеш. В случае несовпадения контрольной суммы блока настроек точно так же создаю образ в ОЗУ, одним вызовом memcpy() заполняю весь блок значениями по-умолчанию, переписываю во флеш.

 

Ой, блин. Опять вторую страницу не заметил.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now