This thread has been locked.
If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.
sorry for this noob question
I've already create custom service by hand working great with 16bit UUID
now I'm trying to use service generator https://dev.ti.com/tirex/explore/content/simplelink_academy_cc13x2_26x2sdk_5_10_00_00/modules/ble5stack/ble_01_custom_profile/ble_01_custom_profile.html#example-service-generator to create a service compliant with nordic semiconductor Uart service (NUS) https://infocenter.nordicsemi.com/index.jsp?topic=%2Fcom.nordic.infocenter.sdk5.v14.0.0%2Fble_sdk_app_nus_eval.html
looks not so hard but UUID are more than 16 bits (and more than 128 too)
NUS UUID : 6E400001-B5A3-F393-E0A9-E50E24DCCA9E (16-bit offset: 0x0001).
Nordic’s UART Service includes the following characteristics:
Name |
Mandatory |
UUID |
Type |
R |
W |
N |
I |
RX Characteristic UUID: 6E400002-B5A3-F393-E0A9-E50E24DCCA9E (16-bit offset: 0x0002).
TX Characteristic UUID: 6E400003-B5A3-F393-E0A9-E50E24DCCA9E (16-bit offset: 0x0003).
if I keep only 16bit offsetted uuid my NUS_SERV_UUID (0x0001) is in conflicting with PZ_SERVICE_CFG_EVT in ProjectZero_processApplicationMessage
NUS_service.h
/********************************************************************************************** * Filename: NUS.h * * Description: This file contains the NUS service definitions and * prototypes. * * Copyright (c) 2015-2019, Texas Instruments Incorporated * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * * Neither the name of Texas Instruments Incorporated nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * *************************************************************************************************/ #ifndef _NUS_H_ #define _NUS_H_ #ifdef __cplusplus extern "C" { #endif /********************************************************************* * INCLUDES */ /********************************************************************* * CONSTANTS */ // Service UUID #define NUS_SERV_UUID 0x0001 // Characteristic defines #define NUS_RX_ID 0 #define NUS_RX_UUID 0x0002 #define NUS_RX_LEN 20 // Characteristic defines #define NUS_TX_ID 1 #define NUS_TX_UUID 0x0003 #define NUS_TX_LEN 20 /********************************************************************* * TYPEDEFS */ /********************************************************************* * MACROS */ /********************************************************************* * Profile Callbacks */ // Callback when a characteristic value has changed typedef void (*NUSChange_t)(uint16_t connHandle, uint8_t paramID, uint16_t len, uint8_t *pValue); typedef struct { NUSChange_t pfnChangeCb; // Called when characteristic value changes NUSChange_t pfnCfgChangeCb; } NUSCBs_t; /********************************************************************* * API FUNCTIONS */ /* * NUS_AddService- Initializes the NUS service by registering * GATT attributes with the GATT server. * */ extern bStatus_t NUS_AddService( uint8_t rspTaskId); /* * NUS_RegisterAppCBs - Registers the application callback function. * Only call this function once. * * appCallbacks - pointer to application callbacks. */ extern bStatus_t NUS_RegisterAppCBs( NUSCBs_t *appCallbacks ); /* * NUS_SetParameter - Set a NUS parameter. * * param - Profile parameter ID * len - length of data to right * value - pointer to data to write. This is dependent on * the parameter ID and WILL be cast to the appropriate * data type (example: data type of uint16 will be cast to * uint16 pointer). */ extern bStatus_t NUS_SetParameter(uint8_t param, uint16_t len, void *value); /* * NUS_GetParameter - Get a NUS parameter. * * param - Profile parameter ID * value - pointer to data to write. This is dependent on * the parameter ID and WILL be cast to the appropriate * data type (example: data type of uint16 will be cast to * uint16 pointer). */ extern bStatus_t NUS_GetParameter(uint8_t param, uint16_t *len, void *value); /********************************************************************* *********************************************************************/ #ifdef __cplusplus } #endif #endif /* _NUS_H_ */
NUS_service.c
/********************************************************************************************** * Filename: NUS.c * * Description: This file contains the implementation of the service. * * Copyright (c) 2015-2019, Texas Instruments Incorporated * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * * Neither the name of Texas Instruments Incorporated nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * *************************************************************************************************/ /********************************************************************* * INCLUDES */ #include <string.h> #include <icall.h> /* This Header file contains all BLE API and icall structure definition */ #include "icall_ble_api.h" #include "NUS.h" /********************************************************************* * MACROS */ /********************************************************************* * CONSTANTS */ /********************************************************************* * TYPEDEFS */ /********************************************************************* * GLOBAL VARIABLES */ // NUS Service UUID CONST uint8_t NUSUUID[ATT_BT_UUID_SIZE] = { LO_UINT16(NUS_SERV_UUID), HI_UINT16(NUS_SERV_UUID) }; // RX UUID CONST uint8_t NUS_RXUUID[ATT_BT_UUID_SIZE] = { LO_UINT16(NUS_RX_UUID), HI_UINT16(NUS_RX_UUID) }; // TX UUID CONST uint8_t NUS_TXUUID[ATT_BT_UUID_SIZE] = { LO_UINT16(NUS_TX_UUID), HI_UINT16(NUS_TX_UUID) }; /********************************************************************* * LOCAL VARIABLES */ static NUSCBs_t *pAppCBs = NULL; /********************************************************************* * Profile Attributes - variables */ // Service declaration static CONST gattAttrType_t NUSDecl = { ATT_BT_UUID_SIZE, NUSUUID }; // Characteristic "RX" Properties (for declaration) static uint8_t NUS_RXProps = GATT_PROP_READ | GATT_PROP_NOTIFY; // Characteristic "RX" Value variable static uint8_t NUS_RXVal[NUS_RX_LEN] = {0}; // Characteristic "RX" CCCD static gattCharCfg_t *NUS_RXConfig; // Characteristic "TX" Properties (for declaration) static uint8_t NUS_TXProps = GATT_PROP_WRITE; // Characteristic "TX" Value variable static uint8_t NUS_TXVal[NUS_TX_LEN] = {0}; /********************************************************************* * Profile Attributes - Table */ static gattAttribute_t NUSAttrTbl[] = { // NUS Service Declaration { { ATT_BT_UUID_SIZE, primaryServiceUUID }, GATT_PERMIT_READ, 0, (uint8_t *)&NUSDecl }, // RX Characteristic Declaration { { ATT_BT_UUID_SIZE, characterUUID }, GATT_PERMIT_READ, 0, &NUS_RXProps }, // RX Characteristic Value { { ATT_BT_UUID_SIZE, NUS_RXUUID }, GATT_PERMIT_READ, 0, NUS_RXVal }, // RX CCCD { { ATT_BT_UUID_SIZE, clientCharCfgUUID }, GATT_PERMIT_READ | GATT_PERMIT_WRITE, 0, (uint8 *)&NUS_RXConfig }, // TX Characteristic Declaration { { ATT_BT_UUID_SIZE, characterUUID }, GATT_PERMIT_READ, 0, &NUS_TXProps }, // TX Characteristic Value { { ATT_BT_UUID_SIZE, NUS_TXUUID }, GATT_PERMIT_WRITE, 0, NUS_TXVal }, }; /********************************************************************* * LOCAL FUNCTIONS */ static bStatus_t NUS_ReadAttrCB( uint16_t connHandle, gattAttribute_t *pAttr, uint8_t *pValue, uint16_t *pLen, uint16_t offset, uint16_t maxLen, uint8_t method ); static bStatus_t NUS_WriteAttrCB( uint16_t connHandle, gattAttribute_t *pAttr, uint8_t *pValue, uint16_t len, uint16_t offset, uint8_t method ); /********************************************************************* * PROFILE CALLBACKS */ // Simple Profile Service Callbacks CONST gattServiceCBs_t NUSCBs = { NUS_ReadAttrCB, // Read callback function pointer NUS_WriteAttrCB, // Write callback function pointer NULL // Authorization callback function pointer }; /********************************************************************* * PUBLIC FUNCTIONS */ /* * NUS_AddService- Initializes the NUS service by registering * GATT attributes with the GATT server. * */ extern bStatus_t NUS_AddService( uint8_t rspTaskId ) { uint8_t status; // Allocate Client Characteristic Configuration table NUS_RXConfig = (gattCharCfg_t *)ICall_malloc( sizeof(gattCharCfg_t) * linkDBNumConns ); if ( NUS_RXConfig == NULL ) { return ( bleMemAllocError ); } // Initialize Client Characteristic Configuration attributes GATTServApp_InitCharCfg( LINKDB_CONNHANDLE_INVALID, NUS_RXConfig ); // Register GATT attribute list and CBs with GATT Server App status = GATTServApp_RegisterService( NUSAttrTbl, GATT_NUM_ATTRS( NUSAttrTbl ), GATT_MAX_ENCRYPT_KEY_SIZE, &NUSCBs ); return ( status ); } /* * NUS_RegisterAppCBs - Registers the application callback function. * Only call this function once. * * appCallbacks - pointer to application callbacks. */ bStatus_t NUS_RegisterAppCBs( NUSCBs_t *appCallbacks ) { if ( appCallbacks ) { pAppCBs = appCallbacks; return ( SUCCESS ); } else { return ( bleAlreadyInRequestedMode ); } } /* * NUS_SetParameter - Set a NUS parameter. * * param - Profile parameter ID * len - length of data to right * value - pointer to data to write. This is dependent on * the parameter ID and WILL be cast to the appropriate * data type (example: data type of uint16 will be cast to * uint16 pointer). */ bStatus_t NUS_SetParameter( uint8_t param, uint16_t len, void *value ) { bStatus_t ret = SUCCESS; switch ( param ) { case NUS_RX_ID: if ( len == NUS_RX_LEN ) { memcpy(NUS_RXVal, value, len); // Try to send notification. GATTServApp_ProcessCharCfg( NUS_RXConfig, (uint8_t *)&NUS_RXVal, FALSE, NUSAttrTbl, GATT_NUM_ATTRS( NUSAttrTbl ), INVALID_TASK_ID, NUS_ReadAttrCB); } else { ret = bleInvalidRange; } break; default: ret = INVALIDPARAMETER; break; } return ret; } /* * NUS_GetParameter - Get a NUS parameter. * * param - Profile parameter ID * value - pointer to data to write. This is dependent on * the parameter ID and WILL be cast to the appropriate * data type (example: data type of uint16 will be cast to * uint16 pointer). */ bStatus_t NUS_GetParameter( uint8_t param, uint16_t *len, void *value ) { bStatus_t ret = SUCCESS; switch ( param ) { case NUS_TX_ID: memcpy(value, NUS_TXVal, NUS_TX_LEN); break; default: ret = INVALIDPARAMETER; break; } return ret; } /********************************************************************* * @fn NUS_ReadAttrCB * * @brief Read an attribute. * * @param connHandle - connection message was received on * @param pAttr - pointer to attribute * @param pValue - pointer to data to be read * @param pLen - length of data to be read * @param offset - offset of the first octet to be read * @param maxLen - maximum length of data to be read * @param method - type of read message * * @return SUCCESS, blePending or Failure */ static bStatus_t NUS_ReadAttrCB( uint16_t connHandle, gattAttribute_t *pAttr, uint8_t *pValue, uint16_t *pLen, uint16_t offset, uint16_t maxLen, uint8_t method ) { bStatus_t status = SUCCESS; // See if request is regarding the RX Characteristic Value if ( ! memcmp(pAttr->type.uuid, NUS_RXUUID, pAttr->type.len) ) { if ( offset > NUS_RX_LEN ) // Prevent malicious ATT ReadBlob offsets. { status = ATT_ERR_INVALID_OFFSET; } else { *pLen = MIN(maxLen, NUS_RX_LEN - offset); // Transmit as much as possible memcpy(pValue, pAttr->pValue + offset, *pLen); } } else { // If we get here, that means you've forgotten to add an if clause for a // characteristic value attribute in the attribute table that has READ permissions. *pLen = 0; status = ATT_ERR_ATTR_NOT_FOUND; } return status; } /********************************************************************* * @fn NUS_WriteAttrCB * * @brief Validate attribute data prior to a write operation * * @param connHandle - connection message was received on * @param pAttr - pointer to attribute * @param pValue - pointer to data to be written * @param len - length of data * @param offset - offset of the first octet to be written * @param method - type of write message * * @return SUCCESS, blePending or Failure */ static bStatus_t NUS_WriteAttrCB( uint16_t connHandle, gattAttribute_t *pAttr, uint8_t *pValue, uint16_t len, uint16_t offset, uint8_t method ) { bStatus_t status = SUCCESS; uint8_t paramID = 0xFF; // See if request is regarding a Client Characterisic Configuration if ( ! memcmp(pAttr->type.uuid, clientCharCfgUUID, pAttr->type.len) ) { // Allow only notifications. status = GATTServApp_ProcessCCCWriteReq( connHandle, pAttr, pValue, len, offset, GATT_CLIENT_CFG_NOTIFY); } // See if request is regarding the TX Characteristic Value else if ( ! memcmp(pAttr->type.uuid, NUS_TXUUID, pAttr->type.len) ) { if ( offset + len > NUS_TX_LEN ) { status = ATT_ERR_INVALID_OFFSET; } else { // Copy pValue into the variable we point to from the attribute table. memcpy(pAttr->pValue + offset, pValue, len); // Only notify application if entire expected value is written if ( offset + len == NUS_TX_LEN) paramID = NUS_TX_ID; } } else { // If we get here, that means you've forgotten to add an if clause for a // characteristic value attribute in the attribute table that has WRITE permissions. status = ATT_ERR_ATTR_NOT_FOUND; } // Let the application know something changed (if it did) by using the // callback it registered earlier (if it did). if (paramID != 0xFF) if ( pAppCBs && pAppCBs->pfnChangeCb ) pAppCBs->pfnChangeCb(connHandle, paramID, len, pValue); // Call app function from stack task context. return status; }
Hello,
The example service generator in the linked SimpleLink Academy module has support to generate 128-bit UUIDs. I don't believe additional modifications are required to support this so you can use the templates provided by the service generator.
ok but if I set simple a 128 bit uuid in generator (0x6E400001B5A3F393E0A9E50E24DCCA9E)
pzCharacteristicData_t struct still using 16bit value for uuid
typedef struct { uint16_t svcUUID; // UUID of the service uint16_t dataLen; // uint8_t paramID; // Index of the characteristic uint8_t data[]; // Flexible array member, extended to malloc - sizeof(.) } spCharacteristicData_t;
and when sending message to main task it simply don't fits
static void user_NUS_ValueChangeCB(uint16_t connHandle, uint8_t paramID, uint16_t len, uint8_t *pValue) { pzCharacteristicData_t *pValChange = ICall_malloc(sizeof(pzCharacteristicData_t) + len); if(pValChange != NULL) { pValChange->svcUUID = NUS_SERV_UUID; pValChange->paramID = paramID; memcpy(pValChange->data, pValue, len); pValChange->dataLen = len; ProjectZero_enqueueMsg(PZ_SERVICE_WRITE_EVT, pValChange); } }
Apologies for any confusion. Project Zero by default is setup to use 128-bit UUIDs for the service and the characteristics.
I would take a look at data_service.c (as an example, I believe the other profiles in Project Zero can also be referenced). When the profile is written to, the Data_Service_WriteAttrCB is called. At this stage, the characteristic is searched for using Data_Service_findCharParamId. It is at this layer that the UUID is fully checked. Once the characteristic is identified, indexes are passed up to the application layer. This takes us to ProjectZero_DataService_ValueChangeCB, where the pzCharacteristicData_t shown above comes into play. At this stage the peripheral already knows what svcUUID is being written to (the callback from the profile was already triggered), so only a 16-bit identifier is used to communicate to the application.
Hope this helps.