Falcon
Loading...
Searching...
No Matches
streamports.hpp
1// ---------------------------------------------------------------------
2// This file is part of falcon-core.
3//
4// Copyright (C) 2015, 2016, 2017 Neuro-Electronics Research Flanders
5//
6// Falcon-server is free software: you can redistribute it and/or modify
7// it under the terms of the GNU General Public License as published by
8// the Free Software Foundation, either version 3 of the License, or
9// (at your option) any later version.
10//
11// Falcon-server is distributed in the hope that it will be useful,
12// but WITHOUT ANY WARRANTY; without even the implied warranty of
13// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14// GNU General Public License for more details.
15//
16// You should have received a copy of the GNU General Public License
17// along with falcon-core. If not, see <http://www.gnu.org/licenses/>.
18// ---------------------------------------------------------------------
19
20#pragma once
21
22#include <memory>
23#include <set>
24#include <string>
25#include <vector>
26
27#include "istreamports.hpp"
28#include "utilities/math_numeric.hpp"
29
31 uint64_t read;
32 uint64_t backlog;
33 bool alive;
34};
35
36// forward declarations
37template <typename DATATYPE>
38class SlotIn;
39template <typename DATATYPE>
40class PortOut;
41template <typename DATATYPE>
42class PortIn;
43int IdentifyNextSlot(int slot_request, int connected_slot_number, bool allow_multi_connect,
44 const PortPolicy& policy);
45
46template <typename DATATYPE>
47class SlotOut : public ISlotOut {
48 friend class PortOut<DATATYPE>;
49
50 public:
51 SlotOut(PortOut<DATATYPE>* parent, const SlotAddress& address,
52 const typename DATATYPE::Parameters& parameters)
53 : ISlotOut(parent, address), streaminfo_(parameters), ringbuffer_serial_number_(0) {}
54
55 // public interface
56 typename DATATYPE::Data* ClaimData(bool clear);
57 std::vector<typename DATATYPE::Data*> ClaimDataN(uint64_t n, bool clear);
58 void PublishData();
59
60 virtual StreamInfo<DATATYPE>& streaminfo() { return streaminfo_; }
61 const typename DATATYPE::Data& prototype() const {
62 return streaminfo_.template getDataPrototype<typename DATATYPE::Data>();
63 }
64 uint64_t nitems_produced() const;
65
66 protected:
67 // called by SlotIn<DATATYPE>
68 virtual typename DATATYPE::Data* DataAt(int64_t sequence) const {
69 return ringbuffer_->Get(sequence);
70 }
71
72 void CreateRingBuffer(int buffer_size, WaitStrategy wait_strategy);
73 void Unlock();
74
75 RingBatch* next_batch(uint64_t n = 1);
76
77 virtual void PrepareProcessing() {
78 ringbuffer_serial_number_ = 0;
79
80 if (!connected()) {
81 return;
82 }
83
84 ringbuffer_->ForcePublish(-1L);
85 ringbuffer_->Claim(-1L);
86 }
87
88 public:
89 StreamInfo<DATATYPE> streaminfo_; // owned by SlotOut, once finalized, the streaminfo (and
90 // datatype) are fixed for the life time of the slot(?)
91 std::unique_ptr<RingBuffer<typename DATATYPE::Data>> ringbuffer_ = nullptr;
92
93 protected:
94 uint64_t ringbuffer_serial_number_;
95};
96
97template <typename DATATYPE>
98class PortOut : public IPortOut {
99 public:
100 PortOut(IProcessor* parent, const PortAddress& address,
101 const typename DATATYPE::Parameters& parameters, const PortOutPolicy& policy)
102 : IPortOut(parent, address, policy), parameters_(parameters) {
103 NewSlot(policy.min_slot_number());
104 }
105
106 SlotType number_of_slots() const override { return slots_.size(); }
107 std::string datatype() const override { return DATATYPE::datatype(); }
108
109 StreamInfo<DATATYPE>& streaminfo(std::size_t index) { return slots_[index]->streaminfo(); }
110
111 const typename DATATYPE::Data& prototype(std::size_t index) const {
112 return slots_[index]->prototype();
113 }
114
115 virtual SlotOut<DATATYPE>* slot(std::size_t index) override { return slots_[index].get(); }
116
117 SlotOut<DATATYPE>* dataslot(std::size_t index) { return slots_[index].get(); }
118
119 protected:
120 // called by StreamOutConnector
121 void Connect(int slot, ISlotIn* downstream) override;
122 int ReserveSlot(int slot) override;
123
124 // called by IPortOut
125 void CreateRingBuffers() override;
126 void UnlockSlots() override;
127
128 // called by PortOut<DATATYPE>::Connect
129 virtual void NewSlot(int n = 1) override;
130
131 void PrepareProcessing() override {
132 for (auto& it : slots_) {
133 it->PrepareProcessing();
134 }
135 }
136
137 private:
138 typename DATATYPE::Parameters parameters_; // default parameters
139 std::vector<std::unique_ptr<SlotOut<DATATYPE>>> slots_;
140};
141
142template <typename DATATYPE>
143class SlotIn : public ISlotIn {
144 friend class PortIn<DATATYPE>;
145
146 public:
147 SlotIn(PortIn<DATATYPE>* parent, const SlotAddress& address,
148 typename DATATYPE::Capabilities capabilities, bool cache = false)
149 : ISlotIn(parent, address, cache), capabilities_(capabilities) {}
150
156 // const typename DATATYPE::Data *GetDataPrototype() const;
157
166 bool RetrieveData(typename DATATYPE::Data*& data, int64_t time_out = -1);
175 bool RetrieveDataN(uint64_t n, std::vector<typename DATATYPE::Data*>& data,
176 int64_t time_out = -1);
185 bool RetrieveDataAll(std::vector<typename DATATYPE::Data*>& data, int64_t time_out = -1);
186
192 bool FlushData() {
193 std::vector<typename DATATYPE::Data*> data;
194 if (!RetrieveDataAll(data, 0)) {
195 return false;
196 }
197
198 auto nread = status_read();
199
200 if (nread == 0) {
201 ReleaseData();
202 }
203 return true;
204 }
205 const IStreamInfo& streaminfo() {
206 if (!connected()) {
207 throw std::runtime_error("Input slot is not connected");
208 }
209
210 NegotiateUpstream();
211
212 return upstream_->streaminfo();
213 }
214
215 const typename DATATYPE::Data& prototype() {
216 return streaminfo().template getDataPrototype<typename DATATYPE::Data>();
217 }
218
219 bool status_alive() const { return status_.alive; }
220 uint64_t status_read() const { return status_.read; }
221 uint64_t status_backlog() const { return status_.backlog; }
222
223 void Validate() override {
224 try {
225 // the template keyword is necessary here for the compiler
226 // to know how to interpret the code
227 // see https://stackoverflow.com/a/613132
228 auto prototype =
229 this->streaminfo().template getDataPrototype<typename DATATYPE::Data>();
230 capabilities_.Validate(prototype);
231 } catch (const std::bad_cast& e) {
232 throw std::runtime_error("Incompatible data types (" + this->streaminfo().datatype() +
233 " -> " + DATATYPE::datatype() + ").");
234 } catch (const std::exception& e) {
235 throw;
236 }
237 }
238
239 protected:
240 void Unlock();
241 void check_high_water_level();
242
243 RingBufferStatus status_;
244
245 const double HIGH_WATER_LEVEL = 0.85;
246 unsigned int n_messages_;
247 const unsigned int MAX_N_MESSAGES = 20;
248
249 typename DATATYPE::Capabilities capabilities_;
250
251 public:
252 typename DATATYPE::Data* cache_;
253};
254
255template <typename DATATYPE>
256class PortIn : public IPortIn {
257 public:
258 PortIn(IProcessor* parent, const PortAddress& address,
259 const typename DATATYPE::Capabilities& capabilities, const PortInPolicy& policy)
260 : IPortIn(parent, address, policy), capabilities_(capabilities) {
261 NewSlot(policy.min_slot_number());
262 }
263
264 SlotType number_of_slots() const override { return slots_.size(); }
265
266 virtual SlotIn<DATATYPE>* slot(std::size_t index) override { return slots_[index].get(); }
267 SlotIn<DATATYPE>* dataslot(std::size_t index) { return slots_[index].get(); }
268
269 std::string datatype() const override { return DATATYPE::datatype(); }
270
271 const IStreamInfo& streaminfo(std::size_t index) { return slots_[index]->streaminfo(); }
272
273 const typename DATATYPE::Data& prototype(std::size_t index) {
274 return slots_[index]->prototype();
275 }
276
277 void PrepareProcessing() override {
278 for (auto& it : slots_) {
279 it->PrepareProcessing();
280 }
281 }
282
283 protected:
284 // called by StreamInConnector
285 virtual void Connect(int slot, ISlotOut* upstream) override;
286 virtual int ReserveSlot(int slot) override;
287
288 void UnlockSlots() override;
289 void NewSlot(int n = 1);
290
291 private:
292 typename DATATYPE::Capabilities capabilities_;
293 std::vector<std::unique_ptr<SlotIn<DATATYPE>>> slots_;
294};
295
296#include "streamports.ipp"
Definition istreamports.hpp:126
Definition istreamports.hpp:40
Definition streaminfo.hpp:31
Definition connections.hpp:24
Definition portpolicy.hpp:43
Definition streamports.hpp:256
Definition portpolicy.hpp:54
Definition streamports.hpp:98
Definition portpolicy.hpp:28
Definition connections.hpp:54
Definition streamports.hpp:143
bool FlushData()
Flush all data already in the ring buffer without retrieve them - method used from the processor impl...
Definition streamports.hpp:192
bool RetrieveData(typename DATATYPE::Data *&data, int64_t time_out=-1)
get a prototype example of a data packet - method used from the processor implementation
bool RetrieveDataN(uint64_t n, std::vector< typename DATATYPE::Data * > &data, int64_t time_out=-1)
Retrieve N data packets in the ring buffer - method used from the processor implementation.
bool RetrieveDataAll(std::vector< typename DATATYPE::Data * > &data, int64_t time_out=-1)
Retrieve all data packets in the ring buffer - method used from the processor implementation.
Definition streamports.hpp:47
Definition streaminfo.hpp:73
Definition streamports.hpp:30