-
Notifications
You must be signed in to change notification settings - Fork 219
Description
I would like to experiment with "raw" DMX-formatted frames, by which I mean DMX-formatted frames with a custom start code (something other than 0x00 for DMX or 0xCC for RDM) - and I would like to do this on Enttec DMX USB PRO attached to a Raspberry Pi running OLA.
The Enttec API documentation https://cdn.enttec.com/pdf/assets/70304/70304_DMX_USB_PRO_API.pdf mentions for:
- "Output Only Send DMX Packet Request (Label=6)"
Size In Bytes: 25 to 513 Description: DMX data to send, beginning with the start code. The overall message size specifies the size of the DMX data to send, ...
- "Send RDM Packet Request (Label=7)"
Size In Bytes: 1 to 513 Description: RDM data to send, beginning with the start code.
So, if I used the Enttec API directly (either via usbserial+ftdi_sio Linux kernel drivers, or using the FTDI proprietary libftd2xx.so driver (conflicts with ftdi_sio)), I could use either of the above commands to send a DMX-formatted packet with a custom start code from the Enttec.
However, even if I want to use the Enttec API directly in a program - if I want to use that program on a Raspberry Pi with an attached Enttec and running OLA (olad) which manages the Enttec (i.e. has the Enttec as a OLA Universe output or input port), I'd assume that olad would in that case take ownership of the device over the kernel drivers, and thus my application would be refused device access - at least until I shut down olad, which I'd rather not.
So, I would like to make a program that uses OLA (that is, olad) to send raw/custom frames over the Enttec - but I cannot find such an OLA API.
First, I took a look at https://docs.openlighting.org/ola/doc/latest/client_tutorial.html - there are no examples there with sending RDM, only DMX, and the API used is ola::client::OlaClient::SendDmx or (probably) ola::client::StreamingClient::SendDmx - both of those use ola::DmxBuffer Class, where it is mentioned:
dmx_buffer.SetFromString("0,1,2,3,4")The above code would set channels 1 through 5 to 0,1,2,3,4 respectively,
... meaning, there is no way to manipulate the start code of DmxBuffer (which makes sense, after all, given DMX is in the name of this class).
As far as RDM goes, I tried analyzing ola_rdm_set in a debug build, and eventually arrived at this stack trace:
$ LD_PRELOAD="/path/to/ola/common/.libs/libolacommon.so.0.0.0 /path/to/ola/./ola/.libs/libola.so.1.0.1" gdb --args examples/.libs/ola_rdm_set --frames -u 1 --uid 1000:12345678 device_label "My Lamp"
...
(gdb) b main
Breakpoint 1 at 0x12c80: file examples/ola-rdm.cpp, line 588.
(gdb) r
Starting program: ...
...
Breakpoint 1, main (argc=8, argv=0x7efff134) at examples/ola-rdm.cpp:588
588 int main(int argc, char *argv[]) {
(gdb) b common/io/Descriptor.cpp:350
Breakpoint 2 at 0x76ec9030: file common/io/Descriptor.cpp, line 350.
(gdb) b common/io/Descriptor.cpp:353
Breakpoint 3 at 0x76ec9044: file common/io/Descriptor.cpp, line 353.
(gdb) c
Continuing.
Breakpoint 2, ola::io::ConnectedDescriptor::Send (this=0x31ff0, buffer=0x49040 "0", size=52) at common/io/Descriptor.cpp:350
350 bytes_sent = send(WriteDescriptor(), buffer, size, MSG_NOSIGNAL);
(gdb) bt
#0 ola::io::ConnectedDescriptor::Send (this=0x31ff0, buffer=0x49040 "0", size=52) at common/io/Descriptor.cpp:350
#1 0x76f4e700 in ola::rpc::RpcChannel::SendMsg (this=this@entry=0x327b8, msg=msg@entry=0x7effe564)
at common/rpc/RpcChannel.cpp:305
#2 0x76f4f728 in ola::rpc::RpcChannel::CallMethod (this=this@entry=0x327b8, method=<optimized out>,
controller=controller@entry=0x36b30,
request=0x76f4f728 <ola::rpc::RpcChannel::CallMethod(google::protobuf::MethodDescriptor const*, ola::rpc::RpcController*, google::protobuf::Message const*, google::protobuf::Message*, ola::SingleUseCallback0<void>*)+504>, request@entry=0x7effe8b4,
reply=reply@entry=0x32848, done=done@entry=0x37fd0) at common/rpc/RpcChannel.cpp:232
#3 0x76f97540 in ola::proto::OlaServerService_Stub::RDMCommand (this=<optimized out>, controller=controller@entry=0x36b30,
request=request@entry=0x7effe8b4, response=0x32848, response@entry=0x76e59a84, done=0x37fd0)
at common/protocol/OlaService.pb.cpp:773
#4 0x76e23110 in ola::client::OlaClientCore::SendRDMCommand (this=0x33278, is_set=is_set@entry=true, universe=<optimized out>,
uid=..., sub_device=0, pid=pid@entry=130, data=data@entry=0x63bd0 "My Lampv\310;\006", data_length=7, data_length@entry=130,
args=...) at ola/OlaClientCore.cpp:1013
#5 0x76e23840 in ola::client::OlaClientCore::RDMSet (this=<optimized out>, universe=<optimized out>, uid=...,
sub_device=<optimized out>, pid=130, data=0x63bd0 "My Lampv\310;\006", data_length=7, args=...) at ola/OlaClientCore.cpp:588
#6 0x76e1ab50 in ola::client::OlaClient::RDMSet (this=<optimized out>, universe=<optimized out>, uid=...,
sub_device=<optimized out>, pid=130, data=data@entry=0x63bd0 "My Lampv\310;\006", data_length=7, args=...)
at ola/OlaClient.cpp:204
#7 0x000141b0 in RDMController::PerformRequestAndWait (this=this@entry=0x7effec9c, universe=163928, uid=...,
sub_device=<optimized out>, pid_name="device_label", is_set=true, inputs=std::vector of length 1, capacity 1 = {...})
at examples/ola-rdm.cpp:494
#8 0x00012f48 in main (argc=<optimized out>, argv=<optimized out>) at examples/ola-rdm.cpp:638
(gdb) p size
$1 = 52
(gdb) p/x buffer[0]@52
$2 = {0x30, 0x0, 0x0, 0x10, 0x8, 0x1, 0x10, 0x0, 0x1a, 0xa, 0x52, 0x44, 0x4d, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x22, 0x1e, 0x8, 0x1, 0x12, 0x8, 0x8, 0xa1, 0x42, 0x15, 0x66, 0x33, 0x22, 0x88, 0x18, 0x0, 0x20, 0x82, 0x1, 0x2a, 0x7, 0x4d, 0x79, 0x20, 0x4c, 0x61, 0x6d, 0x70, 0x30, 0x1, 0x38, 0x1}
So: in the ola_rdm_set itself, we first start with RDMController::PerformRequestAndWait, which then calls OlaClient::RDMSet](ola::client::OlaClient::RDMSet - and then in a rather complicated descent through the OLA API, I guess this gets turned into a Remote Procedure Call serialized using protobuf, and the final buffer resulting from that is used in a C send to write to a socket, which I guess then propagates this data to olad over the network. Inspecting the final buffer reveals there is no byte 0xCC to be found as a start code, which means that buffer does not contain a representation of an RDM frame, but a representation of the RPC call - and it is olad, after that call/command is received, that decides to build an actual RDM frame with start code 0xCC, and pass it to/send it over the device attached to the requested universe (Enttec in my case). Again, I see no way to change the RDM start code from 0xCC to something else in this case, either.
While I understand that other hardware may behave differently, at least the Enttec DMX USB PRO seems to allow for a custom start code. So is there any OLA API that would allow me to use it? That is, is there an OLA API function that would allow me to specify the full (DMX or RDM) frame on the client side - including the start code - which would also be recognized by olad, and propagated in full (including the custom start code) to the Enttec device?