📄 porttcp.c
字号:
/* * FreeModbus Libary: lwIP Port * Copyright (C) 2006 Christian Walter <wolti@sil.at> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * File: $Id: porttcp.c,v 1.1 2006/08/30 23:18:07 wolti Exp $ *//* ----------------------- System includes ----------------------------------*/#include <stdio.h>#include "port.h"/* ----------------------- lwIP includes ------------------------------------*/#include "lwip/api.h"#include "lwip/tcp.h"/* ----------------------- Modbus includes ----------------------------------*/#include "mb.h"#include "mbport.h"/* ----------------------- MBAP Header --------------------------------------*/#define MB_TCP_UID 6#define MB_TCP_LEN 4#define MB_TCP_FUNC 7/* ----------------------- Defines -----------------------------------------*/#define MB_TCP_DEFAULT_PORT 502 /* TCP listening port. */#define MB_TCP_BUF_SIZE ( 256 + 7 ) /* Must hold a complete Modbus TCP frame. *//* ----------------------- Prototypes ---------------------------------------*/void vMBPortEventClose( void );void vMBPortLog( eMBPortLogLevel eLevel, const CHAR * szModule, const CHAR * szFmt, ... );/* ----------------------- Static variables ---------------------------------*/static struct tcp_pcb *pxPCBListen;static struct tcp_pcb *pxPCBClient;static UCHAR aucTCPBuf[MB_TCP_BUF_SIZE];static USHORT usTCPBufPos;/* ----------------------- Static functions ---------------------------------*/static err_t prvxMBTCPPortAccept( void *pvArg, struct tcp_pcb *pxPCB, err_t xErr );static err_t prvxMBTCPPortReceive( void *pvArg, struct tcp_pcb *pxPCB, struct pbuf *p, err_t xErr );static void prvvMBTCPPortError( void *pvArg, err_t xErr );/* ----------------------- Begin implementation -----------------------------*/BOOLxMBTCPPortInit( USHORT usTCPPort ){ struct tcp_pcb *pxPCBListenNew, *pxPCBListenOld; BOOL bOkay = FALSE; USHORT usPort; if( usTCPPort == 0 ) { usPort = MB_TCP_DEFAULT_PORT; } else { usPort = ( USHORT ) usTCPPort; } if( ( pxPCBListenNew = pxPCBListenOld = tcp_new( ) ) == NULL ) { /* Can't create TCP socket. */ bOkay = FALSE; } else if( tcp_bind( pxPCBListenNew, IP_ADDR_ANY, ( u16_t ) usPort ) != ERR_OK ) { /* Bind failed - Maybe illegal port value or in use. */ ( void )tcp_close( pxPCBListenOld ); bOkay = FALSE; } else if( ( pxPCBListenNew = tcp_listen( pxPCBListenNew ) ) == NULL ) { ( void )tcp_close( pxPCBListenOld ); bOkay = FALSE; } else { /* Register callback function for new clients. */ tcp_accept( pxPCBListenNew, prvxMBTCPPortAccept ); /* Everything okay. Set global variable. */ pxPCBListen = pxPCBListenNew;#ifdef MB_TCP_DEBUG vMBPortLog( MB_LOG_DEBUG, "MBTCP-ACCEPT", "Protocol stack ready.\r\n" );#endif } bOkay = TRUE; return bOkay;}voidprvvMBPortReleaseClient( struct tcp_pcb *pxPCB ){ if( pxPCB != NULL ) { if( tcp_close( pxPCB ) != ERR_OK ) { tcp_abort( pxPCB ); } if( pxPCB == pxPCBClient ) {#ifdef MB_TCP_DEBUG vMBPortLog( MB_LOG_DEBUG, "MBTCP-CLOSE", "Closed connection to %d.%d.%d.%d.\r\n", ip4_addr1( &( pxPCB->remote_ip ) ), ip4_addr2( &( pxPCB->remote_ip ) ), ip4_addr3( &( pxPCB->remote_ip ) ), ip4_addr4( &( pxPCB->remote_ip ) ) );#endif pxPCBClient = NULL; } if( pxPCB == pxPCBListen ) { pxPCBListen = NULL; } }}voidvMBTCPPortClose( ){ /* Shutdown any open client sockets. */ prvvMBPortReleaseClient( pxPCBClient ); /* Shutdown or listening socket. */ prvvMBPortReleaseClient( pxPCBListen ); /* Release resources for the event queue. */ vMBPortEventClose( );}voidvMBTCPPortDisable( void ){ prvvMBPortReleaseClient( pxPCBClient );}err_tprvxMBTCPPortAccept( void *pvArg, struct tcp_pcb *pxPCB, err_t xErr ){ err_t error; if( xErr != ERR_OK ) { return xErr; } /* We can handle only one client. */ if( pxPCBClient == NULL ) { /* Register the client. */ pxPCBClient = pxPCB; /* Set up the receive function prvxMBTCPPortReceive( ) to be called when data * arrives. */ tcp_recv( pxPCB, prvxMBTCPPortReceive ); /* Register error handler. */ tcp_err( pxPCB, prvvMBTCPPortError ); /* Set callback argument later used in the error handler. */ tcp_arg( pxPCB, pxPCB ); /* Reset the buffers and state variables. */ usTCPBufPos = 0;#ifdef MB_TCP_DEBUG vMBPortLog( MB_LOG_DEBUG, "MBTCP-ACCEPT", "Accepted new client %d.%d.%d.%d\r\n", ip4_addr1( &( pxPCB->remote_ip ) ), ip4_addr2( &( pxPCB->remote_ip ) ), ip4_addr3( &( pxPCB->remote_ip ) ), ip4_addr4( &( pxPCB->remote_ip ) ) );#endif error = ERR_OK; } else { prvvMBPortReleaseClient( pxPCB ); error = ERR_OK; } return error;}/* Called in case of an unrecoverable error. In any case we drop the client * connection. */voidprvvMBTCPPortError( void *pvArg, err_t xErr ){ struct tcp_pcb *pxPCB = pvArg; if( pxPCB != NULL ) {#ifdef MB_TCP_DEBUG vMBPortLog( MB_LOG_DEBUG, "MBTCP-ERROR", "Error with client connection! Droping it.\r\n" );#endif prvvMBPortReleaseClient( pxPCB ); }}err_tprvxMBTCPPortReceive( void *pvArg, struct tcp_pcb *pxPCB, struct pbuf *p, err_t xErr ){ USHORT usLength; err_t error; if( xErr != ERR_OK ) { return xErr; } /* If pbuf is NULL then remote end has closed connection. */ if( p == NULL ) { prvvMBPortReleaseClient( pxPCB ); return ERR_OK; } /* Acknowledge that we have received the data bytes. */ tcp_recved( pxPCB, p->len ); /* Check for internal buffer overflow. In case of an error drop the * client. */ if( ( usTCPBufPos + p->len ) >= MB_TCP_BUF_SIZE ) { prvvMBPortReleaseClient( pxPCB ); error = ERR_OK; } else { memcpy( &aucTCPBuf[usTCPBufPos], p->payload, p->len ); usTCPBufPos += p->len; /* If we have received the MBAP header we can analyze it and calculate * the number of bytes left to complete the current request. If complete * notify the protocol stack. */ if( usTCPBufPos >= MB_TCP_FUNC ) { /* Length is a byte count of Modbus PDU (function code + data) and the * unit identifier. */ usLength = aucTCPBuf[MB_TCP_LEN] << 8U; usLength |= aucTCPBuf[MB_TCP_LEN + 1]; /* Is the frame already complete. */ if( usTCPBufPos < ( MB_TCP_UID + usLength ) ) { } else if( usTCPBufPos == ( MB_TCP_UID + usLength ) ) {#ifdef MB_TCP_DEBUG prvvMBTCPLogFrame( "MBTCP-RECV", &aucTCPBuf[0], usTCPBufPos );#endif ( void )xMBPortEventPost( EV_FRAME_RECEIVED ); } else {#ifdef MB_TCP_DEBUG vMBPortLog( MB_LOG_DEBUG, "MBTCP-ERROR", "Received to many bytes! Droping client.\r\n" );#endif /* This should not happen. We can't deal with such a client and * drop the connection for security reasons. */ prvvMBPortReleaseClient( pxPCB ); } } } pbuf_free( p ); return error;}BOOLxMBTCPPortGetRequest( UCHAR ** ppucMBTCPFrame, USHORT * usTCPLength ){ *ppucMBTCPFrame = &aucTCPBuf[0]; *usTCPLength = usTCPBufPos; /* Reset the buffer. */ usTCPBufPos = 0; return TRUE;}BOOLxMBTCPPortSendResponse( const UCHAR * pucMBTCPFrame, USHORT usTCPLength ){ BOOL bFrameSent = FALSE; if( pxPCBClient ) { /* Make sure we can send the packet. */ assert( tcp_sndbuf( pxPCBClient ) >= usTCPLength ); if( tcp_write( pxPCBClient, pucMBTCPFrame, ( u16_t ) usTCPLength, NETCONN_COPY ) == ERR_OK ) {#ifdef MB_TCP_DEBUG prvvMBTCPLogFrame( "MBTCP-SENT", &aucTCPBuf[0], usTCPLength );#endif /* Make sure data gets sent immediately. */ ( void )tcp_output( pxPCBClient ); bFrameSent = TRUE; } else { /* Drop the connection in case of an write error. */ prvvMBPortReleaseClient( pxPCBClient ); } } return bFrameSent;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -