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.

CC2642R: more than 16 bit UUID handling

Part Number: CC2642R

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
TX
RX

Mandatory
Yes
Yes

UUID
0x0002
0x0003

Type
U8[20]
U8[20]

R

X

W
X

N

X

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);
        }
    }
    

  • even TI_BASE_UUID_128 macro is getting erro with too large int

  • 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.