C

实现基本功能

平台上下文概念

Qt Quick Ultralite 核心通过 Qul::Platform::PlatformContext 虚拟类与平台通信。该类包含一组虚拟方法,这些方法必须被重写以提供对硬件资源的访问。每个平台都创建一个由 Qul::Platform::PlatformContext 继承的自定义平台上下文类的实现。

通过 Qul::Platform::getPlatformInstance 函数,Qt Quick Ultralite 核心检索 Qul::Platform::PlatformContext 的特定平台实现。

实现基本功能

本章列出了必须实现的基本功能和类方法,以便一般运行 Qt Quick Ultralite 核心您可以将 platform/boards/qt/example-baremetal/platform_context.cpp 中的内容作为您自己的实现基础,并在指定的位置添加您的代码。

平台上下文实现

平台必须通过从其继承实现 Qul::Platform::PlatformContext 虚拟类。最小实现只需要定义纯虚方法。其他函数返回默认值,并且未强制实施。

struct ExamplePlatform : PlatformContext
{
    // 1. Basics
    double rand() QUL_DECL_OVERRIDE;
    uint64_t update() QUL_DECL_OVERRIDE;
    uint64_t currentTimestamp() QUL_DECL_OVERRIDE;
    void exec() QUL_DECL_OVERRIDE;
    void initializeHardware() QUL_DECL_OVERRIDE;
    void initializePlatform() QUL_DECL_OVERRIDE;
    void scheduleEngineUpdate(uint64_t timestamp) QUL_DECL_OVERRIDE;

    // 2. Log printing
    void consoleWrite(char character) QUL_DECL_OVERRIDE;

    // 3. Graphics
    FrameBufferingType frameBufferingType(const PlatformInterface::LayerEngine::ItemLayer *) const QUL_DECL_OVERRIDE;
    FrameStatistics presentFrame(const PlatformInterface::Screen *screen,
                                 const PlatformInterface::Rect &rect) QUL_DECL_OVERRIDE;
    Qul::PlatformInterface::Screen *availableScreens(size_t *screenCount) const QUL_DECL_OVERRIDE;
    PlatformInterface::DrawingDevice *beginFrame(const PlatformInterface::LayerEngine::ItemLayer *layer,
                                                 const PlatformInterface::Rect &rect,
                                                 int refreshInterval) QUL_DECL_OVERRIDE;
    void endFrame(const PlatformInterface::LayerEngine::ItemLayer *layer) QUL_DECL_OVERRIDE;
    void initializeDisplay(const PlatformInterface::Screen *screen) QUL_DECL_OVERRIDE;
    void waitUntilAsyncReadFinished(const void *begin, const void *end) QUL_DECL_OVERRIDE;
    void flushCachesForAsyncRead(const void *addr, size_t length) QUL_DECL_OVERRIDE;

    // 4. Layers
    PlatformInterface::LayerEngine *layerEngine() QUL_DECL_OVERRIDE;

    // 5. Memory
    PlatformInterface::MemoryAllocator *memoryAllocator(PlatformInterface::MemoryAllocator::AllocationType type)
        QUL_DECL_OVERRIDE;

    // 6. Performance metrics
    Platform::PerformanceMetrics *performanceMetrics(void) QUL_DECL_OVERRIDE;
};

方法和示例实现分别在不同的章节中解释。

  1. 基础 - 实现基本功能 (此页面)
  2. 日志打印 - 实现日志支持
  3. 图形 - 将图形显示在屏幕上
  4. 层 - 实现硬件层支持
  5. 内存 - Qt Quick Ultralite 平台抽象中的内存分配
  6. 性能指标 - 实现性能指标平台 API

必须由 Qul::Platform::getPlatformInstance 返回特定平台的上下文类的实例。

PlatformContext *getPlatformInstance()
{
    static ExamplePlatform platform;
    return &platform;
}

Qt Quick Ultralite 核心使用返回的实例并在运行时调用上下文方法与硬件和平台通信。

初始化硬件

硬件组件的初始化可以在PlatformContext::initializeHardware方法中完成。

这可能包括设置时钟、引脚、外设、总线内存等。

开发者也可以决定不实施,并在例如应用程序的main()函数中自行进行硬件初始化。

void ExamplePlatform::initializeHardware()
{
#if 0
    Replace the following code with actual code for your device.

    setup_system_clocks();
    setup_flash_memory();
    setup_sd_ram();
    setup_usart();
    setup_rnd_generator();
#endif
}

初始化平台

Qt Quick Ultralite平台组件的初始化是在任何图形渲染之前进行的。

根据帧缓冲区的颜色深度,您应该在这里调用Qul::PlatformInterface::init8bppRenderingQul::PlatformInterface::init16bppRenderingQul::PlatformInterface::init24bppRenderingQul::PlatformInterface::init32bppRendering。这将初始化Qt Quick Ultralite核心中基于CPU的备用绘图引擎。除非平台本身提供整个虚拟DrawingEngine API,不依赖默认实现,或者明确使用DrawingEngine::fallbackDrawingEngine(),这是必要的。

void ExamplePlatform::initializePlatform()
{
    Qul::PlatformInterface::init32bppRendering();
    ...

预加载Qt Quick Ultralite内部资源

Qt Quick Ultralite内部资源包含引脚和按钮等与Qul::Controls库链接的应用程序的相关图像数据。

注意:如果不使用预加载,下面的部分可以留作未实现。

Qt Quick Ultralite的资源系统期望在启动主循环之前预处理标记为可预加载的内部资源。(有关如何配置内部资源预加载,请参阅预加载Qt Quick Ultralite内部资源。)为此,链接器脚本定义了包含可预加载内部资源的源和目标地址的符号。可以使用DMA执行复制,或如以下示例所示使用memcpy执行复制。

    ...
extern unsigned char __ModuleResourceDataStart;
extern unsigned char __ModuleResourceDataCacheStart;
extern unsigned char __ModuleResourceDataCacheEnd;
memcpy(&__ModuleResourceDataCacheStart,
       &__ModuleResourceDataStart,
       &__ModuleResourceDataCacheEnd - &__ModuleResourceDataCacheStart);
    ...
#pragma section = "QulModuleResourceData"
#pragma section = "QulModuleResourceData_init"
char *__ModuleResourceDataStart = (char *) (__section_begin("QulModuleResourceData_init"));
char *__ModuleResourceDataCacheStart = (char *) (__section_begin("QulModuleResourceData"));
char *__ModuleResourceDataCacheEnd = (char *) (__section_end("QulModuleResourceData"));
memcpy(__ModuleResourceDataCacheStart,
       __ModuleResourceDataStart,
       (unsigned) __ModuleResourceDataCacheEnd - (unsigned) __ModuleResourceDataCacheStart);

随机数

为了向QML应用程序提供随机数,平台要求PlatformContext::rand被重写。

double ExamplePlatform::rand()
{
    // Replace std::rand() by the proper call to the random number generator on your device, if available.
    const uint32_t number = std::rand();
    return number / (std::numeric_limits<uint32_t>::max() + 1.0);
}

当前时间戳

渲染和计时器的一个基本部分是获取系统的当前时间戳。必须返回方法的PlatformContext::currentTimestamp此系统时间。

uint64_t ExamplePlatform::currentTimestamp()
{
    // Replace this line to make it return the system timestamp in milliseconds.
    return 0;
}

性能指标

请参阅实现性能指标平台API以创建特定于平台的性能指标API的定制实现,涉及堆、栈和CPU负载。

PlatformContext类中定义成员函数ExamplePlatform::performanceMetrics()以提供对ExamplePerformanceMetrics结构的访问权限,以便于Qt Quick Ultralite核心。

Platform::PerformanceMetrics *ExamplePlatform::performanceMetrics(void)
{
    static ExamplePerformanceMetrics metrics;
    return &metrics;
}

渲染循环回调调度

Qt Quick Ultralite的渲染循环和事件处理必须在特定时间调用。Qt Quick Ultralite核心将通过调用PlatformContext::scheduleEngineUpdate通知平台有关它下一个需要的回调时间戳,以执行任务。

void ExamplePlatform::scheduleEngineUpdate(uint64_t timestamp)
{
    nextUpdate = timestamp;
}

下一个必需更新的时间戳存储在一个单个变量中。如果您的平台提供了这些,可以使用硬件定时器或操作系统提供的定时器来实现调度超时。

注意: PlatformContext::scheduleEngineUpdate 的实现可从中断调用,并且必须在中断上下文中安全运行。

void ExamplePlatform::scheduleEngineUpdate(uint64_t timestamp)
{
    nextUpdate = timestamp;
}

主循环

Qt Quick Ultralite 不提供主循环,但需要一个自定义主循环,它在指定时间调用核心引擎。

PlatformContext::update 方法通过调用 Qul::PlatformInterface::updateEngine 来负责核心引擎的单次更新,以更新其计时器并显示动画。它使用前面章节中描述的 Qt Quick Ultralite 核心引擎设置的时间戳。

uint64_t ExamplePlatform::update()
{
    const uint64_t timestamp = this->currentTimestamp();

    if (timestamp >= nextUpdate) {
        // Handle deadline or pending events
        Qul::PlatformInterface::updateEngine(timestamp);
    }

    return nextUpdate;
}

PlatformContext::exec 包含 exec 循环,永久运行,或者至少在应用程序运行期间运行,并负责在适当的时间调用 PlatformContext::update。当核心引擎不需要更新调用时,如果可能,设备可以进入睡眠状态。

如果您计划从您的应用程序而不是 Qt Quick Ultralite 平台驱动主循环,可以跳过其实现,而是在您的应用程序主循环中使用类似的代码,而无需调用 PlatformContext::exec。

PlatformContext::update 返回下一次期望调用的时间戳。比当前时间戳小的时间戳,或者甚至是 0,应该尽快调用 PlatformContext::update。比当前时间戳大的时间戳值意味着平台实现应该在给定的该时间内调用 PlatformContext::update。在预定时间之前,设备可能休眠或进入睡眠模式。

void ExamplePlatform::exec()
{
    while (true) {
        logFlush(); // Flush partially filled log buffer
        const uint64_t timestamp = this->update();

        if (timestamp > Platform::getPlatformInstance()->currentTimestamp()) {
            // The device may yield or go into sleep mode
        }
    }
}

用来休眠或退出的函数必须能够在事件(如触摸事件)被中断传递到 Qt Quick Ultralite 核心或达到下一个预定更新时间时返回。

注意: 如果未实现睡眠或省电模式,CPU 将始终运行在全部负载下。

注意: 如果您不打算使用任何演示、示例、测试、调用 Application::exec() 或 app_common 框架,可以留空函数体。

IAR 的附加函数

为了使时间基础设施工作,IAR 库需要实现附加的函数。有关更多信息,请参阅 IAR 开发者指南。

// The number of times an internal timing event occurs per second
int const CLOCKS_PER_SECOND = 1000;

clock_t clock(void)
{
    QUL_UNUSED(CLOCKS_PER_SECOND);

    // This function should return a value, which after division by CLOCKS_PER_SECOND,
    // is the processor time in seconds.
    return (clock_t) HAL_GetTick();
}

// The time_t type is defined in bxarm/arm/inc/c/time{32,64}.h
#if _DLIB_TIME_USES_64
time_t __time64(time_t *t)
#else
time_t __time32(time_t *t)
#endif
{
    uint64_t timeAtStartup = 0; // Read this from a time source like a real time clock;
    uint64_t currentTimestamp = timestamp();
    // same timestamp as _gettimeofday
    time_t curtime = (time_t) (timeAtStartup + (currentTimestamp / 1000));

    if (t)
        *t = curtime;

    return curtime;
}

char const *__getzone()
{
    // See <IAR>/src/lib/time/getzone.c for documentation
    // For Germany as a default timezone
    return ":GMT+1:GMT+2:0100:032502+0:102502+0";
}

__ATTRIBUTES char *_DstMalloc(size_t);
__ATTRIBUTES void _DstFree(char *);

char *_DstMalloc(size_t s)
{
    // Return a buffer that can hold the maximum number of DST entries of
    // of any timezone available on the device.
    // Each DST entry takes up a structure of 5 bytes plus regular alignment.
    // Instead of a static buffer a dynamically allocated memory can be used as well.

    // With the two entries shown above the required buffer size would be
    // 2 * (5 bytes size + 3 bytes alignment) = 16 bytes

    static char buffert[8 * 4];
    return buffert;
}

void _DstFree(char *p)
{
    // Nothing required here because of static buffer in _DstMalloc
    QUL_UNUSED(p);
}

另请参阅 在应用程序中运行 Qt Quick Ultralite

在特定的 Qt 许可证下可用。
了解更多信息。