?lang_form? ?lang_select? ?lang_submit? ?lang_endform?
{HEADER END}
{BLAME START}

library

?curdirlinks? -

Blame information for rev 32

Line No. Rev Author Line
1 32 kaklik /*********************************************************************
2 *
3 * Trivial File Transfer Protocol (TFTP) Client
4 * Module for Microchip TCP/IP Stack
5 * -Provides unreliable file upload and download services to other
6 * applications which wish to connect to a remote UDP based TFTP
7 * server.
8 * -Reference: RFC 1350
9 *
10 *********************************************************************
11 * FileName: TFTPc.c
12 * Dependencies: UDP, ARP, Tick
13 * Processor: PIC18, PIC24F, PIC24H, dsPIC30F, dsPIC33F, PIC32
14 * Compiler: Microchip C32 v1.05 or higher
15 * Microchip C30 v3.12 or higher
16 * Microchip C18 v3.30 or higher
17 * HI-TECH PICC-18 PRO 9.63PL2 or higher
18 * Company: Microchip Technology, Inc.
19 *
20 * Software License Agreement
21 *
22 * Copyright (C) 2002-2009 Microchip Technology Inc. All rights
23 * reserved.
24 *
25 * Microchip licenses to you the right to use, modify, copy, and
26 * distribute:
27 * (i) the Software when embedded on a Microchip microcontroller or
28 * digital signal controller product ("Device") which is
29 * integrated into Licensee's product; or
30 * (ii) ONLY the Software driver source files ENC28J60.c, ENC28J60.h,
31 * ENCX24J600.c and ENCX24J600.h ported to a non-Microchip device
32 * used in conjunction with a Microchip ethernet controller for
33 * the sole purpose of interfacing with the ethernet controller.
34 *
35 * You should refer to the license agreement accompanying this
36 * Software for additional information regarding your rights and
37 * obligations.
38 *
39 * THE SOFTWARE AND DOCUMENTATION ARE PROVIDED "AS IS" WITHOUT
40 * WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT
41 * LIMITATION, ANY WARRANTY OF MERCHANTABILITY, FITNESS FOR A
42 * PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT SHALL
43 * MICROCHIP BE LIABLE FOR ANY INCIDENTAL, SPECIAL, INDIRECT OR
44 * CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, COST OF
45 * PROCUREMENT OF SUBSTITUTE GOODS, TECHNOLOGY OR SERVICES, ANY CLAIMS
46 * BY THIRD PARTIES (INCLUDING BUT NOT LIMITED TO ANY DEFENSE
47 * THEREOF), ANY CLAIMS FOR INDEMNITY OR CONTRIBUTION, OR OTHER
48 * SIMILAR COSTS, WHETHER ASSERTED ON THE BASIS OF CONTRACT, TORT
49 * (INCLUDING NEGLIGENCE), BREACH OF WARRANTY, OR OTHERWISE.
50 *
51 * Author Date Comment
52 *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
53 * Nilesh Rajbharti 8/5/03 Original (Rev 1.0)
54 * Howard Schlunder 01/05/2010 Added TFTPUploadRAMFileToHost(),
55 TFTPUploadFragmentedRAMFileToHost(),
56 and TFTPGetUploadStatus() APIs.
57 ********************************************************************/
58 #define __TFTPC_C
59  
60 #include "TCPIPConfig.h"
61  
62 #if defined(STACK_USE_TFTP_CLIENT)
63  
64 #include "TCPIP Stack/TCPIP.h"
65  
66 // The TFTP Client port - a unique port on this device
67 #define TFTP_CLIENT_PORT 65352L
68 // The TFTP Server Port
69 #define TFTP_SERVER_PORT (69L)
70 // The size of a TFTP block - 512 bytes
71 #define TFTP_BLOCK_SIZE (0x200L)
72 // The MSB of the TFTP_BLOCK_SIZE
73 #define TFTP_BLOCK_SIZE_MSB (0x02u)
74  
75 // The TFTP state machine
76 typedef enum
77 {
78 SM_TFTP_WAIT = 0,
79 SM_TFTP_READY,
80 SM_TFTP_WAIT_FOR_DATA,
81 SM_TFTP_WAIT_FOR_ACK,
82 SM_TFTP_DUPLICATE_ACK,
83 SM_TFTP_SEND_ACK,
84 SM_TFTP_SEND_LAST_ACK
85 } TFTP_STATE;
86  
87 // Enumeration of TFTP opcodes
88 typedef enum
89 {
90 TFTP_OPCODE_RRQ = 1, // Get
91 TFTP_OPCODE_WRQ, // Put
92 TFTP_OPCODE_DATA, // Actual data
93 TFTP_OPCODE_ACK, // Ack for Get/Put
94 TFTP_OPCODE_ERROR // Error
95 } TFTP_OPCODE;
96  
97  
98 UDP_SOCKET _tftpSocket; // TFTP Socket for TFTP server link
99 WORD _tftpError; // Variable to preserve error condition causes for later transmission
100  
101 static union
102 {
103 struct
104 {
105 NODE_INFO _hostInfo;
106 } group1;
107  
108 struct
109 {
110 WORD_VAL _tftpBlockNumber;
111 WORD_VAL _tftpDuplicateBlock;
112 WORD_VAL _tftpBlockLength;
113 } group2;
114 } MutExVar; // Mutually Exclusive variable groups to conserve RAM.
115  
116 // TFTP state machine tracker variable
117 static TFTP_STATE _tftpState;
118 // Tracker variable for the number of TFTP retries
119 static BYTE _tftpRetries;
120 // Timing variable used to detect timeout conditions
121 static DWORD _tftpStartTick;
122  
123 // TFTP status flags
124 static union
125 {
126 struct
127 {
128 unsigned int bIsFlushed : 1;
129 unsigned int bIsAcked : 1;
130 unsigned int bIsClosed : 1;
131 unsigned int bIsClosing : 1;
132 unsigned int bIsReading : 1;
133 } bits;
134 BYTE Val;
135 } _tftpFlags;
136  
137  
138 // Private helper function
139 static void _TFTPSendFileName(TFTP_OPCODE command, BYTE *fileName);
140 // Private helper function
141 static void _TFTPSendAck(WORD_VAL blockNumber);
142  
143 #if defined(__18CXX)
144 // PIC18 ROM variable argument implementation of _TFTPSendFileName
145 static void _TFTPSendROMFileName(TFTP_OPCODE opcode, ROM BYTE *fileName);
146 #endif
147  
148 // Blank out DEBUG statements if not enabled.
149 #if defined(TFTP_DEBUG)
150 #define DEBUG(a) a
151 #else
152 #define DEBUG(a)
153 #endif
154  
155 // TFTPUploadRAMFileToHost(), TFTPUploadFragmentedRAMFileToHost() and
156 // TFTPGetUploadStatus() functions require the DNS client module to be enabled
157 // for them to work. The RAM and ROM resources for these functions can be
158 // preserved if the DNS client module isn't enabled.
159 #if defined(STACK_USE_DNS)
160  
161 static ROM BYTE *vUploadRemoteHost;
162 static ROM BYTE *vUploadFilename;
163 static TFTP_CHUNK_DESCRIPTOR *uploadChunkDescriptor;
164 static WORD wUploadChunkOffset;
165 static CHAR smUpload = TFTP_UPLOAD_COMPLETE;
166 static TFTP_CHUNK_DESCRIPTOR *uploadChunkDescriptorForRetransmit;
167 static WORD wUploadChunkOffsetForRetransmit;
168  
169 /*****************************************************************************
170 Function:
171 void TFTPUploadRAMFileToHost(ROM BYTE *vRemoteHost,
172 ROM BYTE *vFilename,
173 BYTE *vData,
174 WORD wDataLength)
175  
176 Summary:
177 Uploads a contiguous array of RAM bytes as a file to a remote TFTP server.
178  
179 Description:
180 Uploads a contiguous array of RAM bytes as a file to a remote TFTP server.
181  
182 Precondition:
183 None
184  
185 Parameters:
186 vRemoteHost: ROM string of the remote TFTP server to upload to (ex:
187 "www.myserver.com"). For device architectures that make no distinction
188 between RAM and ROM pointers (PIC24, dsPIC and PIC32), this string must
189 remain allocated and unmodified in RAM until the TFTP upload process
190 completes (as indicated by TFTPGetUploadStatus()).
191 vFilename: ROM string of the remote file to create/overwrite (ex:
192 "status.txt"). For device architectures that make no distinction
193 between RAM and ROM pointers (PIC24, dsPIC and PIC32), this string must
194 remain allocated and unmodified in RAM until the TFTP upload process
195 completes (as indicated by TFTPGetUploadStatus()).
196 vData: Pointer to a RAM array of data to write to the file.
197 wDataLength: Number of bytes pointed to by vData. This will be the final
198 file size of the uploaded file. Note that since this is defined as a
199 WORD type, the maximum possible file size is 65535 bytes. For longer
200 files, call the TFTPUploadFragmentedRAMFileToHost() function instead.
201  
202 Returns:
203 None
204  
205 Remarks:
206 The DNS client module must be enabled to use this function. i.e.
207 STACK_USE_DNS must be defined in TCPIPConfig.h.
208  
209 Call the TFTPGetUploadStatus() function to determine the status of the file
210 upload.
211  
212 It is only possible to have one TFTP operation active at any given time.
213 After starting a TFTP operation by calling TFTPUploadRAMFileToHost() or
214 TFTPUploadFragmentedRAMFileToHost(), you must wait until
215 TFTPGetUploadStatus() returns a completion status code (<=0) before calling
216 any other TFTP API functions.
217 ***************************************************************************/
218 void TFTPUploadRAMFileToHost(ROM BYTE *vRemoteHost, ROM BYTE *vFilename, BYTE *vData, WORD wDataLength)
219 {
220 static TFTP_CHUNK_DESCRIPTOR chunk[2];
221 chunk[0].vDataPointer = vData;
222 chunk[0].wDataLength = wDataLength;
223 chunk[1].vDataPointer = NULL;
224 TFTPUploadFragmentedRAMFileToHost(vRemoteHost, vFilename, chunk);
225 }
226  
227 /*****************************************************************************
228 Function:
229 void TFTPUploadFragmentedRAMFileToHost(ROM BYTE *vRemoteHost,
230 ROM BYTE *vFilename,
231 TFTP_CHUNK_DESCRIPTOR *vFirstChunkDescriptor)
232 Summary:
233 Uploads an random, potentially non-contiguous, array of RAM bytes as a file
234 to a remote TFTP server.
235  
236 Description:
237 Uploads an random, potentially non-contiguous, array of RAM bytes as a file
238 to a remote TFTP server.
239  
240 Precondition:
241 None
242  
243 Parameters:
244 vRemoteHost: ROM string of the remote TFTP server to upload to (ex:
245 "www.myserver.com"). For device architectures that make no distinction
246 between RAM and ROM pointers (PIC24, dsPIC and PIC32), this string must
247 remain allocated and unmodified in RAM until the TFTP upload process
248 completes (as indicated by TFTPGetUploadStatus()).
249 vFilename: ROM string of the remote file to create/overwrite (ex:
250 "status.txt"). For device architectures that make no distinction
251 between RAM and ROM pointers (PIC24, dsPIC and PIC32), this string must
252 remain allocated and unmodified in RAM until the TFTP upload process
253 completes (as indicated by TFTPGetUploadStatus()).
254 vFirstChunkDescriptor: Pointer to a static or global (persistent) array of
255 TFTP_CHUNK_DESCRIPTOR structures describing what RAM memory addresses
256 the file contents should be obtained from. The
257 TFTP_CHUNK_DESCRIPTOR.vDataPointer field should be set to the memory
258 address of the data to transmit, and the
259 TFTP_CHUNK_DESCRIPTOR.wDataLength field should be set to the number of
260 bytes to transmit from the given pointer. The TFTP_CHUNK_DESCRIPTOR
261 array must be terminated by a dummy descriptor whos
262 TFTP_CHUNK_DESCRIPTOR.vDataPointer pointer is set to NULL. Refer to the
263 TFTPUploadRAMFileToHost() API for an example calling sequence since it
264 merely a wrapper to this TFTPUploadFragmentedRAMFileToHost() function.
265  
266 Returns:
267 None
268  
269 Remarks:
270 The DNS client module must be enabled to use this function. i.e.
271 STACK_USE_DNS must be defined in TCPIPConfig.h.
272  
273 Call the TFTPGetUploadStatus() function to determine the status of the file
274 upload.
275  
276 It is only possible to have one TFTP operation active at any given time.
277 After starting a TFTP operation by calling TFTPUploadRAMFileToHost() or
278 TFTPUploadFragmentedRAMFileToHost(), you must wait until
279 TFTPGetUploadStatus() returns a completion status code (<=0) before calling
280 any other TFTP API functions.
281 ***************************************************************************/
282 void TFTPUploadFragmentedRAMFileToHost(ROM BYTE *vRemoteHost, ROM BYTE *vFilename, TFTP_CHUNK_DESCRIPTOR *vFirstChunkDescriptor)
283 {
284 vUploadRemoteHost = vRemoteHost;
285 vUploadFilename = vFilename;
286 uploadChunkDescriptor = vFirstChunkDescriptor;
287 uploadChunkDescriptorForRetransmit = vFirstChunkDescriptor;
288 wUploadChunkOffset = 0;
289 wUploadChunkOffsetForRetransmit = 0;
290 if(smUpload == TFTP_UPLOAD_RESOLVE_HOST)
291 DNSEndUsage();
292 smUpload = TFTP_UPLOAD_GET_DNS;
293 }
294  
295  
296 /*****************************************************************************
297 Function:
298 CHAR TFTPGetUploadStatus(void)
299  
300 Summary:
301 Returns the TFTP file upload status started by calling the
302 TFTPUploadRAMFileToHost() or TFTPUploadFragmentedRAMFileToHost() functions.
303  
304 Description:
305 Returns the TFTP file upload status started by calling the
306 TFTPUploadRAMFileToHost() or TFTPUploadFragmentedRAMFileToHost() functions.
307  
308 Precondition:
309 None
310  
311 Parameters:
312 None
313  
314 Returns:
315 A status code. Negative results are fatal errors. Positive results
316 indicate the TFTP upload operation is still being processed. A zero result
317 indicates successful file upload completion (TFTP API is now idle and
318 available for further calls). Specific return values are as follows:
319  
320 1 (TFTP_UPLOAD_GET_DNS): Attempting to obtain DNS client module
321 2 (TFTP_UPLOAD_RESOLVE_HOST): Attempting to resolve TFTP hostname
322 3 (TFTP_UPLOAD_CONNECT): Attempting to ARP and contact the TFTP server
323 4 (TFTP_UPLOAD_SEND_FILENAME): Attempting to send the filename and receive
324 acknowledgement.
325 5 (TFTP_UPLOAD_SEND_DATA): Attempting to send the file contents and receive
326 acknowledgement.
327 6 (TFTP_UPLOAD_WAIT_FOR_CLOSURE): Attempting to send the final packet of
328 file contents and receive acknowledgement.
329 -1 (TFTP_UPLOAD_HOST_RESOLVE_TIMEOUT): Couldn't resolve hostname
330 -2 (TFTP_UPLOAD_CONNECT_TIMEOUT): Couldn't finish ARP and reach server
331 -3 (TFTP_UPLOAD_SERVER_ERROR): TFTP server returned an error (ex: access
332 denial) or file upload failed due to a timeout (partial file may have
333 been uploaded).
334  
335 Remarks:
336 The DNS client module must be enabled to use this function. i.e.
337 STACK_USE_DNS must be defined in TCPIPConfig.h.
338 ***************************************************************************/
339 CHAR TFTPGetUploadStatus(void)
340 {
341 TFTP_RESULT result;
342 IP_ADDR ipRemote;
343 WORD w, w2;
344 BYTE *vData;
345  
346 switch(smUpload)
347 {
348 case TFTP_UPLOAD_GET_DNS:
349 if(!DNSBeginUsage())
350 break;
351 DNSResolveROM(vUploadRemoteHost, DNS_TYPE_A);
352 smUpload = TFTP_UPLOAD_RESOLVE_HOST;
353 break;
354  
355 case TFTP_UPLOAD_RESOLVE_HOST:
356 if(!DNSIsResolved(&ipRemote))
357 break;
358 DNSEndUsage();
359 if(ipRemote.Val == 0u)
360 {
361 smUpload = TFTP_UPLOAD_HOST_RESOLVE_TIMEOUT;
362 break;
363 }
364 TFTPOpen(&ipRemote);
365 smUpload = TFTP_UPLOAD_CONNECT;
366 break;
367  
368 case TFTP_UPLOAD_CONNECT:
369 switch(TFTPIsOpened())
370 {
371 case TFTP_OK:
372 TFTPOpenROMFile(vUploadFilename, TFTP_FILE_MODE_WRITE);
373 smUpload = TFTP_UPLOAD_SEND_FILENAME;
374 break;
375 case TFTP_TIMEOUT:
376 smUpload = TFTP_UPLOAD_CONNECT_TIMEOUT;
377 break;
378 default:
379 break;
380 }
381 break;
382  
383 case TFTP_UPLOAD_SEND_FILENAME:
384 result = TFTPIsFileOpened();
385 switch(result)
386 {
387 case TFTP_OK:
388 smUpload = TFTP_UPLOAD_SEND_DATA;
389 break;
390 case TFTP_RETRY:
391 TFTPOpenROMFile(vUploadFilename, TFTP_FILE_MODE_WRITE);
392 break;
393 case TFTP_TIMEOUT:
394 smUpload = TFTP_UPLOAD_CONNECT_TIMEOUT;
395 break;
396 case TFTP_ERROR:
397 smUpload = TFTP_UPLOAD_SERVER_ERROR;
398 break;
399 default:
400 break;
401 }
402 if(result != TFTP_OK)
403 break;
404 // No break when TFTPIsFileOpened() returns TFTP_OK -- we need to immediately start sending data
405  
406 case TFTP_UPLOAD_SEND_DATA:
407 switch(TFTPIsPutReady())
408 {
409 case TFTP_OK:
410 // Write blocksize bytes of data
411 uploadChunkDescriptorForRetransmit = uploadChunkDescriptor;
412 wUploadChunkOffsetForRetransmit = wUploadChunkOffset;
413 vData = uploadChunkDescriptor->vDataPointer + wUploadChunkOffset;
414 w = TFTP_BLOCK_SIZE;
415 while(w)
416 {
417 w2 = uploadChunkDescriptor->wDataLength - wUploadChunkOffset;
418 if(w2 > w)
419 w2 = w;
420 w -= w2;
421 wUploadChunkOffset += w2;
422 if(vData == NULL)
423 {
424 TFTPCloseFile();
425 smUpload = TFTP_UPLOAD_WAIT_FOR_CLOSURE;
426 break;
427 }
428 while(w2--)
429 {
430 TFTPPut(*vData++);
431 }
432 if(wUploadChunkOffset == uploadChunkDescriptor->wDataLength)
433 {
434 uploadChunkDescriptor++;
435 wUploadChunkOffset = 0;
436 vData = uploadChunkDescriptor->vDataPointer;
437 }
438 }
439 break;
440  
441 case TFTP_RETRY:
442 uploadChunkDescriptor = uploadChunkDescriptorForRetransmit;
443 wUploadChunkOffset = wUploadChunkOffsetForRetransmit;
444 break;
445  
446 case TFTP_TIMEOUT:
447 case TFTP_ERROR:
448 smUpload = TFTP_UPLOAD_SERVER_ERROR;
449 break;
450  
451 default:
452 break;
453 }
454 break;
455  
456 case TFTP_UPLOAD_WAIT_FOR_CLOSURE:
457 switch(TFTPIsFileClosed())
458 {
459 case TFTP_OK:
460 smUpload = TFTP_UPLOAD_COMPLETE;
461 UDPClose(_tftpSocket);
462 break;
463 case TFTP_RETRY:
464 uploadChunkDescriptor = uploadChunkDescriptorForRetransmit;
465 wUploadChunkOffset = wUploadChunkOffsetForRetransmit;
466 smUpload = TFTP_UPLOAD_SEND_DATA;
467 break;
468 case TFTP_TIMEOUT:
469 case TFTP_ERROR:
470 smUpload = TFTP_UPLOAD_SERVER_ERROR;
471 break;
472 default:
473 break;
474 }
475 break;
476  
477 default:
478 break;
479 }
480  
481 return smUpload;
482 }
483 #endif
484  
485  
486 /*********************************************************************
487 * Function: void TFTPOpen(IP_ADDR *host)
488 *
489 * Summary: Initializes TFTP module.
490 *
491 * PreCondition: UDP module is already initialized
492 * and at least one UDP socket is available.
493 *
494 * Input: host - IP address of remote TFTP server
495 *
496 * Output: None
497 *
498 * Side Effects: None
499 *
500 * Overview: Initiates ARP for given host and prepares
501 * TFTP module for next sequence of function calls.
502 *
503 * Note: Use TFTPIsOpened() to check if a connection was
504 * successfully opened or not.
505 *
506 ********************************************************************/
507 void TFTPOpen(IP_ADDR *host)
508 {
509 DEBUG(printf("Opening a connection..."));
510  
511 // Remember this address locally.
512 MutExVar.group1._hostInfo.IPAddr.Val = host->Val;
513  
514 // Initiate ARP resolution.
515 ARPResolve(&MutExVar.group1._hostInfo.IPAddr);
516  
517 // Wait for ARP to get resolved.
518 _tftpState = SM_TFTP_WAIT;
519  
520 // Mark this as start tick to detect timeout condition.
521 _tftpStartTick = TickGet();
522  
523 // Forget about all previous attempts.
524 _tftpRetries = 1;
525  
526 }
527  
528  
529  
530 /*********************************************************************
531 * Function: TFTP_RESULT TFTPIsOpened(void)
532 *
533 * Summary: Determines if the TFTP connection is open.
534 *
535 * PreCondition: TFTPOpen() is already called.
536 *
537 * Input: None
538 *
539 * Output: TFTP_OK if previous call to TFTPOpen is complete
540 *
541 * TFTP_TIMEOUT if remote host did not respond to
542 * previous ARP request.
543 *
544 * TFTP_NOT_READY if remote has still not responded
545 * and timeout has not expired.
546 *
547 * Side Effects: None
548 *
549 * Overview: Waits for ARP reply and opens a UDP socket
550 * to perform further TFTP operations.
551 *
552 * Note: Once opened, application may keep TFTP socket
553 * open and future TFTP operations.
554 * If TFTPClose() is called to close the connection
555 * TFTPOpen() must be called again before performing
556 * any other TFTP operations.
557 ********************************************************************/
558 TFTP_RESULT TFTPIsOpened(void)
559 {
560 switch(_tftpState)
561 {
562 default:
563 DEBUG(printf("Resolving remote IP...\n"));
564  
565 // Check to see if adddress is resolved.
566 if ( ARPIsResolved(&MutExVar.group1._hostInfo.IPAddr,
567 &MutExVar.group1._hostInfo.MACAddr) )
568 {
569 _tftpSocket = UDPOpen(TFTP_CLIENT_PORT,
570 &MutExVar.group1._hostInfo,
571 TFTP_SERVER_PORT);
572 _tftpState = SM_TFTP_READY;
573 }
574 else
575 break;
576  
577 case SM_TFTP_READY:
578 // Wait for UDP to be ready. Immediately after this user will
579 // may TFTPGetFile or TFTPPutFile and we have to make sure that
580 // UDP is read to transmit. These functions do not check for
581 // UDP to get ready.
582 if ( UDPIsPutReady(_tftpSocket) )
583 return TFTP_OK;
584 }
585  
586 // Make sure that we do not do this forever.
587 if ( TickGet() - _tftpStartTick >= TFTP_ARP_TIMEOUT_VAL )
588 {
589 _tftpStartTick = TickGet();
590  
591 // Forget about all previous attempts.
592 _tftpRetries = 1;
593  
594 return TFTP_TIMEOUT;
595 }
596  
597 return TFTP_NOT_READY;
598 }
599  
600  
601  
602 /*********************************************************************
603 * Function: void TFTPOpenFile(char *fileName,
604 * TFTP_FILE_MODE mode)
605 *
606 * Summary: Prepares and sends TFTP file name and mode packet.
607 *
608 * PreCondition: TFPTIsFileOpenReady() = TRUE
609 *
610 * Input: fileName - File name that is to be opened.
611 * mode - Mode of file access
612 * Must be
613 * TFTP_FILE_MODE_READ for read
614 * TFTP_FILE_MODE_WRITE for write
615 *
616 * Output: None
617 *
618 * Side Effects: None
619 *
620 * Overview: Prepares and sends TFTP file name and mode packet.
621 *
622 * Note: By default, this funciton uses "octet" or binary
623 * mode of file transfer.
624 * Use TFTPIsFileOpened() to check if file is
625 * ready to be read or written.
626 ********************************************************************/
627 void TFTPOpenFile(BYTE *fileName, TFTP_FILE_MODE mode)
628 {
629 DEBUG(printf("Opening file...\n"));
630  
631 // Set TFTP Server port. If this is the first call, remotePort
632 // must have been set by TFTPOpen(). But if caller does not do
633 // TFTPOpen for every transfer, we must reset remote port.
634 // Most TFTP servers accept connection TFTP port. but once
635 // connection is established, they use other temp. port,
636 UDPSocketInfo[_tftpSocket].remotePort = TFTP_SERVER_PORT;
637  
638 // Tell remote server about our intention.
639 _TFTPSendFileName(mode, fileName);
640  
641 // Clear all flags.
642 _tftpFlags.Val = 0;
643  
644 // Remember start tick for this operation.
645 _tftpStartTick = TickGet();
646  
647 // Depending on mode of operation, remote server will respond with
648 // specific block number.
649 if ( mode == TFTP_FILE_MODE_READ )
650 {
651 // Remember that we are reading a file.
652 _tftpFlags.bits.bIsReading = TRUE;
653  
654  
655 // For read operation, server would respond with data block of 1.
656 MutExVar.group2._tftpBlockNumber.Val = 1;
657  
658 // Next packet would be the data packet.
659 _tftpState = SM_TFTP_WAIT_FOR_DATA;
660 }
661  
662 else
663 {
664 // Remember that we are writing a file.
665 _tftpFlags.bits.bIsReading = FALSE;
666  
667 // For write operation, server would respond with data block of 0.
668 MutExVar.group2._tftpBlockNumber.Val = 0;
669  
670 // Next packet would be the ACK packet.
671 _tftpState = SM_TFTP_WAIT_FOR_ACK;
672 }
673 }
674  
675 #if defined(__18CXX)
676 void TFTPOpenROMFile(ROM BYTE *fileName, TFTP_FILE_MODE mode)
677 {
678 DEBUG(printf("Opening file...\n"));
679  
680 // Set TFTP Server port. If this is the first call, remotePort
681 // must have been set by TFTPOpen(). But if caller does not do
682 // TFTPOpen for every transfer, we must reset remote port.
683 // Most TFTP servers accept connection TFTP port. but once
684 // connection is established, they use other temp. port,
685 UDPSocketInfo[_tftpSocket].remotePort = TFTP_SERVER_PORT;
686  
687 // Tell remote server about our intention.
688 _TFTPSendROMFileName(mode, fileName);
689  
690 // Clear all flags.
691 _tftpFlags.Val = 0;
692  
693 // Remember start tick for this operation.
694 _tftpStartTick = TickGet();
695  
696 // Depending on mode of operation, remote server will respond with
697 // specific block number.
698 if ( mode == TFTP_FILE_MODE_READ )
699 {
700 // Remember that we are reading a file.
701 _tftpFlags.bits.bIsReading = TRUE;
702  
703  
704 // For read operation, server would respond with data block of 1.
705 MutExVar.group2._tftpBlockNumber.Val = 1;
706  
707 // Next packet would be the data packet.
708 _tftpState = SM_TFTP_WAIT_FOR_DATA;
709 }
710  
711 else
712 {
713 // Remember that we are writing a file.
714 _tftpFlags.bits.bIsReading = FALSE;
715  
716 // For write operation, server would respond with data block of 0.
717 MutExVar.group2._tftpBlockNumber.Val = 0;
718  
719 // Next packet would be the ACK packet.
720 _tftpState = SM_TFTP_WAIT_FOR_ACK;
721 }
722 }
723 #endif
724  
725  
726  
727 /*********************************************************************
728 * Function: TFTP_RESULT TFTPIsFileOpened(void)
729 *
730 * Summary: Determines if file has been opened.
731 *
732 * PreCondition: TFTPOpenFile() is called.
733 *
734 * Input: None
735 *
736 * Output: TFTP_OK if file is ready to be read or written
737 *
738 * TFTP_RETRY if previous attempt was timed out
739 * needs to be retried.
740 *
741 * TFTP_TIMEOUT if all attempts were exhausted.
742 *
743 * TFTP_ERROR if remote server responded with
744 * error
745 *
746 * TFTP_NOT_READY if file is not yet opened.
747 *
748 * Side Effects: None
749 *
750 * Overview: Waits for remote server response regarding
751 * previous attempt to open file.
752 * If no response is received within specified
753 * timeout, fnction returns with TFTP_RETRY
754 * and application logic must issue another
755 * TFTPFileOpen().
756 *
757 * Note: None
758 ********************************************************************/
759 TFTP_RESULT TFTPIsFileOpened(void)
760 {
761 if ( _tftpFlags.bits.bIsReading )
762 return TFTPIsGetReady();
763  
764 else
765 return TFTPIsPutReady();
766 }
767  
768  
769  
770  
771 /*********************************************************************
772 * Function: TFTP_RESULT TFTPIsGetReady(void)
773 *
774 * Summary: Determines if a data block is ready to be read.
775 *
776 * PreCondition: TFTPOpenFile() is called with TFTP_FILE_MODE_READ
777 * and TFTPIsFileOpened() returned with TRUE.
778 *
779 * Input: None
780 *
781 * Output: TFTP_OK if it there is more data byte available
782 * to read
783 *
784 * TFTP_TIMEOUT if timeout occurred waiting for
785 * new data.
786 *
787 * TFTP_END_OF_FILE if end of file has reached.
788 *
789 * TFTP_ERROR if remote server returned ERROR.
790 * Actual error code may be read by calling
791 * TFTPGetError()
792 *
793 * TFTP_NOT_READY if still waiting for new data.
794 *
795 * Side Effects: None
796 *
797 * Overview: Waits for data block. If data block does not
798 * arrive within specified timeout, it automatically
799 * sends out ack for previous block to remind
800 * server to send next data block.
801 * If all attempts are exhausted, it returns with
802 * TFTP_TIMEOUT.
803 *
804 * Note: By default, this funciton uses "octet" or binary
805 * mode of file transfer.
806 ********************************************************************/
807 TFTP_RESULT TFTPIsGetReady(void)
808 {
809 WORD_VAL opCode;
810 WORD_VAL blockNumber;
811 BOOL bTimeOut;
812  
813  
814 // Check to see if timeout has occurred.
815 bTimeOut = FALSE;
816 if ( TickGet() - _tftpStartTick >= TFTP_GET_TIMEOUT_VAL )
817 {
818 bTimeOut = TRUE;
819 _tftpStartTick = TickGet();
820 }
821  
822  
823 switch(_tftpState)
824 {
825 case SM_TFTP_WAIT_FOR_DATA:
826 // If timeout occurs in this state, it may be because, we have not
827 // even received very first data block or some in between block.
828 if ( bTimeOut == TRUE )
829 {
830 bTimeOut = FALSE;
831  
832 if ( _tftpRetries++ > (TFTP_MAX_RETRIES-1) )
833 {
834 DEBUG(printf("TFTPIsGetReady(): Timeout.\n"));
835  
836 // Forget about all previous attempts.
837 _tftpRetries = 1;
838  
839 return TFTP_TIMEOUT;
840 }
841  
842 // If we have not even received first block, ask application
843 // retry.
844 if ( MutExVar.group2._tftpBlockNumber.Val == 1u )
845 {
846 DEBUG(printf("TFTPIsGetReady(): TFTPOpen Retry.\n"));
847 return TFTP_RETRY;
848 }
849 else
850 {
851 DEBUG(printf("TFTPIsGetReady(): ACK Retry #%d...,\n", _tftpRetries));
852  
853 // Block number was already incremented in last ACK attempt,
854 // so decrement it.
855 MutExVar.group2._tftpBlockNumber.Val--;
856  
857 // Do it.
858 _tftpState = SM_TFTP_SEND_ACK;
859 break;
860 }
861 }
862  
863 // For Read operation, server will respond with data block.
864 if ( !UDPIsGetReady(_tftpSocket) )
865 break;
866  
867 // Get opCode
868 UDPGet(&opCode.v[1]);
869 UDPGet(&opCode.v[0]);
870  
871 // Get block number.
872 UDPGet(&blockNumber.v[1]);
873 UDPGet(&blockNumber.v[0]);
874  
875 // In order to read file, this must be data with block number of 0.
876 if ( opCode.Val == (WORD)TFTP_OPCODE_DATA )
877 {
878 // Make sure that this is not a duplicate block.
879 if ( MutExVar.group2._tftpBlockNumber.Val == blockNumber.Val )
880 {
881 // Mark that we have not acked this block.
882 _tftpFlags.bits.bIsAcked = FALSE;
883  
884 // Since we have a packet, forget about previous retry count.
885 _tftpRetries = 1;
886  
887 _tftpState = SM_TFTP_READY;
888 return TFTP_OK;
889 }
890  
891 // If received block has already been received, simply ack it
892 // so that Server can "get over" it and send next block.
893 else if ( MutExVar.group2._tftpBlockNumber.Val > blockNumber.Val )
894 {
895 DEBUG(printf("TFTPIsGetReady(): "\
896 "Duplicate block %d received - droping it...\n", \
897 blockNumber.Val));
898 MutExVar.group2._tftpDuplicateBlock.Val = blockNumber.Val;
899 _tftpState = SM_TFTP_DUPLICATE_ACK;
900 }
901 #if defined(TFTP_DEBUG)
902 else
903 {
904 DEBUG(printf("TFTPIsGetReady(): "\
905 "Unexpected block %d received - droping it...\n", \
906 blockNumber.Val));
907 }
908 #endif
909 }
910 // Discard all unexpected and error blocks.
911 UDPDiscard();
912  
913 // If this was an error, remember error code for later delivery.
914 if ( opCode.Val == (WORD)TFTP_OPCODE_ERROR )
915 {
916 _tftpError = blockNumber.Val;
917 return TFTP_ERROR;
918 }
919  
920 break;
921  
922 case SM_TFTP_DUPLICATE_ACK:
923 if ( UDPIsPutReady(_tftpSocket) )
924 {
925 _TFTPSendAck(MutExVar.group2._tftpDuplicateBlock);
926 _tftpState = SM_TFTP_WAIT_FOR_DATA;
927 }
928 break;
929  
930 case SM_TFTP_READY:
931 if ( UDPIsGetReady(_tftpSocket) )
932 {
933 _tftpStartTick = TickGet();
934 return TFTP_OK;
935 }
936  
937 // End of file is reached when data block is less than 512 bytes long.
938 // To reduce code, only MSB compared against 0x02 (of 0x200 = 512) to
939 // determine if block is less than 512 bytes long or not.
940 else if ( MutExVar.group2._tftpBlockLength.Val == 0u ||
941 MutExVar.group2._tftpBlockLength.v[1] < TFTP_BLOCK_SIZE_MSB )
942 _tftpState = SM_TFTP_SEND_LAST_ACK;
943 else
944 break;
945  
946  
947 case SM_TFTP_SEND_LAST_ACK:
948 case SM_TFTP_SEND_ACK:
949 if ( UDPIsPutReady(_tftpSocket) )
950 {
951 _TFTPSendAck(MutExVar.group2._tftpBlockNumber);
952  
953 // This is the next block we are expecting.
954 MutExVar.group2._tftpBlockNumber.Val++;
955  
956 // Remember that we have already acked current block.
957 _tftpFlags.bits.bIsAcked = TRUE;
958  
959 if ( _tftpState == SM_TFTP_SEND_LAST_ACK )
960 return TFTP_END_OF_FILE;
961  
962 _tftpState = SM_TFTP_WAIT_FOR_DATA;
963 }
964 break;
965 }
966  
967  
968  
969 return TFTP_NOT_READY;
970 }
971  
972  
973  
974 /*********************************************************************
975 * Function: BYTE TFTPGet(void)
976 *
977 * Summary: Gets a data byte from data that was read.
978 *
979 * PreCondition: TFTPOpenFile() is called with TFTP_FILE_MODE_READ
980 * and TFTPIsGetReady() = TRUE
981 *
982 * Input: None
983 *
984 * Output: data byte as received from remote server.
985 *
986 * Side Effects: None
987 *
988 * Overview: Fetches next data byte from TFTP socket.
989 * If end of data block is reached, it issues
990 * ack to server so that next data block can be
991 * received.
992 *
993 * Note: Use this function to read file from server.
994 ********************************************************************/
995 BYTE TFTPGet(void)
996 {
997 BYTE v;
998  
999 // Read byte from UDP
1000 UDPGet(&v);
1001  
1002 // Update block length
1003 MutExVar.group2._tftpBlockLength.Val++;
1004  
1005 // Check to see if entire data block is fetched.
1006 // To reduce code, MSB is compared for 0x02 (of 0x200 = 512).
1007 if ( MutExVar.group2._tftpBlockLength.v[1] == TFTP_BLOCK_SIZE_MSB )
1008 {
1009 // Entire block was fetched. Discard everything else.
1010 UDPDiscard();
1011  
1012 // Remember that we have flushed this block.
1013 _tftpFlags.bits.bIsFlushed = TRUE;
1014  
1015 // Reset block length.
1016 MutExVar.group2._tftpBlockLength.Val = 0;
1017  
1018 // Must send ACK to receive next block.
1019 _tftpState = SM_TFTP_SEND_ACK;
1020 }
1021  
1022 return v;
1023 }
1024  
1025  
1026  
1027  
1028 /*********************************************************************
1029 * Function: void TFTPCloseFile(void)
1030 *
1031 * Summary: Sends file closing messages.
1032 *
1033 * PreCondition: TFTPOpenFile() was called and TFTPIsFileOpened()
1034 * had returned with TFTP_OK.
1035 *
1036 * Input: None
1037 *
1038 * Output: None
1039 *
1040 * Side Effects: None
1041 *
1042 * Overview: If file is opened in read mode, it makes sure
1043 * that last ACK is sent to server
1044 * If file is opened in write mode, it makes sure
1045 * that last block is sent out to server and
1046 * waits for server to respond with ACK.
1047 *
1048 * Note: TFTPIsFileClosed() must be called to confirm
1049 * if file was really closed.
1050 ********************************************************************/
1051 void TFTPCloseFile(void)
1052 {
1053 // If a file was opened for read, we can close it immediately.
1054 if ( _tftpFlags.bits.bIsReading )
1055 {
1056 // If this was premature close, make sure that we discard
1057 // current block.
1058 if ( !_tftpFlags.bits.bIsFlushed )
1059 {
1060 _tftpFlags.bits.bIsFlushed = TRUE;
1061 UDPIsGetReady(_tftpSocket);
1062 UDPDiscard();
1063 }
1064  
1065 if ( _tftpFlags.bits.bIsAcked )
1066 {
1067 _tftpFlags.bits.bIsClosed = TRUE;
1068 _tftpFlags.bits.bIsClosing = FALSE;
1069 return;
1070 }
1071  
1072 else
1073 {
1074 _tftpState = SM_TFTP_SEND_LAST_ACK;
1075 _tftpFlags.bits.bIsClosing = TRUE;
1076 }
1077 return;
1078 }
1079  
1080 // For write mode, if we have not flushed last block, do it now.
1081 if ( !_tftpFlags.bits.bIsFlushed )
1082 {
1083 _tftpFlags.bits.bIsFlushed = TRUE;
1084 UDPIsPutReady(_tftpSocket);
1085 UDPFlush();
1086 }
1087  
1088 // For write mode, if our last block was ack'ed by remote server,
1089 // file is said to be closed.
1090 if ( _tftpFlags.bits.bIsAcked )
1091 {
1092 _tftpFlags.bits.bIsClosed = TRUE;
1093 _tftpFlags.bits.bIsClosing = FALSE;
1094 return;
1095 }
1096  
1097 _tftpState = SM_TFTP_WAIT_FOR_ACK;
1098 _tftpFlags.bits.bIsClosing = TRUE;
1099  
1100 }
1101  
1102  
1103  
1104 /*********************************************************************
1105 * Function: TFTP_RESULT TFTPIsFileClosed(void)
1106 *
1107 * Summary: Determines if the file was closed.
1108 *
1109 * PreCondition: TFTPCloseFile() is already called.
1110 *
1111 * Input: None
1112 *
1113 * Output: TFTP_OK if file was successfully closdd
1114 *
1115 * TFTP_RETRY if file mode was Write and remote
1116 * server did not receive last packet.
1117 * Application must retry with last block.
1118 *
1119 * TFTP_TIMEOUT if all attempts were exhausted
1120 * in closing file.
1121 *
1122 * TFTP_ERROR if remote server sent an error
1123 * in response to last block.
1124 * Actual error code may be read by calling
1125 * TFTPGetError()
1126 *
1127 * TFTP_NOT_READY if file is not closed yet.
1128 *
1129 * Side Effects: None
1130 *
1131 * Overview: If file mode is Read, it simply makes that
1132 * last block is acknowledged.
1133 * If file mode is Write, it waits for server ack.
1134 * If no ack was received within specified timeout
1135 * instructs appliaction to resend last block.
1136 * It keeps track of retries and declares timeout
1137 * all attempts were exhausted.
1138 *
1139 * Note: None
1140 ********************************************************************/
1141 TFTP_RESULT TFTPIsFileClosed(void)
1142 {
1143 if ( _tftpFlags.bits.bIsReading )
1144 return TFTPIsGetReady();
1145  
1146 else
1147 return TFTPIsPutReady();
1148 }
1149  
1150  
1151  
1152  
1153 /*********************************************************************
1154 * Function: TFTP_RESULT TFTPIsPutReady(void)
1155 *
1156 * Summary: Determines if data can be written to a file.
1157 *
1158 * PreCondition: TFTPOpenFile() is called with TFTP_FILE_MODE_WRITE
1159 * and TFTPIsFileOpened() returned with TRUE.
1160 *
1161 * Input: None
1162 *
1163 * Output: TFTP_OK if it is okay to write more data byte.
1164 *
1165 * TFTP_TIMEOUT if timeout occurred waiting for
1166 * ack from server
1167 *
1168 * TFTP_RETRY if all server did not send ack
1169 * on time and application needs to resend
1170 * last block.
1171 *
1172 * TFTP_ERROR if remote server returned ERROR.
1173 * Actual error code may be read by calling
1174 * TFTPGetError()
1175 *
1176 * TFTP_NOT_READY if still waiting...
1177 *
1178 * Side Effects: None
1179 *
1180 * Overview: Waits for ack from server. If ack does not
1181 * arrive within specified timeout, it it instructs
1182 * application to retry last block by returning
1183 * TFTP_RETRY.
1184 *
1185 * If all attempts are exhausted, it returns with
1186 * TFTP_TIMEOUT.
1187 *
1188 * Note: None
1189 ********************************************************************/
1190 TFTP_RESULT TFTPIsPutReady(void)
1191 {
1192 WORD_VAL opCode;
1193 WORD_VAL blockNumber;
1194 BOOL bTimeOut;
1195  
1196 // Check to see if timeout has occurred.
1197 bTimeOut = FALSE;
1198 if ( TickGet() - _tftpStartTick >= TFTP_GET_TIMEOUT_VAL )
1199 {
1200 bTimeOut = TRUE;
1201 _tftpStartTick = TickGet();
1202 }
1203  
1204 switch(_tftpState)
1205 {
1206 case SM_TFTP_WAIT_FOR_ACK:
1207 // When timeout occurs in this state, application must retry.
1208 if ( bTimeOut )
1209 {
1210 if ( _tftpRetries++ > (TFTP_MAX_RETRIES-1) )
1211 {
1212 DEBUG(printf("TFTPIsPutReady(): Timeout.\n"));
1213  
1214 // Forget about all previous attempts.
1215 _tftpRetries = 1;
1216  
1217 return TFTP_TIMEOUT;
1218 }
1219  
1220 else
1221 {
1222 DEBUG(printf("TFTPIsPutReady(): Retry.\n"));
1223 _tftpState = SM_TFTP_WAIT;
1224 MutExVar.group2._tftpBlockNumber.Val--; // Roll back by one so proper block number ID is sent for the next packet
1225 return TFTP_RETRY;
1226 }
1227 }
1228  
1229 // Must wait for ACK from server before we transmit next block.
1230 if ( !UDPIsGetReady(_tftpSocket) )
1231 break;
1232  
1233 // Get opCode.
1234 UDPGet(&opCode.v[1]);
1235 UDPGet(&opCode.v[0]);
1236  
1237 // Get block number.
1238 UDPGet(&blockNumber.v[1]);
1239 UDPGet(&blockNumber.v[0]);
1240  
1241 // Discard everything else.
1242 UDPDiscard();
1243  
1244 // This must be ACK or else there is a problem.
1245 if ( opCode.Val == (WORD)TFTP_OPCODE_ACK )
1246 {
1247 // Also the block number must match with what we are expecting.
1248 if ( MutExVar.group2._tftpBlockNumber.Val == blockNumber.Val )
1249 {
1250 // Mark that block we sent previously has been ack'ed.
1251 _tftpFlags.bits.bIsAcked = TRUE;
1252  
1253 // Since we have ack, forget about previous retry count.
1254 _tftpRetries = 1;
1255  
1256 // If this file is being closed, this must be last ack.
1257 // Declare it as closed.
1258 if ( _tftpFlags.bits.bIsClosing )
1259 {
1260 _tftpFlags.bits.bIsClosed = TRUE;
1261 return TFTP_OK;
1262 }
1263  
1264 // Or else, wait for put to become ready so that caller
1265 // can transfer more data blocks.
1266 _tftpState = SM_TFTP_WAIT;
1267 }
1268  
1269 else
1270 {
1271 DEBUG(printf("TFTPIsPutReady(): "\
1272 "Unexpected block %d received - droping it...\n", \
1273 blockNumber.Val));
1274 return TFTP_NOT_READY;
1275 }
1276 }
1277  
1278 else if ( opCode.Val == (WORD)TFTP_OPCODE_ERROR )
1279 {
1280 // For error opCode, remember error code so that application
1281 // can read it later.
1282 _tftpError = blockNumber.Val;
1283  
1284 // Declare error.
1285 return TFTP_ERROR;
1286 }
1287 else
1288 break;
1289  
1290  
1291 case SM_TFTP_WAIT:
1292 // Wait for UDP is to be ready to transmit.
1293 if ( UDPIsPutReady(_tftpSocket) )
1294 {
1295 // Put next block of data.
1296 MutExVar.group2._tftpBlockNumber.Val++;
1297 UDPPut(0);
1298 UDPPut(TFTP_OPCODE_DATA);
1299  
1300 UDPPut(MutExVar.group2._tftpBlockNumber.v[1]);
1301 UDPPut(MutExVar.group2._tftpBlockNumber.v[0]);
1302  
1303 // Remember that this block is not yet flushed.
1304 _tftpFlags.bits.bIsFlushed = FALSE;
1305  
1306 // Remember that this block is not acknowledged.
1307 _tftpFlags.bits.bIsAcked = FALSE;
1308  
1309 // Now, TFTP module is ready to put more data.
1310 _tftpState = SM_TFTP_READY;
1311  
1312 return TFTP_OK;
1313 }
1314 break;
1315  
1316 case SM_TFTP_READY:
1317 // TFTP module is said to be ready only when underlying UDP
1318 // is ready to transmit.
1319 if ( UDPIsPutReady(_tftpSocket) )
1320 return TFTP_OK;
1321 }
1322  
1323 return TFTP_NOT_READY;
1324 }
1325  
1326  
1327  
1328 /*********************************************************************
1329 * Function: void TFTPPut(BYTE c)
1330 *
1331 * Summary: Write a byte to a file.
1332 *
1333 * PreCondition: TFTPOpenFile() is called with TFTP_FILE_MODE_WRITE
1334 * and TFTPIsPutReady() = TRUE
1335 *
1336 * Input: c - Data byte that is to be written
1337 *
1338 * Output: None
1339 *
1340 * Side Effects: None
1341 *
1342 * Overview: Puts given data byte into TFTP socket.
1343 * If end of data block is reached, it
1344 * transmits entire block.
1345 *
1346 * Note: Use this function to write file to server.
1347 ********************************************************************/
1348 void TFTPPut(BYTE c)
1349 {
1350 // Put given byte directly to UDP
1351 UDPPut(c);
1352  
1353 // One more byte in data block.
1354 ++MutExVar.group2._tftpBlockLength.Val;
1355  
1356 // Check to see if data block is full.
1357 if ( MutExVar.group2._tftpBlockLength.v[1] == TFTP_BLOCK_SIZE_MSB )
1358 {
1359 // If it is, then transmit this block.
1360 UDPFlush();
1361  
1362 // Remember that current block is already flushed.
1363 _tftpFlags.bits.bIsFlushed = TRUE;
1364  
1365 // Prepare for next block.
1366 MutExVar.group2._tftpBlockLength.Val = 0;
1367  
1368 // Need to wait for ACK from server before putting
1369 // next block of data.
1370 _tftpState = SM_TFTP_WAIT_FOR_ACK;
1371 }
1372 }
1373  
1374  
1375  
1376  
1377 static void _TFTPSendFileName(TFTP_OPCODE opcode, BYTE *fileName)
1378 {
1379 BYTE c;
1380  
1381 // Select the proper UDP socket and wait until we can write to it
1382 while(!UDPIsPutReady(_tftpSocket));
1383  
1384 // Write opCode
1385 UDPPut(0);
1386 UDPPut(opcode);
1387  
1388 // write file name, including NULL.
1389 do
1390 {
1391 c = *fileName++;
1392 UDPPut(c);
1393 } while ( c != '\0' );
1394  
1395 // Write mode - always use octet or binay mode to transmit files.
1396 UDPPut('o');
1397 UDPPut('c');
1398 UDPPut('t');
1399 UDPPut('e');
1400 UDPPut('t');
1401 UDPPut(0);
1402  
1403 // Transmit it.
1404 UDPFlush();
1405  
1406 // Reset data block length.
1407 MutExVar.group2._tftpBlockLength.Val = 0;
1408 }
1409  
1410 #if defined(__18CXX)
1411 static void _TFTPSendROMFileName(TFTP_OPCODE opcode, ROM BYTE *fileName)
1412 {
1413 BYTE c;
1414  
1415 // Select the proper UDP socket and wait until we can write to it
1416 while(!UDPIsPutReady(_tftpSocket));
1417  
1418 // Write opCode
1419 UDPPut(0);
1420 UDPPut(opcode);
1421  
1422 // write file name, including NULL.
1423 do
1424 {
1425 c = *fileName++;
1426 UDPPut(c);
1427 } while ( c != '\0' );
1428  
1429 // Write mode - always use octet or binay mode to transmit files.
1430 UDPPut('o');
1431 UDPPut('c');
1432 UDPPut('t');
1433 UDPPut('e');
1434 UDPPut('t');
1435 UDPPut(0);
1436  
1437 // Transmit it.
1438 UDPFlush();
1439  
1440 // Reset data block length.
1441 MutExVar.group2._tftpBlockLength.Val = 0;
1442 }
1443 #endif
1444  
1445 static void _TFTPSendAck(WORD_VAL blockNumber)
1446 {
1447 // Write opCode.
1448 UDPPut(0);
1449 UDPPut(TFTP_OPCODE_ACK);
1450  
1451 // Write block number for this ack.
1452 UDPPut(blockNumber.v[1]);
1453 UDPPut(blockNumber.v[0]);
1454  
1455 // Transmit it.
1456 UDPFlush();
1457 }
1458  
1459  
1460  
1461 #endif //#if defined(STACK_USE_TFTP_CLIENT)
{BLAME END}
{FOOTER START}

Powered by WebSVN v2.8.3