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

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

DMX512 send/recv library

DMX512 is protocol for lighting.

調光プロトコル DMX512 を送受信するライブラリです。

see: http://mbed.org/users/okini3939/notebook/dmx512/

LPC1114 support is thanks to Stanly Chen

Revision:
19:ae8fd2ba7c53
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/RDM.cpp	Fri Oct 20 00:44:06 2017 +0000
@@ -0,0 +1,366 @@
+/*
+ * DMX512, RDM send/recv library
+ * Copyright (c) 2017 Hiroshi Suga
+ * Released under the MIT License: http://mbed.org/license/mit
+ */
+
+/** @file
+ * @brief DMX512 send/recv
+ */
+
+#include "mbed.h"
+#include "DMX.h"
+
+#ifdef RDM_ENABLE
+
+#define htons(n) __REV16(n)
+#define ntohs(n) __REV16(n)
+#define htonl(n) __REV(n)
+#define ntohl(n) __REV(n)
+
+static unsigned char uid_broadcast[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+
+void DMX::pollRdm () {
+    int i, len, crc, forMe, forGrp, forAll;
+    struct RDM_DATA *rdm = (struct RDM_DATA *)data_rx;
+
+    if (!is_rdm_received) return;
+    is_rdm_received = 0;
+    if (rdm->Length < 24) return;
+
+    len = rdm->DataLength;
+    crc = (rdm->Data[len] << 8) | rdm->Data[len + 1];
+    if (calcCrc(data_rx, rdm->Length - 1) != crc) return;
+
+    forMe  = memcmp(rdm_uid, rdm->DestID, 6) == 0 ? 1 : 0;
+    forGrp = (rdm_uid[0] == rdm->DestID[0] && rdm_uid[1] == rdm->DestID[1] && memcmp(&rdm_uid[2], uid_broadcast, 4) == 0) ? 1 : 0;
+    forAll = memcmp(rdm_uid, uid_broadcast, 6) == 0 ? 1 : 0;
+
+    switch (rdm->CmdClass) {
+    case E120_DISCOVERY_COMMAND:
+        switch (ntohs(rdm->Parameter)) {
+        case E120_DISC_UNIQUE_BRANCH:
+            if (rdm->DataLength == 12 && !rdm_mute) {
+                if (memcmp(rdm_uid, &rdm->Data[0], 6) >= 0 && memcmp(rdm_uid, &rdm->Data[6], 6) <= 0) {
+                    sendRdmDiscResponse(rdm);
+                }
+            }
+            break;
+
+        case E120_DISC_MUTE:
+        case E120_DISC_UN_MUTE:
+            if (forMe || forGrp || forAll) {
+                if (rdm->CmdClass == E120_DISC_MUTE) {
+                    rdm_mute = 1;
+                } else {
+                    rdm_mute = 0;
+                }
+                if (forMe) sendRdmDiscMuteResponse(rdm);
+            }
+            break;
+
+        }
+        break;
+
+    case E120_DISCOVERY_COMMAND_RESPONSE:
+        switch (ntohs(rdm->Parameter)) {
+        case E120_DISC_MUTE:
+        case E120_DISC_UN_MUTE:
+            if (forMe && memcmp(found_uid, rdm->SourceID, 6) == 0) {
+                if (buf_uid_size && buf_uid_count < buf_uid_size) {
+                    memcpy(&buf_uid[6 * buf_uid_count], rdm->SourceID, 6);
+                    buf_uid_count ++;
+                }
+            }
+        }
+        break;
+
+    case E120_GET_COMMAND:
+    case E120_SET_COMMAND:
+        if ((forMe || forGrp || forAll) && cb_RdmParser) {
+            cb_RdmParser(rdm);
+        }
+        break;
+
+    case E120_GET_COMMAND_RESPONSE:
+    case E120_SET_COMMAND_RESPONSE:
+        if ((forMe || forGrp || forAll) && cb_RdmParser) {
+            cb_RdmParser(rdm);
+        }
+        break;
+    }
+}
+
+int DMX::calcCrc (unsigned char *buf, int len, int offset) {
+    int i, crc = offset;
+
+    for (i = 0; i < len; i ++) {
+        crc += buf[i];
+    }
+    return crc;
+}
+
+void DMX::rdmStart (int block) {
+    Timer t;
+
+    t.start();
+    while (mode_rx != DMX_MODE_BEGIN && t.read_ms() < 100) {
+        pollRdm();
+    }
+    t.stop();
+
+    mode_rdm = 1;
+    mode_rx = DMX_MODE_BEGIN;
+    mode_tx = DMX_MODE_BEGIN;
+    is_sent = 0;
+    is_received = 0;
+    is_rdm_received = 0;
+    timeout01.attach_us(this, &DMX::int_timer, RDM_TIME_DELAY);
+
+    if (block) {
+        while (mode_rdm);
+    }
+}
+
+void DMX::rdmWaitResponse (int ms) {
+    Timer t;
+
+    t.start();
+    while (t.read_ms() < ms && !is_rdm_received) {
+        pollRdm();
+    }
+    t.stop();
+    pollRdm();
+}
+
+int DMX::sendRdmDiscResponse (struct RDM_DATA *rdm) {
+    int crc;
+    unsigned char data[40];
+
+    data[0]  = 0xFE;
+    data[1]  = 0xFE;
+    data[2]  = 0xFE;
+    data[3]  = 0xFE;
+    data[4]  = 0xFE;
+    data[5]  = 0xFE;
+    data[6]  = 0xFE;
+    data[7]  = 0xAA;
+    data[8]  = rdm_uid[0] | 0xAA;
+    data[9]  = rdm_uid[0] | 0x55;
+    data[10] = rdm_uid[1] | 0xAA;
+    data[11] = rdm_uid[1] | 0x55;
+    data[12] = rdm_uid[2] | 0xAA;
+    data[13] = rdm_uid[2] | 0x55;
+    data[14] = rdm_uid[3] | 0xAA;
+    data[15] = rdm_uid[3] | 0x55;
+    data[16] = rdm_uid[4] | 0xAA;
+    data[17] = rdm_uid[4] | 0x55;
+    data[18] = rdm_uid[5] | 0xAA;
+    data[19] = rdm_uid[5] | 0x55;
+    crc = calcCrc(&data[8], 12, 0);
+    data[20] = ((crc >> 8) & 0xFF) | 0xAA;
+    data[21] = ((crc >> 8) & 0xFF) | 0x55;
+    data[22] = (crc & 0xFF) | 0xAA;
+    data[23] = (crc & 0xFF) | 0x55;
+
+    wait_us(RDM_TIME_DELAY);
+/*
+    do {
+        wait_us(RDM_TIME_DELAY * (rand() / (RAND_MAX / 10)));
+    } while (mode_rx != DMX_MODE_BEGIN);
+*/
+    if (_xmit) _xmit->write(XMIT_TX);
+    wait_us(10);
+    for (int i = 0; i < 24; i ++) {
+        _dmx.putc(data[i]);
+    }
+    while (!(_uart->LSR & (1<<6))); // TEMT
+    if (_xmit) _xmit->write(XMIT_RX);
+
+    return 0;
+}
+
+int DMX::sendRdmMsg (struct RDM_DATA *rdm, int CmdClass, unsigned char *data, int len) {
+    int crc;
+    struct RDM_DATA *rdm_msg = (struct RDM_DATA *)data_rdm;
+
+    while (mode_rdm);
+    rdm_msgcount ++;
+    rdm_msg->SubStartCode   = E120_SC_SUB_MESSAGE;
+    rdm_msg->Length         = 24 + len;
+    memcpy(rdm_msg->DestID, rdm->SourceID, 6);
+    memcpy(rdm_msg->SourceID, rdm_uid, 6);
+    rdm_msg->TransactionNo  = rdm->TransactionNo;
+    rdm_msg->ResponseType   = E120_RESPONSE_TYPE_ACK;
+    rdm_msg->MessageCount   = rdm_msgcount;
+    rdm_msg->SubDev         = 0;
+    rdm_msg->CmdClass       = CmdClass;
+    rdm_msg->Parameter      = rdm->Parameter;
+    rdm_msg->DataLength     = len;
+    if (data && len) {
+        memcpy(rdm_msg->Data, data, len);
+    }
+    crc = calcCrc((unsigned char *)rdm_msg, rdm_msg->Length - 1);
+    rdm_msg->Data[len]      = (crc >> 8) & 0xFF;
+    rdm_msg->Data[len + 1]  = crc & 0xFF;
+
+    rdmStart();
+    return 0;
+}
+
+int DMX::sendRdmMsg (unsigned char *dest, int CmdClass, int Parameter, int Type, unsigned char *data, int len, int block) {
+    int crc;
+    struct RDM_DATA *rdm_msg = (struct RDM_DATA *)data_rdm;
+
+    while (mode_rdm);
+    rdm_transno ++;
+    rdm_msgcount ++;
+    rdm_msg->SubStartCode   = E120_SC_SUB_MESSAGE;
+    rdm_msg->Length         = 24 + len;
+    memcpy(rdm_msg->DestID, dest, 6);
+    memcpy(rdm_msg->SourceID, rdm_uid, 6);
+    rdm_msg->TransactionNo  = rdm_transno;
+    rdm_msg->ResponseType   = Type;
+    rdm_msg->MessageCount   = rdm_msgcount;
+    rdm_msg->SubDev         = 0;
+    rdm_msg->CmdClass       = CmdClass;
+    rdm_msg->Parameter      = htons(Parameter);
+    rdm_msg->DataLength     = len;
+    if (data && len) {
+        memcpy(rdm_msg->Data, data, len);
+    }
+    crc = calcCrc((unsigned char *)rdm_msg, rdm_msg->Length - 1);
+    rdm_msg->Data[len]      = (crc >> 8) & 0xFF;
+    rdm_msg->Data[len + 1]  = crc & 0xFF;
+
+    rdmStart(block);
+    return 0;
+}
+
+int DMX::sendRdmDiscMuteResponse (struct RDM_DATA *rdm) {
+    unsigned char data[2] = {0, 0};
+
+    return sendRdmMsg(rdm, E120_DISCOVERY_COMMAND_RESPONSE, data, 2);
+}
+
+void DMX::attachRdmCallback (void (*handler)(struct RDM_DATA *), char *uid) {
+
+    cb_RdmParser = handler;
+    memcpy(rdm_uid, uid, 6);
+}
+
+void DMX::int_rdm () {
+    int flg, dat;
+
+    flg = _uart->LSR;
+    dat = _dmx.getc();
+
+    if (flg & ((1 << 7)|(1 << 3)|(1 << 4))) {
+        // Conflict
+        addr_rx = -1;
+        return;
+    }
+
+    if (addr_rx >= 0 && addr_rx < DMX_SIZE) {
+        data_rx[addr_rx] = dat;
+        addr_rx ++;
+    }
+}
+
+int DMX::sendRdmDiscMute (unsigned char *dest, int mute) {
+
+    while (mode_rdm);
+
+    int param = mute ? E120_DISC_MUTE : E120_DISC_UN_MUTE;
+    sendRdmMsg(dest, E120_DISCOVERY_COMMAND, param ,E120_RESPONSE_TYPE_ACK_TIMER, NULL, 0, 1);
+    rdmWaitResponse(100);
+    return 0;
+}
+
+int DMX::sendRdmDiscovery (uint64_t uid_begin, uint64_t uid_end) {
+    int crc;
+    unsigned char data[12];
+
+    while (mode_rdm);
+
+    data[ 0] = (uid_begin >> 40) & 0xff;
+    data[ 1] = (uid_begin >> 32) & 0xff;
+    data[ 2] = (uid_begin >> 24) & 0xff;
+    data[ 3] = (uid_begin >> 16) & 0xff;
+    data[ 4] = (uid_begin >> 8) & 0xff;
+    data[ 5] = uid_begin & 0xff;
+    data[ 6] = (uid_end >> 40) & 0xff;
+    data[ 7] = (uid_end >> 32) & 0xff;
+    data[ 8] = (uid_end >> 24) & 0xff;
+    data[ 9] = (uid_end >> 16) & 0xff;
+    data[10] = (uid_end >> 8) & 0xff;
+    data[11] = uid_end & 0xff;
+
+    _dmx.attach(this, &DMX::int_rdm, Serial::RxIrq);
+    addr_rx = 0;
+    sendRdmMsg(uid_broadcast, E120_DISCOVERY_COMMAND, E120_DISC_UNIQUE_BRANCH ,E120_RESPONSE_TYPE_ACK_TIMER, data, 12, 1);
+    rdmWaitResponse(100);
+    _dmx.attach(this, &DMX::int_rx, Serial::RxIrq);
+
+    if (addr_rx >= 24) {
+        if (data_rx[0] == 0xfe && data_rx[7] == 0xaa) {
+            crc = calcCrc(&data_rx[8], 12, 0);
+            if (data_rx[20] == (((crc >> 8) & 0xFF) | 0xAA) &&
+              data_rx[21] == (((crc >> 8) & 0xFF) | 0x55) &&
+              data_rx[22] == ((crc & 0xFF) | 0xAA) && data_rx[23] == ((crc & 0xFF) | 0x55)) {
+                found_uid[0] = (data_rx[ 8] & 0x55) | (data_rx[ 9] & 0xAA);
+                found_uid[1] = (data_rx[10] & 0x55) | (data_rx[11] & 0xAA);
+                found_uid[2] = (data_rx[12] & 0x55) | (data_rx[13] & 0xAA);
+                found_uid[3] = (data_rx[14] & 0x55) | (data_rx[15] & 0xAA);
+                found_uid[4] = (data_rx[16] & 0x55) | (data_rx[17] & 0xAA);
+                found_uid[5] = (data_rx[18] & 0x55) | (data_rx[19] & 0xAA);
+                return 1;
+            }
+            return -1;
+        }
+        return -1;
+    } else
+    if (addr_rx) {
+        return -1;
+    }
+
+    return 0;
+}
+
+int DMX::rdmDiscoverySub (uint64_t uid_begin, uint64_t uid_end, int ttl) {
+    int r;
+    uint64_t uid_mid;
+
+//    printf("rdmDiscoverySub %04x %08x - %04x %08x\r\n", (int)(uid_begin>>32), (int)uid_begin, (int)(uid_end>>32), (int)uid_end);
+    if (!ttl) return 0;
+    ttl --;
+
+    r = sendRdmDiscovery(uid_begin, uid_end);
+    if (uid_begin >= uid_end) {
+        if (r > 0) {
+            sendRdmDiscMute(found_uid, 1);
+        }
+    } else {
+        if (r > 0) {
+            sendRdmDiscMute(found_uid, 1);
+        }
+        if (r) {
+            uid_mid = (uid_begin + uid_end) / 2;
+            r = rdmDiscoverySub(uid_begin, uid_mid, ttl);
+            r |= rdmDiscoverySub(uid_mid + 1, uid_end, ttl);
+        }
+    }
+    return r;
+}
+
+int DMX::rdmDiscovery (unsigned char *buf, int size) {
+
+    buf_uid_count = 0;
+    buf_uid_size = size;
+    buf_uid = buf;
+    sendRdmDiscMute(uid_broadcast, 0);
+    rdmDiscoverySub(0x000000000000, 0xfffffffffffe, 10);
+    return buf_uid_count;
+}
+
+#endif