Exemple #1
0
/*
 * \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;
}
Exemple #2
0
/*
 * \brief Scan done
 *
 * This function updates the max_ed_level and invokes the callback function
 * tal_ed_end_cb().
 *
 * \param parameter unused callback parameter
 */
void ed_scan_done(void)
{
    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 transceiver main interrupt. */

    tal_state = TAL_IDLE;   // ed scan is done
    set_trx_state(CMD_RX_AACK_ON);

#ifndef TRX_REG_RAW_VALUE
    /*
     * Scale ED result.
     * Clip values to 0xFF if > -35dBm
     */
    if (max_ed_level > CLIP_VALUE_REG)
    {
        max_ed_level = 0xFF;
    }
    else
    {
        max_ed_level = (uint8_t)(((uint16_t)max_ed_level * 0xFF) / CLIP_VALUE_REG);
    }
#endif
    tal_ed_end_cb(max_ed_level);
}
Exemple #3
0
/**
 * \brief Sends the frame at the next backoff boundary
 */
static void send_frame_at_next_backoff_boundary(void)
{
	uint8_t ack_is_requested;
	uint32_t now_time_us;

	/*
	 * Locate the next backoff boundary for the frame transmissiom;
	 * this backoff boundary is the starttime for the frame fransmission.
	 * Use a blocking approach, since next backoff boundary should be close.
	 */
	do {
		pal_get_current_time(&now_time_us);
	} while (pal_add_time_us(now_time_us, PRE_TX_DURATION_US) <
			cca_starttime_us);

	/* re-programm the interrupt handler */
	pal_trx_irq_init((FUNC_PTR)ack_reception_handler_cb);
	pal_trx_irq_en();

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

	/* Check if an acknowledgement is requested for this frame. */
	ack_is_requested = *(tal_frame_to_tx + 1) & FCF_ACK_REQUEST;

	if (ack_is_requested > 0) {
		tal_csma_state = FRAME_SENDING_WITH_ACK;
	} else {
		tal_csma_state = FRAME_SENDING_NO_ACK;
	}

	/* download and send frame, no CSMA and no frame_retry */
	send_frame(NO_CSMA_NO_IFS, false);
}
Exemple #4
0
/**
 * \brief Start CCA.
 *
 * \param parameter Unused callback parameter
 */
static void cca_start(void *parameter)
{
	tal_state = TAL_CCA;

	if (set_trx_state(CMD_PLL_ON) == PLL_ON) {
		tal_trx_status_t trx_state;
		/* No interest in receiving frames while doing CCA */
		pal_trx_bit_write(SR_RX_PDT_DIS, RX_DISABLE); /* disable frame
		                                               * reception
		                                               * indication */
		do {
			trx_state = set_trx_state(CMD_RX_ON);
		} while (trx_state != RX_ON);
		/* Setup interrupt handling for CCA IRQ */
		pal_trx_irq_init((FUNC_PTR)cca_done_irq_handler);
		pal_trx_reg_write(RG_IRQ_MASK, TRX_IRQ_CCA_ED_READY); /* enable
		                                                       *CCA
		                                                       *interrupt
		                                                       **/
		/* Start CCA */
		pal_trx_bit_write(SR_CCA_REQUEST, CCA_START);
	} else {
		/* Channel is busy, i.e. device is receiving */
		tal_state = TAL_CSMA_CONTINUE;
	}

	/* Keep compiler happy. */
	parameter = parameter;
}
Exemple #5
0
/**
 * \brief Finalizes the CSMA procedure
 *
 * \param status Result of the slotted transmission
 */
static void tx_done(retval_t status)
{
#if (_DEBUG_ > 0)
	switch (tal_state) {
	case TAL_SLOTTED_CSMA:
	case TAL_TX_BASIC:
		break;

#if ((MAC_START_REQUEST_CONFIRM == 1) && (defined BEACON_SUPPORT))
	case TAL_TX_BEACON:
		Assert("unexpected tal_state TAL_TX_BEACON" == 0);
		return;

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

	default:
		Assert("unexpected tal_state" == 0);
		break;
	}
#endif
#if (_DEBUG_ > 0)
	if (pal_is_timer_running(TAL_CSMA_BEACON_LOSS_TIMER)) {
		Assert("beacon lost timer is still running" == 0);
	}

#endif

	tal_state = TAL_IDLE;
	tal_csma_state = CSMA_IDLE;

	/*
	 * Restore the interrupt handler.
	 * Install a handler for the transceiver interrupt.
	 */
	pal_trx_irq_init((FUNC_PTR)trx_irq_handler_cb);
	pal_trx_reg_read(RG_IRQ_STATUS);

	/* Check if a receive buffer is available. */
	if (NULL != tal_rx_buffer) {
		pal_trx_reg_write(RG_TRX_STATE, CMD_RX_AACK_ON);
	} else {
		tal_rx_on_required = true;
	}

	pal_trx_irq_en();

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

	tal_tx_frame_done_cb(status, mac_frame_ptr);
}
Exemple #6
0
/*
 * \brief handling of CCA result.
 */
void cca_done_handling(void)
{
	set_trx_state(CMD_PLL_ON); /* leave RX_ON */
	/* Restore IRQ handling */
	pal_trx_irq_init((FUNC_PTR)trx_irq_handler_cb);
	pal_trx_reg_write(RG_IRQ_MASK, TRX_IRQ_DEFAULT);
	pal_trx_bit_write(SR_RX_PDT_DIS, RX_ENABLE); /* Enable frame reception.
	                                              **/

	/* Check if channel was idle or busy */
	if (pal_trx_bit_read(SR_CCA_STATUS) == CCA_STATUS_CHANNEL_IS_IDLE) {
		tx_frame();
	} else {
		tal_state = TAL_CSMA_CONTINUE;
	}
}
/**
 * @brief Sets transceiver state
 *
 * @param trx_cmd needs to be one of the trx commands
 *
 * @return current trx state
 */
tal_trx_status_t set_trx_state(trx_cmd_t trx_cmd)
{
    if (tal_trx_status == TRX_SLEEP)
    {
        /*
         * Since the wake-up procedure relies on the Awake IRQ and
         * the global interrupts may be disabled at this point of time,
         * we need to make sure that the global interrupts are enabled
         * during wake-up procedure.
         * Once the TRX is awake, the original state of the global interrupts
         * will be restored.
         */
        /* Reset wake-up interrupt flag. */
        tal_awake_end_flag = false;
        /* Set callback function for the awake interrupt. */
        pal_trx_irq_init(trx_irq_awake_handler_cb);
        /* The pending transceiver interrupts on the microcontroller are cleared. */
        pal_trx_irq_flag_clr();
        pal_trx_irq_en();     /* Enable transceiver main interrupt. */
        /* Save current state of global interrupts. */
        ENTER_CRITICAL_REGION();
        /* Force enabling of global interrupts. */
        ENABLE_GLOBAL_IRQ();
        /* Leave trx sleep mode. */
        PAL_SLP_TR_LOW();
        /* Poll wake-up interrupt flag until set within ISR. */
        while (!tal_awake_end_flag);
        /* Restore original state of global interrupts. */
        LEAVE_CRITICAL_REGION();
        /* Clear existing interrupts */
        pal_trx_reg_read(RG_IRQ_STATUS);
        /* Re-install default IRQ handler for main interrupt. */
        pal_trx_irq_init(trx_irq_handler_cb);
        /* Re-enable TRX_END interrupt */
        pal_trx_reg_write(RG_IRQ_MASK, TRX_IRQ_DEFAULT);
#if (ANTENNA_DIVERSITY == 1)
        /* Enable antenna diversity. */
        pal_trx_bit_write(SR_ANT_EXT_SW_EN, ANT_EXT_SW_ENABLE);
#endif

#ifdef EXT_RF_FRONT_END_CTRL
        /* Enable RF front end control */
        pal_trx_bit_write(SR_PA_EXT_EN, 1);
#endif

        tal_trx_status = TRX_OFF;
        if ((trx_cmd == CMD_TRX_OFF) || (trx_cmd == CMD_FORCE_TRX_OFF))
        {
            return TRX_OFF;
        }
    }
#ifdef ENABLE_DEEP_SLEEP
    else if (tal_trx_status == TRX_DEEP_SLEEP)
    {
        /* Leave trx sleep mode. */
        PAL_SLP_TR_LOW();
        /* Check if trx has left deep sleep. */
        tal_trx_status_t trx_state;
        do
        {
            trx_state = (tal_trx_status_t)pal_trx_reg_read(RG_TRX_STATUS);
        }
        while (trx_state != TRX_OFF);
        tal_trx_status = TRX_OFF;
        /* Using deep sleep, the transceiver's registers need to be restored. */
        trx_config();
        /*
         * Write all PIB values to the transceiver
         * that are needed by the transceiver itself.
         */
        write_all_tal_pib_to_trx(); /* implementation can be found in 'tal_pib.c' */
        if ((trx_cmd == CMD_TRX_OFF) || (trx_cmd == CMD_FORCE_TRX_OFF))
        {
            return TRX_OFF;
        }
    }
#endif

    switch (trx_cmd)    /* requested state */
    {
        case CMD_SLEEP:
#ifdef ENABLE_DEEP_SLEEP
            /* Fall through. */
        case CMD_DEEP_SLEEP:
#endif
            pal_trx_reg_write(RG_TRX_STATE, CMD_FORCE_TRX_OFF);

#if (ANTENNA_DIVERSITY == 1)
            /*
             *  Disable antenna diversity: to reduce the power consumption or
             *  avoid leakage current of an external RF switch during SLEEP.
             */
            pal_trx_bit_write(SR_ANT_EXT_SW_EN, ANT_EXT_SW_DISABLE);
#endif
#ifdef EXT_RF_FRONT_END_CTRL
            /* Disable RF front end control */
            pal_trx_bit_write(SR_PA_EXT_EN, 0);
#endif
            /* Clear existing interrupts */
            pal_trx_reg_read(RG_IRQ_STATUS);
            /*
             * Enable Awake_end interrupt.
             * This is used for save wake-up from sleep later.
             */
            pal_trx_bit_write(SR_IRQ_MASK, TRX_IRQ_4_CCA_ED_DONE);

#ifdef ENABLE_DEEP_SLEEP
            if (trx_cmd == CMD_DEEP_SLEEP)
            {
                pal_trx_reg_write(RG_TRX_STATE, CMD_PREP_DEEP_SLEEP);
                tal_trx_status = TRX_DEEP_SLEEP;
            }
            else
            {
                /*
                 * Enable Awake_end interrupt.
                 * This is used for save wake-up from sleep later.
                 */
                pal_trx_bit_write(SR_IRQ_MASK, TRX_IRQ_4_CCA_ED_DONE);
                tal_trx_status = TRX_SLEEP;
            }
#else
            /*
             * Enable Awake_end interrupt.
             * This is used for save wake-up from sleep later.
             */
            pal_trx_bit_write(SR_IRQ_MASK, TRX_IRQ_4_CCA_ED_DONE);
            tal_trx_status = TRX_SLEEP;
#endif
            PAL_WAIT_1_US();
            PAL_SLP_TR_HIGH();
            pal_timer_delay(TRX_OFF_TO_SLEEP_TIME_CLKM_CYCLES);
            /* Transceiver register cannot be read during TRX_SLEEP or DEEP_SLEEP. */
            return tal_trx_status;

        case CMD_TRX_OFF:
            switch (tal_trx_status)
            {
                case TRX_OFF:
                    break;

                default:
                    pal_trx_reg_write(RG_TRX_STATE, CMD_TRX_OFF);
                    PAL_WAIT_1_US();
                    break;
            }
            break;

        case CMD_FORCE_TRX_OFF:
            switch (tal_trx_status)
            {
                case TRX_OFF:
                    break;

                default:
                    pal_trx_reg_write(RG_TRX_STATE, CMD_FORCE_TRX_OFF);
                    PAL_WAIT_1_US();
                    break;
            }
            break;

        case CMD_PLL_ON:
            switch (tal_trx_status)
            {
                case PLL_ON:
                    break;

                case TRX_OFF:
                    switch_pll_on();
                    break;

                case RX_ON:
                case RX_AACK_ON:
                case TX_ARET_ON:
                    pal_trx_reg_write(RG_TRX_STATE, CMD_PLL_ON);
                    PAL_WAIT_1_US();
                    break;

                case BUSY_RX:
                case BUSY_TX:
                case BUSY_RX_AACK:
                case BUSY_TX_ARET:
                    /* do nothing if trx is busy */
                    break;

                default:
                    ASSERT("state transition not handled" == 0);
                    break;
            }
            break;

        case CMD_FORCE_PLL_ON:
            switch (tal_trx_status)
            {
                case TRX_OFF:
                    switch_pll_on();
                    break;

                case PLL_ON:
                    break;

                default:
                    pal_trx_reg_write(RG_TRX_STATE, CMD_FORCE_PLL_ON);
                    break;
            }
            break;

        case CMD_RX_ON:
            switch (tal_trx_status)
            {
                case RX_ON:
                    break;

                case PLL_ON:
                case RX_AACK_ON:
                case TX_ARET_ON:
                    pal_trx_reg_write(RG_TRX_STATE, CMD_RX_ON);
                    PAL_WAIT_1_US();
                    break;

                case TRX_OFF:
                    switch_pll_on();
                    pal_trx_reg_write(RG_TRX_STATE, CMD_RX_ON);
                    PAL_WAIT_1_US();
                    break;

                case BUSY_RX:
                case BUSY_TX:
                case BUSY_RX_AACK:
                case BUSY_TX_ARET:
                    /* do nothing if trx is busy */
                    break;

                default:
                    ASSERT("state transition not handled" == 0);
                    break;
            }
            break;

        case CMD_RX_AACK_ON:
            switch (tal_trx_status)
            {
                case RX_AACK_ON:
                    break;

                case TX_ARET_ON:
                case PLL_ON:
                case RX_ON:
                    pal_trx_reg_write(RG_TRX_STATE, CMD_RX_AACK_ON);
                    PAL_WAIT_1_US();
                    break;

                case TRX_OFF:
                    switch_pll_on(); // state change from TRX_OFF to RX_AACK_ON can be done directly, too
                    pal_trx_reg_write(RG_TRX_STATE, CMD_RX_AACK_ON);
                    PAL_WAIT_1_US();
                    break;

                case BUSY_RX:
                case BUSY_TX:
                case BUSY_RX_AACK:
                case BUSY_TX_ARET:
                    /* do nothing if trx is busy */
                    break;

                default:
                    ASSERT("state transition not handled" == 0);
                    break;
            }
            break;

        case CMD_TX_ARET_ON:
            switch (tal_trx_status)
            {
                case TX_ARET_ON:
                    break;

                case PLL_ON:
                case RX_ON:
                case RX_AACK_ON:
                    pal_trx_reg_write(RG_TRX_STATE, CMD_TX_ARET_ON);
                    PAL_WAIT_1_US();
                    break;

                case TRX_OFF:
                    switch_pll_on(); // state change from TRX_OFF to TX_ARET_ON can be done directly, too
                    pal_trx_reg_write(RG_TRX_STATE, CMD_TX_ARET_ON);
                    PAL_WAIT_1_US();
                    break;

                case BUSY_RX:
                case BUSY_TX:
                case BUSY_RX_AACK:
                case BUSY_TX_ARET:
                    /* do nothing if trx is busy */
                    break;

                default:
                    ASSERT("state transition not handled" == 0);
                    break;
            }
            break;

        default:
            /* CMD_NOP, CMD_TX_START */
            ASSERT("trx command not handled" == 0);
            break;
    }

    do
    {
        tal_trx_status = (tal_trx_status_t)pal_trx_bit_read(SR_TRX_STATUS);
    }
    while (tal_trx_status == STATE_TRANSITION_IN_PROGRESS);

    return tal_trx_status;
} /* set_trx_state() */
/**
 * @brief Initializes the TAL
 *
 * This function is called to initialize the TAL. The transceiver is
 * initialized, the TAL PIBs are set to their default values, and the TAL state
 * machine is set to TAL_IDLE state.
 *
 * @return MAC_SUCCESS  if the transceiver state is changed to TRX_OFF and the
 *                 current device part number and version number are correct;
 *         FAILURE otherwise
 */
retval_t tal_init(void)
{
    /* Init the PAL and by this means also the transceiver interface */
#ifdef ENABLE_RP
    /*
     * The ranging processor (RP) only performs a minimalistic
     * initialization here.
     */
    pal_basic_init();
#else  /* !ENABLE_RP */
    if (pal_init() != MAC_SUCCESS)
    {
        return FAILURE;
    }

    if (trx_init() != MAC_SUCCESS)
    {
        return FAILURE;
    }

#if (EXTERN_EEPROM_AVAILABLE == 1)
    pal_ps_get(EXTERN_EEPROM, EE_IEEE_ADDR, 8, &tal_pib.IeeeAddress);
#else
    #if (USER_SIGN_AVAILABLE == 1)
        pal_ps_get(USER_SIGNATURE, USER_SIGNATURES_START + 2, 8, &tal_pib.IeeeAddress);
        //http://www.atmel.com/Images/Atmel-42172-Wireless-ZigBit-ATZB-X0-256-3-0-C_Datasheet.pdf
    #else
        pal_ps_get(INTERN_EEPROM, EE_IEEE_ADDR, 8, &tal_pib.IeeeAddress);
    #endif
#endif

    /*
     * Do the reset stuff.
     * Set the default PIBs.
     * Generate random seed.
     */
    if (internal_tal_reset(true) != MAC_SUCCESS)
    {
        return FAILURE;
    }

#ifndef DISABLE_IEEE_ADDR_CHECK
    /* Check if a valid IEEE address is available. */
    /*
     * This while loop is on purpose, since just in the
     * rare case that such an address is randomly
     * generated again, we must repeat this.
     */
    while ((tal_pib.IeeeAddress == 0x0000000000000000) ||
           (tal_pib.IeeeAddress == 0xFFFFFFFFFFFFFFFF))
    {
        /*
         * In case no valid IEEE address is available, a random
         * IEEE address will be generated to be able to run the
         * applications for demonstration purposes.
         * In production code this can be omitted.
         */
        /*
         * The proper seed for function rand() has already been generated
         * in function tal_generate_rand_seed().
         */
        uint8_t *ptr_pib = (uint8_t *)&tal_pib.IeeeAddress;

        for (uint8_t i = 0; i < 8; i++)
        {
            *ptr_pib++ = (uint8_t)rand();
            /*
             * Note:
             * Even if casting the 16 bit rand value back to 8 bit,
             * and running the loop 8 timers (instead of only 4 times)
             * may look cumbersome, it turns out that the code gets
             * smaller using 8-bit here.
             * And timing is not an issue at this place...
             */
        }
    }
#endif  /* #ifndef DISABLE_IEEE_ADDR_CHECK */
#endif  /* ENABLE_RP */

    /*
     * Configure interrupt handling.
     * Install a handler for the transceiver interrupt.
     */
    pal_trx_irq_init(trx_irq_handler_cb);
#ifndef ENABLE_RP
    pal_trx_irq_en();   /* Enable transceiver main interrupt. */
#endif

#if ((defined BEACON_SUPPORT) || (defined ENABLE_TSTAMP)) && (DISABLE_TSTAMP_IRQ == 0)
    /* Configure time stamp interrupt. */
    pal_trx_irq_init_tstamp(trx_irq_timestamp_handler_cb);
#ifndef ENABLE_RP
    pal_trx_irq_en_tstamp();    /* Enable timestamp interrupt. */
#endif
#endif

    /* Initialize the buffer management module and get a buffer to store received frames. */
    bmm_buffer_init();
    tal_rx_buffer = bmm_buffer_alloc(LARGE_BUFFER_SIZE);
#if DEBUG > 0
    if (tal_rx_buffer == NULL)
    {
        return FAILURE;
    }
#endif

    /* Init incoming frame queue */
#ifdef ENABLE_QUEUE_CAPACITY
    qmm_queue_init(&tal_incoming_frame_queue, TAL_INCOMING_FRAME_QUEUE_CAPACITY);
#else
    qmm_queue_init(&tal_incoming_frame_queue);
#endif  /* ENABLE_QUEUE_CAPACITY */

#ifdef ENABLE_TFA
    tfa_init();
#endif

    return MAC_SUCCESS;
} /* tal_init() */
/**
 * @brief Resets TAL state machine and sets the default PIB values if requested
 *
 * @param set_default_pib Defines whether PIB values need to be set
 *                        to its default values
 *
 * @return MAC_SUCCESS  if the transceiver state is changed to TRX_OFF
 *         FAILURE otherwise
 */
retval_t tal_reset(bool set_default_pib)
{
    /*
     * Do the reset stuff.
     * Set the default PIBs depending on the given parameter set_default_pib.
     * Do NOT generate random seed again.
     */
    if (internal_tal_reset(set_default_pib) != MAC_SUCCESS)
    {
        return FAILURE;
    }

#if (NUMBER_OF_TAL_TIMERS > 0)
    /* Clear all running TAL timers. */
    {
        uint8_t timer_id;

        ENTER_CRITICAL_REGION();

        for (timer_id = TAL_FIRST_TIMER_ID; timer_id <= TAL_LAST_TIMER_ID;
             timer_id++)
        {
            pal_timer_stop(timer_id);
        }

        LEAVE_CRITICAL_REGION();
    }
#endif

    /* Clear TAL Incoming Frame queue and free used buffers. */
    while (tal_incoming_frame_queue.size > 0)
    {
        buffer_t *frame = qmm_queue_remove(&tal_incoming_frame_queue, NULL);
        if (NULL != frame)
        {
            bmm_buffer_free(frame);
        }
    }

#ifdef ENABLE_TFA
    tfa_reset(set_default_pib);
#endif

    /*
     * Configure interrupt handling.
     * Install a handler for the transceiver interrupt.
     */
    pal_trx_irq_init(trx_irq_handler_cb);
    /* The pending transceiver interrupts on the microcontroller are cleared. */
    pal_trx_irq_flag_clr();
    pal_trx_irq_en();   /* Enable transceiver main interrupt. */

#ifdef ENABLE_FTN_PLL_CALIBRATION
    {
        /* Handle PLL calibration and filter tuning. */
        retval_t timer_status;

        /* Calibration timer has already been stopped within this function. */

        /* Start periodic calibration timer. */
        timer_status = pal_timer_start(TAL_CALIBRATION,
                                       TAL_CALIBRATION_TIMEOUT_US,
                                       TIMEOUT_RELATIVE,
                                       (FUNC_PTR())calibration_timer_handler_cb,
                                       NULL);

        if (timer_status != MAC_SUCCESS)
        {
            ASSERT("PLL calibration timer start problem" == 0);
        }
    }
#endif  /* ENABLE_FTN_PLL_CALIBRATION */

    return MAC_SUCCESS;
}
Exemple #10
0
/*
 * \brief Sets transceiver state
 *
 * \param trx_cmd needs to be one of the trx commands
 *
 * \return current trx state
 */
tal_trx_status_t set_trx_state(trx_cmd_t trx_cmd)
{
	if (tal_trx_status == TRX_SLEEP) {
		/*
		 * Since the wake-up procedure relies on the Awake IRQ and
		 * the global interrupts may be disabled at this point of time,
		 * we need to make sure that the global interrupts are enabled
		 * during wake-up procedure.
		 * Once the TRX is awake, the original state of the global
		 *interrupts
		 * will be restored.
		 */
		/* Reset wake-up interrupt flag. */
		if(CMD_SLEEP == trx_cmd)
		{
			return TRX_SLEEP;
		}
		tal_awake_end_flag = false;
		/* Set callback function for the awake interrupt. */
		pal_trx_irq_init((FUNC_PTR)trx_irq_awake_handler_cb);
		/* The pending transceiver interrupts on the microcontroller are
		 *cleared. */
		pal_trx_irq_flag_clr();
		pal_trx_irq_en(); /* Enable transceiver main interrupt. */
		/* Save current state of global interrupts. */
		ENTER_CRITICAL_REGION();
		/* Force enabling of global interrupts. */
		ENABLE_GLOBAL_IRQ();
		/* Leave trx sleep mode. */
		PAL_SLP_TR_LOW();
		/* Poll wake-up interrupt flag until set within ISR. */
		while (!tal_awake_end_flag) {
		}
		/* Restore original state of global interrupts. */
		LEAVE_CRITICAL_REGION();
		/* Clear existing interrupts */
		pal_trx_reg_read(RG_IRQ_STATUS);
		/* Re-install default IRQ handler for main interrupt. */
		pal_trx_irq_init((FUNC_PTR)trx_irq_handler_cb);
		/* Re-enable regular interrupts except Awake-IRQ */
		pal_trx_reg_write(RG_IRQ_MASK, TRX_IRQ_DEFAULT);

#if (ANTENNA_DIVERSITY == 1)
		/* Enable antenna diversity. */
		pal_trx_bit_write(SR_ANT_EXT_SW_EN, ANT_EXT_SW_ENABLE);
#endif

#ifdef EXT_RF_FRONT_END_CTRL
		/* Enable RF front end control */
		pal_trx_bit_write(SR_PA_EXT_EN, PA_EXT_ENABLE);
#endif

		if ((trx_cmd == CMD_TRX_OFF) ||
				(trx_cmd == CMD_FORCE_TRX_OFF)) {
			tal_trx_status = TRX_OFF;
			return TRX_OFF;
		}
	}

	switch (trx_cmd) { /* requested state */
	case CMD_SLEEP:
		pal_trx_reg_write(RG_TRX_STATE, CMD_FORCE_TRX_OFF);
#if (ANTENNA_DIVERSITY == 1)
		/* Disable antenna diversity: sets pulls */
		pal_trx_bit_write(SR_ANT_EXT_SW_EN, ANT_EXT_SW_DISABLE);
#endif
#ifdef EXT_RF_FRONT_END_CTRL
		/* Disable RF front end control */
		pal_trx_bit_write(SR_PA_EXT_EN, PA_EXT_DISABLE);
#endif
#ifndef SW_CONTROLLED_CSMA
		{
			uint16_t rand_value;

			/*
			 * Init the SEED value of the CSMA backoff algorithm.
			 */
			rand_value = (uint16_t)rand();
			pal_trx_reg_write(RG_CSMA_SEED_0, (uint8_t)rand_value);
			pal_trx_bit_write(SR_CSMA_SEED_1,
					(uint8_t)(rand_value >> 8));
		}
#endif
		/* Clear existing interrupts */
		pal_trx_reg_read(RG_IRQ_STATUS);

		/*
		 * Enable Awake_end interrupt.
		 * This is used for save wake-up from sleep later.
		 */
		pal_trx_bit_write(SR_IRQ_MASK, TRX_IRQ_CCA_ED_READY);
		PAL_WAIT_1_US();
		PAL_SLP_TR_HIGH();
		pal_timer_delay(TRX_OFF_TO_SLEEP_TIME_CLKM_CYCLES);
		tal_trx_status = TRX_SLEEP;
		return TRX_SLEEP; /* transceiver register cannot be read during
		                   *TRX_SLEEP */

	case CMD_TRX_OFF:
		switch (tal_trx_status) {
		case TRX_OFF:
			break;

		default:
			pal_trx_reg_write(RG_TRX_STATE, CMD_TRX_OFF);
			PAL_WAIT_1_US();
			break;
		}
		break;

	case CMD_FORCE_TRX_OFF:
		switch (tal_trx_status) {
		case TRX_OFF:
			break;

		default:
			pal_trx_reg_write(RG_TRX_STATE, CMD_FORCE_TRX_OFF);
			PAL_WAIT_1_US();
			break;
		}
		break;

	case CMD_PLL_ON:
		switch (tal_trx_status) {
		case PLL_ON:
			break;

		case TRX_OFF:
			switch_pll_on();
			break;

		case RX_ON:
		case RX_AACK_ON:
		case TX_ARET_ON:
			pal_trx_reg_write(RG_TRX_STATE, CMD_PLL_ON);
			PAL_WAIT_1_US();
			break;

		case BUSY_RX:
		case BUSY_TX:
		case BUSY_RX_AACK:
		case BUSY_TX_ARET:
			/* do nothing if trx is busy */
			break;

		default:
			Assert("state transition not handled" == 0);
			break;
		}
		break;

	case CMD_FORCE_PLL_ON:
		switch (tal_trx_status) {
		case TRX_OFF:
			switch_pll_on();
			break;

		case PLL_ON:
			break;

		default:
			pal_trx_reg_write(RG_TRX_STATE, CMD_FORCE_PLL_ON);
			break;
		}
		break;

	case CMD_RX_ON:
		switch (tal_trx_status) {
		case RX_ON:
			break;

		case PLL_ON:
		case RX_AACK_ON:
		case TX_ARET_ON:
			pal_trx_reg_write(RG_TRX_STATE, CMD_RX_ON);
			PAL_WAIT_1_US();
			break;

		case TRX_OFF:
			switch_pll_on();
			pal_trx_reg_write(RG_TRX_STATE, CMD_RX_ON);
			PAL_WAIT_1_US();
			break;

		case BUSY_RX:
		case BUSY_TX:
		case BUSY_RX_AACK:
		case BUSY_TX_ARET:
			/* do nothing if trx is busy */
			break;

		default:
			Assert("state transition not handled" == 0);
			break;
		}
		break;

	case CMD_RX_AACK_ON:
		switch (tal_trx_status) {
		case RX_AACK_ON:
			break;

		case TX_ARET_ON:
		case PLL_ON:
			pal_trx_reg_write(RG_TRX_STATE, CMD_RX_AACK_ON);
			PAL_WAIT_1_US();
			break;

		case TRX_OFF:
			switch_pll_on(); /* state change from TRX_OFF to
			                  * RX_AACK_ON can be done directly, too */
			pal_trx_reg_write(RG_TRX_STATE, CMD_RX_AACK_ON);
			PAL_WAIT_1_US();
			break;

		case RX_ON:
			pal_trx_reg_write(RG_TRX_STATE, CMD_PLL_ON);
			PAL_WAIT_1_US();
			/* check if state change could be applied */
			tal_trx_status = (tal_trx_status_t)pal_trx_bit_read(
					SR_TRX_STATUS);
			if (tal_trx_status != PLL_ON) {
				return tal_trx_status;
			}

			pal_trx_reg_write(RG_TRX_STATE, CMD_RX_AACK_ON);
			PAL_WAIT_1_US();
			break;

		case BUSY_RX:
		case BUSY_TX:
		case BUSY_RX_AACK:
		case BUSY_TX_ARET:
			/* do nothing if trx is busy */
			break;

		default:
			Assert("state transition not handled" == 0);
			break;
		}
		break;

	case CMD_TX_ARET_ON:
		switch (tal_trx_status) {
		case TX_ARET_ON:
			break;

		case PLL_ON:
			pal_trx_reg_write(RG_TRX_STATE, CMD_TX_ARET_ON);
			PAL_WAIT_1_US();
			break;

		case RX_ON:
		case RX_AACK_ON:
			pal_trx_reg_write(RG_TRX_STATE, CMD_PLL_ON);
			PAL_WAIT_1_US();
			/* check if state change could be applied */
			tal_trx_status = (tal_trx_status_t)pal_trx_bit_read(
					SR_TRX_STATUS);
			if (tal_trx_status != PLL_ON) {
				return tal_trx_status;
			}

			pal_trx_reg_write(RG_TRX_STATE, CMD_TX_ARET_ON);
			PAL_WAIT_1_US();
			break;

		case TRX_OFF:
			switch_pll_on(); /* state change from TRX_OFF to
			                  * TX_ARET_ON can be done directly, too */
			pal_trx_reg_write(RG_TRX_STATE, CMD_TX_ARET_ON);
			PAL_WAIT_1_US();
			break;

		case BUSY_RX:
		case BUSY_TX:
		case BUSY_RX_AACK:
		case BUSY_TX_ARET:
			/* do nothing if trx is busy */
			break;

		default:
			Assert("state transition not handled" == 0);
			break;
		}
		break;

	default:
		/* CMD_NOP, CMD_TX_START */
		Assert("trx command not handled" == 0);
		break;
	}

	do {
		tal_trx_status = (tal_trx_status_t)pal_trx_bit_read(
				SR_TRX_STATUS);
	} while (tal_trx_status == STATE_TRANSITION_IN_PROGRESS);

	return tal_trx_status;
} /* set_trx_state() */
Exemple #11
0
/*
 * \brief Resets TAL state machine and sets the default PIB values if requested
 *
 * \param set_default_pib Defines whether PIB values need to be set
 *                        to its default values
 */
retval_t tal_reset(bool set_default_pib)
{
    /*
     * Do the reset stuff.
     * Set the default PIBs depending on the given parameter
     *set_default_pib.
     */
    if (internal_tal_reset(set_default_pib) != MAC_SUCCESS) {
        return FAILURE;
    }

#if (MAC_SCAN_ED_REQUEST_CONFIRM == 1)
    /* Stop the ED sample timer. */
#ifdef ENABLE_HIGH_PRIO_TMR
    pal_stop_high_priority_timer(TAL_ED_SAMPLE_TIMER);
#endif  /* ENABLE_HIGH_PRIO_TMR */
#endif  /* (MAC_SCAN_ED_REQUEST_CONFIRM == 1) */

    ENTER_CRITICAL_REGION();
    tal_timers_stop();
    LEAVE_CRITICAL_REGION();

    /* Clear TAL Incoming Frame queue and free used buffers. */
    while (tal_incoming_frame_queue.size > 0) {
        buffer_t *frame = qmm_queue_remove(&tal_incoming_frame_queue,
                                           NULL);
        if (NULL != frame) {
            bmm_buffer_free(frame);
        }
    }

    /*
     * Configure interrupt handling.
     * Install a handler for the transceiver interrupt.
     */
    pal_trx_irq_init((FUNC_PTR)trx_irq_handler_cb);
    /* The pending transceiver interrupts on the microcontroller are
     *cleared. */
    pal_trx_irq_flag_clr();
    pal_trx_irq_en(); /* Enable transceiver main interrupt. */

#ifdef ENABLE_FTN_PLL_CALIBRATION
    {
        /* Handle PLL calibration and filter tuning. */
        retval_t timer_status;

        /* Calibration timer has already been stopped within this
         *function. */

        /* Start periodic calibration timer.*/
        timer_status = pal_timer_start(TAL_CALIBRATION,
                                       TAL_CALIBRATION_TIMEOUT_US,
                                       TIMEOUT_RELATIVE,
                                       (FUNC_PTR)calibration_timer_handler_cb,
                                       NULL);

        if (timer_status != MAC_SUCCESS) {
            Assert("PLL calibration timer start problem" == 0);
        }
    }
#endif  /* ENABLE_FTN_PLL_CALIBRATION */

    return MAC_SUCCESS;
}
Exemple #12
0
/*
 * \brief Initializes the TAL
 *
 * This function is called to initialize the TAL. The transceiver is
 * initialized, the TAL PIBs are set to their default values, and the TAL state
 * machine is set to TAL_IDLE state.
 *
 * \return MAC_SUCCESS  if the transceiver state is changed to TRX_OFF and the
 *                 current device part number and version number are correct;
 *         FAILURE otherwise
 */
retval_t tal_init(void)
{
    /* Init the PAL and by this means also the transceiver interface */
    if (pal_init() != MAC_SUCCESS) {
        return FAILURE;
    }

    if (trx_init() != MAC_SUCCESS) {
        return FAILURE;
    }

    if (tal_timer_init() != MAC_SUCCESS) {
        return FAILURE;
    }

#ifdef ENABLE_STACK_NVM
    pal_ps_get(INTERN_EEPROM, EE_IEEE_ADDR, 8, &tal_pib.IeeeAddress);
#endif

    /*
     * For systems including the AT86RF230B the random seed generation
     * cannot be done using a dedicated hardware feature.
     * Therefore all random seed generation needs to be done by special
     * means (e.g. utilization of ADC) that generate a random value only
     * within a certain range.
     *
     * In case the node already has a valid IEEE address (i.e. an IEEE
     * address which is different from 0x0000000000000000 or
     * 0xFFFFFFFFFFFFFFFF), this IEEE address (the lower 16 bit)
     * shall be used as seed for srand(), since each node should have a
     *unique
     * IEEE address.
     * In this case srand() is called directly and function
     *tal_generate_rand_seed()
     * is not called.
     *
     * Note: This behaviour is different in all other TALs, since in these
     * cases the seed for srand() is always generated based on transceiver
     * hardware support.
     */

#ifndef DISABLE_IEEE_ADDR_CHECK
    if ((tal_pib.IeeeAddress == 0x0000000000000000) ||
            (tal_pib.IeeeAddress == 0xFFFFFFFFFFFFFFFF)
       ) {
        /*
         * Generate a seed for the random number generator in function
         *rand().
         * This is required (for example) as seed for the CSMA-CA
         *algorithm.
         */
        tal_generate_rand_seed();

        /*
         * Now that we have generated a random seed, we can generate a
         *random
         * IEEE address for this node.
         */
        do {
            /*
             * In case no valid IEEE address is available, a random
             * IEEE address will be generated to be able to run the
             * applications for demonstration purposes.
             * In production code this can be omitted.
             */

            /*
             * The proper seed for function rand() has already been
             *generated
             * in function tal_generate_rand_seed().
             */
            uint8_t *ptr_pib = (uint8_t *)&tal_pib.IeeeAddress;

            for (uint8_t i = 0; i < 8; i++) {
                *ptr_pib++ = (uint8_t)rand();

                /*
                 * Note:
                 * Even if casting the 16 bit rand value back to
                 *8 bit,
                 * and running the loop 8 timers (instead of
                 *only 4 times)
                 * may look cumbersome, it turns out that the
                 *code gets
                 * smaller using 8-bit here.
                 * And timing is not an issue at this place...
                 */
            }
        }
        /* Check if a valid IEEE address is available. */
        while ((tal_pib.IeeeAddress == 0x0000000000000000) ||
                (tal_pib.IeeeAddress == 0xFFFFFFFFFFFFFFFF)
              );
    } else {
        /* Valid IEEE address, so no need to generate a new random seed.
         **/
        uint16_t cur_rand_seed = (uint16_t)tal_pib.IeeeAddress;
        srand(cur_rand_seed);
    }

#else

    /*
     * No check for a valid IEEE address done, so directly create a seed
     * for srand().
     */
    tal_generate_rand_seed();
#endif

    /*
     * Do the reset stuff.
     * Set the default PIBs.
     */
    if (internal_tal_reset(true) != MAC_SUCCESS) {
        return FAILURE;
    }

    pal_trx_reg_read(RG_IRQ_STATUS); /* clear pending irqs, dummy read */

    /*
     * Configure interrupt handling.
     * Install a handler for the transceiver interrupt.
     */
    pal_trx_irq_init((FUNC_PTR)trx_irq_handler_cb);
    pal_trx_irq_en(); /* Enable transceiver main interrupt. */

    /* Initialize the buffer management module and get a buffer to store
     *reveived frames. */
    bmm_buffer_init();
    tal_rx_buffer = bmm_buffer_alloc(LARGE_BUFFER_SIZE);

    /* Init incoming frame queue */
#ifdef ENABLE_QUEUE_CAPACITY
    qmm_queue_init(&tal_incoming_frame_queue,
                   TAL_INCOMING_FRAME_QUEUE_CAPACITY);
#else
    qmm_queue_init(&tal_incoming_frame_queue);
#endif  /* ENABLE_QUEUE_CAPACITY */

    return MAC_SUCCESS;
} /* tal_init() */
Exemple #13
0
/*
 * \brief Initializes the TAL
 *
 * This function is called to initialize the TAL. The transceiver is
 * initialized, the TAL PIBs are set to their default values, and the TAL state
 * machine is set to TAL_IDLE state.
 *
 * \return MAC_SUCCESS  if the transceiver state is changed to TRX_OFF and the
 *                 current device part number and version number are correct;
 *         FAILURE otherwise
 */
retval_t tal_init(void)
{
	/* Init the PAL and by this means also the transceiver interface */
	if (pal_init() != MAC_SUCCESS) {
		return FAILURE;
	}

	if (trx_init() != MAC_SUCCESS) {
		return FAILURE;
	}

	if (tal_timer_init() != MAC_SUCCESS) {
		return FAILURE;
	}

#ifdef ENABLE_STACK_NVM
	pal_ps_get(INTERN_EEPROM, EE_IEEE_ADDR, 8, &tal_pib.IeeeAddress);
#endif

	/*
	 * Do the reset stuff.
	 * Set the default PIBs.
	 * Generate random seed.
	 */
	if (internal_tal_reset(true) != MAC_SUCCESS) {
		return FAILURE;
	}

#ifndef DISABLE_IEEE_ADDR_CHECK
	/* Check if a valid IEEE address is available. */

	/*
	 * This while loop is on purpose, since just in the
	 * rare case that such an address is randomly
	 * generated again, we must repeat this.
	 */
	uint64_t invalid_ieee_address;
	memset((uint8_t *)&invalid_ieee_address, 0xFF, sizeof(invalid_ieee_address));
	while ((tal_pib.IeeeAddress == 0x0000000000000000) ||
	(tal_pib.IeeeAddress == invalid_ieee_address)){
		/*
		 * In case no valid IEEE address is available, a random
		 * IEEE address will be generated to be able to run the
		 * applications for demonstration purposes.
		 * In production code this can be omitted.
		 */

		/*
		 * The proper seed for function rand() has already been
		 *generated
		 * in function tal_generate_rand_seed().
		 */
		uint8_t *ptr_pib = (uint8_t *)&tal_pib.IeeeAddress;

		for (uint8_t i = 0; i < 8; i++) {
			*ptr_pib++ = (uint8_t)rand();

			/*
			 * Note:
			 * Even if casting the 16 bit rand value back to 8 bit,
			 * and running the loop 8 timers (instead of only 4
			 *times)
			 * may look cumbersome, it turns out that the code gets
			 * smaller using 8-bit here.
			 * And timing is not an issue at this place...
			 */
		}
	}
#endif  /* #ifndef DISABLE_IEEE_ADDR_CHECK */
#ifdef ENABLE_STACK_NVM
	pal_ps_set(EE_IEEE_ADDR, 8, &tal_pib.IeeeAddress);
#endif

	/*
	 * Configure interrupt handling.
	 * Install a handler for the main transceiver interrupt.
	 */
	pal_trx_irq_init((FUNC_PTR)trx_irq_handler_cb);
	pal_trx_irq_en(); /* Enable main transceiver interrupt. */

#if ((defined BEACON_SUPPORT) || (defined ENABLE_TSTAMP)) && \
	(DISABLE_TSTAMP_IRQ == 0)

	/* Configure time stamp interrupt.
	 * The timestamping is only required for
	 * - beaconing networks or if timestamping is explicitly enabled,
	 * - and if the time stamp interrupt is not explicitly disabled.
	 */
	pal_trx_irq_init_tstamp((FUNC_PTR)trx_irq_timestamp_handler_cb);
	pal_trx_irq_en_tstamp(); /* Enable timestamp interrupt. */
#endif

	/* Initialize the buffer management module and get a buffer to store
	 *reveived frames. */
	bmm_buffer_init();
	tal_rx_buffer = bmm_buffer_alloc(LARGE_BUFFER_SIZE);

	/* Init incoming frame queue */
#ifdef ENABLE_QUEUE_CAPACITY
	qmm_queue_init(&tal_incoming_frame_queue,
			TAL_INCOMING_FRAME_QUEUE_CAPACITY);
#else
	qmm_queue_init(&tal_incoming_frame_queue);
#endif  /* ENABLE_QUEUE_CAPACITY */

#ifdef ENABLE_TFA
	tfa_init();
#endif

	return MAC_SUCCESS;
} /* tal_init() */
Exemple #14
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. */
}
Exemple #15
0
/**
 * \brief State machine handling slotted CSMA
 */
void slotted_csma_state_handling(void)
{
	switch (tal_csma_state) {
	case BACKOFF_WAITING_FOR_CCA_TIMER:
		break;

	case BACKOFF_WAITING_FOR_BEACON:

		/*
		 * Do not perform any operation and wait until the next beacon
		 * reception. If several beacons are not received, the beacon
		 *loss
		 * timer expires and stops the entire transaction.
		 */
		break;

	case CSMA_HANDLE_BEACON:
		/* debug pin to switch on: define ENABLE_DEBUG_PINS,
		 *pal_config.h */
		PIN_WAITING_FOR_BEACON_END();
		PIN_BEACON_LOSS_TIMER_END();

		pal_timer_stop(TAL_CSMA_BEACON_LOSS_TIMER);
		csma_backoff_calculation();
		break;

	case CSMA_ACCESS_FAILURE:
		NB++;
		BE++;
		/* ensure that BE is no more than macMaxBE */
		if (BE > tal_pib.MaxBE) {  /* macMaxBE */
			BE = tal_pib.MaxBE; /* macMaxBE */
		}

		if (NB > macMaxCSMABackoffs) {
			/* terminate with channel access failure */
			tx_done(MAC_CHANNEL_ACCESS_FAILURE);
		} else {
			/* restart backoff */
			csma_backoff_calculation();
		}

		break;

	case NO_BEACON_TRACKING:
		/* terminate with channel access failure */
		tx_done(MAC_CHANNEL_ACCESS_FAILURE);
		break;

	case FRAME_SENDING_WITH_ACK:
	case FRAME_SENDING_NO_ACK:
		/* waiting for end of frame transmission */
		break;

	case WAITING_FOR_ACK:
		/* waiting for ACK reception */
		break;

	case TX_DONE_SUCCESS:
		tx_done(MAC_SUCCESS);
		break;

	case TX_DONE_FRAME_PENDING:
		tx_done(TAL_FRAME_PENDING);
		break;

	case TX_DONE_NO_ACK:
		if (number_of_tx_retries < tal_pib.MaxFrameRetries) {
			number_of_tx_retries++;
			set_trx_state(CMD_RX_AACK_ON);

			/*
			 * While continuing with CSMA, handle trx irq with
			 *regular isr.
			 * Install a handler for the transceiver interrupt.
			 */
			pal_trx_irq_init((FUNC_PTR)trx_irq_handler_cb);
			pal_trx_reg_read(RG_TRX_STATUS);
			pal_trx_irq_en();

			/*
			 * Start the entire CSMA procedure again,
			 * but do not reset the number of transmission attempts.
			 */
			BE++;

			/* ensure that BE is no more than macMaxBE */
			if (BE > tal_pib.MaxBE) { /* macMaxBE */
				BE = tal_pib.MaxBE; /* macMaxBE */
			}

			NB = 0;
			remaining_backoff_periods
				= (uint8_t)(rand() & ((1 << BE) - 1));
			csma_backoff_calculation();
		} else {
			tx_done(MAC_NO_ACK);
		}

		PIN_NO_ACK_END();
		break;

	default:
		Assert("INVALID CSMA status" == 0);
		break;
	}
} /* csma_ca_state_handling() */