/
VoRoN
/
HTML
Обзор
Документация
Войти
/
VoRoN
/
HTML
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
Serial.html
912 строк
56 KB
NeiroN
update: Serial.html
14 фев 2026, 17:17
Верифицирован
14 фев 2026, 17:17
650cdbd
Код
Авторство
О чём код?
<html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Serial</title> <script> if(Object.assign == undefined)Object.assign = function() {var o = {};for(var i=0; i < arguments.length; i += 1) {var obj = arguments[i],keys = Object.keys(obj);for(var j=0; j < keys.length; j += 1)o[keys[j]] = obj[keys[j]]}return o}; //Format strings String.prototype.format = function () { var i=0,args=arguments,formats={ "f":function(v,s,c,f){v=v||0,s=s||(c[0]=='0'?'0':' '),c=parseInt(c||'0'),f=parseInt(f||'-1');v=f>0?(v>0?Math.floor(v):Math.ceil(v))+"."+Math.round(v*Math.pow(10,f)).toString().padStart(f,'0').slice(-f).padEnd(f,'0'):(f==-1?v.toString():Math.floor(v).toString());return c>v.length?s.repeat(c-v.length)+v:v}, "d":function(v,s,c,f){v=v||0,s=s||(c[0]=='0'?'0':' '),c=parseInt(c||'0');v=Math.floor(v).toString();return c>v.length?s.repeat(c-v.length)+v:v}, "s":function(v,s,c,f){v=v||'',s=s||' ',c=parseInt(c||'0');return c>v.length?s.repeat(c-v.length)+v:v}, "x":function(v,s,c,f){v=v||0,s=s||' ',c=parseInt(c||'0');v=Math.floor(v).toString(16);return c>v.length?s.repeat(c-v.length)+v:v}, "X":function(v,s,c,f){v=v||0,s=s||' ',c=parseInt(c||'0');v=Math.floor(v).toString(16).toUpperCase();return c>v.length?s.repeat(c-v.length)+v:v}, "R":function(v,s,c,f){return v.toString()}, }; return this.replace(/{([\d\w]+):?([0=-_*])?(\d+)?\.?(\d+)?([dfsxX])?}/g, function () { let val = typeof(args[0])=='object'?(args[0][arguments[1]||i]):(arguments[3]?args[arguments[1]||i]:args[i]); i++; return val != undefined ? formats[arguments[5]||"R"](val,arguments[2],arguments[3]||arguments[1],arguments[4]) : arguments[0]; }); }; Uint8Array.prototype.hex = function(d){return Array.from(this).map(x=>x.toString(16).padStart(2, '0').toUpperCase()).join(d==undefined?"-":d)} function bytes(data, size, cl){let buff=new ArrayBuffer(size);let uint=new Uint8Array(buff),ret=new cl(buff);ret[0]=data;return uint} function value(data, size, cl){let buff=new ArrayBuffer(size);let uint=new Uint8Array(buff);for(let i=0;i<size;i++)uint[i]=data[i];let ret=new cl(buff);return ret[0]} GetBytes = { "uint16":data=>bytes(data,2,Uint16Array), "uint32":data=>bytes(data,4,Uint32Array), "int16":data=>bytes(data,2,Int16Array), "int32":data=>bytes(data,4,Int32Array), "float32":data=>bytes(data,4,Float32Array), "float64":data=>bytes(data,8,Float64Array), "string":function(data){return (new TextEncoder()).encode(data)}, }; GetValue = { "uint16":data=>value(data,2,Uint16Array), "uint32":data=>value(data,4,Uint32Array), "int16":data=>value(data,2,Int16Array), "int32":data=>value(data,4,Int32Array), "float32":data=>value(data,4,Float32Array), "float64":data=>value(data,8,Float64Array), "string":function(data,charset){return (new TextDecoder(charset)).decode(data)}, }; class HexDumper { toString(){return "new HexDumper('#"+this.element.id+"')"} constructor(e){ if(typeof(e)=="string")e = document.querySelector(e); this.polling=false; this.polldata=""; e.style.display="block"; this.element = e; this.input = e.querySelector(".control input"); this.input.onkeyup = function(x){if(x.key=="Enter")send(new Uint8Array(x.srcElement.value.split("-").map(v=>parseInt(v,16))))}; } update(){} poll(){} async init(){} async deinit(){} split(buff){ if(buff.length>=16)return buff.slice(0,16); return null; } process(t,dir){ let el = document.createElement("div"); if(dir == undefined)dir="rx"; if(typeof(t)=="string")t=new Uint8Array(t.split("").map(e=>e.charCodeAt(0))); el.setAttribute("class",dir); el.innerHTML = dir.toUpperCase()+": "+t.hex(); this.element.querySelector(".dump").prepend(el); } } class DPS150 { Uout=0; Iout=0; Pout=0; themp=0; Wh=0; Ah=0; CC=false; CV=false; Uinp=0; output=false; MaxVoltage = 30.0; MaxCurrent = 5.0; MaxPower = 150.0; MaxThemp = 60.0; MinVoltage = 3.0; model=""; ver=""; hver=""; state=""; his = []; toString(){return "new DPS150('#"+this.element.id+"')"} constructor(e){ if(typeof(e)=="string")e = document.querySelector(e); this.polling=false; this.polldata=""; e.style.display="block"; this.element = e; //this.input = e.querySelector(".control input"); //this.input.onkeyup = function(x){if(x.key=="Enter")send(new Uint8Array(x.srcElement.value.split("-").map(v=>parseInt(v,16))))}; } update(){ for(s in this){ let e = $("#"+s); if(e!=null){ if(e.attributes['data-format'])e.innerHTML=e.attributes['data-format'].value.format(this[s]); if(e.tagName.toLowerCase()=='input'&&e.type=='checkbox')e.checked=this[s]; } } $('#pwr_btn').className.baseVal=options.parser.output?'red':'green'; $('#pwr_btn title').innerHTML=options.parser.output?'Отключить':'Включить'; } poll(obj){send(obj.cmdModule(0xf1,0xa1,0xe1,0))} async init(){this._lock=true; await send(this.cmdModule(0xf1,0xc1,0,1)); await new Promise(r => setTimeout(r, 100)); //await send(this.cmdModule(0xf1,0xb0,0,1)); await send(this.cmdModule(0xf1,0xa1,0xde,0)); await new Promise(r => setTimeout(r, 100)); await send(this.cmdModule(0xf1,0xa1,0xe0,0)); await new Promise(r => setTimeout(r, 100)); await send(this.cmdModule(0xf1,0xa1,0xdf,0)); await new Promise(r => setTimeout(r, 100)); await send(this.cmdModule(0xf1,0xa1,0xff,0)); } async deinit(){this._lock=false;await send(this.cmdModule(0xf1,0xc1,0,0))} split(buff){ let start=buff.indexOf(0xf0); if(start!=-1&&buff.length>4+start&&buff.length>=buff[3+start]+5+start)return buff.slice(start,buff[3+start]+5); } process(t,dir){ if(dir == undefined)dir="rx"; if(typeof(t)=="string")t=new Uint8Array(t.split("").map(e=>e.charCodeAt(0))); //let el = document.createElement("div"); //el.setAttribute("class",dir); //el.innerHTML = dir.toUpperCase()+": "+t.hex(); //this.element.querySelector(".dump").prepend(el); if(dir=="rx"){ if(t.length<4)return;//too small if(t.length<t[3]+5)return;//incorect length let crc = t[t[3]+4]; let data = t.slice(4,t[3]+4); let src = t[1]; let cmd = t[2]; switch(cmd){ case 0xd9: this.Ah = GetValue.float32(data); break; case 0xda: this.Wh = GetValue.float32(data); break; case 0xdb: this.output = data[0]==0x01; break; case 0xdc: this.state = ["OK","st1","st2","st3","st4","LVP","REP"][data[0]]; break; case 0xdd: this.CC = data[0]==0x01; this.CV = data[0]==0x00; break; case 0xde: this.model=GetValue.string(data); log("Model: "+this.model); break; case 0xdf: this.ver=GetValue.string(data); log("FW:"+this.ver); break; case 0xc0: this.Uinp = GetValue.float32(data); break; case 0xc3: this.Uout = GetValue.float32(data.slice(0,4)); this.Iout = GetValue.float32(data.slice(4,8)); this.Pout = GetValue.float32(data.slice(8,12)); let upd=false; if(this.his.length>0){ let last = this.his.slice(-1)[0]; if(this.Uout!=last.Uout||this.Iout!=last.Iout||this.Pout!=last.Pout)upd=true; }else{ upd=true; } if(upd)this.his.push({time:new Date(),Uout:this.Uout,Iout:this.Iout,Pout:this.Pout}); break; case 0xc4: this.themp = GetValue.float32(data); break; case 0xe0: this.hver=GetValue.string(data); log("HW:"+this.hver); break; case 0xe2: this.MaxVoltage = GetValue.float32(data); break; case 0xe3: this.MaxCurrent = GetValue.float32(data); break; case 0xff: let ret = []; for(let i=0;i<data.length/4;i++)ret[i]=GetValue.float32(data.slice(i*4,(i+1)*4)); this.Uinp=ret[0]; this.Voltage=ret[1]; this.Current=ret[2]; this.Uout=ret[3]; this.Iout=ret[4]; this.Pout=ret[5]; this.themp=ret[6]; this.group=[{vol:ret[7],cur:ret[8]},{vol:ret[9],cur:ret[10]},{vol:ret[11],cur:ret[12]},{vol:ret[13],cur:ret[14]},{vol:ret[15],cur:ret[16]},{vol:ret[17],cur:ret[18]}]; this.group.forEach((e,i)=>{$("#V_"+(i+1)).value=Math.round(e.vol*100)/100;$("#I_"+(i+1)).value=Math.round(e.cur*1000)/1000;}); this.MaxVoltage=ret[19]; this.MaxCurrent=ret[20]; this.MaxPower=ret[21]; this.MaxThemp=ret[22]; this.MinVoltage=ret[23]; break; default: log("pkt: "+t.hex()); log("cmd: 0x{0:02X}".format(cmd)); log("data: "+data.hex()); if(data.length>=4)for(let i=0;i<data.length/4;i++){ let dx = data.slice(i*4,(i+1)*4); log(" data{0:d}: ".format(i)+dx.hex()); log(" value{0:d}: ".format(i)+GetValue.float32(dx)); } break; } } } cmdModule(c1,c2,c3,data){ if(typeof(data)=="boolean")data=[data?1:0]; if(typeof(data)=="number")data=[data&255]; let ret = [c1,c2,c3,data.length]; ret.push(...data); ret.push(data.reduce((a,i)=>(a+i)&255,(ret[3]+c3)&255)); return new Uint8Array(ret); } CMD_1(){send(this.cmdModule(0xf1,0xc1,0,1))} CMD_2(){send(this.cmdModule(0xf1,0xc1,0,0))} CMD_3(){send(this.cmdModule(0xf1,0xa1,0xff,0))} CMD_4(){send(this.cmdModule(0xf1,0xa1,0xc0,0))} CMD_5(){send(this.cmdModule(0xf1,0xa1,0xde,0))} CMD_6(){send(this.cmdModule(0xf1,0xa1,0xe0,0))} CMD_7(){send(this.cmdModule(0xf1,0xa1,0xe1,0))} CMD_8(){send(this.cmdModule(0xf1,0xb1,0xdb,0))} CMD_9(){send(this.cmdModule(0xf1,0xb1,0xdb,1))} CMD_10(){send(this.cmdModule(0xf1,0xb1,0xd8,1))} CMD_11(){send(this.cmdModule(0xf1,0xb1,0xd8,0))} CMD_12(){send(this.cmdModule(0xf1,0xa1,0xd6,0))} CMD_13(){send(this.cmdModule(0xf1,0xb0,0,0))} CMD_14(){send(this.cmdModule(0xf1,0xa1,0xc3,0))} CMD_15(){send(this.cmdModule(0xf1,0xc0,0,1))} CMD_16(){send(this.cmdModule(0xf1,0xa1,0xdf,0))} CMD_17(){send(this.cmdModule(0xf1,0xa1,0xc1,0))} CMD_18(){send(this.cmdModule(0xf1,0xa1,0xc2,0))} setSpeed(data){send(this.cmdModule(0xf1,0xb0,0,({"9600":1,"19200":2,"38400":3,"57600":4,"115200":5})[data]))} //lock keys lock=false; getLock(){return this.lock} setLock(data){this.lock=data;send(this.cmdModule(0xf1,0xc1,0,data))} //enable output getOutput(){return this.output} setOutput(data){send(this.cmdModule(0xf1,0xb1,0xdb,data))} //measurement mode switch measure=false; getMeasure(){return this.measure} setMeasure(data){this.measure=data;send(this.cmdModule(0xf1,0xb1,0xd8,data))} //Values Voltage = 5.0; Current = 1.0; getVoltage(){return this.Voltage} getCurrent(){return this.Current} setVoltage(data){this.Voltage=data;send(this.cmdModule(0xf1,0xb1,0xc1,GetBytes.float32(data)))} setCurrent(data){this.Current=data;send(this.cmdModule(0xf1,0xb1,0xc2,GetBytes.float32(data)))} /* Config 0xf1 0xb1 [set] [val] 0xd1 - max Voltage 0xd2 - max Current 0xd3 - max Power 0xd4 - max Themp 0xd5 - min Voltage */ getMaxVoltage(){return this.MaxVoltage} getMaxCurrent(){return this.MaxCurrent} getMaxPower(){return this.MaxPower} getMaxThemp(){return this.MaxThemp} getMinVoltage(){return this.MinVoltage} setMaxVoltage(data){this.MaxVoltage=data;send(this.cmdModule(0xf1,0xb1,0xd1,GetBytes.float32(data)))} setMaxCurrent(data){this.MaxCurrent=data;send(this.cmdModule(0xf1,0xb1,0xd2,GetBytes.float32(data)))} setMaxPower(data){this.MaxPower=data;send(this.cmdModule(0xf1,0xb1,0xd3,GetBytes.float32(data)))} setMaxThemp(data){this.MaxThemp=data;send(this.cmdModule(0xf1,0xb1,0xd4,GetBytes.float32(data)))} set MinVoltage(data){this.MinVoltage=data;send(this.cmdModule(0xf1,0xb1,0xd5,GetBytes.float32(data)))} /* SetGroup 0xf1 0xb1 0xc3+id*2+(0:vol,1:curr) [value] */ group = [{vol:5.0,cur:1.0},{vol:5.0,cur:1.0},{vol:5.0,cur:1.0},{vol:5.0,cur:1.0},{vol:5.0,cur:1.0},{vol:5.0,cur:1.0}]; setGroupVoltage(id,data){this.group[id-1].vol=data;send(this.cmdModule(0xf1,0xb1,0xc3+id*2,GetBytes.float32(data)))} setGroupCurrent(id,data){this.group[id-1].cur=data;send(this.cmdModule(0xf1,0xb1,0xc4+id*2,GetBytes.float32(data)))} setGroup(id,data){this.setGroupVoltage(id,GetBytes.float32(data.vol));this.setGroupCurrent(id,GetBytes.float32(data.cur))} //switch to Bootloader firmware flash mode firmwareBoot(){send(this.cmdModule(0xf1,0xc0,0,1))} } class Modbus { toString(){return "new Modbus('#"+this.element.id+"')"} constructor(e){ if(typeof(e)=="string")e = document.querySelector(e); this.polling=false; this.polldata=""; e.style.display="block"; this.element = e.querySelector(".dump"); this.input = e.querySelector(".control input"); this.input.onkeyup = function(x){if(x.key=="Enter")send(new Uint8Array(x.srcElement.value.split("-").map(v=>parseInt(v,16))))}; } update(){} poll(){} async init(){} async deinit(){} split(buff){ if(buff.length>=7&&buff.length>=buff[3]+5)return buff.slice(0,buff[3]+5); return null; } process(t,dir){ let el = document.createElement("div"); if(dir == undefined)dir="rx"; if(typeof(t)=="string")t=new Uint8Array(t.split("").map(e=>e.charCodeAt(0))); el.setAttribute("class",dir); el.innerHTML = dir.toUpperCase()+": "+t.hex(); this.element.prepend(el); if(dir=="rx"){ let addr = t[0]; let func = t[1]; let data = t.slice(3,t[3]); let crc = t.slice(t[3]+3,t[3]+5); } } } class Nmea { toString(){return "new Nmea('#"+this.element.id+"')"} constructor(e){ if(typeof(e)=="string")e = document.querySelector(e); this.polling=false; this.polldata=""; this.data={}; this.time = new Date(0); this.timeStr = ""; this.dateStr = ""; this.coordType = "недоступно"; this.longtitude = 0; this.lattitude = 0; this.nSat = 0; this.vSat = 0; this.altitude = 0.0; this.speed = 0.0; this.azimuth = 0.0; this.PDOP = 0.0; this.HDOP = 0.0; this.VDOP = 0.0; this.hMAG = 0.0; this.sats = { "GP":{"name":"GPS (США)","ids":[],"data":{}}, "GL":{"name":"Глонасс (Россия)","ids":[],"data":{}}, "GA":{"name":"Galileo (Европа)","ids":[],"data":{}}, "BD":{"name":"Beidou (Китай)","ids":[],"data":{}}, "GQ":{"name":"QZSS (Япония)","ids":[],"data":{}}, "GN":{"name":"от спутников разных навигационных систем","ids":[],"data":{}} }; this._sats = []; this.element = e; this.element.style.display="block"; } poll(){} async init(){} async deinit(){} update(src){ let i=1; let s=""; for(s in this.sats[src].data){ let color = this.sats[src].ids.includes(parseInt(s))?"#00fa00":"#c0c0c0"; let x = 500+(90-this.sats[src].data[s].h)*Math.cos((this.sats[src].data[s].a)*(Math.PI/180))/-0.9; let y = 140+(90-this.sats[src].data[s].h)*Math.sin((this.sats[src].data[s].a)*(Math.PI/180))/0.9; let t = document.querySelector("#sat_"+i); if(t!=null)t.innerHTML = s; let tn = document.querySelector("#sat_"+i+"_n"),cn=document.querySelector("#sat_"+i+"_p"),e=document.querySelector("#sat_"+i+"_s"); if(tn!=null){tn.innerHTML = s;tn.setAttribute("x",x);tn.setAttribute("y",y+4);} if(cn!=null){cn.setAttribute("cx",x);cn.setAttribute("cy",y);cn.setAttribute("fill",color);cn.setAttribute("r",10);} if(e!=null){e.setAttribute("height",isNaN(this.sats[src].data[s].s)?0:this.sats[src].data[s].s*2.6);e.setAttribute("fill",color)} i++; } for(s in this){ let e = document.querySelector("#"+s); if(e!=null&&e.attributes['data-format']){ e.innerHTML=e.attributes['data-format'].value.format(this[s]); } } } split(buff){ let start=buff.indexOf(0x0D); if(start!=-1&&buff[start+1]==0x0A)return buff.slice(0,start+1);//\r\n return null; } process(t, dir){ t=GetValue.string(t).replace("\r","").replace("\n",""); let crc = t.split("*")[1]; let data = t.split("*")[0].split(","); let src = data[0].substr(1,2); let cmd = data[0].substr(3,3); switch(cmd){ case "GGA": this.setTime(data[1]); //this.setLat(data[2],data[3]); //this.setLon(data[4],data[5]); this.coordType = ["недоступно","автономно","дифференциально","PPS","фиксированный RTK","не фиксированный RTK","экстраполяция","фиксированные координаты","режим симуляции"][data[6]]; this.nSat = parseInt(data[7]); this.HDOP = parseFloat(data[8]); this.altitude = parseFloat(data[9]); break; case "GLL": if(data[6]=='A'){ this.setLat(data[1],data[2]); this.setLon(data[3],data[4]); this.setTime(data[5]); } break; case "GSA": this.mode = ["нет","2D","3D"][data[2]] this.PDOP = parseFloat(data[15]); this.HDOP = parseFloat(data[16]); this.VDOP = parseFloat(data[17]); this.sats[src].ids = data.slice(3,14).map(x=>parseInt(x)); break; case "GSV": if(data[2]=="1")this._sats = []; this._sats.push(data[4],data[8],data[12],data[16]); this.vSat = parseInt(data[3]); this.setSat(src,data.slice(4,8)); this.setSat(src,data.slice(8,12)); this.setSat(src,data.slice(12,16)); this.setSat(src,data.slice(16,20)); if(data[2]==data[1])Object.keys(this.sats[src].data).forEach(x=>{if(!this._sats.includes(x)){delete this.sats[src].data[x]}}); break; case "RMC": this.setTime(data[1]); if(data[2]=='A'){ this.setLat(data[3],data[4]); this.setLon(data[5],data[6]); } this.speed = parseFloat(data[7])*1.85; this.azimuth = parseFloat(data[8]); this.setDateC(data[9]); this.hMAG = parseFloat(data[10])*{"E":-1,"W":1,"M":1}[data[11]]; break; case "VTG": if(data[2]=='T'){ this.azimuth = parseFloat(data[1]); this.speed = parseFloat(data[7])*{"N":1.85,"K":1}[data[8]]; } this.hMAG = parseFloat(data[3])*{"E":-1,"W":1,"M":1}[data[4]]; break; case "ZDA": //this.setTime(data[1]); //this.setDate(data[2],data[3],data[4]); break; } } setSat(s,d){ let v = {}; v[d[0]]={h:parseInt(d[1]),a:parseInt(d[2]),s:parseInt(d[3])}; Object.assign(this.sats[s].data,v) } setDateC(d){this.setDate(d.slice(0,2),d.slice(2,4),"20"+d.slice(4,6))} setDate(d,m,y){ this.time.setUTCDate(parseInt(d)); this.time.setUTCMonth(parseInt(m)-1); this.time.setUTCFullYear(parseInt(y)); this.dateStr = this.time.toLocaleString().replace(" ","").split(",")[0]; } setTime(d){ this.time.setUTCHours(parseInt(d.substr(0,2))); this.time.setUTCMinutes(parseInt(d.substr(2,2))); this.time.setUTCSeconds(parseInt(d.substr(4,2))); this.time.setUTCMilliseconds(parseInt(d.substr(7,3))); this.timeStr = this.time.toLocaleString().replace(" ","").split(",")[1]; } setLat(d, s){ if(s==undefined)s="N"; this.lattitude = parseInt(d.substr(0,2)); this.lattitude += parseFloat(d.substr(2,8))/60; this.lattitude *= {"N":1,"S":-1}[s]; } setLon(d, s){ if(s==undefined)s="E"; this.longtitude = parseInt(d.substr(0,3)); this.longtitude += parseFloat(d.substr(3,8))/60; this.longtitude *= {"E":1,"W":-1}[s]; } } var defparser = {polling:false,polldata:"",poll:function(){},init:async function(){},deinit:async function(){},update:function(){},process:function(){},split:function(b){return b.slice(0,1)},toString:function(){return "defparser"}},ipc = null,port = null, options = {"baudRate":9600,dataBits:8,parity:"none",stopBits:1,flowControl:"hardware","parser":defparser,src:"GP",debug:false,debug_pkt:true}, history = {},buffer = null,$ = document.querySelector.bind(document),$$ = document.querySelectorAll.bind(document); setTimeout(function(){ for(s in options){let v=localStorage.getItem(s);if(v){options[s]=eval(v);if(typeof(options[s])=="boolean")$("#"+s).checked=options[s];}}; showConsole(options.debug); },100); function hide_panels(){ document.querySelectorAll(".panel").forEach(x=>x.style.display="none") } function setDevice(d){ $('#connect').innerHTML="Подключен к "+d.name; } function update(info){ Object.assign(deviceInfo,info); for(k in info){var el = $('#'+k); if(el!=undefined)el[typeof info[k] == "boolean"?"checked":"innerHTML"] = info[k]}; } function crc8(data){let crc=0xFF;for(var i=0;i<data.length;i++){crc^=data[i]&0xFF;for(var j=0;j<8;j++)if(crc & 1){crc>>=1;crc^=0xb8}else{crc>>=1}}return crc & 0xFFFF;} function crc16(data){let crc=0xFFFF,odd;for(d of data){crc=crc^d;for (let i=0;i<8;i++){odd=crc&0x0001;crc=crc>>1;if(odd){crc=crc^0xA001}}}return crc;} function log(msg){$("#data").value=msg+"\n"+$("#data").value;} function showConsole(x){$('#data').style.display = x?"block":"none";} var url = x=>URL.createObjectURL(x); var buff = []; var reader = null; async function connect(){ if(port!=null && port.connected && reader!=null){$("#connect").innerHTML="Соединение";log("Порт отсоединен");reader.cancel();options.parser.deinit().then(e=>port.close());return} if(ipc)clearInterval(ipc); if(navigator.serial!=undefined){ return navigator.serial.requestPort({}).then(e=>{ port = e; return port.open(options); }).then(async e=>{ if(options.parser.polling>0)ipc=setInterval(options.parser.poll,options.parser.polling,options.parser); if(port.connected){log("Порт соединен");$("#connect").innerHTML="Отсоединить";options.parser.init()} while(port.readable){ reader = port.readable.getReader(); try{ buff = []; while(true){ const{value,done} = await reader.read(); if(done)break; buff.push(...value); while(packet=options.parser.split(buff)){ recive(new Uint8Array(packet)); buff=buff.slice(packet.length); } } }catch(error){ log(error); }finally{ reader.releaseLock(); reader=null; break; } } /*e=""; while(reader){ let b = e = e+new TextDecoder().decode((await reader.read())["value"]); ee=e.split("\r\n"); e=ee.pop(); for(eee of ee)recive(eee); }*/ }).catch(e=>{ log(e);//port=null; }); } } async function recive(e){ if(options.debug_pkt)log(GetValue.string(e).replace("\r\n","")); if(options.debug_hex)log("RX: "+e.hex()); options.parser.process(e, "rx"); options.parser.update(options.src); } async function send(e){ if(typeof(e)=="function")e=e() if(typeof(e)=="string")e=GetBytes.string(e,"UTF-8"); if(options.debug_pkt)log(GetValue.string(e).replace("\r\n","")); if(options.debug_hex){log("TX: "+e.hex())}; options.parser.process(e, "tx"); if(port!=null && port.writable!=null){ const writer = port.writable.getWriter(); await writer.write(e); writer.releaseLock(); } return e } function set(param,value){ options[param]=value; localStorage.setItem(param,typeof(value)=='string'?'"'+value+'"':value.toString()); try{ $("#"+param+" a[class*=selected]").classList.remove("selected"); }catch{} try{ $("#"+param+" a[href*='"+value.toString()+"']").classList.add("selected"); }catch{} return value; } var valueAtBit = function (e, t) {return e >> t - 1 & 1}, valueAtIndex2Bit = function (e, t) { return e >> t - 1 & 3 }, crc = function(t){var a = 0;for (s = 0; s < t.length - 1; s++)0 == s ? a = t[s] : a ^= t[s];return a;}; </script> <style> body { margin:0; background:#FFFFFF; font-family: Helvetica, Arial, sans-serif; } #menu a.selected {background-color:#a3f3a3;} #menu {width:auto;display:block;text-align:left;line-height:1.2;height:34px;} #menu ul {display:block;margin:0;padding:0;position:relative;width:auto;font-size:0;text-align:left;color:#EEE;stroke:#EEE;fill:#EEE;background-color:#333;border:transparent;list-style:none;z-index:999999990;border-radius: 3px;} #menu li {display:inline-block;position:relative;font-size:0;margin:0;padding:0;} #menu >ul>li>span, #menu >ul>li>a {font-size:12px;color:inherit;text-decoration:none;padding:10px 15px;font-weight:400;text-transform:uppercase;letter-spacing:2px;display:flex;position:relative;transition:all 0.3s;flex-direction: row;flex-wrap: nowrap;justify-content: space-between;align-items: center;} #menu li:hover > span, #menu li:hover > a {color:#333;stroke:#333;fill:#333;background-color:#F3F3F3;} #menu .smenu {text-align:left;left:0;color: #333;fill:#333;stroke:#333;background-color:#F3F3F3;border:none;position:absolute;box-shadow: 0 4px 8px rgba(0,0,0,0.3);display:none;opacity:0;cursor:default;} #menu .smenu li {display: block;} #menu >ul>li>span.icon,#menu .smenu li > span.icon{ padding:6px } #menu .smenu li > span, #menu .smenu li > a {font-size:14px;font-weight:400;font-family:inherit;margin:0;padding:8px 20px; display:flex;color:inherit;text-decoration:none;flex-direction: row;flex-wrap: nowrap;justify-content: space-between;align-items: center;} #menu .smenu li:hover > span, #menu .smenu li:hover > a{color:#333;background-color:#DDD;} #menu .smenu li > .smenu.right0 {left:auto;right:100%;} #menu li:hover > .smenu {display:block;opacity:1;z-index:1;} #menu .smenu li > .smenu {left:100%; right:auto;top:0;} #menu ul.smenu {min-width:240px;} #menu div.smenu {text-align:center;} #menu .arrow {color:inherit;border-style:solid; border-width:2px 2px 0 0; padding:4px; transform:rotate(135deg);margin-top:-8.5px;margin-left:4px;position:relative;display: inline-block;width: 0;height: 0;vertical-align:middle;overflow:hidden;} #menu .smenu .arrow {transform:rotate(45deg);top:50%;margin-top:-6px;position:absolute;left:auto;right:20px;} @keyframes topItemAnimation {from {opacity: 0; transform:translate3d(0, -60px, 0);} to {opacity: 1; transform:translate3d(0, 0, 0);}} #menu li a {animation:none;} #menu.active li a { animation: topItemAnimation 0.5s cubic-bezier(.16,.84,.44,1) 0.083s backwards;} #menu.active li:nth-of-type(1) a { animation: topItemAnimation 0.5s cubic-bezier(.16,.84,.44,1) 0.5s backwards;} #menu.active li:nth-of-type(2) a { animation: topItemAnimation 0.5s cubic-bezier(.16,.84,.44,1) 0.41s backwards;} #menu.active li:nth-of-type(3) a { animation: topItemAnimation 0.5s cubic-bezier(.16,.84,.44,1) 0.33s backwards;} #menu.active li:nth-of-type(4) a { animation: topItemAnimation 0.5s cubic-bezier(.16,.84,.44,1) 0.25s backwards;} #menu.active li:nth-of-type(5) a { animation: topItemAnimation 0.5s cubic-bezier(.16,.84,.44,1) 0.16s backwards;}@media screen and (-ms-high-contrast: active), (-ms-high-contrast: none) { #menu.active li a{animation:none!important;}} #menu li .switch label {top: -7px;} #data {position:absolute;bottom: 0px;left:0px;width: 100vw;height: 260px;} input.switch[type=checkbox]{height:0;width:0;visibility:hidden;} label.switch{cursor: pointer;text-indent: -9999px;width: 40px;height:20px;background:grey;display:block;border-radius:20px;position:relative;} label.switch:after {content:'';position:absolute;top:1px;left:1px;width:18px;height:18px;background:#fff;border-radius:18px;transition: 0.3s;} input.switch:checked + label {background: #bada55;} input.switch:checked + label:after {left: calc(100% - 1px);transform: translateX(-100%);} label.switch:active:after {width: 26px;} div .switch input[type=checkbox]{height:0;width:0;visibility:hidden;} div .switch label{cursor: pointer;text-indent: -9999px;width: 40px;height:20px;background:grey;display:block;border-radius:20px;position:relative;} div .switch label:after {content:'';position:absolute;top:1px;left:1px;width:18px;height:18px;background:#fff;border-radius:18px;transition: 0.3s;} div .switch input:checked + label {background: #bada55;} div .switch input:checked + label:after {left: calc(100% - 1px);transform: translateX(-100%);} div .switch label:active:after {width: 26px;} .param {font-size: 28px;padding: 10px;margin: 20px;border: 1px dotted #555;border-radius: 10px;} .data {font-size: 28px;padding: 10px;} .param .switch {float: right;} #params { float: left; padding: 20px } #main, #main .panel {width: 100vw;height: calc(100vh - 35px);} #main .panel .control {width: 100vw;height: 20px;} #main .panel .control input {width: 100vw;} #main .panel .dump {width: 100vw;height: calc(100vh - 55px);overflow-y: scroll;overflow-x: hide;} #main .panel .dump .rx {color:#0000c0;} #main .panel .dump .tx {color:#c00000;} </style> </head> <body> <div id="menu"> <ul> <li> <span>Устройство</span> <ul class="smenu"> <li><a href="javascript:connect()" id="connect">Соединение</a></li> <li id="baudRate"><span>Скорость<i class="arrow"></i></span> <ul class="smenu" style="min-width: 80px;"> <li><a href="javascript:set('baudRate',1200)">1200</a></li> <li><a href="javascript:set('baudRate',2400)">2400</a></li> <li><a href="javascript:set('baudRate',4800)">4800</a></li> <li><a href="javascript:set('baudRate',9600)" class="selected">9600</a></li> <li><a href="javascript:set('baudRate',19200)">19200</a></li> <li><a href="javascript:set('baudRate',38400)">38400</a></li> <li><a href="javascript:set('baudRate',59600)">59600</a></li> <li><a href="javascript:set('baudRate',115200)">115200</a></li> </ul> </li> <li id="parity"><span>Четность<i class="arrow"></i></span> <ul class="smenu" style="min-width: 80px;"> <li><a href="javascript:set('parity','none')" class="selected">Нет</a></li> <li><a href="javascript:set('parity','even')">Четная</a></li> <li><a href="javascript:set('parity','odd')">Нечетная</a></li> </ul> </li> <li id="dataBits"><span>Биты данных<i class="arrow"></i></span> <ul class="smenu" style="min-width: 80px;"> <li><a href="javascript:set('dataBits',7)">7</a></li> <li><a href="javascript:set('dataBits',8)" class="selected">8</a></li> </ul> </li> <li id="stopBits"><span>Стоповые биты<i class="arrow"></i></span> <ul class="smenu" style="min-width: 80px;"> <li><a href="javascript:set('stopBits',1)" class="selected">1</a></li> <li><a href="javascript:set('stopBits',2)">2</a></li> </ul> </li> <li><span><label for="debug">Консоль отладки</label><input class="switch" id="debug" type="checkbox" onchange="$('#data').style.display=set('debug',this.checked)?'block':'none'"/><label class="switch" for="debug">Toggle</label></span></li> <li><span><label for="debug_pkt">Дамп пакетов</label><input class="switch" id="debug_pkt" type="checkbox" onchange="set('debug_pkt',this.checked)" /><label class="switch" for="debug_pkt">Toggle</label></span></li> <li><span><label for="debug_hex">Дамп HEX</label><input class="switch" id="debug_hex" type="checkbox" onchange="set('debug_hex',this.checked)" /><label class="switch" for="debug_hex">Toggle</label></span></li> </ul> </li> <li> <span>Обработчик</span> <ul id="parser" class="smenu"> <li><a href="javascript:hide_panels();set('parser',new HexDumper('#hex'))">HEX dump</a></li> <li><a href="javascript:hide_panels();set('parser',new Modbus('#modbus'))">Modbus RTU</a></li> <li><a href="javascript:hide_panels();set('parser',new DPS150('#dps150'))">Fnirsi DPS-150<i class="arrow"></i></a> <ul class="smenu" style="min-width: 100px;"> <li><span>1:<input id="Voltage" style="width:60px" type="number" value="5.00" step="0.01" onchange="options.parser.Voltage=this.value">V, <input id="Current" style="width:60px" type="number" value="1.000" step="0.001" onchange="options.parser.Current=this.value">A</span></li> <li><span><label for="output">Выход</label><input class="switch" id="output" type="checkbox" onchange="options.parser.setOutput(this.checked)"/><label class="switch" for="output">Toggle</label></span> <ul class="smenu" style="min-width: 100px;"> <li><span>1:<input id="V_1" style="width:60px" type="number" value="5.00" step="0.01" onchange="options.parser.setGroupVoltage(1,this.value)">V, <input id="I_1" style="width:60px" type="number" value="1.000" step="0.001" onchange="options.parser.setGroupCurrent(1,this.value)">A</span></li> <li><span>2:<input id="V_2" style="width:60px" type="number" value="5.00" step="0.01" onchange="options.parser.setGroupVoltage(2,this.value)">V, <input id="I_2" style="width:60px" type="number" value="1.000" step="0.001" onchange="options.parser.setGroupCurrent(2,this.value)">A</span></li> <li><span>3:<input id="V_3" style="width:60px" type="number" value="5.00" step="0.01" onchange="options.parser.setGroupVoltage(3,this.value)">V, <input id="I_3" style="width:60px" type="number" value="1.000" step="0.001" onchange="options.parser.setGroupCurrent(3,this.value)">A</span></li> <li><span>4:<input id="V_4" style="width:60px" type="number" value="5.00" step="0.01" onchange="options.parser.setGroupVoltage(4,this.value)">V, <input id="I_4" style="width:60px" type="number" value="1.000" step="0.001" onchange="options.parser.setGroupCurrent(4,this.value)">A</span></li> <li><span>5:<input id="V_5" style="width:60px" type="number" value="5.00" step="0.01" onchange="options.parser.setGroupVoltage(5,this.value)">V, <input id="I_5" style="width:60px" type="number" value="1.000" step="0.001" onchange="options.parser.setGroupCurrent(5,this.value)">A</span></li> <li><span>6:<input id="V_6" style="width:60px" type="number" value="5.00" step="0.01" onchange="options.parser.setGroupVoltage(6,this.value)">V, <input id="I_6" style="width:60px" type="number" value="1.000" step="0.001" onchange="options.parser.setGroupCurrent(6,this.value)">A</span></li> </ul> </li> <li><span><label for="_lock">Блокировка</label><input class="switch" id="_lock" type="checkbox" onchange="options.parser.lock=this.checked"/><label class="switch" for="_lock">Toggle</label></span></li> <li><a href="javascript:options.parser.firmwareBoot()">Режим прошивки</a></li> </ul> </li> <li><a href="javascript:hide_panels();set('parser',new Nmea('#nmea'))">NMEA 0183<i class="arrow"></i></a> <ul class="smenu" style="min-width: 100px;"> <li><a href="javascript:set('src','GP')" class="selected">GPS</a></li> <li><a href="javascript:set('src','GL')">Глонасс</a></li> <li><a href="javascript:set('src','GA')">Galileo</a></li> <li><a href="javascript:set('src','BD')">Beidou</a></li> <li><a href="javascript:set('src','GQ')">QZSS</a></li> <li><a href="javascript:set('src','GN')">разных</a></li> </ul> </li> </ul> </li> </ul> </div> <div id="main"> <svg id="dps150" class="panel" style="display: none;" width="640" height="480" viewbox="0 0 640 480" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> <style>@font-face{font-family: 'Digit';src: url('data:application/font-woff2;base64,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') format('woff');}</style> <style> .green .sym{fill:#00ff00;stroke:#00ff00;} .green .btn{fill:url('#green');stroke:#00ff00;} .red .sym{fill:#ff0000;stroke:#ff0000;} .red .btn{fill:url('#red');stroke:#ff0000;} .power text{fill:#ffffff;font-family:Serif;text-anchor: middle;} text.vol{fill:#ffff00;} text.cur{fill:#ffaa56;} text.pow{fill:#00ff00;} text.valP{font-family:Digit;} text.big{font-size:57;}text.bigT{font-size:32;} text.small{font-size:16;}text.smallT{font-size:14;} </style> <defs> <pattern height="12" id="diagonalHatch" patternUnits="userSpaceOnUse" width="5"> <path d="m-2,2l10,10" id="svg_12" stroke="#02aeff" stroke-width="4"/> </pattern> <filter id="svg_14_blur"> <feGaussianBlur stdDeviation="1.3"/> </filter> <linearGradient id="svg_30" x1="0" x2="1" y1="0" y2="0"> <stop offset="0" stop-color="#02aeff"/> <stop offset="0.60028" stop-color="#000000"/> </linearGradient> <linearGradient id="green" x1="0" x2="1" y1="0" y2="1"> <stop offset="0.32294" stop-color="#56ff56"/> <stop offset="0.86981" stop-color="#000000"/> </linearGradient> <linearGradient id="red" x1="0" x2="1" y1="0" y2="1"> <stop offset="0.32294" stop-color="#ff5656"/> <stop offset="0.86981" stop-color="#000000"/> </linearGradient> </defs> <g class="layer power"> <title>Layer 1</title> <rect fill="#000000" height="480" id="svg_1" stroke-width="0" width="640" x="0" y="0"/> <rect fill="url(#diagonalHatch)" height="145" id="svg_13" width="5" x="10" y="145"/> <rect fill="url(#diagonalHatch)" height="145" id="svg_13" width="5" x="625" y="145"/> <g id="svg_2"> <rect fill="#000000" height="42.2" id="svg_3" stroke-width="0" width="211" x="13" y="2"/> <path d="m44.65,9.03333l-14.06667,0c-2.81333,0 -4.57167,2.46167 -4.57167,5.275l0,24.61667l5.275,0l0,-12.30833l24.61667,0l0,-5.275l-24.61667,0l0,-7.03333l13.36333,0l0,-5.275l0.00001,-0.00001z" fill="#02aeff" id="svg_4" stroke-width="0"/> <path d="m62.23333,9.03333l0,29.89167l5.275,0l0,-22.85833l24.61667,22.85833l5.97833,0l0,-29.89167l-5.275,0l0,22.85833l-24.61667,-22.85833l-5.97833,0z" fill="#02aeff" id="svg_5" stroke-width="0"/> <rect fill="#02aeff" height="29.89167" id="svg_6" stroke-width="0" width="5.275" x="103.02666" y="9.03333"/> <path d="m111.46666,9.03333l27.07833,0c10.55,0 10.55,18.99 0,18.99l-14.06667,0l14.06667,6.33l36.57333,0c5.275,0 5.275,-7.03333 0,-7.03333l-17.935,0c-10.55,0 -10.55,-18.99 0,-18.99l26.375,0l0,5.275l-24.61667,0c-5.275,0 -5.275,8.44 0,8.44l17.58333,0c10.55,0 10.55,16.88 0,16.88l-40.44167,0l-19.34167,-9.14333c-3.165,-1.055 -3.165,-7.03333 1.055,-7.03333l18.99,0c5.275,0 5.275,-8.44 0,-8.44l-25.32,0l0,-5.275l0.00002,-0.00001z" fill="#02aeff" id="svg_7" stroke-width="0"/> <rect fill="#02aeff" height="19.34167" id="svg_8" stroke-width="0" width="5.275" x="187.075" y="19.58333"/> <circle cx="189.53666" cy="11.495" fill="#f6b03e" id="svg_9" r="4.22" stroke-width="0"/> <circle cx="197.625" cy="11.495" fill="#6bc1ac" id="svg_10" r="2.81333" stroke-width="0"/> <circle cx="204.65833" cy="11.495" fill="#02aeff" id="svg_11" r="1.75833" stroke-width="0"/> </g> <path d="m18,24.9l-13,0l0,105l15,15l0,145l-15,10l0,140l20,15l0,20l235,0l10,-15l130,0l10,15l200,0l25,-25l0,-150l-15,-15l0,-145l15,-13l0,-117l-425,0" fill="#000000" fill-opacity="0" id="svg_15" stroke="#02aeff" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" stroke-width="1.2"/> <path d="m273,465l123,0l8,10l-137,0l6,-10z" fill="#02aeff" id="svg_16" stroke="#000000" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" stroke-opacity="0" stroke-width="2"/> <path d="m5,446l15,11l0,18l-15,0" fill="#02aeff" id="svg_17" stroke="#000000" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" stroke-opacity="0" stroke-width="2"/> <path d="m617,475l18,0l0,-18" fill="#02aeff" id="svg_18" stroke="#000000" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" stroke-opacity="0" stroke-width="2"/> <g id="svg_19"> <path d="m410.59999,155.6l155.4094,0l9.9906,9l-9.9906,9l-155.4094,0l0,-18z" fill="url(#svg_30)" fill-opacity="0.35" filter="url(#svg_14_blur)" id="svg_14" stroke="#02aeff" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" stroke-width="1.2"/> <path d="m409.90002,154.9l155.87918,0l10.0208,9.9l-10.0208,9.9l-155.87918,0l0,-19.8z" fill="#000000" fill-opacity="0" id="svg_20" stroke="#02aeff" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null"/> <circle cx="421.3" cy="165.5" fill="#000000" id="svg_25" r="6.08276" stroke="#000000" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" stroke-opacity="0" stroke-width="0"/> <path d="m420.81484,157.99483c-4.00411,0 -7.24999,3.08919 -7.24999,6.9c0,3.81081 3.24589,6.9 7.24999,6.9c4.00411,0 7.24999,-3.08919 7.24999,-6.9c0,-3.81081 -3.24589,-6.9 -7.24999,-6.9zm-0.62005,3.10201l1.20717,0l0,1.222l-1.20717,0l0,-1.222zm1.99781,7.41653l-1.32789,0c-0.51579,0 -0.73577,-0.20889 -0.73577,-0.71022l0,-3.25915c0,-0.15667 -0.08779,-0.22978 -0.24143,-0.22978l-0.43897,0l0,-1.12848l1.32789,0c0.51629,0 0.73528,0.21933 0.73528,0.71022l0,3.2696c0,0.1467 0.08779,0.22978 0.24143,0.22978l0.43897,0l0,1.11803l0.0005,0l-0.00001,0z" fill="#02aeff" id="svg_24" stroke="#000000" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" stroke-opacity="0" stroke-width="0"/> <text fill="#02aeff" font-family="Serif" font-size="14" id="svg_29" text-anchor="middle" x="498.3" xml:space="preserve" y="169.5">Основная информация</text> <path d="m575,165l30,0l10,10l0,113l15,15l0,90l-14,14l-43,0l-27,24l0,40l-132,0l-14,-20l0,-285l10,0" fill="none" stroke="#02aeff"/> </g> <text class="valP small" id="themp" x="580" y="30" data-format="{05.2f}">00.00</text><text class="smallT" x="615" y="32">°C</text> <text class="valP big vol" id="Uout" x="496" y="238" data-format="{05.2f}">00.00</text><text class="bigT vol" x="603" y="244">V</text> <text class="valP big cur" id="Iout" x="496" y="315" data-format="{05.3f}">0.000</text><text class="bigT cur" x="603" y="323">A</text> <text class="valP big pow" id="Pout" x="496" y="391" data-format="{05.2f}">00.00</text><text class="bigT pow" x="603" y="401">W</text> <text class="valP small" id="Ah" x="466" y="437" data-format="{09.4f}">0000.0000</text><text class="smallT" x="531" y="439">Ah</text> <text class="valP small" id="Wh" x="466" y="462" data-format="{09.4f}">0000.0000</text><text class="smallT" x="531" y="465">Wh</text> <g id="pwr_btn" class="green" onclick="options.parser.setOutput(!options.parser.output)"> <title>Включение</title> <path d="m550,468l56,0l22,-21l0,-35l-53,0l-25,22l0,34z" fill-opacity="0.44" class="btn" stroke-width="2"/> <path d="m595.57701,428.94991c-1.00532,-0.48697 -2.21617,-0.06884 -2.70617,0.9385c-0.48798,1.00735 -0.06682,2.21819 0.9385,2.70617c3.15366,1.53481 5.33034,4.76339 5.32832,8.50526c-0.01012,5.21796 -4.23188,9.43972 -9.44883,9.44883c-5.21796,-0.01012 -9.43972,-4.23188 -9.44984,-9.44883c-0.00202,-3.74389 2.17567,-6.97551 5.33237,-8.50729c1.00735,-0.48798 1.42547,-1.69882 0.9385,-2.70617c-0.48798,-1.00532 -1.6968,-1.42649 -2.70415,-0.9385c-4.50725,2.18174 -7.61535,6.80644 -7.61738,12.15196c0.00202,7.45539 6.04308,13.49746 13.50049,13.49948c7.4564,-0.00202 13.49847,-6.04409 13.49948,-13.49948c-0.00202,-5.3435 -3.10608,-9.96516 -7.6113,-12.14994l0.00001,0.00001zm-5.88818,9.95604c1.1177,0 2.02381,-0.90509 2.02381,-2.02482l0,-9.44984c0,-1.11871 -0.90611,-2.02381 -2.02381,-2.02381c-1.11973,0 -2.02482,0.90611 -2.02482,2.02381l0,9.44883c0,1.11973 0.90509,2.02583 2.02482,2.02583z" class="sym" stroke-width="0"/> </g> </g> </svg> <div id="modbus" class="panel" style="display: none;"><!--<h1>Modbus RTU</h1>--><div class="control"><input type="text"/></div><div class="dump"></div></div> <svg id="nmea" class="panel" style="display:none" width="640" height="480" viewbox="0 0 640 480" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> <style> .std{stroke:#000000;stroke-width:1;fill:none;} text{text-anchor:middle;} .sat{font-size:10px;} .par,.val{font-size:24px;} .par{text-anchor:start;font-weight:bold;} .val{text-anchor:end;} </style> <g class="layer"> <path class="std" d="m400,140a100,100,0,0,0,100,100l0,-200a100,100,0,0,1,100,100l-200,0a100,100,0,0,1,100,-100m0,200a100,100,0,0,0,100,-100m-170,-70l140,140m0,-140l-140,140m0,-70a70,70,0,0,0,70,70a70,70,0,0,0,70,-70a70,70,0,0,0,-70,-70a70,70,0,0,0,-70,70m30,0a40,40,0,0,0,40,40a40,40,0,0,0,40,-40a40,40,0,0,0,-40,-40a40,40,0,0,0,-40,40" /> <rect class="std" x=10 y=10 width=340 height=180 /> <rect x=40 y=150 width=20 height=0 stroke="none" fill="#00fa00" transform="rotate(-180,40,150)" id="sat_1_s"/> <rect x=70 y=150 width=20 height=0 stroke="none" fill="#00fa00" transform="rotate(-180,70,150)" id="sat_2_s"/> <rect x=100 y=150 width=20 height=0 stroke="none" fill="#00fa00" transform="rotate(-180,100,150)" id="sat_3_s"/> <rect x=130 y=150 width=20 height=0 stroke="none" fill="#00fa00" transform="rotate(-180,130,150)" id="sat_4_s"/> <rect x=160 y=150 width=20 height=0 stroke="none" fill="#00fa00" transform="rotate(-180,160,150)" id="sat_5_s"/> <rect x=190 y=150 width=20 height=0 stroke="none" fill="#00fa00" transform="rotate(-180,190,150)" id="sat_6_s"/> <rect x=220 y=150 width=20 height=0 stroke="none" fill="#00fa00" transform="rotate(-180,220,150)" id="sat_7_s"/> <rect x=250 y=150 width=20 height=0 stroke="none" fill="#00fa00" transform="rotate(-180,250,150)" id="sat_8_s"/> <rect x=280 y=150 width=20 height=0 stroke="none" fill="#00fa00" transform="rotate(-180,280,150)" id="sat_9_s"/> <rect x=310 y=150 width=20 height=0 stroke="none" fill="#00fa00" transform="rotate(-180,310,150)" id="sat_10_s"/> <rect x=340 y=150 width=20 height=0 stroke="none" fill="#00fa00" transform="rotate(-180,340,150)" id="sat_11_s"/> <circle cx=500 cy=140 r=0 id="sat_1_p" fill="#00fa00" stroke-width=1 stroke="#000000" /> <circle cx=500 cy=140 r=0 id="sat_2_p" fill="#00fa00" stroke-width=1 stroke="#000000" /> <circle cx=500 cy=140 r=0 id="sat_3_p" fill="#00fa00" stroke-width=1 stroke="#000000" /> <circle cx=500 cy=140 r=0 id="sat_4_p" fill="#00fa00" stroke-width=1 stroke="#000000" /> <circle cx=500 cy=140 r=0 id="sat_5_p" fill="#00fa00" stroke-width=1 stroke="#000000" /> <circle cx=500 cy=140 r=0 id="sat_6_p" fill="#00fa00" stroke-width=1 stroke="#000000" /> <circle cx=500 cy=140 r=0 id="sat_7_p" fill="#00fa00" stroke-width=1 stroke="#000000" /> <circle cx=500 cy=140 r=0 id="sat_8_p" fill="#00fa00" stroke-width=1 stroke="#000000" /> <circle cx=500 cy=140 r=0 id="sat_9_p" fill="#00fa00" stroke-width=1 stroke="#000000" /> <circle cx=500 cy=140 r=0 id="sat_10_p" fill="#00fa00" stroke-width=1 stroke="#000000" /> <circle cx=500 cy=140 r=0 id="sat_11_p" fill="#00fa00" stroke-width=1 stroke="#000000" /> <text class="sat" id="sat_1_n" x=500 y=144 ></text> <text class="sat" id="sat_2_n" x=500 y=144 ></text> <text class="sat" id="sat_3_n" x=500 y=144 ></text> <text class="sat" id="sat_4_n" x=500 y=144 ></text> <text class="sat" id="sat_5_n" x=500 y=144 ></text> <text class="sat" id="sat_6_n" x=500 y=144 ></text> <text class="sat" id="sat_7_n" x=500 y=144 ></text> <text class="sat" id="sat_8_n" x=500 y=144 ></text> <text class="sat" id="sat_9_n" x=500 y=144 ></text> <text class="sat" id="sat_10_n" x=500 y=144 ></text> <text class="sat" id="sat_11_n" x=500 y=144 ></text> <rect class="std" x=20 y=20 width=20 height=130 /> <rect class="std" x=50 y=20 width=20 height=130 /> <rect class="std" x=80 y=20 width=20 height=130 /> <rect class="std" x=110 y=20 width=20 height=130 /> <rect class="std" x=140 y=20 width=20 height=130 /> <rect class="std" x=170 y=20 width=20 height=130 /> <rect class="std" x=200 y=20 width=20 height=130 /> <rect class="std" x=230 y=20 width=20 height=130 /> <rect class="std" x=260 y=20 width=20 height=130 /> <rect class="std" x=290 y=20 width=20 height=130 /> <rect class="std" x=320 y=20 width=20 height=130 /> <text id="sat_1" x=30 y=170 >--</text> <text id="sat_2" x=60 y=170 >--</text> <text id="sat_3" x=90 y=170 >--</text> <text id="sat_4" x=120 y=170 >--</text> <text id="sat_5" x=150 y=170 >--</text> <text id="sat_6" x=180 y=170 >--</text> <text id="sat_7" x=210 y=170 >--</text> <text id="sat_8" x=240 y=170 >--</text> <text id="sat_9" x=270 y=170 >--</text> <text id="sat_10" x=300 y=170 >--</text> <text id="sat_11" x=330 y=170 >--</text> <text class="par" x=30 y=230>Широта:</text><text id="lattitude" data-format="{0.6f}" class="val" x=250 y=230>00.000000</text> <text class="par" x=30 y=260>Долгота:</text><text id="longtitude" data-format="{0.6f}" class="val" x=250 y=260>00.000000</text> <text class="par" x=30 y=290>Азимут:</text><text id="azimuth" data-format="{0.2f}" class="val" x=250 y=290>00.00</text> <text class="par" x=30 y=320>Скорость:</text><text id="speed" data-format="{0.2f} км/ч" class="val" x=310 y=320>00.00 км/ч</text> <text class="par" x=30 y=350>Спутников:</text><text id="nSat" data-format="{0.2d}" class="val" x=250 y=350>00</text> <text class="par" x=30 y=380>Видимых:</text><text id="vSat" data-format="{0.2d}" class="val" x=250 y=380>00</text> <text class="par" x=30 y=410>Время:</text><text id="timeStr" data-format="{0:s}" class="val" x=250 y=410></text> <text class="par" x=30 y=440>Дата:</text><text id="dateStr" data-format="{0:s}" class="val" x=250 y=440></text> <text class="par" x=400 y=290>HDOP:</text><text id="HDOP" data-format="{0.2f}" class="val" x=550 y=290>00.00</text> <text class="par" x=400 y=320>VDOP:</text><text id="VDOP" data-format="{0.2f}" class="val" x=550 y=320>00.00</text> <text class="par" x=400 y=350>PDOP:</text><text id="PDOP" data-format="{0.2f}" class="val" x=550 y=350>00.00</text> <text id="coordType" data-format="{0:s}" class="par" x=380 y=30>Подключите GNSS</text> <text x=510 y=60 >N</text><text x=490 y=230 >S</text> <text x=410 y=135 >W</text><text x=590 y=160 >E</text> </g> </svg> <div id="hex" class="panel" style="display: none;"><div class="control"><input type="text" placeholder="Данные для отправки в формате 00-00-00-00"/></div><div class="dump"></div></div> </div> <textarea id="data" style="display: none;" rows=20 cols=50></textarea> </body> </html>