Line data Source code
1 : #pragma once 2 : 3 : #include <AH/STL/algorithm> // std::reverse 4 : #include <AH/STL/utility> // std::forward 5 : #include <limits.h> // CHAR_BIT 6 : #include <stddef.h> // size_t 7 : #include <string.h> // memcpy 8 : 9 : #include <boost/integer.hpp> // boost::uint_t 10 : 11 : #include <SLIPStream/SLIP.hpp> 12 : 13 : /// @addtogroup SLIP 14 : /// @{ 15 : 16 : /** 17 : * @brief Class for sending SLIP packets. 18 : * 19 : * @tparam Sender 20 : * The functor that actually sends a byte over the transmission 21 : * channel. Takes a single byte as an argument and returns the number 22 : * of bytes written (similar to `Serial.write(uint8_t)`): 23 : * `size_t sender(uint8_t byte)` 24 : */ 25 : template <class Sender> 26 : class SLIPSender { 27 : public: 28 : /** 29 : * @brief Default constructor. 30 : */ 31 : SLIPSender() = default; 32 : /** 33 : * @brief Constructor with sender initialization. 34 : * 35 : * @param sender 36 : * Initialization for the sender. Perfect forwarding is used. 37 : */ 38 13 : SLIPSender(Sender &&sender) : sender(std::forward<Sender>(sender)) {} 39 : 40 : /** 41 : * @brief Start a packet. 42 : * 43 : * Sends a SLIP @ref SLIP_Constants::END "END" character to flush the buffer 44 : * of the receiver. 45 : * 46 : * @return The number of bytes sent by the Sender. 47 : */ 48 4 : size_t beginPacket() { return sender(SLIP_Constants::END); } 49 : /** 50 : * @brief Finish the packet. 51 : * 52 : * Sends a SLIP @ref SLIP_Constants::END "END" character. 53 : * 54 : * @return The number of bytes sent by the Sender. 55 : */ 56 4 : size_t endPacket() { return sender(SLIP_Constants::END); } 57 : 58 : /** 59 : * @brief Write some data as the body of a packet. 60 : * 61 : * The data is encoded by SLIP before sending, so arbitrary binary data can 62 : * be sent. 63 : * 64 : * @param data 65 : * A pointer to the data to send. 66 : * @param len 67 : * The number of bytes to send. 68 : * @return The number of bytes sent by the Sender. 69 : */ 70 : size_t write(const uint8_t *data, size_t len); 71 : 72 : private: 73 : Sender sender; 74 : }; 75 : 76 : /// @} 77 : 78 : /// @addtogroup CRC 79 : /// @{ 80 : 81 : /** 82 : * @brief Class for sending SLIP packets with a CRC checksum to check the 83 : * integrity of the packets. 84 : * 85 : * @tparam Sender 86 : * The functor that actually sends a byte over the transmission 87 : * channel. Takes a single byte as an argument and returns the number 88 : * of bytes written (similar to `Serial.write(uint8_t)`): 89 : * `size_t sender(uint8_t byte)` 90 : * @tparam CRC 91 : * The CRC type to use. 92 : */ 93 : template <class Sender, class CRC> 94 : class SLIPSenderCRC { 95 : public: 96 : /** 97 : * @brief Default constructor. 98 : */ 99 : SLIPSenderCRC() = default; 100 : /** 101 : * @brief Constructor with sender initialization. 102 : * 103 : * @param sender 104 : * Initialization for the sender. Perfect forwarding is used. 105 : * The CRC is default-initialized. 106 : */ 107 : SLIPSenderCRC(Sender &&sender) : sender(std::forward<Sender>(sender)) {} 108 : /** 109 : * @brief Constructor with CRC initialization. 110 : * 111 : * @param crc 112 : * Initialization for the CRC. Perfect forwarding is used. 113 : * The sender is default-initialized. 114 : */ 115 : SLIPSenderCRC(CRC &&crc) : crc(std::forward<CRC>(crc)) {} 116 : /** 117 : * @brief Constructor with sender and CRC initialization. 118 : * 119 : * @param sender 120 : * Initialization for the sender. Perfect forwarding is used. 121 : * @param crc 122 : * Initialization for the CRC. Perfect forwarding is used. 123 : */ 124 10 : SLIPSenderCRC(Sender &&sender, CRC &&crc) 125 10 : : sender(std::forward<Sender>(sender)), crc(std::forward<CRC>(crc)) {} 126 : 127 : /// The integer type of the checksum. 128 : using checksum_t = typename boost::uint_t<CRC::bit_count>::least; 129 : 130 : /// @copydoc SLIPSender::beginPacket() 131 3 : size_t beginPacket() { 132 3 : this->crc.reset(); 133 3 : return sender.beginPacket(); 134 : } 135 : 136 : /** 137 : * @brief Finish the packet. 138 : * 139 : * Encodes and sends the checksum of all data sent using the @ref write 140 : * function, followed by a SLIP @ref SLIP_Constants::END "END" character. 141 : * 142 : * @return The number of bytes sent by the Sender. 143 : */ 144 3 : size_t endPacket() { 145 3 : constexpr size_t numChars = sizeof(checksum_t); 146 3 : uint8_t buffer[numChars]; 147 3 : const checksum_t checksum = this->crc.checksum(); 148 3 : memcpy(buffer, &checksum, numChars); 149 3 : std::reverse(std::begin(buffer), std::end(buffer)); 150 6 : return sender.write(buffer, numChars) + sender.endPacket(); 151 3 : } 152 : 153 : /// @copydoc SLIPSender::write() 154 : size_t write(const uint8_t *data, size_t len); 155 : 156 : private: 157 : SLIPSender<Sender> sender; 158 : CRC crc; 159 : }; 160 : 161 : /// @} 162 : 163 : #include "SLIPSender.ipp"