wip
This commit is contained in:
parent
39922749ec
commit
20f30d7c02
@ -1,23 +1,28 @@
|
||||
#ifndef SIMPLESYNC_HPP
|
||||
#define SIMPLESYNC_HPP
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <functional>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
|
||||
#ifdef ARDUINO
|
||||
#include <Arduino.h>
|
||||
#ifdef __AVR__
|
||||
#include "include/nonstd_functional.hpp"
|
||||
using nonstd::function;
|
||||
#else /* ndef __AVR__ */
|
||||
using std::function;
|
||||
#define STDCLIB
|
||||
#endif
|
||||
#else /* ndef ARDUINO */
|
||||
#define STDCLIB
|
||||
#endif
|
||||
#ifdef STDCLIB
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <functional>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
using std::function;
|
||||
using std::string;
|
||||
#endif
|
||||
|
||||
namespace simplesync {
|
||||
@ -127,97 +132,109 @@ inline uint16_t calc_fletcher_checksum(uint8_t *buf, unsigned int buf_size) {
|
||||
return (c1 << 8 | c0);
|
||||
}
|
||||
|
||||
template <typename time_t, typename timedelta_t, unsigned int BUF_SIZE = 256,
|
||||
unsigned int str_len_max = 32>
|
||||
class SimpleSync {
|
||||
template <typename time_t, typename timedelta_t, unsigned int BUF_SIZE = 256> class SimpleSync {
|
||||
public:
|
||||
static constexpr unsigned int STR_LEN_MAX = str_len_max;
|
||||
class NumberInterface {
|
||||
class Interface {
|
||||
public:
|
||||
time_t last_send;
|
||||
char *key;
|
||||
timedelta_t update_interval;
|
||||
uint8_t type;
|
||||
string key;
|
||||
|
||||
std::function<int(uint8_t *buf, unsigned int buf_size)> pack;
|
||||
std::function<int(uint8_t *buf, unsigned int buf_size)> unpack;
|
||||
|
||||
bool send_requested = true;
|
||||
int value;
|
||||
NumberInterface(SimpleSync &s, char *key, timedelta_t update_interval)
|
||||
: key(key), update_interval(update_interval) {
|
||||
s.number_interfaces.push_back(this);
|
||||
}
|
||||
time_t last_send;
|
||||
|
||||
timedelta_t update_interval;
|
||||
bool update_periodically;
|
||||
|
||||
Interface(uint8_t type, string key,
|
||||
std::function<int(uint8_t *buf, unsigned int buf_size)> pack,
|
||||
std::function<int(uint8_t *buf, unsigned int buf_size)> unpack)
|
||||
: type(type), key(key), pack(pack), unpack(unpack), update_periodically(false) {}
|
||||
Interface(uint8_t type, string key,
|
||||
std::function<int(uint8_t *buf, unsigned int buf_size)> pack,
|
||||
std::function<int(uint8_t *buf, unsigned int buf_size)> unpack,
|
||||
timedelta_t update_interval)
|
||||
: Interface(type, key, pack, unpack), update_interval(update_interval),
|
||||
update_periodically(true) {}
|
||||
};
|
||||
|
||||
class StringInterface {
|
||||
public:
|
||||
time_t last_send;
|
||||
char *key;
|
||||
timedelta_t update_interval;
|
||||
bool send_requested = true;
|
||||
char value[str_len_max + 1];
|
||||
StringInterface(SimpleSync &s, char *key, timedelta_t update_interval)
|
||||
: key(key), update_interval(update_interval) {
|
||||
value[str_len_max] = 0x00;
|
||||
s.string_interfaces.push_back(this);
|
||||
template <typename int_t> static void Number(SimpleSync &sync, string key, int_t *value_ptr) {
|
||||
sync.interfaces.push_back(std::make_unique<Interface>(
|
||||
0x01, key,
|
||||
[=](uint8_t *buf, unsigned int buf_size) -> int { /* pack */
|
||||
if (buf_size < sizeof(int) * 8 / 7)
|
||||
return BUFFER_OVERFLOW;
|
||||
return encode_varint(*value_ptr, buf);
|
||||
},
|
||||
[=](uint8_t *buf, unsigned int buf_size) -> int { /* unpack */
|
||||
buf_size = 1 * buf_size;
|
||||
return decode_varint(buf, *value_ptr);
|
||||
}));
|
||||
}
|
||||
};
|
||||
|
||||
std::vector<NumberInterface *> number_interfaces;
|
||||
std::vector<StringInterface *> string_interfaces;
|
||||
static void String(SimpleSync &sync, string key, string *value_ptr) {
|
||||
sync.interfaces.push_back(std::make_unique<Interface>(
|
||||
0x02, key,
|
||||
[=](uint8_t *buf, unsigned int buf_size) -> int { /* pack */
|
||||
auto value_len =
|
||||
1 + strlen(value_ptr->c_str());
|
||||
if (buf_size < value_len)
|
||||
return BUFFER_OVERFLOW;
|
||||
memcpy(buf, value_ptr->c_str(),
|
||||
value_len);
|
||||
return value_len;
|
||||
},
|
||||
[=](uint8_t *buf, unsigned int buf_size) -> int { /* unpack */
|
||||
auto strl = strlen((char *)buf) + 1;
|
||||
if (strl <= buf_size)
|
||||
return BUFFER_OVERFLOW;
|
||||
value_ptr->assign((char *)buf);
|
||||
return strl;
|
||||
}));
|
||||
}
|
||||
|
||||
// int parse_number(uint8_t *buf, unsigned int buf_size, int* value){
|
||||
// return decode_varint(&buf[parsed], *value);
|
||||
// }
|
||||
|
||||
std::vector<std::unique_ptr<Interface>> interfaces;
|
||||
|
||||
function<int(uint8_t *, unsigned int)> write_pkg;
|
||||
function<void(NumberInterface *&, char *, int)> number_update;
|
||||
function<void(StringInterface *&, char *, char *)> string_update;
|
||||
function<void(const std::unique_ptr<Interface> &, char *, int)> interface_update;
|
||||
SimpleSync(function<int(uint8_t *, unsigned int)> write_pkg,
|
||||
function<void(NumberInterface *&, char *, int)> number_update,
|
||||
function<void(StringInterface *&, char *, char *)> string_update)
|
||||
: write_pkg(write_pkg), number_update(number_update), string_update(string_update) {}
|
||||
function<void(const std::unique_ptr<Interface> &, char *, int)> interface_update)
|
||||
: write_pkg(write_pkg), interface_update(interface_update) {}
|
||||
|
||||
Interface &get_or_create_interface(uint8_t type, char *key) {
|
||||
for (auto &i : interfaces) {
|
||||
if (i->type == type && strcmp(i->key.c_str(), key) == 0) {
|
||||
return *i;
|
||||
}
|
||||
}
|
||||
}
|
||||
int parse_pkg(uint8_t *buf, unsigned int buf_size) {
|
||||
if (buf_size < 4) return CRC_MISSMATCH;
|
||||
uint16_t crc = calc_fletcher_checksum(buf, buf_size - 2);
|
||||
if (buf[--buf_size] != (crc & 0xFF) || (buf[--buf_size] != (crc >> 8)))
|
||||
return CRC_MISSMATCH;
|
||||
for (unsigned int parsed = 0; parsed < buf_size;) {
|
||||
switch (buf[parsed]) {
|
||||
uint8_t type = buf[parsed];
|
||||
switch (type) {
|
||||
case 0x00: {
|
||||
for (auto ni : number_interfaces) ni->send_requested = true;
|
||||
for (auto ni : string_interfaces) ni->send_requested = true;
|
||||
} break;
|
||||
case 0x01: {
|
||||
char *key = (char *)&buf[parsed + 1];
|
||||
parsed += 1 + strlen(key) + 1;
|
||||
int value;
|
||||
parsed += decode_varint(&buf[parsed], value);
|
||||
NumberInterface *ni_ptr = nullptr;
|
||||
for (auto ni : number_interfaces) {
|
||||
if (strcmp(ni->key, key) == 0) {
|
||||
ni_ptr = ni;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (number_update) {
|
||||
number_update(ni_ptr, key, value);
|
||||
}
|
||||
if (ni_ptr) {
|
||||
ni_ptr->value = value;
|
||||
}
|
||||
for (auto ni : interfaces) ni->send_requested = true;
|
||||
} break;
|
||||
case 0x01:
|
||||
case 0x02: {
|
||||
char *key = (char *)&buf[parsed + 1];
|
||||
parsed += 1 + strlen(key) + 1;
|
||||
char *value = (char *)&buf[parsed];
|
||||
unsigned int strl = strlen(value) + 1;
|
||||
parsed += strl;
|
||||
StringInterface *stri_ptr = nullptr;
|
||||
for (StringInterface *si : string_interfaces) {
|
||||
if (strcmp(si->key, key) == 0) {
|
||||
stri_ptr = si;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (string_update) {
|
||||
string_update(stri_ptr, key, value);
|
||||
}
|
||||
if (stri_ptr) {
|
||||
memcpy(stri_ptr->value, value, str_len_max > strl ? strl : str_len_max);
|
||||
Interface &ni = get_or_create_interface(type, key);
|
||||
unsigned int unpacked_bytes = ni.unpack(buf + parsed, buf_size - parsed);
|
||||
if (unpacked_bytes >= 0) {
|
||||
parsed += unpacked_bytes;
|
||||
} else { // ERROR -> return
|
||||
return unpacked_bytes;
|
||||
}
|
||||
} break;
|
||||
default:
|
||||
@ -239,11 +256,11 @@ class SimpleSync {
|
||||
void update(time_t time) {
|
||||
uint8_t buf[BUF_SIZE];
|
||||
unsigned int buf_len_used = 0;
|
||||
for (auto ni : number_interfaces) {
|
||||
for (auto& ni : interfaces) {
|
||||
if (ni->send_requested ||
|
||||
(ni->last_send > time || ni->last_send <= time - ni->update_interval)) {
|
||||
unsigned int strl = strlen(ni->key) + 1;
|
||||
unsigned int buf_len_needed = 1 + strl + 8 * sizeof(int) / 7;
|
||||
(ni->update_periodically && (ni->last_send > time || ni->last_send <= time - ni->update_interval))) {
|
||||
unsigned int strl = strlen(ni->key.c_str()) + 1;
|
||||
unsigned int buf_len_needed = 1 + strl + 32; // TODO get real pack size (not always 32)
|
||||
buf_len_needed += buf_len_needed / 0xFF + 3 + 2; // COBS overhead
|
||||
if (BUF_SIZE < buf_len_needed) continue; // Error: update to large, skip interface
|
||||
if (BUF_SIZE < buf_len_used + buf_len_needed) {
|
||||
@ -256,39 +273,12 @@ class SimpleSync {
|
||||
write_pkg(cobs_buf, cobs_buf_needed);
|
||||
buf_len_used = 0;
|
||||
}
|
||||
buf[buf_len_used++] = 0x01;
|
||||
memcpy((char *)&buf[buf_len_used], ni->key, strl);
|
||||
buf_len_used += strl;
|
||||
buf_len_used += encode_varint(ni->value, &buf[buf_len_used]);
|
||||
ni->last_send = time;
|
||||
ni->send_requested = false;
|
||||
}
|
||||
}
|
||||
for (auto ni : string_interfaces) {
|
||||
if (ni->send_requested ||
|
||||
(ni->last_send > time || ni->last_send <= time - ni->update_interval)) {
|
||||
unsigned int strl = strlen(ni->key) + 1;
|
||||
unsigned int strl_value = strlen(ni->value) + 1;
|
||||
unsigned int buf_len_needed = 1 + strl + strl_value;
|
||||
buf_len_needed += buf_len_needed / 0xFF + 3 + 2; // COBS overhead
|
||||
if (BUF_SIZE < buf_len_needed) continue; // Error: update to large, skip interface
|
||||
if (BUF_SIZE < buf_len_used + buf_len_needed + 2) {
|
||||
uint8_t cobs_buf[BUF_SIZE];
|
||||
uint16_t crc = calc_fletcher_checksum(buf, buf_len_used);
|
||||
buf[buf_len_used++] = crc >> 8;
|
||||
buf[buf_len_used++] = crc & 0xFF;
|
||||
unsigned int cobs_buf_needed =
|
||||
cobs_encode(buf, buf_len_used, cobs_buf, BUF_SIZE);
|
||||
write_pkg(cobs_buf, cobs_buf_needed);
|
||||
buf_len_used = 0;
|
||||
}
|
||||
buf[buf_len_used++] = 0x02;
|
||||
memcpy((char *)&buf[buf_len_used], ni->key, strl);
|
||||
buf_len_used += strl;
|
||||
memcpy((char *)&buf[buf_len_used], ni->value, strl_value);
|
||||
buf_len_used += strl_value;
|
||||
buf[buf_len_used++] = ni->type;
|
||||
memcpy((char *)&buf[buf_len_used], ni->key.c_str(), strl);
|
||||
ni->pack(&buf[buf_len_used], BUF_SIZE - buf_len_used);
|
||||
ni->last_send = time;
|
||||
ni->send_requested = false;
|
||||
|
||||
}
|
||||
}
|
||||
if (buf_len_used == 0) return;
|
||||
@ -350,20 +340,6 @@ class SimpleSync {
|
||||
return 0;
|
||||
}
|
||||
|
||||
NumberInterface *get_number_if(const char *const key) const {
|
||||
for (const auto ni : number_interfaces) {
|
||||
if (strcmp(ni->key, key) == 0) return ni;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
StringInterface *get_string_if(const char *const key) const {
|
||||
for (const auto ni : string_interfaces) {
|
||||
if (strcmp(ni->key, key) == 0) return ni;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
#ifdef ARDUINO
|
||||
SimpleSync(Print *ostream, function<void(NumberInterface *&, char *, int)> number_update,
|
||||
function<void(StringInterface *&, char *, char *)> string_update)
|
||||
|
Loading…
x
Reference in New Issue
Block a user