kopia lustrzana https://github.com/mobilinkd/tnc3-firmware
296 wiersze
7.1 KiB
C++
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_
|