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.
Dependencies: EthernetNetIf mbed
Diff: ModBus/porttcp.cpp
- Revision:
- 0:62be54b8975d
- Child:
- 1:e35ceaa8c758
diff -r 000000000000 -r 62be54b8975d ModBus/porttcp.cpp
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/ModBus/porttcp.cpp Tue Mar 13 09:11:49 2012 +0000
@@ -0,0 +1,312 @@
+/*
+ * FreeModbus Libary: mbed 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 <string.h>
+
+#include "port.h"
+
+/* ----------------------- mbed includes ------------------------------------*/
+#include "mbed.h"
+#include "EthernetNetIf.h"
+#include "TCPSocket.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 prvvMBPortReleaseClient( );
+BOOL prvbMBPortAcceptClient( );
+BOOL prvMBTCPGetFrame( );
+void onListeningTCPSocketEvent(TCPSocketEvent e);
+void onConnectedTCPSocketEvent(TCPSocketEvent e);
+
+/* ----------------------- Static variables ---------------------------------*/
+static UCHAR aucTCPBuf[MB_TCP_BUF_SIZE];
+static USHORT usTCPBufPos;
+static USHORT usTCPFrameBytesLeft;
+
+static TCPSocket ListeningSock;
+static TCPSocket* pConnectedSock; // for ConnectedSock
+static Host client;
+
+/* ----------------------- Begin implementation -----------------------------*/
+BOOL
+xMBTCPPortInit( USHORT usTCPPort )
+{
+ BOOL bOkay = FALSE;
+ USHORT usPort;
+
+ if( usTCPPort == 0 )
+ {
+ usPort = MB_TCP_DEFAULT_PORT;
+ }
+ else
+ {
+ usPort = ( USHORT ) usTCPPort;
+ }
+ pConnectedSock=NULL;
+
+ // Set the callbacks for Listening
+ ListeningSock.setOnEvent(&onListeningTCPSocketEvent);
+
+ // bind and listen on TCP
+ if( ListeningSock.bind(Host(IpAddr(), usPort)) )
+ {
+ // Failed to bind
+ bOkay = FALSE;
+ }
+ else if( ListeningSock.listen() )
+ {
+ // Failed to listen
+ bOkay = FALSE;
+ }
+ else
+ {
+#ifdef MB_TCP_DEBUG
+ vMBPortLog( MB_LOG_DEBUG, "MBTCP-ACCEPT", "Protocol stack ready.\r\n" );
+#endif
+ bOkay = TRUE;
+ }
+
+ return bOkay;
+}
+
+void
+vMBTCPPortClose( )
+{
+ /* Shutdown any open client sockets. */
+ prvvMBPortReleaseClient();
+
+ /* Shutdown or listening socket. */
+ ListeningSock.close();
+
+ /* Release resources for the event queue. */
+// vMBPortEventClose( );
+}
+
+void
+vMBTCPPortDisable( void )
+{
+ prvvMBPortReleaseClient( );
+}
+
+BOOL
+xMBTCPPortGetRequest( UCHAR ** ppucMBTCPFrame, USHORT * usTCPLength )
+{
+ *ppucMBTCPFrame = &aucTCPBuf[0];
+ *usTCPLength = usTCPBufPos;
+
+ /* Reset the buffer. */
+ usTCPBufPos = 0;
+ usTCPFrameBytesLeft = MB_TCP_FUNC;
+ return TRUE;
+}
+
+BOOL
+xMBTCPPortSendResponse( const UCHAR * pucMBTCPFrame, USHORT usTCPLength )
+{
+ BOOL bFrameSent = FALSE;
+
+ if( pConnectedSock )
+ {
+ if(pConnectedSock->send((char *)pucMBTCPFrame, usTCPLength)>=0)
+ {
+ bFrameSent = TRUE;
+ printf("sent %d bytes\n",usTCPLength);
+ }
+ else
+ {
+ /* Drop the connection in case of an write error. */
+ printf("sent error!\n");
+ prvvMBPortReleaseClient( );
+ }
+ }
+ return bFrameSent;
+}
+
+void
+prvvMBPortReleaseClient( )
+{
+ if(pConnectedSock){
+ IpAddr clientIp = client.getIp();
+#ifdef MB_TCP_DEBUG
+ vMBPortLog( MB_LOG_DEBUG, "MBTCP-CLOSE", "Closed connection to %d.%d.%d.%d.\r\n",
+ clientIp[0], clientIp[1], clientIp[2], clientIp[3]);
+#endif
+ pConnectedSock->close();
+ pConnectedSock=NULL;
+ }
+}
+
+
+BOOL prvbMBPortAcceptClient( )
+{
+ // Accepts connection from client and gets connected socket.
+
+ if (ListeningSock.accept(&client, &pConnectedSock)) {
+ return FALSE; //Error in accept, discard connection
+ }
+ // Setup the new socket events
+ pConnectedSock->setOnEvent(&onConnectedTCPSocketEvent);
+ // We can find out from where the connection is coming by looking at the
+ // Host parameter of the accept() method
+ IpAddr clientIp = client.getIp();
+
+#ifdef MB_TCP_DEBUG
+ vMBPortLog( MB_LOG_DEBUG, "MBTCP-ACCEPT", "Accepted new client %d.%d.%d.%d\r\n",
+ clientIp[0], clientIp[1], clientIp[2], clientIp[3]);
+#endif
+
+ usTCPBufPos = 0;
+ usTCPFrameBytesLeft = MB_TCP_FUNC;
+
+ return TRUE;
+}
+
+
+BOOL
+prvMBTCPGetFrame( )
+{
+ BOOL bOkay = TRUE;
+ USHORT usLength;
+ int iRes;
+ int i;
+ int total=0;
+ int len;
+ char buf[MB_TCP_BUF_SIZE];
+ /* Make sure that we can safely process the next read request. If there
+ * is an overflow drop the client.
+ */
+
+ if( ( usTCPBufPos + usTCPFrameBytesLeft ) >= MB_TCP_BUF_SIZE )
+ {
+ // buffer overrun
+ return FALSE;
+ }
+
+ /* Though this part is verbose, it doesn't work when data is recieved directly into aucTCPBuf. */
+ while (len = pConnectedSock->recv(&buf[total], MB_TCP_BUF_SIZE-total) ) {
+ total+=len;
+ }
+
+ if(total>0){
+ memcpy((char *)&aucTCPBuf[usTCPBufPos],buf,total);
+ usTCPBufPos+=total;
+ usTCPFrameBytesLeft-=total;
+ prvMBTCPGetFrame();
+ }
+
+ /* 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 ) )
+ {
+ usTCPFrameBytesLeft = usLength + MB_TCP_UID - usTCPBufPos;
+ }
+ /* The frame is complete. */
+ 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 too many bytes! Droping client.[%d>%d]\r\n" ,usTCPBufPos, MB_TCP_UID + usLength);
+#endif
+ /* This should not happen. We can't deal with such a client and
+ * drop the connection for security reasons.
+ */
+ prvvMBPortReleaseClient( );
+ }
+ }
+ return bOkay;
+}
+
+
+void onListeningTCPSocketEvent(TCPSocketEvent e)
+{
+ switch(e)
+ {
+ case TCPSOCKET_ACCEPT:
+ if(!prvbMBPortAcceptClient())
+ {
+#ifdef MB_TCP_DEBUG
+ vMBPortLog( MB_LOG_DEBUG, "MBTCP-ERROR", "Error with client connection! Droping it.\r\n" );
+#endif
+ ListeningSock.close();
+ }
+ break;
+
+ default:
+#ifdef MB_TCP_DEBUG
+ vMBPortLog( MB_LOG_DEBUG, "MBTCP-ERROR", "Unexpeted condition!.\r\n" );
+#endif
+ ListeningSock.close();
+ break;
+ };
+}
+
+void onConnectedTCPSocketEvent(TCPSocketEvent e)
+{
+ switch(e)
+ {
+ case TCPSOCKET_READABLE:
+ if(!prvMBTCPGetFrame())prvvMBPortReleaseClient();
+ break;
+ case TCPSOCKET_CONNECTED:
+ case TCPSOCKET_WRITEABLE:
+ break;
+
+ case TCPSOCKET_CONTIMEOUT:
+ case TCPSOCKET_CONRST:
+ case TCPSOCKET_CONABRT:
+ case TCPSOCKET_ERROR:
+ case TCPSOCKET_DISCONNECTED:
+ prvvMBPortReleaseClient();
+ break;
+ default:
+ break;
+ }
+}