源码里是有Feature的示例的,但当自己写一个自己的Feature时,却遇到了各种问题,有些是示例代码和文档没有说明的小坑,这里记录一下。因源码里的startup目录没有任何代码,就选择它来存放代码。

1.  BUILD.gn文件里的source_set("startup")需要修改成 static_library("startup")。

     source_set 应该是不会打包进去还是什么,代码不会被执行,修改成static_library发现bin文件也增大了一些。

2.  使用SYSEX_FEATURE_INIT(Init);进行初始化即可,可不使用SYS_RUN()和CORE_INI()宏。

3.  直接使用SAMGR_GetInstance()->RegisterFeature(),并不能启动Feature。Feature的启动需要配全Service一块使用,在使用SAMGR_GetInstance()->RegisterFeature()前需要先SAMGR_GetInstance()->RegisterService()注册一个同命的Service才行。这点是最坑的地址,注册Feature时参数是Service名称字符串,所以就很容易想到直接注册就可以了,结束事实证明这样是行不通的。

4.  头文件的顺序,#include <ohos_init.h>要在#include "hctest.h"之前,否则SYSEX_FEATURE_INIT引用的是hos_init.h里的声明,而不是ohos_init.h文件里的声明

下面看一下添加Feature的正确方式:

1.  创建Service变量

static const char *GetName(Service *service);
static BOOL Initialize(Service *service, Identity identity);
static BOOL MessageHandle(Service *service, Request *msg);
static TaskConfig GetTaskConfig(Service *service);
static Service g_exampleService={
    .GetName=GetName,
    .Initialize=Initialize,
    .MessageHandle=MessageHandle,
    .GetTaskConfig=GetTaskConfig
};

2. 创建Feature变量

      这里定义Feature没有直接使用Feature进行定义,而是使用了源码示例中的另一种方式,即同类型定义。

typedef struct DemoApi{
    INHERIT_IUNKNOWN;
    BOOL (*AsyncCall)(IUnknown *iUnknown, const char *buff);
    BOOL (*SyncCall)(IUnknown *iUnknown,struct Payload *payload);
} DemoApi;

typedef struct DemoFeature{
    INHERIT_FEATURE;
    INHERIT_IUNKNOWNENTRY(DemoApi);
    Identity identity;
} DemoFeature;

static BOOL AsyncCall(IUnknown *iUnknown, const char *body);
static BOOL SyncCall(IUnknown *iUnknown, struct Payload *payload);
static const char* FEATURE_GetName(Feature *feature);
static void FEATURE_OnInitialize(Feature *feature, Service* parent, Identity identity);
static void FEATURE_OnStop(Feature *feature, Identity identity);
static BOOL FEATURE_OnMessage(Feature *feature, Request *request);

3. 注册Service&Feature

SAMGR_GetInstance()->RegisterService(&g_exampleService);
SAMGR_GetInstance()->RegisterFeature(EXAMPLE_SERVICE,(Feature*)&g_example);
SAMGR_GetInstance()->RegisterFeatureApi(EXAMPLE_SERVICE,EXAMPLE_FEATURE,GET_IUNKNOWN(g_example));

4. 添加初始化

SYSEX_FEATURE_INIT(Init);

做完以上步骤后编译烧写到wifi-iot开发板后就可以看到Feature能被正常初始化了。当然上面只是贴出了核心代码,声明的方法还是需要再实现一下的,下面是完整的代码。

#include <stdio.h>
#include <unistd.h>
#include <ohos_init.h>
#include <securec.h>
#include <los_base.h>
#include <cmsis_os.h>
#include "iunknown.h"
#include "feature.h"
#include "service.h"
#include "samgr_lite.h"
#include "time_adapter.h"
#include "discovery_service.h"

#define EXAMPLE_SERVICE "example"
#define EXAMPLE_FEATURE "example"

struct Payload{
    int id;
    const char *name;
    int value;
};

typedef struct DemoApi{
    INHERIT_IUNKNOWN;
    BOOL (*AsyncCall)(IUnknown *iUnknown, const char *buff);
    BOOL (*SyncCall)(IUnknown *iUnknown,struct Payload *payload);
} DemoApi;

typedef struct DemoFeature{
    INHERIT_FEATURE;
    INHERIT_IUNKNOWNENTRY(DemoApi);
    Identity identity;
} DemoFeature;

static BOOL AsyncCall(IUnknown *iUnknown, const char *body);
static BOOL SyncCall(IUnknown *iUnknown, struct Payload *payload);
static const char* FEATURE_GetName(Feature *feature);
static void FEATURE_OnInitialize(Feature *feature, Service* parent, Identity identity);
static void FEATURE_OnStop(Feature *feature, Identity identity);
static BOOL FEATURE_OnMessage(Feature *feature, Request *request);

static int g_regStep=0;

static const char *GetName(Service *service)
{
    (void)service;
    printf("GetService name:");
    return EXAMPLE_SERVICE;
}

static BOOL Initialize(Service *service, Identity identity)
{
    (void)identity;
    printf("[Boot Test][TaskID:%p][Step:%d][Reg Finish S:%s]Time: %llu!\n",
           osThreadGetId(), g_regStep++, service->GetName(service), SAMGR_GetProcessTime());
    return TRUE;
}

static BOOL MessageHandle(Service *service, Request *msg)
{
    printf("[Boot Test][TaskID:%p][Step:%d][S:%s] msgId<%d> \n",
           osThreadGetId(), g_regStep++, service->GetName(service), msg->msgId);
    return FALSE;
}

static TaskConfig GetTaskConfig(Service *service)
{
    (void)service;
    TaskConfig config = {LEVEL_HIGH, PRI_ABOVE_NORMAL,
                         0x400, 2, SHARED_TASK};
    return config;
}

static Service g_exampleService={
    .GetName=GetName,
    .Initialize=Initialize,
    .MessageHandle=MessageHandle,
    .GetTaskConfig=GetTaskConfig
};

static DemoFeature g_example={
    .GetName=FEATURE_GetName,
    .OnInitialize = FEATURE_OnInitialize,
    .OnStop = FEATURE_OnStop,
    .OnMessage = FEATURE_OnMessage,
    DEFAULT_IUNKNOWN_ENTRY_BEGIN,
    .AsyncCall=AsyncCall,
    .SyncCall=SyncCall,
    DEFAULT_IUNKNOWN_ENTRY_END,
    .identity = {-1, -1, NULL}
};

static const char* FEATURE_GetName(Feature *feature)
{
    printf("get feature name.");
    (void)feature;
    return EXAMPLE_FEATURE;
}

static void FEATURE_OnInitialize(Feature *feature, Service *parent, Identity identity)
{
    printf("Register Test,Oninit1");
    (void)parent;
    DemoFeature *demoFeature=(DemoFeature*)feature;
    demoFeature->identity=identity;
    printf("Register Test,Oninit");
}

static void FEATURE_OnStop(Feature *feature, Identity identity)
{
    (void)feature;
    (void)identity;
    g_example.identity.queueId = NULL;
    g_example.identity.featureId = -1;
    g_example.identity.serviceId = -1;
}

static BOOL FEATURE_OnMessage(Feature *feature, Request *request)
{
    (void)feature;
    (void)request;
    printf("[LPC Test][TaskID:%p][Step:%d][OnMessage S:%s, F:%s] Inner Error! \n",
           osThreadGetId(), g_regStep++, EXAMPLE_SERVICE, feature->GetName(feature));
    return FALSE;
}

static BOOL SyncCall(IUnknown *iUnknown, struct Payload *payload)
{
    (void)iUnknown;
    if (payload != NULL && payload->id >= 0 && payload->name != NULL) {
        printf("[LPC Test][TaskID:%p][Step:%d][SyncCall API] Id:%d, name:%s, value:%d \n",
               osThreadGetId(), g_regStep++, payload->id, payload->name, payload->value);
        return TRUE;
    }
    printf("[LPC Test][TaskID:%p][Step:%d][SyncCall API] Input Error! \n", osThreadGetId(), g_regStep++);
    return FALSE;
}

static BOOL AsyncCall(IUnknown *iUnknown, const char *body)
{
    Request request = {.msgId = 1, .msgValue = 0};
    request.len = (uint32_t)(strlen(body) + 1);
    request.data = malloc(request.len);
    if (request.data == NULL) {
        return FALSE;
    }
    if (strcpy_s(request.data, request.len, body) != EOK) {
        free(request.data);
        return FALSE;
    }
    DemoFeature *feature = GET_OBJECT(iUnknown, DemoFeature, iUnknown);
    printf("[LPC Test][TaskID:%p][Step:%d][AsyncCall API] Send request! \n", osThreadGetId(), g_regStep++);
    return SAMGR_SendRequest(&feature->identity, &request, NULL);
}

static void OnPublishSuccess(int32_t publishId){
    printf("demo service publish success.%d",publishId);
}

static void onPublishFail(int32_t publishId, PublishFailReason reason)
{
    printf("OnPublishFail.%d,%d",publishId,(int32_t)reason);
}
//初始化工作,注册Service后,再注册Feature
static void Init(void)
{
    SAMGR_GetInstance()->RegisterService(&g_exampleService);
    SAMGR_GetInstance()->RegisterFeature(EXAMPLE_SERVICE,(Feature*)&g_example);
    SAMGR_GetInstance()->RegisterFeatureApi(EXAMPLE_SERVICE,EXAMPLE_FEATURE,GET_IUNKNOWN(g_example));
    printf("[Register Test][TaskID:%d][Step:%d][Reg S:%s, F:%s] Time: %llu!\n",
            osThreadGetId(),g_regStep++,EXAMPLE_SERVICE,EXAMPLE_FEATURE,SAMGR_GetProcessTime());
}
//使用此方式初始化Feature
SYSEX_FEATURE_INIT(Init);