From ca1bb42005399e68e285f4b03e586f13ff9cf217 Mon Sep 17 00:00:00 2001 From: Matthias Ringwald Date: Sun, 19 Apr 2015 22:52:31 +0200 Subject: [PATCH] added Arduino port that provides LE Central/GATT Client API with EM9301 single mode LE chipset --- platforms/arduino/.gitignore | 1 + platforms/arduino/BTstack.cpp | 625 ++++++++++++++++++ platforms/arduino/BTstack.h | 169 +++++ platforms/arduino/bsp_arduino_em9301.cpp | 251 +++++++ platforms/arduino/btstack-config.h | 29 + platforms/arduino/clone.sh | 61 ++ .../BLECentralPseudo/BLECentralPseudo.ino | 184 ++++++ platforms/arduino/examples/Test/Test.ino | 192 ++++++ .../btstack_ancs_client.ino | 91 +++ .../btstack_gatt_client.ino | 129 ++++ .../btstack_gatt_server.ino | 72 ++ 11 files changed, 1804 insertions(+) create mode 100644 platforms/arduino/.gitignore create mode 100644 platforms/arduino/BTstack.cpp create mode 100644 platforms/arduino/BTstack.h create mode 100644 platforms/arduino/bsp_arduino_em9301.cpp create mode 100644 platforms/arduino/btstack-config.h create mode 100755 platforms/arduino/clone.sh create mode 100644 platforms/arduino/examples/BLECentralPseudo/BLECentralPseudo.ino create mode 100644 platforms/arduino/examples/Test/Test.ino create mode 100644 platforms/arduino/examples/btstack_ancs_client/btstack_ancs_client.ino create mode 100644 platforms/arduino/examples/btstack_gatt_client/btstack_gatt_client.ino create mode 100644 platforms/arduino/examples/btstack_gatt_server/btstack_gatt_server.ino diff --git a/platforms/arduino/.gitignore b/platforms/arduino/.gitignore new file mode 100644 index 000000000..0f79225e1 --- /dev/null +++ b/platforms/arduino/.gitignore @@ -0,0 +1 @@ +btstack diff --git a/platforms/arduino/BTstack.cpp b/platforms/arduino/BTstack.cpp new file mode 100644 index 000000000..a46d66f5a --- /dev/null +++ b/platforms/arduino/BTstack.cpp @@ -0,0 +1,625 @@ +/** + * Arduino Wrapper for BTstack + */ + +#include +#include + +#include "BTstack.h" + +#include "btstack_memory.h" +#include "btstack/hal_tick.h" +#include "btstack/hal_cpu.h" +#include "btstack/hci_cmds.h" +#include +#include +#include + +#include "bt_control_em9301.h" +#include "hci.h" +#include "hci_dump.h" +#include "l2cap.h" +#include "ad_parser.h" +#include "att.h" +#include "att_server.h" +#include "le_device_db.h" +#include "sm.h" +#include "debug.h" + +// Pin 13 has an LED connected on most Arduino boards. +#define PIN_LED 13 + +// prototypes +extern "C" void embedded_execute_once(void); +extern "C" void hal_uart_dma_process(void); + +// HAL TICK Implementation +extern "C" void hal_tick_init(void){ + +} +extern "C" void hal_tick_set_handler(void (*tick_handler)(void)){ + +} +extern "C" int hal_tick_get_tick_period_in_ms(void){ + return 250; +} + +// btstack state +static int btstack_state; + +// HAL CPU Implementation +extern "C" void hal_cpu_disable_irqs(void){ } +extern "C" void hal_cpu_enable_irqs(void) { } +extern "C" void hal_cpu_enable_irqs_and_sleep(void) { } + +static const uint8_t adv_data_default[] = { 02, 01, 05, 03, 02, 0xf0, 0xff }; +static const uint8_t * adv_data = adv_data_default; +static uint16_t adv_data_len = sizeof(adv_data_default); +static uint16_t gatt_client_id; +static int gatt_is_characteristics_query; + +typedef enum gattAction { + gattActionWrite, + gattActionSubscribe, + gattActionUnsubscribe, + gattActionServiceQuery, + gattActionCharacteristicQuery, + gattActionRead, +} gattAction_t; + +static gattAction_t gattAction; + +// static btstack_packet_handler_t client_packet_handler = NULL; +static int client_mode = 0; +static bool have_custom_addr; +static bd_addr_t public_bd_addr; + +static timer_source_t connection_timer; + +static void (*bleAdvertismentCallback)(BLEAdvertisement * bleAdvertisement) = NULL; +static void (*bleDeviceConnectedCallback)(BLEStatus status, BLEDevice * device)= NULL; +static void (*bleDeviceDisconnectedCallback)(BLEDevice * device) = NULL; +static void (*gattServiceDiscoveredCallback)(BLEStatus status, BLEDevice * device, BLEService * bleService) = NULL; +static void (*gattCharacteristicDiscoveredCallback)(BLEStatus status, BLEDevice * device, BLECharacteristic * characteristic) = NULL; +static void (*gattCharacteristicNotificationCallback)(BLEDevice * device, uint16_t value_handle, uint8_t* value, uint16_t length) = NULL; +static void (*gattCharacteristicReadCallback)(BLEStatus status, BLEDevice * device, uint8_t * value, uint16_t length) = NULL; +static void (*gattCharacteristicWrittenCallback)(BLEStatus status, BLEDevice * device) = NULL; +static void (*gattCharacteristicSubscribedCallback)(BLEStatus status, BLEDevice * device) = NULL; +static void (*gattCharacteristicUnsubscribedCallback)(BLEStatus status, BLEDevice * device) = NULL; + +static void packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ + + bd_addr_t addr; + uint16_t handle; + + switch (packet_type) { + + case HCI_EVENT_PACKET: + switch (packet[0]) { + + case BTSTACK_EVENT_STATE: + btstack_state = packet[2]; + // bt stack activated, get started + // if (packet[2] == HCI_STATE_WORKING) { + // if (client_mode) { + // emit_stack_ready(); + // return; + // } + // // printf("1 - hci_le_set_advertising_parameters\n"); + // hci_send_cmd(&hci_le_set_advertising_parameters, 0x0400, 0x0800, 0, 0, 0, &addr, 0x07, 0); + // } + break; + + case HCI_EVENT_DISCONNECTION_COMPLETE: + if (bleDeviceDisconnectedCallback) { + handle = READ_BT_16(packet, 3); + BLEDevice device(handle); + (*bleDeviceDisconnectedCallback)(&device); + } + break; + + case GAP_LE_ADVERTISING_REPORT: { + if (bleAdvertismentCallback) { + BLEAdvertisement advertisement(packet); + (*bleAdvertismentCallback)(&advertisement); + } + break; + } + + case HCI_EVENT_COMMAND_COMPLETE: + if (COMMAND_COMPLETE_EVENT(packet, hci_read_bd_addr)) { + bt_flip_addr(addr, &packet[OFFSET_OF_DATA_IN_COMMAND_COMPLETE + 1]); + printf("Local Address: %s\n", bd_addr_to_str(addr)); + break; + } + // if (COMMAND_COMPLETE_EVENT(packet, hci_le_set_advertising_parameters)){ + // printf("2 - hci_le_set_advertising_data\n"); + // hci_send_cmd(&hci_le_set_advertising_data, adv_data_len, adv_data); + // break; + // } + // if (COMMAND_COMPLETE_EVENT(packet, hci_le_set_advertising_data)){ + // printf("3 - hci_le_set_advertise_enable\n"); + // hci_send_cmd(&hci_le_set_advertise_enable, 1); + // break; + // } + // if (COMMAND_COMPLETE_EVENT(packet, hci_le_set_advertise_enable)){ + // emit_stack_ready(); + // break; + // } + break; + + case HCI_EVENT_LE_META: + switch (packet[2]) { + case HCI_SUBEVENT_LE_CONNECTION_COMPLETE: + handle = READ_BT_16(packet, 4); + printf("Connection complete, handle 0x%04x\n", handle); + run_loop_remove_timer(&connection_timer); + if (!bleDeviceConnectedCallback) break; + if (packet[3]){ + (*bleDeviceConnectedCallback)(BLE_STATUS_CONNECTION_ERROR, NULL); + } else { + BLEDevice device(handle); + (*bleDeviceConnectedCallback)(BLE_STATUS_OK, &device); + } + break; + default: + break; + } + break; + } + } + // if (client_packet_handler){ + // (*client_packet_handler)(packet_type, channel, packet, size); + // } +} + +static void gatt_client_callback(le_event_t * event){ + // le_characteristic_t characteristic; + // le_characteristic_value_event_t * value_event; + gatt_complete_event_t * gatt_complete_event; + + BLEDevice device(event->handle); + switch(event->type){ + case GATT_SERVICE_QUERY_RESULT: + if (gattServiceDiscoveredCallback) { + BLEService bleService(((le_service_event_t *) event)->service); + (*gattServiceDiscoveredCallback)(BLE_STATUS_OK, &device, &bleService); + } + break; + case GATT_CHARACTERISTIC_QUERY_RESULT: + if (gattCharacteristicDiscoveredCallback){ + BLECharacteristic bleCharacteristic(((le_characteristic_event_t *) event)->characteristic); + (*gattCharacteristicDiscoveredCallback)(BLE_STATUS_OK, &device, &bleCharacteristic); + } + break; + case GATT_QUERY_COMPLETE: + gatt_complete_event = (gatt_complete_event_t*) event; + switch (gattAction){ + case gattActionWrite: + if (gattCharacteristicWrittenCallback) gattCharacteristicWrittenCallback(gatt_complete_event->status ? BLE_STATUS_OTHER_ERROR : BLE_STATUS_OK, &device); + break; + case gattActionSubscribe: + if (gattCharacteristicSubscribedCallback) gattCharacteristicSubscribedCallback(gatt_complete_event->status ? BLE_STATUS_OTHER_ERROR : BLE_STATUS_OK, &device); + break; + case gattActionUnsubscribe: + if (gattCharacteristicUnsubscribedCallback) gattCharacteristicUnsubscribedCallback(gatt_complete_event->status ? BLE_STATUS_OTHER_ERROR : BLE_STATUS_OK, &device); + break; + case gattActionServiceQuery: + if (gattServiceDiscoveredCallback) gattServiceDiscoveredCallback(BLE_STATUS_DONE, &device, NULL); + break; + case gattActionCharacteristicQuery: + if (gattCharacteristicDiscoveredCallback) gattCharacteristicDiscoveredCallback(BLE_STATUS_DONE, &device, NULL); + break; + default: + break; + }; + break; + case GATT_NOTIFICATION: + case GATT_INDICATION: + if (gattCharacteristicNotificationCallback) { + le_characteristic_value_event_t * value_event = (le_characteristic_value_event_t *) event; + (*gattCharacteristicNotificationCallback)(&device, value_event->value_handle, value_event->blob, value_event->blob_length); + } + break; + case GATT_CHARACTERISTIC_VALUE_QUERY_RESULT: + if (gattCharacteristicReadCallback) { + le_characteristic_value_event_t * value_event = (le_characteristic_value_event_t *) event; + (*gattCharacteristicReadCallback)(BLE_STATUS_OK, &device, value_event->blob, value_event->blob_length); + } + break; + default: + break; + } +} + +static void connection_timeout_handler(timer_source_t * timer){ + // log_info("Cancel outgoing connection"); + le_central_connect_cancel(); + if (!bleDeviceConnectedCallback) return; + (*bleDeviceConnectedCallback)(BLE_STATUS_CONNECTION_TIMEOUT, NULL); // page timeout 0x04 +} + +// + +static int nibble_for_char(const char c){ + if ('0' <= c && c <= '9') return c - '0'; + if ('a' <= c && c <= 'f') return c - 'a' + 10; + if ('A' <= c && c <= 'F') return c - 'A' + 10; + return 0; +} + +/// UUID class +UUID::UUID(){ + memset(uuid, 0, 16); +} + +UUID::UUID(const uint8_t uuid[16]){ + memcpy(this->uuid, uuid, 16); +} + +UUID::UUID(const char * uuidStr){ + memset(uuid, 0, 16); + int len = strlen(uuidStr); + if (len <= 4){ + // Handle 4 Bytes HEX + uint16_t uuid16; + int result = sscanf( (char *) uuidStr, "%x", &uuid16); + if (result == 1){ + sdp_normalize_uuid(uuid, uuid16); + } + return; + } + + // quick UUID parser, ignoring dashes + int i = 0; + int data = 0; + int have_nibble = 0; + while(*uuidStr && i < 16){ + const char c = *uuidStr++; + if (c == '-') continue; + data = data << 4 | nibble_for_char(c); + if (!have_nibble) { + have_nibble = 1; + continue; + } + uuid[i++] = data; + data = 0; + have_nibble = 0; + } +} + +const uint8_t * UUID::getUuid(void) const { + return uuid; +} + +static char uuid16_buffer[5]; +const char * UUID::getUuidString() const { + // TODO: fix sdp_has_blueooth_base_uuid call to use const + if (sdp_has_blueooth_base_uuid((uint8_t*)uuid)){ + sprintf(uuid16_buffer, "%04x", (uint16_t) READ_NET_32(uuid, 0)); + return uuid16_buffer; + } else { + // TODO: fix uuid128_to_str + return uuid128_to_str((uint8_t*)uuid); + } +} + +const char * UUID::getUuid128String() const { + return uuid128_to_str((uint8_t*)uuid); +} + +bool UUID::matches(UUID *other) const { + return memcmp(this->uuid, other->uuid, 16) == 0; +} + + +// BD_ADDR class +BD_ADDR::BD_ADDR(){ +} + +BD_ADDR::BD_ADDR(const char * address_string, BD_ADDR_TYPE address_type ) : address_type(address_type) { + // TODO: implement + // log_error("BD_ADDR::BD_ADDR(const char *, BD_ADDR_TYPE) not implemented yet!"); +} + +BD_ADDR::BD_ADDR(const uint8_t address[6], BD_ADDR_TYPE address_type) : address_type(address_type){ + memcpy(this->address, address, 6); +} + +const uint8_t * BD_ADDR::getAddress(){ + return address; +} + +const char * BD_ADDR::getAddressString(){ + return bd_addr_to_str(address); +} + +BD_ADDR_TYPE BD_ADDR::getAddressType(){ + return address_type; +} + + +BLEAdvertisement::BLEAdvertisement(uint8_t * event_packet) : +advertising_event_type(event_packet[2]), +rssi(event_packet[10]), +data_length(event_packet[11]) +{ + bd_addr_t addr; + bt_flip_addr(addr, &event_packet[4]); + bd_addr = BD_ADDR(addr, (BD_ADDR_TYPE)event_packet[3]); + memcpy(data, &event_packet[12], LE_ADVERTISING_DATA_SIZE); +} + +const uint8_t * BLEAdvertisement::getAdvData(){ + return data; +} + +BD_ADDR * BLEAdvertisement::getBdAddr(void){ + return &bd_addr; +} + +int BLEAdvertisement::getRssi(){ + return rssi > 127 ? rssi - 256 : rssi; +} + + +bool BLEAdvertisement::containsService(UUID * service){ + return ad_data_contains_uuid128(data_length, data, (uint8_t*) service->getUuid()); +} + +bool BLEAdvertisement::nameHasPrefix(const char * namePrefix){ + return false; +}; + +BLECharacteristic::BLECharacteristic() { +} + +BLECharacteristic::BLECharacteristic(le_characteristic_t characteristic) +: characteristic(characteristic), uuid(characteristic.uuid128) { +} + +const UUID * BLECharacteristic::getUUID(){ + return &uuid; +} + +bool BLECharacteristic::matches(UUID * uuid){ + return this->uuid.matches(uuid); +} + +bool BLECharacteristic::isValueHandle(uint16_t value_handle){ + return characteristic.value_handle == value_handle; +} + +const le_characteristic_t * BLECharacteristic::getCharacteristic() { + return &characteristic; +} + + +BLEService::BLEService(){ +} + +BLEService::BLEService(le_service_t service) +: service(service), uuid(service.uuid128){ +} + +const UUID * BLEService::getUUID(){ + return &uuid; +} + +bool BLEService::matches(UUID * uuid){ + return this->uuid.matches(uuid); +} + +const le_service_t * BLEService::getService(){ + return &service; +} + +// discovery of services and characteristics +BLEDevice::BLEDevice(){ +} +BLEDevice::BLEDevice(uint16_t handle) +: handle(handle){ +} +uint16_t BLEDevice::getHandle(){ + return handle; +} +int BLEDevice::discoverGATTServices(){ + return BTstack.discoverGATTServices(this); +} +int BLEDevice::discoverCharacteristicsForService(BLEService * service){ + return BTstack.discoverCharacteristicsForService(this, service); +} +int BLEDevice::readCharacteristic(BLECharacteristic * characteristic){ + return BTstack.readCharacteristic(this, characteristic); +} +int BLEDevice::writeCharacteristic(BLECharacteristic * characteristic, uint8_t * data, uint16_t size){ + return BTstack.writeCharacteristic(this, characteristic, data, size); +} +int BLEDevice::writeCharacteristicWithoutResponse(BLECharacteristic * characteristic, uint8_t * data, uint16_t size){ + return BTstack.writeCharacteristicWithoutResponse(this, characteristic, data, size); +} +int BLEDevice::subscribeForNotifications(BLECharacteristic * characteristic){ + return BTstack.subscribeForNotifications(this, characteristic); +} +int BLEDevice::unsubscribeFromNotifications(BLECharacteristic * characteristic){ + return BTstack.unsubscribeFromNotifications(this, characteristic); +} + + +BTstackManager::BTstackManager() { + // client_packet_handler = NULL; + have_custom_addr = false; + // reset handler + bleAdvertismentCallback = NULL; + bleDeviceConnectedCallback = NULL; + bleDeviceDisconnectedCallback = NULL; + gattServiceDiscoveredCallback = NULL; + gattCharacteristicDiscoveredCallback = NULL; + gattCharacteristicNotificationCallback = NULL; +} + +void BTstackManager::setBLEAdvertisementCallback(void (*callback)(BLEAdvertisement * bleAdvertisement)){ + bleAdvertismentCallback = callback; +} +void BTstackManager::setBLEDeviceConnectedCallback(void (*callback)(BLEStatus status, BLEDevice * device)){ + bleDeviceConnectedCallback = callback; +} +void BTstackManager::setBLEDeviceDisconnectedCallback(void (*callback)(BLEDevice * device)){ + bleDeviceDisconnectedCallback = callback; +} +void BTstackManager::setGATTServiceDiscoveredCallback(void (*callback)(BLEStatus status, BLEDevice * device, BLEService * bleService)){ + gattServiceDiscoveredCallback = callback; +} +void BTstackManager::setGATTCharacteristicDiscoveredCallback(void (*callback)(BLEStatus status, BLEDevice * device, BLECharacteristic * characteristic)){ + gattCharacteristicDiscoveredCallback = callback; +} +void BTstackManager::setGATTCharacteristicNotificationCallback(void (*callback)(BLEDevice * device, uint16_t value_handle, uint8_t* value, uint16_t length)){ + gattCharacteristicNotificationCallback = callback; +} +void BTstackManager::setGATTCharacteristicReadCallback(void (*callback)(BLEStatus status, BLEDevice * device, uint8_t * value, uint16_t length)){ + gattCharacteristicReadCallback = callback; +} +void BTstackManager::setGATTCharacteristicWrittenCallback(void (*callback)(BLEStatus status, BLEDevice * device)){ + gattCharacteristicWrittenCallback = callback; +} +void BTstackManager::setGATTCharacteristicSubscribedCallback(void (*callback)(BLEStatus status, BLEDevice * device)){ + gattCharacteristicSubscribedCallback = callback; +} +void BTstackManager::setGATTCharacteristicUnsubscribedCallback(void (*callback)(BLEStatus status, BLEDevice * device)){ + gattCharacteristicUnsubscribedCallback = callback; +} + +int BTstackManager::discoverGATTServices(BLEDevice * device){ + gattAction = gattActionServiceQuery; + return gatt_client_discover_primary_services(gatt_client_id, device->getHandle()); +} +int BTstackManager::discoverCharacteristicsForService(BLEDevice * device, BLEService * service){ + gattAction = gattActionCharacteristicQuery; + return gatt_client_discover_characteristics_for_service(gatt_client_id, device->getHandle(), (le_service_t*) service->getService()); +} +int BTstackManager::readCharacteristic(BLEDevice * device, BLECharacteristic * characteristic){ + return gatt_client_read_value_of_characteristic(gatt_client_id, device->getHandle(), (le_characteristic_t*) characteristic->getCharacteristic()); +} +int BTstackManager::writeCharacteristic(BLEDevice * device, BLECharacteristic * characteristic, uint8_t * data, uint16_t size){ + gattAction = gattActionWrite; + return gatt_client_write_value_of_characteristic(gatt_client_id, device->getHandle(), characteristic->getCharacteristic()->value_handle, + size, data); +} +int BTstackManager::writeCharacteristicWithoutResponse(BLEDevice * device, BLECharacteristic * characteristic, uint8_t * data, uint16_t size){ + return gatt_client_write_value_of_characteristic_without_response(gatt_client_id, device->getHandle(), characteristic->getCharacteristic()->value_handle, + size, data); +} +int BTstackManager::subscribeForNotifications(BLEDevice * device, BLECharacteristic * characteristic){ + gattAction = gattActionSubscribe; + return gatt_client_write_client_characteristic_configuration(gatt_client_id, device->getHandle(), (le_characteristic_t*) characteristic->getCharacteristic(), + GATT_CLIENT_CHARACTERISTICS_CONFIGURATION_NOTIFICATION); +} +int BTstackManager::unsubscribeFromNotifications(BLEDevice * device, BLECharacteristic * characteristic){ + gattAction = gattActionUnsubscribe; + return gatt_client_write_client_characteristic_configuration(gatt_client_id, device->getHandle(), (le_characteristic_t*) characteristic->getCharacteristic(), + GATT_CLIENT_CHARACTERISTICS_CONFIGURATION_NONE); +} +void BTstackManager::bleConnect(BLEAdvertisement * advertisement, int timeout_ms){ + bleConnect(advertisement->getBdAddr(), timeout_ms); +} +void BTstackManager::bleConnect(BD_ADDR * address, int timeout_ms){ + bleConnect(address->getAddressType(), address->getAddress(), timeout_ms); +} +void BTstackManager::bleConnect(BD_ADDR_TYPE address_type, const char * address, int timeout_ms){ + // TOOD: implement + // log_error("BTstackManager::bleConnect(BD_ADDR_TYPE address_type, const char * address, int timeout_ms) not implemented"); +} +void BTstackManager::bleConnect(BD_ADDR_TYPE address_type, const uint8_t address[6], int timeout_ms){ + le_central_connect((uint8_t*)address, (bd_addr_type_t) address_type); + if (!timeout_ms) return; + run_loop_set_timer(&connection_timer, timeout_ms); + run_loop_set_timer_handler(&connection_timer, connection_timeout_handler); + run_loop_add_timer(&connection_timer); +} + +void BTstackManager::bleDisconnect(BLEDevice * device){ + run_loop_remove_timer(&connection_timer); +} + +void BTstackManager::registerPacketHandler(btstack_packet_handler_t packet_handler){ + // client_packet_handler = packet_handler; +} + +void BTstackManager::setClientMode(){ + client_mode = 1; +} + +void BTstackManager::setAdvData(uint16_t size, const uint8_t * data){ + adv_data = data; + adv_data_len = size; +} + +void BTstackManager::setPublicBdAddr(bd_addr_t addr){ + have_custom_addr = true; + memcpy(public_bd_addr, addr ,6); +} + +// static hci_uart_config_t config; + +void BTstackManager::setup(){ + +#ifdef PIN_LED + pinMode(PIN_LED, OUTPUT); +#endif + + printf("BTstackManager::setup()\n"); + + btstack_memory_init(); + run_loop_init(RUN_LOOP_EMBEDDED); + + hci_dump_open(NULL, HCI_DUMP_STDOUT); + + hci_transport_t * transport = hci_transport_h4_dma_instance(); + bt_control_t * control = bt_control_em9301_instance(); + hci_init(transport, NULL, control, NULL); + + if (have_custom_addr){ + hci_set_bd_addr(public_bd_addr); + } + + l2cap_init(); + + // setup central device db + le_device_db_init(); + + sm_init(); + + att_server_init(NULL, NULL, NULL); + att_server_register_packet_handler(packet_handler); + + gatt_client_init(); + gatt_client_id = gatt_client_register_packet_handler(gatt_client_callback); + + // turn on! + btstack_state = 0; + hci_power_control(HCI_POWER_ON); + + // poll until working + while (btstack_state != HCI_STATE_WORKING){ + loop(); + } + printf("--> READY <--\n"); +} + +void BTstackManager::loop(){ + // process data from/to Bluetooth module + hal_uart_dma_process(); + // BTstack Run Loop + embedded_execute_once(); +} + +void BTstackManager::bleStartScanning(){ + printf("Start scanning\n"); + le_central_start_scan(); +} +void BTstackManager::bleStopScanning(){ + le_central_stop_scan(); +} + +BTstackManager BTstack; + diff --git a/platforms/arduino/BTstack.h b/platforms/arduino/BTstack.h new file mode 100644 index 000000000..661f7ad98 --- /dev/null +++ b/platforms/arduino/BTstack.h @@ -0,0 +1,169 @@ +/** + * Arduino Wrapper for BTstack + */ +#pragma once + +#include "att.h" +#include +#include "gatt_client.h" +#include "hci.h" +#include + +typedef enum BLEStatus { + BLE_STATUS_OK, + BLE_STATUS_DONE, // e.g. for service or characteristic discovery done + BLE_STATUS_CONNECTION_TIMEOUT, + BLE_STATUS_CONNECTION_ERROR, + BLE_STATUS_OTHER_ERROR +} BLEStatus; + +typedef void (*btstack_packet_handler_t) (uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size); + +class UUID { +private: + uint8_t uuid[16]; +public: + UUID(); + UUID(const uint8_t uuid[16]); + UUID(const char * uuidStr); + const char * getUuidString() const; + const char * getUuid128String() const; + const uint8_t * getUuid(void) const; + bool matches(UUID *uuid) const; +}; + +typedef enum BD_ADDR_TYPE { + PUBLIC_ADDRESS = 0, + PRIVAT_ADDRESS +} BD_ADDR_TYPE; + +class BD_ADDR { +private: + uint8_t address[6]; + BD_ADDR_TYPE address_type; +public: + BD_ADDR(); + BD_ADDR(const char * address_string, BD_ADDR_TYPE address_type = PUBLIC_ADDRESS); + BD_ADDR(const uint8_t address[6], BD_ADDR_TYPE address_type = PUBLIC_ADDRESS); + const uint8_t * getAddress(); + const char * getAddressString(); + BD_ADDR_TYPE getAddressType(); +}; + +class BLEAdvertisement { +private: + uint8_t advertising_event_type; + uint8_t rssi; + uint8_t data_length; + uint8_t data[10 + LE_ADVERTISING_DATA_SIZE]; + BD_ADDR bd_addr; +public: + BLEAdvertisement(uint8_t * event_packet); + BD_ADDR * getBdAddr(); + BD_ADDR_TYPE getBdAddrType(); + int getRssi(); + bool containsService(UUID * service); + bool nameHasPrefix(const char * namePrefix); + const uint8_t * getAdvData(); +}; + +class BLECharacteristic { +private: + le_characteristic_t characteristic; + UUID uuid; +public: + BLECharacteristic(); + BLECharacteristic(le_characteristic_t characteristic); + const UUID * getUUID(); + bool matches(UUID * uuid); + bool isValueHandle(uint16_t value_handle); + const le_characteristic_t * getCharacteristic(); +}; + +class BLEService { +private: + le_service_t service; + UUID uuid; +public: + BLEService(); + BLEService(le_service_t service); + const UUID * getUUID(); + bool matches(UUID * uuid); + const le_service_t * getService(); +}; + +class BLEDevice { +private: + uint16_t handle; +public: + BLEDevice(); + BLEDevice(uint16_t handle); + uint16_t getHandle(); + + // discovery of services and characteristics + int discoverGATTServices(); + int discoverCharacteristicsForService(BLEService * service); + + // read/write + int readCharacteristic(BLECharacteristic * characteristic); + int writeCharacteristic(BLECharacteristic * characteristic, uint8_t * data, uint16_t size); + int writeCharacteristicWithoutResponse(BLECharacteristic * characteristic, uint8_t * data, uint16_t size); + + // subscribe/unsubscribe + int subscribeForNotifications(BLECharacteristic * characteristic); + int unsubscribeFromNotifications(BLECharacteristic * characteristic); +}; + +class BTstackManager { +public: + BTstackManager(void); + void setup(void); + void loop(void); + +// @deprecated + void registerPacketHandler(btstack_packet_handler_t packet_handler); +// @deprecated + void setClientMode(); + + void setAdvData(uint16_t size, const uint8_t * data); + void setPublicBdAddr(bd_addr_t addr); + + void bleStartScanning(); + void bleStopScanning(); + + // connection management + void bleConnect(BD_ADDR_TYPE address_type, const uint8_t address[6], int timeout_ms); + void bleConnect(BD_ADDR_TYPE address_type, const char * address, int timeout_ms); + void bleConnect(BD_ADDR * address, int timeout_ms); + void bleConnect(BLEAdvertisement * advertisement, int timeout_ms); + void bleDisconnect(BLEDevice * device); + + // discovery of services and characteristics + int discoverGATTServices(BLEDevice * device); + int discoverCharacteristicsForService(BLEDevice * peripheral, BLEService * service); + + // read/write + int readCharacteristic(BLEDevice * device, BLECharacteristic * characteristic); + int writeCharacteristic(BLEDevice * device, BLECharacteristic * characteristic, uint8_t * data, uint16_t size); + int writeCharacteristicWithoutResponse(BLEDevice * device, BLECharacteristic * characteristic, uint8_t * data, uint16_t size); + + // subscribe/unsubscribe + int subscribeForNotifications(BLEDevice * device, BLECharacteristic * characteristic); + int unsubscribeFromNotifications(BLEDevice * device, BLECharacteristic * characteristic); + + // Callbacks + void setBLEAdvertisementCallback(void (*)(BLEAdvertisement * bleAdvertisement)); + void setBLEDeviceConnectedCallback(void (*)(BLEStatus status, BLEDevice * device)); + void setBLEDeviceDisconnectedCallback(void (*)(BLEDevice * device)); + void setGATTServiceDiscoveredCallback(void (*)(BLEStatus status, BLEDevice * device, BLEService * bleService)); + void setGATTCharacteristicDiscoveredCallback(void (*)(BLEStatus status, BLEDevice * device, BLECharacteristic * characteristic)); + void setGATTCharacteristicReadCallback(void (*)(BLEStatus status, BLEDevice * device, uint8_t * value, uint16_t length)); + void setGATTCharacteristicNotificationCallback(void (*)(BLEDevice * device, uint16_t value_handle, uint8_t* value, uint16_t length)); + void setGATTDoneCallback(void (*)(BLEStatus status, BLEDevice * device)); + + void setGATTCharacteristicWrittenCallback(void (*)(BLEStatus status, BLEDevice * device)); + void setGATTCharacteristicSubscribedCallback(void (*)(BLEStatus status, BLEDevice * device)); + void setGATTCharacteristicUnsubscribedCallback(void (*)(BLEStatus status, BLEDevice * device)); +}; + + extern BTstackManager BTstack; \ No newline at end of file diff --git a/platforms/arduino/bsp_arduino_em9301.cpp b/platforms/arduino/bsp_arduino_em9301.cpp new file mode 100644 index 000000000..4a4ee31e0 --- /dev/null +++ b/platforms/arduino/bsp_arduino_em9301.cpp @@ -0,0 +1,251 @@ +/** + * Arduino + Energia Wrapper for BTstack + */ + +#if !defined(ARDUINO) +#error "Not compiling for Arduino/Energia" +#endif + +#include +#ifdef ENERGIA +#include +#endif +#include + +#include "btstack/hal_uart_dma.h" + +#define HAVE_SHUTDOWN + +#ifdef ENERGIA + +// CMM 9301 Configuration for TI Launchpad +#define PIN_SCK 7 +#define PIN_CS 8 +#define PIN_SHUTDOWN 11 +#define PIN_IRQ_DATA 13 +#define PIN_MISO 14 +#define PIN_MOSI 15 +#else // ARDUINO + +// CMM 9301 Configuration on Arduino +#define PIN_IRQ_DATA 2 +#define PIN_CS 4 +#define PIN_SHUTDOWN 5 +#define PIN_MISO 50 +#define PIN_MOSI 51 +#define PIN_SCK 52 +#endif + +// rx state +static uint16_t bytes_to_read = 0; +static uint8_t * rx_buffer_ptr = 0; + +// tx state +static uint16_t bytes_to_write = 0; +static uint8_t * tx_buffer_ptr = 0; + +// handlers +static void dummy_handler(void){}; +static void (*rx_done_handler)(void) = dummy_handler; +static void (*tx_done_handler)(void) = dummy_handler; + +static void bt_setup(void){ + pinMode(PIN_CS, OUTPUT); + pinMode(PIN_MOSI, OUTPUT); + pinMode(PIN_SCK, OUTPUT); + pinMode(PIN_SHUTDOWN, OUTPUT); + pinMode(PIN_IRQ_DATA, INPUT); + + digitalWrite(PIN_CS, HIGH); + digitalWrite(PIN_MOSI, LOW); + digitalWrite(PIN_SHUTDOWN, HIGH); + + SPI.setBitOrder(MSBFIRST); + SPI.setDataMode(SPI_MODE0); +} + +#ifdef HAVE_SHUTDOWN +static void bt_power_cycle(void){ + // power cycle. set CPU outputs to input to not power EM9301 via IOs + // pinMode(PIN_MOSI, INPUT); + // pinMode(PIN_CS, INPUT); + pinMode(PIN_CS, OUTPUT); + pinMode(PIN_MOSI, OUTPUT); + pinMode(PIN_SCK, OUTPUT); + pinMode(PIN_SHUTDOWN, OUTPUT); + digitalWrite(PIN_CS, LOW); + digitalWrite(PIN_MOSI, LOW); + digitalWrite(PIN_SCK, LOW); + digitalWrite(PIN_SHUTDOWN, HIGH); + delay(500); + + pinMode(PIN_MOSI, OUTPUT); + pinMode(PIN_CS, OUTPUT); + digitalWrite(PIN_MOSI, LOW); + digitalWrite(PIN_CS, HIGH); + digitalWrite(PIN_SHUTDOWN, LOW); + delay(1000); +} +#endif + +#ifndef HAVE_SHUTDOWN +static void bt_send_illegal(){ + digitalWrite(PIN_MOSI, HIGH); + digitalWrite(PIN_CS, LOW); + printf("Illegal start\n"); + SPI.begin(); + int i; + for (i=0;i<255;i++){ + SPI.transfer(0xff); + printf("."); + } + SPI.end(); + printf("\nIllegal stop\n"); + digitalWrite(PIN_CS, HIGH); +} + +static void bt_flush_input(){ + digitalWrite(PIN_MOSI, LOW); + digitalWrite(PIN_CS, LOW); + SPI.begin(); + while (digitalRead(PIN_IRQ_DATA) == HIGH){ + SPI.transfer(0x00); + } + SPI.end(); + digitalWrite(PIN_CS, HIGH); +} + +static void bt_send_reset(){ + digitalWrite(PIN_MOSI, HIGH); + digitalWrite(PIN_CS, LOW); + SPI.begin(); + SPI.transfer(0x01); + SPI.transfer(0x03); + SPI.transfer(0x0c); + SPI.transfer(0x00); + SPI.end(); + digitalWrite(PIN_CS, HIGH); +} +#endif + + +static void bt_try_send(void){ + + if (!bytes_to_write) return; + + // activate module + pinMode(PIN_MOSI, OUTPUT); + digitalWrite(PIN_MOSI, HIGH); + digitalWrite(PIN_CS, LOW); + + // module ready + int tx_done = 0; + if (digitalRead(PIN_MISO) == HIGH){ + // printf("Sending: "); + + SPI.begin(); + while (bytes_to_write){ + // printf("%02x ", *tx_buffer_ptr); + SPI.transfer(*tx_buffer_ptr); + tx_buffer_ptr++; + bytes_to_write--; + } + SPI.end(); + // printf(".\n"); + tx_done = 1; + } + + // deactivate module + digitalWrite(PIN_CS, HIGH); + digitalWrite(PIN_MOSI, LOW); + pinMode(PIN_MOSI, OUTPUT); + + // notify upper layer + if (tx_done) { + (*tx_done_handler)(); + } +} + +static int bt_try_read(void){ + + // check if data available and buffer is ready + if (digitalRead(PIN_IRQ_DATA) == LOW) return 0; + if (bytes_to_read == 0) return 0; + + int num_bytes_read = 0; + + // printf("Reading (%u): ", bytes_to_read); + + // activate module + digitalWrite(PIN_MOSI, LOW); + digitalWrite(PIN_CS, LOW); + SPI.begin(); + do { + uint8_t byte_read = SPI.transfer(0x00); + // printf("%02x ", byte_read); + *rx_buffer_ptr = byte_read; + rx_buffer_ptr++; + bytes_to_read--; + num_bytes_read++; + } while (bytes_to_read > 0); + SPI.end(); + digitalWrite(PIN_CS, HIGH); + + // printf("\n"); + + // notify upper layer + (*rx_done_handler)(); + + return num_bytes_read; +} + +extern "C" void hal_uart_dma_init(void){ + bt_setup(); + +#ifdef HAVE_SHUTDOWN + bt_power_cycle(); +#else + // bring EM9301 into defined state + bt_send_illegal(); + bt_send_reset(); + bt_flush_input(); +#endif +} + +extern "C" void hal_uart_dma_set_block_received( void (*block_handler)(void)){ + rx_done_handler = block_handler; +} +extern "C" void hal_uart_dma_set_block_sent( void (*block_handler)(void)){ + tx_done_handler = block_handler; +} + +extern "C" void hal_uart_dma_set_csr_irq_handler( void (*csr_irq_handler)(void)){ + // only used for eHCILL +} + +extern "C" int hal_uart_dma_set_baud(uint32_t baud){ + return 0; +} + +extern "C" void hal_uart_dma_send_block(const uint8_t *buffer, uint16_t length){ + // printf("send_block, bytes %u\n", length); + tx_buffer_ptr = (uint8_t *) buffer; + bytes_to_write = length; +} + +extern "C" void hal_uart_dma_receive_block(uint8_t *buffer, uint16_t length){ + rx_buffer_ptr = buffer; + bytes_to_read = length; +} + +extern "C" void hal_uart_dma_set_sleep(uint8_t sleep){ + // not needed for SPI (doesn't need internal clock to work) +} + +extern "C" void hal_uart_dma_process(){ + int num_bytes_read = bt_try_read(); + if (num_bytes_read == 0){ + bt_try_send(); + } +} + diff --git a/platforms/arduino/btstack-config.h b/platforms/arduino/btstack-config.h new file mode 100644 index 000000000..65f56d183 --- /dev/null +++ b/platforms/arduino/btstack-config.h @@ -0,0 +1,29 @@ +#define EMBEDDED + +// #define HAVE_INIT_SCRIPT +// #define HAVE_EHCILL + +#define HAVE_BZERO +#define HAVE_TICK + +#define HAVE_BLE + +// #define HAVE_HCI_DUMP +// #define ENABLE_LOG_INFO +// #define ENABLE_LOG_ERROR + +#define HCI_ACL_PAYLOAD_SIZE 52 + +#define MAX_NO_BNEP_SERVICES 0 +#define MAX_NO_BNEP_CHANNELS 0 +#define MAX_NO_GATT_SUBCLIENTS 1 +#define MAX_NO_HCI_CONNECTIONS 1 +#define MAX_NO_L2CAP_SERVICES 0 +#define MAX_NO_L2CAP_CHANNELS 0 +#define MAX_NO_RFCOMM_MULTIPLEXERS 0 +#define MAX_NO_RFCOMM_SERVICES 0 +#define MAX_NO_RFCOMM_CHANNELS 0 +#define MAX_NO_DB_MEM_DEVICE_LINK_KEYS 0 +#define MAX_NO_DB_MEM_DEVICE_NAMES 0 +#define MAX_NO_DB_MEM_SERVICES 0 +#define MAX_NO_GATT_CLIENTS 1 diff --git a/platforms/arduino/clone.sh b/platforms/arduino/clone.sh new file mode 100755 index 000000000..089d7f868 --- /dev/null +++ b/platforms/arduino/clone.sh @@ -0,0 +1,61 @@ +#!/bin/sh +DIR=`dirname $0` +BTSTACK_ROOT=$DIR/../.. +BTSTACK_PACKAGE=$DIR/btstack + +echo Update version.h file +$BTSTACK_ROOT/tools/get_version.sh + +pushd . +cd $BTSTACK_ROOT +VERSION=`sed -n -e 's/^.*BTSTACK_VERSION \"\(.*\)\"/\1/p' include/btstack/version.h` +ARCHIVE=btstack-arduino-$VERSION.zip +popd + +echo Prepare lib at $BTSTACK_PACKAGE + +rm -rf $BTSTACK_PACKAGE +mkdir $BTSTACK_PACKAGE + + +# headers +cp -r $BTSTACK_ROOT/include/btstack $BTSTACK_PACKAGE + +# other headers +cp $BTSTACK_ROOT/ble/*.h $BTSTACK_PACKAGE +cp $BTSTACK_ROOT/src/*.h $BTSTACK_PACKAGE + +# src files +SRC_FILES="btstack_memory.c linked_list.c memory_pool.c run_loop.c run_loop_embedded.c " +SRC_FILES+="hci_dump.c hci.c hci_cmds.c hci_transport_h4_dma.c sdp_util.c utils.c " +for i in $SRC_FILES +do + cp $BTSTACK_ROOT/src/$i $BTSTACK_PACKAGE +done + +# ble files +BLE_FILES="ad_parser.c att.c att_server.c att_dispatch.c le_device_db_memory.c gatt_client.c " +BLE_FILES+="sm.c l2cap_le.c ancs_client_lib.h ancs_client_lib.c" +for i in $BLE_FILES +do + cp $BTSTACK_ROOT/ble/$i $BTSTACK_PACKAGE +done + +# em9301 chipset support +cp $BTSTACK_ROOT/chipset-em9301/* $BTSTACK_PACKAGE + +# Configuration +cp $DIR/btstack-config.h $BTSTACK_PACKAGE + +# BSP Arduino +cp bsp_arduino_em9301.cpp $BTSTACK_PACKAGE + +# Arduino c++ API +cp $DIR/BTstack.cpp $DIR/BTstack.h $BTSTACK_PACKAGE + +# Arduino examples +cp -r $BTSTACK_ROOT/platforms/arduino/examples $BTSTACK_PACKAGE + +echo "Create Archive $ARCHIVE" +rm -f $ARCHIVE btstack.zip +zip -r $ARCHIVE btstack diff --git a/platforms/arduino/examples/BLECentralPseudo/BLECentralPseudo.ino b/platforms/arduino/examples/BLECentralPseudo/BLECentralPseudo.ino new file mode 100644 index 000000000..216474c97 --- /dev/null +++ b/platforms/arduino/examples/BLECentralPseudo/BLECentralPseudo.ino @@ -0,0 +1,184 @@ + +#include +#include + +// BLE Shield Service V2 incl. used Characteristics +UUID bleShieldServiceV2UUID("B8E06067-62AD-41BA-9231-206AE80AB550"); + +typedef enum characteristicIDs { + charRX = 0, + charTX, + charBaud, + charBdAddr, + numCharacteristics /* last one */ +} characteristicIDs_t; + +UUID characteristicUUIDs[] = { + UUID("f897177b-aee8-4767-8ecc-cc694fd5fcee"), + UUID("bf45e40a-de2a-4bc8-bba0-e5d6065f1b4b"), + UUID("2fbc0f31-726a-4014-b9fe-c8be0652e982"), + UUID("65c228da-bad1-4f41-b55f-3d177f4e2196"), +}; + +const char * characteristicNames[] = { + "RX", + "TX", + "Baudrate", + "BD ADDR" +}; + +bool characteristicFound[numCharacteristics]; +BLECharacteristic characteristics[numCharacteristics]; + +// Application state +BLEDevice myBLEDevice; +BLEService myBLEService; +bool serviceFound; +bool sendCounter = false; + +int counter = 0; +char counterString[20]; + +// setup printf +static FILE uartout = {0} ; +static int uart_putchar (char c, FILE *stream) { + Serial.write(c); + return 0; +} +static void setup_printf(int baud) { + Serial.begin(baud); + fdev_setup_stream (&uartout, uart_putchar, NULL, _FDEV_SETUP_WRITE); + stdout = &uartout; +} + +void setup() { + + setup_printf(9600); + + BTstack.setBLEAdvertisementCallback(advertisementCallback); + BTstack.setBLEDeviceConnectedCallback(deviceConnectedCallback); + BTstack.setBLEDeviceDisconnectedCallback(deviceDisconnectedCallback); + BTstack.setGATTServiceDiscoveredCallback(gattServiceDiscovered); + BTstack.setGATTCharacteristicDiscoveredCallback(gattCharacteristicDiscovered); + BTstack.setGATTCharacteristicNotificationCallback(gattCharacteristicNotification); + BTstack.setGATTCharacteristicReadCallback(gattReadCallback); + BTstack.setGATTCharacteristicWrittenCallback(gattWrittenCallback); + BTstack.setGATTCharacteristicSubscribedCallback(gattSubscribedCallback); + + BTstack.setup(); + + BTstack.bleStartScanning(); +} + + +void loop() { + BTstack.loop(); + + // send counter as fast as possible + if (sendCounter){ + sprintf(counterString, "BTstack %u\n", counter); + int result = myBLEDevice.writeCharacteristicWithoutResponse(&characteristics[charTX], (uint8_t*) counterString, strlen(counterString) ); + if (result == BLE_PERIPHERAL_OK){ + printf("Wrote without response: %s\n", counterString); + counter++; + } + } +} + +void advertisementCallback(BLEAdvertisement *bleAdvertisement) { + printf("Device discovered: %s, RSSI: %d\n", bleAdvertisement->getBdAddr()->getAddressString(), bleAdvertisement->getRssi() ); + // if (bleAdvertisement->containsService(&bleShieldServiceV2UUID) && bleAdvertisement->nameHasPrefix("BLE-Shield")) { + if (bleAdvertisement->containsService(&bleShieldServiceV2UUID)) { + printf("\nBLE ShieldService V2 found!\n\n"); + BTstack.bleStopScanning(); + BTstack.bleConnect(bleAdvertisement, 10000); // 10 s + } +} + +void deviceConnectedCallback(BLEStatus status, BLEDevice *device) { + switch (status){ + case BLE_STATUS_OK: + printf("Device connected!\n"); + myBLEDevice = *device; + counter = 0; + myBLEDevice.discoverGATTServices(); + break; + case BLE_STATUS_CONNECTION_TIMEOUT: + printf("Error while Connecting the Peripheral\n"); + BTstack.bleStartScanning(); + break; + default: + break; + } +} + +void deviceDisconnectedCallback(BLEDevice * device){ + printf("Disconnected, starting over..\n"); + sendCounter = false; + BTstack.bleStartScanning(); +} + +void gattServiceDiscovered(BLEStatus status, BLEDevice *device, BLEService *bleService) { + switch(status){ + case BLE_STATUS_OK: + printf("Service Discovered: %s\n", bleService->getUUID()->getUuidString()); + if (bleService->matches(&bleShieldServiceV2UUID)) { + serviceFound = true; + printf("Our service located!\n"); + myBLEService = *bleService; + } + break; + case BLE_STATUS_DONE: + printf("Service discovery finished\n"); + if (serviceFound) { + device->discoverCharacteristicsForService(&myBLEService); + } + break; + default: + printf("Service discovery error\n"); + break; + } +} + +void gattCharacteristicDiscovered(BLEStatus status, BLEDevice *device, BLECharacteristic *characteristic) { + switch(status){ + case BLE_STATUS_OK: + printf("Characteristic Discovered: %s, handle 0x%04x\n", characteristic->getUUID()->getUuidString(), characteristic->getCharacteristic()->value_handle); + int i; + for (i=0;imatches(&characteristicUUIDs[i])){ + printf("\nCharacteristic '%s' found!\n", characteristicNames[i]); + characteristicFound[i] = 1; + characteristics[i] = *characteristic; + break; + } + } + break; + case BLE_STATUS_DONE: + printf("Characteristic discovery finished, status %u.\n", status); + if (characteristicFound[charRX]) { + device->subscribeForNotifications(&characteristics[charRX]); + } + break; + default: + printf("Characteristics discovery error\n"); + break; + } +} + +void gattSubscribedCallback(BLEStatus status, BLEDevice * device){ + device->readCharacteristic(&characteristics[charBdAddr]); +} + +void gattReadCallback(BLEStatus status, BLEDevice *device, uint8_t *value, uint16_t length) { + printf("Read callback: '%s'\n", (const char *)value); + device->writeCharacteristic(&characteristics[charTX], (uint8_t*) "Hello!", 6); +} + +void gattWrittenCallback(BLEStatus status, BLEDevice *device){ + sendCounter = true; +} + +void gattCharacteristicNotification(BLEDevice *device, uint16_t value_handle, uint8_t *value, uint16_t length) { + printf("Notification: '%s'\n", (const char *)value); +} diff --git a/platforms/arduino/examples/Test/Test.ino b/platforms/arduino/examples/Test/Test.ino new file mode 100644 index 000000000..f00de60e1 --- /dev/null +++ b/platforms/arduino/examples/Test/Test.ino @@ -0,0 +1,192 @@ +/* basic SPI */ +#include + +#ifdef ENERGIA + +// CMM 9301 Configuration for TI Launchpad +#define PIN_SCK 7 +#define PIN_CS 8 +#define PIN_SHUTDOWN 11 +#define PIN_IRQ_DATA 13 +#define PIN_MISO 14 +#define PIN_MOSI 15 +#else // ARDUINO + +// CMM 9301 Configuration on Arduino +#define PIN_IRQ_DATA 2 +#define PIN_CS 4 +#define PIN_SHUTDOWN 5 +#define PIN_MISO 50 +#define PIN_MOSI 51 +#define PIN_SCK 52 +#define PIN_SHUTDOWN +#endif + +#if 0 +// software SPI +class Software_SPI { +public: + void setBitOrder(int){} + void setDataMode(int){}; + void setClockDivider(int){}; + void begin(){ + } + void end(){ + } + uint8_t transfer(uint8_t data){ + int i; + for (i=0;i<8;i++){ + if (data & 0x80){ + digitalWrite(PIN_MOSI, HIGH); + } else { + digitalWrite(PIN_MOSI, LOW); + } + digitalWrite(PIN_SCK, HIGH); + data = data << 1; + digitalWrite(PIN_SCK, LOW); + } + return 0; + } +}; + +#define SPI_MODE0 0 +#define SPI_CLOCK_DIV8 8 + +Software_SPI SPI; +#endif + +void setup(){ + pinMode (PIN_CS, OUTPUT); + pinMode(PIN_MOSI, OUTPUT); + pinMode(PIN_SCK, OUTPUT); + pinMode(PIN_SHUTDOWN, OUTPUT); + + SPI.setBitOrder(MSBFIRST); + SPI.setDataMode(SPI_MODE0); + + // digitalWrite(PIN_SHUTDOWN, LOW); + digitalWrite(PIN_CS, HIGH); + digitalWrite(PIN_MOSI, LOW); + + Serial.begin(9600); + Serial.println("Started\n"); +} + +void send_reset(){ + pinMode(PIN_MOSI, OUTPUT); + digitalWrite(PIN_MOSI, HIGH); + delay(1); + digitalWrite(PIN_CS, LOW); + delay(1); + SPI.begin(); + SPI.setClockDivider(SPI_CLOCK_DIV8); + SPI.transfer(0x01); + SPI.transfer(0x03); + SPI.transfer(0x0c); + SPI.transfer(0x00); + SPI.end(); + pinMode(PIN_MOSI, OUTPUT); + digitalWrite(PIN_MOSI, LOW); + digitalWrite(PIN_CS, HIGH); +} + +void send_illegal(){ + digitalWrite(PIN_MOSI, HIGH); + pinMode(PIN_MOSI, OUTPUT); + delay(1); + digitalWrite(PIN_CS, LOW); + delay(1); + SPI.begin(); + int i; + for (i=0;i<255;i++){ + SPI.transfer(0xff); + } + SPI.end(); + digitalWrite(PIN_CS, HIGH); +} + +void flush_input(){ + pinMode(PIN_MOSI, OUTPUT); + digitalWrite(PIN_MOSI, LOW); + digitalWrite(PIN_CS, LOW); + SPI.begin(); + while (digitalRead(PIN_IRQ_DATA) == HIGH){ + SPI.transfer(0x00); + } + SPI.end(); + digitalWrite(PIN_CS, HIGH); +} + +void read_event(){ + do { + pinMode (PIN_CS, OUTPUT); + pinMode(PIN_MOSI, OUTPUT); + digitalWrite(PIN_MOSI, LOW); + delay(1); + digitalWrite(PIN_CS, LOW); + delay(1); + SPI.begin(); + uint8_t data = SPI.transfer(0x00); + Serial.print("Read 0x"); + Serial.println(data, HEX); + SPI.end(); + pinMode (PIN_CS, OUTPUT); + pinMode(PIN_MOSI, OUTPUT); + digitalWrite(PIN_CS, HIGH); + delay(1); + } while (digitalRead(PIN_IRQ_DATA) == HIGH); +} + +void send_noise(){ + while (1){ + Serial.print("."); + pinMode(PIN_MOSI, OUTPUT); + digitalWrite(PIN_MOSI, HIGH); + SPI.begin(); + digitalWrite(PIN_CS, LOW); + SPI.transfer(0x0f); + SPI.transfer(0x55); + SPI.transfer(0xf0); + digitalWrite(PIN_CS, HIGH); + SPI.end(); + pinMode(PIN_MOSI, OUTPUT); + digitalWrite(PIN_MOSI, LOW); + } + Serial.println("\n"); +} + +void power_cycle(){ + // power cycle + pinMode(PIN_MOSI, INPUT); + pinMode(PIN_CS, INPUT); + digitalWrite(PIN_SHUTDOWN, HIGH); + delay(1000); + digitalWrite(PIN_SHUTDOWN, LOW); + delay(1000); + pinMode(PIN_CS, OUTPUT); + pinMode(PIN_MOSI, OUTPUT); +} + +void loop() { + + Serial.println("Send noise"); + + // prepare unsynced state + // send_noise(); + + // bring HCI parser into defined error state + // send_illegal(); + + // power cycle + Serial.println("Power cycle"); + power_cycle(); + + Serial.println("Reset"); + send_reset(); + + while (digitalRead(PIN_IRQ_DATA) == HIGH){ + read_event(); + } + + delay(5000); +} diff --git a/platforms/arduino/examples/btstack_ancs_client/btstack_ancs_client.ino b/platforms/arduino/examples/btstack_ancs_client/btstack_ancs_client.ino new file mode 100644 index 000000000..b81249385 --- /dev/null +++ b/platforms/arduino/examples/btstack_ancs_client/btstack_ancs_client.ino @@ -0,0 +1,91 @@ +#include +#include +#include "att_server.h" +#include "gatt_client.h" +#include "ancs_client_lib.h" +#include "sm.h" +#include + +const uint8_t adv_data[] = { + // Flags general discoverable + 0x02, 0x01, 0x02, + // Name + 0x05, 0x09, 'A', 'N', 'C', 'S', + // Service Solicitation, 128-bit UUIDs - ANCS (little endian) + 0x11,0x15,0xD0,0x00,0x2D,0x12,0x1E,0x4B,0x0F,0xA4,0x99,0x4E,0xCE,0xB5,0x31,0xF4,0x05,0x79 +}; + +// retarget printf +#ifdef ENERGIA +extern "C" { + int putchar(int c) { + Serial.write((uint8_t)c); + return c; + } +} +static void setup_printf(void) { + Serial.begin(9600); +} +#else +static FILE uartout = {0} ; +static int uart_putchar (char c, FILE *stream) { + Serial.write(c); + return 0; +} +static void setup_printf(void) { + Serial.begin(115200); + fdev_setup_stream (&uartout, uart_putchar, NULL, _FDEV_SETUP_WRITE); + stdout = &uartout; +} +#endif + +static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ + printf("packet_handler type %u, event 0x%02x\n", packet_type, packet[0]); + ancs_client_hci_event_handler(packet_type, channel, packet, size); +} + +void ancs_callback(ancs_event_t * event){ + const char * attribute_name; + switch (event->type){ + case ANCS_CLIENT_CONNECTED: + printf("ANCS Client: Connected\n"); + break; + case ANCS_CLIENT_DISCONNECTED: + printf("ANCS Client: Disconnected\n"); + break; + case ANCS_CLIENT_NOTIFICATION: + attribute_name = ancs_client_attribute_name_for_id(event->attribute_id); + if (!attribute_name) break; + printf("Notification: %s - %s\n", attribute_name, event->text); + break; + default: + break; + } +} + +void setup(){ + setup_printf(); + printf("Main::Setup()\n"); + BT.setup(); + BT.setAdvData(sizeof(adv_data), adv_data); + + // setup packet handler (Client+Server_ + BT.registerPacketHandler(&packet_handler); + + sm_set_io_capabilities(IO_CAPABILITY_DISPLAY_ONLY); + sm_set_authentication_requirements( SM_AUTHREQ_BONDING ); + + // set up GATT Server + att_set_db(NULL); + + // setup GATT client + gatt_client_init(); + + // setup ANCS Client + ancs_client_init(); + ancs_client_register_callback(&ancs_callback); +} + +void loop(){ + BT.loop(); +} diff --git a/platforms/arduino/examples/btstack_gatt_client/btstack_gatt_client.ino b/platforms/arduino/examples/btstack_gatt_client/btstack_gatt_client.ino new file mode 100644 index 000000000..044aa986e --- /dev/null +++ b/platforms/arduino/examples/btstack_gatt_client/btstack_gatt_client.ino @@ -0,0 +1,129 @@ +#include +#include +#include "att_server.h" +#include "gatt_client.h" +#include "hci.h" + +#include + +static bd_addr_t em9301_addr = { 0x0C, 0xF3, 0xEE, 0x00, 0x00, 0x00 }; +static gatt_client_t gatt_context; +static uint16_t con_handle; +static uint8_t sensor_value; + +// retarget printf +#ifdef ENERGIA +extern "C" { + int putchar(int c) { + Serial.write((uint8_t)c); + return c; + } +} +static void setup_printf(void) { + Serial.begin(9600); +} +#else +static FILE uartout = {0} ; +static int uart_putchar (char c, FILE *stream) { + Serial.write(c); + return 0; +} +static void setup_printf(void) { + Serial.begin(115200); + fdev_setup_stream (&uartout, uart_putchar, NULL, _FDEV_SETUP_WRITE); + stdout = &uartout; +} +#endif + +// test profile +#include "profile.h" + +// write requests +static int att_write_callback(uint16_t con_handle, uint16_t handle, uint16_t transaction_mode, uint16_t offset, uint8_t *buffer, uint16_t buffer_size){ + printf("WRITE Callback, handle 0x%04x\n", handle); + + switch(handle){ + case ATT_CHARACTERISTIC_FFF1_01_VALUE_HANDLE: + buffer[buffer_size]=0; + printf("New text: %s\n", buffer); + break; + case ATT_CHARACTERISTIC_FFF2_01_VALUE_HANDLE: + printf("New value: %u\n", buffer[0]); +#ifdef PIN_LED + if (buffer[0]){ + digitalWrite(PIN_LED, HIGH); + } else { + digitalWrite(PIN_LED, LOW); + } +#endif + break; + } + return 0; +} + + +static void try_send(){ + if (!con_handle) return; + + // try write + gatt_client_write_value_of_characteristic_without_response(&gatt_context, ATT_CHARACTERISTIC_FFF2_01_VALUE_HANDLE, 1, &sensor_value); +} + +static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ + printf("packet type %x\n", packet[0]); + switch (packet_type) { + case HCI_EVENT_PACKET: + switch (packet[0]) { + case BTSTACK_EVENT_STATE: + if (packet[2] == HCI_STATE_WORKING) { + printf("Connecting to server\n"); + le_central_connect(&em9301_addr, BD_ADDR_TYPE_LE_PUBLIC); + } + break; + + case HCI_EVENT_DISCONNECTION_COMPLETE: + con_handle = 0; + break; + + case HCI_EVENT_LE_META: + switch (packet[2]) { + case HCI_SUBEVENT_LE_CONNECTION_COMPLETE: + // store connection info + con_handle = READ_BT_16(packet, 4); + + // start GATT Client + gatt_client_start(&gatt_context, con_handle); + break; + + default: + break; + } + break; + } + } + try_send(); +} + +void setup(){ + + setup_printf(); + + printf("Main::Setup()\n"); + BT.setup(); + + // set up GATT Server + att_set_db(profile_data); + att_set_write_callback(att_write_callback); + + // set up GATT Client + gatt_client_init(); + BT.setClientMode(); + + // setup packet handler (Client+Server_ + BT.registerPacketHandler(&packet_handler); +} + +void loop(){ + BT.loop(); + sensor_value = analogRead(A0) >> 2; +} diff --git a/platforms/arduino/examples/btstack_gatt_server/btstack_gatt_server.ino b/platforms/arduino/examples/btstack_gatt_server/btstack_gatt_server.ino new file mode 100644 index 000000000..33e563955 --- /dev/null +++ b/platforms/arduino/examples/btstack_gatt_server/btstack_gatt_server.ino @@ -0,0 +1,72 @@ +#include +#include +#include "att_server.h" +#include + +// EM9301 address 0C:F3:EE:00:00:00 + +// retarget printf +#ifdef ENERGIA +extern "C" { + int putchar(int c) { + Serial.write((uint8_t)c); + return c; + } +} +static void setup_printf(void) { + Serial.begin(9600); +} +#else +static FILE uartout = {0} ; +static int uart_putchar (char c, FILE *stream) { + Serial.write(c); + return 0; +} +static void setup_printf(void) { + Serial.begin(115200); + fdev_setup_stream (&uartout, uart_putchar, NULL, _FDEV_SETUP_WRITE); + stdout = &uartout; +} +#endif + +// test profile +#include "profile.h" + +// write requests +static int att_write_callback(uint16_t con_handle, uint16_t handle, uint16_t transaction_mode, uint16_t offset, uint8_t *buffer, uint16_t buffer_size){ + printf("WRITE Callback, handle 0x%04x\n", handle); + + switch(handle){ + case ATT_CHARACTERISTIC_FFF1_01_VALUE_HANDLE: + buffer[buffer_size]=0; + printf("New text: %s\n", buffer); + break; + case ATT_CHARACTERISTIC_FFF2_01_VALUE_HANDLE: + printf("New value: %u\n", buffer[0]); +#ifdef PIN_LED + if (buffer[0]){ + digitalWrite(PIN_LED, HIGH); + } else { + digitalWrite(PIN_LED, LOW); + } +#endif + break; + } + return 0; +} + +void setup(){ + + setup_printf(); + + printf("Main::Setup()\n"); + BT.setup(); + + // set up ATT + att_set_db(profile_data); + att_set_write_callback(att_write_callback); +} + +void loop(){ + BT.loop(); +}