diff --git a/app/Kconfig b/app/Kconfig index e8142fa0..5a7b7cb4 100644 --- a/app/Kconfig +++ b/app/Kconfig @@ -90,6 +90,15 @@ menu "ZSWatch" default 100 endmenu endmenu + + config APPLICATIONS_USE_LEA_ASSISTANT + bool + select BT_CENTRAL + select BT_AUDIO + select BT_BAP_BROADCAST_ASSISTANT + select BT_TINYCRYPT_ECC + prompt "Activate the application 'LE Audio Assistant'" + default n endmenu menu "Watchface" @@ -255,5 +264,6 @@ menu "ZSWatch" rsource "src/applications/notification/Kconfig" rsource "src/applications/trivia/Kconfig" rsource "src/applications/ppt_remote/Kconfig" + rsource "src/applications/lea_assistant/Kconfig" endmenu endmenu diff --git a/app/child_image/hci_ipc.conf b/app/child_image/hci_ipc.conf index e94584eb..8e608b88 100644 --- a/app/child_image/hci_ipc.conf +++ b/app/child_image/hci_ipc.conf @@ -1,47 +1,53 @@ -CONFIG_BT_EXT_ADV=y - -CONFIG_BT_CTLR=y -CONFIG_BT_LL_SW_SPLIT=y - -CONFIG_BT_CTLR_ADV_EXT=y -CONFIG_BT_CTLR_ADV_PERIODIC=y - -CONFIG_BT_CTLR_DF=y - -CONFIG_BT_CTLR_DF_SCAN_CTE_RX=n -CONFIG_BT_CTLR_DF_ANT_SWITCH_RX=n -CONFIG_BT_CTLR_DF_CTE_RX=n - -# Limit number of possible connection to decrease memory usage -CONFIG_BT_MAX_CONN=1 - -# Enable chaining of multiple CTEs in periodic advertising -CONFIG_BT_CTLR_ADVANCED_FEATURES=y -CONFIG_BT_CTLR_ADV_SYNC_PDU_BACK2BACK=y -CONFIG_BT_CTLR_DF_PER_ADV_CTE_NUM_MAX=16 - -CONFIG_BT_CTLR_TX_PWR_0=y -CONFIG_BT_CTLR_ADV_DATA_LEN_MAX=191 - -# Enable chaining of multiple CTEs in periodic advertising -CONFIG_BT_CTLR_ADVANCED_FEATURES=y -CONFIG_BT_CTLR_ADV_SYNC_PDU_BACK2BACK=y -CONFIG_BT_CTLR_DF_PER_ADV_CTE_NUM_MAX=16 - -CONFIG_BT_CTLR_DF_ANT_SWITCH_TX=n -CONFIG_BT_BROADCASTER=y - -CONFIG_BT_EXT_ADV_MAX_ADV_SET=2 -CONFIG_BT_CTLR_ADV_AUX_SET=2 -CONFIG_BT_TICKER_UPDATE=y - -CONFIG_CLOCK_CONTROL_NRF_K32SRC_RC=y -# DFU over BT requires -# increase of ble throughput -CONFIG_BT_BUF_ACL_RX_SIZE=502 -CONFIG_BT_BUF_ACL_TX_SIZE=502 - -# Temporary fix as there is a strange behaviour with some Android -# phones. -CONFIG_BT_DATA_LEN_UPDATE=n -#CONFIG_BT_CTLR_DATA_LENGTH_MAX=251 +CONFIG_BT_EXT_ADV=y + +CONFIG_BT_CTLR=y +CONFIG_BT_LL_SW_SPLIT=y + +CONFIG_BT_CTLR_ADV_EXT=y +CONFIG_BT_CTLR_ADV_PERIODIC=y + +CONFIG_BT_CTLR_DF=y + +CONFIG_BT_CTLR_DF_SCAN_CTE_RX=n +CONFIG_BT_CTLR_DF_ANT_SWITCH_RX=n +CONFIG_BT_CTLR_DF_CTE_RX=n + +# Limit number of possible connection to decrease memory usage +CONFIG_BT_MAX_CONN=3 + +# Enable chaining of multiple CTEs in periodic advertising +CONFIG_BT_CTLR_ADVANCED_FEATURES=y +CONFIG_BT_CTLR_ADV_SYNC_PDU_BACK2BACK=y +CONFIG_BT_CTLR_DF_PER_ADV_CTE_NUM_MAX=16 + +CONFIG_BT_CTLR_TX_PWR_0=y +CONFIG_BT_CTLR_ADV_DATA_LEN_MAX=191 + +# Enable chaining of multiple CTEs in periodic advertising +CONFIG_BT_CTLR_ADVANCED_FEATURES=y +CONFIG_BT_CTLR_ADV_SYNC_PDU_BACK2BACK=y +CONFIG_BT_CTLR_DF_PER_ADV_CTE_NUM_MAX=16 + +CONFIG_BT_CTLR_DF_ANT_SWITCH_TX=n +CONFIG_BT_BROADCASTER=y + +CONFIG_BT_EXT_ADV_MAX_ADV_SET=2 +CONFIG_BT_CTLR_ADV_AUX_SET=2 +CONFIG_BT_TICKER_UPDATE=y + +CONFIG_CLOCK_CONTROL_NRF_K32SRC_RC=y +# DFU over BT requires +# increase of ble throughput +CONFIG_BT_BUF_ACL_RX_SIZE=502 +CONFIG_BT_BUF_ACL_TX_SIZE=502 + +# Temporary fix as there is a strange behaviour with some Android +# phones. +CONFIG_BT_DATA_LEN_UPDATE=n + +CONFIG_BT_PER_ADV_SYNC=y + +CONFIG_BT_CTLR_SCAN_DATA_LEN_MAX=1650 + +CONFIG_BT_BUF_EVT_RX_COUNT=16 + diff --git a/app/prj.conf b/app/prj.conf index 47a4ed9b..273d2bdc 100644 --- a/app/prj.conf +++ b/app/prj.conf @@ -129,7 +129,7 @@ CONFIG_BT_DEVICE_APPEARANCE=194 CONFIG_BT_KEYS_OVERWRITE_OLDEST=y CONFIG_BT_SETTINGS=y CONFIG_BT_MAX_PAIRED=5 -CONFIG_BT_MAX_CONN=1 +CONFIG_BT_MAX_CONN=3 CONFIG_BT_GATT_CLIENT=y CONFIG_BT_GATT_CACHING=y CONFIG_BT_GATT_NOTIFY_MULTIPLE=y @@ -137,9 +137,10 @@ CONFIG_BT_GATT_NOTIFY_MULTIPLE=y CONFIG_BT_BROADCASTER=y CONFIG_BT_SMP_ALLOW_UNAUTH_OVERWRITE=y CONFIG_BT_ECC=y -CONFIG_BT_CONN_TX_MAX=3 +CONFIG_BT_CONN_TX_MAX=6 CONFIG_BT_L2CAP_TX_MTU=498 +CONFIG_BT_L2CAP_TX_BUF_COUNT=6 CONFIG_BT_BUF_ACL_RX_SIZE=502 CONFIG_BT_BUF_ACL_TX_SIZE=502 diff --git a/app/src/applications/lea_assistant/CMakeLists.txt b/app/src/applications/lea_assistant/CMakeLists.txt new file mode 100644 index 00000000..4b576e16 --- /dev/null +++ b/app/src/applications/lea_assistant/CMakeLists.txt @@ -0,0 +1,4 @@ +if(CONFIG_APPLICATIONS_USE_LEA_ASSISTANT) + FILE(GLOB app_sources *.c) + target_sources(app PRIVATE ${app_sources}) +endif() diff --git a/app/src/applications/lea_assistant/Kconfig b/app/src/applications/lea_assistant/Kconfig new file mode 100644 index 00000000..fe831066 --- /dev/null +++ b/app/src/applications/lea_assistant/Kconfig @@ -0,0 +1,3 @@ +module = ZSW_LEA_ASSISTANT_APP +module-str = ZSW_LEA_ASSISTANT_APP +source "subsys/logging/Kconfig.template.log_config" diff --git a/app/src/applications/lea_assistant/broadcast_assistant.c b/app/src/applications/lea_assistant/broadcast_assistant.c new file mode 100644 index 00000000..7c33f77c --- /dev/null +++ b/app/src/applications/lea_assistant/broadcast_assistant.c @@ -0,0 +1,1110 @@ +/* + * Copyright (c) 2024 Demant A/S + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** @note this is adapted from https://github.com/AstraeusLabs/web-broadcast-assistant/tree/f1655305f3f1064fde04ed6f6744ca188bdc1670 */ + +#include +#include +#include +#include +#include + +// #include "webusb.h" +#include "message_handler.h" +#include "broadcast_assistant.h" + +LOG_MODULE_REGISTER(broadcast_assistant, CONFIG_ZSW_LEA_ASSISTANT_APP_LOG_LEVEL); + +#define INVALID_BROADCAST_ID 0xFFFFFFFFU + +#define PA_SYNC_SKIP 5 +#define PA_SYNC_INTERVAL_TO_TIMEOUT_RATIO 20 /* Set the timeout relative to interval */ + +#define MAX_NUMBER_OF_SOURCES 20 + +typedef struct source_data { + bt_addr_le_t addr; + bool base_received; +} source_data_t; + +typedef struct source_data_list { + uint8_t num; + source_data_t data[MAX_NUMBER_OF_SOURCES]; +} source_data_list_t; + +source_data_list_t source_data_list; + +static struct k_mutex source_data_list_mutex; +static struct bt_le_per_adv_sync *pa_sync; +static volatile bool pa_syncing; + +static struct k_work pa_sync_delete_work; + +static void broadcast_assistant_discover_cb(struct bt_conn *conn, int err, + uint8_t recv_state_count); +static void broadcast_assistant_recv_state_cb(struct bt_conn *conn, int err, + const struct bt_bap_scan_delegator_recv_state *state); +static void broadcast_assistant_recv_state_removed_cb(struct bt_conn *conn, + uint8_t src_id); +static void broadcast_assistant_add_src_cb(struct bt_conn *conn, int err); +static void broadcast_assistant_mod_src_cb(struct bt_conn *conn, int err); +static void broadcast_assistant_rem_src_cb(struct bt_conn *conn, int err); +static void connected(struct bt_conn *conn, uint8_t err); +static void disconnected(struct bt_conn *conn, uint8_t reason); +static void security_changed_cb(struct bt_conn *conn, bt_security_t level, + enum bt_security_err err); +static void identity_resolved_cb(struct bt_conn *conn, + const bt_addr_le_t *rpa, + const bt_addr_le_t *identity); +static void restart_scanning_if_needed(void); +static bool device_found(struct bt_data *data, void *user_data); +static bool scan_for_source(const struct bt_le_scan_recv_info *info, struct net_buf_simple *ad, + scan_recv_data_t *sr_data); +static bool scan_for_sink(const struct bt_le_scan_recv_info *info, struct net_buf_simple *ad, + scan_recv_data_t *sr_data); +static void scan_recv_cb(const struct bt_le_scan_recv_info *info, struct net_buf_simple *ad); +static void scan_timeout_cb(void); + +static struct bt_le_scan_cb scan_callbacks = { + .recv = scan_recv_cb, + .timeout = scan_timeout_cb, +}; + +static struct bt_bap_broadcast_assistant_cb broadcast_assistant_callbacks = { + .discover = broadcast_assistant_discover_cb, + .recv_state = broadcast_assistant_recv_state_cb, + .recv_state_removed = broadcast_assistant_recv_state_removed_cb, + .add_src = broadcast_assistant_add_src_cb, + .mod_src = broadcast_assistant_mod_src_cb, + .rem_src = broadcast_assistant_rem_src_cb, +}; + +BT_CONN_CB_DEFINE(conn_callbacks) = { + .connected = connected, + .disconnected = disconnected, + .security_changed = security_changed_cb, + .identity_resolved = identity_resolved_cb +}; + +static struct bt_conn *ba_sink_conn; /* TODO: Make a list of sinks */ +static uint8_t ba_scan_target; +static uint32_t ba_source_broadcast_id; +static uint8_t ba_source_id; /* Source ID of the receive state */ +static struct bt_bap_scan_delegator_recv_state recv_state = {0}; + +/* + * Private functions + */ + +static void pa_sync_delete(struct k_work *work) +{ + int err; + + LOG_DBG("pa_sync_delete"); + + err = bt_le_per_adv_sync_delete(pa_sync); + if (err) { + LOG_WRN("bt_le_per_adv_sync_delete failed (%d)", err); + } +} + +static void source_data_reset(void) +{ + k_mutex_lock(&source_data_list_mutex, K_FOREVER); + for (int i = 0; i < MAX_NUMBER_OF_SOURCES; i++) { + bt_addr_le_copy(&source_data_list.data[i].addr, BT_ADDR_LE_NONE); + source_data_list.data[i].base_received = false; + + } + source_data_list.num = 0; + k_mutex_unlock(&source_data_list_mutex); +} + +static void source_data_add(const bt_addr_le_t *addr) +{ + int i; + bool new_source = true; + char addr_str[BT_ADDR_LE_STR_LEN]; + + bt_addr_le_to_str(addr, addr_str, sizeof(addr_str)); + + k_mutex_lock(&source_data_list_mutex, K_FOREVER); + for (i = 0; i < source_data_list.num; i++) { + if (bt_addr_le_cmp(addr, &source_data_list.data[i].addr) == 0) { + LOG_DBG("Source already added (%s)", addr_str); + new_source = false; + break; + } + } + + if (new_source && i < MAX_NUMBER_OF_SOURCES) { + bt_addr_le_copy(&source_data_list.data[i].addr, addr); + source_data_list.data[i].base_received = false; + source_data_list.num++; + LOG_INF("Source added (%s), (%u)", addr_str, source_data_list.num); + } + + k_mutex_unlock(&source_data_list_mutex); +} + +static bool source_data_get_base_received(const bt_addr_le_t *addr) +{ + bool base_received = false; + + k_mutex_lock(&source_data_list_mutex, K_FOREVER); + for (int i = 0; i < source_data_list.num; i++) { + if (bt_addr_le_cmp(addr, &source_data_list.data[i].addr) == 0 && + source_data_list.data[i].base_received) { + base_received = true; + break; + } + } + k_mutex_unlock(&source_data_list_mutex); + + return base_received; +} + +static void source_data_set_base_received(const bt_addr_le_t *addr) +{ + k_mutex_lock(&source_data_list_mutex, K_FOREVER); + for (int i = 0; i < source_data_list.num; i++) { + if (bt_addr_le_cmp(addr, &source_data_list.data[i].addr) == 0) { + source_data_list.data[i].base_received = true; + break; + } + } + k_mutex_unlock(&source_data_list_mutex); +} + +static void broadcast_assistant_discover_cb(struct bt_conn *conn, int err, uint8_t recv_state_count) +{ + const bt_addr_le_t *bt_addr_le; + char addr_str[BT_ADDR_LE_STR_LEN]; + struct net_buf *evt_msg; + + LOG_DBG("Broadcast assistant discover callback (%p, %d, %u)", (void *)conn, err, recv_state_count); + if (err) { + err = bt_conn_disconnect(conn, BT_HCI_ERR_REMOTE_USER_TERM_CONN); + if (err) { + LOG_ERR("Failed to disconnect (err %d)", err); + } + restart_scanning_if_needed(); + + return; /* return and wait for disconnected callback (assume no err) */ + } + + /* Succesful connected to sink */ + evt_msg = message_alloc_tx_message(); + bt_addr_le = bt_conn_get_dst(conn); + bt_addr_le_to_str(bt_addr_le, addr_str, sizeof(addr_str)); + LOG_DBG("Connected to %s", addr_str); + + /* Bluetooth LE Device Address */ + net_buf_add_u8(evt_msg, 1 + BT_ADDR_LE_SIZE); + net_buf_add_u8(evt_msg, bt_addr_le_is_identity(bt_addr_le) ? BT_DATA_IDENTITY : BT_DATA_RPA); + net_buf_add_u8(evt_msg, bt_addr_le->type); + net_buf_add_mem(evt_msg, &bt_addr_le->a, sizeof(bt_addr_t)); + + /* error code */ + net_buf_add_u8(evt_msg, 1 /* len of BT_DATA type */ + sizeof(int32_t)); + net_buf_add_u8(evt_msg, BT_DATA_ERROR_CODE); + net_buf_add_le32(evt_msg, 0 /* OK */); + + restart_scanning_if_needed(); + send_net_buf_event(MESSAGE_SUBTYPE_SINK_CONNECTED, evt_msg); /// @leomod send the message after trying to restart otherwise there is a race-ish condition +} + +static void broadcast_assistant_recv_state_cb(struct bt_conn *conn, int err, + const struct bt_bap_scan_delegator_recv_state *state) +{ + LOG_DBG("Broadcast assistant recv_state callback (%p, %d)", (void *)conn, err); + + if (state->pa_sync_state != recv_state.pa_sync_state) { + struct net_buf *evt_msg; + enum message_sub_type evt_msg_sub_type; + const bt_addr_le_t *bt_addr_le; + + LOG_DBG("Going from PA state %u to %u", recv_state.pa_sync_state, state->pa_sync_state); + + switch (state->pa_sync_state) { + case BT_BAP_PA_STATE_NOT_SYNCED: + LOG_INF("BT_BAP_PA_STATE_NOT_SYNCED"); + evt_msg_sub_type = MESSAGE_SUBTYPE_NEW_PA_STATE_NOT_SYNCED; + break; + case BT_BAP_PA_STATE_INFO_REQ: + LOG_INF("BT_BAP_PA_STATE_INFO_REQ"); + evt_msg_sub_type = MESSAGE_SUBTYPE_NEW_PA_STATE_INFO_REQ; + break; + case BT_BAP_PA_STATE_SYNCED: + LOG_INF("BT_BAP_PA_STATE_SYNCED (src_id = %u)", state->src_id); + ba_source_id = state->src_id; /* store source ID of the receive state */ + evt_msg_sub_type = MESSAGE_SUBTYPE_NEW_PA_STATE_SYNCED; + break; + case BT_BAP_PA_STATE_FAILED: + LOG_INF("BT_BAP_PA_STATE_FAILED"); + evt_msg_sub_type = MESSAGE_SUBTYPE_NEW_PA_STATE_FAILED; + break; + case BT_BAP_PA_STATE_NO_PAST: + LOG_INF("BT_BAP_PA_STATE_NO_PAST"); + evt_msg_sub_type = MESSAGE_SUBTYPE_NEW_PA_STATE_NO_PAST; + break; + default: + LOG_INF("Invalid State Transition"); + return; + } + + evt_msg = message_alloc_tx_message(); + + /* Bluetooth LE Device Address */ + bt_addr_le = bt_conn_get_dst(conn); + net_buf_add_u8(evt_msg, 1 + BT_ADDR_LE_SIZE); + net_buf_add_u8(evt_msg, bt_addr_le_is_identity(bt_addr_le) ? BT_DATA_IDENTITY : BT_DATA_RPA); + net_buf_add_u8(evt_msg, bt_addr_le->type); + net_buf_add_mem(evt_msg, &bt_addr_le->a, sizeof(bt_addr_t)); + + /* broadcast id */ + net_buf_add_u8(evt_msg, 5); + net_buf_add_u8(evt_msg, BT_DATA_BROADCAST_ID); + net_buf_add_le32(evt_msg, state->broadcast_id); + + send_net_buf_event(evt_msg_sub_type, evt_msg); + } + + for (int i = 0; i < state->num_subgroups; i++) { + if (state->subgroups[i].bis_sync != recv_state.subgroups[i].bis_sync) { + struct net_buf *evt_msg; + enum message_sub_type evt_msg_sub_type; + const bt_addr_le_t *bt_addr_le; + + /* BIS sync changed */ + evt_msg_sub_type = state->subgroups[i].bis_sync == 0 + ? MESSAGE_SUBTYPE_BIS_NOT_SYNCED + : MESSAGE_SUBTYPE_BIS_SYNCED; + + LOG_DBG("%s", evt_msg_sub_type == MESSAGE_SUBTYPE_BIS_SYNCED + ? "MESSAGE_SUBTYPE_BIS_SYNCED" + : "MESSAGE_SUBTYPE_BIS_NOT_SYNCED"); + + evt_msg = message_alloc_tx_message(); + + /* Bluetooth LE Device Address */ + bt_addr_le = bt_conn_get_dst(conn); + net_buf_add_u8(evt_msg, 1 + BT_ADDR_LE_SIZE); + net_buf_add_u8(evt_msg, bt_addr_le_is_identity(bt_addr_le) ? BT_DATA_IDENTITY : BT_DATA_RPA); + net_buf_add_u8(evt_msg, bt_addr_le->type); + net_buf_add_mem(evt_msg, &bt_addr_le->a, sizeof(bt_addr_t)); + + /* broadcast id */ + net_buf_add_u8(evt_msg, 5); + net_buf_add_u8(evt_msg, BT_DATA_BROADCAST_ID); + net_buf_add_le32(evt_msg, state->broadcast_id); + + send_net_buf_event(evt_msg_sub_type, evt_msg); + } + } + + /* Store latest recv_state */ + memcpy(&recv_state, state, sizeof(struct bt_bap_scan_delegator_recv_state)); +} + +static void broadcast_assistant_recv_state_removed_cb(struct bt_conn *conn, uint8_t src_id) +{ + LOG_DBG("Broadcast assistant recv_state_removed callback (%p, %u)", (void *)conn, src_id); + send_event(MESSAGE_SUBTYPE_SOURCE_REMOVED, 0); +} + +static void broadcast_assistant_add_src_cb(struct bt_conn *conn, int err) +{ + const bt_addr_le_t *bt_addr_le; + char addr_str[BT_ADDR_LE_STR_LEN]; + struct net_buf *evt_msg; + + LOG_DBG("Broadcast assistant add_src callback (%p, %d)", (void *)conn, err); + + evt_msg = message_alloc_tx_message(); + bt_addr_le = bt_conn_get_dst(ba_sink_conn); /* sink addr */ + bt_addr_le_to_str(bt_addr_le, addr_str, sizeof(addr_str)); + LOG_DBG("Source added for %s", addr_str); + + /* Bluetooth LE Device Address */ + net_buf_add_u8(evt_msg, 1 + BT_ADDR_LE_SIZE); + net_buf_add_u8(evt_msg, bt_addr_le_is_identity(bt_addr_le) ? BT_DATA_IDENTITY : BT_DATA_RPA); + net_buf_add_u8(evt_msg, bt_addr_le->type); + net_buf_add_mem(evt_msg, &bt_addr_le->a, sizeof(bt_addr_t)); + + /* broadcast id */ + net_buf_add_u8(evt_msg, 5); + net_buf_add_u8(evt_msg, BT_DATA_BROADCAST_ID); + net_buf_add_le32(evt_msg, ba_source_broadcast_id); + /* error code */ + net_buf_add_u8(evt_msg, 1 /* len of BT_DATA type */ + sizeof(int32_t)); + net_buf_add_u8(evt_msg, BT_DATA_ERROR_CODE); + net_buf_add_le32(evt_msg, err); + + send_net_buf_event(MESSAGE_SUBTYPE_SOURCE_ADDED, evt_msg); +} + +static void broadcast_assistant_mod_src_cb(struct bt_conn *conn, int err) +{ + if (err) { + LOG_ERR("BASS modify source (err: %d)", err); + return; + } + + LOG_DBG("BASS modify source (bis_sync = 0, pa_sync = false) ok -> Now remove source"); + + err = bt_bap_broadcast_assistant_rem_src(conn, ba_source_id); + if (err) { + LOG_ERR("BASS remove source (err: %d)", err); + } +} + +static void broadcast_assistant_rem_src_cb(struct bt_conn *conn, int err) +{ + LOG_INF("BASS remove source (err: %d)", err); + ba_source_id = 0; +} + +static void connected(struct bt_conn *conn, uint8_t err) +{ + LOG_DBG("Broadcast assistant connected callback (%p, err:%d)", (void *)conn, err); + + if (conn != ba_sink_conn) { + return; + } + if (err) { + const bt_addr_le_t *bt_addr_le; + struct net_buf *evt_msg; + + LOG_ERR("Connected error (err %d)", err); + + evt_msg = message_alloc_tx_message(); + bt_addr_le = bt_conn_get_dst(conn); + /* Bluetooth LE Device Address */ + net_buf_add_u8(evt_msg, 1 + BT_ADDR_LE_SIZE); + net_buf_add_u8(evt_msg, bt_addr_le_is_identity(bt_addr_le) ? BT_DATA_IDENTITY : BT_DATA_RPA); + net_buf_add_u8(evt_msg, bt_addr_le->type); + net_buf_add_mem(evt_msg, &bt_addr_le->a, sizeof(bt_addr_t)); + /* error code */ + net_buf_add_u8(evt_msg, 1 /* len of BT_DATA type */ + sizeof(int32_t)); + net_buf_add_u8(evt_msg, BT_DATA_ERROR_CODE); + net_buf_add_le32(evt_msg, err); + + bt_conn_unref(ba_sink_conn); + ba_sink_conn = NULL; + + send_net_buf_event(MESSAGE_SUBTYPE_SINK_CONNECTED, evt_msg); + restart_scanning_if_needed(); + return; + } + + /// @leomod check for connection role in order to not interfere with phone connection + struct bt_conn_info info; + bt_conn_get_info(conn, &info); + if(info.role == BT_CONN_ROLE_CENTRAL){ + err = bt_conn_set_security(conn, BT_SECURITY_L2 | BT_SECURITY_FORCE_PAIR); + } + + if (err) { + LOG_ERR("Setting security failed (err %d)", err); + } + +} + +static void disconnected(struct bt_conn *conn, uint8_t reason) +{ + const bt_addr_le_t *bt_addr_le; + struct net_buf *evt_msg; + + LOG_DBG("Broadcast assistant disconnected callback (%p, reason:%d)", (void *)conn, reason); + + if (conn != ba_sink_conn) { + return; + } + + bt_addr_le = bt_conn_get_dst(conn); + evt_msg = message_alloc_tx_message(); + /* Bluetooth LE Device Address */ + net_buf_add_u8(evt_msg, 1 + BT_ADDR_LE_SIZE); + net_buf_add_u8(evt_msg, bt_addr_le_is_identity(bt_addr_le) ? BT_DATA_IDENTITY : BT_DATA_RPA); + net_buf_add_u8(evt_msg, bt_addr_le->type); + net_buf_add_mem(evt_msg, &bt_addr_le->a, sizeof(bt_addr_t)); + /* error code */ + net_buf_add_u8(evt_msg, 1 /* len of BT_DATA type */ + sizeof(int32_t)); + net_buf_add_u8(evt_msg, BT_DATA_ERROR_CODE); + net_buf_add_le32(evt_msg, 0 /* OK */); + + bt_conn_unref(ba_sink_conn); + ba_sink_conn = NULL; + + send_net_buf_event(MESSAGE_SUBTYPE_SINK_DISCONNECTED, evt_msg); +} + +static void security_changed_cb(struct bt_conn *conn, bt_security_t level, enum bt_security_err err) +{ + LOG_DBG("Broadcast assistant security_changed callback (%p, %d, err:%d)", (void *)conn, level, err); + + + /* Connected. Do BAP broadcast assistant discover */ + LOG_INF("Broadcast assistant discover"); + err = bt_bap_broadcast_assistant_discover(ba_sink_conn); + if (false) { // @leomod do not disconnect + LOG_ERR("Broadcast assistant discover (err %d)", err); + err = bt_conn_disconnect(ba_sink_conn, BT_HCI_ERR_REMOTE_USER_TERM_CONN); + if (err) { + LOG_ERR("Failed to disconnect (err %d)", err); + } + restart_scanning_if_needed(); + + return; /* return and wait for disconnected callback (assume no err) */ + } +} + +static void identity_resolved_cb(struct bt_conn *conn, const bt_addr_le_t *rpa, + const bt_addr_le_t *identity) { + char rpa_str[BT_ADDR_LE_STR_LEN]; + char identity_str[BT_ADDR_LE_STR_LEN]; + + bt_addr_le_to_str(rpa, rpa_str, sizeof(rpa_str)); + bt_addr_le_to_str(identity, identity_str, sizeof(identity_str)); + LOG_INF("Identity resolved %s -> %s", rpa_str, identity_str); + + enum message_sub_type evt_msg_sub_type; + struct net_buf *evt_msg; + + evt_msg_sub_type = MESSAGE_SUBTYPE_IDENTITY_RESOLVED; + evt_msg = message_alloc_tx_message(); + + net_buf_add_u8(evt_msg, 1 + BT_ADDR_LE_SIZE); + net_buf_add_u8(evt_msg, BT_DATA_RPA); + net_buf_add_u8(evt_msg, rpa->type); + net_buf_add_mem(evt_msg, &rpa->a, sizeof(bt_addr_t)); + + net_buf_add_u8(evt_msg, 1 + BT_ADDR_LE_SIZE); + net_buf_add_u8(evt_msg, BT_DATA_IDENTITY); + net_buf_add_u8(evt_msg, identity->type); + net_buf_add_mem(evt_msg, &identity->a, sizeof(bt_addr_t)); + + send_net_buf_event(evt_msg_sub_type, evt_msg); +} + +static void restart_scanning_if_needed(void) +{ + int err; + + if (ba_scan_target) { + LOG_DBG("Restart scanning"); + err = bt_le_scan_start(BT_LE_SCAN_PASSIVE, NULL); + if (err) { + LOG_ERR("Scanning failed to start (err %d)", err); + if (ba_scan_target == BROADCAST_ASSISTANT_SCAN_TARGET_ALL) { + send_event(MESSAGE_SUBTYPE_START_SCAN_ALL, err); + } else if (ba_scan_target == BROADCAST_ASSISTANT_SCAN_TARGET_SOURCE) { + send_event(MESSAGE_SUBTYPE_START_SOURCE_SCAN, err); + } else if (ba_scan_target == BROADCAST_ASSISTANT_SCAN_TARGET_SINK) { + send_event(MESSAGE_SUBTYPE_START_SINK_SCAN, err); + } + + ba_scan_target = 0; + } + } +} + +static bool device_found(struct bt_data *data, void *user_data) +{ + scan_recv_data_t *sr_data = (scan_recv_data_t *)user_data; + struct bt_uuid_16 adv_uuid; + + switch (data->type) { + case BT_DATA_NAME_SHORTENED: + case BT_DATA_NAME_COMPLETE: + memcpy(sr_data->bt_name, data->data, MIN(data->data_len, BT_NAME_LEN - 1)); + sr_data->bt_name_type = data->type == BT_DATA_NAME_SHORTENED + ? BT_DATA_NAME_SHORTENED + : BT_DATA_NAME_COMPLETE; + return true; + case BT_DATA_BROADCAST_NAME: + memcpy(sr_data->broadcast_name, data->data, MIN(data->data_len, BT_NAME_LEN - 1)); + return true; + case BT_DATA_SVC_DATA16: + /* TODO: Test code bolow before enable */ +#if 0 + /* Check for BASS in Service Data */ + if (data->data_len >= BT_UUID_SIZE_16) { + const struct bt_uuid *uuid; + uint16_t u16; + + memcpy(&u16, data->data, sizeof(u16)); + uuid = BT_UUID_DECLARE_16(sys_le16_to_cpu(u16)); + + if (bt_uuid_cmp(uuid, BT_UUID_BASS)) { + sr_info->has_bass = true; + return true; + } + } +#endif /* 0 */ + + /* Check for Broadcast ID */ + if (data->data_len < BT_UUID_SIZE_16 + BT_AUDIO_BROADCAST_ID_SIZE) { + return true; + } + + if (!bt_uuid_create(&adv_uuid.uuid, data->data, BT_UUID_SIZE_16)) { + return true; + } + + if (bt_uuid_cmp(&adv_uuid.uuid, BT_UUID_BROADCAST_AUDIO) != 0) { + return true; + } + + sr_data->broadcast_id = sys_get_le24(data->data + BT_UUID_SIZE_16); + return true; + case BT_DATA_UUID16_SOME: + case BT_DATA_UUID16_ALL: + /* NOTE: According to the BAP 1.0.1 Spec, + * Section 3.9.2. Additional Broadcast Audio Scan Service requirements, + * If the Scan Delegator implements a Broadcast Sink, it should also + * advertise a Service Data field containing the Broadcast Audio + * Scan Service (BASS) UUID. + * + * However, it seems that this is not the case with the sinks available + * while developing this sample application. Therefore, we instead, + * search for the existence of BASS and PACS in the list of service UUIDs, + * which does seem to exist in the sinks available. + */ + + /* Check for BASS and PACS */ + if (data->data_len % sizeof(uint16_t) != 0U) { + LOG_ERR("UUID16 AD malformed"); + return true; + } + + for (size_t i = 0; i < data->data_len; i += sizeof(uint16_t)) { + const struct bt_uuid *uuid; + uint16_t u16; + + memcpy(&u16, &data->data[i], sizeof(u16)); + uuid = BT_UUID_DECLARE_16(sys_le16_to_cpu(u16)); + + if (bt_uuid_cmp(uuid, BT_UUID_BASS) == 0) { + sr_data->has_bass = true; + continue; + } + + if (bt_uuid_cmp(uuid, BT_UUID_PACS) == 0) { + sr_data->has_pacs = true; + continue; + } + } + return true; + default: + return true; + } +} + +static bool base_search(struct bt_data *data, void *user_data) +{ + const struct bt_bap_base *base = bt_bap_base_get_base_from_ad(data); + + /* Base is NULL if the data does not contain a valid BASE */ + if (base == NULL) { + return true; + } + + /* Base found */ + *(bool *)user_data = true; + + return false; +} + +static void pa_synced_cb(struct bt_le_per_adv_sync *sync, + struct bt_le_per_adv_sync_synced_info *info) +{ + LOG_DBG("PA sync %p synced", (void *)sync); +} + +static void pa_recv_cb(struct bt_le_per_adv_sync *sync, + const struct bt_le_per_adv_sync_recv_info *info, struct net_buf_simple *buf) +{ + bool base_found = false; + + if (sync != pa_sync) { + return; + } + + LOG_DBG("PA receive %p", (void *)sync); + bt_data_parse(buf, base_search, (void *)&base_found); + + if (base_found) { + enum message_sub_type evt_msg_sub_type; + struct net_buf *evt_msg; + + LOG_INF("BASE found, delete PA sync"); + source_data_set_base_received(info->addr); + + k_work_submit(&pa_sync_delete_work); + + evt_msg_sub_type = MESSAGE_SUBTYPE_SOURCE_BASE_FOUND; + evt_msg = message_alloc_tx_message(); + + net_buf_add_u8(evt_msg, buf->len + 1); + net_buf_add_u8(evt_msg, BT_DATA_BASE); + net_buf_add_mem(evt_msg, buf->data, buf->len); + + /* Append data from struct bt_le_scan_recv_info (BT addr) */ + /* Bluetooth LE Device Address */ + net_buf_add_u8(evt_msg, 1 + BT_ADDR_LE_SIZE); + net_buf_add_u8(evt_msg, bt_addr_le_is_identity(info->addr) ? BT_DATA_IDENTITY : BT_DATA_RPA); + net_buf_add_u8(evt_msg, info->addr->type); + net_buf_add_mem(evt_msg, &info->addr->a, sizeof(bt_addr_t)); + + send_net_buf_event(evt_msg_sub_type, evt_msg); + } +} + +static void pa_term_cb(struct bt_le_per_adv_sync *sync, + const struct bt_le_per_adv_sync_term_info *info) +{ + LOG_DBG("PA terminated %p", (void *)sync); + pa_syncing = false; +} + +static struct bt_le_per_adv_sync_cb pa_synced_callbacks = { + .synced = pa_synced_cb, + .recv = pa_recv_cb, + .term = pa_term_cb, +}; + +static uint16_t interval_to_sync_timeout(uint16_t pa_interval) +{ + uint16_t pa_timeout; + + if (pa_interval == BT_BAP_PA_INTERVAL_UNKNOWN) { + /* Use maximum value to maximize chance of success */ + pa_timeout = BT_GAP_PER_ADV_MAX_TIMEOUT; + } else { + uint32_t interval_ms; + uint32_t timeout; + + /* Add retries and convert to unit in 10's of ms */ + interval_ms = BT_GAP_PER_ADV_INTERVAL_TO_MS(pa_interval); + timeout = (interval_ms * PA_SYNC_INTERVAL_TO_TIMEOUT_RATIO) / 10; + + /* Enforce restraints */ + pa_timeout = CLAMP(timeout, BT_GAP_PER_ADV_MIN_TIMEOUT, BT_GAP_PER_ADV_MAX_TIMEOUT); + } + + return pa_timeout; +} + +static int pa_sync_create(const struct bt_le_scan_recv_info *info) +{ + struct bt_le_per_adv_sync_param per_adv_sync_param = {0}; + + bt_addr_le_copy(&per_adv_sync_param.addr, info->addr); + per_adv_sync_param.options = BT_LE_PER_ADV_SYNC_OPT_FILTER_DUPLICATE; + per_adv_sync_param.sid = info->sid; + per_adv_sync_param.skip = PA_SYNC_SKIP; + per_adv_sync_param.timeout = interval_to_sync_timeout(info->interval); + + return bt_le_per_adv_sync_create(&per_adv_sync_param, &pa_sync); +} + +static bool scan_for_source(const struct bt_le_scan_recv_info *info, struct net_buf_simple *ad, + scan_recv_data_t *sr_data) +{ + /* Scan for and select Broadcast Source */ + + sr_data->broadcast_id = INVALID_BROADCAST_ID; + + /* We are only interested in non-connectable periodic advertisers */ + if ((info->adv_props & BT_GAP_ADV_PROP_CONNECTABLE) != 0 || info->interval == 0) { + return false; + } + + bt_data_parse(ad, device_found, (void *)sr_data); + + if (sr_data->broadcast_id != INVALID_BROADCAST_ID) { + LOG_INF("Broadcast Source Found [name, b_name, b_id] = [\"%s\", \"%s\", 0x%06x]", + sr_data->bt_name, sr_data->broadcast_name, sr_data->broadcast_id); + + source_data_add(info->addr); + + if (!pa_syncing && !source_data_get_base_received(info->addr)) { + LOG_INF("PA sync create (b_id = 0x%06x)", sr_data->broadcast_id); + int err = pa_sync_create(info); + if (err != 0) { + LOG_WRN("Could not create Broadcast PA sync: %d", err); + } else { + pa_syncing = true; + } + } + + return true; + } + + return false; +} + +static bool scan_for_sink(const struct bt_le_scan_recv_info *info, struct net_buf_simple *ad, + scan_recv_data_t *sr_data) +{ + /* Scan for and connect to Broadcast Sink */ + + /* We are only interested in connectable advertisers */ + if ((info->adv_props & BT_GAP_ADV_PROP_CONNECTABLE) == 0) { + return false; + } + + bt_data_parse(ad, device_found, (void *)sr_data); + + if (sr_data->has_bass) { + char addr_str[BT_ADDR_LE_STR_LEN]; + + bt_addr_le_to_str(info->addr, addr_str, sizeof(addr_str)); + LOG_INF("Broadcast Sink Found: [\"%s\", %s]", sr_data->bt_name, addr_str); + + return true; + } + + return false; +} + +static void scan_recv_cb(const struct bt_le_scan_recv_info *info, struct net_buf_simple *ad) +{ + struct net_buf_simple ad_clone1, ad_clone2; + + /* Clone needed for the event message because bt_data_parse consumes ad data */ + net_buf_simple_clone(ad, &ad_clone1); + net_buf_simple_clone(ad, &ad_clone2); + + if (ba_scan_target & BROADCAST_ASSISTANT_SCAN_TARGET_SOURCE) { + enum message_sub_type evt_msg_sub_type; + struct net_buf *evt_msg; + scan_recv_data_t sr_data = {0}; + + if (scan_for_source(info, &ad_clone1, &sr_data)) { + /* broadcast source found */ + evt_msg_sub_type = MESSAGE_SUBTYPE_SOURCE_FOUND; + evt_msg = message_alloc_tx_message(); + + net_buf_add_mem(evt_msg, ad->data, ad->len); + + /* Append data from struct bt_le_scan_recv_info (RSSI, BT addr, ..) */ + /* RSSI */ + net_buf_add_u8(evt_msg, 2); + net_buf_add_u8(evt_msg, BT_DATA_RSSI); + net_buf_add_u8(evt_msg, info->rssi); + /* Bluetooth LE Device Address */ + net_buf_add_u8(evt_msg, 1 + BT_ADDR_LE_SIZE); + net_buf_add_u8(evt_msg, bt_addr_le_is_identity(info->addr) ? BT_DATA_IDENTITY : BT_DATA_RPA); + net_buf_add_u8(evt_msg, info->addr->type); + net_buf_add_mem(evt_msg, &info->addr->a, sizeof(bt_addr_t)); + /* BT name */ + net_buf_add_u8(evt_msg, strlen(sr_data.bt_name) + 1); + net_buf_add_u8(evt_msg, sr_data.bt_name_type); + net_buf_add_mem(evt_msg, &sr_data.bt_name, strlen(sr_data.bt_name)); + + /* sid */ + net_buf_add_u8(evt_msg, 2); + net_buf_add_u8(evt_msg, BT_DATA_SID); + net_buf_add_u8(evt_msg, info->sid); + /* pa interval */ + net_buf_add_u8(evt_msg, 3); + net_buf_add_u8(evt_msg, BT_DATA_PA_INTERVAL); + net_buf_add_le16(evt_msg, info->interval); + /* broadcast id */ + net_buf_add_u8(evt_msg, 5); + net_buf_add_u8(evt_msg, BT_DATA_BROADCAST_ID); + net_buf_add_le32(evt_msg, sr_data.broadcast_id); + + send_net_buf_event(evt_msg_sub_type, evt_msg); + } + } + + if (ba_scan_target & BROADCAST_ASSISTANT_SCAN_TARGET_SINK) { + enum message_sub_type evt_msg_sub_type; + struct net_buf *evt_msg; + scan_recv_data_t sr_data = {0}; + + if (scan_for_sink(info, &ad_clone2, &sr_data)) { + /* broadcast sink found */ + evt_msg_sub_type = MESSAGE_SUBTYPE_SINK_FOUND; + evt_msg = message_alloc_tx_message(); + + net_buf_add_mem(evt_msg, ad->data, ad->len); + + /* Append data from struct bt_le_scan_recv_info (RSSI, BT addr, ..) */ + /* RSSI */ + net_buf_add_u8(evt_msg, 2); + net_buf_add_u8(evt_msg, BT_DATA_RSSI); + net_buf_add_u8(evt_msg, info->rssi); + /* Bluetooth LE Device Address */ + net_buf_add_u8(evt_msg, 1 + BT_ADDR_LE_SIZE); + net_buf_add_u8(evt_msg, bt_addr_le_is_identity(info->addr) ? BT_DATA_IDENTITY : BT_DATA_RPA); + net_buf_add_u8(evt_msg, info->addr->type); + net_buf_add_mem(evt_msg, &info->addr->a, sizeof(bt_addr_t)); + /* BT name */ + net_buf_add_u8(evt_msg, strlen(sr_data.bt_name) + 1); + net_buf_add_u8(evt_msg, sr_data.bt_name_type); + net_buf_add_mem(evt_msg, &sr_data.bt_name, strlen(sr_data.bt_name)); + + send_net_buf_event(evt_msg_sub_type, evt_msg); + } + } +} + +static void scan_timeout_cb(void) +{ + LOG_DBG("Scan timeout"); + + ba_scan_target = 0; + + send_event(MESSAGE_SUBTYPE_STOP_SCAN, 0); +} + +/* + * Public functions + */ + +int start_scan(uint8_t target) +{ + if (ba_scan_target != 0) { + /* Scan already ongoing */ + return 0; + } + + if (target == BROADCAST_ASSISTANT_SCAN_TARGET_ALL || + target == BROADCAST_ASSISTANT_SCAN_TARGET_SOURCE) { + source_data_reset(); + } + + int err = bt_le_scan_start(BT_LE_SCAN_PASSIVE, NULL); + if (err) { + LOG_ERR("Scanning failed to start (err %d)", err); + return err; + } + + ba_scan_target = target; + + LOG_INF("Scanning started (target: 0x%08x)", ba_scan_target); + + return 0; +} + +int stop_scanning(void) +{ + if (ba_scan_target == 0) { + /* No scan ongoing */ + return 0; + } + + int err = bt_le_scan_stop(); + if (err) { + LOG_ERR("bt_le_scan_stop failed with %d", err); + return err; + } + + ba_scan_target = 0; + + LOG_DBG("Scanning stopped"); + + return 0; +} + +static void disconnect(struct bt_conn *conn, void *data) +{ + char addr_str[BT_ADDR_LE_STR_LEN]; + int err; + + bt_addr_le_to_str(bt_conn_get_dst(conn), addr_str, sizeof(addr_str)); + + LOG_INF("Disconnecting from %s", addr_str); + err = bt_conn_disconnect(conn, BT_HCI_ERR_REMOTE_USER_TERM_CONN); + if (err) { + LOG_WRN("Failed to disconnect from %s", addr_str); + } +} + +int disconnect_unpair_all(void) +{ + int err = 0; + + LOG_DBG("Disconnecting and unpairing all devices"); + + bt_conn_foreach(BT_CONN_TYPE_LE, disconnect, NULL); + + LOG_DBG("Disconnecting complete"); + + err = bt_unpair(BT_ID_DEFAULT, NULL); + if (err) { + LOG_ERR("bt_unpair failed with %d", err); + } + + LOG_DBG("Unpair complete"); + + return 0; +} + +int connect_to_sink(bt_addr_le_t *bt_addr_le) +{ + char addr_str[BT_ADDR_LE_STR_LEN]; + int err; + + if (ba_sink_conn) { + /* Sink already connected. TODO: Support multiple sinks*/ + return -EAGAIN; + } + + /* Stop scanning if needed */ + if (ba_scan_target) { + LOG_DBG("Stop scanning"); + /// @leomod + stop_scanning(); + } + + bt_addr_le_to_str(bt_addr_le, addr_str, sizeof(addr_str)); + LOG_INF("Connecting to %s...", addr_str); + + err = bt_conn_le_create(bt_addr_le, BT_CONN_LE_CREATE_CONN, BT_LE_CONN_PARAM_DEFAULT, + &ba_sink_conn); + if (err) { + LOG_ERR("Failed creating connection (err=%d)", err); + restart_scanning_if_needed(); + + return err; + } + + return 0; +} + +int disconnect_from_sink(bt_addr_le_t *bt_addr_le) +{ + char addr_str[BT_ADDR_LE_STR_LEN]; + + bt_addr_le_to_str(bt_addr_le, addr_str, sizeof(addr_str)); + LOG_INF("Disconnecting from %s...", addr_str); + + /* TODO: Support multiple sinks. Search for conn to disconnect via + * bt_conn_foreach(BT_CONN_TYPE_LE, disconnect, NULL). + */ + if (ba_sink_conn) { + int err; + + err = bt_conn_disconnect(ba_sink_conn, BT_HCI_ERR_REMOTE_USER_TERM_CONN); + if (err) { + struct net_buf *evt_msg; + + LOG_ERR("Failed to disconnect (err %d)", err); + evt_msg = message_alloc_tx_message(); + /* Bluetooth LE Device Address */ + net_buf_add_u8(evt_msg, 1 + BT_ADDR_LE_SIZE); + net_buf_add_u8(evt_msg, bt_addr_le_is_identity(bt_addr_le) ? BT_DATA_IDENTITY : BT_DATA_RPA); + net_buf_add_u8(evt_msg, bt_addr_le->type); + net_buf_add_mem(evt_msg, &bt_addr_le->a, sizeof(bt_addr_t)); + /* error code */ + net_buf_add_u8(evt_msg, 1 /* len of BT_DATA type */ + sizeof(int32_t)); + net_buf_add_u8(evt_msg, BT_DATA_ERROR_CODE); + net_buf_add_le32(evt_msg, err); + + send_net_buf_event(MESSAGE_SUBTYPE_SINK_DISCONNECTED, evt_msg); + } + } + + return 0; +} + +int add_source(uint8_t sid, uint16_t pa_interval, uint32_t broadcast_id, bt_addr_le_t *addr) +{ + LOG_INF("Adding broadcast source..."); + + struct bt_bap_bass_subgroup subgroup = {0}; + struct bt_bap_broadcast_assistant_add_src_param param = {0}; + int err = 0; + + subgroup.bis_sync = BT_BAP_BIS_SYNC_NO_PREF; /* We might want to hard code to BIT(1) */ + + bt_addr_le_copy(¶m.addr, addr); + param.adv_sid = sid; + param.pa_interval = pa_interval; + param.broadcast_id = broadcast_id; + param.pa_sync = true; + + /* keep broadcast_id as global variable */ + ba_source_broadcast_id = broadcast_id; + + LOG_INF("adv_sid = %u, pa_interval = %u, broadcast_id = 0x%08x", param.adv_sid, + param.pa_interval, param.broadcast_id); + + param.num_subgroups = 1; + param.subgroups = &subgroup; + + if (!ba_sink_conn) { + LOG_INF("No sink connected!"); + return -ENOTCONN; + } + + err = bt_bap_broadcast_assistant_add_src(ba_sink_conn, ¶m); + if (err) { + LOG_ERR("Failed to add source (err %d)", err); + return err; + } + + return 0; +} + +int remove_source(void) +{ + LOG_INF("Removing broadcast source..."); + + struct bt_bap_bass_subgroup subgroup = {0}; /* bis_sync = 0 */ + struct bt_bap_broadcast_assistant_mod_src_param param = { 0 }; + int err = 0; + + param.src_id = ba_source_id; + param.pa_sync = false; /* stop sync to periodic advertisements */ + param.pa_interval = BT_BAP_PA_INTERVAL_UNKNOWN; + param.num_subgroups = 1; /* TODO: Support multiple subgroups */ + param.subgroups = &subgroup; + + if (!ba_sink_conn) { + LOG_INF("No sink connected!"); + return -ENOTCONN; + } + + err = bt_bap_broadcast_assistant_mod_src(ba_sink_conn, ¶m); + if (err) { + LOG_ERR("Failed to modify source (err %d)", err); + return err; + } + + return 0; +} + +int broadcast_assistant_init(void) +{ + ba_sink_conn = NULL; + + k_work_init(&pa_sync_delete_work, &pa_sync_delete); + + int err = 0; // bt_enable(NULL); + if (err) { + LOG_ERR("Bluetooth init failed (err %d)", err); + return err; + } + + LOG_DBG("Bluetooth initialized"); + + bt_le_scan_cb_register(&scan_callbacks); + bt_le_per_adv_sync_cb_register(&pa_synced_callbacks); + bt_bap_broadcast_assistant_register_cb(&broadcast_assistant_callbacks); + LOG_DBG("Bluetooth scan callback registered"); + + k_mutex_init(&source_data_list_mutex); + ba_scan_target = 0; + + return 0; +} diff --git a/app/src/applications/lea_assistant/broadcast_assistant.h b/app/src/applications/lea_assistant/broadcast_assistant.h new file mode 100644 index 00000000..777b54e7 --- /dev/null +++ b/app/src/applications/lea_assistant/broadcast_assistant.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2024 Demant A/S + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** @note this is adapted from https://github.com/AstraeusLabs/web-broadcast-assistant/tree/f1655305f3f1064fde04ed6f6744ca188bdc1670 */ + +#ifndef __BROADCAST_ASSISTANT_H__ +#define __BROADCAST_ASSISTANT_H__ + +#include +#include +#include + +#define BT_DATA_RSSI (BT_DATA_MANUFACTURER_DATA - 1) +#define BT_DATA_SID (BT_DATA_MANUFACTURER_DATA - 2) +#define BT_DATA_PA_INTERVAL (BT_DATA_MANUFACTURER_DATA - 3) +#define BT_DATA_ERROR_CODE (BT_DATA_MANUFACTURER_DATA - 4) +#define BT_DATA_BROADCAST_ID (BT_DATA_MANUFACTURER_DATA - 5) +#define BT_DATA_RPA (BT_DATA_MANUFACTURER_DATA - 6) +#define BT_DATA_IDENTITY (BT_DATA_MANUFACTURER_DATA - 7) +#define BT_DATA_BASE (BT_DATA_MANUFACTURER_DATA - 8) +#define BT_NAME_LEN 30 + +enum { + BROADCAST_ASSISTANT_SCAN_TARGET_SOURCE = BIT(0), + BROADCAST_ASSISTANT_SCAN_TARGET_SINK = BIT(1), + BROADCAST_ASSISTANT_SCAN_TARGET_ALL = + (BROADCAST_ASSISTANT_SCAN_TARGET_SOURCE | BROADCAST_ASSISTANT_SCAN_TARGET_SINK) +}; + +typedef struct scan_recv_data { + char bt_name[BT_NAME_LEN]; + uint8_t bt_name_type; + char broadcast_name[BT_NAME_LEN]; + uint32_t broadcast_id; + bool has_bass; + bool has_pacs; +} scan_recv_data_t; + +int start_scan(uint8_t target); +int stop_scanning(void); +int connect_to_sink(bt_addr_le_t *bt_addr_le); +int disconnect_from_sink(bt_addr_le_t *bt_addr_le); +int add_source(uint8_t sid, uint16_t pa_interval, uint32_t broadcast_id, bt_addr_le_t *addr); +int remove_source(void); +int broadcast_assistant_init(void); +int disconnect_unpair_all(void); + +#endif /* __BROADCAST_ASSISTANT_H__ */ diff --git a/app/src/applications/lea_assistant/lea_assistant_app.c b/app/src/applications/lea_assistant/lea_assistant_app.c new file mode 100644 index 00000000..034baff8 --- /dev/null +++ b/app/src/applications/lea_assistant/lea_assistant_app.c @@ -0,0 +1,115 @@ +/** + * @file lea_assistant_app.c + * @author Leonardo Bispo + * + * @brief LE Audio Broadcast assistant, a Broadcast Assistant can find Broadcast Audio Streams for a Broadcast Receiver. + * + * @see https://github.com/larsgk/web-broadcast-assistant + * @see https://www.bluetooth.com/learn-about-bluetooth/feature-enhancements/le-audio/le-audio-specifications/ + * + */ +#include +#include +#include +#include + +#include "lea_assistant_ui.h" +#include "lea_assistant_app.h" +#include "managers/zsw_app_manager.h" +#include "ble/ble_comm.h" +#include "events/ble_event.h" +#include "ui/utils/zsw_ui_utils.h" + +#include "message_handler.h" + +LOG_MODULE_REGISTER(lea_assistant_app, CONFIG_ZSW_LEA_ASSISTANT_APP_LOG_LEVEL); + +// Functions needed for all applications +static void lea_assistant_app_start(lv_obj_t *root, lv_group_t *group); +static void lea_assistant_app_stop(void); + +LV_IMG_DECLARE(auracast); + +static lv_obj_t *_root = NULL; + +static application_t app = { + .name = "LEA Assistant", + .icon = &auracast, + .start_func = lea_assistant_app_start, + .stop_func = lea_assistant_app_stop +}; + +static void close_app(void) +{ + zsw_app_manager_app_close_request(&app); +} + +static void on_source_selected(lea_assistant_device_t *device) +{ + LOG_DBG("Source %s selected", device->name); + + // Could use `MESSAGE_SUBTYPE_ADD_SOURCE`, but calling it directly so don't need to fill buffer and parse LTV + add_source(device->sid, device->pa_interval, device->broadcast_id, &device->addr); + close_app(); +} + +static void on_sink_selected(lea_assistant_device_t *device) +{ + LOG_DBG("Sink %s selected", device->name); + + // Could use `MESSAGE_SUBTYPE_CONNECT_SINK`, but calling it directly so don't need to fill buffer and parse LTV + connect_to_sink(&device->addr); + + /// @todo connecting screen + + lea_assistant_ui_show_source(_root, on_source_selected); +} + +static void lea_assistant_app_start(lv_obj_t *root, lv_group_t *group) +{ + _root = root; + LOG_DBG("LEA Assistant app start"); + + message_handler(&(struct webusb_message ) { + .sub_type = MESSAGE_SUBTYPE_START_SINK_SCAN + }, 0); + + lea_assistant_ui_show(_root, on_sink_selected, close_app); +} + +static void lea_assistant_app_stop(void) +{ + lea_assistant_ui_remove(); + + message_handler(&(struct webusb_message ) { + .sub_type = MESSAGE_SUBTYPE_STOP_SCAN + }, 0); + + /// @todo disconnect PA sync +} + +static int lea_assistant_app_add(void) +{ + zsw_app_manager_add_application(&app); + + return 0; +} + +void lea_assistant_app_add_source_entry(lea_assistant_device_t *device) +{ + lea_assistant_ui_add_source_list_entry(device); +} + +void lea_assistant_app_add_sink_entry(lea_assistant_device_t *device) +{ + lea_assistant_ui_add_sink_list_entry(device); +} + +void lea_assistant_app_sink_connected() +{ + message_handler(&(struct webusb_message ) { + .sub_type = MESSAGE_SUBTYPE_START_SOURCE_SCAN + }, 0); +} + +SYS_INIT(lea_assistant_app_add, APPLICATION, CONFIG_APPLICATION_INIT_PRIORITY); diff --git a/app/src/applications/lea_assistant/lea_assistant_app.h b/app/src/applications/lea_assistant/lea_assistant_app.h new file mode 100644 index 00000000..d1421b5b --- /dev/null +++ b/app/src/applications/lea_assistant/lea_assistant_app.h @@ -0,0 +1,20 @@ +#pragma once + +#include + +#include "broadcast_assistant.h" + +typedef struct lea_assistant_device_t { + char name[BT_NAME_LEN]; + /** Advertising Set Identifier. */ + uint8_t sid; + uint16_t pa_interval; + uint32_t broadcast_id; + bt_addr_le_t addr; +} lea_assistant_device_t; + +void lea_assistant_app_add_source_entry(lea_assistant_device_t *device); + +void lea_assistant_app_add_sink_entry(lea_assistant_device_t *device); + +void lea_assistant_app_sink_connected(void); diff --git a/app/src/applications/lea_assistant/lea_assistant_ui.c b/app/src/applications/lea_assistant/lea_assistant_ui.c new file mode 100644 index 00000000..2f4dff3c --- /dev/null +++ b/app/src/applications/lea_assistant/lea_assistant_ui.c @@ -0,0 +1,249 @@ +#include "lea_assistant_ui.h" +#include "managers/zsw_app_manager.h" + +#include + +#define MAX_DEVICES_NUM 6 + +LOG_MODULE_REGISTER(lea_assistant_ui, CONFIG_ZSW_LEA_ASSISTANT_APP_LOG_LEVEL); + +typedef struct devices_list { + uint8_t num; + lea_assistant_device_t device[MAX_DEVICES_NUM]; +} devices_list_t; + +static lv_obj_t *root_page = NULL; +static lv_obj_t *spinner = NULL; +static lv_obj_t *mbox = NULL; +static lv_timer_t *timeout_timer = NULL; +static on_button_press_cb_t click_callback; +static on_close_cb_t close_callback; + +static devices_list_t source_list = { + .num = 0, +}; + +static devices_list_t sink_list = { + .num = 0, +}; + +static void click_popup_event_cb(lv_event_t *e) +{ + if (mbox != NULL) { + lv_msgbox_close(mbox); + mbox = NULL; + } + + close_callback(); +} + +static void timeout_popup(void) +{ + mbox = lv_msgbox_create(NULL, "Scan timeout!", NULL, NULL, true); + lv_obj_t *close_btn = lv_msgbox_get_close_btn(mbox); + // LVGL is not calling for the event cb below, so need to remove all events before adding a new one. + lv_obj_remove_event_cb(close_btn, NULL); + lv_obj_add_event_cb(close_btn, click_popup_event_cb, LV_EVENT_CLICKED, NULL); + lv_obj_center(mbox); + lv_obj_set_size(mbox, 180, LV_SIZE_CONTENT); + lv_obj_set_style_radius(mbox, 5, 0); +} + +static void timeout_timer_cb(lv_timer_t *timer) +{ + // Title and spinner child objects + if ((lv_obj_get_child_cnt(root_page) <= 2) && (spinner != NULL)) { + timeout_popup(); + } +} + +static void click_event_cb(lv_event_t *e) +{ + lv_timer_del(timeout_timer); + lea_assistant_device_t *selected = (lea_assistant_device_t *)lv_event_get_user_data(e); + click_callback(selected); +} + +static void scroll_event_cb(lv_event_t *e) +{ + lv_obj_t *cont = lv_event_get_target(e); + lv_area_t cont_a; + lv_obj_get_coords(cont, &cont_a); + lv_coord_t cont_y_center = cont_a.y1 + lv_area_get_height(&cont_a) / 2; + lv_coord_t r = lv_obj_get_height(cont) * 5 / 10; + + uint32_t i; + uint32_t child_cnt = lv_obj_get_child_cnt(cont); + for (i = 0; i < child_cnt; i++) { + lv_obj_t *child = lv_obj_get_child(cont, i); + lv_area_t child_a; + lv_obj_get_coords(child, &child_a); + + lv_coord_t child_y_center = child_a.y1 + lv_area_get_height(&child_a) / 2; + + lv_coord_t diff_y = child_y_center - cont_y_center; + diff_y = LV_ABS(diff_y); + + /* Get the x of diff_y on a circle. */ + lv_coord_t x; + /* If diff_y is out of the circle use the last point of the circle (the radius) */ + if (diff_y >= r) { + x = r; + } else { + /* Use Pythagoras theorem to get x from radius and y */ + uint32_t x_sqr = r * r - diff_y * diff_y; + lv_sqrt_res_t res; + lv_sqrt(x_sqr, &res, 0x8000); /* Use lvgl's built in sqrt root function */ + x = r - res.i - 20; /* Added - 20 here to pull all a bit more to the left side */ + } + + /* Translate the item by the calculated X coordinate */ + lv_obj_set_style_translate_x(child, x, 0); + lv_obj_set_style_translate_y(child, -13, 0); + + /* Uncomment if to use some opacity with larger translations */ + //lv_opa_t opa = lv_map(x, 0, r, LV_OPA_TRANSP, LV_OPA_COVER); + //lv_obj_set_style_opa(child, LV_OPA_COVER - opa, 0); + } +} + +static void page_init(lv_obj_t *root, const char *header) +{ + assert(root_page == NULL); + timeout_timer = lv_timer_create(timeout_timer_cb, 30000, NULL); + lv_timer_set_repeat_count(timeout_timer, 1); + + root_page = lv_obj_create(root); + lv_obj_set_style_pad_row(root_page, 2, 0); + lv_obj_set_style_border_side(root_page, LV_BORDER_SIDE_NONE, 0); + lv_obj_set_size(root_page, LV_PCT(100), LV_PCT(100)); + lv_obj_center(root_page); + // May change to a roller and have both on the same screen, need to check if it can be added dynamically: https://docs.lvgl.io/8.3/widgets/core/roller.html + lv_obj_set_flex_flow(root_page, LV_FLEX_FLOW_COLUMN); + lv_obj_add_event_cb(root_page, scroll_event_cb, LV_EVENT_SCROLL, NULL); + lv_obj_set_style_radius(root_page, LV_RADIUS_CIRCLE, 0); + lv_obj_set_scroll_dir(root_page, LV_DIR_VER); + lv_obj_set_scroll_snap_y(root_page, LV_SCROLL_SNAP_CENTER); + lv_obj_set_scrollbar_mode(root_page, LV_SCROLLBAR_MODE_OFF); + + lv_obj_t *title = lv_label_create(root_page); + lv_obj_set_width(title, LV_PCT(100)); + lv_obj_align(title, LV_ALIGN_TOP_MID, 0, 55); /*Aling to the center of screen*/ + lv_obj_set_style_text_align(title, LV_TEXT_ALIGN_CENTER, 0); /*Allign text center*/ + lv_obj_set_style_text_font(title, &lv_font_montserrat_18, 0); /*Change font size*/ + lv_label_set_text(title, header); + + /*Create a spinner*/ + spinner = lv_spinner_create(lv_layer_top(), 1000, 60); + lv_obj_set_size(spinner, LV_PCT(40), LV_PCT(40)); + lv_obj_center(spinner); +} + +static void lea_assistant_ui_add_list_entry(lea_assistant_device_t *device) +{ + if (spinner != NULL) { + lv_obj_del(spinner); + spinner = NULL; + } + + lv_obj_t *btn = lv_obj_create(root_page); + lv_obj_center(btn); + lv_obj_set_style_border_side(btn, LV_BORDER_SIDE_NONE, 0); + lv_obj_set_scrollbar_mode(btn, LV_SCROLLBAR_MODE_OFF); + lv_obj_set_size(btn, LV_PCT(100), LV_PCT(20)); + lv_obj_add_flag(btn, LV_OBJ_FLAG_SCROLL_ON_FOCUS); + + lv_obj_t *title = lv_label_create(btn); + lv_label_set_text(title, device->name); + lv_obj_set_size(title, LV_SIZE_CONTENT, LV_SIZE_CONTENT); + lv_obj_align(title, LV_ALIGN_LEFT_MID, 0, 0); + lv_obj_set_style_text_font(title, &lv_font_montserrat_16, 0); + + lv_obj_set_user_data(btn, title); + lv_obj_add_event_cb(btn, click_event_cb, LV_EVENT_CLICKED, device); +} + +void lea_assistant_ui_add_sink_list_entry(lea_assistant_device_t *device) +{ + for (size_t i = 0; i < sink_list.num; i++) { + if (bt_addr_le_cmp(&device->addr, &sink_list.device[i].addr) == 0) { + LOG_DBG("Device already added (%s)", device->name); + return; + } + } + + if (sink_list.num > MAX_DEVICES_NUM) { + LOG_WRN("MAX devices reached"); + return; + } + + bt_addr_le_copy(&sink_list.device[sink_list.num].addr, &device->addr); + strcpy(sink_list.device[sink_list.num].name, device->name); + + lea_assistant_ui_add_list_entry(&sink_list.device[sink_list.num]); + + sink_list.num++; +} + +void lea_assistant_ui_add_source_list_entry(lea_assistant_device_t *device) +{ + for (size_t i = 0; i < source_list.num; i++) { + if (bt_addr_le_cmp(&device->addr, &source_list.device[i].addr) == 0) { + LOG_DBG("Device already added (%s)", device->name); + return; + } + } + + if (source_list.num > MAX_DEVICES_NUM) { + LOG_WRN("MAX devices reached"); + return; + } + + source_list.device[source_list.num].pa_interval = device->pa_interval; + source_list.device[source_list.num].broadcast_id = device->broadcast_id; + source_list.device[source_list.num].sid = device->sid; + bt_addr_le_copy(&source_list.device[source_list.num].addr, &device->addr); + strcpy(source_list.device[source_list.num].name, device->name); + + lea_assistant_ui_add_list_entry(&source_list.device[source_list.num]); + + source_list.num++; +} + +void lea_assistant_ui_show(lv_obj_t *root, on_button_press_cb_t on_button_click_cb, on_close_cb_t close_cb) +{ + sink_list.num = 0; + click_callback = on_button_click_cb; + close_callback = close_cb; + page_init(root, "Audio sink:"); +} + +void lea_assistant_ui_show_source(lv_obj_t *root, on_button_press_cb_t on_button_click_cb) +{ + if (root_page != NULL) { + lv_obj_del(root_page); + root_page = NULL; + } + + source_list.num = 0; + + click_callback = on_button_click_cb; + page_init(root, "Audio source:"); +} + +void lea_assistant_ui_remove(void) +{ + if (mbox != NULL) { + lv_msgbox_close(mbox); + } + + if (root_page != NULL) { + lv_obj_del(root_page); + root_page = NULL; + } + + if (spinner != NULL) { + lv_obj_del(spinner); + spinner = NULL; + } +} diff --git a/app/src/applications/lea_assistant/lea_assistant_ui.h b/app/src/applications/lea_assistant/lea_assistant_ui.h new file mode 100644 index 00000000..616a61e0 --- /dev/null +++ b/app/src/applications/lea_assistant/lea_assistant_ui.h @@ -0,0 +1,18 @@ +#pragma once + +#include +#include +#include "lea_assistant_app.h" + +typedef void (*on_button_press_cb_t)(lea_assistant_device_t *device); +typedef void(*on_close_cb_t)(void); + +void lea_assistant_ui_show(lv_obj_t *root, on_button_press_cb_t on_button_click_cb, on_close_cb_t close_cb); + +void lea_assistant_ui_show_source(lv_obj_t *root, on_button_press_cb_t on_button_click_cb); + +void lea_assistant_ui_add_sink_list_entry(lea_assistant_device_t *device); + +void lea_assistant_ui_add_source_list_entry(lea_assistant_device_t *device); + +void lea_assistant_ui_remove(void); diff --git a/app/src/applications/lea_assistant/message_handler.c b/app/src/applications/lea_assistant/message_handler.c new file mode 100644 index 00000000..da8fd92d --- /dev/null +++ b/app/src/applications/lea_assistant/message_handler.c @@ -0,0 +1,312 @@ +/* + * Copyright (c) 2024 Demant A/S + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** @note this is adapted from https://github.com/AstraeusLabs/web-broadcast-assistant/tree/f1655305f3f1064fde04ed6f6744ca188bdc1670 */ + +#include +#include +#include +#include +#include +#include + +#include "mock_webusb.h" +#include "broadcast_assistant.h" +#include "message_handler.h" + +LOG_MODULE_REGISTER(message_handler, LOG_LEVEL_INF); + +NET_BUF_POOL_DEFINE(command_tx_msg_pool, CONFIG_TX_MSG_MAX_MESSAGES, sizeof(struct webusb_message) + CONFIG_TX_MSG_MAX_PAYLOAD_LEN, 0, NULL); + +struct webusb_ltv_data { + uint8_t adv_sid; + uint16_t pa_interval; + uint32_t broadcast_id; + bt_addr_le_t addr; +} __packed; + + +static void heartbeat_timeout_handler(struct k_timer *dummy_p); +K_TIMER_DEFINE(heartbeat_timer, heartbeat_timeout_handler, NULL); + +static void log_ltv(uint8_t *data, uint16_t data_len); + +#define LTV_STR_LEN 256 + +static void log_ltv(uint8_t *data, uint16_t data_len) +{ + char ltv_str[LTV_STR_LEN] = {0}; + + /* Log message payload (ltv format) */ + for (int i = 0; i < data_len;) { + uint8_t ltv_len = *data++; + char *ch_ptr = <v_str[0]; + + /* length */ + sprintf(ch_ptr, "[ L:%02x ", ltv_len); + ch_ptr += 7; + if (ltv_len > 0) { + /* type */ + sprintf(ch_ptr, "T:%02x ", *data++); + ch_ptr += 5; + if (ltv_len > 1) { + /* value */ + for (int j = 1; j < ltv_len; j++) { + sprintf(ch_ptr, "%02x ", *data++); + ch_ptr += 3; + } + } + } + sprintf(ch_ptr, "]"); + ch_ptr += 1; + i += (ltv_len + 1); + + LOG_DBG("%s", ltv_str); + } +} + +static struct webusb_ltv_data parsed_ltv_data; +static void heartbeat_timeout_handler(struct k_timer *timer) +{ + static uint8_t heartbeat_cnt = 0; + struct net_buf *tx_net_buf; + int ret; + + tx_net_buf = net_buf_alloc(&command_tx_msg_pool, K_FOREVER); + if (!tx_net_buf) { + return; + } + + net_buf_push_le16(tx_net_buf, 0); + net_buf_push_u8(tx_net_buf, heartbeat_cnt++); + net_buf_push_u8(tx_net_buf, MESSAGE_SUBTYPE_HEARTBEAT); + net_buf_push_u8(tx_net_buf, MESSAGE_TYPE_EVT); + + ret = webusb_transmit(tx_net_buf); + if (ret != 0) { + LOG_ERR("Failed to send response (err=%d)", ret); + } +} + +struct net_buf* message_alloc_tx_message(void) +{ + struct net_buf *tx_net_buf; + + tx_net_buf = net_buf_alloc(&command_tx_msg_pool, K_NO_WAIT); + if (!tx_net_buf) { + return NULL; + } + + // Reserve headroom for the webusb msg header + net_buf_reserve(tx_net_buf, sizeof(struct webusb_message)); + + return tx_net_buf; +} + +static void send_simple_message(enum message_type mtype, enum message_sub_type stype, uint8_t seq_no, int32_t rc) +{ + struct net_buf *tx_net_buf; + uint16_t msg_payload_length; + int ret; + + LOG_DBG("send simple message(%d, %d, %u, %d)", mtype, stype, seq_no, rc); + + + tx_net_buf = message_alloc_tx_message(); + if (!tx_net_buf) { + LOG_ERR("Failed to allocate net_buf"); + } + + /* Append error code payload */ + net_buf_add_u8(tx_net_buf, 5); + net_buf_add_u8(tx_net_buf, BT_DATA_ERROR_CODE); + net_buf_add_le32(tx_net_buf, rc); + msg_payload_length = tx_net_buf->len; + + // Prepend message header + net_buf_push_le16(tx_net_buf, msg_payload_length); + net_buf_push_u8(tx_net_buf, seq_no); + net_buf_push_u8(tx_net_buf, stype); + net_buf_push_u8(tx_net_buf, mtype); + + log_ltv(&tx_net_buf->data[0], tx_net_buf->len); + + ret = webusb_transmit(tx_net_buf); + if (ret != 0) { + LOG_ERR("Failed to send message (err=%d)", ret); + } + +} + +void send_response(enum message_sub_type stype, uint8_t seq_no, int32_t rc) +{ + send_simple_message(MESSAGE_TYPE_RES, stype, seq_no, rc); +} + +void send_event(enum message_sub_type stype, int32_t rc) +{ + send_simple_message(MESSAGE_TYPE_EVT, stype, 0, rc); +} + +void send_net_buf_event(enum message_sub_type stype, struct net_buf *tx_net_buf) +{ + int ret; + + // Prepend message header + net_buf_push_le16(tx_net_buf, tx_net_buf->len); + net_buf_push_u8(tx_net_buf, 0); + net_buf_push_u8(tx_net_buf, stype); + net_buf_push_u8(tx_net_buf, MESSAGE_TYPE_EVT); + + LOG_DBG("send_net_buf_event(stype: %d)", stype); + log_ltv(&tx_net_buf->data[0], tx_net_buf->len); + + ret = webusb_transmit(tx_net_buf); + if (ret != 0) { + LOG_ERR("Failed to send message (err=%d)", ret); + } +} + +bool ltv_found(struct bt_data *data, void *user_data) +{ + struct webusb_ltv_data *_parsed = (struct webusb_ltv_data *)user_data; + + LOG_DBG("Found LTV structure with type %u", data->type); + + switch (data->type) { + case BT_DATA_SID: + LOG_DBG("BT_DATA_SID"); + _parsed->adv_sid = data->data[0]; + return true; + case BT_DATA_PA_INTERVAL: + _parsed->pa_interval = sys_get_le16(data->data); + LOG_DBG("BT_DATA_PA_INTERVAL"); + return true; + case BT_DATA_BROADCAST_ID: + _parsed->broadcast_id = sys_get_le24(data->data); + LOG_DBG("BT_DATA_BROADCAST_ID"); + return true; + case BT_DATA_RPA: + case BT_DATA_IDENTITY: + char addr_str[BT_ADDR_LE_STR_LEN]; + _parsed->addr.type = data->data[0]; + memcpy(&_parsed->addr.a, &data->data[1], sizeof(bt_addr_t)); + bt_addr_le_to_str(&_parsed->addr, addr_str, sizeof(addr_str)); + LOG_DBG("Addr: %s", addr_str); + return true; + default: + LOG_DBG("Unknown type"); + } + + return false; +} + +void message_handler(struct webusb_message *msg_ptr, uint16_t msg_length) +{ + if (msg_ptr == NULL) { + LOG_ERR("Null msg_ptr"); + return; + } + + /*uint8_t msg_type = msg_ptr->type;*/ + uint8_t msg_sub_type = msg_ptr->sub_type; + uint8_t msg_seq_no = msg_ptr->seq_no; + int32_t msg_rc = 0; + struct net_buf_simple msg_net_buf; + + msg_net_buf.data = msg_ptr->payload; + msg_net_buf.len = msg_ptr->length; + msg_net_buf.size = CONFIG_TX_MSG_MAX_PAYLOAD_LEN; + msg_net_buf.__buf = msg_ptr->payload; + + bt_data_parse(&msg_net_buf, ltv_found, (void *)&parsed_ltv_data); + + switch (msg_sub_type) { + case MESSAGE_SUBTYPE_HEARTBEAT: + static bool heartbeat_on = false; + if (!heartbeat_on) { + // Start generating heartbeats every second + heartbeat_on = true; + k_timer_start(&heartbeat_timer, K_SECONDS(1), K_SECONDS(1)); + } else { + heartbeat_on = false; + // Stop heartbeat timer if running + k_timer_stop(&heartbeat_timer); + } + send_response(MESSAGE_SUBTYPE_HEARTBEAT, msg_seq_no, 0); + break; + + case MESSAGE_SUBTYPE_START_SINK_SCAN: + LOG_DBG("MESSAGE_SUBTYPE_START_SINK_SCAN"); + msg_rc = start_scan(BROADCAST_ASSISTANT_SCAN_TARGET_SINK); + send_response(MESSAGE_SUBTYPE_START_SINK_SCAN, msg_seq_no, msg_rc); + break; + + case MESSAGE_SUBTYPE_START_SOURCE_SCAN: + LOG_DBG("MESSAGE_SUBTYPE_START_SOURCE_SCAN"); + msg_rc = start_scan(BROADCAST_ASSISTANT_SCAN_TARGET_SOURCE); + send_response(MESSAGE_SUBTYPE_START_SOURCE_SCAN, msg_seq_no, msg_rc); + break; + + case MESSAGE_SUBTYPE_START_SCAN_ALL: + LOG_DBG("MESSAGE_SUBTYPE_START_SCAN_ALL"); + msg_rc = start_scan(BROADCAST_ASSISTANT_SCAN_TARGET_ALL); + send_response(MESSAGE_SUBTYPE_START_SCAN_ALL, msg_seq_no, msg_rc); + break; + + case MESSAGE_SUBTYPE_STOP_SCAN: + LOG_DBG("MESSAGE_SUBTYPE_STOP_SCAN"); + msg_rc = stop_scanning(); + send_response(MESSAGE_SUBTYPE_STOP_SCAN, msg_seq_no, msg_rc); + break; + + case MESSAGE_SUBTYPE_CONNECT_SINK: + LOG_DBG("MESSAGE_SUBTYPE_CONNECT_SINK (len %u)", msg_length); + msg_rc = connect_to_sink(&parsed_ltv_data.addr); + send_response(MESSAGE_SUBTYPE_CONNECT_SINK, msg_seq_no, msg_rc); + break; + + case MESSAGE_SUBTYPE_DISCONNECT_SINK: + LOG_DBG("MESSAGE_SUBTYPE_DISCONNECT_SINK (len %u)", msg_length); + msg_rc = disconnect_from_sink(&parsed_ltv_data.addr); + send_response(MESSAGE_SUBTYPE_DISCONNECT_SINK, msg_seq_no, msg_rc); + break; + + case MESSAGE_SUBTYPE_ADD_SOURCE: + LOG_DBG("MESSAGE_SUBTYPE_ADD_SOURCE (len %u)", msg_length); + msg_rc = add_source(parsed_ltv_data.adv_sid, parsed_ltv_data.pa_interval, + parsed_ltv_data.broadcast_id, &parsed_ltv_data.addr); + send_response(MESSAGE_SUBTYPE_ADD_SOURCE, msg_seq_no, msg_rc); + break; + + case MESSAGE_SUBTYPE_REMOVE_SOURCE: + LOG_DBG("MESSAGE_SUBTYPE_REMOVE_SOURCE (len %u)", msg_length); + msg_rc = remove_source(); + send_response(MESSAGE_SUBTYPE_REMOVE_SOURCE, msg_seq_no, msg_rc); + break; + + case MESSAGE_SUBTYPE_RESET: + LOG_DBG("MESSAGE_SUBTYPE_RESET (len %u)", msg_length); + msg_rc = stop_scanning(); + send_response(MESSAGE_SUBTYPE_STOP_SCAN, msg_seq_no, msg_rc); + msg_rc = disconnect_unpair_all(); + send_response(MESSAGE_SUBTYPE_RESET, msg_seq_no, msg_rc); + // Stop heartbeat if active + heartbeat_on = false; + k_timer_stop(&heartbeat_timer); + break; + + default: + // Unrecognized message + send_response(msg_sub_type, msg_seq_no, -1); + break; + } +} + +void message_handler_init(void) +{ + k_timer_init(&heartbeat_timer, heartbeat_timeout_handler, NULL); +} diff --git a/app/src/applications/lea_assistant/message_handler.h b/app/src/applications/lea_assistant/message_handler.h new file mode 100644 index 00000000..3eecc99d --- /dev/null +++ b/app/src/applications/lea_assistant/message_handler.h @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2024 Demant A/S + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** @note this is adapted from https://github.com/AstraeusLabs/web-broadcast-assistant/tree/f1655305f3f1064fde04ed6f6744ca188bdc1670 */ + +#ifndef __COMMAND_H__ +#define __COMMAND_H__ + +#include +#include + +#define CONFIG_TX_MSG_MAX_MESSAGES 4 +#define CONFIG_TX_MSG_MAX_PAYLOAD_LEN 1024 + +enum message_type { + MESSAGE_TYPE_CMD = 1, + MESSAGE_TYPE_RES, + MESSAGE_TYPE_EVT, +}; + +enum message_sub_type { + /* CMD/RES (bit7 = 0) */ + MESSAGE_SUBTYPE_START_SINK_SCAN = 0x01, + MESSAGE_SUBTYPE_START_SOURCE_SCAN = 0x02, + MESSAGE_SUBTYPE_START_SCAN_ALL = 0x03, + MESSAGE_SUBTYPE_STOP_SCAN = 0x04, + MESSAGE_SUBTYPE_CONNECT_SINK = 0x05, + MESSAGE_SUBTYPE_DISCONNECT_SINK = 0x06, + MESSAGE_SUBTYPE_ADD_SOURCE = 0x07, + MESSAGE_SUBTYPE_REMOVE_SOURCE = 0x08, + MESSAGE_SUBTYPE_RESET = 0x2A, + + /* EVT (bit7 = 1) */ + MESSAGE_SUBTYPE_SINK_FOUND = 0x81, + MESSAGE_SUBTYPE_SOURCE_FOUND = 0x82, + MESSAGE_SUBTYPE_SINK_CONNECTED = 0x83, + MESSAGE_SUBTYPE_SINK_DISCONNECTED = 0x84, + MESSAGE_SUBTYPE_SOURCE_ADDED = 0x85, + MESSAGE_SUBTYPE_SOURCE_REMOVED = 0x86, + MESSAGE_SUBTYPE_NEW_PA_STATE_NOT_SYNCED = 0x87, + MESSAGE_SUBTYPE_NEW_PA_STATE_INFO_REQ = 0x88, + MESSAGE_SUBTYPE_NEW_PA_STATE_SYNCED = 0x89, + MESSAGE_SUBTYPE_NEW_PA_STATE_FAILED = 0x8A, + MESSAGE_SUBTYPE_NEW_PA_STATE_NO_PAST = 0x8B, + MESSAGE_SUBTYPE_BIS_SYNCED = 0x8C, + MESSAGE_SUBTYPE_BIS_NOT_SYNCED = 0x8D, + MESSAGE_SUBTYPE_IDENTITY_RESOLVED = 0x8E, + MESSAGE_SUBTYPE_SOURCE_BASE_FOUND = 0x8F, + + MESSAGE_SUBTYPE_HEARTBEAT = 0xFF, +}; + +struct webusb_message { + uint8_t type; + uint8_t sub_type; + uint8_t seq_no; + uint16_t length; + uint8_t payload[]; +} __packed; + +struct net_buf *message_alloc_tx_message(void); +void send_response(enum message_sub_type stype, uint8_t seq_no, int32_t rc); +void send_event(enum message_sub_type stype, int32_t rc); +void send_net_buf_event(enum message_sub_type stype, struct net_buf *tx_net_buf); +void message_handler(struct webusb_message *msg_ptr, uint16_t msg_length); +void message_handler_init(void); + +#endif /* __COMMAND_H__ */ diff --git a/app/src/applications/lea_assistant/mock_webusb.c b/app/src/applications/lea_assistant/mock_webusb.c new file mode 100644 index 00000000..6a17de9d --- /dev/null +++ b/app/src/applications/lea_assistant/mock_webusb.c @@ -0,0 +1,141 @@ +#include "mock_webusb.h" +#include "message_handler.h" +#include "lea_assistant_app.h" + +#include +#include + +LOG_MODULE_REGISTER(mock_webusb, CONFIG_ZSW_LEA_ASSISTANT_APP_LOG_LEVEL); + +struct webusb_ltv_data { + uint8_t adv_sid; + uint16_t pa_interval; + uint32_t broadcast_id; + bt_addr_le_t addr; + char bt_name[BT_NAME_LEN]; + char broadcast_name[BT_NAME_LEN]; +} __packed; + +static struct webusb_ltv_data parsed_ltv_data; + +static bool data_found(struct bt_data *data, void *user_data) +{ + struct webusb_ltv_data *_parsed = (struct webusb_ltv_data *)user_data; + + LOG_DBG("Found LTV structure with type %u", data->type); + + switch (data->type) { + case BT_DATA_SID: + _parsed->adv_sid = data->data[0]; + LOG_DBG("BT_DATA_SID: 0x%X", _parsed->adv_sid); + return true; + case BT_DATA_PA_INTERVAL: + _parsed->pa_interval = sys_get_le16(data->data); + LOG_DBG("BT_DATA_PA_INTERVAL: 0x%X", _parsed->pa_interval); + return true; + case BT_DATA_BROADCAST_ID: + _parsed->broadcast_id = sys_get_le32(data->data); + LOG_DBG("BT_DATA_BROADCAST_ID: 0x%X", _parsed->broadcast_id); + return true; + case BT_DATA_RPA: + case BT_DATA_IDENTITY: + char addr_str[BT_ADDR_LE_STR_LEN]; + _parsed->addr.type = data->data[0]; + memcpy(&_parsed->addr.a, &data->data[1], sizeof(bt_addr_t)); + bt_addr_le_to_str(&_parsed->addr, addr_str, sizeof(addr_str)); + LOG_DBG("Addr: %s", addr_str); + return true; + case BT_DATA_NAME_SHORTENED: + case BT_DATA_NAME_COMPLETE: + memcpy(_parsed->bt_name, data->data, MIN(data->data_len, BT_NAME_LEN - 1)); + LOG_DBG("BT name: %s", _parsed->bt_name); + return true; + case BT_DATA_BROADCAST_NAME: + memcpy(_parsed->broadcast_name, data->data, MIN(data->data_len, BT_NAME_LEN - 1)); + LOG_DBG("Broadcast name: %s", _parsed->broadcast_name); + return true; + default: + LOG_DBG("Unknown type"); + return true; + } + + return false; +} + +int webusb_transmit(struct net_buf *tx_net_buf) +{ + if (tx_net_buf == NULL) { + LOG_ERR("Null msg_ptr"); + return 1; + } + + struct webusb_message *webusb_message = (struct webusb_message *)tx_net_buf->b.data; + + struct net_buf_simple msg_net_buf = { + .data = webusb_message->payload, + .len = webusb_message->length, + .size = CONFIG_TX_MSG_MAX_PAYLOAD_LEN, + .__buf = webusb_message->payload, + }; + + bt_data_parse(&msg_net_buf, data_found, (void *)&parsed_ltv_data); + + switch (webusb_message->sub_type) { + case MESSAGE_SUBTYPE_SOURCE_FOUND: + LOG_DBG("MESSAGE_SUBTYPE_SOURCE_FOUND"); + lea_assistant_device_t source = { + .pa_interval = parsed_ltv_data.pa_interval, + .sid = parsed_ltv_data.adv_sid, + .broadcast_id = parsed_ltv_data.broadcast_id, + }; + + bt_addr_le_copy(&source.addr, &parsed_ltv_data.addr); + + if (parsed_ltv_data.broadcast_name[0] != '\0') { + strcpy(source.name, parsed_ltv_data.broadcast_name); + } else if (parsed_ltv_data.bt_name[0] != '\0') { + strcpy(source.name, parsed_ltv_data.bt_name); + } else { + // No name + break; + } + + lea_assistant_app_add_source_entry(&source); + break; + + case MESSAGE_SUBTYPE_SINK_FOUND: + LOG_DBG("MESSAGE_SUBTYPE_SINK_FOUND"); + lea_assistant_device_t sink; + + if (parsed_ltv_data.bt_name[0] != '\0') { + strcpy(sink.name, parsed_ltv_data.bt_name); + bt_addr_le_copy(&sink.addr, &parsed_ltv_data.addr); + } else { + // No name + break; + } + + lea_assistant_app_add_sink_entry(&sink); + break; + + case MESSAGE_SUBTYPE_SINK_CONNECTED: + LOG_DBG("MESSAGE_SUBTYPE_SINK_CONNECTED"); + lea_assistant_app_sink_connected(); + break; + + case MESSAGE_SUBTYPE_SINK_DISCONNECTED: + LOG_DBG("MESSAGE_SUBTYPE_SINK_DISCONNECTED"); + break; + + case MESSAGE_SUBTYPE_SOURCE_ADDED: + LOG_DBG("MESSAGE_SUBTYPE_SOURCE_ADDED"); + break; + + default: + break; + } + + net_buf_unref(tx_net_buf); + + return 0; +} diff --git a/app/src/applications/lea_assistant/mock_webusb.h b/app/src/applications/lea_assistant/mock_webusb.h new file mode 100644 index 00000000..4d713abb --- /dev/null +++ b/app/src/applications/lea_assistant/mock_webusb.h @@ -0,0 +1,8 @@ +#pragma once + +#include + +/** + * @brief we don't use USB or the webversion of the code example, so mock some functions to keep it close to the source. + */ +int webusb_transmit(struct net_buf *tx_net_buf); diff --git a/app/src/ble/ble_ams.c b/app/src/ble/ble_ams.c index 4f0dddd3..753f2166 100644 --- a/app/src/ble/ble_ams.c +++ b/app/src/ble/ble_ams.c @@ -324,6 +324,12 @@ static void ams_discover_retry_handle(struct k_work *item) static void security_changed(struct bt_conn *conn, bt_security_t level, enum bt_security_err err) { + struct bt_conn_info info; + bt_conn_get_info(conn, &info); + if (info.role != BT_CONN_ROLE_PERIPHERAL) { + return; + } + if (!err) { LOG_DBG("Security changed: level %u", level); diff --git a/app/src/ble/ble_ancs.c b/app/src/ble/ble_ancs.c index 6388788f..deb66ed5 100644 --- a/app/src/ble/ble_ancs.c +++ b/app/src/ble/ble_ancs.c @@ -301,6 +301,12 @@ static void discover_ancs_again(struct bt_conn *conn) static void security_changed(struct bt_conn *conn, bt_security_t level, enum bt_security_err err) { + struct bt_conn_info info; + bt_conn_get_info(conn, &info); + if (info.role != BT_CONN_ROLE_PERIPHERAL) { + return; + } + char addr[BT_ADDR_LE_STR_LEN]; bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); diff --git a/app/src/ble/ble_comm.c b/app/src/ble/ble_comm.c index 9fa23587..8ef08e37 100644 --- a/app/src/ble/ble_comm.c +++ b/app/src/ble/ble_comm.c @@ -309,14 +309,19 @@ static void ble_connected(struct bt_conn *conn, uint8_t err) LOG_ERR("Connection failed (err %u)", err); return; } + + struct bt_conn_info info; + bt_conn_get_info(conn, &info); + if (info.role != BT_CONN_ROLE_PERIPHERAL) { + return; + } + current_conn = bt_conn_ref(conn); max_send_len = 20; bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); LOG_INF("Connected %s", addr); request_mtu_exchange(); - struct bt_conn_info info; - bt_conn_get_info(conn, &info); LOG_INF("Interval: %d, latency: %d, timeout: %d", info.le.interval, info.le.latency, info.le.timeout); // Right after a new connection we want short connection interval diff --git a/app/src/ble/ble_cts.c b/app/src/ble/ble_cts.c index 9a24f395..03c29059 100644 --- a/app/src/ble/ble_cts.c +++ b/app/src/ble/ble_cts.c @@ -182,6 +182,12 @@ static void read_current_time_cb(struct bt_cts_client *cts_c, static void pairing_complete(struct bt_conn *conn, bool bonded) { + struct bt_conn_info info; + bt_conn_get_info(conn, &info); + if (info.role != BT_CONN_ROLE_PERIPHERAL) { + return; + } + LOG_DBG("Pairing completed, get time"); int err = bt_cts_read_current_time(&cts_c, read_current_time_cb); @@ -233,6 +239,12 @@ static void connected(struct bt_conn *conn, uint8_t err) has_cts = false; + struct bt_conn_info info; + bt_conn_get_info(conn, &info); + if (info.role != BT_CONN_ROLE_PERIPHERAL) { + return; + } + discover_gattp(conn); } diff --git a/app/src/images/auracast.c b/app/src/images/auracast.c new file mode 100644 index 00000000..382ea489 --- /dev/null +++ b/app/src/images/auracast.c @@ -0,0 +1,174 @@ +#ifdef __has_include + #if __has_include("lvgl.h") + #ifndef LV_LVGL_H_INCLUDE_SIMPLE + #define LV_LVGL_H_INCLUDE_SIMPLE + #endif + #endif +#endif + +#if defined(LV_LVGL_H_INCLUDE_SIMPLE) + #include "lvgl.h" +#else + #include "lvgl/lvgl.h" +#endif + + +#ifndef LV_ATTRIBUTE_MEM_ALIGN +#define LV_ATTRIBUTE_MEM_ALIGN +#endif + +#ifndef LV_ATTRIBUTE_IMG_AURACAST +#define LV_ATTRIBUTE_IMG_AURACAST +#endif + +const LV_ATTRIBUTE_MEM_ALIGN LV_ATTRIBUTE_LARGE_CONST LV_ATTRIBUTE_IMG_AURACAST uint8_t auracast_map[] = { +#if LV_COLOR_DEPTH == 1 || LV_COLOR_DEPTH == 8 + /*Pixel format: Alpha 8 bit, Red: 3 bit, Green: 3 bit, Blue: 2 bit*/ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x17, 0x13, 0x2a, 0x13, 0x2a, 0x17, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x01, 0x17, 0x05, 0x00, 0x00, 0x00, 0x00, 0x13, 0x20, 0x13, 0x8a, 0x13, 0xcf, 0x13, 0xeb, 0x13, 0xeb, 0x13, 0xc5, 0x13, 0x72, 0x17, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x17, 0x13, 0x72, 0x13, 0x2a, 0x00, 0x00, 0x13, 0x2a, 0x13, 0xc5, 0x13, 0xff, 0x13, 0xff, 0x13, 0xff, 0x13, 0xff, 0x13, 0xff, 0x13, 0xff, 0x13, 0xa4, 0x17, 0x0e, 0x00, 0x00, 0x17, 0x05, 0x13, 0x52, 0x13, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x31, 0x13, 0xc5, 0x13, 0x8a, 0x1f, 0x01, 0x17, 0x0e, 0x13, 0xb2, 0x13, 0xff, 0x13, 0xff, 0x13, 0xb9, 0x13, 0x72, 0x13, 0x7f, 0x13, 0xcf, 0x13, 0xff, 0x13, 0xff, 0x13, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x13, 0x5d, 0x13, 0xb9, 0x13, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x3c, 0x13, 0xda, 0x13, 0xc5, 0x13, 0x17, 0x00, 0x00, 0x13, 0x66, 0x13, 0xf7, 0x13, 0xff, 0x13, 0x97, 0x17, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x13, 0x20, 0x13, 0xc5, 0x13, 0xff, 0x13, 0xe1, 0x13, 0x2a, 0x00, 0x00, 0x17, 0x0e, 0x13, 0xb9, 0x13, 0xda, 0x13, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x31, 0x13, 0xda, 0x13, 0xf1, 0x13, 0x46, 0x00, 0x00, 0x13, 0x2a, 0x13, 0xda, 0x13, 0xff, 0x13, 0xda, 0x13, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x52, 0x13, 0xf7, 0x13, 0xff, 0x13, 0x97, 0x1f, 0x01, 0x00, 0x00, 0x13, 0x46, 0x13, 0xf7, 0x13, 0xcf, 0x13, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x1f, 0x01, 0x17, 0x0e, 0x13, 0xb9, 0x13, 0xff, 0x13, 0x8a, 0x1f, 0x01, 0x17, 0x05, 0x13, 0x97, 0x13, 0xff, 0x13, 0xf7, 0x13, 0x5d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x05, 0x13, 0xa4, 0x13, 0xff, 0x13, 0xeb, 0x13, 0x3c, 0x00, 0x00, 0x17, 0x05, 0x13, 0xa4, 0x13, 0xff, 0x13, 0xa4, 0x17, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x72, 0x13, 0xff, 0x13, 0xc5, 0x13, 0x17, 0x00, 0x00, 0x13, 0x52, 0x13, 0xf7, 0x13, 0xff, 0x13, 0xa4, 0x17, 0x05, 0x00, 0x00, 0x17, 0x05, 0x13, 0x2a, 0x13, 0x20, 0x00, 0x00, 0x00, 0x00, 0x13, 0x3c, 0x13, 0xeb, 0x13, 0xff, 0x13, 0xb2, 0x17, 0x05, 0x00, 0x00, 0x13, 0x31, 0x13, 0xeb, 0x13, 0xf7, 0x13, 0x52, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x13, 0x20, 0x13, 0xda, 0x13, 0xf1, 0x13, 0x46, 0x00, 0x00, 0x13, 0x17, 0x13, 0xc5, 0x13, 0xff, 0x13, 0xe1, 0x13, 0x31, 0x00, 0x00, 0x17, 0x0e, 0x13, 0x97, 0x13, 0xeb, 0x13, 0xda, 0x13, 0x52, 0x00, 0x00, 0x1f, 0x01, 0x13, 0x97, 0x13, 0xff, 0x13, 0xf7, 0x13, 0x52, 0x00, 0x00, 0x00, 0x00, 0x13, 0x8a, 0x13, 0xff, 0x13, 0xb9, 0x17, 0x0e, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x13, 0x66, 0x13, 0xff, 0x13, 0x8a, 0x1f, 0x01, 0x00, 0x00, 0x13, 0x7f, 0x13, 0xff, 0x13, 0xff, 0x13, 0x72, 0x00, 0x00, 0x00, 0x00, 0x13, 0x66, 0x13, 0xff, 0x13, 0xff, 0x13, 0xff, 0x13, 0xcf, 0x13, 0x17, 0x00, 0x00, 0x13, 0x2a, 0x13, 0xe1, 0x13, 0xff, 0x13, 0xc5, 0x17, 0x0e, 0x00, 0x00, 0x13, 0x20, 0x13, 0xda, 0x13, 0xf7, 0x13, 0x46, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x17, 0x05, 0x13, 0xb2, 0x13, 0xc5, 0x13, 0x17, 0x00, 0x00, 0x13, 0x3c, 0x13, 0xeb, 0x13, 0xff, 0x13, 0xb9, 0x17, 0x0e, 0x00, 0x00, 0x13, 0x20, 0x13, 0xda, 0x13, 0xff, 0x13, 0xff, 0x13, 0xff, 0x13, 0xff, 0x13, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x13, 0x7f, 0x13, 0xff, 0x13, 0xff, 0x13, 0x66, 0x00, 0x00, 0x00, 0x00, 0x13, 0x72, 0x13, 0xff, 0x13, 0x8a, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x13, 0x20, 0x13, 0xcf, 0x13, 0x46, 0x00, 0x00, 0x17, 0x0e, 0x13, 0xb9, 0x13, 0xff, 0x13, 0xf1, 0x13, 0x46, 0x00, 0x00, 0x1f, 0x01, 0x13, 0x97, 0x13, 0xff, 0x13, 0xf7, 0x13, 0x7f, 0x13, 0xc5, 0x13, 0xff, 0x13, 0xe1, 0x13, 0x2a, 0x00, 0x00, 0x13, 0x20, 0x13, 0xcf, 0x13, 0xff, 0x13, 0xcf, 0x13, 0x20, 0x00, 0x00, 0x13, 0x17, 0x13, 0xcf, 0x13, 0xc5, 0x17, 0x0e, 0x00, 0x00, + 0x00, 0x00, 0x13, 0x3c, 0x13, 0x72, 0x1f, 0x01, 0x00, 0x00, 0x13, 0x72, 0x13, 0xff, 0x13, 0xff, 0x13, 0x8a, 0x1f, 0x01, 0x00, 0x00, 0x13, 0x46, 0x13, 0xf1, 0x13, 0xff, 0x13, 0xb2, 0x17, 0x05, 0x13, 0x52, 0x13, 0xf7, 0x13, 0xff, 0x13, 0x8a, 0x1f, 0x01, 0x00, 0x00, 0x13, 0x66, 0x13, 0xff, 0x13, 0xff, 0x13, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x13, 0x5d, 0x13, 0xda, 0x13, 0x20, 0x00, 0x00, + 0x00, 0x00, 0x17, 0x0e, 0x17, 0x0e, 0x00, 0x00, 0x13, 0x2a, 0x13, 0xe1, 0x13, 0xff, 0x13, 0xcf, 0x13, 0x20, 0x00, 0x00, 0x13, 0x17, 0x13, 0xc5, 0x13, 0xff, 0x13, 0xeb, 0x13, 0x3c, 0x00, 0x00, 0x17, 0x05, 0x13, 0xb2, 0x13, 0xff, 0x13, 0xeb, 0x13, 0x3c, 0x00, 0x00, 0x17, 0x0e, 0x13, 0xc5, 0x13, 0xff, 0x13, 0xe1, 0x13, 0x2a, 0x00, 0x00, 0x17, 0x0e, 0x13, 0xa4, 0x13, 0x31, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x05, 0x13, 0xa4, 0x13, 0xff, 0x13, 0xf7, 0x13, 0x52, 0x00, 0x00, 0x00, 0x00, 0x13, 0x72, 0x13, 0xff, 0x13, 0xff, 0x13, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x3c, 0x13, 0xeb, 0x13, 0xff, 0x13, 0xa4, 0x17, 0x05, 0x00, 0x00, 0x13, 0x52, 0x13, 0xf7, 0x13, 0xff, 0x13, 0x97, 0x1f, 0x01, 0x00, 0x00, 0x13, 0x31, 0x13, 0x20, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x5d, 0x13, 0xf7, 0x13, 0xff, 0x13, 0xa4, 0x17, 0x05, 0x00, 0x00, 0x13, 0x31, 0x13, 0xe1, 0x13, 0xff, 0x13, 0xc5, 0x13, 0x17, 0x17, 0x05, 0x13, 0x31, 0x13, 0x3c, 0x13, 0x3c, 0x13, 0xcf, 0x13, 0xff, 0x13, 0xf1, 0x13, 0x46, 0x00, 0x00, 0x17, 0x05, 0x13, 0xa4, 0x13, 0xff, 0x13, 0xeb, 0x13, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x13, 0x17, 0x13, 0xcf, 0x13, 0xff, 0x13, 0xda, 0x13, 0x2a, 0x00, 0x00, 0x17, 0x05, 0x13, 0xa4, 0x13, 0xff, 0x13, 0xf7, 0x13, 0x52, 0x00, 0x00, 0x13, 0x72, 0x13, 0xf1, 0x13, 0xf1, 0x13, 0xf1, 0x13, 0xff, 0x13, 0xff, 0x13, 0xff, 0x13, 0xb9, 0x17, 0x0e, 0x00, 0x00, 0x13, 0x3c, 0x13, 0xeb, 0x13, 0xff, 0x13, 0xa4, 0x17, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x13, 0x3c, 0x13, 0xf7, 0x13, 0xff, 0x13, 0x72, 0x00, 0x00, 0x00, 0x00, 0x13, 0x52, 0x13, 0xf7, 0x13, 0xff, 0x13, 0xa4, 0x17, 0x05, 0x00, 0x00, 0x13, 0x8a, 0x13, 0xff, 0x13, 0xff, 0x13, 0xff, 0x13, 0xff, 0x13, 0xff, 0x13, 0xff, 0x13, 0xf7, 0x13, 0x5d, 0x00, 0x00, 0x1f, 0x01, 0x13, 0xa4, 0x13, 0xff, 0x13, 0xe1, 0x13, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x13, 0x2a, 0x13, 0xeb, 0x13, 0xcf, 0x13, 0x17, 0x00, 0x00, 0x17, 0x05, 0x13, 0xb2, 0x13, 0xff, 0x13, 0xe1, 0x13, 0x2a, 0x00, 0x00, 0x00, 0x00, 0x13, 0x17, 0x13, 0x52, 0x13, 0x5d, 0x13, 0x5d, 0x13, 0x5d, 0x13, 0x72, 0x13, 0xe1, 0x13, 0xff, 0x13, 0xc5, 0x17, 0x0e, 0x00, 0x00, 0x13, 0x66, 0x13, 0xff, 0x13, 0xf1, 0x13, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x17, 0x05, 0x13, 0xb9, 0x13, 0x97, 0x00, 0x00, 0x00, 0x00, 0x13, 0x17, 0x13, 0xda, 0x13, 0xff, 0x13, 0x97, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x66, 0x13, 0xf1, 0x13, 0xa4, 0x17, 0x05, 0x00, 0x00, 0x13, 0x72, 0x13, 0xff, 0x13, 0xf1, 0x13, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x5d, 0x13, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x13, 0x17, 0x13, 0xda, 0x13, 0xff, 0x13, 0x97, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x05, 0x13, 0x2a, 0x13, 0x17, 0x00, 0x00, 0x17, 0x0e, 0x13, 0xb9, 0x13, 0xff, 0x13, 0xcf, 0x13, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x0e, 0x13, 0x46, 0x1f, 0x01, 0x00, 0x00, 0x17, 0x05, 0x13, 0xb2, 0x13, 0xff, 0x13, 0xe1, 0x13, 0x46, 0x17, 0x05, 0x17, 0x05, 0x17, 0x05, 0x17, 0x05, 0x17, 0x05, 0x17, 0x05, 0x17, 0x05, 0x17, 0x05, 0x17, 0x05, 0x1f, 0x01, 0x17, 0x05, 0x13, 0x20, 0x13, 0x97, 0x13, 0xff, 0x13, 0xff, 0x13, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x01, 0x17, 0x05, 0x1f, 0x01, 0x00, 0x00, 0x00, 0x00, 0x13, 0x52, 0x13, 0xf7, 0x13, 0xff, 0x13, 0xeb, 0x13, 0xb9, 0x13, 0xb2, 0x13, 0xb2, 0x13, 0xb2, 0x13, 0xb2, 0x13, 0xb2, 0x13, 0xb2, 0x13, 0xb2, 0x13, 0xb2, 0x13, 0xb2, 0x13, 0xb9, 0x13, 0xda, 0x13, 0xff, 0x13, 0xff, 0x13, 0xc5, 0x13, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x05, 0x13, 0x72, 0x13, 0xf1, 0x13, 0xff, 0x13, 0xff, 0x13, 0xff, 0x13, 0xff, 0x13, 0xff, 0x13, 0xff, 0x13, 0xff, 0x13, 0xff, 0x13, 0xff, 0x13, 0xff, 0x13, 0xff, 0x13, 0xff, 0x13, 0xff, 0x13, 0xff, 0x13, 0xb2, 0x13, 0x2a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x05, 0x13, 0x3c, 0x13, 0x97, 0x13, 0xb9, 0x13, 0xb9, 0x13, 0xb9, 0x13, 0xb9, 0x13, 0xb9, 0x13, 0xb9, 0x13, 0xb9, 0x13, 0xb9, 0x13, 0xb9, 0x13, 0xb9, 0x13, 0xb9, 0x13, 0x97, 0x13, 0x5d, 0x17, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x01, 0x17, 0x05, 0x17, 0x05, 0x17, 0x05, 0x17, 0x05, 0x17, 0x05, 0x17, 0x05, 0x17, 0x05, 0x17, 0x05, 0x17, 0x05, 0x1f, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x01, 0x13, 0x2a, 0x13, 0x31, 0x13, 0x31, 0x13, 0x31, 0x13, 0x31, 0x13, 0x31, 0x13, 0x31, 0x13, 0x31, 0x13, 0x31, 0x13, 0x31, 0x13, 0x31, 0x13, 0x31, 0x13, 0x31, 0x13, 0x31, 0x17, 0x0e, 0x00, 0x00, 0x1f, 0x01, 0x13, 0x17, 0x13, 0x20, 0x13, 0x17, 0x17, 0x05, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x01, 0x13, 0x46, 0x13, 0xb9, 0x13, 0xeb, 0x13, 0xf1, 0x13, 0xf1, 0x13, 0xf1, 0x13, 0xf1, 0x13, 0xf1, 0x13, 0xf1, 0x13, 0xf1, 0x13, 0xf1, 0x13, 0xeb, 0x13, 0xcf, 0x13, 0x72, 0x17, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x13, 0x46, 0x13, 0x72, 0x13, 0x72, 0x13, 0x17, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x01, 0x1f, 0x01, 0x17, 0x0e, 0x13, 0x52, 0x13, 0x97, 0x13, 0xc5, 0x13, 0xe1, 0x13, 0xeb, 0x13, 0xeb, 0x13, 0xe1, 0x13, 0xcf, 0x13, 0xa4, 0x13, 0x66, 0x13, 0x20, 0x1f, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x0e, 0x13, 0x20, 0x13, 0x20, 0x17, 0x05, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x0e, 0x13, 0x20, 0x13, 0x2a, 0x13, 0x2a, 0x13, 0x20, 0x17, 0x0e, 0x1f, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +#endif +#if LV_COLOR_DEPTH == 16 && LV_COLOR_16_SWAP == 0 + /*Pixel format: Alpha 8 bit, Red: 5 bit, Green: 6 bit, Blue: 5 bit*/ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x04, 0x17, 0x3f, 0x04, 0x2a, 0x3f, 0x04, 0x2a, 0x9f, 0x04, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x07, 0x01, 0xdf, 0x04, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x04, 0x20, 0x3f, 0x04, 0x8a, 0x3f, 0x04, 0xcf, 0x3f, 0x04, 0xeb, 0x3f, 0x04, 0xeb, 0x3f, 0x04, 0xc5, 0x3f, 0x04, 0x72, 0x9f, 0x04, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x04, 0x17, 0x3f, 0x04, 0x72, 0x3f, 0x04, 0x2a, 0x00, 0x00, 0x00, 0x3f, 0x04, 0x2a, 0x3f, 0x04, 0xc5, 0x3f, 0x04, 0xff, 0x3f, 0x04, 0xff, 0x3f, 0x04, 0xff, 0x3f, 0x04, 0xff, 0x3f, 0x04, 0xff, 0x3f, 0x04, 0xff, 0x3f, 0x04, 0xa4, 0x9f, 0x04, 0x0e, 0x00, 0x00, 0x00, 0xdf, 0x04, 0x05, 0x3f, 0x04, 0x52, 0x5f, 0x04, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x04, 0x31, 0x3f, 0x04, 0xc5, 0x3f, 0x04, 0x8a, 0xff, 0x07, 0x01, 0x9f, 0x04, 0x0e, 0x3f, 0x04, 0xb2, 0x3f, 0x04, 0xff, 0x3f, 0x04, 0xff, 0x3f, 0x04, 0xb9, 0x3f, 0x04, 0x72, 0x3f, 0x04, 0x7f, 0x3f, 0x04, 0xcf, 0x3f, 0x04, 0xff, 0x3f, 0x04, 0xff, 0x3f, 0x04, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x04, 0x5d, 0x3f, 0x04, 0xb9, 0x3f, 0x04, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x04, 0x3c, 0x3f, 0x04, 0xda, 0x3f, 0x04, 0xc5, 0x3f, 0x04, 0x17, 0x00, 0x00, 0x00, 0x3f, 0x04, 0x66, 0x3f, 0x04, 0xf7, 0x3f, 0x04, 0xff, 0x3f, 0x04, 0x97, 0x9f, 0x04, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x04, 0x20, 0x3f, 0x04, 0xc5, 0x3f, 0x04, 0xff, 0x3f, 0x04, 0xe1, 0x3f, 0x04, 0x2a, 0x00, 0x00, 0x00, 0x9f, 0x04, 0x0e, 0x3f, 0x04, 0xb9, 0x3f, 0x04, 0xda, 0x3f, 0x04, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x04, 0x31, 0x3f, 0x04, 0xda, 0x3f, 0x04, 0xf1, 0x3f, 0x04, 0x46, 0x00, 0x00, 0x00, 0x3f, 0x04, 0x2a, 0x3f, 0x04, 0xda, 0x3f, 0x04, 0xff, 0x3f, 0x04, 0xda, 0x5f, 0x04, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x04, 0x52, 0x3f, 0x04, 0xf7, 0x3f, 0x04, 0xff, 0x3f, 0x04, 0x97, 0xff, 0x07, 0x01, 0x00, 0x00, 0x00, 0x3f, 0x04, 0x46, 0x3f, 0x04, 0xf7, 0x3f, 0x04, 0xcf, 0x5f, 0x04, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x07, 0x01, 0x9f, 0x04, 0x0e, 0x3f, 0x04, 0xb9, 0x3f, 0x04, 0xff, 0x3f, 0x04, 0x8a, 0xff, 0x07, 0x01, 0xdf, 0x04, 0x05, 0x3f, 0x04, 0x97, 0x3f, 0x04, 0xff, 0x3f, 0x04, 0xf7, 0x3f, 0x04, 0x5d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdf, 0x04, 0x05, 0x3f, 0x04, 0xa4, 0x3f, 0x04, 0xff, 0x3f, 0x04, 0xeb, 0x3f, 0x04, 0x3c, 0x00, 0x00, 0x00, 0xdf, 0x04, 0x05, 0x3f, 0x04, 0xa4, 0x3f, 0x04, 0xff, 0x3f, 0x04, 0xa4, 0xdf, 0x04, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x04, 0x72, 0x3f, 0x04, 0xff, 0x3f, 0x04, 0xc5, 0x3f, 0x04, 0x17, 0x00, 0x00, 0x00, 0x3f, 0x04, 0x52, 0x3f, 0x04, 0xf7, 0x3f, 0x04, 0xff, 0x3f, 0x04, 0xa4, 0xdf, 0x04, 0x05, 0x00, 0x00, 0x00, 0xdf, 0x04, 0x05, 0x3f, 0x04, 0x2a, 0x5f, 0x04, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x04, 0x3c, 0x3f, 0x04, 0xeb, 0x3f, 0x04, 0xff, 0x3f, 0x04, 0xb2, 0xdf, 0x04, 0x05, 0x00, 0x00, 0x00, 0x3f, 0x04, 0x31, 0x3f, 0x04, 0xeb, 0x3f, 0x04, 0xf7, 0x3f, 0x04, 0x52, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x04, 0x20, 0x3f, 0x04, 0xda, 0x3f, 0x04, 0xf1, 0x3f, 0x04, 0x46, 0x00, 0x00, 0x00, 0x3f, 0x04, 0x17, 0x3f, 0x04, 0xc5, 0x3f, 0x04, 0xff, 0x3f, 0x04, 0xe1, 0x3f, 0x04, 0x31, 0x00, 0x00, 0x00, 0x9f, 0x04, 0x0e, 0x3f, 0x04, 0x97, 0x3f, 0x04, 0xeb, 0x3f, 0x04, 0xda, 0x3f, 0x04, 0x52, 0x00, 0x00, 0x00, 0xff, 0x07, 0x01, 0x3f, 0x04, 0x97, 0x3f, 0x04, 0xff, 0x3f, 0x04, 0xf7, 0x3f, 0x04, 0x52, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x04, 0x8a, 0x3f, 0x04, 0xff, 0x3f, 0x04, 0xb9, 0x9f, 0x04, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x04, 0x66, 0x3f, 0x04, 0xff, 0x3f, 0x04, 0x8a, 0xff, 0x07, 0x01, 0x00, 0x00, 0x00, 0x3f, 0x04, 0x7f, 0x3f, 0x04, 0xff, 0x3f, 0x04, 0xff, 0x3f, 0x04, 0x72, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x04, 0x66, 0x3f, 0x04, 0xff, 0x3f, 0x04, 0xff, 0x3f, 0x04, 0xff, 0x3f, 0x04, 0xcf, 0x3f, 0x04, 0x17, 0x00, 0x00, 0x00, 0x3f, 0x04, 0x2a, 0x3f, 0x04, 0xe1, 0x3f, 0x04, 0xff, 0x3f, 0x04, 0xc5, 0x9f, 0x04, 0x0e, 0x00, 0x00, 0x00, 0x5f, 0x04, 0x20, 0x3f, 0x04, 0xda, 0x3f, 0x04, 0xf7, 0x3f, 0x04, 0x46, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xdf, 0x04, 0x05, 0x3f, 0x04, 0xb2, 0x3f, 0x04, 0xc5, 0x3f, 0x04, 0x17, 0x00, 0x00, 0x00, 0x3f, 0x04, 0x3c, 0x3f, 0x04, 0xeb, 0x3f, 0x04, 0xff, 0x3f, 0x04, 0xb9, 0x9f, 0x04, 0x0e, 0x00, 0x00, 0x00, 0x5f, 0x04, 0x20, 0x3f, 0x04, 0xda, 0x3f, 0x04, 0xff, 0x3f, 0x04, 0xff, 0x3f, 0x04, 0xff, 0x3f, 0x04, 0xff, 0x3f, 0x04, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x04, 0x7f, 0x3f, 0x04, 0xff, 0x3f, 0x04, 0xff, 0x3f, 0x04, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x04, 0x72, 0x3f, 0x04, 0xff, 0x3f, 0x04, 0x8a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x5f, 0x04, 0x20, 0x3f, 0x04, 0xcf, 0x3f, 0x04, 0x46, 0x00, 0x00, 0x00, 0x9f, 0x04, 0x0e, 0x3f, 0x04, 0xb9, 0x3f, 0x04, 0xff, 0x3f, 0x04, 0xf1, 0x3f, 0x04, 0x46, 0x00, 0x00, 0x00, 0xff, 0x07, 0x01, 0x3f, 0x04, 0x97, 0x3f, 0x04, 0xff, 0x3f, 0x04, 0xf7, 0x3f, 0x04, 0x7f, 0x3f, 0x04, 0xc5, 0x3f, 0x04, 0xff, 0x3f, 0x04, 0xe1, 0x3f, 0x04, 0x2a, 0x00, 0x00, 0x00, 0x5f, 0x04, 0x20, 0x3f, 0x04, 0xcf, 0x3f, 0x04, 0xff, 0x3f, 0x04, 0xcf, 0x5f, 0x04, 0x20, 0x00, 0x00, 0x00, 0x3f, 0x04, 0x17, 0x3f, 0x04, 0xcf, 0x3f, 0x04, 0xc5, 0x9f, 0x04, 0x0e, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x3f, 0x04, 0x3c, 0x3f, 0x04, 0x72, 0xff, 0x07, 0x01, 0x00, 0x00, 0x00, 0x3f, 0x04, 0x72, 0x3f, 0x04, 0xff, 0x3f, 0x04, 0xff, 0x3f, 0x04, 0x8a, 0xff, 0x07, 0x01, 0x00, 0x00, 0x00, 0x3f, 0x04, 0x46, 0x3f, 0x04, 0xf1, 0x3f, 0x04, 0xff, 0x3f, 0x04, 0xb2, 0xdf, 0x04, 0x05, 0x3f, 0x04, 0x52, 0x3f, 0x04, 0xf7, 0x3f, 0x04, 0xff, 0x3f, 0x04, 0x8a, 0xff, 0x07, 0x01, 0x00, 0x00, 0x00, 0x3f, 0x04, 0x66, 0x3f, 0x04, 0xff, 0x3f, 0x04, 0xff, 0x3f, 0x04, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x04, 0x5d, 0x3f, 0x04, 0xda, 0x5f, 0x04, 0x20, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x9f, 0x04, 0x0e, 0x9f, 0x04, 0x0e, 0x00, 0x00, 0x00, 0x3f, 0x04, 0x2a, 0x3f, 0x04, 0xe1, 0x3f, 0x04, 0xff, 0x3f, 0x04, 0xcf, 0x5f, 0x04, 0x20, 0x00, 0x00, 0x00, 0x3f, 0x04, 0x17, 0x3f, 0x04, 0xc5, 0x3f, 0x04, 0xff, 0x3f, 0x04, 0xeb, 0x3f, 0x04, 0x3c, 0x00, 0x00, 0x00, 0xdf, 0x04, 0x05, 0x3f, 0x04, 0xb2, 0x3f, 0x04, 0xff, 0x3f, 0x04, 0xeb, 0x3f, 0x04, 0x3c, 0x00, 0x00, 0x00, 0x9f, 0x04, 0x0e, 0x3f, 0x04, 0xc5, 0x3f, 0x04, 0xff, 0x3f, 0x04, 0xe1, 0x3f, 0x04, 0x2a, 0x00, 0x00, 0x00, 0x9f, 0x04, 0x0e, 0x3f, 0x04, 0xa4, 0x3f, 0x04, 0x31, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdf, 0x04, 0x05, 0x3f, 0x04, 0xa4, 0x3f, 0x04, 0xff, 0x3f, 0x04, 0xf7, 0x3f, 0x04, 0x52, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x04, 0x72, 0x3f, 0x04, 0xff, 0x3f, 0x04, 0xff, 0x3f, 0x04, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x04, 0x3c, 0x3f, 0x04, 0xeb, 0x3f, 0x04, 0xff, 0x3f, 0x04, 0xa4, 0xdf, 0x04, 0x05, 0x00, 0x00, 0x00, 0x3f, 0x04, 0x52, 0x3f, 0x04, 0xf7, 0x3f, 0x04, 0xff, 0x3f, 0x04, 0x97, 0xff, 0x07, 0x01, 0x00, 0x00, 0x00, 0x3f, 0x04, 0x31, 0x5f, 0x04, 0x20, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x04, 0x5d, 0x3f, 0x04, 0xf7, 0x3f, 0x04, 0xff, 0x3f, 0x04, 0xa4, 0xdf, 0x04, 0x05, 0x00, 0x00, 0x00, 0x3f, 0x04, 0x31, 0x3f, 0x04, 0xe1, 0x3f, 0x04, 0xff, 0x3f, 0x04, 0xc5, 0x3f, 0x04, 0x17, 0xdf, 0x04, 0x05, 0x3f, 0x04, 0x31, 0x3f, 0x04, 0x3c, 0x3f, 0x04, 0x3c, 0x3f, 0x04, 0xcf, 0x3f, 0x04, 0xff, 0x3f, 0x04, 0xf1, 0x3f, 0x04, 0x46, 0x00, 0x00, 0x00, 0xdf, 0x04, 0x05, 0x3f, 0x04, 0xa4, 0x3f, 0x04, 0xff, 0x3f, 0x04, 0xeb, 0x3f, 0x04, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x07, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x04, 0x17, 0x3f, 0x04, 0xcf, 0x3f, 0x04, 0xff, 0x3f, 0x04, 0xda, 0x3f, 0x04, 0x2a, 0x00, 0x00, 0x00, 0xdf, 0x04, 0x05, 0x3f, 0x04, 0xa4, 0x3f, 0x04, 0xff, 0x3f, 0x04, 0xf7, 0x3f, 0x04, 0x52, 0x00, 0x00, 0x00, 0x3f, 0x04, 0x72, 0x3f, 0x04, 0xf1, 0x3f, 0x04, 0xf1, 0x3f, 0x04, 0xf1, 0x3f, 0x04, 0xff, 0x3f, 0x04, 0xff, 0x3f, 0x04, 0xff, 0x3f, 0x04, 0xb9, 0x9f, 0x04, 0x0e, 0x00, 0x00, 0x00, 0x3f, 0x04, 0x3c, 0x3f, 0x04, 0xeb, 0x3f, 0x04, 0xff, 0x3f, 0x04, 0xa4, 0xdf, 0x04, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x04, 0x3c, 0x3f, 0x04, 0xf7, 0x3f, 0x04, 0xff, 0x3f, 0x04, 0x72, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x04, 0x52, 0x3f, 0x04, 0xf7, 0x3f, 0x04, 0xff, 0x3f, 0x04, 0xa4, 0xdf, 0x04, 0x05, 0x00, 0x00, 0x00, 0x3f, 0x04, 0x8a, 0x3f, 0x04, 0xff, 0x3f, 0x04, 0xff, 0x3f, 0x04, 0xff, 0x3f, 0x04, 0xff, 0x3f, 0x04, 0xff, 0x3f, 0x04, 0xff, 0x3f, 0x04, 0xf7, 0x3f, 0x04, 0x5d, 0x00, 0x00, 0x00, 0xff, 0x07, 0x01, 0x3f, 0x04, 0xa4, 0x3f, 0x04, 0xff, 0x3f, 0x04, 0xe1, 0x5f, 0x04, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x04, 0x2a, 0x3f, 0x04, 0xeb, 0x3f, 0x04, 0xcf, 0x3f, 0x04, 0x17, 0x00, 0x00, 0x00, 0xdf, 0x04, 0x05, 0x3f, 0x04, 0xb2, 0x3f, 0x04, 0xff, 0x3f, 0x04, 0xe1, 0x3f, 0x04, 0x2a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x04, 0x17, 0x3f, 0x04, 0x52, 0x3f, 0x04, 0x5d, 0x3f, 0x04, 0x5d, 0x3f, 0x04, 0x5d, 0x3f, 0x04, 0x72, 0x3f, 0x04, 0xe1, 0x3f, 0x04, 0xff, 0x3f, 0x04, 0xc5, 0x9f, 0x04, 0x0e, 0x00, 0x00, 0x00, 0x3f, 0x04, 0x66, 0x3f, 0x04, 0xff, 0x3f, 0x04, 0xf1, 0x3f, 0x04, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdf, 0x04, 0x05, 0x3f, 0x04, 0xb9, 0x3f, 0x04, 0x97, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x04, 0x17, 0x3f, 0x04, 0xda, 0x3f, 0x04, 0xff, 0x3f, 0x04, 0x97, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x04, 0x66, 0x3f, 0x04, 0xf1, 0x3f, 0x04, 0xa4, 0xdf, 0x04, 0x05, 0x00, 0x00, 0x00, 0x3f, 0x04, 0x72, 0x3f, 0x04, 0xff, 0x3f, 0x04, 0xf1, 0x3f, 0x04, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x04, 0x5d, 0x3f, 0x04, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x04, 0x17, 0x3f, 0x04, 0xda, 0x3f, 0x04, 0xff, 0x3f, 0x04, 0x97, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdf, 0x04, 0x05, 0x3f, 0x04, 0x2a, 0x3f, 0x04, 0x17, 0x00, 0x00, 0x00, 0x9f, 0x04, 0x0e, 0x3f, 0x04, 0xb9, 0x3f, 0x04, 0xff, 0x3f, 0x04, 0xcf, 0x3f, 0x04, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9f, 0x04, 0x0e, 0x3f, 0x04, 0x46, 0xff, 0x07, 0x01, 0x00, 0x00, 0x00, 0xdf, 0x04, 0x05, 0x3f, 0x04, 0xb2, 0x3f, 0x04, 0xff, 0x3f, 0x04, 0xe1, 0x3f, 0x04, 0x46, 0xdf, 0x04, 0x05, 0xdf, 0x04, 0x05, 0xdf, 0x04, 0x05, 0xdf, 0x04, 0x05, 0xdf, 0x04, 0x05, 0xdf, 0x04, 0x05, 0xdf, 0x04, 0x05, 0xdf, 0x04, 0x05, 0xdf, 0x04, 0x05, 0xff, 0x07, 0x01, 0xdf, 0x04, 0x05, 0x5f, 0x04, 0x20, 0x3f, 0x04, 0x97, 0x3f, 0x04, 0xff, 0x3f, 0x04, 0xff, 0x3f, 0x04, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x07, 0x01, 0xdf, 0x04, 0x05, 0xff, 0x07, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x04, 0x52, 0x3f, 0x04, 0xf7, 0x3f, 0x04, 0xff, 0x3f, 0x04, 0xeb, 0x3f, 0x04, 0xb9, 0x3f, 0x04, 0xb2, 0x3f, 0x04, 0xb2, 0x3f, 0x04, 0xb2, 0x3f, 0x04, 0xb2, 0x3f, 0x04, 0xb2, 0x3f, 0x04, 0xb2, 0x3f, 0x04, 0xb2, 0x3f, 0x04, 0xb2, 0x3f, 0x04, 0xb2, 0x3f, 0x04, 0xb9, 0x3f, 0x04, 0xda, 0x3f, 0x04, 0xff, 0x3f, 0x04, 0xff, 0x3f, 0x04, 0xc5, 0x5f, 0x04, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdf, 0x04, 0x05, 0x3f, 0x04, 0x72, 0x3f, 0x04, 0xf1, 0x3f, 0x04, 0xff, 0x3f, 0x04, 0xff, 0x3f, 0x04, 0xff, 0x3f, 0x04, 0xff, 0x3f, 0x04, 0xff, 0x3f, 0x04, 0xff, 0x3f, 0x04, 0xff, 0x3f, 0x04, 0xff, 0x3f, 0x04, 0xff, 0x3f, 0x04, 0xff, 0x3f, 0x04, 0xff, 0x3f, 0x04, 0xff, 0x3f, 0x04, 0xff, 0x3f, 0x04, 0xff, 0x3f, 0x04, 0xb2, 0x3f, 0x04, 0x2a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdf, 0x04, 0x05, 0x3f, 0x04, 0x3c, 0x3f, 0x04, 0x97, 0x3f, 0x04, 0xb9, 0x3f, 0x04, 0xb9, 0x3f, 0x04, 0xb9, 0x3f, 0x04, 0xb9, 0x3f, 0x04, 0xb9, 0x3f, 0x04, 0xb9, 0x3f, 0x04, 0xb9, 0x3f, 0x04, 0xb9, 0x3f, 0x04, 0xb9, 0x3f, 0x04, 0xb9, 0x3f, 0x04, 0xb9, 0x3f, 0x04, 0x97, 0x3f, 0x04, 0x5d, 0x9f, 0x04, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x07, 0x01, 0xdf, 0x04, 0x05, 0xdf, 0x04, 0x05, 0xdf, 0x04, 0x05, 0xdf, 0x04, 0x05, 0xdf, 0x04, 0x05, 0xdf, 0x04, 0x05, 0xdf, 0x04, 0x05, 0xdf, 0x04, 0x05, 0xdf, 0x04, 0x05, 0xff, 0x07, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x07, 0x01, 0x3f, 0x04, 0x2a, 0x3f, 0x04, 0x31, 0x3f, 0x04, 0x31, 0x3f, 0x04, 0x31, 0x3f, 0x04, 0x31, 0x3f, 0x04, 0x31, 0x3f, 0x04, 0x31, 0x3f, 0x04, 0x31, 0x3f, 0x04, 0x31, 0x3f, 0x04, 0x31, 0x3f, 0x04, 0x31, 0x3f, 0x04, 0x31, 0x3f, 0x04, 0x31, 0x3f, 0x04, 0x31, 0x9f, 0x04, 0x0e, 0x00, 0x00, 0x00, 0xff, 0x07, 0x01, 0x3f, 0x04, 0x17, 0x5f, 0x04, 0x20, 0x3f, 0x04, 0x17, 0xdf, 0x04, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x07, 0x01, 0x3f, 0x04, 0x46, 0x3f, 0x04, 0xb9, 0x3f, 0x04, 0xeb, 0x3f, 0x04, 0xf1, 0x3f, 0x04, 0xf1, 0x3f, 0x04, 0xf1, 0x3f, 0x04, 0xf1, 0x3f, 0x04, 0xf1, 0x3f, 0x04, 0xf1, 0x3f, 0x04, 0xf1, 0x3f, 0x04, 0xf1, 0x3f, 0x04, 0xeb, 0x3f, 0x04, 0xcf, 0x3f, 0x04, 0x72, 0x9f, 0x04, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x04, 0x46, 0x3f, 0x04, 0x72, 0x3f, 0x04, 0x72, 0x3f, 0x04, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x07, 0x01, 0xff, 0x07, 0x01, 0x9f, 0x04, 0x0e, 0x3f, 0x04, 0x52, 0x3f, 0x04, 0x97, 0x3f, 0x04, 0xc5, 0x3f, 0x04, 0xe1, 0x3f, 0x04, 0xeb, 0x3f, 0x04, 0xeb, 0x3f, 0x04, 0xe1, 0x3f, 0x04, 0xcf, 0x3f, 0x04, 0xa4, 0x3f, 0x04, 0x66, 0x5f, 0x04, 0x20, 0xff, 0x07, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9f, 0x04, 0x0e, 0x5f, 0x04, 0x20, 0x5f, 0x04, 0x20, 0xdf, 0x04, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9f, 0x04, 0x0e, 0x5f, 0x04, 0x20, 0x3f, 0x04, 0x2a, 0x3f, 0x04, 0x2a, 0x5f, 0x04, 0x20, 0x9f, 0x04, 0x0e, 0xff, 0x07, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x07, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x07, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +#endif +#if LV_COLOR_DEPTH == 16 && LV_COLOR_16_SWAP != 0 + /*Pixel format: Alpha 8 bit, Red: 5 bit, Green: 6 bit, Blue: 5 bit BUT the 2 color bytes are swapped*/ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x3f, 0x17, 0x04, 0x3f, 0x2a, 0x04, 0x3f, 0x2a, 0x04, 0x9f, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0x01, 0x04, 0xdf, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x5f, 0x20, 0x04, 0x3f, 0x8a, 0x04, 0x3f, 0xcf, 0x04, 0x3f, 0xeb, 0x04, 0x3f, 0xeb, 0x04, 0x3f, 0xc5, 0x04, 0x3f, 0x72, 0x04, 0x9f, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x3f, 0x17, 0x04, 0x3f, 0x72, 0x04, 0x3f, 0x2a, 0x00, 0x00, 0x00, 0x04, 0x3f, 0x2a, 0x04, 0x3f, 0xc5, 0x04, 0x3f, 0xff, 0x04, 0x3f, 0xff, 0x04, 0x3f, 0xff, 0x04, 0x3f, 0xff, 0x04, 0x3f, 0xff, 0x04, 0x3f, 0xff, 0x04, 0x3f, 0xa4, 0x04, 0x9f, 0x0e, 0x00, 0x00, 0x00, 0x04, 0xdf, 0x05, 0x04, 0x3f, 0x52, 0x04, 0x5f, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x3f, 0x31, 0x04, 0x3f, 0xc5, 0x04, 0x3f, 0x8a, 0x07, 0xff, 0x01, 0x04, 0x9f, 0x0e, 0x04, 0x3f, 0xb2, 0x04, 0x3f, 0xff, 0x04, 0x3f, 0xff, 0x04, 0x3f, 0xb9, 0x04, 0x3f, 0x72, 0x04, 0x3f, 0x7f, 0x04, 0x3f, 0xcf, 0x04, 0x3f, 0xff, 0x04, 0x3f, 0xff, 0x04, 0x3f, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x3f, 0x5d, 0x04, 0x3f, 0xb9, 0x04, 0x3f, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x3f, 0x3c, 0x04, 0x3f, 0xda, 0x04, 0x3f, 0xc5, 0x04, 0x3f, 0x17, 0x00, 0x00, 0x00, 0x04, 0x3f, 0x66, 0x04, 0x3f, 0xf7, 0x04, 0x3f, 0xff, 0x04, 0x3f, 0x97, 0x04, 0x9f, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x5f, 0x20, 0x04, 0x3f, 0xc5, 0x04, 0x3f, 0xff, 0x04, 0x3f, 0xe1, 0x04, 0x3f, 0x2a, 0x00, 0x00, 0x00, 0x04, 0x9f, 0x0e, 0x04, 0x3f, 0xb9, 0x04, 0x3f, 0xda, 0x04, 0x3f, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x3f, 0x31, 0x04, 0x3f, 0xda, 0x04, 0x3f, 0xf1, 0x04, 0x3f, 0x46, 0x00, 0x00, 0x00, 0x04, 0x3f, 0x2a, 0x04, 0x3f, 0xda, 0x04, 0x3f, 0xff, 0x04, 0x3f, 0xda, 0x04, 0x5f, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x3f, 0x52, 0x04, 0x3f, 0xf7, 0x04, 0x3f, 0xff, 0x04, 0x3f, 0x97, 0x07, 0xff, 0x01, 0x00, 0x00, 0x00, 0x04, 0x3f, 0x46, 0x04, 0x3f, 0xf7, 0x04, 0x3f, 0xcf, 0x04, 0x5f, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0x01, 0x04, 0x9f, 0x0e, 0x04, 0x3f, 0xb9, 0x04, 0x3f, 0xff, 0x04, 0x3f, 0x8a, 0x07, 0xff, 0x01, 0x04, 0xdf, 0x05, 0x04, 0x3f, 0x97, 0x04, 0x3f, 0xff, 0x04, 0x3f, 0xf7, 0x04, 0x3f, 0x5d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xdf, 0x05, 0x04, 0x3f, 0xa4, 0x04, 0x3f, 0xff, 0x04, 0x3f, 0xeb, 0x04, 0x3f, 0x3c, 0x00, 0x00, 0x00, 0x04, 0xdf, 0x05, 0x04, 0x3f, 0xa4, 0x04, 0x3f, 0xff, 0x04, 0x3f, 0xa4, 0x04, 0xdf, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x3f, 0x72, 0x04, 0x3f, 0xff, 0x04, 0x3f, 0xc5, 0x04, 0x3f, 0x17, 0x00, 0x00, 0x00, 0x04, 0x3f, 0x52, 0x04, 0x3f, 0xf7, 0x04, 0x3f, 0xff, 0x04, 0x3f, 0xa4, 0x04, 0xdf, 0x05, 0x00, 0x00, 0x00, 0x04, 0xdf, 0x05, 0x04, 0x3f, 0x2a, 0x04, 0x5f, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x3f, 0x3c, 0x04, 0x3f, 0xeb, 0x04, 0x3f, 0xff, 0x04, 0x3f, 0xb2, 0x04, 0xdf, 0x05, 0x00, 0x00, 0x00, 0x04, 0x3f, 0x31, 0x04, 0x3f, 0xeb, 0x04, 0x3f, 0xf7, 0x04, 0x3f, 0x52, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x5f, 0x20, 0x04, 0x3f, 0xda, 0x04, 0x3f, 0xf1, 0x04, 0x3f, 0x46, 0x00, 0x00, 0x00, 0x04, 0x3f, 0x17, 0x04, 0x3f, 0xc5, 0x04, 0x3f, 0xff, 0x04, 0x3f, 0xe1, 0x04, 0x3f, 0x31, 0x00, 0x00, 0x00, 0x04, 0x9f, 0x0e, 0x04, 0x3f, 0x97, 0x04, 0x3f, 0xeb, 0x04, 0x3f, 0xda, 0x04, 0x3f, 0x52, 0x00, 0x00, 0x00, 0x07, 0xff, 0x01, 0x04, 0x3f, 0x97, 0x04, 0x3f, 0xff, 0x04, 0x3f, 0xf7, 0x04, 0x3f, 0x52, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x3f, 0x8a, 0x04, 0x3f, 0xff, 0x04, 0x3f, 0xb9, 0x04, 0x9f, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x3f, 0x66, 0x04, 0x3f, 0xff, 0x04, 0x3f, 0x8a, 0x07, 0xff, 0x01, 0x00, 0x00, 0x00, 0x04, 0x3f, 0x7f, 0x04, 0x3f, 0xff, 0x04, 0x3f, 0xff, 0x04, 0x3f, 0x72, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x3f, 0x66, 0x04, 0x3f, 0xff, 0x04, 0x3f, 0xff, 0x04, 0x3f, 0xff, 0x04, 0x3f, 0xcf, 0x04, 0x3f, 0x17, 0x00, 0x00, 0x00, 0x04, 0x3f, 0x2a, 0x04, 0x3f, 0xe1, 0x04, 0x3f, 0xff, 0x04, 0x3f, 0xc5, 0x04, 0x9f, 0x0e, 0x00, 0x00, 0x00, 0x04, 0x5f, 0x20, 0x04, 0x3f, 0xda, 0x04, 0x3f, 0xf7, 0x04, 0x3f, 0x46, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x04, 0xdf, 0x05, 0x04, 0x3f, 0xb2, 0x04, 0x3f, 0xc5, 0x04, 0x3f, 0x17, 0x00, 0x00, 0x00, 0x04, 0x3f, 0x3c, 0x04, 0x3f, 0xeb, 0x04, 0x3f, 0xff, 0x04, 0x3f, 0xb9, 0x04, 0x9f, 0x0e, 0x00, 0x00, 0x00, 0x04, 0x5f, 0x20, 0x04, 0x3f, 0xda, 0x04, 0x3f, 0xff, 0x04, 0x3f, 0xff, 0x04, 0x3f, 0xff, 0x04, 0x3f, 0xff, 0x04, 0x3f, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x3f, 0x7f, 0x04, 0x3f, 0xff, 0x04, 0x3f, 0xff, 0x04, 0x3f, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x3f, 0x72, 0x04, 0x3f, 0xff, 0x04, 0x3f, 0x8a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x04, 0x5f, 0x20, 0x04, 0x3f, 0xcf, 0x04, 0x3f, 0x46, 0x00, 0x00, 0x00, 0x04, 0x9f, 0x0e, 0x04, 0x3f, 0xb9, 0x04, 0x3f, 0xff, 0x04, 0x3f, 0xf1, 0x04, 0x3f, 0x46, 0x00, 0x00, 0x00, 0x07, 0xff, 0x01, 0x04, 0x3f, 0x97, 0x04, 0x3f, 0xff, 0x04, 0x3f, 0xf7, 0x04, 0x3f, 0x7f, 0x04, 0x3f, 0xc5, 0x04, 0x3f, 0xff, 0x04, 0x3f, 0xe1, 0x04, 0x3f, 0x2a, 0x00, 0x00, 0x00, 0x04, 0x5f, 0x20, 0x04, 0x3f, 0xcf, 0x04, 0x3f, 0xff, 0x04, 0x3f, 0xcf, 0x04, 0x5f, 0x20, 0x00, 0x00, 0x00, 0x04, 0x3f, 0x17, 0x04, 0x3f, 0xcf, 0x04, 0x3f, 0xc5, 0x04, 0x9f, 0x0e, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x04, 0x3f, 0x3c, 0x04, 0x3f, 0x72, 0x07, 0xff, 0x01, 0x00, 0x00, 0x00, 0x04, 0x3f, 0x72, 0x04, 0x3f, 0xff, 0x04, 0x3f, 0xff, 0x04, 0x3f, 0x8a, 0x07, 0xff, 0x01, 0x00, 0x00, 0x00, 0x04, 0x3f, 0x46, 0x04, 0x3f, 0xf1, 0x04, 0x3f, 0xff, 0x04, 0x3f, 0xb2, 0x04, 0xdf, 0x05, 0x04, 0x3f, 0x52, 0x04, 0x3f, 0xf7, 0x04, 0x3f, 0xff, 0x04, 0x3f, 0x8a, 0x07, 0xff, 0x01, 0x00, 0x00, 0x00, 0x04, 0x3f, 0x66, 0x04, 0x3f, 0xff, 0x04, 0x3f, 0xff, 0x04, 0x3f, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x3f, 0x5d, 0x04, 0x3f, 0xda, 0x04, 0x5f, 0x20, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x04, 0x9f, 0x0e, 0x04, 0x9f, 0x0e, 0x00, 0x00, 0x00, 0x04, 0x3f, 0x2a, 0x04, 0x3f, 0xe1, 0x04, 0x3f, 0xff, 0x04, 0x3f, 0xcf, 0x04, 0x5f, 0x20, 0x00, 0x00, 0x00, 0x04, 0x3f, 0x17, 0x04, 0x3f, 0xc5, 0x04, 0x3f, 0xff, 0x04, 0x3f, 0xeb, 0x04, 0x3f, 0x3c, 0x00, 0x00, 0x00, 0x04, 0xdf, 0x05, 0x04, 0x3f, 0xb2, 0x04, 0x3f, 0xff, 0x04, 0x3f, 0xeb, 0x04, 0x3f, 0x3c, 0x00, 0x00, 0x00, 0x04, 0x9f, 0x0e, 0x04, 0x3f, 0xc5, 0x04, 0x3f, 0xff, 0x04, 0x3f, 0xe1, 0x04, 0x3f, 0x2a, 0x00, 0x00, 0x00, 0x04, 0x9f, 0x0e, 0x04, 0x3f, 0xa4, 0x04, 0x3f, 0x31, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xdf, 0x05, 0x04, 0x3f, 0xa4, 0x04, 0x3f, 0xff, 0x04, 0x3f, 0xf7, 0x04, 0x3f, 0x52, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x3f, 0x72, 0x04, 0x3f, 0xff, 0x04, 0x3f, 0xff, 0x04, 0x3f, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x3f, 0x3c, 0x04, 0x3f, 0xeb, 0x04, 0x3f, 0xff, 0x04, 0x3f, 0xa4, 0x04, 0xdf, 0x05, 0x00, 0x00, 0x00, 0x04, 0x3f, 0x52, 0x04, 0x3f, 0xf7, 0x04, 0x3f, 0xff, 0x04, 0x3f, 0x97, 0x07, 0xff, 0x01, 0x00, 0x00, 0x00, 0x04, 0x3f, 0x31, 0x04, 0x5f, 0x20, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x3f, 0x5d, 0x04, 0x3f, 0xf7, 0x04, 0x3f, 0xff, 0x04, 0x3f, 0xa4, 0x04, 0xdf, 0x05, 0x00, 0x00, 0x00, 0x04, 0x3f, 0x31, 0x04, 0x3f, 0xe1, 0x04, 0x3f, 0xff, 0x04, 0x3f, 0xc5, 0x04, 0x3f, 0x17, 0x04, 0xdf, 0x05, 0x04, 0x3f, 0x31, 0x04, 0x3f, 0x3c, 0x04, 0x3f, 0x3c, 0x04, 0x3f, 0xcf, 0x04, 0x3f, 0xff, 0x04, 0x3f, 0xf1, 0x04, 0x3f, 0x46, 0x00, 0x00, 0x00, 0x04, 0xdf, 0x05, 0x04, 0x3f, 0xa4, 0x04, 0x3f, 0xff, 0x04, 0x3f, 0xeb, 0x04, 0x3f, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x3f, 0x17, 0x04, 0x3f, 0xcf, 0x04, 0x3f, 0xff, 0x04, 0x3f, 0xda, 0x04, 0x3f, 0x2a, 0x00, 0x00, 0x00, 0x04, 0xdf, 0x05, 0x04, 0x3f, 0xa4, 0x04, 0x3f, 0xff, 0x04, 0x3f, 0xf7, 0x04, 0x3f, 0x52, 0x00, 0x00, 0x00, 0x04, 0x3f, 0x72, 0x04, 0x3f, 0xf1, 0x04, 0x3f, 0xf1, 0x04, 0x3f, 0xf1, 0x04, 0x3f, 0xff, 0x04, 0x3f, 0xff, 0x04, 0x3f, 0xff, 0x04, 0x3f, 0xb9, 0x04, 0x9f, 0x0e, 0x00, 0x00, 0x00, 0x04, 0x3f, 0x3c, 0x04, 0x3f, 0xeb, 0x04, 0x3f, 0xff, 0x04, 0x3f, 0xa4, 0x04, 0xdf, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x3f, 0x3c, 0x04, 0x3f, 0xf7, 0x04, 0x3f, 0xff, 0x04, 0x3f, 0x72, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x3f, 0x52, 0x04, 0x3f, 0xf7, 0x04, 0x3f, 0xff, 0x04, 0x3f, 0xa4, 0x04, 0xdf, 0x05, 0x00, 0x00, 0x00, 0x04, 0x3f, 0x8a, 0x04, 0x3f, 0xff, 0x04, 0x3f, 0xff, 0x04, 0x3f, 0xff, 0x04, 0x3f, 0xff, 0x04, 0x3f, 0xff, 0x04, 0x3f, 0xff, 0x04, 0x3f, 0xf7, 0x04, 0x3f, 0x5d, 0x00, 0x00, 0x00, 0x07, 0xff, 0x01, 0x04, 0x3f, 0xa4, 0x04, 0x3f, 0xff, 0x04, 0x3f, 0xe1, 0x04, 0x5f, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x3f, 0x2a, 0x04, 0x3f, 0xeb, 0x04, 0x3f, 0xcf, 0x04, 0x3f, 0x17, 0x00, 0x00, 0x00, 0x04, 0xdf, 0x05, 0x04, 0x3f, 0xb2, 0x04, 0x3f, 0xff, 0x04, 0x3f, 0xe1, 0x04, 0x3f, 0x2a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x3f, 0x17, 0x04, 0x3f, 0x52, 0x04, 0x3f, 0x5d, 0x04, 0x3f, 0x5d, 0x04, 0x3f, 0x5d, 0x04, 0x3f, 0x72, 0x04, 0x3f, 0xe1, 0x04, 0x3f, 0xff, 0x04, 0x3f, 0xc5, 0x04, 0x9f, 0x0e, 0x00, 0x00, 0x00, 0x04, 0x3f, 0x66, 0x04, 0x3f, 0xff, 0x04, 0x3f, 0xf1, 0x04, 0x3f, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xdf, 0x05, 0x04, 0x3f, 0xb9, 0x04, 0x3f, 0x97, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x3f, 0x17, 0x04, 0x3f, 0xda, 0x04, 0x3f, 0xff, 0x04, 0x3f, 0x97, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x3f, 0x66, 0x04, 0x3f, 0xf1, 0x04, 0x3f, 0xa4, 0x04, 0xdf, 0x05, 0x00, 0x00, 0x00, 0x04, 0x3f, 0x72, 0x04, 0x3f, 0xff, 0x04, 0x3f, 0xf1, 0x04, 0x3f, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x3f, 0x5d, 0x04, 0x3f, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x3f, 0x17, 0x04, 0x3f, 0xda, 0x04, 0x3f, 0xff, 0x04, 0x3f, 0x97, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xdf, 0x05, 0x04, 0x3f, 0x2a, 0x04, 0x3f, 0x17, 0x00, 0x00, 0x00, 0x04, 0x9f, 0x0e, 0x04, 0x3f, 0xb9, 0x04, 0x3f, 0xff, 0x04, 0x3f, 0xcf, 0x04, 0x3f, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x9f, 0x0e, 0x04, 0x3f, 0x46, 0x07, 0xff, 0x01, 0x00, 0x00, 0x00, 0x04, 0xdf, 0x05, 0x04, 0x3f, 0xb2, 0x04, 0x3f, 0xff, 0x04, 0x3f, 0xe1, 0x04, 0x3f, 0x46, 0x04, 0xdf, 0x05, 0x04, 0xdf, 0x05, 0x04, 0xdf, 0x05, 0x04, 0xdf, 0x05, 0x04, 0xdf, 0x05, 0x04, 0xdf, 0x05, 0x04, 0xdf, 0x05, 0x04, 0xdf, 0x05, 0x04, 0xdf, 0x05, 0x07, 0xff, 0x01, 0x04, 0xdf, 0x05, 0x04, 0x5f, 0x20, 0x04, 0x3f, 0x97, 0x04, 0x3f, 0xff, 0x04, 0x3f, 0xff, 0x04, 0x3f, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0x01, 0x04, 0xdf, 0x05, 0x07, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x3f, 0x52, 0x04, 0x3f, 0xf7, 0x04, 0x3f, 0xff, 0x04, 0x3f, 0xeb, 0x04, 0x3f, 0xb9, 0x04, 0x3f, 0xb2, 0x04, 0x3f, 0xb2, 0x04, 0x3f, 0xb2, 0x04, 0x3f, 0xb2, 0x04, 0x3f, 0xb2, 0x04, 0x3f, 0xb2, 0x04, 0x3f, 0xb2, 0x04, 0x3f, 0xb2, 0x04, 0x3f, 0xb2, 0x04, 0x3f, 0xb9, 0x04, 0x3f, 0xda, 0x04, 0x3f, 0xff, 0x04, 0x3f, 0xff, 0x04, 0x3f, 0xc5, 0x04, 0x5f, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xdf, 0x05, 0x04, 0x3f, 0x72, 0x04, 0x3f, 0xf1, 0x04, 0x3f, 0xff, 0x04, 0x3f, 0xff, 0x04, 0x3f, 0xff, 0x04, 0x3f, 0xff, 0x04, 0x3f, 0xff, 0x04, 0x3f, 0xff, 0x04, 0x3f, 0xff, 0x04, 0x3f, 0xff, 0x04, 0x3f, 0xff, 0x04, 0x3f, 0xff, 0x04, 0x3f, 0xff, 0x04, 0x3f, 0xff, 0x04, 0x3f, 0xff, 0x04, 0x3f, 0xff, 0x04, 0x3f, 0xb2, 0x04, 0x3f, 0x2a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xdf, 0x05, 0x04, 0x3f, 0x3c, 0x04, 0x3f, 0x97, 0x04, 0x3f, 0xb9, 0x04, 0x3f, 0xb9, 0x04, 0x3f, 0xb9, 0x04, 0x3f, 0xb9, 0x04, 0x3f, 0xb9, 0x04, 0x3f, 0xb9, 0x04, 0x3f, 0xb9, 0x04, 0x3f, 0xb9, 0x04, 0x3f, 0xb9, 0x04, 0x3f, 0xb9, 0x04, 0x3f, 0xb9, 0x04, 0x3f, 0x97, 0x04, 0x3f, 0x5d, 0x04, 0x9f, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0x01, 0x04, 0xdf, 0x05, 0x04, 0xdf, 0x05, 0x04, 0xdf, 0x05, 0x04, 0xdf, 0x05, 0x04, 0xdf, 0x05, 0x04, 0xdf, 0x05, 0x04, 0xdf, 0x05, 0x04, 0xdf, 0x05, 0x04, 0xdf, 0x05, 0x07, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0x01, 0x04, 0x3f, 0x2a, 0x04, 0x3f, 0x31, 0x04, 0x3f, 0x31, 0x04, 0x3f, 0x31, 0x04, 0x3f, 0x31, 0x04, 0x3f, 0x31, 0x04, 0x3f, 0x31, 0x04, 0x3f, 0x31, 0x04, 0x3f, 0x31, 0x04, 0x3f, 0x31, 0x04, 0x3f, 0x31, 0x04, 0x3f, 0x31, 0x04, 0x3f, 0x31, 0x04, 0x3f, 0x31, 0x04, 0x9f, 0x0e, 0x00, 0x00, 0x00, 0x07, 0xff, 0x01, 0x04, 0x3f, 0x17, 0x04, 0x5f, 0x20, 0x04, 0x3f, 0x17, 0x04, 0xdf, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0x01, 0x04, 0x3f, 0x46, 0x04, 0x3f, 0xb9, 0x04, 0x3f, 0xeb, 0x04, 0x3f, 0xf1, 0x04, 0x3f, 0xf1, 0x04, 0x3f, 0xf1, 0x04, 0x3f, 0xf1, 0x04, 0x3f, 0xf1, 0x04, 0x3f, 0xf1, 0x04, 0x3f, 0xf1, 0x04, 0x3f, 0xf1, 0x04, 0x3f, 0xeb, 0x04, 0x3f, 0xcf, 0x04, 0x3f, 0x72, 0x04, 0x9f, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x3f, 0x46, 0x04, 0x3f, 0x72, 0x04, 0x3f, 0x72, 0x04, 0x3f, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0x01, 0x07, 0xff, 0x01, 0x04, 0x9f, 0x0e, 0x04, 0x3f, 0x52, 0x04, 0x3f, 0x97, 0x04, 0x3f, 0xc5, 0x04, 0x3f, 0xe1, 0x04, 0x3f, 0xeb, 0x04, 0x3f, 0xeb, 0x04, 0x3f, 0xe1, 0x04, 0x3f, 0xcf, 0x04, 0x3f, 0xa4, 0x04, 0x3f, 0x66, 0x04, 0x5f, 0x20, 0x07, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x9f, 0x0e, 0x04, 0x5f, 0x20, 0x04, 0x5f, 0x20, 0x04, 0xdf, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x9f, 0x0e, 0x04, 0x5f, 0x20, 0x04, 0x3f, 0x2a, 0x04, 0x3f, 0x2a, 0x04, 0x5f, 0x20, 0x04, 0x9f, 0x0e, 0x07, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +#endif +#if LV_COLOR_DEPTH == 32 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x85, 0x00, 0x17, 0xff, 0x85, 0x00, 0x2a, 0xff, 0x85, 0x00, 0x2a, 0xff, 0x91, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x01, 0xff, 0x99, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x87, 0x00, 0x20, 0xfd, 0x83, 0x00, 0x8a, 0xfc, 0x82, 0x00, 0xcf, 0xfc, 0x82, 0x00, 0xeb, 0xfc, 0x82, 0x00, 0xeb, 0xfc, 0x82, 0x00, 0xc5, 0xfc, 0x83, 0x00, 0x72, 0xff, 0x91, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x85, 0x00, 0x17, 0xfc, 0x83, 0x00, 0x72, 0xff, 0x85, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x00, 0xff, 0x85, 0x00, 0x2a, 0xfc, 0x82, 0x00, 0xc5, 0xfc, 0x82, 0x00, 0xff, 0xfc, 0x82, 0x00, 0xff, 0xfc, 0x82, 0x00, 0xff, 0xfc, 0x82, 0x00, 0xff, 0xfc, 0x82, 0x00, 0xff, 0xfc, 0x82, 0x00, 0xff, 0xfd, 0x82, 0x00, 0xa4, 0xff, 0x91, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0xff, 0x99, 0x00, 0x05, 0xfe, 0x82, 0x00, 0x52, 0xff, 0x87, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x82, 0x00, 0x31, 0xfc, 0x82, 0x00, 0xc5, 0xfd, 0x83, 0x00, 0x8a, 0xff, 0xff, 0x00, 0x01, 0xff, 0x91, 0x00, 0x0e, 0xfc, 0x82, 0x00, 0xb2, 0xfc, 0x82, 0x00, 0xff, 0xfc, 0x82, 0x00, 0xff, 0xfc, 0x82, 0x00, 0xb9, 0xfc, 0x83, 0x00, 0x72, 0xfc, 0x82, 0x00, 0x7f, 0xfc, 0x82, 0x00, 0xcf, 0xfc, 0x82, 0x00, 0xff, 0xfc, 0x82, 0x00, 0xff, 0xfc, 0x82, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x83, 0x00, 0x5d, 0xfc, 0x82, 0x00, 0xb9, 0xff, 0x82, 0x00, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x83, 0x00, 0x3c, 0xfc, 0x83, 0x00, 0xda, 0xfc, 0x82, 0x00, 0xc5, 0xfe, 0x85, 0x00, 0x17, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x82, 0x00, 0x66, 0xfc, 0x82, 0x00, 0xf7, 0xfc, 0x82, 0x00, 0xff, 0xfd, 0x82, 0x00, 0x97, 0xff, 0x91, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x87, 0x00, 0x20, 0xfc, 0x82, 0x00, 0xc5, 0xfc, 0x82, 0x00, 0xff, 0xfc, 0x82, 0x00, 0xe1, 0xff, 0x85, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x00, 0xff, 0x91, 0x00, 0x0e, 0xfc, 0x82, 0x00, 0xb9, 0xfc, 0x83, 0x00, 0xda, 0xff, 0x82, 0x00, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x82, 0x00, 0x31, 0xfc, 0x83, 0x00, 0xda, 0xfc, 0x82, 0x00, 0xf1, 0xff, 0x83, 0x00, 0x46, 0x00, 0x00, 0x00, 0x00, 0xff, 0x85, 0x00, 0x2a, 0xfc, 0x83, 0x00, 0xda, 0xfc, 0x82, 0x00, 0xff, 0xfc, 0x83, 0x00, 0xda, 0xff, 0x87, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x82, 0x00, 0x52, 0xfc, 0x82, 0x00, 0xf7, 0xfc, 0x82, 0x00, 0xff, 0xfd, 0x82, 0x00, 0x97, 0xff, 0xff, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0xff, 0x83, 0x00, 0x46, 0xfc, 0x82, 0x00, 0xf7, 0xfc, 0x82, 0x00, 0xcf, 0xff, 0x87, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x01, 0xff, 0x91, 0x00, 0x0e, 0xfc, 0x82, 0x00, 0xb9, 0xfc, 0x82, 0x00, 0xff, 0xfd, 0x83, 0x00, 0x8a, 0xff, 0xff, 0x00, 0x01, 0xff, 0x99, 0x00, 0x05, 0xfd, 0x82, 0x00, 0x97, 0xfc, 0x82, 0x00, 0xff, 0xfc, 0x82, 0x00, 0xf7, 0xfc, 0x83, 0x00, 0x5d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x99, 0x00, 0x05, 0xfd, 0x82, 0x00, 0xa4, 0xfc, 0x82, 0x00, 0xff, 0xfc, 0x82, 0x00, 0xeb, 0xff, 0x83, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x00, 0xff, 0x99, 0x00, 0x05, 0xfd, 0x82, 0x00, 0xa4, 0xfc, 0x82, 0x00, 0xff, 0xfd, 0x82, 0x00, 0xa4, 0xff, 0x99, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x83, 0x00, 0x72, 0xfc, 0x82, 0x00, 0xff, 0xfc, 0x82, 0x00, 0xc5, 0xfe, 0x85, 0x00, 0x17, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x82, 0x00, 0x52, 0xfc, 0x82, 0x00, 0xf7, 0xfc, 0x82, 0x00, 0xff, 0xfd, 0x82, 0x00, 0xa4, 0xff, 0x99, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0xff, 0x99, 0x00, 0x05, 0xff, 0x85, 0x00, 0x2a, 0xff, 0x87, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x83, 0x00, 0x3c, 0xfc, 0x82, 0x00, 0xeb, 0xfc, 0x82, 0x00, 0xff, 0xfc, 0x82, 0x00, 0xb2, 0xff, 0x99, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0xff, 0x82, 0x00, 0x31, 0xfc, 0x82, 0x00, 0xeb, 0xfc, 0x82, 0x00, 0xf7, 0xfe, 0x82, 0x00, 0x52, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x87, 0x00, 0x20, 0xfc, 0x83, 0x00, 0xda, 0xfc, 0x82, 0x00, 0xf1, 0xff, 0x83, 0x00, 0x46, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x85, 0x00, 0x17, 0xfc, 0x82, 0x00, 0xc5, 0xfc, 0x82, 0x00, 0xff, 0xfc, 0x82, 0x00, 0xe1, 0xff, 0x82, 0x00, 0x31, 0x00, 0x00, 0x00, 0x00, 0xff, 0x91, 0x00, 0x0e, 0xfd, 0x82, 0x00, 0x97, 0xfc, 0x82, 0x00, 0xeb, 0xfc, 0x83, 0x00, 0xda, 0xfe, 0x82, 0x00, 0x52, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x01, 0xfd, 0x82, 0x00, 0x97, 0xfc, 0x82, 0x00, 0xff, 0xfc, 0x82, 0x00, 0xf7, 0xfe, 0x82, 0x00, 0x52, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfd, 0x83, 0x00, 0x8a, 0xfc, 0x82, 0x00, 0xff, 0xfc, 0x82, 0x00, 0xb9, 0xff, 0x91, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x82, 0x00, 0x66, 0xfc, 0x82, 0x00, 0xff, 0xfd, 0x83, 0x00, 0x8a, 0xff, 0xff, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x82, 0x00, 0x7f, 0xfc, 0x82, 0x00, 0xff, 0xfc, 0x82, 0x00, 0xff, 0xfc, 0x83, 0x00, 0x72, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x82, 0x00, 0x66, 0xfc, 0x82, 0x00, 0xff, 0xfc, 0x82, 0x00, 0xff, 0xfc, 0x82, 0x00, 0xff, 0xfc, 0x82, 0x00, 0xcf, 0xfe, 0x85, 0x00, 0x17, 0x00, 0x00, 0x00, 0x00, 0xff, 0x85, 0x00, 0x2a, 0xfc, 0x82, 0x00, 0xe1, 0xfc, 0x82, 0x00, 0xff, 0xfc, 0x82, 0x00, 0xc5, 0xff, 0x91, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0xff, 0x87, 0x00, 0x20, 0xfc, 0x83, 0x00, 0xda, 0xfc, 0x82, 0x00, 0xf7, 0xff, 0x83, 0x00, 0x46, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xff, 0x99, 0x00, 0x05, 0xfc, 0x82, 0x00, 0xb2, 0xfc, 0x82, 0x00, 0xc5, 0xfe, 0x85, 0x00, 0x17, 0x00, 0x00, 0x00, 0x00, 0xff, 0x83, 0x00, 0x3c, 0xfc, 0x82, 0x00, 0xeb, 0xfc, 0x82, 0x00, 0xff, 0xfc, 0x82, 0x00, 0xb9, 0xff, 0x91, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0xff, 0x87, 0x00, 0x20, 0xfc, 0x83, 0x00, 0xda, 0xfc, 0x82, 0x00, 0xff, 0xfc, 0x82, 0x00, 0xff, 0xfc, 0x82, 0x00, 0xff, 0xfc, 0x82, 0x00, 0xff, 0xfc, 0x82, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x82, 0x00, 0x7f, 0xfc, 0x82, 0x00, 0xff, 0xfc, 0x82, 0x00, 0xff, 0xfc, 0x82, 0x00, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x83, 0x00, 0x72, 0xfc, 0x82, 0x00, 0xff, 0xfd, 0x83, 0x00, 0x8a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xff, 0x87, 0x00, 0x20, 0xfc, 0x82, 0x00, 0xcf, 0xff, 0x83, 0x00, 0x46, 0x00, 0x00, 0x00, 0x00, 0xff, 0x91, 0x00, 0x0e, 0xfc, 0x82, 0x00, 0xb9, 0xfc, 0x82, 0x00, 0xff, 0xfc, 0x82, 0x00, 0xf1, 0xff, 0x83, 0x00, 0x46, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x01, 0xfd, 0x82, 0x00, 0x97, 0xfc, 0x82, 0x00, 0xff, 0xfc, 0x82, 0x00, 0xf7, 0xfc, 0x82, 0x00, 0x7f, 0xfc, 0x82, 0x00, 0xc5, 0xfc, 0x82, 0x00, 0xff, 0xfc, 0x82, 0x00, 0xe1, 0xff, 0x85, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x00, 0xff, 0x87, 0x00, 0x20, 0xfc, 0x82, 0x00, 0xcf, 0xfc, 0x82, 0x00, 0xff, 0xfc, 0x82, 0x00, 0xcf, 0xff, 0x87, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x85, 0x00, 0x17, 0xfc, 0x82, 0x00, 0xcf, 0xfc, 0x82, 0x00, 0xc5, 0xff, 0x91, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xff, 0x83, 0x00, 0x3c, 0xfc, 0x83, 0x00, 0x72, 0xff, 0xff, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x83, 0x00, 0x72, 0xfc, 0x82, 0x00, 0xff, 0xfc, 0x82, 0x00, 0xff, 0xfd, 0x83, 0x00, 0x8a, 0xff, 0xff, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0xff, 0x83, 0x00, 0x46, 0xfc, 0x82, 0x00, 0xf1, 0xfc, 0x82, 0x00, 0xff, 0xfc, 0x82, 0x00, 0xb2, 0xff, 0x99, 0x00, 0x05, 0xfe, 0x82, 0x00, 0x52, 0xfc, 0x82, 0x00, 0xf7, 0xfc, 0x82, 0x00, 0xff, 0xfd, 0x83, 0x00, 0x8a, 0xff, 0xff, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x82, 0x00, 0x66, 0xfc, 0x82, 0x00, 0xff, 0xfc, 0x82, 0x00, 0xff, 0xfc, 0x82, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x83, 0x00, 0x5d, 0xfc, 0x83, 0x00, 0xda, 0xff, 0x87, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xff, 0x91, 0x00, 0x0e, 0xff, 0x91, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0xff, 0x85, 0x00, 0x2a, 0xfc, 0x82, 0x00, 0xe1, 0xfc, 0x82, 0x00, 0xff, 0xfc, 0x82, 0x00, 0xcf, 0xff, 0x87, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x85, 0x00, 0x17, 0xfc, 0x82, 0x00, 0xc5, 0xfc, 0x82, 0x00, 0xff, 0xfc, 0x82, 0x00, 0xeb, 0xff, 0x83, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x00, 0xff, 0x99, 0x00, 0x05, 0xfc, 0x82, 0x00, 0xb2, 0xfc, 0x82, 0x00, 0xff, 0xfc, 0x82, 0x00, 0xeb, 0xff, 0x83, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x00, 0xff, 0x91, 0x00, 0x0e, 0xfc, 0x82, 0x00, 0xc5, 0xfc, 0x82, 0x00, 0xff, 0xfc, 0x82, 0x00, 0xe1, 0xff, 0x85, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x00, 0xff, 0x91, 0x00, 0x0e, 0xfd, 0x82, 0x00, 0xa4, 0xff, 0x82, 0x00, 0x31, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x99, 0x00, 0x05, 0xfd, 0x82, 0x00, 0xa4, 0xfc, 0x82, 0x00, 0xff, 0xfc, 0x82, 0x00, 0xf7, 0xfe, 0x82, 0x00, 0x52, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x83, 0x00, 0x72, 0xfc, 0x82, 0x00, 0xff, 0xfc, 0x82, 0x00, 0xff, 0xfc, 0x82, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x83, 0x00, 0x3c, 0xfc, 0x82, 0x00, 0xeb, 0xfc, 0x82, 0x00, 0xff, 0xfd, 0x82, 0x00, 0xa4, 0xff, 0x99, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x82, 0x00, 0x52, 0xfc, 0x82, 0x00, 0xf7, 0xfc, 0x82, 0x00, 0xff, 0xfd, 0x82, 0x00, 0x97, 0xff, 0xff, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0xff, 0x82, 0x00, 0x31, 0xff, 0x87, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x83, 0x00, 0x5d, 0xfc, 0x82, 0x00, 0xf7, 0xfc, 0x82, 0x00, 0xff, 0xfd, 0x82, 0x00, 0xa4, 0xff, 0x99, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0xff, 0x82, 0x00, 0x31, 0xfc, 0x82, 0x00, 0xe1, 0xfc, 0x82, 0x00, 0xff, 0xfc, 0x82, 0x00, 0xc5, 0xfe, 0x85, 0x00, 0x17, 0xff, 0x99, 0x00, 0x05, 0xff, 0x82, 0x00, 0x31, 0xff, 0x83, 0x00, 0x3c, 0xff, 0x83, 0x00, 0x3c, 0xfc, 0x82, 0x00, 0xcf, 0xfc, 0x82, 0x00, 0xff, 0xfc, 0x82, 0x00, 0xf1, 0xff, 0x83, 0x00, 0x46, 0x00, 0x00, 0x00, 0x00, 0xff, 0x99, 0x00, 0x05, 0xfd, 0x82, 0x00, 0xa4, 0xfc, 0x82, 0x00, 0xff, 0xfc, 0x82, 0x00, 0xeb, 0xff, 0x83, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x85, 0x00, 0x17, 0xfc, 0x82, 0x00, 0xcf, 0xfc, 0x82, 0x00, 0xff, 0xfc, 0x83, 0x00, 0xda, 0xff, 0x85, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x00, 0xff, 0x99, 0x00, 0x05, 0xfd, 0x82, 0x00, 0xa4, 0xfc, 0x82, 0x00, 0xff, 0xfc, 0x82, 0x00, 0xf7, 0xfe, 0x82, 0x00, 0x52, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x83, 0x00, 0x72, 0xfc, 0x82, 0x00, 0xf1, 0xfc, 0x82, 0x00, 0xf1, 0xfc, 0x82, 0x00, 0xf1, 0xfc, 0x82, 0x00, 0xff, 0xfc, 0x82, 0x00, 0xff, 0xfc, 0x82, 0x00, 0xff, 0xfc, 0x82, 0x00, 0xb9, 0xff, 0x91, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0xff, 0x83, 0x00, 0x3c, 0xfc, 0x82, 0x00, 0xeb, 0xfc, 0x82, 0x00, 0xff, 0xfd, 0x82, 0x00, 0xa4, 0xff, 0x99, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x83, 0x00, 0x3c, 0xfc, 0x82, 0x00, 0xf7, 0xfc, 0x82, 0x00, 0xff, 0xfc, 0x83, 0x00, 0x72, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x82, 0x00, 0x52, 0xfc, 0x82, 0x00, 0xf7, 0xfc, 0x82, 0x00, 0xff, 0xfd, 0x82, 0x00, 0xa4, 0xff, 0x99, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0xfd, 0x83, 0x00, 0x8a, 0xfc, 0x82, 0x00, 0xff, 0xfc, 0x82, 0x00, 0xff, 0xfc, 0x82, 0x00, 0xff, 0xfc, 0x82, 0x00, 0xff, 0xfc, 0x82, 0x00, 0xff, 0xfc, 0x82, 0x00, 0xff, 0xfc, 0x82, 0x00, 0xf7, 0xfc, 0x83, 0x00, 0x5d, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x01, 0xfd, 0x82, 0x00, 0xa4, 0xfc, 0x82, 0x00, 0xff, 0xfc, 0x82, 0x00, 0xe1, 0xff, 0x87, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x85, 0x00, 0x2a, 0xfc, 0x82, 0x00, 0xeb, 0xfc, 0x82, 0x00, 0xcf, 0xfe, 0x85, 0x00, 0x17, 0x00, 0x00, 0x00, 0x00, 0xff, 0x99, 0x00, 0x05, 0xfc, 0x82, 0x00, 0xb2, 0xfc, 0x82, 0x00, 0xff, 0xfc, 0x82, 0x00, 0xe1, 0xff, 0x85, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x85, 0x00, 0x17, 0xfe, 0x82, 0x00, 0x52, 0xfc, 0x83, 0x00, 0x5d, 0xfc, 0x83, 0x00, 0x5d, 0xfc, 0x83, 0x00, 0x5d, 0xfc, 0x83, 0x00, 0x72, 0xfc, 0x82, 0x00, 0xe1, 0xfc, 0x82, 0x00, 0xff, 0xfc, 0x82, 0x00, 0xc5, 0xff, 0x91, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x82, 0x00, 0x66, 0xfc, 0x82, 0x00, 0xff, 0xfc, 0x82, 0x00, 0xf1, 0xff, 0x83, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x99, 0x00, 0x05, 0xfc, 0x82, 0x00, 0xb9, 0xfd, 0x82, 0x00, 0x97, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x85, 0x00, 0x17, 0xfc, 0x83, 0x00, 0xda, 0xfc, 0x82, 0x00, 0xff, 0xfd, 0x82, 0x00, 0x97, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x82, 0x00, 0x66, 0xfc, 0x82, 0x00, 0xf1, 0xfd, 0x82, 0x00, 0xa4, 0xff, 0x99, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x83, 0x00, 0x72, 0xfc, 0x82, 0x00, 0xff, 0xfc, 0x82, 0x00, 0xf1, 0xff, 0x82, 0x00, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x83, 0x00, 0x5d, 0xfc, 0x82, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x85, 0x00, 0x17, 0xfc, 0x83, 0x00, 0xda, 0xfc, 0x82, 0x00, 0xff, 0xfd, 0x82, 0x00, 0x97, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x99, 0x00, 0x05, 0xff, 0x85, 0x00, 0x2a, 0xfe, 0x85, 0x00, 0x17, 0x00, 0x00, 0x00, 0x00, 0xff, 0x91, 0x00, 0x0e, 0xfc, 0x82, 0x00, 0xb9, 0xfc, 0x82, 0x00, 0xff, 0xfc, 0x82, 0x00, 0xcf, 0xfe, 0x85, 0x00, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x91, 0x00, 0x0e, 0xff, 0x83, 0x00, 0x46, 0xff, 0xff, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0xff, 0x99, 0x00, 0x05, 0xfc, 0x82, 0x00, 0xb2, 0xfc, 0x82, 0x00, 0xff, 0xfc, 0x82, 0x00, 0xe1, 0xff, 0x83, 0x00, 0x46, 0xff, 0x99, 0x00, 0x05, 0xff, 0x99, 0x00, 0x05, 0xff, 0x99, 0x00, 0x05, 0xff, 0x99, 0x00, 0x05, 0xff, 0x99, 0x00, 0x05, 0xff, 0x99, 0x00, 0x05, 0xff, 0x99, 0x00, 0x05, 0xff, 0x99, 0x00, 0x05, 0xff, 0x99, 0x00, 0x05, 0xff, 0xff, 0x00, 0x01, 0xff, 0x99, 0x00, 0x05, 0xff, 0x87, 0x00, 0x20, 0xfd, 0x82, 0x00, 0x97, 0xfc, 0x82, 0x00, 0xff, 0xfc, 0x82, 0x00, 0xff, 0xfc, 0x82, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x01, 0xff, 0x99, 0x00, 0x05, 0xff, 0xff, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x82, 0x00, 0x52, 0xfc, 0x82, 0x00, 0xf7, 0xfc, 0x82, 0x00, 0xff, 0xfc, 0x82, 0x00, 0xeb, 0xfc, 0x82, 0x00, 0xb9, 0xfc, 0x82, 0x00, 0xb2, 0xfc, 0x82, 0x00, 0xb2, 0xfc, 0x82, 0x00, 0xb2, 0xfc, 0x82, 0x00, 0xb2, 0xfc, 0x82, 0x00, 0xb2, 0xfc, 0x82, 0x00, 0xb2, 0xfc, 0x82, 0x00, 0xb2, 0xfc, 0x82, 0x00, 0xb2, 0xfc, 0x82, 0x00, 0xb2, 0xfc, 0x82, 0x00, 0xb9, 0xfc, 0x83, 0x00, 0xda, 0xfc, 0x82, 0x00, 0xff, 0xfc, 0x82, 0x00, 0xff, 0xfc, 0x82, 0x00, 0xc5, 0xff, 0x87, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x99, 0x00, 0x05, 0xfc, 0x83, 0x00, 0x72, 0xfc, 0x82, 0x00, 0xf1, 0xfc, 0x82, 0x00, 0xff, 0xfc, 0x82, 0x00, 0xff, 0xfc, 0x82, 0x00, 0xff, 0xfc, 0x82, 0x00, 0xff, 0xfc, 0x82, 0x00, 0xff, 0xfc, 0x82, 0x00, 0xff, 0xfc, 0x82, 0x00, 0xff, 0xfc, 0x82, 0x00, 0xff, 0xfc, 0x82, 0x00, 0xff, 0xfc, 0x82, 0x00, 0xff, 0xfc, 0x82, 0x00, 0xff, 0xfc, 0x82, 0x00, 0xff, 0xfc, 0x82, 0x00, 0xff, 0xfc, 0x82, 0x00, 0xff, 0xfc, 0x82, 0x00, 0xb2, 0xff, 0x85, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x99, 0x00, 0x05, 0xff, 0x83, 0x00, 0x3c, 0xfd, 0x82, 0x00, 0x97, 0xfc, 0x82, 0x00, 0xb9, 0xfc, 0x82, 0x00, 0xb9, 0xfc, 0x82, 0x00, 0xb9, 0xfc, 0x82, 0x00, 0xb9, 0xfc, 0x82, 0x00, 0xb9, 0xfc, 0x82, 0x00, 0xb9, 0xfc, 0x82, 0x00, 0xb9, 0xfc, 0x82, 0x00, 0xb9, 0xfc, 0x82, 0x00, 0xb9, 0xfc, 0x82, 0x00, 0xb9, 0xfc, 0x82, 0x00, 0xb9, 0xfd, 0x82, 0x00, 0x97, 0xfc, 0x83, 0x00, 0x5d, 0xff, 0x91, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x01, 0xff, 0x99, 0x00, 0x05, 0xff, 0x99, 0x00, 0x05, 0xff, 0x99, 0x00, 0x05, 0xff, 0x99, 0x00, 0x05, 0xff, 0x99, 0x00, 0x05, 0xff, 0x99, 0x00, 0x05, 0xff, 0x99, 0x00, 0x05, 0xff, 0x99, 0x00, 0x05, 0xff, 0x99, 0x00, 0x05, 0xff, 0xff, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x01, 0xff, 0x85, 0x00, 0x2a, 0xff, 0x82, 0x00, 0x31, 0xff, 0x82, 0x00, 0x31, 0xff, 0x82, 0x00, 0x31, 0xff, 0x82, 0x00, 0x31, 0xff, 0x82, 0x00, 0x31, 0xff, 0x82, 0x00, 0x31, 0xff, 0x82, 0x00, 0x31, 0xff, 0x82, 0x00, 0x31, 0xff, 0x82, 0x00, 0x31, 0xff, 0x82, 0x00, 0x31, 0xff, 0x82, 0x00, 0x31, 0xff, 0x82, 0x00, 0x31, 0xff, 0x82, 0x00, 0x31, 0xff, 0x91, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x01, 0xfe, 0x85, 0x00, 0x17, 0xff, 0x87, 0x00, 0x20, 0xfe, 0x85, 0x00, 0x17, 0xff, 0x99, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x01, 0xff, 0x83, 0x00, 0x46, 0xfc, 0x82, 0x00, 0xb9, 0xfc, 0x82, 0x00, 0xeb, 0xfc, 0x82, 0x00, 0xf1, 0xfc, 0x82, 0x00, 0xf1, 0xfc, 0x82, 0x00, 0xf1, 0xfc, 0x82, 0x00, 0xf1, 0xfc, 0x82, 0x00, 0xf1, 0xfc, 0x82, 0x00, 0xf1, 0xfc, 0x82, 0x00, 0xf1, 0xfc, 0x82, 0x00, 0xf1, 0xfc, 0x82, 0x00, 0xeb, 0xfc, 0x82, 0x00, 0xcf, 0xfc, 0x83, 0x00, 0x72, 0xff, 0x91, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x83, 0x00, 0x46, 0xfc, 0x83, 0x00, 0x72, 0xfc, 0x83, 0x00, 0x72, 0xfe, 0x85, 0x00, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x01, 0xff, 0xff, 0x00, 0x01, 0xff, 0x91, 0x00, 0x0e, 0xfe, 0x82, 0x00, 0x52, 0xfd, 0x82, 0x00, 0x97, 0xfc, 0x82, 0x00, 0xc5, 0xfc, 0x82, 0x00, 0xe1, 0xfc, 0x82, 0x00, 0xeb, 0xfc, 0x82, 0x00, 0xeb, 0xfc, 0x82, 0x00, 0xe1, 0xfc, 0x82, 0x00, 0xcf, 0xfd, 0x82, 0x00, 0xa4, 0xfc, 0x82, 0x00, 0x66, 0xff, 0x87, 0x00, 0x20, 0xff, 0xff, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x91, 0x00, 0x0e, 0xff, 0x87, 0x00, 0x20, 0xff, 0x87, 0x00, 0x20, 0xff, 0x99, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x91, 0x00, 0x0e, 0xff, 0x87, 0x00, 0x20, 0xff, 0x85, 0x00, 0x2a, 0xff, 0x85, 0x00, 0x2a, 0xff, 0x87, 0x00, 0x20, 0xff, 0x91, 0x00, 0x0e, 0xff, 0xff, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +#endif +}; + +const lv_img_dsc_t auracast = { + .header.cf = LV_IMG_CF_TRUE_COLOR_ALPHA, + .header.always_zero = 0, + .header.reserved = 0, + .header.w = 32, + .header.h = 32, + .data_size = 1024 * LV_IMG_PX_SIZE_ALPHA_BYTE, + .data = auracast_map, +}; diff --git a/app/src/main.c b/app/src/main.c index f765f794..eed795f8 100644 --- a/app/src/main.c +++ b/app/src/main.c @@ -64,6 +64,10 @@ #include #include "fuel_gauge/zsw_pmic.h" +#ifdef CONFIG_APPLICATIONS_USE_LEA_ASSISTANT +#include "applications/lea_assistant/broadcast_assistant.h" +#endif + LOG_MODULE_REGISTER(main, CONFIG_ZSW_APP_LOG_LEVEL); #define TASK_WDT_FEED_INTERVAL_MS 3000 @@ -349,6 +353,10 @@ static void enable_bluetooth(void) ble_ams_init(); ble_cts_init(); ble_ancs_init(); + +#ifdef CONFIG_APPLICATIONS_USE_LEA_ASSISTANT + broadcast_assistant_init(); +#endif } static void print_retention_ram(void) diff --git a/app/tools/astyle.cfg b/app/tools/astyle.cfg index d98aa6d9..81f24c0c 100644 --- a/app/tools/astyle.cfg +++ b/app/tools/astyle.cfg @@ -38,3 +38,7 @@ --exclude=src/applications/2048/2048_lib --exclude=src/applications/iaq/ui_export --exclude=src/applications/notification/ui_export +--exclude=src/applications/lea_assistant/broadcast_assistant.c +--exclude=src/applications/lea_assistant/broadcast_assistant.h +--exclude=src/applications/lea_assistant/message_handler.c +--exclude=src/applications/lea_assistant/message_handler.h