Skip to content

Commit 1cb3899

Browse files
committed
Manual MAC
1 parent 7782f9d commit 1cb3899

File tree

10 files changed

+273
-257
lines changed

10 files changed

+273
-257
lines changed

README.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,9 @@ You can either:
100100
Connect your Arduino to ethernet and use your web browser to access the web interface on default IP: http://192.168.1.254
101101
Enjoy :-)
102102
# Settings
103+
- settings marked \* are only available if ENABLE_DHCP is defined in the sketch
104+
- settings marked \*\* are only available if ENABLE_EXTRA_DIAG is defined in the sketch
105+
103106
## System Info
104107
<img src="pics/modbus1.png" alt="01" style="zoom:100%;" />
105108

@@ -111,7 +114,7 @@ Enjoy :-)
111114

112115
**Ethernet Sockets**. Max number of usable sockets. See Limitations bellow. One socket is reserved for Modbus UDP, remaining sockets are shared between Modbus TCP and WebUI.
113116

114-
**Generate New MAC**. Generate new MAC address. First 3 bytes are fixed 90:A2:DA, remaining 3 bytes are true random.
117+
**MAC Address**. First 3 bytes are fixed 90:A2:DA, remaining 3 bytes are random. You can also set manual MAC in IP Settings.
115118

116119
## Modbus Status
117120
<img src="pics/modbus2.png" alt="02" style="zoom:100%;" />
@@ -159,6 +162,8 @@ Enjoy :-)
159162
## IP Settings
160163
<img src="pics/modbus3.png" alt="03" style="zoom:100%;" />
161164

165+
**MAC Address**. Change MAC address. "Randomize" button will generate new random MAC (first 3 bytes fixed 90:A2:DA, last 3 bytes will be random).
166+
162167
**Auto IP**.\* Once enabled, Arduino will receive IP, gateway, subnet and DNS from the DHCP server.
163168

164169
**Static IP**. Set new static IP address. Gateway automatically redirect the web interface to the new IP.

arduino-modbus-rtu-tcp-gateway/01-interfaces.ino

Lines changed: 26 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,8 @@ void startSerial() {
5555
}
5656

5757
// number of bits per character (11 in default Modbus RTU settings)
58-
byte bitsPerChar() {
59-
byte bits =
58+
uint8_t bitsPerChar() {
59+
uint8_t bits =
6060
1 + // start bit
6161
(((localConfig.serialConfig & 0x06) >> 1) + 5) + // data bits
6262
(((localConfig.serialConfig & 0x08) >> 3) + 1); // stop bits
@@ -65,7 +65,7 @@ byte bitsPerChar() {
6565
}
6666

6767
// character timeout in micros
68-
unsigned long charTimeOut() {
68+
uint32_t charTimeOut() {
6969
if (localConfig.baud <= 192) {
7070
return (15000UL * bitsPerChar()) / localConfig.baud; // inter-character time-out should be 1,5T
7171
} else {
@@ -74,7 +74,7 @@ unsigned long charTimeOut() {
7474
}
7575

7676
// minimum frame delay in micros
77-
unsigned long frameDelay() {
77+
uint32_t frameDelay() {
7878
if (localConfig.baud <= 192) {
7979
return (35000UL * bitsPerChar()) / localConfig.baud; // inter-frame delay should be 3,5T
8080
} else {
@@ -90,9 +90,6 @@ void startEthernet() {
9090
digitalWrite(ETH_RESET_PIN, HIGH);
9191
delay(ETH_RESET_DELAY);
9292
}
93-
byte mac[6];
94-
memcpy(mac, MAC_START, 3); // set first 3 bytes
95-
memcpy(mac + 3, localConfig.macEnd, 3); // set last 3 bytes
9693
#ifdef ENABLE_DHCP
9794
if (localConfig.enableDhcp) {
9895
dhcpSuccess = Ethernet.begin(mac);
@@ -131,7 +128,7 @@ void maintainDhcp() {
131128

132129
#ifdef ENABLE_EXTRA_DIAG
133130
void maintainUptime() {
134-
unsigned long milliseconds = millis();
131+
uint32_t milliseconds = millis();
135132
if (last_milliseconds > milliseconds) {
136133
//in case of millis() overflow, store existing passed seconds
137134
remaining_seconds = seconds;
@@ -147,8 +144,8 @@ void maintainUptime() {
147144

148145
bool rollover() {
149146
// synchronize roll-over of run time, data counters and modbus stats to zero, at 0xFFFFFF00
150-
const unsigned long ROLLOVER = 0xFFFFFF00;
151-
for (byte i = 0; i < ERROR_LAST; i++) {
147+
const uint32_t ROLLOVER = 0xFFFFFF00;
148+
for (uint8_t i = 0; i < ERROR_LAST; i++) {
152149
if (errorCount[i] > ROLLOVER) {
153150
return true;
154151
}
@@ -157,7 +154,7 @@ bool rollover() {
157154
if (seconds > ROLLOVER) {
158155
return true;
159156
}
160-
for (byte i = 0; i < DATA_LAST; i++) {
157+
for (uint8_t i = 0; i < DATA_LAST; i++) {
161158
if (rtuCount[i] > ROLLOVER || ethCount[i] > ROLLOVER) {
162159
return true;
163160
}
@@ -181,20 +178,23 @@ void generateMac() {
181178
seed1 = 36969L * (seed1 & 65535L) + (seed1 >> 16);
182179
seed2 = 18000L * (seed2 & 65535L) + (seed2 >> 16);
183180
uint32_t randomBuffer = (seed1 << 16) + seed2; /* 32-bit random */
184-
for (byte i = 0; i < 3; i++) {
185-
localConfig.macEnd[i] = randomBuffer & 0xFF;
181+
memcpy(mac, MAC_START, 3); // set first 3 bytes
182+
for (uint8_t i = 0; i < 3; i++) {
183+
mac[i + 3] = randomBuffer & 0xFF; // random last 3 bytes
186184
randomBuffer >>= 8;
187185
}
188186
}
189187

190188
void updateEeprom() {
191189
eepromTimer.sleep(EEPROM_INTERVAL * 60UL * 60UL * 1000UL); // EEPROM_INTERVAL is in hours, sleep is in milliseconds!
192190
eepromWrites++; // we assume that at least some bytes are written to EEPROM during EEPROM.update or EEPROM.put
193-
int address = CONFIG_START;
191+
uint16_t address = CONFIG_START;
194192
EEPROM.put(address, eepromWrites);
195193
address += sizeof(eepromWrites);
196194
EEPROM.put(address, VERSION[0]);
197195
address += 1;
196+
EEPROM.put(address, mac);
197+
address += 6;
198198
EEPROM.put(address, localConfig);
199199
address += sizeof(localConfig);
200200
EEPROM.put(address, errorCount);
@@ -208,25 +208,25 @@ void updateEeprom() {
208208
}
209209

210210
#if MAX_SOCK_NUM == 8
211-
unsigned long lastSocketUse[MAX_SOCK_NUM] = { 0, 0, 0, 0, 0, 0, 0, 0 };
212-
byte socketInQueue[MAX_SOCK_NUM] = { 0, 0, 0, 0, 0, 0, 0, 0 };
211+
uint32_t lastSocketUse[MAX_SOCK_NUM] = { 0, 0, 0, 0, 0, 0, 0, 0 };
212+
uint8_t socketInQueue[MAX_SOCK_NUM] = { 0, 0, 0, 0, 0, 0, 0, 0 };
213213
#elif MAX_SOCK_NUM == 4
214-
unsigned long lastSocketUse[MAX_SOCK_NUM] = { 0, 0, 0, 0 };
215-
byte socketInQueue[MAX_SOCK_NUM] = { 0, 0, 0, 0 };
214+
uint32_t lastSocketUse[MAX_SOCK_NUM] = { 0, 0, 0, 0 };
215+
uint8_t socketInQueue[MAX_SOCK_NUM] = { 0, 0, 0, 0 };
216216
#endif
217217

218218
// from https://github.com/SapientHetero/Ethernet/blob/master/src/socket.cpp
219219
void manageSockets() {
220220
uint32_t maxAge = 0; // the 'age' of the socket in a 'disconnectable' state that was last used the longest time ago
221-
byte oldest = MAX_SOCK_NUM; // the socket number of the 'oldest' disconnectable socket
222-
byte modbusListening = MAX_SOCK_NUM;
223-
byte webListening = MAX_SOCK_NUM;
224-
byte dataAvailable = MAX_SOCK_NUM;
225-
byte socketsAvailable = 0;
221+
uint8_t oldest = MAX_SOCK_NUM; // the socket number of the 'oldest' disconnectable socket
222+
uint8_t modbusListening = MAX_SOCK_NUM;
223+
uint8_t webListening = MAX_SOCK_NUM;
224+
uint8_t dataAvailable = MAX_SOCK_NUM;
225+
uint8_t socketsAvailable = 0;
226226
// SPI.beginTransaction(SPI_ETHERNET_SETTINGS); // begin SPI transaction
227227
// look at all the hardware sockets, record and take action based on current states
228-
for (byte s = 0; s < maxSockNum; s++) { // for each hardware socket ...
229-
byte status = W5100.readSnSR(s); // get socket status...
228+
for (uint8_t s = 0; s < maxSockNum; s++) { // for each hardware socket ...
229+
uint8_t status = W5100.readSnSR(s); // get socket status...
230230
uint32_t sockAge = millis() - lastSocketUse[s]; // age of the current socket
231231
if (socketInQueue[s] > 0) {
232232
lastSocketUse[s] = millis();
@@ -313,7 +313,7 @@ void manageSockets() {
313313
// we do not need SPI.beginTransaction(SPI_ETHERNET_SETTINGS) or SPI.endTransaction()
314314
}
315315

316-
void disconSocket(byte s) {
316+
void disconSocket(uint8_t s) {
317317
if (W5100.readSnSR(s) == SnSR::ESTABLISHED) {
318318
W5100.execCmdSn(s, Sock_DISCON); // Sock_DISCON does not close LISTEN sockets
319319
lastSocketUse[s] = millis(); // record time at which it was sent...

arduino-modbus-rtu-tcp-gateway/02-modbus-tcp.ino

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -40,25 +40,25 @@ uint8_t masks[8] = { 1, 2, 4, 8, 16, 32, 64, 128 };
4040
uint16_t crc;
4141

4242
void recvUdp() {
43-
unsigned int msgLength = Udp.parsePacket();
43+
uint16_t msgLength = Udp.parsePacket();
4444
if (msgLength) {
4545
#ifdef ENABLE_EXTRA_DIAG
4646
ethCount[DATA_RX] += msgLength;
4747
#endif /* ENABLE_EXTRA_DIAG */
48-
byte inBuffer[MODBUS_SIZE + 4]; // Modbus TCP frame is 4 bytes longer than Modbus RTU frame
48+
uint8_t inBuffer[MODBUS_SIZE + 4]; // Modbus TCP frame is 4 bytes longer than Modbus RTU frame
4949
// Modbus TCP/UDP frame: [0][1] transaction ID, [2][3] protocol ID, [4][5] length and [6] unit ID (address)..... no CRC
5050
// Modbus RTU frame: [0] address.....[n-1][n] CRC
5151
Udp.read(inBuffer, sizeof(inBuffer));
5252
while (Udp.available()) Udp.read();
53-
byte errorCode = checkRequest(inBuffer, msgLength, (uint32_t)Udp.remoteIP(), Udp.remotePort(), UDP_REQUEST);
53+
uint8_t errorCode = checkRequest(inBuffer, msgLength, (uint32_t)Udp.remoteIP(), Udp.remotePort(), UDP_REQUEST);
5454
if (errorCode) {
5555
// send back message with error code
5656
Udp.beginPacket(Udp.remoteIP(), Udp.remotePort());
5757
if (!localConfig.enableRtuOverTcp) {
5858
Udp.write(inBuffer, 5);
5959
Udp.write(0x03);
6060
}
61-
byte addressPos = 6 * !localConfig.enableRtuOverTcp; // position of slave address in the incoming TCP/UDP message (0 for Modbus RTU over TCP/UDP and 6 for Modbus RTU over TCP/UDP)
61+
uint8_t addressPos = 6 * !localConfig.enableRtuOverTcp; // position of slave address in the incoming TCP/UDP message (0 for Modbus RTU over TCP/UDP and 6 for Modbus RTU over TCP/UDP)
6262
Udp.write(inBuffer[addressPos]); // address
6363
Udp.write(inBuffer[addressPos + 1] + 0x80); // function + 0x80
6464
Udp.write(errorCode);
@@ -80,26 +80,26 @@ void recvUdp() {
8080
}
8181

8282
void recvTcp(EthernetClient &client) {
83-
unsigned int msgLength = client.available();
83+
uint16_t msgLength = client.available();
8484
#ifdef ENABLE_EXTRA_DIAG
8585
ethCount[DATA_RX] += msgLength;
8686
#endif /* ENABLE_EXTRA_DIAG */
87-
byte inBuffer[MODBUS_SIZE + 4]; // Modbus TCP frame is 4 bytes longer than Modbus RTU frame
87+
uint8_t inBuffer[MODBUS_SIZE + 4]; // Modbus TCP frame is 4 bytes longer than Modbus RTU frame
8888
// Modbus TCP/UDP frame: [0][1] transaction ID, [2][3] protocol ID, [4][5] length and [6] unit ID (address).....
8989
// Modbus RTU frame: [0] address.....
9090
client.read(inBuffer, sizeof(inBuffer));
9191
while (client.available()) client.read();
92-
byte errorCode = checkRequest(inBuffer, msgLength, {}, client.remotePort(), TCP_REQUEST | client.getSocketNumber());
92+
uint8_t errorCode = checkRequest(inBuffer, msgLength, {}, client.remotePort(), TCP_REQUEST | client.getSocketNumber());
9393
if (errorCode) {
9494
// send back message with error code
95-
byte i = 0;
96-
byte outBuffer[9];
95+
uint8_t i = 0;
96+
uint8_t outBuffer[9];
9797
if (!localConfig.enableRtuOverTcp) {
9898
memcpy(outBuffer, inBuffer, 5);
9999
outBuffer[5] = 0x03;
100100
i = 6;
101101
}
102-
byte addressPos = 6 * !localConfig.enableRtuOverTcp; // position of slave address in the incoming TCP/UDP message (0 for Modbus RTU over TCP/UDP and 6 for Modbus RTU over TCP/UDP)
102+
uint8_t addressPos = 6 * !localConfig.enableRtuOverTcp; // position of slave address in the incoming TCP/UDP message (0 for Modbus RTU over TCP/UDP and 6 for Modbus RTU over TCP/UDP)
103103
outBuffer[i++] = inBuffer[addressPos]; // address
104104
outBuffer[i++] = inBuffer[addressPos + 1] + 0x80; // function + 0x80
105105
outBuffer[i++] = errorCode;
@@ -122,7 +122,7 @@ void recvTcp(EthernetClient &client) {
122122

123123
void scanRequest() {
124124
// Insert scan request into queue, allow only one scan request in a queue
125-
static byte scanCommand[] = { SCAN_FUNCTION_FIRST, 0x00, SCAN_DATA_ADDRESS, 0x00, 0x01 };
125+
static uint8_t scanCommand[] = { SCAN_FUNCTION_FIRST, 0x00, SCAN_DATA_ADDRESS, 0x00, 0x01 };
126126
if (scanCounter != 0 && queueHeaders.available() > 1 && queueData.available() > sizeof(scanCommand) + 1 && scanReqInQueue == false) {
127127
scanReqInQueue = true;
128128
// Store scan request in request queue
@@ -135,7 +135,7 @@ void scanRequest() {
135135
0, // atts
136136
});
137137
queueData.push(scanCounter); // address of the scanned slave
138-
for (byte i = 0; i < sizeof(scanCommand); i++) {
138+
for (uint8_t i = 0; i < sizeof(scanCommand); i++) {
139139
queueData.push(scanCommand[i]);
140140
}
141141
if (scanCommand[0] == SCAN_FUNCTION_FIRST) {
@@ -148,8 +148,8 @@ void scanRequest() {
148148
}
149149
}
150150

151-
byte checkRequest(byte inBuffer[], unsigned int msgLength, const uint32_t remoteIP, const unsigned int remotePort, byte requestType) {
152-
byte addressPos = 6 * !localConfig.enableRtuOverTcp; // position of slave address in the incoming TCP/UDP message (0 for Modbus RTU over TCP/UDP and 6 for Modbus RTU over TCP/UDP)
151+
uint8_t checkRequest(uint8_t inBuffer[], uint16_t msgLength, const uint32_t remoteIP, const uint16_t remotePort, uint8_t requestType) {
152+
uint8_t addressPos = 6 * !localConfig.enableRtuOverTcp; // position of slave address in the incoming TCP/UDP message (0 for Modbus RTU over TCP/UDP and 6 for Modbus RTU over TCP/UDP)
153153
if (localConfig.enableRtuOverTcp) { // check CRC for Modbus RTU over TCP/UDP
154154
if (checkCRC(inBuffer, msgLength) == false) {
155155
errorCount[ERROR_TCP]++;
@@ -194,7 +194,7 @@ byte checkRequest(byte inBuffer[], unsigned int msgLength, const uint32_t remote
194194
byte(requestType), // requestType
195195
0, // atts
196196
});
197-
for (byte i = 0; i < msgLength; i++) {
197+
for (uint8_t i = 0; i < msgLength; i++) {
198198
queueData.push(inBuffer[i + addressPos]);
199199
}
200200
if (queueData.size() > queueDataSize) queueDataSize = queueData.size();
@@ -208,7 +208,7 @@ void deleteRequest() // delete request from queue
208208
if (myHeader.requestType & SCAN_REQUEST) scanReqInQueue = false;
209209
if (myHeader.requestType & TCP_REQUEST) socketInQueue[myHeader.requestType & TCP_REQUEST_MASK]--;
210210
if (myHeader.requestType & PRIORITY_REQUEST) priorityReqInQueue--;
211-
for (byte i = 0; i < myHeader.msgLen; i++) {
211+
for (uint8_t i = 0; i < myHeader.msgLen; i++) {
212212
queueData.shift();
213213
}
214214
queueHeaders.shift();
@@ -224,17 +224,17 @@ void clearQueue() {
224224
sendMicroTimer.sleep(0);
225225
}
226226

227-
bool getSlaveStatus(const uint8_t slave, const byte status) {
227+
bool getSlaveStatus(const uint8_t slave, const uint8_t status) {
228228
if (slave >= MAX_SLAVES) return false; // error
229229
return (slaveStatus[status][slave / 8] & masks[slave & 7]) > 0;
230230
}
231231

232-
void setSlaveStatus(const uint8_t slave, byte status, const bool value, const bool isScan) {
232+
void setSlaveStatus(const uint8_t slave, uint8_t status, const bool value, const bool isScan) {
233233
if (slave >= MAX_SLAVES || status > SLAVE_ERROR_0B_QUEUE) return; // error
234234
if (value == 0) {
235235
slaveStatus[status][slave / 8] &= ~masks[slave & 7];
236236
} else {
237-
for (byte i = 0; i <= SLAVE_ERROR_0B_QUEUE; i++) {
237+
for (uint8_t i = 0; i <= SLAVE_ERROR_0B_QUEUE; i++) {
238238
slaveStatus[i][slave / 8] &= ~masks[slave & 7]; // set all other flags to false, SLAVE_ERROR_0B_QUEUE is the last slave status
239239
}
240240
slaveStatus[status][slave / 8] |= masks[slave & 7];

0 commit comments

Comments
 (0)