树莓派在身份证件核验领域应用
树莓派在身份证件核验领域应用
作者:Mr.Kim.Wu
发布:2013-10-08
关键字:RaspberryPi,Raspi,RPI,树莓派,身份证阅读器,二代证,身份证,居民身份证,RFID,NFC,Debian,linux,创客
一、简介
1.1 第二代居民身份证
第二代居民身份证是一种既具有视读,又具有机读两种功能的法定有效证件。证件内记录了公民的身份信息,是不可以替代而且不能非法复制、仿制的证件,具有唯一性。自2004年换发第二代居民身份证工作正式开展以来,全国二代证的换发量已接近12亿张,基本上人手一张。
第二代居民身份证是由多层聚酯材料复合而成的单页卡式证件,采用非接触式IC卡技术制作,具备视读和机读两种功能。证件尺寸设计长85.6毫米,宽54毫米,厚1.0毫米。证件正面有姓名、性别、民族、出生日期、常住户口所在地住址、公民身份号码和本人相片7个登记项目,印有彩色花纹。证件背面有签发机关和有效期限2个登记项目,印有国徽图案、证件名称、写意长城图案和彩色花纹。
第二代居民身份证有六大变化:融入RFID技术、防伪性能提高、办证时间缩短、存储信息增多、有效期重新确定、发放范围扩大等。
1.2 身份证阅读器
居民身份证阅读器接口技术规范符合GA 467-2004国家标准,新制定的标准里增加了指纹内容。
二代身份证读卡器是一种能判断身份证是否伪造的设备,像验钞机一样,能对身份证真伪进行有效识别,二代证内含有RFID芯片,通过二代身份证读卡器,身份证芯片内所存储信息,包括姓名,地址,照片等信息将一一显示,二代证芯片采用智能卡技术,其芯片无法复制,高度防伪,配合二代身份证读卡器,假身份证将无处藏身。可读取、查询第二代居民身份证全部信息,可验证第二代居民身份证真伪。
具有以下特点:
● 通用性强:支持WIN98/2000/XP/NT/WINCE/LINUX等多种操作系统。
● 开放性好:提供SDK供系统集成商进行二次开发。
● 功能强大:可外接标准键盘、鼠标、显示器,提供RS-232C、USB计算机接口。
● 扩展灵活:可加装指纹采集器,现场比对持证人的指纹,进行“人证同一性”认定。也可以外接数码采集设备,采集个人相片、文字等信息,作信息采集设备使用。
● 操作简便:开机即进入阅读界面,阅读软件自动找卡和阅读。
1.3 树莓派 Raspberry Pi
树莓派(英语:RaspberryPi),是一款基于Linux系统的只有一张信用卡大小的单板机计算机。它由英国的树莓派基金会所开发,目的是以低价硬件及自由软件刺激在学校的基本的电脑科学教育。
相关介绍请参考维基:
http://zh.wikipedia.org/wiki/%E6%A0%91%E8%8E%93%E6%B4%BE
树莓派板载2个USB接口,以及丰富的外设端口,方便与各类外设通讯。
本文实现了树莓派与身份证阅读器的连接,阅读显示身份证芯片内容。
二、准备工作
2.1设备清单:
l 树莓派+ SD卡Class 4/ Class 10 8G
l USB转RS232串口线:ProlificUSB-to-Serial Bridg Y-105 (PL2303HX)
l RS232接口身份证阅读器
l TP-Link无线网络路由器
2.2软件
l 字符终端:SecureCRT软件
l 文件传输: FileZilla软件 SFTP(SSH2)传输协议
l 远程桌面:
u Windows:VNC Viewer或UltraVNC-Viewer
u Android:AndroidVNC
三、实现步骤
3.1连接方式
本文使用树莓派板载USB口,通过USB转换线转成UART RS232串口与身份证9针RS232串口相连: USB<->RS232
USB 驱动:免驱动安装
在树莓派USB口插上阅读器之后查看USB<-> RS232设备:
ls -l /dev/ttyUSB0
如果直接使用树莓派板载GPIOTTL串口ttyAMA0可参考下面2个网址:
http://www.irrational.net/2012/04/19/using-the-raspberry-pis-serial-port/
注意:树莓派板载TTL串口不可直接与身份证阅读器串口相连,电平不匹配容易损坏树莓派板载TTL串口。
3.2开发工具链
开发语言:
G++开发底层通讯库。
界面开发语言:本文使用GTK+(GIMP Toolkit)作开发界面
界面设计工具:Glade
其他可选语言:Python、Java、QT、LazarusPascal
3.3软件开发
本文采用调用串口设备/dev/ttyUSB0的方法。
另外一种是直接调用身份证阅读器的USB IO管道 Pipe驱动设备,
这种方法需要开发专用USB驱动,需熟悉USB协议,比较麻烦。
首先保证串口转换线能用。
短接RS232串口的2,3脚。
编写串口测试程序一:
参考:https://sites.google.com/site/semilleroadt/raspberry-pi-tutorials/gpio
去这个网站下载并安装最新的Pyserial库
http://sourceforge.net/projects/pyserial/files/pyserial/
//Python测试程序 testserial.py
import serial
ser =serial.Serial("/dev/ttyUSB0",115200,timeout=1)
ser.write("UARTthe Font")
read =ser.read(13)
print read
ser.close()
运行Python testserial.py
可以在终端看到输出一串字符UARTthe Font,如果不短接2,3脚将会在超时1秒后程序自动退出,直接换行输出空白。
串口测试方法二:
http://raspberrypi.stackexchange.com/questions/4801/usart-resending-problem-via-console
在SSH字符终端输入
sudo stty 115200-F /dev/ttyUSB0 -echo -onlcr
cat /dev/ttyUSB0
在VNC远程桌面终端输入
echo hello>> /dev/ttyUSB0
授权许可:
身份证阅读器通讯库代码ABCVUtility.cpp、ABCVlib.cpp采用开源GPL授权许可协议,照片图像解码需采用公安专用授权许可协议。详请联系作者。
阅读器串口通讯协议(具体请参考标准GA 467-2004):
树莓派与身份阅读器采用命令/应答方式进行数据交换。
数据通讯帧格式:
命令数据输入帧格式 |
|||||||
帧头 |
长度H |
长度L |
命令码 |
命令参数 |
数据内容 |
校验和 |
|
应答数据输出帧格式 |
|||||||
帧头 |
长度H |
长度L |
状 态 SW1 |
状态 SW2 |
状态SW3 |
数据内容 |
校验和 |
身份证芯片存储编码格式:
文字:256字节Unicode 编码,可转换成GBK码。
照片:1024字节图像压缩编码。
开始敲代码:
///////////////////////////////////////////////
//ABCVlib.cpp代码
#include<stdio.h>
#include<fcntl.h>
#include<time.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include"ABCVlib.h"
#include"ABCVUtility.h"
/*帧头*/
#define Preamble00xDD
#define Preamble10xDD
#define Preamble20xDD
#define Preamble30xDD
#define Preamble40xDD
/*返回错误代码*/
#define RD_OK 0 //操作成功
#define OPENPORT_ERR -1 //打开端口失败
#define TIMEOUT_ERR -2 //超时
#define RD_CARD_ERR -3 //无卡或读卡失败
#define CHECKSUM_ERR -4 //校验和错
#define FILE_ERR -5 //读卡结果文件打开出错
/*机器命令码*/
const unsignedchar CMD_SAM_READALLMSG[2]={0x00, 0x00};
/*机器响应命令*/
#define SW1 inBuffer[7]
#define SW2 inBuffer[8]
#define SW3 inBuffer[9]
#define SAMSTATE inBuffer[9]
#defineRD_SAM_OK 0x90 //操作成功
struct defMsg{
unsigned char name[30];
unsigned char sex[2];
unsigned char nation[4];
unsigned char bY[8],bM[4],bD[4];
unsigned char address[70];
unsigned char id[36];
unsigned char depart[30];
unsigned char tsY[8],tsM[4],tsD[4];
unsigned char tpY[8],tpM[4],tpD[4];
};
#define MSG((struct defMsg *)&inBufferTMP[0])
unsigned charinBuffer[2500],inBufferTMP[2500], outBuffer[50];
unsigned longnBytesWrite=0;
int CheckSum=0;
char TMP[512];
charchNation[100];
/*******************************************************************************
函数名: * abcv_SetPreamble 添加数据帧头
输入参数: * 无
输出参数: * 无
*******************************************************************************/
voidabcv_SetPreamble()
{
outBuffer[0]=Preamble0;
outBuffer[1]=Preamble1; outBuffer[2]=Preamble2;
outBuffer[3]=Preamble3; outBuffer[4]=Preamble4; CheckSum=0;
nBytesWrite=0x05;
}
/*******************************************************************************
函数名: * abcv_CheckControlCode 加入待发数据
输入参数: * unsigned char value 加入的数据
输出参数: * 无
*******************************************************************************/
voidabcv_CheckControlCode(unsigned char value)
{
CheckSum ^= value;
outBuffer[nBytesWrite]=value;
nBytesWrite++;
}
int abcv_ReadMsg(intterm, int port, int timeout, unsigned char *pucCHMsg, int *piCHMsgLen, unsignedchar *pucPHMsg, int *piPHMsgLen)
{
int Rtn=0; int i=0; int nBytes=0;
FILE *f;
//unsigned char TMP[512];
//unsigned char chNation[100];
if(abcv_openPort(term,port)== -1) return (OPENPORT_ERR);
memset(outBuffer,'\0',50);
//memset(inBuffer,'\0',2500);
abcv_SetPreamble();
abcv_CheckControlCode(0x00);
abcv_CheckControlCode(0x03);
abcv_CheckControlCode(CMD_SAM_READALLMSG[0]);
abcv_CheckControlCode(CMD_SAM_READALLMSG[1]);
abcv_CheckControlCode(CheckSum);
abcv_write_n(term, outBuffer, nBytesWrite);
//接收帧头
Rtn= abcv_read_n(term, inBuffer, 7, timeout);
if(Rtn<7)
{
abcv_closePort(term);
return(TIMEOUT_ERR); //接收超时
}
if(inBuffer[0]!=Preamble0 ||inBuffer[1]!=Preamble1 ||
inBuffer[2]!=Preamble2|| inBuffer[3]!=Preamble3 ||
inBuffer[4]!=Preamble4)
{
abcv_closePort(term);
return(TIMEOUT_ERR); //接收超时
}
nBytes=inBuffer[5]*256+inBuffer[6];//计算数据长度
//接收指定长度的数据
Rtn = abcv_read_n(term, &inBuffer[7],nBytes, timeout);
abcv_closePort(term);
if(Rtn<nBytes)
{
abcv_closePort(term);
return(TIMEOUT_ERR); //接收超时
}
CheckSum=0;
for (i=5;i<nBytes+6;i++)
CheckSum^=inBuffer[i];
if(CheckSum!=inBuffer[nBytes+6])
{
abcv_closePort(term);
return(CHECKSUM_ERR); //校验和错
}
//返回状态码
if(SW1==0x00 && SW2==0x00 && SW3==RD_SAM_OK)
{
*piCHMsgLen=256;
*piPHMsgLen=1024;
memcpy(pucCHMsg,&inBuffer[14],256);
memcpy(pucPHMsg,&inBuffer[270],1024);
memcpy(inBufferTMP,&inBuffer[14],256);
return (RD_OK);
}
else
{
return(RD_CARD_ERR);
}
return (RD_CARD_ERR);
}
intabcv_ReadIDCard(int term, int port, int timeout,
unsigned char *pucCHMsg, int*piCHMsgLen, unsigned char *pucPHMsg, int *piPHMsgLen)
{
int RTN;
FILE *f;
char *wzfile="./wz.txt";
char *wltfile="./xp.wlt";
char*bmpfile="./xp.bmp";
unsignedchar CHMsg[512],PHMsg[1024];
unsignedint CHMsgLen,PHMsgLen;
RTN=abcv_ReadMsg(term,port, timeout, CHMsg,&CHMsgLen,PHMsg,&PHMsgLen);
if(RTN!=RD_OK) return(RTN);
*piCHMsgLen=256;
*piPHMsgLen=1024;
memcpy(pucCHMsg,CHMsg,256);
memcpy(pucPHMsg,PHMsg,1024);
f=fopen(wzfile,"wb");
if(f==NULL) return(FILE_ERR);
if (fwrite(CHMsg,CHMsgLen,1,f)!=1){
fclose(f);
return(FILE_ERR);
}
fclose(f);
f=fopen(wltfile,"wb");
if (f==NULL) return(FILE_ERR);
if (fwrite(PHMsg,PHMsgLen,1,f)!=1){
fclose(f);
return(FILE_ERR);
}
fclose(f);
//
return(RD_OK);
}
intabcv_getName(char * szName)
{
memset(TMP,'\0',512);
abcv_strUnicode2GB(MSG->name,TMP,30);
sprintf( szName,"%s",TMP); // 姓名:
return (0);
}
intabcv_getSex(char * szSex)
{
memset(TMP,'\0',512);
abcv_strUnicode2GB(MSG->sex,TMP,2);
if ( memcmp(TMP,"1",1)==0 )
sprintf( szSex,"男"); // 性别:
else
sprintf( szSex,"女");
return (0);
}
//… …
/////////////////////////////////
以上cpp 的Makefile:
#
# libABCVLib.soMakefile
#
ARM_PREFIX=arm-linux-gnueabihf-
CC = $(ARM_PREFIX)g++
LD := ld
CFLAGS := -fpermissive
LDFLAGS := -shared-fpic
SOURCE := $(wildcard *.cpp)
OBJS := $(patsubst %.cpp,%.o,$(SOURCE))
TARGET_LIB := libABCVLib.so
all:$(OBJS)
echo $(OBJS)
$(LD) $(LDFLAGS) -o $(TARGET_LIB) $(OBJS)
%.o:%.cpp
@echo Compiling $< ...
$(CC) -c $(CFLAGS) $< -o $*.o
.PHONY: clean
clean:
rm *.so *.o –rf
so编译环境设置:
生成的共享库libABCVLib.so在非标准路经,ld.so 怎么找到它呢?
目前,Linux 通用的做法是将非标准路经加入 /etc/ld.so.conf,然后运行 ldconfig 生成 /etc/ld.so.cache。ld.so加载共享库的时候,会从ld.so.cache 查找。
或者在/etc/ld.so.conf.d/目录下新建一个共享库名字对应的conf文件:libABCVLib.conf,文件内容为你的工作目录,本文为/home/pi/kim/gtk30。
图形界面: 采用GTK+图形工具包调用libABCVLib.so 动态库显示身份证文字和照片。
图形界面开发参考网址:http://hertaville.com/2012/09/28/development-environment-raspberry-pi-cross-compiler/、http://hertaville.com/2013/07/19/cross-compiling-gtk-applications-for-the-raspberry-pi/
//gtktest.c
#include<gtk/gtk.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<time.h>
#include<termio.h>
#include<unistd.h>
#include<errno.h>
#include<iconv.h>
#include<locale.h>
#include<ABCVlib.h>
#defineTERM_TYPE 1 //终端类型 默认1
#defineTERM_PORT 1 //阅读机具所接的串口号
//1:主机串口一
#defineTIMEOUT 4 //读卡超时4秒返回
#define BUFLEN 255
GtkWidget *window;
GtkWidget *frame;
GtkWidget *label;
GtkWidget *plus;
GtkWidget *minus;
GtkWidget *fixed1;
GtkWidget *entrName;
GtkWidget *entrSex;
GtkWidget *label1;
GtkWidget *entrNation;
GtkWidget *entrBirthday;
GtkWidget *entrAddr;
GtkWidget *entrID;
GtkWidget *entrDep;
GtkWidget *entrValid;
GtkWidget *label7;
GtkWidget *label9;
GtkWidget *hseparator1;
GtkWidget *label2;
GtkWidget *bt_close;
GtkWidget *button1;
GtkWidget *label3;
GtkWidget *label6;
GtkWidget *label5;
GtkWidget *label4;
GtkWidget *image;
//代码转换:从一种编码转为另一种编码
int code_convert(char*from_charset,char *to_charset,char *inbuf,int inlen,char *outbuf,int outlen)
{
iconv_t cd;
int rc;
char **pin = &inbuf;
char **pout = &outbuf;
cd = iconv_open(to_charset,from_charset);
if (cd==0) return -1;
memset(outbuf,0,outlen);
if (iconv(cd,pin,&inlen,pout,&outlen)==-1)return -1;
iconv_close(cd);
return 0;
}
//UNICODE码utf-8转为GB码
int u2g(char *inbuf,int inlen,char *outbuf,intoutlen)
{
returncode_convert("utf-8","gb2312",inbuf,inlen,outbuf,outlen);
}
//GB码转为UNICODE码utf-8
int g2u(char*inbuf,size_t inlen,char *outbuf,size_t outlen)
{
returncode_convert("gb2312","utf-8",inbuf,inlen,outbuf,outlen);
}
voidon_bt_close_clicked(GtkButton *button,gpointer user_data)
{
gtk_main_quit();
}
voidon_bt_ok_clicked (GtkButton *button,gpointer user_data)
{
inti,Len,nRet,zpLen;
unsigned char Buff[500];
char outbuf[BUFLEN];
unsigned char zpBuff[1024];
char TMP[512];
char *wltfile="./xp.wlt";
char*bmpfile="./xp.bmp";
FILE*f;
//调用libABCVLib.so 动态库阅读身份证,自动生成文字和照片文件
nRet =abcv_ReadIDCard (TERM_TYPE, TERM_PORT,TIMEOUT, Buff, &Len, zpBuff, &zpLen); //libABCVLib.so
if (nRet==0)
{
//显示姓名
memset(TMP,'\0',512);
memset(outbuf,'\0',BUFLEN);
abcv_getName(TMP);
if ((i=g2u(TMP,strlen(TMP),outbuf,BUFLEN))==0 )
{
gtk_entry_set_text(GTK_ENTRY(entrName),outbuf);
}
//显示性别
memset(TMP,'\0',512);
abcv_getSex(TMP);
if ((i=g2u(TMP,strlen(TMP),outbuf,BUFLEN))==0 )
{
gtk_entry_set_text(GTK_ENTRY(entrSex), outbuf);
}
//显示民族
memset(TMP,'\0',512);
abcv_getchNation(TMP);
if ((i=g2u(TMP,strlen(TMP),outbuf,BUFLEN))==0 )
{
gtk_entry_set_text(GTK_ENTRY(entrNation), outbuf);
}
//显示出生日期
memset(TMP,'\0',512);
abcv_getBirth(TMP);
if ((i=g2u(TMP,strlen(TMP),outbuf,BUFLEN))==0 )
{
gtk_entry_set_text(GTK_ENTRY(entrBirthday), outbuf);
}
//显示户籍地址
memset(TMP,'\0',512);
abcv_getAddr(TMP);
if ((i=g2u(TMP,strlen(TMP),outbuf,BUFLEN))==0 )
{
gtk_entry_set_text(GTK_ENTRY(entrAddr), outbuf);
}
//显示身份证号码
memset(TMP,'\0',512);
abcv_getIdCode(TMP);
if ((i=g2u(TMP,strlen(TMP),outbuf,BUFLEN))==0 )
{
gtk_entry_set_text(GTK_ENTRY(entrID), outbuf);
}
//显示签发机关
memset(TMP,'\0',512);
abcv_getIssue(TMP);
if ((i=g2u(TMP,strlen(TMP),outbuf,BUFLEN))==0 )
{
gtk_entry_set_text(GTK_ENTRY(entrDep), outbuf);
}
//显示证件有效期
memset(TMP,'\0',512);
abcv_getValidity(TMP);
if ((i=g2u(TMP,strlen(TMP),outbuf,BUFLEN))==0 )
{
gtk_entry_set_text(GTK_ENTRY(entrValid), outbuf);
}
//显示身份证照片
image =gtk_image_new_from_file(bmpfile);
gtk_widget_set_size_request(image,102, 126);
gtk_widget_show (image);
gtk_fixed_put (GTK_FIXED (fixed1),image, 438, 160);
}
else {
g_warning ("Error Code: %d", nRet);
}
}
int main(int argc,char** argv) {
gtk_init(&argc, &argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_position(GTK_WINDOW(window),GTK_WIN_POS_CENTER);
gtk_window_set_default_size (GTK_WINDOW(window), 580, 400);
gtk_window_set_title(GTK_WINDOW(window),"Raspi IDCard2 Reader");
fixed1 = gtk_fixed_new ();
gtk_widget_show (fixed1);
gtk_container_add (GTK_CONTAINER (window),fixed1);
gtk_widget_set_size_request (fixed1, 286,123);
entrName = gtk_entry_new ();
gtk_widget_show (entrName);
gtk_fixed_put (GTK_FIXED (fixed1), entrName,96, 16);
gtk_widget_set_size_request (entrName, 158,25);
entrSex = gtk_entry_new ();
gtk_widget_show (entrSex);
gtk_fixed_put (GTK_FIXED (fixed1), entrSex,96, 72);
gtk_widget_set_size_request (entrSex, 84,25);
label1 = gtk_label_new("\345\247\223 \345\220\215");
gtk_widget_show (label1);
gtk_fixed_put (GTK_FIXED (fixed1), label1, 8,23);
gtk_widget_set_size_request (label1, 82, 17);
entrNation = gtk_entry_new ();
gtk_widget_show (entrNation);
gtk_fixed_put (GTK_FIXED (fixed1),entrNation, 344, 72);
gtk_widget_set_size_request (entrNation, 84,25);
entrBirthday = gtk_entry_new ();
gtk_widget_show (entrBirthday);
gtk_fixed_put (GTK_FIXED (fixed1),entrBirthday, 96, 112);
gtk_widget_set_size_request (entrBirthday,160, 25);
entrAddr = gtk_entry_new ();
gtk_widget_show (entrAddr);
gtk_fixed_put (GTK_FIXED (fixed1), entrAddr,96, 160);
gtk_widget_set_size_request (entrAddr, 331,25);
entrID = gtk_entry_new ();
gtk_widget_show (entrID);
gtk_fixed_put (GTK_FIXED (fixed1), entrID,96, 200);
gtk_widget_set_size_request (entrID, 331,25);
entrDep = gtk_entry_new ();
gtk_widget_show (entrDep);
gtk_fixed_put (GTK_FIXED (fixed1), entrDep,96, 240);
gtk_widget_set_size_request (entrDep, 331,25);
entrValid = gtk_entry_new ();
gtk_widget_show (entrValid);
gtk_fixed_put (GTK_FIXED (fixed1), entrValid,96, 280);
gtk_widget_set_size_request (entrValid, 331,25);
label7 = gtk_label_new("\345\217\221\350\257\201\346\234\272\345\205\263");
gtk_widget_show (label7);
gtk_fixed_put (GTK_FIXED (fixed1), label7,16, 240);
gtk_widget_set_size_request (label7, 68, 25);
label9 = gtk_label_new("\346\234\211\346\225\210\346\234\237\351\231\220");
gtk_widget_show (label9);
gtk_fixed_put (GTK_FIXED (fixed1), label9,16, 280);
gtk_widget_set_size_request (label9, 68, 17);
hseparator1 = gtk_hseparator_new ();
gtk_widget_show (hseparator1);
gtk_fixed_put (GTK_FIXED (fixed1),hseparator1, 24, 312);
gtk_widget_set_size_request (hseparator1,426, 16);
label2 = gtk_label_new("\346\200\247 \345\210\253");
gtk_widget_show (label2);
gtk_fixed_put (GTK_FIXED (fixed1), label2,16, 80);
gtk_widget_set_size_request (label2, 64, 17);
bt_close = gtk_button_new_with_mnemonic("\351\200\200\345\207\272");
gtk_widget_show (bt_close);
gtk_fixed_put (GTK_FIXED (fixed1), bt_close,296, 336);
gtk_widget_set_size_request (bt_close, 53,27);
button1 = gtk_button_new_with_mnemonic("\350\257\273\345\215\241");
gtk_widget_show (button1);
gtk_fixed_put (GTK_FIXED (fixed1), button1,152, 336);
gtk_widget_set_size_request (button1, 53, 27);
label3 = gtk_label_new("\346\260\221 \346\227\217");
gtk_widget_show (label3);
gtk_fixed_put (GTK_FIXED (fixed1), label3,280, 80);
gtk_widget_set_size_request (label3, 64, 17);
label6 = gtk_label_new("\350\272\253\344\273\275\350\257\201\345\217\267");
gtk_widget_show (label6);
gtk_fixed_put (GTK_FIXED (fixed1), label6,16, 208);
gtk_widget_set_size_request (label6, 69, 17);
label5 = gtk_label_new("\345\234\260 \345\235\200");
gtk_widget_show (label5);
gtk_fixed_put (GTK_FIXED (fixed1), label5,16, 168);
gtk_widget_set_size_request (label5, 64, 17);
label4 = gtk_label_new("\347\224\237 \346\227\245");
gtk_widget_show (label4);
gtk_fixed_put (GTK_FIXED (fixed1), label4,16, 120);
gtk_widget_set_size_request (label4, 64,17);
g_signal_connect ((gpointer) bt_close,"clicked",
G_CALLBACK(on_bt_close_clicked),
NULL);
g_signal_connect ((gpointer) button1,"clicked",
G_CALLBACK(on_bt_ok_clicked),
NULL);
gtk_widget_show_all(window);
gtk_main();
return 0;
}
直接在树莓派上编译gtktest.c:
GTK+ Makefile文件:
ARM_PREFIX=arm-linux-gnueabihf-
CC = $(ARM_PREFIX)gcc
SRC += gtktest.c
TARGET = gtktest
LIBRARY += gtk-3
LIBRARY += gdk-3
LIBRARY += atk-1.0
LIBRARY += gio-2.0
LIBRARY +=pangocairo-1.0
LIBRARY +=gdk_pixbuf-2.0
LIBRARY +=cairo-gobject
LIBRARY +=pango-1.0
LIBRARY += cairo
LIBRARY +=gobject-2.0
LIBRARY +=glib-2.0
LIBRARY += stdc++
LIBRARY+= ABCVLib
LIBRARY += dl
LIBRARYDIR +=/lib/arm-linux-gnueabihf
LIBRARYDIR +=/usr/lib/arm-linux-gnueabihf
LIBRARYDIR += /lib
LIBRARYDIR +=/usr/lib
#请改成你自己的工作目录
LIBRARYDIR+= /home/pi/kim/gtk30
XLINK_LIBDIR +=/lib/arm-linux-gnueabihf
XLINK_LIBDIR +=/usr/lib/arm-linux-gnueabihf
INCLUDEDIR +=/usr/include/gtk-3.0
INCLUDEDIR +=/usr/include/pango-1.0
INCLUDEDIR +=/usr/include/gio-unix-2.0/
INCLUDEDIR +=/usr/include/atk-1.0
INCLUDEDIR +=/usr/include/cairo
INCLUDEDIR +=/usr/include/gdk-pixbuf-2.0
INCLUDEDIR +=/usr/include/freetype2
INCLUDEDIR +=/usr/include/glib-2.0
INCLUDEDIR +=/usr/lib/arm-linux-gnueabihf/glib-2.0/include
INCLUDEDIR +=/usr/include/pixman-1
INCLUDEDIR +=/usr/include/libpng12
#请改成你自己的工作目录
INCLUDEDIR+= /home/pi/kim/gtk30
OPT = -O0
DEBUG = -g
WARN= -Wall -Wextra -pedantic
PTHREAD= -pthread
INCDIR = $(patsubst %,-I%,$(INCLUDEDIR))
LIBDIR = $(patsubst %,-L%,$(LIBRARYDIR))
LIB = $(patsubst %, -l%,$(LIBRARY))
XLINKDIR =$(patsubst %,-Xlinker -rpath-link=%,$(XLINK_LIBDIR))
all:
$(CC) $(OPT) $(DEBUG) $(WARN) $(LIBDIR)$(PTHREAD) $(INCDIR) $(XLINKDIR) $(LIB) $(SRC) -o $(TARGET)
clean:
rm -rf $(TARGET)
3.4 身份证阅读运行效果(在电脑VNC显示读卡界面)
依次输入:
$make
$./gtktest
当然也可直接在安卓手机VNC界面下打开阅读界面并显示读卡结果:
附:用Lazarus Pascal设计树莓派下图形界面:
还可在Windows环境下交叉设计编译,正如其所说的一次编译到处运行:
在Windows下执行Lazarus设计的程序:
四、扩展应用
与手机结合、触摸屏、摄像头、指纹头、打印机、蓝牙、NFC…
五、市场前景
该设备应用领域:自助设备、手持设备、物联网、安防门禁…
适用范围:
●公安:身份证申领、户口登记迁移、人口管理等。 旅馆:住宿登记等。
●民政:求学、就业、参军、婚姻登记等。
●民航:机票购买、登机等。
●银行:开户、信用卡交易、大额取款等。
●邮局:领取邮件汇款等。
●电信:电话手机开户、各种通信业务等。
●证券:股票、期货交易等。
●企事业单位:招工、来访登记