Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Send support #25

Draft
wants to merge 9 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 8 additions & 6 deletions .github/workflows/build.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -22,17 +22,12 @@ jobs:
arduino-cli config set directories.user ~/arduino
- name: Install platforms
run: |
arduino-cli core update-index
arduino-cli core install $ESP8266_PLAT
arduino-cli core install $ESP32_PLAT

# Grab all the required libraries
# Checkout won't allow paths outside of our workspace, so we put them in alib and move later.
- name: Checkout ESPAsyncE131
uses: actions/checkout@v2
with:
repository: forkineye/ESPAsyncE131
path: alib/ESPAsyncE131

- name: Checkout ESPAsyncUDP
uses: actions/checkout@v2
with:
Expand All @@ -45,12 +40,19 @@ jobs:
mkdir -p ~/arduino/libraries
mv alib/* ~/arduino/libraries
rmdir alib
mkdir -p ~/arduino/libraries/wifi
echo "#define SECRET_SSID \"test\";" > ~/arduino/libraries/wifi/wifi.h
echo "#define SECRET_PSK \"test\";" >> ~/arduino/libraries/wifi/wifi.h
cp -rv ./ ~/arduino/libraries/ESPAsyncE131


# Build examples
- name: Compile for ESP8266
run: |
arduino-cli compile --fqbn $ESP8266_FQBN examples/E131_Test/E131_Test.ino
arduino-cli compile --fqbn $ESP8266_FQBN examples/E131_Test-Sender/E131_Test-Sender.ino

- name: Compile for ESP32
run: |
arduino-cli compile --fqbn $ESP32_FQBN examples/E131_Test/E131_Test.ino
arduino-cli compile --fqbn $ESP32_FQBN examples/E131_Test-Sender/E131_Test-Sender.ino
156 changes: 156 additions & 0 deletions ESPAsyncE131.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,27 @@ ESPAsyncE131::ESPAsyncE131(uint8_t buffers) {

stats.num_packets = 0;
stats.packet_errors = 0;

memset(pbuff3.raw, 0, sizeof(pbuff3.raw));
memset(pbuff4.raw, 0, sizeof(pbuff4.raw));
packetTX = &pbuff3;
pwbuffTX = &pbuff4;
}

uint16_t ESPAsyncE131::swapf_uint16(uint16_t x) {
// return ( ( (x) <<8) | (( (x) >>8)&0xFF ) );
return ( htons(x) );
}

uint32_t ESPAsyncE131::swapf_uint32(uint32_t x) {
return ( htonl(x) );
}

#define swap_uint16(x) ( ( (x) <<8) | (( (x) >>8)&0xFF ) ) // surprisingly this does not work with printf
// ( ( 0x89<<8) | (( 0x1289 >>8)&0xFF ) )



/////////////////////////////////////////////////////////
//
// Public begin() members
Expand All @@ -61,6 +80,143 @@ bool ESPAsyncE131::begin (e131_listen_t type, ESPAsyncE131PortId UdpPortId, uint
return success;
}

/////////////////////////////////////////////////////////
//
// Public send related members
//
/////////////////////////////////////////////////////////

void ESPAsyncE131::sendPacket(uint16_t universe) {
IPAddress ipMultiE131 = IPAddress(239, 255, ((universe >> 8) & 0xff), ((universe >> 0) & 0xff));
setPacketHeader(universe,512);
udp.broadcastTo(pwbuffTX->raw, sizeof(pwbuffTX->raw), E131_DEFAULT_PORT); // , WiFi.localIP());
}


void ESPAsyncE131::setRGB(const uint8_t channel,const uint8_t dRed,const uint8_t dGreen,const uint8_t dBlue) {
// first channel on [1]; [0] has to be 0
pwbuffTX->dmp.prop_val[channel+1] = dRed;
pwbuffTX->dmp.prop_val[channel+2] = dGreen;
pwbuffTX->dmp.prop_val[channel+3] = dBlue;
}

void ESPAsyncE131::clearSendBuffer() {
memset(&pwbuffTX->dmp.prop_val[0], 0, sizeof(pwbuffTX->dmp.prop_val));
}

void ESPAsyncE131::fillSendBuffer(const uint8_t fillData) {
memset(&pwbuffTX->dmp.prop_val[1],fillData,sizeof(pwbuffTX->dmp.prop_val)-1);
}

void ESPAsyncE131::setSourceName(const char *source_name) {
memcpy(pwbuffTX->frame.source_name, source_name, strlen(source_name) );
}

void ESPAsyncE131::setSequenceNumber(const int seq_number) {
pwbuffTX->frame.seq_number = seq_number;
}

void ESPAsyncE131::setData(const int channel, const int dmxVal ) {
pwbuffTX->dmp.prop_val[channel] = dmxVal;
}

/* Initialize an E1.31 packet using a universe and a number of slots */
int ESPAsyncE131::setPacketHeader(const uint16_t universe, const uint16_t num_channels) {
if (pwbuffTX == NULL || universe < 1 || universe > 63999 || num_channels < 1 || num_channels > 512) {
// errno = EINVAL;
return -1;
}

// compute packet layer lengths
uint16_t prop_val_cnt = num_channels + 1;
uint16_t dmp_length = prop_val_cnt +
sizeof pwbuffTX->dmp - sizeof pwbuffTX->dmp.prop_val;
uint16_t frame_length = sizeof pwbuffTX->frame + dmp_length;
uint16_t root_length = sizeof pwbuffTX->root.flength +
sizeof pwbuffTX->root.vector + sizeof pwbuffTX->root.cid + frame_length;

// clear packet
memset(packetTX, 0, sizeof *packetTX);

// set Root Layer values
pwbuffTX->root.preamble_size = swapf_uint16(_E131_PREAMBLE_SIZE);
pwbuffTX->root.postamble_size = swapf_uint16(_E131_POSTAMBLE_SIZE);
memcpy(pwbuffTX->root.acn_pid, _E131_ACN_PID, sizeof pwbuffTX->root.acn_pid);
pwbuffTX->root.flength = swapf_uint16(0x7000 | root_length);
pwbuffTX->root.vector = swapf_uint32(_E131_ROOT_VECTOR);

// set Framing Layer values
pwbuffTX->frame.flength = swapf_uint16(0x7000 | frame_length);
pwbuffTX->frame.vector = swapf_uint32(_E131_FRAME_VECTOR);
pwbuffTX->frame.priority = E131_DEFAULT_PRIORITY;
pwbuffTX->frame.options = _E131_FRAME_OPTIONS;
pwbuffTX->frame.universe = swapf_uint16(universe);

// set Device Management Protocol (DMP) Layer values
pwbuffTX->dmp.flength = swapf_uint16(0x7000 | dmp_length);
pwbuffTX->dmp.vector = _E131_DMP_VECTOR;
pwbuffTX->dmp.type = _E131_DMP_TYPE;
pwbuffTX->dmp.first_addr = swapf_uint16(_E131_DMP_FIRST_ADDR);
pwbuffTX->dmp.addr_inc = swapf_uint16(_E131_DMP_ADDR_INC);
pwbuffTX->dmp.prop_val_cnt = swapf_uint16(prop_val_cnt);

return 0;
}


// void ESPAsyncE131::dumpPacket(int packetNo) {

// e131_packet_t *dmpbuff;

// if (packetNo==0) {
// dmpbuff = packet;
// Serial.print("\n --------------------------------- packet \n");
// }
// else {
// dmpbuff = pwbuff;
// Serial.print("\n --------------------------------- pwbuff \n");
// }


// Serial.print("E1.31 Root Layer\n");
// printf(" Preamble Size .......... %04x\n" , swapf_uint16(dmpbuff->preamble_size) ); // SWAP // uint16_t = 2 bytes = [0-65535] or [0x0000-0xFFFF] = unsigned int
// printf(" Post-amble Size ........ %04x\n" , swapf_uint16(dmpbuff->postamble_size) ); // uint16_t = 2 bytes = [0-65535] or [0x0000-0xFFFF] = unsigned int
// printf(" ACN Packet Identifier .. %s\n" , dmpbuff->acn_id); // uint8_t = 1 bytes = [0-255] or [0x00-0xFF] = unsigned char
// printf(" Flags & Length ......... %04x\n" , swapf_uint16(dmpbuff->root_flength) ); // uint16_t = 2 bytes = [0-65535] or [0x0000-0xFFFF] = unsigned int
// printf(" Layer Vector ........... %08x\n" , swapf_uint32(dmpbuff->root_vector) ); // uint32_t = 4 bytes = unsigned long
// printf(" Component Identifier ... ");
// for (size_t pos=0, total=sizeof dmpbuff->cid; pos<total; pos++)
// printf("%02x", dmpbuff->cid[pos]);
// printf("\n");

// Serial.print("E1.31 Framing Layer\n");
// printf(" Flags & Length ......... %04x\n" , swapf_uint16(dmpbuff->frame_flength)); // uint16_t
// printf(" Layer Vector ........... %08x\n" , swapf_uint32(dmpbuff->frame_vector)); // uint32_t
// printf(" Source Name ............ %s\n" , dmpbuff->source_name); // uint8_t
// printf(" Packet Priority ........ %02x = %u\n" , dmpbuff->priority,dmpbuff->priority); // ok // uint8_t
// printf(" Reserved ............... %04x\n" , swapf_uint16(dmpbuff->reserved)); // uint16_t
// printf(" Sequence Number ........ %02x\n" , dmpbuff->sequence_number); // ok // uint8_t
// printf(" Options Flags .......... %02x\n" , dmpbuff->options); // uint8_t
// printf(" DMX Universe Number .... %04x = %u\n" , swapf_uint16(dmpbuff->universe),swapf_uint16(dmpbuff->universe));// SWAP // uint16_t

// Serial.print("E1.31 Device Management Protocol (DMP) Layer\n");
// printf(" Flags & Length ......... %04x\n" , swapf_uint16(dmpbuff->dmp_flength)); // uint16_t = 2 bytes = [0-65535] or [0x0000-0xFFFF] = unsigned int
// printf(" Layer Vector ........... %02x\n" , dmpbuff->dmp_vector); // uint8_t = 1 bytes = [0-255] or [0x00-0xFF] = unsigned char
// printf(" Address & Data Type .... %02x\n" , dmpbuff->type); // uint8_t = 1 bytes = [0-255] or [0x00-0xFF] = unsigned char
// printf(" First Address .......... %04x\n" , swapf_uint16(dmpbuff->first_address)); // uint16_t = 2 bytes = [0-65535] or [0x0000-0xFFFF] = unsigned int
// printf(" Address Increment ...... %04x\n" , swapf_uint16(dmpbuff->address_increment)); // uint16_t = 2 bytes = [0-65535] or [0x0000-0xFFFF] = unsigned int
// printf(" Property Value Count ... %04x\n" , swapf_uint16(dmpbuff->property_value_count)); // uint16_t = 2 bytes = [0-65535] or [0x0000-0xFFFF] = unsigned int

// Serial.print("E1.31 DMP Property Values\n ");
// for (size_t pos=0, total=(dmpbuff->property_value_count); pos<total; pos++)
// printf(" %02x", dmpbuff->property_values[pos]);

// Serial.print("\n");

// }



/////////////////////////////////////////////////////////
//
// Private init() members
Expand Down
73 changes: 73 additions & 0 deletions ESPAsyncE131.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,22 @@ typedef struct ip_addr ip4_addr_t;
#define E131_DMP_COUNT 123
#define E131_DMP_DATA 125

/* E1.31 Private Constants */
const uint16_t _E131_PREAMBLE_SIZE = 0x0010;
const uint16_t _E131_POSTAMBLE_SIZE = 0x0000;
const uint8_t _E131_ACN_PID[] = {0x41, 0x53, 0x43, 0x2d, 0x45, 0x31, 0x2e, 0x31, 0x37, 0x00, 0x00, 0x00};
const uint32_t _E131_ROOT_VECTOR = 0x00000004;
const uint32_t _E131_FRAME_VECTOR = 0x00000002;
const uint8_t _E131_FRAME_OPTIONS = 0x40;
const uint8_t _E131_DMP_VECTOR = 0x02;
const uint8_t _E131_DMP_TYPE = 0xa1;
const uint16_t _E131_DMP_FIRST_ADDR = 0x0000;
const uint16_t _E131_DMP_ADDR_INC = 0x0001;

/* E1.31 Public Constants */
const uint16_t E131_DEFAULT_PORT_srv = 5568;
const uint8_t E131_DEFAULT_PRIORITY = 0x64;

// E1.31 Packet Structure
typedef union {
struct {
Expand Down Expand Up @@ -102,6 +118,44 @@ typedef union {
uint8_t raw[638];
} e131_packet_t;

/* E1.31 Packet Type */
/* All packet contents shall be transmitted in network byte order (big endian) */
typedef union {
struct {
struct { /* ACN Root Layer: 38 bytes */
uint16_t preamble_size; /* Preamble Size */
uint16_t postamble_size; /* Post-amble Size */
uint8_t acn_pid[12]; /* ACN Packet Identifier */
uint16_t flength; /* Flags (high 4 bits) & Length (low 12 bits) */
uint32_t vector; /* Layer Vector */
uint8_t cid[16]; /* Component Identifier (UUID) */
} __attribute__((packed)) root;

struct { /* Framing Layer: 77 bytes */
uint16_t flength; /* Flags (high 4 bits) & Length (low 12 bits) */
uint32_t vector; /* Layer Vector */
uint8_t source_name[64]; /* User Assigned Name of Source (UTF-8) */
uint8_t priority; /* Packet Priority (0-200, default 100) */
uint16_t reserved; /* Reserved (should be always 0) */
uint8_t seq_number; /* Sequence Number (detect duplicates or out of order packets) */
uint8_t options; /* Options Flags (bit 7: preview data, bit 6: stream terminated) */
uint16_t universe; /* DMX Universe Number */
} __attribute__((packed)) frame;

struct { /* Device Management Protocol (DMP) Layer: 523 bytes */
uint16_t flength; /* Flags (high 4 bits) / Length (low 12 bits) */
uint8_t vector; /* Layer Vector */
uint8_t type; /* Address Type & Data Type */
uint16_t first_addr; /* First Property Address */
uint16_t addr_inc; /* Address Increment */
uint16_t prop_val_cnt; /* Property Value Count (1 + number of slots) */
uint8_t prop_val[513]; /* Property Values (DMX start code + slots data) */
} __attribute__((packed)) dmp;
} __attribute__((packed));

uint8_t raw[638]; /* raw buffer view: 638 bytes */
} e131_packet_tx_t;

// Error Types
typedef enum {
ERROR_NONE,
Expand Down Expand Up @@ -141,6 +195,9 @@ class ESPAsyncE131 {
e131_packet_t *sbuff; // Pointer to scratch packet buffer
AsyncUDP udp; // AsyncUDP
RingBuf *pbuff; // Ring Buffer of universe packet buffers
e131_packet_tx_t pbuff3; /* Packet buffer */
e131_packet_tx_t pbuff4; /* Double buffer */
e131_packet_tx_t *pwbuffTX; /* Pointer to working packet TX buffer */
void * UserInfo = nullptr;

// Internal Initializers
Expand All @@ -153,8 +210,12 @@ class ESPAsyncE131 {
void (*PacketCallback)(e131_packet_t* ReceivedData, void* UserInfo) = nullptr;
ESPAsyncE131PortId E131_ListenPort = E131_DEFAULT_PORT;

uint16_t swapf_uint16(uint16_t x);
uint32_t swapf_uint32(uint32_t x);

public:
e131_stats_t stats; // Statistics tracker
e131_packet_tx_t *packetTX; /* Pointer to last valid TX packet */
ESPAsyncE131(uint8_t buffers = 1);

// Generic UDP listener, no physical or IP configuration
Expand All @@ -170,6 +231,18 @@ class ESPAsyncE131 {

// Diag functions
void dumpError(e131_error_t error);

// void stopUdp(void);
// void connectMulticast(uint16_t universe);
// void dumpPacket(int packetNo);
void setRGB(const uint8_t channel,const uint8_t dRed,const uint8_t dGreen,const uint8_t dBlue);
void setSourceName(const char *source_name); //
void setSequenceNumber(const int seq_number);
void setData(const int channel, const int dmxVal );
int setPacketHeader(const uint16_t universe, const uint16_t num_channels);
void fillSendBuffer(uint8_t fillData);
void clearSendBuffer(void );
void sendPacket(uint16_t universe);
};

#endif // ESPASYNCE131_H_
Loading