代码结构
所有代码都已通过测试跑通,其中代码结构如下:
一、include文件夹
1.1 common.h
#ifndef _COMMON_H
#define _COMMON_H
typedef struct Region {
int iLeftUpX; //区域左上方的坐标
int iLeftUpY; //区域左下方的坐标
int iWidth; //区域宽度
int iHeigh; //区域高度
}Region, *PRegion;
#endif
1.2 config.h
注意:CFG_FILE 设置为gui.conf在开发板下的路径
#ifndef _CONFIG_H
#define _CONFIG_H
#define ITEMCFG_MAX_NUM 30
#define CFG_FILE "/mnt/gui.conf"
/*定义配置文件结构体*/
typedef struct ItemCfg {
int index;
char name[100];
int bCanBeTouched; // 是否可以被点击
char command[100]; // 状态发生变化时 调用的命令
}ItemCfg, *PItemCfg;
/*获取配置文件按键的数目*/
int GetItemCfgCount(void);
/*根据索引获取配置文件*/
PItemCfg GetItemCfgByIndex(int index);
/*根据名字获取配置文件*/
PItemCfg GetItemCfgByName(char *name);
/*解析配置*/
int ParseConfigFile(void);
#endif
1.3 disp_manager.h
#ifndef _DISP_MANAGER_H //防止头文件重复包含,只要右边的出现过,就不会再往下编译
#define _DISP_MANAGER_H
#include<common.h>
#include<font_manager.h>
//区域结构体
typedef struct DispBuff {
int iXres;
int iYres;
int iBpp;
char *buff;
}DispBuff, *PDispBuff;
//区域结构体
/*
typedef struct Region {
int iLeftUpX; //区域左上方的坐标
int iLeftUpY; //区域左下方的坐标
int iWidth; //区域宽度
int iHeigh; //区域高度
}Region, *PRegion;
*/
//显示设备结构体(LCD设备或者是web设备),通过调用这个结构体中的函数来实现显示功能
typedef struct DispOpr {
char *name; //设备名
int (*DeviceInit)(void);//设备初始化函数
int (*DeviceExit)(void);//设备清除
int (*GetBuffer)(PDispBuff ptDispBuff);///用于获取lcd所需的内存空间,return内存空间的首地址
//argument1-lcd屏长度,argument2-lcd屏宽度,argument3-每一个像素点的位数。
int (*FlushRegion)(PRegion ptRegion, PDispBuff ptDispBuff);//刷新出argum1-按钮区域,argum2-区域数据
struct DispOpr *ptNext;//结构体指针,指向下一个设备机构体 多设备输出
}DispOpr,*PDispOpr;
void RegisterDisplay(PDispOpr ptDispOpr);
void DisplayInit(void);
int SelectDefaultDisplay(char *name);
int InitDefaultDisplay(void);
int PutPixel(int x, int y, unsigned int dwColor);
int FlushDisplayRegion(PRegion ptRegion, PDispBuff ptDispBuff);
PDispBuff GetDisplayBuffer(void);
void DrawFontBitMap(PFontBitMap ptFontBitMap, unsigned int dwColor);
void DrawRegion(PRegion ptRegion, unsigned int dwColor);
void DrawTextInRegionCentral(char *name, PRegion ptRegion, unsigned int dwColor);
#endif
1.4 font_manager.h
#ifndef _FONT_MANAGER_H
#define _FONT_MANAGER_H
#include <common.h>
//描述字体位图
typedef struct FontBitMap {
Region tRegion;
int iCurOriginX;//当期字符基点x坐标
int iCurOriginY;//当期字符基点y坐标
int iNextOriginX;//下一个字符基点x坐标
int iNextOriginY;//下一个字符基点y坐标
unsigned char *pucBuffer;
}FontBitMap, *PFontBitMap;
//描述字库操作
typedef struct FontOpr {
char *name;
int (*FontInit)(char *aFineName);//字体初始化
int (*SetFontSize)(int iFontSize);//字体大小
int (*GetFontBitMap)(unsigned int dwCode, PFontBitMap ptFontBitMap);//获得字符位图,存到ptFontBitMap中
struct FontOpr *ptNext;//方便支持多种字库
}FontOpr, *PFontOpr;
void RegisterFont(PFontOpr ptFontOpr);
void FontsRegister(void);
int SelectAndInitFont(char *aFontOprName, char *aFontFileName);
int SetFontSize(int iFontSize);
int GetFontBitMap(unsigned int dwCode, PFontBitMap ptFontBitMap);
#endif
1.5 input_manager.h
#ifndef _INPUT_MANAGER_H //防止头文件重复包含,只要右边的出现过,就不会再往下编译
#define _INPUT_MANAGER_H
#include <sys/time.h>
#define INPUT_TYPE_TOUCH 1
#define INPUT_TYPE_NET 2
/* 上报的数据格式 */
typedef struct InputEvent
{
struct timeval tTime; //加入时间管理
int iType; //网络事件或者触摸事件类型
int iX; //触摸事件x坐标
int iY; //触摸事件y坐标
int iPressure; //触摸事件压力
char str[1024]; //网络事件字符串
} InputEvent, *PInputEvent;
/* 不同的输入设备,应该模块化,使用下面的结构体表示输入设备 */
typedef struct InputDevice
{
char *name; //设备名称
int (*GetInputEvent)(PInputEvent ptInputEvent); //获得数据
int (*DeviceInit)(void);
int (*DeviceExit)(void);
struct InputDevice *ptNext; //加入链表,将多个输入设备链接到一起
} InputDevice, *PInputDevice;
//static int isInputBufferFull(void);
//static int isInputBufferEmpty(void);
//static void PutInputEventToBuffer(PInputEvent ptInputEvent);
//static int GetInputEventFromBuffer(PInputEvent ptInputEvent);
int GetInputEvent(PInputEvent ptInputEvent);
static void *input_recv_thread_func (void *data);
void RegisterInputDevice(PInputDevice ptInputDev);
void InputInit(void);
void InputDeviceInit(void);
int GetInputEvent(PInputEvent ptInputEvent);
#endif
1.6 page_manager.h
#ifndef _PAGE_MANAGER_H
#define _PAGE_MANAGER_H
typedef struct PageAction {
char *name;
void (*Run)(void *pParams);
struct PageAction *ptNext;
}PageAction, *PPageAction;
void PageRegister(PPageAction ptPageAction);
void PagesRegister(void);
PPageAction Page(char *name);
#endif
1.7 tslib.h(注意:该文件由tslib-1.21.tar.bz2通过交叉编译得来,可参考韦东山-电子量产工具项目:输入单元_Alexius Chao的博客-CSDN博客)
#ifndef _TSLIB_H_
#define _TSLIB_H_
/*
* tslib/src/tslib.h
*
* Copyright (C) 2016 Martin Kepplinger <martink@posteo.de>
* Copyright (C) 2001 Russell King.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
* USA
*
* SPDX-License-Identifier: LGPL-2.1
*
*
* Touch screen library interface definitions.
*/
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
#include <stdarg.h>
#include <sys/time.h>
#ifdef WIN32
#define TSIMPORT __declspec(dllimport)
#define TSEXPORT __declspec(dllexport)
#define TSLOCAL
#else
#define TSIMPORT
#ifdef GCC_HASCLASSVISIBILITY
#define TSEXPORT __attribute__ ((visibility("default")))
#define TSLOCAL __attribute__ ((visibility("hidden")))
#else
#define TSEXPORT
#define TSLOCAL
#endif
#endif
#ifdef TSLIB_INTERNAL
#define TSAPI TSEXPORT
#else
#define TSAPI TSIMPORT
#endif /* TSLIB_INTERNAL */
struct tsdev;
struct ts_sample {
int x;
int y;
unsigned int pressure;
struct timeval tv;
};
struct ts_sample_mt {
/* ABS_MT_* event codes. linux/include/uapi/linux/input-event-codes.h
* has the definitions.
*/
int x;
int y;
unsigned int pressure;
int slot;
int tracking_id;
int tool_type;
int tool_x;
int tool_y;
unsigned int touch_major;
unsigned int width_major;
unsigned int touch_minor;
unsigned int width_minor;
int orientation;
int distance;
int blob_id;
struct timeval tv;
/* BTN_TOUCH state */
short pen_down;
/* valid is set != 0 if this sample
* contains new data; see below for the
* bits that get set.
* valid is set to 0 otherwise
*/
short valid;
};
#define TSLIB_MT_VALID (1 << 0) /* any new data */
#define TSLIB_MT_VALID_TOOL (1 << 1) /* new tool_x or tool_y data */
struct ts_lib_version_data {
const char *package_version;
int version_num;
unsigned int features; /* bitmask, see below */
};
#define TSLIB_VERSION_MT (1 << 0) /* multitouch support */
#define TSLIB_VERSION_OPEN_RESTRICTED (1 << 1) /* ts_open_restricted() */
#define TSLIB_VERSION_EVENTPATH (1 << 2) /* ts_get_eventpath() */
#define TSLIB_VERSION_VERSION (1 << 3) /* tslib_version() */
enum ts_param {
TS_SCREEN_RES = 0, /* 2 integer args, x and y */
TS_SCREEN_ROT /* 1 integer arg, 1 = rotate */
};
struct ts_module_conf {
char *name;
char *params;
int raw;
int nr;
struct ts_module_conf *next;
struct ts_module_conf *prev;
};
/*
* Close the touchscreen device, free all resources.
*/
TSAPI int ts_close(struct tsdev *);
/*
* Reloads all modules - useful to reload calibration data.
*/
TSAPI int ts_reconfig(struct tsdev *);
/*
* Configure the touchscreen device.
*/
TSAPI int ts_config(struct tsdev *);
/*
* Changes a setting.
*/
TSAPI int ts_option(struct tsdev *, enum ts_param, ...);
/*
* Change this hook to point to your custom error handling function.
*/
extern TSAPI int (*ts_error_fn)(const char *fmt, va_list ap);
/*
* Implement this to override open() for the input device and return the fd.
*/
extern TSAPI int (*ts_open_restricted)(const char *path, int flags, void *user_data);
/*
* Implement this to override close().
*/
extern TSAPI void (*ts_close_restricted)(int fd, void *user_data);
/*
* Returns the file descriptor in use for the touchscreen device.
*/
TSAPI int ts_fd(struct tsdev *);
/*
* Load a filter/scaling module
*/
TSAPI int ts_load_module(struct tsdev *, const char *mod, const char *params);
/*
* Open the touchscreen device.
*/
TSAPI struct tsdev *ts_open(const char *dev_name, int nonblock);
/*
* Find, open and configure the touchscreen device.
*/
TSAPI struct tsdev *ts_setup(const char *dev_name, int nonblock);
/*
* Return a scaled touchscreen sample.
*/
TSAPI int ts_read(struct tsdev *, struct ts_sample *, int);
/*
* Returns a raw, unscaled sample from the touchscreen.
*/
TSAPI int ts_read_raw(struct tsdev *, struct ts_sample *, int);
/*
* Return a scaled touchscreen multitouch sample.
*/
TSAPI int ts_read_mt(struct tsdev *, struct ts_sample_mt **, int slots, int nr);
/*
* Return a raw, unscaled touchscreen multitouch sample.
*/
TSAPI int ts_read_raw_mt(struct tsdev *, struct ts_sample_mt **, int slots, int nr);
/*
* This function returns a pointer to a static copy of the version info struct.
*/
TSAPI struct ts_lib_version_data *ts_libversion(void);
/*
* Get the list of (commented-in) ts.conf module lines (as structs)
*/
TSAPI struct ts_module_conf *ts_conf_get(struct tsdev *ts);
/*
* Write the list of modules to ts.conf
*/
TSAPI int ts_conf_set(struct ts_module_conf *conf);
/*
* This function returns the path to the opened touchscreen input device file.
*/
TSAPI char *ts_get_eventpath(struct tsdev *tsdev);
/*
* This simply returns tslib's version string
*/
TSAPI char *tslib_version(void);
/*
* This prints tslib's logo to stdout, with pos preceding spaces
*/
TSAPI void ts_print_ascii_logo(unsigned int pos);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* _TSLIB_H_ */
1.8 ui.h
#ifndef _UI_H_
#define _UI_H_
#include<common.h>
#include<disp_manager.h>
#include<input_manager.h>
#define BUTTON_DEFAULT_COLOR 0xff0000 //red
#define BUTTON_PERCENT_COLOR 0x0000ff //blue
#define BUTTON_TEXT_COLOR 0x000000
#define BUTTON_PRESSED_COLOR 0x00ff00 //green
struct Button;
/* 函数指针(绘制按键) */
typedef int (*ONDRAW_FUNC)(struct Button *ptButton, PDispBuff ptDispBuff);
/* 函数指针(按下按钮) */
typedef int (*ONPRESSED_FUNC)(struct Button *ptButton, PDispBuff ptDispBuff, PInputEvent ptInputEvent);
typedef struct Button {
char *name; // 按键 名字
int status; //按键 按下状态
Region tRegion; // 按键的区域
ONDRAW_FUNC OnDraw; //一个 ONDRAW_FUNC 类型的函数指针,用于指向按钮绘制函数
ONPRESSED_FUNC OnPressed; //一个 ONPRESSED_FUNC 类型的函数指针,用于指向按钮按下事件处理函数
}Button, *PButton;
#endif
二、business文件夹
2.1 config.c
#include <config.h>
#include <string.h>
#include <stdio.h>
static ItemCfg g_tItemCfgs[ITEMCFG_MAX_NUM];
static int g_iItemCfgCount = 0;
int ParseConfigFile(void)
{
FILE *fp;
char buf[100];
char *p = buf;
/* 1. open config file */
fp = fopen(CFG_FILE, "r");
if (!fp)
{
printf("can not open cfg file %s\n", CFG_FILE);
return -1;
}
/*获取每行数据*/
while (fgets(buf, 100, fp))
{
/* 2.1 read each line */
buf[99] = '\0';
/* 2.2 吃掉开头的空格或TAB */
p = buf;
while (*p == ' ' || *p =='\t')
p++;
/* 2.3 忽略注释 */
if (*p == '#')
continue;
/* 2.4 处理 */
g_tItemCfgs[g_iItemCfgCount].command[0] = '\0';
g_tItemCfgs[g_iItemCfgCount].index = g_iItemCfgCount;
sscanf(p, "%s %d %s", g_tItemCfgs[g_iItemCfgCount].name, &g_tItemCfgs[g_iItemCfgCount].bCanBeTouched, \
g_tItemCfgs[g_iItemCfgCount].command);
g_iItemCfgCount++;
}
return 0;
}
int GetItemCfgCount(void)
{
return g_iItemCfgCount;
}
PItemCfg GetItemCfgByIndex(int index)
{
if (index < g_iItemCfgCount)
return &g_tItemCfgs[index];
else
return NULL;
}
PItemCfg GetItemCfgByName(char *name)
{
int i;
for (i = 0; i < g_iItemCfgCount; i++)
{
if (strcmp(name, g_tItemCfgs[i].name) == 0)
return &g_tItemCfgs[i];
}
return NULL;
}
2.2 main.c
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <linux/fb.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <sys/ioctl.h>
#include <stdlib.h>
#include <font_manager.h>
#include <disp_manager.h>
#include <page_manager.h>
#include <input_manager.h>
#include <wchar.h>//可以使用中文
#define FONTDATAMAX 4096
int main(int argc, char **argv)
{
//Region region;
//PDispBuff ptBuffer;
printf("main run!");
int error;
if (argc != 2)
{
printf("Usage: %s <font_size>\n", argv[0]); //打印用法
return -1;
}
/*显示系统初始化*/
DisplayInit();
SelectDefaultDisplay("fb");/*选择lcd显示设备*/
InitDefaultDisplay(); /*lcd显示设备初始化*/
//ptBuffer = GetDisplayBuffer(); /*获取显示内存空间*/
//FlushDisplayRegion(®ion, ptBuffer);
/*输入系统初始化*/
InputInit();
InputDeviceInit();
/*文字系统初始化*/
FontsRegister();/*注册字体*/
error = SelectAndInitFont("freetype", argv[1]);//选择字库操作
if (error)
{
printf("SelectAndInitFont err\n");
return -1;
}
/*页面系统初始化*/
PagesRegister();
/*运行业务系统的主页面*/
Page("main")->Run(NULL);
return 0;
}
2.3 Makefile
EXTRA_CFLAGS :=
CFLAGS_file.o :=
obj-y +=config.o
obj-y +=main.o
三、button文件夹
3.1 button.c(修改,在InitButton函数中添加if(ptRegion)判断)
#include<ui.h>
#include <string.h>
#include <disp_manager.h>
static int DefaultOnDraw(struct Button *ptButton, PDispBuff ptDispBuff){
/* 绘制底色 DrawRegion追加在disp_manager.c中 */
DrawRegion(&ptButton->tRegion, BUTTON_DEFAULT_COLOR); // 红色 0xff0000
/* 居中写文字 DrawTextInRegionCentral追加在disp_manager.c中*/
DrawTextInRegionCentral(ptButton->name, &ptButton->tRegion, BUTTON_TEXT_COLOR); //黑色 0x000000
/* flush to lcd/web */
FlushDisplayRegion(&ptButton->tRegion, ptDispBuff);
return 0;
}
static int DefaultOnPressed(struct Button *ptButton, PDispBuff ptDispBuff, PInputEvent ptInputEvent)
{
unsigned int dwColor = BUTTON_DEFAULT_COLOR;
ptButton->status = !ptButton->status;
if (ptButton->status)
dwColor = BUTTON_PRESSED_COLOR;
/* 绘制底色 */
DrawRegion(&ptButton->tRegion, dwColor);
/* 居中写文字 */
DrawTextInRegionCentral(ptButton->name, &ptButton->tRegion, BUTTON_TEXT_COLOR);
/* flush to lcd/web */
FlushDisplayRegion(&ptButton->tRegion, ptDispBuff);
return 0;
}
void InitButton(PButton ptButton, char *name, PRegion ptRegion, ONDRAW_FUNC OnDraw, ONPRESSED_FUNC OnPressed)
{
ptButton->status = 0; //初始状态为 0 ,未按下
ptButton->name = name;
if(ptRegion)
ptButton->tRegion = *ptRegion; // 按钮的区域
ptButton->OnDraw = OnDraw ? OnDraw : DefaultOnDraw; //若 OnDraw 为空,则执行默认绘制函数DefaultOnDraw
ptButton->OnPressed = OnPressed ? OnPressed : DefaultOnPressed; //若 OnPressed 为空,则执行默认绘制函数DefaultOnPressed
}
3.2 Makefile
EXTRA_CFLAGS :=
CFLAGS_file.o :=
obj-y +=button.o
四、display文件夹
4.1 disp_manager.c
#include "disp_manager.h"
#include "font_manager.h"
#include <stdio.h>
#include <string.h>
//管理底层lcd和web
/* display_manager.c */
static PDispOpr g_DispDevs = NULL;//设备链表表头
static PDispOpr g_DispDefault = NULL;
static DispBuff g_tDispBuff;
static unsigned int line_width;
static unsigned int pixel_width;
//绘制像素
int PutPixel(int x, int y, unsigned int dwColor)
{
char *pen_8 = g_tDispBuff.buff+y*line_width+x*pixel_width;
unsigned short *pen_16;
unsigned int *pen_32;
unsigned int red, green, blue;
pen_16 = (unsigned short *)pen_8;
pen_32 = (unsigned int *)pen_8;
switch (g_tDispBuff.iBpp)
{
case 8:
{
*pen_8 = dwColor;
break;
}
case 16:
{
/* 565 */
red = (dwColor >> 16) & 0xff;
green = (dwColor >> 8) & 0xff;
blue = (dwColor >> 0) & 0xff;
dwColor = ((red >> 3) << 11) | ((green >> 2) << 5) | (blue >> 3);
*pen_16 = dwColor;
break;
}
case 32:
{
*pen_32 = dwColor;
break;
}
default:
{
printf("can't surport %dbpp\n", g_tDispBuff.iBpp);
break;
}
}
return 0;
}
void RegisterDisplay(PDispOpr ptDispOpr)
{
ptDispOpr->ptNext = g_DispDevs;
g_DispDevs = ptDispOpr;
}
//链表中如果存在多个设备,则需要进行设备选择
int SelectDefaultDisplay(char *name)
{
PDispOpr pTmp = g_DispDevs;//从表头开始遍历
while (pTmp)
{
if (strcmp(name, pTmp->name) == 0)//找到了
{
g_DispDefault = pTmp;
return 0;
}
pTmp = pTmp->ptNext;
}
return -1;
}
int InitDefaultDisplay(void)
{
int ret;
ret = g_DispDefault->DeviceInit();
/*在调用前文SelectDefaultDisplay函数后,g_DispDefault即为g_tFramebufferOpr*/
if (ret)
{
printf("DeviceInit err\n");
return -1;
}
ret = g_DispDefault->GetBuffer(&g_tDispBuff);
if (ret)
{
printf("GetBuffer err\n");
return -1;
}
line_width = g_tDispBuff.iXres * g_tDispBuff.iBpp/8;
pixel_width = g_tDispBuff.iBpp/8;
return 0;
}
PDispBuff GetDisplayBuffer(void)
{
return &g_tDispBuff;
}
int FlushDisplayRegion(PRegion ptRegion, PDispBuff ptDispBuff)
{
return g_DispDefault->FlushRegion(ptRegion, ptDispBuff);
}
//文字绘制函数
void DrawFontBitMap(PFontBitMap ptFontBitMap, unsigned int dwColor)
{
int i, j, p, q;
int x = ptFontBitMap->tRegion.iLeftUpX;
int y = ptFontBitMap->tRegion.iLeftUpY;
int x_max = x + ptFontBitMap->tRegion.iWidth;
int y_max = y + ptFontBitMap->tRegion.iHeigh;
int width = ptFontBitMap->tRegion.iWidth;
unsigned char *buffer = ptFontBitMap->pucBuffer;
//printf("x = %d, y = %d\n", x, y);
for ( j = y, q = 0; j < y_max; j++, q++ )
{
for ( i = x, p = 0; i < x_max; i++, p++ )
{
if ( i < 0 || j < 0 ||
i >= g_tDispBuff.iXres || j >= g_tDispBuff.iYres )
continue;
//image[j][i] |= bitmap->buffer[q * bitmap->width + p];
if (buffer[q * width + p])
PutPixel(i, j, dwColor);
}
}
}
// 区域绘制函数
void DrawRegion(PRegion ptRegion, unsigned int dwColor)
{
int x = ptRegion->iLeftUpX;
int y = ptRegion->iLeftUpY;
int width = ptRegion->iWidth;
int heigh = ptRegion->iHeigh;
int i,j;
for (j = y; j < y + heigh; j++)
{
for (i = x; i < x + width; i++)
PutPixel(i, j, dwColor);
}
}
//文本绘制函数
void DrawTextInRegionCentral(char *name, PRegion ptRegion, unsigned int dwColor)
{
int n = strlen(name);
int iFontSize = ptRegion->iWidth / n / 2;
FontBitMap tFontBitMap;
int iOriginX, iOriginY;
int i = 0;
int error;
if (iFontSize > ptRegion->iHeigh)
iFontSize = ptRegion->iHeigh;
iOriginX = (ptRegion->iWidth - n * iFontSize)/2 + ptRegion->iLeftUpX;
iOriginY = (ptRegion->iHeigh - iFontSize)/2 + iFontSize + ptRegion->iLeftUpY;
SetFontSize(iFontSize);
while (name[i])
{
/* get bitmap */
tFontBitMap.iCurOriginX = iOriginX;
tFontBitMap.iCurOriginY = iOriginY;
error = GetFontBitMap(name[i], &tFontBitMap);
if (error)
{
printf("SelectAndInitFont err\n");
return;
}
/* draw on buffer */
DrawFontBitMap(&tFontBitMap, dwColor);
iOriginX = tFontBitMap.iNextOriginX;
iOriginY = tFontBitMap.iNextOriginY;
i++;
}
}
/* display_manager.c */
void DisplayInit(void)
{
extern void FramebufferInit(void); /*对应framebuffer设备lcd输出*/
FramebufferInit();
/*WebTnit()-对应web输出未实现*/
}
4.2 framebuffer.c
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <linux/fb.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <sys/ioctl.h>
#include "disp_manager.h"
static int fd_fb; //设备节点的文件权柄
static struct fb_var_screeninfo var; /* Current var */
static int screen_size;
static unsigned char *fb_base;//LCD的framebuffer地址
static unsigned int line_width;
static unsigned int pixel_width;
static int FbDeviceInit(void) //设备初始化函数
{
fd_fb = open("/dev/fb0", O_RDWR);//打开设备节点
if (fd_fb < 0)
{
printf("can't open /dev/fb0\n");
return -1;
}
if (ioctl(fd_fb, FBIOGET_VSCREENINFO, &var))
{
printf("can't get var\n");
return -1;
}
//var.xres x方向的分辨率
line_width = var.xres * var.bits_per_pixel / 8;
pixel_width = var.bits_per_pixel / 8;
screen_size = var.xres * var.yres * var.bits_per_pixel / 8;
fb_base = (unsigned char *)mmap(NULL , screen_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd_fb, 0);//内存映射
if (fb_base == (unsigned char *)-1)
{
printf("can't mmap\n");
return -1;
}
return 0;
}
static int FbDeviceExit(void) //设备退出函数,释放设备资源
{
munmap(fb_base, screen_size);//取消内存映射
close(fd_fb);
return 0;
}
/* 可以返回LCD的framebuffer, 以后上层APP可以直接操作LCD, 可以不用FbFlushRegion
* 也可以malloc返回一块无关的buffer, 要使用FbFlushRegion
*/
static int FbGetBuffer(PDispBuff ptDispBuff)//获取内存空间
{
ptDispBuff->iXres = var.xres;
ptDispBuff->iYres = var.yres;
ptDispBuff->iBpp = var.bits_per_pixel;
ptDispBuff->buff = (char *)fb_base;
return 0;
}
static int FbFlushRegion(PRegion ptRegion, char *buffer) //刷新函数
{
return 0;
}
// 构建framebuffer设备结构体
static DispOpr g_tFramebufferOpr = {
.name = "fb", //设备的名字是fb
.DeviceInit = FbDeviceInit, //
.DeviceExit = FbDeviceExit, //
.GetBuffer = FbGetBuffer, //获得buf空间中的数据
.FlushRegion = FbFlushRegion, //刷新
};
void FramebufferInit(void)
{
RegisterDisplay(&g_tFramebufferOpr);
}
4.3 Makefile
EXTRA_CFLAGS :=
CFLAGS_file.o :=
obj-y +=disp_manager.o
obj-y +=framebuffer.o
五、freetype文件夹
5.1 font_manager.c
#include "font_manager.h"
#include <string.h>
static PFontOpr g_ptFonts = NULL;
static PFontOpr g_ptDefaulFontOpr = NULL;
void RegisterFont(PFontOpr ptFontOpr)
{
ptFontOpr->ptNext = g_ptFonts;
g_ptFonts = ptFontOpr;
}
void FontsRegister(void)
{
extern void FreetypeRegister(void);
FreetypeRegister();
}
int SelectAndInitFont(char *aFontOprName, char *aFontFileName)
{
PFontOpr ptTmp = g_ptFonts;
while (ptTmp)
{
if (strcmp(ptTmp->name, aFontOprName) == 0)
break;
ptTmp = ptTmp->ptNext;
}
if (!ptTmp)
return -1;
g_ptDefaulFontOpr = ptTmp;
return ptTmp->FontInit(aFontFileName);
}
int SetFontSize(int iFontSize)
{
return g_ptDefaulFontOpr->SetFontSize(iFontSize);
}
int GetFontBitMap(unsigned int dwCode, PFontBitMap ptFontBitMap)
{
return g_ptDefaulFontOpr->GetFontBitMap(dwCode, ptFontBitMap);
}
5.2 freetype.c
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <linux/fb.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <wchar.h>
#include <sys/ioctl.h>
#include "font_manager.h"
#include <ft2build.h>//freetype库中的一个头文件
#include FT_FREETYPE_H
#include FT_GLYPH_H
static FT_Face g_tFace;
static int g_iDefaultFontSize = 12;
static int FreeTypeFontInit(char *aFineName)
{
FT_Library library;
int error;
error = FT_Init_FreeType( &library ); /* initialize library */
if (error)
{
printf("FT_Init_FreeType err\n");
return -1;
}
error = FT_New_Face(library, aFineName, 0, &g_tFace ); /* create face object */
if (error)
{
printf("FT_New_Face err\n");
return -1;
}
FT_Set_Pixel_Sizes(g_tFace, g_iDefaultFontSize, 0);
return 0;
}
static int FreeTypeSetFontSize(int iFontSize)
{
FT_Set_Pixel_Sizes(g_tFace, iFontSize, 0);
return 0;
}
//给编码值,得到位图
static int FreeTypeGetFontBitMap(unsigned int dwCode, PFontBitMap ptFontBitMap)
{
int error;
FT_Vector pen;
FT_GlyphSlot slot = g_tFace->glyph;
pen.x = ptFontBitMap->iCurOriginX * 64; /* 单位: 1/64像素 */
pen.y = ptFontBitMap->iCurOriginY * 64; /* 单位: 1/64像素 */
/* 转换:transformation */
FT_Set_Transform(g_tFace, 0, &pen);//FT_Set_Transform是FreeType库中的函数
/* 加载位图: load glyph image into the slot (erase previous one) */
error = FT_Load_Char(g_tFace, dwCode, FT_LOAD_RENDER);
if (error)
{
printf("FT_Load_Char error\n");
return -1;
}
ptFontBitMap->pucBuffer = slot->bitmap.buffer;
ptFontBitMap->tRegion.iLeftUpX = slot->bitmap_left;
ptFontBitMap->tRegion.iLeftUpY = ptFontBitMap->iCurOriginY*2 - slot->bitmap_top;
ptFontBitMap->tRegion.iWidth = slot->bitmap.width;
ptFontBitMap->tRegion.iHeigh = slot->bitmap.rows;
ptFontBitMap->iNextOriginX = ptFontBitMap->iCurOriginX + slot->advance.x / 64;
ptFontBitMap->iNextOriginY = ptFontBitMap->iCurOriginY;
return 0;
}
//描述字库操作及对应具体实现
static FontOpr g_tFreetypeOpr = {
.name = "freetype",
.FontInit = FreeTypeFontInit,
.SetFontSize = FreeTypeSetFontSize,
.GetFontBitMap = FreeTypeGetFontBitMap,
};
void FreetypeRegister(void)
{
RegisterFont(&g_tFreetypeOpr);
}
5.3 Makefile
EXTRA_CFLAGS :=
CFLAGS_file.o :=
obj-y +=freetype.o
obj-y +=font_manager.o
六、input文件夹
6.1 input_manager.c
#include "input_manager.h"
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
#include <semaphore.h>
#include <string.h>
static pthread_mutex_t g_tMutex = PTHREAD_MUTEX_INITIALIZER;
static pthread_cond_t g_tConVar = PTHREAD_COND_INITIALIZER;
static PInputDevice g_InputDevs = NULL;
/************环形缓冲区开******************/
#define BUFFER_LEN 20 /*环形缓冲区长度*/
static int g_iRead = 0; /*读指针*/
static int g_iWrite = 0; /*写指针*/
static InputEvent g_atInputEvents[BUFFER_LEN]; /*环形缓冲区*/
/*判断环形缓冲区是否为满*/
static int isInputBufferFull(void)
{
return (g_iRead == ((g_iWrite + 1) % BUFFER_LEN));
}
/*判断环形缓冲区是否为空*/
static int isInputBufferEmpty(void)
{
return (g_iRead == g_iWrite);
}
/************环形缓冲区关******************/
//缓冲区事件存储函数
static void PutInputEventToBuffer(PInputEvent ptInputEvent)
{
if (!isInputBufferFull())
{
g_atInputEvents[g_iWrite] = *ptInputEvent;
g_iWrite = (g_iWrite + 1) % BUFFER_LEN;
}
}
//缓冲区事件获取函数
static int GetInputEventFromBuffer(PInputEvent ptInputEvent)
{
if (!isInputBufferEmpty())
{
*ptInputEvent = g_atInputEvents[g_iRead];
g_iRead = (g_iRead + 1) % BUFFER_LEN;
return 1;
}
else
{
return 0;
}
}
// 事件获取函数
int GetInputEvent(PInputEvent ptInputEvent)
{
InputEvent tEvent;
int ret;
/* 无数据则休眠 */
pthread_mutex_lock(&g_tMutex); /*互斥锁*/
if (GetInputEventFromBuffer(&tEvent))
{
*ptInputEvent = tEvent;
pthread_mutex_unlock(&g_tMutex);/*释放互斥锁*/
return 0;
}
else
{
/* 休眠等待 */
pthread_cond_wait(&g_tConVar, &g_tMutex);
if (GetInputEventFromBuffer(&tEvent))
{
*ptInputEvent = tEvent;
ret = 0;
}
else
{
ret = -1;
}
pthread_mutex_unlock(&g_tMutex); /*释放互斥锁*/
}
return ret;
}
//线程函数
static void *input_recv_thread_func (void *data)
{
PInputDevice ptInputDev = (PInputDevice)data;
InputEvent tEvent;
int ret;
while (1)
{
/* 读数据 */
ret = ptInputDev->GetInputEvent(&tEvent);
if (!ret)
{
/* 保存数据 */
pthread_mutex_lock(&g_tMutex);
PutInputEventToBuffer(&tEvent);
/* 唤醒等待数据的线程 */
pthread_cond_signal(&g_tConVar); /* 通知接收线程 */
pthread_mutex_unlock(&g_tMutex);
}
}
return NULL;
}
void RegisterInputDevice(PInputDevice ptInputDev)
{
ptInputDev->ptNext = g_InputDevs;//指向链表头
g_InputDevs = ptInputDev;
}
void InputInit(void)
{
/* 注册按键输入 */
extern void TouchscreenRegister(void);
TouchscreenRegister();//在touchscreen.c中
/* 注册网络输入 */
extern void NetInputRegister(void);
NetInputRegister();//在netinput.c中
}
void InputDeviceInit(void)
{
int ret;
pthread_t tid;
/* for each device ,init,pthread_create */
PInputDevice ptTmp = g_InputDevs;
while (ptTmp)
{
ret = ptTmp->DeviceInit();
if (!ret)
{
ret = pthread_create(&tid, NULL, input_recv_thread_func, ptTmp);
}
ptTmp = ptTmp->ptNext;
}
}
6.2 netinput.c
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include "input_manager.h"
#define SERVER_PORT 8888
static int g_iSocketServer;
static int NetinputGetInputEvent(PInputEvent ptInputEvent)
{
char ucRecvBuf[1000];
int iRecvLen;
struct sockaddr_in tSocketClientAddr;
unsigned int iAddrLen = sizeof(struct sockaddr);
/* 接收客户端数据报文,返回的为接收到的字节数 */
iRecvLen = recvfrom(g_iSocketServer, ucRecvBuf, sizeof(ucRecvBuf), 0, (struct sockaddr *)&tSocketClientAddr, &iAddrLen);
if (iRecvLen > 0)
{
ucRecvBuf[iRecvLen] = '\0';
//printf("Get Msg from %s : %s\n", inet_ntoa(socket_client_addr.sin_addr), buf);
ptInputEvent->iType = INPUT_TYPE_NET;
gettimeofday(&ptInputEvent->tTime, NULL);
strncpy(ptInputEvent->str, ucRecvBuf, 1000);
ptInputEvent->str[999] = '\0';
return 0;
}
else
return -1;
}
static int NetinputDeviceInit(void)
{
struct sockaddr_in tSocketServerAddr;
int iRet;
/*创建数据报套接字*/
g_iSocketServer = socket(AF_INET, SOCK_DGRAM, 0);
if (g_iSocketServer == -1)
{
printf("socket error");
return -1;
}
/* 服务器端填充 sockaddr_in结构 */
tSocketServerAddr.sin_family = AF_INET;
tSocketServerAddr.sin_port = htons(SERVER_PORT);
tSocketServerAddr.sin_addr.s_addr = INADDR_ANY;
memset(tSocketServerAddr.sin_zero, 0, 8);
/*绑定套接字*/
iRet = bind(g_iSocketServer, (const struct sockaddr *)&tSocketServerAddr, sizeof(struct sockaddr));
if (iRet == -1)
{
printf("bind error!\n");
return -1;
}
return 0;
}
static int NetinputDeviceExit(void)
{
close(g_iSocketServer);
return 0;
}
static InputDevice g_tNetinputDev = {
.name = "netinput",
.GetInputEvent = NetinputGetInputEvent,
.DeviceInit = NetinputDeviceInit,
.DeviceExit = NetinputDeviceExit,
};
void NetInputRegister(void)
{
RegisterInputDevice(&g_tNetinputDev);
}
#if 0
int main(int argc, char **argv)
{
InputEvent event;
int ret;
g_tNetinputDev.DeviceInit();
while (1)
{
ret = g_tNetinputDev.GetInputEvent(&event);
if (ret)
{
printf("GetInputEvent err\r\n");
return -1;
}
else
{
printf("iType =%d\r\n", event.iType);
printf("str =%s\r\n", event.str);
}
}
return 0;
}
#endif
6.3 touchscreen.c
#include "input_manager.h"
#include <tslib.h>
#include <stdio.h>
struct tsdev *g_ts;
//获取触摸事件
static int TouchscreenGetInputEvent(PInputEvent ptInputEvent)
{
struct ts_sample samp;
int ret;
ret = ts_read(g_ts, &samp, 1);
if (ret != 1)
return -1;
ptInputEvent->iType = INPUT_TYPE_TOUCH;
ptInputEvent->iX = samp.x;
ptInputEvent->iY = samp.y;
ptInputEvent->iPressure = samp.pressure;
ptInputEvent->tTime = samp.tv;
return 0;
}
//触摸屏设备初始化
static int TouchscreenDeviceInit(void)
{
/* 打开并配置触摸屏设备 */
g_ts = ts_setup(NULL, 0);
if (!g_ts)
{
printf("ts_setup err\n");
return -1;
}
return 0;
}
//触摸设备退出
static int TouchscreenDeviceExit(void)
{
ts_close(g_ts);
return 0;
}
//设备结构体
static InputDevice g_tTouchscreenDev = {
.name = "touchscreen",
.GetInputEvent = TouchscreenGetInputEvent,
.DeviceInit = TouchscreenDeviceInit,
.DeviceExit = TouchscreenDeviceExit,
};
void TouchscreenRegister(void)
{
RegisterInputDevice(&g_tTouchscreenDev);
}
#if 0
int main(int argc, char **argv)
{
InputEvent event;
int ret;
g_tTouchscreenDev.DeviceInit();
while (1)
{
ret = g_tTouchscreenDev.GetInputEvent(&event);
if (ret)
{
printf("GetInputEvent err\r\n");
return -1;
}
else
{
printf("iType =%d\r\n", event.iType);
printf("iX =%d\r\n", event.iX);
printf("iY =%d\r\n", event.iY);
printf("iPressure =%d\r\n", event.iPressure);
}
}
return 0;
}
#endif
6.4 Makefile
EXTRA_CFLAGS :=
CFLAGS_file.o :=
obj-y +=input_manager.o
obj-y +=netinput.o
obj-y +=touchscreen.o
七、page文件夹
7.1 main_page.c
#include <page_manager.h>
#include <config.h>
#include <string.h>
#include <stdio.h>
#include <math.h>
#include <ui.h>
#define X_GAP 5
#define Y_GAP 5
static Button g_tButtons[ITEMCFG_MAX_NUM];
static int g_tButtonCnt;
static int MainPageOnPressed(struct Button *ptButton, PDispBuff ptDispBuff, PInputEvent ptInputEvent)
{
unsigned int dwColor = BUTTON_DEFAULT_COLOR;
char name[100];
char status[100];
char *strButton;
strButton = ptButton->name;
/* 1. 对于触摸屏事件 */
if (ptInputEvent->iType == INPUT_TYPE_TOUCH)
{
/* 1.1 分辨能否被点击 */
if (GetItemCfgByName(ptButton->name)->bCanBeTouched == 0)
return -1;
/* 1.2 修改颜色 */
ptButton->status = !ptButton->status;
if (ptButton->status)//button color
dwColor = BUTTON_PRESSED_COLOR;
strButton = ptButton->name;
}
else if (ptInputEvent->iType == INPUT_TYPE_NET)
{
/* 2. 对于网络事件 */
/* 根据传入的字符串修改颜色 : wifi ok, wifi err, burn 70 */
sscanf(ptInputEvent->str, "%s %s", name, status);
if (strcmp(status, "ok") == 0)
dwColor = BUTTON_PRESSED_COLOR;//green
else if (strcmp(status, "err") == 0)
dwColor = BUTTON_DEFAULT_COLOR;//red
else if (status[0] >= '0' && status[0] <= '9')//blue
{
dwColor = BUTTON_PERCENT_COLOR;
strButton = status;
}
else
return -1;
}
else
{
return -1;
}
/* 绘制底色 */
DrawRegion(&ptButton->tRegion, dwColor);
/* 居中写文字 */
DrawTextInRegionCentral(strButton, &ptButton->tRegion, BUTTON_TEXT_COLOR);
/* 刷新界面到 lcd/web */
FlushDisplayRegion(&ptButton->tRegion, ptDispBuff);
return 0;
}
/* 根据配置文件生成按钮、界面 */
static void GenerateButtons(void)
{
int width, height;
int n_per_line;
int row, rows;
int col;
int n;
PDispBuff pDispBuff;
int xres, yres;
int start_x, start_y;
int pre_start_x, pre_start_y;
PButton pButton;
int i = 0;
/* 算出单个按钮的width/height */
g_tButtonCnt = n = GetItemCfgCount();
pDispBuff = GetDisplayBuffer();
xres = pDispBuff->iXres;
yres = pDispBuff->iYres;
width = sqrt(1.0/0.618 *xres * yres / n);
n_per_line = xres / width + 1;
width = xres / n_per_line;
height = 0.618 * width;
/* 居中显示: 计算每个按钮的region */
start_x = (xres - width * n_per_line) / 2;
rows = n / n_per_line;
if (rows * n_per_line < n)
rows++;
start_y = (yres - rows*height)/2;
/* 计算每个按钮的region */
for (row = 0; (row < rows) && (i < n); row++)
{
pre_start_y = start_y + row * height;
pre_start_x = start_x - width;
for (col = 0; (col < n_per_line) && (i < n); col++)
{
pButton = &g_tButtons[i];
pButton->tRegion.iLeftUpX = pre_start_x + width;
pButton->tRegion.iLeftUpY = pre_start_y;
pButton->tRegion.iWidth = width - X_GAP;
pButton->tRegion.iHeigh = height - Y_GAP;
pre_start_x = pButton->tRegion.iLeftUpX;
/* InitButton */
InitButton(pButton, GetItemCfgByIndex(i)->name, NULL, NULL, MainPageOnPressed);
i++;
}
}
/* OnDraw */
for (i = 0; i < n; i++)
g_tButtons[i].OnDraw(&g_tButtons[i], pDispBuff);
}
/* 判断点击的位置 */
static int isTouchPointInRegion(int iX, int iY, PRegion ptRegion)
{
if (iX < ptRegion->iLeftUpX || iX >= ptRegion->iLeftUpX + ptRegion->iWidth)
return 0;
if (iY < ptRegion->iLeftUpY || iY >= ptRegion->iLeftUpY + ptRegion->iHeigh)
return 0;
return 1;
}
/*根据名字获取配置文件*/
static PButton GetButtonByName(char *name)
{
int i;
for(i=0;i<g_tButtonCnt;i++)
{
if(strcmp(name,g_tButtons[i].name)==0)
return &g_tButtons[i];
}
return NULL;
}
/* 根据输入事件找到按钮 */
static PButton GetButtonByInputEvent(PInputEvent ptInputEvent)
{
int i;
char name[100];
if (ptInputEvent->iType == INPUT_TYPE_TOUCH)//触摸得到事件
{
for (i = 0; i < g_tButtonCnt; i++)
{ ///* 判断点击的位置 */
if (isTouchPointInRegion(ptInputEvent->iX, ptInputEvent->iY, &g_tButtons[i].tRegion))
return &g_tButtons[i];
}
}
else if (ptInputEvent->iType == INPUT_TYPE_NET)//网络得到事件
{
sscanf(ptInputEvent->str, "%s", name);
return GetButtonByName(name);
}
else
{
return NULL;
}
return NULL;
}
static void MainPageRun(void *pParams)
{
int error;
InputEvent tInputEvent;
PButton ptButton;
PDispBuff ptDispBuff = GetDisplayBuffer();
/* 读取配置文件 */
error = ParseConfigFile();
if (error)
return ;
/* 根据配置文件生成按钮、界面 */
GenerateButtons();
while (1)
{
/* 读取输入事件 */
error = GetInputEvent(&tInputEvent);
if (error)
continue;
/* 根据输入事件找到按钮 */
ptButton = GetButtonByInputEvent(&tInputEvent);
if (!ptButton)
continue;
/* 调用按钮的OnPressed函数 */
ptButton->OnPressed(ptButton, ptDispBuff, &tInputEvent);
}
}
static PageAction g_tMainPage = {
.name = "main",
.Run = MainPageRun,
};
void MainPageRegister(void)
{
PageRegister(&g_tMainPage);
}
7.2 page_manager.c
#include <common.h>
#include <page_manager.h>
#include <string.h>
static PPageAction g_ptPages = NULL;
void PageRegister(PPageAction ptPageAction)
{
ptPageAction->ptNext = g_ptPages;
g_ptPages = ptPageAction;
}
PPageAction Page(char *name)
{
PPageAction ptTmp = g_ptPages;
while (ptTmp)
{
if (strcmp(name, ptTmp->name) == 0)
return ptTmp;
ptTmp = ptTmp->ptNext;
}
return NULL;
}
void PagesRegister(void)
{
extern void MainPageRegister(void);
MainPageRegister();
}
7.3 Makefile
EXTRA_CFLAGS :=
CFLAGS_file.o :=
obj-y +=main_page.o
obj-y +=page_manager.o
八、顶层Makefile及Makefile.build
8.1 Makefile
注意:LDFLAGS 添加链接器。此外freetype的交叉编译可参考韦东山-电子量产工具项目:文字单元_Alexius Chao的博客-CSDN博客b韦东山-电子量产工具项目:文字单元_Alexius Chao的博客-CSDN博客b韦东山-电子量产工具项目:文字单元_Alexius Chao的博客-CSDN博客韦东山-电子量产工具项目:文字单元_Alexius Chao的博客-CSDN博客b韦东山-电子量产工具项目:文字单元_Alexius Chao的博客-CSDN博客b
交叉编译完成后Makefile中指定LDFLAGS CFLAGS
#指定交叉编译工具链
COSS_COMPLE ?=arm-linux-gnueabihf-
AS = $(COSS_COMPLE)as
LD = $(COSS_COMPLE)ld
CC = $(COSS_COMPLE)gcc
CPP = $(CC) -E
AR = $(CROSS_COMPILE)ar
NM = $(CROSS_COMPILE)nm
STRIP = $(CROSS_COMPILE)strip
OBJCOPY = $(CROSS_COMPILE)objcopy
OBJDUMP = $(CROSS_COMPILE)objdump
# export导出的变量是给子目录下的Makefile使用的
export AS LD CC CPP AR NM
export STRIP OBJCOPY OBJDUMP
# 编译器在编译时的参数设置
CFLAGS := -Wall -O2 -g -DDEBUG
# 添加头文件路径,不添加的话include目录下的头文件编译时找不到
CFLAGS += -I $(shell pwd)/include -I/home/alexius/Downloads/freetype-2.10.2/install/include/freetype2
# 链接器的链接参数设置,链接库
LDFLAGS := -L/home/alexius/Downloads/tslib-1.21/install/lib -lts -L/home/alexius/Downloads/freetype-2.10.2/install/lib -lfreetype -lpthread -lm #触摸屏库链接
export CFLAGS LDFLAGS
TOPDIR := $(shell pwd)
export TOPDIR
# 定义将来编译生成的可执行程序的名字
TARGET := business_test
# 添加项目中所有用到的源文件,有顶层目录下的.c文件,和子文件夹
# 添加顶层目录下的.c文件
#obj-y += main.o
# 添加顶层目录下的子文件夹(注意目录名后面加一个/)
#obj-y += main.o
obj-y += page/
obj-y += input/
obj-y += business/
obj-y += display/
obj-y += button/
obj-y += freetype/
# 第一个目标
all : start_recursive_build $(TARGET)
@echo $(TARGET) has been built!
# 处理第一个依赖,**转到 Makefile.build 执行**
start_recursive_build:
make -C ./ -f $(TOPDIR)/Makefile.build
# 处理最终目标,把前期处理得出的 built-in.o 用上
$(TARGET) : built-in.o
$(CC) -o $(TARGET) built-in.o $(LDFLAGS)
# 清理
clean:
rm -f $(shell find -name "*.o")
rm -f $(TARGET)
# 彻底清理
distclean:
rm -f $(shell find -name "*.o")
rm -f $(shell find -name "*.d")
rm -f $(TARGET)
8.2 Makefile.build
# 将__build定义为伪目标
PHONY := __build
__build:
# 这里初值为空,下面引入Makefile文件后会被覆盖
obj-y :=
subdir-y :=
# 包含同级目录的Makefile
include Makefile
# 从obj-y变量中,将"/"结尾的字符串提取出来,也就是包含的子文件夹目录
__subdir-y := $(patsubst %/,%,$(filter %/, $(obj-y)))
subdir-y += $(__subdir-y)
# 将subdir-y变量中的字符串依次赋值给f变量,形成新的$(f)/built-in.o字符串
subdir_objs := $(foreach f,$(subdir-y),$(f)/built-in.o)
# 筛选出obj-y中不以"/"结尾的字符串,也就是普通文件,一般是.o结尾
cur_objs := $(filter-out %/, $(obj-y))
# 为每个.o文件生成.d文件
# 注意.$(f).d是隐藏文件,需要ls -a查看
dep_files := $(foreach f,$(cur_objs),.$(f).d)
dep_files := $(wildcard $(dep_files))
# 如果.d文件不是空,则将.d文件都包含进来
ifneq ($(dep_files),)
include $(dep_files)
endif
PHONY += $(subdir-y)
# __build是Makefile的目标
__build : $(subdir-y) built-in.o
# 依次跳转到子目录中,执行Makefile.build文件
$(subdir-y):
make -C $@ -f $(TOPDIR)/Makefile.build
# 生成当前目录的built-in.o,依赖当前目录的.o文件和子目录下的built-in.o文件
built-in.o : $(cur_objs) $(subdir_objs)
$(LD) -r -o $@ $^
# dep_file变量是用来生成.d文件的
dep_file = .$@.d
# Makefile中的规则,把.c文件编译成.o文件
%.o : %.c
$(CC) $(CFLAGS) -Wp,-MD,$(dep_file) -c -o $@ $<
# 重新定义 .PHONY的依赖
.PHONY : $(PHONY)
九、编译
十、client.c文件
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdio.h>
#define SERVER_PORT 8888
int main(int argc, char **argv)
{
int iSocketClient;
struct sockaddr_in tSocketServerAddr;
int iRet;
int iSendLen;
int iAddrLen;
if (argc != 3)
{
printf("Usage:\n");
printf("%s <server_ip> <str>\n", argv[0]);
return -1;
}
iSocketClient = socket(AF_INET, SOCK_DGRAM, 0);
tSocketServerAddr.sin_family = AF_INET;
tSocketServerAddr.sin_port = htons(SERVER_PORT); /* host to net, short */
//tSocketServerAddr.sin_addr.s_addr = INADDR_ANY;
if (0 == inet_aton(argv[1], &tSocketServerAddr.sin_addr))
{
printf("invalid server_ip\n");
return -1;
}
memset(tSocketServerAddr.sin_zero, 0, 8);
#if 0
iRet = connect(iSocketClient, (const struct sockaddr *)&tSocketServerAddr, sizeof(struct sockaddr));
if (-1 == iRet)
{
printf("connect error!\n");
return -1;
}
#endif
iAddrLen = sizeof(struct sockaddr);
iSendLen = sendto(iSocketClient, argv[2], strlen(argv[2]), 0,(const struct sockaddr *)&tSocketServerAddr, iAddrLen);
close(iSocketClient);
return 0;
}
该文件需要单独编译,执行arm-linux-gnueabihf-gcc client.c -o all_client
十一、gui.conf文件
# name can_be_touch command
led 1
speaker 1
record 0
key 0
4G 0
usb 0
serial 0
wifi 0
net0 0
net1 0
burn 0
all 0
十二、测试结果
将可执行文件all_client buinss business_test及配置项gui.conf拷贝到开发板:
执行
./business_test ./SIMSUN.TTC &
执行
./all_client 192.168.10.50 "led ok"
./all_client 192.168.10.50 "burn 88"