| Line |
Branch |
Exec |
Source |
| 1 |
|
|
/***************************************************************************** |
| 2 |
|
|
* |
| 3 |
|
|
* This file is part of the ecapp library (EtherCAT application devices). |
| 4 |
|
|
* |
| 5 |
|
|
* Copyright (C) 2026 Florian Pose <fp@igh.de> |
| 6 |
|
|
* |
| 7 |
|
|
* The ecapp library is free software: you can redistribute it and/or |
| 8 |
|
|
* modify it under the terms of the GNU Lesser General Public License |
| 9 |
|
|
* as published by the Free Software Foundation, version 3 of the |
| 10 |
|
|
* License. |
| 11 |
|
|
* |
| 12 |
|
|
* The ecapp library is distributed in the hope that it will be useful, |
| 13 |
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 14 |
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| 15 |
|
|
* Lesser General Public License for more details. |
| 16 |
|
|
* |
| 17 |
|
|
* You should have received a copy of the GNU Lesser General Public |
| 18 |
|
|
* License along with the ecapp library. If not, see |
| 19 |
|
|
* <https://www.gnu.org/licenses/>. |
| 20 |
|
|
* |
| 21 |
|
|
* Beckhoff pulse-train output terminals: EL2521 (1Ch., RS422), |
| 22 |
|
|
* EL2521-0024 (1Ch., 24V DC), EL2521-0025 (1Ch., 24V DC, negative |
| 23 |
|
|
* switching), EL2522 (2Ch.). The three EL2521-xxxx suffixes share one |
| 24 |
|
|
* product code -- same electronics, only the output driver stage |
| 25 |
|
|
* differs (same convention already used for EL3062/EL3062-0030 in |
| 26 |
|
|
* Ex3xxx.cpp; verify against your own hardware's SII if this ever turns |
| 27 |
|
|
* out to differ). This grouping is an implementation detail -- |
| 28 |
|
|
* application code never names Ex25xx directly, it goes through |
| 29 |
|
|
* createSubDevice("EL2521") / createSubDevice("EL2522") and gets an |
| 30 |
|
|
* EcApp::SubDevice back. |
| 31 |
|
|
* |
| 32 |
|
|
* Always configured in the terminal's "erweiterter Betriebsmodus" |
| 33 |
|
|
* (extended operating mode) -- not the EL2521-xxxx's legacy/normal |
| 34 |
|
|
* mode (Ctrl/Data Out, Status/Data In at 0x7000/0x6000), and not |
| 35 |
|
|
* Distributed-Clocks synchronous operation (SM-synchronous/FreeRun |
| 36 |
|
|
* instead; the EL2522's "continues position" variant, which needs |
| 37 |
|
|
* DC-Synchron, is not implemented -- ecapp does not configure DC for |
| 38 |
|
|
* any device yet). EL2521-xxxx uses the "Standard 16 Bit (MDP |
| 39 |
|
|
* 253/511)" predefined PDO assignment; EL2522 the factory-default |
| 40 |
|
|
* "2 Ch. Standard 32 Bit (MDP 253/511)". |
| 41 |
|
|
* |
| 42 |
|
|
* Both families place their PTO (pulse-train generator) CoE objects at |
| 43 |
|
|
* 0x7000/0x6000/0x8000 (etc.) plus 0x10 per "channel slot": EL2522 |
| 44 |
|
|
* channel 1 sits at slot 0, channel 2 at slot 1; EL2521-xxxx's single |
| 45 |
|
|
* channel sits at slot 1 (slot 0 -- 0x7000/0x6000/0x8000 -- stays |
| 46 |
|
|
* reserved there for the legacy-mode-compatible Ctrl/Data-Out, |
| 47 |
|
|
* Status/Data-In, Feature-object pairing this driver does not use). |
| 48 |
|
|
* Type::slot[] below records that per channel, which is what lets one |
| 49 |
|
|
* shared constructor/update loop serve both families. |
| 50 |
|
|
* |
| 51 |
|
|
* ENC (counter/encoder) CoE objects follow the same per-channel-slot |
| 52 |
|
|
* scheme for EL2522 (channel 1 at 0x7020/0x6020, channel 2 at |
| 53 |
|
|
* 0x7030/0x6030), but NOT for EL2521-xxxx: its single ENC block stays |
| 54 |
|
|
* at the unshifted 0x7020/0x6020 even though its PTO block is at slot |
| 55 |
|
|
* 1. Type::encSlot[] records that separately from Type::slot[]. |
| 56 |
|
|
* |
| 57 |
|
|
****************************************************************************/ |
| 58 |
|
|
|
| 59 |
|
|
#ifndef ECAPP_EX25XX_H |
| 60 |
|
|
#define ECAPP_EX25XX_H |
| 61 |
|
|
|
| 62 |
|
|
/****************************************************************************/ |
| 63 |
|
|
|
| 64 |
|
|
#include "ecapp/Mode.h" |
| 65 |
|
|
#include "ecapp/PulseTrainOutput.h" |
| 66 |
|
|
|
| 67 |
|
|
#include <ecrt.h> // EtherCAT realtime interface |
| 68 |
|
|
#include <stdint.h> |
| 69 |
|
|
#include <string> |
| 70 |
|
|
#include <vector> |
| 71 |
|
|
|
| 72 |
|
|
/****************************************************************************/ |
| 73 |
|
|
|
| 74 |
|
|
namespace EcApp { |
| 75 |
|
|
|
| 76 |
|
|
class Master; |
| 77 |
|
|
class Domain; |
| 78 |
|
|
|
| 79 |
|
|
struct Ex25xxType; |
| 80 |
|
|
|
| 81 |
|
|
template <Mode mode> |
| 82 |
|
|
class Ex25xxAdapter; // Ex25xx.cpp -- the SubDevice wrapping this class, |
| 83 |
|
|
// friended below so it can reach every channel |
| 84 |
|
|
// vector directly for pdserv publishing. |
| 85 |
|
|
|
| 86 |
|
|
template <Mode mode> |
| 87 |
|
2 |
class Ex25xx |
| 88 |
|
|
{ |
| 89 |
|
|
friend class Ex25xxAdapter<mode>; |
| 90 |
|
|
|
| 91 |
|
|
public: |
| 92 |
|
|
enum Type { EL2521, EL2521_0024, EL2521_0025, EL2522, NumTypes }; |
| 93 |
|
|
|
| 94 |
|
|
Ex25xx(Master *, uint16_t, uint16_t, Domain *, Domain *, Type); |
| 95 |
|
|
|
| 96 |
|
|
void updateInputs(); |
| 97 |
|
|
void updateOutputs(); |
| 98 |
|
|
|
| 99 |
|
|
/** See PulseTrainOutput::configure(). */ |
| 100 |
|
|
void configure( |
| 101 |
|
|
unsigned int channel, |
| 102 |
|
|
PulseTrainOutputMode outputMode, |
| 103 |
|
|
bool negativeLogic, |
| 104 |
|
|
bool travelDistanceControl); |
| 105 |
|
|
|
| 106 |
|
|
unsigned int numChannels() const; |
| 107 |
|
|
bool hasInputTZ() const; |
| 108 |
|
|
|
| 109 |
|
|
private: |
| 110 |
|
|
const Ex25xxType &type; |
| 111 |
|
|
ec_slave_config_t *sc; |
| 112 |
|
|
Domain *const domainOut; |
| 113 |
|
|
Domain *const domainIn; |
| 114 |
|
|
|
| 115 |
|
|
std::vector<bool> configured; |
| 116 |
|
|
|
| 117 |
|
|
// Outputs, one entry per channel |
| 118 |
|
|
std::vector<uint8_t> frequencySelect; |
| 119 |
|
|
std::vector<uint8_t> disableRamp; |
| 120 |
|
|
std::vector<uint8_t> goCounter; |
| 121 |
|
|
std::vector<int16_t> frequencyValue; |
| 122 |
|
|
std::vector<int32_t> targetCounterValue; // 16-bit range on a |
| 123 |
|
|
// non-"wide" type -- see |
| 124 |
|
|
// Type::wide |
| 125 |
|
|
std::vector<uint8_t> setCounter; |
| 126 |
|
|
std::vector<int32_t> setCounterValue; // see targetCounterValue |
| 127 |
|
|
|
| 128 |
|
|
// Inputs, one entry per channel |
| 129 |
|
|
std::vector<uint8_t> selAckEndCounter; |
| 130 |
|
|
std::vector<uint8_t> rampActive; |
| 131 |
|
|
std::vector<uint8_t> statusInputTarget; // only if hasInputTZ() |
| 132 |
|
|
std::vector<uint8_t> statusInputZero; // only if hasInputTZ() |
| 133 |
|
|
std::vector<uint8_t> error; |
| 134 |
|
|
std::vector<uint8_t> setCounterDone; |
| 135 |
|
|
std::vector<uint8_t> counterUnderflow; |
| 136 |
|
|
std::vector<uint8_t> counterOverflow; |
| 137 |
|
|
std::vector<int32_t> counterValue; // see targetCounterValue |
| 138 |
|
|
|
| 139 |
|
|
// PDO offsets (output side), one entry per channel |
| 140 |
|
|
std::vector<int> offFrequencySelect; |
| 141 |
|
|
std::vector<unsigned int> offFrequencySelectBit; |
| 142 |
|
|
std::vector<int> offDisableRamp; |
| 143 |
|
|
std::vector<unsigned int> offDisableRampBit; |
| 144 |
|
|
std::vector<int> offGoCounter; |
| 145 |
|
|
std::vector<unsigned int> offGoCounterBit; |
| 146 |
|
|
std::vector<int> offFrequencyValue; |
| 147 |
|
|
std::vector<int> offTargetCounterValue; |
| 148 |
|
|
std::vector<int> offSetCounter; |
| 149 |
|
|
std::vector<unsigned int> offSetCounterBit; |
| 150 |
|
|
std::vector<int> offSetCounterValue; |
| 151 |
|
|
|
| 152 |
|
|
// PDO offsets (input side), one entry per channel |
| 153 |
|
|
std::vector<int> offSelAckEndCounter; |
| 154 |
|
|
std::vector<unsigned int> offSelAckEndCounterBit; |
| 155 |
|
|
std::vector<int> offRampActive; |
| 156 |
|
|
std::vector<unsigned int> offRampActiveBit; |
| 157 |
|
|
std::vector<int> offStatusInputTarget; |
| 158 |
|
|
std::vector<unsigned int> offStatusInputTargetBit; |
| 159 |
|
|
std::vector<int> offStatusInputZero; |
| 160 |
|
|
std::vector<unsigned int> offStatusInputZeroBit; |
| 161 |
|
|
std::vector<int> offError; |
| 162 |
|
|
std::vector<unsigned int> offErrorBit; |
| 163 |
|
|
std::vector<int> offSetCounterDone; |
| 164 |
|
|
std::vector<unsigned int> offSetCounterDoneBit; |
| 165 |
|
|
std::vector<int> offCounterUnderflow; |
| 166 |
|
|
std::vector<unsigned int> offCounterUnderflowBit; |
| 167 |
|
|
std::vector<int> offCounterOverflow; |
| 168 |
|
|
std::vector<unsigned int> offCounterOverflowBit; |
| 169 |
|
|
std::vector<int> offCounterValue; |
| 170 |
|
|
}; |
| 171 |
|
|
|
| 172 |
|
|
} // namespace EcApp |
| 173 |
|
|
|
| 174 |
|
|
#endif // ECAPP_EX25XX_H |
| 175 |
|
|
|
| 176 |
|
|
/****************************************************************************/ |
| 177 |
|
|
|