您现在的位置是:首页 >技术教程 >基于Python的AutoSAR代码生成器---COM网站首页技术教程

基于Python的AutoSAR代码生成器---COM

liudulab 2024-10-21 00:01:03
简介基于Python的AutoSAR代码生成器---COM

1. 模板引擎-Jinja2

Jinja2是基于python的模板引擎,功能比较类似于于PHP的smarty,J2ee的Freemarker和velocity。 它能完全支持unicode,并具有集成的沙箱执行环境,应用广泛。本文将基于Jinja2强大的功能实现dbc文件生成Com代码,通过此方法可以定制自己的代码生成器。
访问Jinja2官方网站可以找到Jinja2的官方文档,包括中文手册。

2. 开发环境准备

需要安装的软件如下:

  • VScode(1.78.2)
  • Python 3.10.5
    需要安装的第三方库如下:
  • canmatrix
  • Jinja2

3. JinJa2 模板(Com_PbCfg.c)

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 %}
};

3. 代码生成器

Jinja2模板引擎使用基本流程

  • 新建一个FileSystemLoader
loader = FileSystemLoader(searchpath='templates')
  • 创建enviroment
enviroment = Environment(loader=loader,trim_blocks=True)
  • 加载template
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 = 'outputCom_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)

4. 测试使用

通过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,
    },
}
风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。