// Copyright 2015 Mobilinkd LLC // All rights reserved. #ifndef MOBILINKD__KISS_HPP_ #define MOBILINKD__KISS_HPP_ #include #include #include #include "HdlcFrame.hpp" namespace mobilinkd { namespace tnc { namespace kiss { const uint8_t FRAME_DATA = 0x00; const uint8_t FRAME_TX_DELAY = 0x01; const uint8_t FRAME_P_PERSIST = 0x02; const uint8_t FRAME_SLOT_TIME = 0x03; const uint8_t FRAME_TX_TAIL = 0x04; const uint8_t FRAME_DUPLEX = 0x05; const uint8_t FRAME_HARDWARE = 0x06; const uint8_t FRAME_LOG = 0x07; const uint8_t FRAME_RETURN = 0xFF; void handle_frame(uint8_t frame_type, hdlc::IoFrame* frame) __attribute__((optimize("-Os"))); // void handle_frame(uint8_t frame_type, hdlc::IoFrame* frame); struct slip_encoder { typedef std::forward_iterator_tag iterator_category; typedef size_t difference_type; typedef char value_type; typedef char& reference; typedef char* pointer; static const char FEND = 0xC0; static const char FESC = 0xDB; static const char TFEND = 0xDC; static const char TFESC = 0xDD; const char* packet_; size_t size_; size_t pos_; char current_; bool shifting_; slip_encoder() : packet_(0), size_(0), pos_(0), current_(0), shifting_(false) {} slip_encoder(const char* packet, size_t len) : packet_(packet), size_(len), pos_(0), current_(0), shifting_(false) { set_current(); } void set_current() { if ((packet_[pos_] == FEND) or (packet_[pos_] == FESC)) { current_ = FESC; shifting_ = true; } else { current_ = packet_[pos_]; } } char operator*() const { return current_; } slip_encoder& operator++() { if (!size_) return *this; if (shifting_) { shifting_ = false; current_ = (packet_[pos_] == FEND ? TFEND : TFESC); return *this; } pos_ += 1; if (pos_ != size_) { set_current(); } else { packet_ = 0; pos_ = 0; size_ = 0; } return *this; } slip_encoder operator++(int) { slip_encoder tmp(*this); ++(*this); return tmp; } bool operator==(const slip_encoder& other) const { return (packet_ == other.packet_) and (pos_ == other.pos_) and (size_ == other.size_); } bool operator!=(const slip_encoder& other) const { return not ((*this) == other); } }; /** * This is a input iterator adapter that SLIP-encodes the data from the * underlying frame iterator. The only requirement is that the underlying * iterator meets the requirements of an input iterator and that its value * type is convertible to char. */ struct slip_encoder2 { typedef std::input_iterator_tag iterator_category; typedef size_t difference_type; typedef char value_type; typedef char& reference; typedef char* pointer; static const char FEND = 0xC0; static const char FESC = 0xDB; static const char TFEND = 0xDC; static const char TFESC = 0xDD; hdlc::IoFrame::iterator iter_; mutable bool shifting_; slip_encoder2() = delete; explicit slip_encoder2(hdlc::IoFrame::iterator iter) : iter_(iter), shifting_(false) {} slip_encoder2(const slip_encoder2& other) : iter_(other.iter_), shifting_(other.shifting_) {} void swap(slip_encoder2& other) { std::swap(this->iter_, other.iter_); std::swap(this->shifting_, other.shifting_); } slip_encoder2& operator=(const slip_encoder2& other) { slip_encoder2 tmp{other}; this->swap(tmp); return *this; } /** * Return the current iterator value. The value will be one of: * * - the actual iterator value. * - FESC if the character is FESC/FEND and not shifting. * - TFESC/TFEND, the transposed shift characters when in shift mode. * * @return the slip-encoded character. */ char operator*() const { char c = *iter_; if (shifting_) { return c == FEND ? TFEND : TFESC; } if ((c == FEND) or (c == FESC)) { return FESC; } return c; } /** * Iterate through the buffer, doing SLIP encoding. The iterator is * either in normal mode or shift mode. When moving into shift mode, * the frame iterator is not advanced. * * This either advances the frame iterator or it enters shift mode. * * The iterator only enters shift mode if the iterator is currently * pointing to FEND/FESC. * * @note It is always legal to dereference the current frame iterator * when we are asked to advance it. It is undefined behavior to * advance a forward iterator past the end. For forward iterators the * standard states: "++r precondition: r is dereferenceable". * * @return a reference to *this. */ slip_encoder2& operator++() { char c = *iter_; if (not shifting_ and ((c == FEND) or (c == FESC))) { shifting_ = true; return *this; } shifting_ = false; ++iter_; return *this; } slip_encoder2 operator++(int) { slip_encoder2 tmp(*this); ++(*this); return tmp; } bool operator==(const slip_encoder2& other) const { return iter_ == other.iter_; } bool operator!=(const slip_encoder2& other) const { return iter_ != other.iter_; } }; struct slip_decoder { typedef std::forward_iterator_tag iterator_category; typedef size_t difference_type; typedef char value_type; typedef char& reference; typedef char* pointer; static const char FEND = 0xC0; static const char FESC = 0xDB; static const char TFEND = 0xDC; static const char TFESC = 0xDD; const char* packet_; size_t size_; size_t pos_; char current_; slip_decoder() : packet_(0), size_(0), pos_(0), current_(0) {} slip_decoder(const char* packet, size_t len) : packet_(packet), size_(len), pos_(0), current_(0) { set_current(); } void set_current() { if (packet_[pos_] == FESC) { pos_ += 1; current_ = (packet_[pos_] == TFEND ? FEND : FESC); } else { current_ = packet_[pos_]; } } char operator*() const { return current_; } slip_decoder& operator++() { if (!size_) return *this; pos_ += 1; if (pos_ != size_) { set_current(); } else { packet_ = 0; pos_ = 0; size_ = 0; } return *this; } slip_decoder operator++(int) { slip_decoder tmp(*this); ++(*this); return tmp; } bool operator==(const slip_decoder& other) const { return (packet_ == other.packet_) and (pos_ == other.pos_) and (size_ == other.size_); } bool operator!=(const slip_decoder& other) const { return not ((*this) == other); } }; }}} // mobilinkd::tnc::kiss #endif // MOBILINKD_KISS_HPP_