Compare commits

2 Commits

Author SHA1 Message Date
83143ca8c2 utils test adapted to Uint8Array 2017-08-10 13:11:43 +02:00
098633af13 replace number[] by Uint8Array 2017-08-10 02:02:42 +02:00
8 changed files with 132 additions and 420 deletions

View File

@ -1,75 +1,31 @@
import {MeterbusLibUtils} from './utils'
export namespace MeterbusLibCodeTables { export namespace MeterbusLibCodeTables {
export const MEDIUM_CODE : string[] = export const MEDIUM_CODE : string[] =
[ ['Other',
'Other', 'Oil',
'Oil', 'Electrity',
'Electrity', 'Gas',
'Gas', 'Heat (Volume measured at return temperature: outlet',
'Heat (Volume measured at return temperature: outlet', 'Steam',
'Steam', 'Hot Water',
'Hot Water', 'Water',
'Water', 'Heat Cost Allocator',
'Heat Cost Allocator', 'Compressed Air',
'Compressed Air', 'Cooling Load Meter (Volume measured at return temperature: outlet',
'Cooling Load Meter (Volume measured at return temperature: outlet', 'Cooling Load Meter (Volume measured at flow temperature: inlet',
'Cooling Load Meter (Volume measured at flow temperature: inlet', 'Heat (Volume measured at flow temperature: inlet)',
'Heat (Volume measured at flow temperature: inlet)', 'Heat / Cooling Load Meter',
'Heat / Cooling Load Meter', 'Bus / System',
'Bus / System', 'Unknown Medium',
'Unknown Medium', 'Reserved (10)',
'Reserved (10)', 'Reserved (11)',
'Reserved (11)', 'Reserved (12)',
'Reserved (12)', 'Reserved (13)',
'Reserved (13)', 'Reserved (14)',
'Reserved (14)', 'Reserved (15)',
'Reserved (15)', 'Cold Water',
'Cold Water', 'Dual Water',
'Dual Water', 'Pressure',
'Pressure', 'A/D Converter',
'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})
]
} }

View File

@ -19,4 +19,7 @@ export namespace MeterbusLibExceptions {
export class PayloadTooShortError extends InvalidTelegramError { export class PayloadTooShortError extends InvalidTelegramError {
} }
export class IllegalNumberError extends InvalidTelegramError {
}
} }

View File

@ -6,48 +6,33 @@ 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 : Uint8Array) {
super(telegram) super(telegram)
} }
parse2() { parse2() {
super.parse2() // control frame parse2 method super.parse2() // control frame parse2 method
this._fixedDataHeader = new FixedDataHeader(this._telegram.slice(7, 19))
let consumed : number = 7 // 68 L L 68 C A CI
this._fixedDataHeader = new FixedDataHeader(this._telegram.slice(consumed))
this._fixedDataHeader.parse() this._fixedDataHeader.parse()
}
consumed += this._fixedDataHeader.consumed getJSON() : string {
let count : number = 0 return JSON.stringify(this)
while (true) {
let die : DataBlock =
new DataBlock(this._telegram.slice(consumed))
die.parse()
this._variableDataBlocks.push(die)
consumed += die.consumed
count++
if ((consumed) >= (this._telegram.length - 2)) {
break
}
}
} }
} }
export class FixedDataHeader { export class FixedDataHeader {
private _data : number[] private _data : Uint8Array
private __consumed : number = 0
private _identNo : number private _identNo : number
private _manufacturer : string private _manufacturer : string
private _version : number private _version : number
private _medium : string private _medium : string
private _accessNo : number private _accessNo : number
private _status : number private _status : number
private _signature : number[] private _signature : Uint8Array
get identNo() : number { return this._identNo } get identNo() : number { return this._identNo }
get manufacturer() : string { return this._manufacturer } get manufacturer() : string { return this._manufacturer }
@ -55,197 +40,24 @@ export namespace MeterbusLibLongFrame {
get medium() : string { return this._medium } get medium() : string { return this._medium }
get accessNo() : number { return this._accessNo } get accessNo() : number { return this._accessNo }
get status() : number { return this._status } get status() : number { return this._status }
get signature() : number[] { return this._signature } get signature() : Uint8Array { return this._signature }
constructor(data : number[]) { constructor(data : Uint8Array) {
this._data = data this._data = data
} }
get consumed() : number {
return this.__consumed
}
parse() : void { parse() : void {
this._identNo = MeterbusLibUtils.bcd(this._data.slice(0, 4)) this._identNo = MeterbusLibUtils.bcd(this._data.slice(0, 4))
this.__consumed += 4
this._manufacturer = MeterbusLibUtils.manufCode(this._data.slice(4, 6)) this._manufacturer = MeterbusLibUtils.manufCode(this._data.slice(4, 6))
this.__consumed += 2
this._version = this._data[6] this._version = this._data[6]
this.__consumed += 1
this._medium = MeterbusLibCodeTables.MEDIUM_CODE[this._data[7]] this._medium = MeterbusLibCodeTables.MEDIUM_CODE[this._data[7]]
this.__consumed += 1
this._accessNo = this._data[8] this._accessNo = this._data[8]
this.__consumed += 1
this._status = this._data[9] this._status = this._data[9]
this.__consumed += 1
this._signature = this._data.slice(10, 12) this._signature = this._data.slice(10, 12)
this.__consumed += 2
} }
toJSON() : any { getJSON() : string {
return MeterbusLibUtils.jsonPrepaper(this, ["_data"]) return JSON.stringify(this)
}
}
export abstract class ADataBlock {
protected __consumed : number = 0
get consumed() : number {
return this.__consumed
}
abstract parse() : void
toJSON() : any {
return MeterbusLibUtils.jsonPrepaper(this, [])
}
}
export class DataBlock extends ADataBlock {
private _content : VariableDataBlock | ManufacturerSpecificData
private _hex : string = ""
private __data : number[]
constructor(data : number[]) {
super()
this.__data = data
if ((data[0] & 0x0f) == 0x0f) {
this._content = new ManufacturerSpecificData(data)
} else {
this._content = new VariableDataBlock(data)
}
}
get consumed() : number {
return this._content.consumed
}
parse() : void {
this._content.parse()
for (let d of this.__data.slice(0, this.consumed)) {
this._hex += "" + d.toString(16) + " "
}
}
toJSON() : any {
return MeterbusLibUtils.jsonPrepaper(this, [])
}
}
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]
let actualLength = dcf.length
if (dcf.length == -1) {
actualLength = this.__indata[this.__consumed]
this.__consumed++
}
this._data = this.__indata.slice(this.__consumed,
this.__consumed + actualLength)
this.__consumed += actualLength
this._value = dcf.encoder(this._data)
}
}
export class ManufacturerSpecificData extends ADataBlock {
private _type : string = "MSD"
private __indata : number[]
constructor(data : number[]) {
super()
this.__indata = data
}
parse() : void {
} }
} }

View File

@ -15,9 +15,6 @@ let inputOkLongFrame_1phase_electric = "68 38 38 68 08 53 72 17 00 13 00 2E 19 2
let inputNOkLongFrame_1phase_electric_wrong_medium = "68 38 38 68 08 53 72 17 00 13 00 2E 19 24 FE D6 00 00 00 8C 10 04 01 02 00 00 8C 11 04 01 02 00 00 02 FD C9 FF 01 E4 00 02 FD DB FF 01 03 00 02 AC FF 01 01 00 82 40 AC FF 01 FA FF 1c 16" let inputNOkLongFrame_1phase_electric_wrong_medium = "68 38 38 68 08 53 72 17 00 13 00 2E 19 24 FE D6 00 00 00 8C 10 04 01 02 00 00 8C 11 04 01 02 00 00 02 FD C9 FF 01 E4 00 02 FD DB FF 01 03 00 02 AC FF 01 01 00 82 40 AC FF 01 FA FF 1c 16"
let inputNOkLongFrame_1phase_electric_wrong_signature = "68 38 38 68 08 53 72 17 00 13 00 2E 19 24 02 D6 00 00 01 8C 10 04 01 02 00 00 8C 11 04 01 02 00 00 02 FD C9 FF 01 E4 00 02 FD DB FF 01 03 00 02 AC FF 01 01 00 82 40 AC FF 01 FA FF 21 16" let inputNOkLongFrame_1phase_electric_wrong_signature = "68 38 38 68 08 53 72 17 00 13 00 2E 19 24 02 D6 00 00 01 8C 10 04 01 02 00 00 8C 11 04 01 02 00 00 02 FD C9 FF 01 E4 00 02 FD DB FF 01 03 00 02 AC FF 01 01 00 82 40 AC FF 01 FA FF 21 16"
let json_1phase_electric = '{"telegram":[104,56,56,104,8,83,114,23,0,19,0,46,25,36,2,214,0,0,0,140,16,4,1,2,0,0,140,17,4,1,2,0,0,2,253,201,255,1,228,0,2,253,219,255,1,3,0,2,172,255,1,1,0,130,64,172,255,1,250,255,32,22],"cField":8,"address":83,"ciField":114,"fixedDataHeader":{"identNo":17001300,"manufacturer":"FIN","version":36,"medium":"Electrity","accessNo":214,"status":0,"signature":[0,0]}}'
// electricity // electricity
let inputOkLongFrame_3phase_electric = "68 92 92 68 08 50 72 81 14 01 11 2E 19 16 02 88 00 00 00 8C 10 04 58 43 86 00 8C 11 04 58 43 86 00 8C 20 04 00 00 00 00 8C 21 04 00 00 00 00 02 FD C9 FF 01 E4 00 02 FD DB FF 01 5A 00 02 AC FF 01 D2 00 82 40 AC FF 01 00 00 02 FD C9 FF 02 DF 00 02 FD DB FF 02 0F 00 02 AC FF 02 21 00 82 40 AC FF 02 FD FF 02 FD C9 FF 03 E3 00 02 FD DB FF 03 04 00 02 AC FF 03 02 00 82 40 AC FF 03 F4 FF 02 FF 68 00 00 02 AC FF 00 F5 00 82 40 AC FF 00 F1 FF 01 FF 13 00 F4 16" let inputOkLongFrame_3phase_electric = "68 92 92 68 08 50 72 81 14 01 11 2E 19 16 02 88 00 00 00 8C 10 04 58 43 86 00 8C 11 04 58 43 86 00 8C 20 04 00 00 00 00 8C 21 04 00 00 00 00 02 FD C9 FF 01 E4 00 02 FD DB FF 01 5A 00 02 AC FF 01 D2 00 82 40 AC FF 01 00 00 02 FD C9 FF 02 DF 00 02 FD DB FF 02 0F 00 02 AC FF 02 21 00 82 40 AC FF 02 FD FF 02 FD C9 FF 03 E3 00 02 FD DB FF 03 04 00 02 AC FF 03 02 00 82 40 AC FF 03 F4 FF 02 FF 68 00 00 02 AC FF 00 F5 00 82 40 AC FF 00 F1 FF 01 FF 13 00 F4 16"
@ -46,6 +43,8 @@ let inputNOKLongframe_too_short = "68 02 02 68 01 02 03 16"
let inputNOk_wrong_startcode = "15 01 02 03 16" let inputNOk_wrong_startcode = "15 01 02 03 16"
let inputNOk_illegal_number = "10 01 260 03 16"
describe('The Meterbus Library', () => { describe('The Meterbus Library', () => {
@ -57,7 +56,7 @@ describe('The Meterbus Library', () => {
it('should parse the hexString into the telegram array', () => { it('should parse the hexString into the telegram array', () => {
const telegram = new MeterbusLib.Telegram() const telegram = new MeterbusLib.Telegram()
telegram.fromHexString("01 02 03") telegram.fromHexString("01 02 03")
expect(telegram.telegram).to.deep.equal([1, 2, 3]) expect(telegram.telegram).to.deep.equal(new Uint8Array([1, 2, 3]))
}) })
it('should detect a control frame', () => { it('should detect a control frame', () => {
const telegram = new MeterbusLib.Telegram() const telegram = new MeterbusLib.Telegram()
@ -108,6 +107,10 @@ describe('The Meterbus Library', () => {
telegram.fromHexString(inputNOKLongframe_too_short) telegram.fromHexString(inputNOKLongframe_too_short)
expect(() => telegram.parse()).to.throw(MeterbusLibExceptions.PayloadTooShortError) expect(() => telegram.parse()).to.throw(MeterbusLibExceptions.PayloadTooShortError)
}) })
it('should detect an invalid number', () => {
const telegram = new MeterbusLib.Telegram()
expect(() => telegram.fromHexString(inputNOk_illegal_number)).to.throw(MeterbusLibExceptions.IllegalNumberError)
})
it('should parse cField from a short frame', () => { it('should parse cField from a short frame', () => {
const telegram = new MeterbusLib.Telegram() const telegram = new MeterbusLib.Telegram()
telegram.fromHexString(inputOkShortframe) telegram.fromHexString(inputOkShortframe)
@ -139,48 +142,46 @@ describe('The Meterbus Library', () => {
expect((telegram.frame as MeterbusLibFrames.ControlFrame).ciField).to.equal(3) expect((telegram.frame as MeterbusLibFrames.ControlFrame).ciField).to.equal(3)
}) })
describe('The Meterbus Longframe Library', () => {
let telegram : MeterbusLib.Telegram
beforeEach(() => {
telegram = new MeterbusLib.Telegram()
telegram.fromHexString(inputOkLongFrame_1phase_electric)
telegram.parse()
})
it('should find the identNo', () => {
expect((telegram.frame as MeterbusLibLongFrame.LongFrame).fixedDataHeader.identNo)
.to.equal(17001300)
})
it('should find the manufacturer', () => {
expect((telegram.frame as MeterbusLibLongFrame.LongFrame).fixedDataHeader.manufacturer)
.to.equal("FIN")
})
it('should find the version', () => {
expect((telegram.frame as MeterbusLibLongFrame.LongFrame).fixedDataHeader.version)
.to.equal(0x24)
})
it('should find the medium', () => {
expect((telegram.frame as MeterbusLibLongFrame.LongFrame).fixedDataHeader.medium)
.to.equal("Electrity")
})
it('should find the accessNo', () => {
expect((telegram.frame as MeterbusLibLongFrame.LongFrame).fixedDataHeader.accessNo)
.to.equal(0xd6)
})
it('should find the status', () => {
expect((telegram.frame as MeterbusLibLongFrame.LongFrame).fixedDataHeader.status)
.to.equal(0)
})
it('should find the signature', () => {
expect((telegram.frame as MeterbusLibLongFrame.LongFrame).fixedDataHeader.signature)
.to.deep.equal(new Uint8Array([0,0]))
})
it('should print itself as json', () => {
console.log((telegram.frame as MeterbusLibLongFrame.LongFrame).getJSON())
})
})
}) })
describe('The Meterbus Longframe Library', () => {
let telegram : MeterbusLib.Telegram
beforeEach(() => {
telegram = new MeterbusLib.Telegram()
telegram.fromHexString(inputOkLongFrame_1phase_electric)
telegram.parse()
})
it('should find the identNo', () => {
expect((telegram.frame as MeterbusLibLongFrame.LongFrame).fixedDataHeader.identNo)
.to.equal(17001300)
})
it('should find the manufacturer', () => {
expect((telegram.frame as MeterbusLibLongFrame.LongFrame).fixedDataHeader.manufacturer)
.to.equal("FIN")
})
it('should find the version', () => {
expect((telegram.frame as MeterbusLibLongFrame.LongFrame).fixedDataHeader.version)
.to.equal(0x24)
})
it('should find the medium', () => {
expect((telegram.frame as MeterbusLibLongFrame.LongFrame).fixedDataHeader.medium)
.to.equal("Electrity")
})
it('should find the accessNo', () => {
expect((telegram.frame as MeterbusLibLongFrame.LongFrame).fixedDataHeader.accessNo)
.to.equal(0xd6)
})
it('should find the status', () => {
expect((telegram.frame as MeterbusLibLongFrame.LongFrame).fixedDataHeader.status)
.to.equal(0)
})
it('should find the signature', () => {
expect((telegram.frame as MeterbusLibLongFrame.LongFrame).fixedDataHeader.signature)
.to.deep.equal([0,0])
})
it('should prepare itself as JSON', () => {
console.log(JSON.stringify(telegram.frame as MeterbusLibLongFrame.LongFrame, null, 2))
expect(JSON.stringify(telegram.frame as MeterbusLibLongFrame.LongFrame)).to.equal(json_1phase_electric)
})
})

View File

@ -1,15 +1,13 @@
import {MeterbusLibExceptions} from './exceptions' import {MeterbusLibExceptions} from './exceptions'
import {MeterbusLibFrames} from './simpleframes' import {MeterbusLibFrames} from './simpleframes'
import {MeterbusLibLongFrame} from './longframe' import {MeterbusLibLongFrame} from './longframe'
import {MeterbusLibUtils} from './utils'
export namespace MeterbusLib { export namespace MeterbusLib {
export class Telegram { export class Telegram {
private _hexString : string private _hexString : string
private _telegram : number[] private _telegram : Uint8Array
private _frame : MeterbusLibFrames.Frame private _frame : MeterbusLibFrames.Frame
constructor() { constructor() {
@ -19,7 +17,7 @@ export namespace MeterbusLib {
return this._hexString return this._hexString
} }
get telegram() : number[] { get telegram() : Uint8Array {
return this._telegram return this._telegram
} }
@ -29,9 +27,13 @@ export namespace MeterbusLib {
fromHexString(hexString : string) { fromHexString(hexString : string) {
this._hexString = hexString this._hexString = hexString
this._telegram = this._hexString.split(' ').map<number>((val) => { this._telegram = new Uint8Array(this._hexString.split(' ').map<number>((val) => {
return parseInt(val, 16) let n = parseInt(val, 16)
}) if ((n < 0) || (n > 255)) {
throw new MeterbusLibExceptions.IllegalNumberError()
}
return n
}))
} }
parse() { parse() {

View File

@ -1,36 +1,31 @@
import {MeterbusLibExceptions} from './exceptions' import {MeterbusLibExceptions} from './exceptions'
import {MeterbusLibUtils} from './utils'
export namespace MeterbusLibFrames { export namespace MeterbusLibFrames {
export abstract class Frame { export abstract class Frame {
protected _telegram : number[] protected _telegram : Uint8Array
protected __startCharacter : number protected _startCharacter : number
protected __frameLength : number protected _frameLength : number
protected __firstPayload : number protected _firstPayload : number
protected __payloadLength : number protected _payloadLength : number
constructor(startCharacter : number, frameLength : number, constructor(startCharacter : number, frameLength : number,
firstPayload : number, telegram : number[]) { firstPayload : number, telegram : Uint8Array) {
this.__startCharacter = startCharacter this._startCharacter = startCharacter
this.__frameLength = frameLength this._frameLength = frameLength
this.__firstPayload = firstPayload this._firstPayload = firstPayload
this._telegram = telegram this._telegram = telegram
this.__payloadLength = this.__frameLength - 6 this._payloadLength = this._frameLength - 6
} }
toJSON() : any {
return MeterbusLibUtils.jsonPrepaper(this, [])
}
verifyChecksumAndEnd() { verifyChecksumAndEnd() {
if (this.__firstPayload != 0) { if (this._firstPayload != 0) {
if (this._telegram[this._telegram.length - 1] != 0x16) { if (this._telegram[this._telegram.length - 1] != 0x16) {
throw new MeterbusLibExceptions.InvalidStopCharError() throw new MeterbusLibExceptions.InvalidStopCharError()
} }
let checksum : number = 0 let checksum : number = 0
this._telegram.slice(this.__firstPayload, this._telegram.length -2).forEach((val) => { this._telegram.slice(this._firstPayload, this._telegram.length -2).forEach((val) => {
checksum += val checksum += val
}) })
// console.log(`calc. checksum ${checksum}, ${checksum & 0xff}`) // console.log(`calc. checksum ${checksum}, ${checksum & 0xff}`)
@ -44,10 +39,10 @@ export namespace MeterbusLibFrames {
abstract parse2() abstract parse2()
parse() { parse() {
if (this._telegram[0] != this.__startCharacter) { if (this._telegram[0] != this._startCharacter) {
throw new MeterbusLibExceptions.InvalidStartCharError() throw new MeterbusLibExceptions.InvalidStartCharError()
} }
if (this._telegram.length != this.__frameLength) { if (this._telegram.length != this._frameLength) {
throw new MeterbusLibExceptions.InvalidLengthError() throw new MeterbusLibExceptions.InvalidLengthError()
} }
this.verifyChecksumAndEnd() this.verifyChecksumAndEnd()
@ -73,15 +68,15 @@ export namespace MeterbusLibFrames {
return this._ciField return this._ciField
} }
constructor(telegram : number[]) { constructor(telegram : Uint8Array) {
super(0x68, (telegram[1] + 6), 4, telegram) super(0x68, (telegram[1] + 6), 4, telegram)
} }
parse2() { parse2() {
if (this._telegram[2] != this.__payloadLength) { if (this._telegram[2] != this._payloadLength) {
throw new MeterbusLibExceptions.InvalidSecondLengthError() throw new MeterbusLibExceptions.InvalidSecondLengthError()
} }
if (this.__payloadLength < 3) { if (this._payloadLength < 3) {
throw new MeterbusLibExceptions.PayloadTooShortError() throw new MeterbusLibExceptions.PayloadTooShortError()
} }
@ -103,7 +98,7 @@ export namespace MeterbusLibFrames {
return this._address return this._address
} }
constructor(telegram : number[]) { constructor(telegram : Uint8Array) {
super(0x10, 5, 1, telegram) super(0x10, 5, 1, telegram)
} }
@ -114,7 +109,7 @@ export namespace MeterbusLibFrames {
} }
export class SingleCharFrame extends Frame { export class SingleCharFrame extends Frame {
constructor(telegram : number[]) { constructor(telegram : Uint8Array) {
super(0xe5, 1, 0, telegram) super(0xe5, 1, 0, telegram)
} }

View File

@ -8,57 +8,21 @@ const expect = chai.expect
describe('The Meterbus Library Utils', () => { describe('The Meterbus Library Utils', () => {
it('should convert a bcd to a number (10203)', () => { it('should convert a bcd to a number (10203)', () => {
expect(MeterbusLibUtils.bcd([1, 2, 3])).to.equal(10203) expect(MeterbusLibUtils.bcd(new Uint8Array([1, 2, 3]))).to.equal(10203)
}) })
it('should convert a bcd to a number (0010203)', () => { it('should convert a bcd to a number (0010203)', () => {
expect(MeterbusLibUtils.bcd([0, 1, 2, 3])).to.equal(10203) expect(MeterbusLibUtils.bcd(new Uint8Array([0, 1, 2, 3]))).to.equal(10203)
}) })
it('should convert a bcd to a number (0)', () => { it('should convert a bcd to a number (0)', () => {
expect(MeterbusLibUtils.bcd([0, 0, 0])).to.equal(0) expect(MeterbusLibUtils.bcd(new Uint8Array([0, 0, 0]))).to.equal(0)
}) })
it('should convert a bcd to a number (0)', () => { it('should convert a bcd to a number (0)', () => {
expect(MeterbusLibUtils.bcd([0, 0, 0, 0])).to.equal(0) expect(MeterbusLibUtils.bcd(new Uint8Array([0, 0, 0, 0]))).to.equal(0)
}) })
it('should convert a bcd to a number (99999999)', () => { it('should convert a bcd to a number (99999999)', () => {
expect(MeterbusLibUtils.bcd([0x99, 0x99, 0x99, 0x99])).to.equal(99999999) expect(MeterbusLibUtils.bcd(new Uint8Array([0x99, 0x99, 0x99, 0x99]))).to.equal(99999999)
}) })
it('should convert two number to manufacturer code', () => { it('should convert two number to manufacturer code', () => {
expect(MeterbusLibUtils.manufCode([0x2e, 0x19])).to.equal("FIN") expect(MeterbusLibUtils.manufCode(new Uint8Array([0x2e, 0x19]))).to.equal("FIN")
})
})
describe('The jsonPrepare function in the Meterbus Library Utils', () => {
it('should forward regular properties of an object', () => {
let objIn = {'a': 1, 'b':2}
let objOut = objIn
expect(MeterbusLibUtils.jsonPrepaper(objIn, [])).to.deep.equal(objOut)
})
it('should hide properties in the hide list', () => {
let objIn = {'a': 1, 'b':2}
let objOut = {'a': 1}
expect(MeterbusLibUtils.jsonPrepaper(objIn, ['b'])).to.deep.equal(objOut)
})
it('should hide properties beginning with two underscores', () => {
let objIn = {'a': 1, '__b':2}
let objOut = {'a': 1}
expect(MeterbusLibUtils.jsonPrepaper(objIn, [])).to.deep.equal(objOut)
})
it('should remove one leading underscore from property names', () => {
let objIn = {'_a': 1, 'b':2}
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

@ -1,5 +1,5 @@
export namespace MeterbusLibUtils { export namespace MeterbusLibUtils {
export function bcd(data : number[]) : number { export function bcd(data : Uint8Array) : number {
let v : string = "" let v : string = ""
data.forEach((c : number) => { data.forEach((c : number) => {
v += (c & 0xf0) >> 4 v += (c & 0xf0) >> 4
@ -9,29 +9,8 @@ export namespace MeterbusLibUtils {
return r return r
} }
export function manufCode(data : number[]) : string { export function manufCode(data : Uint8Array) : string {
let v : number = (data[1] << 8) + data[0] let v : number = (data[1] << 8) + data[0]
return String.fromCharCode((((v >> 10) & 0x1f) + 64), (((v >> 5) & 0x1f) + 64), ((v & 0x1f) + 64)) return String.fromCharCode((((v >> 10) & 0x1f) + 64), (((v >> 5) & 0x1f) + 64), ((v & 0x1f) + 64))
} }
export function jsonPrepaper(obj:any, hideKeys:string[]) : any {
let dup = {}
for (let key in obj) {
if ((hideKeys.indexOf(key) == -1) && ! ((key[0] == "_") && (key[1] == "_"))) {
let dkey = (key[0] == "_") ? key.slice(1) : key
dup[dkey] = obj[key]
}
}
return dup
}
export function clone(obj:any) : any {
let dup = {}
for (let key in obj) {
dup[key] = obj[key]
}
return dup
}
} }