当前位置: 首页 > news >正文

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

代码结构

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

  一、include文件夹 

1.1 common.h

#ifndef _COMMON_H
#define _COMMON_Htypedef 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_Htypedef 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 //greenstruct 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];elsereturn 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 4096int 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 为空,则执行默认绘制函数DefaultOnDrawptButton->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 8888static 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;}elsereturn -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 0int 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 0int 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 5static 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 colordwColor = 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;//greenelse if (strcmp(status, "err") == 0)dwColor = BUTTON_DEFAULT_COLOR;//redelse if (status[0] >= '0' && status[0] <= '9')//blue{			dwColor = BUTTON_PERCENT_COLOR;strButton = status;			}elsereturn -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)nmSTRIP = $(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 LDFLAGSTOPDIR := $(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)
endifPHONY += $(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 8888int 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 0iRet = connect(iSocketClient, (const struct sockaddr *)&tSocketServerAddr, sizeof(struct sockaddr));	if (-1 == iRet){printf("connect error!\n");return -1;}
#endifiAddrLen = 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"

 

相关文章:

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

代码结构 所有代码都已通过测试跑通&#xff0c;其中代码结构如下&#xff1a; 一、include文件夹 1.1 common.h #ifndef _COMMON_H #define _COMMON_Htypedef struct Region {int iLeftUpX; //区域左上方的坐标int iLeftUpY; //区域左下方的坐标int iWidth; //区域宽…...

React(6)

1.React插槽 import React, { Component } from react import Child from ./compoent/Childexport default class App extends Component {render() {return (<div><Child><div>App下的div</div></Child></div>)} }import React, { Compon…...

RabbitMq-2安装与配置

Rabbitmq的安装 1.上传资源 注意&#xff1a;rabbitmq的版本必须与erlang编译器的版本适配 2.安装依赖环境 //打开虚拟机 yum install build-essential openssl openssl-devel unixODBC unixODBC-devel make gcc gcc-c kernel-devel m4 ncurses-devel tk tc xz3.安装erlan…...

论文笔记:Continuous Trajectory Generation Based on Two-Stage GAN

2023 AAAI 1 intro 1.1 背景 建模人类个体移动模式并生成接近真实的轨迹在许多应用中至关重要 1&#xff09;生成轨迹方法能够为城市规划、流行病传播分析和交通管控等城市假设分析场景提供仿仿真数据支撑2&#xff09;生成轨迹方法也是目前促进轨迹数据开源共享与解决轨迹数…...

redis实战-缓存数据解决缓存与数据库数据一致性

缓存的定义 缓存(Cache),就是数据交换的缓冲区,俗称的缓存就是缓冲区内的数据,一般从数据库中获取,存储于本地代码。防止过高的数据访问猛冲系统,导致其操作线程无法及时处理信息而瘫痪&#xff0c;这在实际开发中对企业讲,对产品口碑,用户评价都是致命的;所以企业非常重视缓存…...

【排序】选择排序

文章目录 选择排序时间复杂度空间复杂度稳定性 代码 选择排序 以从小到大为例进行说明。 选择排序就是定义出一个最小值下标&#xff0c;然后遍历整个剩下的数组选择出最小的放进最小值下标的位置。 时间复杂度 O(N) 遍历一次即可 空间复杂度 O(1) 稳定性 不稳定 代码 p…...

深入浅出Pytorch函数——torch.nn.init.trunc_normal_

分类目录&#xff1a;《深入浅出Pytorch函数》总目录 相关文章&#xff1a; 深入浅出Pytorch函数——torch.nn.init.calculate_gain 深入浅出Pytorch函数——torch.nn.init.uniform_ 深入浅出Pytorch函数——torch.nn.init.normal_ 深入浅出Pytorch函数——torch.nn.init.c…...

探索高级UI、源码解析与性能优化,了解开源框架及Flutter,助力Java和Kotlin筑基,揭秘NDK的魅力!

课程链接&#xff1a; 链接: https://pan.baidu.com/s/13cR0Ip6lzgFoz0rcmgYGZA?pwdy7hp 提取码: y7hp 复制这段内容后打开百度网盘手机App&#xff0c;操作更方便哦 --来自百度网盘超级会员v4的分享 课程介绍&#xff1a; &#x1f4da;【01】Java筑基&#xff1a;全方位指…...

国外服务器怎么有效降低延迟

国外服务器怎么有效降低延迟?在全球化网络环境下&#xff0c;越来越多的企业和个人选择使用国外服务器来托管网站、应用程序或数据。然而&#xff0c;由于地理位置、网络连接等因素&#xff0c;使用国外服务器时可能会遇到延迟较高的问题。高延迟不仅影响用户体验&#xff0c;…...

AI百度文心一言大语言模型接入使用(中国版ChatGPT)

百度文心一言接入使用&#xff08;中国版ChatGPT&#xff09; 一、百度文心一言API二、使用步骤1、接口2、请求参数3、请求参数示例4、接口 返回示例 三、 如何获取appKey和uid1、申请appKey:2、获取appKey和uid 四、重要说明 一、百度文心一言API 基于百度文心一言语言大模型…...

vue 安装并配置vuex

1.安装vuex命令:npm i vuex3.6.2 2.全局配置 在main文件里边导入-安装-挂载 main.js页面配置的 import Vue from vue import App from ./App.vue import Vuex from vuex//导入 Vue.use(Vuex)//安装插件 // 创建store对象 const store new Vuex.Store({ }) // 挂载到vue对象上…...

有一种新型病毒在 3Ds Max 环境中传播,如何避免?

3ds Max渲染慢&#xff0c;可以使用渲云渲染农场&#xff1a; 渲云渲染农场解决本地渲染慢、电脑配置不足、紧急项目渲染等问题&#xff0c;可批量渲染&#xff0c;批量出结果&#xff0c;速度快&#xff0c;效率高。 此外3dmax支持的CG MAGIC插件专业版正式上线&#xff0c;…...

基于Java/springboot铁路物流数据平台的设计与实现

摘要 随着科学技术的飞速发展&#xff0c;社会的方方面面、各行各业都在努力与现代的先进技术接轨&#xff0c;通过科技手段来提高自身的优势&#xff0c;铁路物流数据平台当然也不能排除在外&#xff0c;从文档信息、铁路设计的统计和分析&#xff0c;在过程中会产生大量的、各…...

比较杂的html元素

abbr 表示缩写 time 踢动给浏览器或搜索引擎阅读的事件&#xff1b;看着没什么效果 b 以前是一个无语义元素&#xff0c;主要用于加粗字体&#xff0c;有了css之后&#xff0c;加粗就不需要b元素了。 现在作为提醒注意&#xff08;Bring Attention To&#xff09;元素&…...

Docker基本管理

前言一、Docker简介1.1 什么是docker1.2 docker的logo及其含义1.3 docker的设计宗旨1.4 容器的优点1.5 容器和虚拟机的区别1.6 docker容器的两个重要技术1.7 docker的核心概念 二、安装 Docker三、Docker 镜像操作1、搜索镜像2、获取镜像3、查看镜像信息4、查看下载的镜像文件信…...

.NET Core6.0使用NPOI导入导出Excel

一、使用NPOI导出Excel //引入NPOI包 HTML <input type"button" class"layui-btn layui-btn-blue2 layui-btn-sm" id"ExportExcel" onclick"ExportExcel()" value"导出" />JS //导出Excelfunction ExportExcel() {…...

用API接口获取数据的好处有哪些,电商小白看过来!

API接口获取数据有以下几个好处&#xff1a; 1. 数据的实时性&#xff1a;通过API接口获取数据可以实时获取最新的数据&#xff0c;保证数据的及时性。这对于需要及时更新数据的应用非常重要&#xff0c;比如股票行情、天气预报等。 2. 数据的准确性&#xff1a;通过API接口获…...

使用struct解析通达信本地Lday日线数据

★★★★★博文原创不易&#xff0c;我的博文不需要打赏&#xff0c;也不需要知识付费&#xff0c;可以白嫖学习编程小技巧&#xff0c;喜欢的老铁可以多多帮忙点赞&#xff0c;小红牛在此表示感谢。★★★★★ 在Python中&#xff0c;struct模块提供了二进制数据的打包和解包…...

浅谈早期基于模板匹配的OCR的原理

基于模板匹配的概念是一种早期的字符识别方法&#xff0c;它基于事先准备好的字符模板库来与待识别字符进行比较和匹配。其原理如下&#xff1a; 1. 字符模板库准备&#xff1a;首先&#xff0c;针对每个可能出现的字符&#xff0c;制作一个对应的字符模板。这些模板可以手工创…...

第6章 分布式文件存储

mini商城第6章 分布式文件存储 一、课题 分布式文件存储 二、回顾 1、理解Oauth2.0的功能作模式 2、实现mini商城项目的权限登录 三、目标 1、了解文件存储系统的概念 2、了解常用文件服务器的区别 3、掌握Minio的应用 四、内容 第1章 MinIO简介 官...

Spring(四):Spring Boot 的创建和使用

关于Spring之前说到&#xff0c;Spring只是思想&#xff08;核心是IOC、DI和AOP&#xff09;&#xff0c;而具体的如何实现呢&#xff1f;那就是由Spring Boot 来实现&#xff0c;Spring Boot究竟是个啥呢&#xff1f; 什么是Spring Boot&#xff0c;为什么要学Spring Boot Sp…...

SpringCloud Gateway:status: 503 error: Service Unavailable

使用SpringCloud Gateway路由请求时&#xff0c;出现如下错误 yml配置如下&#xff1a; 可能的一种原因是&#xff1a;yml配置了gateway.discovery.locator.enabledtrue&#xff0c;此时gateway会使用负载均衡模式路由请求&#xff0c;但是SpringCloud Alibaba删除了Ribbon的…...

【产品规划】功能需求说明书概述

文章目录 1、瀑布流方法论简介2、产品需求文档&#xff08;PRD&#xff09;简介3、产品需求文档的基本要素4、编写产品需求文档5、优秀产品需求文档的特点6、与产品需求文档相似的其他文档 1、瀑布流方法论简介 2、产品需求文档&#xff08;PRD&#xff09;简介 3、产品需求文档…...

shell连接ubuntu

当使用aws的私钥连接时,老是弹出输入私钥密码,但是根本没有设置过密码,随便输入后,又提示该私钥无密码... 很早就使用过aws的ubuntu,这个问题也很早就遇到过,但是每次遇到都要各种找找找...索性这次记下来算了 此处用FinalShell连接为例 首先现在Putty连接工具: 点击官方下载 …...

华为将收取蜂窝物联网专利费,或将影响LPWAN市场发展

近日&#xff0c;华为正式公布了其4G和5G手机、Wi-Fi6设备和物联网产品的专利许可费率&#xff0c;其中包含了长距离通信技术蜂窝物联网。作为蜂窝物联网技术的先驱&#xff0c;华为是LTE Category NB (NB-IoT)、LTE Category M和其他4G物联网标准的主要贡献者。 在NB-IoT领域…...

【3Ds Max】图形合并命令的简单使用

示例&#xff08;将文字设置在球体上&#xff09; 1. 首先这里创建一个球体和一个文本 2. 选中球体&#xff0c;在复合对象中点击图形合并按钮 点击“拾取图形”按钮&#xff0c;然后选中文本&#xff0c;此时可以看到球体上已经投射出文本 3. 接下来是一些常用参数的介绍 当…...

Flink的常用算子以及实例

1.map 特性&#xff1a;接收一个数据&#xff0c;经过处理之后&#xff0c;就返回一个数据 1.1. 源码分析 我们来看看map的源码 map需要接收一个MapFunction<T,R>的对象&#xff0c;其中泛型T表示传入的数据类型&#xff0c;R表示经过处理之后输出的数据类型我们继续往…...

网络安全---负载均衡案例

一、首先环境配置 1.上传文件并解压 2.进入目录下 为了方便解释&#xff0c;我们只用两个节点&#xff0c;启动之后&#xff0c;大家可以看到有 3 个容器&#xff08;可想像成有 3 台服务器就成&#xff09;。 二、使用蚁剑去连接 因为两台节点都在相同的位置存在 ant.jsp&…...

解决nginx的负载均衡下上传webshell的问题

目录 环境 问题 访问的ip会变动 执行命令的服务器未知 上传大文件损坏 深入内网 解决方案 环境 ps :现在已经拿下服务器了&#xff0c;要解决的是负载均衡问题, 以下是docker环境&#xff1a; 链接: https://pan.baidu.com/s/1cjMfyFbb50NuUtk6JNfXNQ?pwd1aqw 提…...

vue 关闭prettier警告warn

这个就是我们创建vue cli的时候 把这个给默认上了 关闭这个只需在.eslintrc.js页面里边添加一行代码"prettier/prettier": "off"...

听GPT 讲Prometheus源代码--rules

Prometheus的rules目录主要包含规则引擎和管理规则的文件: engine.go 该文件定义了规则引擎的接口和主要结构,包括Rule,Record,RuleGroup等。它提供了规则的加载、匹配、评估和结果记录的功能。 api.go 定义了用于管理和查询规则的RESTful API,包括获取、添加、删除规则等方法。…...

TIA博途_通过EXCEL快速给PLC程序段添加注释信息的方法示例

通过EXCEL快速给PLC程序段添加注释信息的方法示例 如下图所示,以OB1为例,正常情况下,我们可以在博途中直接输入各个程序段的注释信息, 但是如果程序段较多的话,逐个输入的话效率不高,此时可以参考下面这种通过EXCEL进行快速添加的方法。 如下图所示,选中某个OB或FC、FB块…...

【力扣】496. 下一个更大元素 I <单调栈、模拟>

【力扣】496. 下一个更大元素 I nums1 中数字 x 的 下一个更大元素 是指 x 在 nums2 中对应位置 右侧 的 第一个 比 x 大的元素。给你两个没有重复元素的数组 nums1 和 nums2 &#xff0c;下标从 0 开始计数&#xff0c;其中nums1 是 nums2 的子集。   对于每个 0 < i <…...

Java调用https接口添加证书

使用InstallCert.Java生成证书 /** Copyright 2006 Sun Microsystems, Inc. All Rights Reserved.** Redistribution and use in source and binary forms, with or without* modification, are permitted provided that the following conditions* are met:** - Redistri…...

C++入门:函数缺省参数与函数重载

目录 1.函数缺省参数 1.1 缺省参数概念 1.2 缺省参数分类 2.函数重载 2.1 函数重载概念 2.2 C支持函数重载的原理 1.函数缺省参数 1.1 缺省参数概念 缺省参数是声明或定义函数时为函数的参数指定一个缺省值。在调用该函数时&#xff0c;如果没有指定实 参则采用该形参的…...

Android 场景Scene的使用

Scene 翻译过来是场景&#xff0c;开发者提供起始布局和结束布局&#xff0c;就可以实现布局之间的过渡动画。 具体可参考 使用过渡为布局变化添加动画效果 大白话&#xff0c;在 Activity 的各个页面之间切换&#xff0c;会带有过渡动画。 打个比方&#xff0c;使用起来类似…...

Python tkinter Notebook标签添加关闭按钮元素,及左侧添加存储状态提示图标案例,类似Notepad++页面

效果图展示 粉色框是当前页面&#xff0c;橙色框是鼠标经过&#xff0c;红色框是按下按钮&#xff0c;灰色按钮是其他页面的效果&#xff1b; 存储标识可以用来识别页面是否存储&#xff1a;例如当前页面已经保存用蓝色&#xff0c;未保存用红色&#xff0c;其他页面已经保存用…...

基于web网上订餐系统的设计与实现(论文+源码)_kaic

目录 1绪论 1.1课题研究背景 1.2研究现状 1.3主要内容 1.4本文结构 2网上订餐系统需求分析 2.1系统业务流程分析 2.2消费者用户业务流程分析 2.3商户业务流程分析 2.4管理员用户流程分析消费者用户用例分析 2.5系统用例分析 3网上订餐系统设计 3.1功能概述 3.2订单管理模块概要…...

C#生产流程控制(串行,并行混合执行)

开源框架CsGo https://gitee.com/hamasm/CsGo?_fromgitee_search 文档资料&#xff1a; https://blog.csdn.net/aa2528877987/article/details/132139337 实现效果 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37…...

【广州华锐视点】VR线上教学资源平台提供定制化虚拟现实学习内容

虚拟现实&#xff08;VR&#xff09;技术的出现为我们提供了一种全新的在线教学方式。由广州华锐视点开发的VR线上教学资源平台&#xff0c;作为一个综合性的学习工具&#xff0c;正在教育领域迅速发展&#xff0c;并被越来越多的教育机构和学生所接受。那么&#xff0c;VR线上…...

计算机视觉的应用11-基于pytorch框架的卷积神经网络与注意力机制对街道房屋号码的识别应用

大家好&#xff0c;我是微学AI&#xff0c;今天给大家介绍一下计算机视觉的应用11-基于pytorch框架的卷积神经网络与注意力机制对街道房屋号码的识别应用&#xff0c;本文我们借助PyTorch&#xff0c;快速构建和训练卷积神经网络&#xff08;CNN&#xff09;等模型&#xff0c;…...

正则表达式:学习使用正则表达式提取网页中的目标数据

使用正则表达式提取网页中的目标数据主要有以下几个步骤&#xff1a; 获取网页内容&#xff1a;首先&#xff0c;你需要使用Python的库&#xff08;如requests&#xff09;获取网页的HTML内容。 构建正则表达式&#xff1a;根据你想要提取的目标数据的特征&#xff0c;构建相应…...

最长重复子数组(力扣)动态规划 JAVA

给两个整数数组 nums1 和 nums2 &#xff0c;返回 两个数组中 公共的 、长度最长的子数组的长度 。 示例 1&#xff1a; 输入&#xff1a;nums1 [1,2,3,2,1], nums2 [3,2,1,4,7] 输出&#xff1a;3 解释&#xff1a;长度最长的公共子数组是 [3,2,1] 。 示例 2&#xff1a; 输…...

JavaWeb_LeadNews_Day6-Kafka

JavaWeb_LeadNews_Day6-Kafka Kafka概述安装配置kafka入门kafka高可用方案kafka详解生产者同步异步发送消息生产者参数配置消费者同步异步提交偏移量 SpringBoot集成kafka 自媒体文章上下架实现思路具体实现 来源Gitee Kafka 概述 对比 选择 介绍 producer: 发布消息的对象称…...

ATTCK覆盖度97.1%!360终端安全管理系统获赛可达认证

近日&#xff0c;国际知名第三方网络安全检测服务机构——赛可达实验室&#xff08;SKD Labs&#xff09;发布最新测试报告&#xff0c;360终端安全管理系统以ATT&CK V12框架攻击技术覆盖面377个、覆盖度97.1%&#xff0c;勒索病毒、挖矿病毒检出率100%&#xff0c;误报率0…...

透视俄乌网络战之一:数据擦除软件

数据擦除破坏 1. WhisperGate2. HermeticWiper3. IsaacWiper4. WhisperKill5. CaddyWiper6. DoubleZero7. AcidRain8. RURansom 数据是政府、社会和企业组织运行的关键要素。数据擦除软件可以在不留任何痕迹的情况下擦除数据并阻止操作系统恢复摧&#xff0c;达到摧毁或目标系统…...

微服务中间件--Nacos

Nacos 1. Nacos入门a.服务注册到Nacosb.Nacos服务分级存储模型c.NacosRule负载均衡d.服务实例的权重设置e.环境隔离 - namespacef.Nacos和Eureka的对比 2. Nacos配置管理a.统一配置管理b.配置热更新c.多环境配置共享 1. Nacos入门 Nacos是阿里巴巴的产品&#xff0c;现在是Spr…...

驱动开发点亮led灯

头文件 #ifndef __HEAD_H__ #define __HEAD_H__#define PHY_LED_MODER 0X50006000 #define PHY_LED_ODR 0X50006014 #define PHY_LED_RCC 0X50000A28 #define PHY_LED_FMODER 0X50007000 #define PHY_LED_FODR 0X50007014#endif驱动代码 #include <linux/init.h> #incl…...

回归预测 | MATLAB实现IPSO-SVM改进粒子群优化算法优化支持向量机多输入单输出回归预测(多指标,多图)

回归预测 | MATLAB实现IPSO-SVM改进粒子群优化算法优化支持向量机多输入单输出回归预测&#xff08;多指标&#xff0c;多图&#xff09; 目录 回归预测 | MATLAB实现IPSO-SVM改进粒子群优化算法优化支持向量机多输入单输出回归预测&#xff08;多指标&#xff0c;多图&#xf…...

数学建模之“TOPSIS数学模型”原理和代码详解

一、简介 TOPSIS&#xff08;Technique for Order Preference by Similarity to Ideal Solution&#xff09;是一种多准则决策分析方法&#xff0c;用于解决多个候选方案之间的排序和选择问题。它基于一种数学模型&#xff0c;通过比较每个候选方案与理想解和负理想解之间的相…...