distortos  v0.5.0
object-oriented C++ RTOS for microcontrollers
SerialPort.hpp
Go to the documentation of this file.
1 
12 #ifndef INCLUDE_DISTORTOS_DEVICES_COMMUNICATION_SERIALPORT_HPP_
13 #define INCLUDE_DISTORTOS_DEVICES_COMMUNICATION_SERIALPORT_HPP_
14 
17 
18 #include "distortos/Mutex.hpp"
19 
20 namespace distortos
21 {
22 
23 class Semaphore;
24 
25 namespace devices
26 {
27 
28 class UartLowLevel;
29 
36 class SerialPort : private UartBase
37 {
38 public:
39 
49  {
50  public:
51 
59  constexpr CircularBuffer(void* const buffer, const size_t size) :
60  buffer_{static_cast<uint8_t*>(buffer)},
61  size_{size & sizeMask_},
62  readPosition_{},
64  {
65 
66  }
67 
75  constexpr CircularBuffer(const void* const buffer, const size_t size) :
76  buffer_{static_cast<uint8_t*>(const_cast<void*>(buffer))},
77  size_{(size & sizeMask_) | readOnlyMask_},
78  readPosition_{},
80  {
81 
82  }
83 
88  void clear()
89  {
90  readPosition_ = {};
91  writePosition_ = {};
92  }
93 
98  size_t getCapacity() const
99  {
100  return size_ & sizeMask_;
101  }
102 
107  std::pair<const uint8_t*, size_t> getReadBlock() const;
108 
113  size_t getSize() const
114  {
115  const auto readPosition = readPosition_ ;
116  const auto writePosition = writePosition_;
117  if (isEmpty(readPosition, writePosition) == true)
118  return 0;
119  const auto capacity = getCapacity();
120  if (isFull(readPosition, writePosition) == true)
121  return capacity;
122  return (capacity - (readPosition & positionMask_) + (writePosition & positionMask_)) % capacity;
123  }
124 
129  std::pair<uint8_t*, size_t> getWriteBlock() const;
130 
138  void increaseReadPosition(const size_t value)
139  {
141  }
142 
150  void increaseWritePosition(const size_t value)
151  {
153  }
154 
159  bool isEmpty() const
160  {
162  }
163 
168  bool isFull() const
169  {
171  }
172 
177  bool isReadOnly() const
178  {
179  return (size_ & readOnlyMask_) != 0;
180  }
181 
182  private:
183 
196  std::pair<uint8_t*, size_t> getBlock(const size_t begin, const size_t end) const
197  {
198  const auto maskedBegin = begin & positionMask_;
199  const auto maskedEnd = end & positionMask_;
200  return {buffer_ + maskedBegin, (maskedEnd > maskedBegin ? maskedEnd : getCapacity()) - maskedBegin};
201  }
202 
213  size_t increasePosition(const size_t position, const size_t value)
214  {
215  const auto maskedPosition = position & positionMask_;
216  const auto msb = position & msbMask_;
217  // in case of wrap-around MSB is inverted and position is 0
218  return maskedPosition + value != getCapacity() ? msb | (maskedPosition + value) : msb ^ msbMask_;
219  }
220 
232  constexpr static bool isEmpty(const size_t readPosition, const size_t writePosition)
233  {
234  return readPosition == writePosition;
235  }
236 
248  constexpr static bool isFull(const size_t readPosition, const size_t writePosition)
249  {
250  return (readPosition ^ writePosition) == msbMask_;
251  }
252 
254  constexpr static size_t positionMask_ {SIZE_MAX >> 1};
255 
257  constexpr static size_t msbMask_ {~positionMask_};
258 
260  constexpr static size_t sizeMask_ {SIZE_MAX >> 1};
261 
263  constexpr static size_t readOnlyMask_ {~sizeMask_};
264 
266  uint8_t* buffer_;
267 
269  size_t size_;
270 
272  volatile size_t readPosition_;
273 
275  volatile size_t writePosition_;
276  };
277 
290  constexpr SerialPort(UartLowLevel& uart, void* const readBuffer, const size_t readBufferSize,
291  void* const writeBuffer, const size_t writeBufferSize) :
293  writeMutex_{Mutex::Type::normal, Mutex::Protocol::priorityInheritance},
294  readBuffer_{readBuffer, (readBufferSize / 2) * 2},
295  writeBuffer_{writeBuffer, (writeBufferSize / 2) * 2},
298  nextReadBuffer_{},
300  readSemaphore_{},
302  writeSemaphore_{},
303  readLimit_{},
304  writeLimit_{},
305  uart_{uart},
306  baudRate_{},
308  parity_{},
309  _2StopBits_{},
310  openCount_{},
311  readInProgress_{},
314  {
315 
316  }
317 
326  ~SerialPort() override;
327 
345  int close();
346 
368  int open(uint32_t baudRate, uint8_t characterLength, devices::UartParity parity, bool _2StopBits);
369 
400  std::pair<int, size_t> read(void* buffer, size_t size, size_t minSize = 1,
401  const TickClock::time_point* timePoint = nullptr);
402 
424  std::pair<int, size_t> tryReadFor(const TickClock::duration duration, void* const buffer, const size_t size,
425  const size_t minSize = 1)
426  {
427  return tryReadUntil(TickClock::now() + duration, buffer, size, minSize);
428  }
429 
456  template<typename Rep, typename Period>
457  std::pair<int, size_t> tryReadFor(const std::chrono::duration<Rep, Period> duration, void* const buffer,
458  const size_t size, const size_t minSize = 1)
459  {
460  return tryReadFor(std::chrono::duration_cast<TickClock::duration>(duration), buffer, size, minSize);
461  }
462 
484  std::pair<int, size_t> tryReadUntil(const TickClock::time_point timePoint, void* const buffer, const size_t size,
485  const size_t minSize = 1)
486  {
487  return read(buffer, size, minSize, &timePoint);
488  }
489 
515  template<typename Duration>
516  std::pair<int, size_t> tryReadUntil(const std::chrono::time_point<TickClock, Duration> timePoint,
517  void* const buffer, const size_t size, const size_t minSize = 1)
518  {
519  return tryReadUntil(std::chrono::time_point_cast<TickClock::duration>(timePoint), buffer, size, minSize);
520  }
521 
543  std::pair<int, size_t> tryWriteFor(const TickClock::duration duration, const void* const buffer, const size_t size,
544  const size_t minSize = SIZE_MAX)
545  {
546  return tryWriteUntil(TickClock::now() + duration, buffer, size, minSize);
547  }
548 
575  template<typename Rep, typename Period>
576  std::pair<int, size_t> tryWriteFor(const std::chrono::duration<Rep, Period> duration, const void* const buffer,
577  const size_t size, const size_t minSize = SIZE_MAX)
578  {
579  return tryWriteFor(std::chrono::duration_cast<TickClock::duration>(duration), buffer, size, minSize);
580  }
581 
603  std::pair<int, size_t> tryWriteUntil(const TickClock::time_point timePoint, const void* const buffer,
604  const size_t size, const size_t minSize = SIZE_MAX)
605  {
606  return write(buffer, size, minSize, &timePoint);
607  }
608 
632  template<typename Duration>
633  std::pair<int, size_t> tryWriteUntil(const std::chrono::time_point<TickClock, Duration> timePoint,
634  const void* const buffer, const size_t size, const size_t minSize = SIZE_MAX)
635  {
636  return tryWriteUntil(std::chrono::time_point_cast<TickClock::duration>(timePoint), buffer, size, minSize);
637  }
638 
669  std::pair<int, size_t> write(const void* buffer, size_t size, size_t minSize = SIZE_MAX,
670  const TickClock::time_point* timePoint = nullptr);
671 
672 protected:
673 
689  void readCompleteEvent(size_t bytesRead) override;
690 
702  void receiveErrorEvent(ErrorSet errorSet) override;
703 
712  void transmitCompleteEvent() override;
713 
722  void transmitStartEvent() override;
723 
740  void writeCompleteEvent(size_t bytesWritten) override;
741 
742 private:
743 
754 
769  int readImplementation(CircularBuffer& buffer, size_t minSize, const TickClock::time_point* timePoint);
770 
783  int startReadWrapper();
784 
797  int startWriteWrapper();
798 
808  size_t stopReadWrapper();
809 
819  size_t stopWriteWrapper();
820 
835  int writeImplementation(CircularBuffer& buffer, size_t minSize, const TickClock::time_point* timePoint);
836 
847 
850 
853 
856 
859 
862 
865 
868 
871 
874 
877 
880 
882  volatile size_t readLimit_;
883 
885  volatile size_t writeLimit_;
886 
889 
891  uint32_t baudRate_;
892 
895 
898 
901 
903  uint8_t openCount_;
904 
906  volatile bool readInProgress_;
907 
909  volatile bool transmitInProgress_;
910 
912  volatile bool writeInProgress_;
913 };
914 
915 } // namespace devices
916 
917 } // namespace distortos
918 
919 #endif // INCLUDE_DISTORTOS_DEVICES_COMMUNICATION_SERIALPORT_HPP_
bool isReadOnly() const
Definition: SerialPort.hpp:177
std::pair< int, size_t > tryReadUntil(const TickClock::time_point timePoint, void *const buffer, const size_t size, const size_t minSize=1)
Wrapper for read() with absolute timeout.
Definition: SerialPort.hpp:484
priority inheritance protocol, similar to PTHREAD_PRIO_INHERIT
uint8_t characterLength_
current character length, bits
Definition: SerialPort.hpp:894
normal mutex, similar to PTHREAD_MUTEX_NORMAL
std::pair< int, size_t > write(const void *buffer, size_t size, size_t minSize=SIZE_MAX, const TickClock::time_point *timePoint=nullptr)
Writes data to SerialPort.
Definition: SerialPort.cpp:244
std::pair< int, size_t > tryWriteUntil(const TickClock::time_point timePoint, const void *const buffer, const size_t size, const size_t minSize=SIZE_MAX)
Wrapper for write() with absolute timeout.
Definition: SerialPort.hpp:603
std::pair< const uint8_t *, size_t > getReadBlock() const
Definition: SerialPort.cpp:70
Semaphore is the basic synchronization primitive.
Definition: Semaphore.hpp:30
void increaseReadPosition(const size_t value)
Increases read position by given value.
Definition: SerialPort.hpp:138
Mutex readMutex_
mutex used to serialize access to read(), close() and open()
Definition: SerialPort.hpp:849
static constexpr size_t positionMask_
bitmask used to extract position from readPosition_ or writePosition_
Definition: SerialPort.hpp:254
CircularBuffer *volatile nextWriteBuffer_
pointer to nest circular buffer for write operations, used when currentWriteBuffer_ becomes empty ...
Definition: SerialPort.hpp:870
Mutex writeMutex_
mutex used to serialize access to write(), close() and open()
Definition: SerialPort.hpp:852
int startReadWrapper()
Wrapper for UartLowLevel::startRead()
Definition: SerialPort.cpp:455
static constexpr size_t msbMask_
bitmask used to extract MSB from readPosition_ or writePosition_
Definition: SerialPort.hpp:257
std::pair< uint8_t *, size_t > getWriteBlock() const
Definition: SerialPort.cpp:79
Semaphore *volatile readSemaphore_
pointer to semaphore used for "read complete" event notifications
Definition: SerialPort.hpp:873
uint8_t openCount_
number of times this device was opened but not yet closed
Definition: SerialPort.hpp:903
size_t increasePosition(const size_t position, const size_t value)
Increases given position by given value.
Definition: SerialPort.hpp:213
bool _2StopBits_
current configuration of stop bits: 1 (false) or 2 (true)
Definition: SerialPort.hpp:900
static constexpr bool isEmpty(const size_t readPosition, const size_t writePosition)
Tests for empty circular buffer.
Definition: SerialPort.hpp:232
std::pair< int, size_t > read(void *buffer, size_t size, size_t minSize=1, const TickClock::time_point *timePoint=nullptr)
Reads data from SerialPort.
Definition: SerialPort.cpp:212
volatile bool readInProgress_
"read in progress" flag
Definition: SerialPort.hpp:906
Semaphore *volatile transmitSemaphore_
pointer to semaphore used for "transmit complete" event notifications
Definition: SerialPort.hpp:876
size_t size_
size of buffer_, bytes
Definition: SerialPort.hpp:269
UartLowLevel & uart_
reference to low-level implementation of UartLowLevel interface
Definition: SerialPort.hpp:888
void clear()
Clears circular buffer.
Definition: SerialPort.hpp:88
volatile size_t readLimit_
size limit of read operations, 0 if no limiting is needed, bytes
Definition: SerialPort.hpp:882
int writeImplementation(CircularBuffer &buffer, size_t minSize, const TickClock::time_point *timePoint)
Implementation of basic write() functionality.
Definition: SerialPort.cpp:513
static constexpr size_t readOnlyMask_
bitmask used to extract "read-only" flag from size_
Definition: SerialPort.hpp:263
std::chrono::time_point< TickClock > time_point
basic time_point type of clock
Definition: TickClock.hpp:42
int close()
Closes SerialPort.
Definition: SerialPort.cpp:116
int readFromCircularBufferAndStartRead(CircularBuffer &buffer)
Reads data from circular buffer and calls startReadWrapper().
Definition: SerialPort.cpp:367
Semaphore *volatile writeSemaphore_
pointer to semaphore used for "write complete" event notifications
Definition: SerialPort.hpp:879
std::pair< int, size_t > tryReadFor(const TickClock::duration duration, void *const buffer, const size_t size, const size_t minSize=1)
Wrapper for read() with relative timeout.
Definition: SerialPort.hpp:424
CircularBuffer *volatile currentReadBuffer_
pointer to current circular buffer for read operations, always valid
Definition: SerialPort.hpp:861
size_t getSize() const
Definition: SerialPort.hpp:113
volatile size_t writeLimit_
size limit of write operations, 0 if no limiting is needed, bytes
Definition: SerialPort.hpp:885
void increaseWritePosition(const size_t value)
Increases write position by given value.
Definition: SerialPort.hpp:150
Mutex class header.
static time_point now()
Definition: TickClock.cpp:20
constexpr SerialPort(UartLowLevel &uart, void *const readBuffer, const size_t readBufferSize, void *const writeBuffer, const size_t writeBufferSize)
SerialPort&#39;s constructor.
Definition: SerialPort.hpp:290
static constexpr size_t sizeMask_
bitmask used to extract size from size_
Definition: SerialPort.hpp:260
int readImplementation(CircularBuffer &buffer, size_t minSize, const TickClock::time_point *timePoint)
Implementation of basic read() functionality.
Definition: SerialPort.cpp:379
Definition: UartBase.hpp:30
devices::UartParity parity_
current parity
Definition: SerialPort.hpp:897
size_t stopReadWrapper()
Wrapper for UartLowLevel::stopRead()
Definition: SerialPort.cpp:493
void readCompleteEvent(size_t bytesRead) override
"Read complete" event
Definition: SerialPort.cpp:281
Top-level namespace of distortos project.
std::pair< int, size_t > tryReadUntil(const std::chrono::time_point< TickClock, Duration > timePoint, void *const buffer, const size_t size, const size_t minSize=1)
Wrapper for read() with absolute timeout.
Definition: SerialPort.hpp:516
Mutex is the basic synchronization primitive.
Definition: Mutex.hpp:30
UartParity
Definition: UartParity.hpp:29
std::pair< int, size_t > tryWriteFor(const std::chrono::duration< Rep, Period > duration, const void *const buffer, const size_t size, const size_t minSize=SIZE_MAX)
Wrapper for write() with relative timeout.
Definition: SerialPort.hpp:576
std::pair< uint8_t *, size_t > getBlock(const size_t begin, const size_t end) const
Gets first contiguous block between position1 and position2.
Definition: SerialPort.hpp:196
constexpr CircularBuffer(void *const buffer, const size_t size)
CircularBuffer&#39;s constructor.
Definition: SerialPort.hpp:59
Definition: SerialPort.hpp:36
Definition: UartLowLevel.hpp:35
~SerialPort() override
SerialPort&#39;s destructor.
Definition: SerialPort.cpp:95
UartParity enum class header.
bool isEmpty() const
Definition: SerialPort.hpp:159
bool isFull() const
Definition: SerialPort.hpp:168
volatile bool transmitInProgress_
"transmit in progress" flag
Definition: SerialPort.hpp:909
CircularBuffer writeBuffer_
internal instance of circular buffer for write operations
Definition: SerialPort.hpp:858
CircularBuffer *volatile currentWriteBuffer_
pointer to current circular buffer for write operations, always valid
Definition: SerialPort.hpp:864
int startWriteWrapper()
Wrapper for UartLowLevel::startWrite()
Definition: SerialPort.cpp:474
volatile bool writeInProgress_
"write in progress" flag
Definition: SerialPort.hpp:912
volatile size_t readPosition_
current read position
Definition: SerialPort.hpp:272
std::chrono::duration< rep, period > duration
basic duration type of clock
Definition: TickClock.hpp:39
int open(uint32_t baudRate, uint8_t characterLength, devices::UartParity parity, bool _2StopBits)
Opens SerialPort.
Definition: SerialPort.cpp:164
volatile size_t writePosition_
current write position
Definition: SerialPort.hpp:275
size_t getCapacity() const
Definition: SerialPort.hpp:98
UartBase class header.
void transmitCompleteEvent() override
"Transmit complete" event
Definition: SerialPort.cpp:316
CircularBuffer readBuffer_
internal instance of circular buffer for read operations
Definition: SerialPort.hpp:855
Thread-safe, lock-free circular buffer for one-producer and one-consumer.
Definition: SerialPort.hpp:48
CircularBuffer *volatile nextReadBuffer_
pointer to next circular buffer for read operations, used when currentReadBuffer_ becomes full ...
Definition: SerialPort.hpp:867
std::pair< int, size_t > tryWriteUntil(const std::chrono::time_point< TickClock, Duration > timePoint, const void *const buffer, const size_t size, const size_t minSize=SIZE_MAX)
Wrapper for write() with absolute timeout.
Definition: SerialPort.hpp:633
std::pair< int, size_t > tryReadFor(const std::chrono::duration< Rep, Period > duration, void *const buffer, const size_t size, const size_t minSize=1)
Wrapper for read() with relative timeout.
Definition: SerialPort.hpp:457
int writeToCircularBufferAndStartWrite(CircularBuffer &buffer)
Writes data to circular buffer and calls startWriteWrapper().
Definition: SerialPort.cpp:573
constexpr CircularBuffer(const void *const buffer, const size_t size)
CircularBuffer&#39;s constructor, read-only variant.
Definition: SerialPort.hpp:75
std::pair< int, size_t > tryWriteFor(const TickClock::duration duration, const void *const buffer, const size_t size, const size_t minSize=SIZE_MAX)
Wrapper for write() with relative timeout.
Definition: SerialPort.hpp:543
uint8_t * buffer_
pointer to beginning of buffer
Definition: SerialPort.hpp:266
void writeCompleteEvent(size_t bytesWritten) override
"Write complete" event
Definition: SerialPort.cpp:333
size_t stopWriteWrapper()
Wrapper for UartLowLevel::stopWrite()
Definition: SerialPort.cpp:503
static constexpr bool isFull(const size_t readPosition, const size_t writePosition)
Tests for full circular buffer.
Definition: SerialPort.hpp:248
uint32_t baudRate_
current baud rate, bps
Definition: SerialPort.hpp:891
void receiveErrorEvent(ErrorSet errorSet) override
"Receive error" event
Definition: SerialPort.cpp:311
std::bitset< errorBitsMax > ErrorSet
set of error bits
Definition: UartBase.hpp:51
void transmitStartEvent() override
"Transmit start" event
Definition: SerialPort.cpp:328