源码里是有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);