韦东山-电子量产工具项目:业务系统

news2024/11/26 9:44:21

代码结构

所有代码都已通过测试跑通,其中代码结构如下:

  一、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(&region, 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"

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/903719.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Apache DolphinScheduler 支持使用 OceanBase 作为元数据库啦!

DolphinScheduler是一个开源的分布式任务调度系统&#xff0c;拥有分布式架构、多任务类型、可视化操作、分布式调度和高可用等特性&#xff0c;适用于大规模分布式任务调度的场景。目前DolphinScheduler支持的元数据库有Mysql、PostgreSQL、H2&#xff0c;如果在业务中需要更好…

【视觉SLAM入门】5.2. 2D-3D PNP 3D-3D ICP BA非线性优化方法 数学方法SVD DLT

"养气之学&#xff0c;戒之躁急" 1. 3D-2D PNP1.1 代数法1.1.1 DLT(直接线性变换法)1.1.2. P3P 1.2 优化法BA (Bundle Adjustment)法 2. 3D-3D ICP2.1 代数法2.1.1 SVD方法 2.2 优化(BA)法2.2.2 非线性优化方法 前置事项&#xff1a; 1. 3D-2D PNP 该问题描述为&am…

使用swoole实现实时消息推送给客户端

一. 测试服务端 //测试服务端public function testServer(){$server new Server(192.168.0.144, 9501, SWOOLE_BASE, SWOOLE_SOCK_TCP);$server->on(request, function ($request, $response) {$response->header(Content-Type, text/plain);$response->end("He…

【操作系统】虚拟内存相关分段分页页面置换算法

虚拟内存是什么&#xff1f; 【进程地址空间虚拟地址空间C/C程序地址空间就是那个4G的空间】 虚拟内存是操作系统内核为了对进程地址空间进行管理&#xff0c;而设计的一个逻辑意义上的内存空间概念。在程序运行过程中&#xff0c;虚拟内存中需要被访问的部分会被映射到物理内…

Mock平台-08开发:项目管理(四)编辑功能和Component抽离

【Mock平台】为系列测试开发教程&#xff0c;从0到1编码带你一步步使用Spring Boot 和 Antd React框架完成搭建一个测试工具平台&#xff0c;希望作为一个实战项目对各位的测试开发学习之路有帮助&#xff0c;大奇一个专注测试技术干货原创与分享的家伙。 本篇重点&#xff1a;…

HCIP生成树STP总结

STP生成树 网桥的4个选举 根网桥&#xff1a; 有且仅有一台&#xff0c;且由BPDU中的桥ID来决定 桥ID 网桥优先级&#xff08;0-65535公有&#xff09; 默认32768 MAC地址&#xff08;只有…

湘潭大学 湘大 XTU OJ 1055 整数分类 题解(非常详细)

链接 整数分类 题目 Description 按照下面方法对整数x进行分类&#xff1a;如果x是一个个位数&#xff0c;则x属于x类&#xff1b;否则将x的各位上的数码累加&#xff0c;得到一个新的x&#xff0c;依次迭代&#xff0c;可以得到x的所属类。比如说24&#xff0c;246&#…

漏洞指北-VulFocus靶场专栏-高级01

漏洞指北-VulFocus靶场专栏-高级01 高级001 &#x1f338;骑士cms任意代码执行&#xff08;CVE-2020-35339&#xff09;&#x1f338;step1&#xff1a;进入页面&#xff0c;登入后台step2 系统——网站配置——网站域名step3 中国蚁剑连接 高级002 &#x1f338;Django SQL注入…

安装ps找不到vcruntime140_1.dll怎么回事?有哪些解决方法

安装ps找不到vcruntime140_1.dll怎么回事&#xff1f;这可能是因为您的计算机Visual C Redistributable包损坏&#xff0c;其中包含vcruntime140_1.dll文件。VCRuntime140_1.dll是一个重要的动态链接库文件&#xff0c;它包含了Visual C运行时所需的一些函数和资源。当这个文件…

银行客户关系管理系统springboot财务金融进销存java jsp源代码

本项目为前几天收费帮学妹做的一个项目&#xff0c;Java EE JSP项目&#xff0c;在工作环境中基本使用不到&#xff0c;但是很多学校把这个当作编程入门的项目来做&#xff0c;故分享出本项目供初学者参考。 一、项目描述 银行客户关系管理系统springboot 系统有1权限&#x…

周易卦爻解读笔记——未济

第六十四卦未济 火水未济 离上坎下 未济卦由否卦所变&#xff0c;否卦六二与九五换位&#xff0c;象征尚未完成。 天地否 未济卦和既济卦既是错卦又是覆卦&#xff0c;这也是最后一卦&#xff0c;序卦传【物不可穷也&#xff0c;故受之以未济终焉】 未济卦象征尚未完成&…

NSSCTF之Misc篇刷题记录(14)

[SWPUCTF] 2021新生赛之Crypto篇刷题记录① [UUCTF 2022 新生赛]王八快跑[安洵杯 2020]BeCare4[HDCTF 2023]ExtremeMisc NSSCTF平台&#xff1a;https://www.nssctf.cn/ PS&#xff1a;记得所有的flag都改为NSSCTF [UUCTF 2022 新生赛]王八快跑 小游戏 小乌龟跑过线就有 fla…

BDA初级分析——SQL语句应用基础练习题

1、请检查OLYMPIC表中是否存在重复国家? SELECT Team,COUNT(*) AS 重复次数 FROM Olympic GROUP BY Team HAVING COUNT(*) > 1;SELECT COUNT(Team),COUNT(DISTINCT(Team)) FROM Olympic; 2、将OLYMPIC表中Armenia(ARM)的奖牌总数更新为14 UPDATE Olympic SET total_medals …

【C语言】使用C语言,实现九九乘法表(另附Python、Java、JavaScript实现方式)

文章目录 1. C语言实现1.1 思路1.2 代码实现 3.其他语言实现3.1 Python实现3.2 Java实现3.3 JavaScript实现 1. C语言实现 1.1 思路 九九乘法表图示&#xff1a; 思路如下&#xff1a;定义两层for循环即可实现九九乘法表 一共有9层&#xff0c;所以要定义一个变量i&#xff…

记录首次面试2023-08-18

人生第一次面试&#xff0c;大概一个小时左右。没有问我C的&#xff0c;上来一个数据库事务&#xff0c;虽然没有复习&#xff0c;但是还是能够记住一些&#xff0c;主要问的一些事务的隔离级别&#xff0c;以及都有什么作用&#xff0c;我是举例回答的&#xff0c;客户端A和客…

【激光雕刻与DIY Arduino SCARA机器人】

【激光雕刻与DIY Arduino SCARA机器人】 1. 项目概况2. 设计和3D模型3. 安装激光模块4. SCARA机器人激光雕刻机电路图5. 完成装配6. 马林固件,用于使用 SCARA 机器人进行激光雕刻7. 配置 Marlin 固件8. 控制软件 – 主机9. 使用 SCARA 机器人进行激光雕刻10. 生成用于激光雕刻…

PCAP01介绍和STM32模拟SPI驱动

一.芯片介绍 Pcap01是德国acam公司设计的一款革命性的电容测量芯片。该芯片 内部有DSP计算单元&#xff0c;可以直接将电容元件接到Pcap01芯片&#xff0c;然后芯片计算出容值大小&#xff0c;通过SPI总线将电容容值数据传送给CPU&#xff0c;电容测量完全数字化。 二,测量原…

不要着急购买iPhone 15,先看看这5点再做决定吧!

人们对下个月可能推出的iPhone 15感到兴奋,这是有充分理由的——有传言称,新机型正在做出一些重大改变,尤其是在iPhone 15 Pro机型方面。从四款新iPhone都采用USB-C,到iPhone 15 Pro Max采用潜望镜式长焦镜头以实现更好的变焦,听起来有很多功能值得兴奋。 当然,除非你没…

软件综合测试实训室建设方案

一、实训室总体目标 培养目标:培养软件测试的专业技术人才,使学生掌握软件测试的基本理论知识,熟练运用各类测试工具,具备随产品版本迭代进行回归测试的能力。 建设目标:打造一流的软件测试培训基地,建成集教学实训、技术研发、项目实习为一体的软件测试人才培养高地。 二、…

文件上传xxx

本地保存文件 将文件保存到服务器本地硬盘中 max-request-size 多个文件总大小不能大于100M PostMapping("/upload")public Result upload(String username,Integer age,MultipartFile image) throws IOException {log.info("用户名:{},牛叔&#xff1a;{},文件…