Skip to content

Commit 2e8e792

Browse files
committed
Bug fix! Refactor data field strategies
1 parent f1c312f commit 2e8e792

File tree

3 files changed

+69
-59
lines changed

3 files changed

+69
-59
lines changed

src/data-field.ts

Lines changed: 8 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
import { getInputChecked } from "./dom";
22

3-
export interface DataField {
3+
export interface DataFieldStrategy {
44
new(data: number[]): any;
55
}
66

77
const toUInt16 = (data: number[], offset: number): number => data[offset] << 8 ^ data[offset + 1];
88

9-
class AddressQuantity {
9+
export class AddressQuantity {
1010
readonly address: number;
1111
readonly quantity: number;
1212

@@ -19,7 +19,7 @@ class AddressQuantity {
1919
}
2020
}
2121

22-
class Booleans {
22+
export class Booleans {
2323
static readonly bitsInByte: number[] = [0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01];
2424
readonly booleans: boolean[];
2525

@@ -31,7 +31,7 @@ class Booleans {
3131
}
3232
}
3333

34-
class Registers {
34+
export class Registers {
3535
// readonly Uint8?: number[];
3636
// readonly Int8?: number[];
3737
// readonly Uint16?: number[];
@@ -69,7 +69,7 @@ class Registers {
6969
}
7070
}
7171

72-
class AddressBoolean {
72+
export class AddressBoolean {
7373
readonly address: number;
7474
readonly boolean: boolean;
7575

@@ -88,7 +88,7 @@ class AddressBoolean {
8888
}
8989
}
9090

91-
class AddressRegister {
91+
export class AddressRegister {
9292
readonly address: number;
9393
readonly register: number;
9494

@@ -101,7 +101,7 @@ class AddressRegister {
101101
}
102102
}
103103

104-
class AddressQuantityBooleans extends AddressQuantity {
104+
export class AddressQuantityBooleans extends AddressQuantity {
105105
readonly booleans: Booleans;
106106

107107
constructor(data: number[]) {
@@ -113,7 +113,7 @@ class AddressQuantityBooleans extends AddressQuantity {
113113
}
114114
}
115115

116-
class AddressQuantityRegisters extends AddressQuantity {
116+
export class AddressQuantityRegisters extends AddressQuantity {
117117
readonly registers: Registers;
118118

119119
constructor(data: number[]) {
@@ -124,19 +124,3 @@ class AddressQuantityRegisters extends AddressQuantity {
124124
this.registers = new Registers(data.slice(4));
125125
}
126126
}
127-
128-
interface DataFieldFormats {
129-
fromMasterToSlave: DataField;
130-
fromSlaveToMaster: DataField;
131-
}
132-
133-
export const dataFieldStrategies: { [code: number]: DataFieldFormats } = {
134-
0x01: { fromMasterToSlave: AddressQuantity, fromSlaveToMaster: Booleans },
135-
0x02: { fromMasterToSlave: AddressQuantity, fromSlaveToMaster: Booleans },
136-
0x03: { fromMasterToSlave: AddressQuantity, fromSlaveToMaster: Registers },
137-
0x04: { fromMasterToSlave: AddressQuantity, fromSlaveToMaster: Registers },
138-
0x05: { fromMasterToSlave: AddressBoolean, fromSlaveToMaster: AddressBoolean },
139-
0x06: { fromMasterToSlave: AddressRegister, fromSlaveToMaster: AddressRegister },
140-
0x0f: { fromMasterToSlave: AddressQuantityBooleans, fromSlaveToMaster: AddressQuantity },
141-
0x10: { fromMasterToSlave: AddressQuantityRegisters, fromSlaveToMaster: AddressQuantity },
142-
};

src/frame.ts

Lines changed: 22 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,33 @@
11
import { Converters } from "./converters";
2-
import { dataFieldStrategies } from "./data-field";
32
import { Dom, TableColumnButton, TableDataColumn } from "./dom";
43
import { FunctionCodes } from "./function-codes";
54

65
export class Frame {
76
readonly slaveAddress: number;
87
readonly functionCode?: number;
9-
readonly fromMasterToSlave?: any;
10-
readonly fromSlaveToMaster?: any;
11-
readonly fromMasterToSlaveError?: string;
12-
readonly fromSlaveToMasterError?: string;
8+
readonly masterRequest?: any;
9+
readonly slaveResponse?: any;
10+
readonly masterRequestError?: string;
11+
readonly slaveResponseError?: string;
1312
readonly hexData: string;
1413

1514
constructor(readonly data: number[], readonly type: 'error' | 'send' | '') {
1615
this.slaveAddress = data.shift()!;
1716
this.functionCode = data.shift();
17+
if (this.functionCode === undefined) {
18+
type = 'error';
19+
}
1820
this.hexData = Converters.bytesAsHex(data);
19-
if (type !== 'error' || this.functionCode === undefined) {
20-
const specificFormat = dataFieldStrategies[this.functionCode!];
21-
if (specificFormat) {
22-
try {
23-
this.fromMasterToSlave = new specificFormat.fromMasterToSlave(data);
24-
} catch (e: any) {
25-
this.fromMasterToSlaveError = this.getError(e);
26-
}
27-
try {
28-
this.fromSlaveToMaster = new specificFormat.fromSlaveToMaster(data);
29-
} catch (e: any) {
30-
this.fromSlaveToMasterError = this.getError(e);
31-
}
21+
if (type !== 'error') {
22+
try {
23+
this.masterRequest = FunctionCodes.newMasterRequest(this.functionCode!, data);
24+
} catch (e: any) {
25+
this.masterRequestError = this.getError(e);
26+
}
27+
try {
28+
this.slaveResponse = FunctionCodes.newSlaveResponse(this.functionCode!, data);
29+
} catch (e: any) {
30+
this.slaveResponseError = this.getError(e);
3231
}
3332
}
3433
}
@@ -45,7 +44,7 @@ export class Frame {
4544
getRow(): TableDataColumn[] {
4645
return [
4746
new TableDataColumn(Frame.getDateTime(), this.type),
48-
new TableDataColumn(`${this.slaveAddress}=0x${Converters.byteToHex(this.slaveAddress!)}`, this.type),
47+
new TableDataColumn(`${this.slaveAddress} = 0x${Converters.byteToHex(this.slaveAddress!)}`, this.type),
4948
new TableDataColumn(FunctionCodes.getDescription(this.functionCode), this.type),
5049
new TableDataColumn(this.getDataLength().toString(), this.type),
5150
new TableDataColumn(this.getDataAsText(), this.isNoValidDataFormat() ? 'error' : this.type),
@@ -59,18 +58,18 @@ export class Frame {
5958
} else if (this.isUnknownFrame()) {
6059
return `No strategies to format data field. Raw data field is: 0x${this.hexData}`;
6160
} else if (this.isNoValidDataFormat()) {
62-
return `This frame format does not fit to the known function code: fromMasterToSlaveError=${this.fromMasterToSlaveError}; fromSlaveToMasterError=${this.fromSlaveToMasterError}; for: 0x${this.hexData}`;
61+
return `This frame format does not fit to the known function code: masterRequestError=${this.masterRequestError}; slaveResponseError=${this.slaveResponseError}; raw data: 0x${this.hexData}`;
6362
} else {
64-
return `Valid frame: fromMasterToSlave=${JSON.stringify(this.fromMasterToSlave)}; fromSlaveToMasterError=${JSON.stringify(this.fromSlaveToMaster)}`;
63+
return `Valid frame: masterRequest=${JSON.stringify(this.masterRequest)}; slaveResponse=${JSON.stringify(this.slaveResponse)}`;
6564
}
6665
}
6766

6867
private isNoValidDataFormat(): boolean {
69-
return !!this.fromMasterToSlaveError && !!this.fromSlaveToMasterError;
68+
return !!this.masterRequestError && !!this.slaveResponseError;
7069
}
7170

7271
private isUnknownFrame(): boolean {
73-
return !this.isNoValidDataFormat() && !this.fromMasterToSlave && !this.fromSlaveToMaster;
72+
return !this.isNoValidDataFormat() && !this.masterRequest && !this.slaveResponse;
7473
}
7574

7675
protected getError(e: any): string {

src/function-codes.ts

Lines changed: 39 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,24 @@
11
import { Converters } from "./converters";
2-
import { DataField } from "./data-field";
2+
import { AddressBoolean, AddressQuantity, AddressQuantityBooleans, AddressQuantityRegisters, AddressRegister, Booleans, DataFieldStrategy, Registers } from "./data-field";
33

44
interface FunctionCodeDetails {
55
readonly code: number;
66
readonly description: string;
7-
readonly masterRequestStrategy?: DataField;
8-
readonly slaveResponseStrategy?: DataField;
7+
readonly masterRequestStrategy?: DataFieldStrategy;
8+
readonly slaveResponseStrategy?: DataFieldStrategy;
99
}
1010

1111
const allFunctionCodeDetails: ReadonlySet<FunctionCodeDetails> = new Set<FunctionCodeDetails>([
12-
{ code: 0x01, description: 'Read Coils' },
13-
{ code: 0x02, description: 'Read Discrete Inputs' },
14-
{ code: 0x03, description: 'Read Holding Registers' },
15-
{ code: 0x04, description: 'Read Input Registers' },
16-
{ code: 0x05, description: 'Write Single Coil' },
17-
{ code: 0x06, description: 'Write Single Register' },
12+
{ code: 0x01, description: 'Read Coils', masterRequestStrategy: AddressQuantity, slaveResponseStrategy: Booleans },
13+
{ code: 0x02, description: 'Read Discrete Inputs', masterRequestStrategy: AddressQuantity, slaveResponseStrategy: Booleans },
14+
{ code: 0x03, description: 'Read Holding Registers', masterRequestStrategy: AddressQuantity, slaveResponseStrategy: Registers },
15+
{ code: 0x04, description: 'Read Input Registers', masterRequestStrategy: AddressQuantity, slaveResponseStrategy: Registers },
16+
{ code: 0x05, description: 'Write Single Coil', masterRequestStrategy: AddressBoolean, slaveResponseStrategy: AddressBoolean },
17+
{ code: 0x06, description: 'Write Single Register', masterRequestStrategy: AddressRegister, slaveResponseStrategy: AddressRegister },
1818
{ code: 0x07, description: 'Read Exceptions Status' },
1919
{ code: 0x08, description: 'Diagnostic Test' },
20-
{ code: 0x0f, description: 'Write Multiple Coils' },
21-
{ code: 0x10, description: 'Write Multiple Registers' },
20+
{ code: 0x0f, description: 'Write Multiple Coils', masterRequestStrategy: AddressQuantityBooleans, slaveResponseStrategy: AddressQuantity },
21+
{ code: 0x10, description: 'Write Multiple Registers', masterRequestStrategy: AddressQuantityRegisters, slaveResponseStrategy: AddressQuantity },
2222
{ code: 0x11, description: 'Identify Device Server' },
2323
{ code: 0x81, description: 'Illegal Function' },
2424
{ code: 0x82, description: 'Illegal Data Address' },
@@ -33,7 +33,17 @@ const allFunctionCodeDetails: ReadonlySet<FunctionCodeDetails> = new Set<Functio
3333
]);
3434

3535
export class FunctionCodes {
36-
static descriptions: ReadonlyMap<number, string> = new Map<number, string>([...allFunctionCodeDetails].map((it) => [it.code, it.description]));
36+
static descriptions: ReadonlyMap<number, string> = new Map<number, string>([...allFunctionCodeDetails]
37+
.map((it) => [it.code, it.description])
38+
);
39+
static masterRequestStrategies: ReadonlyMap<number, DataFieldStrategy> = new Map<number, DataFieldStrategy>([...allFunctionCodeDetails]
40+
.filter((it) => it.masterRequestStrategy)
41+
.map((it) => [it.code, it.masterRequestStrategy!])
42+
);
43+
static slaveResponseStrategies: ReadonlyMap<number, DataFieldStrategy> = new Map<number, DataFieldStrategy>([...allFunctionCodeDetails]
44+
.filter((it) => it.slaveResponseStrategy)
45+
.map((it) => [it.code, it.slaveResponseStrategy!])
46+
);
3747

3848
static getDescription(code: number | undefined): string {
3949
if (code === undefined) {
@@ -53,4 +63,21 @@ export class FunctionCodes {
5363
static isError(code: number): boolean {
5464
return !!(code & 0x80);
5565
}
66+
67+
static newMasterRequest(code: number, dataFieldBytes: number[]): Object | undefined {
68+
const strategy = this.masterRequestStrategies.get(code);
69+
return this._newDataFieldStrategy(strategy, dataFieldBytes);
70+
}
71+
72+
static newSlaveResponse(code: number, dataFieldBytes: number[]): Object | undefined {
73+
const strategy = this.slaveResponseStrategies.get(code);
74+
return this._newDataFieldStrategy(strategy, dataFieldBytes);
75+
}
76+
77+
private static _newDataFieldStrategy(strategy: DataFieldStrategy | undefined, dataFieldBytes: number[]): Object | undefined {
78+
if (strategy) {
79+
return new strategy(dataFieldBytes);
80+
}
81+
return undefined;
82+
}
5683
}

0 commit comments

Comments
 (0)