I building a python package which will require wrapping many third-party C libraries. For numerous reasons, I have decided to use Cython. The first vendor API is quite large and contains many complex definitions, and so far most were ok. I am having trouble with one struct within a vendors .h, which is structured (conceptually) like so:

typedef struct {                                                                         
  unsigned int blah;
  union {
    struct {
      unsigned int a;
      unsigned char b;
      ...
    } s1;
    struct {
      unsigned int  a;   
      unsigned char b;
      ...
    } s2;
    struct {
      unsigned int  blah; 
      ...             
    } s3;
    struct {
      unsigned short blah
      ...
      union {
        struct {
          unsigned int a;
          unsigned int c;
          ...
        } tx;
        struct {
          unsigned int a;
          unsigned int c;
          ...
        } rx;
        unsigned char raw[24];
      } u1;
    } s5;
    ...
  } main_union;
} hw_params; 

typedef struct hw_config{
          ...
          hw_params         params;
          ...                   

        } HW_CONFIG;

typedef HW_CONFIG hwConfig;
typedef HW_CONFIG *phwConfig; 

typedef struct s_config {
          ...
          hwConfig hcfgs[...];
        } SYS_CONFIG;

typedef SYS_CONFIG XLdriverConfig;
typedef SYS_CONFIG *pXLdriverConfig;

I have seen and played with different suggestions with varying success.

  • Flatting out the whole struct definition: I have issues because of variables of the same name (highlighted by a, b, and c above)
  • cdef all structs and unions individually and then compose them: This has so far been the best approach and depending on my use within the .pxy, I have been able to successfully build and test some variables of the structure, after values are set by a .c API function. I tried both declaring s1, s2, etc outside of my extern section cdef extern from r"bin\vendor.h":, with just the SYS_CONFIG typedef within cdef extern from r"bin\vendor.h", and also made attempts with all definitions within cdef extern from r"bin\vendor.h":. Common example: enter image description here

My question is: What is the best approach for cases like this? It doesn't have to be a solution that provides the exact definition in .pxd, but could also be 'write an interface to lib in pure c then write pxd around that (hopefully simplifying)'

This question can probably be removed, but in case it does help someone, the issue I was having was more to do with use with .pyx. The image and commonly suggested approach worked for me in the end with some trial and error. The following is the complete c struct to .pxd conversion.

cdef extern from r"bin\vxlapi.h":

    cdef struct _canFD:
        unsigned int  arbitrationBitRate     # CAN bus timing for nominal / arbitration bit rate
        unsigned char sjwAbr
        unsigned char tseg1Abr
        unsigned char tseg2Abr
        unsigned char samAbr  # 1 or 3
        unsigned char outputMode
        unsigned char sjwDbr                 # CAN bus timing for data bit rate 
        unsigned char tseg1Dbr
        unsigned char tseg2Dbr
        unsigned int  dataBitRate
        unsigned char canOpMode

    cdef struct _most:
        unsigned int  activeSpeedGrade
        unsigned int  compatibleSpeedGrade
        unsigned int  inicFwVersion

    cdef struct _flexray:
        # status and cfg mode are part of xlFrGetChannelConfiguration, too 
        unsigned int  status                 # XL_FR_CHANNEL_CFG_STATUS_xxx 
        unsigned int  cfgMode                # XL_FR_CHANNEL_CFG_MODE_xxx 
        unsigned int  baudrate               # FlexRay baudrate in kBaud 

    cdef struct _ethernet:
        unsigned char macAddr[6] # MAC address (starting with MSB!)
        unsigned char connector  # XL_ETH_STATUS_CONNECTOR_xxx
        unsigned char phy        # XL_ETH_STATUS_PHY_xxx
        unsigned char link       # XL_ETH_STATUS_LINK_xxx
        unsigned char speed      # XL_ETH_STATUS_SPEED_xxx
        unsigned char clockMode  # XL_ETH_STATUS_CLOCK_xxx
        unsigned char bypass     # XL_ETH_BYPASS_xxx

    cdef struct _tx:
        unsigned int bitrate
        unsigned int parity
        unsigned int minGap

    cdef struct _rx:
        unsigned int bitrate
        unsigned int minBitrate
        unsigned int maxBitrate
        unsigned int parity
        unsigned int minGap
        unsigned int autoBaudrate

    cdef union _dir:
        _tx tx
        _rx rx
        unsigned char raw[24]


    cdef struct _a429:
        unsigned short channelDirection
        unsigned short res1
        _dir dir

    cdef struct _can:
        unsigned int bitRate
        unsigned char sjw
        unsigned char tseg1
        unsigned char tseg2
        unsigned char sam  # 1 or 3
        unsigned char outputMode
        unsigned char reserved[7]
        unsigned char canOpMode


    cdef union _data:
        _can can
        _canFD canfd
        _most most
        _flexray flexray
        _ethernet ethernet
        _a429 a429
        unsigned char raw[28]

    ctypedef struct XLbusParams:                                                                         
        unsigned int busType
        _data data

    ctypedef struct XL_CHANNEL_CONFIG:
        char                name [32]
        unsigned char       hwType                               # HWTYPE_xxxx (see above)
        unsigned char       hwIndex                              # Index of the hardware (same type) (0,1,...)
        unsigned char       hwChannel                            # Index of the channel (same hardware) (0,1,...)
        unsigned short      transceiverType                      # TRANSCEIVER_TYPE_xxxx (see above)
        unsigned short      transceiverState                     # transceiver state (XL_TRANSCEIVER_STATUS...)
        unsigned short      configError                          # XL_CHANNEL_CONFIG_ERROR_XXX (see above)
        unsigned char       channelIndex                         # Global channel index (0,1,...)
        unsigned long long  channelMask                          # Global channel mask (=1<<channelIndex)
        unsigned int        channelCapabilities                  # capabilities which are supported (e.g CHANNEL_FLAG_XXX)
        unsigned int        channelBusCapabilities               # what buses are supported and which are possible to be 
                                                                # activated (e.g. XXX_BUS_ACTIVE_CAP_CAN)

        # Channel          
        unsigned char       isOnBus                              # The channel is on bus
        unsigned int        connectedBusType                     # currently selected bus      
        XLbusParams         busParams
        unsigned int        _doNotUse                            # introduced for compatibility reasons since EM00056439

        unsigned int        driverVersion            
        unsigned int        interfaceVersion                     # version of interface with driver
        unsigned int        raw_data[10]

        unsigned int        serialNumber
        unsigned int        articleNumber

        char                transceiverName [32]  # name for CANcab or another transceiver

        unsigned int        specialCabFlags                      # XL_SPECIAL_CAB_XXX flags
        unsigned int        dominantTimeout                      # Dominant Timeout in us.
        unsigned char       dominantRecessiveDelay               # Delay in us.
        unsigned char       recessiveDominantDelay               # Delay in us.
        unsigned char       connectionInfo                       # XL_CONNECTION_INFO_XXX
        unsigned char       currentlyAvailableTimestamps         # XL_CURRENTLY_AVAILABLE_TIMESTAMP...
        unsigned short      minimalSupplyVoltage                 # Minimal Supply Voltage of the Cab/Piggy in 1/100 V
        unsigned short      maximalSupplyVoltage                 # Maximal Supply Voltage of the Cab/Piggy in 1/100 V
        unsigned int        maximalBaudrate                      # Maximal supported LIN baudrate
        unsigned char       fpgaCoreCapabilities                 # e.g.: XL_FPGA_CORE_TYPE_XXX
        unsigned char       specialDeviceStatus                  # e.g.: XL_SPECIAL_DEVICE_STAT_XXX
        unsigned short      channelBusActiveCapabilities         # like channelBusCapabilities (but without core dependencies)
        unsigned short      breakOffset                          # compensation for edge asymmetry in ns 
        unsigned short      delimiterOffset                      # compensation for edgdfde asymmetry in ns 
        unsigned int        reserved[3]

    ctypedef XL_CHANNEL_CONFIG  XLchannelConfig
    ctypedef XL_CHANNEL_CONFIG  *pXLchannelConfig

    ctypedef struct XL_DRIVER_CONFIG:
        unsigned int      dllVersion
        unsigned int      channelCount  # total number of channels
        unsigned int      reserved[10]
        XLchannelConfig   channel[64]   # [channelCount]

    ctypedef XL_DRIVER_CONFIG  XLdriverConfig
    ctypedef XL_DRIVER_CONFIG *pXLdriverConfig

.h

typedef struct {                                                                         
  unsigned int busType;
  union {
    struct {
      unsigned int bitRate;
      unsigned char sjw;
      unsigned char tseg1;
      unsigned char tseg2;
      unsigned char sam;  // 1 or 3
      unsigned char outputMode;
      unsigned char reserved[7];
      unsigned char canOpMode;
    } can;
    struct {
      unsigned int  arbitrationBitRate;     // CAN bus timing for nominal / arbitration bit rate
      unsigned char sjwAbr;
      unsigned char tseg1Abr;
      unsigned char tseg2Abr;
      unsigned char samAbr;  // 1 or 3
      unsigned char outputMode;
      unsigned char sjwDbr;                 // CAN bus timing for data bit rate 
      unsigned char tseg1Dbr;
      unsigned char tseg2Dbr;
      unsigned int  dataBitRate;
      unsigned char canOpMode;
    } canFD;
    struct {
      unsigned int  activeSpeedGrade;
      unsigned int  compatibleSpeedGrade;
      unsigned int  inicFwVersion;
    } most;
    struct {
      // status and cfg mode are part of xlFrGetChannelConfiguration, too 
      unsigned int  status;                 // XL_FR_CHANNEL_CFG_STATUS_xxx 
      unsigned int  cfgMode;                // XL_FR_CHANNEL_CFG_MODE_xxx 
      unsigned int  baudrate;               // FlexRay baudrate in kBaud 
    } flexray;
    struct {
      unsigned char macAddr[6]; // MAC address (starting with MSB!)
      unsigned char connector;  // XL_ETH_STATUS_CONNECTOR_xxx
      unsigned char phy;        // XL_ETH_STATUS_PHY_xxx
      unsigned char link;       // XL_ETH_STATUS_LINK_xxx
      unsigned char speed;      // XL_ETH_STATUS_SPEED_xxx
      unsigned char clockMode;  // XL_ETH_STATUS_CLOCK_xxx
      unsigned char bypass;     // XL_ETH_BYPASS_xxx
    } ethernet;
    struct {
      unsigned short channelDirection;
      unsigned short res1;
      union {
        struct {
          unsigned int bitrate;
          unsigned int parity;
          unsigned int minGap;
        } tx;
        struct {
          unsigned int bitrate;
          unsigned int minBitrate;
          unsigned int maxBitrate;
          unsigned int parity;
          unsigned int minGap;
          unsigned int autoBaudrate;
        } rx;
        unsigned char raw[24];
      } dir;
    } a429;
    unsigned char raw[28];
  } data;
} XLbusParams; 


// structures for xlGetDriverConfig
typedef struct s_xl_channel_config {
          char                name [XL_MAX_LENGTH + 1];
          unsigned char       hwType;                               //!< HWTYPE_xxxx (see above)
          unsigned char       hwIndex;                              //!< Index of the hardware (same type) (0,1,...)
          unsigned char       hwChannel;                            //!< Index of the channel (same hardware) (0,1,...)
          unsigned short      transceiverType;                      //!< TRANSCEIVER_TYPE_xxxx (see above)
          unsigned short      transceiverState;                     //!< transceiver state (XL_TRANSCEIVER_STATUS...)
          unsigned short      configError;                          //!< XL_CHANNEL_CONFIG_ERROR_XXX (see above)
          unsigned char       channelIndex;                         //!< Global channel index (0,1,...)
          XLuint64            channelMask;                          //!< Global channel mask (=1<<channelIndex)
          unsigned int        channelCapabilities;                  //!< capabilities which are supported (e.g CHANNEL_FLAG_XXX)
          unsigned int        channelBusCapabilities;               //!< what buses are supported and which are possible to be 
                                                                    //!< activated (e.g. XXX_BUS_ACTIVE_CAP_CAN)

          // Channel          
          unsigned char       isOnBus;                              //!< The channel is on bus
          unsigned int        connectedBusType;                     //!< currently selected bus      
          XLbusParams         busParams;
          unsigned int        _doNotUse;                            //!< introduced for compatibility reasons since EM00056439

          unsigned int        driverVersion;            
          unsigned int        interfaceVersion;                     //!< version of interface with driver
          unsigned int        raw_data[10];

          unsigned int        serialNumber;
          unsigned int        articleNumber;

          char                transceiverName [XL_MAX_LENGTH + 1];  //!< name for CANcab or another transceiver

          unsigned int        specialCabFlags;                      //!< XL_SPECIAL_CAB_XXX flags
          unsigned int        dominantTimeout;                      //!< Dominant Timeout in us.
          unsigned char       dominantRecessiveDelay;               //!< Delay in us.
          unsigned char       recessiveDominantDelay;               //!< Delay in us.
          unsigned char       connectionInfo;                       //!< XL_CONNECTION_INFO_XXX
          unsigned char       currentlyAvailableTimestamps;         //!< XL_CURRENTLY_AVAILABLE_TIMESTAMP...
          unsigned short      minimalSupplyVoltage;                 //!< Minimal Supply Voltage of the Cab/Piggy in 1/100 V
          unsigned short      maximalSupplyVoltage;                 //!< Maximal Supply Voltage of the Cab/Piggy in 1/100 V
          unsigned int        maximalBaudrate;                      //!< Maximal supported LIN baudrate
          unsigned char       fpgaCoreCapabilities;                 //!< e.g.: XL_FPGA_CORE_TYPE_XXX
          unsigned char       specialDeviceStatus;                  //!< e.g.: XL_SPECIAL_DEVICE_STAT_XXX
          unsigned short      channelBusActiveCapabilities;         //!< like channelBusCapabilities (but without core dependencies)
          unsigned short      breakOffset;                          //!< compensation for edge asymmetry in ns 
          unsigned short      delimiterOffset;                      //!< compensation for edgdfde asymmetry in ns 
          unsigned int        reserved[3];
        } XL_CHANNEL_CONFIG;

typedef XL_CHANNEL_CONFIG  XLchannelConfig;
typedef XL_CHANNEL_CONFIG  *pXLchannelConfig; 

typedef struct s_xl_driver_config {
          unsigned int      dllVersion;
          unsigned int      channelCount;  // total number of channels
          unsigned int      reserved[10];
          XLchannelConfig   channel[XL_CONFIG_MAX_CHANNELS];    // [channelCount]
        } XL_DRIVER_CONFIG;

typedef XL_DRIVER_CONFIG  XLdriverConfig;
typedef XL_DRIVER_CONFIG  *pXLdriverConfig;

0 Answers