Postby xldaedalus » Sun Jul 24, 2022 4:56 pm
Here is the RDMDeviceTest.ino I've written
/*!
@file RDMDeviceTest.ino
@author Claude Heintz
@license BSD (see LXSAMD21DMX LICENSE)
@copyright 2017-2021 by Claude Heintz
Example showing LXSAMD21DMX RDM support for devices.
Control brightness of LED on GPIO14 with DMX address 1 (settable via RDM)
@section HISTORY
v1.00 - First release
*/
/**************************************************************************/
#include <LXSAMD21DMX.h>
#include <rdm/rdm_utility.h>
#include <rdm/UID.h>
#include <rdm/TOD.h>
int got_dmx = 0;
int got_rdm = 0;
uint8_t discovery_enabled = 1;
uint16_t start_address = 1;
uint16_t input_value = 0;
uint8_t device_label[33];
#define DEFAULT_DEVICE_LABEL "RDM dev test v1.0"
#define MFG_LABEL "LXDMX"
#define MODEL_DESCRIPTION "RDMDeviceTest"
#define DIRECTION_PIN 14 //A0
#define DMX_DE_PIN 15 //A1 disabled on breadboard
#define LED_PIN 25 //PIN_LED_RXL Yellow
#define BUILTIN_LED 13
#define debug_pin 18 //PIN_A4
#define TIMO_PIN 16 //A2
#define Timo_ON 1 // Timo ON
#define Timo_OFF 0 // Timo OFF
#define TIMO_CS 17 //A3
#define SERIAL_DEBUG // <-----------------------------------DEBUG----
//#define DEBUG_LOOP // <----------------------------------- forces program to test pin states only DEBUG PIN-S---
//#define TEST_PIN 30 // <-----------------------------------DEBUG PINS----
/*. HARDWARE INFO
Sparkfun SAMD21 Dev Board configured as Arduino Zero on an R3 shield layout
USB: SerialUSB.xxx <--- default for Serial Monitor, plotter, programming
Hardware Serial (TX/D1 and RX/D0): Serial1.xxx
Hardware Serial (30/TX and 31/RX): Serial.xxx <--- I use this for RS485. I use A)
*/
void setup() {
pinMode(TIMO_PIN, OUTPUT); //Timo is a wireless DMX special function SOC
digitalWrite(TIMO_PIN, Timo_OFF); //If Timo is ON, DMX is NOT handled by Serial.xxx, data received transferred via SPI
pinMode(debug_pin, OUTPUT); // my pins connected to oscope for timing and function testing
digitalWrite(debug_pin, LOW);
pinMode(DIRECTION_PIN, OUTPUT);
digitalWrite(DIRECTION_PIN, LOW); //start in receive mode
pinMode(TIMO_CS, OUTPUT); //talk to Timo SOC
digitalWrite(TIMO_CS, HIGH); //defualt not selected
#ifdef SERIAL_DEBUG // <--------------Use only if using serial monitor---------------------DEBUG----
SerialUSB.begin(115200);
while (!SerialUSB)
{
; // wait for SerialUSB port to connect. Needed for native USB port only
}
SerialUSB.println("SAMD21 RDMDeviceTest"); // test that the port has started properly
#endif
pinMode(BUILTIN_LED, OUTPUT);
pinMode(DIRECTION_PIN, OUTPUT);
digitalWrite(DIRECTION_PIN, LOW);
pinMode(LED_PIN, OUTPUT);
//diagnostic pins
// pinMode(12, OUTPUT);
#ifdef DEBUG_LOOP // <-----------------------------------DEBUG----
// pinMode(TEST_PIN, OUTPUT);
// digitalWrite(TEST_PIN, HIGH);
}
#else
strcpy((char*)device_label, DEFAULT_DEVICE_LABEL);
SAMD21DMX.setDataReceivedCallback(&gotDMXCallback);
SAMD21DMX.setRDMReceivedCallback(&gotRDMCallback);
LXSAMD21DMX::THIS_DEVICE_ID.setBytes(0x6C, 0x78, 0x0F, 0x0A, 0x0C, 0x0E); //change device ID from default
SAMD21DMX.startRDM(DIRECTION_PIN, DMX_TASK_RECEIVE);
}
#endif
//##############################################################################################
#ifdef DEBUG_LOOP // <-----------for testing pins only------------------------DEBUG----
void loop() { //
digitalWrite(LED_PIN, !digitalRead(LED_PIN));
digitalWrite(DIRECTION_PIN, !digitalRead(DIRECTION_PIN));
// digitalWrite(BUILTIN_LED, !digitalRead(BUILTIN_LED));
digitalWrite(PIN_A4, !digitalRead(PIN_A4));
// digitalWrite(TIMO_PIN, !digitalRead(TIMO_PIN));
// digitalWrite(LED_PIN, Timo_ON);
// digitalWrite(TIMO_PIN, Timo_ON);
delay(100);
} // end Test Loop
//################################################################################################
#else
// ***************** input callback function *************
void gotDMXCallback(int slots) {
got_dmx = slots;
}
void gotRDMCallback(int len) {
// rdm start code and checksum are validated before this is called
got_rdm = len;
}
/************************************************************************
The main loop checks to see if dmx input is available (got_dmx>0)
And then reads the level of dimmer 1 to set PWM level of LED connected to pin 14
*************************************************************************/
void loop() {
// SerialUSB.print(PIN_DMX_RX);
if ( got_dmx ) {
input_value = SAMD21DMX.getSlot(start_address);
/*
*#ifdef SERIAL_DEBUG // <-----------------------------------DEBUG----`
SerialUSB.print("Chval ");
SerialUSB.println(input_value);
#endif
*/
//gamma correct
input_value = (input_value * input_value ) / 255;
//ESP8266 PWM is 10bit 0-1024
analogWrite(LED_PIN,2*input_value);
got_dmx = 0; //reset
} else if ( got_rdm ) {
uint8_t* rdmdata = SAMD21DMX.receivedRDMData();
uint8_t cmdclass = rdmdata[RDM_IDX_CMD_CLASS];
uint16_t pid = (rdmdata[RDM_IDX_PID_MSB] << 8 ) | rdmdata[RDM_IDX_PID_LSB];
/*
#ifdef SERIAL_DEBUG // <-------------check CMD received is correct----------------------DEBUG----
SerialUSB.println("Discovery ");
SerialUSB.print("cmdclass ");
SerialUSB.println(cmdclass);
SerialUSB.print("pid ");
SerialUSB.println(pid);
#endif
*/
if ( cmdclass == RDM_DISCOVERY_COMMAND ) {
if ( pid == RDM_DISC_UNIQUE_BRANCH ) {
if ( discovery_enabled ) {
uint64_t tv = SAMD21DMX.THIS_DEVICE_ID.getValue();
UID u;
u.setBytes(&rdmdata[24]); //lower
uint64_t uv = u.getValue();
if ( tv >= uv ) {
u.setBytes(&rdmdata[30]); //upper
uv = u.getValue();
if ( tv <= uv ) {
SAMD21DMX.sendRDMDiscoverBranchResponse();
}
}
}
} else { // mute RDM_DISCOVERY_COMMAND PIDs
UID destination;
destination.setBytes(&rdmdata[RDM_IDX_DESTINATION_UID]);
#ifdef SERIAL_DEBUG // <-----------------------------------DEBUG----`
SerialUSB.print("destination ");
SerialUSB.println(destination);
#endif
if ( pid == RDM_DISC_MUTE ) {
if ( destination == SAMD21DMX.THIS_DEVICE_ID ) {
discovery_enabled = 0; // <----- THIS is where the trouble starts.
// send ACK
UID source;
source.setBytes(&rdmdata[RDM_IDX_SOURCE_UID]);
SAMD21DMX.sendMuteAckRDMResponse(RDM_DISC_COMMAND_RESPONSE, source, RDM_DISC_MUTE);
}
} else if ( pid == RDM_DISC_UNMUTE ) {
if ( destination == BROADCAST_ALL_DEVICES_ID ) {
// just un-mute
discovery_enabled = 1;
} else if ( destination == SAMD21DMX.THIS_DEVICE_ID ) {
discovery_enabled = 1;
// send ACK
UID source;
source.setBytes(&rdmdata[RDM_IDX_SOURCE_UID]);
SAMD21DMX.sendMuteAckRDMResponse(RDM_DISC_COMMAND_RESPONSE, source, RDM_DISC_UNMUTE);
}
}
}
} else if ( cmdclass == RDM_GET_COMMAND ) {
#ifdef SERIAL_DEBUG // <-----------------------------------DEBUG----
SerialUSB.println("GET CMD");
#endif
UID destination;
destination.setBytes(&rdmdata[RDM_IDX_DESTINATION_UID]);
if ( destination == SAMD21DMX.THIS_DEVICE_ID ) {
UID source;
source.setBytes(&rdmdata[RDM_IDX_SOURCE_UID]);
if ( pid == RDM_DEVICE_START_ADDR ) {
uint8_t sa[2];
sa[0] = start_address >> 8;
sa[1] = start_address & 0xff;
SAMD21DMX.sendRDMGetResponse(source, pid, sa, 2);
} else if ( pid == RDM_DEVICE_MFG_LABEL ) {
const char * label = MFG_LABEL;
SAMD21DMX.sendRDMGetResponse(source, pid, (uint8_t*)label, 5);
} else if ( pid == RDM_DEVICE_MODEL_DESC ) {
const char * label = MODEL_DESCRIPTION;
SAMD21DMX.sendRDMGetResponse(source, pid, (uint8_t*)label, 13);
} else if ( pid == RDM_DEVICE_DEV_LABEL ) {
SAMD21DMX.sendRDMGetResponse(source, pid, device_label, strlen((const char*)device_label));
}
}
} else if ( cmdclass == RDM_SET_COMMAND ) {
#ifdef SERIAL_DEBUG // <-----------------------------------DEBUG----
SerialUSB.println("SET CMD");
#endif
UID destination;
destination.setBytes(&rdmdata[RDM_IDX_DESTINATION_UID]);
if ( destination == SAMD21DMX.THIS_DEVICE_ID ) {
UID source;
source.setBytes(&rdmdata[RDM_IDX_SOURCE_UID]);
if ( pid == RDM_DEVICE_START_ADDR ) {
uint16_t scratch = (rdmdata[24] << 8) + rdmdata[25];
if (( scratch > 0 ) && ( scratch < 513 )) {
start_address = scratch;
}
SAMD21DMX.sendAckRDMResponse(RDM_SET_COMMAND_RESPONSE, source, pid);
} else if ( pid == RDM_DEVICE_DEV_LABEL ) {
uint8_t llen = 0;
if ( rdmdata[2] > 24 ) { //label not empty string
llen = rdmdata[2] - 24;
if ( llen > 32 ) { //limit to max 32 characters
llen = 32;
}
}
for ( uint8_t j=0; j<33; j++) { //copy label, zero the rest of the array
if ( j < llen ) {
device_label[j] = rdmdata[24+j];
} else {
device_label[j] = 0;
}
} // <-for
SAMD21DMX.sendAckRDMResponse(RDM_SET_COMMAND_RESPONSE, source, pid);
} // <-pid RDM_DEVICE_DEV_LABEL
}
}
got_rdm = 0;
} //gotRDM
}
#endif
//-------------------------------------- END of RDMDeviceTest.ino -------------------------------------------------------------
//--------------------- Changes to MAIN code needed --------------------------------------------------------------------------
It was necessary to make changes to the Tx/Rx and SERCOM IRQ handler in LXSAMD21DMX.h
( line 530 to end)
#define use_optional_sercom_macros 6 // <-- created my own macro "Serial.xxx" Use Port 0 aka calls Serial.xxx go to Port 0
// #define use_optional_sercom_macros 1 // Use Port 1 aka calls Serial1.xxx go to Port 0
#ifdef use_optional_sercom_macros
#if ( use_optional_sercom_macros == 1 )
//********************** optional sercom macros 1 **********************
// --might be used for Arduino Zero sercom2 pins 3 and 4
#define PIN_DMX_RX (3ul)
#define PIN_DMX_TX (4ul)
#define PAD_DMX_RX SERCOM_RX_PAD_1
#define PAD_DMX_TX UART_TX_PAD_0
// Set to PIO_SERCOM or PIO_SERCOM_ALT
#define MUX_DMX_RX PIO_SERCOM_ALT
#define MUX_DMX_TX PIO_SERCOM_ALT
// SERCOMn is pointer to memory address where SERCOM registers are located.
#define DMX_SERCOM SERCOM2
// sercomN is C++ wrapper for SERCOMn (passed to UART constructor)
#define DMX_sercom sercom2
// sercom handler function
#define DMX_SERCOM_HANDLER_FUNC SERCOM2_Handler
#warning Using use_optional_sercom_macros = 1
#elif ( use_optional_sercom_macros == 2 )
//********************** optional sercom macros 2 **********************
// --might be used for Adafruit M0 Feather sercom1 pins 10 and 11
#define PIN_DMX_RX (11ul)
#define PIN_DMX_TX (10ul)
#define PAD_DMX_RX SERCOM_RX_PAD_0
#define PAD_DMX_TX UART_TX_PAD_2
// Set to PIO_SERCOM or PIO_SERCOM_ALT
#define MUX_DMX_RX PIO_SERCOM
#define MUX_DMX_TX PIO_SERCOM
// SERCOMn is pointer to memory address where SERCOM registers are located.
#define DMX_SERCOM SERCOM1
// sercomN is C++ wrapper for SERCOMn (passed to UART constructor)
#define DMX_sercom sercom1
// sercom handler function
#define DMX_SERCOM_HANDLER_FUNC SERCOM1_Handler
#warning Using use_optional_sercom_macros = 2
#elif ( use_optional_sercom_macros == 3 )
//********************** optional sercom macros 3 **********************
// --might be used for Feather M0 pins D0 and D1
// --added by shiftingtech 7-21-19
#define PIN_DMX_RX (0ul)
#define PIN_DMX_TX (1ul)
#define PAD_DMX_RX SERCOM_RX_PAD_3
#define PAD_DMX_TX UART_TX_PAD_2
// Set to PIO_SERCOM or PIO_SERCOM_ALT
#define MUX_DMX_RX PIO_SERCOM_ALT
#define MUX_DMX_TX PIO_SERCOM_ALT
// SERCOMn is pointer to memory address where SERCOM registers are located.
#define DMX_SERCOM SERCOM2
// sercomN is C++ wrapper for SERCOMn (passed to UART constructor)
#define DMX_sercom sercom2
// sercom handler function
#define DMX_SERCOM_HANDLER_FUNC SERCOM2_Handler
#warning Using use_optional_sercom_macros = 3
#elif ( use_optional_sercom_macros == 4 )
//********************** optional sercom macros 4 **********************
// --replaces Serial1 on MKR1000
// --requires commenting out lines 178 to 186 in
// Arduino15/packages/arduino/hardware/samd/1.8.4/variants/mkr1000/variant.cpp
// otherwise Serial1 will conflict on Sercom5 and this won't compile
#define PIN_DMX_RX (13ul)
#define PIN_DMX_TX (14ul)
#define PAD_DMX_RX SERCOM_RX_PAD_3
#define PAD_DMX_TX UART_TX_PAD_2
// Set to PIO_SERCOM or PIO_SERCOM_ALT
#define MUX_DMX_RX PIO_SERCOM_ALT
#define MUX_DMX_TX PIO_SERCOM_ALT
// SERCOMn is pointer to memory address where SERCOM registers are located.
#define DMX_SERCOM SERCOM5
// sercomN is C++ wrapper for SERCOMn (passed to UART constructor)
#define DMX_sercom sercom5
// sercom handler function
#define DMX_SERCOM_HANDLER_FUNC SERCOM5_Handler
#warning Using use_optional_sercom_macros = 4
#elif ( use_optional_sercom_macros == 6 )
//********************** optional sercom macros 6 ### created by Lee Paker ### **********************
// Arduino Zero Port 0 aka Serial.xxx calls go to this port Port 1 aka Serial1.xxx calls go to pins D0,D1
// SerialUSB.xxx calls go to the USB port and the "Serial Monitor function of the Arduino
#define PIN_DMX_RX (31ul)
#define PIN_DMX_TX (30ul)
#define PAD_DMX_RX SERCOM_RX_PAD_3. //per Sparkfun SAMD21 Dev Breakkout
#define PAD_DMX_TX UART_TX_PAD_2. //per Sparkfun SAMD21 Dev Breakkout
// Set to PIO_SERCOM or PIO_SERCOM_ALT
#define MUX_DMX_RX PIO_SERCOM_ALT
#define MUX_DMX_TX PIO_SERCOM_ALT
// SERCOMn is pointer to memory address where SERCOM registers are located.
#define DMX_SERCOM SERCOM5
// sercomN is C++ wrapper for SERCOMn (passed to UART constructor)
#define DMX_sercom sercom5
// sercom handler function
#define DMX_SERCOM_HANDLER_FUNC SERCOM5_Handler
#warning Using use_optional_sercom_macros = 6
#elif (use_optional_sercom_macros == 5)
//********************** optional sercom macros 5 **********************
// --might be used for SEEED XIAO M0 sercom2 pins 3 and 4
#define PIN_DMX_RX (3ul)
#define PIN_DMX_TX (4ul)
#define PAD_DMX_RX SERCOM_RX_PAD_3
#define PAD_DMX_TX UART_TX_PAD_0
// Set to PIO_SERCOM or PIO_SERCOM_ALT
#define MUX_DMX_RX PIO_SERCOM_ALT
#define MUX_DMX_TX PIO_SERCOM_ALT
// SERCOMn is pointer to memory address where SERCOM registers are located.
#define DMX_SERCOM SERCOM2
// sercomN is C++ wrapper for SERCOMn (passed to UART constructor)
#define DMX_sercom sercom2
// sercom handler function
#define DMX_SERCOM_HANDLER_FUNC SERCOM2_Handler
#warning Using use_optional_sercom_macros = 5
#endif
#else
//********************** default sercom macros **********************
#define PIN_DMX_RX (5ul)
#define PIN_DMX_TX (4ul)
#define PAD_DMX_RX SERCOM_RX_PAD_3
#define PAD_DMX_TX UART_TX_PAD_2
// Set to PIO_SERCOM or PIO_SERCOM_ALT
#define MUX_DMX_RX PIO_SERCOM_ALT
#define MUX_DMX_TX PIO_SERCOM_ALT
// SERCOMn is pointer to memory address where SERCOM registers are located.
#define DMX_SERCOM SERCOM4
// sercomN is C++ wrapper for SERCOMn (passed to UART constructor)
#define DMX_sercom sercom4
// sercom handler function
#define DMX_SERCOM_HANDLER_FUNC SERCOM4_Handler
#endif
#endif // ifndef LXSAM21_DMX_H