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