SPI_IOC_MESSAGE(N)宏适合我 [英] SPI_IOC_MESSAGE(N) macro giving me fits

查看:2160
本文介绍了SPI_IOC_MESSAGE(N)宏适合我的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我无法正常工作的SPI程序无法正常运行,并且SPI_IOC_MESSAGE(N)宏似乎存在一些问题.

I'm having trouble getting a SPI program I'm working on to behave correctly and it seems to be some issue with the SPI_IOC_MESSAGE(N) macro.

这是不起作用的示例代码(ioctl返回EINVAL(22)):

Here's sample code that DOESN'T work (ioctl returns 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的向量. 如果我将代码明确更改为:

My test code right now is creating a vector of length 1. If I explicitly change the code to:

int ret = ioctl(fd, SPI_IOC_MESSAGE( 1 ), tr.data());

...然后ioctl(...)成功执行,我的任务掉了下来. 看着Eclipse中SPI_IOC_MESSAGE宏的扩展,我不明白为什么这不满意.

...then ioctl(...) succeeds and my bits go down the pipe. Looking at the expansion of the SPI_IOC_MESSAGE macro in Eclipse, I don't see why this isn't happy.

建议?

我正在从64位Linux VM交叉编译Linux/ARM(Beaglebone Black),但是我看不到这会影响宏.

I'm cross-compiling for Linux/ARM (Beaglebone Black) from a 64-bit Linux VM, but that I can't see that affecting the macro.

这是C预处理程序的两个宏扩展

Here are the two macro expansions out of the C pre-processor

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()那里如何使用它,我并不感到惊讶.

Absolutely hideous, but I don't see anything surprising in how tr.size() would be getting used there.

编辑以包含似乎是答案的答案

#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

在"extern C"中包装linux SPI include文件,指示系统将该部分视为普通的旧C,这似乎让我调用SPI_IOC_MESSAGE( tr.size() )SPI_IOC_MESSAGE( an_int )并发生了正确的事情(已验证GDB逐步调试和信号分析器).

Wrapping the linux SPI include file in an "extern C" instructs the system to treat that section as plain old C, and that seems to let me call SPI_IOC_MESSAGE( tr.size() ) or SPI_IOC_MESSAGE( an_int ) and have the correct thing happen (verified with GDB stepthrough and a signal analyzer).

推荐答案

我怀疑问题可能出在宏汤中埋藏的这个特殊的金块中:

I suspect the problem might lie in this particular nugget buried in the macro soup:

...sizeof(char[...tr.size()...])...

注意到Linux代码是唯一的C,C标准(这里有C99草案n1256)对sizeof运算符指出,表达式操作数是未求值的,结果是一个常数, 除非,操作数的类型是可变长度数组,在这种情况下,将对其求值并且结果是整数.

Noting that Linux code is exclusively C, the C standard (I have C99 draft n1256 here) states for the sizeof operator that an expression operand is unevaluated, and the result is a constant, unless the type of the operand is a variable-length array, in which case it is evaluated and the result is an integer.

但是,C ++标准(C ++ 11草案n3242)似乎没有给出任何条件来评估操作数,而仅说明结果是常量.

The C++ standard (C++11 draft n3242), however, does not seem to give any condition under which the operand is evaluated, and only states the result is a constant.

因此,这似乎可能是C和C ++不同的角落之一,将它们编译在一起会导致不确定的行为.在那种情况下,我认为选择要么是破解自己的宏版本,要么是使用单独的外部C函数对其进行包装.

Thus it looks like this may be one of the corners where C and C++ differ, and compiling one as the other leads to undefined behaviour. In that case, I think the choice is either just hacking up your own version of the macro, or having a separate external C function that wraps it.

这篇关于SPI_IOC_MESSAGE(N)宏适合我的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆