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
Diff: RDM.cpp
- 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