Yuji Hosogaya / Mbed 2 deprecated ModbusTCP_Modified

Dependencies:   EthernetNetIf mbed

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers porttcp.cpp Source File

porttcp.cpp

00001 /*
00002  * FreeModbus Libary: mbed 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 /* ----------------------- System includes ----------------------------------*/
00022 #include <stdio.h>
00023 #include <string.h>
00024 
00025 #include "port.h"
00026 
00027 /* ----------------------- mbed includes ------------------------------------*/
00028 #include "mbed.h"
00029 #include "EthernetNetIf.h"
00030 #include "TCPSocket.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 prvvMBPortReleaseClient(  );
00047 BOOL prvbMBPortAcceptClient(  );
00048 BOOL prvMBTCPGetFrame(  );
00049 void onListeningTCPSocketEvent(TCPSocketEvent e);
00050 void onConnectedTCPSocketEvent(TCPSocketEvent e);
00051 
00052 /* ----------------------- Static variables ---------------------------------*/
00053 static UCHAR    aucTCPBuf[MB_TCP_BUF_SIZE];
00054 static USHORT   usTCPBufPos;
00055 static USHORT   usTCPFrameBytesLeft;
00056 
00057 static TCPSocket ListeningSock;
00058 static TCPSocket* pConnectedSock; // for ConnectedSock
00059 static Host client;
00060 
00061 /* ----------------------- Begin implementation -----------------------------*/
00062 BOOL
00063 xMBTCPPortInit( USHORT usTCPPort )
00064 {
00065     BOOL            bOkay = FALSE;
00066     USHORT          usPort;
00067 
00068     if( usTCPPort == 0 )
00069     {
00070         usPort = MB_TCP_DEFAULT_PORT;
00071     }
00072     else
00073     {
00074         usPort = ( USHORT ) usTCPPort;
00075     }
00076     pConnectedSock=NULL;
00077 
00078     // Set the callbacks for Listening
00079     ListeningSock.setOnEvent(&onListeningTCPSocketEvent); 
00080 
00081     // bind and listen on TCP
00082     if( ListeningSock.bind(Host(IpAddr(), usPort)) )
00083     {
00084         // Failed to bind
00085         bOkay = FALSE;
00086     }
00087     else if( ListeningSock.listen() )
00088     {
00089         // Failed to listen
00090         bOkay = FALSE;
00091     }
00092     else
00093     {
00094 #ifdef MB_TCP_DEBUG
00095         vMBPortLog( MB_LOG_DEBUG, "MBTCP-ACCEPT", "Protocol stack ready.\r\n" );
00096 #endif
00097         bOkay = TRUE;
00098     }    
00099 
00100     return bOkay;
00101 }
00102 
00103 void
00104 vMBTCPPortClose(  )
00105 {
00106     /* Shutdown any open client sockets. */
00107     prvvMBPortReleaseClient();
00108 
00109     /* Shutdown or listening socket. */
00110     ListeningSock.close();
00111 
00112     /* Release resources for the event queue. */
00113 //    vMBPortEventClose(  );
00114 }
00115 
00116 void
00117 vMBTCPPortDisable( void )
00118 {
00119     prvvMBPortReleaseClient( );
00120 }
00121 
00122 BOOL
00123 xMBTCPPortGetRequest( UCHAR ** ppucMBTCPFrame, USHORT * usTCPLength )
00124 {
00125     *ppucMBTCPFrame = &aucTCPBuf[0];
00126     *usTCPLength = usTCPBufPos;
00127 
00128     /* Reset the buffer. */
00129     usTCPBufPos = 0;
00130     usTCPFrameBytesLeft = MB_TCP_FUNC;
00131     return TRUE;
00132 }
00133 
00134 BOOL
00135 xMBTCPPortSendResponse( const UCHAR * pucMBTCPFrame, USHORT usTCPLength )
00136 {
00137     BOOL            bFrameSent = FALSE;
00138 
00139     if( pConnectedSock )
00140     {
00141         if(pConnectedSock->send((char *)pucMBTCPFrame, usTCPLength)>=0)
00142         {
00143             bFrameSent = TRUE;
00144             printf("sent %d bytes\n",usTCPLength);
00145         }
00146         else
00147         {
00148             /* Drop the connection in case of an write error. */
00149             printf("sent error!\n");
00150             prvvMBPortReleaseClient( );
00151         }
00152     }
00153     return bFrameSent;
00154 }
00155 
00156 void
00157 prvvMBPortReleaseClient(  )
00158 {
00159     if(pConnectedSock){
00160         IpAddr clientIp = client.getIp();
00161 #ifdef MB_TCP_DEBUG
00162         vMBPortLog( MB_LOG_DEBUG, "MBTCP-CLOSE", "Closed connection to %d.%d.%d.%d.\r\n",
00163              clientIp[0], clientIp[1], clientIp[2], clientIp[3]);
00164 #endif
00165         pConnectedSock->close();
00166         pConnectedSock=NULL;
00167     }
00168 }
00169 
00170 
00171 BOOL prvbMBPortAcceptClient(  )
00172 {
00173     // Accepts connection from client and gets connected socket.   
00174 
00175     if (ListeningSock.accept(&client, &pConnectedSock)) {
00176         return FALSE; //Error in accept, discard connection
00177     }
00178     // Setup the new socket events
00179     pConnectedSock->setOnEvent(&onConnectedTCPSocketEvent);
00180     // We can find out from where the connection is coming by looking at the
00181     // Host parameter of the accept() method
00182     IpAddr clientIp = client.getIp();
00183 
00184 #ifdef MB_TCP_DEBUG
00185     vMBPortLog( MB_LOG_DEBUG, "MBTCP-ACCEPT", "Accepted new client %d.%d.%d.%d\r\n",
00186         clientIp[0], clientIp[1], clientIp[2], clientIp[3]);
00187 #endif
00188 
00189     usTCPBufPos = 0;
00190     usTCPFrameBytesLeft = MB_TCP_FUNC;
00191 
00192     return TRUE;
00193 }
00194 
00195 
00196 BOOL
00197 prvMBTCPGetFrame(  )
00198 {
00199     BOOL            bOkay = TRUE;
00200     USHORT          usLength;
00201     int             iRes;
00202     /* Make sure that we can safely process the next read request. If there
00203      * is an overflow drop the client.
00204      */
00205     
00206     if( ( usTCPBufPos + usTCPFrameBytesLeft ) >= MB_TCP_BUF_SIZE )
00207     {
00208         // buffer overrun
00209         return FALSE;
00210     }
00211 
00212     while (iRes = pConnectedSock->recv((char *)&aucTCPBuf[usTCPBufPos], MB_TCP_BUF_SIZE-usTCPBufPos) ) {
00213         usTCPBufPos+=iRes;
00214         usTCPFrameBytesLeft-=iRes;
00215     }
00216 
00217     /* If we have received the MBAP header we can analyze it and calculate
00218      * the number of bytes left to complete the current request. If complete
00219      * notify the protocol stack.
00220      */
00221     if( usTCPBufPos >= MB_TCP_FUNC )
00222     {
00223         /* Length is a byte count of Modbus PDU (function code + data) and the
00224          * unit identifier. */
00225         usLength = aucTCPBuf[MB_TCP_LEN] << 8U;
00226         usLength |= aucTCPBuf[MB_TCP_LEN + 1];
00227 
00228         /* Is the frame already complete. */
00229         if( usTCPBufPos < ( MB_TCP_UID + usLength ) )
00230         {
00231             usTCPFrameBytesLeft = usLength + MB_TCP_UID - usTCPBufPos;
00232         }
00233         /* The frame is complete. */
00234         else if( usTCPBufPos == ( MB_TCP_UID + usLength ) )
00235         {
00236 #ifdef MB_TCP_DEBUG
00237             prvvMBTCPLogFrame( "MBTCP-RECV", &aucTCPBuf[0], usTCPBufPos );
00238 #endif
00239             ( void )xMBPortEventPost( EV_FRAME_RECEIVED );
00240         }
00241         else
00242         {
00243 #ifdef MB_TCP_DEBUG
00244             vMBPortLog( MB_LOG_DEBUG, "MBTCP-ERROR",
00245                             "Received too many bytes! Droping client.[%d>%d]\r\n" ,usTCPBufPos, MB_TCP_UID + usLength);
00246 #endif
00247             /* This should not happen. We can't deal with such a client and
00248              * drop the connection for security reasons.
00249              */
00250             prvvMBPortReleaseClient(  );
00251         }
00252     }
00253     return bOkay;
00254 }
00255 
00256 
00257 void onListeningTCPSocketEvent(TCPSocketEvent e)
00258 {
00259     switch(e)
00260     {
00261     case TCPSOCKET_ACCEPT:
00262         if(!prvbMBPortAcceptClient())
00263         {
00264 #ifdef MB_TCP_DEBUG
00265             vMBPortLog( MB_LOG_DEBUG, "MBTCP-ERROR", "Error with client connection! Droping it.\r\n" );
00266 #endif
00267             ListeningSock.close();
00268         }
00269         break;
00270 
00271     default:
00272 #ifdef MB_TCP_DEBUG
00273         vMBPortLog( MB_LOG_DEBUG, "MBTCP-ERROR", "Unexpeted condition!.\r\n" );
00274 #endif
00275         ListeningSock.close();
00276         break;
00277      };
00278 }
00279 
00280 void onConnectedTCPSocketEvent(TCPSocketEvent e)
00281 {
00282     switch(e)
00283     {
00284     case TCPSOCKET_READABLE:
00285         if(!prvMBTCPGetFrame())prvvMBPortReleaseClient();
00286         break;
00287     case TCPSOCKET_CONNECTED:
00288     case TCPSOCKET_WRITEABLE:
00289         break;
00290 
00291     case TCPSOCKET_CONTIMEOUT:
00292     case TCPSOCKET_CONRST:
00293     case TCPSOCKET_CONABRT:
00294     case TCPSOCKET_ERROR:
00295     case TCPSOCKET_DISCONNECTED:
00296         prvvMBPortReleaseClient();
00297         break;
00298     default:
00299         break;
00300     }
00301 }