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

Dependents:   ArtNode ArtNode DMXStation ArtNodeLED ... more

DmxArtNet.cpp

Committer:
okini3939
Date:
2011-09-29
Revision:
0:629617d401de
Child:
1:c59dc374fc64

File content as of revision 0:629617d401de:

/*
 * 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;
}