yes Spada / Mbed OS programme
Committer:
loicguibert
Date:
Tue Mar 19 20:48:48 2019 +0000
Revision:
11:dbc310addbf6
Point 5 done

Who changed what in which revision?

UserRevisionLine numberNew contents of line
loicguibert 11:dbc310addbf6 1 #include "GAPPeripheral.h"
loicguibert 11:dbc310addbf6 2
loicguibert 11:dbc310addbf6 3 // constructor
loicguibert 11:dbc310addbf6 4 GAPPeripheral::GAPPeripheral(BLE& ble,
loicguibert 11:dbc310addbf6 5 IDevKit& devKit,
loicguibert 11:dbc310addbf6 6 const string& deviceName,
loicguibert 11:dbc310addbf6 7 GapAdvertisingParams::AdvertisingType_t advType,
loicguibert 11:dbc310addbf6 8 events::EventQueue& eventQueue,
loicguibert 11:dbc310addbf6 9 Logger& logger)
loicguibert 11:dbc310addbf6 10 : m_devKit(devKit),
loicguibert 11:dbc310addbf6 11 m_ble(ble),
loicguibert 11:dbc310addbf6 12 m_deviceName(deviceName),
loicguibert 11:dbc310addbf6 13 m_advType(advType),
loicguibert 11:dbc310addbf6 14 m_eventQueue(eventQueue),
loicguibert 11:dbc310addbf6 15 m_logger(logger) {
loicguibert 11:dbc310addbf6 16 }
loicguibert 11:dbc310addbf6 17
loicguibert 11:dbc310addbf6 18 GAPPeripheral::~GAPPeripheral() {
loicguibert 11:dbc310addbf6 19 if (m_ble.hasInitialized()) {
loicguibert 11:dbc310addbf6 20 m_ble.shutdown();
loicguibert 11:dbc310addbf6 21 }
loicguibert 11:dbc310addbf6 22 }
loicguibert 11:dbc310addbf6 23
loicguibert 11:dbc310addbf6 24 void GAPPeripheral::advertise(void) {
loicguibert 11:dbc310addbf6 25 if (m_ble.hasInitialized()) {
loicguibert 11:dbc310addbf6 26 m_logger.log("Ble instance already initialised.\r\n");
loicguibert 11:dbc310addbf6 27 return;
loicguibert 11:dbc310addbf6 28 }
loicguibert 11:dbc310addbf6 29
loicguibert 11:dbc310addbf6 30 // this will inform us off all events so we can schedule their handling
loicguibert 11:dbc310addbf6 31 // using our event queue
loicguibert 11:dbc310addbf6 32 m_ble.onEventsToProcess(makeFunctionPointer(this, &GAPPeripheral::scheduleBleEvents));
loicguibert 11:dbc310addbf6 33
loicguibert 11:dbc310addbf6 34 // handle timeouts, for example when connection attempts fail
loicguibert 11:dbc310addbf6 35 m_ble.gap().onTimeout(makeFunctionPointer(this, &GAPPeripheral::onTimeOut));
loicguibert 11:dbc310addbf6 36
loicguibert 11:dbc310addbf6 37 // set this instance as the event handler for all gap events
loicguibert 11:dbc310addbf6 38 m_ble.gap().setEventHandler(this);
loicguibert 11:dbc310addbf6 39
loicguibert 11:dbc310addbf6 40 // initialize the ble component
loicguibert 11:dbc310addbf6 41 ble_error_t error = m_ble.init(this, &GAPPeripheral::onInitComplete);
loicguibert 11:dbc310addbf6 42 if (error) {
loicguibert 11:dbc310addbf6 43 m_logger.log("Error returned by BLE::init: %d\r\n", error);
loicguibert 11:dbc310addbf6 44 return;
loicguibert 11:dbc310addbf6 45 }
loicguibert 11:dbc310addbf6 46
loicguibert 11:dbc310addbf6 47 // to show we're running we'll blink
loicguibert 11:dbc310addbf6 48 m_eventQueue.call_every(BLINK_INTERVAL, &m_devKit, &IDevKit::toggleLed1);
loicguibert 11:dbc310addbf6 49
loicguibert 11:dbc310addbf6 50 // this will not return until shutdown
loicguibert 11:dbc310addbf6 51 m_eventQueue.dispatch_forever();
loicguibert 11:dbc310addbf6 52 }
loicguibert 11:dbc310addbf6 53
loicguibert 11:dbc310addbf6 54 // private methods
loicguibert 11:dbc310addbf6 55 void GAPPeripheral::scheduleBleEvents(BLE::OnEventsToProcessCallbackContext *context) {
loicguibert 11:dbc310addbf6 56 m_eventQueue.call(mbed::callback(&context->ble, &BLE::processEvents));
loicguibert 11:dbc310addbf6 57 }
loicguibert 11:dbc310addbf6 58
loicguibert 11:dbc310addbf6 59 void GAPPeripheral::onTimeOut(const Gap::TimeoutSource_t source) {
loicguibert 11:dbc310addbf6 60 switch (source) {
loicguibert 11:dbc310addbf6 61 case Gap::TIMEOUT_SRC_ADVERTISING:
loicguibert 11:dbc310addbf6 62 m_logger.log("Stopped advertising early due to timeout parameter\r\n");
loicguibert 11:dbc310addbf6 63 break;
loicguibert 11:dbc310addbf6 64 case Gap::TIMEOUT_SRC_SCAN:
loicguibert 11:dbc310addbf6 65 m_logger.log("Stopped scanning early due to timeout parameter\r\n");
loicguibert 11:dbc310addbf6 66 break;
loicguibert 11:dbc310addbf6 67 case Gap::TIMEOUT_SRC_CONN:
loicguibert 11:dbc310addbf6 68 m_logger.log("Failed to connect\r\n");
loicguibert 11:dbc310addbf6 69 break;
loicguibert 11:dbc310addbf6 70 default:
loicguibert 11:dbc310addbf6 71 m_logger.log("Unexpected timeout\r\n");
loicguibert 11:dbc310addbf6 72 break;
loicguibert 11:dbc310addbf6 73 }
loicguibert 11:dbc310addbf6 74 }
loicguibert 11:dbc310addbf6 75
loicguibert 11:dbc310addbf6 76 void GAPPeripheral::onInitComplete(BLE::InitializationCompleteCallbackContext *event) {
loicguibert 11:dbc310addbf6 77 if (event->error) {
loicguibert 11:dbc310addbf6 78 m_logger.log("Error during the initialisation\r\n");
loicguibert 11:dbc310addbf6 79 return;
loicguibert 11:dbc310addbf6 80 }
loicguibert 11:dbc310addbf6 81
loicguibert 11:dbc310addbf6 82 // print device address
loicguibert 11:dbc310addbf6 83 Gap::AddressType_t addr_type;
loicguibert 11:dbc310addbf6 84 Gap::Address_t addr;
loicguibert 11:dbc310addbf6 85 m_ble.gap().getAddress(&addr_type, addr);
loicguibert 11:dbc310addbf6 86 m_logger.log("Device address: %02x:%02x:%02x:%02x:%02x:%02x\r\n",
loicguibert 11:dbc310addbf6 87 addr[5], addr[4], addr[3], addr[2], addr[1], addr[0]);
loicguibert 11:dbc310addbf6 88
loicguibert 11:dbc310addbf6 89 // setup the callback to be called upon connection
loicguibert 11:dbc310addbf6 90 m_ble.gap().onConnection(this, &GAPPeripheral::onConnect);
loicguibert 11:dbc310addbf6 91
loicguibert 11:dbc310addbf6 92 // all calls are serialised on the user thread through the event queue
loicguibert 11:dbc310addbf6 93 // so schedule start of advertising in the same way
loicguibert 11:dbc310addbf6 94 m_eventQueue.call(this, &GAPPeripheral::startAdvertising);
loicguibert 11:dbc310addbf6 95 };
loicguibert 11:dbc310addbf6 96
loicguibert 11:dbc310addbf6 97 void GAPPeripheral::onConnect(const Gap::ConnectionCallbackParams_t *connection_event) {
loicguibert 11:dbc310addbf6 98 m_logger.log("Connection request received\r\n");
loicguibert 11:dbc310addbf6 99 }
loicguibert 11:dbc310addbf6 100
loicguibert 11:dbc310addbf6 101 void GAPPeripheral::startAdvertising(void) {
loicguibert 11:dbc310addbf6 102 // add advertising flags
loicguibert 11:dbc310addbf6 103 GapAdvertisingData advertisingData;
loicguibert 11:dbc310addbf6 104 advertisingData.addFlags(GapAdvertisingData::LE_GENERAL_DISCOVERABLE
loicguibert 11:dbc310addbf6 105 | GapAdvertisingData::BREDR_NOT_SUPPORTED);
loicguibert 11:dbc310addbf6 106
loicguibert 11:dbc310addbf6 107 // add device name
loicguibert 11:dbc310addbf6 108 advertisingData.addData(GapAdvertisingData::COMPLETE_LOCAL_NAME,
loicguibert 11:dbc310addbf6 109 (const uint8_t*) m_deviceName.c_str(),
loicguibert 11:dbc310addbf6 110 m_deviceName.length());
loicguibert 11:dbc310addbf6 111
loicguibert 11:dbc310addbf6 112 ble_error_t error = m_ble.gap().setAdvertisingPayload(advertisingData);
loicguibert 11:dbc310addbf6 113 if (error) {
loicguibert 11:dbc310addbf6 114 m_logger.log("Error during Gap::setAdvertisingPayload\r\n");
loicguibert 11:dbc310addbf6 115 return;
loicguibert 11:dbc310addbf6 116 }
loicguibert 11:dbc310addbf6 117
loicguibert 11:dbc310addbf6 118 // how many milliseconds between advertisements, lower interval
loicguibert 11:dbc310addbf6 119 // increases the chances of being seen at the cost of more power
loicguibert 11:dbc310addbf6 120 uint16_t interval = 100;
loicguibert 11:dbc310addbf6 121
loicguibert 11:dbc310addbf6 122 // advertising will continue for this many seconds or until connected
loicguibert 11:dbc310addbf6 123 uint16_t timeout = 3600;
loicguibert 11:dbc310addbf6 124
loicguibert 11:dbc310addbf6 125 m_ble.gap().setAdvertisingType(m_advType);
loicguibert 11:dbc310addbf6 126 m_ble.gap().setAdvertisingInterval(interval);
loicguibert 11:dbc310addbf6 127 m_ble.gap().setAdvertisingTimeout(timeout);
loicguibert 11:dbc310addbf6 128
loicguibert 11:dbc310addbf6 129 error = m_ble.gap().startAdvertising();
loicguibert 11:dbc310addbf6 130 if (error) {
loicguibert 11:dbc310addbf6 131 m_logger.log("Error during Gap::startAdvertising.\r\n");
loicguibert 11:dbc310addbf6 132 return;
loicguibert 11:dbc310addbf6 133 }
loicguibert 11:dbc310addbf6 134
loicguibert 11:dbc310addbf6 135 m_logger.log("Advertising started (type: 0x%x, interval: %dms, timeout: %ds)\r\n",
loicguibert 11:dbc310addbf6 136 m_advType, interval, timeout);
loicguibert 11:dbc310addbf6 137 }
loicguibert 11:dbc310addbf6 138
loicguibert 11:dbc310addbf6 139 void GAPPeripheral::setAdvertisementServiceData(ServiceDataPayload* serviceDataPayloadArray,
loicguibert 11:dbc310addbf6 140 uint8_t nbrOfServices) {
loicguibert 11:dbc310addbf6 141 // first clear advertising payload
loicguibert 11:dbc310addbf6 142 m_ble.gap().clearAdvertisingPayload();
loicguibert 11:dbc310addbf6 143
loicguibert 11:dbc310addbf6 144 // set the flags
loicguibert 11:dbc310addbf6 145 m_ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE);
loicguibert 11:dbc310addbf6 146
loicguibert 11:dbc310addbf6 147 // set the complete local name
loicguibert 11:dbc310addbf6 148 m_ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LOCAL_NAME, (const uint8_t*) m_deviceName.c_str(), m_deviceName.length());
loicguibert 11:dbc310addbf6 149
loicguibert 11:dbc310addbf6 150 // set the list of 16 service uuids
loicguibert 11:dbc310addbf6 151 uint16_t serviceUUIDArraySize = nbrOfServices * sizeof(uint16_t);
loicguibert 11:dbc310addbf6 152 uint8_t* serviceUUIDArray = new uint8_t[serviceUUIDArraySize];
loicguibert 11:dbc310addbf6 153 for (uint8_t i = 0; i < nbrOfServices; i++) {
loicguibert 11:dbc310addbf6 154 uint16_encode(serviceDataPayloadArray[i].serviceUUID, serviceUUIDArray + i * sizeof(uint16_t));
loicguibert 11:dbc310addbf6 155 }
loicguibert 11:dbc310addbf6 156 m_ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_16BIT_SERVICE_IDS, serviceUUIDArray, serviceUUIDArraySize);
loicguibert 11:dbc310addbf6 157
loicguibert 11:dbc310addbf6 158 // set the service data payload - each payload is prepended with the service UUID
loicguibert 11:dbc310addbf6 159 for (uint8_t i = 0; i < nbrOfServices; i++) {
loicguibert 11:dbc310addbf6 160 uint16_t prependedServiceDataLength = serviceDataPayloadArray[i].serviceDataLength + 2;
loicguibert 11:dbc310addbf6 161 uint8_t* prependedServiceData = new uint8_t[prependedServiceDataLength];
loicguibert 11:dbc310addbf6 162 uint16_encode(serviceDataPayloadArray[i].serviceUUID, prependedServiceData);
loicguibert 11:dbc310addbf6 163
loicguibert 11:dbc310addbf6 164 memcpy(prependedServiceData + 2, serviceDataPayloadArray[i].serviceData, serviceDataPayloadArray[i].serviceDataLength);
loicguibert 11:dbc310addbf6 165
loicguibert 11:dbc310addbf6 166 m_ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::SERVICE_DATA, prependedServiceData, prependedServiceDataLength);
loicguibert 11:dbc310addbf6 167
loicguibert 11:dbc310addbf6 168 delete prependedServiceData;
loicguibert 11:dbc310addbf6 169 prependedServiceData = NULL;
loicguibert 11:dbc310addbf6 170 }
loicguibert 11:dbc310addbf6 171 }
loicguibert 11:dbc310addbf6 172
loicguibert 11:dbc310addbf6 173 void GAPPeripheral::uint16_encode(const uint16_t value, uint8_t* p_encoded_data) {
loicguibert 11:dbc310addbf6 174 p_encoded_data[0] = (uint8_t) ((value & 0x00FF) >> 0);
loicguibert 11:dbc310addbf6 175 p_encoded_data[1] = (uint8_t) ((value & 0xFF00) >> 8);
loicguibert 11:dbc310addbf6 176 }
loicguibert 11:dbc310addbf6 177
loicguibert 11:dbc310addbf6 178 void GAPPeripheral::int16_encode(const int16_t value, uint8_t* p_encoded_data) {
loicguibert 11:dbc310addbf6 179 uint16_t tmp = value;
loicguibert 11:dbc310addbf6 180 uint16_encode(tmp, p_encoded_data);
loicguibert 11:dbc310addbf6 181 }
loicguibert 11:dbc310addbf6 182
loicguibert 11:dbc310addbf6 183 void GAPPeripheral::uint32_encode(const uint32_t value, uint8_t* p_encoded_data) {
loicguibert 11:dbc310addbf6 184 p_encoded_data[0] = (uint8_t) ((value & 0x000000FF) >> 0);
loicguibert 11:dbc310addbf6 185 p_encoded_data[1] = (uint8_t) ((value & 0x0000FF00) >> 8);
loicguibert 11:dbc310addbf6 186 p_encoded_data[2] = (uint8_t) ((value & 0x00FF0000) >> 16);
loicguibert 11:dbc310addbf6 187 p_encoded_data[3] = (uint8_t) ((value & 0xFF000000) >> 24);
loicguibert 11:dbc310addbf6 188 }