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

查看:86
本文介绍了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

将 linux SPI 包含文件包装在extern C"中指示系统将该部分视为普通的旧 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天全站免登陆