mirror of
https://github.com/esp8266/Arduino.git
synced 2025-04-22 21:23:07 +03:00
Make SSDP event-driven
This commit is contained in:
parent
0c0892c54a
commit
1b27b6760c
@ -26,25 +26,36 @@ 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/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_INTERVAL 1200
|
||||||
#define SSDP_PORT 1900
|
#define SSDP_PORT 1900
|
||||||
#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;
|
||||||
|
@ -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;
|
||||||
|
@ -48,6 +48,5 @@ void setup() {
|
|||||||
|
|
||||||
void loop() {
|
void loop() {
|
||||||
HTTP.handleClient();
|
HTTP.handleClient();
|
||||||
SSDP.update();
|
|
||||||
delay(1);
|
delay(1);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user