Gentoo Forums
Gentoo Forums
Gentoo Forums
Quick Search: in
[TUTO] How to control the RTS pin directly from bash ?
View unanswered posts
View posts from last 24 hours

 
Reply to topic    Gentoo Forums Forum Index Off the Wall
View previous topic :: View next topic  
Author Message
doublehp
Guru
Guru


Joined: 11 Apr 2005
Posts: 472
Location: FRANCE

PostPosted: Sat Oct 21, 2017 1:46 pm    Post subject: [TUTO] How to control the RTS pin directly from bash ? Reply with quote

Cross posting the same answer on many forums. Obviously, many people have the same need, and nobody ever published a simple answer.

The need: control serial port pins directly from shell, without messing with heavy tools, usually in order to control relays.

* Outputting commands

The pins we talk about are output pins: TX, DTR, and RTS. I am not going to talk about reading input pins; it's probably possible with similar solution, but not the topic of the day.

* Software requirements

This answer is target at lame people. Many forums explain that you need C code, and a huge compiler to manipulate RTS; such answers are offtopic. The question was clreadly stated: "how to control RTS with shell". There is a bad news, and a good news.

bad news: you can't. Linux does not include any tool to directly control RTS. You always have to compile C code.

Good news: I am clever, and I know tricks. I remind that the aim here is to play with shell scripts, and avoid using compilers. There are other two many ways to solve our problem; one clean solution would be to compile two binaries called rtson, but this would produce many files. I am looking for a single shell file.

Instead of using GCC to build a binary, I am going to use tcc. There are many other ways to use tcc; it can be used as interpreter for C files; here, I am going to use it as interpreter for raw random text. Using shell variables and substitution, his allows me to alter the content of C code on the fly.

For relay control, I recommend using sleep. But for finer controle, you can use usleep or nanosleep, which take arguments as us and ns.

Note that usleep can not pause execution for a time shorter than the granularity of scheduler. For beginners, it means that any value smaller than 10ms will produce a sleep of 10ms. And for values like 35ms, you will probably get an actual result which will be either 30ms or 40ms. This depends on the configuration of your kernel.

Code:
aptitude install tcc


* Linux /dev namespace

In the following examples, I will directly manipulate the dev node name ttyUSB0. This can break your setup by many ways.

If the script is run when dongle is absent, the dd command will create a classic file with the same name. The C code for RTS will not have that problem. One way to avoid this is to make script die if the dev file is absent:

Code:
MyPort=/dev/ttyUSB0
[ -c "${MyPort}" ] || exit 1


but you may still have problems if the port is removed just in the time slot between execution of the two commands (unlikely, but possible).

If you have more than one serial port, you will have naming issues.

If all your adapters use different chipsets, you can use /dev/serial/by-id/ . This method is resilient, and names will always remain the same even when unplug, replug, or put the devices in different ports:
Code:
ls /dev/serial/by-id/ -l
lrwxrwxrwx 1 root root 13 Jan  1  1970 usb-Prolific_Technology_Inc._USB-Serial_Controller-if00-port0 -> ../../ttyUSB0
lrwxrwxrwx 1 root root 13 Jan  1  1970 usb-Silicon_Labs_CP2102_USB_to_UART_Bridge_Controller_0001-if00-port0 -> ../../ttyUSB1

If several adapters share the same chipset name, then, Linux will put only one in /dev/serial/by-id/ ; so, you will have to rely on /dev/serial/by-path/ . Since this path is a PCI address, you will always have to plug the adapter on the same physical plug-path of the computer. Including the potential USB hubs.

The two following commands are run on the same host:
Code:
$ ls /dev/serial/by-id/ -l
lrwxrwxrwx 1 root root 13 Oct 13 12:19 usb-1a86_USB2.0-Serial-if00-port0 -> ../../ttyUSB1
$ ls /dev/serial/by-path/ -l
lrwxrwxrwx 1 root root 13 Oct 13 12:19 pci-0000:00:14.0-usb-0:1:1.0-port0 -> ../../ttyUSB0
lrwxrwxrwx 1 root root 13 Oct 13 12:19 pci-0000:00:14.0-usb-0:3:1.0-port0 -> ../../ttyUSB1


Note that this heavily depend on your distribution. Also, I had issues in Debian, when some distupgrade updated the kernel, and changed the name of the driver handling the dongle ... the id name of the dev-node had chanced.

/dev/serial/ may not contain all available ports. For example, in an rPi:
Code:
find /dev/serial/ | grep AMA | wc
      0       0       0

... AMA0 port exists in /dev/ but is not listed here. So, sometimes, you will have to search manually your port name. I don't understand why the ttyAMA0 port is not registered as a serial port. Maybe an udev issue; not sure.

* Hardware issues

I am using only USB-TTL serial adapters. People using RS232 ports will need to check the polarity of pins. In most case, polarity is inverted between TTL and RS232.

RTS and TX pins are UP level by default. It means, after boot, the pin is delivering +5V.

There are many ways to workaround this. Most of them may have glitch at power-on time, and reboot, depending on your specific hardware.

- use a two-ways relay

- insert a transistor between the output pin and the relay to invert the logic

- put the relay between the out pin, and +5V supply (if possible, the one from the USB-TTL adapter)

The relays I use: SIP-1A05, JZC-49FA 006, JZC-49FA 005, HF49FD/005-1H11 ...
The first one (1A05) has the advantage of a very high impedance (500R) but can control only 125V on output (can not be used on 250V). The 49FA series are able to drive 250V directly, but with a lower impedance (300R for 6V, and 200R for 5V), whgat produces a much bigger current draw at start and electromagnetic parasite on turn-off. So for controlling low voltages, you should prefer the 1A05, and use 49FA only when 250V is required.

Note that they are all very low power, and should not used for capacitive loads above 0.1A, or resistive loads above 1A.

I like those ref because they provide true galvanic insulation directly from TTL pins, without the polarity problem of optocouplers.

Due to inertia, boot glitches may let your stuff blink witness LEDs, but not activate the relay. Relays are very long to turn on and off; seing the witness LEDs blinking does not mean the relay will perform contact.

* Setting RTS for a short time

Note that since this code will open the port, you may have issues if you try to use other pins of the port while controling RTS.

RTS has a few issues:
- it's UP by default.
- it will stay down only during the execution of the code; when you kill the code, the pin will rise up again. That's why it's probably impossible to activate simultaneously a relay on RTS, and relays on TX or DTR. This limitation is specific to my solution. People who completely control the port using a daemon can do what they want.

Code:
#!/bin/bash
MySerialPort="/dev/ttyUSB0"
MyLatency="1"
echo "
#include <fcntl.h>
#include <sys/ioctl.h>
main()
{
int fd;
fd = open(\"${MySerialPort}\",O_RDWR | O_NOCTTY );
int RTS_flag;
RTS_flag = TIOCM_RTS;
ioctl(fd,TIOCMBIS,&RTS_flag);
sleep (${MyLatency});
ioctl(fd,TIOCMBIC,&RTS_flag);
close(fd);
}
" | tcc -run -

But here, execution of script is halted while the relay is closed.

Note that the max value for MyLatency is 2^32-1=4294967296-1= about 136 years, using sleep, on x86.

Here is an other method where the script can keep running:

Code:
#!/bin/bash
MySerialPort="/dev/ttyUSB0"
# max value is 4294967295
MyLatency="4294967295"
echo "
#include <fcntl.h>
#include <sys/ioctl.h>
main()
{
int fd;
fd = open(\"${MySerialPort}\",O_RDWR | O_NOCTTY );
int RTS_flag;
RTS_flag = TIOCM_RTS;
ioctl(fd,TIOCMBIS,&RTS_flag);
sleep (${MyLatency});
ioctl(fd,TIOCMBIC,&RTS_flag);
close(fd);
}
" | tcc -run - &
dapid=$!
# do your stuff
sleep 10
kill $dapid


If you manually stop your script, note that tcc will keep running, and new execution of script will be unable to control the pin. There are two ways to fix this:
- quick and dirty, at beginning of script, add "killall tcc"
- clean and heavy: use trap.
The choice will depend how sensible your devices are. Any way, boot glitches are probably much more problematic than this.

* Putting a relay on TX

As for the RTS pin, the TX pin is up by default, when not doing anything.

Switching the pin is much easier. I use the physical mechanical inertia of the relay. The relay has a pretty long turn-off time; and as long as the up-states are shorter than half of this delay, we are fine.

By default, baud rate is 9600. This means the line can handle 9600 changes of state per second. One data byte will consume at least 10 time slots, plus one spacer; in short, you can send about 9600/10=960 bytes per second. With default settings. You can tweak everything (the number of bits per word can be adjusted between 6 and 9; plus 0 to 2 parities, plus
0 to 2 stops). Here, I will stick to default settings.

So, this command will switch the relay for one second:

Code:
MyLatency=$((960*1))
dd if=/dev/zero of=/dev/ttyUSB0 bs=1 count=$MyLatency


Real execution time may vary for various reasons. Serial port has cache; as soon as the cache is large enough to contain the remaining data, the command will return.

Note that under very heavy load, the system may be unable to switch context fast enough. In case of a buffer underrun, the data flow will be interrupted, and the relay will glitch.

In terms of time durantion, I am not aware of any top limit. Bash and dd should both be able to work with very large numbers; much larger that centuries worth.

Bash is not able to handle floats; so for values below one second, you need to remove the zero on the factor, and use a duration in deci-second: for 8/10th of a s:
Code:
MyLatency=$((960*8))


* RTS-TX glitch under bash

Each time I send a byte on TX, RTS pin will blink. I have tried various combinations of stty +/-crtscts ... but nothing helped. I don't know if this is handled by Linux driver, or if it's a side effect inherent to my USB-TTL dongle. I strongly believe that it should be possible, via C daemons, to play with TX pin without messing RTS. It's probably impossible in shell oriented approach. Unless other other serial adapters behave a different way than mine.

In my case, this is not an issue, because for today, I want one relay to control the power button of a computer, and the other relay, the reset button. I will use TX for the power button, and RTS for reset. So, when I press POWER, either short or long press, I completely don't care if reset button got pressed at the same time.

In most other use case, this side effect is probably critical.

* DTR

I don't have any USB-TTL adapter with DTR, so I can't test it.

From theory, you just take the above code for RTS pin, and replace TIOCM_RTS with TIOCM_DTR . Code could also be simplified: in C, you can regroup most lines:

Code:
#!/bin/bash
MySerialPort="/dev/ttyUSB0"
MyLatency="1"
echo "
#include <fcntl.h>
#include <sys/ioctl.h>
main()
{ int fd; fd = open(\"${MySerialPort}\",O_RDWR | O_NOCTTY );
int DTR_flag; RTS_flag = TIOCM_DTR;
ioctl(fd,TIOCMBIS,&DTR_flag); sleep (${MyLatency}); ioctl(fd,TIOCMBIC,&DTR_flag);
close(fd);} " | tcc -run -
# untested


* Reading inputs

It could be possible to use RX as single input pin, using a very specific configuration (disabling all start, stop bits and checksums); but it would not work on all serial port. I have met serial-usb adapters that have bugs in exotic settings. It's possible to use pins CD, DSR, CTS, and RX to read state of things. When available.

Not covering this topic now; maybe I will post a reply, or edit this message later.

* Hardware cost

Depending on the seller, the cost of a USB-TTL adapter should be between 1.5€ for a very basic model with only TX-RX-GND-+5V and 2.5€ if you want 3.3V option, and RTS pin. Then you add 1€ to 2€ for the relay (see above for the reference). Thats 2.5€ for a single USB-relay, up to 7€ for a twin-relay-USB able to drive 250V.

Unfortunately, you won't be able to use this kind of relay directly on the Wifi chip esp8266 because it works at 3.3V, and I have never found any 3.3V relay; anyway, at this very low voltage, a relay would have a very low impedance, require a very large current, much higher than whan this kind of chip can provide on an IO pin; so you wil have to use a forward gate or a transistor. 3.3-5V adapters are now very easy to find on rPi and Arduino shops.

* Sources:
http://xanthium.in/Controlling-RTS-and-DTR-pins-SerialPort-in-Linux
http://www.cedarlakeinstruments.com/SharedFiles/io.html
http://pficheux.free.fr/articles/lmf/serial/

People asking the same question:
https://www.promixis.com/forums/showthread.php?21399-Activating-Relay-s-using-Serial-Port
https://stackoverflow.com/questions/24886207/setting-dtr-high-rts-low-using-linux-bash
http://www.domoticz.com/forum/viewtopic.php?t=17454

Other forums offering C solutions:
http://community.sharpdevelop.net/forums/p/10126/28128.aspx
https://www.linuxquestions.org/questions/programming-9/manually-controlling-rts-cts-326590/
_________________
DEMAINE Benoît-Pierre (aka DoubleHP ) http://www.demaine.info/
>o_/ Coin coin coin \_o<
to contact me (MSN,ICQ, JABBER, Skype ... ) http://benoit.demaine.info/contact.png
Back to top
View user's profile Send private message
patrix_neo
Guru
Guru


Joined: 08 Jan 2004
Posts: 437
Location: The Maldives

PostPosted: Sat Oct 21, 2017 2:06 pm    Post subject: Reply with quote

Quote:

This answer is target at lame people. Many forums explain that you need C code, and a huge compiler to manipulate RTS


Omg, you must have horrible....*gosh*.... friends

Me, not your friend, I would try to map the hardware and approach it accordingly. You seem to know howto.
If nothing else works, I have a cow to sell...her name is Rosa. $20...
Back to top
View user's profile Send private message
doublehp
Guru
Guru


Joined: 11 Apr 2005
Posts: 472
Location: FRANCE

PostPosted: Sat Oct 21, 2017 4:02 pm    Post subject: Reply with quote

Brave people could learn C.

Rich people could buy a proper relay board.

Brave people could solder proper forward gates, and use relay drivers.

This tuto is for those who don't want to spend more than 4€, and solder a relay diectly on a TTL pin. It's going to have side effects, but it will work 99,9% of the time. I have stopped doing god level projects with downtime certified below 1ns per year ... Now, I consider that 99.9% uptime is correct. So, after triple checking the definition of lame, it is an appropriate adjective ... including for myself.
_________________
DEMAINE Benoît-Pierre (aka DoubleHP ) http://www.demaine.info/
>o_/ Coin coin coin \_o<
to contact me (MSN,ICQ, JABBER, Skype ... ) http://benoit.demaine.info/contact.png
Back to top
View user's profile Send private message
patrix_neo
Guru
Guru


Joined: 08 Jan 2004
Posts: 437
Location: The Maldives

PostPosted: Sat Oct 21, 2017 4:16 pm    Post subject: Reply with quote

My god, you're drowning me with tears of laughter.
EDIT: Stop doing good things, ok. You're on your own pal. Have you stidied the methodology that is BK? He did fare well with the samba issue. i mean, people did do a big effin effort.
I just so happen to know it would not work. I think he/she just made us try harder!

EDIT2: Did you consider your user to be able to write to the serial port as intened? Or how did you know you are able to? I cannot see it feasible without proper information....(lol)
Besides, if you know proper assembler coding, with proper code, evolving arround different hardware o/c, I think you might be able to control any hardware possible. Not easy, as you was trying to do it. I think that is the way to go though. Hard way...pays off.
Back to top
View user's profile Send private message
Ant P.
Watchman
Watchman


Joined: 18 Apr 2009
Posts: 5008

PostPosted: Sat Oct 21, 2017 6:47 pm    Post subject: Re: [TUTO] How to control the RTS pin directly from bash ? Reply with quote

Quote:
This answer is target at lame people.

This one is too, but it's actually an answer:
Code:
emerge dev-perl/Device-SerialPort

_________________
*.ebuild // /etc/service/*
Back to top
View user's profile Send private message
doublehp
Guru
Guru


Joined: 11 Apr 2005
Posts: 472
Location: FRANCE

PostPosted: Wed Oct 25, 2017 12:31 pm    Post subject: Reply with quote

patrix_neo Lame people who buy an rPi and want it work quick, don't have time to mess with learning ASM, or deal with the huge issues related to C. Sometimes, people ask very simple and trivial questions on internet ( http://www.domoticz.com/forum/viewtopic.php?t=17454 ) and never get answer (untill I register to answer them). The question was clearly phrased, and nobody answered him for weeks.

rPi people don't have time to learn ASM. People who enjoy ASM buy Arduinos.

Ant P. your solution is not usable on Raspbian.

You would have understood this if you had open the three links I gave at the bottom of my post, the questions that made me work on this detailed answer. I chose to post this answer here, rather on Raspbian forum, because I am more confident in Gentoo servers to be able to store a message on long term, and keep the thread open for 10+ years. I am fedup of forums who lock conversations after 3 months, leaving interesting open questions without answer, and sometimes, they come to be the first Google reply to my querry, and, due to lock, I can not publish any helping answer. Google have not yet understood this problem: it's useless to propose me a page asking the same question as I just did, if the page does not contain answer, and I can not publish one.
_________________
DEMAINE Benoît-Pierre (aka DoubleHP ) http://www.demaine.info/
>o_/ Coin coin coin \_o<
to contact me (MSN,ICQ, JABBER, Skype ... ) http://benoit.demaine.info/contact.png
Back to top
View user's profile Send private message
Naib
Watchman
Watchman


Joined: 21 May 2004
Posts: 5290
Location: Removed by Neddy

PostPosted: Wed Oct 25, 2017 12:49 pm    Post subject: Reply with quote

or you know... use a damn parallel port. It is designed for bitbanging.

and if you want to control the rts & dtr you could just use python and pyserial ...

Code:

import serial
ser = serial.Serial(...)
ser.rts = True
ser.dtr = True

_________________
The best argument against democracy is a five-minute conversation with the average voter
Great Britain is a republic, with a hereditary president, while the United States is a monarchy with an elective king
Back to top
View user's profile Send private message
pjp
Administrator
Administrator


Joined: 16 Apr 2002
Posts: 17211

PostPosted: Wed Oct 25, 2017 2:13 pm    Post subject: Reply with quote

doublehp wrote:
Ant P. your solution is not usable on Raspbian.
Raspbian information is best located on Raspbian support channels.
_________________
The whole system has to go. The modern criminal justice system is incompatible with Neuroscience. --Sapolsky
Back to top
View user's profile Send private message
Ant P.
Watchman
Watchman


Joined: 18 Apr 2009
Posts: 5008

PostPosted: Wed Oct 25, 2017 9:06 pm    Post subject: Reply with quote

doublehp wrote:
Ant P. your solution is not usable on Raspbian.

Debian doesn't have perl5? Get a better distro then.
_________________
*.ebuild // /etc/service/*
Back to top
View user's profile Send private message
cokey
Advocate
Advocate


Joined: 23 Apr 2004
Posts: 3343

PostPosted: Sat Oct 28, 2017 2:22 pm    Post subject: Reply with quote

Code:
aptitude: command not found

_________________
"Sex: breakfast of champions" - James Hunt
Back to top
View user's profile Send private message
Display posts from previous:   
Reply to topic    Gentoo Forums Forum Index Off the Wall All times are GMT
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum