const event = require('./event'); const penDataHandle = require('./penDataHandle'); const utils = require('./utils'); class TTSDK { constructor() { // 离线接收进行量 this.gofflineDataProgress = 0 // 离线数据量 this.offlineDataNum = 0 // 进度 this.gefflineCounter = 0 // 已连接蓝牙deviceId this.connectDeviceId = null // 已连接serviceid this.connectServiceId = null // 已连接characteristicId this.connectCharacteristicId = null this.finishFlag = false this.allDevices = {} this.allDevices.foundDevices = [] this.blueToothOn = false } // 监听本地蓝牙状态 listenBlueState(blueToothON) { tt.onBluetoothAdapterStateChange(res => { if (res.available) { tt.offBluetoothAdapterStateChange() if (blueToothOn) { blueToothON(); } } }) } // 初始化蓝牙 initBlueTooth(success, fail) { tt.openBluetoothAdapter({ success: (res) => { if (success) { success() } }, fail: (res) => { if (fail) { fail() } } }) } // 读取本地蓝牙适配器状态信息 getLocalBlueToothState() { return tt.getBluetoothAdapterState({ success: (res) => { return { isDiscovering: res.discovering, isAvailable: res.available } }, }) } // 监听连接的蓝牙设备断开 listenBlueConnection() { tt.onBLEConnectionStateChange((result) => { if (this.connectDeviceId === result.deviceId && !result.connected) { event.emit('unConnect', true) } }) } // 搜索附近的蓝牙设备 searchBlueTooth(success, fail) { tt.startBluetoothDevicesDiscovery({ allowDuplicatesKey: true, success: (res) => { if (success) { success(); } }, fail: () => { if (fail) { fail() } } }) } // 查找到的设备列表 showBlueToothList(that) { let flag = true tt.onBluetoothDeviceFound(res => { res.devices.forEach(device => { let penCheck = ab2hex(device.advertisData) if (penCheck.length < 10) { return } if (penCheck.slice(0, 4).join(':').toUpperCase() !== '31:32:33:34') { return } device.macAddress = penCheck.slice(4, 10).reverse().join(':').toUpperCase(); if (this.allDevices.foundDevices.length !== 0) { flag = this.allDevices.foundDevices.every((item, index) => { return item.deviceId !== device.deviceId }) } if (flag) { this.allDevices.foundDevices.push(device) } }) // console.log(penData) that.setData({ blueToothList: this.allDevices }) }) } // 停止蓝牙搜索 stopBlueToothSearch(success, fail) { tt.stopBluetoothDevicesDiscovery({ success: (res) => { if (success) { success() } }, fail: () => { if (fail) { fail() } } }) } //释放蓝牙 closeBlueTooth(success, fail) { tt.closeBluetoothAdapter({ success: () => { if (success) { success() } }, fail: () => { if (fail) { fail() } } }) } // 创建蓝牙连接 createBlueToothConnection(deviceId, success, fail) { tt.connectBLEDevice({ deviceId, success: () => { tt.stopBluetoothDevicesDiscovery({ success: (res) => { console.log('stop') }, }) if (success) { success(); } }, fail: () => { if (fail) { fail(); } } }); }; // 断开蓝牙设备 unConnectBlueTooth(deviceId, success, fail) { tt.disconnectBLEDevice({ deviceId, success: () => { if (success) { success(); } }, fail: () => { if (fail) { fail(); } } }) } // 获取蓝牙色设备服务 getBlueToothService(deviceId, success, fail) { tt.getBLEDeviceServices({ deviceId, success: (res) => { if (success) { success() } }, fail: () => { if (fail) { fail() } } }) } // 获取蓝牙设备某个服务的所有特征值 getBlueToothCharaceristics(deviceId, serviceId) { tt.getBLEDeviceCharacteristics({ deviceId, serviceId, success: (res) => { res.characteristics.forEach((item) => { if (item.properties.notify || item.properties.indicate) { tt.notifyBLECharacteristicValueChange({ state: true, deviceId, serviceId, characteristicId: item.uuid, success: () => { console.log('notifyBLECharacteristicValueChange success------: ' + res.errMsg) } }) } // 向蓝牙写数据 if (item.properties.write && item.uuid == '0000F102-0000-1000-8000-00805F9B34FB') { this.connectDeviceId = deviceId this.connectServiceId = serviceId this.connectCharacteristicId = item.uuid } }) this.getPenModal(); this.setRTCTime(new Date().getTime()) }, fail: () => { } }) // 监听 第一时间获取数据 tt.onBLECharacteristicValueChange((res) => { switch (res.characteristicId) { // 实时数据 case "0000FFF1-0000-1000-8000-00805F9B34FB": var dataArr = ab2hex(characteristic.value) let dataLength = dataArr.length / 10 for (let i = 0; i < dataLength; i++) { penDataHandle.splitData(hex2Bytes(dataArr.slice(i * 10, (i + 1) * 10))) } break; // 离线数据 case '0000F202-0000-1000-8000-00805F9B34FB': let dataArray = ab2hex(res.value) let dataLength1 = dataArray.length / 10 for (let i = 0; i < dataLength1; i++) { let newArr = dataArray.slice(i * 10, (i + 1) * 10) let arr = hex2Bytes(newArr) penDataHandle.splitData(arr, false) } break; case "0000F101-0000-1000-8000-00805F9B34FB": let dataArr1 = ab2hex(res.value) let arr = hex2Bytes(dataArr1); getDataInfo(arr, this); break; default: break; } }) } // 写入总封装 dealData(index, arrData, success, fail) { let buffer = new ArrayBuffer(index) let bufferView = new DataView(buffer) for (let i = 0; i < index; i++) { bufferView.setUint8(i, arrData[i]) } tt.writeBLECharacteristicValue({ characteristicId: this.connectCharacteristicId, serviceId: this.connectServiceId, deviceId: this.connectDeviceId, value: buffer, success: () => { if (success) { success(); } }, fail: () => { if (fail) { fail() } } }) } // 写入笔名 setPenName(penName, success, fail) { let strBytesArr = strToUtf8(penName); let byteLength = strBytesArr.length; let offLineBuffer = new ArrayBuffer(byteLength + 2); let DataViews = new DataView(offLineBuffer); DataViews.setUint8(0, 0xA2); DataViews.setUint8(1, byteLength); for (let i = 0; i < byteLength; i++) { DataViews.setUint8(i + 2, strBytesArr[i]) } tt.writeBLECharacteristicValue({ characteristicId: this.connectCharacteristicId, serviceId: this.connectServiceId, deviceId: this.connectDeviceId, value: buffer, success: () => { if (success) { success(); } }, fail: () => { if (fail) { fail() } } }) } // 请求笔名 getPenName(success, fail) { this.dealData(3, [0xa0, 0x01, 0xff], success, fail) } // 获取MAC地址 getMACAddress(success, fail) { this.dealData(3, [164, 1, 255], success, fail) } // 获取蓝牙固件版本 getPenFirmWare(success, fail) { this.dealData(3, [0xa6, 0x01, 0xff], success, fail) } // 获取剩余电量 getPenBattery(success, fail) { this.dealData(3, [0xa8, 0x01, 0xff], success, fail) } // 写入rtc时间 // 传入时间为想改写时间的时间戳 setRTCTime(RTCTime, success, fail) { let timeStamp = (RTCTime - 1262275200000) / 1000; console.log(timeStamp, 'timestamp') this.dealData(6, [0xac, 0x04, timeStamp & 0xff, (timeStamp >> 8) & 0xff, (timeStamp >> 16) & 0xff, (timeStamp >> 24) & 0xff], success, fail); } // 请求rtc时间 getRTCTime(success, fail) { this.dealData(3, [0xaa, 0x01, 0xff], success, fail) } // 写入自动关机时间 setPenAutoOff(offTime, success, fail) { if (offTime > 120 || offTime < 0) { return console.error('自动关机时间的范围为0~120') } this.dealData(4, [0xb2, 0x02, offTime % 256, offTime / 256], success, fail) } // 请求自动关机时间 getPenAutoOff(success, fail) { this.dealData(3, [0xb0, 0x01, 0xff], success, fail) } // 获取已使用内存 getPenMemory(success, fail) { this.dealData(3, [0xb6, 0x01, 0xff], success, fail) } // 获取是否点笔开机 getPenClickMode(success, fail) { this.dealData(3, [0xb8, 0x01, 0xff], success, fail) } // 设置点笔开机 setPenClickMode(isClick, success, fail) { this.dealData(3, [0xba, 0x01, isClick ? 0x01 : 0x00], success, fail) } // 设置是否蜂鸣 setPenBeep(isOn, success, fail) { this.dealData(3, [0xbe, 0x01, isOn ? 0x01 : 0x00], success, fail) } // 获取是否蜂鸣 getPenBeep(success, fail) { this.dealData(3, [0xbc, 0x01, 0xff], success, fail) } // 恢复出厂设置 restoreFactory(success, fail) { this.dealData(3, [0xb4, 0x01, 0xff, success, fail]) } // 写入压力敏感度 setPenSensor(level, success, fail) { this.dealData(3, [0xd2, 0x01, level], success, fail) } // 获取压力敏感度 getPenSensor(success, fail) { this.dealData(3, [0xd0, 0x01, 0xff], success, fail) } // 设置LED灯颜色 setPenLedColor(color, success, fail) { this.dealData(3, [0xd6, 0x01, color], success, fail) } // 获取led颜色 getPenLedColor(success, fail) { this.dealData(3, [0xd4, 0x01, 0xff], success, fail) } // 获取压力校正值 getPenSensorRegulate(success, fail) { this.dealData(3, [0xd8, 0x01, 0xff], success, fail) } // 获取mcu固件版本 getMCUVersion(success, fail) { this.dealData(3, [0xda, 0x01, 0xff], success, fail) } // 获取笔的类型 getPenModal(success, fail) { this.dealData(3, [0xe4, 0x01, 0xff], success, fail) } // 获取点码类型 getPenPointType(success, fail) { this.dealData(3, [0xe6, 0x01, 0xff], success, fail) } // led设置开关 setLedConfig(isOn, success, fail) { this.dealData(3, [0xee, 0x01, isOn ? 0x01 : 0x00], success, fail) } // 获取led是够可以设置的结果 getLedConfig(success, fail) { this.dealData(3, [0xec, 0x01, 0xff], success, fail) } // 获取离线数据量大小 getPenOfflineDataSize(success, fail) { this.dealData(3, [0xc0, 0x01, 0xff], success, fail) } // 开始获得离线数据 startGetOfflineData(success, fail) { this.dealData(3, [0xc2, 0x01, 0x00], success, fail) } // 停止获得离线数据 stopGetOfflineData(success, fail) { this.dealData(3, [0xc2, 0x01, 0x01], success, fail) } // 暂停获得离线数据 pauseGetOfflineData(success, fail) { this.dealData(3, [0xcb, 0x01, 0x00], success, fail) } // 继续获得离线数据 continueGetOfflineData(success, fail) { this.dealData(3, [0xcb, 0x01, 0x01], success, fail) } // 删除离线数据 deleteOfflineData(success, fail) { this.dealData(3, [0xc8, 0x01, 0xff], success, fail) } // 确认离线数据已经接受完毕 confirmOfflineDataDone(success, fail) { this.dealData(3, [0xc6, 0x01, this.finishFlag ? 0x00 : 0x01], success, fail) } } // arrayBuffer转16进制字符串数组 const ab2hex = (buffer) => { return Array.prototype.map.call(new Uint8Array(buffer), x => ('00' + x.toString(16)).slice(-2)) } // hex to bytes const hex2Bytes = (arr) => { return arr.map((item) => { return parseInt(item, 16) }) } const getDataInfo = (lpData, doneFlag) => { // console.log(doneFlag) const data = {}; let len = 0; let val = lpData.slice(2, len + 2); switch (lpData[0]) { case 0xa1: len = lpData[1] & 0xff; val = byteToString(lpData.slice(2, len + 2)); emitData({ data: val, cmd: 'getPenName' }) break; case 0xa3: if (lpData[2] === 0x00) { emitData({ cmd: 'setPenName', data: true }) } else { emitData({ cmd: 'setPenName', data: false }) } break case 0xa5: let macAddress = lpData.slice(2, lpData.length).map((item) => { return MAC(item) }).join(':') emitData({ cmd: 'getMacAddress', data: macAddress }) break; case 0xa7: let res = byteToString(lpData.slice(2, lpData.length)) emitData({ cmd: 'getBlueToothVersion', data: res }) break; case 0xa9: let penBattery = lpData[2] & 0xff; let penIsCharging = lpData[3] === 0x01; emitData({ cmd: 'getPenBattery', data: { penBattery: `${penBattery}%`, penIsCharging } }) break; // 获取笔的rtc时间 case 0xab: const startTime = 1262275200000; let currentTime = (new Date()).getTime(); let mPen_time = (lpData[2] & 0xff) | ((lpData[3] << 8) & 0xff00) | ((lpData[4] << 16) & 0xff0000) | ((lpData[5] << 24) & 0xff000000); let timeOffset = (currentTime - startTime) / 1000 let offTimeoff = timeOffset - mPen_time console.log(offTimeoff, '时间差') penDataHandle.changeOffset(offTimeoff); emitData({ cmd: "getRTCtime", data: (mPen_time * 1000 + startTime) }) break; case 0xad: emitData({ cmd: 'setRTCtime', data: lpData[2] === 0x00 }) break; case 0xb1: val = lpData.slice(2, 4); let penAutoShutDown = (val[0] & 0xff) | ((val[1] << 8) & 0xff00) emitData({ cmd: 'getPenAutoShutDownTime', data: penAutoShutDown }) break; case 0xb3: emitData({ cmd: 'setPenAutoOff', data: lpData[2] === 0x00 }) break case 0xb5: emitData({ cmd: 'RestoreFactorySettings', data: lpData[2] === 0x00 }) break case 0xb7: console.log(lpData[2] & 0xff) emitData({ cmd: 'getUsedMemory', data: lpData[2] & 0xff + '%' }) break; case 0xb9: emitData({ cmd: 'getPenClickMode', data: lpData[2] === 0x01 }) break case 0xbb: emitData({ cmd: 'setPenClickMode', data: lpData[2] === 0x00 }) break case 0xbd: emitData({ cmd: 'getPenBeep', data: lpData[2] === 0x01 }) break case 0xbf: emitData({ cmd: 'setPenBeep', data: lpData[2] === 0x00 }) break case 0xd1: emitData({ cmd: 'getPenSensor', data: lpData[2] & 0xff }) break case 0xd3: emitData({ cmd: "setPenSensor", data: lpData[2] === 0x00 }) break case 0xd5: emitData({ cmd: 'getLEDColor', data: lpData[2] & 0xff }) break // case 0xd7: // emitData({ // cmd: "setPenSensor", // data: lpData[2] === 0x00 // }) // break case 0xd9: var sensitivityCorrection = "20g:" + (((lpData[3] << 8) & 0xff00) + (lpData[2] & 0xff)) + "300g:" + (((lpData[5] << 8) & 0xff00) + (lpData[4] & 0xff)); emitData({ cmd: "getSensitivityCorrection", data: sensitivityCorrection }) break; case 0xdb: len = lpData[1] & 0xff; val = lpData.slice(2, len + 2); var isR = lpData[2] & 0xff; var mcu_firmware = ""; if (isR) { mcu_firmware = "MCUF_" + "R" + (lpData[4] & 0xff * 10) + (lpData[5] & 0xff) + (data[6] & 0xff); } else { mcu_firmware = "MCUF_" + "B" + (lpData[4] & 0xff) + (lpData[5] & 0xff) + (lpData[6] & 0xff); } emitData({ cmd: 'getMCUVersion', data: mcu_firmware }) break; case 0xe1: let oid4CodeValue = 0 let oidFlag = (lpData[2] >> 7 & 0x01); if (oidFlag == 1) { // oid4 high-coder let oid_a = (lpData[8] << 40); let oid_b = (lpData[9] << 32); oid4CodeValue = (oid_a & 0x3f0000000000) + (oid_b & 0xff00000000) + ((lpData[10] << 24) & 0xff000000) + ((lpData[11] << 16) & 0xf0000) + ((lpData[12] << 8) & 0xff00) + (lpData[13] & 0xff); } else if (oidFlag == 0) { // oid3 high-coder oid4CodeValue = ((lpData[10] & 0xff) << 24) | (lpData[11] << 16) | (lpData[12] << 8) | (lpData[13]); } else { // console.log("The oidFlag state is : " + oidFlag); } if (oid4CodeValue == 0) { return; } if ((lpData[2] & 0x10) != 0) { return; } emitData({ cmd: 'getOID4CodeValue', data: oid4CodeValue }) break; case 0xf0: let penColor = lpData.slice(2, lpData.length); emitData({ cmd: 'penColor', data: penColor }) break; // 读取笔的类型 case 0xe5: // console.log(lpData[2]) switch (lpData[2]) { case 0x00: utils.changeDistanceAndAngle(3.3641, 17) break case 0x01: utils.changeDistanceAndAngle(2.9431, 180); break; case 0x02: utils.changeDistanceAndAngle(2.9431, 180); break case 0x03: utils.changeDistanceAndAngle(4.3841, 17); break; case 0x08: event.emit('130', true) utils.changeDistanceAndAngle(2.8, 180); break; case 0x09: event.emit('130', true) utils.changeDistanceAndAngle(2.8, 180) break case 0x10: event.emit('130', true) utils.changeDistanceAndAngle(2.5, 180); break default: break } break case 0xeb: var mPen_CurrentCodePointType = ""; switch (lpData[2]) { case 0: mPen_CurrentCodePointType = "OID3"; break; case 1: mPen_CurrentCodePointType = "OID4"; break; default: break; } emitData({ cmd: 'getCodePointType', data: mPen_CurrentCodePointType }) break; // 获取离线数据量 case 0xc1: let offlineDataSize = lpData.slice(2, lpData.length); console.log(lpData, 'lpdata') let offlineDataNum = parseInt((((offlineDataSize[3] << 24) & 0xff000000) | ((offlineDataSize[2] << 16) & 0xff0000) | ((offlineDataSize[1] << 8) & 0xff00) | (offlineDataSize[0] & 0xff)) / 10); emitData({ cmd: "getOfflineDataNum", data: offlineDataNum }) break; // 开始获取离线数据 case 0xc3: if (lpData[2] === 0x00) { emitData({ cmd: 'startGetOffline', data: true }) } else { emitData({ cmd: "startGetOffline", data: false }) } break case 0xc4: doneFlag.gofflineDataProgress = 0 console.log(doneFlag) emitData({ cmd: 'offLineProgressStop', data: lpData[2] === 0x00 }) break case 0xcc: emitData({ cmd: "offLineProgressPause", data: lpData[2] === 0x00 }) break case 0xcd: emitData({ cmd: 'offLineProgressContinue', data: lpData[2] === 0x00 }) break case 0xc5: doneFlag.finishFlag = lpData[2] === 0x00 // console.log(doneFlag) doneFlag.gofflineDataProgress = 0 // console.log(doneFlag) setTimeout(() => { emitData({ cmd: 'offLineProgressFinish', data: lpData[2] === 0x00 ? '100%' : false }) event.emit('finish', true) }, 1000) break case 0xc7: emitData({ cmd: 'offLineDataConfirm', data: lpData[2] === 0x00 }) break case 0xc9: emitData({ cmd: 'offLineDataDelete', data: lpData[2] === 0x00 }) break } } // byte数组转字符串 const byteToString = (arr) => { if (typeof arr === 'string') { return arr; } var str = '', _arr = arr; for (var i = 0; i < _arr.length; i++) { var one = _arr[i].toString(2), v = one.match(/^1+?(?=0)/); if (v && one.length == 8) { var bytesLength = v[0].length; var store = _arr[i].toString(2).slice(7 - bytesLength); for (var st = 1; st < bytesLength; st++) { store += _arr[st + i].toString(2).slice(2); } str += String.fromCharCode(parseInt(store, 2)); i += bytesLength - 1; } else { str += String.fromCharCode(_arr[i]); } } return str; } const emitData = (val) => { event.emit('penData', val); } // 字符串转utf-8 const strToUtf8 = (str) => { const utf8 = []; for (let ii = 0; ii < str.length; ii++) { let charCode = str.charCodeAt(ii); if (charCode < 0x80) utf8.push(charCode); else if (charCode < 0x800) { utf8.push(0xc0 | (charCode >> 6), 0x80 | (charCode & 0x3f)); } else if (charCode < 0xd800 || charCode >= 0xe000) { utf8.push(0xe0 | (charCode >> 12), 0x80 | ((charCode >> 6) & 0x3f), 0x80 | (charCode & 0x3f)); } else { ii++; charCode = 0x10000 + (((charCode & 0x3ff) << 10) | (str.charCodeAt(ii) & 0x3ff)); utf8.push( 0xf0 | (charCode >> 18), 0x80 | ((charCode >> 12) & 0x3f), 0x80 | ((charCode >> 6) & 0x3f), 0x80 | (charCode & 0x3f), ); } } //兼容汉字,ASCII码表最大的值为127,大于127的值为特殊字符 for (let jj = 0; jj < utf8.length; jj++) { var code = utf8[jj]; if (code > 127) { utf8[jj] = code - 256; } } return utf8; } const MAC = (num) => { let num1 = changeData(Math.floor(num / 16)); let num2 = changeData(num % 16); return num1 + num2 } function changeData(num) { let nums = null if (num >= 10) { switch (num) { case 10: nums = 'A'; break; case 11: nums = 'B' break; case 12: nums = 'C'; break; case 13: nums = 'D' break case 14: nums = 'E'; break case 15: nums = 'F' break default: break } } else { nums = num + '' } return nums; } class Queue { constructor() { this.dataStore = [] } enqueue(item) { this.dataStore.push(item) } dequeue() { return this.dataStore.shift() } front() { return this.dataStore[0] } back() { return this.dataStore[this.dataStore.length - 1] } getLength() { return this.dataStore.length } empty() { return this.dataStore.length === 0 } toString() { let retStr = '' this.dataStore.forEach((item) => { retStr += item + '\n' }) return retStr } } // hex字符串转typedArray const hex2TypeArray = (hex) => { return new Uint8Array(hex.match(/[\da-f]{2}/gi).map(function (h) { return parseInt(h, 16) })).buffer } export { TTSDK }