C

Qt Quick Ultralite作为AUTOSAR复杂设备驱动程序

概述

本主题提供了如何将Qt Quick Ultralite应用程序集成到AUTOSAR Classic Platform项目中的说明。

复杂驱动器是一个未经AUTOSAR标准化的软件实体,可以通过AUTOSAR接口或基本软件模块API访问或被访问,这是根据AUTOSAR Classic Platform规范中复杂设备驱动器 (CDD)的定义。

本文档假设用户已熟悉AUTOSAR Classic Platform架构及其术语。

RH850 D1M1A平台可用的参考平台适配和文档。

架构

Qt Quick Ultralite作为AUTOSAR的CDD实现。以下图表描述了完整的架构

CDD

Qt Quick Ultralite CDD由应用程序、核心库、平台抽象和平台库组成。

运行时环境

Qt Quick Ultralite CDD通过AUTOSAR接口与AUTOSAR基本软件组件交互,该接口由AUTOSAR工具生成。生成的运行环境(RTE)代码提供可运行的任务,以定期初始化和更新Qt Quick Ultralite。

服务层

服务层响应硬件中断触发相关基本软件组件的中断服务例程。服务层还提供对硬件计时器的访问,这些计时器可用于Qt Quick Ultralite CDD的时间戳

注意:使用服务层API访问硬件计时器可能会产生性能开销。

微控制器抽象层

在AUTOSAR Classic Platform标准中,微控制器抽象层(MCAL)没有图形设备抽象的规范,但是Qt Quick Ultralite CDD在需要时可以利用MCAL。

微控制器

Qt Quick Ultralite使用MCAL支持的资源之外的驱动器。

集成要求

AUTOSAR项目

板级支持包

必须在初始化Qt Quick Ultralite之前初始化MCU特定的板级支持包(BSP)。在基本运行系统初始化期间初始化BSP,并使用AUTOSAR工具配置中断服务例程。

CDD

向AUTOSAR项目添加一个新的CDD组件,命名为Cdd_Qul,其中包含两个可执行的任务:用于初始化的Cdd_Qul_Init以及用于正常操作的Cdd_Qul_Update

使用AUTOSAR软件开发工具为CDD生成源文件。这被称为软件组件模板,在下述代码示例中称为cdd_qul.c

操作系统任务配置

将Qt Quick Ultralite的可执行任务映射到名为Cdd_Qul_Task的新任务中

名称任务堆栈大小(字节)任务类型
Cdd_Qul_Task32768 1EXTENDED

映射到任务的功能

触发函数触发类别触发条件
Cdd_Qul_Init初始化
Cdd_Qul_Update周期性10 ms

注意:1 堆栈大小要求是特定于应用的。作为参考,Qt Quick Ultralite Automotive Cluster Demo需要大约8 kB的堆栈。

任务调度控制

将任务类型设置为EXTENDED,因为Qt Quick Ultralite平台适配通常等待某些事件来触发。该EXTENDED任务类型允许AUTOSAR操作系统在Qt Quick Ultralite等待时调度其他任务。

在Qt Quick Ultralite平台适配中等待垂直消隐间隔的示例

在Qt Quick Ultralite平台适配中的platform_drawing.cpp

void waitForVblank()
{
    while (waitingForVblank) {
        Cdd_Qul_Event_WaitEvent();
    }

    Cdd_Qul_Event_ClearEvent();
}

在AUTOSAR项目的CDD中的cdd_qul.c

void Cdd_Qul_Event_WaitEvent(void)
{
    (void)WaitEvent(...); // Operating system API
}

void Cdd_Qul_Event_ClearEvent(void)
{
    (void)GetEvent(...); // Operating system API
    (void)ClearEvent(...); // Operating system API
}

Qt Quick Ultralite

应用构建

将Qt Quick Ultralite应用作为静态库构建以与AUTOSAR项目链接。

注意:如果平台适配名称包含"autosar",则默认将应用程序构建为静态库。

动态内存

在Qt Quick Ultralite平台抽象中的内存分配需要堆管理器来处理动态内存分配请求。对于AUTOSAR项目,堆管理器应该为动态内存保留一个预分配区域。堆管理器还应该最小化内存碎片化,并且其执行时间应该是确定的。

为应用代码中的C++标准容器设置Qt Quick Ultralite内存分配器,以利用动态内存分配请求相同的预分配堆区域。

时间戳

Qt Quick Ultralite需要提供一个用于平台适配的时间戳

您可以通过生成的CDD代码查询当前的系统时间戳。以下示例中,一个名为Cdd_Qul_Timestamp的函数被实现到了一个名为cdd_qul.c的CDD软件组件模板文件中。这个新函数将由Qt Quick Ultralite平台适配器调用。

在Qt Quick Ultralite平台适配中存在的platform_context.cpp文件

uint64_t currentTimestamp() QUL_DECL_OVERRIDE { return Cdd_Qul_Timestamp(); }

在AUTOSAR项目的CDD中的cdd_qul.c

uint64 Cdd_Qul_Timestamp(void)
{
    static uint64 timestampMilliseconds = 0;
    ...
    // Read a counter value or timestamp ...
    timestampMilliseconds += ...;

    return timestampMilliseconds;
}

注意:使用服务层API通过硬件计时器访问可能会产生性能开销。建议通过GPT驱动器、硬件寄存器或MCU BSP API来访问计时器。

CDD功能操作

初始化

Cdd_Qul_Init配置为一个初始化可运行的任务。

Cdd_Qul_Init可运行的任务中调用以下函数

在AUTOSAR项目的CDD中的cdd_qul.c

#include <qul_run.h>
...
void Cdd_Qul_Init(void)
{
    qul_init_hardware();
    qul_init_platform();
    qul_init_application();
}

注意:具有qul_init_*前缀的C语言链接函数在qul_run.h中公开。

注意:在初始化Qt Quick Ultralite之前,必须先初始化MCU特定BSP。

正常操作

在正常操作期间,Cdd_Qul_Update会被周期性地触发。例如,每10毫秒。

注意:Qt Quick Ultralite的更新周期应短于显示刷新率,以避免掉帧。

Cdd_Qul_Update可运行的任务中调用以下函数

在AUTOSAR项目的CDD中的cdd_qul.c

#include <qul_run.h>
...
void Cdd_Qul_Update(void)
{
    (void)qul_update_engine();
}

日志记录

consoleWrite日志数据转发到CDD

platform_context.cpp:

void consoleWrite(char character) QUL_DECL_OVERRIDE { Cdd_Qul_Log_Console_Write(character); }

以下是在cdd_qul.c中的日志记录示例实现,该实现将调试消息发送到AUTOSAR DLT

void Cdd_Qul_Log_Console_Write(char character)
{
    static char logBuffer[256];
    static uint16 logBufferIndex = 0;

    logBuffer[logBufferIndex++] = character;

    if ((character == 0) || (character == '\n') || (logBufferIndex == (sizeof(logBuffer) - 1))) {
        logBuffer[logBufferIndex] = 0;

        Dlt_MessageLogInfoType logInfo;
        logInfo.Dlt_MessageLogLevelType = DLT_LOG_DEBUG;
        // ...

        Rte_Call_DLT_Service_SendLogMessage(
            &logInfo,
            (const uint8*)logBuffer,
            logBufferIndex);

        logBufferIndex = 0;
    }
}

注意:要使用DLT服务,它必须包含在软件集成包(SIP)中,并且需要将SendLogMessage服务端口连接到Qt Quick Ultralite CDD。

故障操作

Qt Quick Ultralite库中的致命错误通过错误报告API进行报告。注册一个自定义错误处理程序以接收由Qt Quick Ultralite检测到的致命错误的回调。

cdd_qul.c中注册自定义错误处理程序

#include <qul_run.h>
...
void Cdd_Qul_Init(void)
{
    (void)qul_set_error_handler(Cdd_Qul_Error_Handler); // Calls Qul::setErrorHandler()
    qul_init_hardware();
    ...
}

注意:C语言链接函数qul_set_error_handlerqul_run.h中公开。

自定义错误处理程序的实现是项目特定的。但是,错误处理程序不得返回,因为Qt Quick Ultralite软件栈已经处于无效状态。

以下是在cdd_qul.c中的示例错误处理程序实现,该实现将错误消息发送到AUTOSAR DLT和一个错误事件发送到AUTOSAR DET

void Cdd_Qul_Error_Handler(enum QulError code, unsigned int lineNumber, int param1, int param2, int param3)
{
    Dlt_MessageLogInfoType logInfo;
    logInfo.Dlt_MessageLogLevelType = DLT_LOG_FATAL;
    // ...
    const char* logData = qul_error_code_to_string(code);
    uint16 logDataLength = strlen(logData);

    Rte_Call_DLT_Service_SendLogMessage(
        &logInfo,
        (const uint8*)logData,
        logDataLength);

    uint8 apiId = ...;
    uint8 errorId = ...;
    Rte_Call_DET_Service_ReportError(
        apiId,
        errorId);

    // QUL CDD in an invalid state
    while(1);
}

注意:要从错误报告API报告的错误中进行恢复,必须重新初始化整个Qt Quick Ultralite软件栈。ECU或MCU必须重置,因为Qt Quick Ultralite不支持卸载。

注意:要使用DLT服务,它必须包含在软件集成包(SIP)中,并且需要将SendLogMessage服务端口连接到Qt Quick Ultralite CDD。

注意:要使用DET服务,它必须包含在软件集成包(SIP)中,并且需要将ReportError服务端口连接到Qt Quick Ultralite CDD。

应用程序开发

对AUTOSAR接口的调用

建议仅从以前示例中显示的生成的软件组件模板文件调用AUTOSAR API函数。这样,当软件组件模板文件被重新生成时,您不需要重新编译Qt Quick Ultralite应用程序或平台库。

控制用户界面元素

在与Qt Quick Ultralite引擎更新相关联之前,必须在Cdd_Qul_Update可运行程序中对AUTOSAR接口进行交互。这确保了所有值更改都在GUI应用程序中可见。

将C链接函数添加到Qt Quick Ultralite应用程序代码中,以从cdd_qul.c控制用户界面元素

Qt Quick Ultralite应用程序的业务逻辑

struct VehicleStatus : public Qul::Singleton<VehicleStatus>
{
    Qul::Property<int> speed;
    Qul::Property<int> rpm;
};

extern "C" {
void qul_application_set_speed(int speed)
{
    VehicleStatus::instance().speed.setValue(speed);
}

void qul_application_set_rpm(int rpm)
{
    VehicleStatus::instance().rpm.setValue(rpm);
}
}

cdd_qul.c:

void Cdd_Qul_Update(void)
{
    int speed;

    // Reading a single value from the AUTOSAR Interface:
    if (Rte_Read_Cdd_Qul_Speed_Value(&speed) == RTE_E_OK) {
        qul_application_set_speed(speed);
    }

    // Reading a single message from the AUTOSAR Interface:
    MyMessageQueueMessage rawMessage;

    if (Rte_Receive_Qul_Message_Queue_Message(rawMessage) == RTE_E_OK) {
        MyMessage* message = (MyMessage*)&rawMessage;

        if (message->id == MyMessageId_RPM) {
            qul_application_set_rpm(message->value);
        }
    }

    (void)qul_update_engine(); // Calls Qul::Application::update()
}

Rte_Type.h:

// Example of a raw message format
typedef uint8_t msg[8];
typedef msg MyMessageQueueMessage;

my_message.h:

// Example of an user defined message ID and struct:
typedef enum {
    MyMessageId_RPM,
    ...
} MyMessageId;

typedef struct {
    int id;
    int value;
} MyMessage;

注意事项

  • 如果您想从AUTOSAR接口读取值或消息,请使用AUTOSAR工具将接收器端口添加并连接到Qt Quick Ultralite CDD。
  • Qul::Property::setValue()不是线程安全的,只能从Cdd_Qul_Update可运行程序中调用。

《仪表板集群》示例演示了如何从C应用程序控制用户界面元素。

另请参阅将C++代码与QML集成.

可在某些Qt许可证下使用。
了解更多信息。