C
基本関数の実装
プラットフォームコンテキストの概念
Qt Quick UltraliteコアはQul::Platform::PlatformContext 仮想クラスを通してプラットフォームと通信します。このクラスはハードウェアリソースへのアクセスを提供するために実装されなければならない一連の仮想メソッドを含んでいます。各プラットフォームはQul::Platform::PlatformContext を継承して、プラットフォーム・コンテキスト・クラスの実装を作成します。
Qul::Platform::PlatformContext のプラットフォーム固有の実装は、Qul::Platform::getPlatformInstance 関数を通してQt Quick Ultralite core によって取得されます。
基本関数の実装
この章では、Qt Quick Ultralite coreを実行するために実装しなければならない基本関数とクラスメソッドを示します。あなた自身の実装の基礎としてplatform/boards/qt/example-baremetal/platform_context.cpp の内容を利用し、指定された場所にコードを追加することができます。
プラットフォームコンテキストの実装
プラットフォームはQul::Platform::PlatformContext 仮想クラスを継承して実装する必要があります。
struct ExamplePlatform : PlatformContext
{
void initializeHardware() QUL_DECL_OVERRIDE;
void initializePlatform() QUL_DECL_OVERRIDE;
void exec() QUL_DECL_OVERRIDE;
uint64_t update() QUL_DECL_OVERRIDE;
double rand() QUL_DECL_OVERRIDE;
void scheduleEngineUpdate(uint64_t timestamp) QUL_DECL_OVERRIDE;
uint64_t currentTimestamp() QUL_DECL_OVERRIDE;
void consoleWrite(char character) QUL_DECL_OVERRIDE;注: これらのメソッドとその実装例は、プラットフォーム移植ガイドのさまざまな章で説明されています。
プラットフォーム固有のコンテキストクラスのインスタンスは、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
}
...プラットフォームの初期化
PlatformContext::intializePlatform は、Qt Quick Ultraliteエンジンが実行される前に呼び出され、ボード固有のリソースをセットアップする必要があります。
これは主にグラフィック・リソースに使用されるので、今のところ空にしておくことができます。
void PlatformContext::intializePlatform() {
Qul::PlatformInterface::log("Called platform initialization\n");
}現在のタイムスタンプ
レンダリングとタイマーに不可欠なのは、システムの現在のタイムスタンプを取得することです。メソッドPlatformContext::currentTimestamp は、このシステム時刻を返す必要があります。
uint64_t ExamplePlatform::currentTimestamp()
{
// Replace this line to make it return the system timestamp in milliseconds.
return 0;
}レンダリングループのコールバックスケジュール
Qt Quick Ultraliteのレンダリングループとイベント処理は、指定された時間に呼び出されなければなりません。
Qt Quick Ultraliteコアは、PlatformContext::scheduleEngineUpdate を呼び出して、タスクを実行するためにコールバックする必要がある次のタイムスタンプをプラットフォームに通知します。
void ExamplePlatform::scheduleEngineUpdate(uint64_t timestamp)
{
nextUpdate = timestamp;
}タイムスタンプの引数は、レンダリングループが次に実行される必要がある時間を指定します。ハードウェアタイマーやOSが提供するタイマーを使って、スケジューリングタイムアウトを実装することができる。簡単な解決策は、このタイムアウトを変数に格納し、以下の関数で使用することです。
警告 PlatformContext::scheduleEngineUpdate の実装は割り込みから呼び出すことができ、割り込みコンテキスト内で実行しても安全でなければなりません。
レンダリングループの更新
Qt Quick Ultraliteエンジンは一定回数呼び出される必要があります。
PlatformContext::update メソッドは、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;
}この関数は、次に呼び出されると予想されるときのタイムスタンプを返します。タイムスタンプが現在のタイムスタンプより小さい場合、あるいは0であっても、できるだけ早く再度呼び出す必要があります。現在のタイムスタンプよりも大きなタイムスタンプ値は、プラットフォーム実装 がその指定された時刻にPlatformContext::update 。スケジュールされた時間まで、デバイスは降伏するか、スリープ・モードに入るかもしれない。
この関数は、PlatformContext::scheduleEngineUpdate によってスケジュールされたタイムスタンプがすでに経過しているかどうかをチェックするため、何度でも呼び出すことができます。スケジュールされた時刻を別の方法で処理したい場合は、PlatformInterface::updateEngine の呼び出しだけが不可欠である。
メインループ
PlatformContext::exec は実行ループを含み、永久に、あるいは少なくともアプリケーションが実行されている限り実行され、適切なタイミングでPlatformContext::update を呼び出す役割を果たします。コア・エンジンによる更新呼び出しが必要ない場合、デバイスは可能であればスリープ状態に入ることができる。
Qt Quick Ultraliteプラットフォームの代わりにアプリケーションからメイン・ループを駆動することを計画している場合は、その実装を省略し、代わりにアプリケーションのメイン・ループに同様のコードを記述して、PlatformContext::exec を呼び出すことなく使用することができます。
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フレームワークを使用しない場合のみです。
乱数
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);
}基本的なメモリ割り当て
Qt Quick Ultralite コアライブラリは以下の関数を使用して小さなメモリ割り当てを処理します:
これらの呼び出しは以下のようにプラットフォーム固有の関数に転送することができます:
void *qul_malloc(std::size_t size)
{
return std::malloc(size);
}
void qul_free(void *ptr)
{
std::free(ptr);
}
void *qul_realloc(void *ptr, size_t s)
{
return std::realloc(ptr, s);
}グラフィックス関連のすべてのメモリ割り当てについては、このガイドの後半で取り上げます。
IAR コンパイラのための追加関数
時間インフラストラクチャを動作させるために、IAR ライブラリは追加関数を実装する必要があります。これらは、.c ファイルに記述するか、extern "C" セクションに記述することで、C-linkage が必要です。詳細については、IAR の "IAR C/C++ Developer Guide "を参照してください。
// 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);
}