-
Notifications
You must be signed in to change notification settings - Fork 7
Expand file tree
/
Copy pathopen-serial-port-in-new-console.sh
More file actions
executable file
·277 lines (197 loc) · 8.54 KB
/
Copy pathopen-serial-port-in-new-console.sh
File metadata and controls
executable file
·277 lines (197 loc) · 8.54 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
#!/bin/bash
# If you want to open a serial port in a new console window by clicking on a desktop icon,
# this script will help:
# - You can edit this script in order to change the way all icons open serial ports.
# - This script can open a serial port with many different tools, so you can experiment
# until you find the right one for you.
#
# Copyright (c) 2014-2025 R. Diez - Licensed under the GNU AGPLv3
set -o errexit
set -o nounset
set -o pipefail
# set -x # Enable tracing of this script.
declare -r SCRIPT_NAME="${BASH_SOURCE[0]##*/}" # This script's filename only, without any path components.
declare -r VERSION_NUMBER="1.01"
declare -r EXIT_CODE_SUCCESS=0
declare -r EXIT_CODE_ERROR=1
# If you just specify the name (instead of a full path to it), make sure that run-in-new-console.sh is in your PATH.
PATH_TO_RUN_IN_NEW_CONSOLE_SCRIPT="run-in-new-console.sh"
abort ()
{
echo >&2 && echo "Error in script \"$SCRIPT_NAME\": $*" >&2
exit $EXIT_CODE_ERROR
}
check_whether_tool_exists ()
{
local TOOL_NAME="$1"
if ! type "$TOOL_NAME" >/dev/null 2>&1 ;
then
abort "Tool \"$TOOL_NAME\" is not installed on this system. Install the tool, check your PATH or modify this script."
fi
}
escape_filename_for_socat ()
{
local FILENAME="$1"
# Escaping of the backslash character ('\') only works separately and must be done first.
FILENAME="${FILENAME//\\/\\\\}"
local CHARACTERS_TO_ESCAPE=":,({['!\""
local -i CHARACTERS_TO_ESCAPE_LEN="${#CHARACTERS_TO_ESCAPE}"
local -i INDEX
for (( INDEX = 0 ; INDEX < CHARACTERS_TO_ESCAPE_LEN ; ++INDEX )); do
local CHAR="${CHARACTERS_TO_ESCAPE:$INDEX:1}"
FILENAME="${FILENAME//$CHAR/\\$CHAR}"
done
ESCAPED_SOCAT_FILENAME="$FILENAME"
}
open_with_socat ()
{
# Tool rlwrap uses GNU Readline for stdin, in order to provide convenient line-editing features.
# Instead of using rlwrap, you would normally use "socat READLINE",
# but support for that socat option is normally disabled on Ubuntu/Debian due to licensing issues.
local USE_RLWRAP="$1"
# We could add option "escape=0x03" below (to the STDIO side) in order to make socat
# quit with Ctrl+C, or alternatively "escape=0x0F" in order to quit with Ctrl+O. However,
# leaving this option out seems to pass all such key combinations to the remote device,
# which is usually what you want. In order to terminate socat, you would normally
# close the window with the mouse or with your desktop environment's standard key combination.
#
# See here for more information about the socat options below:
# https://rdiez.miraheze.org/wiki/Serial_Port_Tips_for_Linux
local SOCAT_TOOL_NAME="socat"
check_whether_tool_exists "$SOCAT_TOOL_NAME"
escape_filename_for_socat "$SERIAL_PORT_FILENAME"
# Escape again for the Bash shell.
printf -v ESCAPED_SOCAT_FILENAME "%q" "$ESCAPED_SOCAT_FILENAME"
if $USE_RLWRAP; then
CMD="rlwrap socat -t0 STDIO"
else
CMD="socat -t0 STDIO,raw,echo=0"
fi
CMD+=" file:$ESCAPED_SOCAT_FILENAME,b$SERIAL_PORT_SPEED,cs8,parenb=0,cstopb=0,clocal=0,raw,echo=0,setlk,flock-ex-nb,nonblock=1"
}
open_with_picocom ()
{
# About picocom:
# - Exit with Ctrl+A, Ctrl+X.
# - The serial port file gets locked, so opening a second picocom on the same serial port does not work.
# However, this does not block a second connection with socat "setlk,flock-ex-nb", although socat
# will eventually display messages like "Resource temporarily unavailable".
# - There is a short delay on exit.
local PICOCOM_TOOL_NAME="picocom"
check_whether_tool_exists "$PICOCOM_TOOL_NAME"
# Escape the filename for the Bash shell.
printf -v SERIAL_PORT_FILENAME "%q" "$SERIAL_PORT_FILENAME"
CMD="\"$PICOCOM_TOOL_NAME\" --baud \"$SERIAL_PORT_SPEED\" --flow n --parity n --databits 8 \"$SERIAL_PORT_FILENAME\""
}
open_with_minicom ()
{
# About minicom:
# - Exit with Ctrl+A, x.
# - The serial port file gets locked, so opening a second minicom on the same serial port does not work.
# However, this does not block a second connection with socat "setlk,flock-ex-nb".
local MINICOM_TOOL_NAME="minicom"
check_whether_tool_exists "$MINICOM_TOOL_NAME"
# Escape the filename for the Bash shell.
printf -v SERIAL_PORT_FILENAME "%q" "$SERIAL_PORT_FILENAME"
CMD="\"$MINICOM_TOOL_NAME\" -b \"$SERIAL_PORT_SPEED\" -8 -D \"$SERIAL_PORT_FILENAME\""
}
open_with_screen ()
{
# About GNU Screen:
# - Exit with Ctrl+A, '\' , or with Ctrl+A, 'k'.
# - The serial port file gets locked, so opening a second 'screen' on the same serial port does not work.
# You get no proper error message though.
local SCREEN_TOOL_NAME="screen"
check_whether_tool_exists "$SCREEN_TOOL_NAME"
# If you are an experienced GNU Screen user, you may want to attach to an existing session and so on.
# But if you just want to use GNU Screen as a simple terminal emulator, you want it to exit (and not detach
# and stay in the background) when you close the window.
# To achieve that, we need to feed GNU Screen with a temporary configuration file that contains the right option.
# I tried bash' "Process Substitution", but it did not work.
local TMP_FILENAME
TMP_FILENAME="$(mktemp --tmpdir "tmp.$SCRIPT_NAME.XXXXXXXXXX.screen.cfg")"
local TMP_FILENAME_QUOTED
printf -v TMP_FILENAME_QUOTED "%q" "$TMP_FILENAME"
# shellcheck disable=SC2064
trap "rm -- $TMP_FILENAME_QUOTED" EXIT
echo "autodetach off" >>"$TMP_FILENAME"
# Escape the filename for the Bash shell.
printf -v SERIAL_PORT_FILENAME "%q" "$SERIAL_PORT_FILENAME"
CMD="\"$SCREEN_TOOL_NAME\" -c \"$TMP_FILENAME\" \"$SERIAL_PORT_FILENAME\" \"$SERIAL_PORT_SPEED\" "
}
open_with_ckermit ()
{
# About C-Kermit:
# - Exit with Ctrl+'\', then press uppercase 'C', command "exit". Getting Ctrl+'\' to work on a German keyboard is tricky: press Ctrl+AltGr+'\'.
# - The serial port file gets locked, so opening a second 'screen' on the same serial port does not work.
# Kermit command execution not abort though.
local CKERMIT_TOOL_NAME="kermit"
check_whether_tool_exists "$CKERMIT_TOOL_NAME"
# Escape the filename for the Bash shell.
printf -v SERIAL_PORT_FILENAME "%q" "$SERIAL_PORT_FILENAME"
local KERMIT_COMMANDS="set modem type none,set line $SERIAL_PORT_FILENAME,set carrier-watch off,set speed $SERIAL_PORT_SPEED,connect"
local KERMIT_COMMANDS_QUOTED
printf -v KERMIT_COMMANDS_QUOTED "%q" "$KERMIT_COMMANDS"
CMD="\"$CKERMIT_TOOL_NAME\" -C $KERMIT_COMMANDS_QUOTED"
}
open_with_gtkterm ()
{
# About gtkterm:
# - The serial port file gets locked, so opening a second 'gtkterm' on the same serial port does not work.
# This does not prevent gtkterm from starting and staying open though.
# - It can display hex codes.
local GTKTERM_TOOL_NAME="gtkterm"
check_whether_tool_exists "$GTKTERM_TOOL_NAME"
# Escape the filename for the Bash shell.
printf -v SERIAL_PORT_FILENAME "%q" "$SERIAL_PORT_FILENAME"
CMD="\"$GTKTERM_TOOL_NAME\" --port \"$SERIAL_PORT_FILENAME\" --speed \"$SERIAL_PORT_SPEED\" "
NEEDS_NEW_CONSOLE_WINDOW=false
}
# ------ Entry Point (only by convention) ------
if (( $# == 1 )) && [[ $1 = "--version" ]]; then
echo "$VERSION_NUMBER"
exit $EXIT_CODE_SUCCESS
fi
if (( $# != 4 )); then
abort "Invalid arguments. Usage example: \"$0\" /dev/ttyS0 115200 socat \"My Window Title\"" >&2
fi
# These are the command-line arguments the user needs to supply:
SERIAL_PORT_FILENAME="$1"
SERIAL_PORT_SPEED="$2"
OPEN_WITH="$3"
WINDOW_TITLE="$4"
NEEDS_NEW_CONSOLE_WINDOW=true
case "$OPEN_WITH" in
socat) open_with_socat false;;
socat-rlwrap) open_with_socat true;;
picocom) open_with_picocom;;
minicom) open_with_minicom;;
screen) open_with_screen;;
ckermit) open_with_ckermit;;
gtkterm) open_with_gtkterm;;
# There are many more options we could add.
# For example, Python has 'miniterm':
# $ python -m serial.tools.miniterm /dev/ttyS0
# --- Miniterm on /dev/ttyS0: 9600,8,N,1 ---
# --- Quit: Ctrl+] | Menu: Ctrl+T | Help: Ctrl+T followed by Ctrl+H ---
*) abort "Unknown method \"$OPEN_WITH\".";;
esac
if $NEEDS_NEW_CONSOLE_WINDOW; then
check_whether_tool_exists "$PATH_TO_RUN_IN_NEW_CONSOLE_SCRIPT"
echo "Running this command in new console: $CMD"
printf -v CMD_QUOTED "%q" "$CMD"
CMD_NEW_CONSOLE="\"$PATH_TO_RUN_IN_NEW_CONSOLE_SCRIPT\""
CMD_NEW_CONSOLE+=" --console-discard-stderr"
CMD_NEW_CONSOLE+=" --console-icon=kcmkwm"
CMD_NEW_CONSOLE+=" --console-title=\"$WINDOW_TITLE\""
if false; then
CMD_NEW_CONSOLE+=" --console-no-close"
fi
CMD_NEW_CONSOLE+=" -- "
CMD_NEW_CONSOLE+=" $CMD_QUOTED"
echo "$CMD_NEW_CONSOLE"
eval "$CMD_NEW_CONSOLE"
else
echo "$CMD"
eval "$CMD"
fi