Sending a file via serial port

What is the recommended way of sending a file to a device via the serial port?

I've read various posts which mention things like screen, cu, minicom etc but would be interested to hear anyone's opinion on this forum.
 
It depends. There is no one size fits all answer. It depends on the type of data and the preipheral device where it's being received.
 
I haven't done this for a while but if I was connected over a serial TTY then I'd use the (X|Y|Z)modem protocol - see the comms/lrzsz port.
 
I haven't done this for a while but if I was connected over a serial TTY then I'd use the (X|Y|Z)modem protocol
This will only work if the other end is capable of receiving it. And this depends on the capabilities of the firmware of the device.
 
I'd suggest backing up a bit. If you can boot over ethernet then I'd suggest that instead: bootp/dhcp.
 
The GoFlex Home has a firmware recovery mechanism built into the bootloader.

Firmware can be loaded onto a FAT32 formatted USB stick and inserted into the rear USB host port.

The hard disk should be removed from the dock, otherwise the hard disk may come up as /dev/sda rather than the USB stick and prevent the *.ubi file being found.

Hold the reset pin while power is applied. The yellow light will blink immediately followed by the white LED. At this stage uBoot will have entered the USB firmware installation mode and you can release the reset pin.

Source and further details: https://wiki.beyondlogic.org/index.php/Seagate_FreeAgent_GoFlex_Home_Firmare_Recovery
 
The GoFlex Home has a firmware recovery mechanism built into the bootloader.

Thanks, I am aware of this, but my aim is to boot using a different u-Boot rather than the original firmware. This is normally done by sending a new u-Boot over the serial port using a program called kwboot, which works fine on Linux, but I can't get a FreeBSD compiled version to work. That's why I'm looking for an alternative means of sending the file.
 
It sounds like kwboot does a little more than just sending the file:
Following power-up or a system reset, system BootROM code polls the UART for a brief period of time, sensing a handshake message which initiates an image upload. This
sends this boot message until it receives a positive acknowledgement. The image is transferred using Xmodem.
So if you can't get kwboot to work it sounds like you'll need to figure out this initial interaction first by looking at kwboot's source. I think you can invoke lsx from cu using ~C, or Minicom can do it too once its set up.
 
It sounds like kwboot does a little more than just sending the file:

So if you can't get kwboot to work it sounds like you'll need to figure out this initial interaction first by looking at kwboot's source. I think you can invoke lsx from cu using ~C, or Minicom can do it too once its set up.

Looking at the man page for kwboot it does, as you say, sense a handshake message, which I hadn't noticed before....

I've spent quite a while looking at the source code, but it looks like gobbledegook to me. I guess I need to focus on this 'handshake message' if only I can find it...
 
Many thanks, I'll give it a try...

kwboot.c seems portable - I just can't get it to work :(

.......

Just tried it and got...

unable to open '/dev/cuaU0': m

cu has no problem openning the port. Will have to delve into the code....

After further attempts.... I get...

Sending file..../
Finishing... failed
 
This is the function I can't get to work...
Code:
xmodem_send(int tty_fd, int in_fd)
{
    unsigned char packet[134];
    static const int buflen = 128;
    int packetno, lastpacket;
    int c;
    int retry;
    int res;

    printf("Sending file...");

    /* We have already received a NAK, but wait for another to be sure */
    if (wait_for_nak(tty_fd) == -1)
    return -1;

    lastpacket = 0;
    packetno   = 1;
    for (retry = 0; retry < MAX_RETRANS; ++retry) {
    rotator();

    if (packetno != lastpacket) {
        res = build_packet(in_fd, packetno, packet, buflen);
        if (res == -1) return -1;
        if (res ==  1) break;
        lastpacket = packetno;
    }
    else
        printf("*%d*.", retry);

    c = send_packet(tty_fd, packet, buflen + 4);
    if (c == -1) {
        if (errno == ETIMEDOUT)
        continue; /* retry if timed out */

        fprintf(stderr,
            "%s: error writing to serial port: %m\n", argv0);
        break;
    }

    switch (c) {
        case ACK:
        retry = 0;
        ++packetno;
        break;
        case CAN:
        printf("cancelled by remote\n");
        if ((c = read_byte(tty_fd, 1)) == CAN) {
            write_byte(tty_fd, ACK);
            tcdrain(tty_fd);
            return -1;
        }
        break;
        default:
        printf("unexpected character %02x\n", c);
        case NAK:
        break;
    }
    }
    if (retry == MAX_RETRANS) {
    fprintf(stderr, "Too many retries, cancelling send\n");
    cancel_send(tty_fd);
    return -1; /* xmit error */
    }

    printf("\nFinishing...");
    for (retry = 0; retry < MAX_RETRANS; ++retry) {
        write_byte(tty_fd, EOT);
        tcdrain(tty_fd);
        if ((c = read_byte(tty_fd, 1)) == ACK)
        break;
    }

    if (c != ACK) {
    puts("failed\n");
    return -1;
    }
    puts("done\n");
    return 0;
}


How do I figure out why it prints 'failed' ?
 
After transferring the data, it sends an End Of Transmission (EOT) byte, and expect an ACKnowlegement in return. After retrying this a few times, it gives up and assumes it has failed.
Earlier on in the code it sends the handshake message before calling this. You could either manually push the handshake then run the Xmodem send from a script, or modify this to run the Xmodem transfer as a child process (using system()). Or add some debugging in to this to see what it is giving you back.
 
Do you mean ignoring the check for an ACK like this?
C:
/*
if (c != ACK) {
    puts("failed\n");
    return -1;
    }
    */

I'm not much of a coder so don't know how to run Xmodem using system() although I suspect it is only a few lines code...
 
Back
Top