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
/*      File: EL5101.cpp
*       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 beckhoff_terminals/EL5101.cpp
 * @author Robin Passama
 * @brief source file for EL5101 class
 *
 */
#include <ethercatcpp/beckhoff_terminals/EL5101.h>

#include <pid/log/ethercatcpp-core_ethercatcpp-core.h>

namespace ethercatcpp {

namespace {

//----------------------------------------------------------------------------//
//                M A I L B O X    D E F I N I T I O N S //
//----------------------------------------------------------------------------//

struct [[gnu::packed]] mailbox_out_t {
    int8_t mailbox[48];<--- struct member 'mailbox_out_t::mailbox' is never used.
};
struct [[gnu::packed]] mailbox_in_t {
    int8_t mailbox[48];<--- struct member 'mailbox_in_t::mailbox' is never used.
};

//----------------------------------------------------------------------------//
//                 C Y C L I C    B U F F E R //
//----------------------------------------------------------------------------//
struct [[gnu::packed]] buffer_out_cyclic_command_t {
    uint8_t command_word = 0; // name_7010_01__04;
    uint8_t empty_5 = 0;
    uint32_t set_counter_value = 0; // name_7010_11;
};

struct [[gnu::packed]] buffer_in_cyclic_status_t {
    uint8_t status_word_1;  // name_6010_01__08;<--- struct member 'buffer_in_cyclic_status_t::status_word_1' is never used.
    uint8_t status_word_2;  // name_6010_09__10;<--- struct member 'buffer_in_cyclic_status_t::status_word_2' is never used.
    uint32_t counter_value; // name_6010_11;<--- struct member 'buffer_in_cyclic_status_t::counter_value' is never used.
    uint32_t latch_value;   // name_6010_12;<--- struct member 'buffer_in_cyclic_status_t::latch_value' is never used.
    uint32_t period_value;  // name_6010_14;<--- struct member 'buffer_in_cyclic_status_t::period_value' is never used.
};

} // namespace

EL5101::EL5101() : SlaveDevice(), command_word_(0), set_counter_value_(0) {
    set_id("EL5101", 0x00000002, 0x13ed3052);

    configure_at_init([this]() {
        // Config Command PDO mapping
        start_command_pdo_mapping<uint16_t>();
        add_command_pdo_mapping<uint16_t>(0x1603);
        end_command_pdo_mapping<uint16_t>();

        // Config Status PDO mapping
        start_status_pdo_mapping<uint16_t>();
        add_status_pdo_mapping<uint16_t>(0x1A04);
        add_status_pdo_mapping<uint16_t>(0x1A06);
        end_status_pdo_mapping<uint16_t>();

        configure_gate_polarity(0);
        enable_input_filter(false);
        enable_open_circuit_detection(detection_pin_A, true);
        enable_open_circuit_detection(detection_pin_B, true);
        enable_open_circuit_detection(detection_pin_C, true);
    });

    // Mailboxes configuration
    define_physical_buffer<mailbox_out_t>(ASYNCHROS_OUT, 0x1800, 0x00010026);
    define_physical_buffer<mailbox_in_t>(ASYNCHROS_IN, 0x1880, 0x00010022);
    // In/out buffer config
    define_physical_buffer<buffer_out_cyclic_command_t>(
        SYNCHROS_OUT, 0x1000, 0x00010024); // size depand of configured PDO
    define_physical_buffer<buffer_in_cyclic_status_t>(
        SYNCHROS_IN, 0x1100, 0x00010020); // size depand of configured PDO

    //----------------------------------------------------------------------------//
    //                     R U N S     S T E P S //
    //----------------------------------------------------------------------------//

    add_run_step([this]() { update_command_buffer(); },
                 [this]() { unpack_status_buffer(); }); // add_Run_Step end

} // constructor end

EL5101::~EL5101() = default;

void EL5101::update_command_buffer() {
    auto buff = output_buffer<buffer_out_cyclic_command_t>(0x1000);
    buff->command_word = command_word_;
    buff->set_counter_value = set_counter_value_;
}

void EL5101::unpack_status_buffer() {
    auto buff = input_buffer<buffer_in_cyclic_status_t>(0x1100);
    status_word_1_ = buff->status_word_1;
    status_word_2_ = buff->status_word_2;
    counter_value_ = buff->counter_value;
    latch_value_ = buff->latch_value;
    period_value_ = buff->period_value;
}

// Configuration fct

bool EL5101::enable_counter_reset(bool state) {
    return write_sdo(0x8010, 0x01, state);
}

bool EL5101::enable_external_reset(bool state) {
    return write_sdo(0x8010, 0x02, state);
}

bool EL5101::enable_up_down_counter(bool state) {
    return write_sdo(0x8010, 0x03, state);
}

bool EL5101::configure_gate_polarity(int state) {
    return write_sdo(0x8010, 0x04, state);
}

bool EL5101::enable_input_filter(
    bool state) {      // 1 => active filter | 0 => desactive
    state = not state; // Invert value of state. On device => 0 : activate | 1 :
                       // desactivate
    return write_sdo(0x8010, 0x08, state);
}

bool EL5101::enable_open_circuit_detection(open_circuit_pin_t pin, bool state) {
    switch (pin) {
    case detection_pin_A:
        return write_sdo(0x8010, 0x0B, state);
        break;
    case detection_pin_B:
        return write_sdo(0x8010, 0x0C, state);
        break;
    case detection_pin_C:
        return write_sdo(0x8010, 0x0D, state);
        break;
    }
    return false;
}

bool EL5101::activate_rotation_reversion(bool state) {
    return write_sdo(0x8010, 0x0E, state);
}

bool EL5101::enable_external_reset_polarity(bool state) {
    return write_sdo(0x8010, 0x10, state);
}

bool EL5101::set_frequency_windows(uint16_t value) {
    return write_sdo(0x8010, 0x11, value);
}

bool EL5101::set_frequency_scaling(uint16_t value) {
    return write_sdo(0x8010, 0x13, value);
}

bool EL5101::set_period_scaling(uint16_t value) {
    return write_sdo(0x8010, 0x14, value);
}

bool EL5101::set_frequency_resolution(uint16_t value) {
    return write_sdo(0x8010, 0x15, value);
}

bool EL5101::set_period_resolution(uint16_t value) {
    return write_sdo(0x8010, 0x16, value);
}

bool EL5101::set_frequency_wait_time(uint16_t value) {
    return write_sdo(0x8010, 0x17, value);
}

// enable_latch

void EL5101::enable_latch(latch_activation_pin_t pin, bool state) {
    switch (pin) {
    case latch_pin_C:
        command_word_ ^= (-state ^ command_word_) & (1UL << 0);
        break;
    case latch_pin_ext_pos:
        command_word_ ^= (-state ^ command_word_) & (1UL << 1);
        break;
    case latch_pin_ext_neg:
        command_word_ ^= (-state ^ command_word_) & (1UL << 3);
        break;
    }
}
//

void EL5101::enable_counter_offset(bool state) {
    command_word_ ^= (-state ^ command_word_) & (1UL << 2);
}
void EL5101::set_counter_offset(uint32_t value) {
    set_counter_value_ = value;
}

bool EL5101::check_latch_validity(latch_activation_pin_t pin) const {
    switch (pin) {
    case latch_pin_C:
        return (status_word_1_ >> 0) & 1U;
        break;
    case latch_pin_ext_pos:
        return (status_word_1_ >> 1) & 1U;
        break;
    case latch_pin_ext_neg:
        return (status_word_1_ >> 1) & 1U;
        break;
    }
    return false;
}

bool EL5101::check_counter_offset() const {
    return (status_word_1_ >> 2) & 1U;
}

bool EL5101::counter_underflow() const {
    return (status_word_1_ >> 3) & 1U;
}

bool EL5101::counter_overflow() const {
    return (status_word_1_ >> 4) & 1U;
}

bool EL5101::state_input_1() const {
    return (status_word_1_ >> 5) & 1U;
}

bool EL5101::open_circuit() const {
    return (status_word_1_ >> 6) & 1U;
}

bool EL5101::extrapolation_stall() const {
    return (status_word_1_ >> 7) & 1U;
}

bool EL5101::state_input_A() const {
    return (status_word_2_ >> 0) & 1U;
}

bool EL5101::state_input_B() const {
    return (status_word_2_ >> 1) & 1U;
}

bool EL5101::state_input_C() const {
    return (status_word_2_ >> 2) & 1U;
}

bool EL5101::state_input_gate() const {
    return (status_word_2_ >> 3) & 1U;
}

bool EL5101::state_input_external_latch() const {
    return (status_word_2_ >> 4) & 1U;
}

bool EL5101::sync_error() const {
    return (status_word_2_ >> 5) & 1U; // 0=OK
}

bool EL5101::valid() const {
    return not((status_word_2_ >> 6) & 1U); // 0=valid
}

bool EL5101::updated() const {
    return (status_word_2_ >> 7) & 1U;
}

uint32_t EL5101::counter() const {
    return counter_value_;
}

uint32_t EL5101::latch() const {
    return latch_value_;
}

uint32_t EL5101::period() const {
    return period_value_;
}

void EL5101::print() const {

    pid_log << pid::info
            << " Latch Validity on C = " << check_latch_validity(latch_pin_C)
            << pid::endl;
    pid_log << pid::info << " Latch Validity on ext neg = "
            << check_latch_validity(latch_pin_ext_neg) << pid::endl;
    pid_log << pid::info << " Latch Validity on ext pos = "
            << check_latch_validity(latch_pin_ext_pos) << pid::endl;
    pid_log << pid::info << " Counter_Offset_Set = " << check_counter_offset()
            << pid::endl;
    pid_log << pid::info << " Counter_Underflow = " << counter_underflow()
            << pid::endl;
    pid_log << pid::info << " Counter_Overflow = " << counter_overflow()
            << pid::endl;
    pid_log << pid::info << " State_Input_1 = " << state_input_1() << pid::endl;
    pid_log << pid::info << " Open_Circuit = " << open_circuit() << pid::endl;
    pid_log << pid::info << " Extrapolation_Stall = " << extrapolation_stall()
            << pid::endl;
    pid_log << pid::info << " State_Input_A = " << state_input_A() << pid::endl;
    pid_log << pid::info << " State_Input_B = " << state_input_B() << pid::endl;
    pid_log << pid::info << " State_Input_C = " << state_input_C() << pid::endl;
    pid_log << pid::info << " State_Input_Gate = " << state_input_gate()
            << pid::endl;
    pid_log << pid::info
            << " State_Input_Ext_Latch = " << state_input_external_latch()
            << pid::endl;
    pid_log << pid::info << " Sync_Error = " << sync_error() << pid::endl;
    pid_log << pid::info << " Data_Validity = " << valid() << pid::endl;
    pid_log << pid::info << " Data_Updated = " << updated() << pid::endl;
    pid_log << pid::info << " counter_value = " << counter() << pid::endl;
    pid_log << pid::info << " Latch_value = " << latch() << pid::endl;
    pid_log << pid::info << " Period_value = " << period() << pid::endl;
    pid_log << pid::flush;
}

} // namespace ethercatcpp