В serialized-приложении кодеки сериализации обеспечивают механизм для кодирования и декодирования команд и событий между Bluetooth Application Chip и BLE Connectivity Chip.
Риc. 2. Общий формат кодирования пакета сериализации.
Команды и ответы. На следующем рисунке представлен поток команд и ответов, которые передаются в serialized-приложении.
Рис. 3. Курсирование пакетов команд и ответов.
Тип пакета |
Описание |
0x00 Command |
Пакет, отправленный из Application Chip в BLE Connectivity Chip, где он декодируется, и выполняется соответствующая функция SoftDevice. |
0x01 Command Response |
После того, как в принята функция в SoftDevice, в BLE Connectivity Chip кодируется ответ, и в Application Chip отправляется пакет ответа (response packet). |
0x03 DTM Command |
Пакет, отправленный из Application Chip в BLE Connectivity Chip, где он декодируется, и чип входит в режим DTM. |
0x04 DTM Command Response |
Перед тем, как BLE Connectivity Chip войдет в режим DTM, он ответит response-пакетом, передавая этот пакет в Application Chip. |
Примечание: если поле длины недопустимое для определенной команды, то вызов serialized API вернет код ошибки NRF_ERROR_INVALID_LENGTH из кодека в Application Chip.
События. На следующем рисунке показан поток пакетов событий в serialized-приложении.
Рис. 4. Перемещение пакетов событий.
Тип пакета |
Описание |
0x02 Event |
Если в SoftDevice произошло событие, то пакет события (event packet) отправится из BLE Connectivity Chip в Application Chip. |
Ниже описываются определенные правила при кодировании каждого типа данных в serialized-приложении.
Кодирование примитивных аргументов. Аргументы функции кодируются в том же порядке, как они следуют в декларации функции. Когда аргументы передаются по значению (by value), они кодируются как есть (независимо от их размера и порядка следования). Подразумевается, что получатель знает о порядке следования и типе элементов. Возвращаемое значение из функции также кодируется в пакет и посылается в ответе.
Пример:
uint32_t foo(uint32_t arg1, uint8_t arg2);
Пакет запроса:
Тип пакета: 1 байт
Идентификатор функции (Function ID): 1 байт
arg1: 4 байта
arg2: 1 байт
Пакет ответа:
Тип пакета: 1 байт
Идентификатор функции (Function ID): 1 байт
Возвращаемое значение: 4 байта
Кодирование аргументов, переданное по указателю. Если аргументом функции является указатель, то он кодируется в зависимости от характера аргумента.
Если данные, переданные по указателю, это входной аргумент, то он кодируется только в пакете запроса, и не присутствует в пакете ответа. Аргумент, представленный указателем, предшествует в пакете 1-байтным флагом, который указывает, равен ли указатель NULL или нет. Данные присутствуют только если указатель не равен NULL.
Пример:
uint32_t foo(uint32_t * arg1);
Пакет запроса:
Тип пакета: 1 байт
Идентификатор функции (Function ID): 1 байт
Arg1 представляет флаг: 1 байт
arg1: 4 байта (опционально)
Пакет ответа:
Тип пакета: 1 байт
Идентификатор функции (Function ID): 1 байт
Возвращаемое значение: 4 байта
Если аргумент предназначен для вывода данных, то пакет запроса содержит только флаг присутствия и содержит данные аргумента. Пакет ответа содержит как флаг присутствия, так и содержимое данных.
Пример:
uint32_t foo(uint32_t * arg1);
Пакет запроса:
Тип пакета: 1 байт
Идентификатор функции (Function ID): 1 байт
Arg1 представляет флаг: 1 байт
Пакет ответа:
Тип пакета: 1 байт
Идентификатор функции (Function ID): 1 байт
Возвращаемое значение: 4 байта
Arg1 представляет флаг: 1 байт
arg1: 4 байта (опционально)
Если аргумент описан как для ввода/вывода, то его содержимое присутствует как в пакете запроса, так и в пакете ответа.
Кодирование структур. Структуры кодируются таким же способом, как и аргументы функции. Элементы сохраняют определенный порядок следования кроме случаев, когда этот порядок необходимо поменять. Такие изменения необходимы, когда структура содержит поле указателя на данные и поле длины, и поле длины определено после поля указателя на данные. В этом случае важно отправить сначала длину поля перед реальными данными. Если структура содержит в себе вложенные структуры, то они разворачиваются и кодируется в порядке определения.
Пример:
typedef struct
{
uint8_t elementA;
} nested_element_t;
typedef struct
{
uint8_t elementA;
nested_element_t elementB;
uint8_t elementC;
} foo_t;
uint32_t foo(foo_t * p_data);
Пакет запроса:
Тип пакета: 1 байт
Идентификатор функции (Function ID): 1 байт
p_data, флаг присутствия: 1 байт
p_data->elementA: 1 байт
p_data->elementB->elementA: 1 байт
p_data->elementC: 1 байт
Если структура содержит указатели, то применяется то же самое правило разворачивания, например:
typedef struct
{
uint8_t elementA;
} nested_element_t;
typedef struct
{
uint8_t elementA;
nested_element_t* p_elementB;
uint8_t elementC;
} foo_t;
uint32_t foo(foo_t * p_data);
Пакет запроса:
Тип пакета: 1 байт
Идентификатор функции (Function ID): 1 байт
p_data, флаг присутствия: 1 байт
p_data->elementA: 1 байт
p_data->p_elementB, флаг присутствия: 1 байт
p_data->p_elementB->elementA: 1 байт (опционально)
p_data->elementC: 1 байт
Кодирование данных переменной длины. Кодирование длины данных переменной состоит из кодирования длины и буфера. Из-за того, что буфер это указатель, флаг присутствия помещается перед буфером, и он кодируется только если этот указатель не равен NULL. Поле длины кодируется перед данными, независимо от порядка следования аргументов функции или порядка следования полей в структуре.
Пример:
uint32_t foo(foo_t * p_data, uint16_t len);
Пакет запроса:
Тип пакета: 1 байт
Идентификатор функции (Function ID): 1 байт
Длина: 2 байта
p_data, флаг присутствия: 1 байт
p_data, содержимое: n байт
В определенных случаях в SoftDevice API должны быть данные переменной длины, где поле данных не предоставляется. В этом случает применяются другие методы для определения размера буфера переменной длины (например флаг пользовательского типа). В подобных случаях сериализация выполняет парсинг таких данных для определения их длины.
Кодирование битовых полей. Порядок кодирования битовых полей управляется сериализацией, поэтому этот порядок не зависит ни от компилятора, ни от архитектуры.