mirror of https://github.com/lumapu/ahoy.git
				
				
			
				 6 changed files with 316 additions and 7 deletions
			
			
		@ -0,0 +1,243 @@ | 
				
			|||
//-----------------------------------------------------------------------------
 | 
				
			|||
// 2023 Ahoy, https://www.mikrocontroller.net/topic/525778
 | 
				
			|||
// Creative Commons - http://creativecommons.org/licenses/by-nc-sa/3.0/de/
 | 
				
			|||
//-----------------------------------------------------------------------------
 | 
				
			|||
 | 
				
			|||
#if defined(ETHERNET) | 
				
			|||
 | 
				
			|||
#if defined(ESP32) && defined(F) | 
				
			|||
  #undef F | 
				
			|||
  #define F(sl) (sl) | 
				
			|||
#endif | 
				
			|||
#include "ahoyeth.h" | 
				
			|||
 | 
				
			|||
 | 
				
			|||
//-----------------------------------------------------------------------------
 | 
				
			|||
ahoyeth::ahoyeth() | 
				
			|||
{ | 
				
			|||
    // WiFi.onEvent(ESP32_W5500_event);
 | 
				
			|||
} | 
				
			|||
 | 
				
			|||
 | 
				
			|||
//-----------------------------------------------------------------------------
 | 
				
			|||
void ahoyeth::setup(settings_t *config, uint32_t *utcTimestamp, OnNetworkCB onNetworkCB, OnTimeCB onTimeCB) { | 
				
			|||
    mConfig = config; | 
				
			|||
    mUtcTimestamp = utcTimestamp; | 
				
			|||
    mOnNetworkCB = onNetworkCB; | 
				
			|||
    mOnTimeCB = onTimeCB; | 
				
			|||
 | 
				
			|||
    DPRINTLN(DBG_INFO, F("[ETH]: Register for events...")); | 
				
			|||
    Serial.flush(); | 
				
			|||
    WiFi.onEvent([this](WiFiEvent_t event, arduino_event_info_t info) -> void { this->onEthernetEvent(event, info); }); | 
				
			|||
 | 
				
			|||
    DPRINTLN(DBG_INFO, F("[ETH]: begin...")); | 
				
			|||
    Serial.flush(); | 
				
			|||
    ETH.begin(ETH_MISO_GPIO, ETH_MOSI_GPIO, ETH_SCK_GPIO, ETH_CS_PIN, ETH_INT_GPIO, ETH_SPI_CLOCK_MHZ, ETH_SPI_HOST); | 
				
			|||
} | 
				
			|||
 | 
				
			|||
 | 
				
			|||
//-----------------------------------------------------------------------------
 | 
				
			|||
bool ahoyeth::updateNtpTime(void) { | 
				
			|||
    DPRINTLN(DBG_DEBUG, F(__FUNCTION__)); Serial.flush(); | 
				
			|||
    Serial.printf("ETH.linkUp()=%s\n", ETH.linkUp() ? "up" : "down"); | 
				
			|||
    Serial.print("ETH.localIP()="); | 
				
			|||
    Serial.println(ETH.localIP()); | 
				
			|||
    Serial.printf("Go on? %s\n", (!ETH.localIP()) ? "No..." : "Yes..."); | 
				
			|||
    if (!ETH.localIP()) | 
				
			|||
        return false; | 
				
			|||
 | 
				
			|||
    DPRINTLN(DBG_DEBUG, F("updateNtpTime: checking udp \"connection\"...")); Serial.flush(); | 
				
			|||
    if (!mUdp.connected()) | 
				
			|||
    { | 
				
			|||
        DPRINTLN(DBG_DEBUG, F("updateNtpTime: About to (re)connect...")); Serial.flush(); | 
				
			|||
        IPAddress timeServer; | 
				
			|||
        if (!WiFi.hostByName(mConfig->ntp.addr, timeServer)) | 
				
			|||
            return false; | 
				
			|||
 | 
				
			|||
        if (!mUdp.connect(timeServer, mConfig->ntp.port)) | 
				
			|||
            return false; | 
				
			|||
 | 
				
			|||
        DPRINTLN(DBG_DEBUG, F("updateNtpTime: Connected...")); Serial.flush(); | 
				
			|||
        mUdp.onPacket([this](AsyncUDPPacket packet) | 
				
			|||
        { | 
				
			|||
            DPRINTLN(DBG_DEBUG, F("updateNtpTime: about to handle ntp packet...")); Serial.flush(); | 
				
			|||
            this->handleNTPPacket(packet); | 
				
			|||
        }); | 
				
			|||
    } | 
				
			|||
 | 
				
			|||
    DPRINTLN(DBG_DEBUG, F("updateNtpTime: prepare packet...")); Serial.flush(); | 
				
			|||
 | 
				
			|||
    // set all bytes in the buffer to 0
 | 
				
			|||
    memset(mUdpPacketBuffer, 0, NTP_PACKET_SIZE); | 
				
			|||
    // Initialize values needed to form NTP request
 | 
				
			|||
    // (see URL above for details on the packets)
 | 
				
			|||
 | 
				
			|||
    mUdpPacketBuffer[0]   = 0b11100011;   // LI, Version, Mode
 | 
				
			|||
    mUdpPacketBuffer[1]   = 0;     // Stratum, or type of clock
 | 
				
			|||
    mUdpPacketBuffer[2]   = 6;     // Polling Interval
 | 
				
			|||
    mUdpPacketBuffer[3]   = 0xEC;  // Peer Clock Precision
 | 
				
			|||
 | 
				
			|||
    // 8 bytes of zero for Root Delay & Root Dispersion
 | 
				
			|||
    mUdpPacketBuffer[12]  = 49; | 
				
			|||
    mUdpPacketBuffer[13]  = 0x4E; | 
				
			|||
    mUdpPacketBuffer[14]  = 49; | 
				
			|||
    mUdpPacketBuffer[15]  = 52; | 
				
			|||
 | 
				
			|||
    //Send unicast
 | 
				
			|||
    DPRINTLN(DBG_DEBUG, F("updateNtpTime: send packet...")); Serial.flush(); | 
				
			|||
    mUdp.write(mUdpPacketBuffer, sizeof(mUdpPacketBuffer)); | 
				
			|||
 | 
				
			|||
    return true; | 
				
			|||
} | 
				
			|||
 | 
				
			|||
//-----------------------------------------------------------------------------
 | 
				
			|||
void ahoyeth::handleNTPPacket(AsyncUDPPacket packet) { | 
				
			|||
    char       buf[80]; | 
				
			|||
 | 
				
			|||
    memcpy(buf, packet.data(), sizeof(buf)); | 
				
			|||
 | 
				
			|||
    unsigned long highWord = word(buf[40], buf[41]); | 
				
			|||
    unsigned long lowWord = word(buf[42], buf[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; | 
				
			|||
 | 
				
			|||
    *mUtcTimestamp = secsSince1900 - 2208988800UL; // UTC time
 | 
				
			|||
    DPRINTLN(DBG_INFO, "[NTP]: " + ah::getDateTimeStr(*mUtcTimestamp) + " UTC"); | 
				
			|||
    mOnTimeCB(true); | 
				
			|||
} | 
				
			|||
 | 
				
			|||
//-----------------------------------------------------------------------------
 | 
				
			|||
void ahoyeth::welcome(String ip, String mode) { | 
				
			|||
    DBGPRINTLN(F("\n\n--------------------------------")); | 
				
			|||
    DBGPRINTLN(F("Welcome to AHOY!")); | 
				
			|||
    DBGPRINT(F("\npoint your browser to http://")); | 
				
			|||
    DBGPRINT(ip); | 
				
			|||
    DBGPRINTLN(mode); | 
				
			|||
    DBGPRINTLN(F("to configure your device")); | 
				
			|||
    DBGPRINTLN(F("--------------------------------\n")); | 
				
			|||
} | 
				
			|||
 | 
				
			|||
void ahoyeth::onEthernetEvent(WiFiEvent_t event, arduino_event_info_t info) | 
				
			|||
{ | 
				
			|||
    AWS_LOG(F("[ETH]: Got event...")); | 
				
			|||
    switch (event) | 
				
			|||
    { | 
				
			|||
#if ( ( defined(ESP_ARDUINO_VERSION_MAJOR) && (ESP_ARDUINO_VERSION_MAJOR >= 2) ) && ( ARDUINO_ESP32_GIT_VER != 0x46d5afb1 ) ) | 
				
			|||
    // For breaking core v2.0.0
 | 
				
			|||
    // Why so strange to define a breaking enum arduino_event_id_t in WiFiGeneric.h
 | 
				
			|||
    // compared to the old system_event_id_t, now in tools/sdk/esp32/include/esp_event/include/esp_event_legacy.h
 | 
				
			|||
    // You can preserve the old enum order and just adding new items to do no harm
 | 
				
			|||
    case ARDUINO_EVENT_ETH_START: | 
				
			|||
        AWS_LOG(F("\nETH Started")); | 
				
			|||
        //set eth hostname here
 | 
				
			|||
        if(String(mConfig->sys.deviceName) != "") | 
				
			|||
            ETH.setHostname(mConfig->sys.deviceName); | 
				
			|||
        else | 
				
			|||
            ETH.setHostname("ESP32_W5500"); | 
				
			|||
        break; | 
				
			|||
 | 
				
			|||
    case ARDUINO_EVENT_ETH_CONNECTED: | 
				
			|||
        AWS_LOG(F("ETH Connected")); | 
				
			|||
        break; | 
				
			|||
 | 
				
			|||
    case ARDUINO_EVENT_ETH_GOT_IP: | 
				
			|||
        if (!ESP32_W5500_eth_connected) | 
				
			|||
        { | 
				
			|||
            AWS_LOG3(F("ETH MAC: "), ETH.macAddress(), F(", IPv4: "), ETH.localIP()); | 
				
			|||
 | 
				
			|||
            if (ETH.fullDuplex()) | 
				
			|||
            { | 
				
			|||
            AWS_LOG0(F("FULL_DUPLEX, ")); | 
				
			|||
            } | 
				
			|||
            else | 
				
			|||
            { | 
				
			|||
                AWS_LOG0(F("HALF_DUPLEX, ")); | 
				
			|||
            } | 
				
			|||
 | 
				
			|||
            AWS_LOG1(ETH.linkSpeed(), F("Mbps")); | 
				
			|||
 | 
				
			|||
            ESP32_W5500_eth_connected = true; | 
				
			|||
            mOnNetworkCB(true); | 
				
			|||
        } | 
				
			|||
        break; | 
				
			|||
 | 
				
			|||
    case ARDUINO_EVENT_ETH_DISCONNECTED: | 
				
			|||
      AWS_LOG("ETH Disconnected"); | 
				
			|||
      ESP32_W5500_eth_connected = false; | 
				
			|||
      mUdp.close(); | 
				
			|||
      mOnNetworkCB(false); | 
				
			|||
      break; | 
				
			|||
 | 
				
			|||
    case ARDUINO_EVENT_ETH_STOP: | 
				
			|||
      AWS_LOG("\nETH Stopped"); | 
				
			|||
      ESP32_W5500_eth_connected = false; | 
				
			|||
      mUdp.close(); | 
				
			|||
      mOnNetworkCB(false); | 
				
			|||
      break; | 
				
			|||
 | 
				
			|||
#else | 
				
			|||
 | 
				
			|||
    // For old core v1.0.6-
 | 
				
			|||
    // Core v2.0.0 defines a stupid enum arduino_event_id_t, breaking any code for ESP32_W5500 written for previous core
 | 
				
			|||
    // Why so strange to define a breaking enum arduino_event_id_t in WiFiGeneric.h
 | 
				
			|||
    // compared to the old system_event_id_t, now in tools/sdk/esp32/include/esp_event/include/esp_event_legacy.h
 | 
				
			|||
    // You can preserve the old enum order and just adding new items to do no harm
 | 
				
			|||
    case SYSTEM_EVENT_ETH_START: | 
				
			|||
        AWS_LOG(F("\nETH Started")); | 
				
			|||
        //set eth hostname here
 | 
				
			|||
        if(String(mConfig->sys.deviceName) != "") | 
				
			|||
            ETH.setHostname(mConfig->sys.deviceName); | 
				
			|||
        else | 
				
			|||
            ETH.setHostname("ESP32_W5500"); | 
				
			|||
        break; | 
				
			|||
 | 
				
			|||
    case SYSTEM_EVENT_ETH_CONNECTED: | 
				
			|||
        AWS_LOG(F("ETH Connected")); | 
				
			|||
        break; | 
				
			|||
 | 
				
			|||
    case SYSTEM_EVENT_ETH_GOT_IP: | 
				
			|||
        if (!ESP32_W5500_eth_connected) | 
				
			|||
        { | 
				
			|||
            AWS_LOG3(F("ETH MAC: "), ETH.macAddress(), F(", IPv4: "), ETH.localIP()); | 
				
			|||
 | 
				
			|||
            if (ETH.fullDuplex()) | 
				
			|||
            { | 
				
			|||
                AWS_LOG0(F("FULL_DUPLEX, ")); | 
				
			|||
            } | 
				
			|||
            else | 
				
			|||
            { | 
				
			|||
                AWS_LOG0(F("HALF_DUPLEX, ")); | 
				
			|||
            } | 
				
			|||
 | 
				
			|||
            AWS_LOG1(ETH.linkSpeed(), F("Mbps")); | 
				
			|||
 | 
				
			|||
            ESP32_W5500_eth_connected = true; | 
				
			|||
            mOnNetworkCB(true); | 
				
			|||
        } | 
				
			|||
        break; | 
				
			|||
 | 
				
			|||
    case SYSTEM_EVENT_ETH_DISCONNECTED: | 
				
			|||
        AWS_LOG("ETH Disconnected"); | 
				
			|||
        ESP32_W5500_eth_connected = false; | 
				
			|||
        mUdp.close(); | 
				
			|||
        mOnNetworkCB(false); | 
				
			|||
        break; | 
				
			|||
 | 
				
			|||
    case SYSTEM_EVENT_ETH_STOP: | 
				
			|||
        AWS_LOG("\nETH Stopped"); | 
				
			|||
        ESP32_W5500_eth_connected = false; | 
				
			|||
        mUdp.close(); | 
				
			|||
        mOnNetworkCB(false); | 
				
			|||
        break; | 
				
			|||
#endif | 
				
			|||
 | 
				
			|||
    default: | 
				
			|||
 | 
				
			|||
      break; | 
				
			|||
  } | 
				
			|||
 | 
				
			|||
} | 
				
			|||
 | 
				
			|||
#endif /* defined(ETHERNET) */ | 
				
			|||
@ -0,0 +1,60 @@ | 
				
			|||
//-----------------------------------------------------------------------------
 | 
				
			|||
// 2023 Ahoy, https://www.mikrocontroller.net/topic/525778
 | 
				
			|||
// Creative Commons - http://creativecommons.org/licenses/by-nc-sa/3.0/de/
 | 
				
			|||
//-----------------------------------------------------------------------------
 | 
				
			|||
 | 
				
			|||
#if defined(ETHERNET) | 
				
			|||
#ifndef __AHOYETH_H__ | 
				
			|||
#define __AHOYETH_H__ | 
				
			|||
 | 
				
			|||
#include <functional> | 
				
			|||
 | 
				
			|||
#include <Arduino.h> | 
				
			|||
#include <AsyncUDP.h> | 
				
			|||
#include <DNSServer.h> | 
				
			|||
 | 
				
			|||
#include "../utils/dbg.h" | 
				
			|||
#include "../config/config.h" | 
				
			|||
#include "../config/settings.h" | 
				
			|||
 | 
				
			|||
#include "AsyncWebServer_ESP32_W5500.h" | 
				
			|||
 | 
				
			|||
 | 
				
			|||
class app; | 
				
			|||
 | 
				
			|||
#define NTP_PACKET_SIZE 48 | 
				
			|||
 | 
				
			|||
class ahoyeth { | 
				
			|||
    public: /* types */ | 
				
			|||
        typedef std::function<void(bool)> OnNetworkCB; | 
				
			|||
        typedef std::function<void(bool)> OnTimeCB; | 
				
			|||
 | 
				
			|||
    public: | 
				
			|||
        ahoyeth(); | 
				
			|||
 | 
				
			|||
        void setup(settings_t *config, uint32_t *utcTimestamp, OnNetworkCB onNetworkCB, OnTimeCB onTimeCB); | 
				
			|||
        bool updateNtpTime(void); | 
				
			|||
 | 
				
			|||
    private: | 
				
			|||
        void setupEthernet(); | 
				
			|||
 | 
				
			|||
        void handleNTPPacket(AsyncUDPPacket packet); | 
				
			|||
 | 
				
			|||
        void welcome(String ip, String mode); | 
				
			|||
 | 
				
			|||
        void onEthernetEvent(WiFiEvent_t event, arduino_event_info_t info); | 
				
			|||
 | 
				
			|||
    private: | 
				
			|||
        settings_t *mConfig; | 
				
			|||
 | 
				
			|||
        uint32_t *mUtcTimestamp; | 
				
			|||
        AsyncUDP mUdp; // for time server
 | 
				
			|||
        byte mUdpPacketBuffer[NTP_PACKET_SIZE];   // buffer to hold incoming and outgoing packets
 | 
				
			|||
 | 
				
			|||
        OnNetworkCB mOnNetworkCB; | 
				
			|||
        OnTimeCB mOnTimeCB; | 
				
			|||
 | 
				
			|||
}; | 
				
			|||
 | 
				
			|||
#endif /*__AHOYETH_H__*/ | 
				
			|||
#endif /* defined(ETHERNET) */ | 
				
			|||
					Loading…
					
					
				
		Reference in new issue