http://mbed.org/users/okini3939/notebook/art-net/

Dependents:   ArtNode ArtNode DMXStation ArtNodeLED ... more

Files at this revision

API Documentation at this revision

Comitter:
okini3939
Date:
Fri Sep 13 06:16:58 2019 +0000
Parent:
1:c59dc374fc64
Child:
3:89aa639c946a
Commit message:
fix multi universe

Changed in this revision

DmxArtNet.cpp Show annotated file Show diff for this revision Revisions of this file
DmxArtNet.h Show annotated file Show diff for this revision Revisions of this file
--- a/DmxArtNet.cpp	Thu Sep 29 16:42:34 2011 +0000
+++ b/DmxArtNet.cpp	Fri Sep 13 06:16:58 2019 +0000
@@ -7,20 +7,26 @@
  *
  * http://members.westnet.com.au/rowanmac/
  *
- * for mbed port by Suga 2011
+ * for mbed ported by Suga 2011, 2017
  */
 
 /** @file
  */
 
 #include "mbed.h"
-#include "EthernetNetIf.h"
-#include "UDPSocket.h"
+#include "EthernetInterface.h"
 #include "DmxArtNet.h"
-#include "dbg.h"
 #include <stdio.h>
 #include <string.h>
 
+//#define DEBUG
+#ifdef DEBUG 
+#define DBG(...) printf("" __VA_ARGS__) 
+#else 
+#define DBG(...) 
+#endif 
+
+/*
 // host to network short
 #define htons( x ) ( (( (x) << 8 ) & 0xFF00) | (( (x) >> 8 ) & 0x00FF) )
 #define ntohs( x ) htons(x)
@@ -30,11 +36,18 @@
                    | (( (x) >>  8 ) & 0x0000FF00)  \
                    | (( (x) >> 24 ) & 0x000000FF)  )
 #define ntohl( x ) htonl(x)
-
+*/
 
 extern "C" void mbed_mac_address(char *s);
 
 
+DmxArtNet::DmxArtNet () {
+    BindIpAddress[0] = 0;
+    BCastAddress[0] = 0;
+    Init_ArtDMX();
+    InitArtPollReplyDefaults();
+}
+
 // function to make a word (16bit) from two bytes (2 x 8bit)
 int DmxArtNet::makeword16 (int lsb, int msb) {
     return (msb << 8) + lsb;
@@ -54,112 +67,244 @@
 
 int DmxArtNet::Init () {
    int i;
-   UDPSocketErr err;
+   int err;
 
+   rxlen = 0;
+   cb_ArtParser = NULL;
    LError = 0; // no error yet :)
-   Init_ArtDMX(); // initialize ArtDmx structure
-//   art = new UDPSocket; // create socket
-   net_loopback = 0; // dont listen to ourself, default
-   rxlen = 0;
+   LastRecievedUniverse = 0;
+
+//   Init_ArtDMX(); // initialize ArtDmx structure
 
-   if (BindIpAddress == IpAddr(0,0,0,0)) {
-       BindIpAddress = IpAddr(2,0,0,1); // default to 2.0.0.1
+   if (BindIpAddress[0] == 0) {
+       char mac[6];
+       mbed_mac_address(mac);
+       sprintf(BindIpAddress, "%d.%d.%d.%d", 2, mac[3], mac[4], mac[5]);
+       strcpy(SubNetMask, "255.0.0.0");
    }
-   err = _art.bind(Host(BindIpAddress, ArtUDPPort, NULL));
+   if (BCastAddress[0] == 0) {
+       bcast(BCastAddress, BindIpAddress, SubNetMask);
+   }
+   RemoteSin.set_address(BCastAddress, ArtUDPPort);
+
+   err = _art.bind(ArtUDPPort);
    if (err) {
        SocketErrorOccured("Bind error");
        return -1;
    }
-   if (BCastAddress == IpAddr(0,0,0,0)) {
-       BCastAddress = IpAddr(2,255,255,255); // default
-   }
-   RemoteSin = Host(BCastAddress, ArtUDPPort, NULL);
+//   _art.set_broadcasting(true);
 
-   for (i = 0; i < ArtMaxUniv; i ++) {
-       DmxIn[i] = new unsigned char[512];
-   }
+    int ip[4];
+    sscanf(BindIpAddress, "%d.%d.%d.%d", &ip[0], &ip[1], &ip[2], &ip[3]);
+    for (i = 0; i < 4; i ++) {
+        localaddr.IP[i] = ip[i];
+    }
+    localaddr.Port = ArtUDPPort;
+    ArtPollReply.Addr = localaddr;
 
-   _art.setOnEvent(this, &DmxArtNet::on_UDPSocketEvent);
+    for (i = 0; i < ArtMaxUniv; i ++) {
+//        DmxIn[i] = new unsigned char[DMX_SIZE];
+        DmxIn[i] = (unsigned char*)malloc(DMX_SIZE);
+        memset(DmxIn[i], 0, DMX_SIZE);
+    }
+
+    thread = new Thread(&DmxArtNet::task_UDPSocket, (void*)this, osPriorityNormal, 1024*4);
 
    return 0;
 }
 
-void DmxArtNet::on_UDPSocketEvent (UDPSocketEvent e) {
-    if (e == UDPSOCKET_READABLE) {
-        rxlen = _art.recvfrom((char*)buf, sizeof(buf), &RemoteSin);
+void DmxArtNet::task_UDPSocket (void const *arg) {
+    DmxArtNet *inst = (DmxArtNet*)arg;
+
+    inst->on_UDPSocketEvent();
+}
+
+void DmxArtNet::on_UDPSocketEvent () {
+    int n;
+
+    for (;;) {
+        Work();
+
+        n = _art.receiveFrom(RemoteSin, (char*)buf, sizeof(buf));
+        if (n < 0) break;
+        if (n == 0) continue;
+        rxlen = n;
     }
 }
 
 int DmxArtNet::Work() {
-//   int rxlen, pos;
-   int pos;
-   int x, y;
-   unsigned char *RecvByte;
+   int i, n;
+   struct ArtPacketHeader *ArtHead = (ArtPacketHeader*)buf;
 
    if (rxlen >= sizeof(ArtPacketHeader)) {
       // retreive the packet header
-//      err = art.Recv(buf, sizeof(ArtPacketHeader), 10);
 
      // if looback disabled
-     if (!net_loopback && RemoteSin.getIp() == BindIpAddress) {
+     if (strcmp(RemoteSin.get_address(), BindIpAddress) == NULL) {
          DBG("ArtNet> loopback detected\r\n");
 
-//         art.purge; // dump the data
          rxlen = 0;
          return 0; // don't read packets
                    // which we sent!
      }
 
-     DBG("ArtNet> RX: %d\r\n", rxlen);
-     memcpy(&ArtHead, buf, sizeof(ArtPacketHeader));
+     // confirm is vaild art-net packet
+     if (strncmp(ArtHead->ID, ArtHeaderID, 8) != 0) {
+         rxlen = 0;
+         return 0;
+     }
+
+     DBG("ArtNet> RX: %d OpCode: %04x\r\n", rxlen, ArtHead->OpCode);
 
-     // confirm is vaild art-net packet
-     if (strncmp(ArtHead.ID, ArtHeaderID, 8) == 0) {
+       switch (ArtHead->OpCode) { // determine packet type
 
-       RecvByte = &buf[10];
-
-       switch (ArtHead.OpCode) { // determine packet type
+        case OP_Output:  // 0x5000  An ArtDMX Packet, containts dmx universe
+            if (rxlen >= sizeof(struct ArtDMX_Packet) - (DMX_SIZE - 2)) {
+                struct ArtDMX_Packet *artdmx = (struct ArtDMX_Packet*)buf;
+            
+                // check data length
+                if (ntohs(artdmx->Length) > DMX_SIZE || (artdmx->Universes & 0x7ff0) != (NetSwitch & 0x7ff0)) {
+                    break;
+                }
 
-       case OP_Output: // An ArtDMX Packet, containts dmx universe
-           ArtDMX.VersionH = RecvByte[0];
-           ArtDMX.Version  = RecvByte[1];
-           ArtDMX.Sequence = RecvByte[2];
-           ArtDMX.Physical = RecvByte[3];
+                for (i = 0; i < ArtMaxUniv; i ++) {
+                  if ( (ArtMaxUniv <= 4 && ArtPollReply.Swout[i] == (artdmx->Universes & 0x0f)) ||
+                   (ArtMaxUniv > 4 && ArtPorts.Swout[i] == (artdmx->Universes & 0x0f)) ) {
+                    LastRecievedUniverse |= (1<<i);
+                    // get the dmx data
+                    memcpy(DmxIn[i], artdmx->Data, ntohs(artdmx->Length));
+                    DBG(" <Art-Dmx> Univ: %d  Length: %d  Ch1: %d\r\n", artdmx->Universes, ntohs(artdmx->Length), DmxIn[i][0]);
+                    DBG(" from %s\r\n", RemoteSin.get_address());
+                    rxlen = 0;
+                    return 1; // something happened!
+                  }
+                }
+            }
+            break; // OP_Output
+
+        case OP_Poll:  // 0x2000
+            if (rxlen == sizeof(struct ArtPoll_Packet)) {
+                struct ArtPoll_Packet *artpoll = (struct ArtPoll_Packet*)buf;
 
-           x = RecvByte[4];
-           y = RecvByte[5];
-           ArtDMX.Universes = makeword16(x,y);
-           LastRecievedUniverse = ArtDMX.Universes;
+                if (!(artpoll->TalkToMe & 1)) {
+                    RemoteSin.set_address(BCastAddress, ArtUDPPort);
+                }
+                DBG(" <Art-Poll> Ver: %d TalkToMe: %d\r\n", ArtPoll.Version, ArtPoll.TalkToMe);
+                SendArtPollReply(); // send a reply to the ArtPoll
+            }
+            break; // OP_Poll
 
-           x = RecvByte[6];
-           y = RecvByte[7];
-           ArtDMX.Length = makeword16(y,x);
+        case OP_PollReply:  // 0x2100
+            {
+                struct ArtPollReply_Packet *pollreply = (struct ArtPollReply_Packet*)buf;
+
+                DBG(" <Art-PollReply> Startus: %02x Name: %s\r\n", pollreply->Status, pollreply->ShortName);
+            }
+            break; // OP_PollReply
+
+        case OP_Address:  // 0x6000
+            if (rxlen == sizeof(struct ArtAddress_Packet)) {
+                struct ArtAddress_Packet *address = (struct ArtAddress_Packet *)buf;
 
-           // check data length
-           if (ArtDMX.Length <= 512) {
-           // get the dmx data
-               for (pos = 0; pos < ArtDMX.Length; pos ++) {
-                   DmxIn[ArtDMX.Universes][pos] = RecvByte[8 + pos];
-               }
-               DBG(" <Art-Dmx> Size: %d  Univ: %d  Ch1: %d\r\n", ArtDMX.Length, ArtDMX.Universes, DmxIn[ArtDMX.Universes][0]);
-               rxlen = 0;
-               return 1; // something happened!
-           }
-           break; // op_output
+                if ((address->NetSwitch & 0x80) && (address->SubSwitch & 0x80)) {
+                    NetSwitch = ((address->NetSwitch & 0x7f) << 8) | ((address->SubSwitch & 0x0f) << 4);
+                    ArtPollReply.NetSwitch = (NetSwitch >> 8) & 0x7f;
+                    ArtPollReply.SubSwitch  = (NetSwitch >> 4) & 0x0f;
+                }
+                if (address->ShortName[0]) {
+                    strncpy(ArtPollReply.ShortName, address->ShortName, 18);
+                }
+                if (address->LongName[0]) {
+                    strncpy(ArtPollReply.LongName, address->LongName, 64);
+                }
+                if (address->BindIndex) {
+                    n = (address->BindIndex - 1) * 4;
+                } else {
+                    n = 0;
+                }
+                for (i = 0; i < 4; i ++) {
+                    if (address->Swin[i] != 0x7f) {
+                        ArtPollReply.Swin[i] = address->Swin[i] & 0x0f;
+                        ArtPorts.Swin[n + i] = address->Swin[i] & 0x0f;
+                        if (address->Swin[i] & 0x80) {
+                            ArtPollReply.PortType[i] |= 0x40;
+                            ArtPorts.PortType[n + i] |= 0x40;
+                        } else {
+                            ArtPollReply.PortType[i] &= ~0x40;
+                            ArtPorts.PortType[n + i] &= ~0x40;
+                        }
+                    }
+                    if (address->Swout[i] != 0x7f) {
+                        ArtPollReply.Swout[i] = address->Swout[i] & 0x0f;
+                        ArtPorts.Swout[n + i] = address->Swout[i] & 0x0f;
+                        if (address->Swout[i] & 0x80) {
+                            ArtPollReply.PortType[i] |= 0x80;
+                            ArtPorts.PortType[n + i] |= 0x80;
+                        } else {
+                            ArtPollReply.PortType[i] &= ~0x80;
+                            ArtPorts.PortType[n + i] &= ~0x80;
+                        }
+                    }
+                }
+
+                if (cb_ArtParser) cb_ArtParser(ArtHead, rxlen);
+                SendArtPollReply(); // send a reply to the ArtPoll
+                DBG(" <Art-Address> NetSwitch: %02x Command: %02x\r\n", NetSwitch, address->Command);
+            }
+            break;
 
-       case OP_Poll:
-           ArtPoll.VersionH = RecvByte[0];
-           ArtPoll.Version  = RecvByte[1];
-           ArtPoll.TalkToMe = RecvByte[2];
-           DBG(" <Art-Poll> Ver: %d TalkToMe: %d\r\n", ArtPoll.Version, ArtPoll.TalkToMe);
-           SendArtPollReply(); // send a reply to the ArtPoll
-           break;
+        case OP_IpProg:  // 0xf800
+            if (rxlen == sizeof(struct ArtIpProg_Packet)) {
+                struct ArtIpProg_Packet *ipprog = (struct ArtIpProg_Packet *)buf;
+
+                if (ipprog->Command & (1<<7)) {
+                  if (ipprog->Command & (1<<6)) { // dhcp
+                    BindIpAddress[0] = 0;
+                  }
+                  if (ipprog->Command & (1<<2)) { // ip addrress
+                    sprintf(BindIpAddress, "%d.%d.%d.%d", ipprog->ProgIp[0], ipprog->ProgIp[1], ipprog->ProgIp[2], ipprog->ProgIp[3]);
+//                    sprintf(DGateWay, "%d.%d.%d.%d", ipprog->Padding[0], ipprog->Padding[1], ipprog->Padding[2], ipprog->Padding[3]);
+                  }
+                  if (ipprog->Command & (1<<1)) { // subnet mask
+                    sprintf(SubNetMask, "%d.%d.%d.%d", ipprog->ProgSm[0], ipprog->ProgSm[1], ipprog->ProgSm[2], ipprog->ProgSm[3]);
+                  }
+                  bcast(BCastAddress, BindIpAddress, SubNetMask);
+                }
+
+//                if (cb_ArtParser) cb_ArtParser(ArtHead, rxlen);
+                SendArtIpProgReply();
+                DBG(" <Art-IpProg> NetSwitch: %02x Command: %02x\r\n", NetSwitch, ipprog->Command);
+            }
+                if (cb_ArtParser) cb_ArtParser(ArtHead, rxlen);
+            break;
 
-       default:
-           // NYI Packet Type
-           break;
+        case OP_OpTodRequest:  // 0x8000
+            if (rxlen == sizeof(struct ArtTodRequest_Packet)) {
+                struct ArtTodRequest_Packet *todreq = (struct ArtTodRequest_Packet *)buf;
+                if (cb_ArtParser) cb_ArtParser(ArtHead, rxlen);
+                for (i = 0; i < todreq->AddCount; i ++) {
+                    SendArtTodData(todreq->Address[i]);
+                }
+            }
+            break;
+
+        case OP_OpTodControl:  // 0x8200
+            if (rxlen == sizeof(struct ArtTodControl_Packet)) {
+                struct ArtTodControl_Packet *tod = (struct ArtTodControl_Packet *)buf;
+                if (cb_ArtParser) cb_ArtParser(ArtHead, rxlen);
+                if (tod->Command == 0x01) {
+                    SendArtTodData(tod->Address);
+                }
+            }
+            break;
+
+        case OP_OpRdm:  // 0x8300
+        case OP_OpRdmSub:  // 0x8400
+        default:
+            if (cb_ArtParser) cb_ArtParser(ArtHead, rxlen);
+            DBG(" <Unknown> OpCode: %04x\r\n", ArtHead->OpCode);
+            break;
        } // case packet type
-     } // waiting data
    }
 
    rxlen = 0;
@@ -168,50 +313,56 @@
 
 // socket shutdown
 void DmxArtNet::Done () {
-    _art.resetOnEvent();
     _art.close();
 }
 
 // init ArtDMX packet
 void DmxArtNet::Init_ArtDMX () {
    // header stuff
+   memset(&ArtDMX, 0, sizeof(ArtDMX));
    memcpy(ArtDMX.ID, ArtHeaderID, 8);
    ArtDMX.OpCode = OP_Output;
    ArtDMX.Version = ArtVersion;
    // dmx stuff
    ArtDMX.Universes = 0; // this is the destination for the dmx
    ArtDMX.Sequence = 0;
-   ArtDMX.Length = htons(512);
+   ArtDMX.Length = htons(DMX_SIZE);
 }
 
 // send ArtDmx Packet
 int DmxArtNet::Send_ArtDmx(int univ, int physical, char *data, int length) {
-   Host Remote;
+   Endpoint Remote;
 
    // build a artdmx packet
    memcpy(ArtDMX.Data, data, length);
-   ArtDMX.Universes = univ;
+   ArtDMX.Universes = (NetSwitch & 0x7ff0) | univ;
    ArtDMX.Length = htons(length);
    ArtDMX.Physical = physical;
    ArtDMX.Sequence ++;
 
    // set place to send
-   Remote = Host(BCastAddress, ArtUDPPort, NULL);
+   Remote.set_address(BCastAddress, ArtUDPPort);
 
    // send it off
-   _art.sendto((char*)&ArtDMX, sizeof(ArtDMX), &Remote);
+   _art.sendTo(Remote, (char*)&ArtDMX, sizeof(ArtDMX));
 
    return 0;
 }
 
 
-
 void DmxArtNet::InitArtPollReplyDefaults () {
+   memset(&ArtPollReply, 0, sizeof(ArtPollReply));
+   memset(&ArtPorts, 0, sizeof(ArtPorts));
    memcpy(ArtPollReply.ID, ArtHeaderID, 8);
    ArtPollReply.OpCode = OP_PollReply; // reply packet
    ArtPollReply.Version = ArtVersion;
 
-   memcpy(&ArtPollReply.Addr, &localaddr, sizeof(localaddr));
+   ArtPollReply.NetSwitch = (NetSwitch >> 8) & 0x7f;
+   ArtPollReply.SubSwitch = (NetSwitch >> 4) & 0x0f;
+   ArtPollReply.OEM = htons(OemId);
+   ArtPollReply.Status = (3<<6)|(2<<4); // Normal mode, Universe programmed by network
+
+   ArtPollReply.Addr = localaddr;
    strncpy(ArtPollReply.ShortName, STR_ShortName, 18);
    strncpy(ArtPollReply.LongName, STR_LongName, 64);
    strncpy(ArtPollReply.NodeReport, "OK", 64);
@@ -219,32 +370,114 @@
 
    mbed_mac_address((char*)&ArtPollReply.Mac);
 
-   ArtPollReply.NumPortsH = 0;
-   ArtPollReply.NumPorts = 0;
-   ArtPollReply.Swout[0] = 0;
-   ArtPollReply.Swout[1] = 0;
-   ArtPollReply.Swout[2] = 0;
-   ArtPollReply.Swout[3] = 0;
-   ArtPollReply.Swin[0] = 0;
-   ArtPollReply.Swin[1] = 0;
-   ArtPollReply.Swin[2] = 0;
-   ArtPollReply.Swin[3] = 0;
-
-   ArtPollReply.GoodOutput[0] = 0;
-   ArtPollReply.GoodOutput[1] = 0;
-   ArtPollReply.GoodOutput[2] = 0;
-   ArtPollReply.GoodOutput[3] = 0;
-   ArtPollReply.PortType[0] = 255;
-   ArtPollReply.PortType[1] = 255;
-   ArtPollReply.PortType[2] = 255;
-   ArtPollReply.PortType[3] = 255;
+   ArtPollReply.PortType[0] = 0;
+   ArtPollReply.PortType[1] = 0;
+   ArtPollReply.PortType[2] = 0;
+   ArtPollReply.PortType[3] = 0;
 }
 
 // send ArtPoll Reply
 int DmxArtNet::SendArtPollReply () {
+    int i, j, n;
 
    // send the packet
-   _art.sendto((char*)&ArtPollReply, sizeof(ArtPollReply), &RemoteSin);
+//    DBG("SendArtPollReply> %s:%d\r\n", RemoteSin.get_address(), RemoteSin.get_port());
+    if (ArtMaxUniv <= 4) {
+        _art.sendTo(RemoteSin, (char*)&ArtPollReply, sizeof(ArtPollReply));
+    } else {
+        for (i = 0; i < (ArtMaxUniv + 3) / 4; i ++) {
+            n = i * 4;
+            ArtPollReply.BindIndex = 1 + i;
+            ArtPollReply.NumPorts  = ArtMaxUniv - n < 4 ? ArtMaxUniv - n : 4;
+            for (j = 0; j < ArtPollReply.NumPorts; j ++) {
+                ArtPollReply.PortType[j]   = ArtPorts.PortType[n + j];
+                ArtPollReply.GoodInput[j]  = ArtPorts.GoodInput[n + j];
+                ArtPollReply.GoodOutput[j] = ArtPorts.GoodOutput[n + j];
+                ArtPollReply.Swin[j]       = ArtPorts.Swin[n + j];
+                ArtPollReply.Swout[j]      = ArtPorts.Swout[n + j];
+            }
+            for (; j < 4; j ++) {
+                ArtPollReply.PortType[j]   = 0;
+                ArtPollReply.GoodInput[j]  = 0;
+                ArtPollReply.GoodOutput[j] = 0;
+                ArtPollReply.Swin[j]       = 0;
+                ArtPollReply.Swout[j]      = 0;
+            }
+            _art.sendTo(RemoteSin, (char*)&ArtPollReply, sizeof(ArtPollReply));
+        }
+    }
+   return 0;
+}
+
+// send ArtIpProg Reply
+int DmxArtNet::SendArtIpProgReply () {
+    ArtIpProgReply_Packet ArtIpProgReply;
+    int ip[4];
+
+    memset(&ArtIpProgReply, 0, sizeof(ArtIpProgReply));
+    memcpy(ArtIpProgReply.ID, ArtHeaderID, 8);
+    ArtIpProgReply.OpCode = OP_IpProgReply;
+    ArtIpProgReply.Version = ArtVersion;
+
+    sscanf(BindIpAddress, "%d.%d.%d.%d", &ip[0], &ip[1], &ip[2], &ip[3]);
+    ArtIpProgReply.ProgIp[0] = ip[0];
+    ArtIpProgReply.ProgIp[1] = ip[1];
+    ArtIpProgReply.ProgIp[2] = ip[2];
+    ArtIpProgReply.ProgIp[3] = ip[3];
+    sscanf(SubNetMask, "%d.%d.%d.%d", &ip[0], &ip[1], &ip[2], &ip[3]);
+    ArtIpProgReply.ProgSm[0] = ip[0];
+    ArtIpProgReply.ProgSm[1] = ip[1];
+    ArtIpProgReply.ProgSm[2] = ip[2];
+    ArtIpProgReply.ProgSm[3] = ip[3];
+    ArtIpProgReply.ProgPortH = ArtUDPPort >> 8;
+    ArtIpProgReply.ProgPort = ArtUDPPort & 0xff;
+
+    if (BindIpAddress[0] == '0') {
+        ArtIpProgReply.Status = 0x40; // dhcp
+    }
+
+   _art.sendTo(RemoteSin, (char*)&ArtIpProgReply, sizeof(ArtIpProgReply));
 
    return 0;
 }
+
+// send SendArtTod
+int DmxArtNet::SendArtTodData (int n) {
+    ArtTodData_Packet ArtTodData;
+
+    memset(&ArtTodData, 0, sizeof(ArtTodData));
+    memcpy(ArtTodData.ID, ArtHeaderID, 8);
+    ArtTodData.OpCode = OP_OpTodData;
+    ArtTodData.Version = ArtVersion;
+
+    ArtTodData.RdmVersion = 1;
+    ArtTodData.Port = n + 1;
+
+    ArtTodData.UidTotalH = 0;
+    ArtTodData.UidTotalL = 1;
+    ArtTodData.BlockCount = 0;
+    ArtTodData.UidCount = 2;
+    ArtTodData.ToD[0] = 0x11;
+    ArtTodData.ToD[1] = 0x22;
+
+   _art.sendTo(RemoteSin, (char*)&ArtTodData, sizeof(ArtTodData));
+
+   return 0;
+}
+
+void DmxArtNet::bcast(char *dest, char *ipaddr, char *netmask) {
+    unsigned char ip[4];
+    int a[4], n[4];
+
+    sscanf(ipaddr, "%d.%d.%d.%d", &a[0], &a[1], &a[2], &a[3]);
+    sscanf(netmask, "%d.%d.%d.%d", &n[0], &n[1], &n[2], &n[3]);
+    ip[0] = (a[0] & n[0]) | ~n[0];
+    ip[1] = (a[1] & n[1]) | ~n[1];
+    ip[2] = (a[2] & n[2]) | ~n[2];
+    ip[3] = (a[3] & n[3]) | ~n[3];
+    sprintf(dest, "%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]);
+}
+
+void DmxArtNet::attach (void (*handler)(struct ArtPacketHeader *, int)) {
+    cb_ArtParser = handler;
+}
--- a/DmxArtNet.h	Thu Sep 29 16:42:34 2011 +0000
+++ b/DmxArtNet.h	Fri Sep 13 06:16:58 2019 +0000
@@ -7,37 +7,83 @@
  *
  * http://members.westnet.com.au/rowanmac/
  *
- * for mbed ported by Suga 2011
+ * for mbed ported by Suga 2011, 2017
  */
 
 /** @file
  */
 
+#ifndef _DmxArtNet_H_
+#define _DmxArtNet_H_
+
 #include "mbed.h"
-#include "EthernetNetIf.h"
-#include "UDPSocket.h"
+#include "rtos.h"
+#include "EthernetInterface.h"
+
+#ifndef DMX_SIZE
+#define DMX_SIZE 512
+#endif
 
 //#define ArtMaxUniv 16 // Universe
 #define ArtMaxUniv 4 // Universe
 
 //#define SizeRecvBuffer (530*4)
-#define SizeRecvBuffer 700
+//#define SizeRecvBuffer 560
+#define SizeRecvBuffer 1024
 
 // Art-Net Standard Stuff
-#define ArtHeaderID "Art-Net" // packet header
-#define ArtUDPPort 0x1936 // UDP port 6454 for Art-Net
-#define ArtVersion 14    // Art-Net version
+#define ArtHeaderID     "Art-Net" // packet header
+#define ArtUDPPort      0x1936 // UDP port 6454 for Art-Net
+#define ArtVersion      14    // Art-Net version
 
 // Art-Net OpCodes - defines type of packet
-#define OP_Output 0x5000 //Art-Net DMX Packet 'Output'
-#define OP_Poll 0x2000 // ArtPoll
-#define OP_PollReply 0x2100 // ArtPoll Reply
+#define OP_Output       0x5000 //Art-Net DMX Packet 'Output'
+#define OP_Poll         0x2000 // ArtPoll
+#define OP_PollReply    0x2100 // ArtPoll Reply
+#define OP_Address      0x6000 // ArtAddress
+
+#define OP_OpTodRequest 0x8000 
+#define OP_OpTodData    0x8100 
+#define OP_OpTodControl 0x8200 
+#define OP_OpRdm        0x8300 
+#define OP_OpRdmSub     0x8400 
+
+#define OP_IpProg       0xf800 // IpProg
+#define OP_IpProgReply  0xf900 // IpProgReply
+
+#define StyleNode       0
+#define StyleServer     1
+
+#define STR_LongName    "MbedArtNode - By Suga (2017), Rowan Maclachlan (2005)"
+#define STR_ShortName   "MbedArtNode"
+#define OEM_ID          0x7ff7
 
-#define StyleNode 0
-#define StyleServer 1
+#define OP_Poll_TalkToMe_SendMeDiag     (1<<2)
+#define OP_Poll_TalkToMe_DiagUnicast    (1<<3)
+#define OP_Poll_TalkToMe_DisableVLC     (1<<4)
+
+#define OP_PollRep_GoodIn_ReceiveError  (1<<2)
+#define OP_PollRep_GoodIn_Disabled      (1<<3)
+#define OP_PollRep_GoodIn_DmxText       (1<<4)
+#define OP_PollRep_GoodIn_DmxSip        (1<<5)
+#define OP_PollRep_GoodIn_DmxTest       (1<<6)
+#define OP_PollRep_GoodIn_Received      (1<<7)
 
-#define STR_LongName "MbedArtNode - By Suga (2011), Rowan Maclachlan (2005)"
-#define STR_ShortName "MbedArtNode"
+#define OP_PollRep_GoodOut_sACN         (1<<0)
+#define OP_PollRep_GoodOut_ModeLTP      (1<<1)
+#define OP_PollRep_GoodOut_ShortDetected (1<<2)
+#define OP_PollRep_GoodOut_MergeArtNet  (1<<3)
+#define OP_PollRep_GoodOut_DmxText      (1<<4)
+#define OP_PollRep_GoodOut_DmxSip       (1<<5)
+#define OP_PollRep_GoodOut_DmxTest      (1<<6)
+#define OP_PollRep_GoodOut_Transmitted  (1<<7)
+
+#define OP_IpProg_Command_ProgPort      (1<<0)
+#define OP_IpProg_Command_ProgNetmask   (1<<1)
+#define OP_IpProg_Command_ProgIpaddress (1<<2)
+#define OP_IpProg_Command_Prog3Param    (1<<3)
+#define OP_IpProg_Command_EnableDhcp    (1<<6)
+#define OP_IpProg_Command_EnableProg    (1<<7)
 
 
 // a DMX universe
@@ -64,25 +110,26 @@
      unsigned char Physical; // 0
      unsigned short Universes;
      unsigned short Length; // size of data segment
-     unsigned char Data[512]; // data segment
+     unsigned char Data[DMX_SIZE]; // data segment
 } __attribute__((packed));
 
 struct ArtPoll_Packet {
      char ID[8];
-     unsigned short OpCode; // 0x5000
+     unsigned short OpCode; // 0x2000
      unsigned char VersionH; // 0
      unsigned char Version; // 14
      unsigned char TalkToMe; // 0
+     unsigned char Priority;
 } __attribute__((packed));
 
 // a responce to a artpoll packet
 struct ArtPollReply_Packet {
      char ID[8];
-     unsigned short OpCode; // 0x2000
+     unsigned short OpCode; // 0x2100
      struct ArtAddr Addr; // our ip address
      unsigned char VersionH;
      unsigned char Version;
-     unsigned char SubSwitchH;
+     unsigned char NetSwitch;
      unsigned char SubSwitch;
      unsigned short OEM;
      char UbeaVersion;
@@ -104,15 +151,158 @@
      unsigned char Spare[3]; // three spare bytes
      unsigned char Style;
      unsigned char Mac[6];
-     unsigned char Padding[32]; // padding
+     unsigned char BindIp[4];
+     unsigned char BindIndex;
+     unsigned char Status2;
+     unsigned char Padding[26]; // padding
+} __attribute__((packed));
+
+struct ArtIpProg_Packet {
+     char ID[8];
+     unsigned short OpCode; // 0xf800
+     unsigned char VersionH; // 0
+     unsigned char Version; // 14
+     unsigned char Filler1;
+     unsigned char Filler2;
+     unsigned char Command;
+     unsigned char Filler4;
+     unsigned char ProgIp[4];
+     unsigned char ProgSm[4];
+     unsigned char ProgPortH;
+     unsigned char ProgPort;
+     unsigned char Padding[8];
+} __attribute__((packed));
+
+struct ArtIpProgReply_Packet {
+     char ID[8];
+     unsigned short OpCode; // 0xf900
+     unsigned char VersionH; // 0
+     unsigned char Version; // 14
+     unsigned char Filler1;
+     unsigned char Filler2;
+     unsigned char Filler3;
+     unsigned char Filler4;
+     unsigned char ProgIp[4];
+     unsigned char ProgSm[4];
+     unsigned char ProgPortH;
+     unsigned char ProgPort;
+     unsigned char Status;
+     unsigned char Padding[7];
+} __attribute__((packed));
+
+struct ArtAddress_Packet {
+     char ID[8];
+     unsigned short OpCode; // 0x6000
+     unsigned char VersionH;
+     unsigned char Version;
+     unsigned char NetSwitch;
+     unsigned char BindIndex;
+     char ShortName[18];
+     char LongName[64];
+     unsigned char Swin[4];
+     unsigned char Swout[4];
+     unsigned char SubSwitch;
+     unsigned char SwVideo;
+     unsigned char Command;
+} __attribute__((packed));
+
+struct ArtTodRequest_Packet {
+     char ID[8];
+     unsigned short OpCode; // 0x8300
+     unsigned char VersionH;
+     unsigned char Version;
+     unsigned char Filler1;
+     unsigned char Filler2;
+     char Spare[7];
+     char Net;
+     char Command;
+     char AddCount;
+     char Address[32];
 } __attribute__((packed));
 
+struct ArtTodData_Packet {
+     char ID[8];
+     unsigned short OpCode; // 0x8300
+     unsigned char VersionH;
+     unsigned char Version;
+     unsigned char RdmVersion;
+     unsigned char Port;
+     char Spare[6];
+     char BindIndex;
+     char Net;
+     char CommandResponse;
+     char Address;
+     char UidTotalH;
+     char UidTotalL;
+     char BlockCount;
+     char UidCount;
+     char ToD[6];
+} __attribute__((packed));
+
+struct ArtTodControl_Packet {
+     char ID[8];
+     unsigned short OpCode; // 0x8300
+     unsigned char VersionH;
+     unsigned char Version;
+     unsigned char Filler1;
+     unsigned char Filler2;
+     char Spare[7];
+     char Net;
+     char Command;
+     char Address;
+} __attribute__((packed));
+
+struct ArtRdm_Packet {
+     char ID[8];
+     unsigned short OpCode; // 0x8300
+     unsigned char VersionH;
+     unsigned char Version;
+     unsigned char RdmVersion;
+     unsigned char Filler2;
+     char Spare[7];
+     char Net;
+     char Command;
+     char Address;
+     char RdmPacket[];
+} __attribute__((packed));
+
+struct ArtRdmSub_Packet {
+     char ID[8];
+     unsigned short OpCode; // 0x8400
+     unsigned char VersionH;
+     unsigned char Version;
+     unsigned char RdmVersion;
+     unsigned char Filler2;
+     char uid[6];
+     char Spare1;
+     char CommandClass;
+     short ParameterId;
+     short SubDevice;
+     short SubCount;
+     char Spare[4];
+     short data[];
+} __attribute__((packed));
+
+
+struct ArtPorts_Config {
+     unsigned char PortType[ArtMaxUniv];
+     unsigned char GoodInput[ArtMaxUniv];
+     unsigned char GoodOutput[ArtMaxUniv];
+     unsigned char Swin[ArtMaxUniv];
+     unsigned char Swout[ArtMaxUniv];
+};
+
 /** DmxArtNet class
  */
 class DmxArtNet {
 public:
-    IpAddr BindIpAddress; // Local IP Address to bind onto
-    IpAddr BCastAddress; // address to broadcast on
+    unsigned short NetSwitch;
+    char BindIpAddress[16]; // Local IP Address to bind onto
+    char BCastAddress[16]; // address to broadcast on
+    char SubNetMask[16], DGateWay[16];
+    int UdpPort, OemId;
+
+    DmxArtNet ();
 
     /** create network socket, setup for NetworkWork
      * @return true if socket creation succeded
@@ -139,13 +329,6 @@
      */
     void ClearError();
 
-    /** recieve our own packets
-     * @return recieve our own packets
-     */
-    int loopback() {
-        return net_loopback;
-    }
-
     /** Send
      * send an array [0..511] of (length) bytes representing the dmx you want to send to
      * univ[0..15] ,  physical is info only, can be the universe number or port of device
@@ -156,15 +339,25 @@
      * @return 1 something happened
      */
     int Work();
-
+/*
+    void WorkAddress (ArtAddress_Packet *address);
+    void WorkIpProg (ArtIpProg_Packet *ipprog);
+*/
     unsigned char *DmxIn[ArtMaxUniv]; // Recieved ArtDMX, 16 Dmx Arrays
-    int LastRecievedUniverse; // the number of the last recieved universe
+    volatile int LastRecievedUniverse; // the number of the last recieved universe
 
     struct ArtPollReply_Packet ArtPollReply; // a response to ArtPoll
                                       // contains many variables you may set
+    struct ArtPorts_Config ArtPorts;
 
     void InitArtPollReplyDefaults();
     int SendArtPollReply();
+    int SendArtIpProgReply();
+    int SendArtTodData (int n);
+
+    void attach (void (*handler)(struct ArtPacketHeader *, int));
+
+    void bcast(char *dest, char *ipaddr, char *netmask);
 
 private:
     UDPSocket _art; // the network socket
@@ -174,17 +367,20 @@
     unsigned char buf[SizeRecvBuffer]; // a temp buffer
     struct ArtAddr localaddr;
     int LError;
-    char LErrorString[80];
+    char LErrorString[40];
 
     int makeword16 (int lsb, int msb);
 
     void Init_ArtDMX();
     void SocketErrorOccured(char *proc);
 
-    void on_UDPSocketEvent (UDPSocketEvent e);
+    static void task_UDPSocket (void const *arg);
+    void on_UDPSocketEvent ();
+
+    void (*cb_ArtParser)(struct ArtPacketHeader *art, int len);
 
-    int net_loopback; // if true, then listen to our own packets
-                      // is crap and does not work
-    Host RemoteSin;
+    Endpoint RemoteSin;
     volatile int rxlen;
+    Thread *thread;
 };
+#endif