mirror of
https://github.com/bluekitchen/btstack.git
synced 2025-02-05 18:40:27 +00:00
Merge branch 'develop'
This commit is contained in:
commit
448d4b74f1
@ -26,6 +26,7 @@
|
|||||||
#include "bsp.h"
|
#include "bsp.h"
|
||||||
|
|
||||||
#include "btstack_config.h"
|
#include "btstack_config.h"
|
||||||
|
#include "btstack_debug.h"
|
||||||
#include "btstack_memory.h"
|
#include "btstack_memory.h"
|
||||||
#include "btstack_run_loop.h"
|
#include "btstack_run_loop.h"
|
||||||
#include "btstack_run_loop_embedded.h"
|
#include "btstack_run_loop_embedded.h"
|
||||||
@ -38,6 +39,10 @@
|
|||||||
#define ADVERTISING_RADIO_ACCESS_ADDRESS 0x8E89BED6
|
#define ADVERTISING_RADIO_ACCESS_ADDRESS 0x8E89BED6
|
||||||
#define ADVERTISING_CRC_INIT 0x555555
|
#define ADVERTISING_CRC_INIT 0x555555
|
||||||
|
|
||||||
|
// HCI CMD OGF/OCF
|
||||||
|
#define READ_CMD_OGF(buffer) (buffer[1] >> 2)
|
||||||
|
#define READ_CMD_OCF(buffer) ((buffer[1] & 0x03) << 8 | buffer[0])
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
LL_STATE_STANDBY,
|
LL_STATE_STANDBY,
|
||||||
LL_STATE_SCANNING,
|
LL_STATE_SCANNING,
|
||||||
@ -85,7 +90,6 @@ static void init_timer(void) {
|
|||||||
#if 1
|
#if 1
|
||||||
// start high frequency clock source if not done yet
|
// start high frequency clock source if not done yet
|
||||||
if ( !NRF_CLOCK->EVENTS_HFCLKSTARTED ) {
|
if ( !NRF_CLOCK->EVENTS_HFCLKSTARTED ) {
|
||||||
printf("1\n");
|
|
||||||
NRF_CLOCK->TASKS_HFCLKSTART = 1;
|
NRF_CLOCK->TASKS_HFCLKSTART = 1;
|
||||||
while ( !NRF_CLOCK->EVENTS_HFCLKSTARTED ){
|
while ( !NRF_CLOCK->EVENTS_HFCLKSTARTED ){
|
||||||
// just wait
|
// just wait
|
||||||
@ -99,13 +103,11 @@ static void init_timer(void) {
|
|||||||
|
|
||||||
NRF_TIMER0->TASKS_STOP = 1;
|
NRF_TIMER0->TASKS_STOP = 1;
|
||||||
NRF_TIMER0->TASKS_CLEAR = 1;
|
NRF_TIMER0->TASKS_CLEAR = 1;
|
||||||
#if 0
|
NRF_TIMER0->EVENTS_COMPARE[0] = 0;
|
||||||
NRF_TIMER0->EVENTS_COMPARE[ 0 ] = 0;
|
NRF_TIMER0->EVENTS_COMPARE[1] = 0;
|
||||||
NRF_TIMER0->EVENTS_COMPARE[ 1 ] = 0;
|
NRF_TIMER0->EVENTS_COMPARE[2] = 0;
|
||||||
NRF_TIMER0->EVENTS_COMPARE[ 2 ] = 0;
|
NRF_TIMER0->EVENTS_COMPARE[3] = 0;
|
||||||
NRF_TIMER0->EVENTS_COMPARE[ 3 ] = 0;
|
|
||||||
NRF_TIMER0->INTENCLR = 0xffffffff;
|
NRF_TIMER0->INTENCLR = 0xffffffff;
|
||||||
#endif
|
|
||||||
NRF_TIMER0->TASKS_START = 1;
|
NRF_TIMER0->TASKS_START = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -286,12 +288,15 @@ void RADIO_IRQHandler(void){
|
|||||||
} else {
|
} else {
|
||||||
// ... for now, we just throw the adv away and try to receive the next one
|
// ... for now, we just throw the adv away and try to receive the next one
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: check if there's enough time left before the end of the scan interval
|
||||||
|
|
||||||
|
// restart receiving
|
||||||
|
NRF_RADIO->TASKS_START = 1;
|
||||||
}
|
}
|
||||||
// restart receiving
|
|
||||||
NRF_RADIO->TASKS_START = 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint8_t random_generator_next(void){
|
uint8_t random_generator_next(void){
|
||||||
NRF_RNG->SHORTS = RNG_SHORTS_VALRDY_STOP_Enabled << RNG_SHORTS_VALRDY_STOP_Pos;
|
NRF_RNG->SHORTS = RNG_SHORTS_VALRDY_STOP_Enabled << RNG_SHORTS_VALRDY_STOP_Pos;
|
||||||
NRF_RNG->TASKS_START = 1;
|
NRF_RNG->TASKS_START = 1;
|
||||||
while (!NRF_RNG->EVENTS_VALRDY){
|
while (!NRF_RNG->EVENTS_VALRDY){
|
||||||
@ -299,30 +304,42 @@ static uint8_t random_generator_next(void){
|
|||||||
return NRF_RNG->VALUE;
|
return NRF_RNG->VALUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint32_t get_time_us(void){
|
// uses TIMER0-CC2 for reads
|
||||||
NRF_TIMER0->TASKS_CAPTURE[0] = 1;
|
uint32_t get_time_us(void){
|
||||||
return NRF_TIMER0->CC[0];
|
NRF_TIMER0->TASKS_CAPTURE[2] = 1;
|
||||||
|
return NRF_TIMER0->CC[2];
|
||||||
}
|
}
|
||||||
|
|
||||||
// static
|
volatile int timer_irq_happened;
|
||||||
void tick(void){
|
void TIMER0_IRQHandler(void){
|
||||||
uint32_t now = 0;
|
// Reset IRQ flag
|
||||||
while (1){
|
NRF_TIMER0->EVENTS_COMPARE[0] = 0;
|
||||||
uint8_t random = random_generator_next();
|
NRF_TIMER0->TASKS_CLEAR = 1;
|
||||||
printf("Tick %02x\n", random);
|
|
||||||
now = get_time_us();
|
timer_irq_happened = 1;
|
||||||
uint32_t tick_at = now + 1000000;
|
|
||||||
while (now < tick_at){
|
// if (ll_state == LL_STATE_SCANNING){
|
||||||
now = get_time_us();
|
// // Restart scanning
|
||||||
}
|
// // TODO: use all channels
|
||||||
}
|
// radio_receive_on_channel(37);
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
// static
|
// TODO: implement
|
||||||
void ll_set_scan_params(uint8_t le_scan_type, uint16_t le_scan_interval, uint16_t le_scan_window, uint8_t own_address_type, uint8_t scanning_filter_policy){
|
void hal_cpu_disable_irqs(void){}
|
||||||
|
void hal_cpu_enable_irqs(void){}
|
||||||
|
void hal_cpu_enable_irqs_and_sleep(void){}
|
||||||
|
|
||||||
|
// TODO: get time from RTC
|
||||||
|
uint32_t hal_time_ms(void){
|
||||||
|
return 999;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ll_set_scan_parameters(uint8_t le_scan_type, uint16_t le_scan_interval, uint16_t le_scan_window, uint8_t own_address_type, uint8_t scanning_filter_policy){
|
||||||
// TODO .. store other params
|
// TODO .. store other params
|
||||||
ll_scan_interval_us = ((uint32_t) le_scan_interval) * 625;
|
ll_scan_interval_us = ((uint32_t) le_scan_interval) * 625;
|
||||||
ll_scan_window_us = ((uint32_t) le_scan_window) * 625;
|
ll_scan_window_us = ((uint32_t) le_scan_window) * 625;
|
||||||
|
log_info("LE Scan Params: window %lu, interval %lu ms", ll_scan_interval_us, ll_scan_window_us);
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint8_t ll_start_scanning(uint8_t filter_duplicates){
|
static uint8_t ll_start_scanning(uint8_t filter_duplicates){
|
||||||
@ -331,18 +348,32 @@ static uint8_t ll_start_scanning(uint8_t filter_duplicates){
|
|||||||
|
|
||||||
ll_state = LL_STATE_SCANNING;
|
ll_state = LL_STATE_SCANNING;
|
||||||
|
|
||||||
// reset timer
|
log_info("LE Scan Start: window %lu, interval %lu ms", ll_scan_interval_us, ll_scan_window_us);
|
||||||
NRF_TIMER0->TASKS_CLEAR;
|
|
||||||
|
|
||||||
// set timer to disable radio after end of scan_window
|
// reset timer and capature events
|
||||||
|
NRF_TIMER0->TASKS_CLEAR = 1;
|
||||||
|
NRF_TIMER0->TASKS_STOP = 1;
|
||||||
|
NRF_TIMER0->EVENTS_COMPARE[0] = 0;
|
||||||
|
NRF_TIMER0->EVENTS_COMPARE[1] = 0;
|
||||||
|
|
||||||
|
// limit scanning
|
||||||
|
if (ll_scan_window_us < ll_scan_interval_us){
|
||||||
|
// setup PPI to disable radio after end of scan_window
|
||||||
|
NRF_TIMER0->CC[1] = ll_scan_window_us;
|
||||||
|
NRF_PPI->CHENSET = 1 << 22; // TIMER0->EVENTS_COMPARE[1] -> RADIO->TASKS_DISABLE
|
||||||
|
}
|
||||||
|
|
||||||
// set timer to trigger IRQ for next scan interval
|
// set timer to trigger IRQ for next scan interval
|
||||||
|
NRF_TIMER0->CC[0] = ll_scan_interval_us;
|
||||||
|
NRF_TIMER0->INTENSET = TIMER_INTENSET_COMPARE0_Enabled << TIMER_INTENSET_COMPARE0_Pos;
|
||||||
|
|
||||||
// start receive
|
// next channel to scan
|
||||||
// ..
|
int adv_channel = (random_generator_next() % 3) + 37;
|
||||||
|
log_debug("LE Scan Channel: %u", adv_channel);
|
||||||
|
|
||||||
// TODO: use all channels
|
// start receiving
|
||||||
radio_receive_on_channel(37);
|
NRF_TIMER0->TASKS_START = 1;
|
||||||
|
radio_receive_on_channel(adv_channel);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -351,6 +382,8 @@ static uint8_t ll_stop_scanning(void){
|
|||||||
// COMMAND DISALLOWED if wrong state.
|
// COMMAND DISALLOWED if wrong state.
|
||||||
if (ll_state != LL_STATE_SCANNING) return 0x0c;
|
if (ll_state != LL_STATE_SCANNING) return 0x0c;
|
||||||
|
|
||||||
|
log_info("LE Scan Stop");
|
||||||
|
|
||||||
ll_state = LL_STATE_STANDBY;
|
ll_state = LL_STATE_STANDBY;
|
||||||
|
|
||||||
// stop radio
|
// stop radio
|
||||||
@ -359,8 +392,7 @@ static uint8_t ll_stop_scanning(void){
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// static
|
static uint8_t ll_set_scan_enable(uint8_t le_scan_enable, uint8_t filter_duplicates){
|
||||||
uint8_t ll_set_scan_enable(uint8_t le_scan_enable, uint8_t filter_duplicates){
|
|
||||||
if (le_scan_enable){
|
if (le_scan_enable){
|
||||||
return ll_start_scanning(filter_duplicates);
|
return ll_start_scanning(filter_duplicates);
|
||||||
} else {
|
} else {
|
||||||
@ -368,15 +400,79 @@ uint8_t ll_set_scan_enable(uint8_t le_scan_enable, uint8_t filter_duplicates){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void fake_command_complete(uint16_t opcode){
|
||||||
|
hci_outgoing_event[0] = HCI_EVENT_COMMAND_COMPLETE;
|
||||||
|
hci_outgoing_event[1] = 4;
|
||||||
|
hci_outgoing_event[2] = 1;
|
||||||
|
little_endian_store_16(hci_outgoing_event, 3, opcode);
|
||||||
|
hci_outgoing_event[5] = 0;
|
||||||
|
hci_outgoing_event_ready = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void send_hardware_error(uint8_t error_code){
|
||||||
|
hci_outgoing_event[0] = HCI_EVENT_HARDWARE_ERROR;
|
||||||
|
hci_outgoing_event[1] = 1;
|
||||||
|
hci_outgoing_event[2] = error_code;
|
||||||
|
hci_outgoing_event_ready = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// command handler
|
||||||
|
static void controller_handle_hci_command(uint8_t * packet, uint16_t size){
|
||||||
|
uint16_t opcode = little_endian_read_16(packet, 0);
|
||||||
|
#if 0
|
||||||
|
uint16_t ocf = READ_CMD_OCF(packet);
|
||||||
|
switch (READ_CMD_OGF(packet)){
|
||||||
|
case OGF_CONTROLLER_BASEBAND:
|
||||||
|
switch (ocf):
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
if (opcode == hci_reset.opcode) {
|
||||||
|
fake_command_complete(opcode);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (opcode == hci_le_set_scan_enable.opcode){
|
||||||
|
ll_set_scan_enable(packet[3], packet[4]);
|
||||||
|
fake_command_complete(opcode);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (opcode == hci_le_set_scan_parameters.opcode){
|
||||||
|
ll_set_scan_parameters(packet[3], little_endian_read_16(packet, 4), little_endian_read_16(packet, 6), packet[8], packet[9]);
|
||||||
|
fake_command_complete(opcode);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// try with "OK"
|
||||||
|
printf("CMD opcode %02x not handled yet\n", opcode);
|
||||||
|
fake_command_complete(opcode);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ACL handler
|
||||||
|
static void controller_handle_acl_data(uint8_t * packet, uint16_t size){
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
|
||||||
static void transport_run(btstack_data_source_t *ds, btstack_data_source_callback_type_t callback_type){
|
static void transport_run(btstack_data_source_t *ds, btstack_data_source_callback_type_t callback_type){
|
||||||
// deliver hci packet on main thread
|
// deliver hci packet on main thread
|
||||||
if (hci_outgoing_event_ready){
|
if (hci_outgoing_event_ready){
|
||||||
hci_outgoing_event_ready = 0;
|
hci_outgoing_event_ready = 0;
|
||||||
packet_handler(HCI_EVENT_PACKET, hci_outgoing_event, hci_outgoing_event[1]+2);
|
packet_handler(HCI_EVENT_PACKET, hci_outgoing_event, hci_outgoing_event[1]+2);
|
||||||
hci_outgoing_event_free = 1;
|
hci_outgoing_event_free = 1;
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
return 0;
|
if (timer_irq_happened){
|
||||||
|
// printf("Timer irq occured\n");
|
||||||
|
// radio_dump_state();
|
||||||
|
timer_irq_happened = 0;
|
||||||
|
|
||||||
|
if (ll_state == LL_STATE_SCANNING){
|
||||||
|
// next channel to scan
|
||||||
|
int adv_channel = (random_generator_next() % 3) + 37;
|
||||||
|
log_debug("Restart scan on channel %u", adv_channel);
|
||||||
|
radio_receive_on_channel(adv_channel);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -412,48 +508,19 @@ static void transport_register_packet_handler(void (*handler)(uint8_t packet_typ
|
|||||||
packet_handler = handler;
|
packet_handler = handler;
|
||||||
}
|
}
|
||||||
|
|
||||||
// /**
|
|
||||||
// * support async transport layers, e.g. IRQ driven without buffers
|
|
||||||
// */
|
|
||||||
// int transport_can_send_packet_now(uint8_t packet_type){
|
|
||||||
// return 1;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// TODO: implement
|
|
||||||
void hal_cpu_disable_irqs(void){}
|
|
||||||
void hal_cpu_enable_irqs(void){}
|
|
||||||
void hal_cpu_enable_irqs_and_sleep(void){}
|
|
||||||
|
|
||||||
|
|
||||||
// TODO: get time from RTC
|
|
||||||
uint32_t hal_time_ms(void){
|
|
||||||
return 999;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void fake_command_complete(uint16_t opcode){
|
|
||||||
hci_outgoing_event[0] = HCI_EVENT_COMMAND_COMPLETE;
|
|
||||||
hci_outgoing_event[1] = 4;
|
|
||||||
hci_outgoing_event[2] = 1;
|
|
||||||
little_endian_store_16(hci_outgoing_event, 3, opcode);
|
|
||||||
hci_outgoing_event[5] = 0;
|
|
||||||
hci_outgoing_event_ready = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int transport_send_packet(uint8_t packet_type, uint8_t *packet, int size){
|
int transport_send_packet(uint8_t packet_type, uint8_t *packet, int size){
|
||||||
// process packet
|
|
||||||
uint16_t opcode = little_endian_read_16(packet, 0);
|
switch (packet_type){
|
||||||
if (opcode == hci_reset.opcode) {
|
case HCI_COMMAND_DATA_PACKET:
|
||||||
fake_command_complete(opcode);
|
controller_handle_hci_command(packet, size);
|
||||||
return 0;
|
break;
|
||||||
|
case HCI_ACL_DATA_PACKET:
|
||||||
|
controller_handle_acl_data(packet, size);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
send_hardware_error(0x01); // invalid HCI packet
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
if (opcode == hci_le_set_scan_enable.opcode){
|
|
||||||
ll_set_scan_enable(packet[3], packet[4]);
|
|
||||||
fake_command_complete(opcode);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
// try with "OK"
|
|
||||||
printf("CMD opcode %02x not handled yet\n", opcode);
|
|
||||||
fake_command_complete(opcode);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -496,8 +563,16 @@ int main(void)
|
|||||||
NVIC_ClearPendingIRQ( RADIO_IRQn );
|
NVIC_ClearPendingIRQ( RADIO_IRQn );
|
||||||
NVIC_EnableIRQ( RADIO_IRQn );
|
NVIC_EnableIRQ( RADIO_IRQn );
|
||||||
|
|
||||||
// Bring up BTstack
|
// enable Timer IRQs
|
||||||
|
NVIC_SetPriority( TIMER0_IRQn, 0 );
|
||||||
|
NVIC_ClearPendingIRQ( TIMER0_IRQn );
|
||||||
|
NVIC_EnableIRQ( TIMER0_IRQn );
|
||||||
|
|
||||||
|
// HCI Controller Defaults
|
||||||
|
ll_scan_window_us = 10000;
|
||||||
|
ll_scan_interval_us = 10000;
|
||||||
|
|
||||||
|
// Bring up BTstack
|
||||||
printf("BTstack on Nordic nRF5 SDK\n");
|
printf("BTstack on Nordic nRF5 SDK\n");
|
||||||
|
|
||||||
btstack_memory_init();
|
btstack_memory_init();
|
||||||
|
@ -1027,20 +1027,10 @@ static int rfcomm_hci_event_handler(uint8_t *packet, uint16_t size){
|
|||||||
log_info("L2CAP_EVENT_CHANNEL_CLOSED cid 0x%0x, mult %p", l2cap_cid, multiplexer);
|
log_info("L2CAP_EVENT_CHANNEL_CLOSED cid 0x%0x, mult %p", l2cap_cid, multiplexer);
|
||||||
if (!multiplexer) break;
|
if (!multiplexer) break;
|
||||||
log_info("L2CAP_EVENT_CHANNEL_CLOSED state %u", multiplexer->state);
|
log_info("L2CAP_EVENT_CHANNEL_CLOSED state %u", multiplexer->state);
|
||||||
switch (multiplexer->state) {
|
// no need to call l2cap_disconnect here, as it's already closed
|
||||||
case RFCOMM_MULTIPLEXER_W4_CONNECT:
|
rfcomm_multiplexer_finalize(multiplexer);
|
||||||
case RFCOMM_MULTIPLEXER_SEND_SABM_0:
|
return 1;
|
||||||
case RFCOMM_MULTIPLEXER_W4_SABM_0:
|
|
||||||
case RFCOMM_MULTIPLEXER_SEND_UA_0:
|
|
||||||
case RFCOMM_MULTIPLEXER_W4_UA_0:
|
|
||||||
case RFCOMM_MULTIPLEXER_OPEN:
|
|
||||||
// don't call l2cap_disconnect as it's alreay closed
|
|
||||||
rfcomm_multiplexer_finalize(multiplexer);
|
|
||||||
return 1;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user