jollen / blog

Jollen's Blog
http://www.jollen.org/blog
66 stars 4 forks source link

RTOS WoT (v0.1.0) 使用 FreeRTOS、 lwIP 與 C++ 元件重用 #7

Closed jollen closed 8 years ago

jollen commented 8 years ago

沿續前一個 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 程式碼。

標準 C 程式庫(libc)部份,esp-open-rtos 改用 newlib 來取代 Espressif 官方的標準 C 程式庫(libmain.a),並加入了 thread-safe 的支援。相關說明可參考 SuperHouse 官方的 esp-open-rtos 計畫。

RTOS WoT 目標

RTOS WoTesp-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)的目標非常簡單:

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 的程式碼,範例可參考 DigitalOut.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);
}