wakojosin 发表于 2024-3-15 22:33

KW41Z板卡Openthread源码学习(二)

<p><span style="font-size:16px;"><strong>前言</strong></span></p>

<p>本篇主要从main函数入手分析整个执行过程。主要就是整理了调用过程,带有简单的注释,协议栈没有深入,深入内容有点多。</p>

<p>&nbsp;</p>

<p><span style="font-size:16px;"><strong>源码整理</strong></span></p>

<p>主函数</p>

<pre>
<code class="language-cpp">/* openthread/example/apps/cli/main.c */
int main(int argc, char *argv[])
{
    otInstance *instance;

    OT_SETUP_RESET_JUMP(argv);

pseudo_reset:
        // 调用src/system.c中的otSysInit函数来初始化引脚、时钟等
    otSysInit(argc, argv);
        // 单例模式得到openthread对象
    instance = otInstanceInitSingle();

    assert(instance);

        // 调用openthread/examples/apps/cli/cli_uart.cpp中的
        // extern "C" void otAppCliInit(otInstance *aInstance)
        // 间接调用了src/uart.c中的otPlatUartEnable()
        // 以及openthread/src/cli/cli.cpp中的
        // extern "C" void otCliInit(otInstance *aInstance, otCliOutputCallback aCallback, void *aContext)
        // 实例化了一个解释器对象。
    otAppCliInit(instance);

        // 向解释器注册命令
    IgnoreError(otCliSetUserCommands(kCommands, OT_ARRAY_LENGTH(kCommands), instance));
        // 如果不发生关机和重新初始化的情况就一直进行这个循环
    while (!otSysPseudoResetWasRequested())
    {
                // 间接调用openthread/src/core/common/tasklet.cpp中的
                // void Tasklet::Scheduler::ProcessQueuedTasklets(void)
                // 用于处理注册的任务
      otTaskletsProcess(instance);
                // 间接调用src/system.c中的void otSysProcessDrivers(otInstance *aInstance)
                // 用于处理来自硬件的请求,比如串口、射频、定时器等。
      otSysProcessDrivers(instance);
    }

    otInstanceFinalize(instance);

    goto pseudo_reset;

    return 0;
}</code></pre>

<p>openthread/src/core/common/tasklet.hpp</p>

<p>这部分是整个openthread的核心,支撑起了其他模块的正常运行,当模块发生事件后就会将任务挂到调度器中等待被调度。</p>

<pre>
<code class="language-cpp">/*任务类定义,后面会还有上下文的任务和特定类型的任务模块,不展开*/
class Tasklet : public InstanceLocator
{
public:
    /**
   * 任务调度器类
   *
   */
    class Scheduler : private NonCopyable
    {
      friend class Tasklet;

    public:
      /**
         * 调度器初始化
         *
         */
      Scheduler(void)
            : mTail(nullptr)
      {
      }

      /**
         * 只是是否有任务挂起.
         *
         * @retval TRUE   If there are tasklets pending.
         * @retval FALSEIf there are no tasklets pending.
         *
         */
      bool AreTaskletsPending(void) const { return mTail != nullptr; }

      /**
         * 处理所有运行队列中的任务。
         *
         */
      void ProcessQueuedTasklets(void);

    private:
      void PostTasklet(Tasklet &amp;aTasklet);

      Tasklet *mTail; // A circular singly linked-list
    };

    /**
   * 任务回调函数定义.
   *
   * @paramaTaskletA reference to the tasklet being run.
   *
   */
    typedef void (&amp;Handler)(Tasklet &amp;aTasklet);

    /**
   * 任务构造函数(任务对象创建),初始化内部成员属性.
   *
   * @paramaInstance   A reference to the OpenThread instance object.
   * @paramaHandler    A pointer to a function that is called when the tasklet is run.
   *
   */
    Tasklet(Instance &amp;aInstance, Handler aHandler)
      : InstanceLocator(aInstance)
      , mHandler(aHandler)
      , mNext(nullptr)
    {
    }

    /**
   * 将任务放到任务列表中。
   *
   * If the tasklet is already posted, no change is made and run queue stays as before.
   *
   */
    void Post(void);

    /**
   * 指示任务是否注册到任务列表中.
   *
   * @retval TRUEThe tasklet is posted.
   * @retval FALSE The tasklet is not posted.
   *
   */
    bool IsPosted(void) const { return (mNext != nullptr); }

private:
    void RunTask(void) { mHandler(*this); }

    HandlermHandler;
    Tasklet *mNext;
};</code></pre>

<p>命令处理</p>

<pre>
<code>// 串口命令处理过程
void kw41zUartProcess(void);
        static void processReceive(void);
                void otPlatUartReceived(const uint8_t *aBuf, uint16_t aBufLength);
                        static void ReceiveTask(const uint8_t *aBuf, uint16_t aBufLength);
                                ProcessCommand();
// 承接上面
static otError ProcessCommand(void);
        extern "C" void otCliInputLine(char *aBuf);
                void Interpreter::ProcessLine(char *aBuf);
                        // 解析字符串,获取命令
                        SuccessOrExit(error = Utils::CmdLineParser::ParseCmd(aBuf, args, kMaxArgs));
                        // 执行命令,内部定义了任务列表kCommands
                        // 任务列表包含了命令及其解释器
                        // 所有命令的执行在此完成
                        ProcessCommand(args);</code></pre>

<p>射频</p>

<pre>
<code class="language-cpp">// 射频接收处理过程
void kw41zRadioProcess(otInstance *aInstance);
        extern "C" void otPlatRadioReceiveDone(otInstance *aInstance, otRadioFrame *aFrame, otError aError);
                void Radio::Callbacks::HandleReceiveDone(Mac::RxFrame *aFrame, Error aError);
                        void SubMac::HandleReceiveDone(RxFrame *aFrame, Error aError);
                                void SubMac::Callbacks::ReceiveDone(RxFrame *aFrame, Error aError);
                                        Get&lt;LinkRaw&gt;().InvokeReceiveDone(aFrame, aError);
                                        Get&lt;Mac&gt;().HandleReceivedFrame(aFrame, aError);
// 承上Get&lt;LinkRaw&gt;().InvokeReceiveDone(aFrame, aError);
void LinkRaw::InvokeReceiveDone(RxFrame *aFrame, Error aError);
        void NcpBase::LinkRawReceiveDone(otInstance *aInstance, otRadioFrame *aFrame, otError aError);
                otError NcpBase::PackRadioFrame(otRadioFrame *aFrame, otError aError);

// 承上Get&lt;Mac&gt;().HandleReceivedFrame(aFrame, aError);
void Mac::HandleReceivedFrame(RxFrame *aFrame, Error aError);
        // 后面就是对数据的解析处理,根据数据类型执行不同的操作
        // 展开就是协议栈的实现了,所以不深入。</code></pre>

<p><span style="font-size:16px;"><strong>小结</strong></span></p>

<p>源码整理了命令处理和射频处理,基本上还是比较清楚的,接下来先实现一个功能实时效果吧。</p>

Jacktang 发表于 2024-3-17 16:26

<p>源码整理了命令处理和射频处理确实是清楚的</p>

freebsder 发表于 2024-3-19 15:28

<p>openthread这几年好像没看见在推了。</p>
页: [1]
查看完整版本: KW41Z板卡Openthread源码学习(二)