cleanup
This commit is contained in:
parent
6dee644a12
commit
d10ec6546d
11 changed files with 0 additions and 715 deletions
|
|
@ -1,275 +0,0 @@
|
|||
#if 0
|
||||
#include "esphome/core/component_iterator.h"
|
||||
#include "esphome/core/log.h"
|
||||
#include "esphome/components/esp32_ble/ble.h"
|
||||
#include "controller.h"
|
||||
#include "protocol.h"
|
||||
|
||||
namespace {
|
||||
const char *const TAG = "brmesh.controller";
|
||||
|
||||
template <size_t addr_size, size_t data_size>
|
||||
std::enable_if_t<(addr_size == 3 || addr_size == std::dynamic_extent), uint16_t>
|
||||
crc16(const std::span<const uint8_t, addr_size> &addr, const std::span<const uint8_t, data_size> &data, const uint16_t init = 0xFFFF)
|
||||
{
|
||||
constexpr auto step = [](uint16_t result, uint8_t byte)->uint16_t{
|
||||
result ^= static_cast<uint16_t>(byte) << 8;
|
||||
for (int j = 0; j < 4; j++) {
|
||||
uint16_t tmp = result << 1;
|
||||
if (result & 0x8000)
|
||||
tmp ^= 0x1021;
|
||||
result = tmp << 1;
|
||||
if (tmp & 0x8000)
|
||||
result ^= 0x1021;
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
auto result = init;
|
||||
|
||||
for (const auto &c:addr)
|
||||
result = step(result, c);
|
||||
|
||||
for (const uint8_t &c:data)
|
||||
result = step(result, esphome::reverse_bits(c));
|
||||
|
||||
return ~esphome::reverse_bits(result);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
namespace esphome {
|
||||
namespace brmesh {
|
||||
Controller::Controller(esp32_ble::ESP32BLE &ble,
|
||||
const Key &key,
|
||||
const uint16_t adv_interval_min,
|
||||
const uint16_t adv_interval_max,
|
||||
const uint16_t adv_duration,
|
||||
const uint16_t adv_gap)
|
||||
: ble_(ble), key_(key),
|
||||
adv_interval_min_(adv_interval_min),
|
||||
adv_interval_max_(adv_interval_max),
|
||||
adv_duration_(adv_duration),
|
||||
adv_gap_(adv_duration)
|
||||
{
|
||||
}
|
||||
|
||||
void Controller::setup()
|
||||
{
|
||||
ESP_LOGCONFIG(TAG, "BRmesh Controller:\n"
|
||||
" key: %02hx:%02hx:%02hx:%02hx\n"
|
||||
" adv interval: %hd-%hd\n"
|
||||
" adv duration: %hdms\n"
|
||||
" adv gap: %hdms",
|
||||
key_[0], key_[1], key_[2], key_[3],
|
||||
adv_interval_min_, adv_interval_max_,
|
||||
adv_duration_,
|
||||
adv_gap_);
|
||||
ble_.register_gap_event_handler(this);
|
||||
}
|
||||
|
||||
void Controller::loop()
|
||||
{
|
||||
auto *light = q_.peek();
|
||||
disable_loop();
|
||||
if (light == nullptr)
|
||||
light = q_.peek();
|
||||
if (light == nullptr)
|
||||
return;
|
||||
}
|
||||
|
||||
void Controller::advertise(Light &light)
|
||||
{
|
||||
esp_ble_adv_params_t adv_params = {
|
||||
.adv_int_min = adv_interval_min_,
|
||||
.adv_int_max = adv_interval_max_,
|
||||
.adv_type = ADV_TYPE_NONCONN_IND,
|
||||
.own_addr_type = BLE_ADDR_TYPE_PUBLIC,
|
||||
.peer_addr = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
|
||||
.peer_addr_type = BLE_ADDR_TYPE_PUBLIC,
|
||||
.channel_map = ADV_CHNL_ALL,
|
||||
.adv_filter_policy = ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY,
|
||||
};
|
||||
|
||||
std::array<uint8_t, 31> adv_data_raw[31];
|
||||
uint8_t adv_data_len = 0;
|
||||
|
||||
// Add flags
|
||||
adv_data_raw[adv_data_len++] = 2;
|
||||
adv_data_raw[adv_data_len++] = ESP_BLE_AD_TYPE_FLAG;
|
||||
adv_data_raw[adv_data_len++] = ESP_BLE_ADV_FLAG_BREDR_NOT_SPT | ESP_BLE_ADV_FLAG_GEN_DISC;
|
||||
|
||||
// Add manufacturer data
|
||||
const auto cmd_data_len = adv_data_len++;
|
||||
adv_data_raw[adv_data_len++] = ESP_BLE_AD_MANUFACTURER_SPECIFIC_TYPE;
|
||||
adv_data_raw[adv_data_len++] = MANUFACTURER_DATA_ID & 0xFF;
|
||||
adv_data_raw[adv_data_len++] = (MANUFACTURER_DATA_ID >> 8) & 0xFF;
|
||||
|
||||
const auto cmd = command(std::span(adv_data_raw).subspan(adv_data_len), light);
|
||||
adv_data_raw[cmd_data_len] = cmd.size_bytes();
|
||||
adv_data_len += cmd.size_bytes();
|
||||
|
||||
esp_err_t err = esp_ble_gap_config_adv_data_raw(adv_data_raw, adv_data_len);
|
||||
if (err != ESP_OK)
|
||||
{
|
||||
ESP_LOGW(TAG, "Error setting raw advertisement data (err=%d): %s", err, esp_err_to_name(err));
|
||||
return;
|
||||
}
|
||||
|
||||
err = esp_ble_gap_start_advertising(&adv_params);
|
||||
if (err != ESP_OK)
|
||||
{
|
||||
ESP_LOGW(TAG, "Error starting advertisement (err=%d): %s", err, esp_err_to_name(err));
|
||||
return;
|
||||
}
|
||||
|
||||
ESP_LOGD(TAG, "advertise id=%hd", light.id());
|
||||
}
|
||||
|
||||
void
|
||||
Controller::gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param)
|
||||
{
|
||||
switch (event) {
|
||||
case ESP_GAP_BLE_ADV_START_COMPLETE_EVT:
|
||||
ESP_LOD(TAG, "advertise: %hdms\n", adv_duration_);
|
||||
set_timeout(adv_duration_, esp_ble_gap_stop_advertising);
|
||||
return;
|
||||
|
||||
case ESP_GAP_BLE_ADV_STOP_COMPLETE_EVT:
|
||||
ESP_LOGD(TAG, "advertise gap: %hdms\n", adv_gap_);
|
||||
set_timeout(adv_gap_, [this](){
|
||||
q_.dequeue();
|
||||
auto *light = q_.peek();
|
||||
if (light == nullptr)
|
||||
advertise(*light);
|
||||
});
|
||||
return;
|
||||
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Controller::enqueue(Light &light)
|
||||
{
|
||||
if (!q_.enqueue(light))
|
||||
return;
|
||||
defer([this](){ advertise(*q_.peek()); });
|
||||
}
|
||||
|
||||
std::vector<uint8_t> Controller::single_control(uint32_t light_id_, const std::vector<uint8_t> &light_data)
|
||||
{
|
||||
std::vector<uint8_t> result_data(12);
|
||||
|
||||
result_data[0] = 2 | (((0xfffffff & (light_data.size() + 1)) << 4));
|
||||
result_data[1] = light_id_;
|
||||
std::copy(light_data.begin(), light_data.end(), result_data.begin() + 2);
|
||||
|
||||
// Debug output - print payload as hex
|
||||
auto hex_str = vector_to_hex_string(result_data).data();
|
||||
ESP_LOGD(TAG, "Inner Payload (%d bytes): %s", result_data.size(), hex_str);
|
||||
|
||||
return this->generate_command(5, light_id_, result_data, true);
|
||||
}
|
||||
|
||||
std::vector<uint8_t> Controller::generate_command(uint8_t n, uint32_t light_id_, const std::vector<uint8_t> &data, bool forward)
|
||||
{
|
||||
uint8_t& sequence = seq_;
|
||||
|
||||
// Create command body with header
|
||||
std::vector<uint8_t> body(data.size() + 4);
|
||||
uint8_t i2 = (light_id_ / 256);
|
||||
|
||||
// Construct header
|
||||
body[0] = (i2 & 0b1111) | ((n & 0b111) << 4) | (forward ? 0x80 : 0);
|
||||
body[1] = sequence++; // Use and increment sequence number
|
||||
if (sequence >= 255)
|
||||
sequence = 1;
|
||||
|
||||
body[2] = this->key_[3]; // Safe key
|
||||
|
||||
// Copy data
|
||||
std::copy(data.begin(), data.end(), body.begin() + 4);
|
||||
|
||||
// Calculate checksum
|
||||
uint8_t checksum = 0;
|
||||
for (size_t i = 0; i < body.size(); i++)
|
||||
{
|
||||
if (i != 3)
|
||||
{
|
||||
checksum = checksum + body[i];
|
||||
}
|
||||
}
|
||||
body[3] = checksum;
|
||||
|
||||
// Encrypt header and data
|
||||
for (size_t i = 0; i < 4; i++)
|
||||
{
|
||||
body[i] = DEFAULT_ENCRYPT_KEY[i & 3] ^ body[i];
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < data.size(); i++)
|
||||
{
|
||||
body[4 + i] = this->key_[i & 3] ^ body[4 + i];
|
||||
}
|
||||
|
||||
// Prepare the final payload with RF protocol formatting
|
||||
std::vector<uint8_t> addr = {DEFAULT_BLE_ADDRESS.begin(), DEFAULT_BLE_ADDRESS.end()};
|
||||
return prepare_payload(addr, body);
|
||||
}
|
||||
|
||||
std::span<uint8_t> Controller::payload(std::span<uint8_t, 24> &&span, const Light &light)
|
||||
{
|
||||
const auto header = span.subspan(0, 3);
|
||||
header[0] = 0x71;
|
||||
header[1] = 0x0f;
|
||||
header[2] = 0x55;
|
||||
|
||||
const auto address = span.subspan(3, 3);
|
||||
std::reverse_copy(address.begin(), address.end(),
|
||||
DEFAULT_BLE_ADDRESS.cbegin(),
|
||||
DEFAULT_BLE_ADDRESS.cend());
|
||||
|
||||
const auto data = command(span.subspan(6, 10), light);
|
||||
const auto crc = span.subspan(6 + data.size(), 2);
|
||||
const auto crc16 = ::crc16(address, data);
|
||||
crc[0] = static_cast<uint8_t>(crc16);
|
||||
crc[1] = static_cast<uint8_t>(crc16 >> 8);
|
||||
|
||||
auto result = span.subspan(0, header.size() + address.size() + data.size() + crc.size());
|
||||
|
||||
// TODO: adjust seed to skip zero byte warmup
|
||||
Whitening whitening(0x25);
|
||||
for (size_t i = 0; i< 16; ++i)
|
||||
(void) whitening.encode(0x00);
|
||||
|
||||
whitening.encode(result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::span<uint8_t> command(std::span<uint8_t, 10> &&span, const Light &light)
|
||||
{
|
||||
static constexpr uint8_t n = 5; // TODO
|
||||
static constexpr bool forward = true; // TODO
|
||||
|
||||
const auto inner = span.subpsna(4, light.command(span.subspan(4, 6)));
|
||||
|
||||
auto header = span.subspan(0, 4);
|
||||
header[0] = (i2 & 0b1111) | ((n & 0b111) << 4) | (forward ? 0x80 : 0);
|
||||
header[1] = seq_++;
|
||||
header[2] = key_[3]; // safe key
|
||||
header[3] = crc(inner);
|
||||
|
||||
DEFAULT_ENCRYPT_KEY(header);
|
||||
key_(inner);
|
||||
|
||||
//prepare(DEFAULT_BLE_ADDRESS, span.subspan(4 + inner.size()));
|
||||
return span.subspan(0, 4 + inner.size());
|
||||
}
|
||||
|
||||
} // namespace brmesh
|
||||
} // namespace esphome
|
||||
#endif
|
||||
|
|
@ -1,78 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <queue>
|
||||
#include <mutex>
|
||||
#include <vector>
|
||||
#include "esphome/core/component.h"
|
||||
#include "esphome/components/esp32_ble/ble.h"
|
||||
|
||||
#include "q.h"
|
||||
#include "key.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace brmesh {
|
||||
|
||||
class Light;
|
||||
|
||||
class Controller : public Component, public esp32_ble::GAPEventHandler
|
||||
{
|
||||
public:
|
||||
Controller(esp32_ble::ESP32BLE *ble, const Key &key, uint16_t adv_interval_min, uint16_t adv_interval_max, uint16_t adv_duration, uint16_t adv_gap)
|
||||
: Controller(*ble, key, adv_interval_min, adv_interval_max, adv_duration, adv_gap) {}
|
||||
|
||||
Controller(esp32_ble::ESP32BLE &ble, const Key &key, uint16_t adv_interval_min, uint16_t adv_interval_max, uint16_t adv_duration, uint16_t adv_gap);
|
||||
|
||||
std::vector<uint8_t> single_control(uint32_t addr, const std::vector<uint8_t> &light_data);
|
||||
void enqueue(Light &);
|
||||
|
||||
// interface: Component
|
||||
void setup() override;
|
||||
void loop() override;
|
||||
|
||||
// interface: GAPEventHandler
|
||||
void gap_event_handler(esp_gap_ble_cb_event_t, esp_ble_gap_cb_param_t *);
|
||||
|
||||
protected:
|
||||
struct Command
|
||||
{
|
||||
std::vector<uint8_t> data;
|
||||
uint32_t timestamp;
|
||||
uint8_t retries{0};
|
||||
static constexpr uint8_t MAX_RETRIES = 3;
|
||||
};
|
||||
|
||||
enum class AdvertiseState
|
||||
{
|
||||
IDLE,
|
||||
ADVERTISING,
|
||||
GAP
|
||||
};
|
||||
|
||||
AdvertiseState adv_state_{AdvertiseState::IDLE};
|
||||
uint32_t state_start_time_{0};
|
||||
|
||||
// Protocol implementation
|
||||
std::vector<uint8_t> generate_command(uint8_t n, uint32_t light_id_, const std::vector<uint8_t> &data, bool forward = true);
|
||||
|
||||
static const uint16_t MANUFACTURER_DATA_ID = 0xfff0;
|
||||
private:
|
||||
esp32_ble::ESP32BLE &ble_;
|
||||
Key key_;
|
||||
|
||||
uint16_t adv_interval_min_;
|
||||
uint16_t adv_interval_max_;
|
||||
uint16_t adv_duration_;
|
||||
uint16_t adv_gap_;
|
||||
|
||||
Q<Light> q_ = {};
|
||||
uint8_t seq_ = 0;
|
||||
|
||||
void advertise(Light &);
|
||||
|
||||
std::span<uint8_t> payload(std::span<uint8_t, 24> &span, const Light &light);
|
||||
|
||||
std::span<uint8_t> command(std::span<uint8_t, 24> &&span, const Light &light);
|
||||
};
|
||||
|
||||
} // namespace brmesh
|
||||
} // namespace esphome
|
||||
|
|
@ -1,43 +0,0 @@
|
|||
#pragma once
|
||||
#if 0
|
||||
#include "esphome/core/log.h"
|
||||
#include "esphome/core/defines.h"
|
||||
#include "esphome/core/helpers.h"
|
||||
|
||||
#ifdef USE_LOGGER
|
||||
#include "esphome/components/logger/logger.h"
|
||||
#endif
|
||||
|
||||
#include <span>
|
||||
|
||||
namespace esphome {
|
||||
namespace brmesh {
|
||||
|
||||
namespace {
|
||||
template <typename...types>
|
||||
void hexdump(const unsigned level, const char *tag, unsigned line, const uint8_t *data, size_t size, const char *fmt, types&&...args) {
|
||||
// TODO: conditional format_hex_pretty
|
||||
const auto hex = format_hex_pretty(data, size);
|
||||
ESP_LOGD(tag, fmt, std::forward<types>(args)..., hex.c_str());
|
||||
}
|
||||
|
||||
template <typename...types>
|
||||
void hexdump(const unsigned level, const char *tag, const void *data, size_t size, const char *fmt, types&&...args) {
|
||||
hexdump(level, tag, static_cast<const uint8_t *>(data), size, fmt, std::forward<types>(args)...);
|
||||
}
|
||||
|
||||
template <typename...types, typename base_type, size_t size>
|
||||
void hexdump(const unsigned level, const char *tag, const std::span<base_type, size> &span, const char *fmt, types&&...args) {
|
||||
hexdump(level, tag, static_cast<const void*>(&span.front()), span.size_bytes(), fmt, std::forward<types>(args)...);
|
||||
}
|
||||
|
||||
template <typename...types>
|
||||
void hexdump(const char *tag, types&&...args)
|
||||
{
|
||||
return hexdump(ESPHOME_LOG_LEVEL_DEBUG, tag, std::forward<types>(args)...);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace brmesh
|
||||
} // namespace esphome
|
||||
#endif
|
||||
|
|
@ -1,6 +1,5 @@
|
|||
#include "light.h"
|
||||
|
||||
#include "debug.h"
|
||||
#include "network.h"
|
||||
#include "whitening.h"
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
#include "network.h"
|
||||
|
||||
#include "debug.h"
|
||||
#include "light.h"
|
||||
#include "whitening.h"
|
||||
|
||||
|
|
|
|||
|
|
@ -1,64 +0,0 @@
|
|||
#include <algorithm>
|
||||
#include "protocol.h"
|
||||
#include "debug.h"
|
||||
|
||||
namespace {
|
||||
const char *TAG = "fastcon.protocol";
|
||||
}
|
||||
namespace esphome
|
||||
{
|
||||
namespace brmesh
|
||||
{
|
||||
std::vector<uint8_t> get_rf_payload(const std::vector<uint8_t> &addr, const std::vector<uint8_t> &data)
|
||||
{
|
||||
const size_t data_offset = 0x12;
|
||||
const size_t inverse_offset = 0x0f;
|
||||
const size_t result_data_size = data_offset + addr.size() + data.size();
|
||||
|
||||
// Create result buffer including space for checksum
|
||||
std::vector<uint8_t> resultbuf(result_data_size + 2, 0);
|
||||
|
||||
// Set hardcoded values
|
||||
resultbuf[0x0f] = 0x71;
|
||||
resultbuf[0x10] = 0x0f;
|
||||
resultbuf[0x11] = 0x55;
|
||||
|
||||
// Copy address in reverse
|
||||
for (size_t i = 0; i < addr.size(); i++)
|
||||
{
|
||||
resultbuf[data_offset + addr.size() - i - 1] = addr[i];
|
||||
}
|
||||
|
||||
// Copy data
|
||||
std::copy(data.begin(), data.end(), resultbuf.begin() + data_offset + addr.size());
|
||||
|
||||
// Reverse bytes in specified range
|
||||
for (size_t i = inverse_offset; i < inverse_offset + addr.size() + 3; i++)
|
||||
{
|
||||
resultbuf[i] = reverse_8(resultbuf[i]);
|
||||
}
|
||||
|
||||
// Add CRC
|
||||
uint16_t crc = crc16(addr, data);
|
||||
resultbuf[result_data_size] = crc & 0xFF;
|
||||
resultbuf[result_data_size + 1] = (crc >> 8) & 0xFF;
|
||||
|
||||
return resultbuf;
|
||||
}
|
||||
|
||||
std::vector<uint8_t> prepare_payload(const std::vector<uint8_t> &addr, const std::vector<uint8_t> &data)
|
||||
{
|
||||
auto payload = get_rf_payload(addr, data);
|
||||
|
||||
// Initialize whitening
|
||||
WhiteningContext context;
|
||||
whitening_init(0x25, context);
|
||||
|
||||
// Apply whitening to the payload
|
||||
whitening_encode(payload, context);
|
||||
|
||||
// Return only the portion after 0xf bytes
|
||||
return std::vector<uint8_t>(payload.begin() + 0xf, payload.end());
|
||||
}
|
||||
} // namespace brmesh
|
||||
} // namespace esphome
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
#include "utils.h"
|
||||
|
||||
namespace esphome
|
||||
{
|
||||
namespace brmesh
|
||||
{
|
||||
static const std::array<uint8_t, 4> DEFAULT_ENCRYPT_KEY = {0x5e, 0x36, 0x7b, 0xc4};
|
||||
static const std::array<uint8_t, 3> DEFAULT_BLE_FASTCON_ADDRESS = {0xC1, 0xC2, 0xC3};
|
||||
|
||||
std::vector<uint8_t> get_rf_payload(const std::vector<uint8_t> &addr, const std::vector<uint8_t> &data);
|
||||
std::vector<uint8_t> prepare_payload(const std::vector<uint8_t> &addr, const std::vector<uint8_t> &data);
|
||||
} // namespace brmesh
|
||||
} // namespace esphome
|
||||
|
|
@ -1,72 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
namespace esphome {
|
||||
namespace brmesh {
|
||||
|
||||
template <typename T>
|
||||
class Q {
|
||||
public:
|
||||
class Node;
|
||||
|
||||
constexpr Q() = default;
|
||||
|
||||
bool enqueue(T &);
|
||||
T *dequeue();
|
||||
T *peek();
|
||||
private:
|
||||
Node *head_ = nullptr;
|
||||
Node **tail_ = &head_;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class Q<T>::Node {
|
||||
public:
|
||||
constexpr Node() = default;
|
||||
|
||||
bool enqueue(Node *&head, Node **&tail);
|
||||
static Node *dequeue(Node *&head, Node **&tail);
|
||||
private:
|
||||
Node *next_ = nullptr;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
bool Q<T>::enqueue(T &node) {
|
||||
return static_cast<Node&>(node).enqueue(head_, tail_);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T *Q<T>::dequeue() {
|
||||
auto *node = Node::dequeue(head_, tail_);
|
||||
return dynamic_cast<T*>(node);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T *Q<T>::peek() {
|
||||
auto *node = head_;
|
||||
return dynamic_cast<T*>(node);
|
||||
}
|
||||
|
||||
|
||||
template <typename T>
|
||||
bool Q<T>::Node::enqueue(Node *&head, Node **&tail) {
|
||||
const bool first = tail == &head;
|
||||
*tail = this;
|
||||
tail = &next_;
|
||||
return first;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
Q<T>::Node *Q<T>::Node::dequeue(Node *&head, Node **&tail) {
|
||||
auto *node = head;
|
||||
if (node == nullptr)
|
||||
return nullptr;
|
||||
|
||||
head = node->next_;
|
||||
if (head == nullptr)
|
||||
tail = &head;
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
} // namespace brmesh
|
||||
} // namespace esphome
|
||||
|
|
@ -1,126 +0,0 @@
|
|||
#include <vector>
|
||||
#include <cstdio>
|
||||
#include "esphome/core/log.h"
|
||||
#include "utils.h"
|
||||
|
||||
namespace esphome
|
||||
{
|
||||
namespace brmesh
|
||||
{
|
||||
uint8_t reverse_8(uint8_t d)
|
||||
{
|
||||
uint8_t result = 0;
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
result |= ((d >> i) & 1) << (7 - i);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
uint16_t reverse_16(uint16_t d)
|
||||
{
|
||||
uint16_t result = 0;
|
||||
for (int i = 0; i < 16; i++)
|
||||
{
|
||||
result |= ((d >> i) & 1) << (15 - i);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
uint16_t crc16(const std::vector<uint8_t> &addr, const std::vector<uint8_t> &data)
|
||||
{
|
||||
uint16_t crc = 0xffff;
|
||||
|
||||
// Process address in reverse
|
||||
for (auto it = addr.rbegin(); it != addr.rend(); ++it)
|
||||
{
|
||||
crc ^= (static_cast<uint16_t>(*it) << 8);
|
||||
for (int j = 0; j < 4; j++)
|
||||
{
|
||||
uint16_t tmp = crc << 1;
|
||||
if (crc & 0x8000)
|
||||
{
|
||||
tmp ^= 0x1021;
|
||||
}
|
||||
crc = tmp << 1;
|
||||
if (tmp & 0x8000)
|
||||
{
|
||||
crc ^= 0x1021;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Process data
|
||||
for (size_t i = 0; i < data.size(); i++)
|
||||
{
|
||||
crc ^= (static_cast<uint16_t>(reverse_8(data[i])) << 8);
|
||||
for (int j = 0; j < 4; j++)
|
||||
{
|
||||
uint16_t tmp = crc << 1;
|
||||
if (crc & 0x8000)
|
||||
{
|
||||
tmp ^= 0x1021;
|
||||
}
|
||||
crc = tmp << 1;
|
||||
if (tmp & 0x8000)
|
||||
{
|
||||
crc ^= 0x1021;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
crc = ~reverse_16(crc);
|
||||
return crc;
|
||||
}
|
||||
|
||||
void whitening_init(uint32_t val, WhiteningContext &ctx)
|
||||
{
|
||||
uint32_t v0[] = {(val >> 5), (val >> 4), (val >> 3), (val >> 2)};
|
||||
|
||||
ctx.f_0x0 = 1;
|
||||
ctx.f_0x4 = v0[0] & 1;
|
||||
ctx.f_0x8 = v0[1] & 1;
|
||||
ctx.f_0xc = v0[2] & 1;
|
||||
ctx.f_0x10 = v0[3] & 1;
|
||||
ctx.f_0x14 = (val >> 1) & 1;
|
||||
ctx.f_0x18 = val & 1;
|
||||
}
|
||||
|
||||
void whitening_encode(std::vector<uint8_t> &data, WhiteningContext &ctx)
|
||||
{
|
||||
for (size_t i = 0; i < data.size(); i++)
|
||||
{
|
||||
uint32_t varC = ctx.f_0xc;
|
||||
uint32_t var14 = ctx.f_0x14;
|
||||
uint32_t var18 = ctx.f_0x18;
|
||||
uint32_t var10 = ctx.f_0x10;
|
||||
uint32_t var8 = var14 ^ ctx.f_0x8;
|
||||
uint32_t var4 = var10 ^ ctx.f_0x4;
|
||||
uint32_t _var = var18 ^ varC;
|
||||
uint32_t var0 = _var ^ ctx.f_0x0;
|
||||
|
||||
uint8_t c = data[i];
|
||||
data[i] = ((c & 0x80) ^ ((var8 ^ var18) << 7)) + ((c & 0x40) ^ (var0 << 6)) + ((c & 0x20) ^ (var4 << 5)) + ((c & 0x10) ^ (var8 << 4)) + ((c & 0x08) ^ (_var << 3)) + ((c & 0x04) ^ (var10 << 2)) + ((c & 0x02) ^ (var14 << 1)) + ((c & 0x01) ^ (var18 << 0));
|
||||
|
||||
ctx.f_0x8 = var4;
|
||||
ctx.f_0xc = var8;
|
||||
ctx.f_0x10 = var8 ^ varC;
|
||||
ctx.f_0x14 = var0 ^ var10;
|
||||
ctx.f_0x18 = var4 ^ var14;
|
||||
ctx.f_0x0 = var8 ^ var18;
|
||||
ctx.f_0x4 = var0;
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<char> vector_to_hex_string(std::vector<uint8_t> &data)
|
||||
{
|
||||
std::vector<char> hex_str(data.size() * 2 + 1); // Allocate the vector with the required size
|
||||
for (size_t i = 0; i < data.size(); i++)
|
||||
{
|
||||
sprintf(hex_str.data() + (i * 2), "%02X", data[i]);
|
||||
}
|
||||
hex_str[data.size() * 2] = '\0'; // Ensure null termination
|
||||
return hex_str;
|
||||
}
|
||||
} // namespace brmesh
|
||||
} // namespace esphome
|
||||
|
|
@ -1,36 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
|
||||
namespace esphome
|
||||
{
|
||||
namespace brmesh
|
||||
{
|
||||
// Bit manipulation utilities
|
||||
uint8_t reverse_8(uint8_t d);
|
||||
uint16_t reverse_16(uint16_t d);
|
||||
|
||||
// CRC calculation
|
||||
uint16_t crc16(const std::vector<uint8_t> &addr, const std::vector<uint8_t> &data);
|
||||
|
||||
// Whitening context and functions
|
||||
struct WhiteningContext
|
||||
{
|
||||
uint32_t f_0x0;
|
||||
uint32_t f_0x4;
|
||||
uint32_t f_0x8;
|
||||
uint32_t f_0xc;
|
||||
uint32_t f_0x10;
|
||||
uint32_t f_0x14;
|
||||
uint32_t f_0x18;
|
||||
|
||||
WhiteningContext() : f_0x0(0), f_0x4(0), f_0x8(0), f_0xc(0), f_0x10(0), f_0x14(0), f_0x18(0) {}
|
||||
};
|
||||
|
||||
void whitening_init(uint32_t val, WhiteningContext &ctx);
|
||||
void whitening_encode(std::vector<uint8_t> &data, WhiteningContext &ctx);
|
||||
|
||||
std::vector<char> vector_to_hex_string(std::vector<uint8_t> &data);
|
||||
} // namespace brmesh
|
||||
} // namespace esphome
|
||||
|
|
@ -1,5 +1,4 @@
|
|||
#include "whitening.h"
|
||||
#include "debug.h"
|
||||
|
||||
#include "esphome/core/log.h"
|
||||
#include "esphome/core/helpers.h"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue