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
RDM.cpp
- Committer:
- okini3939
- Date:
- 2017-10-20
- Revision:
- 19:ae8fd2ba7c53
File content as of revision 19:ae8fd2ba7c53:
/* * 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