Maxim Integrated Bluetooth LE Library

Dependents:   BLE_Thermometer MAXWSNENV_demo

Committer:
enginerd
Date:
Thu Oct 06 22:02:31 2016 +0000
Revision:
5:5b87f64ce81e
Parent:
0:b562096246b3
Added new required method.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
enginerd 0:b562096246b3 1 /*******************************************************************************
enginerd 0:b562096246b3 2 * Copyright (C) 2016 Maxim Integrated Products, Inc., All Rights Reserved.
enginerd 0:b562096246b3 3 *
enginerd 0:b562096246b3 4 * Permission is hereby granted, free of charge, to any person obtaining a
enginerd 0:b562096246b3 5 * copy of this software and associated documentation files (the "Software"),
enginerd 0:b562096246b3 6 * to deal in the Software without restriction, including without limitation
enginerd 0:b562096246b3 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
enginerd 0:b562096246b3 8 * and/or sell copies of the Software, and to permit persons to whom the
enginerd 0:b562096246b3 9 * Software is furnished to do so, subject to the following conditions:
enginerd 0:b562096246b3 10 *
enginerd 0:b562096246b3 11 * The above copyright notice and this permission notice shall be included
enginerd 0:b562096246b3 12 * in all copies or substantial portions of the Software.
enginerd 0:b562096246b3 13 *
enginerd 0:b562096246b3 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
enginerd 0:b562096246b3 15 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
enginerd 0:b562096246b3 16 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
enginerd 0:b562096246b3 17 * IN NO EVENT SHALL MAXIM INTEGRATED BE LIABLE FOR ANY CLAIM, DAMAGES
enginerd 0:b562096246b3 18 * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
enginerd 0:b562096246b3 19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
enginerd 0:b562096246b3 20 * OTHER DEALINGS IN THE SOFTWARE.
enginerd 0:b562096246b3 21 *
enginerd 0:b562096246b3 22 * Except as contained in this notice, the name of Maxim Integrated
enginerd 0:b562096246b3 23 * Products, Inc. shall not be used except as stated in the Maxim Integrated
enginerd 0:b562096246b3 24 * Products, Inc. Branding Policy.
enginerd 0:b562096246b3 25 *
enginerd 0:b562096246b3 26 * The mere transfer of this software does not imply any licenses
enginerd 0:b562096246b3 27 * of trade secrets, proprietary technology, copyrights, patents,
enginerd 0:b562096246b3 28 * trademarks, maskwork rights, or any other form of intellectual
enginerd 0:b562096246b3 29 * property whatsoever. Maxim Integrated Products, Inc. retains all
enginerd 0:b562096246b3 30 * ownership rights.
enginerd 0:b562096246b3 31 *******************************************************************************
enginerd 0:b562096246b3 32 */
enginerd 0:b562096246b3 33
enginerd 0:b562096246b3 34 #include "MaximGattServer.h"
enginerd 0:b562096246b3 35 #include "mbed.h"
enginerd 0:b562096246b3 36 #include "MaximGap.h"
enginerd 0:b562096246b3 37 #include "wsf_types.h"
enginerd 0:b562096246b3 38 #include "att_api.h"
enginerd 0:b562096246b3 39
enginerd 0:b562096246b3 40 typedef struct mxmChar_s {
enginerd 0:b562096246b3 41 uint16_t descLen;
enginerd 0:b562096246b3 42 mxmChar_s() {}
enginerd 0:b562096246b3 43 } mxmChar_t;
enginerd 0:b562096246b3 44
enginerd 0:b562096246b3 45 typedef struct mxmService_s mxmService_t;
enginerd 0:b562096246b3 46 struct mxmService_s {
enginerd 0:b562096246b3 47 uint16_t uuidLen;
enginerd 0:b562096246b3 48 mxmChar_t *chars;
enginerd 0:b562096246b3 49 attsGroup_t *attGroup;
enginerd 0:b562096246b3 50 mxmService_t *next;
enginerd 0:b562096246b3 51 mxmService_s() {}
enginerd 0:b562096246b3 52 };
enginerd 0:b562096246b3 53
enginerd 0:b562096246b3 54 static uint16_t currentHandle = 0x20;
enginerd 0:b562096246b3 55
enginerd 0:b562096246b3 56 static UUID cccUUID(BLE_UUID_DESCRIPTOR_CLIENT_CHAR_CONFIG);
enginerd 0:b562096246b3 57 static const uint16_t cccSize = sizeof(uint16_t);
enginerd 0:b562096246b3 58
enginerd 0:b562096246b3 59 MaximGattServer &MaximGattServer::getInstance() {
enginerd 0:b562096246b3 60 static MaximGattServer m_instance;
enginerd 0:b562096246b3 61 return m_instance;
enginerd 0:b562096246b3 62 }
enginerd 0:b562096246b3 63
enginerd 0:b562096246b3 64 ble_error_t MaximGattServer::addService(GattService &service)
enginerd 0:b562096246b3 65 {
enginerd 0:b562096246b3 66 currentHandle = (currentHandle + 0xF) & ~0xF;
enginerd 0:b562096246b3 67 uint16_t startHandle = currentHandle;
enginerd 0:b562096246b3 68
enginerd 0:b562096246b3 69 mxmService_t *mxmSvc = new mxmService_t;
enginerd 0:b562096246b3 70
enginerd 0:b562096246b3 71 // Create WiCentric attribute group
enginerd 0:b562096246b3 72 mxmSvc->attGroup = new attsGroup_t;
enginerd 0:b562096246b3 73
enginerd 0:b562096246b3 74 // Determine the attribute list length
enginerd 0:b562096246b3 75 unsigned int attListLen = 1;
enginerd 0:b562096246b3 76 for (int i = 0; i < service.getCharacteristicCount(); i++) {
enginerd 0:b562096246b3 77 attListLen += 2;
enginerd 0:b562096246b3 78 GattCharacteristic *p_char = service.getCharacteristic(i);
enginerd 0:b562096246b3 79
enginerd 0:b562096246b3 80 if (p_char->getProperties() & (GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_INDICATE)) {
enginerd 0:b562096246b3 81 // add a CCCD
enginerd 0:b562096246b3 82 attListLen++;
enginerd 0:b562096246b3 83 }
enginerd 0:b562096246b3 84 }
enginerd 0:b562096246b3 85
enginerd 0:b562096246b3 86 // Create WiCentric attribute list
enginerd 0:b562096246b3 87 mxmSvc->attGroup->pAttr = (attsAttr_t*)malloc(attListLen * sizeof(attsAttr_t));;
enginerd 0:b562096246b3 88 if (mxmSvc->attGroup->pAttr == NULL) {
enginerd 0:b562096246b3 89 return BLE_ERROR_BUFFER_OVERFLOW;
enginerd 0:b562096246b3 90 }
enginerd 0:b562096246b3 91
enginerd 0:b562096246b3 92 // Create characteristics
enginerd 0:b562096246b3 93 mxmSvc->chars = new mxmChar_t [service.getCharacteristicCount()];
enginerd 0:b562096246b3 94
enginerd 0:b562096246b3 95 attsAttr_t *currAtt = mxmSvc->attGroup->pAttr;
enginerd 0:b562096246b3 96
enginerd 0:b562096246b3 97 /* Service */
enginerd 0:b562096246b3 98 currAtt->pUuid = attPrimSvcUuid;
enginerd 0:b562096246b3 99 if (service.getUUID().shortOrLong() == UUID::UUID_TYPE_LONG) {
enginerd 0:b562096246b3 100 mxmSvc->uuidLen = UUID::LENGTH_OF_LONG_UUID;
enginerd 0:b562096246b3 101 } else {
enginerd 0:b562096246b3 102 mxmSvc->uuidLen = sizeof(UUID::ShortUUIDBytes_t);
enginerd 0:b562096246b3 103 }
enginerd 0:b562096246b3 104 currAtt->pValue = (uint8_t*)malloc(mxmSvc->uuidLen);
enginerd 0:b562096246b3 105 memcpy(currAtt->pValue, service.getUUID().getBaseUUID(), mxmSvc->uuidLen);
enginerd 0:b562096246b3 106 currAtt->maxLen = mxmSvc->uuidLen;
enginerd 0:b562096246b3 107 currAtt->pLen = &mxmSvc->uuidLen;
enginerd 0:b562096246b3 108 currAtt->settings = 0;
enginerd 0:b562096246b3 109 currAtt->permissions = ATTS_PERMIT_READ;
enginerd 0:b562096246b3 110
enginerd 0:b562096246b3 111 currAtt++;
enginerd 0:b562096246b3 112
enginerd 0:b562096246b3 113 /* Add characteristics to the service */
enginerd 0:b562096246b3 114 for (int i = 0; i < service.getCharacteristicCount(); i++) {
enginerd 0:b562096246b3 115 GattCharacteristic *p_char = service.getCharacteristic(i);
enginerd 0:b562096246b3 116
enginerd 0:b562096246b3 117 /* Skip any incompletely defined, read-only characteristics. */
enginerd 0:b562096246b3 118 if ((p_char->getValueAttribute().getValuePtr() == NULL) &&
enginerd 0:b562096246b3 119 (p_char->getValueAttribute().getLength() == 0) &&
enginerd 0:b562096246b3 120 (p_char->getProperties() == GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ)) {
enginerd 0:b562096246b3 121 continue;
enginerd 0:b562096246b3 122 }
enginerd 0:b562096246b3 123
enginerd 0:b562096246b3 124 // Create Characteristic Attribute
enginerd 0:b562096246b3 125 currentHandle += 2;
enginerd 0:b562096246b3 126 currAtt->pUuid = attChUuid;
enginerd 0:b562096246b3 127
enginerd 0:b562096246b3 128 p_char->getValueAttribute().setHandle(currentHandle);
enginerd 0:b562096246b3 129 mxmSvc->chars[i].descLen = 1 + sizeof(currentHandle) + p_char->getValueAttribute().getUUID().getLen();
enginerd 0:b562096246b3 130 currAtt->pValue = (uint8_t*)malloc(mxmSvc->chars[i].descLen);
enginerd 0:b562096246b3 131 uint8_t *pValue = currAtt->pValue;
enginerd 0:b562096246b3 132 *pValue++ = p_char->getProperties();
enginerd 0:b562096246b3 133 memcpy(pValue, &currentHandle, sizeof(currentHandle));
enginerd 0:b562096246b3 134 pValue += sizeof(currentHandle);
enginerd 0:b562096246b3 135 memcpy(pValue, p_char->getValueAttribute().getUUID().getBaseUUID(), p_char->getValueAttribute().getUUID().getLen());
enginerd 0:b562096246b3 136
enginerd 0:b562096246b3 137 currAtt->pLen = &mxmSvc->chars[i].descLen;
enginerd 0:b562096246b3 138 currAtt->maxLen = mxmSvc->chars[i].descLen;
enginerd 0:b562096246b3 139 currAtt->settings = 0;
enginerd 0:b562096246b3 140 currAtt->permissions = ATTS_PERMIT_READ;
enginerd 0:b562096246b3 141 currAtt++;
enginerd 0:b562096246b3 142
enginerd 0:b562096246b3 143 // Create Value Attribute
enginerd 0:b562096246b3 144 currAtt->pUuid = p_char->getValueAttribute().getUUID().getBaseUUID();
enginerd 0:b562096246b3 145 currAtt->pValue = p_char->getValueAttribute().getValuePtr();
enginerd 0:b562096246b3 146 currAtt->pLen = p_char->getValueAttribute().getLengthPtr();
enginerd 0:b562096246b3 147 currAtt->maxLen = p_char->getValueAttribute().getMaxLength();
enginerd 0:b562096246b3 148 currAtt->settings = ATTS_SET_WRITE_CBACK | ATTS_SET_READ_CBACK;
enginerd 0:b562096246b3 149 if (p_char->getValueAttribute().getUUID().shortOrLong() == UUID::UUID_TYPE_LONG) {
enginerd 0:b562096246b3 150 currAtt->settings |= ATTS_SET_UUID_128;
enginerd 0:b562096246b3 151 }
enginerd 0:b562096246b3 152 currAtt->permissions = 0;
enginerd 0:b562096246b3 153 if (p_char->getProperties() & GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ) { currAtt->permissions |= ATTS_PERMIT_READ; }
enginerd 0:b562096246b3 154 if (p_char->getProperties() & GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE) { currAtt->permissions |= ATTS_PERMIT_WRITE; }
enginerd 0:b562096246b3 155 currAtt++;
enginerd 0:b562096246b3 156
enginerd 0:b562096246b3 157 bool cccCreated = false;
enginerd 0:b562096246b3 158
enginerd 0:b562096246b3 159 for (int i = 0; i < p_char->getDescriptorCount(); i++) {
enginerd 0:b562096246b3 160 GattAttribute *p_att = p_char->getDescriptor(i);
enginerd 0:b562096246b3 161
enginerd 0:b562096246b3 162 currentHandle++;
enginerd 0:b562096246b3 163
enginerd 0:b562096246b3 164 currAtt->pUuid = p_att->getUUID().getBaseUUID();
enginerd 0:b562096246b3 165 currAtt->pValue = p_att->getValuePtr();
enginerd 0:b562096246b3 166 currAtt->pLen = p_att->getLengthPtr();
enginerd 0:b562096246b3 167 currAtt->maxLen = p_att->getMaxLength();
enginerd 0:b562096246b3 168 currAtt->settings = 0;
enginerd 0:b562096246b3 169 currAtt->permissions = 0;
enginerd 0:b562096246b3 170 if (p_att->getUUID().shortOrLong() == UUID::UUID_TYPE_LONG) {
enginerd 0:b562096246b3 171 currAtt->settings |= ATTS_SET_UUID_128;
enginerd 0:b562096246b3 172 }
enginerd 0:b562096246b3 173 if (p_att->getUUID() == UUID(BLE_UUID_DESCRIPTOR_CLIENT_CHAR_CONFIG)) {
enginerd 0:b562096246b3 174 cccCreated = true;
enginerd 0:b562096246b3 175 currAtt->settings |= ATTS_SET_CCC;
enginerd 0:b562096246b3 176 currAtt->permissions |= ATTS_PERMIT_READ;
enginerd 0:b562096246b3 177 currAtt->permissions |= ATTS_PERMIT_WRITE;
enginerd 0:b562096246b3 178
enginerd 0:b562096246b3 179 if (cccCnt < MAX_CCC_CNT) {
enginerd 0:b562096246b3 180 cccSet[cccCnt].handle = currentHandle;
enginerd 0:b562096246b3 181 cccSet[cccCnt].valueRange = 0;
enginerd 0:b562096246b3 182 if (p_char->getProperties() & GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY) {
enginerd 0:b562096246b3 183 cccSet[cccCnt].valueRange |= ATT_CLIENT_CFG_NOTIFY;
enginerd 0:b562096246b3 184 }
enginerd 0:b562096246b3 185 if (p_char->getProperties() & GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_INDICATE) {
enginerd 0:b562096246b3 186 cccSet[cccCnt].valueRange |= ATT_CLIENT_CFG_INDICATE;
enginerd 0:b562096246b3 187 }
enginerd 0:b562096246b3 188 cccSet[cccCnt].secLevel = DM_SEC_LEVEL_NONE;
enginerd 0:b562096246b3 189 cccHandles[cccCnt] = p_char->getValueAttribute().getHandle();
enginerd 0:b562096246b3 190 cccCnt++;
enginerd 0:b562096246b3 191 } else {
enginerd 0:b562096246b3 192 return BLE_ERROR_PARAM_OUT_OF_RANGE;
enginerd 0:b562096246b3 193 }
enginerd 0:b562096246b3 194 }
enginerd 0:b562096246b3 195 currAtt++;
enginerd 0:b562096246b3 196 }
enginerd 0:b562096246b3 197
enginerd 0:b562096246b3 198 if (!cccCreated && (p_char->getProperties() & (GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_INDICATE))) {
enginerd 0:b562096246b3 199 /* There was not a CCCD included in the descriptors, but this
enginerd 0:b562096246b3 200 * characteristic is notifiable and/or indicatable. A CCCD is
enginerd 0:b562096246b3 201 * required so create one now.
enginerd 0:b562096246b3 202 */
enginerd 0:b562096246b3 203 if (cccCnt >= MAX_CCC_CNT) {
enginerd 0:b562096246b3 204 return BLE_ERROR_PARAM_OUT_OF_RANGE;
enginerd 0:b562096246b3 205 }
enginerd 0:b562096246b3 206
enginerd 0:b562096246b3 207 currentHandle++;
enginerd 0:b562096246b3 208
enginerd 0:b562096246b3 209 currAtt->pUuid = cccUUID.getBaseUUID();
enginerd 0:b562096246b3 210 currAtt->pValue = (uint8_t*)&cccValues[cccCnt];
enginerd 0:b562096246b3 211 currAtt->pLen = (uint16_t*)&cccSize;
enginerd 0:b562096246b3 212 currAtt->maxLen = sizeof(uint16_t);
enginerd 0:b562096246b3 213 currAtt->settings = ATTS_SET_CCC;
enginerd 0:b562096246b3 214 currAtt->permissions = (ATTS_PERMIT_READ | ATTS_PERMIT_WRITE);
enginerd 0:b562096246b3 215
enginerd 0:b562096246b3 216 cccSet[cccCnt].handle = currentHandle;
enginerd 0:b562096246b3 217 cccSet[cccCnt].valueRange = 0;
enginerd 0:b562096246b3 218 if (p_char->getProperties() & GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY) {
enginerd 0:b562096246b3 219 cccSet[cccCnt].valueRange |= ATT_CLIENT_CFG_NOTIFY;
enginerd 0:b562096246b3 220 }
enginerd 0:b562096246b3 221 if (p_char->getProperties() & GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_INDICATE) {
enginerd 0:b562096246b3 222 cccSet[cccCnt].valueRange |= ATT_CLIENT_CFG_INDICATE;
enginerd 0:b562096246b3 223 }
enginerd 0:b562096246b3 224 cccSet[cccCnt].secLevel = DM_SEC_LEVEL_NONE;
enginerd 0:b562096246b3 225 cccHandles[cccCnt] = p_char->getValueAttribute().getHandle();
enginerd 0:b562096246b3 226
enginerd 0:b562096246b3 227 cccCnt++;
enginerd 0:b562096246b3 228 currAtt++;
enginerd 0:b562096246b3 229 }
enginerd 0:b562096246b3 230 }
enginerd 0:b562096246b3 231
enginerd 0:b562096246b3 232 mxmSvc->attGroup->pNext = NULL;
enginerd 0:b562096246b3 233 mxmSvc->attGroup->readCback = attsReadCback;
enginerd 0:b562096246b3 234 mxmSvc->attGroup->writeCback = attsWriteCback;
enginerd 0:b562096246b3 235 mxmSvc->attGroup->startHandle = startHandle;
enginerd 0:b562096246b3 236 mxmSvc->attGroup->endHandle = currentHandle;
enginerd 0:b562096246b3 237 AttsAddGroup(mxmSvc->attGroup);
enginerd 0:b562096246b3 238
enginerd 0:b562096246b3 239 AttRegister(attCback);
enginerd 0:b562096246b3 240 AttsCccRegister(cccCnt, (attsCccSet_t*)cccSet, cccCback);
enginerd 0:b562096246b3 241
enginerd 0:b562096246b3 242 return BLE_ERROR_NONE;
enginerd 0:b562096246b3 243 }
enginerd 0:b562096246b3 244
enginerd 0:b562096246b3 245 ble_error_t MaximGattServer::read(GattAttribute::Handle_t attributeHandle, uint8_t buffer[], uint16_t *const lengthP)
enginerd 0:b562096246b3 246 {
enginerd 0:b562096246b3 247 if (AttsGetAttr(attributeHandle, lengthP, &buffer) != ATT_SUCCESS) {
enginerd 0:b562096246b3 248 return BLE_ERROR_PARAM_OUT_OF_RANGE;
enginerd 0:b562096246b3 249 }
enginerd 0:b562096246b3 250
enginerd 0:b562096246b3 251 return BLE_ERROR_NONE;
enginerd 0:b562096246b3 252 }
enginerd 0:b562096246b3 253
enginerd 0:b562096246b3 254 ble_error_t MaximGattServer::read(Gap::Handle_t connectionHandle, GattAttribute::Handle_t attributeHandle, uint8_t buffer[], uint16_t *lengthP)
enginerd 0:b562096246b3 255 {
enginerd 0:b562096246b3 256 // Check to see if this is a CCCD
enginerd 0:b562096246b3 257 uint8_t idx;
enginerd 0:b562096246b3 258 for (idx = 0; idx < cccCnt; idx++) {
enginerd 0:b562096246b3 259 if (attributeHandle == cccSet[idx].handle) {
enginerd 0:b562096246b3 260 if (connectionHandle == DM_CONN_ID_NONE) { // CCCDs are always 16 bits
enginerd 0:b562096246b3 261 return BLE_ERROR_PARAM_OUT_OF_RANGE;
enginerd 0:b562096246b3 262 }
enginerd 0:b562096246b3 263 *((uint16_t*)buffer) = AttsCccGet(connectionHandle, idx);
enginerd 0:b562096246b3 264 *lengthP = 2; // CCCDs are always 16 bits
enginerd 0:b562096246b3 265 return BLE_ERROR_NONE;
enginerd 0:b562096246b3 266 }
enginerd 0:b562096246b3 267 }
enginerd 0:b562096246b3 268
enginerd 0:b562096246b3 269 // This is not a CCCD. Use the non-connection specific update method.
enginerd 0:b562096246b3 270 return read(attributeHandle, buffer, lengthP);
enginerd 0:b562096246b3 271 }
enginerd 0:b562096246b3 272
enginerd 0:b562096246b3 273 ble_error_t MaximGattServer::write(GattAttribute::Handle_t attributeHandle, const uint8_t buffer[], uint16_t len, bool localOnly)
enginerd 0:b562096246b3 274 {
enginerd 0:b562096246b3 275 uint16_t connectionHandle = MaximGap::getInstance().getConnectionHandle();
enginerd 0:b562096246b3 276
enginerd 0:b562096246b3 277 if (AttsSetAttr(attributeHandle, len, (uint8_t*)buffer) != ATT_SUCCESS) {
enginerd 0:b562096246b3 278 return BLE_ERROR_PARAM_OUT_OF_RANGE;
enginerd 0:b562096246b3 279 }
enginerd 0:b562096246b3 280
enginerd 0:b562096246b3 281 if (!localOnly) {
enginerd 0:b562096246b3 282 if (connectionHandle != DM_CONN_ID_NONE) {
enginerd 0:b562096246b3 283
enginerd 0:b562096246b3 284 // Check to see if this characteristic has a CCCD attribute
enginerd 0:b562096246b3 285 uint8_t idx;
enginerd 0:b562096246b3 286 for (idx = 0; idx < cccCnt; idx++) {
enginerd 0:b562096246b3 287 if (attributeHandle == cccHandles[idx]) {
enginerd 0:b562096246b3 288 break;
enginerd 0:b562096246b3 289 }
enginerd 0:b562096246b3 290 }
enginerd 0:b562096246b3 291 if (idx < cccCnt) {
enginerd 0:b562096246b3 292 // This characteristic has a CCCD attribute. Handle notifications and indications.
enginerd 0:b562096246b3 293 uint16_t cccEnabled = AttsCccEnabled(connectionHandle, idx);
enginerd 0:b562096246b3 294 if (cccEnabled & ATT_CLIENT_CFG_NOTIFY) {
enginerd 0:b562096246b3 295 AttsHandleValueNtf(connectionHandle, attributeHandle, len, (uint8_t*)buffer);
enginerd 0:b562096246b3 296 }
enginerd 0:b562096246b3 297 if (cccEnabled & ATT_CLIENT_CFG_INDICATE) {
enginerd 0:b562096246b3 298 AttsHandleValueInd(connectionHandle, attributeHandle, len, (uint8_t*)buffer);
enginerd 0:b562096246b3 299 }
enginerd 0:b562096246b3 300 }
enginerd 0:b562096246b3 301 }
enginerd 0:b562096246b3 302 }
enginerd 0:b562096246b3 303
enginerd 0:b562096246b3 304 return BLE_ERROR_NONE;
enginerd 0:b562096246b3 305 }
enginerd 0:b562096246b3 306
enginerd 0:b562096246b3 307 ble_error_t MaximGattServer::write(Gap::Handle_t connectionHandle, GattAttribute::Handle_t attributeHandle, const uint8_t buffer[], uint16_t len, bool localOnly)
enginerd 0:b562096246b3 308 {
enginerd 0:b562096246b3 309 // Check to see if this is a CCCD
enginerd 0:b562096246b3 310 uint8_t idx;
enginerd 0:b562096246b3 311 for (idx = 0; idx < cccCnt; idx++) {
enginerd 0:b562096246b3 312 if (attributeHandle == cccSet[idx].handle) {
enginerd 0:b562096246b3 313 if ((connectionHandle == DM_CONN_ID_NONE) || (len != 2)) { // CCCDs are always 16 bits
enginerd 0:b562096246b3 314 return BLE_ERROR_PARAM_OUT_OF_RANGE;
enginerd 0:b562096246b3 315 }
enginerd 0:b562096246b3 316 AttsCccSet(connectionHandle, idx, *((uint16_t*)buffer));
enginerd 0:b562096246b3 317 return BLE_ERROR_NONE;
enginerd 0:b562096246b3 318 }
enginerd 0:b562096246b3 319 }
enginerd 0:b562096246b3 320
enginerd 0:b562096246b3 321 // This is not a CCCD. Use the non-connection specific update method.
enginerd 0:b562096246b3 322 return write(attributeHandle, buffer, len, localOnly);
enginerd 0:b562096246b3 323 }
enginerd 0:b562096246b3 324
enginerd 0:b562096246b3 325 ble_error_t MaximGattServer::areUpdatesEnabled(const GattCharacteristic &characteristic, bool *enabledP)
enginerd 0:b562096246b3 326 {
enginerd 0:b562096246b3 327 uint16_t connectionHandle = MaximGap::getInstance().getConnectionHandle();
enginerd 0:b562096246b3 328
enginerd 0:b562096246b3 329 if (connectionHandle != DM_CONN_ID_NONE) {
enginerd 0:b562096246b3 330 uint8_t idx;
enginerd 0:b562096246b3 331 for (idx = 0; idx < cccCnt; idx++) {
enginerd 0:b562096246b3 332 if (characteristic.getValueHandle() == cccHandles[idx]) {
enginerd 0:b562096246b3 333 uint16_t cccValue = AttsCccGet(connectionHandle, idx);
enginerd 0:b562096246b3 334 if (cccValue & ATT_CLIENT_CFG_NOTIFY) {
enginerd 0:b562096246b3 335 *enabledP = true;
enginerd 0:b562096246b3 336 } else {
enginerd 0:b562096246b3 337 *enabledP = false;
enginerd 0:b562096246b3 338 }
enginerd 0:b562096246b3 339 return BLE_ERROR_NONE;
enginerd 0:b562096246b3 340 }
enginerd 0:b562096246b3 341 }
enginerd 0:b562096246b3 342 }
enginerd 0:b562096246b3 343
enginerd 0:b562096246b3 344 return BLE_ERROR_PARAM_OUT_OF_RANGE;
enginerd 0:b562096246b3 345 }
enginerd 0:b562096246b3 346
enginerd 0:b562096246b3 347 ble_error_t MaximGattServer::areUpdatesEnabled(Gap::Handle_t connectionHandle, const GattCharacteristic &characteristic, bool *enabledP)
enginerd 0:b562096246b3 348 {
enginerd 0:b562096246b3 349 if (connectionHandle != DM_CONN_ID_NONE) {
enginerd 0:b562096246b3 350 uint8_t idx;
enginerd 0:b562096246b3 351 for (idx = 0; idx < cccCnt; idx++) {
enginerd 0:b562096246b3 352 if (characteristic.getValueHandle() == cccHandles[idx]) {
enginerd 0:b562096246b3 353 uint16_t cccValue = AttsCccGet(connectionHandle, idx);
enginerd 0:b562096246b3 354 if (cccValue & ATT_CLIENT_CFG_NOTIFY) {
enginerd 0:b562096246b3 355 *enabledP = true;
enginerd 0:b562096246b3 356 } else {
enginerd 0:b562096246b3 357 *enabledP = false;
enginerd 0:b562096246b3 358 }
enginerd 0:b562096246b3 359 return BLE_ERROR_NONE;
enginerd 0:b562096246b3 360 }
enginerd 0:b562096246b3 361 }
enginerd 0:b562096246b3 362 }
enginerd 0:b562096246b3 363
enginerd 0:b562096246b3 364 return BLE_ERROR_PARAM_OUT_OF_RANGE;
enginerd 0:b562096246b3 365 }
enginerd 0:b562096246b3 366
enginerd 0:b562096246b3 367 void MaximGattServer::cccCback(attsCccEvt_t *pEvt)
enginerd 0:b562096246b3 368 {
enginerd 0:b562096246b3 369 if (pEvt->value & (ATT_CLIENT_CFG_NOTIFY | ATT_CLIENT_CFG_INDICATE)) {
enginerd 0:b562096246b3 370 getInstance().handleEvent(GattServerEvents::GATT_EVENT_UPDATES_ENABLED, pEvt->handle);
enginerd 0:b562096246b3 371 } else {
enginerd 0:b562096246b3 372 getInstance().handleEvent(GattServerEvents::GATT_EVENT_UPDATES_DISABLED, pEvt->handle);
enginerd 0:b562096246b3 373 }
enginerd 0:b562096246b3 374 }
enginerd 0:b562096246b3 375
enginerd 0:b562096246b3 376 void MaximGattServer::attCback(attEvt_t *pEvt)
enginerd 0:b562096246b3 377 {
enginerd 0:b562096246b3 378 if (pEvt->hdr.status == ATT_SUCCESS) {
enginerd 0:b562096246b3 379 getInstance().handleEvent(GattServerEvents::GATT_EVENT_DATA_SENT, pEvt->handle);
enginerd 0:b562096246b3 380 }
enginerd 0:b562096246b3 381 }
enginerd 0:b562096246b3 382
enginerd 0:b562096246b3 383 uint8_t MaximGattServer::attsReadCback(dmConnId_t connId, uint16_t handle, uint8_t operation, uint16_t offset, attsAttr_t *pAttr)
enginerd 0:b562096246b3 384 {
enginerd 0:b562096246b3 385 GattReadCallbackParams cbParams = {
enginerd 0:b562096246b3 386 .connHandle = connId,
enginerd 0:b562096246b3 387 .handle = handle,
enginerd 0:b562096246b3 388 .offset = offset,
enginerd 0:b562096246b3 389 .len = *pAttr->pLen,
enginerd 0:b562096246b3 390 .data = pAttr->pValue
enginerd 0:b562096246b3 391 };
enginerd 0:b562096246b3 392 getInstance().handleDataReadEvent(&cbParams);
enginerd 0:b562096246b3 393
enginerd 0:b562096246b3 394 return ATT_SUCCESS;
enginerd 0:b562096246b3 395 }
enginerd 0:b562096246b3 396
enginerd 0:b562096246b3 397 uint8_t MaximGattServer::attsWriteCback(dmConnId_t connId, uint16_t handle, uint8_t operation, uint16_t offset, uint16_t len, uint8_t *pValue, attsAttr_t *pAttr)
enginerd 0:b562096246b3 398 {
enginerd 0:b562096246b3 399 uint8_t err;
enginerd 0:b562096246b3 400
enginerd 0:b562096246b3 401 /* TODO: offset is not handled properly */
enginerd 0:b562096246b3 402 if ((err = AttsSetAttr(handle, len, pValue)) != ATT_SUCCESS) {
enginerd 0:b562096246b3 403 return err;
enginerd 0:b562096246b3 404 }
enginerd 0:b562096246b3 405
enginerd 0:b562096246b3 406 GattWriteCallbackParams::WriteOp_t writeOp;
enginerd 0:b562096246b3 407 switch (operation) {
enginerd 0:b562096246b3 408 case ATT_PDU_WRITE_REQ:
enginerd 0:b562096246b3 409 writeOp = GattWriteCallbackParams::OP_WRITE_REQ;
enginerd 0:b562096246b3 410 break;
enginerd 0:b562096246b3 411 case ATT_PDU_WRITE_CMD:
enginerd 0:b562096246b3 412 writeOp = GattWriteCallbackParams::OP_WRITE_CMD;
enginerd 0:b562096246b3 413 break;
enginerd 0:b562096246b3 414 case ATT_PDU_SIGNED_WRITE_CMD:
enginerd 0:b562096246b3 415 writeOp = GattWriteCallbackParams::OP_SIGN_WRITE_CMD;
enginerd 0:b562096246b3 416 break;
enginerd 0:b562096246b3 417 case ATT_PDU_PREP_WRITE_REQ:
enginerd 0:b562096246b3 418 writeOp = GattWriteCallbackParams::OP_PREP_WRITE_REQ;
enginerd 0:b562096246b3 419 break;
enginerd 0:b562096246b3 420 case ATT_PDU_EXEC_WRITE_REQ:
enginerd 0:b562096246b3 421 writeOp = GattWriteCallbackParams::OP_EXEC_WRITE_REQ_NOW;
enginerd 0:b562096246b3 422 break;
enginerd 0:b562096246b3 423 default:
enginerd 0:b562096246b3 424 writeOp = GattWriteCallbackParams::OP_INVALID;
enginerd 0:b562096246b3 425 break;
enginerd 0:b562096246b3 426 }
enginerd 0:b562096246b3 427
enginerd 0:b562096246b3 428 GattWriteCallbackParams cbParams = {
enginerd 0:b562096246b3 429 .connHandle = connId,
enginerd 0:b562096246b3 430 .handle = handle,
enginerd 0:b562096246b3 431 .writeOp = writeOp,
enginerd 0:b562096246b3 432 .offset = offset,
enginerd 0:b562096246b3 433 .len = len,
enginerd 0:b562096246b3 434 .data = pValue
enginerd 0:b562096246b3 435 };
enginerd 0:b562096246b3 436 getInstance().handleDataWrittenEvent(&cbParams);
enginerd 0:b562096246b3 437
enginerd 0:b562096246b3 438 return ATT_SUCCESS;
enginerd 0:b562096246b3 439 }