Skip to content

Commit

Permalink
Merge pull request #7 from DMXControl/master
Browse files Browse the repository at this point in the history
Added support for sensors
  • Loading branch information
mathertel authored Jun 29, 2017
2 parents abc2fd1 + 9d63952 commit 091abda
Show file tree
Hide file tree
Showing 4 changed files with 118 additions and 5 deletions.
3 changes: 2 additions & 1 deletion examples/RDMSerialRecv/RDMSerialRecv.ino
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,8 @@ struct RDMINIT rdmInit = {
1, // Device Model ID
"Arduino RDM Device", // Device Model Label
3, // footprint
(sizeof(my_pids)/sizeof(uint16_t)), my_pids
(sizeof(my_pids)/sizeof(uint16_t)), my_pids,
0, NULL
};


Expand Down
1 change: 1 addition & 0 deletions keywords.txt
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ isIdentifyMode KEYWORD2
getStartAddress KEYWORD2
getFootprint KEYWORD2
attachRDMCallback KEYWORD2
attachSensorCallback KEYWORD2
tick KEYWORD2
term KEYWORD2
deviceLabel KEYWORD2
Expand Down
93 changes: 90 additions & 3 deletions src/DMXSerial2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
// 12.04.2015 change of using datatype boolean to bool8.
// 15.06.2015 On DMX lines sometimes a BREAK condition occures inbetween RDM packets from the controller
// and the device response. Ignore that when no data has arrived.
// 25.05.2017 Stefan Krupop: Add support for sensors
// - - - - -

#include "Arduino.h"
Expand Down Expand Up @@ -344,14 +345,15 @@ int random255();

// Initialize or reinitialize the DMX RDM mode.
// The other values are stored for later use with the specific commands.
void DMXSerialClass2::init(struct RDMINIT *initData, RDMCallbackFunction func, uint8_t modePin, uint8_t modeIn, uint8_t modeOut)
void DMXSerialClass2::init(struct RDMINIT *initData, RDMCallbackFunction func, RDMGetSensorValue sensorFunc, uint8_t modePin, uint8_t modeIn, uint8_t modeOut)
{
// This structure is defined for mapping the values in the EEPROM
struct EEPROMVALUES eeprom;

// save the given initData for later use.
_initData = initData;
_rdmFunc = func;
_sensorFunc = sensorFunc;

_dmxModePin = modePin;
_dmxModeIn = modeIn;
Expand Down Expand Up @@ -452,6 +454,11 @@ void DMXSerialClass2::attachRDMCallback(RDMCallbackFunction newFunction)
_rdmFunc = newFunction;
} // attachRDMCallback

// Register a self implemented function to get sensor values
void DMXSerialClass2::attachSensorCallback(RDMGetSensorValue newFunction)
{
_sensorFunc = newFunction;
} // attachSensorCallback

// some functions to hide the internal variables from beeing changed

Expand Down Expand Up @@ -663,7 +670,7 @@ void DMXSerialClass2::_processRDMMessage(byte CmdClass, uint16_t Parameter, bool
devInfo->personalityCount = 1;
devInfo->startAddress = SWAPINT(_startAddress);
devInfo->subDeviceCount = 0;
devInfo->sensorCount = 0;
devInfo->sensorCount = _initData->sensorsLength;

_rdm.packet.DataLength = sizeof(DEVICEINFO);
handled = true;
Expand Down Expand Up @@ -793,8 +800,15 @@ void DMXSerialClass2::_processRDMMessage(byte CmdClass, uint16_t Parameter, bool
WRITEINT(_rdm.packet.Data , E120_MANUFACTURER_LABEL);
WRITEINT(_rdm.packet.Data+ 2, E120_DEVICE_MODEL_DESCRIPTION);
WRITEINT(_rdm.packet.Data+ 4, E120_DEVICE_LABEL);
uint8_t offset = 6;
if (_initData->sensorsLength > 0) {
_rdm.packet.DataLength += 2 * 2;
offset += 2 * 2;
WRITEINT(_rdm.packet.Data+ 6, E120_SENSOR_DEFINITION);
WRITEINT(_rdm.packet.Data+ 8, E120_SENSOR_VALUE);
}
for (int n = 0; n < _initData->additionalCommandsLength; n++) {
WRITEINT(_rdm.packet.Data+6+n+n, _initData->additionalCommands[n]);
WRITEINT(_rdm.packet.Data+offset+n+n, _initData->additionalCommands[n]);
}
handled = true;
}
Expand All @@ -805,6 +819,79 @@ void DMXSerialClass2::_processRDMMessage(byte CmdClass, uint16_t Parameter, bool

// ADD: PARAMETER_DESCRIPTION

} else if (Parameter == SWAPINT(E120_SENSOR_DEFINITION) && _initData->sensorsLength > 0) { // 0x0200
if (CmdClass == E120_GET_COMMAND) {
if (_rdm.packet.DataLength != 1) {
// Unexpected data
nackReason = E120_NR_FORMAT_ERROR;
} else if (_rdm.packet.SubDev != 0) {
// No sub-devices supported
nackReason = E120_NR_SUB_DEVICE_OUT_OF_RANGE;
} else {
uint8_t sensorNr = _rdm.packet.Data[0];
if (sensorNr >= _initData->sensorsLength) {
// Out of range sensor
nackReason = E120_NR_DATA_OUT_OF_RANGE;
} else {
_rdm.packet.DataLength = 13 + strlen(_initData->sensors[sensorNr].description);
_rdm.packet.Data[0] = sensorNr;
_rdm.packet.Data[1] = _initData->sensors[sensorNr].type;
_rdm.packet.Data[2] = _initData->sensors[sensorNr].unit;
_rdm.packet.Data[3] = _initData->sensors[sensorNr].prefix;
WRITEINT(_rdm.packet.Data + 4, _initData->sensors[sensorNr].rangeMin);
WRITEINT(_rdm.packet.Data + 6, _initData->sensors[sensorNr].rangeMax);
WRITEINT(_rdm.packet.Data + 8, _initData->sensors[sensorNr].normalMin);
WRITEINT(_rdm.packet.Data + 10, _initData->sensors[sensorNr].normalMax);
_rdm.packet.Data[12] = (_initData->sensors[sensorNr].lowHighSupported ? 2 : 0) | (_initData->sensors[sensorNr].recordedSupported ? 1 : 0);
memcpy(_rdm.packet.Data + 13, _initData->sensors[sensorNr].description, _rdm.packet.DataLength - 13);
handled = true;
}
}
} else if (CmdClass == E120_SET_COMMAND) {
// Unexpected set
nackReason = E120_NR_UNSUPPORTED_COMMAND_CLASS;
}
} else if (Parameter == SWAPINT(E120_SENSOR_VALUE) && _initData->sensorsLength > 0) { // 0x0201
if (CmdClass == E120_GET_COMMAND) {
if (_rdm.packet.DataLength != 1) {
// Unexpected data
nackReason = E120_NR_FORMAT_ERROR;
} else if (_rdm.packet.SubDev != 0) {
// No sub-devices supported
nackReason = E120_NR_SUB_DEVICE_OUT_OF_RANGE;
} else {
uint8_t sensorNr = _rdm.packet.Data[0];
if (sensorNr >= _initData->sensorsLength) {
// Out of range sensor
nackReason = E120_NR_DATA_OUT_OF_RANGE;
} else {
int16_t sensorValue = 0;
int16_t lowestValue = 0;
int16_t highestValue = 0;
int16_t recordedValue = 0;
bool8 res = false;
if (_sensorFunc) {
res = _sensorFunc(sensorNr, &sensorValue, &lowestValue, &highestValue, &recordedValue);
}
if (res) {
_rdm.packet.DataLength = 9;
_rdm.packet.Data[0] = sensorNr;
WRITEINT(_rdm.packet.Data + 1, sensorValue);
WRITEINT(_rdm.packet.Data + 3, lowestValue);
WRITEINT(_rdm.packet.Data + 5, highestValue);
WRITEINT(_rdm.packet.Data + 7, recordedValue);
handled = true;
} else {
nackReason = E120_NR_HARDWARE_FAULT;
}
}
}
} else if (CmdClass == E120_SET_COMMAND) {
// Unhandled set. Set on a sensor is used to reset stats.
// User should process it in own handler when sensor supports high/low or recorded value.
nackReason = E120_NR_UNSUPPORTED_COMMAND_CLASS;
}

} else {
handled = false;

Expand Down
26 changes: 25 additions & 1 deletion src/DMXSerial2.h
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ struct RDMDATA {

extern "C" {
typedef bool8 (*RDMCallbackFunction)(struct RDMDATA *buffer, uint16_t *nackReason);
typedef bool8 (*RDMGetSensorValue)(uint8_t sensorNr, int16_t *value, int16_t *lowestValue, int16_t *highestValue, int16_t *recordedValue);
}

// ----- Library Class -----
Expand All @@ -98,6 +99,18 @@ struct RDMPERSONALITY {
// maybe more here... when supporting more personalitites.
}; // struct RDMPERSONALITY

struct RDMSENSOR {
uint8_t type;
uint8_t unit;
uint8_t prefix;
int16_t rangeMin;
int16_t rangeMax;
int16_t normalMin;
int16_t normalMax;
bool8 lowHighSupported;
bool8 recordedSupported;
char *description;
}; // struct RDMSENSOR

struct RDMINIT {
char *manufacturerLabel; //
Expand All @@ -108,6 +121,8 @@ struct RDMINIT {
// RDMPERSONALITY *personalities;
const uint16_t additionalCommandsLength;
const uint16_t *additionalCommands;
const uint8_t sensorsLength;
const RDMSENSOR *sensors;
}; // struct RDMINIT


Expand All @@ -116,7 +131,10 @@ class DMXSerialClass2
{
public:
// Initialize for RDM mode.
void init (struct RDMINIT *initData, RDMCallbackFunction func, uint8_t modePin = 2, uint8_t modeIn = 0, uint8_t modeOut = 1);
void init (struct RDMINIT *initData, RDMCallbackFunction func, uint8_t modePin = 2, uint8_t modeIn = 0, uint8_t modeOut = 1) {
init(initData, func, NULL, modePin, modeIn, modeOut);
}
void init (struct RDMINIT *initData, RDMCallbackFunction func, RDMGetSensorValue sensorFunc, uint8_t modePin = 2, uint8_t modeIn = 0, uint8_t modeOut = 1);

// Read the last known value of a channel.
uint8_t read (int channel);
Expand Down Expand Up @@ -147,6 +165,9 @@ class DMXSerialClass2
// Register a device-specific implemented function for RDM callbacks
void attachRDMCallback (RDMCallbackFunction newFunction);

// Register a device-specific implemented function for getting sensor values
void attachSensorCallback (RDMGetSensorValue newFunction);

// check for unprocessed RDM Command.
void tick(void);

Expand All @@ -171,6 +192,9 @@ class DMXSerialClass2
// callback function to device specific code
RDMCallbackFunction _rdmFunc;

// callback function to get sensor value
RDMGetSensorValue _sensorFunc;

// remember the given manufacturer label and device model strings during init
struct RDMINIT *_initData;

Expand Down

0 comments on commit 091abda

Please sign in to comment.