OpenHarmony轻量系统集成手册
OpenHarmony轻量系统集成手册 1. 简介 本文介绍在非liteos-m内核的系统上,保留原生系统的相关功能,提供一种基于openharmony ArkUI Lite图形界面的轻量设备适配方案。本方案使用 OpenHarmony v4.1 Release版本源码。 ArkUI Lite提供了两种接口: Native API和 JS API, 可以基
1. 简介
本文介绍在非liteos-m内核的系统上,保留原生系统的相关功能,提供一种基于openharmony ArkUI Lite图形界面的轻量设备适配方案。
本方案使用 OpenHarmony v4.1 Release版本源码。
- ArkUI Lite提供了两种接口: Native API和 JS API, 可以基于这两种接口开发应用,简化应用开发过程,并提供应用安装管理功能。
- 在框架层提供了组件,多语言,2D图形库,图像库和轻量渲染框架能。
2. 适配方案
- 不改变原生代码的编译系统和打包系统。
- 使用原生代码的交叉编译工具链编译OpenHarmony为静态库,将静态库集成到原生代码中。
- OpenHarmony中不编译LiteOS-M内核,使用原生代码的RTOS内核。
- 原生代码中新增适配代码,以提供OpenHarmony需要的接口。
3. 原生系统集成
3.1 Input适配
Input事件上报过程
Input事件分发流程如上:
- UI_Task调用InputDeviceManager::Callback接口
- InputDeviceManager调用InputDevice::ProcessEvent获取驱动上报的信息。
- InputDevice::Read读取驱动上报的信息。
- InputDevice::DispatchEvent分发上报的信息到UI界面,处理不同的事件类型。
Input事件类型
UIKit支持处理下列事件类型:
- CancelEvent
- ClickEvent
- DragEvent
- KeyEvent
- LongPressEvent
- PressEvent
- ReleaseEvent
- RotateEvent
InputDevice类型
UIKit提供3中不同的InputDevice类型,分别处理分发相应的事件。
其中:
- KeyInputDevice分发KeyEvent。
- RotateInputDevice触发RotateEvent事件。
- PointerInputDevice分发PressEvent、ReleaseEvent、DragStartEvent、DragEvent、DragEndEvent、LongPressEvent、CancelEvent。
适配过程
根据要支持的事件类型,继承实现相应InputDevice的Read接口,获取硬件上报的坐标信息。
参考bes2600的适配
// device\soc\bestechnic\bes2600\liteos_m\components\ui\touch_input.h
class TouchInput : public PointerInputDevice {
public:
TouchInput(){}
virtual ~TouchInput() {}
static TouchInput* GetInstance();
bool Read(DeviceData& data) override;
private:
bool IsValidTouchMsg(struct touch_msg *msg);
bool init = false;
DevHandle handle = nullptr;
struct touch_msg msg = {0};
};
// 获取硬件上报的坐标信息
bool TouchInput::Read(DeviceData &data)
{
// merge msg with the same event
struct touch_msg tmp[TOUCH_MSG_MAX] = {0};
int i = 0;
while (i < TOUCH_MSG_MAX && TouchRead(this->handle, &tmp[i], 0) == 0) {
if (!IsValidTouchMsg(&tmp[i]))
break;
if (tmp[i].event == TOUCH_EVENT_MOVE) {
tmp[i].event = TOUCH_EVENT_DOWN;
}
i++;
if (IsValidTouchMsg(&this->msg)) {
if (tmp[i - 1].event != this->msg.event) {
break;
}
} else {
if (i > 1 && tmp[i - 1].event != tmp[0].event)
break;
}
}
if (i <= 1) {
data.point.x = this->msg.x;
data.point.y = this->msg.y;
data.state = (this->msg.event == TOUCH_EVENT_DOWN) ? STATE_PRESS : STATE_RELEASE;
} else if (i <= TOUCH_MSG_MAX) {
data.point.x = tmp[i - 2].x;
data.point.y = tmp[i - 2].y;
data.state = (tmp[i - 2].event == TOUCH_EVENT_DOWN) ? STATE_PRESS : STATE_RELEASE;
}
// GRAPHIC_LOGD("Touch {%d, %d} %d", data.point.x, data.point.y, data.state);
if (i >= 1 && i <= TOUCH_MSG_MAX && IsValidTouchMsg(&tmp[i - 1]))
this->msg = tmp[i - 1];
return false;
}
添加InputDevice设备到InputDeviceManager管理类中,当task执行时,则处理相关input事件。
TouchInput* touch = TouchInput::GetInstance();
InputDeviceManager::GetInstance()->Add(touch);
3.2 Display适配
分辨率和刷新率设置
参考foundation\graphic\graphic_utils_lite\interfaces\innerkits\graphic_config.h
, 其中默认屏幕分辨率如下:
/* Resolution width of a graphics display screen. The default value is <b>454</b>. */
#ifndef HORIZONTAL_RESOLUTION
#define HORIZONTAL_RESOLUTION 454
#endif
/* Resolution height of a graphics display screen. The default value is <b>454</b>. */
#ifndef VERTICAL_RESOLUTION
#define VERTICAL_RESOLUTION 454
#endif // VERTICAL_RESOLUTION
默认刷新间隔为16ms。
/* Default task execution period. The default value is <b>16</b> ms. */
static constexpr uint8_t DEFAULT_TASK_PERIOD = 16;
渲染和送显接口适配
BaseGfxEngine提供绘制和送显的接口。
参考foundation\arkui\ui_lite\interfaces\innerkits\engines\gfx\gfx_engine_manager.h
,其接口声明如下:
class BaseGfxEngine : public HeapBase {
public:
virtual void DrawArc(BufferInfo& dst,
ArcInfo& arcInfo,
const Rect& mask,
const Style& style,
OpacityType opacity,
uint8_t cap) = 0;
virtual void MemoryBarrier() {}
virtual void DrawLine(BufferInfo& dst,
const Point& start,
const Point& end,
const Rect& mask,
int16_t width,
ColorType color,
OpacityType opacity) = 0;
virtual void DrawLetter(BufferInfo& gfxDstBuffer,
const uint8_t* fontMap,
const Rect& fontRect,
const Rect& subRect,
const uint8_t fontWeight,
const ColorType& color,
const OpacityType opa) = 0;
virtual void DrawCubicBezier(BufferInfo& dst,
const Point& start,
const Point& control1,
const Point& control2,
const Point& end,
const Rect& mask,
int16_t width,
ColorType color,
OpacityType opacity) = 0;
virtual void
DrawRect(BufferInfo& dst, const Rect& rect, const Rect& dirtyRect, const Style& style, OpacityType opacity) = 0;
virtual void DrawTransform(BufferInfo& dst,
const Rect& mask,
const Point& position,
ColorType color,
OpacityType opacity,
const TransformMap& transMap,
const TransformDataInfo& dataInfo) = 0;
virtual void ClipCircle(const ImageInfo* info, float x, float y, float radius) = 0;
virtual void Blit(BufferInfo& dst,
const Point& dstPos,
const BufferInfo& src,
const Rect& subRect,
const BlendOption& blendOption) = 0;
virtual void Fill(BufferInfo& dst, const Rect& fillArea, const ColorType color, const OpacityType opacity) = 0;
virtual void DrawPath(BufferInfo& dst,
void* param,
const Paint& paint,
const Rect& rect,
const Rect& invalidatedArea,
const Style& style) = 0;
virtual void FillPath(BufferInfo& dst,
void* param,
const Paint& paint,
const Rect& rect,
const Rect& invalidatedArea,
const Style& style) = 0;
virtual uint8_t* AllocBuffer(uint32_t size, uint32_t usage) = 0;
virtual void FreeBuffer(uint8_t* buffer, uint32_t usage) = 0;
virtual BufferInfo* GetFBBufferInfo()
virtual void AdjustLineStride(BufferInfo& info) {}
virtual void Flush(const Rect& flushRect) {}
virtual uint16_t GetScreenWidth();
virtual uint16_t GetScreenHeight();
virtual void SetScreenShape(ScreenShape screenShape);
virtual ScreenShape GetScreenShape();
static BaseGfxEngine* GetInstance();
static void InitGfxEngine(BaseGfxEngine* gfxEngine);
protected:
static BaseGfxEngine* baseEngine_;
uint16_t screenWidth_ = HORIZONTAL_RESOLUTION;
uint16_t screenHeight_ = VERTICAL_RESOLUTION;
ScreenShape screenShape_ = RECTANGLE;
};
- 渲染接口
如果硬件支持GPU或者其他硬件加速绘制,则实现以下接口,提高渲染速度。
virtual void DrawArc(...) = 0;
virtual void DrawLine(...) = 0;
virtual void DrawLetter(...) = 0;
virtual void DrawCubicBezier(...) = 0;
virtual void DrawRect(...) = 0;
virtual void DrawTransform(...) = 0;
virtual void ClipCircle(...) = 0;
virtual void Blit(...) = 0;
virtual void Fill(...) = 0;
virtual void DrawPath(...) = 0;
virtual void FillPath(...) = 0;
UIKit默认提供SoftEngine接口,支持CPU绘制。参考实现:
foundation\arkui\ui_lite\interfaces\innerkits\engines\gfx\soft_engine.h
- 送显接口
针对屏幕的适配,需对接display已经设备,实现以下接口:
virtual uint8_t* AllocBuffer(uint32_t size, uint32_t usage) = 0;
virtual void Flush(const Rect& flushRect) {}
- 参考实现
参考bes2600的适配:
device\soc\bestechnic\bes2600\liteos_m\components\ui
components/ui/
├── BUILD.gn
├── display_device.cpp # 送显接口实现
├── display_device.h
├── fbdev.cpp # 驱动封装
├── fbdev.h
├── touch_input.cpp # 触摸板适配
├── touch_input.h
├── ui_main.cpp # ui task
└── ui_main.h
bes2600默认使用CPU绘制,继承SoftEngine,只需重载实现Flush和GetFBBufferInfo接口即可。
class DisplayDevice : public SoftEngine
{
public:
DisplayDevice() {}
virtual ~DisplayDevice() {}
static DisplayDevice *GetInstance();
// 送显
void Flush(const Rect&) override;
// 获取显示完成的buffer,以进行绘制
BufferInfo *GetFBBufferInfo() override;
void UpdateFBBuffer();
private:
bool isRegister_ = false;
void *fbAddr = nullptr;
};
创建UiMainTask,启动图形界面。
static void *UiMainTask(void *arg)
{
(void)arg;
(void)pthread_setname_np(pthread_self(), "UiMain");
osDelay(UI_MAIN_TASK_DELAY);
InitUiKit();
RunApp();
#if ENABLE_FPS_SUPPORT
uint32_t start = HALTick::GetInstance().GetTime();
#endif
while (1) {
#if FULLY_RENDER
DisplayDevice::GetInstance()->UpdateFBBuffer();
#endif
uint32_t temp = HALTick::GetInstance().GetTime();
TaskManager::GetInstance()->TaskHandler();
uint32_t time = HALTick::GetInstance().GetElapseTime(temp);
if (time < DEFAULT_TASK_PERIOD) {
osDelay(DEFAULT_TASK_PERIOD - time);
}
#if ENABLE_FPS_SUPPORT
if (HALTick::GetInstance().GetElapseTime(start) >= ONE_SECOND) {
GRAPHIC_LOGD("%u fps", (uint32_t)RenderManager::GetInstance().GetFPS());
start = HALTick::GetInstance().GetTime();
}
#endif
}
return nullptr;
}
3.3 其他接口的集成
3.3.1 对接hilog输出接口
参考base\hiviewdfx\hilog_lite\interfaces\native\kits\hilog_lite\hiview_log.h
,hilog_lite接口定义如下:
#define HILOG_DEBUG(mod, fmt, ...) HiLogPrintf(mod, HILOG_LV_DEBUG, FUN_ARG_NUM(__VA_ARGS__), fmt, ##__VA_ARGS__)
#define HILOG_INFO(mod, fmt, ...) HiLogPrintf(mod, HILOG_LV_INFO, FUN_ARG_NUM(__VA_ARGS__), fmt, ##__VA_ARGS__)
#define HILOG_WARN(mod, fmt, ...) HiLogPrintf(mod, HILOG_LV_WARN, FUN_ARG_NUM(__VA_ARGS__), fmt, ##__VA_ARGS__)
#define HILOG_ERROR(mod, fmt, ...) HiLogPrintf(mod, HILOG_LV_ERROR, FUN_ARG_NUM(__VA_ARGS__), fmt, ##__VA_ARGS__)
#define HILOG_FATAL(mod, fmt, ...) HiLogPrintf(mod, HILOG_LV_FATAL, FUN_ARG_NUM(__VA_ARGS__), fmt, ##__VA_ARGS__)
可以根据hilog_lite框架实现日志的打印存储等功能,可以不依赖hilog_lite的实现,直接重新定义HiLogPrintf的实现。
3.3.2 新增LiteOS接口
Arkui Lite系统中调用的LiteOS-M的相关接口:
LOS_CurTaskIDGet
LOS_TaskCreate
LOS_TaskDelete
LOS_TaskLock
LOS_TaskUnlock
LOS_TickCountGet
LOS_BinarySemCreate
LOS_SemCreate
LOS_SemDelete
LOS_SemPost
LOS_SemPend
LOS_MuxCreate
LOS_MuxDelete
LOS_MuxPend
LOS_MuxPost
osThreadGetArgument
OhosMalloc
OhosFree
RefreshAllServiceTimeStamp
3.3.3 文件路径设置
在bundle_framework_lite子系统中,app的安装卸载需依赖文件系统支持,需实现相关接口,并设置文件路径。
参考foundation\bundlemanager\bundle_framework_lite\services\bundlemgr_lite\include\bundle_common.h
const char INSTALL_PATH[] = "user/ace/run";
const char DATA_PATH[] = "user/ace/data";
const char SYSTEM_BUNDLE_PATH[] = "system/ace/sys";
const char THIRD_SYSTEM_BUNDLE_PATH[] = "system/ace/vendor";
.....
3.3.4 RTOS相关的升级
在原生代码中升级模块或新增OpenHarmony调用的接口。如集成ui_lite到FreeRTOS系统中,可从以下步骤入手分析:
- 升级RTOS
由于不支持OpenHarmony中的底层接口,FreeRTOS内核从版本10.0.1升级到版本v10.3.1,适配其HAL层和 OSI层接口。
FreeRTOS源码来自于官网地址: https://github.com/FreeRTOS/FreeRTOS
- 新增CMSIS接口
原生系统kernel中新增cmsis目录,包含CMSIS的源码和头文件。
CMSIS源码来自于开源项目CMSIS-FreeRTOS,地址: https://github.com/ARM-software/CMSIS-FreeRTOS
修改部分源码适配系统源码,并修改kernel的CMakeFile.txt,将源码中的cmsis_os2.c文件加入编译。
4. 参考文档
一种OpenHarmony轻量系统适配方案 - 文章 OpenHarmony开发者论坛
docs: OpenHarmony documentation | OpenHarmony开发者文档 - Gitee.com
更多推荐
所有评论(0)