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: how to send periodic notification

Part Number: CC2642R
Other Parts Discussed in Thread: CC2640,

Tool/software:

hi Experts,

please let me know how to send periodic notification data using CC2640.

thanks

regards,

  • Hi Robin,

    Could you please help specify if you are talking about CC2640, CC2640R2 or CC2642R? 

    Also, can you please confirm you manage to send notifications and are only asking how to make them periodic? 

    Best regards, 

  • Hi Clement

    my customer would like to send notify data every 1 sec using CC2642R

    However, the system stops after only one notification has been sent.

    attached their source code. please point out the error.

     

    /*
        ble 동작 흐름
    
        기존
        cc2642 설정
            - da01, da04, da20 : write, read
    
        app     : da20으로 write
        cc2642  : da20으로 받은 데이터에 맞는 행동을 하고 da01과 da04 데이터를 갱신
        app     : da01과 da04 read요청
        cc2642  : da01과 da04 응답
        
        
        신규
        cc2642 설정
            - da01, da04, da99 : write, read, notify
            - da20 : write
    
        app     : da20으로 데이터 전송
        cc2642  : da20으로 받은 데이터에 맞는 행동을 하고 da01과 da04 데이터를 app에 전송(notify)
        
    */
    
    /*
        증상
        
        app과 연결되기 전까지 Notification is not enabled for DA01 메세지 1초마다 반복
        app과 연결 후 0-GATT_Notification 메세지 나온 후 멈춤
    
        예상
        SimpleProfile_SetParameter 함수 동작 후 멈춤
        SimpleProfile_SetParameter - gattServApp_SendNotiInd - GATT_Notification 함수에서 멈춤
    */
    
    // 1초에 한번씩 전송
    static void user_main_taskFxn(UArg a0, UArg a1)
    {
        for(;;)
    	{
            if(gpram1->ble_test_cnt >= 1000){
                gpram1->ble_test_cnt = 0;
                if (gpram1->connHandle_tmp != LINKDB_CONNHANDLE_INVALID)
                {
                    uint8_t notifyValue = 0;
                    notifyValue++;
    
                    simpleProfileChar1[0] = notifyValue;
                    simpleProfileChar1[1] = notifyValue+10;
                    SimpleProfile_SetParameter(SIMPLEPROFILE_DA01, SIMPLEPROFILE_DA01_LEN, simpleProfileChar1);
                }
                else{
                    System_printf("Invalid connection handle.\r\n");
                }
            }
            fn_UART_Read();
            fn_Interface_DelayTimer();
        }
    }
    
    
    // ble 설정
    
    static uint8 simpleProfileChar1Props = GATT_PROP_READ | GATT_PROP_WRITE | GATT_PROP_NOTIFY;
    
    uint8 simpleProfileChar1[SIMPLEPROFILE_DA01_LEN] = {0,};
    uint8 simpleProfileChar1Length = SIMPLEPROFILE_DA01_LEN;
    static gattCharCfg_t *simpleProfileChar1Config;	//da01
    static gattCharCfg_t *simpleProfileChar2Config;	//da04
    // static gattCharCfg_t *simpleProfileChar3Config;	//da20
    static gattCharCfg_t *simpleProfileChar7Config;	//da99
    
    // Simple Profile Characteristic 1 User Description
    static uint8 simpleProfileChar1UserDesp[16] = "Key Press State";
    
    // Simple Profile Characteristic 2 Properties
    uint8 simpleProfileChar2Props = GATT_PROP_READ | GATT_PROP_WRITE | GATT_PROP_NOTIFY;
    
    // Characteristic 2 Value							0  1   2	3 	4     5	  6		7	8		9
    uint8 simpleProfileChar2[SIMPLEPROFILE_DA04_LEN] = {0,};//{0, 0, 'a', 'b', 'c', 'd', '0', '1', '2', '3'};
    uint8 simpleProfileChar2Length = SIMPLEPROFILE_DA04_LEN;
    
    // Simple Profile Characteristic 3 Properties
    uint8 simpleProfileChar3Props = GATT_PROP_WRITE | GATT_PROP_WRITE_NO_RSP;	//GATT_PROP_READ | GATT_PROP_WRITE | GATT_PROP_NOTIFY;
    
    // Characteristic 3 Value
    uint8 simpleProfileChar3[SIMPLEPROFILE_DA20_LEN] = {0,};
    uint8 simpleProfileChar3Length = SIMPLEPROFILE_DA20_LEN;
    
    // Simple Profile Characteristic 4 Properties
    static uint8 simpleProfileChar4Props = GATT_PROP_NOTIFY;
    
    // Characteristic 4 Value
    uint8 simpleProfileChar4[SIMPLEPROFILE_FFE1_LEN] = {0,};
    
    // Simple Profile Characteristic 4 Configuration Each client has its own
    // instantiation of the Client Characteristic Configuration. Reads of the
    // Client Characteristic Configuration only shows the configuration for
    // that client and writes only affect the configuration of that client.
    static gattCharCfg_t *simpleProfileChar4Config;
    
    // Simple Profile Characteristic 4 User Description
    static uint8 simpleProfileChar4UserDesp[16] = "Key Press State";
    
    // Simple Profile Characteristic 5 Properties
    uint8 simpleProfileChar5Props = GATT_PROP_READ | GATT_PROP_WRITE;
    
    // Characteristic 5 Value
    uint8 simpleProfileChar5[SIMPLEPROFILE_AF01_LEN] = {0,};
    uint8 simpleProfileChar5Length = SIMPLEPROFILE_AF01_LEN;
    
    // Simple Profile Characteristic 6 Properties
    uint8 simpleProfileChar6Props = GATT_PROP_READ | GATT_PROP_WRITE;
    
    // Characteristic 6 Value
    uint8 simpleProfileChar6[SIMPLEPROFILE_AF02_LEN] = {0,};
    uint8 simpleProfileChar6Length = SIMPLEPROFILE_AF02_LEN;
    
    
    // static gattCharCfg_t *simpleProfileChar7Config;
    
    // Simple Profile Characteristic 7 Properties
    uint8 simpleProfileChar7Props = GATT_PROP_READ | GATT_PROP_WRITE | GATT_PROP_NOTIFY;
    
    // Characteristic 7 Value
    uint8 simpleProfileChar7[SIMPLEPROFILE_DA99_LEN] = {1,};
    uint8 simpleProfileChar7Length = SIMPLEPROFILE_DA99_LEN;
    
    #define SERVAPP_NUM_ATTR_SUPPORTED       12
    static gattAttribute_t simpleProfileAttrTbl[SERVAPP_NUM_ATTR_SUPPORTED] =
    {
    	// Simple Profile Service
    	{
    		{ATT_BT_UUID_SIZE, primaryServiceUUID },
    		GATT_PERMIT_READ,
    		0,
    		(uint8 *)&simpleProfileService
    	},
    
    	// Characteristic 1 Declaration (DA01)
    	{
    		{ ATT_BT_UUID_SIZE, characterUUID },
    		GATT_PERMIT_READ,
    		0,
    		&simpleProfileChar1Props
    	},
    	// Characteristic Value 1 (DA01)
    	{
    		{ ATT_BT_UUID_SIZE, simpleProfileDA01UUID },
    		GATT_PERMIT_READ | GATT_PERMIT_WRITE,
    		0,
    		simpleProfileChar1
    	},
    	// Characteristic 1 configuration (CCCD for Notification)
    	{
    		{ ATT_BT_UUID_SIZE, clientCharCfgUUID },
    		GATT_PERMIT_READ | GATT_PERMIT_WRITE,
    		0,
    		(uint8 *)&simpleProfileChar1Config
    	},
    
    	// Characteristic 2 Declaration (DA04)
    	{
    		{ ATT_BT_UUID_SIZE, characterUUID },
    		GATT_PERMIT_READ,
    		0,
    		&simpleProfileChar2Props
    	},
    	// Characteristic Value 2 (DA04)
    	{
    		{ ATT_BT_UUID_SIZE, simpleProfileDA04UUID },
    		GATT_PERMIT_READ | GATT_PERMIT_WRITE,
    		0,
    		simpleProfileChar2
    	},
    	// Characteristic 2 configuration (CCCD for Notification)
    	{
    		{ ATT_BT_UUID_SIZE, clientCharCfgUUID },
    		GATT_PERMIT_READ | GATT_PERMIT_WRITE,
    		0,
    		(uint8 *)&simpleProfileChar2Config
    	},
    
    	// Characteristic 3 Declaration (DA20)
    	{
    		{ ATT_BT_UUID_SIZE, characterUUID },
    		GATT_PERMIT_READ,
    		0,
    		&simpleProfileChar3Props
    	},
    	// Characteristic Value 3 (DA20)
    	{
    		{ ATT_BT_UUID_SIZE, simpleProfileDA20UUID },
    		GATT_PERMIT_WRITE,
    		0,
    		simpleProfileChar3
    	},
    
    	// Characteristic 7 Declaration (DA99)
    	{
    		{ ATT_BT_UUID_SIZE, characterUUID },
    		GATT_PERMIT_READ,
    		0,
    		&simpleProfileChar7Props
    	},
    	// Characteristic Value 7 (DA99)
    	{
    		{ ATT_BT_UUID_SIZE, simpleProfileDA99UUID },
    		GATT_PERMIT_READ | GATT_PERMIT_WRITE,
    		0,
    		simpleProfileChar7
    	},
    	// Characteristic 7 configuration (CCCD for Notification)
    	{
    		{ ATT_BT_UUID_SIZE, clientCharCfgUUID },
    		GATT_PERMIT_READ | GATT_PERMIT_WRITE,
    		0,
    		(uint8 *)&simpleProfileChar7Config
    	}
    };
    
    bStatus_t SimpleProfile_AddService( uint32 services )
    {
      uint8 status;
    
      // Allocate Client Characteristic Configuration table
    //   simpleProfileChar4Config = (gattCharCfg_t *)ICall_malloc( sizeof(gattCharCfg_t) *
    //                                                             MAX_NUM_BLE_CONNS );
    //   if ( simpleProfileChar4Config == NULL )
    //   {
    //     return ( bleMemAllocError );
    //   }
    
      simpleProfileChar1Config = (gattCharCfg_t *)ICall_malloc( sizeof(gattCharCfg_t) *
                                                                MAX_NUM_BLE_CONNS );
      if ( simpleProfileChar1Config == NULL )
      {
        return ( bleMemAllocError );
      }
      
      simpleProfileChar2Config = (gattCharCfg_t *)ICall_malloc( sizeof(gattCharCfg_t) *
                                                                MAX_NUM_BLE_CONNS );
      if ( simpleProfileChar2Config == NULL )
      {
        return ( bleMemAllocError );
      }
      
    //   simpleProfileChar3Config = (gattCharCfg_t *)ICall_malloc( sizeof(gattCharCfg_t) *
    //                                                             MAX_NUM_BLE_CONNS );
    //   if ( simpleProfileChar3Config == NULL )
    //   {
    //     return ( bleMemAllocError );
    //   }
    
      simpleProfileChar7Config = (gattCharCfg_t *)ICall_malloc( sizeof(gattCharCfg_t) *
                                                                MAX_NUM_BLE_CONNS );
      if ( simpleProfileChar7Config == NULL )
      {
        return ( bleMemAllocError );
      }
      
    
      // Initialize Client Characteristic Configuration attributes
    //   GATTServApp_InitCharCfg( LINKDB_CONNHANDLE_INVALID, simpleProfileChar4Config );
      GATTServApp_InitCharCfg( LINKDB_CONNHANDLE_INVALID, simpleProfileChar1Config );
      GATTServApp_InitCharCfg( LINKDB_CONNHANDLE_INVALID, simpleProfileChar2Config );
    //   GATTServApp_InitCharCfg( LINKDB_CONNHANDLE_INVALID, simpleProfileChar3Config );
      GATTServApp_InitCharCfg( LINKDB_CONNHANDLE_INVALID, simpleProfileChar7Config );
    
    //   simpleProfileChar1Config[0].connHandle = 0x0000;
    //   simpleProfileChar1Config[0].value = 0x0000;
    
      if ( services & SIMPLEPROFILE_SERVICE )
      {
        // Register GATT attribute list and CBs with GATT Server App
        status = GATTServApp_RegisterService( simpleProfileAttrTbl,
                                              GATT_NUM_ATTRS( simpleProfileAttrTbl ),
                                              GATT_MAX_ENCRYPT_KEY_SIZE,
                                              &simpleProfileCBs );
      }
      else
      {
        status = SUCCESS;
      }
    
      return ( status );
    }
    
    
    bStatus_t SimpleProfile_SetParameter( uint8 param, uint8 len, void *value )
    {	// GATT 서버의 특성 값을 설정할 때 호출되며, 이는 BLE 장치의 애플리케이션 코드에서 사용되어 데이터를 업데이트하거나 특성 값을 설정
    	bStatus_t ret = SUCCESS;
    	switch ( param )
    	{
    		case SIMPLEPROFILE_DA01:
    			// System_printf("s-1 : %d\r\n", len);
    			if ( len == SIMPLEPROFILE_DA01_LEN )
    			{
    				VOID memcpy( simpleProfileChar1, value, len );
    
    				// See if Notification has been enabled
                    // GATTServApp_ProcessCharCfg( simpleProfileChar4Config, simpleProfileChar1, FALSE,
                    //                             simpleProfileAttrTbl, GATT_NUM_ATTRS( simpleProfileAttrTbl ),
                    //                             INVALID_TASK_ID, simpleProfile_ReadAttrCB );
    
    				if (simpleProfileChar1Config[gpram1->connHandle_tmp].value & GATT_CLIENT_CFG_NOTIFY)
    				{
    					System_printf("0-GATT_Notification\r\n");
    					if (gpram1->connHandle_tmp != LINKDB_CONNHANDLE_INVALID)
    					{
    						// status = GATT_Notification(connHandle, &noti, FALSE);
    						GATTServApp_ProcessCharCfg( simpleProfileChar1Config, simpleProfileChar1, FALSE,
                                                simpleProfileAttrTbl, GATT_NUM_ATTRS( simpleProfileAttrTbl ),
                                                INVALID_TASK_ID, simpleProfile_ReadAttrCB );
    					}
    					else
    					{
    						System_printf("Invalid connection handle.\r\n");
    					}
    					System_printf("1-GATT_Notification\r\n");
    				}
    				else
    				{
    					System_printf("Notification is not enabled for DA01\r\n");
    				}
    				
    			}
    			else
    			{
    				ret = bleInvalidRange;
    			}
    		break;
    
    		case SIMPLEPROFILE_DA04:
    			// System_printf("s-4 : %d\r\n", len);
    			if ( len == SIMPLEPROFILE_DA04_LEN )
    			{
    				VOID memcpy( simpleProfileChar2, value, len );
    				System_printf("DA04 SET: ");
    				for(int i=0; i<SIMPLEPROFILE_DA04_LEN; i++)
    				{
    					System_printf("%02x ", simpleProfileChar2[i]);
    				}
    				System_printf("\r\n");
    
    				// See if Notification has been enabled
    				GATTServApp_ProcessCharCfg( simpleProfileChar2Config, simpleProfileChar2, FALSE,
                                                simpleProfileAttrTbl, GATT_NUM_ATTRS( simpleProfileAttrTbl ),
                                                INVALID_TASK_ID, simpleProfile_ReadAttrCB );
    				// GATTServApp_ProcessCharCfg( simpleProfileChar4Config, simpleProfileChar2, FALSE,
                    //                             simpleProfileAttrTbl, GATT_NUM_ATTRS( simpleProfileAttrTbl ),
                    //                             INVALID_TASK_ID, simpleProfile_ReadAttrCB );
    			}
    			else
    			{
    				ret = bleInvalidRange;
    			}
    		break;
    			
    		case SIMPLEPROFILE_AF01:
    			if ( len == simpleProfileChar5Length )
    			{
    				VOID memcpy( simpleProfileChar5, value, len );
    
    				// See if Notification has been enabled
                    GATTServApp_ProcessCharCfg( simpleProfileChar4Config, simpleProfileChar5, FALSE,
                                                simpleProfileAttrTbl, GATT_NUM_ATTRS( simpleProfileAttrTbl ),
                                                INVALID_TASK_ID, simpleProfile_ReadAttrCB );
    			}
    			else
    			{
    				ret = bleInvalidRange;
    			}
    		break;
    			
    		case SIMPLEPROFILE_AF02:
    			if ( len == simpleProfileChar6Length )
    			{
    				VOID memcpy( simpleProfileChar6, value, len );
    
    				// See if Notification has been enabled
    				GATTServApp_ProcessCharCfg( simpleProfileChar4Config, simpleProfileChar6, FALSE,
                                                simpleProfileAttrTbl, GATT_NUM_ATTRS( simpleProfileAttrTbl ),
                                                INVALID_TASK_ID, simpleProfile_ReadAttrCB );
    			}
    			else
    			{
    				ret = bleInvalidRange;
    			}
    		break;
    
    		case SIMPLEPROFILE_DA99:
    		{
    			// System_printf("s-9 : %d\r\n", len);
    			if ( len == SIMPLEPROFILE_DA99_LEN )
    			{
    				VOID memcpy( simpleProfileChar7, value, len );
    
    				// See if Notification has been enabled
    				GATTServApp_ProcessCharCfg( simpleProfileChar4Config, simpleProfileChar7, FALSE,
                                                simpleProfileAttrTbl, GATT_NUM_ATTRS( simpleProfileAttrTbl ),
                                                INVALID_TASK_ID, simpleProfile_ReadAttrCB );
    			}
    			else
    			{
    				ret = bleInvalidRange;
    			}
    		}
    		break;
    
    		default:
    			ret = INVALIDPARAMETER;
    		break;
    	}
    
    	return ( ret );
    }
    
    

    thanks

    regards,

  • Hello,

    This is the current situation.

    The issue where it stopped at GATTServApp_ProcessCharCfg has been resolved, but sending data through notifications is not working.

    I want to send data via notifications anytime the data is updated.

    When I check the state using state = GATTServApp_ProcessCharCfg, the state shows as 0x1b (blePending).

    Please let me know how I can debug this.

    Below is the BLE transmission flow:

    • The data to be sent is set using fn_Interface_BleState().
    • In multi_role_performPeriodicTask(), every 200ms, the queue is checked, and if there is data, SimpleProfile_SetParameter is called.
    • In the SimpleProfile_SetParameter function, data is sent using GATTServApp_ProcessCharCfg.

    Below is the code I have configured. Please check if anything is incorrect or missing.

    // Simple Profile Service attribute
    static CONST gattAttrType_t simpleProfileService = { ATT_BT_UUID_SIZE, simpleProfileServUUID };

    // Simple Profile Characteristic 1 Properties
    static uint8 simpleProfileChar1Props = GATT_PROP_READ | GATT_PROP_WRITE | GATT_PROP_NOTIFY;

    // Characteristic 1 Value
    uint8 simpleProfileChar1[SIMPLEPROFILE_DA01_LEN] = {0,};
    uint8 simpleProfileChar1Length = SIMPLEPROFILE_DA01_LEN;
    static gattCharCfg_t *simpleProfileChar1Config; //da01
    static gattCharCfg_t *simpleProfileChar2Config; //da04
    static gattCharCfg_t *simpleProfileChar3Config; //da20
    static gattCharCfg_t *simpleProfileChar7Config; //da99

    // Simple Profile Characteristic 1 User Description
    static uint8 simpleProfileChar1UserDesp[16] = "Key Press State";

    // Simple Profile Characteristic 2 Properties
    uint8 simpleProfileChar2Props = GATT_PROP_READ | GATT_PROP_WRITE | GATT_PROP_NOTIFY;

    // Characteristic 2 Value
    uint8 simpleProfileChar2[SIMPLEPROFILE_DA04_LEN] = {0, 0, 'a', 'b', 'c', 'd', '0', '1', '2', '3'};
    uint8 simpleProfileChar2Length = SIMPLEPROFILE_DA04_LEN;

    // Simple Profile Characteristic 3 Properties
    uint8 simpleProfileChar3Props = GATT_PROP_WRITE | GATT_PROP_WRITE_NO_RSP;   //GATT_PROP_READ | GATT_PROP_WRITE | GATT_PROP_NOTIFY;

    // Characteristic 3 Value
    uint8 simpleProfileChar3[SIMPLEPROFILE_DA20_LEN] = {0,};
    uint8 simpleProfileChar3Length = SIMPLEPROFILE_DA20_LEN;

    // Simple Profile Characteristic 4 Properties
    static uint8 simpleProfileChar4Props = GATT_PROP_NOTIFY;

    // Characteristic 4 Value
    uint8 simpleProfileChar4[SIMPLEPROFILE_FFE1_LEN] = {0,};

    // Simple Profile Characteristic 4 Configuration Each client has its own
    // instantiation of the Client Characteristic Configuration. Reads of the
    // Client Characteristic Configuration only shows the configuration for
    // that client and writes only affect the configuration of that client.
    static gattCharCfg_t *simpleProfileChar4Config;

    // Simple Profile Characteristic 4 User Description
    static uint8 simpleProfileChar4UserDesp[16] = "Key Press State";

    // Simple Profile Characteristic 5 Properties
    uint8 simpleProfileChar5Props = GATT_PROP_READ | GATT_PROP_WRITE;

    // Characteristic 5 Value
    uint8 simpleProfileChar5[SIMPLEPROFILE_AF01_LEN] = {0,};
    uint8 simpleProfileChar5Length = SIMPLEPROFILE_AF01_LEN;

    // Simple Profile Characteristic 6 Properties
    uint8 simpleProfileChar6Props = GATT_PROP_READ | GATT_PROP_WRITE;

    // Characteristic 6 Value
    uint8 simpleProfileChar6[SIMPLEPROFILE_AF02_LEN] = {0,};
    uint8 simpleProfileChar6Length = SIMPLEPROFILE_AF02_LEN;


    // static gattCharCfg_t *simpleProfileChar7Config;

    // Simple Profile Characteristic 7 Properties
    uint8 simpleProfileChar7Props = GATT_PROP_READ | GATT_PROP_WRITE | GATT_PROP_NOTIFY;

    // Characteristic 7 Value
    uint8 simpleProfileChar7[SIMPLEPROFILE_DA99_LEN] = {1,};
    uint8 simpleProfileChar7Length = SIMPLEPROFILE_DA99_LEN;

    #define SERVAPP_NUM_ATTR_SUPPORTED        12

    static gattAttribute_t simpleProfileAttrTbl[SERVAPP_NUM_ATTR_SUPPORTED] =
    {
        // Simple Profile Service
        {
            {ATT_BT_UUID_SIZE, primaryServiceUUID }, /* type */
            GATT_PERMIT_READ,                         /* permissions */
            0,                                        /* handle */
            (uint8 *)&simpleProfileService            /* pValue */
        },
        // Characteristic 1 Declaration
        {
            { ATT_BT_UUID_SIZE, characterUUID },
            GATT_PERMIT_READ,
            0,
            &simpleProfileChar1Props
        },
        // Characteristic Value 1
        {
            { ATT_BT_UUID_SIZE, simpleProfileDA01UUID },
            GATT_PERMIT_READ | GATT_PERMIT_WRITE, // Notification added
            0,
            simpleProfileChar1
        },
        // Characteristic 1 configuration (CCCD for Notification)
        {
            { ATT_BT_UUID_SIZE, clientCharCfgUUID },
            GATT_PERMIT_READ | GATT_PERMIT_WRITE,
            0,
            (uint8 *)&simpleProfileChar1Config
        },

        // Characteristic 2 Declaration
        {
            { ATT_BT_UUID_SIZE, characterUUID },
            GATT_PERMIT_READ,
            0,
            &simpleProfileChar2Props
        },
        // Characteristic Value 2
        {
            { ATT_BT_UUID_SIZE, simpleProfileDA04UUID },
            GATT_PERMIT_READ | GATT_PERMIT_WRITE , // Notification added
            0,
            simpleProfileChar2
        },
        // Characteristic 2 configuration (CCCD for Notification)
        {
            { ATT_BT_UUID_SIZE, clientCharCfgUUID },
            GATT_PERMIT_READ | GATT_PERMIT_WRITE,
            0,
            (uint8 *)&simpleProfileChar2Config
        },

        // Characteristic 3 Declaration
        {
            { ATT_BT_UUID_SIZE, characterUUID },
            GATT_PERMIT_READ,
            0,
            &simpleProfileChar3Props
        },
        // Characteristic Value 3
        {
            { ATT_BT_UUID_SIZE, simpleProfileDA20UUID },
            // GATT_PERMIT_READ | GATT_PERMIT_WRITE , // Notification added
            GATT_PERMIT_WRITE ,
            0,
            simpleProfileChar3
        },

        // Characteristic 7 Declaration
        {
            { ATT_BT_UUID_SIZE, characterUUID },
            GATT_PERMIT_READ,
            0,
            &simpleProfileChar7Props
        },
        // Characteristic Value 7
        {
            { ATT_BT_UUID_SIZE, simpleProfileDA99UUID },
            GATT_PERMIT_READ | GATT_PERMIT_WRITE , // Notification added
            0,
            simpleProfileChar7
        },
        // Characteristic 7 configuration (CCCD for Notification)
        {
            { ATT_BT_UUID_SIZE, clientCharCfgUUID },
            GATT_PERMIT_READ | GATT_PERMIT_WRITE,
            0,
            (uint8 *)&simpleProfileChar7Config
        }
    };


    bStatus_t SimpleProfile_AddService( uint32 services )
    {
      uint8 status;

      simpleProfileChar1Config = (gattCharCfg_t *)ICall_malloc( sizeof(gattCharCfg_t) *
                                                                MAX_NUM_BLE_CONNS );
      if ( simpleProfileChar1Config == NULL )
      {
        return ( bleMemAllocError );
      }

      GATTServApp_InitCharCfg( LINKDB_CONNHANDLE_INVALID, simpleProfileChar1Config );

     
     
      simpleProfileChar2Config = (gattCharCfg_t *)ICall_malloc( sizeof(gattCharCfg_t) *
                                                                MAX_NUM_BLE_CONNS );
      if ( simpleProfileChar2Config == NULL )
      {
        return ( bleMemAllocError );
      }

      GATTServApp_InitCharCfg( LINKDB_CONNHANDLE_INVALID, simpleProfileChar2Config );

      simpleProfileChar7Config = (gattCharCfg_t *)ICall_malloc( sizeof(gattCharCfg_t) *
                                                                MAX_NUM_BLE_CONNS );
      if ( simpleProfileChar7Config == NULL )
      {
        return ( bleMemAllocError );
      }

      GATTServApp_InitCharCfg( LINKDB_CONNHANDLE_INVALID, simpleProfileChar7Config );

      if ( services & SIMPLEPROFILE_SERVICE )
      {
        // Register GATT attribute list and CBs with GATT Server App
        status = GATTServApp_RegisterService( simpleProfileAttrTbl,
                                              GATT_NUM_ATTRS( simpleProfileAttrTbl ),
                                              GATT_MAX_ENCRYPT_KEY_SIZE,
                                              &simpleProfileCBs );
      }
      else
      {
        status = SUCCESS;
      }

      return ( status );
    }

    bStatus_t SimpleProfile_SetParameter( uint8 param, uint8 len, void *value )
    {
        bStatus_t ret = SUCCESS;
        switch ( param )
        {
            case SIMPLEPROFILE_DA01:
                if ( len == SIMPLEPROFILE_DA01_LEN )
                {
                    VOID memcpy( simpleProfileChar1, value, len );

                    // See if Notification has been enabled
                    GATTServApp_ProcessCharCfg( simpleProfileChar1Config, simpleProfileChar1, FALSE,
                                                simpleProfileAttrTbl, GATT_NUM_ATTRS( simpleProfileAttrTbl ),
                                                INVALID_TASK_ID, simpleProfile_ReadAttrCB );
                }
                else
                {
                    ret = bleInvalidRange;
                }
            break;

            case SIMPLEPROFILE_DA04:
                if ( len == SIMPLEPROFILE_DA04_LEN )
                {
                    VOID memcpy( simpleProfileChar2, value, len );

                    // See if Notification has been enabled
                    GATTServApp_ProcessCharCfg( simpleProfileChar2Config, simpleProfileChar2, FALSE,
                                                simpleProfileAttrTbl, GATT_NUM_ATTRS( simpleProfileAttrTbl ),
                                                INVALID_TASK_ID, simpleProfile_ReadAttrCB );
                }
                else
                {
                    ret = bleInvalidRange;
                }
            break;

            case SIMPLEPROFILE_DA99:
            {
                if ( len == SIMPLEPROFILE_DA99_LEN )
                {
                    VOID memcpy( simpleProfileChar7, value, len );

                    // See if Notification has been enabled
                    GATTServApp_ProcessCharCfg( simpleProfileChar7Props, simpleProfileChar7, FALSE,
                                                simpleProfileAttrTbl, GATT_NUM_ATTRS( simpleProfileAttrTbl ),
                                                INVALID_TASK_ID, simpleProfile_ReadAttrCB );
                }
                else
                {
                    ret = bleInvalidRange;
                }
            }
            break;

            default:
                ret = INVALIDPARAMETER;
            break;
        }

        return ( ret );
    }

    static bStatus_t simpleProfile_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;

        // 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 )
            {
                // No need for "GATT_SERVICE_UUID" or "GATT_CLIENT_CHAR_CFG_UUID" cases;
                // gattserverapp handles those reads

                // characteristics 1 and 2 have read permissions
                // characteritisc 3 does not have read permissions; therefore it is not
                //   included here
                // characteristic 4 does not have read permissions, but because it
                //   can be sent as a notification, it is included here
                case SIMPLEPROFILE_DA01_UUID:
                {
                    *pLen = simpleProfileChar1Length;
                   
                    VOID memcpy( pValue, pAttr->pValue, SIMPLEPROFILE_DA01_LEN );
                }
                break;

                case SIMPLEPROFILE_DA04_UUID:
                {
                    // �ܵ������� �ܵ� ������ ���� �� ����
                    *pLen = 1;
                   
                    VOID memcpy( pValue, pAttr->pValue, 1 );
                }
                break;
               
                case SIMPLEPROFILE_DA20_UUID:
                {
                    *pLen = simpleProfileChar3Length;
                   
                    VOID memcpy( pValue, pAttr->pValue, SIMPLEPROFILE_DA20_LEN );
                }
                break;

                case SIMPLEPROFILE_DA99_UUID:
                {
                    *pLen = simpleProfileChar7Length;
                   
                    VOID memcpy( pValue, pAttr->pValue, SIMPLEPROFILE_DA99_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 );
    }


    static void multi_role_performPeriodicTask(void)
    {
      /*
        multi_role_performPeriodicTask 흐름
        BLE 인터페이스 활성화 → 전송 큐에서 데이터 가져오기 → 데이터 길이에 따른 특성 결정 → GATT 특성에 데이터 설정 → 알림 전송(필요 시)
      */

        // CHB
        //uint8_t valueToCopy;

        // Call to retrieve the value of the third characteristic in the profile
        // CHB
        //if (SimpleProfile_GetParameter(SIMPLEPROFILE_CHAR3, &valueToCopy) == SUCCESS)   // GATT 프로파일에서 세 번째 특성 값 읽기
        {
            // Call to set that value of the fourth characteristic in the profile.
            // Note that if notifications of the fourth characteristic have been
            // enabled by a GATT client device, then a notification will be sent
            // every time this function is called.
            // CHB
            //SimpleProfile_SetParameter(SIMPLEPROFILE_CHAR4, sizeof(uint8_t), &valueToCopy); // 그 값을 네 번째 특성에 쓰기
        }

    #ifdef INTERFACE_BLE_ENABLE

        unsigned char tBuff[COMMQUEUE_SIZE];
        unsigned short tLength;

        InterfaceBleEnTmr = INTERFACE_ENABLE_TIME;

        // if(InterfaceBleEnFlg == SET)
        {
            tLength = fn_Interface_BleSendQueue_GetData(tBuff);

            if(tLength != 0)
            {
                if(tLength == SIMPLEPROFILE_DA01_LEN)
                {
                    memcpy(simpleProfileChar1, tBuff, SIMPLEPROFILE_DA01_LEN);
                    SimpleProfile_SetParameter(SIMPLEPROFILE_DA01, SIMPLEPROFILE_DA01_LEN, simpleProfileChar1);
                }
                else if(tLength == SIMPLEPROFILE_DA04_LEN)
                {
                    memcpy(simpleProfileChar2, tBuff, SIMPLEPROFILE_DA04_LEN);
                    SimpleProfile_SetParameter(SIMPLEPROFILE_DA04, SIMPLEPROFILE_DA04_LEN, simpleProfileChar2);
                }
          else
                {
                    memcpy(simpleProfileChar7, tBuff, SIMPLEPROFILE_DA99_LEN);
                    SimpleProfile_SetParameter(SIMPLEPROFILE_DA99, SIMPLEPROFILE_DA99_LEN, simpleProfileChar7);
                }
            }
        }
    }

    void fn_Interface_BleState(unsigned char State)
    {
        unsigned char tIndex;
        unsigned char tBuff[COMMQUEUE_SIZE];
       
        if(State == DA99_STATUS)
        {
            fn_Interface_BleSendQueue_PutData(tBuff, SIMPLEPROFILE_DA99_LEN);
        }
        else if(State == DA20_STATUS_SERIAL_NUMBER)
        {
            fn_Interface_BleSendQueue_PutData(tBuff, SIMPLEPROFILE_DA04_LEN);
        }
        else
        {
            fn_Interface_BleSendQueue_PutData(tBuff, SIMPLEPROFILE_DA01_LEN);
        }
    }


    void fn_Interface_BleSendQueue_PutData(unsigned char* Data, unsigned short Size)
    {
        unsigned short i;

        QueueBleSendSize[QueueBleSendHead] = Size;

        for(i=0; i<QueueBleSendSize[QueueBleSendHead]; i++)
        {
            QueueBleSendBuff[(unsigned int)(QueueBleSendHead*COMMQUEUE_SIZE)+i] = Data[i];
        }

        QueueBleSendHead++;
        QueueBleSendHead %= COMMQUEUE_INDEX;
    }

    unsigned short fn_Interface_BleSendQueue_GetData(unsigned char* Data)
    {
        unsigned short i;
        unsigned short tSize;

        if(QueueBleSendHead != QueueBleSendTail)
        {
            tSize = QueueBleSendSize[QueueBleSendTail];

            for(i=0; i<tSize; i++)
            {
                Data[i] = QueueBleSendBuff[(QueueBleSendTail*COMMQUEUE_SIZE)+i];
            }

            QueueBleSendTail++;
            QueueBleSendTail %= COMMQUEUE_INDEX;

            return tSize;
        }

        return 0;
    }


  • The error code 0x1B was not blePending, but actually bleInvalidMtuSize.

    #define ATT_MTU_SIZE L2CAP_MTU_SIZE //!< Minimum ATT MTU size
    #define L2CAP_MTU_SIZE 23 //!< Minimum supported information payload for the Basic information frame (B-frame)

    GATTServApp_ProcessCharCfg( simpleProfileChar1Config, simpleProfileChar1, FALSE,
    simpleProfileAttrTbl, GATT_NUM_ATTRS( simpleProfileAttrTbl ),
    INVALID_TASK_ID, simpleProfile_ReadAttrCB );

    The size of simpleProfileChar1 was 22, which likely caused the bleInvalidMtuSize error.

    After making the following modification, communication through notifications started working: When connected to the app (GAP_LINK_ESTABLISHED_EVENT), I added:

    attExchangeMTUReq_t req; req.clientRxMTU = 247; uint8_t status = GATT_ExchangeMTU(connHandle, &req, selfEntity);

    This resolved the issue.

    thank you.