18#ifndef M5_UNIT_RS485_RS485_COMPONENT_HPP
19#define M5_UNIT_RS485_RS485_COMPONENT_HPP
21#include <M5UnitComponent.hpp>
22#include <m5_utility/stl/byteswap.hpp>
23#include <m5_utility/stl/endianness.hpp>
41 virtual ~ISerial() =
default;
42 virtual int available() = 0;
43 virtual int availableForWrite() = 0;
44 virtual int peek() = 0;
45 virtual int read() = 0;
46 virtual size_t read(uint8_t *buf,
const size_t len) = 0;
47 virtual size_t readBytes(uint8_t *buf,
const size_t len) = 0;
48 virtual void flush() = 0;
49 virtual void flush(
const bool txOnly) = 0;
50 virtual size_t write(
const uint8_t *buf,
const size_t len) = 0;
51 virtual size_t write(uint8_t b) = 0;
52 virtual uint32_t baudRate()
const = 0;
63 virtual bool begin()
override;
97 inline operator bool()
const
99 return isRegistered();
107 return _serial->available();
115 return _serial->availableForWrite();
123 return _serial->peek();
131 return _serial->read();
139 inline size_t read(uint8_t *buffer,
const size_t size)
141 return _serial->read(buffer, size);
149 inline size_t read(
char *buffer,
const size_t size)
151 return read(
reinterpret_cast<uint8_t *
>(buffer), size);
161 return _serial->readBytes(buffer, length);
169 inline size_t readBytes(
char *buffer,
const size_t length)
171 return readBytes(
reinterpret_cast<uint8_t *
>(buffer), length);
184 inline void flush(
const bool txOnly)
186 _serial->flush(txOnly);
194 size_t write(
const uint8_t d,
const bool flush =
true);
202 size_t write(
const uint8_t *buffer,
const size_t size,
const bool flush =
true);
210 size_t write(
const char *buffer,
const size_t size,
const bool flush =
true);
217 size_t write(
const char *s,
const bool flush =
true);
235 template <
typename T,
bool LittleEndian = true>
238 static_assert(std::is_trivially_copyable<T>::value && std::is_standard_layout<T>::value,
239 "readValue requires trivially copyable, standard-layout types only");
241 uint8_t buf[
sizeof(T)]{};
242 size_t got = _serial->readBytes(buf,
sizeof(T));
243 if (got !=
sizeof(T)) {
246 std::memcpy(&value, buf,
sizeof(T));
247 if (LittleEndian != m5::endian::little) {
248 value = byteswap_if_needed(value);
265 template <
typename T,
bool LittleEndian = true>
268 static_assert(std::is_trivially_copyable<T>::value && std::is_standard_layout<T>::value,
269 "writeValue requires trivially copyable, standard-layout types only");
271 if (LittleEndian != m5::endian::little) {
272 tmp = byteswap_if_needed(tmp);
274 uint8_t buf[
sizeof(T)]{};
275 std::memcpy(buf, &tmp,
sizeof(T));
276 return write(buf,
sizeof(T),
true) ==
sizeof(T);
284 inline ISerial *iserial()
286 return _serial.get();
298 virtual std::unique_ptr<ISerial>
make_serial(AdapterUART *ad);
308 template <
typename T>
311 typename std::conditional<std::is_integral<T>::value || std::is_enum<T>::value,
byteswap_int_tag,
316 template <
typename T>
317 static T byteswap_if_needed(T v)
319 return byteswap_if_needed_impl(v,
typename byteswap_tag_of<T>::type{});
323 template <
typename T>
324 static T byteswap_if_needed_impl(T v, byteswap_int_tag)
326 return m5::stl::byteswap(v);
330 template <
typename T>
331 static T byteswap_if_needed_impl(T v, byteswap_float_tag)
333 static_assert(
sizeof(T) == 4 ||
sizeof(T) == 8,
334 "byteswap_if_needed: only 32-bit / 64-bit floating-point supported");
335 typename std::conditional<
sizeof(T) == 4, uint32_t, uint64_t>::type u{};
336 std::memcpy(&u, &v,
sizeof(T));
337 u = m5::stl::byteswap(u);
339 std::memcpy(&out, &u,
sizeof(T));
344 template <
typename T>
345 static T byteswap_if_needed_impl(T v, byteswap_none_tag)
350 std::unique_ptr<ISerial> _serial{};
Non-instantiable base class for RS-485 transceiver units.
Definition rs485_component.hpp:37
int available()
Returns the number of available bytes to read.
Definition rs485_component.hpp:105
size_t readBytes(uint8_t *buffer, const size_t length)
Reads bytes with timeout defined by underlying Serial.
Definition rs485_component.hpp:159
virtual ~RS485Component()=default
Destructor.
size_t read(uint8_t *buffer, const size_t size)
Reads up to size bytes into buffer.
Definition rs485_component.hpp:139
bool readValue(T &value)
Read a trivially copyable value.
Definition rs485_component.hpp:236
int peek()
Peeks the next incoming byte without removing it.
Definition rs485_component.hpp:121
bool writeValue(const T value)
Write a trivially copyable value.
Definition rs485_component.hpp:266
size_t readBytes(char *buffer, const size_t length)
Reads bytes with timeout defined by underlying Serial.
Definition rs485_component.hpp:169
int read()
Reads one byte.
Definition rs485_component.hpp:129
virtual bool begin() override
Begin using the registered UART adapter.
Definition rs485_component.cpp:142
size_t read(char *buffer, const size_t size)
Reads up to size bytes into buffer.
Definition rs485_component.hpp:149
void flush()
Flushes the serial port.
Definition rs485_component.hpp:176
int availableForWrite()
Returns the number of bytes that can be written without blocking.
Definition rs485_component.hpp:113
void config(const config_t &cfg)
Sets the configuration.
Definition rs485_component.hpp:87
size_t write(const uint8_t d, const bool flush=true)
Writes one byte.
Definition rs485_component.cpp:169
void flush(const bool txOnly)
Flushes the serial port.
Definition rs485_component.hpp:184
config_t config()
Gets the configuration.
Definition rs485_component.hpp:79
virtual std::unique_ptr< ISerial > make_serial(AdapterUART *ad)
Factory hook: build the concrete ISerial to be used by begin().
Definition rs485_component.cpp:131
Top level namespace of M5Stack.
Definition rs485_component.hpp:303
Definition rs485_component.hpp:301
Definition rs485_component.hpp:305
Definition rs485_component.hpp:309
Settings for begin.
Definition rs485_component.hpp:69
bool flushRX
Flush RX buffer on begin?
Definition rs485_component.hpp:70