Skip to content

incompatible i2c_t types #24

@mikafreiwald

Description

@mikafreiwald

When trying to generate bindings for the bmx280 device driver, I noticed that the size of the struct bmx280_params_t differs from C to Rust. I used the module USEMODULE += bmp280_i2c and added these lines to rust-riot-sys/riot-headers.h to generate the bindings:

#include "bmx280.h"
#include "bmx280_params.h"

The struct contains an i2c_dev of type i2c_t which seems to be the reason for the difference. I used the following programs to print the sizes. In C:

#include <stdio.h>
#include <bmx280.h>
int main(void) {
    printf("sizeof bmx280_params_t = %d\n", sizeof(bmx280_params_t));
    printf("sizeof i2c_t = %d\n", sizeof(i2c_t));
}
sizeof bmx280_params_t = 32
sizeof i2c_t = 4

In Rust:

use riot_wrappers::{println, riot_main};
use riot_sys::{bmx280_params_t, i2c_t};
use core::mem::size_of;
riot_main!(main);
fn main() {
    println!("sizeof bmx280_params_t = {}", size_of::<bmx280_params_t>());
    println!("sizeof i2c_t = {}", size_of::<i2c_t>());
}
sizeof bmx280_params_t = 28
sizeof i2c_t = 1

In the file RIOT/drivers/include/periph/i2c.h the type is defined as follows:

#ifndef HAVE_I2C_T
typedef uint_fast8_t i2c_t;
#endif

For native, xtensa, risc-v and arm, it seems like all the fast integer types are defined through internal compiler defines like typedef __INT_FAST8_TYPE__ int_fast8_t; These types differ since RIOT is compiled by gcc and the Rust bindings are created with llvm. I did some tests and got the following types using different architectures. The cells show the actual type when using gcc / clang:

Bit Native (x86-64) Xtensa RISC-V ARM
8 char / char int / char int / char int / char
16 long int / short int / short int / short int / short
32 long int / int int / int int / int int / int
64 long int / long int long long int /
long long int
long long int /
long long int
long long int /
long long int

One workaround is to redefine these macros when generating the bindings so that they match the types used by gcc. For the uint_fast8_t this can be done by adding the following lines to riot-bindgen.h and riot-c2rust.h:

#undef __UINT_FAST8_TYPE__
#define __UINT_FAST8_TYPE__ unsigned int

Alternatively, this also works:

#define HAVE_I2C_T
typedef unsigned int i2c_t

However there should be a better way that actually guarantees that the same type is used when compiling RIOT and creating the bindings.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions