Хобрук: Ваш путь к мастерству в программировании

Теневая копия структуры данных, хранящейся в EEPROM

Я использую ARM GCC для процессора STM32F105RC.
Теперь в моем приложении есть что-то вроде:

typedef struct
{
  uint16_t coinValue;
  uint8_t  minimumCoins;
} MIN_COIN_RENDERING;

typedef struct
{
  uint16_t coinValue;
  uint8_t  hopperType;
  uint8_t  motorDelay;
} CONFIG_HOPPER;

typedef struct
{
  MIN_COIN_RENDERING minCoinRendering[10];
  CONFIG_HOPPER hopper[5];
  uint8_t reservedFFU[X];
  //
  uint16_t crc;
} APPLICATION_CONFIG; // MUST have 128 bytes!

Первая проблема заключается в том, как правильно определить количество байтов, зарезервированных FFU (отмеченных выше X).
Если вы скажете: X = 128 - (10 x 3 + 5 x 4 + 2) = 76, ну, это неверно!
Правильное значение для X равно 66, потому что компилятор выравнивает поля в структурах (по крайней мере, с настройками компилятора по умолчанию).
Общая структура должна иметь 128 байтов. , так как он будет сохранен/восстановлен из EEPROM. Структура используется как теневая копия того, что у нас есть в EEPROM...

Мой вопрос: есть ли способ (лучший, гибкий) иметь теневую копию (для EEPROM) без необходимости возиться с размером зарезервированного FFU каждый раз, когда я добавляю новое поле (или что-то меняю) в структуре APPLICATION_CONFIG?

23.10.2015

Ответы:


1

Тот факт, что вам нужно что-то фиксированного размера с данными с определенными смещениями, очень похоже на то, что вы хотите что-то частично структурированное, частично массивное. Если вы готовы относиться к CRC немного по-другому, почему бы не сделать именно это!

typedef union
{
  struct {
    MIN_COIN_RENDERING minCoinRendering[10];
    CONFIG_HOPPER hopper[5];
  };
  uint16_t raw[64];
} APPLICATION_CONFIG;

// Then e.g.
APPLICATION_CONFIG config;
config.hopper[3].motorDelay = 7; // Thanks to anonymous structures
uint16_t *crcptr = &config.raw[63];
23.10.2015
  • UP :) ... и я держу пари, что есть причудливый способ включить uint16_t CRC в необработанную часть этого объединения, правильно? 23.10.2015
  • Что ж, идея struct { uint16_t data[63]; uint16_t crc; } действительно приходит в голову, но я чувствую себя грязным, предлагая ее... 23.10.2015
  • Почему? Какой-нибудь недостаток, связанный с этим?... или что-то еще, что я упускаю? 24.10.2015
  • Я думал о struct { uint8_t data[126]; uint16_t crc; }, поскольку функция CRC обычно запрашивает байтовый * блок данных, так что это было бы удобно. В противном случае, я полагаю, потребуется кастинг... 24.10.2015
  • Бля, как я не подумал об этом? - это немного яснее и менее ужасно. Просто будьте осторожны, не спускайтесь по скользкой дорожке, ведущей к такие вещи ;) 24.10.2015

  • 2

    Просто напишите что-то вроде этого:

    typedef struct
    {
        MIN_COIN_RENDERING minCoinRendering[10];
        CONFIG_HOPPER hopper[5];
    } APPLICATION_CONFIG;
    
    typedef struct
    {
        APPLICATION_CONFIG config;
        uint8_t reserved[128 - sizeof(APPLICATION_CONFIG) - 2];
        uint16_t crc;
    } EEPROM_LAYOUT;
    
    23.10.2015
  • Несмотря на то, что на практике это маловероятно, я думаю, что компилятор все еще технически имеет право заставить EEPROM_LAYOUT переполнить 128 байт и поместить crc в неправильное место - стандарт C99 просто говорит, что внутри может быть безымянное заполнение. объекта структуры, но не в его начале., в отдельном предложении от В конце структуры или объединения может быть безымянный отступ. 23.10.2015
  • между зарезервированными [] и crc могут быть байты выравнивания, так что это не совсем надежный метод. Предложите использовать offsetof() (аналогично sizeof), чтобы получить точное местоположение поля в структуре. Предложите использовать unions, где один элемент равен 128 байтам, чтобы установить расположение полей в структуре. 24.10.2015
  • @user3629249 user3629249: Очень полезный комментарий, но, пожалуйста, не могли бы вы немного рассказать об использовании offsetof() для получения точного местоположения поля...? Я имею в виду, как именно это поможет? ТИА. 25.10.2015

  • 3

    Первая проблема заключается в том, как правильно определить количество байтов, зарезервированных FFU (отмечено выше знаком X).

    Как вы сами упомянули о том факте, что компилятор выравнивает поля в структуре и что на самом деле определяется реализацией, вам необходимо обязательно просмотреть настройки компилятора, чтобы выяснить, как именно он выравнивает данные. Возможно, в нем есть некоторые операторы для изменения настроек выравнивания структуры (я не копался достаточно глубоко в ARM GCC, чтобы сказать это наверняка).

    Мой вопрос: есть ли способ (лучший, гибкий) иметь теневую копию (для EEPROM) без необходимости возиться с размером зарезервированного FFU каждый раз, когда я добавляю новое поле (или что-то меняю) в структуре APPLICATION_CONFIG?

    К сожалению, я не могу дать прямой ответ на этот вопрос. С моей точки зрения, это зависит от решения первой части вашего вопроса.

    23.10.2015
    Новые материалы

    Получение стоковых обновлений с помощью Python
    Для начинающего финансового аналитика Введение Описание: Этот проект Python создает скрипт для получения текущих обновлений акций с финансового веб-сайта Yahoo. Для этого проекта мы..

    Это все, что вам нужно знать о Kotlin в 2022 году
    Добро пожаловать! Kotlin — это язык программирования, популярность которого, кажется, растет, его действительно можно использовать для создания чего угодно, и если вы хотите узнать о Kotlin,..

    Текстовый графический интерфейс с Lanterna на Java
    Мой опыт работы с компьютерами (и текстовыми графическими пользовательскими интерфейсами) начался еще в восьмидесятых, когда я был ребенком, на дне рождения друга. Это был «новенький» Amstrad..

    Перезарядите свой мозг: умопомрачительный потенциал мозговых компьютерных интерфейсов
    Способность читать свои мысли и управлять объектами разумом долгое время были предметом человеческого любопытства, ограниченного областью научной фантастики… то есть до сих пор? С технологией,..

    Основы C# — Нулевой оператор объединения (??)
    Оператор ?? называется null-coalescing operator . Этот оператор используется для предоставления значения по умолчанию, если значение операнда в левой части оператора равно null ...

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

    В мир искусственного интеллекта…
    ИИ — это новое топливо в современном мире. Куда бы вы ни обратились, с кем бы вы ни разговаривали — они, как правило, упоминают об ИИ хотя бы раз в ходе разговора. ИИ гудит повсюду. У каждого..