DPsim
InterfaceQueued.h
1 /* Author: Niklas Eiling <niklas.eiling@eonerc.rwth-aachen.de>
2  * SPDX-FileCopyrightText: 2023-2024 Niklas Eiling <niklas.eiling@eonerc.rwth-aachen.de>
3  * SPDX-License-Identifier: MPL-2.0
4  */
5 
6 #pragma once
7 
8 #include <thread>
9 
10 #include <dpsim-models/Attribute.h>
11 #include <dpsim-models/Logger.h>
12 #include <dpsim-models/Task.h>
13 #include <dpsim/Config.h>
14 #include <dpsim/Definitions.h>
15 #include <dpsim/Interface.h>
16 #include <dpsim/Scheduler.h>
17 
18 #include <readerwriterqueue.h>
19 
20 namespace DPsim {
21 
22 class InterfaceWorker;
23 
24 class InterfaceQueued : public Interface, public SharedFactory<InterfaceQueued> {
25 
26 public:
27  typedef std::shared_ptr<InterfaceQueued> Ptr;
28 
29  using AttributePacket = struct AttributePacket {
31  UInt attributeId; // Used to identify the attribute. Defined by the position in the `mExportAttrsDpsim` and `mImportAttrsDpsim` lists
32  UInt sequenceId; // Increasing ID used to discern multiple consecutive updates of a single attribute
33  unsigned char flags; // Bit 0 set: Close interface
34  };
35 
36  enum AttributePacketFlags {
37  PACKET_NO_FLAGS = 0,
38  PACKET_CLOSE_INTERFACE = 1,
39  };
40 
41  InterfaceQueued(std::shared_ptr<InterfaceWorker> intf, const String &name = "", UInt downsampling = 1) : Interface(name), mInterfaceWorker(intf), mDownsampling(downsampling) {
42  mQueueDpsimToInterface = std::make_shared<moodycamel::BlockingReaderWriterQueue<AttributePacket>>();
43  mQueueInterfaceToDpsim = std::make_shared<moodycamel::BlockingReaderWriterQueue<AttributePacket>>();
44  };
45 
46  virtual void open() override;
47  virtual void close() override;
48 
49  // Function used in the interface's simulation task to read all imported attributes from the queue
50  // Called once before every simulation timestep
51  virtual void pushDpsimAttrsToQueue();
52  // Function used in the interface's simulation task to write all exported attributes to the queue
53  // Called once after every simulation timestep
54  virtual void popDpsimAttrsFromQueue(bool isSync = false);
55 
56  // Function called by the Simulation to perform interface synchronization
57  virtual void syncExports() override;
59  virtual void syncImports() override;
60 
61  virtual CPS::Task::List getTasks() override;
62 
63  virtual void setLogger(CPS::Logger::Log log) override;
64 
65  virtual ~InterfaceQueued() {
66  if (mOpened)
67  close();
68  }
69 
70 protected:
71  std::shared_ptr<InterfaceWorker> mInterfaceWorker;
72  UInt mDownsampling;
73  std::thread mInterfaceWriterThread;
74  std::thread mInterfaceReaderThread;
75 
76  std::shared_ptr<moodycamel::BlockingReaderWriterQueue<AttributePacket>> mQueueDpsimToInterface;
77  std::shared_ptr<moodycamel::BlockingReaderWriterQueue<AttributePacket>> mQueueInterfaceToDpsim;
78 
79 public:
80  class WriterThread {
81  private:
82  std::shared_ptr<moodycamel::BlockingReaderWriterQueue<AttributePacket>> mQueueDpsimToInterface;
83  std::shared_ptr<InterfaceWorker> mInterfaceWorker;
84 
85  public:
86  WriterThread(std::shared_ptr<moodycamel::BlockingReaderWriterQueue<AttributePacket>> queueDpsimToInterface, std::shared_ptr<InterfaceWorker> intf)
87  : mQueueDpsimToInterface(queueDpsimToInterface), mInterfaceWorker(intf){};
88  void operator()() const;
89  };
90 
91  class ReaderThread {
92  private:
93  std::shared_ptr<moodycamel::BlockingReaderWriterQueue<AttributePacket>> mQueueInterfaceToDpsim;
94  std::shared_ptr<InterfaceWorker> mInterfaceWorker;
95  std::atomic<bool> &mOpened;
96 
97  public:
98  ReaderThread(std::shared_ptr<moodycamel::BlockingReaderWriterQueue<AttributePacket>> queueInterfaceToDpsim, std::shared_ptr<InterfaceWorker> intf, std::atomic<bool> &opened)
99  : mQueueInterfaceToDpsim(queueInterfaceToDpsim), mInterfaceWorker(intf), mOpened(opened){};
100  void operator()() const;
101  };
102 
103  class PreStep : public CPS::Task {
104  public:
105  explicit PreStep(InterfaceQueued &intf) : Task(intf.getName() + ".Read"), mIntf(intf) {
106  for (const auto &[attr, _seqId, _blockOnRead, _syncOnStart] : intf.mImportAttrsDpsim) {
107  mModifiedAttributes.push_back(attr);
108  }
109  }
110 
111  void execute(Real time, Int timeStepCount) override;
112 
113  private:
114  InterfaceQueued &mIntf;
115  };
116 
117  class PostStep : public CPS::Task {
118  public:
119  explicit PostStep(InterfaceQueued &intf) : Task(intf.getName() + ".Write"), mIntf(intf) {
120  for (const auto &[attr, _seqId] : intf.mExportAttrsDpsim) {
121  mAttributeDependencies.push_back(attr);
122  }
123  mModifiedAttributes.push_back(Scheduler::external);
124  }
125 
126  void execute(Real time, Int timeStepCount) override;
127 
128  private:
129  InterfaceQueued &mIntf;
130  };
131 };
132 } // namespace DPsim
Tasks to be defined by every component.
Definition: Task.h:25
virtual void syncImports() override
Function called by the Simulation to perform interface synchronization.