├── .gitignore ├── LICENSE ├── README.md ├── examples ├── ArtNetDMX │ ├── ArtNetDMX.ino │ ├── LXArtNetEthernet2.cpp │ ├── LXArtNetEthernet2.h │ └── LXDMXEthernet2.h ├── DMXSerialOutputTest │ └── DMXSerialOutputTest.ino ├── DMXTest │ └── DMXTest.ino └── DMXUSBSerial │ ├── DMXUSBSerial.ino │ ├── LXENTTECSerial.cpp │ └── LXENTTECSerial.h ├── extras └── doc │ ├── Classes │ └── LXUSARTDMX │ │ ├── index.html │ │ └── toc.html │ ├── index.html │ └── toc.html ├── keywords.txt ├── library.properties └── src ├── LXUSARTDMX.cpp └── LXUSARTDMX.h /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2016, Claude Heintz 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 10 | * Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | * Neither the name of LXUSARTDMX nor the names of its 15 | contributors may be used to endorse or promote products derived from 16 | this software without specific prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 22 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 25 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | 29 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # LXUSARTDMX 2 | DMX Driver for Arduino/AVR microcontrollers 3 | 4 | LXUSARTDMX is a driver for sending or receiving DMX using an AVR microcontroller's USART 5 | 6 | LXUSARTDMX output mode continuously sends DMX once its interrupts have been enabled using startOutput(). 7 | Use setSlot() to set the level value for a particular DMX dimmer/address/channel. 8 | 9 | LXUSARTDMX input mode continuously receives DMX once its interrupts have been enabled using startInput() 10 | Use getSlot() to read the level value for a particular DMX dimmer/address/channel. 11 | 12 | LXUSARTDMX is used with a single instance called LXSerialDMX -------------------------------------------------------------------------------- /examples/ArtNetDMX/ArtNetDMX.ino: -------------------------------------------------------------------------------- 1 | /* 2 | Art-Net DMX 3 | 4 | This sketch demonstrates converting Art-Net packets recieved using an 5 | Arduino Ethernet Shield to DMX output using a DMX shield. 6 | 7 | This sketch requires software such as LXConsole, QLC+ or DMXWorkshop 8 | that can send Art-Net packets to the Arduino. 9 | 10 | This sketch requires a DMXLibrary, 11 | LXUSARTDMX is a basic, easy to understand library. 12 | 13 | This example uses a simplified version of the LXDMXEthernet library: 14 | https://github.com/claudeheintz/LXDMXEthernet_library 15 | 16 | The sketch receives incoming UDP packets. If a received packet is 17 | Art-Net DMX output, it uses the microcontroller's USART to transmit 18 | the dmx levels as serial data. A DMX shield is used to convert 19 | this output to a differential signal (actual DMX) for controlling lighting. 20 | 21 | This is the circuit for a simple unisolated DMX Shield: 22 | 23 | Arduino SN 75176 A or MAX 481CPA 24 | pin _______________ 25 | | | 1 Vcc 8 |------ +5v 26 | V | | DMX Output 27 | | +----| 2 B 7 |---------------- Pin 2 28 | | | | | 29 | 2 |----------------------| 3 DE A 6 |---------------- Pin 3 30 | | | | 31 | TX |----------------------| 4 DI Gnd 5 |---+------------ Pin 1 32 | | | 33 | | GND 34 | 5 |--------[ 330 ohm ]---[ LED ]------------| 35 | 36 | 37 | 38 | Created January 7th, 2014 by Claude Heintz 39 | Current version 1.5 40 | (see bottom of file for revision history) 41 | 42 | Copyright 2014-2016 see LXUSARTDMX for license 43 | Art-Net(tm) Designed by and Copyright Artistic Licence Holdings Ltd. 44 | 45 | */ 46 | 47 | //*********************** includes *********************** 48 | 49 | // Choose which DMX library to include: 50 | // (comment out one or the other, do not include both) 51 | #include 52 | //#include 53 | 54 | #include 55 | // *** note if using original Arduino Ethernet Shield 56 | // this next 2 lines should read: 57 | // #include 58 | // #include 59 | // you must also make this change in LXArtNet.h 60 | #include 61 | #include 62 | #include "LXArtNetEthernet2.h" 63 | 64 | //*********************** defines *********************** 65 | 66 | /* 67 | Enter a MAC address and IP address for your controller below. 68 | The MAC address can be random as is the one shown, but should 69 | not match any other MAC address on your network. 70 | 71 | If BROADCAST_IP is not defined, ArtPollReply will be sent directly to server 72 | rather than being broadcast. (If a server' socket is bound to a specific network 73 | interface ip address, it will not receive broadcast packets.) 74 | */ 75 | 76 | #define MAC_ADDRESS 0xDD, 0x43, 0x34, 0x4C, 0x29, 0x7E 77 | #define IP_ADDRESS 192,168,1,140 78 | #define GATEWAY_IP 192,168,1,1 79 | #define SUBNET_MASK 255,255,255,0 80 | #define BROADCAST_IP 192,168,1,255 81 | 82 | // this sketch flashes an indicator led: 83 | #define MONITOR_PIN 5 84 | 85 | // the driver direction is controlled by: 86 | #define RXTX_PIN 2 87 | 88 | //the Ethernet Shield has an SD card that also communicates by SPI 89 | //set its select pin to output to be safe: 90 | #define SDSELECT_PIN 4 91 | 92 | 93 | //*********************** globals *********************** 94 | 95 | //network addresses 96 | byte mac[] = { MAC_ADDRESS }; 97 | IPAddress ip(IP_ADDRESS); 98 | IPAddress gateway(GATEWAY_IP); 99 | IPAddress subnet(SUBNET_MASK); 100 | 101 | #if defined( BROADCAST_IP ) 102 | IPAddress broadcast_ip( BROADCAST_IP); 103 | #else 104 | IPAddress broadcast_ip = INADDR_NONE; 105 | #endif 106 | 107 | // buffer 108 | unsigned char packetBuffer[ARTNET_BUFFER_MAX]; 109 | 110 | // An EthernetUDP instance to let us send and receive packets over UDP 111 | EthernetUDP eUDP; 112 | LXArtNet artnet = LXArtNet(ip); 113 | 114 | // used to toggle on and off the LED when DMX is Received 115 | int monitorstate = LOW; 116 | 117 | 118 | /* setup initializes Ethernet and opens the UDP port 119 | it also sends an Art-Net Poll Reply packet telling other 120 | Art-Net devices that it can transmit DMX from the network */ 121 | 122 | // ***** blinkLED ******************************************* 123 | // 124 | // toggles the monitor LED on and off as an indicator 125 | 126 | void blinkLED() { 127 | if ( monitorstate == LOW ) { 128 | monitorstate = HIGH; 129 | } else { 130 | monitorstate = LOW; 131 | } 132 | digitalWrite(MONITOR_PIN, monitorstate); 133 | } 134 | 135 | // ***** setup ******************************************* 136 | // 137 | // initializes Ethernet and opens the UDP port 138 | // it also sends an Art-Net Poll Reply packet telling other 139 | // Art-Net devices that it can transmit DMX from the network 140 | 141 | void setup() { 142 | pinMode(MONITOR_PIN, OUTPUT); //status LED 143 | blinkLED(); 144 | #if defined(SDSELECT_PIN) 145 | pinMode(SDSELECT_PIN, OUTPUT); 146 | #endif 147 | 148 | Ethernet.begin(mac, ip, gateway, gateway, subnet); 149 | eUDP.begin(ARTNET_PORT); 150 | 151 | LXSerialDMX.setDirectionPin(RXTX_PIN); 152 | LXSerialDMX.startOutput(); 153 | 154 | artnet.send_art_poll_reply(eUDP); 155 | blinkLED(); 156 | } 157 | 158 | 159 | /************************************************************************ 160 | 161 | The main loop checks for and reads packets from UDP ethernet socket 162 | connection. When a packet is recieved, it is checked to see if 163 | it is valid Art-Net and the art DMXReceived function is called, sending 164 | the DMX values to the output. 165 | 166 | *************************************************************************/ 167 | 168 | void loop() { 169 | if ( artnet.readDMXPacket(eUDP) ) { 170 | for (int i = 1; i <= artnet.numberOfSlots(); i++) { 171 | LXSerialDMX.setSlot(i , artnet.getSlot(i)); 172 | blinkLED(); 173 | } 174 | } 175 | } 176 | 177 | /* 178 | Revision History 179 | v1.0 initial release January 2014 180 | v1.1 added monitor LED to code and circuit 181 | v1.2 8/14/15 changed library support and clarified code 182 | v1.3 moved control of options to "includes" and "defines" 183 | v1.4 uses LXArtNet class which encapsulates Art-Net functionality 184 | v1.5 revised for refactor of DMX driver LXSerialDMX January-2016 185 | */ 186 | -------------------------------------------------------------------------------- /examples/ArtNetDMX/LXArtNetEthernet2.cpp: -------------------------------------------------------------------------------- 1 | /* LXArtNet2.cpp 2 | Copyright 2015 by Claude Heintz Design 3 | see: http://www.claudeheintzdesign.com/lx/opensource.html for license 4 | 5 | Art-Net(TM) Designed by and Copyright Artistic Licence Holdings Ltd. 6 | */ 7 | 8 | #include "LXArtNetEthernet2.h" 9 | 10 | LXArtNet::LXArtNet ( IPAddress address ) 11 | { 12 | //zero buffer including _dmx_data[0] which is start code 13 | for (int n=0; n= expected size to allow zero termination or padding 107 | */ 108 | 109 | uint16_t LXArtNet::readArtNetPacket ( EthernetUDP eUDP ) { 110 | uint16_t packetSize = eUDP.parsePacket(); 111 | uint16_t opcode = ARTNET_NOP; 112 | if ( packetSize ) { 113 | packetSize = eUDP.read(_packet_buffer, ARTNET_BUFFER_MAX); 114 | _dmx_slots = 0; 115 | /* Buffer now may not contain dmx data for desired universe. 116 | After reading the packet into the buffer, check to make sure 117 | that it is an Art-Net packet and retrieve the opcode that 118 | tells what kind of message it is. */ 119 | opcode = parse_header(); 120 | switch ( opcode ) { 121 | case ARTNET_ART_DMX: 122 | // ignore sequence[12], physical[13] and subnet/universe hi byte[15] 123 | if (( _packet_buffer[14] == _universe ) && ( _packet_buffer[11] >= 14 )) { //protocol version [10] hi byte [11] lo byte 124 | packetSize -= 18; 125 | uint16_t slots = _packet_buffer[17]; 126 | slots += _packet_buffer[16] << 8; 127 | if ( packetSize >= slots ) { 128 | if ( (uint32_t)_dmx_sender == 0 ) { //if first sender, remember address 129 | _dmx_sender = eUDP.remoteIP(); 130 | } 131 | if ( _dmx_sender == eUDP.remoteIP() ) { 132 | _dmx_slots = slots; 133 | } // matched sender 134 | } // matched size 135 | } // matched universe 136 | if ( _dmx_slots == 0 ) { //only set >0 if all of above matched 137 | opcode = ARTNET_NOP; 138 | } 139 | break; 140 | case ARTNET_ART_ADDRESS: 141 | if (( packetSize >= 108 ) && ( _packet_buffer[11] >= 14 )) { //protocol version [10] hi byte [11] lo byte 142 | opcode = parse_art_address(); 143 | send_art_poll_reply( eUDP ); 144 | } 145 | break; 146 | case ARTNET_ART_POLL: 147 | if (( packetSize >= 14 ) && ( _packet_buffer[11] >= 14 )) { 148 | send_art_poll_reply( eUDP ); 149 | } 150 | break; 151 | } 152 | } 153 | return opcode; 154 | } 155 | 156 | void LXArtNet::sendDMX ( EthernetUDP eUDP, IPAddress to_ip ) { 157 | _packet_buffer[0] = 'A'; 158 | _packet_buffer[1] = 'r'; 159 | _packet_buffer[2] = 't'; 160 | _packet_buffer[3] = '-'; 161 | _packet_buffer[4] = 'N'; 162 | _packet_buffer[5] = 'e'; 163 | _packet_buffer[6] = 't'; 164 | _packet_buffer[7] = 0; 165 | _packet_buffer[8] = 0; //op code lo-hi 166 | _packet_buffer[9] = 0x50; 167 | _packet_buffer[10] = 0; 168 | _packet_buffer[11] = 14; 169 | if ( _sequence == 0 ) { 170 | _sequence = 1; 171 | } else { 172 | _sequence++; 173 | } 174 | _packet_buffer[12] = _sequence; 175 | _packet_buffer[13] = 0; 176 | _packet_buffer[14] = _universe; 177 | _packet_buffer[15] = 0; 178 | _packet_buffer[16] = _dmx_slots >> 8; 179 | _packet_buffer[17] = _dmx_slots & 0xFF; 180 | //assume dmx data has been set 181 | 182 | eUDP.beginPacket(to_ip, ARTNET_PORT); 183 | eUDP.write(_packet_buffer, 18+_dmx_slots); 184 | eUDP.endPacket(); 185 | } 186 | 187 | void LXArtNet::send_art_poll_reply( EthernetUDP eUDP ) { 188 | unsigned char replyBuffer[ARTNET_REPLY_SIZE]; 189 | int i; 190 | for ( i = 0; i < ARTNET_REPLY_SIZE; i++ ) { 191 | replyBuffer[i] = 0; 192 | } 193 | replyBuffer[0] = 'A'; 194 | replyBuffer[1] = 'r'; 195 | replyBuffer[2] = 't'; 196 | replyBuffer[3] = '-'; 197 | replyBuffer[4] = 'N'; 198 | replyBuffer[5] = 'e'; 199 | replyBuffer[6] = 't'; 200 | replyBuffer[7] = 0; 201 | replyBuffer[8] = 0; // op code lo-hi 202 | replyBuffer[9] = 0x21; 203 | replyBuffer[10] = ((uint32_t)_my_address) & 0xff; //ip address 204 | replyBuffer[11] = ((uint32_t)_my_address) >> 8; 205 | replyBuffer[12] = ((uint32_t)_my_address) >> 16; 206 | replyBuffer[13] = ((uint32_t)_my_address) >>24; 207 | replyBuffer[14] = 0x36; // port lo first always 0x1936 208 | replyBuffer[15] = 0x19; 209 | replyBuffer[16] = 0; // firmware hi-lo 210 | replyBuffer[17] = 0; 211 | replyBuffer[18] = 0; // subnet hi-lo 212 | replyBuffer[19] = 0; 213 | replyBuffer[20] = 0; // oem hi-lo 214 | replyBuffer[21] = 0; 215 | replyBuffer[22] = 0; // ubea 216 | replyBuffer[23] = 0; // status 217 | replyBuffer[24] = 0x50; // Mfg Code 218 | replyBuffer[25] = 0x12; // seems DMX workshop reads these bytes backwards 219 | replyBuffer[26] = 'A'; // short name 220 | replyBuffer[27] = 'r'; 221 | replyBuffer[28] = 'd'; 222 | replyBuffer[29] = 'u'; 223 | replyBuffer[30] = 'i'; 224 | replyBuffer[31] = 'n'; 225 | replyBuffer[32] = 'o'; 226 | replyBuffer[33] = 0; 227 | replyBuffer[44] = 'A'; // long name 228 | replyBuffer[45] = 'r'; 229 | replyBuffer[46] = 'd'; 230 | replyBuffer[47] = 'u'; 231 | replyBuffer[48] = 'i'; 232 | replyBuffer[49] = 'n'; 233 | replyBuffer[50] = 'o'; 234 | replyBuffer[51] = 0; 235 | replyBuffer[173] = 1; // number of ports 236 | replyBuffer[174] = 128; // can output from network 237 | replyBuffer[182] = 128; // good output... change if error 238 | replyBuffer[190] = _universe; 239 | 240 | IPAddress a = _broadcast_address; 241 | if ( a == INADDR_NONE ) { 242 | a = eUDP.remoteIP(); // reply directly if no broadcast address is supplied 243 | } 244 | eUDP.beginPacket(a, ARTNET_PORT); 245 | eUDP.write(replyBuffer, ARTNET_REPLY_SIZE); 246 | eUDP.endPacket(); 247 | } 248 | 249 | uint16_t LXArtNet::parse_header( void ) { 250 | if ( strcmp((const char*)_packet_buffer, "Art-Net") == 0 ) { 251 | return _packet_buffer[9] * 256 + _packet_buffer[8]; //opcode lo byte first 252 | } 253 | return ARTNET_NOP; 254 | } 255 | 256 | /* 257 | reads an ARTNET_ART_ADDRESS packet 258 | can set output universe 259 | can cancel merge which resets address of dmx sender 260 | (after first ArtDmx packet, only packets from the same sender are accepted 261 | until a cancel merge command is received) 262 | */ 263 | 264 | uint16_t LXArtNet::parse_art_address( void ) { 265 | //[12] to [29] short name <= 18 bytes 266 | //[30] to [93] long name <= 64 bytes 267 | //[94][95][96][97] input universe ch 1 to 4 268 | //[98][99][100][101] output universe ch 1 to 4 269 | setUniverseAddress(_packet_buffer[98]); 270 | //[102][103][104][105] subnet ch 1 to 4 271 | setSubnetAddress(_packet_buffer[102]); 272 | //[106] reserved 273 | uint8_t command = _packet_buffer[107]; // command 274 | switch ( command ) { 275 | case 0x01: //cancel merge: resets ip address used to identify dmx sender 276 | _dmx_sender = (uint32_t)0; 277 | break; 278 | case 0x90: //clear buffer 279 | _dmx_sender = (uint32_t)0; 280 | for(int j=18; j 12 | #include 13 | #include 14 | #include "LXDMXEthernet2.h" 15 | 16 | #define ARTNET_PORT 0x1936 17 | #define ARTNET_BUFFER_MAX 530 18 | #define ARTNET_REPLY_SIZE 239 19 | #define ARTNET_ADDRESS_OFFSET 17 20 | 21 | #define ARTNET_ART_POLL 0x2000 22 | #define ARTNET_ART_POLL_REPLY 0x2100 23 | #define ARTNET_ART_DMX 0x5000 24 | #define ARTNET_ART_ADDRESS 0x6000 25 | #define ARTNET_NOP 0 26 | 27 | /*! 28 | @class LXArtNet 29 | @abstract 30 | LXArtNet partially implements the Art-Net Ethernet Communication Standard. 31 | 32 | LXArtNet is primarily a node implementation. It supports output of a single universe 33 | of DMX data from the network. It does not support merge and will only accept 34 | packets from the first IP address from which it receives an ArtDMX packet. 35 | This can be reset by sending an ArtAddress cancel merge command. 36 | 37 | When reading packets, LXArtNet will automatically respond to ArtPoll packets. 38 | Depending on the constructor used, it will either broadcast the reply or will 39 | reply directly to the sender of the poll. 40 | 41 | http://www.artisticlicence.com 42 | */ 43 | class LXArtNet : public LXDMXEthernet { 44 | 45 | public: 46 | /*! 47 | * @brief constructor with address used for ArtPollReply 48 | * @param address sent in ArtPollReply 49 | */ 50 | LXArtNet ( IPAddress address ); 51 | /*! 52 | * @brief constructor creates broadcast address for Poll Reply 53 | * @param address sent in ArtPollReply 54 | * @param subnet_mask used to set broadcast address 55 | */ 56 | LXArtNet ( IPAddress address, IPAddress subnet_mask ); 57 | ~LXArtNet ( void ); 58 | 59 | /*! 60 | * @brief UDP port used by protocol 61 | */ 62 | uint16_t dmxPort ( void ) { return ARTNET_PORT; } 63 | 64 | /*! 65 | * @brief universe for sending and receiving dmx 66 | * @discussion First universe is zero for Art-Net. High nibble is subnet, low nibble is universe. 67 | * @return universe 0-255 68 | */ 69 | uint8_t universe ( void ); 70 | /*! 71 | * @brief set universe for sending and receiving 72 | * @discussion First universe is zero for Art-Net. High nibble is subnet, low nibble is universe. 73 | * @param u universe 0-255 74 | */ 75 | void setUniverse ( uint8_t u ); 76 | /*! 77 | * @brief set subnet/universe for sending and receiving 78 | * @discussion First universe is zero for Art-Net. Sets separate nibbles: high/subnet, low/universe. 79 | * @param s subnet 0-16 80 | * @param u universe 0-16 81 | */ 82 | void setSubnetUniverse ( uint8_t s, uint8_t u ); 83 | /*! 84 | * @brief set universe for sending and receiving 85 | * @discussion First universe is zero for Art-Net. High nibble is subnet, low nibble is universe. 86 | * 0x7f is no change, otherwise if high bit is set, low nibble becomes universe (subnet remains the same) 87 | * @param u universe 0-16 + flag 0x80 88 | */ 89 | void setUniverseAddress ( uint8_t u ); 90 | /*! 91 | * @brief set subnet for sending and receiving 92 | * @discussion First universe is zero for Art-Net. High nibble is subnet, low nibble is universe. 93 | * 0x7f is no change, otherwise if high bit is set, low nibble becomes subnet (universe remains the same) 94 | * @param s subnet 0-16 + flag 0x80 95 | */ 96 | void setSubnetAddress ( uint8_t s ); 97 | 98 | /*! 99 | * @brief number of slots (aka addresses or channels) 100 | * @discussion Should be minimum of ~24 depending on actual output speed. Max of 512. 101 | * @return number of slots/addresses/channels 102 | */ 103 | int numberOfSlots ( void ); 104 | /*! 105 | * @brief set number of slots (aka addresses or channels) 106 | * @discussion Should be minimum of ~24 depending on actual output speed. Max of 512. 107 | * @param n number of slots 1 to 512 108 | */ 109 | void setNumberOfSlots ( int n ); 110 | /*! 111 | * @brief get level data from slot/address/channel 112 | * @param slot 1 to 512 113 | * @return level for slot (0-255) 114 | */ 115 | uint8_t getSlot ( int slot ); 116 | /*! 117 | * @brief set level data (0-255) for slot/address/channel 118 | * @param slot 1 to 512 119 | * @param value level 0 to 255 120 | */ 121 | void setSlot ( int slot, uint8_t value ); 122 | /*! 123 | * @brief direct pointer to dmx buffer uint8_t[] 124 | * @return uint8_t* to dmx data buffer 125 | */ 126 | uint8_t* dmxData ( void ); 127 | 128 | /*! 129 | * @brief read UDP packet 130 | * @param eUDP EthernetUDP object to be used for getting UDP packet 131 | * @return 1 if packet contains dmx 132 | */ 133 | uint8_t readDMXPacket ( EthernetUDP eUDP ); 134 | /*! 135 | * @brief process packet, reading it into _packet_buffer 136 | * @param eUDP EthernetUDP (used for Poll Reply if applicable) 137 | * @return Art-Net opcode of packet 138 | */ 139 | uint16_t readArtNetPacket ( EthernetUDP eUDP ); 140 | /*! 141 | * @brief send Art-Net ArtDMX packet for dmx output from network 142 | * @param eUDP EthernetUDP object to be used for sending UDP packet 143 | * @param to_ip target address 144 | */ 145 | void sendDMX ( EthernetUDP eUDP, IPAddress to_ip ); 146 | /*! 147 | * @brief send ArtPoll Reply packet for dmx output from network 148 | * @discussion If broadcast address is defined by passing subnet to constructor, reply is broadcast 149 | * Otherwise, reply is unicast to remoteIP belonging to the sender of the poll 150 | * @param eUDP EthernetUDP object to be used for sending UDP packet 151 | */ 152 | void send_art_poll_reply ( EthernetUDP eUDP ); 153 | 154 | private: 155 | /*! 156 | * @brief buffer that holds contents of incoming or outgoing packet 157 | * @discussion There is no double buffer for dmx data. 158 | * readArtNetPacket fills the buffer with the payload of the incoming packet. 159 | * Previous dmx data is invalidated. 160 | */ 161 | uint8_t _packet_buffer[ARTNET_BUFFER_MAX]; 162 | /// number of slots/address/channels 163 | int _dmx_slots; 164 | /// high nibble subnet, low nibble universe 165 | uint8_t _universe; 166 | /// sequence number for sending ArtDMX packets 167 | uint8_t _sequence; 168 | 169 | /// address included in poll replies 170 | IPAddress _my_address; 171 | /// if subnet is supplied in constructor, holds address to broadcast poll replies 172 | IPAddress _broadcast_address; 173 | /// first sender of an ArtDMX packet (subsequent senders ignored until cancelMerge) 174 | IPAddress _dmx_sender; 175 | 176 | /*! 177 | * @brief checks packet for "Art-Net" header 178 | * @return opcode if Art-Net packet 179 | */ 180 | uint16_t parse_header ( void ); 181 | /*! 182 | * @brief utility for parsing ArtAddress packets 183 | * @return opcode in case command changes dmx data 184 | */ 185 | uint16_t parse_art_address ( void ); 186 | 187 | }; 188 | 189 | #endif // ifndef LXARTNET_H -------------------------------------------------------------------------------- /examples/ArtNetDMX/LXDMXEthernet2.h: -------------------------------------------------------------------------------- 1 | /* LXDMXEthernet2.h 2 | Copyright 2015 by Claude Heintz Design 3 | see: http://www.claudeheintzdesign.com/lx/opensource.html for license 4 | */ 5 | 6 | #ifndef LXDMXETHERNET_H 7 | #define LXDMXETHERNET_H 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | /*! 14 | @class LXDMXEthernet 15 | @abstract 16 | LXDMXEthernet encapsulates functionality for sending and receiving DMX over ethernet. 17 | It is a virtual class with concrete subclasses LXArtNet and LXSACN which specifically 18 | implement the Artistic Licence Art-Net and PLASA sACN 1.31 protocols. 19 | 20 | Note: LXDMXEthernet2_library requires 21 | Ethernet2 library used with Arduino Ethernet Shield 2 22 | Use LXDMXEthernet_library with the original Ethernet shield and Ethernet Library 23 | 24 | For multicast, EthernetUDP2.h and EthernetUDP2.cpp in the Ethernet2 library 25 | must be modified to add the beginMulticast method. 26 | See the code at the bottom of LXDMXEthernet2.h 27 | */ 28 | 29 | class LXDMXEthernet { 30 | 31 | public: 32 | /*! 33 | * @brief UDP port used by protocol 34 | */ 35 | virtual uint16_t dmxPort ( void ); 36 | 37 | /*! 38 | * @brief universe for sending and receiving dmx 39 | * @discussion First universe is zero for Art-Net and one for sACN E1.31. 40 | * @return universe 0/1-255 41 | */ 42 | virtual uint8_t universe ( void ); 43 | /*! 44 | * @brief set universe for sending and receiving 45 | * @discussion First universe is zero for Art-Net and one for sACN E1.31. 46 | * @param u universe 0/1-255 47 | */ 48 | virtual void setUniverse ( uint8_t u ); 49 | 50 | /*! 51 | * @brief number of slots (aka addresses or channels) 52 | * @discussion Should be minimum of ~24 depending on actual output speed. Max of 512. 53 | * @return number of slots/addresses/channels 54 | */ 55 | virtual int numberOfSlots ( void ); 56 | /*! 57 | * @brief set number of slots (aka addresses or channels) 58 | * @discussion Should be minimum of ~24 depending on actual output speed. Max of 512. 59 | * @param slots 1 to 512 60 | */ 61 | virtual void setNumberOfSlots ( int n ); 62 | /*! 63 | * @brief get level data from slot/address/channel 64 | * @param slot 1 to 512 65 | * @return level for slot (0-255) 66 | */ 67 | virtual uint8_t getSlot ( int slot ); 68 | /*! 69 | * @brief set level data (0-255) for slot/address/channel 70 | * @param slot 1 to 512 71 | * @param level 0 to 255 72 | */ 73 | virtual void setSlot ( int slot, uint8_t value ); 74 | /*! 75 | * @brief direct pointer to dmx buffer uint8_t[] 76 | * @return uint8_t* to dmx data buffer 77 | */ 78 | virtual uint8_t* dmxData ( void ); 79 | 80 | /*! 81 | * @brief read UDP packet 82 | * @return 1 if packet contains dmx 83 | */ 84 | virtual uint8_t readDMXPacket ( EthernetUDP eUDP ); 85 | virtual void sendDMX ( EthernetUDP eUDP, IPAddress to_ip ); 86 | }; 87 | 88 | #endif // ifndef LXDMXETHERNET_H 89 | 90 | 91 | /* 92 | @code 93 | ****************** multicast methods added to Ethernet2 library ******************* 94 | 95 | see https://github.com/aallan/Arduino/blob/3811729f82ef05f3ae43341022e7b65a92d333a2/libraries/Ethernet/EthernetUdp.cpp 96 | 97 | 1) Locate the Ethernet2 library 98 | If you have installed this library, it will be located with other libraries in the /libraries folder. 99 | If it is included in the IDE, you will need to search within the IDE files to find the libraries folder. 100 | 101 | 2) Duplicate the Ethernet2 library in your sketchbook folder (~/Documents/Arduino/libraries) 102 | Add the required method as follows: 103 | 104 | 3) In EthernetUDPh or EthernetUDP2.h add the beginMulticast method declaration: 105 | ... 106 | EthernetUDP(); // Constructor 107 | virtual uint8_t begin(uint16_t); // initialize, start listening on specified port. Returns 1 if successful, 0 if there are no sockets available to use 108 | uint8_t beginMulticast(IPAddress ip, uint16_t port); //############## added to standard library 109 | ... 110 | 111 | 4) In EthernetUDP2.cpp add the method body: 112 | 113 | uint8_t EthernetUDP::beginMulticast(IPAddress ip, uint16_t port) { 114 | if (_sock != MAX_SOCK_NUM) 115 | return 0; 116 | 117 | for (int i = 0; i < MAX_SOCK_NUM; i++) { 118 | uint8_t s = w5500.readSnSR(i); 119 | if (s == SnSR::CLOSED || s == SnSR::FIN_WAIT) { 120 | _sock = i; 121 | break; 122 | } 123 | } 124 | 125 | if (_sock == MAX_SOCK_NUM) 126 | return 0; 127 | 128 | 129 | // Calculate MAC address from Multicast IP Address 130 | byte mac[] = { 0x01, 0x00, 0x5E, 0x00, 0x00, 0x00 }; 131 | 132 | mac[3] = ip[1] & 0x7F; 133 | mac[4] = ip[2]; 134 | mac[5] = ip[3]; 135 | 136 | w5500.writeSnDIPR(_sock, rawIPAddress(ip)); //239.255.0.1 137 | w5500.writeSnDPORT(_sock, port); 138 | w5500.writeSnDHAR(_sock,mac); 139 | 140 | _remaining = 0; 141 | 142 | socket(_sock, SnMR::UDP, port, SnMR::MULTI); 143 | 144 | return 1; 145 | } 146 | 147 | ************************************************************************************** 148 | */ -------------------------------------------------------------------------------- /examples/DMXSerialOutputTest/DMXSerialOutputTest.ino: -------------------------------------------------------------------------------- 1 | /* 2 | This sketch demonstrates output using a DMX shield. 3 | It outputs DMX in several patterns depending on the 4 | state of pins which is read at boot time. 5 | 6 | This sketch requires a DMXLibrary, 7 | LXUSARTDMX is a basic, easy to understand library. 8 | 9 | The sketch uses the microcontroller's USART to transmit 10 | dmx levels as serial data. A DMX shield is used to convert 11 | this output to a differential signal (actual DMX). 12 | 13 | This is the circuit for a simple unisolated DMX Shield: 14 | 15 | Arduino SN 75176 A or MAX 481CPA 16 | pin _______________ 17 | | | 1 Vcc 8 |------ +5v 18 | V | | DMX Output 19 | | +----| 2 B 7 |---------------- Pin 2 20 | | | | | 21 | 4 |----------------------| 3 DE A 6 |---------------- Pin 3 22 | | | | 23 | TX |----------------------| 4 DI Gnd 5 |---+------------ Pin 1 24 | | | 25 | | GND 26 | 7 |--------[ 330 ohm ]---[ LED ]------------| 27 | 28 | 29 | Created August 16th, 2015 by Claude Heintz 30 | Copyright 2014-2016 see LXUSARTDMX for license 31 | 32 | */ 33 | 34 | //*********************** includes *********************** 35 | 36 | #include 37 | 38 | //*********************** globals *********************** 39 | 40 | #define RXTX_PIN 4 41 | 42 | uint8_t level = 0; 43 | 44 | void setup() { 45 | LXSerialDMX.setDirectionPin(RXTX_PIN); 46 | LXSerialDMX.startOutput(); 47 | LXSerialDMX.setMaxSlots(512); 48 | } 49 | 50 | void loop() { 51 | LXSerialDMX.setSlot(7, level); 52 | LXSerialDMX.setSlot(8, level); 53 | level++; 54 | delay(20); 55 | } 56 | 57 | -------------------------------------------------------------------------------- /examples/DMXTest/DMXTest.ino: -------------------------------------------------------------------------------- 1 | /* 2 | This sketch demonstrates output using a DMX shield. 3 | It outputs DMX in several patterns depending on the 4 | state of pins which is read at boot time. 5 | 6 | This sketch requires a DMXLibrary, 7 | LXUSARTDMX is a basic, easy to understand library. 8 | 9 | The sketch uses the microcontroller's USART to transmit 10 | dmx levels as serial data. A DMX shield is used to convert 11 | this output to a differential signal (actual DMX). 12 | 13 | This is the circuit for a simple unisolated DMX Shield: 14 | 15 | Arduino SN 75176 A or MAX 481CPA 16 | pin _______________ 17 | | | 1 Vcc 8 |------ +5v 18 | V | | DMX Output 19 | | +----| 2 B 7 |---------------- Pin 2 20 | | | | | 21 | 2 |----------------------| 3 DE A 6 |---------------- Pin 3 22 | | | | 23 | TX |----------------------| 4 DI Gnd 5 |---+------------ Pin 1 24 | | | 25 | | GND 26 | 5 |--------[ 330 ohm ]---[ LED ]------------| 27 | 28 | 29 | Created August 16th, 2015 by Claude Heintz 30 | Copyright 2014-2016 see LXUSARTDMX for license 31 | 32 | */ 33 | 34 | //*********************** includes *********************** 35 | 36 | #include 37 | 38 | //*********************** globals *********************** 39 | 40 | #define RXTX_PIN 2 41 | 42 | // choose the range of addresses for the fade sequence: 43 | #define LOW_ADDRESS 1 44 | #define HIGH_ADDRESS 512 45 | 46 | // these pins are used at startup to determine which program will loop 47 | #define SELECT_PIN_0 8 48 | #define SELECT_PIN_1 9 49 | 50 | #define PROGRAM_FADE_ALL 0 51 | #define PROGRAM_SEQUENCE 1 52 | 53 | uint8_t program = 0; 54 | int address = LOW_ADDRESS; 55 | uint8_t level = 0; 56 | uint8_t direction = 1; 57 | 58 | // out(address, level) is a utility function for 59 | // setting the level of a DMX address 60 | 61 | void out(int addr, uint8_t vx) { 62 | LXSerialDMX.setSlot(addr,vx); 63 | } 64 | 65 | void setup() { 66 | LXSerialDMX.setDirectionPin(RXTX_PIN); 67 | LXSerialDMX.startOutput(); 68 | LXSerialDMX.setMaxSlots(HIGH_ADDRESS); 69 | 70 | pinMode(SELECT_PIN_0, INPUT); 71 | pinMode(SELECT_PIN_1, INPUT); 72 | if ( digitalRead(SELECT_PIN_0) == HIGH ) { 73 | program += 1; 74 | } 75 | if ( digitalRead(SELECT_PIN_1) == HIGH ) { 76 | program += 2; 77 | } 78 | } 79 | 80 | // ***** fadeUpDownOneAtATime ***** 81 | // 82 | // fades a single address up and then down 83 | // 84 | 85 | void fadeUpDownOneAtATime() { 86 | out(address,level); 87 | delay(5); 88 | 89 | if ( direction ) { 90 | level++; 91 | if ( level == 255 ) { 92 | direction = 0; 93 | } 94 | } else { 95 | level--; 96 | if ( level == 0 ) { 97 | direction = 1; 98 | out(address,level); 99 | address++; 100 | if ( address > HIGH_ADDRESS) { 101 | address = LOW_ADDRESS; 102 | } 103 | } 104 | } 105 | } 106 | 107 | // ***** fadeAll ***** 108 | // 109 | // fades all addresses up and then down 110 | // 111 | 112 | void fadeAll() { 113 | for (int i=LOW_ADDRESS; i<= HIGH_ADDRESS; i++) { 114 | out(i, level); 115 | } 116 | delay(10); 117 | if ( direction ) { 118 | level++; 119 | if ( level == 255 ) { 120 | direction = 0; 121 | } 122 | } else { 123 | level--; 124 | if ( level < 0 ) { 125 | level = 0; 126 | direction = 1; 127 | } 128 | } 129 | } 130 | 131 | // ***** allOnThenAllOff ***** 132 | // 133 | // turns all addresses on sequentially 134 | // then turns all addresses off sequentially 135 | 136 | void allOnThenAllOff() { 137 | if ( direction == 1 ) { 138 | out(address,255); 139 | } else { 140 | out(address,0); 141 | } 142 | delay(5); 143 | 144 | address++; 145 | if ( address > HIGH_ADDRESS) { 146 | address = LOW_ADDRESS; 147 | if ( direction == 1 ) { 148 | direction = 0; 149 | } else { 150 | direction = 1; 151 | } 152 | } 153 | } 154 | 155 | void loop() { 156 | if ( program == PROGRAM_FADE_ALL ) { 157 | fadeAll(); 158 | } else if ( program == PROGRAM_SEQUENCE ) { 159 | allOnThenAllOff(); 160 | } else { 161 | fadeUpDownOneAtATime(); 162 | } 163 | } 164 | 165 | -------------------------------------------------------------------------------- /examples/DMXUSBSerial/DMXUSBSerial.ino: -------------------------------------------------------------------------------- 1 | /* DMXUSBSerial 2 | * 3 | * This sketch allows a Teensy 2.0++ board to emulate parts of an 4 | * ENTTEC DMX USB Pro's functions. 5 | * The sketch uses the LXUSARTDMX library for DMX input/output 6 | * through the teensy's USART 1 serial port. 7 | * 8 | * For the sketch to compile, USE_UART_1 must be defined in the 9 | * LXUSARTDMX library. USE_UART_1 is automatically 10 | * defined for a Teensy 2.0++ with an AVR_AT90USB processor. 11 | * However, the sketch should be able to work with any board 12 | * with a processor that has more than one USART. 13 | * To use with other boards, modify the #define in LXUSARTDMX.cpp 14 | * 15 | * This is the circuit for a simple unisolated DMX Shield: 16 | 17 | Teensy 2.0++ SN 75176 A or MAX 481CPA 18 | pin _______________ 19 | 5 |--------------------- | 1 Vcc 8 |------ +5v (Teensy 2.0++ pin 21) 20 | | | | 21 | | +----| 2 B 7 |---------------- Pin 2 22 | | | | | 23 | 7 |----------------------| 3 DE A 6 |---------------- Pin 3 24 | | | | 25 | 6 |----------------------| 4 DI Gnd 5 |---+------------ Pin 1 26 | | _______________ | DMX Output 27 | | | 28 | 8 |--------[ 330 ohm ]---[ LED ]------------| 29 | 9 |--------[ 330 ohm ]---[ LED ]------------| 30 | 10 |--------[ 330 ohm ]---[ LED ]------------| 31 | 1 | GND 32 | 33 | * Created January 18th, 2015 by Claude Heintz 34 | * Current version 1.1 35 | * 36 | * Copyright 2014-2016 see LXUSARTDMX for license 37 | */ 38 | 39 | #include 40 | #include "LXENTTECSerial.h" 41 | 42 | // ********************** defines ********************** 43 | 44 | // Pin 13 has an LED connected on most Arduino boards. 45 | // Pin 11 has the LED on Teensy 2.0 46 | // Pin 6 has the LED on Teensy++ 2.0 47 | // Pin 13 has the LED on Teensy 3.0 48 | #define RED_LED_PIN 6 49 | #define GRN_LED_PIN 7 50 | #define BLU_LED_PIN 8 51 | 52 | #define RED_LED_BIT 1 53 | #define GRN_LED_BIT 2 54 | #define BLU_LED_BIT 4 55 | 56 | #define RXTX_PIN 4 57 | 58 | #define MODE_OUTPUT_DMX 0 59 | #define MODE_INPUT_DMX 1 60 | 61 | #define PACKET_LABEL_DMX 6 62 | #define PACKET_LABEL_RECEIVE 8 63 | #define PACKET_LABEL_GET_INFO 3 64 | #define PACKET_LABEL_GET_SERIAL 10 65 | 66 | // ********************** globals ********************** 67 | 68 | uint8_t mode = MODE_OUTPUT_DMX; 69 | int got_dmx = 0; 70 | uint8_t buffer[513]; 71 | LXENTTECSerial eSerial = LXENTTECSerial(); 72 | 73 | // ***************** setup() runs once **************** 74 | 75 | void setup() { 76 | pinMode(RED_LED_PIN, OUTPUT); 77 | pinMode(GRN_LED_PIN, OUTPUT); 78 | pinMode(BLU_LED_PIN, OUTPUT); 79 | LXSerialDMX.setDirectionPin(RXTX_PIN); 80 | Serial.begin(57600);//115200 doesn't matter because teensy changes to USB speed 81 | } 82 | 83 | // ***************** utility functions **************** 84 | 85 | /* setLED(uint8_t flags) 86 | * sets color of RGB LED 87 | */ 88 | 89 | void setLED(uint8_t flags) { 90 | digitalWrite(RED_LED_PIN, 1 & flags); 91 | digitalWrite(GRN_LED_PIN, 1 & (flags>>1)); 92 | digitalWrite(BLU_LED_PIN, 1 & (flags>>2)); 93 | } 94 | 95 | 96 | // ***************** input/output functions ************* 97 | 98 | void gotDMXCallback(int slots) { 99 | got_dmx = slots; 100 | } 101 | 102 | void doOutputMode() { 103 | uint8_t label = eSerial.readPacket(); 104 | if ( label == ENTTEC_LABEL_SEND_DMX ) { 105 | int s = eSerial.numberOfSlots() + 1; 106 | for(int i=0; i) before calling this method 95 | 96 | uint8_t LXENTTECSerial::readPacket( void ) { 97 | uint8_t b; 98 | uint8_t label = ENTTEC_LABEL_NONE; 99 | int data_length; 100 | uint8_t userlsb = 0; 101 | uint8_t usermsb = 0; 102 | 103 | b = getNextByte(); 104 | if ( b == 0x7E ) { // byte must be packet start delimiter 0x7E 105 | label = getNextByte(); // 6 = Send DMX 106 | data_length = getNextByte(); // LSB 107 | b = getNextByte(); // MSB 108 | data_length += (b << 8); 109 | switch ( label ) { 110 | case ENTTEC_LABEL_SEND_DMX: 111 | for(int n=0; n DMX_MAX ) { 138 | data_length = DMX_MAX; 139 | } 140 | _dmx_slots = data_length-1; //data length includes start code 141 | break; 142 | case ENTTEC_LABEL_GET_INFO: 143 | this->writeInfo(userlsb+(usermsb<<8)); 144 | break; 145 | case ENTTEC_LABEL_GET_SERIAL: 146 | this->writeSerialNumber(0xffffffff); 147 | break; 148 | } 149 | } else { // bad packet 150 | if ( label == ENTTEC_LABEL_SEND_DMX ) { 151 | _dmx_slots = 0; // buffer is not valid anymore 152 | } 153 | label = ENTTEC_LABEL_NONE; 154 | } 155 | } // good start delimiter 156 | 157 | return label; 158 | } 159 | 160 | // ***** writeDMXPacket() ***** 161 | // writes a DMX Received packet to Serial 162 | // sends the DMX data from the _dmx_data buffer 163 | // 164 | // Important: must call Serial.begin() before calling this method 165 | 166 | void LXENTTECSerial::writeDMXPacket( void ) { 167 | this->writeDMXPacket(_dmx_data, _dmx_slots+1); //includes start code 168 | } 169 | 170 | // ***** writeDMXPacket(buffer, length) ***** 171 | // writes a DMX Received packet to Serial 172 | // sends the DMX data from an external buffer 173 | // buffer must include start code 174 | // 175 | // Important: must call Serial.begin() before calling this method 176 | 177 | void LXENTTECSerial::writeDMXPacket( uint8_t *buffer, int length ) { 178 | int total_length = length + 1; 179 | uint8_t header[5]; 180 | header[0] = 0x7E; 181 | header[1] = ENTTEC_LABEL_RECEIVED_DMX; 182 | header[2] = total_length & 0xff; 183 | header[3] = total_length >> 8; 184 | header[4] = 0; //status byte unused at present 185 | Serial.write(header,5); 186 | Serial.write(buffer, length); 187 | header[0] = 0xE7; 188 | Serial.write(header,1); 189 | } 190 | 191 | // ***** writeInfo(length) ***** 192 | // writes widget info packet 193 | // writes zeros for user data of length 194 | // 195 | // Important: must call Serial.begin() before calling this method 196 | 197 | void LXENTTECSerial::writeInfo( uint16_t length ) { 198 | uint8_t header[9]; 199 | header[0] = 0x7E; 200 | header[1] = ENTTEC_LABEL_GET_INFO; 201 | header[2] = (length+5) & 0xff; 202 | header[3] = (length+5) >> 8; 203 | header[4] = 44; // protocol version lsb 204 | header[5] = 1; // msb 205 | header[6] = 9; // DMX break x10.67 usecs (~99usec on Teensy2++) 206 | header[7] = 1; // MAB x10.67 usecs (~13usec on Teensy2++) 207 | header[8] = 0; // output speed packets/sec 0=max 208 | Serial.write(header,9); 209 | header[0] = 0x00; 210 | for(uint16_t n=0; n> 8 ) & 0xff; 228 | header[6] = ( sn >> 16 ) & 0xff; 229 | header[7] = ( sn >> 24 ) & 0xff; 230 | header[8] = 0xE7; 231 | Serial.write(header,9); 232 | } 233 | 234 | // ***** getNextByte() ***** 235 | // blocks until byte is available on Serial connection 236 | // 237 | 238 | uint8_t LXENTTECSerial::getNextByte( void ) { 239 | while ( true ) { 240 | if ( Serial.available()) { 241 | return Serial.read(); 242 | } 243 | } 244 | } 245 | -------------------------------------------------------------------------------- /examples/DMXUSBSerial/LXENTTECSerial.h: -------------------------------------------------------------------------------- 1 | /* LXENTTECSerial.h 2 | Copyright 2015 by Claude Heintz Design 3 | This code is in the public domain 4 | */ 5 | 6 | #ifndef LXENTTECSerial_H 7 | #define LXENTTECSerial_H 8 | 9 | #include 10 | #include 11 | 12 | #define DMX_MIN 25 13 | #define DMX_MAX 513 14 | 15 | #define ENTTEC_LABEL_NONE 0 16 | #define ENTTEC_LABEL_GET_INFO 3 17 | #define ENTTEC_LABEL_RECEIVED_DMX 5 18 | #define ENTTEC_LABEL_SEND_DMX 6 19 | #define ENTTEC_LABEL_RECEIVE_DMX 8 20 | #define ENTTEC_LABEL_GET_SERIAL 10 21 | 22 | class LXENTTECSerial { 23 | 24 | public: 25 | LXENTTECSerial ( void ); 26 | ~LXENTTECSerial ( void ); 27 | 28 | int numberOfSlots ( void ); 29 | void setNumberOfSlots ( int n ); 30 | uint8_t getSlot ( int slot ); 31 | void setSlot ( int slot, uint8_t value ); 32 | uint8_t startCode ( void ); 33 | void setStartCode ( uint8_t value ); 34 | uint8_t* dmxData ( void ); 35 | 36 | uint8_t readPacket ( void ); 37 | void writeDMXPacket ( void ); 38 | void writeDMXPacket ( uint8_t *buffer, int length ); 39 | void writeInfo ( uint16_t length ); 40 | void writeSerialNumber ( uint32_t sn ); 41 | 42 | private: 43 | uint8_t _dmx_data[DMX_MAX]; 44 | int _dmx_slots; 45 | 46 | uint8_t getNextByte( void ); 47 | }; 48 | 49 | #endif // ifndef LXENTTECSerial_H -------------------------------------------------------------------------------- /extras/doc/Classes/LXUSARTDMX/index.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | LXUSARTDMX 5 | 6 | 7 | 8 | 134 | 150 | 162 | 252 | 253 | 254 | 255 |
256 | 257 |

LXUSARTDMX

258 |
259 | 260 |
Declared In:
261 |

Introduction

262 |

LXUSARTDMX is a driver for sending or receiving DMX using an AVR family microcontroller 263 | UART0 RX pin 0, TX pin 1 264 |

265 |

LXUSARTDMX output mode continuously sends DMX once its interrupts have been enabled using startOutput(). 266 | Use setSlot() to set the level value for a particular DMX dimmer/address/channel. 267 |

268 |

LXUSARTDMX input mode continuously receives DMX once its interrupts have been enabled using startInput() 269 | Use getSlot() to read the level value for a particular DMX dimmer/address/channel. 270 |

271 |

LXUSARTDMX is used with a single instance called LXSerialDMX . 272 |

273 |

274 |

Member Functions

275 |
276 |
dmxData
277 |

provides direct access to data array 278 |

279 |
getSlot
280 |

reads the value of a slot/address/channel 281 |

282 |
setDataReceivedCallback
283 |

Function called when DMX frame has been read 284 |

285 |
setDirectionPin
286 |

optional utility sets the pin used to control driver chip's 287 | DE (data enable) line, HIGH for output, LOW for input. 288 |

289 |
setMaxSlots
290 |

Sets the number of slots (aka addresses or channels) sent per DMX frame. 291 |

292 |
setSlot
293 |

Sets the output value of a slot 294 |

295 |
startInput
296 |

starts interrupt that continuously reads DMX data 297 |

298 |
startOutput
299 |

starts interrupt that continuously sends DMX data 300 |

301 |
stop
302 |

disables USART 303 |

304 |
305 |
306 | 307 |

dmxData

308 |

provides direct access to data array 309 |

310 |
311 |
public
312 | 
uint8_t* dmxData( 313 | void);
314 |
315 |
Return Value

pointer to dmx array 316 | 317 |


318 | 319 |

getSlot

320 |

reads the value of a slot/address/channel 321 |

322 |
323 |
public
324 | 
uint8_t getSlot ( 325 | int slot);
326 |
327 |
Return Value

level (0-255) 328 | 329 |

Discussion
330 |

NOTE: Data is not double buffered. 331 | So a complete single frame is not guaranteed. 332 | The ISR continuously reads the next frame into the buffer 333 | 334 |


335 | 336 |

setDataReceivedCallback

337 |

Function called when DMX frame has been read 338 |

339 |
340 |
public
341 | 
void setDataReceivedCallback( 342 | LXRecvCallback callback);
343 |
344 |
Discussion
345 |

Sets a pointer to a function that is called 346 | on the break after a DMX frame has been received. 347 | Whatever happens in this function should be quick! 348 | Best used to set a flag that is polled outside of ISR for available data. 349 | 350 |


351 | 352 |

setDirectionPin

353 |

optional utility sets the pin used to control driver chip's 354 | DE (data enable) line, HIGH for output, LOW for input. 355 |

356 |
357 |
public
358 | 
void setDirectionPin( 359 | uint8_t pin );
360 |
361 |
Parameters
362 |
363 |
364 |
365 | 366 | pin

to be automatically set for input/output direction

367 |
368 |
369 |
370 | 371 |

setMaxSlots

372 |

Sets the number of slots (aka addresses or channels) sent per DMX frame. 373 |

374 |
375 |
public
376 | 
void setMaxSlots ( 377 | int slot);
378 |
379 |
Parameters
380 |
381 |
382 |
383 | 384 | slot

the highest slot number (~24 to 512)

385 |
386 |
387 |
Discussion
388 |

defaults to 512 or DMX_MAX_SLOTS and should be no less DMX_MIN_SLOTS slots. 389 | The DMX standard specifies min break to break time no less than 1024 usecs. 390 | At 44 usecs per slot ~= 24 391 | 392 |


393 | 394 |

setSlot

395 |

Sets the output value of a slot 396 |

397 |
398 |
public
399 | 
void setSlot ( 400 | int slot, 401 | uint8_t value);
402 |
403 |
Parameters
404 |
405 |
406 |
407 | 408 | slot

number of the slot/address/channel (1-512)

409 |
410 | 411 | value

level (0-255)

412 |
413 |
414 |
415 | 416 |

startInput

417 |

starts interrupt that continuously reads DMX data 418 |

419 |
420 |
public
421 | 
void startInput( 422 | void );
423 |
424 |
Discussion
425 |

sets up baud rate, bits and parity, 426 | sets globals accessed in ISR, 427 | enables receive and rx interrupt 428 | 429 |


430 | 431 |

startOutput

432 |

starts interrupt that continuously sends DMX data 433 |

434 |
435 |
public
436 | 
void startOutput( 437 | void );
438 |
439 |
Discussion
440 |

sets up baud rate, bits and parity, 441 | sets globals accessed in ISR, 442 | enables transmission and tx interrupt 443 | 444 |


445 | 446 |

stop

447 |

disables USART 448 |

449 |
450 |
public
451 | 
void stop( 452 | void );
453 |
454 |
455 | 456 |

Member Data

457 |
458 |
_direction_pin
459 |

pin used to control direction of output driver chip 460 |

461 |
_dmxData
462 |

Array of dmx data including start code 463 |

464 |
_interrupt_status
465 |

Indicates mode ISR_OUTPUT_ENABLED or ISR_INPUT_ENABLED or ISR_DISABLED 466 |

467 |
468 |
469 | 470 |

_direction_pin

471 |

pin used to control direction of output driver chip 472 |

473 |
474 |
private
475 | 
uint8_t _direction_pin;
476 |
477 |
478 | 479 |

_dmxData

480 |

Array of dmx data including start code 481 |

482 |
483 |
private
484 | 
uint8_t _dmxData[DMX_MAX_SLOTS+1];
485 |
486 |
487 | 488 |

_interrupt_status

489 |

Indicates mode ISR_OUTPUT_ENABLED or ISR_INPUT_ENABLED or ISR_DISABLED 490 |

491 |
492 |
private
493 | 
uint8_t _interrupt_status;
494 |
495 |

 


498 |
499 | 500 | -------------------------------------------------------------------------------- /extras/doc/Classes/LXUSARTDMX/toc.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | Documentation for LXUSARTDMX (LXUSARTDMX.h) 6 | 7 | 8 | 9 | 10 | 11 | 14 |
 
15 | 16 | 17 | 60 |
Class:
  LXUSARTDMX
18 | 19 |
20 | 21 | 22 |
Introduction
23 |
24 |
25 | 27 |
26 | Member Functions
28 |
29 | Public 30 |
40 |
41 | 43 |
42 | Member Data
44 |
45 | Protected 46 |
50 |
51 |

Other Reference

52 |
53 | 54 | 55 |
Header
56 |
57 | 58 | 59 |

 

61 |

62 | 63 | -------------------------------------------------------------------------------- /extras/doc/index.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | LXUSARTDMX.h 5 | 6 | 7 | 8 | 134 | 150 | 162 | 252 | 253 | 254 | 255 | 256 |
257 | 258 |

LXUSARTDMX.h

259 |
260 | 262 |
Includes:
<Arduino.h>
261 | <inttypes.h>
263 |

Introduction

264 |

Use the links in the table of contents to the left to access the documentation.
265 |

266 |

267 |

Classes

268 |
269 |
LXUSARTDMX
270 |

LXUSARTDMX is a driver for sending or receiving DMX using an AVR family microcontroller 271 | UART0 RX pin 0, TX pin 1 272 |

273 |

LXUSARTDMX output mode continuously sends DMX once its interrupts have been enabled using startOutput(). 274 | Use setSlot() to set the level value for a particular DMX dimmer/address/channel. 275 |

276 |

LXUSARTDMX input mode continuously receives DMX once its interrupts have been enabled using startInput() 277 | Use getSlot() to read the level value for a particular DMX dimmer/address/channel. 278 |

279 |

LXUSARTDMX is used with a single instance called LXSerialDMX . 280 |

281 |
282 |

 


285 |
286 | 287 | -------------------------------------------------------------------------------- /extras/doc/toc.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | Documentation for LXUSARTDMX.h 6 | 7 | 8 | 9 | 10 | 11 | 14 |
 
15 | 16 | 17 | 34 |
Header:
  LXUSARTDMX.h
18 | 19 |
20 | 21 | 22 |
Introduction
23 |
24 |
25 | 27 |
26 | Classes
28 |
29 |
31 | 32 | 33 |

 

35 |

36 | 37 | -------------------------------------------------------------------------------- /keywords.txt: -------------------------------------------------------------------------------- 1 | ####################################### 2 | # Syntax Coloring Map for LXUSARTDMX 3 | ####################################### 4 | 5 | 6 | ####################################### 7 | # Datatypes (KEYWORD1) 8 | ####################################### 9 | 10 | LXSerialDMX KEYWORD1 11 | 12 | ####################################### 13 | # Methods and Functions (KEYWORD2) 14 | ####################################### 15 | 16 | startOutput KEYWORD2 17 | startInput KEYWORD2 18 | stop KEYWORD2 19 | setDirectionPin KEYWORD2 20 | setMaxSlots KEYWORD2 21 | setSlot KEYWORD2 22 | getSlot KEYWORD2 23 | dmxData KEYWORD2 24 | setDataReceivedCallback KEYWORD2 25 | 26 | 27 | ####################################### 28 | # Constants (LITERAL1) 29 | ####################################### 30 | 31 | -------------------------------------------------------------------------------- /library.properties: -------------------------------------------------------------------------------- 1 | name=LXUSARTDMX 2 | version=1.0 3 | author=Claude Heintz 4 | maintainer=Claude Heintz 5 | sentence=DMX input/output driver for Arduino/AVR microcontrollers 6 | paragraph=With addition of external Max485 liner driver chip, enables DMX input/output using USART serial. 7 | category=Communication 8 | url=https://github.com/claudeheintz/LXUSARTDMX 9 | architectures=* 10 | -------------------------------------------------------------------------------- /src/LXUSARTDMX.cpp: -------------------------------------------------------------------------------- 1 | /**************************************************************************/ 2 | /*! 3 | @file LXUSARTDMX.cpp 4 | @author Claude Heintz 5 | @license BSD (see LXUSARTDMX.h) 6 | @copyright 2015-2016 by Claude Heintz 7 | 8 | DMX Driver for Arduino using USART. 9 | 10 | @section HISTORY 11 | 12 | v1.0 First release 13 | v1.1 - Consolidated input and output into single class 14 | */ 15 | /**************************************************************************/ 16 | #include "pins_arduino.h" 17 | #include "LXUSARTDMX.h" 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | LXUSARTDMX LXSerialDMX; 24 | 25 | // ***************** define registers, flags and interrupts **************** 26 | 27 | // processors with single UART such AT328 processor (Uno) 28 | // should not define USE_UART_1 29 | // Uncomment the following to use UART1: 30 | //#define USE_UART_1 31 | 32 | // USE_UART_1 should be defined for Teensy 2.0++, Leonardo, Yun 33 | #if defined(__AVR_AT90USB1286__) || defined (__AVR_ATmega32U4__) 34 | #define USE_UART_1 35 | #endif 36 | 37 | 38 | #if !defined(USE_UART_1) // definitions for UART0 39 | // for AT328 see datasheet pg 194 40 | 41 | #define LXUCSRA UCSR0A // USART register A 42 | #define LXTXC TXC0 // tx buffer empty 43 | #define LXUDRE UDRE0 // data ready 44 | #define LXFE FE0 // frame error 45 | #define LXU2X U2X0 // double speed 46 | 47 | #define LXUCSRB UCSR0B // USART register B 48 | #define LXRXCIE RXCIE0 // rx interrupt enable bit 49 | #define LXTXCIE TXCIE0 // tx interrupt enable bit 50 | #define LXRXEN RXEN0 // rx enable bit 51 | #define LXTXEN TXEN0 // tx enable bit 52 | 53 | #define LXUCSRC UCSR0C // USART register C 54 | #define LXUSBS0 USBS0 // stop bits 55 | #define LXUCSZ0 UCSZ00 // length 56 | #define LXUPM0 UPM00 // parity 57 | #define LXUCSRRH UBRR0H // USART baud rate register msb 58 | #define LXUCSRRL UBRR0L // USARTbaud rate register msb 59 | #define LXUDR UDR0 // USART data register tx/rx 60 | 61 | #define LXUSART_RX_vect USART_RX_vect // RX ISR 62 | #define LXUSART_TX_vect USART_TX_vect // TX ISR 63 | 64 | #define BIT_FRAME_ERROR (1<>8); 173 | LXUCSRRL = (unsigned char) ((F_CLK + DMX_DATA_BAUD * 8L) / (DMX_DATA_BAUD * 16L) - 1); 174 | LXUCSRA &= ~BIT_2X_SPEED; 175 | 176 | LXUDR = 0x0; //USART send register 177 | _shared_dmx_data = dmxData(); 178 | _shared_dmx_state = DMX_STATE_BREAK; 179 | 180 | LXUCSRC = FORMAT_8N2; //set length && stopbits (no parity) 181 | LXUCSRB |= BIT_TX_ENABLE | BIT_TX_ISR_ENABLE; //enable tx and tx interrupt 182 | _interrupt_status = ISR_OUTPUT_ENABLED; 183 | } 184 | } 185 | 186 | // ***** start ***** 187 | // sets up baud rate, bits and parity 188 | // sets globals accessed in ISR 189 | // enables transmission and tx interrupt 190 | 191 | void LXUSARTDMX::startInput ( void ) { 192 | if ( _direction_pin != DIRECTION_PIN_NOT_USED ) { 193 | digitalWrite(_direction_pin, LOW); 194 | } 195 | if ( _interrupt_status == ISR_OUTPUT_ENABLED ) { 196 | stop(); 197 | } 198 | if ( _interrupt_status == ISR_DISABLED ) { //prevent messing up sequence if already started... 199 | LXUCSRRH = (unsigned char)(((F_CLK + DMX_DATA_BAUD * 8L) / (DMX_DATA_BAUD * 16L) - 1)>>8); 200 | LXUCSRRL = (unsigned char) ((F_CLK + DMX_DATA_BAUD * 8L) / (DMX_DATA_BAUD * 16L) - 1); 201 | LXUCSRA &= ~BIT_2X_SPEED; 202 | 203 | _shared_dmx_data = dmxData(); 204 | _shared_dmx_state = DMX_STATE_IDLE; 205 | _shared_dmx_slot = 0; 206 | 207 | LXUCSRC = FORMAT_8N2; //set length && stopbits (no parity) 208 | LXUCSRB |= BIT_RX_ENABLE | BIT_RX_ISR_ENABLE; //enable tx and tx interrupt 209 | _interrupt_status = ISR_INPUT_ENABLED; 210 | } 211 | } 212 | 213 | // ***** stop ***** 214 | // disables interrupts 215 | 216 | void LXUSARTDMX::stop ( void ) { 217 | if ( _interrupt_status == ISR_OUTPUT_ENABLED ) { 218 | LXUCSRB &= ~BIT_TX_ISR_ENABLE; //disable tx interrupt 219 | LXUCSRB &= ~BIT_TX_ENABLE; //disable tx enable 220 | } else if ( _interrupt_status == ISR_INPUT_ENABLED ) { 221 | LXUCSRB &= ~BIT_RX_ISR_ENABLE; //disable rx interrupt 222 | LXUCSRB &= ~BIT_RX_ENABLE; //disable rx enable 223 | } 224 | _interrupt_status = ISR_DISABLED; 225 | } 226 | 227 | void LXUSARTDMX::setDirectionPin( uint8_t pin ) { 228 | _direction_pin = pin; 229 | pinMode(_direction_pin, OUTPUT); 230 | } 231 | 232 | // ***** setMaxSlots ***** 233 | // sets the number of slots sent per DMX frame 234 | // defaults to 512 or DMX_MAX_SLOTS 235 | // should be no less DMX_MIN_SLOTS slots 236 | // the DMX standard specifies min break to break time no less than 1024 usecs 237 | // at 44 usecs per slot ~= 24 238 | 239 | void LXUSARTDMX::setMaxSlots (int slots) { 240 | _shared_max_slots = max(slots, DMX_MIN_SLOTS); 241 | } 242 | 243 | // ***** getSlot ***** 244 | // reads the value of a slot 245 | // see buffering note for ISR below 246 | 247 | uint8_t LXUSARTDMX::getSlot (int slot) { 248 | return _dmxData[slot]; 249 | } 250 | 251 | // ***** setSlot ***** 252 | // sets the output value of a slot 253 | 254 | void LXUSARTDMX::setSlot (int slot, uint8_t value) { 255 | _dmxData[slot] = value; 256 | } 257 | 258 | // ***** dmxData ***** 259 | // pointer to data buffer 260 | 261 | uint8_t* LXUSARTDMX::dmxData(void) { 262 | return &_dmxData[0]; 263 | } 264 | 265 | // ***** setDataReceivedCallback ***** 266 | // sets pointer to function that is called 267 | // on the break after a frame has been received 268 | // whatever happens in this function should be quick 269 | // ie set a flag so that processing of the received data happens 270 | // outside of the ISR. 271 | 272 | 273 | void LXUSARTDMX::setDataReceivedCallback(LXRecvCallback callback) { 274 | _shared_receive_callback = callback; 275 | } 276 | 277 | 278 | //************************************************************************************ 279 | // ************************ TX ISR (transmit interrupt service routine) ************* 280 | // 281 | // this routine is called when USART transmission is complete 282 | // what this does is to send the next byte 283 | // when that byte is done being sent, the ISR is called again 284 | // and the cycle repeats... 285 | // until _shared_max_slots worth of bytes have been sent on succesive triggers of the ISR 286 | // and then on the next ISR... 287 | // the break/mark after break is sent at a different speed 288 | // and then on the next ISR... 289 | // the start code is sent 290 | // and then on the next ISR... 291 | // the next data byte is sent 292 | // and the cycle repeats... 293 | 294 | 295 | ISR (LXUSART_TX_vect) { 296 | switch ( _shared_dmx_state ) { 297 | 298 | case DMX_STATE_BREAK: 299 | // set the slower baud rate and send the break 300 | LXUCSRRH = (unsigned char)(((F_CLK + DMX_BREAK_BAUD * 8L) / (DMX_BREAK_BAUD * 16L) - 1)>>8); 301 | LXUCSRRL = (unsigned char) ((F_CLK + DMX_BREAK_BAUD * 8L) / (DMX_BREAK_BAUD * 16L) - 1); 302 | LXUCSRA &= ~BIT_2X_SPEED; 303 | LXUCSRC = FORMAT_8E1; 304 | _shared_dmx_state = DMX_STATE_START; 305 | LXUDR = 0x0; 306 | break; // <- DMX_STATE_BREAK 307 | 308 | case DMX_STATE_START: 309 | // set the baud to full speed and send the start code 310 | LXUCSRRH = (unsigned char)(((F_CLK + DMX_DATA_BAUD * 8L) / (DMX_DATA_BAUD * 16L) - 1)>>8); 311 | LXUCSRRL = (unsigned char) ((F_CLK + DMX_DATA_BAUD * 8L) / (DMX_DATA_BAUD * 16L) - 1); 312 | LXUCSRA &= ~BIT_2X_SPEED; 313 | LXUCSRC = FORMAT_8N2; 314 | _shared_dmx_slot = 0; 315 | LXUDR = _shared_dmx_data[_shared_dmx_slot++]; //send next slot (start code) 316 | _shared_dmx_state = DMX_STATE_DATA; 317 | break; // <- DMX_STATE_START 318 | 319 | case DMX_STATE_DATA: 320 | // send the next data byte until the end is reached 321 | LXUDR = _shared_dmx_data[_shared_dmx_slot++]; //send next slot 322 | if ( _shared_dmx_slot > _shared_max_slots ) { 323 | _shared_dmx_state = DMX_STATE_BREAK; 324 | } 325 | break; // <- DMX_STATE_DATA 326 | } 327 | } 328 | 329 | //*********************************************************************************** 330 | // ************************ RX ISR (receive interrupt service routine) ************* 331 | // 332 | // this routine is called when USART receives data 333 | // wait for break: if have previously read data call callback function 334 | // then on next receive: check start code 335 | // then on next receive: read data until done (in which case idle) 336 | // 337 | // NOTE: data is not double buffered 338 | // so a complete single frame is not guaranteed 339 | // the ISR will continue to read the next frame into the buffer 340 | 341 | ISR (LXUSART_RX_vect) { 342 | uint8_t status_register = LXUCSRA; 343 | uint8_t incoming_byte = LXUDR; 344 | 345 | if ( status_register & BIT_FRAME_ERROR ) { 346 | _shared_dmx_state = DMX_STATE_BREAK; 347 | if ( _shared_dmx_slot > 0 ) { 348 | if ( _shared_receive_callback != NULL ) { 349 | _shared_receive_callback(_shared_dmx_slot); 350 | } 351 | } 352 | _shared_dmx_slot = 0; 353 | return; 354 | } 355 | 356 | switch ( _shared_dmx_state ) { 357 | 358 | case DMX_STATE_BREAK: 359 | if ( incoming_byte == 0 ) { //start code == zero (DMX) 360 | _shared_dmx_state = DMX_STATE_DATA; 361 | _shared_dmx_slot = 1; 362 | } else { 363 | _shared_dmx_state = DMX_STATE_IDLE; 364 | } 365 | break; 366 | 367 | case DMX_STATE_DATA: 368 | _shared_dmx_data[_shared_dmx_slot++] = incoming_byte; 369 | if ( _shared_dmx_slot > DMX_MAX_SLOTS ) { 370 | _shared_dmx_state = DMX_STATE_IDLE; // go to idle, wait for next break 371 | } 372 | break; 373 | } 374 | } -------------------------------------------------------------------------------- /src/LXUSARTDMX.h: -------------------------------------------------------------------------------- 1 | /* LXArduinoDMX.h 2 | Copyright 2015-2016 by Claude Heintz Design 3 | 4 | ----------------------------------- License ----------------------------------- 5 | LXArduinoDMX is free software: you can redistribute it and/or modify 6 | it for any purpose provided the following conditions are met: 7 | 8 | 1) Redistributions of source code must retain the above copyright notice, 9 | this list of conditions and the following disclaimer. 10 | 11 | 2) Redistributions in binary form must reproduce the above copyright notice, 12 | this list of conditions and the following disclaimer in the documentation 13 | and/or other materials provided with the distribution. 14 | 15 | 3) Neither the name of the copyright owners nor the names of its contributors 16 | may be used to endorse or promote products derived from this software 17 | without specific prior written permission. 18 | 19 | LXArduinoDMX is distributed in the hope that it will be useful, 20 | but WITHOUT ANY WARRANTY; without even the implied warranty of 21 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 22 | 23 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 24 | INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 25 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 26 | HOLDERS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 27 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 | OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 29 | AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 31 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 | ----------------------------------------------------------------------------------- 33 | 34 | The LXArduinoDMX library supports output and input of DMX using the USART 35 | serial output of an Arduino's microcontroller. With microcontrollers with a single 36 | USART such as the AT328 used by an Arduino Uno, this means that the Serial library 37 | conflicts with LXArduinoDMX and cannot be used. Other chips have more than one 38 | USART and can support both Serial and LXArduinoDMX by specifying that LXArduinoDMX uses 39 | USART1 instead of USART0. 40 | 41 | This is the circuit for a simple unisolated DMX Shield 42 | that could be used with LXArdunoDMX. It uses a line driver IC 43 | to convert the output from the Arduino to DMX: 44 | 45 | Arduino Pin 46 | | SN 75176 A or MAX 481CPA 47 | V _______________ 48 | | | 1 Vcc 8 |------(+5v) 49 | RX (0) |----------------------| | DMX Output 50 | | +----| 2 B 7 |---------------- Pin 2 51 | | | | | 52 | (2) |----------------------| 3 DE A 6 |---------------- Pin 3 53 | | | | 54 | TX (1) |----------------------| 4 DI Gnd 5 |---+------------ Pin 1 55 | | | 56 | | (GND) 57 | 58 | Data Enable (DE) and Inverted Read Enable (!RE) can be wired to +5v for output 59 | or Gnd for input, if direction switching is not needed. 60 | 61 | 62 | */ 63 | 64 | #ifndef LXusartDMX_H 65 | #define LXusartDMX_H 66 | 67 | #include 68 | #include 69 | 70 | #define DMX_MIN_SLOTS 24 71 | #define DMX_MAX_SLOTS 512 72 | 73 | #define DIRECTION_PIN_NOT_USED 255 74 | 75 | typedef void (*LXRecvCallback)(int); 76 | 77 | /*! 78 | @class LXUSARTDMX 79 | @abstract 80 | LXUSARTDMX is a driver for sending or receiving DMX using an AVR family microcontroller 81 | UART0 RX pin 0, TX pin 1 82 | 83 | LXUSARTDMX output mode continuously sends DMX once its interrupts have been enabled using startOutput(). 84 | Use setSlot() to set the level value for a particular DMX dimmer/address/channel. 85 | 86 | LXUSARTDMX input mode continuously receives DMX once its interrupts have been enabled using startInput() 87 | Use getSlot() to read the level value for a particular DMX dimmer/address/channel. 88 | 89 | LXUSARTDMX is used with a single instance called LXSerialDMX . 90 | */ 91 | 92 | class LXUSARTDMX { 93 | 94 | public: 95 | LXUSARTDMX ( void ); 96 | ~LXUSARTDMX ( void ); 97 | 98 | /*! 99 | * @brief starts interrupt that continuously sends DMX data 100 | * @discussion sets up baud rate, bits and parity, 101 | * sets globals accessed in ISR, 102 | * enables transmission and tx interrupt 103 | */ 104 | void startOutput( void ); 105 | 106 | /*! 107 | * @brief starts interrupt that continuously reads DMX data 108 | * @discussion sets up baud rate, bits and parity, 109 | * sets globals accessed in ISR, 110 | * enables receive and rx interrupt 111 | */ 112 | void startInput( void ); 113 | 114 | /*! 115 | * @brief disables USART 116 | */ 117 | void stop( void ); 118 | 119 | /*! 120 | * @brief optional utility sets the pin used to control driver chip's 121 | * DE (data enable) line, HIGH for output, LOW for input. 122 | * @param pin to be automatically set for input/output direction 123 | */ 124 | void setDirectionPin( uint8_t pin ); 125 | 126 | /*! 127 | * @brief Sets the number of slots (aka addresses or channels) sent per DMX frame. 128 | * @discussion defaults to 512 or DMX_MAX_SLOTS and should be no less DMX_MIN_SLOTS slots. 129 | * The DMX standard specifies min break to break time no less than 1024 usecs. 130 | * At 44 usecs per slot ~= 24 131 | * @param slot the highest slot number (~24 to 512) 132 | */ 133 | void setMaxSlots (int slot); 134 | 135 | /*! 136 | * @brief reads the value of a slot/address/channel 137 | * @discussion NOTE: Data is not double buffered. 138 | * So a complete single frame is not guaranteed. 139 | * The ISR continuously reads the next frame into the buffer 140 | * @return level (0-255) 141 | */ 142 | uint8_t getSlot (int slot); 143 | 144 | /*! 145 | * @brief Sets the output value of a slot 146 | * @param slot number of the slot/address/channel (1-512) 147 | * @param value level (0-255) 148 | */ 149 | void setSlot (int slot, uint8_t value); 150 | 151 | /*! 152 | * @brief provides direct access to data array 153 | * @return pointer to dmx array 154 | */ 155 | uint8_t* dmxData(void); 156 | 157 | /*! 158 | * @brief Function called when DMX frame has been read 159 | * @discussion Sets a pointer to a function that is called 160 | * on the break after a DMX frame has been received. 161 | * Whatever happens in this function should be quick! 162 | * Best used to set a flag that is polled outside of ISR for available data. 163 | */ 164 | void setDataReceivedCallback(LXRecvCallback callback); 165 | 166 | private: 167 | /*! 168 | * @brief Indicates mode ISR_OUTPUT_ENABLED or ISR_INPUT_ENABLED or ISR_DISABLED 169 | */ 170 | uint8_t _interrupt_status; 171 | 172 | /*! 173 | * @brief pin used to control direction of output driver chip 174 | */ 175 | uint8_t _direction_pin; 176 | 177 | /*! 178 | * @brief Array of dmx data including start code 179 | */ 180 | uint8_t _dmxData[DMX_MAX_SLOTS+1]; 181 | }; 182 | 183 | extern LXUSARTDMX LXSerialDMX; 184 | 185 | #endif // ifndef LXArduinoDMX_H --------------------------------------------------------------------------------