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

Dependents:   ArtNode ArtNode DMXStation ArtNodeLED ... more

Revision:
0:629617d401de
Child:
1:c59dc374fc64
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/DmxArtNet.cpp	Thu Sep 29 15:46:43 2011 +0000
@@ -0,0 +1,253 @@
+/*
+ * Control Art-Net from freepascal & delphi
+ * (c) Rowan Maclachlan (hippy) rowanmac@optusnet.com.au [15d/01m/06y]
+ *
+ * Free for personal not-for-profit use only, please contact me if you are
+ * using it in a commercial product, as i would like a copy :)
+ *
+ * http://members.westnet.com.au/rowanmac/
+ *
+ * for mbed port by Suga 2011
+ */
+
+/** @file
+ */
+
+#include "mbed.h"
+#include "EthernetNetIf.h"
+#include "UDPSocket.h"
+#include "DmxArtNet.h"
+#include "dbg.h"
+#include <stdio.h>
+#include <string.h>
+
+// host to network short
+#define htons( x ) ( (( (x) << 8 ) & 0xFF00) | (( (x) >> 8 ) & 0x00FF) )
+#define ntohs( x ) htons(x)
+// host to network long
+#define htonl( x ) ( (( (x) << 24 ) & 0xFF000000)  \
+                   | (( (x) <<  8 ) & 0x00FF0000)  \
+                   | (( (x) >>  8 ) & 0x0000FF00)  \
+                   | (( (x) >> 24 ) & 0x000000FF)  )
+#define ntohl( x ) htonl(x)
+
+
+extern "C" void mbed_mac_address(char *s);
+
+
+// function to make a word (16bit) from two bytes (2 x 8bit)
+int DmxArtNet::makeword16 (int lsb, int msb) {
+    return (msb << 8) + lsb;
+}
+
+// report a socket error, halt program
+void DmxArtNet::SocketErrorOccured (char *proc) {
+    LError = 1;
+    snprintf(LErrorString, sizeof(LErrorString), "socket> error occured in '%s'\r\n", proc);
+    DBG("%s", LErrorString);
+}
+
+// clear error
+void DmxArtNet::ClearError () {
+   LError = 0;
+}
+
+int DmxArtNet::Init () {
+   int i;
+   UDPSocketErr err;
+
+   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;
+
+   if (BindIpAddress == IpAddr(0,0,0,0)) {
+       BindIpAddress = IpAddr(2,0,0,1); // default to 2.0.0.1
+   }
+   err = _art.bind(Host(BindIpAddress, ArtUDPPort, NULL));
+   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);
+
+   for (i = 0; i < ArtMaxUniv; i ++) {
+       DmxIn[i] = new unsigned char[512];
+   }
+
+   _art.setOnEvent(this, &DmxArtNet::on_UDPSocketEvent);
+
+   return 0;
+}
+
+void DmxArtNet::on_UDPSocketEvent (UDPSocketEvent e) {
+    if (e == UDPSOCKET_READABLE) {
+        rxlen = _art.recvfrom((char*)buf, sizeof(buf), &RemoteSin);
+    }
+}
+
+int DmxArtNet::Work() {
+//   int rxlen, pos;
+   int pos;
+   int x, y;
+   int err;
+   unsigned char *RecvByte;
+
+   if (rxlen >= sizeof(ArtPacketHeader)) {
+      // retreive the packet header
+//      err = art.Recv(buf, sizeof(ArtPacketHeader), 10);
+
+     // if looback disabled
+     if (!net_loopback && RemoteSin.getIp() == BindIpAddress) {
+         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) {
+
+       RecvByte = &buf[10];
+
+       switch (ArtHead.OpCode) { // determine packet type
+
+       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];
+
+           x = RecvByte[4];
+           y = RecvByte[5];
+           ArtDMX.Universes = makeword16(x,y);
+           LastRecievedUniverse = ArtDMX.Universes;
+
+           x = RecvByte[6];
+           y = RecvByte[7];
+           ArtDMX.Length = makeword16(y,x);
+
+           // 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]);
+               return 0; // something happened!
+           }
+           break; // op_output
+
+       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;
+
+       default:
+           // NYI Packet Type
+           break;
+       } // case packet type
+
+       rxlen = 0;
+       return 1;
+     } // waiting data
+   }
+
+   rxlen = 0;
+   return 0;
+}
+
+// socket shutdown
+void DmxArtNet::Done () {
+    _art.resetOnEvent();
+    _art.close();
+}
+
+// init ArtDMX packet
+void DmxArtNet::Init_ArtDMX () {
+   // header stuff
+   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);
+}
+
+// send ArtDmx Packet
+int DmxArtNet::Send_ArtDmx(int univ, int physical, char *data, int length) {
+   Host Remote;
+
+   // build a artdmx packet
+   memcpy(ArtDMX.Data, data, length);
+   ArtDMX.Universes = univ;
+   ArtDMX.Length = htons(length);
+   ArtDMX.Physical = physical;
+   ArtDMX.Sequence ++;
+
+   // set place to send
+   Remote = Host(BCastAddress, ArtUDPPort, NULL);
+
+   // send it off
+   _art.sendto((char*)&ArtDMX, sizeof(ArtDMX), &Remote);
+
+   return 0;
+}
+
+
+
+void DmxArtNet::InitArtPollReplyDefaults () {
+   memcpy(ArtPollReply.ID, ArtHeaderID, 8);
+   ArtPollReply.OpCode = OP_PollReply; // reply packet
+   ArtPollReply.Version = ArtVersion;
+
+   memcpy(&ArtPollReply.Addr, &localaddr, sizeof(localaddr));
+   strncpy(ArtPollReply.ShortName, STR_ShortName, 18);
+   strncpy(ArtPollReply.LongName, STR_LongName, 64);
+   strncpy(ArtPollReply.NodeReport, "OK", 64);
+   ArtPollReply.Style = StyleNode;
+
+   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;
+}
+
+// send ArtPoll Reply
+int DmxArtNet::SendArtPollReply () {
+
+   // send the packet
+   _art.sendto((char*)&ArtPollReply, sizeof(ArtPollReply), &RemoteSin);
+
+   return 0;
+}