【湖南步联科技身份证】 身份证读取与酒店收银系统源码整合———未来之窗行业应用跨平台架构

news2024/11/16 16:01:21

 一、html5

<!DOCTYPE html>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
     <script type="text/javascript" src="http://51.onelink.ynwlzc.net/o2o/tpl/Merchant/static/js/jquery.min.js"></script>
       
        <style type="text/css">
            html {
                height: 100%;
                width: 100%;
            }
            #readCard {
                width: 90px;
                margin: 10px;
            }
            #output {
                width: 500px;
                height: 200px;
            }
        </style>
    </head>
    <body>
       <h1>读身份证示例-湖南步联科技身份证
</h1> <h1>未来之窗星链-推进器测试
</h1><br>
        
        <input type="button" id="getReader" value="列出设备" style="margin:10px" onclick="getReader();" />
        <select id="readerList" style="width:250px;margin:10px"></select>
        <!-- 读卡参数<input type="text" id="readParam" value='{"portType": 5}' size="25" style="margin:10px" > -->


        <br/>
        <input type="button" id="readCard" value="读卡" onclick="startReadCard();" />
        <input type="checkbox" id="autoReadCard" value="autoRead"  >自动读卡
        <br>
        阅读次数:<input type="text" id="totalReadCount" name="Num" value="100" size="7">
        成功次数<input type="text" id="SuccessTimes" value="0" size="7">
        失败次数<input type="text" id="FailTimes" value="0" size="7">
        所用时间<input type="text" id="TimeExpand" value="0" size="7">
        成功率<input type="text" id="Rate" value="0%" size="5">
        平均耗时<input type="text" id="AvgTime" value="0" size="5">

        <br>
            开始时间<input type="text" id="StartTime" value="" size="25">
            完成时间<input type="text" id="EndTime" value="" size="25">
            单次用时<input type="text" id="ReadTime" value="111" size="25">
            
        


        <table border="1" cellpadding="0" cellspacing="2" bordercolor="#3333FF">
            <tr>
                <td><div align="right">姓名:</div></td>
                <td><input name="text_name" type="text" id="text_name" size="20"/></td>
                <td><div align="right">性别代码:</div></td>
                <td><input name="text_genderid" type="text" id="text_genderid" size="5"/></td>
                <td><div align="right">民族代码:</div></td>
                <td><input name="text_nationid" type="text" id="text_nationid" size="5"/></td>
                <td><div align="right">出生日期:</div></td>
                <td><input name="text_birthdate" type="text" id="text_birthdate" size="20"/></td>
            </tr>
            <tr>
                <td><div align="right">身份证号码:</div></td>
                <td><input name="text_idnumber" type="text" id="text_idnumber" size="20"/></td>
                <td><div align="right">签发机关:</div></td>
                <td><input name="text_signorgan" type="text" id="text_signorgan" size="20"/></td>
                <td><div align="right">起始有效期:</div></td>
                <td><input name="text_beginterm" type="text" id="text_beginterm" size="20"/></td>
                <td><div align="right">终止有效期:</div></td>
                <td><input name="text_endterm" type="text" id="text_endterm" size="20"/></td>
            </tr>
            <tr>
                <td><div align="right">住址:</div></td>
                <td colspan="5"><input name="text_address" type="text" id="text_address" size="82"/>
                </td>
                <td><div align="right">民族:</div></td>
                <td><input name="text_nationid" type="text" id="text_nation" size="5"/></td>

            </tr>
            <tr>
                <td height="43">
                    <div align="right">照片编码:</div>
                </td>
                <td colspan="7"><textarea name="text_photobase64" cols="80" rows="5" id="text_photobase64"></textarea></td>
                <td><img name="PhotoDisplay" id="PhotoDisplay" style="width:102px; height:126px;"/></td>
            </tr>
        </table>
        <br/>
		<textarea id="output"></textarea><br/>
    </body>
</html>


<script type="text/javascript" >

var baseUrl = "http://127.0.0.1:6045"
$(document).ready(function(){
     //解决IE浏览器不支持console,报错未定义问题
     window.console = window.console || (function () {
        var c ={};
        c.log = c.warn = c.debug = c.info = c.error = c.time = c.dir = c.profile= c.clear = c.exception = c.trace = c.assert = function(){};
        return c;
    })();
//    alert(location.host)
//    if(location.host){
//        baseUrl = location.protocol + "//" + location.host;
//    }
    console.log("baseurl "+ baseUrl);
    
});

function fixInt(val){
    if(val<10)
      return "0"+val;
     else
      return val;
}


function fmtDate(date){
    return date.getFullYear()+"-"+fixInt(date.getMonth()+1)+"-"+fixInt(date.getDate())+" "+fixInt(date.getHours())+":"+fixInt(date.getMinutes())+":"+fixInt(date.getSeconds())+":"+fixInt(date.getMilliseconds());
}

function clearForm() {
    $("#output").text("");
    $("#text_name").val("");
    $("#text_genderid").val("");
    $("#text_nationid").val("");
    $("#text_birthdate").val("");
    $("#text_address").val("");
    $("#text_idnumber").val("");
    $("#text_signorgan").val("");
    $("#text_beginterm").val("");
    $("#text_endterm").val("");
    
}

function getReader(){


    $.ajax({
		type: "get",
		dataType: "json", 
        timeout:10000,
        crossDomain: true,

        url: baseUrl + "/getCardReaderList",
        success: function(resultInfo) {
            $("#output").text(JSON.stringify(resultInfo));
            var list = document.getElementById("readerList");
            for(var i = list.options.length-1; i >= 0; i--){
                list.remove(i);
            }
            var strArray = resultInfo;
            for(var i = 0; i < resultInfo.length; i++){
                var newOption = document.createElement("option");
                newOption.setAttribute("version", strArray[i].version);
                newOption.setAttribute("index", strArray[i].index);
                newOption.appendChild(document.createTextNode(strArray[i].version));
                list.appendChild(newOption);
            }
        },
        error: function(jqXHR, textStatus, errorThrown) {
            console.error("getReader request error  ", textStatus, errorThrown );
            $("#output").text("getReader error status "+ textStatus+" errorThrown "  +errorThrown)
        }
    });
}
function parseCardWzxx(wzxx) {
  var result = {};

  result['xm'] = wzxx.substr(0, 15);
  result['xbdm'] = wzxx.substr(15, 1);
  result['mzdm'] = wzxx.substr(16, 2);
  result['csrq'] = wzxx.substr(18, 8);
  result['dzmc'] = wzxx.substr(26, 35);
  result['gmsfhm'] = wzxx.substr(61, 18);
  result['qfjgmc'] = wzxx.substr(79, 15);
  result['qfjgmc'] = wzxx.substr(79, 15);
  result['yxqqsrq'] = wzxx.substr(94, 8);
  result['yxqjzrq'] = wzxx.substr(102, 8);
  result['zjlxbs'] = wzxx.substr(124, 1);

  switch (result['xbdm']) {
    case '1': result['xbmc'] = '男'; break;
    case '2': result['xbmc'] = '女'; break;
    default: result['xbmc'] = '未知';
  }

  if (result['zjlxbs'] == 'J'){
    result['txzhm'] = wzxx.substr(110, 9);
    result['qfcs'] = wzxx.substr(119, 2);
  }

  switch (result['mzdm']) {
    case '01': result['mzmc'] = '汉'; break;
    case '02': result['mzmc'] = '蒙古'; break;
    case '03': result['mzmc'] = '回'; break;
    case '04': result['mzmc'] = '藏'; break;
    case '05': result['mzmc'] = '维吾尔'; break;
    case '06': result['mzmc'] = '苗'; break;
    case '07': result['mzmc'] = '彝'; break;
    case '08': result['mzmc'] = '壮'; break;
    case '09': result['mzmc'] = '布依'; break;
    case '10': result['mzmc'] = '朝鲜'; break;
    case '11': result['mzmc'] = '满'; break;
    case '12': result['mzmc'] = '侗'; break;
    case '13': result['mzmc'] = '瑶'; break;
    case '14': result['mzmc'] = '白'; break;
    case '15': result['mzmc'] = '土家'; break;
    case '16': result['mzmc'] = '哈尼'; break;
    case '17': result['mzmc'] = '哈萨克'; break;
    case '18': result['mzmc'] = '傣'; break;
    case '19': result['mzmc'] = '黎'; break;
    case '20': result['mzmc'] = '傈僳'; break;
    case '21': result['mzmc'] = '佤'; break;
    case '22': result['mzmc'] = '畲'; break;
    case '23': result['mzmc'] = '高山'; break;
    case '24': result['mzmc'] = '拉祜'; break;
    case '25': result['mzmc'] = '水'; break;
    case '26': result['mzmc'] = '东乡'; break;
    case '27': result['mzmc'] = '纳西'; break;
    case '28': result['mzmc'] = '景颇'; break;
    case '29': result['mzmc'] = '柯尔克孜'; break;
    case '30': result['mzmc'] = '土'; break;
    case '31': result['mzmc'] = '达翰尔'; break;
    case '32': result['mzmc'] = '仫佬'; break;
    case '33': result['mzmc'] = '羌'; break;
    case '34': result['mzmc'] = '布朗'; break;
    case '35': result['mzmc'] = '撒拉'; break;
    case '36': result['mzmc'] = '毛南'; break;
    case '37': result['mzmc'] = '仡佬'; break;
    case '38': result['mzmc'] = '锡伯'; break;
    case '39': result['mzmc'] = '阿昌'; break;
    case '40': result['mzmc'] = '普米'; break;
    case '41': result['mzmc'] = '塔吉克'; break;
    case '42': result['mzmc'] = '怒'; break;
    case '43': result['mzmc'] = '乌孜别克'; break;
    case '44': result['mzmc'] = '俄罗斯'; break;
    case '45': result['mzmc'] = '鄂温克'; break;
    case '46': result['mzmc'] = '德昂'; break;
    case '47': result['mzmc'] = '保安'; break;
    case '48': result['mzmc'] = '裕固'; break;
    case '49': result['mzmc'] = '京'; break;
    case '50': result['mzmc'] = '塔塔尔'; break;
    case '51': result['mzmc'] = '独龙'; break;
    case '52': result['mzmc'] = '鄂伦春'; break;
    case '53': result['mzmc'] = '赫哲'; break;
    case '54': result['mzmc'] = '门巴'; break;
    case '55': result['mzmc'] = '珞巴'; break;
    case '56': result['mzmc'] = '基诺'; break;
    case '59': result['mzmc'] = '穿青人'; break;
    case '60': result['mzmc'] = '革家人'; break;
    case '97': result['mzmc'] = '其它'; break;
    case '98': result['mzmc'] = '入籍'; break;
    case '99': result['mzmc'] = '其它'; break;
    default: result['mzmc'] = '';
  }
  return result;
}
var totalStartTime;
var totalReadCount;
var SuccessTimes = 0;
var FailTimes = 0;
var totalUsedTime = 0;
function startReadCard(){
    totalStartTime = new Date();
    totalReadCount = $("#totalReadCount").val();
    SuccessTimes = 0;
    FailTimes = 0;
    totalUsedTime = 0;
    readCard();
}

function readCard(){   
    clearForm();
    var startTime = new Date();
    $("#StartTime").val(fmtDate(startTime));
    $("#readCard").attr("disabled", "disabled");
    var readerIndex = $("#readerList").find("option:selected").attr("index");
    console.info("read card", readerIndex)

    $.ajax({
		type: "get",
		dataType: "json", 
        timeout:10000,
        url: baseUrl + "/readIDCard?index="+readerIndex,
        success: function(resultInfo) {
            console.info("readIDCard ", resultInfo, status);
            $("#output").text(JSON.stringify(resultInfo));
            if( resultInfo.result === 0 ){
                var textInfo = resultInfo.wzInfo;

                $("#text_name").val(textInfo.substr(0,15).trim());
                $("#text_genderid").val(textInfo.substr(15,1).trim());
                $("#text_nationid").val(textInfo.substr(16,2).trim());
                $("#text_birthdate").val(textInfo.substr(18,8).trim());
                $("#text_address").val(textInfo.substr(26,35).trim());
                $("#text_idnumber").val(textInfo.substr(61,18).trim());
                $("#text_signorgan").val(textInfo.substr(79,15).trim());
                $("#text_beginterm").val(textInfo.substr(94,8).trim());
                $("#text_endterm").val(textInfo.substr(102,8).trim());

                var wzObj = parseCardWzxx(textInfo);
                $("#text_nation").val(wzObj.mzmc);

                console.info("read card success", wzObj) ;

                $.ajax({
					type: "get",
					dataType: "json", 
					timeout:10000,
                    url:baseUrl +"/wltUnpack?wlt="+resultInfo.zpWlt+"&format=bmp",
                    success:function(response){
                        if(response['result'] === 0){
                            var imageBase64 = response['image'];
                            $("#text_photobase64").val(imageBase64);
                            document.all['PhotoDisplay'].src = 'data:image/bmp;base64,' + imageBase64;
                        }else{
                          alert("unpack error " + response['result']);
                        }
                    },
                    complete: function(XMLHttpRequest, textStatus) {
                    }
                });
            } 
            var endTime = new Date();
            $("#EndTime").val(fmtDate(endTime));
            var usedTime = endTime.getTime()-startTime.getTime();
            $("#ReadTime").val(usedTime + "ms");
            
            if ( $('#autoReadCard').is(":checked") && totalReadCount--> 0){
                self.setTimeout("readCard()", 1000);
                totalUsedTime +=  usedTime;
                $("#TimeExpand").val(totalUsedTime + "ms");
                if(resultInfo.result == 0){
                    ++SuccessTimes; 
                }else{
                    ++FailTimes;
                }
                $("#SuccessTimes").val(SuccessTimes);
                $("#FailTimes").val(FailTimes);
                $("#Rate").val(SuccessTimes*100/(SuccessTimes+FailTimes) + "%");
                $("#AvgTime").val(totalUsedTime/(SuccessTimes+FailTimes) + "ms");

            }else{
                $("#readCard").removeAttr("disabled");
            }

        },
        complete: function(XMLHttpRequest, textStatus) {
//            alert("cloudReadCard/appId complete");
            console.info("complete");
        },
        error: function(jqXHR, textStatus, errorThrown) {
            console.error("read card request error  ", textStatus, errorThrown );
            $("#output").text("read card error status "+ textStatus+" errorThrown "  +errorThrown)
            $("#readCard").removeAttr("disabled");

        }
    });
}


</script>

二、JAVA

import com.bland.IDReader;
import org.json.JSONArray;
import org.json.JSONObject;
import java.util.Base64;

import java.io.*;

public class demo{
	
    static public String race_table[][] ={
        {"01","汉族"},//   GB/T 3304-1991","Han","HA
        {"02","蒙古族"},//   GB/T 3304-1991","Mongol","MG
        {"03","回族"},//   GB/T 3304-1991","Hui","HU
        {"04","藏族"},//   GB/T 3304-1991","Zang","ZA
        {"05","维吾尔族"},//   GB/T 3304-1991","Uygur","uG
        {"06","苗族"},//   GB/T 3304-1991","Miao","MH
        {"07","彝族"},//   GB/T 3304-1991","Yi","YI
        {"08","壮族"},//   GB/T 3304-1991","Zhuang","ZH
        {"09","布依族"},//   GB/T 3304-1991","Buyei","BY
        {"10","朝鲜族"},//   GB/T 3304-1991","Chosen","cs
        {"11","满族"},//   GB/T 3304-1991","Man","MA
        {"12","侗族"},//   GB/T 3304-1991","Dong","DO
        {"13","瑶族"},//   GB/T 3304-1991","Yao","YA
        {"14","白族"},//   GB/T 3304-1991","Bai","BA
        {"15","土家族"},//   GB/T 3304-1991","Tujia","TJ
        {"16","哈尼族"},//   GB/T 3304-1991","Hani","HN
        {"17","哈萨克族"},//   GB/T 3304-1991","Kazak","KZ
        {"18","傣族"},//   GB/T 3304-1991","Dai","DA
        {"19","黎族"},//   GB/T 3304-1991","Li","LI
        {"20","傈僳族"},//   GB/T 3304-1991","Lisu","LS
        {"21","佤族"},//   GB/T 3304-1991","Va","VA
        {"22","畲族"},//   GB/T 3304-1991","She","SH
        {"23","高山族"},//   GB/T 3304-1991","Gaoshan","Gs
        {"24","拉枯族"},//   GB/T 3304-1991","Lahu","LH
        {"25","水族"},//   GB/T 3304-1991","Sui","su
        {"26","东乡族"},//   GB/T 3304-1991","Dongxiang","DX
        {"27","纳西族"},//   GB/T 3304-1991","Naxi","NX
        {"28","景颇族"},//   GB/T 3304-1991","Jingpo","JP
        {"29","柯尔克孜族"},//   GB/T 3304-1991","Kirgiz","KG
        {"30","土族"},//   GB/T 3304-1991","Tu","TU
        {"31","达斡尔族"},//   GB/T 3304-1991","Daur","DU
        {"32","仫佬族"},//   GB/T 3304-1991","Mulao","ML
        {"33","羌族"},//   GB/T 3304-1991","Qiang","QI
        {"34","布朗族"},//   GB/T 3304-1991","Blang","BL
        {"35","撒拉族"},//   GB/T 3304-1991","Salar","SL
        {"36","毛南族"},//   GB/T 3304-1991","Maonan","MN
        {"37","仡佬族"},//   GB/T 3304-1991","Gelao","GL
        {"38","锡伯族"},//   GB/T 3304-1991","Xibe","XB
        {"39","阿昌族"},//   GB/T 3304-1991","Achang","AC
        {"40","普米族"},//   GB/T 3304-1991","Pumi","PM
        {"41","塔吉克族"},//   GB/T 3304-1991","Tajik","TA
        {"42","怒族"},//   GB/T 3304-1991","Nu","NU
        {"43","乌孜别克族"},//   GB/T 3304-1991","Uzbek","Uz
        {"44","俄罗斯族"},//   GB/T 3304-1991","Russ","RS
        {"45","鄂温克族"},//   GB/T 3304-1991","Ewenki","EW
        {"46","德昂族"},//   GB/T 3304-1991","Deang","DE
        {"47","保安族"},//   GB/T 3304-1991","Bonan","BN
        {"48","裕固族"},//   GB/T 3304-1991","Yugur","YG
        {"49","京族"},//   GB/T 3304-1991","Gin","GI
        {"50","塔塔尔族"},//   GB/T 3304-1991","Tatar","TT
        {"51","独龙族"},//   GB/T 3304-1991","Derung","DR
        {"52","鄂伦春族"},//   GB/T 3304-1991","Oroqen","OR
        {"53","赫哲族"},//   GB/T 3304-1991","Hezhen","HZ
        {"54","门巴族"},//   GB/T 3304-1991","Monba","MB
        {"55","珞巴族"},//   GB/T 3304-1991","Lhoba","LB
        {"56","基诺族"},//   GB/T 3304-1991","Jino","JN
        {"",""}
    };

    /**
     * 将民族代码,转换成文本
     * @param code
     * @return
     */
    public static String GetRace(String code) {
        int i;
        for (i = 0; i < race_table.length; i++) {
            if (race_table[i][0].compareTo(code) == 0) {
                return race_table[i][1];
            }
        }
        return "其它";
    }

    /**
     * 显示身份证信息
     * @param text 文本
     * @param image 照片
     */
    public static void ViewInfo(String text,byte[] image) {
        System.out.println(text);
		try
		{
			File imgFile = new File("image.jpg"); 
			FileOutputStream writer = new FileOutputStream(imgFile); 
			writer.write(image); 
			writer.close(); 
		}
		catch (Exception e)
		{
			e.printStackTrace(); 
		}
    }


    /**
     * 解析SN
     * @param str JSON 格式字符串
     * @return 返回错误或成功信息
     */
    public static int ParseSN(String str) {
        byte[] img;
        String info = "";

        try {
            JSONObject jsondata = new JSONObject(str);

            if(jsondata.has("errorMsg")) {
				//System.out.println(jsondata.getString("errorMsg"));
                return -1;
            }

            if( !jsondata.has("data") ) {
                return -1;
            }

            JSONObject content = jsondata.getJSONObject("data");

			System.out.println("SAM ID: " + content.getString("samid"));
			if(content.has("sn")) {
				System.out.println("SN: " + content.getString("sn"));
			}
		}
		catch (Exception e) {
			e.printStackTrace(); 
            return -1;
        }
		return 0;
	}

    /**
     * 解析身份证读卡结果
     * @param str JSON 格式字符串
     * @return 返回错误或成功信息
     */
    public static String ParseIDInfo(String str) {
        byte[] img;
        String info = "";

        try {
            JSONObject jsondata = new JSONObject(str);

            if(jsondata.getString("function").compareTo("readcard") != 0) {
                return "";//不是读卡消息,直接返回
            }

            if(jsondata.has("errorMsg")) {
				System.out.println(jsondata.getString("errorMsg"));
                return jsondata.getString("errorMsg");
            }

            if( !jsondata.has("data") ) {
                return "";
            }

            JSONObject content = jsondata.getJSONObject("data");

			if(content.getString("type").compareTo("I") == 0) { 
				info = "外国人永久居留证";
			}
			else if(content.getString("type").compareTo("J") == 0) { 
				info = "港澳台居住证";
			}
			else if(content.getString("type").compareTo(" ") == 0) { 
				info = "居民身份证";
			}
			else  {
				info = "未知";
			}

            info = info + "\r\n姓名:" + content.getString("name");
            info = info + "\r\n身份证号:" + content.getString("number");
            String gender;
            if(content.getInt("gender") == 1) {
                gender = "男";
            }
            else if (content.getInt("gender") == 2){
                gender = "女";
            }
            else {
                gender = "未知";
            }
            info = info + "\r\n性别: " + gender;
			
			if(content.getString("type").compareTo(" ") == 0) { 
				//只有身份证有民族信息
	            info = info + "\r\n民族: " + GetRace(content.getString("race"));
			}

            info = info + "\r\n生日: " + content.getString("birthday");

			if(content.getString("type").compareTo("I") != 0 ) { 
				//外国人永久居留证没有住址信息
	            info = info + "\r\n住址: " + content.getString("address");
			}

            info = info + "\r\n签发机关: " + content.getString("issuer");
            info = info + "\r\n有效期限: " + content.getString("valied") + "-" + content.getString("expire");
			
			if(content.getString("type").compareTo("I") == 0) { 
				//外国人永久居留证
	            info = info + "\r\n中文名称: " + content.getString("cn_name");
				info = info + "\r\n版本: " + content.getString("version");
				info = info + "\r\n国籍: " + content.getString("nation");
			}
			else if(content.getString("type").compareTo("J") == 0) { 
				//港澳台居住证
	            info = info + "\r\n通行证号码: " + content.getString("pass_number");
				info = info + "\r\n签发次数: " + content.getString("issue_count");
			}

			info = info + "\r\n";

            img = Base64.getDecoder().decode(content.getString("photo"));
			ViewInfo(info,img);
            return "读卡成功!";
        }
        catch (Exception e) {
			e.printStackTrace(); 
            return e.getMessage();
        }

    }

    /**
     * 解析银行卡读卡结果
     * @param str JSON 格式字符串
     * @return 返回错误或成功信息
     */
    public static String ParseBankInfo(String str) {
        byte[] img;
        String info = "";

        try {
            JSONObject jsondata = new JSONObject(str);

            if(jsondata.has("errorMsg")) {
				System.out.println(jsondata.getString("errorMsg"));
                return jsondata.getString("errorMsg");
            }

            if( !jsondata.has("data") ) {
                return "";
            }

            JSONObject content = jsondata.getJSONObject("data");


            info = info + "\r\n银行卡号:" + content.getString("number");
            info = info + "\r\n有效期截止: " + content.getString("expire");
			
            info = info + "\r\n持卡人:" + content.getString("owner");
            info = info + "\r\n持卡人证件号码: " + content.getString("owner_id");

			info = info + "\r\n";
			
			System.out.println(info);

            return "读卡成功!";
        }
        catch (Exception e) {
			e.printStackTrace(); 
            return e.getMessage();
        }

	}

    /**
     * 解析读卡结果的返回值
     * @param str JSON 格式字符串
     * @return 返回读卡结果的返回值
     */
	public static int GetRetValue(String str) {
        try {
            JSONObject jsondata = new JSONObject(str);
			if(jsondata.has("ret")) {
				return jsondata.getInt("ret");
			}
			else {
				return -1;
			}
		}
        catch (Exception e) {
			e.printStackTrace(); 
            return -1;
        }
	}

	public static void main(String [] args) {
		String systemType = System.getProperty("os.name");   
		String systemArch = System.getProperty("os.arch");   

		IDReader reader = new IDReader();

		System.out.println("System Type: " + systemType + ", " + systemArch);

		//提供一个可读写的目录,用于初始化过程中读写配置,解压调用库文件。初始化只能调用一次。

		reader.Init("./res");
		System.out.println("demo start!");

		try
		{
			while(true) {
				Thread.sleep(100);
				String result = reader.WebSocketAPI("{\"module\":\"idcard\",\"msgid\":\"0\",\"function\":\"getsam\"}");
				if(ParseSN(result) == 0) {
					break;
				}
			}
		}
		catch (Exception e)
		{
			e.printStackTrace(); 
		}

		try
		{

			while(true) {
				String result;

				result = reader.WebSocketAPI("{\"module\":\"idcard\",\"msgid\":\"0\",\"function\":\"readcard\"}");
				if( GetRetValue(result) == 0) {
					ParseIDInfo(result);
					Thread.sleep(1000);
					continue;
				}

				result = reader.WebSocketAPI("{\"module\":\"iccard\",\"msgid\":\"0\",\"function\":\"iso14443a_find\"}");
				if( GetRetValue(result) == 0) {
					//读银行卡号码
					result = reader.WebSocketAPI("{\"module\":\"iccard\",\"msgid\":\"0\",\"function\":\"pboc_read\"}");
					ParseBankInfo(result);
					Thread.sleep(1000);
					continue;
				}
				Thread.sleep(100);
			}
		}
		catch (Exception e)
		{
			e.printStackTrace(); 
		}

		
	}
}

三、PYTHON

# -*- coding: utf-8 -*-
# import urllib2
import urllib.request
import json
import time

race = ["","汉族","蒙古族","回族","藏族","维吾尔族","苗族","彝族","壮族","布依族","朝鲜族","满族","侗族","瑶族","白族","土家族","哈尼族","哈萨克族","傣族","黎族","傈僳族","佤族","畲族","高山族","拉枯族","水族","东乡族","纳西族","景颇族","柯尔克孜族","土族","达斡尔族","仫佬族","羌族","布朗族","撒拉族","毛南族","仡佬族","锡伯族","阿昌族","普米族","塔吉克族","怒族","乌孜别克族","俄罗斯族","鄂温克族","德昂族","保安族","裕固族","京族","塔塔尔族","独龙族","鄂伦春族","赫哲族","门巴族","珞巴族" ,"基诺族"]
gender = ["未知","男","女","其他"]


while 1:
    time.sleep(1)
    url = "http://127.0.0.1:7846/api/readCard?utf8=1"

    response = urllib.request.urlopen(url)
    page_html = response.read()
    #print(page_html)

    result = json.loads(page_html)

    if result["resultFlag"] == "0":
        print("读卡成功:\n")
        print("身份证号码:"+result["resultContent"]["idNum"])
        print("姓名:"+result["resultContent"]["name"])
        print("性别:"+gender[int(result["resultContent"]["gender"])])
        print("民族:"+race[int(result["resultContent"]["nation"])])
        print("地址:"+result["resultContent"]["address"])
        print("生日:"+result["resultContent"]["birthday"])
        print("有效期: "+result["resultContent"]["effectDate"] + "-" + result["resultContent"]["expireDate"] )
        print("签发机关: "+result["resultContent"]["issueOrg"])
        continue

    url = "http://127.0.0.1:7846/readBankCard"
    response = urllib.request.urlopen(url)
    page_html = response.read()
    #print(page_html)

    result = json.loads(page_html)
    if result["result"] == 0 :
        print("读卡成功:\n")
        print("银行卡号码:"+result["number"])
        print("有效期截止:"+result["expire"])
        print("持卡人:"+result["owner"])
        print("持卡人证件号码:"+result["owner_id"])

    

四、VB

Public Class Form1
	Dim port As reader_serviceLib.sdt = New reader_serviceLib.sdt()
	Dim card As reader_serviceLib.card

	Private Sub refreshButton()
		Dim ret As Integer

		ret = port.opened()

		If ret = 0 Then
			btOpen.Enabled = True
			btReadCard.Enabled = False
			btReadBank.Enabled = False
			btOpen.Text = "打开"
		Else
			btOpen.Enabled = True
			btReadCard.Enabled = True
			btReadBank.Enabled = True
			btOpen.Text = "关闭"
			If ret > 1000 Then
				TextStatus.Text = "已打开USB端口" & ret
			Else
				TextStatus.Text = "已打开串口COM" & ret
			End If
			TextSAMID.Text = port.samid()
		End If

	End Sub


	Private Sub btReadCard_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btReadCard.Click
		Dim ret As Integer


		ret = port.find()
		If ret <> &H9F Then
			TextStatus.Text = "找卡失败!"
			Exit Sub
		End If

		ret = port.select()
		If ret <> &H90 Then
			TextStatus.Text = "选卡失败!"
			Exit Sub
		End If

		TextCardSN.Text = port.cardSN(0)

		card = port.readcard(0)
		If card.name = "" Then
			TextStatus.Text = "读卡失败!"
			Exit Sub
		End If

		TextName.Text = card.name
		TextAddress.Text = card.address
		TextBirthday.Text = card.birthday
		TextGender.Text = card.gender
		TextIssuer.Text = card.issuer
		TextRace.Text = card.race
		TextNumber.Text = card.number
		TextExpired.Text = card.valied & "-" & card.expire

		PictureBox1.ImageLocation = card.image_path



	End Sub

	Private Sub btOpen_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btOpen.Click
		Dim ret As Integer

		If ComboPortList.Text = "USB" Then
			ret = port.open(1001, 115200)
		ElseIf ComboPortList.Text.StartsWith("COM") Then
			ret = port.open(Integer.Parse(ComboPortList.Text.Substring(3)), 115200)
		Else
			ret = port.open(0, 0)
		End If

		If ret <> &H90 Then
			TextStatus.Text = "端口打开失败!"
			Exit Sub
		End If

		Call refreshButton()
	End Sub

	Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
		refreshButton()
	End Sub

	Private Sub btReadBank_Click(sender As Object, e As EventArgs) Handles btReadBank.Click
		Dim uid As reader_serviceLib.iso14443a_uid
		Dim obj()
		Dim ret As Integer

		obj = port.iso14443a_find(4)

		If obj.Length = 0 Then
			TextStatus.Text = "找卡失败!"
			' 必须要退出 ISO14443A 模式,否则下次无法读取身份证
			Call port.iso14443a_mode_exit()
			Exit Sub
		End If

		uid = obj(0)

		ret = port.iso14443a_select(uid.text, uid.sak)

		If ret <> &H90 Then
			' 必须要退出 ISO14443A 模式,否则下次无法读取身份证
			Call port.iso14443a_mode_exit()
			Call MsgBox("选卡失败!")
			Exit Sub
		End If

		'参数0代表读身份证,参数1代表读银行卡
		card = port.readcard(1)
		If card.number = "" Then
			' 必须要退出 ISO14443A 模式,否则下次无法读取身份证
			Call port.iso14443a_mode_exit()
			Call MsgBox("读卡失败!")
			Exit Sub
		End If

		Call MsgBox("银行卡号:" & card.number & ";有效期:" & card.expire & ";持卡人:" & card.name)


		' 必须要退出 ISO14443A 模式,否则下次无法读取身份证
		Call port.iso14443a_mode_exit()

	End Sub
End Class

五、安卓

package com.example.demo;

import android.annotation.SuppressLint;
import android.app.PendingIntent;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.hardware.usb.UsbManager;
import android.os.Bundle;

import com.bland.IDReader;
import com.bland.TpNfc;
import com.google.android.material.snackbar.Snackbar;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Message;
import android.os.Handler;
import android.view.View;
import android.app.PendingIntent;
import android.content.Context;
import android.hardware.usb.UsbDevice;
import android.widget.Toast;
import androidx.navigation.NavController;
import androidx.navigation.Navigation;
import androidx.navigation.ui.AppBarConfiguration;
import androidx.navigation.ui.NavigationUI;
import android.content.Intent;
import android.content.IntentFilter;
import com.example.demo.databinding.ActivityMainBinding;


import java.util.HashMap;

import android.view.Menu;
import android.view.MenuItem;
import android.nfc.tech.NfcB;

import org.json.JSONArray;
import org.json.JSONObject;
import 	android.provider.Settings;
import android.content.Context;
import android.nfc.Tag;
import android.nfc.NfcAdapter;
import android.util.Log;
import java.util.HashMap;
import android.util.Base64;
import android.widget.ImageView;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {

    //用于身份证解码先关变量
    public String race_table[][] ={
        {"01","汉族"},//   GB/T 3304-1991","Han","HA
        {"02","蒙古族"},//   GB/T 3304-1991","Mongol","MG
        {"03","回族"},//   GB/T 3304-1991","Hui","HU
        {"04","藏族"},//   GB/T 3304-1991","Zang","ZA
        {"05","维吾尔族"},//   GB/T 3304-1991","Uygur","uG
        {"06","苗族"},//   GB/T 3304-1991","Miao","MH
        {"07","彝族"},//   GB/T 3304-1991","Yi","YI
        {"08","壮族"},//   GB/T 3304-1991","Zhuang","ZH
        {"09","布依族"},//   GB/T 3304-1991","Buyei","BY
        {"10","朝鲜族"},//   GB/T 3304-1991","Chosen","cs
        {"11","满族"},//   GB/T 3304-1991","Man","MA
        {"12","侗族"},//   GB/T 3304-1991","Dong","DO
        {"13","瑶族"},//   GB/T 3304-1991","Yao","YA
        {"14","白族"},//   GB/T 3304-1991","Bai","BA
        {"15","土家族"},//   GB/T 3304-1991","Tujia","TJ
        {"16","哈尼族"},//   GB/T 3304-1991","Hani","HN
        {"17","哈萨克族"},//   GB/T 3304-1991","Kazak","KZ
        {"18","傣族"},//   GB/T 3304-1991","Dai","DA
        {"19","黎族"},//   GB/T 3304-1991","Li","LI
        {"20","傈僳族"},//   GB/T 3304-1991","Lisu","LS
        {"21","佤族"},//   GB/T 3304-1991","Va","VA
        {"22","畲族"},//   GB/T 3304-1991","She","SH
        {"23","高山族"},//   GB/T 3304-1991","Gaoshan","Gs
        {"24","拉枯族"},//   GB/T 3304-1991","Lahu","LH
        {"25","水族"},//   GB/T 3304-1991","Sui","su
        {"26","东乡族"},//   GB/T 3304-1991","Dongxiang","DX
        {"27","纳西族"},//   GB/T 3304-1991","Naxi","NX
        {"28","景颇族"},//   GB/T 3304-1991","Jingpo","JP
        {"29","柯尔克孜族"},//   GB/T 3304-1991","Kirgiz","KG
        {"30","土族"},//   GB/T 3304-1991","Tu","TU
        {"31","达斡尔族"},//   GB/T 3304-1991","Daur","DU
        {"32","仫佬族"},//   GB/T 3304-1991","Mulao","ML
        {"33","羌族"},//   GB/T 3304-1991","Qiang","QI
        {"34","布朗族"},//   GB/T 3304-1991","Blang","BL
        {"35","撒拉族"},//   GB/T 3304-1991","Salar","SL
        {"36","毛南族"},//   GB/T 3304-1991","Maonan","MN
        {"37","仡佬族"},//   GB/T 3304-1991","Gelao","GL
        {"38","锡伯族"},//   GB/T 3304-1991","Xibe","XB
        {"39","阿昌族"},//   GB/T 3304-1991","Achang","AC
        {"40","普米族"},//   GB/T 3304-1991","Pumi","PM
        {"41","塔吉克族"},//   GB/T 3304-1991","Tajik","TA
        {"42","怒族"},//   GB/T 3304-1991","Nu","NU
        {"43","乌孜别克族"},//   GB/T 3304-1991","Uzbek","Uz
        {"44","俄罗斯族"},//   GB/T 3304-1991","Russ","RS
        {"45","鄂温克族"},//   GB/T 3304-1991","Ewenki","EW
        {"46","德昂族"},//   GB/T 3304-1991","Deang","DE
        {"47","保安族"},//   GB/T 3304-1991","Bonan","BN
        {"48","裕固族"},//   GB/T 3304-1991","Yugur","YG
        {"49","京族"},//   GB/T 3304-1991","Gin","GI
        {"50","塔塔尔族"},//   GB/T 3304-1991","Tatar","TT
        {"51","独龙族"},//   GB/T 3304-1991","Derung","DR
        {"52","鄂伦春族"},//   GB/T 3304-1991","Oroqen","OR
        {"53","赫哲族"},//   GB/T 3304-1991","Hezhen","HZ
        {"54","门巴族"},//   GB/T 3304-1991","Monba","MB
        {"55","珞巴族"},//   GB/T 3304-1991","Lhoba","LB
        {"56","基诺族"},//   GB/T 3304-1991","Jino","JN
        {"",""}
    };
    private static final int SDK_NFC_FLAG = 3;
    private static final int SDK_READER_FLAG = 4;
    private static final int SDK_DEVICE_FLAG = 5;
    private static final int SDK_CLIENT_FLAG = 6;
    private static final int SDK_ICCARD_FLAG = 7;
    private static final int SDK_BANKCARD_FLAG = 8;

    //用于 OTG 阅读器相关变量
    public IDReader reader;
    public UsbManager usbManager;
    private static final String ACTION_USB_PERMISSION = "com.android.usb.USB_PERMISSION";
    private boolean id_card_exist = false;      // 标记上一次读卡时,身份证是否存在
    private String samid = "";                      // 标记阅读器是否连接,以及SAM ID是多少
    private String last_idcard_text = "";           // 最近一次身份证读卡信息,方便判断身份证是否变化
    private String last_iccard_text = "";           // 最近一次Mifare one读卡数据信息
    private String last_iccard_uid = "";           // 最近一次Mifare one 读卡UID信息
    private int last_iccard_sak = 0;           // 最近一次Mifare one 读卡SAK信息
    //用于手机本机 NFC 相关变量
    public TpNfc tpnfc;
    NfcAdapter mNfcAdapter;
    PendingIntent pIntent;

    //其他变量
    private AppBarConfiguration appBarConfiguration;
    private ActivityMainBinding binding;

    /**
     * 将民族代码,转换成文本
     * @param code
     * @return
     */
    public String GetRace(String code) {
        int i;
        for (i = 0; i < race_table.length; i++) {
            if (race_table[i][0].compareTo(code) == 0) {
                return race_table[i][1];
            }
        }
        return "其它";
    }

    /**
     * 在 UI 上显示身份证信息
     * @param text 文本
     * @param image 照片
     */
    void ViewInfo(String text,Bitmap image) {
        TextView tv = (TextView) findViewById(R.id.textview_first);
        ImageView iv = (ImageView) findViewById(R.id.imageView);

        tv.setText(text.toCharArray(), 0, text.toCharArray().length);
        iv.setImageBitmap(image);
    }

    /**
     * 解析身份证读卡结果
     * @param str JSON 格式字符串
     * @return 返回错误或成功信息
     */
    String ParseInfo(String str) {
        Bitmap decodedByte = null;
        String info = "";

        try {
            JSONObject jsondata = new JSONObject(str);

            if(jsondata.getString("function").compareTo("readcard") != 0) {
                return "";//不是读卡消息,直接返回
            }

            if(jsondata.has("errorMsg")) {
                ViewInfo(info,decodedByte);  //卡片已拿走或其他错误,清空信息
                return jsondata.getString("errorMsg");
            }

            if( !jsondata.has("data") ) {
                //异常情况,不应该出现,清空信息
                ViewInfo(info,decodedByte);
                return "";
            }

            JSONObject content = jsondata.getJSONObject("data");
            if(content.getString("type").compareTo("I") == 0) {
                info = "2017版外国人永久居留证";
            }
            else if(content.getString("type").compareTo("Y") == 0) {
                info = "新版外国人永久居留证";
            }
            else if(content.getString("type").compareTo("J") == 0) {
                info = "港澳台居住证";
            }
            else if(content.getString("type").compareTo(" ") == 0) {
                info = "居民身份证";
            }
            else  {
                info = "未知";
            }

            info = info + "\r\n姓名:" + content.getString("name");
            info = info + "\r\n身份证号:" + content.getString("number");
            String gender;
            if(content.getInt("gender") == 1) {
                gender = "男";
            }
            else if (content.getInt("gender") == 2){
                gender = "女";
            }
            else {
                gender = "未知";
            }
            info = info + "\r\n性别: " + gender;

            if(content.getString("type").compareTo(" ") == 0) {
                //只有身份证有民族信息
                info = info + "\r\n民族: " + GetRace(content.getString("race"));
            }

            info = info + "\r\n生日: " + content.getString("birthday");

            if(content.getString("type").compareTo("I") != 0 ) {
                //外国人永久居留证没有住址信息
                info = info + "\r\n住址: " + content.getString("address");
            }

            info = info + "\r\n签发机关: " + content.getString("issuer");
            info = info + "\r\n有效期限: " + content.getString("valied") + "-" + content.getString("expire");

            if(content.getString("type").compareTo("I") == 0) {
                //2017版外国人永久居留证
                info = info + "\r\n中文名称: " + content.getString("cn_name");
                info = info + "\r\n版本: " + content.getString("version");
                info = info + "\r\n国籍: " + content.getString("nation");
            }
            else if(content.getString("type").compareTo("Y") == 0) {
                //新版外国人永久居留证
                info = info + "\r\n中文名称: " + content.getString("cn_name");
                info = info + "\r\n换证次数: " + content.getString("renewal_count");
                info = info + "\r\n关联号码: " + content.getString("relational_number");
                info = info + "\r\n国籍: " + content.getString("nation");
            }
            else if(content.getString("type").compareTo("J") == 0) {
                //港澳台居住证
                info = info + "\r\n通行证号码: " + content.getString("pass_number");
                info = info + "\r\n签发次数: " + content.getString("issue_count");
            }

            byte[] img = Base64.decode(content.getString("photo"),Base64.DEFAULT);
            decodedByte = BitmapFactory.decodeByteArray(img, 0, img.length);

            ViewInfo(info,decodedByte);
            return "读卡成功!";
        }
        catch (Exception e) {
            return e.getMessage();
        }

    }

    /**
     * 处理身份证阅读消息,或者 OTG 阅读器插入拔出消息
     */
    @SuppressLint("HandlerLeak")
    private Handler mHandler = new Handler(){
        @Override
        public  void handleMessage(Message msg) {
            String err = "";
            switch (msg.what) {
                case SDK_NFC_FLAG: {
                    err = ParseInfo((String)msg.obj);
                    break;
                }
                case SDK_READER_FLAG: {
                    err = ParseInfo((String)msg.obj);
                    break;
                }
                case SDK_DEVICE_FLAG:{
                    if(samid == "" ) {
                        err = "阅读器已拔出!";
                    }
                    else {
                        err = "阅读器已连接:" + samid;
                    }
                    break;
                }
                case SDK_CLIENT_FLAG: {
                    ViewInfo((String)msg.obj,null);
                    break;
                }
                case SDK_ICCARD_FLAG: {
                    if(last_iccard_uid != "") {
                        ViewInfo("uid: " + last_iccard_uid + "\r\ndata: " + last_iccard_text, null);
                    }
                    else {
                        ViewInfo("",null);
                    }
                    break;
                }
                case SDK_BANKCARD_FLAG: {
                    if(last_iccard_uid != "") {
                        ViewInfo("uid: " + last_iccard_uid + "\r\n" + (String)msg.obj, null);
                    }
                    else {
                        ViewInfo("",null);
                    }
                    break;
                }
            }

            if (err != "") {
                Snackbar.make(findViewById(R.id.fab), err, Snackbar.LENGTH_LONG)
                        .setAction("Action", null).show();
            }
        }
    };

    /**
     * 申请 USB OTG 阅读器访问权限
     * @param usbManager
     * @return
     */
    public int UsbPermission(UsbManager usbManager) {
        //单独申请USB权限
        PendingIntent permissionIntent = PendingIntent.getBroadcast(this, 0, new Intent(ACTION_USB_PERMISSION), PendingIntent.FLAG_IMMUTABLE);
        HashMap<String, UsbDevice> deviceList = usbManager.getDeviceList();
        for (UsbDevice usbDevice : deviceList.values()) {
            if( reader.CompareReaderID(usbDevice.getVendorId(),usbDevice.getProductId()) ) {
                if(!usbManager.hasPermission(usbDevice)) {
                    usbManager.requestPermission(usbDevice, permissionIntent);
                }
                else {

                }
                Log.e("id_reader","Reader found!");
                break;
            }
            else {
            }
            Log.e("id_reader","Name: " + usbDevice.getManufacturerName() + " " + usbDevice.getProductName() + ", VID: " + usbDevice.getVendorId() + ",PID: " + usbDevice.getProductId());
        }
        return 0;
    }

    /**
     * 发送消息到 UI
     * @param str
     */
    public void SendMsg(String str,int type) {
        Message msg = new Message();
        msg = new Message();
        if(mHandler != null) {
            msg.what = type;
            msg.obj = str;
            mHandler.sendMessage(msg);
        }
    }

    /**
     * 发送 OTG 阅读器连接或拔出的消息到 UI
     * @param samid
     */
    public void SendDeviceMsg(String samid) {
        SendMsg(samid,SDK_DEVICE_FLAG);
    }

    /**
     * 发送身份证读卡结果消息到 UI
     * @param result 身份证读卡结果,JSON格式
     * @param type
     */
    public void SendCardInfoMsg(String result,int type) {
        //tpnfc.SetLastRead(result);
        SendMsg(result,type);
    }

    /**
     * 判断 OTG 阅读器身份证读卡结果是否有变化,以决定是否需要发送消息到 UI
     * @param result
     * @return 返回身份证是否存在于OTG 阅读器
     */
    public boolean OnIDCardResult(String result) {
        try {
            boolean cur_exist;

            JSONObject jsondata = new JSONObject(result);
            if(jsondata.getInt("ret") != 0 ) {
                if (jsondata.getInt("ret") == 2) {
                    //阅读器设备状态改变,变为不存在,发送通知消息
                    samid = "";
                    SendDeviceMsg(samid);
                }
                last_idcard_text = "";
                cur_exist = false;
            }
            else {
                cur_exist = true;
            }

            if(jsondata.has("data")) {
                JSONObject data = jsondata.getJSONObject("data");
                if(data.has("text")) {
                    String cur_text = data.getString("text");
                    if (cur_text.compareTo(last_idcard_text) != 0) {//卡片信息发生改变,发送通知消息
                        id_card_exist = true;
                        last_idcard_text = cur_text;
                        SendCardInfoMsg(result, SDK_READER_FLAG);
                        return id_card_exist;
                    }
                }
            }

            if(cur_exist != id_card_exist) {//卡片状态发生改变,发送通知消息
                id_card_exist = cur_exist;
                SendCardInfoMsg(result, SDK_READER_FLAG);
                return id_card_exist;
            }

        }
        catch (Exception e) {
            id_card_exist = false;
        }

        return id_card_exist;
    }


    /**
     * 判断 OTG Mifare one 读卡结果是否有变化,以决定是否需要发送消息到 UI
     * @param result
     * @return 返回Mifare one 卡是否存在
     */
    public boolean OnICCardResult(String result) {
        try {

            JSONObject jsondata = new JSONObject(result);
            if(jsondata.getInt("ret") != 0 ) {
                if (jsondata.getInt("ret") == 2) {
                    //阅读器设备状态改变,变为不存在,发送通知消息
                    samid = "";
                    SendDeviceMsg(samid);
                }
                last_iccard_text = "";
                last_iccard_sak = 0;
            }
            String cmd = jsondata.getString("function");
            if(jsondata.has("data")) {
                JSONObject data = jsondata.getJSONObject("data");
                if( cmd.compareTo("iso14443a_find") == 0) {//处理找卡结果
                    JSONArray uid = data.getJSONArray("uid");
                    if(uid.length()>0) {
                        last_iccard_uid = uid.getJSONObject(0).getString("text");
                        last_iccard_sak = uid.getJSONObject(0).getInt("sak");
                        return true;
                    }
                    else {
                    }
                }
                else if(cmd.compareTo("pboc_read") == 0 && data.has("number") ) {
                    if(last_iccard_text.compareTo(data.getString("number")) !=0 ) {
                        last_iccard_text = data.getString("number");
                        String bankInfo = "银行卡号:"+data.getString("number") + "\r\n";
                        bankInfo += "有效期截止:" + data.getString("expire") + "\r\n";
                        bankInfo += "持卡人:" + data.getString("owner") + "\r\n";
                        bankInfo += "持卡人证件号码:" + data.getString("owner_id") + "\r\n";
                        SendCardInfoMsg(bankInfo, SDK_BANKCARD_FLAG);
                    }
                    return true;
                }
                else if( data.has("hex") ){//处理读到的数据
                    if(last_iccard_text.compareTo(data.getString("hex")) !=0 ) {
                        reader.WebSocketAPI("{\"module\":\"common\",\"msgid\":\"0\",\"function\":\"beep\",\"data\":{\"length\":200}}");
                        last_iccard_text = data.getString("hex");
                        SendCardInfoMsg(result, SDK_ICCARD_FLAG);
                    }
                    return true;
                }
            }
            if(last_iccard_text != "" || last_iccard_uid != "") {//卡片状态发生改变,发送通知消息
                last_iccard_uid = "";
                last_iccard_text = "";
                last_iccard_sak = 0;
                SendCardInfoMsg(result, SDK_ICCARD_FLAG);
            }
            return false;
        }
        catch (Exception e) {
            return false;
        }
    }

    /**
     * 清除读卡结果,并发送消息到 UI
     */
    public void ClearReaderResult() {
        if( samid.compareTo("") != 0 ){
            samid = "";
            SendDeviceMsg(samid);
        }

        if(id_card_exist) {
            id_card_exist = false;
            SendCardInfoMsg("{\"module\":\"idcard\",\"msgid\":\"0\",\"function\":\"readcard\",\"errorMsg\":\"设备不存在\",\"ret\":2}", SDK_READER_FLAG);
        }

        last_idcard_text = "";
    }

    /**
     * 读取 OTG 阅读器的 SAM ID,并返回 OTG 阅读器是否存在
     * @return 返回 OTG 阅读器是否存在
     */
    public boolean CheckSamID() {
        String result;
        JSONObject jsondata;
        try {
            if(samid == "" ) {
                result = reader.WebSocketAPI("{\"module\":\"idcard\",\"msgid\":\"0\",\"function\":\"getsam\"}");
                jsondata = new JSONObject(result);
                if(jsondata.has("errorMsg") ) {
                    if(jsondata.has("ret") && jsondata.getInt("ret") == 2) {
                        //设备不存在
                    }
                    return false;
                }
                if(!jsondata.has("data") ) {
                    return false;
                }
                JSONObject data = jsondata.getJSONObject("data");
                if(!data.has("samid") ) {
                    return false;
                }
                samid = data.getString("samid");
                if(samid == "" ) {
                    return false;
                }
                SendDeviceMsg(samid);
            }
            return true;
        }
        catch(Exception e) {
            return false;
        }
    }

    /**
     * 使用 OTG 阅读器读取身份证,处理读取结果并返回身份证是否存在
     * @return 返回身份证是否存在
     */
    public boolean ReadIDCard() {
        try {
            if(!id_card_exist) {
                //还没有检测到卡片存在的情况下,可以先找卡和选卡。 这段代码不是必须,可以去掉,一样正常使用
                if( ! OnIDCardResult( reader.WebSocketAPI("{\"module\":\"idcard\",\"msgid\":\"0\",\"function\":\"findcard\"}") ) ){
                    return false;
                }

                if( !OnIDCardResult( reader.WebSocketAPI("{\"module\":\"idcard\",\"msgid\":\"0\",\"function\":\"selectcard\"}") ) ) {
                    return false;
                }
            }
            return OnIDCardResult( reader.WebSocketAPI("{\"module\":\"idcard\",\"msgid\":\"0\",\"function\":\"readcard\"}") );
        }
        catch(Exception e) {
            return false;
        }
    }

    /**
     * 使用 OTG 阅读器读取Mifare one卡
     * @return 返回Mifare one卡是否存在
     */
    public boolean ReadICCard() {
        String cmd,pre_uid;

        if(id_card_exist) {//确认身份证卡片已存在的情况下,不读IC卡,避免冲突
            return false;
        }
        try {
            pre_uid = last_iccard_uid;

            if (!OnICCardResult(reader.WebSocketAPI("{\"module\":\"iccard\",\"msgid\":\"0\",\"function\":\"iso14443a_find\"}"))) {
                return false;
            }

            if( last_iccard_uid.compareTo(pre_uid) == 0) {
                //卡没有发生变化,不重复读了
                return true;
            }

            if((last_iccard_sak & 0x20) == 0x20 ) {
                //构造读取银行卡号码的指令
                cmd = "{\"module\":\"iccard\",\"msgid\":\"0\",\"function\":\"pboc_read\",\"data\": {\"uid\":\""+ last_iccard_uid + "\"} }";
            }
            else {
                //构造读取 IC 卡的第 0 个Block 的指令
                int type = 0x60;  //密钥A:0x60 , 密钥B:0x61
                String key = "FFFFFFFFFFFF";
                int block = 0;
                cmd = "{\"module\":\"iccard\",\"msgid\":\"0\",\"function\":\"mifare_read\",\"data\": {\"uid\":\""+ last_iccard_uid + "\",\"block\":"+block+",\"type\":"+ type + ",\"key\":\""+key+"\"} }";
            }
            return OnICCardResult( reader.WebSocketAPI(cmd) );
        }
        catch(Exception e) {
            return false;
        }
    }

    /**
     * OTG 阅读器读取身份证信息线程
     */
    Runnable runnable = new Runnable() {
        @Override
        public void run() {
            while(true) {
                int  msgid = 0;
                try {
                    if( reader.Connected(usbManager) ) {
                        // 使用串口转网口模块时, reader.Connected(usbManager) 改为 true,直接 if(true) {
                        if(!CheckSamID()) {
                            Thread.sleep(1000);
                            continue;
                        }

                        if( ReadIDCard() || ReadICCard()) {
                            Thread.sleep(100);
                            continue;
                        }

                        Thread.sleep(100);

                    }
                    else {
                        ClearReaderResult();
                        Thread.sleep(200);
                        continue;
                    }

                }
                catch (Exception e) {
                    String error = e.toString();
                    Log.e("id_reader",error);
                }
            }
        }
    };


    /**
     *  感应到身份证时触发该事件。实现手机本机 NFC 读身份证。
     * @param intent
     */
    @Override
    protected void onNewIntent(Intent intent){
        super.onNewIntent(intent);
        setIntent(intent);

        Tag tag = getIntent().getParcelableExtra(NfcAdapter.EXTRA_TAG);
        if(tag == null ) {
            return ;
        }

        //sendCardInfoMsg("{\"module\" : \"tpnfc\",\"function\" : \"card\", \"data\": {\"id\":\"" + byte2hex(tag.getId()) + "\"},\"ret\":0}",SDK_NFC_FLAG);

        NfcB card = NfcB.get(tag);

        if(card == null ) {
            return;
        }

        try {
            card.connect();
            String result = tpnfc.LocalNfcRead(card);
            card.close();

            JSONObject content = new JSONObject(result);
            if(content.has("errorMsg")) {
                String error = content.getString("errorMsg");
                String s = new String(error.getBytes("ISO-8859-1"), "UTF-8");
                String info = "\nerror: " + s + "\n";
            }
            SendCardInfoMsg(result,SDK_NFC_FLAG);
        }
        catch (java.io.IOException e){
            String result = "{\"module\" : \"idcard\",\"function\" : \"readcard\",\"errorMsg\":\"" + e.getMessage() + "\",\"errorNo\":34, \"server_error_code\": 0 ,\"server_error_string\": \"\"}";
            SendCardInfoMsg(result,SDK_NFC_FLAG);
        }
        catch (Exception e){
            String result = "{\"module\" : \"idcard\",\"function\" : \"readcard\",\"errorMsg\":\"" + e.getMessage() + "\",\"errorNo\":34, \"server_error_code\": 0 ,\"server_error_string\": \"\"}";
            SendCardInfoMsg(result,SDK_NFC_FLAG);
        }
    }

    /**
     * 初始化手机本机 NFC 读身份证的相关变量和事件
     * @param path 提供可读写的路径,用于保存会话信息
     */
    public void InitNfc(String path){
        TpNfc.Init(path);
        tpnfc = new TpNfc();

        mNfcAdapter = NfcAdapter.getDefaultAdapter(this);
        if (null == mNfcAdapter) {
            Toast.makeText(this, "不支持NFC功能", Toast.LENGTH_SHORT).show();
            TpNfc.nfc_support = 0;
        } else if (!mNfcAdapter.isEnabled()) {
            TpNfc.nfc_support = 0;
            Intent intent = new Intent(Settings.ACTION_NFC_SETTINGS);
            // 根据包名打开对应的设置界面
            startActivity(intent);
        }
        else {
            TpNfc.nfc_support = 1;
        }

        pIntent = PendingIntent.getActivity(this, 0,
                //在Manifest里或者这里设置当前activity启动模式,否则每次向阳NFC事件,activity会重复创建
                // 当然也要按照具体情况来,你设置成singleTask也不是不行,
                new Intent(this, getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP),
                PendingIntent.FLAG_MUTABLE);
    }

    /**
     * 初始化 OTG 阅读器相关的变量、事件、权限等等
     * @param path 提供可读写的路径,用于保存配置
     */
    public void InitReader(String path){
        IDReader.ServiceStart(path);
        reader = new IDReader();

        usbManager = (UsbManager) getSystemService(Context.USB_SERVICE);

        UsbPermission(usbManager);

        new Thread(runnable).start();
    }

    /**
     * 修改手机本机 NFC 的相关设置
     */
    @Override
    protected void onResume() {
        super.onResume();
        if (mNfcAdapter != null) {
            //添加intent-filter
            IntentFilter ndef = new IntentFilter(NfcAdapter.ACTION_NDEF_DISCOVERED);
            IntentFilter tag = new IntentFilter(NfcAdapter.ACTION_TAG_DISCOVERED);
            IntentFilter tech = new IntentFilter(NfcAdapter.ACTION_TECH_DISCOVERED);
            IntentFilter[] filters = new IntentFilter[]{ndef, tag, tech};

            String[][] techList = new String[][]{
                    new String[]{
                            "android.nfc.tech.Ndef",
                            "android.nfc.tech.NfcA",
                            "android.nfc.tech.NfcB",
                            "android.nfc.tech.NfcF",
                            "android.nfc.tech.NfcV",
                            "android.nfc.tech.NdefFormatable",
                            "android.nfc.tech.MifareClassic",
                            "android.nfc.tech.MifareUltralight",
                            "android.nfc.tech.NfcBarcode"
                    }
            };
            mNfcAdapter.enableForegroundDispatch(this, pIntent, filters, techList);
        }
    }

    @Override
    protected void onPause() {
        super.onPause();
        if (mNfcAdapter != null) {
            mNfcAdapter.disableForegroundDispatch(this);
        }
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        binding = ActivityMainBinding.inflate(getLayoutInflater());
        setContentView(binding.getRoot());

        String path = getFilesDir().toString();

        InitNfc(path);

        InitReader(path);

        setSupportActionBar(binding.toolbar);

        NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment_content_main);
        appBarConfiguration = new AppBarConfiguration.Builder(navController.getGraph()).build();
        NavigationUI.setupActionBarWithNavController(this, navController, appBarConfiguration);


        binding.fab.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {

                if(tpnfc == null ) {
                    return ;
                }

                /*
                    使用手机本机 NFC 阅读身份证时,需要先将手机与账号绑定。步骤如下:
                    1. 官网注册账号
                    2. 使用 tpnfc.SendBindRequest 向账号发送绑定请求
                    3. 官网登录账号,接受绑定请求
                    3. 调用 tpnfc.ClientInfo() 获取信息,判断是否绑定成功。
                    4. 绑定成功功后,即可正常使用手机NFC读取身份证信息
                 */

                String info = "";
                String user = "18118742537"; //用户账号
                try {
                    JSONObject jsondata = new JSONObject(tpnfc.ClientInfo());
                    if (jsondata.has("secret") && jsondata.has("limit") && jsondata.has("expire")) {
                        //已经绑定账号
                        info = "NFC客户端\n有效期:" + jsondata.getString("expire") + "\n次数限制:" + jsondata.getInt("decode") + "/" + jsondata.getInt("limit");
                        if(jsondata.getString("secret").compareTo("ok") != 0) {
                            //客户端认证失败,需要解除绑定后,再重新绑定
                            info += "\n密钥:密钥丢失,需要重新绑定";
                            info += "\n解除绑定:" + ParseServerError(tpnfc.Unbind(jsondata.getString("id"), user)); //解除绑定
                        }
                        else {

                        }
                    } else {
                        //还未绑定账号, 发送绑定请求, tpnfc.SendBindRequest 第一个参数为 客户端名称, 第二个参数是用户账号(手机号码)
                        info += "发送绑定请求:";
                        info += ParseServerError(tpnfc.SendBindRequest("测试NFC客户端", user));
                    }
                }
                catch ( Exception e) {
                    info = e.getMessage();
                }
                SendMsg(info,SDK_CLIENT_FLAG);
            }
        });
    }

    public String ParseServerError(String result) {
        String err = "";
        try {
            JSONObject ret = new JSONObject(result);
            if (ret.has("errorMsg")) {
                if (ret.getInt("errorNo") == 43) {
                    err = "操作失败:" + ret.getString("server_error_string");
                } else {
                    err = "操作失败:" + ret.getString("errorMsg");
                }
            } else {
                err = "操作成功!";
            }
        }
        catch (Exception e) {
            err = e.getMessage();
        }
        return err;
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();

        //noinspection SimplifiableIfStatement
        if (id == R.id.action_settings) {
            //测试重启服务
            reader.ServiceStop();
            reader.ServiceStart(getFilesDir().toString());
            return true;
        }

        return super.onOptionsItemSelected(item);
    }

    @Override
    public boolean onSupportNavigateUp() {
        NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment_content_main);
        return NavigationUI.navigateUp(navController, appBarConfiguration)
                || super.onSupportNavigateUp();
    }


}

六、C#

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace webapi_http
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void btReadCard_Click(object sender, EventArgs e)
        {
            string result;
            string url = "http://127.0.0.1:7846/api/readCard?utf8=1";
            try
            {
                HttpWebRequest wbRequest = (HttpWebRequest)WebRequest.Create(url);
                wbRequest.Proxy = null;
                wbRequest.Method = "GET";
                HttpWebResponse wbResponse = (HttpWebResponse)wbRequest.GetResponse();
                using (Stream responseStream = wbResponse.GetResponseStream())
                {
                    using (StreamReader sReader = new StreamReader(responseStream))
                    {
                        result = sReader.ReadToEnd();
                    }
                }
            }
            catch (Exception ex)
            {
                result = ex.Message;     //输出捕获到的异常,用OUT关键字输出
            }
            textResult.Text = result;
        }
    }
}

七、C

#include <stdio.h>
#include <sdtapi.h>
#include <time.h>
#include <stdlib.h>
#include <string.h>


#ifndef WIN32
#include <sys/time.h>
#include <sys/stat.h>
#include <dirent.h>

void Sleep(unsigned int x)  
{ 
	struct timespec xsleep; \
	xsleep.tv_sec = x / 1000; \
	xsleep.tv_nsec = (x - xsleep.tv_sec * 1000) * 1000 * 1000; \
	nanosleep(&xsleep, NULL); \
}
#else
#include <windows.h>
#include <winnls.h>

#endif

#include "bland.h"


#ifndef WIN32
void print_com_list()//for linux
{
	struct dirent *pDirent;
	DIR *pDir;
	int i,index;
	struct stat st;
	char path[512] = {0};

	pDir = opendir("/sys/class/tty");
	if (pDir == NULL) {
		return ;
	}

	for (i=0,index=1;;i++) {
		pDirent = readdir(pDir);
		if(pDirent == NULL) {
			break;
		}
		snprintf(path,sizeof(path)-1,"/sys/class/tty/%s/device",pDirent->d_name);
		
		if (lstat(path, &st) < 0) {
			continue;
		}
		printf("COM%d: %s\n",index,path);
		index++;
	}
	closedir(pDir);
}

//使用 UTF-8 字符编码
#define GetName			GetNameUtf8
#define GetGender		GetGenderUtf8
#define GetBirthday		GetBirthdayUtf8
#define GetAddress		GetAddressUtf8
#define GetRace			GetRaceUtf8
#define GetIDNum		GetIDNumUtf8
#define GetIssuer		GetIssuerUtf8
#define GetValidFrom	GetValidFromUtf8
#define GetExpireDate	GetExpireDateUtf8
#define GetPassNum		GetPassNumUtf8
#define GetIssueCount	GetIssueCountUtf8
#define GetNationCode	GetNationCodeUtf8
#define GetCnName		GetCnNameUtf8


#endif


void print_info2(char * text)
{
	char str[256] = {0};
	char str2[256] = {0};
	int ret,type;

	type = GetType(text);

	ret = GetName(text,str,sizeof(str));
	if(ret < 0) {
		goto info_error;
	}
	printf("name: %s\n",str);
	
	ret = GetGender(text,str,sizeof(str));
	if(ret < 0) {
		goto info_error;
	}
	printf("gender: %s\n",str);

	if(type == ' ') {
		//只有身份证有此项
		ret = GetRace(text,str,sizeof(str));
		if(ret < 0) {
			goto info_error;
		}
		printf("race: %s\n",str);
	}

	ret = GetBirthday(text,str,sizeof(str));
	if(ret < 0) {
		goto info_error;
	}
	printf("birthday: %s\n",str);

	if(type != 'I' && type != 'Y') {
		//外国人永久居留证没有此项
		ret = GetAddress(text,str,sizeof(str));
		if(ret < 0) {
			goto info_error;
		}
		printf("address: %s\n",str);
	}

	ret = GetIDNum(text,str,sizeof(str));
	if(ret < 0) {
		goto info_error;
	}
	printf("IDNum: %s\n",str);

	ret = GetIssuer(text,str,sizeof(str));
	if(ret < 0) {
		goto info_error;
	}
	printf("issuer: %s\n",str);

	ret = GetValidFrom(text,str,sizeof(str));
	if(ret < 0) {
		goto info_error;
	}
	ret = GetExpireDate(text,str2,sizeof(str2));
	if(ret < 0) {
		goto info_error;
	}
	printf("valid: %s-%s\n",str,str2);

	if(type == 'J') {
		ret = GetPassNum(text,str,sizeof(str));
		if(ret < 0) {
			goto info_error;
		}
		printf("passNum: %s\n",str);

		ret = GetIssueCount(text,str,sizeof(str));
		if(ret < 0) {
			goto info_error;
		}
		printf("IssueCount: %s\n",str);
	}
	else if(type == 'I' || type == 'Y') {
		ret = GetNationCode(text,str,sizeof(str));
		if(ret < 0) {
			goto info_error;
		}
		printf("nation: %s\n",str);

		ret = GetCnName(text,str,sizeof(str));
		if(ret < 0) {
			goto info_error;
		}
		printf("cnName: %s\n",str);

		if(type == 'I') {
			//2017版外国人永久居留证
			ret = GetCardVersion(text,str,sizeof(str));
			if(ret < 0) {
				goto info_error;
			}
			printf("version: %s\n",str);
		}
		else {
			ret = GetRelationalNum(text,str,sizeof(str));
			if(ret < 0) {
				goto info_error;
			}
			printf("relational number: %s\n",str);

			ret = GetRenewalCount(text,str,sizeof(str));
			if(ret < 0) {
				goto info_error;
			}
			printf("renewal count: %s\n",str);
		}
	}

	printf("\n");

info_error:

	return ;
}

unsigned int get_sector_num(unsigned int block_num)
{
    int sector;
    if (block_num < 128)
    {
        sector = block_num / 4;
    }
    else
    {
        sector = ((block_num - 128) / 16) + 32;
    }

    return sector;
}

#define MAX_UID_FIND	6

//读取银行卡卡号等信息
int ReadBankCard(int iPort, ISO14443A_UID_T * card)
{
	int ret;
	char number[256] = {0};
	char info[sizeof(number)] = {0};
	
	ret = ReadPbocCardNumA(iPort,card->UID,card->UIDLen,number,info,sizeof(number));

	if(ret>0) {
		printf("Bank Card Number:\t%s\n",number);
		printf("Other Information:\t%s\n",info);
		return ret;
	}
	else {
		return -1;
	}
}



//读取 Mifare IC卡
int ReadMifare(int iPort, ISO14443A_UID_T * card)
{
	int ret;
	unsigned int j,i;
	int max_block,sector;
	int type = 0x60; // 0x60 为密钥A 认证, 0x61 为密钥B认证
	unsigned char data[256][16] = {0};
	unsigned char key[6] = {0xff,0xff,0xff,0xff,0xff,0xff};
	
	//read card 
	
    if(card->SAK == 0x18)
    {
        max_block = 256;
    }
	else {
		max_block = 64;
	}

	for (i = 0, sector=-1 ;i< max_block;i++)
	{
		if(get_sector_num(i) != sector )
		{//扇区发生变化,需要重新认证
			//需要先HALT一下卡片,必要的,但暂不清楚原因
			ISO14443A_Halt(iPort, 0);
            sector = get_sector_num(i);
            ret = MIFARE1_AuthBlock(iPort, card->UID, card->UIDLen, i, type, key, 0);
            if (ret != 0x90){
				printf("Mifare Auth block %d Failed!\n",i);
                return -1;
            }
        }

        ret = MIFARE1_ReadBlock(iPort, i, data[i], 0);
        if (ret != 0x90) {
            printf("Read block %d failed!\n",i);
			return -1;
        }
    }

	/* //write block
	memset(data,rand(),16);

	
	ISO14443A_Halt(iPort, 0);
	MIFARE1_AuthBlock(iPort, uid[0].UID, uid[0].UIDLen, 1, type, key, 0);
	ret = MIFARE1_WriteBlock(iPort,1,data,0);
	if(ret != 0x90) {
		printf("Write block 1 failed!\n");
		return -1;
	}
	*/

	//

	for (i = 0;i< max_block && i<8;i++) //只显示一部分数据,否则内容太多刷屏了
	{
		for(j=0;j<16;j++) {
			if(j==8) {
				printf(" ");
			}
			printf("%02X ",data[i][j]);
		}
		printf("\n");
    }
	return max_block;
}

static unsigned char passport_data[128*1024];
static unsigned char passport_photo[256*1024];


void ReadPassport(int iPort,const char * pass_num, const char * birthday, const char * expire)
{
	int ret;
	FILE * fp;

	//读护照
	char auth[90] = {0};
	char MRZ[256];

	//生成认证码 auth
	GetICAO9303AuthCode(pass_num,birthday,expire,auth);

	//读取护照
	ret = ReadICAO9303All(iPort,auth,passport_data,sizeof(passport_data));
	
	if(ret<=0) {
		return ;
	}

	ret = GetICAO9303MRZ(passport_data,MRZ,sizeof(MRZ));
	if(ret<0) {
		return ;
	}
	//读取护照/港澳通行证成功
	printf("MRZ: %s\n",MRZ);


	ret = GetICAO9303JpgData(passport_data,passport_photo,sizeof(passport_photo));
	if(ret>0) {
		fp = fopen("image.jpg","wb+");
		if(fp) {
			fwrite(passport_photo,1,ret,fp);
			fclose(fp);
		}
	}
}

void ReadOtherCard(int iPort)
{
	int ret;
	unsigned int j,i,cnt = 0;
	ISO14443A_UID_T uid[MAX_UID_FIND];

	//find card
	ret = ISO14443A_FindCard(iPort,uid,MAX_UID_FIND,&cnt,0);
	if(ret != 0x90) {
		goto finished;
	}
	
	if(cnt <= 0) {
		goto finished;
	}

	for(i=0;i<cnt;i++) {	
		if(uid[i].SAK == 0x8) {
			printf("Mifare S50:\t");
		}
		else if(uid[i].SAK == 0x18) {
			printf("Mifare S70:\t");
		}
		else {
			printf("Unknow:\t");
		}
		for(j=0;j<uid[i].UIDLen;j++) {
			printf("%02X",uid[i].UID[j]);
		}
		printf("\n");
	}

	if(uid[0].SAK & 0x8) {
		//尝试作为 Mifare IC卡读取
		ret = ReadMifare(iPort,&uid[0]);
		if(ret>=0) {
			ISO14443A_Halt(iPort,0);
			SDT_ReaderBeep(iPort,100,0);
			Sleep(1000);
		}

		ISO14443A_ModeExit(iPort,0); //退出模式(短暂关闭天线),并Sleep一段时间,解决部分银行卡作为Mifare卡读过之后,就不能读取银行卡号的问题
		Sleep(200);
	}

	if(uid[0].SAK & 0x20) {

		//尝试作为银行卡读取
		ret = ReadBankCard(iPort,&uid[0]);
		if(ret>=0) {
			SDT_ReaderBeep(iPort,100,0);
			Sleep(1000);
			goto finished;
		}
	}

	if(uid[0].SAK & 0x20) {
		//尝试作为护照/港澳通行证读取
		ISO14443A_ModeExit(iPort,0);//  接口要求需要先退出type a模式
		Sleep(10);
		// 读取护照的参数需要通过OCR文字识别,获得护照(或港澳通行证)的号码,生日,过期时间, 并作为参数传入
		// 所以此处传入的 "C06765690", "131116", "191125" 只是示例, 需要根据实际情况修改
		ReadPassport(iPort,"C06765690","131116","191125");
	}

finished:
	// 从 ISO14443A 模式切回 ISO14443B模式(读取身份证模式),这样可以继续读取身份证,还起到了重置 ISO14443A 类型卡片的作用
	ISO14443A_ModeExit(iPort,0);
	Sleep(50);
}


int main(int argc, char * argv[])
{
	int port = 1001;
	int ret;
	unsigned char ManaInfo[4];
	unsigned char ManaMsg[8];
	unsigned char text[256];
	unsigned char image[1024];
	unsigned char finger[1024];
	unsigned char AppInfo[1024];
	unsigned char bmp[65536];
	unsigned int textLen,imageLen,fingerLen,AppInfoLen;
	unsigned int ID[4];
	char str[1024];
	FILE * fp;

	if(argc > 1) {
		port = atoi(argv[1]);
	}
#ifndef WIN32
	print_com_list();
#endif

	while(1) {

		ret = SDT_GetSAMStatus(port,1);
		if(ret != 0x90 ) {
			Sleep(200);
			continue;
		}
/*
		SDT.ResetSAM(port,1);
		Sleep(1000);
		continue;
*/

		
		ret = SDT_OpenPort(port);
		if(ret != 0x90 ) {
			Sleep(200);
			continue;
		}

		printf("reader detected!\n");

		ret = SDT_GetSAMID(port,(unsigned char *)ID,0);
		if(ret!= 0x90) {
			SDT_ClosePort(port);
			continue;
		}
		

		ret = SDT_GetSAMID(port,(unsigned char *)ID,0);
		if(ret!= 0x90) {
			SDT_ClosePort(port);
			continue;
		}

		printf("SAMID: %02d.%02d-%08d-%010d-%010d\n",ID[0]&0xffff,ID[0]>>16,ID[1],ID[2],ID[3]);

		ret = SDT_GetSAMIDToStr(port,str,0);
		if(ret!= 0x90) {
			SDT_ClosePort(port);
			continue;
		}

		printf("SAMID: %s\n",str);


		while(1) {


			ret = SDT_ReadBaseFPMsg(port,text,&textLen,image,&imageLen,finger,&fingerLen,0);
			if(ret == 0x90) {
				printf("read card success!(%d,%d,%d)\n",textLen,imageLen,fingerLen);
				goto success;
			}
			else if(ret < 0x21 ){
				break;
			}

			ret = SDT_StartFindIDCard(port,ManaInfo,0);
			if(ret == 0x9f) {
				printf("find card success!\n");
			}
			else  if(ret < 0x21 ){
				break;
			}
			else {
				//读取其他类型的卡片
				ReadOtherCard(port);
				Sleep(100);
				continue;
			}
			
			
			ret = SDT_SelectIDCard(port,ManaMsg,0);
			if(ret == 0x90) {
				printf("select card success!\n");
			}
			else  if(ret < 0x21 ){
				break;
			}
			else {
				printf("select failed!(ret=0x%02X)\n",ret);
				Sleep(1000);
				continue;
			}

			ret = SDT_ReadBaseFPMsg(port,text,&textLen,image,&imageLen,finger,&fingerLen,0);
			if(ret == 0x90) {
				printf("read card success!(%d,%d,%d)\n",textLen,imageLen,fingerLen);
				goto success;
			}
			else  if(ret < 0x21 ){
				break;
			}
			else  {
				printf("read card failed!(ret=0x%02X)\n",ret);
				// 读取护照的参数需要通过OCR文字识别,获得护照(或港澳通行证)的号码,生日,过期时间, 并作为参数传入
				// 所以此处传入的 "E18314949", "870623", "240615" 只是示例, 需要根据实际情况修改
				ReadPassport(port,"E18314949","870623","240615");//身份证读取失败了,尝试读取护照/港澳通行证

				Sleep(1000);
				continue;
			}

			

success:
			AppInfoLen = 0;
			ret = SDT_ReadNewAppMsg(port,AppInfo,&AppInfoLen,0);
			if(ret == 0x90){
				printf("read address success!(%d)\n",AppInfoLen);
			}
			else {
				printf("no address!(0x%x)\n",ret);
			}

			ret = SDT_ReadBaseFPMsgToFile(port,"text.txt",&textLen,"image.wlt",&imageLen,"finger.bin",&fingerLen,0);
			
			print_info2((char*)text);

			ret = GetBmpData(image,bmp,sizeof(bmp));
			if(ret > 0 ) {
				fp = fopen("image.bmp","wb+");
				if(fp) {
					fwrite(bmp,1,ret,fp);
					fclose(fp);
				}
			}

			Sleep(1000);
		}
		printf("reader removed!\n");
		
		SDT_ClosePort(port);
		
	}

	return 0;
}


八、Delphi

object Form1: TForm1
  Left = 212
  Top = 147
  Width = 1740
  Height = 900
  Caption = #27493#32852#31185#25216' '#36523#20221#35777#38405#35835#28436#31034#31243#24207
  Color = clBtnFace
  Font.Charset = DEFAULT_CHARSET
  Font.Color = clWindowText
  Font.Height = -13
  Font.Name = 'MS Sans Serif'
  Font.Style = []
  OldCreateOrder = False
  OnCreate = OnCreate
  PixelsPerInch = 120
  TextHeight = 16
  object Label1: TLabel
    Left = 16
    Top = 32
    Width = 48
    Height = 16
    Caption = #31471#21475#21495#65306
  end
  object Label2: TLabel
    Left = 16
    Top = 136
    Width = 36
    Height = 16
    Caption = #22995#21517#65306
  end
  object Label3: TLabel
    Left = 16
    Top = 176
    Width = 36
    Height = 16
    Caption = #24615#21035#65306
  end
  object Label4: TLabel
    Left = 184
    Top = 176
    Width = 36
    Height = 16
    Caption = #27665#26063#65306
  end
  object Label5: TLabel
    Left = 16
    Top = 208
    Width = 60
    Height = 16
    Caption = #20986#29983#26085#26399#65306
  end
  object Label6: TLabel
    Left = 16
    Top = 240
    Width = 36
    Height = 16
    Caption = #20303#22336#65306
  end
  object Label7: TLabel
    Left = 16
    Top = 328
    Width = 72
    Height = 16
    Caption = #36523#20221#35777#21495#30721#65306
  end
  object Label8: TLabel
    Left = 16
    Top = 368
    Width = 60
    Height = 16
    Caption = #31614#21457#26426#20851#65306
  end
  object Label9: TLabel
    Left = 16
    Top = 400
    Width = 60
    Height = 16
    Caption = #26377#25928#26399#38480#65306
  end
  object Label10: TLabel
    Left = 16
    Top = 72
    Width = 54
    Height = 16
    Caption = 'SAMID'#65306
  end
  object Label11: TLabel
    Left = 16
    Top = 104
    Width = 60
    Height = 16
    Caption = #21345#29255#24207#21495#65306
  end
  object Image1: TImage
    Left = 296
    Top = 104
    Width = 105
    Height = 105
  end
  object txtName: TEdit
    Left = 136
    Top = 136
    Width = 137
    Height = 24
    ReadOnly = True
    TabOrder = 0
  end
  object txtGender: TEdit
    Left = 136
    Top = 168
    Width = 41
    Height = 24
    ReadOnly = True
    TabOrder = 1
  end
  object btRead: TButton
    Left = 392
    Top = 32
    Width = 75
    Height = 25
    Caption = #35835#21345
    TabOrder = 2
    OnClick = btReadClick
  end
  object btOpen: TButton
    Left = 280
    Top = 32
    Width = 97
    Height = 25
    Caption = #25171#24320#31471#21475
    TabOrder = 3
    OnClick = btOpenClick
  end
  object cbPort: TComboBox
    Left = 136
    Top = 32
    Width = 129
    Height = 24
    ItemHeight = 16
    TabOrder = 4
    Text = '0'
  end
  object txtBirthday: TEdit
    Left = 136
    Top = 200
    Width = 137
    Height = 24
    ReadOnly = True
    TabOrder = 5
  end
  object txtAddress: TEdit
    Left = 136
    Top = 232
    Width = 209
    Height = 24
    ReadOnly = True
    TabOrder = 6
  end
  object txtNumber: TEdit
    Left = 136
    Top = 328
    Width = 209
    Height = 24
    ReadOnly = True
    TabOrder = 7
  end
  object txtIssuer: TEdit
    Left = 136
    Top = 360
    Width = 209
    Height = 24
    ReadOnly = True
    TabOrder = 8
  end
  object txtValid: TEdit
    Left = 136
    Top = 392
    Width = 209
    Height = 24
    ReadOnly = True
    TabOrder = 9
  end
  object txtSAMID: TEdit
    Left = 136
    Top = 64
    Width = 241
    Height = 24
    ReadOnly = True
    TabOrder = 10
  end
  object StatusBar1: TStatusBar
    Left = 0
    Top = 834
    Width = 1722
    Height = 19
    Panels = <
      item
        Width = 250
      end
      item
        Width = 450
      end>
  end
  object txtRace: TEdit
    Left = 232
    Top = 168
    Width = 41
    Height = 24
    ReadOnly = True
    TabOrder = 12
  end
  object txtCardSn: TEdit
    Left = 136
    Top = 104
    Width = 137
    Height = 24
    ReadOnly = True
    TabOrder = 13
  end
end

九、阿雪技术观


拥抱开源与共享,见证科技进步奇迹,畅享人类幸福时光!

让我们积极投身于技术共享的浪潮中,不仅仅是作为受益者,更要成为贡献者。无论是分享自己的代码、撰写技术博客,还是参与开源项目的维护和改进,每一个小小的举动都可能成为推动技术进步的巨大力量

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2171965.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

电脑桌面美化用什么软件?精选6款桌面文件管理工具,小白秒变大师!

随着电脑在日常生活和工作中的普及&#xff0c;越来越多的用户开始重视电脑桌面美化的需求。单调的桌面背景和杂乱的文件排列已经无法满足我们对个性化与效率的追求。许多用户渴望找到合适的桌面整理工具&#xff0c;使他们的电脑桌面不仅美观&#xff0c;还能提升工作效率。为…

艺术家刘欢近况时隔5年再登《歌手》舞台,国家级嗓音引发热议

在我国&#xff0c;有这样一位艺术家&#xff0c;他自上世纪80年代至今&#xff0c;用一首首脍炙人口的歌曲和他那独特的嗓音陪伴数代人成长。凭借音乐上的造诣和天赋&#xff0c;他被众多网友誉为“音乐教父”&#xff1b;攀登至领域巅峰时&#xff0c;他不忘提携后辈&#xf…

低代码平台推荐与对比,国内外哪家更胜一筹?

低代码开发通过图形界面简化开发&#xff0c;提升速度与协作&#xff0c;降低成本。国内外平台如ZohoCreator、OutSystems等各具特色&#xff0c;支持快速开发、集成与数据安全。企业可试用后按需选择&#xff0c;降低决策成本。 一、低代码是什么&#xff1f; 低代码开发是一…

如何组织一场考试并筛选未参加答题的考生?

&#x1f64b;频繁有小伙伴咨询&#xff1a;我组织了一场答题活动&#xff0c;导出考试成绩时只有参加了答题的人&#xff0c;但我想要找到哪些人没答题 此前我们会建议小伙伴逐人排查&#xff0c;但这建议被反复吐槽&#x1f926; 确实&#xff0c;如果只有十几个人逐人排查还…

一家5口全感染?幽门螺杆菌筛查的意义!

近日&#xff0c;浙江的一家医院消化内科专家接诊了一名因感染幽门螺杆菌多年而罹患胃癌的患者。糟糕的是&#xff0c;他一家5口全感染了这种菌。2023年底&#xff0c;浙江杭州李先生&#xff08;化名&#xff09;在公司组织体检时查出幽门螺杆菌阳性。但他也不知道自己是何时、…

HTML基础用法介绍一

VS code 如何快速生成HTML骨架注释是什么&#xff1f;为什么要写注释&#xff1f;注释的标签是什么&#xff1f;标题标签段落标签换行标签与水平线标签 (都是单标签&#xff09;文本格式化标签图片标签超链接标签音频标签视频标签 &#x1f698;正片开始 VS code 如何快速生成…

相亲交友系统的社会影响:家庭结构的变化

随着互联网技术的发展&#xff0c;相亲交友系统已成为许多单身人士寻找伴侣的重要途径。这些平台不仅改变了人们的社交方式&#xff0c;还对家庭结构产生了深远的影响。本文将探讨相亲交友系统如何促使家庭结构发生变化&#xff0c;开发h17711347205并通过简单的Python代码示例…

【bug fixed】hexo d的时候Spawn failed

在执行hexo d部署的时候&#xff0c;遇到报错&#xff1a; % hexo d INFO Validating config INFO Deploying: git INFO Clearing .deploy_git folder... INFO Copying files from public folder... INFO Copying files from extend dirs... [main 8e89088] Site updated…

信息学奥赛的最佳启蒙阶段是小学还是初中?

信息学奥赛&#xff08;NOI&#xff09;近年来越来越受家长和学生的关注&#xff0c;尤其是在编程教育不断升温的背景下&#xff0c;信息学竞赛成为了许多家庭的教育选择之一。家长们往往关心的是&#xff1a;孩子应该在什么年龄段开始接触信息学竞赛&#xff0c;才能打下坚实的…

设计模式 之 —— MVC模式

目录 什么是MVC模式&#xff1f; MVC 工作流程&#xff1a; MVC模式&#xff08;java示例.部分代码&#xff09; 1、Model java 2、View HTML CSS JS 3、Controller java 运行结果&#xff1a; 适用场景&#xff1a; 什么是MVC模式&#xff1f; MVC模式提供了灵活…

基于 C# 的文本文件的编码识别

基于 C# 的文本文件的编码识别 前言一、有 BOM 文件头二、无 BOM 文件头三、简体中文汉字编码四、C# 程序对编码的识别1、文件选择按钮代码&#xff1a;2、获取文件编码&#xff0c;有 BOM 的文件识别3、获取文件编码&#xff0c;UTF8 无 BOM 文件的识别4、获取文件编码&#x…

如何有效应对商标撤三挑战?

商标撤三作为商标法中的一项重要制度&#xff0c;时刻考验着企业的商标维护与保护能力。面对这一挑战&#xff0c;企业如何构建一套有效的商标撤三管理体系&#xff0c;以确保自身品牌权益不受侵害&#xff0c;成为了一个亟待解决的问题。 理解商标撤三制度的核心要义 商标撤三…

【MyBatis 源码拆解系列】执行 Mapper 接口的方法时,MyBatis 怎么知道执行的哪个 SQL?

欢迎关注公众号 【11来了】 &#xff0c;持续 MyBatis 源码系列内容&#xff01; 在我后台回复 「资料」 可领取编程高频电子书&#xff01; 在我后台回复「面试」可领取硬核面试笔记&#xff01; 文章导读地址&#xff1a;点击查看文章导读&#xff01; 感谢你的关注&#xff…

web前端-CSS字体属性

CSS Fonts(字体)属性用于定义字体系列、大小、粗细、和文字样式(如斜体)。 一、字体 1.字体系列 CSS使用font-family属性定义文本的字体系列 例如&#xff1a; <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8">&l…

vmware-toolbox安装,VMware虚拟机访问win10共享目录

问题&#xff1a;VMware界面无法安装vmware-toolbox&#xff0c;共享目录设置失败 解决方法&#xff1a; VMware设置 共享文件夹 ubuntu24 vm中运行vmware-toolbox-cmd -v 检查版本 vm运行sudo apt install open-vm-tools // vm可能需要重启 vm的 /mnt 目录下如果没有 hgfs…

UE5 C++: 插件编写04 | 增加和删改前缀

准备工作 UObject* Asset UObject* Asset 通常指的是一个指向UObject的指针。UObject是Unreal Engine中的基类&#xff0c;几乎所有的引擎对象都继承自UObject。这个指针可以引用任何派生自UObject的对象&#xff0c;比如蓝图、材质、贴图、音频资源等资产。 如果你看到UObj…

开箱即用的大模型应用跟踪与批量测试方案

背景介绍 最近抽空参加了一个讯飞的 RAG 比赛&#xff0c;耗时两周终于在最后一天冲上了榜首。 整体的框架是基于 RAG 能力有点弱弱的 Dify 实现。在比赛调优的过程中&#xff0c;经常需要批量提交几百个问题至 Dify 获取回答&#xff0c;并需要跟踪多轮调优的效果差异。借助…

Paxos 协议详解:分布式系统一致性的基石

文章目录 1. 分布式系统与一致性问题1.1 分布式系统的定义1.2 一致性问题的起源1.3 CAP 定理及其影响1.4 分布式系统中的失败假设 2. Paxos 协议的背景与介绍2.1 Paxos 协议是什么2.3 Paxos 解决什么问题 3. Paxos 的基本原理3.1 Paxos 角色3.2 Paxos 的多数原则3.3 Paxos 协议…

Python画笔案例-068 绘制漂亮米

1、绘制漂亮米 通过 python 的turtle 库绘制 漂亮米,如下图: 2、实现代码 绘制 漂亮米,以下为实现代码: """漂亮米.py注意亮度为0.5的时候最鲜艳本程序需要coloradd模块支持,安装方法:pip install coloradd程序运行需要很长时间,请耐心等待。可以把窗口最小…

找不到MFC100U.dll,无法继续执行代码,重新安装此程序可解决此问题

概要 最近在研究中移物联的模组ML307R&#xff0c;通过二次开发 的方式对之前开发的物联网--如意控项目进行升级&#xff0c;研究了ML307R模组的开发资料&#xff0c;中移物联的模组二次开发难度确实很高&#xff0c;中移物联ML307R的openCPU开发采用的事C语言开发的&#xff0…