-
Notifications
You must be signed in to change notification settings - Fork 8
/
Copy pathModbusTCPMaster.class.nut
156 lines (146 loc) · 5.07 KB
/
ModbusTCPMaster.class.nut
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
// Copyright (c) 2017 Electric Imp
// This file is licensed under the MIT License
// http://opensource.org/licenses/MIT
class ModbusTCPMaster extends ModbusMaster {
static MAX_TRANSACTION_COUNT = 65535;
_transactions = null;
_wiz = null;
_transactionCount = null;
_connection = null;
_connectionSettings = null;
_shouldRetry = null;
_connectCallback = null;
_reconnectCallback = null;
//
// Constructor for ModbusTCPMaster
//
// @param {object} wiz - The W5500 object
// @param {bool} debug - false by default. If enabled, the outgoing and incoming ADU will be printed for debugging purpose
//
constructor(wiz, debug = false) {
base.constructor(debug);
_wiz = wiz;
_transactionCount = 1;
_transactions = {};
}
//
// configure and open a TCP connection
//
// @param {table} networkSettings - The network settings table. It entails sourceIP, subnet, gatewayIP
// @param {table} connectionSettings - The connection settings table. It entails device IP and port
// @param {function} connectCallback - The function to be fired when the connection is established
// @param {function} reconnectCallback - The function to be fired when the connection is reestablished
//
function connect(connectionSettings, connectCallback = null, reconnectCallback = null) {
_shouldRetry = true;
_connectCallback = connectCallback;
_reconnectCallback = reconnectCallback;
_connectionSettings = connectionSettings;
_wiz.onReady(function() {
local destIP = connectionSettings.destIP;
local destPort = connectionSettings.destPort;
_wiz.openConnection(destIP, destPort, _onConnect.bindenv(this));
}.bindenv(this));
}
//
// close the existing TCP connection
//
// @param {function} callback - The function to be fired when the connection is closed
//
function disconnect(callback = null) {
_shouldRetry = false;
_connection.close(callback);
}
//
// The callback function to be fired when the connection is established
//
function _onConnect(error, conn) {
if (error) {
return _callbackHandler(error, null, _connectCallback);
}
_connection = conn;
_connection.onReceive(_parseADU.bindenv(this));
_connection.onDisconnect(_onDisconnect.bindenv(this));
_callbackHandler(null, conn, _connectCallback);
}
//
// The callback function to be fired when the connection is dropped
//
function _onDisconnect(conn) {
_connection = null;
if (_shouldRetry) {
if (_reconnectCallback != null) {
_connectCallback = _reconnectCallback;
}
_wiz.openConnection(_connectionSettings.destIP, _connectionSettings.destPort, _onConnect.bindenv(this));
}
}
//
// The callback function to be fired it receives a packet
//
function _parseADU(error, ADU) {
if (error) {
return _callbackHandler(error, null, _connectCallback);
}
ADU.seek(0);
local header = ADU.readblob(7);
local transactionID = swap2(header.readn('w'));
local PDU = ADU.readblob(ADU.len() - 7);
local params = null;
try {
params = _transactions[transactionID];
} catch (error) {
return _callbackHandler(format("Error parsing the response, transactionID %d does not exist", transactionID), null, _connectCallback);
}
local callback = params.callback;
params.PDU <- PDU;
try {
local result = ModbusRTU.parse(params);
_callbackHandler(null, result, callback);
} catch (error) {
_callbackHandler(error, null, callback);
}
_transactions.rawdelete(transactionID);
_log(ADU, "Incoming ADU: ");
}
//
// create an ADU
//
function _createADU(PDU) {
local ADU = blob();
ADU.writen(swap2(_transactionCount), 'w');
ADU.writen(swap2(0x0000), 'w');
ADU.writen(swap2(PDU.len() + 1), 'w');
ADU.writen(0x00, 'b');
ADU.writeblob(PDU);
return ADU;
}
//
// send the ADU via Ethernet
//
function _send(PDU, properties) {
_transactions[_transactionCount] <- properties;
local ADU = _createADU(PDU);
// with or without success in transmission of data, the transaction count would be advanced
_transactionCount = (_transactionCount + 1) % MAX_TRANSACTION_COUNT;
_connection.transmit(ADU, function(error) {
if (error) {
_callbackHandler(error, null, properties.callback);
} else {
_log(ADU, "Outgoing ADU: ");
}
}.bindenv(this));
}
//
// fire the callback
//
function _callbackHandler(error, result, callback) {
if (callback) {
if (error) {
callback(error, null);
} else {
callback(null, result);
}
}
}
}