For RDM decoding and encoding we can provide you a simple library.
This guide describes how to implement it. The library is not optimized and has only support for the necessary commands.
You can find the Source Code for the library in the Vision External Example or download it from here:
https://kk-t.com/wp-content/uploads/2025/12/VisionRdmLibrary_2025_12_31.zip
Include
Just add all the files to your project. Include “libRdmInterface.h“ and call the necessary functions.
#include "libRdmInterface.h"
Initialization
For initialization you have to call “rdm_init“ function. Therefore you have to provide an rdmInstance pointer, a valid rdm id and the necessary callback. The rdm id will be copied into the library.
(global) rdm_library_instance_t rdmInstance;
....
rdm_init(&rdmInstance,(const uint8_t*) rdmId,&rdm_answer_callback);
Decode RDM Message
In order to decode a RDM Message call “rdm_decodeMessage“. The id param is used as a identifier for the rdm answer callbacks if more than one interface is used.
rdm_decodeMessage(&rdmInstance,buf, length,id);
After decoding a message the “rdm_answer_callback“ will be called. ( If the message is valid for the controller)
Use of RdmAnswer Callback
The answer callback provides the answer message of the decoded rdm message.
static void rdm_answer_callback(const uint8_t * msg, uint16_t length,bool sentBreak, uint8_t id)
{
iqMesh_WriteRdm(msg,length);
}
Supported Commands
Following commands can be implemented:
void RdmExtGetFactoryDefaults(rdm_answer_t* rdmImp, rdm_factory_default_get_response_t* responseBuf);
void RdmExtGetDeviceInfo(rdm_answer_t* rdmImp, rdm_device_info_get_response_t* responseBuf);
void RdmExtGetProductDetail(rdm_answer_t* rdmImp, rdm_product_detail_id_get_response_t* responseBuf);
void RdmExtGetDeviceModelDescription(rdm_answer_t* rdmImp, rdm_device_model_description_get_response_t* responseBuf);
void RdmExtGetManufacturerLabel(rdm_answer_t* rdmImp, rdm_manufacturer_label_get_response_t* responseBuf);
void RdmExtGetDeviceLabel(rdm_answer_t* rdmImp, rdm_device_label_get_response_t* responseBuf);
void RdmExtGetSoftwareVersionLabel(rdm_answer_t* rdmImp,rdm_softwareversion_label_get_response_t* responseBuf);
void RdmExtGetBootSoftwareVersionLabel(rdm_answer_t* rdmImp, rdm_boot_softwareversion_label_get_response_t* responseBuf);
void RdmExtGetDmxPersonality(rdm_answer_t* rdmImp, rdm_dmx_personality_get_response_t* responseBuf);
void RdmExtGetDmxPersonalityDescription(rdm_answer_t* rdmImp, rdm_dmx_personality_description_get_response_t* responseBuf);
void RdmExtGetDmxStartaddress(rdm_answer_t* rdmImp, rdm_dmx_startaddress_get_response_t* responseBuf);
void RdmExtGetSensorDefinition(rdm_answer_t* rdmImp, rdm_sensor_defintion_get_response_t* responseBuf);
void RdmExtGetSensorValue(rdm_answer_t* rdmImp, rdm_sensor_value_get_response_t* responseBuf);
void RdmExtGetDeviceHours(rdm_answer_t* rdmImp, rdm_device_hours_get_response_t* responseBuf);
void RdmExtGetLampHours(rdm_answer_t* rdmImp, rdm_lamphours_get_response_t* responseBuf);
void RdmExtGetLampStrikes(rdm_answer_t* rdmImp, rdm_lampstrike_get_response_t* responseBuf);
void RdmExtGetLampState(rdm_answer_t* rdmImp, rdm_lampstate_get_response_t* responseBuf);
void RdmExtGetDevicePowerCycles(rdm_answer_t* rdmImp, rdm_device_power_cycle_get_response_t* responseBuf);
void RdmExtGetIdentify(rdm_answer_t* rdmImp, rdm_identify_device_get_response_t* responseBuf);
void RdmExtGetPowerState(rdm_answer_t* rdmImp, rdm_power_state_get_response_t* responseBuf);
void RdmExtGetPerformSelftest(rdm_answer_t* rdmImp, rdm_perform_selftest_get_response_t* responseBuf);
void RdmExtGetSelfTestDescription(rdm_answer_t* rdmImp,rdm_selftest_description_get_response_t* responseBuf);
void RdmExtGetSupportedParameter(rdm_answer_t* rdmImp,uint16_t* responseBuf, uint8_t* pidCount);
void RdmExtGetParameterDescription(rdm_answer_t* rdmImp,rdm_parameter_description_get_response_t* responseBuf);
void RdmExtGetLanguageCapabilities(rdm_answer_t* rdmImp,uint8_t* responseBuf, uint8_t* languageCounter);
void RdmExtGetLanguage(rdm_answer_t* rdmImp,rdm_language_get_response_t* responseBuf);
void RdmExtGetBootSoftwareID(rdm_answer_t* rdmImp,uint32_t* responseBootSoftwareID);
void RdmExtGetSlotInfo(rdm_answer_t* rdmImp,rdm_slot_info_get_response_array_t* responseBuf, uint8_t* slotCount);
void RdmExtGetSlotDescription(rdm_answer_t* rdmImp,rdm_slot_desc_get_response_t* responseBuf);
void RdmExtGetDefaultSlotValue(rdm_answer_t* rdmImp,rdm_slot_default_get_response_array_t* responseBuf, uint8_t* slotCount);
void RdmExtGetLampOnMode(rdm_answer_t* rdmImp,rdm_lamp_on_mode_response_t* responseBuf);
void RdmExtGetDisplayInvert(rdm_answer_t* rdmImp,rdm_display_invert_get_response_t* responseBuf);
void RdmExtGetDisplayLevel(rdm_answer_t* rdmImp,uint8_t* responseBuf);
void RdmExtGetPanInvert(rdm_answer_t* rdmImp,bool* responseBuf);
void RdmExtGetTiltInvert(rdm_answer_t* rdmImp,bool* responseBuf);
void RdmExtGetRealTimeClock(rdm_answer_t* rdmImp,uint64_t* responseBuf);
void RdmExtGetPresetPlayback(rdm_answer_t* rdmImp,rdm_preset_playback_response_t* responseBuf);
void RdmExtGetIq(rdm_answer_t* rdmImp, rdm_iq_get_response_t* responseBuf);
void RdmExtGetCustomError(rdm_answer_t* rdmImp, rdm_custom_label_get_response_t* responseBuf);
void RdmExtGetCustomWarning(rdm_answer_t* rdmImp, rdm_custom_label_get_response_t* responseBuf);
void RdmExtGetCustomAdjustLedCalibrationData(rdm_answer_t* rdmImp, rdm_adjustledcalibration_get_response_t* responseBuf,rdm_adjustledcalibration_colorinfos_get_response_t* responseBufColorInfos);
void RdmExtGetCustomAdjustLedCalibrationDebug(rdm_answer_t* rdmImp, rdm_adjustledcalibration_debug_get_response_t* responseBuf);
void RdmExtGetCustomServiceHours(rdm_answer_t* rdmImp, uint32_t* responseBuf);
void RdmExtGetCustomPid(uint16_t pid, uint8_t* msg, uint16_t pdl, rdm_answer_t* rdmImp, uint8_t* responseBuf, uint16_t* responseLength);
void RdmExtSetFactoryDefaults(rdm_answer_t* rdmImp);
void RdmExtSetDeviceLabel(rdm_answer_t* rdmImp, char* label, uint8_t labelLength);
void RdmExtSetDmxPersonality(rdm_answer_t* rdmImp, uint8_t personality);
void RdmExtSetDmxStartaddress(rdm_answer_t* rdmImp,uint16_t dmxStartAddress);
void RdmExtSetIdentify(rdm_answer_t* rdmImp, bool set);
void RdmExtSetResetDevice(rdm_answer_t* rdmImp,rdm_reset_t reset);
void RdmExtSetPowerState(rdm_answer_t* rdmImp, rdm_powerstate_t powerState);
void RdmExtSetPerformSelftest(rdm_answer_t* rdmImp,uint8_t selftest);
void RdmExtSetCustomAdjustLedCalibrationSend(rdm_answer_t* rdmImp, rdm_adjustledcalibration_send_set_t set,uint8_t* data, uint8_t chunkLength, custom_adjust_cal_send_response_t* response);
void RdmExtSetCustomAdjustLedCalibrationData(rdm_answer_t* rdmImp, rdm_adjustledcalibration_set_t responseBuf);
void RdmExtSetCustomServiceHours(rdm_answer_t* rdmImp, uint32_t counter);
void RdmExtSetCustomPid(rdm_answer_t* rdmImp, uint16_t pid, uint8_t* data, uint16_t pdl);
void RdmExtSetIqInputSource(rdm_answer_t* rdmImp,rdm_iq_inputsource_t inputSource);
void RdmExtSetIqInputState(rdm_answer_t* rdmImp, rdm_iq_set_input_state_t inputState);
void RdmExtSetIqPopup(rdm_answer_t* rdmImp, rdm_iq_popup_t popup);
void RdmExtSetIqEmergencyMode(rdm_answer_t* rdmImp, bool emergencyMode);
void RdmExtSetIqBatteryRuntime(rdm_answer_t* rdmImp, rdm_iq_battery_runtime_t runTime);
void RdmExtSetIqAntitheftMode(rdm_answer_t* rdmImp, rdm_iq_antitheft_t antitheft );
void RdmExtSetLanguage(rdm_answer_t* rdmImp,rdm_language_set_t language);
void RdmExtSetLampOnMode(rdm_answer_t* rdmImp,rdm_lamp_on_mode_t lamp_mode);
void RdmExtSetDisplayInvert(rdm_answer_t* rdmImp,rdm_display_invert_t displayInvert);
void RdmExtSetDisplayLevel(rdm_answer_t* rdmImp,uint8_t displayLevel);
void RdmExtSetPanInvert(rdm_answer_t* rdmImp,bool invert);
void RdmExtSetTiltInvert(rdm_answer_t* rdmImp,bool invert);
void RdmExtSetCapturePreset(rdm_answer_t* rdmImp,rdm_capture_preset_set_t preset);
void RdmExtSetRealTimeClock(rdm_answer_t* rdmImp,uint64_t rtc);
void RdmExtSetPresetPlayback(rdm_answer_t* rdmImp,rdm_preset_playback_response_t preset);
Don’t forget to expose all supported commands via the Supported Parameters PID.
Each implemented command must be added to this list.
After filling the array, you must also set the correct command count.
Refer to the example shown in the picture for the expected structure and order.

Custom Commands
You can implement manufacturer-specific commands usingRdmExtSetCustomPid, RdmExtGetCustomPid, and RdmExtGetParameterDescription.
Register the custom PID
Add the custom PID to Supported Parameters first, exactly as shown above.
If it is not listed there, controllers will ignore it.
Describe the parameter
Implement RdmExtGetParameterDescription (if not already present) and provide a proper parameter description for the custom PID, as shown in the example picture.

Implement GET and SET handling
Implement RdmExtGetCustomPid and RdmExtSetCustomPid.
These functions must decode the custom PID and handle the corresponding get/set logic.
Here a Example for the RdmExtGetCustomPid:

The RdmExtSetCustomPid looks basically the same. From this point on, the implementation is identical to a standard PID: same decoding, same validation, same processing logic.