DynExp
Highly flexible laboratory automation for dynamically changing experiments.
HardwareAdapterSmarAct.cpp
Go to the documentation of this file.
1 // This file is part of DynExp.
2 
3 #include "stdafx.h"
5 
6 namespace DynExpHardware
7 {
9  {
10  // Since C++17, writing to std::string's internal buffer is allowed.
11  std::string DeviceList;
12  DeviceList.resize(256);
13  size_t RequiredSize = DeviceList.size();
14  auto Result = SmarActSyms::SA_CTL_FindDevices("", DeviceList.data(), &RequiredSize);
15 
16  // In case buffer of DeviceList is to small, RequiredSize now contains the required size. So, try again.
17  if (DeviceList.size() < RequiredSize)
18  {
19  DeviceList.resize(RequiredSize + 1);
20  RequiredSize = DeviceList.size();
21  Result = SmarActSyms::SA_CTL_FindDevices("", DeviceList.data(), &RequiredSize);
22  }
23 
24  // Adjust length of string to length of data written by SA_CTL_FindDevices()
25  DeviceList.resize(RequiredSize);
26 
27  if (Result != SA_CTL_ERROR_NONE)
28  throw SmarActException("Error enumerating SmarAct controllers.", Result);
29 
30  // All descriptors are separated by '\n'. Replace that by ' ' and use std::istringstream to split by ' '.
31  std::replace(DeviceList.begin(), DeviceList.end(), '\n', ' ');
32  std::istringstream ss(DeviceList);
33  std::vector<std::string> DeviceDescriptors{ std::istream_iterator<std::string>(ss), std::istream_iterator<std::string>() };
34 
35  return DeviceDescriptors;
36  }
37 
39  {
40  auto SmarActDevices = SmarActHardwareAdapter::Enumerate();
41  if (!DeviceDescriptor.Get().empty() &&
42  std::find(SmarActDevices.cbegin(), SmarActDevices.cend(), DeviceDescriptor) == std::cend(SmarActDevices))
43  SmarActDevices.push_back(DeviceDescriptor);
44  if (SmarActDevices.empty())
45  throw Util::EmptyException("There is not any available SmarAct controller.");
46  DeviceDescriptor.SetTextList(std::move(SmarActDevices));
47 
49  }
50 
51  SmarActHardwareAdapter::SmarActHardwareAdapter(const std::thread::id OwnerThreadID, DynExp::ParamsBasePtrType&& Params)
52  : HardwareAdapterBase(OwnerThreadID, std::move(Params))
53  {
54  Init();
55  }
56 
58  {
59  // Not locking, since the object is being destroyed. This should be inherently thread-safe.
60  CloseUnsafe();
61  }
62 
64  {
65  auto DerivedParams = dynamic_Params_cast<SmarActHardwareAdapter>(GetParams());
66 
67  DeviceDescriptor = DerivedParams->DeviceDescriptor.Get();
68 
69  SmarActHandleValid = false;
70  SmarActHandle = SmarActSyms::SA_CTL_DeviceHandle_t();
71  }
72 
74  {
75  // auto lock = AcquireLock(); not necessary here, since DynExp ensures that Object::Reset() can only
76  // be called if respective object is not in use.
77 
78  CloseUnsafe();
79  Init();
80 
82  }
83 
85  {
87 
88  OpenUnsafe();
89  }
90 
92  {
94 
95  auto Exception = GetExceptionUnsafe();
96  Util::ForwardException(Exception);
97 
98  return IsOpened();
99  }
100 
102  {
103  return IsOpened();
104  }
105 
106  void SmarActHardwareAdapter::CheckError(const SmarActSyms::SA_CTL_Result_t Result, const std::source_location Location) const
107  {
108  if (Result == SA_CTL_ERROR_NONE)
109  return;
110 
111  std::string ErrorString(SmarActSyms::SA_CTL_GetResultInfo(Result));
112 
113  // AcquireLock() has already been called by an (in)direct caller of this function.
114  ThrowExceptionUnsafe(std::make_exception_ptr(SmarActException(ErrorString, Result, Location)));
115  }
116 
118  {
119  if (IsOpened())
120  return;
121 
122  auto Result = SmarActSyms::SA_CTL_Open(&SmarActHandle, DeviceDescriptor.c_str(), "");
123  CheckError(Result);
124 
125  SmarActHandleValid = true;
126  }
127 
129  {
130  if (IsOpened())
131  {
132  // Handle now considered invalid, even if SA_CTL_Close() fails.
133  SmarActHandleValid = false;
134 
135  auto Result = SmarActSyms::SA_CTL_Close(SmarActHandle);
136  CheckError(Result);
137  }
138  }
139 
141  {
143 
144  PositionType Position;
145  auto Result = SmarActSyms::SA_CTL_GetProperty_i64(SmarActHandle, Channel, SA_CTL_PKEY_POSITION, &Position, nullptr);
146  CheckError(Result);
147 
148  return Position;
149  }
150 
152  {
154 
155  PositionType TargetPosition;
156  auto Result = SmarActSyms::SA_CTL_GetProperty_i64(SmarActHandle, Channel, SA_CTL_PKEY_TARGET_POSITION, &TargetPosition, nullptr);
157  CheckError(Result);
158 
159  return TargetPosition;
160  }
161 
163  {
165 
166  PositionType Velocity;
167  auto Result = SmarActSyms::SA_CTL_GetProperty_i64(SmarActHandle, Channel, SA_CTL_PKEY_MOVE_VELOCITY, &Velocity, nullptr);
168  CheckError(Result);
169 
170  return Velocity;
171  }
172 
174  {
176 
177  int32_t State;
178  auto Result = SmarActSyms::SA_CTL_GetProperty_i32(SmarActHandle, Channel, SA_CTL_PKEY_CHANNEL_STATE, &State, 0);
179  CheckError(Result);
180 
181  return State;
182  }
183 
185  {
187 
188  auto Result = SmarActSyms::SA_CTL_Calibrate(SmarActHandle, Channel, 0);
189  CheckError(Result);
190  }
191 
193  {
195 
196  // Using direction configured as 'Safe Direction' on the SmarAct controller. Not allwing
197  // to change this setting, because this requires recalibration.
198  auto Result = SmarActSyms::SA_CTL_Reference(SmarActHandle, Channel, 0);
199  CheckError(Result);
200  }
201 
203  {
205 
206  auto Result = SmarActSyms::SA_CTL_SetProperty_i64(SmarActHandle, Channel, SA_CTL_PKEY_MOVE_VELOCITY, Velocity);
207  CheckError(Result);
208  }
209 
211  {
213 
214  auto Result = SmarActSyms::SA_CTL_SetProperty_i32(SmarActHandle, Channel, SA_CTL_PKEY_MOVE_MODE, SA_CTL_MOVE_MODE_CL_ABSOLUTE);
215  CheckError(Result);
216 
217  Result = SmarActSyms::SA_CTL_Move(SmarActHandle, Channel, Position, 0);
218  CheckError(Result);
219  }
220 
222  {
224 
225  auto Result = SmarActSyms::SA_CTL_SetProperty_i32(SmarActHandle, Channel, SA_CTL_PKEY_MOVE_MODE, SA_CTL_MOVE_MODE_CL_RELATIVE);
226  CheckError(Result);
227 
228  Result = SmarActSyms::SA_CTL_Move(SmarActHandle, Channel, Position, 0);
229  CheckError(Result);
230  }
231 
233  {
235 
236  if (!IsOpened())
237  return;
238 
239  auto Result = SmarActSyms::SA_CTL_Stop(SmarActHandle, Channel, 0);
240  CheckError(Result);
241  }
242 }
Implementation of a hardware adapter to control SmarAct MCS2 hardware.
void ConfigureParamsImpl(dispatch_tag< HardwareAdapterParamsBase >) override final
PositionType GetVelocity(const ChannelType Channel) const
int32_t GetChannelState(const ChannelType Channel) const
void MoveAbsolute(const ChannelType Channel, PositionType Position) const
bool IsConnectedChild() const noexcept override final
Determines the connection status of the hardware interface.
void ResetImpl(dispatch_tag< HardwareAdapterBase >) override final
void MoveRelative(const ChannelType Channel, PositionType Position) const
void CheckError(const SmarActSyms::SA_CTL_Result_t Result, const std::source_location Location=std::source_location::current()) const
PositionType GetTargetPosition(const ChannelType Channel) const
SmarActSyms::SA_CTL_DeviceHandle_t SmarActHandle
void EnsureReadyStateChild() override final
Ensures that this Object instance is ready by possibly starting its worker thread or by opening conne...
void Calibrate(const ChannelType Channel) const
void SetVelocity(const ChannelType Channel, PositionType Velocity) const
void Reference(const ChannelType Channel) const
SmarActHardwareAdapter(const std::thread::id OwnerThreadID, DynExp::ParamsBasePtrType &&Params)
bool IsReadyChild() const override final
Returns wheter this Object instance is ready (e.g. it is running or connected to a hardware device) a...
void StopMotion(const ChannelType Channel) const
PositionType GetCurrentPosition(const ChannelType Channel) const
static constexpr auto HardwareOperationTimeout
Default timeout used to lock the mutex provided by the base class Util::ILockable to synchronize acce...
void ThrowExceptionUnsafe(std::exception_ptr Exception) const
Stores Exception in LastException, wraps it in a Util::ForwardedException and throws the wrapped exce...
auto GetExceptionUnsafe() const
Getter for LastException.
ParamsConstTypeSyncPtrType GetParams(const std::chrono::milliseconds Timeout=GetParamsTimeoutDefault) const
Locks the mutex of the parameter class instance Params assigned to this Object instance and returns a...
Definition: Object.cpp:436
Refer to ParamsBase::dispatch_tag.
Definition: Object.h:2018
Tag for function dispatching mechanism within this class used when derived classes are not intended t...
Definition: Object.h:349
Thrown when a list is expected to contain entries and when a query results in an empty answer or an e...
Definition: Exception.h:224
LockType AcquireLock(const std::chrono::milliseconds Timeout=DefaultTimeout) const
Locks the internal mutex. Blocks until the mutex is locked or until the timeout duration is exceeded.
Definition: Util.cpp:8
DynExp's hardware namespace contains the implementation of DynExp hardware adapters which extend DynE...
std::unique_ptr< ParamsBase > ParamsBasePtrType
Alias for a pointer to the parameter system base class ParamsBase.
Definition: Object.h:1807
void ForwardException(std::exception_ptr e)
Wraps the exception passed to the function in a ForwardedException and throws the ForwardedException....
Definition: Exception.cpp:30
Accumulates include statements to provide a precompiled header.