如何創建一個新的AliOS Things組件

1、前言

當我們基於AliOS Things做應用或項目開發時,會發現自己寫的很多代碼具備很強的可複用性,不單本項目可以使用,可能後續的類似項目都可以用到。那我們怎麼把這部分功能抽象成OS的一個能力呢?顯然,我們把這部分代碼從project中挪到components中當作一個組件是非常合適的。

 

接下來我們將詳細介紹如何快速開發一個AliOS Thing的標準組件。

本案例基於以下平臺:

2、快速掌握AliOS Things的編譯系統

AliOS Things 編譯系統由兩部分組件。

  • 負責組件配置的Config.in
  • 負責具體編譯的aos.mk

2.1、Config.in 介紹

如果大家玩過linux內核編譯,應該清楚Config.in是munuconfig圖形化配置的配置文件。

對於一個組件,需要一個config選項,如下格式:

config AOS_COMP_XXX1
    bool "xxxx"
    select AOS_COMP_XXX2
    default n
    help
        what is this.

四要素:

  1. config後接組件名(配置系統中的名稱);
  2. bool 代表選項類型,對於一個組件來說存在“選中“和“不選中“兩種狀態,故使用bool類型,bool後空一個寫其在menuconfig中顯示的名稱;
  3. select 用於選中其必須依賴的組件,如CoAP這種應用層協議會依賴tcp/ip協議棧LwIP。
  4. default 默認狀態,對於bool類型,只有“n”或“y”兩種狀態,建議默認n。
  5. help 功能描述。

另外需要注意的是,AliOS Things3.1支持創建工程,因此對Config.in做了一定的改造,加了“AOS_CREATE_PROJECT”控制開關,如果我們需要能主動創建工程,擇需要如下方式改造一下,做前後兼容:

#注意這裏,如果AOS_CREATE_PROJECT使能的話,無需設置組件名,並且默認使能
if AOS_CREATE_PROJECT
config AOS_COMP_XXX1
    bool 
    select AOS_COMP_XXX2
    default y
    help
        what is this.
endif

#注意這裏,如果AOS_CREATE_PROJECT未使能的話,則按傳統方式設置組件名,並且默認不使能
if !AOS_CREATE_PROJECT
config AOS_COMP_XXX1
    bool "xxx"
    default n
    select AOS_COMP_XXX2
    help
        what is this.
endif

詳細介紹可參考 配置系統簡介

2.2、aos.mk介紹

aos.mk其實就是makefile,語法保持一致。

mk文件參數說明。

1、組件名:

NAME := mcoap

2、依賴組件,當有Config.in保證依賴關係時,此處可以不填寫:

$(NAME)_COMPONENTS := 

3、編譯類型:

$(NAME)_MBINS_TYPE := kernel

4、組件版本:

$(NAME)_VERSION := 1.0.0

5、組件描述:

$(NAME)_SUMMARY := Your component description.

6、指定編譯源文件:

#包含src目錄下全部.c
$(NAME)_SOURCES     := src/*.c
#包含src目錄下指定.c
$(NAME)_SOURCES     := src/xxx.c src/xxxy.c

7、指定頭文件路徑:

#全局頭文件,組件外也可以找到
GLOBAL_INCLUDES     += public/
#內部頭文件,僅組件使用
$(NAME)_INCLUDES    += private/

8、定義全局宏:

#整個編譯系統下可見的宏
GLOBAL_DEFINES      += CONFIG_COAP
#僅組件下可見的宏
$(NAME)_DEFINES      += CONFIG_COAP_WITH_TLS

9、CFLAGS設置:

#整個編譯系統下可見的CFLAG
#GLOBAL_CFLAGS += -DON_DAILY 
#僅組件下可見的CFLAG
$(NAME)_CFLAGS   += -DON_DAILY  

2.3、目錄格式

組件默認都放在components目錄下,然後根據具體功能又可細分目錄,如我們示例移植一份開源的coap庫,則可以放在components/network目錄下。目錄格式建議爲:

your_comp_dir
--include
--src

3、一步步實現自有組件

鑑於代碼開源相關風險,本用例使用一個mit lisense的開源coap庫(示例代碼來源:https://github.com/1248/microcoap)當做示例代碼加入到AliOS Things中,使其成爲其標準組件。

 

1、在components/network/下新建microcoap文件夾,並新建兩個子文件夾include/src分別用於存放.h和.c文件;

2、在src/include文件夾下分別創建你的.c和.h文件;

3、按2章節方法在microcoap目錄下新建Config.in:

#注意這裏,如果AOS_CREATE_PROJECT使能的話,無需設置組件名,並且默認使能
if AOS_CREATE_PROJECT
config AOS_COMP_MICROCOAP
    bool 
    select AOS_COMP_LWIP
    default y
    help
        A tiny open source CoAP server for microcontrollers.
endif

#注意這裏,如果AOS_CREATE_PROJECT未使能的話,則按傳統方式設置組件名,並且默認不使能
if !AOS_CREATE_PROJECT
config AOS_COMP_MICROCOAP
    bool "microcoap"
    default n
    select AOS_COMP_LWIP
    help
        A tiny open source CoAP server for microcontrollers.
endif

同時在build/Config.in中增加此文件的索引:

menu "Network     Configuration"
...
source "components/network/microcoap/Config.in"
...

4、按2章節方法在microcoap目錄下新建aos.mk文件:

NAME := microcoap

$(NAME)_MBINS_TYPE := kernel
$(NAME)_VERSION := 1.0.0
$(NAME)_SUMMARY := A tiny open source CoAP server for microcontrollers.

$(NAME)_SOURCES     := src/coap.c src/endpoints.c

GLOBAL_INCLUDES     := include

5、完成代碼開發(示例使用開源代碼演示,略過)。

至此整個文件結構如圖:

image.png

4、測試驗證

4.1、編寫測試demo

1、拷貝已經存在的helloworld_demo例程爲模板創建自有demo:mcoap_demo。

2、修改aos.mk,如下:

NAME := mcoap_demo

$(NAME)_MBINS_TYPE := app
$(NAME)_VERSION := 1.0.0
$(NAME)_SUMMARY := microcoap demo
$(NAME)_SOURCES := appdemo.c maintask.c

$(NAME)_COMPONENTS += osal_aos cli

$(NAME)_INCLUDES += ./

3、修改Config.in,如下:

config AOS_APP_MCOAP_DEMO
    bool "mcoap Demo"
    select AOS_COMP_OSAL_AOS  if !AOS_CREATE_PROJECT
    select AOS_COMP_MICROCOAP if !AOS_CREATE_PROJECT
    select AOS_COMP_YLOOP     if !AOS_CREATE_PROJECT
    select AOS_COMP_NETMGR    if !AOS_CREATE_PROJECT 
    help
        microcoap demo

if AOS_APP_MCOAP_DEMO
# Configurations for app mcoap_demo
config SYSINFO_APP_VERSION
    string "Firmware Version"
    default "app-1.0.0-20201208.140831"
    help
        application main firmware version
endif

4、編輯application/example/Config.in,增加本demo信息:

source "application/example/mcoap_demo/Config.in"
if AOS_APP_MCOAP_DEMO
    config AOS_BUILD_APP
        default "mcoap_demo"
endif

5、編輯appdemo.c,增加自己的測試驗證代碼。如下:

/*
 * Copyright (C) 2015-2020 Alibaba Group Holding Limited
 */

#include <stdio.h>
#include <stdlib.h>
#include <aos/errno.h>
#include <aos/kernel.h>
#include "aos/init.h"
#include "board.h"
#include <k_api.h>
#include "coap.h"
#include "network/network.h"
#include "aos/yloop.h"
#include "netmgr.h"

#define PORT 5683

int test_main(void *data)
{
    int fd;

    struct sockaddr_in servaddr, cliaddr;

    uint8_t buf[1024];
    uint8_t scratch_raw[1024];
    coap_rw_buffer_t scratch_buf = {scratch_raw, sizeof(scratch_raw)};


    fd = socket(AF_INET,SOCK_DGRAM,0);


    bzero(&servaddr,sizeof(servaddr));

    servaddr.sin_family = AF_INET;
    servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    servaddr.sin_port = htons(PORT);

    bind(fd,(struct sockaddr *)&servaddr, sizeof(servaddr));

    endpoint_setup();

    while(1)
    {
        int n, rc;
        socklen_t len = sizeof(cliaddr);
        coap_packet_t pkt;

        n = recvfrom(fd, buf, sizeof(buf), 0, (struct sockaddr *)&cliaddr, &len);
#ifdef DEBUG
        printf("Received: ");
        coap_dump(buf, n, true);
        printf("\n");
#endif

        if (0 != (rc = coap_parse(&pkt, buf, n)))
            printf("Bad packet rc=%d\n", rc);
        else
        {
            size_t rsplen = sizeof(buf);
            coap_packet_t rsppkt;
#ifdef DEBUG
            coap_dumpPacket(&pkt);
#endif
            coap_handle_req(&scratch_buf, &pkt, &rsppkt);

            if (0 != (rc = coap_build(buf, &rsplen, &rsppkt)))
                printf("coap_build failed rc=%d\n", rc);
            else
            {
#ifdef DEBUG
                printf("Sending: ");
                coap_dump(buf, rsplen, true);
                printf("\n");
#endif
#ifdef DEBUG
                coap_dumpPacket(&rsppkt);
#endif

                sendto(fd, buf, rsplen, 0, (struct sockaddr *)&cliaddr, sizeof(cliaddr));
            }
        }
    }
}


/*
 * WiFi Got IP event
 */
static void wifi_service_event(input_event_t *event, void *priv_data)
{
    static int started = 0;
    if (event->type != EV_WIFI) {
        return;
    }

    if (event->code != CODE_WIFI_ON_GOT_IP) {
        return;
    }

    netmgr_ap_config_t config;
    memset(&config, 0, sizeof(netmgr_ap_config_t));
    netmgr_get_ap_config(&config);
    LOG("wifi_service_event config.ssid %s", config.ssid);
    if (strcmp(config.ssid, "adha") == 0 || strcmp(config.ssid, "aha") == 0) {
        return;
    }

    /* Start CoAP task  */
    if (!started) {
        aos_task_new("iotx_example", test_main, NULL, 1024*6);
        started = 1;
    }
}

int application_start(int argc, char *argv[])
{
    int count = 0;
    
    printf("nano entry here!\r\n");

    /* Register WiFi event handle */
    aos_register_event_filter(EV_WIFI, wifi_service_event, NULL);

    /* Initialize and start net manager */
    netmgr_init();
    netmgr_start(false);

    aos_loop_run();

}

4.2、編譯&測試

1、編譯我們新增加的demo程序,生產固件。

aos make mcoap_demo@haas100 -c config
aos make 

2、將上述編譯的固件按照haas100開發板燒入指導手冊燒入板中,進行相關功能驗證。

5、總結

將一個通用能力集合當作一個組件加入到AliOS Things中並不難。主要有以下幾步:

  1. 編寫組件功能代碼;
  2. 編寫Config.in;
  3. 編寫aos.mk;
  4. 將組件Config.in加入配置體系;
  5. 至此主要流程已經完成。當然你還可以做如下工作用於驗證組件是否能正常工作:
  6. 編寫測試demo;
  7. 編譯測試固件,上板驗證。

你學會了沒?最後歡迎大家將自己的組件貢獻到AliOS Things生態中來,可通過(https://github.com/alibaba/AliOS-Things/pulls)等開源倉庫提交你的代碼,我們審覈通過後就將成爲AliOS Things的一部分!

同時,我們推出了HaaS 年度大玩家計劃,除了成爲AliOS Things的一部分,也歡迎同學們在CSDN上踊躍投稿,還有機會被邀請到 雲棲大會 現場來進行頒獎哦

6、開發者技術支持

如需更多技術支持,可加入釘釘開發者羣

更多技術與解決方案介紹,請訪問阿里雲AIoT首頁https://iot.aliyun.com/

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章