Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Fork of Modbus by
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.2 2006/09/04 14:39:20 wolti Exp $ 00020 */ 00021 00022 /* ----------------------- System includes ----------------------------------*/ 00023 #include <stdio.h> 00024 #include "string.h" 00025 00026 #include "port.h" 00027 00028 /* ----------------------- lwIP includes ------------------------------------*/ 00029 #include "lwip/api.h" 00030 #include "lwip/tcp.h" 00031 00032 /* ----------------------- Modbus includes ----------------------------------*/ 00033 #include "mb.h" 00034 #include "mbport.h" 00035 00036 /* ----------------------- MBAP Header --------------------------------------*/ 00037 #define MB_TCP_UID 6 00038 #define MB_TCP_LEN 4 00039 #define MB_TCP_FUNC 7 00040 00041 /* ----------------------- Defines -----------------------------------------*/ 00042 #define MB_TCP_DEFAULT_PORT 502 /* TCP listening port. */ 00043 #define MB_TCP_BUF_SIZE ( 256 + 7 ) /* Must hold a complete Modbus TCP frame. */ 00044 00045 /* ----------------------- Prototypes ---------------------------------------*/ 00046 void vMBPortEventClose( void ){}; 00047 void vMBPortLog( eMBPortLogLevel eLevel, const CHAR * szModule, 00048 const CHAR * szFmt, ... ); 00049 00050 /* ----------------------- Static variables ---------------------------------*/ 00051 static struct tcp_pcb *pxPCBListen; 00052 static struct tcp_pcb *pxPCBClient; 00053 00054 static UCHAR aucTCPBuf[MB_TCP_BUF_SIZE]; 00055 static USHORT usTCPBufPos; 00056 00057 /* ----------------------- Static functions ---------------------------------*/ 00058 static err_t prvxMBTCPPortAccept( void *pvArg, struct tcp_pcb *pxPCB, err_t xErr ); 00059 static err_t prvxMBTCPPortReceive( void *pvArg, struct tcp_pcb *pxPCB, struct pbuf *p, 00060 err_t xErr ); 00061 static void prvvMBTCPPortError( void *pvArg, err_t xErr ); 00062 00063 /* ----------------------- Begin implementation -----------------------------*/ 00064 BOOL 00065 xMBTCPPortInit( USHORT usTCPPort ) 00066 { 00067 struct tcp_pcb *pxPCBListenNew, *pxPCBListenOld; 00068 BOOL bOkay = FALSE; 00069 USHORT usPort; 00070 00071 if( usTCPPort == 0 ) 00072 { 00073 usPort = MB_TCP_DEFAULT_PORT; 00074 } 00075 else 00076 { 00077 usPort = ( USHORT ) usTCPPort; 00078 } 00079 00080 if( ( pxPCBListenNew = pxPCBListenOld = tcp_new( ) ) == NULL ) 00081 { 00082 /* Can't create TCP socket. */ 00083 bOkay = FALSE; 00084 } 00085 else if( tcp_bind( pxPCBListenNew, IP_ADDR_ANY, ( u16_t ) usPort ) != ERR_OK ) 00086 { 00087 /* Bind failed - Maybe illegal port value or in use. */ 00088 ( void )tcp_close( pxPCBListenOld ); 00089 bOkay = FALSE; 00090 } 00091 else if( ( pxPCBListenNew = tcp_listen( pxPCBListenNew ) ) == NULL ) 00092 { 00093 ( void )tcp_close( pxPCBListenOld ); 00094 bOkay = FALSE; 00095 } 00096 else 00097 { 00098 /* Register callback function for new clients. */ 00099 tcp_accept( pxPCBListenNew, prvxMBTCPPortAccept ); 00100 00101 /* Everything okay. Set global variable. */ 00102 pxPCBListen = pxPCBListenNew; 00103 00104 #ifdef MB_TCP_DEBUG 00105 vMBPortLog( MB_LOG_DEBUG, "MBTCP-ACCEPT", "Protocol stack ready.\r\n" ); 00106 #endif 00107 } 00108 bOkay = TRUE; 00109 return bOkay; 00110 } 00111 00112 void 00113 prvvMBPortReleaseClient( struct tcp_pcb *pxPCB ) 00114 { 00115 if( pxPCB != NULL ) 00116 { 00117 if( tcp_close( pxPCB ) != ERR_OK ) 00118 { 00119 tcp_abort( pxPCB ); 00120 } 00121 // vPortEnterCritical( ); 00122 if( pxPCB == pxPCBClient ) 00123 { 00124 #ifdef MB_TCP_DEBUG 00125 vMBPortLog( MB_LOG_DEBUG, "MBTCP-CLOSE", "Closed connection to %d.%d.%d.%d.\r\n", 00126 ip4_addr1( &( pxPCB->remote_ip ) ), 00127 ip4_addr2( &( pxPCB->remote_ip ) ), 00128 ip4_addr3( &( pxPCB->remote_ip ) ), ip4_addr4( &( pxPCB->remote_ip ) ) ); 00129 #endif 00130 pxPCBClient = NULL; 00131 } 00132 if( pxPCB == pxPCBListen ) 00133 { 00134 pxPCBListen = NULL; 00135 } 00136 //vPortExitCritical( ); 00137 } 00138 } 00139 void 00140 vMBTCPPortClose( ) 00141 { 00142 /* Shutdown any open client sockets. */ 00143 prvvMBPortReleaseClient( pxPCBClient ); 00144 00145 /* Shutdown or listening socket. */ 00146 prvvMBPortReleaseClient( pxPCBListen ); 00147 00148 /* Release resources for the event queue. */ 00149 vMBPortEventClose( ); 00150 } 00151 00152 void 00153 vMBTCPPortDisable( void ) 00154 { 00155 prvvMBPortReleaseClient( pxPCBClient ); 00156 } 00157 00158 err_t 00159 prvxMBTCPPortAccept( void *pvArg, struct tcp_pcb *pxPCB, err_t xErr ) 00160 { 00161 err_t error; 00162 00163 if( xErr != ERR_OK ) 00164 { 00165 return xErr; 00166 } 00167 00168 /* We can handle only one client. */ 00169 if( pxPCBClient == NULL ) 00170 { 00171 /* Register the client. */ 00172 pxPCBClient = pxPCB; 00173 00174 /* Set up the receive function prvxMBTCPPortReceive( ) to be called when data 00175 * arrives. 00176 */ 00177 tcp_recv( pxPCB, prvxMBTCPPortReceive ); 00178 00179 /* Register error handler. */ 00180 tcp_err( pxPCB, prvvMBTCPPortError ); 00181 00182 /* Set callback argument later used in the error handler. */ 00183 tcp_arg( pxPCB, pxPCB ); 00184 00185 /* Reset the buffers and state variables. */ 00186 usTCPBufPos = 0; 00187 00188 #ifdef MB_TCP_DEBUG 00189 vMBPortLog( MB_LOG_DEBUG, "MBTCP-ACCEPT", "Accepted new client %d.%d.%d.%d\r\n", 00190 ip4_addr1( &( pxPCB->remote_ip ) ), 00191 ip4_addr2( &( pxPCB->remote_ip ) ), 00192 ip4_addr3( &( pxPCB->remote_ip ) ), ip4_addr4( &( pxPCB->remote_ip ) ) ); 00193 #endif 00194 00195 error = ERR_OK; 00196 } 00197 else 00198 { 00199 prvvMBPortReleaseClient( pxPCB ); 00200 error = ERR_OK; 00201 } 00202 return error; 00203 } 00204 00205 /* Called in case of an unrecoverable error. In any case we drop the client 00206 * connection. */ 00207 void 00208 prvvMBTCPPortError( void *pvArg, err_t xErr ) 00209 { 00210 struct tcp_pcb *pxPCB = (struct tcp_pcb *)pvArg; 00211 00212 if( pxPCB != NULL ) 00213 { 00214 #ifdef MB_TCP_DEBUG 00215 vMBPortLog( MB_LOG_DEBUG, "MBTCP-ERROR", "Error with client connection! Droping it.\r\n" ); 00216 #endif 00217 prvvMBPortReleaseClient( pxPCB ); 00218 } 00219 } 00220 00221 err_t 00222 prvxMBTCPPortReceive( void *pvArg, struct tcp_pcb *pxPCB, struct pbuf *p, err_t xErr ) 00223 { 00224 USHORT usLength; 00225 00226 err_t error = xErr; 00227 00228 if( error != ERR_OK ) 00229 { 00230 return error; 00231 } 00232 00233 /* If pbuf is NULL then remote end has closed connection. */ 00234 if( p == NULL ) 00235 { 00236 prvvMBPortReleaseClient( pxPCB ); 00237 return ERR_OK; 00238 } 00239 00240 /* Acknowledge that we have received the data bytes. */ 00241 tcp_recved( pxPCB, p->len ); 00242 00243 /* Check for internal buffer overflow. In case of an error drop the 00244 * client. */ 00245 if( ( usTCPBufPos + p->len ) >= MB_TCP_BUF_SIZE ) 00246 { 00247 prvvMBPortReleaseClient( pxPCB ); 00248 error = ERR_OK; 00249 } 00250 else 00251 { 00252 memcpy( &aucTCPBuf[usTCPBufPos], p->payload, p->len ); 00253 usTCPBufPos += p->len; 00254 00255 /* If we have received the MBAP header we can analyze it and calculate 00256 * the number of bytes left to complete the current request. If complete 00257 * notify the protocol stack. 00258 */ 00259 if( usTCPBufPos >= MB_TCP_FUNC ) 00260 { 00261 /* Length is a byte count of Modbus PDU (function code + data) and the 00262 * unit identifier. */ 00263 usLength = aucTCPBuf[MB_TCP_LEN] << 8U; 00264 usLength |= aucTCPBuf[MB_TCP_LEN + 1]; 00265 00266 /* Is the frame already complete. */ 00267 if( usTCPBufPos < ( MB_TCP_UID + usLength ) ) 00268 { 00269 } 00270 else if( usTCPBufPos == ( MB_TCP_UID + usLength ) ) 00271 { 00272 #ifdef MB_TCP_DEBUG 00273 prvvMBTCPLogFrame( (UCHAR*)"MBTCP-RECV", &aucTCPBuf[0], usTCPBufPos ); 00274 #endif 00275 ( void )xMBPortEventPost( EV_FRAME_RECEIVED ); 00276 } 00277 else 00278 { 00279 #ifdef MB_TCP_DEBUG 00280 vMBPortLog( MB_LOG_DEBUG, "MBTCP-ERROR", 00281 "Received to many bytes! Droping client.\r\n" ); 00282 #endif 00283 /* This should not happen. We can't deal with such a client and 00284 * drop the connection for security reasons. 00285 */ 00286 prvvMBPortReleaseClient( pxPCB ); 00287 } 00288 } 00289 } 00290 pbuf_free( p ); 00291 return error; 00292 } 00293 00294 BOOL 00295 xMBTCPPortGetRequest( UCHAR ** ppucMBTCPFrame, USHORT * usTCPLength ) 00296 { 00297 *ppucMBTCPFrame = &aucTCPBuf[0]; 00298 *usTCPLength = usTCPBufPos; 00299 00300 /* Reset the buffer. */ 00301 usTCPBufPos = 0; 00302 return TRUE; 00303 } 00304 00305 BOOL 00306 xMBTCPPortSendResponse( const UCHAR * pucMBTCPFrame, USHORT usTCPLength ) 00307 { 00308 BOOL bFrameSent = FALSE; 00309 00310 if( pxPCBClient ) 00311 { 00312 /* Make sure we can send the packet. */ 00313 assert( tcp_sndbuf( pxPCBClient ) >= usTCPLength ); 00314 00315 if( tcp_write( pxPCBClient, pucMBTCPFrame, ( u16_t ) usTCPLength, TCP_WRITE_FLAG_COPY ) == ERR_OK ) 00316 { 00317 #ifdef MB_TCP_DEBUG 00318 prvvMBTCPLogFrame( (UCHAR*)"MBTCP-SENT", &aucTCPBuf[0], usTCPLength ); 00319 #endif 00320 /* Make sure data gets sent immediately. */ 00321 ( void )tcp_output( pxPCBClient ); 00322 bFrameSent = TRUE; 00323 } 00324 else 00325 { 00326 /* Drop the connection in case of an write error. */ 00327 prvvMBPortReleaseClient( pxPCBClient ); 00328 } 00329 } 00330 return bFrameSent; 00331 } 00332
Generated on Tue Jul 12 2022 18:48:34 by
1.7.2
