http://mbed.org/users/okini3939/notebook/art-net/
Dependents: ArtNode ArtNode DMXStation ArtNodeLED ... more
Diff: DmxArtNet.cpp
- Revision:
- 2:0753f1ed1dec
- Parent:
- 1:c59dc374fc64
- Child:
- 3:89aa639c946a
--- 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; +}