如何将N个字节的参数传递给指针调用的函数

时间:2015-04-01 16:09:28

标签: c embedded parameter-passing function-pointers

我的软件驱动一个在TI DSP TMS320f2812上运行C代码的嵌入式设备。

通过USB串口仿真完成通信。

在某些时候,在设备方面,我需要解析一条消息,这意味着"用给定的参数调用给定地址的函数"。 该消息包含:

    函数地址的
  • 4 字节。
  • 参数(s)大小的
  • 1 字节(以字节为单位)。
  • 参数(s)数据的
  • n 字节。

这里是我目前使用的代码:

typedef void    (*void_fct_void)    (void);
typedef void    (*void_fct_int16)   (int16);
typedef void    (*void_fct_int32)   (int32);
typedef void    (*void_fct_2int32)  (int32, int32);

...

Uint32 address;
Uint16 sizeIn;

address = HW_Usb_Read_4Bytes();
sizeIn = HW_Usb_Read_1Byte();

switch(sizeIn) {
    case 0:
        ((void_fct_void) address)();
        break;              
    case 2:
        ((void_fct_int16) address)(HW_Usb_Read_2Bytes());
        break;
    case 4:
        ((void_fct_int32) address)(HW_Usb_Read_4Bytes());
        break;
    case 8:
        ((void_fct_2int32) address)(HW_Usb_Read_4Bytes(), HW_Usb_Read_4Bytes());
        break;
}

我想知道是否有办法让它更通用并避免切换,例如:

Uint32 address;
Uint16 sizeIn;

address = HW_Usb_Read_4Bytes();
sizeIn = HW_Usb_Read_1Byte();

putNbytesOnParamsStack(sizeIn); // magic function, will call HW_Usb_Read_1Byte 'sizeIn' times.
((void_fct_void) address)();

目标函数也很多并且嵌入代码使用,我无法更改其签名。

3 个答案:

答案 0 :(得分:1)

您可以使用libffi(如果它支持您的目标处理器体系结构,调用约定和ABI),这使您能够模拟"一个arbirary电话。

但是,您应该传递指向数据的指针,而不是数据本身。

答案 1 :(得分:0)

可以使用内联汇编在堆栈上推送var:

__asm {
    push sizeIn
    ; You can also call your fp using asm:
    call address
    ; But it's not very safe because your compiler may not 
    ; have saved its registries before the call
}

但是我想知道推sizeIn如何帮助你,你不需要推动HW_Usb_Read_NBytes()的结果吗?


编辑:

通过多次调用HW_Usb_Read_1Byte()并按位操作,您可以删除开关案例。

int32 param = 0;
for (int i = 0; i < sizeIn; i++)
   param |= (HW_Usb_Read_1Byte() << (i * 8));

每次迭代得到的字节向左移动了我们到目前为止读取的位数,并附加到整数。

然而,这仅在读取的数据来自小端系统时才有效。如果您的API为每种数据大小提供方法,则情况可能并非如此。

答案 2 :(得分:0)

正如Riley Avron所说,使用一些汇编代码是一种解决方案。

为此我需要知道如何接口C和汇编语言 用我使用的DSP。

这称为Calling convention。我找不到关于它的文档,this one与TMS320系列有关,但与FPU有关,而TMS320f2812并非如此。

我记得我使用的代码编辑工作室版本允许在连接JTAG时混合源代码和ASM代码。

这是我在当前代码中看到的内容:

// Case 0:
MOVL    XAR7,@XAR2          ; put address in XAR7
LCR     *XAR7               ; call the function
...

// Case 1:
LCR     HW_Usb_Read_2Bytes  ; get the data
MOVL    XAR7,@XAR2          ; put address in XAR7
LCR     *XAR7               ; call the function
...

// Case 2:
LCR     HW_Usb_Read_4Bytes  ; get the data
MOVL    XAR7,@XAR2          ; put address in XAR7
LCR     *XAR7               ; call the function
...

我们可以看到,对HW_Usb_Read_{2|4}Bytes的调用所收回的数据未被处理。我想被调用的函数会将它放在已放置的堆栈中。

正如我所说,HW_Usb_Read_4Bytes只拨打HW_Usb_Read_2Bytes两次,并从两个UInt32撰写UInt16

TMS320C28x具有RPT (§2.5.3)操作,允许执行单个指令倍数。

我们可以想象这样的解决方案:

RPT #N−1                        ; Where #N is sizeIn/2
||LCR     HW_Usb_Read_2Bytes    ; get the data
MOVL    XAR7,@XAR2              ; put address in XAR7
LCR     *XAR7                   ; call the function

实际上有一些限制要做到这一点:

  • 我不知道如何确保address位于XAR2
  • 数据字节序是否适用于多参数情况?