/[H8]/trunk/docs/MCHPStack2.20/Source/TFTPc.c
ViewVC logotype

Annotation of /trunk/docs/MCHPStack2.20/Source/TFTPc.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 62 - (hide annotations) (download)
Tue May 1 08:17:39 2007 UTC (17 years, 2 months ago) by hedin
File MIME type: text/plain
File size: 30897 byte(s)
Removed tcpip stack 4.02 and added tcpip stack 2.20.
1 hedin 62 /*********************************************************************
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 "tftpc.h"
44     #include "arptsk.h"
45     #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     }

  ViewVC Help
Powered by ViewVC 1.1.20