嵌入式linux之go语言开发(三)卡库的封装

卡库的封装和调用,这是一个重头戏,完成了它,则就完整了所有的封装。至于网络通信,记录存储等,则可以

使用go本身的模块去做。后续做一版完整的go语言版B503应用。

截至目前,非接触式卡库的封装接近尾声,这部分花了不少精力。

package drivers

/*

#cgo CFLAGS: -Iinclude

#cgo LDFLAGS: -Llib -lpicc
#include <stdlib.h>
#include "pcd_apis.h"
*/
import "C"
import "unsafe"

import (
	"fmt"
	"log"
)

const (
	DEF_PCD_SeleTypeA int = 1
	DEF_PCD_SeleTypeB int = 2
)

type __Pcd14443Cfg struct {
	PPS   int //AB  0:标准的支持PPS,非0:强制不支持PPS
	M1CPU int //AB  0:自动识别,1:强制M1,2:强制CPU
}
type __Pcd14443Info struct {
	ATQA []byte //A专用   REQA命令返回的ATQA值  		固定有效2字节
	UID  []byte //A专用   卡片的UID,					长度为4,7,10字节

	UID_Size byte //A专用   卡片的UID长度					长度为4,7,10字节
	SAK      byte //A专用   卡片选卡成功返回的SAK值  		固定有效1字节
	TypeAB   byte //A/B共用 当前是A卡还是B卡     DEF_PCD_SeleTypeA=A卡,DEF_PCD_SeleTypeB=B卡
	ATS_Size byte //A专用   接收到的ATS数据长度

	BActive  byte //B激活状态 0:非激活  非0:激活
	Rvs08bit byte
	Rvs16bit byte

	ATS []byte //A专用   ATS接收数据缓冲区 按中国金融规定 PICC回的数据最长为21字节

	ATQB []byte //B专用   卡片应答数据

} //14443应用数据结构

var (
	Pcd14443CfgMode int = DEF_PCD_SeleTypeA //PCD选择TypeA卡 操作PICC类型定义
	Pcd14443CfgA    __Pcd14443Cfg
	Pcd14443CfgB    __Pcd14443Cfg
	Pcd14443Info    __Pcd14443Info //14443协议层数据缓冲区

	PiccCid int
)

func init() {
	Pcd14443Info.ATQA = make([]byte, 4)
	Pcd14443Info.UID = make([]byte, 16)
	Pcd14443Info.ATS = make([]byte, 40)
	Pcd14443Info.ATQB = make([]byte, 20)
}

func ICC_PCD_SysCfg(mode, m1, pps int) {
	Pcd14443CfgMode = mode
	if DEF_PCD_SeleTypeA == Pcd14443CfgMode {
		Pcd14443CfgA.PPS = pps
		Pcd14443CfgA.M1CPU = m1
	} else if DEF_PCD_SeleTypeB == Pcd14443CfgMode {
		Pcd14443CfgB.PPS = pps
		Pcd14443CfgB.M1CPU = m1
	}

}

func ICC_PCD_Init() int {

	tpe := make([]byte, 4)
	para := make([]byte, 50)

	//var cardType *C.uchar = (*C.uchar)(unsafe.Pointer(&tpe[0]))
	//var rfPara *C.uchar = (*C.uchar)(unsafe.Pointer(&para[0]))
	cardType := (*C.uchar)(unsafe.Pointer(&tpe[0]))
	rfPara := (*C.uchar)(unsafe.Pointer(&para[0]))

	ret := C.PcdInit(cardType, rfPara)
	if ret != 0 {
		return 1
	}
	fmt.Println(tpe)
	fmt.Println(para)
	ret = C.PiccOpen()
	return int(ret)

}

func ICC_PCD_Open() int {
	ret := C.PiccOpen()
	return int(ret)
}

func ICC_PCD_Close() {
	C.PiccClose()
}

//ISO14443 A/B 使卡进入HALT状态
func ICC_PCD_Halt() int {
	//nc_iso14443_debug("%s","ICC_PCD_Halt\n");
	ret := C.PiccRemove('H', C.uchar(PiccCid))
	return int(ret)
}

//ISO14443 A/B 使已经进入HALT状态的卡激活,并且进行冲突循环,选卡操作
func ICC_PCD_WakeUp() int {
	ret := ICC_PCD_Request(Pcd14443CfgMode)
	return int(ret)
}

func ICC_PCD_Request(mode int) int {

	tpe := make([]byte, 4)
	sno := make([]byte, 100)
	oth := make([]byte, 100)
	pid := make([]byte, 1)
	lenth := 0
	ptr := 0

	ret := C.uchar(0)
	cardType := (*C.uchar)(unsafe.Pointer(&tpe[0]))
	serialNo := (*C.uchar)(unsafe.Pointer(&sno[0]))
	other := (*C.uchar)(unsafe.Pointer(&oth[0]))
	piccid := (*C.uchar)(unsafe.Pointer(&pid[0]))

	if DEF_PCD_SeleTypeA == Pcd14443CfgMode {
		if DEF_PCD_SeleTypeA == Pcd14443CfgA.M1CPU { //强制M1
			ret = C.PiccDetect('M', cardType, serialNo, piccid, other)
		} else if DEF_PCD_SeleTypeB == Pcd14443CfgA.M1CPU { //强制CPUA
			ret = C.PiccDetect('A', cardType, serialNo, piccid, other)
		} else if 3 == Pcd14443CfgA.M1CPU { //自动检测A,B,无法检测到纯M1 操作一次28ms
			ret = C.PiccDetect(0x01, cardType, serialNo, piccid, other)
		} else { //自动CPUA/M1 操作一次18ms
			ret = C.PiccDetect('X', cardType, serialNo, piccid, other)
		}
		//		printf(">>>>>>>>>>>>PiccDetect, ret=%d   count=%d\n", ret, count++);
	} else if DEF_PCD_SeleTypeB == Pcd14443CfgMode { //强制CPUB
		ret = C.PiccDetect('B', cardType, serialNo, piccid, other)
	} else {
		log.Fatal("err config!")
	}
	//fmt.Printf("ret = %d\n", int(ret))
	PiccCid = int(pid[0])
	if ret == 0 {
		//fmt.Printf("tpe:%x\n", tpe)
		//fmt.Printf("sno:%x\n", sno)
		//fmt.Printf("oth:%x\n", oth)
		if 'B' == tpe[0] {
			Pcd14443Info.TypeAB = byte(DEF_PCD_SeleTypeB) //TYPE B
		} else if 'M' == tpe[0] {
			Pcd14443Info.TypeAB = byte(DEF_PCD_SeleTypeA) //TYPE A
		} else {
			Pcd14443Info.TypeAB = byte(DEF_PCD_SeleTypeA) //TYPE A
		}

		if sno[0] > 10 { //序列号长度不能大于10
			return 1
		}

		Pcd14443Info.UID_Size = sno[0]
		copy(Pcd14443Info.UID, sno[1:1+Pcd14443Info.UID_Size])
		if oth[0] > 2 {
			ptr = 3
			lenth = int(oth[ptr])
			ptr += 1

			if ptr+lenth < len(oth) {
				copy(Pcd14443Info.ATQA, oth[ptr:ptr+2])
				//fmt.Printf("ATQA:%x\n", Pcd14443Info.ATQA)
			}
			ptr += lenth

			lenth = int(oth[ptr])
			ptr += 1

			if ptr+lenth < len(oth) {
				Pcd14443Info.SAK = oth[ptr]
			}
			ptr += lenth
			lenth = int(oth[ptr])
			if 'A' == tpe[0] && (ptr+lenth < len(oth)) {
				copy(Pcd14443Info.ATS, oth[ptr:ptr+lenth])
				Pcd14443Info.ATS_Size = byte(lenth)
			}
			//fmt.Println(Pcd14443Info)
			fmt.Printf("ATQA:%x\n", Pcd14443Info.ATQA)
			fmt.Printf("SAK:%x\n", Pcd14443Info.SAK)
			fmt.Printf("UID:%x\n", Pcd14443Info.UID)
		}
	} else {
		Pcd14443Info.ATQA[0] = 0
		Pcd14443Info.ATQA[1] = 0
		Pcd14443Info.ATQA[2] = 0
		Pcd14443Info.ATQA[3] = 0
	}

	return int(ret)
}

//ISO14443 A/B 检测卡片是否存在,卡片激活状态后调用
func ICC_PCD_CheckPICCRounge() int {
	ret := C.PiccRemove('C', C.uchar(PiccCid))
	//nc_iso14443_debug("PiccRemove('C').ret=%d\n", ret);
	if 0x06 == ret { //卡片仍在感应区
		//nc_iso14443_debug( "%s", "Card exist\n" );	//PiccRemove('C')停活卡片,需要重新寻卡以激活卡片
		return 0 //返回卡片仍在
	} else {
		//nc_iso14443_debug( "%s", "Card removed\n" );
		return 1 //返回卡片离开
	}

}

//ISO14443 A/B 检测PICC是否移出工作场
func ICC_PCD_CheckPICCrf() int {
	ret := C.PiccRemove('R', C.uchar(PiccCid))
	//nc_iso14443_debug("PiccRemove('C').ret=%d\n", ret);
	if 0x06 == ret { //卡片仍在感应区
		//nc_iso14443_debug( "%s", "Card exist\n" );	//PiccRemove('C')停活卡片,需要重新寻卡以激活卡片
		return 0 //返回卡片仍在
	} else {
		//nc_iso14443_debug( "%s", "Card removed\n" );
		return 1 //返回卡片离开
	}
}

//ISO14443 A/B 等待PICC移出工作场
func ICC_PCD_WaitPICCrf() int {

	for true {
		ret := C.PiccRemove('C', C.uchar(PiccCid))
		//nc_iso14443_debug("PiccRemove('C').ret=%d\n", ret);
		if 0x06 == ret {
			//nc_iso14443_debug( "%s", "Card exist\n" );
			continue //返回卡片仍在
		} else {
			//nc_iso14443_debug( "%s", "Card removed\n" );
			break //卡片移出
		}
	}
	return 0
}

//ISO14443 A/B 复位工作场
func ICC_PCD_ResetPCDrf() int {

	C.PiccClose()
	ret := C.PiccOpen()
	//nc_iso14443_debug("ICC_PCD_ResetPCDrf. ret = %d\n", ret);
	return int(ret)
}

func ICC_PCD_APDUCommand(in []byte, inlen int, out []byte, outlen *int, maxsize int, lc, le byte) int {

	var ApduSend C.APDU_SEND
	var ApduResp C.APDU_RESP

	ApduSend.Command[0] = C.uchar(in[0])
	ApduSend.Command[1] = C.uchar(in[1])
	ApduSend.Command[2] = C.uchar(in[2])
	ApduSend.Command[3] = C.uchar(in[3])
	ApduSend.Lc = C.ushort(lc)

	for i := 0; i < int(lc); i++ {
		ApduSend.DataIn[i] = C.uchar(in[5+i])
	}
	if le != 0 { //此处须填非0值,若le非0则填实际值,否则固定填256
		ApduSend.Le = C.ushort(le)
	} else {
		ApduSend.Le = 256
	}
	fmt.Printf("->APDU:%x\n", in[0:inlen])

	ret := C.PiccIsoCommand(C.uchar(PiccCid), &ApduSend, &ApduResp)
	if ret != 0 {
		return int(ret)
	}
	if (le != 0) && (byte(ApduResp.LenOut) != le) {

	}
	if int(ApduResp.LenOut+2) < maxsize { //还有两个字节的状态字节 SWA/SWB

		//memcpy( out, &ApduResp.DataOut[0], ApduResp.LenOut );
		for i := 0; i < int(ApduResp.LenOut); i++ {
			out[i] = byte(ApduResp.DataOut[i])
		}
		out[ApduResp.LenOut] = byte(ApduResp.SWA)
		out[ApduResp.LenOut+1] = byte(ApduResp.SWB)
	} else {
		//memcpy( out, &ApduResp.DataOut[0], maxsize-2 );
		for i := 0; i < maxsize-2; i++ {
			out[i] = byte(ApduResp.DataOut[i])
		}
		out[ApduResp.LenOut] = byte(ApduResp.SWA)
		out[ApduResp.LenOut+1] = byte(ApduResp.SWB)
	}

	*outlen = int(ApduResp.LenOut + 2)

	fmt.Printf("<-APDU:%x\n", out[0:ApduResp.LenOut+2])

	return 0
}
func main() {
	fmt.Println("Hello Go")

	ret := ICC_PCD_Init()
	if ret == 0 {
		fmt.Println("ICC PCD init ok!")
		ICC_PCD_SysCfg(DEF_PCD_SeleTypeA, 0, 1)
		for i := 0; i < 100; i++ {
			ret = ICC_PCD_Request(DEF_PCD_SeleTypeA)
			if ret == 0 {
				fmt.Println("find card ok!")
			} else {
				fmt.Println("not find card!")
			}
		}

	} else {
		fmt.Printf("ICC PCD init err!,code=%d\n", ret)
	}
	name := ""
	fmt.Println("over!press any key to continue: ")
	fmt.Scanln(&name)
}
package card

import (
	"encoding/hex"
	"fmt"
	"go8583/drivers"
	"math/rand"
	"time"
)

func ICF_GetChallenge8B(Rnd []byte, ich int) int {

	CmdBuffer[0] = 0x00 //CLA
	CmdBuffer[1] = 0x84 //INS
	CmdBuffer[2] = 0x00 //P1
	CmdBuffer[3] = 0x00 //P2
	CmdBuffer[4] = 0x08 //Le

	rcode := drivers.ICC_APDU_Exchange(ich, CmdBuffer, 5, RcvBuffer, &Grcv_Len, 260, 0, CmdBuffer[4])
	if rcode != 0 {
		fmt.Printf("ICC_APDU_Exchange err,code=%d\n", rcode)
		return rcode
	}
	if Grcv_Len < 2 {
		return 2
	}
	rcode = ((int(RcvBuffer[Grcv_Len-2]) << 8) | int(RcvBuffer[Grcv_Len-1]))
	if rcode != 0x9000 {
		return rcode
	}
	copy(Rnd, RcvBuffer[0:8])
	return rcode

}

func ICF_SelectAID(AID []byte, ilen int, ich int) int {

	CmdBuffer[0] = 0x00       //CLA
	CmdBuffer[1] = 0xA4       //INS
	CmdBuffer[2] = 0x04       //P1
	CmdBuffer[3] = 0x00       //P2
	CmdBuffer[4] = byte(ilen) //Lc

	copy(CmdBuffer[5:], AID[0:ilen])

	rcode := drivers.ICC_APDU_Exchange(ich, CmdBuffer, ilen+5, RcvBuffer, &Grcv_Len, 260, CmdBuffer[4], 0)
	if rcode != 0 {
		fmt.Printf("ICC_APDU_Exchange err,code=%d\n", rcode)
		return rcode
	}
	if Grcv_Len < 2 {
		return 2
	}
	rcode = ((int(RcvBuffer[Grcv_Len-2]) << 8) | int(RcvBuffer[Grcv_Len-1]))
	if rcode != 0x9000 {
		return rcode
	}

	return rcode

}

//{9f38 18 9f66049f02069f03069f1a0295055f2a029a039c019f3704}
func UP_GPO(pdoc []byte, lenth byte, ich int) int {

	CmdBuffer[0] = 0x80      //CLA
	CmdBuffer[1] = 0xA8      //INS
	CmdBuffer[2] = 0x00      //P1
	CmdBuffer[3] = 0x00      //P2	‘01’用于ED(电子存折,需要个人密码PIN ‘02’用于EP(电子钱包)
	CmdBuffer[4] = lenth + 2 //Lc
	CmdBuffer[5] = 0x83
	CmdBuffer[6] = lenth

	copy(CmdBuffer[7:], pdoc[0:lenth])

	rcode := drivers.ICC_APDU_Exchange(ich, CmdBuffer, int(lenth+8), RcvBuffer, &Grcv_Len, 260, CmdBuffer[4], 0)
	if rcode != 0 {
		fmt.Printf("ICC_APDU_Exchange err,code=%d\n", rcode)
		return rcode
	}
	if Grcv_Len < 2 {
		return 2
	}
	rcode = ((int(RcvBuffer[Grcv_Len-2]) << 8) | int(RcvBuffer[Grcv_Len-1]))
	if rcode != 0x9000 {
		return rcode
	}

	return rcode

}

/*
*双免GPO组包
 */
//{9f38 18 9f66049f02069f03069f1a0295055f2a029a039c019f3704}
func UP_qUICS(money int, opdt string, ich int) int {

	t9F66 := "........"                  //交易属性
	t9F02 := fmt.Sprintf("%012d", money) //授权金额
	t9F03 := "000000000000"
	t9F1A := "0156"
	t95 := "0000000000"
	t5F2A := "0156"
	t9A := opdt
	t9C := "00"
	rand.Seed(time.Now().Unix())
	t9F37 := fmt.Sprintf("%08x", rand.Int31())
	pdoc := t9F66 + t9F02 + t9F03 + t9F1A + t95 + t5F2A + t9A + t9C + t9F37

	fmt.Printf("pdoc:%s\n", pdoc)
	bpdoc, err := hex.DecodeString(pdoc)
	if err != nil {
		fmt.Printf("DecodeString error:%s\n", err.Error())
	}
	fmt.Printf("bpdoc:%x\n", bpdoc)

	return UP_GPO(bpdoc, byte(len(bpdoc)), ich)

}

root@b503_lcd:/app/city_app/opt# ./cardlib
Hello Go
ATQA:08000000
SAK:20
UID:5deaa62a000000000000000000000000
find card ok!

ATQA:04000000
SAK:28
UID:2f7bb136000000000000000000000000
find card ok!
->APDU:00a404000e325041592e5359532e4444463031
<-APDU:6f30840e325041592e5359532e4444463031a51ebf0c1b61194f08a000000333010101500a50424f432044454249548701019000
ICF_SelectAID ok!
[{6f 30 840e325041592e5359532e4444463031a51ebf0c1b61194f08a000000333010101500a50424f43204445424954870101} {84 0e 325041592e5359532e4444463031} {a5 1e bf0c1b61194f08a000000333010101500a50424f43204445424954870101} {bf0c 1b 61194f08a000000333010101500a50424f43204445424954870101} {61 19 4f08a000000333010101500a50424f43204445424954870101} {4f 08 a000000333010101} {50 0a 50424f43204445424954} {87 01 01}]

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

特立独行的猫a

您的鼓励是我的创作动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值