目录
前言
1.报文消息格式介绍
1.1 术语定义
1.2 帧类型
编辑
2.代码格式化处理待发送的消息
2.1 单帧
2.2 首帧
2.3 连续帧
前言
can总线通讯时,需要按照can报文格式进行消息的发送.发送的消息长度不同,格式会不一样.
下面用代码完成消息转换成报文.
1.报文消息格式介绍
1.1 术语定义
术语简写 | 术语描述 |
SI | 服务标识符 |
PCI | 协议控制信息 |
DID | 数据标识符 |
SF | 单帧 |
FF | 首帧 |
FC | 流控制 |
CF | 连续帧 |
FF_DL | 首帧字节长度 |
SF_DL | 单帧字节长度 |
BS | 块大小 |
STmin | 时间间隙 |
SN | 连续帧编号 |
NRC | 消极应答码 |
DTC | 故障码 |
PH | 物理层 |
PDU | 协议数据单元 |
1.2 帧类型
2.代码格式化处理待发送的消息
2.1 单帧
发送的消息不超过7个字节.
# 单帧-SingleFrame
def func_sf_format(data):
"""
发送数据前,添加一个字节的帧类型+数据长度
data_new = 0{数据长度}{data_raw}
:param data: str '500300' -> 0{3}{500300} 500300为三个字节
:return:
"""
# 首字节 高4bit值 0000 是SingleFrame标志 低4bit值为DataLength
_data_length = int(len(data) / 2)
_data = f"0{hex(_data_length).replace('0x', '')}{data}"
return _data
2.2 首帧
发送的消息不超过6个字节.
def get_ff_format(data):
"""
:param data: str
:return:
"""
_data_length = int(len(data) / 2)
# 数据长度 已包含 (传送数据服务请求id)
_ff_data = f"10{hex(_data_length).replace('0x', '').zfill(2)}{data}"
return _ff_data
2.3 连续帧
(['10', '82', '36', '01', '18', '08', '00', '20'], 'FF', '30')
[['21', '9D', '41', '00', '00', '8D', '50', '00'], 'SN', None]
[['22', '00', '79', '50', '00', '00', '00', '00'], 'SN', None]
[['23', '00', '00', '00', '00', '00', '00', '00'], 'SN', None]
当发送的消息超过6个字节时,需要用连续帧的报文格式进行发送.
注意:
2.3.1 发送多帧数据时, 报文消息体包含两类数据帧: 首帧 + 连续帧
首帧构成 数据帧类型 + 数据长度 + 服务ID + 数据块大编号(01-FF) + 消息体
连续帧构成 数据帧类型 + 数据块小编号(0-F) + 消息体
def func_mf_format(data, id):
"""
:param data: str
:return:
"""
data_list = re.findall(".{2}", data)
data_group = []
group_num = 0
temp = []
def get_ff_data(_data_list, _group_sn):
if id == "36":
# 数据长度 + 2 (传送数据服务请求id 占一个字节 + 数据块编号 占一个字节)
_ff_data = ["10", f"{hex(len(_data_list) + 2).replace('0x', '').zfill(2)}", id, _group_sn]
else:
# 数据长度 已包含 (传送数据服务请求id)
_ff_data = ["10", f"{hex(len(_data_list)).replace('0x', '').zfill(2)}"]
# 首帧的信息由 数据帧类型+数据长度+id + (循环的次数) 剩余位置 用有效数据补
rest_length = 8 - len(_ff_data)
_ff_data.extend(_data_list[:rest_length])
return (_ff_data, "FF", "30"), _data_list[rest_length:]
def get_sn_data(_data_list, _group_sn, is_check=True):
"""
在首帧 占用了序号0 之后,连续帧就从 1开始到 F
:param _data_list: list 有效数据 ['00', '01', '02']
:return:
"""
sn_num = 1
_sn_data_list = []
step = 7
for i in range(0, len(_data_list), step):
sn = f"2{hex(sn_num).replace('0x', '')}"
_cf_data = _data_list[i:i + step]
_cf_data.insert(0, sn)
# sn 最大为 f,
_sn_data_list.append([_cf_data, "SN", None])
if sn_num >= 15:
sn_num = 0
else:
sn_num += 1
if is_check:
_sn_data_list[-1][-1] = "76"
return _sn_data_list
def _set_command(data_list, _group_sn):
loop_data_list = []
# 构造首帧
ff_data, rest_data = get_ff_data(data_list, _group_sn)
loop_data_list.append(ff_data)
# 构造连续帧 (剩余有效数据,构造成 连续帧
sn_data_list = get_sn_data(rest_data, _group_sn)
loop_data_list.extend(sn_data_list)
return loop_data_list
command_big_list = []
# 每128个字节(有效数据)为一组 一个小循环
# 一个小循环分 首帧 6个 其余 122个,7个为一组, 分成9组, 不足一组用 55 补齐
group_step = 128
_group_num = 1
for j in range(0, len(data_list), group_step):
_group_sn = f"{hex(_group_num).replace('0x', '').zfill(2)}"
temp = data_list[j:j + group_step]
if len(temp) >= 7:
command_list = _set_command(temp, _group_sn)
else:
# 少于7个 发单帧 长度增加2 服务id + 编号
base_temp = [f"0{hex(len(temp) + 2).replace('0x', '')}", "36", _group_sn]
base_temp.extend(temp)
command_list = [(base_temp, "SF", "76")]
command_big_list.extend(command_list)
_group_num += 1
# 分组累加到 256(FF) 时,从0开始
if _group_num == 255:
_group_num = 0
return command_big_list