Tom Martins
/
Probleme_implementation_lwip2
test public
Fork of Probleme_implementation_lwip by
Diff: porttcp.cpp
- Revision:
- 1:a3ee8cb24540
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/porttcp.cpp Mon Jul 02 14:36:46 2018 +0000 @@ -0,0 +1,332 @@ +/* + * 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.2 2006/09/04 14:39:20 wolti Exp $ + */ + +/* ----------------------- System includes ----------------------------------*/ +#include <stdio.h> +#include "string.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 -----------------------------*/ +BOOL +xMBTCPPortInit( 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; +} + +void +prvvMBPortReleaseClient( struct tcp_pcb *pxPCB ) +{ + if( pxPCB != NULL ) + { + if( tcp_close( pxPCB ) != ERR_OK ) + { + tcp_abort( pxPCB ); + } + // vPortEnterCritical( ); + 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; + } + //vPortExitCritical( ); + } +} +void +vMBTCPPortClose( ) +{ + /* Shutdown any open client sockets. */ + prvvMBPortReleaseClient( pxPCBClient ); + + /* Shutdown or listening socket. */ + prvvMBPortReleaseClient( pxPCBListen ); + + /* Release resources for the event queue. */ + vMBPortEventClose( ); +} + +void +vMBTCPPortDisable( void ) +{ + prvvMBPortReleaseClient( pxPCBClient ); +} + +err_t +prvxMBTCPPortAccept( 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. */ +void +prvvMBTCPPortError( void *pvArg, err_t xErr ) +{ + struct tcp_pcb *pxPCB = (struct tcp_pcb *)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_t +prvxMBTCPPortReceive( void *pvArg, struct tcp_pcb *pxPCB, struct pbuf *p, err_t xErr ) +{ + USHORT usLength; + + err_t error = xErr; + + if( error != ERR_OK ) + { + return error; + } + + /* 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( (UCHAR*)"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; +} + +BOOL +xMBTCPPortGetRequest( UCHAR ** ppucMBTCPFrame, USHORT * usTCPLength ) +{ + *ppucMBTCPFrame = &aucTCPBuf[0]; + *usTCPLength = usTCPBufPos; + + /* Reset the buffer. */ + usTCPBufPos = 0; + return TRUE; +} + +BOOL +xMBTCPPortSendResponse( 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, TCP_WRITE_FLAG_COPY ) == ERR_OK ) + { +#ifdef MB_TCP_DEBUG + prvvMBTCPLogFrame( (UCHAR*)"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; +} +