Как вытащить массив, вложенный в структуру?

А вы его компилировать пробовали? В ардуино ИДЕ?

Извините, компилируется, мой косяк, криво скопировал/вставил

по моему ответ уже дали

Блин, тут просто детская, школьная ошибка в адресной арифметике! Зачем рассказывать про то, что где-то такое работает?

void my_func(uint32_t *para, size_t para_num) {
  uint8_t regval;
  for(uint8_t i=0; i<para_num; i++) {
    regval = *(uint8_t *)para;
    Serial.print(regval, HEX);
    Serial.println("\r");
    para++;
  }

В строке #7 Вы увеличиваете на 1 указатель на uint32_t . На сколько но, по Вашему, численно увеличится? На 4! Вот Вы это и кушаете с маслом.

Сделайте правильно и “забудьте о перхоти”

void my_func(uint32_t *para, size_t para_num) {
  const uint8_t * bPara = reinterpret_cast<const uint8_t *>(para);
  // можно и как Вы делаете
  //	 const uint8_t * bPara = (const uint8_t *) para;
  // но так, как я написал - лучше
  for(uint8_t i=0; i<para_num; i++) {
    const uint8_t regval = bPara[i];
    Serial.println(regval, HEX);
  }
}
2 лайка

Он не в обратном порядке выводит, а с шагом в 4 байта. Первое значение, потом пятое, а затем просто по не пойми какой памяти проезжаетесь, и там нули с единицей.

У вас в коде проблемы из-за плохой работы с типами, а из-за нее - с указателями. Я же вам выше написал.

Компилятор вас предупреждает, как может.

Уберите void *, уберите unsigned long *, оставьте везде unsigned char, ну или uint8_t. Вы работаете с байтами, не нужны вам эти кошмарные преобразования типов кругом. С преобразованиями типов впрямую надо быть аккуратным:

void setup() {
  Serial.begin(9600);

  my_func((uint8_t *)(init_cmd[0].data), init_cmd[0].data_bytes);

}

Кому как. ТСу, похоже, нельзя.

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

typedef struct {
    int cmd;
    const uint8_t *data;
    size_t data_bytes;
    unsigned int delay_ms;
} st7701_lcd_init_cmd_t;

static const st7701_lcd_init_cmd_t init_cmd[] = {
    {0xFF, (uint8_t []){0x77, 0x01, 0x00, 0x00, 0x13}, 5, 0},
    {0xEF, (uint8_t []){0x08}, 1, 0},
    {0xFF, (uint8_t []){0x77, 0x01, 0x00, 0x00, 0x10}, 5, 0},
    {0xC0, (uint8_t []){0x2c, 0x00}, 2, 0},
    {0xC1, (uint8_t []){0x10, 0x0C}, 2, 0},
    {0xC2, (uint8_t []){0x21, 0x0A}, 2, 0},
};

void setup() {
  Serial.begin(9600);

  // Находим размер (количество "командо-строк") структуры данных инита
  // Бывают иниты по 400-500 и более команд, поэтому с запасом
  uint16_t init_cmd_size = sizeof(init_cmd) / sizeof(st7701_lcd_init_cmd_t);

  for(uint16_t i=0; i<init_cmd_size; i++) {
    my_func(init_cmd[i].cmd, (uint32_t *)(init_cmd[i].data), init_cmd[i].data_bytes);
  }
}

void loop() {

}

void my_func(uint8_t cmds, uint32_t *para, size_t para_num) {
  const uint8_t * bPara = reinterpret_cast<const uint8_t *>(para);
  // сюда вставляем отправку команды cmds
  for(uint8_t i=0; i<para_num; i++) {
    const uint8_t regval = bPara[i];
    // Сюда вставляем отправку байтов инита regval в устройство по нужному интерфейсу
    Serial.println(regval, HEX); 
  }
}

Если вдруг кому-то непонятно, зачем головная боль с этими структурами и массивами переменной длины, вот так выглядит фрагмент найденного в сети кода инициализации дисплея “в лоб”:

GP_COMMAD_PA(20);
  SPI_WriteData(0x53);
  SPI_WriteData(0x1F);
  SPI_WriteData(0x19);
  SPI_WriteData(0x15);
  SPI_WriteData(0x11);
  SPI_WriteData(0x11);
  SPI_WriteData(0x11);
  SPI_WriteData(0x12);
  SPI_WriteData(0x14);
  SPI_WriteData(0x15);
  SPI_WriteData(0x11);
  SPI_WriteData(0x0D);
  SPI_WriteData(0x0B);
  SPI_WriteData(0x0B);
  SPI_WriteData(0x0D);
  SPI_WriteData(0x0C);
  SPI_WriteData(0x0C);
  SPI_WriteData(0x08);
  SPI_WriteData(0x04);
  SPI_WriteData(0x00);

  GP_COMMAD_PA(20);
  SPI_WriteData(0x54);
  SPI_WriteData(0x1F);
  SPI_WriteData(0x19);
  SPI_WriteData(0x15);
  SPI_WriteData(0x11);
  SPI_WriteData(0x11);
  SPI_WriteData(0x11);
  SPI_WriteData(0x13);
  SPI_WriteData(0x15);
  SPI_WriteData(0x16);
  SPI_WriteData(0x11);
  SPI_WriteData(0x0D);
  SPI_WriteData(0x0C);
  SPI_WriteData(0x0C);
  SPI_WriteData(0x0E);
  SPI_WriteData(0x0C);
  SPI_WriteData(0x0C);
  SPI_WriteData(0x08);
  SPI_WriteData(0x04);
  SPI_WriteData(0x00);

В общей сложности более 500 строк. Не, я уж лучше день потрачу на ковыряние в структурах, зато потом будет красивый и удобный многоразовый шаблон.

По уму надо такой указатель на массив делать последним полем структуры.

Пуркуа? Следом опять идет такой же элемент структуры. Если начнется беспредел, то порубит его.

У нас тут принято, не себе любимому галку ставить “Вопрос решен”, а все таки человеку, чей пост помог вам решить проблему.

Исправил.

1 лайк

Мне другое непонятно - если вам уже показали вашу ошибку с типами данных, почему опять в функции my_func

указатель на дата у вас имеет тип uimt32*?
Нахрена использовать неверный тип, а потом делать каст?

Решение “в лоб” через пятьсот строк имеет преимущество что оно простое и понятное.
Лобовое решение можно было бы улучшить, записав 500 значений в массив в Прогмем и читая его в цикле. Этого было бы вполне достаточно.

А когда подобный вам новичок начинает придумывать " удобные шаблоны", при этом путая элементарные типы данных, получается никому не нужная заумь.

1 лайк

Потому что а) я копировал начальное решение из другого источника, где так было, б) в сообщении #24 мне так было указано, дословно: Сделайте правильно и “забудьте о перхоти”. И далее именно этот фрагмент кода с кастом. Согласен, отвечавший пропустил этот момент (и не обязан), я тоже не обратил внимание в радости, что заработало. Бывает. Собственно, вся эта тема результат моего бездумного дерганья кода из косячных источников, в надежде слепить по-быстрому.

Я портирую куски чужого кода с другой платформы, там нет прогмем. Зато есть необъяснимые ляпы, как оказалось. Но предлагать новичку сознательно примитизировать решения вместо того, чтобы спотыкаться, набивать шишки и нарабатывать свою базу кода - неправильно, по-моему.

Для того что бы на куче одним куском выделить место под структуру с заранее не известным размером буфера…

С какого это бодуна я его пропустил? Отлично видел. Просто решал проблему минимальным воздействием на код. Всё, что можно не трогать - не трогал. Откуда мне знать, что там у Вас ещё в коде, может Вам зачем-нибудь реально нужен такой тип (вполне могу себе представить реальные причины для этого).

Более того, это далеко не единственная “странность” в Вашем коде, которую я “пропустил”. Вы, похоже, вообще большой любитель собственноручно раскладывать грабли а потом пытаться их обойти по тонкому льду. Но Вы не просили такого анализа, я и не лезу с ним.

2 лайка

А это вообще бред. У вас размер каждой команды разный и не равен размеру структуры.
Как результат, в последующем цикле вы почти наверняка вылезаете за границы массива.

Ей богу, тупые 500 строк явно были лучше, чем ваша оптимизация с кучей грубейших ошибок.

Не понял о чём Вы. Размер структуры st7701_lcd_init_cmd_t всегда 8 байтов. Массив data живёт совершенно отдельно (в структуре только указатель на его нулевой элемент). В чём проблема, чтобы перебрать массив структур таким образом?

“по-быстрому”, говорите.

  • засеките время.
  • наберите в текстовом редакторе “мама мыла раму”.
  • посмотрите, сколько времени это заняло.
    А теперь возьмите ножницы, клей и старую газету.
  • засеките время.
  • сделайте такую же надпись из букв, вырезанных из газеты.
    Намного быстрее получилось?

Да, ошибся.