// 使用ws模块
const { monitorEventLoopDelay } = require('perf_hooks');
const WebSocket = require('ws');

// npm i stickpackage
// npm i ws

var ws = new WebSocket("ws://jiangyi.site:11111/");

let stringsArray = [
    // 获取(可批量)
    "get:heart_beat=?;time=?;version=?;work_status=?;fire_status=?;fault_status=?",
    "get:humidity=?;temperature=?;cur_photosen0=?;photosen0=?",
    "get:net=?;event_num=?;warning_num=?", 

    // 设置(可批量) 
    // "set:extra_time=180;standing_time=10;interval_time=600",
    // "set:photosen0=6000,6000,6000,6000",
    // "set:net=WIFI24,12345678,qq.com,1883,user,123456;event_num=1000;warning_num=1000",

    // 操作(单独)
    // "set:time=24,9,15,21,53,0",
    // "set:reset=1",
    // "set:erase_bit=7",
];
let strings_i = 0;



function bin2String(array) {
    return String.fromCharCode.apply(String, array);
}

function calculateChecksum16bit(code) {
    let sum = 0;
    for (let i = 0; i < code.length; i++) {
        sum += (code[i])&0xff;
        // console.log("sum:"+ sum +",i:"+ code[i] );
    }
    // 将结果转换为16位二进制字符串
    return sum&0xffff;
}

function bufferToHex (buffer) {
    return [...new Uint8Array (buffer)]
        .map (b => b.toString (16).padStart (2, "0"))
        .join (" ");
}

function stringToByteArray(str) {
    const encoder = new TextEncoder(); // 创建TextEncoder实例
    const bytes = encoder.encode(str); // 将字符串转换为字节序列
    return bytes; // 返回字节数组
}

//小端模式
function BytesToIntLittleEndian(bytes){
    var val = 0;
    for (var i = bytes.length - 1; i >= 0; i--) {        
        val += bytes[i];    
        if (i != 0) {
            val = val << 8;
        }    
    }
    return val;
}
 
//小端模式
//number 要转换的整形数值
//length 要转成什么byte数组，规定数组的长度
//如uint16，则lenght=2表示两个字节，转成的byte数组长度是length=2
//如uint32，则lenght=2表示两个字节，转成的byte数组长度是length=4
function IntToBytesLittleEndian(number, length){
    var bytes = [];
    var i = 0;
    do {
    bytes[i++] = number & (255);
    number = number>>8;
    } while ( i < length )
    return bytes;
}
 
//大端模式
function BytesToIntBigEndian(bytes){
    var val = 0;
    for (var i = 0; i < bytes.length; ++i) {        
        val += bytes[i];        
        if (i < bytes.length-1) {
            val = val << 8;
        }
    }
    return val;
}
 
//大端模式
//number 要转换的整形数值
//length 要转成什么byte数组，规定数组的长度
//如uint16，则lenght=2表示两个字节，转成的byte数组长度是length=2
//如uint32，则lenght=2表示两个字节，转成的byte数组长度是length=4
function IntToBytesBigEndian(number, length){
    var bytes = [];
    var i = length;
    do {
    bytes[--i] = number & (255);
    number = number>>8;
    } while (i)
    return bytes;
}

function Uint8ArrayToString(fileData){
    var dataString = "";
    for (var i = 0; i < fileData.length; i++) {
      dataString += String.fromCharCode(fileData[i]);
    }
   
    return dataString
  
  }

function stringToUint8Array(str){
    var arr = [];
    for (var i = 0, j = str.length; i < j; ++i) {
      arr.push(str.charCodeAt(i));
    }
   
    var tmpUint8Array = new Uint8Array(arr);
    return tmpUint8Array
  }
     
function intToHex(number, minLength) {
    return number.toString(16).padStart(minLength, '0');
}

function hexToString(hex) {
    var string = '';
    for (var i = 0; i < hex.length; i += 2) {
        string += String.fromCharCode(parseInt(hex.substr(i, 2), 16));
    }
    return string;
}


// 封包
function pack_send(str) {
    console.log("封包前:"+str);
    
    body = str;
    let data_len = body.length & 0xffff;
    let data_check = calculateChecksum16bit(stringToByteArray(body)) & 0xffff;
    // console.log("len:"+intToHex(data_len,4));
    // console.log("check:"+intToHex(data_check,4));
    const headBuf = Buffer.from([0x59, 0x4c, 0x3c, (data_len>>8)&0xff, (data_len)&0xff, (data_check>>8)&0xff, (data_check)&0xff]);
    const bodyBuf = Buffer.from(body);
    let pack_date = Buffer.concat([headBuf, bodyBuf]);
    ws.send(pack_date);
    // console.log("headBuf:"+bufferToHex(headBuf));
    // console.log("bodyBuf:"+bufferToHex(bodyBuf));
    console.log("封包后:"+bufferToHex(pack_date));    

}

function handler_recv(out){
    console.log("解析:" + out);
    str = String(out);
    let arr = str.split("=");
    if(arr.length == 2){
        let key = arr[0]
        let val = arr[1]
        if(key == "heart_beat"){
            let arr2 = val.split(",");
            if(arr2.length == 6){
                year = arr2[0];
                mon = arr2[1]; 
                day = arr2[2]; 
                hour = arr2[3];
                min = arr2[4]; 
                sec = arr2[5]; 
                console.log("heart_beat:20"+year+"-"+mon+"-"+day+" "+hour+":"+min+":"+sec);
            }

        }
    }
}


// 解包
let RecvBuf = "";
function unpack_recv(data) {
    datArray = stringToByteArray(data);
    console.log("接收 " + data.length +": "+ bufferToHex(datArray));
    // data添加到全局RecvBuf
    if(RecvBuf == ""){
        RecvBuf = data;
    }else{
        RecvBuf += data;
    }
    

    if(RecvBuf.length < 7){
        return;
    }

    // console.log(Buffer.from(RecvBuf.slice(0, 7)).toString('hex')); 

    //找包头 
    let index = -1;    
    for (i = 0; i < RecvBuf.length-3; i++) { 
        if(RecvBuf.slice(i, i+3) == "YL>"){
            index = i;
            break;
        }
    }
    if(index == -1){
        console.log("未找到到包头");
        return;
    }
    console.log("已查到包头, index:"+ index );

    // 如果不满足，断包了
    if(index+7 > RecvBuf.length){
        console.log("检查长度1失败");
        return;
    }
    console.log("检查长度1正常" );

    // console.log(RecvBuf.slice(index+3, index+5));   
    let data_len = BytesToIntBigEndian(RecvBuf.slice(index+3, index+5));
    // console.log("data_len:"+ data_len );
    // 检查实际长度
    if(index+7+data_len > RecvBuf.length || data_len == 0){
        console.log("检查长度2失败, data_len:" + data_len + "recv_len:" + RecvBuf.length );
        return;
    }    
    console.log("检查长度2正常" );

    // 检查校验码
    // console.log("5:" + RecvBuf[index+5]  +", 6:"+ RecvBuf[index+6] );
    let recv_check = BytesToIntBigEndian(RecvBuf.slice(index+5, index+7));
    let cal_check = calculateChecksum16bit(RecvBuf.slice(index+7,index+7+data_len));
    if(recv_check != cal_check){
        console.log("校验码失败, recv_check:" + recv_check  +", cal_check:"+ cal_check );
        return;
    }
    console.log("校验码成功" );

    //解析数据
    // let start = index+7;
    // let stop = index+7+data_len;
    // console.log("start:" + start  +", stop:"+ stop );
    let out = RecvBuf.slice(index+7,index+7+data_len);

    // 处理out数据
    handler_recv(out);

    // 留下剩余数据：正常情况下长度=0：无剩余数据
    let old_len = data.length;
    RecvBuf = RecvBuf.slice(index+7+data_len);
    console.log("剩余数据:" + RecvBuf);
}


// 设置一个每5000毫秒执行一次的定时器
setInterval(function() {
    array = stringsArray[strings_i];
    if(array.length >= 500){
        console.log("长度太大，请减少数据长度");
        return;
    }

    pack_send(array);

    strings_i++;
    if(strings_i >= stringsArray.length){
        strings_i = 0;
    }
}, 5000);



ws.onopen = function(evt) {
	console.log("Connection open ...");
};
 
ws.onmessage = function(evt) {
    unpack_recv(evt.data); //string
};
 
ws.onclose = function(evt) {
	console.log("Connection closed.");
};


