Jinja2是基于python的模板引擎,功能比较类似于于PHP的smarty,J2ee的Freemarker和velocity。 它能完全支持unicode,并具有集成的沙箱执行环境,应用广泛。本文将基于Jinja2强大的功能实现dbc文件生成Com代码,通过此方法可以定制自己的代码生成器。
访问Jinja2官方网站可以找到Jinja2的官方文档,包括中文手册。
需要安装的软件如下:
Jinja2的模板格式为 *.tpl ,新建一个文件名为Com_PbCfg.c.tpl,编辑写入期待的代码格式。
/**
* @file Com_PbCfg.c
*
* @brief
* Com module configuration file
*
* @details
*
* @author {{ author }}
* @version {{ version }}
* @date {{ date }}
*
* \par
* NOTE:
* (C) Copyright 2023 LiduLab, Inc.
*/
#include "Com.h"
#include "Com_Internal.h"
#if defined(USE_PDUR)
#include "PduR.h"
#endif
//Signal definitions
static const ComSignal_type ComSignal[] =
{
{% for Pdu in ComTxPduCfg %}
{%- for Sgn in Pdu.signals %}
{
.ComBitPosition = {{ Sgn.start_bit }},
.ComBitSize = {{Sgn.size}},
.ComErrorNotification = NULL,
.ComFirstTimeoutFactor = {{Pdu.cycle_time}},
.ComHandleId = ComConf_ComSignal_{{ Sgn.name }},
.ComNotification = NULL,
.ComRxDataTimeoutAction = COM_TIMEOUT_DATA_ACTION_NONE,
.ComSignalEndianess = COM_LITTLE_ENDIAN,
.ComSignalInitValue = NULL,
{% if Sgn.size > 16 %}
.ComSignalType = COM_UINT8_N,
{% elif Sgn.size > 8 %}
.ComSignalType = COM_UINT16,
{% else %}
.ComSignalType = COM_UINT8,
{% endif %}
.ComTimeoutFactor = {{Pdu.cycle_time}},
.ComTimeoutNotification = NULL,
.ComTransferProperty = COM_PENDING,
.ComUpdateBitPosition = 0,
.ComSignalArcUseUpdateBit = FALSE,
.Com_Arc_IsSignalGroup = FALSE,
.ComGroupSignal = NULL,
.Com_Arc_ShadowBuffer_Mask = NULL,
.ComIPduHandleId = ComConf_{{ Pdu.name }},
},
{% endfor -%}
{% endfor %}
{% for Pdu in ComRxPduCfg %}
{%- for Sgn in Pdu.signals %}
{
.ComBitPosition = {{ Sgn.start_bit }},
.ComBitSize = {{Sgn.size}},
.ComErrorNotification = NULL,
.ComFirstTimeoutFactor = {{Pdu.cycle_time}},
.ComHandleId = ComConf_ComSignal_{{ Sgn.name }},
.ComNotification = NULL,
.ComRxDataTimeoutAction = COM_TIMEOUT_DATA_ACTION_NONE,
.ComSignalEndianess = COM_LITTLE_ENDIAN,
.ComSignalInitValue = NULL,
{% if Sgn.size > 16 %}
.ComSignalType = COM_UINT8_N,
{% elif Sgn.size > 8 %}
.ComSignalType = COM_UINT16,
{% else %}
.ComSignalType = COM_UINT8,
{% endif %}
.ComTimeoutFactor = {{Pdu.cycle_time}},
.ComTimeoutNotification = NULL,
.ComTransferProperty = COM_PENDING,
.ComUpdateBitPosition = 0,
.ComSignalArcUseUpdateBit = FALSE,
.Com_Arc_IsSignalGroup = FALSE,
.ComGroupSignal = NULL,
.Com_Arc_ShadowBuffer_Mask = NULL,
.ComIPduHandleId = ComConf_{{ Pdu.name }},
},
{% endfor -%}
{% endfor %}
};
Jinja2模板引擎使用基本流程
loader = FileSystemLoader(searchpath='templates')
enviroment = Environment(loader=loader,trim_blocks=True)
tpl = enviroment.get_template('Com_PbCfg.c.tpl')
newFile = tpl.render()
fout.write(newFile)
完整代码如下:
import sys
import time
import canmatrix.formats
import canmatrix
import os
from datetime import *
from jinja2 import FileSystemLoader, Environment
loader = FileSystemLoader(searchpath='templates')
enviroment = Environment(loader=loader,trim_blocks=True)
RxSgnCfg_list: list= []
TxSgnCfg_list: list= []
def GenCom(author,version,RxPduCfg_list,TxPduCfg_list):
for i in range(len(RxPduCfg_list)):
pdu = RxPduCfg_list[i]
for idxSgn in range(len(pdu.signals)):
pdu.signals[idxSgn].name = pdu.signals[idxSgn].name+'_o'+pdu.name
RxSgnCfg_list.append(pdu.signals[idxSgn])
for i in range(len(TxPduCfg_list)):
pdu = TxPduCfg_list[i]
for idxSgn in range(len(pdu.signals)):
pdu.signals[idxSgn].name = pdu.signals[idxSgn].name+'_o'+pdu.name
TxSgnCfg_list.append(pdu.signals[idxSgn])
GenC(author,version,RxPduCfg_list, TxPduCfg_list)
print('>>> Gen Com DONE <<<')
def GenC(author,version,RxPduCfg_list, TxPduCfg_list):
tpl = enviroment.get_template('Com_PbCfg.c.tpl')
filePath = 'output\Com_PbCfg.c'
newFile = tpl.render(author=author,
version=version,
date=date.today(),
ComRxPduCfg=RxPduCfg_list,
ComTxPduCfg=TxPduCfg_list
)
with open(filePath, 'w') as fout:
fout.write(newFile)
通过canmatrix 读取dbc文件,通过上一章的生成器就可以生成代码。
__author__ = 'Liudulab'
__version__ = '1.0.0'
import sys
import time
import canmatrix.formats
import canmatrix
import os
from GenCom import GenCom
ecu_name = 'ADAS'
ComRxPduCfg_list: list= []
ComTxPduCfg_list: list= []
def loadDbcFile(dbc_name):
dbc_file=canmatrix.formats.loadp_flat(dbc_name)
dbc_file.frames.sort(key=lambda x: x.arbitration_id.id)
for frame in dbc_file.frames:
for ecu_name_in_dbc in frame.receivers:
if ecu_name == ecu_name_in_dbc:
frame.name = frame.name + '_Rx'
for idxSgn in range(len(frame.signals)):
if frame.signals[idxSgn].is_little_endian == False:
frame.signals[idxSgn].start_bit = frame.signals[idxSgn].start_bit-(frame.signals[idxSgn].start_bit%8)+7-(frame.signals[idxSgn].start_bit%8)
frame.signals[idxSgn].is_little_endian = True
frame.signals.sort(key=lambda x: x.start_bit)
ComRxPduCfg_list.append(frame)
for ecu_name_in_dbc in frame.transmitters:
if ecu_name == ecu_name_in_dbc:
frame.name = frame.name + '_Tx'
for idxSgn in range(len(frame.signals)):
if frame.signals[idxSgn].is_little_endian == False:
frame.signals[idxSgn].start_bit = frame.signals[idxSgn].start_bit-(frame.signals[idxSgn].start_bit%8)+7-(frame.signals[idxSgn].start_bit%8)
frame.signals[idxSgn].is_little_endian = True
frame.signals.sort(key=lambda x: x.start_bit)
ComTxPduCfg_list.append(frame)
if __name__ == "__main__":
"""
Main Function used when testing this module!
"""
if not os.path.exists('output'):
os.mkdir('output')
loadDbcFile("ADAS.dbc")
GenCom(__author__,__version__,ComRxPduCfg_list,ComTxPduCfg_list)
生成的代码片段如下所示:
/**
* @file Com_PbCfg.c
*
* @brief
* Com module configuration file
*
* @details
*
* @author Liudulab
* @version 1.0.0
* @date 2023-06-13
*
* \par
* NOTE:
* (C) Copyright 2023 LiduLab, Inc.
*/
#include "Com.h"
#include "Com_Internal.h"
#if defined(USE_PDUR)
#include "PduR.h"
#endif
//Signal definitions
static const ComSignal_type ComSignal[] =
{
{
.ComBitPosition = 7,
.ComBitSize = 8,
.ComErrorNotification = NULL,
.ComFirstTimeoutFactor = 20,
.ComHandleId = ComConf_ComSignal_MRR_LongCtrlTargetAccel_oMRR_2_Tx,
.ComNotification = NULL,
.ComRxDataTimeoutAction = COM_TIMEOUT_DATA_ACTION_NONE,
.ComSignalEndianess = COM_LITTLE_ENDIAN,
.ComSignalInitValue = NULL,
.ComSignalType = COM_UINT8,
.ComTimeoutFactor = 20,
.ComTimeoutNotification = NULL,
.ComTransferProperty = COM_PENDING,
.ComUpdateBitPosition = 0,
.ComSignalArcUseUpdateBit = FALSE,
.Com_Arc_IsSignalGroup = FALSE,
.ComGroupSignal = NULL,
.Com_Arc_ShadowBuffer_Mask = NULL,
.ComIPduHandleId = ComConf_MRR_2_Tx,
},
{
.ComBitPosition = 9,
.ComBitSize = 2,
.ComErrorNotification = NULL,
.ComFirstTimeoutFactor = 20,
.ComHandleId = ComConf_ComSignal_ADAS_LongCtrlTypReqMode_oMRR_2_Tx,
.ComNotification = NULL,
.ComRxDataTimeoutAction = COM_TIMEOUT_DATA_ACTION_NONE,
.ComSignalEndianess = COM_LITTLE_ENDIAN,
.ComSignalInitValue = NULL,
.ComSignalType = COM_UINT8,
.ComTimeoutFactor = 20,
.ComTimeoutNotification = NULL,
.ComTransferProperty = COM_PENDING,
.ComUpdateBitPosition = 0,
.ComSignalArcUseUpdateBit = FALSE,
.Com_Arc_IsSignalGroup = FALSE,
.ComGroupSignal = NULL,
.Com_Arc_ShadowBuffer_Mask = NULL,
.ComIPduHandleId = ComConf_MRR_2_Tx,
},
{
.ComBitPosition = 12,
.ComBitSize = 3,
.ComErrorNotification = NULL,
.ComFirstTimeoutFactor = 20,
.ComHandleId = ComConf_ComSignal_ADAS_LongCtrlTypReqLong_oMRR_2_Tx,
.ComNotification = NULL,
.ComRxDataTimeoutAction = COM_TIMEOUT_DATA_ACTION_NONE,
.ComSignalEndianess = COM_LITTLE_ENDIAN,
.ComSignalInitValue = NULL,
.ComSignalType = COM_UINT8,
.ComTimeoutFactor = 20,
.ComTimeoutNotification = NULL,
.ComTransferProperty = COM_PENDING,
.ComUpdateBitPosition = 0,
.ComSignalArcUseUpdateBit = FALSE,
.Com_Arc_IsSignalGroup = FALSE,
.ComGroupSignal = NULL,
.Com_Arc_ShadowBuffer_Mask = NULL,
.ComIPduHandleId = ComConf_MRR_2_Tx,
},
}