http://mbed.org/users/okini3939/notebook/art-net/
Dependents: ArtNode ArtNode DMXStation ArtNodeLED ... more
DmxArtNet.cpp@0:629617d401de, 2011-09-29 (annotated)
- Committer:
- okini3939
- Date:
- Thu Sep 29 15:46:43 2011 +0000
- Revision:
- 0:629617d401de
- Child:
- 1:c59dc374fc64
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
okini3939 | 0:629617d401de | 1 | /* |
okini3939 | 0:629617d401de | 2 | * Control Art-Net from freepascal & delphi |
okini3939 | 0:629617d401de | 3 | * (c) Rowan Maclachlan (hippy) rowanmac@optusnet.com.au [15d/01m/06y] |
okini3939 | 0:629617d401de | 4 | * |
okini3939 | 0:629617d401de | 5 | * Free for personal not-for-profit use only, please contact me if you are |
okini3939 | 0:629617d401de | 6 | * using it in a commercial product, as i would like a copy :) |
okini3939 | 0:629617d401de | 7 | * |
okini3939 | 0:629617d401de | 8 | * http://members.westnet.com.au/rowanmac/ |
okini3939 | 0:629617d401de | 9 | * |
okini3939 | 0:629617d401de | 10 | * for mbed port by Suga 2011 |
okini3939 | 0:629617d401de | 11 | */ |
okini3939 | 0:629617d401de | 12 | |
okini3939 | 0:629617d401de | 13 | /** @file |
okini3939 | 0:629617d401de | 14 | */ |
okini3939 | 0:629617d401de | 15 | |
okini3939 | 0:629617d401de | 16 | #include "mbed.h" |
okini3939 | 0:629617d401de | 17 | #include "EthernetNetIf.h" |
okini3939 | 0:629617d401de | 18 | #include "UDPSocket.h" |
okini3939 | 0:629617d401de | 19 | #include "DmxArtNet.h" |
okini3939 | 0:629617d401de | 20 | #include "dbg.h" |
okini3939 | 0:629617d401de | 21 | #include <stdio.h> |
okini3939 | 0:629617d401de | 22 | #include <string.h> |
okini3939 | 0:629617d401de | 23 | |
okini3939 | 0:629617d401de | 24 | // host to network short |
okini3939 | 0:629617d401de | 25 | #define htons( x ) ( (( (x) << 8 ) & 0xFF00) | (( (x) >> 8 ) & 0x00FF) ) |
okini3939 | 0:629617d401de | 26 | #define ntohs( x ) htons(x) |
okini3939 | 0:629617d401de | 27 | // host to network long |
okini3939 | 0:629617d401de | 28 | #define htonl( x ) ( (( (x) << 24 ) & 0xFF000000) \ |
okini3939 | 0:629617d401de | 29 | | (( (x) << 8 ) & 0x00FF0000) \ |
okini3939 | 0:629617d401de | 30 | | (( (x) >> 8 ) & 0x0000FF00) \ |
okini3939 | 0:629617d401de | 31 | | (( (x) >> 24 ) & 0x000000FF) ) |
okini3939 | 0:629617d401de | 32 | #define ntohl( x ) htonl(x) |
okini3939 | 0:629617d401de | 33 | |
okini3939 | 0:629617d401de | 34 | |
okini3939 | 0:629617d401de | 35 | extern "C" void mbed_mac_address(char *s); |
okini3939 | 0:629617d401de | 36 | |
okini3939 | 0:629617d401de | 37 | |
okini3939 | 0:629617d401de | 38 | // function to make a word (16bit) from two bytes (2 x 8bit) |
okini3939 | 0:629617d401de | 39 | int DmxArtNet::makeword16 (int lsb, int msb) { |
okini3939 | 0:629617d401de | 40 | return (msb << 8) + lsb; |
okini3939 | 0:629617d401de | 41 | } |
okini3939 | 0:629617d401de | 42 | |
okini3939 | 0:629617d401de | 43 | // report a socket error, halt program |
okini3939 | 0:629617d401de | 44 | void DmxArtNet::SocketErrorOccured (char *proc) { |
okini3939 | 0:629617d401de | 45 | LError = 1; |
okini3939 | 0:629617d401de | 46 | snprintf(LErrorString, sizeof(LErrorString), "socket> error occured in '%s'\r\n", proc); |
okini3939 | 0:629617d401de | 47 | DBG("%s", LErrorString); |
okini3939 | 0:629617d401de | 48 | } |
okini3939 | 0:629617d401de | 49 | |
okini3939 | 0:629617d401de | 50 | // clear error |
okini3939 | 0:629617d401de | 51 | void DmxArtNet::ClearError () { |
okini3939 | 0:629617d401de | 52 | LError = 0; |
okini3939 | 0:629617d401de | 53 | } |
okini3939 | 0:629617d401de | 54 | |
okini3939 | 0:629617d401de | 55 | int DmxArtNet::Init () { |
okini3939 | 0:629617d401de | 56 | int i; |
okini3939 | 0:629617d401de | 57 | UDPSocketErr err; |
okini3939 | 0:629617d401de | 58 | |
okini3939 | 0:629617d401de | 59 | LError = 0; // no error yet :) |
okini3939 | 0:629617d401de | 60 | Init_ArtDMX(); // initialize ArtDmx structure |
okini3939 | 0:629617d401de | 61 | // art = new UDPSocket; // create socket |
okini3939 | 0:629617d401de | 62 | net_loopback = 0; // dont listen to ourself, default |
okini3939 | 0:629617d401de | 63 | rxlen = 0; |
okini3939 | 0:629617d401de | 64 | |
okini3939 | 0:629617d401de | 65 | if (BindIpAddress == IpAddr(0,0,0,0)) { |
okini3939 | 0:629617d401de | 66 | BindIpAddress = IpAddr(2,0,0,1); // default to 2.0.0.1 |
okini3939 | 0:629617d401de | 67 | } |
okini3939 | 0:629617d401de | 68 | err = _art.bind(Host(BindIpAddress, ArtUDPPort, NULL)); |
okini3939 | 0:629617d401de | 69 | if (err) { |
okini3939 | 0:629617d401de | 70 | SocketErrorOccured("Bind error"); |
okini3939 | 0:629617d401de | 71 | return -1; |
okini3939 | 0:629617d401de | 72 | } |
okini3939 | 0:629617d401de | 73 | if (BCastAddress == IpAddr(0,0,0,0)) { |
okini3939 | 0:629617d401de | 74 | BCastAddress = IpAddr(2,255,255,255); // default |
okini3939 | 0:629617d401de | 75 | } |
okini3939 | 0:629617d401de | 76 | RemoteSin = Host(BCastAddress, ArtUDPPort, NULL); |
okini3939 | 0:629617d401de | 77 | |
okini3939 | 0:629617d401de | 78 | for (i = 0; i < ArtMaxUniv; i ++) { |
okini3939 | 0:629617d401de | 79 | DmxIn[i] = new unsigned char[512]; |
okini3939 | 0:629617d401de | 80 | } |
okini3939 | 0:629617d401de | 81 | |
okini3939 | 0:629617d401de | 82 | _art.setOnEvent(this, &DmxArtNet::on_UDPSocketEvent); |
okini3939 | 0:629617d401de | 83 | |
okini3939 | 0:629617d401de | 84 | return 0; |
okini3939 | 0:629617d401de | 85 | } |
okini3939 | 0:629617d401de | 86 | |
okini3939 | 0:629617d401de | 87 | void DmxArtNet::on_UDPSocketEvent (UDPSocketEvent e) { |
okini3939 | 0:629617d401de | 88 | if (e == UDPSOCKET_READABLE) { |
okini3939 | 0:629617d401de | 89 | rxlen = _art.recvfrom((char*)buf, sizeof(buf), &RemoteSin); |
okini3939 | 0:629617d401de | 90 | } |
okini3939 | 0:629617d401de | 91 | } |
okini3939 | 0:629617d401de | 92 | |
okini3939 | 0:629617d401de | 93 | int DmxArtNet::Work() { |
okini3939 | 0:629617d401de | 94 | // int rxlen, pos; |
okini3939 | 0:629617d401de | 95 | int pos; |
okini3939 | 0:629617d401de | 96 | int x, y; |
okini3939 | 0:629617d401de | 97 | int err; |
okini3939 | 0:629617d401de | 98 | unsigned char *RecvByte; |
okini3939 | 0:629617d401de | 99 | |
okini3939 | 0:629617d401de | 100 | if (rxlen >= sizeof(ArtPacketHeader)) { |
okini3939 | 0:629617d401de | 101 | // retreive the packet header |
okini3939 | 0:629617d401de | 102 | // err = art.Recv(buf, sizeof(ArtPacketHeader), 10); |
okini3939 | 0:629617d401de | 103 | |
okini3939 | 0:629617d401de | 104 | // if looback disabled |
okini3939 | 0:629617d401de | 105 | if (!net_loopback && RemoteSin.getIp() == BindIpAddress) { |
okini3939 | 0:629617d401de | 106 | DBG("ArtNet> loopback detected\r\n"); |
okini3939 | 0:629617d401de | 107 | |
okini3939 | 0:629617d401de | 108 | // art.purge; // dump the data |
okini3939 | 0:629617d401de | 109 | rxlen = 0; |
okini3939 | 0:629617d401de | 110 | return 0; // don't read packets |
okini3939 | 0:629617d401de | 111 | // which we sent! |
okini3939 | 0:629617d401de | 112 | } |
okini3939 | 0:629617d401de | 113 | |
okini3939 | 0:629617d401de | 114 | DBG("ArtNet> RX: %d\r\n", rxlen); |
okini3939 | 0:629617d401de | 115 | memcpy(&ArtHead, buf, sizeof(ArtPacketHeader)); |
okini3939 | 0:629617d401de | 116 | |
okini3939 | 0:629617d401de | 117 | // confirm is vaild art-net packet |
okini3939 | 0:629617d401de | 118 | if (strncmp(ArtHead.ID, ArtHeaderID, 8) == 0) { |
okini3939 | 0:629617d401de | 119 | |
okini3939 | 0:629617d401de | 120 | RecvByte = &buf[10]; |
okini3939 | 0:629617d401de | 121 | |
okini3939 | 0:629617d401de | 122 | switch (ArtHead.OpCode) { // determine packet type |
okini3939 | 0:629617d401de | 123 | |
okini3939 | 0:629617d401de | 124 | case OP_Output: // An ArtDMX Packet, containts dmx universe |
okini3939 | 0:629617d401de | 125 | ArtDMX.VersionH = RecvByte[0]; |
okini3939 | 0:629617d401de | 126 | ArtDMX.Version = RecvByte[1]; |
okini3939 | 0:629617d401de | 127 | ArtDMX.Sequence = RecvByte[2]; |
okini3939 | 0:629617d401de | 128 | ArtDMX.Physical = RecvByte[3]; |
okini3939 | 0:629617d401de | 129 | |
okini3939 | 0:629617d401de | 130 | x = RecvByte[4]; |
okini3939 | 0:629617d401de | 131 | y = RecvByte[5]; |
okini3939 | 0:629617d401de | 132 | ArtDMX.Universes = makeword16(x,y); |
okini3939 | 0:629617d401de | 133 | LastRecievedUniverse = ArtDMX.Universes; |
okini3939 | 0:629617d401de | 134 | |
okini3939 | 0:629617d401de | 135 | x = RecvByte[6]; |
okini3939 | 0:629617d401de | 136 | y = RecvByte[7]; |
okini3939 | 0:629617d401de | 137 | ArtDMX.Length = makeword16(y,x); |
okini3939 | 0:629617d401de | 138 | |
okini3939 | 0:629617d401de | 139 | // check data length |
okini3939 | 0:629617d401de | 140 | if (ArtDMX.Length <= 512) { |
okini3939 | 0:629617d401de | 141 | // get the dmx data |
okini3939 | 0:629617d401de | 142 | for (pos = 0; pos < ArtDMX.Length; pos ++) { |
okini3939 | 0:629617d401de | 143 | DmxIn[ArtDMX.Universes][pos] = RecvByte[8 + pos]; |
okini3939 | 0:629617d401de | 144 | } |
okini3939 | 0:629617d401de | 145 | DBG(" <Art-Dmx> Size: %d Univ: %d Ch1: %d\r\n", ArtDMX.Length, ArtDMX.Universes, DmxIn[ArtDMX.Universes][0]); |
okini3939 | 0:629617d401de | 146 | return 0; // something happened! |
okini3939 | 0:629617d401de | 147 | } |
okini3939 | 0:629617d401de | 148 | break; // op_output |
okini3939 | 0:629617d401de | 149 | |
okini3939 | 0:629617d401de | 150 | case OP_Poll: |
okini3939 | 0:629617d401de | 151 | ArtPoll.VersionH = RecvByte[0]; |
okini3939 | 0:629617d401de | 152 | ArtPoll.Version = RecvByte[1]; |
okini3939 | 0:629617d401de | 153 | ArtPoll.TalkToMe = RecvByte[2]; |
okini3939 | 0:629617d401de | 154 | DBG(" <Art-Poll> Ver: %d TalkToMe: %d\r\n", ArtPoll.Version, ArtPoll.TalkToMe); |
okini3939 | 0:629617d401de | 155 | SendArtPollReply(); // send a reply to the ArtPoll |
okini3939 | 0:629617d401de | 156 | break; |
okini3939 | 0:629617d401de | 157 | |
okini3939 | 0:629617d401de | 158 | default: |
okini3939 | 0:629617d401de | 159 | // NYI Packet Type |
okini3939 | 0:629617d401de | 160 | break; |
okini3939 | 0:629617d401de | 161 | } // case packet type |
okini3939 | 0:629617d401de | 162 | |
okini3939 | 0:629617d401de | 163 | rxlen = 0; |
okini3939 | 0:629617d401de | 164 | return 1; |
okini3939 | 0:629617d401de | 165 | } // waiting data |
okini3939 | 0:629617d401de | 166 | } |
okini3939 | 0:629617d401de | 167 | |
okini3939 | 0:629617d401de | 168 | rxlen = 0; |
okini3939 | 0:629617d401de | 169 | return 0; |
okini3939 | 0:629617d401de | 170 | } |
okini3939 | 0:629617d401de | 171 | |
okini3939 | 0:629617d401de | 172 | // socket shutdown |
okini3939 | 0:629617d401de | 173 | void DmxArtNet::Done () { |
okini3939 | 0:629617d401de | 174 | _art.resetOnEvent(); |
okini3939 | 0:629617d401de | 175 | _art.close(); |
okini3939 | 0:629617d401de | 176 | } |
okini3939 | 0:629617d401de | 177 | |
okini3939 | 0:629617d401de | 178 | // init ArtDMX packet |
okini3939 | 0:629617d401de | 179 | void DmxArtNet::Init_ArtDMX () { |
okini3939 | 0:629617d401de | 180 | // header stuff |
okini3939 | 0:629617d401de | 181 | memcpy(ArtDMX.ID, ArtHeaderID, 8); |
okini3939 | 0:629617d401de | 182 | ArtDMX.OpCode = OP_Output; |
okini3939 | 0:629617d401de | 183 | ArtDMX.Version = ArtVersion; |
okini3939 | 0:629617d401de | 184 | // dmx stuff |
okini3939 | 0:629617d401de | 185 | ArtDMX.Universes = 0; // this is the destination for the dmx |
okini3939 | 0:629617d401de | 186 | ArtDMX.Sequence = 0; |
okini3939 | 0:629617d401de | 187 | ArtDMX.Length = htons(512); |
okini3939 | 0:629617d401de | 188 | } |
okini3939 | 0:629617d401de | 189 | |
okini3939 | 0:629617d401de | 190 | // send ArtDmx Packet |
okini3939 | 0:629617d401de | 191 | int DmxArtNet::Send_ArtDmx(int univ, int physical, char *data, int length) { |
okini3939 | 0:629617d401de | 192 | Host Remote; |
okini3939 | 0:629617d401de | 193 | |
okini3939 | 0:629617d401de | 194 | // build a artdmx packet |
okini3939 | 0:629617d401de | 195 | memcpy(ArtDMX.Data, data, length); |
okini3939 | 0:629617d401de | 196 | ArtDMX.Universes = univ; |
okini3939 | 0:629617d401de | 197 | ArtDMX.Length = htons(length); |
okini3939 | 0:629617d401de | 198 | ArtDMX.Physical = physical; |
okini3939 | 0:629617d401de | 199 | ArtDMX.Sequence ++; |
okini3939 | 0:629617d401de | 200 | |
okini3939 | 0:629617d401de | 201 | // set place to send |
okini3939 | 0:629617d401de | 202 | Remote = Host(BCastAddress, ArtUDPPort, NULL); |
okini3939 | 0:629617d401de | 203 | |
okini3939 | 0:629617d401de | 204 | // send it off |
okini3939 | 0:629617d401de | 205 | _art.sendto((char*)&ArtDMX, sizeof(ArtDMX), &Remote); |
okini3939 | 0:629617d401de | 206 | |
okini3939 | 0:629617d401de | 207 | return 0; |
okini3939 | 0:629617d401de | 208 | } |
okini3939 | 0:629617d401de | 209 | |
okini3939 | 0:629617d401de | 210 | |
okini3939 | 0:629617d401de | 211 | |
okini3939 | 0:629617d401de | 212 | void DmxArtNet::InitArtPollReplyDefaults () { |
okini3939 | 0:629617d401de | 213 | memcpy(ArtPollReply.ID, ArtHeaderID, 8); |
okini3939 | 0:629617d401de | 214 | ArtPollReply.OpCode = OP_PollReply; // reply packet |
okini3939 | 0:629617d401de | 215 | ArtPollReply.Version = ArtVersion; |
okini3939 | 0:629617d401de | 216 | |
okini3939 | 0:629617d401de | 217 | memcpy(&ArtPollReply.Addr, &localaddr, sizeof(localaddr)); |
okini3939 | 0:629617d401de | 218 | strncpy(ArtPollReply.ShortName, STR_ShortName, 18); |
okini3939 | 0:629617d401de | 219 | strncpy(ArtPollReply.LongName, STR_LongName, 64); |
okini3939 | 0:629617d401de | 220 | strncpy(ArtPollReply.NodeReport, "OK", 64); |
okini3939 | 0:629617d401de | 221 | ArtPollReply.Style = StyleNode; |
okini3939 | 0:629617d401de | 222 | |
okini3939 | 0:629617d401de | 223 | mbed_mac_address((char*)&ArtPollReply.Mac); |
okini3939 | 0:629617d401de | 224 | |
okini3939 | 0:629617d401de | 225 | ArtPollReply.NumPortsH = 0; |
okini3939 | 0:629617d401de | 226 | ArtPollReply.NumPorts = 0; |
okini3939 | 0:629617d401de | 227 | ArtPollReply.Swout[0] = 0; |
okini3939 | 0:629617d401de | 228 | ArtPollReply.Swout[1] = 0; |
okini3939 | 0:629617d401de | 229 | ArtPollReply.Swout[2] = 0; |
okini3939 | 0:629617d401de | 230 | ArtPollReply.Swout[3] = 0; |
okini3939 | 0:629617d401de | 231 | ArtPollReply.Swin[0] = 0; |
okini3939 | 0:629617d401de | 232 | ArtPollReply.Swin[1] = 0; |
okini3939 | 0:629617d401de | 233 | ArtPollReply.Swin[2] = 0; |
okini3939 | 0:629617d401de | 234 | ArtPollReply.Swin[3] = 0; |
okini3939 | 0:629617d401de | 235 | |
okini3939 | 0:629617d401de | 236 | ArtPollReply.GoodOutput[0] = 0; |
okini3939 | 0:629617d401de | 237 | ArtPollReply.GoodOutput[1] = 0; |
okini3939 | 0:629617d401de | 238 | ArtPollReply.GoodOutput[2] = 0; |
okini3939 | 0:629617d401de | 239 | ArtPollReply.GoodOutput[3] = 0; |
okini3939 | 0:629617d401de | 240 | ArtPollReply.PortType[0] = 255; |
okini3939 | 0:629617d401de | 241 | ArtPollReply.PortType[1] = 255; |
okini3939 | 0:629617d401de | 242 | ArtPollReply.PortType[2] = 255; |
okini3939 | 0:629617d401de | 243 | ArtPollReply.PortType[3] = 255; |
okini3939 | 0:629617d401de | 244 | } |
okini3939 | 0:629617d401de | 245 | |
okini3939 | 0:629617d401de | 246 | // send ArtPoll Reply |
okini3939 | 0:629617d401de | 247 | int DmxArtNet::SendArtPollReply () { |
okini3939 | 0:629617d401de | 248 | |
okini3939 | 0:629617d401de | 249 | // send the packet |
okini3939 | 0:629617d401de | 250 | _art.sendto((char*)&ArtPollReply, sizeof(ArtPollReply), &RemoteSin); |
okini3939 | 0:629617d401de | 251 | |
okini3939 | 0:629617d401de | 252 | return 0; |
okini3939 | 0:629617d401de | 253 | } |