Modified version of ModbusTCP

Dependencies:   EthernetNetIf mbed

Committer:
paleskyjp
Date:
Thu Mar 15 15:28:14 2012 +0000
Revision:
3:d7d7c67f21fa
Parent:
2:53de07fd9705
eMBRegCoilsCB was corrected.
(Implementation of writing single coil was wrong.)

Who changed what in which revision?

UserRevisionLine numberNew contents of line
paleskyjp 0:62be54b8975d 1 /*
paleskyjp 0:62be54b8975d 2 * FreeModbus Libary: mbed Port
paleskyjp 0:62be54b8975d 3 * Copyright (C) 2006 Christian Walter <wolti@sil.at>
paleskyjp 0:62be54b8975d 4 *
paleskyjp 0:62be54b8975d 5 * This library is free software; you can redistribute it and/or
paleskyjp 0:62be54b8975d 6 * modify it under the terms of the GNU Lesser General Public
paleskyjp 0:62be54b8975d 7 * License as published by the Free Software Foundation; either
paleskyjp 0:62be54b8975d 8 * version 2.1 of the License, or (at your option) any later version.
paleskyjp 0:62be54b8975d 9 *
paleskyjp 0:62be54b8975d 10 * This library is distributed in the hope that it will be useful,
paleskyjp 0:62be54b8975d 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
paleskyjp 0:62be54b8975d 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
paleskyjp 0:62be54b8975d 13 * Lesser General Public License for more details.
paleskyjp 0:62be54b8975d 14 *
paleskyjp 0:62be54b8975d 15 * You should have received a copy of the GNU Lesser General Public
paleskyjp 0:62be54b8975d 16 * License along with this library; if not, write to the Free Software
paleskyjp 0:62be54b8975d 17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
paleskyjp 0:62be54b8975d 18 *
paleskyjp 0:62be54b8975d 19 * File: $Id: porttcp.c,v 1.1 2006/08/30 23:18:07 wolti Exp $
paleskyjp 0:62be54b8975d 20 */
paleskyjp 0:62be54b8975d 21 /* ----------------------- System includes ----------------------------------*/
paleskyjp 0:62be54b8975d 22 #include <stdio.h>
paleskyjp 0:62be54b8975d 23 #include <string.h>
paleskyjp 0:62be54b8975d 24
paleskyjp 0:62be54b8975d 25 #include "port.h"
paleskyjp 0:62be54b8975d 26
paleskyjp 0:62be54b8975d 27 /* ----------------------- mbed includes ------------------------------------*/
paleskyjp 0:62be54b8975d 28 #include "mbed.h"
paleskyjp 0:62be54b8975d 29 #include "EthernetNetIf.h"
paleskyjp 0:62be54b8975d 30 #include "TCPSocket.h"
paleskyjp 0:62be54b8975d 31
paleskyjp 0:62be54b8975d 32 /* ----------------------- Modbus includes ----------------------------------*/
paleskyjp 0:62be54b8975d 33 #include "mb.h"
paleskyjp 0:62be54b8975d 34 #include "mbport.h"
paleskyjp 0:62be54b8975d 35
paleskyjp 0:62be54b8975d 36 /* ----------------------- MBAP Header --------------------------------------*/
paleskyjp 0:62be54b8975d 37 #define MB_TCP_UID 6
paleskyjp 0:62be54b8975d 38 #define MB_TCP_LEN 4
paleskyjp 0:62be54b8975d 39 #define MB_TCP_FUNC 7
paleskyjp 0:62be54b8975d 40
paleskyjp 0:62be54b8975d 41 /* ----------------------- Defines -----------------------------------------*/
paleskyjp 0:62be54b8975d 42 #define MB_TCP_DEFAULT_PORT 502 /* TCP listening port. */
paleskyjp 0:62be54b8975d 43 #define MB_TCP_BUF_SIZE ( 256 + 7 ) /* Must hold a complete Modbus TCP frame. */
paleskyjp 0:62be54b8975d 44
paleskyjp 0:62be54b8975d 45 /* ----------------------- Prototypes ---------------------------------------*/
paleskyjp 0:62be54b8975d 46 void prvvMBPortReleaseClient( );
paleskyjp 0:62be54b8975d 47 BOOL prvbMBPortAcceptClient( );
paleskyjp 0:62be54b8975d 48 BOOL prvMBTCPGetFrame( );
paleskyjp 0:62be54b8975d 49 void onListeningTCPSocketEvent(TCPSocketEvent e);
paleskyjp 0:62be54b8975d 50 void onConnectedTCPSocketEvent(TCPSocketEvent e);
paleskyjp 0:62be54b8975d 51
paleskyjp 0:62be54b8975d 52 /* ----------------------- Static variables ---------------------------------*/
paleskyjp 0:62be54b8975d 53 static UCHAR aucTCPBuf[MB_TCP_BUF_SIZE];
paleskyjp 0:62be54b8975d 54 static USHORT usTCPBufPos;
paleskyjp 0:62be54b8975d 55 static USHORT usTCPFrameBytesLeft;
paleskyjp 0:62be54b8975d 56
paleskyjp 0:62be54b8975d 57 static TCPSocket ListeningSock;
paleskyjp 0:62be54b8975d 58 static TCPSocket* pConnectedSock; // for ConnectedSock
paleskyjp 0:62be54b8975d 59 static Host client;
paleskyjp 0:62be54b8975d 60
paleskyjp 0:62be54b8975d 61 /* ----------------------- Begin implementation -----------------------------*/
paleskyjp 0:62be54b8975d 62 BOOL
paleskyjp 0:62be54b8975d 63 xMBTCPPortInit( USHORT usTCPPort )
paleskyjp 0:62be54b8975d 64 {
paleskyjp 0:62be54b8975d 65 BOOL bOkay = FALSE;
paleskyjp 0:62be54b8975d 66 USHORT usPort;
paleskyjp 0:62be54b8975d 67
paleskyjp 0:62be54b8975d 68 if( usTCPPort == 0 )
paleskyjp 0:62be54b8975d 69 {
paleskyjp 0:62be54b8975d 70 usPort = MB_TCP_DEFAULT_PORT;
paleskyjp 0:62be54b8975d 71 }
paleskyjp 0:62be54b8975d 72 else
paleskyjp 0:62be54b8975d 73 {
paleskyjp 0:62be54b8975d 74 usPort = ( USHORT ) usTCPPort;
paleskyjp 0:62be54b8975d 75 }
paleskyjp 0:62be54b8975d 76 pConnectedSock=NULL;
paleskyjp 0:62be54b8975d 77
paleskyjp 0:62be54b8975d 78 // Set the callbacks for Listening
paleskyjp 0:62be54b8975d 79 ListeningSock.setOnEvent(&onListeningTCPSocketEvent);
paleskyjp 0:62be54b8975d 80
paleskyjp 0:62be54b8975d 81 // bind and listen on TCP
paleskyjp 0:62be54b8975d 82 if( ListeningSock.bind(Host(IpAddr(), usPort)) )
paleskyjp 0:62be54b8975d 83 {
paleskyjp 0:62be54b8975d 84 // Failed to bind
paleskyjp 0:62be54b8975d 85 bOkay = FALSE;
paleskyjp 0:62be54b8975d 86 }
paleskyjp 0:62be54b8975d 87 else if( ListeningSock.listen() )
paleskyjp 0:62be54b8975d 88 {
paleskyjp 0:62be54b8975d 89 // Failed to listen
paleskyjp 0:62be54b8975d 90 bOkay = FALSE;
paleskyjp 0:62be54b8975d 91 }
paleskyjp 0:62be54b8975d 92 else
paleskyjp 0:62be54b8975d 93 {
paleskyjp 0:62be54b8975d 94 #ifdef MB_TCP_DEBUG
paleskyjp 0:62be54b8975d 95 vMBPortLog( MB_LOG_DEBUG, "MBTCP-ACCEPT", "Protocol stack ready.\r\n" );
paleskyjp 0:62be54b8975d 96 #endif
paleskyjp 0:62be54b8975d 97 bOkay = TRUE;
paleskyjp 0:62be54b8975d 98 }
paleskyjp 0:62be54b8975d 99
paleskyjp 0:62be54b8975d 100 return bOkay;
paleskyjp 0:62be54b8975d 101 }
paleskyjp 0:62be54b8975d 102
paleskyjp 0:62be54b8975d 103 void
paleskyjp 0:62be54b8975d 104 vMBTCPPortClose( )
paleskyjp 0:62be54b8975d 105 {
paleskyjp 0:62be54b8975d 106 /* Shutdown any open client sockets. */
paleskyjp 0:62be54b8975d 107 prvvMBPortReleaseClient();
paleskyjp 0:62be54b8975d 108
paleskyjp 0:62be54b8975d 109 /* Shutdown or listening socket. */
paleskyjp 0:62be54b8975d 110 ListeningSock.close();
paleskyjp 0:62be54b8975d 111
paleskyjp 0:62be54b8975d 112 /* Release resources for the event queue. */
paleskyjp 0:62be54b8975d 113 // vMBPortEventClose( );
paleskyjp 0:62be54b8975d 114 }
paleskyjp 0:62be54b8975d 115
paleskyjp 0:62be54b8975d 116 void
paleskyjp 0:62be54b8975d 117 vMBTCPPortDisable( void )
paleskyjp 0:62be54b8975d 118 {
paleskyjp 0:62be54b8975d 119 prvvMBPortReleaseClient( );
paleskyjp 0:62be54b8975d 120 }
paleskyjp 0:62be54b8975d 121
paleskyjp 0:62be54b8975d 122 BOOL
paleskyjp 0:62be54b8975d 123 xMBTCPPortGetRequest( UCHAR ** ppucMBTCPFrame, USHORT * usTCPLength )
paleskyjp 0:62be54b8975d 124 {
paleskyjp 0:62be54b8975d 125 *ppucMBTCPFrame = &aucTCPBuf[0];
paleskyjp 0:62be54b8975d 126 *usTCPLength = usTCPBufPos;
paleskyjp 0:62be54b8975d 127
paleskyjp 0:62be54b8975d 128 /* Reset the buffer. */
paleskyjp 0:62be54b8975d 129 usTCPBufPos = 0;
paleskyjp 0:62be54b8975d 130 usTCPFrameBytesLeft = MB_TCP_FUNC;
paleskyjp 0:62be54b8975d 131 return TRUE;
paleskyjp 0:62be54b8975d 132 }
paleskyjp 0:62be54b8975d 133
paleskyjp 0:62be54b8975d 134 BOOL
paleskyjp 0:62be54b8975d 135 xMBTCPPortSendResponse( const UCHAR * pucMBTCPFrame, USHORT usTCPLength )
paleskyjp 0:62be54b8975d 136 {
paleskyjp 0:62be54b8975d 137 BOOL bFrameSent = FALSE;
paleskyjp 0:62be54b8975d 138
paleskyjp 0:62be54b8975d 139 if( pConnectedSock )
paleskyjp 0:62be54b8975d 140 {
paleskyjp 0:62be54b8975d 141 if(pConnectedSock->send((char *)pucMBTCPFrame, usTCPLength)>=0)
paleskyjp 0:62be54b8975d 142 {
paleskyjp 0:62be54b8975d 143 bFrameSent = TRUE;
paleskyjp 0:62be54b8975d 144 printf("sent %d bytes\n",usTCPLength);
paleskyjp 0:62be54b8975d 145 }
paleskyjp 0:62be54b8975d 146 else
paleskyjp 0:62be54b8975d 147 {
paleskyjp 0:62be54b8975d 148 /* Drop the connection in case of an write error. */
paleskyjp 0:62be54b8975d 149 printf("sent error!\n");
paleskyjp 0:62be54b8975d 150 prvvMBPortReleaseClient( );
paleskyjp 0:62be54b8975d 151 }
paleskyjp 0:62be54b8975d 152 }
paleskyjp 0:62be54b8975d 153 return bFrameSent;
paleskyjp 0:62be54b8975d 154 }
paleskyjp 0:62be54b8975d 155
paleskyjp 0:62be54b8975d 156 void
paleskyjp 0:62be54b8975d 157 prvvMBPortReleaseClient( )
paleskyjp 0:62be54b8975d 158 {
paleskyjp 0:62be54b8975d 159 if(pConnectedSock){
paleskyjp 0:62be54b8975d 160 IpAddr clientIp = client.getIp();
paleskyjp 0:62be54b8975d 161 #ifdef MB_TCP_DEBUG
paleskyjp 0:62be54b8975d 162 vMBPortLog( MB_LOG_DEBUG, "MBTCP-CLOSE", "Closed connection to %d.%d.%d.%d.\r\n",
paleskyjp 0:62be54b8975d 163 clientIp[0], clientIp[1], clientIp[2], clientIp[3]);
paleskyjp 0:62be54b8975d 164 #endif
paleskyjp 0:62be54b8975d 165 pConnectedSock->close();
paleskyjp 0:62be54b8975d 166 pConnectedSock=NULL;
paleskyjp 0:62be54b8975d 167 }
paleskyjp 0:62be54b8975d 168 }
paleskyjp 0:62be54b8975d 169
paleskyjp 0:62be54b8975d 170
paleskyjp 0:62be54b8975d 171 BOOL prvbMBPortAcceptClient( )
paleskyjp 0:62be54b8975d 172 {
paleskyjp 0:62be54b8975d 173 // Accepts connection from client and gets connected socket.
paleskyjp 0:62be54b8975d 174
paleskyjp 0:62be54b8975d 175 if (ListeningSock.accept(&client, &pConnectedSock)) {
paleskyjp 0:62be54b8975d 176 return FALSE; //Error in accept, discard connection
paleskyjp 0:62be54b8975d 177 }
paleskyjp 0:62be54b8975d 178 // Setup the new socket events
paleskyjp 0:62be54b8975d 179 pConnectedSock->setOnEvent(&onConnectedTCPSocketEvent);
paleskyjp 0:62be54b8975d 180 // We can find out from where the connection is coming by looking at the
paleskyjp 0:62be54b8975d 181 // Host parameter of the accept() method
paleskyjp 0:62be54b8975d 182 IpAddr clientIp = client.getIp();
paleskyjp 0:62be54b8975d 183
paleskyjp 0:62be54b8975d 184 #ifdef MB_TCP_DEBUG
paleskyjp 0:62be54b8975d 185 vMBPortLog( MB_LOG_DEBUG, "MBTCP-ACCEPT", "Accepted new client %d.%d.%d.%d\r\n",
paleskyjp 0:62be54b8975d 186 clientIp[0], clientIp[1], clientIp[2], clientIp[3]);
paleskyjp 0:62be54b8975d 187 #endif
paleskyjp 0:62be54b8975d 188
paleskyjp 0:62be54b8975d 189 usTCPBufPos = 0;
paleskyjp 0:62be54b8975d 190 usTCPFrameBytesLeft = MB_TCP_FUNC;
paleskyjp 0:62be54b8975d 191
paleskyjp 0:62be54b8975d 192 return TRUE;
paleskyjp 0:62be54b8975d 193 }
paleskyjp 0:62be54b8975d 194
paleskyjp 0:62be54b8975d 195
paleskyjp 0:62be54b8975d 196 BOOL
paleskyjp 0:62be54b8975d 197 prvMBTCPGetFrame( )
paleskyjp 0:62be54b8975d 198 {
paleskyjp 0:62be54b8975d 199 BOOL bOkay = TRUE;
paleskyjp 0:62be54b8975d 200 USHORT usLength;
paleskyjp 0:62be54b8975d 201 int iRes;
paleskyjp 0:62be54b8975d 202 /* Make sure that we can safely process the next read request. If there
paleskyjp 0:62be54b8975d 203 * is an overflow drop the client.
paleskyjp 0:62be54b8975d 204 */
paleskyjp 0:62be54b8975d 205
paleskyjp 0:62be54b8975d 206 if( ( usTCPBufPos + usTCPFrameBytesLeft ) >= MB_TCP_BUF_SIZE )
paleskyjp 0:62be54b8975d 207 {
paleskyjp 0:62be54b8975d 208 // buffer overrun
paleskyjp 0:62be54b8975d 209 return FALSE;
paleskyjp 0:62be54b8975d 210 }
paleskyjp 0:62be54b8975d 211
paleskyjp 2:53de07fd9705 212 while (iRes = pConnectedSock->recv((char *)&aucTCPBuf[usTCPBufPos], MB_TCP_BUF_SIZE-usTCPBufPos) ) {
paleskyjp 2:53de07fd9705 213 usTCPBufPos+=iRes;
paleskyjp 2:53de07fd9705 214 usTCPFrameBytesLeft-=iRes;
paleskyjp 0:62be54b8975d 215 }
paleskyjp 0:62be54b8975d 216
paleskyjp 0:62be54b8975d 217 /* If we have received the MBAP header we can analyze it and calculate
paleskyjp 0:62be54b8975d 218 * the number of bytes left to complete the current request. If complete
paleskyjp 0:62be54b8975d 219 * notify the protocol stack.
paleskyjp 0:62be54b8975d 220 */
paleskyjp 0:62be54b8975d 221 if( usTCPBufPos >= MB_TCP_FUNC )
paleskyjp 0:62be54b8975d 222 {
paleskyjp 0:62be54b8975d 223 /* Length is a byte count of Modbus PDU (function code + data) and the
paleskyjp 0:62be54b8975d 224 * unit identifier. */
paleskyjp 0:62be54b8975d 225 usLength = aucTCPBuf[MB_TCP_LEN] << 8U;
paleskyjp 0:62be54b8975d 226 usLength |= aucTCPBuf[MB_TCP_LEN + 1];
paleskyjp 0:62be54b8975d 227
paleskyjp 0:62be54b8975d 228 /* Is the frame already complete. */
paleskyjp 0:62be54b8975d 229 if( usTCPBufPos < ( MB_TCP_UID + usLength ) )
paleskyjp 0:62be54b8975d 230 {
paleskyjp 0:62be54b8975d 231 usTCPFrameBytesLeft = usLength + MB_TCP_UID - usTCPBufPos;
paleskyjp 0:62be54b8975d 232 }
paleskyjp 0:62be54b8975d 233 /* The frame is complete. */
paleskyjp 0:62be54b8975d 234 else if( usTCPBufPos == ( MB_TCP_UID + usLength ) )
paleskyjp 0:62be54b8975d 235 {
paleskyjp 0:62be54b8975d 236 #ifdef MB_TCP_DEBUG
paleskyjp 0:62be54b8975d 237 prvvMBTCPLogFrame( "MBTCP-RECV", &aucTCPBuf[0], usTCPBufPos );
paleskyjp 0:62be54b8975d 238 #endif
paleskyjp 0:62be54b8975d 239 ( void )xMBPortEventPost( EV_FRAME_RECEIVED );
paleskyjp 0:62be54b8975d 240 }
paleskyjp 0:62be54b8975d 241 else
paleskyjp 0:62be54b8975d 242 {
paleskyjp 0:62be54b8975d 243 #ifdef MB_TCP_DEBUG
paleskyjp 0:62be54b8975d 244 vMBPortLog( MB_LOG_DEBUG, "MBTCP-ERROR",
paleskyjp 0:62be54b8975d 245 "Received too many bytes! Droping client.[%d>%d]\r\n" ,usTCPBufPos, MB_TCP_UID + usLength);
paleskyjp 0:62be54b8975d 246 #endif
paleskyjp 0:62be54b8975d 247 /* This should not happen. We can't deal with such a client and
paleskyjp 0:62be54b8975d 248 * drop the connection for security reasons.
paleskyjp 0:62be54b8975d 249 */
paleskyjp 0:62be54b8975d 250 prvvMBPortReleaseClient( );
paleskyjp 0:62be54b8975d 251 }
paleskyjp 0:62be54b8975d 252 }
paleskyjp 0:62be54b8975d 253 return bOkay;
paleskyjp 0:62be54b8975d 254 }
paleskyjp 0:62be54b8975d 255
paleskyjp 0:62be54b8975d 256
paleskyjp 0:62be54b8975d 257 void onListeningTCPSocketEvent(TCPSocketEvent e)
paleskyjp 0:62be54b8975d 258 {
paleskyjp 0:62be54b8975d 259 switch(e)
paleskyjp 0:62be54b8975d 260 {
paleskyjp 0:62be54b8975d 261 case TCPSOCKET_ACCEPT:
paleskyjp 0:62be54b8975d 262 if(!prvbMBPortAcceptClient())
paleskyjp 0:62be54b8975d 263 {
paleskyjp 0:62be54b8975d 264 #ifdef MB_TCP_DEBUG
paleskyjp 0:62be54b8975d 265 vMBPortLog( MB_LOG_DEBUG, "MBTCP-ERROR", "Error with client connection! Droping it.\r\n" );
paleskyjp 0:62be54b8975d 266 #endif
paleskyjp 0:62be54b8975d 267 ListeningSock.close();
paleskyjp 0:62be54b8975d 268 }
paleskyjp 0:62be54b8975d 269 break;
paleskyjp 0:62be54b8975d 270
paleskyjp 0:62be54b8975d 271 default:
paleskyjp 0:62be54b8975d 272 #ifdef MB_TCP_DEBUG
paleskyjp 0:62be54b8975d 273 vMBPortLog( MB_LOG_DEBUG, "MBTCP-ERROR", "Unexpeted condition!.\r\n" );
paleskyjp 0:62be54b8975d 274 #endif
paleskyjp 0:62be54b8975d 275 ListeningSock.close();
paleskyjp 0:62be54b8975d 276 break;
paleskyjp 0:62be54b8975d 277 };
paleskyjp 0:62be54b8975d 278 }
paleskyjp 0:62be54b8975d 279
paleskyjp 0:62be54b8975d 280 void onConnectedTCPSocketEvent(TCPSocketEvent e)
paleskyjp 0:62be54b8975d 281 {
paleskyjp 0:62be54b8975d 282 switch(e)
paleskyjp 0:62be54b8975d 283 {
paleskyjp 0:62be54b8975d 284 case TCPSOCKET_READABLE:
paleskyjp 0:62be54b8975d 285 if(!prvMBTCPGetFrame())prvvMBPortReleaseClient();
paleskyjp 0:62be54b8975d 286 break;
paleskyjp 0:62be54b8975d 287 case TCPSOCKET_CONNECTED:
paleskyjp 0:62be54b8975d 288 case TCPSOCKET_WRITEABLE:
paleskyjp 0:62be54b8975d 289 break;
paleskyjp 0:62be54b8975d 290
paleskyjp 0:62be54b8975d 291 case TCPSOCKET_CONTIMEOUT:
paleskyjp 0:62be54b8975d 292 case TCPSOCKET_CONRST:
paleskyjp 0:62be54b8975d 293 case TCPSOCKET_CONABRT:
paleskyjp 0:62be54b8975d 294 case TCPSOCKET_ERROR:
paleskyjp 0:62be54b8975d 295 case TCPSOCKET_DISCONNECTED:
paleskyjp 0:62be54b8975d 296 prvvMBPortReleaseClient();
paleskyjp 0:62be54b8975d 297 break;
paleskyjp 0:62be54b8975d 298 default:
paleskyjp 0:62be54b8975d 299 break;
paleskyjp 0:62be54b8975d 300 }
paleskyjp 0:62be54b8975d 301 }