嵌入式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 = 1DEF_PCD_SeleTypeB int = 2 )type __Pcd14443Cfg struct {PPS int //AB 0:標準的支持PPS,非0:強制不支持PPSM1CPU 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 byteRvs16bit byteATS []byte //A專用 ATS接收數據緩沖區 按中國金融規定 PICC回的數據最長為21字節ATQB []byte //B專用 卡片應答數據} //14443應用數據結構var (Pcd14443CfgMode int = DEF_PCD_SeleTypeA //PCD選擇TypeA卡 操作PICC類型定義Pcd14443CfgA __Pcd14443CfgPcd14443CfgB __Pcd14443CfgPcd14443Info __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 = modeif DEF_PCD_SeleTypeA == Pcd14443CfgMode {Pcd14443CfgA.PPS = ppsPcd14443CfgA.M1CPU = m1} else if DEF_PCD_SeleTypeB == Pcd14443CfgMode {Pcd14443CfgB.PPS = ppsPcd14443CfgB.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(¶[0]))cardType := (*C.uchar)(unsafe.Pointer(&tpe[0]))rfPara := (*C.uchar)(unsafe.Pointer(¶[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 := 0ptr := 0ret := 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 { //強制M1ret = C.PiccDetect('M', cardType, serialNo, piccid, other)} else if DEF_PCD_SeleTypeB == Pcd14443CfgA.M1CPU { //強制CPUAret = C.PiccDetect('A', cardType, serialNo, piccid, other)} else if 3 == Pcd14443CfgA.M1CPU { //自動檢測A,B,無法檢測到純M1 操作一次28msret = C.PiccDetect(0x01, cardType, serialNo, piccid, other)} else { //自動CPUA/M1 操作一次18msret = C.PiccDetect('X', cardType, serialNo, piccid, other)}// printf(">>>>>>>>>>>>PiccDetect, ret=%d count=%d\n", ret, count++);} else if DEF_PCD_SeleTypeB == Pcd14443CfgMode { //強制CPUBret = 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 { //序列號長度不能大于10return 1}Pcd14443Info.UID_Size = sno[0]copy(Pcd14443Info.UID, sno[1:1+Pcd14443Info.UID_Size])if oth[0] > 2 {ptr = 3lenth = int(oth[ptr])ptr += 1if ptr+lenth < len(oth) {copy(Pcd14443Info.ATQA, oth[ptr:ptr+2])//fmt.Printf("ATQA:%x\n", Pcd14443Info.ATQA)}ptr += lenthlenth = int(oth[ptr])ptr += 1if ptr+lenth < len(oth) {Pcd14443Info.SAK = oth[ptr]}ptr += lenthlenth = 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] = 0Pcd14443Info.ATQA[1] = 0Pcd14443Info.ATQA[2] = 0Pcd14443Info.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_SENDvar ApduResp C.APDU_RESPApduSend.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則填實際值,否則固定填256ApduSend.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 cardimport ("encoding/hex""fmt""go8583/drivers""math/rand""time" )func ICF_GetChallenge8B(Rnd []byte, ich int) int {CmdBuffer[0] = 0x00 //CLACmdBuffer[1] = 0x84 //INSCmdBuffer[2] = 0x00 //P1CmdBuffer[3] = 0x00 //P2CmdBuffer[4] = 0x08 //Lercode := 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 //CLACmdBuffer[1] = 0xA4 //INSCmdBuffer[2] = 0x04 //P1CmdBuffer[3] = 0x00 //P2CmdBuffer[4] = byte(ilen) //Lccopy(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 //CLACmdBuffer[1] = 0xA8 //INSCmdBuffer[2] = 0x00 //P1CmdBuffer[3] = 0x00 //P2 ‘01’用于ED(電子存折,需要個人密碼PIN ‘02’用于EP(電子錢包)CmdBuffer[4] = lenth + 2 //LcCmdBuffer[5] = 0x83CmdBuffer[6] = lenthcopy(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 := opdtt9C := "00"rand.Seed(time.Now().Unix())t9F37 := fmt.Sprintf("%08x", rand.Int31())pdoc := t9F66 + t9F02 + t9F03 + t9F1A + t95 + t5F2A + t9A + t9C + t9F37fmt.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}]
?
總結
以上是生活随笔為你收集整理的嵌入式linux之go语言开发(三)卡库的封装的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 发送手机验证码,验证手机验证码,包括数据
- 下一篇: 【人工智能】新一代人工智能发展白皮书