/** * Function initializing the Timestamp IRQ to get synchronized * as required for ranging. */ void rtb_tstamp_irq_init(void) { pal_trx_irq_dis(); pal_trx_reg_read(RG_IRQ_STATUS); pal_trx_bit_write(SR_ARET_TX_TS_EN, 0x01); pal_trx_bit_write(SR_IRQ_2_EXT_EN, 0x01); //Enable Timestamping over DIG2 on the at86rf233 PORTC.INTFLAGS = PORT_INT1IF_bm; TCC1_CTRLB &= ~TC1_CCAEN_bm; TIMER_SRC_DURING_TRX_AWAKE(); PORTC.INT1MASK = PIN1_bm; //DIG2 over PortC 1 /* Reset register, until time out is triggered is 65535 ms */ TCC1_CNT = 0; PORTC.PIN1CTRL = PORT_ISC1_bm; TCC1_INTFLAGS = TC1_CCAIF_bm; TCC1_INTCTRLB = TC_CCAINTLVL_HI_gc; TCC1_CTRLB |= TC1_CCAEN_bm; }
void tal_tx_beacon(frame_info_t *tx_frame) { tal_trx_status_t trx_status; /* Set pointer to actual mpdu to be downloaded to the transceiver. */ uint8_t *tal_beacon_to_tx = tx_frame->mpdu; /* Avoid that the beacon is transmitted while other transmision is * on-going. */ if (tal_state == TAL_TX_AUTO) { Assert( "trying to transmit beacon while ongoing transmission" == 0); return; } /* Send the pre-created beacon frame to the transceiver. */ do { trx_status = set_trx_state(CMD_PLL_ON); #if (_DEBUG_ > 1) if (trx_status != PLL_ON) { Assert("PLL_ON failed for beacon transmission" == 0); } #endif } while (trx_status != PLL_ON); /* \TODO wait for talbeaconTxTime */ pal_trx_irq_dis(); /* Toggle the SLP_TR pin triggering transmission. */ TRX_SLP_TR_HIGH(); PAL_WAIT_65_NS(); TRX_SLP_TR_LOW(); /* * Send the frame to the transceiver. * Note: The PhyHeader is the first byte of the frame to * be sent to the transceiver and this contains the frame * length. * The actual length of the frame to be downloaded * (parameter two of trx_frame_write) * is * 1 octet frame length octet * + n octets frame (i.e. value of frame_tx[0]) * + 1 extra octet (see datasheet) * - 2 octets FCS */ trx_frame_write(tal_beacon_to_tx, tal_beacon_to_tx[0]); tal_beacon_transmission = true; #ifndef NON_BLOCKING_SPI pal_trx_irq_en(); #endif #ifdef TX_OCTET_COUNTER tal_tx_octet_cnt += PHY_OVERHEAD + LENGTH_FIELD_LEN + tal_beacon_to_tx[0]; #endif }
/* * \brief Perform a single ED measurement * * \return ed_value Result of the measurement * If the build switch TRX_REG_RAW_VALUE is defined, the transceiver's * register value is returned. */ uint8_t tfa_ed_sample(void) { uint8_t ed_value; tal_trx_status_t trx_status; /* Make sure that receiver is switched on. */ do { trx_status = set_trx_state(CMD_RX_ON); } while (trx_status != RX_ON); /* * Disable the transceiver interrupts to prevent frame reception * while performing ED scan. */ pal_trx_irq_dis(); /* * Initiate ED operation by writing any value into transceiver register * PHY_ED_LEVEL. */ pal_trx_reg_write(RG_PHY_ED_LEVEL, 0x00); /* * Start timer for reading ED value from the transceiver after * 140 microseconds. */ pal_timer_delay(TAL_CONVERT_SYMBOLS_TO_US(ED_SAMPLE_DURATION_SYM + 1)); /* Read the ED Value. */ ed_value = pal_trx_reg_read(RG_PHY_ED_LEVEL); /* Clear IRQ register */ pal_trx_reg_read(RG_IRQ_STATUS); /* Enable reception agian */ pal_trx_irq_flag_clr(); pal_trx_irq_en(); /* Switch receiver off again */ set_trx_state(CMD_TRX_OFF); #ifndef TRX_REG_RAW_VALUE /* * Scale ED result. * Clip values to 0xFF if > -35dBm */ if (ed_value > CLIP_VALUE_REG) { ed_value = 0xFF; } else { ed_value = (uint8_t)(((uint16_t)ed_value * 0xFF) / CLIP_VALUE_REG); } #endif return ed_value; }
/* * \brief Starts ED Scan * * This function starts an ED Scan for the scan duration specified by the * MAC layer. * * \param scan_duration Specifies the ED scan duration in symbols * * \return MAC_SUCCESS - ED scan duration timer started successfully * TAL_BUSY - TAL is busy servicing the previous request from MAC * TAL_TRX_ASLEEP - Transceiver is currently sleeping * FAILURE otherwise */ retval_t tal_ed_start(uint8_t scan_duration) { /* * Check if the TAL is in idle state. Only in idle state it can * accept and ED request from the MAC. */ if (TAL_IDLE != tal_state) { if (tal_trx_status == TRX_SLEEP) { return TAL_TRX_ASLEEP; } else { Assert("TAL is TAL_BUSY" == 0); return TAL_BUSY; } } /* * Disable the transceiver interrupts to prevent frame reception * while performing ED scan. */ pal_trx_irq_dis(); /* Disable transceiver main interrupt. */ set_trx_state(CMD_FORCE_PLL_ON); pal_trx_reg_read(RG_IRQ_STATUS); /* Clear existing interrupts */ pal_trx_bit_write(SR_RX_PDT_DIS, RX_DISABLE); pal_trx_irq_init((FUNC_PTR)trx_ed_irq_handler_cb); pal_trx_bit_write(SR_IRQ_MASK, TRX_IRQ_CCA_ED_READY); /* enable interrupt */ pal_trx_irq_en(); /* Enable main transceiver interrupt. */ /* Make sure that receiver is switched on. */ if (set_trx_state(CMD_RX_ON) != RX_ON) { /* Restore previous configuration */ pal_trx_bit_write(SR_RX_PDT_DIS, RX_ENABLE); pal_trx_irq_init((FUNC_PTR)trx_irq_handler_cb); pal_trx_reg_write(RG_IRQ_MASK, TRX_IRQ_DEFAULT); /* enable TRX_END interrupt */ pal_trx_irq_en(); /* Enable main transceiver interrupt. */ return FAILURE; } // write dummy value to start measurement pal_trx_reg_write(RG_PHY_ED_LEVEL, 0xFF); /* Perform ED in TAL_ED_RUNNING state. */ tal_state = TAL_ED_RUNNING; max_ed_level = 0; // reset max value sampler_counter = CALCULATE_SYMBOL_TIME_SCAN_DURATION(scan_duration) / ED_SAMPLE_DURATION_SYM; return MAC_SUCCESS; }
/** * @brief todo * */ void tal_rampdown(void) { /* * Deactivate interrupt handling. */ pal_trx_irq_dis(); /* Enable transceiver main interrupt. */ #if ((defined BEACON_SUPPORT) || (defined ENABLE_TSTAMP)) && (DISABLE_TSTAMP_IRQ == 0) /* Configure time stamp interrupt. */ pal_trx_irq_dis_tstamp(); /* Enable timestamp interrupt. */ #endif pal_trx_uninit(false); /* release SPI interface */ } /* tal_rampdown() */
/** * @brief Switches the PLL on */ static void switch_pll_on(void) { trx_irq_reason_t irq_status; uint32_t start_time, now; /* Check if trx is in TRX_OFF; only from PLL_ON the following procedure is applicable */ if (pal_trx_bit_read(SR_TRX_STATUS) != TRX_OFF) { ASSERT("Switch PLL_ON failed, because trx is not in TRX_OFF" == 0); return; } /* use the IRQ status register checking for the actual PLL status */ pal_trx_irq_dis(); pal_trx_reg_write(RG_IRQ_MASK, TRX_IRQ_PLL_LOCK); /* allow PLL lock IRQ only*/ pal_trx_reg_read(RG_IRQ_STATUS); /* clear PLL lock bit */ /* Switch PLL on */ pal_trx_reg_write(RG_TRX_STATE, CMD_PLL_ON); /* Check if PLL has been locked. */ pal_get_current_time(&start_time); while (1) { irq_status = (trx_irq_reason_t)pal_trx_reg_read(RG_IRQ_STATUS); if (irq_status & TRX_IRQ_PLL_LOCK) { break; // PLL is locked now } /* Check if polling needs too much time. */ pal_get_current_time(&now); if (pal_sub_time_us(now, start_time) > (10 * PLL_LOCK_TIME_US)) { /* leave poll loop and throw assertion */ #if (DEBUG > 0) ASSERT("PLL switch failed" == 0); #endif break; } } pal_trx_irq_flag_clr(); pal_trx_reg_write(RG_IRQ_MASK, TRX_IRQ_TRX_END); /* enable TRX_END interrupt */ pal_trx_irq_en(); }
/** * \brief Transmits the frame over-the-air */ static void tx_frame(void) { tal_trx_status_t trx_status; /* * Trigger transmission * In case of an ongoing reception, * the incoming frame is handled first within ISR. */ do { trx_status = set_trx_state(CMD_TX_ARET_ON); } while (trx_status != TX_ARET_ON); pal_trx_irq_dis(); /* Toggle the SLP_TR pin triggering transmission. */ PAL_SLP_TR_HIGH(); PAL_WAIT_65_NS(); PAL_SLP_TR_LOW(); /* * Send the frame to the transceiver. * Note: The PhyHeader is the first byte of the frame to * be sent to the transceiver and this contains the frame * length. * The actual length of the frame to be downloaded * (parameter two of pal_trx_frame_write) * is * 1 octet frame length octet * + n octets frame (i.e. value of frame_tx[0]) * + 1 extra octet (see datasheet) * - 2 octets FCS */ pal_trx_frame_write(tal_frame_to_tx, tal_frame_to_tx[0]); tal_state = TAL_TX_AUTO; #ifndef NON_BLOCKING_SPI pal_trx_irq_en(); #endif #ifdef TX_OCTET_COUNTER tal_tx_octet_cnt += PHY_OVERHEAD + LENGTH_FIELD_LEN + tal_frame_to_tx[0]; #endif }
/* * \brief Get the transceiver's supply voltage * * \return mv Milli Volt; 0 if below threshold, 0xFFFF if above threshold */ uint16_t tfa_get_batmon_voltage(void) { tal_trx_status_t previous_trx_status; uint8_t vth_val; uint8_t i; uint16_t mv = 1; /* 1 used as indicator flag */ bool range; previous_trx_status = tal_trx_status; if (tal_trx_status == TRX_SLEEP) { set_trx_state(CMD_TRX_OFF); } /* * Disable all trx interrupts. * This needs to be done AFTER the transceiver has been woken up. */ pal_trx_irq_dis(); /* Check if supply voltage is within lower range */ trx_bit_write(SR_BATMON_HR, BATMON_LOW_RANGE); trx_bit_write(SR_BATMON_VTH, 0x0F); pal_timer_delay(5); /* Wait until Batmon has been settled. */ if (trx_bit_read(SR_BATMON_OK) == BATMON_BELOW_THRES) { /* Lower range */ /* Check if supply voltage is below lower limit */ trx_bit_write(SR_BATMON_VTH, 0); pal_timer_delay(2); /* Wait until Batmon has been settled. */ if (trx_bit_read(SR_BATMON_OK) == BATMON_BELOW_THRES) { /* below lower limit */ mv = SUPPLY_VOLTAGE_BELOW_LOWER_LIMIT; } range = LOW; } else { /* Higher range */ trx_bit_write(SR_BATMON_HR, BATMON_HIGH_RANGE); /* Check if supply voltage is above upper limit */ trx_bit_write(SR_BATMON_VTH, 0x0F); pal_timer_delay(5); /* Wait until Batmon has been settled. */ if (trx_bit_read(SR_BATMON_OK) == BATMON_ABOVE_THRES) { /* above upper limit */ mv = SUPPLY_VOLTAGE_ABOVE_UPPER_LIMIT; } range = HIGH; } /* Scan through the current range for the matching threshold. */ if (mv == 1) { vth_val = 0x0F; for (i = 0; i < 16; i++) { trx_bit_write(SR_BATMON_VTH, i); pal_timer_delay(2); /* Wait until Batmon has been * settled. */ if (trx_bit_read(SR_BATMON_OK) == BATMON_BELOW_THRES) { if (i > 0) { vth_val = i - 1; } else { vth_val = i; } break; } } if (range == HIGH) { mv = 2550 + (75 * vth_val); } else { mv = 1700 + (50 * vth_val); } } trx_reg_read(RG_IRQ_STATUS); /* * Enable all trx interrupts. * This needs to be done BEFORE putting the transceiver back to slee. */ pal_trx_irq_en(); if (previous_trx_status == TRX_SLEEP) { set_trx_state(CMD_SLEEP); } return mv; }
/* * \brief Sends frame using trx features to handle CSMA and re-transmissions * * \param use_csma Flag indicating if CSMA is requested * \param tx_retries Flag indicating if transmission retries are requested * by the MAC layer */ void send_frame(csma_mode_t csma_mode, bool tx_retries) { tal_trx_status_t trx_status; /* Configure tx according to tx_retries */ if (tx_retries) { trx_bit_write(SR_MAX_FRAME_RETRIES, tal_pib.MaxFrameRetries); } else { trx_bit_write(SR_MAX_FRAME_RETRIES, 0); } /* Configure tx according to csma usage */ if ((csma_mode == NO_CSMA_NO_IFS) || (csma_mode == NO_CSMA_WITH_IFS)) { trx_bit_write(SR_MAX_CSMA_RETRIES, 7); /* immediate * transmission */ } else { trx_bit_write(SR_MAX_CSMA_RETRIES, tal_pib.MaxCSMABackoffs); } do { trx_status = set_trx_state(CMD_TX_ARET_ON); } while (trx_status != TX_ARET_ON); pal_trx_irq_dis(); /* Handle interframe spacing */ if (csma_mode == NO_CSMA_WITH_IFS) { if (last_frame_length > aMaxSIFSFrameSize) { pal_timer_delay(TAL_CONVERT_SYMBOLS_TO_US( macMinLIFSPeriod_def) - IRQ_PROCESSING_DLY_US - PRE_TX_DURATION_US); last_frame_length = 0; } else { pal_timer_delay(TAL_CONVERT_SYMBOLS_TO_US( macMinSIFSPeriod_def) - IRQ_PROCESSING_DLY_US - PRE_TX_DURATION_US); last_frame_length = 0; } } /* Toggle the SLP_TR pin triggering transmission. */ TRX_SLP_TR_HIGH(); PAL_WAIT_65_NS(); TRX_SLP_TR_LOW(); /* * Send the frame to the transceiver. * Note: The PhyHeader is the first byte of the frame to * be sent to the transceiver and this contains the frame * length. * The actual length of the frame to be downloaded * (parameter two of trx_frame_write) * is * 1 octet frame length octet * + n octets frame (i.e. value of frame_tx[0]) * - 2 octets FCS */ trx_frame_write(tal_frame_to_tx, tal_frame_to_tx[0] - 1); tal_state = TAL_TX_AUTO; #ifndef NON_BLOCKING_SPI pal_trx_irq_en(); #endif #ifdef TX_OCTET_COUNTER tal_tx_octet_cnt += PHY_OVERHEAD + LENGTH_FIELD_LEN + frame_tx[0]; #endif }
void tal_tx_beacon(frame_info_t *tx_frame) { tal_trx_status_t trx_status; /* Set pointer to actual mpdu to be downloaded to the transceiver. */ uint8_t *tal_beacon_to_tx = tx_frame->mpdu; /* * Avoid that the beacon is transmitted while transmitting * a frame using slotted CSMA. */ if ((tal_csma_state == FRAME_SENDING_WITH_ACK) || (tal_csma_state == FRAME_SENDING_NO_ACK) || (tal_csma_state == WAITING_FOR_ACK)) { Assert( "trying to transmit beacon while ongoing transmission" == 0); return; } /* Send the pre-created beacon frame to the transceiver. */ /* debug pin to switch on: define ENABLE_DEBUG_PINS, pal_config.h */ PIN_BEACON_START(); /* \TODO wait for talbeaconTxTime */ do { trx_status = set_trx_state(CMD_FORCE_PLL_ON); #if (_DEBUG_ > 1) if (trx_status != PLL_ON) { Assert("PLL_ON failed for beacon transmission" == 0); } #endif } while (trx_status != PLL_ON); pal_trx_irq_dis(); /* Toggle the SLP_TR pin triggering transmission. */ PAL_SLP_TR_HIGH(); PAL_WAIT_65_NS(); PAL_SLP_TR_LOW(); /* * Send the frame to the transceiver. * Note: The PhyHeader is the first byte of the frame to * be sent to the transceiver and this contains the frame * length. * The actual length of the frame to be downloaded * (parameter two of pal_trx_frame_write) * is * 1 octet frame length octet * + n octets frame (i.e. value of frame_tx[0]) * - 2 octets FCS */ pal_trx_frame_write(tal_beacon_to_tx, tal_beacon_to_tx[0] - 1); #ifndef NON_BLOCKING_SPI pal_trx_irq_en(); #endif tal_state = TAL_TX_BEACON; }
/* * \brief Sends frame * * \param use_csma Flag indicating if CSMA is requested * \param tx_retries Flag indicating if transmission retries are requested * by the MAC layer */ void send_frame(csma_mode_t csma_mode, bool tx_retries) { tal_trx_status_t trx_status; #ifdef BEACON_SUPPORT /* Handle frame transmission in slotted CSMA via basic mode */ if (tal_csma_state != CSMA_IDLE) { do { trx_status = set_trx_state(CMD_PLL_ON); } while (trx_status != PLL_ON); tal_state = TAL_TX_BASIC; } else #endif { /* Configure tx according to tx_retries */ if (tx_retries) { pal_trx_bit_write(SR_MAX_FRAME_RETRIES, tal_pib.MaxFrameRetries); } else { pal_trx_bit_write(SR_MAX_FRAME_RETRIES, 0); } /* Configure tx according to csma usage */ if ((csma_mode == NO_CSMA_NO_IFS) || (csma_mode == NO_CSMA_WITH_IFS)) { /* * RF230B does not support "no" CSMA mode, * therefore use shortest CSMA mode: CCA w/o backoff */ pal_trx_bit_write(SR_MIN_BE, 0x00); pal_trx_bit_write(SR_MAX_CSMA_RETRIES, 0); } else { pal_trx_bit_write(SR_MIN_BE, tal_pib.MinBE); pal_trx_bit_write(SR_MAX_CSMA_RETRIES, tal_pib.MaxCSMABackoffs); /* * Handle interframe spacing * Reduce IFS duration, since RF230B does CCA */ if (csma_mode == NO_CSMA_WITH_IFS) { if (last_frame_length > aMaxSIFSFrameSize) { pal_timer_delay(TAL_CONVERT_SYMBOLS_TO_US( macMinLIFSPeriod_def - CCA_DURATION_SYM) - IRQ_PROCESSING_DLY_US - PRE_TX_DURATION_US); } else { /* * No delay required, since processing *delay and CCA_DURATION_SYM * delay the handling enough. */ } } } do { trx_status = set_trx_state(CMD_TX_ARET_ON); } while (trx_status != TX_ARET_ON); tal_state = TAL_TX_AUTO; } pal_trx_irq_dis(); /* Toggle the SLP_TR pin triggering transmission. */ PAL_SLP_TR_HIGH(); PAL_WAIT_65_NS(); PAL_SLP_TR_LOW(); /* * Send the frame to the transceiver. * Note: The PhyHeader is the first byte of the frame to * be sent to the transceiver and this contains the frame * length. * The actual length of the frame to be downloaded * (parameter two of pal_trx_frame_write) * is * 1 octet frame length octet * + n octets frame (i.e. value of frame_tx[0]) * - 2 octets FCS */ pal_trx_frame_write(tal_frame_to_tx, tal_frame_to_tx[0] - 1); #ifndef NON_BLOCKING_SPI pal_trx_irq_en(); #endif }
/** * \brief Performs CCA twice */ static uint8_t perform_cca_twice(void) { tal_trx_status_t trx_status; uint8_t cca_status; uint8_t CW = 2; uint32_t now_time_us; do { pal_get_current_time(&now_time_us); } while (pal_add_time_us(now_time_us, (SLEEP_TO_TRX_OFF_US + CCA_PREPARATION_DURATION_US)) < cca_starttime_us); /* Ensure that trx is at least in TRX_OFF mode at this time. */ if (tal_trx_status == TRX_SLEEP) { set_trx_state(CMD_TRX_OFF); } do { pal_get_current_time(&now_time_us); } while (pal_add_time_us(now_time_us, (PLL_LOCK_TIME_US + CCA_PREPARATION_DURATION_US)) < cca_starttime_us); /* * Set trx to PLL_ON. * If trx is busy and trx cannot be set to PLL_ON, assess channel as *busy. */ if (set_trx_state(CMD_PLL_ON) != PLL_ON) { return PHY_BUSY; } /* no interest in trx interrupts while doing CCA */ pal_trx_irq_dis(); /* do CCA twice */ do { /* wait here until 16us before backoff boundary */ /* assume TRX is in PLL_ON */ do { pal_get_current_time(&now_time_us); } while (pal_add_time_us(now_time_us, CCA_PRE_START_DURATION_US) < cca_starttime_us); set_trx_state(CMD_RX_ON); /* debug pin to switch on: define ENABLE_DEBUG_PINS, *pal_config.h */ PIN_CCA_START(); /* Start CCA by writing any dummy value to this register */ pal_trx_bit_write(SR_CCA_REQUEST, 1); /* wait until CCA is done and get status */ pal_timer_delay(TAL_CONVERT_SYMBOLS_TO_US(CCA_DURATION_SYM)); do { /* poll until CCA is really done; */ trx_status = (tal_trx_status_t)pal_trx_reg_read( RG_TRX_STATUS); } while ((trx_status & CCA_DONE_BIT) != CCA_DONE_BIT); /* between both CCA switch trx to PLL_ON to reduce power *consumption */ set_trx_state(CMD_PLL_ON); /* debug pin to switch on: define ENABLE_DEBUG_PINS, *pal_config.h */ PIN_CCA_END(); /* check if channel was idle or busy */ if (trx_status & CCA_STATUS_BIT) { /* do next CCA at next backoff boundary */ cca_starttime_us = pal_add_time_us(cca_starttime_us, TAL_CONVERT_SYMBOLS_TO_US( aUnitBackoffPeriod)); CW--; cca_status = PHY_IDLE; } else { /* PHY busy */ cca_status = PHY_BUSY; set_trx_state(CMD_RX_AACK_ON); break; /* if channel is busy do no do CCA for the second * time */ } } while (CW > 0); /* * Keep trx ready for transmission if channel is idle. * The transceiver is still in PLL_ON. * If the channel is not idle, the trx handling is done in *csma_backoff(). */ /* * Since we are not interested in any frames that might be received * during CCA, reject any information that indicates a previous frame * reception. */ pal_trx_reg_read(RG_IRQ_STATUS); pal_trx_irq_flag_clr(); pal_trx_irq_en(); return cca_status; }
/* * \brief Get the transceiver's supply voltage * * \return mv Milli Volt; 0 if below threshold, 0xFFFF if above threshold */ uint16_t tfa_get_batmon_voltage(void) { tal_trx_status_t previous_trx_status; uint8_t vth_val; uint8_t i; uint16_t mv = 1; // 1 used as indicator flag bool range; pal_trx_irq_dis(); previous_trx_status = tal_trx_status; if (tal_trx_status == TRX_SLEEP) { set_trx_state(CMD_TRX_OFF); } /* Check if supply voltage is within lower range */ pal_trx_bit_write(SR_BATMON_HR, BATMON_LOW_RANGE); pal_trx_bit_write(SR_BATMON_VTH, 0x0F); if (pal_trx_bit_read(SR_BATMON_OK) == BATMON_BELOW_THRES) { /* Lower range */ /* Check if supply voltage is below lower limit */ pal_trx_bit_write(SR_BATMON_VTH, 0); if (pal_trx_bit_read(SR_BATMON_OK) == BATMON_BELOW_THRES) { /* below lower limit */ mv = SUPPLY_VOLTAGE_BELOW_LOWER_LIMIT; } range = LOW; } else { /* Higher range */ pal_trx_bit_write(SR_BATMON_HR, BATMON_HIGH_RANGE); /* Check if supply voltage is above upper limit */ pal_trx_bit_write(SR_BATMON_VTH, 0x0F); if (pal_trx_bit_read(SR_BATMON_OK) == BATMON_ABOVE_THRES) { /* above upper limit */ mv = SUPPLY_VOLTAGE_ABOVE_UPPER_LIMIT; } range = HIGH; } if (mv == 1) { vth_val = 0x0F; for (i = 0; i < 16; i++) { pal_trx_bit_write(SR_BATMON_VTH, i); if (pal_trx_bit_read(SR_BATMON_OK) == BATMON_BELOW_THRES) { if (i > 0) { vth_val = i - 1; } else { vth_val = i; } break; } } if (range == HIGH) { mv = 2550 + (75 * vth_val); } else { mv = 1700 + (50 * vth_val); } } pal_trx_reg_read(RG_IRQ_STATUS); if (previous_trx_status == TRX_SLEEP) { set_trx_state(CMD_TRX_SLEEP); } pal_trx_irq_en(); return mv; }
/* * \brief Perform a CCA * * This function performs a CCA request. * * \return phy_enum_t PHY_IDLE or PHY_BUSY */ phy_enum_t tfa_cca_perform(void) { tal_trx_status_t trx_status; uint8_t cca_status; /* Ensure that trx is not in SLEEP for register access */ do { trx_status = set_trx_state(CMD_TRX_OFF); } while (trx_status != TRX_OFF); // no interest in trx interrupts while doing CCA pal_trx_irq_dis(); /* Set trx to rx mode. */ do { trx_status = set_trx_state(CMD_RX_ON); } while (trx_status != RX_ON); /* Start CCA by writing any dummy value to this register */ pal_trx_bit_write(SR_CCA_REQUEST, 1); /* wait until CCA is done */ pal_timer_delay(TAL_CONVERT_SYMBOLS_TO_US(CCA_DURATION_SYM)); do { /* * Poll until CCA is really done. * Do NOT use bit read here! */ trx_status = (tal_trx_status_t)pal_trx_reg_read(RG_TRX_STATUS); } while ((trx_status & CCA_DONE_BIT) != CCA_DONE_BIT); set_trx_state(CMD_TRX_OFF); /* Check if channel was idle or busy. */ if (trx_status & CCA_STATUS_BIT) { cca_status = PHY_IDLE; } else { cca_status = PHY_BUSY; } /* * Since we are not interested in any frames that might be received * during CCA, reject any information that indicates a previous frame * reception. */ pal_trx_reg_read(RG_IRQ_STATUS); pal_trx_irq_flag_clr(); pal_trx_irq_en(); return (phy_enum_t)cca_status; }
/** * @brief Get the transceiver's supply voltage * * @return mv Milli Volt; 0 if below threshold, 0xFFFF if above threshold */ uint16_t tfa_get_batmon_voltage(void) { tal_trx_status_t previous_trx_status; uint8_t vth_val; uint16_t mv = 1; // 1 used as indicator flag bool range; previous_trx_status = tal_trx_status; if (tal_trx_status == TRX_SLEEP) { set_trx_state(CMD_TRX_OFF); } /* * Disable all trx interrupts. * This needs to be done AFTER the transceiver has been woken up. */ pal_trx_irq_dis(); /* Check if supply voltage is within upper or lower range. */ pal_trx_bit_write(SR_BATMON_HR, BATMON_HR_HIGH); pal_trx_bit_write(SR_BATMON_VTH, 0x00); pal_timer_delay(5); /* Wait until Batmon has been settled. */ /* Check if supply voltage is within lower range */ if (pal_trx_bit_read(SR_BATMON_OK) == BATMON_NOT_VALID) { /* Lower range */ /* Check if supply voltage is below lower limit */ pal_trx_bit_write(SR_BATMON_HR, BATMON_HR_LOW); pal_timer_delay(2); /* Wait until Batmon has been settled. */ if (pal_trx_bit_read(SR_BATMON_OK) == BATMON_NOT_VALID) { /* below lower limit */ mv = SUPPLY_VOLTAGE_BELOW_LOWER_LIMIT; } range = LOW; } else { /* Higher range */ /* Check if supply voltage is above upper limit */ pal_trx_bit_write(SR_BATMON_VTH, 0x0F); pal_timer_delay(5); /* Wait until Batmon has been settled. */ if (pal_trx_bit_read(SR_BATMON_OK) == BATMON_VALID) { /* above upper limit */ mv = SUPPLY_VOLTAGE_ABOVE_UPPER_LIMIT; } range = HIGH; } /* Scan through the current range for the matching threshold. */ if (mv == 1) // 1 = indicates that voltage is within supported range { vth_val = 0x0F; for (uint8_t i = 0; i < 16; i++) { pal_trx_bit_write(SR_BATMON_VTH, vth_val); pal_timer_delay(2); /* Wait until Batmon has been settled. */ if (pal_trx_bit_read(SR_BATMON_OK) == BATMON_VALID) { break; } vth_val--; } /* Calculate voltage based on register value and range. */ if (range == HIGH) { mv = 2550 + (75 * vth_val); } else { mv = 1700 + (50 * vth_val); } } pal_trx_reg_read(RG_IRQ_STATUS); /* * Enable all trx interrupts. * This needs to be done BEFORE putting the transceiver back to slee. */ pal_trx_irq_en(); if (previous_trx_status == TRX_SLEEP) { set_trx_state(CMD_SLEEP); } return mv; }