From 0c998e7709f5ce01a4bc1deccb1180b9f54b51ae Mon Sep 17 00:00:00 2001 From: Wolfgang Hottgenroth Date: Wed, 9 Aug 2017 23:05:24 +0200 Subject: [PATCH] Refactoring: split into many files --- src/exceptions.ts | 22 ++++++ src/index.ts | 4 ++ src/longframe.ts | 16 +++++ src/meterbus.test.ts | 31 ++++---- src/meterbus.ts | 163 +++---------------------------------------- src/simpleframes.ts | 120 +++++++++++++++++++++++++++++++ src/utils.test.ts | 25 +++++++ src/utils.ts | 12 ++++ 8 files changed, 227 insertions(+), 166 deletions(-) create mode 100644 src/exceptions.ts create mode 100644 src/longframe.ts create mode 100644 src/simpleframes.ts create mode 100644 src/utils.test.ts create mode 100644 src/utils.ts diff --git a/src/exceptions.ts b/src/exceptions.ts new file mode 100644 index 0000000..dee6bb8 --- /dev/null +++ b/src/exceptions.ts @@ -0,0 +1,22 @@ +export namespace MeterbusLibExceptions { + export class InvalidTelegramError extends Error { + } + + export class InvalidStartCharError extends InvalidTelegramError { + } + + export class InvalidLengthError extends InvalidTelegramError { + } + + export class InvalidChecksumError extends InvalidTelegramError { + } + + export class InvalidStopCharError extends InvalidTelegramError { + } + + export class InvalidSecondLengthError extends InvalidTelegramError { + } + + export class PayloadTooShortError extends InvalidTelegramError { + } +} \ No newline at end of file diff --git a/src/index.ts b/src/index.ts index c9f4ea7..8d6ac0d 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1 +1,5 @@ export {MeterbusLib} from './meterbus' +export {MeterbusLibUtils} from './utils' +export {MeterbusLibLongFrame} from './longframe' +import {MeterbusLibExceptions} from './exceptions' +import {MeterbusLibFrames} from './simpleframes' diff --git a/src/longframe.ts b/src/longframe.ts new file mode 100644 index 0000000..66d1e7b --- /dev/null +++ b/src/longframe.ts @@ -0,0 +1,16 @@ +import {MeterbusLibExceptions} from './exceptions' +import {MeterbusLibFrames} from './simpleframes' + +export namespace MeterbusLibLongFrame { + export class LongFrame extends MeterbusLibFrames.ControlFrame { + constructor(telegram : number[]) { + super(telegram) + } + + parse2() { + super.parse2() // control frame parse2 method + } + } + + +} \ No newline at end of file diff --git a/src/meterbus.test.ts b/src/meterbus.test.ts index 2929eb8..60c19c5 100644 --- a/src/meterbus.test.ts +++ b/src/meterbus.test.ts @@ -1,4 +1,7 @@ import {MeterbusLib} from './meterbus' +import {MeterbusLibLongFrame} from './longframe' +import {MeterbusLibExceptions} from './exceptions' +import {MeterbusLibFrames} from './simpleframes' import * as mocha from 'mocha' import * as chai from 'chai' @@ -55,80 +58,80 @@ describe('The Meterbus Library', () => { const telegram = new MeterbusLib.Telegram() telegram.fromHexString(inputOKControlframe) telegram.parse() - expect(telegram.frame).instanceof(MeterbusLib.ControlFrame) + expect(telegram.frame).instanceof(MeterbusLibFrames.ControlFrame) }) it('should detect a short frame', () => { const telegram = new MeterbusLib.Telegram() telegram.fromHexString(inputOkShortframe) telegram.parse() - expect(telegram.frame).instanceof(MeterbusLib.ShortFrame) + expect(telegram.frame).instanceof(MeterbusLibFrames.ShortFrame) }) it('should detect a long frame', () => { const telegram = new MeterbusLib.Telegram() telegram.fromHexString(inputOkLongFrame_1phase_electric) telegram.parse() - expect(telegram.frame).instanceof(MeterbusLib.LongFrame) + expect(telegram.frame).instanceof(MeterbusLibLongFrame.LongFrame) }) it('should detect a single char frame', () => { const telegram = new MeterbusLib.Telegram() telegram.fromHexString(inputOkSingleCharacter) telegram.parse() - expect(telegram.frame).instanceof(MeterbusLib.SingleCharFrame) + expect(telegram.frame).instanceof(MeterbusLibFrames.SingleCharFrame) }) it('should detect an invalid telegram (invalid start char)', () => { const telegram = new MeterbusLib.Telegram() telegram.fromHexString(inputNOk_wrong_startcode) - expect(() => telegram.parse()).to.throw(MeterbusLib.InvalidStartCharError) + expect(() => telegram.parse()).to.throw(MeterbusLibExceptions.InvalidStartCharError) }) it('should detect an invalid telegram (invalid stop char)', () => { const telegram = new MeterbusLib.Telegram() telegram.fromHexString(inputNOKControlframe_wrong_stopcode) - expect(() => telegram.parse()).to.throw(MeterbusLib.InvalidStopCharError) + expect(() => telegram.parse()).to.throw(MeterbusLibExceptions.InvalidStopCharError) }) it('should detect an invalid telegram (invalid checksum)', () => { const telegram = new MeterbusLib.Telegram() telegram.fromHexString(inputNOkLongFrame_thermometer_checksum_failure) - expect(() => telegram.parse()).to.throw(MeterbusLib.InvalidChecksumError) + expect(() => telegram.parse()).to.throw(MeterbusLibExceptions.InvalidChecksumError) }) it('should detect an invalid telegram (invalid second length)', () => { const telegram = new MeterbusLib.Telegram() telegram.fromHexString(inputNOKControlframe_wrong_secondlength) - expect(() => telegram.parse()).to.throw(MeterbusLib.InvalidSecondLengthError) + expect(() => telegram.parse()).to.throw(MeterbusLibExceptions.InvalidSecondLengthError) }) it('should detect an invalid telegram (too short)', () => { const telegram = new MeterbusLib.Telegram() telegram.fromHexString(inputNOKLongframe_too_short) - expect(() => telegram.parse()).to.throw(MeterbusLib.PayloadTooShortError) + expect(() => telegram.parse()).to.throw(MeterbusLibExceptions.PayloadTooShortError) }) it('should parse cField from a short frame', () => { const telegram = new MeterbusLib.Telegram() telegram.fromHexString(inputOkShortframe) telegram.parse() - expect((telegram.frame as MeterbusLib.ShortFrame).cField).to.equal(1) + expect((telegram.frame as MeterbusLibFrames.ShortFrame).cField).to.equal(1) }) it('should parse address from a short frame', () => { const telegram = new MeterbusLib.Telegram() telegram.fromHexString(inputOkShortframe) telegram.parse() - expect((telegram.frame as MeterbusLib.ShortFrame).address).to.equal(2) + expect((telegram.frame as MeterbusLibFrames.ShortFrame).address).to.equal(2) }) it('should parse cField from a control frame', () => { const telegram = new MeterbusLib.Telegram() telegram.fromHexString(inputOKControlframe) telegram.parse() - expect((telegram.frame as MeterbusLib.ControlFrame).cField).to.equal(1) + expect((telegram.frame as MeterbusLibFrames.ControlFrame).cField).to.equal(1) }) it('should parse address from a control frame', () => { const telegram = new MeterbusLib.Telegram() telegram.fromHexString(inputOKControlframe) telegram.parse() - expect((telegram.frame as MeterbusLib.ControlFrame).address).to.equal(2) + expect((telegram.frame as MeterbusLibFrames.ControlFrame).address).to.equal(2) }) it('should parse ciField from a control frame', () => { const telegram = new MeterbusLib.Telegram() telegram.fromHexString(inputOKControlframe) telegram.parse() - expect((telegram.frame as MeterbusLib.ControlFrame).ciField).to.equal(3) + expect((telegram.frame as MeterbusLibFrames.ControlFrame).ciField).to.equal(3) }) }) \ No newline at end of file diff --git a/src/meterbus.ts b/src/meterbus.ts index 68083c7..825e62a 100644 --- a/src/meterbus.ts +++ b/src/meterbus.ts @@ -1,155 +1,14 @@ +import {MeterbusLibExceptions} from './exceptions' +import {MeterbusLibFrames} from './simpleframes' +import {MeterbusLibLongFrame} from './longframe' + export namespace MeterbusLib { - export class InvalidTelegramError extends Error { - } - export class InvalidStartCharError extends InvalidTelegramError { - } - - export class InvalidLengthError extends InvalidTelegramError { - } - - export class InvalidChecksumError extends InvalidTelegramError { - } - - export class InvalidStopCharError extends InvalidTelegramError { - } - - export class InvalidSecondLengthError extends InvalidTelegramError { - } - - export class PayloadTooShortError extends InvalidTelegramError { - } - - export abstract class Frame { - protected _telegram : number[] - protected _startCharacter : number - protected _frameLength : number - protected _firstPayload : number - protected _payloadLength : number - - constructor(startCharacter : number, frameLength : number, - firstPayload : number, telegram : number[]) { - this._startCharacter = startCharacter - this._frameLength = frameLength - this._firstPayload = firstPayload - this._telegram = telegram - this._payloadLength = this._frameLength - 6 - - } - - verifyChecksumAndEnd() { - if (this._firstPayload != 0) { - if (this._telegram[this._telegram.length - 1] != 0x16) { - throw new InvalidStopCharError() - } - let checksum : number = 0 - this._telegram.slice(this._firstPayload, this._telegram.length -2).forEach((val) => { - checksum += val - }) - // console.log(`calc. checksum ${checksum}, ${checksum & 0xff}`) - // console.log(`found checksum ${this._telegram[this._telegram.length - 2]}`) - if ((checksum & 0xff) != this._telegram[this._telegram.length - 2]) { - throw new InvalidChecksumError() - } - } - } - - abstract parse2() - - parse() { - if (this._telegram[0] != this._startCharacter) { - throw new InvalidStartCharError() - } - if (this._telegram.length != this._frameLength) { - throw new InvalidLengthError() - } - this.verifyChecksumAndEnd() - this.parse2() - } - - } - - export class ControlFrame extends Frame { - private _cField : number - private _address : number - private _ciField : number - - get cField() : number { - return this._cField - } - - get address() : number { - return this._address - } - - get ciField() : number { - return this._ciField - } - - constructor(telegram : number[]) { - super(0x68, (telegram[1] + 6), 4, telegram) - } - - parse2() { - if (this._telegram[2] != this._payloadLength) { - throw new InvalidSecondLengthError() - } - if (this._payloadLength < 3) { - throw new PayloadTooShortError() - } - - this._cField = this._telegram[4] - this._address = this._telegram[5] - this._ciField = this._telegram[6] - } - } - - export class ShortFrame extends Frame { - private _cField : number - private _address : number - - get cField() : number { - return this._cField - } - - get address() : number { - return this._address - } - - constructor(telegram : number[]) { - super(0x10, 5, 1, telegram) - } - - parse2() { - this._cField = this._telegram[1] - this._address = this._telegram[2] - } - } - - export class LongFrame extends ControlFrame { - constructor(telegram : number[]) { - super(telegram) - } - - parse2() { - super.parse2() - } - } - - export class SingleCharFrame extends Frame { - constructor(telegram : number[]) { - super(0xe5, 1, 0, telegram) - } - - parse2() { - - } - } export class Telegram { private _hexString : string private _telegram : number[] - private _frame : Frame + private _frame : MeterbusLibFrames.Frame constructor() { } @@ -162,7 +21,7 @@ export namespace MeterbusLib { return this._telegram } - get frame() : Frame { + get frame() : MeterbusLibFrames.Frame { return this._frame } @@ -175,15 +34,15 @@ export namespace MeterbusLib { parse() { if (this._telegram[0] === 0x68 && this._telegram[1] === 0x03) { - this._frame = new ControlFrame(this._telegram) + this._frame = new MeterbusLibFrames.ControlFrame(this._telegram) } else if (this._telegram[0] === 0x68) { - this._frame = new LongFrame(this._telegram) + this._frame = new MeterbusLibLongFrame.LongFrame(this._telegram) } else if (this._telegram[0] === 0x10) { - this._frame = new ShortFrame(this._telegram) + this._frame = new MeterbusLibFrames.ShortFrame(this._telegram) } else if (this._telegram[0] === 0xe5) { - this._frame = new SingleCharFrame(this._telegram) + this._frame = new MeterbusLibFrames.SingleCharFrame(this._telegram) } else { - throw new InvalidStartCharError() + throw new MeterbusLibExceptions.InvalidStartCharError() } this._frame.parse() diff --git a/src/simpleframes.ts b/src/simpleframes.ts new file mode 100644 index 0000000..8fb99b1 --- /dev/null +++ b/src/simpleframes.ts @@ -0,0 +1,120 @@ +import {MeterbusLibExceptions} from './exceptions' + + +export namespace MeterbusLibFrames { + export abstract class Frame { + protected _telegram : number[] + protected _startCharacter : number + protected _frameLength : number + protected _firstPayload : number + protected _payloadLength : number + + constructor(startCharacter : number, frameLength : number, + firstPayload : number, telegram : number[]) { + this._startCharacter = startCharacter + this._frameLength = frameLength + this._firstPayload = firstPayload + this._telegram = telegram + this._payloadLength = this._frameLength - 6 + + } + + verifyChecksumAndEnd() { + if (this._firstPayload != 0) { + if (this._telegram[this._telegram.length - 1] != 0x16) { + throw new MeterbusLibExceptions.InvalidStopCharError() + } + let checksum : number = 0 + this._telegram.slice(this._firstPayload, this._telegram.length -2).forEach((val) => { + checksum += val + }) + // console.log(`calc. checksum ${checksum}, ${checksum & 0xff}`) + // console.log(`found checksum ${this._telegram[this._telegram.length - 2]}`) + if ((checksum & 0xff) != this._telegram[this._telegram.length - 2]) { + throw new MeterbusLibExceptions.InvalidChecksumError() + } + } + } + + abstract parse2() + + parse() { + if (this._telegram[0] != this._startCharacter) { + throw new MeterbusLibExceptions.InvalidStartCharError() + } + if (this._telegram.length != this._frameLength) { + throw new MeterbusLibExceptions.InvalidLengthError() + } + this.verifyChecksumAndEnd() + this.parse2() + } + } + + + export class ControlFrame extends Frame { + private _cField : number + private _address : number + private _ciField : number + + get cField() : number { + return this._cField + } + + get address() : number { + return this._address + } + + get ciField() : number { + return this._ciField + } + + constructor(telegram : number[]) { + super(0x68, (telegram[1] + 6), 4, telegram) + } + + parse2() { + if (this._telegram[2] != this._payloadLength) { + throw new MeterbusLibExceptions.InvalidSecondLengthError() + } + if (this._payloadLength < 3) { + throw new MeterbusLibExceptions.PayloadTooShortError() + } + + this._cField = this._telegram[4] + this._address = this._telegram[5] + this._ciField = this._telegram[6] + } + } + + export class ShortFrame extends Frame { + private _cField : number + private _address : number + + get cField() : number { + return this._cField + } + + get address() : number { + return this._address + } + + constructor(telegram : number[]) { + super(0x10, 5, 1, telegram) + } + + parse2() { + this._cField = this._telegram[1] + this._address = this._telegram[2] + } + } + + export class SingleCharFrame extends Frame { + constructor(telegram : number[]) { + super(0xe5, 1, 0, telegram) + } + + parse2() { + } + } +} + diff --git a/src/utils.test.ts b/src/utils.test.ts new file mode 100644 index 0000000..2a9038c --- /dev/null +++ b/src/utils.test.ts @@ -0,0 +1,25 @@ +import {MeterbusLibUtils} from './utils' + +import * as mocha from 'mocha' +import * as chai from 'chai' + +const expect = chai.expect + + +describe('The Meterbus Library Utils', () => { + it('should convert a bcd to a number (10203)', () => { + expect(MeterbusLibUtils.bcd([1, 2, 3])).to.equal(10203) + }) + it('should convert a bcd to a number (0010203)', () => { + expect(MeterbusLibUtils.bcd([0, 1, 2, 3])).to.equal(10203) + }) + it('should convert a bcd to a number (0)', () => { + expect(MeterbusLibUtils.bcd([0, 0, 0])).to.equal(0) + }) + it('should convert a bcd to a number (0)', () => { + expect(MeterbusLibUtils.bcd([0, 0, 0, 0])).to.equal(0) + }) + it('should convert a bcd to a number (99999999)', () => { + expect(MeterbusLibUtils.bcd([0x99, 0x99, 0x99, 0x99])).to.equal(99999999) + }) +}) diff --git a/src/utils.ts b/src/utils.ts new file mode 100644 index 0000000..c33ddde --- /dev/null +++ b/src/utils.ts @@ -0,0 +1,12 @@ +export namespace MeterbusLibUtils { + export function bcd(data : number[]) : number { + let v : string = "" + data.forEach((c : number) => { + v += (c & 0xf0) >> 4 + v += c & 0x0f + }) + let r : number = parseInt(v) + return r + } + +} \ No newline at end of file