Skip to content

Commit f1c312f

Browse files
committed
Refactor function code descriptions
1 parent 0e0840a commit f1c312f

File tree

4 files changed

+59
-39
lines changed

4 files changed

+59
-39
lines changed

src/dom.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { Converters } from "./converters";
22
import { Frame } from "./frame";
3+
import { FunctionCodes } from "./function-codes";
34

45
export class TableDataColumn {
56
readonly td: HTMLElement = document.createElement('td');
@@ -118,10 +119,10 @@ export class Dom {
118119
static readonly sendForm = new DomForm<SendFormData>(document.querySelector('form[name=send]')!);
119120

120121
private static readonly functionCodeList = document.getElementById('functionCodeList')!;
121-
static addFunctionCodeListOption(code: string, description: string): void {
122+
static addFunctionCodeListOption(code: number): void {
122123
const option = document.createElement('option');
123-
option.value = code;
124-
option.appendChild(document.createTextNode(`${Converters.byteToHex(+code)} ${description}`));
124+
option.value = code.toString();
125+
option.appendChild(document.createTextNode(FunctionCodes.getDescription(code)));
125126
Dom.functionCodeList.appendChild(option);
126127
}
127128

src/frame.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { Converters } from "./converters";
22
import { dataFieldStrategies } from "./data-field";
33
import { Dom, TableColumnButton, TableDataColumn } from "./dom";
4-
import { getFunctionCodeDescription } from "./function-codes";
4+
import { FunctionCodes } from "./function-codes";
55

66
export class Frame {
77
readonly slaveAddress: number;
@@ -46,7 +46,7 @@ export class Frame {
4646
return [
4747
new TableDataColumn(Frame.getDateTime(), this.type),
4848
new TableDataColumn(`${this.slaveAddress}=0x${Converters.byteToHex(this.slaveAddress!)}`, this.type),
49-
new TableDataColumn(`${this.functionCode}=${this.functionCode === undefined ? '' : getFunctionCodeDescription(this.functionCode)}`, this.type),
49+
new TableDataColumn(FunctionCodes.getDescription(this.functionCode), this.type),
5050
new TableDataColumn(this.getDataLength().toString(), this.type),
5151
new TableDataColumn(this.getDataAsText(), this.isNoValidDataFormat() ? 'error' : this.type),
5252
this.type === 'error' ? new TableDataColumn('', this.type) : new TableColumnButton('To send form', () => Dom.sendForm.setFormData(this)),
@@ -57,7 +57,7 @@ export class Frame {
5757
if (this.type === 'error') {
5858
return `Invalid frame: 0x${this.hexData}`;
5959
} else if (this.isUnknownFrame()) {
60-
return `Data field format is unknown, data field: 0x${this.hexData}`;
60+
return `No strategies to format data field. Raw data field is: 0x${this.hexData}`;
6161
} else if (this.isNoValidDataFormat()) {
6262
return `This frame format does not fit to the known function code: fromMasterToSlaveError=${this.fromMasterToSlaveError}; fromSlaveToMasterError=${this.fromSlaveToMasterError}; for: 0x${this.hexData}`;
6363
} else {

src/function-codes.ts

Lines changed: 50 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,56 @@
11
import { Converters } from "./converters";
2+
import { DataField } from "./data-field";
23

3-
export const functionCodes: { [code: number]: string } = {
4-
0x01: 'Read Coils',
5-
0x02: 'Read Discrete Inputs',
6-
0x03: 'Read Holding Registers',
7-
0x04: 'Read Input Registers',
8-
0x05: 'Write Single Coil',
9-
0x06: 'Write Single Register',
10-
0x07: 'Read Exceptions Status',
11-
0x08: 'Diagnostic Test',
12-
0x0f: 'Write Multiple Coils',
13-
0x10: 'Write Multiple Registers',
14-
0x11: 'Identify Device Server',
15-
};
4+
interface FunctionCodeDetails {
5+
readonly code: number;
6+
readonly description: string;
7+
readonly masterRequestStrategy?: DataField;
8+
readonly slaveResponseStrategy?: DataField;
9+
}
1610

17-
export const errorCodes: { [code: number]: string } = {
18-
0x81: 'Illegal Function',
19-
0x82: 'Illegal Data Address',
20-
0x83: 'Illegal Data Value',
21-
0x84: 'Server Device Failure',
22-
0x85: 'Acknowledge',
23-
0x86: 'Server Device Busy',
24-
0x87: 'Negative Acknowledge',
25-
0x88: 'Memory Parity Error',
26-
0x90: 'Gateway Path Unavailable',
27-
0x91: 'Gateway Target Device Failed to Respond',
28-
};
11+
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' },
18+
{ code: 0x07, description: 'Read Exceptions Status' },
19+
{ code: 0x08, description: 'Diagnostic Test' },
20+
{ code: 0x0f, description: 'Write Multiple Coils' },
21+
{ code: 0x10, description: 'Write Multiple Registers' },
22+
{ code: 0x11, description: 'Identify Device Server' },
23+
{ code: 0x81, description: 'Illegal Function' },
24+
{ code: 0x82, description: 'Illegal Data Address' },
25+
{ code: 0x83, description: 'Illegal Data Value' },
26+
{ code: 0x84, description: 'Server Device Failure' },
27+
{ code: 0x85, description: 'Acknowledge' },
28+
{ code: 0x86, description: 'Server Device Busy' },
29+
{ code: 0x87, description: 'Negative Acknowledge' },
30+
{ code: 0x88, description: 'Memory Parity Error' },
31+
{ code: 0x90, description: 'Gateway Path Unavailable' },
32+
{ code: 0x91, description: 'Gateway Target Device Failed to Respond' },
33+
]);
2934

35+
export class FunctionCodes {
36+
static descriptions: ReadonlyMap<number, string> = new Map<number, string>([...allFunctionCodeDetails].map((it) => [it.code, it.description]));
3037

31-
export const getFunctionCodeDescription = (code: number): string => {
32-
const description = functionCodes[code] ?? errorCodes[code];
33-
if (description) {
34-
return `0x${Converters.byteToHex(code)} ${description}`;
38+
static getDescription(code: number | undefined): string {
39+
if (code === undefined) {
40+
return '';
41+
}
42+
const description = this.descriptions.get(code);
43+
if (description) {
44+
return this._getDescription(code, description);
45+
}
46+
return this._getDescription(code, '<UNKNOWN>');
3547
}
36-
return `0x${Converters.byteToHex(code)} UNKNOWN`;
37-
}
48+
49+
private static _getDescription(code: number, description: string): string {
50+
return `${code} = 0x${Converters.byteToHex(code)} => ${description} ${this.isError(code) ? '(ERROR)' : ''}`;
51+
}
52+
53+
static isError(code: number): boolean {
54+
return !!(code & 0x80);
55+
}
56+
}

src/main.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33
import { AsciiModeStrategy, ModeStrategy, RtuModeStrategy } from "./mode";
44
import { clearSniffingTable, Dom, downloadAllSniffedEntries, insertFrameRow } from "./dom";
55
import { Frame } from "./frame";
6-
import { errorCodes, functionCodes } from "./function-codes";
76
import { intTest } from "./int.spec";
7+
import { FunctionCodes } from "./function-codes";
88

99
const serial: Serial = navigator.serial;
1010
if (!serial) {
@@ -68,7 +68,7 @@ const start = (serialOptions: SerialOptions, mode: ModeStrategy) => {
6868
}, console.warn);
6969
};
7070

71-
[...Object.entries(functionCodes), ...Object.entries(errorCodes)].forEach(([code, description]) => Dom.addFunctionCodeListOption(code, description));
71+
[...FunctionCodes.descriptions.keys()].forEach((code: number) => Dom.addFunctionCodeListOption(code));
7272

7373
Dom.sendForm.submit = (formData) => {
7474
formData.slaveAddress = +formData.slaveAddress;

0 commit comments

Comments
 (0)