/******************************************************************************* * @note Copyright (C) 2023 Shanghai Panchip Microelectronics Co., Ltd. All rights reserved. * * @file radio.c * @brief * * @history - V0.7, 2024-3 *******************************************************************************/ #include "pan3029_port.h" #include "pan3029.h" extern bool pan3029_irq_trigged_flag; /* * flag that indicate if a new packet is received. */ static int packet_received = RADIO_FLAG_IDLE; /* * flag that indicate if transmision is finished. */ static int packet_transmit = RADIO_FLAG_IDLE; struct RxDoneMsg RxDoneParams; uint32_t cad_tx_timeout_flag = MAC_EVT_TX_CAD_NONE; /** * @brief get receive flag * @param[in] * @return receive state */ uint32_t rf_get_recv_flag(void) { return packet_received; } /** * @brief set receive flag * @param[in] receive flag state to set * @return none */ void rf_set_recv_flag(int status) { packet_received = status; } /** * @brief get transmit flag * @param[in] * @return reansmit state */ uint32_t rf_get_transmit_flag(void) { return packet_transmit; } /** * @brief set transmit flag * @param[in] transmit flag state to set * @return none */ void rf_set_transmit_flag(int status) { packet_transmit = status; } /** * @brief do basic configuration to initialize * @param[in] * @return result */ uint32_t rf_init(void) { if(PAN3029_deepsleep_wakeup() != OK) { return FAIL; } if(PAN3029_ft_calibr() != OK) { return FAIL; } if(PAN3029_init() != OK) { return FAIL; } if(rf_set_agc(AGC_ON) != OK) { return FAIL; } rf_port.antenna_init(); return OK; } /** * @brief change PAN3029 mode from deep sleep to wakeup(STB3) * @param[in] * @return result */ uint32_t rf_deepsleep_wakeup(void) { if(PAN3029_deepsleep_wakeup() != OK) { return FAIL; } if(PAN3029_init() != OK) { return FAIL; } if(rf_set_agc(AGC_ON) != OK) { return FAIL; } rf_port.antenna_init(); return OK; } /** * @brief change PAN3029 mode from sleep to wakeup(STB3) * @param[in] * @return result */ uint32_t rf_sleep_wakeup(void) { if(PAN3029_sleep_wakeup() != OK) { return FAIL; } rf_port.antenna_init(); return OK; } /** * @brief change PAN3029 mode from standby3(STB3) to deep sleep, PAN3029 should set DCDC_OFF before enter deepsleep * @param[in] * @return result */ uint32_t rf_deepsleep(void) { rf_port.antenna_close(); return PAN3029_deepsleep(); } /** * @brief change PAN3029 mode from standby3(STB3) to deep sleep, PAN3029 should set DCDC_OFF before enter sleep * @param[in] * @return result */ uint32_t rf_sleep(void) { rf_port.antenna_close(); return PAN3029_sleep(); } /** * @brief calculate tx time * @param[in] tx len * @return tx time(us) */ uint32_t rf_get_tx_time(uint8_t size) { return PAN3029_calculate_tx_time(size); } /** * @brief set rf mode * @param[in] * PAN3029_MODE_DEEP_SLEEP / PAN3029_MODE_SLEEP * PAN3029_MODE_STB1 / PAN3029_MODE_STB2 * PAN3029_MODE_STB3 / PAN3029_MODE_TX / PAN3029_MODE_RX * @return result */ uint32_t rf_set_mode(uint8_t mode) { return PAN3029_set_mode(mode); } /** * @brief get rf mode * @param[in] * @return mode * PAN3029_MODE_DEEP_SLEEP / PAN3029_MODE_SLEEP * PAN3029_MODE_STB1 / PAN3029_MODE_STB2 * PAN3029_MODE_STB3 / PAN3029_MODE_TX / PAN3029_MODE_RX */ uint8_t rf_get_mode(void) { return PAN3029_get_mode(); } /** * @brief set rf Tx mode * @param[in] * PAN3029_TX_SINGLE/PAN3029_TX_CONTINOUS * @return result */ uint32_t rf_set_tx_mode(uint8_t mode) { return PAN3029_set_tx_mode(mode); } /** * @brief set rf Rx mode * @param[in] * PAN3029_RX_SINGLE/PAN3029_RX_SINGLE_TIMEOUT/PAN3029_RX_CONTINOUS * @return result */ uint32_t rf_set_rx_mode(uint8_t mode) { return PAN3029_set_rx_mode(mode); } /** * @brief set timeout for Rx. It is useful in PAN3029_RX_SINGLE_TIMEOUT mode * @param[in] rx single timeout time(in ms) * @return result */ uint32_t rf_set_rx_single_timeout(uint32_t timeout) { return PAN3029_set_timeout(timeout); } /** * @brief get snr value * @param[in] * @return snr */ float rf_get_snr(void) { return PAN3029_get_snr(); } /** * @brief get rssi value * @param[in] * @return rssi */ int8_t rf_get_rssi(void) { return PAN3029_get_rssi(); } /** * @brief current channel energy detection * @param[in] * @return rssi */ int8_t rf_get_channel_rssi(void) { return PAN3029_get_channel_rssi(); } /** * @brief get irq * @param[in] * @return irq */ uint8_t rf_get_irq(void) { return PAN3029_get_irq(); } /** * @brief clr irq * @param[in] * @return result */ uint8_t rf_clr_irq(void) { return PAN3029_clr_irq(); } /** * @brief set refresh * @param[in] * @return result */ uint32_t rf_set_refresh(void) { return PAN3029_refresh(); } /** * @brief set preamble * @param[in] preamble * @return result */ uint32_t rf_set_preamble(uint16_t pream) { return PAN3029_set_preamble(pream); } /** * @brief get preamble * @param[in] * @return preamble */ uint32_t rf_get_preamble(void) { return PAN3029_get_preamble(); } /** * @brief CAD function enable * @param[in] CAD_DETECT_THRESHOLD_0A / CAD_DETECT_THRESHOLD_10 / CAD_DETECT_THRESHOLD_15 / CAD_DETECT_THRESHOLD_20 CAD_DETECT_NUMBER_1 / CAD_DETECT_NUMBER_2 / CAD_DETECT_NUMBER_3 / * @return result */ uint32_t rf_set_cad(uint8_t threshold, uint8_t chirps) { return PAN3029_cad_en(threshold, chirps); } /** * @brief CAD function disable * @param[in] * @return result */ uint32_t rf_set_cad_off(void) { return PAN3029_cad_off(); } /** * @brief set rf syncword * @param[in] syncword * @return result */ uint32_t rf_set_syncword(uint8_t sync) { return PAN3029_set_syncword(sync); } /** * @brief read rf syncword * @param[in] * @return syncword */ uint8_t rf_get_syncword(void) { return PAN3029_get_syncword(); } /** * @brief RF IRQ server routine, it should be call at ISR of IRQ pin * @param[in] * @return result */ void rf_irq_handler(void) { PAN3029_irq_handler(); } /** * @brief set rf plhd mode on , rf will use early interruption * @param[in] PLHD start addr,Range:0..7f PLHD len PLHD_LEN8 / PLHD_LEN16 * @return result */ void rf_set_plhd_rx_on(uint8_t addr,uint8_t len) { PAN3029_set_early_irq(PLHD_IRQ_ON); PAN3029_set_plhd(addr, len); PAN3029_set_plhd_mask(PLHD_ON); } /** * @brief set rf plhd mode off * @param[in] * @return result */ void rf_set_plhd_rx_off(void) { PAN3029_set_early_irq(PLHD_IRQ_OFF); PAN3029_set_plhd_mask(PLHD_OFF); } /** * @brief get plhd len reg value * @param[in] * @return PLHD_LEN8 / PLHD_LEN16 */ uint8_t rf_get_plhd_len(void) { return PAN3029_get_plhd_len(); } /** * @brief receive a packet in non-block method, it will return 0 when no data got * @param[in] buffer provide for data to receive PLHD_LEN8 / PLHD_LEN16 * @return result */ uint32_t rf_plhd_receive(uint8_t *buf,uint8_t len) { return PAN3029_plhd_receive(buf, len); } /** * @brief set rf mapm mode on , rf will use mapm interruption * @param[in] * @return result */ void rf_set_mapm_on(void) { PAN3029_mapm_en(); PAN3029_set_mapm_mask(MAPM_ON); } /** * @brief set mapm mode off * @param[in] * @return result */ void rf_set_mapm_off(void) { PAN3029_mapm_dis(); PAN3029_set_mapm_mask(MAPM_OFF); } /** * @brief configure relevant parameters used in mapm mode * @param[in] set the number of fields(range in 0x01~0xe0) The unit code word of the Field counter represents several Fields The last group in the Field, its ADDR position function selection 0:ordinary address 1:Field counter register for configuring the number of groups in a Field 0 1group\1 2group\2 3group\3 4group set the number of Preambles in first groups> the number of Preambles in other groups the number of chirps before syncword after all fields have been sent * @return result */ void rf_set_mapm_para(stc_mapm_cfg_t *p_mapm_cfg) { PAN3029_set_mapm_field_num(p_mapm_cfg->fn); PAN3029_set_mapm_field_num_mux(p_mapm_cfg->fnm); PAN3029_set_mapm_group_fun_sel(p_mapm_cfg->gfs); PAN3029_set_mapm_group_num(p_mapm_cfg->gn); PAN3029_set_mapm_firgroup_preamble_num(p_mapm_cfg->pg1); PAN3029_set_mapm_group_preamble_num(p_mapm_cfg->pgn); PAN3029_set_mapm_neces_preamble_num(p_mapm_cfg->pn); } /** * @brief receive a packet in non-block method, it will return 0 when no data got * @param[in] buffer provide for data to receive * @return length, it will return 0 when no data got */ uint32_t rf_receive(uint8_t *buf) { return PAN3029_recv_packet(buf); } /** * @brief rf enter rx continous mode to receive packet * @param[in] * @return result */ uint32_t rf_enter_continous_rx(void) { if(PAN3029_set_mode(PAN3029_MODE_STB3) != OK) { return FAIL; } rf_port.set_rx(); if(PAN3029_set_rx_mode(PAN3029_RX_CONTINOUS) != OK) { return FAIL; } if(PAN3029_set_mode(PAN3029_MODE_RX) != OK) { return FAIL; } return OK; } /** * @brief rf enter rx single timeout mode to receive packet * @param[in] rx single timeout time(in ms) * @return result */ uint32_t rf_enter_single_timeout_rx(uint32_t timeout) { if(PAN3029_set_mode(PAN3029_MODE_STB3) != OK) { return FAIL; } rf_port.set_rx(); if(PAN3029_set_rx_mode(PAN3029_RX_SINGLE_TIMEOUT) != OK) { return FAIL; } if(PAN3029_set_timeout(timeout) != OK) { return FAIL; } if(PAN3029_set_mode(PAN3029_MODE_RX) != OK) { return FAIL; } return OK; } /** * @brief rf enter rx single mode to receive packet * @param[in] * @return result */ uint32_t rf_enter_single_rx(void) { if(PAN3029_set_mode(PAN3029_MODE_STB3) != OK) { return FAIL; } rf_port.set_rx(); if(PAN3029_set_rx_mode(PAN3029_RX_SINGLE) != OK) { return FAIL; } if(PAN3029_set_mode(PAN3029_MODE_RX) != OK) { return FAIL; } return OK; } /** * @brief rf enter single tx mode and send packet * @param[in] buffer contain data to send * @param[in] the length of data to send * @param[in] the packet tx time(us) * @return result */ uint32_t rf_single_tx_data(uint8_t *buf, uint8_t size, uint32_t *tx_time) { if(PAN3029_set_mode(PAN3029_MODE_STB3) != OK) { return FAIL; } if(PAN3029_set_ldo_pa_on() != OK) { return FAIL; } rf_port.set_tx(); if(PAN3029_set_tx_mode(PAN3029_TX_SINGLE) != OK) { return FAIL; } *tx_time = rf_get_tx_time(size); if(PAN3029_send_packet(buf, size) != OK) { return FAIL; } return OK; } /** * @brief rf enter continous tx mode to ready send packet * @param[in] * @return result */ uint32_t rf_enter_continous_tx(void) { if(PAN3029_set_mode(PAN3029_MODE_STB3) != OK) { return FAIL; } if(PAN3029_set_tx_mode(PAN3029_TX_CONTINOUS) != OK) { return FAIL; } return OK; } /** * @brief rf continous mode send packet * @param[in] buffer contain data to send * @param[in] the length of data to send * @return result */ uint32_t rf_continous_tx_send_data(uint8_t *buf, uint8_t size) { if(PAN3029_set_ldo_pa_on() != OK) { return FAIL; } rf_port.set_tx(); if(PAN3029_send_packet(buf, size) != OK) { return FAIL; } return OK; } /** * @brief enable AGC function * @param[in] * AGC_OFF/AGC_ON * @return result */ uint32_t rf_set_agc(uint32_t state) { if(PAN3029_agc_enable(state) != OK) { return FAIL; } if(PAN3029_agc_config() != OK) { return FAIL; } return OK; } /** * @brief set rf para * @param[in] set type, rf_para_type_t para_type * @param[in] set value * @return result */ uint32_t rf_set_para(rf_para_type_t para_type, uint32_t para_val) { PAN3029_set_mode(PAN3029_MODE_STB3); switch(para_type) { case RF_PARA_TYPE_FREQ: PAN3029_set_freq(para_val); rf_set_refresh(); break; case RF_PARA_TYPE_CR: PAN3029_set_code_rate(para_val); rf_set_refresh(); break; case RF_PARA_TYPE_BW: PAN3029_set_bw(para_val); rf_set_refresh(); break; case RF_PARA_TYPE_SF: PAN3029_set_sf(para_val); rf_set_refresh(); break; case RF_PARA_TYPE_TXPOWER: PAN3029_set_tx_power(para_val); rf_set_refresh(); break; case RF_PARA_TYPE_CRC: PAN3029_set_crc(para_val); rf_set_refresh(); break; default: break; } return OK; } /** * @brief get rf para * @param[in] get typ, rf_para_type_t para_type * @param[in] get value * @return result */ uint32_t rf_get_para(rf_para_type_t para_type, uint32_t *para_val) { PAN3029_set_mode(PAN3029_MODE_STB3); switch(para_type) { case RF_PARA_TYPE_FREQ: *para_val = PAN3029_read_freq(); return OK; case RF_PARA_TYPE_CR: *para_val = PAN3029_get_code_rate(); return OK; case RF_PARA_TYPE_BW: *para_val = PAN3029_get_bw(); return OK; case RF_PARA_TYPE_SF: *para_val = PAN3029_get_sf(); return OK; case RF_PARA_TYPE_TXPOWER: *para_val = PAN3029_get_tx_power(); return OK; case RF_PARA_TYPE_CRC: *para_val = PAN3029_get_crc(); return OK; default: return FAIL; } } /** * @brief set rf default para * @param[in] * @return result */ void rf_set_default_para(void) { PAN3029_set_mode(PAN3029_MODE_STB3); rf_set_para(RF_PARA_TYPE_FREQ, DEFAULT_FREQ); rf_set_para(RF_PARA_TYPE_CR, DEFAULT_CR); rf_set_para(RF_PARA_TYPE_BW, DEFAULT_BW); rf_set_para(RF_PARA_TYPE_SF, DEFAULT_SF); rf_set_para(RF_PARA_TYPE_CRC, CRC_ON); rf_set_para(RF_PARA_TYPE_TXPOWER, DEFAULT_PWR); } /** * @brief set dcdc mode, The default configuration is DCDC_OFF, PAN3029 should set DCDC_OFF before enter sleep/deepsleep * @param[in] dcdc switch * DCDC_ON / DCDC_OFF * @return result */ uint32_t rf_set_dcdc_mode(uint32_t dcdc_val) { return PAN3029_set_dcdc_mode(dcdc_val); } /** * @brief set LDR mode * @param[in] LDR switch * LDR_ON / LDR_OFF * @return result */ uint32_t rf_set_ldr(uint32_t mode) { return PAN3029_set_ldr(mode); } /** * @brief get LDR mode * @param[in] * @return result */ uint32_t rf_get_ldr(void) { return PAN3029_get_ldr(); } /** * @brief set preamble by Spreading Factor,It is useful in all_sf_search mode * @param[in] Spreading Factor * @return result */ uint32_t rf_set_all_sf_preamble(uint32_t sf) { return PAN3029_set_all_sf_preamble(sf); } /** * @brief open all sf auto-search mode * @param[in] * @return result */ uint32_t rf_set_all_sf_search(void) { return PAN3029_set_all_sf_search(); } /** * @brief close all sf auto-search mode * @param[in] * @return result */ uint32_t rf_set_all_sf_search_off(void) { return PAN3029_set_all_sf_search_off(); } /** * @brief set mode * @param[in] MODEM_MODE_NORMAL/MODEM_MODE_MULTI_SECTOR * @return result */ uint32_t rf_set_modem_mode(uint8_t mode) { return PAN3029_set_modem_mode(mode); } /** * @brief RF IRQ server routine, it should be call at ISR of IRQ pin * @param[in] * @return result */ void rf_irq_process(void) { if(pan3029_irq_trigged_flag == true) { pan3029_irq_trigged_flag = false; uint8_t irq = rf_get_irq(); if(irq & REG_IRQ_RX_PLHD_DONE) { RxDoneParams.PlhdSize = rf_get_plhd_len(); rf_set_recv_flag(RADIO_FLAG_PLHDRXDONE); RxDoneParams.PlhdSize = rf_plhd_receive(RxDoneParams.PlhdPayload, RxDoneParams.PlhdSize); } if(irq & REG_IRQ_MAPM_DONE) { uint8_t addr_val = PAN3029_read_spec_page_reg(PAGE0_SEL, 0x6e); RxDoneParams.mpam_recv_buf[RxDoneParams.mpam_recv_index++] = addr_val; rf_set_recv_flag(RADIO_FLAG_MAPM); } if(irq & REG_IRQ_RX_DONE) { RxDoneParams.Snr = rf_get_snr(); RxDoneParams.Rssi = rf_get_rssi(); rf_set_recv_flag(RADIO_FLAG_RXDONE); RxDoneParams.Size = rf_receive(RxDoneParams.Payload); } if(irq & REG_IRQ_CRC_ERR) { PAN3029_read_fifo(REG_FIFO_ACC_ADDR, RxDoneParams.TestModePayload, 10); rf_set_recv_flag(RADIO_FLAG_RXERR); } if(irq & REG_IRQ_RX_TIMEOUT) { rf_set_refresh(); rf_set_recv_flag(RADIO_FLAG_RXTIMEOUT); } if(irq & REG_IRQ_TX_DONE) { PAN3029_set_ldo_pa_off(); rf_set_transmit_flag(RADIO_FLAG_TXDONE); } rf_clr_irq(); } } /** * @brief get one chirp time * @param[in] , * @return