CAN DBC解析自動生成C 信號 API代碼

    衆所周知,Python的腳本解析最近非常流行,Python入門是非常友好的,如果有C語言基礎,一週基本就入門了。

    一直想寫一下DBC自動生成代碼的小工具,正好藉助小工具的編寫,學習一下Python。

    目標:通過Python對CAN DBC文件進行解析,並把幀解析爲具體的信號。

    實現過程:方法一,Python讀取DBC====》對DBC完成信號提取====》生成對應的信號API接口

                      方法二,通過Matlab CAN Unpack也可實現

                      方法一更加靈活,方便代碼集成,故採用方法一

生成腳本

dbc_demo.py -i 243.dbc -s IO > IO.txt
:pause
choice /t 20 /d y /n >nul

生成代碼


#ifndef __GENEARTED_DBC_PARSER
#define __GENERATED_DBC_PARSER
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>



/// Extern function needed for dbc_encode_and_send()
extern bool dbc_app_send_can_msg(uint32_t mid, uint8_t dlc, uint8_t bytes[8]);

/// Missing in Action structure
typedef struct {
    uint32_t is_mia : 1;          ///< Missing in action flag
    uint32_t mia_counter_ms : 31; ///< Missing in action counter
} dbc_mia_info_t;

/// CAN message header structure
typedef struct { 
    uint32_t mid; ///< Message ID of the message
    uint8_t  dlc; ///< Data length of the message
} dbc_msg_hdr_t; 

static const dbc_msg_hdr_t DBC_TEST1_HDR =                        { 0x1f4, 8 };
static const dbc_msg_hdr_t DBC_TEST2_HDR =                        { 0x1f5, 8 };
static const dbc_msg_hdr_t DBC_TEST3_HDR =                        { 0x1f6, 8 };
// static const dbc_msg_hdr_t DRIVER_HEARTBEAT_HDR =                 { 0x64, 1 };
// static const dbc_msg_hdr_t MOTOR_CMD_HDR =                        { 0x65, 1 };
static const dbc_msg_hdr_t MOTOR_STATUS_HDR =                     { 0x190, 3 };
static const dbc_msg_hdr_t SENSOR_SONARS_HDR =                    { 0xc8, 8 };
static const dbc_msg_hdr_t DBC_TEST4_HDR =                        { 0x1f7, 8 };




/// Message: DBC_TEST1 from 'IO', DLC: 8 byte(s), MID: 0x1f4
typedef struct {
    uint32_t DBC_TEST1_unsigned1 : 8;         ///< B7:0   Destination: DBG
    uint32_t DBC_TEST1_unsigned_minmax : 8;   ///< B15:8  Min: 0 Max: 100   Destination: DBG
    uint32_t DBC_TEST1_enum : 8;              ///< B39:32   Destination: DBG
    uint32_t DBC_TEST1_float : 8;             ///< B47:40   Destination: DBG
    uint32_t DBC_TEST1_float_signed : 16;     ///< B63:48  Min: 0 Max: 65.535   Destination: DBG

    // No dbc_mia_info_t for a message that we will send
} DBC_TEST1_t;


/// Message: DBC_TEST2 from 'IO', DLC: 8 byte(s), MID: 0x1f5
typedef struct {
    uint32_t DBC_TEST2_real_signed1 : 12;     ///< B17:6   Destination: DBG
    uint32_t DBC_TEST2_real_signed2 : 18;     ///< B35:18   Destination: DBG
    uint32_t DBC_TEST2_signed : 8;            ///< B43:36   Destination: DBG
    uint32_t DBC_TEST2_signed_minmax : 16;    ///< B59:44  Min: -32768 Max: 32767   Destination: DBG

    // No dbc_mia_info_t for a message that we will send
} DBC_TEST2_t;


/// Message: DBC_TEST3 from 'IO', DLC: 8 byte(s), MID: 0x1f6
typedef struct {
    uint32_t DBC_TEST3_real_signed1 : 4;      ///< B5:2   Destination: DBG
    uint32_t DBC_TEST3_real_signed2 : 8;      ///< B15:8   Destination: DBG

    // No dbc_mia_info_t for a message that we will send
} DBC_TEST3_t;


/// Message: MOTOR_STATUS from 'MOTOR', DLC: 3 byte(s), MID: 0x190
typedef struct {
    uint32_t MOTOR_STATUS_wheel_error : 1;    ///< B0:0   Destination: DRIVER,IO
    uint32_t MOTOR_STATUS_speed_kph : 16;     ///< B23:8   Destination: DRIVER,IO

    dbc_mia_info_t mia_info;
} MOTOR_STATUS_t;

/// @{ MUX'd message: SENSOR_SONARS

/// Struct for MUX: m0 (used for transmitting)
typedef struct {
    uint32_t SENSOR_SONARS_err_count : 12;    ///< B15:4   Destination: DRIVER,IO
    uint32_t SENSOR_SONARS_left : 12;         ///< B27:16   Destination: DRIVER,IO
    uint32_t SENSOR_SONARS_middle : 12;       ///< B39:28   Destination: DRIVER,IO
    uint32_t SENSOR_SONARS_right : 12;        ///< B51:40   Destination: DRIVER,IO
    uint32_t SENSOR_SONARS_rear : 12;         ///< B63:52   Destination: DRIVER,IO

    dbc_mia_info_t mia_info;
} SENSOR_SONARS_m0_t;

/// Struct for MUX: m1 (used for transmitting)
typedef struct {
    uint32_t SENSOR_SONARS_err_count : 12;    ///< B15:4   Destination: DRIVER,IO
    uint32_t SENSOR_SONARS_no_filt_left : 12; ///< B27:16   Destination: DBG
    uint32_t SENSOR_SONARS_no_filt_middle : 12; ///< B39:28   Destination: DBG
    uint32_t SENSOR_SONARS_no_filt_right : 12; ///< B51:40   Destination: DBG
    uint32_t SENSOR_SONARS_no_filt_rear : 12; ///< B63:52   Destination: DBG

    dbc_mia_info_t mia_info;
} SENSOR_SONARS_m1_t;

/// Struct with all the child MUX'd signals (Used for receiving)
typedef struct {
    SENSOR_SONARS_m0_t m0; ///< MUX'd structure
    SENSOR_SONARS_m1_t m1; ///< MUX'd structure
} SENSOR_SONARS_t;
/// @} MUX'd message


/// Message: DBC_TEST4 from 'IO', DLC: 8 byte(s), MID: 0x1f7
typedef struct {
    uint32_t DBC_TEST4_real_signed1 : 32;     ///< B31:0   Destination: DBG
    uint32_t DBC_TEST4_real_signed2 : 16;     ///< B47:32  Min: -32768 Max: 32767   Destination: DBG
    uint32_t DBC_TEST4_real_overflow : 16;    ///< B63:48   Destination: DBG

    // No dbc_mia_info_t for a message that we will send
} DBC_TEST4_t;


/// @{ These 'externs' need to be defined in a source file of your project
extern const uint32_t                             MOTOR_STATUS__MIA_MS;
extern const MOTOR_STATUS_t                       MOTOR_STATUS__MIA_MSG;
extern const uint32_t                             SENSOR_SONARS_m0__MIA_MS;
extern const SENSOR_SONARS_m0_t                   SENSOR_SONARS_m0__MIA_MSG;
extern const uint32_t                             SENSOR_SONARS_m1__MIA_MS;
extern const SENSOR_SONARS_m1_t                   SENSOR_SONARS_m1__MIA_MSG;
/// @}


/// Encode IO's 'DBC_TEST1' message
/// @returns the message header of this message
static inline dbc_msg_hdr_t dbc_encode_DBC_TEST1(uint8_t frame[8], DBC_TEST1_t *msg)
{
    uint32_t raw;
    frame[0]=frame[1]=frame[2]=frame[3]=frame[4]=frame[5]=frame[6]=frame[7]=0;

    // Stuff a SIG into the DBC 8-bit signal
    ///<  bit(s) starting from BBitStart:0BitSize:8
    set_frame_data(frame, MOTOROLA_MSB, 0, 8, msg->DBC_TEST1_unsigned1);

    // Stuff a SIG into the DBC 8-bit signal
    ///<  bit(s) starting from BBitStart:8BitSize:8
    set_frame_data(frame, MOTOROLA_MSB, 8, 8, msg->DBC_TEST1_unsigned_minmax);

    // Stuff a SIG into the DBC 8-bit signal
    ///<  bit(s) starting from BBitStart:32BitSize:8
    set_frame_data(frame, MOTOROLA_MSB, 32, 8, msg->DBC_TEST1_enum);

    // Stuff a SIG into the DBC 8-bit signal
    ///<  bit(s) starting from BBitStart:40BitSize:8
    set_frame_data(frame, MOTOROLA_MSB, 40, 8, msg->DBC_TEST1_float);

    // Stuff a SIG into the DBC 16-bit signal
    ///<  bit(s) starting from BBitStart:48BitSize:16
    set_frame_data(frame, MOTOROLA_MSB, 48, 16, msg->DBC_TEST1_float_signed);

    return DBC_TEST1_HDR;
}

/// Encode and send for dbc_encode_DBC_TEST1() message
static inline bool dbc_encode_and_send_DBC_TEST1(DBC_TEST1_t *from)
{
    uint8_t bytes[8];
    const dbc_msg_hdr_t hdr = dbc_encode_DBC_TEST1(bytes, from);
    return dbc_app_send_can_msg(hdr.mid, hdr.dlc, bytes);
}



/// Encode IO's 'DBC_TEST2' message
/// @returns the message header of this message
static inline dbc_msg_hdr_t dbc_encode_DBC_TEST2(uint8_t frame[8], DBC_TEST2_t *msg)
{
    uint32_t raw;
    frame[0]=frame[1]=frame[2]=frame[3]=frame[4]=frame[5]=frame[6]=frame[7]=0;

    // Stuff a SIG into the DBC 12-bit signal
    ///<  bit(s) starting from BBitStart:6BitSize:12
    set_frame_data(frame, MOTOROLA_MSB, 6, 12, msg->DBC_TEST2_real_signed1);

    // Stuff a SIG into the DBC 18-bit signal
    ///<  bit(s) starting from BBitStart:18BitSize:18
    set_frame_data(frame, MOTOROLA_MSB, 18, 18, msg->DBC_TEST2_real_signed2);

    // Stuff a SIG into the DBC 8-bit signal
    ///<  bit(s) starting from BBitStart:36BitSize:8
    set_frame_data(frame, MOTOROLA_MSB, 36, 8, msg->DBC_TEST2_signed);

    // Stuff a SIG into the DBC 16-bit signal
    ///<  bit(s) starting from BBitStart:44BitSize:16
    set_frame_data(frame, MOTOROLA_MSB, 44, 16, msg->DBC_TEST2_signed_minmax);

    return DBC_TEST2_HDR;
}

/// Encode and send for dbc_encode_DBC_TEST2() message
static inline bool dbc_encode_and_send_DBC_TEST2(DBC_TEST2_t *from)
{
    uint8_t bytes[8];
    const dbc_msg_hdr_t hdr = dbc_encode_DBC_TEST2(bytes, from);
    return dbc_app_send_can_msg(hdr.mid, hdr.dlc, bytes);
}



/// Encode IO's 'DBC_TEST3' message
/// @returns the message header of this message
static inline dbc_msg_hdr_t dbc_encode_DBC_TEST3(uint8_t frame[8], DBC_TEST3_t *msg)
{
    uint32_t raw;
    frame[0]=frame[1]=frame[2]=frame[3]=frame[4]=frame[5]=frame[6]=frame[7]=0;

    // Stuff a SIG into the DBC 4-bit signal
    ///<  bit(s) starting from BBitStart:2BitSize:4
    set_frame_data(frame, MOTOROLA_MSB, 2, 4, msg->DBC_TEST3_real_signed1);

    // Stuff a SIG into the DBC 8-bit signal
    ///<  bit(s) starting from BBitStart:8BitSize:8
    set_frame_data(frame, MOTOROLA_MSB, 8, 8, msg->DBC_TEST3_real_signed2);

    return DBC_TEST3_HDR;
}

/// Encode and send for dbc_encode_DBC_TEST3() message
static inline bool dbc_encode_and_send_DBC_TEST3(DBC_TEST3_t *from)
{
    uint8_t bytes[8];
    const dbc_msg_hdr_t hdr = dbc_encode_DBC_TEST3(bytes, from);
    return dbc_app_send_can_msg(hdr.mid, hdr.dlc, bytes);
}



/// Not generating code for dbc_encode_DRIVER_HEARTBEAT() since the sender is DRIVER and we are IO

/// Not generating code for dbc_encode_MOTOR_CMD() since the sender is DRIVER and we are IO

/// Not generating code for dbc_encode_MOTOR_STATUS() since the sender is MOTOR and we are IO

/// Not generating code for dbc_encode_SENSOR_SONARS() since the sender is SENSOR and we are IO

/// Encode IO's 'DBC_TEST4' message
/// @returns the message header of this message
static inline dbc_msg_hdr_t dbc_encode_DBC_TEST4(uint8_t frame[8], DBC_TEST4_t *msg)
{
    uint32_t raw;
    frame[0]=frame[1]=frame[2]=frame[3]=frame[4]=frame[5]=frame[6]=frame[7]=0;

    // Stuff a SIG into the DBC 32-bit signal
    ///<  bit(s) starting from BBitStart:0BitSize:32
    set_frame_data(frame, MOTOROLA_MSB, 0, 32, msg->DBC_TEST4_real_signed1);

    // Stuff a SIG into the DBC 16-bit signal
    ///<  bit(s) starting from BBitStart:32BitSize:16
    set_frame_data(frame, MOTOROLA_MSB, 32, 16, msg->DBC_TEST4_real_signed2);

    // Stuff a SIG into the DBC 16-bit signal
    ///<  bit(s) starting from BBitStart:48BitSize:16
    set_frame_data(frame, MOTOROLA_MSB, 48, 16, msg->DBC_TEST4_real_overflow);

    return DBC_TEST4_HDR;
}

/// Encode and send for dbc_encode_DBC_TEST4() message
static inline bool dbc_encode_and_send_DBC_TEST4(DBC_TEST4_t *from)
{
    uint8_t bytes[8];
    const dbc_msg_hdr_t hdr = dbc_encode_DBC_TEST4(bytes, from);
    return dbc_app_send_can_msg(hdr.mid, hdr.dlc, bytes);
}



/// Not generating code for dbc_decode_DBC_TEST1() since 'IO' is not the recipient of any of the signals

/// Not generating code for dbc_decode_DBC_TEST2() since 'IO' is not the recipient of any of the signals

/// Not generating code for dbc_decode_DBC_TEST3() since 'IO' is not the recipient of any of the signals

/// Not generating code for dbc_decode_DRIVER_HEARTBEAT() since 'IO' is not the recipient of any of the signals

/// Not generating code for dbc_decode_MOTOR_CMD() since 'IO' is not the recipient of any of the signals

/// Decode MOTOR's 'MOTOR_STATUS' message
/// @param hdr  The header of the message to validate its DLC and MID; this can be NULL to skip this check
static inline bool dbc_decode_MOTOR_STATUS(MOTOR_STATUS_t *msg, const uint8_t frame[8], const dbc_msg_hdr_t *hdr)
{
    const bool success = true;
    // If msg header is provided, check if the DLC and the MID match
    if (NULL != hdr && (hdr->dlc != MOTOR_STATUS_HDR.dlc || hdr->mid != MOTOR_STATUS_HDR.mid)) {
        return !success;
    }

    uint32_t raw;
    // Stuff a SIG from the DBC 1-bit signal
    ///<  bit(s) starting from BBitStart:0BitSize:1
    get_frame_data(frame, MOTOROLA_MSB, 0, 1, msg->MOTOR_STATUS_wheel_error);
    // Stuff a SIG from the DBC 16-bit signal
    ///<  bit(s) starting from BBitStart:8BitSize:16
    get_frame_data(frame, MOTOROLA_MSB, 8, 16, msg->MOTOR_STATUS_speed_kph);

    msg->mia_info.mia_counter_ms = 0; ///< Reset the MIA counter

    return success;
}


/// Decode SENSOR's 'SENSOR_SONARS' message
/// @param hdr  The header of the message to validate its DLC and MID; this can be NULL to skip this check
static inline bool dbc_decode_SENSOR_SONARS(SENSOR_SONARS_t *msg, const uint8_t frame[8], const dbc_msg_hdr_t *hdr)
{
    const bool success = true;
    // If msg header is provided, check if the DLC and the MID match
    if (NULL != hdr && (hdr->dlc != SENSOR_SONARS_HDR.dlc || hdr->mid != SENSOR_SONARS_HDR.mid)) {
        return !success;
    }

    uint32_t raw;
    // Decode the MUX
    uint8_t MUX = 0;    // Stuff a SIG from the DBC 4-bit signal
    ///<  bit(s) starting from BBitStart:0BitSize:4
    get_frame_data(frame, MOTOROLA_MSB, 0, 4, &MUX);

    if (0 == MUX) {
        // Non Muxed signals (part of all MUX'd structures)
        // Stuff a SIG from the DBC 12-bit signal
        ///<  bit(s) starting from BBitStart:4BitSize:12
        get_frame_data(frame, MOTOROLA_MSB, 4, 12, &msg->m0.SENSOR_SONARS_err_count);

        // Stuff a SIG from the DBC 12-bit signal
        ///<  bit(s) starting from BBitStart:16BitSize:12
        get_frame_data(frame, MOTOROLA_MSB, 16, 12, &msg->m0.SENSOR_SONARS_left);
        // Stuff a SIG from the DBC 12-bit signal
        ///<  bit(s) starting from BBitStart:28BitSize:12
        get_frame_data(frame, MOTOROLA_MSB, 28, 12, &msg->m0.SENSOR_SONARS_middle);
        // Stuff a SIG from the DBC 12-bit signal
        ///<  bit(s) starting from BBitStart:40BitSize:12
        get_frame_data(frame, MOTOROLA_MSB, 40, 12, &msg->m0.SENSOR_SONARS_right);
        // Stuff a SIG from the DBC 12-bit signal
        ///<  bit(s) starting from BBitStart:52BitSize:12
        get_frame_data(frame, MOTOROLA_MSB, 52, 12, &msg->m0.SENSOR_SONARS_rear);

        msg->m0.mia_info.mia_counter_ms = 0; ///< Reset the MIA counter
    }
    else if (1 == MUX) {
        // Non Muxed signals (part of all MUX'd structures)
        // Stuff a SIG from the DBC 12-bit signal
        ///<  bit(s) starting from BBitStart:4BitSize:12
        get_frame_data(frame, MOTOROLA_MSB, 4, 12, &msg->m1.SENSOR_SONARS_err_count);

        // Stuff a SIG from the DBC 12-bit signal
        ///<  bit(s) starting from BBitStart:16BitSize:12
        get_frame_data(frame, MOTOROLA_MSB, 16, 12, &msg->m1.SENSOR_SONARS_no_filt_left);
        // Stuff a SIG from the DBC 12-bit signal
        ///<  bit(s) starting from BBitStart:28BitSize:12
        get_frame_data(frame, MOTOROLA_MSB, 28, 12, &msg->m1.SENSOR_SONARS_no_filt_middle);
        // Stuff a SIG from the DBC 12-bit signal
        ///<  bit(s) starting from BBitStart:40BitSize:12
        get_frame_data(frame, MOTOROLA_MSB, 40, 12, &msg->m1.SENSOR_SONARS_no_filt_right);
        // Stuff a SIG from the DBC 12-bit signal
        ///<  bit(s) starting from BBitStart:52BitSize:12
        get_frame_data(frame, MOTOROLA_MSB, 52, 12, &msg->m1.SENSOR_SONARS_no_filt_rear);

        msg->m1.mia_info.mia_counter_ms = 0; ///< Reset the MIA counter
    }
    else {
        return !success;
    }

    return success;
}


/// Not generating code for dbc_decode_DBC_TEST4() since 'IO' is not the recipient of any of the signals

/// Handle the MIA for MOTOR's MOTOR_STATUS message
/// @param   time_incr_ms  The time to increment the MIA counter with
/// @returns true if the MIA just occurred
/// @post    If the MIA counter reaches the MIA threshold, MIA struct will be copied to *msg
static inline bool dbc_handle_mia_MOTOR_STATUS(MOTOR_STATUS_t *msg, uint32_t time_incr_ms)
{
    bool mia_occurred = false;
    const dbc_mia_info_t old_mia = msg->mia_info;
    msg->mia_info.is_mia = (msg->mia_info.mia_counter_ms >= MOTOR_STATUS__MIA_MS);

    if (!msg->mia_info.is_mia) { // Not MIA yet, so keep incrementing the MIA counter
        msg->mia_info.mia_counter_ms += time_incr_ms;
    }
    else if(!old_mia.is_mia)   { // Previously not MIA, but it is MIA now
        // Copy MIA struct, then re-write the MIA counter and is_mia that is overwriten
        *msg = MOTOR_STATUS__MIA_MSG;
        msg->mia_info.mia_counter_ms = MOTOR_STATUS__MIA_MS;
        msg->mia_info.is_mia = true;
        mia_occurred = true;
    }

    return mia_occurred;
}

/// Handle the MIA for SENSOR's SENSOR_SONARS for MUX "m0" message
/// @param   time_incr_ms  The time to increment the MIA counter with
/// @returns true if the MIA just occurred
/// @post    If the MIA counter reaches the MIA threshold, MIA struct will be copied to *msg
static inline bool dbc_handle_mia_SENSOR_SONARS_m0(SENSOR_SONARS_m0_t *msg, uint32_t time_incr_ms)
{
    bool mia_occurred = false;
    const dbc_mia_info_t old_mia = msg->mia_info;
    msg->mia_info.is_mia = (msg->mia_info.mia_counter_ms >= SENSOR_SONARS_m0__MIA_MS);

    if (!msg->mia_info.is_mia) { // Not MIA yet, so keep incrementing the MIA counter
        msg->mia_info.mia_counter_ms += time_incr_ms;
    }
    else if(!old_mia.is_mia)   { // Previously not MIA, but it is MIA now
        // Copy MIA struct, then re-write the MIA counter and is_mia that is overwriten
        *msg = SENSOR_SONARS_m0__MIA_MSG;
        msg->mia_info.mia_counter_ms = SENSOR_SONARS_m0__MIA_MS;
        msg->mia_info.is_mia = true;
        mia_occurred = true;
    }

    return mia_occurred;
}

/// Handle the MIA for SENSOR's SENSOR_SONARS for MUX "m1" message
/// @param   time_incr_ms  The time to increment the MIA counter with
/// @returns true if the MIA just occurred
/// @post    If the MIA counter reaches the MIA threshold, MIA struct will be copied to *msg
static inline bool dbc_handle_mia_SENSOR_SONARS_m1(SENSOR_SONARS_m1_t *msg, uint32_t time_incr_ms)
{
    bool mia_occurred = false;
    const dbc_mia_info_t old_mia = msg->mia_info;
    msg->mia_info.is_mia = (msg->mia_info.mia_counter_ms >= SENSOR_SONARS_m1__MIA_MS);

    if (!msg->mia_info.is_mia) { // Not MIA yet, so keep incrementing the MIA counter
        msg->mia_info.mia_counter_ms += time_incr_ms;
    }
    else if(!old_mia.is_mia)   { // Previously not MIA, but it is MIA now
        // Copy MIA struct, then re-write the MIA counter and is_mia that is overwriten
        *msg = SENSOR_SONARS_m1__MIA_MSG;
        msg->mia_info.mia_counter_ms = SENSOR_SONARS_m1__MIA_MS;
        msg->mia_info.is_mia = true;
        mia_occurred = true;
    }

    return mia_occurred;
}

#endif

Python片段

def main(argv):
    dbcfile = '243.dbc'  # Default value unless overriden
    self_node = 'DRIVER'  # Default value unless overriden
    gen_all = False
    muxed_signal = False
    mux_bit_width = 0
    msg_ids_used = []
    try:
        opts, args = getopt.getopt(argv, "i:s:a", ["ifile=", "self=", "all"])
    except getopt.GetoptError:
        print('dbc_parse.py -i <dbcfile> -s <self_node> <-a>')
        sys.exit(2)
    for opt, arg in opts:
        if opt == '-h':
            print('dbc_parse.py -i <dbcfile> -s <self_node> <-a> <-b>')
            sys.exit()
        elif opt in ("-i", "--ifile"):
            dbcfile = arg
        elif opt in ("-s", "--self"):
            self_node = arg
        elif opt in ("-a", "--all"):
            gen_all = True

    # Parse the DBC file
    dbc = DBC(dbcfile, self_node, gen_all)
    f = open(dbcfile, "r")
    last_mid = -1
    validFile = True
    while 1:
        line = f.readline()
        if not line:
            break

        # Nodes in the DBC file
        if line.startswith("BU_:"):
            nodes = line.strip("\n").split(' ')
            dbc.nodes = (nodes[1:])
            if self_node not in dbc.nodes:
                print('/////////////////////////////// ERROR /////////////////////////////////////')
                print('#error "Self node: ' + self_node + ' not found in _BU nodes in the DBC file"')
                print('/////////////////////////////// ERROR /////////////////////////////////////')
                print('')
                raise ValueError('#error "Self node: ' + self_node + ' not found in _BU nodes in the DBC file"')

        # Start of a message
        # BO_ 100 DRIVER_HEARTBEAT: 1 DRIVER
        if line.startswith("BO_ "):
            muxed_signal = False
            mux_bit_width = 0
            tokens = line.split(' ')
            msg_id = hex(int(tokens[1],10))
            msg_name = tokens[2].strip(":")
            dbc.messages[msg_id] = Message(msg_id, msg_name, tokens[3], tokens[4].strip("\n"))
            msg_length = tokens[3]
            last_mid = msg_id
            fixed_mux_signal = False
            fixed_signal_end = 0
            prev_signal_end = 0
            prev_mux_index = 0

            if (int(msg_id, 16) < 0) or (int(msg_id, 16) > 536870911):
                print('/////////////////////////////// ERROR /////////////////////////////////////')
                print('#error msg id '+ tokens[1] + ' is out of bounds')
                print('/////////////////////////////// ERROR /////////////////////////////////////')
                print('')
                raise ValueError('#error msg id '+ tokens[1] + ' is out of bounds for 29-bit msgID')

            if msg_id not in msg_ids_used:
                msg_id = msg_ids_used.append(msg_id)
            else:
                print('/////////////////////////////// ERROR /////////////////////////////////////')
                print('#error '+ tokens[1] + ' has already been used')
                print('/////////////////////////////// ERROR /////////////////////////////////////')
                print('')
                raise ValueError('#error msg id '+ msg_id + ' has already been used')

            if (int(msg_length) > 8) or (int(msg_length) < 0):
                print('/////////////////////////////// ERROR /////////////////////////////////////')
                print('#error ' + str(tokens[1]) + ' has an incorrect number of bytes. It must be between 0 and 8 bytes.')
                print('/////////////////////////////// ERROR /////////////////////////////////////')
                print('')
                raise ValueError('#error msg id ' + str(tokens[1]) + ' has an incorrect number of bytes. It must be between 0 and 8 bytes.')

        # Signals: SG_ IO_DEBUG_test_signed : 16|8@1+ (1,-128) [0|0] "" DBG
        if line.startswith(" SG_ "):
            t = line[1:].split(' ')

            # If this is a MUX'd symbol
            mux = ''
            if t[3] == ":":
                mux = t[2]
                line = line.replace(mux + " ", '')
                t = line[1:].split(' ')

            # Split the bit start and the bit size
            s = re.split('[|@]', t[3])
            bit_start = s[0]
            bit_size = s[1]

            if mux == 'M':
                muxed_signal = True
                mux_bit_width = int(bit_size)

            if not muxed_signal:
                if (int(bit_start) < prev_signal_end):
                    print('/////////////////////////////// ERROR /////////////////////////////////////')
                    print('#error ' + t[1] + ' start bit overwrites previous signal')
                    print('/////////////////////////////// ERROR /////////////////////////////////////')
                    print('')
                    raise ValueError('#error ' + t[1] + ' start bit overwrites previous signal')
                prev_signal_end = int(bit_start) + int(bit_size)
            # Ensure a mux index
            if muxed_signal:
                if mux == '':
                    fixed_mux_signal = True
                    fixed_signal_end = mux_bit_width + int(bit_size)
                elif mux[0] == 'm':
                    fixed_mux_signal = False
                    if int(mux[1:]) != prev_mux_index:
                        prev_signal_end = fixed_signal_end

                if fixed_mux_signal:
                    if int(bit_start) < mux_bit_width:
                        print('/////////////////////////////// ERROR /////////////////////////////////////')
                        print('#error ' + t[1] + ' start bit overwrites mux index')
                        print('/////////////////////////////// ERROR /////////////////////////////////////')
                        print('')
                        raise ValueError('#error ' + t[1] + ' start bit overwrites mux index')
                else:
                    if mux != 'M':
                        # Do not allow the signal to use the indexing bits
                        if int(bit_start) < fixed_signal_end:
                            print('/////////////////////////////// ERROR /////////////////////////////////////')
                            print('#error ' + t[1] + ' start bit overwrites mux index')
                            print('/////////////////////////////// ERROR /////////////////////////////////////')
                            print('')
                            raise ValueError('#error ' + t[1] + ' start bit overwrites previous fixed signal')
                        if mux[0] == 'm':
                        # Check for mux index out of bounds
                            if (int(mux[1:]) >= pow(2,mux_bit_width)) or (int(mux[1:]) < 0):
                                print('/////////////////////////////// ERROR /////////////////////////////////////')
                                print('#error ' + t[1] + ' mux index out of bounds.')
                                print('/////////////////////////////// ERROR /////////////////////////////////////')
                                print('')
                                raise ValueError('#error ' + t[1] + ' mux index out of bounds.')

                            if int(bit_start) < prev_signal_end:
                                print('/////////////////////////////// ERROR /////////////////////////////////////')
                                print('#error ' + t[1] + ' start bit overwrites previous signal')
                                print('/////////////////////////////// ERROR /////////////////////////////////////')
                                print('')
                                raise ValueError('#error ' + t[1] + ' start bit overwrites previous signal')
                            prev_signal_end = int(bit_start) + int(bit_size)
                        prev_mux_index = int(mux[1:])

            # If we have an invalid message length then invalidate the DBC and print the offending signal
            # Signal bit width is <= 0
            if (int(bit_size) <= 0):
                print('/////////////////////////////// ERROR /////////////////////////////////////')
                print('#error ' + t[1] + ' has invalid size. Signal bit width is: ' + str(int(bit_size)))
                print('/////////////////////////////// ERROR /////////////////////////////////////')
                print('')
                raise ValueError('#error ' + t[1] + ' has invalid size. Signal bit width is: ' + str(int(bit_size)))

            # Signal is too wide for message
            if (int(bit_start) + int(bit_size)) > (int(msg_length) * 8):
                print('/////////////////////////////// ERROR /////////////////////////////////////')
                print('#error ' + t[1] + ' too large. Message needs ' + str(int(bit_start) + int(bit_size)) + ' bits.')
                print('/////////////////////////////// ERROR /////////////////////////////////////')
                print('')
                raise ValueError('#error ' + t[1] + ' too large. Message needs ' + str(int(bit_start) + int(bit_size)) + ' bits.')

            endian_and_sign = s[2]
            # Split (0.1,1) to two tokens by removing the ( and the )
            s = t[4][1:-1].split(',')
            scale = s[0]
            offset = s[1]

            # Split the [0|0] to min and max
            s = t[5][1:-1].split('|')
            min_val = s[0]
            max_val = s[1]

            signal_min = 0
            signal_max = (float(scale) * pow(2,int(bit_size)))
            if '-' in t[3]:
                signal_min = -(float(scale) * pow(2,int(bit_size))) / 2
                signal_max = (float(scale) * pow(2,int(bit_size)) / 2)
            # If our min / max values are incorrect then clamping will not work correctly.
            # Invalidate the DBC and print out the offending signal.
            signal_min = signal_min + float(offset)
            signal_max = signal_max + float(offset) - float(scale)

            # Min for signal is too low.
            if (float(min_val) != 0) and (float(min_val) < float(signal_min)):
                print('/////////////////////////////// ERROR /////////////////////////////////////')
                print('#error ' + t[1] + ' min value too low. Min value is: ' + str(signal_min))
                print('/////////////////////////////// ERROR /////////////////////////////////////')
                print('')
                raise ValueError('#error ' + t[1] + ' min value too low. Min value is: ' + str(signal_min))

            # Max for signal is too high
            if (float(max_val) != 0) and (float(max_val)) > (float(signal_max)):
                print('/////////////////////////////// ERROR /////////////////////////////////////')
                print('#error ' + t[1] + ' max value too high. Max value is: ' + str(signal_max))
                print('/////////////////////////////// ERROR /////////////////////////////////////')
                print('')
                raise ValueError('#error ' + t[1] + ' max value too high. Max value is: ' + str(signal_max))

            recipients = t[7].strip('\n').split(',')

            # Add the signal the last message object
            sig = Signal(t[1], bit_start, bit_size, endian_and_sign, scale, offset, min_val, max_val, recipients, mux, signal_min, signal_max)
            dbc.messages[last_mid].add_signal(sig)

        # Parse the "FieldType" which is the trigger to use enumeration type for certain signals
        if line.startswith('BA_ "FieldType"'):
            t = line[1:].split(' ')  # BA_ "FieldType" SG_ 123 Some_sig "Some_sig";
            sig_mid = t[3]
            sig_name = t[4]

            # Locate the message and the signal whom this "FieldType" type belongs to
            if sig_mid in dbc.messages:
                if sig_name in dbc.messages[sig_mid].signals:
                    dbc.messages[sig_mid].signals[sig_name].has_field_type = True

        # Enumeration types
        # VAL_ 100 DRIVER_HEARTBEAT_cmd 2 "DRIVER_HEARTBEAT_cmd_REBOOT" 1 "DRIVER_HEARTBEAT_cmd_SYNC" ;
        if line.startswith("VAL_ "):
            t = line[1:].split(' ')
            sig_mid = t[1]
            enum_name = t[2]
            pairs = {}
            t = t[3:]
            for i in range(0, int(len(t) / 2)):
                pairs[t[i * 2 + 1].replace('"', '').replace(';\n', '')] = t[i * 2]

            # Locate the message and the signal whom this enumeration type belongs to
            if sig_mid in dbc.messages:
                if enum_name in dbc.messages[sig_mid].signals:
                    if dbc.messages[sig_mid].signals[enum_name].has_field_type:
                        dbc.messages[sig_mid].signals[enum_name].enum_info = pairs

    # If there were errors in parsing the DBC file then do not continue with generation.
    if not validFile:
        sys.exit(-1)
    
    print(HeadCode)
    print(dbc.gen_file_header())
    print("\n")

    # Generate the application send extern function
    print("/// Extern function needed for dbc_encode_and_send()")
    print("extern bool dbc_app_send_can_msg(uint32_t mid, uint8_t dlc, uint8_t bytes[8]);")
    print("")

    # Generate header structs and MIA struct
    print(dbc.gen_mia_struct())
    print(dbc.gen_msg_hdr_struct())
    print(dbc.gen_msg_hdr_instances())
    print(dbc.gen_enum_types())

    # Generate converted struct types for each message
    for mid in dbc.messages:
        m = dbc.messages[mid]
        if not gen_all and not m.is_recipient_of_at_least_one_sig(self_node) and m.sender != self_node:
            code = ("\n// Not generating '" + m.get_struct_name() + "' since we are not the sender or a recipient of any of its signals")
        else:
            print(m.gen_converted_struct(self_node, gen_all))

    # Generate MIA handler "externs"
    print("\n/// @{ These 'externs' need to be defined in a source file of your project")
    for mid in dbc.messages:
        m = dbc.messages[mid]
        if gen_all or m.is_recipient_of_at_least_one_sig(self_node):
            if m.contains_muxed_signals():
                muxes = m.get_muxes()
                for mux in muxes[1:]:
                    print(str("extern const uint32_t ").ljust(50) + (m.name + "_" + mux + "__MIA_MS;"))
                    print(str("extern const " + m.get_struct_name()[:-2] + "_" + mux + "_t").ljust(49) + " " + (
                    m.name + "_" + mux + "__MIA_MSG;"))
            else:
                print(str("extern const uint32_t ").ljust(50) + (m.name + "__MIA_MS;"))
                print(str("extern const " + m.get_struct_name()).ljust(49) + " " + (m.name + "__MIA_MSG;"))
    print("/// @}\n")

    # Generate encode methods
    for mid in dbc.messages:
        m = dbc.messages[mid]
        if not gen_all and m.sender != self_node:
            print ("\n/// Not generating code for dbc_encode_" + m.get_struct_name()[:-2] + "() since the sender is " + m.sender + " and we are " + self_node)
        else:
            print(m.get_encode_code())

    # Generate decode methods
    for mid in dbc.messages:
        m = dbc.messages[mid]
        if not gen_all and not m.is_recipient_of_at_least_one_sig(self_node):
            print ("\n/// Not generating code for dbc_decode_" + m.get_struct_name()[:-2] + "() since '" + self_node + "' is not the recipient of any of the signals")
        else:
            print(m.get_decode_code())

    print(dbc.gen_mia_funcs())
    print("#endif")


if __name__ == "__main__":
    main(sys.argv[1:])

有了這個工具,我們的程序員就可以省下點時間好好喝杯茶了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章