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.

Adding new profile to KeyFobDemo cc2530/40

Other Parts Discussed in Thread: Z-STACK, BLE-STACK

Hey guys,

I am trying to create a new profile on KeyFobDemo. I was able to modify Characteristic 5 on the SimplePeripheral example to read and write 22 bytes. However, when I try to use the same structure on my KeyFobDemo profile I cannot write/read more than 7 bytes... 

I am using the osal_memcpy technique i have seen in other discussions. My guess is that the osal_mem is out of space which is causing the error? If anyone has an idea of what the problem could be that would be greatly appreciated.

In addition, I eventually need to store this data in flash (not using z-stack) and read multiple packets (incoming data from phone will be around 6KB. Therefore any advice, examples, or resources on how to implement that would be great. I haven't found any useful forums on this topic.

Requesting a response as soon as possible.

Thanks,

Adam

  • Hey Adam,

    osal_memcpy doesn't require any memory allocation, it is just an efficient method for copying byte arrays. Which keyfob profile (specifically which .c and which characteristic) are you trying to modify or are you adding your modified simpleGATTprofile to the existing project and calling the add service and register call back functions from your application?

    For writing large amount of data to flash look at the osal_nv or osal_snv APIs in ./Documents/osal/Osal API.pdf of your BLE-stack download folder.

    -Matt 

  • Hey Matt,

    Thank you for the quick response! I created my own profile in Keyfob profile folder. At first, i used the simpleGATTprofile as an outline and edited the first and fifth characteristic to become familiar with GATT. I reconfigured the fifth characteristic with read/write permissions and was able to successfully write 22 bytes to the attribute. I copied the fifth characteristic into my new profile in the keyfob project space (adjusted the variable names and inserted the necessary functions and callbacks in the keyfobdemo.c). I am able to read and write to the attribute but it does not seem to work past 7 bytes (although it is the exact same structure as my fifth characteristic in simpleGATTprofile)

  • I'm unsure of exactly what the symptoms are when it fails. If you declare the size of that characteristic (SIMPLEPROFILE_CHAR5_LEN) to be <=7 then you are able to read and write to all bytes this characteristic from a central device. If you declare the characteristic value length to be >7 then the device doesn't work.

    Does that mean the device doesn't operate (meaning it doesn't even advertise initally), or can you not discover that characteristic or the service on the central side, or can you still discover everything but when reading or writing to that characteristic the value field of the characteristic still appears to be only 7 bytes long?

    -Matt

  • Heres an example: (this is ontop of KeyFob project)

    I define the characteristic length to be >7 for example #define READIMAGE_CHAR5_LEN 10 and change the characteristic value in the .c file to the appropriate length.

    When I connect, I am able to read and write to other services like battery and proximity but when i try to write a value in the characteristic, i get disconnected from the device. I just don't understand why it does not work if it is working in simpleBLEperipheral. I pasted a snippet of the code in my profile:

    (note that this is the same structure as the characteristic 5 in simpleprofileGATT which i was able to read/write 22 bytes.)

    , *********************************************************************
     * @fn      ReadImage_SetParameter
     */
    bStatus_t ReadImage_SetParameter( uint8 param, uint32 len, void *value )
    {
      bStatus_t ret = SUCCESS;
      switch ( param )
      {
        case READIMAGE_CHAR1:
          if ( len == READIMAGE_CHAR1_LEN )
          {
            VOID osal_memcpy( readImageChar1, value, READIMAGE_CHAR1_LEN );

          }
          else
          {
            ret = bleInvalidRange;
          }
          break;

          
      default:
          ret = INVALIDPARAMETER;
          break;
      }
     
      return ( ret );
    }

    /*********************************************************************
     * @fn      ReadImage_GetParameter
     */


    bStatus_t ReadImage_GetParameter( uint8 param, void *value )
    {
      bStatus_t ret = SUCCESS;
      switch ( param )
      {
        case READIMAGE_CHAR1:
          VOID osal_memcpy( value, readImageChar1, READIMAGE_CHAR1_LEN );
          break;
          
        default:
          ret = INVALIDPARAMETER;
          break;
      }
     
      return ( ret );
    }


    /*********************************************************************
     * @fn          readImage_ReadAttrCB
     */
    static uint8 readImage_ReadAttrCB( uint16 connHandle, gattAttribute_t *pAttr,
                                uint8 *pValue, uint8 *pLen, uint16 offset, uint8 maxLen )
    {
      bStatus_t status = SUCCESS;

      // If attribute permissions require authorization to read, return error
      if ( gattPermitAuthorRead( pAttr->permissions ) )
      {
        // Insufficient authorization
        return ( ATT_ERR_INSUFFICIENT_AUTHOR );
      }
     
      // Make sure it's not a blob operation (no attributes in the profile are long)
      if ( offset > 0 )
      {
       return ( ATT_ERR_ATTR_NOT_LONG );
      }
     
      if ( pAttr->type.len == ATT_BT_UUID_SIZE )
      {
        // 16-bit UUID
        uint16 uuid = BUILD_UINT16( pAttr->type.uuid[0], pAttr->type.uuid[1]);
        switch ( uuid )
        {
           case READIMAGE_CHAR1_UUID:
            *pLen = READIMAGE_CHAR1_LEN;
            VOID osal_memcpy( pValue, pAttr->pValue, READIMAGE_CHAR1_LEN );
            break;
            
            
          default:
            // Should never get here! (characteristics 3 and 4 do not have read permissions)
            *pLen = 0;
            status = ATT_ERR_ATTR_NOT_FOUND;
            break;
        }
      }
      else
      {
        // 128-bit UUID
        *pLen = 0;
        status = ATT_ERR_INVALID_HANDLE;
      }

      return ( status );
    }

    /*********************************************************************
     * @fn      simpleProfile_WriteAttrCB
     */
    static bStatus_t readImage_WriteAttrCB( uint16 connHandle, gattAttribute_t *pAttr,
                                     uint8 *pValue, uint8 len, uint16 offset )
    {
      bStatus_t status = SUCCESS;
      uint8 notifyApp = 0xFF;
     
      // If attribute permissions require authorization to write, return error
      if ( gattPermitAuthorWrite( pAttr->permissions ) )
      {
        // Insufficient authorization
        return ( ATT_ERR_INSUFFICIENT_AUTHOR );
      }
     
      if ( pAttr->type.len == ATT_BT_UUID_SIZE )
      {
        // 16-bit UUID
        uint16 uuid = BUILD_UINT16( pAttr->type.uuid[0], pAttr->type.uuid[1]);
        switch ( uuid )
        {
          case READIMAGE_CHAR1_UUID:
              //Validate the value
            // Make sure it's not a blob oper
            if ( offset == 0 )
            {
              if ( len > READIMAGE_CHAR1_LEN )
              {
                status = ATT_ERR_INVALID_VALUE_SIZE;
              }
            }
            else
            {
              status = ATT_ERR_ATTR_NOT_LONG;
           }
           
           if ( status == SUCCESS )
            {
              uint8 *pCurValue = (uint8 *)pAttr->pValue;
              osal_memset(pCurValue, 0, READIMAGE_CHAR1_LEN);
              VOID osal_memcpy(pCurValue, pValue, len);
              
              if( pAttr->pValue == readImageChar1 )
              {
                notifyApp = READIMAGE_CHAR1;        
              }
            }
          break;
           

          default:
            // Should never get here! (characteristics 2 and 4 do not have write permissions)
            status = ATT_ERR_ATTR_NOT_FOUND;
            break;
        }
      }
      else
      {
        // 128-bit UUID
        status = ATT_ERR_INVALID_HANDLE;
      }

      // If a charactersitic value changed then callback function to notify application of change
      if ( (notifyApp != 0xFF ) && readImage_AppCBs && readImage_AppCBs->pfnReadImageChange )
      {
        readImage_AppCBs->pfnReadImageChange( notifyApp );  
      }
     
      return ( status );
    }

  • Adam,

    I don't see anything wrong with what you've implemented just glancing through it.

    If you have some way to see the link traffic through a sniffer I would see if you are getting an error response packet from the CC254x when you try to read/write that attribute or if you are getting no responses and just timing out on your central device. If you're getting an error packet that will help narrow down what is going wrong.

    I would also try to set break points in my read/write call backs and make sure those are behaving as expected. Just a note, when you add a breakpoint it is going to cause a connection timeout but it will give you an opportunity to make sure you're getting correct output from your call backs. I would also check the return status of your AddService() call to make sure there were no issues with linking characteristics to the server.

    -Matt

  • What does readImage_AppCBs->pfnReadImageChange() do? Maybe comment out that line for now to hone in on your read/write issue. 

  • Hi Peter,

    Commenting out that readImage_AppCB line seemed to help... a little. I am able to read/write up to 21 bytes to the characteristic. However, when I cannot send 22 bytes ( that is the theoretical maximum correct? ). I apologize I am new to BLE and struggling through the learning process. When I try to write 22 bytes (lets say the text string 0123456789012345678901), it appears to go through but when I read the value i lose the last 4 bytes? they are all 0's.

    Eventually I will need to read/write and store multiple packets. I figured knowing how to send the max number of bytes is a good place to start.

  • I meant that the max number i could successfully read/write was 20 bytes. I try to write 21 bytes, but when I read the value, the last 3 bytes are 0's, similar with 22 bytes but the last 4 bytes are 0's

  • How are you reading the characteristics? Some R/Ws can fit 22 bytes in a packet, but only for notifications or blob reads. Standard single packet reads can only be 20. Some posts are here claim 19 under some circumstances. I've never heard a clear explanation why we can't send 22 bytes in single packet reads..

    The packet size limit is based off the MTU size. Some reads require more than one packet which requires an offset. The TI example apps reject any reads that includes an offset.

  • Hi Peter,

    Thanks for the help. I understand with the standard read/write that I will only be able to send/read 20 bytes. My next step is to implement the Gatt_ReadLongCharValue and Gatt_WriteLongCharValue. I've read the other posts regarding these functions but they lack examples and my versions do not work. Am I implementing the functions incorectly? Am i using them in the wrong place? Below is my attempt to use these functions. Any help would be much appreciated.

    Under my ReadAttrCB():

           case READIMAGE_CHAR1_UUID:
            *pLen = READIMAGE_CHAR1_LEN;    
            VOID osal_memcpy( pValue, pAttr->pValue, READIMAGE_CHAR1_LEN );
            attReadBlobReq_t readBlob;
            readBlob.handle = pAttr->handle;
            readBlob.offset = offset;
            GATT_ReadLongCharValue(connHandle, &readBlob, 0xFFF1);
            break;

    Under my WriteAttrCB():

           if ( status == SUCCESS )
            {
              uint8 *pCurValue = (uint8 *)pAttr->pValue;
              *pCurValue = pValue[0];
              osal_memset(pCurValue, 0, READIMAGE_CHAR1_LEN);
              VOID osal_memcpy(pCurValue, pValue, len);
            gattPrepareWriteReq_t writeBlob;
            writeBlob.handle = pAttr->handle;
            writeBlob.offset = offset;
            writeBlob.len = len+1;
            GATT_WriteLongCharValue(connHandle, &writeBlob, 0xFFF1);
              if( pAttr->pValue == readImageChar1 )
              {
                notifyApp = READIMAGE_CHAR1;       
              }
            }