diff --git a/README.md b/README.md
index ade7681..bac3164 100644
--- a/README.md
+++ b/README.md
@@ -165,7 +165,6 @@ SOFTWARE.
| Library | Copyright | License |
| :- | :- | :-: |
[WiFlash](https//git.company235.com/kevin/WiFlasher) | Copyright © 2020 Kevin Matz | [MIT](https//git.company235.com/kevin/WiFlasher/src/branch/master/LICENSE) |
-[ESPAsyncE131](https//github.com/forkineye/ESPAsyncE131) | Copyright © 2019 Shelby Merrick |
[NeoPixelBus](https//github.com/Makuna/NeoPixelBus) | Michael Miller| [LGPL 3.0](https//github.com/Makuna/NeoPixelBus/blob/master/COPYING) |
[ESPAsyncWebServer](https//github.com/me-no-dev/ESPAsyncWebServer) | Copyright © 2016 Hristo Gochkov | [LGPL 2.1](http//www.gnu.org/licenses/lgpl-2.1.html) |
[arduino-esp32](https//github.com/espressif/arduino-esp32) | Copyright © 2015 Ivan Grokhotkov | [LGPL 2.1](https//github.com/espressif/arduino-esp32/blob/master/LICENSE.md) |
diff --git a/wiflash_esp32/data/www/index.html b/wiflash_esp32/data/www/index.html
index 935f59d..29e0f3d 100644
--- a/wiflash_esp32/data/www/index.html
+++ b/wiflash_esp32/data/www/index.html
@@ -363,11 +363,6 @@
Copyright © 2020 Kevin Matz |
MIT |
-
- ESPAsyncE131 |
- Copyright © 2019 Shelby Merrick |
- |
-
NeoPixelBus |
Michael Miller |
diff --git a/wiflash_esp32/sacn.cpp b/wiflash_esp32/sacn.cpp
index 2c5d7b0..cbfbeac 100644
--- a/wiflash_esp32/sacn.cpp
+++ b/wiflash_esp32/sacn.cpp
@@ -1,19 +1,25 @@
/*
- ESPAsyncE131.cpp
+ sacn.cpp
- Project: ESPAsyncE131 - Asynchronous E.131 (sACN) library for Arduino ESP8266 and ESP32
- Copyright (c) 2019 Shelby Merrick
- http://www.forkineye.com
+ Copyright (c) 2020 Kevin Matz (kevin.matz@gmail.com)
- This program is provided free for you to use in any way that you wish,
- subject to the laws and regulations where you are using it. Due diligence
- is strongly suggested before using this code. Please give credit where due.
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
- The Author makes no warranty of any kind, express or implied, with regard
- to this program or the documentation contained in this document. The
- Author shall not be liable in any event for incidental or consequential
- damages in connection with, or arising out of, the furnishing, performance
- or use of these programs.
+ The above copyright notice and this permission notice shall be included in all
+ copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
*/
#include
@@ -21,27 +27,23 @@
#include
#include "sacn.h"
-// E1.17 ACN Packet Identifier
-const uint8_t ESPAsyncE131::ACN_ID[12] = { 0x41, 0x53, 0x43, 0x2d, 0x45, 0x31, 0x2e, 0x31, 0x37, 0x00, 0x00, 0x00 };
-ESPAsyncE131::ESPAsyncE131() {
- stats.num_packets = 0;
- stats.packet_errors = 0;
-
- udp.onPacket(std::bind(&ESPAsyncE131::parsePacket, this,
+ESPsACN::ESPsACN() {
+ udp.onPacket(std::bind(&ESPsACN::parsePacket, this,
std::placeholders::_1));
}
-bool ESPAsyncE131::subscribe(uint16_t num) {
- bool success = false;
+bool ESPsACN::subscribe(uint16_t num) {
+ bool success;
if (universes_.count(num)) {
// already subscribed
return true;
}
+ // listen multicast; works for unicast too
success = udp.listenMulticast(E131MulticastAddress(num),
- E131_DEFAULT_PORT);
+ ACN_SDT_MULTICAST_PORT);
Universe *u = new Universe();
universes_.emplace(num, u);
@@ -49,80 +51,54 @@ bool ESPAsyncE131::subscribe(uint16_t num) {
return success;
}
-void ESPAsyncE131::parsePacket(AsyncUDPPacket _packet) {
- e131_error_t error = ERROR_NONE;
-
+void ESPsACN::parsePacket(AsyncUDPPacket _packet) {
buff_ = reinterpret_cast(_packet.data());
- if (memcmp(buff_->acn_id, ESPAsyncE131::ACN_ID, sizeof(buff_->acn_id)))
- error = ERROR_ACN_ID;
- else if (htonl(buff_->root_vector) != ESPAsyncE131::VECTOR_ROOT)
- error = ERROR_VECTOR_ROOT;
- else if (htonl(buff_->frame_vector) != ESPAsyncE131::VECTOR_FRAME)
- error = ERROR_VECTOR_FRAME;
- else if (buff_->dmp_vector != ESPAsyncE131::VECTOR_DMP)
- error = ERROR_VECTOR_DMP;
- else if (buff_->property_values[0] != 0)
- error = ERROR_IGNORE;
- if (error == ERROR_NONE) {
- stats.num_packets++;
- stats.last_clientIP = _packet.remoteIP();
- stats.last_clientPort = _packet.remotePort();
- stats.last_seen = millis();
- uint16_t univ_number = buff_->universe >> 8 |
- buff_->universe << 8;
- if (universes_.count(univ_number)) {
- // slots beyond the recieved count should be zero'd
- std::array full = {0};
- uint16_t slot_count = buff_->property_value_count >> 8 |
- buff_->property_value_count << 8;
- std::copy(std::begin(buff_->property_values),
- std::begin(buff_->property_values) + slot_count,
- std::begin(full));
- // copy full-lenght universe
- e111_universe_t u;
- std::copy(std::begin(full), std::end(full), std::begin(u.data));
- // set universe data
- universes_.at(univ_number)->setData(&u);
- }
- } else if (error == ERROR_IGNORE) {
- // Do nothing
- } else {
- if (Serial)
- dumpError(buff_, error);
- stats.packet_errors++;
- }
+ // E1.31 - 5.3 ACN Packet Identifier
+ // The ACN Packet Identifier shall contain the following sequence of characters
+ if (memcmp(buff_->rlp.acn_id, ACN_PACKET_IDENTIFIER, sizeof(buff_->rlp.acn_id)))
+ return;
+
+ // E1.31 - 5.5 Vector
+ // Sources shall set the Root Layer's Vector to VECTOR_ROOT_E131_DATA
+ // if the packet contains E1.31 Data
+ if (htonl(buff_->rlp.vector) != VECTOR_ROOT_E131_DATA)
+ return;
+
+ // E1.31 - 6.2.1 E1.31 Data Packet: Vector
+ // Sources sending an E1.31 Data Packet shall set the E1.31 Layer's
+ // Vector to VECTOR_E131_DATA_PACKET.
+ if (htonl(buff_->frame.vector) != VECTOR_E131_DATA_PACKET)
+ return;
+
+ // E1.31 - 7.2 DMP Layer: Vector
+ // The DMP Layer's Vector shall be set to VECTOR_DMP_SET_PROPERTY
+ if (buff_->dmp.vector != VECTOR_DMP_SET_PROPERTY)
+ return;
+
+ // ignore unverses recieved without active subscriptions
+ if (!universes_.count(htons(buff_->frame.universe)))
+ return;
+
+ // E1.11 - 8.5.2 Dimmer class data
+ // Dimmer level data should be sent in NULL START Code packets.
+ if (buff_->dmp.property_values[0] != E111_NULL_START)
+ return;
+
+ // slots beyond the recieved count should be zero'd
+ std::array full = {0};
+ std::copy(std::begin(buff_->dmp.property_values),
+ std::begin(buff_->dmp.property_values) + htons(buff_->dmp.property_value_count),
+ std::begin(full));
+ // copy full-lenght universe
+ e111_universe_t u;
+ std::copy(std::begin(full), std::end(full), std::begin(u.data));
+
+ // set universe data
+ universes_.at(htons(buff_->frame.universe))->setData(&u);
}
-void ESPAsyncE131::dumpError(e131_packet_t *packet, e131_error_t error) {
- switch (error) {
- case ERROR_ACN_ID:
- Serial.print(F("INVALID PACKET ID: "));
- for (uint i = 0; i < sizeof(ACN_ID); i++)
- Serial.print(packet->acn_id[i], HEX);
- Serial.println("");
- break;
- case ERROR_PACKET_SIZE:
- Serial.println(F("INVALID PACKET SIZE: "));
- break;
- case ERROR_VECTOR_ROOT:
- Serial.print(F("INVALID ROOT VECTOR: 0x"));
- Serial.println(htonl(packet->root_vector), HEX);
- break;
- case ERROR_VECTOR_FRAME:
- Serial.print(F("INVALID FRAME VECTOR: 0x"));
- Serial.println(htonl(packet->frame_vector), HEX);
- break;
- case ERROR_VECTOR_DMP:
- Serial.print(F("INVALID DMP VECTOR: 0x"));
- Serial.println(packet->dmp_vector, HEX);
- case ERROR_NONE:
- break;
- case ERROR_IGNORE:
- break;
- }
-}
-IPAddress ESPAsyncE131::E131MulticastAddress(uint16_t universe) {
+IPAddress ESPsACN::E131MulticastAddress(uint16_t universe) {
return IPAddress(239, 255, ((universe >> 8) & 0xff), ((universe >> 0) & 0xff));
}
diff --git a/wiflash_esp32/sacn.h b/wiflash_esp32/sacn.h
index 0f86866..794344e 100644
--- a/wiflash_esp32/sacn.h
+++ b/wiflash_esp32/sacn.h
@@ -1,135 +1,125 @@
/*
- ESPAsyncE131.h
+ sacn.h
- Project: ESPAsyncE131 - Asynchronous E.131 (sACN) library for Arduino ESP8266 and ESP32
- Copyright (c) 2019 Shelby Merrick
- http://www.forkineye.com
+ Copyright (c) 2020 Kevin Matz (kevin.matz@gmail.com)
- This program is provided free for you to use in any way that you wish,
- subject to the laws and regulations where you are using it. Due diligence
- is strongly suggested before using this code. Please give credit where due.
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
- The Author makes no warranty of any kind, express or implied, with regard
- to this program or the documentation contained in this document. The
- Author shall not be liable in any event for incidental or consequential
- damages in connection with, or arising out of, the furnishing, performance
- or use of these programs.
+ The above copyright notice and this permission notice shall be included in all
+ copies or substantial portions of the Software.
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
*/
-#ifndef ESPASYNCE131_H_
-#define ESPASYNCE131_H_
+#ifndef SACN_H_
+#define SACN_H_
#include
#include
#include "dmx_universe.h"
-// Defaults
-#define E131_DEFAULT_PORT 5568
+// Appendix A: Defined Parameters (Normative)
+#define VECTOR_ROOT_E131_DATA 0x00000004
+#define VECTOR_ROOT_E131_EXTENDED 0x00000008
-// E1.31 Packet Offsets
-#define E131_ROOT_PREAMBLE_SIZE 0
-#define E131_ROOT_POSTAMBLE_SIZE 2
-#define E131_ROOT_ID 4
-#define E131_ROOT_FLENGTH 16
-#define E131_ROOT_VECTOR 18
-#define E131_ROOT_CID 22
+#define VECTOR_DMP_SET_PROPERTY 0x02 // informative
-#define E131_FRAME_FLENGTH 38
-#define E131_FRAME_VECTOR 40
-#define E131_FRAME_SOURCE 44
-#define E131_FRAME_PRIORITY 108
-#define E131_FRAME_RESERVED 109
-#define E131_FRAME_SEQ 111
-#define E131_FRAME_OPT 112
-#define E131_FRAME_UNIVERSE 113
+#define VECTOR_E131_DATA_PACKET 0x00000002
-#define E131_DMP_FLENGTH 115
-#define E131_DMP_VECTOR 117
-#define E131_DMP_TYPE 118
-#define E131_DMP_ADDR_FIRST 119
-#define E131_DMP_ADDR_INC 121
-#define E131_DMP_COUNT 123
-#define E131_DMP_DATA 125
+#define VECTOR_E131_EXTENDED_SYNCHRONIZATION 0x00000001
+#define VECTOR_E131_EXTENDED_DISCOVERY 0x00000002
-// E1.31 Packet Structure
+#define E131_E131_UNIVERSE_DISCOVER_INTERVAL 10000 // ms
+#define E131_NETWORK_DATA_LOSS_TIMEOUT 2500 // ms
+#define E131_DISCOVERY_UNIVERSE 64214
+
+#define ACN_SDT_MULTICAST_PORT 5568
+
+// A S C - E 1 . 1 7
+static constexpr uint8_t ACN_PACKET_IDENTIFIER[] = { 0x41, 0x53, 0x43, 0x2d, 0x45, 0x31, 0x2e, 0x31, 0x37, 0x00, 0x00, 0x00 };
+
+
+// Table 5-1: ACN Root Layer
typedef union {
struct {
- // Root Layer
uint16_t preamble_size;
uint16_t postamble_size;
uint8_t acn_id[12];
- uint16_t root_flength;
- uint32_t root_vector;
+ uint16_t flength;
+ uint32_t vector;
uint8_t cid[16];
+ } __attribute__((packed));
+ uint8_t raw[37];
+} e131_rlp_t;
- // Frame Layer
- uint16_t frame_flength;
- uint32_t frame_vector;
+
+// Table 6-1: E1.31 Data Packet Framing Layer
+typedef union {
+ struct {
+ uint16_t flength;
+ uint32_t vector;
uint8_t source_name[64];
uint8_t priority;
uint16_t reserved;
uint8_t sequence_number;
uint8_t options;
uint16_t universe;
+ } __attribute__((packed));
+ uint8_t raw[77];
+} e131_frame_t;
- // DMP Layer
- uint16_t dmp_flength;
- uint8_t dmp_vector;
+
+// Table 7-1: E131 Data Packet DMP Layer
+typedef union {
+ struct {
+ uint16_t flength;
+ uint8_t vector;
uint8_t type;
uint16_t first_address;
uint16_t address_increment;
uint16_t property_value_count;
uint8_t property_values[513];
} __attribute__((packed));
+ uint8_t raw[523];
+} e131_dmp_t;
+
+// Table 4-1: E1.31 Data Packet
+typedef union {
+ struct {
+ e131_rlp_t rlp;
+ e131_frame_t frame;
+ e131_dmp_t dmp;
+ } __attribute__((packed));
uint8_t raw[638];
} e131_packet_t;
-// Error Types
-typedef enum {
- ERROR_NONE,
- ERROR_IGNORE,
- ERROR_ACN_ID,
- ERROR_PACKET_SIZE,
- ERROR_VECTOR_ROOT,
- ERROR_VECTOR_FRAME,
- ERROR_VECTOR_DMP
-} e131_error_t;
-
-// Status structure
-typedef struct {
- uint32_t num_packets;
- uint32_t packet_errors;
- IPAddress last_clientIP;
- uint16_t last_clientPort;
- unsigned long last_seen;
-} e131_stats_t;
-
typedef std::function E131PacketHandlerFunction;
-class ESPAsyncE131 {
+class ESPsACN {
public:
- ESPAsyncE131();
+ ESPsACN();
bool subscribe(uint16_t universe = 1);
- static void dumpError(e131_packet_t *packet, e131_error_t error);
static IPAddress E131MulticastAddress(uint16_t universe);
Universe * universe(uint16_t num) {
return universes_.at(num);
}
- e131_stats_t stats; // Statistics tracker
-
private:
- // Constants for packet validation
- static const uint8_t ACN_ID[];
- static const uint32_t VECTOR_ROOT = 4;
- static const uint32_t VECTOR_FRAME = 2;
- static const uint8_t VECTOR_DMP = 2;
-
e131_packet_t *buff_; // Pointer to scratch packet buffer
AsyncUDP udp; // AsyncUDP
@@ -139,4 +129,4 @@ class ESPAsyncE131 {
std::unordered_map universes_;
};
-#endif // ESPASYNCE131_H_
+#endif // SACN_H_
diff --git a/wiflash_esp32/wiflash_esp32.ino b/wiflash_esp32/wiflash_esp32.ino
index 607864c..074fa11 100644
--- a/wiflash_esp32/wiflash_esp32.ino
+++ b/wiflash_esp32/wiflash_esp32.ino
@@ -43,7 +43,7 @@
//// device objects
Strobe *strobe;
NeoPixelBus *strip;
-ESPAsyncE131 *e131 = new ESPAsyncE131();
+ESPsACN *e131 = new ESPsACN();
AsyncWebServer *httpd = new AsyncWebServer(80);