MotionLib  1.0.0
SamBuCa motion library
ApiController.hpp
1 /*
2 ** Copyright (C) 2022 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: 2022-07-11T13:35:13
21 ** Author: Sylvain Fargier <sylvain.fargier@cern.ch>
22 */
23 
24 #ifndef APICONTROLLER_HPP__
25 #define APICONTROLLER_HPP__
26 
27 #include <algorithm>
28 #include <memory>
29 
30 #include <ccut/async.hpp>
31 #include <ccut/utils.hpp>
32 #include <logger/Logger.hpp>
33 #include <oatpp/core/macro/codegen.hpp>
34 #include <oatpp/core/macro/component.hpp>
35 #include <oatpp/web/server/api/ApiController.hpp>
36 
37 #include "Exception.hpp"
38 #include "device/Axis.hpp"
39 #include "device/DeviceBase.hpp"
40 #include "device/DeviceStore.hpp"
41 #include "platform/PlatformFactory.hpp"
42 #include "util/serialize.hpp"
43 
44 #include OATPP_CODEGEN_BEGIN(ApiController)
45 
46 class ApiController : public oatpp::web::server::api::ApiController
47 {
48 public:
49  explicit ApiController(OATPP_COMPONENT(std::shared_ptr<ObjectMapper>,
50  objectMapper)) :
51  oatpp::web::server::api::ApiController(objectMapper)
52  {}
53 
54  ENDPOINT_INFO(root)
55  {
56  info->summary = "api-docs redirection";
57  info->addResponse<List<String>>(Status::CODE_302, "");
58  }
59  ENDPOINT("GET", "/", root)
60  {
61  auto ret = createResponse(Status::CODE_302);
62  ret->putHeader("Location", "/api-docs/ui");
63  return ret;
64  }
65 
66  ENDPOINT_INFO(devicesTypes)
67  {
68  info->summary = "List device types";
69  info->addResponse<List<String>>(Status::CODE_200, "application/json")
70  .addExample("example",
71  List<String>{"axis", "position", "gpio", "trigger"});
72  }
73  ENDPOINT("GET", "/devices/types", devicesTypes)
74  {
75  auto deviceStore(m_deviceStore.lock());
76  List<String> ret{List<String>::createShared()};
77  if (deviceStore)
78  {
79  std::set<smc::DeviceType> deviceTypes =
80  smc::getEnumValues<smc::DeviceType>();
81  std::transform(deviceTypes.cbegin(), deviceTypes.cend(),
82  std::inserter(*ret, ret->begin()),
83  [](smc::DeviceType t) { return smc::to_string(t); });
84  }
85  return createDtoResponse(Status::CODE_200, ret);
86  }
87 
88  ENDPOINT_INFO(devices)
89  {
90  info->summary = "List available devices";
91  info->addResponse<List<String>>(Status::CODE_200, "application/json")
92  .addExample("example",
93  List<String>{"grbl://1/platform", "grbl://1/axis/X",
94  "grbl://1/axis/Y", "grbl://1/axis/Z",
95  "grbl://1/axis/A", "grbl://1/axis/B",
96  "grbl://1/axis/C"});
97  auto &param = info->queryParams.add<String>("type")
98  .addExample("fetch all", String())
99  .addExample("trigger", String("trigger"))
100  .addExample("axis", String("axis"))
101  .addExample("platform", String("platform"));
102  param.description = "device type filter, accepted values are listed in "
103  "`GET /devices/types`";
104  param.required = false;
105  }
106  ENDPOINT("GET", "/devices", devices, QUERIES(QueryParams, queryParams))
107  {
108  const std::string deviceType = queryParams.get("type").getValue("");
109  oatpp::UnorderedSet<String> ret{
110  oatpp::UnorderedSet<String>::createShared()};
111 
112  auto deviceStore(m_deviceStore.lock());
113  if (deviceStore)
114  {
115  std::set<smc::DeviceId> devices = deviceType.empty() ?
116  deviceStore->getDeviceList() :
117  deviceStore->getDeviceList(
118  smc::from_string<smc::DeviceType>(deviceType));
119  ret->insert(devices.begin(), devices.end());
120  }
121  return createDtoResponse(Status::CODE_200, ret);
122  }
123 
124  ENDPOINT("PUT",
125  "/axis/{id}/position",
126  putPosition,
127  PATH(String, id),
128  BODY_DTO(Float64, position))
129  {
130  auto deviceStore(m_deviceStore.lock());
131  if (deviceStore)
132  {
133  smc::Axis::Shared axis = deviceStore->getDevice<smc::Axis>(
134  ccut::urldecode(id.getValue("")));
135  if (!axis)
136  return createResponse(Status::CODE_404, "No such axis");
137 
138  axis->moveTo(smc::units::value_t{smc::units::mm, position}).wait();
139  return createResponse(Status::CODE_200, "done");
140  }
141  return createResponse(Status::CODE_500, "no deviceStore");
142  }
143 
144  ENDPOINT("GET", "/axis/{id}/position", getPosition, PATH(String, id))
145  {
146  auto deviceStore(m_deviceStore.lock());
147  if (deviceStore)
148  {
149  smc::Axis::Shared axis = deviceStore->getDevice<smc::Axis>(
150  ccut::urldecode(id.getValue("")));
151  if (!axis)
152  return createResponse(Status::CODE_404, "No such axis");
153  return createDtoResponse(
154  Status::CODE_200,
155  Float64(ccut::wait(axis->getPosition(smc::units::mm)).value));
156  }
157  return createResponse(Status::CODE_500, "no deviceStore");
158  }
159 
160  std::weak_ptr<smc::internal::PlatformFactory> m_platformFactory;
161  std::weak_ptr<smc::internal::DeviceStore> m_deviceStore;
162 };
163 
164 #include OATPP_CODEGEN_END(ApiController)
165 
166 #endif
DeviceType
List of possible device types supported.
Definition: DeviceBase.hpp:52