JS调用web hid api接口驱动RFID读卡器读取IC卡号


`

<html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>Web HID Api IC卡读卡器Demo</title>
<script language="javascript">
	var time1;
	let device;   // 需要连接或已连接的设备

	if ('hid' in navigator){
		
	}else{
	    alert('您的浏览器不支持 Web Hid API,暂无法使用以下功能!');
	}

	navigator.hid.onconnect = function event() {
	    console.log("hid device connected: ", event.target);
	}

	navigator.hid.ondisconnect = function event() {
	    console.log("hid device disconnected: ", event.target);
	}

	function ParsedReturnData(databuff){
	    var datahex="";
	    if(databuff[0]==0x78 && databuff[1]==0x68 && databuff.length>4){
	        switch ( databuff[3]) {
	            case 0x0f:
	                textarea.value="读卡器已接受响声指令!";
	                break;
	            case 0x1E:
	                textarea.value="读取设备编号成功!";
	                for (i=5;i<9;i++){datahex=datahex+databuff[i].toString(16).padStart(2, '0').toUpperCase();}
	                serialnumber.value=datahex;
	                break;
	            case 0xF0:
	                switch(databuff[4]){
	                    case 0x00:
	                        textarea.value="读取IC卡号成功!";
	                        for (i=5;i<9;i++){datahex=datahex+databuff[i].toString(16).padStart(2, '0').toUpperCase();}
	                        carduid.value=datahex;

	                        card8h10dz.value = parseInt("0x" + datahex).toString().padStart(10, '0');

	                        LHCode = datahex.substring(6, 8) + datahex.substring(4, 6) + datahex.substring(2, 4) + datahex.substring(0, 2);
	                        card8h10df.value = parseInt("0x" + LHCode).toString().padStart(10, '0');

	                        break;
	                    case 0x08:
	                        textarea.value="寻卡失败,请重新将卡片放在读卡器感应区!";
	                        break;
	                    case 0x09:
	                        textarea.value="选卡失败,此卡可能不是Mifare卡或感应区内有多张卡!";
	                        break;
	                    default:
	                        textarea.value="寻卡失败,错误代码:"+databuff[4].toString();
	                        break;
	                }
	                break;
	            case 0x10:
	                switch(databuff[4]){
	                    case 0x00:
	                        textarea.value="读取Ntag卡UID成功!";
	                        for (i=5;i<12;i++){datahex=datahex+databuff[i].toString(16).padStart(2, '0').toUpperCase();}
	                        ntaguid.value=datahex;
	                        break;
	                    case 0x08:
	                        textarea.value="寻卡失败,请重新将Ntag卡放在读卡器感应区!";
	                        break;
	                    case 0x09:
	                        textarea.value="选卡失败,此卡可能不是Ntag卡或感应区内有多张卡!";
	                        break;
	                    default:
	                        textarea.value="寻卡失败,错误代码:"+databuff[4].toString();
	                        break;
	                }
	                break;
	            case 0x21:
	                switch(databuff[4]){
	                    case 0x00:
	                        textarea.value="读取15693卡UID成功!";
	                        for (i=7;i<15;i++){datahex=datahex+databuff[i].toString(16).padStart(2, '0').toUpperCase();}
	                        uid15693.value=datahex;
	                        break;
	                    case 0x08:
	                        textarea.value="寻卡失败,请重新将15693卡放在读卡器感应区!";
	                        break;
	                    case 0x09:
	                        textarea.value="选卡失败,此卡可能不是15693卡!";
	                        break;
	                    default:
	                        textarea.value="寻卡失败,错误代码:"+databuff[4].toString();
	                        break;
	                }
	                break;
	            case 0x50:
	                switch(databuff[4]){
	                    case 0x00:
	                        textarea.value="读取二代证UID成功!";
	                        for (i=5;i<13;i++){datahex=datahex+databuff[i].toString(16).padStart(2, '0').toUpperCase();}
	                        sfzuid.value=datahex;
	                        break;
	                    case 0x08:
	                        textarea.value="寻卡失败,请重新将二代证卡放在读卡器感应区!";
	                        break;
	                    default:
	                        textarea.value="寻卡失败,错误代码:"+databuff[4].toString();
	                        break;
	                }
	                break;
	            case 0x51:
	                switch(databuff[4]){
	                    case 0x00:
	                        textarea.value="读取iCLASS卡UID成功!";
	                        for (i=5;i<13;i++){datahex=datahex+databuff[i].toString(16).padStart(2, '0').toUpperCase();}
	                        iclassuid.value=datahex;
	                        break;
	                    case 0x08:
	                        textarea.value="寻卡失败,请重新将iCLASS卡片放在读卡器感应区!";
	                        break;
	                    default:
	                        textarea.value="寻卡失败,错误代码:"+databuff[4].toString();
	                        break;
	                }
	                break;
	            default:

	        }
	    }
	}

	async function selectdev() {
	    try{
	        //const devices = await navigator.hid.requestDevice({ filters: [] });
	        //if (devices.length == 0) {
	        //    console.log("No device selected\n\n");
	        //    return;
	        //}
	        const devices = await navigator.hid.requestDevice({
	            filters: [{
	                vendorId: 0x0801,    // 根据VID进行过滤
	                productId: 0x2011,   // 根据PID进行过滤
	                //usagePage: 0x0c,   // 根据usagePage进行过滤
	                //usage: 0x01,       // 根据usage进行过滤
	            },],
	        });

	        device = devices[0];         // 选择列表中第一个设备
	        if (!device.opened) {        // 检查设备是否打开		            
	            await device.open();     // 打开设备
	        }
	        
	        device.oninputreport = (event) => {     // 电脑接收到来自设备的消息回调
	            console.log(event);                 // event中包含device、reportId、data等内容

	            let array = new Uint8Array(event.data.buffer); // event.data.buffer就是接收到的inputreport包数据了
	            ParsedReturnData(array);    
	            //let hexstr = "";
	            //for (const data of array) {
                //    hexstr += (Array(2).join(0) + data.toString(16).toUpperCase()).slice(-2) + " "; // 将字节数据转换成(XX )形式字符串
	            //}
	            //textarea.value += hexstr;                        		                                        
	        };
	    }
		catch (e){
	        console.log(e);
	    }
    }

	
    function isUIntNum(val) {
        var testval = /^\d+$/; // 非负整数
        return (testval.test(val));
    }

    function isHex(val) {
        var testval = /^(\d|[A-F]|[a-f])+$/; // 十六进制数判断
        return (testval.test(val));
    }

    function ButtonDisable() {  //删除按键的 onclick 事件,防止重复执行指令                 
        document.getElementById("butt_beep").setAttribute("onclick", null);
        document.getElementById("butt_getdevnum").setAttribute("onclick", null);
        document.getElementById("butt_piccrequest").setAttribute("onclick", null);
        //document.getElementById("butt_readloop").setAttribute("onclick", null);
    }

    async function beep() {				     //驱动发卡器响声令            
        if (!device?.opened) {
            alert("请先选择已连接的读卡器!");
            return;
        }
        textarea.value = "";

        const outputData = new Uint8Array(32);
        outputData[0]=0x78;     
        outputData[1]=0x68;   
        outputData[2]=0x04;
        outputData[3]=0x0f;
        outputData[4]=0x1e;
        outputData[5]=0x00;
        outputData[6]=0xe9;
        outputData[7]=0x00;            
        await device.sendReport(0, outputData); // 发送数据,第一个参数为reportId,填0表示不使用reportId
    }
	
    async function getdevicenumber() {         //读取发卡器唯一出厂序号,可以当加密狗使用			
        if (!device?.opened) {
            alert("请先选择已连接的读卡器!");
            return;
        }
        textarea.value = "";	
        serialnumber.value="";

        const outputData = new Uint8Array(32);
        outputData[0]=0x78;     
        outputData[1]=0x68;   
        outputData[2]=0x01;
        outputData[3]=0x1e;
	    
        await device.sendReport(0, outputData); // 发送数据,第一个参数为reportId,填0表示不使用reportId
    }			
	
    async function piccrequest() {
        if (!device?.opened) {
            alert("请先选择已连接的读卡器!");
            return;
        }
        textarea.value = "";		
        carduid.value="";
        card8h10dz.value="";
        card8h10df.value="";

        const outputData = new Uint8Array(32);
        outputData[0]=0x78;     
        outputData[1]=0x68;   
        outputData[2]=0x01;
        outputData[3]=0xf0;
	    
        await device.sendReport(0, outputData); // 发送数据,第一个参数为reportId,填0表示不使用reportId
    }
	
    function request_loop() {
        if (!device?.opened) {
            alert("请先选择已连接的读卡器!");
            return;
        }
        if (document.getElementById('butt_readloop').value == '轮询读取M1卡UID') {
            document.getElementById('butt_readloop').value = '停止轮询';
            ButtonDisable();
            time1 = setInterval("piccrequest()", 500);             //开启间隔500毫秒寻一次卡
        } else {
            document.getElementById('butt_readloop').value = '轮询读取M1卡UID';
            clearInterval(time1);
            ButtonEnabled();
        }
    }

    async function sfzrequest() {
        if (!device?.opened) {
            alert("请先选择已连接的读卡器!");
            return;
        }
        textarea.value = "";		
        sfzuid.value="";

        const outputData = new Uint8Array(32);
        outputData[0]=0x78;     
        outputData[1]=0x68;   
        outputData[2]=0x01;
        outputData[3]=0x50;
	    
        await device.sendReport(0, outputData); // 发送数据,第一个参数为reportId,填0表示不使用reportId
    }

    async function iclassrequest() {
        if (!device?.opened) {
            alert("请先选择已连接的读卡器!");
            return;
        }
        textarea.value = "";		
        sfzuid.value="";

        const outputData = new Uint8Array(32);
        outputData[0]=0x78;     
        outputData[1]=0x68;   
        outputData[2]=0x01;
        outputData[3]=0x51;
	    
        await device.sendReport(0, outputData); // 发送数据,第一个参数为reportId,填0表示不使用reportId
    }
    
    async function ntagrequest() {
        if (!device?.opened) {
            alert("请先选择已连接的读卡器!");
            return;
        }
        textarea.value = "";		
        ntaguid.value="";

        const outputData = new Uint8Array(32);
        outputData[0]=0x78;     
        outputData[1]=0x68;   
        outputData[2]=0x01;
        outputData[3]=0x10;
	    
        await device.sendReport(0, outputData); // 发送数据,第一个参数为reportId,填0表示不使用reportId
    }

    async function iso15693request(){
        if (!device?.opened) {
            alert("请先选择已连接的读卡器!");
            return;
        }
        textarea.value = "";		
        uid15693.value="";

        const outputData = new Uint8Array(32);
        outputData[0]=0x78;     
        outputData[1]=0x68;   
        outputData[2]=0x0d;
        outputData[3]=0x21;
        outputData[4]=0x16;
        outputData[15]=0xdd;
        await device.sendReport(0, outputData); // 发送数据,第一个参数为reportId,填0表示不使用reportId
    }

	function ButtonEnabled() {  //恢复各button 的onclick事件            
	    document.getElementById("butt_beep").setAttribute("onclick", "beep()");
	    document.getElementById("butt_getdevnum").setAttribute("onclick", "getdevicenumber()");
	    document.getElementById("butt_piccrequest").setAttribute("onclick", "piccrequest()");
	    //document.getElementById("butt_readloop").setAttribute("onclick", "request_loop()");		    
	}
							
	window.onerror = function (e) {
	    ButtonEnabled();  //恢复按键的onclick事件
	    clearInterval(time1);
	    document.getElementById('butt_readloop').value = '轮询读取IC卡卡号';
        alert("不好意思,出错了!");
        return true;//屏蔽系统事件
    }


</script>

<style>
	th {
	  background-color:#F6FAFF;	
	  color: blue;
	  font-family:楷体;
	}
	td {
	  background-color:#F6FAFF;		
	  font-family:楷体;
	}  
</style>    
</head> <body> <table width="866" height="346" align="center"> <tr> <th width="124" height="45" scope="row"><input style="width:120px" name="butt_selectdev" type="submit" id="butt_selectdev" onclick="selectdev()" value="选择连接的读卡器" /></th> <td width="716">
    </td>
</tr>
设备编号:

原始16进制卡号: ,转8H10D正码: ,8H10D反码:
<tr>
    <th width="124" height="45" scope="row"><input style="width:120px" name="butt_sfzrequest" type="submit" id="butt_sfzrequest" onclick="sfzrequest()" value="读取二代证UID" /></th>
    <td >原始16进制卡号:<input style="color:red;text-align:center;" name="sfzuid" type="text" id="sfzuid" size="16" maxlength="16" />

    </td>
</tr>

<tr>
    <th width="124" height="45" scope="row"><input style="width:120px" name="butt_iclassrequest" type="submit" id="butt_iclassrequest" onclick="iclassrequest()" value="读取iCLASS卡UID" /></th>
    <td>
        原始16进制卡号:<input style="color:red;text-align:center;" name="iclassuid" type="text" id="iclassuid" size="16" maxlength="16" />
    </td>
</tr>

<tr>
    <th width="124" height="45" scope="row"><input style="width:120px" name="butt_ntagrequest" type="submit" id="butt_ntagrequest" onclick="ntagrequest()" value="读取Ntag卡UID" /></th>
    <td>
        原始16进制卡号:<input style="color:red;text-align:center;" name="ntaguid" type="text" id="ntaguid" size="16" maxlength="16" />
    </td>
</tr>

<tr>
    <th width="124" height="45" scope="row"><input style="width:120px" name="butt_15693request" type="submit" id="butt_15693request" onclick="iso15693request()" value="读取15693卡UID" /></th>
    <td>
        原始16进制卡号:<input style="color:red;text-align:center;" name="uid15693" type="text" id="uid15693" size="16" maxlength="16" />
    </td>
</tr>

 

操作提示

 

以上功能使用Web HID API技术,请使用支持Web HID API的浏览器!

`

posted @ 2025-03-01 09:34  津津有味0202  阅读(198)  评论(0)    收藏  举报