📄 基于 linux 和 minigui 的嵌入式系统软件开发指南(六).htm
字号:
<P>前一类用来将某个 16位、32 位或者 64 位整数从某个特定的字节序转换为系统私有(native)字节序。举例如下:
<TABLE cellSpacing=0 cellPadding=5 width="100%" bgColor=#cccccc
border=1><TBODY>
<TR>
<TD><PRE><CODE>
int fd, len_header;
...
if (read (fd, &len_header, sizeof (int)) == -1)
goto error;
#if MGUI_BYTEORDER == MGUI_BIG_ENDIAN
len_header = ArchSwap32 (len_header); // 如果是 Big Endian 系统,则转换字节序
#endif
...
</CODE></PRE></TD></TR></TBODY></TABLE></P>
<P>在上面的程序段中,首先通过 read 系统调用从指定的文件描述符中读取一个整数值到 len_header 变量中。该文件中保存的整数值是
Little Endian 的,因此如果在 Big Endian 系统上使用这个整数值,就必须进行字节顺序交换。这里可以使用
ArchSwapLE32,将 Little Endian 的 32 位整数值转换为系统私有的字节序。也可以如上述程序段那样,只对 Big
Endian 系统进行字节序转换,这时,只要利用 ArchSwap32 函数即可。</P>
<P>MiniGUI 提供的用来转换字节序的函数(或者宏)如下:
<UL class=n01>
<LI>ArchSwapLE16(X) 将指定的以 Little Endian 字节序存放的 16 位整数值转换为系统私有整数值。如果系统本身是
Little Endian 系统,则该函数不作任何工作,直接返回 X;如果系统本身是 Big Endian 系统,则调用 ArchSwap16
函数交换字节序。
<LI>ArchSwapLE32(X) 将指定的以 Little Endian 字节序存放的 32 位整数值转换为系统私有整数值。如果系统本身是
Little Endian 系统,则该函数不作任何工作,直接返回 X;如果系统本身是 Big Endian 系统,则调用 ArchSwap32
函数交换字节序。
<LI>ArchSwapBE16(X) 将指定的以 Big Endian 字节序存放的 16 位整数值转换为系统私有整数值。如果系统本身是
Big Endian 系统,则该函数不作任何工作,直接返回 X;如果系统本身是 Little Endian 系统,则调用 ArchSwap16
函数交换字节序。
<LI>ArchSwapBE32(X) 将指定的以 Big Endian 字节序存放的 32 位整数值转换为系统私有整数值。如果系统本身是
Big Endian 系统,则该函数不作任何工作,直接返回 X;如果系统本身是 Little Endian 系统,则调用 ArchSwap32
函数交换字节序。 </LI></UL>
<P></P>
<P>MiniGUI 提供的第二类函数用来从标准 I/O 的文件对象中读写 Endian 整数值。如果要读取的文件是以 Little Endian
字节序存放的,则可以使用 MGUI_ReadLE16 和MGUI_ReadLE32
等函数读取整数值,这些函数将把读入的整数值转换为系统私有字节序,反之使用MGUI_ReadBE16 和MGUI_ReadBE32
函数。如果要写入的文件是以 Little Endian 字节序存放的,则可以使用 MGUI_WriteLE16 和MGUI_WriteLE32
等函数读取整数值,这些函数将把要写入的整数值从系统私有字节序转换为 Little Endian
字节序,然后写入文件,反之使用MGUI_WriteBE16 和MGUI_WriteBE32 函数。下面的代码段说明了上述函数的用法:
<TABLE cellSpacing=0 cellPadding=5 width="100%" bgColor=#cccccc
border=1><TBODY>
<TR>
<TD><PRE><CODE>
FILE* out;
int ount;
...
MGUI_WriteLE32 (out, count); // 以 Little Endian 字节序保存 count 到文件中。
...
</CODE></PRE></TD></TR></TBODY></TABLE></P>
<P><SPAN class=atitle3>4.2
利用条件编译编写可移植代码</SPAN><BR>在涉及到可移植性问题的时候,有时我们能够方便地通过 4.1
中描述的方法进行函数封装,从而提供具有良好移植性的代码,但有时我们无法通过函数封装的方法提供可移植性代码。这时,恐怕只能使用条件编译了。下面的代码说明了如何使用条件编译的方法确保程序正常工作(该代码来自
MiniGUI src/kernel/sharedres.c):
<TABLE cellSpacing=0 cellPadding=5 width="100%" bgColor=#cccccc
border=1><TBODY>
<TR>
<TD><PRE><CODE>
/* 如果系统不支持共享内存,则定义 _USE_MMAP
#undef _USE_MMAP
/* #define _USE_MMAP 1 */
void *LoadSharedResource (void)
{
#ifndef _USE_MMAP
key_t shm_key;
void *memptr;
int shmid;
#endif
/* 装载共享资源 */
...
#ifndef _USE_MMAP /* 获取共享内存对象 */
if ((shm_key = get_shm_key ()) == -1) {
goto error;
}
shmid = shmget (shm_key, mgSizeRes, SHM_PARAM | IPC_CREAT | IPC_EXCL);
if (shmid == -1) {
goto error;
}
// Attach to the share memory.
memptr = shmat (shmid, 0, 0);
if (memptr == (char*)-1)
goto error;
else {
memcpy (memptr, mgSharedRes, mgSizeRes);
free (mgSharedRes);
}
if (shmctl (shmid, IPC_RMID, NULL) < 0)
goto error;
#endif
/* 打开文件 */
if ((lockfd = open (LOCKFILE, O_WRONLY | O_CREAT | O_TRUNC, 0644)) == -1)
goto error;
#ifdef _USE_MMAP
/* 如果使用 mmap,就将共享资源写入文件 */
if (write (lockfd, mgSharedRes, mgSizeRes) < mgSizeRes)
goto error;
else
{
free(mgSharedRes);
mgSharedRes = mmap( 0, mgSizeRes, PROT_READ|PROT_WRITE, MAP_SHARED, lockfd, 0);
}
#else
/* 否则将共享内存对象 ID 写入文件 */
if (write (lockfd, &shmid, sizeof (shmid)) < sizeof (shmid))
goto error;
#endif
close (lockfd);
#ifndef _USE_MMAP
mgSharedRes = memptr;
SHAREDRES_SHMID = shmid;
#endif
SHAREDRES_SEMID = semid;
return mgSharedRes;
error:
perror ("LoadSharedResource");
return NULL;
}</CODE></PRE></TD></TR></TBODY></TABLE></P>
<P>上述程序段是 MiniGUI-Lite
服务器程序用来装载共享资源的。如果系统支持共享内存,则初始化共享内存对象,并将装载的共享资源关联到共享内存对象,然后将共享内存对象 ID
写入文件;如果系统不支持共享内存,则将初始化后的共享资源全部写入文件。在客户端,如果支持共享内存,则可以从文件中获得共享内存对象
ID,并直接关联到共享内存;如果不支持共享内存,则可以使用 mmap 系统调用,将文件映射到进程的地址空间。客户端的代码段如下:
<TABLE cellSpacing=0 cellPadding=5 width="100%" bgColor=#cccccc
border=1><TBODY>
<TR>
<TD><PRE><CODE>
void* AttachSharedResource (void)
{
#ifndef _USE_MMAP
int shmid;
#endif
int lockfd;
void* memptr;
if ((lockfd = open (LOCKFILE, O_RDONLY)) == -1)
goto error;
#ifdef _USE_MMAP
/* 使用 mmap 将共享资源映射到进程地址空间 */
mgSizeRes = lseek (lockfd, 0, SEEK_END );
memptr = mmap( 0, mgSizeRes, PROT_READ, MAP_SHARED, lockfd, 0);
#else
/* 否则获取共享内存对象 ID,并关联该共享内存 */
if (read (lockfd, &shmid, sizeof (shmid)) < sizeof (shmid))
goto error;
close (lockfd);
memptr = shmat (shmid, 0, SHM_RDONLY);
#endif
if (memptr == (char*)-1)
goto error;
return memptr;
error:
perror ("AttachSharedResource");
return NULL;
}</CODE></PRE></TD></TR></TBODY></TABLE></P>
<P><A name=5><SPAN class=atitle2>5 其他</SPAN></A></P>
<P><SPAN class=atitle3>5.1 读写配置文件</SPAN><BR>MiniGUI 的配置文件,即
/etc/MiniGUI.cfg 文件的格式,采用了类似 Windows INI 文件的格式。这种文件格式非常简单,如下所示:
<TABLE cellSpacing=0 cellPadding=5 width="100%" bgColor=#cccccc
border=1><TBODY>
<TR>
<TD><PRE><CODE>
[section-name1]
key-name1=key-value1
key-name2=key-value2
[section-name2]
key-name3=key-value3
key-name4=key-value4
</CODE></PRE></TD></TR></TBODY></TABLE></P>
<P>这种配置文件中的参数以 section 分组,然后用 key=value
的形式指定参数及其值。应用程序也可以利用这种配置文件格式保存一些配置信息,为此,MiniGUI
提供了如下三个函数(include/minigui.h):
<TABLE cellSpacing=0 cellPadding=5 width="100%" bgColor=#cccccc
border=1><TBODY>
<TR>
<TD><PRE><CODE>
int GUIAPI GetValueFromEtcFile (const char* pEtcFile, const char* pSection,const char* pKey, char* pValue, int iLen);
int GUIAPI GetIntValueFromEtcFile (const char* pEtcFile, const char* pSection,const char* pKey, int* value);
int GUIAPI SetValueToEtcFile (const char* pEtcFile, const char* pSection, const char* pKey, char* pValue);
</CODE></PRE></TD></TR></TBODY></TABLE></P>
<P>这三个函数的用途如下:
<UL class=n01>
<LI>GetValueFromEtcFile:从指定的配置文件当中获取指定的键值,键值以字符串形式返回。
<LI>GetIntValueFromEtcFile:从指定的配置文件当中获取指定的整数型键值。该函数将获得的字符串转换为整数值返回(采用strtol
函数转换)。
<LI>SetValueToEtcFile:该函数将给定的键值保存到指定的配置文件当中,如果配置文件不存在,则将新建配置文件。如果给定的键已存在,则将覆盖旧值。</LI></UL>
<P></P>
<P>假定某个配置文件记录了一些应用程序信息,并具有如下格式:
<TABLE cellSpacing=0 cellPadding=5 width="100%" bgColor=#cccccc
border=1><TBODY>
<TR>
<TD><PRE><CODE>
[mginit]
nr=8
autostart=0
[app0]
path=../tools/
name=vcongui
layer=
tip=Virtual&console&on&MiniGUI
icon=res/konsole.gif
[app1]
path=../bomb/
name=bomb
layer=
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -