Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependents: BLE_Thermometer MAXWSNENV_demo
MaximGattServer.cpp
00001 /******************************************************************************* 00002 * Copyright (C) 2016 Maxim Integrated Products, Inc., All Rights Reserved. 00003 * 00004 * Permission is hereby granted, free of charge, to any person obtaining a 00005 * copy of this software and associated documentation files (the "Software"), 00006 * to deal in the Software without restriction, including without limitation 00007 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 00008 * and/or sell copies of the Software, and to permit persons to whom the 00009 * Software is furnished to do so, subject to the following conditions: 00010 * 00011 * The above copyright notice and this permission notice shall be included 00012 * in all copies or substantial portions of the Software. 00013 * 00014 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 00015 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 00016 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 00017 * IN NO EVENT SHALL MAXIM INTEGRATED BE LIABLE FOR ANY CLAIM, DAMAGES 00018 * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 00019 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 00020 * OTHER DEALINGS IN THE SOFTWARE. 00021 * 00022 * Except as contained in this notice, the name of Maxim Integrated 00023 * Products, Inc. shall not be used except as stated in the Maxim Integrated 00024 * Products, Inc. Branding Policy. 00025 * 00026 * The mere transfer of this software does not imply any licenses 00027 * of trade secrets, proprietary technology, copyrights, patents, 00028 * trademarks, maskwork rights, or any other form of intellectual 00029 * property whatsoever. Maxim Integrated Products, Inc. retains all 00030 * ownership rights. 00031 ******************************************************************************* 00032 */ 00033 00034 #include "MaximGattServer.h" 00035 #include "mbed.h" 00036 #include "MaximGap.h" 00037 #include "wsf_types.h" 00038 #include "att_api.h" 00039 00040 typedef struct mxmChar_s { 00041 uint16_t descLen; 00042 mxmChar_s() {} 00043 } mxmChar_t; 00044 00045 typedef struct mxmService_s mxmService_t; 00046 struct mxmService_s { 00047 uint16_t uuidLen; 00048 mxmChar_t *chars; 00049 attsGroup_t *attGroup; 00050 mxmService_t *next; 00051 mxmService_s() {} 00052 }; 00053 00054 static uint16_t currentHandle = 0x20; 00055 00056 static UUID cccUUID(BLE_UUID_DESCRIPTOR_CLIENT_CHAR_CONFIG); 00057 static const uint16_t cccSize = sizeof(uint16_t); 00058 00059 MaximGattServer &MaximGattServer::getInstance() { 00060 static MaximGattServer m_instance; 00061 return m_instance; 00062 } 00063 00064 ble_error_t MaximGattServer::addService(GattService &service) 00065 { 00066 currentHandle = (currentHandle + 0xF) & ~0xF; 00067 uint16_t startHandle = currentHandle; 00068 00069 mxmService_t *mxmSvc = new mxmService_t; 00070 00071 // Create WiCentric attribute group 00072 mxmSvc->attGroup = new attsGroup_t ; 00073 00074 // Determine the attribute list length 00075 unsigned int attListLen = 1; 00076 for (int i = 0; i < service.getCharacteristicCount(); i++) { 00077 attListLen += 2; 00078 GattCharacteristic *p_char = service.getCharacteristic(i); 00079 00080 if (p_char->getProperties() & (GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_INDICATE)) { 00081 // add a CCCD 00082 attListLen++; 00083 } 00084 } 00085 00086 // Create WiCentric attribute list 00087 mxmSvc->attGroup->pAttr = (attsAttr_t *)malloc(attListLen * sizeof(attsAttr_t ));; 00088 if (mxmSvc->attGroup->pAttr == NULL) { 00089 return BLE_ERROR_BUFFER_OVERFLOW; 00090 } 00091 00092 // Create characteristics 00093 mxmSvc->chars = new mxmChar_t [service.getCharacteristicCount()]; 00094 00095 attsAttr_t *currAtt = mxmSvc->attGroup->pAttr; 00096 00097 /* Service */ 00098 currAtt->pUuid = attPrimSvcUuid ; 00099 if (service.getUUID().shortOrLong() == UUID::UUID_TYPE_LONG) { 00100 mxmSvc->uuidLen = UUID::LENGTH_OF_LONG_UUID; 00101 } else { 00102 mxmSvc->uuidLen = sizeof(UUID::ShortUUIDBytes_t); 00103 } 00104 currAtt->pValue = (uint8_t*)malloc(mxmSvc->uuidLen); 00105 memcpy(currAtt->pValue , service.getUUID().getBaseUUID(), mxmSvc->uuidLen); 00106 currAtt->maxLen = mxmSvc->uuidLen; 00107 currAtt->pLen = &mxmSvc->uuidLen; 00108 currAtt->settings = 0; 00109 currAtt->permissions = ATTS_PERMIT_READ; 00110 00111 currAtt++; 00112 00113 /* Add characteristics to the service */ 00114 for (int i = 0; i < service.getCharacteristicCount(); i++) { 00115 GattCharacteristic *p_char = service.getCharacteristic(i); 00116 00117 /* Skip any incompletely defined, read-only characteristics. */ 00118 if ((p_char->getValueAttribute().getValuePtr() == NULL) && 00119 (p_char->getValueAttribute().getLength() == 0) && 00120 (p_char->getProperties() == GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ)) { 00121 continue; 00122 } 00123 00124 // Create Characteristic Attribute 00125 currentHandle += 2; 00126 currAtt->pUuid = attChUuid ; 00127 00128 p_char->getValueAttribute().setHandle(currentHandle); 00129 mxmSvc->chars[i].descLen = 1 + sizeof(currentHandle) + p_char->getValueAttribute().getUUID().getLen(); 00130 currAtt->pValue = (uint8_t*)malloc(mxmSvc->chars[i].descLen); 00131 uint8_t *pValue = currAtt->pValue ; 00132 *pValue++ = p_char->getProperties(); 00133 memcpy(pValue, ¤tHandle, sizeof(currentHandle)); 00134 pValue += sizeof(currentHandle); 00135 memcpy(pValue, p_char->getValueAttribute().getUUID().getBaseUUID(), p_char->getValueAttribute().getUUID().getLen()); 00136 00137 currAtt->pLen = &mxmSvc->chars[i].descLen; 00138 currAtt->maxLen = mxmSvc->chars[i].descLen; 00139 currAtt->settings = 0; 00140 currAtt->permissions = ATTS_PERMIT_READ; 00141 currAtt++; 00142 00143 // Create Value Attribute 00144 currAtt->pUuid = p_char->getValueAttribute().getUUID().getBaseUUID(); 00145 currAtt->pValue = p_char->getValueAttribute().getValuePtr(); 00146 currAtt->pLen = p_char->getValueAttribute().getLengthPtr(); 00147 currAtt->maxLen = p_char->getValueAttribute().getMaxLength(); 00148 currAtt->settings = ATTS_SET_WRITE_CBACK | ATTS_SET_READ_CBACK; 00149 if (p_char->getValueAttribute().getUUID().shortOrLong() == UUID::UUID_TYPE_LONG) { 00150 currAtt->settings |= ATTS_SET_UUID_128; 00151 } 00152 currAtt->permissions = 0; 00153 if (p_char->getProperties() & GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ) { currAtt->permissions |= ATTS_PERMIT_READ; } 00154 if (p_char->getProperties() & GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE) { currAtt->permissions |= ATTS_PERMIT_WRITE; } 00155 currAtt++; 00156 00157 bool cccCreated = false; 00158 00159 for (int i = 0; i < p_char->getDescriptorCount(); i++) { 00160 GattAttribute *p_att = p_char->getDescriptor(i); 00161 00162 currentHandle++; 00163 00164 currAtt->pUuid = p_att->getUUID().getBaseUUID(); 00165 currAtt->pValue = p_att->getValuePtr(); 00166 currAtt->pLen = p_att->getLengthPtr(); 00167 currAtt->maxLen = p_att->getMaxLength(); 00168 currAtt->settings = 0; 00169 currAtt->permissions = 0; 00170 if (p_att->getUUID().shortOrLong() == UUID::UUID_TYPE_LONG) { 00171 currAtt->settings |= ATTS_SET_UUID_128; 00172 } 00173 if (p_att->getUUID() == UUID(BLE_UUID_DESCRIPTOR_CLIENT_CHAR_CONFIG)) { 00174 cccCreated = true; 00175 currAtt->settings |= ATTS_SET_CCC; 00176 currAtt->permissions |= ATTS_PERMIT_READ; 00177 currAtt->permissions |= ATTS_PERMIT_WRITE; 00178 00179 if (cccCnt < MAX_CCC_CNT) { 00180 cccSet[cccCnt].handle = currentHandle; 00181 cccSet[cccCnt].valueRange = 0; 00182 if (p_char->getProperties() & GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY) { 00183 cccSet[cccCnt].valueRange |= ATT_CLIENT_CFG_NOTIFY; 00184 } 00185 if (p_char->getProperties() & GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_INDICATE) { 00186 cccSet[cccCnt].valueRange |= ATT_CLIENT_CFG_INDICATE; 00187 } 00188 cccSet[cccCnt].secLevel = DM_SEC_LEVEL_NONE; 00189 cccHandles[cccCnt] = p_char->getValueAttribute().getHandle(); 00190 cccCnt++; 00191 } else { 00192 return BLE_ERROR_PARAM_OUT_OF_RANGE; 00193 } 00194 } 00195 currAtt++; 00196 } 00197 00198 if (!cccCreated && (p_char->getProperties() & (GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_INDICATE))) { 00199 /* There was not a CCCD included in the descriptors, but this 00200 * characteristic is notifiable and/or indicatable. A CCCD is 00201 * required so create one now. 00202 */ 00203 if (cccCnt >= MAX_CCC_CNT) { 00204 return BLE_ERROR_PARAM_OUT_OF_RANGE; 00205 } 00206 00207 currentHandle++; 00208 00209 currAtt->pUuid = cccUUID.getBaseUUID(); 00210 currAtt->pValue = (uint8_t*)&cccValues[cccCnt]; 00211 currAtt->pLen = (uint16_t*)&cccSize; 00212 currAtt->maxLen = sizeof(uint16_t); 00213 currAtt->settings = ATTS_SET_CCC; 00214 currAtt->permissions = (ATTS_PERMIT_READ | ATTS_PERMIT_WRITE); 00215 00216 cccSet[cccCnt].handle = currentHandle; 00217 cccSet[cccCnt].valueRange = 0; 00218 if (p_char->getProperties() & GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY) { 00219 cccSet[cccCnt].valueRange |= ATT_CLIENT_CFG_NOTIFY; 00220 } 00221 if (p_char->getProperties() & GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_INDICATE) { 00222 cccSet[cccCnt].valueRange |= ATT_CLIENT_CFG_INDICATE; 00223 } 00224 cccSet[cccCnt].secLevel = DM_SEC_LEVEL_NONE; 00225 cccHandles[cccCnt] = p_char->getValueAttribute().getHandle(); 00226 00227 cccCnt++; 00228 currAtt++; 00229 } 00230 } 00231 00232 mxmSvc->attGroup->pNext = NULL; 00233 mxmSvc->attGroup->readCback = attsReadCback; 00234 mxmSvc->attGroup->writeCback = attsWriteCback; 00235 mxmSvc->attGroup->startHandle = startHandle; 00236 mxmSvc->attGroup->endHandle = currentHandle; 00237 AttsAddGroup(mxmSvc->attGroup); 00238 00239 AttRegister(attCback); 00240 AttsCccRegister(cccCnt, (attsCccSet_t *)cccSet, cccCback); 00241 00242 return BLE_ERROR_NONE; 00243 } 00244 00245 ble_error_t MaximGattServer::read(GattAttribute::Handle_t attributeHandle, uint8_t buffer[], uint16_t *const lengthP) 00246 { 00247 if (AttsGetAttr(attributeHandle, lengthP, &buffer) != ATT_SUCCESS) { 00248 return BLE_ERROR_PARAM_OUT_OF_RANGE; 00249 } 00250 00251 return BLE_ERROR_NONE; 00252 } 00253 00254 ble_error_t MaximGattServer::read(Gap::Handle_t connectionHandle, GattAttribute::Handle_t attributeHandle, uint8_t buffer[], uint16_t *lengthP) 00255 { 00256 // Check to see if this is a CCCD 00257 uint8_t idx; 00258 for (idx = 0; idx < cccCnt; idx++) { 00259 if (attributeHandle == cccSet[idx].handle) { 00260 if (connectionHandle == DM_CONN_ID_NONE) { // CCCDs are always 16 bits 00261 return BLE_ERROR_PARAM_OUT_OF_RANGE; 00262 } 00263 *((uint16_t*)buffer) = AttsCccGet(connectionHandle, idx); 00264 *lengthP = 2; // CCCDs are always 16 bits 00265 return BLE_ERROR_NONE; 00266 } 00267 } 00268 00269 // This is not a CCCD. Use the non-connection specific update method. 00270 return read(attributeHandle, buffer, lengthP); 00271 } 00272 00273 ble_error_t MaximGattServer::write(GattAttribute::Handle_t attributeHandle, const uint8_t buffer[], uint16_t len, bool localOnly) 00274 { 00275 uint16_t connectionHandle = MaximGap::getInstance().getConnectionHandle(); 00276 00277 if (AttsSetAttr(attributeHandle, len, (uint8_t*)buffer) != ATT_SUCCESS) { 00278 return BLE_ERROR_PARAM_OUT_OF_RANGE; 00279 } 00280 00281 if (!localOnly) { 00282 if (connectionHandle != DM_CONN_ID_NONE) { 00283 00284 // Check to see if this characteristic has a CCCD attribute 00285 uint8_t idx; 00286 for (idx = 0; idx < cccCnt; idx++) { 00287 if (attributeHandle == cccHandles[idx]) { 00288 break; 00289 } 00290 } 00291 if (idx < cccCnt) { 00292 // This characteristic has a CCCD attribute. Handle notifications and indications. 00293 uint16_t cccEnabled = AttsCccEnabled(connectionHandle, idx); 00294 if (cccEnabled & ATT_CLIENT_CFG_NOTIFY) { 00295 AttsHandleValueNtf(connectionHandle, attributeHandle, len, (uint8_t*)buffer); 00296 } 00297 if (cccEnabled & ATT_CLIENT_CFG_INDICATE) { 00298 AttsHandleValueInd(connectionHandle, attributeHandle, len, (uint8_t*)buffer); 00299 } 00300 } 00301 } 00302 } 00303 00304 return BLE_ERROR_NONE; 00305 } 00306 00307 ble_error_t MaximGattServer::write(Gap::Handle_t connectionHandle, GattAttribute::Handle_t attributeHandle, const uint8_t buffer[], uint16_t len, bool localOnly) 00308 { 00309 // Check to see if this is a CCCD 00310 uint8_t idx; 00311 for (idx = 0; idx < cccCnt; idx++) { 00312 if (attributeHandle == cccSet[idx].handle) { 00313 if ((connectionHandle == DM_CONN_ID_NONE) || (len != 2)) { // CCCDs are always 16 bits 00314 return BLE_ERROR_PARAM_OUT_OF_RANGE; 00315 } 00316 AttsCccSet(connectionHandle, idx, *((uint16_t*)buffer)); 00317 return BLE_ERROR_NONE; 00318 } 00319 } 00320 00321 // This is not a CCCD. Use the non-connection specific update method. 00322 return write(attributeHandle, buffer, len, localOnly); 00323 } 00324 00325 ble_error_t MaximGattServer::areUpdatesEnabled(const GattCharacteristic &characteristic, bool *enabledP) 00326 { 00327 uint16_t connectionHandle = MaximGap::getInstance().getConnectionHandle(); 00328 00329 if (connectionHandle != DM_CONN_ID_NONE) { 00330 uint8_t idx; 00331 for (idx = 0; idx < cccCnt; idx++) { 00332 if (characteristic.getValueHandle() == cccHandles[idx]) { 00333 uint16_t cccValue = AttsCccGet(connectionHandle, idx); 00334 if (cccValue & ATT_CLIENT_CFG_NOTIFY) { 00335 *enabledP = true; 00336 } else { 00337 *enabledP = false; 00338 } 00339 return BLE_ERROR_NONE; 00340 } 00341 } 00342 } 00343 00344 return BLE_ERROR_PARAM_OUT_OF_RANGE; 00345 } 00346 00347 ble_error_t MaximGattServer::areUpdatesEnabled(Gap::Handle_t connectionHandle, const GattCharacteristic &characteristic, bool *enabledP) 00348 { 00349 if (connectionHandle != DM_CONN_ID_NONE) { 00350 uint8_t idx; 00351 for (idx = 0; idx < cccCnt; idx++) { 00352 if (characteristic.getValueHandle() == cccHandles[idx]) { 00353 uint16_t cccValue = AttsCccGet(connectionHandle, idx); 00354 if (cccValue & ATT_CLIENT_CFG_NOTIFY) { 00355 *enabledP = true; 00356 } else { 00357 *enabledP = false; 00358 } 00359 return BLE_ERROR_NONE; 00360 } 00361 } 00362 } 00363 00364 return BLE_ERROR_PARAM_OUT_OF_RANGE; 00365 } 00366 00367 void MaximGattServer::cccCback(attsCccEvt_t *pEvt) 00368 { 00369 if (pEvt->value & (ATT_CLIENT_CFG_NOTIFY | ATT_CLIENT_CFG_INDICATE)) { 00370 getInstance().handleEvent(GattServerEvents::GATT_EVENT_UPDATES_ENABLED, pEvt->handle ); 00371 } else { 00372 getInstance().handleEvent(GattServerEvents::GATT_EVENT_UPDATES_DISABLED, pEvt->handle ); 00373 } 00374 } 00375 00376 void MaximGattServer::attCback(attEvt_t *pEvt) 00377 { 00378 if (pEvt->hdr.status == ATT_SUCCESS) { 00379 getInstance().handleEvent(GattServerEvents::GATT_EVENT_DATA_SENT, pEvt->handle ); 00380 } 00381 } 00382 00383 uint8_t MaximGattServer::attsReadCback(dmConnId_t connId, uint16_t handle, uint8_t operation, uint16_t offset, attsAttr_t *pAttr) 00384 { 00385 GattReadCallbackParams cbParams = { 00386 .connHandle = connId, 00387 .handle = handle, 00388 .offset = offset, 00389 .len = *pAttr->pLen , 00390 .data = pAttr->pValue 00391 }; 00392 getInstance().handleDataReadEvent(&cbParams); 00393 00394 return ATT_SUCCESS; 00395 } 00396 00397 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) 00398 { 00399 uint8_t err; 00400 00401 /* TODO: offset is not handled properly */ 00402 if ((err = AttsSetAttr(handle, len, pValue)) != ATT_SUCCESS) { 00403 return err; 00404 } 00405 00406 GattWriteCallbackParams::WriteOp_t writeOp; 00407 switch (operation) { 00408 case ATT_PDU_WRITE_REQ: 00409 writeOp = GattWriteCallbackParams::OP_WRITE_REQ; 00410 break; 00411 case ATT_PDU_WRITE_CMD: 00412 writeOp = GattWriteCallbackParams::OP_WRITE_CMD; 00413 break; 00414 case ATT_PDU_SIGNED_WRITE_CMD: 00415 writeOp = GattWriteCallbackParams::OP_SIGN_WRITE_CMD; 00416 break; 00417 case ATT_PDU_PREP_WRITE_REQ: 00418 writeOp = GattWriteCallbackParams::OP_PREP_WRITE_REQ; 00419 break; 00420 case ATT_PDU_EXEC_WRITE_REQ: 00421 writeOp = GattWriteCallbackParams::OP_EXEC_WRITE_REQ_NOW; 00422 break; 00423 default: 00424 writeOp = GattWriteCallbackParams::OP_INVALID; 00425 break; 00426 } 00427 00428 GattWriteCallbackParams cbParams = { 00429 .connHandle = connId, 00430 .handle = handle, 00431 .writeOp = writeOp, 00432 .offset = offset, 00433 .len = len, 00434 .data = pValue 00435 }; 00436 getInstance().handleDataWrittenEvent(&cbParams); 00437 00438 return ATT_SUCCESS; 00439 }
Generated on Tue Jul 12 2022 19:59:22 by
1.7.2