Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/Duet3D/RepRapFirmware.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Crocker <dcrocker@eschertech.com>2022-07-22 13:22:30 +0300
committerDavid Crocker <dcrocker@eschertech.com>2022-07-22 13:22:30 +0300
commitae57311e07859914d4cebca351911257a6fcc060 (patch)
tree75d2374b8f4a7d2cc859e5b15fb553df795c4bf4
parentb5b5790b303d32286a65192d3790ae246444dc4c (diff)
parent444b78c7463d9a5497b49a9665d3da64e7baa871 (diff)
Merge branch '3.4-multicast' into 3.4-dev
-rw-r--r--src/CAN/CanInterface.cpp59
-rw-r--r--src/CAN/CanInterface.h5
-rw-r--r--src/Config/Pins.h4
-rw-r--r--src/Config/Pins_Duet3_MB6HC.h6
-rw-r--r--src/Config/Pins_Duet3_MB6XD.h6
-rw-r--r--src/Hardware/SAME70/Ethernet/GmacInterface.cpp7
-rw-r--r--src/Networking/ESP8266WiFi/WiFiInterface.cpp1
-rw-r--r--src/Networking/ESP8266WiFi/WiFiInterface.h8
-rw-r--r--src/Networking/LwipEthernet/Lwip/lwipopts.h2
-rw-r--r--src/Networking/LwipEthernet/LwipEthernetInterface.cpp41
-rw-r--r--src/Networking/LwipEthernet/LwipEthernetInterface.h11
-rw-r--r--src/Networking/MulticastDiscovery/MulticastResponder.cpp181
-rw-r--r--src/Networking/MulticastDiscovery/MulticastResponder.h29
-rw-r--r--src/Networking/MulticastDiscovery/Notes on multicast implementation.md37
-rw-r--r--src/Networking/MulticastDiscovery/fgmc_header.h173
-rw-r--r--src/Networking/MulticastDiscovery/fgmc_protocol.cpp497
-rw-r--r--src/Networking/MulticastDiscovery/fgmc_protocol.h114
-rw-r--r--src/Networking/Network.cpp60
-rw-r--r--src/Networking/Network.h3
-rw-r--r--src/Networking/NetworkDefs.h31
-rw-r--r--src/Networking/NetworkInterface.h3
-rw-r--r--src/Networking/NetworkResponder.h4
-rw-r--r--src/Networking/W5500Ethernet/W5500Interface.h8
23 files changed, 1248 insertions, 42 deletions
diff --git a/src/CAN/CanInterface.cpp b/src/CAN/CanInterface.cpp
index f3d1de15..4dac2518 100644
--- a/src/CAN/CanInterface.cpp
+++ b/src/CAN/CanInterface.cpp
@@ -203,6 +203,52 @@ extern "C" [[noreturn]] void CanSenderLoop(void *) noexcept;
extern "C" [[noreturn]] void CanClockLoop(void *) noexcept;
extern "C" [[noreturn]] void CanReceiverLoop(void *) noexcept;
+// Status LED handling
+
+#if SUPPORT_MULTICAST_DISCOVERY
+
+// The STATUS LED is also used to identify one board among several visible to the user
+static volatile uint32_t identInitialClocks = 0; // when we started identifying
+static volatile uint32_t identTotalClocks = 0; // how many step clocks to identify for, zero means until cancelled
+static volatile bool identifying = false;
+
+void CanInterface::SetStatusLedIdentify(uint32_t seconds) noexcept
+{
+ identTotalClocks = seconds * StepClockRate;
+ identInitialClocks = StepTimer::GetTimerTicks();
+ identifying = true;
+}
+
+void CanInterface::SetStatusLedNormal() noexcept
+{
+ identifying = false;
+}
+
+#endif
+
+// This is called only from the CAN clock loop, so inline
+static inline void UpdateLed(uint32_t stepClocks) noexcept
+{
+#if SUPPORT_MULTICAST_DISCOVERY
+ if (identifying)
+ {
+ if (identTotalClocks != 0 && stepClocks - identInitialClocks >= identTotalClocks)
+ {
+ identifying = 0; // stop identifying
+ }
+ else
+ {
+ // Blink the LED fast. This function gets called every 200ms, so that's the fastest we can blink it without having another task do it.
+ digitalWrite(DiagPin, !digitalRead(DiagPin));
+ return;
+ }
+ }
+#endif
+
+ // Blink the LED at about 1Hz. Duet 3 expansion boards will blink in sync when they have established clock sync with us.
+ digitalWrite(DiagPin, XNor(DiagOnPolarity, (stepClocks & (1u << 19)) != 0));
+}
+
static void InitReceiveFilters() noexcept
{
// Set up a filter to receive all request messages addressed to us in FIFO 0
@@ -570,8 +616,7 @@ extern "C" [[noreturn]] void CanClockLoop(void *) noexcept
SendCanMessage(TxBufferIndexTimeSync, 0, &buf);
++timeSyncMessagesSent;
- // Blink the LED at about 2Hz. Duet 3 expansion boards will blink in sync when they have established clock sync with us.
- digitalWrite(DiagPin, XNor(DiagOnPolarity, lastTimeSent & (1u << 19)) != 0);
+ UpdateLed(lastTimeSent);
// Delay until it is time again
vTaskDelayUntil(&lastWakeTime, CanClockIntervalMillis);
@@ -1490,15 +1535,14 @@ GCodeResult CanInterface::StartClosedLoopDataCollection(DriverId device, uint16_
}
#if DUAL_CAN
+
CanId CanInterface::ODrive::ArbitrationId(DriverId const driver, uint8_t const cmd) noexcept {
const auto arbitration_id = (driver.boardAddress << 5) + cmd;
CanId canId;
canId.SetReceivedId(arbitration_id);
return canId;
}
-#endif
-#if DUAL_CAN
CanMessageBuffer * CanInterface::ODrive::PrepareSimpleMessage(DriverId const driver, const StringRef& reply) noexcept
{
// Detect any early return conditions
@@ -1523,17 +1567,12 @@ CanMessageBuffer * CanInterface::ODrive::PrepareSimpleMessage(DriverId const dri
return buf;
}
-#endif
-#if DUAL_CAN
void CanInterface::ODrive::FlushCanReceiveHardware() noexcept
{
while (CanInterface::ReceivePlainMessage(nullptr, 0)) { }
}
-#endif
-
-#if DUAL_CAN
bool CanInterface::ODrive::GetExpectedSimpleMessage(CanMessageBuffer *buf, DriverId const driver, uint8_t const cmd, const StringRef& reply) noexcept
{
CanId const expectedId = ArbitrationId(driver, cmd);
@@ -1554,7 +1593,7 @@ bool CanInterface::ODrive::GetExpectedSimpleMessage(CanMessageBuffer *buf, Drive
return ok;
}
-#endif
+#endif // DUAL_CAN
#endif
diff --git a/src/CAN/CanInterface.h b/src/CAN/CanInterface.h
index ef322205..14b9faca 100644
--- a/src/CAN/CanInterface.h
+++ b/src/CAN/CanInterface.h
@@ -109,6 +109,11 @@ namespace CanInterface
#endif
GCodeResult StartClosedLoopDataCollection(DriverId device, uint16_t filter, uint16_t numSamples, uint16_t rateRequested, uint8_t movementRequested, uint8_t mode, const GCodeBuffer& gb, const StringRef& reply) THROWS(GCodeException);
+#if SUPPORT_MULTICAST_DISCOVERY
+ void SetStatusLedIdentify(uint32_t seconds) noexcept;
+ void SetStatusLedNormal() noexcept;
+#endif
+
#if DUAL_CAN
namespace ODrive {
CanId ArbitrationId(DriverId driver, uint8_t cmd) noexcept;
diff --git a/src/Config/Pins.h b/src/Config/Pins.h
index efa86e7f..69d7f45d 100644
--- a/src/Config/Pins.h
+++ b/src/Config/Pins.h
@@ -179,6 +179,10 @@
# define SUPPORT_TELNET HAS_NETWORKING
#endif
+#ifndef SUPPORT_MULTICAST_DISCOVERY
+# define SUPPORT_MULTICAST_DISCOVERY 0
+#endif
+
#ifndef HAS_SBC_INTERFACE
# define HAS_SBC_INTERFACE 0
#endif
diff --git a/src/Config/Pins_Duet3_MB6HC.h b/src/Config/Pins_Duet3_MB6HC.h
index 6d7ea386..168d82f9 100644
--- a/src/Config/Pins_Duet3_MB6HC.h
+++ b/src/Config/Pins_Duet3_MB6HC.h
@@ -15,12 +15,15 @@
constexpr uint32_t IAP_IMAGE_START = 0x20458000; // last 32kb of RAM
// Features definition
+// Networking support
#define HAS_LWIP_NETWORKING 1
#define HAS_WIFI_NETWORKING 0
-#define HAS_SBC_INTERFACE 1
+// Storage support
+#define HAS_SBC_INTERFACE 1
#define HAS_MASS_STORAGE 1
#define HAS_HIGH_SPEED_SD 1
+
#define HAS_CPU_TEMP_SENSOR 1
#define SUPPORT_TMC51xx 1
@@ -46,6 +49,7 @@ constexpr uint32_t IAP_IMAGE_START = 0x20458000; // last 32kb of RAM
#define SUPPORT_OBJECT_MODEL 1
#define SUPPORT_FTP 1
#define SUPPORT_TELNET 1
+#define SUPPORT_MULTICAST_DISCOVERY 1
#define SUPPORT_ASYNC_MOVES 1
#define ALLOCATE_DEFAULT_PORTS 0
#define TRACK_OBJECT_NAMES 1
diff --git a/src/Config/Pins_Duet3_MB6XD.h b/src/Config/Pins_Duet3_MB6XD.h
index c1df8adf..aa1c3bce 100644
--- a/src/Config/Pins_Duet3_MB6XD.h
+++ b/src/Config/Pins_Duet3_MB6XD.h
@@ -15,12 +15,15 @@
constexpr uint32_t IAP_IMAGE_START = 0x20458000; // last 32kb of RAM
// Features definition
+// Networking support
#define HAS_LWIP_NETWORKING 1
#define HAS_WIFI_NETWORKING 0
-#define HAS_SBC_INTERFACE 1
+// Storage support
+#define HAS_SBC_INTERFACE 1
#define HAS_MASS_STORAGE 1
#define HAS_HIGH_SPEED_SD 1
+
#define HAS_CPU_TEMP_SENSOR 1
#define SUPPORT_TMC51xx 0
@@ -45,6 +48,7 @@ constexpr uint32_t IAP_IMAGE_START = 0x20458000; // last 32kb of RAM
#define SUPPORT_OBJECT_MODEL 1
#define SUPPORT_FTP 1
#define SUPPORT_TELNET 1
+#define SUPPORT_MULTICAST_DISCOVERY 1
#define SUPPORT_ASYNC_MOVES 1
#define ALLOCATE_DEFAULT_PORTS 0
#define TRACK_OBJECT_NAMES 1
diff --git a/src/Hardware/SAME70/Ethernet/GmacInterface.cpp b/src/Hardware/SAME70/Ethernet/GmacInterface.cpp
index 8099da8c..abf2e0a0 100644
--- a/src/Hardware/SAME70/Ethernet/GmacInterface.cpp
+++ b/src/Hardware/SAME70/Ethernet/GmacInterface.cpp
@@ -667,6 +667,13 @@ void ethernetif_hardware_init() noexcept
gmac_enable_copy_all(GMAC, false);
gmac_disable_broadcast(GMAC, false);
+#if SUPPORT_MULTICAST_DISCOVERY
+ // Without this code, we don't receive any multicast packets
+ GMAC->GMAC_NCFGR |= GMAC_NCFGR_MTIHEN; // enable multicast hash reception
+ GMAC->GMAC_HRB = 0xFFFFFFFF; // enable reception of all multicast frames
+ GMAC->GMAC_HRT = 0xFFFFFFFF;
+#endif
+
/* Set RX buffer size to 1536. */
gmac_set_rx_bufsize(GMAC, 0x18);
diff --git a/src/Networking/ESP8266WiFi/WiFiInterface.cpp b/src/Networking/ESP8266WiFi/WiFiInterface.cpp
index bb7e0c29..ee284d91 100644
--- a/src/Networking/ESP8266WiFi/WiFiInterface.cpp
+++ b/src/Networking/ESP8266WiFi/WiFiInterface.cpp
@@ -1029,6 +1029,7 @@ void WiFiInterface::EspRequestsTransfer() noexcept
void WiFiInterface::SetIPAddress(IPAddress p_ip, IPAddress p_netmask, IPAddress p_gateway) noexcept
{
ipAddress = p_ip;
+ usingDhcp = ipAddress.IsNull();
netmask = p_netmask;
gateway = p_gateway;
}
diff --git a/src/Networking/ESP8266WiFi/WiFiInterface.h b/src/Networking/ESP8266WiFi/WiFiInterface.h
index 29ba546d..18fac5bc 100644
--- a/src/Networking/ESP8266WiFi/WiFiInterface.h
+++ b/src/Networking/ESP8266WiFi/WiFiInterface.h
@@ -58,7 +58,11 @@ public:
bool IsWiFiInterface() const noexcept override { return true; }
void UpdateHostname(const char *hostname) noexcept override;
+
IPAddress GetIPAddress() const noexcept override { return ipAddress; }
+ IPAddress GetNetmask() const noexcept override { return netmask; }
+ IPAddress GetGateway() const noexcept override { return gateway; }
+ bool UsingDhcp() const noexcept override { return usingDhcp; }
void SetIPAddress(IPAddress p_ip, IPAddress p_netmask, IPAddress p_gateway) noexcept override;
GCodeResult SetMacAddress(const MacAddress& mac, const StringRef& reply) noexcept override;
const MacAddress& GetMacAddress() const noexcept override { return macAddress; }
@@ -138,7 +142,7 @@ private:
WiFiSocket *sockets[NumWiFiTcpSockets];
size_t currentSocket;
- TcpPort portNumbers[NumProtocols]; // port number used for each protocol
+ TcpPort portNumbers[NumProtocols]; // port number used for each protocol
TcpPort ftpDataPort;
bool closeDataPort;
bool protocolEnabled[NumProtocols]; // whether each protocol is enabled
@@ -164,6 +168,8 @@ private:
char wiFiServerVersion[16];
+ bool usingDhcp = true;
+
// For processing debug messages from the WiFi module
bool serialRunning;
bool debugPrintPending;
diff --git a/src/Networking/LwipEthernet/Lwip/lwipopts.h b/src/Networking/LwipEthernet/Lwip/lwipopts.h
index dc747e95..ec45aee7 100644
--- a/src/Networking/LwipEthernet/Lwip/lwipopts.h
+++ b/src/Networking/LwipEthernet/Lwip/lwipopts.h
@@ -267,7 +267,7 @@ extern uint32_t random32(void) noexcept;
#define LWIP_NETIF_HOSTNAME 1
/** The maximum number of services per netif */
-#define MDNS_MAX_SERVICES 4
+#define MDNS_MAX_SERVICES 5 // increased from 4 to 5 to include _duet_discovery service
/*
diff --git a/src/Networking/LwipEthernet/LwipEthernetInterface.cpp b/src/Networking/LwipEthernet/LwipEthernetInterface.cpp
index 9f35a201..443a09f7 100644
--- a/src/Networking/LwipEthernet/LwipEthernetInterface.cpp
+++ b/src/Networking/LwipEthernet/LwipEthernetInterface.cpp
@@ -20,6 +20,10 @@
#include <Networking/HttpResponder.h>
#include <Networking/FtpResponder.h>
#include <Networking/TelnetResponder.h>
+#if SUPPORT_MULTICAST_DISCOVERY
+# include <Networking/MulticastDiscovery/MulticastResponder.h>
+#endif
+
#include <General/IP4String.h>
#include <Version.h> // version is reported by MDNS
#include "GMAC/ethernet_sam.h"
@@ -46,7 +50,14 @@ extern "C"
extern struct netif gs_net_if;
}
-const char * const MdnsServiceStrings[NumProtocols] = { "_http", "_ftp", "_telnet" };
+const char * const MdnsServiceStrings[NumProtocols] =
+{
+ "_http", "_ftp", "_telnet",
+#if SUPPORT_MULTICAST_DISCOVERY
+ "_duet_discovery"
+#endif
+};
+
const char * const MdnsTxtRecords[2] = { "product=" FIRMWARE_NAME, "version=" VERSION };
const unsigned int MdnsTtl = 10 * 60; // same value as on the Duet 0.6/0.8.5
@@ -142,9 +153,9 @@ void LwipEthernetInterface::Init() noexcept
lwipMutex.Create("LwipCore");
// Clear the PCBs
- for (size_t i = 0; i < NumTcpPorts; ++i)
+ for (tcp_pcb*& pcb : listeningPcbs)
{
- listeningPcbs[i] = nullptr;
+ pcb = nullptr;
}
macAddress = platform.GetDefaultMacAddress();
@@ -178,6 +189,7 @@ GCodeResult LwipEthernetInterface::EnableProtocol(NetworkProtocol protocol, int
RebuildMdnsServices();
}
}
+
ReportOneProtocol(protocol, reply);
return GCodeResult::ok;
}
@@ -205,7 +217,11 @@ GCodeResult LwipEthernetInterface::DisableProtocol(NetworkProtocol protocol, con
void LwipEthernetInterface::StartProtocol(NetworkProtocol protocol) noexcept
{
- if (listeningPcbs[protocol] == nullptr)
+ if ( listeningPcbs[protocol] == nullptr
+#if SUPPORT_MULTICAST_DISCOVERY
+ && protocol != MulticastDiscoveryProtocol
+#endif
+ )
{
tcp_pcb *pcb = tcp_new();
if (pcb == nullptr)
@@ -245,6 +261,12 @@ void LwipEthernetInterface::StartProtocol(NetworkProtocol protocol) noexcept
sockets[TelnetSocketNumber]->Init(TelnetSocketNumber, portNumbers[protocol], protocol);
break;
+#if SUPPORT_MULTICAST_DISCOVERY
+ case MulticastDiscoveryProtocol:
+ MulticastResponder::Start(portNumbers[protocol]);
+ break;
+#endif
+
default:
break;
}
@@ -270,6 +292,12 @@ void LwipEthernetInterface::ShutdownProtocol(NetworkProtocol protocol) noexcept
sockets[TelnetSocketNumber]->TerminateAndDisable();
break;
+#if SUPPORT_MULTICAST_DISCOVERY
+ case MulticastDiscoveryProtocol:
+ MulticastResponder::Stop();
+ break;
+#endif
+
default:
break;
}
@@ -547,11 +575,6 @@ bool LwipEthernetInterface::ConnectionEstablished(tcp_pcb *pcb) noexcept
return false;
}
-IPAddress LwipEthernetInterface::GetIPAddress() const noexcept
-{
- return ipAddress;
-}
-
void LwipEthernetInterface::SetIPAddress(IPAddress p_ipAddress, IPAddress p_netmask, IPAddress p_gateway) noexcept
{
if (GetState() == NetworkState::obtainingIP || GetState() == NetworkState::active)
diff --git a/src/Networking/LwipEthernet/LwipEthernetInterface.h b/src/Networking/LwipEthernet/LwipEthernetInterface.h
index 01fa0f03..e1a34da5 100644
--- a/src/Networking/LwipEthernet/LwipEthernetInterface.h
+++ b/src/Networking/LwipEthernet/LwipEthernetInterface.h
@@ -48,8 +48,13 @@ public:
bool IsWiFiInterface() const noexcept override { return false; }
void UpdateHostname(const char *hostname) noexcept override;
- IPAddress GetIPAddress() const noexcept override;
+
+ IPAddress GetIPAddress() const noexcept override { return ipAddress; }
+ IPAddress GetNetmask() const noexcept override { return netmask; }
+ IPAddress GetGateway() const noexcept override { return gateway; }
+ bool UsingDhcp() const noexcept override { return usingDhcp; }
void SetIPAddress(IPAddress p_ipAddress, IPAddress p_netmask, IPAddress p_gateway) noexcept override;
+
GCodeResult SetMacAddress(const MacAddress& mac, const StringRef& reply) noexcept override;
const MacAddress& GetMacAddress() const noexcept override { return macAddress; }
@@ -87,11 +92,11 @@ private:
TcpPort portNumbers[NumProtocols]; // port number used for each protocol
bool protocolEnabled[NumProtocols]; // whether each protocol is enabled
bool closeDataPort;
- tcp_pcb *listeningPcbs[NumTcpPorts];
+ tcp_pcb *listeningPcbs[NumProtocols + 1];
bool activated;
bool initialised;
- bool usingDhcp;
+ bool usingDhcp = true;
IPAddress ipAddress;
IPAddress netmask;
diff --git a/src/Networking/MulticastDiscovery/MulticastResponder.cpp b/src/Networking/MulticastDiscovery/MulticastResponder.cpp
new file mode 100644
index 00000000..c2227c33
--- /dev/null
+++ b/src/Networking/MulticastDiscovery/MulticastResponder.cpp
@@ -0,0 +1,181 @@
+/*
+ * MulticastResponder.cpp
+ *
+ * Created on: 12 Jul 2022
+ * Author: David
+ */
+
+#include "MulticastResponder.h"
+
+#if SUPPORT_MULTICAST_DISCOVERY
+
+#include <Platform/RepRap.h>
+#include <Platform/Platform.h>
+#include <Hardware/ExceptionHandlers.h>
+
+#include "fgmc_header.h"
+#include "fgmc_protocol.h"
+
+extern "C" {
+#include "LwipEthernet/Lwip/src/include/lwip/udp.h"
+#include "LwipEthernet/Lwip/src/include/lwip/igmp.h"
+extern struct netif gs_net_if;
+}
+
+static constexpr ip_addr_t ourGroup = IPADDR4_INIT_BYTES(239, 255, 2, 3);
+
+static udp_pcb *ourPcb = nullptr;
+static pbuf * volatile receivedPbuf = nullptr;
+static volatile uint32_t receivedIpAddr;
+static volatile uint16_t receivedPort;
+static uint16_t lastMessageReceivedPort;
+static unsigned int messagesProcessed = 0;
+static FGMCProtocol *fgmcHandler = nullptr;
+static uint32_t ticksToReboot = 0;
+static uint32_t whenRebootScheduled;
+
+static bool active = false;
+
+// Receive callback function
+extern "C" void rcvFunc(void *arg, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *addr, u16_t port) noexcept
+{
+ if (active && receivedPbuf == nullptr)
+ {
+ receivedIpAddr = addr->addr;
+ receivedPort = port;
+ receivedPbuf = p;
+ }
+ else
+ {
+ pbuf_free(p);
+ }
+}
+
+void MulticastResponder::Init() noexcept
+{
+ // Nothing needed here yet
+}
+
+// Do some work, returning true if we did anything significant
+void MulticastResponder::Spin() noexcept
+{
+ if (ticksToReboot != 0)
+ {
+ if (millis() - whenRebootScheduled > ticksToReboot)
+ {
+ reprap.EmergencyStop(); // this disables heaters and drives - Duet WiFi pre-production boards need drives disabled here
+ SoftwareReset(SoftwareResetReason::user); // doesn't return
+ }
+
+ }
+ else
+ {
+ pbuf *rxPbuf = receivedPbuf;
+ if (rxPbuf != nullptr)
+ {
+ lastMessageReceivedPort = receivedPort;
+#if 0
+ debugPrintf("Rx UDP: addr %u.%u.%u.%u port %u data",
+ (unsigned int)(receivedIpAddr & 0xFF), (unsigned int)((receivedIpAddr >> 8) & 0xFF), (unsigned int)((receivedIpAddr >> 16) & 0xFF), (unsigned int)((receivedIpAddr >> 24) & 0xFF), lastMessageReceivedPort);
+ for (size_t i = 0; i < rxPbuf->len; ++i)
+ {
+ debugPrintf(" %02x", ((const uint8_t*)(rxPbuf->payload))[i]);
+ }
+ debugPrintf("\n");
+#endif
+ receivedPbuf = nullptr;
+ fgmcHandler->handleStream(0, (uint8_t *)rxPbuf->payload, rxPbuf->len);
+ pbuf_free(rxPbuf);
+ ++messagesProcessed;
+ }
+ }
+}
+
+void MulticastResponder::Diagnostics(MessageType mtype) noexcept
+{
+ reprap.GetPlatform().MessageF(mtype, "=== Multicast handler ===\nResponder is %s, messages processed %u\n", (active) ? "active" : "inactive", messagesProcessed);
+}
+
+void MulticastResponder::Start(TcpPort port) noexcept
+{
+ if (fgmcHandler == nullptr)
+ {
+ fgmcHandler = new FGMCProtocol;
+ fgmcHandler->init();
+ }
+
+ if (ourPcb == nullptr)
+ {
+ ourPcb = udp_new_ip_type(IPADDR_TYPE_ANY);
+ if (ourPcb == nullptr)
+ {
+ reprap.GetPlatform().Message(ErrorMessage, "unable to allocate a pcb\n");
+ }
+ else
+ {
+ udp_set_multicast_ttl(ourPcb, 255);
+ if (igmp_joingroup_netif(&gs_net_if, ip_2_ip4(&ourGroup)) != ERR_OK) // without this call, multicast packets to this IP address get discarded
+ {
+ reprap.GetPlatform().Message(ErrorMessage, "igmp_joingroup failed\n");
+ }
+ else if (udp_bind(ourPcb, &ourGroup, port) != ERR_OK)
+ {
+ reprap.GetPlatform().Message(ErrorMessage, "udp_bind call failed\n");
+ }
+ else
+ {
+ udp_recv(ourPcb, rcvFunc, nullptr);
+ }
+ }
+ }
+ active = true;
+ messagesProcessed = 0;
+}
+
+void MulticastResponder::Stop() noexcept
+{
+ if (ourPcb != nullptr)
+ {
+ udp_remove(ourPcb);
+ ourPcb = nullptr;
+ }
+ active = false;
+}
+
+void MulticastResponder::SendResponse(uint8_t *data, size_t length) noexcept
+{
+#if 0
+ debugPrintf("Tx UDP: port %u data", lastMessageReceivedPort);
+ for (size_t i = 0; i < length; ++i)
+ {
+ debugPrintf(" %02x", data[i]);
+ }
+ debugPrintf("\n");
+#endif
+
+ pbuf * const pb = pbuf_alloc(PBUF_TRANSPORT, length, PBUF_RAM);
+#if 0
+ if (pbuf_take(pb, data, length) != ERR_OK)
+ {
+ debugPrintf("pbuf_take returned error\n");
+ }
+ if (udp_sendto_if(ourPcb, pb, &ourGroup, lastMessageReceivedPort, &gs_net_if) != ERR_OK)
+ {
+ debugPrintf("UDP send failed\n");
+ }
+#else
+ (void)pbuf_take(pb, data, length);
+ (void)udp_sendto_if(ourPcb, pb, &ourGroup, lastMessageReceivedPort, &gs_net_if);
+#endif
+}
+
+// Schedule a reboot. We delay a little while to allow the response to be transmitted first.
+void MulticastResponder::ScheduleReboot() noexcept
+{
+ whenRebootScheduled = millis();
+ ticksToReboot = 1000;
+}
+
+#endif
+
+// End
diff --git a/src/Networking/MulticastDiscovery/MulticastResponder.h b/src/Networking/MulticastDiscovery/MulticastResponder.h
new file mode 100644
index 00000000..173a0087
--- /dev/null
+++ b/src/Networking/MulticastDiscovery/MulticastResponder.h
@@ -0,0 +1,29 @@
+/*
+ * MulricastResponder.h
+ *
+ * Created on: 12 Jul 2022
+ * Author: David
+ */
+
+#ifndef SRC_NETWORKING_MULTICASTRESPONDER_H_
+#define SRC_NETWORKING_MULTICASTRESPONDER_H_
+
+#include <RepRapFirmware.h>
+#include <NetworkDefs.h>
+
+#if SUPPORT_MULTICAST_DISCOVERY
+
+namespace MulticastResponder
+{
+ void Init() noexcept;
+ void Spin() noexcept;
+ void Start(TcpPort port) noexcept;
+ void Stop() noexcept;
+ void SendResponse(uint8_t *data, size_t length) noexcept;
+ void ScheduleReboot() noexcept;
+ void Diagnostics(MessageType mtype) noexcept;
+}
+
+#endif
+
+#endif /* SRC_NETWORKING_MULTICASTRESPONDER_H_ */
diff --git a/src/Networking/MulticastDiscovery/Notes on multicast implementation.md b/src/Networking/MulticastDiscovery/Notes on multicast implementation.md
new file mode 100644
index 00000000..217754cc
--- /dev/null
+++ b/src/Networking/MulticastDiscovery/Notes on multicast implementation.md
@@ -0,0 +1,37 @@
+# Summary
+
+The protocol uses multicast IP address 239.255.2.3 and default port number 10002. As with other network protocols supported by RRF, the port number can be changed in the M586 command.
+
+# Availability
+
+The protocol is implemented only on the Ethernet interface of Duet 3 MB6HC and MB6XD boards. It is implemented in RRF 3.4.2 and later [to be confirmed].
+
+# Enabling and disabling the protocol
+
+The protocol is disabled in RRF by default. To enable the protocol, use this command:
+
+```M586 P3 S1```
+
+This command can be included in config.g if support for the protocol is always required. When this command is run, RAM will be allocated for the multicast protocol handler.
+
+To disable the protocol, use:
+
+```M586 P3 S0```
+
+Running this command does not release the RAM occupied by the protocol handler.
+
+# Implementing the DNETINF command
+
+The DNETINF command allows the IP address, netmask and gateway UP address to be changed as from the next reboot. If support for this command is required then the configuration files on the SD card must adhere to the following convention:
+
+- File sys/config.g must include the following lines:
+```
+M98 P"network-override.g"
+M552 S1
+```
+- After these commands there must not be any M550, M552, M553 or M554 commands
+- Optionally, create an initial file sys/network-override.g containing M550, M552, M553 and M554 commands to set default device name, IP address etc. In the absence of file network-override.g, DHCP will be used.
+
+When the DNETINF multicast command is received, file sys/network-override.g will be re-created with M550, M552, M553 and M554 commands to set the requested device name, IP address, netmask and gateway IP address.
+
+Note, if the DHCP flag is set in the DNETINF command then the received IP address, netmask and gateway address will be ignored and the IP address etc. will be set to zero instead. This is because RRF uses a zero IP address to indicate that DHCP should be used.
diff --git a/src/Networking/MulticastDiscovery/fgmc_header.h b/src/Networking/MulticastDiscovery/fgmc_header.h
new file mode 100644
index 00000000..348cb626
--- /dev/null
+++ b/src/Networking/MulticastDiscovery/fgmc_header.h
@@ -0,0 +1,173 @@
+// Multicast discovery protocol and associated constants
+
+#ifndef FGMC_HEADER_H
+#define FGMC_HEADER_H
+
+/// fgmc device id for platform family cmmt
+enum class FGMCHwTypeId : uint32_t { FGMC_DEVICE_ID_ZERO = 0, FGMC_DEVICE_ID_CMMT_AS = 23, FGMC_DEVICE_ID_CMMT_ST = 33, FGMC_DEVICE_ID_DUET3 = 41 };
+
+/// fgmc error codes
+enum class FGMCErrorCode : int16_t
+{
+ FGMC_ERROR_CODE_NORMAL = 0,
+ FGMC_ERROR_CODE_CMD_NOT_KNOWN = -1,
+ FGMC_ERROR_CODE_CMD_VERSION_NOT_SUPPORTED = -2,
+ FGMC_ERROR_CODE_CMD_FAILED = -3,
+ FGMC_ERROR_CODE_CMD_SEGMENT_INDEX_MISS = -4
+};
+
+/// fgmc commands
+enum class FGMCCommand : int32_t
+{
+ MCD_COMMAND_UNKNOWN = 0,
+ MCD_COMMAND_UNETINF = 1,
+ MCD_COMMAND_DNETINF = 2,
+ MCD_COMMAND_DNETINF_REBOOT = 3,
+ MCD_COMMAND_REBOOT = 4,
+ MCD_COMMAND_UPDATE_FIRMWARE = 5,
+ MCD_COMMAND_IDENTIFY = 6,
+ MCD_COMMAND_GET_VERSIONS = 7,
+ MCD_COMMAND_READFILE = 8,
+ MCD_COMMAND_GET_FIRMWARE_VERSION = 9,
+ MCD_COMMAND_GET_SUPPORTED_COMMANDS = 10
+};
+
+/// fgmc command version
+enum class FGMCCommandVersion : uint16_t { MCD_COMMAND_VERSION = 0 };
+
+//
+constexpr const char * INVALID_EEPROM_DATA_STRING = "invalid eeprom data";
+
+/// array size definitions
+constexpr const char *FGMC_NAME = "FESTOMULTICAST";
+constexpr size_t SIZE_FGMC_NAME = strlen(FGMC_NAME);
+constexpr size_t SIZE_FGMC_DEST_ID = 16;
+
+/// fgmc protocol header
+struct __attribute__((packed)) FGMC_GenericHeader
+{
+ char fgmc_name_[SIZE_FGMC_NAME];
+ uint32_t fgmc_length_;
+ FGMCHwTypeId fgmc_hw_type_id_;
+ char fgmc_destination_id_[SIZE_FGMC_DEST_ID];
+ uint32_t fgmc_packet_id_;
+ uint32_t fgmc_segment_index_;
+ uint32_t fgmc_segment_count_;
+ FGMCCommand fgmc_command_;
+ FGMCCommandVersion fgmc_command_version_;
+ FGMCErrorCode fgmc_error_code_;
+};
+
+/// array size definitions
+constexpr size_t SIZE_MAC_ADDRESS = 6;
+constexpr size_t SIZE_IP_V4 = 4;
+constexpr size_t SIZE_IP_V6 = 16;
+constexpr size_t SIZE_DEVICE_TYPE = 12;
+constexpr size_t SIZE_NOC_CODE = 64;
+constexpr size_t SIZE_SERIAL_NUMBER = 64;
+constexpr size_t SIZE_GENERIC_INFO = 12;
+constexpr size_t SIZE_DEVICE_NAME = 128;
+
+/// fgmc command response header upload network informations
+struct __attribute__((packed)) FGMC_ResUploadNetInfoHeader
+{
+ FGMC_GenericHeader fgmc_header_;
+ char fgmc_mac_address_[SIZE_MAC_ADDRESS];
+ uint32_t fgmc_ip_address_type_;
+ uint8_t fgmc_ip_v4_static_address_[SIZE_IP_V4];
+ uint8_t fgmc_ip_v4_static_netmask_[SIZE_IP_V4];
+ uint8_t fgmc_ip_v4_static_gateway_[SIZE_IP_V4];
+ uint8_t fgmc_ip_v4_static_dns_[SIZE_IP_V4];
+ uint8_t fgmc_ip_v6_static_6_addr_[SIZE_IP_V6];
+ uint8_t fgmc_ip_v6_static_netmask_[SIZE_IP_V6];
+ uint8_t fgmc_ip_v6_static_gateway_[SIZE_IP_V6];
+ uint8_t fgmc_ip_v6_static_dns_[SIZE_IP_V6];
+ uint8_t fgmc_ip_v4_address_[SIZE_IP_V4];
+ uint8_t fgmc_ip_v4_netmask_[SIZE_IP_V4];
+ uint8_t fgmc_ip_v4_gateway_[SIZE_IP_V4];
+ uint8_t fgmc_ip_v4_dns_[SIZE_IP_V4];
+ char fgmc_noc_code_[SIZE_NOC_CODE];
+ int32_t fgmc_ttl_;
+ uint8_t fgmc_connection_state_;
+ char fgmc_device_type_[SIZE_DEVICE_TYPE];
+ char fgmc_serial_number_[SIZE_SERIAL_NUMBER];
+ uint32_t fgmc_application_type_;
+ uint32_t fgmc_application_version_;
+ uint32_t fgmc_application_version_revision_;
+ uint8_t fgmc_generic_info_[SIZE_GENERIC_INFO];
+ char fgmc_device_name_[SIZE_DEVICE_NAME];
+};
+
+/// array size definitions
+constexpr size_t SIZE_PASSWORD = 12;
+
+/// fgmc command request header "download network informations"
+struct __attribute__((packed)) FGMC_ReqDownloadNetInfoHeader
+{
+ uint32_t fgmc_ip_address_type_;
+ uint8_t fgmc_ip_v4_static_address_[SIZE_IP_V4];
+ uint8_t fgmc_ip_v4_static_netmask_[SIZE_IP_V4];
+ uint8_t fgmc_ip_v4_static_gateway_[SIZE_IP_V4];
+ uint8_t fgmc_ip_v4_static_dns_[SIZE_IP_V4];
+ uint8_t fgmc_ip_v6_static_6_addr_[SIZE_IP_V6];
+ uint8_t fgmc_ip_v6_static_netmask_[SIZE_IP_V6];
+ uint8_t fgmc_ip_v6_static_gateway_[SIZE_IP_V6];
+ uint8_t fgmc_ip_v6_static_dns_[SIZE_IP_V6];
+ int32_t fgmc_ttl_;
+ char fgmc_device_name_[SIZE_DEVICE_NAME];
+ char fgmc_password_[SIZE_PASSWORD];
+};
+
+/// fgmc command response header "download network informations"
+struct __attribute__((packed)) FGMC_ResDownloadNetInfoHeader
+{
+ FGMC_GenericHeader fgmc_header_;
+};
+
+/// array size definitions
+constexpr uint32_t IDENTIFY_DEFAULT = 0;
+constexpr uint32_t IDENTIFY_ON = 1;
+constexpr uint32_t IDENTIFY_OFF = 2;
+
+/// fgmc command request header "identify"
+struct __attribute__((packed)) FGMC_ReqIdentify
+{
+ int32_t identification_type_;
+ int32_t reserved_;
+};
+
+/// fgmc command response header "identify"
+struct __attribute__((packed)) FGMC_ResIdentify
+{
+ FGMC_GenericHeader fgmc_header_;
+};
+
+/// array size definitions
+constexpr size_t SIZE_MODULE_NAME = 192;
+constexpr size_t SIZE_MODULE_VERSION = 64;
+
+/// fgmc command response header "get firmware version"
+struct __attribute__((packed)) FGMC_ResGetFwVersion
+{
+ FGMC_GenericHeader fgmc_header_;
+ char module_name_[SIZE_MODULE_NAME];
+ char module_version_[SIZE_MODULE_VERSION];
+};
+
+/// fgmc command response header "get supported commands"
+struct __attribute__((packed)) FGMC_ResGetSupportedCommands
+{
+ FGMC_GenericHeader fgmc_header_;
+ uint32_t cmd_;
+ uint16_t cmd_version_;
+};
+
+constexpr size_t SIZE_FGMC_RES_MAX = 461; // 461 Bytes for FGMC_ResUploadNetInfoHeader
+
+static_assert(SIZE_FGMC_RES_MAX >= sizeof(FGMC_ResIdentify));
+static_assert(SIZE_FGMC_RES_MAX >= sizeof(FGMC_ResUploadNetInfoHeader));
+static_assert(SIZE_FGMC_RES_MAX >= sizeof(FGMC_ResDownloadNetInfoHeader));
+static_assert(SIZE_FGMC_RES_MAX >= sizeof(FGMC_ResGetFwVersion));
+static_assert(SIZE_FGMC_RES_MAX >= sizeof(FGMC_ResGetSupportedCommands));
+
+#endif // #ifndef FGMC_HEADER_H
diff --git a/src/Networking/MulticastDiscovery/fgmc_protocol.cpp b/src/Networking/MulticastDiscovery/fgmc_protocol.cpp
new file mode 100644
index 00000000..34d8e397
--- /dev/null
+++ b/src/Networking/MulticastDiscovery/fgmc_protocol.cpp
@@ -0,0 +1,497 @@
+// Implementation of MulticastDiscovery protocol
+
+#include "fgmc_protocol.h"
+
+#if SUPPORT_MULTICAST_DISCOVERY
+
+#include <Platform/RepRap.h>
+#include <Platform/Platform.h>
+#include <Networking/Network.h>
+#include <Networking/MulticastDiscovery/MulticastResponder.h>
+#include <CAN/CanInterface.h>
+#include <Version.h>
+#include <cstring>
+
+constexpr const char *NetworkConfigOverrideFileName = "network-override.g";
+
+// Disable gcc warning about strncpy not being able to include a terminating null.
+// We don't need a terminating null when filling in response fields (if we did then we would use SafeStrcpy instead).
+#pragma GCC diagnostic ignored "-Wstringop-truncation"
+
+FGMCProtocol::FGMCProtocol() noexcept
+ : iface_id_(0),
+ fgmc_device_id_(FGMCHwTypeId::FGMC_DEVICE_ID_ZERO),
+ fgmc_application_type_(0),
+ tx_netbuf_{0}
+{
+}
+
+// Build a unique ID from the MAC address
+void FGMCProtocol::macToString(uint32_t interface) noexcept
+{
+ InterfaceData& ifData = ifaceData[interface];
+
+ for (uint32_t i = 0; i < SIZE_FGMC_DEST_ID; i++)
+ {
+ ifData.unique_id_[i] = '\0';
+ }
+
+ const MacAddress& macAddress = reprap.GetNetwork().GetMacAddress(interface);
+ for (uint32_t i = 0; i < 6; i++)
+ {
+ const uint8_t byte = macAddress.bytes[i];
+ uint8_t lowValue = (byte & 0x0Fu);
+ if (lowValue < 0xA)
+ {
+ lowValue = lowValue + 48;
+ }
+ else
+ {
+ lowValue = lowValue + 55;
+ }
+
+ uint8_t highValue = (byte >> 4u) & 0x0Fu;
+ if (highValue < 0xA)
+ {
+ highValue = highValue + 48;
+ }
+ else
+ {
+ highValue = highValue + 55;
+ }
+ ifData.unique_id_[i * 2] = static_cast<char>(lowValue);
+ ifData.unique_id_[(i * 2) + 1] = static_cast<char>(highValue);
+ }
+}
+
+void FGMCProtocol::init() noexcept
+{
+#if 0
+
+ // check eeprom values available
+ if ((eeprom_noc_code_[0] == '\0')) { // || (eeprom_product_key_[0] == '\0')
+ // EEPROMs not described
+ eeprom_product_key_[0] = '1';
+ eeprom_product_key_[1] = '\0';
+ (void)memcpy(&eeprom_noc_code_[0], &INVALID_EEPROM_DATA_STRING, INVALID_EEPROM_DATA_STRING_LEN);
+ (void)memcpy(&deviceName[0], &INVALID_EEPROM_DATA_STRING, INVALID_EEPROM_DATA_STRING_LEN);
+ }
+
+#endif
+
+ for (uint32_t i = 0; i < IP_MAX_IFACES; i++)
+ {
+ macToString(i);
+ ifaceData[i].configuredIpAddress = reprap.GetNetwork().GetIPAddress(i);
+ ifaceData[i].configuredNetmask = reprap.GetNetwork().GetNetmask(i);
+ ifaceData[i].configuredGateway = reprap.GetNetwork().GetGateway(i);
+ }
+
+ fgmc_device_id_ = FGMCHwTypeId::FGMC_DEVICE_ID_DUET3;
+}
+
+void FGMCProtocol::handleStream(unsigned int iFaceId, uint8_t* inputBufferAddress, uint32_t rxLength) noexcept
+{
+ // backup sciopta connection handle
+ // if a null pointer received => plattform should execute a exception
+ this->iface_id_ = iFaceId;
+
+ if (rxLength >= static_cast<uint32_t>(sizeof(FGMC_GenericHeader)))
+ {
+ FGMC_GenericHeader* const pInGenericHeader = reinterpret_cast<FGMC_GenericHeader*>(inputBufferAddress);
+
+ // read incoming packetid
+ const uint32_t packetId = pInGenericHeader->fgmc_packet_id_;
+ InterfaceData& ifData = ifaceData[iface_id_];
+ if (!ifData.insertPacketId(packetId))
+ {
+ return;
+ }
+
+ switch (pInGenericHeader->fgmc_command_)
+ {
+ case FGMCCommand::MCD_COMMAND_UNETINF:
+ if (pInGenericHeader->fgmc_destination_id_[0] == '\0')
+ {
+ // fgmc command: upload network information
+ cmdUnetinf(packetId);
+ }
+ break;
+
+ case FGMCCommand::MCD_COMMAND_DNETINF:
+ if (strncmp(pInGenericHeader->fgmc_destination_id_, ifData.unique_id_, SIZE_FGMC_DEST_ID) == 0)
+ {
+ // fgmc command: download network information
+ FGMC_ReqDownloadNetInfoHeader* const pInCmdPointer =
+ reinterpret_cast<FGMC_ReqDownloadNetInfoHeader*>(reinterpret_cast<uint32_t>(inputBufferAddress) + static_cast<uint32_t>(sizeof(FGMC_GenericHeader)));
+ cmdDnetinf(pInCmdPointer, packetId);
+ }
+ break;
+
+ case FGMCCommand::MCD_COMMAND_REBOOT:
+ if (strncmp(pInGenericHeader->fgmc_destination_id_, ifData.unique_id_, SIZE_FGMC_DEST_ID) == 0)
+ {
+ // fgmc command: reboot
+ cmdReboot(packetId);
+ }
+ break;
+
+ case FGMCCommand::MCD_COMMAND_IDENTIFY:
+ if (strncmp(pInGenericHeader->fgmc_destination_id_, ifData.unique_id_, SIZE_FGMC_DEST_ID) == 0)
+ {
+ // fgmc command: identify
+ FGMC_ReqIdentify* pInCmdPointer =
+ reinterpret_cast<FGMC_ReqIdentify*>(reinterpret_cast<uint32_t>(inputBufferAddress) + static_cast<uint32_t>(sizeof(FGMC_GenericHeader)));
+ cmdIdentify(pInCmdPointer, packetId);
+ }
+ break;
+
+ case FGMCCommand::MCD_COMMAND_GET_FIRMWARE_VERSION:
+ if (strncmp(pInGenericHeader->fgmc_destination_id_, ifData.unique_id_, SIZE_FGMC_DEST_ID) == 0)
+ {
+ // fgmc command: get firmware version
+ cmdGetFirmwareVersion(packetId);
+ }
+ break;
+
+ case FGMCCommand::MCD_COMMAND_GET_SUPPORTED_COMMANDS:
+ if (strncmp(pInGenericHeader->fgmc_destination_id_, ifData.unique_id_, SIZE_FGMC_DEST_ID) == 0)
+ {
+ // fgmc command: get supported commands
+ cmdGetSupportedCommands(packetId);
+ }
+ break;
+
+ default:
+ // unknown command will be skipped
+ break;
+ }
+ }
+}
+
+void FGMCProtocol::sendGenericHeader(uint8_t* tx_netbuf, FGMCCommand cmd, uint32_t length, uint32_t packetId, uint32_t segmentIndex, uint32_t segmentCount) noexcept
+{
+ FGMC_GenericHeader* pOutGenericHeader = reinterpret_cast<FGMC_GenericHeader*>(tx_netbuf);
+
+ //-----------------------------------------------------------------------------------
+ // Generic Multicast Header
+ //-----------------------------------------------------------------------------------
+ memcpy(pOutGenericHeader->fgmc_name_, FGMC_NAME, SIZE_FGMC_NAME);
+ pOutGenericHeader->fgmc_length_ = length;
+ pOutGenericHeader->fgmc_hw_type_id_ = fgmc_device_id_;
+ // device unique fgmc destination id
+ strncpy(pOutGenericHeader->fgmc_destination_id_, ifaceData[iface_id_].unique_id_, SIZE_FGMC_DEST_ID);
+ pOutGenericHeader->fgmc_packet_id_ = packetId + 1;
+ pOutGenericHeader->fgmc_segment_index_ = segmentIndex;
+ pOutGenericHeader->fgmc_segment_count_ = segmentCount;
+ pOutGenericHeader->fgmc_command_ = cmd;
+ pOutGenericHeader->fgmc_command_version_ = FGMCCommandVersion::MCD_COMMAND_VERSION;
+ pOutGenericHeader->fgmc_error_code_ = FGMCErrorCode::FGMC_ERROR_CODE_NORMAL;
+
+ // Send Message
+ (void)ifaceData[iface_id_].insertPacketId(pOutGenericHeader->fgmc_packet_id_);
+
+ MulticastResponder::SendResponse(tx_netbuf, length);
+}
+
+void FGMCProtocol::cmdUnetinf(uint32_t inPacketId) noexcept
+{
+ FGMC_ResUploadNetInfoHeader* pOutCmdHeader = reinterpret_cast<FGMC_ResUploadNetInfoHeader*>(tx_netbuf_);
+ (void)memset(pOutCmdHeader, 0x00, sizeof(FGMC_ResUploadNetInfoHeader));
+
+ //-----------------------------------------------------------------------------------
+ // The Upload Netinformation Structure
+ //-----------------------------------------------------------------------------------
+
+ // ip address type
+ const bool dhcpEnable = reprap.GetNetwork().UsingDhcp(iface_id_);
+ if (dhcpEnable)
+ {
+ // dynamic
+ pOutCmdHeader->fgmc_ip_address_type_ = 1;
+ }
+ else
+ {
+ // static
+ pOutCmdHeader->fgmc_ip_address_type_ = 0;
+ }
+
+ // mac address
+ const MacAddress& macAddress = reprap.GetNetwork().GetMacAddress(iface_id_);
+ memcpy(pOutCmdHeader->fgmc_mac_address_, macAddress.bytes, 6);
+
+ // IPv4
+ const InterfaceData& ifData = ifaceData[iface_id_];
+ const uint32_t ipaddress = ifData.configuredIpAddress.GetV4LittleEndian();
+ (void)memcpy(&pOutCmdHeader->fgmc_ip_v4_static_address_[0], &ipaddress, SIZE_IP_V4);
+
+ const uint32_t subnetmask = ifData.configuredNetmask.GetV4LittleEndian();
+ (void)memcpy(&pOutCmdHeader->fgmc_ip_v4_static_netmask_[0], &subnetmask, SIZE_IP_V4);
+
+ const uint32_t gateway = ifData.configuredGateway.GetV4LittleEndian();
+ (void)memcpy(&pOutCmdHeader->fgmc_ip_v4_static_gateway_[0], &gateway, SIZE_IP_V4);
+
+ pOutCmdHeader->fgmc_ip_v4_static_dns_[0] = 0;
+ pOutCmdHeader->fgmc_ip_v4_static_dns_[1] = 0;
+ pOutCmdHeader->fgmc_ip_v4_static_dns_[2] = 0;
+ pOutCmdHeader->fgmc_ip_v4_static_dns_[3] = 0;
+
+ // IPv6
+ (void)memset(&pOutCmdHeader->fgmc_ip_v6_static_6_addr_[0], 0x00, SIZE_IP_V6);
+ (void)memset(&pOutCmdHeader->fgmc_ip_v6_static_netmask_[0], 0x00, SIZE_IP_V6);
+ (void)memset(&pOutCmdHeader->fgmc_ip_v6_static_gateway_[0], 0x00, SIZE_IP_V6);
+ (void)memset(&pOutCmdHeader->fgmc_ip_v6_static_dns_[0], 0x00, SIZE_IP_V6);
+
+ // IPv4 active
+ const uint32_t ipaddressActive = reprap.GetNetwork().GetIPAddress(iface_id_).GetV4LittleEndian();
+ (void)memcpy(&pOutCmdHeader->fgmc_ip_v4_address_[0], &ipaddressActive, SIZE_IP_V4);
+
+ const uint32_t subnetmaskActive = reprap.GetNetwork().GetNetmask(iface_id_).GetV4LittleEndian();
+ (void)memcpy(&pOutCmdHeader->fgmc_ip_v4_netmask_[0], &subnetmaskActive, SIZE_IP_V4);
+
+ const uint32_t gatewayActive = reprap.GetNetwork().GetGateway(iface_id_).GetV4LittleEndian();
+ (void)memcpy(&pOutCmdHeader->fgmc_ip_v4_gateway_[0], &gatewayActive, SIZE_IP_V4);
+
+ pOutCmdHeader->fgmc_ip_v4_dns_[0] = 0;
+ pOutCmdHeader->fgmc_ip_v4_dns_[1] = 0;
+ pOutCmdHeader->fgmc_ip_v4_dns_[2] = 0;
+ pOutCmdHeader->fgmc_ip_v4_dns_[3] = 0;
+
+ // NOC-CODE
+ (void)strncpy(pOutCmdHeader->fgmc_noc_code_, INVALID_EEPROM_DATA_STRING, SIZE_EEPROM_NOC_CODE);
+
+ // iTTL
+ pOutCmdHeader->fgmc_ttl_ = 255;
+
+ // Connection State
+ pOutCmdHeader->fgmc_connection_state_ = 0;
+
+ // Device Type
+ (void)strncpy(pOutCmdHeader->fgmc_device_type_, BOARD_NAME, SIZE_DEVICE_TYPE);
+
+ // Device Serial Number
+ memset(pOutCmdHeader->fgmc_serial_number_, 0, sizeof(pOutCmdHeader->fgmc_serial_number_));
+
+ // Application Type
+ pOutCmdHeader->fgmc_application_type_ = fgmc_application_type_;
+
+ // Application Version
+ pOutCmdHeader->fgmc_application_version_ = 0;
+
+ // Application Version Revision
+ pOutCmdHeader->fgmc_application_version_revision_ = 0;
+
+ // Generic Info
+ (void)memset(pOutCmdHeader->fgmc_generic_info_, 0x00, SIZE_GENERIC_INFO);
+
+ // Device Name
+ strncpy(pOutCmdHeader->fgmc_device_name_, reprap.GetName(), ARRAY_SIZE(pOutCmdHeader->fgmc_device_name_));
+
+ //-----------------------------------------------------------------------------------
+ // Generic Multicast Header
+ //-----------------------------------------------------------------------------------
+ sendGenericHeader(tx_netbuf_, FGMCCommand::MCD_COMMAND_UNETINF, sizeof(FGMC_ResUploadNetInfoHeader), inPacketId, 0, 1);
+}
+
+void FGMCProtocol::cmdDnetinf(FGMC_ReqDownloadNetInfoHeader* pInCmdHeader, uint32_t inPacketId) noexcept
+{
+ FGMC_ResDownloadNetInfoHeader* pOutCmdHeader = reinterpret_cast<FGMC_ResDownloadNetInfoHeader*>(tx_netbuf_);
+ (void)memset(pOutCmdHeader, 0x00, sizeof(FGMC_ResDownloadNetInfoHeader));
+
+ //-----------------------------------------------------------------------------------
+ // The Download Netinformation Structure
+ //-----------------------------------------------------------------------------------
+
+ // set new network settings
+ InterfaceData& ifData = ifaceData[iface_id_];
+ const bool dhcpEnable = static_cast<bool>(pInCmdHeader->fgmc_ip_address_type_);
+ if (dhcpEnable)
+ {
+ ifData.configuredIpAddress.SetNull();
+ }
+ else
+ {
+ ifData.configuredIpAddress.SetV4LittleEndian(LoadLE32(pInCmdHeader->fgmc_ip_v4_static_address_));
+ }
+
+ ifData.configuredNetmask.SetV4LittleEndian(LoadLE32(pInCmdHeader->fgmc_ip_v4_static_netmask_));
+ ifData.configuredGateway.SetV4LittleEndian(LoadLE32(pInCmdHeader->fgmc_ip_v4_static_gateway_));
+
+ // set new device name
+ // filter out " (X19) / (X18)
+ for (uint32_t i = 0; i < SIZE_DEVICE_NAME; i++)
+ {
+ if (pInCmdHeader->fgmc_device_name_[i] == '\0')
+ {
+ if (i > 6)
+ {
+ if ((pInCmdHeader->fgmc_device_name_[i - 6] == ' ') && (pInCmdHeader->fgmc_device_name_[i - 5] == '(') &&
+ (pInCmdHeader->fgmc_device_name_[i - 4] == 'X') && (pInCmdHeader->fgmc_device_name_[i - 3] == '1') &&
+ (pInCmdHeader->fgmc_device_name_[i - 1] == ')'))
+ {
+ for (uint32_t j = 1; j <= 6; j++)
+ {
+ pInCmdHeader->fgmc_device_name_[i - j] = '\0';
+ }
+ }
+ }
+ break;
+ }
+ }
+
+ // Create a new network-override.g file
+ FileStore *const fs = reprap.GetPlatform().OpenSysFile(NetworkConfigOverrideFileName, OpenMode::write);
+ if (fs == nullptr)
+ {
+ reprap.GetPlatform().MessageF(ErrorMessage, "Unable to create file %s\n", NetworkConfigOverrideFileName);
+ }
+ else
+ {
+ String<StringLength256> buf;
+ buf.printf( "M550 P\"%s\"\n"
+ "M552 P%u.%u.%u.%u\n"
+ "M553 P%u.%u.%u.%u\n"
+ "M554 P%u.%u.%u.%u\n",
+ pInCmdHeader->fgmc_device_name_,
+ ifData.configuredIpAddress.GetQuad(0), ifData.configuredIpAddress.GetQuad(1), ifData.configuredIpAddress.GetQuad(2), ifData.configuredIpAddress.GetQuad(3),
+ ifData.configuredNetmask.GetQuad(0), ifData.configuredNetmask.GetQuad(1), ifData.configuredNetmask.GetQuad(2), ifData.configuredNetmask.GetQuad(3),
+ ifData.configuredGateway.GetQuad(0), ifData.configuredGateway.GetQuad(1), ifData.configuredGateway.GetQuad(2), ifData.configuredGateway.GetQuad(3)
+ );
+
+ if (!fs->Write(buf.c_str()))
+ {
+ reprap.GetPlatform().MessageF(ErrorMessage, "Unable to write file %s\n", NetworkConfigOverrideFileName);
+ }
+ if (!fs->Close())
+ {
+ reprap.GetPlatform().MessageF(ErrorMessage, "Unable to close file %s\n", NetworkConfigOverrideFileName);
+ }
+ }
+
+ //-----------------------------------------------------------------------------------
+ // Generic Multicast Header
+ //-----------------------------------------------------------------------------------
+ sendGenericHeader(tx_netbuf_, FGMCCommand::MCD_COMMAND_DNETINF, sizeof(FGMC_ResDownloadNetInfoHeader), inPacketId, 0, 1);
+}
+
+void FGMCProtocol::cmdReboot(uint32_t inPacketId) noexcept
+{
+ (void)memset(tx_netbuf_, 0x00, sizeof(FGMC_GenericHeader));
+
+ //-----------------------------------------------------------------------------------
+ // Generic Multicast Header
+ //-----------------------------------------------------------------------------------
+ sendGenericHeader(tx_netbuf_, FGMCCommand::MCD_COMMAND_REBOOT, sizeof(FGMC_GenericHeader), inPacketId, 0, 1);
+ MulticastResponder::ScheduleReboot();
+}
+
+void FGMCProtocol::cmdIdentify(FGMC_ReqIdentify* pInCmdHeader, uint32_t inPacketId) noexcept
+{
+ FGMC_ResIdentify* pOutCmdHeader = reinterpret_cast<FGMC_ResIdentify*>(tx_netbuf_);
+ (void)memset(pOutCmdHeader, 0x00, sizeof(FGMC_ResIdentify));
+
+ switch (pInCmdHeader->identification_type_)
+ {
+ case IDENTIFY_DEFAULT:
+ CanInterface::SetStatusLedIdentify(30); // identify for about 30 seconds
+ break;
+
+ case IDENTIFY_ON:
+ CanInterface::SetStatusLedIdentify(0); // identify until cancelled
+ break;
+
+ case IDENTIFY_OFF:
+ default:
+ CanInterface::SetStatusLedNormal(); // cancel identify
+ break;
+ }
+
+ //-----------------------------------------------------------------------------------
+ // Generic Multicast Header
+ //-----------------------------------------------------------------------------------
+ sendGenericHeader(tx_netbuf_, FGMCCommand::MCD_COMMAND_IDENTIFY, sizeof(FGMC_ResIdentify), inPacketId, 0, 1);
+}
+
+void FGMCProtocol::cmdGetFirmwareVersion(uint32_t inPacketId) noexcept
+{
+ FGMC_ResGetFwVersion* pOutCmdHeader = reinterpret_cast<FGMC_ResGetFwVersion*>(tx_netbuf_);
+ (void)memset(pOutCmdHeader, 0x00, sizeof(FGMC_ResGetFwVersion));
+
+ //-----------------------------------------------------------------------------------
+ // Get Firmware Version
+ //-----------------------------------------------------------------------------------
+ (void)strncpy(pOutCmdHeader->module_name_, BOARD_NAME, SIZE_DEVICE_TYPE);
+
+ SafeSnprintf(pOutCmdHeader->module_version_, SIZE_MODULE_VERSION, "%s version %s", FIRMWARE_NAME, VERSION);
+
+ //-----------------------------------------------------------------------------------
+ // Generic Multicast Header
+ //-----------------------------------------------------------------------------------
+ sendGenericHeader(tx_netbuf_, FGMCCommand::MCD_COMMAND_GET_FIRMWARE_VERSION, sizeof(FGMC_ResGetFwVersion), inPacketId, 0, 1);
+}
+
+void FGMCProtocol::cmdGetSupportedCommands(uint32_t inPacketId) noexcept
+{
+ uint32_t segmentIndex = 0;
+ uint32_t segmentCount = 0;
+
+ FGMCCommand supportedCommands[] =
+ {
+ FGMCCommand::MCD_COMMAND_UNETINF,
+ FGMCCommand::MCD_COMMAND_DNETINF,
+ FGMCCommand::MCD_COMMAND_REBOOT,
+ FGMCCommand::MCD_COMMAND_IDENTIFY,
+ FGMCCommand::MCD_COMMAND_GET_FIRMWARE_VERSION,
+ FGMCCommand::MCD_COMMAND_GET_SUPPORTED_COMMANDS,
+ };
+
+ for (uint8_t i = 0; i < ARRAY_SIZE(supportedCommands); i++)
+ {
+ FGMC_ResGetSupportedCommands* pOutCmdHeader = reinterpret_cast<FGMC_ResGetSupportedCommands*>(tx_netbuf_);
+ (void)memset(pOutCmdHeader, 0x00, sizeof(FGMC_ResGetSupportedCommands));
+
+ //-----------------------------------------------------------------------------------
+ // Get Supported Commands
+ //-----------------------------------------------------------------------------------
+ pOutCmdHeader->cmd_ = static_cast<uint32_t>(supportedCommands[i]);
+ pOutCmdHeader->cmd_version_ = 0;
+
+ //-----------------------------------------------------------------------------------
+ // Generic Multicast Header
+ //-----------------------------------------------------------------------------------
+ segmentIndex = static_cast<uint32_t>(i);
+ segmentCount = static_cast<uint32_t>(ARRAY_SIZE(supportedCommands));
+ sendGenericHeader(tx_netbuf_, FGMCCommand::MCD_COMMAND_GET_SUPPORTED_COMMANDS, sizeof(FGMC_ResGetSupportedCommands), inPacketId, segmentIndex, segmentCount);
+ }
+}
+
+FGMCProtocol::InterfaceData::InterfaceData() noexcept
+ : unique_id_{0},
+ packetIdBuffer{0},
+ packetIdIndex(0)
+{
+}
+
+// Insert packet ID into buffer, returning true if success, false if it was already there,
+bool FGMCProtocol::InterfaceData::insertPacketId(uint32_t packetId) noexcept
+{
+ for (uint32_t i = 0; i < InterfaceData::ringBufferSize; i++)
+ {
+ if (packetId == packetIdBuffer[i])
+ {
+ return false;
+ }
+ }
+
+ packetIdBuffer[packetIdIndex] = packetId;
+ packetIdIndex++;
+ if (packetIdIndex >= InterfaceData::ringBufferSize)
+ {
+ packetIdIndex = 0;
+ }
+ return true;
+}
+
+#endif
+
+// End
diff --git a/src/Networking/MulticastDiscovery/fgmc_protocol.h b/src/Networking/MulticastDiscovery/fgmc_protocol.h
new file mode 100644
index 00000000..0a3faece
--- /dev/null
+++ b/src/Networking/MulticastDiscovery/fgmc_protocol.h
@@ -0,0 +1,114 @@
+// FGMC protocol handler
+
+#ifndef FGMC_PROTOCOL_H
+#define FGMC_PROTOCOL_H
+
+#include <RepRapFirmware.h>
+#include <General/IPAddress.h>
+
+#if SUPPORT_MULTICAST_DISCOVERY
+
+#include "fgmc_header.h"
+
+/// array size definitions
+#define SIZE_EEPROM_MAC_ADDRESS 6
+#define SIZE_EEPROM_PRODUCT_KEY 15
+#define SIZE_EEPROM_SERIAL_NUMBER 5
+#define SIZE_EEPROM_TEST_NUMBER 9
+#define SIZE_EEPROM_NOC_CODE 50
+
+/// fgmc port
+//#define FGMC_PORT 10002
+//#define FGMC_IP IP_BYTES2ADDR(239, 255, 2, 3) // Broadcast-IP
+
+constexpr size_t IP_MAX_IFACES = 1;
+
+class FGMCProtocol
+{
+public:
+ /// constructor
+ FGMCProtocol() noexcept;
+
+ /// this function initializes fgmc protocoll class
+ void init() noexcept;
+
+ /// this handles a fgmc frame
+ /// \param nConn connection
+ /// \param inputBufferAddress fgmc request frame
+ /// \param rxLength receive frame length
+ void handleStream(unsigned int iFaceId, uint8_t* inputBufferAddress, uint32_t rxLength) noexcept;
+
+private:
+ /// this functions sends fgmc frame
+ /// \param pOutPointer sciopta network buffer
+ /// \param cmd cmd
+ /// \param length length
+ /// \param packetId packedId
+ /// \param segmentIndex segmentIndex
+ /// \param segmentCount segmentCount
+ void sendGenericHeader(uint8_t* tx_netbuf, FGMCCommand cmd, uint32_t length, uint32_t packetId, uint32_t segmentIndex, uint32_t segmentCount) noexcept;
+
+ /// fgmc command "upload network informations"
+ /// \param inPacketId packedId
+ void cmdUnetinf(uint32_t inPacketId) noexcept;
+
+ /// fgmc command "download network information"
+ /// \param pInCmdHeader request header network information header
+ /// \param inPacketId packedId
+ void cmdDnetinf(FGMC_ReqDownloadNetInfoHeader* pInCmdHeader, uint32_t inPacketId) noexcept;
+
+ /// fgmc command "reboot"
+ /// \param inPacketId packedId
+ void cmdReboot(uint32_t inPacketId) noexcept;
+
+ /// fgmc command "identify"
+ /// \param pInCmdHeader request header identify
+ /// \param inPacketId packedId
+ void cmdIdentify(FGMC_ReqIdentify* pInCmdHeader, uint32_t inPacketId) noexcept;
+
+ /// fgmc command "get firmware version"
+ /// \param inPacketId packedId
+ void cmdGetFirmwareVersion(uint32_t inPacketId) noexcept;
+
+ /// fgmc command "get supported commands"
+ /// \param inPacketId packedId
+ void cmdGetSupportedCommands(uint32_t inPacketId) noexcept;
+
+ void macToString(uint32_t interface) noexcept;
+
+ // connection data pointer
+ unsigned int iface_id_;
+
+ // product key from eeprom
+// char eeprom_product_key_[SIZE_EEPROM_PRODUCT_KEY];
+// char eeprom_noc_code_[SIZE_EEPROM_NOC_CODE];
+
+ // variables will be initialized at init phase
+ FGMCHwTypeId fgmc_device_id_;
+ uint32_t fgmc_application_type_;
+
+ // struct to hold per-interface data
+ struct InterfaceData
+ {
+ char unique_id_[SIZE_FGMC_DEST_ID];
+ IPAddress configuredIpAddress, configuredNetmask, configuredGateway;
+ static constexpr uint32_t ringBufferSize = 10;
+ uint32_t packetIdBuffer[ringBufferSize];
+ uint32_t packetIdIndex;
+
+ InterfaceData() noexcept;
+
+ /// insert used packet-id
+ /// \param packetId packedId
+ /// \return true if inserted, false if it was already used
+ bool insertPacketId(uint32_t packetId) noexcept;
+ };
+
+
+ InterfaceData ifaceData[IP_MAX_IFACES];
+ uint8_t tx_netbuf_[SIZE_FGMC_RES_MAX];
+};
+
+#endif // SUPPORT_MULTICAST_DISCOVERY
+
+#endif // FGMC_PROTOCOL_H
diff --git a/src/Networking/Network.cpp b/src/Networking/Network.cpp
index f80f18bf..c8fd283a 100644
--- a/src/Networking/Network.cpp
+++ b/src/Networking/Network.cpp
@@ -21,29 +21,32 @@
#include "NetworkInterface.h"
#if HAS_LWIP_NETWORKING
-#include "LwipEthernet/LwipEthernetInterface.h"
+# include "LwipEthernet/LwipEthernetInterface.h"
#endif
#if HAS_W5500_NETWORKING
-#include "W5500Ethernet/W5500Interface.h"
+# include "W5500Ethernet/W5500Interface.h"
#endif
#if HAS_WIFI_NETWORKING
-#include "ESP8266WiFi/WiFiInterface.h"
+# include "ESP8266WiFi/WiFiInterface.h"
#endif
#if HAS_RTOSPLUSTCP_NETWORKING
-#include "RTOSPlusTCPEthernet/RTOSPlusTCPEthernetInterface.h"
+# include "RTOSPlusTCPEthernet/RTOSPlusTCPEthernetInterface.h"
#endif
#if SUPPORT_HTTP
-#include "HttpResponder.h"
+# include "HttpResponder.h"
#endif
#if SUPPORT_FTP
-#include "FtpResponder.h"
+# include "FtpResponder.h"
#endif
#if SUPPORT_TELNET
-#include "TelnetResponder.h"
+# include "TelnetResponder.h"
+#endif
+#if SUPPORT_MULTICAST_DISCOVERY
+# include "MulticastDiscovery/MulticastResponder.h"
#endif
#ifdef __LPC17xx__
@@ -250,6 +253,11 @@ GCodeResult Network::DisableProtocol(unsigned int interface, NetworkProtocol pro
break;
#endif
+#if SUPPORT_MULTICAST_DISCOVERY
+ case MulticastDiscoveryProtocol:
+ break;
+#endif
+
default:
break;
}
@@ -435,6 +443,10 @@ void Network::Activate() noexcept
}
# endif
+#if SUPPORT_MULTICAST_DISCOVERY
+ MulticastResponder::Init();
+#endif
+
// Finally, create the network task
networkTask.Create(NetworkLoop, "NETWORK", nullptr, TaskPriority::SpinPriority);
#endif
@@ -519,6 +531,9 @@ void Network::Spin() noexcept
if (nr == nullptr)
{
nr = responders; // 'responders' can't be null at this point
+#if SUPPORT_MULTICAST_DISCOVERY
+ MulticastResponder::Spin();
+#endif
}
doneSomething = nr->Spin();
nr = nr->GetNext();
@@ -572,6 +587,10 @@ void Network::Diagnostics(MessageType mtype) noexcept
iface->Diagnostics(mtype);
}
#endif
+
+#if SUPPORT_MULTICAST_DISCOVERY
+ MulticastResponder::Diagnostics(mtype);
+#endif
}
int Network::EnableState(unsigned int interface) const noexcept
@@ -607,6 +626,33 @@ IPAddress Network::GetIPAddress(unsigned int interface) const noexcept
IPAddress();
}
+IPAddress Network::GetNetmask(unsigned int interface) const noexcept
+{
+ return
+#if HAS_NETWORKING
+ (interface < NumNetworkInterfaces) ? interfaces[interface]->GetNetmask() :
+#endif
+ IPAddress();
+}
+
+IPAddress Network::GetGateway(unsigned int interface) const noexcept
+{
+ return
+#if HAS_NETWORKING
+ (interface < NumNetworkInterfaces) ? interfaces[interface]->GetGateway() :
+#endif
+ IPAddress();
+}
+
+bool Network::UsingDhcp(unsigned int interface) const noexcept
+{
+#if HAS_NETWORKING
+ return interface < NumNetworkInterfaces && interfaces[interface]->UsingDhcp();
+#else
+ return false;
+#endif
+}
+
void Network::SetHostname(const char *name) noexcept
{
#if HAS_NETWORKING
diff --git a/src/Networking/Network.h b/src/Networking/Network.h
index c0ce6e73..2543443d 100644
--- a/src/Networking/Network.h
+++ b/src/Networking/Network.h
@@ -95,6 +95,9 @@ public:
void SetEthernetIPAddress(IPAddress p_ipAddress, IPAddress p_netmask, IPAddress p_gateway) noexcept;
IPAddress GetIPAddress(unsigned int interface) const noexcept;
+ IPAddress GetNetmask(unsigned int interface) const noexcept;
+ IPAddress GetGateway(unsigned int interface) const noexcept;
+ bool UsingDhcp(unsigned int interface) const noexcept;
const char *GetHostname() const noexcept { return hostname; }
void SetHostname(const char *name) noexcept;
GCodeResult SetMacAddress(unsigned int interface, const MacAddress& mac, const StringRef& reply) noexcept;
diff --git a/src/Networking/NetworkDefs.h b/src/Networking/NetworkDefs.h
index 116a97ea..d1f17b9e 100644
--- a/src/Networking/NetworkDefs.h
+++ b/src/Networking/NetworkDefs.h
@@ -36,16 +36,37 @@ constexpr IPAddress DefaultIpAddress; // will be initialised to 0 by construc
constexpr IPAddress DefaultNetMask(0x00FFFFFF); // equivalent to 255.255.255.0. Use constexpr constructor to avoid it being allocated in RAM.
constexpr IPAddress DefaultGateway; // will be initialised to 0 by constructor
-constexpr size_t NumProtocols = 3; // number of network protocols we support, not counting FtpDataProtocol, MdnsProtocol or AnyProtocol
-constexpr NetworkProtocol HttpProtocol = 0, FtpProtocol = 1, TelnetProtocol = 2, FtpDataProtocol = 3, MdnsProtocol = 4, AnyProtocol = 255;
+constexpr size_t NumTcpProtocols = 3;
+
+#if SUPPORT_MULTICAST_DISCOVERY
+constexpr size_t NumProtocols = NumTcpProtocols + 1; // number of network protocols we support, not counting FtpDataProtocol, MdnsProtocol or AnyProtocol
+#else
+constexpr size_t NumProtocols = NumTcpProtocols; // number of network protocols we support, not counting FtpDataProtocol, MdnsProtocol or AnyProtocol
+#endif
+
+constexpr NetworkProtocol HttpProtocol = 0, FtpProtocol = 1, TelnetProtocol = 2, MulticastDiscoveryProtocol = 3, FtpDataProtocol = 3, MdnsProtocol = 4, AnyProtocol = 255;
-constexpr size_t NumTcpPorts = NumProtocols + 1;
constexpr TcpPort DefaultHttpPort = 80;
constexpr TcpPort DefaultFtpPort = 21;
constexpr TcpPort DefaultTelnetPort = 23;
+#if SUPPORT_MULTICAST_DISCOVERY
+constexpr TcpPort DefaultMulticastDiscoveryPort = 10002; // this is actually a UDP port
+#endif
-constexpr TcpPort DefaultPortNumbers[NumProtocols] = { DefaultHttpPort, DefaultFtpPort, DefaultTelnetPort };
-constexpr const char *_ecv_array ProtocolNames[NumProtocols] = { "HTTP", "FTP", "TELNET" };
+constexpr TcpPort DefaultPortNumbers[NumProtocols] =
+{
+ DefaultHttpPort, DefaultFtpPort, DefaultTelnetPort,
+#if SUPPORT_MULTICAST_DISCOVERY
+ DefaultMulticastDiscoveryPort
+#endif
+};
+constexpr const char *_ecv_array ProtocolNames[NumProtocols] =
+{
+ "HTTP", "FTP", "TELNET",
+#if SUPPORT_MULTICAST_DISCOVERY
+ "Multicast Discovery"
+#endif
+};
constexpr uint8_t MdnsMacAddress[6] = { 0x01, 0x00, 0x5E, 0x00, 0x00, 0xFB };
constexpr uint8_t MdnsIPAddress[4] = { 224, 0, 0, 251 };
diff --git a/src/Networking/NetworkInterface.h b/src/Networking/NetworkInterface.h
index 9401827b..b6279eef 100644
--- a/src/Networking/NetworkInterface.h
+++ b/src/Networking/NetworkInterface.h
@@ -35,6 +35,9 @@ public:
virtual GCodeResult ReportProtocols(const StringRef& reply) const noexcept = 0;
virtual IPAddress GetIPAddress() const noexcept = 0;
+ virtual IPAddress GetNetmask() const noexcept = 0;
+ virtual IPAddress GetGateway() const noexcept = 0;
+ virtual bool UsingDhcp() const noexcept = 0;
virtual void SetIPAddress(IPAddress p_ipAddress, IPAddress p_netmask, IPAddress p_gateway) noexcept = 0;
virtual GCodeResult SetMacAddress(const MacAddress& mac, const StringRef& reply) noexcept = 0;
virtual const MacAddress& GetMacAddress() const noexcept = 0;
diff --git a/src/Networking/NetworkResponder.h b/src/Networking/NetworkResponder.h
index 2bf3976d..2cfb3c97 100644
--- a/src/Networking/NetworkResponder.h
+++ b/src/Networking/NetworkResponder.h
@@ -27,8 +27,8 @@ public:
NetworkResponder(const NetworkResponder&) = delete;
NetworkResponder *GetNext() const noexcept { return next; }
- virtual bool Spin() noexcept = 0; // do some work, returning true if we did anything significant
- virtual bool Accept(Socket *s, NetworkProtocol protocol) noexcept = 0; // ask the responder to accept this connection, returns true if it did
+ virtual bool Spin() noexcept = 0; // do some work, returning true if we did anything significant
+ virtual bool Accept(Socket *s, NetworkProtocol protocol) noexcept = 0; // ask the responder to accept this connection, returns true if it did
virtual void Terminate(NetworkProtocol protocol, NetworkInterface *interface) noexcept = 0; // terminate the responder if it is serving the specified protocol on the specified interface
virtual void Diagnostics(MessageType mtype) const noexcept = 0;
diff --git a/src/Networking/W5500Ethernet/W5500Interface.h b/src/Networking/W5500Ethernet/W5500Interface.h
index e0176891..66e03b89 100644
--- a/src/Networking/W5500Ethernet/W5500Interface.h
+++ b/src/Networking/W5500Ethernet/W5500Interface.h
@@ -50,7 +50,11 @@ public:
bool IsWiFiInterface() const noexcept override { return false; }
void UpdateHostname(const char *name) noexcept override;
+
IPAddress GetIPAddress() const noexcept override { return ipAddress; }
+ IPAddress GetNetmask() const noexcept override { return netmask; }
+ IPAddress GetGateway() const noexcept override { return gateway; }
+ bool UsingDhcp() const noexcept override { return usingDhcp; }
void SetIPAddress(IPAddress p_ipAddress, IPAddress p_netmask, IPAddress p_gateway) noexcept override;
GCodeResult SetMacAddress(const MacAddress& mac, const StringRef& reply) noexcept override;
const MacAddress& GetMacAddress() const noexcept override { return macAddress; }
@@ -81,11 +85,11 @@ private:
W5500Socket *mdnsSocket;
MdnsResponder *mdnsResponder;
- TcpPort portNumbers[NumProtocols]; // port number used for each protocol
+ TcpPort portNumbers[NumProtocols]; // port number used for each protocol
bool protocolEnabled[NumProtocols]; // whether each protocol is enabled
bool activated;
- bool usingDhcp;
+ bool usingDhcp = true;
IPAddress ipAddress;
IPAddress netmask;