/* * 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_clock.h" #include "uwb_api.h" #include "aoa.h" #include "lib_aoa.h" #if PDOA_3D_EN #include "lib_pdoa_3d.h" #endif #include "board.h" #if PDOA_3D_EN #define PDOA_3D_SUPPORT_NUM 100 #define PDOA_3D_TIMEOUT_MS 2000 static struct PDOA_3D_MAC_ADDR_T mac_addr_cache[PDOA_3D_SUPPORT_NUM]; static struct PDOA_3D_PDOA_DATA_T pdoa_data_cache[PDOA_3D_SUPPORT_NUM]; #endif struct AOA_ENV_T aoa_env; static struct AOA_CB_T aoa_cb; static struct UWB_OP_T op = { .session_configure = aoa_configure, .session_start = aoa_start, .session_stop = NULL, .session_local_addr_set = NULL, .session_peer_addr_set = NULL, .session_responder_addr_add = NULL, .session_responder_list_clr = NULL, .session_set_ccc_ursk = NULL, }; static void aoa_tx_process(struct MAC_HW_REPORT_T *tx_report); static void aoa_rx_process(struct MAC_HW_REPORT_T *rx_report); void app_session_init(void); //------------------------------------------------------------------------------ int aoa_init(uint8_t handle_id) { /* store handler ID */ aoa_cb.handle_id = handle_id; /* init rx queue */ WSF_QUEUE_INIT(&aoa_cb.msg_queue); LOG_INFO(TRACE_MODULE_APP, "AoA lib version: %s\r\n", MK8000_get_aoalib_version()); return 0; } int aoa_deinit(void) { return 0; } // This function will be called by the uwbapi_session_init() void app_session_init(void) { // register process handler for MAC TX done and RX done mac_register_process_handler(aoa_tx_process, aoa_rx_process); uwbs_handler_init(&op); } void aoa_configure(void) { aoa_env.stage = AOA_IDLE; aoa_env.ranging_period = MS_TO_PHY_TIMER_COUNT(uwb_app_config.session_param.ranging_interval); aoa_env.lost_cnt = 0; uwbs_configure(PHY_TX | PHY_RX, uwb_app_config.session_param.tx_power_level); if (uwb_app_config.session_param.device_role == DEV_ROLE_INITIATOR) { phy_rx_sts_switch_mode_set(uwb_app_config.ppdu_params.sts_pkt_cfg, STS_NEVER_SWITCH, 0, 0); } else { phy_rx_sts_switch_mode_set(uwb_app_config.ppdu_params.sts_pkt_cfg, STS_SWITCH_EVERY_4SYM, 0, 0); } #if (ANT_PATTERN == ANT_PATTERN_SQUARE) struct AOA_ANGLE_SPAN_T aoa_span; #if AOA_3D_EN aoa_span.Ndim = 2; aoa_span.el_low = 0; aoa_span.el_high = 90; aoa_span.el_step = 5; aoa_span.az_low = 0; aoa_span.az_high = 359; aoa_span.az_step = 3; #else aoa_span.Ndim = 2; aoa_span.el_low = 90; aoa_span.el_high = 90; aoa_span.el_step = 5; aoa_span.az_low = 0; aoa_span.az_high = 359; aoa_span.az_step = 1; #endif aoa_angle_search_span_set(&aoa_span); #endif #if AOA_EN aoa_aux_info_set(AOA_AUX_ANT_IQ_RSSI_PDOA_AOA_FOM); aoa_steering_vector_set((const float *)((uint32_t)((uwb_app_config.ppdu_params.ch_num == 9) ? svec_ch9_ptr : svec_ch5_ptr) | SRAM_BASE)); #else aoa_aux_info_set(AOA_AUX_ANT_IQ_RSSI); #endif aoa_param_config(); #if PDOA_3D_EN pdoa_3d_param_config(ANT_PATTERN, ANT_LAYOUT, PDOA_3D_AMBIGUITY_LEVEL_HIGH, mac_addr_cache, pdoa_data_cache, PDOA_3D_SUPPORT_NUM, PDOA_3D_TIMEOUT_MS); #endif #if FILTER_EN if (uwb_app_config.filter_en) { loc_post_filter_config(uwb_app_config.session_param.ranging_interval, 0, 1); } #endif } static void aoa_timer_callback(void *dev, uint32_t time) { aoa_env.anchor_point += aoa_env.ranging_period; aoa_env.sequence_num++; if (uwb_app_config.session_param.device_role == DEV_ROLE_INITIATOR) { // Power on radio power_on_radio(1, 0); // SP3 payload len = 0 mac_tx(EVT_MODE_MAC_ASAP_PHY_FIX, aoa_env.anchor_point, 0, NULL, 0); mac_start(); LOG_INFO(TRACE_MODULE_APP, "AoA Initiator SEQ NUM %u\r\n", aoa_env.sequence_num); } else { // Change Rx main antenna uint8_t main_ant = 3; phy_rx_sts_switch_mode_set(uwb_app_config.ppdu_params.sts_pkt_cfg, STS_SWITCH_EVERY_4SYM, 1, main_ant); aoa_param_update(main_ant); // Power on radio power_on_radio(0, 1); sts_lsp_store(); if (aoa_env.stage == AOA_SYNC) { mac_rx(EVT_MODE_MAC_PHY_ASAP, 0, aoa_env.ranging_period); } else { mac_rx(EVT_MODE_MAC_ASAP_PHY_FIX, aoa_env.anchor_point - UWB_RX_OPEN_IN_ADVANCE, UWB_RX_WINDOW); } mac_start(); LOG_INFO(TRACE_MODULE_APP, "AoA Responder SEQ NUM %u\r\n", aoa_env.sequence_num); } } void aoa_start(void) { aoa_env.anchor_point = phy_timer_count_get(); if (uwb_app_config.session_param.device_role == DEV_ROLE_INITIATOR) { aoa_env.stage = AOA_POLL; } else { aoa_env.stage = AOA_SYNC; } phy_timer_target_set(aoa_env.anchor_point + aoa_env.ranging_period - UWB_EVT_PREFETCH_TIME, aoa_timer_callback); aoa_env.sequence_num = 0; } void aoa_process(const struct MAC_HW_REPORT_T *ind) { if (uwb_app_config.session_param.device_role == DEV_ROLE_INITIATOR) { phy_timer_target_set(aoa_env.anchor_point + aoa_env.ranging_period - UWB_EVT_PREFETCH_TIME, aoa_timer_callback); } else { if (ind->err_code == UWB_RX_OK) { sts_lsp_store_stop(); // update anchor point aoa_env.anchor_point = ind->timestamp - phy_shr_duration(); aoa_env.stage = AOA_POLL; aoa_env.lost_cnt = 0; if (aoa_done_flag) { aoa_done_flag = 0; aoa_done(ind); } } else { if (aoa_env.stage == AOA_SYNC) { sts_lsp_store(); mac_rx(EVT_MODE_MAC_PHY_ASAP, 0, aoa_env.ranging_period); mac_start(); return; } else { aoa_env.lost_cnt++; if (aoa_env.lost_cnt > 3) { aoa_env.stage = AOA_SYNC; } } } phy_timer_target_set(aoa_env.anchor_point + aoa_env.ranging_period - UWB_EVT_PREFETCH_TIME, aoa_timer_callback); } power_off_radio(); } void aoa_done(const struct MAC_HW_REPORT_T *rx) { struct AOA_DONE_IND_T *ind; if ((ind = WsfMsgAlloc(sizeof(struct AOA_DONE_IND_T) + rx->pkt_len)) != NULL) { ind->hdr.event = AOA_DONE_MSG; ind->status = rx->err_code; ind->rssi = rx->rssi; ind->snr = rx->snr; if ((rx->pkt_len) && (rx->pkt_data != NULL)) { memcpy(ind->rx_data, rx->pkt_data, rx->pkt_len); } ind->rx_len = rx->pkt_len; // Send the message WsfMsgSend(aoa_cb.handle_id, ind); } } static void aoa_tx_process(struct MAC_HW_REPORT_T *tx_report) { aoa_process(tx_report); } static void aoa_rx_process(struct MAC_HW_REPORT_T *rx_report) { aoa_process(rx_report); }