DynExp
Highly flexible laboratory automation for dynamically changing experiments.
Loading...
Searching...
No Matches
HardwareAdapter.h
Go to the documentation of this file.
1// This file is part of DynExp.
2
8#pragma once
9
10#include "stdafx.h"
11#include "Object.h"
12
13namespace DynExp
14{
15 class HardwareAdapterBase;
16 class SerialCommunicationHardwareAdapter;
17 class QSerialCommunicationHardwareAdapter;
18
22 using HardwareAdapterPtrType = std::shared_ptr<HardwareAdapterBase>;
23
29 template <typename HardwareAdapterT>
31 {
32 return std::make_shared<typename HardwareAdapterT::ConfigType>();
33 }
34
42 template <typename HardwareAdapterT>
43 HardwareAdapterPtrType MakeHardwareAdapter(const std::thread::id OwnerThreadID, ParamsBasePtrType&& Params)
44 {
45 return std::make_shared<HardwareAdapterT>(OwnerThreadID, std::move(Params));
46 }
47
52 {
53 public:
59
60 virtual ~HardwareAdapterParamsBase() = 0;
61
62 virtual const char* GetParamClassTag() const noexcept override { return "HardwareAdapterParamsBase"; }
63
64 private:
67
68 DummyParam Dummy = { *this };
69 };
70
83
89 {
90 public:
93
97 static constexpr auto ShortTimeoutDefault = std::chrono::milliseconds(10);
98
103 static constexpr auto HardwareOperationTimeout = std::chrono::milliseconds(100);
104
109 constexpr static auto Category() noexcept { return ""; }
110
116 : Object(OwnerThreadID, std::move(Params)) {}
117
118 virtual ~HardwareAdapterBase() = 0;
119
120 virtual std::string GetCategory() const override { return Category(); }
121
125 void ResetException() const;
126
132 bool IsConnected() const noexcept { return IsConnectedChild(); }
133
134 protected:
140 void ThrowException(std::exception_ptr Exception) const;
141
146
149 void ThrowExceptionUnsafe(std::exception_ptr Exception) const;
150
155 void SetExceptionUnsafe(std::exception_ptr Exception) const;
156
161 auto GetExceptionUnsafe() const { return LastException; }
163
164 private:
165 void ResetImpl(dispatch_tag<Object>) override final;
167
172 void EnsureReadyStateChild([[maybe_unused]] bool IsAutomaticStartup) override final;
173
174 virtual void EnsureReadyStateChild() = 0;
175 std::exception_ptr GetExceptionChild(const std::chrono::milliseconds Timeout) const override final;
176
181 virtual bool IsConnectedChild() const noexcept = 0;
183
184 mutable std::exception_ptr LastException;
185 };
186
190 class SerialCommunicationException : public Util::Exception
191 {
192 public:
199 SerialCommunicationException(std::string Description, const int ErrorCode,
200 const std::source_location Location = std::source_location::current()) noexcept
201 : Exception(std::move(Description), Util::ErrorType::Error, ErrorCode, Location)
202 {}
203 };
204
209 {
210 public:
215 enum LineEndingType { None, Zero, LF, CRLF, CR };
216
222
224
225 virtual const char* GetParamClassTag() const noexcept override { return "SerialCommunicationHardwareAdapterParams"; }
226
231 static Util::TextValueListType<LineEndingType> AvlblLineEndingsStrList();
232
236 Param<LineEndingType> LineEnding = { *this, AvlblLineEndingsStrList(), "LineEnding", "Line ending",
237 "Characters which terminate a single line", true, LineEndingType::LF };
238
239 private:
242 };
243
256
262 {
263 public:
266
270 struct endl {};
271
276 constexpr static auto Name() noexcept { return "< any >"; }
277
278 constexpr static auto Category() noexcept { return "Communication"; }
279
287 constexpr static std::array<char, 2> LineEndingToChar(SerialCommunicationHardwareAdapterParams::LineEndingType LineEnding) noexcept;
288
295 constexpr static unsigned int GetLineEndingLength(SerialCommunicationHardwareAdapterParams::LineEndingType LineEnding) noexcept;
296
301 constexpr static auto GetMaxBufferSize() noexcept { return 104857600; }
302
306 SerialCommunicationHardwareAdapter(const std::thread::id OwnerThreadID, ParamsBasePtrType&& Params);
307
309
310 virtual std::string GetName() const override { return Name(); }
311 virtual std::string GetCategory() const override { return Category(); }
312
321 auto GetLineEnding() const { return LineEnding.load(); }
322
328 std::string ReadLine() const;
329
334 std::string ReadAll() const;
335
344 std::string WaitForLine(unsigned int NumTries = 10, std::chrono::milliseconds DelayBetweenTries = std::chrono::milliseconds(10)) const;
345
350 void Clear() const;
351
355 void Flush() const;
356
362 const SerialCommunicationHardwareAdapter& operator>>(std::stringstream& OutStream) const;
363
368 const SerialCommunicationHardwareAdapter& operator<<(endl) const;
369
375 const SerialCommunicationHardwareAdapter& operator<<(const std::stringstream& InStream) const;
376
382 const SerialCommunicationHardwareAdapter& operator<<(const std::string& Text) const;
383
387 const SerialCommunicationHardwareAdapter& operator<<(const std::string_view Text) const;
388
392 const SerialCommunicationHardwareAdapter& operator<<(const char* Text) const;
393
399 const SerialCommunicationHardwareAdapter& operator<<(const char Char) const;
400
407 template <typename T>
408 auto& operator<<(const T& Value) const
409 {
410 auto lock = AcquireLock(HardwareOperationTimeout);
411
412 Write(Util::ToStr(Value));
413 Write_endl();
414
415 return *this;
416 }
417
418 protected:
429 void InsertIntoBuffer(const std::string& String) const;
430
431 private:
432 void Init();
433
434 void ResetImpl(dispatch_tag<HardwareAdapterBase>) override final;
436
441
447 void ReadIntoBuffer() const;
448
452 void ClearReadBuffer() const;
453
459 bool CheckOverflow() const;
461
467 virtual void ClearChild() const {}
468 virtual void FlushChild() const {}
469
474 virtual std::string Read() const = 0;
475
480 virtual void Write(const std::string& String) const = 0;
481
485 virtual void Write_endl() const = 0;
487
493 std::atomic<SerialCommunicationHardwareAdapterParams::LineEndingType> LineEnding = SerialCommunicationHardwareAdapterParams::LineEndingType::LF;
494
495 std::string LineEndingString;
496 mutable std::stringstream ReadBuffer;
497 };
498
500 {
501 switch (LineEnding)
502 {
506 default: return { '\0', '\0' };
507 }
508 }
509
519
542
555
564 {
565 Q_OBJECT
566
567 public:
570
571 public slots:
572 void Open() { OpenChild(); }
573 void Close() { CloseChild(); }
574 void Reset() { ResetChild(); }
575 void Clear() { ClearChild(); }
576 void Flush() { FlushChild(); }
577 void Read() { ReadChild(); }
578 void Write(const QString String) { WriteChild(String); }
579 void Write_endl() { Write_endl_Child(); }
580
581 protected:
586 void SetCommunicationChannelOpened() const noexcept;
587
592 void SetCommunicationChannelClosed() const noexcept;
593
598 void DataRead(const std::string& String) const;
599
606 template <typename ExceptionType>
607 void SetException(const ExceptionType& Exception) const;
608
609 private:
610 virtual void OpenChild() = 0;
611 virtual void CloseChild() = 0;
612 virtual void ResetChild() = 0;
613 virtual void ClearChild() = 0;
614 virtual void FlushChild() = 0;
615 virtual void ReadChild() = 0;
616 virtual void WriteChild(const QString& String) = 0;
617 virtual void Write_endl_Child() = 0;
618 };
619
629 {
630 Q_OBJECT
631
632 private:
638 {
641
647
648 void SetCommunicationChannelOpened() const noexcept { Parent.SetCommunicationChannelOpened(); }
649 void SetCommunicationChannelClosed() const noexcept { Parent.SetCommunicationChannelClosed(); }
650 void DataRead(const std::string& String) const { Parent.DataRead(String); }
651
655 template <typename ExceptionType>
656 void SetException(const ExceptionType& Exception) const { Parent.SetException(Exception); }
657
659 };
660
661 public:
664 using QWorkerPtrType = std::unique_ptr<QSerialCommunicationHardwareAdapterWorker>;
665
666 QSerialCommunicationHardwareAdapter(const std::thread::id OwnerThreadID, ParamsBasePtrType&& Params);
668
670
671 private:
676
684
689 virtual void InitWorker() {}
691
692 void ResetImpl(dispatch_tag<SerialCommunicationHardwareAdapter>) override final;
694
699 void EnsureReadyStateChild() override final;
700
701 bool IsReadyChild() const override final;
702 bool IsConnectedChild() const noexcept override final;
703
709 void SetCommunicationChannelOpened() const noexcept { CommunicationChannelOpened = true; }
710 void SetCommunicationChannelClosed() const noexcept { CommunicationChannelOpened = false; }
711
716 void DataRead(const std::string& String) const;
717
724 template <typename ExceptionType>
725 void SetException(const ExceptionType& Exception) const noexcept
726 {
727 try
728 {
729 auto lock = AcquireLock(HardwareOperationTimeout);
730
731 auto ExceptionPtr = std::make_exception_ptr(Exception);
732 SetExceptionUnsafe(ExceptionPtr);
733 PendingException = ExceptionPtr;
734 }
735 catch (...)
736 {
737 // Swallow exception if an error occurs setting it. This is not optimal but there
738 // is no other way since exceptions are not allowed to leave Qt's slots.
739 }
740 }
742
747 void ClearChild() const override final;
748 void FlushChild() const override final;
749 std::string Read() const override final;
750 void Write(const std::string& String) const override final;
751 void Write_endl() const override final;
752
759 void ThrowPendingException() const;
761
762 signals:
768 void OpenSig();
769 void CloseSig();
770 void ResetSig();
771 void ClearSig() const;
772 void FlushSig() const;
773 void ReadSig() const;
774 void WriteSig(const QString String) const;
775 void Write_endl_Sig() const;
777
778 private:
780 mutable std::atomic<bool> CommunicationChannelOpened;
781 mutable std::exception_ptr PendingException;
782 };
783
784 // Needs to be defined after declaration of class QSerialCommunicationHardwareAdapter.
785 template <typename ExceptionType>
786 void QSerialCommunicationHardwareAdapterWorker::SetException(const ExceptionType& Exception) const
787 {
788 auto Owner = std::dynamic_pointer_cast<const QSerialCommunicationHardwareAdapter>(GetOwner());
789 if (!Owner)
790 return;
791
792 Owner->QSerialCommunicationHardwareAdapterWorkerOnly.SetException(Exception);
793 }
794}
795
800namespace DynExpHardware {};
Implementation of DynExp objects as the base for derived resources and implementation of the object p...
The configurator classes have the task to generate parameter objects (refer to DynExp::ParamsBase) of...
Definition Object.h:1879
DynExp's core class acts as the interface between the user interface and DynExp's internal data like ...
Definition DynExpCore.h:127
Defines the base class for a hardware adapter object. Hardware adapters describe interfaces/connectio...
HardwareAdapterBase(const std::thread::id OwnerThreadID, ParamsBasePtrType &&Params)
Constructs a hardware adapter instance.
void ThrowException(std::exception_ptr Exception) const
Stores Exception in LastException, wraps it in a Util::ForwardedException and throws the wrapped exce...
std::exception_ptr GetExceptionChild(const std::chrono::milliseconds Timeout) const override final
Returns a pointer to the exception which has caused this Object instance to fail.
virtual bool IsConnectedChild() const noexcept=0
Determines the connection status of the hardware interface.
bool IsConnected() const noexcept
Determines the connection status of the hardware interface.
void SetExceptionUnsafe(std::exception_ptr Exception) const
Stores Exception in LastException.
static constexpr auto ShortTimeoutDefault
Default timeout e.g. used as a default for calls to Object::GetException().
virtual std::string GetCategory() const override
Returns the category of this Object type.
virtual void EnsureReadyStateChild()=0
Ensures that this Object instance is ready by possibly starting its worker thread or by opening conne...
std::exception_ptr LastException
Stores the most recent exception caused by a hardware operation.
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.
void ResetImpl(dispatch_tag< Object >) override final
Refer to DynExp::Object::Reset(). Using tag dispatch mechanism to ensure that ResetImpl() of every de...
static constexpr auto Category() noexcept
Every derived class has to redefine this function.
void ResetException() const
Sets LastException to nullptr in a thread-safe way.
virtual void ResetImpl(dispatch_tag< HardwareAdapterBase >)=0
Refer to DynExp::Object::Reset(). Using tag dispatch mechanism to ensure that ResetImpl() of every de...
Configurator class for HardwareAdapterBase.
Parameter class for HardwareAdapterBase.
void ConfigureParamsImpl(dispatch_tag< ParamsBase >) override final
Called by DynExp::ParamsBase::ConfigureParams() as a starting point for the tag dispatch mechanism to...
DummyParam Dummy
Dummy parameter which is to be owned once by parameter classes that do not contain any other paramete...
virtual const char * GetParamClassTag() const noexcept override
This function is intended to be overridden once in each derived class returning the name of the respe...
HardwareAdapterParamsBase(ItemIDType ID, const DynExpCore &Core)
Constructs the parameters for a HardwareAdapterBase instance.
virtual void ConfigureParamsImpl(dispatch_tag< HardwareAdapterParamsBase >)
Called by DynExp::ParamsBase::ConfigureParams() as a starting point for the tag dispatch mechanism to...
Base class for all DynExp Objects like hardware adapters (DynExp::HardwareAdapterBase),...
Definition Object.h:1971
const std::thread::id OwnerThreadID
Thread id of the thread which has constructed (and owns) this Object instance.
Definition Object.h:2302
const ParamsBasePtrType Params
Pointer to the parameter class instance belonging to this Object instance.
Definition Object.h:2303
Refer to ParamsBase::dispatch_tag.
Definition Object.h:2018
Dummy parameter which is to be owned once by parameter classes that do not contain any other paramete...
Definition Object.h:522
Abstract base class for object parameter classes. Each class derived from class Object must be accomp...
Definition Object.h:326
const ItemIDType ID
ID of the Object this parameter class instance belongs to.
Definition Object.h:1779
const DynExpCore & Core
Reference to DynExp's core.
Definition Object.h:1780
Tag for function dispatching mechanism within this class used when derived classes are not intended t...
Definition Object.h:349
Configurator class for QSerialCommunicationHardwareAdapter.
Parameter class for QSerialCommunicationHardwareAdapter.
virtual const char * GetParamClassTag() const noexcept override
This function is intended to be overridden once in each derived class returning the name of the respe...
virtual void ConfigureParamsImpl(dispatch_tag< QSerialCommunicationHardwareAdapterParams >)
Called by DynExp::ParamsBase::ConfigureParams() as a starting point for the tag dispatch mechanism to...
void ConfigureParamsImpl(dispatch_tag< SerialCommunicationHardwareAdapterParams >) override final
Called by DynExp::ParamsBase::ConfigureParams() as a starting point for the tag dispatch mechanism to...
QSerialCommunicationHardwareAdapterParams(ItemIDType ID, const DynExpCore &Core)
Constructs the parameters for a QSerialCommunicationHardwareAdapter instance.
Qt worker which performs actual serial communication hardware operations in a separate thread in orde...
void Read()
Reads from the communication connection's hardware interface.
void Clear()
Clears the communication connection's buffers and state.
void Write_endl()
Writes end of the line character(s) to the communication connection's hardware interface.
void Flush()
Flushes the communication connection's buffers.
void Close()
Closes the communication connection.
void Write(const QString String)
Writes String to the communication connection's hardware interface.
void Open()
Opens the communication connection.
void Reset()
Resets the worker and the communication connection.
Allow exclusive access to some of QSerialCommunicationHardwareAdapter's private methods to QSerialCom...
void SetException(const ExceptionType &Exception) const
Sets Exception as PendingException and stores it by calling HardwareAdapterBase::SetExceptionUnsafe()...
QSerialCommunicationHardwareAdapter & Parent
Owning QSerialCommunicationHardwareAdapter instance.
void DataRead(const std::string &String) const
Passes data to the hardware adapter which has been received by the worker instance.
void SetCommunicationChannelClosed() const noexcept
Sets CommunicationChannelOpened to false.
constexpr QSerialCommunicationHardwareAdapterWorkerOnlyType(QSerialCommunicationHardwareAdapter &Parent) noexcept
Construcs an instance - one for each QSerialCommunicationHardwareAdapter instance.
void SetCommunicationChannelOpened() const noexcept
Sets CommunicationChannelOpened to true.
SerialCommunicationHardwareAdapter is based on a Qt communication object (wrapped by QSerialCommunica...
virtual void InitWorker()
Tells the worker instance to perform initialization steps, e.g. by emitting a Qt signal which is rece...
void SetException(const ExceptionType &Exception) const noexcept
Sets Exception as PendingException and stores it by calling HardwareAdapterBase::SetExceptionUnsafe()...
QSerialCommunicationHardwareAdapterWorkerOnlyType QSerialCommunicationHardwareAdapterWorkerOnly
Allow exclusive access to some of QSerialCommunicationHardwareAdapter's private methods to QSerialCom...
std::unique_ptr< QSerialCommunicationHardwareAdapterWorker > QWorkerPtrType
Pointer-type owning the related QSerialCommunicationHardwareAdapterWorker instance.
virtual void ResetImpl(dispatch_tag< QSerialCommunicationHardwareAdapter >)
Refer to DynExp::Object::Reset(). Using tag dispatch mechanism to ensure that ResetImpl() of every de...
void SetCommunicationChannelClosed() const noexcept
Sets CommunicationChannelOpened to false.
virtual QWorkerPtrType MakeWorker()=0
Abstract factory function for a worker instance derived from QSerialCommunicationHardwareAdapterWorke...
Defines an exception caused by a serial communication operation of a hardware adapter.
SerialCommunicationException(std::string Description, const int ErrorCode, const std::source_location Location=std::source_location::current()) noexcept
Constructs a SerialCommunicationException instance.
Configurator class for SerialCommunicationHardwareAdapter.
Parameter class for SerialCommunicationHardwareAdapter.
LineEndingType
Possible line endings sent after writing a line and used to determine the end of a line while reading...
void ConfigureParamsImpl(dispatch_tag< HardwareAdapterParamsBase >) override final
Called by DynExp::ParamsBase::ConfigureParams() as a starting point for the tag dispatch mechanism to...
virtual const char * GetParamClassTag() const noexcept override
This function is intended to be overridden once in each derived class returning the name of the respe...
virtual void ConfigureParamsImpl(dispatch_tag< SerialCommunicationHardwareAdapterParams >)
Called by DynExp::ParamsBase::ConfigureParams() as a starting point for the tag dispatch mechanism to...
SerialCommunicationHardwareAdapterParams(ItemIDType ID, const DynExpCore &Core)
Constructs the parameters for a SerialCommunicationHardwareAdapter instance.
Defines a hardware adapter for serial communication. Logical const-ness: see declaration of class Dyn...
static constexpr unsigned int GetLineEndingLength(SerialCommunicationHardwareAdapterParams::LineEndingType LineEnding) noexcept
Determines the amount of characters required to express a line ending type defined by SerialCommunica...
virtual void Write_endl() const =0
Writes end of the line characters to the underlying hardware interface.
static constexpr auto GetMaxBufferSize() noexcept
Defines the maximal size of the hardware adapter's (read) buffer.
virtual void FlushChild() const
Flushes the underlying hardware interface.
virtual void Write(const std::string &String) const =0
Writes a string to the underlying hardware interface.
std::string LineEndingString
String corresponding to LineEnding. Refer to LineEndingToChar()
virtual void ClearChild() const
Clears internal buffers of the underlying hardware interface.
static constexpr std::array< char, 2 > LineEndingToChar(SerialCommunicationHardwareAdapterParams::LineEndingType LineEnding) noexcept
Converts SerialCommunicationHardwareAdapterParams::LineEndingType to two characters being used as the...
virtual void ResetImpl(dispatch_tag< SerialCommunicationHardwareAdapter >)
Refer to DynExp::Object::Reset(). Using tag dispatch mechanism to ensure that ResetImpl() of every de...
static constexpr auto Category() noexcept
Every derived class has to redefine this function.
virtual std::string Read() const =0
Reads a string from the underlying hardware interface.
auto & operator<<(const T &Value) const
Writes the input parameter calling Write(). Also writes endl at the end automatically.
virtual std::string GetName() const override
Returns the name of this Object type.
virtual std::string GetCategory() const override
Returns the category of this Object type.
auto GetLineEnding() const
Getter for LineEnding. Thread-safe since LineEnding only changes when Object::Reset() is called (itse...
std::stringstream ReadBuffer
Buffer storing data read from the underlying physical hardware.
static constexpr auto Name() noexcept
Every derived class has to redefine this function.
Type denoting the end of a line when piped to operator<<(endl)
Interface to allow synchronizing the access to derived classes between different threads by providing...
Definition Util.h:56
Implements a QObject belonging to a hardware adapter (derived from DynExp::HardwareAdapterBase) that ...
Definition QtUtil.h:327
DynExp's hardware namespace contains the implementation of DynExp hardware adapters which extend DynE...
DynExp's main namespace contains the implementation of DynExp including classes to manage resources (...
HardwareAdapterPtrType MakeHardwareAdapter(const std::thread::id OwnerThreadID, ParamsBasePtrType &&Params)
Factory function to generate a hardware adapter of a specific type.
std::unique_ptr< ParamsBase > ParamsBasePtrType
Alias for a pointer to the parameter system base class ParamsBase.
Definition Object.h:1807
size_t ItemIDType
ID type of objects/items managed by DynExp.
ConfiguratorBasePtrType MakeHardwareAdapterConfig()
Factory function to generate a configurator for a specific hardware adapter type.
std::shared_ptr< ConfiguratorBase > ConfiguratorBasePtrType
Alias for a pointer to the configurator base class ConfiguratorBase.
Definition Object.h:1959
std::shared_ptr< HardwareAdapterBase > HardwareAdapterPtrType
Pointer type to store a hardware adapter (DynExp::HardwareAdapterBase) with.
DynExp's Util namespace contains commonly used functions and templates as well as extensions to Qt an...
std::string ToStr(const T &Value, int Precision=-1)
Converts a (numeric) value of type T to a std::string using operator<< of std::stringstream.
Definition Util.h:625
std::vector< std::pair< TextType, ValueType > > TextValueListType
Type of a list containing key-value pairs where key is a text of type Util::TextType.
Definition QtUtil.h:37
Accumulates include statements to provide a precompiled header.