开启DA14580蓝牙服务--点亮LED【git2版本】

工程 D:\git\dialog\6.0.10.511\projects\target_apps\ble_examples\ble_app_peripheral\Keil_5

直接debug

手机APP连接蓝牙 DLG-PRPH

最后连续三个unknown service

如下的位置 是LED的 写01可以看到黄色LED亮起

 

开始分析

开始倒退 谁点灯的

是 user_catch_rest_hndl 中收到消息 msgid=CUSTS1_VAL_WRITE_IND msg_param->handle=SVC1_IDX_LED_STATE_VAL
执行的user_svc1_led_wr_ind_handler
这两个参数 可以说是一个大 一个小 前面是写 大类 后面是参数 写哪一个

                            void user_svc1_led_wr_ind_handler(ke_msg_id_t const msgid,
                                                                 struct custs1_val_write_ind const *param,
                                                                 ke_task_id_t const dest_id,
                                                                 ke_task_id_t const src_id)
                            {
                                uint8_t val = 0;
                                memcpy(&val, &param->value[0], param->length);

                                if (val == CUSTS1_LED_ON)
                                    GPIO_SetActive(GPIO_LED_PORT, GPIO_LED_PIN);
                                else if (val == CUSTS1_LED_OFF)
                                    GPIO_SetInactive(GPIO_LED_PORT, GPIO_LED_PIN);
                            }

                            void user_catch_rest_hndl(ke_msg_id_t const msgid,
                                                      void const *param,
                                                      ke_task_id_t const dest_id,
                                                      ke_task_id_t const src_id)
                            {
                                switch(msgid)
                                {
                                    case CUSTS1_VAL_WRITE_IND:
                                    {
                                        struct custs1_val_write_ind const *msg_param = (struct custs1_val_write_ind const *)(param);

                                        switch (msg_param->handle)
                                        {
                                            case SVC1_IDX_CONTROL_POINT_VAL:
                                                user_svc1_ctrl_wr_ind_handler(msgid, msg_param, dest_id, src_id);
                                                break;

                                            case SVC1_IDX_LED_STATE_VAL:
                                                user_svc1_led_wr_ind_handler(msgid, msg_param, dest_id, src_id);
                                                break;
 那么谁调用的 user_catch_rest_hndl


/// Format of a catch rest event handler function
typedef void(*catch_rest_event_func_t)(ke_msg_id_t const msgid,
                                       void const *param,
                                       ke_task_id_t const dest_id,
                                       ke_task_id_t const src_id);

static const catch_rest_event_func_t app_process_catch_rest_cb = (catch_rest_event_func_t)user_catch_rest_hndl;
                                       
                                       
他其实是给了一个钩子  那么谁调用的狗子 app_process_catch_rest_cb

看到很多 
            if (app_process_catch_rest_cb != NULL)
            {
                app_process_catch_rest_cb(msgid, param, dest_id, src_id);
            }
            我们看看是哪里的

断点如图 流程很明白了

也就是app_entry_point_handler --- app_process_catch_rest_cb  user_catch_rest_hndl ---

那么谁来触发 app_entry_point_handler 这个函数  只有

const struct ke_msg_handler app_default_state[] =
{
    {KE_MSG_DEFAULT_HANDLER,                (ke_msg_func_t)app_entry_point_handler},
};

它是一个事件驱动型的 只管发消息即可 TX KE_MSG_DEFAULT_HANDLER 后面就是挨个去消费的!

重点关注第一个参数 ke_msg_id_t const msgid 它是U16 SVC1_IDX_LED_STATE_VAL 

这个ID是一些枚举 和任务有绑定关系的

 

app_entry_point_handler --- app_process_catch_rest_cb  user_catch_rest_hndl ---

那么谁TX消息的
           // Inform APP
struct custs1_val_write_ind *req_id = KE_MSG_ALLOC_DYN(CUSTS1_VAL_WRITE_IND,
                                        prf_dst_task_get(&(custs1_env->prf_env), KE_IDX_GET(src_id)),
                                        dest_id, custs1_val_write_ind,
                                        param->length);
memcpy(req_id->value, param->value, param->length);
//req_id->conhdl = gapc_get_conhdl(custs1_env.con_info.conidx);
req_id->handle = att_idx;
req_id->length = param->length;

ke_msg_send(req_id);


是这个函数
static int gattc_write_req_ind_handler(ke_msg_id_t const msgid,

注意这里到了生产-消费模型 任意的地方 都可以生产 也就是TX 然后死循环是消费的 
它做的是柔性数组 TX的时候malloc 在消费发时候free




struct fake_custs1_val_write_ind
{
    /// Connection index
    uint8_t  conidx;
    /// Handle of the attribute that has to be written
    uint16_t handle;
    /// Data length to be written
    uint16_t length;
    /// Data to be written in attribute database
    uint8_t  value[10];
};
struct fake_custs1_val_write_ind fake_custs1_val_write={0};
static int gattc_write_req_ind_handler(ke_msg_id_t const msgid,
                                       const struct gattc_write_req_ind *param,
                                       ke_task_id_t const dest_id,
                                       ke_task_id_t const src_id)
{
    struct custs1_env_tag *custs1_env = PRF_ENV_GET(CUSTS1, custs1);
    struct gattc_write_cfm * cfm;
    uint8_t att_idx = 0;
    uint8_t conidx = KE_IDX_GET(src_id);
    // retrieve handle information
    uint8_t status = custs1_get_att_idx(param->handle, &att_idx);
    att_perm_type perm;

    ASSERT_ERROR(param->offset == 0);
    // If the attribute has been found, status is ATT_ERR_NO_ERROR
    if (status == ATT_ERR_NO_ERROR)
    {
        const struct cust_prf_func_callbacks *callbacks = custs_get_func_callbacks(TASK_ID_CUSTS1);

        if (callbacks->att_db[att_idx].uuid_size == ATT_UUID_16_LEN &&
            *(uint16_t *)callbacks->att_db[att_idx].uuid == ATT_DESC_CLIENT_CHAR_CFG)
        {
            struct attm_elmt elem = {0};

            // Find the handle of the Characteristic Value
            uint16_t value_hdl = get_value_handle(param->handle);
            ASSERT_ERROR(value_hdl);

            // Get permissions to identify if it is NTF or IND.
            attmdb_att_get_permission(value_hdl, &perm, 0, &elem);
            status = check_client_char_cfg(PERM_IS_SET(perm, NTF, ENABLE), param);

            if (status == ATT_ERR_NO_ERROR)
            {
                custs1_set_ccc_value(conidx, att_idx, *(uint16_t *)param->value);
            }
        }
        else
        {
            if (callbacks != NULL && callbacks->value_wr_validation_func != NULL)
                status = callbacks->value_wr_validation_func(att_idx, param->offset, param->length, (uint8_t *)&param->value[0]);

            if (status == ATT_ERR_NO_ERROR)
            {
                // Set value in the database
                status = attmdb_att_set_value(param->handle, param->length, param->offset, (uint8_t *)&param->value[0]);
            }
        }

        if (status == ATT_ERR_NO_ERROR)
        {
            // Inform APP
            struct custs1_val_write_ind *req_id = KE_MSG_ALLOC_DYN(CUSTS1_VAL_WRITE_IND,
                                                    prf_dst_task_get(&(custs1_env->prf_env), KE_IDX_GET(src_id)),
                                                    dest_id, custs1_val_write_ind,
                                                    param->length);
            memcpy(req_id->value, param->value, param->length);
            //req_id->conhdl = gapc_get_conhdl(custs1_env.con_info.conidx);
            req_id->handle = att_idx;
            req_id->length = param->length;
            
memcpy(&fake_custs1_val_write,req_id,(sizeof(struct custs1_val_write_ind) + param->length));
            ke_msg_send(req_id);
        }
    }

可以测试 00     ---    01 控制LED

这里把参数2找到了 前面的大参数1 呢

在malloc的时候出现了!!!!!!!

真相大白了 所以 这个大参数是RW内核自己控制的 在malloc的就指定了

(怀疑它不是一个数组再做生产消费 它有多个数组 用哪个数组生产呢 就是这个malloc约定的)

https://blog.csdn.net/adr5970/article/details/101306927

 

谁来调 gattc_write_req_ind_handler  只有

/// Default State handlers definition
const struct ke_msg_handler custs1_default_state[] =
{
    {GATTC_READ_REQ_IND,            (ke_msg_func_t)gattc_read_req_ind_handler},
    {GATTC_WRITE_REQ_IND,           (ke_msg_func_t)gattc_write_req_ind_handler},
    {GATTC_ATT_INFO_REQ_IND, 

 

const struct ke_state_handler custs1_default_handler = KE_STATE_HANDLER(custs1_default_state);
 

这个东西 放在一个接口 就不动了

static uint8_t custs1_init(struct prf_task_env *env, uint16_t *start_hdl, uint16_t app_task, uint8_t sec_lvl, struct custs1_db_cfg *params)
{

    for (uint8_t i = 0; i < custs1_services_size; i++)
    {
        // Create the service
        status = attm_svc_create_db_128(custs1_services[i],
                                        start_hdl,
                                        NULL,
                                        custs1_services[i+1],
                                        NULL,
                                        env->task,
                                        custs1_att_db,
                                        (sec_lvl & PERM_MASK_SVC_AUTH) | (sec_lvl & PERM_MASK_SVC_EKS) | PERM(SVC_PRIMARY, ENABLE));

    }

    if (status == ATT_ERR_NO_ERROR)
    {

        env->desc.default_handler   = &custs1_default_handler;
 
        ke_state_set(env->task, CUSTS1_IDLE);
    }

 

+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

直接开始自己完成一个LED 手机APP去写

 

 

#define DEF_SVC4_USER_DESC     "0000-off 0001-ON"

    SVC3_IDX_READ_3_CHAR,
    SVC3_IDX_READ_3_VAL,
    SVC3_IDX_READ_3_IND_CFG,
    SVC3_IDX_READ_3_USER_DESC,
    
    SVC4_IDX_SVC,
    
    SVC4_IDX_WRITE_CHAR,
    SVC4_IDX_WRITE_VAL,
    SVC4_IDX_WRITE_USER_DESC,

    CUSTS1_IDX_NB
};

const uint8_t custs1_services[]  = {SVC1_IDX_SVC, SVC2_IDX_SVC, SVC3_IDX_SVC, SVC4_IDX_SVC, CUSTS1_IDX_NB};
const uint8_t custs1_services_size = ARRAY_LEN(custs1_services) - 1;
const uint16_t custs1_att_max_nb = CUSTS1_IDX_NB;


static const att_svc_desc128_t custs1_svc4            = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0x0B, 0x10, 0x99, 0x2E, 0xC6, 0xFE, 0xED};
static const uint8_t DEF_SVC4_CTRL_POINT_UUID_128[]   = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0x00, 0x10, 0x99, 0x2E, 0xC6, 0xFE, 0xED};


    


// Service 1 Declaration
    [SVC4_IDX_SVC]                     = {(uint8_t*)&att_decl_svc, ATT_UUID_128_LEN, PERM(RD, ENABLE) | PERM(WR, ENABLE),
                                            sizeof(custs1_svc4), sizeof(custs1_svc4), (uint8_t*)&custs1_svc4},

    // Control Point Characteristic Declaration
    [SVC4_IDX_WRITE_CHAR]      = {(uint8_t*)&att_decl_char, ATT_UUID_16_LEN, PERM(RD, ENABLE),
                                            0, 0, NULL},

    // Control Point Characteristic Value
    [SVC4_IDX_WRITE_VAL]       = {DEF_SVC4_CTRL_POINT_UUID_128, ATT_UUID_128_LEN, PERM(WR, ENABLE) | PERM(WRITE_REQ, ENABLE),
                                            2*DEF_SVC1_CTRL_POINT_CHAR_LEN, 0, NULL},

    // Control Point Characteristic User Description
    [SVC4_IDX_WRITE_USER_DESC] = {(uint8_t*)&att_desc_user_desc, ATT_UUID_16_LEN, PERM(RD, ENABLE),
                                            sizeof(DEF_SVC4_USER_DESC) - 1, sizeof(DEF_SVC4_USER_DESC) - 1, DEF_SVC4_USER_DESC},

此时看到APP已经出现这个服务了

发送oooo 0001 看到handel就是我们的枚举

ADD一个LED函数

                case SVC4_IDX_WRITE_VAL:
                    user_svc4_wr_ind_handler(msgid, msg_param, dest_id, src_id);
                    break;

测试OK

发送0000关灯 0001开灯

+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

 

换个角度看问题

全局    SVC1_IDX_LED_STATE_VAL  关注额这个线索

 

第一个是枚举  每一个都是一个数组的成员  每一个数组成员都是一个服务

enum
{
    // Custom Service 1
    SVC1_IDX_SVC = 0,

    SVC1_IDX_CONTROL_POINT_CHAR,
    SVC1_IDX_CONTROL_POINT_VAL,
    SVC1_IDX_CONTROL_POINT_USER_DESC,

    SVC1_IDX_LED_STATE_CHAR,
    SVC1_IDX_LED_STATE_VAL,
    SVC1_IDX_LED_STATE_USER_DESC,

第二个是数组 这里面全部是蓝牙的服务  =一个profile 多个service

uint8_t interesting=10;
/// Full CUSTS1 Database Description - Used to add attributes into the database
const struct attm_desc_128 custs1_att_db[CUSTS1_IDX_NB] =
{
    /*************************
     * Service 1 configuration
     *************************
     */

	   //ͳһ Ò»¸öserver
    // Service 1 Declaration                       2800
    [SVC1_IDX_SVC]                     = {(uint8_t*)&att_decl_svc,
    			                                  ATT_UUID_128_LEN, PERM(RD, ENABLE),
                                            sizeof(custs1_svc1),
		                                        sizeof(custs1_svc1), 
		                                        (uint8_t*)&custs1_svc1},
                                         //DEF_SVC1_UUID_128
		

//ûÓÐʲôÒâÒå																				
    // Control Point Characteristic Declaration   2803
    [SVC1_IDX_CONTROL_POINT_CHAR]      = {(uint8_t*)&att_decl_char, 
			                                       ATT_UUID_16_LEN, PERM(RD, ENABLE),
                                            0, 
		                                       0, 
		                                       NULL},

//Ò»¸ö126bitµÄUUIDÃèÊöµÄ ÌØÕ÷Öµ
    // Control Point Characteristic Value  //UUID ´ó
    [SVC1_IDX_CONTROL_POINT_VAL]       = {SVC1_CTRL_POINT_UUID_128, 
			                                    ATT_UUID_128_LEN, PERM(RD, ENABLE),
                                          DEF_SVC1_CTRL_POINT_CHAR_LEN, 
		                                      0, 
		                                       (uint8_t *)&interesting}, 
//Ò»¸ö16bieµÄUUIDÃèÊöµÄ ÌØÕ÷ÖµÃèÊö
    // Control Point Characteristic User Description  2901
    [SVC1_IDX_CONTROL_POINT_USER_DESC] = {(uint8_t*)&att_desc_user_desc, 
																						ATT_UUID_16_LEN, PERM(RD, ENABLE),
                                            sizeof(DEF_SVC1_CONTROL_POINT_USER_DESC) - 1, 
																						sizeof(DEF_SVC1_CONTROL_POINT_USER_DESC) - 1,
                                            (uint8_t *) DEF_SVC1_CONTROL_POINT_USER_DESC}, 

																						
																						
																						
																						
																						
																						
    // LED State Characteristic Declaration
    [SVC1_IDX_LED_STATE_CHAR]          = {(uint8_t*)&att_decl_char, ATT_UUID_16_LEN, PERM(RD, ENABLE),
                                            0, 0, NULL},

    // LED State Characteristic Value
    [SVC1_IDX_LED_STATE_VAL]           = {SVC1_LED_STATE_UUID_128, ATT_UUID_128_LEN, PERM(WR, ENABLE) | PERM(WRITE_COMMAND, ENABLE),
                                            PERM(RI, ENABLE) | DEF_SVC1_LED_STATE_CHAR_LEN, 0, NULL},

    // LED State Characteristic User Description
    [SVC1_IDX_LED_STATE_USER_DESC]     = {(uint8_t*)&att_desc_user_desc, ATT_UUID_16_LEN, PERM(RD, ENABLE),
                                            sizeof(DEF_SVC1_LED_STATE_USER_DESC) - 1, sizeof(DEF_SVC1_LED_STATE_USER_DESC) - 1,
                                            (uint8_t *) DEF_SVC1_LED_STATE_USER_DESC},

第三个是这个任务回来的处理

                case SVC1_IDX_LED_STATE_VAL:
                    user_svc1_led_wr_ind_handler(msgid, msg_param, dest_id, src_id);
                    break;

                case SVC1_IDX_ADC_VAL_1_NTF_CFG://µã»÷Çл»ÐÇÐÇ¿ª¹Ø
                    user_svc1_adc_val_1_cfg_ind_handler(msgid, msg_param, dest_id, src_id);
                    break;

可以输入 1  0  控制LED开关

 

 

另外一个 没有使用 我们研究一下

 

 

 

 

 

 

 

 

					
{GATTC_WRITE_REQ_IND,           (ke_msg_func_t)gattc_write_req_ind_handler},

手机写的数据 马上到这里来						
gattc_write_req_ind_handler

从 gattc_write_req_ind_handler 再到 user_catch_rest_hndl 是通过 app_entry_point_handler 过来的
user_catch_rest_hndl  

那么user_catch_rest_hndl 是怎么调用 app_entry_point_handler 的?

看下面

 

/* Default State handlers definition. */
const struct ke_msg_handler app_default_state[] =
{
    {KE_MSG_DEFAULT_HANDLER,                (ke_msg_func_t)app_entry_point_handler},
        // {APP_TIMER_API_MES2,                    (ke_msg_func_t)app_second_timer_handler},
};

只需要发消息即可!右边就会去消费的!

并且 SDK只有这样一个消息!

 

 

一个似曾相识燕归来的函数


int app_entry_point_handler(ke_msg_id_t const msgid,
                            void const *param,
                            ke_task_id_t const dest_id,
                            ke_task_id_t const src_id)
{
    int i = 0;
    enum ke_msg_status_tag process_msg_handling_result;

    while (i < (sizeof(app_process_handlers) / sizeof(process_event_func_t)))
    {
        ASSERT_ERROR(app_process_handlers[i]);
         if (app_process_handlers[i](msgid, param, dest_id, src_id, &process_msg_handling_result) == PR_EVENT_HANDLED)
         {
             return (process_msg_handling_result);
         }
         i++;
    }

    //user cannot do anything else than consume the message
    if (app_process_catch_rest_cb != NULL)
    {
        app_process_catch_rest_cb(msgid,param, dest_id, src_id);
    }

    return (KE_MSG_CONSUMED);
};

消息ID都过了 消费 这个数组里面全部是函数 每个函数都把msgid拿去看看 不是我的就不管 类似

前面的各位大佬完成消费以后 再给最后的小弟 用户自己完成 app_process_catch_rest_cb(msgid,param, dest_id, src_id);

 

 

 

 

C基础知识 没有问题的

struct gattc_test
{
    uint16_t handle;
    uint8_t  value[3];
};

struct gattc_test A={0X1234,{3,4,5}};
struct gattc_test B={0};
void my_test(void)
{
memcpy(&B,&A,sizeof(struct gattc_test));
}
 

 

但是这个兄弟 用的是 柔性数组啊

struct gattc_write_req_ind
{
    /// Handle of the attribute that has to be written
    uint16_t handle;
    /// offset at which the data has to be written
    uint16_t offset;
    /// Data length to be written
    uint16_t length;
    /// Data to be written in attribute database
    uint8_t  value[__ARRAY_EMPTY];
};

最后是  uint8_t  value[]

 

啥意思

它的sizeof------6  也就是2+2+2 最后的这个value 不参加!!!!!!

 

那怎么办?再次表示一下我的问题

 struct gattc_write_req_ind AAAA={0};
static int gattc_write_req_ind_handler(ke_msg_id_t const msgid,
                                      struct gattc_write_req_ind const *param,
                                      ke_task_id_t const dest_id,
                                      ke_task_id_t const src_id)
{

    int msg_status = KE_MSG_CONSUMED;
  memcpy(&AAAA,param,sizeof(struct gattc_write_req_ind));---这里AAAA看不到数组!!

}
 

就是一个数字 这么看呢? 仔细看上面我测试C的小程序

我虽然memcpy了 但是 地址 不能修改的 !!!

 

那就这样做

uint32_t AAAADDR=0;
uint8_t *AAAADDRP=0;

    AAAADDR = (uint32_t)&param->value[0];
    AAAADDRP= (uint8_t *)param->value;

 

 

 

 

+++++++++++++++++++++++++++++

所以这个是比较符合我们公司这样的业务的 工程对比

可以看到

D:\A_CODE\6.0.10.511\projects\target_apps\ble_examples\mCube_mc36xx_data_notifcation\keil_v5

增加服务 类似外设LED 它是我们追加的 不是官方的SDK

我增加一个服务 XYZG 我是S  点击以后板子不停的notify ++到手机APP

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值