Search code examples
binaryporttransfer

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


I am trying to transfer a binary file over a serial port on a small embedded device that doesn't have uudecode, base64 or x/y/z/ modem utils.

What I tried for far is:

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

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

But that hangs my device.


Solution

  • Actually, what I can do is upload my own uudecode.sh in ascii mode and then I can use it to decode my own binary file!

    Here is the script that works on 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=$(($1 -32 & 63 ))
                shift
                while [ $l -gt 0 ] ; do
                    i0=$(($1 -32 & 63))
                    shift
                    i1=$(($1 -32 & 63))
                    shift
                    i2=$(($1 -32 & 63))
                    shift
                    i3=$(($1 -32 & 63))
                    shift
                    if [ $l -gt 2 ] ; then
                        echo -ne "\0$(($i0 >> 4))$(($i0 >> 1 & 7))$(($i0 << 2 & 4 | $i1 >> 4))\0$(($i1 >> 2 & 3))$(($i1 << 1 & 6 | $i2 >> 5))$(($i2 >> 2 & 7))\0$(($i2 & 3))$(($i3 >> 3 & 7))$(($i3 & 7))"
                        true
                    elif [ $l -eq 2 ] ; then
                        echo -ne "\0$(($i0 >> 4))$(($i0 >> 1 & 7))$(($i0 << 2 & 4 | $i1 >> 4))\0$(($i1 >> 2 & 3))$(($i1 << 1 & 6 | $i2 >> 5))$(($i2 >> 2 & 7))"
                        true
                    else
                        echo -ne "\0$(($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
    

    Then it can be used as such on the device:

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

    EDIT

    Apparently "printf" is not even present on my device but not to worry since there's an even faster script available in 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($0, 1, 1);
        if (cnt == "`") next;
        cnt = charval(cnt) - 32;
        enc = substr($0, 2, length($0) - 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;
        }
    }
    '