GCC Code Coverage Report


Directory: ./
File: src/Master.cpp
Date: 2026-09-23 16:22:15
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 36 } // namespace EcApp
171
172 /****************************************************************************/
173