Skip to content
typescript
import {SetUpCovDataType} from "@EBSDK/EBCompiler/EBModel/interface";
import {QueryEvent} from "@EBSDK/EBCompiler/EBModel/Event/QueryEvent";
import {EBModel} from "@EBSDK/EBCompiler/EBModel/EBModel";
import {ActionAfertExpr, CrcMode, ExprCondition} from "@EBSDK/EBCompiler/EBModel/EBEnum";
import {LoraUpEvent} from "@EBSDK/EBCompiler/EBModel/Event/LoraUpEvent";
import {Buffer} from "buffer";
import {CalcData} from "@EBSDK/EBCompiler/EBModel/EBExpr";
const version="1.02.006"
type TypeVal =
    SetUpCovDataType
    |"BCD"
    |"FloatCDAB"
    |"IntCDAB"
    |"UintCDAB"
    |"INVALID";
type TypeProtocol =
    |"DLT64507"
    |"modbus"
    |"modbusBitCov"
    |"any"
class Utils{
    public static readonly INVALID_NUM=-1000000000
    public static readonly INVALID_STR="INVALID"
    public static readonly PERIOD_DEFAULT=900;
    public static readonly PERIOD_DUMB=86400*3650;
    public static readonly PERIOD_TRIGGER="trigger";
    public static readonly PERIOD_MAX =86400*365
    static parseVal(valstr:string):number{
        let val=valstr.toLowerCase();
        if (val.includes("0x")){
            val=val.replaceAll("0x","").replaceAll(" ","");
            let cleanedHex =val.length % 2 === 0 ? val : '0' + val;
            return parseInt(cleanedHex, 16);
        }
        return parseInt(val,10)
    }
    static parseSeconds(time :string){
        let valTime=time.replaceAll(" ","").toLowerCase()
        if (valTime.length==1) {    return parseInt(valTime,10)}
        const valueStr = valTime.slice(0, -1);
        const unit = valTime.slice(-1).toLowerCase();
        let retval=parseInt(valueStr,10)
        switch (unit){
            case "s": return retval;
            case "m": return retval*60;
            case "h": return retval*3600;
            case "d": return retval*86400;
            case "y": return retval*86400*365;
            default:
                return parseInt(valTime,10)
        }
    }
}
interface UserConfQueryItem { //
    name?:string;
    protocol?: TypeProtocol; //
    isLast?: boolean;
    period?: string;
    periodIndex?: number;
    code?: string; // modbus function code, e.g. "0x03" |"03"
    addr?: string; // slave address in hex string "0x123F"|"345"
    cmd?: string; //hex
    ack?: string;
    payIndex?:number;
    ackAddrIndex?:number;
    indexAPP?: number;
    indexCMD?: number;
    copySize?: number;
    listTag?:{
        index:number;
        val:string;
    }[];
    listVal: {
        start: string;
        end: string;
        covAppIndex?: number;
        covType?: TypeVal;
    }[];
}
interface UserConfUPItem {
    name?: string;
    port?: number;
    version?: string;
    dataType: string;
    indexCovStatus?:number;
    indexStatus?:number;
    indexBattery?:number;
    indexAddr?: number;
    addrSize?:number;
    indexApp?: number;
    upPeriod?: string;
    upPeriodIndex?: number;
    quInfo: UserConfQueryItem[];
}
class ConfigPreCopy {
    indexAPP: number;
    indexCMD: number;
    copySize: number;
    static appIndex=150
    constructor(data?: Partial<ConfigPreCopy>) {
        if (data?.indexCMD===undefined ||data?.indexCMD===Utils.INVALID_NUM ||
            data?.copySize===undefined|| data?.copySize===Utils.INVALID_NUM) {
            this.indexAPP =Utils.INVALID_NUM;
            this.indexCMD=Utils.INVALID_NUM;
            this.copySize=Utils.INVALID_NUM;
        }else {
            this.indexCMD = data?.indexCMD ?? Utils.INVALID_NUM;
            this.copySize = data?.copySize ?? Utils.INVALID_NUM;
            if (data.indexAPP===undefined || data.indexAPP===Utils.INVALID_NUM) {
                this.indexAPP = ConfigPreCopy.appIndex;
                ConfigPreCopy.appIndex=this.indexAPP+this.copySize;
            }else {
                this.indexAPP = data?.indexAPP ?? Utils.INVALID_NUM;
            }
        }
    }
    config(event:QueryEvent) {
        if (this.indexAPP===Utils.INVALID_NUM||this.indexCMD===Utils.INVALID_NUM||this.copySize===Utils.INVALID_NUM) {return}
        event.pushEBData(   event.cmdBuffer.copy( EBModel.APP,this.indexAPP,this.copySize,this.indexCMD),
            {condition:ExprCondition.PRE}
        )
    }
}
class ConfigPeriod {
    index: number;
    val: number;
    static periodIndex=70
    constructor(data?: Partial<{index?:number,val?:string}>) {
        if (data?.index!==undefined ) {
            if (data.index===-1) {
                this.index=ConfigPeriod.periodIndex;
                ConfigPeriod.periodIndex = this.index+4
                this.val=Utils.PERIOD_DUMB
                return;
            }
            this.index=data?.index;
            this.val=Utils.PERIOD_DUMB;
            return
        }
        if (data?.val!==undefined ) {
            if (data.val===Utils.PERIOD_TRIGGER) {
                this.val=Utils.PERIOD_DUMB
            }else {
                this.val=Utils.parseSeconds(data.val);
            }
            this.index=Utils.INVALID_NUM;
            return
        }
        this.index=ConfigPeriod.periodIndex;
        ConfigPeriod.periodIndex = this.index+4
        this.val=Utils.PERIOD_DUMB
    }
    config(event:QueryEvent|LoraUpEvent) {
        if (this.index !== Utils.INVALID_NUM){   event.setPeriodFromApp(this.index);
        }else { event.setPeriod(this.val); }
    }
}
class TagItem{
    index:number;
    val:number;
    constructor(data?: Partial<{
        index?:number;
        val?:string;
    }>) {
        this.index = data?.index??Utils.INVALID_NUM;
        if (data?.val===undefined){this.val=0x00
        }else {this.val=Utils.parseVal(data.val)}
    }
    config(event:QueryEvent) {
        if (this.index === Utils.INVALID_NUM){   return}
        event.addAckCheckRule(this.index,this.val)
    }
}
class ValItem {
    start: number;
    end: number;
    ackProcess?:string;
    covAppIndex?: number;
    covType?: TypeVal;
    static covIndex=110
    constructor(data?: Partial<{
        start: string;
        end: string;
        covType?: TypeVal;
        covAppIndex?: number;
    }>) {
        if (data?.start===undefined){ this.start=Utils.INVALID_NUM
        }else { this.start=Utils.parseVal(data.start) }
        if (data?.end===undefined){ this.end=Utils.INVALID_NUM
        }else { this.end=Utils.parseVal(data.end) }
        if (data?.covType===undefined ||data?.covType==="INVALID") {
            this.covAppIndex=Utils.INVALID_NUM;
            this.covType="INVALID";
        }else {
            if (data?.covAppIndex===undefined) {
                this.covAppIndex = ValItem.covIndex
                ValItem.covIndex+=4
            }else {
                this.covAppIndex = data?.covAppIndex
            }
            this.covType = data?.covType
        }
    }
    processAck(quEvent:QueryEvent,upEvent:LoraUpEvent,txIndex:number,indexCovStatus:number){
        if(this.covType==="INVALID" || this.covAppIndex===Utils.INVALID_NUM ){
            quEvent.pushEBData(
                upEvent.txBuffer.copy(quEvent.ackBuffer,this.start,this.end-this.start+1,txIndex),
                {condition:ExprCondition.ONTIME});
        }else{
            quEvent.setupCov({
                ackBufferIndex: this.start,
                up: {   event: upEvent, txBufferIndex: txIndex},
                binaryDataType: this.covType as SetUpCovDataType,
                appBufferCovThresholdIndex: this.covAppIndex,
                txCovResultIndex: indexCovStatus
            })
        }
        return {
            txIndex:txIndex+this.end-this.start+1,
            txLength:this.end-this.start+1,
        }
    }
}
class EventConfig {
    name: string;
    port: number;
    version: number;
    dataType: number;
    addrSize:number;
    indexCovStatus:number;
    indexStatus:number;
    indexBattery:number;
    indexAddr: number;
    indexApp: number;
    upPeriod: ConfigPeriod;
    static eventIndex=0
    static quIndex=0
    static dataType=0x31
    constructor(data?: Partial<UserConfUPItem>) {
        this.name = data?.name?? ("event_"+(EventConfig.eventIndex++).toString());
        this.port = data?.port?? 22;
        if (data?.version===undefined) {    this.version = 0x83
        }else { this.version=Utils.parseVal(data.version);    }
        if (data?.dataType===undefined) { this.dataType=EventConfig.dataType++
        }else { this.dataType=Utils.parseVal(data.dataType); }
        this.indexCovStatus = data?.indexCovStatus?? 2;
        this.indexStatus = data?.indexStatus ?? 3;
        this.indexBattery = data?.indexBattery ?? 4;
        this.indexAddr = data?.indexAddr ?? 5;
        this.addrSize=data?.addrSize ?? 1;
        this.indexApp = this.indexAddr+this.addrSize
        this.upPeriod=new ConfigPeriod({index:data?.upPeriodIndex,val:data?.upPeriod })
    }
}
class QuFrameInfo{
    start:number=0;
    end:number=0;
    group:number=0;
    constructor() {
        this.start=0;
        this.end=0;
        this.group=0;
    }
    getInfo(list:{ start: string; end: string; covAppIndex?: number; covType?: TypeVal; }[]) {
        let listVal:ValItem[]=[]
        list.forEach(item=>{
            let valItem=new ValItem(item)
            listVal.push(valItem)
        })
        this.group=0
        if (listVal.length===0) {return }
        this.start = listVal[0].start;
        this.end = listVal[0].end;
        listVal.forEach(data => {
            if (data.start < this.start) this.start = data.start;
            if (data.end > this.end) this.end = data.end;
            this.group++
        });
    }
}
abstract class QuItemBase {
    name:string;  // name query event
    protocol:TypeProtocol;
    isLast: boolean;
    period: ConfigPeriod;
    preCopy: ConfigPreCopy;
    cmd:Buffer;
    ack:Buffer;
    addr:Buffer;
    code:Buffer;
    payIndex:number;
    ackAddrIndex:number;
    txDataLen:number=0;
    listVal: ValItem[];
    listTag: TagItem[];
    quEvent: QueryEvent;
    _userConfQueryItem:Partial<UserConfQueryItem>;
    _inited=false
    _setuped =false
    static quIndex:number=0;
    constructor(data?: Partial<UserConfQueryItem>) {
        this.isLast = data?.isLast;
        this.protocol=data?.protocol;
        this.name = data?.name;
        this.payIndex=data?.payIndex;
        this.ackAddrIndex=data?.ackAddrIndex;
        this.listTag=[]
        this.listVal=[]
        this._userConfQueryItem=data
        this._inited=false
        this._setuped=false
    }
    static parseToBuffer(inputStr: string | undefined,erroMessage:string):Buffer{
        if (inputStr===undefined){
            throw new Error(erroMessage);
        }
        let xstr=inputStr.replaceAll("0x","").replaceAll("0X","").replaceAll(" ","")
        return Buffer.from(xstr.length%2===0?xstr:('0'+xstr),"hex")
    }
    protected getProtocol():TypeProtocol{   return "any"}
    protected getPayIndex(): number { return 0}
    protected getAckAddrIndex(): number { return 0}
    protected parseCmd(inputStr: string | undefined): Buffer{ return QuItemAny.parseToBuffer(inputStr,"no cmd") }
    protected parseAck(inputStr: string | undefined): Buffer{ return QuItemAny.parseToBuffer(inputStr,"no ack")}
    protected parseAddr(inputStr: string | undefined): Buffer {return  Buffer.alloc(0) }
    protected parseCode(inputStr:string | undefined): Buffer {return    Buffer.alloc(0) }
    protected parsePeriod(data?: Partial<UserConfQueryItem>){
        this.period=new ConfigPeriod({index:data?.periodIndex,val:data?.period})
    }
    protected parsePreCopy(data?: Partial<UserConfQueryItem>){
        if (data?.indexAPP===undefined || data?.indexCMD===undefined||data?.copySize===undefined) {
            this.preCopy = new ConfigPreCopy({  indexAPP:Utils.INVALID_NUM, indexCMD:Utils.INVALID_NUM, copySize:Utils.INVALID_NUM});
            return
        }
        this.preCopy=new ConfigPreCopy({indexAPP:data.indexAPP, indexCMD:data.indexCMD, copySize:data.copySize})
    }
    protected parseTagList(dataListTag: {index:number,val:string}[]) {
        if (dataListTag !== undefined) {
            dataListTag.forEach(item=>{
                let tag=new TagItem(item)
                this.listTag.push(tag)
            })
        }
    }
    protected parseListVal(dataListVal: {
        start: string
        end: string
        ackProcess?: string
        covAppIndex?: number
        covType?: TypeVal
    }[]){
        dataListVal.forEach(item=>{
            let valItem=new ValItem(item)
            valItem.start=this.payIndex+valItem.start
            valItem.end=this.payIndex+valItem.end
            this.txDataLen+=valItem.end-valItem.start+1
            if (valItem.covAppIndex!==Utils.INVALID_NUM) {
                console.log("[cov index ]"+this.name+" : "+valItem.covAppIndex.toString())
            }
            this.listVal.push(valItem)
        })
    }
    protected _init():void{
        if (this._inited) { return }
        this._inited=true
        if (this._userConfQueryItem?.protocol==undefined) {this.protocol=this.getProtocol()}
        if (this._userConfQueryItem?.name==undefined){ this.name=this.protocol+"_"+(EventConfig.quIndex++).toString(); }
        if (this._userConfQueryItem?.payIndex==undefined) { this.payIndex=this.getPayIndex(); }
        if (this._userConfQueryItem?.ackAddrIndex==undefined) {this.ackAddrIndex=this.getAckAddrIndex();}
        this.cmd =  this.parseCmd(this._userConfQueryItem?.cmd);
        this.ack =  this.parseAck(this._userConfQueryItem?.ack);
        this.addr = this.parseAddr(this._userConfQueryItem?.addr);
        this.code = this.parseCode(this._userConfQueryItem?.code);
        this.parsePeriod(this._userConfQueryItem)
        this.parsePreCopy(this._userConfQueryItem)
        this.parseTagList(this._userConfQueryItem?.listTag)
        if (this._userConfQueryItem?.listVal===undefined) {    throw  new Error("no listVal")
        }else{
            this.parseListVal(this._userConfQueryItem?.listVal)
        }
    }
    init(){ this._init()}
    protected buildCommand(eventPara:EventConfig,upEvent:LoraUpEvent,txIndex:number):void{
        return
    }
    protected  setDefaultTags(): void{
        return
    }
    protected setCrcRules(quEvent: QueryEvent) {
        this.quEvent.setQueryCrc({
            Mode: CrcMode.CRC16, placeIndex: -2, LittleEndian: true,
            crcCheckRange: {startIndex: 0, endIndex: -2}
        });
        this.quEvent.setAckCrc({
            Mode: CrcMode.CRC16, placeIndex: -2, LittleEndian: true,
            crcCheckRange: {startIndex: 0, endIndex: -2}
        });
    }
    protected processStart(
        data:{
            eventPara?:EventConfig,
            upEvent?:LoraUpEvent,
            quEvent?:QueryEvent,
            txIndex:number}) {
        return data.txIndex;
    }
    protected processAckBuffer(data:{
        eventPara:EventConfig,
        upEvent:LoraUpEvent,
        quEvent:QueryEvent,
        txIndex:number}) {
        let txIndex:number=data.txIndex;
        let  txDataLen=0
        this.listVal.forEach(val=>{
            let txInfo:{txIndex:number,txLength:number}
            txInfo = val.processAck(
                this.quEvent, data.upEvent, txIndex, data.eventPara.indexCovStatus
            )
            txIndex=txInfo.txIndex;
            txDataLen+=txInfo.txLength
        })
        return txIndex
    }
    protected processEnd(data:{
        eventPara?:EventConfig,
        upEvent?:LoraUpEvent,
        quEvent?:QueryEvent,
        txIndex:number}) {
        return data.txIndex;
    }
    protected _setupQuEvent(eventPara:EventConfig,upEvent:LoraUpEvent,txIndex:number) {
        if(this._setuped) { return this.txDataLen}
        this._setuped=true
        this.buildCommand(eventPara,upEvent,txIndex)
        this.quEvent = new QueryEvent("qu_"+this.name, {cmdBuffer: this.cmd, ackBuffer: this.ack,})
        this.listTag.forEach(item=>{    item.config(this.quEvent)   })
        this.setDefaultTags()
        this.setCrcRules(this.quEvent)
        this.preCopy.config(this.quEvent)
        if (this.preCopy.indexAPP!==Utils.INVALID_NUM) {
            console.log("[pre copy  index]" + this.name +":"
                + this.preCopy.indexAPP.toString()+" To "
                + this.preCopy.indexCMD.toString()+" size "
                + this.preCopy.copySize.toString())
        }
        this.period.config(this.quEvent)
        if (this.period.index!==Utils.INVALID_NUM){
            console.log("[qu period index]" + this.name +":"+ this.period.index.toString())
        } else {
            console.log("[qu period]" + this.name +":"+ this.period.val.toString())
        }
        txIndex=this.processStart({
            eventPara:eventPara,
            upEvent:upEvent,
            quEvent:this.quEvent,
            txIndex:txIndex
        });
        txIndex=this.processAckBuffer({
            eventPara:eventPara,
            upEvent:upEvent,
            quEvent:this.quEvent,
            txIndex:txIndex
        })
        txIndex=this.processEnd({
            eventPara:eventPara,
            upEvent:upEvent,
            quEvent:this.quEvent,
            txIndex:txIndex
        })
        this.quEvent.pushEBData(upEvent.txBuffer.copy(this.quEvent.ackBuffer,this.ackAddrIndex,eventPara.addrSize,eventPara.indexAddr),{condition:ExprCondition.ONTIME})
        let act=ActionAfertExpr.NONE
        if (this.isLast) { act=ActionAfertExpr.ALWAYS }
        this.quEvent.pushEBData(upEvent.txBuffer.writeUint8(EBModel.DEVICE_STATUS.readUint8(3),eventPara.indexBattery),{ActAfterCvt:act})
        this.quEvent.pushEBData(upEvent.txBuffer.writeUint8(EBModel.APP_STATUS.readUint8(2),eventPara.indexStatus),{ActAfterCvt:act})
        return txIndex
    }
    setupQuEvent(eventPara:EventConfig,upEvent:LoraUpEvent,txIndex:number) {
        return this._setupQuEvent(eventPara,upEvent,txIndex)
    }
}
class QuItemAny extends QuItemBase {
    constructor(data?: Partial<UserConfQueryItem>) {    super(data);    }
}
class QuItemModBus extends QuItemBase {
    modBusFrameInfo :QuFrameInfo=new QuFrameInfo();
    constructor(data?: Partial<UserConfQueryItem>) {
        super(data);
    }
    protected getPayIndex(): number { return 3}
    protected getAckAddrIndex(): number { return 0}
    protected parseCmd(inputStr: string | undefined): Buffer{
        if (inputStr===undefined) { return Buffer.from([0x01, 0x03, 0x01, 0x00, 0x00, 0x39, 0x00, 0x00]);   }
        return QuItemAny.parseToBuffer(inputStr,"no cmd")
    }
    protected parseAck(inputStr: string | undefined): Buffer{
        if (inputStr===undefined) { return Buffer.alloc(0);   }
        return QuItemAny.parseToBuffer(inputStr,"no ack")
    }
    protected parseAddr(inputStr: string | undefined): Buffer {
        if (inputStr===undefined) { return Buffer.alloc(0); }
        let retval=Buffer.alloc(1)
        retval[0]=Utils.parseVal(inputStr);
        return retval
    }
    protected parseCode(inputStr:string | undefined): Buffer {
        if (inputStr===undefined) { return Buffer.alloc(0); }
        let retval=Buffer.alloc(1)
        retval[0]=Utils.parseVal(inputStr);
        return retval
    }
    protected parseListVal(dataListVal: {
        start: string
        end: string
        ackProcess?: string
        covAppIndex?: number
        covType?: TypeVal
    }[]){
        let listVal=[]
        this.modBusFrameInfo.getInfo(dataListVal)
        dataListVal.forEach(item=>{
            let valItem=new ValItem(item)
            listVal.push(valItem)
        })
        listVal.forEach(item=>{
            let val=new ValItem({
                start: (this.payIndex+(item.start-this.modBusFrameInfo.start)*2).toString(),
                end:(this.payIndex+(item.end-this.modBusFrameInfo.start)*2+1).toString(),
                covAppIndex:item?.covAppIndex,
                covType:item?.covType
            })
            if (val.covType!=="INVALID") {
                console.log("[cov index ]"+this.name+" : "+val.covAppIndex.toString())
            }
            this.txDataLen+=(item.end-item.start+1)*2
            this.listVal.push(val)
        })
    }
    protected buildCommand(eventPara:EventConfig,upEvent:LoraUpEvent,txIndex:number):void{
        if (this.addr.length>0) { this.addr.copy(this.cmd,0) }
        if (this.code.length>0) { this.code.copy(this.cmd,1) }
        this.cmd.writeUInt16BE(this.modBusFrameInfo.start,2)
        this.cmd.writeUInt16BE(this.modBusFrameInfo.end-this.modBusFrameInfo.start+1,4)
        this.ack=Buffer.alloc(5+(this.modBusFrameInfo.end-this.modBusFrameInfo.start+1)*2);
    }
    protected setDefaultTags(){
        if (this.preCopy.indexCMD!==0 && this.preCopy.indexCMD!==Utils.INVALID_NUM) { this.quEvent.addAckCheckRule(0, this.cmd[0]);}
        if(this.preCopy.indexCMD>1 && this.preCopy.indexCMD!==Utils.INVALID_NUM) {this.quEvent.addAckCheckRule(1, this.cmd[1]);}
        this.quEvent.addAckCheckRule(2,(this.modBusFrameInfo.end-this.modBusFrameInfo.start+1)*2)
    }
}
class QuItemDLT64507 extends QuItemBase {
    constructor(data?: Partial<UserConfQueryItem>) {    super(data);    }
    protected getPayIndex(): number { return 0}
    protected getAckAddrIndex(): number { return 1}
    protected parseCmd(inputStr: string | undefined): Buffer{ return QuItemDLT64507.parseToBuffer(inputStr,"no cmd") }
    protected parseAck(inputStr: string | undefined): Buffer{ return QuItemDLT64507.parseToBuffer(inputStr,"no ack") }
    protected setDefaultTags(){
        new TagItem({index:0,val:"0x68"}).config(this.quEvent)
        new TagItem({index:7,val:"0x68"}).config(this.quEvent)
        new TagItem({index:8,val:"0x91"}).config(this.quEvent)
    }
    protected  setCrcRules(quEvent: QueryEvent) {
        this.quEvent.setQueryCrc({Mode: CrcMode.SUM, placeIndex: -2, CrcLen:1, crcCheckRange: {startIndex: 4, endIndex: -2}})
        this.quEvent.setAckCrc({Mode: CrcMode.SUM, placeIndex: -2, CrcLen:1, crcCheckRange: {startIndex: 0, endIndex: -2}})
    }
}
class QuItemModBusBitCov extends QuItemModBus {
    protected parseListVal(dataListVal: {
        start: string
        end: string
        ackProcess?: string
        covAppIndex?: number
        covType?: TypeVal
    }[]){
        let listVal=[]
        this.modBusFrameInfo.getInfo(dataListVal)
        dataListVal.forEach(item=>{
            let valItem=new ValItem(item)
            listVal.push(valItem)
        })
        listVal.forEach(item=>{
            let val=new ValItem({
                start: (this.payIndex+(item.start-this.modBusFrameInfo.start)*2).toString(),
                end:(this.payIndex+(item.end-this.modBusFrameInfo.start)*2+1).toString(),
                covAppIndex:item?.covAppIndex,
                covType:item?.covType
            })
            if (val.covType!=="INVALID") {
                console.log("[cov index ]"+this.name+" : "+val.covAppIndex.toString())
            }
            this.listVal.push(val)
        })
        this.txDataLen+=this.modBusFrameInfo.group
    }
    protected processAckBuffer(data:{
        eventPara:EventConfig,
        upEvent:LoraUpEvent,
        quEvent:QueryEvent,
        txIndex:number}) {
        data.quEvent.pushEBData(
            EBModel.SENSOR_DATA.writeUint8(new CalcData(0), 0),
            {
                condition: ExprCondition.ONTIME,
                Repeat: this.modBusFrameInfo.group
            }
        );
        let bitIndex=0;
        this.listVal.forEach(item=>{
            data.quEvent.pushEBData(
                EBModel.SENSOR_DATA.writeUint8(
                    data.quEvent.ackBuffer.readUint16BE(item.start).
                    notEqual(0).leftShift(bitIndex).bitwiseOr(EBModel.SENSOR_DATA.readUint8(0)),data.txIndex
                ),
                {
                    condition: ExprCondition.ONTIME,
                    Repeat: (item.end-item.start+1)/2,
                }
            )
            bitIndex++
        })
        data.quEvent.pushEBData(
            data.upEvent.txBuffer.writeUint8(
                EBModel.SENSOR_DATA.readUintBE(0,this.modBusFrameInfo.group).notEqual(
                    data.upEvent.txBuffer.readUintBE(data.txIndex,this.modBusFrameInfo.group)
                )
                ,data.eventPara.indexCovStatus),
            {
                condition: ExprCondition.ONTIME,
                ActAfterCvt:ActionAfertExpr.UP_TO_RESULT
            }
        )
        data.upEvent.pushEBData(data.upEvent.txBuffer.copy(EBModel.SENSOR_DATA,0,this.modBusFrameInfo.group,data.txIndex))
        return data.txIndex+this.modBusFrameInfo.group
    }
}
/////////////////////////////////////////////////////////////////////////////
type TypeQuItem=QuItemModBus|QuItemDLT64507|QuItemAny
const QuItemMap = {
    modbus: QuItemModBus,
    DLT64507: QuItemDLT64507,
    modbusBitCov: QuItemModBusBitCov,
    any: QuItemAny
};
const DEFAULT_QuItem = QuItemAny;
//////////////////////////////////////////////////////////////////////
class EventInfoItem {
    eventPara: EventConfig;
    quInfo: Array<QuItemBase>;
    upEvent:LoraUpEvent;
    txLength:number;
    constructor(data?: Partial<UserConfUPItem>,option?:{quItemClass?:new () => QuItemBase}) {
        this.eventPara=new EventConfig(data);
        this.txLength=0
        this.quInfo=[]
        let qcounts=data?.quInfo?.length
        for (let i=0;i<qcounts;i++) {
            let item=data?.quInfo[i]
            const ItemClass = option?.quItemClass??(QuItemMap[item.protocol] || DEFAULT_QuItem);
            const quInstance = new ItemClass(item);
            quInstance.init()
            this.txLength += quInstance.txDataLen;
            if(quInstance.isLast==undefined) {
                if ((this.eventPara.upPeriod.val >= Utils.PERIOD_MAX)&&(this.eventPara.upPeriod.index!==Utils.INVALID_NUM) && i === qcounts - 1) {
                    quInstance.isLast = true;
                }else {
                    quInstance.isLast = false;
                }
            }
            this.protocolBuild(quInstance.protocol)
            this.quInfo.push(quInstance);
        }
    }
    protected protocolBuild( protocol:string) {
        if(protocol=="DLT64507" && this.eventPara.addrSize<6) { this.eventPara.addrSize=6}
        return
    }
    upEventSetup() {
        let txBuffer = Buffer.alloc(5+this.eventPara.addrSize+this.txLength);
        txBuffer[0]=this.eventPara.version
        txBuffer[1] = this.eventPara.dataType; // 设备类型
        txBuffer[this.eventPara.indexStatus]=0x02;
        this.upEvent = new LoraUpEvent("up_"+this.eventPara.name, {
            txBuffer: txBuffer,
            txPort: this.eventPara.port
        })
        this.eventPara.upPeriod.config(this.upEvent);
        if (this.eventPara.upPeriod.index!==Utils.INVALID_NUM){
            console.log("[up period index ] "+this.eventPara.name+":"+this.eventPara.upPeriod.index.toString(10))
        }else {
            console.log("[up period ] "+this.eventPara.name+":"+this.eventPara.upPeriod.val.toString(10))
        }
    }
    eventInstall(){
        let txIndex=this.eventPara.indexApp
        this.quInfo.forEach((item:any)=>{
            item.init()
            txIndex=item.setupQuEvent(this.eventPara,this.upEvent,txIndex);
        })
    }
}
export {version,Utils,UserConfQueryItem,UserConfUPItem,TypeVal,TypeProtocol,TypeQuItem,QuItemMap,
    ConfigPreCopy,ConfigPeriod,TagItem,ValItem,EventConfig,
    QuFrameInfo,QuItemBase,QuItemModBus,QuItemModBusBitCov,QuItemDLT64507,EventInfoItem}