Linux基础项目开发1:量产工具——改进优化(八)

前言:

前面我们已经构造出来显示系统、输入系统、文字系统、UI系统、页面系统,业务系统,这个小项目该完成的功能我们已经都完成了,但是还是有很多地方可以优化改进的,现在让我们对这个系统不足的地方进行相应的和改进与优化吧。

目录

一、改进:按钮文字

 1.freetype.c

2.font_manager.h

3.font_manager.c

4.common.h

5.main_page.c

6.disp_manager.c 

7.上板效果:

二、改进:接口函数名优化 

main.c 

 三、改进:支持配置文件中的command

1.main_page.c:

2.执行命令后所执行的脚本 

 3.ubuntu上:

4.开发板上: 


 

一、改进:按钮文字

按钮文字大小不一,没有严格居中,太小看不清

根据配置文件的各项确定最长的名字,确定字符大小:每个按钮中文字大小都一样

修改disp_manager.c中的DrawTextInRegionCentral

 1.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>
#include FT_FREETYPE_H
#include FT_GLYPH_H


static FT_Face g_tFace;
static int g_iDefaultFontSize = 12;


static int FreetypeGetStringRegionCar(char *str, PRegionCartesian ptRegionCar)
{
    int i;
    int error;
    FT_BBox bbox;
    FT_BBox glyph_bbox;
    FT_Vector pen;
    FT_Glyph  glyph;
    FT_GlyphSlot slot = g_tFace->glyph;

    /* 初始化 */
    bbox.xMin = bbox.yMin = 32000;
    bbox.xMax = bbox.yMax = -32000;

    /* 指定原点为(0, 0) */
    pen.x = 0;
    pen.y = 0;

    /* 计算每个字符的bounding box */
    /* 先translate, 再load char, 就可以得到它的外框了 */
    for (i = 0; i < strlen(str); i++)
    {
        /* 转换:transformation */
        FT_Set_Transform(g_tFace, 0, &pen);

        /* 加载位图: load glyph image into the slot (erase previous one) */
        error = FT_Load_Char(g_tFace, str[i], FT_LOAD_RENDER);
        if (error)
        {
            printf("FT_Load_Char error\n");
            return -1;
        }

        /* 取出glyph */
        error = FT_Get_Glyph(g_tFace->glyph, &glyph);
        if (error)
        {
            printf("FT_Get_Glyph error!\n");
            return -1;
        }
        
        /* 从glyph得到外框: bbox */
        FT_Glyph_Get_CBox(glyph, FT_GLYPH_BBOX_TRUNCATE, &glyph_bbox);

        /* 更新外框 */
        if ( glyph_bbox.xMin < bbox.xMin )
            bbox.xMin = glyph_bbox.xMin;

        if ( glyph_bbox.yMin < bbox.yMin )
            bbox.yMin = glyph_bbox.yMin;

        if ( glyph_bbox.xMax > bbox.xMax )
            bbox.xMax = glyph_bbox.xMax;

        if ( glyph_bbox.yMax > bbox.yMax )
            bbox.yMax = glyph_bbox.yMax;
        
        /* 计算下一个字符的原点: increment pen position */
        pen.x += slot->advance.x;
        pen.y += slot->advance.y;
    }

    /* return string bbox */
    //*abbox = bbox;
    ptRegionCar->iLeftUpX = bbox.xMin;
    ptRegionCar->iLeftUpY = bbox.yMax;
    ptRegionCar->iWidth     = bbox.xMax - bbox.xMin + 1;
    ptRegionCar->iHeigh     = bbox.yMax - bbox.yMin + 1;

	return 0;	
}


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);

	/* 加载位图: 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,
	.GetStringRegionCar = FreetypeGetStringRegionCar,
};

void FreetypeRegister(void)
{
	RegisterFont(&g_tFreetypeOpr);
}

static int FreetypeGetStringRegionCar(char *str, PRegionCartesian ptRegionCar)

第23行:将外框保存在笛卡坐标系里面 

2.font_manager.h

#ifndef _FONT_MANAGER_H
#define _FONT_MANAGER_H

#include <common.h>

typedef struct FontBitMap {
	Region tRegion;
	int iCurOriginX;
	int iCurOriginY;
	int iNextOriginX;
	int iNextOriginY;
	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);
	int (*GetStringRegionCar)(char *str, PRegionCartesian ptRegionCar);
	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);
int GetStringRegionCar(char *str, PRegionCartesian ptRegionCar);


#endif

第20行:添加 GetStringRegionCar 函数指针

第31行:在头文件里将这个函数声明出来

3.font_manager.c

调用你所选择的字库操作函数里面对应的函数


int GetStringRegionCar(char *str, PRegionCartesian ptRegionCar)
{
	return g_ptDefaulFontOpr->GetStringRegionCar(str, ptRegionCar);
}

4.common.h

构建笛卡坐标系计算外框



#ifndef _COMMON_H
#define _COMMON_H

#ifndef NULL
#define NULL (void *)0
#endif

typedef struct Region {
	int iLeftUpX;
	int iLeftUpY;
	int iWidth;
	int iHeigh;
}Region, *PRegion;

typedef struct RegionCartesian {
	int iLeftUpX;
	int iLeftUpY;
	int iWidth;
	int iHeigh;
}RegionCartesian, *PRegionCartesian;


#endif

5.main_page.c

对边框进行计算得出文字大小


static int GetFontSizeForAllButton(void)
{
	int i;
	int max_len = -1;
	int max_index = 0;
	int len;
	RegionCartesian tRegionCar;
	float k, kx, ky;
	
	/* 1. 找出name最长的Button */
	for (i = 0; i < g_tButtonCnt; i++)
	{
		len = strlen(g_tButtons[i].name);
		if (len > max_len)
		{
			max_len = len;
			max_index = i;
		}
	}

	/* 2. 以font_size =100, 算出它的外框 */
	SetFontSize(100);
	GetStringRegionCar(g_tButtons[max_index].name, &tRegionCar);

	/* 3. 把文字的外框缩放为Button的外框 */
	kx = (float)g_tButtons[max_index].tRegion.iWidth / tRegionCar.iWidth;
	ky = (float)g_tButtons[max_index].tRegion.iHeigh / tRegionCar.iHeigh;
	
	if (kx < ky)
		k = kx;
	else
		k = ky;

	//printf("font size = %d\n", (int)(k*100));
	/* 4. 反算出font size, 只取0.80, 避免文字过于接近边界 */
	return k * 100 * 0.8;
}

6.disp_manager.c 

DrawTextInRegionCentral绘制函数中 

/* 计算字符串的外框 */
GetStringRegionCar(name, &tRegionCar);
/* 算出第一个字符的origin */
iOriginX = ptRegion->iLeftUpX + (ptRegion->iWidth - tRegionCar.iWidth)/2 - tRegionCar.iLeftUpX;
iOriginY = ptRegion->iLeftUpY + (ptRegion->iHeigh - tRegionCar.iHeigh)/2 + tRegionCar.iLeftUpY;

7.上板效果:

二、改进:接口函数名优化 

显示系统、输入系统中,有多个init函数,让人难以分辨。

如下图修改:

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 <disp_manager.h>
#include <font_manager.h>
#include <input_manager.h>
#include <page_manager.h>


int main(int argc, char **argv)
{
	int error;

	if (argc != 2)
	{
		printf("Usage: %s <font_file>\n", argv[0]);
		return -1;
	}
	
	/* 初始化显示系统 */		
	DisplaySystemRegister();  /* 以前是: DisplayInit(); */

	SelectDefaultDisplay("fb");

	InitDefaultDisplay();

	/* 初始化输入系统 */		
	InputSystemRegister(); /* 以前是: InputInit(); */
	IntpuDeviceInit();


	/* 初始化文字系统 */		
	FontSystemRegister(); /* 以前是: FontsRegister(); */
	
	error = SelectAndInitFont("freetype", argv[1]);
	if (error)
	{
		printf("SelectAndInitFont err\n");
		return -1;
	}

	/* 初始化页面系统 */		
	PageSystemRegister(); /* 以前是: PagesRegister(); */

	/* 运行业务系统的主页面 */
	Page("main")->Run(NULL);
	
	return 0;	
}

 三、改进:支持配置文件中的command

1.main_page.c:

在按钮的OnPressed函数中,用system函数运行command


#include <config.h>
#include <stdio.h>
#include <ui.h>
#include <page_manager.h>
#include <math.h>
#include <string.h>
#include <stdlib.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;
	char *command_status[3] = {"err", "ok", "percent"};
	int command_status_index = 0;
	char command[1000];
	PItemCfg ptItemCfg;

	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)
		{
			dwColor = BUTTON_PRESSED_COLOR;
			command_status_index = 1;
		}
	}
	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)
		{
			command_status_index = 1;
			dwColor = BUTTON_PRESSED_COLOR;
		}
		else if (strcmp(status, "err") == 0)
		{
			command_status_index = 0;
			dwColor = BUTTON_DEFAULT_COLOR;
		}
		else if (status[0] >= '0' && status[0] <= '9')
		{			
			command_status_index = 2;
			dwColor = BUTTON_PERCENT_COLOR;
			strButton = status;			
		}
		else
			return -1;
	}
	else
	{
		return -1;
	}

	/* 绘制底色 */
	DrawRegion(&ptButton->tRegion, dwColor);

	/* 居中写文字 */
	DrawTextInRegionCentral(strButton, &ptButton->tRegion, BUTTON_TEXT_COLOR);

	/* flush to lcd/web */
	FlushDisplayRegion(&ptButton->tRegion, ptDispBuff);

	/* 执行command */
	ptItemCfg = GetItemCfgByName(ptButton->name);
	if (ptItemCfg->command[0] != '\0')
	{
		sprintf(command, "%s %s", ptItemCfg->command, command_status[command_status_index]);
		system(command);
	}
	
	return 0;
}

static int GetFontSizeForAllButton(void)
{
	int i;
	int max_len = -1;
	int max_index = 0;
	int len;
	RegionCartesian tRegionCar;
	float k, kx, ky;
	
	/* 1. 找出name最长的Button */
	for (i = 0; i < g_tButtonCnt; i++)
	{
		len = strlen(g_tButtons[i].name);
		if (len > max_len)
		{
			max_len = len;
			max_index = i;
		}
	}

	/* 2. 以font_size =100, 算出它的外框 */
	SetFontSize(100);
	GetStringRegionCar(g_tButtons[max_index].name, &tRegionCar);

	/* 3. 把文字的外框缩放为Button的外框 */
	kx = (float)g_tButtons[max_index].tRegion.iWidth / tRegionCar.iWidth;
	ky = (float)g_tButtons[max_index].tRegion.iHeigh / tRegionCar.iHeigh;
	//printf("button width / str width   = %d/%d = %f\n", g_tButtons[max_index].tRegion.iWidth, tRegionCar.iWidth, kx);
	//printf("button height / str height = %d/%d = %f\n", g_tButtons[max_index].tRegion.iHeigh, tRegionCar.iHeigh, ky);
	if (kx < ky)
		k = kx;
	else
		k = ky;

	//printf("font size = %d\n", (int)(k*100));
	/* 4. 反算出font size, 只取0.80, 避免文字过于接近边界 */
	return k * 100 * 0.8;
}

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;
	int iFontSize;
	
	/* 算出单个按钮的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++;
		}
	}

	iFontSize = GetFontSizeForAllButton();
	//SetFontSize(iFontSize);

	/* OnDraw */
	for (i = 0; i < n; i++)
	{
		g_tButtons[i].iFontSize = iFontSize;
		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);
}


第22行:状态存储

第23行:默认状态为err,并且用command_status_index标记状态

第84~89行:执行command

        第84行:根据名字找到配置项

        第85行:查看是否查找到配置项

        第86行:打印出命令和命令的状态

        第87行:执行命令

2.执行命令后所执行的脚本 

led.sh

#!/bin/sh
status=$1
if [ "$status" = "ok" ]
then
echo "led has been tested, it is ok"
fi

if [ "$status" = "err" ]
then
echo "led has been tested, it is fail"
fi

test_sleep_key.sh

#!/bin/sh
status=$1
if [ "$status" = "processing" ]
then
wakeup_count=$(cat /sys/power/wakeup_count)
echo standby > /sys/power/state

wakeup_count_new=$(cat /sys/power/wakeup_count)
while [ $wakeup_count_new -eq $wakeup_count ]
do
	wakeup_count_new=$(cat /sys/power/wakeup_count)
done

count=0
while [ $count -le 1 ]
do
	detect_dev 127.0.0.1 "ALL ok" > /dev/null 2>&1	
	sleep 1
        let count++
done

fi

 3.ubuntu上:

book@100ask:~/31_improve_command$ dos2unix led.sh
dos2unix: converting file led.sh to Unix format...

4.开发板上: 

[root@100ask:/mnt/31_improve_command]# cp led.sh /bin/
[root@100ask:/mnt/31_improve_command]# chmod +x /bin/led.sh
[root@100ask:/mnt/31_improve_command]# led.sh ok
led has been tested, it is ok
[root@100ask:/mnt/31_improve_command]# led.sh err
led has been tested, it is fail
[root@100ask:/mnt/31_improve_command]#

当点击开发板上的LED时会运行led.sh这个脚本 

Guess you like

Origin blog.csdn.net/m0_63168877/article/details/134893615