-
-
Notifications
You must be signed in to change notification settings - Fork 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
Linux low latency fix (allow set without changing low latency mode) #2241
Conversation
Proposed fix to address serialport#2240
} else if(err == -2) { | ||
snprintf(data->errorString, sizeof(data->errorString), "Error: %s, cannot set", strerror(errno)); | ||
return; | ||
if (data->lowLatency) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
so if it's undefined or false its not set, and if it's true it is set? does this mean you can't turn it off? Would you ever want to turn it off?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi @reconbot, thanks for the quick response :-)
I have to admit, toggling low latency on and off isn't really something I considered. Given how the user sets low latency within linux, and the use cases I've seen I don't know if toggling is common.
I'm not certain this is the best fix, and bigger change may be needed to fully address this feature, but my priorities when proposing this were:
- to get the set method to work again for people who don't need to invoke low latency mode
- continue to allow anyone who does want to invoke the low latency mode to enable it
- keep the change as small and low impact as possible (so we can fix point 1 asap)
As I understand it, the current code and the default behaviour of Linux are not aligned. In particular, I believe that in order to be able to invoke lowLatency mode you need to first change the default behaviour of the port, using something like: sudo setserial /dev/ttyUSB0 low_latency
. As such, by default Linux will not allow you to invoke low latency mode in Serialport, however the code within the set method tries to configure it irrespective of the options the user supplies to the set method. Even specifying port.set({dtr: true, LowLatency: false })
or port.set({dtr: true})
will cause an attempt to set the low latency bit to zero and error out.
Having thought about this a little more, I wonder if the set method is really the right place to be activating low latency mode, since all of the other options within the set method are really control signals. I can't help thinking about low latency mode being more like setting the baud rate etc. As such it would seem to me to be more appropriate to allow it to be defined within the port open method, and within the update method. Of course we probably need to find a way to check if we have permission to enable low latency mode first otherwise we will continue to throw errors. The potential downside of treating low latency mode like baud rate is that baud rate has it's own get method, it would be a shame to have to add a get method just for this since it is platform specific.
Let me know if you would like me to try a different way to fix this
Cheers
Gareth
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Upon further investigation I think we need a better fix for this. I'll add more info to the issue based on my improved understanding of what's going on...
I will try to make a new PR to address this more completely ASAP, but until a better fix is available I still think this is an acceptable workaround to get the v9 code working on Linux for all users.
Per my comment in the issue, anyone placing a dependency on "serialport": "9.0.0" will get the broken version of bindings since the interdependence is specified as "^9.0.0".
Fix for linux low latency mode issue serialport#2240 (revised)
Improved fix for low latency mode: Changesserialport_linux.cpp:
serialport_linux.h:
serialport_unix.cpp:
TestingTested on Linux Ubuntu LTS and Win10: Linux without admin rights
Linux with admin rights
Windows 10
Additional considerationsThe the focus of this change was entirely on addressing errors per #2240 as such I have not performed any actual benchmarking of the lowLatency mode to check for changes to latency (or increases to CPU load - setserial has info on expected benefits/impacts). |
@reconbot do let me know if you would like to discuss or revise any of these changes, or if you would prefer if I setup a new PR for this |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry for the delay in review. I think you uncovered a bug, and also some feedback on simplifying the call to set.
return -2; | ||
if (oldFlags != ss.flags) | ||
{ | ||
if (ioctl(fd, TIOCSSERIAL, &ss)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this is wrong - https://man7.org/linux/man-pages/man2/ioctl.2.html#RETURN_VALUE
It should be a positive number on success not failure.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
agreed, looks like we should check for negative values to indicate errors instead:
if (ioctl(fd, TIOCSSERIAL, &ss) < 0) {
although the same also seems to be true for the setting the baud rate:
if (ioctl(fd, TCSETS2, &t)) { return -2; }
does that need a fix too?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think so
@@ -43,17 +43,34 @@ int linuxSetLowLatencyMode(const int fd, const bool enable) { | |||
if (ioctl(fd, TIOCGSERIAL, &ss)) { | |||
return -1; | |||
} | |||
|
|||
int oldFlags = ss.flags; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lets see if oldFlags & ASYNC_LOW_LATENCY == enable
and just return early if we don't have to do anything?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
good shout that is lots nicer
@@ -332,17 +332,6 @@ void EIO_Set(uv_work_t* req) { | |||
bits |= TIOCM_DSR; | |||
} | |||
|
|||
#if defined(__linux__) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
good move
ss.flags &= ~ASYNC_LOW_LATENCY; | ||
} | ||
if (ss.flags & ASYNC_LOW_LATENCY != enable) { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
just a nitpick it's better to return early than it is to nest
if (oldFlags != ss.flags) | ||
{ | ||
if (ioctl(fd, TIOCSSERIAL, &ss)) { | ||
if (ioctl(fd, TIOCSSERIAL, &ss) < 0) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
another nitpick ioctl will always return -1 on error never anything else
…serialport#2241) * only set lowLatency if defined * fix set and get methods for low_latency * clarify error messages Proposed fix to address serialport#2240
Only set low Latency mode if lowLatency is defined
Proposed fix to address #2240