DMX512, RDM send/recv library http://mbed.org/users/okini3939/notebook/dmx512

Dependents:   dmx_test ArtNodeLED SPK-DVIMXR SPK-DMXer ... more

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers RDM.cpp Source File

RDM.cpp

Go to the documentation of this file.
00001 /*
00002  * DMX512, RDM send/recv library
00003  * Copyright (c) 2017 Hiroshi Suga
00004  * Released under the MIT License: http://mbed.org/license/mit
00005  */
00006 
00007 /** @file
00008  * @brief DMX512 send/recv
00009  */
00010 
00011 #include "mbed.h"
00012 #include "DMX.h"
00013 
00014 #ifdef RDM_ENABLE
00015 
00016 #define htons(n) __REV16(n)
00017 #define ntohs(n) __REV16(n)
00018 #define htonl(n) __REV(n)
00019 #define ntohl(n) __REV(n)
00020 
00021 static unsigned char uid_broadcast[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
00022 
00023 void DMX::pollRdm () {
00024     int i, len, crc, forMe, forGrp, forAll;
00025     struct RDM_DATA *rdm = (struct RDM_DATA *)data_rx;
00026 
00027     if (!is_rdm_received) return;
00028     is_rdm_received = 0;
00029     if (rdm->Length < 24) return;
00030 
00031     len = rdm->DataLength;
00032     crc = (rdm->Data[len] << 8) | rdm->Data[len + 1];
00033     if (calcCrc(data_rx, rdm->Length - 1) != crc) return;
00034 
00035     forMe  = memcmp(rdm_uid, rdm->DestID, 6) == 0 ? 1 : 0;
00036     forGrp = (rdm_uid[0] == rdm->DestID[0] && rdm_uid[1] == rdm->DestID[1] && memcmp(&rdm_uid[2], uid_broadcast, 4) == 0) ? 1 : 0;
00037     forAll = memcmp(rdm_uid, uid_broadcast, 6) == 0 ? 1 : 0;
00038 
00039     switch (rdm->CmdClass) {
00040     case E120_DISCOVERY_COMMAND:
00041         switch (ntohs(rdm->Parameter)) {
00042         case E120_DISC_UNIQUE_BRANCH:
00043             if (rdm->DataLength == 12 && !rdm_mute) {
00044                 if (memcmp(rdm_uid, &rdm->Data[0], 6) >= 0 && memcmp(rdm_uid, &rdm->Data[6], 6) <= 0) {
00045                     sendRdmDiscResponse(rdm);
00046                 }
00047             }
00048             break;
00049 
00050         case E120_DISC_MUTE:
00051         case E120_DISC_UN_MUTE:
00052             if (forMe || forGrp || forAll) {
00053                 if (rdm->CmdClass == E120_DISC_MUTE) {
00054                     rdm_mute = 1;
00055                 } else {
00056                     rdm_mute = 0;
00057                 }
00058                 if (forMe) sendRdmDiscMuteResponse(rdm);
00059             }
00060             break;
00061 
00062         }
00063         break;
00064 
00065     case E120_DISCOVERY_COMMAND_RESPONSE:
00066         switch (ntohs(rdm->Parameter)) {
00067         case E120_DISC_MUTE:
00068         case E120_DISC_UN_MUTE:
00069             if (forMe && memcmp(found_uid, rdm->SourceID, 6) == 0) {
00070                 if (buf_uid_size && buf_uid_count < buf_uid_size) {
00071                     memcpy(&buf_uid[6 * buf_uid_count], rdm->SourceID, 6);
00072                     buf_uid_count ++;
00073                 }
00074             }
00075         }
00076         break;
00077 
00078     case E120_GET_COMMAND:
00079     case E120_SET_COMMAND:
00080         if ((forMe || forGrp || forAll) && cb_RdmParser) {
00081             cb_RdmParser(rdm);
00082         }
00083         break;
00084 
00085     case E120_GET_COMMAND_RESPONSE:
00086     case E120_SET_COMMAND_RESPONSE:
00087         if ((forMe || forGrp || forAll) && cb_RdmParser) {
00088             cb_RdmParser(rdm);
00089         }
00090         break;
00091     }
00092 }
00093 
00094 int DMX::calcCrc (unsigned char *buf, int len, int offset) {
00095     int i, crc = offset;
00096 
00097     for (i = 0; i < len; i ++) {
00098         crc += buf[i];
00099     }
00100     return crc;
00101 }
00102 
00103 void DMX::rdmStart (int block) {
00104     Timer t;
00105 
00106     t.start();
00107     while (mode_rx != DMX_MODE_BEGIN && t.read_ms() < 100) {
00108         pollRdm();
00109     }
00110     t.stop();
00111 
00112     mode_rdm = 1;
00113     mode_rx = DMX_MODE_BEGIN;
00114     mode_tx = DMX_MODE_BEGIN;
00115     is_sent = 0;
00116     is_received = 0;
00117     is_rdm_received = 0;
00118     timeout01.attach_us(this, &DMX::int_timer, RDM_TIME_DELAY);
00119 
00120     if (block) {
00121         while (mode_rdm);
00122     }
00123 }
00124 
00125 void DMX::rdmWaitResponse (int ms) {
00126     Timer t;
00127 
00128     t.start();
00129     while (t.read_ms() < ms && !is_rdm_received) {
00130         pollRdm();
00131     }
00132     t.stop();
00133     pollRdm();
00134 }
00135 
00136 int DMX::sendRdmDiscResponse (struct RDM_DATA *rdm) {
00137     int crc;
00138     unsigned char data[40];
00139 
00140     data[0]  = 0xFE;
00141     data[1]  = 0xFE;
00142     data[2]  = 0xFE;
00143     data[3]  = 0xFE;
00144     data[4]  = 0xFE;
00145     data[5]  = 0xFE;
00146     data[6]  = 0xFE;
00147     data[7]  = 0xAA;
00148     data[8]  = rdm_uid[0] | 0xAA;
00149     data[9]  = rdm_uid[0] | 0x55;
00150     data[10] = rdm_uid[1] | 0xAA;
00151     data[11] = rdm_uid[1] | 0x55;
00152     data[12] = rdm_uid[2] | 0xAA;
00153     data[13] = rdm_uid[2] | 0x55;
00154     data[14] = rdm_uid[3] | 0xAA;
00155     data[15] = rdm_uid[3] | 0x55;
00156     data[16] = rdm_uid[4] | 0xAA;
00157     data[17] = rdm_uid[4] | 0x55;
00158     data[18] = rdm_uid[5] | 0xAA;
00159     data[19] = rdm_uid[5] | 0x55;
00160     crc = calcCrc(&data[8], 12, 0);
00161     data[20] = ((crc >> 8) & 0xFF) | 0xAA;
00162     data[21] = ((crc >> 8) & 0xFF) | 0x55;
00163     data[22] = (crc & 0xFF) | 0xAA;
00164     data[23] = (crc & 0xFF) | 0x55;
00165 
00166     wait_us(RDM_TIME_DELAY);
00167 /*
00168     do {
00169         wait_us(RDM_TIME_DELAY * (rand() / (RAND_MAX / 10)));
00170     } while (mode_rx != DMX_MODE_BEGIN);
00171 */
00172     if (_xmit) _xmit->write(XMIT_TX);
00173     wait_us(10);
00174     for (int i = 0; i < 24; i ++) {
00175         _dmx.putc(data[i]);
00176     }
00177     while (!(_uart->LSR & (1<<6))); // TEMT
00178     if (_xmit) _xmit->write(XMIT_RX);
00179 
00180     return 0;
00181 }
00182 
00183 int DMX::sendRdmMsg (struct RDM_DATA *rdm, int CmdClass, unsigned char *data, int len) {
00184     int crc;
00185     struct RDM_DATA *rdm_msg = (struct RDM_DATA *)data_rdm;
00186 
00187     while (mode_rdm);
00188     rdm_msgcount ++;
00189     rdm_msg->SubStartCode   = E120_SC_SUB_MESSAGE;
00190     rdm_msg->Length         = 24 + len;
00191     memcpy(rdm_msg->DestID, rdm->SourceID, 6);
00192     memcpy(rdm_msg->SourceID, rdm_uid, 6);
00193     rdm_msg->TransactionNo  = rdm->TransactionNo;
00194     rdm_msg->ResponseType   = E120_RESPONSE_TYPE_ACK;
00195     rdm_msg->MessageCount   = rdm_msgcount;
00196     rdm_msg->SubDev         = 0;
00197     rdm_msg->CmdClass       = CmdClass;
00198     rdm_msg->Parameter      = rdm->Parameter;
00199     rdm_msg->DataLength     = len;
00200     if (data && len) {
00201         memcpy(rdm_msg->Data, data, len);
00202     }
00203     crc = calcCrc((unsigned char *)rdm_msg, rdm_msg->Length - 1);
00204     rdm_msg->Data[len]      = (crc >> 8) & 0xFF;
00205     rdm_msg->Data[len + 1]  = crc & 0xFF;
00206 
00207     rdmStart();
00208     return 0;
00209 }
00210 
00211 int DMX::sendRdmMsg (unsigned char *dest, int CmdClass, int Parameter, int Type, unsigned char *data, int len, int block) {
00212     int crc;
00213     struct RDM_DATA *rdm_msg = (struct RDM_DATA *)data_rdm;
00214 
00215     while (mode_rdm);
00216     rdm_transno ++;
00217     rdm_msgcount ++;
00218     rdm_msg->SubStartCode   = E120_SC_SUB_MESSAGE;
00219     rdm_msg->Length         = 24 + len;
00220     memcpy(rdm_msg->DestID, dest, 6);
00221     memcpy(rdm_msg->SourceID, rdm_uid, 6);
00222     rdm_msg->TransactionNo  = rdm_transno;
00223     rdm_msg->ResponseType   = Type;
00224     rdm_msg->MessageCount   = rdm_msgcount;
00225     rdm_msg->SubDev         = 0;
00226     rdm_msg->CmdClass       = CmdClass;
00227     rdm_msg->Parameter      = htons(Parameter);
00228     rdm_msg->DataLength     = len;
00229     if (data && len) {
00230         memcpy(rdm_msg->Data, data, len);
00231     }
00232     crc = calcCrc((unsigned char *)rdm_msg, rdm_msg->Length - 1);
00233     rdm_msg->Data[len]      = (crc >> 8) & 0xFF;
00234     rdm_msg->Data[len + 1]  = crc & 0xFF;
00235 
00236     rdmStart(block);
00237     return 0;
00238 }
00239 
00240 int DMX::sendRdmDiscMuteResponse (struct RDM_DATA *rdm) {
00241     unsigned char data[2] = {0, 0};
00242 
00243     return sendRdmMsg(rdm, E120_DISCOVERY_COMMAND_RESPONSE, data, 2);
00244 }
00245 
00246 void DMX::attachRdmCallback (void (*handler)(struct RDM_DATA *), char *uid) {
00247 
00248     cb_RdmParser = handler;
00249     memcpy(rdm_uid, uid, 6);
00250 }
00251 
00252 void DMX::int_rdm () {
00253     int flg, dat;
00254 
00255     flg = _uart->LSR;
00256     dat = _dmx.getc();
00257 
00258     if (flg & ((1 << 7)|(1 << 3)|(1 << 4))) {
00259         // Conflict
00260         addr_rx = -1;
00261         return;
00262     }
00263 
00264     if (addr_rx >= 0 && addr_rx < DMX_SIZE) {
00265         data_rx[addr_rx] = dat;
00266         addr_rx ++;
00267     }
00268 }
00269 
00270 int DMX::sendRdmDiscMute (unsigned char *dest, int mute) {
00271 
00272     while (mode_rdm);
00273 
00274     int param = mute ? E120_DISC_MUTE : E120_DISC_UN_MUTE;
00275     sendRdmMsg(dest, E120_DISCOVERY_COMMAND, param ,E120_RESPONSE_TYPE_ACK_TIMER, NULL, 0, 1);
00276     rdmWaitResponse(100);
00277     return 0;
00278 }
00279 
00280 int DMX::sendRdmDiscovery (uint64_t uid_begin, uint64_t uid_end) {
00281     int crc;
00282     unsigned char data[12];
00283 
00284     while (mode_rdm);
00285 
00286     data[ 0] = (uid_begin >> 40) & 0xff;
00287     data[ 1] = (uid_begin >> 32) & 0xff;
00288     data[ 2] = (uid_begin >> 24) & 0xff;
00289     data[ 3] = (uid_begin >> 16) & 0xff;
00290     data[ 4] = (uid_begin >> 8) & 0xff;
00291     data[ 5] = uid_begin & 0xff;
00292     data[ 6] = (uid_end >> 40) & 0xff;
00293     data[ 7] = (uid_end >> 32) & 0xff;
00294     data[ 8] = (uid_end >> 24) & 0xff;
00295     data[ 9] = (uid_end >> 16) & 0xff;
00296     data[10] = (uid_end >> 8) & 0xff;
00297     data[11] = uid_end & 0xff;
00298 
00299     _dmx.attach(this, &DMX::int_rdm, Serial::RxIrq);
00300     addr_rx = 0;
00301     sendRdmMsg(uid_broadcast, E120_DISCOVERY_COMMAND, E120_DISC_UNIQUE_BRANCH ,E120_RESPONSE_TYPE_ACK_TIMER, data, 12, 1);
00302     rdmWaitResponse(100);
00303     _dmx.attach(this, &DMX::int_rx, Serial::RxIrq);
00304 
00305     if (addr_rx >= 24) {
00306         if (data_rx[0] == 0xfe && data_rx[7] == 0xaa) {
00307             crc = calcCrc(&data_rx[8], 12, 0);
00308             if (data_rx[20] == (((crc >> 8) & 0xFF) | 0xAA) &&
00309               data_rx[21] == (((crc >> 8) & 0xFF) | 0x55) &&
00310               data_rx[22] == ((crc & 0xFF) | 0xAA) && data_rx[23] == ((crc & 0xFF) | 0x55)) {
00311                 found_uid[0] = (data_rx[ 8] & 0x55) | (data_rx[ 9] & 0xAA);
00312                 found_uid[1] = (data_rx[10] & 0x55) | (data_rx[11] & 0xAA);
00313                 found_uid[2] = (data_rx[12] & 0x55) | (data_rx[13] & 0xAA);
00314                 found_uid[3] = (data_rx[14] & 0x55) | (data_rx[15] & 0xAA);
00315                 found_uid[4] = (data_rx[16] & 0x55) | (data_rx[17] & 0xAA);
00316                 found_uid[5] = (data_rx[18] & 0x55) | (data_rx[19] & 0xAA);
00317                 return 1;
00318             }
00319             return -1;
00320         }
00321         return -1;
00322     } else
00323     if (addr_rx) {
00324         return -1;
00325     }
00326 
00327     return 0;
00328 }
00329 
00330 int DMX::rdmDiscoverySub (uint64_t uid_begin, uint64_t uid_end, int ttl) {
00331     int r;
00332     uint64_t uid_mid;
00333 
00334 //    printf("rdmDiscoverySub %04x %08x - %04x %08x\r\n", (int)(uid_begin>>32), (int)uid_begin, (int)(uid_end>>32), (int)uid_end);
00335     if (!ttl) return 0;
00336     ttl --;
00337 
00338     r = sendRdmDiscovery(uid_begin, uid_end);
00339     if (uid_begin >= uid_end) {
00340         if (r > 0) {
00341             sendRdmDiscMute(found_uid, 1);
00342         }
00343     } else {
00344         if (r > 0) {
00345             sendRdmDiscMute(found_uid, 1);
00346         }
00347         if (r) {
00348             uid_mid = (uid_begin + uid_end) / 2;
00349             r = rdmDiscoverySub(uid_begin, uid_mid, ttl);
00350             r |= rdmDiscoverySub(uid_mid + 1, uid_end, ttl);
00351         }
00352     }
00353     return r;
00354 }
00355 
00356 int DMX::rdmDiscovery (unsigned char *buf, int size) {
00357 
00358     buf_uid_count = 0;
00359     buf_uid_size = size;
00360     buf_uid = buf;
00361     sendRdmDiscMute(uid_broadcast, 0);
00362     rdmDiscoverySub(0x000000000000, 0xfffffffffffe, 10);
00363     return buf_uid_count;
00364 }
00365 
00366 #endif