Пример #1
0
/**
 * \brief Handles software-controlled CSMA.
 *
 * \param csma_mode     CSMA Mode; eg. ED or CS
 * \param retransmit    true if frame re-transmission is requested
 */
static inline void sw_controlled_csma(csma_mode_t csma_mode, bool retransmit)
{
	if (retransmit) {
		number_of_tx_retries = 0; /* actual number of retries */
	} else {
		/* no further retries */
		number_of_tx_retries = tal_pib.MaxFrameRetries;
	}

	/* 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);
		} else {
			pal_timer_delay(TAL_CONVERT_SYMBOLS_TO_US(
					macMinSIFSPeriod_def)
					- IRQ_PROCESSING_DLY_US -
					PRE_TX_DURATION_US);
		}
	}

	if ((csma_mode == NO_CSMA_WITH_IFS) || (csma_mode == NO_CSMA_NO_IFS)) {
		tx_frame();
	} else {
		csma_start();
	}
}
Пример #2
0
/**
 * \brief Starts the timer for the backoff period and enables receiver.
 */
static void start_backoff(void)
{
	/* Start backoff timer to trigger CCA */
	uint8_t backoff_8;
	backoff_8  = (uint8_t)rand() & ((1 << BE) - 1);
	if (backoff_8 > 0) {
		uint16_t backoff_16;
		uint32_t backoff_duration_us;
		backoff_16 = backoff_8 * aUnitBackoffPeriod;
		backoff_duration_us = TAL_CONVERT_SYMBOLS_TO_US(backoff_16);
		pal_timer_start(TAL_T_BOFF, backoff_duration_us,
				TIMEOUT_RELATIVE,
				(FUNC_PTR)cca_start, NULL);
		tal_state = TAL_BACKOFF;

#ifdef RX_WHILE_BACKOFF
		/* Switch receiver on during backoff */
		if (NULL == tal_rx_buffer) {
			set_trx_state(CMD_PLL_ON);
			tal_rx_on_required = true;
		} else {
			set_trx_state(CMD_RX_AACK_ON); /* receive while backoff
			                                **/
		}

#else
		set_trx_state(CMD_PLL_ON);
#endif
	} else {
		/* Start CCA immediately - no backoff */
		cca_start(NULL);
	}
}
Пример #3
0
/*
 * \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;
}
Пример #4
0
/*
 * @brief helper function to start missed beacon timer
 */
void mac_start_missed_beacon_timer(void)
{
    uint32_t sync_loss_time;
    uint8_t timer_status;

    /* Stop the missed beacon timer. */
    pal_timer_stop(T_Missed_Beacon);

#if (DEBUG > 0)
    if (pal_is_timer_running(T_Missed_Beacon))
    {
        ASSERT("Missed BCN tmr running" == 0);
    }
#endif

    /* Calculate the time allowed for missed beacons. */
    if (tal_pib.BeaconOrder < NON_BEACON_NWK)
    {
        /*
         * This the regualar case where we already have a Beacon Order.
         * In this case the Sync Loss time is a function of the actual
         * Beacon Order.
         */
        sync_loss_time = TAL_GET_BEACON_INTERVAL_TIME(tal_pib.BeaconOrder);
    }
    else
    {
        /*
         * This the "pathological" case where we don NOT have a Beacon Order.
         * This happens regularly in case of synchronization before association
         * if the Beacon Order was not set be the network layer or application.
         *
         * In this case the Sync Loss time is based on the highest possible
         * Beacon Order, which is 15 - 1, since 15 means no Beacon network.
         */
        sync_loss_time = TAL_GET_BEACON_INTERVAL_TIME(NON_BEACON_NWK - 1);
    }

    sync_loss_time *= aMaxLostBeacons;

    sync_loss_time = TAL_CONVERT_SYMBOLS_TO_US(sync_loss_time);

    timer_status = pal_timer_start(T_Missed_Beacon,
                                   sync_loss_time,
                                   TIMEOUT_RELATIVE,
                                   (FUNC_PTR)mac_t_missed_beacons_cb,
                                   NULL);

    if (MAC_SUCCESS != timer_status)
    {
#if (DEBUG > 0)
        ASSERT(MAC_SUCCESS == timer_status);
#endif
        /* Sync timer could not be started hence report sync-loss */
        mac_sync_loss(MAC_BEACON_LOSS);
    }
}
Пример #5
0
/**
 * @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)
{
    trx_irq_reason_t trx_irq_cause;
    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_bit_write(SR_RX_PDT_DIS, RX_DISABLE);

    /* Write dummy value to start measurement. */
    pal_trx_reg_write(RG_PHY_ED_LEVEL, 0xFF);

    /* Wait for ED measurement completion. */
    pal_timer_delay(TAL_CONVERT_SYMBOLS_TO_US(ED_SAMPLE_DURATION_SYM));
    do
    {
        trx_irq_cause = (trx_irq_reason_t)pal_trx_reg_read(RG_IRQ_STATUS);
    }
    while ((trx_irq_cause & TRX_IRQ_CCA_ED_READY) != TRX_IRQ_CCA_ED_READY);

    /* Read the ED Value. */
    ed_value = pal_trx_reg_read(RG_PHY_ED_LEVEL);

#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

    /* Clear IRQ register */
    pal_trx_reg_read(RG_IRQ_STATUS);
    /* Enable reception agian */
    pal_trx_bit_write(SR_RX_PDT_DIS, RX_ENABLE);
    /* Switch receiver off again */
    set_trx_state(CMD_TRX_OFF);

    return ed_value;
}
/*
 * @brief Internal function to handle immediate RX_ON
 *
 * This function immediately enables the receiver with the given
 * RxOnDuration time in symbols from now.
 *
 * @param rx_on_duration_symbols Duration in symbols that the reciever is
 *                               switched on.
 */
static void handle_rx_on(uint32_t rx_on_duration_symbols, uint8_t *m)
{
    retval_t timer_status;
    uint8_t rx_enable_status = mac_rx_enable();

    /*
     * TODO: Once it is possible to restart a timer even if it is
     * already running, this could be improved by simply calling
     * function pal_timer_start() without this previous check using
     * function pal_is_timer_running().
     */
    if (pal_is_timer_running(T_Rx_Enable))
    {
        /*
         * Rx-Enable timer is already running, so we need to stopp it first
         * before it will be started.
         */
        pal_timer_stop(T_Rx_Enable);
    }

    /*
     * Start timer for the Rx On duration of the radio being on
     * in order to switch it off later again.
     */
    timer_status =
        pal_timer_start(T_Rx_Enable,
                        TAL_CONVERT_SYMBOLS_TO_US(rx_on_duration_symbols),
                        TIMEOUT_RELATIVE,
                        (FUNC_PTR())mac_t_rx_off_cb,
                        NULL);

    ASSERT(MAC_SUCCESS == timer_status);

    /*
     * Send the confirm immediately depending on the status of
     * the timer start and the Rx Status
     */
    if (MAC_SUCCESS != timer_status)
    {
        gen_rx_enable_conf((buffer_t *)m, (uint8_t)MAC_INVALID_PARAMETER);
        /* Do house-keeeping and turn radio off. */
        mac_t_rx_off_cb(NULL);
    }
    else if (PHY_RX_ON != rx_enable_status)
    {
        gen_rx_enable_conf((buffer_t *)m, (uint8_t)MAC_TX_ACTIVE);
    }
    else
    {
        gen_rx_enable_conf((buffer_t *)m, (uint8_t)MAC_SUCCESS);
    }

    return;
}
Пример #7
0
/**
 * @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;
    uint8_t cca_done;

    /* 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 receiving frames while doing CCA */
    pal_trx_bit_write(SR_RX_PDT_DIS, RX_DISABLE); // disable frame reception indication

    /* Set trx to rx mode. */
    do
    {
        trx_status = set_trx_state(CMD_RX_ON);
    }
    while (trx_status != RX_ON);

    /* Start CCA */
    pal_trx_bit_write(SR_CCA_REQUEST, CCA_START);

    /* wait until CCA is done */
    pal_timer_delay(TAL_CONVERT_SYMBOLS_TO_US(CCA_DURATION_SYM));
    do
    {
        /* poll until CCA is really done */
        cca_done = pal_trx_bit_read(SR_CCA_DONE);
    }
    while (cca_done != CCA_COMPLETED);

    set_trx_state(CMD_TRX_OFF);

    /* Check if channel was idle or busy. */
    if (pal_trx_bit_read(SR_CCA_STATUS) == CCA_CH_IDLE)
    {
        cca_status = PHY_IDLE;
    }
    else
    {
        cca_status = PHY_BUSY;
    }

    /* Enable frame reception again. */
    pal_trx_bit_write(SR_RX_PDT_DIS, RX_ENABLE);

    return (phy_enum_t)cca_status;
}
Пример #8
0
/**
 * @brief Continue scanning after the completion of frame transmission.
 *
 * This functions continues the corresponding scaning depending on status
 * from the transmission of a beacon request or orphan notification frame.
 *
 * @param status Status of transmission
 */
void mac_scan_send_complete(retval_t status)
{
	retval_t timer_status;

	mac_pib.mac_DSN++;

	if (MAC_SUCCESS == status) {
		uint32_t tmr = 0;

		if (MAC_SCAN_ACTIVE == mac_scan_state) {
			tmr = MAC_CALCULATE_SYMBOL_TIME_SCANDURATION(
					scan_duration);
		} else {
			/*
			 * Since this function is only called in active or
			 * orphan scan state,
			 * this case is handling the orphan scan state.
			 */
			tmr = mac_pib.mac_ResponseWaitTime;
		}

		timer_status = pal_timer_start(T_Scan_Duration,
				TAL_CONVERT_SYMBOLS_TO_US(tmr),
				TIMEOUT_RELATIVE,
				(FUNC_PTR)mac_t_scan_duration_cb,
				NULL);
#if (_DEBUG_ > 0)
		Assert(MAC_SUCCESS == timer_status);
#endif
		if (MAC_SUCCESS != timer_status) {
			uint8_t timer_id = T_Scan_Duration;

			/*
			 * Scan duration timer could not be started, so we call
			 * the timer callback function directly. This will
			 * basically
			 * shorten scanning without having really scanned.
			 */
			mac_t_scan_duration_cb((void *)&timer_id);
		}
	} else {
		/* Did not work, continue. */
		scan_curr_channel++;
		scan_proceed(scan_type, (buffer_t *)mac_conf_buf_ptr);
	}
}
Пример #9
0
/**
 * \brief Starts the beacon loss timer
 */
static void start_beacon_loss_timer(void)
{
	uint32_t timer_duration_us;
#if (_DEBUG_ > 0)
	retval_t timer_status;
#endif

	/* debug pin to switch on: define ENABLE_DEBUG_PINS, pal_config.h */
	PIN_BEACON_LOSS_TIMER_START();

	timer_duration_us
		= TAL_CONVERT_SYMBOLS_TO_US(TAL_GET_BEACON_INTERVAL_TIME(tal_pib
			.BeaconOrder));
	timer_duration_us *= aMaxLostBeacons;
	timer_duration_us += CSMA_BEACON_LOSS_GUARD_TIME_US;

#if (_DEBUG_ > 0)
	timer_status =
#endif
	pal_timer_start(TAL_CSMA_BEACON_LOSS_TIMER,
			timer_duration_us,
			TIMEOUT_RELATIVE,
			(FUNC_PTR)beacon_loss_timer_cb,
			NULL);

#if (_DEBUG_ > 0)
	if (timer_status != MAC_SUCCESS) {
		if (timer_status == PAL_TMR_INVALID_TIMEOUT) {
			Assert(
					"beacon loss timer start failed: PAL_TMR_INVALID_TIMEOUT" ==
					0);
		} else if (timer_status == PAL_TMR_ALREADY_RUNNING) {
			Assert(
					"beacon loss timer start failed: PAL_TMR_ALREADY_RUNNING" ==
					0);
		} else {
			Assert("beacon loss timer start failed: ?" == 0);
		}
	}

#endif
}
Пример #10
0
/*
 * \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;
}
Пример #11
0
/**
 * \brief Calculates backoff duration and handles the start of the CCA
 */
static void csma_backoff_calculation(void)
{
	uint32_t current_CAP_duration_sym;
	uint32_t current_CAP_end_sym;
	uint32_t next_backoff_boundary_us;
	uint32_t now_time_sym;
	uint32_t guard_time_before_next_beacon;

	/* \TODO consider CFP and BLE mode */
	current_CAP_duration_sym = TAL_GET_SUPERFRAME_DURATION_TIME(
			tal_pib.SuperFrameOrder);
	current_CAP_end_sym = tal_add_time_symbols(tal_pib.BeaconTxTime,
			current_CAP_duration_sym);

	/*
	 * Add some guard time to ensure that the transaction is completed
	 * before
	 * the timer fires that is going to track the next beacon.
	 */
	guard_time_before_next_beacon = TAL_RADIO_WAKEUP_TIME_SYM <<
			(tal_pib.BeaconOrder + 2);
	guard_time_before_next_beacon += TAL_CONVERT_US_TO_SYMBOLS(
			PRE_BEACON_GUARD_TIME_US);
	current_CAP_end_sym = tal_sub_time_symbols(current_CAP_end_sym,
			guard_time_before_next_beacon);

	/* Calculate next backoff period boundary. */
	{
		uint32_t time_since_last_beacon_sym;
		uint32_t next_backoff_boundary_period;

		pal_get_current_time(&now_time_sym);
		now_time_sym = TAL_CONVERT_US_TO_SYMBOLS(now_time_sym);

		time_since_last_beacon_sym = tal_sub_time_symbols(now_time_sym,
				tal_pib.BeaconTxTime);
		next_backoff_boundary_period = time_since_last_beacon_sym /
				aUnitBackoffPeriod;

		if ((time_since_last_beacon_sym % aUnitBackoffPeriod) > 0) {
			next_backoff_boundary_period++;
		}

		next_backoff_boundary_us
			= TAL_CONVERT_SYMBOLS_TO_US(
				pal_add_time_us(tal_pib.BeaconTxTime,
				(next_backoff_boundary_period *
				aUnitBackoffPeriod)));
	}

	/* Check if we are still within the CAP. */
	if (next_backoff_boundary_us >=
			TAL_CONVERT_SYMBOLS_TO_US(current_CAP_end_sym)) {
		/* current CAP is over, wait for next CAP */
		tal_csma_state = BACKOFF_WAITING_FOR_BEACON;
		start_beacon_loss_timer();
	} else { /* next backoff boundary is within current CAP */
		uint32_t remaining_periods_in_CAP; /* \TODO check if variable
		                                    * size can be reduced */

		/* Check if the remaining backoff time will expire in current
		 * CAP. */
		remaining_periods_in_CAP = tal_sub_time_symbols(
				current_CAP_end_sym, now_time_sym) /
				aUnitBackoffPeriod;

		if (remaining_backoff_periods > remaining_periods_in_CAP) {
			/*
			 * Reduce the backoff peridos by the remaining duration
			 * in
			 * the current CAP and continue in next CAP.
			 */
			remaining_backoff_periods -= remaining_periods_in_CAP;
			tal_csma_state = BACKOFF_WAITING_FOR_BEACON;

			start_beacon_loss_timer();
		} else { /* there are enough backoff periods in current CAP */
			uint32_t time_after_transaction_sym; /* \TODO check if
			                                      * variable size
			                                      * can be reduced
			                                      **/
			uint32_t transaction_duration_sym; /* \TODO check if
			                                    * variable size can
			                                    * be reduced */

			/* Add some guard time to wakeup the transceiver. */
			transaction_duration_sym
				= (transaction_duration_periods *
					aUnitBackoffPeriod) +
					TAL_CONVERT_US_TO_SYMBOLS(
					SLEEP_TO_TRX_OFF_TYP_US +
					CCA_GUARD_DURATION_US);

			time_after_transaction_sym
				= tal_add_time_symbols(TAL_CONVERT_US_TO_SYMBOLS(
					next_backoff_boundary_us),
					transaction_duration_sym);

			/* Check if the entire transaction fits into the current
			 * CAP. */
			if (time_after_transaction_sym < current_CAP_end_sym) {
				retval_t timer_status;
				uint32_t callback_start_time;

				/* Calculate the time needed to backoff. */
				cca_starttime_us
					= pal_add_time_us(
						next_backoff_boundary_us,
						TAL_CONVERT_SYMBOLS_TO_US(
						remaining_backoff_periods *
						aUnitBackoffPeriod));

				/*
				 * Ensure that wakeup time is available before
				 * CCA.
				 * The required duration depends on the current
				 * trx status.
				 * Assume here the worst case: trx is in SLEEP.
				 */

				/*
				 * \TODO depending on the duration that we need
				 * to backoff,
				 * set trx to SLEEP, TRX_OFF or PLL_ON
				 * meanwhile.
				 */
				while (pal_sub_time_us(cca_starttime_us,
						TAL_CONVERT_SYMBOLS_TO_US(
						now_time_sym)) <
						(SLEEP_TO_TRX_OFF_TYP_US +
						CCA_GUARD_DURATION_US)) {
					cca_starttime_us
						= pal_add_time_us(
							cca_starttime_us,
							TAL_CONVERT_SYMBOLS_TO_US(
							aUnitBackoffPeriod));
				}

				/*
				 * Start the CCA timer.
				 * Add some time to locate the next backoff
				 * boundary
				 * once CCA timer fires.
				 */
				callback_start_time
					= pal_sub_time_us(cca_starttime_us,
						(SLEEP_TO_TRX_OFF_TYP_US +
						CCA_PREPARATION_DURATION_US));

				timer_status = pal_timer_start(TAL_CSMA_CCA,
						callback_start_time,
						TIMEOUT_ABSOLUTE,
						(FUNC_PTR)cca_timer_handler_cb,
						NULL);

				if (timer_status == MAC_SUCCESS) {
					tal_csma_state
						= BACKOFF_WAITING_FOR_CCA_TIMER;
				} else if (timer_status ==
						PAL_TMR_INVALID_TIMEOUT) {
					/* Start the CCA immediately. */
					cca_timer_handler_cb(NULL);
				} else {
					tal_csma_state = CSMA_ACCESS_FAILURE;
					Assert("CCA timer start problem" == 0);
				}

				/* debug pin to switch on: define
				 * ENABLE_DEBUG_PINS, pal_config.h */
				PIN_BACKOFF_START();
			} else {
				/* Restart again after next beacon. */
				NB = 0;
				remaining_backoff_periods
					= (uint8_t)(rand() &
						((1 << BE) - 1));
				tal_csma_state = BACKOFF_WAITING_FOR_BEACON;

				start_beacon_loss_timer();
			}
		}
	}
}
Пример #12
0
/**
 * \brief Performs CCA twice
 */
static uint8_t perform_cca_twice(void)
{
	uint8_t cca_status;
	uint8_t cca_done;
	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_TYP_US +
			CCA_PREPARATION_DURATION_US)) <
			cca_starttime_us);

#if ((MAC_START_REQUEST_CONFIRM == 1) && (defined BEACON_SUPPORT))
	if (tal_beacon_transmission) {
#if (_DEBUG_ > 0)
		Assert("Ongoing beacon transmission, slotted CSMA busy" == 0);
#endif
		return PHY_BUSY;
	}

#endif /* ((MAC_START_REQUEST_CONFIRM == 1) && (defined BEACON_SUPPORT)) */

	/* 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,
			(TRX_OFF_TO_PLL_ON_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 receiving frames while doing CCA */
	trx_bit_write(SR_RX_PDT_DIS, RX_DISABLE); /* disable frame reception
	                                           * indication */

	/* 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 */
		trx_bit_write(SR_CCA_REQUEST, CCA_START);

		/* 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; */
			cca_done = trx_bit_read(SR_CCA_DONE);
		} while (cca_done != CCA_COMPLETED);

		/* 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_bit_read(SR_CCA_STATUS) == CCA_CH_IDLE) {
			/* 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().
	 */

	/*
	 * Clear CCA interrupt flag.
	 * This is only necessary for debugging, because only in debug mode
	 * interrupt that are not handled cause an assert in the ISR.
	 */
#if (_DEBUG_ > 0)
	trx_reg_read(RG_IRQ_STATUS);
#endif

	/*
	 * Since we are not interested in any frames that might be received
	 * during CCA, reject any information that indicates a previous frame
	 * reception.
	 */
	trx_bit_write(SR_RX_PDT_DIS, RX_ENABLE); /* enable frame reception
	                                          * indication */

	return cca_status;
}
/**
 * @brief Implement the MLME-RX-ENABLE.request primitive.
 *
 * The MLME-RX-ENABLE.request primitive is generated by the next
 * higher layer and issued to MAC to enable the receiver for a
 * fixed duration, at a time relative to the start of the current or
 * next superframe on a beacon-enabled PAN or immediately on a
 * nonbeacon-enabled PAN. The receiver is enabled exactly once per
 * primitive request.
 *
 * @param m Pointer to the MLME-RX-ENABLE.request message
 */
void mlme_rx_enable_request(uint8_t *m)
{
    mlme_rx_enable_req_t *rxe;

    rxe = (mlme_rx_enable_req_t *)BMM_BUFFER_POINTER((buffer_t *)m);

    /* If RxOnDuration is zero, the receiver shall be disabled */
    if (0 == rxe->RxOnDuration)
    {
        /*
         * Turn the radio off. This is doney by calling the
         * same function as for the expiration of the Rx on timer.
         */
        mac_t_rx_off_cb(NULL);

        /* Send the confirm immediately. */
        gen_rx_enable_conf((buffer_t *)m, (uint8_t)MAC_SUCCESS);
        return;
    }

    /*
     * Reject the request when the MAC is currently in any of the
     * polling states or scanning.
     */
    if ((MAC_POLL_IDLE != mac_poll_state) ||
        (MAC_SCAN_IDLE != mac_scan_state)
       )
    {
        /* Send the confirm immediately. */
        gen_rx_enable_conf((buffer_t *)m, (uint8_t)MAC_TX_ACTIVE);
        return;
    }

#ifdef BEACON_SUPPORT
    if (NON_BEACON_NWK == tal_pib.BeaconOrder)
    {
        handle_rx_on(rxe->RxOnDuration, m);
    }
    else
    {
        /* We have a beacon-enabled network. */
        uint32_t curr_beacon_int_time_symbols = TAL_GET_BEACON_INTERVAL_TIME(tal_pib.BeaconOrder);
        uint32_t now_time_symbols;
        uint32_t symbols_since_beacon;
        uint32_t rx_on_time_symbols;
        retval_t timer_status;

        /*
         * Determine if (RxOnTime + RxOnDuration) is less than the beacon
         * interval.
         * According to 7.1.10.1.3:
         * On a beacon-enabled PAN, the MLME first determines whether
         * (RxOnTime + RxOnDuration) is less than the beacon interval, defined
         * by macBeaconOrder. If it is not less, the MLME issues the
         * MLME-RX-ENABLE.confirm primitive with a status of MAC_INVALID_PARAMETER.
         */

        rx_off_time_symbols = rxe->RxOnTime + rxe->RxOnDuration;

        if (rx_off_time_symbols >= curr_beacon_int_time_symbols)
        {
            /* Send the confirm immediately. */
            gen_rx_enable_conf((buffer_t *)m, (uint8_t)MAC_INVALID_PARAMETER);
            return;
        }

        pal_get_current_time(&now_time_symbols);
        now_time_symbols = TAL_CONVERT_US_TO_SYMBOLS(now_time_symbols);

        symbols_since_beacon  = tal_sub_time_symbols(now_time_symbols, tal_pib.BeaconTxTime);

        /*
         * Actually, MLME-RX-ENABLE.request in a beacon enabled PAN does
         * only make sense if the MAC is currently tracking beacons, so
         * that macBeaconTxTime is up to date. If it appears that
         * the last known macBeaconTxTime does not relate to the
         * current superframe, reject the request.
         */
        if (symbols_since_beacon > curr_beacon_int_time_symbols)
        {
            /* Send the confirm immediately. */
            gen_rx_enable_conf((buffer_t *)m, (uint8_t)MAC_INVALID_PARAMETER);
            return;
        }

        rx_on_time_symbols = tal_add_time_symbols(tal_pib.BeaconTxTime, rxe->RxOnTime);

        /* Check whether RxOnTime can still be handled in current CAP. */
        pal_get_current_time(&now_time_symbols);
        now_time_symbols = TAL_CONVERT_US_TO_SYMBOLS(now_time_symbols);

        if (tal_add_time_symbols(rx_on_time_symbols, TAL_CONVERT_US_TO_SYMBOLS(MIN_TIMEOUT))
            < now_time_symbols)
        {
            /* RxOnTime not possible within this CAP, see whether deferred
             * handling is allowed or not.. */
            if (!(rxe->DeferPermit))
            {
                gen_rx_enable_conf((buffer_t *)m, (uint8_t)MAC_PAST_TIME);
                return;
            }
            else
            {
                /*
                 * The MAC defers until the next superframe and attempts to enable
                 * the receiver in that superframe.
                 */
                rx_on_time_symbols = tal_add_time_symbols(rx_on_time_symbols,
                                                          curr_beacon_int_time_symbols);
            }
        }

        /*
         * Since the Rx-Enable timer could already be running,
         * it is stopped first, before it will be started (again).
         */
        pal_timer_stop(T_Rx_Enable);

        do
        {
            /*
             * Start a timer to turn Rx ON at the time "rxe->RxOnTime" from the start
             * of the next superframe.
             * Return value to be checked, because Rx on time could be too short
             * or in the past already.
             */
            timer_status =
                pal_timer_start(T_Rx_Enable,
                                TAL_CONVERT_SYMBOLS_TO_US(rx_on_time_symbols),
                                TIMEOUT_ABSOLUTE,
                                (FUNC_PTR())mac_t_rx_on_cb,
                                (void *)m);

            if (MAC_SUCCESS != timer_status)
            {
                rx_on_time_symbols = tal_add_time_symbols(rx_on_time_symbols,
                                                          curr_beacon_int_time_symbols);
            }
        }
        while (MAC_SUCCESS != timer_status);

        /* Remember the time to turn off the receiver. */
        rx_off_time_symbols = tal_add_time_symbols(rx_on_time_symbols, rxe->RxOnDuration);

        /* The remaining stuff will be done once the Rx On Timer expires. */
    }
#else   /* No BEACON_SUPPORT */
    handle_rx_on(rxe->RxOnDuration, m);
#endif  /* BEACON_SUPPORT / No BEACON_SUPPORT */
} /* mlme_rx_enable_request() */
Пример #14
0
/*
 * \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;

	/* 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)) {
		if (tx_retries) {
			trx_bit_write(SR_MAX_CSMA_RETRIES,
					tal_pib.MaxCSMABackoffs);
			trx_reg_write(RG_CSMA_BE, 0x00);
		} else {
			trx_bit_write(SR_MAX_CSMA_RETRIES, 7);
		}
	} else {
		trx_reg_write(RG_CSMA_BE,
				((tal_pib.MaxBE << 4) | tal_pib.MinBE));
		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);

	/* 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;
		}
	} else {
		/*
		 * If no delay is applied after switching to TX_ARET_ON,
		 * a short delay is required that allows that a pending TX_END
		 * IRQ for
		 * ACK transmission gets served.
		 */
		pal_timer_delay(TRX_IRQ_DELAY_US);
	}

	ENTER_CRITICAL_REGION(); /* prevent from buffer underrun */

	/* 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;

	LEAVE_CRITICAL_REGION();
}
Пример #15
0
/**
 * @brief Processes received beacon frame
 *
 * This function processes a received beacon frame.
 * When the system is scanning it records PAN descriptor information
 * contained in the beacon. These PAN descriptors will be reported to the
 * next higher layer via MLME_SCAN.confirm.
 * Also this routine constructs the MLME_BEACON_NOTIFY.indication.
 * Additionally when a device is synced with the coordinator, it tracks beacon
 * frames, checks whether the coordinator does have pending data and will
 * initiate the transmission of a data request frame.
 * The routine uses global "parse_data" structure.
 * The PAN descriptors are stored in the mlme_scan_conf_t structure.
 *
 * @param beacon Pointer to the buffer in which the beacon was received
 *
 */
void mac_process_beacon_frame(buffer_t *beacon)
{
    bool matchflag;
    wpan_pandescriptor_t *pand_long_start_p = NULL;
    wpan_pandescriptor_t pand_long;
    mlme_scan_conf_t *msc = NULL;

#if ((MAC_BEACON_NOTIFY_INDICATION == 1) || \
     ((MAC_INDIRECT_DATA_BASIC == 1) && (MAC_SYNC_REQUEST == 1)) \
    )
    uint8_t numaddrshort;
    uint8_t numaddrlong;
#endif

#ifdef BEACON_SUPPORT
    uint16_t beacon_length;

    /*
     * Extract the superframe parameters of the beacon frame only if
     * scanning is NOT ongoing.
     */
    if (MAC_SCAN_IDLE == mac_scan_state)
    {
#if (MAC_START_REQUEST_CONFIRM == 1)
        /* Beacon frames are not of interest for a PAN coordinator. */
        if (MAC_PAN_COORD_STARTED != mac_state)
#endif /* MAC_START_REQUEST_CONFIRM */
        {
            uint8_t superframe_order;
            uint8_t beacon_order;

            /*
             * For a device, the parameters obtained from the beacons are used to
             * update the PIBs at TAL
             */
            beacon_order =
                GET_BEACON_ORDER(mac_parse_data.mac_payload_data.beacon_data.superframe_spec);

#if (_DEBUG_ > 0)
            retval_t set_status =
#endif
            set_tal_pib_internal(macBeaconOrder, (void *)&beacon_order);

#if (_DEBUG_ > 0)
            Assert(MAC_SUCCESS == set_status);
#endif
            superframe_order =
                GET_SUPERFRAME_ORDER(mac_parse_data.mac_payload_data.beacon_data.superframe_spec);
#if (_DEBUG_ > 0)
            set_status =
#endif
            set_tal_pib_internal(macSuperframeOrder, (void *)&superframe_order);

#if (_DEBUG_ > 0)
            Assert(MAC_SUCCESS == set_status);
#endif

            mac_final_cap_slot =
            GET_FINAL_CAP(mac_parse_data.mac_payload_data.beacon_data.superframe_spec);

            /*
             * In a beacon-enabled network with the batterylife extension
             * enabled, the first backoff slot boundary is computed after the
             * end of the beacon's IFS
             */
            if ((tal_pib.BeaconOrder < NON_BEACON_NWK) && tal_pib.BattLifeExt)
            {
                /* Length given in octets */
                beacon_length = mac_parse_data.mpdu_length + PHY_OVERHEAD;

                /* Convert to symbols */
                beacon_length *= SYMBOLS_PER_OCTET;

                /* Space needed for IFS is added to it */
                if (mac_parse_data.mpdu_length <= aMaxSIFSFrameSize)
                {
                    beacon_length += macMinSIFSPeriod_def;
                }
                else
                {
                    beacon_length += macMinLIFSPeriod_def;
                }

                /* Round up to backoff slot boundary */
                beacon_length = (beacon_length + aUnitBackoffPeriod - 1) / aUnitBackoffPeriod;
                beacon_length *= aUnitBackoffPeriod;

                /*
                 * Slotted CSMA-CA with macBattLifeExt must start within
                 * the first macBattLifeExtPeriods backoff slots of the CAP
                 */
                beacon_length += mac_pib.mac_BattLifeExtPeriods * aUnitBackoffPeriod;
            }
        }   /* (MAC_PAN_COORD_STARTED != mac_state) */
    }   /* (MAC_SCAN_IDLE == mac_scan_state) */
#endif  /* BEACON_SUPPORT */

    /*
     * The following section needs to be done when we are
     * either scanning (and look for a new PAN descriptor to be returned
     * as part of the scan confirm message),
     * or we need to create a beacon notification (in which case we are
     * interested in any beacon, but omit the generation of scan confirm).
     */
    {
        uint8_t index;

        /*
         * If we are scanning a scan confirm needs to be created.
         *
         * According to 802.15.4-2006 this is only done in case the PIB
         * attribute macAutoRequest is true. Otherwise the PAN descriptor will
         * NOT be put into the PAN descriptor list of the Scan confirm message.
         */
        if (
            ((MAC_SCAN_ACTIVE == mac_scan_state) || (MAC_SCAN_PASSIVE == mac_scan_state)) &&
            mac_pib.mac_AutoRequest
           )
        {
            /*
             * mac_conf_buf_ptr points to the buffer allocated for scan
             * confirmation.
             */
             msc =  (mlme_scan_conf_t *)BMM_BUFFER_POINTER(
                        ((buffer_t *)mac_conf_buf_ptr));

            /*
             * The PAN descriptor list is updated with the PANDescriptor of the
             * received beacon
             */
            pand_long_start_p = (wpan_pandescriptor_t *)&msc->scan_result_list;
        }

        /*
         * The beacon data received from the parse variable is arranged
         * into a PAN descriptor structure style
         */
        pand_long.CoordAddrSpec.AddrMode = mac_parse_data.src_addr_mode;
        pand_long.CoordAddrSpec.PANId = mac_parse_data.src_panid;

        if (FCF_SHORT_ADDR == pand_long.CoordAddrSpec.AddrMode)
        {
            /* Initially clear the complete address. */
            pand_long.CoordAddrSpec.Addr.long_address = 0;

            ADDR_COPY_DST_SRC_16(pand_long.CoordAddrSpec.Addr.short_address, mac_parse_data.src_addr.short_address);
        }
        else
        {
            ADDR_COPY_DST_SRC_64(pand_long.CoordAddrSpec.Addr.long_address, mac_parse_data.src_addr.long_address);
        }

        pand_long.LogicalChannel = tal_pib.CurrentChannel;
        pand_long.ChannelPage    = tal_pib.CurrentPage;
        pand_long.SuperframeSpec = mac_parse_data.mac_payload_data.beacon_data.superframe_spec;
        pand_long.GTSPermit      = mac_parse_data.mac_payload_data.beacon_data.gts_spec >> 7;
        pand_long.LinkQuality    = mac_parse_data.ppdu_link_quality;
#ifdef ENABLE_TSTAMP
        pand_long.TimeStamp      = mac_parse_data.time_stamp;
#endif  /* ENABLE_TSTAMP */

        /*
         * If we are scanning we need to check whether this is a new
         * PAN descriptor.
         *
         * According to 802.15.4-2006 this is only done in case the PIB
         * attribute macAutoRequest is true. Otherwise the PAN descriptor will
         * NOT be put into the PAN descriptor list of the Scan confirm message.
         */
        if (
            ((MAC_SCAN_ACTIVE == mac_scan_state) || (MAC_SCAN_PASSIVE == mac_scan_state)) &&
            mac_pib.mac_AutoRequest
           )
        {
            /*
             * This flag is used to indicate a match of the current (received) PAN
             * descriptor with one of those present already in the list.
             */
            matchflag = false;

            /*
             * The beacon frame PAN descriptor is compared with the PAN descriptors
             * present in the list and determine if the current PAN
             * descriptor is to be taken as a valid one. A PAN is considered to be
             * the same as an existing one, if all, the PAN Id, the coordinator address
             * mode, the coordinator address, and the Logical Channel are same.
             */
            for (index = 0; index < msc->ResultListSize; index++, pand_long_start_p++)
            {
                if ((pand_long.CoordAddrSpec.PANId == pand_long_start_p->CoordAddrSpec.PANId) &&
                    (pand_long.CoordAddrSpec.AddrMode == pand_long_start_p->CoordAddrSpec.AddrMode) &&
                    (pand_long.LogicalChannel == pand_long_start_p->LogicalChannel) &&
                    (pand_long.ChannelPage == pand_long_start_p->ChannelPage)
                   )
                {
                    if (pand_long.CoordAddrSpec.AddrMode == WPAN_ADDRMODE_SHORT)
                    {
                        if (pand_long.CoordAddrSpec.Addr.short_address == pand_long_start_p->CoordAddrSpec.Addr.short_address)
                        {
                            /* Beacon with same parameters already received */
                            matchflag = true;
                            break;
                        }
                    }
                    else
                    {
                        if (pand_long.CoordAddrSpec.Addr.long_address == pand_long_start_p->CoordAddrSpec.Addr.long_address)
                        {
                            /* Beacon with same parameters already received */
                            matchflag = true;
                            break;
                        }
                    }
                }
            }

            /*
             * If the PAN descriptor is not in the current list, and there is space
             * left, it is put into the list
             */
            if ((!matchflag) && (msc->ResultListSize < MAX_PANDESCRIPTORS))
            {
                memcpy(pand_long_start_p, &pand_long, sizeof(pand_long));
                msc->ResultListSize++;
            }
        }
    }


#if ((MAC_BEACON_NOTIFY_INDICATION == 1) || \
     ((MAC_INDIRECT_DATA_BASIC == 1) && (MAC_SYNC_REQUEST == 1)) \
    )
    /* The short and extended pending addresses are extracted from the beacon */
    numaddrshort =
        NUM_SHORT_PEND_ADDR(mac_parse_data.mac_payload_data.beacon_data.pending_addr_spec);

    numaddrlong =
        NUM_LONG_PEND_ADDR(mac_parse_data.mac_payload_data.beacon_data.pending_addr_spec);
#endif

#if (MAC_BEACON_NOTIFY_INDICATION == 1)
    /*
     * In all cases (PAN or device) if the payload is not equal to zero
     * or macAutoRequest is false, MLME_BEACON_NOTIFY.indication is
     * generated
     */
    if ((mac_parse_data.mac_payload_data.beacon_data.beacon_payload_len > 0) ||
        (!mac_pib.mac_AutoRequest)
       )
    {
        mlme_beacon_notify_ind_t *mbni =
            (mlme_beacon_notify_ind_t *)BMM_BUFFER_POINTER(((buffer_t *)beacon));

        /* The beacon notify indication structure is built */
        mbni->cmdcode       = MLME_BEACON_NOTIFY_INDICATION;
        mbni->BSN           = mac_parse_data.sequence_number;
        mbni->PANDescriptor = pand_long;
        mbni->PendAddrSpec  = mac_parse_data.mac_payload_data.beacon_data.pending_addr_spec;

        if ((numaddrshort > 0) || (numaddrlong > 0))
        {
            mbni->AddrList = mac_parse_data.mac_payload_data.beacon_data.pending_addr_list;
        }

        mbni->sduLength = mac_parse_data.mac_payload_data.beacon_data.beacon_payload_len;
        mbni->sdu = mac_parse_data.mac_payload_data.beacon_data.beacon_payload;

        /*
         * The beacon notify indication is given to the NHLE and then the buffer
         * is freed up.
         */
        qmm_queue_append(&mac_nhle_q, (buffer_t *)beacon);
    }
    else
#endif /* (MAC_BEACON_NOTIFY_INDICATION == 1) */
    {
        /* Payload is not present, hence the buffer is freed here */
        bmm_buffer_free(beacon);
    }


/* Handling of ancounced broadcast traffic by the parent. */
#ifdef BEACON_SUPPORT
    if (MAC_SCAN_IDLE == mac_scan_state)
    {
        /*
         * In case this is a beaconing network, and this node is not scanning,
         * and the FCF indicates pending data thus indicating broadcast data at
         * parent, the node needs to be awake until the received broadcast
         * data has been received.
         */
        if (mac_parse_data.fcf & FCF_FRAME_PENDING)
        {
            mac_bc_data_indicated = true;

            /*
             * Start timer since the broadcast frame is expected within
             * macMaxFrameTotalWaitTime symbols.
             */
            if (MAC_POLL_IDLE == mac_poll_state)
            {
                /*
                 * If the poll state is not idle, there is already an
                 * indirect transaction ongoing.
                 * Since the T_Poll_Wait_Time is going to be re-used,
                 * this timer can only be started, if we are not in
                 * a polling state other than idle.
                 */
                uint32_t response_timer = mac_pib.mac_MaxFrameTotalWaitTime;
                response_timer = TAL_CONVERT_SYMBOLS_TO_US(response_timer);

                if (MAC_SUCCESS != pal_timer_start(T_Poll_Wait_Time,
                                                   response_timer,
                                                   TIMEOUT_RELATIVE,
                                                   (FUNC_PTR)mac_t_wait_for_bc_time_cb,
                                                   NULL))
                {
                    mac_t_wait_for_bc_time_cb(NULL);
                }
            }
            else
            {
                /*
                 * Any indirect poll operation is ongoing, so the timer will
                 * not be started, i.e. nothing to be done here.
                 * Once this ongoing indirect transaction has finished, this
                 * node will go back to sleep anyway.
                 */
            }
        }
        else
        {
            mac_bc_data_indicated = false;
        }

    }   /* (MAC_SCAN_IDLE == mac_scan_state) */
#endif /* BEACON_SUPPORT */


/* Handling of presented indirect traffic by the parent for this node. */
#if ((MAC_INDIRECT_DATA_BASIC == 1) && (MAC_SYNC_REQUEST == 1))
    if (MAC_SCAN_IDLE == mac_scan_state)
    {
        /*
         * If this node is NOT scanning, and is doing a mlme_sync_request,
         * then the pending address list of the beacon is examined to see
         * if the node's parent has data for this node.
         */
        if (mac_pib.mac_AutoRequest)
        {
            if (MAC_SYNC_NEVER != mac_sync_state)
            {
                uint8_t index;
#if (_DEBUG_ > 0)
                bool status;
#endif
                /*
                 * Short address of the device is compared with the
                 * pending short address in the beacon frame
                 */

                /*
                 * PAN-ID and CoordAddress does not have to be checked here,
                 * since the device is already synced with the coordinator, and
                 * only beacon frames passed from data_ind.c (where the first level
                 * filtering is already done) are received. The pending addresses
                 * in the beacon frame are compared with the device address. If a
                 * match is found, it indicates that a data belonging to this
                 * deivce is present with the coordinator and hence a data request
                 * is sent to the coordinator.
                 */
                uint16_t cur_short_addr;

                for (index = 0; index < numaddrshort; index++)
                {
                    cur_short_addr = convert_byte_array_to_16_bit((mac_parse_data.mac_payload_data.beacon_data.pending_addr_list +
                                                    index * sizeof(uint16_t)));
                    if (cur_short_addr == tal_pib.ShortAddress)
                    {
                        /*
                         * Device short address matches with one of the address
                         * in the beacon address list. Implicit poll (using the
                         * device short address) is done to get the pending data
                         */
#if (_DEBUG_ > 0)
                        status =
#endif
                            mac_build_and_tx_data_req(false, false, 0, NULL, 0);

#if (_DEBUG_ > 0)
                        Assert(status == true);
#endif
                        return;
                    }
                }

                /*
                 * Extended address of the device is compared with
                 * the pending extended address in the beacon frame
                 */
                uint64_t cur_long_addr;

                for (index = 0; index < numaddrlong; index++)
                {
                    cur_long_addr = convert_byte_array_to_64_bit((mac_parse_data.mac_payload_data.beacon_data.pending_addr_list +
                                                    numaddrshort * sizeof(uint16_t) + index * sizeof(uint64_t)));

                    if (cur_long_addr == tal_pib.IeeeAddress)
                    {
                        /*
                         * Device extended address matches with one of the
                         * address in the beacon address list. Implicit poll
                         * (using the device extended address) is done to get
                         * the pending data
                         */
#if (_DEBUG_ > 0)
                        status =
#endif
                            mac_build_and_tx_data_req(false, true, 0, NULL, 0);


#if (_DEBUG_ > 0)
                        Assert(status == true);
#endif
                        return;
                    }
                }
            }
        }   /* (mac_pib.mac_AutoRequest) */
    }   /* (MAC_SCAN_IDLE == mac_scan_state) */
#endif /* (MAC_INDIRECT_DATA_BASIC == 1) && (MAC_SYNC_REQUEST == 1)) */
} /* mac_process_beacon_frame() */
Пример #16
0
/**
 * \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;
}
Пример #17
0
/**
 * @brief Conversion of symbols to microseconds
 */
uint32_t tal_convert_symbols_to_us_def(uint32_t symbols)
{
	return (TAL_CONVERT_SYMBOLS_TO_US(symbols));
}
Пример #18
0
/*
 * \brief Implements the handling of the transmission end.
 *
 * This function handles the callback for the transmission end.
 */
void tx_done_handling(void)
{
	tal_state = TAL_IDLE;

#if (defined BEACON_SUPPORT) || (defined ENABLE_TSTAMP)

	/*
	 * The entire timestamp calculation is only required for beaconing
	 *networks
	 * or if timestamping is explicitly enabled.
	 */

	/* Calculate negative offset of timestamp */
	uint16_t offset;

	/* Calculate the tx time */
	offset
		= TAL_CONVERT_SYMBOLS_TO_US(
			(PHY_OVERHEAD + LENGTH_FIELD_LEN) * SYMBOLS_PER_OCTET)
			+ TAL_PSDU_US_PER_OCTET(*tal_frame_to_tx + FCS_LEN)
			+ IRQ_PROCESSING_DLY_US;
	if (mac_frame_ptr->mpdu[PL_POS_FCF_1] & FCF_ACK_REQUEST) {
		/* Tx timestamp needs to be reduced by ACK duration etc. */
		offset
			+= TAL_CONVERT_SYMBOLS_TO_US(
				(PHY_OVERHEAD +
				LENGTH_FIELD_LEN) * SYMBOLS_PER_OCTET) +
				TAL_PSDU_US_PER_OCTET(ACK_PAYLOAD_LEN +
				FCS_LEN);

#ifdef HIGH_DATA_RATE_SUPPORT
		if (tal_pib.CurrentPage == 0) {
			offset += TAL_CONVERT_SYMBOLS_TO_US(aTurnaroundTime);
		} else {
			offset += 32;
		}

#else
		offset += TAL_CONVERT_SYMBOLS_TO_US(aTurnaroundTime);
#endif  /* #ifdef HIGH_DATA_RATE_SUPPORT */
	}
	mac_frame_ptr->time_stamp -= offset;
#endif  /* #if (defined BEACON_SUPPORT) || (defined ENABLE_TSTAMP) */

	retval_t status;

	switch (trx_trac_status) {
	case TRAC_SUCCESS:
		status = MAC_SUCCESS;
		break;

	case TRAC_SUCCESS_DATA_PENDING:
		status = TAL_FRAME_PENDING;
		break;

	case TRAC_CHANNEL_ACCESS_FAILURE:
		status = MAC_CHANNEL_ACCESS_FAILURE;
		break;

	case TRAC_NO_ACK:
		status = MAC_NO_ACK;
		break;

	case TRAC_INVALID:
		status = FAILURE;
		break;

	default:
		Assert("Unexpected tal_tx_state" == 0);
		status = FAILURE;
		break;
	}

	tal_tx_frame_done_cb(status, mac_frame_ptr);
} /* tx_done_handling() */
Пример #19
0
/**
 * @brief Continue scanning after setting of PIB attributes
 *
 * This functions continues scanning once the corresponding PIB
 * attribute change has been completed depending on the status.
 *
 * @param set_status Status of the Request to change the PIB attribute
 */
void scan_set_complete(retval_t set_status)
{
	switch (mac_scan_state) {
#if (MAC_SCAN_ED_REQUEST_CONFIRM == 1)
	case MAC_SCAN_ED:
	{
		if (MAC_SUCCESS == set_status) {
			MAKE_MAC_BUSY();
			tal_ed_start(scan_duration);
		} else {
			/* Channel not supported, continue. */
			scan_curr_channel++;
		}
	}
	break;
#endif /* (MAC_SCAN_ED_REQUEST_CONFIRM == 1) */

#if (MAC_SCAN_ACTIVE_REQUEST_CONFIRM == 1)
	case MAC_SCAN_ACTIVE:
		if (MAC_SUCCESS == set_status) {
			/*
			 * The TAL switches ON the transmitter while sending a
			 * beacon request, hence the MAC can call
			 * send_scan_cmd() to send
			 * the beacon directly
			 */

			/* Send an beacon request command */
			if (!send_scan_cmd(true)) {
				uint8_t timer_id = T_Scan_Duration;

				/*
				 * Beacon request could not be transmitted
				 * since there is no buffer available stop
				 * scanning
				 * we call the function usually called by the
				 * scan
				 * duration timer to pretend scanning has
				 * finished
				 */
				mac_t_scan_duration_cb((uint8_t *)&timer_id);
			}
		} else {
			/* Channel not supported, continue. */
			scan_curr_channel++;
		}
		break;
#endif /* (MAC_SCAN_ACTIVE_REQUEST_CONFIRM == 1) */

#if (MAC_SCAN_PASSIVE_REQUEST_CONFIRM == 1)
	case MAC_SCAN_PASSIVE:
	{
		if (MAC_SUCCESS == set_status) {
			uint8_t status = tal_rx_enable(PHY_RX_ON);

			if (PHY_RX_ON == status) {
				retval_t timer_status;
				uint32_t tmr
					= MAC_CALCULATE_SYMBOL_TIME_SCANDURATION(
						scan_duration);

				timer_status = pal_timer_start(T_Scan_Duration,
						TAL_CONVERT_SYMBOLS_TO_US(
						tmr),
						TIMEOUT_RELATIVE,
						(FUNC_PTR)mac_t_scan_duration_cb,
						NULL);
#if (_DEBUG_ > 0)
				Assert(MAC_SUCCESS == timer_status);
#endif
				if (MAC_SUCCESS != timer_status) {
					uint8_t timer_id = T_Scan_Duration;

					/*
					 * Scan duration timer could not be
					 * started so we
					 * call the timer callback function
					 * directly this
					 * will basically shorten scanning
					 * without having
					 * really scanned.
					 */
					mac_t_scan_duration_cb((void *)&timer_id);
				}
			} else {
				/* Did not work, continue. */
				scan_curr_channel++;
				scan_proceed(MLME_SCAN_TYPE_PASSIVE,
						(buffer_t *)mac_conf_buf_ptr);
			}
		} else {
			/* Channel not supported, continue. */
			scan_curr_channel++;
		}
	}
	break;
#endif /* (MAC_SCAN_PASSIVE_REQUEST_CONFIRM == 1) */

#if (MAC_SCAN_ORPHAN_REQUEST_CONFIRM == 1)
	case MAC_SCAN_ORPHAN:
		if (MAC_SUCCESS == set_status) {
			/* Send an orphan notification command */
			if (!send_scan_cmd(false)) {
				uint8_t timer_id = T_Scan_Duration;

				/*
				 * Orphan notification could not be transmitted
				 * since there
				 * is no buffer available stop scanning
				 * we call the function usually called by the
				 * scan duration
				 * timer to pretend scanning has finished
				 */
				mac_t_scan_duration_cb((uint8_t *)&timer_id);
			}
		} else {
			/* Channel not supported, continue. */
			scan_curr_channel++;
		}
		break;
#endif /* (MAC_SCAN_ORPHAN_REQUEST_CONFIRM == 1) */

	default:
		break;
	}
} /* scan_set_complete() */
Пример #20
0
/**
 * \brief Interrupt handler for ACK reception
 *
 * \param parameter Unused callback parameter
 */
static void ack_reception_handler_cb(void *parameter)
{
	trx_irq_reason_t trx_irq_cause;

	if (tal_csma_state == TX_DONE_NO_ACK) {
		return; /* ack expiration timer has already been fired */
	}

	trx_irq_cause = (trx_irq_reason_t)pal_trx_reg_read(RG_IRQ_STATUS);

	if (trx_irq_cause & TRX_IRQ_TRX_END) {
		retval_t timer_status;

		switch (tal_csma_state) {
		case FRAME_SENDING_WITH_ACK:
			set_trx_state(CMD_RX_ON);

			timer_status
				= pal_timer_start(TAL_ACK_WAIT_TIMER,
					TAL_CONVERT_SYMBOLS_TO_US(
					TAL_ACK_WAIT_DURATION_DEFAULT),
					TIMEOUT_RELATIVE,
					(FUNC_PTR)ack_timer_expiry_handler_cb,
					NULL);

			if (timer_status == MAC_SUCCESS) {
				tal_csma_state = WAITING_FOR_ACK;
			} else if (timer_status == PAL_TMR_ALREADY_RUNNING) {
				tal_csma_state = WAITING_FOR_ACK;
			} else {
				tal_csma_state = TX_DONE_NO_ACK;
				Assert("timer start failed" == 0);
			}

			/* debug pin to switch on: define ENABLE_DEBUG_PINS,
			 *pal_config.h */
			PIN_TX_END();
			PIN_ACK_WAITING_START();
			break;

		case WAITING_FOR_ACK:
		{
			uint8_t ack_frame[ACK_FRAME_LEN + LENGTH_FIELD_LEN];

			/*
			 * Read the frame buffer, identify if this is an ACK
			 *frame,
			 * and get the sequence number.
			 * Üpload the frame from the transceiver.
			 */
			pal_trx_frame_read(ack_frame,
					(ACK_FRAME_LEN +
					LENGTH_FIELD_LEN));

			/* Check if the uploaded frame is an ACK frame */
			if ((ack_frame[1] & ACK_FRAME) != ACK_FRAME) {
				/* The received frame is not an ACK frame */
				return;
			}

			/* check CRC */
			if (pal_trx_bit_read(SR_RX_CRC_VALID) != CRC16_VALID) {
				return;
			}

			/* check the sequence number */
			if (ack_frame[3] == tal_frame_to_tx[SEQ_NUMBER_POS]) {
				/*
				 * If we are here, the ACK is valid and matches
				 * the transmitted sequence number.
				 */
				pal_timer_stop(TAL_ACK_WAIT_TIMER);
#if (_DEBUG_ > 0)
				if (pal_is_timer_running(TAL_ACK_WAIT_TIMER)) {
					Assert("Ack timer running" == 0);
				}

#endif
				/* restore the interrupt handler */
				pal_trx_irq_init((FUNC_PTR)trx_irq_handler_cb);
				pal_trx_irq_en();

				if (NULL != tal_rx_buffer) {
					pal_trx_reg_write(RG_TRX_STATE,
							CMD_RX_AACK_ON);
				} else {
					tal_rx_on_required = true;
				}

				/* debug pin to switch on: define
				 *ENABLE_DEBUG_PINS, pal_config.h */
				PIN_ACK_OK_START();

				if (ack_frame[1] & FCF_FRAME_PENDING) {
					tal_csma_state = TX_DONE_FRAME_PENDING;
				} else {
					tal_csma_state = TX_DONE_SUCCESS;
				}

				/* debug pin to switch on: define
				 *ENABLE_DEBUG_PINS, pal_config.h */
				PIN_ACK_OK_END();
				PIN_ACK_WAITING_END();
			}
		}
		break;

		case FRAME_SENDING_NO_ACK:
			/* Tx is done */
			/* debug pin to switch on: define ENABLE_DEBUG_PINS,
			 *pal_config.h */
			PIN_TX_END();
			tal_csma_state = TX_DONE_SUCCESS;
			break;

		default:
			Assert("unknown tal_csma_state" == 0);
			break;
		}
	} else { /* other interrupt than TRX_END */
		/* no interest in any other interrupt */
		return;
	}

	parameter = parameter; /* Keep compiler happy. */
}
Пример #21
0
/*
 * \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
}
Пример #22
0
/**
 * @brief Continues processing a data indication from the TAL for
 *        non-polling and non-scanning states of the MAC
 *        (mac_poll_state == MAC_POLL_IDLE, mac_scan_state == MAC_SCAN_IDLE).
 *
 * @param b_ptr Pointer to the buffer header.
 * @param f_ptr Pointer to the frame_info_t structure.
 *
 * @return bool True if frame has been processed, or false otherwise.
 */
static bool process_data_ind_not_transient(buffer_t *b_ptr, frame_info_t *f_ptr)
{
	bool processed_in_not_transient = false;

	/*
	 * We are in MAC_POLL_IDLE and MAC_SCAN_IDLE now,
	 * so continue with the real MAC states.
	 */
	switch (mac_state) {
#if (MAC_START_REQUEST_CONFIRM == 1)
	case MAC_PAN_COORD_STARTED:
	{
		switch (mac_parse_data.frame_type) {
		case FCF_FRAMETYPE_MAC_CMD:
		{
			switch (mac_parse_data.mac_command) {
#if (MAC_ASSOCIATION_INDICATION_RESPONSE == 1)
			case ASSOCIATIONREQUEST:
				mac_process_associate_request(b_ptr);
				processed_in_not_transient = true;
				break;
#endif /* (MAC_ASSOCIATION_INDICATION_RESPONSE == 1) */

#if (MAC_DISASSOCIATION_BASIC_SUPPORT == 1)
			case DISASSOCIATIONNOTIFICATION:
				mac_process_disassociate_notification(b_ptr);
				processed_in_not_transient = true;
				break;
#endif /* (MAC_DISASSOCIATION_BASIC_SUPPORT == 1) */

#if (MAC_INDIRECT_DATA_FFD == 1)
			case DATAREQUEST:
				if (indirect_data_q.size > 0) {
					mac_process_data_request(b_ptr);
					processed_in_not_transient = true;
				} else {
					mac_handle_tx_null_data_frame();
				}
				break;
#endif /* (MAC_INDIRECT_DATA_FFD == 1) */

#if (MAC_ORPHAN_INDICATION_RESPONSE == 1)
			case ORPHANNOTIFICATION:
				mac_process_orphan_notification(b_ptr);
				processed_in_not_transient = true;
				break;
#endif /* (MAC_ORPHAN_INDICATION_RESPONSE == 1) */

			case BEACONREQUEST:
				mac_process_beacon_request(b_ptr);
				processed_in_not_transient = true;
				break;

#if (MAC_PAN_ID_CONFLICT_AS_PC == 1)
			case PANIDCONFLICTNOTIFICAION:
				mac_sync_loss(MAC_PAN_ID_CONFLICT);
				break;

#endif  /* (MAC_PAN_ID_CONFLICT_AS_PC == 1) */
#ifdef GTS_SUPPORT
			case GTSREQUEST:
				mac_process_gts_request(b_ptr);
				processed_in_not_transient = true;
#endif /* GTS_SUPPORT */

			default:
				break;
			}
		}
		break;

		case FCF_FRAMETYPE_DATA:
			mac_process_data_frame(b_ptr);
			processed_in_not_transient = true;
			break;

#if (MAC_PAN_ID_CONFLICT_AS_PC == 1)
		case FCF_FRAMETYPE_BEACON:
			/* PAN-Id conflict detection as PAN-Coordinator. */
			/* Node is not scanning. */
			check_for_pan_id_conflict_as_pc(false);
			break;
#endif  /* (MAC_PAN_ID_CONFLICT_AS_PC == 1) */

		default:
			break;
		}
	}
	break;
		/* MAC_PAN_COORD_STARTED */
#endif /* (MAC_START_REQUEST_CONFIRM == 1) */

	case MAC_IDLE:
#if (MAC_ASSOCIATION_REQUEST_CONFIRM == 1)
	case MAC_ASSOCIATED:
#endif /* (MAC_ASSOCIATION_REQUEST_CONFIRM == 1) */
#if (MAC_START_REQUEST_CONFIRM == 1)
	case MAC_COORDINATOR:
#endif /* (MAC_START_REQUEST_CONFIRM == 1) */
		{
			/* Is it a Beacon from our parent? */
			switch (mac_parse_data.frame_type) {
#if (MAC_SYNC_REQUEST == 1)
			case FCF_FRAMETYPE_BEACON:
			{
				uint32_t beacon_tx_time_symb;

				/* Check for PAN-Id conflict being NOT a PAN
				 * Corodinator. */
#if (MAC_PAN_ID_CONFLICT_NON_PC == 1)
				if (mac_pib.mac_AssociatedPANCoord &&
						(MAC_IDLE !=
						mac_state)) {
					check_for_pan_id_conflict_non_pc(false);
				}

#endif  /* (MAC_PAN_ID_CONFLICT_NON_PC == 1) */

				/* Check if the beacon is received from my
				 * parent. */
				if ((mac_parse_data.src_panid ==
						tal_pib.PANId) &&
						(((mac_parse_data.src_addr_mode
						== FCF_SHORT_ADDR) &&
						(mac_parse_data.src_addr.
						short_address ==
						mac_pib.mac_CoordShortAddress))
						||
						((mac_parse_data.src_addr_mode
						== FCF_LONG_ADDR) &&
						(mac_parse_data.src_addr.
						long_address ==
						mac_pib.mac_CoordExtendedAddress))))
				{
					beacon_tx_time_symb
						= TAL_CONVERT_US_TO_SYMBOLS(
							f_ptr->time_stamp);

#if (_DEBUG_ > 0)
					retval_t set_status =
#endif
					set_tal_pib_internal(macBeaconTxTime,
							(void *)&beacon_tx_time_symb);
#if (_DEBUG_ > 0)
					Assert(MAC_SUCCESS == set_status);
#endif
					if ((MAC_SYNC_TRACKING_BEACON ==
							mac_sync_state)
							||
							(MAC_SYNC_BEFORE_ASSOC
							==
							mac_sync_state)
							) {
						uint32_t nxt_bcn_tm;
						uint32_t beacon_int_symb;

						/* Process a received beacon. */
						mac_process_beacon_frame(b_ptr);

						/* Initialize beacon tracking
						 * timer. */
						{
							retval_t tmr_start_res
								= FAILURE;

#ifdef BEACON_SUPPORT
							if (tal_pib.BeaconOrder
									<
									NON_BEACON_NWK)
							{
								beacon_int_symb
									=
										TAL_GET_BEACON_INTERVAL_TIME(
										tal_pib.BeaconOrder);
							} else
#endif /* BEACON_SUPPORT */
							{
								beacon_int_symb
									=
										TAL_GET_BEACON_INTERVAL_TIME(
										BO_USED_FOR_MAC_PERS_TIME);
							}

							pal_timer_stop(
									T_Beacon_Tracking_Period);

#if (_DEBUG_ > 0)
							if (pal_is_timer_running(
									T_Beacon_Tracking_Period))
							{
								Assert(
										"Bcn tmr running" ==
										0);
							}

#endif

							do {
								/*
								 * Calculate the
								 * time for next
								 * beacon
								 * transmission
								 */
								beacon_tx_time_symb
									=
										tal_add_time_symbols(
										beacon_tx_time_symb,
										beacon_int_symb);

								/*
								 * Take into
								 * account the
								 * time taken by
								 * the radio to
								 * wakeup from
								 * sleep state
								 */
								nxt_bcn_tm
									=
										tal_sub_time_symbols(
										beacon_tx_time_symb,
										TAL_RADIO_WAKEUP_TIME_SYM <<
										(
											tal_pib
											.
											BeaconOrder
											+
											2));

								tmr_start_res
									=
										pal_timer_start(
										T_Beacon_Tracking_Period,
										TAL_CONVERT_SYMBOLS_TO_US(
										nxt_bcn_tm),
										TIMEOUT_ABSOLUTE,
										(
											FUNC_PTR)mac_t_tracking_beacons_cb,
										NULL);
							} while (MAC_SUCCESS !=
									tmr_start_res);
							#ifdef GTS_DEBUG
							port_pin_toggle_output_level(
									DEBUG_PIN1);
							port_pin_set_output_level(
									DEBUG_PIN2,
									0);
							#endif
						}

						/*
						 * Initialize superframe timer
						 * if required only
						 * for devices because
						 * Superframe timer is already
						 * running for
						 * coordinator.
						 */
						/* TODO */

						if (MAC_ASSOCIATED ==
								mac_state) {
							mac_superframe_state
								= MAC_ACTIVE_CAP;

							/* Check whether the
							 * radio needs to be
							 * woken up. */
							mac_trx_wakeup();

							/* Set transceiver in rx
							 * mode, otherwise it
							 * may stay in
							 * TRX_OFF). */
							tal_rx_enable(PHY_RX_ON);

							if (tal_pib.
									SuperFrameOrder
									<
									tal_pib
									.
									BeaconOrder)
							{
								pal_timer_start(
										T_Superframe,
										TAL_CONVERT_SYMBOLS_TO_US(
										TAL_GET_SUPERFRAME_DURATION_TIME(
										tal_pib
										.
										SuperFrameOrder)),
										TIMEOUT_RELATIVE,
										(
											FUNC_PTR)mac_t_start_inactive_device_cb,
										NULL);
								#ifdef GTS_DEBUG
								port_pin_set_output_level(
										DEBUG_PIN2,
										1);
								#endif
							}

#ifdef GTS_SUPPORT
							if (mac_final_cap_slot <
									FINAL_CAP_SLOT_DEFAULT)
							{
								uint32_t
										gts_tx_time
									= (
									TAL_CONVERT_SYMBOLS_TO_US(
									TAL_GET_SUPERFRAME_DURATION_TIME(
									tal_pib
									.
									SuperFrameOrder))
									>>
									4)
										* (
									mac_final_cap_slot
									+
									1);

								pal_timer_start(
										T_CAP, gts_tx_time,
										TIMEOUT_RELATIVE,
										(
											FUNC_PTR)mac_t_gts_cb,
										NULL);
							#ifdef GTS_DEBUG
								port_pin_set_output_level(
										DEBUG_PIN3,
										1);
							#endif
							}

#endif /* GTS_SUPPORT */
						}

						/* Initialize missed beacon
						 * timer. */
						mac_start_missed_beacon_timer();

						/* A device that is neither
						 * scanning nor polling shall go
						 * to sleep now. */
						if (
							(MAC_COORDINATOR !=
							mac_state)
							&&
							(MAC_SCAN_IDLE ==
							mac_scan_state)
							&&
							(MAC_POLL_IDLE ==
							mac_poll_state)
							) {
							/*
							 * If the last received
							 * beacon frame from our
							 * parent
							 * has indicated pending
							 * broadbast data, we
							 * need to
							 * stay awake, until the
							 * broadcast data has
							 * been received.
							 */
							if (!
									mac_bc_data_indicated)
							{
								/* Set radio to
								 * sleep if
								 * allowed */
								mac_sleep_trans();
							}
						}
					} else if (MAC_SYNC_ONCE ==
							mac_sync_state) {
						mac_process_beacon_frame(b_ptr);

						/* Do this after processing the
						 * beacon. */
						mac_sync_state = MAC_SYNC_NEVER;

						/* A device that is neither
						 * scanning nor polling shall go
						 * to sleep now. */
						if (
							(MAC_COORDINATOR !=
							mac_state)
							&&
							(MAC_SCAN_IDLE ==
							mac_scan_state)
							&&
							(MAC_POLL_IDLE ==
							mac_poll_state)
							) {
							/*
							 * If the last received
							 * beacon frame from our
							 * parent
							 * has indicated pending
							 * broadbast data, we
							 * need to
							 * stay awake, until the
							 * broadcast data has
							 * been received.
							 */
							if (!
									mac_bc_data_indicated)
							{
								/* Set radio to
								 * sleep if
								 * allowed */
								mac_sleep_trans();
							}
						}
					} else {
						/* Process the beacon frame */
						bmm_buffer_free(b_ptr);
					}

					processed_in_not_transient = true;
				} else {
Пример #23
0
/*
 * \brief Implements the handling of the transmission end.
 *
 * This function handles the callback for the transmission end.
 */
void tx_done_handling(void)
{
    tal_state = TAL_IDLE;

#if (defined BEACON_SUPPORT) || (defined ENABLE_TSTAMP)
#if (DISABLE_TSTAMP_IRQ == 0)
    /*
     * The Tx timestamp IRQ is enabled and provided via DIG2.
     * The actual value is stored within trx_irq_timestamp_handler_cb();
     * see file "tal_irq_handler.c".
     * The value gets stored into the mac_frame_ptr structure during the
     * tx end interrupt; see handle_tx_end_irq().
     * So, here is nothing left to do.
     */
#else   /* (DISABLE_TSTAMP_IRQ == 1) */
    /*
     * The entire timestamp calculation is only required for beaconing networks
     * or if timestamping is explicitly enabled.
     */

    /* Calculate negative offset of timestamp */
    uint16_t offset;

    /* Calculate the tx time */
    offset =
        TAL_CONVERT_SYMBOLS_TO_US((PHY_OVERHEAD + LENGTH_FIELD_LEN) * SYMBOLS_PER_OCTET)
        + TAL_PSDU_US_PER_OCTET(*tal_frame_to_tx + FCS_LEN)
        + TRX_IRQ_DELAY_US;
    if (mac_frame_ptr->mpdu[PL_POS_FCF_1] & FCF_ACK_REQUEST)
    {
        /* Tx timestamp needs to be reduced by ACK duration etc. */
        offset += TAL_CONVERT_SYMBOLS_TO_US((PHY_OVERHEAD + LENGTH_FIELD_LEN) * SYMBOLS_PER_OCTET) +
                  TAL_PSDU_US_PER_OCTET(ACK_PAYLOAD_LEN + FCS_LEN);

        offset += TAL_CONVERT_SYMBOLS_TO_US(aTurnaroundTime);
    }
    mac_frame_ptr->time_stamp -= offset;
#endif  /* #if (DISABLE_TSTAMP_IRQ == 0) */
#endif  /* #if (defined BEACON_SUPPORT) || (defined ENABLE_TSTAMP) */

    retval_t status;

    switch (trx_trac_status)
    {
        case TRAC_SUCCESS:
            status = MAC_SUCCESS;
            break;

        case TRAC_SUCCESS_DATA_PENDING:
            status = TAL_FRAME_PENDING;
            break;

        case TRAC_CHANNEL_ACCESS_FAILURE:
            status = MAC_CHANNEL_ACCESS_FAILURE;
            break;

        case TRAC_NO_ACK:
            status = MAC_NO_ACK;
            break;

        case TRAC_INVALID:
            status = FAILURE;
            break;

        default:
            Assert("Unexpected tal_tx_state" == 0);
            status = FAILURE;
            break;
    }

    tal_tx_frame_done_cb(status, mac_frame_ptr);
} /* tx_done_handling() */
Пример #24
0
/*
 * \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
}
Пример #25
0
/**
 * @brief Performs CCA twice
 */
static uint8_t perform_cca_twice(void)
{
    uint8_t cca_status;
    uint8_t cca_done;
    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);

#ifndef RFD
    if (tal_beacon_transmission)
    {
#if (DEBUG > 0)
        ASSERT("Ongoing beacon transmission, slotted CSMA busy" == 0);
#endif
        return PHY_BUSY;
    }
#endif

    // 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 receiving frames while doing CCA
    pal_trx_bit_write(SR_RX_PDT_DIS, RX_DISABLE); // disable frame reception indication

    // 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);

        pal_trx_reg_write(RG_TRX_STATE, CMD_RX_ON);

        // debug pin to switch on: define ENABLE_DEBUG_PINS, pal_config.h
        PIN_CCA_START();

        /* Start CCA */
        pal_trx_bit_write(SR_CCA_REQUEST, CCA_START);

        // 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;
          cca_done = pal_trx_bit_read(SR_CCA_DONE);
        } while (cca_done != CCA_DETECTION_DONE);

        // between both CCA switch trx to PLL_ON to reduce power consumption
        pal_trx_reg_write(RG_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 (pal_trx_bit_read(SR_CCA_STATUS) == CCA_STATUS_CHANNEL_IS_IDLE)
        {
            // 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;
            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().
     */

    /*
     * Clear CCA interrupt flag.
     * This is only necessary for debugging, because only in debug mode
     * interrupt that are not handled cause an assert in the ISR.
     */
#if (DEBUG > 0)
    pal_trx_reg_read(RG_IRQ_STATUS);
#endif

    /*
     * 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_bit_write(SR_RX_PDT_DIS, RX_ENABLE); // enable frame reception indication

    return cca_status;
}