Я хочу включить библиотеку в свой проект C++ (управляет светодиодными полосками RGB на малине Pi). Импорт библиотеки работает нормально, но у меня есть проблема с правильной инициализацией некоторых структур. Я довольно потерян там, где даже нашел правильный синтаксис, я много гуглеров, но не очень далеко.
Сначала я хочу получить пример приложения, который поставляется с библиотекой. См. Https://github.com/richardghirst/rpi_ws281x/blob/master/main.c.
Моя главная проблема в этом. Как мне сделать то, что делается ниже C++?
ws2811_t ledstring =
{
.freq = TARGET_FREQ,
.dmanum = DMA,
.channel =
{
[0] =
{
.gpionum = GPIO_PIN,
.count = LED_COUNT,
.invert = 0,
.brightness = 255,
},
[1] =
{
.gpionum = 0,
.count = 0,
.invert = 0,
.brightness = 0,
},
},
};
Способ инициализации имеет значение C и не компилируется ни в одном текущем стандарте C++. См.: Почему C++ 11 не поддерживает указанный список инициализаторов как C99? До сих пор я использовал только свои собственные структуры и никогда не использовал typedef, поэтому я просто путаю то, как здесь определяются структуры.
Таким образом определяется структура (ы), которая инициализируется выше. См. Https://github.com/richardghirst/rpi_ws281x/blob/master/ws2811.h
typedef struct
{
int gpionum; //< GPIO Pin with PWM alternate function
int invert; //< Invert output signal
int count; //< Number of LEDs, 0 if channel is unused
int brightness; //< Brightness value between 0 and 255
ws2811_led_t *leds; //< LED buffers, allocated by driver based on count
} ws2811_channel_t;
typedef struct
{
struct ws2811_device *device; //< Private data for driver use
uint32_t freq; //< Required output frequency
int dmanum; //< DMA number _not_ already in use
ws2811_channel_t channel[RPI_PWM_CHANNELS];
} ws2811_t;
Я пробовал это:
ws2811_led_t matrix[WIDTH][HEIGHT];
ws2811_channel_t channel0 = {GPIO_PIN,LED_COUNT,0,255,*matrix};
ws2811_t ledstring = {nullptr,TARGET_FREQ,DMA,channel0};
Это компилируется, но приводит к ошибке malloc, когда я нахожусь на самом деле "визуализировать" светодиодную полосу:
int x, y;
for (x = 0; x < WIDTH; x++)
{
for (y = 0; y < HEIGHT; y++)
{
cout << "LEDs size: " << (y * WIDTH) + x << endl;
ledstring.channel[0].leds[(y * WIDTH) + x] = matrix[x][y];
}
}
Результаты в этом сообщении об ошибке после завершения контура цикла:
malloc(): memory corruption (fast): 0x021acaa8
Вы должны использовать использование следующего инициализатора:
ws2811_t ledstring =
{
nullptr,
TARGET_FREQ,
DMA,
{
{ GPIO_PIN, 0, LED_COUNT, 255 },
{ 0 }
}
};
Эта строка
ledstring.channel[0].leds[(y * WIDTH) + x] = matrix[x][y];
почти наверняка является причиной повреждения памяти, поскольку это может произойти только при переполнении буфера или разыменовании недействительного (но не NULL) указателя.
Я вижу некоторые проблемы в этом коде
ws2811_channel_t channel0 = {GPIO_PIN,LED_COUNT,0,255,*matrix};
ws2811_t ledstring = {nullptr,TARGET_FREQ,DMA,channel0};
Во-первых, в инициализаторе для channel0
вы устанавливаете поле leds
на содержимое matrix[0][0]
а не на его адрес. Вы должны изменить окончательный инициализатор как просто matrix
.
Затем вы инициализируете channel0.leds
чтобы указать на matrix
двухмерного массива, но рассматривая ее как одномерный массив в ledstring.channel[0].leds[(y * WIDTH) + x]
. Вероятно, это должно быть ledstring.channel[0].leds[x][y]
.
Наконец, последний инициализатор для ledstring
должен быть {channel0}
для ясности. Это не большая проблема, но она позволяет вам инициализировать несколько записей в массиве.
channer0
может быть{GPIO_PIN,0,LED_COUNT,255,*matrix}
.channel1
. В C-кодеchannel
представляет собой массив из 2 элементов. Это намеренно?