📄 tftpc.c
字号:
/*********************************************************************
*
* TFTP Client module for Microchip TCP/IP Stack
*
*********************************************************************
* FileName: TFTPc.c
* Dependencies: TFTPc.h
* UDP.h
* Processor: PIC18
* Complier: MCC18 v1.00.50 or higher
* HITECH PICC-18 V8.10PL1 or higher
* Company: Microchip Technology, Inc.
*
* Software License Agreement
*
* This software is owned by Microchip Technology Inc. ("Microchip")
* and is supplied to you for use exclusively as described in the
* associated software agreement. This software is protected by
* software and other intellectual property laws. Any use in
* violation of the software license may subject the user to criminal
* sanctions as well as civil liability. Copyright 2006 Microchip
* Technology Inc. All rights reserved.
*
* This software is provided "AS IS." MICROCHIP DISCLAIMS ALL
* WARRANTIES, EXPRESS, IMPLIED, STATUTORY OR OTHERWISE, NOT LIMITED
* TO MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND
* INFRINGEMENT. Microchip shall in no event be liable for special,
* incidental, or consequential damages.
*
* Author Date Comment
*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Nilesh Rajbharti 8/5/03 Original (Rev 1.0)
********************************************************************/
#if defined(WIN32)
#include <stdio.h>
#define TFTP_DEBUG
#endif
#include "tftpc.h"
#include "arptsk.h"
#include "tick.h"
#define TFTP_CLIENT_PORT 65352L // Some unique port on this
// device.
#define TFTP_SERVER_PORT (69L)
#define TFTP_BLOCK_SIZE (0x200L) // 512 bytes
#define TFTP_BLOCK_SIZE_MSB (0x02)
typedef enum _TFTP_STATE
{
SM_TFTP_WAIT = 0,
SM_TFTP_READY,
SM_TFTP_WAIT_FOR_DATA,
SM_TFTP_WAIT_FOR_ACK,
SM_TFTP_DUPLICATE_ACK,
SM_TFTP_SEND_ACK,
SM_TFTP_SEND_LAST_ACK
} TFTP_STATE;
typedef enum _TFTP_OPCODE
{
TFTP_OPCODE_RRQ = 1, // Get
TFTP_OPCODE_WRQ, // Put
TFTP_OPCODE_DATA, // Actual data
TFTP_OPCODE_ACK, // Ack for Get/Put
TFTP_OPCODE_ERROR // Error
} TFTP_OPCODE;
UDP_SOCKET _tftpSocket; // TFTP Socket for TFTP server link
WORD _tftpError;
static struct _MutExVar // modified by lfei union to struct
{
struct
{
NODE_INFO _hostInfo;
}__attribute__ ((packed)) group1;
struct
{
WORD_VAL _tftpBlockNumber;
WORD_VAL _tftpDuplicateBlock;
WORD_VAL _tftpBlockLength;
}__attribute__ ((packed)) group2;
}__attribute__ ((packed)) MutExVar; // Mutually Exclusive variable groups to conserve RAM.
static TFTP_STATE _tftpState;
static BYTE _tftpRetries;
static TICK _tftpStartTick;
static union
{
struct
{
unsigned int bIsFlushed : 1;
unsigned int bIsAcked : 1;
unsigned int bIsClosed : 1;
unsigned int bIsClosing : 1;
unsigned int bIsReading : 1;
}__attribute__ ((packed)) bits;
BYTE Val;
}__attribute__ ((packed)) _tftpFlags;
// Private helper functions
static void _TFTPSendFileName(TFTP_OPCODE command, char *fileName);
static void _TFTPSendAck(WORD_VAL blockNumber);
// Blank out DEBUG statements if not enabled.
#if defined(TFTP_DEBUG)
#define DEBUG(a) a
#else
#define DEBUG(a)
#endif
/*********************************************************************
* Function: void TFTPOpen(IP_ADDR *host)
*
* PreCondition: UDP module is already initialized
* and at least one UDP socket is available.
*
* Input: host - IP address of remote TFTP server
*
* Output: None
*
* Side Effects: None
*
* Overview: Initiates ARP for given host and prepares
* TFTP module for next sequence of function calls.
*
* Note: Use TFTPIsOpened() to check if a connection was
* successfully opened or not.
*
********************************************************************/
void TFTPOpen(IP_ADDR *host)
{
/* commented by lfei 2007/03/05 ****
DEBUG(printf("Opening a connection..."));
********************************/
// print1("Setup a connection with remote server !\n");
// Remember this address locally.
MutExVar.group1._hostInfo.IPAddr.Val = host->Val;
// Initiate ARP resolution.
ARPResolve(&MutExVar.group1._hostInfo.IPAddr);
// Wait for ARP to get resolved.
_tftpState = SM_TFTP_WAIT;
// Mark this as start tick to detect timeout condition.
_tftpStartTick = TickGet();
// Forget about all previous attempts.
_tftpRetries = 1;
}
/*********************************************************************
* Function: TFTP_RESULT TFTPIsOpened(void)
*
* PreCondition: TFTPOpen() is already called.
*
* Input: None
*
* Output: TFTP_OK if previous call to TFTPOpen is complete
*
* TFTP_TIMEOUT if remote host did not respond to
* previous ARP request.
*
* TFTP_NOT_READY if remote has still not responded
* and timeout has not expired.
*
* Side Effects: None
*
* Overview: Waits for ARP reply and opens a UDP socket
* to perform further TFTP operations.
*
* Note: Once opened, application may keep TFTP socket
* open and future TFTP operations.
* If TFTPClose() is called to close the connection
* TFTPOpen() must be called again before performing
* any other TFTP operations.
********************************************************************/
TFTP_RESULT TFTPIsOpened(void)
{
switch(_tftpState)
{
default:
DEBUG(printf("Resolving remote IP...\n"));
// Check to see if adddress is resolved.
if ( ARPIsResolved(&MutExVar.group1._hostInfo.IPAddr,
&MutExVar.group1._hostInfo.MACAddr) )
{
_tftpSocket = UDPOpen(TFTP_CLIENT_PORT,
&MutExVar.group1._hostInfo,
TFTP_SERVER_PORT);
_tftpState = SM_TFTP_READY;
}
else
break;
case SM_TFTP_READY:
// Wait for UDP to be ready. Immediately after this user will
// may TFTPGetFile or TFTPPutFile and we have to make sure that
// UDP is read to transmit. These functions do not check for
// UDP to get ready.
if ( UDPIsPutReady(_tftpSocket) )
return TFTP_OK;
}
// Make sure that we do not do this forever.
if ( TickGetDiff(TickGet(), _tftpStartTick) >= TFTP_ARP_TIMEOUT_VAL )
{
_tftpStartTick = TickGet();
// Forget about all previous attempts.
_tftpRetries = 1;
return TFTP_TIMEOUT;
}
return TFTP_NOT_READY;
}
/*********************************************************************
* Function: void TFTPOpenFile(char *fileName,
* TFTP_FILE_MODE mode)
*
* PreCondition: TFPTIsFileOpenReady() = TRUE
*
* Input: fileName - File name that is to be opened.
* mode - Mode of file access
* Must be
* TFTP_FILE_MODE_READ for read
* TFTP_FILE_MODE_WRITE for write
*
* Output: None
*
* Side Effects: None
*
* Overview: Prepares and sends TFTP file name and mode packet.
*
* Note: By default, this funciton uses "octet" or binary
* mode of file transfer.
* Use TFTPIsFileOpened() to check if file is
* ready to be read or written.
********************************************************************/
void TFTPOpenFile(char *fileName, TFTP_FILE_MODE mode)
{
// Set TFTP Server port. If this is the first call, remotePort
// must have been set by TFTPOpen(). But if caller does not do
// TFTPOpen for every transfer, we must reset remote port.
// Most TFTP servers accept connection TFTP port. but once
// connection is established, they use other temp. port,
UDPSocketInfo[_tftpSocket].remotePort = TFTP_SERVER_PORT;
// Tell remote server about our intention.
_TFTPSendFileName(mode, fileName);
// Clear all flags.
_tftpFlags.Val = 0;
// Remember start tick for this operation.
_tftpStartTick = TickGet();
// Depending on mode of operation, remote server will respond with
// specific block number.
if ( mode == TFTP_FILE_MODE_READ )
{
// Remember that we are reading a file.
_tftpFlags.bits.bIsReading = TRUE;
// For read operation, server would respond with data block of 1.
MutExVar.group2._tftpBlockNumber.Val = 1;
// Next packet would be the data packet.
_tftpState = SM_TFTP_WAIT_FOR_DATA;
}
else
{
// Remember that we are writing a file.
_tftpFlags.bits.bIsReading = FALSE;
// For write operation, server would respond with data block of 0.
MutExVar.group2._tftpBlockNumber.Val = 0;
// Next packet would be the ACK packet.
_tftpState = SM_TFTP_WAIT_FOR_ACK;
}
}
/*********************************************************************
* Function: TFTP_RESULT TFTPIsFileOpened(void)
*
* PreCondition: TFTPOpenFile() is called.
*
* Input: None
*
* Output: TFTP_OK if file is ready to be read or written
*
* TFTP_RETRY if previous attempt was timed out
* needs to be retried.
*
* TFTP_TIMEOUT if all attempts were exhausted.
*
* TFTP_NOT_ERROR if remote server responded with
* error
*
* TFTP_NOT_READY if file is not yet opened.
*
* Side Effects: None
*
* Overview: Waits for remote server response regarding
* previous attempt to open file.
* If no response is received within specified
* timeout, fnction returns with TFTP_RETRY
* and application logic must issue another
* TFTPFileOpen().
*
* Note: None
********************************************************************/
TFTP_RESULT TFTPIsFileOpened(void)
{
if ( _tftpFlags.bits.bIsReading )
return TFTPIsGetReady();
else
return TFTPIsPutReady();
}
/*********************************************************************
* Function: TFTP_RESULT TFTPIsGetReady(void)
*
* PreCondition: TFTPOpenFile() is called with TFTP_FILE_MODE_READ
* and TFTPIsFileOpened() returned with TRUE.
*
* Input: None
*
* Output: TFTP_OK if it there is more data byte available
* to read
*
* TFTP_TIMEOUT if timeout occurred waiting for
* new data.
*
* TFTP_END_OF_FILE if end of file has reached.
*
* TFTP_ERROR if remote server returned ERROR.
* Actual error code may be read by calling
* TFTPGetError()
*
* TFTP_NOT_READY if still waiting for new data.
*
* Side Effects: None
*
* Overview: Waits for data block. If data block does not
* arrive within specified timeout, it automatically
* sends out ack for previous block to remind
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -