Пример #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);
	trx_reg_read(RG_IRQ_STATUS);    /* Clear existing interrupts */
	trx_bit_write(SR_RX_PDT_DIS, RX_DISABLE);
	trx_irq_init((FUNC_PTR)trx_ed_irq_handler_cb);
	trx_bit_write(SR_IRQ_MASK, TRX_IRQ_4_CCA_ED_DONE); /* 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 */
		trx_bit_write(SR_RX_PDT_DIS, RX_ENABLE);
		trx_irq_init((FUNC_PTR)trx_irq_handler_cb);
		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 */
	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;
}
Пример #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)
{
	trx_bit_write(SR_RX_PDT_DIS, RX_ENABLE);
	trx_irq_init((FUNC_PTR)trx_irq_handler_cb);
	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);
}
Пример #3
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 */
		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 */
		trx_irq_init((FUNC_PTR)cca_done_irq_handler);
		trx_reg_write(RG_IRQ_MASK, TRX_IRQ_CCA_ED_READY); /* enable
		                                                   * CCA
		                                                   * interrupt
		                                                   **/
		/* Start CCA */
		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;
}
Пример #4
0
/**
 * \brief      Init the radio
 * \return     Returns success/fail
 * \retval 0   Success
 */
static int
rf212_init(void)
{
  volatile uint8_t regtemp;
   uint8_t radio_state;  /* don't optimize this away, it's important */
  //uint8_t temp;
  PRINTF("RF212: init.\n");

  /* init SPI and GPIOs, wake up from sleep/power up. */
  //rf212_arch_init();
  trx_spi_init();
 
  /* reset will put us into TRX_OFF state */
  /* reset the radio core */
  port_pin_set_output_level(AT86RFX_RST_PIN, false);
  delay_cycles_ms(1);
  port_pin_set_output_level(AT86RFX_RST_PIN, true);
  
  port_pin_set_output_level(AT86RFX_SLP_PIN, false); /*wakeup from sleep*/

  /* before enabling interrupts, make sure we have cleared IRQ status */
  regtemp = trx_reg_read(RF212_REG_IRQ_STATUS);
  printf("After wake from sleep\n");
  radio_state = rf212_status();
  printf("After arch read reg: state 0x%04x\n", radio_state);
 
  /* Assign regtemp to regtemp to avoid compiler warnings */
  regtemp = regtemp;
if(radio_state == STATE_P_ON) {
	trx_reg_write(RF212_REG_TRX_STATE, TRXCMD_TRX_OFF);
	}  
  trx_irq_init((FUNC_PTR)rf212_interrupt_poll);
  ENABLE_TRX_IRQ();  
  system_interrupt_enable_global();
  /* Configure the radio using the default values except these. */
  trx_reg_write(RF212_REG_TRX_CTRL_1,      RF212_REG_TRX_CTRL_1_CONF);
  trx_reg_write(RF212_REG_PHY_CC_CCA,      RF212_REG_PHY_CC_CCA_CONF);
  trx_reg_write(RF212_REG_PHY_TX_PWR_CONF, RF212_REG_PHY_TX_PWR_CONF);
  //temp = rf212_arch_read_reg(RF212_REG_TRX_CTRL_2);
  trx_reg_write(RF212_REG_TRX_CTRL_2, RF212_REG_TRX_CTRL_2_CONF);
  trx_reg_write(RF212_REG_IRQ_MASK,        RF212_REG_IRQ_MASK_CONF);
#if HW_CSMA_FRAME_RETRIES
  trx_bit_write(SR_MAX_FRAME_RETRIES, 3);
  trx_bit_write(SR_MAX_CSMA_RETRIES, 4);
#else  
  trx_bit_write(SR_MAX_FRAME_RETRIES, 0);
  trx_bit_write(SR_MAX_CSMA_RETRIES, 7);
#endif  
  SetPanId(IEEE802154_CONF_PANID);
  rf_generate_random_seed();
  /* start the radio process */
  process_start(&rf212_radio_process, NULL);
  return 0;
}
Пример #5
0
/*
 * \brief handling of CCA result.
 */
void cca_done_handling(void)
{
	set_trx_state(CMD_PLL_ON); /* leave RX_ON */
	/* Restore IRQ handling */
	trx_irq_init((FUNC_PTR)trx_irq_handler_cb);
	trx_reg_write(RG_IRQ_MASK, TRX_IRQ_DEFAULT);
	trx_bit_write(SR_RX_PDT_DIS, RX_ENABLE); /* Enable frame reception.
	                                         **/

	/* Check if channel was idle or busy */
	if (trx_bit_read(SR_CCA_STATUS) == CCA_STATUS_CHANNEL_IS_IDLE) {
		tx_frame();
	} else {
		tal_state = TAL_CSMA_CONTINUE;
	}
}
Пример #6
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
 *
 * \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;
	}

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

#ifdef ENABLE_TFA
	tfa_reset(set_default_pib);
#endif

	/*
	 * Configure interrupt handling.
	 * Install a handler for the transceiver interrupt.
	 */
	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;
}
Пример #7
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.
	 */
	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() */
Пример #8
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. */
		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. */
		TRX_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 */
		trx_reg_read(RG_IRQ_STATUS);
		/* Re-install default IRQ handler for main interrupt. */
		trx_irq_init((FUNC_PTR)trx_irq_handler_cb);
		/* Re-enable TRX_END interrupt */
		trx_reg_write(RG_IRQ_MASK, TRX_IRQ_DEFAULT);

#if (ANTENNA_DIVERSITY == 1)
		/* Enable antenna diversity. */
		trx_bit_write(SR_ANT_EXT_SW_EN, ANT_EXT_SW_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:
		trx_reg_write(RG_TRX_STATE, CMD_FORCE_TRX_OFF);
#if (ANTENNA_DIVERSITY == 1)
		/* Disable antenna diversity: sets pulls */
		trx_bit_write(SR_ANT_EXT_SW_EN, ANT_EXT_SW_DISABLE);
#endif
#ifndef SW_CONTROLLED_CSMA
		{
			uint16_t rand_value;

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

		/*
		 * Enable Awake_end interrupt.
		 * This is used for save wake-up from sleep later.
		 */
		trx_bit_write(SR_IRQ_MASK, TRX_IRQ_4_CCA_ED_DONE);
		PAL_WAIT_1_US();
		TRX_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:
			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:
			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:
			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:
			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:
			trx_reg_write(RG_TRX_STATE, CMD_RX_ON);
			PAL_WAIT_1_US();
			break;

		case TRX_OFF:
			switch_pll_on();
			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:
			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
			                  **/
			trx_reg_write(RG_TRX_STATE, CMD_RX_AACK_ON);
			PAL_WAIT_1_US();
			break;

		case RX_ON:
			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)trx_bit_read(
					SR_TRX_STATUS);
			if (tal_trx_status != PLL_ON) {
				return tal_trx_status;
			}

			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:
			trx_reg_write(RG_TRX_STATE, CMD_TX_ARET_ON);
			PAL_WAIT_1_US();
			break;

		case RX_ON:
		case RX_AACK_ON:
			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)trx_bit_read(
					SR_TRX_STATUS);
			if (tal_trx_status != PLL_ON) {
				return tal_trx_status;
			}

			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
			                  **/
			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)trx_bit_read(
				SR_TRX_STATUS);
	} while (tal_trx_status == STATE_TRANSITION_IN_PROGRESS);

	return tal_trx_status;
} /* set_trx_state() */
Пример #9
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. */
		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. */
		TRX_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 */
		trx_reg_read(RG_IRQ_STATUS);
		/* Re-install default IRQ handler for main interrupt. */
		trx_irq_init((FUNC_PTR)trx_irq_handler_cb);
		/* Re-enable TRX_END interrupt */
		trx_reg_write(RG_IRQ_MASK, TRX_IRQ_DEFAULT);
#if (ANTENNA_DIVERSITY == 1)
		/* Enable antenna diversity. */
		trx_bit_write(SR_ANT_EXT_SW_EN, ANT_EXT_SW_ENABLE);
#endif

#ifdef EXT_RF_FRONT_END_CTRL
		/* Enable RF front end control */
		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) {
		if (CMD_DEEP_SLEEP == trx_cmd) {
			return TRX_DEEP_SLEEP;
		}

		/* Leave trx sleep mode. */
		TRX_SLP_TR_LOW();
		/* Check if trx has left deep sleep. */
		tal_trx_status_t trx_state;
		do {
			trx_state = 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
		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.
		 */
		trx_bit_write(SR_ANT_EXT_SW_EN, ANT_EXT_SW_DISABLE);
#endif
#ifdef EXT_RF_FRONT_END_CTRL
		/* Disable RF front end control */
		trx_bit_write(SR_PA_EXT_EN, 0);
#endif
		/* Clear existing interrupts */
		trx_reg_read(RG_IRQ_STATUS);

		/*
		 * Enable Awake_end interrupt.
		 * This is used for save wake-up from sleep later.
		 */
		trx_bit_write(SR_IRQ_MASK, TRX_IRQ_4_CCA_ED_DONE);

#ifdef ENABLE_DEEP_SLEEP
		if (trx_cmd == CMD_DEEP_SLEEP) {
			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.
			 */
			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.
		 */
		trx_bit_write(SR_IRQ_MASK, TRX_IRQ_4_CCA_ED_DONE);
		tal_trx_status = TRX_SLEEP;
#endif
		PAL_WAIT_1_US();
		TRX_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:
			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:
			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:
			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:
			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:
			trx_reg_write(RG_TRX_STATE, CMD_RX_ON);
			PAL_WAIT_1_US();
			break;

		case TRX_OFF:
			switch_pll_on();
			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:
			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
			                  **/
			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:
			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
			                  **/
			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) */ trx_bit_read(
				SR_TRX_STATUS);
	} while (tal_trx_status == STATE_TRANSITION_IN_PROGRESS);

	return tal_trx_status;
} /* set_trx_state() */
Пример #10
0
/**
 * @brief Resets TAL state machine and sets the default PIB values if requested
 *
 * @param trx_id Transceiver identifier
 * @param set_default_pib Defines whether PIB values need to be set
 *                        to its default values
 *
 * @return
 *      - @ref MAC_SUCCESS if the transceiver state is changed to TRX_OFF
 *      - @ref FAILURE otherwise
 * @ingroup apiTalApi
 */
retval_t tal_reset(trx_id_t trx_id, bool set_default_pib)
{
	rf_cmd_state_t previous_trx_state[NUM_TRX];

	previous_trx_state[RF09] = trx_state[RF09];
	previous_trx_state[RF24] = trx_state[RF24];

	/* Reset the actual device or part of the device */
	if (trx_reset(trx_id) != MAC_SUCCESS) {
		return FAILURE;
	}

	/* Init Trx if necessary, e.g. trx was in deep sleep */
	if (((previous_trx_state[RF09] == RF_SLEEP) &&
			(previous_trx_state[RF24] == RF_SLEEP)) ||
			(trx_id == RFBOTH)) {
		trx_init(); /* Initialize generic trx functionality */
	}

	if (trx_id == RFBOTH) {
		for (uint8_t i = 0; i < NUM_TRX; i++) {
			/* Clean TAL and removed any pending tasks */
			cleanup_tal((trx_id_t)i);

			/* Configure the transceiver register values. */
			trx_config((trx_id_t)i);

			if (set_default_pib) {
				/* Set the default PIB values */
				init_tal_pib((trx_id_t)i); /* see 'tal_pib.c' */
				calculate_pib_values(trx_id);
			} else {
				/* nothing to do - the current TAL PIB attribute
				 *values are used */
			}

			write_all_tal_pib_to_trx((trx_id_t)i); /* see
			                                        *'tal_pib.c' */
			config_phy((trx_id_t)i);

			/* Reset TAL variables. */
			tal_state[(trx_id_t)i] = TAL_IDLE;
			tx_state[(trx_id_t)i] = TX_IDLE;
#ifdef ENABLE_FTN_PLL_CALIBRATION
			/* Stop FTN timer */
			stop_ftn_timer((trx_id_t)i);
#endif  /* ENABLE_FTN_PLL_CALIBRATION */
		}
	} else {
		/* Maintain other trx */
		trx_id_t other_trx_id;
		if (trx_id == RF09) {
			other_trx_id = RF24;
		} else {
			other_trx_id = RF09;
		}

		if (tal_state[other_trx_id] == TAL_SLEEP) {
			/* Switch other trx back to sleep again */
			uint16_t reg_offset = RF_BASE_ADDR_OFFSET *
					other_trx_id;
#ifdef IQ_RADIO
			pal_dev_reg_write(RF215_BB, reg_offset + RG_RF09_CMD,
					RF_SLEEP);
			pal_dev_reg_write(RF215_RF, reg_offset + RG_RF09_CMD,
					RF_SLEEP);
#else
			trx_reg_write(reg_offset + RG_RF09_CMD, RF_SLEEP);
#endif
			TAL_RF_IRQ_CLR_ALL(trx_id);
		}

		/* Clean TAL and removed any pending tasks */
		cleanup_tal(trx_id);

		/* Configure the transceiver register values. */
		trx_config(trx_id);

		if (set_default_pib) {
			/* Set the default PIB values */
			init_tal_pib(trx_id); /* see 'tal_pib.c' */
			calculate_pib_values(trx_id);
		} else {
			/* nothing to do - the current TAL PIB attribute values
			 *are used */
		}

		write_all_tal_pib_to_trx(trx_id); /* see 'tal_pib.c' */
		config_phy(trx_id);

		/* Reset TAL variables. */
		tal_state[trx_id] = TAL_IDLE;
		tx_state[trx_id] = TX_IDLE;
#ifdef ENABLE_FTN_PLL_CALIBRATION
		/* Stop FTN timer */
		stop_ftn_timer(trx_id);
#endif  /* ENABLE_FTN_PLL_CALIBRATION */
	}

	/*
	 * Configure interrupt handling.
	 * Install a handler for the transceiver interrupt.
	 */
#ifdef IQ_RADIO
	trx_irq_init(RF215_BB, bb_irq_handler_cb);
	trx_irq_init(RF215_RF, rf_irq_handler_cb);
	pal_trx_irq_en(RF215_BB); /* Enable transceiver main interrupt. */
	pal_trx_irq_en(RF215_RF); /* Enable transceiver main interrupt. */
#else
	trx_irq_init((FUNC_PTR)trx_irq_handler_cb);
	pal_trx_irq_en(); /* Enable transceiver main interrupt. */
#endif

	return MAC_SUCCESS;
}
Пример #11
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;
	}

	/* Reset trx */
	if (trx_reset(RFBOTH) != MAC_SUCCESS) {
		return FAILURE;
	}

	/* Check if RF215 is connected */
	if ((trx_reg_read( RG_RF_PN) != 0x34) ||
			(trx_reg_read( RG_RF_VN) != 0x01)) {
		return FAILURE;
	}

	/* Initialize trx */
	trx_init();

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

	/* Initialize the buffer management */
	bmm_buffer_init();

	/* Configure both trx and set default PIB values */
	for (uint8_t trx_id = 0; trx_id < NUM_TRX; trx_id++) {
		/* Configure transceiver */
		trx_config((trx_id_t)trx_id);
#ifdef RF215V1
		/* Calibrate LO */
		calibrate_LO((trx_id_t)trx_id);
#endif

		/* Set the default PIB values */
		init_tal_pib((trx_id_t)trx_id); /* see 'tal_pib.c' */
		calculate_pib_values((trx_id_t)trx_id);

		/*
		 * Write all PIB values to the transceiver
		 * that are needed by the transceiver itself.
		 */
		write_all_tal_pib_to_trx((trx_id_t)trx_id); /* see 'tal_pib.c'
		                                             **/
		config_phy((trx_id_t)trx_id);

		tal_rx_buffer[trx_id] = bmm_buffer_alloc(LARGE_BUFFER_SIZE);
		if (tal_rx_buffer[trx_id] == NULL) {
			return FAILURE;
		}

		/* Init incoming frame queue */
		qmm_queue_init(&tal_incoming_frame_queue[trx_id]);

		tal_state[trx_id] = TAL_IDLE;
		tx_state[trx_id] = TX_IDLE;
	}

	/* Init seed of rand() */
	tal_generate_rand_seed();

#ifndef DISABLE_IEEE_ADDR_CHECK
	for (uint8_t trx_id = 0; trx_id < 2; trx_id++) {
		/* 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[trx_id].IeeeAddress == 0x0000000000000000) ||
				(tal_pib[trx_id].IeeeAddress ==
				((uint64_t)-1))) {
			/*
			 * 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[trx_id].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

#ifdef IQ_RADIO
	/* Init BB IRQ handler */
	pal_trx_irq_flag_clr(RF215_BB);
	trx_irq_init(RF215_BB, bb_irq_handler_cb);
	pal_trx_irq_en(RF215_BB);

	/* Init RF IRQ handler */
	pal_trx_irq_flag_clr(RF215_RF);
	trx_irq_init(RF215_RF, rf_irq_handler_cb);
	pal_trx_irq_en(RF215_RF);
#else

	/*
	 * Configure interrupt handling.
	 * Install a handler for the radio and the baseband interrupt.
	 */
	pal_trx_irq_flag_clr();
	trx_irq_init((FUNC_PTR)trx_irq_handler_cb);
	pal_trx_irq_en(); /* Enable transceiver main interrupt. */
#endif

#if ((defined SUPPORT_FSK) && (defined SUPPORT_MODE_SWITCH))
	init_mode_switch();
#endif

	return MAC_SUCCESS;
} /* tal_init() */