/**@brief Set scan parameters and start scanning * * @note The HCI spec specifies interval in units of 0.625 ms. * Here we use us directly. * * @param [in] scan_type: should be LL_SCAN_ACTIVE or LL_SCAN_PASSIVE * (only the latter implemented at this time) * @param [in] interval: the scan Interval in us * @param [in] window: the scan Window in us * @param [in] adv_report_cb: the function to call for advertising report events * * @return -EINVAL if window > interval or interval > 10.24 s * @return -EINVAL if scan_type != LL_SCAN_PASSIVE */ int16_t ll_scan_start(uint8_t scan_type, uint32_t interval, uint32_t window, adv_report_cb_t adv_report_cb) { int16_t err_code; if(window > interval || interval > LL_SCAN_INTERVAL_MAX) return -EINVAL; switch(scan_type) { case LL_SCAN_PASSIVE: /* Setup callback function */ ll_adv_report_cb = adv_report_cb; break; case LL_SCAN_ACTIVE: /* Not implemented */ default: return -EINVAL; } radio_set_callbacks(ll_on_radio_rx, NULL); /* Setup timer and save window length */ t_scan_window = window; err_code = timer_start(t_ll_interval, interval); if (err_code < 0) return err_code; current_state = LL_STATE_SCANNING; t_ll_interval_cb(); DBG("interval %uus, window %uus", interval, window); return 0; }
int16_t ll_advertise_start(ll_pdu_t type, uint32_t interval, uint8_t chmap) { int16_t err_code; if (current_state != LL_STATE_STANDBY) return -ENOREADY; if (!chmap || (chmap & !LL_ADV_CH_ALL)) return -EINVAL; if (interval % LL_ADV_INTERVAL_QUANTUM) return -EINVAL; if (interval < LL_ADV_INTERVAL_MIN_NONCONN || interval > LL_ADV_INTERVAL_MAX) return -EINVAL; adv_ch_map = chmap; switch (type) { case LL_PDU_ADV_IND: case LL_PDU_ADV_SCAN_IND: rx = true; break; case LL_PDU_ADV_NONCONN_IND: rx = false; break; case LL_PDU_ADV_DIRECT_IND: /* TODO: Not implemented */ default: /* Invalid PDU */ return -EINVAL; } pdu_adv.type = type; t_adv_pdu_interval = TIMER_MILLIS(10); /* <= 10ms Sec 4.4.2.6 */ radio_set_callbacks(rx ? ll_on_radio_rx : NULL, rx ? ll_on_radio_tx : NULL); DBG("PDU interval %u ms, event interval %u ms", t_adv_pdu_interval / 1000, interval / 1000); err_code = timer_start(t_ll_interval, interval); if (err_code < 0) return err_code; current_state = LL_STATE_ADVERTISING; t_ll_interval_cb(); return 0; }
int16_t radio_init(void) { if (NRF_CLOCK->EVENTS_HFCLKSTARTED == 0UL) { NRF_CLOCK->TASKS_HFCLKSTART = 1UL; while (NRF_CLOCK->EVENTS_HFCLKSTARTED == 0UL); } /* nRF51 Series Reference Manual v2.1, section 6.1.1, page 18 * PCN-083 rev.1.1 * * Fine tune BLE deviation parameters. */ if ((NRF_FICR->OVERRIDEEN & FICR_OVERRIDEEN_BLE_1MBIT_Msk) == (FICR_OVERRIDEEN_BLE_1MBIT_Override << FICR_OVERRIDEEN_BLE_1MBIT_Pos)) { NRF_RADIO->OVERRIDE0 = NRF_FICR->BLE_1MBIT[0]; NRF_RADIO->OVERRIDE1 = NRF_FICR->BLE_1MBIT[1]; NRF_RADIO->OVERRIDE2 = NRF_FICR->BLE_1MBIT[2]; NRF_RADIO->OVERRIDE3 = NRF_FICR->BLE_1MBIT[3]; NRF_RADIO->OVERRIDE4 = NRF_FICR->BLE_1MBIT[4] | 0x80000000; } /* nRF51 Series Reference Manual v2.1, section 16.2.7, page 86 */ NRF_RADIO->MODE = RADIO_MODE_MODE_Ble_1Mbit << RADIO_MODE_MODE_Pos; /* Link Layer specification section 4.1, Core 4.1, page 2524 * nRF51 Series Reference Manual v2.1, section 16.2.7, page 92 * * Set the inter frame space (T_IFS) to 150 us. */ NRF_RADIO->TIFS = 150; /* nRF51 Series Reference Manual v2.1, section 16.2.9, page 88 * * Enable data whitening, set the maximum payload length and set the * access address size (3 + 1 octets). */ NRF_RADIO->PCNF1 = (RADIO_PCNF1_WHITEEN_Enabled << RADIO_PCNF1_WHITEEN_Pos) | (MAX_PAYLOAD_LEN << RADIO_PCNF1_MAXLEN_Pos) | (3UL << RADIO_PCNF1_BALEN_Pos); /* nRF51 Series Reference Manual v2.1, section 16.1.4, page 74 * nRF51 Series Reference Manual v2.1, section 16.2.14-15, pages 89-90 * * Preset the address to use when receive and transmit packets (logical * address 0, which is assembled by base address BASE0 and prefix byte * PREFIX0.AP0. */ NRF_RADIO->RXADDRESSES = 1UL; NRF_RADIO->TXADDRESS = 0UL; /* nRF51 Series Reference Manual v2.1, section 16.1.7, page 76 * nRF51 Series Reference Manual v2.1, sections 16.1.16-17, page 90 * * Configure the CRC length (3 octets), polynominal and set it to * ignore the access address when calculate the CRC. */ NRF_RADIO->CRCCNF = (RADIO_CRCCNF_LEN_Three << RADIO_CRCCNF_LEN_Pos) | (RADIO_CRCCNF_SKIP_ADDR_Skip << RADIO_CRCCNF_SKIP_ADDR_Pos); NRF_RADIO->CRCPOLY = 0x100065B; /* nRF51 Series Reference Manual v2.1, section 16.1.2, page 74 * nRF51 Series Reference Manual v2.1, sections 16.1.8, page 87 * Link Layer specification section 2.3, Core 4.1, page 2504 * Link Layer specification section 2.4, Core 4.1, page 2511 * * Configure the header size. The nRF51822 has 3 fields before the * payload field: S0, LENGTH and S1. These fields can be used to store * the PDU header. */ NRF_RADIO->PCNF0 = (1UL << RADIO_PCNF0_S0LEN_Pos) | (8UL << RADIO_PCNF0_LFLEN_Pos) | (0UL << RADIO_PCNF0_S1LEN_Pos); /* nRF51 Series Reference Manual v2.1, section 16.1.8, page 76 * nRF51 Series Reference Manual v2.1, section 16.1.10-11, pages 78-80 * nRF51 Series Reference Manual v2.1, section 16.2.1, page 85 * * Enable READY_START short: when the READY event happens, initialize * the START task. * * Enable END_DISABLE short: when the END event happens, initialize the * DISABLE task. */ NRF_RADIO->SHORTS = BASE_SHORTS; /* Trigger RADIO interruption when an END event happens */ NRF_RADIO->INTENSET = RADIO_INTENSET_END_Msk; NVIC_SetPriority(RADIO_IRQn, IRQ_PRIORITY_HIGH); NVIC_ClearPendingIRQ(RADIO_IRQn); NVIC_EnableIRQ(RADIO_IRQn); radio_set_callbacks(NULL, NULL); radio_set_tx_power(RADIO_POWER_0_DBM); radio_set_out_buffer(NULL); NRF_RADIO->PACKETPTR = (uint32_t) inbuf; memset(inbuf, 0, sizeof(inbuf)); status = STATUS_INITIALIZED; return 0; }