start to parse variable data blocks, tests are yet missing, coding tables and especially encoder functions not completex

This commit is contained in:
Wolfgang Hottgenroth 2017-08-10 23:33:20 +02:00
parent 49a6a46052
commit f1830497b0
5 changed files with 279 additions and 27 deletions

View File

@ -1,31 +1,95 @@
import {MeterbusLibUtils} from './utils'
export namespace MeterbusLibCodeTables { export namespace MeterbusLibCodeTables {
export const MEDIUM_CODE : string[] = export const MEDIUM_CODE : string[] =
['Other', [
'Oil', 'Other',
'Electrity', 'Oil',
'Gas', 'Electrity',
'Heat (Volume measured at return temperature: outlet', 'Gas',
'Steam', 'Heat (Volume measured at return temperature: outlet',
'Hot Water', 'Steam',
'Water', 'Hot Water',
'Heat Cost Allocator', 'Water',
'Compressed Air', 'Heat Cost Allocator',
'Cooling Load Meter (Volume measured at return temperature: outlet', 'Compressed Air',
'Cooling Load Meter (Volume measured at flow temperature: inlet', 'Cooling Load Meter (Volume measured at return temperature: outlet',
'Heat (Volume measured at flow temperature: inlet)', 'Cooling Load Meter (Volume measured at flow temperature: inlet',
'Heat / Cooling Load Meter', 'Heat (Volume measured at flow temperature: inlet)',
'Bus / System', 'Heat / Cooling Load Meter',
'Unknown Medium', 'Bus / System',
'Reserved (10)', 'Unknown Medium',
'Reserved (11)', 'Reserved (10)',
'Reserved (12)', 'Reserved (11)',
'Reserved (13)', 'Reserved (12)',
'Reserved (14)', 'Reserved (13)',
'Reserved (15)', 'Reserved (14)',
'Cold Water', 'Reserved (15)',
'Dual Water', 'Cold Water',
'Pressure', 'Dual Water',
'A/D Converter', 'Pressure',
'A/D Converter',
] ]
export const DIF_FUNCTION_FIELD : string[] =
[
'Instantaneous value',
'Maximum value',
'Minimum value',
'Value during error state'
]
export class DCFt {
name : string
length : number
encoder : (v: number[]) => any
constructor(n : string, l : number, e : (v: number[]) => any) {
this.name = n
this.length = l
this.encoder = e
}
}
export const DIF_CODING_FIELD : DCFt[] =
[
new DCFt('No Data', 0, (x)=>{ return x}),
new DCFt('8 Bit Integer', 1, (x)=>{ return x[0]}),
new DCFt('16 Bit Integer', 2, (x)=>{ return (x[1] << 8) + x[0]}),
new DCFt('24 Bit Integer', 3, (x)=>{ return (x[2] << 16) + (x[1] << 8) + x[0]}),
new DCFt('32 Bit Integer', 4, (x)=>{ return (x[3] << 24) + (x[2] << 16) + (x[1] << 8) + x[0]}),
new DCFt('32 Bit Real', 4, (x)=>{ return x}), // FIXME
new DCFt('48 Bit Integer', 6, (x)=>{ return (x[5] << 40) + (x[4] << 32) + (x[3] << 24) + (x[2] << 16) + (x[1] << 8) + x[0]}),
new DCFt('64 Bit Integer', 8, (x)=>{ return (x[7] << 56) + (x[6] << 48) + (x[5] << 40) + (x[4] << 32) + (x[3] << 24) + (x[2] << 16) + (x[1] << 8) + x[0]}),
new DCFt('Selection for Readout', 0, (x)=>{ return x}),
new DCFt('2 Digit BCD', 1, (x)=>{ return MeterbusLibUtils.bcd(x)}),
new DCFt('4 Digit BCD', 2, (x)=>{ return MeterbusLibUtils.bcd(x)}),
new DCFt('6 Digit BCD', 3, (x)=>{ return MeterbusLibUtils.bcd(x)}),
new DCFt('8 Digit BCD', 4, (x)=>{ return MeterbusLibUtils.bcd(x)}),
new DCFt('variable length', -1, (x)=>{ return x}),
new DCFt('12 Digit BCD', 6, (x)=>{ return MeterbusLibUtils.bcd(x)}),
new DCFt('Special Function', 0, (x)=>{ return x})
]
/*
DATA_FIELD_CODES = (
('No Data', 0, None),
('8 Bit Integer', 1, lambda x: x[0]),
('16 Bit Integer', 2, lambda x: (x[1] << 8) + x[0]),
('24 Bit Integer', 3, lambda x: (x[2] << 16) + (x[1] << 8) + x[0]),
('32 Bit Integer', 4, lambda x: (x[3] << 24) + (x[2] << 16) + (x[1] << 8) + x[0]),
('32 Bit Real', 4, lambda x: struct.unpack('f', str(bytearray(x)))[0]),
('48 Bit Integer', 6, lambda x: (x[5] << 40) + (x[4] << 32) + (x[3] << 24) + (x[2] << 16) + (x[1] << 8) + x[0]),
('64 Bit Integer', 8, lambda x: (x[7] << 56) + (x[6] << 48) + (x[5] << 40) + (x[4] << 32) + (x[3] << 24) + (x[2] << 16) + (x[1] << 8) + x[0]),
('Selection for Readout', 0, None),
('2 Digit BCD', 1, lambda x: MeterbusTypeConversion.bcd(x)),
('4 Digit BCD', 2, lambda x: MeterbusTypeConversion.bcd(x)),
('6 Digit BCD', 3, lambda x: MeterbusTypeConversion.bcd(x)),
('8 Digit BCD', 4, lambda x: MeterbusTypeConversion.bcd(x)),
('variable length', -1, None),
('12 Digit BCD', 6, lambda x: MeterbusTypeConversion.bcd(x)),
('Special Function', 0, None),
)
*/
} }

View File

@ -6,6 +6,8 @@ import {MeterbusLibCodeTables} from './codetables'
export namespace MeterbusLibLongFrame { export namespace MeterbusLibLongFrame {
export class LongFrame extends MeterbusLibFrames.ControlFrame { export class LongFrame extends MeterbusLibFrames.ControlFrame {
private _fixedDataHeader : FixedDataHeader private _fixedDataHeader : FixedDataHeader
private _variableDataBlocks : DataBlock[] = []
get fixedDataHeader() : FixedDataHeader { return this._fixedDataHeader } get fixedDataHeader() : FixedDataHeader { return this._fixedDataHeader }
constructor(telegram : number[]) { constructor(telegram : number[]) {
@ -16,6 +18,16 @@ export namespace MeterbusLibLongFrame {
super.parse2() // control frame parse2 method super.parse2() // control frame parse2 method
this._fixedDataHeader = new FixedDataHeader(this._telegram.slice(7, 19)) this._fixedDataHeader = new FixedDataHeader(this._telegram.slice(7, 19))
this._fixedDataHeader.parse() this._fixedDataHeader.parse()
let consumed : number = 0
while (true) {
let die : DataBlock =
new DataBlock(this._telegram.slice(19 + consumed))
die.parse()
this._variableDataBlocks.push(die)
consumed += die.consumed
break //FIXME
}
} }
} }
@ -61,4 +73,157 @@ export namespace MeterbusLibLongFrame {
} }
} }
export abstract class ADataBlock {
protected __consumed : number = 0
get consumed() : number {
return this.__consumed
}
abstract parse() : void
toJSON() : any {
console.log("x")
return MeterbusLibUtils.jsonPrepaper(this, [])
}
getJSON() : string {
return JSON.stringify(this)
}
}
export class DataBlock extends ADataBlock {
private _content : VariableDataBlock | ManufacturerSpecificData
constructor(data : number[]) {
super()
if ((data[0] & 0x0f) == 0x0f) {
this._content = new ManufacturerSpecificData(data)
} else {
this._content = new VariableDataBlock(data)
}
}
parse() : void {
this._content.parse()
}
toJSON() : any {
return MeterbusLibUtils.jsonPrepaper(this._content, [])
}
}
export class DIF {
raw : number
function : number
coding : number
lsb : number
extension : number
toJSON() : any {
let dup = MeterbusLibUtils.clone(this)
dup.function = MeterbusLibCodeTables.DIF_FUNCTION_FIELD[dup.function]
dup.coding = MeterbusLibCodeTables.DIF_CODING_FIELD[dup.coding].name
return dup
}
}
export class DIFE {
raw : number
extension : number
}
export class VIF {
raw : number
unitAndMultiplier : number
extension : number
}
export class VIFE {
raw : number
extension : number
}
export class VariableDataBlock extends ADataBlock {
private _type : string = "VDB"
private __indata : number[]
private _dif : DIF
private _dife : DIFE[] = []
private _vif : VIF
private _vife : VIFE[] = []
private _data : number[]
private _value : any
constructor(data : number[]) {
super()
this.__indata = data
}
parse() : void {
this._dif = new DIF()
this._dif.raw = this.__indata[0]
this.__consumed++
this._dif.function = (this._dif.raw & 0x30) >> 4
this._dif.coding = this._dif.raw & 0x0f
this._dif.lsb = (this._dif.raw & 0x40) >> 6
this._dif.extension = (this._dif.raw & 0x80) >> 7
if (this._dif.extension == 1) {
while (true) {
let dife = new DIFE()
dife.raw = this.__indata[this.__consumed]
this.__consumed++
dife.extension = (dife.raw & 0x80) >> 7
this._dife.push(dife)
if (dife.extension == 0) {
break
}
}
}
this._vif = new VIF()
this._vif.raw = this.__indata[this.__consumed]
this.__consumed++
this._vif.unitAndMultiplier = this._vif.raw & 0x7f
this._vif.extension = (this._vif.raw & 0x80) >> 7
if (this._vif.extension == 1) {
while (true) {
let vife = new VIFE()
vife.raw = this.__indata[this.__consumed]
this.__consumed++
vife.extension = (vife.raw & 0x80) >> 7
this._vife.push(vife)
if (vife.extension == 0) {
break
}
}
}
let dcf : MeterbusLibCodeTables.DCFt = MeterbusLibCodeTables.DIF_CODING_FIELD[this._dif.coding]
this._data = this.__indata.slice(this.__consumed,
this.__consumed + dcf.length)
this.__consumed += dcf.length
console.log(dcf.encoder)
this._value = dcf.encoder(this._data)
console.log(this._value)
}
}
export class ManufacturerSpecificData extends ADataBlock {
private _type : string = "MSD"
private _data : number[]
constructor(data : number[]) {
super()
this._data = data
}
parse() : void {
}
}
} }

View File

@ -180,6 +180,7 @@ describe('The Meterbus Longframe Library', () => {
.to.deep.equal([0,0]) .to.deep.equal([0,0])
}) })
it('should prepare itself as JSON', () => { it('should prepare itself as JSON', () => {
console.log((telegram.frame as MeterbusLibLongFrame.LongFrame).getJSON())
expect((telegram.frame as MeterbusLibLongFrame.LongFrame).getJSON()).to.equal(json_1phase_electric) expect((telegram.frame as MeterbusLibLongFrame.LongFrame).getJSON()).to.equal(json_1phase_electric)
}) })
}) })

View File

@ -49,3 +49,16 @@ describe('The jsonPrepare function in the Meterbus Library Utils', () => {
expect(MeterbusLibUtils.jsonPrepaper(objIn, [])).to.deep.equal(objOut) expect(MeterbusLibUtils.jsonPrepaper(objIn, [])).to.deep.equal(objOut)
}) })
}) })
describe('The clone function in the Meterbus Library Utils', () => {
it('should clone the attributes of an object', () => {
let objIn = {'a': 1, 'b': 2}
let objOut = {'a': 1, 'b': 2}
expect(MeterbusLibUtils.clone(objIn)).to.deep.equal(objOut)
})
it('should not just return the same object', () => {
let objIn = {'a': 1, 'b':2}
let objOut = objIn
expect(MeterbusLibUtils.clone(objIn)).to.not.equal(objOut)
})
})

View File

@ -24,5 +24,14 @@ export namespace MeterbusLibUtils {
} }
return dup return dup
} }
export function clone(obj:any) : any {
let dup = {}
for (let key in obj) {
dup[key] = obj[key]
}
return dup
}
} }