import previous work

This commit is contained in:
jake downs 2024-02-03 21:30:22 -05:00
parent de50469b4e
commit 9fe684f9d0
17 changed files with 5435 additions and 0 deletions

5
DISCLAIMER.md Normal file
View File

@ -0,0 +1,5 @@
# Disclaimer of Warranty
This Work is provided "AS IS." Any express or implied warranties, including but not limited to, the implied warranties of merchantability and fitness for a particular purpose are disclaimed. In no event shall the repository Creator or Contributors be liable for any direct, indirect, incidental, special, exemplary or consequential damages (including, but not limited to, procurement of substitute goods or services, loss of use, data or profits, or business interruption) however caused and on any theory of liability, whether in contract, strict liability, or tort (including negligence or otherwise) arising in any way out of the use of this Work, even if advised of the possibility of such damage.
The User of this Work agrees to hold harmless and indemnify the repository Creator and it's Contributors, its agents and employees from every claim or liability (whether in tort or in contract), including attorney's fees, court costs, and expenses, arising in direct consequence of Recipient's use of the item, including, but not limited to, claims or liabilities made for injury to or death of personnel of User or third parties, damage to or destruction of property of User or third parties, and infringement or other violations of intellectual property or technical data rights.

21
cert.pem Normal file
View File

@ -0,0 +1,21 @@
-----BEGIN CERTIFICATE-----
MIIDhDCCAmwCCQD2xSDyQCMEuTANBgkqhkiG9w0BAQsFADCBgzELMAkGA1UEBhMC
dXMxEzARBgNVBAgMCmNhbGlmb3JuaWExCzAJBgNVBAcMAmxhMQswCQYDVQQKDAJj
bzEQMA4GA1UECwwHc2VjdGlvbjESMBAGA1UEAwwJMTI3LjAuMC4xMR8wHQYJKoZI
hvcNAQkBFhBtZUBqYWtlZG93bnMuY29tMB4XDTIyMTEyNDA3MDcxN1oXDTMyMTEy
MTA3MDcxN1owgYMxCzAJBgNVBAYTAnVzMRMwEQYDVQQIDApjYWxpZm9ybmlhMQsw
CQYDVQQHDAJsYTELMAkGA1UECgwCY28xEDAOBgNVBAsMB3NlY3Rpb24xEjAQBgNV
BAMMCTEyNy4wLjAuMTEfMB0GCSqGSIb3DQEJARYQbWVAamFrZWRvd25zLmNvbTCC
ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL79eV4MifDgLHjIriewR9ri
k+vVpzgaefEs2LYtGuT2il26uxQIUBn/nNoDPtEM4F4PD0MulINEonbh5ipih1YQ
VDSZhFcdYt6nm+ew1T7kMm++y0HrhojsXiA3kpab3XzSCFqZ2o/ae3xDxjxIEq4F
XrED5h5budcCSwAez/2NS5GLTH8xHlDg1djTl+Y1h4mOwnR18PmOFP+9sOAg6ZzO
/jLbxwx+AoE0OnO/ldbvLvytdmB8k/mi79+OtS6w53jqIggvTkPK/yQss82EaWTm
XJyEJ9BTB0jcRItS0Y2ck0tRUI7QifdY8Q+exQwO0kRpyA/EtE/BK5PwMY10LnkC
AwEAATANBgkqhkiG9w0BAQsFAAOCAQEAhN2x+yfItai4ozVvdXKlvECsdlQzmKEe
aXfPuDTdYLuOBPnpPRALM9ewML2xiwX4TVGltTWIIxWubRIGyVT8RzdwYY6lOx0w
UhQz9MUK2MqJM7hAwjeEnKTMned5PTtm6Jd+HBU9o9FBEhi4LuFrFrVa2vZLzfGp
kJoq7tKFcotHEQ5aQ1OfsOwcHEBeqv+yM7RMjl1B1hlU5z0OtmOU8RLlSe5xLT9X
/m9YmrAlJwslqtBBcaAgP1TMJeCEL14ezp0Z4CFakX+1TuopqPyp5F4h97i6spER
kzH5kfp0E99OwAmooI+++CSEm+/2NQKWOEZ98qa7rLaEWp8Q6lmEAw==
-----END CERTIFICATE-----

178
common.js Normal file
View File

@ -0,0 +1,178 @@
// air light 在 检查设备 => 连接设备 => 获取实例 => 判断设备类型 进行整合
// 不同类型升级提供俩个接口通过判断设备类型分别调用不同的SDK包再进行升级后续操作
let curGlasses = null;
const DEBUG = true;
import GlassesLight from './js_light/glasses.js';
import * as managerLight from './js_light/manager.js'
import GlassesAir from './js_air/glasses.js'
import * as managerAir from './js_air/manager.js'
// *******************
export function isNrealDevice(device) {
// 涉及俩种设备的区分协议(符合 air 和 light 俩种Nreal设备)
// console.log({
// pid_hex: device.productId.toString(16),
// pid_dec: device.productId
// })
return device.productId == 0x0423
|| device.productId == 0x573C
|| device.productId == 0x0424;
}
export function addHidListener() {
navigator.hid.onconnect = function (event) {
let device = event.device;
if (device.productId == 1059 || device.productId == 1060) {
console.log('connected',{device});
managerAir.canCommand(device).then(result => {
if (result) {
curGlasses = new GlassesAir(device);
}
});
}
if (device.productId == 22332 || device.productId == 22336) {
managerLight.canCommand(device).then(result => {
if (result) {
curGlasses = new GlassesLight(device);
}
});
}
}
navigator.hid.ondisconnect = function (event) {
if (curGlasses && curGlasses.device == event.device) {
curGlasses = null;
}
}
}
window.curGlassesArray = [];
export function checkConnection() {
if (curGlasses) {
return curGlasses;
}
return navigator.hid.getDevices().then(devices => {
// console.warn('filtering', devices);
// filters out devices that are nreal devices.
return devices.filter(isNrealDevice);
}).then(async devices => {
console.log('filtered:', devices)
for (let device of devices) {
// if(curGlasses){
// console.warn('skipping',device)
// continue;
// }
if (device.productId == 1059 || device.productId == 1060) {
console.log({air:device});
if (await managerAir.canCommand(device)) {
curGlasses = new GlassesAir(device);
curGlassesArray.push(curGlasses);
return curGlasses;
}
}
if (device.productId == 22332 || device.productId == 22336) {
if (await managerLight.canCommand(device)) {
curGlasses = new GlassesLight(device);
return curGlasses;
}
}
}
});
}
export function requestDevice() {
return navigator.hid.requestDevice({
filters: [{
vendorId: 0x0486, // ? ASUS Computers Inc. ?
}, {
vendorId: 0x0483, // STMicroelectronics ?
}, {
vendorId: 0x0482, // Kyocera Corporation ?
}, {
vendorId: 0x3318, // Gleaming Reality (Wuxi) Technology Co., LTD ?
}]
}).then(async devices => {
for (let device of devices) {
if (deviceIsAir(device)) {
// can command checks isMcu
// air shows up as 3 separate HID devices
// but we only select 1 that can be commanded
// this code was originally from their activation/update page
// so, maybe devices OTHER than MCU can be communicated with via JS?
// I'm not sure yet...
if (await managerAir.canCommand(device)) {
curGlasses = new GlassesAir(device);
return curGlasses;
}
} else if (deviceIsLight(device)) {
// NOTE i don't have a Light to test with,
// so all my work is focusedd on the Air Protocol for now...
if (await managerLight.canCommand(device)) {
curGlasses = new GlassesLight(device);
return curGlasses;
}
}
}
});
}
export async function connectDevice() {
let glasses = await checkConnection();
if (glasses) {
return glasses;
}
return await requestDevice();
}
export async function disconnectDevice() {
if(curGlasses){
curGlasses._device.close()
curGlasses = null;
}
}
export function deviceIsAir(device){
// 0x423 || 0x424
return device.productId == 1059 || device.productId == 1060
}
export function deviceIsLight(device){
// 0x573C || 0x5740
return device.productId == 22332 || device.productId == 22336
}
// check glasses is air or light?
export function isAirOrLight() {
if (!curGlasses) {
return 'not found device';
}
if (deviceIsAir(curGlasses.device)) {
return 1
}
if (deviceIsLight(curGlasses.device)) {
return 2
}
return null
}
export function hexStream2int8Array(captureString){
return new Uint8Array(captureString.match(/.{1,2}/g).map((b)=>{
// console.log(b);
return b //.parseInt(16)
}))
}
export function parseHexString(captureString){
return glasses.protocol.parse_rsp(hexStream2int8Array(captureString))
}
export {
curGlasses
}

535
index_old.html Normal file
View File

@ -0,0 +1,535 @@
<html>
<head>
<style>
html,body {
font-family: sans-serif;
}
#imu, #imu-labels {
font-family: monospace;
}
#imu {
display: block;
position: relative;
width: 100%;
}
#imu-bars {
width: 100%;
display: flex;
flex-direction: row;
height: 300px;
clear: both;
}
#imu-bars .bar {
width: 24px;
background: blue;
margin: 0 7px 0 0;
min-height: 1px;
}
#imu-bars .bar.bar-gap {
margin-right: 39px;
}
#sparklines {
display: block;
}
#sparklines .sparkline-wrapper {
float: left;
width: 500px;
height: 50px;
margin-right: 10px;
position: relative;
margin-bottom: 10px;
}
#sparklines .sparkline-label {
position: absolute;
left: 0;
top: 0;
background: black;
color: white;
}
#sparklines .sparkline {
width: 500px;
background: beige;
/* border: 1px solid blue;*/
height: 50px;
min-width: 500px;
min-height: 50px;
display: block;
}
.sparkline {
stroke: transparent;
fill: blue;
}
/*.sparkline--line {
stroke: red;
}
.sparkline--fill {
fill: blue;
}*/
</style>
</head>
<body>
<div id="noSupportHid"></div>
<div id="connect"><button>connect</button></div>
<div id="disconnect" onclick="disconnectDevices()"><button>disconnect</button></div>
<div id="hadConnect"></div>
<div id="sn"></div>
<div id="firmwareMcu"></div>
<div id="firmwareDp"></div>
<!-- <div id="getBrightness" onclick="window.getBrightness()"><button>get brightness</button></div> -->
<!-- <div id="setBrightness" onclick="window.setBrightness()"><button>set brightness</button></div> -->
<input type="range" min="1" max="8" step="1" value="8"
name="brightness"
oninput="window.updateBrightness(event)">
<!-- <label for="brightness">set brightness to: <span class="req-brightness-value"></span> </label> -->
<div>current brightness: <span class="current-brightness">?</span></div>
<hr/>
<div id="imu-labels"></div>
<div id="imu"></div>
<div id="imu-bars"></div>
<div id="sparklines"></div>
<hr/>
<div id="output"></div>
<script type="module">
// if(!header){
// window.location.href = 'https://www-uat.nreal.cn/support/activationGlasses/'
// }
import * as Manager from './js_air/manager.js';
import * as Common from './common.js';
//import * as GA from '../addGa.js';
import http from "../tools/http.js"
// import downloadfiles from "../tools/downloadfile.js"
const hidFilters = [
{ 'vendorId': 0x3318 }, // NReal Vendor ID, Gleaming Reality?
];
let binFile = null;
let currentGlass = null;
window.Manager = Manager;
// UI Stuff / todo remake in vue or something
// let brightness_out = document.querySelector('[name="brightness"]').value;
window.updateBrightness = function(event) {
//console.log(event);
let value = event.target.value;
console.log(value);
// document.querySelector('.req-brightness-value').innerHTML = value;
// brightness_out = value;
}
/*
async function upgradeMcu() {
if (binFile == null) {
alert('Please select the firmware file or redownload it. ')
return;
}
let version = await Manager.getFirmwareVersionInMcu();
if (version == null) {
alert("The device is not connected, please connect the glasses");
return;
}
let result;
http.get({ url: `/nebula/v1/isc/admin/device/version/check?deviceType=2&country=2&fileType=10&currentFileName=air_${version}.bin`, timeout: 1000 }, async function (err, res) {
if (err) {
alert('Error. Please refresh and try again.')
return false;
} else {
if (res.data.isLatest) {
document.getElementById('alreadyLast').innerText = "Your MCU firmware is the latest. There's no update available."
document.getElementById('alreadyLast').style.display = 'block'
return;
} else {
document.getElementById('upgradeDp').disabled = true;
let data = await binFile.arrayBuffer();
// document.getElementById('tip').style.display = 'block'
document.getElementById('upgradeMcu').style.display = 'none'
document.getElementById('progress').style.display = 'block'
result = await Manager.upgradeInMcu(await binFile.arrayBuffer());
if (result) {
// document.getElementById('tip').style.display = 'none'
document.getElementById('outputMcu').style.display = 'block'
let mcuTimer = setInterval(async () => {
if (Common.curGlasses) {
Manager.getFirmwareVersionInMcu().then(lastVersion => {
document.getElementById('latestVersionMcu').style.display = 'block';
document.getElementById('latestVersionMcu').innerText = lastVersion ? `Current MCU firmware version is: ${lastVersion}` : ''
})
.catch(err => {
console.log('err', err)
})
.finally(() => {
clearInterval(mcuTimer);
mcuTimer = null;
})
}
}, 300);
} else {
document.getElementById('fail').style.display = 'block'
}
document.getElementById('upgradeDp').disabled = false;
}
}
});
}
async function upgradeInDp() {
if (binFile == null) {
alert('Please select the firmware file or redownload it. ')
return;
}
document.getElementById('alreadyLastDp').style.display = 'none'
document.getElementById('outputdp').style.display = 'none'
let dpVersion = await Manager.isNeedUpgradeInDp();
console.log('dpVersion', dpVersion)
if (dpVersion == null) {
alert("The device is not connected, please connect the glasses");
return;
}
if (!dpVersion) {
document.getElementById('alreadyLastDp').innerText = "Your DP firmware is the latest. There's no update available."
document.getElementById('alreadyLastDp').style.display = 'block'
return;
}
document.getElementById('tipdp').style.display = 'block'
document.getElementById('upgradeDp').style.display = 'none'
document.getElementById('progressDp').style.display = 'block'
let result;
result = await Manager.upgradeInDp();
if (result) {
document.getElementById('outputdp').style.display = 'block'
let dpTimer = setInterval(async () => {
if (Common.curGlasses) {
Manager.getFirmwareVersionInDp()
.then(lastVersion => {
document.getElementById('latestVersionDp').style.display = 'block';
document.getElementById('latestVersionDp').innerText = lastVersion ? `Current DP firmware version is: ${lastVersion}` : '';
})
.catch(err => { console.log(err) })
.finally(() => {
clearInterval(dpTimer)
dpTimer = null
})
}
}, 300);
} else {
document.getElementById('progressDp').style.display = 'none';
document.getElementById('faildp').style.display = 'block'
}
}
async function upgradeDsp() {
if (binFile == null) {
alert('Please select the firmware file or redownload it. ')
return;
}
// 拿到文件的版本号
let version = binFile.name.slice(4, 9)
let flag = await Manager.isNeedUpgradeInDsp(version);
if (flag == null) {
alert("Please connect glasses first!");
return;
}
if (flag != 1) {
alert("Already the latest version!");
return
}
let data = await binFile.arrayBuffer();
let result = await Manager.upgradeInDsp(await binFile.arrayBuffer());
// let timer = setInterval(() => {
// setOutput((Manager.current/Manager.total) * 100 + '%')
// if(Manager.current == Manager.total){
// clearInterval(timer)
// setOutput(result)
// }
// })
// setOutput((Manager.current/Manager.total) * 100 + '%')
}
*/
// function downloadFile() {
// http.get({ url: `/nebula/v1/isc/admin/device/version/check?deviceType=2&country=2&fileType=10&currentFileName=isLatest`, timeout: 1000 }, function (err, result) {
// if (err) {
// alert("download failed")
// } else {
// const url = result.data.uri
// downloadfiles(url)
// }
// });
// }
async function isLastest(ver) {
http.get({ url: `/nebula/v1/isc/admin/device/version/check?deviceType=2&country=2&fileType=10&currentFileName=air_${ver}`, timeout: 1000 }, function (err, result) {
if (err) {
return false;
} else {
return result.data.isLatest
}
});
}
// 获取文件名
// function fileNameFromHeader (disposition) {
// let result = null;
// if (disposition && /filename=.*/ig.test(disposition)) {
// result = disposition.match(/filename=.*/ig);
// return decodeURI(result[0].split('=')[1]);
// }
// return null;
// }
// function selectbin() {
// return Manager.selectBinFile().then(file => {
// var reg = /07.[1-2].[0-9]{2}.[0-9]{3}_[0-9]{8}/g;
// if (reg.test(file.name)) {
// binFile = file;
// document.getElementById('binfile').value = file.name;
// } else {
// document.getElementById('binfile').value = " "
// window.alert("Please select the firmware file or redownload it. ")
// binFile = null
// }
// return binFile;
// });
// }
function connect() {
Common.connectDevice().then(async glasses => {
if (glasses) {
document.getElementById('hadConnect').style.display = 'block'
document.getElementById('connect').style.opacity = '0'
document.getElementById('firmwareMcu').innerText = 'Current glasses version is : ' + await firmwareMcu()
document.getElementById('firmwareDp').innerText = 'Current DP version is : ' + await firmwareDp()
document.getElementById('sn').innerText = 'SN' + await getSN()
} else {
}
// document.getElementById('sn').innerHTML = getSN()
// document.getElementById('version').innerText = '版本号' + firmwareMcu()
setOutput('glasses : ' + glasses.toString());
});
}
function firmwareMcu() {
return Manager.getFirmwareVersionInMcu().then(version => {
// setOutput('firmware : ' + version);
return version
})
}
function firmwareDp() {
return Manager.getFirmwareVersionInDp().then(version => {
// setOutput('firmware : ' + version);
return version
})
}
function getSN() {
return Manager.getSN().then(version => {
// setOutput('SN : ' + version);
return version
});
}
function JumpToApp() {
Manager.boot2App().then(result => {
setOutput('jump to app : ' + result);
});
}
function serial() {
Manager.getSerialPort().then(version => {
setOutput('serial port: ' + version.serialNumber);
});
}
function deactivate() {
Manager.deactivate().then(result => {
setOutput('deactivate ' + result);
});
}
// function activate() {
// let nowTime = new Date().getTime()
// Manager.activate(nowTime).then(async result => {
// if (result) {
// let sn = await getSN()
// const data = {
// sn,
// timestamp: nowTime,
// deviceType: 'Air_OTA'
// }
// document.getElementById('activeted').style.display = 'block'
// document.getElementById('activate').style.opacity = '0'
// } else {
// }
// });
// }
//上传测井数据表到服务器数据库
// function PostToServer(data) {
// var httpRequest = new XMLHttpRequest();//第一步:建立所需的对象
// httpRequest.open("POST", "https://app-uat-api-cn.nreal.work/api/user-profile/v1/rest/device-activation/activate", true); //调用AddDataToServer
// httpRequest.setRequestHeader("Content-Type", "application/json"); //设置请求头信息
// // httpRequest.setRequestHeader("Authorization", header); //设置请求头信息
// httpRequest.setRequestHeader("Authorization", header); //设置请求头信息
// httpRequest.send(JSON.stringify(data)); //设置为发送给服务器数据
// }
window.setOutput = function(output) {
document.getElementById('output').innerText = output + '<br/>' + document.getElementById('output').innerText;
}
window.getBrightness = function() {
Manager.getBrightness().then(brightness => {
setOutput('brightness : ' + brightness);
document.querySelector('.current-brightness').innerText = brightness;
});
}
window.setBrightness = function() {
let brightness = document.querySelector('.brightness').value;
Manager.setBrightness(parseInt(brightness)-1).then(result => {
setOutput('set brightness : ' + result);
});
}
window.onBrightnessChanged = function(new_value) {
document.querySelector('[name="brightness"]').value = new_value;
document.querySelector('.current-brightness').innerText = new_value;
}
window.disconnectDevices = () => {
window.curGlassesArray.map(g=>{
g._device.close();
g._device.forget();
})
}
window.endpoints = [];
window.listUsbEndpoints = () => {
window.endpoints = [];
// list usb endpoints
navigator.usb.requestDevice({filters:[]}).then((device)=>{
window.usb_device = device;
//usb_device.configurations[0].interfaces[1].alternates[1].endpoints[0]
for(let configuration of device.configurations){
for(let _interface of configuration.interfaces){
for(let alternate of _interface?.alternates ?? []){
for(let endpoint of alternate.endpoints){
window.endpoints.push(endpoint);
}
}
}
}
console.table(window.endpoints);
})
}
window.sparkline_elements = [];
window.onload = async () => {
for(var i = 0; i<41; i++){
let child = document.createElement('div');
child.classList.add('bar');
if((i+1) % 4 === 0){
child.classList.add('bar-gap');
}
document.getElementById('imu-bars').append(child)
document.getElementById('imu-labels').innerHTML+= i.toString().padStart(3,'0') + ' ';
if((i+1)%4 === 0){
document.getElementById('imu-labels').innerHTML+= '&nbsp;|&nbsp;&nbsp;';
}
//<svg class="sparkline" width="100" height="30" stroke-width="0"></svg>
// const _svg = document.createElement('svg');
var svgns = "http://www.w3.org/2000/svg";
var _svg = document.createElementNS(svgns,'svg');
_svg.classList.add('sparkline')
_svg.setAttribute('width', '500')
_svg.setAttribute('height', '50')
_svg.setAttribute('stroke-width', '0')
_svg.setAttributeNS(null, 'viewBox', '0 0 500 50')
// _svg.setAttribute('viewBox', '0 0 500 50')
const _span = document.createElement('span')
_span.classList.add('sparkline-label')
_span.innerText = (i).toString().padStart(3,'0');
window.sparkline_elements.push(_svg)
const _sl_wrapper = document.createElement('div');
_sl_wrapper.classList.add('sparkline-wrapper')
_sl_wrapper.append(_span)
_sl_wrapper.append(_svg)
document.getElementById('sparklines').append(_sl_wrapper)
}
if (!Manager?.hidSupported()) {
document.getElementById('noSupportHid').style.display = "block";
return;
}
window.Common = Common;
Common.addHidListener();
Common.checkConnection(); // see if we can re-connect
// Manager.addHidListener();
// Manager.addSerialListener();
document.getElementById('connect').onclick = connect;
//document.getElementById('getBrightness').onclick = getBrightness;
// document.getElementById('activate').onclick = activate;
// document.getElementById('downloadFile').onclick = downloadFile;
// document.getElementById('deactivate').onclick = deactivate;
// document.getElementById('firmwareMcu').onclick = firmwareMcu;
// document.getElementById('SN').onclick = getSN;
// document.getElementById('app').onclick = JumpToApp;
// document.getElementById('serial').onclick = serial;
// document.getElementById('upload').onclick = upload;
// document.getElementById('selectbin').onclick = selectbin;
// document.getElementById('upgradeMcu').onclick = upgradeMcu;
// document.getElementById('upgradeDp').onclick = upgradeInDp;
// document.getElementById('upgradeDsp').onclick = upgradeDsp;
}
</script>
</body>
</html>

435
js_air/glasses.js Normal file
View File

@ -0,0 +1,435 @@
import * as Protocol from './protocol.js';
import sparkline from '../tools/sparkline.js'
/* captures */
// TODO: move this to another folder
// import {captures} from './captures.js';
// window.captures = captures
// let values = '';
// let fourBytesToFloat = (data) => {
// // Create a buffer
// var buf = new ArrayBuffer(4);
// // Create a data view of it
// var view = new DataView(buf);
// // set bytes
// data.forEach(function (b, i) {
// view.setUint8(i, b);
// });
// // Read the bits as a float; note that by doing this, we're implicitly
// // converting it from a 32-bit float into JavaScript's native 64-bit double
// var num = view.getFloat32(0);
// // Done
// // console.log(num);
// return num;
// }
// captures.forEach((capture,i)=>{
// if(i<100){
// if(capture.msgId === "0 0x0" && capture.payload.split(' ').length === 41){
// // hex2dec
// // console.log(capture.payload.split(' ').map(x=>parseInt(x).toString().padStart(2,'0')))
// // const hex2dec = capture.payload.split(' ').map((x,k)=>{
// // // return x.padStart(2,'0')
// // let i = parseInt(x,16)
// // return i ? i.toString().padStart(3, '0') : ' '
// // }).join(' ');
// // values+=hex2dec+'\n';
// // console.log(hex2dec)
// // ok i think it's transmitted as a 4x4f matrix, based on
// // \NRSDK\Scripts\Utility\ConversionUtility.cs
// // convert string representation of 41 bytes to Uint8Array
// // hrm... 41 bytes is too small a payload for 16 floats would need at least 48 bytes
// let _payload = new Uint8Array(capture.payload.split(' ').map(x=>parseInt(x,16)));
// // let f0 = fourBytesToFloat(_payload.slice(0,4));
// // extract 4x4 matrix of floats from byte-string
// let _f = [];
// for(let i=0;i<4;i++){
// // push 3 4-byte floats to _f
// for(let j=0;j<3;j++){
// let bytes = _payload.slice((i*4)+j,(i*4)+j+4)
// _f.push(fourBytesToFloat(bytes))
// }
// }
// // print 4x4 visual diagram to console
// console.log(_f.map((x)=>{
// return x; //.toFixed(2)
// }).join(', \n'))
// console.log('-------')
// }
// }
// });
// console.log(values)
/* End captures */
window.sparkline_values = [];
let stop_at = Infinity;//1000;
let current = 0;
//reduce update rate
let render_every = 2;
let imu_report_current = 0;
window.max_history = 1000;
// 41-byte packets
window.fo_packets = [];
window.fo_status_min = Infinity;
window.fo_status_max = -Infinity;
window.fo_status_distribution = {};
window.i8_two_samples = [];
// non-41 byte packets
window.packets_len_distribution = {};
window.packets_status_distribution = {};
window.render_sparklines = true;
window.bar_heights = [];
let bars = [];
window.samples_for_csv = [];
window.stats_by_packet_length = {};
// set to false to disable printing output when
// mysterious msgId 0x0 is being received
window.imu_output = true;
window.logPackets = () => {
console.log('packets:',{
packets_len_distribution,
packets_status_distribution
})
}
// window.logFOPackets = () => {
// console.table([
// {
// // 0 - 255
// min: window.fo_status_min,
// max: window.fo_status_max,
// }
// ])
// console.log(window.fo_status_distribution)
// }
export default class Glasses extends EventTarget {
constructor(device) {
console.log('constructing');
super();
this._device = device;
this._interestMsg = [];
this._reports = new Map();
this._captures = [];
// set input listener
device.oninputreport = this._handleInputReport.bind(this);
window.glasses = this;
window.glasses.protocol = Protocol;
this.setBrightness = window.Manager.setBrightness;
for(let i = 0; i<41; i++){
bars.push(document.querySelector('#imu-bars .bar:nth-child('+(i+1)+')'))
}
// this.renderSparklines();
}
renderSparklines(){
if(!window.imu_output){
return;
}
window.bar_heights.map((v,k)=>{
if(bars[k]){
bars[k].style.height = v+'px';
}
})
// console.log('renderSparklines');
if(window.render_sparklines){
for(const [v,k] of window.sparkline_values){
if(window.sparkline_elements[k]){
requestAnimationFrame(()=>{
sparkline(window.sparkline_elements[k],window.sparkline_values[k],{
spotRadius: 0
})
})
}
}
}
// if(fo_packets.length){
requestAnimationFrame(this.renderSparklines.bind(this))
// }
}
dumpCaptures(){
console.log(JSON.stringify(window.captures));
}
get device() { return this._device; }
connect() {
if (!this._device.opened) {
return this._device.open();
}
return Promise.resolve();
}
_handleInputReport({ device, reportId, data }) {
const reportData = new Uint8Array(data.buffer);
let report = Protocol.parse_rsp(reportData);
if(!report){
return;
}
// console.log('input',{
// reportId,
// data,
// reportData,
// report
// });
// if(device !== glasses._device){
// debugger;
// }
const packet = {
dir: 'IN',
reportId: reportId,
plen: report.payload.length,
status: report.status,
msgId: [report.msgId, '0x'+(report.msgId.toString(16))].join(' '),
key: Protocol.keyForHex(report.msgId),
payload: report.payload.map(b => b.toString(16).padStart(2, "0")).join(' '),
dec: report.payload.map(Protocol.hex2Decimal).join(' '),
string: String.fromCharCode.apply(null, report.payload),
// ascii: new TextDecoder().decode(
// new Uint8Array(
// report.payload
// )
// ).split('\x00').join(' ')
}
if(report.msgId === 0){
// console.log(report.payload.length, report.status)
imu_report_current++;
if(imu_report_current < 1000){
// // update stats by packet length
// if(!window.stats_by_packet_length[report.payload.length]){
// window.stats_by_packet_length[report.payload.length] = {
// count: 0,
// status: {
// distribution: {}
// },
// // byte_stats[pos] = {distribution: {}}
// byte_stats: {}
// }
// }
// window.stats_by_packet_length[report.payload.length].count++;
// if(!window.stats_by_packet_length[report.payload.length].status.distribution[report.status]){
// window.stats_by_packet_length[report.payload.length].status.distribution[report.status] = 0;
// }
// window.stats_by_packet_length[report.payload.length].status.distribution[report.status]++;
// // update stats by byte position
// for(let i = 0; i<report.payload.length; i++){
// if(!window.stats_by_packet_length[report.payload.length].byte_stats[i]){
// window.stats_by_packet_length[report.payload.length].byte_stats[i] = {
// distribution: {}
// }
// }
// if(!window.stats_by_packet_length[report.payload.length].byte_stats[i].distribution[report.payload[i]]){
// window.stats_by_packet_length[report.payload.length].byte_stats[i].distribution[report.payload[i]] = 0;
// }
// window.stats_by_packet_length[report.payload.length].byte_stats[i].distribution[report.payload[i]]++;
// }
}
// status len data
// samples_for_csv.push([report.status, report.payload.length, ...report.payload].join(','))
// if(samples_for_csv.length > 1000){
// samples_for_csv.shift();
// }
if(imu_report_current === render_every && window.imu_output){
imu_report_current = 0;
// update text/bar graphs
// console.log('got report',report);
const stringified = [...report.payload].map((x,k)=>{
// return x.padStart(2,'0')
let i = x//parseInt(x)
let padded = (i).toString().padStart(3, '0');
let out = '' + (i ? padded : '___')
if((k+1)%4 === 0){
out+='&nbsp;&nbsp;|&nbsp;';
}
//console.table([packet]);
// window.packets_len_distribution[report.payload.length]
// = (window.packets_len_distribution[report.payload.length] || 0) + 1;
// window.packets_status_distribution[report.status]
// = (window.packets_status_distribution[report.status] || 0) + 1;
// update sparkline
if(current<stop_at && report.payload.length === 41){
i8_two_samples.push(report.payload[2]);
if(i8_two_samples.length > 50){
i8_two_samples.shift();
}
// fo_packets.push(report);
// if(fo_packets.length > window.max_history){
// fo_packets.shift();
// }
// if(report.status < window.fo_status_min){
// window.fo_status_min = report.status;
// }
// if(report.status > window.fo_status_max){
// window.fo_status_max = report.status;
// }
// if(!window.fo_status_distribution[report.status]){
// window.fo_status_distribution[report.status] = 0;
// }
// window.fo_status_distribution[report.status]++;
window.bar_heights[k] = i;
if(!window.sparkline_values[k]){
window.sparkline_values[k] = [];
}
if(window.sparkline_values[k].length > window.max_history){
window.sparkline_values[k].shift();
}
// debugger;
window.sparkline_values[k].push(i);
}
return out
}).join(' ');
document.getElementById('imu').innerHTML = stringified
// debugger;
if(current < stop_at){
current++;
}
// if(current>=stop_at){
// console.warn('no longer updating sparklines');
// }
// console.log('IN',report.msgId);
}
}else{
console.table([packet])
}
// console.log('IN',report.msgId);
// window.captures.push(packet)
if(report.msgId === Protocol.MESSAGES.P_BUTTON_PRESSED){
// button press payloads are 11-bits
// ┌- first 4 bytes appear to be which button is pressed
// | ┌- second 4 bytes are a associated payload
// | | ┌- haven't seen last 3 bits used yet
// 0000 0000 000
// Button IDs
// 0001 = power button
// payloads
// 0000 - turned off
// 0001 - turned on
// 0006 = brightness increase
// 0007 = brightness decrease
// payloads
// 0000 - 0007 = 8 brightness levels, 0007 being brightest
const button = report.payload[3];
const int = Protocol.brightBytes2Int(report.payload);
// if report.payload[3] ===
console.log('button pressed',
{
button,
brightness_int: int
});
window.onBrightnessChanged(int);
}
this._reports.set(report.msgId, report);
}
sendReport(msgId, payload) {
const data = new Uint8Array(payload);
const cmd = Protocol.cmd_build(msgId, data);
// console.log({
// msgId,
// payload,
// data,
// cmd
// })
console.table([{
dir: 'OUT',
msgId: [msgId, '0x'+(msgId.toString(16))].join(' '),
key: Protocol.keyForHex(msgId),
payload: data.join(' '),
cmd: cmd.map(b => b.toString(16).padStart(2, "0")).join(' ')
}])
this._device.sendReport(0x00, cmd);
}
async sendReportTimeout(msgId, payload = [], timeout = 1000) {
this.sendReport(msgId, payload);
const time = new Date().getTime();
while ((new Date().getTime() - time) < timeout) {
if (this._reports.has(msgId)) {
let report = this._reports.get(msgId);
this._reports.delete(msgId);
return report;
}
await new Promise(resolve => setTimeout(resolve, 10));
}
return null;
}
async isMcu() {
const report = await this.sendReportTimeout(Protocol.MESSAGES.R_ACTIVATION_TIME);
return report != null;
}
toString() {
return `<Glasses deviceName=${this._device.productName} vid=${this._device.vendorId} pid=${this._device.vendorId}>`;
}
}

567
js_air/manager.js Normal file
View File

@ -0,0 +1,567 @@
import Glasses from './glasses.js';
import * as Protocol from './protocol.js';
import * as common from './../common.js'
// let devices = [];
const DEBUG = true;
// progress bar
let current
let total
// DP progress
let dpCurrent
// DSP progress
let DspSecond
let DspThrid
/** check browser whether hid support */
// todo move to common
export function hidSupported() {
return !(navigator.hid === undefined);
}
// check glasses is open?
// note we filter out things that arent the master control unit
export function canCommand(device) {
if (device) {
let glasses = new Glasses(device);
return glasses.connect().then(() => {
return glasses.isMcu();
});
}
return false;
}
function getGlasses() {
return common.curGlasses;
}
export async function hasActivated() {
let glasses = await common.connectDevice();
if (!glasses) {
return false;
}
let activationReport = await glasses.sendReportTimeout(Protocol.MESSAGES.R_ACTIVATION_TIME);
if (reportSuccess(activationReport) && activationReport.payload.length > 0) {
let time = Protocol.bytes2Time(activationReport.payload);
return time > 0;
}
return false;
}
// /** activate the glasses */
// export async function activate(timeStamp) {
// let glasses = await common.connectDevice();
// if (!glasses) {
// return false;
// }
// // hardcode value = 300
// // 3C 4B 46 52 54 41 01
// const time = Protocol.time2Bytes(timeStamp);
// return glasses.sendReportTimeout(Protocol.MESSAGES.W_ACTIVATION_TIME, time)
// .then(report => {
// return reportSuccess;
// });
// }
// /** deactivate the glasses */
// export async function deactivate() {
// let glasses = await common.connectDevice();
// if (!glasses) {
// return false;
// }
// return glasses.sendReportTimeout(Protocol.MESSAGES.W_CANCEL_ACTIVATION)
// .then(report => {
// return reportSuccess;
// });
// }
// Conversion from decimal to hexadecimal
function Decimal2Hex(value) {
if (value.toString(16).length == 1) {
return ('0x0' + value.toString(16))
} else {
return ('0x' + value.toString(16))
}
}
/** read firmware MCU version*/
export async function getFirmwareVersionInMcu() {
let glasses = await common.connectDevice();
if (!glasses) {
return 'not found device';
}
return glasses.sendReportTimeout(Protocol.MESSAGES.R_MCU_APP_FW_VERSION)
.then(report => {
if (reportSuccess(report)) {
return String.fromCharCode.apply(null, report.payload);
}
});
}
/** read firmware DP version*/
export async function getFirmwareVersionInDp() {
let glasses = await common.connectDevice();
if (!glasses) {
return 'not found device';
}
return glasses.sendReportTimeout(Protocol.MESSAGES.R_DP7911_FW_VERSION)
.then(report => {
if (reportSuccess(report)) {
return String.fromCharCode.apply(null, report.payload);
}
});
}
/** read firmware DSP version*/
export async function getFirmwareVersionInDsp() {
let glasses = await common.connectDevice();
if (!glasses) {
return 'not found device';
}
return glasses.sendReportTimeout(Protocol.MESSAGES.R_DSP_VERSION)
.then(report => {
if (reportSuccess(report)) {
return String.fromCharCode.apply(null, report.payload);
}
});
}
// Parameters required for the progress bar
// function progress(cur, all) {
// current = cur
// total = all
// document.getElementById('progress').innerText = parseInt((current / total) * 100) + 1 + '%'
// }
// function progressInDp(cur) {
// current = cur
// document.getElementById('progressDp').innerText = current + '%'
// }
// export async function selectBinFile() {
// const pickerOpts = {
// types: [
// {
// description: 'firmware image',
// accept: {
// 'bin/*': ['.bin']
// }
// },
// ],
// excludeAcceptAllOption: true,
// multiple: false
// };
// let filePaths = await window.showOpenFilePicker(pickerOpts);
// if (filePaths.length > 0) {
// return filePaths[0].getFile();
// }
// return null;
// }
function isBootDevice(device) {
return device.vendorId === Protocol.NREAL_VENDOR_ID
&& device.productId === Protocol.BOOT_PRODUCT_ID;
}
async function waitBootDevice() {
let devices = await navigator.hid.getDevices().then(devices => {
return devices.filter(isBootDevice);
});
if (devices.length > 0) {
return devices[0];
}
// await requestDevice()
await navigator.hid.requestDevice({
filters: [{ vendorId: Protocol.NREAL_VENDOR_ID, productId: Protocol.NREAL_BOOT_PRODUCT_ID }]
});
const time = new Date().getTime();
while ((new Date().getTime() - time) < 2000) {
await new Promise(resolve => setTimeout(resolve, 20));
devices = await navigator.hid.getDevices().then(devices => {
return devices.filter(isBootDevice);
});
if (devices.length > 0) {
return devices[0];
}
}
}
// export async function upgradeInMcu(data) {
// let glasses = await common.connectDevice();
// if (!glasses) {
// return false;
// }
// return glasses.sendReportTimeout(Protocol.MESSAGES.W_UPDATE_MCU_APP_FW_PREPARE)
// .then(report => {
// if (reportSuccess(report)) {
// return glasses.sendReportTimeout(Protocol.MESSAGES.W_MCU_APP_JUMP_TO_BOOT);
// }
// }).then(async (report) => {
// if (reportSuccess(report)) {
// let device = await waitBootDevice();
// if (await canCommand(device)) {
// return sendFirmwareInMcu(new Glasses(device), data);
// }
// }
// });
// }
export function Asc2Hex(value) {
return ('0x' + value.charCodeAt().toString(16));
}
/** need to upgrade firmware DSP version? */
// export async function isNeedUpgradeInDsp(version) {
// let glasses = await common.connectDevice();
// if (!glasses) {
// return 'not found device';
// }
// let HexVersion = version.split('').map((item, index) => {
// return Asc2Hex(item)
// })
// return glasses.sendReportTimeout(Protocol.MESSAGES.R_IS_NEED_UPGRADE_DSP_FW, HexVersion)
// .then(report => {
// if (reportSuccess(report)) {
// return report.payload[0]
// }
// });
// }
export async function upgradeInDsp(data) {
let glasses = await common.connectDevice();
if (!glasses) {
return false;
}
return sendFirmwareInDsp(glasses, data);
}
/** need to upgrade firmware DP version? */
export async function isNeedUpgradeInDp() {
let glasses = await common.connectDevice();
if (!glasses) {
return 'not found device';
}
return glasses.sendReportTimeout(Protocol.MESSAGES.R_DP7911_FW_IS_UPDATE)
.then(report => {
if (reportSuccess(report)) {
return report.payload[0]
}
});
}
export async function upgradeInDp() {
let glasses = await common.connectDevice();
if (!glasses) {
return false;
}
// 添加眼镜休眠时间
const time = Protocol.time2Bytes('600');
return glasses.sendReportTimeout(Protocol.MESSAGES.W_SLEEP_TIME, time)
.then(report => {
if (reportSuccess(report)) {
return glasses.sendReportTimeout(Protocol.MESSAGES.W_UPDATE_DP)
.then(async report => {
if (reportSuccess(report)) {
// wait for air dp upgrade completed
while(!glasses._reports.has(27661) && common.curGlasses){
await sleep(500)
dpCurrent = glasses._reports.get(27660) ? glasses._reports.get(27660).status : 0
progressInDp(dpCurrent)
}
return glasses._reports.get(27661) ? glasses._reports.get(27661).status == 0 : false
}
return false
});
}
});
}
async function sendFirmwareInMcu(bootDevice, data) {
let ofs = 0;
const firstPackLen = 24;
const fwLen = data.byteLength;
let report = await bootDevice.sendReportTimeout(
Protocol.MESSAGES.W_UPDATE_MCU_APP_FW_START,
data.slice(ofs, ofs + firstPackLen));
if (!reportSuccess(report)) {
console.error('send fw data failed');
return false;
}
ofs += firstPackLen;
while (ofs < fwLen) {
progress(ofs, fwLen)
if ((ofs + 42) > fwLen) {
report = await bootDevice.sendReportTimeout(
Protocol.MESSAGES.W_UPDATE_MCU_APP_FW_TRANSMIT,
data.slice(ofs, fwLen));
if (!reportSuccess(report)) {
console.error('send fw data failed');
return false;
}
}
report = await bootDevice.sendReportTimeout(
Protocol.MESSAGES.W_UPDATE_MCU_APP_FW_TRANSMIT,
data.slice(ofs, ofs + 42));
if (!reportSuccess(report)) {
console.error('send fw data failed');
return false;
}
ofs += 42;
}
/* send finish */
report = await bootDevice.sendReportTimeout(Protocol.MESSAGES.W_UPDATE_MCU_APP_FW_FINISH);
// if (!reportSuccess(report)) {
// console.error('send fw data failed');
// return false;
// }
/* jump to app */
report = await bootDevice.sendReportTimeout(Protocol.MESSAGES.W_BOOT_JUMP_TO_APP);
// if (!reportSuccess(report)) {
// console.error('send fw data failed');
// return false;
// }
// Send the command to upgrade the DP
// report = await bootDevice.sendReportTimeout(Protocol.MESSAGES.W_UPDATE_DP);
current = 0
total = 0
return true;
}
async function sendFirmwareInDsp(glasses, data) {
let ofs = 0;
let sendBufferLength = 0
const firstPackLen = 24;
const fwLen = data.byteLength;
// prepare upgrade dsp
await glasses.sendReportTimeout(Protocol.MESSAGES.W_UPDATE_DSP_APP_FW_PREPARE);
// wait for air dsp upgrade boot
while (!glasses._reports.has(27663)) {
await sleep(100)
}
// await sleep(30000)
let report = await glasses.sendReportTimeout(
Protocol.MESSAGES.W_UPDATE_DSP_APP_FW_START,
data.slice(ofs, ofs + firstPackLen));
if (!reportSuccess(report)) {
console.error('send fw data failed');
return false;
}
ofs += firstPackLen;
while (ofs < fwLen) {
if ((ofs + 42) <= fwLen) {
progress(ofs, fwLen)
}
if ((ofs + 42) > fwLen) {
report = await glasses.sendReportTimeout(
Protocol.MESSAGES.W_UPDATE_DSP_APP_FW_TRANSMIT,
data.slice(ofs, fwLen));
if (!reportSuccess(report)) {
console.error('send fw data failed');
return false;
}
// 最后一包4K发送
// air DSP one package write finish, wait a while
// while(!glasses._reports.has(27662)){
// await sleep(100)
// }
// glasses._reports.delete(27662)
await sleep(300)
sendBufferLength = 0
break
}
report = await glasses.sendReportTimeout(
Protocol.MESSAGES.W_UPDATE_DSP_APP_FW_TRANSMIT,
data.slice(ofs, ofs + 42));
if (!reportSuccess(report)) {
console.error('send fw data failed');
return false;
}
ofs += 42;
sendBufferLength += 42
if (sendBufferLength >= 4096) {
// 等待4K包传完回送消息
// air DSP one package write finish, wait a while
while (!(glasses._reports.has(27662) && (glasses._reports.get(27662).status == 0 || glasses._reports.get(27662).status == 1))) {
// while(!glasses._reports.has(27662)){
await sleep(100)
}
glasses._reports.delete(27662)
// await sleep(300)
sendBufferLength -= 4096
}
}
/* send finish */
report = await glasses.sendReportTimeout(Protocol.MESSAGES.W_UPDATE_DSP_APP_FW_FINISH);
// if (!reportSuccess(report)) {
// console.error('send fw data failed');
// return false;
// }
// dsp write bin ==> first 100%
progress(ofs,fwLen)
/* Check whether the upgrade is complete */
// air DSP judge for flash&boot
// 删除之前刷新boot的过程dsp重新刷新
glasses._reports.delete(27664)
while(!(glasses._reports.has(27664) && (glasses._reports.get(27664).status == 100))){
if(common.curGlasses){
await sleep(100)
DspSecond = glasses._reports.has(27664) ? glasses._reports.get(27664).status : 0
}else{
return false
}
}
DspSecond = 100
while(!(glasses._reports.has(27667) && (glasses._reports.get(27667).status == 100))){
if(common.curGlasses){
await sleep(100)
DspThrid = glasses._reports.has(27667) ? glasses._reports.get(27667).status : 0
}else{
return false
}
}
DspThrid = 100
while (!(glasses._reports.has(27668) && (glasses._reports.get(27668).status == 0))) {
await sleep(100)
}
// report = await glasses.sendReportTimeout(Protocol.MESSAGES.E_DSP_UPDATE_ENDING);
current = 0
total = 0
DspSecond = 0
DspThrid = 0
return true;
}
// Delay synchronization program execution
function sleep(delay) {
return new Promise((resolve) => setTimeout(resolve, delay))
}
/** read air glasses SN*/
export async function getSN() {
let glasses = await common.connectDevice();
if (!glasses) {
return 'not found device';
}
return glasses.sendReportTimeout(Protocol.MESSAGES.R_GLASSID)
.then(report => {
if (reportSuccess(report)) {
return String.fromCharCode.apply(null, report.payload);
}
});
}
/** read air glassess Brightness */
export async function getBrightness() {
let glasses = await common.connectDevice();
if (!glasses) {
return 'not found device';
}
// what's the chance the getBrightness is the same as setBrightness?
return glasses.sendReportTimeout(Protocol.MESSAGES.W_BRIGHTNESS)
.then(report => {
if (reportSuccess(report)) {
return report.payload;
// return String.fromCharCode.apply(null, report.payload);
}
});
}
/** write air glassess Brightness */
export async function setBrightness(brightness_int) {
let glasses = await common.connectDevice();
if (!glasses) {
return 'not found device';
}
const payload = Protocol.brightInt2Bytes(brightness_int-1);
return glasses.sendReportTimeout(Protocol.MESSAGES.W_BRIGHTNESS, payload)
.then(report => {
if (reportSuccess(report)) {
return report.payload;
}
});
}
// export async function isAirOrLight(){
// let glasses = await common.connectDevice();
// if (!glasses) {
// return 'not found device';
// }
// if(glasses.device.productId == 1059 || glasses.device.productId == 1060){
// return 1
// }
// if(glasses.device.productId == 22332 || glasses.device.productId == 22336){
// return 2
// }
// }
function reportSuccess(report) {
return report && report.status === 0;
}
export {
current,
total,
dpCurrent
}

377
js_air/protocol.js Normal file
View File

@ -0,0 +1,377 @@
const HEAD = 0xfd;
const MSG_ID_OFS = 15;
const PAYLOAD_OFS = 22;
const LEN_OFS = 5;
const CRC_OFS = 1;
const TS_OFS = 7;
const RESERVED_OFS = 17;
export const NREAL_VENDOR_ID = 0x3318;
export const BOOT_PRODUCT_ID = 0x0423;
export const MESSAGES = {
W_CANCEL_ACTIVATION: 0x19,
R_MCU_APP_FW_VERSION: 0x26,//MCU APP FW version.
R_GLASSID: 0x15,//MCU APP FW version.
// R_DSP_APP_FW_VERSION: 0x21,//DSP APP FW version.
R_DP7911_FW_VERSION: 0x16,//DP APP FW version.
R_ACTIVATION_TIME: 0x29,//Read activation time
W_ACTIVATION_TIME: 0x2A,//Write activation time
W_SLEEP_TIME: 0x1E,//Write unsleep time
// R_IS_NEED_UPGRADE_DSP_FW: 0x49,//Check whether the DSP needs to be upgraded.
// W_FORCE_UPGRADE_DSP_FW: 0x69,//Force upgrade DSP.
R_DSP_VERSION: 0x18,//DSP APP FW version.
W_UPDATE_DSP_APP_FW_PREPARE: 0x45, //(Implemented in APP)
W_UPDATE_DSP_APP_FW_START: 0x46, //(Implemented in APP)
W_UPDATE_DSP_APP_FW_TRANSMIT: 0x47, //(Implemented in APP)
E_DSP_ONE_PACKGE_WRITE_FINISH: 0x6C0E, //(check 4K as one package send)
W_UPDATE_DSP_APP_FW_FINISH: 0x48, //(Implemented in APP)
E_DSP_UPDATE_ENDING: 0x6C11, //whether the upgrade is complete.
E_DSP_UPDATE_PROGRES: 0x6C10, //before upgrade dsp, air for update dsp boot
W_UPDATE_MCU_APP_FW_PREPARE: 0x3E,//Preparations for mcu app fw upgrade
W_UPDATE_MCU_APP_FW_START: 0x3F, //(Implemented in Boot)
W_UPDATE_MCU_APP_FW_TRANSMIT: 0x40, //(Implemented in Boot)
W_UPDATE_MCU_APP_FW_FINISH: 0x41, //(Implemented in Boot)
W_BOOT_JUMP_TO_APP: 0x42, //(Implemented in Boot)
W_MCU_APP_JUMP_TO_BOOT: 0x44,
R_DP7911_FW_IS_UPDATE:0x3C,
W_UPDATE_DP: 0x3D,
W_BOOT_UPDATE_MODE: 0x1100,
W_BOOT_UPDATE_CONFIRM: 0x1101,
W_BOOT_UPDATE_PREPARE: 0x1102,
W_BOOT_UPDATE_START: 0x1103,
W_BOOT_UPDATE_TRANSMIT: 0x1104,
W_BOOT_UPDATE_FINISH: 0x1105,
// P_ = pushed from device
// 11-bit payload
P_BUTTON_PRESSED: 0x6C05,
// appear to fire every 5 seconds with payload = 0
P_UKNOWN_HEARTBEAT: 0x6c02,
P_UKNOWN_HEARTBEAT_2: 0x6c12
};
export function keyForHex(hex){
for (let key in MESSAGES) {
if (MESSAGES[key] == hex) {
return key;
}
}
return null;
}
export function listKnownCommands(){
let data = [];
Object.keys(MESSAGES).map((key)=>{
data.push({
key,
hex:'0x'+MESSAGES[key].toString(16),
dec:MESSAGES[key]
})
})
console.log('air commands:');
console.table(data);
}
const crc32_table = [
0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA,
0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE,
0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940,
0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116,
0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A,
0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818,
0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C,
0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2,
0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086,
0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4,
0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,
0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8,
0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE,
0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252,
0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60,
0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04,
0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A,
0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E,
0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0,
0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6,
0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
];
function cmd_crc(buf, len) {
let CRC32_data = 0xFFFFFFFF;
for (let i = 0; i != len; ++i) {
let t = (CRC32_data ^ buf[i]) & 0xFF;
CRC32_data = ((CRC32_data >> 8) & 0xFFFFFF) ^ crc32_table[t];
}
return ~CRC32_data;
};
export function cmd_build(msgId, payload) {
let crc = 0;
let buff = new Uint8Array(64);
buff[0] = HEAD;
// memset(buff + TS_OFS, 0, 8);
// memset(buff + RESERVED_OFS, 0, 5);
buff[MSG_ID_OFS] = (msgId >> 0) & 0xff;
buff[MSG_ID_OFS + 1] = (msgId >> 8) & 0xff;
let len = /*LEN*/2 + /*TS*/8 + /*MSG_ID*/2 + /*RESERVED*/5;
if (payload != null && payload.length > 0) {
buff.set(payload, PAYLOAD_OFS);
len += payload.length;
}
buff[LEN_OFS] = (len) & 0xff;
buff[LEN_OFS + 1] = (len >> 8) & 0xff;
crc = cmd_crc(buff.slice(LEN_OFS), len);
buff[CRC_OFS] = (crc >> 0) & 0xff;
buff[CRC_OFS + 1] = (crc >> 8) & 0xff;
buff[CRC_OFS + 2] = (crc >> 16) & 0xff;
buff[CRC_OFS + 3] = (crc >> 24) & 0xff;
return buff;
};
function get_msgId(response) {
let msgId = (response[15]) | (response[16] << 8);
return msgId;
};
function get_status_byte(response) {
return response[22];
};
window.unparsed = [];
// 4-bytes to 32-bit float
function four_bytes_to_float(byte_array){
var data = byte_array; // [64, 226, 157, 10];
// Create a buffer
var buf = new ArrayBuffer(4);
// Create a data view of it
var view = new DataView(buf);
// set bytes
data.forEach(function (b, i) {
view.setUint8(i, b);
});
// Read the bits as a float; note that by doing this, we're implicitly
// converting it from a 32-bit float into JavaScript's native 64-bit double
var num = view.getFloat32(0);
return num;
}
export function parse_rsp(rsp) {
let result = {
msgId: -1,
status: 0,
payload: new Uint8Array()
};
if(rsp[0] !== HEAD){
// console.warn('HEAD mismatch', rsp[0]);
// console.warn([...rsp].map(x => x.toString(16).padStart(2,'0')).join(' '));
if(window.unparsed.length<1000){
window.unparsed.push([...rsp].map(x => x.toString(16).padStart(2,'0')).join(','))
// extract 16 32-bit,4-byte floats from 64 bytes
// NOPE
// window.unparsed.push([
// [
// four_bytes_to_float(rsp.slice(0,4)),
// four_bytes_to_float(rsp.slice(4,8)),
// four_bytes_to_float(rsp.slice(8,12)),
// four_bytes_to_float(rsp.slice(12,16)),
// ],
// [
// four_bytes_to_float(rsp.slice(16,20)),
// four_bytes_to_float(rsp.slice(20,24)),
// four_bytes_to_float(rsp.slice(24,28)),
// four_bytes_to_float(rsp.slice(28,32)),
// ],
// [
// four_bytes_to_float(rsp.slice(32,36)),
// four_bytes_to_float(rsp.slice(36,40)),
// four_bytes_to_float(rsp.slice(40,44)),
// four_bytes_to_float(rsp.slice(44,48)),
// ],
// [
// four_bytes_to_float(rsp.slice(48,52)),
// four_bytes_to_float(rsp.slice(52,56)),
// four_bytes_to_float(rsp.slice(56,60)),
// four_bytes_to_float(rsp.slice(60,64)),
// ]
// ])
}
/*
tried assuming the entire payload was 4x4 32-bit numbers,
but some of these values are way out there, so it's not
close but not quite
[2.3931767537309237e-38, 262153.6875, 1.7935222607106134e-33, -1.2112571145736495e-19]
[1.6100218705859986e-40, -1.0015453862283195e+36, 7.89323398984883e-39, 0]
[7.068319291428253e-38, -2.0569895575965996e-38, 4.316160146187087e+34, 3.6734198463196485e-40]
[4164320, 8.664825968624503e-22, -3.881952544155522e-34, 0]
*/
return;
// debugger
}
if (rsp == null || rsp.length < 1) {
return result;
}
result.msgId = get_msgId(rsp);
result.status = get_status_byte(rsp);
let packet_len = (rsp[5]) | (rsp[6] << 8);
if (packet_len < 18) {
return result;
}
packet_len = packet_len - 17 - 1;/* len, ts, msgid, reserve, status*/
result.payload = rsp.slice(PAYLOAD_OFS + 1, PAYLOAD_OFS + 1 + packet_len);
return result;
};
// todo: learn bitshifts/bitmasks and stuff instead of writing it out
// export const brightness_map = [
// // 3: 6 = increase (3= button id)
// // 7 = decrease
// // 7: intensity 0-7
// // 0 0 0 4 - 0 0 0 8 - 0 0 0
// "0 0 0 6 0 0 0 0 0 0 0", // dimmest
// "0 0 0 6 0 0 0 1 0 0 0",
// "0 0 0 6 0 0 0 2 0 0 0",
// "0 0 0 6 0 0 0 3 0 0 0",
// "0 0 0 6 0 0 0 4 0 0 0",
// "0 0 0 6 0 0 0 5 0 0 0",
// "0 0 0 6 0 0 0 6 0 0 0",
// "0 0 0 6 0 0 0 7 0 0 0", // brightest
// ]
// arg brightness_int 1-8, 8 being the brightest
export function brightInt2Bytes(brightness_int) {
// const req_bright = brightness_map[parseInt(brightness_int)-1];
// const byte_arr = new Uint8Array(req_bright.split(' ').map(x => parseInt(x)));
// return byte_arr
return new Uint8Array(['0' + brightness_int]);
}
// arg Uint8Array, returns string
export function brightBytes2Int(bright_byte_arr) {
return bright_byte_arr[7] + 1;
//return brightness_map.indexOf(bright_byte_arr.join(' ')) + 1;
}
export function bytes2Time(bytes) {
let time = '';
for (let i = bytes.byteLength - 1; i >= 0; i--) {
if(i > 3){
time += bytes[i].toString(2)
}else{
time += bytes[i].toString(2)
// time += bytes[i] << (i * 8);
}
}
return time;
};
export function hex2Decimal(byte){
return parseInt(byte, 16);
}
export function time2Bytes(timeStamp){
let arr = new Uint8Array(8)
let len = Math.floor((Number(timeStamp).toString(2).length) / 8)
let longN = parseInt(Number(timeStamp).toString(2).substring(0,Number(timeStamp).toString(2).length - 32), 2)
for (let i = len; i >= 0; i--) {
if(i > 3){
arr[i] = ((longN >>> ((i - 4) * 8)) & 0xFF);
}else{
arr[i] = ((timeStamp >>> (i * 8)) & 0xFF);
}
}
return arr;
}
// Formats an 8-bit integer |value| in hexadecimal with leading zeros.
export function hex8(value) {
return ('0x' + value.toString(16)).substring(-2).toUpperCase();
};
export function bytes2String(buffer) {
let bufferString = '';
for (let byte of buffer)
bufferString += ' ' + hex8(byte);
return bufferString;
}

1000
js_air/samples-2.csv Normal file

File diff suppressed because it is too large Load Diff

1000
js_air/samples.csv Normal file

File diff suppressed because it is too large Load Diff

37
js_air/sdkgraph.dot Normal file
View File

@ -0,0 +1,37 @@
digraph G {
NRSessionManager -> NRSubsystemManager
NRSubsystemManager -> NRDeviceSubsystem
NRDeviceSubsystem -> m_NativeGlassesController
NRDeviceSubsystem -> m_NativeHMD
m_NativeGlassesController -> GetTempratureLevel
NRSessionManager -> TrackingSubSystem
TrackingSubSystem -> InitTrackingMode
TrackingSubSystem -> _tss_Start
TrackingSubSystem -> Recenter
NRRenderer
TrackableFactory -> _tf_Start
NRTrackingModeChangedListener
NRDebugger -> Log
NRKernel -> NRDevice -> NRDevice_init
NRKernalUpdater
NRNotificationListener
NRKernel -> GlassesTemperatureLevel
NRKernel -> AsyncTaskExecuter
NRSessionManager -> CreateSession -> NRDevice_init
NRSessionManager -> AutoAdaptSessionConfig
NativeAPI -> NativeInterface
NativeAPI -> Configration -> UpdateConfig
}

90
js_light/glasses.js Normal file
View File

@ -0,0 +1,90 @@
import * as Protocol from './protocol.js';
import * as ProtocolYmodem from './protocolYmodem.js';
export default class Glasses extends EventTarget {
constructor(device) {
super();
this._device = device;
this._interestMsg = [];
this._reports = new Map();
// set input listener
device.oninputreport = this._handleInputReport.bind(this);
}
get device() { return this._device; }
connect() {
if (!this._device.opened) {
return this._device.open();
}
return Promise.resolve();
}
// Information parsing to distinguish between connect and upgrade
_handleInputReport({ device, reportId, data }) {
const reportData = new Uint8Array(data.buffer);
// Different parsing modes by protocol
let report = Protocol.parse_rsp(reportData);
this._reports.set(report.msgId, report);
}
// light connect
sendReport(msgId, payload, option) {
const data = new Uint8Array(payload);
const cmd = Protocol.cmd_build(msgId, data, option);
this._device.sendReport(0x00, cmd);
}
async sendReportTimeout(msgId, payload = [], option, timeout = 3000) {
this.sendReport(msgId, payload, option);
const time = new Date().getTime();
while ((new Date().getTime() - time) < timeout) {
if (this._reports.has(msgId)) {
let report = this._reports.get(msgId);
this._reports.delete(msgId);
return report;
}
await new Promise(resolve => setTimeout(resolve, 10));
}
return null;
}
// light upgrade
//#region
// sendReportUpgrade(msgId, payload) {
// const data = new Uint8Array(payload);
// const cmd = Protocol.cmd_build(msgId, data);
// this._device.controlTransferOut(0x00, cmd);
// }
// async sendReportTimeoutUpgrade(msgId, payload = [], timeout = 2000) {
// this.sendReportUpgrade(msgId, payload);
// const time = new Date().getTime();
// // console.log('sendReportTimeout', Protocol.hex8(msgId), payload);
// while ((new Date().getTime() - time) < timeout) {
// if (this._reports.has(msgId)) {
// let report = this._reports.get(msgId);
// // console.log('sendReportTimeout recv', report);
// this._reports.delete(msgId);
// return report;
// }
// await new Promise(resolve => setTimeout(resolve, 20));
// }
// return null;
// }
//#endregion
async isMcu() {
const report = await this.sendReportTimeout(Protocol.MESSAGES.R_ACTIVATION_TIME);
return report != null;
}
toString() {
return `<Glasses deviceName=${this._device.productName} vid=${this._device.vendorId} pid=${this._device.vendorId}>`;
}
}

462
js_light/manager.js Normal file
View File

@ -0,0 +1,462 @@
import Glasses from './glasses.js';
import * as Protocol from './protocol.js';
import * as ProtocolYmodem from './protocolYmodem.js';
import * as common from './../common.js'
// let devices = [];
const DEBUG = true;
// progress bar
let current
let total
/** check browser whether hid support */
// todo move to common
export function hidSupported() {
return !(navigator.hid === undefined);
}
/** check browser whether serial support */
// export function serialSupported() {
// return !(navigator.serial === undefined);
// }
// check glasses is open?
export function canCommand(device) {
if (device) {
let glasses = new Glasses(device);
return glasses.connect().then(() => {
return glasses.isMcu();
});
}
return false;
}
function getGlasses() {
return common.curGlasses;
}
export async function hasActivated(glasses) {
let activationReport = await glasses.sendReportTimeout(Protocol.MESSAGES.R_ACTIVATION_TIME);
if (!reportSuccess(activationReport) && activationReport.payload.length > 0) {
let time = Protocol.bytes2Time(activationReport.payload);
return time > 0;
}
return false;
}
/** activate the glasses */
export async function activate(timeStamp, flag) {
let glasses = await common.connectDevice();
if (!glasses) {
return false;
}
// if (await hasActivated(glasses)) {
// return true;
// }
// hardcode value = 300
// const time = new Uint8Array([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2C, 0x01]);
let time
if (flag == 1) {
time = new Uint8Array([0xff, 0xff]);
} else {
let timeHex = Number(timeStamp).toString(16)
time = new Uint8Array(timeHex.toString().length);
for (let i = 0; i < timeHex.toString().length; i++) {
time[i] = Asc2Hex(timeHex.toString().slice(i, i + 1))
}
}
return glasses.sendReportTimeout(Protocol.MESSAGES.W_ACTIVATION_TIME, time, 1)
.then(report => {
return reportSuccess;
});
}
/** deactivate the glasses */
export async function deactivate() {
let glasses = await common.connectDevice();
if (!glasses) {
return false;
}
// 时间清除
activate('ff', 1)
const deactiveMessage = new Uint8Array([0x31]);
return glasses.sendReportTimeout(Protocol.MESSAGES.W_CANCEL_ACTIVATION, deactiveMessage, 1)
.then(report => {
return reportSuccess(report);
});
}
// Conversion from decimal to hexadecimal
function Asc2Hex(value) {
return ('0x' + value.charCodeAt().toString(16));
}
/** read firmware version MCU*/
export async function getFirmwareVersionInMcu() {
let glasses = await common.connectDevice();
if (!glasses) {
return 'not found device';
}
return glasses.sendReportTimeout(Protocol.MESSAGES.R_MCU_APP_FW_VERSION)
.then(report => {
if (reportSuccess) {
return String.fromCharCode.apply(null, report.payload);
}
});
}
/** read firmware version AUDIO*/
export async function getFirmwareVersionInAudio() {
let glasses = await common.connectDevice();
if (!glasses) {
return 'not found device';
}
return glasses.sendReportTimeout(Protocol.MESSAGES.R_AUDIO_APP_FW_VERSION)
.then(report => {
if (reportSuccess) {
return String.fromCharCode.apply(null, report.payload);
}
});
}
/** read firmware version OV580*/
export async function getFirmwareVersionInOv580() {
let glasses = await common.connectDevice();
if (!glasses) {
return 'not found device';
}
return glasses.sendReportTimeout(Protocol.MESSAGES.R_OV580_APP_FW_VERSION)
.then(report => {
if (reportSuccess) {
return String.fromCharCode.apply(null, report.payload);
}
});
}
export async function selectBinFile() {
const pickerOpts = {
types: [
{
description: 'firmware image',
accept: {
'bin/*': ['.bin']
}
},
],
excludeAcceptAllOption: true,
multiple: false
};
let filePaths = await window.showOpenFilePicker(pickerOpts);
if (filePaths.length > 0) {
return filePaths[0].getFile();
}
return null;
}
// function isBootDevice(device) {
// return device.vendorId === ProtocolYmodem.NREAL_VENDOR_ID
// && device.productId === ProtocolYmodem.BOOT_PRODUCT_ID;
// }
// 通过hid识别设备
// async function waitBootDevice() {
// let devices = await navigator.hid.getDevices().then(devices => {
// return devices.filter(isBootDevice);
// });
// if (devices.length > 0) {
// return devices[0];
// }
// navigator.hid.requestDevice({
// filters: [{ vendorId: Protocol.NREAL_VENDOR_ID, productId: Protocol.BOOT_PRODUCT_ID }]
// });
// const time = new Date().getTime();
// while ((new Date().getTime() - time) < 2000) {
// await new Promise(resolve => setTimeout(resolve, 20));
// devices = await navigator.hid.getDevices().then(devices => {
// return devices.filter(isBootDevice);
// });
// if (devices.length > 0) {
// return devices[0];
// }
// }
// }
export async function getSerialPort() {
if ('serial' in navigator) {
console.log('当前浏览器支持serial')
}
return navigator.serial.requestPort({
filters: [{ usbVendorId: ProtocolYmodem.NREAL_VENDOR_ID, usbProductId: ProtocolYmodem.BOOT_PRODUCT_ID }]
});
}
// NREAL GLASSES
// function isBootport(port){
// return port.serialNumber === "00000000001A"
// }
// 通过USB虚拟串口识别
async function waitSerialPort() {
let port = await navigator.serial.getPorts().then(port => {
return port;
});
if (port.length > 0) {
return port[0];
}
// MCU + AUDIO + 580
// Prompt user to select any serial port.
port = await getSerialPort()
return port
}
export async function upgradeInMcuForSerial(data){
let port = await waitSerialPort();
// let device = await waitBootDevice();
if (port) {
// open serial port
await port.open({ baudRate: 115200 }); //串口波特率
return sendFirmwareInMcu(port, data);
}
}
export async function upgradeInMcu(data) {
let glasses = await common.connectDevice();
if (!glasses) {
return false;
}
return glasses.sendReportTimeout(Protocol.MESSAGES.W_MCU_SUPER_B_JUMP_TO_A)
// .then(report => {
// if (reportSuccess) {
// return glasses.sendReportTimeout(Protocol.MESSAGES.W_UPDATE_MCU_SUPER_A_FW_START);
// }
// })
.then(async (report) => {
if (reportSuccess) {
let port = await waitSerialPort();
// let device = await waitBootDevice();
if (port) {
// open serial port
await port.open({ baudRate: 115200 }); //串口波特率
return sendFirmwareInMcu(port, data);
}
}
});
}
// Delay synchronization program execution
function sleep(delay) {
return new Promise((resolve) => setTimeout(resolve, delay))
}
export async function upgradeInDp() {
let glasses = await common.connectDevice();
if (!glasses) {
return false;
}
// upgrade DP
if (DEBUG) console.log("send fw to upgrade the DP");
return glasses.sendReportTimeout(Protocol.MESSAGES.W_UPDATE_DP, [], 1)
.then(async report => {
if (!reportSuccess(report)) {
if (glasses._reports.has(68)) {
glasses._reports.delete(68)
}
// wait for light dp upgrade completed
while (!glasses._reports.has(68)) {
await sleep(500)
}
return glasses._reports.get(68).payload[0] == 49
}
return false
});
}
// check glasses is air or light?
// export async function isAirOrLight(){
// let glasses = await common.connectDevice();
// if (!glasses) {
// return 'not found device';
// }
// if(glasses.device.productId == 1059 || glasses.device.productId == 1060){
// return 1
// }
// if(glasses.device.productId == 22332 || glasses.device.productId == 22336){
// return 2
// }
// }
// Listening for serial port response
async function listenSerial(reader, port) {
while (port.readable) {
try {
while (true) {
const { value, done } = await reader.read();
if (value) {
return value
}
}
} catch (error) {
// TODO: Handle non-fatal read error.
// console.log(error)
}
}
}
// Parameters required for the progress bar
function progress(cur, all) {
current = cur
total = all
}
async function sendFirmwareInMcu(port, data) {
data = new Uint8Array(data)
let ofs = 0;
const firstPackLen = 1024;
const fwLen = data.byteLength;
const writer = port.writable.getWriter();
const reader = port.readable.getReader();
// Write upgrade command
await writer.write(Protocol.cmd_build(Protocol.MESSAGES.W_UPDATE_MCU_SUPER_A_FW_START))
console.log(await listenSerial(reader, port))
// Transmission over serial port
// Ymodem
while (ofs < fwLen) {
progress(ofs, fwLen)
if ((ofs + 1024) > fwLen) {
let DATNB = ProtocolYmodem.cmd_build(data.slice(ofs, fwLen))
await writer.write(DATNB)
// console.log(await listenSerial(reader, port))
break;
}
let DATNB = ProtocolYmodem.cmd_build(data.slice(ofs, ofs + firstPackLen))
await writer.write(DATNB)
// console.log(await listenSerial(reader, port))
// .then(async (report)=>{
// while (port.readable) {
// const reader = port.readable.getReader();
// try {
// while (true) {
// const { value, done } = await reader.read();
// if (done) {
// // Allow the serial port to be closed later.
// reader.releaseLock();
// break;
// }
// if (value) {
// console.log(value);
// }
// }
// } catch (error) {
// // TODO: Handle non-fatal read error.
// }
// }
// })
ofs += 1024;
}
/* send finish */
// if (!reportSuccess(report)) {
// console.error('send fw data failed');
// return false;
// }
let EOT_FIRST = ProtocolYmodem.cmd_build_EOT()
await writer.write(EOT_FIRST)
// console.log(await listenSerial(reader, port))
let EOT_SECOND = ProtocolYmodem.cmd_build_EOT()
await writer.write(EOT_SECOND)
// console.log(await listenSerial(reader, port))
// let SOH = ProtocolYmodem.cmd_build_SOH()
// await writer.write(SOH)
// console.log(await listenSerial(reader, port))
/* jump to B */
await writer.write(Protocol.cmd_build(Protocol.MESSAGES.W_MCU_SUPER_A_JUMP_TO_B))
// Send the command to upgrade the DP
// await writer.write(Protocol.cmd_build(Protocol.MESSAGES.W_UPDATE_DP, [], 1))
// report = await bootDevice.sendReportTimeout(Protocol.MESSAGES.W_MCU_SUPER_A_JUMP_TO_B);
// if (!reportSuccess(report)) {
// console.error('send fw data failed');
// return false;
// }
// close serial port
// reader.releaseLock();
// await port.close();
return true;
}
/** read Glasses SN*/
export async function getSN() {
let glasses = await common.connectDevice();
if (!glasses) {
return 'not found device';
}
return glasses.sendReportTimeout(Protocol.MESSAGES.R_GLASSID)
.then(report => {
if (reportSuccess) {
return String.fromCharCode.apply(null, report.payload);
}
});
}
function reportSuccess(report) {
return (report && report.payload.length === 0);
}
export {
current,
total,
}

249
js_light/protocol.js Normal file
View File

@ -0,0 +1,249 @@
// light demo connect
const HEAD = 0x02;
const END = 0x03;
const BREAK = 0x3a;
export const NREAL_VENDOR_ID = 0x0486;
export const BOOT_PRODUCT_ID = 0x573C;
export const MESSAGES = {
W_CANCEL_ACTIVATION: 0x65,
R_MCU_APP_FW_VERSION: 0x35,//MCU APP FW version.
R_AUDIO_APP_FW_VERSION: 0x35,//AUDIO APP FW version.
R_OV580_APP_FW_VERSION: 0x35,//OV580 APP FW version.
R_ACTIVATION_TIME: 0x66,//Read activation time
W_ACTIVATION_TIME: 0x66,//Write activation time
R_GLASSID: 0x43,//Read Glasses SN
R_ISNEED_ACTIVATION: 0x65,//Read whether to activate
W_MCU_SUPER_B_JUMP_TO_A: 0x38, //(Implemented in A)
W_UPDATE_MCU_SUPER_A_FW_START: 0x39, //(Implemented in A)
W_MCU_SUPER_A_JUMP_TO_B: 0x52, //(Implemented in A)
W_UPDATE_DP: 0x58,
W_BOOT_UPDATE_MODE: 0x1100,
W_BOOT_UPDATE_CONFIRM: 0x1101,
W_BOOT_UPDATE_PREPARE: 0x1102,
W_BOOT_UPDATE_START: 0x1103,
W_BOOT_UPDATE_TRANSMIT: 0x1104,
W_BOOT_UPDATE_FINISH: 0x1105,
};
const crc32_table = [
0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA,
0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE,
0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940,
0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116,
0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A,
0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818,
0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C,
0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2,
0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086,
0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4,
0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,
0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8,
0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE,
0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252,
0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60,
0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04,
0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A,
0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E,
0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0,
0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6,
0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
];
function cmd_crc(buf, len) {
let CRC32_data = 0xFFFFFFFF;
for (let i = 0; i != len; ++i) {
let t = (CRC32_data ^ buf[i]) & 0xFF;
CRC32_data = ((CRC32_data >> 8) & 0xFFFFFF) ^ crc32_table[t];
}
return ~CRC32_data;
};
export function cmd_build(msgId, payload, option) {
let DATATYPE
//102:激活时间 53:软件版本 52:当前固件中的7211软件版本 72:查询视频转换芯片7211的软件版本 97:SDK1.4以及以后版本的软件版本
// 101:获取是否需要激活 67:读取眼镜SN 57:休眠命令眼镜(SET) 101:失活眼镜(test) 88:升级DP
if (msgId == 102 || msgId == 53 || msgId == 52 || msgId == 72 || msgId == 97 || msgId == 101 || msgId == 67 || msgId == 88) {
if (option == 1) {
DATATYPE = 0x31 // SET命令
} else {
DATATYPE = 0x33 // GET命令
}
}
// 56:重启到达A区 57:触发升级程序 82:重启回到B区s
if (msgId == 56 || msgId == 57 || msgId == 82) {
DATATYPE = 0x40 // 超级命令
}
let num = 0;
let crc = 0;
let buff = new Uint8Array(64);
buff[num++] = HEAD; /*head*/
buff[num++] = BREAK; /*:*/
buff[num++] = DATATYPE; /*dataType*/
buff[num++] = BREAK; /*:*/
buff[num++] = msgId; /*commandId*/
buff[num++] = BREAK; /*:*/
if (payload != null && payload.length > 0) {
for (let i = 0; i < payload.length; i++) {
buff[num++] = payload[i] /*data*/
}
} else {
buff[num++] = 0x33; /* tmp data */
}
buff[num++] = BREAK; /*:*/
buff[num++] = 0x38 /*timeStamp*/
buff[num++] = 0x38
buff[num++] = BREAK; /*:*/
crc = cmd_crc(buff.slice(0, num), num);
buff[num++] = Asc2Hex(Hex2Decimal((crc >> 24) & 0xff)[0]);
buff[num++] = Asc2Hex(Hex2Decimal((crc >> 24) & 0xff)[1]);
buff[num++] = Asc2Hex(Hex2Decimal((crc >> 16) & 0xff)[0]);
buff[num++] = Asc2Hex(Hex2Decimal((crc >> 16) & 0xff)[1]);
buff[num++] = Asc2Hex(Hex2Decimal((crc >> 8) & 0xff)[0]);
buff[num++] = Asc2Hex(Hex2Decimal((crc >> 8) & 0xff)[1]);
buff[num++] = Asc2Hex(Hex2Decimal((crc >> 0) & 0xff)[0]);
buff[num++] = Asc2Hex(Hex2Decimal((crc >> 0) & 0xff)[1]);
buff[num++] = BREAK; /*:*/
buff[num++] = END; /*end*/
return buff;
};
function get_msgId(response) {
let msgId = response[4];
return msgId;
};
export function parse_rsp(rsp) {
let result = {
msgId: -1,
payload: new Uint8Array()
};
if (rsp == null || rsp.length < 1) {
return result;
}
result.msgId = get_msgId(rsp);
let packet_len = rsp.lastIndexOf(3) + 1
if (packet_len < 22) {
return result;
}
packet_len = packet_len - 6 - 14;/* head, dataType, msgid, timeStamp, crc, endflag*/
result.payload = rsp.slice(6, 6 + packet_len);
return result;
};
// export function time2Bytes(timeStamp){
// let arr = new Uint8Array(8)
// let len = Math.floor((Number(timeStamp).toString(2).length) / 8)
// for (let i = len; i >= 0; i--) {
// arr[i] = (timeStamp >> (i * 8) & 0xFFFFFFFF);
// }
// return arr;
// }
export function bytes2Time(bytes) {
let time = '';
for (let i = 0; i < bytes.byteLength; i++) {
time += String.fromCharCode(bytes[i]);
}
time = parseInt(time, 16)
return time;
};
// Formats an 8-bit integer |value| in hexadecimal with leading zeros.
export function hex8(value) {
return ('0x' + value.toString(16)).substring(-2).toUpperCase();
};
function Hex2Decimal(value) {
if (value.toString(16).length == 2) {
return value.toString(16)
} else {
return '0' + value.toString(16)
}
}
function Asc2Hex(value) {
return ('0x' + value.charCodeAt().toString(16));
}
export function bytes2String(buffer) {
let bufferString = '';
for (let byte of buffer)
bufferString += ' ' + hex8(byte);
return bufferString;
}

173
js_light/protocolYmodem.js Normal file
View File

@ -0,0 +1,173 @@
// light demo upgrade
const HEAD = 0x02;
let pn = 1; // PN
export const NREAL_VENDOR_ID = 0x0483;
export const BOOT_PRODUCT_ID = 0x5740;
export const MESSAGES = {
W_CANCEL_ACTIVATION: 0x19,
R_MCU_APP_FW_VERSION: 0x35,//MCU APP FW version.
R_ACTIVATION_TIME: 0x66,//Read activation time
W_ACTIVATION_TIME: 0x2A,//Write activation time
W_UPDATE_MCU_APP_FW_PREPARE: 0x3E,//Preparations for mcu app fw upgrade
W_UPDATE_MCU_APP_FW_START: 0x39, //(Implemented in APP A)
W_UPDATE_MCU_APP_FW_TRANSMIT: 0x40, //(Implemented in APP A)
W_UPDATE_MCU_APP_FW_FINISH: 0x41, //(Implemented in APP A)
W_BOOT_JUMP_TO_APP: 0x42, //(Implemented in APP A)
W_MCU_APP_JUMP_TO_BOOT: 0x38, //Jump into APP A
W_BOOT_UPDATE_MODE: 0x1100,
W_BOOT_UPDATE_CONFIRM: 0x1101,
W_BOOT_UPDATE_PREPARE: 0x1102,
W_BOOT_UPDATE_START: 0x1103,
W_BOOT_UPDATE_TRANSMIT: 0x1104,
W_BOOT_UPDATE_FINISH: 0x1105,
};
const crc16_table = [
0, 4129, 8258, 12387, 16516, 20645, 24774, 28903, 33032, 37161, 41290, 45419, 49548, 53677,
57806, 61935, 4657, 528, 12915, 8786, 21173, 17044, 29431, 25302, 37689, 33560, 45947, 41818,
54205, 50076, 62463, 58334, 9314, 13379, 1056, 5121, 25830, 29895, 17572, 21637, 42346, 46411,
34088, 38153, 58862, 62927, 50604, 54669, 13907, 9842, 5649, 1584, 30423, 26358, 22165, 18100,
46939, 42874, 38681, 34616, 63455, 59390, 55197, 51132, 18628, 22757, 26758, 30887, 2112, 6241,
10242, 14371, 51660, 55789, 59790, 63919, 35144, 39273, 43274, 47403, 23285, 19156, 31415,
27286, 6769, 2640, 14899, 10770, 56317, 52188, 64447, 60318, 39801, 35672, 47931, 43802, 27814,
31879, 19684, 23749, 11298, 15363, 3168, 7233, 60846, 64911, 52716, 56781, 44330, 48395, 36200,
40265, 32407, 28342, 24277, 20212, 15891, 11826, 7761, 3696, 65439, 61374, 57309, 53244, 48923,
44858, 40793, 36728, 37256, 33193, 45514, 41451, 53516, 49453, 61774, 57711, 4224, 161, 12482,
8419, 20484, 16421, 28742, 24679, 33721, 37784, 41979, 46042, 49981, 54044, 58239, 62302, 689,
4752, 8947, 13010, 16949, 21012, 25207, 29270, 46570, 42443, 38312, 34185, 62830, 58703, 54572,
50445, 13538, 9411, 5280, 1153, 29798, 25671, 21540, 17413, 42971, 47098, 34713, 38840, 59231,
63358, 50973, 55100, 9939, 14066, 1681, 5808, 26199, 30326, 17941, 22068, 55628, 51565, 63758,
59695, 39368, 35305, 47498, 43435, 22596, 18533, 30726, 26663, 6336, 2273, 14466, 10403, 52093,
56156, 60223, 64286, 35833, 39896, 43963, 48026, 19061, 23124, 27191, 31254, 2801, 6864, 10931,
14994, 64814, 60687, 56684, 52557, 48554, 44427, 40424, 36297, 31782, 27655, 23652, 19525, 15522,
11395, 7392, 3265, 61215, 65342, 53085, 57212, 44955, 49082, 36825, 40952, 28183, 32310, 20053,
24180, 11923, 16050, 3793, 7920
];
function cmd_crc(buf, len) {
let CRC16_data = 0x0000;
for (let i = 0; i != len; ++i) {
let t = (CRC16_data >> 8) ^ (buf[i] & 0xFF);
CRC16_data = (CRC16_data << 8) ^ crc16_table[t];
CRC16_data = '0x' + CRC16_data.toString(16).substring(CRC16_data.toString(16).length - 4)
Hex2Decimal(CRC16_data)
}
return CRC16_data;
};
export function cmd_build(payload) {
let num = 0;
let crc = 0;
let buff = new Uint8Array(1029);
buff[num++] = HEAD; /*head*/
if (pn > 255) {
pn = 0
}
buff[num++] = Decimal2Hex(pn); /*pn*/
buff[num++] = Decimal2Hex((~pn) >>> 0); /*xpn*/
// buff[num++] = 0x01 /*pn*/
// buff[num++] = 0xFE /*xpn*/
pn++
if (payload != null && payload.byteLength > 0) {
for (let i = 0; i < payload.byteLength; i++) {
buff[num++] = payload[i] /*data*/
}
} else {
buff[num++] = 0x33; /* tmp data */
}
crc = cmd_crc(buff.slice(3, 3 + payload.length), payload.length);
buff[num++] = (crc >> 8) & 0xff;
buff[num++] = (crc >> 0) & 0xff;
return buff;
};
export function cmd_build_EOT() {
let num = 0;
let buff = new Uint8Array(133);
buff[num++] = 0x04
buff[num++] = 0x00
buff[num++] = 0xFF
for (let i = 0; i < 128; i++) {
buff[num++] = 0x00
}
buff[num++] = 0x00
buff[num++] = 0x00
return buff
}
export function cmd_build_SOH() {
let num = 0;
let buff = new Uint8Array(133);
buff[num++] = 0x01
buff[num++] = 0x00
buff[num++] = 0xFF
for (let i = 0; i < 128; i++) {
buff[num++] = 0x00
}
buff[num++] = 0x00
buff[num++] = 0x00
return buff
}
export function bytes2Time(bytes) {
let time = 0;
for (let i = bytes.byteLength - 1; i >= 0; i--) {
time += bytes[i] << (i * 8);
}
return time;
};
// Formats an 8-bit integer |value| in hexadecimal with leading zeros.
export function hex8(value) {
return ('0x' + value.toString(16)).substring(-2).toUpperCase();
};
// Conversion from decimal to hexadecimal
function Decimal2Hex(value) {
if (value.toString(16).length == 1) {
return ('0x0' + value.toString(16))
} else {
return ('0x' + value.toString(16))
}
}
// Conversion from hexadecimal to decimal
function Hex2Decimal(value) {
return eval(value).toString(10)
}
// ASCII character to hexadecimal
function Asc2Hex(value) {
return ('0x' + value.charCodeAt().toString(16));
}
export function bytes2String(buffer) {
let bufferString = '';
for (let byte of buffer)
bufferString += ' ' + hex8(byte);
return bufferString;
}

28
key.pem Normal file
View File

@ -0,0 +1,28 @@
-----BEGIN PRIVATE KEY-----
MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQC+/XleDInw4Cx4
yK4nsEfa4pPr1ac4GnnxLNi2LRrk9opdursUCFAZ/5zaAz7RDOBeDw9DLpSDRKJ2
4eYqYodWEFQ0mYRXHWLep5vnsNU+5DJvvstB64aI7F4gN5KWm9180ghamdqP2nt8
Q8Y8SBKuBV6xA+YeW7nXAksAHs/9jUuRi0x/MR5Q4NXY05fmNYeJjsJ0dfD5jhT/
vbDgIOmczv4y28cMfgKBNDpzv5XW7y78rXZgfJP5ou/fjrUusOd46iIIL05Dyv8k
LLPNhGlk5lychCfQUwdI3ESLUtGNnJNLUVCO0In3WPEPnsUMDtJEacgPxLRPwSuT
8DGNdC55AgMBAAECggEBAJWvDIa0JwvcdZ44EZ3TX41h1HKZoROsVHO7JSEqGpDl
1C1/Yo1hsn2dwq1uq7WldNbi0KBjikuS6A1qIDyJue2uoIAU7Q5lXo6IJ/0erxI6
QHkpvB0u3OLE9UQkqcNV5vGjnp57RDtIDU2nxF6MUe+HD96F4r1aQD0NdABlJbdd
vr/THU2vfA+RbSg1Uhy2k2CS1k67wNn1qHVgZk8kwPPYOlX3x0sXpis6Ppe7fODi
e13O7YHgu9+xjjbFTqmt0xyHhX4VT0uhgTO7HrS3tGHD/yPGy+novIwbevRsT2sc
drmznOckM8Ml8JKLEUjUHuKwa5cHdTGc6SHBOfsre60CgYEA/cFwbFzb5WVx/XbD
LR3Y47IYOcEvTvNJytHZhrg04WKwwUECA3Cr1eTgx+gPcroSAN8ASsSq8r8OhQut
Sl8uBIMTL4Cd0gxtN8gKqjj7IUKZfw1S+kC/2QKg5kveHEC9g8OU4d98mgHgyWSw
suVbC1dk52TMrlDul5HAEcStSksCgYEAwK3rZBwmDcRLjxfc62IRsCvxaIy/jhWa
+gjD4k6VZwb4VTTd4TM6sLIdUhbPSjisdDnsz6hJt/6E0UKKZu7ZXMA1DDW0dP1V
AzK+POrnfIKIMStXHmVFd0SKyj1Ti2lZ65vXImOVX97uvmpVGUiztW1xlISdnr+t
llKmaK4jr8sCgYBi0N5nxG15UlzmeEYfHp1kZekbLIiwtPsKeVe9J6SoFFeCmj8f
edPgsoV6M3s4kQ8LucuSUi3D4/TSiK6N5Ky14xkoiWxr7JzneQX2LcRVumqt2FF0
1Jwg9O4VYHv5ApkKY7Jply8dhhe0NXq936TpsLnBhjZSt3+CFKb4BF/7KwKBgQCr
ymVVnMNRAvNbYatXMtkSehuDW/pudFT5GVeNLwOGGHDRh5FMeKCbajM6PZwUUPNx
rTO28hTIN+WzreA4ZjzmtXiWqkt7A2QItfVn2wkJulgzfrDuKN0GudYE+yjB4+yI
ZSorPx6vm9TBcYzuPiP8Xtgl0xe1srDSll5IdvragQKBgQDQHD1NaljMbffbQtcd
6wSJH6a8UyKvXKUzPaK8XlklJDH5GNmqy/0kgPWROZ3w6riu4XXbluRw9tlveKAO
IuOr3epJXZenLK0l6235p3Cp7CHUPWbPefNiH+DoEG7BE0VTyoUQMuS0XN+abrWv
/5qdNgzNzqy7VEO1/g0ZG2fzLw==
-----END PRIVATE KEY-----

54
tools/http.js Normal file
View File

@ -0,0 +1,54 @@
/*
* @Author: 哈库呐玛塔塔
* @Date: 2022-11-18 11:32:07
* @Descripttion:
* @LastEditors: 哈库呐玛塔塔
* @LastEditTime: 2022-11-21 14:36:15
*/
var http = {};
// var baseUrl = "https://app-test-api.nreal.work/api" // test
// var baseUrl = "https://app-uat-api.nreal.ai/api" // uat
var baseUrl = "https://app-api.nreal.ai/api" // master
http.rquest = function (option, callback) {
var url = baseUrl + option.url;
var method = option.method;
var data = option.data;
var timeout = option.timeout || 0;
var xhr = new XMLHttpRequest();
(timeout > 0) && (xhr.timeout = timeout);
xhr.onreadystatechange = function () {
if (xhr.readyState == 4) {
if (xhr.status >= 200 && xhr.status < 400) {
var result = xhr.responseText;
try { result = JSON.parse(xhr.responseText); } catch (e) { }
callback && callback(null, result);
} else {
callback && callback('status: ' + xhr.status);
}
}
}.bind(this);
xhr.open(method, url, true);
if (typeof data === 'object') {
try {
data = JSON.stringify(data);
} catch (e) { }
}
xhr.send(data);
xhr.ontimeout = function () {
callback && callback('timeout');
console.log('%c连%c接%c超%c时', 'color:red', 'color:orange', 'color:purple', 'color:green');
};
};
http.get = function (url, callback) {
console.log('url', url)
var option = url.url ? url : { url: url };
option.method = 'get';
this.rquest(option, callback);
};
http.post = function (option, callback) {
option.method = 'post';
this.rquest(option, callback);
};
export default http

224
tools/sparkline.js Normal file
View File

@ -0,0 +1,224 @@
// https://github.com/fnando/sparkline/blob/main/src/sparkline.js
function getY(max, height, diff, value) {
if (max===0) return height;
const pre_parse = (height - (value * height / max) + diff);
// console.log(pre_parse);
return parseFloat((pre_parse).toFixed(2));
}
function removeChildren(svg) {
[...svg.querySelectorAll("*")].forEach(element => svg.removeChild(element));
}
function defaultFetch(entry) {
return entry.value;
}
function buildElement(tag, attrs) {
const element = document.createElementNS("http://www.w3.org/2000/svg", tag);
for (let name in attrs) {
element.setAttribute(name, attrs[name]);
}
return element;
}
export function sparkline(svg, entries, options) {
removeChildren(svg);
if (entries.length <= 1) {
return;
}
options = options || {};
if (typeof(entries[0]) === "number") {
entries = entries.map(entry => {
return {value: entry};
});
}
// This function will be called whenever the mouse moves
// over the SVG. You can use it to render something like a
// tooltip.
const onmousemove = options.onmousemove;
// This function will be called whenever the mouse leaves
// the SVG area. You can use it to hide the tooltip.
const onmouseout = options.onmouseout;
// Should we run in interactive mode? If yes, this will handle the
// cursor and spot position when moving the mouse.
const interactive = ("interactive" in options) ? options.interactive : !!onmousemove;
// Define how big should be the spot area.
const spotRadius = options.spotRadius || 2;
const spotDiameter = spotRadius * 2;
// Define how wide should be the cursor area.
const cursorWidth = options.cursorWidth || 2;
// Get the stroke width; this is used to compute the
// rendering offset.
const strokeWidth = parseFloat(svg.attributes["stroke-width"].value);
// By default, data must be formatted as an array of numbers or
// an array of objects with the value key (like `[{value: 1}]`).
// You can set a custom function to return data for a different
// data structure.
const fetch = options.fetch || defaultFetch;
// Retrieve only values, easing the find for the maximum value.
const values = entries.map(entry => fetch(entry));
// The rendering width will account for the spot size.
const width = parseFloat(svg.attributes.width.value) - spotDiameter * 2;
// Get the SVG element's full height.
// This is used
const fullHeight = parseFloat(svg.attributes.height.value);
// The rendering height accounts for stroke width and spot size.
const height = fullHeight - (strokeWidth * 2) - spotDiameter;
// The maximum value. This is used to calculate the Y coord of
// each sparkline datapoint.
const max = Math.max(...values);
// Some arbitrary value to remove the cursor and spot out of
// the viewing canvas.
const offscreen = -1000;
// Cache the last item index.
const lastItemIndex = values.length - 1;
// Calculate the X coord base step.
const offset = width / lastItemIndex;
// Hold all datapoints, which is whatever we got as the entry plus
// x/y coords and the index.
const datapoints = [];
// Hold the line coordinates.
const pathY = getY(max, height, strokeWidth + spotRadius, values[0]);
let pathCoords = `M${spotDiameter} ${pathY}`;
values.forEach((value, index) => {
const x = index * offset + spotDiameter;
const y = getY(max, height, strokeWidth + spotRadius, value);
datapoints.push(Object.assign({}, entries[index], {
index: index,
x: x,
y: y
}));
pathCoords += ` L ${x} ${y}`;
});
if(pathCoords.includes("NaN")) {
debugger;
}
const path = buildElement("path", {
class: "sparkline--line",
d: pathCoords,
fill: "none"
});
let fillCoords = `${pathCoords} V ${fullHeight} L ${spotDiameter} ${fullHeight} Z`;
if(fillCoords.includes("NaN")) {
debugger;
}
const fill = buildElement("path", {
class: "sparkline--fill",
d: fillCoords,
stroke: "none"
});
svg.appendChild(fill);
svg.appendChild(path);
if (!interactive) {
return;
}
// const cursor = buildElement("line", {
// class: "sparkline--cursor",
// x1: offscreen,
// x2: offscreen,
// y1: 0,
// y2: fullHeight,
// "stroke-width": cursorWidth
// });
// const spot = buildElement("circle", {
// class: "sparkline--spot",
// cx: offscreen,
// cy: offscreen,
// r: spotRadius
// });
// svg.appendChild(cursor);
// svg.appendChild(spot);
// const interactionLayer = buildElement("rect", {
// width: svg.attributes.width.value,
// height: svg.attributes.height.value,
// style: "fill: transparent; stroke: transparent",
// class: "sparkline--interaction-layer",
// });
// svg.appendChild(interactionLayer);
// interactionLayer.addEventListener("mouseout", event => {
// cursor.setAttribute("x1", offscreen);
// cursor.setAttribute("x2", offscreen);
// spot.setAttribute("cx", offscreen);
// if (onmouseout) {
// onmouseout(event);
// }
// });
// interactionLayer.addEventListener("mousemove", event => {
// const mouseX = event.offsetX;
// let nextDataPoint = datapoints.find(entry => {
// return entry.x >= mouseX;
// });
// if (!nextDataPoint) {
// nextDataPoint = datapoints[lastItemIndex];
// }
// let previousDataPoint = datapoints[datapoints.indexOf(nextDataPoint) - 1];
// let currentDataPoint;
// let halfway;
// if (previousDataPoint) {
// halfway = previousDataPoint.x + ((nextDataPoint.x - previousDataPoint.x) / 2);
// currentDataPoint = mouseX >= halfway ? nextDataPoint : previousDataPoint;
// } else {
// currentDataPoint = nextDataPoint;
// }
// const x = currentDataPoint.x;
// const y = currentDataPoint.y;
// spot.setAttribute("cx", x);
// spot.setAttribute("cy", y);
// cursor.setAttribute("x1", x);
// cursor.setAttribute("x2", x);
// if (onmousemove) {
// onmousemove(event, currentDataPoint);
// }
// });
}
export default sparkline;