diff --git a/docs/api.md b/docs/api.md index 76265c82..c8117e06 100644 --- a/docs/api.md +++ b/docs/api.md @@ -473,6 +473,83 @@ void setup() { void loop () {} ``` +### `Ethernet.setHostName()` + +#### Description + +Set the hostname of the device. This is used in DHCP requests and responses. + + +#### Syntax + +``` +Ethernet.setHostName(hostName) + +``` + +#### Parameters +- hostName: the hostname of the device (const char*) + +#### Returns +Nothing + +#### Example + +``` +#include +#include + +byte mac[] = {0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED}; +char hostName[] = "NameOfTheDevice"; + +void setup() { + Ethernet.setHostName(hostName); + Ethernet.begin(mac); +} + +void loop () {} +``` + +### `Ethernet.getHostName()` + +#### Description + +Get the hostname of the device. This is used in DHCP requests and responses. + + +#### Syntax + +``` +Ethernet.getHostName() + +``` + +#### Parameters +none + +#### Returns +- hostName: the hostname of the device (const char*) + +#### Example + +``` +#include +#include + +byte mac[] = {0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED}; + +void setup() { + Ethernet.begin(mac); + const char* hostName = Ethernet.getHostName(); + + Serial.begin(9600); + Serial.print("Host name: "); + Serial.println(hostName); +} + +void loop () {} +``` + ### `Ethernet.setGatewayIP()` #### Description diff --git a/examples/SetHostName/SetHostName.ino b/examples/SetHostName/SetHostName.ino new file mode 100644 index 00000000..5eb08c23 --- /dev/null +++ b/examples/SetHostName/SetHostName.ino @@ -0,0 +1,61 @@ +/* + Set Host Name + + This example shows you how to set the host name with the Ethernet library. + + Circuit: + * Ethernet shield attached to pins 10, 11, 12, 13 + + created 28 May 2023 + by Attila Herczog +*/ + +#include +#include + +// Enter a MAC address for your controller below. +// Newer Ethernet shields have a MAC address printed on a sticker on the shield +byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; + +// Host name to use +char hostName[] = "ExampleHostName"; + +void setup() +{ + // Open serial communications and wait for port to open: + Serial.begin(9600); + while (!Serial) + { + ; // wait for serial port to connect. Needed for native USB port only + } + Serial.println("Host Name Example"); + + // Set the Host Name + // Call this function before Ethernet.begin() to set your host name. + Ethernet.setHostName(hostName); + + // Start the Ethernet connection and the server: + Ethernet.begin(mac); + + // Check for Ethernet hardware present + if (Ethernet.hardwareStatus() == EthernetNoHardware) + { + Serial.println("Ethernet shield was not found. Sorry, can't run without hardware. :("); + while (true) + { + delay(1); // do nothing, no point running without Ethernet hardware + } + } + if (Ethernet.linkStatus() == LinkOFF) + { + Serial.println("Ethernet cable is not connected."); + } + + Serial.print("My IP is: "); + Serial.println(Ethernet.localIP()); + Serial.print("My host name is: "); + Serial.println(Ethernet.getHostName()); + Serial.println("You can now check your router's DHCP table to see the assigned host name."); +} + +void loop() {} diff --git a/src/Dhcp.cpp b/src/Dhcp.cpp index 2bfd584b..aa12c721 100644 --- a/src/Dhcp.cpp +++ b/src/Dhcp.cpp @@ -6,13 +6,14 @@ #include "Dhcp.h" #include "utility/w5100.h" -int DhcpClass::beginWithDHCP(uint8_t *mac, unsigned long timeout, unsigned long responseTimeout) +int DhcpClass::beginWithDHCP(uint8_t *mac, const char *hostName, unsigned long timeout, unsigned long responseTimeout) { _dhcpLeaseTime=0; _dhcpT1=0; _dhcpT2=0; _timeout = timeout; _responseTimeout = responseTimeout; + _dhcpHostName = hostName; // zero out _dhcpMacAddr memset(_dhcpMacAddr, 0, 6); @@ -186,17 +187,16 @@ void DhcpClass::send_DHCP_MESSAGE(uint8_t messageType, uint16_t secondsElapsed) buffer[9] = 0x01; memcpy(buffer + 10, _dhcpMacAddr, 6); - // OPT - host name - buffer[16] = hostName; - buffer[17] = strlen(HOST_NAME) + 6; // length of hostname + last 3 bytes of mac address - strcpy((char*)&(buffer[18]), HOST_NAME); + _dhcpUdpSocket.write(buffer, 16); - printByte((char*)&(buffer[24]), _dhcpMacAddr[3]); - printByte((char*)&(buffer[26]), _dhcpMacAddr[4]); - printByte((char*)&(buffer[28]), _dhcpMacAddr[5]); + // OPT - host name + buffer[0] = hostName; + uint8_t hostNameLength = strlen(_dhcpHostName); + buffer[1] = hostNameLength; + strcpy((char*)&(buffer[2]), _dhcpHostName); //put data in W5100 transmit buffer - _dhcpUdpSocket.write(buffer, 30); + _dhcpUdpSocket.write(buffer, hostNameLength + 2); if (messageType == DHCP_REQUEST) { buffer[0] = dhcpRequestedIPaddr; diff --git a/src/Dhcp.h b/src/Dhcp.h index 43ec4f85..1b3ed2a3 100644 --- a/src/Dhcp.h +++ b/src/Dhcp.h @@ -42,7 +42,6 @@ #define MAGIC_COOKIE 0x63825363 #define MAX_DHCP_OPT 16 -#define HOST_NAME "WIZnet" #define DEFAULT_LEASE (900) //default lease time in seconds #define DHCP_CHECK_NONE (0) diff --git a/src/Ethernet.cpp b/src/Ethernet.cpp index 8d9ce7fd..4c6dd5c9 100644 --- a/src/Ethernet.cpp +++ b/src/Ethernet.cpp @@ -25,6 +25,8 @@ IPAddress EthernetClass::_dnsServerAddress; DhcpClass* EthernetClass::_dhcp = NULL; +bool EthernetClass::_manualHostName = false; +char EthernetClass::_hostName[HOST_NAME_MAX_LEN] = ""; int EthernetClass::begin(uint8_t *mac, unsigned long timeout, unsigned long responseTimeout) { @@ -38,8 +40,13 @@ int EthernetClass::begin(uint8_t *mac, unsigned long timeout, unsigned long resp W5100.setIPAddress(IPAddress(0,0,0,0).raw_address()); SPI.endTransaction(); + // Generate a default host name based on the MAC address if not already set by user + if(!_manualHostName) { + generateDefaultHostName(mac); + } + // Now try to get our config info from a DHCP server - int ret = _dhcp->beginWithDHCP(mac, timeout, responseTimeout); + int ret = _dhcp->beginWithDHCP(mac, _hostName, timeout, responseTimeout); if (ret == 1) { // We've successfully found a DHCP server and got our configuration // info, so set things accordingly @@ -224,6 +231,32 @@ void EthernetClass::setRetransmissionCount(uint8_t num) SPI.endTransaction(); } +void EthernetClass::generateDefaultHostName(uint8_t *mac) { + // Generate a default host name based on the MAC address + strcpy_P(_hostName, PSTR(DEFAULT_HOST_NAME)); + + // Append last 3 bytes of MAC address to the name + PGM_P hexChars = PSTR("0123456789ABCDEF"); + for (int i = 0; i <= 2; i++) + { + _hostName[DEFAULT_HOST_NAME_LENGTH + i * 2] = pgm_read_byte_near(hexChars + (mac[3 + i] >> 4)); + _hostName[DEFAULT_HOST_NAME_LENGTH + i * 2 + 1] = pgm_read_byte_near(hexChars + (mac[3 + i] & 0x0F)); + } + _hostName[DEFAULT_HOST_NAME_LENGTH + 6] = '\0'; +} + +void EthernetClass::setHostName(const char *dhcpHost) { + // Copy the host name and ensure it is null terminated + strncpy(_hostName, dhcpHost, HOST_NAME_MAX_LEN); + _hostName[HOST_NAME_MAX_LEN - 1] = '\0'; + + // Indicate that a host name has been set manually + _manualHostName = true; +} + +char* EthernetClass::getHostName() { + return _hostName; +} diff --git a/src/Ethernet.h b/src/Ethernet.h index 0045de88..1a29853a 100644 --- a/src/Ethernet.h +++ b/src/Ethernet.h @@ -53,6 +53,10 @@ #include "Server.h" #include "Udp.h" +#define DEFAULT_HOST_NAME "WIZnet" +#define DEFAULT_HOST_NAME_LENGTH (sizeof(DEFAULT_HOST_NAME) - 1) +#define HOST_NAME_MAX_LEN 20 // Max 30 or change the DHCP local buffer size + enum EthernetLinkStatus { Unknown, LinkON, @@ -75,6 +79,8 @@ class EthernetClass { private: static IPAddress _dnsServerAddress; static DhcpClass* _dhcp; + static char _hostName[HOST_NAME_MAX_LEN]; + static bool _manualHostName; public: // Initialise the Ethernet shield to use the provided MAC address and // gain the rest of the configuration through DHCP. @@ -104,6 +110,8 @@ class EthernetClass { void setDnsServerIP(const IPAddress dns_server) { _dnsServerAddress = dns_server; } void setRetransmissionTimeout(uint16_t milliseconds); void setRetransmissionCount(uint8_t num); + void setHostName(const char *hostName); + char* getHostName(); friend class EthernetClient; friend class EthernetServer; @@ -142,6 +150,7 @@ class EthernetClass { static bool socketSendUDP(uint8_t s); // Initialize the "random" source port number static void socketPortRand(uint16_t n); + static void generateDefaultHostName(uint8_t *mac); }; extern EthernetClass Ethernet; @@ -275,6 +284,7 @@ class DhcpClass { uint32_t _dhcpInitialTransactionId; uint32_t _dhcpTransactionId; uint8_t _dhcpMacAddr[6]; + const char* _dhcpHostName; #ifdef __arm__ uint8_t _dhcpLocalIp[4] __attribute__((aligned(4))); uint8_t _dhcpSubnetMask[4] __attribute__((aligned(4))); @@ -312,7 +322,7 @@ class DhcpClass { IPAddress getDhcpServerIp(); IPAddress getDnsServerIp(); - int beginWithDHCP(uint8_t *, unsigned long timeout = 60000, unsigned long responseTimeout = 4000); + int beginWithDHCP(uint8_t *, const char *hostName, unsigned long timeout = 60000, unsigned long responseTimeout = 4000); int checkLease(); };