A script package to read / write data using a COM port

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

I know I can send data to a COM port using

echo hello > COM1

      

And I can read the data coming into a text file using

type COM1 > sample.txt

      

I would like to continually capture the data coming into the COM port into a text file and 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?

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

EDIT: The data I want to read is the system boot output to a UEFI wrapper. Then, when it gets there, enter some commands and write the output of those commands. Then boot the OS (write down the boot output), enter some more commands into the Linux shell, and write their output. It does not contain the exact number of characters.

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

+3


source to share


2 answers


Playing around with a few different things with batch scripts leads me to the conclusion that nothing will work with batch script and standard Windows command line tools. set /P

returns immediately when reading from COM1

, and something like type COM1

will copy sequential data in large chunks line by line.

I've had luck with Cygwin bash. Here's a simple script that gets lines from COM1

and sends them back. It exits when it receives a line starting with "quit". You can test it with a terminal emulator on the other end of the serial link, or simply with assertions such as 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 variable CR

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

The line exec 4<> /dev/com1

is critical. This opens the COM port once for reading and writing. Windows only allows the COM port to be opened once, so if it wasn't done it would be impossible to read and write to the COM port. 4

means it is assigned to file descriptor 4 and the statement exec

keeps it open for the rest of the script.

The part is also important cat <&4 |

. Unfortunately, Cygwin bash seems to have a bug where it will try to rewind the file descriptor if it reads the end of the end of the line. This works for files, but not for serial ports, so data is lost. To work around this problem, the script reads from that pipe, which bash is smart enough not to try to rewind.



The reason for setting IFS="$CR"

is to disable carriage return at the end of the line, as mentioned earlier, and not erase anything while reading. The command read

uses an IFS string to split the input line into words. You can use this to your advantage and tune it to a different value to make it easier to parse the BIOS output.

The rest of the details are pretty straightforward. The option -r

for read

forces not to process characters \

specifically. Depending on which lines end up, your BIOS expects you to have three different ways to record your echoes:

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 fails to do is set COM port parameters such as baud rate and flow control. This is probably best done with a regular command MODE COM1

. Cygwin has an equivalent command stty

, but it doesn't seem to support all options.

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

+3


source


There is no standard way to read data from a serial port:

type COM1 > sample.txt

      

nor

copy COM1 sample.txt

      

It would be if this data had the standard EndOfFile character, like the Ctrl-Z character.

If this data comes in lines ending in CR + LF or only CR characters, then the standard way to read it is:

set /P "var=" < COM1

      

If this data does not have a delimiter, for example CR or CR + LF, then you must specify the exact format of such data:



  • Do you want to read records of a fixed number of characters?
  • Do you want to read characters until a certain one appears? Which one?
  • Can the input contain control characters? Which of them?
  • Any other input data format?

EDIT : Reply to comments

When the command set /P

is executed with redirected input, it does not wait for data. In this case, it returns immediately and the variable is not changed.

We can try to wait for the next character from the serial port and then execute the command set /P

; thus, set /P

must correctly read an input line terminated in CR or CR + LF that does not contain control characters.

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 cannot try to read input from COM1 on my computer.

0


source







All Articles