wip
This commit is contained in:
		
							parent
							
								
									39922749ec
								
							
						
					
					
						commit
						aca4b18125
					
				@ -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 {
 | 
			
		||||
@ -25,9 +30,10 @@ namespace simplesync {
 | 
			
		||||
enum error_t {
 | 
			
		||||
    BUFFER_OVERFLOW   = (-1),
 | 
			
		||||
    INVALID_COMMAND   = (-2),
 | 
			
		||||
    ID_INVALID      = (-3),
 | 
			
		||||
    UNKNOWN_INTERFACE = (-3),
 | 
			
		||||
    OUT_OF_MEMORY     = (-4),
 | 
			
		||||
    CRC_MISSMATCH     = (-5),
 | 
			
		||||
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
inline int cobs_encode(uint8_t *buf_in, unsigned int buf_in_size, uint8_t *buf_out,
 | 
			
		||||
@ -128,47 +134,78 @@ inline uint16_t calc_fletcher_checksum(uint8_t *buf, unsigned int buf_size) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename time_t, typename timedelta_t, unsigned int BUF_SIZE = 256,
 | 
			
		||||
          unsigned int str_len_max = 32>
 | 
			
		||||
          bool DYNAMIC_INTERFACES = false>
 | 
			
		||||
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;
 | 
			
		||||
 | 
			
		||||
        void *data;
 | 
			
		||||
        bool data_owned;
 | 
			
		||||
 | 
			
		||||
        Interface(uint8_t type, string key, void *data,
 | 
			
		||||
                  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),
 | 
			
		||||
              data(data), data_owned(false) {}
 | 
			
		||||
        ~Interface() {
 | 
			
		||||
            if (data != nullptr && data_owned) switch (type) {
 | 
			
		||||
                case 0x01:
 | 
			
		||||
                    delete (int *)data;
 | 
			
		||||
                    break;
 | 
			
		||||
                case 0x02:
 | 
			
		||||
                    delete (string *)data;
 | 
			
		||||
                    break;
 | 
			
		||||
                default:
 | 
			
		||||
                    free(data);
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    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);
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
    // int parse_number(uint8_t *buf, unsigned int buf_size, int* value){
 | 
			
		||||
    //     return decode_varint(&buf[parsed], *value);
 | 
			
		||||
    // }
 | 
			
		||||
 | 
			
		||||
    std::vector<NumberInterface *> number_interfaces;
 | 
			
		||||
    std::vector<StringInterface *> string_interfaces;
 | 
			
		||||
    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;
 | 
			
		||||
    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) {}
 | 
			
		||||
    SimpleSync(function<int(uint8_t *, unsigned int)> write_pkg) : write_pkg(write_pkg) {}
 | 
			
		||||
 | 
			
		||||
    Interface *get_interface(const uint8_t type, const char *const key) const {
 | 
			
		||||
        for (auto &i : interfaces) {
 | 
			
		||||
            if (i->type == type && strcmp(i->key.c_str(), key) == 0) {
 | 
			
		||||
                return i.get();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return nullptr;
 | 
			
		||||
    }
 | 
			
		||||
    Interface *get_or_create_interface(uint8_t type, const char *const key) {
 | 
			
		||||
        Interface *i_exists = get_interface(type, key);
 | 
			
		||||
        if (i_exists) {
 | 
			
		||||
            return i_exists;
 | 
			
		||||
        }
 | 
			
		||||
        if (DYNAMIC_INTERFACES) {
 | 
			
		||||
            switch (type) {
 | 
			
		||||
            case 0x01:
 | 
			
		||||
                return Number(*this, key);
 | 
			
		||||
            case 0x02:
 | 
			
		||||
                return String(*this, key);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return nullptr;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    int parse_pkg(uint8_t *buf, unsigned int buf_size) {
 | 
			
		||||
        if (buf_size < 4) return CRC_MISSMATCH;
 | 
			
		||||
@ -176,48 +213,22 @@ class SimpleSync {
 | 
			
		||||
        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);
 | 
			
		||||
                if (ni == nullptr) return UNKNOWN_INTERFACE;
 | 
			
		||||
                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:
 | 
			
		||||
@ -236,69 +247,54 @@ class SimpleSync {
 | 
			
		||||
        write_pkg(cobs_buf, cobs_buf_needed);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  private:
 | 
			
		||||
    void encode_and_write_pkg(uint8_t *buf, unsigned int buf_size) {
 | 
			
		||||
        if (buf_size <= 2) {
 | 
			
		||||
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        uint8_t cobs_buf[BUF_SIZE];
 | 
			
		||||
        uint16_t crc                 = calc_fletcher_checksum(buf, buf_size);
 | 
			
		||||
        buf[buf_size++]              = crc >> 8;
 | 
			
		||||
        buf[buf_size++]              = crc & 0xFF;
 | 
			
		||||
        unsigned int cobs_buf_needed = cobs_encode(buf, buf_size, cobs_buf, BUF_SIZE);
 | 
			
		||||
        write_pkg(cobs_buf, cobs_buf_needed);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  public:
 | 
			
		||||
    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) {
 | 
			
		||||
                    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);
 | 
			
		||||
                    encode_and_write_pkg(buf, buf_len_used);
 | 
			
		||||
                    buf_len_used = 0;
 | 
			
		||||
                }
 | 
			
		||||
                buf[buf_len_used++] = 0x01;
 | 
			
		||||
                memcpy((char *)&buf[buf_len_used], ni->key, strl);
 | 
			
		||||
                buf[buf_len_used++] = ni->type;
 | 
			
		||||
                memcpy((char *)&buf[buf_len_used], ni->key.c_str(), strl);
 | 
			
		||||
                buf_len_used += strl;
 | 
			
		||||
                buf_len_used += encode_varint(ni->value, &buf[buf_len_used]);
 | 
			
		||||
                int pack_len = ni->pack(&buf[buf_len_used], BUF_SIZE - buf_len_used);
 | 
			
		||||
                if (pack_len < 0) {
 | 
			
		||||
                    // ERROR -> return
 | 
			
		||||
                    buf_len_used = 0;
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
                buf_len_used += pack_len;
 | 
			
		||||
                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);
 | 
			
		||||
        encode_and_write_pkg(buf, buf_len_used);
 | 
			
		||||
        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;
 | 
			
		||||
                ni->last_send      = time;
 | 
			
		||||
                ni->send_requested = false;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        if (buf_len_used == 0) return;
 | 
			
		||||
        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);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    int parse_stream_buf(uint8_t *buf, unsigned int buf_size) {
 | 
			
		||||
        int parsed = 0;
 | 
			
		||||
@ -350,31 +346,27 @@ 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;
 | 
			
		||||
        }
 | 
			
		||||
    int *get_number(const char *const key) {
 | 
			
		||||
        Interface *i = get_interface(0x01, key);
 | 
			
		||||
        if (i) return (int *)i->data;
 | 
			
		||||
        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;
 | 
			
		||||
        }
 | 
			
		||||
    string *get_string(const char *const key) {
 | 
			
		||||
        Interface *i = get_interface(0x02, key);
 | 
			
		||||
        if (i) return (string *)i->data;
 | 
			
		||||
        return nullptr;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
#ifdef ARDUINO
 | 
			
		||||
    SimpleSync(Print *ostream, function<void(NumberInterface *&, char *, int)> number_update,
 | 
			
		||||
               function<void(StringInterface *&, char *, char *)> string_update)
 | 
			
		||||
        : write_pkg([ostream](uint8_t *buf, unsigned int buf_size) {
 | 
			
		||||
    SimpleSync(Print *ostream)
 | 
			
		||||
        : SimpleSync([ostream](uint8_t *buf, unsigned int buf_size) {
 | 
			
		||||
              if (ostream) {
 | 
			
		||||
                  ostream->write(buf, buf_size);
 | 
			
		||||
                  return 0;
 | 
			
		||||
              }
 | 
			
		||||
              return -1;
 | 
			
		||||
          }),
 | 
			
		||||
          number_update(number_update), string_update(string_update) {}
 | 
			
		||||
          }) {}
 | 
			
		||||
    int handle_stream(Stream &in_stream) {
 | 
			
		||||
        unsigned int buf_new_size = in_stream.available();
 | 
			
		||||
        if (buf_new_size + stream_buf_used > BUF_SIZE) {
 | 
			
		||||
@ -389,82 +381,107 @@ class SimpleSync {
 | 
			
		||||
    }
 | 
			
		||||
#endif
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template <typename time_t, typename timedelta_t, unsigned int buf_len = 256,
 | 
			
		||||
          unsigned int str_len_max = 32>
 | 
			
		||||
class SimpleSyncStatic : public SimpleSync<time_t, timedelta_t, buf_len, str_len_max> {
 | 
			
		||||
  public:
 | 
			
		||||
    SimpleSyncStatic(function<int(uint8_t *, unsigned int)> write_pkg)
 | 
			
		||||
        : SimpleSync<time_t, timedelta_t, buf_len, str_len_max>(write_pkg, nullptr, nullptr){};
 | 
			
		||||
#ifdef ARDUINO
 | 
			
		||||
    SimpleSyncStatic(Print *ostream)
 | 
			
		||||
        : SimpleSync<time_t, timedelta_t, buf_len, str_len_max>(ostream, nullptr, nullptr) {}
 | 
			
		||||
#endif
 | 
			
		||||
};
 | 
			
		||||
template <typename time_t, typename timedelta_t, unsigned int buf_len = 256,
 | 
			
		||||
          unsigned int str_len_max = 32>
 | 
			
		||||
class SimpleSyncDynamic : public SimpleSync<time_t, timedelta_t, buf_len, str_len_max> {
 | 
			
		||||
    std::vector<typename SimpleSync<time_t, timedelta_t, buf_len, str_len_max>::NumberInterface *>
 | 
			
		||||
        dyn_number_interfaces;
 | 
			
		||||
    std::vector<typename SimpleSync<time_t, timedelta_t, buf_len, str_len_max>::StringInterface *>
 | 
			
		||||
        dyn_string_interfaces;
 | 
			
		||||
    std::vector<char *> dyn_keys;
 | 
			
		||||
 | 
			
		||||
  public:
 | 
			
		||||
    SimpleSyncDynamic(
 | 
			
		||||
        function<int(uint8_t *, unsigned int)> write_pkg,
 | 
			
		||||
        function<
 | 
			
		||||
            void(typename SimpleSync<time_t, timedelta_t, buf_len, str_len_max>::NumberInterface *&,
 | 
			
		||||
                 char *, int)>
 | 
			
		||||
            dyn_number_update,
 | 
			
		||||
        function<
 | 
			
		||||
            void(typename SimpleSync<time_t, timedelta_t, buf_len, str_len_max>::StringInterface *&,
 | 
			
		||||
                 char *, char *)>
 | 
			
		||||
            dyn_string_update,
 | 
			
		||||
        timedelta_t dyn_update_feq)
 | 
			
		||||
        : SimpleSync<time_t, timedelta_t, buf_len, str_len_max>(
 | 
			
		||||
              write_pkg,
 | 
			
		||||
              [this, dyn_number_update, dyn_update_feq](
 | 
			
		||||
                  typename SimpleSync<time_t, timedelta_t, buf_len, str_len_max>::NumberInterface *
 | 
			
		||||
                      &ni,
 | 
			
		||||
                  char *key, int value) {
 | 
			
		||||
                  if (ni == nullptr) {
 | 
			
		||||
                      auto allocated_key = (char *)malloc(strlen(key) + 1);
 | 
			
		||||
                      strcpy(allocated_key, key);
 | 
			
		||||
                      dyn_keys.push_back(allocated_key);
 | 
			
		||||
                      ni                 = new SimpleSync<time_t, timedelta_t, buf_len,
 | 
			
		||||
                                          str_len_max>::NumberInterface(*this, allocated_key,
 | 
			
		||||
                                                                                        dyn_update_feq);
 | 
			
		||||
                      ni->send_requested = false;
 | 
			
		||||
                      dyn_number_interfaces.push_back(ni);
 | 
			
		||||
                  }
 | 
			
		||||
                  dyn_number_update(ni, key, value);
 | 
			
		||||
template <typename time_t, typename timedelta_t, unsigned int BUF_SIZE = 256,
 | 
			
		||||
          bool DYNAMIC_INTERFACES = false>
 | 
			
		||||
SimpleSync<time_t, timedelta_t, BUF_SIZE, DYNAMIC_INTERFACES>::Interface *
 | 
			
		||||
NumberPtr(SimpleSync<time_t, timedelta_t, BUF_SIZE, DYNAMIC_INTERFACES> &sync, string key,
 | 
			
		||||
          int *value_ptr) {
 | 
			
		||||
    sync.interfaces.push_back(std::unique_ptr<typename SimpleSync<time_t, timedelta_t, BUF_SIZE,
 | 
			
		||||
                                                                  DYNAMIC_INTERFACES>::Interface>(
 | 
			
		||||
        new SimpleSync<time_t, timedelta_t, BUF_SIZE, DYNAMIC_INTERFACES>::Interface(
 | 
			
		||||
            0x01, key, (void *)value_ptr,
 | 
			
		||||
            [=](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);
 | 
			
		||||
            },
 | 
			
		||||
              [this, dyn_string_update, dyn_update_feq](
 | 
			
		||||
                  typename SimpleSync<time_t, timedelta_t, buf_len, str_len_max>::StringInterface *
 | 
			
		||||
                      &ni,
 | 
			
		||||
                  char *key, char *value) {
 | 
			
		||||
                  if (ni == nullptr) {
 | 
			
		||||
                      auto allocated_key = (char *)malloc(strlen(key) + 1);
 | 
			
		||||
                      strcpy(allocated_key, key);
 | 
			
		||||
                      dyn_keys.push_back(allocated_key);
 | 
			
		||||
                      ni                 = new SimpleSync<time_t, timedelta_t, buf_len,
 | 
			
		||||
                                          str_len_max>::StringInterface(*this, allocated_key,
 | 
			
		||||
                                                                                        dyn_update_feq);
 | 
			
		||||
                      ni->send_requested = false;
 | 
			
		||||
                      dyn_string_interfaces.push_back(ni);
 | 
			
		||||
            [=](uint8_t *buf, unsigned int buf_size) -> int { /* unpack */
 | 
			
		||||
                                                              buf_size = 1 * buf_size;
 | 
			
		||||
                                                              return decode_varint(buf, *value_ptr);
 | 
			
		||||
            })));
 | 
			
		||||
    return sync.interfaces.back().get();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename time_t, typename timedelta_t, unsigned int BUF_SIZE = 256,
 | 
			
		||||
          bool DYNAMIC_INTERFACES = false>
 | 
			
		||||
SimpleSync<time_t, timedelta_t, BUF_SIZE, DYNAMIC_INTERFACES>::Interface *
 | 
			
		||||
NumberPtrPeriodic(SimpleSync<time_t, timedelta_t, BUF_SIZE, DYNAMIC_INTERFACES> &sync, string key,
 | 
			
		||||
                  int *value_ptr, timedelta_t update_interval) {
 | 
			
		||||
    auto i = NumberPtr(sync, key, value_ptr);
 | 
			
		||||
    if (i) {
 | 
			
		||||
        i->update_interval     = update_interval;
 | 
			
		||||
        i->update_periodically = true;
 | 
			
		||||
    }
 | 
			
		||||
                  dyn_string_update(ni, key, value);
 | 
			
		||||
              }){};
 | 
			
		||||
    ~SimpleSyncDynamic() {
 | 
			
		||||
        for (auto i : dyn_number_interfaces) delete i;
 | 
			
		||||
        for (auto i : dyn_string_interfaces) delete i;
 | 
			
		||||
        for (auto i : dyn_keys) free(i);
 | 
			
		||||
    };
 | 
			
		||||
#ifdef ARDUINO
 | 
			
		||||
    SimpleSyncDynamic(Print *ostream)
 | 
			
		||||
        : SimpleSync<time_t, timedelta_t, buf_len, str_len_max>(ostream, nullptr, nullptr) {}
 | 
			
		||||
#endif
 | 
			
		||||
};
 | 
			
		||||
    return i;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename time_t, typename timedelta_t, unsigned int BUF_SIZE = 256,
 | 
			
		||||
          bool DYNAMIC_INTERFACES = false>
 | 
			
		||||
SimpleSync<time_t, timedelta_t, BUF_SIZE, DYNAMIC_INTERFACES>::Interface *
 | 
			
		||||
Number(SimpleSync<time_t, timedelta_t, BUF_SIZE, DYNAMIC_INTERFACES> &sync, string key) {
 | 
			
		||||
    auto v_ptr = new int;
 | 
			
		||||
    auto i     = NumberPtr(sync, key, v_ptr);
 | 
			
		||||
    if (i)
 | 
			
		||||
        i->data_owned = true;
 | 
			
		||||
    else
 | 
			
		||||
        delete v_ptr;
 | 
			
		||||
    return i;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename time_t, typename timedelta_t, unsigned int BUF_SIZE = 256,
 | 
			
		||||
          bool DYNAMIC_INTERFACES = false>
 | 
			
		||||
SimpleSync<time_t, timedelta_t, BUF_SIZE, DYNAMIC_INTERFACES>::Interface *
 | 
			
		||||
StringPtr(SimpleSync<time_t, timedelta_t, BUF_SIZE, DYNAMIC_INTERFACES> &sync, string key,
 | 
			
		||||
          string *value_ptr) {
 | 
			
		||||
    sync.interfaces.push_back(
 | 
			
		||||
        std::unique_ptr<
 | 
			
		||||
            typename SimpleSync<time_t, timedelta_t, BUF_SIZE, DYNAMIC_INTERFACES>::Interface>(
 | 
			
		||||
            new SimpleSync<time_t, timedelta_t, BUF_SIZE, DYNAMIC_INTERFACES>::Interface(
 | 
			
		||||
                0x02, key, (void *)value_ptr,
 | 
			
		||||
                [=](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;
 | 
			
		||||
                })));
 | 
			
		||||
    return sync.interfaces.back().get();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename time_t, typename timedelta_t, unsigned int BUF_SIZE = 256,
 | 
			
		||||
          bool DYNAMIC_INTERFACES = false>
 | 
			
		||||
SimpleSync<time_t, timedelta_t, BUF_SIZE, DYNAMIC_INTERFACES>::Interface *
 | 
			
		||||
StringPtrPeriodic(SimpleSync<time_t, timedelta_t, BUF_SIZE, DYNAMIC_INTERFACES> &sync, string key,
 | 
			
		||||
                  string *value_ptr, timedelta_t update_interval) {
 | 
			
		||||
    auto i = StringPtr(sync, key, value_ptr);
 | 
			
		||||
    if (i) {
 | 
			
		||||
        i->update_interval     = update_interval;
 | 
			
		||||
        i->update_periodically = true;
 | 
			
		||||
    }
 | 
			
		||||
    return i;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename time_t, typename timedelta_t, unsigned int BUF_SIZE = 256,
 | 
			
		||||
          bool DYNAMIC_INTERFACES = false>
 | 
			
		||||
SimpleSync<time_t, timedelta_t, BUF_SIZE, DYNAMIC_INTERFACES>::Interface *
 | 
			
		||||
String(SimpleSync<time_t, timedelta_t, BUF_SIZE, DYNAMIC_INTERFACES> &sync, string key) {
 | 
			
		||||
    auto v_ptr = new string;
 | 
			
		||||
    auto i     = StringPtr(sync, key, v_ptr);
 | 
			
		||||
    if (i)
 | 
			
		||||
        i->data_owned = true;
 | 
			
		||||
    else
 | 
			
		||||
        delete v_ptr;
 | 
			
		||||
    return i;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // namespace simplesync
 | 
			
		||||
#endif // SIMPLESYNC_HPP
 | 
			
		||||
 | 
			
		||||
@ -8,44 +8,42 @@
 | 
			
		||||
#include "simplesync.hpp"
 | 
			
		||||
 | 
			
		||||
namespace py = pybind11;
 | 
			
		||||
typedef simplesync::SimpleSyncDynamic<std::chrono::time_point<std::chrono::steady_clock>,
 | 
			
		||||
                                      std::chrono::nanoseconds, 1024>
 | 
			
		||||
typedef simplesync::SimpleSync<std::chrono::time_point<std::chrono::steady_clock>,
 | 
			
		||||
                               std::chrono::nanoseconds, 1024, true>
 | 
			
		||||
    SimpleS;
 | 
			
		||||
 | 
			
		||||
PYBIND11_MODULE(pysimplesync, m) {
 | 
			
		||||
    py::class_<SimpleS>(m, "SimpleSync")
 | 
			
		||||
        .def(py::init([]() {
 | 
			
		||||
            return std::unique_ptr<SimpleS>(new SimpleS(
 | 
			
		||||
                [](uint8_t *buf, unsigned int buf_size) {
 | 
			
		||||
            return std::unique_ptr<SimpleS>(new SimpleS([](uint8_t *buf, unsigned int buf_size) {
 | 
			
		||||
                py::print(py::bytes((char *)buf, buf_size));
 | 
			
		||||
                return 0;
 | 
			
		||||
                },
 | 
			
		||||
                [](SimpleS::NumberInterface *&, char *key, int value) {
 | 
			
		||||
                    py::print(std::string(key), ": ", value);
 | 
			
		||||
                },
 | 
			
		||||
                nullptr, std::chrono::nanoseconds::max()));
 | 
			
		||||
            }));
 | 
			
		||||
        }))
 | 
			
		||||
        .def(
 | 
			
		||||
            "__getitem__",
 | 
			
		||||
            [](SimpleS &s, const std::string &key) -> py::object {
 | 
			
		||||
                auto ni = s.get_number_if(key.c_str());
 | 
			
		||||
                if (ni) return py::int_(ni->value);
 | 
			
		||||
                auto si = s.get_string_if(key.c_str());
 | 
			
		||||
                if (si) return py::str(si->value);
 | 
			
		||||
                auto ni = s.get_number(key.c_str());
 | 
			
		||||
                if (ni) return py::int_(*ni);
 | 
			
		||||
                auto si = s.get_string(key.c_str());
 | 
			
		||||
                if (si) return py::str(*si);
 | 
			
		||||
                throw pybind11::key_error();
 | 
			
		||||
            },
 | 
			
		||||
            py::is_operator())
 | 
			
		||||
        .def(
 | 
			
		||||
            "__getitem__",
 | 
			
		||||
            [](SimpleS &s, unsigned int i) -> py::tuple {
 | 
			
		||||
                if (i < s.number_interfaces.size()) {
 | 
			
		||||
                    return py::make_tuple(py::str(s.number_interfaces[i]->key),
 | 
			
		||||
                                          py::int_(s.number_interfaces[i]->value));
 | 
			
		||||
                if (i < s.interfaces.size()) {
 | 
			
		||||
                    auto &interface = s.interfaces[i];
 | 
			
		||||
                    if (!interface) throw pybind11::index_error();
 | 
			
		||||
                    switch (interface->type) {
 | 
			
		||||
                    case 0x01:
 | 
			
		||||
                        return py::make_tuple(py::str(interface->key),
 | 
			
		||||
                                              py::int_(*s.get_number(interface->key.c_str())));
 | 
			
		||||
                    case 0x02:
 | 
			
		||||
                        return py::make_tuple(py::str(interface->key),
 | 
			
		||||
                                              py::str(*s.get_string(interface->key.c_str())));
 | 
			
		||||
                    }
 | 
			
		||||
                i -= s.number_interfaces.size();
 | 
			
		||||
                if (i < s.string_interfaces.size()) {
 | 
			
		||||
                    return py::make_tuple(py::str(s.string_interfaces[i]->key),
 | 
			
		||||
                                          py::str(s.string_interfaces[i]->value));
 | 
			
		||||
                }
 | 
			
		||||
                throw pybind11::index_error();
 | 
			
		||||
            },
 | 
			
		||||
@ -54,19 +52,16 @@ PYBIND11_MODULE(pysimplesync, m) {
 | 
			
		||||
            "__setitem__",
 | 
			
		||||
            [](SimpleS &s, const std::string &key, py::object value) {
 | 
			
		||||
                if (py::isinstance<py::int_>(value)) {
 | 
			
		||||
                    auto ni = s.get_number_if(key.c_str());
 | 
			
		||||
                    auto ni = s.get_or_create_interface(0x01, key.c_str());
 | 
			
		||||
                    if (ni) {
 | 
			
		||||
                        ni->value          = value.cast<int>();
 | 
			
		||||
                        *(int *)ni->data   = value.cast<int>();
 | 
			
		||||
                        ni->send_requested = true;
 | 
			
		||||
                        return;
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                else if (py::isinstance<py::str>(value)) {
 | 
			
		||||
                    auto ni = s.get_string_if(key.c_str());
 | 
			
		||||
                } else if (py::isinstance<py::str>(value)) {
 | 
			
		||||
                    auto ni = s.get_or_create_interface(0x02, key.c_str());
 | 
			
		||||
                    if (ni) {
 | 
			
		||||
                        if(value.cast<std::string>().length() > SimpleS::STR_LEN_MAX)
 | 
			
		||||
                          throw pybind11::buffer_error();
 | 
			
		||||
                        strcpy(ni->value, value.cast<std::string>().c_str());
 | 
			
		||||
                        *(std::string *)ni->data = value.cast<std::string>();
 | 
			
		||||
                        ni->send_requested       = true;
 | 
			
		||||
                        return;
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
@ -1,5 +1,6 @@
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
#include <cstring>
 | 
			
		||||
#include <iostream>
 | 
			
		||||
#include <gtest/gtest.h>
 | 
			
		||||
 | 
			
		||||
#include "simplesync.hpp"
 | 
			
		||||
@ -46,33 +47,43 @@ unsigned int buf_used = 0;
 | 
			
		||||
 | 
			
		||||
TEST(simplesync_test, encode_decode) {
 | 
			
		||||
    buf_used = 0;
 | 
			
		||||
    typedef simplesync::SimpleSyncStatic<int, int, 999> S;
 | 
			
		||||
    S s([](uint8_t *buf, unsigned int buf_size) {
 | 
			
		||||
    typedef simplesync::SimpleSync<int, int, 512, true> S;
 | 
			
		||||
    S s_send([](uint8_t *buf, unsigned int buf_size) {
 | 
			
		||||
        memcpy(stream_buf + buf_used, buf, buf_size);
 | 
			
		||||
        buf_used += buf_size;
 | 
			
		||||
        return 0;
 | 
			
		||||
    });
 | 
			
		||||
    S s_recv([](uint8_t *, unsigned int) {
 | 
			
		||||
        return 0;
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    S::NumberInterface n1(s, (char *)"n1", 0);
 | 
			
		||||
    S::StringInterface s1(s, (char *)"s1", 0);
 | 
			
		||||
    S::NumberInterface n2(s, (char *)"n2", 2);
 | 
			
		||||
 | 
			
		||||
    n1.value = 4;
 | 
			
		||||
    strcpy(s1.value, "hallo");
 | 
			
		||||
    n2.value = 2;
 | 
			
		||||
    int n1 = 4;
 | 
			
		||||
    int n2 = 2;
 | 
			
		||||
    std::string str = "hello";
 | 
			
		||||
    NumberPtrPeriodic(s_send, "n1",&n1,0);
 | 
			
		||||
    NumberPtrPeriodic(s_send, "n2",&n2,2);
 | 
			
		||||
    StringPtrPeriodic(s_send, "s1",&str, 0);
 | 
			
		||||
 | 
			
		||||
    for (int time = 0; time < 5; time += 1) {
 | 
			
		||||
        buf_used = 0;
 | 
			
		||||
        s.update(time);
 | 
			
		||||
        s.update(time);
 | 
			
		||||
        s_send.update(time);
 | 
			
		||||
        s_send.update(time);
 | 
			
		||||
        for(unsigned int i = 0;i < buf_used; i+=1) std::cout << std::hex <<(int) stream_buf[i] << " ";
 | 
			
		||||
        std::cout << std::dec << std::endl;
 | 
			
		||||
        
 | 
			
		||||
        unsigned int parsed = 0;
 | 
			
		||||
        for (unsigned int i = 1; i <= buf_used; i += 1)
 | 
			
		||||
            parsed += s.parse_stream_buf(stream_buf + parsed, i - parsed);
 | 
			
		||||
            parsed += s_recv.parse_stream_buf(stream_buf + parsed, i - parsed);
 | 
			
		||||
        ASSERT_EQ(parsed, buf_used);
 | 
			
		||||
    }
 | 
			
		||||
    ASSERT_EQ(n1.value, 4);
 | 
			
		||||
    ASSERT_EQ(n2.value, 2);
 | 
			
		||||
    ASSERT_STREQ(s1.value,"hallo");
 | 
			
		||||
    str = "hollo2";
 | 
			
		||||
    ASSERT_EQ(*s_recv.get_number((char*)"n1"), n1);
 | 
			
		||||
    ASSERT_EQ(*s_recv.get_number((char*)"n2"), n2);
 | 
			
		||||
    ASSERT_STREQ(s_send.get_string((char*)"s1")->c_str(),"hollo2");
 | 
			
		||||
    ASSERT_STREQ(str.c_str(),"hollo2");
 | 
			
		||||
    ASSERT_STREQ(s_recv.get_string((char*)"s1")->c_str(),"hello");
 | 
			
		||||
    ASSERT_EQ(4, n1);
 | 
			
		||||
    ASSERT_EQ(2, n2);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int main(int argc, char **argv) {
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user