Teensy DMX on the Teensy 3.5 and 3.6

Status
Not open for further replies.

harryprayiv

Active member
I am having a bit of trouble getting started with the Teensy DMX library. I realize that it this library is specifically written for the Teensy 3.1, but I am hoping that I can get it ported (or port it myself) to the Teensy 3.5 and 3.6.

The TeensyDMX library works flawlessly with the Teensy 3.5/3.6
____
Some background: I built a Teensy 3.6 into a big custom proto-board with:
- 9 linear pots into 1-9 analog ins on the Teensy 3.6 (w/ individual decoupling capacitors)
- wired a Texas Instruments SN75LBC184D into 0 for UART Receive and 1 for UART Send (schematic attached) and pin 24 as REDE pin.
Texas Instruments SN75LBC184D wiring.jpg

What I am attempting to do:
Create a simple DMX controller that sends pots 1-8 as values (channels 1-16 with two for each fader to get 16 bit DMX values) with the 9th as a master.

____

I have combed through the code for a few days now and here's what I have compiled so far:

DMX commands for Teensy DMX
Code:
setMode(DMX_OUT);   //sets the DMX mode to Send

Dmx.setMode(DMX_IN);    //sets the DMX mode to Receive

Dmx.startTransmit();    // start DMX transmission (initialize?)

Dmx.stopTransmit();     // stop DMX transmission (de-initialize?) 

Dmx.setMode(TeensyDmx::DMX_OUT);


Dmx.setChannels(startaddress, values, length);           //changes multiple RDM channels up to 512 total
setChannels(const uint16_t startAddress, const uint8_t* values, const uint16_t length)


Dmx.setDMXChannels(startaddress, values, length);    //changes multiple DMX channels up to 512 total
setDmxChannels(const uint16_t startAddress, const uint8_t* values, const uint16_t length)


Dmx.setChannel(address, value);            //leaves other RDM channels as they were and changes one channel
setChannel(const uint16_t address, const uint8_t value)

Dmx.setDMXChannel(address, value);     //leaves other DMX channels as they were and changes one channel
setDmxChannel(const uint16_t address, const uint8_t value)

I have been getting really helpful tips from the two creators of the library and now I just need some lights to test it on.


Here is the latest (1/3/2017) code for the libraries (check the actual site because it is changing frequently as of late:

TeensyDMX.cpp:

Code:
#include "teensydmx.h"
#include "rdm.h"

static constexpr uint32_t BREAKSPEED = 100000;
static constexpr uint32_t RDM_BREAKSPEED = 45500;
static constexpr uint32_t BREAKFORMAT = SERIAL_8E1;
static constexpr uint32_t DMXSPEED = 250000;
static constexpr uint32_t DMXFORMAT = SERIAL_8N2;
static constexpr uint16_t NACK_WAS_ACK = 0xffff;  // Send an ACK, not a NACK

// It was an easy job to register a manufacturer id to myself as explained
// on http://tsp.plasa.org/tsp/working_groups/CP/mfctrIDs.php.
// The ID below is designated as a prototyping ID.
static constexpr byte _devID[] = { 0x7f, 0xf0, 0x20, 0x12, 0x00, 0x00 };

// The Device ID for adressing all devices of a manufacturer.
static constexpr byte _devIDGroup[] = { 0x7f, 0xf0, 0xFF, 0xFF, 0xFF, 0xFF };

// The Device ID for adressing all devices: 6 times 0xFF.
static constexpr byte _devIDAll[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };

struct RDMDATA
{
  //byte     StartCode;    // Start Code 0xCC for RDM (discarded by Recv)
  byte     SubStartCode; // Start Code 0x01 for RDM
  byte     Length;       // packet length
  byte     DestID[6];
  byte     SourceID[6];

  byte     _TransNo;     // transaction number, not checked
  byte     ResponseType;    // ResponseType
  byte     _unknown;     // I don't know, ignore this
  uint16_t SubDev;      // sub device number (root = 0)
  byte     CmdClass;     // command class
  uint16_t Parameter;	   // parameter ID
  byte     DataLength;   // parameter data length in bytes
  byte     Data[231];   // data byte field
}; // struct RDMDATA

// the special discovery response message
struct DISCOVERYMSG
{
  byte headerFE[7];
  byte headerAA;
  byte maskedDevID[12];
  byte checksum[4];
}; // struct DISCOVERYMSG

// The DEVICEINFO structure (length = 19) has to be responsed for E120_DEVICE_INFO
// See http://rdm.openlighting.org/pid/display?manufacturer=0&pid=96
struct DEVICEINFO
{
  byte protocolMajor;
  byte protocolMinor;
  uint16_t deviceModel;
  uint16_t productCategory;
  uint32_t softwareVersion;
  uint16_t footprint;
  byte currentPersonality;
  byte personalityCount;
  uint16_t startAddress;
  uint16_t subDeviceCount;
  byte sensorCount;
}; // struct DEVICEINFO

// Instance for UART0, UART1, UART2
static TeensyDmx *uartInstances[3] = {0};

static inline void putInt(void* const buffer, const size_t offset, const uint16_t value)
{
    reinterpret_cast<byte*>(buffer)[offset] = value >> 8;
    reinterpret_cast<byte*>(buffer)[offset + 1] = value & 0xff;
}

TeensyDmx::TeensyDmx(HardwareSerial& uart, struct RDMINIT* rdm, uint8_t redePin) :
    m_uart(uart),
    m_dmxBuffer1{0},
    m_dmxBuffer2{0},
    m_activeBuffer(m_dmxBuffer1),
    m_inactiveBuffer(m_dmxBuffer2),
    m_dmxBufferIndex(0),
    m_frameCount(0),
    m_newFrame(false),
    m_rdmChange(false),
    m_mode(DMX_OFF),
    m_state(State::IDLE),
    m_redePin(portOutputRegister(redePin)),
    m_rdmMute(false),
    m_identifyMode(false),
    m_rdm(rdm),
    m_deviceLabel{0}
{
    pinMode(redePin, OUTPUT);
    *m_redePin = 0;

    if (&m_uart == &Serial1) {
        uartInstances[0] = this;
    } else if (&m_uart == &Serial2) {
        uartInstances[1] = this;
    } else if (&m_uart == &Serial3) {
        uartInstances[2] = this;
    }
}

TeensyDmx::TeensyDmx(HardwareSerial& uart, uint8_t redePin) :
    TeensyDmx(uart, nullptr, redePin)
{
}

const volatile uint8_t* TeensyDmx::getBuffer() const
{
    return m_inactiveBuffer;
}

bool TeensyDmx::isIdentify() const
{
    return m_identifyMode;
}

const char* TeensyDmx::getLabel() const
{
    return m_deviceLabel;
}

void TeensyDmx::setMode(TeensyDmx::Mode mode)
{
    switch (m_mode)
    {
        case DMX_IN:
            stopReceive();
            break;
        case DMX_OUT:
            stopTransmit();
            break;
        default:
            // No action
            break;
    }

    m_mode = mode;

    switch (m_mode)
    {
        case DMX_IN:
            startReceive();
            break;
        case DMX_OUT:
            startTransmit();
            break;
        default:
            *m_redePin = 0;  // Off puts in receive state so as to be passive
            break;
    }
}

void TeensyDmx::setChannel(const uint16_t address, const uint8_t value)
{
    if (address < DMX_BUFFER_SIZE) {
        m_activeBuffer[address] = value;
    }
}

void TeensyDmx::setChannels(
        const uint16_t startAddress, 
        const uint8_t* values,
        const uint16_t length)
{
    uint16_t currentAddress = 0;
    while (currentAddress < startAddress && currentAddress < DMX_BUFFER_SIZE) {
        m_activeBuffer[currentAddress] = 0;
        ++currentAddress;
    }
    for (uint16_t i = 0; i < length && currentAddress < DMX_BUFFER_SIZE; ++i) {
        m_activeBuffer[currentAddress] = values[i];
        ++currentAddress;
    }
    while (currentAddress < DMX_BUFFER_SIZE) {
        m_activeBuffer[currentAddress] = 0;
        ++currentAddress;
    }
}

void TeensyDmx::nextTx()
{
    if (m_state == State::BREAK) {
        m_state = DMX_TX;
        m_uart.begin(DMXSPEED, DMXFORMAT);
        m_uart.write(0);
    } else if (m_state == State::DMX_TX) {
        // Check if we're at the end of the packet
        if (m_dmxBufferIndex == DMX_BUFFER_SIZE) {
            // Send BREAK
            m_state = State::BREAK;
            m_uart.begin(BREAKSPEED, BREAKFORMAT);
            m_uart.write(0);
            m_dmxBufferIndex = 0;
        } else {
            m_uart.write(m_activeBuffer[m_dmxBufferIndex]);
            ++m_dmxBufferIndex;
        }
    }
}

void uart0_status_isr();  // Back reference to serial1.c
void UART0TxStatus()
{
    if ((UART0_C2 & UART_C2_TCIE) && (UART0_S1 & UART_S1_TC)) {
        // TX complete
        uartInstances[0]->nextTx();
    }
    // Call standard ISR too
    uart0_status_isr();
}

void uart1_status_isr();  // Back reference to serial2.c
void UART1TxStatus()
{
    if ((UART1_C2 & UART_C2_TCIE) && (UART1_S1 & UART_S1_TC)) {
        // TX complete
        uartInstances[1]->nextTx();
    }
    // Call standard ISR too
    uart1_status_isr();
}

void uart2_status_isr();  // Back reference to serial3.c
void UART2TxStatus()
{
    if ((UART2_C2 & UART_C2_TCIE) && (UART2_S1 & UART_S1_TC)) {
        // TX complete
        uartInstances[2]->nextTx();
    }
    // Call standard ISR too
    uart2_status_isr();
}

void TeensyDmx::startTransmit()
{
    *m_redePin = 1;

    m_dmxBufferIndex = 0;

    if (&m_uart == &Serial1) {
        // Change interrupt vector to mine to monitor TX complete
        attachInterruptVector(IRQ_UART0_STATUS, UART0TxStatus);
    } else if (&m_uart == &Serial2) {
        // Change interrupt vector to mine to monitor TX complete
        attachInterruptVector(IRQ_UART1_STATUS, UART1TxStatus);
    } else if (&m_uart == &Serial3) {
        // Change interrupt vector to mine to monitor TX complete
        attachInterruptVector(IRQ_UART2_STATUS, UART2TxStatus);
    }

    // Send BREAK
    m_state = State::BREAK;
    m_uart.begin(BREAKSPEED, BREAKFORMAT);
    m_uart.write(0);

}

void TeensyDmx::stopTransmit()
{
    m_uart.end();

    if (&m_uart == &Serial1) {
        attachInterruptVector(IRQ_UART0_STATUS, uart0_status_isr);
    } else if (&m_uart == &Serial2) {
        attachInterruptVector(IRQ_UART1_STATUS, uart1_status_isr);
    } else if (&m_uart == &Serial3) {
        attachInterruptVector(IRQ_UART2_STATUS, uart2_status_isr);
    }
}

bool TeensyDmx::newFrame(void)
{
    if (m_newFrame) {
        m_newFrame = false;
        return true;
    }
    return false;
}

bool TeensyDmx::rdmChanged(void)
{
    if (m_rdmChange) {
        m_rdmChange = false;
        return true;
    }
    return false;
}

void TeensyDmx::completeFrame()
{
    // Ensure we've processed all the data that may still be sitting
    // in software buffers.
    readBytes();

    if (m_state == State::DMX_RECV || m_state == State::DMX_COMPLETE) {
        // Update frame count and swap buffers
        ++m_frameCount;
        if (m_activeBuffer == m_dmxBuffer1) {
            m_activeBuffer = m_dmxBuffer2;
            m_inactiveBuffer = m_dmxBuffer1;
        } else {
            m_activeBuffer = m_dmxBuffer1;
            m_inactiveBuffer = m_dmxBuffer2;
        }
        m_newFrame = true;
    } else if (m_state == State::RDM_RECV) {
        // Check if we need to reply to this RDM message
        m_state = State::IDLE; // Stop the ISR messing up things
        processRDM();
    }
    m_dmxBufferIndex = 0;
    m_state = State::BREAK;
}

void TeensyDmx::rdmUniqueBranch(const unsigned long timingStart, struct RDMDATA* rdm)
{
    if (m_rdmMute) return;

    if (rdm->Length != 36) return;
    if (rdm->DataLength != 12) return;

    if (memcmp(rdm->Data, _devID, sizeof(_devID)) <= 0 &&
            memcmp(_devID, rdm->Data+6, sizeof(_devID)) <= 0) {
        // I'm in range - say hello to the lovely controller
    
        // respond a special discovery message !
        struct DISCOVERYMSG *disc = (struct DISCOVERYMSG*)(m_activeBuffer);
        uint16_t checksum = 6 * 0xFF;

        // fill in the _rdm.discovery response structure
        for (byte i = 0; i < 7; i++) {
            disc->headerFE[i] = 0xFE;
        }
        disc->headerAA = 0xAA;
        for (byte i = 0; i < 6; i++) {
            disc->maskedDevID[i+i]   = _devID[i] | 0xAA;
            disc->maskedDevID[i+i+1] = _devID[i] | 0x55;
            checksum += _devID[i];
        }
        disc->checksum[0] = (checksum >> 8)   | 0xAA;
        disc->checksum[1] = (checksum >> 8)   | 0x55;
        disc->checksum[2] = (checksum & 0xFF) | 0xAA;
        disc->checksum[3] = (checksum & 0xFF) | 0x55;
    
        // Send reply
        stopReceive();
        *m_redePin = 1;
        m_dmxBufferIndex = 0;
        m_uart.begin(RDM_BREAKSPEED, BREAKFORMAT);
        m_uart.write(0);
        m_uart.flush();
        m_uart.begin(DMXSPEED, DMXFORMAT);
        for (uint16_t i = 0; i < sizeof(struct DISCOVERYMSG); ++i) {
            m_uart.write(m_activeBuffer[i]);
            m_uart.flush();
        }
        startReceive();
    }
}

void TeensyDmx::rdmUnmute(const unsigned long timingStart, struct RDMDATA* rdm)
{
    if (rdm->DataLength == 0) {
        m_rdmMute = false;
        // Control field
        rdm->Data[0] = 0;
        rdm->Data[1] = 0;
        rdm->DataLength = 2;
        respondMessage(timingStart, NACK_WAS_ACK);
    }
}

void TeensyDmx::rdmMute(const unsigned long timingStart, struct RDMDATA* rdm)
{
    if (rdm->DataLength == 0) {
        m_rdmMute = true;
        // Control field
        rdm->Data[0] = 0;
        rdm->Data[1] = 0;
        rdm->DataLength = 2;
        respondMessage(timingStart, NACK_WAS_ACK);
    }
}

void TeensyDmx::rdmSetIdentify(const unsigned long timingStart, struct RDMDATA* rdm)
{
    if (rdm->DataLength != 1) {
        // Oversized data
        respondMessage(timingStart, E120_NR_FORMAT_ERROR);
    } else if ((rdm->Data[0] != 0) && (rdm->Data[0] != 1)) {
        // Out of range data
        respondMessage(timingStart, E120_NR_DATA_OUT_OF_RANGE);
    } else {
        m_identifyMode = rdm->Data[0] != 0;
        m_rdmChange = true;
        rdm->DataLength = 0;
        respondMessage(timingStart, NACK_WAS_ACK);
    }
}

void TeensyDmx::rdmSetDeviceLabel(const unsigned long timingStart, struct RDMDATA* rdm)
{
    if (rdm->DataLength > sizeof(m_deviceLabel)) {
        // Oversized data
        respondMessage(timingStart, E120_NR_FORMAT_ERROR);
    } else {
        memcpy(m_deviceLabel, rdm->Data, rdm->DataLength);
        m_deviceLabel[rdm->DataLength] = '\0';
        rdm->DataLength = 0;
        m_rdmChange = true;
        respondMessage(timingStart, NACK_WAS_ACK);
    }
}

void TeensyDmx::rdmSetStartAddress(const unsigned long timingStart, struct RDMDATA* rdm)
{
    if (rdm->DataLength != 2) {
        // Oversized data
        respondMessage(timingStart, E120_NR_FORMAT_ERROR);
    } else {
        uint16_t newStartAddress = (rdm->Data[0] << 8) | (rdm->Data[1]);
        if ((newStartAddress <= 0) || (newStartAddress > DMX_BUFFER_SIZE)) {
            // Out of range start address
            respondMessage(timingStart, E120_NR_DATA_OUT_OF_RANGE);
        } else if (m_rdm == nullptr) {
            respondMessage(timingStart, E120_NR_HARDWARE_FAULT);
        } else {
            m_rdm->startAddress = newStartAddress;
            rdm->DataLength = 0;
            m_rdmChange = true;
            respondMessage(timingStart, NACK_WAS_ACK);
        }
    }
}

void TeensyDmx::rdmSetParameters(const unsigned long timingStart, struct RDMDATA* rdm)
{
    respondMessage(timingStart, E120_NR_UNSUPPORTED_COMMAND_CLASS);
}

void TeensyDmx::rdmGetIdentify(const unsigned long timingStart, struct RDMDATA* rdm)
{
    if (rdm->DataLength > 0) {
        // Unexpected data
        respondMessage(timingStart, E120_NR_FORMAT_ERROR);
    } else if (rdm->SubDev != 0) {
        // No sub-devices supported
        respondMessage(timingStart, E120_NR_SUB_DEVICE_OUT_OF_RANGE);
    } else {
        rdm->Data[0] = m_identifyMode;
        rdm->DataLength = 1;
        respondMessage(timingStart, NACK_WAS_ACK);
    }
}

void TeensyDmx::rdmGetDeviceInfo(const unsigned long timingStart, struct RDMDATA* rdm)
{
    if (rdm->DataLength > 0) {
        // Unexpected data
        respondMessage(timingStart, E120_NR_FORMAT_ERROR);
    } else if (rdm->SubDev != 0) {
        // No sub-devices supported
        respondMessage(timingStart, E120_NR_SUB_DEVICE_OUT_OF_RANGE);
    } else {
        // return all device info data
        // The data has to be responsed in the Data buffer.
        DEVICEINFO *devInfo = (DEVICEINFO *)(rdm->Data);

        devInfo->protocolMajor = 1;
        devInfo->protocolMinor = 0;
        putInt(&devInfo->productCategory, 0, E120_PRODUCT_CATEGORY_DIMMER_CS_LED);
        devInfo->softwareVersion = 0x00000010;  // Endian swapped
        devInfo->currentPersonality = 1;
        devInfo->personalityCount = 1;
        devInfo->subDeviceCount = 0;
        devInfo->sensorCount = 0;
        if (m_rdm == nullptr) {
            devInfo->deviceModel = 0;
            devInfo->startAddress = 0;
            devInfo->footprint = 0;
        } else {
            putInt(&devInfo->deviceModel, 0, m_rdm->deviceModelId);
            putInt(&devInfo->startAddress, 0, m_rdm->startAddress);
            putInt(&devInfo->footprint, 0, m_rdm->footprint);
        }

        rdm->DataLength = sizeof(DEVICEINFO);
        respondMessage(timingStart, NACK_WAS_ACK);
    }
}

void TeensyDmx::rdmGetManufacturerLabel(
        const unsigned long timingStart,
        struct RDMDATA* rdm)
{
    if (rdm->DataLength > 0) {
        // Unexpected data
        respondMessage(timingStart, E120_NR_FORMAT_ERROR);
    } else if (rdm->SubDev != 0) {
        // No sub-devices supported
        respondMessage(timingStart, E120_NR_SUB_DEVICE_OUT_OF_RANGE);
    } else if (m_rdm == nullptr) {
        rdm->DataLength = 0;
        respondMessage(timingStart, NACK_WAS_ACK);
    } else {
        // return the manufacturer label
        rdm->DataLength = strlen(m_rdm->manufacturerLabel);
        memcpy(rdm->Data, m_rdm->manufacturerLabel, rdm->DataLength);
        respondMessage(timingStart, NACK_WAS_ACK);
    }
}

void TeensyDmx::rdmGetModelDescription(
        const unsigned long timingStart,
        struct RDMDATA* rdm)
{
    if (rdm->DataLength > 0) {
        // Unexpected data
        respondMessage(timingStart, E120_NR_FORMAT_ERROR);
    } else if (rdm->SubDev != 0) {
        // No sub-devices supported
        respondMessage(timingStart, E120_NR_SUB_DEVICE_OUT_OF_RANGE);
    } else if (m_rdm == nullptr) {
        rdm->DataLength = 0;
        respondMessage(timingStart, NACK_WAS_ACK);
    } else {
        // return the DEVICE MODEL DESCRIPTION
        rdm->DataLength = strlen(m_rdm->deviceModel);
        memcpy(rdm->Data, m_rdm->deviceModel, rdm->DataLength);
        respondMessage(timingStart, NACK_WAS_ACK);
    }
}

void TeensyDmx::rdmGetDeviceLabel(const unsigned long timingStart, struct RDMDATA* rdm)
{
    if (rdm->DataLength > 0) {
        // Unexpected data
        respondMessage(timingStart, E120_NR_FORMAT_ERROR);
    } else if (rdm->SubDev != 0) {
        // No sub-devices supported
        respondMessage(timingStart, E120_NR_SUB_DEVICE_OUT_OF_RANGE);
    } else {
        rdm->DataLength = strlen(m_deviceLabel);
        memcpy(rdm->Data, m_deviceLabel, rdm->DataLength);
        respondMessage(timingStart, NACK_WAS_ACK);
    }
}

void TeensyDmx::rdmGetSoftwareVersion(
        const unsigned long timingStart,
        struct RDMDATA* rdm)
{
    if (rdm->DataLength > 0) {
        // Unexpected data
        respondMessage(timingStart, E120_NR_FORMAT_ERROR);
    } else if (rdm->SubDev != 0) {
        // No sub-devices supported
        respondMessage(timingStart, E120_NR_SUB_DEVICE_OUT_OF_RANGE);
    } else if (m_rdm == nullptr) {
        rdm->DataLength = 0;
        respondMessage(timingStart, NACK_WAS_ACK);
    } else {
        // return the SOFTWARE_VERSION_LABEL
        rdm->DataLength = strlen(m_rdm->softwareLabel);
        memcpy(rdm->Data, m_rdm->softwareLabel, rdm->DataLength);
        respondMessage(timingStart, NACK_WAS_ACK);
    }
}

void TeensyDmx::rdmGetStartAddress(const unsigned long timingStart, struct RDMDATA* rdm)
{
   if (rdm->DataLength > 0) {
       // Unexpected data
       respondMessage(timingStart, E120_NR_FORMAT_ERROR);
   } else if (rdm->SubDev != 0) {
       // No sub-devices supported
       respondMessage(timingStart, E120_NR_SUB_DEVICE_OUT_OF_RANGE);
   } else {
       if (m_rdm == nullptr) {
           putInt(rdm->Data, 0, 0);
       } else {
           putInt(rdm->Data, 0, m_rdm->startAddress);
       }
       rdm->DataLength = 2;
       respondMessage(timingStart, NACK_WAS_ACK);
   }
}

void TeensyDmx::rdmGetParameters(const unsigned long timingStart, struct RDMDATA* rdm)
{
    if (rdm->DataLength > 0) {
        // Unexpected data
        respondMessage(timingStart, E120_NR_FORMAT_ERROR);
    } else if (rdm->SubDev != 0) {
        // No sub-devices supported
        respondMessage(timingStart, E120_NR_SUB_DEVICE_OUT_OF_RANGE);
    } else {
        if (m_rdm == nullptr) {
            rdm->DataLength = 6;
        } else {
            rdm->DataLength = 2 * (3 + m_rdm->additionalCommandsLength);
            for (int n = 0; n < m_rdm->additionalCommandsLength; ++n) {
                putInt(rdm->Data, 6+n+n, m_rdm->additionalCommands[n]);
            }
        }
        putInt(rdm->Data, 0, E120_MANUFACTURER_LABEL);
        putInt(rdm->Data, 2, E120_DEVICE_MODEL_DESCRIPTION);
        putInt(rdm->Data, 4, E120_DEVICE_LABEL);
        respondMessage(timingStart, NACK_WAS_ACK);
    }
}

void TeensyDmx::processRDM()
{
    unsigned long timingStart = micros();
    struct RDMDATA* rdm = (struct RDMDATA*)(m_activeBuffer);

    bool isForMe = (memcmp(rdm->DestID, _devID, sizeof(_devID)) == 0);
    if (isForMe ||
            memcmp(rdm->DestID, _devIDAll, sizeof(_devIDAll)) == 0 ||
            memcmp(rdm->DestID, _devIDGroup, sizeof(_devIDGroup)) == 0) {

        uint16_t parameter = (rdm->Parameter << 8) | ((rdm->Parameter >> 8) & 0xff);
        switch (rdm->CmdClass)
        {
            case E120_DISCOVERY_COMMAND:
                switch (parameter)
                {
                    case E120_DISC_UNIQUE_BRANCH:
                        rdmUniqueBranch(timingStart, rdm);
                        break;
                    case E120_DISC_UN_MUTE:
                        if (isForMe)
                        {
                            rdmUnmute(timingStart, rdm);
                        }
                        break;
                    case E120_DISC_MUTE:
                        if (isForMe)
                        {
                            rdmMute(timingStart, rdm);
                        }
                        break;
                    default:
                        respondMessage(timingStart, E120_NR_UNKNOWN_PID);
                        break;
                }
                break;
            case E120_SET_COMMAND:
                switch (parameter)
                {
                    case E120_IDENTIFY_DEVICE:
                        rdmSetIdentify(timingStart, rdm);
                        break;
                    case E120_DEVICE_LABEL:
                        rdmSetDeviceLabel(timingStart, rdm);
                        break;
                    case E120_DMX_START_ADDRESS:
                        rdmSetStartAddress(timingStart, rdm);
                        break;
                    case E120_SUPPORTED_PARAMETERS:
                        rdmSetParameters(timingStart, rdm);
                        break;
                    default:
                        respondMessage(timingStart, E120_NR_UNKNOWN_PID);
                        break;
                }
                break;
            case E120_GET_COMMAND:
                switch (parameter)
                {
                    case E120_IDENTIFY_DEVICE:
                        rdmGetIdentify(timingStart, rdm);
                        break;
                    case E120_DEVICE_INFO:
                        rdmGetDeviceInfo(timingStart, rdm);
                        break;
                    case E120_MANUFACTURER_LABEL:
                        rdmGetManufacturerLabel(timingStart, rdm);
                        break;
                    case E120_DEVICE_MODEL_DESCRIPTION:
                        rdmGetModelDescription(timingStart, rdm);
                        break;
                    case E120_DEVICE_LABEL:
                        rdmGetDeviceLabel(timingStart, rdm);
                        break;
                    case E120_SOFTWARE_VERSION_LABEL:
                        rdmGetSoftwareVersion(timingStart, rdm);
                        break;
                    case E120_DMX_START_ADDRESS:
                        rdmGetStartAddress(timingStart, rdm);
                        break;
                    case E120_SUPPORTED_PARAMETERS:
                        rdmGetParameters(timingStart, rdm);
                        break;
                    default:
                        respondMessage(timingStart, E120_NR_UNKNOWN_PID);
                        break;
                }
                break;
            default:
                respondMessage(timingStart, E120_NR_UNKNOWN_PID);
                break;
        }
    }
}

void TeensyDmx::respondMessage(unsigned long timingStart, uint16_t nackReason)
{
    uint16_t i;
    uint16_t checkSum = 0;
    struct RDMDATA* rdm = (struct RDMDATA*)(m_activeBuffer);

    // TIMING: don't send too fast, min: 176 microseconds
    timingStart = micros() - timingStart;
    if (timingStart < 176) {
        delayMicroseconds(176 - timingStart);
    }

    // no need to set these data fields:
    // StartCode, SubStartCode
    if (nackReason == NACK_WAS_ACK) {
        rdm->ResponseType = E120_RESPONSE_TYPE_ACK;
    } else {
        rdm->ResponseType = E120_RESPONSE_TYPE_NACK_REASON;
        rdm->DataLength = 2;
        rdm->Data[0] = (nackReason >> 8) & 0xFF;
        rdm->Data[1] = nackReason & 0xFF;
    }
    rdm->Length = rdm->DataLength + 24; // total packet length

    // swap SrcID into DestID for sending back.
    memcpy(rdm->DestID, rdm->SourceID, sizeof(rdm->SourceID));
    memcpy(rdm->SourceID, _devID, sizeof(_devID));

    ++(rdm->CmdClass);
    // Parameter

    // prepare buffer and Checksum
    checkSum += E120_SC_RDM;
    for (i = 0; i < rdm->Length; i++) {
        checkSum += m_activeBuffer[i];
    }

    // Send reply
    stopReceive();
    *m_redePin = 1;
    m_dmxBufferIndex = 0;

    m_uart.begin(RDM_BREAKSPEED, BREAKFORMAT);
    m_uart.write(0);
    m_uart.flush();
    m_uart.begin(DMXSPEED, DMXFORMAT);
    m_uart.write(E120_SC_RDM);
    m_uart.flush();
    for (uint16_t i = 0; i < rdm->Length; ++i) {
        m_uart.write(m_activeBuffer[i]);
        m_uart.flush();
    }
    m_uart.write(checkSum >> 8);
    m_uart.flush();
    m_uart.write(checkSum & 0xff);
    m_uart.flush();

    // Restart receive
    startReceive();
}

void uart0_error_isr();  // Back reference to serial1.c
// UART0 will throw a frame error on the DMX break pulse.  That's our
// cue to switch buffers and reset the index to zero
void UART0RxError(void)
{
    // On break, uart0_status_isr() will probably have already
    // fired and read the data buffer, clearing the framing error.
    // If for some reason it hasn't, make sure we consume the 0x00
    // byte that was received.
    if (UART0_S1 & UART_S1_FE)
        (void) UART0_D;

    uartInstances[0]->completeFrame();
}

void uart1_error_isr();  // Back reference to serial2.c
// UART1 will throw a frame error on the DMX break pulse.  That's our
// cue to switch buffers and reset the index to zero
void UART1RxError(void)
{
    // On break, uart1_status_isr() will probably have already
    // fired and read the data buffer, clearing the framing error.
    // If for some reason it hasn't, make sure we consume the 0x00
    // byte that was received.
    if (UART1_S1 & UART_S1_FE)
        (void) UART1_D;

    uartInstances[1]->completeFrame();
}

void uart2_error_isr();  // Back reference to serial3.c
// UART2 will throw a frame error on the DMX break pulse.  That's our
// cue to switch buffers and reset the index to zero
void UART2RxError(void)
{
    // On break, uart2_status_isr() will probably have already
    // fired and read the data buffer, clearing the framing error.
    // If for some reason it hasn't, make sure we consume the 0x00
    // byte that was received.
    if (UART2_S1 & UART_S1_FE)
        (void) UART2_D;

    uartInstances[2]->completeFrame();
}

void TeensyDmx::startReceive()
{
    *m_redePin = 0;

    // UART Initialisation
    m_uart.begin(250000);

    if (&m_uart == &Serial1) {
        // Fire UART0 receive interrupt immediately after each byte received
        UART0_RWFIFO = 1;
        
        // Set error IRQ priority lower than that of the status IRQ,
        // so that the status IRQ receives any leftover bytes before
        // we detect and trigger a new frame.
        NVIC_SET_PRIORITY(IRQ_UART0_ERROR,
                          NVIC_GET_PRIORITY(IRQ_UART0_STATUS) + 1);

        // Enable UART0 interrupt on frame error and enable IRQ
        UART0_C3 |= UART_C3_FEIE;
        NVIC_ENABLE_IRQ(IRQ_UART0_ERROR);

        attachInterruptVector(IRQ_UART0_ERROR, UART0RxError);
    } else if (&m_uart == &Serial2) {
        // Fire UART1 receive interrupt immediately after each byte received
        UART1_RWFIFO = 1;

        // Set error IRQ priority lower than that of the status IRQ,
        // so that the status IRQ receives any leftover bytes before
        // we detect and trigger a new frame.
        NVIC_SET_PRIORITY(IRQ_UART1_ERROR,
                          NVIC_GET_PRIORITY(IRQ_UART1_STATUS) + 1);

        // Enable UART1 interrupt on frame error and enable IRQ
        UART1_C3 |= UART_C3_FEIE;
        NVIC_ENABLE_IRQ(IRQ_UART1_ERROR);

        attachInterruptVector(IRQ_UART1_ERROR, UART1RxError);
    } else if (&m_uart == &Serial3) {
        // Fire UART2 receive interrupt immediately after each byte received
        UART2_RWFIFO = 1;
        
        // Set error IRQ priority lower than that of the status IRQ,
        // so that the status IRQ receives any leftover bytes before
        // we detect and trigger a new frame.
        NVIC_SET_PRIORITY(IRQ_UART2_ERROR,
                          NVIC_GET_PRIORITY(IRQ_UART2_STATUS) + 1);

        // Enable UART2 interrupt on frame error and enable IRQ
        UART2_C3 |= UART_C3_FEIE;
        NVIC_ENABLE_IRQ(IRQ_UART2_ERROR);

        attachInterruptVector(IRQ_UART2_ERROR, UART2RxError);
    }

    m_dmxBufferIndex = 0;
    m_state = State::IDLE;
}

void TeensyDmx::stopReceive()
{
    m_uart.end();
    if (&m_uart == &Serial1) {
        UART0_RWFIFO = 0;
        UART0_C3 &= ~UART_C3_FEIE;
        NVIC_DISABLE_IRQ(IRQ_UART0_ERROR);
        attachInterruptVector(IRQ_UART0_ERROR, uart0_error_isr);
    } else if (&m_uart == &Serial2) {
        UART1_RWFIFO = 0;
        UART1_C3 &= ~UART_C3_FEIE;
        NVIC_DISABLE_IRQ(IRQ_UART1_ERROR);
        attachInterruptVector(IRQ_UART1_ERROR, uart1_error_isr);
    } else if (&m_uart == &Serial3) {
        UART2_RWFIFO = 0;
        UART2_C3 &= ~UART_C3_FEIE;
        NVIC_DISABLE_IRQ(IRQ_UART2_ERROR);
        attachInterruptVector(IRQ_UART2_ERROR, uart2_error_isr);
    }
}

void TeensyDmx::readBytes()
{
    __disable_irq();  // Prevents conflicts with the error ISR

    int available = m_uart.available();
    while (available--)
    {
        switch (m_state)
        {
            case State::BREAK:
                switch (m_uart.read())
                {
                    case 0:
                        m_state = State::DMX_RECV;
                        break;
                    case E120_SC_RDM:
                        m_state = State::RDM_RECV;
                        break;
                    default:
                        m_state = State::IDLE;
                        break;
                }
                break;
            case State::RDM_RECV:
            case State::DMX_RECV:
                ++m_dmxBufferIndex;
                m_activeBuffer[m_dmxBufferIndex] = m_uart.read();

                if (m_dmxBufferIndex >= DMX_BUFFER_SIZE) {
                    if (m_state == State::DMX_RECV) {
                        m_state = State::DMX_COMPLETE;
                    } else {
                        m_state = State::IDLE;  // Buffer full
                    }
                }
                break;
            default:
                // Discarding bytes
                m_uart.read();
                break;
        }
    }

    __enable_irq();
}

void TeensyDmx::loop()
{
    if (m_mode == DMX_IN) {
        readBytes();
    }
}

TeensyDMX.h:

Code:
/* TeensyDmx - DMX Sender/Receiver with RDM for Teensy 3.2
   Copyright (c) 2017 Peter Newman, Dan Large, http://daniellarge.co.uk
   Copyright (c) 2017 Chris Staite
   Copyright (c) 2014 Jim Paris
   Copyright (c) 2014 Ward
   Copyright (c) 2008-2009 Peter Knight, Tinker.it! All rights reserved.
   Copyright (c) 2011-2013 by Matthias Hertel, http://www.mathertel.de
   Permission is hereby granted, free of charge, to any person obtaining a copy
   of this software and associated documentation files (the "Software"), to deal
   in the Software without restriction, including without limitation the rights
   to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
   copies of the Software, and to permit persons to whom the Software is
   furnished to do so, subject to the following conditions:
   The above copyright notice and this permission notice shall be included in
   all copies or substantial portions of the Software.
   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
   AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
   OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
   THE SOFTWARE.
*/

#ifndef _TEENSYDMX_H
#define _TEENSYDMX_H

#include "Arduino.h"

#ifndef UART_C3_FEIE
#define UART_C3_FEIE    (uint8_t)0x02   // Framing Error Interrupt Enable
#endif

struct RDMINIT
{
    const char *softwareLabel;
    const char *manufacturerLabel;
    const uint16_t deviceModelId;
    const char  *deviceModel;
    uint16_t footprint;
    uint16_t startAddress;
    const uint16_t  additionalCommandsLength;
    const uint16_t  *additionalCommands;
}; // struct RDMINIT

class TeensyDmx
{
  public:
    enum Mode { DMX_OFF, DMX_IN, DMX_OUT };
    TeensyDmx(HardwareSerial& uart, struct RDMINIT* rdm, uint8_t redePin);
    TeensyDmx(HardwareSerial& uart, uint8_t redePin);
    void setMode(TeensyDmx::Mode mode);
    void loop();

    // Returns true if a new frame has been received since the this was last called
    bool newFrame();
    // Use for receive
    const volatile uint8_t* getBuffer() const;
    // Returns true if RDM has changed since this was last called
    bool rdmChanged();
    // Returns true if the device should be in identify mode
    bool isIdentify() const;
    // Returns the user-set label of the device
    const char* getLabel() const;
    
    // Use for transmit with addresses from 0-511
    // Will keep all other values as they were previously
    void setChannel(const uint16_t address, const uint8_t value);
    // Use for transmit with addresses from 1-512
    // Will keep all other values as they were previously
    void setDmxChannel(const uint16_t address, const uint8_t value)
    {
        setChannel(address - 1, value);
    }

    // Use for transmit with channels from 0-511
    // Will set all other channels to 0
    void setChannels(const uint16_t startAddress, const uint8_t* values, const uint16_t length);
    // Use for transmit with channels from 1-512
    // Will set all other channels to 0
    void setDmxChannels(const uint16_t startAddress, const uint8_t* values, const uint16_t length)
    {
        setChannels(startAddress - 1, values, length);
    }

  private:
    TeensyDmx(const TeensyDmx&);
    TeensyDmx& operator=(const TeensyDmx&);
    
    enum State { IDLE, BREAK, DMX_TX, DMX_RECV, DMX_COMPLETE, RDM_RECV };
    enum { DMX_BUFFER_SIZE = 512 };

    void startTransmit();
    void stopTransmit();
    void startReceive();
    void stopReceive();
    
    void completeFrame();  // Called at error ISR during recv
    void processRDM();
    void respondMessage(unsigned long timingStart, uint16_t nackReason);
    void readBytes();  // Recv handler

    void nextTx();
    
    // RDM handler functions
    void rdmUniqueBranch(const unsigned long timingStart, struct RDMDATA* rdm);
    void rdmUnmute(const unsigned long timingStart, struct RDMDATA* rdm);
    void rdmMute(const unsigned long timingStart, struct RDMDATA* rdm);
    void rdmSetIdentify(const unsigned long timingStart, struct RDMDATA* rdm);
    void rdmSetDeviceLabel(const unsigned long timingStart, struct RDMDATA* rdm);
    void rdmSetStartAddress(const unsigned long timingStart, struct RDMDATA* rdm);
    void rdmSetParameters(const unsigned long timingStart, struct RDMDATA* rdm);
    void rdmGetIdentify(const unsigned long timingStart, struct RDMDATA* rdm);
    void rdmGetDeviceInfo(const unsigned long timingStart, struct RDMDATA* rdm);
    void rdmGetManufacturerLabel(const unsigned long timingStart, struct RDMDATA* rdm);
    void rdmGetModelDescription(const unsigned long timingStart, struct RDMDATA* rdm);
    void rdmGetDeviceLabel(const unsigned long timingStart, struct RDMDATA* rdm);
    void rdmGetSoftwareVersion(const unsigned long timingStart, struct RDMDATA* rdm);
    void rdmGetStartAddress(const unsigned long timingStart, struct RDMDATA* rdm);
    void rdmGetParameters(const unsigned long timingStart, struct RDMDATA* rdm);
    
    HardwareSerial& m_uart;
    
    volatile uint8_t m_dmxBuffer1[DMX_BUFFER_SIZE];
    volatile uint8_t m_dmxBuffer2[DMX_BUFFER_SIZE];
    volatile uint8_t *m_activeBuffer;
    volatile uint8_t *m_inactiveBuffer;
    volatile uint16_t m_dmxBufferIndex;
    volatile unsigned int m_frameCount;
    volatile bool m_newFrame;
    volatile bool m_rdmChange;
    Mode m_mode;
    State m_state;
    volatile uint8_t* m_redePin;
    bool m_rdmMute;
    bool m_identifyMode;
    struct RDMINIT *m_rdm;
    char m_deviceLabel[32];
    
    friend void UART0TxStatus(void);
    friend void UART1TxStatus(void);
    friend void UART2TxStatus(void);
    friend void UART0RxError(void);
    friend void UART1RxError(void);
    friend void UART2RxError(void);
};

#endif  // _TEENSYDMX_H

This library is undergoing massive changes at the moment and I am (currently) unable to test any of them. Still, I am posting the updates here in the code snippets as they come in.

I will make sure to create a documentation file so the next person isn't as confused as I am.
 
Last edited:
Rdm.h

RDM.h

Code:
/*****************************************************************/
/* Entertainment Services Technology Association (ESTA)          */
/* ANSI E1.20 Remote Device Management (RDM) over DMX512 Networks*/
/*****************************************************************/
/*                                                               */
/*                          RDM.h                                */
/*                                                               */
/*****************************************************************/
/* Appendix A Defines for the RDM Protocol.                      */
/* Publish date: 3/31/2006                                       */
/*****************************************************************/
/* Compiled by: Scott M. Blair   8/18/2006                       */
/* Updated 10/11/2011: Adding E1.20-2010 and E1.37-1 defines.    */
/*****************************************************************/
/* For updates see: http://www.rdmprotocol.org                   */
/*****************************************************************/
/* Copyright 2006,2011 Litespeed Design                          */
/*****************************************************************/
/* Permission to use, copy, modify, and distribute this software */
/* is freely granted, provided that this notice is preserved.    */
/*****************************************************************/

/* Protocol version. */
#define E120_PROTOCOL_VERSION                             0x0100

/* RDM START CODE (Slot 0)                                                                                                     */
#define	E120_SC_RDM 									  0xCC

/* RDM Protocol Data Structure ID's (Slot 1)                                                                                   */
#define E120_SC_SUB_MESSAGE 							  0x01

/* Broadcast Device UID's                                                                                                      */
#define E120_BROADCAST_ALL_DEVICES_ID       			  0xFFFFFFFFFFFF   /* (Broadcast all Manufacturers)                    */
//#define ALL_DEVICES_ID  				     			  0xmmmmFFFFFFFF   /* (Specific Manufacturer ID 0xmmmm)                                              */

#define E120_SUB_DEVICE_ALL_CALL 		     			  0xFFFF


/********************************************************/
/* Table A-1: RDM Command Classes (Slot 20)             */
/********************************************************/
#define E120_DISCOVERY_COMMAND                            0x10
#define E120_DISCOVERY_COMMAND_RESPONSE                   0x11
#define E120_GET_COMMAND                                  0x20
#define E120_GET_COMMAND_RESPONSE                         0x21
#define E120_SET_COMMAND                                  0x30
#define E120_SET_COMMAND_RESPONSE                         0x31



/********************************************************/
/* Table A-2: RDM Response Type (Slot 16)               */
/********************************************************/
#define E120_RESPONSE_TYPE_ACK                            0x00
#define E120_RESPONSE_TYPE_ACK_TIMER                      0x01
#define E120_RESPONSE_TYPE_NACK_REASON                    0x02   /* See Table A-17                                              */
#define E120_RESPONSE_TYPE_ACK_OVERFLOW                   0x03   /* Additional Response Data available beyond single response length.*/


/********************************************************/
/* Table A-3: RDM Parameter ID's (Slots 21-22)          */
/********************************************************/
/* Category - Network Management   */
#define E120_DISC_UNIQUE_BRANCH                           0x0001
#define E120_DISC_MUTE                                    0x0002
#define E120_DISC_UN_MUTE                                 0x0003
#define E120_PROXIED_DEVICES                              0x0010
#define E120_PROXIED_DEVICE_COUNT                         0x0011
#define E120_COMMS_STATUS                                 0x0015

/* Category - Status Collection    */
#define E120_QUEUED_MESSAGE                               0x0020 /* See Table A-4                                              */
#define E120_STATUS_MESSAGES                              0x0030 /* See Table A-4                                              */
#define E120_STATUS_ID_DESCRIPTION                        0x0031
#define E120_CLEAR_STATUS_ID                              0x0032
#define E120_SUB_DEVICE_STATUS_REPORT_THRESHOLD           0x0033 /* See Table A-4                                              */

/* Category - RDM Information      */
#define E120_SUPPORTED_PARAMETERS                         0x0050 /* Support required only if supporting Parameters beyond the minimum required set.*/
#define E120_PARAMETER_DESCRIPTION                        0x0051 /* Support required for Manufacturer-Specific PIDs exposed in SUPPORTED_PARAMETERS message */

/* Category - Product Information  */
#define E120_DEVICE_INFO                                  0x0060
#define E120_PRODUCT_DETAIL_ID_LIST                       0x0070
#define E120_DEVICE_MODEL_DESCRIPTION                     0x0080
#define E120_MANUFACTURER_LABEL                           0x0081
#define E120_DEVICE_LABEL                                 0x0082
#define E120_FACTORY_DEFAULTS                             0x0090
#define E120_LANGUAGE_CAPABILITIES                        0x00A0
#define E120_LANGUAGE                                     0x00B0
#define E120_SOFTWARE_VERSION_LABEL                       0x00C0
#define E120_BOOT_SOFTWARE_VERSION_ID                     0x00C1
#define E120_BOOT_SOFTWARE_VERSION_LABEL                  0x00C2

/* Category - DMX512 Setup         */
#define E120_DMX_PERSONALITY                              0x00E0
#define E120_DMX_PERSONALITY_DESCRIPTION                  0x00E1
#define E120_DMX_START_ADDRESS                            0x00F0 /* Support required if device uses a DMX512 Slot.             */
#define E120_SLOT_INFO                                    0x0120
#define E120_SLOT_DESCRIPTION                             0x0121
#define E120_DEFAULT_SLOT_VALUE                           0x0122
#define E137_1_DMX_BLOCK_ADDRESS                          0x0140 /* Defined in ANSI E1.37-1 document                           */
#define E137_1_DMX_FAIL_MODE                              0x0141 /* Defined in ANSI E1.37-1 document                           */
#define E137_1_DMX_STARTUP_MODE                           0x0142 /* Defined in ANSI E1.37-1 document                           */


/* Category - Sensors              */
#define E120_SENSOR_DEFINITION                            0x0200
#define E120_SENSOR_VALUE                                 0x0201
#define E120_RECORD_SENSORS                               0x0202

/* Category - Dimmer Settings      */
#define E137_1_DIMMER_INFO                                0x0340
#define E137_1_MINIMUM_LEVEL                              0x0341
#define E137_1_MAXIMUM_LEVEL                              0x0342
#define E137_1_CURVE                                      0x0343
#define E137_1_CURVE_DESCRIPTION                          0x0344 /* Support required if CURVE is supported                     */
#define E137_1_OUTPUT_RESPONSE_TIME                       0x0345
#define E137_1_OUTPUT_RESPONSE_TIME_DESCRIPTION           0x0346 /* Support required if OUTPUT_RESPONSE_TIME is supported      */
#define E137_1_MODULATION_FREQUENCY                       0x0347
#define E137_1_MODULATION_FREQUENCY_DESCRIPTION           0x0348 /* Support required if MODULATION_FREQUENCY is supported      */

/* Category - Power/Lamp Settings  */
#define E120_DEVICE_HOURS                                 0x0400
#define E120_LAMP_HOURS                                   0x0401
#define E120_LAMP_STRIKES                                 0x0402
#define E120_LAMP_STATE                                   0x0403 /* See Table A-8                                              */
#define E120_LAMP_ON_MODE                                 0x0404 /* See Table A-9                                              */
#define E120_DEVICE_POWER_CYCLES                          0x0405
#define E137_1_BURN_IN									  0x0440 /* Defined in ANSI E1.37-1                                    */

/* Category - Display Settings     */
#define E120_DISPLAY_INVERT                               0x0500
#define E120_DISPLAY_LEVEL                                0x0501

/* Category - Configuration        */
#define E120_PAN_INVERT                                   0x0600
#define E120_TILT_INVERT                                  0x0601
#define E120_PAN_TILT_SWAP                                0x0602
#define E120_REAL_TIME_CLOCK                              0x0603
#define E137_1_LOCK_PIN                                   0x0640 /* Defined in ANSI E1.37-1                                    */
#define E137_1_LOCK_STATE                                 0x0641 /* Defined in ANSI E1.37-1                                    */
#define E137_1_LOCK_STATE_DESCRIPTION                     0x0642 /* Support required if MODULATION_FREQUENCY is supported      */

/* Category - Control              */
#define E120_IDENTIFY_DEVICE                              0x1000
#define E120_RESET_DEVICE                                 0x1001
#define E120_POWER_STATE                                  0x1010 /* See Table A-11                                              */
#define E120_PERFORM_SELFTEST                             0x1020 /* See Table A-10                                              */
#define E120_SELF_TEST_DESCRIPTION                        0x1021
#define E120_CAPTURE_PRESET                               0x1030
#define E120_PRESET_PLAYBACK                              0x1031 /* See Table A-7                                               */
#define E137_1_IDENTIFY_MODE                              0x1040 /* Defined in ANSI E1.37-1                                     */
#define E137_1_PRESET_INFO                                0x1041 /* Defined in ANSI E1.37-1                                     */
#define E137_1_PRESET_STATUS                              0x1042 /* Defined in ANSI E1.37-1                                     */
#define E137_1_PRESET_MERGEMODE                           0x1043 /* See E1.37-1 Table A-3                                       */
#define E137_1_POWER_ON_SELF_TEST                         0x1044 /* Defined in ANSI E1.37-1                                     */

/* ESTA Reserved Future RDM Development                   0x7FE0-
                                                          0x7FFF
   Manufacturer-Specific PIDs                             0x8000-
                                                          0xFFDF
   ESTA Reserved Future RDM Development
                                                          0xFFE0-
                                                          0xFFFF
*/


/*****************************************************************/
/* Discovery Mute/Un-Mute Messages Control Field. See Table 7-3. */
/*****************************************************************/
#define E120_CONTROL_PROXIED_DEVICE                       0x0008
#define E120_CONTROL_BOOT_LOADER                          0x0004
#define E120_CONTROL_SUB_DEVICE                           0x0002
#define E120_CONTROL_MANAGED_PROXY                        0x0001


/********************************************************/
/* Table A-4: Status Type Defines                       */
/********************************************************/
#define E120_STATUS_NONE                                  0x00   /* Not allowed for use with GET: QUEUED_MESSAGE                */
#define E120_STATUS_GET_LAST_MESSAGE                      0x01
#define E120_STATUS_ADVISORY                              0x02
#define E120_STATUS_WARNING                               0x03
#define E120_STATUS_ERROR                                 0x04
#define E120_STATUS_ADVISORY_CLEARED                      0x12  /* Added in E1.20-2010 version                                  */
#define E120_STATUS_WARNING_CLEARED                       0x13  /* Added in E1.20-2010 version                                  */
#define E120_STATUS_ERROR_CLEARED                         0x14  /* Added in E1.20-2010 version                                  */



/********************************************************/
/* Table A-5: Product Category Defines                  */
/********************************************************/
#define E120_PRODUCT_CATEGORY_NOT_DECLARED                0x0000

/* Fixtures - intended as source of illumination See Note 1                                                                     */
#define E120_PRODUCT_CATEGORY_FIXTURE                     0x0100 /* No Fine Category declared                                   */
#define E120_PRODUCT_CATEGORY_FIXTURE_FIXED               0x0101 /* No pan / tilt / focus style functions                       */
#define E120_PRODUCT_CATEGORY_FIXTURE_MOVING_YOKE         0x0102
#define E120_PRODUCT_CATEGORY_FIXTURE_MOVING_MIRROR       0x0103
#define E120_PRODUCT_CATEGORY_FIXTURE_OTHER               0x01FF /* For example, focus but no pan/tilt.                         */

/* Fixture Accessories - add-ons to fixtures or projectors                                                                      */
#define E120_PRODUCT_CATEGORY_FIXTURE_ACCESSORY           0x0200 /* No Fine Category declared.                                  */
#define E120_PRODUCT_CATEGORY_FIXTURE_ACCESSORY_COLOR     0x0201 /* Scrollers / Color Changers                                  */
#define E120_PRODUCT_CATEGORY_FIXTURE_ACCESSORY_YOKE      0x0202 /* Yoke add-on                                                 */
#define E120_PRODUCT_CATEGORY_FIXTURE_ACCESSORY_MIRROR    0x0203 /* Moving mirror add-on                                        */
#define E120_PRODUCT_CATEGORY_FIXTURE_ACCESSORY_EFFECT    0x0204 /* Effects Discs                                               */
#define E120_PRODUCT_CATEGORY_FIXTURE_ACCESSORY_BEAM      0x0205 /* Gobo Rotators /Iris / Shutters / Dousers/ Beam modifiers.   */
#define E120_PRODUCT_CATEGORY_FIXTURE_ACCESSORY_OTHER     0x02FF

/* Projectors - light source capable of producing realistic images from another media i.e Video / Slide / Oil Wheel / Film */
#define E120_PRODUCT_CATEGORY_PROJECTOR                   0x0300 /* No Fine Category declared.                                  */
#define E120_PRODUCT_CATEGORY_PROJECTOR_FIXED             0x0301 /* No pan / tilt functions.                                    */
#define E120_PRODUCT_CATEGORY_PROJECTOR_MOVING_YOKE       0x0302
#define E120_PRODUCT_CATEGORY_PROJECTOR_MOVING_MIRROR     0x0303
#define E120_PRODUCT_CATEGORY_PROJECTOR_OTHER             0x03FF

/* Atmospheric Effect - earth/wind/fire                                                                                         */
#define E120_PRODUCT_CATEGORY_ATMOSPHERIC                 0x0400 /* No Fine Category declared.                                  */
#define E120_PRODUCT_CATEGORY_ATMOSPHERIC_EFFECT          0x0401 /* Fogger / Hazer / Flame, etc.                                */
#define E120_PRODUCT_CATEGORY_ATMOSPHERIC_PYRO            0x0402 /* See Note 2.                                                 */
#define E120_PRODUCT_CATEGORY_ATMOSPHERIC_OTHER           0x04FF

/* Intensity Control (specifically Dimming equipment)                                                                           */
#define E120_PRODUCT_CATEGORY_DIMMER                      0x0500 /* No Fine Category declared.                                  */
#define E120_PRODUCT_CATEGORY_DIMMER_AC_INCANDESCENT      0x0501 /* AC > 50VAC                                                  */
#define E120_PRODUCT_CATEGORY_DIMMER_AC_FLUORESCENT       0x0502
#define E120_PRODUCT_CATEGORY_DIMMER_AC_COLDCATHODE       0x0503 /* High Voltage outputs such as Neon or other cold cathode.    */
#define E120_PRODUCT_CATEGORY_DIMMER_AC_NONDIM            0x0504 /* Non-Dim module in dimmer rack.                              */
#define E120_PRODUCT_CATEGORY_DIMMER_AC_ELV               0x0505 /* AC <= 50V such as 12/24V AC Low voltage lamps.              */
#define E120_PRODUCT_CATEGORY_DIMMER_AC_OTHER             0x0506
#define E120_PRODUCT_CATEGORY_DIMMER_DC_LEVEL             0x0507 /* Variable DC level output.                                   */
#define E120_PRODUCT_CATEGORY_DIMMER_DC_PWM               0x0508 /* Chopped (PWM) output.                                       */
#define E120_PRODUCT_CATEGORY_DIMMER_CS_LED               0x0509 /* Specialized LED dimmer.                                     */
#define E120_PRODUCT_CATEGORY_DIMMER_OTHER                0x05FF

/* Power Control (other than Dimming equipment)                                                                                 */
#define E120_PRODUCT_CATEGORY_POWER                       0x0600 /* No Fine Category declared.                                  */
#define E120_PRODUCT_CATEGORY_POWER_CONTROL               0x0601 /* Contactor racks, other forms of Power Controllers.          */
#define E120_PRODUCT_CATEGORY_POWER_SOURCE                0x0602 /* Generators                                                  */
#define E120_PRODUCT_CATEGORY_POWER_OTHER                 0x06FF

/* Scenic Drive - including motorized effects unrelated to light source.                                                        */
#define E120_PRODUCT_CATEGORY_SCENIC                      0x0700 /* No Fine Category declared                                   */
#define E120_PRODUCT_CATEGORY_SCENIC_DRIVE                0x0701 /* Rotators / Kabuki drops, etc. See Note 2.                   */
#define E120_PRODUCT_CATEGORY_SCENIC_OTHER                0x07FF

/* DMX Infrastructure, conversion and interfaces                                                                                */
#define E120_PRODUCT_CATEGORY_DATA                        0x0800 /* No Fine Category declared.                                  */
#define E120_PRODUCT_CATEGORY_DATA_DISTRIBUTION           0x0801 /* Splitters/repeaters/Ethernet products used to distribute DMX*/
#define E120_PRODUCT_CATEGORY_DATA_CONVERSION             0x0802 /* Protocol Conversion analog decoders.                        */
#define E120_PRODUCT_CATEGORY_DATA_OTHER                  0x08FF

/* Audio-Visual Equipment                                                                                                       */
#define E120_PRODUCT_CATEGORY_AV                          0x0900 /* No Fine Category declared.                                  */
#define E120_PRODUCT_CATEGORY_AV_AUDIO                    0x0901 /* Audio controller or device.                                 */
#define E120_PRODUCT_CATEGORY_AV_VIDEO                    0x0902 /* Video controller or display device.                         */
#define E120_PRODUCT_CATEGORY_AV_OTHER                    0x09FF

/* Parameter Monitoring Equipment See Note 3.                                                                                   */
#define E120_PRODUCT_CATEGORY_MONITOR                     0x0A00 /* No Fine Category declared.                                  */
#define E120_PRODUCT_CATEGORY_MONITOR_ACLINEPOWER         0x0A01 /* Product that monitors AC line voltage, current or power.    */
#define E120_PRODUCT_CATEGORY_MONITOR_DCPOWER             0x0A02 /* Product that monitors DC line voltage, current or power.    */
#define E120_PRODUCT_CATEGORY_MONITOR_ENVIRONMENTAL       0x0A03 /* Temperature or other environmental parameter.               */
#define E120_PRODUCT_CATEGORY_MONITOR_OTHER               0x0AFF

/* Controllers, Backup devices                                                                                                  */
#define E120_PRODUCT_CATEGORY_CONTROL                     0x7000 /* No Fine Category declared.                                  */
#define E120_PRODUCT_CATEGORY_CONTROL_CONTROLLER          0x7001
#define E120_PRODUCT_CATEGORY_CONTROL_BACKUPDEVICE        0x7002
#define E120_PRODUCT_CATEGORY_CONTROL_OTHER               0x70FF

/* Test Equipment                                                                                                               */
#define E120_PRODUCT_CATEGORY_TEST                        0x7100 /* No Fine Category declared.                                  */
#define E120_PRODUCT_CATEGORY_TEST_EQUIPMENT              0x7101
#define E120_PRODUCT_CATEGORY_TEST_EQUIPMENT_OTHER        0x71FF

/* Miscellaneous                                                                                                                */
#define E120_PRODUCT_CATEGORY_OTHER                       0x7FFF /* For devices that aren't described within this table.        */

/* Manufacturer Specific Categories                       0x8000 -
                                                          0xDFFF                                                                */


/********************************************************/
/* Table A-6: Product Detail Defines                    */
/********************************************************/

#define E120_PRODUCT_DETAIL_NOT DECLARED                  0x0000

/* Generally applied to fixtures                                                                                                */
#define E120_PRODUCT_DETAIL_ARC                           0x0001
#define E120_PRODUCT_DETAIL_METAL_HALIDE                  0x0002
#define E120_PRODUCT_DETAIL_INCANDESCENT                  0x0003
#define E120_PRODUCT_DETAIL_LED                           0x0004
#define E120_PRODUCT_DETAIL_FLUROESCENT                   0x0005
#define E120_PRODUCT_DETAIL_COLDCATHODE                   0x0006  /*includes Neon/Argon                                         */
#define E120_PRODUCT_DETAIL_ELECTROLUMINESCENT            0x0007
#define E120_PRODUCT_DETAIL_LASER                         0x0008
#define E120_PRODUCT_DETAIL_FLASHTUBE                     0x0009 /* Strobes or other flashtubes                                 */

/* Generally applied to fixture accessories                                                                                     */
#define E120_PRODUCT_DETAIL_COLORSCROLLER                 0x0100
#define E120_PRODUCT_DETAIL_COLORWHEEL                    0x0101
#define E120_PRODUCT_DETAIL_COLORCHANGE                   0x0102 /* Semaphore or other type                                     */
#define E120_PRODUCT_DETAIL_IRIS_DOUSER                   0x0103
#define E120_PRODUCT_DETAIL_DIMMING_SHUTTER               0x0104
#define E120_PRODUCT_DETAIL_PROFILE_SHUTTER               0x0105 /* hard-edge beam masking                                      */
#define E120_PRODUCT_DETAIL_BARNDOOR_SHUTTER              0x0106 /* soft-edge beam masking                                      */
#define E120_PRODUCT_DETAIL_EFFECTS_DISC                  0x0107
#define E120_PRODUCT_DETAIL_GOBO_ROTATOR                  0x0108

/* Generally applied to Projectors                                                                                              */
#define E120_PRODUCT_DETAIL_VIDEO                         0x0200
#define E120_PRODUCT_DETAIL_SLIDE                         0x0201
#define E120_PRODUCT_DETAIL_FILM                          0x0202
#define E120_PRODUCT_DETAIL_OILWHEEL                      0x0203
#define E120_PRODUCT_DETAIL_LCDGATE                       0x0204

/* Generally applied to Atmospheric Effects                                                                                     */
#define E120_PRODUCT_DETAIL_FOGGER_GLYCOL                 0x0300 /* Glycol/Glycerin hazer                                       */
#define E120_PRODUCT_DETAIL_FOGGER_MINERALOIL             0x0301 /* White Mineral oil hazer                                     */
#define E120_PRODUCT_DETAIL_FOGGER_WATER                  0x0302 /* Water hazer                                                 */
#define E120_PRODUCT_DETAIL_C02                           0x0303 /* Dry Ice/Carbon Dioxide based                                */
#define E120_PRODUCT_DETAIL_LN2                           0x0304 /* Nitrogen based                                              */
#define E120_PRODUCT_DETAIL_BUBBLE                        0x0305 /* including foam                                              */
#define E120_PRODUCT_DETAIL_FLAME_PROPANE                 0x0306
#define E120_PRODUCT_DETAIL_FLAME_OTHER                   0x0307
#define E120_PRODUCT_DETAIL_OLEFACTORY_STIMULATOR         0x0308 /* Scents                                                      */
#define E120_PRODUCT_DETAIL_SNOW                          0x0309
#define E120_PRODUCT_DETAIL_WATER_JET                     0x030A /* Fountain controls etc                                       */
#define E120_PRODUCT_DETAIL_WIND                          0x030B /* Air Mover                                                   */
#define E120_PRODUCT_DETAIL_CONFETTI                      0x030C
#define E120_PRODUCT_DETAIL_HAZARD                        0x030D /* Any form of pyrotechnic control or device.                  */

/* Generally applied to Dimmers/Power controllers See Note 1                                                                    */
#define E120_PRODUCT_DETAIL_PHASE_CONTROL                 0x0400
#define E120_PRODUCT_DETAIL_REVERSE_PHASE_CONTROL         0x0401 /* includes FET/IGBT                                           */
#define E120_PRODUCT_DETAIL_SINE                          0x0402
#define E120_PRODUCT_DETAIL_PWM                           0x0403
#define E120_PRODUCT_DETAIL_DC                            0x0404 /* Variable voltage                                            */
#define E120_PRODUCT_DETAIL_HFBALLAST                     0x0405 /* for Fluroescent                                             */
#define E120_PRODUCT_DETAIL_HFHV_NEONBALLAST              0x0406 /* for Neon/Argon and other coldcathode.                       */
#define E120_PRODUCT_DETAIL_HFHV_EL                       0x0407 /* for Electroluminscent                                       */
#define E120_PRODUCT_DETAIL_MHR_BALLAST                   0x0408 /* for Metal Halide                                            */
#define E120_PRODUCT_DETAIL_BITANGLE_MODULATION           0x0409
#define E120_PRODUCT_DETAIL_FREQUENCY_MODULATION          0x040A
#define E120_PRODUCT_DETAIL_HIGHFREQUENCY_12V             0x040B /* as commonly used with MR16 lamps                            */
#define E120_PRODUCT_DETAIL_RELAY_MECHANICAL              0x040C /* See Note 1                                                  */
#define E120_PRODUCT_DETAIL_RELAY_ELECTRONIC              0x040D /* See Note 1, Note 2                                          */
#define E120_PRODUCT_DETAIL_SWITCH_ELECTRONIC             0x040E /* See Note 1, Note 2                                          */
#define E120_PRODUCT_DETAIL_CONTACTOR                     0x040F /* See Note 1                                                  */

/* Generally applied to Scenic drive                                                                                            */
#define E120_PRODUCT_DETAIL_MIRRORBALL_ROTATOR            0x0500
#define E120_PRODUCT_DETAIL_OTHER_ROTATOR                 0x0501 /* includes turntables                                         */
#define E120_PRODUCT_DETAIL_KABUKI_DROP                   0x0502
#define E120_PRODUCT_DETAIL_CURTAIN                       0x0503 /* flown or traveller                                          */
#define E120_PRODUCT_DETAIL_LINESET                       0x0504
#define E120_PRODUCT_DETAIL_MOTOR_CONTROL                 0x0505
#define E120_PRODUCT_DETAIL_DAMPER_CONTROL                0x0506 /* HVAC Damper                                                 */

/* Generally applied to Data Distribution                                                                                       */
#define E120_PRODUCT_DETAIL_SPLITTER                      0x0600 /* Includes buffers/repeaters                                  */
#define E120_PRODUCT_DETAIL_ETHERNET_NODE                 0x0601 /* DMX512 to/from Ethernet                                     */
#define E120_PRODUCT_DETAIL_MERGE                         0x0602 /* DMX512 combiner                                             */
#define E120_PRODUCT_DETAIL_DATAPATCH                     0x0603 /* Electronic Datalink Patch                                   */
#define E120_PRODUCT_DETAIL_WIRELESS_LINK                 0x0604 /* radio/infrared                                              */

/* Generally applied to Data Conversion and Interfaces                                                                          */
#define E120_PRODUCT_DETAIL_PROTOCOL_CONVERTOR            0x0701 /* D54/AMX192/Non DMX serial links, etc to/from DMX512         */
#define E120_PRODUCT_DETAIL_ANALOG_DEMULTIPLEX            0x0702 /* DMX to DC voltage                                           */
#define E120_PRODUCT_DETAIL_ANALOG_MULTIPLEX              0x0703 /* DC Voltage to DMX                                           */
#define E120_PRODUCT_DETAIL_SWITCH_PANEL                  0x0704 /* Pushbuttons to DMX or polled using RDM                      */

/* Generally applied to Audio or Video (AV) devices                                                                             */
#define E120_PRODUCT_DETAIL_ROUTER                        0x0800 /* Switching device                                            */
#define E120_PRODUCT_DETAIL_FADER                         0x0801 /* Single channel                                              */
#define E120_PRODUCT_DETAIL_MIXER                         0x0802 /* Multi-channel                                               */

/* Generally applied to Controllers, Backup devices and Test Equipment                                                          */
#define E120_PRODUCT_DETAIL_CHANGEOVER_MANUAL            0x0900 /* requires manual intervention to assume control of DMX line   */
#define E120_PRODUCT_DETAIL_CHANGEOVER_AUTO              0x0901 /* may automatically assume control of DMX line                 */
#define E120_PRODUCT_DETAIL_TEST                         0x0902 /* test equipment                                               */

/* Could be applied to any category                                                                                             */
#define E120_PRODUCT_DETAIL_GFI_RCD                      0x0A00 /* device includes GFI/RCD trip                                 */
#define E120_PRODUCT_DETAIL_BATTERY                      0x0A01 /* device is battery operated                                   */
#define E120_PRODUCT_DETAIL_CONTROLLABLE_BREAKER         0x0A02


#define E120_PRODUCT_DETAIL_OTHER                        0x7FFF /* for use where the Manufacturer believes that none of the
                                                                   defined details apply.                                            */
/* Manufacturer Specific Types                           0x8000-
                                                         0xDFFF                                                                 */

/* Note 1: Products intended for switching 50V AC / 120V DC or greater should be declared with a
           Product Category of PRODUCT_CATEGORY_POWER_CONTROL.
           Products only suitable for extra low voltage switching (typically up to 50VAC / 30VDC) at currents
           less than 1 ampere should be declared with a Product Category of PRODUCT_CATEGORY_DATA_CONVERSION.
           Please refer to GET: DEVICE_INFO and Table A-5 for an explanation of Product Category declaration.
   Note 2: Products with TTL, MOSFET or Open Collector Transistor Outputs or similar non-isolated electronic
           outputs should be declared as PRODUCT_DETAIL_SWITCH_ELECTRONIC. Use of PRODUCT_DETAIL_RELAY_ELECTRONIC
           shall be restricted to devices whereby the switched circuits are electrically isolated from the control signals.     */


/********************************************************/
/* Table A-7: Preset Playback Defines                   */
/********************************************************/

#define E120_PRESET_PLAYBACK_OFF                         0x0000 /* Returns to Normal DMX512 Input                               */
#define E120_PRESET_PLAYBACK_ALL                         0xFFFF /* Plays Scenes in Sequence if supported.                       */
/*      E120_PRESET_PLAYBACK_SCENE                       0x0001-
                                                         0xFFFE    Plays individual Scene #                                     */

/********************************************************/
/* Table A-8: Lamp State Defines                        */
/********************************************************/

#define E120_LAMP_OFF                                    0x00   /* No demonstrable light output                                 */
#define E120_LAMP_ON                                     0x01
#define E120_LAMP_STRIKE                                 0x02   /* Arc-Lamp ignite                                              */
#define E120_LAMP_STANDBY                                0x03   /* Arc-Lamp Reduced Power Mode                                  */
#define E120_LAMP_NOT_PRESENT                            0x04   /* Lamp not installed                                           */
#define E120_LAMP_ERROR                                  0x7F
/* Manufacturer-Specific States                          0x80-
                                                         0xDF                                                                   */

/********************************************************/
/* Table A-9: Lamp On Mode Defines                      */
/********************************************************/

#define E120_LAMP_ON_MODE_OFF                            0x00   /* Lamp Stays off until directly instructed to Strike.          */
#define E120_LAMP_ON_MODE_DMX                            0x01   /* Lamp Strikes upon receiving a DMX512 signal.                 */
#define E120_LAMP_ON_MODE_ON                             0x02   /* Lamp Strikes automatically at Power-up.                      */
#define E120_LAMP_ON_MODE_AFTER_CAL                      0x03   /* Lamp Strikes after Calibration or Homing procedure.          */
/* Manufacturer-Specific Modes                           0x80-
                                                         0xDF                                                                   */

/********************************************************/
/* Table A-10: Self Test Defines                        */
/********************************************************/

#define E120_SELF_TEST_OFF                               0x00   /* Turns Self Tests Off                                         */
/* Manufacturer Tests                                    0x01-
                                                         0xFE      Various Manufacturer Self Tests                              */
#define E120_SELF_TEST_ALL                               0xFF   /* Self Test All, if applicable                                 */

/********************************************************/
/* Table A-11: Power State Defines                      */
/********************************************************/

#define E120_POWER_STATE_FULL_OFF                        0x00   /* Completely disengages power to device. Device can no longer respond. */
#define E120_POWER_STATE_SHUTDOWN                        0x01   /* Reduced power mode, may require device reset to return to
                                                                   normal operation. Device still responds to messages.         */
#define E120_POWER_STATE_STANDBY                         0x02   /* Reduced power mode. Device can return to NORMAL without a
                                                                   reset. Device still responds to messages.                    */
#define E120_POWER_STATE_NORMAL                          0xFF   /* Normal Operating Mode.                                       */

/********************************************************/
/* Table A-12: Sensor Type Defines                      */
/********************************************************/

#define E120_SENS_TEMPERATURE                            0x00
#define E120_SENS_VOLTAGE                                0x01
#define E120_SENS_CURRENT                                0x02
#define E120_SENS_FREQUENCY                              0x03
#define E120_SENS_RESISTANCE                             0x04   /* Eg: Cable resistance                                         */
#define E120_SENS_POWER                                  0x05
#define E120_SENS_MASS                                   0x06   /* Eg: Truss load Cell                                          */
#define E120_SENS_LENGTH                                 0x07
#define E120_SENS_AREA                                   0x08
#define E120_SENS_VOLUME                                 0x09   /* Eg: Smoke Fluid                                              */
#define E120_SENS_DENSITY                                0x0A
#define E120_SENS_VELOCITY                               0x0B
#define E120_SENS_ACCELERATION                           0x0C
#define E120_SENS_FORCE                                  0x0D
#define E120_SENS_ENERGY                                 0x0E
#define E120_SENS_PRESSURE                               0x0F
#define E120_SENS_TIME                                   0x10
#define E120_SENS_ANGLE                                  0x11
#define E120_SENS_POSITION_X                             0x12   /* E.g.: Lamp position on Truss                                 */
#define E120_SENS_POSITION_Y                             0x13
#define E120_SENS_POSITION_Z                             0x14
#define E120_SENS_ANGULAR_VELOCITY                       0x15   /* E.g.: Wind speed                                             */
#define E120_SENS_LUMINOUS_INTENSITY                     0x16
#define E120_SENS_LUMINOUS_FLUX                          0x17
#define E120_SENS_ILLUMINANCE                            0x18
#define E120_SENS_CHROMINANCE_RED                        0x19
#define E120_SENS_CHROMINANCE_GREEN                      0x1A
#define E120_SENS_CHROMINANCE_BLUE                       0x1B
#define E120_SENS_CONTACTS                               0x1C   /* E.g.: Switch inputs.                                         */
#define E120_SENS_MEMORY                                 0x1D   /* E.g.: ROM Size                                               */
#define E120_SENS_ITEMS                                  0x1E   /* E.g.: Scroller gel frames.                                   */
#define E120_SENS_HUMIDITY                               0x1F
#define E120_SENS_COUNTER_16BIT                          0x20
#define E120_SENS_OTHER                                  0x7F
/* Manufacturer-Specific Sensors                         0x80-
                                                         0xFF                                                                   */

/********************************************************/
/* Table A-13: Sensor Unit Defines                      */
/********************************************************/

#define E120_UNITS_NONE                                  0x00   /* CONTACTS                                                     */
#define E120_UNITS_CENTIGRADE                            0x01   /* TEMPERATURE	                                                */
#define E120_UNITS_VOLTS_DC                              0x02   /* VOLTAGE		                                                */
#define E120_UNITS_VOLTS_AC_PEAK                         0x03   /* VOLTAGE                                                      */
#define E120_UNITS_VOLTS_AC_RMS                          0x04   /* VOLTAGE                                                      */
#define E120_UNITS_AMPERE_DC                             0x05   /* CURRENT	                                                    */
#define E120_UNITS_AMPERE_AC_PEAK                        0x06   /* CURRENT	                                                    */
#define E120_UNITS_AMPERE_AC_RMS                         0x07   /* CURRENT                                                      */
#define E120_UNITS_HERTZ                                 0x08   /* FREQUENCY / ANG_VEL                                          */
#define E120_UNITS_OHM                                   0x09   /* RESISTANCE			                                        */
#define E120_UNITS_WATT                                  0x0A   /* POWER					                                    */
#define E120_UNITS_KILOGRAM                              0x0B   /* MASS                                                         */
#define E120_UNITS_METERS                                0x0C   /* LENGTH / POSITION		                                    */
#define E120_UNITS_METERS_SQUARED                        0x0D   /* AREA					                                        */
#define E120_UNITS_METERS_CUBED                          0x0E   /* VOLUME                                                       */
#define E120_UNITS_KILOGRAMMES_PER_METER_CUBED           0x0F   /* DENSITY                                                      */
#define E120_UNITS_METERS_PER_SECOND                     0x10   /* VELOCITY		                                                */
#define E120_UNITS_METERS_PER_SECOND_SQUARED             0x11   /* ACCELERATION	                                                */
#define E120_UNITS_NEWTON                                0x12   /* FORCE                                                        */
#define E120_UNITS_JOULE                                 0x13   /* ENERGY		                                                */
#define E120_UNITS_PASCAL                                0x14   /* PRESSURE		                                                */
#define E120_UNITS_SECOND                                0x15   /* TIME                                                         */
#define E120_UNITS_DEGREE                                0x16   /* ANGLE			                                            */
#define E120_UNITS_STERADIAN                             0x17   /* ANGLE			                                            */
#define E120_UNITS_CANDELA                               0x18   /* LUMINOUS_INTENSITY                                           */
#define E120_UNITS_LUMEN                                 0x19   /* LUMINOUS_FLUX		                                        */
#define E120_UNITS_LUX                                   0x1A   /* ILLUMINANCE		                                            */
#define E120_UNITS_IRE                                   0x1B   /* CHROMINANCE                                                  */
#define E120_UNITS_BYTE                                  0x1C   /* MEMORY	                                                    */
/* Manufacturer-Specific Units                           0x80-
 				                                         0xFF				                                                    */


/********************************************************/
/* Table A-14: Sensor Unit Prefix Defines               */
/********************************************************/

#define E120_PREFIX_NONE                                 0x00   /* Multiply by 1                                                */
#define E120_PREFIX_DECI                                 0x01   /* Multiply by 10-1	                                            */
#define E120_PREFIX_CENTI                                0x02   /* Multiply by 10-2	                                            */
#define E120_PREFIX_MILLI                                0x03   /* Multiply by 10-3	                                            */
#define E120_PREFIX_MICRO                                0x04   /* Multiply by 10-6	                                            */
#define E120_PREFIX_NANO                                 0x05   /* Multiply by 10-9	                                            */
#define E120_PREFIX_PICO                                 0x06   /* Multiply by 10-12	                                        */
#define E120_PREFIX_FEMPTO                               0x07   /* Multiply by 10-15	                                        */
#define E120_PREFIX_ATTO                                 0x08   /* Multiply by 10-18	                                        */
#define E120_PREFIX_ZEPTO                                0x09   /* Multiply by 10-21	                                        */
#define E120_PREFIX_YOCTO                                0x0A   /* Multiply by 10-24	                                        */
#define E120_PREFIX_DECA                                 0x11   /* Multiply by 10+1	                                            */
#define E120_PREFIX_HECTO                                0x12   /* Multiply by 10+2	                                            */
#define E120_PREFIX_KILO                                 0x13   /* Multiply by 10+3	                                            */
#define E120_PREFIX_MEGA                                 0x14   /* Multiply by 10+6	                                            */
#define E120_PREFIX_GIGA                                 0x15   /* Multiply by 10+9	                                            */
#define E120_PREFIX_TERRA                                0x16   /* Multiply by 10+12	                                        */
#define E120_PREFIX_PETA                                 0x17   /* Multiply by 10+15	                                        */
#define E120_PREFIX_EXA                                  0x18   /* Multiply by 10+18	                                        */
#define E120_PREFIX_ZETTA                                0x19   /* Multiply by 10+21	                                        */
#define E120_PREFIX_YOTTA                                0x1A   /* Multiply by 10+24	                                        */


/********************************************************/
/* Table A-15: Data Type Defines                        */
/********************************************************/

#define E120_DS_NOT_DEFINED                              0x00   /* Data type is not defined                                     */
#define E120_DS_BIT_FIELD                                0x01   /* Data is bit packed			                                */
#define E120_DS_ASCII                                    0x02   /* Data is a string					                            */
#define E120_DS_UNSIGNED_BYTE                            0x03   /* Data is an array of unsigned bytes                           */
#define E120_DS_SIGNED_BYTE                              0x04   /* Data is an array of signed bytes                             */
#define E120_DS_UNSIGNED_WORD                            0x05   /* Data is an array of unsigned 16-bit words	                */
#define E120_DS_SIGNED_WORD                              0x06   /* Data is an array of signed 16-bit words	                    */
#define E120_DS_UNSIGNED_DWORD                           0x07   /* Data is an array of unsigned 32-bit words	                */
#define E120_DS_SIGNED_DWORD                             0x08   /* Data is an array of signed 32-bit words						*/
/* Manufacturer-Specific Data Types		     		     0x80-                                                                  */
/*                                                       0xDF	                                                                */

/********************************************************/
/* Table A-16: Parameter Desc. Command Class Defines    */
/********************************************************/

#define E120_CC_GET                                      0x01   /* PID supports GET only                                        */
#define E120_CC_SET                                      0x02   /* PID supports SET only                                        */
#define E120_CC_GET_SET                                  0x03   /* PID supports GET & SET                                       */

/********************************************************/
/* Table A-17: Response NACK Reason Code Defines        */
/********************************************************/

#define E120_NR_UNKNOWN_PID                              0x0000 /* The responder cannot comply with request because the message
                                                                   is not implemented in responder.                             */
#define E120_NR_FORMAT_ERROR                             0x0001 /* The responder cannot interpret request as controller data
                                                                   was not formatted correctly.                                 */
#define E120_NR_HARDWARE_FAULT                           0x0002 /* The responder cannot comply due to an internal hardware fault*/
#define E120_NR_PROXY_REJECT                             0x0003 /* Proxy is not the RDM line master and cannot comply with message.*/
#define E120_NR_WRITE_PROTECT                            0x0004 /* SET Command normally allowed but being blocked currently.    */
#define E120_NR_UNSUPPORTED_COMMAND_CLASS                0x0005 /* Not valid for Command Class attempted. May be used where
                                                                   GET allowed but SET is not supported.                        */
#define E120_NR_DATA_OUT_OF_RANGE                        0x0006 /* Value for given Parameter out of allowable range or
                                                                   not supported.                                               */
#define E120_NR_BUFFER_FULL                              0x0007 /* Buffer or Queue space currently has no free space to store data. */
#define E120_NR_PACKET_SIZE_UNSUPPORTED                  0x0008 /* Incoming message exceeds buffer capacity.                    */
#define E120_NR_SUB_DEVICE_OUT_OF_RANGE                  0x0009 /* Sub-Device is out of range or unknown.                       */
#define E120_NR_PROXY_BUFFER_FULL                        0x000A /* Proxy buffer is full and can not store any more Queued       */
                                                                /* Message or Status Message responses.                         */

/********************************************************************************************************************************/
/********************************************************************************************************************************/
/* ANSI E1.37-1 DEFINES                                                                                                         */
/********************************************************************************************************************************/
/********************************************************************************************************************************/

/********************************************************/
/* E1.37-1 Table A-2: Preset Programmed Defines         */
/********************************************************/
#define E137_1_PRESET_NOT_PROGRAMMED                     0x00 /* Preset Scene not programmed.                                   */
#define E137_1_PRESET_PROGRAMMED                         0x01 /* Preset Scene programmed.                                       */
#define E137_1_PRESET_PROGRAMMED_READ_ONLY               0x02 /* Preset Scene read-only, factory programmed.                    */

/********************************************************/
/* E1.37-1 Table A-3: Merge Mode Defines                */
/********************************************************/
#define E137_1_MERGEMODE_DEFAULT                         0x00 /* Preset overrides DMX512 default behavior as defined in         */
                                                              /* E1.20 PRESET_PLAYBACK                                          */
#define E137_1_MERGEMODE_HTP                             0x01 /* Highest Takes Precedence on slot by slot basis                 */
#define E137_1_MERGEMODE_LTP                             0x02 /* Latest Takes Precedence from Preset or DMX512 on slot by slot  */
#define E137_1_MERGEMODE_DMX_ONLY                        0x03 /* DMX512 only, Preset ignored                                    */
#define E137_1_MERGEMODE_OTHER                           0xFF /* Other (undefined) merge mode
 
Last edited:
I had a nice, long exchange with Chris Staite over Twitter yesterday and was able to clear up some of my questions about this library. According to the author, it should be relatively easy to use this library with Serial1 on the Teensy 3.6 and 3.5's. I am not 100% confident in this yet because I have yet to wire up my DMX lights but once I do, I will share every line of code here.

Here's what I will be doing:

1. Teensy 3.6 reading 9 slider potentiometers at 16-bits
2. Convert those raw values to two 8 bit unsigned integers per channel in an array (using sqrt with round)
3. map into a different array of 16 bit values for extremely fine-grained display values.
4. scale all values based on the master fader values
5. send display values to OLED via software SPI
6. transmit the 8 bit values to a TI SN75LBC184D via Hardware Serial1 using the Teensy DMX library setChannels() command
7. loop
 
Last edited:
Thanks, Paul. I know that there is a bit-banging method out there. However the purpose of my thread here was to nail down the use of Teensy DMX library in particular. In the past day, I have received the code that I was looking for by the two creators of the library. Sharing here


TeensyDMXSend.ino:

Code:
#include <TeensyDmx.h>

#define DMX_REDE 2

byte DMXVal[] = {50};

TeensyDmx Dmx(Serial1, DMX_REDE);

void setup() {
  Dmx.setMode(TeensyDmx::DMX_OUT);
}

void loop() {
  Dmx.setChannels(0, DMXVal, 1);
  Dmx.loop();
}

TeensyDMXReceive.ino:

Code:
#include <TeensyDmx.h>

#define DMX_REDE 24
#define CHANNEL 0

struct RDMINIT rdmData {
  "TeensyDMX v0.1",
  "Teensyduino",
  1,  // Device ID
  "DMX Node",
  1,  // The DMX footprint
  0,  // The DMX startAddress - only used for RDM
  0,  // Additional commands length for RDM
  0   // Definition of additional commands
};

byte DMXVal[] = {50};

TeensyDmx Dmx(Serial1, &rdmData, DMX_REDE);

void setup() {
  Dmx.setMode(TeensyDmx::DMX_IN);
}

void loop() {
  Dmx.loop();
  if (Dmx.newFrame()) {
    Serial.println(Dmx.getBuffer()[CHANNEL]);
  }
  if (Dmx.rdmChanged()) {
    if (Dmx.isIdentify()) {
      Serial.println("Identify mode");
    }
    Serial.print("Device label: ");
    Serial.println(Dmx.getLabel());
    Serial.print("Start address: ");
    Serial.println(rdmData.startAddress, DEC);
  }
}

I finally put everything I have been working on together. I have yet to test it but it compiles OK.


Harry Pockonsole V1.0 Beta

Code:
/*********************************************************************
Harry Pockonsole V1
**********************************************************************
 
Custom Board Name: VoV1366v0.8
   Board Designer: Steve French @ Voltvision 
______________________________
DMX Connections (hardware UART @ Serial1) to TI SN75LBC184D: 
    DMX1RX on pin 0
    DMX1TX on pin 1
    DMX1DE and RE (DMX_REDE) on pin 24
_____________________________
OLED connections (software SPI):
    OLED MOSI0 on pin 11
    OLED SCK0 on pin 13
    OLED_DC on pin 32
    OLED_RST on pin 33
    OLED_CS on pin 34
______________________________
Wipers (10k mini pots @ 16bit):
    Wiper 1 is  analog(1)
    Wiper 2 is  analog(2)
    Wiper 3 is  analog(3)
    Wiper 4 is  analog(4)
    Wiper 5 is  analog(5)
    Wiper 6 is  analog(6)
    Wiper 7 is  analog(7)
    Wiper 8 is  analog(8)
    Wiper 9 is  analog(9)
______________________________    
Breadboard Area: 
  Digital Pins to breadboard area: D2,D3,D4,D5,D6,D7,D8,D9,D10,D12,D25,D25,D27,D28,D29,D30
  Analog Pins to breadboard area: D31/A12,D35/A16,D36/A17,D37/A18,D38/A19,D39/A20 
  3V3 Rail
  Ground Rail (future iterations will have a switch for analog isolation)
______________________________

*/

#include <U8g2lib.h>
#include <U8x8lib.h>
#include <Arduino.h>
#include <TeensyDmx.h>


#ifdef U8X8_HAVE_HW_SPI
#include <SPI.h>
#endif
#ifdef U8X8_HAVE_HW_I2C
#include <Wire.h>
#endif

//U8G2 CONSTRUCTOR (declares pinout for Teensy 3.6 with the U8g2lib.h OLED library)
U8G2_SSD1306_128X64_NONAME_F_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 34, /* dc=*/ 32, /* reset=*/ 33);  

#define DMX_REDE 24

byte dmxVal[9];
float scalerVal;

TeensyDmx Dmx(Serial1, DMX_REDE);

void setup() {
  analogReadRes(16);
  Dmx.setMode(TeensyDmx::DMX_OUT);  // Teensy DMX Declaration of Output
  analogReadAveraging(8);
  u8g2.begin();
  
  delay(100);
  u8g2.setFont(u8g2_font_helvB14_tf); // choose a font
  u8g2.drawStr(5,21,"Pockonsole");  // write something to the internal memory

  u8g2.setFont(u8g2_font_baby_tf); // choose a font
  u8g2.drawStr(103,9,"V 0.5");  // write something to the internal memory
  
  u8g2.setFont(u8g2_font_7x13_tf); // choose a font
  u8g2.drawStr(8,36,"by Harry Pray IV");  // write something to the internal memory
  
  u8g2.sendBuffer();          // transfer internal memory to the display
  delay(1000);
  u8g2.clearBuffer();
}

void loop() {
  scalerVal = (floatmap(analogRead(9), 1, 65536, 65025, 1) / 65025);                    // Master Fader_______________________________
  if (scalerVal <= .01) {                  // eliminate small values to avoid flickering (I may eventually do smoothing instead)
      scalerVal = 0;
    };
  
  
  for (int i = 0; i < 8; ++i) {
    dmxVal[i] = round(floatmap(analogRead(i+1), 1, 65536, 255, 1) * scalerVal);
    if (dmxVal[i] < 2) {                  // eliminate small values to avoid flickering (I may eventually do smoothing instead)
      dmxVal[i] = 0;
    };
    Dmx.setDmxChannel((i+1), dmxVal[i]);
  }
  u8g2.setFont(u8g2_font_5x8_mn);  // choose a suitable font
  u8g2.setCursor(0, 10);
  u8g2.print(dmxVal[0]);
  u8g2.setCursor(22, 10);
  u8g2.print(dmxVal[1]);
  u8g2.setCursor(44, 10);
  u8g2.print(dmxVal[2]);
  u8g2.setCursor(66,10);
  u8g2.print(dmxVal[3]);

  u8g2.setFont(u8g2_font_profont15_tf);  // choose a suitable font
  u8g2.drawStr(2,24,"1");
  u8g2.drawStr(26,24,"2");
  u8g2.drawStr(50,24,"3");
  u8g2.drawStr(72,24,"4");
  
  u8g2.setFont(u8g2_font_5x8_mn);  // choose a suitable font
  u8g2.setCursor(0, 47);
  u8g2.print(dmxVal[4]);
  u8g2.setCursor(22, 47);
  u8g2.print(dmxVal[5]);
  u8g2.setCursor(44, 47);
  u8g2.print(dmxVal[6]);
  u8g2.setCursor(66, 47);
  u8g2.print(dmxVal[7]);
 
  u8g2.setCursor(93, 30);
  u8g2.print(scalerVal*100);
      
  u8g2.setFont(u8g2_font_profont15_tf);  // choose a suitable font
  u8g2.drawStr(2,60,"5");
  u8g2.drawStr(26,60,"6");
  u8g2.drawStr(50,60,"7");
  u8g2.drawStr(72,60,"8");
  
  u8g2.setFont(u8g2_font_profont15_tf);  // choose a suitable font
  u8g2.drawStr(94,41,"All");
  u8g2.setFont(u8g2_font_5x8_mn);  // choose a suitable font

  u8g2.drawLine(17, 0, 17, 64);
  u8g2.drawLine(39, 0, 39, 64);
  u8g2.drawLine(61, 0, 61, 64);
  u8g2.drawLine(83, 0, 83, 64);
  u8g2.drawLine(0, 30, 83, 30);

  u8g2.drawFrame(87,21,94,24);

  u8g2.sendBuffer();          // transfer internal memory to the display
  delay(100);  
  u8g2.clearBuffer();
}

float floatmap(float x, float in_min, float in_max, float out_min, float out_max)  {
  return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}
 
Last edited:
That code on Instructables uses the FIFO-based serial port, not big banging.

But sounds like you've got this library code working, so all looks good. :)
 
Thanks. I stand corrected.

I also picked this library because it includes RDM, which is becoming more and more prevalent in the film industry. I can't wait to someday set all of the channel numbers from the ground instead of taking a lift up to each head after installing them.
 
I got ALL of it working. Tomorrow, I will post an example of Version 1.0 of this board and software. I can't believe how easy this was. The TeensyDMX library had a bug that was causing me headaches but the author has ALREADY fixed the bug and it is working flawlessly now.

Here's some solid, working code that enables the absolute most basic functionality of my board (sliders 1-8 controlling channels 1-8 then slider 9 as a master scaler).

Code:
/*********************************************************************
Dimmer Board (with Master Fader)
**********************************************************************/

#include <Arduino.h>
#include <TeensyDmx.h>

#define DMX_REDE 24

TeensyDmx Dmx(Serial1, DMX_REDE);

byte dmxVal[9];
float scalerVal;

void setup() {
  analogReadRes(8);
  Dmx.setMode(TeensyDmx::DMX_OUT);  // Teensy DMX Declaration of Output
}

void loop() {
  scalerVal = (floatmap(analogRead(9), 1, 1024, 1024, 1) / 1024);  // Master Fader_______________________________
  
  for (int i = 0; i < 8; ++i) {   // Channel Fader 1-8__________________________
    dmxVal[i] = round(floatmap(analogRead(i+1), 1, 1024, 255, 1) * scalerVal);
    Dmx.setDmxChannel((i+1), dmxVal[i]);
  }
}

float floatmap(float x, float in_min, float in_max, float out_min, float out_max)  { // function for mapping floats
  return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}
 
Next bit of coding I am doing is going to enable some sort of custom channel mapping. The funniest thing about that functionality is that there aren't any buttons on my board yet. We broke out all of the pins (except the underside of the board) so I will be soldering in a keypad in order to make this board more versatile.

On another revision of this board, I intend to add some nice buttons in that have RGB LED's behind them to help with the UI. I could probably just add a touchscreen but I REALLY love these buttons. I don't want to waste all of the pins on the Teensy, though, so I might get an i2C LED controller so this board can remain versatile as a proto solution (part of its intention).
 
since u have 6 uarts you could also use a 4d systems display, a fraction of the code compared to lcd libraries, 2 wires as it connects to uart at max 600,000 baud, which teensy is very capable of doing easily...
 
here is a sample testrun ive done (this was tested @200,000baud)
the code needed is very minimal in teensy/arduino, as the music,video,code is in the lcd's mcu and lcd's sdcard, using the lcd's own workshop IDE, you can drag drop objects as you please without hastle.
https://m.youtube.com/watch?v=QX34t0PSPjA

commands to lcd from arduino/teensy are only 1 line, making it cleaner and using much less resources as the commands trigger objects that are on the lcd, including Strings.

and the canbus data:

https://m.youtube.com/watch?v=fnQL2S9BPZI

im pretty sure id go nuts if i did this with a regular lcd lol
 
Last edited:
I actually miswrote. I have a decent solution to the UI but the UX is where I need to work on this. I need to add a keypad for sure (or at least a few buttons and a rotary encoder/another pot) but I think I am going to be OK with just this small OLED display for user feedback (UI). I had originally wanted one smaller OLED screen above each fader but the EE who designed the board convinced me that that was kind of asking for trouble. I was planning to use i2c for them but he also convinced me to use software SPI which has actually been fine. Not too bad. The OLED was the easiest part, I think.

I certainly will keep those panels in mind on the next iteration of this project (are they touchscreen??) but it definitely is not going to work on the boards that I am building right now.


FullSizeRender 4.jpg
As you can see, there is very little room for a screen because it would get in the way of the proto area.

FullSizeRender 3.jpg
This board will reside inside the lid of a Pelican case



(I found ports/connectors that will allow the setup to remain IP68 even while still being powered) and will be hard coded to control two City Theatrical B4 dimmers that will be controlling 6 color LED light ribbon RGBT, RGBD, and RGBA (Red, Green, Blue, Tungsten, Amber, and Daylight) when there is no proper dimmer board available to send data into the board. I also plan to get a DMXCat from City Theatrical (a wireless DMX controller) but this board will be good because I can literally just permanently install it in my LED ballast case and hard-code many of the options to work for those ballasts alone.


If City Theatrical had built knobs onto those B4 dimmers, this project would quite literally not exist.

PS. I have 9 more copies of this board that I intend to use for prototyping other projects and building custom controllers for specific needs....which is why I had a proto area added to it.
 
Last edited:
here i have uLCD-43PT (4.3") and uLCD-70DT (7") in my car
View attachment 9362

it will control hvac, digital gauges, teensy settings, and digital push to start

yeah what you see is the IDE which is used to program the teensy haha
 
Last edited:
the screen has its own mcu built on 4dgl code, if you know it you may gain access to the onboard i2c(x3),spi(x3),uart(x3) and gpios as well. the visigenie environment only has gpio access unlesss you get the pro, visigenie is by far the easiest for any non coder to start working on arduino+lcd setup
 
Interesting. The fact that it is closed source and requires you to learn their proprietary stuff makes it a non-starter in my work. I want to use (and further the state of) the open source world as much as I can and once I start using closed stuff like that (no matter how cool it is), I go against my philosophy about IP.

Ps. that round display looks pretty slick. I might have a few uses for something like that....especially an array of them.
 
well it is open source, the genie environment can be converted to visi environment which is pure code, but cant be cknverted back to genie, the easiest way to setup the screen is using genie environment, and to implement custom code get the pro version, which allows you to put in "magic code" which is nothing more than pure 4dgl code as if you were in the coding environment, which is a benefit of both worlds in one sketch :) the code is all available
 
Status
Not open for further replies.
Back
Top