http://mbed.org/users/okini3939/notebook/art-net/
Dependents: ArtNode ArtNode DMXStation ArtNodeLED ... more
DmxArtNet.cpp
00001 /* 00002 * Control Art-Net from freepascal & delphi 00003 * (c) Rowan Maclachlan (hippy) rowanmac@optusnet.com.au [15d/01m/06y] 00004 * 00005 * Free for personal not-for-profit use only, please contact me if you are 00006 * using it in a commercial product, as i would like a copy :) 00007 * 00008 * http://members.westnet.com.au/rowanmac/ 00009 * 00010 * for mbed ported by Suga 2011, 2017 00011 */ 00012 00013 /* 00014 * You can use GainSpan Wi-Fi module 00015 * 00016 * Include: GSwifiInterface 00017 * Create file: EthernetInterface.h 00018 * ----- 00019 * #include "GSwifiInterface.h" 00020 * #define eth gs 00021 * ----- 00022 */ 00023 00024 /** @file 00025 */ 00026 00027 #include "mbed.h" 00028 #include "EthernetInterface.h" 00029 #include "DmxArtNet.h " 00030 #include <stdio.h> 00031 #include <string.h> 00032 00033 //#define DEBUG 00034 #ifdef DEBUG 00035 #define DBG(...) printf("" __VA_ARGS__) 00036 #else 00037 #define DBG(...) 00038 #endif 00039 00040 /* 00041 // host to network short 00042 #define htons( x ) ( (( (x) << 8 ) & 0xFF00) | (( (x) >> 8 ) & 0x00FF) ) 00043 #define ntohs( x ) htons(x) 00044 // host to network long 00045 #define htonl( x ) ( (( (x) << 24 ) & 0xFF000000) \ 00046 | (( (x) << 8 ) & 0x00FF0000) \ 00047 | (( (x) >> 8 ) & 0x0000FF00) \ 00048 | (( (x) >> 24 ) & 0x000000FF) ) 00049 #define ntohl( x ) htonl(x) 00050 */ 00051 00052 extern "C" void mbed_mac_address(char *s); 00053 00054 00055 DmxArtNet::DmxArtNet () { 00056 BindIpAddress[0] = 0; 00057 BCastAddress[0] = 0; 00058 Init_ArtDMX(); 00059 InitArtPollReplyDefaults(); 00060 } 00061 00062 // function to make a word (16bit) from two bytes (2 x 8bit) 00063 int DmxArtNet::makeword16 (int lsb, int msb) { 00064 return (msb << 8) + lsb; 00065 } 00066 00067 // report a socket error, halt program 00068 void DmxArtNet::SocketErrorOccured (char *proc) { 00069 LError = 1; 00070 snprintf(LErrorString, sizeof(LErrorString), "socket> error occured in '%s'\r\n", proc); 00071 DBG("%s", LErrorString); 00072 } 00073 00074 // clear error 00075 void DmxArtNet::ClearError () { 00076 LError = 0; 00077 } 00078 00079 int DmxArtNet::Init () { 00080 int i; 00081 int err; 00082 00083 rxlen = 0; 00084 cb_ArtParser = NULL; 00085 LError = 0; // no error yet :) 00086 LastRecievedUniverse = 0; 00087 00088 // Init_ArtDMX(); // initialize ArtDmx structure 00089 00090 if (BindIpAddress[0] == 0) { 00091 char mac[6]; 00092 mbed_mac_address(mac); 00093 sprintf(BindIpAddress, "%d.%d.%d.%d", 2, mac[3], mac[4], mac[5]); 00094 strcpy(SubNetMask, "255.0.0.0"); 00095 } 00096 if (BCastAddress[0] == 0) { 00097 bcast(BCastAddress, BindIpAddress, SubNetMask); 00098 } 00099 RemoteSin.set_address(BCastAddress, ArtUDPPort); 00100 00101 err = _art.bind(ArtUDPPort); 00102 if (err) { 00103 SocketErrorOccured("Bind error"); 00104 return -1; 00105 } 00106 #ifndef GSWIFIINTERFACE_H_ 00107 _art.set_broadcasting(true); 00108 #endif 00109 00110 int ip[4]; 00111 sscanf(BindIpAddress, "%d.%d.%d.%d", &ip[0], &ip[1], &ip[2], &ip[3]); 00112 for (i = 0; i < 4; i ++) { 00113 localaddr.IP[i] = ip[i]; 00114 } 00115 localaddr.Port = ArtUDPPort; 00116 ArtPollReply.Addr = localaddr; 00117 00118 for (i = 0; i < ArtMaxUniv; i ++) { 00119 // DmxIn[i] = new unsigned char[DMX_SIZE]; 00120 DmxIn[i] = (unsigned char*)malloc(DMX_SIZE); 00121 memset(DmxIn[i], 0, DMX_SIZE); 00122 } 00123 00124 thread = new Thread(&DmxArtNet::task_UDPSocket, (void*)this, osPriorityNormal, 1024*4); 00125 00126 return 0; 00127 } 00128 00129 void DmxArtNet::task_UDPSocket (void const *arg) { 00130 DmxArtNet *inst = (DmxArtNet*)arg; 00131 00132 inst->on_UDPSocketEvent(); 00133 } 00134 00135 void DmxArtNet::on_UDPSocketEvent () { 00136 int n; 00137 00138 for (;;) { 00139 Work(); 00140 00141 n = _art.receiveFrom(RemoteSin, (char*)buf, sizeof(buf)); 00142 if (n < 0) break; 00143 if (n == 0) continue; 00144 rxlen = n; 00145 } 00146 } 00147 00148 int DmxArtNet::Work() { 00149 int i, n; 00150 struct ArtPacketHeader *ArtHead = (ArtPacketHeader*)buf; 00151 00152 if (rxlen >= sizeof(ArtPacketHeader)) { 00153 // retreive the packet header 00154 00155 // if looback disabled 00156 if (strcmp(RemoteSin.get_address(), BindIpAddress) == NULL) { 00157 DBG("ArtNet> loopback detected\r\n"); 00158 00159 rxlen = 0; 00160 return 0; // don't read packets 00161 // which we sent! 00162 } 00163 00164 // confirm is vaild art-net packet 00165 if (strncmp(ArtHead->ID, ArtHeaderID, 8) != 0) { 00166 rxlen = 0; 00167 return 0; 00168 } 00169 00170 DBG("ArtNet> RX: %d OpCode: %04x\r\n", rxlen, ArtHead->OpCode); 00171 00172 switch (ArtHead->OpCode) { // determine packet type 00173 00174 case OP_Output: // 0x5000 An ArtDMX Packet, containts dmx universe 00175 if (rxlen >= sizeof(struct ArtDMX_Packet) - (DMX_SIZE - 2)) { 00176 struct ArtDMX_Packet *artdmx = (struct ArtDMX_Packet*)buf; 00177 00178 // check data length 00179 if (ntohs(artdmx->Length) > DMX_SIZE || (artdmx->Universes & 0x7ff0) != (NetSwitch & 0x7ff0)) { 00180 break; 00181 } 00182 00183 for (i = 0; i < ArtMaxUniv; i ++) { 00184 if ( (ArtMaxUniv <= 4 && ArtPollReply.Swout[i] == (artdmx->Universes & 0x0f)) || 00185 (ArtMaxUniv > 4 && ArtPorts.Swout[i] == (artdmx->Universes & 0x0f)) ) { 00186 LastRecievedUniverse |= (1<<i); 00187 // get the dmx data 00188 memcpy(DmxIn[i], artdmx->Data, ntohs(artdmx->Length)); 00189 DBG(" <Art-Dmx> Univ: %d Length: %d Ch1: %d\r\n", artdmx->Universes, ntohs(artdmx->Length), DmxIn[i][0]); 00190 DBG(" from %s\r\n", RemoteSin.get_address()); 00191 rxlen = 0; 00192 return 1; // something happened! 00193 } 00194 } 00195 } 00196 break; // OP_Output 00197 00198 case OP_Poll: // 0x2000 00199 if (rxlen == sizeof(struct ArtPoll_Packet)) { 00200 struct ArtPoll_Packet *artpoll = (struct ArtPoll_Packet*)buf; 00201 00202 if (!(artpoll->TalkToMe & 1)) { 00203 RemoteSin.set_address(BCastAddress, ArtUDPPort); 00204 } 00205 DBG(" <Art-Poll> Ver: %d TalkToMe: %d\r\n", ArtPoll.Version, ArtPoll.TalkToMe); 00206 SendArtPollReply(); // send a reply to the ArtPoll 00207 } 00208 break; // OP_Poll 00209 00210 case OP_PollReply: // 0x2100 00211 { 00212 struct ArtPollReply_Packet *pollreply = (struct ArtPollReply_Packet*)buf; 00213 00214 DBG(" <Art-PollReply> Startus: %02x Name: %s\r\n", pollreply->Status, pollreply->ShortName); 00215 } 00216 break; // OP_PollReply 00217 00218 case OP_Address: // 0x6000 00219 if (rxlen == sizeof(struct ArtAddress_Packet)) { 00220 struct ArtAddress_Packet *address = (struct ArtAddress_Packet *)buf; 00221 00222 if ((address->NetSwitch & 0x80) && (address->SubSwitch & 0x80)) { 00223 NetSwitch = ((address->NetSwitch & 0x7f) << 8) | ((address->SubSwitch & 0x0f) << 4); 00224 ArtPollReply.NetSwitch = (NetSwitch >> 8) & 0x7f; 00225 ArtPollReply.SubSwitch = (NetSwitch >> 4) & 0x0f; 00226 } 00227 if (address->ShortName[0]) { 00228 strncpy(ArtPollReply.ShortName, address->ShortName, 18); 00229 } 00230 if (address->LongName[0]) { 00231 strncpy(ArtPollReply.LongName, address->LongName, 64); 00232 } 00233 if (address->BindIndex) { 00234 n = (address->BindIndex - 1) * 4; 00235 } else { 00236 n = 0; 00237 } 00238 for (i = 0; i < 4; i ++) { 00239 if (address->Swin[i] != 0x7f) { 00240 ArtPollReply.Swin[i] = address->Swin[i] & 0x0f; 00241 ArtPorts.Swin[n + i] = address->Swin[i] & 0x0f; 00242 if (address->Swin[i] & 0x80) { 00243 ArtPollReply.PortType[i] |= 0x40; 00244 ArtPorts.PortType[n + i] |= 0x40; 00245 } else { 00246 ArtPollReply.PortType[i] &= ~0x40; 00247 ArtPorts.PortType[n + i] &= ~0x40; 00248 } 00249 } 00250 if (address->Swout[i] != 0x7f) { 00251 ArtPollReply.Swout[i] = address->Swout[i] & 0x0f; 00252 ArtPorts.Swout[n + i] = address->Swout[i] & 0x0f; 00253 if (address->Swout[i] & 0x80) { 00254 ArtPollReply.PortType[i] |= 0x80; 00255 ArtPorts.PortType[n + i] |= 0x80; 00256 } else { 00257 ArtPollReply.PortType[i] &= ~0x80; 00258 ArtPorts.PortType[n + i] &= ~0x80; 00259 } 00260 } 00261 } 00262 00263 if (cb_ArtParser) cb_ArtParser(ArtHead, rxlen); 00264 SendArtPollReply(); // send a reply to the ArtPoll 00265 DBG(" <Art-Address> NetSwitch: %02x Command: %02x\r\n", NetSwitch, address->Command); 00266 } 00267 break; 00268 00269 case OP_IpProg: // 0xf800 00270 if (rxlen == sizeof(struct ArtIpProg_Packet)) { 00271 struct ArtIpProg_Packet *ipprog = (struct ArtIpProg_Packet *)buf; 00272 00273 if (ipprog->Command & (1<<7)) { 00274 if (ipprog->Command & (1<<6)) { // dhcp 00275 BindIpAddress[0] = 0; 00276 } 00277 if (ipprog->Command & (1<<2)) { // ip addrress 00278 sprintf(BindIpAddress, "%d.%d.%d.%d", ipprog->ProgIp[0], ipprog->ProgIp[1], ipprog->ProgIp[2], ipprog->ProgIp[3]); 00279 // sprintf(DGateWay, "%d.%d.%d.%d", ipprog->Padding[0], ipprog->Padding[1], ipprog->Padding[2], ipprog->Padding[3]); 00280 } 00281 if (ipprog->Command & (1<<1)) { // subnet mask 00282 sprintf(SubNetMask, "%d.%d.%d.%d", ipprog->ProgSm[0], ipprog->ProgSm[1], ipprog->ProgSm[2], ipprog->ProgSm[3]); 00283 } 00284 bcast(BCastAddress, BindIpAddress, SubNetMask); 00285 } 00286 00287 // if (cb_ArtParser) cb_ArtParser(ArtHead, rxlen); 00288 SendArtIpProgReply(); 00289 DBG(" <Art-IpProg> NetSwitch: %02x Command: %02x\r\n", NetSwitch, ipprog->Command); 00290 } 00291 if (cb_ArtParser) cb_ArtParser(ArtHead, rxlen); 00292 break; 00293 00294 case OP_OpTodRequest: // 0x8000 00295 if (rxlen == sizeof(struct ArtTodRequest_Packet)) { 00296 struct ArtTodRequest_Packet *todreq = (struct ArtTodRequest_Packet *)buf; 00297 if (cb_ArtParser) cb_ArtParser(ArtHead, rxlen); 00298 for (i = 0; i < todreq->AddCount; i ++) { 00299 SendArtTodData(todreq->Address[i]); 00300 } 00301 } 00302 break; 00303 00304 case OP_OpTodControl: // 0x8200 00305 if (rxlen == sizeof(struct ArtTodControl_Packet)) { 00306 struct ArtTodControl_Packet *tod = (struct ArtTodControl_Packet *)buf; 00307 if (cb_ArtParser) cb_ArtParser(ArtHead, rxlen); 00308 if (tod->Command == 0x01) { 00309 SendArtTodData(tod->Address); 00310 } 00311 } 00312 break; 00313 00314 case OP_OpRdm: // 0x8300 00315 case OP_OpRdmSub: // 0x8400 00316 default: 00317 if (cb_ArtParser) cb_ArtParser(ArtHead, rxlen); 00318 DBG(" <Unknown> OpCode: %04x\r\n", ArtHead->OpCode); 00319 break; 00320 } // case packet type 00321 } 00322 00323 rxlen = 0; 00324 return 0; 00325 } 00326 00327 // socket shutdown 00328 void DmxArtNet::Done () { 00329 _art.close(); 00330 } 00331 00332 // init ArtDMX packet 00333 void DmxArtNet::Init_ArtDMX () { 00334 // header stuff 00335 memset(&ArtDMX, 0, sizeof(ArtDMX)); 00336 memcpy(ArtDMX.ID, ArtHeaderID, 8); 00337 ArtDMX.OpCode = OP_Output; 00338 ArtDMX.Version = ArtVersion; 00339 // dmx stuff 00340 ArtDMX.Universes = 0; // this is the destination for the dmx 00341 ArtDMX.Sequence = 0; 00342 ArtDMX.Length = htons(DMX_SIZE); 00343 } 00344 00345 // send ArtDmx Packet 00346 int DmxArtNet::Send_ArtDmx(int univ, int physical, char *data, int length) { 00347 Endpoint Remote; 00348 00349 // build a artdmx packet 00350 memcpy(ArtDMX.Data, data, length); 00351 ArtDMX.Universes = (NetSwitch & 0x7ff0) | univ; 00352 ArtDMX.Length = htons(length); 00353 ArtDMX.Physical = physical; 00354 ArtDMX.Sequence ++; 00355 00356 // set place to send 00357 Remote.set_address(BCastAddress, ArtUDPPort); 00358 00359 // send it off 00360 _art.sendTo(Remote, (char*)&ArtDMX, sizeof(ArtDMX)); 00361 00362 return 0; 00363 } 00364 00365 00366 void DmxArtNet::InitArtPollReplyDefaults () { 00367 memset(&ArtPollReply, 0, sizeof(ArtPollReply)); 00368 memset(&ArtPorts, 0, sizeof(ArtPorts)); 00369 memcpy(ArtPollReply.ID, ArtHeaderID, 8); 00370 ArtPollReply.OpCode = OP_PollReply; // reply packet 00371 ArtPollReply.Version = ArtVersion; 00372 00373 ArtPollReply.NetSwitch = (NetSwitch >> 8) & 0x7f; 00374 ArtPollReply.SubSwitch = (NetSwitch >> 4) & 0x0f; 00375 ArtPollReply.OEM = htons(OemId); 00376 ArtPollReply.Status = (3<<6)|(2<<4); // Normal mode, Universe programmed by network 00377 00378 ArtPollReply.Addr = localaddr; 00379 strncpy(ArtPollReply.ShortName, STR_ShortName, 18); 00380 strncpy(ArtPollReply.LongName, STR_LongName, 64); 00381 strncpy(ArtPollReply.NodeReport, "OK", 64); 00382 ArtPollReply.Style = StyleNode; 00383 00384 mbed_mac_address((char*)&ArtPollReply.Mac); 00385 00386 ArtPollReply.PortType[0] = 0; 00387 ArtPollReply.PortType[1] = 0; 00388 ArtPollReply.PortType[2] = 0; 00389 ArtPollReply.PortType[3] = 0; 00390 } 00391 00392 // send ArtPoll Reply 00393 int DmxArtNet::SendArtPollReply () { 00394 int i, j, n; 00395 00396 // send the packet 00397 // DBG("SendArtPollReply> %s:%d\r\n", RemoteSin.get_address(), RemoteSin.get_port()); 00398 if (ArtMaxUniv <= 4) { 00399 _art.sendTo(RemoteSin, (char*)&ArtPollReply, sizeof(ArtPollReply)); 00400 } else { 00401 for (i = 0; i < (ArtMaxUniv + 3) / 4; i ++) { 00402 n = i * 4; 00403 ArtPollReply.BindIndex = 1 + i; 00404 ArtPollReply.NumPorts = ArtMaxUniv - n < 4 ? ArtMaxUniv - n : 4; 00405 for (j = 0; j < ArtPollReply.NumPorts; j ++) { 00406 ArtPollReply.PortType[j] = ArtPorts.PortType[n + j]; 00407 ArtPollReply.GoodInput[j] = ArtPorts.GoodInput[n + j]; 00408 ArtPollReply.GoodOutput[j] = ArtPorts.GoodOutput[n + j]; 00409 ArtPollReply.Swin[j] = ArtPorts.Swin[n + j]; 00410 ArtPollReply.Swout[j] = ArtPorts.Swout[n + j]; 00411 } 00412 for (; j < 4; j ++) { 00413 ArtPollReply.PortType[j] = 0; 00414 ArtPollReply.GoodInput[j] = 0; 00415 ArtPollReply.GoodOutput[j] = 0; 00416 ArtPollReply.Swin[j] = 0; 00417 ArtPollReply.Swout[j] = 0; 00418 } 00419 _art.sendTo(RemoteSin, (char*)&ArtPollReply, sizeof(ArtPollReply)); 00420 } 00421 } 00422 return 0; 00423 } 00424 00425 // send ArtIpProg Reply 00426 int DmxArtNet::SendArtIpProgReply () { 00427 ArtIpProgReply_Packet ArtIpProgReply; 00428 int ip[4]; 00429 00430 memset(&ArtIpProgReply, 0, sizeof(ArtIpProgReply)); 00431 memcpy(ArtIpProgReply.ID, ArtHeaderID, 8); 00432 ArtIpProgReply.OpCode = OP_IpProgReply; 00433 ArtIpProgReply.Version = ArtVersion; 00434 00435 sscanf(BindIpAddress, "%d.%d.%d.%d", &ip[0], &ip[1], &ip[2], &ip[3]); 00436 ArtIpProgReply.ProgIp[0] = ip[0]; 00437 ArtIpProgReply.ProgIp[1] = ip[1]; 00438 ArtIpProgReply.ProgIp[2] = ip[2]; 00439 ArtIpProgReply.ProgIp[3] = ip[3]; 00440 sscanf(SubNetMask, "%d.%d.%d.%d", &ip[0], &ip[1], &ip[2], &ip[3]); 00441 ArtIpProgReply.ProgSm[0] = ip[0]; 00442 ArtIpProgReply.ProgSm[1] = ip[1]; 00443 ArtIpProgReply.ProgSm[2] = ip[2]; 00444 ArtIpProgReply.ProgSm[3] = ip[3]; 00445 ArtIpProgReply.ProgPortH = ArtUDPPort >> 8; 00446 ArtIpProgReply.ProgPort = ArtUDPPort & 0xff; 00447 00448 if (BindIpAddress[0] == '0') { 00449 ArtIpProgReply.Status = 0x40; // dhcp 00450 } 00451 00452 _art.sendTo(RemoteSin, (char*)&ArtIpProgReply, sizeof(ArtIpProgReply)); 00453 00454 return 0; 00455 } 00456 00457 // send SendArtTod 00458 int DmxArtNet::SendArtTodData (int n) { 00459 ArtTodData_Packet ArtTodData; 00460 00461 memset(&ArtTodData, 0, sizeof(ArtTodData)); 00462 memcpy(ArtTodData.ID, ArtHeaderID, 8); 00463 ArtTodData.OpCode = OP_OpTodData; 00464 ArtTodData.Version = ArtVersion; 00465 00466 ArtTodData.RdmVersion = 1; 00467 ArtTodData.Port = n + 1; 00468 00469 ArtTodData.UidTotalH = 0; 00470 ArtTodData.UidTotalL = 1; 00471 ArtTodData.BlockCount = 0; 00472 ArtTodData.UidCount = 2; 00473 ArtTodData.ToD[0] = 0x11; 00474 ArtTodData.ToD[1] = 0x22; 00475 00476 _art.sendTo(RemoteSin, (char*)&ArtTodData, sizeof(ArtTodData)); 00477 00478 return 0; 00479 } 00480 00481 void DmxArtNet::bcast(char *dest, char *ipaddr, char *netmask) { 00482 unsigned char ip[4]; 00483 int a[4], n[4]; 00484 00485 sscanf(ipaddr, "%d.%d.%d.%d", &a[0], &a[1], &a[2], &a[3]); 00486 sscanf(netmask, "%d.%d.%d.%d", &n[0], &n[1], &n[2], &n[3]); 00487 ip[0] = (a[0] & n[0]) | ~n[0]; 00488 ip[1] = (a[1] & n[1]) | ~n[1]; 00489 ip[2] = (a[2] & n[2]) | ~n[2]; 00490 ip[3] = (a[3] & n[3]) | ~n[3]; 00491 sprintf(dest, "%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]); 00492 } 00493 00494 void DmxArtNet::attach (void (*handler)(struct ArtPacketHeader *, int)) { 00495 cb_ArtParser = handler; 00496 }
Generated on Thu Jul 14 2022 05:23:18 by 1.7.2