最近一个项目需要使用身份证读卡器进行数据采集,采集的身份证数据需要实时进入公司数据库,这就难免需要对设备进行二次开发。由于之前有过类似USB/串口盒子开发的经验,所以就接下了。
2021-07-15更新
技术选型
简单搜了一下,目前身份证读卡器的开发环境大部分还停留在Windows+C/C++/C#阶段,但少部分头部厂家已经开始提供Linux+Java/JS/PHP的SDK了,虽然功能可能没有windows的多。
由于这个中间件需要提供给业务部门使用,需要面对不同的操作系统,大概率会出现兼容性问题。所以拟在类似树莓派一样的Linux平台上进行部署,最终将读卡器与中间件主机一同交付,这样就不会存在兼容性问题了。
为了能快速部署,考虑将中间件使用docker部署,但由于对docker挂载非存储设备的可行性不了解,故还需要进一步研究。
开发语言选择我最熟悉的Python,原因如下:
- 之前有使用Python开发串口设备的经验;
- Python能够调用C++的动态库;
2021-07-16更新
设备选型
身份证读卡器的技术已经基本成熟了,各厂家的产品也几乎大同小异,区别也就在售后服务、技术支持上面了,综合各方面因素,最终选择了新中新的读卡器F200。SDK下载地址在:https://www.onecardok.com.cn/download,操作系统和语言支持还是非常丰富的,主要是提供有我需要的Linux C++开发包,而且Linux平台支持x86、x64、arm32、arm64
在京东下单,估计19日就能到
2021-07-19更新
设备到手,在win上测试功能完好,但发现在win上的驱动安装比较繁琐
在官网下载如下开发包
测试代码:
import ctypes
synR = ctypes.cdll.LoadLibrary("/usr/lib/libSynReader.so")
nRet = synR.openUsbComm()
if nRet == 0:
class IDCardDataUTF8(ctypes.Structure):
_fields_ = [
("CardType", ctypes.c_char * 10), # I为外国人居住证,J 为港澳台居住证,空格(0x20)为普通身份证
("Name", ctypes.c_char * 40), # 姓名
("EngName", ctypes.c_char * 130), # 英文名(外国人居住证)
("Sex", ctypes.c_char * 10), # 性别
("Nation", ctypes.c_char*100), # 民族或国籍(外国人居住证)
("Birthday", ctypes.c_char*18), # 出生日期
("Address", ctypes.c_char*130), # 住址
("IDCardNo", ctypes.c_char*40), # 身份证号或外国人居住证号(外国人居住证)
("GrantDept", ctypes.c_char*40), # 发证机关
("UserLifeBegin", ctypes.c_char*30), # 有效开始日期
("UserLifeEnd", ctypes.c_char*30), # 有效截止日期
("PassID", ctypes.c_char*30), # 通行证号码(港澳台)
("IssuesTimes", ctypes.c_char*10), # 签发次数(港澳台)
("CertVol", ctypes.c_char * 10), # 证件版本号(外国人居住证)
("wlt", ctypes.c_byte*1024), # 照片数据
("isSavePhotoOK", ctypes.c_int), # 照片是否解码保存 0=no 1=yes
("fp", ctypes.c_char*1024), # 指纹数据
("isFpRead", ctypes.c_int) # 是否读取了指纹
]
data = IDCardDataUTF8()
ctype_data = ctypes.byref(data)
readRet = synR.getIDcard(ctype_data)
print(data.Name.decode('utf-8')) #身份证上的姓名
synR.closeComm()
else:
print(f'未连接成功!: nRet')
解压后会发现有非常多平台的动态库,目录中的libusb-1.0.so可以忽略,因为我们能自己安装
>>> sudo apt install libusb-1.0-0-dev
目录中的libSynReader.so建议移入/usr/lib目录中
在树莓派4b+ubuntu 20.04 64bit平台上,libArm64目录下的动态库能正常使用
>>> uname -a
Linux rasp02 5.4.0-1038-raspi #41-Ubuntu SMP PREEMPT Thu Jun 17 14:14:11 UTC 2021 aarch64 aarch64 aarch64 GNU/Linux
在树莓派4b+Raspberry Pi OS with desktop平台上,libHf32目录下的动态库能正常使用
>>> uname -a
Linux raspberrypi 5.10.17-v7l+ #1421 SMP Thu May 27 14:00:13 BST 2021 armv7l GNU/Linux
参考:
https://www.cnblogs.com/lxcsmallcity/p/12289503.html
https://blog.csdn.net/weixin_34240520/article/details/91846951
2021-07-20更新
经过大量搜索后发现,起初在docker中部署中间件的设想可能要落空了,因为目前docker对非存储设备的挂载非常不友好,故放弃使用docker,直接在操作系统上部署
考虑到对读卡器的管理,需要读取读卡器的SAMID(可以理解为设备ID),而咨询技术支持后发现,Linux版本的开发包暂不支持获取设备的SAMID,但可以给我提供一个支持该功能的版本,最终甚至把源码给我,让我在自己的平台上进行编译。最终顺利完成编译,生成新的libSynReader.so文件。
最后甚至在Mac上编译成功并成功读取到SAMID
在Mac上编译时如果命令中存在’-lrt’会报错
>>> g++ version.cpp IDCard.cpp M1Reader.cpp convertUtf8Manual.cpp usbHelper.cpp com.cpp serialHelper.cpp transData.cpp -L/usr/lib -lusb-1.0 -lrt -shared -fPIC -o libSynReader.so
...
clang: error: linker command failed with exit code 1
...
解决办法就是把’-lrt’这个参数去掉即可,貌似没有影响
参考:
https://www.cnblogs.com/yjf512/p/9553356.html
https://stackoverflow.com/a/1506342/7151777
2021-07-28更新
经过验证,开发包中提供的样例程序在Mac平台也是能够正常编译的,只是需要对Makefile进行少许修改
2021-08-05更新
经过验证,在宿主机和容器均为Linux系统的情况下,容器中可以连接读卡器,Mac作为宿主机的docker容器则无法连接。
docker run:
docker run --privileged -v /dev:/dev ...
docker-compose.yaml:
services:
xxxxxxx:
volumes:
- /dev:/dev
privileged: true
参考:https://stackoverflow.com/a/51064150/7151777
2021-08-06更新
关于在树莓派的容器内播放声音的问题可参考以下几篇博客:
最后,通过远程桌面实现无外设的情况下连接树莓派,参考:
如果在p = pyaudio.Pyaudio()时出现报警信息,不用在意,直接忽略就好,参考:
https://blog.yjl.im/2012/11/pyaudio-portaudio-and-alsa-messages.html