InterfaceShmem.h 4.6 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/* Copyright 2017-2020 Institute for Automation of Complex Power Systems,
 *                     EONERC, RWTH Aachen University
 * DPsim
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * any later version.
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 *********************************************************************************/

17
18
19
20
// #############################################
// Do NOT include this header in any MPL2 files
// #############################################

21
22
23
24
25
26
27
28
29
30
31
32
#pragma once

#include <vector>

#include <cps/PtrFactory.h>
#include <dpsim/Interface.h>

#include <villas/sample.h>
#include <villas/shmem.h>

namespace DPsim {
	/// Shmem interface used in combination with VILLAS
33
	class InterfaceShmem :
Markus Mirz's avatar
Markus Mirz committed
34
		public Interface {
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107

	public:
		typedef std::shared_ptr<InterfaceShmem> Ptr;
		typedef struct ::sample Sample;
		typedef struct ::shmem_conf Config;
		typedef struct ::shmem_int ShmemInt;

	protected:
		// Using std::function / lambda makes the other template code nicer, but from
		// the outside, only the attribute-based functions should be used to
		// guarantee proper scheduling

		void addImport(std::function<void(Sample*)> l) { mImports.push_back(l); }
		void addExport(std::function<void(Sample*)> l) { mExports.push_back(l); }

		std::vector<std::function<void(Sample*)>> mExports, mImports;
		CPS::AttributeBase::List mExportAttrs, mImportAttrs;

		ShmemInt mShmem;
		Sample *mLastSample;

		bool mOpened;
		int mSequence;
		String mRName, mWName;
		Config mConf;

		CPS::Logger::Log mLog;

		/// Is this InterfaceShmem used for synchorinzation?
		bool mSync;
		/// Downsampling
		UInt mDownsampling;

	public:

		class PreStep : public CPS::Task {
		public:
			PreStep(InterfaceShmem& intf) :
				Task(intf.mRName + ".Read"), mIntf(intf) {
				for (auto attr : intf.mImportAttrs) {
					mModifiedAttributes.push_back(attr);
				}
			}

			void execute(Real time, Int timeStepCount);

		private:
			InterfaceShmem& mIntf;
		};

		class PostStep : public CPS::Task {
		public:
			PostStep(InterfaceShmem& intf) :
				Task(intf.mWName + ".Write"), mIntf(intf) {
				for (auto attr : intf.mExportAttrs) {
					mAttributeDependencies.push_back(attr);
				}
				mModifiedAttributes.push_back(Scheduler::external);
			}

			void execute(Real time, Int timeStepCount);

		private:
			InterfaceShmem& mIntf;
		};

		/** Create a InterfaceShmem with a specific configuration for the output queue.
		 *
		 * @param wname The name of the POSIX shmem object where samples will be written to.
		 * @param rname The name of the POSIX shmem object where samples will be read from.
		 * @param conf The configuration object for the output queue (see VILLASnode's documentation), or nullptr for sensible defaults.
		 */
		InterfaceShmem(const String &wn, const String &rn, Config *conf = nullptr, Bool sync = true, UInt downsampling = 1) :
108
			mLastSample(nullptr),
109
			mOpened(false),
110
			mSequence(0),
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
			mRName(rn),
			mWName(wn),
			mSync(sync),
			mDownsampling(downsampling)
		{
			if (conf != nullptr) {
				mConf = *conf;
			} else {
				mConf.queuelen = 512;
				mConf.samplelen = 64;
				mConf.polling = 0;
			}
		}

		~InterfaceShmem() {
			if (mOpened)
				close();
		}

		void open(CPS::Logger::Log log);
		void close();

		CPS::Attribute<Int>::Ptr importInt(UInt idx);
		CPS::Attribute<Real>::Ptr importReal(UInt idx);
		CPS::Attribute<Bool>::Ptr importBool(UInt idx);
		CPS::Attribute<Complex>::Ptr importComplex(UInt idx);
		CPS::Attribute<Complex>::Ptr importComplexMagPhase(UInt idx);

		void exportInt(CPS::Attribute<Int>::Ptr attr, UInt idx);
		void exportReal(CPS::Attribute<Real>::Ptr attr, UInt idx);
		void exportBool(CPS::Attribute<Bool>::Ptr attr, UInt idx);
		void exportComplex(CPS::Attribute<Complex>::Ptr attr, UInt idx);

		/** Read data for a timestep from the InterfaceShmem and passes the values
		 * to all registered current / voltage sources.
		 */
		void readValues(bool blocking = true);

		/** Write all exported values to the InterfaceShmem. Called after every timestep.
		 * @param model Reference to the system model which should be used to
		 * calculate needed voltages.
		 */
		void writeValues();

		CPS::Task::List getTasks();
	};
}