RF433any/RF433any.h

712 lines
21 KiB
C++

// RF433any.h
/*
Copyright 2021 Sébastien Millet
`RF433any' is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
`RF433any' is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this program. If not, see
<https://www.gnu.org/licenses>.
*/
#ifndef _RF433ANY_H
#define _RF433ANY_H
// ****************************************************************************
// RF433ANY_TESTPLAN **********************************************************
#if RF433ANY_TESTPLAN == 1
#define RF433ANY_DBG_SIMULATE
#define RF433ANY_DBG_TRACK
#elif RF433ANY_TESTPLAN == 2 // RF433ANY_TESTPLAN
#define RF433ANY_DBG_SIMULATE
#define RF433ANY_DBG_RAWCODE
#elif RF433ANY_TESTPLAN == 3 // RF433ANY_TESTPLAN
#define RF433ANY_DBG_SIMULATE
#define RF433ANY_DBG_DECODER
#elif RF433ANY_TESTPLAN == 4 // RF433ANY_TESTPLAN
#define RF433ANY_DBG_SIMULATE
#define RF433ANY_DBG_DECODER
#define RF433ANY_DBG_SMALL_RECORDED
#define RF433ANY_MAX_SECTIONS 10
#elif RF433ANY_TESTPLAN == 5 // RF433ANY_TESTPLAN
#define RF433ANY_DBG_SIMULATE
#define RF433ANY_DBG_SMALL_RECORDED
#else // RF433ANY_TESTPLAN
#ifdef RF433ANY_TESTPLAN
#error "RF433ANY_TESTPLAN macro has an illegal value."
#endif
// RF433ANY_TESTPLAN **********************************************************
// ****************************************************************************
// It is OK to update the below, because if this code is compiled, then we are
// not in the test plan.
//#define RF433ANY_DBG_SIMULATE
//#define RF433ANY_DBG_TRACE
//#define RF433ANY_DBG_TIMINGS
//#define RF433ANY_DBG_TRACK
//#define RF433ANY_DBG_RAWCODE
//#define RF433ANY_DBG_DECODER
//#define RF433ANY_DBG_SMALL_RECORDED
#endif // RF433ANY_TESTPLAN
#if defined(RF433ANY_DBG_SIMULATE) || defined(RF433ANY_DBG_TRACE) \
|| defined(RF433ANY_DBG_TIMINGS) || defined(RF433ANY_DBG_TRACK) \
|| defined(RF433ANY_DBG_RAWCODE) || defined(RF433ANY_DBG_DECODER)
#define DEBUG
#endif
#ifdef RF433ANY_DBG_SIMULATE
#include "RF433Serial.h"
#define SIM_TIMINGS_LEN 140
#endif
#ifdef DEBUG
#include "RF433Debug.h"
#else
#define dbg(a)
#define dbgf(...)
#endif
#include <Arduino.h>
// Don't uncomment the below unless you know what you are doing!
//#define RF433ANY_DBG_NO_COMPACT_DURATIONS
#ifdef RF433ANY_DBG_NO_COMPACT_DURATIONS
#define duration_t uint16_t
#else
#define duration_t byte
#endif
duration_t compact(uint16_t u);
uint16_t uncompact(duration_t b);
#define RF433ANY_MAX_DURATION 65535
#define RF433ANY_MAX_SEP_DURATION 65535
#ifndef RF433ANY_MAX_SECTIONS
#define RF433ANY_MAX_SECTIONS 8
#endif
// * **** *********************************************************************
// * Band *********************************************************************
// * **** *********************************************************************
#define BAND_MIN_D 64
// IMPORTANT
// Value must be so that BAND_MAX_D * 2 can be stored in a uint16_t.
// That means BAND_MAX_D must be lower than 32768.
#define BAND_MAX_D 30000
struct Band {
uint16_t inf;
uint16_t mid;
uint16_t sup;
bool got_it;
bool test_value_init_if_needed(uint16_t d);
bool test_value(uint16_t d);
void breset();
bool init(uint16_t d);
bool init_sep(uint16_t d);
};
// * **** *********************************************************************
// * Rail *********************************************************************
// * **** *********************************************************************
#ifdef RF433ANY_DBG_SIMULATE
#ifdef RF433ANY_DBG_SMALL_RECORDED
typedef uint8_t recorded_t;
#define FMTRECORDEDT "%02X"
#else
typedef uint32_t recorded_t;
#define FMTRECORDEDT "%08lX"
#endif
#else // RF433ANY_DBG_SIMULATE
typedef uint16_t recorded_t;
#define FMTRECORDEDT "%04lx"
#endif
#define RAIL_MOOD_STRICT 0
#define RAIL_MOOD_LAXIST 1
#define DEFAULT_RAIL_MOOD RAIL_MOOD_LAXIST
#define RAIL_OPEN 0
#define RAIL_FULL 1
#define RAIL_STP_RCVD 2
#define RAIL_CLOSED 3
#define RAIL_ERROR 4
class Rail {
friend class Track;
private:
Band b_short;
Band b_long;
Band b_sep;
byte last_bit_recorded;
recorded_t rec;
byte status;
byte index;
byte mood;
public:
Rail(byte arg_mood);
bool rail_eat(uint16_t d);
void rreset();
void rreset_soft();
#ifdef RF433ANY_DBG_TRACK
void rail_debug() const;
#endif
byte get_band_count() const;
};
// * **** *********************************************************************
// * Misc *********************************************************************
// * **** *********************************************************************
typedef enum {
STS_CONTINUED,
STS_SHORT_SEP,
STS_LONG_SEP,
STS_SEP_SEP,
STS_ERROR
} section_term_status_t;
struct Timings {
uint16_t low_short;
uint16_t low_long;
uint16_t high_short;
uint16_t high_long;
uint16_t sep;
};
struct TimingsExt: public Timings {
uint16_t initseq;
uint16_t first_low;
uint16_t first_high;
uint16_t first_low_ignored;
uint16_t last_low;
};
struct Section {
recorded_t low_rec;
unsigned char low_bits :6;
unsigned char low_bands :2;
recorded_t high_rec;
unsigned char high_bits :6;
unsigned char high_bands :2;
uint16_t first_low;
uint16_t first_high;
uint16_t last_low;
Timings ts;
section_term_status_t sts;
};
struct RawCode {
uint16_t initseq;
uint16_t max_code_d;
byte nb_sections;
Section sections[RF433ANY_MAX_SECTIONS];
void debug_rawcode() const;
};
// * ********* ****************************************************************
// * BitVector ****************************************************************
// * ********* ****************************************************************
// vector-like of the (very) poor man. No time to make it fancier.
// It'll simply accept to add a bit at the beginning (add_bit),
// to get the number of bits and bytes, and access the Nth bit or byte.
// Also, an iterator would be best to walk through bits, but it is 'TO DO' for
// now.
class BitVector {
private:
uint8_t* array;
byte allocated;
byte nb_bits;
public:
BitVector();
BitVector(short arg_nb_bits, short arg_nb_bytes, byte b0, byte b1);
BitVector(short arg_nb_bits, short arg_nb_bytes, byte b0, byte b1,
byte b2);
BitVector(short arg_nb_bits, short arg_nb_bytes, byte b0, byte b1,
byte b2, byte b3);
BitVector(short arg_nb_bits, short arg_nb_bytes, byte b0, byte b1,
byte b2, byte b3, byte b4);
BitVector(short arg_nb_bits, short arg_nb_bytes, byte b0, byte b1,
byte b2, byte b3, byte b4, byte b5);
void prepare_BitVector_construction(short arg_nb_bits,
short arg_nb_bytes, short n);
virtual ~BitVector();
virtual void add_bit(byte v);
virtual int get_nb_bits() const;
virtual byte get_nb_bytes() const;
virtual byte get_nth_bit(byte n) const;
virtual byte get_nth_byte(byte n) const;
virtual char *to_str() const;
virtual short cmp(const BitVector *p) const;
};
// * ******* ******************************************************************
// * Decoder ******************************************************************
// * ******* ******************************************************************
// IMPORTANT
// VALUES ARE NOT ARBITRARY.
// RF433ANY_CONV0 must be 0 and RF433ANY_CONV1 must be 1.
// This is due to the decoding that uses a bit value ultimately coming
// from RF433ANY_CONV0 or RF433ANY_CONV1.
#define RF433ANY_CONV0 0
#define RF433ANY_CONV1 1
enum class Signal {
SHORT,
LONG,
OTHER
};
// FD = Filter Data
// Bit-mask values, to be used in conjunction
#define RF433ANY_FD_ALL 0
#define RF433ANY_FD_DECODED 1
#define RF433ANY_FD_NO_ERROR 2
#define RF433ANY_FD_DEDUP 4
#define RF433ANY_FD_TRI 8
#define RF433ANY_FD_TRN 16
#define RF433ANY_FD_MAN 32
#define RF433ANY_ID_RAW_INCONSISTENT 0
#define RF433ANY_ID_START 1 // Start enumeration of real decoders
#define RF433ANY_ID_RAW_SYNC 1
#define RF433ANY_ID_TRIBIT 2
#define RF433ANY_ID_TRIBIT_INV 3
#define RF433ANY_ID_MANCHESTER 4
#define RF433ANY_ID_RAW_UNKNOWN_CODING 5 // At last we use this one, that'll
// always produce a successful result.
#define RF433ANY_ID_END 5 // End of enumeration of real decoders
#define RF433ANY_ID_ANY_ENCODING 99
class Decoder {
private:
Decoder *next;
byte repeats;
protected:
BitVector* pdata;
byte convention;
byte nb_errors;
TimingsExt tsext;
void add_data_bit(byte valbit);
virtual void add_signal_step(Signal low, Signal high) = 0;
public:
Decoder(byte arg_convention);
virtual ~Decoder();
virtual byte get_id() const = 0;
virtual char get_id_letter() const = 0;
static Decoder *build_decoder(byte id, byte convention);
virtual void add_sync(byte n) { }
virtual byte get_nb_errors() const;
virtual int get_nb_bits() const;
virtual void get_tsext(TimingsExt *p_tsext) const;
virtual void set_ts(const uint16_t& arg_initseq, const Timings& arg_ts);
virtual void decode_section(const Section *psec,
bool is_cont_of_prev_sec);
virtual void take_into_account_first_low_high(const Section *psec,
bool is_cont_of_prev_sec);
virtual uint16_t first_lo_ignored() const;
virtual void attach(Decoder *pdec);
virtual void detach();
virtual bool data_got_decoded() const { return false; }
virtual const BitVector* get_pdata() const;
virtual BitVector* take_away_data();
virtual Decoder* get_next() const { return next; }
virtual void reset_repeats() { repeats = 0; }
virtual void inc_repeats() { ++repeats; }
virtual byte get_repeats() const { return repeats; };
#ifdef RF433ANY_DBG_DECODER
virtual void dbg_data(byte seq) const;
virtual void dbg_meta(byte disp_level) const;
virtual void dbg_decoder(byte disp_level = 1, byte seq = 0) const
= 0;
virtual void dbg_next(byte disp_level, byte seq) const;
#endif
};
// * ********************** ***************************************************
// * DecoderRawInconsistent ***************************************************
// * ********************** ***************************************************
class DecoderRawInconsistent: public Decoder {
public:
DecoderRawInconsistent(): Decoder(RF433ANY_CONV0) { }
~DecoderRawInconsistent() { }
virtual byte get_id() const override {
return RF433ANY_ID_RAW_INCONSISTENT;
}
virtual char get_id_letter() const override { return 'I'; }
virtual void add_signal_step(Signal lo, Signal hi) override { }
#ifdef RF433ANY_DBG_DECODER
virtual void dbg_decoder(byte disp_level, byte seq) const override;
#endif
};
// * ************** ***********************************************************
// * DecoderRawSync ***********************************************************
// * ************** ***********************************************************
class DecoderRawSync: public Decoder {
private:
byte nb_low_high;
Signal sync_shape;
bool sync_shape_set;
public:
DecoderRawSync(byte arg_nb_low_high):
Decoder(RF433ANY_CONV0),
nb_low_high(arg_nb_low_high),
sync_shape_set(false) { }
~DecoderRawSync() { }
virtual byte get_id() const override { return RF433ANY_ID_RAW_SYNC; }
virtual char get_id_letter() const override { return 'S'; }
virtual void add_signal_step(Signal lo, Signal hi) override;
virtual void add_sync(byte n) override;
virtual int get_nb_bits() const override;
#ifdef RF433ANY_DBG_DECODER
virtual void dbg_decoder(byte disp_level, byte seq) const override;
#endif
};
// * *********************** **************************************************
// * DecoderRawUnknownCoding **************************************************
// * *********************** **************************************************
class DecoderRawUnknownCoding: public Decoder {
private:
Signal unused_final_low;
bool terminates_with_sep;
public:
DecoderRawUnknownCoding():
Decoder(RF433ANY_CONV0),
unused_final_low(Signal::OTHER),
terminates_with_sep(false) { }
~DecoderRawUnknownCoding() { }
virtual byte get_id() const override
{ return RF433ANY_ID_RAW_UNKNOWN_CODING; }
virtual char get_id_letter() const override { return 'U'; }
virtual void add_signal_step(Signal lo, Signal hi) override;
#ifdef RF433ANY_DBG_DECODER
virtual void dbg_decoder(byte disp_level, byte seq) const override;
#endif
};
// * ************* ************************************************************
// * DecoderTriBit ************************************************************
// * ************* ************************************************************
class DecoderTriBit: public Decoder {
public:
DecoderTriBit(byte arg_convention = RF433ANY_CONV0)
:Decoder(arg_convention) {
}
~DecoderTriBit() { }
virtual byte get_id() const override { return RF433ANY_ID_TRIBIT; }
virtual char get_id_letter() const override { return 'T'; }
virtual void add_signal_step(Signal low, Signal high)
override;
virtual bool data_got_decoded() const override {
return pdata && pdata->get_nb_bits();
}
#ifdef RF433ANY_DBG_DECODER
virtual void dbg_decoder(byte disp_level, byte seq) const override;
#endif
};
// * **************** *********************************************************
// * DecoderTriBitInv *********************************************************
// * **************** *********************************************************
class DecoderTriBitInv: public Decoder {
private:
bool first_call_to_add_sgn_lo_hi;
Signal unused_initial_low;
Signal last_hi;
public:
DecoderTriBitInv(byte arg_convention = RF433ANY_CONV0)
:Decoder(arg_convention),
first_call_to_add_sgn_lo_hi(true),
unused_initial_low(Signal::OTHER) {
}
~DecoderTriBitInv() { }
virtual byte get_id() const override { return RF433ANY_ID_TRIBIT_INV; }
virtual char get_id_letter() const override { return 'N'; }
virtual void add_signal_step(Signal low, Signal high)
override;
virtual bool data_got_decoded() const override {
return pdata && pdata->get_nb_bits();
}
virtual uint16_t first_lo_ignored() const override;
#ifdef RF433ANY_DBG_DECODER
virtual void dbg_decoder(byte disp_level, byte seq) const override;
#endif
};
// * ***************** ********************************************************
// * DecoderManchester ********************************************************
// * ***************** ********************************************************
class DecoderManchester: public Decoder {
private:
byte buf[3];
byte buf_pos;
// Manchester encoding comes with a mandatory leading 'short low'
// (otherwise we could not distinguish it from the initialization
// sequence).
// Said differently: Manchester needs a leading '0' bit (if
// considering low-then-high is '0'), that is not part of data.
bool leading_lo_hi_has_been_passed;
void add_buf(byte r);
void consume_buf();
public:
DecoderManchester(byte arg_convention = RF433ANY_CONV0);
~DecoderManchester() { }
virtual byte get_id() const override { return RF433ANY_ID_MANCHESTER; }
virtual char get_id_letter() const override { return 'M'; }
virtual void add_signal_step(Signal low, Signal high)
override;
virtual bool data_got_decoded() const override {
return pdata && pdata->get_nb_bits();
}
#ifdef RF433ANY_DBG_DECODER
virtual void dbg_decoder(byte disp_level, byte seq) const override;
#endif
};
// * ***** ********************************************************************
// * Track ********************************************************************
// * ***** ********************************************************************
#define TRACK_MIN_INITSEQ_DURATION 2000
#define TRACK_MIN_BITS 7
// IMPORTANT
// IH_MASK must be equal to the size of IH_timings - 1.
// The size of IH_timings must be a power of 2.
// Thus, IH_MASK allows to quickly calculate modulo, while walking through
// IH_timings.
#define IH_SIZE 4
#define IH_MASK (IH_SIZE - 1)
struct IH_timing_t {
byte r;
uint16_t d;
IH_timing_t() { }
IH_timing_t(const volatile IH_timing_t& t) {
r = t.r;
d = t.d;
}
};
struct callback_t {
byte encoding;
const BitVector *pcode;
void *data;
void (*func)(void *data);
uint32_t min_delay_between_two_calls;
uint32_t last_trigger;
callback_t *next;
};
// NOTE - ABOUT STATIC MEMBER VARIABLES AND FUNCTIONS IN THE TRACK CLASS
// The class is designed so that one object is useful at a time. This comes
// from the fact that we attach interrupt handler to a static method (as is
// mandatory: an object method would not be possible, compiler would block
// because no way to populate 'this' pointer.)
// At last, the distinction between static and non-static members is a bit
// arbitrary.
// I decided that variables and functions _directly_ tied to interrupt handler
// are static, while all others are non-static.
typedef enum {TRK_WAIT, TRK_RECV, TRK_DATA} trk_t;
class Track {
private:
#ifdef RF433ANY_DBG_TIMINGS
static uint16_t ih_dbg_timings[40];
static uint16_t ih_dbg_exec[40];
static unsigned int ih_dbg_pos;
#endif
static byte pin_number;
static volatile IH_timing_t IH_timings[IH_SIZE];
static volatile unsigned char IH_write_head;
static volatile unsigned char IH_read_head;
static byte IH_max_pending_timings;
static bool IH_interrupt_handler_is_attached;
static volatile uint16_t IH_wait_free_last16;
static volatile short IH_wait_free_count_ok;
volatile trk_t trk;
byte count;
Rail r_low;
Rail r_high;
byte prev_r;
uint16_t first_low;
uint16_t first_high;
uint16_t last_low;
RawCode rawcode;
callback_t *head;
bool opt_wait_free_433_before_calling_callbacks;
void reset_border_mgmt();
Decoder* get_data_core(byte convention);
callback_t* get_tail(const callback_t* h);
public:
Track(int arg_pin_number, byte mood = DEFAULT_RAIL_MOOD);
static void ih_handle_interrupt();
static void ih_handle_interrupt_wait_free();
static byte ih_get_max_pending_timings() {
return IH_max_pending_timings;
}
void treset();
void track_eat(byte r, uint16_t d);
#ifdef RF433ANY_DBG_TRACK
void track_debug() const;
#endif
#ifdef RF433ANY_DBG_TIMINGS
void dbg_timings() const;
#endif
trk_t get_trk() const { return trk; }
void force_stop_recv();
void activate_recording();
void deactivate_recording();
bool process_interrupt_timing();
bool do_events();
void wait_free_433();
Decoder* get_data(uint16_t filter, byte convention = RF433ANY_CONV0);
void setopt_wait_free_433_before_calling_callbacks(const bool val);
void register_callback(byte encoding, const BitVector *pcode,
void *data, void (*func)(void *data),
uint32_t min_delay_between_two_calls);
void check_registered_callbacks();
};
#endif // _RF433ANY_H
// vim: ts=4:sw=4:tw=80:et