tnc3-firmware/TNC/Kiss.hpp

296 wiersze
7.1 KiB
C++

// Copyright 2015 Mobilinkd LLC <rob@mobilinkd.com>
// All rights reserved.
#ifndef MOBILINKD__KISS_HPP_
#define MOBILINKD__KISS_HPP_
#include <iterator>
#include <algorithm>
#include <cstdint>
#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_