http://mbed.org/users/okini3939/notebook/art-net/
Dependents: ArtNode ArtNode DMXStation ArtNodeLED ... more
Revision 0:629617d401de, committed 2011-09-29
- Comitter:
- okini3939
- Date:
- Thu Sep 29 15:46:43 2011 +0000
- Child:
- 1:c59dc374fc64
- Commit message:
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 |
--- /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; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/DmxArtNet.h Thu Sep 29 15:46:43 2011 +0000 @@ -0,0 +1,189 @@ +/* + * 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 ported by Suga 2011 + */ + +/** @file + */ + +#include "mbed.h" +#include "EthernetNetIf.h" +#include "UDPSocket.h" + +//#define ArtMaxUniv 16 // Universe +#define ArtMaxUniv 4 // Universe + +//#define SizeRecvBuffer (530*4) +#define SizeRecvBuffer 700 + +// 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 + +// 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 StyleNode 0 +#define StyleServer 1 + +#define STR_LongName "MbedArtNode - By Suga (2011), Rowan Maclachlan (2005)" +#define STR_ShortName "MbedArtNode" + + +// a DMX universe +//#define DMXArray = array[0..511] of byte; + +struct ArtAddr { + unsigned char IP[4]; // ip addess 0.1.2.3 + unsigned short Port; +} __attribute__((packed)); + +struct ArtPacketHeader { + char ID[8]; + unsigned short OpCode; // 0x5000 +} __attribute__((packed)); + + +// dmx transport packet +struct ArtDMX_Packet { + char ID[8]; + unsigned short OpCode; // 0x5000 + unsigned char VersionH; // 0 + unsigned char Version; // 14 + unsigned char Sequence; // 0 + unsigned char Physical; // 0 + unsigned short Universes; + unsigned short Length; // size of data segment + unsigned char Data[512]; // data segment +} __attribute__((packed)); + +struct ArtPoll_Packet { + char ID[8]; + unsigned short OpCode; // 0x5000 + unsigned char VersionH; // 0 + unsigned char Version; // 14 + unsigned char TalkToMe; // 0 +} __attribute__((packed)); + +// a responce to a artpoll packet +struct ArtPollReply_Packet { + char ID[8]; + unsigned short OpCode; // 0x2000 + struct ArtAddr Addr; // our ip address + unsigned char VersionH; + unsigned char Version; + unsigned char SubSwitchH; + unsigned char SubSwitch; + unsigned short OEM; + char UbeaVersion; + char Status; + unsigned short EstaMan; + char ShortName[18]; + char LongName[64]; + char NodeReport[64]; + unsigned char NumPortsH; + unsigned char NumPorts; + unsigned char PortType[4]; + unsigned char GoodInput[4]; + unsigned char GoodOutput[4]; + unsigned char Swin[4]; + unsigned char Swout[4]; + unsigned char SwVideo; + unsigned char SwMacro; + unsigned char SwRemote; + unsigned char Spare[3]; // three spare bytes + unsigned char Style; + unsigned char Mac[6]; + unsigned char Padding[32]; // padding +} __attribute__((packed)); + + +class DmxArtNet { +public: + IpAddr BindIpAddress; // Local IP Address to bind onto + IpAddr BCastAddress; // address to broadcast on + + /** create network socket, setup for NetworkWork + * @return true if socket creation succeded + */ + int Init(); + + /** socket shutdown + */ + void Done(); + + /** last error + * @retval 0 ok + */ + int LastError() { + return LError; + } + /** returns descrip of last error + * @return descrip of last error + */ + char *LastErrorString() { + return LErrorString; + } + /** clear error + */ + 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 + */ + int Send_ArtDmx(int univ, int physical, char *data, int length); + /** execute often + * returns true if something happened + * @return 1 something happened + */ + int Work(); + + unsigned char *DmxIn[ArtMaxUniv]; // Recieved ArtDMX, 16 Dmx Arrays + int LastRecievedUniverse; // the number of the last recieved universe + + struct ArtPollReply_Packet ArtPollReply; // a response to ArtPoll + // contains many variables you may set + + void InitArtPollReplyDefaults(); + int SendArtPollReply(); + +private: + UDPSocket _art; // the network socket + struct ArtPacketHeader ArtHead; // packet header + struct ArtDMX_Packet ArtDMX; // an Art-Net DMX Packet + struct ArtPoll_Packet ArtPoll; // an Art-Poll Packet + unsigned char buf[SizeRecvBuffer]; // a temp buffer + struct ArtAddr localaddr; + int LError; + char LErrorString[80]; + + int makeword16 (int lsb, int msb); + + void Init_ArtDMX(); + void SocketErrorOccured(char *proc); + + void on_UDPSocketEvent (UDPSocketEvent e); + + int net_loopback; // if true, then listen to our own packets + // is crap and does not work + Host RemoteSin; + volatile int rxlen; +};