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 @@
export namespace MeterbusLibCodeTables {
import {MeterbusLibUtils} from './utils'
export namespace MeterbusLibCodeTables {
export const MEDIUM_CODE : string[] =
['Other',
'Oil',
'Electrity',
'Gas',
'Heat (Volume measured at return temperature: outlet',
'Steam',
'Hot Water',
'Water',
'Heat Cost Allocator',
'Compressed Air',
'Cooling Load Meter (Volume measured at return temperature: outlet',
'Cooling Load Meter (Volume measured at flow temperature: inlet',
'Heat (Volume measured at flow temperature: inlet)',
'Heat / Cooling Load Meter',
'Bus / System',
'Unknown Medium',
'Reserved (10)',
'Reserved (11)',
'Reserved (12)',
'Reserved (13)',
'Reserved (14)',
'Reserved (15)',
'Cold Water',
'Dual Water',
'Pressure',
'A/D Converter',
[
'Other',
'Oil',
'Electrity',
'Gas',
'Heat (Volume measured at return temperature: outlet',
'Steam',
'Hot Water',
'Water',
'Heat Cost Allocator',
'Compressed Air',
'Cooling Load Meter (Volume measured at return temperature: outlet',
'Cooling Load Meter (Volume measured at flow temperature: inlet',
'Heat (Volume measured at flow temperature: inlet)',
'Heat / Cooling Load Meter',
'Bus / System',
'Unknown Medium',
'Reserved (10)',
'Reserved (11)',
'Reserved (12)',
'Reserved (13)',
'Reserved (14)',
'Reserved (15)',
'Cold Water',
'Dual Water',
'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 class LongFrame extends MeterbusLibFrames.ControlFrame {
private _fixedDataHeader : FixedDataHeader
private _variableDataBlocks : DataBlock[] = []
get fixedDataHeader() : FixedDataHeader { return this._fixedDataHeader }
constructor(telegram : number[]) {
@ -16,6 +18,16 @@ export namespace MeterbusLibLongFrame {
super.parse2() // control frame parse2 method
this._fixedDataHeader = new FixedDataHeader(this._telegram.slice(7, 19))
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])
})
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)
})
})

View File

@ -48,4 +48,17 @@ describe('The jsonPrepare function in the Meterbus Library Utils', () => {
let objOut = {'a': 1, 'b':2}
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
}
export function clone(obj:any) : any {
let dup = {}
for (let key in obj) {
dup[key] = obj[key]
}
return dup
}
}