1. 程式人生 > >siliconLabs host 為啥介面必須在event中呼叫

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很樸實,用最簡單的辦法實現執行緒安全。