Beispiel #1
0
/**
 * @brief MAC function to wake-up the radio from sleep state
 */
void mac_trx_wakeup(void)
{
	/* If the radio is sleeping, it is woken-up */
	if (RADIO_SLEEPING == mac_radio_sleep_state) {
		if (FAILURE != tal_trx_wakeup()) {
			pal_timer_source_select(TMR_CLK_SRC_DURING_TRX_AWAKE);

			mac_radio_sleep_state = RADIO_AWAKE;
		}
	}
}
Beispiel #2
0
/**
 * \brief Configures the transceiver
 *
 * This function is called to configure the transceiver after reset.
 */
static void trx_config(void)
{
    /* Set pin driver strength */
    pal_trx_reg_write(RG_TRX_CTRL_0, ((CLKM_2mA << 6) |
                                      (CLKM_2mA << 4) | CLKM_1MHz));               /* fast
	                                                              * change */

    /*
     * Init the SEED value of the CSMA backoff algorithm.
     */
    uint16_t 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));

    /*
     * To make sure that the CSMA seed is properly set within the
     *transceiver,
     * put the trx to sleep briefly and wake it up again.
     */
    tal_trx_sleep(SLEEP_MODE_1);
    tal_trx_wakeup();

    pal_trx_bit_write(SR_AACK_SET_PD, PD_ACK_BIT_SET_ENABLE); /* 1 == frame
	                                                           *pending bit
	                                                           *is always
	                                                           *set to 1 */
    pal_trx_bit_write(SR_TX_AUTO_CRC_ON, TX_AUTO_CRC_ENABLE); /* enable auto
	                                                           *crc */
    pal_trx_reg_write(RG_IRQ_MASK, TRX_IRQ_TRX_END); /* enable TRX_END
	                                                  *interrupt */

#ifdef CCA_ED_THRESHOLD

    /*
     * Set CCA ED Threshold to other value than standard register due to
     * board specific loss (see pal_config.h). */
    pal_trx_bit_write(SR_CCA_ED_THRES, CCA_ED_THRESHOLD);
#endif
}
Beispiel #3
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;
    }

#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.  Clear all pending interrupts.
     * Handlers have been installed in tal_init(), and are never
     * uninstalled.
     */
    pal_trx_irq_flag_clr_rx_end();
    pal_trx_irq_flag_clr_tx_end();
#if (defined BEACON_SUPPORT) || (defined ENABLE_TSTAMP)
    pal_trx_irq_flag_clr_tstamp();
#endif /* (defined BEACON_SUPPORT) || (defined ENABLE_TSTAMP) */
    pal_trx_irq_flag_clr_awake();

    /*
     * To make sure that the CSMA seed is properly set within the transceiver,
     * put the trx to sleep briefly and wake it up again.
     */
    tal_trx_sleep(SLEEP_MODE_1);

    tal_trx_wakeup();

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

#ifdef STB_ON_SAL
    stb_restart();
#endif

    return MAC_SUCCESS;
}
Beispiel #4
0
/*
 * \brief Sets a TAL PIB attribute
 *
 * This function is called to set the transceiver information base
 * attributes.
 *
 * \param attribute TAL infobase attribute ID
 * \param value TAL infobase attribute value to be set
 *
 * \return MAC_UNSUPPORTED_ATTRIBUTE if the TAL info base attribute is not found
 *         TAL_BUSY if the TAL is not in TAL_IDLE state. An exception is
 *         macBeaconTxTime which can be accepted by TAL even if TAL is not
 *         in TAL_IDLE state.
 *         MAC_SUCCESS if the attempt to set the PIB attribute was successful
 *         TAL_TRX_ASLEEP if trx is in SLEEP mode and access to trx is required
 */
retval_t tal_pib_set(uint8_t attribute, pib_value_t *value)
{
	/*
	 * Do not allow any changes while ED or TX is done.
	 * We allow changes during RX, but it's on the user's own risk.
	 */
#if (MAC_SCAN_ED_REQUEST_CONFIRM == 1)
	if (tal_state == TAL_ED) {
		Assert("TAL is busy" == 0);
		return TAL_BUSY;
	}

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

	/*
	 * Distinguish between PIBs that need to be changed in trx directly
	 * and those that are simple variable udpates.
	 * Ensure that the transceiver is not in SLEEP.
	 * If it is in SLEEP, change it to TRX_OFF.
	 * For all other state force TRX_OFF.
	 * Abort any TAL_BUSY state, because the change might have an impact to
	 * ongoing transactions.
	 */

	switch (attribute) {
	case macMaxFrameRetries:

		/*
		 * The new PIB value is not immediately written to the
		 * transceiver. This is done on a frame-by-frame base.
		 */
		tal_pib.MaxFrameRetries = value->pib_value_8bit;
		break;

	case macMaxCSMABackoffs:

		/*
		 * The new PIB value is not immediately written to the
		 * transceiver. This is done on a frame-by-frame base.
		 */
		tal_pib.MaxCSMABackoffs = value->pib_value_8bit;
		break;

#ifdef BEACON_SUPPORT
	case macBattLifeExt:
		tal_pib.BattLifeExt = value->pib_value_bool;
		break;

	case macBeaconOrder:
		tal_pib.BeaconOrder = value->pib_value_8bit;
		break;

	case macSuperframeOrder:
		tal_pib.SuperFrameOrder = value->pib_value_8bit;
		break;

	case macBeaconTxTime:
		tal_pib.BeaconTxTime = value->pib_value_32bit;
		break;

#endif  /* BEACON_SUPPORT */
#ifdef PROMISCUOUS_MODE
	case macPromiscuousMode:
		tal_pib.PromiscuousMode = value->pib_value_8bit;
		if (tal_pib.PromiscuousMode) {
			tal_trx_wakeup();

			/* Check if receive buffer is available or queue is not
			 *full. */
			if (NULL == tal_rx_buffer) {
				set_trx_state(CMD_PLL_ON);
				tal_rx_on_required = true;
			} else {
				set_trx_state(CMD_RX_ON);
			}
		} else {
			set_trx_state(CMD_TRX_OFF);
			tal_rx_on_required = false;
		}
		break;
#endif

	default:

		/*
		 * Following PIBs require access to trx.
		 * Therefore trx must be at least in TRX_OFF.
		 */

		if (tal_trx_status == TRX_SLEEP) {
			/* While trx is in SLEEP, register cannot be accessed.
			 **/
			return TAL_TRX_ASLEEP;
		}

		switch (attribute) {
		case macMinBE:
			tal_pib.MinBE = value->pib_value_8bit;

#ifndef REDUCED_PARAM_CHECK

			/*
			 * macMinBE must not be larger than macMaxBE or
			 *calculation
			 * of macMaxFrameWaitTotalTime will fail.
			 */
			if (tal_pib.MinBE > tal_pib.MaxBE) {
				tal_pib.MinBE = tal_pib.MaxBE;
			}

#endif  /* REDUCED_PARAM_CHECK */

			pal_trx_bit_write(SR_MIN_BE, tal_pib.MinBE);
			break;

		case macPANId:
			tal_pib.PANId = value->pib_value_16bit;
			uint8_t *ptr_pan;
			ptr_pan = (uint8_t *)&tal_pib.PANId;
			for (uint8_t i = 0; i < 2; i++) {
				pal_trx_reg_write((RG_PAN_ID_0 + i), *ptr_pan);
				ptr_pan++;
			}
			break;

		case macShortAddress:
			tal_pib.ShortAddress = value->pib_value_16bit;
			uint8_t *ptr_shrt;
			ptr_shrt = (uint8_t *)&tal_pib.ShortAddress;
			for (uint8_t i = 0; i < 2; i++) {
				pal_trx_reg_write((RG_SHORT_ADDR_0 + i),
						*ptr_shrt);
				ptr_shrt++;
			}
			break;

		case phyCurrentChannel:
			if (tal_state != TAL_IDLE) {
				return TAL_BUSY;
			}

			if ((uint32_t)TRX_SUPPORTED_CHANNELS &
					((uint32_t)0x01 <<
					value->pib_value_8bit)) {
				tal_trx_status_t previous_trx_status = TRX_OFF;

				/*
				 * Set trx to "soft" off avoiding that ongoing
				 * transaction (e.g. ACK) are interrupted.
				 */
				if (tal_trx_status != TRX_OFF) {
					previous_trx_status = RX_AACK_ON; /* any
					                                   *other
					                                   *than
					                                   *TRX_OFF
					                                   *state
					                                   **/
					do {
						/* set TRX_OFF until it could be
						 * set;
						 * trx might be busy */
					} while (set_trx_state(CMD_TRX_OFF) !=
							TRX_OFF);
				}

				tal_pib.CurrentChannel = value->pib_value_8bit;
				pal_trx_bit_write(SR_CHANNEL,
						tal_pib.CurrentChannel);
				/* Re-store previous trx state */
				if (previous_trx_status != TRX_OFF) {
					/* Set to default state */
					set_trx_state(CMD_RX_AACK_ON);
				}
			} else {
				return MAC_INVALID_PARAMETER;
			}

			break;

		case phyCurrentPage:

			if (tal_state != TAL_IDLE) {
				return TAL_BUSY;
			} else {
				uint8_t page;

				page = value->pib_value_8bit;
				if (page != 0) {
					return MAC_INVALID_PARAMETER;
				}
			}

			break;

		case macMaxBE:
			tal_pib.MaxBE = value->pib_value_8bit;
#ifndef REDUCED_PARAM_CHECK

			/*
			 * macMinBE must not be larger than macMaxBE or
			 *calculation
			 * of macMaxFrameWaitTotalTime will fail.
			 */
			if (tal_pib.MaxBE < tal_pib.MinBE) {
				tal_pib.MinBE = tal_pib.MaxBE;
			}

#endif  /* REDUCED_PARAM_CHECK */
			break;

		case phyTransmitPower:
		{
			uint8_t reg_value;

			tal_pib.TransmitPower = value->pib_value_8bit;

			/* Limit tal_pib.TransmitPower to max/min trx values */
			tal_pib.TransmitPower = limit_tx_pwr(
					tal_pib.TransmitPower);
			reg_value = convert_phyTransmitPower_to_reg_value(
					tal_pib.TransmitPower);
			pal_trx_bit_write(SR_TX_PWR, reg_value);
		}
		break;

		case phyCCAMode:
			tal_pib.CCAMode = value->pib_value_8bit;
			pal_trx_bit_write(SR_CCA_MODE, tal_pib.CCAMode);
			break;

		case macIeeeAddress:
		{
			uint8_t *ptr;
			tal_pib.IeeeAddress = value->pib_value_64bit;
			ptr = (uint8_t *)&tal_pib.IeeeAddress;
			for (uint8_t i = 0; i < 8; i++) {
				pal_trx_reg_write((RG_IEEE_ADDR_0 + i), *ptr);
				ptr++;
			}
		}
		break;

		case mac_i_pan_coordinator:
			tal_pib.PrivatePanCoordinator = value->pib_value_bool;
			pal_trx_bit_write(SR_I_AM_COORD,
					tal_pib.PrivatePanCoordinator);
			break;

		case macAckWaitDuration:
			/* AT86RF230B does not support changing this value */
			return MAC_UNSUPPORTED_ATTRIBUTE;

		default:
			return MAC_UNSUPPORTED_ATTRIBUTE;
		}

		break; /* end of 'default' from 'switch (attribute)' */
	}
	return MAC_SUCCESS;
} /* tal_pib_set() */
/**
 * \brief Configures the transceiver
 *
 * This function is called to configure the transceiver after reset.
 */
static void trx_config(void)
{
	/* Set pin driver strength */
	trx_bit_write(SR_PAD_IO_CLKM, PAD_CLKM_2_MA);
	trx_bit_write(SR_CLKM_SHA_SEL, CLKM_SHA_DISABLE);

#ifndef SW_CONTROLLED_CSMA

	/* After we have initialized a proper seed for rand(),
	 * the transceiver's CSMA seed can be initialized.
	 * It needs to be assured that a seed for function rand()
	 * had been generated before.
	 */

	/*
	 * Init the SEED value of the CSMA backoff algorithm.
	 */
	uint16_t 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));

	/*
	 * To make sure that the CSMA seed is properly set within the
	 * transceiver,
	 * put the trx to sleep briefly and wake it up again.
	 */
	tal_trx_sleep(SLEEP_MODE_1);
	tal_trx_wakeup();
#endif

	trx_bit_write(SR_AACK_SET_PD, SET_PD); /* ACKs for data requests,
	                                        * indicate pending data */
	trx_bit_write(SR_RX_SAFE_MODE, RX_SAFE_MODE_ENABLE); /* Enable
	                                                      * buffer
	                                                      * protection
	                                                      * mode */
	trx_bit_write(SR_IRQ_MASK_MODE, IRQ_MASK_MODE_ON); /* Enable poll
	                                                    * mode */
	trx_reg_write(RG_IRQ_MASK, TRX_IRQ_DEFAULT); /* The TRX_END
	                                              * interrupt of the
	                                              * transceiver is
	                                              * enabled. */

#if (ANTENNA_DIVERSITY == 1)
	trx_bit_write(SR_ANT_EXT_SW_EN, ANT_EXT_SW_ENABLE); /* Enable
	                                                     * antenna
	                                                     * diversity. */
#if (ANTENNA_DEFAULT != ANT_CTRL_1)
	trx_bit_write(SR_ANT_CTRL, ANTENNA_DEFAULT);
#endif  /* ANTENNA_DEFAULT */
#endif
#if ((defined BEACON_SUPPORT) || (defined ENABLE_TSTAMP)) && \
	(DISABLE_TSTAMP_IRQ == 0)

	/*
	 * Use timestamping.
	 * The timestamping is only required for beaconing networks
	 * or if timestamping is explicitly enabled.
	 */
	/* Enable timestamping output signal - DIG2. */
	trx_bit_write(SR_IRQ_2_EXT_EN, RX_TIMESTAMPING_ENABLE);
#endif  /* #if (defined BEACON_SUPPORT) || (defined ENABLE_TSTAMP) */

#ifdef CCA_ED_THRESHOLD

	/*
	 * Set CCA ED Threshold to other value than standard register due to
	 * board specific loss (see pal_config.h). */
	trx_bit_write(SR_CCA_ED_THRES, CCA_ED_THRESHOLD);
#endif

#ifndef ENABLE_RX_OVERRIDE
	trx_bit_write(SR_RX_OVERRIDE, RXO_ENABLE);
#else

	/*
	 * Allow overriding of a 'weak' frame when another frame with stronger
	 * signal power arrives during the reception of this 'weak' frame.
	 */
	trx_bit_write(SR_RX_OVERRIDE, ENABLE_RX_OVERRIDE);
#endif /* ENABLE_RX_OVERRIDE */
}
Beispiel #6
0
/**
 * \brief Configures the transceiver
 *
 * This function is called to configure the transceiver after reset.
 */
static void trx_config(void)
{
	/* Set pin driver strength */
	trx_bit_write(SR_PAD_IO_CLKM, PAD_CLKM_2_MA);
	trx_bit_write(SR_CLKM_SHA_SEL, CLKM_SHA_DISABLE);
	trx_bit_write(SR_CLKM_CTRL, CLKM_1MHZ);

#ifndef SW_CONTROLLED_CSMA

	/* After we have initialized a proper seed for rand(),
	 * the transceiver's CSMA seed can be initialized.
	 * It needs to be assured that a seed for function rand()
	 * had been generated before.
	 */

	/*
	 * Init the SEED value of the CSMA backoff algorithm.
	 */
	uint16_t 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));

	/*
	 * To make sure that the CSMA seed is properly set within the
	 * transceiver,
	 * put the trx to sleep briefly and wake it up again.
	 */
	tal_trx_sleep(SLEEP_MODE_1);
	tal_trx_wakeup();
#endif

	trx_bit_write(SR_AACK_SET_PD, PD_ACK_BIT_SET_ENABLE); /* ACKs for
	                                                       * data
	                                                       * requests,
	                                                       * indicate
	                                                       * pending data
	                                                       **/
	trx_bit_write(SR_RX_SAFE_MODE, RX_SAFE_MODE_ENABLE); /* Enable
	                                                      * buffer
	                                                      * protection
	                                                      * mode */
	trx_bit_write(SR_IRQ_MASK_MODE, IRQ_MASK_MODE_ON); /* Enable poll
	                                                    * mode */
	trx_reg_write(RG_IRQ_MASK, TRX_IRQ_DEFAULT); /* The TRX_END
	                                              * interrupt of the
	                                              * transceiver is
	                                              * enabled. */

#if (ANTENNA_DIVERSITY == 1)
	/* Use antenna diversity */
	trx_bit_write(SR_ANT_CTRL, ANTENNA_DEFAULT);
	trx_bit_write(SR_PDT_THRES, THRES_ANT_DIV_ENABLE);
	trx_bit_write(SR_ANT_DIV_EN, ANT_DIV_ENABLE);
	trx_bit_write(SR_ANT_EXT_SW_EN, ANT_EXT_SW_ENABLE);
#elif (DISABLE_TSTAMP_IRQ == 0)
#if (defined BEACON_SUPPORT) || (defined ENABLE_TSTAMP)

	/*
	 * Use timestamping.
	 * The timestamping is only required for beaconing networks
	 * or if timestamping is explicitly enabled.
	 */
	trx_bit_write(SR_IRQ_2_EXT_EN, TIMESTAMPING_ENABLE); /* Enable
	                                                      * timestamping
	                                                      * output
	                                                      * signal. */
#endif  /* #if (defined BEACON_SUPPORT) || (defined ENABLE_TSTAMP) */
#endif

#ifdef CCA_ED_THRESHOLD

	/*
	 * Set CCA ED Threshold to other value than standard register due to
	 * board specific loss (see pal_config.h). */
	trx_bit_write(SR_CCA_ED_THRES, CCA_ED_THRESHOLD);
#endif

#ifdef EXT_RF_FRONT_END_CTRL
	/* Enable RF front end control */
	trx_bit_write(SR_PA_EXT_EN, PA_EXT_ENABLE);
#endif
}
Beispiel #7
0
/**
 * @brief Sets a TAL PIB attribute
 *
 * This function is called to set the transceiver information base
 * attributes.
 *
 * @param attribute TAL infobase attribute ID
 * @param value TAL infobase attribute value to be set
 *
 * @return MAC_UNSUPPORTED_ATTRIBUTE if the TAL info base attribute is not found
 *         TAL_BUSY if the TAL is not in TAL_IDLE state. An exception is
 *         macBeaconTxTime which can be accepted by TAL even if TAL is not
 *         in TAL_IDLE state.
 *         MAC_SUCCESS if the attempt to set the PIB attribute was successful
 *         TAL_TRX_ASLEEP if trx is in SLEEP mode and access to trx is required
 */
retval_t tal_pib_set(uint8_t attribute, pib_value_t *value)
{
    /*
     * Do not allow any changes while ED or TX is done.
     * We allow changes during RX, but it's on the user's own risk.
     */
#if (MAC_SCAN_ED_REQUEST_CONFIRM == 1)
    if (tal_state == TAL_ED_RUNNING)
    {
        ASSERT("TAL is busy" == 0);
        return TAL_BUSY;
    }
#endif /* (MAC_SCAN_ED_REQUEST_CONFIRM == 1) */

    /*
     * Distinguish between PIBs that need to be changed in trx directly
     * and those that are simple variable udpates.
     * Ensure that the transceiver is not in SLEEP.
     * If it is in SLEEP, change it to TRX_OFF.
     */

    switch (attribute)
    {
        case macMaxFrameRetries:
                    /*
                     * The new PIB value is not immediately written to the
                     * transceiver. This is done on a frame-by-frame base.
                     */
                    tal_pib_MaxFrameRetries = value->pib_value_8bit;
                    break;

        case macMaxCSMABackoffs:
                    /*
                     * The new PIB value is not immediately written to the
                     * transceiver. This is done on a frame-by-frame base.
                     */
                    tal_pib_MaxCSMABackoffs = value->pib_value_8bit;
                    break;

#ifdef BEACON_SUPPORT
        case macBattLifeExt:
            tal_pib_BattLifeExt = value->pib_value_bool;
            break;

        case macBeaconOrder:
            tal_pib_BeaconOrder = value->pib_value_8bit;
            break;

        case macSuperframeOrder:
            tal_pib_SuperFrameOrder = value->pib_value_8bit;
            break;

        case macBeaconTxTime:
            tal_pib_BeaconTxTime = value->pib_value_32bit;
            break;

#endif  /* BEACON_SUPPORT */
#ifdef PROMISCUOUS_MODE
        case macPromiscuousMode:
            tal_pib_PromiscuousMode = value->pib_value_8bit;
            if (tal_pib_PromiscuousMode)
            {
                tal_trx_wakeup();

                /* Check if receive buffer is available or queue is not full. */
                if (NULL == tal_rx_buffer)
                {
                    set_trx_state(CMD_PLL_ON);
                    tal_rx_on_required = true;
                }
                else
                {
                    set_trx_state(CMD_RX_ON);
                }
            }
            else
            {
                set_trx_state(CMD_TRX_OFF);
                tal_rx_on_required = false;
            }
            break;
#endif

        default:
            /*
             * Following PIBs require access to trx.
             * Therefore trx must be at least in TRX_OFF.
             */

            if (tal_trx_status == TRX_SLEEP)
            {
                /* While trx is in SLEEP, register cannot be accessed. */
                return TAL_TRX_ASLEEP;
            }

            switch (attribute)
            {
                case macMinBE:
                    tal_pib_MinBE = value->pib_value_8bit;

#ifndef REDUCED_PARAM_CHECK
                    /*
                     * macMinBE must not be larger than macMaxBE or calculation
                     * of macMaxFrameWaitTotalTime will fail.
                     */
                    if (tal_pib_MinBE > tal_pib_MaxBE)
                    {
                        tal_pib_MinBE = tal_pib_MaxBE;
                    }
#endif  /* REDUCED_PARAM_CHECK */

                    pal_trx_bit_write(SR_MIN_BE, tal_pib_MinBE);
                    break;

                case macPANId:
                    tal_pib_PANId = value->pib_value_16bit;
                    pal_trx_reg_write(RG_PAN_ID_0, (uint8_t)tal_pib_PANId);
                    pal_trx_reg_write(RG_PAN_ID_1, (uint8_t)(tal_pib_PANId >> 8));
                    break;

                case macShortAddress:
                    tal_pib_ShortAddress = value->pib_value_16bit;
                    pal_trx_reg_write(RG_SHORT_ADDR_0, (uint8_t)tal_pib_ShortAddress);
                    pal_trx_reg_write(RG_SHORT_ADDR_1, (uint8_t)(tal_pib_ShortAddress >> 8));
                    break;

                case phyCurrentChannel:
                    if (tal_state != TAL_IDLE)
                    {
                        return TAL_BUSY;
                    }

                    if (tal_pib_CurrentPage == 5)
                    {
                        if (((uint32_t)TRX_SUPPORTED_CHANNELS_CHINA & ((uint32_t)0x01 << value->pib_value_8bit)) == false)
                        {
                            return MAC_INVALID_PARAMETER;
                        }
                    }
                    else
                    {
                        if (((uint32_t)TRX_SUPPORTED_CHANNELS & ((uint32_t)0x01 << value->pib_value_8bit)) == false)
                        {
                            return MAC_INVALID_PARAMETER;
                        }
                    }

                    {
                        uint8_t previous_channel;
                        tal_trx_status_t previous_trx_status = TRX_OFF;

                        previous_channel = tal_pib_CurrentChannel;
                        tal_pib_CurrentChannel = value->pib_value_8bit;

                        /*
                         * Set trx to "soft" off avoiding that ongoing
                         * transaction (e.g. ACK) are interrupted.
                         */
                        if (tal_trx_status != TRX_OFF)
                        {
                            previous_trx_status = RX_AACK_ON;   /* any other than TRX_OFF state */
                            do
                            {
                                /* set TRX_OFF until it could be set;
                                 * trx might be busy */
                            } while (set_trx_state(CMD_TRX_OFF) != TRX_OFF);
                        }

                        /* Check if frequency band/modulation is changed. */
                        if (tal_pib_CurrentPage == 5)
                        {
                            pal_trx_bit_write(SR_CC_NUMBER, GET_CHINA_FREQ(tal_pib_CurrentChannel));
                        }
                        else if ((tal_pib_CurrentChannel > 0) && (previous_channel > 0))
                        {
                            pal_trx_bit_write(SR_CHANNEL, tal_pib_CurrentChannel);
                        }
                        else
                        {
                            uint8_t reg_value;

                            /* Set modulation and channel */
                            apply_channel_page_configuration(tal_pib_CurrentPage);
                            limit_tx_pwr();
                            reg_value = convert_phyTransmitPower_to_reg_value(tal_pib_TransmitPower);
                            pal_trx_reg_write(RG_PHY_TX_PWR, reg_value);
                        }

                        /* Re-store previous trx state */
                        if (previous_trx_status != TRX_OFF)
                        {
                            /* Set to default state */
                            set_trx_state(CMD_RX_AACK_ON);
                        }
                    }
                    break;

                case phyCurrentPage:
                    if (tal_state != TAL_IDLE)
                    {
                        return TAL_BUSY;
                    }
                    else
                    {
                        uint8_t page;
                        tal_trx_status_t previous_trx_status = TRX_OFF;
                        bool ret_val;
                        uint8_t reg_value;

                        /*
                         * Changing the channel, channel page or modulation
                         * requires that TRX is in TRX_OFF.
                         * Store current trx state and return to default state
                         * after channel page has been set.
                         */
                        if (tal_trx_status != TRX_OFF)
                        {
                            previous_trx_status = RX_AACK_ON;   /* any other than TRX_OFF state */
                            do
                            {
                                /* set TRX_OFF until it could be set;
                                 * trx might be busy */
                            } while (set_trx_state(CMD_TRX_OFF) != TRX_OFF);
                        }

                        page = value->pib_value_8bit;

                        ret_val = apply_channel_page_configuration(page);

                        if (previous_trx_status != TRX_OFF)
                        {
                            /* Set to default state */
                            set_trx_state(CMD_RX_AACK_ON);
                        }

                        if (ret_val)
                        {
                            tal_pib_CurrentPage = page;
                        }
                        else
                        {
                            return MAC_INVALID_PARAMETER;
                        }
                        limit_tx_pwr();
                        reg_value = convert_phyTransmitPower_to_reg_value(tal_pib_TransmitPower);
                        pal_trx_reg_write(RG_PHY_TX_PWR, reg_value);
                    }
                    break;

                case macMaxBE:
                    tal_pib_MaxBE = value->pib_value_8bit;
#ifndef REDUCED_PARAM_CHECK
                    /*
                     * macMinBE must not be larger than macMaxBE or calculation
                     * of macMaxFrameWaitTotalTime will fail.
                     */
                    if (tal_pib_MaxBE < tal_pib_MinBE)
                    {
                        tal_pib_MinBE = tal_pib_MaxBE;
                    }
#endif  /* REDUCED_PARAM_CHECK */
                    pal_trx_bit_write(SR_MAX_BE, tal_pib_MaxBE);
                    break;

                case phyTransmitPower:
                    {
                        uint8_t reg_value;

                        tal_pib_TransmitPower = value->pib_value_8bit;

                        /* Limit tal_pib_TransmitPower to max/min trx values */
                        limit_tx_pwr();
                        reg_value = convert_phyTransmitPower_to_reg_value(tal_pib_TransmitPower);
                        pal_trx_reg_write(RG_PHY_TX_PWR, reg_value);
                    }
                    break;

                case phyCCAMode:
                    tal_pib_CCAMode = value->pib_value_8bit;
                    pal_trx_bit_write(SR_CCA_MODE, tal_pib_CCAMode);
                    break;

                case macIeeeAddress:
                    {
                        uint8_t *ptr;

                        tal_pib_IeeeAddress = value->pib_value_64bit;
                        ptr = (uint8_t *)&tal_pib_IeeeAddress;

                        for (uint8_t i = 0; i < 8; i++)
                        {
                            pal_trx_reg_write((RG_IEEE_ADDR_0 + i), *ptr);
                            ptr++;
                        }
                    }
                    break;

                case mac_i_pan_coordinator:
                    tal_pib_PrivatePanCoordinator = value->pib_value_bool;
                    pal_trx_bit_write(SR_AACK_I_AM_COORD, tal_pib_PrivatePanCoordinator);
                    break;

                case macAckWaitDuration:
                    /*
                     * AT86RF212 does not support changing this value w.r.t.
                     * compliance operation.
                     */
                    return MAC_UNSUPPORTED_ATTRIBUTE;

                default:
                    return MAC_UNSUPPORTED_ATTRIBUTE;
            }

            break; /* end of 'default' from 'switch (attribute)' */
    }
    return MAC_SUCCESS;
} /* tal_pib_set() */
Beispiel #8
0
retval_t mlme_set(uint8_t attribute, pib_value_t *attribute_value,
		bool set_trx_to_sleep)
#endif
{
	/*
	 * Variables indicates whether the transceiver has been woken up for
	 * setting a TAL PIB attribute.
	 */
	static bool trx_pib_wakeup;

	retval_t status = MAC_SUCCESS;

	switch (attribute) {
#if (MAC_ASSOCIATION_REQUEST_CONFIRM == 1)
	case macAssociatedPANCoord:
		mac_pib.mac_AssociatedPANCoord
			= attribute_value->pib_value_8bit;
		break;
#endif /* (MAC_ASSOCIATION_REQUEST_CONFIRM == 1) */

#if ((MAC_INDIRECT_DATA_BASIC == 1) || defined(BEACON_SUPPORT))
	case macMaxFrameTotalWaitTime:
		mac_pib.mac_MaxFrameTotalWaitTime
			= attribute_value->pib_value_16bit;
		break;
#endif  /* ((MAC_INDIRECT_DATA_BASIC == 1) || defined(BEACON_SUPPORT)) */

	case macResponseWaitTime:
		mac_pib.mac_ResponseWaitTime = attribute_value->pib_value_16bit;
		break;

	case macAutoRequest:
#if (MAC_BEACON_NOTIFY_INDICATION == 1)

		/*
		 * If the beacon notification indications are not included
		 * in the build, macAutoRequest can be changed as desired, since
		 * beacon frames will be indicated to the higher
		 * layer if required as defined by IEEE 802.15.4.
		 */
		mac_pib.mac_AutoRequest = attribute_value->pib_value_8bit;
		break;
#else

		/*
		 * If the beacon notification indications are not included
		 * in the build, macAutoRequest must not be changed, since
		 * beacon frames will never be indicated to the higher
		 * layer, i.e. the higher would not be able to act on
		 * received beacon frame information itself.
		 */
		status = MAC_INVALID_PARAMETER;
		break;
#endif  /* (MAC_BEACON_NOTIFY_INDICATION == 1) */

#ifdef GTS_SUPPORT
	case macGTSPermit:
		mac_pib.mac_GTSPermit
			= attribute_value->pib_value_8bit;
		break;
#endif /* GTS_SUPPORT */

	case macBattLifeExtPeriods:
		mac_pib.mac_BattLifeExtPeriods
			= attribute_value->pib_value_8bit;
		break;

#if (MAC_ASSOCIATION_INDICATION_RESPONSE == 1)
	case macAssociationPermit:
		mac_pib.mac_AssociationPermit = attribute_value->pib_value_8bit;
		break;
#endif /* (MAC_ASSOCIATION_INDICATION_RESPONSE == 1) */

#if (MAC_START_REQUEST_CONFIRM == 1)
	case macBeaconPayload:
		memcpy(mac_beacon_payload, attribute_value,
				mac_pib.mac_BeaconPayloadLength);
		break;

	case macBeaconPayloadLength:
#ifndef REDUCED_PARAM_CHECK

		/*
		 * If the application sits directly  on top of the MAC,
		 * this is also checked in mac_api.c.
		 */
		if (attribute_value->pib_value_8bit > aMaxBeaconPayloadLength) {
			status = MAC_INVALID_PARAMETER;
			break;
		}
#endif  /* REDUCED_PARAM_CHECK */
		mac_pib.mac_BeaconPayloadLength
			= attribute_value->pib_value_8bit;
		break;

	case macBSN:
		mac_pib.mac_BSN = attribute_value->pib_value_8bit;
		break;
#endif  /* (MAC_START_REQUEST_CONFIRM == 1) */

#if (MAC_INDIRECT_DATA_FFD == 1)
	case macTransactionPersistenceTime:
		mac_pib.mac_TransactionPersistenceTime
			= attribute_value->pib_value_16bit;
		break;
#endif /* (MAC_INDIRECT_DATA_FFD == 1) */
	case macCoordExtendedAddress:
		mac_pib.mac_CoordExtendedAddress
			= attribute_value->pib_value_64bit;
		break;

	case macCoordShortAddress:
		mac_pib.mac_CoordShortAddress
			= attribute_value->pib_value_16bit;
		break;

	case macDSN:
		mac_pib.mac_DSN = attribute_value->pib_value_8bit;
		break;

	case macRxOnWhenIdle:
		mac_pib.mac_RxOnWhenIdle = attribute_value->pib_value_8bit;
		/* Check whether radio state needs to change now, */
		if (mac_pib.mac_RxOnWhenIdle) {
			/* 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);
		} else {
			/* Check whether the radio needs to be put to sleep. */
			mac_sleep_trans();
		}

		break;

	case macBattLifeExt:
	case macBeaconOrder:
	case macMaxCSMABackoffs:
	case macMaxBE:
	case macMaxFrameRetries:
	case macMinBE:
	case macPANId:
#ifdef PROMISCUOUS_MODE
	case macPromiscuousMode:
#endif /* PROMISCUOUS_MODE */
	case macShortAddress:
	case macSuperframeOrder:
	case macIeeeAddress:
	case phyCurrentChannel:
	case phyCurrentPage:
	case phyTransmitPower:
	case phyCCAMode:
#ifdef TEST_HARNESS
	case macPrivateCCAFailure:
	case macPrivateDisableACK:
#endif /* TEST_HARNESS */
		{
			/* Now only TAL PIB attributes are handled anymore. */
			status = tal_pib_set(attribute, attribute_value);

			if (status == TAL_TRX_ASLEEP) {
				/*
				 * Wake up the transceiver and repeat the
				 * attempt
				 * to set the TAL PIB attribute.
				 */
				tal_trx_wakeup();
				status
					= tal_pib_set(attribute,
						attribute_value);
				if (status == MAC_SUCCESS) {
					/*
					 * Set flag indicating that the trx has
					 * been woken up
					 * during PIB setting.
					 */
					trx_pib_wakeup = true;
				}
			}

#if ((MAC_INDIRECT_DATA_BASIC == 1) || defined(BEACON_SUPPORT))

			/*
			 * In any case that the PIB setting was successful (no
			 * matter
			 * whether the trx had to be woken up or not), the PIB
			 * attribute
			 * recalculation needs to be done.
			 */
			if (status == MAC_SUCCESS) {
				/*
				 * The value of the PIB attribute
				 * macMaxFrameTotalWaitTime depends on the
				 * values of the
				 * following PIB attributes:
				 * macMinBE
				 * macMaxBE
				 * macMaxCSMABackoffs
				 * phyMaxFrameDuration
				 * In order to save code space and since
				 * changing of PIB
				 * attributes is going to happen not too often,
				 * this is done
				 * always whenever a PIB attribute residing in
				 * TAL is changed
				 * (since all above mentioned PIB attributes are
				 * in TAL).
				 */
				recalc_macMaxFrameTotalWaitTime();
			}
#endif  /* ((MAC_INDIRECT_DATA_BASIC == 1) || defined(BEACON_SUPPORT)) */
		}
		break;

	case macAckWaitDuration:
	default:
		status = MAC_UNSUPPORTED_ATTRIBUTE;
		break;

#if ((defined MAC_SECURITY_ZIP)  || (defined MAC_SECURITY_2006))
	case macSecurityEnabled:
		mac_pib.mac_SecurityEnabled = attribute_value->pib_value_8bit;
		break;

	case macKeyTable:
		if (attribute_index >= mac_sec_pib.KeyTableEntries) {
			status = MAC_INVALID_INDEX;
		} else {
			memcpy(&mac_sec_pib.KeyTable[attribute_index],
					attribute_value,
					sizeof(mac_key_table_t));
		}

		break;

	case macKeyTableEntries:
		if (attribute_value->pib_value_8bit >
				MAC_ZIP_MAX_KEY_TABLE_ENTRIES) {
			status = MAC_INVALID_PARAMETER;
		} else {
			mac_sec_pib.KeyTableEntries
				= attribute_value->pib_value_8bit;
		}

		break;

	case macDeviceTable:
		if (attribute_index >= mac_sec_pib.DeviceTableEntries) {
			status = MAC_INVALID_INDEX;
		} else {
			uint8_t *attribute_temp_ptr
				= (uint8_t *)attribute_value;

			/*
			 * Since the members of the mac_dev_table_t structure do
			 * contain padding bytes,
			 * each member needs to be filled in separately.
			 */
			/* PAN-Id */
			memcpy((uint8_t *)&mac_sec_pib.DeviceTable[
						attribute_index].DeviceDescriptor[
						0].PANId,
					attribute_temp_ptr,
					sizeof(uint16_t));

			/*
			 *
			 *ADDR_COPY_DST_SRC_16(mac_sec_pib.DeviceTable[attribute_index].DeviceDescriptor[0].PANId,
			 *(uint16_t *)attribute_temp_ptr); */
			attribute_temp_ptr += sizeof(uint16_t);

			/* Short Address */
			memcpy((uint8_t *)&mac_sec_pib.DeviceTable[
						attribute_index].DeviceDescriptor[
						0].ShortAddress,
					attribute_temp_ptr,
					sizeof(uint16_t));

			/*ADDR_COPY_DST_SRC_16(mac_sec_pib.DeviceTable[attribute_index].DeviceDescriptor[0].ShortAddress,
			 *(uint16_t *)attribute_temp_ptr);*/
			attribute_temp_ptr += sizeof(uint16_t);

			/* Extended Address */
			memcpy((uint8_t *)&mac_sec_pib.DeviceTable[
						attribute_index].DeviceDescriptor[
						0].ExtAddress,
					attribute_temp_ptr,
					sizeof(uint64_t));

			/*ADDR_COPY_DST_SRC_64(mac_sec_pib.DeviceTable[attribute_index].DeviceDescriptor[0].ExtAddress,
			 *(uint64_t *)attribute_temp_ptr);*/
			attribute_temp_ptr += sizeof(uint64_t);

			/* Extended Address */
			memcpy(
					&mac_sec_pib.DeviceTable[attribute_index].DeviceDescriptor[
						0].FrameCounter,
					attribute_temp_ptr,
					sizeof(uint32_t));
			attribute_temp_ptr += sizeof(uint32_t);

			/* Exempt */
			mac_sec_pib.DeviceTable[attribute_index].
			DeviceDescriptor[0].Exempt
				= *attribute_temp_ptr;
		}

		break;

	case macDeviceTableEntries:
		if (attribute_value->pib_value_16bit >
				MAC_ZIP_MAX_DEV_TABLE_ENTRIES) {
			status = MAC_INVALID_PARAMETER;
		} else {
			mac_sec_pib.DeviceTableEntries
				= attribute_value->pib_value_16bit;
		}

		break;

	case macSecurityLevelTable:
		if (attribute_index >= mac_sec_pib.SecurityLevelTableEntries) {
			status = MAC_INVALID_INDEX;
		} else {
			memcpy(&mac_sec_pib.SecurityLevelTable[attribute_index],
					attribute_value,
					sizeof(mac_sec_lvl_table_t));
		}

		break;

	case macSecurityLevelTableEntries:
		if (attribute_value->pib_value_8bit >
				MAC_ZIP_MAX_SEC_LVL_TABLE_ENTRIES) {
			status = MAC_INVALID_PARAMETER;
		} else {
			mac_sec_pib.SecurityLevelTableEntries
				= attribute_value->pib_value_8bit;
		}

		break;

	case macFrameCounter:
		mac_sec_pib.FrameCounter = attribute_value->pib_value_32bit;
		break;

	case macDefaultKeySource:
		/* Key Source length is 8 octets. */
		memcpy(mac_sec_pib.DefaultKeySource, attribute_value, 8);
		break;

	case macPANCoordExtendedAddress:
		memcpy(mac_sec_pib.PANCoordExtendedAddress, attribute_value, 8);
		break;

	case macPANCoordShortAddress:
		mac_sec_pib.PANCoordShortAddress
			= attribute_value->pib_value_16bit;
		break;
#endif  /* (MAC_SECURITY_ZIP || MAC_SECURITY_2006) */

#ifdef TEST_HARNESS
	case macPrivateIllegalFrameType:
		mac_pib.privateIllegalFrameType
			= attribute_value->pib_value_8bit;
		break;

	case macPrivateNoDataAfterAssocReq:
		mac_pib.privateNoDataAfterAssocReq
			= attribute_value->pib_value_8bit;
		break;

	case macPrivateVirtualPANs:
		mac_pib.privateVirtualPANs = attribute_value->pib_value_8bit;
		break;
#endif /* TEST_HARNESS */
	}

	/*
	 * In case the transceiver shall be forced back to sleep and
	 * has been woken up, it is put back to sleep again.
	 */
	if (set_trx_to_sleep && trx_pib_wakeup && !mac_pib.mac_RxOnWhenIdle) {
#ifdef ENABLE_DEEP_SLEEP
		tal_trx_sleep(DEEP_SLEEP_MODE);
#else
		tal_trx_sleep(SLEEP_MODE_1);
#endif
		trx_pib_wakeup = false;
	}

	return status;
}
/**
 * @brief Secure one block with CCM*
 *
 * This functions secures one block with CCM* according to 802.15.4.
 *
 * @param[in,out] buffer Input: plaintext header and payload concatenated;
 *                       for encryption: MUST HAVE 'AES_BLOCKSIZE'
 *                       BYTES SPACE AT THE END FOR THE MIC!
 *                       Output: frame secured (with MIC at end)/unsecured
 * @param[in]  nonce   The nonce: Initialization Vector (IV) as used in
 *                     cryptography; the ZigBee nonce (13 bytes long)
 *                     are the bytes 2...14 of this nonce
 * @param[in] key The key to be used; if NULL, use the current key
 * @param[in] hdr_len Length of plain text header (will not be encrypted)
 * @param[in] pld_len Length of payload to be encrypted; if 0, then only MIC
 *                    authentication implies
 * @param[in] sec_level Security level according to IEEE 802.15.4,
 *                    7.6.2.2.1, Table 95:
 *                    - the value may be 0 ... 7;
 *                    - the two LSBs contain the MIC length in bytes
 *                      (0, 4, 8 or 16);
 *                    - bit 2 indicates whether encryption applies or not
 * @param[in] aes_dir AES_DIR_ENCRYPT if secure, AES_DIR_DECRYPT if unsecured
 *
 * @return STB CCM Status
 */
stb_ccm_t stb_ccm_secure(uint8_t *buffer,
		uint8_t nonce[AES_BLOCKSIZE],
		uint8_t *key,
		uint8_t hdr_len,
		uint8_t pld_len,
		uint8_t sec_level,
		uint8_t aes_dir)
{
	uint8_t nonce_0; /* nonce[0] for MIC computation. */
	uint8_t mic_len = 0;
	uint8_t enc_flag = ENCRYPTION_NOT_REQD;

	if (stb_restart_required) {
#if (SAL_TYPE != ATXMEGA_SAL)
		prev_trx_status = tal_trx_status;
		if (tal_trx_status == TRX_SLEEP) {
			tal_trx_wakeup();
		}
#endif
		sal_aes_restart();
		stb_restart_required = false;
	}

	switch (sec_level) {
	case SECURITY_00_LEVEL:
		/* No MIC & No Encryption at Security Level -0 */
		mic_len = LEN_MIC_00;
		break;

	case SECURITY_01_LEVEL:
		/* MIC-32 & No Encryption at Security Level -1 */
		mic_len = LEN_MIC_32;
		break;

	case SECURITY_02_LEVEL:
		/* MIC-64 & No Encryption at Security Level -2 */
		mic_len = LEN_MIC_64;
		break;

	case SECURITY_03_LEVEL:
		/* MIC-128 & No Encryption at Security Level -3 */
		mic_len = LEN_MIC_128;
		break;

	case SECURITY_04_LEVEL:
		/* No MIC & Encryption at Security Level -4 */
		mic_len = LEN_MIC_00;
		enc_flag = ENCRYPTION_REQD;
		break;

	case SECURITY_05_LEVEL:
		/* MIC-32 & Encryption at Security Level -5 */
		mic_len = LEN_MIC_32;
		enc_flag = ENCRYPTION_REQD;
		break;

	case SECURITY_06_LEVEL:
		/* MIC-64 & Encryption at Security Level -6 */
		mic_len = LEN_MIC_64;
		enc_flag = ENCRYPTION_REQD;
		break;

	case SECURITY_07_LEVEL:
		/* MIC-128 & Encryption at Security Level -7 */
		mic_len = LEN_MIC_128;
		enc_flag = ENCRYPTION_REQD;
		break;

	default:
		break;
	}

	/* Test on correct parameters. */

	if ((sec_level & ~0x7) ||
			(buffer == NULL) ||
			(nonce == NULL) ||
			((uint16_t)pld_len + (uint16_t)hdr_len +
			(uint16_t)mic_len > aMaxPHYPacketSize)
			) {
#if (SAL_TYPE != ATXMEGA_SAL)
		TRX_SLEEP();
		sal_aes_clean_up();
#endif
		return (STB_CCM_ILLPARM);
	}

	if (key_change && (key == NULL)) {
#if (SAL_TYPE != ATXMEGA_SAL)
		TRX_SLEEP();
		sal_aes_clean_up();
#endif
		/* Initial call, but no key given. */
		return (STB_CCM_KEYMISS);
	}

	/* Setup key if necessary. */

	if (!key_change && key != NULL) { /* There was some previous key. */
		uint8_t i;

		/* Test on changed key. */
		for (i = AES_BLOCKSIZE; i--; /* */) {
			key_change |= (last_key[i] ^ key[i]);
		}
	}

	if (key_change) {
		/*
		 * Key must be non-NULL because of test above, and
		 * ECB encryption is always the initial encryption mode.
		 */
		sal_aes_setup(key, AES_MODE_ECB, AES_DIR_ENCRYPT);
		memcpy(last_key, key, AES_KEYSIZE);
		key_change = false;
	}

	/* Prepare nonce. */
	nonce[0] = LEN_FIELD; /* Always 2 bytes for length field. */

	if (mic_len > 0) {
		nonce[0] |= (uint8_t)(((mic_len - 2) >> 1) << 3);
	}