3743|7

1379

帖子

2

TA的资源

五彩晶圆(初级)

楼主
 

关于RSL10 SDK中Event Kernel部分的代码分析(上) [复制链接]

 

  本人在一个多月以前就开始分析官方给的工程范例了,然而对其中的函数回调用法没有看懂,自己的项目实验也就因此卡住了,拖到了现在。估计有许多网友也遇到了同样的问题,所以在此把这段时间的学习分析心得总结出来,希望对大家开发RSL10程序有帮助。

 

  RSL10 的 BLE 程序要依赖于 Event Kernel, 这个 Kernel 是个啥?
  随便找 BLE 应用的若干例子,在其 app.c 中可以见到,主函数到了最后是一个循环,里面都含有这三个调用:
        Kernel_Schedule();
        Sys_Watchdog_Refresh();
        SYS_WAIT_FOR_EVENT;

第二个是刷新WDT, 第三个是使用 ARM 的 WFE 指令进入低功耗模式,等待硬件唤醒,然后再次执行 Kernel_Schedule(). 明显,这是一个 RTOS 吗?这个和FreeRTOS的调度器不一样。关键的是,代码其它地方也看不到多任务系统的特征——每个任务独立的堆栈。所以,大胆猜测:这个调度器,是根据事件去调用若干函数而已。
 

  在 ble_peripheral_server_hrp 这个例子里面,在 main() 开始就调用的 Device_Initialize() 函数中,执行了一条

    ke_task_create(TASK_APP, &TASK_DESC_APP);

乍一看,像是一个 RTOS 创建了一个任务呢,可是这个调用的参数又很诡异,不像。在 ON 的文档《RSL10 Firmware Reference》中,竟然没有对这个函数的说明。纵观整个代码,除了创建这个 TASK_APP 也没有创建别的“任务”了。这当然不对,如果是支持多任务的话,多个任务(线程)函数总要有吧。
  因为 ke_task_create() 没有提供源代码,从头文件给出的定义来看:

/****************************************************************************************
 * [url=home.php?mod=space&uid=159083]@brief[/url] Create a task.
 *
 * @param[in]  task_type       Task type.
 * @param[in]  p_task_desc     Pointer to task descriptor.
 *
 * [url=home.php?mod=space&uid=784970]@return[/url] Status
 ***************************************************************************************/
uint8_t ke_task_create(uint8_t task_type, struct ke_task_desc const * p_task_desc);

第一个参数是 8-bit 的 task 类型, 第二个参数指向一个 task descriptor (ke_task_desc结构体). 那么就看看这个结构体的定义:

/// Task descriptor grouping all information required by the kernel for the scheduling.
struct ke_task_desc
{
    /// Pointer to the state handler table (one element for each state).
    const struct ke_state_handler* state_handler;
    /// Pointer to the default state handler (element parsed after the current state).
    const struct ke_state_handler* default_handler;
    /// Pointer to the state table (one element for each instance).
    ke_state_t* state;
    /// Maximum number of states in the task.
    uint16_t state_max;
    /// Maximum index of supported instances of the task.
    uint16_t idx_max;
};

  推测,一个 task 可以有多种状态,每个状态可以有不同的 handler 函数(用途是处理消息)。一个 task 类型可以有多个实例。

 

  在 ble_peripheral_server_hrp 中,ke_task_create() 使用的 TASK_DESC_APP 这个结构常量定义为:

static const struct ke_task_desc TASK_DESC_APP = {
    .state_handler = NULL,
    .default_handler = &appm_default_handler,
    .state = appm_state,
    .state_max = 0,
    .idx_max = APP_IDX_MAX
};

其中 state_handler 是空指针,不起作用。默认的 handler 是 appm_default_handler, 这是 ke_state_handler 结构类型:

struct ke_state_handler
{
    /// Pointer to the message handler table of this state.
    const struct ke_msg_handler *msg_table;
    /// Number of messages handled in this state.
    uint16_t msg_cnt;
};

其中包含一个指针和一个16-bit数,指针是指向 ke_msg_handler 结构类型。

struct ke_msg_handler
{
    /// Id of the handled message.
    ke_msg_id_t id;
    /// Pointer to the handler function for the msgid above.
    ke_msg_func_t func;
};

 

  在这个例子中,appm_default_handler 定义是:

static const struct ke_state_handler appm_default_handler
    = KE_STATE_HANDLER(appm_default_state);

static const struct ke_msg_handler appm_default_state[] =
{
    { KE_MSG_DEFAULT_HANDLER, (ke_msg_func_t)MsgHandler_Notify }
};

KE_STATE_HANDLER 这个宏定义是 

#define KE_STATE_HANDLER(hdl) {hdl, sizeof(hdl)/sizeof(struct ke_msg_handler)}

 

  代码看着不明显,我总结成个图:

  ble_peripheral_server_hrp 中 appm_default_state 这个表很简单,只有一项,handler 函数是 MsgHandler_Notify(), 这个函数是 SDK 中提供的,有源代码。但并不是说只用一个 handler 函数就足够。另外看一个例子:peripheral_server 中,appm_default_state[] 表有5项:

const struct ke_msg_handler appm_default_state[] =
{
    /* Note: Put the default handler on top as this is used for handling any
     *       messages without a defined handler */
    { KE_MSG_DEFAULT_HANDLER, (ke_msg_func_t)Msg_Handler },
    BLE_MESSAGE_HANDLER_LIST,
    BASS_MESSAGE_HANDLER_LIST,
    CS_MESSAGE_HANDLER_LIST,
    APP_MESSAGE_HANDLER_LIST
};

  这么看来,表的用法还不清楚,每个 handler 函数各自的作用也不清楚。

 

  我用 GDB 调试了 ble_peripheral_server_hrp 的执行,在 ke_task_create() 函数入口设置断点,发现在 BLE_InitNoTL() 中调用了很多次 ke_task_create(). 其中 task type 为 0x0A 到 0x31 的调用,第二个参数指向的地址位于 SRAM 中 prf_env 全局变量内,值为全0。其它的调用,第二个参数指向的是 flash 的地址,是程序中的只读常量,有:

TASK_DESC_GAPM
TASK_DESC_GAPC
TASK_DESC_GATTM
TASK_DESC_GATTC
TASK_DESC_L2CC
TASK_DESC_LLD
TASK_DESC_LLC
TASK_DESC_LLM
  这些常量来自于二进制库,可以在 GDB 下查看,如,查看 TASK_DESC_GAPC 这个任务描述结构

(gdb) print *(struct ke_task_desc *)TASK_DESC_GAPC
$2 = {state_handler = 0x0, default_handler = 0x124afc <gapc_default_handler>,
  state = 0x200020b0 <gapc_state> "????????", state_max = 64, idx_max = 8}

(gdb) print *(struct ke_state_handler *)gapc_default_handler
$4 = {msg_table = 0x124b04 <gapc_default_state>, msg_cnt = 38}

(gdb) print *(struct ke_msg_handler *)gapc_default_state
$5 = {id = 65535, func = 0x118f73 <gapc_default_msg_handler+1>}

  gapc_default_state 表有38项,第一项的 handler 是 gapc_default_msg_handler
  要看最后一项,可以这样
(gdb) print ((struct ke_msg_handler *)gapc_default_state)[37]
$25 = {id = 3639,
  func = 0x119a0d <gapc_set_max_rx_size_and_time_cmd_handler+1>}

  直接地,还可以写成
(gdb) print ((struct ke_task_desc *)TASK_DESC_GAPC)->default_handler->msg_table[37]

这样可以发现很多的 handler 函数了,它们又是怎样被使用的呢?
 

  现在来看下 handler 函数的类型定义:

/// Format of a task message handler function
typedef int (*ke_msg_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);

  当一个 handler 被调用的时候,会传给它 4 个参数。这正好是一个消息要包含的内容。在手册里给出了描述:

  在 ke_msg.h 头文件中定义了

/// Message structure.
struct ke_msg
{
    struct co_list_hdr hdr;     ///< List header for chaining

    ke_msg_id_t     id;         ///< Message id.
    ke_task_id_t    dest_id;    ///< Destination kernel identifier.
    ke_task_id_t    src_id;     ///< Source kernel identifier.
    uint16_t        param_len;  ///< Parameter embedded struct length.
    uint32_t        param[1];   ///< Parameter embedded struct. Must be word-aligned.
};

其中的 struct co_list_hdr 类型成员是用来构造链表的,暂且不管。后面有三个字段较为关键:消息的ID, 消息目标(task)的id, 和消息来源(task)的id. 剩下的是消息带的数据(payload)。

 

  前面已经说过 task 类型,那么 task id 又是啥?

  根据定义

/// Task Identifier. Composed by the task type and the task index.
typedef uint16_t ke_task_id_t;

/// Builds the task identifier from the type and the index of that task.
#define KE_BUILD_ID(type, index) ( (ke_task_id_t)(((index) << 8)|(type)) )

知道了 task id 是一个16-bit数据,低8位是 task 类型,高8位是 "task index" ——如何用?我假设是实例的索引(一个task类型可以有多个实例)。

 

  消息的 ID 也是个16-bit数据, 在头文件中写了注释

/// Message Identifier. The number of messages is limited to 0xFFFF.
/// The message ID is divided in two parts:
/// bits[15~8]: task index (no more than 255 tasks support)
/// bits[7~0]: message index(no more than 255 messages per task)
typedef uint16_t ke_msg_id_t;

  这样一来,消息 ID 包含 task index 和 message index 两部分。但是不清楚了,此 task 又对应接收方还是发送方,还是可能有其它?

  注释的说明和手册有所不同:

  按照手册说的,一个 task 的第一个消息 ID, 高8位就是 task 类型。task type 和 task index 必然不是同一个东西,不然 task id 就不会包含两者了。晕了!

 

  还是找代码来验证吧。

  使用了 TASK_FIRST_MSG 宏的地方,例如:

/// Messages for Battery Server
enum bass_msg_id
{
    /// Start the Battery Server - at connection used to restore bond data
    BASS_ENABLE_REQ = TASK_FIRST_MSG(TASK_ID_BASS),
    /// Confirmation of the Battery Server start
    BASS_ENABLE_RSP,
    /// Battery Level Value Update Request
    BASS_BATT_LEVEL_UPD_REQ,
    /// Inform APP if Battery Level value has been notified or not
    BASS_BATT_LEVEL_UPD_RSP,
    /// Inform APP that Battery Level Notification Configuration has been changed - use to update bond data
    BASS_BATT_LEVEL_NTF_CFG_IND,
};

定义这些消息ID的高8位是 TASK_ID_BASS, 低8位则从0开始计数。
  再查找 TASK_ID_BASS 的定义,在 rwip_task.h 当中:

/// Tasks types definition, this value shall be in [0-254] range
enum TASK_API_ID
{
    // Link Layer Tasks
    TASK_ID_LLM          = 0,
    TASK_ID_LLC          = 1,
    TASK_ID_LLD          = 2,
    TASK_ID_DBG          = 3,

    // BT Controller Tasks
    TASK_ID_LM           = 4,
    TASK_ID_LC           = 5,
    TASK_ID_LB           = 6,
    TASK_ID_LD           = 7,

    TASK_ID_HCI          = 8,
    TASK_ID_DISPLAY      = 9,

    // -----------------------------------------------------------------------------------
    // --------------------- BLE HL TASK API Identifiers ---------------------------------
    // -----------------------------------------------------------------------------------

    TASK_ID_L2CC         = 10,   // L2CAP Controller Task
    TASK_ID_GATTM        = 11,   // Generic Attribute Profile Manager Task
    TASK_ID_GATTC        = 12,   // Generic Attribute Profile Controller Task
    TASK_ID_GAPM         = 13,   // Generic Access Profile Manager
    TASK_ID_GAPC         = 14,   // Generic Access Profile Controller

    TASK_ID_APP          = 15,   // Application API
    TASK_ID_AHI          = 16,   // Application Host Interface

    // -----------------------------------------------------------------------------------
    // --------------------- BLE Profile TASK API Identifiers ----------------------------
    // -----------------------------------------------------------------------------------
    TASK_ID_DISS         = 20,   // Device Information Service Server Task
    TASK_ID_DISC         = 21,   // Device Information Service Client Task

    TASK_ID_PROXM        = 22,   // Proximity Monitor Task
    TASK_ID_PROXR        = 23,   // Proximity Reporter Task

    TASK_ID_FINDL        = 24,   // Find Me Locator Task
    TASK_ID_FINDT        = 25,   // Find Me Target Task

    TASK_ID_HTPC         = 26,   // Health Thermometer Collector Task
    TASK_ID_HTPT         = 27,   // Health Thermometer Sensor Task

    TASK_ID_BLPS         = 28,   // Blood Pressure Sensor Task
    TASK_ID_BLPC         = 29,   // Blood Pressure Collector Task

    TASK_ID_HRPS         = 30,   // Heart Rate Sensor Task
    TASK_ID_HRPC         = 31,   // Heart Rate Collector Task

    TASK_ID_TIPS         = 32,   // Time Server Task
    TASK_ID_TIPC         = 33,   // Time Client Task

    TASK_ID_SCPPS        = 34,   // Scan Parameter Profile Server Task
    TASK_ID_SCPPC        = 35,   // Scan Parameter Profile Client Task

    TASK_ID_BASS         = 36,   // Battery Service Server Task
    TASK_ID_BASC         = 37,   // Battery Service Client Task

这里的代码才是 task id 的诠释。那么,task type 呢?

  在 rwip_config.h 中定义了

/// Tasks types definition
enum KE_TASK_TYPE
{
#if (BT_EMB_PRESENT)
    // BT Controller Tasks
    TASK_LM,
    TASK_LC,
    TASK_LB,
    TASK_LD,
    TASK_HCI,
#endif // (BT_EMB_PRESENT)

#if (BLE_EMB_PRESENT)
    // Link Layer Tasks
    TASK_LLM ,
    TASK_LLC ,
    TASK_LLD ,
#endif // (BLE_EMB_PRESENT)

#if ((BLE_EMB_PRESENT) || (BT_EMB_PRESENT))
    TASK_DBG,
#endif // ((BLE_EMB_PRESENT) || (BT_EMB_PRESENT))

#if (DISPLAY_SUPPORT)
    TASK_DISPLAY,
#endif // (DISPLAY_SUPPORT)

#if (BLE_APP_PRESENT)
    TASK_APP,
#endif // (BLE_APP_PRESENT)

#if (BLE_HOST_PRESENT)
    TASK_L2CC,    // L2CAP Controller Task
    TASK_GATTM,   // Generic Attribute Profile Manager Task
    TASK_GATTC,   // Generic Attribute Profile Controller Task
    TASK_GAPM,    // Generic Access Profile Manager
    TASK_GAPC,    // Generic Access Profile Controller

    // allocate a certain number of profiles task
    TASK_PRF_MAX = (TASK_GAPC + BLE_NB_PROFILES),

    #ifdef BLE_AUDIO_AM0_TASK
    TASK_AM0,     // BLE Audio Mode 0 Task
    #endif // BLE_AUDIO_AM0_TASK
#endif // (BLE_HOST_PRESENT)

#if (AHI_TL_SUPPORT)
    TASK_AHI,
#endif // (AHI_TL_SUPPORT)

    /// Maximum number of tasks
    TASK_MAX,

    TASK_NONE = 0xFF,
};

 

  可见,task type 和 task index 都是预定义的常量。而且 task index 值的意义是固定的,并非动态分配。task type 值对应的任务类型可以配置,不完全固定。然后,task type 和 task index 看起来不能随意组合成一个有效的 task id. 消息ID里面包含的,是 task index 而非 task type, 文档的叙述不确切。

 

  来看一个工程代码中涉及到 task id 的调用:

   ke_timer_set(LED_TIMER, TASK_APP, TIMER_2S_SETTING);

  这个函数原型是:

/* @param[in] timer_id      Timer identifier (message identifier type).
 * @param[in] task_id       Task identifier which will be notified
 * @param[in] delay         Delay in time units.                 ******/
void ke_timer_set(ke_msg_id_t const timer_id, ke_task_id_t const task, uint32_t delay);

其中的第二个参数是 ke_task_id_t 类型的,在调用中传入参数是 TASK_APP, 这是一个 task type 值。这样的话,高8位,即 task index 被置0了。又晕了。

 

  再看一处调用:

    cmd = KE_MSG_ALLOC(GAPM_RESET_CMD, TASK_GAPM, TASK_APP, gapm_reset_cmd);

隐含调用的是函数

void *ke_msg_alloc(ke_msg_id_t const id, ke_task_id_t const dest_id,
                   ke_task_id_t const src_id, uint16_t const param_len);

仍然是 TASK_GAPM, TASK_APP 两个 task type 值被用作了需要 task id 的参数。

 

  既然如此用法是能工作的,那么 task index 在实际中并不是很重要?尚且不明白的是,task type, task index 在消息处理过程中的作用是什么。

 

  我将 ble_peripheral_server_hrp 例子稍做修改,用自己的 handler 替换原来的,以便插入调试代码:

int My_MsgHandler(ke_msg_id_t const msg_id, void *param,
                ke_task_id_t const dest_id, ke_task_id_t const src_id)
{
	PRINTF("[%04X: %04X<-%04X]\n", msg_id, dest_id, src_id);

	return MsgHandler_Notify(msg_id, param, dest_id, src_id);
}

  然后重新编译,烧写,运行。在 RTT Viewer 中看到:

00> 
00> ble_peripheral_server_bond has started 20:34:28!
00> [0D01: 0004<-0008]
00> conidx=0 [0D00: 0004<-0008]
00> conidx=0 [0D00: 0004<-0008]
00> conidx=0 [0D1C: 0004<-0008]
00> conidx=0 [0D00: 0004<-0008]
00> conidx=0 [0D1C: 0004<-0008]
00> conidx=0 [0D00: 0004<-0008]
00> conidx=0 [0D1C: 0004<-0008]
00> conidx=0 [0D00: 0004<-0008]
00> conidx=0 [0F01: 0004<-00FF]
00> [0F01: 0004<-00FF]
00> [0F01: 0004<-00FF]
00> [0F01: 0004<-00FF]
00> [1E32: 0004<-00FF]
00> [0F01: 0004<-00FF]
00> [0F01: 0004<-00FF]
00> [0F01: 0004<-00FF]
00> [0F01: 0004<-00FF]
00> [0F01: 0004<-00FF]
00> [1E32: 0004<-00FF]

  My_MsgHandler 处理过的以上消息,参数中 task id 对应的 task index 都是0, 即仅含有 task type. 但是消息ID都包含了task index. 那么消息ID的task index是发送方还是接收方?看似都有可能。

  由 Kernel_Schedule() 来处理所有的消息,选择恰当的 handler, 那么它首先要决定的是在哪个 task (type)的 handler 函数列表中查找。根据上面测试结果,应当是由消息的 dest_id 包含的 task type 来决定。

  如前所述,一个 task 的 handler 函数可以不止一个,在 ke_msg_handler 结构中有一个id成员表示了消息ID, 那就意味着有一种根据消息ID进行匹配的机制。由于这部分代码是二进制的,不容易看它是如何匹配的。

  用 GDB 查看了一下 TASK_GATTM 的 default_handler 列表,一共8个,包括消息ID与 handler 函数

id = 65535, func = 0x1129bf <gattm_default_msg_handler+1>
id = 2816, func = 0x112b0f <gattm_add_svc_req_handler+1>
id = 2818, func = 0x112ae5 <gattm_svc_get_permission_req_handler+1>
id = 2820, func = 0x112abb <gattm_svc_set_permission_req_handler+1>
id = 2822, func = 0x112a75 <gattm_att_get_permission_req_handler+1>
id = 2824, func = 0x112a49 <gattm_att_set_permission_req_handler+1>
id = 2826, func = 0x1129f1 <gattm_att_get_value_req_handler+1>
id = 2828,

func = 0x1129c3 <gattm_att_set_value_req_handler+1>

 

 

 

 

 

 

 

 

 

 

  除了第一项的ID为0xFFFF外,后面7项ID的高8位都是0x0B, 也就是对应 TASK_ID_GATTM. 
  在 gattm_task.h 中找到消息ID的定义:
 

/// GATT Task messages
enum gattm_msg_id
{
    /* Database Management */
    /// Add service in database request
    GATTM_ADD_SVC_REQ = TASK_FIRST_MSG(TASK_ID_GATTM),
    /// Add service in database response
    GATTM_ADD_SVC_RSP,

    /* Service management */
    /// Get permission settings of service request
    GATTM_SVC_GET_PERMISSION_REQ,
    /// Get permission settings of service response
    GATTM_SVC_GET_PERMISSION_RSP,
    /// Set permission settings of service request
    GATTM_SVC_SET_PERMISSION_REQ,
    /// Set permission settings of service response
    GATTM_SVC_SET_PERMISSION_RSP,

    /* Attribute Manipulation */
    /// Get permission settings of attribute request
    GATTM_ATT_GET_PERMISSION_REQ,
    /// Get permission settings of attribute response
    GATTM_ATT_GET_PERMISSION_RSP,
    /// Set permission settings of attribute request
    GATTM_ATT_SET_PERMISSION_REQ,
    /// Set permission settings of attribute response
    GATTM_ATT_SET_PERMISSION_RSP,

    /// Get attribute value request
    GATTM_ATT_GET_VALUE_REQ,
    /// Get attribute value response
    GATTM_ATT_GET_VALUE_RSP,
    /// Set attribute value request
    GATTM_ATT_SET_VALUE_REQ,
    /// Set attribute value response
    GATTM_ATT_SET_VALUE_RSP,

    /* Debug messages */
    /// DEBUG ONLY: Destroy Attribute database request
    GATTM_DESTROY_DB_REQ,
    /// DEBUG ONLY: Destroy Attribute database response
    GATTM_DESTROY_DB_RSP,
    /// DEBUG ONLY: Retrieve list of services request
    GATTM_SVC_GET_LIST_REQ,
    /// DEBUG ONLY: Retrieve list of services response
    GATTM_SVC_GET_LIST_RSP,
    /// DEBUG ONLY: Retrieve information of attribute request
    GATTM_ATT_GET_INFO_REQ,
    /// DEBUG ONLY: Retrieve information of attribute response
    GATTM_ATT_GET_INFO_RSP,
};

 

  翻译出来,表中消息ID与handler函数是:

    GATTM_ADD_SVC_REQ              ----- gattm_add_svc_req_handler
    GATTM_SVC_GET_PERMISSION_REQ   ----- gattm_svc_get_permission_req_handler
    GATTM_SVC_SET_PERMISSION_REQ   ----- gattm_svc_set_permission_req_handler
    GATTM_ATT_GET_PERMISSION_REQ   ----- gattm_att_get_permission_req_handler
    GATTM_ATT_SET_PERMISSION_REQ   ----- gattm_att_set_permission_req_handler
    GATTM_ATT_GET_VALUE_REQ        ----- gattm_att_get_value_req_handler
    GATTM_ATT_SET_VALUE_REQ        ----- gattm_att_set_value_req_handler

刚好名称都对应上了。看来第一个 gattm_default_msg_handler 是用来处理余下的没有对应ID的消息的。反汇编了一下,发现它什么都没有做,就算处理完了。
(gdb) disass gattm_default_msg_handler
Dump of assembler code for function gattm_default_msg_handler:
   0x001129be <+0>:     movs    r0, #0
   0x001129c0 <+2>:     bx      lr
End of assembler dump.

这表明,在正常情况下是不应当有除了以上7种ID的消息之外的任何消息,发送给 GATTM_TASK 的。

 

  至此,我大概明白了Event Kernel 涉及到的 task 是怎样一个概念,消息发送给一个 task 时,调度器如何选择其默认的 handler 函数列表中的函数来处理消息。

 

最新回复

看着像是基于消息驱动的处理架构,任务间的协作都是通过发送消息来处理的,但是又叫event_kernel事件内核,一开始以为是事件驱动呢,楼主分析的很细致,有些代码不开源,分析确实会比较难懂   详情 回复 发表于 2021-6-12 10:08
点赞(2) 关注
 
 

回复
举报

6807

帖子

0

TA的资源

五彩晶圆(高级)

沙发
 

经验之谈,

楼主把自己陌生学习分析心得总结出来,肯定会对大家开发RSL10程序有帮助的

这次活动 ON 的文档RSL10 Firmware Reference有的地方说明确实欠缺,该说明的没说

 
 
 

回复

85

帖子

2

TA的资源

一粒金砂(中级)

板凳
 

谢谢楼主分享!因忙做不到像楼主一样做细致深入工作,点个赞!功在当代,利在千秋!先收藏下来用时学习,谢啦~

 
 
 

回复

1239

帖子

68

TA的资源

纯净的硅(中级)

4
 

前来学习,话说,这个芯片资料上手难度比常用的芯片确实高了点,估计是用的人少的原因吧,网上关于它的资料太少了。

 
 
 

回复

828

帖子

216

TA的资源

管理员

5
 

谢谢分享,辛苦楼主了。

加EE小助手好友,
入技术交流群
EE服务号
精彩活动e手掌握
EE订阅号
热门资讯e网打尽
聚焦汽车电子软硬件开发
认真关注技术本身
个人签名在路上……

EEworld 有你有我
 
 
 

回复

7608

帖子

18

TA的资源

五彩晶圆(高级)

6
 

回调确实严重阻碍静态代码分析,跑跑就不知道调哪里去了。

个人签名

默认摸鱼,再摸鱼。2022、9、28

 
 
 

回复

3416

帖子

0

TA的资源

纯净的硅(高级)

7
 
本帖最后由 ljj3166 于 2021-6-9 23:05 编辑

真牛,还没这么仔细考虑过

不过我觉得这个所谓kernel本质上只是完成了一个BLE协议栈软件定时器的调度工作

更像是一个链表或者队列的调度

所有task是根据软件定时器的ID和handler来完成处理

至于index,可能只是对应软件定时器在链表或者队列索引吧

个人签名

So TM what......?

 

 
 

回复

1976

帖子

0

TA的资源

五彩晶圆(初级)

8
 

看着像是基于消息驱动的处理架构,任务间的协作都是通过发送消息来处理的,但是又叫event_kernel事件内核,一开始以为是事件驱动呢,楼主分析的很细致,有些代码不开源,分析确实会比较难懂

 
 
 

回复
您需要登录后才可以回帖 登录 | 注册

查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/8 下一条

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2025 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表