SatCat5
io_writeable.cc
1 // Copyright 2023-2025 The Aerospace Corporation.
3 // This file is a part of SatCat5, licensed under CERN-OHL-W v2 or later.
5 
6 #include <cstring>
7 #include <satcat5/io_writeable.h>
8 #include <satcat5/utils.h>
9 
16 
17 // Global instance of the basic NullWrite object.
19 
20 void Writeable::write_u8(u8 data) {
21  if (get_write_space() >= 1) {
22  write_next(data);
23  } else {write_overflow();}
24 }
25 
26 // Make sure Doxygen ignores all write_ functions for scalars except write_u8().
28 void Writeable::write_u16(u16 data) {
29  if (get_write_space() >= 2) {
30  write_next((u8)(data >> 8)); // Big-endian
31  write_next((u8)(data >> 0));
32  } else {write_overflow();}
33 }
34 
35 void Writeable::write_u24(u32 data) {
36  if (get_write_space() >= 3) {
37  write_next((u8)(data >> 16)); // Big-endian
38  write_next((u8)(data >> 8));
39  write_next((u8)(data >> 0));
40  } else {write_overflow();}
41 }
42 
43 void Writeable::write_u32(u32 data) {
44  if (get_write_space() >= 4) {
45  write_next((u8)(data >> 24)); // Big-endian
46  write_next((u8)(data >> 16));
47  write_next((u8)(data >> 8));
48  write_next((u8)(data >> 0));
49  } else {write_overflow();}
50 }
51 
52 void Writeable::write_u48(u64 data) {
53  if (get_write_space() >= 6) {
54  write_next((u8)(data >> 40)); // Big-endian
55  write_next((u8)(data >> 32));
56  write_next((u8)(data >> 24));
57  write_next((u8)(data >> 16));
58  write_next((u8)(data >> 8));
59  write_next((u8)(data >> 0));
60  } else {write_overflow();}
61 }
62 
63 void Writeable::write_u64(u64 data) {
64  if (get_write_space() >= 8) {
65  write_next((u8)(data >> 56)); // Big-endian
66  write_next((u8)(data >> 48));
67  write_next((u8)(data >> 40));
68  write_next((u8)(data >> 32));
69  write_next((u8)(data >> 24));
70  write_next((u8)(data >> 16));
71  write_next((u8)(data >> 8));
72  write_next((u8)(data >> 0));
73  } else {write_overflow();}
74 }
75 
76 void Writeable::write_u16l(u16 data) {
77  if (get_write_space() >= 2) {
78  write_next((u8)(data >> 0)); // Little-endian
79  write_next((u8)(data >> 8));
80  } else {write_overflow();}
81 }
82 
83 void Writeable::write_u24l(u32 data) {
84  if (get_write_space() >= 3) {
85  write_next((u8)(data >> 0)); // Little-endian
86  write_next((u8)(data >> 8));
87  write_next((u8)(data >> 16));
88  } else {write_overflow();}
89 }
90 
91 void Writeable::write_u32l(u32 data) {
92  if (get_write_space() >= 4) {
93  write_next((u8)(data >> 0)); // Little-endian
94  write_next((u8)(data >> 8));
95  write_next((u8)(data >> 16));
96  write_next((u8)(data >> 24));
97  } else {write_overflow();}
98 }
99 
100 void Writeable::write_u48l(u64 data) {
101  if (get_write_space() >= 6) {
102  write_next((u8)(data >> 0)); // Little-endian
103  write_next((u8)(data >> 8));
104  write_next((u8)(data >> 16));
105  write_next((u8)(data >> 24));
106  write_next((u8)(data >> 32));
107  write_next((u8)(data >> 40));
108  } else {write_overflow();}
109 }
110 
111 void Writeable::write_u64l(u64 data) {
112  if (get_write_space() >= 8) {
113  write_next((u8)(data >> 0)); // Little-endian
114  write_next((u8)(data >> 8));
115  write_next((u8)(data >> 16));
116  write_next((u8)(data >> 24));
117  write_next((u8)(data >> 32));
118  write_next((u8)(data >> 40));
119  write_next((u8)(data >> 48));
120  write_next((u8)(data >> 56));
121  } else {write_overflow();}
122 }
123 
124 void Writeable::write_s8(s8 data)
125  { write_u8(reinterpret<s8,u8>(data)); }
126 
127 void Writeable::write_s16(s16 data)
128  { write_u16(reinterpret<s16,u16>(data)); }
129 
130 void Writeable::write_s24(s32 data)
131  { write_u24(reinterpret<s32,u32>(data)); }
132 
133 void Writeable::write_s32(s32 data)
134  { write_u32(reinterpret<s32,u32>(data)); }
135 
136 void Writeable::write_s48(s64 data)
137  { write_u48(reinterpret<s64,u64>(data)); }
138 
139 void Writeable::write_s64(s64 data)
140  { write_u64(reinterpret<s64,u64>(data)); }
141 
142 void Writeable::write_f32(float data)
143  { write_u32(reinterpret<float,u32>(data)); }
144 
145 void Writeable::write_f64(double data)
146  { write_u64(reinterpret<double,u64>(data)); }
147 
148 void Writeable::write_s16l(s16 data)
149  { write_u16l(reinterpret<s16,u16>(data)); }
150 
151 void Writeable::write_s24l(s32 data)
152  { write_u24l(reinterpret<s32,u32>(data)); }
153 
154 void Writeable::write_s32l(s32 data)
155  { write_u32l(reinterpret<s32,u32>(data)); }
156 
157 void Writeable::write_s48l(s64 data)
158  { write_u48l(reinterpret<s64,u64>(data)); }
159 
160 void Writeable::write_s64l(s64 data)
161  { write_u64l(reinterpret<s64,u64>(data)); }
162 
163 void Writeable::write_f32l(float data)
164  { write_u32l(reinterpret<float,u32>(data)); }
165 
166 void Writeable::write_f64l(double data)
167  { write_u64l(reinterpret<double,u64>(data)); }
169 
170 void Writeable::write_bytes(unsigned nbytes, const void* src) {
171  const u8* src8 = reinterpret_cast<const u8*>(src);
172  if (get_write_space() >= nbytes) {
173  while (nbytes) {
174  write_next(*src8);
175  src8++; nbytes--;
176  }
177  } else {write_overflow();}
178 }
179 
180 void Writeable::write_str(const char* str) {
181  unsigned nbytes = strlen(str); // Do not include null-termination
182  write_bytes(nbytes, str);
183 }
184 
185 bool Writeable::write_finalize() {return true;}
188 
189 unsigned ArrayWrite::get_write_space() const {
190  return m_len - m_wridx; // Remaining space in array
191 }
192 
194  m_ovr = false; // Clear overflow flag
195  m_wrlen = 0; // Clear prior contents
196  m_wridx = 0; // Restart at beginning
197 }
198 
200  bool ok = !m_ovr; // Fail on overflow
201  m_ovr = false; // Clear overflow flag
202  m_wrlen = ok ? m_wridx : 0; // Note current length
203  m_wridx = 0; // Next write wraps to start
204  return ok;
205 }
206 
208  m_ovr = true;
209 }
210 
211 void ArrayWrite::write_next(u8 data) {
212  m_wrlen = 0; // Clear prior contents
213  m_dst[m_wridx++] = data; // Write the new byte
214 }
215 
217  return satcat5::util::min_unsigned(m_rem, m_dst->get_write_space());
218 }
219 
220 void LimitedWrite::write_bytes(unsigned nbytes, const void* src) {
221  if (get_write_space() >= nbytes) {
222  m_dst->write_bytes(nbytes, src);
223  m_rem -= nbytes;
224  } else {write_overflow();}
225 }
226 
228  m_dst->write_next(data);
229  --m_rem;
230 }
231 
232 // The WriteableRedirect class is all one-liners that could all be defined
233 // in the .h file. However, this leads to duplication of the underlying
234 // function (inline, direct, and virtual methods) that complicate testing.
235 // Defining these micro-functions here prevents such undesired changes.
237  { return m_dst ? m_dst->get_write_space() : 0; }
238 
240  { if (m_dst) m_dst->write_abort(); }
241 
242 void WriteableRedirect::write_bytes(unsigned nbytes, const void* src)
243  { if (m_dst) m_dst->write_bytes(nbytes, src); }
244 
246  { return m_dst && m_dst->write_finalize(); }
247 
249  { m_dst->write_next(data); } // Unreachable if m_dst is null.
250 
252  { if (m_dst) m_dst->write_overflow(); }
253 
254 // NullWrite functions simply discard their inputs.
256  { return m_write_space; }
257 
258 void NullWrite::write_bytes(unsigned nbytes, const void* src)
259  {} // Do nothing, all incoming data is discarded.
260 
262  {} // Do nothing, all incoming data is discarded.
Ephemeral Writeable interface for a simple array.
Definition: io_writeable.h:127
bool write_finalize() override
Mark end of frame and release temporary working data.
void write_abort() override
If possible, abort the current partially-written packet.
void write_overflow() override
Optional error handling for write overflow.
void write_next(u8 data) override
Write the next byte to the underlying buffer or device.
unsigned get_write_space() const override
How many bytes can be written without blocking?
Limited write up to N bytes.
Definition: io_writeable.h:183
void write_next(u8 data) override
Write the next byte to the underlying buffer or device.
void write_bytes(unsigned nbytes, const void *src) override
Write 0 or more bytes from a buffer.
unsigned get_write_space() const override
How many bytes can be written without blocking?
Writeable object that accepts and discards all incoming data.
Definition: io_writeable.h:236
unsigned get_write_space() const override
How many bytes can be written without blocking?
void write_next(u8 data) override
Write the next byte to the underlying buffer or device.
void write_bytes(unsigned nbytes, const void *src) override
Write 0 or more bytes from a buffer.
Abstract API for writing byte-streams and packets.
Definition: io_writeable.h:24
virtual unsigned get_write_space() const =0
How many bytes can be written without blocking?
virtual void write_bytes(unsigned nbytes, const void *src)
Write 0 or more bytes from a buffer.
virtual void write_abort()
If possible, abort the current partially-written packet.
void write_u8(u8 data)
One of many functions for writing integer/floating point values, see details.
Definition: io_writeable.cc:20
virtual void write_overflow()
Optional error handling for write overflow.
void write_str(const char *str)
Write the contents of a null-terminated string.
virtual void write_next(u8 data)=0
Write the next byte to the underlying buffer or device.
virtual bool write_finalize()
Mark end of frame and release temporary working data.
Wrapper class for forwarding writes to another object.
Definition: io_writeable.h:218
void write_next(u8 data) override
Write the next byte to the underlying buffer or device.
unsigned get_write_space() const override
How many bytes can be written without blocking?
void write_overflow() override
Optional error handling for write overflow.
bool write_finalize() override
Mark end of frame and release temporary working data.
void write_bytes(unsigned nbytes, const void *src) override
Write 0 or more bytes from a buffer.
void write_abort() override
If possible, abort the current partially-written packet.
"Writeable" I/O interface core definitions
satcat5::io::NullWrite null_write
Global instance of the basic NullWrite object.
Miscellaneous mathematical utility functions.
T2 reinterpret(T1 x)
In-place byte-for-byte format conversion, aka "type-punning".
Definition: utils.h:414