RTOS WoT (v0.1.0) 使用 FreeRTOS、 lwIP 與 C++ 元件重用
.作者:jollen/
.日期:January 7, 2016 10:57 AM
沿續前一個 Web of Things 的實驗計畫在 NodeMCU 上使用 er-coap-13,RTOS WoT 使用由 SuperHouse 開發的 esp-open-rtos 版本,進行一些實驗性質的修改。esp-open-rtos 同樣是基於 Espressif 官方的 Espressif IOT RTOS SDK,但改採 open source 版本的 FreeRTOS 與 lwIP 程式碼。
本文章採用 Markdown 語法撰寫(why?),若無法完整閱讀全文,請點擊這裡。
關於 libc
標準 C 程式庫(libc)部份,esp-open-rtos 改用 newlib 來取代 Espressif 官方的標準 C 程式庫(libmain.a),並加入了 thread-safe 的支援。相關說明可參考 SuperHouse 官方的 esp-open-rtos 計畫。
RTOS WoT 目標
RTOS WoT 是 esp-open-rtos 的一份 fork,目標是基於 FreeRTOS 設計並實作符合 W3C Web of Things 標準的 WoT server。RTOS WoT 目標是支援 constrained devices(Micro-controllers),這與目前 W3C 正在發展的 Web of Things Framework(採用 Node.js)目標不同,但未來都會經由 Web of Things 標準,讓不同的平台互通(interoperability)。
RTOS WoT v0.1.0
RTOS WoT 共有 10 個版本計畫,第一個版本(v0.1.0)的目標非常簡單:
- 使用 C++ programming model
- 加入 WebSocket(版本 13 以上)的支援
WebSocket 的部份還在測試中,C++ programming model 的概念說明如下。
Reusable Components
加入 C++ programming model 的想法,「不是」為了使用 C++ 來撰寫 FreeRTOS 應用程式,而是能將 device drivers 的程式碼,封裝為 component,以達到重用(reuse)的目的。
設計考量部份,只需要將 ESP8266 的 GPIO、Analog、I2C、UART 腳位,封裝為 class library 即可,但不封裝 FreeRTOS APIs。這項工作的目標,是讓 FreeRTOS 可以具備一層能重用的 device driver 架構。
實作部份,則是直接引用 ARM mbed 的程式碼,範例可參考 AnalogIn.h。有了 mbed components 的移植,未來還可以使用 mbed programming style 來撰寫 FreeRTOS 的驅動程式。
例如,要讀取 ESP8266 的 A0 數據,使用 mbed programming style 的寫法如下:
AnalogIn AIR(17);
int a = AIR;
以下是一個 Air Quality 的完整程式碼範例:
#include "espressif/esp_common.h"
#include "esp/uart.h"
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include "esp8266.h"
#include "math.h"
// C++ programming model
#include "AnalogIn.h"
struct userdata {
xQueueHandle xQueue;
xTaskHandle xHandle;
};
/* user context */
static struct userdata user;
/* ADC0 (A0)
*
* MP503 Air Quality Sensor -
* http://www.seeedstudio.com/wiki/File:Air_quality_sensor_MP503.pdf
*/
AnalogIn AIR(17);
/* This task uses the high level GPIO API (esp_gpio.h) to blink an LED.
*
*/
void readTask(void *pvParameters)
{
struct userdata *user = (struct userdata *)pvParameters;
int a;
while(1) {
// read from sensor output voltage
a = AIR;
if (a > 798 || a <= 10) {
printf("Sensor is initializing. Waiting for 5 seconds...\n");
wait(5);
continue;
}
// send to queue
xQueueSendToBack( user->xQueue, (void *) &a, portMAX_DELAY );
// Resume the suspended task ourselves.
if( user->xHandle != NULL ) {
vTaskResume( user->xHandle );
}
wait(5);
}
}
void transmitTask(void *pvParameters)
{
struct userdata *user = (struct userdata *)pvParameters;
int a;
while(1) {
// Suspend ourselves.
vTaskSuspend( NULL );
xQueueReceive(user->xQueue, &a, portMAX_DELAY);
printf("{ \"quality\": %d }\n", a);
}
}
extern "C" void user_init(void)
{
uart_set_baud(0, 115200);
user.xQueue = xQueueCreate(2, sizeof(uint32_t));
xTaskCreate(readTask, (signed char *)"readTask", 256, &user, tskIDLE_PRIORITY+1, NULL);
xTaskCreate(transmitTask, (signed char*)"transmitTask", 256, &user, tskIDLE_PRIORITY, &user.xHandle);
}
同樣的方式,移植 DigitalOut.h。以下是一個 GPIO 控制的完整範例:
#include "espressif/esp_common.h"
#include "esp/uart.h"
#include "FreeRTOS.h"
#include "task.h"
#include "esp8266.h"
// mbed API layer
#include "DigitalOut.h"
#include "AnalogIn.h"
// GPIO2 (D4)
DigitalOut D4(2);
/* This task uses the mbed programming style to blink a LED.
*
*/
void blinkenTask(void *pvParameters)
{
while(1) {
D4 = 1;
wait(1)
D4 = 0;
wait(3);
}
}
extern "C" void user_init(void)
{
uart_set_baud(0, 115200);
xTaskCreate(blinkenTask, (signed char *)"blinkenTask", 256, NULL, 2, NULL);
}
留言與討論
Tags: