-
Notifications
You must be signed in to change notification settings - Fork 1.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support framing error/break detection #539
Comments
I would vote for parmrk. Clearing the queue would lose data, and would not give the user program any indication the break happened. Plus, adding parmrk would be almost trivial to do. |
@onitake not sure if there is already available solution, so I made a simple (linux/posix only) utility, to set port attributes and detect sync in the stream here https://github.com/smarek/dmx-python-client with particular emphasis on how i use the existing file-descriptor and modify the attributes here https://github.com/smarek/dmx-python-client/blob/master/roh/dmx/client/dmx_client.py#L47 Or is there any easier solution to this? Thank you! |
@smarek I tried to solve it like this: def initdmx(port):
with serial.Serial(port=port, baudrate=250000, bytesize=8, parity='N', stopbits=2, timeout=1.0) as ser:
fd = ser.fileno()
attr = termios.tcgetattr(fd)
# enable breaks: set PARMRK and INPCK, clear IGNPAR and ISTRIP in iflag
attr[0] = attr[0] | termios.PARMRK | termios.INPCK & ~termios.IGNPAR & ~termios.ISTRIP
termios.tcsetattr(fd, termios.TCSANOW, attr)
def readdmx(ser):
mark = ser.read()
if len(mark) < 1:
return NO_DATA
if mark[0] == 255:
mark = ser.read()
if len(mark) < 1:
return NO_DATA
if mark[0] == 255:
return FRAME_ERROR
return mark[0] It didn't work reliably, however. |
@onitake thank you for sharing your code I developed https://github.com/smarek/dmx-python-client as a client to uDMX USB dongle and RS485 to RS232 USB converter With master software being QLC+ or Q Light Controller, i found that the transmission is really unstable and thus I cannot rely on single bytestream sync and I have to verify each frame and re-sync each time the frame does not end with expected BREAK sequence (FF 00 00) Also the rate at which data come in is almost the same as speed i can read the data out from pyserial buffer, so i've never experienced empty buffer, you on the other hand, have the NO_DATA as something that happened to you quite regularly So my reading dmx data here: https://github.com/smarek/dmx-python-client/blob/master/roh/dmx/client/dmx_client.py#L67 |
I have tested a bunch of RS485-to-USB converters and observed the same problem: The frame sync goes all over the place practically instantly, and I can't manage to synchronize to the frame start. As can be seen in initdmx(), the idea was to set two stop bits and a 1-second timeout, then react to frame errors, which should occur whenever a new frame starts. When there is "silence" on wire, the timeout should ensure that the read() waits at least one frame period (1s), then fires and I get NO_DATA, which resets the sync counter. But this doesn't seem to work. Here's the input loop: def loop(ser, present, refresh, report):
# frame type (=start code)
frametype = 0
# frame
frame = bytearray(512)
# frame index counter
index = 0
# break only on ctrl+c
while True:
value = readdmx(ser)
received = False
if value < 0:
# break or read error, reset frame counter
index = 0
report(value)
else:
# not out of bounds?
if index < 512:
# nope, process
if index == 0:
# set the frame type
frametype = value
else:
# store next byte (we store the start code separately)
frame[index-1] = value
# present
received = True
# did we receive a valid value?
if received:
# yes, was it something else than the start code?
if index > 0:
# are we in a default frame? (i.e. start code = 0)
if frametype == 0:
# data value, present it
present(index, value)
# and increment the counter
index += 1
# and present (probably not the best idea to do here though)
refresh() |
Well with more further testing, obviously, having any DMX address set to value |
So i got it figured out, for anybody interested, tag v0.3 works so far with all usb/gpio rs485 to serial (baud=250000), i got to test with Trick is
Also while testing buffers add up and over time data are processed with more delay (in my trivial/naive scripts), so currently there is buffer reset every 50 valid DMX512 frames received, see https://github.com/smarek/dmx-python-client/blob/master/roh/dmx/client/dmx_client.py#L117 Usual time to obtain sync, on rpi zero w, is 0.7 seconds, and valid frame update (DmxClientCallback) comes 3-5 times per second, which was good enough for me I'm not sure |
In DMX-512, a break condition is used to signal the start of a data frame. Unfortunately, using POSIX or even W32 APIs, it seems to be quite hard to detect when a break occurs - in contrast with sending a break.
Nevertheless, would it be possible to implement support for detecting breaks, or at least allow configuring serial ports to send special codes when a break is detected?
On POSIX, this could be achieved by clearing IGNPAR and setting PARMRK, while for W32, I found this: https://social.msdn.microsoft.com/Forums/en-US/b503e85f-4efc-4fe5-9cb9-89ec93d64430/detect-a-break-as-the-begining-of-a-serial-data-frame-windows-iot-serial-device?forum=WindowsIoT
Another option for POSIX would be to clear IGNBRK and set BRKINT - the Linux man page states:
If the SIGINT can be prevented somehow, flusing the input queue might be exactly what's needed for this special case.
I saw that there was a proposal for something similar (parity error detection) in #154 , but it got closed without being merged.
The text was updated successfully, but these errors were encountered: