DPsim
Interface.h
1 // SPDX-License-Identifier: Apache-2.0
2 
3 #pragma once
4 
5 #include <thread>
6 
7 #include <dpsim-models/Attribute.h>
8 #include <dpsim-models/Logger.h>
9 #include <dpsim-models/Task.h>
10 #include <dpsim/Config.h>
11 #include <dpsim/Definitions.h>
12 #include <dpsim/Interface.h>
13 #include <dpsim/Scheduler.h>
14 
15 #include <readerwriterqueue.h>
16 
17 namespace DPsim {
18 
19 class InterfaceWorker;
20 
21 class Interface : public SharedFactory<Interface> {
22 
23 public:
24  typedef std::shared_ptr<Interface> Ptr;
25 
26  using AttributePacket = struct AttributePacket {
28  UInt
29  attributeId; //Used to identify the attribute. Defined by the position in the `mExportAttrsDpsim` and `mImportAttrsDpsim` lists
30  UInt
31  sequenceId; //Increasing ID used to discern multiple consecutive updates of a single attribute
32  unsigned char flags; //Bit 0 set: Close interface
33  };
34 
35  enum AttributePacketFlags {
36  PACKET_NO_FLAGS = 0,
37  PACKET_CLOSE_INTERFACE = 1,
38  };
39 
40  Interface(std::shared_ptr<InterfaceWorker> intf, const String &name = "",
41  UInt downsampling = 1)
42  : mInterfaceWorker(intf), mName(name), mDownsampling(downsampling),
43  mOpened(false) {
44  mQueueDpsimToInterface = std::make_shared<
45  moodycamel::BlockingReaderWriterQueue<AttributePacket>>();
46  mQueueInterfaceToDpsim = std::make_shared<
47  moodycamel::BlockingReaderWriterQueue<AttributePacket>>();
48  };
49 
50  virtual void open();
51  virtual void close();
52 
53  // Function used in the interface's simulation task to read all imported attributes from the queue
54  // Called once before every simulation timestep
55  virtual void pushDpsimAttrsToQueue();
56  // Function used in the interface's simulation task to write all exported attributes to the queue
57  // Called once after every simulation timestep
58  virtual void popDpsimAttrsFromQueue(bool isSync = false);
59 
60  // Function called by the Simulation to perform interface synchronization
61  virtual void syncExports();
63  virtual void syncImports();
64 
65  virtual CPS::Task::List getTasks();
66 
67  void setLogger(CPS::Logger::Log log);
68 
69  virtual ~Interface() {
70  if (mOpened)
71  close();
72  }
73 
74  // Attributes used in the DPsim simulation. Should only be accessed by the dpsim-thread
75  // Tuple attributes: Attribute to be imported, Current sequenceID, blockOnRead, syncOnSimulationStart
76  std::vector<std::tuple<CPS::AttributeBase::Ptr, UInt, bool, bool>>
77  mImportAttrsDpsim;
78  // Tuple attributes: Attribute to be exported, Current Sequence ID
79  std::vector<std::tuple<CPS::AttributeBase::Ptr, UInt>> mExportAttrsDpsim;
80 
81 protected:
82  std::shared_ptr<InterfaceWorker> mInterfaceWorker;
83  CPS::Logger::Log mLog;
84  String mName;
85  bool mSyncOnSimulationStart;
86  UInt mCurrentSequenceDpsimToInterface = 1;
87  UInt mNextSequenceInterfaceToDpsim = 1;
88  UInt mDownsampling;
89  std::atomic<bool> mOpened;
90  std::thread mInterfaceWriterThread;
91  std::thread mInterfaceReaderThread;
92 
93  std::shared_ptr<moodycamel::BlockingReaderWriterQueue<AttributePacket>>
94  mQueueDpsimToInterface;
95  std::shared_ptr<moodycamel::BlockingReaderWriterQueue<AttributePacket>>
96  mQueueInterfaceToDpsim;
97 
98  virtual void addImport(CPS::AttributeBase::Ptr attr, bool blockOnRead = false,
99  bool syncOnSimulationStart = true);
100  virtual void addExport(CPS::AttributeBase::Ptr attr);
101 
102 public:
103  class WriterThread {
104  private:
105  std::shared_ptr<moodycamel::BlockingReaderWriterQueue<AttributePacket>>
106  mQueueDpsimToInterface;
107  std::shared_ptr<InterfaceWorker> mInterfaceWorker;
108 
109  public:
110  WriterThread(
111  std::shared_ptr<moodycamel::BlockingReaderWriterQueue<AttributePacket>>
112  queueDpsimToInterface,
113  std::shared_ptr<InterfaceWorker> intf)
114  : mQueueDpsimToInterface(queueDpsimToInterface),
115  mInterfaceWorker(intf){};
116  void operator()() const;
117  };
118 
119  class ReaderThread {
120  private:
121  std::shared_ptr<moodycamel::BlockingReaderWriterQueue<AttributePacket>>
122  mQueueInterfaceToDpsim;
123  std::shared_ptr<InterfaceWorker> mInterfaceWorker;
124  std::atomic<bool> &mOpened;
125 
126  public:
127  ReaderThread(
128  std::shared_ptr<moodycamel::BlockingReaderWriterQueue<AttributePacket>>
129  queueInterfaceToDpsim,
130  std::shared_ptr<InterfaceWorker> intf, std::atomic<bool> &opened)
131  : mQueueInterfaceToDpsim(queueInterfaceToDpsim), mInterfaceWorker(intf),
132  mOpened(opened){};
133  void operator()() const;
134  };
135 
136  class PreStep : public CPS::Task {
137  public:
138  explicit PreStep(Interface &intf)
139  : Task(intf.mName + ".Read"), mIntf(intf) {
140  for (const auto &[attr, _seqId, _blockOnRead, _syncOnStart] :
141  intf.mImportAttrsDpsim) {
142  mModifiedAttributes.push_back(attr);
143  }
144  }
145 
146  void execute(Real time, Int timeStepCount) override;
147 
148  private:
149  Interface &mIntf;
150  };
151 
152  class PostStep : public CPS::Task {
153  public:
154  explicit PostStep(Interface &intf)
155  : Task(intf.mName + ".Write"), mIntf(intf) {
156  for (const auto &[attr, _seqId] : intf.mExportAttrsDpsim) {
157  mAttributeDependencies.push_back(attr);
158  }
159  mModifiedAttributes.push_back(Scheduler::external);
160  }
161 
162  void execute(Real time, Int timeStepCount) override;
163 
164  private:
165  Interface &mIntf;
166  };
167 };
168 } // namespace DPsim
Tasks to be defined by every component.
Definition: Task.h:25
Definition: Interface.h:152
virtual void syncImports()
Function called by the Simulation to perform interface synchronization.
Definition: Interface.cpp:88