韦东山-电子量产工具项目:业务系统
代码结构
所有代码都已通过测试跑通,其中代码结构如下:
一、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(®ion, ptBuffer);/*输入系统初始化*/InputInit();InputDeviceInit();/*文字系统初始化*/FontsRegister();/*注册字体*/error = SelectAndInitFont("freetype", argv[1]);//选择字库操作if (error){printf("SelectAndInitFont err\n");return -1;} /*页面系统初始化*/PagesRegister();/*运行业务系统的主页面*/Page("main")->Run(NULL);return 0;
}
2.3 Makefile
EXTRA_CFLAGS :=
CFLAGS_file.o :=
obj-y +=config.o
obj-y +=main.o
三、button文件夹
3.1 button.c(修改,在InitButton函数中添加if(ptRegion)判断)
#include<ui.h>
#include <string.h>
#include <disp_manager.h>
static int DefaultOnDraw(struct Button *ptButton, PDispBuff ptDispBuff){/* 绘制底色 DrawRegion追加在disp_manager.c中 */DrawRegion(&ptButton->tRegion, BUTTON_DEFAULT_COLOR); // 红色 0xff0000/* 居中写文字 DrawTextInRegionCentral追加在disp_manager.c中*/DrawTextInRegionCentral(ptButton->name, &ptButton->tRegion, BUTTON_TEXT_COLOR); //黑色 0x000000/* flush to lcd/web */FlushDisplayRegion(&ptButton->tRegion, ptDispBuff);return 0;}
static int DefaultOnPressed(struct Button *ptButton, PDispBuff ptDispBuff, PInputEvent ptInputEvent)
{unsigned int dwColor = BUTTON_DEFAULT_COLOR; ptButton->status = !ptButton->status;if (ptButton->status)dwColor = BUTTON_PRESSED_COLOR;/* 绘制底色 */DrawRegion(&ptButton->tRegion, dwColor);/* 居中写文字 */DrawTextInRegionCentral(ptButton->name, &ptButton->tRegion, BUTTON_TEXT_COLOR);/* flush to lcd/web */FlushDisplayRegion(&ptButton->tRegion, ptDispBuff);return 0;
}void InitButton(PButton ptButton, char *name, PRegion ptRegion, ONDRAW_FUNC OnDraw, ONPRESSED_FUNC OnPressed)
{ptButton->status = 0; //初始状态为 0 ,未按下ptButton->name = name;if(ptRegion)ptButton->tRegion = *ptRegion; // 按钮的区域ptButton->OnDraw = OnDraw ? OnDraw : DefaultOnDraw; //若 OnDraw 为空,则执行默认绘制函数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"
相关文章:

韦东山-电子量产工具项目:业务系统
代码结构 所有代码都已通过测试跑通,其中代码结构如下: 一、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.上传资源 注意: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)生成轨迹方法能够为城市规划、流行病传播分析和交通管控等城市假设分析场景提供仿仿真数据支撑2)生成轨迹方法也是目前促进轨迹数据开源共享与解决轨迹数…...

redis实战-缓存数据解决缓存与数据库数据一致性
缓存的定义 缓存(Cache),就是数据交换的缓冲区,俗称的缓存就是缓冲区内的数据,一般从数据库中获取,存储于本地代码。防止过高的数据访问猛冲系统,导致其操作线程无法及时处理信息而瘫痪,这在实际开发中对企业讲,对产品口碑,用户评价都是致命的;所以企业非常重视缓存…...
【排序】选择排序
文章目录 选择排序时间复杂度空间复杂度稳定性 代码 选择排序 以从小到大为例进行说明。 选择排序就是定义出一个最小值下标,然后遍历整个剩下的数组选择出最小的放进最小值下标的位置。 时间复杂度 O(N) 遍历一次即可 空间复杂度 O(1) 稳定性 不稳定 代码 p…...
深入浅出Pytorch函数——torch.nn.init.trunc_normal_
分类目录:《深入浅出Pytorch函数》总目录 相关文章: 深入浅出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的魅力!
课程链接: 链接: https://pan.baidu.com/s/13cR0Ip6lzgFoz0rcmgYGZA?pwdy7hp 提取码: y7hp 复制这段内容后打开百度网盘手机App,操作更方便哦 --来自百度网盘超级会员v4的分享 课程介绍: 📚【01】Java筑基:全方位指…...
国外服务器怎么有效降低延迟
国外服务器怎么有效降低延迟?在全球化网络环境下,越来越多的企业和个人选择使用国外服务器来托管网站、应用程序或数据。然而,由于地理位置、网络连接等因素,使用国外服务器时可能会遇到延迟较高的问题。高延迟不仅影响用户体验,…...

AI百度文心一言大语言模型接入使用(中国版ChatGPT)
百度文心一言接入使用(中国版ChatGPT) 一、百度文心一言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渲染慢,可以使用渲云渲染农场: 渲云渲染农场解决本地渲染慢、电脑配置不足、紧急项目渲染等问题,可批量渲染,批量出结果,速度快,效率高。 此外3dmax支持的CG MAGIC插件专业版正式上线,…...

基于Java/springboot铁路物流数据平台的设计与实现
摘要 随着科学技术的飞速发展,社会的方方面面、各行各业都在努力与现代的先进技术接轨,通过科技手段来提高自身的优势,铁路物流数据平台当然也不能排除在外,从文档信息、铁路设计的统计和分析,在过程中会产生大量的、各…...
比较杂的html元素
abbr 表示缩写 time 踢动给浏览器或搜索引擎阅读的事件;看着没什么效果 b 以前是一个无语义元素,主要用于加粗字体,有了css之后,加粗就不需要b元素了。 现在作为提醒注意(Bring Attention To)元素&…...

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接口获取数据有以下几个好处: 1. 数据的实时性:通过API接口获取数据可以实时获取最新的数据,保证数据的及时性。这对于需要及时更新数据的应用非常重要,比如股票行情、天气预报等。 2. 数据的准确性:通过API接口获…...

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

浅谈早期基于模板匹配的OCR的原理
基于模板匹配的概念是一种早期的字符识别方法,它基于事先准备好的字符模板库来与待识别字符进行比较和匹配。其原理如下: 1. 字符模板库准备:首先,针对每个可能出现的字符,制作一个对应的字符模板。这些模板可以手工创…...
第6章 分布式文件存储
mini商城第6章 分布式文件存储 一、课题 分布式文件存储 二、回顾 1、理解Oauth2.0的功能作模式 2、实现mini商城项目的权限登录 三、目标 1、了解文件存储系统的概念 2、了解常用文件服务器的区别 3、掌握Minio的应用 四、内容 第1章 MinIO简介 官...

css实现圆环展示百分比,根据值动态展示所占比例
代码如下 <view class""><view class"circle-chart"><view v-if"!!num" class"pie-item" :style"{background: conic-gradient(var(--one-color) 0%,#E9E6F1 ${num}%),}"></view><view v-else …...

Zustand 状态管理库:极简而强大的解决方案
Zustand 是一个轻量级、快速和可扩展的状态管理库,特别适合 React 应用。它以简洁的 API 和高效的性能解决了 Redux 等状态管理方案中的繁琐问题。 核心优势对比 基本使用指南 1. 创建 Store // store.js import create from zustandconst useStore create((set)…...

AI Agent与Agentic AI:原理、应用、挑战与未来展望
文章目录 一、引言二、AI Agent与Agentic AI的兴起2.1 技术契机与生态成熟2.2 Agent的定义与特征2.3 Agent的发展历程 三、AI Agent的核心技术栈解密3.1 感知模块代码示例:使用Python和OpenCV进行图像识别 3.2 认知与决策模块代码示例:使用OpenAI GPT-3进…...

无法与IP建立连接,未能下载VSCode服务器
如题,在远程连接服务器的时候突然遇到了这个提示。 查阅了一圈,发现是VSCode版本自动更新惹的祸!!! 在VSCode的帮助->关于这里发现前几天VSCode自动更新了,我的版本号变成了1.100.3 才导致了远程连接出…...

【网络安全产品大调研系列】2. 体验漏洞扫描
前言 2023 年漏洞扫描服务市场规模预计为 3.06(十亿美元)。漏洞扫描服务市场行业预计将从 2024 年的 3.48(十亿美元)增长到 2032 年的 9.54(十亿美元)。预测期内漏洞扫描服务市场 CAGR(增长率&…...
【Web 进阶篇】优雅的接口设计:统一响应、全局异常处理与参数校验
系列回顾: 在上一篇中,我们成功地为应用集成了数据库,并使用 Spring Data JPA 实现了基本的 CRUD API。我们的应用现在能“记忆”数据了!但是,如果你仔细审视那些 API,会发现它们还很“粗糙”:有…...

ardupilot 开发环境eclipse 中import 缺少C++
目录 文章目录 目录摘要1.修复过程摘要 本节主要解决ardupilot 开发环境eclipse 中import 缺少C++,无法导入ardupilot代码,会引起查看不方便的问题。如下图所示 1.修复过程 0.安装ubuntu 软件中自带的eclipse 1.打开eclipse—Help—install new software 2.在 Work with中…...

【JavaWeb】Docker项目部署
引言 之前学习了Linux操作系统的常见命令,在Linux上安装软件,以及如何在Linux上部署一个单体项目,大多数同学都会有相同的感受,那就是麻烦。 核心体现在三点: 命令太多了,记不住 软件安装包名字复杂&…...
.Net Framework 4/C# 关键字(非常用,持续更新...)
一、is 关键字 is 关键字用于检查对象是否于给定类型兼容,如果兼容将返回 true,如果不兼容则返回 false,在进行类型转换前,可以先使用 is 关键字判断对象是否与指定类型兼容,如果兼容才进行转换,这样的转换是安全的。 例如有:首先创建一个字符串对象,然后将字符串对象隐…...

Maven 概述、安装、配置、仓库、私服详解
目录 1、Maven 概述 1.1 Maven 的定义 1.2 Maven 解决的问题 1.3 Maven 的核心特性与优势 2、Maven 安装 2.1 下载 Maven 2.2 安装配置 Maven 2.3 测试安装 2.4 修改 Maven 本地仓库的默认路径 3、Maven 配置 3.1 配置本地仓库 3.2 配置 JDK 3.3 IDEA 配置本地 Ma…...