如何在没有 uudecode、base64 或 x/y/z/ 调制解调器的情况下通过串口传输二进制文件?

Howto transfer a binary file over serial port without uudecode, base64, or x/y/z/ modem?

我正在尝试通过没有 uudecode、base64 或 x/y/z/调制解调器实用程序的小型嵌入式设备上的串行端口传输二进制文件。

我目前尝试的是:

$ sudo picocom -l -r -b 921600 --send-cmd "ascii-xfr -snv" /dev/ttyS0
# cat > libdebug.so

$ cat libdebug.so | sudo tee /dev/ttyS0

但这会挂起我的设备。

实际上,我能做的就是以ascii模式上传我自己的uudecode.sh,然后我可以用它来解码我自己的二进制文件!

这是在 ksh 上运行的脚本:

#!/bin/ksh

# uudecode in POSIX bourne shell
#
# *EXCRUCIATINGLY* SLOW!!!
#
# Taken from a reply to a blog post here:
# http://www.weeklywhinge.com/?p=108
#
# Copyright (c) 2015, Rafael Kitover <rkitover@gmail.com>
# Modified in 2018, Philippe Bouchard <philippeb8@gmail.com>
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER ``AS IS'' AND ANY
# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

bs=0
while read -r t ; do
    if [ "$bs" -eq 1 ] ; then
        if [ "a$t" = "aend" ] ; then
            bs=2
        else
            set $(printf "%d " "'$(echo $t | cut -c1)" "'$(echo $t | cut -c2)" "'$(echo $t | cut -c3)" "'$(echo $t | cut -c4)" "'$(echo $t | cut -c5)" "'$(echo $t | cut -c6)" "'$(echo $t | cut -c7)" "'$(echo $t | cut -c8)" "'$(echo $t | cut -c9)" "'$(echo $t | cut -c10)" "'$(echo $t | cut -c11)" "'$(echo $t | cut -c12)" "'$(echo $t | cut -c13)" "'$(echo $t | cut -c14)" "'$(echo $t | cut -c15)" "'$(echo $t | cut -c16)" "'$(echo $t | cut -c17)" "'$(echo $t | cut -c18)" "'$(echo $t | cut -c19)" "'$(echo $t | cut -c20)" "'$(echo $t | cut -c21)" "'$(echo $t | cut -c22)" "'$(echo $t | cut -c23)" "'$(echo $t | cut -c24)" "'$(echo $t | cut -c25)" "'$(echo $t | cut -c26)" "'$(echo $t | cut -c27)" "'$(echo $t | cut -c28)" "'$(echo $t | cut -c29)" "'$(echo $t | cut -c30)" "'$(echo $t | cut -c31)" "'$(echo $t | cut -c32)" "'$(echo $t | cut -c33)" "'$(echo $t | cut -c34)" "'$(echo $t | cut -c35)" "'$(echo $t | cut -c36)" "'$(echo $t | cut -c37)" "'$(echo $t | cut -c38)" "'$(echo $t | cut -c39)" "'$(echo $t | cut -c40)" "'$(echo $t | cut -c41)" "'$(echo $t | cut -c42)" "'$(echo $t | cut -c43)" "'$(echo $t | cut -c44)" "'$(echo $t | cut -c45)" "'$(echo $t | cut -c46)" "'$(echo $t | cut -c47)" "'$(echo $t | cut -c48)" "'$(echo $t | cut -c49)" "'$(echo $t | cut -c50)" "'$(echo $t | cut -c51)" "'$(echo $t | cut -c52)" "'$(echo $t | cut -c53)" "'$(echo $t | cut -c54)" "'$(echo $t | cut -c55)" "'$(echo $t | cut -c56)" "'$(echo $t | cut -c57)" "'$(echo $t | cut -c58)" "'$(echo $t | cut -c59)" "'$(echo $t | cut -c60)" "'$(echo $t | cut -c61)")
            l=$(( -32 & 63 ))
            shift
            while [ $l -gt 0 ] ; do
                i0=$(( -32 & 63))
                shift
                i1=$(( -32 & 63))
                shift
                i2=$(( -32 & 63))
                shift
                i3=$(( -32 & 63))
                shift
                if [ $l -gt 2 ] ; then
                    echo -ne "[=10=]$(($i0 >> 4))$(($i0 >> 1 & 7))$(($i0 << 2 & 4 | $i1 >> 4))[=10=]$(($i1 >> 2 & 3))$(($i1 << 1 & 6 | $i2 >> 5))$(($i2 >> 2 & 7))[=10=]$(($i2 & 3))$(($i3 >> 3 & 7))$(($i3 & 7))"
                    true
                elif [ $l -eq 2 ] ; then
                    echo -ne "[=10=]$(($i0 >> 4))$(($i0 >> 1 & 7))$(($i0 << 2 & 4 | $i1 >> 4))[=10=]$(($i1 >> 2 & 3))$(($i1 << 1 & 6 | $i2 >> 5))$(($i2 >> 2 & 7))"
                    true
                else
                    echo -ne "[=10=]$(($i0 >> 4))$(($i0 >> 1 & 7))$(($i0 << 2 & 4 | $i1 >> 4))"
                    true
                fi
                l=$(($l-3))
            done
        fi
    elif [ $(echo $t | cut -c1-5) = "begin" ]; then
        bs=1
    fi
done

然后就可以在设备上这样使用了:

# uudecode.sh < libdebug.so.uu > libdebug.so

编辑

显然 "printf" 甚至没有出现在我的设备上,但不用担心,因为 awk 中有一个更快的脚本可用:

#!/bin/sh

# uudecode in GNU awk (and some others, like OpenBSD) decodes stdin to stdout
#
# Copyright (c) 2014, Rafael Kitover <rkitover@gmail.com>
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER ``AS IS'' AND ANY
# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

awk=awk

if command -v gawk >/dev/null; then
    awk=gawk
fi

$awk '
BEGIN {
    charset=" !\"#$%&'\''()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_";
}
function charval(char) {
    return index(charset, char) + 32 - 1;
}
/^begin / { next }
/^end$/   { exit }
{
    cnt = substr([=12=], 1, 1);
    if (cnt == "`") next;
    cnt = charval(cnt) - 32;
    enc = substr([=12=], 2, length([=12=]) - 1);
    chars = 0;
    pos   = 1;
    while (chars < cnt) {
        grp = substr(enc, pos, 4);
        gsub(/`/, " ", grp); # zero bytes
        c1 = charval(substr(grp, 1, 1)) - 32;
        c2 = charval(substr(grp, 2, 1)) - 32;
        c3 = charval(substr(grp, 3, 1)) - 32;
        c4 = charval(substr(grp, 4, 1)) - 32;
        chars_bits = or(c4, or(or(lshift(c3, 6), lshift(c2, 12)), lshift(c1, 18)));
        char[1] = sprintf("%c", rshift(and(chars_bits, 16711680), 16));
        char[2] = sprintf("%c", rshift(and(chars_bits, 65280),     8));
        char[3] = sprintf("%c", and(chars_bits, 255));
        for (i = 1; i <= 3 && chars < cnt; i++) {
            printf("%s", char[i]);
            chars++;
        }
        pos += 4;
    }
}
'