http://mbed.org/users/okini3939/notebook/art-net/
Dependents: ArtNode ArtNode DMXStation ArtNodeLED ... more
Revision 2:0753f1ed1dec, committed 2019-09-13
- 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