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_Task | 32768 1 | EXTENDED |
映射到任务的功能
触发函数 | 触发类别 | 触发条件 |
---|---|---|
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_handler
在qul_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许可证下使用。
了解更多信息。