diff --git a/libraries/ESP8266SSDP/ESP8266SSDP.cpp b/libraries/ESP8266SSDP/ESP8266SSDP.cpp index c381f7ff9..24997eee8 100644 --- a/libraries/ESP8266SSDP/ESP8266SSDP.cpp +++ b/libraries/ESP8266SSDP/ESP8266SSDP.cpp @@ -26,25 +26,36 @@ License (MIT license): */ #define LWIP_OPEN_SRC +#include #include "ESP8266SSDP.h" +#include "WiFiUdp.h" +#include "debug.h" extern "C" { + #include "osapi.h" + #include "ets_sys.h" #include "user_interface.h" - #include "mem.h" } -#include "lwip/ip_addr.h" -#include "lwip/igmp.h" -//#define DEBUG_SSDP Serial +#include "lwip/opt.h" +#include "lwip/udp.h" +#include "lwip/inet.h" +#include "lwip/igmp.h" +#include "lwip/mem.h" +#include "include/UdpContext.h" + +// #define DEBUG_SSDP Serial #define SSDP_INTERVAL 1200 #define SSDP_PORT 1900 #define SSDP_METHOD_SIZE 10 #define SSDP_URI_SIZE 2 #define SSDP_BUFFER_SIZE 64 - +#define SSDP_MULTICAST_TTL 1 static const IPAddress SSDP_MULTICAST_ADDR(239, 255, 255, 250); + + static const char* _ssdp_response_template = "HTTP/1.1 200 OK\r\n" "EXT:\r\n" @@ -108,7 +119,17 @@ static const char* _ssdp_schema_template = "\r\n" "\r\n"; -SSDPClass::SSDPClass(){ + +struct SSDPTimer { + ETSTimer timer; +}; + +SSDPClass::SSDPClass() : +_server(0), +_port(80), +_pending(false), +_timer(new SSDPTimer) +{ _uuid[0] = '\0'; _modelNumber[0] = '\0'; _friendlyName[0] = '\0'; @@ -119,65 +140,95 @@ SSDPClass::SSDPClass(){ _manufacturer[0] = '\0'; _manufacturerURL[0] = '\0'; sprintf(_schemaURL, "ssdp/schema.xml"); - _port = 80; - _pending = false; } SSDPClass::~SSDPClass(){ + delete _timer; } -void SSDPClass::begin(){ - ip_addr_t ifaddr; - ip_addr_t multicast_addr; - +bool SSDPClass::begin(){ _pending = false; - - ifaddr.addr = WiFi.localIP(); - multicast_addr.addr = (uint32_t) SSDP_MULTICAST_ADDR; - igmp_joingroup(&ifaddr, &multicast_addr); - - uint8_t mac[6]; - WiFi.macAddress(mac); + uint32_t chipId = ESP.getChipId(); - sprintf(_uuid, "38323636-4558-%04x-%04x-%02x%02x%02x%02x%02x%02x", - (chipId >> 16) & 0xFFFF, chipId & 0xFFFF, - mac[0], mac[1], mac[2], mac[3], mac[4], mac[5] - ); + sprintf(_uuid, "38323636-4558-4dda-9188-cda0e6%02x%02x%02x", + (uint16_t) ((chipId >> 16) & 0xff), + (uint16_t) ((chipId >> 8) & 0xff), + (uint16_t) chipId & 0xff ); + #ifdef DEBUG_SSDP DEBUG_SSDP.printf("SSDP UUID: %s\n", (char *)_uuid); #endif - _server.begin(SSDP_PORT); + + if (_server) { + _server->unref(); + _server = 0; + } + + _server = new UdpContext; + _server->ref(); + + ip_addr_t ifaddr; + ifaddr.addr = WiFi.localIP(); + ip_addr_t multicast_addr; + multicast_addr.addr = (uint32_t) SSDP_MULTICAST_ADDR; + if (igmp_joingroup(&ifaddr, &multicast_addr) != ERR_OK ) { + DEBUGV("SSDP failed to join igmp group"); + return false; + } + + if (!_server->listen(*IP_ADDR_ANY, SSDP_PORT)) { + return false; + } + + _server->setMulticastInterface(ifaddr); + _server->setMulticastTTL(SSDP_MULTICAST_TTL); + _server->onRx(std::bind(&SSDPClass::_update, this)); + if (!_server->connect(multicast_addr, SSDP_PORT)) { + return false; + } + + _startTimer(); + + return true; } void SSDPClass::_send(ssdp_method_t method){ -#ifdef DEBUG_SSDP - if(method == NONE){ - DEBUG_SSDP.print("Sending Response to "); - DEBUG_SSDP.print(_server.remoteIP()); - DEBUG_SSDP.print(":"); - DEBUG_SSDP.println(_server.remotePort()); - }else if(method == NOTIFY){ - DEBUG_SSDP.println("Sending Notify to 239.255.255.250:1900"); - } -#endif - - if(method == NONE){ - _server.beginPacket(_server.remoteIP(), _server.remotePort()); - } else { - _server.beginPacket(SSDP_MULTICAST_ADDR, SSDP_PORT); - } - + char buffer[1460]; uint32_t ip = WiFi.localIP(); - _server.printf(_ssdp_packet_template, + int len = snprintf(buffer, sizeof(buffer), + _ssdp_packet_template, (method == NONE)?_ssdp_response_template:_ssdp_notify_template, SSDP_INTERVAL, _modelName, _modelNumber, _uuid, IP2STR(&ip), _port, _schemaURL ); - - _server.endPacket(); + + _server->append(buffer, len); + + ip_addr_t remoteAddr; + uint16_t remotePort; + if(method == NONE) { + remoteAddr.addr = _respondToAddr; + remotePort = _respondToPort; +#ifdef DEBUG_SSDP + DEBUG_SSDP.print("Sending Response to "); +#endif + } else { + remoteAddr.addr = SSDP_MULTICAST_ADDR; + remotePort = SSDP_PORT; +#ifdef DEBUG_SSDP + DEBUG_SSDP.println("Sending Notify to "); +#endif + } +#ifdef DEBUG_SSDP + DEBUG_SSDP.print(IPAddress(remoteAddr.addr)); + DEBUG_SSDP.print(":"); + DEBUG_SSDP.println(remotePort); +#endif + + _server->send(&remoteAddr, remotePort); } void SSDPClass::schema(WiFiClient client){ @@ -196,10 +247,13 @@ void SSDPClass::schema(WiFiClient client){ ); } -uint8_t SSDPClass::update(){ - if(!_pending && _server.parsePacket() > 0){ +void SSDPClass::_update(){ + if(!_pending && _server->next()) { ssdp_method_t method = NONE; + _respondToAddr = _server->getRemoteAddress(); + _respondToPort = _server->getRemotePort(); + typedef enum {METHOD, URI, PROTO, KEY, VALUE, ABORT} states; states state = METHOD; @@ -211,8 +265,8 @@ uint8_t SSDPClass::update(){ char buffer[SSDP_BUFFER_SIZE] = {0}; - while(_server.available() > 0){ - char c = _server.read(); + while(_server->getSize() > 0){ + char c = _server->read(); (c == '\r' || c == '\n') ? cr++ : cr = 0; @@ -280,8 +334,6 @@ uint8_t SSDPClass::update(){ break; } } - - _server.flush(); } if(_pending && (millis() - _process_time) > _delay){ @@ -291,6 +343,12 @@ uint8_t SSDPClass::update(){ _notify_time = millis(); _send(NOTIFY); } + + if (_pending) { + while (_server->next()) + _server->flush(); + } + } void SSDPClass::setSchemaURL(const char *url){ @@ -333,4 +391,16 @@ void SSDPClass::setManufacturerURL(const char *url){ strlcpy(_manufacturerURL, url, sizeof(_manufacturerURL)); } +void SSDPClass::_onTimerStatic(SSDPClass* self) { + self->_update(); +} + +void SSDPClass::_startTimer() { + ETSTimer* tm = &(_timer->timer); + const int interval = 1000; + os_timer_disarm(tm); + os_timer_setfn(tm, reinterpret_cast(&SSDPClass::_onTimerStatic), reinterpret_cast(this)); + os_timer_arm(tm, interval, 1 /* repeat */); +} + SSDPClass SSDP; diff --git a/libraries/ESP8266SSDP/ESP8266SSDP.h b/libraries/ESP8266SSDP/ESP8266SSDP.h index 44e8b4423..8f6e280f3 100644 --- a/libraries/ESP8266SSDP/ESP8266SSDP.h +++ b/libraries/ESP8266SSDP/ESP8266SSDP.h @@ -33,6 +33,8 @@ License (MIT license): #include #include +class UdpContext; + #define SSDP_UUID_SIZE 37 #define SSDP_SCHEMA_URL_SIZE 64 #define SSDP_FRIENDLY_NAME_SIZE 64 @@ -50,13 +52,16 @@ typedef enum { NOTIFY } ssdp_method_t; + +struct SSDPTimer; + class SSDPClass{ public: SSDPClass(); ~SSDPClass(); - void begin(); - uint8_t update(); + bool begin(); + void schema(WiFiClient client); void setName(const String& name) { setName(name.c_str()); } @@ -78,9 +83,19 @@ class SSDPClass{ void setManufacturerURL(const String& url) { setManufacturerURL(url.c_str()); } void setManufacturerURL(const char *url); void setHTTPPort(uint16_t port); - - private: - WiFiUDP _server; + + protected: + void _send(ssdp_method_t method); + void _update(); + void _startTimer(); + static void _onTimerStatic(SSDPClass* self); + + UdpContext* _server; + SSDPTimer* _timer; + + IPAddress _respondToAddr; + uint16_t _respondToPort; + bool _pending; unsigned short _delay; unsigned long _process_time; @@ -97,8 +112,6 @@ class SSDPClass{ char _modelName[SSDP_MODEL_NAME_SIZE]; char _modelURL[SSDP_MODEL_URL_SIZE]; char _modelNumber[SSDP_MODEL_VERSION_SIZE]; - - void _send(ssdp_method_t method); }; extern SSDPClass SSDP; diff --git a/libraries/ESP8266SSDP/examples/SSDP/SSDP.ino b/libraries/ESP8266SSDP/examples/SSDP/SSDP.ino index be4c0791e..a1f55a848 100644 --- a/libraries/ESP8266SSDP/examples/SSDP/SSDP.ino +++ b/libraries/ESP8266SSDP/examples/SSDP/SSDP.ino @@ -48,6 +48,5 @@ void setup() { void loop() { HTTP.handleClient(); - SSDP.update(); delay(1); }