bash 使用 COM 端口读取/写入数据的批处理脚本

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/25329129/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-08 21:37:28  来源:igfitidea点击:

Batch script to read/write data using COM port

bashbatch-file

提问by headinabook

I need to write a batch script that can read and write to a COM port (in my case, COM1).

我需要编写一个可以读写 COM 端口(在我的例子中是 COM1)的批处理脚本。

I know that I can send data to a COM port using

我知道我可以使用

echo hello > COM1

And I can read data coming in to a text file using

我可以使用读取进入文本文件的数据

type COM1 > sample.txt

I'd like to be constantly capturing the data coming into the COM port into a text file and be able to send commands to the COM port depending on what data was just read on the COM port. Is there a way to do this in a batch script?

我想不断地将进入 COM 端口的数据捕获到一个文本文件中,并且能够根据刚刚在 COM 端口上读取的数据向 COM 端口发送命令。有没有办法在批处理脚本中做到这一点?

Would it be easier/better to do it in a bash script? How would I do it in bash?

在 bash 脚本中这样做会更容易/更好吗?我将如何在 bash 中做到这一点?

EDIT:The data I wish to read is the output of the boot of a system to an UEFI shell. Then, when it gets there, enter some commands and capture the output of those commands. Then, boot an OS (capturing the output of the boot), enter some more commands to the Linux shell and capture the output of them. It does not contain an exact number of characters.

编辑:我希望读取的数据是系统启动到 UEFI shell 的输出。然后,当它到达那里时,输入一些命令并捕获这些命令的输出。然后,启动一个操作系统(捕获启动的输出),向 Linux shell 输入更多命令并捕获它们的输出。它不包含确切数量的字符。

If a bash script is the only answer, that is ok. I can work with that. I am currently running version 4.1.10(4) of bash in Windows 7 using cygwin.

如果 bash 脚本是唯一的答案,那没关系。我可以使用它。我目前正在使用 cygwin 在 Windows 7 中运行 bash 4.1.10(4) 版。

回答by Ross Ridge

Playing around with a few different things with batch scripts leads me to believe nothing is going to work in with a batch script and the standard Windows command line tools. set /Preturns immediately when reading from COM1, and something like type COM1will copy the serial data in large chunks line by line.

使用批处理脚本处理一些不同的事情让我相信批处理脚本和标准的 Windows 命令行工具不会起作用。set /P从 读取时立即返回COM1,类似的东西type COM1将逐行复制大块中的串行数据。

I had better luck using Cygwin bash. Here's a simple script that receives lines from COM1and echoes them back. It exits when it receives a line starting with "quit". You can test it out by using a terminal emulator on the other end of the serial link or just using statements like echo quit > COM1.

我使用 Cygwin bash 运气更好。这是一个简单的脚本,它接收行COM1并回显它们。它在收到以“quit”开头的行时退出。您可以通过在串行链路的另一端使用终端仿真器或仅使用像echo quit > COM1.

CR="$(echo -e '\r')"
exec 4<> /dev/com1

cat <&4 | while :
do
    IFS="$CR" read -r line 
    case "$line" in
    quit*)
        echo "goodbye$CR" >&4
        break
        ;;
    *)
        echo "recieved line: $line"
        echo "recieved line: $line$CR" >&4
        ;;
    esac
done

The CRvariable holds a carriage return character which in this example is used to strip it off the input lines and used to terminate lines with CR LF when outputting them over the serial line. Depending how exactly your BIOS behaves you may or may not need to do this in your own script.

CR变量包含一个回车符,在本例中用于将其从输入行中剥离,并在通过串行线路输出时用于终止带有 CR LF 的行。根据您的 BIOS 行为的准确程度,您可能需要也可能不需要在您自己的脚本中执行此操作。

The exec 4<> /dev/com1line is crucial. This opens the COM port once for both reading and writing. Windows only allows a COM port to be open once, so if this wasn't done it wouldn't be possible to read and write to the COM port. The 4means that is assigned to file descriptor 4 and the execstatement keeps it open for the rest of the script.

exec 4<> /dev/com1线是至关重要的。这将打开一次 COM 端口以进行读取和写入。Windows 只允许打开一个 COM 端口一次,因此如果不这样做,就无法读取和写入 COM 端口。该4分配给文件描述符4和手段exec的语句保持打开状态的脚本的其余部分。

The cat <&4 |part is also important. Unfortunately there seems to be a bug in Cygwin bash where it will try to rewind the file descriptor if it reads past the end of a line. This works for files, but it doesn't for serial ports so data gets lost. To workaround this problem the script reads from a pipe instead, which bash is smart enough to not try to rewind.

cat <&4 |部分也很重要。不幸的是,Cygwin bash 中似乎存在一个错误,如果它读取到行尾,它将尝试倒带文件描述符。这适用于文件,但不适用于串行端口,因此数据会丢失。为了解决这个问题,脚本改为从管道读取,bash 足够聪明,不会尝试倒带。

The reason for setting IFS="$CR"is to strip off the carriage return at the end of a line as mentioned before, and to not strip off anything while reading. The readcommand uses the IFS string to break up the input line into words. You may be able to use this to your advantage and set it to a different value to make it easier to parse the BIOS output.

设置的原因IFS="$CR"是前面说的去掉行尾的回车,读的时候不去掉任何东西。该read命令使用 IFS 字符串将输入行分解为单词。您可以充分利用它并将其设置为不同的值,以便更轻松地解析 BIOS 输出。

The rest of the details are pretty straightforward. The -roption for readcauses it not to treat \characters specially. Depending on what sort of line endings your BIOS expects you have three different ways you can write your echo statements:

其余的细节非常简单。在-r供选择read的原因是不是要善待\字符特别。根据 BIOS 期望的行尾类型,您可以通过三种不同的方式编写 echo 语句:

echo "Both CR and LF line ending$CR" >&4
echo -n "CR only line ending$CR" >&4
echo "LF only line ending" >&4

One thing this script doesn't do it set the COM port parameters like baud rate and flow control. This is probably best done using the normal MODE COM1command. Cygwin has an equivalent sttycommand, but it doesn't appear to support all the parameters.

这个脚本没有做的一件事是设置 COM 端口参数,如波特率和流量控制。这可能最好使用普通MODE COM1命令来完成。Cygwin 有一个等效的stty命令,但它似乎不支持所有参数。

Another entirely different option is to use Expect. If you find that it's hard to get bash to parse and respond appropriately to your BIOS's output then you might consider using that instead. This sort of thing is what its designed for, though there's a bit of learning curve if you're not already familiar with TCL. It's available as a standard Cygwin package.

另一个完全不同的选择是使用 Expect。如果您发现很难让 bash 解析并适当地响应您的 BIOS 输出,那么您可以考虑改用它。这种事情就是它的设计目的,尽管如果您还不熟悉 TCL,则有一些学习曲线。它可以作为标准 Cygwin 包使用。

回答by Aacini

The standard way to read data from the serial port is not:

从串口读取数据的标准方法不是

type COM1 > sample.txt

nor:

也不:

copy COM1 sample.txt

It would be if that data would have a standard EndOfFile mark, like a Ctrl-Z character.

如果该数据具有标准的 EndOfFile 标记,例如 Ctrl-Z 字符,那就是。

If that data comes in linesthat ends in CR+LF or just CR characters, then the standard way to read them would be:

如果该数据以 CR+LF 或仅以 CR 字符结尾的出现,则读取它们的标准方法是:

set /P "var=" < COM1

If that data have nota delimiter, like CR or CR+LF, then you must specify the exact format of such data:

如果该数据没有分隔符,如 CR 或 CR+LF,则您必须指定此类数据的确切格式:

  • Do you want to read records of a fixed number of characters?
  • Do you want to read characters until a certain one appear? Which one?
  • May the input data contain control characters? Which ones?
  • Any other format of the input data?
  • 您想读取固定字符数的记录吗?
  • 是否要读取字符直到某个字符出现?哪一个?
  • 输入数据可以包含控制字符吗?哪个?
  • 输入数据的任何其他格式?

EDIT: Reply to the comments

编辑回复评论

When set /Pcommand is executed with redirected input, it does notwait for data. In this case, it returns immediately and the variable is not changed.

set /P命令与重定向输入执行,它并没有等待数据。在这种情况下,它立即返回并且变量没有改变。

We may try to wait for the next character received from the serial port and thenexecute the set /Pcommand; this way, the set /Pshould correctly read an input line terminated in CR or CR+LF that does not contain control characters.

我们可以尝试等待从串口接收到下一个字符,然后执行set /P命令;这样,set /P应该正确读取以 CR 或 CR+LF 结尾的不包含控制字符的输入行。

This is the code:

这是代码:

set "key="
for /F "delims=" %%K in ('xcopy /W "%~F0" "%~F0" ^< COM1 2^> NUL') do (
   if not defined key set "key=%%K"
)
set /P "line=" < COM1
set "line=%key:~-1%%line%"
echo Line read from COM1: "%line%"

Try it and report the result. Sorry, I can not try input read from COM1 in my computer.

尝试一下并报告结果。抱歉,我无法尝试从计算机中的 COM1 读取输入。