ucgui在嵌入式linux下的移植

时间:2022-02-12 08:32:04

 前几天在研究minigui,照着官方的步骤编译,竟然一堆错,不是缺这库,就是缺那库。好不容易快到了最后一步,竟然再链接时告诉我用的64位系统不兼容32位的minigui。

早不说呀,真折腾,这是让我再重装个32位系统么。想出来个helloworld,竟在编译环境上浪费时间,太坑。也不喜欢minigui的为win32风格,应用都得在他的框架下写,必须得有入口函数。类似于win32的api编程,很原始,连个界面的长宽高都要自己去定义。也没有好用的可视化的窗口设计及仿真环境。其实,如果没有那么多的人机交互,比如车载pos,不需要这些吧。不如直接调用显示接口函数,比如想显示个内容,直接LCD_DisplayString()来的容易。

用 ucgui还有个好处是,只要应用做稳定了,界面根本不会卡死或down掉。因为界面就像一个画布,让显示什么,什么时候显示,都是受应用控制的,界面是被动的。但是,如果应用跑在miniGUI的框架下,如果界面消息循环阻塞,或者minigui挂掉,整个应用就完了。且minigui的让显示什么,就发个消息,然后在主线程对消息就行处理再显示,感觉像是平白无故兜了一圈。完全没有直接操作屏幕爽。让什么时候显示什么直接LCD_Display,安全稳定。当然,这只针对目前的应用而言,界面不那么重要。如果是靠界面取胜的应用,都这么来会很累。

无意间发现了一个好东西,ucgui,这在原来单片机stm32上跑过,以及ucosII。之前也用过。ucgui占用资源很少,在stm32等单片机上都能跑,在linux 上更是没一点儿问题。

而且超轻量级,代码很好移植。甚至因为小巧,可以用来学习研究GUI用,或者增加定制些功能。

同事说这么小巧的东西在linux上有点儿不搭吧,linux那么强大,应该首先考虑minigui和QT。但是我我举得对于目前正在做的新项目而言,不需要界面太花哨,功能稳定就行,先快速出来产品再说吧。先整出来个界面用用,毕竟也不占多少精力。越是简单小巧越容易掌控,不容易掉坑里。

对于一款智能pos来说,从功能上无非是 卡处理、记录存储、通信、显示、这几块功能。目前 通信库,和文件存储库都已封装好。把显示也搞定了,就剩封装读卡库了。最后再实现个多线程框架把这些*组装起来,就是一完整 pos 了,也不是什么难事。难在接口封装和风格尽量要做到和原来一致啊,要不那么多地方的应用,移植是件痛苦的事。

进一步查资料发现,用这个 ucgui,电脑上还有模拟器可以用,那么界面设计部分,完全可以在电脑上仿真啦。这样,想设计个漂亮的界面出来,也不难啊。别抱怨说界面原生丑陋,那是没经过设计。至于是否支持中文,以及字体有哪些,那就自己画呗,用工具生成各种需要的中文字库导进去。 想让界面漂亮些,那自己画呗,正好考验下有没艺术细胞。反正画着也挺简单的,最底层的画点画线基本函数都有了。甚至可以移植gif解码库,让支持更多类型的图片动画。后续准备加入常用的中文字库支持。以及gif动画支持。

官方的模拟器  emWin(UCGUI)模拟器。在电脑上有模拟器啊,这是不是很赞。

移植之后,使用也很简单 。就一个libucgui.a库文件和gui.h头文件包含进来即可。

使用类似这样:

#include <stdio.h>
#include "GUI.h"

int main(int argc, char* argv[])

  char c;
  printf("this is ucgui-linux test!\n");


  GUI_Init();
  GUI_SetBkColor(GUI_BLUE);
  GUI_Clear();
  GUI_SetColor(GUI_WHITE);
  GUI_SetTextAlign(GUI_TA_HCENTER);
  GUI_SetFont(&GUI_Font16B_ASCII);
  GUI_DispStringAt("hello world, ucgui-linux",240,100);
  GUI_DrawCircle(100,100,50);//画圆
  printf("system pause\n");
  while ((c = getchar()) != '\n');
  system("pause");
  return 0;
}

先来张运行成功的截图:

ucgui在嵌入式linux下的移植

ucgui在嵌入式linux下的移植

ucgui在嵌入式linux下的移植

又发现ucGUI一个强大功能,竟可以windows上设计界面自动生成代码,带仿真执行功能。附图:是不是很赞,这是minigui远远不能及的....

ucgui在嵌入式linux下的移植

ucgui在嵌入式linux下的移植

ucgui在嵌入式linux下的移植

连带电脑上的代码编写仿真环境都有,

ucgui在嵌入式linux下的移植

ucgui在嵌入式linux下的移植

进入正题,移植minigui,

很好移植,把底层调用的几个函数,用linux上的frambuffer实现就可以了。

具体文件是LCDDummy.c那么文件 里的LCD_L0_Init(void),LCD_L0_SetPixelIndex,LCD_L0_GetPixelIndex,这三个函数,实现这三个函数。

/*********************************************
*
* LCD_L0_Init
*
**********************************************
Purpose:
Initialises the LCD-controller.
*/

int LCD_L0_Init(void) {
return fb_init();
}
/***********************************************       LCD_L0_SetPixelIndex***********************************************Purpose:  Sets the index of the given pixel. The upper layers of emWin  calling this routine make sure that the coordinates are in range, so  that no check on the parameters needs to be performed.*/void LCD_L0_SetPixelIndex(int x, int y, int PixelIndex) {  /* Convert logical into physical coordinates (Dep. on LCDConf.h) */  #if LCD_SWAP_XY | LCD_MIRROR_X| LCD_MIRROR_Y    int xPhys = LOG2PHYS_X(x, y);    int yPhys = LOG2PHYS_Y(x, y);  #else    #define xPhys x    #define yPhys y  #endif  /* Write into hardware ... Adapt to your system */  {    /* ... */    fb_setpixel(480, 272, xPhys, yPhys, PixelIndex);  }}/***********************************************       LCD_L0_GetPixelIndex***********************************************Purpose:  Returns the index of the given pixel. The upper layers of emWin  calling this routine make sure that the coordinates are in range, so  that no check on the parameters needs to be performed.*/unsigned int LCD_L0_GetPixelIndex(int x, int y) {  LCD_PIXELINDEX PixelIndex;  /* Convert logical into physical coordinates (Dep. on LCDConf.h) */  #if LCD_SWAP_XY | LCD_MIRROR_X| LCD_MIRROR_Y    int xPhys = LOG2PHYS_X(x, y);    int yPhys = LOG2PHYS_Y(x, y);  #else    #define xPhys x    #define yPhys y  #endif  /* Read from hardware ... Adapt to your system */  {    PixelIndex = 0;/* ... */    PixelIndex = fb_readpixel(480, 272, xPhys, yPhys);  }  return PixelIndex;}

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <memory.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <sys/mman.h>
#include <linux/fb.h>

static unsigned char* npu8_fbmem;
static int ns32_fb;
static unsigned int nu32_screensize;

static void* _fb_mmap(int fd, unsigned int screensize)
{
caddr_t fbmem;

if ((fbmem = mmap(0, screensize, PROT_READ | PROT_WRITE,
MAP_SHARED, fd, 0)) == MAP_FAILED) {
perror(__func__);
return (void *) (-1);
}

return fbmem;
}

static int _fb_munmap(void *start, size_t length)
{
return (munmap(start, length));
}

static int _fb_stat(int fd, unsigned int *width, unsigned int *height, unsigned int *depth)
{
//struct fb_fix_screeninfo fb_finfo;
struct fb_var_screeninfo fb_vinfo;

//if (ioctl(fd, FBIOGET_FSCREENINFO, &fb_finfo)) {
// perror(__func__);
// return -1;
//}

if (ioctl(fd, FBIOGET_VSCREENINFO, &fb_vinfo)) {
perror(__func__);
return -1;
}

*width = fb_vinfo.xres;
*height = fb_vinfo.yres;
*depth = fb_vinfo.bits_per_pixel;

return 0;
}

int fb_init(void)
{
unsigned int fbw, fbh, fbd;

ns32_fb = open("/dev/fb0", O_RDWR);
if(ns32_fb<0){
printf("can not open fb0\n");
return -1;
}
if( _fb_stat(ns32_fb, &fbw, &fbh, &fbd) < 0 ) return -1;
printf("%d, %d, %d\n", fbw, fbh, fbd);
nu32_screensize = fbw * fbh * fbd / 8;
npu8_fbmem = _fb_mmap(ns32_fb, nu32_screensize);
return 0;
}

void fb_deinit(void)
{
close(ns32_fb);
_fb_munmap(npu8_fbmem, nu32_screensize);
}

int fb_setpixel(int width, int height, int x, int y, unsigned short color)
{
if ((x > width) || (y > height))
return -1;

unsigned short *dst = ((unsigned short *)npu8_fbmem + y * width + x);

*dst = color;
return 0;
}

unsigned short fb_readpixel(int width, int height, int x, int y)
{
if ((x > width) || (y > height)) return -1;
unsigned short *dst = ((unsigned short *)npu8_fbmem + y * width + x);
return *dst;
}



最后,要在linux上编译,写个makefile吧,简单省事。写完后配置下工具链直接make即可。

########################################
##makefile
########################################
#****************************************************************************
# Cross complie path
#****************************************************************************
#CHAIN_ROOT=/home/yangyongzhen/imax283/ctools/gcc-4.4.4-glibc-2.11.1-multilib-1.0/arm-fsl-linux-gnueabi/bin

#CROSS_COMPILE=$(CHAIN_ROOT)/arm-none-linux-gnueabi-

CROSS_COMPILE =

CC := $(CROSS_COMPILE)gcc
CXX := $(CROSS_COMPILE)g++
AS := $(CROSS_COMPILE)as
AR := $(CROSS_COMPILE)ar
LD := $(CROSS_COMPILE)ld
RANLIB := $(CROSS_COMPILE)ranlib
OBJDUMP:= $(CROSS_COMPILE)objdump
OBJCOPY:= $(CROSS_COMPILE)objcopy
STRIP := $(CROSS_COMPILE)strip

#****************************************************************************
# Source files
#****************************************************************************
SRC_C=$(shell find . -name "*.c")

OBJ_C=$(patsubst %.c, %.o, $(SRC_C))

SRCS := $(SRC_C) $(SRC_C)

OBJS := $(OBJ_C)

#****************************************************************************
# Flags
#****************************************************************************

CFLAGS= -I./GUI_X -I./GUI/Core -I./GUI/WM -I./GUI/Widget
LDSCRIPT=
LDFLAGS=
#****************************************************************************
# Targets of the build
#****************************************************************************
TARGET := libucgui

.PHONY: clean
all: prebuild $(TARGET).a

#****************************************************************************
# TARGET
#****************************************************************************
prebuild:
@echo Building lib...

$(TARGET).a : $(OBJS)
@echo Generating lib...
ar crv $(TARGET).a $(OBJS)
cp $(TARGET).a ../
@echo OK!

%.o : %.c
$(CC) -c $(CFLAGS) $< -o $@

clean:
@echo The following files:
rm -f $(TARGET) *.a
find . -name "*.[od]" |xargs rm
@echo Removed!