siliconLabs host 为啥接口必须在event中调用

在HOST模式下,接口所执行的动作一般都需要用到串口去和NCP进行通信的,
应用层下,EZSP层以上就是sendCommand函数,核心语句如下:

 sendingCommand = true;
  status = serialSendCommand();
  if (status == EZSP_SUCCESS) {
    status = responseReceived();
    while (status == RESPONSE_WAITING) 
		{
      status = responseReceived();
      ezspWaitingForResponse();
    }
  } else {
    EZSP_ASH_TRACE("sendCommand(): ezspErrorHandler(): 0x%x", status);
    ezspErrorHandler(status);
  }
  sendingCommand = false;

串口执行前将 sendingCommand = true;
串口执行完成将 sendingCommand = false;
并且这个过程还有一个 while (status == RESPONSE_WAITING) ,就是说这是“一应一答”的机制,有发送就必须要收到响应数据的。

若是收不到数据就会阻塞在这里,这个阻塞就是整个系统在阻塞!等待NCP串口在响应数据。
这个目的是保证串口资源在线程安全。规避串口同一时间被多个线程访问使用。

回过头来看整个host其实是没有真正意义上的任务或者线程的,main函数emberAfMain里面就是一个while(1)的循环,在这个dead-loop里一直轮询event
这里与TI的OSAL是一样的,OSAL的串口是使用队列来发送,每个event只管往队列里丢数据,只有一个event专门负责操作串口资源,就不存在线程安全问题。

在这个dead-loop里还在不断在检查串口是否被其他线程占用了, assert(!sendingCommand);

 while (true) {
    halResetWatchdog();   // Periodically reset the watchdog.

    // see if the NCP has anything waiting to send us
    ezspTick();
    }


void ezspTick(void)
{
  uint8_t count = serialPendingResponseCount() + 1;
  // Ensure that we are not being called from within a command.
  vDEBUG_PRINTF_ERROR1("555->%d",sendingCommand);
  assert(!sendingCommand);
  while (count > 0 && responseReceived() == RESPONSE_SUCCESS) {
    callbackDispatch();
    count--;
  }
  simulatedTimePasses();
}

到这里就明白为啥只能在event里执行接口调用了:

在event里调用接口会阻塞整个event的轮询,进而阻塞了系统对串口资源在占用情况的检查,若是自己写个线程调用接口函数,执行到sendCommand阻塞的是自己创建的那个线程,并没有将系统阻塞住,main的那个while轮询还是在继续,对串口资源的线程安全检查也在继续,当发现有两个线程(main的while(1)和自己创建的线程)在访问串口资源就报错了!

感觉silicon很朴实,用最简单的办法实现线程安全。

猜你喜欢

转载自blog.csdn.net/H542723151/article/details/83385152