Batch script to read/write data using COM port

后端 未结 2 1430
长情又很酷
长情又很酷 2021-01-06 16:34

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

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

echo hello &         


        
相关标签:
2条回答
  • 2021-01-06 16:55

    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 /P returns immediately when reading from COM1, and something like type COM1 will copy the serial data in large chunks line by line.

    I had better luck using Cygwin bash. Here's a simple script that receives lines from COM1 and 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.

    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 CR variable 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.

    The exec 4<> /dev/com1 line 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 4 means that is assigned to file descriptor 4 and the exec statement keeps it open for the rest of the script.

    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.

    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 read command 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.

    The rest of the details are pretty straightforward. The -r option for read causes 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:

    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 COM1 command. Cygwin has an equivalent stty command, but it doesn't appear to support all the parameters.

    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.

    0 讨论(0)
  • 2021-01-06 16:55

    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.

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

    set /P "var=" < COM1
    

    If that data have not a delimiter, like 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 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 /P command is executed with redirected input, it does not wait for data. In this case, it returns immediately and the variable is not changed.

    We may try to wait for the next character received from the serial port and then execute the set /P command; this way, the set /P should 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 can not try input read from COM1 in my computer.

    0 讨论(0)
提交回复
热议问题