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

Dependents:   ArtNode ArtNode DMXStation ArtNodeLED ... more

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers DmxArtNet.cpp Source File

DmxArtNet.cpp

Go to the documentation of this file.
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 }