├── .github └── workflows │ ├── arduino-checks.yml │ └── codespell.yml ├── LICENSE ├── README.md ├── examples ├── RDMIntoDMXOut.ino └── RDMSerialRecv │ └── RDMSerialRecv.ino ├── keywords.txt ├── library.properties └── src ├── DMXSerial2.cpp ├── DMXSerial2.h └── rdm.h /.github/workflows/arduino-checks.yml: -------------------------------------------------------------------------------- 1 | # This is a basic workflow to help you get started with Actions for Arduino library projects 2 | 3 | name: Arduino Library Checks 4 | 5 | # Controls when the action will run. 6 | on: 7 | # Triggers the workflow on push or pull request events but only for the develop branch 8 | push: 9 | branches: [develop,master] 10 | pull_request: 11 | branches: [develop,master] 12 | 13 | # Allows you to run this workflow manually from the Actions tab 14 | workflow_dispatch: 15 | 16 | schedule: 17 | # Run every Tuesday at 6 AM UTC to catch breakage caused by new rules added to Arduino Lint or changes in the tools. 18 | - cron: "0 6 * * TUE" 19 | 20 | jobs: 21 | 22 | # This defines a job for checking the Arduino library format specifications 23 | # see 24 | lint: 25 | name: check library format 26 | runs-on: ubuntu-latest 27 | continue-on-error: true 28 | 29 | steps: 30 | - uses: actions/checkout@v2 31 | 32 | # Arduino - lint 33 | - name: Arduino-lint 34 | uses: arduino/arduino-lint-action@v1 35 | with: 36 | compliance: strict 37 | library-manager: update 38 | verbose: false 39 | 40 | # These jobs are used to compile the examples for the specific processor/board. 41 | # see 42 | compile-uno: 43 | name: compile uno examples 44 | runs-on: ubuntu-latest 45 | continue-on-error: true 46 | 47 | steps: 48 | - uses: actions/checkout@v2 49 | 50 | # Compile Examples for UNO 51 | - name: Compile examples on uno 52 | uses: arduino/compile-sketches@v1 53 | with: 54 | verbose: true 55 | fqbn: arduino:avr:uno 56 | sketch-paths: | 57 | - 'examples/RDMSerialRecv' 58 | 59 | compile-leonardo: 60 | needs: compile-uno 61 | name: compile leonardo examples 62 | runs-on: ubuntu-latest 63 | continue-on-error: true 64 | 65 | steps: 66 | - uses: actions/checkout@v2 67 | 68 | - name: Compile for leonardo 69 | uses: arduino/compile-sketches@v1 70 | with: 71 | verbose: true 72 | fqbn: arduino:avr:leonardo 73 | sketch-paths: | 74 | - 'examples/RDMSerialRecv' 75 | 76 | compile-mega: 77 | needs: compile-uno 78 | name: compile examples for mega 79 | runs-on: ubuntu-latest 80 | continue-on-error: true 81 | 82 | steps: 83 | - uses: actions/checkout@v2 84 | 85 | - name: Compile for mega 86 | uses: arduino/compile-sketches@v1 87 | with: 88 | verbose: true 89 | fqbn: arduino:avr:mega 90 | sketch-paths: | 91 | - 'examples/RDMSerialRecv' 92 | -------------------------------------------------------------------------------- /.github/workflows/codespell.yml: -------------------------------------------------------------------------------- 1 | # GitHub Action to automate the identification of common misspellings in text files. 2 | # https://github.com/codespell-project/actions-codespell 3 | # https://github.com/codespell-project/codespell 4 | name: codespell 5 | on: [push, pull_request] 6 | jobs: 7 | codespell: 8 | name: Check for spelling errors 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: actions/checkout@v2 12 | - uses: codespell-project/actions-codespell@master 13 | with: 14 | check_filenames: true 15 | skip: ./.git 16 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2005-2020, Matthias Hertel, http://www.mathertel.de/ 4 | 5 | All rights reserved. 6 | 7 | Redistribution and use in source and binary forms, with or without 8 | modification, are permitted provided that the following conditions are met: 9 | 10 | 1. Redistributions of source code must retain the above copyright notice, this 11 | list of conditions and the following disclaimer. 12 | 13 | 2. Redistributions in binary form must reproduce the above copyright notice, 14 | this list of conditions and the following disclaimer in the documentation 15 | and/or other materials provided with the distribution. 16 | 17 | 3. Neither the name of the copyright holder nor the names of its 18 | contributors may be used to endorse or promote products derived from 19 | this software without specific prior written permission. 20 | 21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 22 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 24 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 25 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 28 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Build Status](https://travis-ci.org/mathertel/DmxSerial2.svg?branch=master)](https://travis-ci.org/mathertel/DmxSerial2) 2 | 3 | DmxSerial2 4 | ========== 5 | 6 | An Arduino library for sending and receiving DMX RDM packets. 7 | 8 | You can find more detail on this library at http://www.mathertel.de/Arduino/DMXSerial2.aspx. 9 | 10 | A suitable hardware is the Arduino platform plus a shield for the DMX/RDM physical protocol implementation. 11 | You can find such a shield at: http://www.mathertel.de/Arduino/DMXShield.aspx. 12 | 13 | N.B. This library writes to the EEPROM to store your DMX start address and other parameters during a repower. 14 | -------------------------------------------------------------------------------- /examples/RDMIntoDMXOut.ino: -------------------------------------------------------------------------------- 1 | // - - - - - 2 | // DmxSerial2 - A hardware supported interface to DMX and RDM. 3 | // RDMSerialRecv.ino: Sample RDM application. 4 | // 5 | // Copyright (c) 2011-2013 by Matthias Hertel, http://www.mathertel.de 6 | // This work is licensed under a BSD style license. See http://www.mathertel.de/License.aspx 7 | // 8 | // The following RDM commands are implemented here: 9 | // E120_LAMP_HOURS 10 | // E120_DEVICE_HOURS 11 | // 12 | // More documentation and samples are available at http://www.mathertel.de/Arduino 13 | // - - - - - 14 | 15 | #include 16 | #include 17 | #include 18 | 19 | // see DMXSerial2.h for the definition of the fields of this structure 20 | //const uint16_t my_pids[] = {E120_DEVICE_HOURS, E120_LAMP_HOURS}; 21 | const uint16_t my_pids[] = {}; 22 | struct RDMINIT rdmInit = { 23 | "Company Name", // Manufacturer Label 24 | 1, // Device Model ID 25 | "RDM Module", // Device Model Label 26 | 3, // footprint 27 | (sizeof(my_pids)/sizeof(uint16_t)), my_pids 28 | }; 29 | 30 | uint16_t startAddress = 0; 31 | int maxSize = 3; 32 | 33 | void setup () { 34 | DMXSerial2.init(&rdmInit, processCommand); 35 | 36 | pinMode(9, OUTPUT); // defined isIdentifyMode pin for output 37 | digitalWrite(9, LOW); 38 | DmxSimple.usePin(3); // Use Digital pin 3 for DMXSimple output 39 | DmxSimple.maxChannel(maxSize); //set the maxChannel for DMXSimple to the same as the RDM module's max size 40 | 41 | } // setup() 42 | 43 | 44 | void loop() { 45 | if (DMXSerial2.isIdentifyMode()) { 46 | 47 | digitalWrite(9, HIGH); // indicator light for the Identify mode 48 | 49 | } else { 50 | startAddress = DMXSerial2.getStartAddress(); // retrieve current RDM start address 51 | 52 | for (int i = 0; i < maxSize; i++){ // for all DMX packets sent to addresses up to maxSize, forward to DMX out 53 | 54 | DmxSimple.write(i + 1, DMXSerial2.readRelative(i)); //Grab all DMX packets sent to RDM address and forward to DMX out 55 | } 56 | 57 | digitalWrite(9, LOW); 58 | } 59 | 60 | DMXSerial2.tick(); 61 | } // loop() 62 | 63 | // This function was registered to the DMXSerial2 library in the initRDM call. 64 | // Here device specific RDM Commands are implemented. 65 | bool8 processCommand(struct RDMDATA *rdm, uint16_t *nackReason) 66 | { 67 | byte CmdClass = rdm->CmdClass; 68 | uint16_t Parameter = rdm->Parameter; 69 | bool8 handled = false; 70 | 71 | if (CmdClass == E120_SET_COMMAND) { 72 | *nackReason = E120_NR_UNSUPPORTED_COMMAND_CLASS; 73 | } 74 | 75 | return handled; 76 | } 77 | -------------------------------------------------------------------------------- /examples/RDMSerialRecv/RDMSerialRecv.ino: -------------------------------------------------------------------------------- 1 | // - - - - - 2 | // DmxSerial2 - A hardware supported interface to DMX and RDM. 3 | // RDMSerialRecv.ino: Sample RDM application. 4 | // 5 | // Copyright (c) 2011-2013 by Matthias Hertel, http://www.mathertel.de 6 | // This work is licensed under a BSD style license. See http://www.mathertel.de/License.aspx 7 | // 8 | // This Arduino project is a sample application for the DMXSerial2 library that shows 9 | // how a 3 channel receiving RDM client can be implemented. 10 | // The 3 channels are used for PWM Output: 11 | // address (startAddress) + 0 (red) -> PWM Port 9 12 | // address (startAddress) + 1 (green) -> PWM Port 6 13 | // address (startAddress) + 2 (blue) -> PWM Port 5 14 | // 15 | // This sample shows how Device specific RDM Commands are handled in the processCommand function. 16 | // The following RDM commands are implemented here: 17 | // E120_LAMP_HOURS 18 | // E120_DEVICE_HOURS 19 | // 20 | // More documentation and samples are available at http://www.mathertel.de/Arduino 21 | // 06.12.2012 created from DMXSerialRecv sample. 22 | // 09.12.2012 added first RDM response. 23 | // 22.01.2013 first published version to support RDM 24 | // 03.03.2013 Using DMXSerial2 as a library 25 | // 15.05.2013 Arduino Leonard and Arduino MEGA compatibility 26 | // 15.12.2013 ADD: output information on a LEONARDO board by using the #define SERIAL_DEBUG definition 27 | // If you have to save pgm space you can delete the inner lines of this "#if" blocks 28 | // 24.01.2014 Peter Newman/Sean Sill: Get device specific PIDs returning properly in supportedParameters 29 | // 24.01.2014 Peter Newman: Make the device specific PIDs compliant with the OLA RDM Tests. Add device model ID option 30 | // 12.04.2015 change of using datatype boolean to bool8. 31 | // 25.05.2017 Stefan Krupop: Add support for sensors 32 | // 21.08.2018 improvements and typo by Peter Newman 33 | // 31.10.2018 Remove unnecessary #include by Graham Hanson 34 | // - - - - - 35 | 36 | #include 37 | 38 | // uncomment this line for enabling information on a LEONARD board. 39 | // #define SERIAL_DEBUG 40 | 41 | // Constants for demo program 42 | 43 | const int RedPin = 9; // PWM output pin for Red Light. 44 | const int GreenPin = 6; // PWM output pin for Green Light. 45 | const int BluePin = 5; // PWM output pin for Blue Light. 46 | 47 | // color: #203050 * 2 48 | #define RedDefaultLevel 0x20 * 2 49 | #define GreenDefaultLevel 0x30 * 2 50 | #define BlueDefaultLevel 0x50 * 2 51 | 52 | // define the RGB output color 53 | void rgb(byte r, byte g, byte b) 54 | { 55 | analogWrite(RedPin, r); 56 | analogWrite(GreenPin, g); 57 | analogWrite(BluePin, b); 58 | } // rgb() 59 | 60 | // see DMXSerial2.h for the definition of the fields of this structure 61 | const uint16_t my_pids[] = {E120_DEVICE_HOURS, E120_LAMP_HOURS}; 62 | struct RDMINIT rdmInit = { 63 | "mathertel.de", // Manufacturer Label 64 | 1, // Device Model ID 65 | "Arduino RDM Device", // Device Model Label 66 | 3, // footprint 67 | (sizeof(my_pids)/sizeof(uint16_t)), my_pids, 68 | 0, NULL 69 | }; 70 | 71 | 72 | void setup () { 73 | 74 | #if defined(SERIAL_DEBUG) 75 | // The Serial port can be used on Arduino Leonard Boards for debugging purpose 76 | // because it is not mapped to the real serial port of the ATmega32U4 chip but to the USB port. 77 | // Don't use that on Arduino Uno, 2009,... boards based on ATmega328 or ATmega168 chips. 78 | Serial.begin(9600); 79 | while (!Serial) ; 80 | Serial.println("starting..."); 81 | #endif 82 | 83 | // initialize the Serial interface to be used as an RDM Device Node. 84 | // There are several constants that have to be passed to the library so it can reposonse to the 85 | // corresponding commands for itself. 86 | DMXSerial2.init(&rdmInit, processCommand); 87 | 88 | uint16_t start = DMXSerial2.getStartAddress(); 89 | #if defined(SERIAL_DEBUG) 90 | Serial.print("Listening on DMX address #"); Serial.println(start); 91 | #endif 92 | 93 | // set default values to dark red 94 | // this color will be shown when no signal is present for the first 5 seconds. 95 | DMXSerial2.write(start + 0, 30); 96 | DMXSerial2.write(start + 1, 0); 97 | DMXSerial2.write(start + 2, 0); 98 | 99 | // enable pwm outputs 100 | pinMode(RedPin, OUTPUT); // sets the digital pin as output 101 | pinMode(GreenPin, OUTPUT); 102 | pinMode(BluePin, OUTPUT); 103 | 104 | #if defined(SERIAL_DEBUG) 105 | // output the current DeviceID 106 | 107 | DEVICEID thisDevice; 108 | DMXSerial2.getDeviceID(thisDevice); 109 | 110 | Serial.print("This Device is: "); 111 | if (thisDevice[0] < 0x10) Serial.print('0'); Serial.print(thisDevice[0], HEX); 112 | if (thisDevice[1] < 0x10) Serial.print('0'); Serial.print(thisDevice[1], HEX); 113 | Serial.print(":"); 114 | if (thisDevice[2] < 0x10) Serial.print('0'); Serial.print(thisDevice[2], HEX); 115 | if (thisDevice[3] < 0x10) Serial.print('0'); Serial.print(thisDevice[3], HEX); 116 | if (thisDevice[4] < 0x10) Serial.print('0'); Serial.print(thisDevice[4], HEX); 117 | if (thisDevice[5] < 0x10) Serial.print('0'); Serial.print(thisDevice[5], HEX); 118 | Serial.println(); 119 | #endif 120 | 121 | } // setup() 122 | 123 | 124 | void loop() { 125 | // Calculate how long no data backet was received 126 | unsigned long lastPacket = DMXSerial2.noDataSince(); 127 | 128 | if (DMXSerial2.isIdentifyMode()) { 129 | // RDM command for identification was sent. 130 | // Blink the device. 131 | unsigned long now = millis(); 132 | if (now % 1000 < 500) { 133 | rgb(200, 200, 200); 134 | } else { 135 | rgb(0, 0, 0); 136 | } // if 137 | 138 | } else if (lastPacket < 30000) { 139 | // read recent DMX values and set pwm levels 140 | analogWrite(RedPin, DMXSerial2.readRelative(0)); 141 | analogWrite(GreenPin, DMXSerial2.readRelative(1)); 142 | analogWrite(BluePin, DMXSerial2.readRelative(2)); 143 | 144 | } else { 145 | #if defined(SERIAL_DEBUG) 146 | Serial.println("no signal since 30 secs."); 147 | #endif 148 | // Show default color, when no data was received since 30 seconds or more. 149 | analogWrite(RedPin, RedDefaultLevel); 150 | analogWrite(GreenPin, GreenDefaultLevel); 151 | analogWrite(BluePin, BlueDefaultLevel); 152 | } // if 153 | 154 | // check for unhandled RDM commands 155 | DMXSerial2.tick(); 156 | } // loop() 157 | 158 | 159 | // This function was registered to the DMXSerial2 library in the initRDM call. 160 | // Here device specific RDM Commands are implemented. 161 | bool8 processCommand(struct RDMDATA *rdm, uint16_t *nackReason) 162 | { 163 | byte CmdClass = rdm->CmdClass; // command class 164 | uint16_t Parameter = rdm->Parameter; // parameter ID 165 | bool8 handled = false; 166 | 167 | // This is a sample of how to return some device specific data 168 | if (Parameter == SWAPINT(E120_DEVICE_HOURS)) { // 0x0400 169 | if (CmdClass == E120_GET_COMMAND) { 170 | if (rdm->DataLength > 0) { 171 | // Unexpected data 172 | *nackReason = E120_NR_FORMAT_ERROR; 173 | } else if (rdm->SubDev != 0) { 174 | // No sub-devices supported 175 | *nackReason = E120_NR_SUB_DEVICE_OUT_OF_RANGE; 176 | } else { 177 | rdm->DataLength = 4; 178 | rdm->Data[0] = 0; 179 | rdm->Data[1] = 0; 180 | rdm->Data[2] = 2; 181 | rdm->Data[3] = 0; 182 | handled = true; 183 | } 184 | } else if (CmdClass == E120_SET_COMMAND) { 185 | // This device doesn't support set 186 | *nackReason = E120_NR_UNSUPPORTED_COMMAND_CLASS; 187 | } 188 | 189 | } else if (Parameter == SWAPINT(E120_LAMP_HOURS)) { // 0x0401 190 | if (CmdClass == E120_GET_COMMAND) { 191 | if (rdm->DataLength > 0) { 192 | // Unexpected data 193 | *nackReason = E120_NR_FORMAT_ERROR; 194 | } else if (rdm->SubDev != 0) { 195 | // No sub-devices supported 196 | *nackReason = E120_NR_SUB_DEVICE_OUT_OF_RANGE; 197 | } else { 198 | rdm->DataLength = 4; 199 | rdm->Data[0] = 0; 200 | rdm->Data[1] = 0; 201 | rdm->Data[2] = 0; 202 | rdm->Data[3] = 1; 203 | handled = true; 204 | } 205 | } else if (CmdClass == E120_SET_COMMAND) { 206 | // This device doesn't support set 207 | *nackReason = E120_NR_UNSUPPORTED_COMMAND_CLASS; 208 | } 209 | } // if 210 | 211 | return handled; 212 | } // processCommand 213 | 214 | 215 | // End. 216 | 217 | -------------------------------------------------------------------------------- /keywords.txt: -------------------------------------------------------------------------------- 1 | ####################################### 2 | # Syntax Coloring Map for DMXSerial2 3 | ####################################### 4 | 5 | 6 | ####################################### 7 | # Datatypes (KEYWORD1) 8 | ####################################### 9 | 10 | RDMDATA KEYWORD1 11 | DMXMode KEYWORD1 12 | boolean KEYWORD1 13 | byte KEYWORD1 14 | uint16_t KEYWORD1 15 | 16 | ####################################### 17 | # Methods and Functions (KEYWORD2) 18 | ####################################### 19 | 20 | 21 | init KEYWORD2 22 | initRDM KEYWORD2 23 | maxChannel KEYWORD2 24 | read KEYWORD2 25 | readRelative KEYWORD2 26 | write KEYWORD2 27 | noDataSince KEYWORD2 28 | getStartAddress KEYWORD2 29 | isIdentifyMode KEYWORD2 30 | getStartAddress KEYWORD2 31 | getFootprint KEYWORD2 32 | attachRDMCallback KEYWORD2 33 | attachSensorCallback KEYWORD2 34 | tick KEYWORD2 35 | term KEYWORD2 36 | deviceLabel KEYWORD2 37 | 38 | ####################################### 39 | # Instances (KEYWORD2) 40 | ####################################### 41 | 42 | DMXSerial2 KEYWORD2 43 | 44 | 45 | ####################################### 46 | # Constants (LITERAL1) 47 | ####################################### 48 | 49 | DMXNone LITERAL1 50 | DMXError LITERAL1 51 | DMXController LITERAL1 52 | DMXReceiver LITERAL1 53 | RDMDeviceMode LITERAL1 -------------------------------------------------------------------------------- /library.properties: -------------------------------------------------------------------------------- 1 | name=DMXSerial2 2 | version=1.4.2 3 | author=Matthias Hertel 4 | maintainer=Matthias Hertel, http://www.mathertel.de 5 | sentence=Enables building DMX/RDM devices using the built-in serial port for Arduino boards UNO, Leonardo, Mega. 6 | paragraph=This is a library to implement a DMX devices that also listen and respond to RDM commands to retrieve information from the DMX devices. 7 | category=Communication 8 | url=http://www.mathertel.de/Arduino/DMXSerial2.aspx 9 | architectures=* 10 | -------------------------------------------------------------------------------- /src/DMXSerial2.cpp: -------------------------------------------------------------------------------- 1 | // - - - - - 2 | // DMXSerial2 - A hardware supported interface to DMX and RDM. 3 | // DMXSerial2.cpp: Library implementation file 4 | // 5 | // Copyright (c) 2011-2013 by Matthias Hertel, http://www.mathertel.de 6 | // This work is licensed under a BSD style license. See http://www.mathertel.de/License.aspx 7 | // 8 | // Documentation and samples are available at http://www.mathertel.de/Arduino 9 | // 10 | // IMPORTANT NOTE: Even when I name by implementation RDM, it is not guaranteed as a fully 11 | // compliant RDM implementation. Right now it is only a experimental version with regards 12 | // to the published information about RDM available on the internet. (see links inside the 13 | // code) 14 | // 15 | // History: 16 | // see DMXSerial2.h 17 | // - - - - - 18 | 19 | #include "Arduino.h" 20 | #include 21 | #include "DMXSerial2.h" 22 | 23 | #include 24 | 25 | // ----- Debugging ----- 26 | 27 | // to debug on an oscilloscope, enable this 28 | #undef SCOPEDEBUG 29 | #ifdef SCOPEDEBUG 30 | #define DmxTriggerPin 4 // low spike at beginning of start byte 31 | #define DmxISRPin 3 // low during interrupt service routines 32 | #endif 33 | 34 | // ----- Timing, Testing, and Debugging helpers ----- 35 | 36 | // Helper function for simply sending an RGB signal out to indicate a debug or testing condition. 37 | void rgbDebug(byte r, byte g, byte b) 38 | { 39 | analogWrite(9, r); 40 | analogWrite(6, g); 41 | analogWrite(5, b); 42 | } // rgbDebug() 43 | 44 | // TIMING: 45 | unsigned long _timingReceiveEnd; // when the last incoming byte was received 46 | 47 | // ----- Constants ----- 48 | 49 | // Define port & bit values for Hardware Serial Port. 50 | // The library works unchanged with the Arduino 2009, UNO and Arduino MGEA 2560 boards, 51 | // using the serial port 0 and the Arduino Leonardo using serial port 1 (on the 32u4 boards the first USART is USART1) 52 | 53 | // For using the serial port 1 on a Arduino MEGA 2560 board, enable the DMX_USE_PORT1 definition. 54 | // #define DMX_USE_PORT1 55 | 56 | #if !defined(DMX_USE_PORT1) && defined(USART_RX_vect) 57 | // These definitions are for using serial port 0 58 | #define UCSRnA UCSR0A // Control and Status Register A 59 | #define TXCn TXC0 60 | 61 | #define UCSRnB UCSR0B // USART Control and Status Register B 62 | 63 | #define RXCIEn RXCIE0 // Enable Receive Complete Interrupt 64 | #define TXCIEn TXCIE0 // Enable Transmission Complete Interrupt 65 | #define UDRIEn UDRIE0 // Enable Data Register Empty Interrupt 66 | #define RXENn RXEN0 // Enable Receiving 67 | #define TXENn TXEN0 // Enable Sending 68 | 69 | #define UCSRnC UCSR0C // Control and Status Register C 70 | #define USBSn USBS0 // Stop bit select 0=1bit, 1=2bits 71 | #define UCSZn0 UCSZ00 // Character size 00=5, 01=6, 10=7, 11=8 bits 72 | #define UPMn0 UPM00 // Parity setting 00=N, 10=E, 11=O 73 | 74 | #define UBRRnH UBRR0H // USART Baud Rate Register High 75 | #define UBRRnL UBRR0L // USART Baud Rate Register Low 76 | 77 | #define UDRn UDR0 // USART Data Register 78 | #define UDREn UDRE0 // USART Data Ready 79 | #define FEn FE0 // Frame Error 80 | 81 | #define USARTn_RX_vect USART_RX_vect 82 | #define USARTn_TX_vect USART_TX_vect 83 | #define USARTn_UDRE_vect USART_UDRE_vect 84 | 85 | #elif !defined(DMX_USE_PORT1) && defined(USART0_RX_vect) 86 | // These definitions are for using serial port 0 87 | #define UCSRnA UCSR0A // Control and Status Register A 88 | #define TXCn TXC0 89 | 90 | #define UCSRnB UCSR0B // USART Control and Status Register B 91 | 92 | #define RXCIEn RXCIE0 // Enable Receive Complete Interrupt 93 | #define TXCIEn TXCIE0 // Enable Transmission Complete Interrupt 94 | #define UDRIEn UDRIE0 // Enable Data Register Empty Interrupt 95 | #define RXENn RXEN0 // Enable Receiving 96 | #define TXENn TXEN0 // Enable Sending 97 | 98 | #define UCSRnC UCSR0C // Control and Status Register C 99 | #define USBSn USBS0 // Stop bit select 0=1bit, 1=2bits 100 | #define UCSZn0 UCSZ00 // Character size 00=5, 01=6, 10=7, 11=8 bits 101 | #define UPMn0 UPM00 // Parity setting 00=N, 10=E, 11=O 102 | 103 | #define UBRRnH UBRR0H // USART Baud Rate Register High 104 | #define UBRRnL UBRR0L // USART Baud Rate Register Low 105 | 106 | #define UDRn UDR0 // USART Data Register 107 | #define UDREn UDRE0 // USART Data Ready 108 | #define FEn FE0 // Frame Error 109 | 110 | #define USARTn_RX_vect USART0_RX_vect 111 | #define USARTn_TX_vect USART0_TX_vect 112 | #define USARTn_UDRE_vect USART0_UDRE_vect 113 | 114 | #elif defined(DMX_USE_PORT1) || defined(USART1_RX_vect) 115 | // These definitions are for using serial port 1 116 | #define UCSRnA UCSR1A // Control and Status Register A 117 | #define TXCn TXC1 118 | 119 | #define UCSRnB UCSR1B // USART Control and Status Register B 120 | 121 | #define RXCIEn RXCIE1 // Enable Receive Complete Interrupt 122 | #define TXCIEn TXCIE1 // Enable Transmission Complete Interrupt 123 | #define UDRIEn UDRIE1 // Enable Data Register Empty Interrupt 124 | #define RXENn RXEN1 // Enable Receiving 125 | #define TXENn TXEN1 // Enable Sending 126 | 127 | #define UCSRnC UCSR1C // Control and Status Register C 128 | #define USBSn USBS1 // Stop bit select 0=1bit, 1=2bits 129 | #define UCSZn0 UCSZ10 // Character size 00=5, 01=6, 10=7, 11=8 bits 130 | #define UPMn0 UPM10 // Parity setting 00=N, 10=E, 11=O 131 | 132 | #define UBRRnH UBRR1H // USART Baud Rate Register High 133 | #define UBRRnL UBRR1L // USART Baud Rate Register Low 134 | 135 | #define UDRn UDR1 // USART Data Register 136 | #define UDREn UDRE1 // USART Data Ready 137 | #define FEn FE1 // Frame Error 138 | 139 | #define USARTn_RX_vect USART1_RX_vect 140 | #define USARTn_TX_vect USART1_TX_vect 141 | #define USARTn_UDRE_vect USART1_UDRE_vect 142 | 143 | #endif 144 | 145 | 146 | // The formats for serial transmission, already defined in `Arduino.h` -> `HardwareSerial.h` 147 | // We do not include `HardwareSerial.h` but home it's still there in future version. 148 | // If not, here are the required values: 149 | 150 | #ifndef SERIAL_8N2 151 | #define SERIAL_8N2 ((1<= 92 usec break and >= 12 usec MAB 168 | // receiver must accept 88 us break and 8 us MAB 169 | // #define BREAKSPEED 100000 170 | 171 | // 45500 bit/sec is for RDM: gives aprox 22 usec per bit. 172 | // That gives 220 usec break and 22+ usec MAB 173 | #define BREAKSPEED 45500 174 | #define BREAKFORMAT SERIAL_8E1 175 | 176 | #define DMXSPEED 250000 177 | #define DMXFORMAT SERIAL_8N2 178 | 179 | // ----- Enumerations ----- 180 | 181 | // current state of receiving or sending DMX/RDM Bytes 182 | typedef enum { 183 | IDLE, // ignoring everything and wait for the next BREAK 184 | // or a valid RDM packet arrived, need for processing ! 185 | BREAK, // received a BREAK: now a new packet will start 186 | DMXDATA, // receiving DMX data into the _dmxData buffer 187 | RDMDATA, // receiving RDM data into the _rdm.buffer 188 | CHECKSUMH, // received the High byte of the _rdm.buffer checksum 189 | CHECKSUML // received the Low byte of the _rdm.buffer checksum 190 | } DMXReceivingState; 191 | 192 | // ----- Structs ----- 193 | 194 | // the special discovery response message 195 | struct DISCOVERYMSG { 196 | byte headerFE[7]; 197 | byte headerAA; 198 | byte maskedDevID[12]; 199 | byte checksum[4]; 200 | }; // struct DISCOVERYMSG 201 | 202 | 203 | // The DEVICEINFO structure (length = 19) has to be responded for E120_DEVICE_INFO 204 | // See http://rdm.openlighting.org/pid/display?manufacturer=0&pid=96 205 | struct DEVICEINFO { 206 | byte protocolMajor; 207 | byte protocolMinor; 208 | uint16_t deviceModel; 209 | uint16_t productCategory; 210 | uint32_t softwareVersion; 211 | uint16_t footprint; 212 | byte currentPersonality; 213 | byte personalityCount; 214 | uint16_t startAddress; 215 | uint16_t subDeviceCount; 216 | byte sensorCount; 217 | }; // struct DEVICEINFO 218 | 219 | 220 | // This structure is defined for mapping the values into the EEPROM 221 | struct EEPROMVALUES { 222 | byte sig1; // 0x6D signature 1, EPROM values are valid of both signatures match. 223 | byte sig2; // 0x68 signature 2 224 | uint16_t startAddress; // the DMX start address can be changed by a RDM command. 225 | char deviceLabel[DMXSERIAL_MAX_RDM_STRING_LENGTH]; // the device Label can be changed by a RDM command. Don't store the null in the EPROM for backwards compatibility. 226 | DEVICEID deviceID; // store the device ID to allow easy software updates. 227 | }; // struct EEPROMVALUES 228 | 229 | 230 | // ----- non class variables ----- 231 | // variables that are needed inside the interrupt routines so they are not declared in the class definition. 232 | 233 | // The Device ID must be a unique number for each individual device. 234 | // The first 2 bytes are specific for a manufacturer. 235 | // The list of codes is available at http://tsp.plasa.org/tsp/working_groups/CP/mfctrIDs.php 236 | // I use the number 0x0987 that is registered with myself. 237 | // For the other 4 bytes I use the date of creation: 0x2012 0x11 0x02 238 | // When the EEPROM values are valid, the _devID is taken from these values. 239 | // This allows software updates without losing a specific device ID. 240 | 241 | // It was an easy job to register a manufacturer id to myself as explained 242 | // on http://tsp.plasa.org/tsp/working_groups/CP/mfctrIDs.php. 243 | // Feel free to use my manufacturer id yourself if you promise only to use it 244 | // for experiments and never to put a real device. 245 | // If no valid EEPROM parameter block was found the following device ID is used and the last 2 bytes are randomized. 246 | // If you plan for more please request your own manufacturer id 247 | // and adjust the next line and the first two values in the array below that to use it: 248 | DEVICEID _devID = { 0x09, 0x87, 0x20, 0x12, 0x00, 0x00 }; 249 | 250 | // The Device ID for addressing all devices of a manufacturer. 251 | DEVICEID _devIDGroup = { 0x09, 0x87, 0xFF, 0xFF, 0xFF, 0xFF }; 252 | 253 | // The Device ID for addressing all devices: 6 times 0xFF. 254 | DEVICEID _devIDAll = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; 255 | 256 | 257 | // This is the buffer for RDM packets being received and sent. 258 | // This structure is needed to separate RDM data from DMX data. 259 | union RDMMEM { 260 | // the most common RDM packet layout for commands 261 | struct RDMDATA packet; 262 | 263 | // the layout of the RDM packet when returning a discovery message 264 | struct DISCOVERYMSG discovery; 265 | 266 | // the byte array used while receiving and sending. 267 | // This is the max size of any RDM packet and it's max PDL, to allow an 268 | // aribitrary length packet to be received. Thanks to the union it doesn't 269 | // need any more memory 270 | byte buffer[sizeof(packet)]; 271 | } _rdm; // union RDMMEM 272 | 273 | // This flag will be set when a full RDM packet was received. 274 | bool8 _rdmAvailable; 275 | 276 | // This is the current 16 bit checksum for RDM commands, used by the interrupt routines. 277 | uint16_t _rdmCheckSum; 278 | 279 | // static data that is not needed externally so it is not put into the class definition. 280 | bool8 _isMute; // is set to true when RDM discovery command muted this device. 281 | 282 | uint8_t _dmxModePin = 2; 283 | uint8_t _dmxModeOut = HIGH; 284 | uint8_t _dmxModeIn = LOW; 285 | 286 | // ----- Macros ----- 287 | 288 | // calculate prescaler from baud rate and cpu clock rate at compile time 289 | // nb implements rounding of ((clock / 16) / baud) - 1 per atmega datasheet 290 | #define Calcprescale(B) ( ( (((F_CPU)/8)/(B)) - 1 ) / 2 ) 291 | 292 | // compare 2 DeviceIDs 293 | #define DeviceIDCmp(id1, id2) memcmp(id1, id2, sizeof(DEVICEID)) 294 | 295 | // copy an DeviceID id2 to id1 296 | #define DeviceIDCpy(id1, id2) memcpy(id1, id2, sizeof(DEVICEID)) 297 | 298 | 299 | // ----- DMXSerial Private variables ----- 300 | // These variables are not class members because they have to be reached by the interrupt implementations. 301 | // don't use these variable from outside, use the appropriate methods. 302 | 303 | volatile uint8_t _dmxState; // Current State of receiving DMX Bytes 304 | volatile int _dmxPos; // the current read or write position in a DMX/RDM packet transmission. 305 | unsigned long _gotLastPacket = 0; // the last time (using the millis function) a packet was received. 306 | 307 | volatile byte *_dmxSendBuffer; 308 | volatile int _dmxSendLen; 309 | 310 | // Array of DMX values (raw). 311 | // Entry 0 will never be used for DMX data but will store the startbyte (0 for DMX mode). 312 | volatile byte _dmxData[DMXSERIAL_MAX+1]; 313 | 314 | // Create a single class instance. Multiple class instances (multiple simultaneous DMX ports) are not supported. 315 | DMXSerialClass2 DMXSerial2; 316 | 317 | 318 | // ----- forwards ----- 319 | 320 | void _DMXSerialBaud(uint16_t baud_setting, uint8_t format); 321 | void _DMXSerialWriteByte(uint8_t data); 322 | 323 | void respondMessage(bool8 isHandled, uint16_t nackReason = E120_NR_UNKNOWN_PID); 324 | int random255(); 325 | 326 | // ----- Class implementation ----- 327 | 328 | // Initialize or reinitialize the DMX RDM mode. 329 | // The other values are stored for later use with the specific commands. 330 | void DMXSerialClass2::init(struct RDMINIT *initData, RDMCallbackFunction func, RDMGetSensorValue sensorFunc, uint8_t modePin, uint8_t modeIn, uint8_t modeOut) 331 | { 332 | // This structure is defined for mapping the values in the EEPROM 333 | struct EEPROMVALUES eeprom; 334 | 335 | // save the given initData for later use. 336 | _initData = initData; 337 | _rdmFunc = func; 338 | _sensorFunc = sensorFunc; 339 | 340 | _dmxModePin = modePin; 341 | _dmxModeIn = modeIn; 342 | _dmxModeOut = modeOut; 343 | 344 | _baseInit(); 345 | 346 | // now initialize RDM specific elements 347 | _isMute = false; 348 | _rdmAvailable = false; 349 | _identifyMode = false; 350 | _softwareLabel = "Arduino RDM 1.0"; 351 | 352 | // read from EEPROM or set defaults 353 | for (unsigned int i = 0; i < sizeof(eeprom); i++) 354 | ((byte *)(&eeprom))[i] = EEPROM.read(i); 355 | 356 | // check if the EEPROM values are from the RDM library 357 | if ((eeprom.sig1 == 0x6D) && (eeprom.sig2 == 0x68)) { 358 | _startAddress = eeprom.startAddress; 359 | // Restricting this to 32 characters or the length, whichever is shorter 360 | strncpy(deviceLabel, eeprom.deviceLabel, DMXSERIAL_MAX_RDM_STRING_LENGTH); 361 | DeviceIDCpy(_devID, eeprom.deviceID); 362 | 363 | // setup the manufacturer addressing device-ID 364 | _devIDGroup[0] = _devID[0]; 365 | _devIDGroup[1] = _devID[1]; 366 | 367 | } else { 368 | // set default values 369 | _startAddress = 1; 370 | strncpy(deviceLabel, "new", DMXSERIAL_MAX_RDM_STRING_LENGTH); 371 | _devID[4] = random255(); // random(255); 372 | _devID[5] = random255(); // random(255); 373 | } // if 374 | _saveEEPRom(); 375 | 376 | // now start 377 | digitalWrite(_dmxModePin, _dmxModeIn); // data in direction 378 | 379 | _dmxSendBuffer = _rdm.buffer; 380 | // _dmxSendLen = ... will be set individually 381 | 382 | // Setup Hardware 383 | // Enable receiver and transmitter and interrupts 384 | UCSRnB = (1< DMXSERIAL_MAX) channel = DMXSERIAL_MAX; 395 | // read value from buffer 396 | return(_dmxData[channel]); 397 | } // read() 398 | 399 | 400 | // get the deviceID 401 | void DMXSerialClass2::getDeviceID (DEVICEID id) { 402 | DeviceIDCpy(id, _devID); 403 | } // getDeviceID() 404 | 405 | 406 | // Read the current value of a channel, relative to the startAddress. 407 | uint8_t DMXSerialClass2::readRelative(unsigned int channel) 408 | { 409 | uint8_t val = 0; 410 | if (channel < _initData->footprint) { 411 | // channel is in a valid range! (channel >= 0) is assumed by (unsigned int) type. 412 | val = _dmxData[_startAddress + channel]; 413 | } // if 414 | return(val); 415 | } // readRelative() 416 | 417 | 418 | // Write the value into the channel. 419 | // The value is just stored in the sending buffer and will be picked up 420 | // by the DMX sending interrupt routine. 421 | void DMXSerialClass2::write(int channel, uint8_t value) 422 | { 423 | // adjust parameters 424 | if (channel < 1) channel = 1; 425 | if (channel > DMXSERIAL_MAX) channel = DMXSERIAL_MAX; 426 | 427 | // The next 2 comparisons have no effect because uint8_t covers exact this range. -> removed 428 | // When changing DMXSERIAL_MAX_SLOT_VALUE or _dmxData space allocation, check again. 429 | // if (value < DMXSERIAL_MIN_SLOT_VALUE) value = DMXSERIAL_MIN_SLOT_VALUE; 430 | // if (value > DMXSERIAL_MAX_SLOT_VALUE) value = DMXSERIAL_MAX_SLOT_VALUE; 431 | 432 | // store value for later sending 433 | _dmxData[channel] = value; 434 | } // write() 435 | 436 | 437 | // Register a self implemented function for RDM callbacks 438 | void DMXSerialClass2::attachRDMCallback(RDMCallbackFunction newFunction) 439 | { 440 | _rdmFunc = newFunction; 441 | } // attachRDMCallback 442 | 443 | // Register a self implemented function to get sensor values 444 | void DMXSerialClass2::attachSensorCallback(RDMGetSensorValue newFunction) 445 | { 446 | _sensorFunc = newFunction; 447 | } // attachSensorCallback 448 | 449 | // some functions to hide the internal variables from being changed 450 | 451 | unsigned long DMXSerialClass2::noDataSince() { 452 | /* Make sure we don't load partial updates of this multi-byte value */ 453 | noInterrupts(); 454 | unsigned long lastPacket = _gotLastPacket; 455 | interrupts(); 456 | return(millis() - lastPacket); 457 | } 458 | 459 | bool8 DMXSerialClass2::isIdentifyMode() { return(_identifyMode); } 460 | uint16_t DMXSerialClass2::getStartAddress() { return(_startAddress); } 461 | uint16_t DMXSerialClass2::getFootprint() { return(_initData->footprint); } 462 | 463 | 464 | // Handle RDM Requests and send response 465 | // see http://www.opendmx.net/index.php/RDM_Discovery 466 | // see http://www.enttec.com/docs/sniffer_manual.pdf 467 | void DMXSerialClass2::tick(void) 468 | { 469 | if (((_dmxState == IDLE) || (_dmxState == BREAK)) && (_rdmAvailable)) { // 15.06.2015 470 | // never process twice. 471 | _rdmAvailable = false; 472 | 473 | // respond to RDM commands now. 474 | bool8 packetIsForMe = false; 475 | bool8 packetIsForGroup = false; 476 | bool8 packetIsForAll = false; 477 | bool8 isHandled = false; 478 | 479 | struct RDMDATA *rdm = &_rdm.packet; 480 | 481 | byte CmdClass = rdm->CmdClass; // command class 482 | uint16_t Parameter = rdm->Parameter; // parameter ID 483 | 484 | // in the ISR only some global conditions are checked: DestID 485 | if (DeviceIDCmp(rdm->DestID, _devIDAll) == 0) { 486 | packetIsForAll = true; 487 | } else if (DeviceIDCmp(rdm->DestID, _devIDGroup) == 0) { 488 | packetIsForGroup = true; 489 | } else if (DeviceIDCmp(rdm->DestID, _devID) == 0) { 490 | packetIsForMe = true; 491 | } // if 492 | 493 | if ((! packetIsForMe) && (! packetIsForGroup) && (! packetIsForAll)) { 494 | // ignore this packet 495 | 496 | } else if (CmdClass == E120_DISCOVERY_COMMAND) { // 0x10 497 | // handle all Discovery commands locally 498 | if (Parameter == SWAPINT(E120_DISC_UNIQUE_BRANCH)) { // 0x0001 499 | // not tested here for pgm space reasons: rdm->Length must be 24+6+6 = 36 500 | // not tested here for pgm space reasons: rdm->_DataLength must be 6+6 = 12 501 | 502 | if (! _isMute) { 503 | // check if my _devID is in the discovery range 504 | if ((DeviceIDCmp(rdm->Data, _devID) <= 0) && (DeviceIDCmp(_devID, rdm->Data+6) <= 0)) { 505 | 506 | // respond with a special discovery message ! 507 | struct DISCOVERYMSG *disc = &_rdm.discovery; 508 | _rdmCheckSum = 6 * 0xFF; 509 | 510 | // fill in the _rdm.discovery response structure 511 | for (byte i = 0; i < 7; i++) 512 | disc->headerFE[i] = 0xFE; 513 | disc->headerAA = 0xAA; 514 | for (byte i = 0; i < 6; i++) { 515 | disc->maskedDevID[i+i] = _devID[i] | 0xAA; 516 | disc->maskedDevID[i+i+1] = _devID[i] | 0x55; 517 | _rdmCheckSum += _devID[i]; 518 | } 519 | disc->checksum[0] = (_rdmCheckSum >> 8) | 0xAA; 520 | disc->checksum[1] = (_rdmCheckSum >> 8) | 0x55; 521 | disc->checksum[2] = (_rdmCheckSum & 0xFF) | 0xAA; 522 | disc->checksum[3] = (_rdmCheckSum & 0xFF) | 0x55; 523 | 524 | // disable all interrupt routines and send the _rdm.discovery packet 525 | // now send out the _rdm.buffer without a starting BREAK. 526 | _DMXSerialBaud(Calcprescale(DMXSPEED), DMXFORMAT); 527 | UCSRnB = (1< 0) { 551 | // Unexpected data 552 | // Do nothing 553 | } else { 554 | _isMute = false; 555 | if (packetIsForMe) { // Only actually respond if it's sent direct to us 556 | // Control field 557 | _rdm.packet.Data[0] = 0b00000000; 558 | _rdm.packet.Data[1] = 0b00000000; 559 | _rdm.packet.DataLength = 2; 560 | respondMessage(true); // 21.11.2013 561 | } 562 | } 563 | 564 | } else if (Parameter == SWAPINT(E120_DISC_MUTE)) { // 0x0002 565 | isHandled = true; 566 | if (_rdm.packet.DataLength > 0) { 567 | // Unexpected data 568 | // Do nothing 569 | } else { 570 | _isMute = true; 571 | if (packetIsForMe) { // Only actually respond if it's sent direct to us 572 | // Control field 573 | _rdm.packet.Data[0] = 0b00000000; 574 | _rdm.packet.Data[1] = 0b00000000; 575 | _rdm.packet.DataLength = 2; 576 | respondMessage(true); // 21.11.2013 577 | } 578 | } 579 | } // if 580 | 581 | } else { 582 | // don't ignore packets not sent directly but via broadcasts. 583 | // Only send an answer on directly sent packages. 584 | DMXSerial2._processRDMMessage(CmdClass, Parameter, isHandled, packetIsForMe); 585 | 586 | } // if 587 | } // if 588 | } // tick() 589 | 590 | 591 | // Terminale operation 592 | void DMXSerialClass2::term(void) 593 | { 594 | // Disable all USART Features, including Interrupts 595 | UCSRnB = 0; 596 | } // term() 597 | 598 | 599 | // Process the RDM Command Message by changing the _rdm buffer and returning (true). 600 | // if returning (false) a NAK will be sent. 601 | // This method processes the commands/parameters regarding mute, DeviceInfo, devicelabel, 602 | // manufacturer label, DMX Start address. 603 | // When parameters are changed by a SET command they are persisted into EEPROM. 604 | // When doRespond is true, send an answer back to the controller node. 605 | void DMXSerialClass2::_processRDMMessage(byte CmdClass, uint16_t Parameter, bool8 handled, bool8 doRespond) 606 | { 607 | uint16_t nackReason = E120_NR_UNKNOWN_PID; 608 | 609 | // call the device specific method 610 | if ((! handled) && (_rdmFunc)) { 611 | handled = _rdmFunc(&_rdm.packet, &nackReason); 612 | } // if 613 | 614 | // if not already handled the command: handle it using this implementation 615 | if (! handled ) { 616 | 617 | if (Parameter == SWAPINT(E120_IDENTIFY_DEVICE)) { // 0x1000 618 | if (CmdClass == E120_SET_COMMAND) { // 0x30 619 | if (_rdm.packet.DataLength != 1) { 620 | // Oversized data 621 | nackReason = E120_NR_FORMAT_ERROR; 622 | } else if ((_rdm.packet.Data[0] != 0) && (_rdm.packet.Data[0] != 1)) { 623 | // Out of range data 624 | nackReason = E120_NR_DATA_OUT_OF_RANGE; 625 | } else { 626 | _identifyMode = _rdm.packet.Data[0] != 0; 627 | _rdm.packet.DataLength = 0; 628 | handled = true; 629 | } 630 | } else if (CmdClass == E120_GET_COMMAND) { // 0x20 631 | if (_rdm.packet.DataLength > 0) { 632 | // Unexpected data 633 | nackReason = E120_NR_FORMAT_ERROR; 634 | } else if (_rdm.packet.SubDev != 0) { 635 | // No sub-devices supported 636 | nackReason = E120_NR_SUB_DEVICE_OUT_OF_RANGE; 637 | } else { 638 | _rdm.packet.Data[0] = _identifyMode; 639 | _rdm.packet.DataLength = 1; 640 | handled = true; 641 | } 642 | } // if 643 | 644 | } else if (Parameter == SWAPINT(E120_DEVICE_INFO)) { // 0x0060 645 | if (CmdClass == E120_GET_COMMAND) { 646 | if (_rdm.packet.DataLength > 0) { 647 | // Unexpected data 648 | nackReason = E120_NR_FORMAT_ERROR; 649 | } else if (_rdm.packet.SubDev != 0) { 650 | // No sub-devices supported 651 | nackReason = E120_NR_SUB_DEVICE_OUT_OF_RANGE; 652 | } else { 653 | // return all device info data 654 | DEVICEINFO *devInfo = (DEVICEINFO *)(_rdm.packet.Data); // The data has to be responded in the Data buffer. 655 | 656 | devInfo->protocolMajor = 1; 657 | devInfo->protocolMinor = 0; 658 | devInfo->deviceModel = SWAPINT(_initData->deviceModelId); 659 | devInfo->productCategory = SWAPINT(E120_PRODUCT_CATEGORY_DIMMER_CS_LED); 660 | devInfo->softwareVersion = SWAPINT32(0x01000000);// 0x04020900; 661 | devInfo->footprint = SWAPINT(_initData->footprint); 662 | devInfo->currentPersonality = 1; 663 | devInfo->personalityCount = 1; 664 | devInfo->startAddress = SWAPINT(_startAddress); 665 | devInfo->subDeviceCount = 0; 666 | devInfo->sensorCount = _initData->sensorsLength; 667 | 668 | _rdm.packet.DataLength = sizeof(DEVICEINFO); 669 | handled = true; 670 | } 671 | } else if (CmdClass == E120_SET_COMMAND) { 672 | // Unexpected set 673 | nackReason = E120_NR_UNSUPPORTED_COMMAND_CLASS; 674 | } 675 | 676 | } else if (Parameter == SWAPINT(E120_MANUFACTURER_LABEL)) { // 0x0081 677 | if (CmdClass == E120_GET_COMMAND) { 678 | if (_rdm.packet.DataLength > 0) { 679 | // Unexpected data 680 | nackReason = E120_NR_FORMAT_ERROR; 681 | } else if (_rdm.packet.SubDev != 0) { 682 | // No sub-devices supported 683 | nackReason = E120_NR_SUB_DEVICE_OUT_OF_RANGE; 684 | } else { 685 | // return the manufacturer label 686 | _rdm.packet.DataLength = strnlen(_initData->manufacturerLabel, DMXSERIAL_MAX_RDM_STRING_LENGTH); 687 | memcpy(_rdm.packet.Data, _initData->manufacturerLabel, _rdm.packet.DataLength); 688 | handled = true; 689 | } 690 | } else if (CmdClass == E120_SET_COMMAND) { 691 | // Unexpected set 692 | nackReason = E120_NR_UNSUPPORTED_COMMAND_CLASS; 693 | } 694 | 695 | } else if (Parameter == SWAPINT(E120_DEVICE_MODEL_DESCRIPTION)) { // 0x0080 696 | if (CmdClass == E120_GET_COMMAND) { 697 | if (_rdm.packet.DataLength > 0) { 698 | // Unexpected data 699 | nackReason = E120_NR_FORMAT_ERROR; 700 | } else if (_rdm.packet.SubDev != 0) { 701 | // No sub-devices supported 702 | nackReason = E120_NR_SUB_DEVICE_OUT_OF_RANGE; 703 | } else { 704 | // return the DEVICE MODEL DESCRIPTION 705 | _rdm.packet.DataLength = strnlen(_initData->deviceModel, DMXSERIAL_MAX_RDM_STRING_LENGTH); 706 | memcpy(_rdm.packet.Data, _initData->deviceModel, _rdm.packet.DataLength); 707 | handled = true; 708 | } 709 | } else if (CmdClass == E120_SET_COMMAND) { 710 | // Unexpected set 711 | nackReason = E120_NR_UNSUPPORTED_COMMAND_CLASS; 712 | } 713 | 714 | } else if (Parameter == SWAPINT(E120_DEVICE_LABEL)) { // 0x0082 715 | if (CmdClass == E120_SET_COMMAND) { 716 | if (_rdm.packet.DataLength > DMXSERIAL_MAX_RDM_STRING_LENGTH) { 717 | // Oversized data 718 | nackReason = E120_NR_FORMAT_ERROR; 719 | } else { 720 | memcpy(deviceLabel, _rdm.packet.Data, _rdm.packet.DataLength); 721 | deviceLabel[min(_rdm.packet.DataLength, DMXSERIAL_MAX_RDM_STRING_LENGTH)] = '\0'; 722 | _rdm.packet.DataLength = 0; 723 | // persist in EEPROM 724 | _saveEEPRom(); 725 | handled = true; 726 | } 727 | } else if (CmdClass == E120_GET_COMMAND) { 728 | if (_rdm.packet.DataLength > 0) { 729 | // Unexpected data 730 | nackReason = E120_NR_FORMAT_ERROR; 731 | } else if (_rdm.packet.SubDev != 0) { 732 | // No sub-devices supported 733 | nackReason = E120_NR_SUB_DEVICE_OUT_OF_RANGE; 734 | } else { 735 | _rdm.packet.DataLength = strnlen(deviceLabel, DMXSERIAL_MAX_RDM_STRING_LENGTH); 736 | memcpy(_rdm.packet.Data, deviceLabel, _rdm.packet.DataLength); 737 | handled = true; 738 | } 739 | } // if 740 | 741 | } else if (Parameter == SWAPINT(E120_SOFTWARE_VERSION_LABEL)) { // 0x00C0 742 | if (CmdClass == E120_GET_COMMAND) { 743 | if (_rdm.packet.DataLength > 0) { 744 | // Unexpected data 745 | nackReason = E120_NR_FORMAT_ERROR; 746 | } else if (_rdm.packet.SubDev != 0) { 747 | // No sub-devices supported 748 | nackReason = E120_NR_SUB_DEVICE_OUT_OF_RANGE; 749 | } else { 750 | // return the SOFTWARE_VERSION_LABEL 751 | _rdm.packet.DataLength = strnlen(_softwareLabel, DMXSERIAL_MAX_RDM_STRING_LENGTH); 752 | memcpy(_rdm.packet.Data, _softwareLabel, _rdm.packet.DataLength); 753 | handled = true; 754 | } 755 | } else if (CmdClass == E120_SET_COMMAND) { 756 | // Unexpected set 757 | nackReason = E120_NR_UNSUPPORTED_COMMAND_CLASS; 758 | } 759 | 760 | } else if (Parameter == SWAPINT(E120_DMX_START_ADDRESS)) { // 0x00F0 761 | if (CmdClass == E120_SET_COMMAND) { 762 | if (_rdm.packet.DataLength != 2) { 763 | // Oversized data 764 | nackReason = E120_NR_FORMAT_ERROR; 765 | } else { 766 | uint16_t newStartAddress = READINT(_rdm.packet.Data); 767 | if ((newStartAddress <= 0) || (newStartAddress > DMXSERIAL_MAX)) { 768 | // Out of range start address 769 | // TODO(Peter): Should it be newStartAddress less footprint? 770 | nackReason = E120_NR_DATA_OUT_OF_RANGE; 771 | } else { 772 | _startAddress = newStartAddress; 773 | _rdm.packet.DataLength = 0; 774 | // persist in EEPROM 775 | _saveEEPRom(); 776 | handled = true; 777 | } 778 | } 779 | } else if (CmdClass == E120_GET_COMMAND) { 780 | if (_rdm.packet.DataLength > 0) { 781 | // Unexpected data 782 | nackReason = E120_NR_FORMAT_ERROR; 783 | } else if (_rdm.packet.SubDev != 0) { 784 | // No sub-devices supported 785 | nackReason = E120_NR_SUB_DEVICE_OUT_OF_RANGE; 786 | } else { 787 | WRITEINT(_rdm.packet.Data, _startAddress); 788 | _rdm.packet.DataLength = 2; 789 | handled = true; 790 | } 791 | } // if 792 | 793 | } else if (Parameter == SWAPINT(E120_SUPPORTED_PARAMETERS)) { // 0x0050 794 | if (CmdClass == E120_GET_COMMAND) { 795 | if (_rdm.packet.DataLength > 0) { 796 | // Unexpected data 797 | nackReason = E120_NR_FORMAT_ERROR; 798 | } else if (_rdm.packet.SubDev != 0) { 799 | // No sub-devices supported 800 | nackReason = E120_NR_SUB_DEVICE_OUT_OF_RANGE; 801 | } else { 802 | // Some supported PIDs shouldn't be returned as per the standard, these are: 803 | // E120_DISC_UNIQUE_BRANCH 804 | // E120_DISC_MUTE 805 | // E120_DISC_UN_MUTE 806 | // E120_SUPPORTED_PARAMETERS 807 | // E120_IDENTIFY_DEVICE 808 | // E120_DEVICE_INFO 809 | // E120_DMX_START_ADDRESS 810 | // E120_SOFTWARE_VERSION_LABEL 811 | _rdm.packet.DataLength = 2 * (3 + _initData->additionalCommandsLength); 812 | WRITEINT(_rdm.packet.Data , E120_MANUFACTURER_LABEL); 813 | WRITEINT(_rdm.packet.Data+ 2, E120_DEVICE_MODEL_DESCRIPTION); 814 | WRITEINT(_rdm.packet.Data+ 4, E120_DEVICE_LABEL); 815 | uint8_t offset = 6; 816 | if (_initData->sensorsLength > 0) { 817 | _rdm.packet.DataLength += 2 * 2; 818 | offset += 2 * 2; 819 | WRITEINT(_rdm.packet.Data+ 6, E120_SENSOR_DEFINITION); 820 | WRITEINT(_rdm.packet.Data+ 8, E120_SENSOR_VALUE); 821 | } 822 | for (uint16_t n = 0; n < _initData->additionalCommandsLength; n++) { 823 | WRITEINT(_rdm.packet.Data+offset+n+n, _initData->additionalCommands[n]); 824 | } 825 | handled = true; 826 | } 827 | } else if (CmdClass == E120_SET_COMMAND) { 828 | // Unexpected set 829 | nackReason = E120_NR_UNSUPPORTED_COMMAND_CLASS; 830 | } 831 | 832 | // ADD: PARAMETER_DESCRIPTION 833 | 834 | } else if (Parameter == SWAPINT(E120_SENSOR_DEFINITION) && _initData->sensorsLength > 0) { // 0x0200 835 | if (CmdClass == E120_GET_COMMAND) { 836 | if (_rdm.packet.DataLength != 1) { 837 | // Unexpected data 838 | nackReason = E120_NR_FORMAT_ERROR; 839 | } else if (_rdm.packet.SubDev != 0) { 840 | // No sub-devices supported 841 | nackReason = E120_NR_SUB_DEVICE_OUT_OF_RANGE; 842 | } else { 843 | uint8_t sensorNr = _rdm.packet.Data[0]; 844 | if (sensorNr >= _initData->sensorsLength) { 845 | // Out of range sensor 846 | nackReason = E120_NR_DATA_OUT_OF_RANGE; 847 | } else { 848 | _rdm.packet.DataLength = 13 + strnlen(_initData->sensors[sensorNr].description, DMXSERIAL_MAX_RDM_STRING_LENGTH); 849 | _rdm.packet.Data[0] = sensorNr; 850 | _rdm.packet.Data[1] = _initData->sensors[sensorNr].type; 851 | _rdm.packet.Data[2] = _initData->sensors[sensorNr].unit; 852 | _rdm.packet.Data[3] = _initData->sensors[sensorNr].prefix; 853 | WRITEINT(_rdm.packet.Data + 4, _initData->sensors[sensorNr].rangeMin); 854 | WRITEINT(_rdm.packet.Data + 6, _initData->sensors[sensorNr].rangeMax); 855 | WRITEINT(_rdm.packet.Data + 8, _initData->sensors[sensorNr].normalMin); 856 | WRITEINT(_rdm.packet.Data + 10, _initData->sensors[sensorNr].normalMax); 857 | _rdm.packet.Data[12] = (_initData->sensors[sensorNr].lowHighSupported ? 2 : 0) | (_initData->sensors[sensorNr].recordedSupported ? 1 : 0); 858 | memcpy(_rdm.packet.Data + 13, _initData->sensors[sensorNr].description, _rdm.packet.DataLength - 13); 859 | handled = true; 860 | } 861 | } 862 | } else if (CmdClass == E120_SET_COMMAND) { 863 | // Unexpected set 864 | nackReason = E120_NR_UNSUPPORTED_COMMAND_CLASS; 865 | } 866 | } else if (Parameter == SWAPINT(E120_SENSOR_VALUE) && _initData->sensorsLength > 0) { // 0x0201 867 | if (CmdClass == E120_GET_COMMAND) { 868 | if (_rdm.packet.DataLength != 1) { 869 | // Unexpected data 870 | nackReason = E120_NR_FORMAT_ERROR; 871 | } else if (_rdm.packet.SubDev != 0) { 872 | // No sub-devices supported 873 | nackReason = E120_NR_SUB_DEVICE_OUT_OF_RANGE; 874 | } else { 875 | uint8_t sensorNr = _rdm.packet.Data[0]; 876 | if (sensorNr >= _initData->sensorsLength) { 877 | // Out of range sensor 878 | nackReason = E120_NR_DATA_OUT_OF_RANGE; 879 | } else { 880 | int16_t sensorValue = 0; 881 | int16_t lowestValue = 0; 882 | int16_t highestValue = 0; 883 | int16_t recordedValue = 0; 884 | bool8 res = false; 885 | if (_sensorFunc) { 886 | res = _sensorFunc(sensorNr, &sensorValue, &lowestValue, &highestValue, &recordedValue); 887 | } 888 | if (res) { 889 | _rdm.packet.DataLength = 9; 890 | _rdm.packet.Data[0] = sensorNr; 891 | WRITEINT(_rdm.packet.Data + 1, sensorValue); 892 | WRITEINT(_rdm.packet.Data + 3, lowestValue); 893 | WRITEINT(_rdm.packet.Data + 5, highestValue); 894 | WRITEINT(_rdm.packet.Data + 7, recordedValue); 895 | handled = true; 896 | } else { 897 | nackReason = E120_NR_HARDWARE_FAULT; 898 | } 899 | } 900 | } 901 | } else if (CmdClass == E120_SET_COMMAND) { 902 | // Unhandled set. Set on a sensor is used to reset stats. 903 | // User should process it in own handler when sensor supports high/low or recorded value. 904 | nackReason = E120_NR_UNSUPPORTED_COMMAND_CLASS; 905 | } 906 | 907 | } else { 908 | handled = false; 909 | 910 | } // if 911 | } // if 912 | 913 | if (doRespond) 914 | respondMessage(handled, nackReason); 915 | } // _processRDMMessage 916 | 917 | 918 | // ----- internal functions and interrupt implementations ----- 919 | 920 | // internal init function for all static initializations. 921 | void DMXSerialClass2::_baseInit() { 922 | _dmxPos = 0; 923 | 924 | _dmxState= IDLE; // initial state 925 | _gotLastPacket = millis(); // remember current (relative) time in msecs. 926 | 927 | // initialize the DMX buffer 928 | for (int n = 0; n < DMXSERIAL_MAX+1; n++) 929 | _dmxData[n] = 0; 930 | 931 | pinMode(_dmxModePin, OUTPUT); // enables pin 2 for output to control data direction 932 | } // _baseInit 933 | 934 | 935 | // save all data to EEPROM 936 | void DMXSerialClass2::_saveEEPRom() 937 | { 938 | // This structure is defined for mapping the values in the EEPROM 939 | struct EEPROMVALUES eeprom; 940 | 941 | // initialize 942 | for (unsigned int i = 0; i < sizeof(eeprom); i++) 943 | ((byte *)(&eeprom))[i] = 0x00; 944 | 945 | eeprom.sig1 = 0x6D; 946 | eeprom.sig2 = 0x68; 947 | eeprom.startAddress = _startAddress; 948 | // This needs restricting to 32 chars (potentially no null), for backwards compatibility 949 | strncpy(eeprom.deviceLabel, deviceLabel, DMXSERIAL_MAX_RDM_STRING_LENGTH); 950 | DeviceIDCpy(eeprom.deviceID, _devID); 951 | 952 | for (unsigned int i = 0; i < sizeof(eeprom); i++) { 953 | // EEPROM.update does a read/write check and only writes on a change 954 | EEPROM.update(i, ((byte *)(&eeprom))[i]); 955 | } // for 956 | } // _saveEEPRom 957 | 958 | 959 | // ----- internal non-class functions and interrupt implementations ----- 960 | 961 | // Initialize the Hardware serial port with the given baud rate 962 | // using 8 data bits, no parity, 2 stop bits for data 963 | // and 8 data bits, even parity, 1 stop bit for the break 964 | void _DMXSerialBaud(uint16_t baud_setting, uint8_t format) 965 | { 966 | // assign the baud_setting to the USART Baud Rate Register 967 | UCSRnA = 0; // 04.06.2012: use normal speed operation 968 | UBRRnH = baud_setting >> 8; 969 | UBRRnL = baud_setting; 970 | 971 | // 2 stop bits and 8 bit character size, no parity 972 | UCSRnC = format; 973 | } // _DMXSerialBaud 974 | 975 | 976 | // send the next byte after current byte was sent completely. 977 | void _DMXSerialWriteByte(uint8_t data) 978 | { 979 | // putting data into buffer sends the data 980 | UDRn = data; 981 | } // _DMXSerialWrite 982 | 983 | 984 | // Interrupt Service Routine, called when a byte or frame error was received. 985 | ISR(USARTn_RX_vect) 986 | { 987 | // digitalWrite(rxStatusPin, HIGH); 988 | uint8_t USARTstate= UCSRnA; //get state before data! 989 | uint8_t DmxByte = UDRn; //get data 990 | uint8_t DmxState = _dmxState; //just load once from SRAM to increase speed 991 | 992 | if (USARTstate & (1< not implemented so wait for next BREAK ! 1013 | _dmxState= IDLE; 1014 | } // if 1015 | 1016 | } else if (DmxState == DMXDATA) { 1017 | // another DMX byte 1018 | _dmxData[_dmxPos++]= DmxByte; // store received data into DMX data buffer. 1019 | 1020 | if (_dmxPos > DMXSERIAL_MAX) { // all channels done. 1021 | _dmxState = IDLE; // wait for next break 1022 | } // if 1023 | 1024 | } else if (DmxState == RDMDATA) { 1025 | // another RDM byte 1026 | if (_dmxPos >= (int)sizeof(_rdm.buffer)) { 1027 | // too much data ... 1028 | _dmxState = IDLE; // wait for next break 1029 | } else { 1030 | _rdm.buffer[_dmxPos++] = DmxByte; 1031 | _rdmCheckSum += DmxByte; 1032 | 1033 | if (_dmxPos == _rdm.packet.Length) { 1034 | // all data received. Now getting checksum ! 1035 | _dmxState = CHECKSUMH; // wait for checksum High Byte 1036 | } // if 1037 | } // if 1038 | 1039 | } else if (DmxState == CHECKSUMH) { 1040 | // High byte of RDM checksum -> subtract from checksum 1041 | _rdmCheckSum -= DmxByte << 8; 1042 | _dmxState = CHECKSUML; 1043 | 1044 | } else if (DmxState == CHECKSUML) { 1045 | // Low byte of RDM checksum -> subtract from checksum 1046 | _rdmCheckSum -= DmxByte; 1047 | 1048 | // now check some error conditions and addressing issues 1049 | if ((_rdmCheckSum == 0) && (_rdm.packet.SubStartCode == E120_SC_SUB_MESSAGE)) { // 0x01 1050 | // prepare for answering when tick() is called 1051 | _rdmAvailable = true; 1052 | _gotLastPacket = millis(); // remember current (relative) time in msecs. 1053 | // TIMING: remember when the last byte was sent 1054 | _timingReceiveEnd = micros(); 1055 | } // if 1056 | 1057 | _dmxState = IDLE; // wait for next break or RDM package processing. 1058 | } // if 1059 | 1060 | } // ISR(USART_RX_vect) 1061 | 1062 | 1063 | // Interrupt service routines that are called when the actual byte was sent. 1064 | // When changing speed (for sending break and sending start code) we use TX finished interrupt 1065 | // which occurs shortly after the last stop bit is sent 1066 | // When staying at the same speed (sending data bytes) we use data register empty interrupt 1067 | // which occurs shortly after the start bit of the *previous* byte 1068 | // When sending a DMX sequence it just takes the next channel byte and sends it out. 1069 | // In DMXController mode when the buffer was sent completely the DMX sequence will resent, starting with a BREAK pattern. 1070 | // In DMXReceiver mode this interrupt is disabled and will not occur. 1071 | // In RDM mode this interrupt acts like in DMXController mode but the packet is not resent automatically. 1072 | ISR(USARTn_TX_vect) 1073 | { 1074 | if (_dmxPos == 0) { 1075 | // this interrupt occurs after the stop bits of the break byte 1076 | // now back to DMX speed: 250000baud 1077 | _DMXSerialBaud(Calcprescale(DMXSPEED), DMXFORMAT); 1078 | // take next interrupt when data register empty (early) and handle sending the next byte in USART_UDRE_vect 1079 | UCSRnB = (1<> 8) & 0xFF; 1102 | _rdm.packet.Data[1] = nackReason & 0xFF; 1103 | } // if 1104 | _rdm.packet.Length = _rdm.packet.DataLength + 24; // total packet length 1105 | 1106 | // swap SrcID into DestID for sending back. 1107 | DeviceIDCpy(_rdm.packet.DestID, _rdm.packet.SourceID); 1108 | DeviceIDCpy(_rdm.packet.SourceID, _devID); 1109 | 1110 | _rdm.packet.CmdClass++; 1111 | // Parameter 1112 | 1113 | // prepare buffer and Checksum 1114 | _dmxSendLen = _rdm.packet.Length; 1115 | for (byte i = 0; i < _dmxSendLen; i++) { 1116 | checkSum += _dmxSendBuffer[i]; 1117 | } // for 1118 | 1119 | // TIMING: don't send too fast, min: 176 microseconds 1120 | unsigned long d = micros() - _timingReceiveEnd; 1121 | if (d < 190) 1122 | delayMicroseconds(190 - d); 1123 | 1124 | // send package by starting with a BREAK 1125 | UCSRnB = (1<> 8; 1145 | UCSRnA= (1<>8)) 110 | 111 | /// Use SWAPINT32 to swap the 4 bytes of a 32-bit int to match the byte order on the DMX Protocol. 112 | #define SWAPINT32(i) ((i&0x000000ff)<<24) | ((i&0x0000ff00)<<8) | ((i&0x00ff0000)>>8) | ((i&0xff000000)>>24) 113 | 114 | /// read a 16 bit number from a data buffer location 115 | #define READINT(p) ((p[0]<<8) | (p[1])) 116 | 117 | /// write a 16 bit number to a data buffer location 118 | #define WRITEINT(p, d) (p)[0] = (d&0xFF00)>>8; (p)[1] = (d&0x00FF); 119 | 120 | 121 | // ----- Callback function types ----- 122 | 123 | extern "C" { 124 | /** 125 | * @brief Callback function for RDM functions. 126 | * 127 | * @param [in,out] buffer Buffer containing the RDM network package. 128 | * @param [in,out] nackReason on error a RDM Response NACK Reason Code. 129 | */ 130 | typedef bool8 (*RDMCallbackFunction)(struct RDMDATA *buffer, uint16_t *nackReason); 131 | 132 | /** 133 | * @brief Callback function for RDM sensors. 134 | */ 135 | typedef bool8 (*RDMGetSensorValue)(uint8_t sensorNr, int16_t *value, int16_t *lowestValue, int16_t *highestValue, int16_t *recordedValue); 136 | } 137 | 138 | // ----- Library Class ----- 139 | 140 | // These types are used to pass all the data into the initRDM function. 141 | // The library needs this data to reposonse at the corresponding commands for itself. 142 | 143 | struct RDMPERSONALITY { 144 | uint16_t footprint; 145 | // maybe more here... when supporting more personalities. 146 | }; // struct RDMPERSONALITY 147 | 148 | struct RDMSENSOR { 149 | uint8_t type; 150 | uint8_t unit; 151 | uint8_t prefix; 152 | int16_t rangeMin; 153 | int16_t rangeMax; 154 | int16_t normalMin; 155 | int16_t normalMax; 156 | bool8 lowHighSupported; 157 | bool8 recordedSupported; 158 | char *description; 159 | }; // struct RDMSENSOR 160 | 161 | struct RDMINIT { 162 | const char *manufacturerLabel; // 163 | const uint16_t deviceModelId; // 164 | const char *deviceModel; // 165 | uint16_t footprint; 166 | // uint16_t personalityCount; 167 | // RDMPERSONALITY *personalities; 168 | const uint16_t additionalCommandsLength; 169 | const uint16_t *additionalCommands; 170 | const uint8_t sensorsLength; 171 | const RDMSENSOR *sensors; 172 | }; // struct RDMINIT 173 | 174 | 175 | 176 | class DMXSerialClass2 177 | { 178 | public: 179 | /** 180 | * @brief Initialize for RDM mode. 181 | * @param [in] initData Startup parameters. 182 | * @param [in] func Callback function for answering on device specific features. 183 | * @param [in] modePin The pin used to switch the communication direction. This parameter is optiona and defaults to 2. 184 | * @param [in] modeIn The level for inbound communication. This parameter is optiona and defaults to 0 = LOW. 185 | * @param [in] modeOut The level for outbound communication. This parameter is optiona and defaults to 1 = HIGH. 186 | */ 187 | void init (struct RDMINIT *initData, RDMCallbackFunction func, uint8_t modePin = 2, uint8_t modeIn = 0, uint8_t modeOut = 1) { 188 | init(initData, func, NULL, modePin, modeIn, modeOut); 189 | } 190 | 191 | /** 192 | * @brief Initialize for RDM mode with sensor. 193 | * @param [in] initData Startup parameters. 194 | * @param [in] func Callback function for answering on device specific features. 195 | * @param [in] sensorFunc Callback function for retrieving a sensor value. 196 | * @param [in] modePin The pin used to switch the communication direction. This parameter is optiona and defaults to 2. 197 | * @param [in] modeIn The level for inbound communication. This parameter is optiona and defaults to 0 = LOW. 198 | * @param [in] modeOut The level for outbound communication. This parameter is optiona and defaults to 1 = HIGH. 199 | */ 200 | void init (struct RDMINIT *initData, RDMCallbackFunction func, RDMGetSensorValue sensorFunc, uint8_t modePin = 2, uint8_t modeIn = 0, uint8_t modeOut = 1); 201 | 202 | /** 203 | * @brief Read the current value of a channel. 204 | * @param [in] channel The channel number. 205 | * @return uint8_t The current value. 206 | */ 207 | uint8_t read (int channel); 208 | 209 | // Read the last known value of a channel by using the startAddress and footprint range. 210 | uint8_t readRelative(unsigned int channel); 211 | 212 | /** 213 | * @brief Write a new value to a channel. 214 | * This function also can be called in DMXReceiver mode to set a channel value even when no data is received. 215 | * It will be overwritten by the next received package. 216 | * @param [in] channel The channel number. 217 | * @param [in] value The current value. 218 | * @return void 219 | */ 220 | void write (int channel, uint8_t value); 221 | 222 | /** 223 | * @brief Return the duration since data was received. 224 | * On startup the internal timer is reset too. 225 | * @return long milliseconds since last pdata package. 226 | */ 227 | unsigned long noDataSince(); 228 | 229 | // ----- RDM specific members ----- 230 | 231 | /// Return true when identify mode was set on by controller. 232 | bool8 isIdentifyMode(); 233 | 234 | /// Returns the Device ID. Copies the UID to the buffer passed through the uid argument. 235 | void getDeviceID(DEVICEID id); 236 | 237 | /// Return the current DMX start address that is the first DMX address used by the device. 238 | uint16_t getStartAddress(); 239 | 240 | /// Return the current DMX footprint, that is the number of DMX addresses used by the device. 241 | uint16_t getFootprint(); 242 | 243 | /// Register a device-specific implemented function for RDM callbacks 244 | void attachRDMCallback (RDMCallbackFunction newFunction); 245 | 246 | /// Register a device-specific implemented function for getting sensor values 247 | void attachSensorCallback (RDMGetSensorValue newFunction); 248 | 249 | /// check for unprocessed RDM Command. 250 | void tick(void); 251 | 252 | /// Terminate operation. 253 | void term(void); 254 | 255 | /// A short custom label given to the device. Add an extra char for a null. 256 | char deviceLabel[DMXSERIAL_MAX_RDM_STRING_LENGTH + 1]; 257 | 258 | /// don't use that method from extern. 259 | void _processRDMMessage(byte CmdClass, uint16_t Parameter, bool8 isHandled); 260 | 261 | /// save all data to EEPROM 262 | void _saveEEPRom(); 263 | 264 | private: 265 | /// process a relevant message 266 | void _processRDMMessage(byte CmdClass, uint16_t Parameter, bool8 isHandled, bool8 doRespond); 267 | 268 | /// common internal initialization function. 269 | void _baseInit(); 270 | 271 | /// callback function to device specific code 272 | RDMCallbackFunction _rdmFunc; 273 | 274 | /// callback function to get sensor value 275 | RDMGetSensorValue _sensorFunc; 276 | 277 | /// remember the given manufacturer label and device model strings during init 278 | struct RDMINIT *_initData; 279 | 280 | /// intern parameter settings 281 | const char *_softwareLabel; 282 | bool8 _identifyMode; 283 | uint16_t _startAddress; 284 | }; // class DMXSerialClass2 285 | 286 | 287 | // Use the DMXSerial2 library through the DMXSerial2 object. 288 | extern DMXSerialClass2 DMXSerial2; 289 | 290 | #endif 291 | 292 | // --- End of File --- 293 | -------------------------------------------------------------------------------- /src/rdm.h: -------------------------------------------------------------------------------- 1 | /*****************************************************************/ 2 | /* Entertainment Services Technology Association (ESTA) */ 3 | /* ANSI E1.20 Remote Device Management (RDM) over DMX512 Networks*/ 4 | /*****************************************************************/ 5 | /* */ 6 | /* RDM.h */ 7 | /* */ 8 | /*****************************************************************/ 9 | /* Appendix A Defines for the RDM Protocol. */ 10 | /* Publish date: 3/31/2006 */ 11 | /*****************************************************************/ 12 | /* Compiled by: Scott M. Blair 8/18/2006 */ 13 | /* Updated 10/11/2011: Adding E1.20-2010 and E1.37-1 defines. */ 14 | /* Updated 10/24/2014: Adding E1.37-2 defines */ 15 | /*****************************************************************/ 16 | /* For updates see: http://www.rdmprotocol.org */ 17 | /*****************************************************************/ 18 | /* Copyright 2006,2011, 2014 Litespeed Design */ 19 | /*****************************************************************/ 20 | /* Permission to use, copy, modify, and distribute this software */ 21 | /* is freely granted, provided that this notice is preserved. */ 22 | /*****************************************************************/ 23 | 24 | /* Protocol version. */ 25 | #define E120_PROTOCOL_VERSION 0x0100 26 | 27 | /* RDM START CODE (Slot 0) */ 28 | #define E120_SC_RDM 0xCC 29 | 30 | /* RDM Protocol Data Structure ID's (Slot 1) */ 31 | #define E120_SC_SUB_MESSAGE 0x01 32 | 33 | /* Broadcast Device UID's */ 34 | #define E120_BROADCAST_ALL_DEVICES_ID 0xFFFFFFFFFFFF /* (Broadcast all Manufacturers) */ 35 | //#define ALL_DEVICES_ID 0xmmmmFFFFFFFF /* (Specific Manufacturer ID 0xmmmm) */ 36 | 37 | #define E120_SUB_DEVICE_ALL_CALL 0xFFFF 38 | 39 | 40 | /********************************************************/ 41 | /* Table A-1: RDM Command Classes (Slot 20) */ 42 | /********************************************************/ 43 | #define E120_DISCOVERY_COMMAND 0x10 44 | #define E120_DISCOVERY_COMMAND_RESPONSE 0x11 45 | #define E120_GET_COMMAND 0x20 46 | #define E120_GET_COMMAND_RESPONSE 0x21 47 | #define E120_SET_COMMAND 0x30 48 | #define E120_SET_COMMAND_RESPONSE 0x31 49 | 50 | 51 | 52 | /********************************************************/ 53 | /* Table A-2: RDM Response Type (Slot 16) */ 54 | /********************************************************/ 55 | #define E120_RESPONSE_TYPE_ACK 0x00 56 | #define E120_RESPONSE_TYPE_ACK_TIMER 0x01 57 | #define E120_RESPONSE_TYPE_NACK_REASON 0x02 /* See Table A-17 */ 58 | #define E120_RESPONSE_TYPE_ACK_OVERFLOW 0x03 /* Additional Response Data available beyond single response length.*/ 59 | 60 | 61 | /********************************************************/ 62 | /* Table A-3: RDM Parameter ID's (Slots 21-22) */ 63 | /********************************************************/ 64 | /* Category - Network Management */ 65 | #define E120_DISC_UNIQUE_BRANCH 0x0001 66 | #define E120_DISC_MUTE 0x0002 67 | #define E120_DISC_UN_MUTE 0x0003 68 | #define E120_PROXIED_DEVICES 0x0010 69 | #define E120_PROXIED_DEVICE_COUNT 0x0011 70 | #define E120_COMMS_STATUS 0x0015 71 | 72 | /* Category - Status Collection */ 73 | #define E120_QUEUED_MESSAGE 0x0020 /* See Table A-4 */ 74 | #define E120_STATUS_MESSAGES 0x0030 /* See Table A-4 */ 75 | #define E120_STATUS_ID_DESCRIPTION 0x0031 76 | #define E120_CLEAR_STATUS_ID 0x0032 77 | #define E120_SUB_DEVICE_STATUS_REPORT_THRESHOLD 0x0033 /* See Table A-4 */ 78 | 79 | /* Category - RDM Information */ 80 | #define E120_SUPPORTED_PARAMETERS 0x0050 /* Support required only if supporting Parameters beyond the minimum required set.*/ 81 | #define E120_PARAMETER_DESCRIPTION 0x0051 /* Support required for Manufacturer-Specific PIDs exposed in SUPPORTED_PARAMETERS message */ 82 | 83 | /* Category - Product Information */ 84 | #define E120_DEVICE_INFO 0x0060 85 | #define E120_PRODUCT_DETAIL_ID_LIST 0x0070 86 | #define E120_DEVICE_MODEL_DESCRIPTION 0x0080 87 | #define E120_MANUFACTURER_LABEL 0x0081 88 | #define E120_DEVICE_LABEL 0x0082 89 | #define E120_FACTORY_DEFAULTS 0x0090 90 | #define E120_LANGUAGE_CAPABILITIES 0x00A0 91 | #define E120_LANGUAGE 0x00B0 92 | #define E120_SOFTWARE_VERSION_LABEL 0x00C0 93 | #define E120_BOOT_SOFTWARE_VERSION_ID 0x00C1 94 | #define E120_BOOT_SOFTWARE_VERSION_LABEL 0x00C2 95 | 96 | /* Category - DMX512 Setup */ 97 | #define E120_DMX_PERSONALITY 0x00E0 98 | #define E120_DMX_PERSONALITY_DESCRIPTION 0x00E1 99 | #define E120_DMX_START_ADDRESS 0x00F0 /* Support required if device uses a DMX512 Slot. */ 100 | #define E120_SLOT_INFO 0x0120 101 | #define E120_SLOT_DESCRIPTION 0x0121 102 | #define E120_DEFAULT_SLOT_VALUE 0x0122 103 | #define E137_1_DMX_BLOCK_ADDRESS 0x0140 /* Defined in ANSI E1.37-1 document */ 104 | #define E137_1_DMX_FAIL_MODE 0x0141 /* Defined in ANSI E1.37-1 document */ 105 | #define E137_1_DMX_STARTUP_MODE 0x0142 /* Defined in ANSI E1.37-1 document */ 106 | 107 | 108 | /* Category - Sensors */ 109 | #define E120_SENSOR_DEFINITION 0x0200 110 | #define E120_SENSOR_VALUE 0x0201 111 | #define E120_RECORD_SENSORS 0x0202 112 | 113 | /* Category - Dimmer Settings */ 114 | #define E137_1_DIMMER_INFO 0x0340 115 | #define E137_1_MINIMUM_LEVEL 0x0341 116 | #define E137_1_MAXIMUM_LEVEL 0x0342 117 | #define E137_1_CURVE 0x0343 118 | #define E137_1_CURVE_DESCRIPTION 0x0344 /* Support required if CURVE is supported */ 119 | #define E137_1_OUTPUT_RESPONSE_TIME 0x0345 120 | #define E137_1_OUTPUT_RESPONSE_TIME_DESCRIPTION 0x0346 /* Support required if OUTPUT_RESPONSE_TIME is supported */ 121 | #define E137_1_MODULATION_FREQUENCY 0x0347 122 | #define E137_1_MODULATION_FREQUENCY_DESCRIPTION 0x0348 /* Support required if MODULATION_FREQUENCY is supported */ 123 | 124 | /* Category - Power/Lamp Settings */ 125 | #define E120_DEVICE_HOURS 0x0400 126 | #define E120_LAMP_HOURS 0x0401 127 | #define E120_LAMP_STRIKES 0x0402 128 | #define E120_LAMP_STATE 0x0403 /* See Table A-8 */ 129 | #define E120_LAMP_ON_MODE 0x0404 /* See Table A-9 */ 130 | #define E120_DEVICE_POWER_CYCLES 0x0405 131 | #define E137_1_BURN_IN 0x0440 /* Defined in ANSI E1.37-1 */ 132 | 133 | /* Category - Display Settings */ 134 | #define E120_DISPLAY_INVERT 0x0500 135 | #define E120_DISPLAY_LEVEL 0x0501 136 | 137 | /* Category - Configuration */ 138 | #define E120_PAN_INVERT 0x0600 139 | #define E120_TILT_INVERT 0x0601 140 | #define E120_PAN_TILT_SWAP 0x0602 141 | #define E120_REAL_TIME_CLOCK 0x0603 142 | #define E137_1_LOCK_PIN 0x0640 /* Defined in ANSI E1.37-1 */ 143 | #define E137_1_LOCK_STATE 0x0641 /* Defined in ANSI E1.37-1 */ 144 | #define E137_1_LOCK_STATE_DESCRIPTION 0x0642 /* Support required if MODULATION_FREQUENCY is supported */ 145 | 146 | /* Category - Network Configuration*/ 147 | 148 | #define E137_2_LIST_INTERFACES 0x0700 /* Defined in ANSI E1.37-2 */ 149 | #define E137_2_INTERFACE_LABEL 0x0701 /* Defined in ANSI E1.37-2 */ 150 | #define E137_2_INTERFACE_HARDWARE_ADDRESS_TYPE1 0x0702 /* Defined in ANSI E1.37-2 */ 151 | #define E137_2_IPV4_DHCP_MODE 0x0703 /* Defined in ANSI E1.37-2 */ 152 | #define E137_2_IPV4_ZEROCONF_MODE 0x0704 /* Defined in ANSI E1.37-2 */ 153 | #define E137_2_IPV4_CURRENT_ADDRESS 0x0705 /* Defined in ANSI E1.37-2 */ 154 | #define E137_2_IPV4_STATIC_ADDRESS 0x0706 /* Defined in ANSI E1.37-2 */ 155 | #define E137_2_INTERFACE_RENEW_DHCP 0x0707 /* Defined in ANSI E1.37-2 */ 156 | #define E137_2_INTERFACE_RELEASE_DHCP 0x0708 /* Defined in ANSI E1.37-2 */ 157 | #define E137_2_INTERFACE_APPLY_CONFIGURATION 0x0709 /* Defined in ANSI E1.37-2 (Support required if _ADDRESS PIDs supported) */ 158 | #define E137_2_IPV4_DEFAULT_ROUTE 0x070A /* Defined in ANSI E1.37-2 */ 159 | #define E137_2_DNS_IPV4_NAME_SERVER 0x070B /* Defined in ANSI E1.37-2 */ 160 | #define E137_2_DNS_HOSTNAME 0x070C /* Defined in ANSI E1.37-2 */ 161 | #define E137_2_DNS_DOMAIN_NAME 0x070D /* Defined in ANSI E1.37-2 */ 162 | 163 | 164 | /* Category - Control */ 165 | #define E120_IDENTIFY_DEVICE 0x1000 166 | #define E120_RESET_DEVICE 0x1001 167 | #define E120_POWER_STATE 0x1010 /* See Table A-11 */ 168 | #define E120_PERFORM_SELFTEST 0x1020 /* See Table A-10 */ 169 | #define E120_SELF_TEST_DESCRIPTION 0x1021 170 | #define E120_CAPTURE_PRESET 0x1030 171 | #define E120_PRESET_PLAYBACK 0x1031 /* See Table A-7 */ 172 | #define E137_1_IDENTIFY_MODE 0x1040 /* Defined in ANSI E1.37-1 */ 173 | #define E137_1_PRESET_INFO 0x1041 /* Defined in ANSI E1.37-1 */ 174 | #define E137_1_PRESET_STATUS 0x1042 /* Defined in ANSI E1.37-1 */ 175 | #define E137_1_PRESET_MERGEMODE 0x1043 /* See E1.37-1 Table A-3 */ 176 | #define E137_1_POWER_ON_SELF_TEST 0x1044 /* Defined in ANSI E1.37-1 */ 177 | 178 | /* ESTA Reserved Future RDM Development 0x7FE0- 179 | 0x7FFF 180 | 181 | Manufacturer-Specific PIDs 0x8000- 182 | 0xFFDF 183 | ESTA Reserved Future RDM Development 184 | 0xFFE0- 185 | 0xFFFF 186 | */ 187 | 188 | 189 | /*****************************************************************/ 190 | /* Discovery Mute/Un-Mute Messages Control Field. See Table 7-3. */ 191 | /*****************************************************************/ 192 | #define E120_CONTROL_PROXIED_DEVICE 0x0008 193 | #define E120_CONTROL_BOOT_LOADER 0x0004 194 | #define E120_CONTROL_SUB_DEVICE 0x0002 195 | #define E120_CONTROL_MANAGED_PROXY 0x0001 196 | 197 | 198 | /********************************************************/ 199 | /* Table A-4: Status Type Defines */ 200 | /********************************************************/ 201 | #define E120_STATUS_NONE 0x00 /* Not allowed for use with GET: QUEUED_MESSAGE */ 202 | #define E120_STATUS_GET_LAST_MESSAGE 0x01 203 | #define E120_STATUS_ADVISORY 0x02 204 | #define E120_STATUS_WARNING 0x03 205 | #define E120_STATUS_ERROR 0x04 206 | #define E120_STATUS_ADVISORY_CLEARED 0x12 /* Added in E1.20-2010 version */ 207 | #define E120_STATUS_WARNING_CLEARED 0x13 /* Added in E1.20-2010 version */ 208 | #define E120_STATUS_ERROR_CLEARED 0x14 /* Added in E1.20-2010 version */ 209 | 210 | 211 | 212 | /********************************************************/ 213 | /* Table A-5: Product Category Defines */ 214 | /********************************************************/ 215 | #define E120_PRODUCT_CATEGORY_NOT_DECLARED 0x0000 216 | 217 | /* Fixtures - intended as source of illumination See Note 1 */ 218 | #define E120_PRODUCT_CATEGORY_FIXTURE 0x0100 /* No Fine Category declared */ 219 | #define E120_PRODUCT_CATEGORY_FIXTURE_FIXED 0x0101 /* No pan / tilt / focus style functions */ 220 | #define E120_PRODUCT_CATEGORY_FIXTURE_MOVING_YOKE 0x0102 221 | #define E120_PRODUCT_CATEGORY_FIXTURE_MOVING_MIRROR 0x0103 222 | #define E120_PRODUCT_CATEGORY_FIXTURE_OTHER 0x01FF /* For example, focus but no pan/tilt. */ 223 | 224 | /* Fixture Accessories - add-ons to fixtures or projectors */ 225 | #define E120_PRODUCT_CATEGORY_FIXTURE_ACCESSORY 0x0200 /* No Fine Category declared. */ 226 | #define E120_PRODUCT_CATEGORY_FIXTURE_ACCESSORY_COLOR 0x0201 /* Scrollers / Color Changers */ 227 | #define E120_PRODUCT_CATEGORY_FIXTURE_ACCESSORY_YOKE 0x0202 /* Yoke add-on */ 228 | #define E120_PRODUCT_CATEGORY_FIXTURE_ACCESSORY_MIRROR 0x0203 /* Moving mirror add-on */ 229 | #define E120_PRODUCT_CATEGORY_FIXTURE_ACCESSORY_EFFECT 0x0204 /* Effects Discs */ 230 | #define E120_PRODUCT_CATEGORY_FIXTURE_ACCESSORY_BEAM 0x0205 /* Gobo Rotators /Iris / Shutters / Dousers/ Beam modifiers. */ 231 | #define E120_PRODUCT_CATEGORY_FIXTURE_ACCESSORY_OTHER 0x02FF 232 | 233 | /* Projectors - light source capable of producing realistic images from another media i.e Video / Slide / Oil Wheel / Film */ 234 | #define E120_PRODUCT_CATEGORY_PROJECTOR 0x0300 /* No Fine Category declared. */ 235 | #define E120_PRODUCT_CATEGORY_PROJECTOR_FIXED 0x0301 /* No pan / tilt functions. */ 236 | #define E120_PRODUCT_CATEGORY_PROJECTOR_MOVING_YOKE 0x0302 237 | #define E120_PRODUCT_CATEGORY_PROJECTOR_MOVING_MIRROR 0x0303 238 | #define E120_PRODUCT_CATEGORY_PROJECTOR_OTHER 0x03FF 239 | 240 | /* Atmospheric Effect - earth/wind/fire */ 241 | #define E120_PRODUCT_CATEGORY_ATMOSPHERIC 0x0400 /* No Fine Category declared. */ 242 | #define E120_PRODUCT_CATEGORY_ATMOSPHERIC_EFFECT 0x0401 /* Fogger / Hazer / Flame, etc. */ 243 | #define E120_PRODUCT_CATEGORY_ATMOSPHERIC_PYRO 0x0402 /* See Note 2. */ 244 | #define E120_PRODUCT_CATEGORY_ATMOSPHERIC_OTHER 0x04FF 245 | 246 | /* Intensity Control (specifically Dimming equipment) */ 247 | #define E120_PRODUCT_CATEGORY_DIMMER 0x0500 /* No Fine Category declared. */ 248 | #define E120_PRODUCT_CATEGORY_DIMMER_AC_INCANDESCENT 0x0501 /* AC > 50VAC */ 249 | #define E120_PRODUCT_CATEGORY_DIMMER_AC_FLUORESCENT 0x0502 250 | #define E120_PRODUCT_CATEGORY_DIMMER_AC_COLDCATHODE 0x0503 /* High Voltage outputs such as Neon or other cold cathode. */ 251 | #define E120_PRODUCT_CATEGORY_DIMMER_AC_NONDIM 0x0504 /* Non-Dim module in dimmer rack. */ 252 | #define E120_PRODUCT_CATEGORY_DIMMER_AC_ELV 0x0505 /* AC <= 50V such as 12/24V AC Low voltage lamps. */ 253 | #define E120_PRODUCT_CATEGORY_DIMMER_AC_OTHER 0x0506 254 | #define E120_PRODUCT_CATEGORY_DIMMER_DC_LEVEL 0x0507 /* Variable DC level output. */ 255 | #define E120_PRODUCT_CATEGORY_DIMMER_DC_PWM 0x0508 /* Chopped (PWM) output. */ 256 | #define E120_PRODUCT_CATEGORY_DIMMER_CS_LED 0x0509 /* Specialized LED dimmer. */ 257 | #define E120_PRODUCT_CATEGORY_DIMMER_OTHER 0x05FF 258 | 259 | /* Power Control (other than Dimming equipment) */ 260 | #define E120_PRODUCT_CATEGORY_POWER 0x0600 /* No Fine Category declared. */ 261 | #define E120_PRODUCT_CATEGORY_POWER_CONTROL 0x0601 /* Contactor racks, other forms of Power Controllers. */ 262 | #define E120_PRODUCT_CATEGORY_POWER_SOURCE 0x0602 /* Generators */ 263 | #define E120_PRODUCT_CATEGORY_POWER_OTHER 0x06FF 264 | 265 | /* Scenic Drive - including motorized effects unrelated to light source. */ 266 | #define E120_PRODUCT_CATEGORY_SCENIC 0x0700 /* No Fine Category declared */ 267 | #define E120_PRODUCT_CATEGORY_SCENIC_DRIVE 0x0701 /* Rotators / Kabuki drops, etc. See Note 2. */ 268 | #define E120_PRODUCT_CATEGORY_SCENIC_OTHER 0x07FF 269 | 270 | /* DMX Infrastructure, conversion and interfaces */ 271 | #define E120_PRODUCT_CATEGORY_DATA 0x0800 /* No Fine Category declared. */ 272 | #define E120_PRODUCT_CATEGORY_DATA_DISTRIBUTION 0x0801 /* Splitters/repeaters/Ethernet products used to distribute DMX*/ 273 | #define E120_PRODUCT_CATEGORY_DATA_CONVERSION 0x0802 /* Protocol Conversion analog decoders. */ 274 | #define E120_PRODUCT_CATEGORY_DATA_OTHER 0x08FF 275 | 276 | /* Audio-Visual Equipment */ 277 | #define E120_PRODUCT_CATEGORY_AV 0x0900 /* No Fine Category declared. */ 278 | #define E120_PRODUCT_CATEGORY_AV_AUDIO 0x0901 /* Audio controller or device. */ 279 | #define E120_PRODUCT_CATEGORY_AV_VIDEO 0x0902 /* Video controller or display device. */ 280 | #define E120_PRODUCT_CATEGORY_AV_OTHER 0x09FF 281 | 282 | /* Parameter Monitoring Equipment See Note 3. */ 283 | #define E120_PRODUCT_CATEGORY_MONITOR 0x0A00 /* No Fine Category declared. */ 284 | #define E120_PRODUCT_CATEGORY_MONITOR_ACLINEPOWER 0x0A01 /* Product that monitors AC line voltage, current or power. */ 285 | #define E120_PRODUCT_CATEGORY_MONITOR_DCPOWER 0x0A02 /* Product that monitors DC line voltage, current or power. */ 286 | #define E120_PRODUCT_CATEGORY_MONITOR_ENVIRONMENTAL 0x0A03 /* Temperature or other environmental parameter. */ 287 | #define E120_PRODUCT_CATEGORY_MONITOR_OTHER 0x0AFF 288 | 289 | /* Controllers, Backup devices */ 290 | #define E120_PRODUCT_CATEGORY_CONTROL 0x7000 /* No Fine Category declared. */ 291 | #define E120_PRODUCT_CATEGORY_CONTROL_CONTROLLER 0x7001 292 | #define E120_PRODUCT_CATEGORY_CONTROL_BACKUPDEVICE 0x7002 293 | #define E120_PRODUCT_CATEGORY_CONTROL_OTHER 0x70FF 294 | 295 | /* Test Equipment */ 296 | #define E120_PRODUCT_CATEGORY_TEST 0x7100 /* No Fine Category declared. */ 297 | #define E120_PRODUCT_CATEGORY_TEST_EQUIPMENT 0x7101 298 | #define E120_PRODUCT_CATEGORY_TEST_EQUIPMENT_OTHER 0x71FF 299 | 300 | /* Miscellaneous */ 301 | #define E120_PRODUCT_CATEGORY_OTHER 0x7FFF /* For devices that aren't described within this table. */ 302 | 303 | /* Manufacturer Specific Categories 0x8000 - 304 | 0xDFFF */ 305 | 306 | 307 | /********************************************************/ 308 | /* Table A-6: Product Detail Defines */ 309 | /********************************************************/ 310 | 311 | #define E120_PRODUCT_DETAIL_NOT DECLARED 0x0000 312 | 313 | /* Generally applied to fixtures */ 314 | #define E120_PRODUCT_DETAIL_ARC 0x0001 315 | #define E120_PRODUCT_DETAIL_METAL_HALIDE 0x0002 316 | #define E120_PRODUCT_DETAIL_INCANDESCENT 0x0003 317 | #define E120_PRODUCT_DETAIL_LED 0x0004 318 | #define E120_PRODUCT_DETAIL_FLUORESCENT 0x0005 319 | #define E120_PRODUCT_DETAIL_COLDCATHODE 0x0006 /*includes Neon/Argon */ 320 | #define E120_PRODUCT_DETAIL_ELECTROLUMINESCENT 0x0007 321 | #define E120_PRODUCT_DETAIL_LASER 0x0008 322 | #define E120_PRODUCT_DETAIL_FLASHTUBE 0x0009 /* Strobes or other flashtubes */ 323 | 324 | /* Generally applied to fixture accessories */ 325 | #define E120_PRODUCT_DETAIL_COLORSCROLLER 0x0100 326 | #define E120_PRODUCT_DETAIL_COLORWHEEL 0x0101 327 | #define E120_PRODUCT_DETAIL_COLORCHANGE 0x0102 /* Semaphore or other type */ 328 | #define E120_PRODUCT_DETAIL_IRIS_DOUSER 0x0103 329 | #define E120_PRODUCT_DETAIL_DIMMING_SHUTTER 0x0104 330 | #define E120_PRODUCT_DETAIL_PROFILE_SHUTTER 0x0105 /* hard-edge beam masking */ 331 | #define E120_PRODUCT_DETAIL_BARNDOOR_SHUTTER 0x0106 /* soft-edge beam masking */ 332 | #define E120_PRODUCT_DETAIL_EFFECTS_DISC 0x0107 333 | #define E120_PRODUCT_DETAIL_GOBO_ROTATOR 0x0108 334 | 335 | /* Generally applied to Projectors */ 336 | #define E120_PRODUCT_DETAIL_VIDEO 0x0200 337 | #define E120_PRODUCT_DETAIL_SLIDE 0x0201 338 | #define E120_PRODUCT_DETAIL_FILM 0x0202 339 | #define E120_PRODUCT_DETAIL_OILWHEEL 0x0203 340 | #define E120_PRODUCT_DETAIL_LCDGATE 0x0204 341 | 342 | /* Generally applied to Atmospheric Effects */ 343 | #define E120_PRODUCT_DETAIL_FOGGER_GLYCOL 0x0300 /* Glycol/Glycerin hazer */ 344 | #define E120_PRODUCT_DETAIL_FOGGER_MINERALOIL 0x0301 /* White Mineral oil hazer */ 345 | #define E120_PRODUCT_DETAIL_FOGGER_WATER 0x0302 /* Water hazer */ 346 | #define E120_PRODUCT_DETAIL_C02 0x0303 /* Dry Ice/Carbon Dioxide based */ 347 | #define E120_PRODUCT_DETAIL_LN2 0x0304 /* Nitrogen based */ 348 | #define E120_PRODUCT_DETAIL_BUBBLE 0x0305 /* including foam */ 349 | #define E120_PRODUCT_DETAIL_FLAME_PROPANE 0x0306 350 | #define E120_PRODUCT_DETAIL_FLAME_OTHER 0x0307 351 | #define E120_PRODUCT_DETAIL_OLEFACTORY_STIMULATOR 0x0308 /* Scents */ 352 | #define E120_PRODUCT_DETAIL_SNOW 0x0309 353 | #define E120_PRODUCT_DETAIL_WATER_JET 0x030A /* Fountain controls etc */ 354 | #define E120_PRODUCT_DETAIL_WIND 0x030B /* Air Mover */ 355 | #define E120_PRODUCT_DETAIL_CONFETTI 0x030C 356 | #define E120_PRODUCT_DETAIL_HAZARD 0x030D /* Any form of pyrotechnic control or device. */ 357 | 358 | /* Generally applied to Dimmers/Power controllers See Note 1 */ 359 | #define E120_PRODUCT_DETAIL_PHASE_CONTROL 0x0400 360 | #define E120_PRODUCT_DETAIL_REVERSE_PHASE_CONTROL 0x0401 /* includes FET/IGBT */ 361 | #define E120_PRODUCT_DETAIL_SINE 0x0402 362 | #define E120_PRODUCT_DETAIL_PWM 0x0403 363 | #define E120_PRODUCT_DETAIL_DC 0x0404 /* Variable voltage */ 364 | #define E120_PRODUCT_DETAIL_HFBALLAST 0x0405 /* for Fluorescent */ 365 | #define E120_PRODUCT_DETAIL_HFHV_NEONBALLAST 0x0406 /* for Neon/Argon and other coldcathode. */ 366 | #define E120_PRODUCT_DETAIL_HFHV_EL 0x0407 /* for Electroluminscent */ 367 | #define E120_PRODUCT_DETAIL_MHR_BALLAST 0x0408 /* for Metal Halide */ 368 | #define E120_PRODUCT_DETAIL_BITANGLE_MODULATION 0x0409 369 | #define E120_PRODUCT_DETAIL_FREQUENCY_MODULATION 0x040A 370 | #define E120_PRODUCT_DETAIL_HIGHFREQUENCY_12V 0x040B /* as commonly used with MR16 lamps */ 371 | #define E120_PRODUCT_DETAIL_RELAY_MECHANICAL 0x040C /* See Note 1 */ 372 | #define E120_PRODUCT_DETAIL_RELAY_ELECTRONIC 0x040D /* See Note 1, Note 2 */ 373 | #define E120_PRODUCT_DETAIL_SWITCH_ELECTRONIC 0x040E /* See Note 1, Note 2 */ 374 | #define E120_PRODUCT_DETAIL_CONTACTOR 0x040F /* See Note 1 */ 375 | 376 | /* Generally applied to Scenic drive */ 377 | #define E120_PRODUCT_DETAIL_MIRRORBALL_ROTATOR 0x0500 378 | #define E120_PRODUCT_DETAIL_OTHER_ROTATOR 0x0501 /* includes turntables */ 379 | #define E120_PRODUCT_DETAIL_KABUKI_DROP 0x0502 380 | #define E120_PRODUCT_DETAIL_CURTAIN 0x0503 /* flown or traveller */ 381 | #define E120_PRODUCT_DETAIL_LINESET 0x0504 382 | #define E120_PRODUCT_DETAIL_MOTOR_CONTROL 0x0505 383 | #define E120_PRODUCT_DETAIL_DAMPER_CONTROL 0x0506 /* HVAC Damper */ 384 | 385 | /* Generally applied to Data Distribution */ 386 | #define E120_PRODUCT_DETAIL_SPLITTER 0x0600 /* Includes buffers/repeaters */ 387 | #define E120_PRODUCT_DETAIL_ETHERNET_NODE 0x0601 /* DMX512 to/from Ethernet */ 388 | #define E120_PRODUCT_DETAIL_MERGE 0x0602 /* DMX512 combiner */ 389 | #define E120_PRODUCT_DETAIL_DATAPATCH 0x0603 /* Electronic Datalink Patch */ 390 | #define E120_PRODUCT_DETAIL_WIRELESS_LINK 0x0604 /* radio/infrared */ 391 | 392 | /* Generally applied to Data Conversion and Interfaces */ 393 | #define E120_PRODUCT_DETAIL_PROTOCOL_CONVERTER 0x0701 /* D54/AMX192/Non DMX serial links, etc to/from DMX512 */ 394 | #define E120_PRODUCT_DETAIL_ANALOG_DEMULTIPLEX 0x0702 /* DMX to DC voltage */ 395 | #define E120_PRODUCT_DETAIL_ANALOG_MULTIPLEX 0x0703 /* DC Voltage to DMX */ 396 | #define E120_PRODUCT_DETAIL_SWITCH_PANEL 0x0704 /* Pushbuttons to DMX or polled using RDM */ 397 | 398 | /* Generally applied to Audio or Video (AV) devices */ 399 | #define E120_PRODUCT_DETAIL_ROUTER 0x0800 /* Switching device */ 400 | #define E120_PRODUCT_DETAIL_FADER 0x0801 /* Single channel */ 401 | #define E120_PRODUCT_DETAIL_MIXER 0x0802 /* Multi-channel */ 402 | 403 | /* Generally applied to Controllers, Backup devices and Test Equipment */ 404 | #define E120_PRODUCT_DETAIL_CHANGEOVER_MANUAL 0x0900 /* requires manual intervention to assume control of DMX line */ 405 | #define E120_PRODUCT_DETAIL_CHANGEOVER_AUTO 0x0901 /* may automatically assume control of DMX line */ 406 | #define E120_PRODUCT_DETAIL_TEST 0x0902 /* test equipment */ 407 | 408 | /* Could be applied to any category */ 409 | #define E120_PRODUCT_DETAIL_GFI_RCD 0x0A00 /* device includes GFI/RCD trip */ 410 | #define E120_PRODUCT_DETAIL_BATTERY 0x0A01 /* device is battery operated */ 411 | #define E120_PRODUCT_DETAIL_CONTROLLABLE_BREAKER 0x0A02 412 | 413 | 414 | #define E120_PRODUCT_DETAIL_OTHER 0x7FFF /* for use where the Manufacturer believes that none of the 415 | defined details apply. */ 416 | /* Manufacturer Specific Types 0x8000- 417 | 0xDFFF */ 418 | 419 | /* Note 1: Products intended for switching 50V AC / 120V DC or greater should be declared with a 420 | Product Category of PRODUCT_CATEGORY_POWER_CONTROL. 421 | 422 | Products only suitable for extra low voltage switching (typically up to 50VAC / 30VDC) at currents 423 | less than 1 ampere should be declared with a Product Category of PRODUCT_CATEGORY_DATA_CONVERSION. 424 | 425 | Please refer to GET: DEVICE_INFO and Table A-5 for an explanation of Product Category declaration. 426 | Note 2: Products with TTL, MOSFET or Open Collector Transistor Outputs or similar non-isolated electronic 427 | outputs should be declared as PRODUCT_DETAIL_SWITCH_ELECTRONIC. Use of PRODUCT_DETAIL_RELAY_ELECTRONIC 428 | shall be restricted to devices whereby the switched circuits are electrically isolated from the control signals. */ 429 | 430 | 431 | /********************************************************/ 432 | /* Table A-7: Preset Playback Defines */ 433 | /********************************************************/ 434 | 435 | #define E120_PRESET_PLAYBACK_OFF 0x0000 /* Returns to Normal DMX512 Input */ 436 | #define E120_PRESET_PLAYBACK_ALL 0xFFFF /* Plays Scenes in Sequence if supported. */ 437 | /* E120_PRESET_PLAYBACK_SCENE 0x0001- 438 | 0xFFFE Plays individual Scene # */ 439 | 440 | /********************************************************/ 441 | /* Table A-8: Lamp State Defines */ 442 | /********************************************************/ 443 | 444 | #define E120_LAMP_OFF 0x00 /* No demonstrable light output */ 445 | #define E120_LAMP_ON 0x01 446 | #define E120_LAMP_STRIKE 0x02 /* Arc-Lamp ignite */ 447 | #define E120_LAMP_STANDBY 0x03 /* Arc-Lamp Reduced Power Mode */ 448 | #define E120_LAMP_NOT_PRESENT 0x04 /* Lamp not installed */ 449 | #define E120_LAMP_ERROR 0x7F 450 | /* Manufacturer-Specific States 0x80- 451 | 0xDF */ 452 | 453 | /********************************************************/ 454 | /* Table A-9: Lamp On Mode Defines */ 455 | /********************************************************/ 456 | 457 | #define E120_LAMP_ON_MODE_OFF 0x00 /* Lamp Stays off until directly instructed to Strike. */ 458 | #define E120_LAMP_ON_MODE_DMX 0x01 /* Lamp Strikes upon receiving a DMX512 signal. */ 459 | #define E120_LAMP_ON_MODE_ON 0x02 /* Lamp Strikes automatically at Power-up. */ 460 | #define E120_LAMP_ON_MODE_AFTER_CAL 0x03 /* Lamp Strikes after Calibration or Homing procedure. */ 461 | /* Manufacturer-Specific Modes 0x80- 462 | 0xDF */ 463 | 464 | /********************************************************/ 465 | /* Table A-10: Self Test Defines */ 466 | /********************************************************/ 467 | 468 | #define E120_SELF_TEST_OFF 0x00 /* Turns Self Tests Off */ 469 | /* Manufacturer Tests 0x01- 470 | 0xFE Various Manufacturer Self Tests */ 471 | #define E120_SELF_TEST_ALL 0xFF /* Self Test All, if applicable */ 472 | 473 | /********************************************************/ 474 | /* Table A-11: Power State Defines */ 475 | /********************************************************/ 476 | 477 | #define E120_POWER_STATE_FULL_OFF 0x00 /* Completely disengages power to device. Device can no longer respond. */ 478 | #define E120_POWER_STATE_SHUTDOWN 0x01 /* Reduced power mode, may require device reset to return to 479 | normal operation. Device still responds to messages. */ 480 | #define E120_POWER_STATE_STANDBY 0x02 /* Reduced power mode. Device can return to NORMAL without a 481 | reset. Device still responds to messages. */ 482 | #define E120_POWER_STATE_NORMAL 0xFF /* Normal Operating Mode. */ 483 | 484 | /********************************************************/ 485 | /* Table A-12: Sensor Type Defines */ 486 | /********************************************************/ 487 | 488 | #define E120_SENS_TEMPERATURE 0x00 489 | #define E120_SENS_VOLTAGE 0x01 490 | #define E120_SENS_CURRENT 0x02 491 | #define E120_SENS_FREQUENCY 0x03 492 | #define E120_SENS_RESISTANCE 0x04 /* Eg: Cable resistance */ 493 | #define E120_SENS_POWER 0x05 494 | #define E120_SENS_MASS 0x06 /* Eg: Truss load Cell */ 495 | #define E120_SENS_LENGTH 0x07 496 | #define E120_SENS_AREA 0x08 497 | #define E120_SENS_VOLUME 0x09 /* Eg: Smoke Fluid */ 498 | #define E120_SENS_DENSITY 0x0A 499 | #define E120_SENS_VELOCITY 0x0B 500 | #define E120_SENS_ACCELERATION 0x0C 501 | #define E120_SENS_FORCE 0x0D 502 | #define E120_SENS_ENERGY 0x0E 503 | #define E120_SENS_PRESSURE 0x0F 504 | #define E120_SENS_TIME 0x10 505 | #define E120_SENS_ANGLE 0x11 506 | #define E120_SENS_POSITION_X 0x12 /* E.g.: Lamp position on Truss */ 507 | #define E120_SENS_POSITION_Y 0x13 508 | #define E120_SENS_POSITION_Z 0x14 509 | #define E120_SENS_ANGULAR_VELOCITY 0x15 /* E.g.: Wind speed */ 510 | #define E120_SENS_LUMINOUS_INTENSITY 0x16 511 | #define E120_SENS_LUMINOUS_FLUX 0x17 512 | #define E120_SENS_ILLUMINANCE 0x18 513 | #define E120_SENS_CHROMINANCE_RED 0x19 514 | #define E120_SENS_CHROMINANCE_GREEN 0x1A 515 | #define E120_SENS_CHROMINANCE_BLUE 0x1B 516 | #define E120_SENS_CONTACTS 0x1C /* E.g.: Switch inputs. */ 517 | #define E120_SENS_MEMORY 0x1D /* E.g.: ROM Size */ 518 | #define E120_SENS_ITEMS 0x1E /* E.g.: Scroller gel frames. */ 519 | #define E120_SENS_HUMIDITY 0x1F 520 | #define E120_SENS_COUNTER_16BIT 0x20 521 | #define E120_SENS_OTHER 0x7F 522 | /* Manufacturer-Specific Sensors 0x80- 523 | 0xFF */ 524 | 525 | /********************************************************/ 526 | /* Table A-13: Sensor Unit Defines */ 527 | /********************************************************/ 528 | 529 | #define E120_UNITS_NONE 0x00 /* CONTACTS */ 530 | #define E120_UNITS_CENTIGRADE 0x01 /* TEMPERATURE */ 531 | #define E120_UNITS_VOLTS_DC 0x02 /* VOLTAGE */ 532 | #define E120_UNITS_VOLTS_AC_PEAK 0x03 /* VOLTAGE */ 533 | #define E120_UNITS_VOLTS_AC_RMS 0x04 /* VOLTAGE */ 534 | #define E120_UNITS_AMPERE_DC 0x05 /* CURRENT */ 535 | #define E120_UNITS_AMPERE_AC_PEAK 0x06 /* CURRENT */ 536 | #define E120_UNITS_AMPERE_AC_RMS 0x07 /* CURRENT */ 537 | #define E120_UNITS_HERTZ 0x08 /* FREQUENCY / ANGULAR_VELOCITY */ 538 | #define E120_UNITS_OHM 0x09 /* RESISTANCE */ 539 | #define E120_UNITS_WATT 0x0A /* POWER */ 540 | #define E120_UNITS_KILOGRAM 0x0B /* MASS */ 541 | #define E120_UNITS_METERS 0x0C /* LENGTH / POSITION */ 542 | #define E120_UNITS_METERS_SQUARED 0x0D /* AREA */ 543 | #define E120_UNITS_METERS_CUBED 0x0E /* VOLUME */ 544 | #define E120_UNITS_KILOGRAMMES_PER_METER_CUBED 0x0F /* DENSITY */ 545 | #define E120_UNITS_METERS_PER_SECOND 0x10 /* VELOCITY */ 546 | #define E120_UNITS_METERS_PER_SECOND_SQUARED 0x11 /* ACCELERATION */ 547 | #define E120_UNITS_NEWTON 0x12 /* FORCE */ 548 | #define E120_UNITS_JOULE 0x13 /* ENERGY */ 549 | #define E120_UNITS_PASCAL 0x14 /* PRESSURE */ 550 | #define E120_UNITS_SECOND 0x15 /* TIME */ 551 | #define E120_UNITS_DEGREE 0x16 /* ANGLE */ 552 | #define E120_UNITS_STERADIAN 0x17 /* ANGLE */ 553 | #define E120_UNITS_CANDELA 0x18 /* LUMINOUS_INTENSITY */ 554 | #define E120_UNITS_LUMEN 0x19 /* LUMINOUS_FLUX */ 555 | #define E120_UNITS_LUX 0x1A /* ILLUMINANCE */ 556 | #define E120_UNITS_IRE 0x1B /* CHROMINANCE */ 557 | #define E120_UNITS_BYTE 0x1C /* MEMORY */ 558 | /* Manufacturer-Specific Units 0x80- 559 | 0xFF */ 560 | 561 | 562 | /********************************************************/ 563 | /* Table A-14: Sensor Unit Prefix Defines */ 564 | /********************************************************/ 565 | 566 | #define E120_PREFIX_NONE 0x00 /* Multiply by 1 */ 567 | #define E120_PREFIX_DECI 0x01 /* Multiply by 10-1 */ 568 | #define E120_PREFIX_CENTI 0x02 /* Multiply by 10-2 */ 569 | #define E120_PREFIX_MILLI 0x03 /* Multiply by 10-3 */ 570 | #define E120_PREFIX_MICRO 0x04 /* Multiply by 10-6 */ 571 | #define E120_PREFIX_NANO 0x05 /* Multiply by 10-9 */ 572 | #define E120_PREFIX_PICO 0x06 /* Multiply by 10-12 */ 573 | #define E120_PREFIX_FEMTO 0x07 /* Multiply by 10-15 */ 574 | #define E120_PREFIX_ATTO 0x08 /* Multiply by 10-18 */ 575 | #define E120_PREFIX_ZEPTO 0x09 /* Multiply by 10-21 */ 576 | #define E120_PREFIX_YOCTO 0x0A /* Multiply by 10-24 */ 577 | #define E120_PREFIX_DECA 0x11 /* Multiply by 10+1 */ 578 | #define E120_PREFIX_HECTO 0x12 /* Multiply by 10+2 */ 579 | #define E120_PREFIX_KILO 0x13 /* Multiply by 10+3 */ 580 | #define E120_PREFIX_MEGA 0x14 /* Multiply by 10+6 */ 581 | #define E120_PREFIX_GIGA 0x15 /* Multiply by 10+9 */ 582 | #define E120_PREFIX_TERA 0x16 /* Multiply by 10+12 */ 583 | #define E120_PREFIX_PETA 0x17 /* Multiply by 10+15 */ 584 | #define E120_PREFIX_EXA 0x18 /* Multiply by 10+18 */ 585 | #define E120_PREFIX_ZETTA 0x19 /* Multiply by 10+21 */ 586 | #define E120_PREFIX_YOTTA 0x1A /* Multiply by 10+24 */ 587 | 588 | 589 | /********************************************************/ 590 | /* Table A-15: Data Type Defines */ 591 | /********************************************************/ 592 | 593 | #define E120_DS_NOT_DEFINED 0x00 /* Data type is not defined */ 594 | #define E120_DS_BIT_FIELD 0x01 /* Data is bit packed */ 595 | #define E120_DS_ASCII 0x02 /* Data is a string */ 596 | #define E120_DS_UNSIGNED_BYTE 0x03 /* Data is an array of unsigned bytes */ 597 | #define E120_DS_SIGNED_BYTE 0x04 /* Data is an array of signed bytes */ 598 | #define E120_DS_UNSIGNED_WORD 0x05 /* Data is an array of unsigned 16-bit words */ 599 | #define E120_DS_SIGNED_WORD 0x06 /* Data is an array of signed 16-bit words */ 600 | #define E120_DS_UNSIGNED_DWORD 0x07 /* Data is an array of unsigned 32-bit words */ 601 | #define E120_DS_SIGNED_DWORD 0x08 /* Data is an array of signed 32-bit words */ 602 | /* Manufacturer-Specific Data Types 0x80- */ 603 | /* 0xDF */ 604 | 605 | /********************************************************/ 606 | /* Table A-16: Parameter Desc. Command Class Defines */ 607 | /********************************************************/ 608 | 609 | #define E120_CC_GET 0x01 /* PID supports GET only */ 610 | #define E120_CC_SET 0x02 /* PID supports SET only */ 611 | #define E120_CC_GET_SET 0x03 /* PID supports GET & SET */ 612 | 613 | /********************************************************/ 614 | /* Table A-17: Response NACK Reason Code Defines */ 615 | /********************************************************/ 616 | 617 | #define E120_NR_UNKNOWN_PID 0x0000 /* The responder cannot comply with request because the message 618 | is not implemented in responder. */ 619 | #define E120_NR_FORMAT_ERROR 0x0001 /* The responder cannot interpret request as controller data 620 | was not formatted correctly. */ 621 | #define E120_NR_HARDWARE_FAULT 0x0002 /* The responder cannot comply due to an internal hardware fault*/ 622 | #define E120_NR_PROXY_REJECT 0x0003 /* Proxy is not the RDM line master and cannot comply with message.*/ 623 | #define E120_NR_WRITE_PROTECT 0x0004 /* SET Command normally allowed but being blocked currently. */ 624 | #define E120_NR_UNSUPPORTED_COMMAND_CLASS 0x0005 /* Not valid for Command Class attempted. May be used where 625 | GET allowed but SET is not supported. */ 626 | #define E120_NR_DATA_OUT_OF_RANGE 0x0006 /* Value for given Parameter out of allowable range or 627 | not supported. */ 628 | #define E120_NR_BUFFER_FULL 0x0007 /* Buffer or Queue space currently has no free space to store data. */ 629 | #define E120_NR_PACKET_SIZE_UNSUPPORTED 0x0008 /* Incoming message exceeds buffer capacity. */ 630 | #define E120_NR_SUB_DEVICE_OUT_OF_RANGE 0x0009 /* Sub-Device is out of range or unknown. */ 631 | #define E120_NR_PROXY_BUFFER_FULL 0x000A /* Proxy buffer is full and can not store any more Queued */ 632 | /* Message or Status Message responses. */ 633 | #define E137_2_NR_ACTION_NOT_SUPPORTED 0x000B /* The parameter data is valid but the SET operation cannot be */ 634 | /* performed with the current configuration. */ 635 | 636 | /********************************************************************************************************************************/ 637 | /********************************************************************************************************************************/ 638 | /* ANSI E1.37-1 DEFINES */ 639 | /********************************************************************************************************************************/ 640 | /********************************************************************************************************************************/ 641 | 642 | /********************************************************/ 643 | /* E1.37-1 Table A-2: Preset Programmed Defines */ 644 | /********************************************************/ 645 | #define E137_1_PRESET_NOT_PROGRAMMED 0x00 /* Preset Scene not programmed. */ 646 | #define E137_1_PRESET_PROGRAMMED 0x01 /* Preset Scene programmed. */ 647 | #define E137_1_PRESET_PROGRAMMED_READ_ONLY 0x02 /* Preset Scene read-only, factory programmed. */ 648 | 649 | /********************************************************/ 650 | /* E1.37-1 Table A-3: Merge Mode Defines */ 651 | /********************************************************/ 652 | #define E137_1_MERGEMODE_DEFAULT 0x00 /* Preset overrides DMX512 default behavior as defined in */ 653 | /* E1.20 PRESET_PLAYBACK */ 654 | #define E137_1_MERGEMODE_HTP 0x01 /* Highest Takes Precedence on slot by slot basis */ 655 | #define E137_1_MERGEMODE_LTP 0x02 /* Latest Takes Precedence from Preset or DMX512 on slot by slot */ 656 | #define E137_1_MERGEMODE_DMX_ONLY 0x03 /* DMX512 only, Preset ignored */ 657 | #define E137_1_MERGEMODE_OTHER 0xFF /* Other (undefined) merge mode */ 658 | 659 | 660 | /********************************************************************************************************************************/ 661 | /********************************************************************************************************************************/ 662 | /* ANSI E1.37-2 DEFINES */ 663 | /********************************************************************************************************************************/ 664 | /********************************************************************************************************************************/ 665 | 666 | /********************************************************/ 667 | /* E1.37-2 Table A-3: DHCP Mode Defines */ 668 | /********************************************************/ 669 | #define E137_2_DHCP_MODE_INACTIVE 0x00 /* IP Address was not obtained via DHCP */ 670 | #define E137_2_DHCP_MODE_ACTIVE 0x01 /* IP Address was obtained via DHCP */ 671 | #define E137_2_DHCP_MODE_UNKNOWN 0x02 /* The system cannot determine if address was obtained via DHCP. */ 672 | --------------------------------------------------------------------------------