Chapter 10: FileData Transfer

The monitor now includes a flash file system, serial port communications, and Ethernet connectivity. The next natural step is to provide a mechanism that allows file transfer to and from the target. The file transfer protocols presented in this chapter are not new but remain popular because of their simplicity. The monitor uses Xmodem and TFTP for RS-232 and Ethernet implementations respectively. Data can be transferred as raw memory or as a file for both protocols. The MicroMonitor package includes code for a PC-based TFTP client/server and PC-based Xmodem transfer. I will limit this discussion to the target side. Complete implementation details are beyond the scope of this discussion. (Refer to the CD for a full source listing.)

Both Xmodem and TFTP are lock step protocols, meaning that when one end sends some data, it doesnt send any new data until it receives acknowledgment from the other end indicating that the data was received. Although this design slows things down a bit, especially with respect to TFTP, the lock step approach offers the benefit of simplicity.

Xmodem

I think Xmodem has been around since dirt. Xmodem is one of those things that just wont go away, which is good because Xmodem can be found just about anywhere and its not too difficult to implement. Xmodem has spawned many variants, including derivatives that support CRC versus checksum, 128- versus 1024-byte packets, and multiple files per transfer. I wont discuss these variants here, because my focus is MicroMonitors Xmodem support not the larger protocol. Keep in mind that MicroMonitor assumes that the target is communicating with the host via an error-free connection, so consequently the Xmodem implementation doesnt need to be very robust. The point of the discussion is to give you a feel for the Xmodem protocol as it is used in MicroMonitor and to let you experience a basic Xmodem implementation for a very blue sky environment.

This implementation of Xmodem is primarily based on two important functions: Xup() and Xdown(). These functions provide upload and download capability, respectively. Both functions use the same data structures to describe and track a transfer. Listing 10.1 shows the declaration for this structure.

Listing 10.1: The Xmodem Control Structure.
image from book
 struct xinfo {     uchar   sno;            /* Sequence number.                              */     uchar   pad;            /* Unused, padding.                              */     int     xfertot;        /* Running total of transfer.                    */     int     pktlen;         /* Length of packet (128 or 1024).               */     int     pktcnt;         /* Running tally of number of packets processed. */     int     filcnt;         /* Number of files transferred by ymodem.        */     long    size;           /* Size of upload.                               */     ulong   flags;          /* Storage for various runtime flags.            */     ulong   base;           /* Starting address for data transfer.           */     ulong   dataddr;        /* Running address for data transfer.            */     int     errcnt;         /* Keep track of errors (used in verify mode).   */     char    *firsterrat;    /* Pointer to location of error detected when    */                             /* transfer is in verify mode.                   */     char    fname[TFSNAMESIZE]; }; 
image from book
 

Regardless of whether the Xmodem transfer is an upload or a download, the transfer starts with a command at the MicroMonitor CLI. Once the command is issued, the Xmodem code waits for the other end (usually HyperTerminal in Windows) to connect and begin the actual transfer.

Listing 10.2 shows the Xup() function, which is called when the user requests a file transfer from the target to the host.

Listing 10.2: Xup().
image from book
 static int Xup(struct xinfo *xip) {     uchar   c, buf[PKTLEN_128];     int     done, pktlen;     long    actualsize;     Mtrace("Xup starting");     actualsize = xip->size;     if (xip->size & 0x7f) {         xip->size += 128;         xip->size &= 0xffffff80L;     }     printf("Upload %ld bytes from 0x%lx\n",xip->size,(ulong)xip->base);     /* Startup synchronization... */     /* Wait to receive a NAK or 'C' from receiver. */     done = 0;     while(!done) {         c = (uchar)getchar();         switch(c) {         case NAK:             done = 1;             Mtrace("CSM");             break;         case 'C':             xip->flags = USECRC;             done = 1;             Mtrace("CRC");             break;         default:             break;         }     }     done = 0;     xip->sno = 1;     xip->pktcnt = 0;     while(!done) {         c = (uchar)putPacket((uchar *)(xip->dataddr),xip);         switch(c) {         case ACK:             xip->sno++;             xip->pktcnt++;             xip->size -= xip->pktlen;             xip->dataddr += xip->pktlen;             Mtrace("A");             break;         case NAK:             Mtrace("N");             break;         case CAN:             done = -1;             Mtrace("C");             break;         case EOT:             done = -1;             Mtrace("E");             break;         default:             done = -1;             Mtrace("<%2x>",c);             break;         }         if (xip->size <= 0) {             rputchar(EOT);             getchar();  /* Flush the ACK */             break;         }         Mtrace("!");     }     Mtrace("Xup_done.");     return(0); } 
image from book
 
Note 

The Mtrace() function (see Listing 10.2) deserves a quick side note. The Xmodem code uses Mtrace() to help with debugging. The Xmodem protocol is using the same serial port as is usually used by printf() , so you cant add printf statements to debug the code because adding printf statements screws up the protocol. The Mtrace() (or memory trace) function looks like printf() , but, instead of the output going to the console, it goes to an internal RAM buffer so that after the protocol completes, you have the option to dump the contents of that buffer to see a trace log of what was happening. Mtrace() is a useful tool to have for any case where you are writing code in an area that does not allow printing through the serial port. Now back to Xup() .

Right off the bat this function must deal with an Xmodem yukism. The size of the transfer must be converted to a mod-128 size. The smallest packet size for Xmodem is 128 bytes, so if the actual transfer size is 129 bytes, Xmodem sends 256. After padding the data size, the function attempts to synchronize with the receiver by listening for the other end to connect. The program at the other end of the serial connection sends either a NAK (negative acknowledgement ) to initiate a transfer using checksums or the character C to initiate a transfer using CCITT CRC16. After this synchronization is finished, the packets begin to flow. This Xmodem implementation is about as simple as it can get. Function Xup() sends each packet and then waits for a response using the putPacket() function. The putPacket() function (not shown) sends the SOH (start of header) character, increments the sequence number by one, sends the sequence number and its complement, sends the packet data and checksum or CRC, then waits for the response, and returns to the calling Xup() function. If the response is a positive acknowledgment ( ACK ), then Xup() continues with the next packet. Otherwise, it quits. No retransmission, nothing fancy. If a transfer fails, then it is up to the user to try again.

Xdown()

The Xdown() function (see Listing 10.3) is called from the xmodem command when the user requests a file transfer from the host to target.

Listing 10.3: Xdown().
image from book
 /* Xdown():  * Called when a transfer from host to target is being made (considered  * a download).  */ static int Xdown(struct xinfo *xip) {     long    timeout;     char    c, tmppkt[PKTLEN_1K];     int     done;     xip->sno = 0x01;     xip->pktcnt = 0;     xip->errcnt = 0;     xip->xfertot = 0;     xip->firsterrat = 0;     /* Startup synchronization... */     /* Continuously send NAK or 'C' until sender responds. */     Mtrace("Xdown");     while(1) {         if (xip->flags & USECRC)             rputchar('C');         else             rputchar(NAK);         timeout = LoopsPerSecond;         while(!gotachar() && timeout)             timeout--;         if (timeout)             break;     }     done = 0;     Mtrace("Got response");     while(done == 0) {         c = (char)getchar();         switch(c) {         case SOH:               /* 128-byte incoming packet */             Mtrace("O");             xip->pktlen = PKTLEN_128;             done = getPacket(tmppkt,xip);             break;         case STX:               /* 1024-byte incoming packet */             Mtrace("T");             xip->pktlen = PKTLEN_1K;             done = getPacket(tmppkt,xip);             break;         case CAN:             Mtrace("C");             done = -1;             break;         case EOT:             Mtrace("E");             rputchar(ACK);             done = xip->xfertot;             printf("\nRcvd %d pkt%c (%d bytes)\n",xip->pktcnt,                 xip->pktcnt > 1 ? 's' : ' ',xip->xfertot);             break;         case ESC:       /* User-invoked abort */             Mtrace("X");             done = -1;             break;         default:             Mtrace("<%02x>",c);             done = -1;             break;         }         Mtrace("!");     }     if (xip->flags & VERIFY) {         if (xip->errcnt)             printf("%d errors, first at 0x%lx\n",                 xip->errcnt,(ulong)(xip->firsterrat));         else             printf("verification passed\n");     }     return(done); } 
image from book
 

If Xdown() looks similar to Xup() , that is because it is. Xdown() is just the other end of the protocol. At the top of Listing 10.3 is the synchronization step. This time this code is sending either the C or NAK (depending on how the transfer was configured) and then waiting for the response. Once the response is received, the packets once again begin to flow, but this time the packets flow in the other direction (into target memory). In this direction, packets are announced by either of two bytes: SOH and STX . SOH indicates an incoming packet of 128 bytes, and STX indicates a 1024-byte inbound packet. The getPacket() function (not shown) does the real work of pulling in the packets and sending a response character. (The getPacket() function is similar to putPacket() on the Xup() side.) After the sender has completed the transmission, the sender sends an end-of-transmission (EOT) character to indicate that the transfer is done. Receipt of the EOT character causes the loop to terminate, completing the transaction. A few other situations can abort the transfer, but these situations are the exception.

Notice the VERIFY flag check just after the loop. The VERIFY flag check is a useful option added to MicroMonitors Xmodem implementation. This option allows a host to download and verify (not overwrite, just compare) the downloaded data to data already resident on the target.

Xmodem in MicroMonitor

Xmodem gives MicroMonitor the ability to transfer files to and from the target. This file transfer can be to/from files or to/from raw memory in the target. The verification option mentioned above is useful for simple memory tests or to verify that code did not overwrite some block of data. The actual implementation of Xmodem in MicroMonitor supports most of the options, such as 128/1024-byte packets, checksum and CRC, Ymodem extensions, and so forth. Refer to the CD for more detail.

One last note on MicroMonitors Xmodem implementation. The boot monitor resides in boot flash memory and occasionally the boot flash memory might need to be updated. You could just use a programmer to burn a new device and install it; however, MicroMonitors Xmodem hooks up with the flash driver code to allow the user to download a binary image and automatically re-burn the monitor code on board. This feature is a nice convenience, especially when you are porting the monitor to a new target. After the serial port and flash drivers are in place, you can use Xmodem to make quick boot flash updates while you are working on other aspects of the monitor port.



Embedded Systems Firmware Demystified
Embedded Systems Firmware Demystified (With CD-ROM)
ISBN: 1578200997
EAN: 2147483647
Year: 2002
Pages: 118
Authors: Ed Sutter

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net