MotionLib  1.0.0
SamBuCa motion library
MockAxis.cpp
1 /*
2 ** Copyright (C) 2025 CERN
3 **
4 ** This software is provided 'as-is', without any express or implied
5 ** warranty. In no event will the authors be held liable for any damages
6 ** arising from the use of this software.
7 **
8 ** Permission is granted to anyone to use this software for any purpose,
9 ** including commercial applications, and to alter it and redistribute it
10 ** freely, subject to the following restrictions:
11 **
12 ** 1. The origin of this software must not be misrepresented; you must not
13 ** claim that you wrote the original software. If you use this software
14 ** in a product, an acknowledgment in the product documentation would be
15 ** appreciated but is not required.
16 ** 2. Altered source versions must be plainly marked as such, and must not be
17 ** misrepresented as being the original software.
18 ** 3. This notice may not be removed or altered from any source distribution.
19 **
20 ** Created on: 2025-04-16T10:36:20
21 ** Author: Sylvain Fargier <sylvain.fargier@cern.ch>
22 */
23 
24 #include "MockAxis.hpp"
25 
26 #include <ccut/async.hpp>
27 #include <logger/Logger.hpp>
28 
29 #include "MockPlatform.hpp"
30 
31 using namespace logger;
32 using namespace smc;
33 using namespace smc::internal;
34 
35 MockAxis::MockAxis(const std::string &uid,
36  const std::shared_ptr<MockPlatform> &mock) :
37  Axis{uid},
38  m_mock(mock)
39 {}
40 
41 std::future<void> MockAxis::moveTo(const units::Value &position) const
42 {
43  std::shared_ptr<MockPlatform> mock(m_mock.lock());
44  if (!mock)
45  return ccut::make_future_error(
46  Exception(ErrorCode::Canceled, "platform stopped (deleted)"));
47 
48  info(MockPlatform::s_loggerCat)
49  << "MoveTo requested on MockPlatform id: " << mock->getPlatformId()
50  << " for axis " << uid() << " to position: " << position.value;
51  std::promise<void> movePromise;
52  auto moveFuture = movePromise.get_future();
53 
54  try
55  {
56  units::Value convertedPosition{position};
57  if (!convert(convertedPosition, units::unit_t::MILLIMETERS))
58  {
59  throw Exception{ErrorCode::IncompatibleUnits};
60  }
61  if (convertedPosition.unit != units::MILLIMETERS)
62  {
63  throw Exception{ErrorCode::InternalError};
64  }
65  mock->setMotorPosition(uid(), convertedPosition.value);
66 
67  movePromise.set_value();
68  mock->notify(uid());
69  }
70  catch (...)
71  {
72  movePromise.set_exception(std::current_exception());
73  }
74  return moveFuture;
75 }
76 
77 std::future<void> MockAxis::moveBy(const units::Value &distance) const
78 {
79  std::shared_ptr<MockPlatform> mock(m_mock.lock());
80  if (!mock)
81  return ccut::make_future_error(
82  Exception(ErrorCode::Canceled, "platform stopped (deleted)"));
83 
84  info(MockPlatform::s_loggerCat)
85  << "MoveBy requested on MockPlatform id: " << mock->getPlatformId()
86  << " for axis " << uid() << " by distance: " << distance.value;
87  std::promise<void> movePromise;
88  auto moveFuture = movePromise.get_future();
89 
90  try
91  {
92  units::Value convertedDistance{distance};
93  if (!convert(convertedDistance, units::unit_t::MILLIMETERS))
94  {
95  throw Exception{ErrorCode::IncompatibleUnits};
96  }
97  if (convertedDistance.unit != units::MILLIMETERS)
98  {
99  throw Exception{ErrorCode::InternalError};
100  }
101  units::Value newPosition{units::unit_t::MILLIMETERS,
102  mock->getMotorPosition(uid())};
103  newPosition += convertedDistance.value;
104 
105  mock->setMotorPosition(uid(), newPosition.value);
106  movePromise.set_value();
107  mock->notify(uid());
108  }
109  catch (...)
110  {
111  movePromise.set_exception(std::current_exception());
112  }
113  return moveFuture;
114 }
115 
116 std::future<units::value_t> MockAxis::getPosition(units::unit_t unit) const
117 {
118  std::shared_ptr<MockPlatform> mock(m_mock.lock());
119  if (!mock)
120  return ccut::make_future_error<units::value_t>(
121  Exception(ErrorCode::Canceled, "platform stopped (deleted)"));
122 
123  info(MockPlatform::s_loggerCat)
124  << "Querying axis " << uid()
125  << " on MockPlatform id: " << mock->getPlatformId() << " for position";
126  std::promise<units::value_t> positionPromise;
127  auto positionFuture = positionPromise.get_future();
128 
129  try
130  {
131  positionPromise.set_value(lastPosition(unit));
132  }
133  catch (...)
134  {
135  positionPromise.set_exception(std::current_exception());
136  }
137  return positionFuture;
138 }
139 
140 std::future<void> MockAxis::stop() const
141 {
142  std::shared_ptr<MockPlatform> mock(m_mock.lock());
143  if (!mock)
144  return ccut::make_future_error(
145  Exception(ErrorCode::Canceled, "platform stopped (deleted)"));
146 
147  std::promise<void> promise;
148  auto future = promise.get_future();
149 
150  promise.set_value();
151  return future;
152 }
153 
154 std::future<void> MockAxis::pause() const
155 {
156  std::shared_ptr<MockPlatform> mock(m_mock.lock());
157  if (!mock)
158  return ccut::make_future_error(
159  Exception(ErrorCode::Canceled, "platform stopped (deleted)"));
160 
161  std::promise<void> promise;
162  auto future = promise.get_future();
163 
164  promise.set_value();
165  return future;
166 }
167 
168 std::future<void> MockAxis::resume() const
169 {
170  std::shared_ptr<MockPlatform> mock(m_mock.lock());
171  if (!mock)
172  return ccut::make_future_error(
173  Exception(ErrorCode::Canceled, "platform stopped (deleted)"));
174 
175  std::promise<void> promise;
176  auto future = promise.get_future();
177 
178  promise.set_value();
179  return future;
180 }
181 
182 std::future<void> MockAxis::setActualPosition(const units::Value &position) const
183 {
184  std::shared_ptr<MockPlatform> mock(m_mock.lock());
185  if (!mock)
186  return ccut::make_future_error(
187  Exception(ErrorCode::Canceled, "platform stopped (deleted)"));
188 
189  info(MockPlatform::s_loggerCat)
190  << "setActualPosition requested on MockPlatform id: "
191  << mock->getPlatformId() << " for axis " << uid()
192  << " to position: " << position;
193  std::promise<void> promise;
194  auto future = promise.get_future();
195 
196  try
197  {
198  units::Value convertedDistance{position};
199  if (!convert(convertedDistance, units::unit_t::MILLIMETERS))
200  {
201  throw Exception{ErrorCode::IncompatibleUnits};
202  }
203  if (convertedDistance.unit != units::MILLIMETERS)
204  {
205  throw Exception{ErrorCode::InternalError};
206  }
207 
208  mock->setMotorPosition(uid(), convertedDistance.value);
209  promise.set_value();
210  mock->notify(uid());
211  }
212  catch (...)
213  {
214  promise.set_exception(std::current_exception());
215  }
216  return future;
217 }
218 
219 units::value_t MockAxis::lastPosition(units::unit_t unit) const
220 {
221  std::shared_ptr<MockPlatform> mock(m_mock.lock());
222  if (!mock)
223  throw Exception(ErrorCode::Canceled, "platform stopped (deleted)");
224 
225  units::Value motorPosition{units::unit_t::MILLIMETERS,
226  mock->getMotorPosition(uid())};
227  if (!convert(motorPosition, unit))
228  {
229  throw Exception{ErrorCode::IncompatibleUnits};
230  }
231  return motorPosition;
232 }
233 
234 std::future<void> MockAxis::takeReference(
235  const std::chrono::milliseconds &timeout) const
236 {
237  std::shared_ptr<MockPlatform> mock(m_mock.lock());
238  if (!mock)
239  return ccut::make_future_error(
240  Exception(ErrorCode::Canceled, "platform stopped (deleted)"));
241 
242  info(MockPlatform::s_loggerCat)
243  << "Homing sequence (takeReference) requested on MockPlatform id: "
244  << mock->getPlatformId() << "with timeout: " << timeout.count() << "ms";
245 
246  mock->setMotorPosition(uid(), 0.0);
247 
248  std::promise<void> promise;
249  auto future = promise.get_future();
250 
251  promise.set_value();
252  return future;
253 }
254 
255 std::future<Axis::State> MockAxis::getState() const
256 {
257  std::shared_ptr<MockPlatform> mock(m_mock.lock());
258  if (!mock)
259  return ccut::make_future_error<Axis::State>(
260  Exception(ErrorCode::Canceled, "platform stopped (deleted)"));
261 
262  info(MockPlatform::s_loggerCat)
263  << "Querying axis " << uid()
264  << " on MockPlatform id: " << mock->getPlatformId() << " for run state";
265  std::promise<Axis::State> promise;
266  auto future = promise.get_future();
267  // TODO: Implement a more robust run state mock
268  promise.set_value(Axis::State::IDLE);
269  return future;
270 }
virtual bool convert(units::Value &value, units::unit_t unit) const
Convert value in a manner specific to this device.
Definition: DeviceBase.cpp:86
DeviceId uid() const
Get the address of device.
Definition: DeviceBase.cpp:76
Exception thrown by MotionController in case of issues with command.
Definition: Exception.hpp:61
std::future< units::value_t > getPosition(units::unit_t unit) const override
Get current position of this axis.
Definition: MockAxis.cpp:116
units::value_t lastPosition(units::unit_t unit) const override
Get last known position of the axis.
Definition: MockAxis.cpp:219
std::future< void > resume() const override
Resume paused motion.
Definition: MockAxis.cpp:168
std::future< void > moveBy(const units::Value &distance) const override
Move this axis by given distance.
Definition: MockAxis.cpp:77
std::future< State > getState() const override
Get the current axis state.
Definition: MockAxis.cpp:255
std::future< void > pause() const override
Pause ongoing motion, prevent queued motions from running.
Definition: MockAxis.cpp:154
std::future< void > setActualPosition(const units::Value &position) const override
Set current axis position.
Definition: MockAxis.cpp:182
std::future< void > stop() const override
Stop any ongoing motion, flush the motion-queue.
Definition: MockAxis.cpp:140
std::future< void > takeReference(const std::chrono::milliseconds &timeout) const override
Start a homing sequence.
Definition: MockAxis.cpp:234
main motion-lib namespace
Definition: Client.cpp:30