CONNECT() and DTR

as we know bunch of the boards out there are ATMEGA's that has a reset tied to /DTR line of the usb2serial chip (ch430, ftdi, atmel...) and when octoprint connects to the printer it reboots if this link is there. number of these boards have a jumper, but number of them don't.. was reminded by this after I took one ender5 for test, connect/disconnect octoprint in the middle of the print from sd and printer reboots :frowning: ..

the solution as we all know is stty -F /dev/ttyUSB0 -hup -hupcl that you need to add to /udev/rules.d..... to make sure it gets set properly every time usb serial is connected... problem is that interferes with other operations (when you actually want to reset the board to shoot the new firmware in for e.g.) and since I seen somewhere that python serial library also knows how to "not use DTR" on connect ... something like

port =serial.Serial( "/dev/ttyUSB0", baudrate=115200...   dsrdtr = False );

maybe it would be cool to by default connect with dsrdtr=false and add a config to enable/disable that if for any reason anyone want to :slight_smile: ..

no clue how to do this trough plugin and really don't wanna touch source of the core octoprint as I know I can mess it up big time :smiley:

2 Likes

May be a moot point with the new comm layer of 1.4.x. but that makes sense to me. Maybe submit a feature request to the issue tracker?

1 Like

I guess new layer would use the same serial library?! so that the connect function is identical.. in any way it made more sense to me to put it here then on the github, not sure why :smiley: ...

Don't know if the new comm layer uses the same library or not.

there are multiple serial libs for python??!?!? that sounds like a waste of resources :smiley: .. anyhow, I hope if there is other one that it supports the dtr control too :slight_smile:

I wonder if this setting has any effect if it's changed?

image

it resets the printer irrelevant to that setting (no clue what it does)

Looking at the docs I think false is the default value. It would be just a matter of adding a setting and combining it with the arguments, similar to how the exclusive option is being done now, linked below. It seems that the dsrdtr command is related to hardware flow control though and probably will break something...I think you should try it, lol.

I wanted to, before I wrote the post :smiley: but was not smart enough to figure out where/how it works on octoprint :smiley: ... I think I mentioned before I'm really not a python dev, I reaaaaaaly dislike everything about python :frowning: .. it's just not my cup of tea, I don't even know the basics... I managed to write few plugins by doing copy/paste google copy/paste google... and made them work but..

e.g.

			serial_port_args = {
				"port": str(port),
				"baudrate": baudrateList()[0] if baudrate == 0 else baudrate,
				"timeout": read_timeout,
				"write_timeout": 0,
				"parity": serial.PARITY_ODD
			}

			if settings().getBoolean(["serial", "exclusive"]):
				serial_port_args["exclusive"] = True

			serial_obj = serial.Serial(**serial_port_args)

serial.Serial(**serial_port_args)
you are actually calling a constructor with a pointer to a structure here?! how the hack does that work? name, value tuples?

serial_port_args["exclusive"] = True
but there is no "exclusive" in here:

			serial_port_args = {
				"port": str(port),
				"baudrate": baudrateList()[0] if baudrate == 0 else baudrate,
				"timeout": read_timeout,
				"write_timeout": 0,
				"parity": serial.PARITY_ODD
			}

?!?! this will out of the blue create one?

I believe you understand why I decided not to try :smiley: .. but if I'm understanding you correctly I should just change this (to test if this would not reset the printer even if stty -F /dev/ttyUSB0 +hupcl )

			serial_port_args = {
				"port": str(port),
				"baudrate": baudrateList()[0] if baudrate == 0 else baudrate,
				"timeout": read_timeout,
				"write_timeout": 0,
				"parity": serial.PARITY_ODD
			}

to

			serial_port_args = {
				"port": str(port),
				"baudrate": baudrateList()[0] if baudrate == 0 else baudrate,
				"timeout": read_timeout,
				"write_timeout": 0,
				"parity": serial.PARITY_ODD,
				dsrdtr = False
			}

irrelevant of the position of dsrdtr in the structure?

(I would be playing with it myself already instead of writing this but I got this ender5 to finish some work as I was a printer short, and I'm shooting some 20+ hour prints so not much time to tweak... attm octoprint disconnected from that marlin as it was rebooting it and as soon as I finish the current task I'll replace electronics there but wanna be ready to try out everything I can before I toss that melzi (or whatever's hiding in the the box) to the trash :smiley: )

This one I don't necessarily understand completely, but there's something special about the ** in the constructor call.

I understand it as a dictionary object where if the name:value pair isn't already defined it adds it. This is very similar to javascript the way I interpret it.

I would lean towards something more like:

			if settings().getBoolean(["serial", "disable_dsrdtr"]):
				serial_port_args["dsrdtr "] = True

but just for testing this should suffice:

			serial_port_args = {
				"port": str(port),
				"baudrate": baudrateList()[0] if baudrate == 0 else baudrate,
				"timeout": read_timeout,
				"write_timeout": 0,
				"parity": serial.PARITY_ODD,
				"dsrdtr" = False
			}

But I don't know python that well either, so it's just a stab in the dark.

In Python, methods can have "positional arguments" and "keyword arguments". Basically, if a method definition defines a default value for an argument, it becomes a keyword argument. The cool thing about keyword arguments is that the order in which you supply them when calling the method does not matter, though arguments should always be listed before the keyword arguments.

def exampleMethod(
  first_argument, second_argument, 
  some_keyword_argument=0, 
  another_keyword_argument=False):

This method can be called like this:

exampleMethod(0, 0, 1, True)
exampleMethod(1, 1)
exampleMethod(2, 2, another_keyword_argument=True)
exampleMethod(3, 3, another_keyword_argument=True, some_keyword_argument=2)

Note that the positional arguments should always be specified; otherwise you get a typeerror about a missing argument, and they always have to be specified before any keyword arguments.

Say we have the following dict:

keyword_args = {
  "some_keyword_argument": 20, 
  "another_keyword_argument": True
}

We can use that dict to supply the keyword arguments for the method using the ** unpack operator in Python (which has nothing to do with pointers). The following two lines are equivalent:

exampleMethod(3,3, **keyword_args)
exampleMethod(3,3, some_keyword_argument=20, another_keyword_argument=True)

There's a similar way to unpack positional arguments from a list or tuple using the * operator:

positional_args = (4, 4)
exampleMethod(*positional_args, **keyword_args)

3 Likes

interesting concept, anyhow this evening the print will finish and I will test what works :smiley:

I added:


                        serial_port_args = {
                                "baudrate": baudrateList()[0] if baudrate == 0 else baudrate,
                                "timeout": read_timeout,
                                "write_timeout": 0,
                                "dsrdtr" : False,
                        }

and it does not solve nothing :frowning: the marlin is resseting ...

So, what does it solve?

well the marlin reset issue is solved by

root@octopi:~# cat /usr/local/bin/disabledtr.sh
#!/bin/sh

if [ -z "$DEVNAME" ]; then
        exit 1
fi

/bin/stty -hupcl -F $DEVNAME

root@octopi:~# cat /etc/udev/rules.d/99-ender.rules
# udevadm info -q all -n /dev/ttyUSB0
# ACTION=="add", SUBSYSTEM=="usb", ATTR{idVendor}=="1a86", ATTR{idProduct}=="7523", RUN+="/bin/stty -hup -hupcl -F "

KERNEL=="ttyUSB?", RUN+="/usr/local/bin/disabledtr.sh"
root@octopi:~#

I read somewhere online that adding this dsrdtr=false to serial.connect will do the same (octoprint will open a connection and set serial port to not use DTR), but it does not when done this way... now if it didn't work 'cause I %@$%^^ something with python, or it can't be done trough python or I simply did it in the wrong place - no clue :frowning: .. neither do I know python enough to have a clue how to debug it nor I know octoprint source enough to understand how it work exactly.. I just think that if there is a way to select not to use DTR on serial port, from software, it should exist as option... there's still issue of turning pi on/off (it will reboot the board) but that one I have no clue how to solve in sw...

this is not a huge issue for me (if it were I'd probbly start learning python and looking for any way how to integrate this into octoprint, even run a fork of octoprint like I run my own for of smoothieware) as I will be replacing the marlin board tonight (still have not decided if I'm going original smoothieboard, replicape or smoothie PRC clone + klipper, will see what I find inside when I open the box ... what space do I have to work with :smiley: ) so I will not have to deal with it any more, but my initial experience with "setup octopi, connected to ender 5, reboots, loads of reboots" and assumed how weird it might look to a new user :smiley: and tried to help with suggestion... unfortunately I'm not smart enough to make my suggestion work in short time :frowning: .. maybe someone knows how

btw thatnks for this explanation, made lot of things clearer when reading python code :slight_smile:

I was joking at your double negative.

This page describes some code in C for dealing with an array of strings. Note that each string itself might be referred to as char * by type, a "pointer to a single char". So a char **, as it were, might be a pointer to a pointer to a character (the beginning of this collection). It's clear to me that whoever created the Python interface was writing the underlying code in C.

python has pointers?

See my explanation of ** in Python above. It has nothing to do with pointers, or C. It is an unpacking operator to convert a "dict" to a series of keyword arguments.