1
0
mirror of https://github.com/esp8266/Arduino.git synced 2025-04-21 10:26:06 +03:00

Make SSDP event-driven

This commit is contained in:
Ivan Grokhotkov 2015-07-07 17:39:13 +03:00
parent 0c0892c54a
commit 1b27b6760c
3 changed files with 140 additions and 58 deletions

View File

@ -26,14 +26,23 @@ License (MIT license):
*/ */
#define LWIP_OPEN_SRC #define LWIP_OPEN_SRC
#include <functional>
#include "ESP8266SSDP.h" #include "ESP8266SSDP.h"
#include "WiFiUdp.h"
#include "debug.h"
extern "C" { extern "C" {
#include "osapi.h"
#include "ets_sys.h"
#include "user_interface.h" #include "user_interface.h"
#include "mem.h"
} }
#include "lwip/ip_addr.h"
#include "lwip/opt.h"
#include "lwip/udp.h"
#include "lwip/inet.h"
#include "lwip/igmp.h" #include "lwip/igmp.h"
#include "lwip/mem.h"
#include "include/UdpContext.h"
// #define DEBUG_SSDP Serial // #define DEBUG_SSDP Serial
@ -42,9 +51,11 @@ extern "C" {
#define SSDP_METHOD_SIZE 10 #define SSDP_METHOD_SIZE 10
#define SSDP_URI_SIZE 2 #define SSDP_URI_SIZE 2
#define SSDP_BUFFER_SIZE 64 #define SSDP_BUFFER_SIZE 64
#define SSDP_MULTICAST_TTL 1
static const IPAddress SSDP_MULTICAST_ADDR(239, 255, 255, 250); static const IPAddress SSDP_MULTICAST_ADDR(239, 255, 255, 250);
static const char* _ssdp_response_template = static const char* _ssdp_response_template =
"HTTP/1.1 200 OK\r\n" "HTTP/1.1 200 OK\r\n"
"EXT:\r\n" "EXT:\r\n"
@ -108,7 +119,17 @@ static const char* _ssdp_schema_template =
"</root>\r\n" "</root>\r\n"
"\r\n"; "\r\n";
SSDPClass::SSDPClass(){
struct SSDPTimer {
ETSTimer timer;
};
SSDPClass::SSDPClass() :
_server(0),
_port(80),
_pending(false),
_timer(new SSDPTimer)
{
_uuid[0] = '\0'; _uuid[0] = '\0';
_modelNumber[0] = '\0'; _modelNumber[0] = '\0';
_friendlyName[0] = '\0'; _friendlyName[0] = '\0';
@ -119,57 +140,64 @@ SSDPClass::SSDPClass(){
_manufacturer[0] = '\0'; _manufacturer[0] = '\0';
_manufacturerURL[0] = '\0'; _manufacturerURL[0] = '\0';
sprintf(_schemaURL, "ssdp/schema.xml"); sprintf(_schemaURL, "ssdp/schema.xml");
_port = 80;
_pending = false;
} }
SSDPClass::~SSDPClass(){ SSDPClass::~SSDPClass(){
delete _timer;
} }
void SSDPClass::begin(){ bool SSDPClass::begin(){
ip_addr_t ifaddr;
ip_addr_t multicast_addr;
_pending = false; _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(); uint32_t chipId = ESP.getChipId();
sprintf(_uuid, "38323636-4558-%04x-%04x-%02x%02x%02x%02x%02x%02x", sprintf(_uuid, "38323636-4558-4dda-9188-cda0e6%02x%02x%02x",
(chipId >> 16) & 0xFFFF, chipId & 0xFFFF, (uint16_t) ((chipId >> 16) & 0xff),
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5] (uint16_t) ((chipId >> 8) & 0xff),
); (uint16_t) chipId & 0xff );
#ifdef DEBUG_SSDP #ifdef DEBUG_SSDP
DEBUG_SSDP.printf("SSDP UUID: %s\n", (char *)_uuid); DEBUG_SSDP.printf("SSDP UUID: %s\n", (char *)_uuid);
#endif #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){ void SSDPClass::_send(ssdp_method_t method){
#ifdef DEBUG_SSDP char buffer[1460];
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);
}
uint32_t ip = WiFi.localIP(); 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, (method == NONE)?_ssdp_response_template:_ssdp_notify_template,
SSDP_INTERVAL, SSDP_INTERVAL,
_modelName, _modelNumber, _modelName, _modelNumber,
@ -177,7 +205,30 @@ void SSDPClass::_send(ssdp_method_t method){
IP2STR(&ip), _port, _schemaURL 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){ void SSDPClass::schema(WiFiClient client){
@ -196,10 +247,13 @@ void SSDPClass::schema(WiFiClient client){
); );
} }
uint8_t SSDPClass::update(){ void SSDPClass::_update(){
if(!_pending && _server.parsePacket() > 0){ if(!_pending && _server->next()) {
ssdp_method_t method = NONE; ssdp_method_t method = NONE;
_respondToAddr = _server->getRemoteAddress();
_respondToPort = _server->getRemotePort();
typedef enum {METHOD, URI, PROTO, KEY, VALUE, ABORT} states; typedef enum {METHOD, URI, PROTO, KEY, VALUE, ABORT} states;
states state = METHOD; states state = METHOD;
@ -211,8 +265,8 @@ uint8_t SSDPClass::update(){
char buffer[SSDP_BUFFER_SIZE] = {0}; char buffer[SSDP_BUFFER_SIZE] = {0};
while(_server.available() > 0){ while(_server->getSize() > 0){
char c = _server.read(); char c = _server->read();
(c == '\r' || c == '\n') ? cr++ : cr = 0; (c == '\r' || c == '\n') ? cr++ : cr = 0;
@ -280,8 +334,6 @@ uint8_t SSDPClass::update(){
break; break;
} }
} }
_server.flush();
} }
if(_pending && (millis() - _process_time) > _delay){ if(_pending && (millis() - _process_time) > _delay){
@ -291,6 +343,12 @@ uint8_t SSDPClass::update(){
_notify_time = millis(); _notify_time = millis();
_send(NOTIFY); _send(NOTIFY);
} }
if (_pending) {
while (_server->next())
_server->flush();
}
} }
void SSDPClass::setSchemaURL(const char *url){ void SSDPClass::setSchemaURL(const char *url){
@ -333,4 +391,16 @@ void SSDPClass::setManufacturerURL(const char *url){
strlcpy(_manufacturerURL, url, sizeof(_manufacturerURL)); 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<ETSTimerFunc*>(&SSDPClass::_onTimerStatic), reinterpret_cast<void*>(this));
os_timer_arm(tm, interval, 1 /* repeat */);
}
SSDPClass SSDP; SSDPClass SSDP;

View File

@ -33,6 +33,8 @@ License (MIT license):
#include <ESP8266WiFi.h> #include <ESP8266WiFi.h>
#include <WiFiUdp.h> #include <WiFiUdp.h>
class UdpContext;
#define SSDP_UUID_SIZE 37 #define SSDP_UUID_SIZE 37
#define SSDP_SCHEMA_URL_SIZE 64 #define SSDP_SCHEMA_URL_SIZE 64
#define SSDP_FRIENDLY_NAME_SIZE 64 #define SSDP_FRIENDLY_NAME_SIZE 64
@ -50,13 +52,16 @@ typedef enum {
NOTIFY NOTIFY
} ssdp_method_t; } ssdp_method_t;
struct SSDPTimer;
class SSDPClass{ class SSDPClass{
public: public:
SSDPClass(); SSDPClass();
~SSDPClass(); ~SSDPClass();
void begin(); bool begin();
uint8_t update();
void schema(WiFiClient client); void schema(WiFiClient client);
void setName(const String& name) { setName(name.c_str()); } void setName(const String& name) { setName(name.c_str()); }
@ -79,8 +84,18 @@ class SSDPClass{
void setManufacturerURL(const char *url); void setManufacturerURL(const char *url);
void setHTTPPort(uint16_t port); void setHTTPPort(uint16_t port);
private: protected:
WiFiUDP _server; 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; bool _pending;
unsigned short _delay; unsigned short _delay;
unsigned long _process_time; unsigned long _process_time;
@ -97,8 +112,6 @@ class SSDPClass{
char _modelName[SSDP_MODEL_NAME_SIZE]; char _modelName[SSDP_MODEL_NAME_SIZE];
char _modelURL[SSDP_MODEL_URL_SIZE]; char _modelURL[SSDP_MODEL_URL_SIZE];
char _modelNumber[SSDP_MODEL_VERSION_SIZE]; char _modelNumber[SSDP_MODEL_VERSION_SIZE];
void _send(ssdp_method_t method);
}; };
extern SSDPClass SSDP; extern SSDPClass SSDP;

View File

@ -48,6 +48,5 @@ void setup() {
void loop() { void loop() {
HTTP.handleClient(); HTTP.handleClient();
SSDP.update();
delay(1); delay(1);
} }