MotionLib  1.0.0
SamBuCa motion library
GrblPlatform_Base.cpp
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-14
21  * Author: Michal Mysior <mmysior> <michal.mysior@cern.ch>
22  *
23  */
24 
25 #include <chrono>
26 
27 #include <ccut/async.hpp>
28 #include <logger/Logger.hpp>
29 
30 #include "GrblAxis.hpp"
31 #include "GrblGpio.hpp"
32 #include "GrblPlatform.hpp"
33 #include "GrblPlatformDevice.hpp"
34 #include "device/Axis.hpp"
35 #include "platform/specialized/GrblPlatform/GrblTrigger.hpp"
36 #include "util/SettingParser.hpp"
37 #include "util/grbl/GrblDeviceBase.hpp"
38 #include "util/grbl/GrblGenerator.hpp"
39 #include "util/grbl/GrblParser.hpp"
40 
41 using namespace logger;
42 using namespace std::chrono;
43 using grbl::GrblParser;
44 
45 static const std::string s_resolutionSettingName{"travel resolution"};
46 static const std::string s_loggerCat{"smc:platform:grbl"};
47 
48 namespace smc {
49 namespace internal {
50 
51 PlatformBase::DeviceTypeList GrblPlatform::getSupportedDevices() const
52 {
53  return DeviceTypeList{DeviceType::AXIS, DeviceType::TRIGGER,
54  DeviceType::GPIO, DeviceType::PLATFORM};
55 }
56 
57 PlatformBase::DeviceList GrblPlatform::generateDevices(
58  const DeviceTypeList &deviceType)
59 {
60  DeviceList ret;
61  if (deviceType.count(DeviceType::AXIS))
62  {
63  std::shared_ptr<GrblPlatform> self(
64  std::static_pointer_cast<GrblPlatform>(shared_from_this()));
65 
66  std::future<std::list<GrblAxis::Shared>> f =
67  run<std::list<GrblAxis::Shared>>(
68  [self](ImmediateCmd &cmd, const Context &ctx) {
69  std::list<GrblAxis::Shared> ret;
70  self->generateAxes(ctx, ctx.binfo.axisCount, ret);
71  cmd.prom->get<std::list<GrblAxis::Shared>>().set_value(ret);
72  });
73  if (f.wait_for(milliseconds(3000)) == std::future_status::timeout)
74  {
75  error(s_loggerCat) << "failed to generate Axes";
76  return DeviceList();
77  }
78  std::list<GrblAxis::Shared> axisList{f.get()};
79  for (GrblAxis::Shared axis : axisList)
80  {
81  /* load parts from config */
82  axis->getConfig(s_resolutionSettingName).wait();
83  ret.push_back(axis);
84  }
85  }
86  bool hasTriggers = deviceType.count(DeviceType::TRIGGER);
87  bool hasGpios = deviceType.count(DeviceType::GPIO);
88  if (hasTriggers || hasGpios)
89  {
90  std::shared_ptr<GrblPlatform> self(
91  std::static_pointer_cast<GrblPlatform>(shared_from_this()));
92 
93  std::future<std::list<DeviceBase::Shared>> f =
94  run<std::list<DeviceBase::Shared>>(
95  [self, hasTriggers, hasGpios](ImmediateCmd &cmd, Context &ctx) {
96  std::list<GrblParser::PinInfo> pinfo;
97  ctx.device->send(grbl::gen::System::EnumeratePins,
98  [&pinfo](const std::string &line) {
99  return GrblParser::parsePinInfo(line,
100  pinfo);
101  });
102  std::list<DeviceBase::Shared> ret;
103  if (hasGpios)
104  {
105  std::list<GrblGpio::Shared> gpios;
106  self->generateGpios(ctx, pinfo, gpios);
107  ret.insert(ret.end(), gpios.begin(), gpios.end());
108  }
109  if (hasTriggers)
110  {
111  std::list<GrblTrigger::Shared> triggers;
112  self->generateTriggers(ctx, pinfo, triggers);
113  ret.insert(ret.end(), triggers.begin(), triggers.end());
114  }
115  cmd.prom->get<std::list<DeviceBase::Shared>>().set_value(
116  ret);
117  });
118 
119  if (f.wait_for(milliseconds(3000)) == std::future_status::timeout)
120  {
121  error(s_loggerCat) << "failed to generate Gpios and Triggers";
122  return DeviceList();
123  }
124  std::list<DeviceBase::Shared> devices{f.get()};
125  ret.insert(ret.end(), devices.begin(), devices.end());
126  }
127  if (deviceType.count(DeviceType::PLATFORM))
128  {
129  ret.emplace_back(new GrblPlatformDevice{
130  m_ctx->prefix + m_ctx->id + "/platform", shared_from_this()});
131  }
132  return ret;
133 }
134 
135 void GrblPlatform::generateTriggers(
136  Context &ctx,
137  const std::list<grbl::GrblParser::PinInfo> &pins,
138  std::list<GrblTrigger::Shared> &out)
139 {
140  const std::string platformUrl = ctx.prefix + ctx.id;
141 
142  for (const GrblParser::PinInfo &pinInfo : pins)
143  {
144  if (pinInfo.description == "Hardware Trigger")
145  {
146  const std::string url = platformUrl + "/trigger";
147  out.emplace_back(new GrblTrigger{url, shared_from_this()});
148  {
149  std::lock_guard<std::mutex> l(m_lock);
150  m_trigger.first = platformUrl;
151  m_trigger.second = pinInfo.pin;
152  }
153 
154  // Add Triggered motion setting
155  ctx.localSetting["Triggered motion"] = {
156  [](Context &ctx, const std::string &value) {
157  ctx.triggeredMotion = SettingParser::parse<bool>(value);
158  },
159  [](const Context &ctx) -> std::string {
160  return ctx.triggeredMotion ? "1" : "0";
161  },
162  };
163  }
164  }
165 }
166 
167 void GrblPlatform::generateGpios(const Context &ctx,
168  const std::list<grbl::GrblParser::PinInfo> &pins,
169  std::list<GrblGpio::Shared> &out)
170 {
171  const std::string platformUrl = ctx.prefix + ctx.id;
172 
173  for (const GrblParser::PinInfo &pinInfo : pins)
174  {
175  if (pinInfo.description == "Pause/Resume")
176  {
177  const std::string url = platformUrl + "/gpio/pauseResume";
178  out.emplace_back(new GrblGpio{url, shared_from_this()});
179  {
180  std::lock_guard<std::mutex> l(m_lock);
181  m_gpioMap[url] = pinInfo.pin;
182  }
183  }
184  }
185 }
186 
187 void GrblPlatform::generateAxes(const Context &ctx,
188  size_t axesCount,
189  std::list<GrblAxis::Shared> &out)
190 {
191  const std::string platformUrl = ctx.prefix + ctx.id + "/axis/";
192 
193  for (size_t i = 0; i < axesCount; ++i)
194  {
195  const grbl::Axis grblAxis = static_cast<grbl::Axis>(i);
196  const std::string url = platformUrl + grbl::to_string(grblAxis);
197  grbl::SettingId resolutionSettingId = -1;
198  try
199  {
200  resolutionSettingId =
201  ctx.findSetting(s_resolutionSettingName, grblAxis).id;
202  }
203  catch (const Exception &ex)
204  {
205  logger::warning(s_loggerCat)
206  << "failed to retrieve " << s_resolutionSettingName << ": "
207  << ex.what();
208  }
209 
210  out.emplace_back(new GrblAxis{url, shared_from_this()});
211  {
212  std::lock_guard<std::mutex> l(m_lock);
213  m_axisMap[url] = AxisData{
214  grblAxis, units::value_t{units::mm, std::nan("initial value")},
215  resolutionSettingId,
216  units::value_t{units::STEPS_PER_MILLIMETER, -1.0}};
217  }
218  }
219 }
220 
221 std::future<void> GrblPlatform::send(const std::string &grblCmd,
222  std::function<bool(const std::string &)> msg,
223  const std::chrono::milliseconds &timeout)
224 {
225  return run<void>(
226  [this, grblCmd, msg, timeout](ImmediateCmd &cmd, Context &ctx) {
227  grbl::ErrorCode rc = ctx.device->send(grblCmd, msg, timeout);
228  ctx.checkReply(rc);
229  cmd.prom->get<void>().set_value();
230  });
231 }
232 
233 } // namespace internal
234 } // namespace smc
const std::string & to_string(Axis::State state)
convert State to string
Definition: Axis.cpp:78
main motion-lib namespace
Definition: Client.cpp:30
void checkReply(grbl::ErrorCode code)
check command result code