MotionLib  1.0.0
SamBuCa motion library
AsyncAxisController.cpp
1 /*
2 ** Copyright (C) 2023 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: 2023-10-26T11:44:27
21 ** Author: Sylvain Fargier <sylvain.fargier@cern.ch>
22 */
23 
24 #include "AsyncAxisController.hpp"
25 
26 #include OATPP_CODEGEN_BEGIN(ApiController)
27 
28 using namespace oatpp::web::protocol::http;
29 using namespace oatpp::async;
30 using namespace smc;
31 
32 AsyncAxisController::AsyncAxisController(
33  std::shared_ptr<ObjectMapper> &objectMapper) :
34  SmcController(objectMapper)
35 {
36  addTag(*this, "axis");
37 }
38 
39 void AsyncAxisController::addParams(
40  const std::shared_ptr<oatpp::web::server::api::Endpoint::Info> &info)
41 {
42  info->pathParams.add<String>("id").addExample("Grbl axis X",
43  String("grbl://1/axis/X"));
44 
45  {
46  auto &param = info->queryParams.add<String>("unit")
47  .addExample("mm", String("mm"))
48  .addExample("steps", String("steps"));
49 
50  param.required = false;
51  param.description = "request unit";
52  }
53 }
54 
55 Action AsyncAxisController::getPosition::act()
56 {
57  const std::string unit = request->getQueryParameter("unit").getValue("mm");
58  auto deviceStore(controller->deviceStore.lock());
59  if (deviceStore)
60  {
61  smc::Axis::Shared axis = deviceStore->getDevice<smc::Axis>(
62  ccut::urldecode(request->getPathVariable("id").getValue("")));
63 
64  auto future = axis->getPosition(
65  smc::from_string<smc::units::Unit>(unit));
66  return smc::debug::wait(future.share())
67  .callbackTo(&getPosition::onResult);
68  }
69  return _return(
70  controller->createResponse(Status::CODE_500, "no deviceStore"));
71 }
72 
73 Action AsyncAxisController::getPosition::onResult(
74  const smc::units::value_t &value)
75 {
76  return _return(
77  controller->createDtoResponse(Status::CODE_200, Float64(value.value)));
78 }
79 
80 Action AsyncAxisController::putPosition::act()
81 {
82  return request
83  ->readBodyToDtoAsync<Float64>(controller->getDefaultObjectMapper())
84  .callbackTo(&putPosition::onMoveTo);
85 }
86 
87 Action AsyncAxisController::putPosition::onMoveTo(const Float64 &position)
88 {
89  const std::string unit = request->getQueryParameter("unit").getValue("mm");
90  auto deviceStore(controller->deviceStore.lock());
91  if (deviceStore)
92  {
93  smc::Axis::Shared axis = deviceStore->getDevice<smc::Axis>(
94  ccut::urldecode(request->getPathVariable("id").getValue("")));
95 
96  auto future = axis->moveTo(
97  smc::units::value_t{smc::from_string<smc::units::Unit>(unit),
98  position.getValue(std::nan("invalid"))});
99 
100  if (future.wait_for(std::chrono::milliseconds(0)) !=
101  std::future_status::timeout)
102  {
103  future.get(); // throw if needed
104  }
105  return _return(controller->createResponse(Status::CODE_200, "done"));
106  }
107 
108  return _return(
109  controller->createResponse(Status::CODE_500, "no deviceStore"));
110 }
111 
112 Action AsyncAxisController::postPosition::act()
113 {
114  return request
115  ->readBodyToDtoAsync<Float64>(controller->getDefaultObjectMapper())
116  .callbackTo(&postPosition::onMoveBy);
117 }
118 Action AsyncAxisController::postPosition::onMoveBy(const Float64 &position)
119 {
120  const std::string unit = request->getQueryParameter("unit").getValue("mm");
121  auto deviceStore(controller->deviceStore.lock());
122  if (deviceStore)
123  {
124  smc::Axis::Shared axis = deviceStore->getDevice<smc::Axis>(
125  ccut::urldecode(request->getPathVariable("id").getValue("")));
126 
127  auto future = axis->moveBy(
128  smc::units::value_t{smc::from_string<smc::units::Unit>(unit),
129  position.getValue(std::nan("invalid"))});
130 
131  if (future.wait_for(std::chrono::milliseconds(0)) !=
132  std::future_status::timeout)
133  {
134  future.get(); // throw if needed
135  }
136  return _return(controller->createResponse(Status::CODE_200, "done"));
137  }
138  return _return(
139  controller->createResponse(Status::CODE_500, "no deviceStore"));
140 }
141 
142 Action AsyncAxisController::putCurrentPosition::act()
143 {
144  return request
145  ->readBodyToDtoAsync<Float64>(controller->getDefaultObjectMapper())
146  .callbackTo(&putCurrentPosition::onSetCurrentPosition);
147 }
148 
149 Action AsyncAxisController::putCurrentPosition::onSetCurrentPosition(
150  const Float64 &position)
151 {
152  const std::string unit = request->getQueryParameter("unit").getValue("mm");
153  auto deviceStore(controller->deviceStore.lock());
154  if (deviceStore)
155  {
156  smc::Axis::Shared axis = deviceStore->getDevice<smc::Axis>(
157  ccut::urldecode(request->getPathVariable("id").getValue("")));
158 
159  auto future = axis->setActualPosition(
160  smc::units::value_t{smc::from_string<smc::units::Unit>(unit),
161  position.getValue(std::nan("invalid"))});
162  return smc::debug::wait(future.share())
163  .next(_return(controller->createResponse(Status::CODE_200, "done")));
164  }
165  return _return(
166  controller->createResponse(Status::CODE_500, "no deviceStore"));
167 }
168 
169 Action AsyncAxisController::putStop::act()
170 {
171  auto deviceStore(controller->deviceStore.lock());
172  if (deviceStore)
173  {
174  smc::Axis::Shared axis = deviceStore->getDevice<smc::Axis>(
175  ccut::urldecode(request->getPathVariable("id").getValue("")));
176 
177  auto future = axis->stop();
178  return smc::debug::wait(future.share())
179  .next(_return(controller->createResponse(Status::CODE_200, "done")));
180  }
181  return _return(
182  controller->createResponse(Status::CODE_500, "no deviceStore"));
183 }
184 
185 Action AsyncAxisController::putPause::act()
186 {
187  auto deviceStore(controller->deviceStore.lock());
188  if (deviceStore)
189  {
190  smc::Axis::Shared axis = deviceStore->getDevice<smc::Axis>(
191  ccut::urldecode(request->getPathVariable("id").getValue("")));
192 
193  auto future = axis->pause();
194  return smc::debug::wait(future.share())
195  .next(_return(controller->createResponse(Status::CODE_200, "done")));
196  }
197  return _return(
198  controller->createResponse(Status::CODE_500, "no deviceStore"));
199 }
200 
201 Action AsyncAxisController::putResume::act()
202 {
203  auto deviceStore(controller->deviceStore.lock());
204  if (deviceStore)
205  {
206  smc::Axis::Shared axis = deviceStore->getDevice<smc::Axis>(
207  ccut::urldecode(request->getPathVariable("id").getValue("")));
208 
209  auto future = axis->resume();
210  return smc::debug::wait(future.share())
211  .next(_return(controller->createResponse(Status::CODE_200, "done")));
212  }
213  return _return(
214  controller->createResponse(Status::CODE_500, "no deviceStore"));
215 }
216 
217 Action AsyncAxisController::postTakeReference::act()
218 {
219  return request
220  ->readBodyToDtoAsync<Float64>(controller->getDefaultObjectMapper())
221  .callbackTo(&postTakeReference::onTakeReference);
222 }
223 
224 Action AsyncAxisController::postTakeReference::onTakeReference(
225  const Float64 &timeout)
226 {
227  auto deviceStore(controller->deviceStore.lock());
228  if (deviceStore)
229  {
230  smc::Axis::Shared axis = deviceStore->getDevice<smc::Axis>(
231  ccut::urldecode(request->getPathVariable("id").getValue("")));
232 
233  auto future = axis->takeReference(std::chrono::milliseconds(timeout));
234 
235  if (future.wait_for(std::chrono::milliseconds(0)) !=
236  std::future_status::timeout)
237  {
238  future.get(); // throw if needed
239  }
240 
241  return _return(
242  controller->createResponse(Status::CODE_200, "homing started"));
243  }
244  return _return(
245  controller->createResponse(Status::CODE_500, "no deviceStore"));
246 }
247 
248 Action AsyncAxisController::getState::act()
249 {
250  auto deviceStore(controller->deviceStore.lock());
251  if (deviceStore)
252  {
253  smc::Axis::Shared axis = deviceStore->getDevice<smc::Axis>(
254  ccut::urldecode(request->getPathVariable("id").getValue("")));
255 
256  auto future = axis->getState();
257 
258  return smc::debug::wait(future.share()).callbackTo(&getState::onResult);
259  }
260  return _return(
261  controller->createResponse(Status::CODE_500, "no deviceStore"));
262 }
263 
264 Action AsyncAxisController::getState::onResult(const smc::Axis::State &state)
265 {
266  return _return(controller->createDtoResponse(
267  Status::CODE_200, String(smc::to_string(state))));
268 }
virtual std::future< void > resume() const
Resume paused motion.
virtual std::future< void > takeReference(const std::chrono::milliseconds &timeout=std::chrono::seconds{ 120}) const
Start a homing sequence.
virtual std::future< units::value_t > getPosition(units::unit_t unit) const =0
Get current position of this axis.
virtual std::future< void > moveBy(const units::Value &distance) const =0
Move this axis by given distance.
virtual std::future< void > stop() const =0
Stop any ongoing motion, flush the motion-queue.
State
Axis State.
Definition: Axis.hpp:54
virtual std::future< void > setActualPosition(const units::Value &position) const
Set current axis position.
virtual std::future< State > getState() const =0
Get the current axis state.
virtual std::future< void > pause() const
Pause ongoing motion, prevent queued motions from running.
virtual std::future< void > moveTo(const units::Value &position) const =0
Move this axis to given position.
const std::string & to_string(Axis::State state)
convert State to string
Definition: Axis.cpp:78
main motion-lib namespace
Definition: Client.cpp:30