http://mbed.org/users/okini3939/notebook/art-net/
Dependents: ArtNode ArtNode DMXStation ArtNodeLED ... more
Diff: DmxArtNet.cpp
- 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; +}