modbus_server.c
Go to the documentation of this file.
1 /**
2  * @file modbus_server.c
3  * @brief Modbus/TCP server
4  *
5  * @section License
6  *
7  * Copyright (C) 2010-2018 Oryx Embedded SARL. All rights reserved.
8  *
9  * This file is part of CycloneTCP Open.
10  *
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License
13  * as published by the Free Software Foundation; either version 2
14  * of the License, or (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software Foundation,
23  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
24  *
25  * @author Oryx Embedded SARL (www.oryx-embedded.com)
26  * @version 1.9.0
27  **/
28 
29 //Switch to the appropriate trace level
30 #define TRACE_LEVEL MODBUS_TRACE_LEVEL
31 
32 //Dependencies
33 #include "modbus/modbus_server.h"
35 #include "debug.h"
36 
37 //Check TCP/IP stack configuration
38 #if (MODBUS_SERVER_SUPPORT == ENABLED)
39 
40 
41 /**
42  * @brief Initialize settings with default values
43  * @param[out] settings Structure that contains Modbus/TCP server settings
44  **/
45 
47 {
48  //The Modbus/TCP server is not bound to any interface
49  settings->interface = NULL;
50 
51  //Modbus/TCP port number
52  settings->port = MODBUS_TCP_PORT;
53  //Default unit identifier
54  settings->unitId = MODBUS_DEFAULT_UNIT_ID;
55 
56  //Lock Modbus table callback function
57  settings->lockCallback = NULL;
58  //Unlock Modbus table callback function
59  settings->unlockCallback = NULL;
60  //Get coil state callback function
61  settings->readCoilCallback = NULL;
62  //Set coil state callback function
63  settings->writeCoilCallback = NULL;
64  //Get register value callback function
65  settings->readRegCallback = NULL;
66  //Set register value callback function
67  settings->writeRegValueCallback = NULL;
68  //PDU processing callback
69  settings->processPduCallback = NULL;
70 }
71 
72 
73 /**
74  * @brief Initialize Modbus/TCP server context
75  * @param[in] context Pointer to the Modbus/TCP server context
76  * @param[in] settings Modbus/TCP server specific settings
77  * @return Error code
78  **/
79 
81  const ModbusServerSettings *settings)
82 {
83  error_t error;
84 
85  //Debug message
86  TRACE_INFO("Initializing Modbus/TCP server...\r\n");
87 
88  //Ensure the parameters are valid
89  if(context == NULL || settings == NULL)
91 
92  //Clear Modbus/TCP server context
93  memset(context, 0, sizeof(ModbusServerContext));
94 
95  //Save user settings
96  context->settings = *settings;
97 
98  //Create an event object to poll the state of sockets
99  if(!osCreateEvent(&context->event))
100  {
101  //Failed to create event
102  return ERROR_OUT_OF_RESOURCES;
103  }
104 
105  //Start of exception handling block
106  do
107  {
108  //Open a TCP socket
110 
111  //Failed to open socket?
112  if(context->socket == NULL)
113  {
114  //Report an error
115  error = ERROR_OPEN_FAILED;
116  //Exit immediately
117  break;
118  }
119 
120  //Associate the socket with the relevant interface
121  error = socketBindToInterface(context->socket, settings->interface);
122  //Any error to report?
123  if(error)
124  break;
125 
126  //The Modbus/TCP server listens for connection requests on port 502
127  error = socketBind(context->socket, &IP_ADDR_ANY, settings->port);
128  //Any error to report?
129  if(error)
130  break;
131 
132  //Place socket in listening state
133  error = socketListen(context->socket, 0);
134  //Any error to report?
135  if(error)
136  break;
137 
138  //End of exception handling block
139  } while(0);
140 
141  //Did we encounter an error?
142  if(error)
143  {
144  //Free previously allocated resources
145  osDeleteEvent(&context->event);
146  //Close socket
147  socketClose(context->socket);
148  }
149 
150  //Return status code
151  return error;
152 }
153 
154 /**
155  * @brief Start Modbus/TCP server
156  * @param[in] context Pointer to the Modbus/TCP server context
157  * @return Error code
158  **/
159 
161 {
162  OsTask *task;
163 
164  //Debug message
165  TRACE_INFO("Starting Modbus/TCP server...\r\n");
166 
167  //Make sure the Modbus/TCP server context is valid
168  if(context == NULL)
170 
171  //Create the Modbus/TCP server task
172  task = osCreateTask("Modbus/TCP Server", (OsTaskCode) modbusServerTask,
174 
175  //Unable to create the task?
176  if(task == OS_INVALID_HANDLE)
177  return ERROR_OUT_OF_RESOURCES;
178 
179  //Successful processing
180  return NO_ERROR;
181 }
182 
183 
184 /**
185  * @brief Modbus/TCP server task
186  * @param[in] context Pointer to the Modbus/TCP server context
187  **/
188 
190 {
191  error_t error;
192  uint_t i;
193  ModbusClientConnection *connection;
194 
195 #if (NET_RTOS_SUPPORT == ENABLED)
196  //Process events
197  while(1)
198  {
199 #endif
200  //Clear event descriptor set
201  memset(context->eventDesc, 0, sizeof(context->eventDesc));
202 
203  //Specify the events the application is interested in
204  for(i = 0; i < MODBUS_SERVER_MAX_CONNECTIONS; i++)
205  {
206  //Point to the structure describing the current connection
207  connection = &context->connection[i];
208 
209  //Check the state of the connection
210  if(connection->state == MODBUS_CONNECTION_STATE_RECEIVING)
211  {
212  //Wait for data to be available for reading
213  context->eventDesc[i].socket = connection->socket;
214  context->eventDesc[i].eventMask = SOCKET_EVENT_RX_READY;
215  }
216  else if(connection->state == MODBUS_CONNECTION_STATE_SENDING)
217  {
218  //Wait until there is more room in the send buffer
219  context->eventDesc[i].socket = connection->socket;
220  context->eventDesc[i].eventMask = SOCKET_EVENT_TX_READY;
221  }
222  }
223 
224  //The Modbus/TCP server listens for connection requests on port 502
225  context->eventDesc[i].socket = context->socket;
226  context->eventDesc[i].eventMask = SOCKET_EVENT_RX_READY;
227 
228  //Wait for one of the set of sockets to become ready to perform I/O
229  error = socketPoll(context->eventDesc, MODBUS_SERVER_MAX_CONNECTIONS + 1,
230  &context->event, MODBUS_SERVER_TICK_INTERVAL);
231 
232  //Verify status code
233  if(!error)
234  {
235  //Event-driven processing
236  for(i = 0; i < MODBUS_SERVER_MAX_CONNECTIONS; i++)
237  {
238  //Point to the structure describing the current connection
239  connection = &context->connection[i];
240 
241  //Loop through active connections only
242  if(connection->state == MODBUS_CONNECTION_STATE_RECEIVING ||
243  connection->state == MODBUS_CONNECTION_STATE_SENDING)
244  {
245  //Check whether the socket is ready to perform I/O
246  if(context->eventDesc[i].eventFlags != 0)
247  {
248  //Connection event handler
249  modbusServerProcessConnectionEvents(context, connection);
250  }
251  }
252  }
253 
254  //Any connection request received on port 502?
255  if(context->eventDesc[i].eventFlags != 0)
256  {
257  //Accept connection request
259  }
260  }
261 
262  //Handle periodic operations
263  modbusServerTick(context);
264 
265 #if (NET_RTOS_SUPPORT == ENABLED)
266  }
267 #endif
268 }
269 
270 #endif
uint16_t port
Modbus/TCP port number.
Modbus/TCP server.
ModbusServerLockCallback lockCallback
Lock Modbus table callback function.
void modbusServerAcceptConnection(ModbusServerContext *context)
Accept connection request.
Modbus/TCP server settings.
ModbusServerWriteRegCallback writeRegValueCallback
Set register value callback function.
ModbusServerProcessPduCallback processPduCallback
PDU processing callback.
Debugging facilities.
#define MODBUS_TCP_PORT
Definition: modbus_common.h:36
ModbusServerWriteCoilCallback writeCoilCallback
Set coil state callback function.
ModbusServerReadRegCallback readRegCallback
Get register value callback function.
OsTask * osCreateTask(const char_t *name, OsTaskCode taskCode, void *param, size_t stackSize, int_t priority)
Create a new task.
Invalid parameter.
Definition: error.h:45
error_t socketListen(Socket *socket, uint_t backlog)
Place a socket in the listening state.
Definition: socket.c:420
void socketClose(Socket *socket)
Close an existing socket.
Definition: socket.c:797
void modbusServerTask(ModbusServerContext *context)
Modbus/TCP server task.
NetInterface * interface
Underlying network interface.
const IpAddr IP_ADDR_ANY
Definition: ip.c:42
error_t modbusServerStart(ModbusServerContext *context)
Start Modbus/TCP server.
bool_t osCreateEvent(OsEvent *event)
Create an event object.
#define MODBUS_SERVER_PRIORITY
Definition: modbus_server.h:52
error_t socketPoll(SocketEventDesc *eventDesc, uint_t size, OsEvent *extEvent, systime_t timeout)
Wait for one of a set of sockets to become ready to perform I/O.
Definition: socket.c:857
ModbusConnectionState state
Connection state.
Socket * socket
Underlying socket.
Task object.
Modbus/TCP client connection.
uint8_t unitId
Unit identifier.
Helper functions for Modbus/TCP server.
error_t modbusServerInit(ModbusServerContext *context, const ModbusServerSettings *settings)
Initialize Modbus/TCP server context.
Definition: modbus_server.c:80
void(* OsTaskCode)(void *param)
Task routine.
#define MODBUS_SERVER_STACK_SIZE
Definition: modbus_server.h:45
#define TRACE_INFO(...)
Definition: debug.h:86
Success.
Definition: error.h:42
#define ModbusServerContext
Definition: modbus_server.h:78
error_t
Error codes.
Definition: error.h:40
unsigned int uint_t
Definition: compiler_port.h:43
Socket * socketOpen(uint_t type, uint_t protocol)
Create a socket (UDP or TCP)
Definition: socket.c:92
void modbusServerGetDefaultSettings(ModbusServerSettings *settings)
Initialize settings with default values.
Definition: modbus_server.c:46
void osDeleteEvent(OsEvent *event)
Delete an event object.
ModbusServerReadCoilCallback readCoilCallback
Get coil state callback function.
void modbusServerTick(ModbusServerContext *context)
Handle periodic operations.
#define MODBUS_SERVER_MAX_CONNECTIONS
Definition: modbus_server.h:57
#define MODBUS_DEFAULT_UNIT_ID
Definition: modbus_common.h:40
#define OS_INVALID_HANDLE
Definition: os_port.h:77
void modbusServerProcessConnectionEvents(ModbusServerContext *context, ModbusClientConnection *connection)
Connection event handler.
#define MODBUS_SERVER_TICK_INTERVAL
Definition: modbus_server.h:71
ModbusServerUnlockCallback unlockCallback
Unlock Modbus table callback function.
error_t socketBind(Socket *socket, const IpAddr *localIpAddr, uint16_t localPort)
Associate a local address with a socket.
Definition: socket.c:331
error_t socketBindToInterface(Socket *socket, NetInterface *interface)
Bind a socket to a particular network interface.
Definition: socket.c:309