Application
Application - приложение для системы AFW. Приложение это именно то, что взаимодействует с пользователем (драйвера, в отличие от приложений, обычно не взаимодействуют с пользователем, они работают с железом и приложениями или операционной системой).
Приложение для AFW разрабатывалось таким, чтобы работать из ROM'а, поэтому может вообще не иметь глобальных переменных, все данные должны храниться в структуре приложения, в которой первой должна быть структура APPLICATION_T. Указатель на экземпляр текущего приложения передаётся в каждом обработчике событий, из которых, по сути, и состоит приложение. В приложениях из эльфов немного иначе, как минимум таблица ивентов регистрации должна быть в RAM'е, т.к. база ивентов выделяется динамически. В прошивке коды ивентов назначаются автоматически в процессе компиляции.
Содержание
Таблица ивентов регистрации
Массив кодов ивентов на которые стартует приложение, регистрируется функция старта. Для эльфов это обычно один единственный ивент, код которого записывается в глобальной структуре ldrElf.
Регистрация
Приложение должно быть зарегистрировано в системе AFW, делается это функцией APP_Register.
Регистрируется приложение один раз и удалить её потом будет невозможно, а эльф обычно должен выгружаться из памяти, поэтому нужно исключить совпадение ивентов для выгружаемого эльфа, для этого используется функция ldrRequestEventBase, которая каждый раз возвращает уникальный свободный код ивента который можно использовать как "свои" ивенты. Даже более, следующие 63 кода тоже свободны и никогда не встретятся. При регистрации система запоминает не ивенты, а адресс таблицы, а т.к. память эльфа может быть освобождена данные могут быть изменениы и это может быть источником глюков, от этого никуда не деться. Также после получения базы ивентов нужно провести инициализацию таблиц обработчиков ивентов, т.к. там используются не реальные коды ивентов.
Пример:
UINT32 reserve; UINT32 status; int i; reserve = ldrRequestEventBase(); elf.name = (char *)app_name; elf.app = NULL; elf.evbase = reserve ++; status = APP_Register( &elf.evbase, // указатель на первый элемент таблицы ивентов регистрации 1, // количество элементов в этой таблице state_handling_table, // таблица, описывающая все состояния приложения APP_STATE_MAX, // количество элементов в этой таблице (void *) AppStart ); // функция старта приложения if ( status != RESULT_OK ) return status; // ...
Старт
Функция старта приложения имеет вид:
UINT32 AppStart( EVENT_STACK_T * ev_st, REG_ID_T reg_id, void * reg_hdl );
Параметры:
- ev_st - указатель на стэк событий.
- reg_id - идентификатор регистрации приложения. Когда приложение регистрируется, оно получает уникальный идентификатор регистрации, по которому его можно найти. По reg_id можно определить, что приложение с таким идентификатором уже запущено (см. AFW_InquireRoutingStackByRegId).
- reg_hdr - структура с данными, которые получены при регистрации приложениями.
В начале можно проверить - вдруг это приложение уже запущено:
if( AFW_InquireRoutingStackByRegId( reg_id ) == RESULT_OK ) { return RESULT_FAIL; }
Инициализация
На этой стадии нужно выделить память под структуру и провести инициализацию приложения. Все это делает функция APP_InitAppData.
APPLICATION_T* APP_InitAppData( void *main_event_handler, UINT32 sizeof_app, REG_ID_T reg_id, UINT32 history_size, UINT16 max_state_levels, UINT32 token_priority, UINT8 centricity, UINT8 routing_stack, UINT8 stack_priority );
Параметры:
- функция обработчика ивентов приложения. Лучше воспользоваться уже готовыми функциями из прошивки - APP_HandleEvent для приложений использующих графический интерфейс или APP_HandleEventPrepost для фоновых.
- размер структуры приложения.
- идентификатор регистрации приложения.
- размер элемента стэка истории приложения.
- глубина стэка истории приложения.
- приоритет. =1.
- Дальше идут несколько уровней приоритета приложения. Очевидно, фоновое приложение имеет высший приоритет и раньше поймает событие в обработчике.
- =AFW_APP_CENTRICITY_NONE для фоновых, =AFW_APP_CENTRICITY_SECONDARY для приложений с UIS.
- =AFW_PREPROCESSING для фоновых, =AFW_FOCUS для приложений с UIS.
- приоритет в стэке приложений. =AFW_POSITION_TOP.
Пример:
THISAPP_T * papp; papp = (THISAPP_T *) APP_InitAppData( (void *)APP_HandleEvent, sizeof(THISAPP_T), reg_id, 0, 0, 1, AFW_APP_CENTRICITY_SECONDARY, AFW_FOCUS, AFW_POSITION_TOP );
Если функция вернула не NULL, то приложение можно запустить, после чего приложение будет обрабатывать ивенты.
Запуск
Непосредственный запуск приложения выполняет функция APP_Start. Она должна вернуть RESULT_OK если нет ошибок.
Пример:
status = APP_Start( ev_st, // указатель на стэк событий &papp->apt, // указатель на структуру приложения APP_STATE_INIT, // индекс первого стэйта, в котором стартует приложение state_handling_table, // таблица, описывающая все состояния приложения AppExit, // функция выхода из приложения app_name, // указатель на глобальную константу, содержащую имя приложения NULL ); // указатель на таблицу, описывающую имена стэйтов return status;
Выход
Функция выхода(закрытия) из приложения имеет вид:
UINT32 AppExit( EVENT_STACK_T * ev_st, APPLICATION_T * app );
В этой функции должны быть удалены диалоги, освобождена память и прочие ресурсы, выделенные динамически в процессе работы приложения. Вызвана стандартная функция выхода из приложения.
Таблица состояний (англ. states)
В один момент времени приложение в целом может находиться в одном из состояний, за исключением зарезервированного ANY под индексом 0. От стэйта зависит поведение приложения. Когда на стандартный обработчик событий приложением (задается первым параметром в APP_InitAppData при старте приложения) поступает ивент, он ищет код этого ивента в таблице обработчиков ивентов, которая записана под ANY стэйтом, если там не находит, то ищет в таблице под текущим стэйтом и вызывает обработчик события. Если обработчик ивента вернул чтото отличное от RESULT_OK вызывается функция выхода из приложения. Одно состояние должно иметь:
- идентификатор. Задается через enum в заголовочном файле, при этом ANY_STATE под индексом 0.
- функция входа в стэйт, можно NULL, если такая не нужна.
- функция выхода из стэйта, можно NULL, если такая не нужна.
- указатель на таблицу обработчиков ивентов.
Пример:
static const STATE_HANDLERS_ENTRY_T state_handling_table[] = { APP_STATE_ANY, NULL, NULL, any_state_handlers }, { APP_STATE_INIT, NULL, NULL, init_state_handlers }, { APP_STATE_MAIN, MainStateEnter, MainStateExit, main_state_handlers }//, };
Функция входа в стэйт
Должна иметь вид:
UINT32 StateEnter( EVENT_STACK_T * ev_st, APPLICATION_T * app, ENTER_STATE_TYPE_T type );
type при этом может принимать значения:
- ENTER_STATE_ENTER - обычный вход в стэйт, либо при старте приложения, либо при смене стэйта.
- ENTER_STATE_RESUME - приложение уже находится в этом стэйте, если приложение потеряло фокус, из-за того, что было запущено другое, которое использует UIS, и закрылось. Тоесть потеряло фокус и снова получило.
Функция выхода из стэйта
Должна иметь вид:
UINT32 StateExit( EVENT_STACK_T * ev_st, APPLICATION_T * app, EXIT_STATE_TYPE_T type );
type при этом может принимать значения:
- EXIT_STATE_EXIT - обычный выход из стэйта.
- EXIT_STATE_SUSPEND - когда приложение должно "приостановить" свою активность т.к. оно не имеет фокус.
Таблица обработчиков ивентов
Представляет собой массив элементов типа:
typedef struct { EVENT_CODE_T code; // код ивента EVENT_HANDLER_T *hfunc; // функция, которая обрабатывает ивент с этим кодом } EVENT_HANDLER_ENTRY_T;
В эльфах в этих таблицах не используются реальные коды событий, поэтому после получения базы ивентов нужно инициализировать таблицы:
int i; for ( i=0; i<APP_STATE_MAX; i++ ) reserve = ldrInitEventHandlersTbl((EVENT_HANDLER_ENTRY_T *)state_handling_table[i].htable, reserve);