有时候为了测试卡片消费,不能每次都重新编译进来吧,这时候可以利用LUA脚本。选择第11项。把需要测试卡片的指令写进LUA脚本,然后执行,
如图所示:
执行结果:
封装的功能模块,即各种库如下:
liblua.a 执行lua脚本使用
libblkfile.a 黑名单查找与存储
libmaycalc.a 算法库,如SHA,DES算法
libmycard.a 卡库,提供操作卡片的APDU
libmyfile.a 文件库,提供文件存储与读取
libmycom.a 通信库,提供socket通信
libmyup.a 银联库,银联卡处理逻辑与银联后台通信业务
其中,libmyblkfile库的makefile文件如下:
######################################## #makefile ######################################## BINARY= libmyblkfile CC= gcc LD= ld CFLAGS= -std=c99 -g LDSCRIPT= LDFLAGS= -Llib OBJS= AH_BlackList.o AH_BlkDirFileLib.o APP_Blacklist.o #CFLAGS=-std=c99 .PHONY: clean all:images images: $(BINARY).a $(OBJS):%.o:%.c $(CC) -c $(CFLAGS) $< -o $@ %.a: $(OBJS) ar crv $(*).a $(OBJS) cp libmyblkfile.a ../ clean: rm -f *.o
主程序的makefile文件如下:
######################################## #makefile ######################################## #编译指定子目录 SUBDIRS := .\\lib\\NC_Com\ .\\lib\\NC_FileSys\ .\\lib\\NC_BlkFile\ .\\lib\\NC_Card\\NC_Card_Lib\ .\\lib\\NC_UPCash\\NC_UPCash_Lib define make_subdir @ for subdir in $(SUBDIRS) ; do \ ( cd $$subdir && make $1) \ done; endef #编译主程序 BINARY := ./bin/bus OBJ_DIR := ./obj/ CC= gcc LD= ld CFLAGS= -std=c99 -Wall -g LDSCRIPT= -lmycom -lws2_32 -liconv -lmyfile -lmycard -lmyup -lmycalc -lmyblkfile -llua LDFLAGS= -Llib SRC = $(wildcard *.c) DIR = $(notdir $(SRC)) OBJS = $(patsubst %.c,$(OBJ_DIR)%.o,$(DIR)) #OBJS= main.o myutils.o inirw.o cmdpboc.o cputest.o bustcp.o ansrec.o m1cmd.o m1api.o m1test.o upcash.o myother.o getsys.o #CFLAGS=-std=c99 #@echo Building lib... #$(call make_subdir) .PHONY: clean lib all: prebuild $(BINARY).exe prebuild: @echo Building app... $(BINARY).exe : $(OBJS) @echo Generating ... $(CC) -o $(BINARY).exe $(OBJS) $(LDFLAGS) $(LDSCRIPT) @echo OK! $(OBJ_DIR)%.o : %.c $(CC) -c $(CFLAGS) $< -o $@ lib: @echo Building lib... $(call make_subdir) clean: rm -f $(OBJ_DIR)*.o @echo Removed!
各个功能模块,又可以进一步细分为子模块。
拿通信库举例:
嵌入式设备都需要支持各种不同的通讯模块。比如硬件设备有A701、A801、B502等,通讯模块有GL868、MG323、MC8630、N710、ZIGBEE等,这些设备分别支持全部或部分通讯模块。
整体架构分为如下:
驱动大致分为三层:
1、接口层:为用户提供统一的接口,比如:Connect、TxData、RxData、Disconnect等。
2、驱动层:向接口层暴露统一的接口,这些接口用于完成实际的连接断开和数据收发等,比如:DevConnect、DevTxData、RxData、Disconnect等。该层只会和支持的通讯模块相关,不会直接访问任何硬件功能,包括串口通讯、GPIO控制全部通过底层的设备层实现。
3、设备层:向驱动层提供统一的接口,这些接口通过访问物理硬件来实现和模块的通讯,比如:XXXPowerOn、SerialSend、SerialReceive等,并定义该设备支持哪些模块。
三层之间通过标准的接口进行互相访问。
1、接口层对外接口(用户操作通讯模块使用的API):
uint32_t Com_Dev_Start(void); //设备重新上电,并和网络建立连接 uint32_t Com_Dev_Restart(void); //设备断网断电 uint32_t Com_Dev_Stop(void); //连接远端服务器 uint32_t Com_Dev_Connect(uint8_t *ip, uint16_t port, uint32_t timeout, uint32_t channel); //断开连接 uint32_t Com_Dev_Disconnect(uint32_t channel); //发送数据 uint32_t Com_Dev_TxData(uint8_t *buf, uint32_t len, uint32_t timeout, uint32_t channel); //接收数据 uint32_t Com_Dev_RxData(uint8_t *buf, uint32_t *rxlen, uint32_t len, uint32_t timeout, uint32_t channel); //获取信号质量 uint32_t Com_Dev_GetSQ(uint8_t *csq);
2、驱动层对接口层的接口(对接口层屏蔽各通讯模块的差异):
struct ComDevFunc{ uint32_t (*start)(ComDevDesc *dev); uint32_t (*restart)(ComDevDesc *dev); uint32_t (*stop)(ComDevDesc *dev); uint32_t (*connect)(ComDevDesc *dev, uint8_t *ip, uint16_t port, uint32_t timeout, uint32_t channel); uint32_t (*disconnect)(ComDevDesc *dev, uint32_t channel); uint32_t (*txData)(ComDevDesc *dev, uint8_t *buf, uint32_t len, uint32_t timeout, uint32_t channel); uint32_t (*rxData)(ComDevDesc *dev, uint8_t *buf, uint32_t *rxlen, uint32_t len, uint32_t timeout, uint32_t channel); uint32_t (*getVer)(ComDevDesc *dev, uint8_t *buf, uint32_t versize); uint32_t (*getCSQ)(ComDevDesc *dev, uint8_t *csq); };
3、设备层对驱动层提供的接口(屏蔽串口号、GPIO引脚等平台相关的内容):
int Com_PortOpen(uint32_t baud); int Com_PortClose(void); int Com_PortSend(uint8_t *buf, int len); int Com_PortRecv(uint8_t *buf, int len, int timeout); int Com_PortGetLen(void); int Com_PortFlush(void); //具体硬件相关函数,在Model_XXXXX.h中实现 //仅需实现平台支持的模块即可 void COM_GL868Power(int state); void COM_MC8332Power(int state); void COM_MG323Power(int state); void COM_EMV3081Power(int state); void COM_CC2530Power(int state); void COM_N710Power(int state);
4. 目录结构
│ ComAPI.c -----通讯库API实现 │ ComAPI.h -----通讯库API声明(接口层API) │ ComDevs.c -----供驱动使用的公共定义和工具函数 │ ComDevs.h -----供驱动使用的公共定义和工具函数(驱动层API) │ Readme.txt │ ├─Devices -----存放各种模块的驱动程序 │ Dev_CDMA_MC8332.c │ Dev_CDMA_MC8332.h │ Dev_GPRS_GL868.C │ Dev_GPRS_GL868.h │ Dev_WIFI_EMV3081.c │ Dev_WIFI_EMV3081.h │ └─Models -----存放适配各种设备型号的目录 Model.h -----设备层API Model_A701.c Model_B502.c
5. 支持新模块的方法
比如A701设备要新增支持SUPER123模块
1、在Devices目录中增加一个文件Dev_6G_SUPER123.c并实现ComDevFunc结构中定义的各函数
2、在设备文件Model_A701.c中增加电源控制函数COM_SUPER123Power。
3、在设备文件Model_A701.c中添加驱动函数到gComFuncs数组中。
4. 适配新设备的方法
1、在Models目录新增加一个文件Model_XXXX.c
2、实现串口通讯函数(Com_PortXXXX系列,参考Model.h中的定义)
3、实现支持的通讯模块的上下电函数COM_XXXXPower(int state);
4、实现gComFuncs数组,其中引用所有支持模块的驱动函数。
5. 对部分系统函数的引用
对于部分系统相关函数,比如延时、调试信息的打印等,全部提供默认实现,并将默认实现声明为弱函数。这样当用户需要进行自定义的时候可以进行自定义,如果不需要可以直接忽略不会造成编译错误。
这样的函数有如下三个:
void Com_Hook_Printf(char* fmt, ...); void Com_Hook_PrintHex(uint8_t* buf, int len); //重定义延时功能,如果使用操作系统的话可以充分利用操作系统的调度特性,避免死等造成的浪费 void Com_Hook_DelayMs(uint32_t ms);
6. 驱动中普遍使用的功能
对于部分编写通讯模块驱动常用的功能,模块中提供了一系列的辅助函数,避免重复劳动