众所周知,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:])
有了这个工具,我们的程序员就可以省下点时间好好喝杯茶了。