const app = getApp(); import {tools} from "../des3/nfcTool" Component({ options: { addGlobalClass: true, multipleSlots: true, }, properties: { scanType: { type: Number, value: 1, }, scanTxt: { value: '', }, }, data: { reading:false, key:"", nfc:"", debug:1, keyA:[0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7], keyB:[0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF], }, pageLifetimes:{ async show() { //type值,1查看有源状态,2激活有源标签,3锁闭有源标签,4读取有源标签温度,6读取防伪标签,7读取uid this.initNfc(this.scanType) }, hide() { var nfc = this.nfc if(nfc){ nfc.offDiscovered(this.discoverHandler) } }, }, async ready(){ console.log(this.data.scanType) }, methods: { offNfc(){ return new Promise((resolve, reject)=>{ if(this.nfc){ this.nfc.offDiscovered({ complete:(r)=>{ this.nfc.stopDiscovery({ complete:(res)=>{ console.log(res) resolve() } }) } }) }else{ resolve() } }) }, async initNfc(type){//初始化NFC var that = this if(this.data.debug)console.log(this.nfcObj) if(this.nfc){ await this.offNfc() } this.type = type this.type = this.data.scanType const nfc = wx.getNFCAdapter() this.nfc = nfc return new Promise(async (resolve, reject)=>{ this.nfc.onDiscovered(res=>{//监听NFC接近 this.type = this.data.scanType var techs = res.techs this.techTime = new Date().getTime() this.nfcObj = this.nfc.getIsoDep(); //连接NFC this.nfcObj.connect({ success:async (resc)=>{ this.setData({reading:true}) var temp = {} //ACCESS验证 await this.COS_Access() //读取有源标签温度 if(this.type==4)temp =await this.read_yy() //检查有源标签状态 if(this.type==1)temp =await this.check_yy_status() //激活有源标签 if(this.type==2)temp =await this.active_yy() //锁闭有源标签 if(this.type==3)temp =await this.close_yy() //读取防伪标签 if(this.type==6)temp =await this.read_fw() //读取uid if(this.type==7)temp =await this.read_uid() //读取自定义信息 if(this.type==8)temp =await this.read_data() //写入自定义信息 if(this.type==9)temp =await this.write_data(this.data.scanTxt) //读采温周期 if(this.type==10)temp =await this.read_interval() //读采温周期 if(this.type==11)temp =await this.write_interval(this.data.scanTxt) //x106读取自定义信息和温度数据 if(this.type==101)temp =await this.x106_end() //x106读取自定义信息和温度数据 if(this.type==102)temp =await this.x106_start(this.data.scanTxt) this.setData({reading:false}) this.triggerEvent('setNfcRes', temp) resolve(temp) }, fail:err=>{ if(this.data.debug)console.log("connect",err) reject(err) } }) }) this.nfc.startDiscovery({ fail(err) { //app.globalData?.nonfc = true reject(err) } }) }) }, async COS_Access(){ await this.authNfc() var trnd = await this.setApdu([0xA2, 0xB0, 0x00, 0x10, 0x10]) await this.calcKey(trnd) }, sleep(ms){ return new Promise(resolve => setTimeout(resolve, ms)) }, authNfc(){ return new Promise(async (resolve, reject)=>{ var authRes = await this.setApdu([0xA2, 0xA4, 0x00, 0x0C, 0x02, 0xAC, 0x01]) if(authRes.join("") == "99192"){//[99,192] if(this.data.debug)console.log("解锁标签") await this.sleep(20) authRes = await this.setApdu([0xA2, 0xA4, 0x00, 0x0C, 0x02, 0xAC, 0x01]) } if(authRes.join("") == "1440"){//[144,0] resolve() }else{ if(this.data.debug)console.log("解锁失败") reject() } }) }, async calcKey(data){ var trnd_bytes = data.slice(0,8) var mid_bytes = data.slice(8,17) var des3_key_list = [] for(var i=0;i<8;i++){ des3_key_list[i] = trnd_bytes[i] ^ this.data.keyA[i] des3_key_list[i+8] = mid_bytes[i] ^ this.data.keyB[i] } var des3_key_bytes = tools.numArrToHex(des3_key_list)//numArrToBit(des3_key_list)// this.des3Key = des3_key_bytes // this.des3Key = "11223344556677889900AABBCCDDEEFF" //3des的KEY var random_key_bytes = tools.numArrToHex(trnd_bytes)//numArrToBit(trnd_bytes)// var trnd_encrpyt_bytes = tools.encode3des(random_key_bytes,des3_key_bytes) var command_bytes = [0xA2, 0xD6, 0x00, 0x10, 0x10] var rad = [1,2,3,4,5,6,7,8]//8位随机字节,直接写死试试 //拼三段指令 command_bytes= [...command_bytes,...tools.hexToNumArr(trnd_encrpyt_bytes),...rad] if(this.data.debug)console.log(command_bytes) rad = tools.numArrToHex(rad)//numArrToBit(rad)// trnd_encrpyt_bytes = tools.encode3des(rad,des3_key_bytes) if(this.data.debug)console.log(tools.hexToNumArr(trnd_encrpyt_bytes)) var authRes = await this.setApdu(command_bytes) return new Promise(async (resolve, reject)=>{ if(authRes.join("") == "99192"){//[99,192] if(this.data.debug)console.log("解锁标签") authRes = await this.setApdu(command_bytes) } if(authRes.join("") == "1440"){//[144,0] var trnd = await this.setApdu([0xA2, 0xB0, 0x00, 0x10, 0x10]) if(this.data.debug)console.log(trnd) if(trnd.slice(0,8).join("") == tools.hexToNumArr(trnd_encrpyt_bytes).join("")){ if(this.data.debug)console.log("验证通过1") resolve() }else{ if(this.data.debug)console.log("验证不通过") reject() } }else{ if(this.data.debug)console.log("设备异常") reject() } }) }, async read_yy(){ var data_bytes = await this.COS_Analysis(data_bytes) if(this.data.debug)console.log(data_bytes) return {data_bytes,timeUsed:new Date().getTime() - this.techTime} }, async COS_Analysis(){ await this.setApdu([0xA2, 0xA4, 0x00, 0x0C, 0x02, 0xDA, 0x01]) var data_bytes = await this.ISO14443_4A_ReadBinary(0xA2, 0, 80, 56) var data_bias = 24 var uid = data_bytes.substring(data_bias + 0, data_bias + 52) var CID_bytes = data_bytes.substring(data_bias + 0, data_bias + 4) var TID_bytes = data_bytes.substring(data_bias + 4, data_bias + 16) var GTIN_bytes = data_bytes.substring(data_bias + 16, data_bias + 36) var VID_bytes = data_bytes.substring(data_bias + 36, data_bias + 52) var MID_bytes = data_bytes.substring(data_bias + 52, data_bias + 68) var MAC_bytes = data_bytes.substring(data_bias + 68, data_bias + 84) var TRNG_bytes = data_bytes.substring(data_bias + 84, data_bias + 100) var PAGE_bytes = data_bytes.substring(data_bias + 100, data_bias + 102) var RNUM_bytes = data_bytes.substring(data_bias + 102, data_bias + 110) //解析校准值 var data_Nums = tools.hexToNumArr(data_bytes) var Cal_Data = [[],[],[]] Cal_Data[0][0] = ((data_Nums[data_bias/2 + 56] >> 4) + data_Nums[data_bias/2 + 55]) / 10 Cal_Data[0][1] = data_Nums[data_bias/2 + 57] + (data_Nums[data_bias/2 + 56] & 0x0F) * 256 Cal_Data[1][0] = ((data_Nums[data_bias/2 + 59] >> 4) + data_Nums[data_bias/2 + 58]) / 10 Cal_Data[1][1] = data_Nums[data_bias/2 + 60] + (data_Nums[data_bias/2 + 59] & 0x0F) * 256 Cal_Data[2][0] = tools.hex2int((data_Nums[data_bias/2 + 62] >> 4) + tools.numArrToHex([data_Nums[data_bias/2 + 61]])) / 10 Cal_Data[2][1] = data_Nums[data_bias/2 + 63] + (data_Nums[data_bias/2 + 62] & 0x0F) * 256 //计算温度长度 var record_number_int = tools.hex2int(RNUM_bytes) var record_data_size_int = Math.ceil(record_number_int * 11 / 8) var record_data_size_mod_int = record_data_size_int % 8 if(record_data_size_mod_int){ record_data_size_int = record_data_size_int + (8 - record_data_size_mod_int) } //读取数据 const NDEF_MAX_INT = 4032 var start_address_int = 78 if ((start_address_int + record_data_size_int) > NDEF_MAX_INT){ record_data_size_int = record_data_size_int - 8 record_number_int = Math.floor(record_data_size_int * 8 / 11) } data_bytes = await this.ISO14443_4A_ReadBinary(0xA2, start_address_int, record_data_size_int, 56) data_bytes = tools.hexToNumArr(data_bytes) // 解析adc var tempture_data = [] var repeat_cnt = Math.floor(record_number_int / 8) var count_residue = record_number_int % 8 if (count_residue > 0) repeat_cnt += 1 var decode_count = 0 var temp = {} for(var i=0;i= record_number_int)break; else decode_count += 1 var adc_data_int = null if(j==0){ adc_data_int = data_bytes[i * 11] * 256 + data_bytes[i * 11 + 1] adc_data_int = (adc_data_int & 0x0000FFE0) >> 5 }else if(j==1){ adc_data_int = data_bytes[i * 11 + 1] * 256 + data_bytes[i * 11 + 2] adc_data_int = (adc_data_int & 0x00001FFC) >> 2 }else if(j==2){ adc_data_int = data_bytes[i * 11 + 2] * 65536 + data_bytes[i * 11 + 3] * 256 + data_bytes[ i * 11 + 4] adc_data_int = (adc_data_int & 0x0003FF80) >> 7 }else if(j==3){ adc_data_int = data_bytes[i * 11 + 4] * 256 + data_bytes[i * 11 + 5] adc_data_int = (adc_data_int & 0x00007FF0) >> 4 }else if(j==4){ adc_data_int = data_bytes[i * 11 + 5] * 256 + data_bytes[i * 11 + 6] adc_data_int = (adc_data_int & 0x00000FFE) >> 1 }else if(j==5){ adc_data_int = data_bytes[i * 11 + 6] * 65536 + data_bytes[i * 11 + 7] * 256 + data_bytes[ i * 11 + 8] adc_data_int = (adc_data_int & 0x0001FFC0) >> 6 }else if(j==6){ adc_data_int = data_bytes[i * 11 + 8] * 256 + data_bytes[i * 11 + 9] adc_data_int = (adc_data_int & 0x000003FF8) >> 3 }else if(j==7){ adc_data_int = data_bytes[i * 11 + 9] * 256 + data_bytes[i * 11 + 10] adc_data_int = (adc_data_int & 0x000007FF) >> 0 } adc_data_int = Math.floor(adc_data_int) temp = {} // 温度小于第二个校准点,使用第一个点和第二个点计算KB值 var tempture1,adc1,tempture2,adc2 if (adc_data_int < Cal_Data[1][1]){ tempture1 = Cal_Data[0][0] adc1 = Cal_Data[0][1] tempture2 = Cal_Data[1][0] adc2 = Cal_Data[1][1] }else{ tempture1 = Cal_Data[1][0] adc1 = Cal_Data[1][1] tempture2 = Cal_Data[2][0] adc2 = Cal_Data[2][1] } if ((adc1 - adc2) != 0){ var k = (tempture1 - tempture2) / (adc1 - adc2) var b = tempture1 - (k * adc1) var tempture_float = k * adc_data_int + b temp['temp'] = Math.round(tempture_float*10)/10 temp['adc'] = adc_data_int }else{ temp['adc'] = adc_data_int } tempture_data.push(temp) } } return { "CID": CID_bytes, "TID": TID_bytes, "GTIN": GTIN_bytes, "VID": VID_bytes, "MID": MID_bytes, "MAC": MAC_bytes, "TRNG": TRNG_bytes, "PAGE": PAGE_bytes, "RUNM": RNUM_bytes, "CAL1": { "TEMP": Cal_Data[0][0], "ADC": Cal_Data[0][1] }, "CAL2": { "TEMP": Cal_Data[1][0], "ADC": Cal_Data[1][1] }, "CAL3": { "TEMP": Cal_Data[2][0], "ADC": Cal_Data[2][1] }, 'tempture_data':tempture_data, "uid":uid, } }, async read_uid(){ await this.setApdu([0xA2, 0xA4, 0x00, 0x0C, 0x02, 0xDA, 0x01]) var data_bytes = await this.ISO14443_4A_ReadBinary(0xA2, 0, 80, 56) var data_bias = 24 var uid = data_bytes.substr(data_bias,data_bias+52) return {uid,timeUsed:new Date().getTime() - this.techTime} }, async read_fw(){ var data_bytes = await this.ISO14443_4A_ReadBinary(0xA4, 8, 8, 8) if(data_bytes?.length == 16){ //记录值 var record_adc_int_list = [tools.hex2int(data_bytes.substr(0,4)),tools.hex2int(data_bytes.substr(4,4))] //当前值 var current_adc_int_list = [tools.hex2int(data_bytes.substr(8,4)),tools.hex2int(data_bytes.substr(12,4))] if(this.data.debug)console.log('阻值为:',[record_adc_int_list,current_adc_int_list]) if(current_adc_int_list[0] && current_adc_int_list[1]){ if(record_adc_int_list[0] && record_adc_int_list[1]){ var abs0 = Math.abs(current_adc_int_list[0]-record_adc_int_list[0]) < record_adc_int_list[0]*0.01 var abs1 = Math.abs(current_adc_int_list[1]-record_adc_int_list[1]) < record_adc_int_list[0]*0.01 if(abs0 && abs1){ if(this.data.debug)console.log('标签验证通过') await this.setApdu([0xA2, 0xA4, 0x00, 0x0C, 0x02, 0xDA, 0x01]) var data_bytes = await this.ISO14443_4A_ReadBinary(0xA2, 0, 80, 56) var data_bias = 24 var uid = data_bytes.substr(data_bias,data_bias+110) return {res:'ok',uid,timeUsed:new Date().getTime() - this.techTime} }else{ if(this.data.debug)console.log('标签验证不通过') return {res:'no',uid:null,timeUsed:new Date().getTime() - this.techTime} } }else{ if(this.data.debug)console.log('标签初始化') return {res:'init',uid:null,timeUsed:new Date().getTime() - this.techTime} } }else{ if(this.data.debug)console.log('标签未放置到位,请重试') return {res:'retry',uid:null,timeUsed:new Date().getTime() - this.techTime} } }else{ if(this.data.debug)console.log('读取结果异常,请重试') return {res:'retry',uid:null,timeUsed:new Date().getTime() - this.techTime} } }, async write_data(write_bytes){ if(!write_bytes){ wx.showToast({ title: '数据写入不能为空', }) return {sta:0,msg:"写入不能为空",timeUsed:new Date().getTime() - this.techTime} } write_bytes = tools.str2NumArr(write_bytes) var len = write_bytes.length for(var i=0;i<(8-len%8);i++){ write_bytes.push(255) } if(this.data.debug)console.log(write_bytes) var data_bytes = await this.COS_Write_Config(49316, write_bytes.length,write_bytes, 56) if(data_bytes.join('') == '1440'){ return {sta:1,msg:"写入成功",timeUsed:new Date().getTime() - this.techTime} }else{ return {sta:0,msg:"写入失败,请重试",timeUsed:new Date().getTime() - this.techTime} } }, async read_data(){ const maxData = 128 var data_bytes = await this.COS_Read_Config(49316,maxData,56) var data_bytes = tools.hexToNumArr(data_bytes) var index = data_bytes.indexOf(255) index = index==-1?maxData:index data_bytes = data_bytes.slice(0,index) return {data:tools.numArrToBit(data_bytes),timeUsed:new Date().getTime() - this.techTime} }, async read_interval(){ var data_bytes = await this.COS_Read_Config(49213,16,16) console.log(data_bytes) data_bytes = data_bytes.substr(0,4) data_bytes = tools.hex2int(data_bytes) return {data:data_bytes,timeUsed:new Date().getTime() - this.techTime} }, async write_interval(idel_num){ var data_bytes = await this.COS_Read_Config(49213,16,16) idel_num = ("0000" + (parseInt(idel_num)).toString(16)).substr(-4) var write_bytes = idel_num+data_bytes.substr(4) write_bytes = tools.hexToNumArr(write_bytes) if(this.data.debug)console.log(write_bytes) var data_bytes = await this.COS_Write_Config(49213, 16,write_bytes, 16) if(data_bytes.join('') == '1440'){ return {sta:1,msg:"写入成功",timeUsed:new Date().getTime() - this.techTime} }else{ return {sta:0,msg:"写入失败,请重试",timeUsed:new Date().getTime() - this.techTime} } }, async check_yy_status(){//检查有源标签状态 var data_bytes = await this.COS_Read_Config(49162,8,8) var stateVal = tools.hexToNumArr(data_bytes)[0] if(stateVal){ stateVal = tools.num2bin(stateVal) || [] //0b11111000 py取下标为6 if(stateVal[4] == '1'){ // wx.showToast({title: '芯片已激活',}) return {sta:1,msg:"设备已激活",timeUsed:new Date().getTime() - this.techTime} } if(stateVal[4] == '0'){ // wx.showToast({title: '芯片未激活',}) return {sta:0,msg:"设备已锁闭",timeUsed:new Date().getTime() - this.techTime} } return {sta:null,msg:"读取失败",timeUsed:new Date().getTime() - this.techTime} }else{ return {sta:null,msg:"读取失败",timeUsed:new Date().getTime() - this.techTime} } }, async active_yy(){ //("NFC激活") var data_bytes = await this.COS_Write_Config(49162, 8,[0xFC, 0x03, 0x00, 0x0F, 0x20, 0x00, 0xF6, 0x00], 8) if(data_bytes.join('') == '1440'){ //NFC操作成功,开始读取并修改page var data = await this.COS_Read_Config(49458,16,16) if(this.data.debug)console.log(data) if(data&&data.length ==32){ data = tools.hexToNumArr(data) data[12] = 1 data = tools.numArrToHex(data) data_bytes = await this.COS_Write_Config(49458, 16, data, 16) if(data_bytes.join('') == '1440'){ // wx.showToast({title: 'NFC激活成功',}) if(this.data.debug)console.log("设备已激活") return {sta:1,msg:"设备已激活",timeUsed:new Date().getTime() - this.techTime} }else{ if(this.data.debug)console.log("激活失败,请重试!") // wx.showToast({title: 'NFC激活失败',}) return {sta:null,msg:"激活失败,请重试!",timeUsed:new Date().getTime() - this.techTime} } }else{ wx.showToast({title: '激活失败,请重试!',}) return {sta:null,msg:"激活失败,请重试!",timeUsed:new Date().getTime() - this.techTime} } }else{ wx.showToast({title: '激活失败,请重试!',}) return {sta:null,msg:"激活失败,请重试!",timeUsed:new Date().getTime() - this.techTime} } }, async close_yy(){ //("NFC锁闭") var data_bytes = await this.COS_Write_Config(49162, 8,[0xF0, 0x03, 0x00, 0x0F, 0x20, 0x00, 0xF6, 0x00], 8) if(data_bytes.join('') == '1440'){ //NFC操作成功,开始读取并修改page var data = await this.COS_Read_Config(49458,16,16) if(this.data.debug)console.log(data) if(data&&data.length ==32){ data = tools.hexToNumArr(data) data[12] = 0 data = tools.numArrToHex(data) data_bytes = await this.COS_Write_Config(49458, 16, data, 16) if(data_bytes.join('') == '1440'){ wx.showToast({title: '设备锁闭成功',}) return {sta:1,msg:"设备锁闭成功",timeUsed:new Date().getTime() - this.techTime} }else{ wx.showToast({title: '设备锁闭失败,请重试!',}) return {sta:null,msg:"设备锁闭失败,请重试!",timeUsed:new Date().getTime() - this.techTime} } }else{ wx.showToast({title: '设备锁闭失败,请重试!',}) return {sta:null,msg:"设备锁闭失败,请重试!",timeUsed:new Date().getTime() - this.techTime} } }else{ wx.showToast({title: '设备锁闭失败,请重试!',}) return {sta:null,msg:"设备锁闭失败,请重试!",timeUsed:new Date().getTime() - this.techTime} } }, async COS_Write_Config(address_int, length_int, write_bytes, package_size){ //选中CONFIG var data_bytes = await this.setApdu([0xA2, 0xA4, 0x00, 0x0C, 0x02, 0xCF, 0x01]) write_bytes = tools.numArrToHex(write_bytes) var data_write_bytes = tools.encode3des(write_bytes,this.des3Key) data_write_bytes = tools.hexToNumArr(data_write_bytes) data_bytes = await this.ISO14443_4A_UpdateBinary(0xA2, address_int, length_int, data_write_bytes, package_size) return new Promise(async (resolve)=>{ resolve(data_bytes) }) }, async COS_Read_Config(address_int, length_int, package_size){ //选中CONFIG var data_bytes = await this.setApdu([0xA2, 0xA4, 0x00, 0x0C, 0x02, 0xCF, 0x01]) data_bytes = await this.ISO14443_4A_ReadBinary(0xA2, address_int, length_int, package_size) return new Promise(async (resolve)=>{ resolve(data_bytes) }) }, async ISO14443_4A_ReadBinary(cla_bytes, address_start_int, length_int, package_size_int){ var data_read_bytes = [] var des3_key_int_list = [] var package_number_int = Math.floor(length_int / package_size_int) var package_bytes_left_int = length_int % package_size_int var i = 0 //读取整包数据 for(;i{ if(strTemp.length != dataList.length){wx.showToast({title: '解密失败',})} resolve(strTemp) }) }, async ISO14443_4A_UpdateBinary(cla_bytes,address_start_int, length_int, data_write_bytes, RF_PACKAGE_SIZE){ var des3_key_int_list = [] var package_size_int = RF_PACKAGE_SIZE var package_number_int = Math.floor(length_int / package_size_int) var package_bytes_left_int = length_int % package_size_int var i = 0 var data_bytes = '' // 写整包数据 for(;i{ resolve(data_bytes) }) }, setApdu(arr){ var that = this return new Promise((resolve, reject)=>{ const nfcObj = that.nfcObj var key = new Uint8Array(arr).buffer nfcObj.transceive({ data: key, success: res => { var hexData = tools.ab2NumArr(res.data) resolve(hexData) }, fail:res=>{ if(that.data.debug)console.log("transceive",res) reject(res) } }) }) }, async x106_end(){ //读温度 var data = await this.read_yy() data = data.data_bytes //读自定义信息 var str = await this.read_data() data.data = str.data //锁闭 var data = await this.close_yy() //数据汇总返回 return {data,timeUsed:new Date().getTime() - this.techTime} }, async x106_start(config){ //写入采温周期 var time = config.split(";")[1] this.write_interval(time) //写自定义信息 this.read_data(config) //激活 var data = await this.active_yy() //数据汇总返回 return {data,timeUsed:new Date().getTime() - this.techTime} }, } })