mirror of
https://github.com/esp8266/Arduino.git
synced 2025-04-25 20:02:37 +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
|
||||
#include <functional>
|
||||
#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 =
|
||||
"</root>\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<ETSTimerFunc*>(&SSDPClass::_onTimerStatic), reinterpret_cast<void*>(this));
|
||||
os_timer_arm(tm, interval, 1 /* repeat */);
|
||||
}
|
||||
|
||||
SSDPClass SSDP;
|
||||
|
@ -33,6 +33,8 @@ License (MIT license):
|
||||
#include <ESP8266WiFi.h>
|
||||
#include <WiFiUdp.h>
|
||||
|
||||
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;
|
||||
|
@ -48,6 +48,5 @@ void setup() {
|
||||
|
||||
void loop() {
|
||||
HTTP.handleClient();
|
||||
SSDP.update();
|
||||
delay(1);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user