SatCat5
multi_buffer.h
Go to the documentation of this file.
1 // Copyright 2024-2025 The Aerospace Corporation.
3 // This file is a part of SatCat5, licensed under CERN-OHL-W v2 or later.
38 
39 #pragma once
40 
41 #include <satcat5/io_readable.h>
42 #include <satcat5/io_writeable.h>
43 #include <satcat5/list.h>
44 #include <satcat5/types.h>
45 
46 // Set default: Chunk size for internal allocator.
47 #ifndef SATCAT5_MBUFF_CHUNK
48 #define SATCAT5_MBUFF_CHUNK (64 - sizeof(uintptr_t))
49 #endif
50 
51 // Set default: Maximum bytes per packet.
52 #ifndef SATCAT5_MBUFF_PKTLEN
53 #define SATCAT5_MBUFF_PKTLEN 2048
54 #endif
55 
56 // Set default: Maximum packets in the read queue.
57 #ifndef SATCAT5_MBUFF_RXPKT
58 #define SATCAT5_MBUFF_RXPKT 32
59 #endif
60 
61 // Set default: Per-byte read timeout, in milliseconds.
62 #ifndef SATCAT5_MBUFF_TIMEOUT
63 #define SATCAT5_MBUFF_TIMEOUT 1500
64 #endif
65 
66 // Set default: Reserved size for additional packet metadata.
67 #ifndef SATCAT5_MBUFF_USER
68 #define SATCAT5_MBUFF_USER 8
69 #endif
70 
71 namespace satcat5 {
72  namespace io {
75  struct MultiChunk final {
76  private:
79  public:
80  constexpr MultiChunk() : m_next(0), m_data{0} {}
81  MultiChunk(const MultiChunk& t) = delete;
82  MultiChunk& operator=(const MultiChunk& t) = delete;
83  u8 m_data[SATCAT5_MBUFF_CHUNK];
84  };
85 
91  struct MultiPacket final {
92  private:
98 
99  public:
100  // Data for this packet should only be read by io::MultiReader.
102  unsigned m_length;
103  unsigned m_refct;
105  u16 m_pcount;
106  // Metadata for user extensions (see comment above).
107  u32 m_user[SATCAT5_MBUFF_USER];
108 
109  // Explicitly declare default constructor and copy operators.
110  MultiPacket() = default;
111  MultiPacket(const MultiChunk& t) = delete;
112  MultiPacket& operator=(const MultiChunk& t) = delete;
113 
115  inline bool is_deleted() const
116  { return m_length && m_chunks.is_empty(); }
117 
120 
122  bool copy_to(satcat5::io::Writeable* wr) const;
123 
129  class Reader : public satcat5::io::Readable {
130  public:
132  explicit Reader(const satcat5::io::MultiPacket* pkt = 0);
133 
136  { return (MultiPacket*)m_read_pkt; }
137 
139  void read_reset(const satcat5::io::MultiPacket* pkt);
140 
141  // Implement the io::Readable API.
142  // (Inherits Doxygen comments from io_writeable.h.)
143  unsigned get_read_ready() const override;
144  bool read_bytes(unsigned nbytes, void* dst) override;
145  bool read_consume(unsigned nbytes) override;
146  void read_finalize() override;
147 
148  protected:
149  // Implement the io::Readable API.
150  u8 read_next() override;
151 
152  private:
155  unsigned m_read_pos;
156  unsigned m_read_rem;
160  };
161 
167  public:
169  explicit Overwriter(satcat5::io::MultiPacket* pkt);
170 
172  inline unsigned write_count() const {return m_write_tot;}
173 
174  // Implement the io::Writeable API.
175  // (Inherits Doxygen comments from io_writeable.h.)
176  unsigned get_write_space() const override;
177  void write_bytes(unsigned nbytes, const void* src) override;
178 
179  protected:
180  // Implement the io::Writeable API.
181  void write_next(u8 data) override;
182 
183  private:
186  unsigned m_write_pos;
187  unsigned m_write_rem;
188  unsigned m_write_tot;
191  };
192  };
193 
199  public:
201  MultiBuffer(u8* buff, unsigned nbytes);
202 
204  bool consistency() const;
205 
207  inline unsigned get_free_bytes() const
208  { return m_free_bytes; }
209 
211  inline u16 get_pcount()
212  { return m_pcount; }
213 
218  bool enqueue(satcat5::io::MultiPacket* packet);
219 
223 
224  protected:
227  void poll_demand() override;
228 
233  virtual unsigned deliver(satcat5::io::MultiPacket* packet);
234 
240 
241  // Internal state.
245  unsigned m_free_bytes;
246  u16 m_pcount;
251  };
252 
257  , public satcat5::poll::Timer
258  {
259  public:
272  virtual bool accept(satcat5::io::MultiPacket* packet);
273 
275  void flush();
276 
278  bool get_port_enable() const
279  { return m_port_enable; }
280 
283  void set_port_enable(bool enable)
284  { m_port_enable = enable; }
285 
290  inline void set_timeout(unsigned timeout_msec)
291  { m_read_timeout = timeout_msec; }
292 
293  // Override the basic read_finalize() behavior.
294  void read_finalize() override;
295 
296  protected:
298  explicit MultiReader(satcat5::io::MultiBuffer* src);
299  ~MultiReader() SATCAT5_OPTIONAL_DTOR;
300 
303  virtual bool pkt_push(satcat5::io::MultiPacket* packet) = 0;
304 
307  virtual satcat5::io::MultiPacket* pkt_pop() = 0;
308 
310  void pkt_init(satcat5::io::MultiPacket* packet);
311 
313  void pkt_free(satcat5::io::MultiPacket* packet);
314 
316  void timer_event() override;
317 
319  satcat5::io::MultiBuffer* const m_src;
320 
323  friend satcat5::util::ListCore;
324  satcat5::io::MultiReader* m_next;
326 
330  unsigned m_read_timeout;
332  };
333 
336  class MultiReaderSimple : public satcat5::io::MultiReader {
337  public:
340  ~MultiReaderSimple() SATCAT5_OPTIONAL_DTOR;
341 
343  inline bool can_accept() const
344  { return m_queue_count < SATCAT5_MBUFF_RXPKT; }
345 
346  protected:
349  bool pkt_push(satcat5::io::MultiPacket* pkt) override;
350  satcat5::io::MultiPacket* pkt_pop() override;
352 
353  private:
357  unsigned m_queue_rdidx;
358  unsigned m_queue_count;
359  satcat5::io::MultiPacket* m_queue[SATCAT5_MBUFF_RXPKT];
361  };
362 
366  public:
369  ~MultiReaderPriority() SATCAT5_OPTIONAL_DTOR;
370 
372  inline bool can_accept() const
373  { return m_heap_count < SATCAT5_MBUFF_RXPKT; }
374 
376  bool consistency() const;
377 
378  protected:
381  bool pkt_push(satcat5::io::MultiPacket* pkt) override;
382  satcat5::io::MultiPacket* pkt_pop() override;
384 
385  private:
387  u32 offset_priority(unsigned idx) const;
388 
390  unsigned swap_index(unsigned prev, unsigned next);
391 
395  unsigned m_heap_count;
396  satcat5::io::MultiPacket* m_heap[SATCAT5_MBUFF_RXPKT];
398  };
399 
403  : public satcat5::io::Writeable
404  , public satcat5::poll::Timer
405  {
406  public:
408  explicit MultiWriter(satcat5::io::MultiBuffer* dst);
409  ~MultiWriter() SATCAT5_OPTIONAL_DTOR;
410 
413  inline void set_max_packet(unsigned max_bytes)
414  { m_write_maxlen = max_bytes; }
415 
420  void set_priority(u16 priority);
421 
425  inline void set_timeout(unsigned timeout_msec)
426  { m_write_timeout = timeout_msec; }
427 
429  inline unsigned get_write_partial() const {return m_write_len;}
430 
431  // Implement the io::Writeable API.
432  // (Inherits Doxygen comments from io_writeable.h.)
433  unsigned get_write_space() const override;
434  void write_bytes(unsigned nbytes, const void* src) override;
435  void write_abort() override;
436  bool write_finalize() override;
437 
446  bool write_bypass(satcat5::io::MultiReader* dst);
447 
448  protected:
450  void timer_event() override;
451 
452  // Implement the io::Writeable API.
453  // (Inherits Doxygen comments from io_writeable.h.)
454  void write_next(u8 data) override;
455  void write_overflow() override;
456 
459  unsigned write_prep();
460 
462  satcat5::io::MultiPacket* prepare_pkt();
463 
466 
471  unsigned m_write_pos;
472  unsigned m_write_len;
473  unsigned m_write_maxlen;
474  unsigned m_write_timeout;
476  };
477 
482  public:
488  u16 priority = 0);
489 
491  bool write_finalize() override;
492 
493  protected:
494  satcat5::io::MultiReader* const m_dst;
495  u16 m_priority;
496  };
497  }
498 }
Ephemeral Readable interface for a simple array.
Definition: io_readable.h:206
A multi-source, multi-sink packet buffer.
Definition: multi_buffer.h:198
void free_packet(satcat5::io::MultiPacket *packet)
Immediately free memory associated with this packet.
satcat5::io::MultiPacket * new_packet()
Memory allocation.
u16 get_pcount()
Current value of the packet counter.
Definition: multi_buffer.h:211
satcat5::io::MultiChunk * new_chunk()
Memory allocation.
bool consistency() const
Internal consistency self-test (Optional).
MultiBuffer(u8 *buff, unsigned nbytes)
Configure this object and link to the working buffer.
void poll_demand() override
Deferred event handler, called after request().
virtual unsigned deliver(satcat5::io::MultiPacket *packet)
Deliver a complete packet to any number of output port(s).
satcat5::io::MultiPacket * dequeue()
Event handler for deferred packet delivery.
bool enqueue(satcat5::io::MultiPacket *packet)
Queue an incoming packet for deferred processing.
unsigned get_free_bytes() const
Query remaining buffer capacity.
Definition: multi_buffer.h:207
Barebones class for overwriting contents of a MultiPacket.
Definition: multi_buffer.h:166
void write_next(u8 data) override
Write the next byte to the underlying buffer or device.
satcat5::io::MultiChunk * m_write_chunk
Current write state.
Definition: multi_buffer.h:189
void write_bytes(unsigned nbytes, const void *src) override
Write 0 or more bytes from a buffer.
unsigned m_write_rem
Current write state.
Definition: multi_buffer.h:187
Overwriter(satcat5::io::MultiPacket *pkt)
Create a new Writer object.
unsigned write_count() const
Return total bytes written by this object.
Definition: multi_buffer.h:172
unsigned m_write_pos
Current write state.
Definition: multi_buffer.h:186
unsigned m_write_tot
Current write state.
Definition: multi_buffer.h:188
unsigned get_write_space() const override
How many bytes can be written without blocking?
Barebones class for reading data from a MultiPacket.
Definition: multi_buffer.h:129
unsigned m_read_pos
Current read state.
Definition: multi_buffer.h:155
unsigned get_read_ready() const override
How many bytes can be read without blocking?
Definition: multi_buffer.cc:63
satcat5::io::MultiChunk * m_read_chunk
Current read state.
Definition: multi_buffer.h:158
bool read_consume(unsigned nbytes) override
Read and discard 0 or more bytes.
Definition: multi_buffer.cc:88
Reader(const satcat5::io::MultiPacket *pkt=0)
Create a new Reader object.
Definition: multi_buffer.cc:41
u8 read_next() override
Read the next byte from the underlying buffer or device.
Definition: multi_buffer.cc:96
bool read_bytes(unsigned nbytes, void *dst) override
Read 0 or more bytes into a buffer.
Definition: multi_buffer.cc:68
void read_reset(const satcat5::io::MultiPacket *pkt)
Reset read state for the designated packet.
Definition: multi_buffer.cc:50
satcat5::io::MultiPacket * get_packet() const
Get a pointer to the current packet, if active.
Definition: multi_buffer.h:135
unsigned m_read_rem
Current read state.
Definition: multi_buffer.h:156
const satcat5::io::MultiPacket * m_read_pkt
Current read state.
Definition: multi_buffer.h:157
void read_finalize() override
Consume any remaining bytes in this frame, if applicable.
Definition: multi_buffer.cc:92
A port for reading from a MultiBuffer object.
Definition: multi_buffer.h:258
virtual bool accept(satcat5::io::MultiPacket *packet)
Accept a packet from the source buffer? Default accepts all packets unless this port is disabled or f...
bool m_port_enable
Internal state.
Definition: multi_buffer.h:329
void timer_event() override
Timeouts help prevent resource-hogging.
unsigned m_read_timeout
Internal state.
Definition: multi_buffer.h:330
void set_timeout(unsigned timeout_msec)
Update the watchdog timeout.
Definition: multi_buffer.h:290
void read_finalize() override
Consume any remaining bytes in this frame, if applicable.
satcat5::io::MultiBuffer *const m_src
Pointer to the source buffer.
Definition: multi_buffer.h:319
void set_port_enable(bool enable)
Enable or disable this port.
Definition: multi_buffer.h:283
void flush()
Discard all queued packets.
MultiReader(satcat5::io::MultiBuffer *src)
Constructor and destructor are only accessible to children.
bool get_port_enable() const
Is this port currently enabled?
Definition: multi_buffer.h:278
void pkt_init(satcat5::io::MultiPacket *packet)
Helper function for starting a new packet, or NULL to stop.
virtual satcat5::io::MultiPacket * pkt_pop()=0
Choose the next packet to start reading, or NULL to stop.
void pkt_free(satcat5::io::MultiPacket *packet)
Decrement reference count, free when it reaches zero.
virtual bool pkt_push(satcat5::io::MultiPacket *packet)=0
Push a packet onto the end of a queue or similar data structure.
A variant of MultiReader that follows priority ordering.
Definition: multi_buffer.h:365
unsigned m_heap_count
Binary heap sorted by increasing priority.
Definition: multi_buffer.h:395
bool can_accept() const
Can this object accept new packets? Required for testing.
Definition: multi_buffer.h:372
A variant of MultiReader with a simple first-in, first-out queue.
Definition: multi_buffer.h:336
unsigned m_queue_rdidx
Queue based on a circular buffer.
Definition: multi_buffer.h:357
unsigned m_queue_count
Queue based on a circular buffer.
Definition: multi_buffer.h:358
bool can_accept() const
Can this object accept new packets? Required for testing.
Definition: multi_buffer.h:343
MultiWriter adapter for bypass mode.
Definition: multi_buffer.h:481
A port for writing to a MultiBuffer object.
Definition: multi_buffer.h:405
void set_timeout(unsigned timeout_msec)
Update the watchdog timeout.
Definition: multi_buffer.h:425
unsigned m_write_pos
Current write state.
Definition: multi_buffer.h:471
satcat5::io::MultiBuffer *const m_dst
Pointer to the destination buffer.
Definition: multi_buffer.h:465
unsigned get_write_partial() const
Get current write length.
Definition: multi_buffer.h:429
satcat5::io::MultiChunk * m_write_tail
Current write state.
Definition: multi_buffer.h:470
unsigned m_write_maxlen
Current write state.
Definition: multi_buffer.h:473
satcat5::io::MultiPacket * m_write_pkt
Current write state.
Definition: multi_buffer.h:469
unsigned m_write_timeout
Current write state.
Definition: multi_buffer.h:474
unsigned m_write_len
Current write state.
Definition: multi_buffer.h:472
void set_max_packet(unsigned max_bytes)
Update the maximum allowed packet length.
Definition: multi_buffer.h:413
Abstract API for reading byte-streams and packets.
Definition: io_readable.h:68
Abstract API for writing byte-streams and packets.
Definition: io_writeable.h:24
An "OnDemand" object is polled only on request.
Definition: polling.h:131
Timer objects are polled after a fixed delay or at a regular interval.
Definition: polling.h:213
Helper functions for manipulating singly-linked lists.
Definition: list.h:52
bool is_empty() const
Is this list empty?
Definition: list.h:253
"Readable" I/O interface core definitions
"Writeable" I/O interface core definitions
Templated functions for manipulating singly-linked lists.
Data-structure representing a single fine-grained memory block.
Definition: multi_buffer.h:75
A packet is a linked-list of memory blocks, plus metadata.
Definition: multi_buffer.h:91
unsigned m_length
Packet length in bytes.
Definition: multi_buffer.h:102
u16 m_priority
Packet priority.
Definition: multi_buffer.h:104
u16 m_pcount
Packet counter.
Definition: multi_buffer.h:105
u32 m_user[SATCAT5_MBUFF_USER]
Packet metadata.
Definition: multi_buffer.h:107
bool is_deleted() const
Has this packet been deleted?
Definition: multi_buffer.h:115
bool copy_to(satcat5::io::Writeable *wr) const
Copy the packet contents to the specified destination.
Definition: multi_buffer.cc:36
unsigned m_refct
Reference counter.
Definition: multi_buffer.h:103
satcat5::io::ArrayRead peek() const
Peek at the first chunk, up to SATCAT5_MBUFF_CHUNK bytes.
Definition: multi_buffer.cc:31
Basic type aliases and prototypes used throughout SatCat5.