diff --git a/README.adoc b/README.adoc new file mode 100644 index 0000000..918db9a --- /dev/null +++ b/README.adoc @@ -0,0 +1,16 @@ += DMX Library for Arduino = + +This is a library for sending and receiving DMX codes using the Arduino plattform +or a ATmega (ATmega168, ATmega328 or similar) processor with a clock speed of 16 MHz. + +For more information about this library please visit us at +http://www.mathertel.de/Arduino/DMXSerial.aspx + +== License == + +Copyright (c) 2005-2015 by Matthias Hertel, http://www.mathertel.de/ + +The detailed Software License Agreement can be found at: +http://www.mathertel.de/License.aspx + + diff --git a/library.properties b/library.properties new file mode 100644 index 0000000..cee0174 --- /dev/null +++ b/library.properties @@ -0,0 +1,9 @@ +name=DMXSerial +version=1.2 +author=Matthias Hertel +maintainer=Matthias Hertel +sentence=Enables DMX communication using the built-in serial port. For Arduino boards UNO, Leonardo, Mega. +paragraph=With this library you ... +category=Communication +url=http://www.mathertel.de/Arduino/DMXSerial.aspx +architectures=* \ No newline at end of file diff --git a/DMXSerial.cpp b/src/DMXSerial.cpp similarity index 85% rename from DMXSerial.cpp rename to src/DMXSerial.cpp index b78ba7a..6da051a 100644 --- a/DMXSerial.cpp +++ b/src/DMXSerial.cpp @@ -1,5 +1,5 @@ // - - - - - -// DMXSerial - A hardware supported interface to DMX. +// DMXSerial - A Arduino library for sending and receiving DMX using the builtin serial hardware port. // DMXSerial.cpp: Library implementation file // // Copyright (c) 2011 by Matthias Hertel, http://www.mathertel.de @@ -192,13 +192,22 @@ DMXMode _dmxMode; // Mode of Operation uint8_t _dmxRecvState; // Current State of receiving DMX Bytes int _dmxChannel; // the next channel byte to be sent. -volatile int _dmxMaxChannel = 32; // the last channel used for sending (1..32). -volatile unsigned long _gotLastPacket = 0; // the last time (using the millis function) a packet was received. +volatile unsigned int _dmxMaxChannel = 32; // the last channel used for sending (1..32). +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. +dmxUpdateFunction _dmxOnUpdateFunc = NULL; // 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]; +// This pointer will point to the next byte in _dmxData; +uint8_t *_dmxDataPtr; + +// This pointer will point to the last byte in _dmxData; +uint8_t *_dmxDataLastPtr; + // Create a single class instance. Multiple class instances (multiple simultaneous DMX ports) are not supported. DMXSerialClass DMXSerial; @@ -224,9 +233,11 @@ void DMXSerialClass::init (int mode) _dmxMode = DMXNone; _dmxRecvState= IDLE; // initial state _dmxChannel = 0; - _gotLastPacket = millis(); // remember current (relative) time in msecs. + _dmxDataPtr = _dmxData; + _dmxLastPacket = millis(); // remember current (relative) time in msecs. // initialize the DMX buffer +// memset(_dmxData, 0, sizeof(_dmxData)); for (int n = 0; n < DMXSERIAL_MAX+1; n++) _dmxData[n] = 0; @@ -245,7 +256,7 @@ void DMXSerialClass::init (int mode) // Start sending a BREAK and loop (forever) in UDRE ISR _DMXSerialBaud(Calcprescale(BREAKSPEED), BREAKFORMAT); _DMXSerialWriteByte((uint8_t)0); - _dmxChannel = 0; + _dmxMaxChannel = 32; // The default in Controller mode is sending 32 channels. } else if (_dmxMode == DMXReceiver) { // Setup external mode signal @@ -257,6 +268,9 @@ void DMXSerialClass::init (int mode) UCSRnB = (1< DMXSERIAL_MAX) channel = DMXSERIAL_MAX; _dmxMaxChannel = channel; + _dmxDataLastPtr = _dmxData + channel; } // maxChannel @@ -301,20 +316,48 @@ void DMXSerialClass::write(int channel, uint8_t value) _dmxData[channel] = value; // Make sure we transmit enough channels for the ones used - if (channel > _dmxMaxChannel) + if (channel > _dmxMaxChannel) { _dmxMaxChannel = channel; + _dmxDataLastPtr = _dmxData + _dmxMaxChannel; + } // if } // write() +// Return the DMX buffer of unsave direct but faster access +uint8_t *DMXSerialClass::getBuffer() +{ + return(_dmxData); +} // getBuffer() + + // Calculate how long no data packet was received unsigned long DMXSerialClass::noDataSince() { unsigned long now = millis(); - return(now - _gotLastPacket); + return(now - _dmxLastPacket); } // noDataSince() -// Terminale operation +// save function for the onUpdate callback +void DMXSerialClass::attachOnUpdate(dmxUpdateFunction newFunction) +{ + _dmxOnUpdateFunc = newFunction; +} // attachOnUpdate + + + +bool DMXSerialClass::dataUpdated() +{ + return(_dmxUpdated); +} + +void DMXSerialClass::resetUpdated() +{ + _dmxUpdated = false; +} + + +// Terminate operation void DMXSerialClass::term(void) { // Disable all USART Features, including Interrupts @@ -352,8 +395,8 @@ void _DMXSerialWriteByte(uint8_t data) // In DMXReceiver mode when a byte was received it is stored to the dmxData buffer. ISR(USARTn_RX_vect) { - uint8_t USARTstate = UCSRnA; //get state before data! - uint8_t DmxByte = UDRn; //get data + uint8_t USARTstate = UCSRnA; // get state before data! + uint8_t DmxByte = UDRn; // get data uint8_t DmxState = _dmxRecvState; //just load once from SRAM to increase speed #ifdef SCOPEDEBUG @@ -362,29 +405,43 @@ ISR(USARTn_RX_vect) if (USARTstate & (1< not implemented so wait for next BREAK ! + // This might be a RDM or customer DMX command -> not implemented so wait for next BREAK ! _dmxRecvState = IDLE; } // if } else if (DmxState == DATA) { - _dmxData[_dmxChannel] = DmxByte; // store received data into dmx data buffer. - _dmxChannel++; - if (_dmxChannel > DMXSERIAL_MAX) { // all channels done. + // check for new data + if (*_dmxDataPtr != DmxByte) { + _dmxUpdated = true; + // store data + *_dmxDataPtr = DmxByte; //_dmxData[_dmxChannel] = DmxByte; store received data into dmx data buffer. + } // if + + if (_dmxDataPtr == _dmxDataLastPtr) { // all channels received. _dmxRecvState = IDLE; // wait for next break + + if ((_dmxUpdated) && (_dmxOnUpdateFunc)) + _dmxOnUpdateFunc(); + _dmxUpdated = false; } // if + // _dmxChannel++; + _dmxDataPtr++; } // if diff --git a/DMXSerial.h b/src/DMXSerial.h similarity index 63% rename from DMXSerial.h rename to src/DMXSerial.h index f14230a..e7be3f6 100644 --- a/DMXSerial.h +++ b/src/DMXSerial.h @@ -1,14 +1,20 @@ // - - - - - -// DMXSerial - A hardware supported interface to DMX. +// DMXSerial - A Arduino library for sending and receiving DMX using the builtin serial hardware port. // DMXSerial.h: Library header file // -// Copyright (c) 2011 by Matthias Hertel, http://www.mathertel.de +// Copyright (c) 2011-2014 by Matthias Hertel, http://www.mathertel.de // This work is licensed under a BSD style license. See http://www.mathertel.de/License.aspx // // Documentation and samples are available at http://www.mathertel.de/Arduino // 25.07.2011 creation of the DMXSerial library. // 01.12.2011 include file changed to work with the Arduino 1.0 environment // 10.05.2012 added method noDataSince to check how long no packet was received +// 12.07.2014 added update flag +// Until here the maxChannel feature only was used in DMXController mode. +// Now it enables triggering the onUpdate function in DMX receiver mode. +// +// See the WebSite for more information. +// // - - - - - #ifndef DmxSerial_h @@ -35,6 +41,10 @@ typedef enum { // ----- Library Class ----- +extern "C" { + typedef void (*dmxUpdateFunction)(void); +} + class DMXSerialClass { public: @@ -50,14 +60,29 @@ class DMXSerialClass // Write a new value of a channel. void write (int channel, uint8_t value); - // Calculate how long no data backet was received + uint8_t *getBuffer(); + + // Calculate how long no data packet was received unsigned long noDataSince(); + // attach function that will be called when new data was received. + void attachOnUpdate(dmxUpdateFunction newFunction); + + // Calculate how long no data backet was received + bool dataUpdated(); + void resetUpdated(); + // Terminate operation. void term (void); + + private: + // Not used. + // all private information is in the global _dmxXXX variables for speed and code size optimization. + // See DMXSerial.cpp. }; // Use the DMXSerial library through the DMXSerial object. +// There is only one DMX port supported and DMXSerial is a static object. extern DMXSerialClass DMXSerial; #endif