Открыть главное меню

Application: различия между версиями

(Старт)
 
(не показано 6 промежуточных версий 2 участников)
Строка 1:Строка 1:
 
Application - приложение для системы [[AFW]]. Приложение это именно то, что взаимодействует с пользователем (драйвера, в отличие от приложений, обычно не взаимодействуют с пользователем, они работают с железом и приложениями или [[OS|операционной системой]]).
 
Application - приложение для системы [[AFW]]. Приложение это именно то, что взаимодействует с пользователем (драйвера, в отличие от приложений, обычно не взаимодействуют с пользователем, они работают с железом и приложениями или [[OS|операционной системой]]).
  
Приложение для AFW разрабатывалось таким, чтобы работать из [[ROM]]'а, поэтому может вообще не иметь глобальных переменных, все данные должны храниться в структуре приложения, в которой первой должна быть структура [[APPLICATION_T]]. Указатель на экземпляр текущего приложения передаётся в каждом обработчике событий, из которых по сути и состоит приложение. В приложениях из эльфов немного иначе, как минимум таблица ивентов регистрации должна быть в [[RAM]]'е, т.к. база ивентов выделяется динамически. В прошивке коды ивентов назначаются автоматически в процессе компиляции.
+
Приложение для AFW разрабатывалось таким, чтобы работать из [[ROM]]'а, поэтому может вообще не иметь глобальных переменных, все данные должны храниться в структуре приложения, в которой первой должна быть структура [[APPLICATION_T]]. Указатель на экземпляр текущего приложения передаётся в каждом обработчике событий, из которых, по сути, и состоит приложение. В приложениях из эльфов немного иначе, как минимум таблица ивентов регистрации должна быть в [[RAM]]'е, т.к. база ивентов выделяется динамически. В прошивке коды ивентов назначаются автоматически в процессе компиляции.
  
 +
<metadesc>Application - приложение для системы AFW. Приложение это именно то, что взаимодействует с пользователем (драйвера, в отличие от приложений, обычно не взаимодействуют с пользователем, они работают с железом и приложениями или операционной системой).</metadesc>
  
 
== Таблица [[Event|ивентов]] регистрации ==
 
== Таблица [[Event|ивентов]] регистрации ==
Массив кодов ивентов на которые стартует приложение, регистрируется функция старта. Для эльфов это обычно один единственный ивент код которого записывается в глобальной структуре [[ldrElf]].
+
Массив кодов ивентов на которые стартует приложение, регистрируется функция старта. Для эльфов это обычно один единственный ивент, код которого записывается в глобальной структуре [[ldrElf]].
  
 
== Регистрация ==
 
== Регистрация ==
Приложение должно быть зарегестрировано в системе [[AFW]], делается это функцией [[APP_Register]].
+
Приложение должно быть зарегистрировано в системе [[AFW]], делается это функцией [[APP_Register]].
  
Регистрируется приложение один раз и удалить регистрацию потом будет невозможно, а эльф обычно должен выгружаться из памяти, поэтому нужно исключить совпадение ивентов для выгружаемого эльфа, для этого используется функция [[ldrRequestEventBase]], которая каждый раз возвращает уникальный свободный код ивента который можно использовать как "свои" ивенты. Даже более, следующие 63 кода тоже свободны и никогда не встретятся. При регистрации система запоминает не ивенты, а адресс таблицы, а т.к. память эльфа может быть освобождена данные могут быть изменениы и это может быть источником глюков, от этого никуда не деться.
+
Регистрируется приложение один раз и удалить её потом будет невозможно, а эльф обычно должен выгружаться из памяти, поэтому нужно исключить совпадение ивентов для выгружаемого эльфа, для этого используется функция [[ldrRequestEventBase]], которая каждый раз возвращает уникальный свободный код ивента который можно использовать как "свои" ивенты. Даже более, следующие 63 кода тоже свободны и никогда не встретятся. При регистрации система запоминает не ивенты, а адресс таблицы, а т.к. память эльфа может быть освобождена данные могут быть изменениы и это может быть источником глюков, от этого никуда не деться. Также после получения базы ивентов нужно провести инициализацию таблиц обработчиков ивентов, т.к. там используются не реальные коды ивентов.
  
 
Пример:
 
Пример:
Строка 16:Строка 17:
 
UINT32 reserve;
 
UINT32 reserve;
 
UINT32 status;
 
UINT32 status;
 +
int i;
  
 
reserve = ldrRequestEventBase();
 
reserve = ldrRequestEventBase();
Строка 21:Строка 23:
 
elf.app = NULL;
 
elf.app = NULL;
 
elf.evbase = reserve ++;
 
elf.evbase = reserve ++;
 +
 
status = APP_Register( &elf.evbase, // указатель на первый элемент таблицы ивентов регистрации
 
status = APP_Register( &elf.evbase, // указатель на первый элемент таблицы ивентов регистрации
 
1,                    // количество элементов в этой таблице
 
1,                    // количество элементов в этой таблице
Строка 36:Строка 39:
 
Параметры:
 
Параметры:
 
* ev_st - указатель на [[Event_Stack|стэк событий]].
 
* ev_st - указатель на [[Event_Stack|стэк событий]].
* reg_id - идентификатор регистрации приложения. Когда приложение регистрируется оно получает уникальный идентификатор регистрации, по которому его можно найти. По reg_id можно определить что приложение с таким идентификатором уже запущено (см. [[AFW_InquireRoutingStackByRegId]]).
+
* reg_id - идентификатор регистрации приложения. Когда приложение регистрируется, оно получает уникальный идентификатор регистрации, по которому его можно найти. По reg_id можно определить, что приложение с таким идентификатором уже запущено (см. [[AFW_InquireRoutingStackByRegId]]).
 
* reg_hdr - структура с данными, которые получены при регистрации приложениями.
 
* reg_hdr - структура с данными, которые получены при регистрации приложениями.
В начале можно проверить, вдруг это приложение уже папущено:
+
В начале можно проверить - вдруг это приложение уже запущено:
 
<pre>
 
<pre>
 
if( AFW_InquireRoutingStackByRegId( reg_id ) == RESULT_OK ) {
 
if( AFW_InquireRoutingStackByRegId( reg_id ) == RESULT_OK ) {
Строка 44:Строка 47:
 
}</pre>
 
}</pre>
 
=== Инициализация ===
 
=== Инициализация ===
На этой стадии нужно выделить память под структуру и провести инициализацию приложения. Все это делает функция [[APP_InitAppData]]. Параметры:
+
На этой стадии нужно выделить память под структуру и провести инициализацию приложения. Все это делает функция [[APP_InitAppData]].  
* адресс функции обработчика ивентов приложения. Лучше воспользоваться уже готовыми в прошивке - [[APP_HandleEvent]] для приложений использующих [[UIS|графический интерфейс]] или [[APP_HandleEventPrepost]] для фоновых.
+
 
 +
<pre>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 );</pre>
 +
 
 +
Параметры:
 +
* функция обработчика ивентов приложения. Лучше воспользоваться уже готовыми функциями из прошивки - [[APP_HandleEvent]] для приложений использующих [[UIS|графический интерфейс]] или [[APP_HandleEventPrepost]] для фоновых.
 
* размер структуры приложения.
 
* размер структуры приложения.
 
* идентификатор регистрации приложения.
 
* идентификатор регистрации приложения.
Строка 52:Строка 67:
 
* приоритет. =1.
 
* приоритет. =1.
 
:Дальше идут несколько уровней приоритета приложения. Очевидно, фоновое приложение имеет высший приоритет и раньше поймает событие в обработчике.
 
:Дальше идут несколько уровней приоритета приложения. Очевидно, фоновое приложение имеет высший приоритет и раньше поймает событие в обработчике.
* =AFW_APP_CENTRICITY_PRIMARY для фоновых, =AFW_APP_CENTRICITY_SECONDARY для приложений с [[UIS]].
+
* =AFW_APP_CENTRICITY_NONE для фоновых, =AFW_APP_CENTRICITY_SECONDARY для приложений с [[UIS]].
 
* =AFW_PREPROCESSING для фоновых, =AFW_FOCUS для приложений с UIS.
 
* =AFW_PREPROCESSING для фоновых, =AFW_FOCUS для приложений с UIS.
 
* приоритет в стэке приложений. =AFW_POSITION_TOP.
 
* приоритет в стэке приложений. =AFW_POSITION_TOP.
Строка 72:Строка 87:
 
</pre>
 
</pre>
 
Если функция вернула не NULL, то приложение можно запустить, после чего приложение будет обрабатывать ивенты.
 
Если функция вернула не NULL, то приложение можно запустить, после чего приложение будет обрабатывать ивенты.
 
  
 
=== Запуск ===
 
=== Запуск ===
Строка 82:Строка 96:
 
APP_Start( ev_st,      // указатель на стэк событий
 
APP_Start( ev_st,      // указатель на стэк событий
 
&papp->apt,    // указатель на структуру приложения
 
&papp->apt,    // указатель на структуру приложения
APP_STATE_INIT, // индеск первого стэйта, в котором стартует приложение
+
APP_STATE_INIT, // индекс первого стэйта, в котором стартует приложение
 
state_handling_table, // таблица, описывающая все состояния приложения
 
state_handling_table, // таблица, описывающая все состояния приложения
 
AppExit,        // функция выхода из приложения
 
AppExit,        // функция выхода из приложения
Строка 93:Строка 107:
 
== Выход ==
 
== Выход ==
 
Функция выхода(закрытия) из приложения имеет вид:
 
Функция выхода(закрытия) из приложения имеет вид:
<pre>UINT32 AppExit( EVENT_STACK_T * ev_st, APPLICATION_T * app );</pre>
+
'''<pre>UINT32 AppExit( EVENT_STACK_T * ev_st, APPLICATION_T * app );</pre>
 
В этой функции должны быть удалены диалоги, освобождена память и прочие ресурсы, выделенные динамически в процессе работы приложения. Вызвана стандартная функция выхода из приложения.
 
В этой функции должны быть удалены диалоги, освобождена память и прочие ресурсы, выделенные динамически в процессе работы приложения. Вызвана стандартная функция выхода из приложения.
  
  
 
== Таблица состояний ({{lang-en|states}}) ==
 
== Таблица состояний ({{lang-en|states}}) ==
В один момент времени приложение в целом может находиться в одном из состояний, за исключением зарезервированного ANY под индексом 0. От стэйта зависит поведение приложения. Когда на стандартный обработчик событий приложением (задается первым параметром в [[APP_InitAppData]] при старте приложения) поступает ивент он ищет код этого ивента в таблице обработчиков ивентов, которая записана под ANY стэйтом, если там не находит, то ищет в таблице под текущим стэйтом и вызывает обработчик события. Если обработчик ивента вернул чтото отличное от RESULT_OK вызывается функция выхода из приложения.
+
В один момент времени приложение в целом может находиться в одном из состояний, за исключением зарезервированного ANY под индексом 0. От стэйта зависит поведение приложения. Когда на стандартный обработчик событий приложением (задается первым параметром в [[APP_InitAppData]] при старте приложения) поступает ивент, он ищет код этого ивента в таблице обработчиков ивентов, которая записана под ANY стэйтом, если там не находит, то ищет в таблице под текущим стэйтом и вызывает обработчик события. Если обработчик ивента вернул чтото отличное от RESULT_OK вызывается функция выхода из приложения.
 
Одно состояние должно иметь:
 
Одно состояние должно иметь:
 
* идентификатор. Задается через enum в заголовочном файле, при этом ANY_STATE под индексом 0.
 
* идентификатор. Задается через enum в заголовочном файле, при этом ANY_STATE под индексом 0.
Строка 140:Строка 154:
  
 
=== Таблица обработчиков ивентов ===
 
=== Таблица обработчиков ивентов ===
Представляет из себя массив элементов типа:
+
Представляет собой массив элементов типа:
 
<pre>typedef struct
 
<pre>typedef struct
 
{
 
{
Строка 146:Строка 160:
 
EVENT_HANDLER_T *hfunc; // функция, которая обрабатывает ивент с этим кодом
 
EVENT_HANDLER_T *hfunc; // функция, которая обрабатывает ивент с этим кодом
 
} EVENT_HANDLER_ENTRY_T;</pre>
 
} EVENT_HANDLER_ENTRY_T;</pre>
 +
В эльфах в этих таблицах не используются реальные коды событий, поэтому после получения базы ивентов нужно инициализировать таблицы:
 +
<pre>
 +
int i;
 +
for ( i=0; i<APP_STATE_MAX; i++ )
 +
reserve = ldrInitEventHandlersTbl((EVENT_HANDLER_ENTRY_T *)state_handling_table[i].htable, reserve);
 +
</pre>
 +
 +
 +
[[Категория:Эльфостроение]]

Текущая версия на 05:29, 1 апреля 2019

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 );

Параметры:

Дальше идут несколько уровней приоритета приложения. Очевидно, фоновое приложение имеет высший приоритет и раньше поймает событие в обработчике.
  • =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);