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
path: root/src
diff options
context:
space:
mode:
authorDavid Crocker <dcrocker@eschertech.com>2016-12-24 02:19:20 +0300
committerDavid Crocker <dcrocker@eschertech.com>2016-12-24 02:19:33 +0300
commitdf5507c8c86904bca3c27f63bef715928f80f324 (patch)
treeecbf6049ec633251b6b16e05a0b603aa048a3bed /src
parentad87e81ed3c3370582ae31c83da927df0f04efa0 (diff)
More work on Duet Ethernet support
Diffstat (limited to 'src')
-rw-r--r--src/Duet/Network.cpp4
-rw-r--r--src/Duet/Network.h10
-rw-r--r--src/DuetNG/DuetEthernet/Network.cpp821
-rw-r--r--src/DuetNG/DuetEthernet/Network.h161
-rw-r--r--src/DuetNG/DuetEthernet/NetworkTransacrion.cpp595
-rw-r--r--src/DuetNG/DuetEthernet/NetworkTransaction.h160
-rw-r--r--src/DuetNG/DuetEthernet/Webserver.cpp162
-rw-r--r--src/DuetNG/DuetEthernet/Wiznet/Ethernet/W5500/w5500.cpp35
-rw-r--r--src/DuetNG/DuetEthernet/Wiznet/Ethernet/W5500/w5500.h2
-rw-r--r--src/DuetNG/DuetEthernet/Wiznet/Ethernet/WizSpi.cpp431
-rw-r--r--src/DuetNG/DuetEthernet/Wiznet/Ethernet/WizSpi.h25
-rw-r--r--src/DuetNG/DuetEthernet/Wiznet/Ethernet/socket.cpp23
-rw-r--r--src/DuetNG/DuetEthernet/Wiznet/Ethernet/socket.h2
-rw-r--r--src/DuetNG/DuetEthernet/Wiznet/Ethernet/wizchip_conf.cpp4
-rw-r--r--src/DuetNG/DuetEthernet/Wiznet/Ethernet/wizchip_conf.h4
-rw-r--r--src/DuetNG/DuetEthernet/Wiznet/Internet/DHCP/dhcp.cpp1004
-rw-r--r--src/DuetNG/DuetEthernet/Wiznet/Internet/DHCP/dhcp.h144
-rw-r--r--src/DuetNG/DuetWiFi/Network.cpp2
-rw-r--r--src/DuetNG/DuetWiFi/Network.h8
-rw-r--r--src/Platform.cpp13
20 files changed, 2686 insertions, 924 deletions
diff --git a/src/Duet/Network.cpp b/src/Duet/Network.cpp
index f3ecfcf3..ad2fdb8b 100644
--- a/src/Duet/Network.cpp
+++ b/src/Duet/Network.cpp
@@ -72,7 +72,7 @@ static struct mdns_service mdns_services[] = {
},
{
.name = "\x05_http\x04_tcp\x05local",
- .port = DEFAULT_HTTP_PORT,
+ .port = DefaultHttpPort,
},
{
.name = "\x04_ftp\x04_tcp\x05local",
@@ -102,7 +102,7 @@ static uint16_t sendingWindowSize, sentDataOutstanding;
static uint8_t sendingRetries;
static err_t writeResult, outputResult;
-static uint16_t httpPort = DEFAULT_HTTP_PORT;
+static uint16_t httpPort = DefaultHttpPort;
/*-----------------------------------------------------------------------------------*/
diff --git a/src/Duet/Network.h b/src/Duet/Network.h
index cc099864..d3d9904b 100644
--- a/src/Duet/Network.h
+++ b/src/Duet/Network.h
@@ -33,12 +33,12 @@ const size_t NETWORK_TRANSACTION_COUNT = 24; // Number of NetworkTransacti
const uint32_t TCP_WRITE_TIMEOUT = 4000; // Miliseconds to wait for data we have written to be acknowledged
const uint32_t TCP_MAX_SEND_RETRIES = 8; // How many times can we attempt to write data
-const uint8_t MAC_ADDRESS[6] = { 0xBE, 0xEF, 0xDE, 0xAD, 0xFE, 0xED }; // Need some sort of default...
-const uint8_t IP_ADDRESS[4] = { 192, 168, 1, 10 };
-const uint8_t NET_MASK[4] = { 255, 255, 255, 0 };
-const uint8_t GATE_WAY[4] = { 192, 168, 1, 1 };
+const uint8_t DefaultMacAddress[6] = { 0xBE, 0xEF, 0xDE, 0xAD, 0xFE, 0xED }; // Need some sort of default...
+const uint8_t DefaultIpAddress[4] = { 192, 168, 1, 10 };
+const uint8_t DefaultNetMask[4] = { 255, 255, 255, 0 };
+const uint8_t DefaultGateway[4] = { 192, 168, 1, 1 };
-const uint16_t DEFAULT_HTTP_PORT = 80;
+const uint16_t DefaultHttpPort = 80;
const uint16_t FTP_PORT = 21;
const uint16_t TELNET_PORT = 23;
diff --git a/src/DuetNG/DuetEthernet/Network.cpp b/src/DuetNG/DuetEthernet/Network.cpp
index 27deb978..e2c17ddf 100644
--- a/src/DuetNG/DuetEthernet/Network.cpp
+++ b/src/DuetNG/DuetEthernet/Network.cpp
@@ -8,8 +8,9 @@
#include "RepRapFirmware.h"
#include "compiler.h"
#include "Pins.h"
-#include "Ethernet3/Ethernet3.h"
-
+#include "IPAddress.h"
+#include "wizchip_conf.h"
+#include "Wiznet/Internet/DHCP/dhcp.h"
void Network::SetIPAddress(const uint8_t p_ipAddress[], const uint8_t p_netmask[], const uint8_t p_gateway[])
{
@@ -18,11 +19,12 @@ void Network::SetIPAddress(const uint8_t p_ipAddress[], const uint8_t p_netmask[
memcpy(gateway, p_gateway, sizeof(gateway));
}
-Network::Network(Platform* p) : platform(p), responseCode(0), responseBody(nullptr), responseText(nullptr), responseFile(nullptr),
- httpPort(DEFAULT_HTTP_PORT),
- state(disabled), activated(false)
+Network::Network(Platform* p)
+ : platform(p), lastTickMillis(0),
+ freeTransactions(nullptr), readyTransactions(nullptr), writingTransactions(nullptr),
+ httpPort(DefaultHttpPort), state(NetworkState::disabled), activated(false)
{
- SetIPAddress(IP_ADDRESS, NET_MASK, GATE_WAY);
+ SetIPAddress(DefaultIpAddress, DefaultNetMask, DefaultGateway);
strcpy(hostname, HOSTNAME);
}
@@ -30,7 +32,9 @@ void Network::Init()
{
// Ensure that the chip is in the reset state
pinMode(EspResetPin, OUTPUT_LOW);
- state = disabled;
+ state = NetworkState::disabled;
+ longWait = platform->Time();
+ lastTickMillis = millis();
}
// This is called at the end of config.g processing.
@@ -38,7 +42,7 @@ void Network::Init()
void Network::Activate()
{
activated = true;
- if (state == enabled)
+ if (state == NetworkState::enabled)
{
Start();
}
@@ -51,106 +55,176 @@ void Network::Exit()
void Network::Spin()
{
-#if 1
-#if 0
- if (state == starting)
+ switch(state)
{
- const int rc = Ethernet.begin(platform->MACAddress(), 12000, 5000); // for now we always use DHCP
- if (rc == 1)
+ case NetworkState::enabled:
+ case NetworkState::disabled:
+ // Nothing to do
+ break;
+
+ case NetworkState::establishingLink:
+ if (wizphy_getphylink() == PHY_LINK_ON)
{
- state = running;
+
+ usingDhcp = (ipAddress[0] == 0 && ipAddress[1] == 0 && ipAddress[2] == 0 && ipAddress[3] == 0);
+ if (usingDhcp)
+ {
+ debugPrintf("Link established, getting IP address\n");
+ // IP address is all zeros, so use DHCP
+ DHCP_init(DhcpSocketNumber, hostname);
+ lastTickMillis = millis();
+ state = NetworkState::obtainingIP;
+ }
+ else
+ {
+ debugPrintf("Link established, network running\n");
+ state = NetworkState::active;
+ }
}
- }
- else if (state == running)
-#else
- if (state == starting || state == running)
-#endif
- {
- // Check DHCP
- const int rc = Ethernet.maintain();
- if (state == starting && (rc == DHCP_CHECK_RENEW_OK || rc == DHCP_CHECK_REBIND_OK))
+ break;
+
+ case NetworkState::obtainingIP:
+ if (wizphy_getphylink() == PHY_LINK_ON)
+ {
+ const uint32_t now = millis();
+ if (now - lastTickMillis >= 1000)
+ {
+ lastTickMillis += 1000;
+ DHCP_time_handler();
+ }
+ const DhcpRunResult ret = DHCP_run();
+ if (ret == DhcpRunResult::DHCP_IP_ASSIGN)
+ {
+ debugPrintf("IP address obtained, network running\n");
+ getSIPR(ipAddress);
+ // Send mDNS announcement so that some routers can perform hostname mapping
+ // if this board is connected via a non-IGMP capable WiFi bridge (like the TP-Link WR701N)
+ //mdns_announce();
+ state = NetworkState::active;
+ }
+ }
+ else
{
- state = running;
+ DHCP_stop();
+ state = NetworkState::establishingLink;
}
+ break;
+
+ case NetworkState::active:
+ if (wizphy_getphylink() == PHY_LINK_ON)
+ {
+ if (usingDhcp)
+ {
+ const uint32_t now = millis();
+ if (now - lastTickMillis >= 1000)
+ {
+ lastTickMillis += 1000;
+ DHCP_time_handler();
+ }
+ const DhcpRunResult ret = DHCP_run();
+ if (ret == DhcpRunResult::DHCP_IP_CHANGED)
+ {
+ getSIPR(ipAddress);
+ }
+ }
+
+ // See if we can read any packets
+// ethernet_task();
+
+ // See if we can send anything
+ NetworkTransaction *transaction = writingTransactions;
+ if (transaction != nullptr /*&& sendingConnection == nullptr*/ )
+ {
+ if (transaction->GetNext() != nullptr)
+ {
+ // Data is supposed to be sent and the last packet has been acknowledged.
+ // Rotate the transactions so every client is served even while multiple files are sent
+ NetworkTransaction *next = transaction->GetNext();
+ writingTransactions = next;
+ AppendTransaction(&writingTransactions, transaction);
+ transaction = next;
+ }
+
+ if (transaction->Send())
+ {
+ // This transaction can be released, do this here
+ writingTransactions = transaction->GetNext();
+ PrependTransaction(&freeTransactions, transaction);
+
+ // If there is more data to write on this connection, do it sometime soon
+ NetworkTransaction *nextWrite = transaction->GetNextWrite();
+ if (nextWrite != nullptr)
+ {
+ PrependTransaction(&writingTransactions, nextWrite);
+ }
+ }
+ }
+ }
+ else
+ {
+ DHCP_stop();
+ state = NetworkState::establishingLink;
+ }
+ break;
}
-#endif
+
platform->ClassReport(longWait);
}
void Network::Diagnostics(MessageType mtype)
{
-
+ platform->Message(mtype, "=== Network ===\n");
+ platform->MessageF(mtype, "State: %d\n", (int)state);
}
void Network::Start()
{
+ SetIPAddress(platform->GetIPAddress(), platform->NetMask(), platform->GateWay());
pinMode(EspResetPin, OUTPUT_LOW);
delayMicroseconds(550); // W550 reset pulse must be at least 500us long
Platform::WriteDigital(EspResetPin, HIGH); // raise /Reset pin
delay(55); // W5500 needs 50ms to start up
- state = starting;
-#if 0
- w5500.init();
- w5500.setMACAddress(platform->MACAddress());
-#endif
- const int rc = Ethernet.begin(platform->MACAddress(), 12000, 5000); // for now we always use DHCP
- if (rc == 1)
- {
- state = running;
- }
- else
- {
-#if 1
- {
- uint8_t tmp = w5500.readPHYCFGR();
- uint8_t version = w5500.readVERSIONR();
- uint8_t macBuf[6];
- w5500.readSHAR(macBuf);
- platform->MessageF(GENERIC_MESSAGE, "Phy %02x ver %02x Mac %02x:%02x:%02x:%02x:%02x:%02x\n",
- tmp, version, macBuf[0], macBuf[1], macBuf[2], macBuf[3], macBuf[4], macBuf[5]);
- }
-#endif
- platform->Message(GENERIC_MESSAGE, "Failed to start Ethernet interface\n");
- Stop();
- }
+
+ static const uint8_t bufSizes[8] = { 2, 2, 2, 2, 2, 2, 2, 2 };
+ wizchip_init(bufSizes, bufSizes);
+
+ setSHAR(platform->MACAddress());
+ setSIPR(ipAddress);
+ setGAR(gateway);
+ setSUBR(netmask);
+
+ state = NetworkState::establishingLink;
}
void Network::Stop()
{
- if (state != disabled)
+ if (state != NetworkState::disabled)
{
- Ethernet.stop();
+//TODO Ethernet.stop();
+ if (usingDhcp)
+ {
+ DHCP_stop();
+ }
digitalWrite(EspResetPin, LOW); // put the ESP back into reset
- state = disabled;
+ state = NetworkState::disabled;
}
}
void Network::Enable()
{
- if (state == disabled)
+ if (state == NetworkState::disabled)
{
- state = enabled;
+ state = NetworkState::enabled;
if (activated)
{
Start();
}
}
-#if 1
- else if (state == starting)
- {
- uint8_t tmp = w5500.readPHYCFGR();
- uint8_t version = w5500.readVERSIONR();
- uint8_t macBuf[6];
- w5500.readSHAR(macBuf);
- platform->MessageF(GENERIC_MESSAGE, "Phy %02x ver %02x Mac %02x:%02x:%02x:%02x:%02x:%02x\n",
- tmp, version, macBuf[0], macBuf[1], macBuf[2], macBuf[3], macBuf[4], macBuf[5]);
- }
-#endif
}
void Network::Disable()
{
- if (activated && state != disabled)
+ if (activated && state != NetworkState::disabled)
{
Stop();
platform->Message(GENERIC_MESSAGE, "WiFi server stopped\n");
@@ -159,21 +233,12 @@ void Network::Disable()
bool Network::IsEnabled() const
{
- return state != disabled;
+ return state != NetworkState::disabled;
}
const uint8_t *Network::GetIPAddress() const
{
- if (state == running)
- {
- static IPAddress ip;
- ip = Ethernet.localIP();
- return ip.GetRawAddress();
- }
- else
- {
- return ipAddress;
- }
+ return ipAddress;
}
void Network::SetHttpPort(uint16_t port)
@@ -277,6 +342,22 @@ NetworkTransaction *Network::GetTransaction(const ConnectionState *cs)
#endif
}
+void Network::AppendTransaction(NetworkTransaction* * list, NetworkTransaction *r)
+{
+ r->next = nullptr;
+ while (*list != nullptr)
+ {
+ list = &((*list)->next);
+ }
+ *list = r;
+}
+
+void Network::PrependTransaction(NetworkTransaction* * list, NetworkTransaction *r)
+{
+ r->next = *list;
+ *list = r;
+}
+
void Network::OpenDataPort(uint16_t port)
{
//TODO
@@ -384,586 +465,4 @@ bool Network::AcquireTelnetTransaction()
#endif
}
-//***************************************************************************************************
-
-// ConnectionState class
-
-#if 0
-void ConnectionState::Init(tcp_pcb *p)
-{
- pcb = p;
- localPort = p->local_port;
- remoteIPAddress = p->remote_ip.addr;
- remotePort = p->remote_port;
- next = nullptr;
- sendingTransaction = nullptr;
- persistConnection = true;
- isTerminated = false;
-}
-#endif
-
-void ConnectionState::Terminate()
-{
- //TODO
-#if 0
- if (pcb != nullptr)
- {
- tcp_abort(pcb);
- }
-#endif
-}
-
-//***************************************************************************************************
-// NetworkTransaction class
-
-NetworkTransaction::NetworkTransaction(NetworkTransaction *n) : next(n), status(released)
-{
- sendStack = new OutputStack();
-}
-
-void NetworkTransaction::Set(pbuf *p, ConnectionState *c, TransactionStatus s)
-{
- cs = c;
-// pb = readingPb = p;
- status = s;
-// inputPointer = 0;
- sendBuffer = nullptr;
- fileBeingSent = nullptr;
- closeRequested = false;
- nextWrite = nullptr;
- dataAcknowledged = false;
-}
-
-bool NetworkTransaction::HasMoreDataToRead() const
-{
- //TODO
- return false;
-}
-
-// Read one char from the NetworkTransaction
-bool NetworkTransaction::Read(char& b)
-{
-#if 1
- return false;
-#else
- if (readingPb == nullptr)
- {
- b = 0;
- return false;
- }
-
- b = ((const char*)readingPb->payload)[inputPointer++];
- if (inputPointer == readingPb->len)
- {
- readingPb = readingPb->next;
- inputPointer = 0;
- }
- return true;
-#endif
-}
-
-// Read data from the NetworkTransaction and return true on success
-bool NetworkTransaction::ReadBuffer(const char *&buffer, size_t &len)
-{
-#if 1
- return false;
-#else
- if (readingPb == nullptr)
- {
- return false;
- }
-
- if (inputPointer >= readingPb->len)
- {
- readingPb = readingPb->next;
- inputPointer = 0;
- if (readingPb == nullptr)
- {
- return false;
- }
- }
-
- buffer = (const char*)readingPb->payload + inputPointer;
- len = readingPb->len - inputPointer;
- readingPb = readingPb->next;
- inputPointer = 0;
- return true;
-#endif
-}
-
-void NetworkTransaction::Write(char b)
-{
- if (CanWrite())
- {
- if (sendBuffer == nullptr && !OutputBuffer::Allocate(sendBuffer))
- {
- // Should never get here
- return;
- }
- sendBuffer->cat(b);
- }
-}
-
-void NetworkTransaction::Write(const char* s)
-{
- if (CanWrite())
- {
- if (sendBuffer == nullptr && !OutputBuffer::Allocate(sendBuffer))
- {
- // Should never get here
- return;
- }
- sendBuffer->cat(s);
- }
-}
-
-void NetworkTransaction::Write(StringRef ref)
-{
- Write(ref.Pointer(), ref.strlen());
-}
-
-void NetworkTransaction::Write(const char* s, size_t len)
-{
- if (CanWrite())
- {
- if (sendBuffer == nullptr && !OutputBuffer::Allocate(sendBuffer))
- {
- // Should never get here
- return;
- }
- sendBuffer->cat(s, len);
- }
-}
-
-void NetworkTransaction::Write(OutputBuffer *buffer)
-{
- if (CanWrite())
- {
- // Note we use an individual stack here, because we don't want to link different
- // OutputBuffers for different destinations together...
- sendStack->Push(buffer);
- }
- else
- {
- // Don't keep buffers we can't send...
- OutputBuffer::ReleaseAll(buffer);
- }
-}
-
-void NetworkTransaction::Write(OutputStack *stack)
-{
- if (stack != nullptr)
- {
- if (CanWrite())
- {
- sendStack->Append(stack);
- }
- else
- {
- stack->ReleaseAll();
- }
- }
-}
-
-void NetworkTransaction::Printf(const char* fmt, ...)
-{
- if (CanWrite() && (sendBuffer != nullptr || OutputBuffer::Allocate(sendBuffer)))
- {
- va_list p;
- va_start(p, fmt);
- sendBuffer->vprintf(fmt, p);
- va_end(p);
- }
-}
-
-void NetworkTransaction::SetFileToWrite(FileStore *file)
-{
- if (CanWrite())
- {
- fileBeingSent = file;
- }
- else if (file != nullptr)
- {
- file->Close();
- }
-}
-
-// Send exactly one TCP window of data and return true when this transaction can be released
-bool NetworkTransaction::Send()
-{
-#if 1
- return true;
-#else
- // Free up this transaction if the connection is supposed to be closed
- if (closeRequested)
- {
- reprap.GetNetwork()->ConnectionClosed(cs, true); // This will release the transaction too
- return false;
- }
-
- // Fill up the TCP window with some data chunks from our OutputBuffer instances
- size_t bytesBeingSent = 0, bytesLeftToSend = TCP_WND;
- while (sendBuffer != nullptr && bytesLeftToSend > 0)
- {
- size_t copyLength = min<size_t>(bytesLeftToSend, sendBuffer->BytesLeft());
- memcpy(sendingWindow + bytesBeingSent, sendBuffer->Read(copyLength), copyLength);
- bytesBeingSent += copyLength;
- bytesLeftToSend -= copyLength;
-
- if (sendBuffer->BytesLeft() == 0)
- {
- sendBuffer = OutputBuffer::Release(sendBuffer);
- if (sendBuffer == nullptr)
- {
- sendBuffer = sendStack->Pop();
- }
- }
- }
-
- // We also intend to send a file, so check if we can fill up the TCP window
- if (sendBuffer == nullptr && bytesLeftToSend != 0 && fileBeingSent != nullptr)
- {
- // For HSMCI efficiency, read from the file in multiples of 4 bytes except at the end.
- // This ensures that the second and subsequent chunks can be DMA'd directly into sendingWindow.
- size_t bytesToRead = bytesLeftToSend & (~3);
- if (bytesToRead != 0)
- {
- int bytesRead = fileBeingSent->Read(sendingWindow + bytesBeingSent, bytesToRead);
- if (bytesRead > 0)
- {
- bytesBeingSent += bytesRead;
- }
-
- if (bytesRead != (int)bytesToRead)
- {
- fileBeingSent->Close();
- fileBeingSent = nullptr;
- }
- }
- }
-
- if (bytesBeingSent == 0)
- {
- // If we have no data to send, this connection can be closed next time
- if (!cs->persistConnection && nextWrite == nullptr)
- {
- Close();
- return false;
- }
-
- // We want to send data from another transaction as well, so only free up this one
- cs->sendingTransaction = nextWrite;
- return true;
- }
-
- // The TCP window has been filled up as much as possible, so send it now. There is no need to check
- // the available space in the SNDBUF queue, because we really write only one TCP window at once.
- writeResult = tcp_write(cs->pcb, sendingWindow, bytesBeingSent, 0);
- if (ERR_IS_FATAL(writeResult))
- {
- reprap.GetPlatform()->MessageF(HOST_MESSAGE, "Network: Failed to write data in Send (code %d)\n", writeResult);
- tcp_abort(cs->pcb);
- return false;
- }
-
- outputResult = tcp_output(cs->pcb);
- if (ERR_IS_FATAL(outputResult))
- {
- reprap.GetPlatform()->MessageF(HOST_MESSAGE, "Network: Failed to output data in Send (code %d)\n", outputResult);
- tcp_abort(cs->pcb);
- return false;
- }
-
- if (outputResult != ERR_OK && reprap.Debug(moduleNetwork))
- {
- reprap.GetPlatform()->MessageF(HOST_MESSAGE, "Network: tcp_output resulted in error code %d\n", outputResult);
- }
-
- // Set LwIP callbacks for ACK and retransmission handling
- tcp_poll(cs->pcb, conn_poll, TCP_WRITE_TIMEOUT / TCP_SLOW_INTERVAL / TCP_MAX_SEND_RETRIES);
- tcp_sent(cs->pcb, conn_sent);
-
- // Set all values for the send process
- sendingConnection = cs;
- sendingRetries = 0;
- sendingWindowSize = sentDataOutstanding = bytesBeingSent;
- return false;
-#endif
-}
-
-// This is called by the Webserver to send output data to a client. If keepConnectionAlive is set to false,
-// the current connection will be terminated once everything has been sent.
-void NetworkTransaction::Commit(bool keepConnectionAlive)
-{
-#if 0
- // If the connection has been terminated (e.g. RST received while writing upload data), discard this transaction
- if (!IsConnected() || status == released)
- {
- Discard();
- return;
- }
-
- // Free buffer holding the incoming data and prepare some values for the sending process
- FreePbuf();
- cs->persistConnection = keepConnectionAlive;
- if (sendBuffer == nullptr)
- {
- sendBuffer = sendStack->Pop();
- }
- status = sending;
-
- // Unlink the item(s) from the list of ready transactions
- if (keepConnectionAlive)
- {
- // Our connection is still of interest, remove only this transaction from the list
- NetworkTransaction *previous = nullptr;
- for(NetworkTransaction *item = reprap.GetNetwork()->readyTransactions; item != nullptr; item = item->next)
- {
- if (item == this)
- {
- if (previous == nullptr)
- {
- reprap.GetNetwork()->readyTransactions = next;
- }
- else
- {
- previous->next = next;
- }
- break;
- }
- previous = item;
- }
- }
- else
- {
- // We will close this connection soon, stop receiving data from this PCB
- tcp_recv(cs->pcb, nullptr);
-
- // Also remove all ready transactions pointing to our ConnectionState
- NetworkTransaction *previous = nullptr, *item = reprap.GetNetwork()->readyTransactions;
- while (item != nullptr)
- {
- if (item->cs == cs)
- {
- if (item == this)
- {
- // Only unlink this item
- if (previous == nullptr)
- {
- reprap.GetNetwork()->readyTransactions = next;
- }
- else
- {
- previous->next = next;
- }
- item = next;
- }
- else
- {
- // Remove all others
- item->Discard();
- item = (previous == nullptr) ? reprap.GetNetwork()->readyTransactions : previous->next;
- }
- }
- else
- {
- previous = item;
- item = item->next;
- }
- }
- }
-
- // Enqueue this transaction, so it's sent in the right order
- NetworkTransaction *mySendingTransaction = cs->sendingTransaction;
- if (mySendingTransaction == nullptr)
- {
- cs->sendingTransaction = this;
- reprap.GetNetwork()->AppendTransaction(&reprap.GetNetwork()->writingTransactions, this);
- }
- else
- {
- while (mySendingTransaction->nextWrite != nullptr)
- {
- mySendingTransaction = mySendingTransaction->nextWrite;
- }
- mySendingTransaction->nextWrite = this;
- }
-#endif
-}
-
-// Call this to perform some networking tasks while processing deferred requests,
-// and to move this transaction and all transactions that are associated with its
-// connection to the end of readyTransactions. There are three ways to do this:
-//
-// 1) DeferOnly: Do not modify any of the processed data and don't send an ACK.
-// This will ensure that zero-window packets are sent back to the client
-// 2) ResetData: Reset the read pointers and acknowledge that the data has been processed
-// 3) DiscardData: Free the processed data, acknowledge it and append this transaction as
-// an empty item again without payload (i.e. without pbufs)
-//
-void NetworkTransaction::Defer(DeferralMode mode)
-{
-#if 0
- if (mode == DeferralMode::ResetData)
- {
- // Reset the reading pointers and send an ACK
- inputPointer = 0;
- readingPb = pb;
- if (IsConnected() && pb != nullptr && !dataAcknowledged)
- {
- tcp_recved(cs->pcb, pb->tot_len);
- dataAcknowledged = true;
- }
- }
- else if (mode == DeferralMode::DiscardData)
- {
- // Discard the incoming data, because we don't need to process it any more
- FreePbuf();
- }
-
- status = deferred;
-
- // Unlink this transaction from the list of ready transactions and append it again
- Network *network = reprap.GetNetwork();
- NetworkTransaction *item, *previous = nullptr;
- for(item = network->readyTransactions; item != nullptr; item = item->next)
- {
- if (item == this)
- {
- if (previous == nullptr)
- {
- network->readyTransactions = next;
- }
- else
- {
- previous->next = next;
- }
- break;
- }
- previous = item;
- }
- network->AppendTransaction(&network->readyTransactions, this);
-
- // Append all other transactions that are associated to this connection, so that the
- // Webserver gets a chance to deal with all connected clients even while multiple
- // deferred requests are present in the list.
- item = network->readyTransactions;
- previous = nullptr;
- while (item != this)
- {
- if (item->cs == cs)
- {
- NetworkTransaction *nextItem = item->next;
- if (previous == nullptr)
- {
- network->readyTransactions = item->next;
- network->AppendTransaction(&network->readyTransactions, item);
- }
- else
- {
- previous->next = item->next;
- network->AppendTransaction(&network->readyTransactions, item);
- }
- item = nextItem;
- }
- else
- {
- previous = item;
- item = item->next;
- }
- }
-#endif
-}
-
-
-// This method should be called if we don't want to send data to the client and if we
-// don't want to interfere with the connection state. May also be called from ISR!
-void NetworkTransaction::Discard()
-{
-#if 0
- // Can we do anything?
- if (status == released)
- {
- // No - don't free up released items multiple times
- return;
- }
-
- // Free up some resources
- FreePbuf();
-
- if (fileBeingSent != nullptr)
- {
- fileBeingSent->Close();
- fileBeingSent = nullptr;
- }
-
- OutputBuffer::ReleaseAll(sendBuffer);
- sendStack->ReleaseAll();
-
- // Unlink this transactions from the list of ready transactions and free it. It is then appended to the list of
- // free transactions because we don't want to risk reusing it when the ethernet ISR processes incoming data
- NetworkTransaction *previous = nullptr;
- for(NetworkTransaction *item = reprap.GetNetwork()->readyTransactions; item != nullptr; item = item->next)
- {
- if (item == this)
- {
- if (previous == nullptr)
- {
- reprap.GetNetwork()->readyTransactions = next;
- }
- else
- {
- previous->next = next;
- }
- break;
- }
- previous = item;
- }
- reprap.GetNetwork()->AppendTransaction(&reprap.GetNetwork()->freeTransactions, this);
- bool callDisconnectHandler = (cs != nullptr && status == disconnected);
- status = released;
-
- // Call disconnect event if this transaction indicates a graceful disconnect and if the connection
- // still persists (may not be the case if a RST packet was received before)
- if (callDisconnectHandler)
- {
- if (reprap.Debug(moduleNetwork))
- {
- reprap.GetPlatform()->Message(HOST_MESSAGE, "Network: Discard() is handling a graceful disconnect\n");
- }
- reprap.GetNetwork()->ConnectionClosed(cs, false);
- }
-#endif
-}
-
-uint32_t NetworkTransaction::GetRemoteIP() const
-{
- return (cs != nullptr) ? cs->GetRemoteIP() : 0;
-}
-
-uint16_t NetworkTransaction::GetRemotePort() const
-{
- return (cs != nullptr) ? cs->GetRemotePort() : 0;
-}
-
-uint16_t NetworkTransaction::GetLocalPort() const
-{
- return (cs != nullptr) ? cs->GetLocalPort() : 0;
-}
-
-void NetworkTransaction::Close()
-{
-#if 0
- tcp_pcb *pcb = cs->pcb;
- tcp_recv(pcb, nullptr);
- closeRequested = true;
-#endif
-}
-
-bool ConnectionState::IsConnected() const
-{
- //TODO
- return false;
-}
-
// End
diff --git a/src/DuetNG/DuetEthernet/Network.h b/src/DuetNG/DuetEthernet/Network.h
index a2e1b4d7..36501dcc 100644
--- a/src/DuetNG/DuetEthernet/Network.h
+++ b/src/DuetNG/DuetEthernet/Network.h
@@ -15,131 +15,26 @@ Separated out from Platform.h by dc42 and extended by zpl
#include <cstdlib>
#include "MessageType.h"
+#include "NetworkTransaction.h"
-const uint8_t MAC_ADDRESS[6] = { 0xBE, 0xEF, 0xDE, 0xAD, 0xFE, 0xED }; // Need some sort of default...
-const uint8_t IP_ADDRESS[4] = { 192, 168, 1, 10 }; // Need some sort of default...
-const uint8_t NET_MASK[4] = { 255, 255, 255, 0 };
-const uint8_t GATE_WAY[4] = { 192, 168, 1, 1 };
+const uint8_t DefaultMacAddress[6] = { 0xBE, 0xEF, 0xDE, 0xAD, 0xFE, 0xED }; // Need some sort of default...
+const uint8_t DefaultIpAddress[4] = { 0, 0, 0, 0 }; // Need some sort of default...
+const uint8_t DefaultNetMask[4] = { 255, 255, 255, 0 };
+const uint8_t DefaultGateway[4] = { 0, 0, 0, 0 };
-const uint16_t DEFAULT_HTTP_PORT = 80;
+const uint16_t DefaultHttpPort = 80;
const uint16_t FTP_PORT = 21;
const uint16_t TELNET_PORT = 23;
-class Platform;
-
-struct tcp_pcb;
-struct pbuf;
-
-class NetworkTransaction;
-
-// ConnectionState structure that we use to track TCP connections. It is usually combined with NetworkTransactions.
-struct ConnectionState
-{
-// tcp_pcb *volatile pcb; // Connection PCB
- uint16_t localPort, remotePort; // Copy of the local and remote ports, because the PCB may be unavailable
- uint32_t remoteIPAddress; // Same for the remote IP address
- NetworkTransaction * volatile sendingTransaction; // NetworkTransaction that is currently sending via this connection
- ConnectionState * volatile next; // Next ConnectionState in this list
- bool persistConnection; // Do we expect this connection to stay alive?
- volatile bool isTerminated; // Will be true if the connection has gone down unexpectedly (TCP RST)
-
-// void Init(tcp_pcb *p);
- uint16_t GetLocalPort() const { return localPort; }
- uint32_t GetRemoteIP() const { return remoteIPAddress; }
- uint16_t GetRemotePort() const { return remotePort; }
- bool IsConnected() const; // { return pcb != nullptr; }
- bool IsTerminated() const { return isTerminated; }
- void Terminate();
-};
+// We have 8 sockets available on the W5500. We reserve one for DHCP, leaving 7 for TCP/IP transactions i.e. HTTP, FTP and Telnet.
+const size_t NumTcpSockets = 7;
+const uint8_t DhcpSocketNumber = 7;
-// Assign a status to each NetworkTransaction
-enum TransactionStatus
-{
- released,
- connected,
- receiving,
- sending,
- disconnected,
- deferred,
- acquired
-};
-
-// How is a deferred request supposed to be handled?
-enum class DeferralMode
-{
- DeferOnly, // don't change anything, because we want to read more of it next time
- ResetData, // keep the data and reset all reading pointers allowing us to process it again
- DiscardData // discard all incoming data and re-enqueue the empty transaction
-};
-
-// Start with a class to hold input and output from the network that needs to be responded to.
-// This includes changes in the connection state, e.g. connects and disconnects.
-class NetworkTransaction
-{
- public:
- friend class Network;
-
- NetworkTransaction(NetworkTransaction* n);
- void Set(pbuf *p, ConnectionState* c, TransactionStatus s);
- TransactionStatus GetStatus() const { return status; }
- bool IsConnected() const;
-
- bool HasMoreDataToRead() const; // { return readingPb != nullptr; }
- bool Read(char& b);
- bool ReadBuffer(const char *&buffer, size_t &len);
- void Write(char b);
- void Write(const char* s);
- void Write(StringRef ref);
- void Write(const char* s, size_t len);
- void Write(OutputBuffer *buffer);
- void Write(OutputStack *stack);
- void Printf(const char *fmt, ...);
- void SetFileToWrite(FileStore *file);
-
- ConnectionState *GetConnection() const { return cs; }
- uint16_t GetLocalPort() const;
- uint32_t GetRemoteIP() const;
- uint16_t GetRemotePort() const;
-
- void Commit(bool keepConnectionAlive);
- void Defer(DeferralMode mode);
- void Discard();
-
- private:
- bool CanWrite() const;
- bool Send();
- void Close();
-
- ConnectionState* cs;
- NetworkTransaction* volatile next; // next NetworkTransaction in the list we are in
- NetworkTransaction* volatile nextWrite; // next NetworkTransaction queued to write to assigned connection
-// pbuf *pb, *readingPb; // received packet queue and a pointer to the pbuf being read from
-// size_t inputPointer; // amount of data already taken from the first packet buffer
-
- OutputBuffer *sendBuffer;
- OutputStack *sendStack;
- FileStore * volatile fileBeingSent;
-
- volatile TransactionStatus status;
- volatile bool closeRequested, dataAcknowledged;
-};
+class Platform;
// The main network class that drives the network.
class Network
{
- enum NetworkState
- {
- disabled, // WiFi not active
- enabled, // WiFi enabled but not started yet
- starting, // starting up (waiting for initialisation)
- running
-// idle, // nothing happening
-// receivePending, // we have asserted TransferReady and await completion of a receive-only transaction
-// sendReceivePending, // we have asserted TransferReady and await completion of a transmit/receive
-// transferDone, // transfer completed but receive DMA fifo may not have been flushed yet
-// processing, // a transaction has been completed but we haven't released the input buffer yet
-// sending // a transaction has been completed and we are sending the response
- };
public:
const uint8_t *GetIPAddress() const;
void SetIPAddress(const uint8_t p_ipAddress[], const uint8_t p_netmask[], const uint8_t p_gateway[]);
@@ -183,19 +78,26 @@ public:
bool AcquireTelnetTransaction();
private:
- void SetupSpi();
+ enum class NetworkState
+ {
+ disabled, // WiFi not active
+ enabled, // WiFi enabled but not started yet
+ establishingLink, // starting up (waiting for initialisation)
+ obtainingIP,
+ active
+ };
Platform *platform;
+ float longWait;
+ uint32_t lastTickMillis;
-// uint32_t responseIp;
- uint32_t responseCode;
-// uint32_t responseFragment;
- OutputBuffer *responseBody;
- const char* responseText;
- FileStore *responseFile;
-// uint32_t responseFileBytes;
+ void AppendTransaction(NetworkTransaction* * list, NetworkTransaction *r);
+ void PrependTransaction(NetworkTransaction* * list, NetworkTransaction *r);
+ bool AcquireTransaction(ConnectionState *cs);
- float longWait;
+ NetworkTransaction * freeTransactions;
+ NetworkTransaction * readyTransactions;
+ NetworkTransaction * writingTransactions;
uint16_t httpPort;
uint8_t ipAddress[4];
@@ -205,16 +107,7 @@ private:
NetworkState state;
bool activated;
+ bool usingDhcp;
};
-inline bool NetworkTransaction::IsConnected() const
-{
- return (cs != nullptr && cs->IsConnected());
-}
-
-inline bool NetworkTransaction::CanWrite() const
-{
- return (IsConnected() && status != released);
-}
-
#endif
diff --git a/src/DuetNG/DuetEthernet/NetworkTransacrion.cpp b/src/DuetNG/DuetEthernet/NetworkTransacrion.cpp
new file mode 100644
index 00000000..e954723d
--- /dev/null
+++ b/src/DuetNG/DuetEthernet/NetworkTransacrion.cpp
@@ -0,0 +1,595 @@
+/*
+ * NetworkTransacrion.cpp
+ *
+ * Created on: 23 Dec 2016
+ * Author: David
+ */
+
+#include "NetworkTransaction.h"
+#include <cstdarg>
+
+//***************************************************************************************************
+
+// ConnectionState class
+
+#if 0
+void ConnectionState::Init(tcp_pcb *p)
+{
+ pcb = p;
+ localPort = p->local_port;
+ remoteIPAddress = p->remote_ip.addr;
+ remotePort = p->remote_port;
+ next = nullptr;
+ sendingTransaction = nullptr;
+ persistConnection = true;
+ isTerminated = false;
+}
+#endif
+
+void ConnectionState::Terminate()
+{
+ //TODO
+#if 0
+ if (pcb != nullptr)
+ {
+ tcp_abort(pcb);
+ }
+#endif
+}
+
+bool ConnectionState::IsConnected() const
+{
+ //TODO
+ return false;
+}
+
+//***************************************************************************************************
+// NetworkTransaction class
+
+NetworkTransaction::NetworkTransaction(NetworkTransaction *n) : next(n), status(released)
+{
+ sendStack = new OutputStack();
+}
+
+#if 0
+void NetworkTransaction::Set(pbuf *p, ConnectionState *c, TransactionStatus s)
+{
+ cs = c;
+// pb = readingPb = p;
+ status = s;
+// inputPointer = 0;
+ sendBuffer = nullptr;
+ fileBeingSent = nullptr;
+ closeRequested = false;
+ nextWrite = nullptr;
+ dataAcknowledged = false;
+}
+#endif
+
+bool NetworkTransaction::HasMoreDataToRead() const
+{
+ //TODO
+ return false;
+}
+
+// Read one char from the NetworkTransaction
+bool NetworkTransaction::Read(char& b)
+{
+#if 1
+ return false;
+#else
+ if (readingPb == nullptr)
+ {
+ b = 0;
+ return false;
+ }
+
+ b = ((const char*)readingPb->payload)[inputPointer++];
+ if (inputPointer == readingPb->len)
+ {
+ readingPb = readingPb->next;
+ inputPointer = 0;
+ }
+ return true;
+#endif
+}
+
+// Read data from the NetworkTransaction and return true on success
+bool NetworkTransaction::ReadBuffer(const char *&buffer, size_t &len)
+{
+#if 1
+ return false;
+#else
+ if (readingPb == nullptr)
+ {
+ return false;
+ }
+
+ if (inputPointer >= readingPb->len)
+ {
+ readingPb = readingPb->next;
+ inputPointer = 0;
+ if (readingPb == nullptr)
+ {
+ return false;
+ }
+ }
+
+ buffer = (const char*)readingPb->payload + inputPointer;
+ len = readingPb->len - inputPointer;
+ readingPb = readingPb->next;
+ inputPointer = 0;
+ return true;
+#endif
+}
+
+void NetworkTransaction::Write(char b)
+{
+ if (CanWrite())
+ {
+ if (sendBuffer == nullptr && !OutputBuffer::Allocate(sendBuffer))
+ {
+ // Should never get here
+ return;
+ }
+ sendBuffer->cat(b);
+ }
+}
+
+void NetworkTransaction::Write(const char* s)
+{
+ if (CanWrite())
+ {
+ if (sendBuffer == nullptr && !OutputBuffer::Allocate(sendBuffer))
+ {
+ // Should never get here
+ return;
+ }
+ sendBuffer->cat(s);
+ }
+}
+
+void NetworkTransaction::Write(StringRef ref)
+{
+ Write(ref.Pointer(), ref.strlen());
+}
+
+void NetworkTransaction::Write(const char* s, size_t len)
+{
+ if (CanWrite())
+ {
+ if (sendBuffer == nullptr && !OutputBuffer::Allocate(sendBuffer))
+ {
+ // Should never get here
+ return;
+ }
+ sendBuffer->cat(s, len);
+ }
+}
+
+void NetworkTransaction::Write(OutputBuffer *buffer)
+{
+ if (CanWrite())
+ {
+ // Note we use an individual stack here, because we don't want to link different
+ // OutputBuffers for different destinations together...
+ sendStack->Push(buffer);
+ }
+ else
+ {
+ // Don't keep buffers we can't send...
+ OutputBuffer::ReleaseAll(buffer);
+ }
+}
+
+void NetworkTransaction::Write(OutputStack *stack)
+{
+ if (stack != nullptr)
+ {
+ if (CanWrite())
+ {
+ sendStack->Append(stack);
+ }
+ else
+ {
+ stack->ReleaseAll();
+ }
+ }
+}
+
+void NetworkTransaction::Printf(const char* fmt, ...)
+{
+ if (CanWrite() && (sendBuffer != nullptr || OutputBuffer::Allocate(sendBuffer)))
+ {
+ va_list p;
+ va_start(p, fmt);
+ sendBuffer->vprintf(fmt, p);
+ va_end(p);
+ }
+}
+
+void NetworkTransaction::SetFileToWrite(FileStore *file)
+{
+ if (CanWrite())
+ {
+ fileBeingSent = file;
+ }
+ else if (file != nullptr)
+ {
+ file->Close();
+ }
+}
+
+// Send exactly one TCP window of data and return true when this transaction can be released
+bool NetworkTransaction::Send()
+{
+#if 1
+ return true;
+#else
+ // Free up this transaction if the connection is supposed to be closed
+ if (closeRequested)
+ {
+ reprap.GetNetwork()->ConnectionClosed(cs, true); // This will release the transaction too
+ return false;
+ }
+
+ // Fill up the TCP window with some data chunks from our OutputBuffer instances
+ size_t bytesBeingSent = 0, bytesLeftToSend = TCP_WND;
+ while (sendBuffer != nullptr && bytesLeftToSend > 0)
+ {
+ size_t copyLength = min<size_t>(bytesLeftToSend, sendBuffer->BytesLeft());
+ memcpy(sendingWindow + bytesBeingSent, sendBuffer->Read(copyLength), copyLength);
+ bytesBeingSent += copyLength;
+ bytesLeftToSend -= copyLength;
+
+ if (sendBuffer->BytesLeft() == 0)
+ {
+ sendBuffer = OutputBuffer::Release(sendBuffer);
+ if (sendBuffer == nullptr)
+ {
+ sendBuffer = sendStack->Pop();
+ }
+ }
+ }
+
+ // We also intend to send a file, so check if we can fill up the TCP window
+ if (sendBuffer == nullptr && bytesLeftToSend != 0 && fileBeingSent != nullptr)
+ {
+ // For HSMCI efficiency, read from the file in multiples of 4 bytes except at the end.
+ // This ensures that the second and subsequent chunks can be DMA'd directly into sendingWindow.
+ size_t bytesToRead = bytesLeftToSend & (~3);
+ if (bytesToRead != 0)
+ {
+ int bytesRead = fileBeingSent->Read(sendingWindow + bytesBeingSent, bytesToRead);
+ if (bytesRead > 0)
+ {
+ bytesBeingSent += bytesRead;
+ }
+
+ if (bytesRead != (int)bytesToRead)
+ {
+ fileBeingSent->Close();
+ fileBeingSent = nullptr;
+ }
+ }
+ }
+
+ if (bytesBeingSent == 0)
+ {
+ // If we have no data to send, this connection can be closed next time
+ if (!cs->persistConnection && nextWrite == nullptr)
+ {
+ Close();
+ return false;
+ }
+
+ // We want to send data from another transaction as well, so only free up this one
+ cs->sendingTransaction = nextWrite;
+ return true;
+ }
+
+ // The TCP window has been filled up as much as possible, so send it now. There is no need to check
+ // the available space in the SNDBUF queue, because we really write only one TCP window at once.
+ writeResult = tcp_write(cs->pcb, sendingWindow, bytesBeingSent, 0);
+ if (ERR_IS_FATAL(writeResult))
+ {
+ reprap.GetPlatform()->MessageF(HOST_MESSAGE, "Network: Failed to write data in Send (code %d)\n", writeResult);
+ tcp_abort(cs->pcb);
+ return false;
+ }
+
+ outputResult = tcp_output(cs->pcb);
+ if (ERR_IS_FATAL(outputResult))
+ {
+ reprap.GetPlatform()->MessageF(HOST_MESSAGE, "Network: Failed to output data in Send (code %d)\n", outputResult);
+ tcp_abort(cs->pcb);
+ return false;
+ }
+
+ if (outputResult != ERR_OK && reprap.Debug(moduleNetwork))
+ {
+ reprap.GetPlatform()->MessageF(HOST_MESSAGE, "Network: tcp_output resulted in error code %d\n", outputResult);
+ }
+
+ // Set LwIP callbacks for ACK and retransmission handling
+ tcp_poll(cs->pcb, conn_poll, TCP_WRITE_TIMEOUT / TCP_SLOW_INTERVAL / TCP_MAX_SEND_RETRIES);
+ tcp_sent(cs->pcb, conn_sent);
+
+ // Set all values for the send process
+ sendingConnection = cs;
+ sendingRetries = 0;
+ sendingWindowSize = sentDataOutstanding = bytesBeingSent;
+ return false;
+#endif
+}
+
+// This is called by the Webserver to send output data to a client. If keepConnectionAlive is set to false,
+// the current connection will be terminated once everything has been sent.
+void NetworkTransaction::Commit(bool keepConnectionAlive)
+{
+#if 0
+ // If the connection has been terminated (e.g. RST received while writing upload data), discard this transaction
+ if (!IsConnected() || status == released)
+ {
+ Discard();
+ return;
+ }
+
+ // Free buffer holding the incoming data and prepare some values for the sending process
+ FreePbuf();
+ cs->persistConnection = keepConnectionAlive;
+ if (sendBuffer == nullptr)
+ {
+ sendBuffer = sendStack->Pop();
+ }
+ status = sending;
+
+ // Unlink the item(s) from the list of ready transactions
+ if (keepConnectionAlive)
+ {
+ // Our connection is still of interest, remove only this transaction from the list
+ NetworkTransaction *previous = nullptr;
+ for(NetworkTransaction *item = reprap.GetNetwork()->readyTransactions; item != nullptr; item = item->next)
+ {
+ if (item == this)
+ {
+ if (previous == nullptr)
+ {
+ reprap.GetNetwork()->readyTransactions = next;
+ }
+ else
+ {
+ previous->next = next;
+ }
+ break;
+ }
+ previous = item;
+ }
+ }
+ else
+ {
+ // We will close this connection soon, stop receiving data from this PCB
+ tcp_recv(cs->pcb, nullptr);
+
+ // Also remove all ready transactions pointing to our ConnectionState
+ NetworkTransaction *previous = nullptr, *item = reprap.GetNetwork()->readyTransactions;
+ while (item != nullptr)
+ {
+ if (item->cs == cs)
+ {
+ if (item == this)
+ {
+ // Only unlink this item
+ if (previous == nullptr)
+ {
+ reprap.GetNetwork()->readyTransactions = next;
+ }
+ else
+ {
+ previous->next = next;
+ }
+ item = next;
+ }
+ else
+ {
+ // Remove all others
+ item->Discard();
+ item = (previous == nullptr) ? reprap.GetNetwork()->readyTransactions : previous->next;
+ }
+ }
+ else
+ {
+ previous = item;
+ item = item->next;
+ }
+ }
+ }
+
+ // Enqueue this transaction, so it's sent in the right order
+ NetworkTransaction *mySendingTransaction = cs->sendingTransaction;
+ if (mySendingTransaction == nullptr)
+ {
+ cs->sendingTransaction = this;
+ reprap.GetNetwork()->AppendTransaction(&reprap.GetNetwork()->writingTransactions, this);
+ }
+ else
+ {
+ while (mySendingTransaction->nextWrite != nullptr)
+ {
+ mySendingTransaction = mySendingTransaction->nextWrite;
+ }
+ mySendingTransaction->nextWrite = this;
+ }
+#endif
+}
+
+// Call this to perform some networking tasks while processing deferred requests,
+// and to move this transaction and all transactions that are associated with its
+// connection to the end of readyTransactions. There are three ways to do this:
+//
+// 1) DeferOnly: Do not modify any of the processed data and don't send an ACK.
+// This will ensure that zero-window packets are sent back to the client
+// 2) ResetData: Reset the read pointers and acknowledge that the data has been processed
+// 3) DiscardData: Free the processed data, acknowledge it and append this transaction as
+// an empty item again without payload (i.e. without pbufs)
+//
+void NetworkTransaction::Defer(DeferralMode mode)
+{
+#if 0
+ if (mode == DeferralMode::ResetData)
+ {
+ // Reset the reading pointers and send an ACK
+ inputPointer = 0;
+ readingPb = pb;
+ if (IsConnected() && pb != nullptr && !dataAcknowledged)
+ {
+ tcp_recved(cs->pcb, pb->tot_len);
+ dataAcknowledged = true;
+ }
+ }
+ else if (mode == DeferralMode::DiscardData)
+ {
+ // Discard the incoming data, because we don't need to process it any more
+ FreePbuf();
+ }
+
+ status = deferred;
+
+ // Unlink this transaction from the list of ready transactions and append it again
+ Network *network = reprap.GetNetwork();
+ NetworkTransaction *item, *previous = nullptr;
+ for(item = network->readyTransactions; item != nullptr; item = item->next)
+ {
+ if (item == this)
+ {
+ if (previous == nullptr)
+ {
+ network->readyTransactions = next;
+ }
+ else
+ {
+ previous->next = next;
+ }
+ break;
+ }
+ previous = item;
+ }
+ network->AppendTransaction(&network->readyTransactions, this);
+
+ // Append all other transactions that are associated to this connection, so that the
+ // Webserver gets a chance to deal with all connected clients even while multiple
+ // deferred requests are present in the list.
+ item = network->readyTransactions;
+ previous = nullptr;
+ while (item != this)
+ {
+ if (item->cs == cs)
+ {
+ NetworkTransaction *nextItem = item->next;
+ if (previous == nullptr)
+ {
+ network->readyTransactions = item->next;
+ network->AppendTransaction(&network->readyTransactions, item);
+ }
+ else
+ {
+ previous->next = item->next;
+ network->AppendTransaction(&network->readyTransactions, item);
+ }
+ item = nextItem;
+ }
+ else
+ {
+ previous = item;
+ item = item->next;
+ }
+ }
+#endif
+}
+
+
+// This method should be called if we don't want to send data to the client and if we
+// don't want to interfere with the connection state. May also be called from ISR!
+void NetworkTransaction::Discard()
+{
+#if 0
+ // Can we do anything?
+ if (status == released)
+ {
+ // No - don't free up released items multiple times
+ return;
+ }
+
+ // Free up some resources
+ FreePbuf();
+
+ if (fileBeingSent != nullptr)
+ {
+ fileBeingSent->Close();
+ fileBeingSent = nullptr;
+ }
+
+ OutputBuffer::ReleaseAll(sendBuffer);
+ sendStack->ReleaseAll();
+
+ // Unlink this transactions from the list of ready transactions and free it. It is then appended to the list of
+ // free transactions because we don't want to risk reusing it when the ethernet ISR processes incoming data
+ NetworkTransaction *previous = nullptr;
+ for(NetworkTransaction *item = reprap.GetNetwork()->readyTransactions; item != nullptr; item = item->next)
+ {
+ if (item == this)
+ {
+ if (previous == nullptr)
+ {
+ reprap.GetNetwork()->readyTransactions = next;
+ }
+ else
+ {
+ previous->next = next;
+ }
+ break;
+ }
+ previous = item;
+ }
+ reprap.GetNetwork()->AppendTransaction(&reprap.GetNetwork()->freeTransactions, this);
+ bool callDisconnectHandler = (cs != nullptr && status == disconnected);
+ status = released;
+
+ // Call disconnect event if this transaction indicates a graceful disconnect and if the connection
+ // still persists (may not be the case if a RST packet was received before)
+ if (callDisconnectHandler)
+ {
+ if (reprap.Debug(moduleNetwork))
+ {
+ reprap.GetPlatform()->Message(HOST_MESSAGE, "Network: Discard() is handling a graceful disconnect\n");
+ }
+ reprap.GetNetwork()->ConnectionClosed(cs, false);
+ }
+#endif
+}
+
+uint32_t NetworkTransaction::GetRemoteIP() const
+{
+ return (cs != nullptr) ? cs->GetRemoteIP() : 0;
+}
+
+uint16_t NetworkTransaction::GetRemotePort() const
+{
+ return (cs != nullptr) ? cs->GetRemotePort() : 0;
+}
+
+uint16_t NetworkTransaction::GetLocalPort() const
+{
+ return (cs != nullptr) ? cs->GetLocalPort() : 0;
+}
+
+void NetworkTransaction::Close()
+{
+#if 0
+ tcp_pcb *pcb = cs->pcb;
+ tcp_recv(pcb, nullptr);
+ closeRequested = true;
+#endif
+}
+
+// End
diff --git a/src/DuetNG/DuetEthernet/NetworkTransaction.h b/src/DuetNG/DuetEthernet/NetworkTransaction.h
new file mode 100644
index 00000000..91a9eedb
--- /dev/null
+++ b/src/DuetNG/DuetEthernet/NetworkTransaction.h
@@ -0,0 +1,160 @@
+/*
+ * NetworkTransaction.h
+ *
+ * Created on: 23 Dec 2016
+ * Author: David
+ */
+
+#ifndef SRC_DUETNG_DUETETHERNET_NETWORKTRANSACTION_H_
+#define SRC_DUETNG_DUETETHERNET_NETWORKTRANSACTION_H_
+
+#include <cstdint>
+#include <cstddef>
+#include "Libraries/General/StringRef.h"
+#include "OutputMemory.h"
+#include "Storage/FileStore.h"
+
+typedef uint8_t SocketNumber;
+
+const SocketNumber NoSocket = 255;
+
+// Network buffer class. These buffers are 2K long so that they can accept as much data as the W5500 can provide in one go.
+class NetworkBuffer
+{
+public:
+ friend class NetworkTransaction;
+
+ NetworkBuffer();
+
+ // Release this buffer and return the next one in the chain
+ NetworkBuffer *Release();
+
+ // Read 1 character, returning true of successful, false if no data left
+ bool Read(char& b);
+
+ // Read some data
+ bool ReadBuffer(const char *&buffer, size_t &len);
+
+ // Return the amount of data available, not including continuation buffers
+ size_t Remaining() const;
+
+ // Return the amount of data available, including continuation buffers
+ size_t TotalRemaining() const;
+
+private:
+ NetworkBuffer *next;
+ size_t dataLength;
+ size_t readPointer;
+ uint8_t data[2048];
+};
+
+class NetworkTransaction;
+
+// ConnectionState structure that we use to track TCP connections. It is usually combined with NetworkTransactions.
+class ConnectionState
+{
+public:
+ void Init(SocketNumber s);
+ uint16_t GetLocalPort() const { return localPort; }
+ uint32_t GetRemoteIP() const { return remoteIPAddress; }
+ uint16_t GetRemotePort() const { return remotePort; }
+ bool IsConnected() const; // { return pcb != nullptr; }
+ bool IsTerminated() const { return isTerminated; }
+ void Terminate();
+
+private:
+ uint16_t localPort, remotePort; // Copy of the local and remote ports, because the PCB may be unavailable
+ uint32_t remoteIPAddress; // Same for the remote IP address
+ NetworkTransaction * volatile sendingTransaction; // NetworkTransaction that is currently sending via this connection
+ ConnectionState * volatile next; // Next ConnectionState in this list
+ bool persistConnection; // Do we expect this connection to stay alive?
+ bool isTerminated; // Will be true if the connection has gone down unexpectedly (TCP RST)
+ SocketNumber socketNum; // The W5500 socket number we are using
+};
+
+// Assign a status to each NetworkTransaction
+enum TransactionStatus
+{
+ released,
+ connected,
+ receiving,
+ sending,
+ disconnected,
+ deferred,
+ acquired
+};
+
+// How is a deferred request supposed to be handled?
+enum class DeferralMode
+{
+ DeferOnly, // don't change anything, because we want to read more of it next time
+ ResetData, // keep the data and reset all reading pointers allowing us to process it again
+ DiscardData // discard all incoming data and re-enqueue the empty transaction
+};
+
+// Start with a class to hold input and output from the network that needs to be responded to.
+// This includes changes in the connection state, e.g. connects and disconnects.
+class NetworkTransaction
+{
+public:
+ friend class Network;
+
+ NetworkTransaction(NetworkTransaction* n);
+// void Set(pbuf *p, ConnectionState* c, TransactionStatus s);
+ TransactionStatus GetStatus() const { return status; }
+ bool IsConnected() const;
+
+ bool HasMoreDataToRead() const; // { return readingPb != nullptr; }
+ bool Read(char& b);
+ bool ReadBuffer(const char *&buffer, size_t &len);
+ void Write(char b);
+ void Write(const char* s);
+ void Write(StringRef ref);
+ void Write(const char* s, size_t len);
+ void Write(OutputBuffer *buffer);
+ void Write(OutputStack *stack);
+ void Printf(const char *fmt, ...);
+ void SetFileToWrite(FileStore *file);
+
+ ConnectionState *GetConnection() const { return cs; }
+ uint16_t GetLocalPort() const;
+ uint32_t GetRemoteIP() const;
+ uint16_t GetRemotePort() const;
+
+ bool Send();
+ void Commit(bool keepConnectionAlive);
+ void Defer(DeferralMode mode);
+ void Discard();
+
+ NetworkTransaction *GetNext() const { return next; }
+ NetworkTransaction *GetNextWrite() const { return nextWrite; }
+
+private:
+ bool CanWrite() const;
+ void Close();
+
+ ConnectionState* cs;
+ NetworkTransaction* next; // next NetworkTransaction in the list we are in
+ NetworkTransaction* nextWrite; // next NetworkTransaction queued to write to assigned connection
+ NetworkBuffer *pb, *readingPb; // received packet queue and a pointer to the pbuf being read from
+// size_t inputPointer; // amount of data already taken from the first packet buffer
+
+ OutputBuffer *sendBuffer;
+ OutputStack *sendStack;
+ FileStore * volatile fileBeingSent;
+
+ volatile TransactionStatus status;
+ volatile bool closeRequested, dataAcknowledged;
+};
+
+inline bool NetworkTransaction::IsConnected() const
+{
+ return (cs != nullptr && cs->IsConnected());
+}
+
+inline bool NetworkTransaction::CanWrite() const
+{
+ return (IsConnected() && status != released);
+}
+
+#endif /* SRC_DUETNG_DUETETHERNET_NETWORKTRANSACTION_H_ */
diff --git a/src/DuetNG/DuetEthernet/Webserver.cpp b/src/DuetNG/DuetEthernet/Webserver.cpp
index 293b77e0..af1bdcbe 100644
--- a/src/DuetNG/DuetEthernet/Webserver.cpp
+++ b/src/DuetNG/DuetEthernet/Webserver.cpp
@@ -121,36 +121,26 @@ void Webserver::Init()
// Deal with input/output from/to the client (if any)
void Webserver::Spin()
{
- if (webserverActive)
+ // Check if we are enabled and we can actually send something back to the client
+ if (webserverActive && OutputBuffer::GetBytesLeft(nullptr) != 0)
{
- // Check if we can actually send something back to the client
- if (OutputBuffer::GetBytesLeft(nullptr) == 0)
- {
- platform->ClassReport(longWait);
- return;
- }
-
// We must ensure that we have exclusive access to LWIP
if (!network->Lock())
{
- platform->ClassReport(longWait);
- return;
- }
-
- // Allow each ProtocolInterpreter to do something
- httpInterpreter->Spin();
- ftpInterpreter->Spin();
- telnetInterpreter->Spin();
+ // Allow each ProtocolInterpreter to do something
+ httpInterpreter->Spin();
+ ftpInterpreter->Spin();
+ telnetInterpreter->Spin();
- // See if we have new data to process
- currentTransaction = network->GetTransaction(readingConnection);
- if (currentTransaction != nullptr)
- {
- // Take care of different protocol types here
- ProtocolInterpreter *interpreter;
- uint16_t localPort = currentTransaction->GetLocalPort();
- switch (localPort)
+ // See if we have new data to process
+ currentTransaction = network->GetTransaction(readingConnection);
+ if (currentTransaction != nullptr)
{
+ // Take care of different protocol types here
+ ProtocolInterpreter *interpreter;
+ const uint16_t localPort = currentTransaction->GetLocalPort();
+ switch (localPort)
+ {
case FTP_PORT: /* FTP */
interpreter = ftpInterpreter;
break;
@@ -169,82 +159,82 @@ void Webserver::Spin()
interpreter = ftpInterpreter;
}
break;
- }
+ }
- // See if we have to print some debug info
- if (reprap.Debug(moduleWebserver))
- {
- const char *type;
- switch (currentTransaction->GetStatus())
+ // See if we have to print some debug info
+ if (reprap.Debug(moduleWebserver))
{
- case released: type = "released"; break;
- case connected: type = "connected"; break;
- case receiving: type = "receiving"; break;
- case sending: type = "sending"; break;
- case disconnected: type = "disconnected"; break;
- case deferred: type = "deferred"; break;
- case acquired: type = "acquired"; break;
- default: type = "unknown"; break;
+ const char *type;
+ switch (currentTransaction->GetStatus())
+ {
+ case released: type = "released"; break;
+ case connected: type = "connected"; break;
+ case receiving: type = "receiving"; break;
+ case sending: type = "sending"; break;
+ case disconnected: type = "disconnected"; break;
+ case deferred: type = "deferred"; break;
+ case acquired: type = "acquired"; break;
+ default: type = "unknown"; break;
+ }
+ platform->MessageF(HOST_MESSAGE, "Incoming transaction: Type %s at local port %d (remote port %d)\n",
+ type, localPort, currentTransaction->GetRemotePort());
}
- platform->MessageF(HOST_MESSAGE, "Incoming transaction: Type %s at local port %d (remote port %d)\n",
- type, localPort, currentTransaction->GetRemotePort());
- }
- // For protocols other than HTTP it is important to send a HELO message
- TransactionStatus status = currentTransaction->GetStatus();
- if (status == connected)
- {
- interpreter->ConnectionEstablished();
- }
- // Graceful disconnects are handled here, because prior NetworkTransactions might still contain valid
- // data. That's why it's a bad idea to close these connections immediately in the Network class.
- else if (status == disconnected)
- {
- // This will call the disconnect events and effectively close the connection
- currentTransaction->Discard();
- }
- // Check for fast uploads via this connection
- else if (interpreter->DoingFastUpload())
- {
- interpreter->DoFastUpload();
- }
- // Process other messages (if we can)
- else if (interpreter->CanParseData())
- {
- readingConnection = currentTransaction->GetConnection();
- for(size_t i = 0; i < TCP_MSS / 3; i++)
+ // For protocols other than HTTP it is important to send a HELO message
+ TransactionStatus status = currentTransaction->GetStatus();
+ if (status == connected)
+ {
+ interpreter->ConnectionEstablished();
+ }
+ // Graceful disconnects are handled here, because prior NetworkTransactions might still contain valid
+ // data. That's why it's a bad idea to close these connections immediately in the Network class.
+ else if (status == disconnected)
+ {
+ // This will call the disconnect events and effectively close the connection
+ currentTransaction->Discard();
+ }
+ // Check for fast uploads via this connection
+ else if (interpreter->DoingFastUpload())
+ {
+ interpreter->DoFastUpload();
+ }
+ // Process other messages (if we can)
+ else if (interpreter->CanParseData())
{
- char c;
- if (currentTransaction->Read(c))
+ readingConnection = currentTransaction->GetConnection();
+ for (size_t i = 0; i < TCP_MSS / 3; i++)
{
- // Each ProtocolInterpreter must take care of the current NetworkTransaction by
- // calling either Commit(), Discard() or Defer()
- if (interpreter->CharFromClient(c))
+ char c;
+ if (currentTransaction->Read(c))
{
+ // Each ProtocolInterpreter must take care of the current NetworkTransaction by calling either Commit(), Discard() or Defer()
+ if (interpreter->CharFromClient(c))
+ {
+ readingConnection = nullptr;
+ break;
+ }
+ }
+ else
+ {
+ // We ran out of data before finding a complete request. This happens when the incoming
+ // message length exceeds the TCP MSS. Notify the current ProtocolInterpreter about this,
+ // which will remove the current transaction too
+ interpreter->NoMoreDataAvailable();
readingConnection = nullptr;
break;
}
}
- else
- {
- // We ran out of data before finding a complete request. This happens when the incoming
- // message length exceeds the TCP MSS. Notify the current ProtocolInterpreter about this,
- // which will remove the current transaction too
- interpreter->NoMoreDataAvailable();
- readingConnection = nullptr;
- break;
- }
}
}
+ else if (readingConnection != nullptr)
+ {
+ // We failed to find a transaction for a reading connection.
+ // This should never happen, but if it does, terminate this connection instantly
+ platform->Message(HOST_MESSAGE, "Error: Transaction for reading connection not found\n");
+ readingConnection->Terminate();
+ }
+ network->Unlock(); // unlock LWIP again
}
- else if (readingConnection != nullptr)
- {
- // We failed to find a transaction for a reading connection.
- // This should never happen, but if it does, terminate this connection instantly
- platform->Message(HOST_MESSAGE, "Error: Transaction for reading connection not found\n");
- readingConnection->Terminate();
- }
- network->Unlock(); // unlock LWIP again
}
platform->ClassReport(longWait);
}
diff --git a/src/DuetNG/DuetEthernet/Wiznet/Ethernet/W5500/w5500.cpp b/src/DuetNG/DuetEthernet/Wiznet/Ethernet/W5500/w5500.cpp
index 7447386b..3fab829e 100644
--- a/src/DuetNG/DuetEthernet/Wiznet/Ethernet/W5500/w5500.cpp
+++ b/src/DuetNG/DuetEthernet/Wiznet/Ethernet/W5500/w5500.cpp
@@ -53,6 +53,7 @@
//*****************************************************************************
#include "w5500.h"
+#include "WizSpi.h"
#define _W5500_SPI_VDM_OP_ 0x00
#define _W5500_SPI_FDM_OP_LEN1_ 0x01
@@ -63,35 +64,35 @@
uint8_t WIZCHIP_READ(uint32_t AddrSel)
{
- SpiAssertSS();
- SpiSendAddress(AddrSel | (_W5500_SPI_READ_ | _W5500_SPI_VDM_OP_));
- const uint8_t ret = SpiReadByte();
- SpiReleaseSS();
+ WizSpi::AssertSS();
+ WizSpi::SendAddress(AddrSel | (_W5500_SPI_READ_ | _W5500_SPI_VDM_OP_));
+ const uint8_t ret = WizSpi::ExchangeByte(0xFF, true);
+ WizSpi::ReleaseSS();
return ret;
}
void WIZCHIP_WRITE(uint32_t AddrSel, uint8_t wb )
{
- SpiAssertSS();
- SpiSendAddress(AddrSel | (_W5500_SPI_WRITE_ | _W5500_SPI_VDM_OP_));
- SpiSendByte(wb);
- SpiReleaseSS();
+ WizSpi::AssertSS();
+ WizSpi::SendAddress(AddrSel | (_W5500_SPI_WRITE_ | _W5500_SPI_VDM_OP_));
+ WizSpi::ExchangeByte(wb, true);
+ WizSpi::ReleaseSS();
}
void WIZCHIP_READ_BUF (uint32_t AddrSel, uint8_t* pBuf, uint16_t len)
{
- SpiAssertSS();
- SpiSendAddress(AddrSel | (_W5500_SPI_READ_ | _W5500_SPI_VDM_OP_));
- SpiReadBurst(pBuf, len);
- SpiReleaseSS();
+ WizSpi::AssertSS();
+ WizSpi::SendAddress(AddrSel | (_W5500_SPI_READ_ | _W5500_SPI_VDM_OP_));
+ WizSpi::ReadBurst(pBuf, len);
+ WizSpi::ReleaseSS();
}
void WIZCHIP_WRITE_BUF(uint32_t AddrSel, const uint8_t* pBuf, uint16_t len)
{
- SpiAssertSS();
- SpiSendAddress(AddrSel | (_W5500_SPI_WRITE_ | _W5500_SPI_VDM_OP_));
- SpiSendBurst(pBuf, len);
- SpiReleaseSS();
+ WizSpi::AssertSS();
+ WizSpi::SendAddress(AddrSel | (_W5500_SPI_WRITE_ | _W5500_SPI_VDM_OP_));
+ WizSpi::SendBurst(pBuf, len);
+ WizSpi::ReleaseSS();
}
@@ -128,7 +129,7 @@ uint16_t getSn_RX_RSR(uint8_t sn)
return val;
}
-void wiz_send_data(uint8_t sn, uint8_t *wizdata, uint16_t len)
+void wiz_send_data(uint8_t sn, const uint8_t *wizdata, uint16_t len)
{
if (len != 0)
{
diff --git a/src/DuetNG/DuetEthernet/Wiznet/Ethernet/W5500/w5500.h b/src/DuetNG/DuetEthernet/Wiznet/Ethernet/W5500/w5500.h
index 048c47eb..495772ac 100644
--- a/src/DuetNG/DuetEthernet/Wiznet/Ethernet/W5500/w5500.h
+++ b/src/DuetNG/DuetEthernet/Wiznet/Ethernet/W5500/w5500.h
@@ -2266,7 +2266,7 @@ static inline uint16_t getSn_TxMAX(uint8_t sn)
* @param len Data length
* @sa wiz_recv_data()
*/
-void wiz_send_data(uint8_t sn, uint8_t *wizdata, uint16_t len);
+void wiz_send_data(uint8_t sn, const uint8_t *wizdata, uint16_t len);
/**
* @ingroup Basic_IO_function
diff --git a/src/DuetNG/DuetEthernet/Wiznet/Ethernet/WizSpi.cpp b/src/DuetNG/DuetEthernet/Wiznet/Ethernet/WizSpi.cpp
new file mode 100644
index 00000000..c32a14a5
--- /dev/null
+++ b/src/DuetNG/DuetEthernet/Wiznet/Ethernet/WizSpi.cpp
@@ -0,0 +1,431 @@
+/*
+ * WizSpi.cpp
+ *
+ * Created on: 16 Dec 2016
+ * Author: David
+ */
+
+#include "WizSpi.h"
+#include "variant.h"
+#include "Pins.h"
+
+// Define exactly one of the following as 1, the other as zero
+// The PDC seems to be too slow to work reliably without getting transmit underruns, so we use the DMAC now.
+#define USE_PDC 0 // use peripheral DMA controller
+#define USE_DMAC 0 // use general DMA controller
+
+#if USE_PDC
+#include "pdc.h"
+#endif
+
+#if USE_DMAC
+#include "dmac.h"
+#endif
+
+#include "matrix.h"
+
+// Functions called by the W5500 module to transfer data to/from the W5500 via SPI
+const uint32_t SpiClockFrequency = 10000000; // use 10MHz for now, increase it later
+const unsigned int SpiPeripheralChannelId = 0; // we use NPCS0 as the slave select signal
+
+#if USE_PDC
+static Pdc *spi_pdc;
+static inline void spi_rx_dma_enable()
+{
+ pdc_enable_transfer(spi_pdc, PERIPH_PTCR_RXTEN);
+}
+
+static inline void spi_tx_dma_enable()
+{
+ pdc_enable_transfer(spi_pdc, PERIPH_PTCR_TXTEN);
+}
+
+static inline void spi_rx_dma_disable()
+{
+ pdc_disable_transfer(spi_pdc, PERIPH_PTCR_RXTDIS);
+}
+
+static inline void spi_tx_dma_disable()
+{
+ pdc_disable_transfer(spi_pdc, PERIPH_PTCR_TXTDIS);
+}
+
+static bool spi_dma_check_rx_complete()
+{
+ return true;
+}
+
+static void spi_tx_dma_setup(const TransactionBuffer *buf, uint32_t maxTransmitLength)
+{
+ pdc_packet_t pdc_spi_packet;
+ pdc_spi_packet.ul_addr = reinterpret_cast<uint32_t>(buf);
+ pdc_spi_packet.ul_size = buf->PacketLength() * 4; // need length in bytes
+ pdc_tx_init(spi_pdc, &pdc_spi_packet, NULL);
+}
+
+static void spi_rx_dma_setup(const TransactionBuffer *buf)
+{
+ pdc_packet_t pdc_spi_packet;
+ pdc_spi_packet.ul_addr = reinterpret_cast<uint32_t>(buf);
+ pdc_spi_packet.ul_size = TransactionBuffer::MaxReceiveBytes;
+ pdc_rx_init(spi_pdc, &pdc_spi_packet, NULL);
+}
+
+#endif
+
+#if USE_DMAC
+
+// Our choice of DMA channels to use
+const uint32_t CONF_SPI_DMAC_TX_CH = 1;
+const uint32_t CONF_SPI_DMAC_RX_CH = 2;
+
+// Hardware IDs of the SPI transmit and receive DMA interfaces. See atsam datasheet.
+const uint32_t DMA_HW_ID_SPI_TX = 1;
+const uint32_t DMA_HW_ID_SPI_RX = 2;
+
+static inline void spi_rx_dma_enable()
+{
+ dmac_channel_enable(DMAC, CONF_SPI_DMAC_RX_CH);
+}
+
+static inline void spi_tx_dma_enable()
+{
+ dmac_channel_enable(DMAC, CONF_SPI_DMAC_TX_CH);
+}
+
+static inline void spi_rx_dma_disable()
+{
+ dmac_channel_disable(DMAC, CONF_SPI_DMAC_RX_CH);
+}
+
+static inline void spi_tx_dma_disable()
+{
+ dmac_channel_disable(DMAC, CONF_SPI_DMAC_TX_CH);
+}
+
+static bool spi_dma_check_rx_complete()
+{
+ uint32_t status = DMAC->DMAC_CHSR;
+ if ( ((status & (DMAC_CHSR_ENA0 << CONF_SPI_DMAC_RX_CH)) == 0) // controller is not enabled, perhaps because it finished a full buffer transfer
+ || ((status & (DMAC_CHSR_EMPT0 << CONF_SPI_DMAC_RX_CH)) != 0) // controller is enabled, probably suspended, and the FIFO is empty
+ )
+ {
+ // Disable the channel.
+ // We also need to set the resume bit, otherwise it remains suspended when we re-enable it.
+ DMAC->DMAC_CHDR = (DMAC_CHDR_DIS0 << CONF_SPI_DMAC_RX_CH) | (DMAC_CHDR_RES0 << CONF_SPI_DMAC_RX_CH);
+ return true;
+ }
+ return false;
+}
+
+static void spi_tx_dma_setup(const TransactionBuffer *buf, uint32_t maxTransmitLength)
+{
+ DMAC->DMAC_EBCISR; // clear any pending interrupts
+
+ dmac_channel_set_source_addr(DMAC, CONF_SPI_DMAC_TX_CH, reinterpret_cast<uint32_t>(buf));
+ dmac_channel_set_destination_addr(DMAC, CONF_SPI_DMAC_TX_CH, reinterpret_cast<uint32_t>(& SPI->SPI_TDR));
+ dmac_channel_set_descriptor_addr(DMAC, CONF_SPI_DMAC_TX_CH, 0);
+ dmac_channel_set_ctrlA(DMAC, CONF_SPI_DMAC_TX_CH, maxTransmitLength | DMAC_CTRLA_SRC_WIDTH_WORD | DMAC_CTRLA_DST_WIDTH_BYTE);
+ dmac_channel_set_ctrlB(DMAC, CONF_SPI_DMAC_TX_CH,
+ DMAC_CTRLB_SRC_DSCR | DMAC_CTRLB_DST_DSCR | DMAC_CTRLB_FC_MEM2PER_DMA_FC | DMAC_CTRLB_SRC_INCR_INCREMENTING | DMAC_CTRLB_DST_INCR_FIXED);
+}
+
+static void spi_rx_dma_setup(const TransactionBuffer *buf)
+{
+ DMAC->DMAC_EBCISR; // clear any pending interrupts
+
+ dmac_channel_set_source_addr(DMAC, CONF_SPI_DMAC_RX_CH, reinterpret_cast<uint32_t>(& SPI->SPI_RDR));
+ dmac_channel_set_destination_addr(DMAC, CONF_SPI_DMAC_RX_CH, reinterpret_cast<uint32_t>(buf));
+ dmac_channel_set_descriptor_addr(DMAC, CONF_SPI_DMAC_RX_CH, 0);
+// dmac_channel_set_ctrlA(DMAC, CONF_SPI_DMAC_RX_CH, TransactionBuffer::MaxTransferBytes | DMAC_CTRLA_SRC_WIDTH_BYTE | DMAC_CTRLA_DST_WIDTH_WORD);
+ dmac_channel_set_ctrlB(DMAC, CONF_SPI_DMAC_RX_CH,
+ DMAC_CTRLB_SRC_DSCR | DMAC_CTRLB_DST_DSCR | DMAC_CTRLB_FC_PER2MEM_DMA_FC | DMAC_CTRLB_SRC_INCR_FIXED | DMAC_CTRLB_DST_INCR_INCREMENTING);
+}
+
+#endif
+
+#if USE_PDC || USE_DMAC
+
+static void spi_dma_disable()
+{
+ spi_tx_dma_disable();
+ spi_rx_dma_disable();
+}
+
+#if 0
+/**
+ * \brief Set SPI slave transfer.
+ */
+static void spi_slave_dma_setup(bool dataToSend, bool allowReceive)
+{
+#if USE_PDC
+ pdc_disable_transfer(spi_pdc, PERIPH_PTCR_TXTDIS | PERIPH_PTCR_RXTDIS);
+
+ TransactionBuffer *outBufPointer = (dataToSend) ? &outBuffer : reinterpret_cast<TransactionBuffer*>(&dummyOutBuffer);
+ spi_tx_dma_setup(outBufPointer);
+ if (allowReceive)
+ {
+ outBufPointer->SetDataTaken();
+ spi_rx_dma_setup(&inBuffer);
+ pdc_enable_transfer(spi_pdc, PERIPH_PTCR_TXTEN | PERIPH_PTCR_RXTEN);
+ }
+ else
+ {
+ outBufPointer->ClearDataTaken();
+ pdc_enable_transfer(spi_pdc, PERIPH_PTCR_TXTEN);
+ }
+#endif
+
+#if USE_DMAC
+ spi_dma_disable();
+
+ TransactionBuffer *outBufPointer = (dataToSend) ? &outBuffer : reinterpret_cast<TransactionBuffer*>(&dummyOutBuffer);
+ if (allowReceive)
+ {
+ spi_rx_dma_setup(&inBuffer);
+ spi_rx_dma_enable();
+// outBufPointer->SetDataTaken();
+ }
+ else
+ {
+// outBufPointer->ClearDataTaken();
+ }
+
+// spi_tx_dma_setup(outBufPointer, (dataToSend) ? TransactionBuffer::MaxTransferBytes : 4 * TransactionBuffer::headerDwords);
+ spi_tx_dma_enable();
+#endif
+}
+#endif
+
+#endif
+
+namespace WizSpi
+{
+ // Initialise the SPI interface
+ void Init()
+ {
+ #if USE_PDC
+ spi_pdc = spi_get_pdc_base(SPI);
+ // The PDCs are masters 2 and 3 and the SRAM is slave 0. Give the PDCs the highest priority.
+ matrix_set_master_burst_type(0, MATRIX_ULBT_8_BEAT_BURST);
+ matrix_set_slave_default_master_type(0, MATRIX_DEFMSTR_LAST_DEFAULT_MASTER);
+ matrix_set_slave_priority(0, (3 << MATRIX_PRAS0_M2PR_Pos) | (3 << MATRIX_PRAS0_M3PR_Pos));
+ matrix_set_slave_slot_cycle(0, 8);
+ #endif
+
+ #if USE_DMAC
+ pmc_enable_periph_clk(ID_DMAC);
+ dmac_init(DMAC);
+ dmac_set_priority_mode(DMAC, DMAC_PRIORITY_ROUND_ROBIN);
+ dmac_enable(DMAC);
+ // The DMAC is master 4 and the SRAM is slave 0. Give the DMAC the highest priority.
+ matrix_set_slave_default_master_type(0, MATRIX_DEFMSTR_LAST_DEFAULT_MASTER);
+ matrix_set_slave_priority(0, (3 << MATRIX_PRAS0_M4PR_Pos));
+ // Set the slave slot cycle limit.
+ // If we leave it at the default value of 511 clock cycles, we get transmit underruns due to the HSMCI using the bus for too long.
+ // A value of 8 seems to work. I haven't tried other values yet.
+ matrix_set_slave_slot_cycle(0, 8);
+ #endif
+
+ // Set up the SPI pins
+ ConfigurePin(g_APinDescription[APIN_SPI_SCK]);
+ ConfigurePin(g_APinDescription[APIN_SPI_MOSI]);
+ ConfigurePin(g_APinDescription[APIN_SPI_MISO]);
+#if 1
+ pinMode(APIN_SPI_SS0, OUTPUT_HIGH); // use manual SS control for now
+#else
+ ConfigurePin(g_APinDescription[APIN_SPI_SS0]);
+#endif
+
+ pmc_enable_periph_clk(ID_SPI);
+
+#if USE_PDC || USE_DMAC
+ spi_dma_disable();
+#endif
+
+ spi_reset(SPI); // this clears the transmit and receive registers and puts the SPI into slave mode
+ SPI->SPI_MR = SPI_MR_MSTR // master mode
+ | SPI_MR_MODFDIS // disable fault detection
+ | SPI_MR_PCS(SpiPeripheralChannelId); // fixed peripheral select
+
+ // Set SPI mode, clock frequency, CS active after transfer, delay between transfers
+ const uint16_t baud_div = (uint16_t)spi_calc_baudrate_div(SpiClockFrequency, SystemCoreClock);
+ const uint32_t csr = SPI_CSR_SCBR(baud_div) // Baud rate
+ | SPI_CSR_BITS_8_BIT // Transfer bit width
+ | SPI_CSR_DLYBCT(0) // Transfer delay
+ | SPI_CSR_CSAAT // Keep CS low after transfer in case we are slow in writing the next byte
+ | SPI_CSR_NCPHA; // Data is captured on the leading edge of the clock (SPI mode 0)
+ SPI->SPI_CSR[SpiPeripheralChannelId] = csr;
+ spi_enable(SPI);
+
+#if USE_DMAC
+ // Configure DMA RX channel
+ dmac_channel_set_configuration(DMAC, CONF_SPI_DMAC_RX_CH,
+ DMAC_CFG_SRC_PER(DMA_HW_ID_SPI_RX) | DMAC_CFG_SRC_H2SEL | DMAC_CFG_SOD | DMAC_CFG_FIFOCFG_ASAP_CFG);
+
+ // Configure DMA TX channel
+ dmac_channel_set_configuration(DMAC, CONF_SPI_DMAC_TX_CH,
+ DMAC_CFG_DST_PER(DMA_HW_ID_SPI_TX) | DMAC_CFG_DST_H2SEL | DMAC_CFG_SOD | DMAC_CFG_FIFOCFG_ASAP_CFG);
+#endif
+ }
+
+ void Stop()
+ {
+ NVIC_DisableIRQ(SPI_IRQn);
+ spi_disable(SPI);
+#if USE_PDC || USE_DMA
+ spi_dma_check_rx_complete();
+ spi_dma_disable();
+#endif
+ }
+
+ // Wait for transmitter ready returning true if timed out
+ static inline bool waitForTxReady()
+ {
+ uint32_t timeout = SPI_TIMEOUT;
+ while (!spi_is_tx_ready(SPI))
+ {
+ if (--timeout == 0)
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ // Wait for transmitter empty returning true if timed out
+ static inline bool waitForTxEmpty()
+ {
+ uint32_t timeout = SPI_TIMEOUT;
+ while (!spi_is_tx_empty(SPI))
+ {
+ if (!timeout--)
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ // Wait for receive data available returning true if timed out
+ static inline bool waitForRxReady()
+ {
+ uint32_t timeout = SPI_TIMEOUT;
+ while (!spi_is_rx_ready(SPI))
+ {
+ if (--timeout == 0)
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ // Set the SS pin low to address the W5500
+ void AssertSS()
+ {
+ spi_set_peripheral_chip_select_value(SPI, spi_get_pcs(SpiPeripheralChannelId));
+ digitalWrite(SamCsPin, LOW);
+ }
+
+ // Set the SS pin high again
+ void ReleaseSS()
+ {
+ waitForTxEmpty();
+ digitalWrite(SamCsPin, HIGH);
+ }
+
+ void SendAddress(uint32_t addr)
+ {
+ (void)ExchangeByte((uint8_t)(addr >> 16), false);
+ (void)ExchangeByte((uint8_t)(addr >> 8), false);
+ (void)ExchangeByte((uint8_t)addr, false);
+ }
+
+ uint8_t ExchangeByte(uint8_t b, bool isLast)
+ {
+ if (waitForTxReady())
+ {
+ return 0;
+ }
+
+ // Write to transmit register
+ uint32_t dOut = b;
+ if (isLast)
+ {
+ dOut |= SPI_TDR_LASTXFER;
+ }
+ SPI->SPI_TDR = dOut;
+
+ // Wait for receive register
+ if (waitForRxReady())
+ {
+ return 0;
+ }
+
+ // Get data from receive register
+ return (uint8_t)SPI->SPI_RDR;
+ }
+
+ spi_status_t ReadBurst(uint8_t* rx_data, size_t len)
+ {
+ for (size_t i = 0; i < len; ++i)
+ {
+ uint32_t dOut = 0x000000FF;
+ if (waitForTxReady())
+ {
+ return SPI_ERROR_TIMEOUT;
+ }
+
+ // Write to transmit register
+ if (i + 1 == len)
+ {
+ dOut |= SPI_TDR_LASTXFER;
+ }
+ SPI->SPI_TDR = dOut;
+
+ // Wait for receive register
+ if (waitForRxReady())
+ {
+ return SPI_ERROR_TIMEOUT;
+ }
+
+ // Get data from receive register
+ *rx_data++ = (uint8_t)SPI->SPI_RDR;
+ }
+
+ return SPI_OK;
+ }
+
+ spi_status_t SendBurst(const uint8_t* tx_data, size_t len)
+ {
+ for (uint32_t i = 0; i < len; ++i)
+ {
+ uint32_t dOut = (uint32_t)*tx_data++;
+ if (waitForTxReady())
+ {
+ return SPI_ERROR_TIMEOUT;
+ }
+
+ // Write to transmit register
+ if (i + 1 == len)
+ {
+ dOut |= SPI_TDR_LASTXFER;
+ }
+ SPI->SPI_TDR = dOut;
+ // Wait for receive register
+ if (waitForRxReady())
+ {
+ return SPI_ERROR_TIMEOUT;
+ }
+
+ // Get data from receive register
+ (void)SPI->SPI_RDR;
+ }
+
+ return SPI_OK;
+ }
+
+} // end namespace
+
+// End
diff --git a/src/DuetNG/DuetEthernet/Wiznet/Ethernet/WizSpi.h b/src/DuetNG/DuetEthernet/Wiznet/Ethernet/WizSpi.h
new file mode 100644
index 00000000..2829e168
--- /dev/null
+++ b/src/DuetNG/DuetEthernet/Wiznet/Ethernet/WizSpi.h
@@ -0,0 +1,25 @@
+/*
+ * Spi.h
+ *
+ * Created on: 16 Dec 2016
+ * Author: David
+ */
+
+#ifndef SRC_DUETNG_DUETETHERNET_ETHERNET3_UTILITY_WIZSPI_H_
+#define SRC_DUETNG_DUETETHERNET_ETHERNET3_UTILITY_WIZSPI_H_
+
+#include "spi.h"
+
+namespace WizSpi
+{
+ void Init();
+ void Stop();
+ void AssertSS();
+ void ReleaseSS();
+ void SendAddress(uint32_t addr);
+ uint8_t ExchangeByte(uint8_t b, bool isLast);
+ spi_status_t ReadBurst(uint8_t* rx_data, size_t len);
+ spi_status_t SendBurst(const uint8_t* tx_data, size_t len);
+}
+
+#endif /* SRC_DUETNG_DUETETHERNET_ETHERNET3_UTILITY_WIZSPI_H_ */
diff --git a/src/DuetNG/DuetEthernet/Wiznet/Ethernet/socket.cpp b/src/DuetNG/DuetEthernet/Wiznet/Ethernet/socket.cpp
index 5aeca9b8..a647d08a 100644
--- a/src/DuetNG/DuetEthernet/Wiznet/Ethernet/socket.cpp
+++ b/src/DuetNG/DuetEthernet/Wiznet/Ethernet/socket.cpp
@@ -55,6 +55,18 @@
//*****************************************************************************
#include "socket.h"
+#define _SOCKET_DEBUG_
+
+#ifdef _SOCKET_DEBUG_
+extern "C" void debugPrintf(const char *fmt, ...);
+extern "C" void delay(uint32_t);
+# define DEBUG_PRINTF(...) debugPrintf(__VA_ARGS__)
+#else
+# define DEBUG_PRINTF(_fmt, ...)
+#endif
+
+
+
#define SOCK_ANY_PORT_NUM 0xC000
static uint16_t sock_any_port = SOCK_ANY_PORT_NUM;
@@ -82,7 +94,7 @@ uint8_t sock_pack_info[_WIZCHIP_SOCK_NUM_] = {0,};
static void ExecCommand(uint8_t sn, uint8_t cmd)
{
- setSn_CR(sn, Sn_CR_OPEN);
+ setSn_CR(sn, cmd);
while(getSn_CR(sn) != 0) { }
}
@@ -309,6 +321,7 @@ int32_t send(uint8_t sn, uint8_t * buf, uint16_t len)
{
break;
}
+ DEBUG_PRINTF("Socket %u need %u free %u\n", sn, len, freesize);
}
wiz_send_data(sn, buf, len);
@@ -373,7 +386,7 @@ int32_t recv(uint8_t sn, uint8_t * buf, uint16_t len)
return (int32_t)len;
}
-int32_t sendto(uint8_t sn, uint8_t * buf, uint16_t len, uint8_t * addr, uint16_t port)
+int32_t sendto(uint8_t sn, const uint8_t * buf, uint16_t len, const uint8_t * addr, uint16_t port)
{
switch(getSn_MR(sn) & 0x0F)
{
@@ -426,10 +439,10 @@ int32_t sendto(uint8_t sn, uint8_t * buf, uint16_t len, uint8_t * addr, uint16_t
{
break;
}
+ DEBUG_PRINTF("Socket %u need %u free %u\n", sn, len, freesize);
};
wiz_send_data(sn, buf, len);
-
ExecCommand(sn, Sn_CR_SEND);
while(1)
@@ -445,6 +458,10 @@ int32_t sendto(uint8_t sn, uint8_t * buf, uint16_t len, uint8_t * addr, uint16_t
setSn_IR(sn, Sn_IR_TIMEOUT);
return SOCKERR_TIMEOUT;
}
+ DEBUG_PRINTF("Socket %u waiting for send to complete, IR=%02x\n", sn, tmp);
+#ifdef _SOCKET_DEBUG_
+ delay(10); // to avoid too many messages
+#endif
}
return (int32_t)len;
}
diff --git a/src/DuetNG/DuetEthernet/Wiznet/Ethernet/socket.h b/src/DuetNG/DuetEthernet/Wiznet/Ethernet/socket.h
index d7da7a8f..24bb7f7c 100644
--- a/src/DuetNG/DuetEthernet/Wiznet/Ethernet/socket.h
+++ b/src/DuetNG/DuetEthernet/Wiznet/Ethernet/socket.h
@@ -294,7 +294,7 @@ int32_t recv(uint8_t sn, uint8_t * buf, uint16_t len);
* @ref SOCKERR_TIMEOUT - Timeout occurred \n
* @ref SOCK_BUSY - Socket is busy.
*/
-int32_t sendto(uint8_t sn, uint8_t * buf, uint16_t len, uint8_t * addr, uint16_t port);
+int32_t sendto(uint8_t sn, const uint8_t * buf, uint16_t len, const uint8_t * addr, uint16_t port);
/**
* @ingroup WIZnet_socket_APIs
diff --git a/src/DuetNG/DuetEthernet/Wiznet/Ethernet/wizchip_conf.cpp b/src/DuetNG/DuetEthernet/Wiznet/Ethernet/wizchip_conf.cpp
index 85d19e26..6e3a8c2c 100644
--- a/src/DuetNG/DuetEthernet/Wiznet/Ethernet/wizchip_conf.cpp
+++ b/src/DuetNG/DuetEthernet/Wiznet/Ethernet/wizchip_conf.cpp
@@ -53,6 +53,7 @@
#include <cstddef>
#include <cstring>
#include "wizchip_conf.h"
+#include "WizSpi.h"
/**
* @\ref WIZCHIP instance data
@@ -181,8 +182,9 @@ void wizchip_sw_reset(void)
setSIPR(sip);
}
-int8_t wizchip_init(uint8_t* txsize, uint8_t* rxsize)
+int8_t wizchip_init(const uint8_t* txsize, const uint8_t* rxsize)
{
+ WizSpi::Init();
wizchip_sw_reset();
if (txsize != nullptr)
{
diff --git a/src/DuetNG/DuetEthernet/Wiznet/Ethernet/wizchip_conf.h b/src/DuetNG/DuetEthernet/Wiznet/Ethernet/wizchip_conf.h
index edb0f590..ceeec9a6 100644
--- a/src/DuetNG/DuetEthernet/Wiznet/Ethernet/wizchip_conf.h
+++ b/src/DuetNG/DuetEthernet/Wiznet/Ethernet/wizchip_conf.h
@@ -305,7 +305,7 @@ int8_t ctlnetwork(ctlnetwork_type cntype, void* arg);
* @ingroup extra_functions
* @brief Reset WIZCHIP by softly.
*/
-void wizchip_sw_reset(void);
+void wizchip_sw_reset(void);
/**
* @ingroup extra_functions
@@ -315,7 +315,7 @@ void wizchip_sw_reset(void);
* @return 0 : succcess \n
* -1 : fail. Invalid buffer size
*/
-int8_t wizchip_init(uint8_t* txsize, uint8_t* rxsize);
+int8_t wizchip_init(const uint8_t* txsize, const uint8_t* rxsize);
/**
* @ingroup extra_functions
diff --git a/src/DuetNG/DuetEthernet/Wiznet/Internet/DHCP/dhcp.cpp b/src/DuetNG/DuetEthernet/Wiznet/Internet/DHCP/dhcp.cpp
new file mode 100644
index 00000000..079f72bf
--- /dev/null
+++ b/src/DuetNG/DuetEthernet/Wiznet/Internet/DHCP/dhcp.cpp
@@ -0,0 +1,1004 @@
+//*****************************************************************************
+//
+//! \file dhcp.c
+//! \brief DHCP APIs implement file.
+//! \details Processig DHCP protocol as DISCOVER, OFFER, REQUEST, ACK, NACK and DECLINE.
+//! \version 1.1.0
+//! \date 2013/11/18
+//! \par Revision history
+//! <2013/11/18> 1st Release
+//! <2012/12/20> V1.1.0
+//! 1. Optimize code
+//! 2. Add reg_dhcp_cbfunc()
+//! 3. Add DHCP_stop()
+//! 4. Integrate check_DHCP_state() & DHCP_run() to DHCP_run()
+//! 5. Don't care system endian
+//! 6. Add comments
+//! <2012/12/26> V1.1.1
+//! 1. Modify variable declaration: dhcp_tick_1s is declared volatile for code optimization
+//! \author Eric Jung & MidnightCow
+//! \copyright
+//!
+//! Copyright (c) 2013, WIZnet Co., LTD.
+//! All rights reserved.
+//!
+//! Redistribution and use in source and binary forms, with or without
+//! modification, are permitted provided that the following conditions
+//! are met:
+//!
+//! * Redistributions of source code must retain the above copyright
+//! notice, this list of conditions and the following disclaimer.
+//! * Redistributions in binary form must reproduce the above copyright
+//! notice, this list of conditions and the following disclaimer in the
+//! documentation and/or other materials provided with the distribution.
+//! * Neither the name of the <ORGANIZATION> nor the names of its
+//! contributors may be used to endorse or promote products derived
+//! from this software without specific prior written permission.
+//!
+//! THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+//! AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+//! IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+//! ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+//! LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+//! CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+//! SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+//! INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+//! CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+//! ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+//! THE POSSIBILITY OF SUCH DAMAGE.
+//
+//*****************************************************************************
+
+#include "socket.h"
+#include "dhcp.h"
+#include <cstring>
+
+/* If you want to display debug & processing message, Define _DHCP_DEBUG_ in dhcp.h */
+
+#define _DHCP_DEBUG_
+
+#ifdef _DHCP_DEBUG_
+extern "C" void debugPrintf(const char *fmt, ...);
+# define DEBUG_PRINTF(...) debugPrintf(__VA_ARGS__)
+#else
+# define DEBUG_PRINTF(_fmt, ...)
+#endif
+
+/* DHCP state machine. */
+#define STATE_DHCP_INIT 0 ///< Initialize
+#define STATE_DHCP_DISCOVER 1 ///< send DISCOVER and wait OFFER
+#define STATE_DHCP_REQUEST 2 ///< send REQEUST and wait ACK or NACK
+#define STATE_DHCP_LEASED 3 ///< ReceiveD ACK and IP leased
+#define STATE_DHCP_REREQUEST 4 ///< send REQUEST for maintaining leased IP
+#define STATE_DHCP_RELEASE 5 ///< No use
+#define STATE_DHCP_STOP 6 ///< Stop processing DHCP
+
+#define DHCP_FLAGSBROADCAST 0x8000 ///< The broadcast value of flags in @ref RIP_MSG
+#define DHCP_FLAGSUNICAST 0x0000 ///< The unicast value of flags in @ref RIP_MSG
+
+/* DHCP message OP code */
+#define DHCP_BOOTREQUEST 1 ///< Request Message used in op of @ref RIP_MSG
+#define DHCP_BOOTREPLY 2 ///< Reply Message used i op of @ref RIP_MSG
+
+/* DHCP message type */
+#define DHCP_DISCOVER 1 ///< DISCOVER message in OPT of @ref RIP_MSG
+#define DHCP_OFFER 2 ///< OFFER message in OPT of @ref RIP_MSG
+#define DHCP_REQUEST 3 ///< REQUEST message in OPT of @ref RIP_MSG
+#define DHCP_DECLINE 4 ///< DECLINE message in OPT of @ref RIP_MSG
+#define DHCP_ACK 5 ///< ACK message in OPT of @ref RIP_MSG
+#define DHCP_NAK 6 ///< NACK message in OPT of @ref RIP_MSG
+#define DHCP_RELEASE 7 ///< RELEASE message in OPT of @ref RIP_MSG. No use
+#define DHCP_INFORM 8 ///< INFORM message in OPT of @ref RIP_MSG. No use
+
+#define DHCP_HTYPE10MB 1 ///< Used in type of @ref RIP_MSG
+#define DHCP_HTYPE100MB 2 ///< Used in type of @ref RIP_MSG
+
+#define DHCP_HLENETHERNET 6 ///< Used in hlen of @ref RIP_MSG
+#define DHCP_HOPS 0 ///< Used in hops of @ref RIP_MSG
+#define DHCP_SECS 0 ///< Used in secs of @ref RIP_MSG
+
+#define INFINITE_LEASETIME 0xffffffff ///< Infinite lease time
+
+#define OPT_SIZE 312 /// Max OPT size of @ref RIP_MSG
+#define RIP_MSG_SIZE (236+OPT_SIZE) /// Max size of @ref RIP_MSG
+
+/*
+ * @brief DHCP option and value (cf. RFC1533)
+ */
+enum
+{
+ padOption = 0,
+ subnetMask = 1,
+ timerOffset = 2,
+ routersOnSubnet = 3,
+ timeServer = 4,
+ nameServer = 5,
+ dns = 6,
+ logServer = 7,
+ cookieServer = 8,
+ lprServer = 9,
+ impressServer = 10,
+ resourceLocationServer = 11,
+ hostName = 12,
+ bootFileSize = 13,
+ meritDumpFile = 14,
+ domainName = 15,
+ swapServer = 16,
+ rootPath = 17,
+ extentionsPath = 18,
+ IPforwarding = 19,
+ nonLocalSourceRouting = 20,
+ policyFilter = 21,
+ maxDgramReasmSize = 22,
+ defaultIPTTL = 23,
+ pathMTUagingTimeout = 24,
+ pathMTUplateauTable = 25,
+ ifMTU = 26,
+ allSubnetsLocal = 27,
+ broadcastAddr = 28,
+ performMaskDiscovery = 29,
+ maskSupplier = 30,
+ performRouterDiscovery = 31,
+ routerSolicitationAddr = 32,
+ staticRoute = 33,
+ trailerEncapsulation = 34,
+ arpCacheTimeout = 35,
+ ethernetEncapsulation = 36,
+ tcpDefaultTTL = 37,
+ tcpKeepaliveInterval = 38,
+ tcpKeepaliveGarbage = 39,
+ nisDomainName = 40,
+ nisServers = 41,
+ ntpServers = 42,
+ vendorSpecificInfo = 43,
+ netBIOSnameServer = 44,
+ netBIOSdgramDistServer = 45,
+ netBIOSnodeType = 46,
+ netBIOSscope = 47,
+ xFontServer = 48,
+ xDisplayManager = 49,
+ dhcpRequestedIPaddr = 50,
+ dhcpIPaddrLeaseTime = 51,
+ dhcpOptionOverload = 52,
+ dhcpMessageType = 53,
+ dhcpServerIdentifier = 54,
+ dhcpParamRequest = 55,
+ dhcpMsg = 56,
+ dhcpMaxMsgSize = 57,
+ dhcpT1value = 58,
+ dhcpT2value = 59,
+ dhcpClassIdentifier = 60,
+ dhcpClientIdentifier = 61,
+ endOption = 255
+};
+
+/*
+ * @brief DHCP message format
+ */
+typedef struct {
+ uint8_t op; ///< @ref DHCP_BOOTREQUEST or @ref DHCP_BOOTREPLY
+ uint8_t htype; ///< @ref DHCP_HTYPE10MB or @ref DHCP_HTYPE100MB
+ uint8_t hlen; ///< @ref DHCP_HLENETHERNET
+ uint8_t hops; ///< @ref DHCP_HOPS
+ uint32_t xid; ///< @ref DHCP_XID This increase one every DHCP transaction.
+ uint16_t secs; ///< @ref DHCP_SECS
+ uint16_t flags; ///< @ref DHCP_FLAGSBROADCAST or @ref DHCP_FLAGSUNICAST
+ uint8_t ciaddr[4]; ///< @ref Request IP to DHCP sever
+ uint8_t yiaddr[4]; ///< @ref Offered IP from DHCP server
+ uint8_t siaddr[4]; ///< No use
+ uint8_t giaddr[4]; ///< No use
+ uint8_t chaddr[16]; ///< DHCP client 6bytes MAC address. Others is filled to zero
+ uint8_t sname[64]; ///< No use
+ uint8_t file[128]; ///< No use
+ uint8_t OPT[OPT_SIZE]; ///< Option
+} RIP_MSG;
+
+
+
+uint8_t DHCP_SOCKET; // Socket number for DHCP
+
+uint8_t DHCP_SIP[4]; // DHCP Server IP address
+
+// Network information from DHCP Server
+uint8_t OLD_allocated_ip[4] = {0, }; // Previous IP address
+uint8_t DHCP_allocated_ip[4] = {0, }; // IP address from DHCP
+uint8_t DHCP_allocated_gw[4] = {0, }; // Gateway address from DHCP
+uint8_t DHCP_allocated_sn[4] = {0, }; // Subnet mask from DHCP
+uint8_t DHCP_allocated_dns[4] = {0, }; // DNS address from DHCP
+
+
+int8_t dhcp_state = STATE_DHCP_INIT; // DHCP state
+int8_t dhcp_retry_count = 0;
+
+uint32_t dhcp_lease_time = INFINITE_LEASETIME;
+volatile uint32_t dhcp_tick_1s = 0; // unit 1 second
+uint32_t dhcp_tick_next = DHCP_WAIT_TIME ;
+
+uint32_t DHCP_XID; // Any number
+
+static RIP_MSG dhcpMessageBuffer;
+RIP_MSG* const pDHCPMSG = &dhcpMessageBuffer; // Buffer pointer for DHCP processing
+
+char HOST_NAME[16] = DCHP_HOST_NAME;
+uint8_t DHCP_CHADDR[6]; // DHCP Client MAC address.
+
+/* The default callback function */
+void default_ip_assign(void);
+void default_ip_update(void);
+void default_ip_conflict(void);
+
+/* Callback handler */
+void (*dhcp_ip_assign)(void) = default_ip_assign; /* handler to be called when the IP address from DHCP server is first assigned */
+void (*dhcp_ip_update)(void) = default_ip_update; /* handler to be called when the IP address from DHCP server is updated */
+void (*dhcp_ip_conflict)(void) = default_ip_conflict; /* handler to be called when the IP address from DHCP server is conflict */
+
+void reg_dhcp_cbfunc(void(*ip_assign)(void), void(*ip_update)(void), void(*ip_conflict)(void));
+
+
+/* send DISCOVER message to DHCP server */
+void send_DHCP_DISCOVER(void);
+
+/* send REQEUST message to DHCP server */
+void send_DHCP_REQUEST(void);
+
+/* send DECLINE message to DHCP server */
+void send_DHCP_DECLINE(void);
+
+/* IP conflict check by sending ARP-request to leased IP and wait ARP-response. */
+bool check_DHCP_leasedIP(void);
+
+/* check the timeout in DHCP process */
+DhcpRunResult check_DHCP_timeout(void);
+
+/* Initialize to timeout process. */
+void reset_DHCP_timeout(void);
+
+/* Parse message as OFFER and ACK and NACK from DHCP server.*/
+int8_t parseDHCPMSG(void);
+
+/* The default handler of ip assign first */
+void default_ip_assign(void)
+{
+ setSIPR(DHCP_allocated_ip);
+ setSUBR(DHCP_allocated_sn);
+ setGAR (DHCP_allocated_gw);
+}
+
+/* The default handler of ip chaged */
+void default_ip_update(void)
+{
+ /* WIZchip Software Reset */
+ setMR(MR_RST);
+ getMR(); // for delay
+ default_ip_assign();
+ setSHAR(DHCP_CHADDR);
+}
+
+/* The default handler of ip chaged */
+void default_ip_conflict(void)
+{
+ // WIZchip Software Reset
+ setMR(MR_RST);
+ getMR(); // for delay
+ setSHAR(DHCP_CHADDR);
+}
+
+/* register the call back func. */
+void reg_dhcp_cbfunc(void(*ip_assign)(void), void(*ip_update)(void), void(*ip_conflict)(void))
+{
+ dhcp_ip_assign = default_ip_assign;
+ dhcp_ip_update = default_ip_update;
+ dhcp_ip_conflict = default_ip_conflict;
+ if(ip_assign) { dhcp_ip_assign = ip_assign; }
+ if(ip_update) { dhcp_ip_update = ip_update; }
+ if(ip_conflict) { dhcp_ip_conflict = ip_conflict; }
+}
+
+/* make the common DHCP message */
+void makeDHCPMSG(void)
+{
+ uint8_t bk_mac[6];
+ getSHAR(bk_mac);
+ pDHCPMSG->op = DHCP_BOOTREQUEST;
+ pDHCPMSG->htype = DHCP_HTYPE10MB;
+ pDHCPMSG->hlen = DHCP_HLENETHERNET;
+ pDHCPMSG->hops = DHCP_HOPS;
+ uint8_t* ptmp = (uint8_t*)(&pDHCPMSG->xid);
+ *(ptmp+0) = (uint8_t)((DHCP_XID & 0xFF000000) >> 24);
+ *(ptmp+1) = (uint8_t)((DHCP_XID & 0x00FF0000) >> 16);
+ *(ptmp+2) = (uint8_t)((DHCP_XID & 0x0000FF00) >> 8);
+ *(ptmp+3) = (uint8_t)((DHCP_XID & 0x000000FF) >> 0);
+ pDHCPMSG->secs = DHCP_SECS;
+ ptmp = (uint8_t*)(&pDHCPMSG->flags);
+ *(ptmp+0) = (uint8_t)((DHCP_FLAGSBROADCAST & 0xFF00) >> 8);
+ *(ptmp+1) = (uint8_t)((DHCP_FLAGSBROADCAST & 0x00FF) >> 0);
+
+ pDHCPMSG->ciaddr[0] = 0;
+ pDHCPMSG->ciaddr[1] = 0;
+ pDHCPMSG->ciaddr[2] = 0;
+ pDHCPMSG->ciaddr[3] = 0;
+
+ pDHCPMSG->yiaddr[0] = 0;
+ pDHCPMSG->yiaddr[1] = 0;
+ pDHCPMSG->yiaddr[2] = 0;
+ pDHCPMSG->yiaddr[3] = 0;
+
+ pDHCPMSG->siaddr[0] = 0;
+ pDHCPMSG->siaddr[1] = 0;
+ pDHCPMSG->siaddr[2] = 0;
+ pDHCPMSG->siaddr[3] = 0;
+
+ pDHCPMSG->giaddr[0] = 0;
+ pDHCPMSG->giaddr[1] = 0;
+ pDHCPMSG->giaddr[2] = 0;
+ pDHCPMSG->giaddr[3] = 0;
+
+ pDHCPMSG->chaddr[0] = DHCP_CHADDR[0];
+ pDHCPMSG->chaddr[1] = DHCP_CHADDR[1];
+ pDHCPMSG->chaddr[2] = DHCP_CHADDR[2];
+ pDHCPMSG->chaddr[3] = DHCP_CHADDR[3];
+ pDHCPMSG->chaddr[4] = DHCP_CHADDR[4];
+ pDHCPMSG->chaddr[5] = DHCP_CHADDR[5];
+
+ for (size_t i = 6; i < 16; i++)
+ {
+ pDHCPMSG->chaddr[i] = 0;
+ }
+ for (size_t i = 0; i < 64; i++)
+ {
+ pDHCPMSG->sname[i] = 0;
+ }
+ for (size_t i = 0; i < 128; i++)
+ {
+ pDHCPMSG->file[i] = 0;
+ }
+
+ // MAGIC_COOKIE
+ pDHCPMSG->OPT[0] = (uint8_t)((MAGIC_COOKIE & 0xFF000000) >> 24);
+ pDHCPMSG->OPT[1] = (uint8_t)((MAGIC_COOKIE & 0x00FF0000) >> 16);
+ pDHCPMSG->OPT[2] = (uint8_t)((MAGIC_COOKIE & 0x0000FF00) >> 8);
+ pDHCPMSG->OPT[3] = (uint8_t) (MAGIC_COOKIE & 0x000000FF) >> 0;
+}
+
+/* SEND DHCP DISCOVER */
+void send_DHCP_DISCOVER(void)
+{
+ makeDHCPMSG();
+
+ size_t k = 4; // because MAGIC_COOKIE already made by makeDHCPMSG()
+
+ // Option Request Param
+ pDHCPMSG->OPT[k++] = dhcpMessageType;
+ pDHCPMSG->OPT[k++] = 0x01;
+ pDHCPMSG->OPT[k++] = DHCP_DISCOVER;
+
+ // Client identifier
+ pDHCPMSG->OPT[k++] = dhcpClientIdentifier;
+ pDHCPMSG->OPT[k++] = 0x07;
+ pDHCPMSG->OPT[k++] = 0x01;
+ pDHCPMSG->OPT[k++] = DHCP_CHADDR[0];
+ pDHCPMSG->OPT[k++] = DHCP_CHADDR[1];
+ pDHCPMSG->OPT[k++] = DHCP_CHADDR[2];
+ pDHCPMSG->OPT[k++] = DHCP_CHADDR[3];
+ pDHCPMSG->OPT[k++] = DHCP_CHADDR[4];
+ pDHCPMSG->OPT[k++] = DHCP_CHADDR[5];
+
+ // host name
+ pDHCPMSG->OPT[k++] = hostName;
+ pDHCPMSG->OPT[k++] = 0; // fill zero length of hostname
+ size_t i;
+ for (i = 0 ; HOST_NAME[i] != 0; i++)
+ {
+ pDHCPMSG->OPT[k++] = HOST_NAME[i];
+ }
+ pDHCPMSG->OPT[k - (i+1)] = i; // length of hostname
+ pDHCPMSG->OPT[k++] = dhcpParamRequest;
+ pDHCPMSG->OPT[k++] = 0x06; // length of request
+ pDHCPMSG->OPT[k++] = subnetMask;
+ pDHCPMSG->OPT[k++] = routersOnSubnet;
+ pDHCPMSG->OPT[k++] = dns;
+ pDHCPMSG->OPT[k++] = domainName;
+ pDHCPMSG->OPT[k++] = dhcpT1value;
+ pDHCPMSG->OPT[k++] = dhcpT2value;
+ pDHCPMSG->OPT[k++] = endOption;
+
+ for (i = k; i < OPT_SIZE; i++)
+ {
+ pDHCPMSG->OPT[i] = 0;
+ }
+
+ // send broadcasting packet
+ uint8_t ip[4];
+ ip[0] = 255;
+ ip[1] = 255;
+ ip[2] = 255;
+ ip[3] = 255;
+
+ DEBUG_PRINTF("> Send DHCP_DISCOVER\n");
+
+ sendto(DHCP_SOCKET, (uint8_t *)pDHCPMSG, RIP_MSG_SIZE, ip, DHCP_SERVER_PORT);
+ DEBUG_PRINTF("Sent\n");
+}
+
+/* SEND DHCP REQUEST */
+void send_DHCP_REQUEST(void)
+{
+
+ makeDHCPMSG();
+
+ uint8_t ip[4];
+ if (dhcp_state == STATE_DHCP_LEASED || dhcp_state == STATE_DHCP_REREQUEST)
+ {
+ *((uint8_t*)(&pDHCPMSG->flags)) = ((DHCP_FLAGSUNICAST & 0xFF00)>> 8);
+ *((uint8_t*)(&pDHCPMSG->flags)+1) = (DHCP_FLAGSUNICAST & 0x00FF);
+ pDHCPMSG->ciaddr[0] = DHCP_allocated_ip[0];
+ pDHCPMSG->ciaddr[1] = DHCP_allocated_ip[1];
+ pDHCPMSG->ciaddr[2] = DHCP_allocated_ip[2];
+ pDHCPMSG->ciaddr[3] = DHCP_allocated_ip[3];
+ ip[0] = DHCP_SIP[0];
+ ip[1] = DHCP_SIP[1];
+ ip[2] = DHCP_SIP[2];
+ ip[3] = DHCP_SIP[3];
+ }
+ else
+ {
+ ip[0] = 255;
+ ip[1] = 255;
+ ip[2] = 255;
+ ip[3] = 255;
+ }
+
+ size_t k = 4; // because MAGIC_COOKIE already made by makeDHCPMSG()
+
+ // Option Request Param.
+ pDHCPMSG->OPT[k++] = dhcpMessageType;
+ pDHCPMSG->OPT[k++] = 0x01;
+ pDHCPMSG->OPT[k++] = DHCP_REQUEST;
+
+ pDHCPMSG->OPT[k++] = dhcpClientIdentifier;
+ pDHCPMSG->OPT[k++] = 0x07;
+ pDHCPMSG->OPT[k++] = 0x01;
+ pDHCPMSG->OPT[k++] = DHCP_CHADDR[0];
+ pDHCPMSG->OPT[k++] = DHCP_CHADDR[1];
+ pDHCPMSG->OPT[k++] = DHCP_CHADDR[2];
+ pDHCPMSG->OPT[k++] = DHCP_CHADDR[3];
+ pDHCPMSG->OPT[k++] = DHCP_CHADDR[4];
+ pDHCPMSG->OPT[k++] = DHCP_CHADDR[5];
+
+ if (ip[3] == 255) // if(dchp_state == STATE_DHCP_LEASED || dchp_state == DHCP_REREQUEST_STATE)
+ {
+ pDHCPMSG->OPT[k++] = dhcpRequestedIPaddr;
+ pDHCPMSG->OPT[k++] = 0x04;
+ pDHCPMSG->OPT[k++] = DHCP_allocated_ip[0];
+ pDHCPMSG->OPT[k++] = DHCP_allocated_ip[1];
+ pDHCPMSG->OPT[k++] = DHCP_allocated_ip[2];
+ pDHCPMSG->OPT[k++] = DHCP_allocated_ip[3];
+
+ pDHCPMSG->OPT[k++] = dhcpServerIdentifier;
+ pDHCPMSG->OPT[k++] = 0x04;
+ pDHCPMSG->OPT[k++] = DHCP_SIP[0];
+ pDHCPMSG->OPT[k++] = DHCP_SIP[1];
+ pDHCPMSG->OPT[k++] = DHCP_SIP[2];
+ pDHCPMSG->OPT[k++] = DHCP_SIP[3];
+ }
+
+ // host name
+ pDHCPMSG->OPT[k++] = hostName;
+ pDHCPMSG->OPT[k++] = 0; // length of hostname
+ size_t i;
+ for (i = 0 ; HOST_NAME[i] != 0; i++)
+ {
+ pDHCPMSG->OPT[k++] = HOST_NAME[i];
+ }
+ pDHCPMSG->OPT[k - (i+1)] = i; // length of hostname
+ pDHCPMSG->OPT[k++] = dhcpParamRequest;
+ pDHCPMSG->OPT[k++] = 0x08;
+ pDHCPMSG->OPT[k++] = subnetMask;
+ pDHCPMSG->OPT[k++] = routersOnSubnet;
+ pDHCPMSG->OPT[k++] = dns;
+ pDHCPMSG->OPT[k++] = domainName;
+ pDHCPMSG->OPT[k++] = dhcpT1value;
+ pDHCPMSG->OPT[k++] = dhcpT2value;
+ pDHCPMSG->OPT[k++] = performRouterDiscovery;
+ pDHCPMSG->OPT[k++] = staticRoute;
+ pDHCPMSG->OPT[k++] = endOption;
+
+ for (size_t i = k; i < OPT_SIZE; i++)
+ {
+ pDHCPMSG->OPT[i] = 0;
+ }
+
+ DEBUG_PRINTF("> Send DHCP_REQUEST\n");
+
+ sendto(DHCP_SOCKET, (uint8_t *)pDHCPMSG, RIP_MSG_SIZE, ip, DHCP_SERVER_PORT);
+}
+
+/* SEND DHCP DHCPDECLINE */
+void send_DHCP_DECLINE(void)
+{
+ makeDHCPMSG();
+
+ size_t k = 4; // beacaue MAGIC_COOKIE already made by makeDHCPMSG()
+
+ *((uint8_t*)(&pDHCPMSG->flags)) = ((DHCP_FLAGSUNICAST & 0xFF00)>> 8);
+ *((uint8_t*)(&pDHCPMSG->flags)+1) = (DHCP_FLAGSUNICAST & 0x00FF);
+
+ // Option Request Param.
+ pDHCPMSG->OPT[k++] = dhcpMessageType;
+ pDHCPMSG->OPT[k++] = 0x01;
+ pDHCPMSG->OPT[k++] = DHCP_DECLINE;
+
+ pDHCPMSG->OPT[k++] = dhcpClientIdentifier;
+ pDHCPMSG->OPT[k++] = 0x07;
+ pDHCPMSG->OPT[k++] = 0x01;
+ pDHCPMSG->OPT[k++] = DHCP_CHADDR[0];
+ pDHCPMSG->OPT[k++] = DHCP_CHADDR[1];
+ pDHCPMSG->OPT[k++] = DHCP_CHADDR[2];
+ pDHCPMSG->OPT[k++] = DHCP_CHADDR[3];
+ pDHCPMSG->OPT[k++] = DHCP_CHADDR[4];
+ pDHCPMSG->OPT[k++] = DHCP_CHADDR[5];
+
+ pDHCPMSG->OPT[k++] = dhcpRequestedIPaddr;
+ pDHCPMSG->OPT[k++] = 0x04;
+ pDHCPMSG->OPT[k++] = DHCP_allocated_ip[0];
+ pDHCPMSG->OPT[k++] = DHCP_allocated_ip[1];
+ pDHCPMSG->OPT[k++] = DHCP_allocated_ip[2];
+ pDHCPMSG->OPT[k++] = DHCP_allocated_ip[3];
+
+ pDHCPMSG->OPT[k++] = dhcpServerIdentifier;
+ pDHCPMSG->OPT[k++] = 0x04;
+ pDHCPMSG->OPT[k++] = DHCP_SIP[0];
+ pDHCPMSG->OPT[k++] = DHCP_SIP[1];
+ pDHCPMSG->OPT[k++] = DHCP_SIP[2];
+ pDHCPMSG->OPT[k++] = DHCP_SIP[3];
+
+ pDHCPMSG->OPT[k++] = endOption;
+
+ for (size_t i = k; i < OPT_SIZE; i++)
+ {
+ pDHCPMSG->OPT[i] = 0;
+ }
+
+ //send broadcasting packet
+ uint8_t ip[4];
+ ip[0] = 0xFF;
+ ip[1] = 0xFF;
+ ip[2] = 0xFF;
+ ip[3] = 0xFF;
+
+ DEBUG_PRINTF("\n> Send DHCP_DECLINE\n");
+
+ sendto(DHCP_SOCKET, (uint8_t *)pDHCPMSG, RIP_MSG_SIZE, ip, DHCP_SERVER_PORT);
+}
+
+/* PARSE REPLY pDHCPMSG */
+int8_t parseDHCPMSG(void)
+{
+ uint8_t type = 0;
+ uint16_t len;
+ if ((len = getSn_RX_RSR(DHCP_SOCKET)) > 0)
+ {
+ if (len > sizeof(RIP_MSG))
+ {
+ len = sizeof(RIP_MSG);
+ }
+
+ uint8_t svr_addr[6];
+ uint16_t svr_port;
+ len = recvfrom(DHCP_SOCKET, (uint8_t *)pDHCPMSG, len, svr_addr, &svr_port);
+
+ DEBUG_PRINTF("DHCP message : %d.%d.%d.%d(%d) %d received. \n", svr_addr[0], svr_addr[1], svr_addr[2], svr_addr[3],svr_port, len);
+
+ if (svr_port == DHCP_SERVER_PORT)
+ {
+ // compare mac address
+ if ( (pDHCPMSG->chaddr[0] == DHCP_CHADDR[0]) && (pDHCPMSG->chaddr[1] == DHCP_CHADDR[1])
+ && (pDHCPMSG->chaddr[2] == DHCP_CHADDR[2]) && (pDHCPMSG->chaddr[3] == DHCP_CHADDR[3])
+ && (pDHCPMSG->chaddr[4] == DHCP_CHADDR[4]) && (pDHCPMSG->chaddr[5] == DHCP_CHADDR[5])
+ )
+ {
+ const uint8_t *p = (uint8_t *)(&pDHCPMSG->op);
+ p = p + 240; // 240 = sizeof(RIP_MSG) + MAGIC_COOKIE size in RIP_MSG.opt - sizeof(RIP_MSG.opt)
+ const uint8_t * const e = p + (len - 240);
+
+ while (p < e)
+ {
+ switch (*p )
+ {
+ case endOption :
+ p = e; // for break while(p < e)
+ break;
+ case padOption :
+ p++;
+ break;
+ case dhcpMessageType :
+ p++;
+ p++;
+ type = *p++;
+ break;
+ case subnetMask :
+ p++;
+ p++;
+ DHCP_allocated_sn[0] = *p++;
+ DHCP_allocated_sn[1] = *p++;
+ DHCP_allocated_sn[2] = *p++;
+ DHCP_allocated_sn[3] = *p++;
+ break;
+ case routersOnSubnet :
+ {
+ p++;
+ const uint8_t opt_len = *p++;
+ DHCP_allocated_gw[0] = *p++;
+ DHCP_allocated_gw[1] = *p++;
+ DHCP_allocated_gw[2] = *p++;
+ DHCP_allocated_gw[3] = *p++;
+ p = p + (opt_len - 4);
+ }
+ break;
+ case dns :
+ {
+ p++;
+ const uint8_t opt_len = *p++;
+ DHCP_allocated_dns[0] = *p++;
+ DHCP_allocated_dns[1] = *p++;
+ DHCP_allocated_dns[2] = *p++;
+ DHCP_allocated_dns[3] = *p++;
+ p = p + (opt_len - 4);
+ }
+ break;
+ case dhcpIPaddrLeaseTime :
+ {
+ p++;
+ p++;
+ dhcp_lease_time = *p++;
+ dhcp_lease_time = (dhcp_lease_time << 8) + *p++;
+ dhcp_lease_time = (dhcp_lease_time << 8) + *p++;
+ dhcp_lease_time = (dhcp_lease_time << 8) + *p++;
+#if 0 //#ifdef _DHCP_DEBUG_
+ dhcp_lease_time = 10;
+#endif
+ }
+ break;
+ case dhcpServerIdentifier :
+ {
+ p++;
+ p++;
+ DHCP_SIP[0] = *p++;
+ DHCP_SIP[1] = *p++;
+ DHCP_SIP[2] = *p++;
+ DHCP_SIP[3] = *p++;
+ }
+ break;
+
+ default :
+ {
+ p++;
+ const uint8_t opt_len = *p++;
+ p += opt_len;
+ }
+ break;
+ } // switch
+ } // while
+ } // if
+ } // if
+ } // if
+ return type;
+}
+
+DhcpRunResult DHCP_run(void)
+{
+ if (dhcp_state == STATE_DHCP_STOP)
+ {
+ return DhcpRunResult::DHCP_STOPPED;
+ }
+
+ if (getSn_SR(DHCP_SOCKET) != SOCK_UDP)
+ {
+ socket(DHCP_SOCKET, Sn_MR_UDP, DHCP_CLIENT_PORT, 0x00);
+ }
+
+ DhcpRunResult ret = DhcpRunResult::DHCP_RUNNING;
+ const uint8_t type = parseDHCPMSG();
+
+ switch (dhcp_state)
+ {
+ case STATE_DHCP_INIT:
+ DHCP_allocated_ip[0] = 0;
+ DHCP_allocated_ip[1] = 0;
+ DHCP_allocated_ip[2] = 0;
+ DHCP_allocated_ip[3] = 0;
+ send_DHCP_DISCOVER();
+ dhcp_state = STATE_DHCP_DISCOVER;
+ break;
+
+ case STATE_DHCP_DISCOVER:
+ if (type == DHCP_OFFER)
+ {
+ DEBUG_PRINTF("> Receive DHCP_OFFER\n");
+ DHCP_allocated_ip[0] = pDHCPMSG->yiaddr[0];
+ DHCP_allocated_ip[1] = pDHCPMSG->yiaddr[1];
+ DHCP_allocated_ip[2] = pDHCPMSG->yiaddr[2];
+ DHCP_allocated_ip[3] = pDHCPMSG->yiaddr[3];
+
+ send_DHCP_REQUEST();
+ dhcp_state = STATE_DHCP_REQUEST;
+ }
+ else
+ {
+ ret = check_DHCP_timeout();
+ }
+ break;
+
+ case STATE_DHCP_REQUEST :
+ if (type == DHCP_ACK)
+ {
+ DEBUG_PRINTF("> Receive DHCP_ACK\n");
+ if (check_DHCP_leasedIP())
+ {
+ // Network info assignment from DHCP
+ dhcp_ip_assign();
+ reset_DHCP_timeout();
+ dhcp_state = STATE_DHCP_LEASED;
+ ret = DhcpRunResult::DHCP_IP_ASSIGN;
+ }
+ else
+ {
+ // IP address conflict occurred
+ reset_DHCP_timeout();
+ dhcp_ip_conflict();
+ dhcp_state = STATE_DHCP_INIT;
+ }
+ }
+ else if (type == DHCP_NAK)
+ {
+ DEBUG_PRINTF("> Receive DHCP_NACK\n");
+ reset_DHCP_timeout();
+ dhcp_state = STATE_DHCP_DISCOVER;
+ }
+ else
+ {
+ ret = check_DHCP_timeout();
+ }
+ break;
+
+ case STATE_DHCP_LEASED :
+ ret = DhcpRunResult::DHCP_IP_LEASED;
+ if ((dhcp_lease_time != INFINITE_LEASETIME) && ((dhcp_lease_time/2) < dhcp_tick_1s))
+ {
+ DEBUG_PRINTF("> Maintains the IP address \n");
+ OLD_allocated_ip[0] = DHCP_allocated_ip[0];
+ OLD_allocated_ip[1] = DHCP_allocated_ip[1];
+ OLD_allocated_ip[2] = DHCP_allocated_ip[2];
+ OLD_allocated_ip[3] = DHCP_allocated_ip[3];
+
+ DHCP_XID++;
+
+ send_DHCP_REQUEST();
+ reset_DHCP_timeout();
+ dhcp_state = STATE_DHCP_REREQUEST;
+ }
+ break;
+
+ case STATE_DHCP_REREQUEST :
+ ret = DhcpRunResult::DHCP_IP_LEASED;
+ if (type == DHCP_ACK)
+ {
+ dhcp_retry_count = 0;
+ if (OLD_allocated_ip[0] != DHCP_allocated_ip[0] ||
+ OLD_allocated_ip[1] != DHCP_allocated_ip[1] ||
+ OLD_allocated_ip[2] != DHCP_allocated_ip[2] ||
+ OLD_allocated_ip[3] != DHCP_allocated_ip[3])
+ {
+ ret = DhcpRunResult::DHCP_IP_CHANGED;
+ dhcp_ip_update();
+ DEBUG_PRINTF(">IP changed.\n");
+ }
+ else
+ {
+ DEBUG_PRINTF(">IP is continued.\n");
+ }
+ reset_DHCP_timeout();
+ dhcp_state = STATE_DHCP_LEASED;
+ }
+ else if (type == DHCP_NAK)
+ {
+ DEBUG_PRINTF("> Receive DHCP_NACK, Failed to maintain ip\n");
+ reset_DHCP_timeout();
+ dhcp_state = STATE_DHCP_DISCOVER;
+ }
+ else
+ {
+ ret = check_DHCP_timeout();
+ }
+ break;
+
+ default :
+ break;
+ }
+
+ return ret;
+}
+
+void DHCP_stop(void)
+{
+ close(DHCP_SOCKET);
+ dhcp_state = STATE_DHCP_STOP;
+}
+
+DhcpRunResult check_DHCP_timeout(void)
+{
+ DhcpRunResult ret = DhcpRunResult::DHCP_RUNNING;
+
+ if (dhcp_retry_count < MAX_DHCP_RETRY)
+ {
+ if (dhcp_tick_next < dhcp_tick_1s)
+ {
+ switch ( dhcp_state )
+ {
+ case STATE_DHCP_DISCOVER :
+ DEBUG_PRINTF("<<timeout>> state : STATE_DHCP_DISCOVER\n");
+ send_DHCP_DISCOVER();
+ break;
+
+ case STATE_DHCP_REQUEST :
+ DEBUG_PRINTF("<<timeout>> state : STATE_DHCP_REQUEST\n");
+
+ send_DHCP_REQUEST();
+ break;
+
+ case STATE_DHCP_REREQUEST :
+ DEBUG_PRINTF("<<timeout>> state : STATE_DHCP_REREQUEST\n");
+
+ send_DHCP_REQUEST();
+ break;
+
+ default :
+ break;
+ }
+
+ dhcp_tick_1s = 0;
+ dhcp_tick_next = dhcp_tick_1s + DHCP_WAIT_TIME;
+ dhcp_retry_count++;
+ }
+ }
+ else
+ { // exceeded retry count
+ switch(dhcp_state)
+ {
+ case STATE_DHCP_DISCOVER:
+ dhcp_state = STATE_DHCP_INIT;
+ ret = DhcpRunResult::DHCP_FAILED;
+ break;
+ case STATE_DHCP_REQUEST:
+ case STATE_DHCP_REREQUEST:
+ send_DHCP_DISCOVER();
+ dhcp_state = STATE_DHCP_DISCOVER;
+ break;
+ default :
+ break;
+ }
+ reset_DHCP_timeout();
+ }
+ return ret;
+}
+
+bool check_DHCP_leasedIP(void)
+{
+ uint8_t tmp;
+ int32_t ret;
+
+ //WIZchip RCR value changed for ARP Timeout count control
+ tmp = getRCR();
+ setRCR(0x03);
+
+ // IP conflict detection : ARP request - ARP reply
+ // Broadcasting ARP Request for check the IP conflict using UDP sendto() function
+ // TODO the following takes 620ms to time out - hanging for this long isn't very nice
+ ret = sendto(DHCP_SOCKET, (const uint8_t *)"CHECK_IP_CONFLICT", 17, DHCP_allocated_ip, 5000);
+
+ // RCR value restore
+ setRCR(tmp);
+
+ if (ret == SOCKERR_TIMEOUT)
+ {
+ // UDP send Timeout occurred : allocated IP address is unique, DHCP Success
+ DEBUG_PRINTF("\n> Check leased IP - OK\n");
+ return true;
+ }
+ else
+ {
+ // Received ARP reply or etc : IP address conflict occur, DHCP Failed
+ send_DHCP_DECLINE();
+
+ ret = dhcp_tick_1s;
+ //TODO can't tolerate a 1 to 2 second wait here
+ while((dhcp_tick_1s - ret) < 2) { } // wait for 1s over; wait to complete to send DECLINE message;
+
+ return false;
+ }
+}
+
+void DHCP_init(uint8_t s, const char *hname)
+{
+ strncpy(HOST_NAME, hname, sizeof(HOST_NAME));
+ HOST_NAME[sizeof(HOST_NAME) - 1] = 0;
+
+ uint8_t zeroip[4] = {0,0,0,0};
+ getSHAR(DHCP_CHADDR);
+ DEBUG_PRINTF("MAC address: %02x:%02x:%02x:%02x:%02x:%02x\n", DHCP_CHADDR[0], DHCP_CHADDR[1], DHCP_CHADDR[2], DHCP_CHADDR[3], DHCP_CHADDR[4], DHCP_CHADDR[5]);
+
+ if ((DHCP_CHADDR[0] | DHCP_CHADDR[1] | DHCP_CHADDR[2] | DHCP_CHADDR[3] | DHCP_CHADDR[4] | DHCP_CHADDR[5]) == 0x00)
+ {
+ // assing temporary mac address, you should be set SHAR before call this function.
+ DHCP_CHADDR[0] = 0x00;
+ DHCP_CHADDR[1] = 0x08;
+ DHCP_CHADDR[2] = 0xdc;
+ DHCP_CHADDR[3] = 0x00;
+ DHCP_CHADDR[4] = 0x00;
+ DHCP_CHADDR[5] = 0x00;
+ setSHAR(DHCP_CHADDR);
+ }
+
+ DHCP_SOCKET = s; // SOCK_DHCP
+ DHCP_XID = 0x12345678;
+
+ // WIZchip Netinfo Clear
+ setSIPR(zeroip);
+ setSIPR(zeroip);
+ setGAR(zeroip);
+
+ reset_DHCP_timeout();
+ dhcp_state = STATE_DHCP_INIT;
+}
+
+/* Rset the DHCP timeout count and retry count. */
+void reset_DHCP_timeout(void)
+{
+ dhcp_tick_1s = 0;
+ dhcp_tick_next = DHCP_WAIT_TIME;
+ dhcp_retry_count = 0;
+}
+
+void DHCP_time_handler(void)
+{
+ dhcp_tick_1s++;
+}
+
+void getIPfromDHCP(uint8_t* ip)
+{
+ ip[0] = DHCP_allocated_ip[0];
+ ip[1] = DHCP_allocated_ip[1];
+ ip[2] = DHCP_allocated_ip[2];
+ ip[3] = DHCP_allocated_ip[3];
+}
+
+void getGWfromDHCP(uint8_t* ip)
+{
+ ip[0] =DHCP_allocated_gw[0];
+ ip[1] =DHCP_allocated_gw[1];
+ ip[2] =DHCP_allocated_gw[2];
+ ip[3] =DHCP_allocated_gw[3];
+}
+
+void getSNfromDHCP(uint8_t* ip)
+{
+ ip[0] = DHCP_allocated_sn[0];
+ ip[1] = DHCP_allocated_sn[1];
+ ip[2] = DHCP_allocated_sn[2];
+ ip[3] = DHCP_allocated_sn[3];
+}
+
+void getDNSfromDHCP(uint8_t* ip)
+{
+ ip[0] = DHCP_allocated_dns[0];
+ ip[1] = DHCP_allocated_dns[1];
+ ip[2] = DHCP_allocated_dns[2];
+ ip[3] = DHCP_allocated_dns[3];
+}
+
+uint32_t getDHCPLeasetime(void)
+{
+ return dhcp_lease_time;
+}
+
+// End
diff --git a/src/DuetNG/DuetEthernet/Wiznet/Internet/DHCP/dhcp.h b/src/DuetNG/DuetEthernet/Wiznet/Internet/DHCP/dhcp.h
new file mode 100644
index 00000000..4f238b6e
--- /dev/null
+++ b/src/DuetNG/DuetEthernet/Wiznet/Internet/DHCP/dhcp.h
@@ -0,0 +1,144 @@
+//*****************************************************************************
+//
+//! \file dhcp.h
+//! \brief DHCP APIs Header file.
+//! \details Processig DHCP protocol as DISCOVER, OFFER, REQUEST, ACK, NACK and DECLINE.
+//! \version 1.1.0
+//! \date 2013/11/18
+//! \par Revision history
+//! <2013/11/18> 1st Release
+//! <2012/12/20> V1.1.0
+//! 1. Move unreferenced DEFINE to dhcp.c
+//! <2012/12/26> V1.1.1
+//! \author Eric Jung & MidnightCow
+//! \copyright
+//!
+//! Copyright (c) 2013, WIZnet Co., LTD.
+//! All rights reserved.
+//!
+//! Redistribution and use in source and binary forms, with or without
+//! modification, are permitted provided that the following conditions
+//! are met:
+//!
+//! * Redistributions of source code must retain the above copyright
+//! notice, this list of conditions and the following disclaimer.
+//! * Redistributions in binary form must reproduce the above copyright
+//! notice, this list of conditions and the following disclaimer in the
+//! documentation and/or other materials provided with the distribution.
+//! * Neither the name of the <ORGANIZATION> nor the names of its
+//! contributors may be used to endorse or promote products derived
+//! from this software without specific prior written permission.
+//!
+//! THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+//! AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+//! IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+//! ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+//! LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+//! CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+//! SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+//! INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+//! CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+//! ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+//! THE POSSIBILITY OF SUCH DAMAGE.
+//
+//*****************************************************************************
+#ifndef _DHCP_H_
+#define _DHCP_H_
+
+/* Retry to processing DHCP */
+#define MAX_DHCP_RETRY 2 ///< Maxium retry count
+#define DHCP_WAIT_TIME 10 ///< Wait Time 10s
+
+
+/* UDP port numbers for DHCP */
+#define DHCP_SERVER_PORT 67 ///< DHCP server port number
+#define DHCP_CLIENT_PORT 68 ///< DHCP client port number
+
+
+#define MAGIC_COOKIE 0x63825363 ///< Any number. You can be modified it any number
+
+#define DCHP_HOST_NAME "DuetEthernet"
+
+/*
+ * @brief return value of @ref DHCP_run()
+ */
+enum class DhcpRunResult : uint8_t
+{
+ DHCP_FAILED = 0, ///< Processing Fail
+ DHCP_RUNNING, ///< Processing DHCP protocol
+ DHCP_IP_ASSIGN, ///< First Occupy IP from DHPC server (if cbfunc == null, act as default default_ip_assign)
+ DHCP_IP_CHANGED, ///< Change IP address by new ip from DHCP (if cbfunc == null, act as default default_ip_update)
+ DHCP_IP_LEASED, ///< Stand by
+ DHCP_STOPPED ///< Stop processing DHCP protocol
+};
+
+/*
+ * @brief DHCP client initialization (outside of the main loop)
+ * @param s - socket number
+ * @param hname - null-terminated host name string
+ */
+void DHCP_init(uint8_t s, const char *hname);
+
+/*
+ * @brief DHCP 1s Tick Timer handler
+ * @note SHOULD BE register to your system 1s Tick timer handler
+ */
+void DHCP_time_handler(void);
+
+/*
+ * @brief Register call back function
+ * @param ip_assign - callback func when IP is assigned from DHCP server first
+ * @param ip_update - callback func when IP is changed
+ * @prarm ip_conflict - callback func when the assigned IP is conflict with others.
+ */
+void reg_dhcp_cbfunc(void(*ip_assign)(void), void(*ip_update)(void), void(*ip_conflict)(void));
+
+/*
+ * @brief DHCP client in the main loop
+ * @return The value is as the follow \n
+ * @ref DHCP_FAILED \n
+ * @ref DHCP_RUNNING \n
+ * @ref DHCP_IP_ASSIGN \n
+ * @ref DHCP_IP_CHANGED \n
+ * @ref DHCP_IP_LEASED \n
+ * @ref DHCP_STOPPED \n
+ *
+ * @note This function is always called by you main task.
+ */
+DhcpRunResult DHCP_run(void);
+
+/*
+ * @brief Stop DHCP processing
+ * @note If you want to restart. call DHCP_init() and DHCP_run()
+ */
+void DHCP_stop(void);
+
+/* Get Network information assigned from DHCP server */
+/*
+ * @brief Get IP address
+ * @param ip - IP address to be returned
+ */
+void getIPfromDHCP(uint8_t* ip);
+/*
+ * @brief Get Gateway address
+ * @param ip - Gateway address to be returned
+ */
+void getGWfromDHCP(uint8_t* ip);
+/*
+ * @brief Get Subnet mask value
+ * @param ip - Subnet mask to be returned
+ */
+void getSNfromDHCP(uint8_t* ip);
+/*
+ * @brief Get DNS address
+ * @param ip - DNS address to be returned
+ */
+void getDNSfromDHCP(uint8_t* ip);
+
+/*
+ * @brief Get the leased time by DHCP sever
+ * @return unit 1s
+ */
+uint32_t getDHCPLeasetime(void);
+
+#endif /* _DHCP_H_ */
diff --git a/src/DuetNG/DuetWiFi/Network.cpp b/src/DuetNG/DuetWiFi/Network.cpp
index 3b9c6226..31aa3459 100644
--- a/src/DuetNG/DuetWiFi/Network.cpp
+++ b/src/DuetNG/DuetWiFi/Network.cpp
@@ -743,7 +743,7 @@ const uint8_t *Network::GetIPAddress() const
uint16_t Network::GetHttpPort() const
{
- return DEFAULT_HTTP_PORT;
+ return DefaultHttpPort;
}
void Network::SetHttpPort(uint16_t port)
diff --git a/src/DuetNG/DuetWiFi/Network.h b/src/DuetNG/DuetWiFi/Network.h
index a4bf3759..2d403412 100644
--- a/src/DuetNG/DuetWiFi/Network.h
+++ b/src/DuetNG/DuetWiFi/Network.h
@@ -21,10 +21,10 @@ const uint32_t rcNumber = 0x0000FFFF;
const uint32_t rcJson = 0x00010000;
const uint32_t rcKeepOpen = 0x00020000;
-static const uint8_t IP_ADDRESS[4] = { 192, 168, 1, 10 }; // Need some sort of default...
-static const uint8_t NET_MASK[4] = { 255, 255, 255, 0 };
-static const uint8_t GATE_WAY[4] = { 192, 168, 1, 1 };
-static const uint16_t DEFAULT_HTTP_PORT = 80;
+static const uint8_t DefaultIpAddress[4] = { 192, 168, 1, 10 }; // Need some sort of default...
+static const uint8_t DefaultNetMask[4] = { 255, 255, 255, 0 };
+static const uint8_t DefaultGateway[4] = { 192, 168, 1, 1 };
+static const uint16_t DefaultHttpPort = 80;
class TransactionBuffer;
class WifiFirmwareUploader;
diff --git a/src/Platform.cpp b/src/Platform.cpp
index 972f7877..b118ba5d 100644
--- a/src/Platform.cpp
+++ b/src/Platform.cpp
@@ -208,15 +208,15 @@ void Platform::Init()
SERIAL_AUX2_DEVICE.begin(baudRates[2]);
#endif
- compatibility = marlin; // default to Marlin because the common host programs expect the "OK" response to commands
- ARRAY_INIT(ipAddress, IP_ADDRESS);
- ARRAY_INIT(netMask, NET_MASK);
- ARRAY_INIT(gateWay, GATE_WAY);
+ compatibility = marlin; // default to Marlin because the common host programs expect the "OK" response to commands
+ ARRAY_INIT(ipAddress, DefaultIpAddress);
+ ARRAY_INIT(netMask, DefaultNetMask);
+ ARRAY_INIT(gateWay, DefaultGateway);
#if defined(DUET_NG) && defined(DUET_WIFI)
memset(macAddress, 0xFF, sizeof(macAddress));
#else
- ARRAY_INIT(macAddress, MAC_ADDRESS);
+ ARRAY_INIT(macAddress, DefaultMacAddress);
#endif
zProbeType = 0; // Default is to use no Z probe switch
@@ -435,7 +435,7 @@ void Platform::Init()
}
#endif
- // MCU temperature and power monitoring
+ // MCU temperature monitoring - doesn't work in RADDS due to pin assignmentgs and SAM3X chip bug
#ifndef __RADDS__
temperatureAdcChannel = GetTemperatureAdcChannel();
AnalogInEnableChannel(temperatureAdcChannel, true);
@@ -446,6 +446,7 @@ void Platform::Init()
mcuTemperatureAdjust = 0.0;
#ifdef DUET_NG
+ // Power monitoring
vInMonitorAdcChannel = PinToAdcChannel(PowerMonitorVinDetectPin);
pinMode(PowerMonitorVinDetectPin, AIN);
AnalogInEnableChannel(vInMonitorAdcChannel, true);