mirror of
https://github.com/esphome/esphome.git
synced 2024-11-09 16:57:47 +01:00
Implement ByteBuffer (#6878)
This commit is contained in:
parent
0c567adf63
commit
68c56b3e03
2 changed files with 230 additions and 0 deletions
134
esphome/core/bytebuffer.cpp
Normal file
134
esphome/core/bytebuffer.cpp
Normal file
|
@ -0,0 +1,134 @@
|
|||
#include "bytebuffer.h"
|
||||
#include <cassert>
|
||||
|
||||
namespace esphome {
|
||||
|
||||
ByteBuffer ByteBuffer::create(size_t capacity) {
|
||||
std::vector<uint8_t> data(capacity);
|
||||
return {data};
|
||||
}
|
||||
|
||||
ByteBuffer ByteBuffer::wrap(uint8_t *ptr, size_t len) {
|
||||
std::vector<uint8_t> data(ptr, ptr + len);
|
||||
return {data};
|
||||
}
|
||||
|
||||
ByteBuffer ByteBuffer::wrap(std::vector<uint8_t> data) { return {std::move(data)}; }
|
||||
|
||||
void ByteBuffer::set_limit(size_t limit) {
|
||||
assert(limit <= this->get_capacity());
|
||||
this->limit_ = limit;
|
||||
}
|
||||
void ByteBuffer::set_position(size_t position) {
|
||||
assert(position <= this->get_limit());
|
||||
this->position_ = position;
|
||||
}
|
||||
void ByteBuffer::clear() {
|
||||
this->limit_ = this->get_capacity();
|
||||
this->position_ = 0;
|
||||
}
|
||||
uint16_t ByteBuffer::get_uint16() {
|
||||
assert(this->get_remaining() >= 2);
|
||||
uint16_t value;
|
||||
if (endianness_ == LITTLE) {
|
||||
value = this->data_[this->position_++];
|
||||
value |= this->data_[this->position_++] << 8;
|
||||
} else {
|
||||
value = this->data_[this->position_++] << 8;
|
||||
value |= this->data_[this->position_++];
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
uint32_t ByteBuffer::get_uint32() {
|
||||
assert(this->get_remaining() >= 4);
|
||||
uint32_t value;
|
||||
if (endianness_ == LITTLE) {
|
||||
value = this->data_[this->position_++];
|
||||
value |= this->data_[this->position_++] << 8;
|
||||
value |= this->data_[this->position_++] << 16;
|
||||
value |= this->data_[this->position_++] << 24;
|
||||
} else {
|
||||
value = this->data_[this->position_++] << 24;
|
||||
value |= this->data_[this->position_++] << 16;
|
||||
value |= this->data_[this->position_++] << 8;
|
||||
value |= this->data_[this->position_++];
|
||||
}
|
||||
return value;
|
||||
}
|
||||
uint32_t ByteBuffer::get_uint24() {
|
||||
assert(this->get_remaining() >= 3);
|
||||
uint32_t value;
|
||||
if (endianness_ == LITTLE) {
|
||||
value = this->data_[this->position_++];
|
||||
value |= this->data_[this->position_++] << 8;
|
||||
value |= this->data_[this->position_++] << 16;
|
||||
} else {
|
||||
value = this->data_[this->position_++] << 16;
|
||||
value |= this->data_[this->position_++] << 8;
|
||||
value |= this->data_[this->position_++];
|
||||
}
|
||||
return value;
|
||||
}
|
||||
uint32_t ByteBuffer::get_int24() {
|
||||
auto value = this->get_uint24();
|
||||
uint32_t mask = (~(uint32_t) 0) << 23;
|
||||
if ((value & mask) != 0)
|
||||
value |= mask;
|
||||
return value;
|
||||
}
|
||||
uint8_t ByteBuffer::get_uint8() {
|
||||
assert(this->get_remaining() >= 1);
|
||||
return this->data_[this->position_++];
|
||||
}
|
||||
float ByteBuffer::get_float() {
|
||||
auto value = this->get_uint32();
|
||||
return *(float *) &value;
|
||||
}
|
||||
void ByteBuffer::put_uint8(uint8_t value) {
|
||||
assert(this->get_remaining() >= 1);
|
||||
this->data_[this->position_++] = value;
|
||||
}
|
||||
|
||||
void ByteBuffer::put_uint16(uint16_t value) {
|
||||
assert(this->get_remaining() >= 2);
|
||||
if (this->endianness_ == LITTLE) {
|
||||
this->data_[this->position_++] = (uint8_t) value;
|
||||
this->data_[this->position_++] = (uint8_t) (value >> 8);
|
||||
} else {
|
||||
this->data_[this->position_++] = (uint8_t) (value >> 8);
|
||||
this->data_[this->position_++] = (uint8_t) value;
|
||||
}
|
||||
}
|
||||
void ByteBuffer::put_uint24(uint32_t value) {
|
||||
assert(this->get_remaining() >= 3);
|
||||
if (this->endianness_ == LITTLE) {
|
||||
this->data_[this->position_++] = (uint8_t) value;
|
||||
this->data_[this->position_++] = (uint8_t) (value >> 8);
|
||||
this->data_[this->position_++] = (uint8_t) (value >> 16);
|
||||
} else {
|
||||
this->data_[this->position_++] = (uint8_t) (value >> 16);
|
||||
this->data_[this->position_++] = (uint8_t) (value >> 8);
|
||||
this->data_[this->position_++] = (uint8_t) value;
|
||||
}
|
||||
}
|
||||
void ByteBuffer::put_uint32(uint32_t value) {
|
||||
assert(this->get_remaining() >= 4);
|
||||
if (this->endianness_ == LITTLE) {
|
||||
this->data_[this->position_++] = (uint8_t) value;
|
||||
this->data_[this->position_++] = (uint8_t) (value >> 8);
|
||||
this->data_[this->position_++] = (uint8_t) (value >> 16);
|
||||
this->data_[this->position_++] = (uint8_t) (value >> 24);
|
||||
} else {
|
||||
this->data_[this->position_++] = (uint8_t) (value >> 24);
|
||||
this->data_[this->position_++] = (uint8_t) (value >> 16);
|
||||
this->data_[this->position_++] = (uint8_t) (value >> 8);
|
||||
this->data_[this->position_++] = (uint8_t) value;
|
||||
}
|
||||
}
|
||||
void ByteBuffer::put_float(float value) { this->put_uint32(*(uint32_t *) &value); }
|
||||
void ByteBuffer::flip() {
|
||||
this->limit_ = this->position_;
|
||||
this->position_ = 0;
|
||||
}
|
||||
} // namespace esphome
|
96
esphome/core/bytebuffer.h
Normal file
96
esphome/core/bytebuffer.h
Normal file
|
@ -0,0 +1,96 @@
|
|||
#pragma once
|
||||
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include <cinttypes>
|
||||
#include <cstddef>
|
||||
|
||||
namespace esphome {
|
||||
|
||||
enum Endian { LITTLE, BIG };
|
||||
|
||||
/**
|
||||
* A class modelled on the Java ByteBuffer class. It wraps a vector of bytes and permits putting and getting
|
||||
* items of various sizes, with an automatically incremented position.
|
||||
*
|
||||
* There are three variables maintained pointing into the buffer:
|
||||
*
|
||||
* 0 <= position <= limit <= capacity
|
||||
*
|
||||
* capacity: the maximum amount of data that can be stored
|
||||
* limit: the limit of the data currently available to get or put
|
||||
* position: the current insert or extract position
|
||||
*
|
||||
* In addition a mark can be set to the current position with mark(). A subsequent call to reset() will restore
|
||||
* the position to the mark.
|
||||
*
|
||||
* The buffer can be marked to be little-endian (default) or big-endian. All subsequent operations will use that order.
|
||||
*
|
||||
*/
|
||||
class ByteBuffer {
|
||||
public:
|
||||
/**
|
||||
* Create a new Bytebuffer with the given capacity
|
||||
*/
|
||||
static ByteBuffer create(size_t capacity);
|
||||
/**
|
||||
* Wrap an existing vector in a Bytebufffer
|
||||
*/
|
||||
static ByteBuffer wrap(std::vector<uint8_t> data);
|
||||
/**
|
||||
* Wrap an existing array in a Bytebufffer
|
||||
*/
|
||||
static ByteBuffer wrap(uint8_t *ptr, size_t len);
|
||||
|
||||
// Get one byte from the buffer, increment position by 1
|
||||
uint8_t get_uint8();
|
||||
// Get a 16 bit unsigned value, increment by 2
|
||||
uint16_t get_uint16();
|
||||
// Get a 24 bit unsigned value, increment by 3
|
||||
uint32_t get_uint24();
|
||||
// Get a 32 bit unsigned value, increment by 4
|
||||
uint32_t get_uint32();
|
||||
// signed versions of the get functions
|
||||
uint8_t get_int8() { return (int8_t) this->get_uint8(); };
|
||||
int16_t get_int16() { return (int16_t) this->get_uint16(); }
|
||||
uint32_t get_int24();
|
||||
int32_t get_int32() { return (int32_t) this->get_uint32(); }
|
||||
// Get a float value, increment by 4
|
||||
float get_float();
|
||||
|
||||
// put values into the buffer, increment the position accordingly
|
||||
void put_uint8(uint8_t value);
|
||||
void put_uint16(uint16_t value);
|
||||
void put_uint24(uint32_t value);
|
||||
void put_uint32(uint32_t value);
|
||||
void put_float(float value);
|
||||
|
||||
inline size_t get_capacity() const { return this->data_.size(); }
|
||||
inline size_t get_position() const { return this->position_; }
|
||||
inline size_t get_limit() const { return this->limit_; }
|
||||
inline size_t get_remaining() const { return this->get_limit() - this->get_position(); }
|
||||
inline Endian get_endianness() const { return this->endianness_; }
|
||||
inline void mark() { this->mark_ = this->position_; }
|
||||
inline void big_endian() { this->endianness_ = BIG; }
|
||||
inline void little_endian() { this->endianness_ = LITTLE; }
|
||||
void set_limit(size_t limit);
|
||||
void set_position(size_t position);
|
||||
// set position to 0, limit to capacity.
|
||||
void clear();
|
||||
// set limit to current position, postition to zero. Used when swapping from write to read operations.
|
||||
void flip();
|
||||
// retrieve a pointer to the underlying data.
|
||||
uint8_t *array() { return this->data_.data(); };
|
||||
void rewind() { this->position_ = 0; }
|
||||
void reset() { this->position_ = this->mark_; }
|
||||
|
||||
protected:
|
||||
ByteBuffer(std::vector<uint8_t> data) : data_(std::move(data)) { this->limit_ = this->get_capacity(); }
|
||||
std::vector<uint8_t> data_;
|
||||
Endian endianness_{LITTLE};
|
||||
size_t position_{0};
|
||||
size_t mark_{0};
|
||||
size_t limit_{0};
|
||||
};
|
||||
|
||||
} // namespace esphome
|
Loading…
Reference in a new issue