GCC Code Coverage Report


Directory: ./
File: src/Master.cpp
Date: 2026-09-03 16:05:57
Exec Total Coverage
Lines: 1 58 1.7%
Branches: 0 82 0.0%

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 ****************************************************************************/
22
23 #include "ecapp/Master.h"
24
25 #include <arpa/inet.h> // ntohs()
26 #include <cstdio>
27 #include <cstring>
28 #include <iostream>
29 #include <sstream>
30 #include <stdexcept>
31 #include <string>
32
33 using std::cerr;
34 using std::endl;
35 using std::invalid_argument;
36 using std::runtime_error;
37 using std::string;
38 using std::stringstream;
39
40 /****************************************************************************/
41
42 namespace EcApp {
43
44 struct Master::Impl
45 {
46 ec_master_t *master;
47 unsigned int sync_cycles;
48 unsigned int sync_ref_counter;
49 unsigned int slaves_responding;
50 uint8_t al_states;
51 bool link_up;
52 uint32_t dc_deviation;
53 };
54
55 /****************************************************************************/
56
57 Master::Master(pdserv *pdserv, pdtask *task) :
58 impl(new Impl {
59 NULL,
60 1,
61 0,
62 0U,
63 0x00,
64 false,
65 0U,
66 })
67 {
68 string prefix("/EtherCAT");
69
70 if (!(impl->master = ecrt_request_master(0))) {
71 stringstream err;
72 err << "Requesting master 0 failed!";
73 cerr << err.str() << endl;
74 throw invalid_argument("config failed");
75 }
76
77 if (pdserv && task) {
78 pdserv_parameter(
79 pdserv, (prefix + "/SyncCycles").c_str(), 0666, pd_uint32_T,
80 &impl->sync_cycles, 1, NULL, NULL, NULL);
81 pdserv_signal(
82 task, 1, (prefix + "/SyncRefCounter").c_str(), pd_uint32_T,
83 &impl->sync_ref_counter, 1, NULL);
84 pdserv_signal(
85 task, 1, (prefix + "/SlavesResponding").c_str(), pd_uint32_T,
86 &impl->slaves_responding, 1, NULL);
87 pdserv_signal(
88 task, 1, (prefix + "/ApplicationLayerStates").c_str(),
89 pd_uint32_T, &impl->al_states, 1, NULL);
90 pdserv_signal(
91 task, 1, (prefix + "/LinkUp").c_str(), pd_boolean_T,
92 &impl->link_up, 1, NULL);
93 pdserv_signal(
94 task, 1, (prefix + "/DcDeviation").c_str(), pd_uint32_T,
95 &impl->dc_deviation, 1, NULL);
96 }
97 }
98
99 /****************************************************************************/
100
101 Master::~Master()
102 {
103 ecrt_release_master(impl->master);
104 }
105
106 /****************************************************************************/
107
108 ec_master_t *Master::getMaster()
109 {
110 return impl->master;
111 }
112
113 /****************************************************************************/
114
115 void Master::activate()
116 {
117 {
118 stringstream msg;
119 msg << "Activating master...";
120 cerr << msg.str() << endl;
121 }
122
123 if (ecrt_master_activate(impl->master)) {
124 throw runtime_error("Failed to activate master!");
125 }
126 }
127
128 /****************************************************************************/
129
130 void Master::receive()
131 {
132 // receive datagrams
133 ecrt_master_receive(impl->master);
134
135 ec_master_state_t state;
136 ecrt_master_state(impl->master, &state);
137 impl->slaves_responding = state.slaves_responding;
138 impl->al_states = state.al_states;
139 impl->link_up = state.link_up;
140
141 impl->dc_deviation = ecrt_master_sync_monitor_process(impl->master);
142 }
143
144 /****************************************************************************/
145
146 void Master::send()
147 {
148 struct timespec t;
149 clock_gettime(CLOCK_MONOTONIC, &t);
150 ecrt_master_application_time(
151 impl->master, t.tv_sec * 1000000000ULL + t.tv_nsec);
152
153 if (!impl->sync_ref_counter) {
154 ecrt_master_sync_reference_clock(impl->master);
155 }
156 ecrt_master_sync_slave_clocks(impl->master);
157 ecrt_master_sync_monitor_queue(impl->master);
158
159 ecrt_master_send(impl->master);
160
161 if (impl->sync_ref_counter) {
162 impl->sync_ref_counter--;
163 }
164 else {
165 impl->sync_ref_counter =
166 impl->sync_cycles > 0 ? impl->sync_cycles - 1 : 0;
167 }
168 }
169
170 24 } // namespace EcApp
171
172 /****************************************************************************/
173