Skip to content

Commit

Permalink
Add DMX Receiver address and channel width functionality
Browse files Browse the repository at this point in the history
  • Loading branch information
aidancrowther committed Oct 4, 2024
1 parent 0fb4504 commit ff1bc22
Show file tree
Hide file tree
Showing 2 changed files with 61 additions and 10 deletions.
57 changes: 47 additions & 10 deletions src/DMXSerial.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -104,15 +104,18 @@ int _dmxModePin; // pin used for I/O direction.

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

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

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

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

// This pointer will point to the next byte in _dmxData;
uint8_t *_dmxDataPtr;
Expand All @@ -137,19 +140,26 @@ void DMXSerialClass::init(int mode)
void DMXSerialClass::init(int mode, int dmxModePin)
{
// initialize global variables

if(!_dmxRecvAddress) _dmxRecvAddress = 1;
if(!_dmxMaxChannel) _dmxMaxChannel = DMXSERIAL_MAX; // The default in Receiver mode is reading all possible 512 channels.

_dmxData = malloc((min(_dmxMaxChannel, DMXSERIAL_MAX) + 1) * sizeof(uint8_t));

_dmxMode = DMXNone;
_dmxModePin = dmxModePin;
_dmxRecvState = STARTUP; // initial state
_dmxChannel = 0;
_dmxDataPtr = _dmxData;
_dmxLastPacket = millis(); // remember current (relative) time in msecs.
_dmxLastUpdate = _dmxLastPacket;
_dmxReceivePos = 0;

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

// initialize the DMX buffer
// memset(_dmxData, 0, sizeof(_dmxData));
for (int n = 0; n < DMXSERIAL_MAX + 1; n++)
for (int n = 0; n < _dmxMaxChannel + 1; n++)
_dmxData[n] = 0;

// now start
Expand Down Expand Up @@ -297,9 +307,30 @@ void DMXSerialClass::term(void)
{
// Disable all USART Features, including Interrupts
_DMX_setMode(DMXUARTMode::OFF);
free(_dmxData);
} // term()


// Calculate how long it has been since a channel was updated
unsigned long DMXSerialClass::noUpdateSince(void)
{
unsigned long now = millis();
return (now - _dmxLastUpdate);
} //noUpdateSince()


// Set the DMX address of the listening device
void DMXSerialClass::setAddress(uint16_t address)
{
if(address < 1){
_dmxRecvAddress = 1;
} else if(address >= DMXSERIAL_MAX){
_dmxRecvAddress = DMXSERIAL_MAX;
} else {
_dmxRecvAddress = address;
}
}

// ----- internal functions and interrupt implementations -----


Expand Down Expand Up @@ -342,6 +373,7 @@ void _DMXReceived(uint8_t data, uint8_t frameerror)
// break condition detected.
_dmxRecvState = BREAK;
_dmxDataPtr = _dmxData;
_dmxReceivePos = 0;

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

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

} else if (DmxState == DATA) {
// check for new data
if (*_dmxDataPtr != data) {
_dmxUpdated = true;
// store received data into dmx data buffer.
*_dmxDataPtr = data;
} // if
_dmxDataPtr++;
if(_dmxReceivePos >= _dmxRecvAddress && _dmxReceivePos < (_dmxRecvAddress+_dmxMaxChannel)){
if (*_dmxDataPtr != data) {
_dmxUpdated = true;
_dmxLastUpdate = millis();
// store received data into dmx data buffer.
*_dmxDataPtr = data;
} // if
_dmxDataPtr++;
}
_dmxReceivePos++;

if (_dmxDataPtr > _dmxDataLastPtr) {
// all channels received.
Expand Down
14 changes: 14 additions & 0 deletions src/DMXSerial.h
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,20 @@ class DMXSerialClass
* @return false after timeout no package was received.
*/
bool receive(uint8_t wait);

/**
* @brief Return the duration since the last time a channel had updated data
* This function will report and and all channel updates, so may not be useful for busy networks
* @return long milliseconds since an update was detected
*/
unsigned long noUpdateSince();

/**
* @brief Specifies the address to which the receiver should listen
* @param address The DMX address of the receiver
* @return void
*/
void setAddress(uint16_t address);

/**
* @brief Terminate the current operation mode.
Expand Down

0 comments on commit ff1bc22

Please sign in to comment.