У меня проблемы с получением программы SPI, над которой я работаю, чтобы вести себя корректно, и, похоже, это проблема макроса SPI_IOC_MESSAGE (N).
Вот пример кода, который НЕ РАБОТАЕТ (ioctl возвращает EINVAL (22)):
std::vector<spi_ioc_transfer> tr;
<code that fills tr with 1+ transfers>
// Hand the transmission(s) off to the SPI driver
if (tr.size() > 0)
{
int ret = ioctl(fd, SPI_IOC_MESSAGE(tr.size()), tr.data());
if (ret < 1)
{
int err = errno;
}
}
Мой тестовый код сейчас создает вектор длиной 1.
Если я явно изменю код на:
int ret = ioctl(fd, SPI_IOC_MESSAGE( 1 ), tr.data());
…тогда ioctl (…) преуспевает, и мои биты идут по трубе.
Глядя на расширение макроса SPI_IOC_MESSAGE в Eclipse, я не понимаю, почему это не радует.
Предложения?
Я кросс-компилирую для Linux / ARM (Beaglebone Black) с 64-битной виртуальной машины Linux, но я не вижу, что это влияет на макрос.
РЕДАКТИРОВАТЬ:
Вот два расширения макроса из препроцессора C
int ret = ioctl(fd, (((1U) << (((0 +8)+8)+14)) | ((('k')) << (0 +8)) | (((0)) << 0) | ((((sizeof(char[((((tr.size())*(sizeof (struct spi_ioc_transfer))) < (1 << 14)) ? ((tr.size())*(sizeof (struct spi_ioc_transfer))) : 0)])))) << ((0 +8)+8))), tr.data());
и буквальное:
int ret = ioctl(fd, (((1U) << (((0 +8)+8)+14)) | ((('k')) << (0 +8)) | (((0)) << 0) | ((((sizeof(char[((((1)*(sizeof (struct spi_ioc_transfer))) < (1 << 14)) ? ((1)*(sizeof (struct spi_ioc_transfer))) : 0)])))) << ((0 +8)+8))), tr.data());
Абсолютно отвратительно, но я не вижу ничего удивительного в том, как tr.size()
будет привыкать там.
Изменить, чтобы включить то, что кажется ответом
#ifdef __cplusplus /* If this is a C++ compiler, use C linkage */
extern "C" {
#endif
#include <linux/spi/spidev.h>
#ifdef __cplusplus /* If this is a C++ compiler, use C linkage */
}
#endif
Обертывание включаемого файла linux SPI в «extern C» дает системе команду относиться к этому разделу как к простому старому C, и это, кажется, позволяет мне вызывать SPI_IOC_MESSAGE( tr.size() )
или же SPI_IOC_MESSAGE( an_int )
и иметь правильную вещь происходит (проверено с помощью пошагового руководства GDB и анализатором сигналов).
Я подозреваю, что проблема может заключаться в этом конкретном самородке, похороненном в макросе:
...sizeof(char[...tr.size()...])...
Отмечая, что код Linux является исключительно C, стандарт C (у меня здесь есть проект C99 n1256) гласит: sizeof
оператор, операнд выражения невычисленного, и результат является константой, если тип операнда является массивом переменной длины, в этом случае он оценивается, а результатом является целое число.
Однако стандарт C ++ (C ++ 11 черновик n3242), по-видимому, не дает каких-либо условий, при которых оценивается операнд, а только утверждает, что результат является константой.
Таким образом, похоже, что это может быть одним из углов, где C и C ++ различаются, и компиляция одного из них приводит к неопределенному поведению. В этом случае, я думаю, что выбор заключается либо в том, чтобы просто взломать вашу собственную версию макроса, либо иметь отдельную внешнюю функцию C, которая обертывает ее.