Bash echoing in a screen - bash

I have this bash file:
#!/bin/bash
stty -F /dev/ttyACM0 cs8 9600 ignbrk -brkint -imaxbel -opost -onlcr -isig -icanon - iext en -echo -echoe -echok -echoctl -echoke noflsh -ixon -crtscts
screen /dev/ttyACM0 9600
echo "1"
This is basically an Arduino connected to my Ubuntu PC and I can run the code perfectly all until the echo "1" section.
I can ...
establish the connection
see the screen of the serial connection
type in "1" and see my light bulb light up, and when I type "0" the light bulb turns off.
The problem I am meeting now is that I would like to control the on/off in code (without me manually typing it out) and it seems almost impossible to do that. The logic is correct but when I start the screen, the code just stops there and runs the screen waiting for me to have some input. All until I plug out the Arduino will the echo finally come out. Is there a way to solve this?

I had a problem like this before, this was my workaround:
I had more luck with cu then with stty
Start a screen session:
screen -S arduino -dmS cu -l /dev/ttyACM0 -s 9600
Now there is a screen session created called arduino
You can send commands to it from a script:
screen -S arduino -X stuff 1
This will send the 1 to the serial connection just like your example
If you want to control this with a different user make sure rights will allow this and create the screen session with the same user that will be sending commands to the screen session.
If you have more questions just ask me.

Related

Redirect xterm to a background for a headless machine

I have a application that launches xterm and dumps uart logs. I am able to see it launch and dump the logs in the GUI. However, Using a remote session I want the xterm output to be running as a background process somewhere so that I can switch back and forth within a single terminal.
Using GUI
Using remote terminal (SSH)
$ xterm
xterm: Xt error: Can't open display: :0
I tried to do something like, but failed to work -
alias xterm="/bin/bash -c"
I don't want to have X forwarding and launch a window on my local machine as well.
If you just need the logs, you most likely don't need an X server or xterm.
You can simply run the target command itself. From your screenshot it looks like the command might be telnet 127.0.0.1 <port_number>. You can find it from the script that your application launches, or with ps -ef when it's running. If it's an UART, then you can also use minicom or socat to connect directly to serial port without any extra programs. This way, you don't even need telnet.
You can combine this command with either screen or tmux so that it's running in the background and you can switch to it from any terminal or console. Just run screen with no arguments, then run the command on virtual screen. Detach with CTRL-a d, and your command will continue to run in the background ready for you to reconnect to it at any time with screen -r.
Moreover, screen can also connect to serial port directly so you get two for the price of one.
The thing with xterm is that it will not write the logs anywhere except in the graphics buffer, and even there it will be only as flashing pixels which is not suitable for any processing. If you insist on going that way, you have several options:
Change the script that application runs (might not be possible depending on your situation)
Replace /usr/bin/xterm with your dummy script that just runs bash instead of xterm, and redirects the output to a file (ugly, but you could probably avoid breaking other applications by changing PATH and putting it somewhere else). In your script, you can use bash's redirection features such as >, or pipe output to tee.
Start a VNC server in the background and set the DISPLAY environment variable when you run your application to the number of virtual screen. In this case, any windows from application will open on VNC virtual screen and you can connect to it as you please.
Use xvfb as a dummy X server and combine it with xterm logging, etc.
Solution 1: Fake xterm on X11-less systems
You can also create a wrapper script that replaces xterm with another function. Test this out on a laptop with X11:
$ function xterm {
echo "hello $#"
}
$ xterm world 1
hello world 1
$ export -f xterm
$ /bin/xterm # opens a new xterm session
$ xterm world 2 # commands executed in second terminal
hello world 2
This means that you've replaced the command xterm for a function in all of the child processes.
Now, if you already know that your script will work in a terminal without xterm, you could create a function that accepts all of the parameters and executes it. No need for complicated screen stuff or replacing /usr/bin/xterm.
Solution 2: Dump UART data for the winz
If you want to save all of the uart data into a file, this is easily fixed by creating a screen session and a log file. Below the command will create a session named myscreensessionname that listens on the serial connection /dev/ttyUSB0 and writes its data to /home/$USER/myscreensessionname.log.
$ screen -dmS myscreensessionname -L -Logfile /home/$USER \
/myscreensessionname.log /dev/ttyUSB0 115200
Note that if you're going to use multiple screen sessions, you might want to use serial ids instead of /dev/ttyUSB0. You can identify the connections with udevadmin as follows.
$ udevadm info --name=/dev/ttyUSB0 | grep 'by-id'
S: serial/by-id/usb-FTDI_TTL232R-3V3_FTBDBIQ7-if00-port0
E: DEVLINKS=/dev/serial/by-id/usb-FTDI_TTL232R-3V3_FTBDBIQ7-if00-port0 /dev/serial/by-path/pci-0000:00:14.0-usb-0:4.4.4.1:1.0-port0
Here, instead of /dev/ttyUSB0, I would make use of /dev/serial/by-id/usb-FTDI_TTL232R-3V3_FTBDBIQ7-if00-port0.
EDIT:
You can attach the screen session with the following command. Once in the screen session, press crtl+a, and press d to detach.
$ screen -Dr myscreensessionname
To view all of your screen sessions:
$ screen -list
There is a screen on:
2382.myscreensessionname (04/02/2021 10:32:07 PM) (Attached)
1 Socket in /run/screen/S-user.

Toggling the Wi-Fi with XF86WLAN and script

I have the following script (in my PATH):
#!/usr/bin/env bash
main()
{
local state=$(sudo rfkill list wifi -n -o SOFT)
if [[ $state == 'blocked' ]]
then
sudo rfkill unblock wifi
state='Unblocked'
else
sudo rfkill block wifi
state='Blocked'
fi
notify-send 'Wi-Fi' "$state"
exit 0
}
main $#
Running the script from the command line works as expected, then I add the following shortcut to my.xbindkeysrc:
"kill-wifi"
XF86WLAN
But the notifications, and the Wi-Fi interface get stuck in one of the two states, blocked or unblocked, it doesn't toggle. Sometimes, if I press several times the XF86WLAN key, I get a toggle.
The weird thing is that using another key to trigger the script, such as F8, the whole thing works fine, but I want to leave F8 for purposes other than toggling the WiFi.
So one of my guesses was that there's "something" binding the XF86LAN KeySym that messes up when my script runs. But then commenting out the command that actually kills the WiFi interface, produces the right notifications (but I'm not actually doing anything useful).
Any pointers would be appreciated.
Aaaanyways, for anyone in my same situation, install urfkill which automatically listen for the XF86WLAN event.
Then in your script, simply produce the notification:
#!/usr/bin/env bash
main()
{
local state=$(sudo rfkill list wifi -n -o SOFT)
notify-send "Wi-Fi" "$state"
}
main
Note that the script uses another utility named rfkill only for getting the state of the Wi-Fi interface, and spit it in the notification.
Finally in your .xbindkeysrc:
"kill-wifi"
XF86WLAN
You could be using other hotkeys daemon like sxhkd or even the configuration file of i3 or sway, in any case your shell script only is used for notify the state of the Wifi interface, the real work of toggling the Wifi on and off is done by urfkill.
The good news is that now that button with the little antena symbol on your laptop actually toggles on/off your Wi-Fi card and you still have free to use the underlying Function key (F8 in my case) ;-)
P.S. If anyone reads this and knows why my first approach was failing (race condition or whatever), please feel free to let me know how to solve it.

Opening serial connection to Arduino through Bash

I have set up my Arduino so when I send a "0" via the serial monitor, a stepper motor turns a given amount.
I want to include this in a bash script, but I can only get this to work when the arduino serial monitor is open and entering echo 0 > /dev/tty.usbserial641 in bash. I assume this is because serial monitor is opening the connection for me.
In my struggle to open the connection in bash (without serial monitor open) I have tried all manner of options with stty -f /dev/tty.usbserial641 and have also tried connecting reset to ground with a 10uF capacitor.
Can any help me open the connection in bash without the use of arduino serial monitor?
System:
Arduino Uno rev3
OS X 10.8.4
Many thanks,
hcaw
Do the commands below work for you.
# stty -F /dev/ttyUSB0 9600 cs8 -cstopb
# sleep 0.1
# echo "0" > /dev/ttyUSB0
There is a difference between the value 0 and the ascii char 0 (48). Which one you trying to send, and which one are you trying to receive?
If you want to read the port from the terminal you can do it like this
head -n 1 /dev/ttyUSB0 //the number after n is how many lines you want to read
As a last note, I am a fan of pySerial. I would much rather write an interface in python than shell scripts.
I found a great binary written in C that solves my problem called Arduino-serial. Here's the link.
I hope this helps people with similar problems!

How can I send a string to serial /dev/tty.* port, delay a second, disconnect from the port and continue my bash script in OSX?

This is in relation to resetting an Arduino, and then start pushing data to it from my usb xbee.
I've tried using screen, with no luck.
screen -S Xbee -d -m /dev/tty.usbserial-A900fra9 115200 *reset
I don't know how to close this session, not sure whether the args are correct, either.
to send anything to devices on /dev, you can use the > >> 2> 2>&1, etc.
Try this example from tty1 (ctrl+alt+F1):
echo "my string" > /dev/tty2
now go to tty2 (alt+F2) and you gonna see your string. It should work with any device.
and to sleep, use:
sleep 1
your problem could be also with permissions. Try it with root! ;)

How to set the baud rate for Macs in a terminal

Is it possible to set the baud rate for Macs in a terminal? If yes, how to set the baud rate in terminal through the terminal?
I am trying to talk to the Mac using an Arduino (open source microcontroller), an XBee (wireless communicator) to type in the terminal through the serial monitor. The only problem I am having is the baud rate of the serial monitor and terminal are different. I can easily change the baud rate for the serial monitor in the Arduino, but I do not know what the baud rate is for the terminal in Mac.
On Mac OS, stty seemingly can only change terminal settings for an ongoing access.
It works to either:
Access the serial interface, e.g. cat /dev/cu.usbserial, the default settings will be used at first. On a different terminal use stty, e.g. stty -f /dev/cu.usbserial 230400 to set the baud rate, the settings of the terminal accessed before will change.
There is a small time window after executing stty, in which the access can be performed with the desired parameters, e.g. stty -f /dev/cu.usbserial 230400 & cat /dev/cu.usbserial executes stty, detaches it and then immediately performs the access to the serial device.
For one line command logging serial port /dev/tty.usbserial-X's output to cat.out and terminating the logging by pressing Ctrl+C, here is the solution: trap 'kill $(jobs -p)' SIGINT ; cat /dev/tty.usbserial-X | tee cat.out & stty -f /dev/tty.usbserial-X 115200. You can type Ctrl+C to terminate logging to cat.out. (edited)
This only seems to work for the /dev/cu.* device files. I don't know the difference from /dev/tty.* files.
Minicom is an excellent tool that does exactly what you're asking for. You can get it using apt on ubuntu but should check this Tutorial out for Mac.
Keep the serial reset issue in mind if you plan on sending data to the Arduino. see http://arduino.cc/playground/Main/DisablingAutoResetOnSerialConnection
stty 19200 or so.
Check man stty, you can set stop bits, speed, etc.
Surprised that no one mentioned picocom which could set higher bard rate up to 4000000.

Resources