1
0
mirror of https://github.com/DCC-EX/CommandStation-EX.git synced 2024-11-22 15:46:14 +01:00

Automatic MAC Address handling for Ethernet/WiFi

This commit is contained in:
Gregor Baues 2020-11-10 16:36:34 +01:00
parent dda7bc7277
commit 8fa6ded079
8 changed files with 331 additions and 7 deletions

121
ArduinoUniqueID.cpp Normal file
View File

@ -0,0 +1,121 @@
/*
* © 2020 Gregor Baues, Luiz Henrique Cassettari. All rights reserved.
*
* This is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
* See the GNU General Public License for more details <https://www.gnu.org/licenses/>
*/
#include "ArduinoUniqueID.h"
ArduinoUniqueID::ArduinoUniqueID()
{
#if defined(ARDUINO_ARCH_AVR)
for (size_t i = 0; i < UniqueIDsize; i++)
{
id[i] = boot_signature_byte_get(0x0E + i + (UniqueIDsize == 9 && i > 5 ? 1 : 0));
}
#elif defined(ARDUINO_ARCH_ESP8266)
uint32_t chipid = ESP.getChipId();
id[0] = 0;
id[1] = 0;
id[2] = 0;
id[3] = 0;
id[4] = chipid >> 24;
id[5] = chipid >> 16;
id[6] = chipid >> 8;
id[7] = chipid;
#elif defined(ARDUINO_ARCH_ESP32)
uint64_t chipid = ESP.getEfuseMac();
id[0] = 0;
id[1] = 0;
id[2] = chipid;
id[3] = chipid >> 8;
id[4] = chipid >> 16;
id[5] = chipid >> 24;
id[6] = chipid >> 32;
id[7] = chipid >> 40;
#elif defined(ARDUINO_ARCH_SAM)
unsigned int status ;
/* Send the Start Read unique Identifier command (STUI) by writing the Flash Command Register with the STUI command.*/
EFC1->EEFC_FCR = (0x5A << 24) | EFC_FCMD_STUI;
do
{
status = EFC1->EEFC_FSR ;
} while ( (status & EEFC_FSR_FRDY) == EEFC_FSR_FRDY ) ;
/* The Unique Identifier is located in the first 128 bits of the Flash memory mapping. So, at the address 0x400000-0x400003. */
uint32_t pdwUniqueID[4];
pdwUniqueID[0] = *(uint32_t *)IFLASH1_ADDR;
pdwUniqueID[1] = *(uint32_t *)(IFLASH1_ADDR + 4);
pdwUniqueID[2] = *(uint32_t *)(IFLASH1_ADDR + 8);
pdwUniqueID[3] = *(uint32_t *)(IFLASH1_ADDR + 12);
for (int i = 0; i < 4; i++)
{
id[i*4+0] = (uint8_t)(pdwUniqueID[i] >> 24);
id[i*4+1] = (uint8_t)(pdwUniqueID[i] >> 16);
id[i*4+2] = (uint8_t)(pdwUniqueID[i] >> 8);
id[i*4+3] = (uint8_t)(pdwUniqueID[i] >> 0);
}
/* To stop the Unique Identifier mode, the user needs to send the Stop Read unique Identifier
command (SPUI) by writing the Flash Command Register with the SPUI command. */
EFC1->EEFC_FCR = (0x5A << 24) | EFC_FCMD_SPUI ;
/* When the Stop read Unique Unique Identifier command (SPUI) has been performed, the
FRDY bit in the Flash Programming Status Register (EEFC_FSR) rises. */
do
{
status = EFC1->EEFC_FSR ;
} while ( (status & EEFC_FSR_FRDY) != EEFC_FSR_FRDY );
#elif defined(ARDUINO_ARCH_SAMD)
// from section 9.3.3 of the datasheet
#define SERIAL_NUMBER_WORD_0 *(volatile uint32_t*)(0x0080A00C)
#define SERIAL_NUMBER_WORD_1 *(volatile uint32_t*)(0x0080A040)
#define SERIAL_NUMBER_WORD_2 *(volatile uint32_t*)(0x0080A044)
#define SERIAL_NUMBER_WORD_3 *(volatile uint32_t*)(0x0080A048)
uint32_t pdwUniqueID[4];
pdwUniqueID[0] = SERIAL_NUMBER_WORD_0;
pdwUniqueID[1] = SERIAL_NUMBER_WORD_1;
pdwUniqueID[2] = SERIAL_NUMBER_WORD_2;
pdwUniqueID[3] = SERIAL_NUMBER_WORD_3;
for (int i = 0; i < 4; i++)
{
id[i*4+0] = (uint8_t)(pdwUniqueID[i] >> 24);
id[i*4+1] = (uint8_t)(pdwUniqueID[i] >> 16);
id[i*4+2] = (uint8_t)(pdwUniqueID[i] >> 8);
id[i*4+3] = (uint8_t)(pdwUniqueID[i] >> 0);
}
#elif defined(ARDUINO_ARCH_STM32)
uint32_t pdwUniqueID[3];
pdwUniqueID[0] = HAL_GetUIDw0();
pdwUniqueID[1] = HAL_GetUIDw1();
pdwUniqueID[2] = HAL_GetUIDw2();
for (int i = 0; i < 3; i++)
{
id[i*4+0] = (uint8_t)(pdwUniqueID[i] >> 24);
id[i*4+1] = (uint8_t)(pdwUniqueID[i] >> 16);
id[i*4+2] = (uint8_t)(pdwUniqueID[i] >> 8);
id[i*4+3] = (uint8_t)(pdwUniqueID[i] >> 0);
}
#endif
}
ArduinoUniqueID _UniqueID;

104
ArduinoUniqueID.h Normal file
View File

@ -0,0 +1,104 @@
/*
* © 2020 Gregor Baues, Luiz Henrique Cassettari. All rights reserved.
*
* This is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
* See the GNU General Public License for more details <https://www.gnu.org/licenses/>
*/
#ifndef _ARDUINO_UNIQUE_ID_H_
#define _ARDUINO_UNIQUE_ID_H_
#include <Arduino.h>
#if defined(ARDUINO_ARCH_AVR)
#include <avr/boot.h>
#ifndef SIGRD
#define SIGRD 5
#endif
#elif defined(ARDUINO_ARCH_ESP8266)
#elif defined(ARDUINO_ARCH_ESP32)
#elif defined(ARDUINO_ARCH_SAM)
#elif defined(ARDUINO_ARCH_SAMD)
#elif defined(ARDUINO_ARCH_STM32)
#else
#error "ArduinoUniqueID only works on AVR, SAM, SAMD, STM32 and ESP Architecture"
#endif
#if defined(ARDUINO_ARCH_AVR)
#if defined(__AVR_ATmega328PB__)
#define UniqueIDsize 10
#else
#define UniqueIDsize 9
#endif
#define UniqueIDbuffer UniqueIDsize
#elif defined(ARDUINO_ARCH_ESP8266)
#define UniqueIDsize 4
#define UniqueIDbuffer 8
#elif defined(ARDUINO_ARCH_ESP32)
#define UniqueIDsize 6
#define UniqueIDbuffer 8
#elif defined(ARDUINO_ARCH_SAM)
#define UniqueIDsize 16
#define UniqueIDbuffer 16
#elif defined(ARDUINO_ARCH_SAMD)
#define UniqueIDsize 16
#define UniqueIDbuffer 16
#elif defined(ARDUINO_ARCH_STM32)
#define UniqueIDsize 12
#define UniqueIDbuffer 12
#endif
#define UniqueID8 (_UniqueID.id + UniqueIDbuffer - 8)
#define UniqueID (_UniqueID.id + UniqueIDbuffer - UniqueIDsize)
#define UniqueIDdump(stream) \
{ \
stream.print("UniqueID: "); \
for (size_t i = 0; i < UniqueIDsize; i++) \
{ \
if (UniqueID[i] < 0x10) \
stream.print("0"); \
stream.print(UniqueID[i], HEX); \
stream.print(" "); \
} \
stream.println(); \
}
#define UniqueID8dump(stream) \
{ \
stream.print("UniqueID: "); \
for (size_t i = 0; i < 8; i++) \
{ \
if (UniqueID8[i] < 0x10) \
stream.print("0"); \
stream.print(UniqueID8[i], HEX); \
stream.print(" "); \
} \
stream.println(); \
}
class ArduinoUniqueID
{
public:
ArduinoUniqueID();
uint8_t id[UniqueIDbuffer];
};
extern ArduinoUniqueID _UniqueID;
#endif

View File

@ -86,7 +86,7 @@ void setup()
// nwi1.setup(ETHERNET, TCP); // ETHERNET/TCP on Port 2560
nwi2.setup(ETHERNET, TCP, 23); // ETHERNET/TCP on Port 23 for the CLI
// nwi1.setup(ETHERNET, TCP, 8888); // ETHERNET/TCP on Port 8888
// nwi2.setup(WIFI, TCP); // WIFI/TCP on Port 2560
nwi2.setup(WIFI, TCP); // WIFI/TCP on Port 2560
// nwi1.setHttpCallback(httpRequestHandler); // HTTP callback
DIAG(F("\nNetwork Setup done ...\n"));

View File

@ -20,10 +20,13 @@
#include <Arduino.h>
#include "NetworkDiag.h"
#include "NetworkSetup.h"
#include "EthernetSetup.h"
byte EthernetSetup::setup()
{
INFO(F("Initialize MAC Address ..."));
NetworkSetup::genMacAddress();
INFO(F("Initialize Ethernet with DHCP"));
if (Ethernet.begin(mac) == 0)
@ -61,7 +64,7 @@ byte EthernetSetup::setup()
maxConnections = 8;
}
INFO(F("Network Protocol: [%s]"), protocol ? "UDP" : "TCP");
INFO(F("Network Protocol: [%s]"), protocol ? "UDP" : "TCP");
switch (protocol)
{
case UDPR:
@ -102,8 +105,9 @@ byte EthernetSetup::setup()
if (connected)
{
ip = Ethernet.localIP();
INFO(F("Local IP address: [%d.%d.%d.%d]"), ip[0], ip[1], ip[2], ip[3]);
INFO(F("Listening on port: [%d]"), port);
NetworkSetup::printMacAddress(NetworkSetup::mac);
INFO(F("Local IP address: [%d.%d.%d.%d]"), ip[0], ip[1], ip[2], ip[3]);
INFO(F("Listening on port: [%d]"), port);
dnsip = Ethernet.dnsServerIP();
INFO(F("DNS server IP address: [%d.%d.%d.%d] "), dnsip[0], dnsip[1], dnsip[2], dnsip[3]);
INFO(F("Number of connections: [%d]"), maxConnections);

View File

@ -20,6 +20,7 @@
#include <Arduino.h>
#include "NetworkDiag.h"
#include "NetworkSetup.h"
#include "NetworkInterface.h"
#include "Transport.h"
#include "EthernetSetup.h"
@ -76,6 +77,8 @@ void NetworkInterface::setup(transportType transport, protocolType protocol, uin
bool ok = false;
_nLogLevel = 4; // set the log level to ERROR during setup to get proper information
NetworkSetup::setDeviceId();
INFO(F("[%s] Transport Setup In Progress ..."), transport ? "Ethernet" : "Wifi");
// configure the Transport and get Ethernet/Wifi server up and running
@ -130,7 +133,7 @@ void NetworkInterface::setup(transportType transport, protocolType protocol, uin
}
INFO(F("[%s] Transport %s ..."), transport ? "Ethernet" : "Wifi", ok ? "OK" : "Failed");
_nLogLevel = 0; // set loging back to silent;
// _nLogLevel = 0; // set loging back to silent;
}
void NetworkInterface::setup(transportType tt, protocolType pt)

View File

@ -18,7 +18,59 @@
*/
#include <Arduino.h>
#include "ArduinoUniqueID.h"
#include "NetworkSetup.h"
#include "NetworkDiag.h"
bool NetworkSetup::deviceIdSet = false;
bool NetworkSetup::macAddressSet = false;
char NetworkSetup::_deviceId[MAXDEVICEID] = {0};
uint8_t NetworkSetup::mac[6] = MAC_ADDRESS; // default MacAddress
uint8_t NetworkSetup::apWifiMacAddress[6] = MAC_ADDRESS; // default MacAddress
uint8_t NetworkSetup::stWifiMacAddress[6] = MAC_ADDRESS; // default MacAddress
static void array_to_string(byte array[], unsigned int len, char buffer[])
{
for (unsigned int i = 0; i < len; i++)
{
byte nib1 = (array[i] >> 4) & 0x0F;
byte nib2 = (array[i] >> 0) & 0x0F;
buffer[i * 2 + 0] = nib1 < 0xA ? '0' + nib1 : 'A' + nib1 - 0xA;
buffer[i * 2 + 1] = nib2 < 0xA ? '0' + nib2 : 'A' + nib2 - 0xA;
}
buffer[len * 2] = '\0';
}
void NetworkSetup::setDeviceId()
{
array_to_string(UniqueID, UniqueIDsize, _deviceId);
DBG(F("Unique device ID: %s\n"), _deviceId);
deviceIdSet = true;
}
void NetworkSetup::printMacAddress(uint8_t a[]) {
INFO(F("MAC Address: [%x:%x:%x:%x:%x:%x]"),a[0],a[1],a[2],a[3],a[4],a[5]);
}
/**
* @brief generates Mac Addresses for Ethernet and WiFi
*
*/
void NetworkSetup::genMacAddress() {
if (!deviceIdSet) NetworkSetup::setDeviceId();
if (!macAddressSet) {
for (byte i = 0; i < 6; i++)
{
mac[i] = UniqueID[i];
};
}
macAddressSet = true;
}
NetworkSetup::NetworkSetup() {}
NetworkSetup::~NetworkSetup() {}
NetworkSetup::~NetworkSetup() {}
// WiFi.apMacAddress(apWifiMacAddress);
// WiFi.macAddress(stWifiMacAddress);

View File

@ -25,18 +25,36 @@
#include "NetworkConfig.h"
#include "NetworkInterface.h"
#define MAXDEVICEID 20
class NetworkSetup
{
private:
static char _deviceId[MAXDEVICEID];
static bool macAddressSet;
static bool deviceIdSet;
public:
IPAddress dnsip;
IPAddress ip;
uint8_t mac[6] = MAC_ADDRESS;
static uint8_t mac[6]; // Default if not set automatically for EthernetShield
static uint8_t apWifiMacAddress[6]; // for the WiFi AP
static uint8_t stWifiMacAddress[6]; // for the normal WiFi connection
uint8_t maxConnections;
bool connected; // semantics is that the server has successfullt started or not; client connections will be started in the Transport object
protocolType protocol;
uint16_t port = LISTEN_PORT; // Default port
static void setDeviceId();
char *getDeviceId() {
return _deviceId;
}
static void genMacAddress();
static void printMacAddress(uint8_t a[]);
NetworkSetup();
~NetworkSetup();
};

View File

@ -23,6 +23,8 @@
#include "NetworkSetup.h"
#include "WifiSetup.h"
void reverseArray(uint8_t arr[], int start, int end);
bool WifiSetup::setup() {
/**
* @todo setup using SoftwareSerial or any other Hardware Serial port on the mega (i.e. 2 or 3);
@ -47,6 +49,11 @@ bool WifiSetup::setup() {
}
INFO(F("Network Protocol: [%s]"), protocol ? "UDP" : "TCP");
INFO(F("Initialize MAC Addresses ... "));
WiFi.apMacAddress(apWifiMacAddress);
reverseArray(apWifiMacAddress, 0, 5); // the MAc is provided in reverse order ...
WiFi.macAddress(stWifiMacAddress);
reverseArray(stWifiMacAddress, 0, 5);
// Setup the protocol handler
switch (protocol)
@ -96,6 +103,9 @@ bool WifiSetup::setup() {
if (connected)
{
ip = WiFi.localIP();
NetworkSetup::printMacAddress(apWifiMacAddress);
NetworkSetup::printMacAddress(stWifiMacAddress);
INFO(F("Local IP address: [%d.%d.%d.%d]"), ip[0], ip[1], ip[2], ip[3]);
INFO(F("Listening on port: [%d]"), port);
dnsip = WiFi.dnsServer1();
@ -107,6 +117,18 @@ bool WifiSetup::setup() {
};
void reverseArray(uint8_t arr[], int start, int end)
{
while (start < end)
{
uint8_t temp = arr[start];
arr[start] = arr[end];
arr[end] = temp;
start++;
end--;
}
}
WifiSetup::WifiSetup() {}
WifiSetup::WifiSetup(uint16_t p, protocolType pt ) { port = p; protocol = pt; }
WifiSetup::~WifiSetup() {}