Skip to content

Commit ff1bc22

Browse files
committed
Add DMX Receiver address and channel width functionality
1 parent 0fb4504 commit ff1bc22

File tree

2 files changed

+61
-10
lines changed

2 files changed

+61
-10
lines changed

src/DMXSerial.cpp

+47-10
Original file line numberDiff line numberDiff line change
@@ -104,15 +104,18 @@ int _dmxModePin; // pin used for I/O direction.
104104

105105
uint8_t _dmxRecvState; // Current State of receiving DMX Bytes
106106
int _dmxChannel; // the next channel byte to be sent.
107+
uint16_t _dmxRecvAddress = 0; // the address to which the devic should listen
108+
uint16_t _dmxReceivePos = 0; // the DMX receiver channel count
107109

108-
volatile int _dmxMaxChannel = 32; // the last channel used for sending (1..512).
110+
volatile int _dmxMaxChannel = 0; // the last channel used for sending (1..512).
109111
volatile unsigned long _dmxLastPacket = 0; // the last time (using the millis function) a packet was received.
110112

111113
bool _dmxUpdated = true; // is set to true when new data arrived.
114+
volatile unsigned long _dmxLastUpdate = 0; // the last time (using the millis function) a packet updated a channel.
112115

113116
// Array of DMX values (raw).
114117
// Entry 0 will never be used for DMX data but will store the startbyte (0 for DMX mode).
115-
uint8_t _dmxData[DMXSERIAL_MAX + 1];
118+
uint8_t* _dmxData;
116119

117120
// This pointer will point to the next byte in _dmxData;
118121
uint8_t *_dmxDataPtr;
@@ -137,19 +140,26 @@ void DMXSerialClass::init(int mode)
137140
void DMXSerialClass::init(int mode, int dmxModePin)
138141
{
139142
// initialize global variables
143+
144+
if(!_dmxRecvAddress) _dmxRecvAddress = 1;
145+
if(!_dmxMaxChannel) _dmxMaxChannel = DMXSERIAL_MAX; // The default in Receiver mode is reading all possible 512 channels.
146+
147+
_dmxData = malloc((min(_dmxMaxChannel, DMXSERIAL_MAX) + 1) * sizeof(uint8_t));
148+
140149
_dmxMode = DMXNone;
141150
_dmxModePin = dmxModePin;
142151
_dmxRecvState = STARTUP; // initial state
143152
_dmxChannel = 0;
144153
_dmxDataPtr = _dmxData;
145154
_dmxLastPacket = millis(); // remember current (relative) time in msecs.
155+
_dmxLastUpdate = _dmxLastPacket;
156+
_dmxReceivePos = 0;
146157

147-
_dmxMaxChannel = DMXSERIAL_MAX; // The default in Receiver mode is reading all possible 512 channels.
148158
_dmxDataLastPtr = _dmxData + _dmxMaxChannel;
149159

150160
// initialize the DMX buffer
151161
// memset(_dmxData, 0, sizeof(_dmxData));
152-
for (int n = 0; n < DMXSERIAL_MAX + 1; n++)
162+
for (int n = 0; n < _dmxMaxChannel + 1; n++)
153163
_dmxData[n] = 0;
154164

155165
// now start
@@ -297,9 +307,30 @@ void DMXSerialClass::term(void)
297307
{
298308
// Disable all USART Features, including Interrupts
299309
_DMX_setMode(DMXUARTMode::OFF);
310+
free(_dmxData);
300311
} // term()
301312

302313

314+
// Calculate how long it has been since a channel was updated
315+
unsigned long DMXSerialClass::noUpdateSince(void)
316+
{
317+
unsigned long now = millis();
318+
return (now - _dmxLastUpdate);
319+
} //noUpdateSince()
320+
321+
322+
// Set the DMX address of the listening device
323+
void DMXSerialClass::setAddress(uint16_t address)
324+
{
325+
if(address < 1){
326+
_dmxRecvAddress = 1;
327+
} else if(address >= DMXSERIAL_MAX){
328+
_dmxRecvAddress = DMXSERIAL_MAX;
329+
} else {
330+
_dmxRecvAddress = address;
331+
}
332+
}
333+
303334
// ----- internal functions and interrupt implementations -----
304335

305336

@@ -342,6 +373,7 @@ void _DMXReceived(uint8_t data, uint8_t frameerror)
342373
// break condition detected.
343374
_dmxRecvState = BREAK;
344375
_dmxDataPtr = _dmxData;
376+
_dmxReceivePos = 0;
345377

346378
} else if (DmxState == BREAK) {
347379
// first byte after a break was read.
@@ -350,6 +382,7 @@ void _DMXReceived(uint8_t data, uint8_t frameerror)
350382
_dmxRecvState = DATA;
351383
_dmxLastPacket = millis(); // remember current (relative) time in msecs.
352384
_dmxDataPtr++; // start saving data with channel # 1
385+
_dmxReceivePos++;
353386

354387
} else {
355388
// This might be a RDM or customer DMX command -> not implemented so wait for next BREAK !
@@ -358,12 +391,16 @@ void _DMXReceived(uint8_t data, uint8_t frameerror)
358391

359392
} else if (DmxState == DATA) {
360393
// check for new data
361-
if (*_dmxDataPtr != data) {
362-
_dmxUpdated = true;
363-
// store received data into dmx data buffer.
364-
*_dmxDataPtr = data;
365-
} // if
366-
_dmxDataPtr++;
394+
if(_dmxReceivePos >= _dmxRecvAddress && _dmxReceivePos < (_dmxRecvAddress+_dmxMaxChannel)){
395+
if (*_dmxDataPtr != data) {
396+
_dmxUpdated = true;
397+
_dmxLastUpdate = millis();
398+
// store received data into dmx data buffer.
399+
*_dmxDataPtr = data;
400+
} // if
401+
_dmxDataPtr++;
402+
}
403+
_dmxReceivePos++;
367404

368405
if (_dmxDataPtr > _dmxDataLastPtr) {
369406
// all channels received.

src/DMXSerial.h

+14
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,20 @@ class DMXSerialClass
163163
* @return false after timeout no package was received.
164164
*/
165165
bool receive(uint8_t wait);
166+
167+
/**
168+
* @brief Return the duration since the last time a channel had updated data
169+
* This function will report and and all channel updates, so may not be useful for busy networks
170+
* @return long milliseconds since an update was detected
171+
*/
172+
unsigned long noUpdateSince();
173+
174+
/**
175+
* @brief Specifies the address to which the receiver should listen
176+
* @param address The DMX address of the receiver
177+
* @return void
178+
*/
179+
void setAddress(uint16_t address);
166180

167181
/**
168182
* @brief Terminate the current operation mode.

0 commit comments

Comments
 (0)