Subversion Repositories HomeAutomation

Rev

Rev 363 | Blame | Compare with Previous | Last modification | View Log | SVN | RSS feed

  1. /*********************************************************************
  2.  *
  3.  *                  TFTP Client module for Microchip TCP/IP Stack
  4.  *
  5.  *********************************************************************
  6.  * FileName:        TFTPc.c
  7.  * Dependencies:    TFTPc.h
  8.  *                  UDP.h
  9.  * Processor:       PIC18
  10.  * Complier:        MCC18 v1.00.50 or higher
  11.  *                  HITECH PICC-18 V8.10PL1 or higher
  12.  * Company:         Microchip Technology, Inc.
  13.  *
  14.  * Software License Agreement
  15.  *
  16.  * The software supplied herewith by Microchip Technology Incorporated
  17.  * (the “Company”) for its PICmicro® Microcontroller is intended and
  18.  * supplied to you, the Company’s customer, for use solely and
  19.  * exclusively on Microchip PICmicro Microcontroller products. The
  20.  * software is owned by the Company and/or its supplier, and is
  21.  * protected under applicable copyright laws. All rights are reserved.
  22.  * Any use in violation of the foregoing restrictions may subject the
  23.  * user to criminal sanctions under applicable laws, as well as to
  24.  * civil liability for the breach of the terms and conditions of this
  25.  * license.
  26.  *
  27.  * THIS SOFTWARE IS PROVIDED IN AN “AS IS” CONDITION. NO WARRANTIES,
  28.  * WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT NOT LIMITED
  29.  * TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
  30.  * PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. THE COMPANY SHALL NOT,
  31.  * IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL OR
  32.  * CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER.
  33.  *
  34.  * Author               Date    Comment
  35.  *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  36.  * Nilesh Rajbharti     8/5/03  Original        (Rev 1.0)
  37.  ********************************************************************/
  38. #if defined(WIN32)
  39.     #include <stdio.h>
  40.     #define TFTP_DEBUG
  41. #endif
  42.  
  43. #include "..\Include\tftpc.h"
  44. #include "..\Include\arptsk.h"
  45. #include "..\Include\tick.h"
  46.  
  47. #if !defined(STACK_USE_TFTP_CLIENT)
  48.     #error TFTP Client module is not enabled.
  49.     #error If you do not want TFTP Client module, remove this file from your
  50.     #error project to reduce your code size.
  51.     #error If you do want TFTP Client module, make sure that STACK_USE_TFTP_CLIENT
  52.     #error is defined in StackTsk.h file.
  53. #endif
  54.  
  55.  
  56. #define TFTP_CLIENT_PORT        65352L       // Some unique port on this
  57.                                             // device.
  58. #define TFTP_SERVER_PORT        (69L)
  59. #define TFTP_BLOCK_SIZE         (0x200L)     // 512 bytes
  60. #define TFTP_BLOCK_SIZE_MSB     (0x02)
  61.  
  62. typedef enum _TFTP_STATE
  63. {
  64.     SM_TFTP_WAIT = 0,
  65.     SM_TFTP_READY,
  66.     SM_TFTP_WAIT_FOR_DATA,
  67.     SM_TFTP_WAIT_FOR_ACK,
  68.     SM_TFTP_DUPLICATE_ACK,
  69.     SM_TFTP_SEND_ACK,
  70.     SM_TFTP_SEND_LAST_ACK
  71. } TFTP_STATE;
  72.  
  73. typedef enum _TFTP_OPCODE
  74. {
  75.     TFTP_OPCODE_RRQ = 1,         // Get
  76.     TFTP_OPCODE_WRQ,            // Put
  77.     TFTP_OPCODE_DATA,           // Actual data
  78.     TFTP_OPCODE_ACK,            // Ack for Get/Put
  79.     TFTP_OPCODE_ERROR           // Error
  80. } TFTP_OPCODE;
  81.  
  82.  
  83.  
  84. UDP_SOCKET _tftpSocket;         // TFTP Socket for TFTP server link
  85. WORD _tftpError;
  86.  
  87. static union _MutExVar
  88. {
  89.     struct
  90.     {
  91.         NODE_INFO _hostInfo;
  92.     } group1;
  93.  
  94.     struct
  95.     {
  96.         WORD_VAL _tftpBlockNumber;
  97.         WORD_VAL _tftpDuplicateBlock;
  98.         WORD_VAL _tftpBlockLength;
  99.     } group2;
  100. } MutExVar;     // Mutually Exclusive variable groups to conserve RAM.
  101.  
  102.  
  103. static TFTP_STATE _tftpState;
  104. static BYTE _tftpRetries;
  105. static TICK _tftpStartTick;
  106. static union
  107. {
  108.     struct
  109.     {
  110.         unsigned int bIsFlushed : 1;
  111.         unsigned int bIsAcked : 1;
  112.         unsigned int bIsClosed : 1;
  113.         unsigned int bIsClosing : 1;
  114.         unsigned int bIsReading : 1;
  115.     } bits;
  116.     BYTE Val;
  117. } _tftpFlags;
  118.  
  119.  
  120. // Private helper functions
  121. static void _TFTPSendFileName(TFTP_OPCODE command, char *fileName);
  122. static void _TFTPSendAck(WORD_VAL blockNumber);
  123.  
  124. // Blank out DEBUG statements if not enabled.
  125. #if defined(TFTP_DEBUG)
  126.     #define DEBUG(a)        a
  127. #else
  128.     #define DEBUG(a)
  129. #endif
  130.  
  131.  
  132. /*********************************************************************
  133.  * Function:        void TFTPOpen(IP_ADDR *host)
  134.  *
  135.  * PreCondition:    UDP module is already initialized
  136.  *                  and at least one UDP socket is available.
  137.  *
  138.  * Input:           host        - IP address of remote TFTP server
  139.  *
  140.  * Output:          None
  141.  *
  142.  * Side Effects:    None
  143.  *
  144.  * Overview:        Initiates ARP for given host and prepares
  145.  *                  TFTP module for next sequence of function calls.
  146.  *
  147.  * Note:            Use TFTPIsOpened() to check if a connection was
  148.  *                  successfully opened or not.
  149.  *
  150.  ********************************************************************/
  151. void TFTPOpen(IP_ADDR *host)
  152. {
  153.     DEBUG(printf("Opening a connection..."));
  154.  
  155.     // Remember this address locally.
  156.     MutExVar.group1._hostInfo.IPAddr.Val = host->Val;
  157.  
  158.     // Initiate ARP resolution.
  159.     ARPResolve(&MutExVar.group1._hostInfo.IPAddr);
  160.  
  161.     // Wait for ARP to get resolved.
  162.     _tftpState = SM_TFTP_WAIT;
  163.  
  164.     // Mark this as start tick to detect timeout condition.
  165.     _tftpStartTick = TickGet();
  166.  
  167.     // Forget about all previous attempts.
  168.     _tftpRetries = 1;
  169.  
  170. }
  171.  
  172.  
  173.  
  174. /*********************************************************************
  175.  * Function:        TFTP_RESULT TFTPIsOpened(void)
  176.  *
  177.  * PreCondition:    TFTPOpen() is already called.
  178.  *
  179.  * Input:           None
  180.  *
  181.  * Output:          TFTP_OK if previous call to TFTPOpen is complete
  182.  *
  183.  *                  TFTP_TIMEOUT if remote host did not respond to
  184.  *                          previous ARP request.
  185.  *
  186.  *                  TFTP_NOT_READY if remote has still not responded
  187.  *                          and timeout has not expired.
  188.  *
  189.  * Side Effects:    None
  190.  *
  191.  * Overview:        Waits for ARP reply and opens a UDP socket
  192.  *                  to perform further TFTP operations.
  193.  *
  194.  * Note:            Once opened, application may keep TFTP socket
  195.  *                  open and future TFTP operations.
  196.  *                  If TFTPClose() is called to close the connection
  197.  *                  TFTPOpen() must be called again before performing
  198.  *                  any other TFTP operations.
  199.  ********************************************************************/
  200. TFTP_RESULT TFTPIsOpened(void)
  201. {
  202.     switch(_tftpState)
  203.     {
  204.     default:
  205.         DEBUG(printf("Resolving remote IP...\n"));
  206.  
  207.         // Check to see if adddress is resolved.
  208.         if ( ARPIsResolved(&MutExVar.group1._hostInfo.IPAddr,
  209.                            &MutExVar.group1._hostInfo.MACAddr) )
  210.         {
  211.             _tftpSocket = UDPOpen(TFTP_CLIENT_PORT,
  212.                                   &MutExVar.group1._hostInfo,
  213.                                   TFTP_SERVER_PORT);
  214.             _tftpState = SM_TFTP_READY;
  215.         }
  216.         else
  217.             break;
  218.  
  219.     case SM_TFTP_READY:
  220.         // Wait for UDP to be ready.  Immediately after this user will
  221.         // may TFTPGetFile or TFTPPutFile and we have to make sure that
  222.         // UDP is read to transmit.  These functions do not check for
  223.         // UDP to get ready.
  224.         if ( UDPIsPutReady(_tftpSocket) )
  225.             return TFTP_OK;
  226.     }
  227.  
  228.     // Make sure that we do not do this forever.
  229.     if ( TickGetDiff(TickGet(), _tftpStartTick) >= TFTP_ARP_TIMEOUT_VAL )
  230.     {
  231.         _tftpStartTick = TickGet();
  232.  
  233.         // Forget about all previous attempts.
  234.         _tftpRetries = 1;
  235.  
  236.         return TFTP_TIMEOUT;
  237.     }
  238.  
  239.     return TFTP_NOT_READY;
  240. }
  241.  
  242.  
  243.  
  244. /*********************************************************************
  245.  * Function:        void TFTPOpenFile(char *fileName,
  246.  *                                    TFTP_FILE_MODE mode)
  247.  *
  248.  * PreCondition:    TFPTIsFileOpenReady() = TRUE
  249.  *
  250.  * Input:           fileName        - File name that is to be opened.
  251.  *                  mode            - Mode of file access
  252.  *                                    Must be
  253.  *                                      TFTP_FILE_MODE_READ for read
  254.  *                                      TFTP_FILE_MODE_WRITE for write
  255.  *
  256.  * Output:          None
  257.  *
  258.  * Side Effects:    None
  259.  *
  260.  * Overview:        Prepares and sends TFTP file name and mode packet.
  261.  *
  262.  * Note:            By default, this funciton uses "octet" or binary
  263.  *                  mode of file transfer.
  264.  *                  Use TFTPIsFileOpened() to check if file is
  265.  *                  ready to be read or written.
  266.  ********************************************************************/
  267. void TFTPOpenFile(char *fileName, TFTP_FILE_MODE mode)
  268. {
  269.     DEBUG(printf("Opening file...\n"));
  270.  
  271.     // Set TFTP Server port.  If this is the first call, remotePort
  272.     // must have been set by TFTPOpen().  But if caller does not do
  273.     // TFTPOpen for every transfer, we must reset remote port.
  274.     // Most TFTP servers accept connection TFTP port. but once
  275.     // connection is established, they use other temp. port,
  276.     UDPSocketInfo[_tftpSocket].remotePort = TFTP_SERVER_PORT;
  277.  
  278.     // Tell remote server about our intention.
  279.     _TFTPSendFileName(mode, fileName);
  280.  
  281.     // Clear all flags.
  282.     _tftpFlags.Val = 0;
  283.  
  284.     // Remember start tick for this operation.
  285.     _tftpStartTick = TickGet();
  286.  
  287.     // Depending on mode of operation, remote server will respond with
  288.     // specific block number.
  289.     if ( mode == TFTP_FILE_MODE_READ )
  290.     {
  291.         // Remember that we are reading a file.
  292.         _tftpFlags.bits.bIsReading = TRUE;
  293.  
  294.  
  295.         // For read operation, server would respond with data block of 1.
  296.         MutExVar.group2._tftpBlockNumber.Val = 1;
  297.  
  298.         // Next packet would be the data packet.
  299.         _tftpState = SM_TFTP_WAIT_FOR_DATA;
  300.     }
  301.  
  302.     else
  303.     {
  304.         // Remember that we are writing a file.
  305.         _tftpFlags.bits.bIsReading = FALSE;
  306.  
  307.         // For write operation, server would respond with data block of 0.
  308.         MutExVar.group2._tftpBlockNumber.Val = 0;
  309.  
  310.         // Next packet would be the ACK packet.
  311.         _tftpState = SM_TFTP_WAIT_FOR_ACK;
  312.     }
  313.  
  314.  
  315. }
  316.  
  317.  
  318.  
  319.  
  320. /*********************************************************************
  321.  * Function:        TFTP_RESULT TFTPIsFileOpened(void)
  322.  *
  323.  * PreCondition:    TFTPOpenFile() is called.
  324.  *
  325.  * Input:           None
  326.  *
  327.  * Output:          TFTP_OK if file is ready to be read or written
  328.  *
  329.  *                  TFTP_RETRY if previous attempt was timed out
  330.  *                  needs to be retried.
  331.  *
  332.  *                  TFTP_TIMEOUT if all attempts were exhausted.
  333.  *
  334.  *                  TFTP_NOT_ERROR if remote server responded with
  335.  *                  error
  336.  *
  337.  *                  TFTP_NOT_READY if file is not yet opened.
  338.  *
  339.  * Side Effects:    None
  340.  *
  341.  * Overview:        Waits for remote server response regarding
  342.  *                  previous attempt to open file.
  343.  *                  If no response is received within specified
  344.  *                  timeout, fnction returns with TFTP_RETRY
  345.  *                  and application logic must issue another
  346.  *                  TFTPFileOpen().
  347.  *
  348.  * Note:            None
  349.  ********************************************************************/
  350. TFTP_RESULT TFTPIsFileOpened(void)
  351. {
  352.     if ( _tftpFlags.bits.bIsReading )
  353.         return TFTPIsGetReady();
  354.  
  355.     else
  356.         return TFTPIsPutReady();
  357. }
  358.  
  359.  
  360.  
  361.  
  362. /*********************************************************************
  363.  * Function:        TFTP_RESULT TFTPIsGetReady(void)
  364.  *
  365.  * PreCondition:    TFTPOpenFile() is called with TFTP_FILE_MODE_READ
  366.  *                  and TFTPIsFileOpened() returned with TRUE.
  367.  *
  368.  * Input:           None
  369.  *
  370.  * Output:          TFTP_OK if it there is more data byte available
  371.  *                  to read
  372.  *
  373.  *                  TFTP_TIMEOUT if timeout occurred waiting for
  374.  *                  new data.
  375.  *
  376.  *                  TFTP_END_OF_FILE if end of file has reached.
  377.  *
  378.  *                  TFTP_ERROR if remote server returned ERROR.
  379.  *                      Actual error code may be read by calling
  380.  *                      TFTPGetError()
  381.  *
  382.  *                  TFTP_NOT_READY if still waiting for new data.
  383.  *
  384.  * Side Effects:    None
  385.  *
  386.  * Overview:        Waits for data block.  If data block does not
  387.  *                  arrive within specified timeout, it automatically
  388.  *                  sends out ack for previous block to remind
  389.  *                  server to send next data block.
  390.  *                  If all attempts are exhausted, it returns with
  391.  *                  TFTP_TIMEOUT.
  392.  *
  393.  * Note:            By default, this funciton uses "octet" or binary
  394.  *                  mode of file transfer.
  395.  ********************************************************************/
  396. TFTP_RESULT TFTPIsGetReady(void)
  397. {
  398.     WORD_VAL opCode;
  399.     WORD_VAL blockNumber;
  400.     BOOL bTimeOut;
  401.  
  402.  
  403.     // Check to see if timeout has occurred.
  404.     bTimeOut = FALSE;
  405.     if ( TickGetDiff(TickGet(), _tftpStartTick) >= TFTP_GET_TIMEOUT_VAL )
  406.     {
  407.         bTimeOut = TRUE;
  408.         _tftpStartTick = TickGet();
  409.     }
  410.  
  411.  
  412.     switch(_tftpState)
  413.     {
  414.     case SM_TFTP_WAIT_FOR_DATA:
  415.         // If timeout occurs in this state, it may be because, we have not
  416.         // even received very first data block or some in between block.
  417.         if ( bTimeOut == TRUE )
  418.         {
  419.             bTimeOut = FALSE;
  420.  
  421.             if ( _tftpRetries++ > (TFTP_MAX_RETRIES-1) )
  422.             {
  423.                 DEBUG(printf("TFTPIsGetReady(): Timeout.\n"));
  424.  
  425.                 // Forget about all previous attempts.
  426.                 _tftpRetries = 1;
  427.  
  428.                 return TFTP_TIMEOUT;
  429.             }
  430.  
  431.             // If we have not even received first block, ask application
  432.             // retry.
  433.             if ( MutExVar.group2._tftpBlockNumber.Val == 1 )
  434.             {
  435.                 DEBUG(printf("TFTPIsGetReady(): TFTPOpen Retry.\n"));
  436.                 return TFTP_RETRY;
  437.             }
  438.             else
  439.             {
  440.                 DEBUG(printf("TFTPIsGetReady(): ACK Retry #%d...,\n", _tftpRetries));
  441.  
  442.                 // Block number was already incremented in last ACK attempt,
  443.                 // so decrement it.
  444.                 MutExVar.group2._tftpBlockNumber.Val--;
  445.  
  446.                 // Do it.
  447.                 _tftpState = SM_TFTP_SEND_ACK;
  448.                 break;
  449.             }
  450.         }
  451.  
  452.         // For Read operation, server will respond with data block.
  453.         if ( !UDPIsGetReady(_tftpSocket) )
  454.             break;
  455.  
  456.         // Get opCode
  457.         UDPGet(&opCode.byte.MSB);
  458.         UDPGet(&opCode.byte.LSB);
  459.  
  460.         // Get block number.
  461.         UDPGet(&blockNumber.byte.MSB);
  462.         UDPGet(&blockNumber.byte.LSB);
  463.  
  464.         // In order to read file, this must be data with block number of 0.
  465.         if ( opCode.Val == TFTP_OPCODE_DATA )
  466.         {
  467.             // Make sure that this is not a duplicate block.
  468.             if ( MutExVar.group2._tftpBlockNumber.Val == blockNumber.Val )
  469.             {
  470.                 // Mark that we have not acked this block.
  471.                 _tftpFlags.bits.bIsAcked = FALSE;
  472.  
  473.                 // Since we have a packet, forget about previous retry count.
  474.                 _tftpRetries = 1;
  475.  
  476.                 _tftpState = SM_TFTP_READY;
  477.                 return TFTP_OK;
  478.             }
  479.  
  480.             // If received block has already been received, simply ack it
  481.             // so that Server can "get over" it and send next block.
  482.             else if ( MutExVar.group2._tftpBlockNumber.Val > blockNumber.Val )
  483.             {
  484.                 DEBUG(printf("TFTPIsGetReady(): "\
  485.                             "Duplicate block %d received - droping it...\n", \
  486.                             blockNumber.Val));
  487.                 MutExVar.group2._tftpDuplicateBlock.Val = blockNumber.Val;
  488.                 _tftpState = SM_TFTP_DUPLICATE_ACK;
  489.             }
  490. #if defined(TFTP_DEBUG)
  491.             else
  492.             {
  493.                 DEBUG(printf("TFTPIsGetReady(): "\
  494.                              "Unexpected block %d received - droping it...\n", \
  495.                              blockNumber.Val));
  496.             }
  497. #endif
  498.         }
  499.         // Discard all unexpected and error blocks.
  500.         UDPDiscard();
  501.  
  502.         // If this was an error, remember error code for later delivery.
  503.         if ( opCode.Val == TFTP_OPCODE_ERROR )
  504.         {
  505.             _tftpError = blockNumber.Val;
  506.             return TFTP_ERROR;
  507.         }
  508.  
  509.         break;
  510.  
  511.     case SM_TFTP_DUPLICATE_ACK:
  512.         if ( UDPIsPutReady(_tftpSocket) )
  513.         {
  514.             _TFTPSendAck(MutExVar.group2._tftpDuplicateBlock);
  515.             _tftpState = SM_TFTP_WAIT_FOR_DATA;
  516.         }
  517.         break;
  518.  
  519.     case SM_TFTP_READY:
  520.         if ( UDPIsGetReady(_tftpSocket) )
  521.         {
  522.             _tftpStartTick = TickGet();
  523.             return TFTP_OK;
  524.         }
  525.  
  526.         // End of file is reached when data block is less than 512 bytes long.
  527.         // To reduce code, only MSB compared against 0x02 (of 0x200 = 512) to
  528.         // determine if block is less than 512 bytes long or not.
  529.         else if ( MutExVar.group2._tftpBlockLength.Val == 0 ||
  530.                   MutExVar.group2._tftpBlockLength.byte.MSB < TFTP_BLOCK_SIZE_MSB )
  531.             _tftpState = SM_TFTP_SEND_LAST_ACK;
  532.         else
  533.             break;
  534.  
  535.  
  536.     case SM_TFTP_SEND_LAST_ACK:
  537.     case SM_TFTP_SEND_ACK:
  538.         if ( UDPIsPutReady(_tftpSocket) )
  539.         {
  540.             _TFTPSendAck(MutExVar.group2._tftpBlockNumber);
  541.  
  542.             // This is the next block we are expecting.
  543.             MutExVar.group2._tftpBlockNumber.Val++;
  544.  
  545.             // Remember that we have already acked current block.
  546.             _tftpFlags.bits.bIsAcked = TRUE;
  547.  
  548.             if ( _tftpState == SM_TFTP_SEND_LAST_ACK )
  549.                 return TFTP_END_OF_FILE;
  550.  
  551.             _tftpState = SM_TFTP_WAIT_FOR_DATA;
  552.         }
  553.         break;
  554.     }
  555.  
  556.  
  557.  
  558.     return TFTP_NOT_READY;
  559. }
  560.  
  561.  
  562.  
  563. /*********************************************************************
  564.  * Function:        BYTE TFTPGet(void)
  565.  *
  566.  * PreCondition:    TFTPOpenFile() is called with TFTP_FILE_MODE_READ
  567.  *                  and TFTPIsGetReady() = TRUE
  568.  *
  569.  * Input:           None
  570.  *
  571.  * Output:          data byte as received from remote server.
  572.  *
  573.  * Side Effects:    None
  574.  *
  575.  * Overview:        Fetches next data byte from TFTP socket.
  576.  *                  If end of data block is reached, it issues
  577.  *                  ack to server so that next data block can be
  578.  *                  received.
  579.  *
  580.  * Note:            Use this function to read file from server.
  581.  ********************************************************************/
  582. BYTE TFTPGet(void)
  583. {
  584.     BYTE v;
  585.  
  586.     // Read byte from UDP
  587.     UDPGet(&v);
  588.  
  589.     // Update block length
  590.     MutExVar.group2._tftpBlockLength.Val++;
  591.  
  592.     // Check to see if entire data block is fetched.
  593.     // To reduce code, MSB is compared for 0x02 (of 0x200 = 512).
  594.     if ( MutExVar.group2._tftpBlockLength.byte.MSB == TFTP_BLOCK_SIZE_MSB )
  595.     {
  596.         // Entire block was fetched.  Discard everything else.
  597.         UDPDiscard();
  598.  
  599.         // Remember that we have flushed this block.
  600.         _tftpFlags.bits.bIsFlushed = TRUE;
  601.  
  602.         // Reset block length.
  603.         MutExVar.group2._tftpBlockLength.Val = 0;
  604.  
  605.         // Must send ACK to receive next block.
  606.         _tftpState = SM_TFTP_SEND_ACK;
  607.     }
  608.  
  609.     return v;
  610. }
  611.  
  612.  
  613.  
  614.  
  615. /*********************************************************************
  616.  * Function:        void TFTPCloseFile(void)
  617.  *
  618.  * PreCondition:    TFTPOpenFile() was called and TFTPIsFileOpened()
  619.  *                  had returned with TFTP_OK.
  620.  *
  621.  * Input:           None
  622.  *
  623.  * Output:          None
  624.  *
  625.  * Side Effects:    None
  626.  *
  627.  * Overview:        If file is opened in read mode, it makes sure
  628.  *                  that last ACK is sent to server
  629.  *                  If file is opened in write mode, it makes sure
  630.  *                  that last block is sent out to server and
  631.  *                  waits for server to respond with ACK.
  632.  *
  633.  * Note:            TFTPIsFileClosed() must be called to confirm
  634.  *                  if file was really closed.
  635.  ********************************************************************/
  636. void TFTPCloseFile(void)
  637. {
  638.     // If a file was opened for read, we can close it immediately.
  639.     if ( _tftpFlags.bits.bIsReading )
  640.     {
  641.         // If this was premature close, make sure that we discard
  642.         // current block.
  643.         if ( !_tftpFlags.bits.bIsFlushed )
  644.         {
  645.             _tftpFlags.bits.bIsFlushed = TRUE;
  646.             UDPDiscard();
  647.         }
  648.  
  649.         if ( _tftpFlags.bits.bIsAcked )
  650.         {
  651.             _tftpFlags.bits.bIsClosed = TRUE;
  652.             _tftpFlags.bits.bIsClosing = FALSE;
  653.             return;
  654.         }
  655.  
  656.         else
  657.         {
  658.             _tftpState = SM_TFTP_SEND_LAST_ACK;
  659.             _tftpFlags.bits.bIsClosing = TRUE;
  660.         }
  661.         return;
  662.     }
  663.  
  664.     // For write mode, if we have not flushed last block, do it now.
  665.     if ( !_tftpFlags.bits.bIsFlushed )
  666.     {
  667.         _tftpFlags.bits.bIsFlushed = TRUE;
  668.         UDPFlush();
  669.     }
  670.  
  671.     // For write mode, if our last block was ack'ed by remote server,
  672.     // file is said to be closed.
  673.     if ( _tftpFlags.bits.bIsAcked )
  674.     {
  675.         _tftpFlags.bits.bIsClosed = TRUE;
  676.         _tftpFlags.bits.bIsClosing = FALSE;
  677.         return;
  678.     }
  679.  
  680.     _tftpState = SM_TFTP_WAIT_FOR_ACK;
  681.     _tftpFlags.bits.bIsClosing =  TRUE;
  682.  
  683. }
  684.  
  685.  
  686.  
  687. /*********************************************************************
  688.  * Function:        TFTP_RESULT TFPTIsFileClosed(void)
  689.  *
  690.  * PreCondition:    TFTPCloseFile() is already called.
  691.  *
  692.  * Input:           None
  693.  *
  694.  * Output:          TFTP_OK if file was successfully closdd
  695.  *
  696.  *                  TFTP_RETRY if file mode was Write and remote
  697.  *                  server did not receive last packet.
  698.  *                  Application must retry with last block.
  699.  *
  700.  *                  TFTP_TIMEOUT if all attempts were exhausted
  701.  *                  in closing file.
  702.  *
  703.  *                  TFTP_ERROR if remote server sent an error
  704.  *                  in response to last block.
  705.  *                  Actual error code may be read by calling
  706.  *                  TFTPGetError()
  707.  *
  708.  *                  TFTP_NOT_READY if file is not closed yet.
  709.  *
  710.  * Side Effects:    None
  711.  *
  712.  * Overview:        If file mode is Read, it simply makes that
  713.  *                  last block is acknowledged.
  714.  *                  If file mode is Write, it waits for server ack.
  715.  *                  If no ack was received within specified timeout
  716.  *                  instructs appliaction to resend last block.
  717.  *                  It keeps track of retries and declares timeout
  718.  *                  all attempts were exhausted.
  719.  *
  720.  * Note:            None
  721.  ********************************************************************/
  722. TFTP_RESULT TFTPIsFileClosed(void)
  723. {
  724.     if ( _tftpFlags.bits.bIsReading )
  725.         return TFTPIsGetReady();
  726.  
  727.     else
  728.         return TFTPIsPutReady();
  729. }
  730.  
  731.  
  732.  
  733.  
  734. /*********************************************************************
  735.  * Function:        TFTP_RESULT TFTPIsPutReady(void)
  736.  *
  737.  * PreCondition:    TFTPOpenFile() is called with TFTP_FILE_MODE_WRITE
  738.  *                  and TFTPIsFileOpened() returned with TRUE.
  739.  *
  740.  * Input:           None
  741.  *
  742.  * Output:          TFTP_OK if it is okay to write more data byte.
  743.  *
  744.  *                  TFTP_TIMEOUT if timeout occurred waiting for
  745.  *                  ack from server
  746.  *
  747.  *                  TFTP_RETRY if all server did not send ack
  748.  *                  on time and application needs to resend
  749.  *                  last block.
  750.  *
  751.  *                  TFTP_ERROR if remote server returned ERROR.
  752.  *                  Actual error code may be read by calling
  753.  *                  TFTPGetError()
  754.  *
  755.  *                  TFTP_NOT_READY if still waiting...
  756.  *
  757.  * Side Effects:    None
  758.  *
  759.  * Overview:        Waits for ack from server.  If ack does not
  760.  *                  arrive within specified timeout, it it instructs
  761.  *                  application to retry last block by returning
  762.  *                  TFTP_RETRY.
  763.  *
  764.  *                  If all attempts are exhausted, it returns with
  765.  *                  TFTP_TIMEOUT.
  766.  *
  767.  * Note:            None
  768.  ********************************************************************/
  769. TFTP_RESULT TFTPIsPutReady(void)
  770. {
  771.     WORD_VAL opCode;
  772.     WORD_VAL blockNumber;
  773.     BOOL bTimeOut;
  774.  
  775.     // Check to see if timeout has occurred.
  776.     bTimeOut = FALSE;
  777.     if ( TickGetDiff(TickGet(), _tftpStartTick) >= TFTP_GET_TIMEOUT_VAL )
  778.     {
  779.         bTimeOut = TRUE;
  780.         _tftpStartTick = TickGet();
  781.     }
  782.  
  783.     switch(_tftpState)
  784.     {
  785.     case SM_TFTP_WAIT_FOR_ACK:
  786.         // When timeout occurs in this state, application must retry.
  787.         if ( bTimeOut )
  788.         {
  789.             if ( _tftpRetries++ > (TFTP_MAX_RETRIES-1) )
  790.             {
  791.                 DEBUG(printf("TFTPIsPutReady(): Timeout.\n"));
  792.  
  793.                 // Forget about all previous attempts.
  794.                 _tftpRetries = 1;
  795.  
  796.                 return TFTP_TIMEOUT;
  797.             }
  798.  
  799.             else
  800.             {
  801.                 DEBUG(printf("TFTPIsPutReady(): Retry.\n"));
  802.                 return TFTP_RETRY;
  803.             }
  804.         }
  805.  
  806.         // Must wait for ACK from server before we transmit next block.
  807.         if ( !UDPIsGetReady(_tftpSocket) )
  808.             break;
  809.  
  810.         // Get opCode.
  811.         UDPGet(&opCode.byte.MSB);
  812.         UDPGet(&opCode.byte.LSB);
  813.  
  814.         // Get block number.
  815.         UDPGet(&blockNumber.byte.MSB);
  816.         UDPGet(&blockNumber.byte.LSB);
  817.  
  818.         // Discard everything else.
  819.         UDPDiscard();
  820.  
  821.         // This must be ACK or else there is a problem.
  822.         if ( opCode.Val == TFTP_OPCODE_ACK )
  823.         {
  824.             // Also the block number must match with what we are expecting.
  825.             if ( MutExVar.group2._tftpBlockNumber.Val == blockNumber.Val )
  826.             {
  827.                 // Mark that block we sent previously has been ack'ed.
  828.                 _tftpFlags.bits.bIsAcked = TRUE;
  829.  
  830.                 // Since we have ack, forget about previous retry count.
  831.                 _tftpRetries = 1;
  832.  
  833.                 // If this file is being closed, this must be last ack.
  834.                 // Declare it as closed.
  835.                 if ( _tftpFlags.bits.bIsClosing )
  836.                 {
  837.                     _tftpFlags.bits.bIsClosed = TRUE;
  838.                     return TFTP_OK;
  839.                 }
  840.  
  841.                 // Or else, wait for put to become ready so that caller
  842.                 // can transfer more data blocks.
  843.                 _tftpState = SM_TFTP_WAIT;
  844.             }
  845.  
  846.             else
  847.             {
  848.                 DEBUG(printf("TFTPIsPutReady(): "\
  849.                     "Unexpected block %d received - droping it...\n", \
  850.                     blockNumber.Val));
  851.                 return TFTP_NOT_READY;
  852.             }
  853.         }
  854.  
  855.         else if ( opCode.Val == TFTP_OPCODE_ERROR )
  856.         {
  857.             // For error opCode, remember error code so that application
  858.             // can read it later.
  859.             _tftpError = blockNumber.Val;
  860.  
  861.             // Declare error.
  862.             return TFTP_ERROR;
  863.         }
  864.         else
  865.             break;
  866.  
  867.  
  868.     case SM_TFTP_WAIT:
  869.         // Wait for UDP is to be ready to transmit.
  870.         if ( UDPIsPutReady(_tftpSocket) )
  871.         {
  872.             // Put next block of data.
  873.             MutExVar.group2._tftpBlockNumber.Val++;
  874.             UDPPut(0);
  875.             UDPPut(TFTP_OPCODE_DATA);
  876.  
  877.             UDPPut(MutExVar.group2._tftpBlockNumber.byte.MSB);
  878.             UDPPut(MutExVar.group2._tftpBlockNumber.byte.LSB);
  879.  
  880.             // Remember that this block is not yet flushed.
  881.             _tftpFlags.bits.bIsFlushed = FALSE;
  882.  
  883.             // Remember that this block is not acknowledged.
  884.             _tftpFlags.bits.bIsAcked = FALSE;
  885.  
  886.             // Now, TFTP module is ready to put more data.
  887.             _tftpState = SM_TFTP_READY;
  888.  
  889.             return TFTP_OK;
  890.         }
  891.         break;
  892.  
  893.     case SM_TFTP_READY:
  894.         // TFTP module is said to be ready only when underlying UDP
  895.         // is ready to transmit.
  896.         if ( UDPIsPutReady(_tftpSocket) )
  897.             return TFTP_OK;
  898.     }
  899.  
  900.     return TFTP_NOT_READY;
  901. }
  902.  
  903.  
  904.  
  905. /*********************************************************************
  906.  * Function:        void TFTPPut(BYTE c)
  907.  *
  908.  * PreCondition:    TFTPOpenFile() is called with TFTP_FILE_MODE_WRITE
  909.  *                  and TFTPIsPutReady() = TRUE
  910.  *
  911.  * Input:           c       - Data byte that is to be written
  912.  *
  913.  * Output:          None
  914.  *
  915.  * Side Effects:    None
  916.  *
  917.  * Overview:        Puts given data byte into TFTP socket.
  918.  *                  If end of data block is reached, it
  919.  *                  transmits entire block.
  920.  *
  921.  * Note:            Use this function to write file to server.
  922.  ********************************************************************/
  923. void TFTPPut(BYTE c)
  924. {
  925.     // Put given byte directly to UDP
  926.     UDPPut(c);
  927.  
  928.     // One more byte in data block.
  929.     ++MutExVar.group2._tftpBlockLength.Val;
  930.  
  931.     // Check to see if data block is full.
  932.     if ( MutExVar.group2._tftpBlockLength.byte.MSB == TFTP_BLOCK_SIZE_MSB )
  933.     {
  934.         // If it is, then transmit this block.
  935.         UDPFlush();
  936.  
  937.         // Remember that current block is already flushed.
  938.         _tftpFlags.bits.bIsFlushed = TRUE;
  939.  
  940.         // Prepare for next block.
  941.         MutExVar.group2._tftpBlockLength.Val = 0;
  942.  
  943.         // Need to wait for ACK from server before putting
  944.         // next block of data.
  945.         _tftpState = SM_TFTP_WAIT_FOR_ACK;
  946.     }
  947. }
  948.  
  949.  
  950.  
  951.  
  952. static void _TFTPSendFileName(TFTP_OPCODE opcode, char *fileName)
  953. {
  954.     BYTE c;
  955.  
  956.     // Write opCode
  957.     UDPPut(0);
  958.     UDPPut(opcode);
  959.  
  960.     // write file name, including NULL.
  961.     do
  962.     {
  963.         c = *fileName++;
  964.         UDPPut(c);
  965.     } while ( c != '\0' );
  966.  
  967.     // Write mode - always use octet or binay mode to transmit files.
  968.     UDPPut('o');
  969.     UDPPut('c');
  970.     UDPPut('t');
  971.     UDPPut('e');
  972.     UDPPut('t');
  973.     UDPPut(0);
  974.  
  975.     // Transmit it.
  976.     UDPFlush();
  977.  
  978.     // Reset data block length.
  979.     MutExVar.group2._tftpBlockLength.Val = 0;
  980.  
  981. }
  982.  
  983. static void _TFTPSendAck(WORD_VAL blockNumber)
  984. {
  985.     // Write opCode.
  986.     UDPPut(0);
  987.     UDPPut(TFTP_OPCODE_ACK);
  988.  
  989.     // Write block number for this ack.
  990.     UDPPut(blockNumber.byte.MSB);
  991.     UDPPut(blockNumber.byte.LSB);
  992.  
  993.     // Transmit it.
  994.     UDPFlush();
  995. }
  996.