Phone APP can't read characteristic from QN902x peripheral device

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Phone APP can't read characteristic from QN902x peripheral device

2,860 Views
leaflee
Contributor III

I defined 2 characteristics with 1 service on my QN902x peripheral device, as below:

unsigned char attdata[20];

const struct atts_desc llf_att_db[5] = //'5' used in atts_svc_create_db()!!!!!!
{
[0]={ATT_DECL_PRIMARY_SERVICE, PERM(RD, ENABLE), sizeof(llf_main_svc), sizeof(llf_main_svc), (uint8_t *)&llf_main_svc},

[1]={ATT_DECL_CHARACTERISTIC, PERM(RD, ENABLE), sizeof(llf_report_char), sizeof(llf_report_char), (uint8_t *)&llf_report_char},

[2]={LLF_ATT_CHAR_REPORT, PERM(RD, ENABLE), 20, 0, NULL}, //'2' is the index of reading!!!!!!

[3]={ATT_DECL_CHARACTERISTIC, PERM(RD, ENABLE), sizeof(llf_command_char), sizeof(llf_command_char), (uint8_t *)&llf_command_char},

[4]={LLF_ATT_CHAR_COMMAND, PERM(WR, ENABLE), 14, 0, NULL}, //'4' is the index of writing!!!!!!
};


const uint16_t llf_main_svc = LLF_MAIN_SVC;
const struct atts_char_desc llf_report_char = ATTS_CHAR(ATT_CHAR_PROP_RD, 0, LLF_ATT_CHAR_REPORT);
const struct atts_char_desc llf_command_char = ATTS_CHAR(ATT_CHAR_PROP_WR_NO_RESP, 0, LLF_ATT_CHAR_COMMAND);

"LLF_ATT_CHAR_REPORT",index=[2], is a characteristic for a counterpart device (phone) to read. I initialized it and updated it as below:

static int llf_enable_req_handler(ke_msg_id_t const msgid,
struct llf_enable_req const *param,
ke_task_id_t const dest_id,
ke_task_id_t const src_id)
{
uint8_t ctemp;

// con_info=conhdl+appid+prfid
llf_env.con_info.appid = src_id;
llf_env.con_info.conhdl = param->conhdl;

if (gap_get_rec_idx(param->conhdl) == GAP_INVALID_CONIDX) //send error message to TASK_APP
{
prf_server_error_ind_send((prf_env_struct *)&llf_env, PRF_ERR_REQ_DISALLOWED,
LLF_ERROR_IND, LLF_ENABLE_REQ);
}
else
{
for(ctemp=0;ctemp<20;ctemp++) attdata[ctemp]=0; //prepare report char for phone!!!!!!
attsdb_att_set_value(llf_env.shdl+2, 20, attdata);
attsdb_svc_set_permission(llf_env.shdl, param->sec_lvl); //security requirement!!!!!!
ke_state_set(TASK_LLF, LLF_CONNECTED);
}

return (KE_MSG_CONSUMED);
}


static int gatt_write_cmd_ind_handler(ke_msg_id_t const msgid,
struct gatt_write_cmd_ind const *param,
ke_task_id_t const dest_id,
ke_task_id_t const src_id)
{
uint8_t ctemp;

if ((param->conhdl == llf_env.con_info.conhdl)&&(param->handle == llf_env.shdl + 4)&&(param->value[0]==0xaa))
{
attdata[0]=0xa5;
switch(param->value[1]){
case 0x01:
if(param->value[2]!=0xfe) break;
if(!pwmipfg) pwmgetidip();
if(!pwmipfg) {
attdata[1]=0x47;
attdata[2]=0xb8;
attsdb_att_set_value(llf_env.shdl+2, 3, attdata);
break;
}
attdata[1]=0x01;
attdata[2]=0xfe;
for(ctemp=0;ctemp<8;ctemp++) attdata[ctemp+3]=iddata[ctemp];
for(ctemp=0;ctemp<8;ctemp++) attdata[ctemp+11]=ipbddt[ctemp]; //6->7###
// attsdb_att_set_value(llf_env.shdl+2, 19, attdata);
attsdb_att_set_value(llf_env.shdl+2, 20, attdata);
// attsdb_att_set_value(param->handle, 8, (uint8_t *)&param->value[0]); //len='8'?
// atts_write_rsp_send(llf_env.con_info.conhdl, param->handle, PRF_ERR_OK); //no need rsp
break;
case 0x02:
if(param->value[2]!=0xfd) break;
attdata[1]=0x02;
attdata[2]=0xfd;
attdata[3]=pwmsigval();
// attsdb_att_set_value(llf_env.shdl+2, 4, attdata);
attsdb_att_set_value(llf_env.shdl+2, 20, attdata);
break;
case 0x10:
if(param->value[2]!=0xef) break;
pwmclose();
// attdata[1]=0x10;
// attdata[2]=0xef;
// attsdb_att_set_value(llf_env.shdl+2, 3, attdata);
break;
case 0x11:
if(param->value[2]!=0xee) break;
attdata[1]=0x11;
attdata[2]=0xee;
attdata[3]=pwmopenlock(param->value[3],param->value[4]);
// attsdb_att_set_value(llf_env.shdl+2, 4, attdata);
attsdb_att_set_value(llf_env.shdl+2, 20, attdata);
break;
case 0x12:
if(param->value[2]!=0xed) break;
attdata[1]=0x12;
attdata[2]=0xed;
//should check ID######
attdata[3]=pwmopensuper();
// attsdb_att_set_value(llf_env.shdl+2, 4, attdata);
attsdb_att_set_value(llf_env.shdl+2, 20, attdata);
break;

}
attsdb_att_set_value(param->handle, 14, (uint8_t *)&param->value[0]); //len='8'?
}
return (KE_MSG_CONSUMED);
}

 

The phone APP can read the characteristic of "LLF_ATT_CHAR_REPORT" after connection.

But once  the characteristic of "LLF_ATT_CHAR_REPORT" updated, The phone APP can not read the characteristic of "LLF_ATT_CHAR_REPORT" any more!

I really feel confused about it. Anyone met that situation?

Labels (1)
0 Kudos
Reply
10 Replies

2,470 Views
leaflee
Contributor III

I found: Once I use this statement:

attsdb_att_set_value(llf_env.shdl+2, 20, attdata);

to update a characteristic (read permission).

The characteristic (read permission) can not be read by Phone APP any more!

Is anything wrong with attsdb_att_set_value()?

0 Kudos
Reply

2,470 Views
mario_castaneda
NXP TechSupport
NXP TechSupport

Hi Leaf Lee,

Could you please what is the SDK version that you are working on? 1.3.9 or 1.4.0?

You can look at the QPPS profile, as you know, this example is custom profile example and you can take as reference.

Regards,

Mario

0 Kudos
Reply

2,470 Views
leaflee
Contributor III

I have another question.

How does a peripheral device of QN902x proactively send a characteristic (or updated notify) to a central device, a phone i.e.?

If use "PERM(RD, ENABLE)", the central device ( a phone i.e.) need to perform a read command to get the characteristic. Then the central device knows the whether the characteristic is changed. That is not smart.

If the peripheral device of QN902x changes the characteristic, I want to notify the central device. Then the central device can get the updated characteristic. How can that?

0 Kudos
Reply

2,470 Views
mario_castaneda
NXP TechSupport
NXP TechSupport

Hi Leaf Lee,

For example the health thermometer application. update the intermediate measurement value with the notification enable.

// Intermediate Measurement Characteristic Value
[HTS_IDX_INTERM_TEMP_VAL] = {ATT_CHAR_INTERMED_TEMPERATURE, PERM(NTF, ENABLE), HTPT_TEMP_MEAS_MAX_LEN,
0, NULL},

Also, the QPPS example, the TX data is sending through a notification enable.

    // Characteristic Value
    [QPPS_IDX_VAL]                  =   {{ATT_UUID_128_LEN, (uint8_t *)QPPS_FIRST_TX_CHAR_UUID}, PERM(NTF, ENABLE), QPP_DATA_MAX_LEN,
                                         0, NULL},

Regards,

Mario

0 Kudos
Reply

2,470 Views
leaflee
Contributor III

Thanks!

I have another question.

Does QN902x SDK have application-data encrypt/decrypt functions?

I search SDK, and find such definitions in "fw_func_addr.h":

#if (defined(QN_9020_B2))
...
#elif (defined(QN_9020_B4))
...
#define _llm_encryption_start 0x010084f1
#define _llm_encryption_done 0x01008571
...
#endif

I find TI CC2540 has such functions: LL_Encrypt(),LL_EXT_Decrypt().

0 Kudos
Reply

2,470 Views
mario_castaneda
NXP TechSupport
NXP TechSupport

Hi Leaf Lee,

AES HW engine is part of the BLE IP but can be shared with the application.

QN902x SDK includes the API to encrypt data by leveraging the AES module but there is no API to use the HW engine to decrypt data. 

Regards,

Mario

0 Kudos
Reply

2,470 Views
leaflee
Contributor III

Hi Mario,

Many thanks for your valuable advice.

Still I have a question, why are there 2 firmware versions of QN_9020_B2 / QN_9020_B4? Those 2 versions of QN_9020_B2 / QN_9020_B4 have a lot of differences, just say, totally different!

I use QN9021. How can I know: The QN9021 I use is of  QN_9020_B2 version, or is of QN_9020_B4 version?

0 Kudos
Reply

2,470 Views
mario_castaneda
NXP TechSupport
NXP TechSupport

Hi Leaf Lee,

The lib version that you need will depend on the chip version that you purchased, the QN902x-B2 (QN902xY) and B3 (QN902x/DY) and B4 (QN902x/EY)

Different chip version:

a)QN902x-B2 (QN902xY) and B3 (QN902x/DY): #define CFG_9020_B2
b)QN902x-B4 (QN902x/EY): #define CFG_9020_B4

Regards,

Mario

0 Kudos
Reply

2,470 Views
leaflee
Contributor III

I got it.

Thank you very much!

0 Kudos
Reply

2,470 Views
leaflee
Contributor III

QBlue-1.3.9, SDK should be 1.3.9

0 Kudos
Reply