From 2fdab09d3c4bd079c306d17d739522b65781b44b Mon Sep 17 00:00:00 2001 From: Leonardo Cavagnis Date: Thu, 31 Jul 2025 18:30:56 +0200 Subject: [PATCH 1/7] ethernet lib: set mac address, log module fix --- libraries/SocketWrapper/Ethernet.h | 44 +++-- libraries/SocketWrapper/SocketHelpers.cpp | 150 +++++++++++++++++ libraries/SocketWrapper/SocketHelpers.h | 189 +++++----------------- loader/llext_exports.c | 6 +- loader/main.c | 2 +- 5 files changed, 228 insertions(+), 163 deletions(-) diff --git a/libraries/SocketWrapper/Ethernet.h b/libraries/SocketWrapper/Ethernet.h index 989420ab..7f3d455d 100644 --- a/libraries/SocketWrapper/Ethernet.h +++ b/libraries/SocketWrapper/Ethernet.h @@ -21,6 +21,21 @@ class EthernetClass: public NetworkInterface EthernetClass() {} virtual ~EthernetClass() {} + int begin(bool blocking = true, uint32_t additional_event_mask = 0) { + hardwareStatus(); + return NetworkInterface::begin(blocking, additional_event_mask); + } + + int begin(uint8_t *mac, unsigned long timeout = 60000, unsigned long responseTimeout = 4000) { + hardwareStatus(); + if (mac != nullptr) { + NetworkInterface::setMACAddress(mac); + } + return NetworkInterface::begin(true, 0); + } + + int maintain(); //TODO + EthernetLinkStatus linkStatus() { hardwareStatus(); if (net_if_is_up(netif)) { @@ -29,20 +44,7 @@ class EthernetClass: public NetworkInterface return LinkOFF; } } - - bool begin(bool blocking = true, uint32_t additional_event_mask = 0) { - hardwareStatus(); - return NetworkInterface::begin(blocking, additional_event_mask); - } - - bool begin(uint8_t* mac_address, int _timeout, int _response_timeout) { - return begin(); - } - - bool begin(uint8_t* mac_address, IPAddress _ip, IPAddress _dns, IPAddress _gateway, IPAddress _netmask, int _timeout, int _response_timeout) { - return begin(); - } - + EthernetHardwareStatus hardwareStatus() { const struct device *const dev = DEVICE_DT_GET(DT_COMPAT_GET_ANY_STATUS_OKAY(ethernet_phy)); if (device_is_ready(dev)) { @@ -57,7 +59,21 @@ class EthernetClass: public NetworkInterface } else { return EthernetNoHardware; } + } + + int begin(uint8_t *mac, IPAddress ip) { + return begin(); //TODO + } + int begin(uint8_t *mac, IPAddress ip, IPAddress dns) { + return begin(); //TODO + } + int begin(uint8_t *mac, IPAddress ip, IPAddress dns, IPAddress gateway) { + return begin(); //TODO } + int begin(uint8_t *mac, IPAddress ip, IPAddress dns, IPAddress gateway, IPAddress subnet) { + return begin(); //TODO + } + void init(uint8_t sspin = 10); //TODO }; extern EthernetClass Ethernet; diff --git a/libraries/SocketWrapper/SocketHelpers.cpp b/libraries/SocketWrapper/SocketHelpers.cpp index aa4d59ab..e61eab3b 100644 --- a/libraries/SocketWrapper/SocketHelpers.cpp +++ b/libraries/SocketWrapper/SocketHelpers.cpp @@ -1,4 +1,154 @@ #include "SocketHelpers.h" +#include +LOG_MODULE_DECLARE(sketch, CONFIG_LOG_DEFAULT_LEVEL); + struct net_mgmt_event_callback NetworkInterface::mgmt_cb; struct net_dhcpv4_option_callback NetworkInterface::dhcp_cb; + +void NetworkInterface::event_handler(struct net_mgmt_event_callback *cb, + uint64_t mgmt_event, + struct net_if *iface) +{ + int i = 0; + + if (mgmt_event != NET_EVENT_IPV4_ADDR_ADD) { + return; + } + + for (i = 0; i < NET_IF_MAX_IPV4_ADDR; i++) { + char buf[NET_IPV4_ADDR_LEN]; + + if (iface->config.ip.ipv4->unicast[i].ipv4.addr_type != + NET_ADDR_DHCP) { + continue; + } + + LOG_INF(" Address[%d]: %s", net_if_get_by_iface(iface), + net_addr_ntop(AF_INET, + &iface->config.ip.ipv4->unicast[i].ipv4.address.in_addr, + buf, sizeof(buf))); + LOG_INF(" Subnet[%d]: %s", net_if_get_by_iface(iface), + net_addr_ntop(AF_INET, + &iface->config.ip.ipv4->unicast[i].netmask, + buf, sizeof(buf))); + LOG_INF(" Router[%d]: %s", net_if_get_by_iface(iface), + net_addr_ntop(AF_INET, + &iface->config.ip.ipv4->gw, + buf, sizeof(buf))); + LOG_INF("Lease time[%d]: %u seconds", net_if_get_by_iface(iface), + iface->config.dhcpv4.lease_time); + } +} + +void NetworkInterface::option_handler(struct net_dhcpv4_option_callback *cb, + size_t length, + enum net_dhcpv4_msg_type msg_type, + struct net_if *iface) +{ + char buf[NET_IPV4_ADDR_LEN]; + + LOG_INF("DHCP Option %d: %s", cb->option, + net_addr_ntop(AF_INET, cb->data, buf, sizeof(buf))); +} + +int NetworkInterface::dhcp() +{ + net_mgmt_init_event_callback(&mgmt_cb, event_handler, NET_EVENT_IPV4_ADDR_ADD | NET_EVENT_IF_UP | NET_EVENT_IF_DOWN); + net_mgmt_add_event_callback(&mgmt_cb); + + net_dhcpv4_init_option_callback(&dhcp_cb, option_handler, + DHCP_OPTION_NTP, ntp_server, + sizeof(ntp_server)); + + net_dhcpv4_add_option_callback(&dhcp_cb); + + net_dhcpv4_start(netif); + + LOG_INF("DHCPv4 started...\n"); + + return 0; +} + +void NetworkInterface::enable_dhcpv4_server(struct net_if *netif, char* _netmask) +{ + static struct in_addr addr; + static struct in_addr netmaskAddr; + + if (net_addr_pton(AF_INET, String(localIP()).c_str(), &addr)) { + LOG_ERR("Invalid address: %s", String(localIP()).c_str()); + return; + } + + if (net_addr_pton(AF_INET, _netmask, &netmaskAddr)) { + LOG_ERR("Invalid netmask: %s", _netmask); + return; + } + + net_if_ipv4_set_gw(netif, &addr); + + if (net_if_ipv4_addr_add(netif, &addr, NET_ADDR_MANUAL, 0) == NULL) { + LOG_ERR("unable to set IP address for AP interface"); + } + + if (!net_if_ipv4_set_netmask_by_addr(netif, &addr, &netmaskAddr)) { + LOG_ERR("Unable to set netmask for AP interface: %s", _netmask); + } + + addr.s4_addr[3] += 10; /* Starting IPv4 address for DHCPv4 address pool. */ + + if (net_dhcpv4_server_start(netif, &addr) != 0) { + LOG_ERR("DHCP server is not started for desired IP"); + return; + } + + LOG_INF("DHCPv4 server started...\n"); +} + +IPAddress NetworkInterface::localIP() { + return IPAddress(netif->config.ip.ipv4->unicast[0].ipv4.address.in_addr.s_addr); +} + +IPAddress NetworkInterface::subnetMask() { + return IPAddress(netif->config.ip.ipv4->unicast[0].netmask.s_addr); +} +IPAddress NetworkInterface::gatewayIP() { + return IPAddress(netif->config.ip.ipv4->gw.s_addr); +} +IPAddress NetworkInterface::dnsServerIP() { + return arduino::INADDR_NONE; +} + +IPAddress NetworkInterface::dnsIP(int n) { + //TODO +} + +void NetworkInterface::setMACAddress(const uint8_t* mac) { + struct net_eth_addr new_mac; + struct ethernet_req_params params = { 0 }; + + memcpy(¶ms.mac_address, &new_mac, sizeof(struct net_eth_addr)); + + net_if_down(netif); // Ensure the interface is down before changing the MAC address + + int ret = net_mgmt(NET_REQUEST_ETHERNET_SET_MAC_ADDRESS, netif, + ¶ms, sizeof(params)); + if (ret != 0) { + LOG_ERR("Failed to set MAC address via net_mgmt, ret=%d", ret); + } else { + LOG_INF("MAC address set successfully via net_mgmt"); + } + + net_if_up(netif); // Bring the interface back up after changing the MAC address +} + +int NetworkInterface::begin(bool blocking, uint32_t additional_event_mask) { + dhcp(); + int ret = net_mgmt_event_wait_on_iface(netif, NET_EVENT_IPV4_ADDR_ADD | additional_event_mask, + NULL, NULL, NULL, blocking ? K_FOREVER : K_SECONDS(1)); + return (ret == 0) ? 1 : 0; +} + +bool NetworkInterface::disconnect() { + return (net_if_down(netif) == 0); +} diff --git a/libraries/SocketWrapper/SocketHelpers.h b/libraries/SocketWrapper/SocketHelpers.h index cf15fefe..ebf85067 100644 --- a/libraries/SocketWrapper/SocketHelpers.h +++ b/libraries/SocketWrapper/SocketHelpers.h @@ -12,157 +12,52 @@ #include #include #include +#include +#include #include #define DHCP_OPTION_NTP (42) -#undef LOG_INF -#define LOG_INF(...) -#undef LOG_ERR -#define LOG_ERR(...) - class NetworkInterface { -private: - - uint8_t ntp_server[4]; - static struct net_mgmt_event_callback mgmt_cb; - static struct net_dhcpv4_option_callback dhcp_cb; - - static void event_handler(struct net_mgmt_event_callback *cb, - uint32_t mgmt_event, - struct net_if *iface) - { - int i = 0; - - if (mgmt_event != NET_EVENT_IPV4_ADDR_ADD) { - return; - } - - for (i = 0; i < NET_IF_MAX_IPV4_ADDR; i++) { - char buf[NET_IPV4_ADDR_LEN]; - - if (iface->config.ip.ipv4->unicast[i].ipv4.addr_type != - NET_ADDR_DHCP) { - continue; - } - - LOG_INF(" Address[%d]: %s", net_if_get_by_iface(iface), - net_addr_ntop(AF_INET, - &iface->config.ip.ipv4->unicast[i].ipv4.address.in_addr, - buf, sizeof(buf))); - LOG_INF(" Subnet[%d]: %s", net_if_get_by_iface(iface), - net_addr_ntop(AF_INET, - &iface->config.ip.ipv4->unicast[i].netmask, - buf, sizeof(buf))); - LOG_INF(" Router[%d]: %s", net_if_get_by_iface(iface), - net_addr_ntop(AF_INET, - &iface->config.ip.ipv4->gw, - buf, sizeof(buf))); - LOG_INF("Lease time[%d]: %u seconds", net_if_get_by_iface(iface), - iface->config.dhcpv4.lease_time); - } - } - - static void option_handler(struct net_dhcpv4_option_callback *cb, - size_t length, - enum net_dhcpv4_msg_type msg_type, - struct net_if *iface) - { - char buf[NET_IPV4_ADDR_LEN]; - - LOG_INF("DHCP Option %d: %s", cb->option, - net_addr_ntop(AF_INET, cb->data, buf, sizeof(buf))); - } - -protected: - - struct net_if *netif = nullptr; - int dhcp() - { - net_mgmt_init_event_callback(&mgmt_cb, event_handler, NET_EVENT_IPV4_ADDR_ADD | NET_EVENT_IF_UP | NET_EVENT_IF_DOWN); - net_mgmt_add_event_callback(&mgmt_cb); - - net_dhcpv4_init_option_callback(&dhcp_cb, option_handler, - DHCP_OPTION_NTP, ntp_server, - sizeof(ntp_server)); - - net_dhcpv4_add_option_callback(&dhcp_cb); - - net_dhcpv4_start(netif); - - return 0; - } - - void enable_dhcpv4_server(struct net_if *netif, char* _netmask = "255.255.255.0") - { - static struct in_addr addr; - static struct in_addr netmaskAddr; - - if (net_addr_pton(AF_INET, String(localIP()).c_str(), &addr)) { - LOG_ERR("Invalid address: %s", String(localIP()).c_str()); - return; - } - - if (net_addr_pton(AF_INET, _netmask, &netmaskAddr)) { - LOG_ERR("Invalid netmask: %s", _netmask); - return; - } - - net_if_ipv4_set_gw(netif, &addr); - - if (net_if_ipv4_addr_add(netif, &addr, NET_ADDR_MANUAL, 0) == NULL) { - LOG_ERR("unable to set IP address for AP interface"); - } - - if (!net_if_ipv4_set_netmask_by_addr(netif, &addr, &netmaskAddr)) { - LOG_ERR("Unable to set netmask for AP interface: %s", _netmask); - } - - addr.s4_addr[3] += 10; /* Starting IPv4 address for DHCPv4 address pool. */ - - if (net_dhcpv4_server_start(netif, &addr) != 0) { - LOG_ERR("DHCP server is not started for desired IP"); - return; - } - - LOG_INF("DHCPv4 server started...\n"); - } - - -public: - NetworkInterface() {} - ~NetworkInterface() {} - IPAddress localIP() { - return IPAddress(netif->config.ip.ipv4->unicast[0].ipv4.address.in_addr.s_addr); - } - - IPAddress subnetMask() { - return IPAddress(netif->config.ip.ipv4->unicast[0].netmask.s_addr); - } - IPAddress gatewayIP() { - return IPAddress(netif->config.ip.ipv4->gw.s_addr); - } - IPAddress dnsServerIP() { - return arduino::INADDR_NONE; - } - - IPAddress dnsIP(int n = 0); - - void setMACAddress(const uint8_t* mac); - - bool begin(bool blocking = true, uint32_t additional_event_mask = 0) { - dhcp(); - int ret = net_mgmt_event_wait_on_iface(netif, NET_EVENT_IPV4_ADDR_ADD | additional_event_mask, - NULL, NULL, NULL, blocking ? K_FOREVER : K_SECONDS(1)); - return (ret == 0); - } - - bool disconnect() { - return (net_if_down(netif) == 0); - } - - // TODO: manual functions for setting IP address, subnet mask, gateway, etc. - // net_if_ipv4_set_netmask_by_addr(iface, &addr4, &nm); - // net_if_ipv4_addr_add(iface, &addr4, NET_ADDR_MANUAL, 0); + private: + uint8_t ntp_server[4]; + static struct net_mgmt_event_callback mgmt_cb; + static struct net_dhcpv4_option_callback dhcp_cb; + + static void event_handler(struct net_mgmt_event_callback *cb, + uint64_t mgmt_event, + struct net_if *iface); + + static void option_handler(struct net_dhcpv4_option_callback *cb, + size_t length, + enum net_dhcpv4_msg_type msg_type, + struct net_if *iface); + + protected: + struct net_if *netif = nullptr; + int dhcp(); + void enable_dhcpv4_server(struct net_if *netif, char* _netmask = "255.255.255.0"); + + public: + NetworkInterface() {} + ~NetworkInterface() {} + + IPAddress localIP(); + + IPAddress subnetMask(); + IPAddress gatewayIP(); + IPAddress dnsServerIP(); + + IPAddress dnsIP(int n = 0); + + void setMACAddress(const uint8_t* mac); + + int begin(bool blocking = true, uint32_t additional_event_mask = 0); + + bool disconnect(); + + // TODO: manual functions for setting IP address, subnet mask, gateway, etc. + // net_if_ipv4_set_netmask_by_addr(iface, &addr4, &nm); + // net_if_ipv4_addr_add(iface, &addr4, NET_ADDR_MANUAL, 0); }; diff --git a/loader/llext_exports.c b/loader/llext_exports.c index f1370a92..5da9b619 100644 --- a/loader/llext_exports.c +++ b/loader/llext_exports.c @@ -66,9 +66,12 @@ EXPORT_SYMBOL(usb_disable); EXPORT_SYMBOL(z_log_msg_runtime_vcreate); +FORCE_EXPORT_SYM(log_dynamic_sketch) + #if defined(CONFIG_NETWORKING) FORCE_EXPORT_SYM(net_if_foreach); FORCE_EXPORT_SYM(net_if_down); +FORCE_EXPORT_SYM(net_if_up); FORCE_EXPORT_SYM(net_if_get_by_iface); FORCE_EXPORT_SYM(net_if_ipv4_maddr_add); FORCE_EXPORT_SYM(net_if_ipv4_maddr_join); @@ -80,6 +83,7 @@ FORCE_EXPORT_SYM(net_if_lookup_by_dev); #if defined(CONFIG_NET_L2_ETHERNET) FORCE_EXPORT_SYM(_net_l2_ETHERNET); +FORCE_EXPORT_SYM(net_mgmt_NET_REQUEST_ETHERNET_SET_MAC_ADDRESS); #endif #if defined(CONFIG_NET_DHCPV4) @@ -239,4 +243,4 @@ FORCE_EXPORT_SYM(__aeabi_dcmpge); #if defined (CONFIG_CPP) FORCE_EXPORT_SYM(__cxa_pure_virtual); -#endif \ No newline at end of file +#endif diff --git a/loader/main.c b/loader/main.c index 643da9d7..0e68e970 100644 --- a/loader/main.c +++ b/loader/main.c @@ -6,7 +6,7 @@ #include "zephyr/sys/printk.h" #include -LOG_MODULE_REGISTER(app); +LOG_MODULE_REGISTER(sketch); #include #include From 03c689e4bf8138e1511da3f79a7b6807462d2384 Mon Sep 17 00:00:00 2001 From: Leonardo Cavagnis Date: Fri, 1 Aug 2025 16:51:42 +0200 Subject: [PATCH 2/7] Ethernet lib: move Ethernet functions implementation in .cpp --- libraries/SocketWrapper/Ethernet.cpp | 67 +++++++++++++++++++++++ libraries/SocketWrapper/Ethernet.h | 79 +++++++++------------------- 2 files changed, 93 insertions(+), 53 deletions(-) diff --git a/libraries/SocketWrapper/Ethernet.cpp b/libraries/SocketWrapper/Ethernet.cpp index 94802bb3..c7607713 100644 --- a/libraries/SocketWrapper/Ethernet.cpp +++ b/libraries/SocketWrapper/Ethernet.cpp @@ -1,5 +1,72 @@ #include "Ethernet.h" #if DT_HAS_COMPAT_STATUS_OKAY(ethernet_phy) + +int EthernetClass::begin(uint8_t *mac, unsigned long timeout, unsigned long responseTimeout) { + setMACAddress(mac); + return NetworkInterface::begin(true, 0); +} + +int EthernetClass::begin(uint8_t *mac, IPAddress ip) { + IPAddress dns = ip; + dns[3] = 1; + + auto ret = begin(mac, ip, dns); + return ret; +} + +int EthernetClass::begin(uint8_t *mac, IPAddress ip, IPAddress dns) { + IPAddress gateway = ip; + gateway[3] = 1; + + auto ret = begin(mac, ip, dns, gateway); + return ret; +} + +int EthernetClass::begin(uint8_t *mac, IPAddress ip, IPAddress dns, IPAddress gateway) { + IPAddress subnet(255, 255, 255, 0); + auto ret = begin(mac, ip, dns, gateway, subnet); + return ret; +} + +int EthernetClass::begin(uint8_t *mac, IPAddress ip, IPAddress dns, IPAddress gateway, IPAddress subnet, unsigned long timeout, unsigned long responseTimeout) { + // TODO: Config the network interface with the provided IP, DNS, gateway, and subnet + + return begin(mac, timeout, responseTimeout); +} + +EthernetLinkStatus EthernetClass::linkStatus() { + if ((hardwareStatus() == EthernetOk) && net_if_is_up(netif)) { + return LinkON; + } + return LinkOFF; +} + +EthernetHardwareStatus EthernetClass::hardwareStatus() { + const struct device *const dev = DEVICE_DT_GET(DT_COMPAT_GET_ANY_STATUS_OKAY(ethernet_phy)); + if (device_is_ready(dev)) { + for (int i = 1; i < 3; i++) { + auto _if = net_if_get_by_index(i); + if (!net_eth_type_is_wifi(_if)) { + netif = _if; + break; + } + } + return EthernetOk; + } else { + return EthernetNoHardware; + } +} + +void EthernetClass::setMACAddress(const uint8_t *mac_address) { + if (mac_address != nullptr) { + NetworkInterface::setMACAddress(mac_address); + } +} + +IPAddress EthernetClass::localIP() { + return NetworkInterface::localIP(); +} + EthernetClass Ethernet; #endif \ No newline at end of file diff --git a/libraries/SocketWrapper/Ethernet.h b/libraries/SocketWrapper/Ethernet.h index 7f3d455d..5a98b49d 100644 --- a/libraries/SocketWrapper/Ethernet.h +++ b/libraries/SocketWrapper/Ethernet.h @@ -21,60 +21,33 @@ class EthernetClass: public NetworkInterface EthernetClass() {} virtual ~EthernetClass() {} - int begin(bool blocking = true, uint32_t additional_event_mask = 0) { - hardwareStatus(); - return NetworkInterface::begin(blocking, additional_event_mask); - } - - int begin(uint8_t *mac, unsigned long timeout = 60000, unsigned long responseTimeout = 4000) { - hardwareStatus(); - if (mac != nullptr) { - NetworkInterface::setMACAddress(mac); - } - return NetworkInterface::begin(true, 0); - } - - int maintain(); //TODO - - EthernetLinkStatus linkStatus() { - hardwareStatus(); - if (net_if_is_up(netif)) { - return LinkON; - } else { - return LinkOFF; - } - } - - EthernetHardwareStatus hardwareStatus() { - const struct device *const dev = DEVICE_DT_GET(DT_COMPAT_GET_ANY_STATUS_OKAY(ethernet_phy)); - if (device_is_ready(dev)) { - for (int i = 1; i < 3; i++) { - auto _if = net_if_get_by_index(i); - if (!net_eth_type_is_wifi(_if)) { - netif = _if; - break; - } - } - return EthernetOk; - } else { - return EthernetNoHardware; - } - } - - int begin(uint8_t *mac, IPAddress ip) { - return begin(); //TODO - } - int begin(uint8_t *mac, IPAddress ip, IPAddress dns) { - return begin(); //TODO - } - int begin(uint8_t *mac, IPAddress ip, IPAddress dns, IPAddress gateway) { - return begin(); //TODO - } - int begin(uint8_t *mac, IPAddress ip, IPAddress dns, IPAddress gateway, IPAddress subnet) { - return begin(); //TODO - } - void init(uint8_t sspin = 10); //TODO + int begin(uint8_t *mac, unsigned long timeout = 60000, unsigned long responseTimeout = 4000); + int maintain(); + EthernetLinkStatus linkStatus(); + EthernetHardwareStatus hardwareStatus(); + + // Manual configuration + int begin(uint8_t *mac, IPAddress ip); + int begin(uint8_t *mac, IPAddress ip, IPAddress dns); + int begin(uint8_t *mac, IPAddress ip, IPAddress dns, IPAddress gateway); + int begin(uint8_t *mac, IPAddress ip, IPAddress dns, IPAddress gateway, IPAddress subnet, unsigned long timeout = 60000, unsigned long responseTimeout = 4000); + void init(uint8_t sspin = 10); + + void MACAddress(uint8_t *mac_address); + IPAddress localIP(); + IPAddress subnetMask(); + IPAddress gatewayIP(); + IPAddress dnsServerIP(); + + void setMACAddress(const uint8_t *mac_address); + void setLocalIP(const IPAddress local_ip); + void setSubnetMask(const IPAddress subnet); + void setGatewayIP(const IPAddress gateway); + void setDnsServerIP(const IPAddress dns_server); + void setRetransmissionTimeout(uint16_t milliseconds); + void setRetransmissionCount(uint8_t num); }; + extern EthernetClass Ethernet; #endif \ No newline at end of file From 7c421d794c8c8f42d428de6b65bd7353f6077dd7 Mon Sep 17 00:00:00 2001 From: Leonardo Cavagnis Date: Fri, 1 Aug 2025 17:32:17 +0200 Subject: [PATCH 3/7] Ethernet lib: (tentative) set manual IP,subnet,gateway --- libraries/SocketWrapper/Ethernet.cpp | 12 ++++++++++-- libraries/SocketWrapper/Ethernet.h | 2 +- libraries/SocketWrapper/SocketHelpers.cpp | 22 ++++++++++++++++++++++ libraries/SocketWrapper/SocketHelpers.h | 1 + 4 files changed, 34 insertions(+), 3 deletions(-) diff --git a/libraries/SocketWrapper/Ethernet.cpp b/libraries/SocketWrapper/Ethernet.cpp index c7607713..e60a833e 100644 --- a/libraries/SocketWrapper/Ethernet.cpp +++ b/libraries/SocketWrapper/Ethernet.cpp @@ -30,9 +30,17 @@ int EthernetClass::begin(uint8_t *mac, IPAddress ip, IPAddress dns, IPAddress ga } int EthernetClass::begin(uint8_t *mac, IPAddress ip, IPAddress dns, IPAddress gateway, IPAddress subnet, unsigned long timeout, unsigned long responseTimeout) { - // TODO: Config the network interface with the provided IP, DNS, gateway, and subnet + setMACAddress(mac); + + if (!NetworkInterface::setLocalIP(ip, subnet, gateway)) { + return 0; + } + + if (!net_if_is_up(netif)) { + net_if_up(netif); + } - return begin(mac, timeout, responseTimeout); + return 1; } EthernetLinkStatus EthernetClass::linkStatus() { diff --git a/libraries/SocketWrapper/Ethernet.h b/libraries/SocketWrapper/Ethernet.h index 5a98b49d..99f81c61 100644 --- a/libraries/SocketWrapper/Ethernet.h +++ b/libraries/SocketWrapper/Ethernet.h @@ -21,7 +21,7 @@ class EthernetClass: public NetworkInterface EthernetClass() {} virtual ~EthernetClass() {} - int begin(uint8_t *mac, unsigned long timeout = 60000, unsigned long responseTimeout = 4000); + int begin(uint8_t *mac = nullptr, unsigned long timeout = 60000, unsigned long responseTimeout = 4000); int maintain(); EthernetLinkStatus linkStatus(); EthernetHardwareStatus hardwareStatus(); diff --git a/libraries/SocketWrapper/SocketHelpers.cpp b/libraries/SocketWrapper/SocketHelpers.cpp index e61eab3b..f877781c 100644 --- a/libraries/SocketWrapper/SocketHelpers.cpp +++ b/libraries/SocketWrapper/SocketHelpers.cpp @@ -152,3 +152,25 @@ int NetworkInterface::begin(bool blocking, uint32_t additional_event_mask) { bool NetworkInterface::disconnect() { return (net_if_down(netif) == 0); } + +bool NetworkInterface::setLocalIP(IPAddress ip, IPAddress subnet, IPAddress gateway) { + struct in_addr ip_addr, subnet_addr, gw_addr; + + ip_addr.s_addr = ip; + subnet_addr.s_addr = subnet; + gw_addr.s_addr = gateway; + + if (!net_if_ipv4_addr_add(netif, &ip_addr, NET_ADDR_MANUAL, 0)) { + LOG_ERR("Failed to set static IP address"); + return false; + } + + if (!net_if_ipv4_set_netmask_by_addr(netif, &ip_addr, &subnet_addr)) { + LOG_ERR("Failed to set subnet mask"); + return false; + } + + net_if_ipv4_set_gw(netif, &gw_addr); + LOG_INF("Static IP configured"); + return true; +} \ No newline at end of file diff --git a/libraries/SocketWrapper/SocketHelpers.h b/libraries/SocketWrapper/SocketHelpers.h index ebf85067..20ce4524 100644 --- a/libraries/SocketWrapper/SocketHelpers.h +++ b/libraries/SocketWrapper/SocketHelpers.h @@ -52,6 +52,7 @@ class NetworkInterface { IPAddress dnsIP(int n = 0); void setMACAddress(const uint8_t* mac); + bool setLocalIP(IPAddress ip, IPAddress subnet, IPAddress gateway); int begin(bool blocking = true, uint32_t additional_event_mask = 0); From 814849bb0943b337f7fc331ada7c1dab75856fba Mon Sep 17 00:00:00 2001 From: Leonardo Cavagnis Date: Mon, 4 Aug 2025 17:19:37 +0200 Subject: [PATCH 4/7] Ethernet lib: add set IP, Subnet, Gateway functions --- libraries/SocketWrapper/Ethernet.cpp | 34 ++++++++++++++++- libraries/SocketWrapper/Ethernet.h | 2 + libraries/SocketWrapper/SocketHelpers.cpp | 45 ++++++++++++++++++++--- libraries/SocketWrapper/SocketHelpers.h | 12 +++--- 4 files changed, 80 insertions(+), 13 deletions(-) diff --git a/libraries/SocketWrapper/Ethernet.cpp b/libraries/SocketWrapper/Ethernet.cpp index e60a833e..1e24bfcd 100644 --- a/libraries/SocketWrapper/Ethernet.cpp +++ b/libraries/SocketWrapper/Ethernet.cpp @@ -32,7 +32,7 @@ int EthernetClass::begin(uint8_t *mac, IPAddress ip, IPAddress dns, IPAddress ga int EthernetClass::begin(uint8_t *mac, IPAddress ip, IPAddress dns, IPAddress gateway, IPAddress subnet, unsigned long timeout, unsigned long responseTimeout) { setMACAddress(mac); - if (!NetworkInterface::setLocalIP(ip, subnet, gateway)) { + if (!NetworkInterface::setLocalIPFull(ip, subnet, gateway)) { return 0; } @@ -72,9 +72,41 @@ void EthernetClass::setMACAddress(const uint8_t *mac_address) { } } +void EthernetClass::MACAddress(uint8_t *mac_address) { + setMACAddress(mac_address); +} + IPAddress EthernetClass::localIP() { return NetworkInterface::localIP(); } +IPAddress EthernetClass::subnetMask() { + return NetworkInterface::subnetMask(); +} + +IPAddress EthernetClass::gatewayIP() { + return NetworkInterface::gatewayIP(); +} + +IPAddress EthernetClass::dnsServerIP() { + return NetworkInterface::dnsServerIP(); +} + +void EthernetClass::setLocalIP(const IPAddress local_ip) { + NetworkInterface::setLocalIP(local_ip); +} + +void EthernetClass::setSubnetMask(const IPAddress subnet) { + NetworkInterface::setSubnetMask(subnet); +} + +void EthernetClass::setGatewayIP(const IPAddress gateway) { + NetworkInterface::setGatewayIP(gateway); +} + +void EthernetClass::setDnsServerIP(const IPAddress dns_server) { + NetworkInterface::setDnsServerIP(dns_server); +} + EthernetClass Ethernet; #endif \ No newline at end of file diff --git a/libraries/SocketWrapper/Ethernet.h b/libraries/SocketWrapper/Ethernet.h index 99f81c61..e5657958 100644 --- a/libraries/SocketWrapper/Ethernet.h +++ b/libraries/SocketWrapper/Ethernet.h @@ -31,6 +31,7 @@ class EthernetClass: public NetworkInterface int begin(uint8_t *mac, IPAddress ip, IPAddress dns); int begin(uint8_t *mac, IPAddress ip, IPAddress dns, IPAddress gateway); int begin(uint8_t *mac, IPAddress ip, IPAddress dns, IPAddress gateway, IPAddress subnet, unsigned long timeout = 60000, unsigned long responseTimeout = 4000); + void init(uint8_t sspin = 10); void MACAddress(uint8_t *mac_address); @@ -44,6 +45,7 @@ class EthernetClass: public NetworkInterface void setSubnetMask(const IPAddress subnet); void setGatewayIP(const IPAddress gateway); void setDnsServerIP(const IPAddress dns_server); + void setRetransmissionTimeout(uint16_t milliseconds); void setRetransmissionCount(uint8_t num); }; diff --git a/libraries/SocketWrapper/SocketHelpers.cpp b/libraries/SocketWrapper/SocketHelpers.cpp index f877781c..b7026199 100644 --- a/libraries/SocketWrapper/SocketHelpers.cpp +++ b/libraries/SocketWrapper/SocketHelpers.cpp @@ -119,10 +119,6 @@ IPAddress NetworkInterface::dnsServerIP() { return arduino::INADDR_NONE; } -IPAddress NetworkInterface::dnsIP(int n) { - //TODO -} - void NetworkInterface::setMACAddress(const uint8_t* mac) { struct net_eth_addr new_mac; struct ethernet_req_params params = { 0 }; @@ -153,7 +149,7 @@ bool NetworkInterface::disconnect() { return (net_if_down(netif) == 0); } -bool NetworkInterface::setLocalIP(IPAddress ip, IPAddress subnet, IPAddress gateway) { +bool NetworkInterface::setLocalIPFull(IPAddress ip, IPAddress subnet, IPAddress gateway) { struct in_addr ip_addr, subnet_addr, gw_addr; ip_addr.s_addr = ip; @@ -173,4 +169,43 @@ bool NetworkInterface::setLocalIP(IPAddress ip, IPAddress subnet, IPAddress gate net_if_ipv4_set_gw(netif, &gw_addr); LOG_INF("Static IP configured"); return true; +} + +bool NetworkInterface::setLocalIP(IPAddress ip) { + struct in_addr addr; + addr.s_addr = ip; + + if (!net_if_ipv4_addr_add(netif, &addr, NET_ADDR_MANUAL, 0)) { + LOG_ERR("Failed to set local IP address"); + return false; + } + + LOG_INF("Local IP address set: %s", ip.toString().c_str()); + return true; +} + +bool NetworkInterface::setSubnetMask(IPAddress subnet) { + struct in_addr netmask_addr; + netmask_addr.s_addr = subnet; + + if (!net_if_ipv4_set_netmask_by_addr(netif, &netmask_addr, &netmask_addr)) { + LOG_ERR("Failed to set subnet mask"); + return false; + } + + LOG_INF("Subnet mask set: %s", subnet.toString().c_str()); + return true; +} + +bool NetworkInterface::setGatewayIP(IPAddress gateway) { + struct in_addr gw_addr; + gw_addr.s_addr = gateway; + + net_if_ipv4_set_gw(netif, &gw_addr); + LOG_INF("Gateway IP set: %s", gateway.toString().c_str()); + return true; +} + +bool NetworkInterface::setDnsServerIP(IPAddress dns_server) { + return false; // DNS server dynamic configuration is not supported } \ No newline at end of file diff --git a/libraries/SocketWrapper/SocketHelpers.h b/libraries/SocketWrapper/SocketHelpers.h index 20ce4524..b407c077 100644 --- a/libraries/SocketWrapper/SocketHelpers.h +++ b/libraries/SocketWrapper/SocketHelpers.h @@ -49,16 +49,14 @@ class NetworkInterface { IPAddress gatewayIP(); IPAddress dnsServerIP(); - IPAddress dnsIP(int n = 0); - void setMACAddress(const uint8_t* mac); - bool setLocalIP(IPAddress ip, IPAddress subnet, IPAddress gateway); + bool setLocalIPFull(IPAddress ip, IPAddress subnet, IPAddress gateway); + bool setLocalIP(IPAddress ip); + bool setSubnetMask(IPAddress subnet); + bool setGatewayIP(IPAddress gateway); + bool setDnsServerIP(IPAddress dns_server); int begin(bool blocking = true, uint32_t additional_event_mask = 0); bool disconnect(); - - // TODO: manual functions for setting IP address, subnet mask, gateway, etc. - // net_if_ipv4_set_netmask_by_addr(iface, &addr4, &nm); - // net_if_ipv4_addr_add(iface, &addr4, NET_ADDR_MANUAL, 0); }; From d8df965855b02a57654c3b874ddc2ed04df57ade Mon Sep 17 00:00:00 2001 From: Leonardo Cavagnis Date: Mon, 4 Aug 2025 17:25:19 +0200 Subject: [PATCH 5/7] Ethernet lib: add disconnect fun --- libraries/SocketWrapper/Ethernet.cpp | 8 ++++++++ libraries/SocketWrapper/Ethernet.h | 15 +++++++++------ 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/libraries/SocketWrapper/Ethernet.cpp b/libraries/SocketWrapper/Ethernet.cpp index 1e24bfcd..d88c7e6b 100644 --- a/libraries/SocketWrapper/Ethernet.cpp +++ b/libraries/SocketWrapper/Ethernet.cpp @@ -66,6 +66,14 @@ EthernetHardwareStatus EthernetClass::hardwareStatus() { } } +int EthernetClass::disconnect() { + return NetworkInterface::disconnect(); +} + +void EthernetClass::end() { + disconnect(); +} + void EthernetClass::setMACAddress(const uint8_t *mac_address) { if (mac_address != nullptr) { NetworkInterface::setMACAddress(mac_address); diff --git a/libraries/SocketWrapper/Ethernet.h b/libraries/SocketWrapper/Ethernet.h index e5657958..da0ffc96 100644 --- a/libraries/SocketWrapper/Ethernet.h +++ b/libraries/SocketWrapper/Ethernet.h @@ -21,20 +21,23 @@ class EthernetClass: public NetworkInterface EthernetClass() {} virtual ~EthernetClass() {} - int begin(uint8_t *mac = nullptr, unsigned long timeout = 60000, unsigned long responseTimeout = 4000); + int begin(uint8_t *mac = nullptr, unsigned long timeout = 60000, unsigned long responseTimeout = 4000); int maintain(); EthernetLinkStatus linkStatus(); EthernetHardwareStatus hardwareStatus(); - // Manual configuration + // Manual configuration int begin(uint8_t *mac, IPAddress ip); int begin(uint8_t *mac, IPAddress ip, IPAddress dns); int begin(uint8_t *mac, IPAddress ip, IPAddress dns, IPAddress gateway); - int begin(uint8_t *mac, IPAddress ip, IPAddress dns, IPAddress gateway, IPAddress subnet, unsigned long timeout = 60000, unsigned long responseTimeout = 4000); - + int begin(uint8_t *mac, IPAddress ip, IPAddress dns, IPAddress gateway, IPAddress subnet, unsigned long timeout = 60000, unsigned long responseTimeout = 4000); + void init(uint8_t sspin = 10); - void MACAddress(uint8_t *mac_address); + int disconnect(void); + void end(void); + + void MACAddress(uint8_t *mac_address); IPAddress localIP(); IPAddress subnetMask(); IPAddress gatewayIP(); @@ -45,7 +48,7 @@ class EthernetClass: public NetworkInterface void setSubnetMask(const IPAddress subnet); void setGatewayIP(const IPAddress gateway); void setDnsServerIP(const IPAddress dns_server); - + void setRetransmissionTimeout(uint16_t milliseconds); void setRetransmissionCount(uint8_t num); }; From 58d1444b8a6f41186d0f2e7444215e6b96f6b1e9 Mon Sep 17 00:00:00 2001 From: Leonardo Cavagnis Date: Tue, 5 Aug 2025 13:27:31 +0200 Subject: [PATCH 6/7] Ethernet lib: extract Ethernet lib from SocketWrapper lib --- libraries/Ethernet/README.md | 11 ++++ .../examples/TestClient/TestClient.ino | 0 .../examples/TestServer/TestServer.ino | 0 libraries/Ethernet/keywords.txt | 64 +++++++++++++++++++ libraries/Ethernet/library.properties | 10 +++ .../src}/Ethernet.cpp | 0 .../src}/Ethernet.h | 0 libraries/Ethernet/src/ZephyrEthernet.h | 3 + libraries/Ethernet/src/Zephyr_Ethernet.h | 1 + 9 files changed, 89 insertions(+) create mode 100644 libraries/Ethernet/README.md rename libraries/{SocketWrapper => Ethernet}/examples/TestClient/TestClient.ino (100%) rename libraries/{SocketWrapper => Ethernet}/examples/TestServer/TestServer.ino (100%) create mode 100644 libraries/Ethernet/keywords.txt create mode 100644 libraries/Ethernet/library.properties rename libraries/{SocketWrapper => Ethernet/src}/Ethernet.cpp (100%) rename libraries/{SocketWrapper => Ethernet/src}/Ethernet.h (100%) create mode 100644 libraries/Ethernet/src/ZephyrEthernet.h create mode 100644 libraries/Ethernet/src/Zephyr_Ethernet.h diff --git a/libraries/Ethernet/README.md b/libraries/Ethernet/README.md new file mode 100644 index 00000000..872a6637 --- /dev/null +++ b/libraries/Ethernet/README.md @@ -0,0 +1,11 @@ +# Ethernet Library for Arduino + +Provides Ethernet connectivity for Arduino boards using the Arduino Zephyr core, together with a shield or carrier featuring an Ethernet connector. + +📖 For more information about this library please read the documentation [here](http://www.arduino.cc/en/Reference/Ethernet). + +## License + +Copyright (c) 2025 Arduino SA. All rights reserved. + +This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/. \ No newline at end of file diff --git a/libraries/SocketWrapper/examples/TestClient/TestClient.ino b/libraries/Ethernet/examples/TestClient/TestClient.ino similarity index 100% rename from libraries/SocketWrapper/examples/TestClient/TestClient.ino rename to libraries/Ethernet/examples/TestClient/TestClient.ino diff --git a/libraries/SocketWrapper/examples/TestServer/TestServer.ino b/libraries/Ethernet/examples/TestServer/TestServer.ino similarity index 100% rename from libraries/SocketWrapper/examples/TestServer/TestServer.ino rename to libraries/Ethernet/examples/TestServer/TestServer.ino diff --git a/libraries/Ethernet/keywords.txt b/libraries/Ethernet/keywords.txt new file mode 100644 index 00000000..3c4ed937 --- /dev/null +++ b/libraries/Ethernet/keywords.txt @@ -0,0 +1,64 @@ +####################################### +# Syntax Coloring Map For Ethernet +####################################### + +####################################### +# Datatypes (KEYWORD1) +####################################### + +Ethernet KEYWORD1 Ethernet +EthernetClient KEYWORD1 EthernetClient +EthernetServer KEYWORD1 EthernetServer +IPAddress KEYWORD1 EthernetIPAddress + +####################################### +# Methods and Functions (KEYWORD2) +####################################### + +status KEYWORD2 +connect KEYWORD2 +write KEYWORD2 +available KEYWORD2 +availableForWrite KEYWORD2 +read KEYWORD2 +peek KEYWORD2 +flush KEYWORD2 +stop KEYWORD2 +connected KEYWORD2 +accept KEYWORD2 +begin KEYWORD2 +beginMulticast KEYWORD2 +beginPacket KEYWORD2 +endPacket KEYWORD2 +parsePacket KEYWORD2 +remoteIP KEYWORD2 +remotePort KEYWORD2 +getSocketNumber KEYWORD2 +localIP KEYWORD2 +localPort KEYWORD2 +maintain KEYWORD2 +linkStatus KEYWORD2 +hardwareStatus KEYWORD2 +MACAddress KEYWORD2 +subnetMask KEYWORD2 +gatewayIP KEYWORD2 +dnsServerIP KEYWORD2 +setMACAddress KEYWORD2 +setLocalIP KEYWORD2 +setSubnetMask KEYWORD2 +setGatewayIP KEYWORD2 +setDnsServerIP KEYWORD2 +setRetransmissionTimeout KEYWORD2 +setRetransmissionCount KEYWORD2 +setConnectionTimeout KEYWORD2 + +####################################### +# Constants (LITERAL1) +####################################### + +EthernetLinkStatus LITERAL1 +Unknown LITERAL1 +LinkON LITERAL1 +LinkOFF LITERAL1 +EthernetHardwareStatus LITERAL1 +EthernetNoHardware LITERAL1 \ No newline at end of file diff --git a/libraries/Ethernet/library.properties b/libraries/Ethernet/library.properties new file mode 100644 index 00000000..cae314d2 --- /dev/null +++ b/libraries/Ethernet/library.properties @@ -0,0 +1,10 @@ +name=Ethernet +version=0.1.0 +author=Arduino +maintainer=Arduino +sentence=Enables network connection (local and Internet) using Ethernet on Zephyr enabled boards +paragraph=With this library you can connect to Internet via Ethernet. The library provides both Client and server functionalities. The library permits you to connect to a local network also with DHCP and to resolve DNS. +category=Communication +url=http://www.arduino.cc/en/Reference/Ethernet +architectures=zephyr,zephyr_portenta,zephyr_nicla,zephyr_giga +includes=Ethernet.h diff --git a/libraries/SocketWrapper/Ethernet.cpp b/libraries/Ethernet/src/Ethernet.cpp similarity index 100% rename from libraries/SocketWrapper/Ethernet.cpp rename to libraries/Ethernet/src/Ethernet.cpp diff --git a/libraries/SocketWrapper/Ethernet.h b/libraries/Ethernet/src/Ethernet.h similarity index 100% rename from libraries/SocketWrapper/Ethernet.h rename to libraries/Ethernet/src/Ethernet.h diff --git a/libraries/Ethernet/src/ZephyrEthernet.h b/libraries/Ethernet/src/ZephyrEthernet.h new file mode 100644 index 00000000..f1349895 --- /dev/null +++ b/libraries/Ethernet/src/ZephyrEthernet.h @@ -0,0 +1,3 @@ +#pragma once + +#include "Ethernet.h" \ No newline at end of file diff --git a/libraries/Ethernet/src/Zephyr_Ethernet.h b/libraries/Ethernet/src/Zephyr_Ethernet.h new file mode 100644 index 00000000..6761ba5e --- /dev/null +++ b/libraries/Ethernet/src/Zephyr_Ethernet.h @@ -0,0 +1 @@ +// placeholder to allow the discovery of this library \ No newline at end of file From cbb85d9eda8beba7599f77f3d59b197f862804e1 Mon Sep 17 00:00:00 2001 From: Leonardo Cavagnis Date: Tue, 5 Aug 2025 17:09:41 +0200 Subject: [PATCH 7/7] Ethernet lib: add default examples --- .../AdvancedChatServer/AdvancedChatServer.ino | 97 ++++++++ .../BarometricPressureWebServer.ino | 231 ++++++++++++++++++ .../DhcpAddressPrinter/DhcpAddressPrinter.ino | 87 +++++++ .../examples/LinkStatus/LinkStatus.ino | 28 +++ .../examples/TelnetClient/TelnetClient.ino | 94 +++++++ .../examples/TestClient/TestClient.ino | 31 --- .../UDPSendReceiveString.ino | 129 ++++++++++ .../examples/UdpNtpClient/UdpNtpClient.ino | 175 +++++++++++++ .../Ethernet/examples/WebClient/WebClient.ino | 129 ++++++++++ .../WebClientRepeating/WebClientRepeating.ino | 114 +++++++++ .../WebClientRepeatingManual.ino | 142 +++++++++++ .../WebClientRepeatingSSL.ino | 110 +++++++++ .../WebServer.ino} | 64 +++-- libraries/Ethernet/src/Ethernet.h | 12 + libraries/SocketWrapper/SocketWrapper.h | 22 ++ libraries/SocketWrapper/ZephyrClient.h | 3 + libraries/SocketWrapper/ZephyrUDP.h | 2 + loader/llext_exports.c | 2 + 18 files changed, 1427 insertions(+), 45 deletions(-) create mode 100644 libraries/Ethernet/examples/AdvancedChatServer/AdvancedChatServer.ino create mode 100644 libraries/Ethernet/examples/BarometricPressureWebServer/BarometricPressureWebServer.ino create mode 100644 libraries/Ethernet/examples/DhcpAddressPrinter/DhcpAddressPrinter.ino create mode 100644 libraries/Ethernet/examples/LinkStatus/LinkStatus.ino create mode 100644 libraries/Ethernet/examples/TelnetClient/TelnetClient.ino delete mode 100755 libraries/Ethernet/examples/TestClient/TestClient.ino create mode 100644 libraries/Ethernet/examples/UDPSendReceiveString/UDPSendReceiveString.ino create mode 100644 libraries/Ethernet/examples/UdpNtpClient/UdpNtpClient.ino create mode 100644 libraries/Ethernet/examples/WebClient/WebClient.ino create mode 100644 libraries/Ethernet/examples/WebClientRepeating/WebClientRepeating.ino create mode 100644 libraries/Ethernet/examples/WebClientRepeatingManual/WebClientRepeatingManual.ino create mode 100644 libraries/Ethernet/examples/WebClientRepeatingSSL/WebClientRepeatingSSL.ino rename libraries/Ethernet/examples/{TestServer/TestServer.ino => WebServer/WebServer.ino} (57%) diff --git a/libraries/Ethernet/examples/AdvancedChatServer/AdvancedChatServer.ino b/libraries/Ethernet/examples/AdvancedChatServer/AdvancedChatServer.ino new file mode 100644 index 00000000..5e70d16c --- /dev/null +++ b/libraries/Ethernet/examples/AdvancedChatServer/AdvancedChatServer.ino @@ -0,0 +1,97 @@ +/* + Advanced Chat Server + + A more advanced server that distributes any incoming messages + to all connected clients but the client the message comes from. + To use, telnet to your device's IP address and type. + + */ + +#include "ZephyrServer.h" +#include "ZephyrClient.h" +#include "ZephyrEthernet.h" + +// The IP address will be dependent on your local network. +// gateway and subnet are optional: +IPAddress ip(192, 168, 1, 177); +IPAddress myDns(192, 168, 1, 1); +IPAddress gateway(192, 168, 1, 1); +IPAddress subnet(255, 255, 255, 0); + + +// telnet defaults to port 23 +ZephyrServer server(23); + +ZephyrClient clients[8]; + +void setup() { + + // initialize the Ethernet device + Ethernet.begin(ip, myDns, gateway, subnet); + + // 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 + } + + // 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."); + } + + // start listening for clients + server.begin(); + + Serial.print("Chat server address:"); + Serial.println(Ethernet.localIP()); +} + +void loop() { + // check for any new client connecting, and say hello (before any incoming data) + ZephyrClient newClient = server.accept(); + if (newClient) { + for (byte i=0; i < 8; i++) { + if (!clients[i]) { + Serial.print("We have a new client #"); + Serial.println(i); + newClient.print("Hello, client number: "); + newClient.println(i); + // Once we "accept", the client is no longer tracked by EthernetServer + // so we must store it into our list of clients + clients[i] = newClient; + break; + } + } + } + + // check for incoming data from all clients + for (byte i=0; i < 8; i++) { + if (clients[i] && clients[i].available() > 0) { + // read bytes from a client + byte buffer[80]; + int count = clients[i].read(buffer, 80); + // write the bytes to all other connected clients + for (byte j=0; j < 8; j++) { + if (j != i && clients[j].connected()) { + clients[j].write(buffer, count); + } + } + } + } + + // stop any clients which disconnect + for (byte i=0; i < 8; i++) { + if (clients[i] && !clients[i].connected()) { + Serial.print("disconnect client #"); + Serial.println(i); + clients[i].stop(); + } + } +} diff --git a/libraries/Ethernet/examples/BarometricPressureWebServer/BarometricPressureWebServer.ino b/libraries/Ethernet/examples/BarometricPressureWebServer/BarometricPressureWebServer.ino new file mode 100644 index 00000000..c7d78938 --- /dev/null +++ b/libraries/Ethernet/examples/BarometricPressureWebServer/BarometricPressureWebServer.ino @@ -0,0 +1,231 @@ +/* + SCP1000 Barometric Pressure Sensor Display + + Serves the output of a Barometric Pressure Sensor as a web page. + Uses the SPI library. For details on the sensor, see: + http://www.sparkfun.com/commerce/product_info.php?products_id=8161 + + This sketch adapted from Nathan Seidle's SCP1000 example for PIC: + http://www.sparkfun.com/datasheets/Sensors/SCP1000-Testing.zip + + TODO: this hardware is long obsolete. This example program should + be rewritten to use https://www.sparkfun.com/products/9721 + + Circuit: + SCP1000 sensor attached to pins 6,7, and 11 - 13: + DRDY: pin 6 + CSB: pin 7 + MOSI: pin 11 + MISO: pin 12 + SCK: pin 13 + + */ + +#include "ZephyrServer.h" +#include "ZephyrEthernet.h" +// the sensor communicates using SPI, so include the library: +#include + +// assign an IP address for the controller: +IPAddress ip(192, 168, 1, 20); + +// Initialize the Ethernet server library +// with the IP address and port you want to use +// (port 80 is default for HTTP): +ZephyrServer server(80); + +//Sensor's memory register addresses: +const int PRESSURE = 0x1F; //3 most significant bits of pressure +const int PRESSURE_LSB = 0x20; //16 least significant bits of pressure +const int TEMPERATURE = 0x21; //16 bit temperature reading + +// pins used for the connection with the sensor +// the others you need are controlled by the SPI library): +const int dataReadyPin = 6; +const int chipSelectPin = 7; + +float temperature = 0.0; +long pressure = 0; +long lastReadingTime = 0; + +void setup() { + + // start the SPI library: + SPI.begin(); + + // start the Ethernet connection + Ethernet.begin(ip); + + // 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 + } + + // 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."); + } + + // start listening for clients + server.begin(); + + // initalize the data ready and chip select pins: + pinMode(dataReadyPin, INPUT); + pinMode(chipSelectPin, OUTPUT); + + //Configure SCP1000 for low noise configuration: + writeRegister(0x02, 0x2D); + writeRegister(0x01, 0x03); + writeRegister(0x03, 0x02); + + // give the sensor and Ethernet shield time to set up: + delay(1000); + + //Set the sensor to high resolution mode tp start readings: + writeRegister(0x03, 0x0A); + +} + +void loop() { + // check for a reading no more than once a second. + if (millis() - lastReadingTime > 1000) { + // if there's a reading ready, read it: + // don't do anything until the data ready pin is high: + if (digitalRead(dataReadyPin) == HIGH) { + getData(); + // timestamp the last time you got a reading: + lastReadingTime = millis(); + } + } + + // listen for incoming Ethernet connections: + listenForEthernetClients(); +} + + +void getData() { + Serial.println("Getting reading"); + //Read the temperature data + int tempData = readRegister(0x21, 2); + + // convert the temperature to celsius and display it: + temperature = (float)tempData / 20.0; + + //Read the pressure data highest 3 bits: + byte pressureDataHigh = readRegister(0x1F, 1); + pressureDataHigh &= 0b00000111; //you only needs bits 2 to 0 + + //Read the pressure data lower 16 bits: + unsigned int pressureDataLow = readRegister(0x20, 2); + //combine the two parts into one 19-bit number: + pressure = ((pressureDataHigh << 16) | pressureDataLow) / 4; + + Serial.print("Temperature: "); + Serial.print(temperature); + Serial.println(" degrees C"); + Serial.print("Pressure: " + String(pressure)); + Serial.println(" Pa"); +} + +void listenForEthernetClients() { + // listen for incoming clients + ZephyrClient client = server.accept(); + if (client) { + Serial.println("Got a client"); + // an http request ends with a blank line + boolean currentLineIsBlank = true; + while (client.connected()) { + if (client.available()) { + char c = client.read(); + // if you've gotten to the end of the line (received a newline + // character) and the line is blank, the http request has ended, + // so you can send a reply + if (c == '\n' && currentLineIsBlank) { + // send a standard http response header + client.println("HTTP/1.1 200 OK"); + client.println("Content-Type: text/html"); + client.println(); + // print the current readings, in HTML format: + client.print("Temperature: "); + client.print(temperature); + client.print(" degrees C"); + client.println("
"); + client.print("Pressure: " + String(pressure)); + client.print(" Pa"); + client.println("
"); + break; + } + if (c == '\n') { + // you're starting a new line + currentLineIsBlank = true; + } else if (c != '\r') { + // you've gotten a character on the current line + currentLineIsBlank = false; + } + } + } + // give the web browser time to receive the data + delay(1); + // close the connection: + client.stop(); + } +} + + +//Send a write command to SCP1000 +void writeRegister(byte registerName, byte registerValue) { + // SCP1000 expects the register name in the upper 6 bits + // of the byte: + registerName <<= 2; + // command (read or write) goes in the lower two bits: + registerName |= 0b00000010; //Write command + + // take the chip select low to select the device: + digitalWrite(chipSelectPin, LOW); + + SPI.transfer(registerName); //Send register location + SPI.transfer(registerValue); //Send value to record into register + + // take the chip select high to de-select: + digitalWrite(chipSelectPin, HIGH); +} + + +//Read register from the SCP1000: +unsigned int readRegister(byte registerName, int numBytes) { + byte inByte = 0; // incoming from the SPI read + unsigned int result = 0; // result to return + + // SCP1000 expects the register name in the upper 6 bits + // of the byte: + registerName <<= 2; + // command (read or write) goes in the lower two bits: + registerName &= 0b11111100; //Read command + + // take the chip select low to select the device: + digitalWrite(chipSelectPin, LOW); + // send the device the register you want to read: + int command = SPI.transfer(registerName); + // send a value of 0 to read the first byte returned: + inByte = SPI.transfer(0x00); + + result = inByte; + // if there's more than one byte returned, + // shift the first byte then get the second byte: + if (numBytes > 1) { + result = inByte << 8; + inByte = SPI.transfer(0x00); + result = result | inByte; + } + // take the chip select high to de-select: + digitalWrite(chipSelectPin, HIGH); + // return the result: + return (result); +} diff --git a/libraries/Ethernet/examples/DhcpAddressPrinter/DhcpAddressPrinter.ino b/libraries/Ethernet/examples/DhcpAddressPrinter/DhcpAddressPrinter.ino new file mode 100644 index 00000000..53741f7e --- /dev/null +++ b/libraries/Ethernet/examples/DhcpAddressPrinter/DhcpAddressPrinter.ino @@ -0,0 +1,87 @@ +/* + DHCP-based IP printer + + This sketch uses the DHCP extensions to the Ethernet library + to get an IP address via DHCP and print the address obtained. + using an Arduino Wiznet Ethernet shield. + + */ + +#include "ZephyrEthernet.h" + +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 + } + + // in Zephyr system check if Ethernet is ready before proceeding to initialize + Serial.print("Waiting for link on"); + while (Ethernet.linkStatus() != LinkON) { + Serial.print("."); + delay(100); + } + Serial.println(); + + // start the Ethernet connection: + Serial.println("Initialize Ethernet with DHCP:"); + if (Ethernet.begin() == 0) { + Serial.println("Failed to configure Ethernet using DHCP"); + if (Ethernet.hardwareStatus() == EthernetNoHardware) { + Serial.println("Ethernet shield was not found. Sorry, can't run without hardware. :("); + } else if (Ethernet.linkStatus() == LinkOFF) { + Serial.println("Ethernet cable is not connected."); + } + // no point in carrying on, so do nothing forevermore: + while (true) { + delay(1); + } + } + // print your local IP address: + Serial.print("My IP address: "); + Serial.println(Ethernet.localIP()); +} + +void loop() +{ + if (Ethernet.linkStatus() != LinkON) { + Serial.println(Ethernet.linkStatus()); + connectEth(); + } +} + +void connectEth() +{ + // in Zephyr system check if Ethernet is ready before proceeding to initialize + Serial.print("Waiting for link on"); + while (Ethernet.linkStatus() != LinkON) { + Serial.print("."); + delay(100); + } + Serial.println(); + + // start the Ethernet connection: + Serial.println("Initialize Ethernet with DHCP:"); + if (Ethernet.begin() == 0) { + Serial.println("Failed to configure Ethernet using DHCP"); + // 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."); + } + } else { + Serial.print(" DHCP assigned IP "); + Serial.println(Ethernet.localIP()); + } + + Serial.println("You're connected to the network"); + Serial.println(); +} diff --git a/libraries/Ethernet/examples/LinkStatus/LinkStatus.ino b/libraries/Ethernet/examples/LinkStatus/LinkStatus.ino new file mode 100644 index 00000000..a38e005d --- /dev/null +++ b/libraries/Ethernet/examples/LinkStatus/LinkStatus.ino @@ -0,0 +1,28 @@ +/* + Link Status + This sketch prints the ethernet link status. When the + ethernet cable is connected the link status should go to "ON". +*/ + +#include + +void setup() { + Serial.begin(9600); +} + +void loop() { + auto link = Ethernet.linkStatus(); + Serial.print("Link status: "); + switch (link) { + case Unknown: + Serial.println("Unknown"); + break; + case LinkON: + Serial.println("ON"); + break; + case LinkOFF: + Serial.println("OFF"); + break; + } + delay(1000); +} diff --git a/libraries/Ethernet/examples/TelnetClient/TelnetClient.ino b/libraries/Ethernet/examples/TelnetClient/TelnetClient.ino new file mode 100644 index 00000000..92aad146 --- /dev/null +++ b/libraries/Ethernet/examples/TelnetClient/TelnetClient.ino @@ -0,0 +1,94 @@ +/* + Telnet client + + This sketch connects to a a telnet server (http://www.google.com) + using an Arduino Wiznet Ethernet shield. You'll need a telnet server + to test this with. + Processing's ChatServer example (part of the network library) works well, + running on port 10002. It can be found as part of the examples + in the Processing application, available at + http://processing.org/ + */ + +#include "ZephyrClient.h" +#include "ZephyrEthernet.h" + +// The IP address will be dependent on your local network: +IPAddress ip(192, 168, 1, 177); + +// Enter the IP address of the server you're connecting to: +IPAddress server(1, 1, 1, 1); + +// Initialize the Ethernet client library +// with the IP address and port of the server +// that you want to connect to (port 23 is default for telnet; +// if you're using Processing's ChatServer, use port 10002): +ZephyrClient client; + +void setup() { + // 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 + } + } + while (Ethernet.linkStatus() == LinkOFF) { + Serial.println("Ethernet cable is not connected."); + delay(500); + } + + // start the Ethernet connection: + Ethernet.begin(ip); + + // 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 + } + + // give the Ethernet shield a second to initialize: + delay(1000); + Serial.println("connecting..."); + + // if you get a connection, report back via serial: + if (client.connect(server, 10002)) { + Serial.println("connected"); + } else { + // if you didn't get a connection to the server: + Serial.println("connection failed"); + } +} + +void loop() { + // if there are incoming bytes available + // from the server, read them and print them: + if (client.available()) { + char c = client.read(); + Serial.print(c); + } + + // as long as there are bytes in the serial queue, + // read them and send them out the socket if it's open: + while (Serial.available() > 0) { + char inChar = Serial.read(); + if (client.connected()) { + client.print(inChar); + } + } + + // if the server's disconnected, stop the client: + if (!client.connected()) { + Serial.println(); + Serial.println("disconnecting."); + client.stop(); + // do nothing: + while (true) { + delay(1); + } + } +} + + + + diff --git a/libraries/Ethernet/examples/TestClient/TestClient.ino b/libraries/Ethernet/examples/TestClient/TestClient.ino deleted file mode 100755 index dc5b98c3..00000000 --- a/libraries/Ethernet/examples/TestClient/TestClient.ino +++ /dev/null @@ -1,31 +0,0 @@ -#include -#include "Ethernet.h" - -ZephyrClient client; -IPAddress addr(93, 184, 215, 14); - -void setup() { - - pinMode(LED_BUILTIN, OUTPUT); - Serial.begin(115200); - - while (Ethernet.linkStatus() != LinkON) { - Serial.println("waiting for link on"); - delay(100); - } - Ethernet.begin(); - Serial.println(Ethernet.localIP()); - - auto res = client.connect("example.com", 80); - res = client.println("GET / HTTP/1.0"); - client.println("Host: example.com"); - client.println("Connection: close"); - client.println(); -} - -// the loop function runs over and over again forever -void loop() { - while (client.available()) { - Serial.write(client.read()); - } -} diff --git a/libraries/Ethernet/examples/UDPSendReceiveString/UDPSendReceiveString.ino b/libraries/Ethernet/examples/UDPSendReceiveString/UDPSendReceiveString.ino new file mode 100644 index 00000000..c733e15b --- /dev/null +++ b/libraries/Ethernet/examples/UDPSendReceiveString/UDPSendReceiveString.ino @@ -0,0 +1,129 @@ +/* + UDPSendReceiveString: + This sketch receives UDP message strings, prints them to the serial port + and sends an "acknowledge" string back to the sender + + A Processing sketch is included at the end of file that can be used to send + and received messages for testing with a computer. + */ + +#include +#include + +// The IP address will be dependent on your local network: +IPAddress ip(192, 168, 1, 177); + +unsigned int localPort = 8888; // local port to listen on + +// buffers for receiving and sending data +char packetBuffer[UDP_TX_PACKET_MAX_SIZE]; // buffer to hold incoming packet, +char ReplyBuffer[] = "acknowledged"; // a string to send back + +// An EthernetUDP instance to let us send and receive packets over UDP +ZephyrUDP Udp; + +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 + } + + // in Zephyr system check if Ethernet is ready before proceeding to initialize + Serial.print("Waiting for link on"); + while (Ethernet.linkStatus() != LinkON) { + Serial.print("."); + delay(100); + } + Serial.println(); + + // start the Ethernet + Ethernet.begin(ip); + + // 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."); + } + + // start UDP + Udp.begin(localPort); +} + +void loop() { + // if there's data available, read a packet + int packetSize = Udp.parsePacket(); + if (packetSize) { + Serial.print("Received packet of size "); + Serial.println(packetSize); + Serial.print("From "); + IPAddress remote = Udp.remoteIP(); + for (int i=0; i < 4; i++) { + Serial.print(remote[i], DEC); + if (i < 3) { + Serial.print("."); + } + } + Serial.print(", port "); + Serial.println(Udp.remotePort()); + + // read the packet into packetBufffer + Udp.read(packetBuffer, UDP_TX_PACKET_MAX_SIZE); + Serial.println("Contents:"); + Serial.println(packetBuffer); + + // send a reply to the IP address and port that sent us the packet we received + Udp.beginPacket(Udp.remoteIP(), Udp.remotePort()); + Udp.write(ReplyBuffer); + Udp.endPacket(); + } + delay(10); +} + + +/* + Processing sketch to run with this example + ===================================================== + + // Processing UDP example to send and receive string data from Arduino + // press any key to send the "Hello Arduino" message + + + import hypermedia.net.*; + + UDP udp; // define the UDP object + + + void setup() { + udp = new UDP( this, 6000 ); // create a new datagram connection on port 6000 + //udp.log( true ); // <-- printout the connection activity + udp.listen( true ); // and wait for incoming message + } + + void draw() + { + } + + void keyPressed() { + String ip = "192.168.1.177"; // the remote IP address + int port = 8888; // the destination port + + udp.send("Hello World", ip, port ); // the message to send + + } + + void receive( byte[] data ) { // <-- default handler + //void receive( byte[] data, String ip, int port ) { // <-- extended handler + + for(int i=0; i < data.length; i++) + print(char(data[i])); + println(); + } + */ + + diff --git a/libraries/Ethernet/examples/UdpNtpClient/UdpNtpClient.ino b/libraries/Ethernet/examples/UdpNtpClient/UdpNtpClient.ino new file mode 100644 index 00000000..a8b9a391 --- /dev/null +++ b/libraries/Ethernet/examples/UdpNtpClient/UdpNtpClient.ino @@ -0,0 +1,175 @@ +/* + + Udp NTP Client + + Get the time from a Network Time Protocol (NTP) time server + Demonstrates use of UDP sendPacket and ReceivePacket + For more on NTP time servers and the messages needed to communicate with them, + see http://en.wikipedia.org/wiki/Network_Time_Protocol + + */ + +#include +#include + +unsigned int localPort = 8888; // local port to listen for UDP packets + +const char timeServer[] = "time.nist.gov"; // time.nist.gov NTP server + +const int NTP_PACKET_SIZE = 48; // NTP time stamp is in the first 48 bytes of the message + +byte packetBuffer[NTP_PACKET_SIZE]; //buffer to hold incoming and outgoing packets + +// A UDP instance to let us send and receive packets over UDP +ZephyrUDP Udp; + +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 + } + + // in Zephyr system check if Ethernet is ready before proceeding to initialize + Serial.print("Waiting for link on"); + while (Ethernet.linkStatus() != LinkON) { + Serial.print("."); + delay(100); + } + Serial.println(); + + // start Ethernet and UDP + if (Ethernet.begin() == 0) { + Serial.println("Failed to configure Ethernet using DHCP"); + // Check for Ethernet hardware present + if (Ethernet.hardwareStatus() == EthernetNoHardware) { + Serial.println("Ethernet shield was not found. Sorry, can't run without hardware. :("); + } else if (Ethernet.linkStatus() == LinkOFF) { + Serial.println("Ethernet cable is not connected."); + } + // no point in carrying on, so do nothing forevermore: + while (true) { + delay(1); + } + } + Udp.begin(localPort); +} + +void loop() { + if (Ethernet.linkStatus() != LinkON) { + Serial.println(Ethernet.linkStatus()); + connectEth(); + } + sendNTPpacket(timeServer); // send an NTP packet to a time server + + // wait to see if a reply is available + delay(1000); + if (Udp.parsePacket()) { + // We've received a packet, read the data from it + Udp.read(packetBuffer, NTP_PACKET_SIZE); // read the packet into the buffer + + // the timestamp starts at byte 40 of the received packet and is four bytes, + // or two words, long. First, extract the two words: + + unsigned long highWord = word(packetBuffer[40], packetBuffer[41]); + unsigned long lowWord = word(packetBuffer[42], packetBuffer[43]); + // combine the four bytes (two words) into a long integer + // this is NTP time (seconds since Jan 1 1900): + unsigned long secsSince1900 = highWord << 16 | lowWord; + Serial.print("Seconds since Jan 1 1900 = "); + Serial.println(secsSince1900); + + // now convert NTP time into everyday time: + Serial.print("Unix time = "); + // Unix time starts on Jan 1 1970. In seconds, that's 2208988800: + const unsigned long seventyYears = 2208988800UL; + // subtract seventy years: + unsigned long epoch = secsSince1900 - seventyYears; + // print Unix time: + Serial.println(epoch); + + + // print the hour, minute and second: + Serial.print("The UTC time is "); // UTC is the time at Greenwich Meridian (GMT) + Serial.print((epoch % 86400L) / 3600); // print the hour (86400 equals secs per day) + Serial.print(':'); + if (((epoch % 3600) / 60) < 10) { + // In the first 10 minutes of each hour, we'll want a leading '0' + Serial.print('0'); + } + Serial.print((epoch % 3600) / 60); // print the minute (3600 equals secs per minute) + Serial.print(':'); + if ((epoch % 60) < 10) { + // In the first 10 seconds of each minute, we'll want a leading '0' + Serial.print('0'); + } + Serial.println(epoch % 60); // print the second + } + // wait ten seconds before asking for the time again + delay(10000); +} + +// send an NTP request to the time server at the given address +void sendNTPpacket(const char * address) { + // set all bytes in the buffer to 0 + memset(packetBuffer, 0, NTP_PACKET_SIZE); + // Initialize values needed to form NTP request + // (see URL above for details on the packets) + packetBuffer[0] = 0b11100011; // LI, Version, Mode + packetBuffer[1] = 0; // Stratum, or type of clock + packetBuffer[2] = 6; // Polling Interval + packetBuffer[3] = 0xEC; // Peer Clock Precision + // 8 bytes of zero for Root Delay & Root Dispersion + packetBuffer[12] = 49; + packetBuffer[13] = 0x4E; + packetBuffer[14] = 49; + packetBuffer[15] = 52; + + // all NTP fields have been given values, now + // you can send a packet requesting a timestamp: + Udp.beginPacket(address, 123); // NTP requests are to port 123 + Udp.write(packetBuffer, NTP_PACKET_SIZE); + Udp.endPacket(); +} + +void connectEth() +{ + // in Zephyr system check if Ethernet is ready before proceeding to initialize + Serial.print("Waiting for link on"); + while (Ethernet.linkStatus() != LinkON) { + Serial.print("."); + delay(100); + } + Serial.println(); + + // start the Ethernet connection: + Serial.println("Initialize Ethernet with DHCP:"); + if (Ethernet.begin(nullptr) == 0) { + Serial.println("Failed to configure Ethernet using DHCP"); + // 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."); + } + } else { + Serial.print(" DHCP assigned IP "); + Serial.println(Ethernet.localIP()); + } + + Serial.println("You're connected to the network"); + Serial.println(); +} + + + + + + + + diff --git a/libraries/Ethernet/examples/WebClient/WebClient.ino b/libraries/Ethernet/examples/WebClient/WebClient.ino new file mode 100644 index 00000000..f5d85a4d --- /dev/null +++ b/libraries/Ethernet/examples/WebClient/WebClient.ino @@ -0,0 +1,129 @@ +/* + Web client + + This sketch connects to a website (http://www.google.com) + */ + +#include +#include "ZephyrEthernet.h" + +// 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 }; + +// if you don't want to use DNS (and reduce your sketch size) +// use the numeric IP instead of the name for the server: +//IPAddress server(74,125,232,128); // numeric IP for Google (no DNS) +char server[] = "www.google.com"; // name address for Google (using DNS) + +// Set the static IP address to use if the DHCP fails to assign +IPAddress ip(192, 168, 2, 177); +IPAddress myDns(192, 168, 2, 1); + +// Initialize the Ethernet client library +// with the IP address and port of the server +// that you want to connect to (port 80 is default for HTTP): +ZephyrClient client; + +// Variables to measure the speed +unsigned long beginMicros, endMicros; +unsigned long byteCount = 0; +bool printWebData = true; // set to false for better speed measurement + +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 + } + + // in Zephyr system check if Ethernet is ready before proceeding to initialize + while (Ethernet.linkStatus() != LinkON) { + Serial.println("Waiting for link on"); + delay(100); + } + + // start the Ethernet connection: + Serial.println("Initialize Ethernet with DHCP:"); + if (Ethernet.begin() == 0) { + Serial.println("Failed to configure Ethernet using DHCP"); + // 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."); + } + // try to congifure using IP address instead of DHCP: + Ethernet.begin(ip, myDns); + } else { + Serial.print(" DHCP assigned IP "); + Serial.println(Ethernet.localIP()); + } + + // give the Ethernet shield a second to initialize: + delay(1000); + Serial.print("connecting to "); + Serial.print(server); + Serial.println("..."); + + // if you get a connection, report back via serial: + if (client.connect(server, 80)) { + Serial.print("connected to "); + Serial.println(client.remoteIP()); + // Make a HTTP request: + client.println("GET /search?q=arduino HTTP/1.1"); + client.println("Host: www.google.com"); + client.println("Connection: close"); + client.println(); + } else { + // if you didn't get a connection to the server: + Serial.println("connection failed"); + } + beginMicros = micros(); +} + +void loop() +{ + // if there are incoming bytes available + // from the server, read them and print them: + int len = client.available(); + if (len > 0) { + byte buffer[80]; + if (len > 80) + len = 80; + client.read(buffer, len); + if (printWebData) { + Serial.write(buffer, len); // show in the serial monitor (slows some boards) + } + byteCount = byteCount + len; + } + + // if the server's disconnected, stop the client: + if (!client.connected()) { + endMicros = micros(); + Serial.println(); + Serial.println("disconnecting."); + client.stop(); + Serial.print("Received "); + Serial.print(byteCount); + Serial.print(" bytes in "); + float seconds = (float)(endMicros - beginMicros) / 1000000.0; + Serial.print(seconds, 4); + float rate = (float)byteCount / seconds / 1000.0; + Serial.print(", rate = "); + Serial.print(rate); + Serial.print(" kbytes/second"); + Serial.println(); + + // do nothing forevermore: + while (true) { + delay(1); + } + } +} diff --git a/libraries/Ethernet/examples/WebClientRepeating/WebClientRepeating.ino b/libraries/Ethernet/examples/WebClientRepeating/WebClientRepeating.ino new file mode 100644 index 00000000..8b37198f --- /dev/null +++ b/libraries/Ethernet/examples/WebClientRepeating/WebClientRepeating.ino @@ -0,0 +1,114 @@ +/* + Repeating Web client + + This sketch connects to a a web server and makes a request + using a Wiznet Ethernet shield. You can use the Arduino Ethernet shield, or + the Adafruit Ethernet shield, either one will work, as long as it's got + a Wiznet Ethernet module on board. + + This example uses DNS, by assigning the Ethernet client with a MAC address, + IP address, and DNS address. + + */ + +#include +#include "ZephyrEthernet.h" + +// Set the static IP address to use if the DHCP fails to assign +IPAddress ip(192, 168, 0, 177); +IPAddress myDns(192, 168, 0, 1); + +// initialize the library instance: +ZephyrClient client; + +char server[] = "www.arduino.cc"; // also change the Host line in httpRequest() +//IPAddress server(64,131,82,241); + +unsigned long lastConnectionTime = 0; // last time you connected to the server, in milliseconds +const unsigned long postingInterval = 10*1000; // delay between updates, in milliseconds + +void setup() { + // start serial port: + Serial.begin(9600); + while (!Serial) { + ; // wait for serial port to connect. Needed for native USB port only + } + + // in Zephyr system check if Ethernet is ready before proceeding to initialize + Serial.print("Waiting for link on"); + while (Ethernet.linkStatus() != LinkON) { + Serial.print("."); + delay(100); + } + Serial.println(); + + // start the Ethernet connection: + Serial.println("Initialize Ethernet with DHCP:"); + if (Ethernet.begin() == 0) { + Serial.println("Failed to configure Ethernet using DHCP"); + // 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."); + } + // try to congifure using IP address instead of DHCP: + Ethernet.begin(ip, myDns); + Serial.print("My IP address: "); + Serial.println(Ethernet.localIP()); + } else { + Serial.print(" DHCP assigned IP "); + Serial.println(Ethernet.localIP()); + } + // give the Ethernet shield a second to initialize: + delay(1000); +} + +void loop() { + // if there's incoming data from the net connection. + // send it out the serial port. This is for debugging + // purposes only: + if (client.available()) { + char c = client.read(); + Serial.write(c); + } + + // if ten seconds have passed since your last connection, + // then connect again and send data: + if (millis() - lastConnectionTime > postingInterval) { + httpRequest(); + } + +} + +// this method makes a HTTP connection to the server: +void httpRequest() { + // close any connection before send a new request. + // This will free the socket on the WiFi shield + client.stop(); + + // if there's a successful connection: + if (client.connect(server, 80)) { + Serial.println("connecting..."); + // send the HTTP GET request: + client.println("GET /latest.txt HTTP/1.1"); + client.println("Host: www.arduino.cc"); + client.println("User-Agent: arduino-ethernet"); + client.println("Connection: close"); + client.println(); + + // note the time that the connection was made: + lastConnectionTime = millis(); + } else { + // if you couldn't make a connection: + Serial.println("connection failed"); + } +} + + + + diff --git a/libraries/Ethernet/examples/WebClientRepeatingManual/WebClientRepeatingManual.ino b/libraries/Ethernet/examples/WebClientRepeatingManual/WebClientRepeatingManual.ino new file mode 100644 index 00000000..ce1d728d --- /dev/null +++ b/libraries/Ethernet/examples/WebClientRepeatingManual/WebClientRepeatingManual.ino @@ -0,0 +1,142 @@ +/* + Repeating Web client + + This sketch connects to a a web server and makes a request + using a Wiznet Ethernet shield. You can use the Arduino Ethernet shield, or + the Adafruit Ethernet shield, either one will work, as long as it's got + a Wiznet Ethernet module on board. + + This example uses DNS, by assigning the Ethernet client with a MAC address, + IP address, and DNS address. + */ + +#include +#include "ZephyrEthernet.h" + +// The IP address will be dependent on your local network. +// DNS, gateway and subnet are optional: +IPAddress ip(192, 168, 1, 177); +IPAddress myDns(192, 168, 1, 1); +IPAddress gateway(192, 168, 1, 1); +IPAddress subnet(255, 255, 0, 0); + +// initialize the library instance: +ZephyrClient client; + +char server[] = "www.arduino.cc"; // also change the Host line in httpRequest() +//IPAddress server(64,131,82,241); + +unsigned long lastConnectionTime = 0; // last time you connected to the server, in milliseconds +const unsigned long postingInterval = 10 * 1000; // delay between updates, in milliseconds + +void setup() +{ + // start serial port: + Serial.begin(9600); + while (!Serial) { + ; // wait for serial port to connect. Needed for native USB port only + } + + // in Zephyr system check if Ethernet is ready before proceeding to initialize + Serial.print("Waiting for link on"); + while (Ethernet.linkStatus() != LinkON) { + Serial.print("."); + delay(100); + } + Serial.println(); + + delay(2500); + + // start the Ethernet connection: + Serial.println("Initialize Ethernet with Static IP Address:"); + if (Ethernet.begin(ip, myDns, gateway, subnet) == 0) { + Serial.println("Failed to configure Ethernet with Static IP Address"); + // 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."); + } + // try to congifure using IP address instead of DHCP: + Serial.print("My IP address: "); + Serial.println(Ethernet.localIP()); + Serial.print("My Gateway IP address: "); + Serial.println(Ethernet.gatewayIP()); + Serial.print("My DNS Server IP address: "); + Serial.println(Ethernet.dnsServerIP()); + // give the Ethernet shield a second to initialize: + delay(2500); +} + +void loop() +{ + // if there's incoming data from the net connection. + // send it out the serial port. This is for debugging + // purposes only: + if (client.available()) { + char c = client.read(); + Serial.write(c); + } + + // if ten seconds have passed since your last connection, + // then connect again and send data: + if (millis() - lastConnectionTime > postingInterval) { + httpRequest(); + } +} + +// this method makes a HTTP connection to the server: +void httpRequest() +{ + // close any connection before send a new request. + // This will free the socket on the WiFi shield + client.stop(); + + // if there's a successful connection: + if (client.connect(server, 80)) { + Serial.println("connecting..."); + // send the HTTP GET request: + client.println("GET /latest.txt HTTP/1.1"); + client.println("Host: www.arduino.cc"); + client.println("User-Agent: arduino-ethernet"); + client.println("Connection: close"); + client.println(); + + // note the time that the connection was made: + lastConnectionTime = millis(); + } else { + // if you couldn't make a connection: + Serial.println("connection failed"); + } +} + +void connectEth() +{ + // start the Ethernet connection: + Serial.println("Initialize Ethernet with DHCP:"); + if (Ethernet.begin(nullptr) == 0) { + Serial.println("Failed to configure Ethernet using DHCP"); + // 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."); + } + } else { + Serial.print(" DHCP assigned IP "); + Serial.println(Ethernet.localIP()); + } + + Serial.println("You're connected to the network"); + Serial.println(); +} diff --git a/libraries/Ethernet/examples/WebClientRepeatingSSL/WebClientRepeatingSSL.ino b/libraries/Ethernet/examples/WebClientRepeatingSSL/WebClientRepeatingSSL.ino new file mode 100644 index 00000000..748f63c1 --- /dev/null +++ b/libraries/Ethernet/examples/WebClientRepeatingSSL/WebClientRepeatingSSL.ino @@ -0,0 +1,110 @@ +/* + Repeating TLS/SSL Ethernet Web client. + + Remeber to update the CA certificates using WiFiFirmwareUpdater sketch + before using this sketch. + + */ + +#include +#include "ZephyrEthernet.h" + +// initialize the library instance: +ZephyrSSLClient client; + +char server[] = "www.arduino.cc"; +int port = 443; +// IPAddress server(64,131,82,241); + +// Set the static IP address to use if the DHCP fails to assign +IPAddress ip(192, 168, 0, 177); +IPAddress myDns(192, 168, 0, 1); + +unsigned long lastConnectionTime = 0; // last time you connected to the server, in milliseconds +const unsigned long postingInterval = 10 * 1000; // delay between updates, in milliseconds + +void setup() +{ + // start serial port: + Serial.begin(9600); + while (!Serial) { + ; // wait for serial port to connect. Needed for native USB port only + } + + // in Zephyr system check if Ethernet is ready before proceeding to initialize + Serial.print("Waiting for link on"); + while (Ethernet.linkStatus() != LinkON) { + Serial.print("."); + delay(100); + } + Serial.println(); + + // start the Ethernet connection: + Serial.println("Initialize Ethernet with DHCP:"); + if (Ethernet.begin() == 0) { + Serial.println("Failed to configure Ethernet using DHCP"); + // 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."); + } + // try to congifure using IP address instead of DHCP: + Ethernet.begin(ip, myDns); + Serial.print("My IP address: "); + Serial.println(Ethernet.localIP()); + } else { + Serial.print(" DHCP assigned IP "); + Serial.println(Ethernet.localIP()); + } + // give the Ethernet shield a second to initialize: + delay(1000); +} + +void loop() +{ + // if there's incoming data from the net connection. + // send it out the serial port. This is for debugging + // purposes only: + if (client.available()) { + char c = client.read(); + Serial.write(c); + } + + // if ten seconds have passed since your last connection, + // then connect again and send data: + if (millis() - lastConnectionTime > postingInterval) { + httpRequest(); + } +} + +// this method makes a HTTP connection to the server: +void httpRequest() +{ + // close any connection before send a new request. + // This will free the socket on the WiFi shield + client.stop(); + + // if there's a successful connection: + if (client.connect(server, port)) { + Serial.println("connecting..."); + // send the HTTP GET request: + client.println("GET /latest.txt HTTP/1.1"); + client.print("Host: "); + client.println(server); + client.println("User-Agent: arduino-ethernet"); + client.println("Accept: *"); + client.println("Connection: close"); + client.println(); + + // note the time that the connection was made: + lastConnectionTime = millis(); + } else { + // if you couldn't make a connection: + Serial.println("connection failed"); + } +} diff --git a/libraries/Ethernet/examples/TestServer/TestServer.ino b/libraries/Ethernet/examples/WebServer/WebServer.ino similarity index 57% rename from libraries/Ethernet/examples/TestServer/TestServer.ino rename to libraries/Ethernet/examples/WebServer/WebServer.ino index b74e6ce3..6dd3a287 100644 --- a/libraries/Ethernet/examples/TestServer/TestServer.ino +++ b/libraries/Ethernet/examples/WebServer/WebServer.ino @@ -1,27 +1,66 @@ +/* + Web Server + + A simple web server that shows the value of the analog input pins. + using an Arduino Wiznet Ethernet shield. + + */ + #include "ZephyrServer.h" -#include "Ethernet.h" +#include "ZephyrClient.h" +#include "ZephyrEthernet.h" + +// The IP address will be dependent on your local network: +IPAddress ip(192, 168, 2, 177); +// Initialize the Ethernet server library +// with the IP address and port you want to use +// (port 80 is default for HTTP): ZephyrServer server(80); void setup() { - Serial.begin(115200); + // 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("Ethernet WebServer Example"); + + // in Zephyr system check if Ethernet is ready before proceeding to initialize while (Ethernet.linkStatus() != LinkON) { - Serial.println("waiting for link on"); + Serial.println("Waiting for link on"); delay(100); } - Ethernet.begin(); - Serial.println(Ethernet.localIP()); + + // start the Ethernet connection and the server: + Ethernet.begin(ip); + + // 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."); + } + + // start the server server.begin(); + Serial.print("server is at "); + Serial.println(Ethernet.localIP()); } -void loop() { - ZephyrClient client = server.available(); +void loop() { + // listen for incoming clients + ZephyrClient client = server.accept(); if (client) { Serial.println("new client"); // an http request ends with a blank line - bool currentLineIsBlank = true; + boolean currentLineIsBlank = true; while (client.connected()) { if (client.available()) { char c = client.read(); @@ -40,7 +79,7 @@ void loop() { client.println(""); // output the value of each analog input pin for (int analogChannel = 0; analogChannel < 6; analogChannel++) { - int sensorReading = random(analogChannel, 100); + int sensorReading = analogRead(analogChannel); client.print("analog input "); client.print(analogChannel); client.print(" is "); @@ -50,11 +89,9 @@ void loop() { client.println(""); break; } - if (c == '\n') { // you're starting a new line currentLineIsBlank = true; - } else if (c != '\r') { // you've gotten a character on the current line currentLineIsBlank = false; @@ -66,7 +103,6 @@ void loop() { // close the connection: client.stop(); Serial.println("client disconnected"); - } else { - delay(100); } -} \ No newline at end of file +} + diff --git a/libraries/Ethernet/src/Ethernet.h b/libraries/Ethernet/src/Ethernet.h index da0ffc96..09d29de1 100644 --- a/libraries/Ethernet/src/Ethernet.h +++ b/libraries/Ethernet/src/Ethernet.h @@ -32,6 +32,18 @@ class EthernetClass: public NetworkInterface int begin(uint8_t *mac, IPAddress ip, IPAddress dns, IPAddress gateway); int begin(uint8_t *mac, IPAddress ip, IPAddress dns, IPAddress gateway, IPAddress subnet, unsigned long timeout = 60000, unsigned long responseTimeout = 4000); + int begin(IPAddress ip) { + return begin(nullptr, ip); + } + int begin(IPAddress ip, IPAddress dns) { + return begin(nullptr, ip, dns); + } + int begin(IPAddress ip, IPAddress dns, IPAddress gateway) { + return begin(nullptr, ip, dns, gateway); + } + int begin(IPAddress ip, IPAddress dns, IPAddress gateway, IPAddress subnet) { + return begin(nullptr, ip, dns, gateway, subnet); + } void init(uint8_t sspin = 10); int disconnect(void); diff --git a/libraries/SocketWrapper/SocketWrapper.h b/libraries/SocketWrapper/SocketWrapper.h index ad5c36db..ce58ec8d 100644 --- a/libraries/SocketWrapper/SocketWrapper.h +++ b/libraries/SocketWrapper/SocketWrapper.h @@ -265,5 +265,27 @@ class ZephyrSocketWrapper { return ::accept(sock_fd, nullptr, nullptr); } + String remoteIP() { + if (sock_fd == -1) { + return {}; + } + + struct sockaddr_storage addr; + socklen_t addr_len = sizeof(addr); + char ip_str[INET6_ADDRSTRLEN] = {0}; + + if (::getpeername(sock_fd, (struct sockaddr*)&addr, &addr_len) == 0) { + if (addr.ss_family == AF_INET) { + struct sockaddr_in *s = (struct sockaddr_in*)&addr; + ::inet_ntop(AF_INET, &s->sin_addr, ip_str, sizeof(ip_str)); + } else if (addr.ss_family == AF_INET6) { + struct sockaddr_in6 *s6 = (struct sockaddr_in6*)&addr; + ::inet_ntop(AF_INET6, &s6->sin6_addr, ip_str, sizeof(ip_str)); + } + return String(ip_str); + } + + return {}; + } friend class ZephyrClient; }; diff --git a/libraries/SocketWrapper/ZephyrClient.h b/libraries/SocketWrapper/ZephyrClient.h index 8d947963..7ba08627 100644 --- a/libraries/SocketWrapper/ZephyrClient.h +++ b/libraries/SocketWrapper/ZephyrClient.h @@ -85,5 +85,8 @@ class ZephyrClient : public arduino::Client, ZephyrSocketWrapper { operator bool() { return sock_fd != -1; } + String remoteIP() { + return ZephyrSocketWrapper::remoteIP(); + } friend class ZephyrServer; }; \ No newline at end of file diff --git a/libraries/SocketWrapper/ZephyrUDP.h b/libraries/SocketWrapper/ZephyrUDP.h index d0620205..27cf40f9 100644 --- a/libraries/SocketWrapper/ZephyrUDP.h +++ b/libraries/SocketWrapper/ZephyrUDP.h @@ -29,6 +29,8 @@ #include #include +#define UDP_TX_PACKET_MAX_SIZE 24 + class ZephyrUDP : public arduino::UDP { private: int _socket; diff --git a/loader/llext_exports.c b/loader/llext_exports.c index 5da9b619..a76672ab 100644 --- a/loader/llext_exports.c +++ b/loader/llext_exports.c @@ -161,6 +161,8 @@ FORCE_EXPORT_SYM(inet_pton); FORCE_EXPORT_SYM(sendto); FORCE_EXPORT_SYM(recvfrom); FORCE_EXPORT_SYM(setsockopt); +FORCE_EXPORT_SYM(getpeername); +FORCE_EXPORT_SYM(inet_ntop); #endif #if defined(CONFIG_CDC_ACM_DTE_RATE_CALLBACK_SUPPORT)