You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
256 lines
7.5 KiB
C++
256 lines
7.5 KiB
C++
/*
|
|
* e131.h
|
|
*
|
|
* Project: E131 - E.131 (sACN) library for Arduino
|
|
* Copyright (c) 2015 Shelby Merrick
|
|
* http://www.forkineye.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.
|
|
*
|
|
* 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.
|
|
*
|
|
* Modified to work on RP2040 by Amelia Deck
|
|
* This version will not run anymore on ESP32 due to changes to the includes.
|
|
*
|
|
*/
|
|
|
|
#ifndef E131_H_
|
|
#define E131_H_
|
|
|
|
#include "Arduino.h"
|
|
#include "config.h"
|
|
|
|
|
|
/* Network interface detection. WiFi for ESP8266 and Ethernet for AVR */
|
|
#ifdef INT_WIFI
|
|
#include <WiFi.h>
|
|
#endif
|
|
//# include <WiFiMulti.h>
|
|
//# include <WiFiUdp.h>
|
|
#ifdef INT_ETHERNET
|
|
#include <W5500lwIP.h>
|
|
#endif
|
|
# include <lwip/ip_addr.h>
|
|
# include <lwip/igmp.h>
|
|
# define _UDP WiFiUDP
|
|
//# define INT_ETHERNET
|
|
|
|
|
|
#define NO_DOUBLE_BUFFER 1
|
|
/* Defaults */
|
|
#define E131_DEFAULT_PORT 5568
|
|
#define WIFI_CONNECT_TIMEOUT 15000 /* 15 seconds */
|
|
|
|
/* 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 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 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
|
|
|
|
/* E1.31 Packet Structure */
|
|
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;
|
|
uint8_t cid[16];
|
|
|
|
/* Frame Layer */
|
|
uint16_t frame_flength;
|
|
uint32_t frame_vector;
|
|
uint8_t source_name[64];
|
|
uint8_t priority;
|
|
uint16_t reserved;
|
|
uint8_t sequence_number;
|
|
uint8_t options;
|
|
uint16_t universe;
|
|
|
|
/* DMP Layer */
|
|
uint16_t dmp_flength;
|
|
uint8_t dmp_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[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;
|
|
|
|
/* E1.31 Listener Types */
|
|
typedef enum {
|
|
E131_UNICAST,
|
|
E131_MULTICAST
|
|
} e131_listen_t;
|
|
|
|
/* Status structure */
|
|
typedef struct {
|
|
uint32_t num_packets;
|
|
uint32_t packet_errors;
|
|
IPAddress last_clientIP;
|
|
uint16_t last_clientPort;
|
|
} e131_stats_t;
|
|
|
|
class E131 {
|
|
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 pbuff1; /* Packet buffer */
|
|
#ifndef NO_DOUBLE_BUFFER
|
|
e131_packet_t pbuff2; /* Double buffer */
|
|
#endif
|
|
e131_packet_t *pwbuff; /* Pointer to working packet buffer */
|
|
_UDP udp; /* UDP handle */
|
|
|
|
/* Internal Initializers */
|
|
int initWiFi(const char *ssid, const char *passphrase);
|
|
int initEthernet(uint8_t *mac, IPAddress ip, IPAddress netmask,
|
|
IPAddress gateway, IPAddress dns);
|
|
void initUnicast();
|
|
void initMulticast(uint16_t universe, uint8_t n = 1);
|
|
|
|
public:
|
|
uint8_t *data; /* Pointer to DMX channel data */
|
|
uint16_t universe; /* DMX Universe of last valid packet */
|
|
e131_packet_t *packet; /* Pointer to last valid packet */
|
|
e131_stats_t stats; /* Statistics tracker */
|
|
|
|
E131();
|
|
|
|
/* Generic UDP listener, no physical or IP configuration */
|
|
void begin(e131_listen_t type, uint16_t universe = 1, uint8_t n = 1);
|
|
|
|
/****** START - Wireless ifdef block ******/
|
|
#if defined (INT_WIFI) || defined (INT_ESP8266)
|
|
/* Unicast WiFi Initializers */
|
|
int begin(const char *ssid, const char *passphrase);
|
|
int begin(const char *ssid, const char *passphrase,
|
|
IPAddress ip, IPAddress netmask, IPAddress gateway, IPAddress dns);
|
|
#endif
|
|
/****** END - Wireless ifdef block ******/
|
|
|
|
/****** START - ESP8266 ifdef block ******/
|
|
#if defined (INT_ESP8266)
|
|
/* Multicast WiFi Initializers -- ESP8266 Only */
|
|
int beginMulticast(const char *ssid, const char *passphrase,
|
|
uint16_t universe, uint8_t n = 1);
|
|
int beginMulticast(const char *ssid, const char *passphrase,
|
|
uint16_t universe, IPAddress ip, IPAddress netmask,
|
|
IPAddress gateway, IPAddress dns, uint8_t n = 1);
|
|
#endif
|
|
/****** END - ESP8266 ifdef block ******/
|
|
|
|
/****** START - Ethernet ifdef block ******/
|
|
#if defined (INT_ETHERNET)
|
|
/* Unicast Ethernet Initializers */
|
|
int begin(Wiznet5500lwIP eth);
|
|
|
|
/* Multicast Ethernet Initializers */
|
|
int beginMulticast(uint8_t *mac, uint16_t universe, uint8_t n = 1);
|
|
void beginMulticast(uint8_t *mac, uint16_t universe,
|
|
IPAddress ip, IPAddress netmask, IPAddress gateway,
|
|
IPAddress dns, uint8_t n = 1);
|
|
#endif
|
|
/****** END - Ethernet ifdef block ******/
|
|
|
|
/* Diag functions */
|
|
void dumpError(e131_error_t error);
|
|
|
|
/* Main packet parser */
|
|
inline uint16_t parsePacket() {
|
|
e131_error_t error;
|
|
uint16_t retval = 0;
|
|
|
|
int size = udp.parsePacket();
|
|
if (size) {
|
|
udp.readBytes(pwbuff->raw, size);
|
|
error = validate();
|
|
if (!error) {
|
|
#ifndef NO_DOUBLE_BUFFER
|
|
e131_packet_t *swap = packet;
|
|
packet = pwbuff;
|
|
pwbuff = swap;
|
|
#endif
|
|
universe = htons(packet->universe);
|
|
data = packet->property_values + 1;
|
|
retval = htons(packet->property_value_count) - 1;
|
|
stats.num_packets++;
|
|
stats.last_clientIP = udp.remoteIP();
|
|
stats.last_clientPort = udp.remotePort();
|
|
} else if (error == ERROR_IGNORE) {
|
|
// Do nothing
|
|
return 0;
|
|
} else {
|
|
if (Serial)
|
|
dumpError(error);
|
|
stats.packet_errors++;
|
|
}
|
|
}
|
|
return retval;
|
|
}
|
|
|
|
/* Packet validater */
|
|
inline e131_error_t validate() {
|
|
#ifdef ARDUINO_ARCH_AVR
|
|
if (memcmp_P(pwbuff->acn_id, ACN_ID, sizeof(pwbuff->acn_id)))
|
|
#else
|
|
if (memcmp(pwbuff->acn_id, ACN_ID, sizeof(pwbuff->acn_id)))
|
|
#endif
|
|
return ERROR_ACN_ID;
|
|
if (htonl(pwbuff->root_vector) != VECTOR_ROOT)
|
|
return ERROR_VECTOR_ROOT;
|
|
if (htonl(pwbuff->frame_vector) != VECTOR_FRAME)
|
|
return ERROR_VECTOR_FRAME;
|
|
if (pwbuff->dmp_vector != VECTOR_DMP)
|
|
return ERROR_VECTOR_DMP;
|
|
if (pwbuff->property_values[0] != 0)
|
|
return ERROR_IGNORE;
|
|
return ERROR_NONE;
|
|
}
|
|
};
|
|
|
|
#endif /* E131_H_ */ |