Пример #1
0
/** Callback function for the "interval" LL timer
 */
static void t_ll_interval_cb(void)
{
	switch(current_state) {
		case LL_STATE_ADVERTISING:
			adv_ch_idx = first_adv_ch_idx();
			t_ll_single_shot_cb();
			break;

		case LL_STATE_SCANNING:
			if(!inc_adv_ch_idx())
				adv_ch_idx = first_adv_ch_idx();

			radio_prepare(adv_chs[adv_ch_idx],
					LL_ACCESS_ADDRESS_ADV, LL_CRCINIT_ADV);
			radio_recv(0);
			timer_start(t_ll_single_shot, t_scan_window);
			break;

		case LL_STATE_INITIATING:
		case LL_STATE_CONNECTION:
			/* Not implemented */
		case LL_STATE_STANDBY:
		default:
			/* Nothing to do */
			return;
	}
}
Пример #2
0
/** Callback function for the "single shot" LL timer
 */
static void t_ll_single_shot_cb(void)
{
	switch(current_state) {
		case LL_STATE_ADVERTISING:
			radio_stop();
			radio_prepare(adv_chs[adv_ch_idx],
					LL_ACCESS_ADDRESS_ADV, LL_CRCINIT_ADV);
			radio_send((uint8_t *) &pdu_adv,
						rx ? RADIO_FLAGS_RX_NEXT : 0);

			prev_adv_ch_idx = adv_ch_idx;
			if (!inc_adv_ch_idx())
				timer_start(t_ll_single_shot,
							t_adv_pdu_interval);
			break;

		case LL_STATE_SCANNING:
			/* Called at the end of the scan window */
			radio_stop();
			break;

		case LL_STATE_INITIATING:
		case LL_STATE_CONNECTION:
			/* Not implemented */
		case LL_STATE_STANDBY:
		default:
			/* Nothing to do */
			return;
	}
}
Пример #3
0
/**@brief Function for handling vendor specific commands.
 *        Used when packet type is set to Vendor specific.
 *        The length field is used for encoding vendor specific command.
 *        The frequency field is used for encoding vendor specific options to the command.
 *
 * @param[in]   vendor_cmd      Vendor specific command to be executed.
 * @param[in]   vendor_option   Vendor specific option to the vendor command.
 *
 * @return      DTM_SUCCESS or one of the DTM_ERROR_ values
 */
static uint32_t dtm_vendor_specific_pkt(uint32_t vendor_cmd, dtm_freq_t vendor_option)
{
    switch (vendor_cmd)
    {
        // nRFgo Studio uses CARRIER_TEST_STUDIO to indicate a continuous carrier without
        // a modulated signal.
        case CARRIER_TEST:
        case CARRIER_TEST_STUDIO:
            // Not a packet type, but used to indicate that a continuous carrier signal
            // should be transmitted by the radio.
            radio_prepare(TX_MODE);

            dtm_constant_carrier();

            // Shortcut between READY event and START task
            NRF_RADIO->SHORTS = 1 << RADIO_SHORTS_READY_START_Pos;

            // Shortcut will start radio in Tx mode when it is ready
            NRF_RADIO->TASKS_TXEN = 1;
            m_state               = STATE_CARRIER_TEST;
            break;

        case SET_TX_POWER:
            if (!dtm_set_txpower(vendor_option))
            {
                return DTM_ERROR_ILLEGAL_CONFIGURATION;
            }
            break;

        case SELECT_TIMER:
            if (!dtm_set_timer(vendor_option))
            {
                return DTM_ERROR_ILLEGAL_CONFIGURATION;
            }
            break;
    }
    // Event code is unchanged, successful
    return DTM_SUCCESS;
}
Пример #4
0
uint32_t dtm_cmd(dtm_cmd_t cmd, dtm_freq_t freq, uint32_t length, dtm_pkt_type_t payload)
{
    // Save specified packet in static variable for tx/rx functions to use.
    // Note that BLE conformance testers always use full length packets.
    m_packet_length = (m_packet_length & 0xC0) | ((uint8_t)length & 0x3F);
    m_packet_type   = payload;
    m_phys_ch       = freq;

    // Clean out any non-retrieved event that might linger from an earlier test
    m_new_event     = true;

    // Set default event; any error will set it to LE_TEST_STATUS_EVENT_ERROR
    m_event         = LE_TEST_STATUS_EVENT_SUCCESS;

    if (m_state == STATE_UNINITIALIZED)
    {
        // Application has not explicitly initialized DTM,
        return DTM_ERROR_UNINITIALIZED;
    }

    if (cmd == LE_RESET)
    {
        // Note that timer will continue running after a reset
        dtm_test_done();
        if (freq == 0x01)
        {
            m_packet_length = length << 6;
        }
        else
        {
            m_packet_length = 0;
        }
        return DTM_SUCCESS;
    }

    if (cmd == LE_TEST_END)
    {
        if (m_state == STATE_IDLE)
        {
            // Sequencing error - only rx or tx test may be ended!
            m_event = LE_TEST_STATUS_EVENT_ERROR;
            return DTM_ERROR_INVALID_STATE;
        }
        m_event = LE_PACKET_REPORTING_EVENT | m_rx_pkt_count;
        dtm_test_done();
        return DTM_SUCCESS;
    }

    if (m_state != STATE_IDLE)
    {
        // Sequencing error - only TEST_END/RESET are legal while test is running
        // Note: State is unchanged; ongoing test not affected
        m_event = LE_TEST_STATUS_EVENT_ERROR;
        return DTM_ERROR_INVALID_STATE;
    }

    // Check for illegal values of m_phys_ch. Skip the check if the packet is vendor spesific.
    if (payload != DTM_PKT_VENDORSPECIFIC && m_phys_ch > PHYS_CH_MAX)
    {
        // Parameter error
        // Note: State is unchanged; ongoing test not affected
        m_event = LE_TEST_STATUS_EVENT_ERROR;
        return DTM_ERROR_ILLEGAL_CHANNEL;
    }

    m_rx_pkt_count = 0;

    if (cmd == LE_RECEIVER_TEST)
    {
        // Zero fill all pdu fields to avoid stray data from earlier test run
        memset(&m_pdu, 0, DTM_PDU_MAX_MEMORY_SIZE);
        radio_prepare(RX_MODE);                      // Reinitialize "everything"; RF interrupts OFF
        m_state = STATE_RECEIVER_TEST;
        return DTM_SUCCESS;
    }

    if (cmd == LE_TRANSMITTER_TEST)
    {
        // Check for illegal values of m_packet_length. Skip the check if the packet is vendor spesific.
        if (payload != DTM_PKT_VENDORSPECIFIC && m_packet_length > DTM_PAYLOAD_MAX_SIZE)
        {
            // Parameter error
            m_event = LE_TEST_STATUS_EVENT_ERROR;
            return DTM_ERROR_ILLEGAL_LENGTH;
        }

        // Note that PDU uses 4 bits even though BLE DTM uses only 2 (the HCI SDU uses all 4)
        m_pdu.content[DTM_HEADER_OFFSET] = ((uint8_t)m_packet_type & 0x0F);
        m_pdu.content[DTM_LENGTH_OFFSET] = m_packet_length;

        switch (m_packet_type)
        {
            case DTM_PKT_PRBS9:
                // Non-repeated, must copy entire pattern to PDU
                memcpy(m_pdu.content + DTM_HEADER_SIZE, m_prbs_content, m_packet_length);
                break;

            case DTM_PKT_0X0F:
                // Bit pattern 00001111 repeated
                memset(m_pdu.content + DTM_HEADER_SIZE, RFPHY_TEST_0X0F_REF_PATTERN, m_packet_length);
                break;

            case DTM_PKT_0X55:
                // Bit pattern 01010101 repeated
                memset(m_pdu.content + DTM_HEADER_SIZE, RFPHY_TEST_0X55_REF_PATTERN, m_packet_length);
                break;

            case DTM_PKT_VENDORSPECIFIC:
                // The length field is for indicating the vendor specific command to execute.
                // The frequency field is used for vendor specific options to the command.
                return dtm_vendor_specific_pkt(length, freq);

            default:
                // Parameter error
                m_event = LE_TEST_STATUS_EVENT_ERROR;
                return DTM_ERROR_ILLEGAL_CONFIGURATION;
        }

        // Initialize CRC value, set channel:
        radio_prepare(TX_MODE);
        // Set the timer to the correct period. The delay between each packet is described in the
        // Bluetooth Core Spsification version 4.2 Vol. 6 Part F Section 4.1.6.
        if ((m_packet_length + DTM_ON_AIR_OVERHEAD_SIZE ) * 8  <= 376)
        {
            mp_timer->CC[0]       = 625;                        // 625uS with 1MHz clock to the timer
        }
        else if ((m_packet_length + DTM_ON_AIR_OVERHEAD_SIZE ) * 8  <= 1000)
        {
            mp_timer->CC[0]       = 1250;                        // 625uS with 1MHz clock to the timer
        }
        else if ((m_packet_length + DTM_ON_AIR_OVERHEAD_SIZE ) * 8  <= 1624)
        {
            mp_timer->CC[0]       = 1875;                        // 625uS with 1MHz clock to the timer
        }
        else
        {
            mp_timer->CC[0]       = 2500;                        // 625uS with 1MHz clock to the timer
        }

        // Configure PPI so that timer will activate radio every 625 us
        NRF_PPI->CH[0].EEP = (uint32_t)&mp_timer->EVENTS_COMPARE[0];
        NRF_PPI->CH[0].TEP = (uint32_t)&NRF_RADIO->TASKS_TXEN;
        NRF_PPI->CHENSET   = 0x01;
        m_state            = STATE_TRANSMITTER_TEST;
    }
    return DTM_SUCCESS;
}