1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
/*      File: slave.h
*       This file is part of the program ethercatcpp-core
*       Program description : EtherCAT driver libraries for UNIX
*       Copyright (C) 2017-2024 -  Robin Passama (LIRMM / CNRS) Arnaud Meline (LIRMM / CNRS) Benjamin Navarro (LIRMM / CNRS). All Right reserved.
*
*       This software is free software: you can redistribute it and/or modify
*       it under the terms of the CeCILL-C license as published by
*       the CEA CNRS INRIA, either version 1
*       of the License, or (at your option) any later version.
*       This software 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
*       CeCILL-C License for more details.
*
*       You should have received a copy of the CeCILL-C License
*       along with this software. If not, it can be found on the official website
*       of the CeCILL licenses family (http://www.cecill.info/index.en.html).
*/
/**
 * @file slave.h
 * @author Arnaud Meline (original)
 * @author Benjamin Navarro (refactoring)
 * @author Robin Passama (design and refactoring)
 * @brief Header file for SlaveInfo class
 * @date October 2018 12.
 * @ingroup ethercatcpp-core
 */

#pragma once

#include <ethercatcpp/slave_device.h>
#include <cstdint>
#include <string>

#include <ethercat.h>

// Forward declarations
using ecx_contextt = struct ecx_context;

/*! \namespace ethercatcpp
 *
 * Root namespace for common and general purpose ethercatcpp packages
 */
namespace ethercatcpp {

class Master;

/** @brief This class define an EtherCAT slave
 *
 * The slave class regroup all datas / informations for an EtherCAT slave
 * device.
 */
class SlaveInfo {
public:
    /***
     * @brief Constructor of SlaveInfo class
     *
     * @param [in] unit_dev_ptr is its SlaveDevice pointer.
     */
    SlaveInfo(SlaveDevice* unit_dev_ptr);
    SlaveInfo(SlaveInfo&&) = default;
    SlaveInfo(SlaveInfo&) = delete;

    ~SlaveInfo();

    SlaveInfo& operator=(SlaveInfo&&) = default;
    SlaveInfo& operator=(SlaveInfo&) = delete;

    /**
     * @brief Set master context
     *
     * @param [in] conext is master context address.
     */
    void set_master_context(ecx_contextt* conext);

    /**
     * @brief Get slave position on EtherCAT master bus.
     *
     * @return slave position on EtherCAT master bus.
     */
    uint16_t ec_bus_position() const;

    /**
     * @brief Set slave position on EtherCAT master bus.
     *
     * @param [in] position slave position on EtherCAT master bus.
     */
    void set_ec_bus_position(uint16_t position);

    /**
     * @brief Get EtherCAT AL state.
     *
     * @return slave EtherCAT AL state.
     */
    uint16_t state() const;

    /**
     * @brief Set slave EtherCAT AL state.
     *
     * @param [in] state is the slave EtherCAT AL state.
     */
    void set_state(uint16_t state);

    /**
     * @brief Get EtherCAT station configured address
     *
     * @return EtherCAT station configured address.
     */
    uint16_t configured_addr() const;

    /**
     * @brief Set EtherCAT station configured address
     *
     * @param [in] configadr is the EtherCAT station configured address.
     */
    void configure_address(uint16_t configadr);

    /**
     * @brief Get EtherCAT station Alias address
     *
     * @return EtherCAT station Alias address.
     */
    uint16_t alias_addr() const;

    /**
     * @brief Function to set EtherCAT station Alias address
     *
     * @param [in] aliasadr is the EtherCAT station Alias address.
     */
    void set_alias_addr(uint16_t aliasadr);

    /**
     * @brief Get EtherCAT device manufacturer id.
     *
     * @return EtherCAT device manufacturer id.
     */
    uint32_t eep_manufacturer() const;

    /**
     * @brief Set EtherCAT device manufacturer id.
     *
     * Some time when EEPROM device is not configure, we have to set this
     * value from ESI file.
     *
     * @param [in] eep_man is the device manufacturer id.
     */
    void set_eep_manufacturer(uint32_t eep_man);

    /**
     * @brief Function to get EtherCAT device id.
     *
     * @return the device id.
     */
    uint32_t eep_device() const;

    /**
     * @brief Set EtherCAT device id.
     *
     * Some time when EEPROM device is not configure, we have to set this
     * value from ESI file.
     *
     * @param [in] eep_man is the device id.
     */
    void set_eep_device(uint32_t eep_id);

    uint32_t serial_number() const;

    void set_serial_number(uint32_t serial_number);

    // Outputs config from Master to SlaveInfo (input for slave)
    /**
     * @brief Get pointer in master IOmap for output datas (from Master to
     * SlaveInfo).
     *
     * @return  pointer in master buffer IOmap for output datas (from Master
     * to SlaveInfo).
     */
    uint8_t* output_address() const;

    /**
     * @brief Set pointer in master buffer IOmap for output
     * datas (from Master to SlaveInfo).
     *
     * @param [in] output_address_ptr  pointer in master buffer IOmap for
     * output datas (from Master to SlaveInfo).
     */
    void set_output_address(uint8_t* output_address_ptr);

    /**
     * @brief Get size of slave output buffer in bits (from Master to Slave).
     *
     * @return size of slave output buffer in bits (from Master to Slave).
     */
    uint16_t output_size_bits() const;

    /**
     * @brief Set size of slave output buffer in bits (from Master to Slave).
     *
     * @param [in] outputs_size_bits size of slave output buffer in bits
     * (from Master to Slave).
     */
    void set_output_size_bits(uint16_t outputs_size_bits);

    /**
     * @brief Get size of slave output buffer in bytes (from Master to Slave).
     *
     * @return size of slave output buffer in bytes (from Master to Slave).
     */
    uint32_t output_size() const;

    /**
     * @brief Set size of slave output buffer in bytes (from Master to Slave).
     *
     * @param [in] outputs_size_bits size of slave output buffer in bytes
     * (from Master to Slave).
     */
    void set_output_size(uint16_t outputs_size_bytes);

    /**
     * @brief FGet the start bit in the first byte of output
     * buffer.
     *
     * @return the start bit in the first byte of output buffer.
     */
    uint8_t output_start_bit() const;

    /**
     * @brief Set the start bit in the first byte of output buffer.
     *
     * @param [in] output_start_bit is the start bit in the first byte of
     * output buffer.
     */
    void set_output_start_bit(uint8_t output_start_bit);

    // inputs config from Slave to Master (output for slave)
    /**
     * @brief Get pointer in master IOmap for input datas (from Slave to
     * Master).
     *
     * @return  pointer in master buffer IOmap for input datas (from Slave
     * to Master).
     */
    uint8_t* input_address() const;

    /**
     * @brief Set pointer in master buffer IOmap for input datas (from Slave to
     * Master).
     *
     * @param [in] input_address_ptr  pointer in master buffer IOmap for
     * input datas (from Slave to Master).
     */
    void set_input_address(uint8_t* input_address_ptr);

    /**
     * @brief Get size of slave input buffer in bits (from Slave to Master).
     *
     * @return size of slave input buffer in bits (from Slave to Master).
     */
    uint16_t input_size_bits() const;

    /**
     * @brief Set size of slave input buffer in bits (from Slave to Master).
     *
     * @param [in] inputs_size_bits size of slave input buffer in bits (from
     * Slave to Master).
     */
    void set_input_size_bits(uint16_t inputs_size_bits);

    /**
     * @brief Get size of slave input buffer in bytes (from Slave to Master).
     *
     * @return size of slave input buffer in bytes (from Slave to Master).
     */
    uint32_t input_size() const;

    /**
     * @brief Set size of slave input buffer in bytes (from Slave to Master).
     *
     * @param [in] inputs_size_bits size of slave input buffer in bytes
     * (from Slave to Master).
     */
    void set_input_size(uint16_t inputs_size_bytes);

    /**
     * @brief Get the start bit in the first byte of input buffer.
     *
     * @return the start bit in the first byte of input buffer.
     */
    uint8_t input_start_bit() const;

    /**
     * @brief Set the start bit in the first byte of input buffer.
     *
     * @param [in] input_start_bit is the start bit in the first byte of
     * input buffer.
     */
    void set_input_start_bit(uint8_t input_start_bit);

    // SyncManager configuration (ec_smt struct)
    /**
     * @brief Get a specific SyncMananger start address.
     *
     * @param [in] sm_id desired SyncManager id.
     * @return the selected SyncMananger start address.
     */
    uint16_t SM_start_address(const int& sm_id) const;

    /**
     * @brief Set a specific SyncMananger start address.
     *
     * @param [in] sm_id desired SyncManager id.
     * @param [in] startaddr SyncMananger start address.
     */
    void set_SM_start_address(const int& sm_id, uint16_t startaddr);

    /**
     * @brief Get a specific SyncMananger buffer length.
     *
     * @param [in] sm_id desired SyncManager id.
     * @return the selected SyncMananger buffer length.
     */
    uint16_t SM_length(const int& sm_id) const;

    /**
     * @brief Set a specific SyncMananger buffer length.
     *
     * @param [in] sm_id desired SyncManager id.
     * @param [in] sm_length SyncMananger buffer length.
     */
    void set_SM_length(const int& sm_id, uint16_t sm_length);

    /**
     * @brief Get flags of a specific SyncMananger.
     *
     * @param [in] sm_id desired SyncManager id.
     * @return the selected SyncMananger flags.
     */
    uint32_t SM_flags(const int& sm_id) const;

    /**
     * @brief Set flags of a specific SyncMananger.
     *
     * @param [in] sm_id desired SyncManager id.
     * @param [in] sm_flag SyncMananger flags.
     */
    void set_SM_flags(const int& sm_id, uint32_t sm_flag);

    /**
     * @brief Get type of a specific SyncMananger.
     *
     * @param [in] sm_id desired SyncManager id.
     * @return the selected SyncMananger type.
     */
    uint8_t SM_type(const int& sm_id) const;

    /**
     * @brief Set type of a specific SyncMananger.
     *
     * @param [in] sm_id desired SyncManager id.
     * @param [in] sm_type SyncMananger type.
     */
    void set_SM_type(const int& sm_id, uint8_t sm_type);

    // FMMU configurations (ec_fmmut) //fmmu_id < EC_MAXFMMU !!
    /**
     * @brief Get logical start buffer address of a specific FMMU.
     *
     * @param [in] fmmu_id desired FMMU id.
     * @return the selected FMMU logical start buffer address.
     */
    uint32_t FMMU_logical_start(const int& fmmu_id) const;

    /**
     * @brief Set logical start buffer address of a specific FMMU.
     *
     * @param [in] fmmu_id desired FMMU id.
     * @param [in] logical_start FMMU logical start buffer address.
     */
    void set_FMMU_logical_start(const int& fmmu_id, uint32_t logical_start);

    /**
     * @brief Get logical buffer length of a specific FMMU .
     *
     * @param [in] fmmu_id desired FMMU id.
     * @return the selected FMMU logical buffer length.
     */
    uint16_t FMMU_logical_length(const int& fmmu_id) const;

    /**
     * @brief Set logical buffer length of a specific FMMU .
     *
     * @param [in] fmmu_id desired FMMU id.
     * @param [in] logical_length FMMU logical buffer length.
     */
    void set_FMMU_logical_length(const int& fmmu_id, uint16_t logical_length);

    /**
     * @brief Get the start bit in the first byte of a specific
     * FMMU logical buffer.
     *
     * @param [in] fmmu_id desired FMMU id.
     * @return start bit in the first byte of a specific FMMU logical
     * buffer.
     */
    uint8_t FMMU_logical_start_bit(const int& fmmu_id) const;

    /**
     * @brief Set the start bit in the first byte of a specific
     * FMMU logical buffer.
     *
     * @param [in] fmmu_id desired FMMU id.
     * @param [in] logical_start_bit start bit in the first byte of a
     * specific FMMU logical buffer.
     */
    void set_FMMU_logical_start_bit(const int& fmmu_id,
                                    uint8_t logical_start_bit);

    /**
     * @brief Get the end bit in the last byte of a specific FMMU logical
     * buffer.
     *
     * @param [in] fmmu_id desired FMMU id.
     * @return the end bit in the last byte of a desired FMMU logical
     * buffer.
     */
    uint8_t FMMU_logical_end_bit(const int& fmmu_id) const;

    /**
     * @brief Set the end bit in the last byte of a specific FMMU logical
     * buffer.
     *
     * @param [in] fmmu_id desired FMMU id.
     * @param [in] logical_end_bit end bit in the last byte of FMMU logical
     * buffer.
     */
    void set_FMMU_logical_end_bit(const int& fmmu_id, uint8_t logical_end_bit);

    /**
     * @brief Get start address of a specific FMMU physical buffer .
     *
     * @param [in] fmmu_id desired FMMU id.
     * @return the selected FMMU physical start buffer address.
     */
    uint16_t FMMU_physical_start(const int& fmmu_id) const;

    /**
     * @brief Set a specific FMMU physical start buffer address.
     *
     * @param [in] fmmu_id desired FMMU id.
     * @param [in] logical_start FMMU physical start buffer address.
     */
    void set_FMMU_physical_start(const int& fmmu_id, uint16_t physical_start);

    /**
     * @brief Get the start bit in the first byte of a specific
     * FMMU physical buffer.
     *
     * @param [in] fmmu_id desired FMMU id.
     * @return start bit in the first byte of a specific FMMU physical
     * buffer.
     */
    uint8_t FMMU_physical_start_bit(const int& fmmu_id) const;

    /**
     * @brief Set the start bit in the first byte of a specific
     * FMMU physical buffer.
     *
     * @param [in] fmmu_id desired FMMU id.
     * @param [in] logical_start_bit start bit in the first byte of a
     * specific FMMU physical buffer.
     */
    void set_FMMU_physical_start_bit(const int& fmmu_id,
                                     uint8_t physical_start_bit);

    /**
     * @brief Get the type of a specific FMMU.
     *
     * @param [in] fmmu_id desired FMMU id.
     * @return type of a specific FMMU.
     */
    uint8_t FMMU_type(const int& fmmu_id) const;

    /**
     * @brief Set the type of a specific FMMU.
     *
     * @param [in] fmmu_id desired FMMU id.
     * @param [in] fmmu_type type of FMMU.
     */
    void set_FMMU_type(const int& fmmu_id, uint8_t fmmu_type);

    /**
     * @brief Check if a specific FMUU is active.
     *
     * @param [in] fmmu_id desired FMMU id.
     * @return 1 if FMMU active, 0 if unactive.
     */
    uint8_t FMMU_active(const int& fmmu_id) const;

    /**
     * @brief Activate a specific FMUU.
     *
     * @param [in] fmmu_id desired FMMU id.
     * @param [in] fmmu_active 1 to activate FMMU, 0 to unactive.
     */
    void set_FMMU_active(const int& fmmu_id, uint8_t fmmu_active);

    /**
     * @brief Get number of first FMMU unused.
     *
     * @param [in] fmmu_id desired FMMU id.
     * @return number of first FMMU unused
     */
    uint8_t FMMU_unused() const;

    /**
     * @brief Function to set number of first FMMU unused.
     *
     * @param [in] fmmu_id desired FMMU id.
     * @param [in] FMMUunused number of first FMMU unused
     */
    void set_FMMU_unused(uint8_t FMMUunused);

    // DC config
    /**
     * @brief Check if a slave can use DC (distributed clock).
     *
     * @return 1 if has DC, 0 if haven't
     */
    bool has_dc() const;

    /**
     * @brief Function to set if a slave can use DC (distributed clock).
     *
     * @param [in] hasdc 1 if has DC, 0 if haven't
     */
    void set_dc(bool hasdc);

    /**
     * @brief Check if DC (distributed clock) is active.
     *
     * @return 1 if active, 0 if unactive
     */
    uint8_t dc_active();

    /**
     * @brief activate DC (distributed clock).
     *
     * @param [in] dc_active 1 if active, 0 if unactive
     */
    void activate_dc(uint8_t dc_active);

    /**
     * @brief Get delay from master to slave to synchro DC (distributed clock).
     *
     * @return delay beetween master and slave
     */
    int32_t delay() const;

    /**
     * @brief Set delay from master to slave to synchro DC (distributed clock).
     *
     * @param [in] delay delay beetween master and slave
     */
    void set_delay(int32_t delay);

    // < 0 if slave config forced.
    /**
     * @brief Check if a slave is already configured.
     *
     * @return 0 if don't configure, 1 or more if configured
     */
    uint16_t configured_index() const;

    /**
     * @brief Set a slave as (un)configured.
     *
     * @param [in] configindex  0 if don't configure, 1 or more if
     * configured
     */
    void set_configured_index(uint16_t configindex);

    // group
    /**
     * @brief Get slave's group ID.
     *
     * @return slave's group ID
     */
    uint8_t group_id() const;

    /**
     * @brief Set slave's group ID.
     *
     * @param [in] group_id slave's group ID
     */
    void set_group_id(uint8_t group_id);

    // SlaveInfo Name
    /**
     * @brief Get slave's name.
     *
     * @return slave's name
     */
    const std::string name() const;

    /**
     * @brief Set slave's name.
     *
     * @param [in] name slave's name
     */
    void set_name(const std::string& name);

    // Size of SM Vector
    /**
     * @brief Get the maximum number of SyncManager .
     *
     * @return maximum of SyncManager can be used
     */
    int max_SMs() const;

    // Size of FMMU Vector
    /**
     * @brief Function to get the maximum number of FMMU .
     *
     * @return maximum of FMMU can be used
     */
    int max_FMMUs() const;

    // Nb of step needed to update all datas
    /**
     * @brief Get the number of run steps
     *
     * @return number of run steps
     */
    uint8_t run_steps() const;

    /**
     * @brief Launch the pre_function for one specific run step
     *
     * @param [in] step is the specific step number who want to launch.
     */
    void pre_run_step(uint8_t step);

    /**
     * @brief Launch the post_function for one specific run step
     *
     * @param [in] step is the specific step number who want to launch.
     */
    void post_run_step(uint8_t step);

    /**
     * @brief Get the number of init steps
     *
     * @return number of init steps
     */
    uint8_t init_steps() const;

    /**
     * @brief Launch the pre_function for one specific init step
     *
     * @param [in] step is the specific step number who want to launch.
     */
    void pre_init_step(uint8_t step);

    /**
     * @brief Launch the post_function for one specific init step
     *
     * @param [in] step is the specific step number who want to launch.
     */
    void post_init_step(uint8_t step);

    /**
     * @brief Get the number of end steps
     *
     * @return number of end steps
     */
    uint8_t end_steps() const;

    /**
     * @brief FLaunch the pre_function for one specific end step
     *
     * @param [in] step is the specific step number who want to launch.
     */
    void pre_end_step(uint8_t step);

    /**
     * @brief Launch the post_function for one specific end step
     *
     * @param [in] step is the specific step number who want to launch.
     */
    void post_end_step(uint8_t step);

    /**
     * @brief Get the current step.
     *
     * @return current number step.
     */
    uint8_t current_step() const;

    /**
     * @brief Set the current step.
     *
     * @param[in] step current number step.
     */
    void set_current_step(uint8_t step);

    /**
     * @brief Increment value of the current step.
     */
    void increment_current_step();

    /**
     * @brief Get the time to wait value.
     *
     * This value (used only in Init and End step) set time to wait beetween
     * two EtherCAT frames.
     * @return value of timewait step
     */
    int step_wait_time() const;

    /**
     * @brief Set the time to wait value.
     *
     * This value (used only in Init and End step) set time to wait beetween
     * two EtherCAT frames.
     * @param [in] timewait value of timewait step
     */
    void set_step_wait_time(int timewait);

    // Update UnitDevice buffers
    /**
     * @brief Update In/Out buffers address
     */
    void update_device_buffers();

    /**
     * @brief Launch the init configuration function
     */
    void launch_init_configuration();

    /**
     * @brief Launch the end configuration function
     */

    void launch_end_configuration();

    /**
     * @brief Send a CoE SDO read.
     *
     * @param[in]  index      = Index to write.
     * @param[in]  sub_index  = Subindex to write.
     * @param[in]  buffer_size= Size in bytes of parameter buffer.
     * @param[out] buffer_ptr = Pointer to parameter buffer.
     * @return Workcounter from last slave response
     */
    int read_sdo(uint16_t index, uint8_t sub_index, int buffer_size,
                 void* buffer_ptr);

    /**
     * @brief Send a CoE SDO write.
     *
     * @param[in]  index      = Index to write.
     * @param[in]  sub_index  = Subindex to write.
     * @param[in]  buffer_size= Size in bytes of parameter buffer.
     * @param[out] buffer_ptr = Pointer to parameter buffer.
     * @return Workcounter from last slave response
     */
    int write_sdo(uint16_t index, uint8_t sub_index, int buffer_size,
                  void* buffer_ptr);

    // Configuration of DC synchro 0 and 1 signal
    /**
     * @brief Get the sync cycle shift for DC sync config.
     *
     * @return cycle shift value in ns
     */
    int32_t sync_cycle_shift();

    /**
     * @brief Get the sync0 cycle time for DC sync config.
     *
     * @return sync0 cycle time value in ns
     */
    uint32_t sync0_cycle_time();

    /**
     * @brief Check if DC sync0 is used.
     *
     * @return TRUE if used, FALSE if unused
     */
    bool sync0_used();

    /**
     * @brief Define DC synchro signal 0.
     *
     * @param [in] cycle_time_0 is Cycltime SYNC0 in ns.
     * @param [in] cycle_shift is CyclShift in ns.
     */
    void config_sync0(uint32_t cycle_time_0, int32_t cycle_shift);

    /**
     * @brief Get the sync1 cycle time for DC sync config.
     *
     * @return sync1 cycle time value in ns
     */
    uint32_t sync1_cycle_time();

    /**
     * @brief Check if DC sync1 is used.
     *
     * @return TRUE if used, FALSE if unused
     */
    bool sync0_1_used();

    /**
     * @brief Define DC synchro signal 0 and 1.
     *
     * @param [in] cycle_time_0 is Cycltime SYNC0 in ns.
     * @param [in] cycle_time_1 is Cycltime SYNC1 in ns. This time is a
     * delta time in relation to the SYNC0 fire. If CylcTime1 = 0 then SYNC1
     * fires a the same time as SYNC0.
     * @param [in] cycle_shift is CyclShift in ns.
     */
    void config_sync0_1(uint32_t cycle_time_0, uint32_t cycle_time_1,
                        int32_t cycle_shift); // time in ns

    int32_t read_file(std::string_view filename, uint32_t password,
                      int32_t size, uint8_t* buffer);
    bool write_file(std::string_view filename, uint32_t password, int32_t size,
                    uint8_t* buffer);

    bool read_sercos(uint8_t drive, uint8_t flags, uint16_t idn, int32_t size,
                     uint8_t* buffer);
    bool write_sercos(uint8_t drive, uint8_t flags, uint16_t idn, int32_t size,
                      uint8_t* buffer);
#ifdef EOE_AVAILABLE
    bool
    detect_ethernet_configuration(uint8_t port,
                                  SlaveDevice::EthernetConfiguration& config);
    bool configure_ethernet(uint8_t port,
                            const SlaveDevice::EthernetConfiguration& config);
    int32_t read_ethernet(uint8_t port, int32_t size, uint8_t* buffer);
    bool write_ethernet(uint8_t port, int32_t size, uint8_t* buffer);
#endif

private:
    ec_slavet slave_soem_;
    void init_soem_data();

    SlaveDevice* device_;
    ecx_contextt* context_;

    uint16_t ec_bus_pos_; // Position on EtherCAT bus
    uint32_t serial_number_;

    uint8_t current_step_; // Current step executed by master.
    int timewait_step_;    // Time to wait beetween 2 init or end steps (in us)

    // var to activate and configure Distributed clock syncro 0 signal.
    bool dc_sync0_is_used_;
    bool dc_sync0_1_is_used_;
    int32_t dc_sync_cycle_shift_;  // time in ns
    uint32_t dc_sync0_cycle_time_; // time in ns
    uint32_t dc_sync1_cycle_time_; // time in ns
};

} // namespace ethercatcpp