IgH EtherCAT Master  1.5.2
fsm_mbox_gateway.c
Go to the documentation of this file.
1 /******************************************************************************
2  *
3  * $Id$
4  *
5  * Copyright (C) 2019 Florian Pose, Ingenieurgemeinschaft IgH
6  *
7  * This file is part of the IgH EtherCAT Master.
8  *
9  * The IgH EtherCAT Master is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU General Public License version 2, as
11  * published by the Free Software Foundation.
12  *
13  * The IgH EtherCAT Master is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
16  * Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License along
19  * with the IgH EtherCAT Master; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
21  *
22  * ---
23  *
24  * The license mentioned above concerns the source code only. Using the
25  * EtherCAT technology and brand is only permitted in compliance with the
26  * industrial property and similar rights of Beckhoff Automation GmbH.
27  *
28  *****************************************************************************/
29 
34 /*****************************************************************************/
35 
36 #include "globals.h"
37 #include "master.h"
38 #include "mailbox.h"
39 #include "fsm_mbox_gateway.h"
40 #include "slave_config.h"
41 
42 /*****************************************************************************/
43 
46 #define DEBUG_RETRIES 0
47 
50 #define DEBUG_LONG 0
51 
52 /*****************************************************************************/
53 
59 
62 
63 /*****************************************************************************/
64 
68  ec_fsm_mbg_t *fsm
69  )
70 {
71  fsm->state = NULL;
72  fsm->datagram = NULL;
73 }
74 
75 /*****************************************************************************/
76 
80  ec_fsm_mbg_t *fsm
81  )
82 {
83 }
84 
85 /*****************************************************************************/
86 
90  ec_fsm_mbg_t *fsm,
91  ec_slave_t *slave,
92  ec_mbg_request_t *request
93  )
94 {
95  fsm->slave = slave;
96  fsm->request = request;
97 
98  fsm->state = ec_fsm_mbg_start;
99 }
100 
101 /*****************************************************************************/
102 
108  ec_fsm_mbg_t *fsm,
109  ec_datagram_t *datagram
110  )
111 {
112  if (fsm->state == ec_fsm_mbg_end || fsm->state == ec_fsm_mbg_error)
113  return 0;
114 
115  fsm->state(fsm, datagram);
116 
117  if (fsm->state == ec_fsm_mbg_end || fsm->state == ec_fsm_mbg_error) {
118  fsm->datagram = NULL;
119  return 0;
120  }
121 
122  fsm->datagram = datagram;
123  return 1;
124 }
125 
126 /*****************************************************************************/
127 
132  const ec_fsm_mbg_t *fsm
133  )
134 {
135  return fsm->state == ec_fsm_mbg_end;
136 }
137 
138 /******************************************************************************
139  * MBox gateway state machine
140  *****************************************************************************/
141 
147  ec_fsm_mbg_t *fsm,
148  ec_datagram_t *datagram
149  )
150 {
151  u8 *data;
152  ec_slave_t *slave = fsm->slave;
153  ec_mbg_request_t *request = fsm->request;
154  int ret;
155 
156  if (slave->configured_rx_mailbox_size <
157  request->data_size) {
158  EC_SLAVE_ERR(slave, "Mailbox too small!\n");
159  request->error_code = EOVERFLOW;
160  fsm->state = ec_fsm_mbg_error;
161  return request->error_code;
162  }
163 
164  // configure datagram header
165  ret = ec_datagram_fpwr(datagram, slave->station_address,
168  if (ret) {
169  request->error_code = ret;
170  fsm->state = ec_fsm_mbg_error;
171  return request->error_code;
172  }
173 
174  // copy payload
175  data = datagram->data;
176  memcpy(data, request->data, request->data_size);
177 
178  fsm->state = ec_fsm_mbg_request;
179 
180  return 0;
181 }
182 
183 /****************************************************************************/
184 
189 int mbox_type_to_prot(uint8_t mbox_type, uint8_t *mbox_prot)
190 {
191  switch (mbox_type)
192  {
193  case EC_MBOX_TYPE_AOE : { *mbox_prot = EC_MBOX_AOE; } break;
194  case EC_MBOX_TYPE_EOE : { *mbox_prot = EC_MBOX_EOE; } break;
195  case EC_MBOX_TYPE_COE : { *mbox_prot = EC_MBOX_COE; } break;
196  case EC_MBOX_TYPE_FOE : { *mbox_prot = EC_MBOX_FOE; } break;
197  case EC_MBOX_TYPE_SOE : { *mbox_prot = EC_MBOX_SOE; } break;
198  case EC_MBOX_TYPE_VOE : { *mbox_prot = EC_MBOX_VOE; } break;
199  default : {
200  *mbox_prot = 0;
201  return 0;
202  }
203  }
204 
205  return 1;
206 }
207 
208 /****************************************************************************/
209 
213  ec_fsm_mbg_t *fsm,
214  ec_datagram_t *datagram
215  )
216 {
217  ec_slave_t *slave = fsm->slave;
218  ec_mbg_request_t *request = fsm->request;
219  uint8_t mbox_prot;
220 
221  if (fsm->slave->master->debug_level) {
222  EC_SLAVE_DBG(slave, 1, "Mailbox Gateway request.\n");
223  ec_print_data(request->data, request->data_size);
224  }
225 
226  if (!slave->sii_image) {
227  EC_SLAVE_ERR(slave, "Slave cannot process Mailbox Gateway request."
228  " SII data not available.\n");
229  request->error_code = EAGAIN;
230  fsm->state = ec_fsm_mbg_error;
231  return;
232  }
233 
234  // check protocol type supported by slave
235  if ( (request->data_size < EC_MBOX_HEADER_SIZE) ||
236  !mbox_type_to_prot(EC_READ_U16(request->data + 5) & 0x0F, &mbox_prot) ||
237  !(slave->sii_image->sii.mailbox_protocols & mbox_prot) ) {
238  EC_SLAVE_ERR(slave, "Slave does not support requested mailbox type!\n");
239  request->error_code = EPROTONOSUPPORT;
240  fsm->state = ec_fsm_mbg_error;
241  return;
242  }
243 
244  // cache the mbox type
245  request->mbox_type = EC_READ_U16(request->data + 5) & 0x0F;
246 
247  if (slave->configured_rx_mailbox_size <
248  request->data_size) {
249  EC_SLAVE_ERR(slave, "Mailbox too small!\n");
250  request->error_code = EOVERFLOW;
251  fsm->state = ec_fsm_mbg_error;
252  return;
253  }
254 
255 
256  fsm->request->jiffies_sent = jiffies;
257  fsm->retries = EC_FSM_RETRIES;
258 
259  if (ec_fsm_mbg_prepare_start(fsm, datagram)) {
260  fsm->state = ec_fsm_mbg_error;
261  }
262 }
263 
264 /*****************************************************************************/
265 
272  ec_fsm_mbg_t *fsm,
273  ec_datagram_t *datagram
274  )
275 {
276  ec_slave_t *slave = fsm->slave;
277  unsigned long diff_ms;
278 
279  if (fsm->datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--) {
280  if (ec_fsm_mbg_prepare_start(fsm, datagram)) {
281  fsm->state = ec_fsm_mbg_error;
282  }
283  return;
284  }
285 
286  if (fsm->datagram->state != EC_DATAGRAM_RECEIVED) {
287  fsm->request->error_code = EIO;
288  fsm->state = ec_fsm_mbg_error;
289  EC_SLAVE_ERR(slave, "Failed to receive MBox Gateway"
290  " request datagram: ");
292  return;
293  }
294 
295  diff_ms = (jiffies - fsm->request->jiffies_sent) * 1000 / HZ;
296 
297  if (fsm->datagram->working_counter != 1) {
298  if (!fsm->datagram->working_counter) {
299  if (diff_ms < fsm->request->response_timeout) {
300 #if DEBUG_RETRIES
301  EC_SLAVE_DBG(slave, 1, "Slave did not respond to MBox"
302  " Gateway request. Retrying after %lu ms...\n",
303  diff_ms);
304 #endif
305  // no response; send request datagram again
306  if (ec_fsm_mbg_prepare_start(fsm, datagram)) {
307  fsm->state = ec_fsm_mbg_error;
308  }
309  return;
310  }
311  }
312  fsm->request->error_code = EIO;
313  fsm->state = ec_fsm_mbg_error;
314  EC_SLAVE_ERR(slave, "Reception of MBox Gateway request"
315  " failed with timeout after %lu ms: ", diff_ms);
317  return;
318  }
319 
320 #if DEBUG_LONG
321  if (diff_ms > 200) {
322  EC_SLAVE_WARN(slave, "MBox Gateway request took %lu ms.\n", diff_ms);
323  }
324 #endif
325 
326  fsm->jiffies_start = fsm->datagram->jiffies_sent;
327 
328  // mailbox read check is skipped if a read request is already ongoing
329  if (ec_read_mbox_locked(slave)) {
331  // the datagram is not used and marked as invalid
332  datagram->state = EC_DATAGRAM_INVALID;
333  } else {
334  ec_slave_mbox_prepare_check(slave, datagram); // can not fail.
335  fsm->retries = EC_FSM_RETRIES;
336  fsm->state = ec_fsm_mbg_check;
337  }
338 }
339 
340 /*****************************************************************************/
341 
345  ec_fsm_mbg_t *fsm,
346  ec_datagram_t *datagram
347  )
348 {
349  ec_slave_t *slave = fsm->slave;
350 
351  if (fsm->datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--) {
352  ec_slave_mbox_prepare_check(slave, datagram); // can not fail.
353  return;
354  }
355 
356  if (fsm->datagram->state != EC_DATAGRAM_RECEIVED) {
357  fsm->request->error_code = EIO;
358  fsm->state = ec_fsm_mbg_error;
360  EC_SLAVE_ERR(slave, "Failed to receive MBox Gateway mailbox check"
361  " datagram: ");
363  return;
364  }
365 
366  if (fsm->datagram->working_counter != 1) {
367  fsm->request->error_code = EIO;
368  fsm->state = ec_fsm_mbg_error;
370  EC_SLAVE_ERR(slave, "Reception of MBox Gateway check"
371  " datagram failed: ");
373  return;
374  }
375 
376  if (!ec_slave_mbox_check(fsm->datagram)) {
377  unsigned long diff_ms = 0;
378 
379  // check that data is not already received by another read request
380  if (slave->mbox_mbg_data.payload_size > 0) {
383  fsm->state(fsm, datagram);
384  return;
385  }
386 
387  diff_ms = (fsm->datagram->jiffies_received - fsm->jiffies_start) *
388  1000 / HZ;
389 
390  if (diff_ms >= fsm->request->response_timeout) {
391  fsm->request->error_code = EIO;
392  fsm->state = ec_fsm_mbg_error;
394  EC_SLAVE_ERR(slave, "Timeout after %lu ms while waiting"
395  " for MBox Gateway response.\n", diff_ms);
396  return;
397  }
398 
399  ec_slave_mbox_prepare_check(slave, datagram); // can not fail.
400  fsm->retries = EC_FSM_RETRIES;
401  return;
402  }
403 
404  // Fetch response
405  ec_slave_mbox_prepare_fetch(slave, datagram); // can not fail.
406  fsm->retries = EC_FSM_RETRIES;
407  fsm->state = ec_fsm_mbg_response;
408 }
409 
410 /*****************************************************************************/
411 
418  ec_fsm_mbg_t *fsm,
419  ec_datagram_t *datagram
420  )
421 {
422  ec_slave_t *slave = fsm->slave;
423  ec_mbg_request_t *request = fsm->request;
424 
425  if (fsm->datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--) {
426  ec_slave_mbox_prepare_fetch(slave, datagram); // can not fail.
427  return;
428  }
429 
430  if (fsm->datagram->state != EC_DATAGRAM_RECEIVED) {
431  request->error_code = EIO;
432  fsm->state = ec_fsm_mbg_error;
433  EC_SLAVE_ERR(slave, "Failed to receive MBox Gateway"
434  " response datagram: ");
436  return;
437  }
438 
439  if (fsm->datagram->working_counter != 1) {
440  // only an error if data has not already been read by another read request
441  if (slave->mbox_mbg_data.payload_size == 0) {
442  request->error_code = EIO;
443  fsm->state = ec_fsm_mbg_error;
445  EC_SLAVE_ERR(slave, "Reception of MBox Gateway response failed: ");
447  return;
448  }
449  }
452  fsm->state(fsm, datagram);
453 }
454 
455 /*****************************************************************************/
456 
463  ec_fsm_mbg_t *fsm,
464  ec_datagram_t *datagram
465  )
466 {
467  ec_slave_t *slave = fsm->slave;
468  ec_mbg_request_t *request = fsm->request;
469  uint8_t *data, mbox_type;
470  size_t data_size;
471  int ret;
472 
473  // process the data available or initiate a new mailbox read check
474  if (slave->mbox_mbg_data.payload_size > 0) {
475  slave->mbox_mbg_data.payload_size = 0;
476  } else {
477  // initiate a new mailbox read check if required data is not available
478  if (ec_read_mbox_locked(slave)) {
479  // await current read request and mark the datagram as invalid
480  datagram->state = EC_DATAGRAM_INVALID;
481  } else {
482  ec_slave_mbox_prepare_check(slave, datagram); // can not fail.
483  fsm->state = ec_fsm_mbg_check;
484  }
485  return;
486  }
487 
488  // check data is assigned
489  if (!slave->mbox_mbg_data.data) {
490  request->error_code = EPROTO;
491  fsm->state = ec_fsm_mbg_error;
492  EC_SLAVE_ERR(slave, "No mailbox response data received!\n");
493  return;
494  }
495  data = slave->mbox_mbg_data.data;
496  data_size = EC_READ_U16(data);
497 
498  // sanity check that data size received is not too big
499  if (data_size + EC_MBOX_HEADER_SIZE > slave->configured_tx_mailbox_size) {
500  request->error_code = EPROTO;
501  fsm->state = ec_fsm_mbg_error;
502  EC_SLAVE_ERR(slave, "Corrupt mailbox response received!\n");
504  return;
505  }
506 
507  // check for error response, output to log, but continue
508  mbox_type = EC_READ_U8(data + 5) & 0x0F;
509  if (mbox_type == 0x00) {
510  const ec_code_msg_t *mbox_msg;
511  uint16_t code = EC_READ_U16(data + 8);
512 
513  EC_SLAVE_ERR(slave, "Mailbox Gateway error response received - ");
514 
515  for (mbox_msg = mbox_error_messages; mbox_msg->code; mbox_msg++) {
516  if (mbox_msg->code != code)
517  continue;
518  printk(KERN_CONT "Code 0x%04X: \"%s\".\n",
519  mbox_msg->code, mbox_msg->message);
520  break;
521  }
522 
523  if (!mbox_msg->code) {
524  printk(KERN_CONT "Unknown error reply code 0x%04X.\n", code);
525  }
526 
527  if (slave->master->debug_level && data_size > 0) {
528  ec_print_data(data + EC_MBOX_HEADER_SIZE, data_size);
529  }
530  }
531 
532  // add back on the header size
533  data_size += EC_MBOX_HEADER_SIZE;
534 
535  // check the response matches the request mbox type
536  if (mbox_type != request->mbox_type) {
537  request->error_code = EIO;
538  fsm->state = ec_fsm_mbg_error;
539  EC_SLAVE_ERR(slave, "Received mailbox type 0x%02X as response.\n",
540  mbox_type);
541  return;
542  }
543 
544  if (slave->master->debug_level) {
545  EC_SLAVE_DBG(slave, 1, "MBox Gateway response:\n");
546  ec_print_data(data, data_size);
547  }
548 
549  ret = ec_mbg_request_copy_data(request, data, data_size);
550  if (ret) {
551  request->error_code = -ret;
552  fsm->state = ec_fsm_mbg_error;
553  return;
554  }
555 
556  fsm->state = ec_fsm_mbg_end;
557 }
558 
559 /*****************************************************************************/
560 
566  ec_fsm_mbg_t *fsm,
567  ec_datagram_t *datagram
568  )
569 {
570 }
571 
572 /*****************************************************************************/
573 
579  ec_fsm_mbg_t *fsm,
580  ec_datagram_t *datagram
581  )
582 {
583 }
584 
585 /*****************************************************************************/
unsigned int retries
retries upon datagram timeout
uint8_t * data
Mailbox response data.
Definition: datagram.h:123
#define EC_FSM_RETRIES
Number of state machine retries on datagram timeout.
Definition: globals.h:59
Vendor specific.
Definition: globals.h:187
unsigned long jiffies_sent
Jiffies, when the datagram was sent.
Definition: datagram.h:105
uint8_t mbox_type
Cached MBox type.
uint16_t configured_tx_mailbox_size
Configured send mailbox size.
Definition: slave.h:248
EtherCAT Mailbox Gateway request.
void ec_fsm_mbg_error(ec_fsm_mbg_t *, ec_datagram_t *)
State: ERROR.
void(* state)(ec_fsm_mbg_t *, ec_datagram_t *)
mbox state function
#define EC_SLAVE_DBG(slave, level, fmt, args...)
Convenience macro for printing slave-specific debug messages to syslog.
Definition: slave.h:108
Servo-Profile over EtherCAT.
Definition: globals.h:186
size_t data_size
Size of MBox request data.
void ec_fsm_mbg_response_data(ec_fsm_mbg_t *, ec_datagram_t *)
MBox Gateway state: RESPONSE DATA.
uint32_t response_timeout
Maximum time in ms, the transfer is retried, if the slave does not respond.
ec_mbox_data_t mbox_mbg_data
Received mailbox data for MBox Gateway.
Definition: slave.h:295
int ec_slave_mbox_prepare_fetch(const ec_slave_t *slave, ec_datagram_t *datagram)
Prepares a datagram to fetch mailbox data.
Definition: mailbox.c:134
uint32_t code
Code.
Definition: globals.h:314
#define EC_SLAVE_WARN(slave, fmt, args...)
Convenience macro for printing slave-specific warnings to syslog.
Definition: slave.h:91
EtherCAT datagram.
Definition: datagram.h:88
uint16_t working_counter
Working counter.
Definition: datagram.h:100
uint16_t station_address
Configured station address.
Definition: slave.h:222
const char * message
Message belonging to code.
Definition: globals.h:315
int ec_fsm_mbg_prepare_start(ec_fsm_mbg_t *fsm, ec_datagram_t *datagram)
Prepare a request.
void ec_fsm_mbg_response(ec_fsm_mbg_t *, ec_datagram_t *)
MBox Gateway state: RESPONSE.
Global definitions and macros.
EtherCAT master structure.
uint8_t * data
Pointer to MBox request data.
EtherCAT slave.
Definition: slave.h:214
void ec_fsm_mbg_transfer(ec_fsm_mbg_t *fsm, ec_slave_t *slave, ec_mbg_request_t *request)
Starts to transfer a mailbox gateway request to/from a slave.
uint16_t error_code
MBox Gateway error code.
ec_sii_image_t * sii_image
Current complete SII image.
Definition: slave.h:267
Code/Message pair.
Definition: globals.h:313
int ec_mbg_request_copy_data(ec_mbg_request_t *req, const uint8_t *source, size_t size)
Copies Mbox Gateway data from an external source.
ec_datagram_state_t state
State.
Definition: datagram.h:101
CANopen over EtherCAT.
Definition: globals.h:184
uint16_t mailbox_protocols
Supported mailbox protocols.
Definition: slave.h:172
int mbox_type_to_prot(uint8_t mbox_type, uint8_t *mbox_prot)
convert mailbox type number to mailbox prototype flag
unsigned int debug_level
Master debug level.
Definition: master.h:310
#define EC_SLAVE_ERR(slave, fmt, args...)
Convenience macro for printing slave-specific errors to syslog.
Definition: slave.h:77
void ec_datagram_print_wc_error(const ec_datagram_t *datagram)
Evaluates the working counter of a single-cast datagram.
Definition: datagram.c:627
void ec_fsm_mbg_clear(ec_fsm_mbg_t *fsm)
Destructor.
int ec_fsm_mbg_success(const ec_fsm_mbg_t *fsm)
Returns, if the state machine terminated with success.
uint16_t configured_rx_mailbox_offset
Configured receive mailbox offset.
Definition: slave.h:242
Ethernet over EtherCAT.
Definition: globals.h:183
ec_master_t * master
Master owning the slave.
Definition: slave.h:216
Finite state machines for the CANopen over EtherCAT protocol.
int ec_datagram_fpwr(ec_datagram_t *datagram, uint16_t configured_address, uint16_t mem_address, size_t data_size)
Initializes an EtherCAT FPWR datagram.
Definition: datagram.c:320
ec_datagram_t * datagram
Datagram used in last step.
int ec_read_mbox_locked(ec_slave_t *slave)
Return the current mailbox lock status and lock it if not locked.
Definition: slave.c:229
void ec_fsm_mbg_init(ec_fsm_mbg_t *fsm)
Constructor.
const ec_code_msg_t mbox_error_messages[]
Mailbox error codes.
Definition: mailbox.c:154
#define EC_MBOX_HEADER_SIZE
Mailbox header size.
Definition: globals.h:100
void ec_print_data(const uint8_t *, size_t)
Outputs frame contents for debugging purposes.
Definition: module.c:355
void ec_read_mbox_lock_clear(ec_slave_t *slave)
Clears the mailbox lock.
Definition: slave.c:216
EtherCAT Mailbox Gateway state machine.
int ec_fsm_mbg_exec(ec_fsm_mbg_t *fsm, ec_datagram_t *datagram)
Executes the current state of the state machine.
unsigned long jiffies_start
MBox Gateway timestamp.
int ec_slave_mbox_prepare_check(const ec_slave_t *slave, ec_datagram_t *datagram)
Prepares a datagram for checking the mailbox state.
Definition: mailbox.c:103
#define EC_READ_U16(DATA)
Read a 16-bit unsigned value from EtherCAT data.
Definition: ecrt.h:2554
void ec_datagram_print_state(const ec_datagram_t *datagram)
Prints the state of a datagram.
Definition: datagram.c:587
Mailbox functionality.
void ec_fsm_mbg_end(ec_fsm_mbg_t *, ec_datagram_t *)
State: END.
Timed out (dequeued).
Definition: datagram.h:79
void ec_fsm_mbg_check(ec_fsm_mbg_t *, ec_datagram_t *)
MBox Gateway state: CHECK.
unsigned long jiffies_sent
Jiffies, when the upload/download request was sent.
uint16_t configured_rx_mailbox_size
Configured receive mailbox size.
Definition: slave.h:244
ec_mbg_request_t * request
MBox Gateway request.
void ec_fsm_mbg_request(ec_fsm_mbg_t *, ec_datagram_t *)
MBox Gateway: REQUEST.
void ec_fsm_mbg_start(ec_fsm_mbg_t *, ec_datagram_t *)
MBox Gateway state: START.
uint8_t * data
Datagram payload.
Definition: datagram.h:95
#define EC_READ_U8(DATA)
Read an 8-bit unsigned value from EtherCAT data.
Definition: ecrt.h:2538
EtherCAT slave configuration structure.
ec_sii_t sii
Extracted SII data.
Definition: slave.h:207
Unused and should not be queued (dequeued).
Definition: datagram.h:81
Received (dequeued).
Definition: datagram.h:78
ADS over EtherCAT.
Definition: globals.h:182
ec_slave_t * slave
slave the FSM runs on
File-Access over EtherCAT.
Definition: globals.h:185
unsigned long jiffies_received
Jiffies, when the datagram was received.
Definition: datagram.h:110
size_t payload_size
Size of the mailbox response payload data.
Definition: datagram.h:125
int ec_slave_mbox_check(const ec_datagram_t *datagram)
Processes a mailbox state checking datagram.
Definition: mailbox.c:122