/* * Copyright (c) 2019-2023 Beijing Hanwei Innovation Technology Ltd. Co. and * its subsidiaries and affiliates (collectly called MKSEMI). * * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form, except as embedded into an MKSEMI * integrated circuit in a product or a software update for such product, * must reproduce the above copyright notice, this list of conditions and * the following disclaimer in the documentation and/or other materials * provided with the distribution. * * 3. Neither the name of MKSEMI nor the names of its contributors may be used * to endorse or promote products derived from this software without * specific prior written permission. * * 4. This software, with or without modification, must only be used with a * MKSEMI integrated circuit. * * 5. Any software provided in binary form under this license must not be * reverse engineered, decompiled, modified and/or disassembled. * * THIS SOFTWARE IS PROVIDED BY MKSEMI "AS IS" AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL MKSEMI OR CONTRIBUTORS BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "mk_trace.h" #include "mk_power.h" #include "mk_uwb.h" #include "mk_aes.h" #include "mk_misc.h" #include "uwb_audio.h" #include "board.h" extern void uwb_audio_buf_update(uint8_t idx); struct RANGING_ENV_T ranging_env; uint8_t fira_uwb_tx_buf[PHY_PAYLOAD_LEN_MAX]; static struct UWB_AUDIO_CB_T uwb_audio_cb; static struct UWB_OP_T op = { .session_configure = uwb_audio_configure, .session_start = uwb_audio_start, .session_stop = uwb_audio_stop, .session_local_addr_set = ranging_local_addr_set, .session_peer_addr_set = ranging_peer_addr_set, .session_responder_addr_add = ranging_responder_addr_add, .session_responder_list_clr = ranging_responder_list_clr, .session_responder_num_get = ranging_responder_num_get, .session_responder_addr_get = ranging_responder_addr_get, .session_dynamic_update_responder_list = NULL, .session_set_ccc_ursk = NULL, .vendor_session_configure = NULL, .vendor_session_start = NULL, .vendor_session_stop = NULL, }; static void uwb_audio_tx_process(struct MAC_HW_REPORT_T *tx_report); static void uwb_audio_rx_process(struct MAC_HW_REPORT_T *rx_report); void app_session_init(void); static uint8_t *uwb_audio_tx_msg_buf[2][UWB_AUDIO_TX_SLOT_NUM]; static uint16_t uwb_audio_tx_msg_len[2][UWB_AUDIO_TX_SLOT_NUM]; UWB_AUDIO_SDU_T uwb_audio_buf[2][UWB_AUDIO_TX_SLOT_NUM]; static uint8_t uwb_audio_tx_flag[2] = {0}; static uint8_t uwb_audio_rx_flag[2] = {0}; uint8_t *mac_tx_buf_get(uint8_t idx); extern uint8_t *mac_tx_buf_get(uint8_t idx); extern uint8_t mac_repeat_rx(enum EVT_MODE_T mode, uint32_t tgt_time, uint8_t em_idx, uint32_t timeout); extern uint8_t mac_repeat_tx(enum EVT_MODE_T mode, uint32_t tgt_time, uint8_t em_idx, uint8_t *pkt_data, uint16_t pkt_len); int uwb_audio_init(uint8_t handle_id) { /* store handler ID */ uwb_audio_cb.handle_id = handle_id; /* init rx queue */ WSF_QUEUE_INIT(&uwb_audio_cb.msg_queue); for (uint8_t i = 0; i < UWB_AUDIO_TX_SLOT_NUM; i++) { uwb_audio_tx_msg_buf[0][i] = mac_tx_buf_get(i); uwb_audio_tx_msg_buf[1][i] = mac_tx_buf_get(UWB_AUDIO_TX_SLOT_NUM + i); uwb_audio_buf[0][i].data = uwb_audio_tx_msg_buf[0][i] + UWB_AUDIO_DATA_OFFSET; uwb_audio_buf[1][i].data = uwb_audio_tx_msg_buf[1][i] + UWB_AUDIO_DATA_OFFSET; } return 0; } int uwb_audio_deinit(void) { return 0; } // This function will be called by uwbapi_session_init() void app_session_init(void) { // register process handler for MAC TX done and RX done mac_register_process_handler(uwb_audio_tx_process, uwb_audio_rx_process); uwbs_handler_init(&op); } void uwb_audio_configure(void) { fira_keys_generate(); aes_update_key(AES_ID0, &fira_key.devPayKey.ukey.keyByte[0]); mac_update_ccm_key((uint32_t *)&fira_key.devPayKey.ukey.keyWord[0]); mac_update_key_table(KEY_IDX_0, &fira_key.devPayKey.ukey.keyWord[0]); uwb_app_config.ranging_stage = RANGING_IDLE; ranging_env.uwb_period_prefetch_time = UWB_PERIOD_PREFETCH_TIME; ranging_env.uwb_evt_prefetch_time = UWB_EVT_PREFETCH_TIME; ranging_env.uwb_rx_open_in_advance = UWB_RX_OPEN_IN_ADVANCE; ranging_env.uwb_rx_window = UWB_RX_WINDOW; ranging_env.uwb_rx_open_in_advance_wakeup = UWB_RX_OPEN_IN_ADVANCE; ranging_env.uwb_rx_window_wakeup = UWB_RX_WINDOW; ranging_env.ranging_period = MS_TO_PHY_TIMER_COUNT(uwb_app_config.session_param.ranging_interval) / 4; // ranging_env.slots_per_block = (uint16_t)(uwb_app_config.session_param.ranging_interval * 1000 / RSTU_TO_US(uwb_app_config.session_param.slot_duration)); // ASSERT(ranging_env.slots_per_block >= uwb_app_config.session_param.slots_per_round, "Ranging block parameters configure wrong"); ranging_env.slot_interval = RSTU_TO_PHY_TIMER_COUNT(uwb_app_config.session_param.slot_duration); ranging_env.round_duration = UWB_AUDIO_TX_SLOT_NUM * ranging_env.slot_interval + RSTU_TO_PHY_TIMER_COUNT(UWB_AUDIO_ACK_SLOT_DURATION); ranging_env.slots_per_block = (uint16_t)(ranging_env.ranging_period / ranging_env.slot_interval); ranging_env.phy_sts_index = fira_key.phyStsIdxInit - ranging_env.slots_per_block; ranging_env.enable = 0; ranging_env.slot_idx = 0; ranging_env.tof = 0; ranging_env.range_data.ranging_type = 0x1; // TWR (SS-TWR, DS-TWR) ranging_env.range_data.ranging_interval = uwb_app_config.session_param.ranging_interval; ranging_env.range_data.mac_addr_mode = uwbs_mac_addr_mode_get(); ranging_env.range_data.session_id = uwb_app_config.session_id; ranging_env.stride_length = uwb_app_config.session_param.stride_length; ranging_env.round_offset_in_block = 0; ranging_env.next_round_index = 0; uwbs_configure(PHY_TX | PHY_RX, uwb_app_config.session_param.tx_power_level); LOG_INFO(TRACE_MODULE_FIRA, "slot duration %dus ranging interval %fms slots per round %d slots per block %d\r\n", RSTU_TO_US(uwb_app_config.session_param.slot_duration), uwb_app_config.session_param.ranging_interval / 4.0, uwb_app_config.session_param.slots_per_round, ranging_env.slots_per_block); } void uwb_audio_start(void) { ranging_env.enable = 1; ranging_env.lost_cnt = 0x0; ranging_env.anchor_point = phy_timer_count_get(); ranging_env.slot_idx = 0; phy_sts_pkt_cfg_set(SP0); enum DEV_ROLE_T role = uwb_app_config.session_param.device_role; if (role == DEV_ROLE_INITIATOR) { uwb_app_config.ranging_stage = RANGING_DM_TX; uwb_app_config.session_param.responder_slot_idx = 1; phy_timer_target_set(ranging_env.anchor_point + ranging_env.ranging_period - UWB_PERIOD_PREFETCH_TIME, uwb_audio_phy_timer_callback); power_mode_request(POWER_UNIT_APP, POWER_MODE_POWER_DOWN); } else { uwb_app_config.ranging_stage = RANGING_SYNC; ranging_update_slot_index(ranging_env.slot_idx); power_on_radio(0, 1); mac_rx(EVT_MODE_MAC_PHY_ASAP, 0, ranging_env.ranging_period); mac_start(); power_mode_request(POWER_UNIT_APP, POWER_MODE_SLEEP); } ranging_env.count = 0; ranging_env.count_last = 0; LOG_INFO(TRACE_MODULE_FIRA, "Session start, role %d\r\n", uwb_app_config.session_param.device_role); } void uwb_audio_stop(void) { ranging_env.enable = 0; LOG_INFO(TRACE_MODULE_FIRA, "Ranging stop\r\n"); } static void uwb_audio_tx_done_ind(const struct MAC_HW_REPORT_T *tx, enum RANGING_STAGE_T stage, uint8_t slot_idx) { struct UWB_PKT_TX_DONE_IND_T *ind = WsfMsgAlloc(sizeof(struct UWB_PKT_TX_DONE_IND_T)); if (ind != NULL) { ind->hdr.event = UWB_PKT_TX_DONE_MSG; ind->ranging_stage = (uint8_t)stage; ind->slot_idx = slot_idx; ind->status = tx->err_code; ind->tx_len = tx->pkt_len; // Send the message WsfMsgSend(uwb_audio_cb.handle_id, ind); } else { LOG_WARNING(TRACE_MODULE_UWB, "memory is not enough for UWB_PKT_TX_DONE_IND_T\r\n"); } } static uint16_t uwb_audio_rx_done_ind(const struct MAC_HW_REPORT_T *rx, enum RANGING_STAGE_T stage, uint8_t slot_idx) { // send an indication to application const uint16_t rx_len = (uwb_app_config.session_param.device_type == DEV_TYPE_CONTROLLER) ? rx->pkt_len : UWB_AUDIO_DATA_OFFSET; struct UWB_PKT_RX_DONE_IND_T *ind = WsfMsgAlloc(sizeof(struct UWB_PKT_RX_DONE_IND_T) + rx_len); if (ind != NULL) { ind->hdr.event = UWB_PKT_RX_DONE_MSG; ind->ranging_stage = (uint8_t)stage; ind->slot_idx = slot_idx; ind->status = rx->err_code; ind->rx_len = rx->pkt_len; if (rx->err_code == UWB_RX_OK) { if (rx_len) { memcpy(ind->rx_data, rx->pkt_data, rx_len); } else { // SPI transmit } } // Send the message WsfMsgSend(uwb_audio_cb.handle_id, ind); return ind->status; } else { LOG_WARNING(TRACE_MODULE_UWB, "memory is not enough for UWB_PKT_RX_DONE_IND_T\r\n"); return 0xFFFF; } } static void uwb_audio_audio_pkt_construct(uint16_t mac_addr, UWB_AUDIO_SDU_T *sdu) { uint8_t *input = uwb_audio_tx_msg_buf[uwb_app_config.session_param.responder_slot_idx][sdu->slot_idx]; uint16_t input_len = 0; /* Frame Type : 0 - 2 Security Enable : 3 Frame Pending : 4 AR : 5 PAND ID Compression : 6 Reserved : 7 Sequence Number Suppression : 8 IE Present : 9 Destination Addressing Mode : 10 - 11 Frame Version : 12 - 13 Source Addressing Mode : 14 - 15 */ uint16_t frame_control = (2 << 12) | (2 << 10) | (1 << 8) | (1 << 6) | (1 << 0); input[input_len++] = frame_control & 0xff; input[input_len++] = (frame_control >> 8) & 0xff; input[input_len++] = mac_addr & 0xff; input[input_len++] = (mac_addr >> 8) & 0xff; // Payload input[input_len++] = sdu->slot_idx; input[input_len++] = sdu->len & 0xFF; input[input_len++] = (sdu->len >> 8) & 0xFF; // Audio data is filled by uwb_audio_buf_update() input_len += sdu->len; uwb_audio_tx_msg_len[uwb_app_config.session_param.responder_slot_idx][sdu->slot_idx] = input_len; } static void uwb_audio_ack_pkt_construct(uint16_t mac_addr, uint8_t slot_idx) { uint8_t *input = uwb_audio_tx_msg_buf[uwb_app_config.session_param.responder_slot_idx][0]; uint16_t input_len = 0; /* Frame Type : 0 - 2 Security Enable : 3 Frame Pending : 4 AR : 5 PAND ID Compression : 6 Reserved : 7 Sequence Number Suppression : 8 IE Present : 9 Destination Addressing Mode : 10 - 11 Frame Version : 12 - 13 Source Addressing Mode : 14 - 15 */ uint16_t frame_control = (2 << 12) | (2 << 10) | (1 << 8) | (1 << 6) | (1 << 0); input[input_len++] = frame_control & 0xff; input[input_len++] = (frame_control >> 8) & 0xff; input[input_len++] = mac_addr & 0xff; input[input_len++] = (mac_addr >> 8) & 0xff; // Payload input[input_len++] = slot_idx; // RX packets status input[input_len++] = uwb_audio_rx_flag[uwb_app_config.session_param.responder_slot_idx]; uwb_audio_tx_msg_len[uwb_app_config.session_param.responder_slot_idx][0] = input_len; } static uint8_t uwb_audio_audio_pkt_process(uint8_t *pkt_data, uint16_t pkt_len) { uint8_t slot_idx = pkt_data[UWB_AUDIO_SLOT_IDX_OFFSET]; // LOG_INFO(TRACE_MODULE_FIRA, "slot index %d\r\n", slot_idx); uwb_audio_buf[uwb_app_config.session_param.responder_slot_idx][slot_idx].len = READ_SHORT(&pkt_data[UWB_AUDIO_DATA_LEN_OFFSET]); uwb_audio_rx_flag[uwb_app_config.session_param.responder_slot_idx] |= (1 << slot_idx); return slot_idx; } static uint8_t uwb_audio_ack_pkt_process(uint8_t *pkt_data, uint16_t pkt_len) { uint8_t slot_idx = pkt_data[UWB_AUDIO_SLOT_IDX_OFFSET]; // LOG_INFO(TRACE_MODULE_FIRA, "slot index %d\r\n", slot_idx); // ACK uwb_audio_rx_flag[uwb_app_config.session_param.responder_slot_idx] = pkt_data[5]; // LOG_INFO(TRACE_MODULE_FIRA, "%d\r\n", pkt_data[5]); return slot_idx; } static uint32_t uwb_audio_target_time(uint8_t slot) { uint32_t round_idx = slot / (UWB_AUDIO_TX_SLOT_NUM + UWB_AUDIO_ACK_SLOT_NUM); uint8_t slot_offset = slot % (UWB_AUDIO_TX_SLOT_NUM + UWB_AUDIO_ACK_SLOT_NUM); uint32_t target = ranging_env.anchor_point + (ranging_env.round_duration * round_idx) + (slot_offset * ranging_env.slot_interval); return target; } #if defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050) #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wunreachable-code-break" #pragma clang diagnostic ignored "-Wswitch-enum" #endif void uwb_audio_phy_timer_callback(void *dev, uint32_t time) { // LOG_INFO(TRACE_MODULE_FIRA, "FSM %02x slot %d\r\n", uwb_app_config.ranging_stage, ranging_env.slot_idx); // board_led_on(BOARD_LED_1); uint32_t target_time; uint8_t responder_idx = uwb_app_config.session_param.responder_slot_idx; if (ranging_env.enable) { if (uwb_app_config.session_param.device_role == DEV_ROLE_INITIATOR) { switch (uwb_app_config.ranging_stage) { case RANGING_DM_TX: { if (ranging_env.repeat) { for (uint8_t i = 0; i < UWB_AUDIO_TX_SLOT_NUM; i++) { uwb_audio_buf[responder_idx][i].ready = 1; uwb_audio_tx_flag[responder_idx] |= (1 << i); } } else { ranging_env.anchor_point += ranging_env.ranging_period; ranging_env.phy_sts_index += uwb_app_config.session_param.slots_per_round; uwb_app_config.session_param.responder_slot_idx = !uwb_app_config.session_param.responder_slot_idx; responder_idx = uwb_app_config.session_param.responder_slot_idx; uwb_audio_buf_update(responder_idx); for (uint8_t i = 0; i < UWB_AUDIO_TX_SLOT_NUM; i++) { if (uwb_audio_buf[responder_idx][i].ready) { uwb_audio_audio_pkt_construct(0xffff, &uwb_audio_buf[responder_idx][i]); uwb_audio_tx_flag[responder_idx] |= (1 << i); } else { uwb_audio_tx_flag[responder_idx] &= ~(1 << i); } } } // send DM if (uwb_audio_tx_flag[responder_idx] == 0) { uwb_audio_fsm(NULL); goto _exit; } else { power_on_radio(1, 0); for (uint8_t i = 0; i < UWB_AUDIO_TX_SLOT_NUM; i++) { if (uwb_audio_tx_flag[responder_idx] & (1 << i)) { target_time = uwb_audio_target_time(ranging_env.slot_idx + i); uint8_t *tx = uwb_audio_tx_msg_buf[responder_idx][i]; // board_led_on(BOARD_LED_1); // mac_tx(EVT_MODE_MAC_ASAP_PHY_FIX, target_time, 0, tx, uwb_audio_tx_msg_len[responder_idx][i]); uint8_t em_idx = responder_idx * UWB_AUDIO_TX_SLOT_NUM + i; mac_repeat_tx(EVT_MODE_MAC_ASAP_PHY_FIX, target_time, em_idx, tx, uwb_audio_tx_msg_len[responder_idx][i]); // board_led_off(BOARD_LED_1); } } } } break; case RANGING_DM_RX: { // receive DM target_time = uwb_audio_target_time(ranging_env.slot_idx) - UWB_RX_OPEN_IN_ADVANCE + UWB_RX_GUARD_TIME; power_on_radio(0, 1); mac_rx(EVT_MODE_MAC_ASAP_PHY_FIX, target_time, UWB_ACK_RX_WINDOW); } break; default: ASSERT(0, "UNEXPECTED STAGE\r\n"); break; } } else if (uwb_app_config.session_param.device_role == DEV_ROLE_RESPONDER) { switch (uwb_app_config.ranging_stage) { case RANGING_SYNC: { // mac_update_key_table(KEY_IDX_0, &fira_key.devPayKey.ukey.keyWord[0]); power_on_radio(0, 1); mac_rx(EVT_MODE_MAC_PHY_ASAP, 0, ranging_env.ranging_period); power_mode_request(POWER_UNIT_APP, POWER_MODE_SLEEP); } break; case RANGING_DM_RX: { // mac_update_key_table(KEY_IDX_0, &fira_key.devPayKey.ukey.keyWord[0]); if (ranging_env.repeat) { } else { ranging_env.anchor_point += ranging_env.ranging_period; uwb_app_config.session_param.responder_slot_idx = !uwb_app_config.session_param.responder_slot_idx; responder_idx = uwb_app_config.session_param.responder_slot_idx; } uwb_audio_rx_flag[responder_idx] = 0; // receive DM power_on_radio(0, 1); for (uint8_t i = 0; i < UWB_AUDIO_TX_SLOT_NUM; i++) { target_time = uwb_audio_target_time(ranging_env.slot_idx + i) - UWB_RX_OPEN_IN_ADVANCE; // mac_rx(EVT_MODE_MAC_ASAP_PHY_FIX, target_time, UWB_RX_WINDOW); uint8_t em_idx = responder_idx * UWB_AUDIO_TX_SLOT_NUM + i; mac_repeat_rx(EVT_MODE_MAC_ASAP_PHY_FIX, target_time, em_idx, UWB_RX_WINDOW); } } break; case RANGING_DM_TX: { // send DM uint16_t mac_addr = uwbs_peer_short_addr_get(); power_on_radio(1, 0); uwb_audio_ack_pkt_construct(mac_addr, ranging_env.slot_idx); target_time = uwb_audio_target_time(ranging_env.slot_idx) + UWB_RX_GUARD_TIME; mac_tx(EVT_MODE_MAC_ASAP_PHY_FIX, target_time, 0, uwb_audio_tx_msg_buf[responder_idx][0], uwb_audio_tx_msg_len[responder_idx][0]); } break; default: ASSERT(0, "UNEXPECTED STAGE\r\n"); break; } } mac_start(); } else { power_mode_clear(POWER_UNIT_APP); } _exit: // board_led_off(BOARD_LED_1); return; } enum RANGING_STAGE_T uwb_audio_fsm(const struct MAC_HW_REPORT_T *ind) { // LOG_INFO(TRACE_MODULE_FIRA, "FSM %02x slot %d\r\n", uwb_app_config.ranging_stage, ranging_env.slot_idx); // board_led_on(BOARD_LED_2); uint16_t status = 0; uint8_t responder_idx = uwb_app_config.session_param.responder_slot_idx; if (ranging_env.enable) { ranging_env.count++; uint32_t target_time = ranging_env.anchor_point; if (uwb_app_config.session_param.device_role == DEV_ROLE_INITIATOR) { switch (uwb_app_config.ranging_stage) { case RANGING_DM_TX: { if (uwb_audio_tx_flag[responder_idx]) { uint8_t offset = search_byte_right_one(uwb_audio_tx_flag[responder_idx]) - 1; // process tx-DM packet uwb_audio_tx_done_ind(ind, uwb_app_config.ranging_stage, ranging_env.slot_idx + offset); uwb_audio_buf[responder_idx][offset].ready = 0; uwb_audio_tx_flag[responder_idx] &= ~(1 << offset); if (uwb_audio_tx_flag[responder_idx] == 0) { #if UWB_UDP_MODE_EN ranging_env.slot_idx = 0; target_time += ranging_env.ranging_period; #else // TX done - add a half slot as guard time for TX/RX switching ranging_env.slot_idx += UWB_AUDIO_TX_SLOT_NUM; uwb_app_config.ranging_stage = RANGING_DM_RX; target_time = uwb_audio_target_time(ranging_env.slot_idx) + UWB_RX_GUARD_TIME; #endif } } else { // skip RX ranging_env.slot_idx = 0; target_time += ranging_env.ranging_period; } } break; case RANGING_DM_RX: { ranging_env.repeat = 0; // process rx-DM packet status = uwb_audio_rx_done_ind(ind, uwb_app_config.ranging_stage, ranging_env.slot_idx); if ((status == UWB_RX_OK) && (uwb_audio_ack_pkt_process(ind->pkt_data, ind->pkt_len) == ranging_env.slot_idx)) { if (uwb_audio_rx_flag[responder_idx] != ((1 << UWB_AUDIO_TX_SLOT_NUM) - 1)) { ranging_env.repeat = 1; } } ranging_env.slot_idx++; if (ranging_env.repeat) { if (ranging_env.slot_idx + uwb_app_config.session_param.slots_per_round >= ranging_env.slots_per_block) { ranging_env.slot_idx = 0; target_time += ranging_env.ranging_period; ranging_env.repeat = 0; } else { target_time = uwb_audio_target_time(ranging_env.slot_idx); } } else { ranging_env.slot_idx = 0; target_time += ranging_env.ranging_period; ranging_env.repeat = 0; } uwb_app_config.ranging_stage = RANGING_DM_TX; } break; default: ASSERT(0, "UNEXPECTED STAGE\r\n"); break; } } else if (uwb_app_config.session_param.device_role == DEV_ROLE_RESPONDER) { switch (uwb_app_config.ranging_stage) { case RANGING_SYNC: { // process rx-DM packet status = uwb_audio_rx_done_ind(ind, uwb_app_config.ranging_stage, ranging_env.slot_idx); if ((status == UWB_RX_OK) && (uwb_audio_audio_pkt_process(ind->pkt_data, ind->pkt_len) == ranging_env.slot_idx)) { // update anchor point ranging_env.anchor_point = ind->timestamp - phy_shr_duration(); ranging_env.lost_cnt = 0; ranging_env.slot_idx = 0; target_time = ranging_env.anchor_point + ranging_env.ranging_period; uwb_app_config.ranging_stage = RANGING_DM_RX; } else { // receive DM again mac_rx(EVT_MODE_MAC_PHY_ASAP, 0, ranging_env.ranging_period); mac_start(); return uwb_app_config.ranging_stage; } } break; case RANGING_DM_RX: { // process rx-DM packet status = uwb_audio_rx_done_ind(ind, uwb_app_config.ranging_stage, ranging_env.slot_idx); if ((status == UWB_RX_OK) && (uwb_audio_audio_pkt_process(ind->pkt_data, ind->pkt_len) == (ranging_env.slot_idx % (UWB_AUDIO_TX_SLOT_NUM + UWB_AUDIO_ACK_SLOT_NUM)))) { // update anchor point if (ranging_env.slot_idx == 0) { ranging_env.anchor_point = ind->timestamp - phy_shr_duration(); target_time = ranging_env.anchor_point; } ranging_env.lost_cnt = 0; } else { ranging_env.lost_cnt++; } ranging_env.slot_idx++; if ((ranging_env.slot_idx % (UWB_AUDIO_TX_SLOT_NUM + UWB_AUDIO_ACK_SLOT_NUM)) == UWB_AUDIO_TX_SLOT_NUM) { if (ranging_env.lost_cnt > 10) { ranging_env.repeat = 0; ranging_env.slot_idx = 0; uwb_app_config.ranging_stage = RANGING_SYNC; target_time = ranging_env.anchor_point + ranging_env.ranging_period; } else { #if UWB_UDP_MODE_EN ranging_env.slot_idx = 0; target_time = ranging_env.anchor_point + ranging_env.ranging_period; #else // Add a half slot as guard time for RX/TX switching target_time = uwb_audio_target_time(ranging_env.slot_idx) + UWB_RX_GUARD_TIME; uwb_app_config.ranging_stage = RANGING_DM_TX; #endif } } } break; case RANGING_DM_TX: { // process tx-DM packet uwb_audio_tx_done_ind(ind, uwb_app_config.ranging_stage, ranging_env.slot_idx); if (uwb_audio_rx_flag[responder_idx] == ((1 << UWB_AUDIO_TX_SLOT_NUM) - 1)) { ranging_env.repeat = 0; } else { ranging_env.repeat = 1; } ranging_env.slot_idx++; if (ranging_env.repeat) { if (ranging_env.slot_idx + uwb_app_config.session_param.slots_per_round >= ranging_env.slots_per_block) { ranging_env.slot_idx = 0; target_time += ranging_env.ranging_period; ranging_env.repeat = 0; } else { target_time = uwb_audio_target_time(ranging_env.slot_idx); } } else { ranging_env.slot_idx = 0; target_time += ranging_env.ranging_period; } uwb_app_config.ranging_stage = RANGING_DM_RX; } break; default: ASSERT(0, "UNEXPECTED STAGE\r\n"); break; } } if (target_time != ranging_env.anchor_point) { power_off_radio(); if ((ranging_env.slot_idx % (UWB_AUDIO_TX_SLOT_NUM + UWB_AUDIO_ACK_SLOT_NUM)) == 0) { // for 3 packets construction phy_timer_target_set(target_time - UWB_PERIOD_PREFETCH_TIME, uwb_audio_phy_timer_callback); } else { // for 1 packet construction phy_timer_target_set(target_time - UWB_EVT_PREFETCH_TIME, uwb_audio_phy_timer_callback); } power_mode_request(POWER_UNIT_APP, POWER_MODE_POWER_DOWN); } } else { power_off_radio(); power_mode_clear(POWER_UNIT_APP); } // board_led_off(BOARD_LED_2); return uwb_app_config.ranging_stage; } #if defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050) #pragma clang diagnostic pop #endif static void uwb_audio_tx_process(struct MAC_HW_REPORT_T *tx_report) { uwb_audio_fsm(tx_report); } static void uwb_audio_rx_process(struct MAC_HW_REPORT_T *rx_report) { uwb_audio_fsm(rx_report); }