Modbus RTU/ASCII/TCP with lwip TCP working partial, but with errors (retransmitions)
Dependencies: EthernetNetIf mbed
porttcp.cpp
00001 /* 00002 * FreeModbus Libary: lwIP Port 00003 * Copyright (C) 2006 Christian Walter <wolti@sil.at> 00004 * 00005 * This library is free software; you can redistribute it and/or 00006 * modify it under the terms of the GNU Lesser General Public 00007 * License as published by the Free Software Foundation; either 00008 * version 2.1 of the License, or (at your option) any later version. 00009 * 00010 * This library is distributed in the hope that it will be useful, 00011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00013 * Lesser General Public License for more details. 00014 * 00015 * You should have received a copy of the GNU Lesser General Public 00016 * License along with this library; if not, write to the Free Software 00017 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 00018 * 00019 * File: $Id: porttcp.c,v 1.1 2006/08/30 23:18:07 wolti Exp $ 00020 */ 00021 #include "mbed.h" // Cam 00022 00023 extern DigitalOut RXLed; 00024 extern DigitalOut TXLed; 00025 extern Timeout RXTimeout; 00026 extern Timeout TXTimeout; 00027 00028 void RXTimeoutFunc(void); 00029 void TXTimeoutFunc(void); 00030 00031 /* ----------------------- System includes ----------------------------------*/ 00032 #include <stdio.h> 00033 #include <string.h> 00034 00035 #include "port.h" 00036 00037 /* ----------------------- lwIP includes ------------------------------------*/ 00038 #include "lwip/api.h" 00039 #include "lwip/tcp.h" 00040 00041 /* ----------------------- Modbus includes ----------------------------------*/ 00042 #include "mb.h" 00043 #include "mbport.h" 00044 00045 /* ----------------------- MBAP Header --------------------------------------*/ 00046 #define MB_TCP_UID 6 00047 #define MB_TCP_LEN 4 00048 #define MB_TCP_FUNC 7 00049 00050 /* ----------------------- Defines -----------------------------------------*/ 00051 #define MB_TCP_DEFAULT_PORT 502 /* TCP listening port. */ 00052 #define MB_TCP_BUF_SIZE ( 256 + 7 ) /* Must hold a complete Modbus TCP frame. */ 00053 00054 /* ----------------------- Prototypes ---------------------------------------*/ 00055 void vMBPortEventClose( void ); 00056 #ifdef MB_TCP_DEBUG 00057 void vMBPortLog( eMBPortLogLevel eLevel, const CHAR * szModule, 00058 const CHAR * szFmt, ... ); 00059 #endif 00060 00061 /* ----------------------- Static variables ---------------------------------*/ 00062 static struct tcp_pcb *pxPCBListen; 00063 static struct tcp_pcb *pxPCBClient; 00064 00065 static UCHAR aucTCPBuf[MB_TCP_BUF_SIZE]; 00066 static USHORT usTCPBufPos; 00067 00068 /* ----------------------- Static functions ---------------------------------*/ 00069 static err_t prvxMBTCPPortAccept( void *pvArg, struct tcp_pcb *pxPCB, err_t xErr ); 00070 static err_t prvxMBTCPPortReceive( void *pvArg, struct tcp_pcb *pxPCB, struct pbuf *p, 00071 err_t xErr ); 00072 static void prvvMBTCPPortError( void *pvArg, err_t xErr ); 00073 00074 /* ----------------------- Begin implementation -----------------------------*/ 00075 BOOL 00076 xMBTCPPortInit( USHORT usTCPPort ) 00077 { 00078 struct tcp_pcb *pxPCBListenNew, *pxPCBListenOld; 00079 BOOL bOkay = FALSE; 00080 USHORT usPort; 00081 00082 if( usTCPPort == 0 ) 00083 { 00084 usPort = MB_TCP_DEFAULT_PORT; 00085 } 00086 else 00087 { 00088 usPort = ( USHORT ) usTCPPort; 00089 } 00090 00091 if( ( pxPCBListenNew = pxPCBListenOld = tcp_new( ) ) == NULL ) 00092 { 00093 /* Can't create TCP socket. */ 00094 bOkay = FALSE; 00095 } 00096 else if( tcp_bind( pxPCBListenNew, IP_ADDR_ANY, ( u16_t ) usPort ) != ERR_OK ) 00097 { 00098 /* Bind failed - Maybe illegal port value or in use. */ 00099 ( void )tcp_close( pxPCBListenOld ); 00100 bOkay = FALSE; 00101 } 00102 else if( ( pxPCBListenNew = tcp_listen( pxPCBListenNew ) ) == NULL ) 00103 { 00104 ( void )tcp_close( pxPCBListenOld ); 00105 bOkay = FALSE; 00106 } 00107 else 00108 { 00109 /* Register callback function for new clients. */ 00110 tcp_accept( pxPCBListenNew, prvxMBTCPPortAccept ); 00111 00112 /* Everything okay. Set global variable. */ 00113 pxPCBListen = pxPCBListenNew; 00114 00115 #ifdef MB_TCP_DEBUG 00116 vMBPortLog( MB_LOG_DEBUG, "MBTCP-ACCEPT", "Protocol stack ready.\r\n" ); 00117 #endif 00118 } 00119 bOkay = TRUE; 00120 return bOkay; 00121 } 00122 00123 void 00124 prvvMBPortReleaseClient( struct tcp_pcb *pxPCB ) 00125 { 00126 if( pxPCB != NULL ) 00127 { 00128 if( tcp_close( pxPCB ) != ERR_OK ) 00129 { 00130 tcp_abort( pxPCB ); 00131 } 00132 if( pxPCB == pxPCBClient ) 00133 { 00134 #ifdef MB_TCP_DEBUG 00135 vMBPortLog( MB_LOG_DEBUG, "MBTCP-CLOSE", "Closed connection to %d.%d.%d.%d.\r\n", 00136 ip4_addr1( &( pxPCB->remote_ip ) ), 00137 ip4_addr2( &( pxPCB->remote_ip ) ), 00138 ip4_addr3( &( pxPCB->remote_ip ) ), ip4_addr4( &( pxPCB->remote_ip ) ) ); 00139 #endif 00140 pxPCBClient = NULL; 00141 } 00142 if( pxPCB == pxPCBListen ) 00143 { 00144 pxPCBListen = NULL; 00145 } 00146 } 00147 } 00148 void 00149 vMBTCPPortClose( ) 00150 { 00151 /* Shutdown any open client sockets. */ 00152 prvvMBPortReleaseClient( pxPCBClient ); 00153 00154 /* Shutdown or listening socket. */ 00155 prvvMBPortReleaseClient( pxPCBListen ); 00156 00157 /* Release resources for the event queue. */ 00158 // vMBPortEventClose( ); 00159 } 00160 00161 void 00162 vMBTCPPortDisable( void ) 00163 { 00164 prvvMBPortReleaseClient( pxPCBClient ); 00165 } 00166 00167 err_t 00168 prvxMBTCPPortAccept( void *pvArg, struct tcp_pcb *pxPCB, err_t xErr ) 00169 { 00170 err_t error; 00171 00172 if( xErr != ERR_OK ) 00173 { 00174 return xErr; 00175 } 00176 00177 /* We can handle only one client. */ 00178 if( pxPCBClient == NULL ) 00179 { 00180 /* Register the client. */ 00181 pxPCBClient = pxPCB; 00182 00183 /* Set up the receive function prvxMBTCPPortReceive( ) to be called when data 00184 * arrives. 00185 */ 00186 tcp_recv( pxPCB, prvxMBTCPPortReceive ); 00187 00188 /* Register error handler. */ 00189 tcp_err( pxPCB, prvvMBTCPPortError ); 00190 00191 /* Set callback argument later used in the error handler. */ 00192 tcp_arg( pxPCB, pxPCB ); 00193 00194 /* Reset the buffers and state variables. */ 00195 usTCPBufPos = 0; 00196 00197 #ifdef MB_TCP_DEBUG 00198 vMBPortLog( MB_LOG_DEBUG, "MBTCP-ACCEPT", "Accepted new client %d.%d.%d.%d\r\n", 00199 ip4_addr1( &( pxPCB->remote_ip ) ), 00200 ip4_addr2( &( pxPCB->remote_ip ) ), 00201 ip4_addr3( &( pxPCB->remote_ip ) ), ip4_addr4( &( pxPCB->remote_ip ) ) ); 00202 #endif 00203 00204 error = ERR_OK; 00205 } 00206 else 00207 { 00208 prvvMBPortReleaseClient( pxPCB ); 00209 error = ERR_OK; 00210 } 00211 return error; 00212 } 00213 00214 /* Called in case of an unrecoverable error. In any case we drop the client 00215 * connection. */ 00216 void 00217 prvvMBTCPPortError( void *pvArg, err_t xErr ) 00218 { 00219 struct tcp_pcb *pxPCB = (tcp_pcb*)&pvArg; 00220 00221 if( pxPCB != NULL ) 00222 { 00223 #ifdef MB_TCP_DEBUG 00224 vMBPortLog( MB_LOG_DEBUG, "MBTCP-ERROR", "Error with client connection! Droping it.\r\n" ); 00225 #endif 00226 prvvMBPortReleaseClient( pxPCB ); 00227 } 00228 } 00229 00230 err_t 00231 prvxMBTCPPortReceive( void *pvArg, struct tcp_pcb *pxPCB, struct pbuf *p, err_t xErr ) 00232 { 00233 USHORT usLength; 00234 00235 err_t error; 00236 00237 if( xErr != ERR_OK ) 00238 { 00239 return xErr; 00240 } 00241 00242 /* If pbuf is NULL then remote end has closed connection. */ 00243 if( p == NULL ) 00244 { 00245 prvvMBPortReleaseClient( pxPCB ); 00246 return ERR_OK; 00247 } 00248 00249 /* Acknowledge that we have received the data bytes. */ 00250 // tcp_recved( pxPCB, p->len ); 00251 00252 RXLed = 1; 00253 RXTimeout.attach(RXTimeoutFunc, 0.020); 00254 00255 /* Check for internal buffer overflow. In case of an error drop the 00256 * client. */ 00257 if( ( usTCPBufPos + p->len ) >= MB_TCP_BUF_SIZE ) 00258 { 00259 prvvMBPortReleaseClient( pxPCB ); 00260 error = ERR_OK; 00261 } 00262 else 00263 { 00264 memcpy( &aucTCPBuf[usTCPBufPos], p->payload, p->len ); 00265 usTCPBufPos += p->len; 00266 00267 /* If we have received the MBAP header we can analyze it and calculate 00268 * the number of bytes left to complete the current request. If complete 00269 * notify the protocol stack. 00270 */ 00271 if( usTCPBufPos >= MB_TCP_FUNC ) 00272 { 00273 /* Length is a byte count of Modbus PDU (function code + data) and the 00274 * unit identifier. */ 00275 usLength = aucTCPBuf[MB_TCP_LEN] << 8U; 00276 usLength |= aucTCPBuf[MB_TCP_LEN + 1]; 00277 00278 /* Is the frame already complete. */ 00279 if( usTCPBufPos < ( MB_TCP_UID + usLength ) ) 00280 { 00281 } 00282 else if( usTCPBufPos == ( MB_TCP_UID + usLength ) ) 00283 { 00284 #ifdef MB_TCP_DEBUG 00285 prvvMBTCPLogFrame( "MBTCP-RECV", &aucTCPBuf[0], usTCPBufPos ); 00286 #endif 00287 ( void )xMBPortEventPost( EV_FRAME_RECEIVED ); 00288 } 00289 else 00290 { 00291 #ifdef MB_TCP_DEBUG 00292 vMBPortLog( MB_LOG_DEBUG, "MBTCP-ERROR", 00293 "Received to many bytes! Droping client.\r\n" ); 00294 #endif 00295 /* This should not happen. We can't deal with such a client and 00296 * drop the connection for security reasons. 00297 */ 00298 prvvMBPortReleaseClient( pxPCB ); 00299 } 00300 } 00301 } 00302 pbuf_free( p ); 00303 return error; 00304 } 00305 00306 BOOL 00307 xMBTCPPortGetRequest( UCHAR ** ppucMBTCPFrame, USHORT * usTCPLength ) 00308 { 00309 *ppucMBTCPFrame = &aucTCPBuf[0]; 00310 *usTCPLength = usTCPBufPos; 00311 00312 /* Reset the buffer. */ 00313 usTCPBufPos = 0; 00314 return TRUE; 00315 } 00316 00317 BOOL 00318 xMBTCPPortSendResponse( const UCHAR * pucMBTCPFrame, USHORT usTCPLength ) 00319 { 00320 BOOL bFrameSent = FALSE; 00321 00322 if( pxPCBClient ) 00323 { 00324 /* Make sure we can send the packet. */ 00325 assert( tcp_sndbuf( pxPCBClient ) >= usTCPLength ); 00326 00327 // if( tcp_write( pxPCBClient, pucMBTCPFrame, ( u16_t ) usTCPLength, NETCONN_COPY ) == ERR_OK ) 00328 if( tcp_write( pxPCBClient, pucMBTCPFrame, ( u16_t ) usTCPLength, 1 ) == ERR_OK ) 00329 { 00330 #ifdef MB_TCP_DEBUG 00331 prvvMBTCPLogFrame( "MBTCP-SENT", &aucTCPBuf[0], usTCPLength ); 00332 #endif 00333 /* Make sure data gets sent immediately. */ 00334 ( void )tcp_output( pxPCBClient ); 00335 bFrameSent = TRUE; 00336 00337 TXLed = 1; 00338 TXTimeout.attach(TXTimeoutFunc, 0.020); 00339 } 00340 else 00341 { 00342 /* Drop the connection in case of an write error. */ 00343 prvvMBPortReleaseClient( pxPCBClient ); 00344 } 00345 } 00346 return bFrameSent; 00347 }
Generated on Tue Jul 12 2022 21:29:48 by 1.7.2