mirror of
https://github.com/esphome/esphome.git
synced 2026-10-28 00:42:11 +00:00
Compare commits
10
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5cd8781a94 | ||
|
|
ff26d32406 | ||
|
|
2df80fbf71 | ||
|
|
470f7eb51d | ||
|
|
e7b2dfed57 | ||
|
|
83080c4560 | ||
|
|
104cb09475 | ||
|
|
a7824ed4e7 | ||
|
|
6420db90b1 | ||
|
|
d3c2a7c734 |
No files matched your search
@@ -22,7 +22,7 @@ CONF_CUSTOM_PATTERNS = "custom_patterns"
|
||||
CONF_SKIP_CRC = "skip_crc"
|
||||
CONF_DEFAULT_OBIS = "default_obis"
|
||||
|
||||
DLMS_PARSER_VERSION = "2.2.2"
|
||||
DLMS_PARSER_VERSION = "2.2.0"
|
||||
|
||||
dlms_meter_component_ns = cg.esphome_ns.namespace("dlms_meter")
|
||||
DlmsMeterComponent = dlms_meter_component_ns.class_(
|
||||
|
||||
@@ -2389,9 +2389,7 @@ FRAMEWORK_SCHEMA = cv.Schema(
|
||||
cv.Schema(
|
||||
{
|
||||
cv.Required(CONF_NAME): cv.string_strict,
|
||||
cv.Optional(CONF_SOURCE): cv.All(
|
||||
cv.string_strict, cv.Length(min=1)
|
||||
),
|
||||
cv.Optional(CONF_SOURCE): cv.git_ref,
|
||||
cv.Optional(CONF_REF): cv.string,
|
||||
cv.Optional(CONF_PATH): cv.string,
|
||||
}
|
||||
|
||||
@@ -373,7 +373,7 @@ void ESPHomeOTAComponent::handle_handshake_() {
|
||||
// Value initialized: a corrupt stream that back references the
|
||||
// window before it is filled then copies zeros, never stale memory.
|
||||
// Default placement, PSRAM first where present: the session lives for one
|
||||
// upload and keeps 4.9 KB of internal heap free while it runs
|
||||
// upload and keeps 6.0 KB of internal heap free while it runs
|
||||
this->inflate_ = RAMAllocator<InflateSession>().make_unique();
|
||||
if (this->inflate_ != nullptr) {
|
||||
this->handshake_buf_[1] |= SERVER_FEATURE_SUPPORTS_DEFLATE;
|
||||
|
||||
@@ -36,7 +36,10 @@
|
||||
* Altered for ESPHome: this is the raw deflate decoder from uzlib's
|
||||
* tinflate.c (v2.9.5) with the gzip/zlib header parsers, checksums,
|
||||
* runtime table builder and in-memory (non ring window) output path
|
||||
* removed, and the public names prefixed with ota_inflate.
|
||||
* removed, and the public names prefixed with ota_inflate. Symbols are
|
||||
* decoded from a 32 bit bit buffer through 9 bit lookup tables, with a
|
||||
* fast loop for when a whole symbol fits in both the input and the output,
|
||||
* and the output is written straight into the ring window.
|
||||
*/
|
||||
|
||||
#include "ota_esphome_inflate.h"
|
||||
@@ -49,16 +52,6 @@
|
||||
#define TINF_DICT_ERROR OTA_INFLATE_DICT_ERROR
|
||||
#define TINF_DATA struct OtaInflateState
|
||||
#define TINF_TREE struct OtaInflateTree
|
||||
#define TINF_ARRAY_SIZE(arr) (sizeof(arr) / sizeof(*(arr)))
|
||||
|
||||
/* every output byte also goes into the ring window */
|
||||
#define TINF_PUT(d, c) \
|
||||
{ \
|
||||
*d->dest++ = c; \
|
||||
d->dict_ring[d->dict_idx++] = c; \
|
||||
if (d->dict_idx == d->dict_size) \
|
||||
d->dict_idx = 0; \
|
||||
}
|
||||
|
||||
/* --------------------------------------------------- *
|
||||
* -- constant tables (upstream builds them at runtime) -- *
|
||||
@@ -82,34 +75,52 @@ static const unsigned char CLCIDX[] = {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4,
|
||||
* -- utility functions -- *
|
||||
* ----------------------- */
|
||||
|
||||
/* given an array of code lengths, build a tree */
|
||||
static void tinf_build_tree(TINF_TREE *t, const unsigned char *lengths, unsigned int num) {
|
||||
unsigned short offs[16];
|
||||
unsigned int i, sum;
|
||||
enum {
|
||||
LIT_FAST_BITS = OTA_INFLATE_LIT_FAST_BITS,
|
||||
DIST_FAST_BITS = OTA_INFLATE_DIST_FAST_BITS,
|
||||
/* a lookup table entry is (code length << SYM_BITS) | symbol; 0 marks a longer code */
|
||||
SYM_BITS = 9,
|
||||
SYM_MASK = (1 << SYM_BITS) - 1,
|
||||
/* input bytes one pass of the fast loop may take: three refills of up to 4 bytes */
|
||||
FAST_IN_MIN = 12,
|
||||
};
|
||||
|
||||
/* given an array of code lengths, build a tree and its lookup table */
|
||||
static void tinf_build_tree(TINF_TREE *t, const unsigned char *lengths, unsigned int num, unsigned int fast_bits) {
|
||||
const unsigned int fast_size = 1u << fast_bits;
|
||||
unsigned short offs[16], next[16];
|
||||
unsigned int i, sum, code;
|
||||
|
||||
/* clear code length count table */
|
||||
for (i = 0; i < 16; ++i)
|
||||
t->table[i] = 0;
|
||||
|
||||
/* scan symbol lengths, and sum code length counts */
|
||||
for (i = 0; i < num; ++i)
|
||||
t->table[lengths[i]]++;
|
||||
|
||||
/* In the lengths array, 0 means unused code. So, t->table[0] now contains
|
||||
number of unused codes. But table's purpose is to contain # of codes of
|
||||
particular length, and there're 0 codes of length 0. */
|
||||
t->table[0] = 0;
|
||||
|
||||
/* compute offset table for distribution sort */
|
||||
for (sum = 0, i = 0; i < 16; ++i) {
|
||||
for (sum = 0, code = 0, i = 0; i < 16; ++i) {
|
||||
offs[i] = sum;
|
||||
sum += t->table[i];
|
||||
if (i > 0)
|
||||
code = (code + t->table[i - 1]) << 1;
|
||||
next[i] = code;
|
||||
}
|
||||
|
||||
/* create code->symbol translation table (symbols sorted by code) */
|
||||
for (i = 0; i < fast_size; ++i)
|
||||
t->fast[i] = 0;
|
||||
|
||||
for (i = 0; i < num; ++i) {
|
||||
if (lengths[i])
|
||||
t->trans[offs[lengths[i]]++] = i;
|
||||
unsigned int len = lengths[i];
|
||||
if (!len)
|
||||
continue;
|
||||
t->trans[offs[len]++] = i;
|
||||
if (len <= fast_bits) {
|
||||
/* codes arrive MSB first, the bit buffer is LSB first */
|
||||
unsigned int c = next[len]++, rev = 0, j;
|
||||
for (j = 0; j < len; ++j, c >>= 1)
|
||||
rev = (rev << 1) | (c & 1);
|
||||
for (j = rev; j < fast_size; j += 1u << len)
|
||||
t->fast[j] = (unsigned short) ((len << SYM_BITS) | i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -117,89 +128,78 @@ static void tinf_build_tree(TINF_TREE *t, const unsigned char *lengths, unsigned
|
||||
* -- decode functions -- *
|
||||
* ---------------------- */
|
||||
|
||||
static unsigned char uzlib_get_byte(TINF_DATA *d) {
|
||||
/* If end of source buffer is not reached, return next byte from source
|
||||
buffer. */
|
||||
if (d->source < d->source_limit) {
|
||||
return *d->source++;
|
||||
/* top the bit buffer up from the input buffer, without blocking for more */
|
||||
static inline void tinf_refill(TINF_DATA *d) {
|
||||
while (d->bitcount <= 24 && d->source < d->source_limit) {
|
||||
d->tag |= (unsigned int) *d->source++ << d->bitcount;
|
||||
d->bitcount += 8;
|
||||
}
|
||||
|
||||
/* Otherwise if there's callback and we haven't seen EOF yet, try to
|
||||
read next byte using it. (Note: the callback can also update ->source
|
||||
and ->source_limit). */
|
||||
if (!d->eof) {
|
||||
int val = d->source_read_cb(d);
|
||||
if (val >= 0) {
|
||||
return (unsigned char) val;
|
||||
}
|
||||
}
|
||||
|
||||
/* Otherwise, we hit EOF (either from ->source_read_cb() or from exhaustion
|
||||
of the buffer), and it will be "sticky", i.e. further calls to this
|
||||
function will end up here too. */
|
||||
d->eof = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* get one bit from source stream */
|
||||
static int tinf_getbit(TINF_DATA *d) {
|
||||
unsigned int bit;
|
||||
|
||||
/* check if tag is empty */
|
||||
if (!d->bitcount--) {
|
||||
/* load next tag */
|
||||
d->tag = uzlib_get_byte(d);
|
||||
d->bitcount = 7;
|
||||
/* make at least num (<= 16) bits available; past the end of input reads zeros and sets eof */
|
||||
static inline void tinf_need(TINF_DATA *d, unsigned int num) {
|
||||
while (d->bitcount < num) {
|
||||
int val = -1;
|
||||
if (d->source < d->source_limit) {
|
||||
val = *d->source++;
|
||||
} else if (!d->eof) {
|
||||
val = d->source_read_cb(d);
|
||||
}
|
||||
if (val < 0) {
|
||||
d->eof = true;
|
||||
val = 0;
|
||||
}
|
||||
d->tag |= (unsigned int) val << d->bitcount;
|
||||
d->bitcount += 8;
|
||||
}
|
||||
}
|
||||
|
||||
/* shift bit out of tag */
|
||||
bit = d->tag & 0x01;
|
||||
d->tag >>= 1;
|
||||
|
||||
return bit;
|
||||
static inline unsigned int tinf_take(TINF_DATA *d, unsigned int num) {
|
||||
unsigned int val = d->tag & ((1u << num) - 1);
|
||||
d->tag >>= num;
|
||||
d->bitcount -= num;
|
||||
return val;
|
||||
}
|
||||
|
||||
/* read a num bit value from a stream and add base */
|
||||
static unsigned int tinf_read_bits(TINF_DATA *d, int num, int base) {
|
||||
unsigned int val = 0;
|
||||
|
||||
/* read num bits */
|
||||
if (num) {
|
||||
unsigned int limit = 1 << (num);
|
||||
unsigned int mask;
|
||||
|
||||
for (mask = 1; mask < limit; mask *= 2)
|
||||
if (tinf_getbit(d))
|
||||
val += mask;
|
||||
}
|
||||
|
||||
return val + base;
|
||||
static inline unsigned int tinf_read_bits(TINF_DATA *d, unsigned int num, unsigned int base) {
|
||||
tinf_need(d, num);
|
||||
return tinf_take(d, num) + base;
|
||||
}
|
||||
|
||||
/* given a data stream and a tree, decode a symbol */
|
||||
static int tinf_decode_symbol(TINF_DATA *d, TINF_TREE *t) {
|
||||
int sum = 0, cur = 0, len = 0;
|
||||
|
||||
/* get more bits while code value is above sum */
|
||||
do {
|
||||
cur = 2 * cur + tinf_getbit(d);
|
||||
|
||||
if (++len == TINF_ARRAY_SIZE(t->table)) {
|
||||
return TINF_DATA_ERROR;
|
||||
/* canonical decode of the code at the bottom of tag; len gets the code length.
|
||||
The trans index stays below the tree's symbol count, which trans always holds */
|
||||
static int tinf_decode_long(const TINF_TREE *t, unsigned int tag, unsigned int *len) {
|
||||
unsigned int code = 0, first = 0, index = 0, l;
|
||||
for (l = 1; l < 16; ++l, tag >>= 1) {
|
||||
unsigned int count = t->table[l];
|
||||
code |= tag & 1;
|
||||
if (code - first < count) {
|
||||
*len = l;
|
||||
return t->trans[index + code - first];
|
||||
}
|
||||
|
||||
sum += t->table[len];
|
||||
cur -= t->table[len];
|
||||
|
||||
} while (cur >= 0);
|
||||
|
||||
sum += cur;
|
||||
if (sum < 0 || sum >= t->size) {
|
||||
return TINF_DATA_ERROR;
|
||||
index += count;
|
||||
first = (first + count) << 1;
|
||||
code <<= 1;
|
||||
}
|
||||
return TINF_DATA_ERROR;
|
||||
}
|
||||
|
||||
return t->trans[sum];
|
||||
/* decode a symbol, reading more input only while the code is not all in the bit
|
||||
buffer; bits above bitcount are zero, so a code no longer than bitcount is real */
|
||||
static int tinf_decode_symbol(TINF_DATA *d, const TINF_TREE *t) {
|
||||
tinf_refill(d);
|
||||
for (;;) {
|
||||
unsigned int len;
|
||||
int sym = tinf_decode_long(t, d->tag, &len);
|
||||
if (sym >= 0 && len <= d->bitcount) {
|
||||
tinf_take(d, len);
|
||||
return sym;
|
||||
}
|
||||
if (d->bitcount >= 15)
|
||||
return TINF_DATA_ERROR;
|
||||
tinf_need(d, d->bitcount + 1);
|
||||
}
|
||||
}
|
||||
|
||||
/* given a data stream, decode dynamic trees from it */
|
||||
@@ -230,7 +230,7 @@ static int tinf_decode_trees(TINF_DATA *d, TINF_TREE *lt, TINF_TREE *dt) {
|
||||
}
|
||||
|
||||
/* build code length tree, temporarily use length tree */
|
||||
tinf_build_tree(lt, lengths, 19);
|
||||
tinf_build_tree(lt, lengths, 19, LIT_FAST_BITS);
|
||||
|
||||
/* decode code lengths for the dynamic trees */
|
||||
hlimit = hlit + hdist;
|
||||
@@ -282,8 +282,8 @@ static int tinf_decode_trees(TINF_DATA *d, TINF_TREE *lt, TINF_TREE *dt) {
|
||||
}
|
||||
|
||||
/* build dynamic trees */
|
||||
tinf_build_tree(lt, lengths, hlit);
|
||||
tinf_build_tree(dt, lengths + hlit, hdist);
|
||||
tinf_build_tree(lt, lengths, hlit, LIT_FAST_BITS);
|
||||
tinf_build_tree(dt, lengths + hlit, hdist, DIST_FAST_BITS);
|
||||
|
||||
return TINF_OK;
|
||||
}
|
||||
@@ -302,84 +302,189 @@ static void tinf_build_fixed_trees(TINF_TREE *lt, TINF_TREE *dt) {
|
||||
lengths[i] = 7;
|
||||
for (; i < 288; ++i)
|
||||
lengths[i] = 8;
|
||||
tinf_build_tree(lt, lengths, 288);
|
||||
tinf_build_tree(lt, lengths, 288, LIT_FAST_BITS);
|
||||
|
||||
for (i = 0; i < 32; ++i)
|
||||
lengths[i] = 5;
|
||||
tinf_build_tree(dt, lengths, 32);
|
||||
tinf_build_tree(dt, lengths, 32, DIST_FAST_BITS);
|
||||
}
|
||||
|
||||
/* inflate with the bit buffer and both cursors in locals while the input holds a
|
||||
whole symbol; a match that runs past the end of the ring is left in curlen */
|
||||
static int tinf_inflate_fast(TINF_DATA *d, const TINF_TREE *lt, const TINF_TREE *dt) {
|
||||
const unsigned char *src = d->source;
|
||||
const unsigned char *const src_end = d->source_limit;
|
||||
unsigned char *const ring = d->dict_ring;
|
||||
unsigned char *const ring_end = ring + d->dict_size;
|
||||
unsigned char *out = d->dest;
|
||||
const uint16_t *const lfast = lt->fast;
|
||||
const uint16_t *const dfast = dt->fast;
|
||||
unsigned int tag = d->tag, bits = d->bitcount;
|
||||
int res = TINF_OK;
|
||||
|
||||
#define REFILL() \
|
||||
while (bits <= 24) { \
|
||||
tag |= (unsigned int) *src++ << bits; \
|
||||
bits += 8; \
|
||||
}
|
||||
#define DROP(n) (tag >>= (n), bits -= (n))
|
||||
|
||||
while (src_end - src >= FAST_IN_MIN && out < ring_end) {
|
||||
unsigned int e, len;
|
||||
int sym;
|
||||
|
||||
REFILL();
|
||||
e = lfast[tag & ((1u << LIT_FAST_BITS) - 1)];
|
||||
if (e) {
|
||||
len = e >> SYM_BITS;
|
||||
sym = e & SYM_MASK;
|
||||
} else {
|
||||
sym = tinf_decode_long(lt, tag, &len);
|
||||
if (sym < 0) {
|
||||
res = sym;
|
||||
break;
|
||||
}
|
||||
}
|
||||
DROP(len);
|
||||
|
||||
if (sym < 256) {
|
||||
*out++ = sym;
|
||||
continue;
|
||||
}
|
||||
if (sym == 256) {
|
||||
res = TINF_DONE;
|
||||
break;
|
||||
}
|
||||
sym -= 257;
|
||||
if (sym >= 29) {
|
||||
res = TINF_DATA_ERROR;
|
||||
break;
|
||||
}
|
||||
/* the lit/len code and its extra bits fit the refilled buffer together */
|
||||
unsigned int length = LENGTH_BASE[sym] + (tag & ((1u << LENGTH_BITS[sym]) - 1));
|
||||
DROP(LENGTH_BITS[sym]);
|
||||
|
||||
REFILL();
|
||||
e = dfast[tag & ((1u << DIST_FAST_BITS) - 1)];
|
||||
if (e) {
|
||||
len = e >> SYM_BITS;
|
||||
sym = e & SYM_MASK;
|
||||
} else {
|
||||
sym = tinf_decode_long(dt, tag, &len);
|
||||
}
|
||||
if (sym < 0 || sym >= 30) {
|
||||
res = TINF_DATA_ERROR;
|
||||
break;
|
||||
}
|
||||
DROP(len);
|
||||
REFILL();
|
||||
unsigned int offs = DIST_BASE[sym] + (tag & ((1u << DIST_BITS[sym]) - 1));
|
||||
DROP(DIST_BITS[sym]);
|
||||
if (offs > d->dict_size) {
|
||||
res = TINF_DICT_ERROR;
|
||||
break;
|
||||
}
|
||||
|
||||
/* wrap as an index: a pointer before the ring would be undefined */
|
||||
unsigned int at = out - ring;
|
||||
const unsigned char *from = ring + (at >= offs ? at - offs : at + d->dict_size - offs);
|
||||
unsigned int n = ring_end - out;
|
||||
if (n > length)
|
||||
n = length;
|
||||
length -= n;
|
||||
/* at most two runs: up to the end of the ring, then on from its start */
|
||||
while (n) {
|
||||
unsigned int run = ring_end - from;
|
||||
if (run > n)
|
||||
run = n;
|
||||
n -= run;
|
||||
do {
|
||||
*out++ = *from++;
|
||||
} while (--run);
|
||||
if (from == ring_end)
|
||||
from = ring;
|
||||
}
|
||||
if (length) {
|
||||
d->curlen = length;
|
||||
d->lz_off = from - ring;
|
||||
}
|
||||
}
|
||||
#undef REFILL
|
||||
#undef DROP
|
||||
|
||||
d->source = src;
|
||||
d->dest = out;
|
||||
d->tag = tag;
|
||||
d->bitcount = bits;
|
||||
return res;
|
||||
}
|
||||
|
||||
/* ----------------------------- *
|
||||
* -- block inflate functions -- *
|
||||
* ----------------------------- */
|
||||
|
||||
/* given a stream and two trees, inflate next chunk of output (a byte or more) */
|
||||
/* given a stream and two trees, inflate until the ring is full or the block ends */
|
||||
static int tinf_inflate_block_data(TINF_DATA *d, TINF_TREE *lt, TINF_TREE *dt) {
|
||||
if (d->curlen == 0) {
|
||||
unsigned char *const ring_end = d->dict_ring + d->dict_size;
|
||||
while (d->dest < ring_end) {
|
||||
if (d->curlen != 0) {
|
||||
unsigned int n = ring_end - d->dest;
|
||||
if (n > d->curlen)
|
||||
n = d->curlen;
|
||||
d->curlen -= n;
|
||||
do {
|
||||
*d->dest++ = d->dict_ring[d->lz_off];
|
||||
if ((unsigned) ++d->lz_off == d->dict_size)
|
||||
d->lz_off = 0;
|
||||
} while (--n);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (d->source_limit - d->source >= FAST_IN_MIN) {
|
||||
int res = tinf_inflate_fast(d, lt, dt);
|
||||
if (res != TINF_OK)
|
||||
return res;
|
||||
continue;
|
||||
}
|
||||
|
||||
unsigned int offs;
|
||||
int dist;
|
||||
int sym = tinf_decode_symbol(d, lt);
|
||||
|
||||
if (d->eof) {
|
||||
if (d->eof)
|
||||
return TINF_DATA_ERROR;
|
||||
}
|
||||
|
||||
if (sym < 0) {
|
||||
if (sym < 0)
|
||||
return sym;
|
||||
}
|
||||
|
||||
/* literal byte */
|
||||
if (sym < 256) {
|
||||
TINF_PUT(d, sym);
|
||||
return TINF_OK;
|
||||
*d->dest++ = sym;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* end of block */
|
||||
if (sym == 256) {
|
||||
if (sym == 256)
|
||||
return TINF_DONE;
|
||||
}
|
||||
|
||||
/* substring from sliding dictionary */
|
||||
sym -= 257;
|
||||
if (sym >= 29) {
|
||||
if (sym >= 29)
|
||||
return TINF_DATA_ERROR;
|
||||
}
|
||||
|
||||
/* possibly get more bits from length code */
|
||||
d->curlen = tinf_read_bits(d, LENGTH_BITS[sym], LENGTH_BASE[sym]);
|
||||
|
||||
dist = tinf_decode_symbol(d, dt);
|
||||
if (dist < 0 || dist >= 30) {
|
||||
if (dist < 0 || dist >= 30)
|
||||
return TINF_DATA_ERROR;
|
||||
}
|
||||
|
||||
/* possibly get more bits from distance code */
|
||||
offs = tinf_read_bits(d, DIST_BITS[dist], DIST_BASE[dist]);
|
||||
|
||||
/* calculate and validate actual LZ offset to use */
|
||||
if (offs > d->dict_size) {
|
||||
if (offs > d->dict_size)
|
||||
return TINF_DICT_ERROR;
|
||||
}
|
||||
/* Note: we don't try to catch offset which points to not yet filled
|
||||
part of the dictionary here. Doing so would require keeping another
|
||||
variable to track "filled in" size of the dictionary. Appearance of
|
||||
such an offset cannot lead to accessing memory outside of the
|
||||
dictionary buffer, and clients which don't want to leak unrelated
|
||||
information, should explicitly initialize dictionary buffer passed
|
||||
to uzlib. */
|
||||
|
||||
d->lz_off = d->dict_idx - offs;
|
||||
if (d->lz_off < 0) {
|
||||
d->lz_off = (int) (d->dest - d->dict_ring) - (int) offs;
|
||||
if (d->lz_off < 0)
|
||||
d->lz_off += d->dict_size;
|
||||
}
|
||||
}
|
||||
|
||||
/* copy next byte from dict substring */
|
||||
TINF_PUT(d, d->dict_ring[d->lz_off]);
|
||||
if ((unsigned) ++d->lz_off == d->dict_size) {
|
||||
d->lz_off = 0;
|
||||
}
|
||||
d->curlen--;
|
||||
return TINF_OK;
|
||||
}
|
||||
|
||||
@@ -388,30 +493,22 @@ static int tinf_inflate_uncompressed_block(TINF_DATA *d) {
|
||||
if (d->curlen == 0) {
|
||||
unsigned int length, invlength;
|
||||
|
||||
/* get length */
|
||||
length = uzlib_get_byte(d);
|
||||
length += 256 * uzlib_get_byte(d);
|
||||
/* get one's complement of length */
|
||||
invlength = uzlib_get_byte(d);
|
||||
invlength += 256 * uzlib_get_byte(d);
|
||||
/* check length */
|
||||
/* the block starts on a byte boundary */
|
||||
tinf_take(d, d->bitcount & 7);
|
||||
length = tinf_read_bits(d, 16, 0);
|
||||
invlength = tinf_read_bits(d, 16, 0);
|
||||
if (length != (~invlength & 0x0000ffff))
|
||||
return TINF_DATA_ERROR;
|
||||
|
||||
/* increment length to properly return TINF_DONE below, without
|
||||
producing data at the same time */
|
||||
d->curlen = length + 1;
|
||||
|
||||
/* make sure we start next block on a byte boundary */
|
||||
d->bitcount = 0;
|
||||
}
|
||||
|
||||
if (--d->curlen == 0) {
|
||||
if (--d->curlen == 0)
|
||||
return TINF_DONE;
|
||||
}
|
||||
|
||||
unsigned char c = uzlib_get_byte(d);
|
||||
TINF_PUT(d, c);
|
||||
/* read first: a read that needs input may flush the output up to dest */
|
||||
unsigned char c = tinf_read_bits(d, 8, 0);
|
||||
*d->dest++ = c;
|
||||
return TINF_OK;
|
||||
}
|
||||
|
||||
@@ -419,10 +516,10 @@ static int tinf_inflate_uncompressed_block(TINF_DATA *d) {
|
||||
* -- public functions -- *
|
||||
* ---------------------- */
|
||||
|
||||
/* initialize decompression structure */
|
||||
void ota_inflate_init(TINF_DATA *d, unsigned char *dict, unsigned int dict_len) {
|
||||
d->source = NULL;
|
||||
d->source_limit = NULL;
|
||||
d->dest = dict;
|
||||
d->tag = 0;
|
||||
d->eof = 0;
|
||||
d->bitcount = 0;
|
||||
@@ -431,68 +528,56 @@ void ota_inflate_init(TINF_DATA *d, unsigned char *dict, unsigned int dict_len)
|
||||
d->btype = -1;
|
||||
d->dict_size = dict_len;
|
||||
d->dict_ring = dict;
|
||||
d->dict_idx = 0;
|
||||
d->curlen = 0;
|
||||
d->ltree.trans = d->ltrans;
|
||||
d->ltree.size = TINF_ARRAY_SIZE(d->ltrans);
|
||||
d->ltree.fast = d->lfast;
|
||||
d->dtree.trans = d->dtrans;
|
||||
d->dtree.size = TINF_ARRAY_SIZE(d->dtrans);
|
||||
d->dtree.fast = d->dfast;
|
||||
}
|
||||
|
||||
/* inflate next output bytes from compressed stream */
|
||||
int ota_inflate(TINF_DATA *d) {
|
||||
/* the caller has taken the previous ringful */
|
||||
if (d->dest == d->dict_ring + d->dict_size)
|
||||
d->dest = d->dict_ring;
|
||||
|
||||
do {
|
||||
int res;
|
||||
|
||||
/* start a new block */
|
||||
if (d->btype == -1) {
|
||||
int old_btype;
|
||||
next_blk:
|
||||
old_btype = d->btype;
|
||||
/* read final block flag */
|
||||
d->bfinal = tinf_getbit(d);
|
||||
/* read block type (2 bits) */
|
||||
d->bfinal = tinf_read_bits(d, 1, 0);
|
||||
d->btype = tinf_read_bits(d, 2, 0);
|
||||
|
||||
if (d->btype == 1 && old_btype != 1) {
|
||||
/* build fixed huffman trees */
|
||||
tinf_build_fixed_trees(&d->ltree, &d->dtree);
|
||||
} else if (d->btype == 2) {
|
||||
/* decode trees from stream */
|
||||
res = tinf_decode_trees(d, &d->ltree, &d->dtree);
|
||||
if (res != TINF_OK) {
|
||||
if (res != TINF_OK)
|
||||
return res;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* process current block */
|
||||
switch (d->btype) {
|
||||
case 0:
|
||||
/* decompress uncompressed block */
|
||||
res = tinf_inflate_uncompressed_block(d);
|
||||
break;
|
||||
case 1:
|
||||
case 2:
|
||||
/* decompress block with fixed/dynamic huffman trees */
|
||||
/* trees were decoded previously, so it's the same routine for both */
|
||||
res = tinf_inflate_block_data(d, &d->ltree, &d->dtree);
|
||||
break;
|
||||
default:
|
||||
return TINF_DATA_ERROR;
|
||||
}
|
||||
|
||||
if (res == TINF_DONE && !d->bfinal) {
|
||||
/* the block has ended (without producing more data), but we
|
||||
can't return without data, so start procesing next block */
|
||||
if (res == TINF_DONE && !d->bfinal)
|
||||
goto next_blk;
|
||||
}
|
||||
|
||||
if (res != TINF_OK) {
|
||||
if (res != TINF_OK)
|
||||
return res;
|
||||
}
|
||||
|
||||
} while (d->dest < d->dest_limit);
|
||||
} while (d->dest < d->dict_ring + d->dict_size);
|
||||
|
||||
return TINF_OK;
|
||||
}
|
||||
@@ -16,10 +16,14 @@ enum OtaInflateResult {
|
||||
OTA_INFLATE_DICT_ERROR = -5,
|
||||
};
|
||||
|
||||
/* Code bits each lookup table resolves; longer codes take the canonical decode.
|
||||
The distance alphabet has 30 symbols, so its table is kept small */
|
||||
enum { OTA_INFLATE_LIT_FAST_BITS = 9, OTA_INFLATE_DIST_FAST_BITS = 6 };
|
||||
|
||||
struct OtaInflateTree {
|
||||
uint16_t table[16]; /* table of code length counts */
|
||||
uint16_t *trans; /* code -> symbol translation table, size entries */
|
||||
uint16_t size;
|
||||
uint16_t *fast; /* (len << 9) | symbol by the next input bits, 0 = longer code */
|
||||
uint16_t *trans; /* code -> symbol translation table */
|
||||
};
|
||||
|
||||
struct OtaInflateState {
|
||||
@@ -29,9 +33,8 @@ struct OtaInflateState {
|
||||
/* Called when source is exhausted; returns the next byte or -1 at EOF.
|
||||
It may refill source/source_limit for buffered operation. */
|
||||
int (*source_read_cb)(struct OtaInflateState *d);
|
||||
/* Output cursor and one past the end of the output buffer */
|
||||
/* Output cursor in dict_ring: each call fills the ring from here */
|
||||
unsigned char *dest;
|
||||
unsigned char *dest_limit;
|
||||
/* Ring window holding the last dict_size output bytes for back references */
|
||||
unsigned char *dict_ring;
|
||||
|
||||
@@ -39,9 +42,8 @@ struct OtaInflateState {
|
||||
unsigned int curlen;
|
||||
int lz_off;
|
||||
unsigned int dict_size;
|
||||
unsigned int dict_idx;
|
||||
|
||||
/* One word: btype is -1 between blocks, bitcount never exceeds 7 */
|
||||
/* btype is -1 between blocks; bitcount is the number of valid bits in tag (<= 32) */
|
||||
int8_t btype;
|
||||
uint8_t bfinal;
|
||||
uint8_t bitcount;
|
||||
@@ -51,13 +53,15 @@ struct OtaInflateState {
|
||||
struct OtaInflateTree dtree; /* dynamic distance tree */
|
||||
uint16_t ltrans[288];
|
||||
uint16_t dtrans[32]; /* the distance alphabet has 30 symbols, so the tree is kept small */
|
||||
uint16_t lfast[1 << OTA_INFLATE_LIT_FAST_BITS];
|
||||
uint16_t dfast[1 << OTA_INFLATE_DIST_FAST_BITS];
|
||||
};
|
||||
|
||||
/* dict must cover the encoder's window (its largest back reference) */
|
||||
void ota_inflate_init(struct OtaInflateState *d, unsigned char *dict, unsigned int dict_len);
|
||||
/* Fills dest up to dest_limit (OK) or to the end of the stream (DONE). dest may
|
||||
alias dict only if dest_limit - dest == dict_len and dest is reset to dict
|
||||
exactly when a call returns OK, so the ring index and dest stay in lockstep */
|
||||
/* Inflates into dict until it is full (OK) or the stream ends (DONE); the output
|
||||
is dict up to dest. The next call after OK starts dict over, so take its
|
||||
contents first */
|
||||
int ota_inflate(struct OtaInflateState *d);
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
@@ -65,16 +65,15 @@ ota::OTAResponseTypes ESPHomeOTAComponent::inflate_data_(uint8_t *in, size_t ima
|
||||
};
|
||||
|
||||
int res;
|
||||
session.flushed = 0;
|
||||
do {
|
||||
// The ring index wrapped to 0 exactly when the window filled
|
||||
session.dest = session.window;
|
||||
session.dest_limit = session.window + OTA_INFLATE_WINDOW_SIZE;
|
||||
session.flushed = 0;
|
||||
res = ota_inflate(&session);
|
||||
// A stored block keeps emitting zeros after a failed read, hence eof
|
||||
if (res < 0 || session.eof)
|
||||
break;
|
||||
session.error = this->inflate_flush_(session);
|
||||
// A full window is all in flash; the next call starts it over
|
||||
session.flushed = 0;
|
||||
} while (res != OTA_INFLATE_DONE && session.error == ota::OTA_RESPONSE_OK);
|
||||
|
||||
// Transport and flash failures are logged where they happen
|
||||
|
||||
@@ -138,11 +138,6 @@ static uint8_t calc_checksum(const void *data, size_t size) {
|
||||
return xor_bytes(static_cast<const uint8_t *>(data), size);
|
||||
}
|
||||
|
||||
// Simple mode needs simple reporting from the module; Normal and Calibrate read energy frames
|
||||
static uint16_t system_mode_for(uint8_t mode) {
|
||||
return mode == OP_SIMPLE_MODE ? CMD_SYSTEM_MODE_SIMPLE : CMD_SYSTEM_MODE_ENERGY;
|
||||
}
|
||||
|
||||
static int32_t get_firmware_int(const char *version_string) {
|
||||
// Convert "v1.5.4" -> 154 by skipping 'v' and '.', accumulating digits
|
||||
const char *p = (*version_string == 'v') ? version_string + 1 : version_string;
|
||||
@@ -212,10 +207,13 @@ void LD2420Component::setup() {
|
||||
|
||||
memcpy(&this->new_config, &this->current_config, sizeof(this->current_config));
|
||||
if (ld2420::get_firmware_int(this->firmware_ver_) < CALIBRATE_VERSION_MIN) {
|
||||
this->set_operating_mode(OP_SIMPLE_MODE);
|
||||
this->set_mode_(CMD_SYSTEM_MODE_SIMPLE);
|
||||
ESP_LOGW(TAG, "Firmware version %s and older supports Simple Mode only", this->firmware_ver_);
|
||||
} else {
|
||||
this->set_operating_mode(OP_NORMAL_MODE);
|
||||
this->set_mode_(CMD_SYSTEM_MODE_ENERGY);
|
||||
}
|
||||
this->set_operating_mode(OP_NORMAL_MODE); // older firmware is held in Simple
|
||||
this->set_mode_(system_mode_for(this->current_operating_mode));
|
||||
#ifdef USE_NUMBER
|
||||
this->init_gate_config_numbers();
|
||||
#endif
|
||||
@@ -246,9 +244,7 @@ void LD2420Component::apply_config_action() {
|
||||
#endif
|
||||
this->set_system_mode(this->system_mode_);
|
||||
this->set_config_mode(false); // Disable config mode to save new values in LD2420 nvm
|
||||
// Applying the calibrated thresholds ends calibration; Normal and Simple stay as they are
|
||||
if (this->current_operating_mode == OP_CALIBRATE_MODE)
|
||||
this->set_operating_mode(OP_NORMAL_MODE);
|
||||
this->set_operating_mode(OP_NORMAL_MODE);
|
||||
}
|
||||
|
||||
void LD2420Component::factory_reset_action() {
|
||||
@@ -360,22 +356,6 @@ void LD2420Component::set_operating_mode(const char *state) {
|
||||
}
|
||||
}
|
||||
|
||||
void LD2420Component::change_operating_mode(OpMode mode) {
|
||||
this->set_operating_mode(mode);
|
||||
const uint16_t system_mode = system_mode_for(this->current_operating_mode);
|
||||
if (system_mode == this->get_mode_())
|
||||
return;
|
||||
if (this->set_config_mode(true) != LD2420_ERROR_TIMEOUT) {
|
||||
this->set_system_mode(system_mode);
|
||||
this->set_config_mode(false);
|
||||
}
|
||||
if (this->get_mode_() != system_mode) {
|
||||
// The module kept its reporting mode; show the mode that matches it
|
||||
ESP_LOGE(TAG, ESP_LOG_MSG_COMM_FAIL);
|
||||
this->set_operating_mode(this->get_mode_() == CMD_SYSTEM_MODE_SIMPLE ? OP_SIMPLE_MODE : OP_NORMAL_MODE);
|
||||
}
|
||||
}
|
||||
|
||||
void LD2420Component::set_operating_mode(OpMode mode) {
|
||||
// Older firmware only supports simple mode
|
||||
if (ld2420::get_firmware_int(this->firmware_ver_) < CALIBRATE_VERSION_MIN) {
|
||||
|
||||
@@ -119,7 +119,6 @@ class LD2420Component final : public Component, public uart::UARTDevice {
|
||||
void handle_cmd_error(uint16_t error);
|
||||
void set_operating_mode(const char *state);
|
||||
void set_operating_mode(OpMode mode);
|
||||
void change_operating_mode(OpMode mode);
|
||||
void auto_calibrate_sensitivity();
|
||||
void update_radar_data(uint16_t const *gate_energy, uint8_t sample_number);
|
||||
uint8_t set_config_mode(bool enable);
|
||||
|
||||
@@ -30,5 +30,6 @@ async def to_code(config: ConfigType) -> None:
|
||||
CONF_OPERATING_MODE,
|
||||
hub.set_operating_mode_select,
|
||||
options=CONF_SELECTS,
|
||||
apply="change_operating_mode(static_cast<ld2420::OpMode>(index + 1))",
|
||||
apply="set_operating_mode(static_cast<ld2420::OpMode>(index + 1))",
|
||||
publish="before",
|
||||
)
|
||||
@@ -607,10 +607,9 @@ async def _late_logger_init(config: ConfigType) -> None:
|
||||
# esp_rom_printf instead of pulling ~1.2KB esp_rom_vprintf into IRAM.
|
||||
# S2/C2 have a ROM vprintf, so IDF forces CONSTRAINED_ENV_SAFE=1 and
|
||||
# cache-off DRAM logs would reach the flash-resident wrapper; keep V1.
|
||||
if (
|
||||
CORE.using_toolchain_esp_idf
|
||||
and idf_version() >= cv.Version(6, 1, 0)
|
||||
and get_esp32_variant() not in (VARIANT_ESP32C2, VARIANT_ESP32S2)
|
||||
if idf_version() >= cv.Version(6, 1, 0) and get_esp32_variant() not in (
|
||||
VARIANT_ESP32C2,
|
||||
VARIANT_ESP32S2,
|
||||
):
|
||||
add_idf_sdkconfig_option("CONFIG_LOG_VERSION_1", False)
|
||||
add_idf_sdkconfig_option("CONFIG_LOG_VERSION_2", True)
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <span>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
@@ -54,25 +53,16 @@ using DataCallbackManagerBase = CallbackManager<void(const AudioCapture &)>;
|
||||
|
||||
class DataCallbackManager : public DataCallbackManagerBase {
|
||||
public:
|
||||
DataCallbackManager(const audio::AudioStreamInfo *stream_info, const bool *mute_state)
|
||||
: stream_info_(stream_info), mute_state_(mute_state) {}
|
||||
explicit DataCallbackManager(const audio::AudioStreamInfo *stream_info) : stream_info_(stream_info) {}
|
||||
|
||||
using DataCallbackManagerBase::call;
|
||||
|
||||
// Remove before 2027.5.0, along with this class (use a plain CallbackManager)
|
||||
ESPDEPRECATED("Use Microphone::publish_audio_() instead. Removed in 2027.5.0", "2026.11.0")
|
||||
void call(const std::vector<uint8_t> &data) {
|
||||
if (*this->mute_state_) {
|
||||
const std::vector<uint8_t> zeros(data.size(), 0);
|
||||
this->call(AudioCapture{zeros, *this->stream_info_, 0});
|
||||
} else {
|
||||
this->call(AudioCapture{data, *this->stream_info_, 0});
|
||||
}
|
||||
}
|
||||
void call(const std::vector<uint8_t> &data) { this->call(AudioCapture{data, *this->stream_info_, 0}); }
|
||||
|
||||
protected:
|
||||
const audio::AudioStreamInfo *stream_info_;
|
||||
const bool *mute_state_;
|
||||
};
|
||||
|
||||
class Microphone {
|
||||
@@ -82,7 +72,15 @@ class Microphone {
|
||||
|
||||
/// Callbacks take (const AudioCapture &) and run on the microphone's task.
|
||||
template<typename F> void add_data_callback(F &&data_callback) {
|
||||
this->data_callbacks_.add(as_capture_callback(std::forward<F>(data_callback)));
|
||||
this->data_callbacks_.add(
|
||||
[this, callback = as_capture_callback(std::forward<F>(data_callback))](const AudioCapture &capture) {
|
||||
if (this->mute_state_) {
|
||||
const std::vector<uint8_t> zeros(capture.data.size(), 0);
|
||||
callback(AudioCapture{zeros, capture.stream_info, capture.capture_time_us});
|
||||
} else {
|
||||
callback(capture);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
bool is_running() const { return this->state_ == STATE_RUNNING; }
|
||||
@@ -94,11 +92,8 @@ class Microphone {
|
||||
audio::AudioStreamInfo get_audio_stream_info() { return this->audio_stream_info_; }
|
||||
|
||||
protected:
|
||||
/// While muted, data is zeroed first, so it must be a buffer the platform owns.
|
||||
void publish_audio_(std::span<uint8_t> data, const audio::AudioStreamInfo &stream_info, int64_t capture_time_us = 0) {
|
||||
if (this->mute_state_) {
|
||||
std::memset(data.data(), 0, data.size());
|
||||
}
|
||||
void publish_audio_(std::span<const uint8_t> data, const audio::AudioStreamInfo &stream_info,
|
||||
int64_t capture_time_us = 0) {
|
||||
this->data_callbacks_.call(AudioCapture{data, stream_info, capture_time_us});
|
||||
}
|
||||
|
||||
@@ -110,7 +105,7 @@ class Microphone {
|
||||
audio::AudioStreamInfo audio_stream_info_;
|
||||
|
||||
// Make private when the deprecated call(data) is removed in 2027.5.0
|
||||
DataCallbackManager data_callbacks_{&this->audio_stream_info_, &this->mute_state_};
|
||||
DataCallbackManager data_callbacks_{&this->audio_stream_info_};
|
||||
};
|
||||
|
||||
} // namespace esphome::microphone
|
||||
@@ -90,7 +90,6 @@ bool ResamplerMicrophone::init_resampler_(const audio::AudioStreamInfo &input_st
|
||||
|
||||
if (input_stream_info.get_sample_rate() == this->target_sample_rate_) {
|
||||
// The source already delivers the target sample rate, so its audio is passed through unchanged
|
||||
this->output_buffer_.reserve(input_stream_info.ms_to_bytes(BUFFER_DURATION_MS));
|
||||
this->input_stream_info_ = input_stream_info;
|
||||
this->resampler_ready_ = true;
|
||||
return true;
|
||||
@@ -138,23 +137,7 @@ void ResamplerMicrophone::process_audio_(const microphone::AudioCapture &capture
|
||||
}
|
||||
|
||||
if (this->resampler_ == nullptr) {
|
||||
if (this->mute_state_) {
|
||||
// The source's buffer is shared with its other consumers, so publish zeros from our own buffer, in pieces that
|
||||
// fit its reserved size so muting never allocates
|
||||
const uint32_t max_frames = input_stream_info.ms_to_frames(BUFFER_DURATION_MS);
|
||||
const uint32_t total_frames = input_stream_info.bytes_to_frames(capture.data.size());
|
||||
for (uint32_t done = 0; done < total_frames;) {
|
||||
const uint32_t frames = std::min(total_frames - done, max_frames);
|
||||
this->output_buffer_.assign(input_stream_info.frames_to_bytes(frames), 0);
|
||||
const int64_t time_us =
|
||||
capture.capture_time_us == 0 ? 0 : capture.capture_time_us + input_stream_info.frames_to_microseconds(done);
|
||||
this->publish_audio_(this->output_buffer_, input_stream_info, time_us);
|
||||
done += frames;
|
||||
}
|
||||
} else {
|
||||
// Needs a protected forwarding method once data_callbacks_ is made private in 2027.5.0
|
||||
this->data_callbacks_.call(microphone::AudioCapture{capture.data, input_stream_info, capture.capture_time_us});
|
||||
}
|
||||
this->publish_audio_(capture.data, input_stream_info, capture.capture_time_us);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -4,28 +4,16 @@ from typing import Any
|
||||
|
||||
from esphome import automation
|
||||
import esphome.codegen as cg
|
||||
from esphome.components import (
|
||||
audio,
|
||||
esp32,
|
||||
mdns,
|
||||
microphone,
|
||||
network,
|
||||
psram,
|
||||
socket,
|
||||
wifi,
|
||||
)
|
||||
from esphome.components import esp32, mdns, network, psram, socket, wifi
|
||||
from esphome.components.const import CONF_ENABLED, CONF_MANUFACTURER
|
||||
from esphome.components.mdns import DOMAIN as MDNS_DOMAIN
|
||||
import esphome.config_validation as cv
|
||||
from esphome.const import (
|
||||
CONF_BITS_PER_SAMPLE,
|
||||
CONF_BUFFER_SIZE,
|
||||
CONF_CHANNELS,
|
||||
CONF_ESPHOME,
|
||||
CONF_FORMAT,
|
||||
CONF_HEIGHT,
|
||||
CONF_ID,
|
||||
CONF_MICROPHONE,
|
||||
CONF_MODEL,
|
||||
CONF_NAME,
|
||||
CONF_PROJECT,
|
||||
@@ -37,7 +25,6 @@ from esphome.const import (
|
||||
)
|
||||
from esphome.core import CORE
|
||||
from esphome.cpp_generator import MockObj
|
||||
import esphome.final_validate as fv
|
||||
from esphome.types import ConfigType
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
@@ -72,10 +59,6 @@ CONF_ON_CLEAR_PAIRING_CODE = "on_clear_pairing_code"
|
||||
CONF_ON_PAIRING_SUCCEEDED = "on_pairing_succeeded"
|
||||
CONF_ON_PAIRING_FAILED = "on_pairing_failed"
|
||||
|
||||
CONF_ON_STREAMING_STARTED = "on_streaming_started"
|
||||
CONF_ON_STREAMING_STOPPED = "on_streaming_stopped"
|
||||
CONF_PRESENT = "present"
|
||||
|
||||
# A static pairing code is exactly 8 decimal digits.
|
||||
STATIC_PAIRING_CODE_DIGITS = 8
|
||||
|
||||
@@ -121,9 +104,6 @@ CODECS = {
|
||||
DEFAULT_CODECS = [CODEC_FLAC, CODEC_OPUS, CODEC_PCM]
|
||||
OPUS_SAMPLE_RATE = 48000
|
||||
|
||||
# The source role's limits, matching SourceRoleConfig in sendspin-cpp.
|
||||
SOURCE_BITS_PER_SAMPLE = (16, 24, 32)
|
||||
|
||||
SendspinImageFormat = sendspin_library_ns.enum("SendspinImageFormat", is_class=True)
|
||||
IMAGE_FORMAT_JPEG = SendspinImageFormat.enum("JPEG")
|
||||
IMAGE_FORMAT_PNG = SendspinImageFormat.enum("PNG")
|
||||
@@ -137,7 +117,6 @@ AudioSupportedFormatObject = sendspin_library_ns.struct("AudioSupportedFormatObj
|
||||
PlayerRoleConfig = sendspin_library_ns.struct("PlayerRoleConfig")
|
||||
ArtworkRoleConfig = sendspin_library_ns.struct("ArtworkRoleConfig")
|
||||
ImageSlotPreference = sendspin_library_ns.struct("ImageSlotPreference")
|
||||
SourceRoleConfig = sendspin_library_ns.struct("SourceRoleConfig")
|
||||
|
||||
# MemoryLocation enum (from sendspin/types.h) controls SPIRAM-vs-internal-RAM placement
|
||||
# preference for the player role's transfer buffers.
|
||||
@@ -197,11 +176,6 @@ class SendspinConfiguration:
|
||||
visualizer_support: bool = False
|
||||
pairing_code_display_support: bool = False
|
||||
switch_types: set[str] = field(default_factory=set)
|
||||
# Set by the sendspin.source actions and conditions, which need a source block.
|
||||
source_referenced: bool = False
|
||||
source_line_sense: bool = False
|
||||
# The microphone's sample rate, read during final validation.
|
||||
source_sample_rate: int | None = None
|
||||
|
||||
artwork_preferences: list[ConfigType] = field(default_factory=list)
|
||||
player_config: ConfigType | None = None
|
||||
@@ -296,44 +270,6 @@ def _request_high_performance_networking(config: ConfigType) -> ConfigType:
|
||||
return config
|
||||
|
||||
|
||||
_SOURCE_CALLBACK_AUTOMATIONS = (
|
||||
automation.CallbackAutomation(
|
||||
CONF_ON_STREAMING_STARTED, "add_on_source_streaming_started_callback"
|
||||
),
|
||||
automation.CallbackAutomation(
|
||||
CONF_ON_STREAMING_STOPPED, "add_on_source_streaming_stopped_callback"
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
def _validate_source_format(config: ConfigType) -> ConfigType:
|
||||
if config[CONF_MICROPHONE][CONF_BITS_PER_SAMPLE] not in SOURCE_BITS_PER_SAMPLE:
|
||||
raise cv.Invalid(
|
||||
f"{CONF_BITS_PER_SAMPLE} must be one of "
|
||||
f"{', '.join(str(bits) for bits in SOURCE_BITS_PER_SAMPLE)}",
|
||||
path=[CONF_MICROPHONE, CONF_BITS_PER_SAMPLE],
|
||||
)
|
||||
return config
|
||||
|
||||
|
||||
SOURCE_SCHEMA = cv.All(
|
||||
cv.Schema(
|
||||
{
|
||||
cv.Required(CONF_MICROPHONE): microphone.microphone_source_schema(
|
||||
min_bits_per_sample=16,
|
||||
max_bits_per_sample=32,
|
||||
min_channels=1,
|
||||
max_channels=2,
|
||||
),
|
||||
cv.Optional(CONF_TASK_STACK_IN_PSRAM): psram.validate_task_stack_in_psram,
|
||||
cv.Optional(CONF_ON_STREAMING_STARTED): automation.validate_automation({}),
|
||||
cv.Optional(CONF_ON_STREAMING_STOPPED): automation.validate_automation({}),
|
||||
}
|
||||
),
|
||||
_validate_source_format,
|
||||
)
|
||||
|
||||
|
||||
CONFIG_SCHEMA = cv.All(
|
||||
cv.Schema(
|
||||
{
|
||||
@@ -359,7 +295,6 @@ CONFIG_SCHEMA = cv.All(
|
||||
cv.Optional(CONF_ON_CLEAR_PAIRING_CODE): automation.validate_automation({}),
|
||||
cv.Optional(CONF_ON_PAIRING_SUCCEEDED): automation.validate_automation({}),
|
||||
cv.Optional(CONF_ON_PAIRING_FAILED): automation.validate_automation({}),
|
||||
cv.Optional(CONF_SOURCE): SOURCE_SCHEMA,
|
||||
}
|
||||
),
|
||||
cv.only_on_esp32,
|
||||
@@ -400,38 +335,9 @@ def _final_validate(config: ConfigType) -> ConfigType:
|
||||
CONF_UNPAIRED_ACCESS,
|
||||
CONF_STATIC_PAIRING_CODE,
|
||||
)
|
||||
_final_validate_source(config)
|
||||
return config
|
||||
|
||||
|
||||
def _final_validate_source(config: ConfigType) -> None:
|
||||
data = _get_data()
|
||||
if (source := config.get(CONF_SOURCE)) is None:
|
||||
if data.source_referenced:
|
||||
raise cv.Invalid(
|
||||
f"The sendspin.source actions and conditions require a '{CONF_SOURCE}' "
|
||||
"block on the sendspin component"
|
||||
)
|
||||
return
|
||||
|
||||
mic_source = source[CONF_MICROPHONE]
|
||||
try:
|
||||
microphone.final_validate_microphone_source_schema(DOMAIN)(mic_source)
|
||||
except cv.Invalid as err:
|
||||
err.prepend([CONF_SOURCE, CONF_MICROPHONE])
|
||||
raise
|
||||
|
||||
# MicrophoneSource cannot resample, so the stream takes the microphone's own rate.
|
||||
mic_config = fv.get_declaring_config(mic_source[CONF_MICROPHONE])
|
||||
sample_rate = mic_config.get(audio.CONF_MAX_SAMPLE_RATE)
|
||||
if sample_rate is None or mic_config.get(audio.CONF_MIN_SAMPLE_RATE) != sample_rate:
|
||||
raise cv.Invalid(
|
||||
"The microphone used by the sendspin source must have a fixed sample rate",
|
||||
path=[CONF_SOURCE, CONF_MICROPHONE],
|
||||
)
|
||||
data.source_sample_rate = sample_rate
|
||||
|
||||
|
||||
FINAL_VALIDATE_SCHEMA = _final_validate
|
||||
|
||||
|
||||
@@ -442,7 +348,6 @@ def _request_controller_role(config: ConfigType) -> ConfigType:
|
||||
|
||||
|
||||
# Selects the hub. sendspin.switch adds the controller role it needs; the pairing window actions need no role.
|
||||
# sendspin.source.is_streaming also uses it.
|
||||
SENDSPIN_HUB_ACTION_SCHEMA = automation.maybe_simple_id(
|
||||
cv.Schema(
|
||||
{
|
||||
@@ -476,40 +381,6 @@ automation.register_apply_action(
|
||||
)
|
||||
|
||||
|
||||
def _request_source(config: ConfigType) -> ConfigType:
|
||||
"""Mark that a source action or condition is used, so a missing source block is reported."""
|
||||
_get_data().source_referenced = True
|
||||
return config
|
||||
|
||||
|
||||
def _request_source_line_sense(config: ConfigType) -> ConfigType:
|
||||
"""Advertise line sense for the sendspin.source.set_signal action."""
|
||||
_get_data().source_line_sense = True
|
||||
return _request_source(config)
|
||||
|
||||
|
||||
automation.register_apply_condition(
|
||||
"sendspin.source.is_streaming",
|
||||
cv.All(SENDSPIN_HUB_ACTION_SCHEMA, _request_source),
|
||||
"is_source_streaming()",
|
||||
)
|
||||
|
||||
|
||||
automation.register_apply_action(
|
||||
"sendspin.source.set_signal",
|
||||
cv.All(
|
||||
cv.Schema(
|
||||
{
|
||||
cv.GenerateID(): cv.use_id(SendspinHub),
|
||||
cv.Required(CONF_PRESENT): cv.templatable(cv.boolean),
|
||||
}
|
||||
),
|
||||
_request_source_line_sense,
|
||||
),
|
||||
automation.ApplyField(CONF_PRESENT, "set_source_signal", cg.bool_),
|
||||
)
|
||||
|
||||
|
||||
async def to_code(config: ConfigType) -> None:
|
||||
var = cg.new_Pvariable(config[CONF_ID])
|
||||
await cg.register_component(var, config)
|
||||
@@ -562,8 +433,9 @@ async def to_code(config: ConfigType) -> None:
|
||||
|
||||
data = _get_data()
|
||||
|
||||
# The color role is not yet wired up in ESPHome; disable it in the library for now.
|
||||
# The color and source roles are not yet wired up in ESPHome; disable them in the library for now.
|
||||
esp32.add_idf_sdkconfig_option("CONFIG_SENDSPIN_ENABLE_COLOR", False)
|
||||
esp32.add_idf_sdkconfig_option("CONFIG_SENDSPIN_ENABLE_SOURCE", False)
|
||||
|
||||
# Configure Sendspin roles based on requested features (ESPHome internally via USE_SENDSPIN_*)
|
||||
# and disable building unused code paths in the sendspin-cpp library (IDF SDKConfig via CONFIG_SENDSPIN_ENABLE_*).
|
||||
@@ -653,37 +525,6 @@ async def to_code(config: ConfigType) -> None:
|
||||
else:
|
||||
esp32.add_idf_sdkconfig_option("CONFIG_SENDSPIN_ENABLE_PLAYER", False)
|
||||
|
||||
if (source := config.get(CONF_SOURCE)) is not None:
|
||||
cg.add_define("USE_SENDSPIN_SOURCE", True)
|
||||
|
||||
mic_source = await microphone.microphone_source_to_code(source[CONF_MICROPHONE])
|
||||
cg.add(var.set_microphone_source(mic_source))
|
||||
|
||||
source_psram_stack = source.get(CONF_TASK_STACK_IN_PSRAM, False)
|
||||
if source_psram_stack:
|
||||
psram.request_external_task_stack()
|
||||
|
||||
# Designated initializers must follow SourceRoleConfig's declaration order. The fields left out keep
|
||||
# sendspin-cpp's defaults.
|
||||
cg.add(
|
||||
var.set_source_config(
|
||||
cg.StructInitializer(
|
||||
SourceRoleConfig,
|
||||
("sample_rate", data.source_sample_rate),
|
||||
("channels", len(source[CONF_MICROPHONE][CONF_CHANNELS])),
|
||||
("bit_depth", source[CONF_MICROPHONE][CONF_BITS_PER_SAMPLE]),
|
||||
("line_sense", data.source_line_sense),
|
||||
("psram_stack", source_psram_stack),
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
await automation.build_callback_automations(
|
||||
var, source, _SOURCE_CALLBACK_AUTOMATIONS
|
||||
)
|
||||
else:
|
||||
esp32.add_idf_sdkconfig_option("CONFIG_SENDSPIN_ENABLE_SOURCE", False)
|
||||
|
||||
if not data.player_support or CODEC_OPUS not in data.player_config[CONF_CODECS]:
|
||||
esp32.add_idf_sdkconfig_option("CONFIG_SENDSPIN_ENABLE_OPUS", False)
|
||||
|
||||
|
||||
@@ -158,23 +158,6 @@ void SendspinHub::setup() {
|
||||
this->client_->add_player(this->player_config_).set_listener(this->player_listener_);
|
||||
#endif
|
||||
|
||||
#ifdef USE_SENDSPIN_SOURCE
|
||||
this->source_role_ = &this->client_->add_source(this->source_config_);
|
||||
this->source_role_->set_listener(this);
|
||||
// THREAD CONTEXT: Microphone task, the role's single producer. A capture time of 0 (unknown) makes the library
|
||||
// stamp the buffer as ending now.
|
||||
this->microphone_source_->add_data_callback([this](const microphone::AudioCapture &capture) {
|
||||
// A failed microphone read can publish an empty buffer, which the library rejects with a warning
|
||||
if (!capture.data.empty()) {
|
||||
this->source_role_->write_audio(capture.data.data(), capture.data.size(), capture.capture_time_us);
|
||||
}
|
||||
});
|
||||
// A sensor that reports its state at boot can run the set_signal action before this setup()
|
||||
if (this->source_signal_.has_value()) {
|
||||
this->set_source_signal(*this->source_signal_);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Set before setup() by codegen; an unpaired access switch sets it later, from its own setup().
|
||||
if (this->unpaired_access_.has_value()) {
|
||||
this->client_->set_unpaired_access_enabled(*this->unpaired_access_);
|
||||
@@ -240,18 +223,6 @@ void SendspinHub::dump_config() {
|
||||
preference.display_offset_ms);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef USE_SENDSPIN_SOURCE
|
||||
ESP_LOGCONFIG(TAG,
|
||||
" Source:\n"
|
||||
" Sample rate: %" PRIu32 " Hz\n"
|
||||
" Channels: %u\n"
|
||||
" Bits per sample: %u\n"
|
||||
" Task stack in PSRAM: %s\n"
|
||||
" Line sense: %s",
|
||||
this->source_config_.sample_rate, this->source_config_.channels, this->source_config_.bit_depth,
|
||||
YESNO(this->source_config_.psram_stack), YESNO(this->source_config_.line_sense));
|
||||
#endif
|
||||
}
|
||||
|
||||
// THREAD CONTEXT: Main loop (invoked from codegen before setup(), or from Sendspin components)
|
||||
@@ -593,29 +564,6 @@ sendspin::PlayerRole *SendspinHub::get_player_role() {
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef USE_SENDSPIN_SOURCE
|
||||
// THREAD CONTEXT: Main loop (invoked from the sendspin.source.set_signal action)
|
||||
void SendspinHub::set_source_signal(bool present) {
|
||||
if (this->source_role_ == nullptr) {
|
||||
this->source_signal_ = present; // Applied in setup()
|
||||
return;
|
||||
}
|
||||
this->source_role_->set_signal(present ? sendspin::SourceSignal::PRESENT : sendspin::SourceSignal::ABSENT);
|
||||
}
|
||||
|
||||
// THREAD CONTEXT: Main loop (SourceRoleListener override, fired from client_->loop())
|
||||
void SendspinHub::on_streaming_started() {
|
||||
this->microphone_source_->start();
|
||||
this->source_streaming_started_callbacks_.call();
|
||||
}
|
||||
|
||||
// THREAD CONTEXT: Main loop (SourceRoleListener override, fired from client_->loop())
|
||||
void SendspinHub::on_streaming_stopped() {
|
||||
this->microphone_source_->stop();
|
||||
this->source_streaming_stopped_callbacks_.call();
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace esphome::sendspin_
|
||||
|
||||
#endif // USE_ESP_IDF
|
||||
@@ -31,11 +31,6 @@
|
||||
#ifdef USE_SENDSPIN_PLAYER
|
||||
#include <sendspin/player_role.h>
|
||||
#endif
|
||||
#ifdef USE_SENDSPIN_SOURCE
|
||||
#include "esphome/components/microphone/microphone_source.h"
|
||||
|
||||
#include <sendspin/source_role.h>
|
||||
#endif
|
||||
|
||||
#include <array>
|
||||
#include <cstddef>
|
||||
@@ -80,7 +75,6 @@ enum SendspinFeature : uint32_t {
|
||||
/// - Handles Sendspin roles that apply to multiple child components (artwork, controller, metadata) so their events
|
||||
/// can be fanned out. Roles specific to a single component (player) are configured by the hub but owned by the
|
||||
/// child thereafter, since no fan-out is needed.
|
||||
/// - The source role streams a microphone. Its data callback runs on the microphone's task.
|
||||
///
|
||||
/// The sendspin-cpp library follows this design:
|
||||
/// - Core and role configuration are passed at client/role construction time as structs. Built in our `setup()`.
|
||||
@@ -97,9 +91,6 @@ class SendspinHub final : public Component,
|
||||
#endif
|
||||
#ifdef USE_SENDSPIN_METADATA
|
||||
public sendspin::MetadataRoleListener,
|
||||
#endif
|
||||
#ifdef USE_SENDSPIN_SOURCE
|
||||
public sendspin::SourceRoleListener,
|
||||
#endif
|
||||
public sendspin::SendspinClientListener,
|
||||
public sendspin::SendspinNetworkProvider,
|
||||
@@ -294,31 +285,6 @@ class SendspinHub final : public Component,
|
||||
sendspin::PlayerRole *get_player_role();
|
||||
#endif
|
||||
|
||||
#ifdef USE_SENDSPIN_SOURCE
|
||||
void set_source_config(const sendspin::SourceRoleConfig &config) { this->source_config_ = config; }
|
||||
void set_microphone_source(microphone::MicrophoneSource *microphone_source) {
|
||||
this->microphone_source_ = microphone_source;
|
||||
}
|
||||
|
||||
/// @brief Reports whether the capture input has a signal; exposed as the sendspin.source.set_signal action.
|
||||
///
|
||||
/// Using the action enables line sense in the source config. A call before setup() is applied there. Must be called
|
||||
/// from the main loop thread.
|
||||
void set_source_signal(bool present);
|
||||
|
||||
/// @brief Returns whether the source is streaming microphone audio to the server.
|
||||
bool is_source_streaming() const { return this->source_role_ != nullptr && this->source_role_->is_streaming(); }
|
||||
|
||||
/// @brief Registers a callback that fires when the server opens the source stream.
|
||||
template<typename F> void add_on_source_streaming_started_callback(F &&callback) {
|
||||
this->source_streaming_started_callbacks_.add(std::forward<F>(callback));
|
||||
}
|
||||
/// @brief Registers a callback that fires when the source stream closes.
|
||||
template<typename F> void add_on_source_streaming_stopped_callback(F &&callback) {
|
||||
this->source_streaming_stopped_callbacks_.add(std::forward<F>(callback));
|
||||
}
|
||||
#endif
|
||||
|
||||
protected:
|
||||
/// @brief Builds the SendspinClientConfig from ESPHome configuration and platform info.
|
||||
sendspin::SendspinClientConfig build_client_config_();
|
||||
@@ -417,22 +383,6 @@ class SendspinHub final : public Component,
|
||||
sendspin::PlayerRoleConfig player_config_{};
|
||||
#endif
|
||||
|
||||
#ifdef USE_SENDSPIN_SOURCE
|
||||
// The server opens and closes the stream; the microphone runs only while it is open.
|
||||
void on_streaming_started() override;
|
||||
void on_streaming_stopped() override;
|
||||
|
||||
sendspin::SourceRoleConfig source_config_{};
|
||||
sendspin::SourceRole *source_role_{nullptr};
|
||||
microphone::MicrophoneSource *microphone_source_{nullptr};
|
||||
// Signal state set before setup(), applied once the role exists
|
||||
std::optional<bool> source_signal_;
|
||||
|
||||
// Lazy: each is fed by an optional YAML automation.
|
||||
LazyCallbackManager<void()> source_streaming_started_callbacks_{};
|
||||
LazyCallbackManager<void()> source_streaming_stopped_callbacks_{};
|
||||
#endif
|
||||
|
||||
// --- Core member variables ---
|
||||
|
||||
// Built once in setup(): make_preference() allocates a backend that is never freed.
|
||||
|
||||
@@ -6,7 +6,6 @@ from esphome.automation import maybe_simple_id
|
||||
import esphome.codegen as cg
|
||||
from esphome.components import i2c
|
||||
from esphome.components.audio_dac import AudioDac
|
||||
from esphome.components.const import CONF_MODULATION
|
||||
import esphome.config_validation as cv
|
||||
from esphome.const import CONF_ENABLE_PIN, CONF_ID, CONF_MODEL
|
||||
from esphome.cpp_generator import MockObj
|
||||
@@ -20,7 +19,6 @@ DEPENDENCIES = ["i2c"]
|
||||
|
||||
CONF_ANALOG_GAIN = "analog_gain"
|
||||
CONF_DAC_MODE = "dac_mode"
|
||||
CONF_FAULT_OUTPUT = "fault_output"
|
||||
CONF_IGNORE_ENABLE_PIN_WARNING = "ignore_enable_pin_warning"
|
||||
CONF_MIXER_MODE = "mixer_mode"
|
||||
CONF_VOLUME_MIN_DB = "volume_min_db"
|
||||
@@ -41,11 +39,6 @@ MIXER_MODES = MixerMode.options(
|
||||
"stereo", "stereo_inverse", "mono", "left", "right", prefix="MIXER_MODE_"
|
||||
)
|
||||
|
||||
Modulation = tas58xx_ns.enum("Modulation")
|
||||
MODULATIONS = Modulation.options("bd_mode", "1spw_mode", prefix="MODULATION_")
|
||||
|
||||
FAULT_OUTPUT_NONE = "none"
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class Model:
|
||||
@@ -56,9 +49,6 @@ class Model:
|
||||
volume_min_db: float
|
||||
volume_max_db: float
|
||||
default_address: int
|
||||
# Pins that can report FAULTZ: name -> pin number n, selected at 0x61 + n (ModelInfo::fault_output_pins)
|
||||
fault_outputs: dict[str, int]
|
||||
default_fault_output: str
|
||||
|
||||
|
||||
MODELS: dict[str, Model] = {
|
||||
@@ -68,8 +58,6 @@ MODELS: dict[str, Model] = {
|
||||
volume_min_db=-103.0,
|
||||
volume_max_db=24.0,
|
||||
default_address=0x2D,
|
||||
fault_outputs={"adr": 0},
|
||||
default_fault_output="adr",
|
||||
),
|
||||
DAC_TAS5825M: Model(
|
||||
model_info=tas58xx_ns.TAS5825M_MODEL,
|
||||
@@ -77,8 +65,6 @@ MODELS: dict[str, Model] = {
|
||||
volume_min_db=-103.0,
|
||||
volume_max_db=24.0,
|
||||
default_address=0x4C,
|
||||
fault_outputs={"gpio0": 0, "gpio1": 1, "gpio2": 2},
|
||||
default_fault_output="gpio1",
|
||||
),
|
||||
}
|
||||
|
||||
@@ -114,15 +100,9 @@ def _model_schema(model: Model) -> cv.Schema:
|
||||
cv.Optional(CONF_DAC_MODE, default="btl"): cv.enum(
|
||||
DAC_MODES, lower=True
|
||||
),
|
||||
cv.Optional(
|
||||
CONF_FAULT_OUTPUT, default=model.default_fault_output
|
||||
): cv.one_of(FAULT_OUTPUT_NONE, *model.fault_outputs, lower=True),
|
||||
cv.Optional(CONF_MIXER_MODE, default="stereo"): cv.enum(
|
||||
MIXER_MODES, lower=True
|
||||
),
|
||||
cv.Optional(CONF_MODULATION, default="bd_mode"): cv.enum(
|
||||
MODULATIONS, lower=True
|
||||
),
|
||||
cv.Optional(
|
||||
CONF_VOLUME_MIN_DB, default=model.volume_min_db
|
||||
): volume_validator,
|
||||
@@ -192,10 +172,7 @@ async def to_code(config: ConfigType) -> None:
|
||||
|
||||
cg.add(var.set_analog_gain(config[CONF_ANALOG_GAIN]))
|
||||
cg.add(var.set_dac_mode(config[CONF_DAC_MODE]))
|
||||
if (fault_output := config[CONF_FAULT_OUTPUT]) != FAULT_OUTPUT_NONE:
|
||||
cg.add(var.set_fault_output(model.fault_outputs[fault_output]))
|
||||
cg.add(var.set_mixer_mode(config[CONF_MIXER_MODE]))
|
||||
cg.add(var.set_modulation(config[CONF_MODULATION]))
|
||||
cg.add(var.set_volume_min_db(config[CONF_VOLUME_MIN_DB]))
|
||||
cg.add(var.set_volume_max_db(config[CONF_VOLUME_MAX_DB]))
|
||||
await cg.add_pin(var.set_enable_pin, config.get(CONF_ENABLE_PIN))
|
||||
@@ -8,8 +8,11 @@ namespace esphome::tas58xx {
|
||||
// Registers 0x46, 0x7D, 0x7E and page 1 register 0x51 are not documented in the datasheet.
|
||||
static constexpr i2c::I2CRegValue STARTUP_SEQUENCE[] PROGMEM = {
|
||||
{0x03, 0x00}, // DEVICE_CTRL_2: deep sleep
|
||||
{0x46, 0x01}, // PPC 96 kHz process flow value (its 48 kHz FIR flows write 0x11)
|
||||
{0x46, 0x01},
|
||||
{0x03, 0x02}, // DEVICE_CTRL_2: Hi-Z
|
||||
// The I2C address is latched at power up, after which the ADR pin can report faults
|
||||
{0x61, 0x0B}, // ADR_PIN_CONFIG: FAULTZ
|
||||
{0x60, 0x01}, // ADR_PIN_CTRL: output
|
||||
{0x7D, 0x11},
|
||||
{0x7E, 0xFF},
|
||||
{0x00, 0x01}, // Page 1
|
||||
@@ -22,8 +25,6 @@ static constexpr i2c::I2CRegValue STARTUP_SEQUENCE[] PROGMEM = {
|
||||
|
||||
static const LogString *model_name() { return LOG_STR("TAS5805M"); }
|
||||
|
||||
static const LogString *fault_output_name(uint8_t) { return LOG_STR("ADR"); }
|
||||
|
||||
// An if chain rather than a switch: a switch table would land in rodata, which is RAM on ESP8266.
|
||||
static const LogString *fault_name(uint8_t index) {
|
||||
if (index == 0)
|
||||
@@ -87,8 +88,6 @@ const ModelInfo TAS5805M_MODEL = {
|
||||
NO_BIT, // FAULT_SENSOR_RIGHT_CHANNEL_CBC_OVER_CURRENT_WARNING
|
||||
NO_BIT, // FAULT_SENSOR_OVER_TEMP_146C_WARNING
|
||||
},
|
||||
.fault_output_pins = 1, // ADR
|
||||
.fault_output_name = fault_output_name,
|
||||
};
|
||||
|
||||
} // namespace esphome::tas58xx
|
||||
@@ -6,7 +6,7 @@ namespace esphome::tas58xx {
|
||||
|
||||
// Remainder of the startup sequence, run after the reset in TAS58xx::init_(). Register 0x00 selects the page.
|
||||
// Based on the TI PurePath Console (PPC) export for "TAS5825M 2-Band DRC&AGL 2.0 96k".
|
||||
// Registers 0x7D, 0x7E, page 1 register 0x51 and page 2 registers 0x1D, 0x19 are not documented in datasheet.
|
||||
// Registers 0x46, 0x7D, 0x7E, page 1 register 0x51 and page 2 registers 0x1D, 0x19 are not documented in datasheet.
|
||||
static constexpr i2c::I2CRegValue STARTUP_SEQUENCE[] PROGMEM = {
|
||||
{0x03, 0x00}, // DEVICE_CTRL_2: deep sleep, the state the PPC sequence starts from
|
||||
{0x7D, 0x11},
|
||||
@@ -17,25 +17,20 @@ static constexpr i2c::I2CRegValue STARTUP_SEQUENCE[] PROGMEM = {
|
||||
{0x1D, 0x00},
|
||||
{0x19, 0x80},
|
||||
{0x00, 0x00}, // Page 0
|
||||
{0x46, 0x11}, // DSP_CTRL: 96 kHz processing (bits 4-3 = 10), use default coefficients (bit 0 = 1)
|
||||
{0x46, 0x11},
|
||||
// PPC also writes 0x02 (DEVICE_CTRL_1) and 0x54 (AGAIN) here; init_() writes both from YAML
|
||||
{0x53, 0x01}, // ANA_CTRL: in phase, 100kHz bandwidth for high audio performance with Fsw=384kHz
|
||||
{0x03, 0x02}, // DEVICE_CTRL_2: Hi-Z
|
||||
|
||||
// Additional register configuration
|
||||
// GPIO1 is a dedicated pin on TAS5825M (separate from ADR), used as FAULTZ
|
||||
{0x62, 0x0B}, // GPIO1_SEL: GPIO1 as FAULTZ
|
||||
{0x60, 0x02}, // GPIO_CTRL: GPIO1 is output
|
||||
{0x77, 0x07}, // CBC_CONTROL: enable cycle-by-cycle current limit for warnings and faults
|
||||
};
|
||||
|
||||
static const LogString *model_name() { return LOG_STR("TAS5825M"); }
|
||||
|
||||
static const LogString *fault_output_name(uint8_t pin) {
|
||||
if (pin == 0)
|
||||
return LOG_STR("GPIO0");
|
||||
if (pin == 1)
|
||||
return LOG_STR("GPIO1");
|
||||
return LOG_STR("GPIO2");
|
||||
}
|
||||
|
||||
// An if chain rather than a switch: a switch table would land in rodata, which is RAM on ESP8266.
|
||||
static const LogString *fault_name(uint8_t index) {
|
||||
if (index == 0)
|
||||
@@ -118,8 +113,6 @@ const ModelInfo TAS5825M_MODEL = {
|
||||
// 25, // FAULT_SENSOR_OVER_TEMP_122C_WARNING // not currently included
|
||||
// 24, // FAULT_SENSOR_OVER_TEMP_112C_WARNING // not currently included
|
||||
},
|
||||
.fault_output_pins = 3, // GPIO0, GPIO1, GPIO2 (ADR is an analog input only on TAS5825M)
|
||||
.fault_output_name = fault_output_name,
|
||||
};
|
||||
|
||||
} // namespace esphome::tas58xx
|
||||
@@ -20,7 +20,6 @@ static constexpr uint8_t TAS58XX_RESET_CTRL = 0x01;
|
||||
static constexpr uint8_t TAS58XX_RESET_CTRL_ALL = 0x11; // Reset DSP/control port and registers
|
||||
static constexpr uint8_t TAS58XX_DEVICE_CTRL_1 = 0x02;
|
||||
static constexpr uint8_t TAS58XX_DEVICE_CTRL_1_PBTL = (1 << 2);
|
||||
static constexpr uint8_t TAS58XX_DEVICE_CTRL_1_1SPW = 0x01; // DAMP_MOD = 01
|
||||
static constexpr uint8_t TAS58XX_DEVICE_CTRL_2 = 0x03;
|
||||
static constexpr uint8_t TAS58XX_DEVICE_CTRL_2_MUTE = (1 << 3);
|
||||
static constexpr uint8_t TAS58XX_CTRL_STATE_MASK = 0x03; // DEVICE_CTRL_2 and POWER_STATE
|
||||
@@ -34,9 +33,6 @@ static constexpr uint8_t TAS58XX_DIG_VOL_0DB = 0x30;
|
||||
static constexpr uint8_t TAS58XX_DIG_VOL_MINUS_103DB = 0xFE;
|
||||
static constexpr uint8_t TAS58XX_AGAIN = 0x54; // 0x00 = 0 dB to 0x1F = -15.5 dB in 0.5 dB steps
|
||||
static constexpr uint8_t TAS58XX_AGAIN_MINUS_15_5DB = 0x1F;
|
||||
static constexpr uint8_t TAS58XX_GPIO_CTRL = 0x60; // ADR_PIN_CTRL on TAS5805M: output enable, bit n for pin n
|
||||
static constexpr uint8_t TAS58XX_GPIO0_SEL = 0x61; // ADR_PIN_CONFIG on TAS5805M: pin n is selected at 0x61 + n
|
||||
static constexpr uint8_t TAS58XX_GPIO_SEL_FAULTZ = 0x0B; // pin function: FAULTZ output
|
||||
static constexpr uint8_t TAS58XX_POWER_STATE = 0x68;
|
||||
static constexpr uint8_t TAS58XX_CHAN_FAULT = 0x70; // GLOBAL_FAULT1, GLOBAL_FAULT2 and OT_WARNING follow
|
||||
static constexpr uint8_t TAS58XX_FAULT_REGISTER_COUNT = 4;
|
||||
@@ -102,26 +98,12 @@ bool TAS58xx::init_() {
|
||||
return false;
|
||||
}
|
||||
|
||||
// The I2C address is latched at power up, so ADR can now be an output. The pin function is written before the
|
||||
// output enable, so the pin never drives another function.
|
||||
if (this->fault_output_pin_ != FAULT_OUTPUT_NONE) {
|
||||
// The setter is public, so only write this model's pins; YAML only allows the pins of the model
|
||||
if (this->fault_output_pin_ >= this->model_->fault_output_pins) {
|
||||
ESP_LOGW(TAG, "Invalid fault output index %u", this->fault_output_pin_);
|
||||
} else if (!this->write_byte(TAS58XX_GPIO0_SEL + this->fault_output_pin_, TAS58XX_GPIO_SEL_FAULTZ) ||
|
||||
!this->write_byte(TAS58XX_GPIO_CTRL, static_cast<uint8_t>(1 << this->fault_output_pin_))) {
|
||||
ESP_LOGE(TAG, "I2C write failed during init");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Setters are public, so keep the values inside the register ranges
|
||||
// Setters are public, so keep the value inside the register range
|
||||
const uint8_t again =
|
||||
static_cast<uint8_t>(lroundf(clamp(-this->analog_gain_db_ * 2.0f, 0.0f, float{TAS58XX_AGAIN_MINUS_15_5DB})));
|
||||
const uint8_t device_ctrl_1 = (this->dac_mode_ == DAC_MODE_PBTL ? TAS58XX_DEVICE_CTRL_1_PBTL : 0) |
|
||||
(this->modulation_ == MODULATION_1SPW_MODE ? TAS58XX_DEVICE_CTRL_1_1SPW : 0);
|
||||
if (!this->write_byte(TAS58XX_DEVICE_CTRL_1, device_ctrl_1) || !this->write_byte(TAS58XX_AGAIN, again) ||
|
||||
!this->write_volume_() || !this->write_ctrl_state_(TAS58XX_CTRL_STATE_PLAY, this->is_muted_) ||
|
||||
if (!this->write_byte(TAS58XX_DEVICE_CTRL_1, this->dac_mode_ == DAC_MODE_PBTL ? TAS58XX_DEVICE_CTRL_1_PBTL : 0) ||
|
||||
!this->write_byte(TAS58XX_AGAIN, again) || !this->write_volume_() ||
|
||||
!this->write_ctrl_state_(TAS58XX_CTRL_STATE_PLAY, this->is_muted_) ||
|
||||
!this->write_byte(TAS58XX_FAULT_CLEAR, TAS58XX_FAULT_CLEAR_ANALOG)) {
|
||||
ESP_LOGE(TAG, "I2C write failed during init");
|
||||
return false;
|
||||
@@ -281,14 +263,6 @@ void TAS58xx::dump_config() {
|
||||
} else {
|
||||
mixer_mode = LOG_STR("Stereo");
|
||||
}
|
||||
const LogString *fault_output;
|
||||
if (this->fault_output_pin_ == FAULT_OUTPUT_NONE) {
|
||||
fault_output = LOG_STR("None");
|
||||
} else if (this->fault_output_pin_ >= this->model_->fault_output_pins) {
|
||||
fault_output = LOG_STR("Invalid");
|
||||
} else {
|
||||
fault_output = this->model_->fault_output_name(this->fault_output_pin_);
|
||||
}
|
||||
ESP_LOGCONFIG(TAG,
|
||||
"Audio Amplifier:\n"
|
||||
" Model: %s",
|
||||
@@ -299,14 +273,11 @@ void TAS58xx::dump_config() {
|
||||
ESP_LOGCONFIG(TAG,
|
||||
" Analog Gain: %.1f dB\n"
|
||||
" DAC Mode: %s\n"
|
||||
" Modulation: %s\n"
|
||||
" Mixer Mode: %s\n"
|
||||
" Volume Range: %.1f dB to %.1f dB\n"
|
||||
" Fault Output: %s",
|
||||
" Volume Range: %.1f dB to %.1f dB",
|
||||
this->analog_gain_db_,
|
||||
this->dac_mode_ == DAC_MODE_PBTL ? LOG_STR_LITERAL("PBTL") : LOG_STR_LITERAL("BTL"),
|
||||
this->modulation_ == MODULATION_1SPW_MODE ? LOG_STR_LITERAL("1SPW") : LOG_STR_LITERAL("BD"),
|
||||
LOG_STR_ARG(mixer_mode), this->volume_min_db_, this->volume_max_db_, LOG_STR_ARG(fault_output));
|
||||
LOG_STR_ARG(mixer_mode), this->volume_min_db_, this->volume_max_db_);
|
||||
#ifdef USE_BINARY_SENSOR
|
||||
LOG_BINARY_SENSOR(" ", "Any Fault", this->have_fault_binary_sensor_);
|
||||
for (auto *sensor : this->fault_binary_sensors_) {
|
||||
|
||||
@@ -22,12 +22,6 @@ enum DacMode : uint8_t {
|
||||
DAC_MODE_PBTL = 1, // Parallel bridge tied load, one speaker
|
||||
};
|
||||
|
||||
/// DEVICE_CTRL_1 DAMP_MOD values, the same on all models
|
||||
enum Modulation : uint8_t {
|
||||
MODULATION_BD_MODE = 0,
|
||||
MODULATION_1SPW_MODE = 1,
|
||||
};
|
||||
|
||||
enum MixerMode : uint8_t {
|
||||
MIXER_MODE_STEREO = 0,
|
||||
MIXER_MODE_STEREO_INVERSE,
|
||||
@@ -70,8 +64,6 @@ static_assert(
|
||||
|
||||
/// ModelInfo::fault_sensor_bits value for a FaultSensor that the model does not have.
|
||||
static constexpr uint8_t NO_BIT = 0xFF;
|
||||
/// fault_output_pin_ value for no fault output
|
||||
static constexpr uint8_t FAULT_OUTPUT_NONE = 0xFF;
|
||||
|
||||
/// Everything that differs between models of the family. One constant instance exists per model, see
|
||||
/// model_*.cpp, and each TAS58xx instance points to the one for its model.
|
||||
@@ -99,10 +91,6 @@ struct ModelInfo {
|
||||
const LogString *(*fault_name)(uint8_t index);
|
||||
/// Bit index for each FaultSensor, NO_BIT used where the model does not have that fault bit
|
||||
uint8_t fault_sensor_bits[FAULT_SENSOR_COUNT];
|
||||
/// Number of pins that can report FAULTZ: pin n is selected at 0x61 + n and enabled by bit n of 0x60
|
||||
uint8_t fault_output_pins;
|
||||
/// Name of FAULTZ pin n, for dump_config
|
||||
const LogString *(*fault_output_name)(uint8_t pin);
|
||||
};
|
||||
|
||||
#ifdef USE_TAS58XX_TAS5805M
|
||||
@@ -139,10 +127,7 @@ class TAS58xx : public audio_dac::AudioDac, public PollingComponent, public i2c:
|
||||
void set_enable_pin(GPIOPin *enable_pin) { this->enable_pin_ = enable_pin; }
|
||||
void set_analog_gain(float analog_gain_db) { this->analog_gain_db_ = analog_gain_db; }
|
||||
void set_dac_mode(DacMode dac_mode) { this->dac_mode_ = dac_mode; }
|
||||
/// pin: 0 to 2 for GPIOn on TAS5825M, 0 for ADR on TAS5805M; leave unset for no fault output
|
||||
void set_fault_output(uint8_t pin) { this->fault_output_pin_ = pin; }
|
||||
void set_mixer_mode(MixerMode mixer_mode) { this->mixer_mode_ = mixer_mode; }
|
||||
void set_modulation(Modulation modulation) { this->modulation_ = modulation; }
|
||||
void set_volume_min_db(float volume_min_db) { this->volume_min_db_ = volume_min_db; }
|
||||
void set_volume_max_db(float volume_max_db) { this->volume_max_db_ = volume_max_db; }
|
||||
|
||||
@@ -186,9 +171,7 @@ class TAS58xx : public audio_dac::AudioDac, public PollingComponent, public i2c:
|
||||
float volume_max_db_{24.0f};
|
||||
uint32_t logged_faults_{0}; // Fault bits as last logged, packed like the fault masks
|
||||
DacMode dac_mode_{DAC_MODE_BTL};
|
||||
uint8_t fault_output_pin_{FAULT_OUTPUT_NONE}; // No fault output: the pin keeps its power on state
|
||||
MixerMode mixer_mode_{MIXER_MODE_STEREO};
|
||||
Modulation modulation_{MODULATION_BD_MODE};
|
||||
uint8_t ctrl_state_{0};
|
||||
uint8_t power_state_{0xFF}; // Last POWER_STATE seen by update(), 0xFF until the first read
|
||||
bool mixer_written_{false}; // Mixer written since the last reset
|
||||
|
||||
@@ -2744,13 +2744,8 @@ def url(value):
|
||||
raise Invalid("Expected a file scheme or a URL scheme with host")
|
||||
|
||||
|
||||
# Characters git never allows in a branch or tag name (git check-ref-format)
|
||||
GIT_REF_PATTERN = r"[^\s~^:?*\[\\]+"
|
||||
|
||||
|
||||
def git_ref(value: typing.Any) -> str:
|
||||
value = string_strict(value)
|
||||
if re.fullmatch(GIT_REF_PATTERN, value) is None:
|
||||
def git_ref(value):
|
||||
if re.match(r"[a-zA-Z0-9_./-]+", value) is None:
|
||||
raise Invalid("Not a valid git ref")
|
||||
return value
|
||||
|
||||
@@ -3005,8 +3000,9 @@ def validate_source_shorthand(value):
|
||||
except Invalid:
|
||||
pass
|
||||
# Regex for GitHub repo name with optional branch/tag
|
||||
m = re.fullmatch(
|
||||
rf"github://(?:([a-zA-Z0-9\-]+)/([a-zA-Z0-9\-\._]+)(?:@({GIT_REF_PATTERN}))?|pr#([0-9]+))",
|
||||
# Note: git allows other branch/tag names as well, but never seen them used before
|
||||
m = re.match(
|
||||
r"github://(?:([a-zA-Z0-9\-]+)/([a-zA-Z0-9\-\._]+)(?:@([a-zA-Z0-9\-_.\./]+))?|pr#([0-9]+))",
|
||||
value,
|
||||
)
|
||||
if m is None:
|
||||
|
||||
@@ -527,7 +527,6 @@
|
||||
#define USE_SENDSPIN_CONTROLLER
|
||||
#define USE_SENDSPIN_METADATA
|
||||
#define USE_SENDSPIN_PLAYER
|
||||
#define USE_SENDSPIN_SOURCE
|
||||
#define USE_SENDSPIN_SWITCH
|
||||
#define USE_SENDSPIN_VISUALIZER
|
||||
#define USE_SENDSPIN_PORT 8928 // NOLINT
|
||||
|
||||
+5
-5
@@ -718,9 +718,9 @@ def _clone_or_update_locked(
|
||||
# compute the same cache key as this one.
|
||||
original_url = url
|
||||
if username is not None and password is not None:
|
||||
user = urllib.parse.quote(username, safe="")
|
||||
token = urllib.parse.quote(password, safe="")
|
||||
url = url.replace("://", f"://{user}:{token}@")
|
||||
url = url.replace(
|
||||
"://", f"://{urllib.parse.quote(username)}:{urllib.parse.quote(password)}@"
|
||||
)
|
||||
|
||||
hash_dir_name = _compute_destination_path(key, domain).name
|
||||
repo_dir = _repo_entry_dir(key, domain, subpath)
|
||||
@@ -1051,8 +1051,8 @@ class GitFile:
|
||||
"""Parse a git shorthand URL into its components."""
|
||||
if not isinstance(shorthand, str):
|
||||
raise ValueError("Git shorthand must be a string")
|
||||
m = re.fullmatch(
|
||||
rf"(?P<domain>[a-zA-Z0-9\-]+)://(?P<owner>[a-zA-Z0-9\-]+)/(?P<repo>[a-zA-Z0-9\-\._]+)/(?P<filename>[a-zA-Z0-9\-_.\./]+)(?:@(?P<ref>{cv.GIT_REF_PATTERN}))?(?:\?(?P<query>[a-zA-Z0-9\-_.\./]+))?",
|
||||
m = re.match(
|
||||
r"(?P<domain>[a-zA-Z0-9\-]+)://(?P<owner>[a-zA-Z0-9\-]+)/(?P<repo>[a-zA-Z0-9\-\._]+)/(?P<filename>[a-zA-Z0-9\-_.\./]+)(?:@(?P<ref>[a-zA-Z0-9\-_.\./]+))?(?:\?(?P<query>[a-zA-Z0-9\-_.\./]+))?",
|
||||
shorthand,
|
||||
)
|
||||
if m is None:
|
||||
|
||||
@@ -2,7 +2,7 @@ dependencies:
|
||||
bblanchon/arduinojson:
|
||||
version: "7.4.3"
|
||||
esphome/dlms_parser:
|
||||
version: 2.2.2
|
||||
version: 2.2.0
|
||||
esphome/esp-audio-libs:
|
||||
version: 4.1.0
|
||||
esphome/esp-micro-speech-features:
|
||||
|
||||
+2
-7
@@ -284,17 +284,12 @@ def _lookup_module(domain: str, exception: bool) -> ComponentManifest | None:
|
||||
_COMPONENT_CACHE[domain] = manif
|
||||
return manif
|
||||
|
||||
module_name = f"esphome.components.{domain}"
|
||||
try:
|
||||
module = importlib.import_module(module_name)
|
||||
module = importlib.import_module(f"esphome.components.{domain}")
|
||||
except ImportError as e:
|
||||
if exception:
|
||||
raise
|
||||
if (
|
||||
isinstance(e, ModuleNotFoundError)
|
||||
and e.name is not None
|
||||
and f"{module_name}.".startswith(f"{e.name}.")
|
||||
):
|
||||
if "No module named" in str(e):
|
||||
_LOGGER.info(
|
||||
"Unable to import component %s: %s", domain, str(e), exc_info=False
|
||||
)
|
||||
|
||||
+1
-1
@@ -106,7 +106,7 @@ build_unflags =
|
||||
; esp32 envs (which would double-include them).
|
||||
[common:idf-component-libs]
|
||||
lib_deps =
|
||||
esphome/dlms_parser@2.2.2 ; dlms_meter
|
||||
esphome/dlms_parser@2.2.0 ; dlms_meter
|
||||
bblanchon/ArduinoJson@7.4.3 ; json
|
||||
lvgl/lvgl@9.6.0 ; lvgl
|
||||
|
||||
|
||||
@@ -138,26 +138,3 @@ def test_task_log_buffer_size_unaligned_allowed_on_libretiny(
|
||||
) -> None:
|
||||
set_core_config(PlatformFramework.BK72XX_ARDUINO)
|
||||
assert validate_task_log_buffer_alignment(641) == 641
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("config", "log_v2"),
|
||||
[
|
||||
pytest.param("test_logger_idf6_esp_idf.yaml", True, id="native"),
|
||||
pytest.param("test_logger_idf6_platformio.yaml", False, id="platformio"),
|
||||
],
|
||||
)
|
||||
def test_log_v2_only_on_native_toolchain(
|
||||
generate_main: Callable[[str | Path], str],
|
||||
config: str,
|
||||
log_v2: bool,
|
||||
) -> None:
|
||||
"""PlatformIO links the bootloader with the app's build flags, so the wrap has no target there."""
|
||||
from esphome.components.esp32 import KEY_ESP32, KEY_SDKCONFIG_OPTIONS
|
||||
|
||||
generate_main(f"tests/component_tests/logger/{config}")
|
||||
|
||||
assert ("-Wl,--wrap=esp_log_format" in CORE.build_flags) is log_v2
|
||||
assert ("USE_ESP32_LOG_V2" in {d.name for d in CORE.defines}) is log_v2
|
||||
sdkconfig = CORE.data[KEY_ESP32][KEY_SDKCONFIG_OPTIONS]
|
||||
assert ("CONFIG_LOG_VERSION_2" in sdkconfig) is log_v2
|
||||
@@ -1,11 +0,0 @@
|
||||
esphome:
|
||||
name: test
|
||||
|
||||
esp32:
|
||||
board: esp32dev
|
||||
toolchain: esp-idf
|
||||
framework:
|
||||
type: esp-idf
|
||||
version: 6.1.0
|
||||
|
||||
logger:
|
||||
@@ -1,12 +0,0 @@
|
||||
esphome:
|
||||
name: test
|
||||
|
||||
esp32:
|
||||
board: esp32dev
|
||||
toolchain: platformio
|
||||
framework:
|
||||
type: esp-idf
|
||||
version: 6.1.0
|
||||
platform_version: 61.4.0-RC1
|
||||
|
||||
logger:
|
||||
@@ -1,36 +0,0 @@
|
||||
esphome:
|
||||
name: test
|
||||
|
||||
esp32:
|
||||
board: esp32dev
|
||||
framework:
|
||||
type: esp-idf
|
||||
|
||||
wifi:
|
||||
ap:
|
||||
|
||||
i2s_audio:
|
||||
- id: i2s_bus
|
||||
i2s_lrclk_pin: GPIO4
|
||||
i2s_bclk_pin: GPIO5
|
||||
|
||||
microphone:
|
||||
- platform: i2s_audio
|
||||
id: mic
|
||||
i2s_din_pin: GPIO39
|
||||
adc_type: external
|
||||
sample_rate: 16000
|
||||
|
||||
sendspin:
|
||||
source:
|
||||
microphone: mic
|
||||
|
||||
# The condition alone does not report signals, so line sense stays off
|
||||
interval:
|
||||
- interval: 10s
|
||||
then:
|
||||
- if:
|
||||
condition:
|
||||
sendspin.source.is_streaming:
|
||||
then:
|
||||
- delay: 1ms
|
||||
@@ -1,29 +0,0 @@
|
||||
esphome:
|
||||
name: test
|
||||
|
||||
esp32:
|
||||
board: esp32dev
|
||||
framework:
|
||||
type: esp-idf
|
||||
|
||||
wifi:
|
||||
ap:
|
||||
|
||||
i2s_audio:
|
||||
- id: i2s_bus
|
||||
i2s_lrclk_pin: GPIO4
|
||||
i2s_bclk_pin: GPIO5
|
||||
|
||||
microphone:
|
||||
- platform: i2s_audio
|
||||
id: mic
|
||||
i2s_din_pin: GPIO39
|
||||
adc_type: external
|
||||
sample_rate: 48000
|
||||
|
||||
sendspin:
|
||||
source:
|
||||
microphone: mic
|
||||
on_streaming_started:
|
||||
- sendspin.source.set_signal:
|
||||
present: true
|
||||
@@ -1,160 +0,0 @@
|
||||
"""Validation and code generation tests for the sendspin source role.
|
||||
|
||||
These cover the rejection branches of the source block and the generated role
|
||||
config, which a compile test cannot check: a `test*.yaml` can only assert that a
|
||||
configuration is accepted.
|
||||
"""
|
||||
|
||||
from collections.abc import Callable
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
import pytest
|
||||
|
||||
from esphome import config_validation as cv
|
||||
from esphome.automation import ACTION_REGISTRY, CONDITION_REGISTRY
|
||||
from esphome.components.audio import CONF_MAX_SAMPLE_RATE, CONF_MIN_SAMPLE_RATE
|
||||
from esphome.components.esp32.const import KEY_ESP32, KEY_SDKCONFIG_OPTIONS
|
||||
from esphome.components.sendspin import CONFIG_SCHEMA, FINAL_VALIDATE_SCHEMA, _get_data
|
||||
from esphome.config import Config
|
||||
from esphome.const import CONF_ID, CONF_SOURCE, PlatformFramework
|
||||
from esphome.core import CORE, ID
|
||||
from esphome.types import ConfigType
|
||||
from tests.component_tests.types import SetCoreConfigCallable
|
||||
|
||||
HUB_ID = "sendspin_hub"
|
||||
MIC_ID = "mic"
|
||||
|
||||
|
||||
def _full_config(min_sample_rate: int = 16000, max_sample_rate: int = 16000) -> Config:
|
||||
"""A full config carrying one microphone, as the ID pass leaves it."""
|
||||
mic: ConfigType = {
|
||||
CONF_ID: ID(MIC_ID, is_declaration=True, type="microphone"),
|
||||
CONF_MIN_SAMPLE_RATE: min_sample_rate,
|
||||
CONF_MAX_SAMPLE_RATE: max_sample_rate,
|
||||
"min_channels": 1,
|
||||
"max_channels": 2,
|
||||
"min_bits_per_sample": 16,
|
||||
"max_bits_per_sample": 32,
|
||||
}
|
||||
full = Config()
|
||||
full["microphone"] = [mic]
|
||||
full.declare_ids.append((mic[CONF_ID], ["microphone", 0, CONF_ID]))
|
||||
return full
|
||||
|
||||
|
||||
def _hub_config(**source: Any) -> ConfigType:
|
||||
"""Validate a hub config with a source block, allowing field overrides."""
|
||||
source_config: ConfigType = {
|
||||
"microphone": {"microphone": ID(MIC_ID, is_declaration=False)}
|
||||
}
|
||||
source_config.update(source)
|
||||
return CONFIG_SCHEMA({CONF_ID: HUB_ID, CONF_SOURCE: source_config})
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def microphone(set_core_config: SetCoreConfigCallable) -> None:
|
||||
set_core_config(PlatformFramework.ESP32_IDF, full_config=_full_config())
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("microphone")
|
||||
def test_final_validate_records_sample_rate() -> None:
|
||||
"""The stream takes the microphone's own rate, since nothing can resample it."""
|
||||
FINAL_VALIDATE_SCHEMA(_hub_config())
|
||||
|
||||
assert _get_data().source_sample_rate == 16000
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("microphone")
|
||||
def test_unsupported_bits_per_sample_rejected() -> None:
|
||||
with pytest.raises(cv.Invalid, match="bits_per_sample must be one of"):
|
||||
_hub_config(microphone={"microphone": MIC_ID, "bits_per_sample": 20})
|
||||
|
||||
|
||||
def test_variable_sample_rate_rejected(set_core_config: SetCoreConfigCallable) -> None:
|
||||
set_core_config(
|
||||
PlatformFramework.ESP32_IDF,
|
||||
full_config=_full_config(min_sample_rate=16000, max_sample_rate=48000),
|
||||
)
|
||||
|
||||
with pytest.raises(cv.Invalid, match="must have a fixed sample rate"):
|
||||
FINAL_VALIDATE_SCHEMA(_hub_config())
|
||||
|
||||
|
||||
def test_microphone_source_errors_point_at_the_source(
|
||||
set_core_config: SetCoreConfigCallable,
|
||||
) -> None:
|
||||
"""A channel the microphone does not have is reported at source: microphone:."""
|
||||
full_config = _full_config()
|
||||
full_config["microphone"][0]["max_channels"] = 1
|
||||
set_core_config(PlatformFramework.ESP32_IDF, full_config=full_config)
|
||||
|
||||
with pytest.raises(cv.Invalid) as err:
|
||||
FINAL_VALIDATE_SCHEMA(
|
||||
_hub_config(microphone={"microphone": MIC_ID, "channels": [0, 1]})
|
||||
)
|
||||
assert err.value.path[:2] == [CONF_SOURCE, "microphone"]
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("registry", "name", "action_config"),
|
||||
[
|
||||
(ACTION_REGISTRY, "sendspin.source.set_signal", {"present": True}),
|
||||
(CONDITION_REGISTRY, "sendspin.source.is_streaming", {}),
|
||||
],
|
||||
)
|
||||
def test_source_automation_without_source_rejected(
|
||||
set_core_config: SetCoreConfigCallable,
|
||||
registry: dict[str, Any],
|
||||
name: str,
|
||||
action_config: ConfigType,
|
||||
) -> None:
|
||||
"""The source action and condition have nothing to act on without a source block."""
|
||||
set_core_config(PlatformFramework.ESP32_IDF)
|
||||
registry[name].schema({CONF_ID: ID(HUB_ID, is_declaration=False), **action_config})
|
||||
|
||||
with pytest.raises(cv.Invalid, match="require a 'source' block"):
|
||||
FINAL_VALIDATE_SCHEMA(CONFIG_SCHEMA({CONF_ID: HUB_ID}))
|
||||
|
||||
|
||||
def _sdkconfig_option(name: str) -> Any:
|
||||
return CORE.data[KEY_ESP32][KEY_SDKCONFIG_OPTIONS].get(name)
|
||||
|
||||
|
||||
def test_line_sense_source_config_generated(
|
||||
generate_main: Callable[[str | Path], str],
|
||||
component_config_path: Callable[[str], Path],
|
||||
) -> None:
|
||||
"""The set_signal action turns on line sense."""
|
||||
main_cpp = generate_main(component_config_path("source_line_sense.yaml"))
|
||||
|
||||
assert "set_source_config(" in main_cpp
|
||||
assert ".sample_rate = 48000" in main_cpp
|
||||
assert ".line_sense = true" in main_cpp
|
||||
assert _sdkconfig_option("CONFIG_SENDSPIN_ENABLE_SOURCE") is None
|
||||
assert _sdkconfig_option("CONFIG_SENDSPIN_ENABLE_OPUS") is False
|
||||
|
||||
|
||||
def test_default_source_config_generated(
|
||||
generate_main: Callable[[str | Path], str],
|
||||
component_config_path: Callable[[str], Path],
|
||||
) -> None:
|
||||
"""Fields with no option keep sendspin-cpp's defaults, and is_streaming alone leaves line sense off."""
|
||||
main_cpp = generate_main(component_config_path("source_defaults.yaml"))
|
||||
|
||||
assert ".sample_rate = 16000" in main_cpp
|
||||
assert ".chunk_duration_ms" not in main_cpp
|
||||
assert ".capture_buffer_ms" not in main_cpp
|
||||
assert ".line_sense = false" in main_cpp
|
||||
assert ".buffer_location" not in main_cpp
|
||||
assert _sdkconfig_option("CONFIG_SENDSPIN_ENABLE_OPUS") is False
|
||||
|
||||
|
||||
def test_no_source_disables_the_role(
|
||||
generate_main: Callable[[str | Path], str],
|
||||
component_config_path: Callable[[str], Path],
|
||||
) -> None:
|
||||
main_cpp = generate_main(component_config_path("device_info_default.yaml"))
|
||||
|
||||
assert "set_source_config(" not in main_cpp
|
||||
assert _sdkconfig_option("CONFIG_SENDSPIN_ENABLE_SOURCE") is False
|
||||
@@ -1,31 +0,0 @@
|
||||
"""Tests that the TAS58xx fault_output and modulation defaults keep the existing behaviour."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from collections.abc import Callable
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
def test_tas58xx_defaults_keep_the_fault_pin_and_bd_modulation(
|
||||
generate_main: Callable[[str | Path], str],
|
||||
) -> None:
|
||||
"""Without fault_output or modulation each model keeps its usual fault pin and BD modulation."""
|
||||
main_cpp = generate_main(
|
||||
"tests/component_tests/tas58xx/test_tas58xx_fault_output_modulation.yaml"
|
||||
)
|
||||
|
||||
assert "amp_5805_default->set_fault_output(0);" in main_cpp
|
||||
assert "amp_5825_default->set_fault_output(1);" in main_cpp
|
||||
for amp in ("amp_5805_default", "amp_5825_default", "amp_5805_none"):
|
||||
assert f"{amp}->set_modulation(tas58xx::MODULATION_BD_MODE);" in main_cpp
|
||||
|
||||
|
||||
def test_tas58xx_fault_output_none_leaves_the_pin_alone(
|
||||
generate_main: Callable[[str | Path], str],
|
||||
) -> None:
|
||||
"""fault_output: none does not configure a fault pin."""
|
||||
main_cpp = generate_main(
|
||||
"tests/component_tests/tas58xx/test_tas58xx_fault_output_modulation.yaml"
|
||||
)
|
||||
|
||||
assert "amp_5805_none->set_fault_output(" not in main_cpp
|
||||
@@ -1,26 +0,0 @@
|
||||
esphome:
|
||||
name: test
|
||||
|
||||
esp32:
|
||||
board: esp32dev
|
||||
|
||||
i2c:
|
||||
id: i2c_bus
|
||||
sda: 21
|
||||
scl: 22
|
||||
|
||||
audio_dac:
|
||||
- platform: tas58xx
|
||||
model: tas5805m
|
||||
id: amp_5805_default
|
||||
ignore_enable_pin_warning: true
|
||||
- platform: tas58xx
|
||||
model: tas5825m
|
||||
id: amp_5825_default
|
||||
ignore_enable_pin_warning: true
|
||||
- platform: tas58xx
|
||||
model: tas5805m
|
||||
id: amp_5805_none
|
||||
address: 0x2C
|
||||
ignore_enable_pin_warning: true
|
||||
fault_output: none
|
||||
@@ -11,6 +11,14 @@ namespace esphome::testing {
|
||||
// build_plain() compressed with the CLI's window (espota2.DEFLATE_WINDOW_BITS):
|
||||
// DEFLATED = zlib.compress(plain, 9, wbits=-12)
|
||||
// STORED = zlib.compress(plain[:300], 0, wbits=-12)
|
||||
// c = zlib.compressobj(9, zlib.DEFLATED, -12, 9, zlib.Z_FIXED)
|
||||
// FIXED = c.compress(plain) + c.flush()
|
||||
// and build_skewed(), whose rare bytes get codes longer than the lookup tables:
|
||||
// SKEWED = zlib.compress(skewed, 9, wbits=-12)
|
||||
// and build_mixed() in three parts, so stored blocks follow Huffman blocks:
|
||||
// c = zlib.compressobj(9, zlib.DEFLATED, -12)
|
||||
// MIXED = (c.compress(text) + c.flush(zlib.Z_SYNC_FLUSH) + c.compress(noise)
|
||||
// + c.flush(zlib.Z_SYNC_FLUSH) + c.compress(tail) + c.flush())
|
||||
static const uint8_t DEFLATED[] = {
|
||||
0xed, 0xc8, 0xf7, 0x3f, 0xd4, 0x0f, 0x03, 0x00, 0x70, 0x67, 0xaf, 0x4b, 0x67, 0x66, 0x9f, 0x90, 0x91, 0x11, 0xc2,
|
||||
0x11, 0x91, 0xb8, 0xb3, 0xf7, 0x3a, 0xd9, 0x5f, 0x4e, 0x99, 0x67, 0x1e, 0xce, 0x8a, 0xac, 0xec, 0x59, 0xb8, 0xc2,
|
||||
@@ -201,6 +209,532 @@ static const uint8_t STORED[] = {
|
||||
0x68, 0x6f, 0x6d, 0x65, 0x20, 0x6f, 0x74, 0x61, 0x20, 0x64, 0x65, 0x66, 0x6c, 0x61, 0x74, 0x65, 0x20,
|
||||
};
|
||||
|
||||
static const uint8_t FIXED[] = {
|
||||
0x4b, 0x2d, 0x2e, 0xc8, 0xc8, 0xcf, 0x4d, 0x55, 0xc8, 0x2f, 0x49, 0x54, 0x48, 0x49, 0x4d, 0xcb, 0x49, 0x2c, 0x49,
|
||||
0x55, 0x48, 0x1d, 0x15, 0x1b, 0x15, 0x1b, 0x15, 0x1b, 0x15, 0x1b, 0x15, 0x1b, 0x15, 0x1b, 0x15, 0x1b, 0x15, 0x1b,
|
||||
0x15, 0x1b, 0x15, 0x1b, 0x15, 0x1b, 0x15, 0x1b, 0x15, 0x1b, 0x15, 0x1b, 0x15, 0x1b, 0x15, 0x1b, 0x15, 0x1b, 0x15,
|
||||
0x1b, 0x15, 0x1b, 0x15, 0x1b, 0x15, 0x1b, 0x15, 0x1b, 0x15, 0x23, 0x49, 0xec, 0x58, 0x5d, 0x63, 0xb6, 0xf7, 0xef,
|
||||
0x47, 0xbf, 0x43, 0xbe, 0xed, 0xbd, 0x5f, 0x23, 0xf3, 0xb0, 0x9d, 0x71, 0xbf, 0xe1, 0xbd, 0xb0, 0x22, 0x7e, 0xf7,
|
||||
0xf4, 0xb4, 0xf6, 0xc8, 0x55, 0x1d, 0x36, 0x91, 0xaf, 0xc2, 0x84, 0xab, 0x2f, 0xb5, 0x2e, 0xbc, 0x61, 0x13, 0x12,
|
||||
0xaa, 0x6f, 0xbe, 0x2e, 0x35, 0xfa, 0x16, 0x53, 0xe5, 0x8c, 0x33, 0x8f, 0xa5, 0xca, 0xfa, 0xe2, 0x6f, 0xce, 0xec,
|
||||
0x97, 0xb7, 0x37, 0x7b, 0xe7, 0x5c, 0xe1, 0xcb, 0xfb, 0x6b, 0xdf, 0xb2, 0x5b, 0x4f, 0xda, 0xfa, 0xee, 0x68, 0xe6,
|
||||
0xfa, 0xfd, 0x0f, 0x7b, 0x58, 0xa0, 0xf0, 0xbb, 0x7f, 0x63, 0x04, 0xeb, 0x84, 0xa3, 0x9c, 0x77, 0x82, 0xcf, 0xae,
|
||||
0xb2, 0xf6, 0x98, 0x19, 0x74, 0x39, 0x68, 0x2e, 0xdb, 0xfc, 0x57, 0x5b, 0x0f, 0xb1, 0x09, 0xcf, 0xf0, 0xdc, 0xc4,
|
||||
0x28, 0xb7, 0xc6, 0xa8, 0xc3, 0x70, 0x4e, 0x90, 0xdb, 0xd4, 0x42, 0xb3, 0xfe, 0xf0, 0x6f, 0x96, 0xb2, 0x62, 0xbf,
|
||||
0x3a, 0x4a, 0xbe, 0xce, 0xa8, 0x11, 0x8f, 0x71, 0xdc, 0x9d, 0x5b, 0xd8, 0xc7, 0x5f, 0x10, 0x79, 0x9c, 0x51, 0x5a,
|
||||
0xdf, 0xd8, 0x76, 0xe2, 0x01, 0xd9, 0xa5, 0xbc, 0xbc, 0xab, 0x8d, 0x7b, 0xeb, 0xe2, 0xfa, 0xed, 0x9e, 0x65, 0x94,
|
||||
0x2c, 0xb3, 0xda, 0x78, 0x78, 0xb2, 0xe0, 0x8a, 0x94, 0xe3, 0xb7, 0x4f, 0x3d, 0x48, 0x78, 0xf8, 0x79, 0x3f, 0x27,
|
||||
0x43, 0xfa, 0xa2, 0xc7, 0xaa, 0x0b, 0x14, 0x0d, 0xdb, 0xaf, 0x26, 0x1d, 0x5d, 0xe1, 0x5f, 0xa7, 0xc7, 0x99, 0x3d,
|
||||
0x65, 0xfe, 0x86, 0xdc, 0x95, 0xf3, 0xa2, 0xb8, 0xdd, 0x0a, 0x1a, 0xb6, 0x9d, 0x77, 0xe7, 0x59, 0xb6, 0x54, 0xeb,
|
||||
0xc6, 0x9a, 0xdf, 0x0b, 0x5e, 0x6f, 0xaf, 0x54, 0x29, 0x52, 0x9e, 0xe4, 0xd1, 0x70, 0x74, 0xd9, 0xf2, 0xd6, 0xed,
|
||||
0xd7, 0x7b, 0x26, 0x3c, 0x59, 0x9d, 0xec, 0x12, 0x94, 0xf6, 0x78, 0x8e, 0xb1, 0xea, 0xcf, 0xb8, 0x55, 0xbb, 0x8a,
|
||||
0x13, 0x62, 0xbd, 0x0b, 0xeb, 0xf6, 0xad, 0xec, 0x09, 0x97, 0x2c, 0x3c, 0x7c, 0x2a, 0xee, 0xa9, 0x96, 0xf1, 0x9a,
|
||||
0x8e, 0xc0, 0xb4, 0x85, 0xd5, 0xa5, 0xe9, 0x29, 0xb3, 0x32, 0xdf, 0xe7, 0x87, 0x39, 0x2d, 0x90, 0x0d, 0x3c, 0xca,
|
||||
0xf4, 0x7d, 0xf7, 0x24, 0xd7, 0x7d, 0xf9, 0xbc, 0xdb, 0x2c, 0xce, 0x08, 0xfc, 0xdd, 0x1d, 0x12, 0x28, 0x53, 0xcd,
|
||||
0x3e, 0x45, 0x7d, 0x72, 0xed, 0xa4, 0xc3, 0x57, 0x8e, 0x2d, 0x4d, 0x0c, 0x64, 0xb4, 0xb0, 0x58, 0xbe, 0xff, 0x23,
|
||||
0x0b, 0xaf, 0xe8, 0xec, 0x06, 0xf9, 0xe6, 0xab, 0x4b, 0x32, 0x3b, 0x6a, 0xe6, 0x6f, 0x63, 0xbc, 0x35, 0x59, 0xdc,
|
||||
0xb5, 0x5b, 0x68, 0x13, 0x93, 0x71, 0x4c, 0xc0, 0xb5, 0x87, 0x61, 0x4b, 0xd6, 0x3a, 0x79, 0xc5, 0xdc, 0x6d, 0x4b,
|
||||
0x7c, 0xc9, 0x2c, 0xf4, 0x90, 0x7f, 0xf6, 0x2b, 0x35, 0x9d, 0xc4, 0x3b, 0x49, 0x1e, 0xd9, 0xb9, 0x22, 0x0f, 0x98,
|
||||
0x5b, 0xbd, 0x8a, 0xdc, 0x6e, 0x4d, 0x3b, 0x51, 0x2b, 0x73, 0x91, 0xd5, 0xee, 0xe9, 0xa4, 0x02, 0xe7, 0xf8, 0x1c,
|
||||
0x66, 0xd6, 0xcd, 0xaf, 0x37, 0x2b, 0x98, 0xfa, 0xd6, 0xa5, 0x05, 0x30, 0x9a, 0x1d, 0x30, 0x7e, 0xc8, 0x7f, 0xd2,
|
||||
0x42, 0xef, 0xa5, 0xa6, 0xa4, 0x7f, 0xdc, 0xc6, 0x8b, 0x9e, 0xdd, 0xd6, 0xc1, 0x7f, 0xe7, 0xdb, 0xbf, 0x53, 0x55,
|
||||
0x35, 0xad, 0xe6, 0x15, 0x5c, 0xef, 0x23, 0xd8, 0x63, 0x74, 0xe5, 0x56, 0xfd, 0x0d, 0xb1, 0xf0, 0x87, 0xcb, 0xce,
|
||||
0xd5, 0x1e, 0x5c, 0x97, 0xb4, 0x5f, 0xf8, 0x49, 0xbb, 0x8f, 0xd5, 0xc1, 0xcd, 0x3c, 0x91, 0x33, 0xdd, 0x23, 0xa2,
|
||||
0xf6, 0x56, 0xd4, 0xec, 0x0a, 0x60, 0x7c, 0x2b, 0xfd, 0xaa, 0xcb, 0xb3, 0xe3, 0xdd, 0x35, 0x91, 0xd6, 0xd5, 0x1b,
|
||||
0x74, 0xee, 0x99, 0x4e, 0x16, 0xd4, 0x65, 0x94, 0xb9, 0xae, 0xe1, 0x6c, 0xf0, 0x7c, 0x03, 0xc7, 0xdb, 0xca, 0x99,
|
||||
0xc2, 0x81, 0x97, 0xac, 0xca, 0xd7, 0xda, 0x6e, 0xf9, 0x71, 0xfc, 0x14, 0xb3, 0xd2, 0xa5, 0x93, 0xc7, 0xd4, 0xf9,
|
||||
0x59, 0xce, 0x55, 0xd9, 0x1f, 0xc8, 0xd0, 0x39, 0x5f, 0x94, 0xc5, 0x79, 0xc8, 0x89, 0xa1, 0x28, 0xce, 0xd1, 0xe4,
|
||||
0xc7, 0xb4, 0x4c, 0xfb, 0xbd, 0x56, 0x11, 0x13, 0xbb, 0x1f, 0x9e, 0x59, 0xb4, 0x71, 0xd2, 0xdd, 0xf2, 0x85, 0xa6,
|
||||
0xff, 0x3e, 0x7b, 0xef, 0xd9, 0xf8, 0xd8, 0x5c, 0x90, 0xf7, 0x78, 0xea, 0xbe, 0x8f, 0x89, 0x4f, 0xe3, 0xd8, 0xfe,
|
||||
0x9b, 0x1e, 0x2f, 0xeb, 0x8c, 0xfd, 0x92, 0xe7, 0x75, 0x66, 0x6b, 0x48, 0xdd, 0x47, 0xd1, 0x13, 0x0b, 0x66, 0xf6,
|
||||
0xc7, 0x14, 0x70, 0xbf, 0x17, 0x39, 0xf6, 0x94, 0x6b, 0x8e, 0xe4, 0x16, 0x59, 0x9f, 0x73, 0x61, 0x6c, 0x77, 0x9c,
|
||||
0x04, 0x55, 0x9f, 0x4f, 0xcb, 0xe7, 0x57, 0xb4, 0xbd, 0xff, 0x33, 0xdc, 0x9d, 0xf7, 0xbe, 0x76, 0xd6, 0x9f, 0xf2,
|
||||
0xde, 0xab, 0x2f, 0x6f, 0xfe, 0xdc, 0xfa, 0xe0, 0x75, 0x51, 0x8b, 0x54, 0x9f, 0x93, 0x88, 0x6c, 0x57, 0x5e, 0xfc,
|
||||
0x24, 0xab, 0xdf, 0xdc, 0x4f, 0xbf, 0x3d, 0x39, 0x30, 0xdf, 0xf5, 0x9a, 0x56, 0xf3, 0xfe, 0x8d, 0x67, 0xb3, 0x8e,
|
||||
0xec, 0xef, 0xb9, 0x77, 0x7f, 0xd3, 0xf7, 0xca, 0xef, 0x09, 0xe1, 0x7f, 0xac, 0x6d, 0xab, 0xf5, 0x4e, 0xcf, 0x71,
|
||||
0xac, 0x56, 0x5f, 0xfa, 0xd8, 0x23, 0x42, 0x94, 0x5d, 0xfc, 0xc1, 0xce, 0xd6, 0xf8, 0xe4, 0x15, 0xdf, 0x34, 0x85,
|
||||
0x9c, 0x19, 0xb2, 0x6e, 0xbf, 0x4b, 0x51, 0x09, 0xea, 0x3e, 0x62, 0x1d, 0xbb, 0xdb, 0x54, 0x62, 0xd1, 0xe5, 0xce,
|
||||
0xff, 0x9b, 0x16, 0x44, 0x1a, 0x7c, 0xba, 0x7d, 0xf5, 0xa0, 0x6f, 0x96, 0xb7, 0xd9, 0x9c, 0xd8, 0x8a, 0x67, 0x17,
|
||||
0x16, 0x4f, 0xe2, 0x7d, 0x3a, 0x41, 0x70, 0x43, 0x1b, 0xbf, 0xa3, 0x49, 0xc3, 0xb2, 0xce, 0xbd, 0x2f, 0xf5, 0x2b,
|
||||
0xdc, 0x79, 0x03, 0xa6, 0xb6, 0x4b, 0xef, 0x7f, 0x5c, 0x3f, 0xc5, 0xdc, 0xec, 0x49, 0xbe, 0xa5, 0x85, 0x3e, 0x4f,
|
||||
0xb3, 0x55, 0xeb, 0xfd, 0xc0, 0x3d, 0x1e, 0x37, 0xc3, 0x76, 0x57, 0x4e, 0xad, 0xdc, 0x7b, 0xc5, 0x23, 0x60, 0xee,
|
||||
0xca, 0xd4, 0x58, 0xf1, 0x1a, 0x61, 0x6e, 0xa1, 0x18, 0xff, 0xf4, 0x0d, 0x2c, 0x0f, 0xe7, 0x49, 0x6c, 0x66, 0xb0,
|
||||
0xfa, 0x77, 0xfa, 0x88, 0xcc, 0x77, 0xed, 0x00, 0x8b, 0x3a, 0xbf, 0xdd, 0xc2, 0x47, 0x15, 0x0e, 0xff, 0xb3, 0x5d,
|
||||
0x62, 0xc0, 0xff, 0xc4, 0x9d, 0xeb, 0x49, 0x10, 0x63, 0x95, 0x78, 0xa3, 0x61, 0x43, 0x43, 0xbc, 0x69, 0x94, 0xae,
|
||||
0xe8, 0x99, 0x0d, 0x4a, 0xa2, 0xba, 0x0d, 0x17, 0x9f, 0x3d, 0x39, 0x13, 0xb1, 0x3e, 0x9f, 0xb5, 0xb6, 0x75, 0x8e,
|
||||
0x69, 0x56, 0xc9, 0x82, 0x0f, 0x1a, 0xfe, 0xdf, 0x7f, 0xde, 0xb1, 0x60, 0xd8, 0x7c, 0xe4, 0x5d, 0x88, 0xdf, 0xc7,
|
||||
0x9b, 0xaf, 0xd6, 0x1e, 0xba, 0xfe, 0x5a, 0x52, 0xe5, 0x48, 0xd8, 0x8a, 0xee, 0xd3, 0x21, 0xd9, 0xeb, 0x0b, 0x22,
|
||||
0xa2, 0xd8, 0x23, 0xff, 0x31, 0xb0, 0xdd, 0x5f, 0xf8, 0x4c, 0x22, 0x72, 0xd7, 0xc1, 0x68, 0xe5, 0x3f, 0xd1, 0x72,
|
||||
0x05, 0x06, 0x4e, 0x52, 0x57, 0x2e, 0x18, 0x15, 0x4d, 0x48, 0x73, 0xca, 0x99, 0xbb, 0xe8, 0xe2, 0xdb, 0x72, 0x3b,
|
||||
0x83, 0x6d, 0xeb, 0x26, 0xf1, 0x26, 0xea, 0x7d, 0x5b, 0x24, 0xe5, 0x79, 0x7b, 0xa1, 0x6c, 0xe7, 0x8a, 0x7b, 0x9f,
|
||||
0x2c, 0xc2, 0x76, 0x65, 0xaf, 0x3e, 0x15, 0x1c, 0x15, 0xfc, 0x2d, 0x57, 0xb8, 0x71, 0x9d, 0xfc, 0xd2, 0x3f, 0x5e,
|
||||
0xb6, 0xd7, 0x5d, 0x19, 0x3b, 0x9f, 0x2c, 0x61, 0x98, 0xf1, 0xed, 0xb7, 0x6f, 0x5b, 0x8a, 0x5b, 0x7c, 0xe4, 0x9a,
|
||||
0xaf, 0x95, 0x66, 0xfa, 0xaf, 0x4e, 0xb9, 0xad, 0x0f, 0x70, 0x4b, 0xeb, 0x54, 0x74, 0x9a, 0xb8, 0xb1, 0xec, 0x12,
|
||||
0x6f, 0x51, 0xef, 0xe3, 0x88, 0xc7, 0x73, 0xc4, 0x2f, 0x6a, 0x44, 0x24, 0xab, 0xe7, 0xb9, 0x64, 0x37, 0x2d, 0xd9,
|
||||
0x35, 0xa3, 0xf8, 0xd7, 0xee, 0xff, 0x73, 0xa4, 0xca, 0x3e, 0xc9, 0x6b, 0xce, 0x4c, 0x3a, 0x51, 0x13, 0xfd, 0xfb,
|
||||
0xa7, 0x94, 0xdb, 0xdf, 0xc8, 0x6f, 0x47, 0x6f, 0xdb, 0xbc, 0x2c, 0x9c, 0x76, 0xa1, 0x50, 0xe6, 0x06, 0xaf, 0xce,
|
||||
0xcc, 0x0b, 0x51, 0x42, 0x81, 0x17, 0x18, 0x4a, 0xdb, 0x57, 0xf8, 0xef, 0x4a, 0x3b, 0x30, 0xe9, 0xea, 0x85, 0xef,
|
||||
0x5b, 0xda, 0x9e, 0xda, 0xaf, 0x0f, 0x0d, 0xfd, 0xba, 0xc3, 0x2f, 0x8d, 0x51, 0xa7, 0xf6, 0xc8, 0x26, 0x0b, 0x0d,
|
||||
0x9e, 0x30, 0xef, 0xf3, 0xe2, 0x73, 0x6c, 0x9f, 0xb0, 0xaf, 0xb6, 0xf1, 0x12, 0xfa, 0x57, 0x3d, 0x41, 0x90, 0x6d,
|
||||
0xe6, 0xab, 0xe3, 0xb5, 0x17, 0x3f, 0x7f, 0xea, 0x79, 0xae, 0x2a, 0x32, 0xe7, 0x9c, 0xc8, 0xbf, 0x3f, 0x92, 0xb9,
|
||||
0x8a, 0xe6, 0x1a, 0x9b, 0xa6, 0x18, 0xf3, 0x6f, 0x7e, 0xc2, 0xe5, 0x7a, 0x7a, 0xfe, 0x0a, 0xc1, 0x07, 0xf3, 0x35,
|
||||
0xb7, 0x48, 0x88, 0xbf, 0x0f, 0x8f, 0x89, 0x6f, 0xdb, 0xdc, 0x5b, 0x6f, 0xd9, 0xd4, 0x59, 0x5b, 0xb8, 0xf2, 0x4e,
|
||||
0xfa, 0x05, 0x25, 0x37, 0x79, 0xc1, 0xd5, 0x1f, 0x5f, 0xce, 0x33, 0xc8, 0xdf, 0xf6, 0xee, 0x67, 0xa9, 0xde, 0xd2,
|
||||
0x29, 0x91, 0xf5, 0x99, 0x0d, 0xbe, 0x2f, 0x5a, 0xe7, 0x45, 0xb2, 0x38, 0x44, 0x48, 0x5d, 0xff, 0xdd, 0x67, 0x33,
|
||||
0x8b, 0xd7, 0x75, 0xa7, 0x5b, 0x3c, 0xdf, 0xb9, 0x47, 0xc7, 0x2c, 0x0e, 0xf5, 0xaa, 0x6c, 0x0d, 0xf3, 0xb6, 0x3d,
|
||||
0xcb, 0xdd, 0x1f, 0xd9, 0x22, 0xd6, 0x33, 0xff, 0x8c, 0x8a, 0x8d, 0x4e, 0xf6, 0x39, 0xdd, 0x6f, 0xab, 0x6e, 0xf1,
|
||||
0xa5, 0x1c, 0x36, 0xff, 0xbb, 0x92, 0x63, 0x7b, 0xdf, 0x93, 0xcb, 0x5d, 0xb3, 0x7f, 0x1a, 0xd6, 0x9d, 0xd3, 0xf5,
|
||||
0xfd, 0xf1, 0xbe, 0x79, 0xde, 0xc6, 0x77, 0xb7, 0x2e, 0x18, 0x6d, 0x38, 0x5c, 0xcc, 0x3b, 0x4b, 0x25, 0xed, 0xe1,
|
||||
0xbd, 0x3e, 0x26, 0xee, 0x8e, 0x58, 0x36, 0x1d, 0xf7, 0xa9, 0xae, 0xf1, 0x7f, 0xca, 0x05, 0xcd, 0x59, 0x9e, 0xa5,
|
||||
0x55, 0xbb, 0xd5, 0x5e, 0x5b, 0xf8, 0x3b, 0xd7, 0x82, 0xdb, 0x41, 0x5c, 0x80, 0x39, 0x36, 0x77, 0x6f, 0xc5, 0x65,
|
||||
0xce, 0xd4, 0x32, 0x75, 0xae, 0x85, 0xe9, 0x85, 0x9b, 0x9e, 0x73, 0x2f, 0x3e, 0xb0, 0xdb, 0x72, 0x56, 0xdf, 0xd4,
|
||||
0xe0, 0x67, 0xaf, 0x27, 0x76, 0x45, 0x6d, 0xbb, 0x79, 0x3d, 0xc8, 0xfe, 0xd2, 0x96, 0xe3, 0xb1, 0x9c, 0xf3, 0x44,
|
||||
0xfc, 0xef, 0xf8, 0xb4, 0x06, 0xbf, 0x58, 0xb3, 0x94, 0xc3, 0x6c, 0x91, 0x4b, 0x8b, 0x4a, 0x83, 0x97, 0xa9, 0xa8,
|
||||
0xb3, 0x7d, 0xc5, 0x8d, 0xc9, 0xd3, 0x7e, 0xdf, 0xac, 0xdc, 0x73, 0x99, 0xeb, 0xde, 0xd3, 0x98, 0xfe, 0xe3, 0x13,
|
||||
0xaf, 0xe8, 0x04, 0x3d, 0xd8, 0x9e, 0x5f, 0x30, 0xfb, 0xc6, 0xdc, 0x84, 0x7f, 0x2e, 0xb1, 0xef, 0xdd, 0xaf, 0xa9,
|
||||
0x15, 0xfe, 0x9f, 0x95, 0x55, 0xcb, 0xfd, 0xa8, 0x3e, 0xa7, 0x50, 0x2b, 0x68, 0xc2, 0xeb, 0xb5, 0xa7, 0x4c, 0xf5,
|
||||
0x0e, 0xff, 0x8d, 0xfc, 0xce, 0x28, 0xaa, 0x75, 0x8b, 0x9f, 0xd1, 0xe5, 0x94, 0xfb, 0xed, 0xe5, 0xe9, 0xc2, 0x32,
|
||||
0x55, 0xdc, 0xcc, 0x4d, 0x8d, 0x93, 0x37, 0xee, 0x49, 0x78, 0x1b, 0x7a, 0xbb, 0x37, 0x4d, 0xbd, 0x52, 0x6c, 0x63,
|
||||
0xc5, 0x72, 0x89, 0x6d, 0xfd, 0x33, 0x7e, 0x2b, 0xb8, 0xf0, 0xe5, 0x2d, 0x8d, 0xeb, 0x50, 0x13, 0x59, 0xa7, 0x11,
|
||||
0xa6, 0xf0, 0x22, 0xed, 0xed, 0x3b, 0x97, 0xf2, 0x49, 0x09, 0x37, 0xaa, 0x13, 0xe4, 0xb7, 0x64, 0x26, 0x66, 0xef,
|
||||
0xde, 0x7d, 0x66, 0x91, 0xcb, 0xcd, 0x7f, 0x13, 0x4b, 0xdc, 0xac, 0xea, 0x22, 0x7b, 0x14, 0x3f, 0x1e, 0x7f, 0xf1,
|
||||
0xc1, 0xed, 0xf3, 0xb6, 0xea, 0x2f, 0x17, 0x67, 0xbf, 0x9d, 0xad, 0x5b, 0x62, 0x7b, 0xbe, 0x9b, 0x31, 0x7f, 0xf9,
|
||||
0x81, 0xc0, 0x7e, 0x16, 0xdf, 0xb7, 0x79, 0x0b, 0xeb, 0x8e, 0x48, 0xdf, 0x77, 0xbf, 0xa5, 0xe0, 0x77, 0x73, 0x7d,
|
||||
0xd3, 0x6f, 0xf6, 0x82, 0xb2, 0x9a, 0x98, 0x07, 0x8f, 0xf7, 0xfc, 0x60, 0x99, 0xd3, 0xae, 0x3f, 0x31, 0xea, 0xca,
|
||||
0x03, 0xb1, 0xaa, 0x6b, 0x53, 0x5f, 0xd6, 0x1c, 0x8c, 0xbf, 0x6c, 0x1e, 0x93, 0x5f, 0x7d, 0xd7, 0xbb, 0x64, 0xf2,
|
||||
0x66, 0xa9, 0x1d, 0x47, 0x7a, 0x39, 0x7f, 0x45, 0x71, 0xcd, 0xe2, 0x5c, 0x3f, 0xf5, 0xb6, 0x6a, 0xa4, 0x78, 0x89,
|
||||
0xa8, 0x70, 0x4d, 0x3e, 0x47, 0xce, 0x9b, 0x53, 0x3a, 0x86, 0xc7, 0xf6, 0x09, 0xcc, 0x8e, 0x39, 0xbb, 0xcb, 0xb2,
|
||||
0xb0, 0xaf, 0x63, 0x4e, 0xb1, 0xc5, 0xf1, 0x23, 0x15, 0x1f, 0x44, 0x7d, 0x7f, 0x5f, 0x2a, 0x8f, 0x0c, 0x3e, 0x68,
|
||||
0x69, 0xf3, 0xfd, 0x7d, 0xe7, 0xab, 0x62, 0xed, 0x4b, 0x8a, 0x9a, 0xef, 0x6e, 0x86, 0x9d, 0x50, 0x99, 0x95, 0xd8,
|
||||
0xb7, 0xeb, 0xc1, 0x0b, 0xdb, 0xd7, 0xcb, 0xbb, 0xef, 0x79, 0x1b, 0x5e, 0xb1, 0x9c, 0xf0, 0xea, 0x2e, 0xbf, 0xf2,
|
||||
0xdf, 0x7d, 0x72, 0xd9, 0x9b, 0xf6, 0x5e, 0xba, 0xd2, 0x67, 0x7a, 0x7a, 0xa1, 0xa6, 0x93, 0x70, 0xf9, 0x59, 0x23,
|
||||
0xe9, 0xa5, 0x97, 0x57, 0x57, 0x99, 0xec, 0x9b, 0x93, 0xb6, 0x49, 0xe4, 0xc9, 0xbb, 0xfd, 0x0c, 0x47, 0xff, 0x86,
|
||||
0xac, 0x64, 0xe7, 0xbf, 0x16, 0xf0, 0x66, 0xc3, 0x7d, 0x9d, 0xeb, 0x3b, 0x8f, 0xb3, 0xee, 0xf6, 0xfa, 0x32, 0xc9,
|
||||
0xa5, 0xed, 0xd9, 0x94, 0x13, 0x82, 0x8c, 0xeb, 0xdf, 0x78, 0x4b, 0x72, 0x8b, 0x79, 0x1e, 0x58, 0x37, 0x6d, 0xba,
|
||||
0xff, 0xf4, 0xc9, 0x1b, 0xb6, 0xce, 0xde, 0x6e, 0xc5, 0xc4, 0x38, 0x8b, 0x69, 0xd3, 0x9d, 0x0f, 0xbb, 0x76, 0x69,
|
||||
0x17, 0x96, 0x84, 0x6c, 0xec, 0xbe, 0xdb, 0x3d, 0xf5, 0x94, 0x55, 0xeb, 0x2e, 0x66, 0x95, 0x29, 0x77, 0x5c, 0x98,
|
||||
0x7f, 0xe7, 0x57, 0xfb, 0x34, 0x58, 0xbc, 0xac, 0xda, 0xb6, 0xc2, 0xe5, 0x1c, 0xfb, 0xef, 0xf5, 0xc7, 0x9a, 0x45,
|
||||
0xa3, 0x62, 0x73, 0xc4, 0x7f, 0x72, 0xd4, 0x1e, 0x79, 0x96, 0xfb, 0x6f, 0xba, 0xe8, 0xc3, 0xce, 0x05, 0xbb, 0x57,
|
||||
0xcc, 0x54, 0xda, 0xf7, 0xe6, 0xc6, 0xbb, 0xdb, 0x95, 0xaa, 0x75, 0x33, 0xed, 0xd2, 0x2f, 0x7c, 0x6c, 0x11, 0xe1,
|
||||
0xd8, 0xf5, 0xba, 0xe1, 0xe8, 0x35, 0xcd, 0x67, 0xf6, 0xf2, 0x4d, 0x16, 0xaa, 0xfc, 0xec, 0xcb, 0x2c, 0x0c, 0xfb,
|
||||
0x3e, 0x2c, 0xf7, 0x2e, 0xcd, 0xd1, 0xf4, 0x10, 0xbb, 0x76, 0xf7, 0x05, 0xc7, 0xed, 0x87, 0x6a, 0xd2, 0x29, 0x5b,
|
||||
0x72, 0x84, 0x16, 0xfb, 0x54, 0xca, 0xdd, 0xfb, 0xc6, 0x27, 0xff, 0xef, 0x53, 0xcc, 0xac, 0x6b, 0xa7, 0x74, 0x2b,
|
||||
0x4c, 0xcb, 0xae, 0xb4, 0xac, 0x32, 0xbc, 0xb6, 0x48, 0x4a, 0x32, 0xf4, 0x02, 0x73, 0xa7, 0xc3, 0xbd, 0x5e, 0x73,
|
||||
0x9b, 0xb7, 0xa1, 0x3c, 0x81, 0x2b, 0x7f, 0x1e, 0x0b, 0x75, 0x4b, 0x0e, 0x90, 0xb4, 0xb9, 0x76, 0x27, 0xf4, 0xe0,
|
||||
0xae, 0x63, 0xc1, 0xdc, 0xea, 0x9a, 0x71, 0x4e, 0xc6, 0xb6, 0xaf, 0xdc, 0xff, 0x94, 0x37, 0xa8, 0x97, 0xc4, 0x15,
|
||||
0xc4, 0xbe, 0xd7, 0x37, 0x39, 0x9d, 0x67, 0xb0, 0xac, 0x7c, 0xe5, 0x95, 0x47, 0x6c, 0xf7, 0xa6, 0xfc, 0xfc, 0x19,
|
||||
0xd3, 0x11, 0xb5, 0xf2, 0xdc, 0x71, 0x46, 0x66, 0x8f, 0x96, 0x58, 0x16, 0xe1, 0xa7, 0x4c, 0x9f, 0x2d, 0x17, 0x09,
|
||||
0x27, 0x9d, 0x4f, 0xca, 0x7d, 0xc4, 0x7a, 0x6d, 0x4a, 0xe7, 0xfb, 0x89, 0x71, 0xaa, 0x02, 0xeb, 0x12, 0x6d, 0x57,
|
||||
0x2b, 0xc8, 0x9e, 0x3e, 0x75, 0xfd, 0xd5, 0x1e, 0xee, 0x19, 0x0b, 0x94, 0x75, 0x67, 0x72, 0x38, 0xc6, 0xdd, 0x67,
|
||||
0x35, 0x73, 0x8a, 0x68, 0x6a, 0x3e, 0xbc, 0x43, 0xda, 0x7d, 0xb6, 0x48, 0xb7, 0xe9, 0x62, 0xfb, 0x1b, 0x11, 0x37,
|
||||
0x5f, 0x38, 0xb4, 0x19, 0x15, 0x3c, 0x5c, 0xaa, 0xda, 0xa3, 0xb3, 0xf0, 0xcb, 0x7c, 0x0e, 0xcd, 0x1d, 0x57, 0x8e,
|
||||
0xea, 0x98, 0xfc, 0x3f, 0x2e, 0x1e, 0x66, 0xf8, 0xfe, 0x74, 0x8f, 0xec, 0x89, 0x84, 0xb3, 0x7a, 0x65, 0x73, 0x92,
|
||||
0x52, 0xe2, 0x0d, 0x2b, 0x3e, 0x4d, 0xdb, 0x95, 0x3e, 0x93, 0xa7, 0xe4, 0xc0, 0xa1, 0xd2, 0x3d, 0x92, 0x71, 0xbf,
|
||||
0x7d, 0xa6, 0xd7, 0x2d, 0x33, 0x75, 0xd8, 0xd8, 0x36, 0xe7, 0x9f, 0xe2, 0x52, 0x93, 0xa2, 0x9c, 0x0d, 0xf5, 0x75,
|
||||
0xce, 0xf1, 0x47, 0x26, 0x1e, 0x5d, 0x75, 0x7e, 0xe3, 0xcc, 0x55, 0xd9, 0x5e, 0x67, 0xfd, 0x17, 0xec, 0x28, 0x3a,
|
||||
0xbe, 0x76, 0xda, 0x97, 0x95, 0x47, 0x8e, 0x58, 0x3d, 0xed, 0xb0, 0x6a, 0xcc, 0x75, 0x9f, 0xf0, 0x63, 0xfe, 0x77,
|
||||
0x4f, 0x99, 0xca, 0x4f, 0x8f, 0x2f, 0x55, 0x17, 0xce, 0x77, 0x8b, 0x3e, 0x25, 0xd0, 0x9a, 0x9d, 0x99, 0x76, 0xe7,
|
||||
0xf4, 0x84, 0x8a, 0x0f, 0x7e, 0xe7, 0x26, 0xcf, 0xd2, 0x75, 0x60, 0xe9, 0xc8, 0xeb, 0x4e, 0x9f, 0x2a, 0x34, 0x75,
|
||||
0xdd, 0x63, 0x46, 0xb6, 0x0f, 0xfb, 0xb6, 0x35, 0x7d, 0x37, 0x58, 0xb5, 0xb8, 0x23, 0xa5, 0x69, 0x47, 0xc1, 0xee,
|
||||
0xef, 0xf6, 0xc1, 0x1b, 0x3a, 0x55, 0x4c, 0x72, 0x1e, 0xef, 0x38, 0xac, 0xc1, 0x5b, 0x90, 0xe5, 0x1e, 0x92, 0x24,
|
||||
0xa6, 0xff, 0xb3, 0xfe, 0xd8, 0xeb, 0x39, 0x13, 0xaf, 0x34, 0xa5, 0x7d, 0x61, 0x13, 0xf9, 0x29, 0x12, 0xb2, 0x4b,
|
||||
0x72, 0x55, 0xb9, 0xb4, 0xf8, 0x56, 0xb3, 0x73, 0x8c, 0x56, 0x05, 0x25, 0xdd, 0x7b, 0x5e, 0x4c, 0xd8, 0x53, 0x7d,
|
||||
0x59, 0x37, 0x22, 0x47, 0x59, 0x4f, 0xf0, 0xf7, 0xc4, 0xe2, 0x9c, 0xe6, 0xdc, 0x8d, 0x25, 0x9d, 0xaa, 0x7c, 0x4a,
|
||||
0x7b, 0xa6, 0xd7, 0xb7, 0xaf, 0x15, 0x7b, 0xb4, 0xdf, 0xcf, 0xee, 0xd6, 0x34, 0x9d, 0x8a, 0xbc, 0xef, 0x39, 0x3e,
|
||||
0x89, 0x92, 0xed, 0x59, 0xfe, 0xe9, 0x47, 0xcb, 0x7a, 0x8c, 0xab, 0xa7, 0xed, 0x91, 0x66, 0xd9, 0x6b, 0x64, 0xde,
|
||||
0xb0, 0x8d, 0x93, 0xc3, 0xff, 0x03, 0xab, 0x82, 0x0f, 0x8f, 0xfa, 0xc4, 0x93, 0xea, 0x42, 0x62, 0xfe, 0xcf, 0x15,
|
||||
0x58, 0x84, 0xdc, 0x9d, 0xdf, 0x99, 0x29, 0xcf, 0x93, 0x3e, 0xd2, 0x7c, 0x7f, 0x65, 0xd6, 0xf2, 0xa4, 0xda, 0x6f,
|
||||
0xd7, 0xd8, 0x3f, 0x4d, 0x7c, 0x7e, 0xde, 0x76, 0x77, 0x8f, 0xe5, 0x22, 0xae, 0xa4, 0xf8, 0x88, 0x45, 0x3b, 0xcf,
|
||||
0xdb, 0x16, 0x2b, 0x6b, 0x59, 0x99, 0xed, 0xab, 0x2f, 0x51, 0x75, 0x4c, 0x35, 0xaf, 0x3d, 0x79, 0x6b, 0xf1, 0x96,
|
||||
0xc4, 0xfb, 0x22, 0x55, 0xc1, 0xe7, 0x83, 0x8b, 0x0c, 0x9b, 0xeb, 0xd6, 0x2e, 0xd2, 0xd8, 0xfe, 0xfa, 0xdd, 0xed,
|
||||
0xfe, 0x09, 0xee, 0x9c, 0x86, 0xe9, 0x77, 0x3b, 0xfd, 0xa4, 0x16, 0x94, 0x9d, 0xc9, 0xbd, 0x7c, 0x4e, 0xcf, 0x2e,
|
||||
0xf4, 0xcc, 0x41, 0xdb, 0x75, 0xac, 0x3d, 0xd9, 0x77, 0x5c, 0xbe, 0x86, 0xdc, 0x51, 0x37, 0xe6, 0xfe, 0x5e, 0x56,
|
||||
0xfe, 0xea, 0xa2, 0xdb, 0x2d, 0x76, 0xe3, 0x4b, 0xac, 0xa5, 0x93, 0x45, 0x16, 0xd9, 0x67, 0xaa, 0xb7, 0xa9, 0x1a,
|
||||
0xc6, 0xcc, 0x16, 0xb1, 0x93, 0xeb, 0x4f, 0x77, 0x6d, 0xb3, 0x7b, 0xb0, 0x74, 0xef, 0x83, 0x94, 0x72, 0xd1, 0x4f,
|
||||
0x55, 0x51, 0xcf, 0x9e, 0x36, 0xfd, 0xd6, 0xea, 0xdc, 0x9a, 0x7e, 0xc3, 0xe2, 0x81, 0x00, 0xe3, 0xa1, 0x07, 0x0b,
|
||||
0x56, 0xcb, 0xdc, 0x69, 0x2c, 0x3c, 0xee, 0xaa, 0x79, 0x9d, 0xa9, 0x5f, 0x2d, 0x6f, 0xfd, 0x9a, 0xb7, 0xab, 0x59,
|
||||
0x7d, 0x93, 0x3a, 0x7e, 0x5f, 0x57, 0xbf, 0x51, 0xa0, 0xbe, 0x34, 0x5b, 0x8a, 0xed, 0xf6, 0x53, 0xd3, 0xec, 0x97,
|
||||
0xf1, 0xcf, 0x8b, 0xa3, 0x77, 0x97, 0x2a, 0x9a, 0x1d, 0xd7, 0xb8, 0x7a, 0x54, 0xf2, 0x6f, 0x9f, 0xc2, 0x12, 0xfe,
|
||||
0xfb, 0x8d, 0x72, 0x47, 0x37, 0xb9, 0x09, 0xed, 0x3e, 0x70, 0xf4, 0x48, 0xd1, 0x99, 0x2b, 0x27, 0xb6, 0x2d, 0x12,
|
||||
0x4e, 0xbc, 0x7c, 0x99, 0x61, 0x56, 0xb9, 0xee, 0x0e, 0xb5, 0xd4, 0xbf, 0x7d, 0x3f, 0xef, 0xb3, 0xf8, 0x2e, 0xbe,
|
||||
0x60, 0xe5, 0x9b, 0xbf, 0xd7, 0xc5, 0xc2, 0x3e, 0x6b, 0xfb, 0x2c, 0x55, 0x1f, 0x2e, 0xad, 0x43, 0x9b, 0x62, 0x6f,
|
||||
0xc5, 0x6f, 0x7c, 0xb3, 0xe0, 0xec, 0x95, 0x40, 0xa6, 0x3f, 0x0d, 0xb5, 0x29, 0x71, 0x9a, 0xa5, 0x82, 0x3f, 0xcd,
|
||||
0xcf, 0x70, 0xfb, 0x6d, 0x7b, 0x32, 0xf9, 0xdd, 0x81, 0xc7, 0xe5, 0x57, 0x57, 0x95, 0xcb, 0xf5, 0x7e, 0xf4, 0x0a,
|
||||
0x61, 0x7e, 0xec, 0x72, 0x4d, 0x83, 0xb7, 0x65, 0xae, 0x7b, 0x86, 0xcc, 0x6b, 0x4d, 0xa7, 0x3e, 0xb1, 0x57, 0xef,
|
||||
0xb8, 0xc4, 0x67, 0x6a, 0xa7, 0x5e, 0x9a, 0x1c, 0x7a, 0x53, 0x79, 0x8e, 0x6f, 0xfd, 0x9a, 0x43, 0x9a, 0xbd, 0x89,
|
||||
0x9f, 0xe6, 0xf8, 0x5f, 0x08, 0x57, 0x79, 0x6e, 0x58, 0xf6, 0xed, 0x88, 0x11, 0xf7, 0xca, 0xc7, 0xf5, 0x0b, 0x97,
|
||||
0x9c, 0x10, 0xfe, 0xec, 0x69, 0xed, 0xc8, 0x7a, 0xef, 0x70, 0x23, 0x93, 0xc3, 0x93, 0xdf, 0x57, 0xdc, 0xc4, 0xaf,
|
||||
0xb6, 0x7e, 0xeb, 0xb5, 0x8d, 0xcc, 0x5a, 0x62, 0xba, 0xbc, 0x41, 0x4d, 0xa9, 0xda, 0xd5, 0x45, 0xe8, 0x9d, 0x7c,
|
||||
0xe8, 0x05, 0x87, 0x3d, 0x7e, 0xab, 0x76, 0xed, 0x63, 0xf8, 0xeb, 0xa6, 0x2c, 0xda, 0x7a, 0xaa, 0xec, 0x44, 0x9a,
|
||||
0xe7, 0xf6, 0xf4, 0x9f, 0x3b, 0xb9, 0xbb, 0xc2, 0x17, 0x29, 0x0b, 0xae, 0xa8, 0xce, 0xbb, 0xaf, 0x79, 0xe4, 0x5f,
|
||||
0xc4, 0xbf, 0x47, 0xd6, 0xb3, 0xf7, 0xee, 0xf7, 0xaa, 0xdf, 0x26, 0x67, 0xed, 0xcf, 0xb2, 0xef, 0xab, 0x5b, 0xa8,
|
||||
0xd9, 0xc3, 0x93, 0x95, 0xdd, 0x91, 0x69, 0xab, 0x27, 0x9d, 0x9f, 0xb0, 0x88, 0x73, 0xaf, 0x44, 0x78, 0x71, 0x40,
|
||||
0xf6, 0xd4, 0xed, 0x57, 0xfa, 0x9c, 0xca, 0xef, 0xdd, 0xca, 0x37, 0xb4, 0x2e, 0x57, 0x94, 0x98, 0x33, 0xf3, 0xee,
|
||||
0x86, 0xbf, 0xb5, 0x5f, 0x75, 0x6e, 0x29, 0x4d, 0x6d, 0x17, 0x3c, 0xd1, 0x9b, 0x32, 0x55, 0xeb, 0xce, 0xf2, 0x9b,
|
||||
0x55, 0x0c, 0xe7, 0xbf, 0x29, 0x30, 0x48, 0x2d, 0x32, 0x36, 0x0d, 0xbf, 0xb8, 0xe5, 0x4e, 0xa7, 0x46, 0x6f, 0xac,
|
||||
0x83, 0x9a, 0x4f, 0xe4, 0x76, 0xa1, 0x79, 0x65, 0xeb, 0x16, 0xf5, 0xbd, 0x62, 0x2b, 0xa8, 0x3e, 0x21, 0x27, 0x7b,
|
||||
0x9b, 0xf7, 0x83, 0xd3, 0xa6, 0xac, 0x57, 0xd2, 0x17, 0xce, 0xf7, 0x7e, 0x3a, 0xbb, 0xe7, 0xb8, 0xef, 0x51, 0x77,
|
||||
0xc1, 0xeb, 0x57, 0xde, 0x78, 0xf0, 0x07, 0x88, 0xfb, 0x6c, 0x3a, 0x59, 0x1c, 0xfd, 0xf2, 0xd0, 0x07, 0x6d, 0x23,
|
||||
0x9d, 0x69, 0x27, 0x05, 0x96, 0xf1, 0x9a, 0x14, 0x95, 0xbf, 0xd8, 0xf1, 0xd4, 0x7d, 0x2b, 0x4f, 0xc5, 0x82, 0xa3,
|
||||
0xda, 0xc5, 0x1a, 0x7b, 0x3e, 0x6f, 0x9f, 0x73, 0xbd, 0xee, 0x73, 0x0f, 0x83, 0x4b, 0xcf, 0xcd, 0xc9, 0x6f, 0x3d,
|
||||
0xdf, 0xbd, 0xfb, 0x7e, 0xe8, 0xe0, 0x6e, 0x9e, 0xb6, 0x8e, 0xbf, 0x0a, 0xfc, 0x36, 0xb7, 0xfd, 0xd2, 0xce, 0xeb,
|
||||
0x17, 0x4c, 0xd3, 0x39, 0xd7, 0x70, 0xe9, 0xd3, 0xd4, 0x4d, 0xa9, 0x1f, 0x2c, 0x7c, 0xe3, 0x12, 0x4e, 0xf9, 0x7e,
|
||||
0x7f, 0xc2, 0xb3, 0xeb, 0xa4, 0x53, 0xe9, 0xb1, 0x4d, 0xf7, 0x58, 0x57, 0x36, 0xfd, 0x3e, 0x65, 0x9b, 0xb1, 0x91,
|
||||
0x61, 0x14, 0x8c, 0x82, 0x51, 0x30, 0x0a, 0x46, 0xc1, 0x28, 0x18, 0x05, 0xa3, 0x60, 0x14, 0x8c, 0x82, 0x51, 0x30,
|
||||
0x0a, 0x46, 0xc1, 0x28, 0x18, 0x05, 0xa3, 0x60, 0x14, 0x8c, 0x82, 0x51, 0x40, 0x73, 0x90, 0x5a, 0x5c, 0x90, 0x91,
|
||||
0x9f, 0x9b, 0xaa, 0x90, 0x5f, 0x92, 0xa8, 0x90, 0x92, 0x9a, 0x96, 0x93, 0x58, 0x92, 0xaa, 0x30, 0x2a, 0x36, 0x2a,
|
||||
0x36, 0x2a, 0x36, 0x2a, 0x36, 0x2a, 0x36, 0x2a, 0x36, 0x2a, 0x36, 0xb4, 0xc4, 0x00,
|
||||
};
|
||||
|
||||
static const uint8_t SKEWED[] = {
|
||||
0x2d, 0x97, 0x79, 0xf0, 0x97, 0x55, 0x15, 0xc6, 0x2d, 0x0a, 0xc5, 0x25, 0x25, 0x1b, 0x9d, 0x6c, 0xcc, 0xe3, 0xd8,
|
||||
0xf0, 0x07, 0x4c, 0x8e, 0x96, 0x63, 0xe2, 0x16, 0x90, 0x26, 0x6a, 0x35, 0x14, 0x2a, 0xc5, 0xe8, 0xc8, 0x35, 0xaf,
|
||||
0x7a, 0x5d, 0xce, 0x51, 0xba, 0x1a, 0x82, 0x4c, 0x63, 0x2a, 0x69, 0xa6, 0xe0, 0xa8, 0x8c, 0xb8, 0x11, 0x1a, 0x03,
|
||||
0x29, 0x2e, 0x29, 0xa2, 0x69, 0x2e, 0x8c, 0x1a, 0x05, 0x3f, 0xad, 0x46, 0x74, 0xc4, 0x22, 0xb7, 0x18, 0xd3, 0x16,
|
||||
0x74, 0x10, 0xd1, 0x98, 0xac, 0xe7, 0x73, 0xbe, 0xf2, 0x63, 0xbe, 0xdf, 0xef, 0xfb, 0xbe, 0xf7, 0xbd, 0xf7, 0x2c,
|
||||
0xcf, 0x79, 0xce, 0x73, 0xa2, 0x37, 0xf3, 0x62, 0xad, 0xd6, 0xe2, 0xbd, 0x4d, 0xa8, 0x2d, 0xfa, 0x3e, 0xde, 0x7b,
|
||||
0x6b, 0xd6, 0xad, 0xb8, 0x7b, 0x09, 0xd7, 0xf3, 0x28, 0xad, 0x78, 0x44, 0xf3, 0x68, 0x25, 0xf4, 0x82, 0x45, 0xd7,
|
||||
0xb3, 0xda, 0x43, 0x1f, 0xc5, 0x9e, 0xd0, 0x97, 0x5d, 0x5a, 0xb4, 0x4b, 0x58, 0x78, 0xdb, 0xb7, 0x9b, 0xf5, 0x28,
|
||||
0xd6, 0x3b, 0xaf, 0x15, 0xf3, 0x1e, 0xb5, 0xd9, 0x5c, 0x8f, 0xd7, 0xa2, 0x0f, 0xd5, 0xf2, 0x78, 0xf7, 0x56, 0xce,
|
||||
0x2a, 0x5e, 0x6a, 0xad, 0xad, 0x1e, 0xe3, 0x75, 0xad, 0x47, 0xd1, 0xda, 0xd6, 0xf4, 0x15, 0xd3, 0x2d, 0x22, 0x7a,
|
||||
0x75, 0x5d, 0x55, 0x1d, 0x12, 0xd5, 0x8e, 0x73, 0x0f, 0xed, 0x50, 0xb4, 0x58, 0xdb, 0x37, 0x9d, 0x58, 0xe3, 0x56,
|
||||
0xad, 0xd7, 0x06, 0xa1, 0x45, 0xd3, 0x4b, 0x2d, 0xda, 0x5f, 0x26, 0xb4, 0xae, 0x9d, 0xab, 0x75, 0xad, 0xd3, 0x6b,
|
||||
0xf2, 0xa6, 0xd7, 0xa8, 0xdd, 0xc7, 0x58, 0x95, 0xd9, 0xba, 0x3b, 0x24, 0xdf, 0x46, 0xba, 0x95, 0x16, 0xb2, 0x4b,
|
||||
0xe7, 0x45, 0x9b, 0x6e, 0xde, 0xfc, 0xf6, 0x43, 0xd7, 0x85, 0xc9, 0xab, 0xf6, 0x57, 0x59, 0xed, 0xc3, 0x65, 0x83,
|
||||
0xce, 0x97, 0x2d, 0xda, 0x42, 0xeb, 0x88, 0x40, 0x8f, 0xc7, 0xe4, 0xbb, 0x36, 0x6d, 0xae, 0xa8, 0x5c, 0x25, 0xc3,
|
||||
0xaa, 0x36, 0xd0, 0x6f, 0xfd, 0x23, 0x78, 0x66, 0x55, 0x6e, 0x1e, 0xd1, 0x8b, 0x2c, 0xb2, 0x1f, 0xd6, 0xbd, 0xcc,
|
||||
0x1e, 0x96, 0xe9, 0x17, 0xd6, 0x3e, 0x59, 0x2b, 0x4d, 0xd1, 0xd2, 0x4a, 0xc5, 0xad, 0x17, 0x1f, 0x5a, 0xad, 0x6d,
|
||||
0x0c, 0x7f, 0x74, 0xb7, 0xee, 0xf8, 0xf6, 0x07, 0xeb, 0xe3, 0x06, 0xed, 0x2b, 0x03, 0xf1, 0xae, 0x6a, 0xaf, 0xbf,
|
||||
0xeb, 0xd0, 0x62, 0xda, 0x68, 0x92, 0x5e, 0xf3, 0xd2, 0x74, 0x4f, 0x6e, 0x34, 0x57, 0x30, 0xc2, 0x8f, 0xd4, 0x16,
|
||||
0x79, 0x75, 0x4f, 0x9d, 0x17, 0x25, 0xec, 0xe4, 0x6a, 0x6b, 0x6b, 0xd7, 0xa2, 0x8a, 0xf7, 0x85, 0xe8, 0xcb, 0x74,
|
||||
0x9d, 0x75, 0x80, 0x0e, 0xab, 0x3b, 0xe8, 0x51, 0x89, 0x47, 0x9b, 0x55, 0xe5, 0x58, 0x36, 0x12, 0x54, 0x65, 0xf0,
|
||||
0x4c, 0x25, 0xd7, 0xdb, 0x24, 0x8f, 0xcc, 0xb0, 0x16, 0x7b, 0xb5, 0x6a, 0xed, 0x70, 0xc5, 0xa5, 0x96, 0x6e, 0x3a,
|
||||
0x82, 0x5c, 0x2b, 0xca, 0xfd, 0xc5, 0xee, 0x33, 0x5d, 0x89, 0x5e, 0x14, 0x32, 0x6e, 0x8a, 0xde, 0x7f, 0x49, 0x56,
|
||||
0x0a, 0x14, 0xe5, 0x90, 0x57, 0x3d, 0xd6, 0x44, 0xf8, 0x6d, 0x5d, 0x89, 0x7b, 0x5b, 0x10, 0x50, 0x34, 0x2f, 0x2d,
|
||||
0x44, 0x5e, 0xdb, 0x3d, 0x7b, 0x7f, 0x08, 0x4e, 0x0a, 0x6c, 0x74, 0x23, 0x64, 0xe5, 0x12, 0xf9, 0x6f, 0x02, 0xcb,
|
||||
0x2b, 0x3e, 0x96, 0xa0, 0xd6, 0xae, 0x84, 0x68, 0x1d, 0x59, 0xd1, 0x8b, 0x24, 0x64, 0xa1, 0x1c, 0x2f, 0x56, 0xff,
|
||||
0xe6, 0xb1, 0x8d, 0x70, 0xb1, 0x61, 0x85, 0x96, 0x09, 0x72, 0x7e, 0x94, 0x37, 0x6b, 0x06, 0x0e, 0x14, 0x7d, 0xfd,
|
||||
0x92, 0x8f, 0x02, 0x80, 0x11, 0x97, 0x32, 0xbb, 0x5d, 0xa8, 0x3c, 0x29, 0x09, 0x72, 0xf2, 0xa1, 0xe2, 0xb7, 0x2a,
|
||||
0xd0, 0x4a, 0xaf, 0x7d, 0x17, 0x58, 0xcc, 0x27, 0x9d, 0x2c, 0x55, 0x4c, 0x46, 0xc9, 0x26, 0x85, 0x4c, 0xc0, 0xe8,
|
||||
0x3b, 0xd7, 0x2a, 0x70, 0xe9, 0x52, 0x5b, 0x96, 0x8f, 0x57, 0x21, 0xb4, 0xbc, 0x25, 0x2c, 0xb5, 0xf2, 0x9c, 0xff,
|
||||
0x51, 0xe9, 0x39, 0x5e, 0x89, 0x57, 0xfe, 0xea, 0xeb, 0x42, 0xb6, 0x82, 0x25, 0xe0, 0xcb, 0x4a, 0x61, 0x8f, 0x57,
|
||||
0x0a, 0xa0, 0x53, 0xd2, 0xff, 0x22, 0x8b, 0xfa, 0xdd, 0x72, 0x40, 0xc7, 0x78, 0x4c, 0xee, 0xd6, 0xfa, 0xaf, 0x65,
|
||||
0x41, 0xd4, 0xe3, 0x48, 0x30, 0xc1, 0xaf, 0x8d, 0x78, 0xbb, 0x71, 0xbe, 0x16, 0x0d, 0x70, 0x54, 0xfa, 0x52, 0x59,
|
||||
0x17, 0x53, 0x74, 0x5f, 0xb1, 0x68, 0xf2, 0xb5, 0x39, 0x15, 0xa2, 0xed, 0xbb, 0xa0, 0xa3, 0x20, 0xe6, 0xb7, 0x1e,
|
||||
0x29, 0xdc, 0x05, 0xa4, 0x7b, 0xfb, 0x9f, 0xf2, 0xd8, 0x95, 0x5b, 0x25, 0x24, 0xfa, 0xfe, 0xbe, 0x1f, 0x96, 0xd4,
|
||||
0xb4, 0xa4, 0xb7, 0x45, 0xed, 0x04, 0x53, 0xaa, 0x04, 0x13, 0xcb, 0xc8, 0x28, 0x91, 0x9d, 0xca, 0xd8, 0x55, 0x38,
|
||||
0x71, 0x30, 0xe7, 0x27, 0x5a, 0x98, 0x91, 0xda, 0xe7, 0x14, 0x34, 0x6a, 0xa9, 0xe0, 0x80, 0x5d, 0x5f, 0x41, 0xae,
|
||||
0xd0, 0xe8, 0x32, 0xec, 0x88, 0xba, 0x84, 0x0a, 0x97, 0xa7, 0xbc, 0x4b, 0xa2, 0x7d, 0x27, 0x2a, 0xa6, 0x6f, 0x92,
|
||||
0x05, 0x06, 0x20, 0x95, 0x6a, 0xb9, 0xda, 0xff, 0xa5, 0x7a, 0xac, 0xfd, 0x61, 0x2d, 0x15, 0xc2, 0xde, 0x95, 0xad,
|
||||
0xde, 0xee, 0x28, 0xb6, 0xc8, 0x6f, 0x96, 0xcd, 0xb7, 0x41, 0x0b, 0x20, 0xba, 0x53, 0x57, 0x0d, 0xcb, 0xbb, 0xbd,
|
||||
0xaf, 0x13, 0x40, 0x78, 0x91, 0xed, 0x72, 0x6f, 0x34, 0x29, 0x93, 0x8f, 0xa5, 0x43, 0x33, 0x8b, 0x65, 0xd9, 0x5a,
|
||||
0xd5, 0xbe, 0x3f, 0x2f, 0x83, 0x74, 0x2b, 0xca, 0x51, 0x14, 0x97, 0x78, 0x42, 0x68, 0xa1, 0x98, 0x14, 0x7e, 0xaf,
|
||||
0xfb, 0xc3, 0x49, 0xf2, 0x5e, 0x99, 0x14, 0x88, 0x47, 0x0a, 0x26, 0x7d, 0xc2, 0x09, 0x8a, 0x4d, 0x5c, 0x11, 0xa7,
|
||||
0xc8, 0xb1, 0x7b, 0xea, 0x5b, 0x02, 0x77, 0x07, 0xc4, 0x03, 0x94, 0x41, 0x20, 0xfe, 0x61, 0xc7, 0x9a, 0x58, 0x63,
|
||||
0x13, 0xb4, 0x9e, 0xa4, 0xab, 0x30, 0x15, 0xa2, 0x42, 0xc9, 0xad, 0x57, 0x88, 0x27, 0xea, 0x96, 0x58, 0xc1, 0x6d,
|
||||
0x7b, 0x45, 0xc4, 0xa1, 0x88, 0x0a, 0xe0, 0x15, 0xe0, 0xe3, 0xbb, 0x3c, 0x6d, 0xf6, 0x16, 0x27, 0x1c, 0xff, 0x4d,
|
||||
0xed, 0xa5, 0xd7, 0xbe, 0xe6, 0xd4, 0xa4, 0x00, 0xac, 0x10, 0x29, 0x2a, 0xba, 0xb5, 0x97, 0x98, 0x61, 0x8d, 0xa2,
|
||||
0x2e, 0x5c, 0x89, 0x01, 0xcb, 0x37, 0x14, 0x59, 0x5d, 0xc8, 0x42, 0x31, 0x4e, 0xf2, 0x64, 0x83, 0x7b, 0xa6, 0xba,
|
||||
0x70, 0x11, 0x5b, 0x29, 0x58, 0x41, 0x41, 0xa1, 0xd3, 0xe9, 0x04, 0xe6, 0xd9, 0xcf, 0x6a, 0xb9, 0x4a, 0x4d, 0x0f,
|
||||
0xeb, 0x07, 0x3a, 0xff, 0x0c, 0x3f, 0x6c, 0xc4, 0x91, 0xef, 0x4d, 0x2d, 0x49, 0x06, 0xd0, 0xa4, 0x7c, 0x50, 0x14,
|
||||
0xb5, 0xb9, 0xf2, 0x13, 0x00, 0xfb, 0x5e, 0x08, 0xb0, 0x2b, 0xec, 0xbe, 0xa0, 0x1c, 0xf4, 0x7b, 0xef, 0x38, 0x13,
|
||||
0x31, 0x8a, 0x78, 0x2b, 0x7e, 0x49, 0x54, 0x54, 0xc7, 0x54, 0x59, 0xd7, 0x37, 0x34, 0x10, 0x58, 0x4f, 0x25, 0xce,
|
||||
0x61, 0x73, 0xec, 0x41, 0x85, 0x06, 0x8e, 0xcd, 0x5c, 0xaa, 0xd0, 0x55, 0x6e, 0xc2, 0xa8, 0x8a, 0x4d, 0x41, 0x16,
|
||||
0x5b, 0xe8, 0xae, 0x51, 0x84, 0x14, 0xc7, 0x17, 0xa1, 0x0e, 0x51, 0x9d, 0x5c, 0x15, 0xaa, 0xb4, 0xae, 0xe8, 0x42,
|
||||
0x68, 0xb6, 0xef, 0x28, 0x09, 0xa7, 0xcd, 0x50, 0x00, 0x94, 0x93, 0x00, 0xd9, 0x09, 0x4f, 0x19, 0xa8, 0xe0, 0x89,
|
||||
0x08, 0xc0, 0xa7, 0x56, 0xee, 0xec, 0x6d, 0x27, 0xfb, 0x4d, 0x87, 0x44, 0x28, 0x93, 0x78, 0x5a, 0x34, 0x54, 0x49,
|
||||
0x8d, 0x90, 0x29, 0xb7, 0x2d, 0x46, 0x97, 0xb2, 0x8e, 0x3e, 0x21, 0x9f, 0xaf, 0x55, 0xc8, 0xa8, 0x0c, 0x19, 0x14,
|
||||
0xb7, 0xc3, 0x9b, 0xca, 0xc0, 0x79, 0x25, 0x39, 0x8c, 0x7e, 0x22, 0x20, 0x2b, 0x5e, 0x43, 0x24, 0x75, 0x48, 0xc7,
|
||||
0xb6, 0x8b, 0x2b, 0x99, 0x80, 0xe1, 0xe5, 0x6c, 0xeb, 0xe7, 0x89, 0x69, 0x74, 0xa8, 0xf2, 0x6f, 0x97, 0x90, 0x59,
|
||||
0x48, 0xb8, 0x7d, 0x0b, 0xc2, 0x83, 0xc6, 0x8c, 0x8e, 0x62, 0x47, 0x44, 0x8c, 0x59, 0xdb, 0xab, 0x7d, 0x99, 0x1e,
|
||||
0x46, 0xfe, 0xa8, 0x61, 0x71, 0xa8, 0x01, 0x08, 0xd5, 0x5f, 0xc1, 0x85, 0x68, 0xf7, 0x0a, 0x59, 0x22, 0xe9, 0x42,
|
||||
0xd4, 0x5a, 0x9b, 0x53, 0xff, 0xdb, 0x62, 0x83, 0x2e, 0x5a, 0x6c, 0xce, 0x9a, 0xac, 0x90, 0x81, 0x12, 0xd3, 0x6f,
|
||||
0x86, 0x94, 0xa9, 0x90, 0xce, 0x16, 0x01, 0xc3, 0x41, 0x66, 0xad, 0xff, 0xc9, 0xe1, 0x69, 0xba, 0x0c, 0xdc, 0x65,
|
||||
0x49, 0x39, 0xb0, 0xa3, 0x9c, 0x9f, 0x50, 0x20, 0xf9, 0x3d, 0x45, 0x73, 0x76, 0x1f, 0xcc, 0x01, 0x78, 0x94, 0xaa,
|
||||
0x37, 0xf4, 0x65, 0xdb, 0x38, 0xf1, 0x83, 0x26, 0xba, 0xbd, 0x53, 0xa8, 0xaf, 0xfa, 0x3b, 0xac, 0x52, 0x68, 0x2b,
|
||||
0x9b, 0xe0, 0x1b, 0xb4, 0x12, 0x2d, 0xe9, 0x60, 0xb9, 0xa2, 0xaa, 0x2a, 0x73, 0x18, 0xbe, 0x72, 0x50, 0xc0, 0x87,
|
||||
0xb2, 0x99, 0x66, 0x4b, 0x16, 0x1d, 0x24, 0xf6, 0x3a, 0xc2, 0xc1, 0xd6, 0xe7, 0x68, 0xd5, 0x72, 0x79, 0x17, 0xed,
|
||||
0x73, 0xb7, 0xd8, 0x87, 0x64, 0x8a, 0x80, 0xee, 0xa1, 0xcd, 0x71, 0x42, 0x9b, 0x5a, 0xe9, 0x2a, 0x7a, 0x00, 0x0b,
|
||||
0x0b, 0x4a, 0x9f, 0xc2, 0xba, 0xb0, 0x9b, 0x08, 0x30, 0x68, 0x10, 0x54, 0xa7, 0x7d, 0x66, 0xdd, 0x83, 0x59, 0x39,
|
||||
0x49, 0xb7, 0xf2, 0x50, 0x49, 0x2c, 0xf8, 0x79, 0x83, 0xac, 0xd7, 0x2a, 0x6d, 0x9f, 0x0c, 0x40, 0x3f, 0xa9, 0xfe,
|
||||
0x3a, 0x8c, 0x5f, 0x29, 0x9d, 0xa3, 0xe9, 0x1c, 0xda, 0x53, 0x15, 0xb0, 0x27, 0x85, 0x29, 0x9b, 0x15, 0x7a, 0xca,
|
||||
0x83, 0xcc, 0x68, 0x47, 0xc5, 0xe4, 0x2c, 0xa1, 0x8a, 0xfa, 0x1b, 0x05, 0x97, 0xc9, 0x21, 0x03, 0x4c, 0x0e, 0x9a,
|
||||
0x74, 0xdb, 0xe3, 0x05, 0xc2, 0x57, 0xa7, 0x72, 0x9e, 0xf6, 0x39, 0x5c, 0xd4, 0x01, 0x3e, 0xb2, 0xa9, 0x26, 0x11,
|
||||
0x5b, 0xbf, 0xd1, 0x07, 0xbc, 0x1a, 0x20, 0x85, 0xf8, 0x08, 0xa7, 0xe9, 0x18, 0x0d, 0x43, 0x49, 0xd0, 0xa3, 0x8d,
|
||||
0x49, 0xe9, 0xf4, 0xe6, 0xcc, 0x8a, 0xbe, 0xe9, 0x6a, 0x38, 0x22, 0x82, 0xb0, 0x91, 0x9d, 0xf2, 0x4b, 0x97, 0x94,
|
||||
0x7d, 0x2a, 0x4f, 0xb8, 0x85, 0x04, 0x10, 0x11, 0x75, 0x58, 0xb4, 0x5b, 0xe0, 0x28, 0x80, 0xd2, 0xe9, 0xd2, 0x73,
|
||||
0x4b, 0x79, 0xb9, 0xb3, 0x99, 0x32, 0x55, 0x00, 0xfc, 0x53, 0xc9, 0x71, 0x85, 0x64, 0xf4, 0x8d, 0x2a, 0xc8, 0x96,
|
||||
0x04, 0xa6, 0xe3, 0x75, 0xe4, 0xae, 0x75, 0x97, 0x93, 0x14, 0xb6, 0x5c, 0x2b, 0x32, 0x85, 0xf1, 0xaf, 0x6d, 0x74,
|
||||
0x25, 0x79, 0x48, 0xcf, 0x53, 0x52, 0xc7, 0xc9, 0x7a, 0x10, 0x93, 0x92, 0x45, 0x31, 0xfc, 0x27, 0x0c, 0xa4, 0xe0,
|
||||
0x42, 0x42, 0x60, 0x44, 0xb1, 0x2a, 0xd9, 0xec, 0x00, 0x66, 0x87, 0xcd, 0xb2, 0x22, 0x9d, 0x3d, 0x69, 0xe9, 0xa5,
|
||||
0x3e, 0x04, 0xa9, 0xb6, 0x74, 0xce, 0x11, 0x1c, 0x5b, 0xb5, 0xab, 0x4a, 0x18, 0xaa, 0x69, 0x3b, 0x8b, 0x82, 0x5f,
|
||||
0xe6, 0x80, 0x0a, 0x92, 0x9d, 0xaa, 0x26, 0x4d, 0x22, 0xd2, 0xb9, 0x7a, 0x33, 0x61, 0xcc, 0x8b, 0x9e, 0xdf, 0xfd,
|
||||
0xa3, 0xb6, 0x28, 0x03, 0xf6, 0x03, 0x85, 0x08, 0xb2, 0xd9, 0xaa, 0xf2, 0x02, 0xa3, 0xd8, 0x35, 0x4e, 0x14, 0x3b,
|
||||
0xf2, 0xad, 0x95, 0xbd, 0x91, 0x2e, 0x78, 0x0f, 0x83, 0xaf, 0x90, 0x3c, 0xd0, 0x0f, 0x27, 0x6d, 0x47, 0x09, 0x9a,
|
||||
0x72, 0x58, 0x2d, 0x93, 0x76, 0xad, 0xc3, 0xfe, 0x1c, 0x33, 0x54, 0xf9, 0x2d, 0x93, 0x83, 0xa4, 0xa9, 0x10, 0x38,
|
||||
0x50, 0xa5, 0x70, 0x2f, 0x30, 0xff, 0xe4, 0x1d, 0xc5, 0x97, 0x2d, 0x2e, 0xbf, 0x2c, 0x33, 0xe5, 0xce, 0x23, 0xdd,
|
||||
0x16, 0x54, 0xb4, 0x03, 0x10, 0x8a, 0x64, 0x2a, 0x42, 0x1f, 0x64, 0x9f, 0x28, 0x25, 0x21, 0xb5, 0xd8, 0xcd, 0x7c,
|
||||
0x42, 0xd0, 0x34, 0x91, 0x83, 0x3f, 0xc2, 0x1e, 0x05, 0x53, 0xb6, 0xa8, 0x5c, 0xfe, 0xd1, 0x32, 0xc1, 0x14, 0x21,
|
||||
0x25, 0xa1, 0x07, 0xb3, 0xa1, 0xd7, 0x8c, 0x61, 0xf3, 0xff, 0xe8, 0x65, 0x98, 0xab, 0xc5, 0x39, 0xbe, 0x55, 0x61,
|
||||
0xae, 0x3d, 0x63, 0x5a, 0xb6, 0xa8, 0x21, 0x5c, 0xde, 0x92, 0xc1, 0x2b, 0x42, 0x47, 0xd8, 0x38, 0x87, 0x2e, 0x58,
|
||||
0x3f, 0x86, 0x0e, 0xdb, 0x6c, 0x75, 0x5e, 0x6d, 0xe7, 0x88, 0x5e, 0xeb, 0x89, 0x9c, 0x22, 0xc3, 0x6f, 0x27, 0xe5,
|
||||
0x38, 0x08, 0xe3, 0x02, 0x47, 0xfe, 0xb7, 0xc5, 0x6d, 0x2c, 0x85, 0xb4, 0xad, 0x21, 0x95, 0xfd, 0x5c, 0x7b, 0xc5,
|
||||
0x4f, 0x87, 0xf6, 0xba, 0xbf, 0xc1, 0x2a, 0xa4, 0x09, 0x1d, 0x11, 0x2a, 0x4f, 0xc7, 0x94, 0x8f, 0xd1, 0x54, 0xaf,
|
||||
0x12, 0x80, 0xfe, 0x2a, 0x94, 0x90, 0xdb, 0x95, 0x15, 0x7a, 0x48, 0x23, 0x56, 0xf9, 0xd5, 0x0d, 0xa8, 0xa2, 0xc6,
|
||||
0x9e, 0x04, 0x7f, 0x14, 0x3e, 0x02, 0xa8, 0x53, 0xe0, 0x70, 0x06, 0x0d, 0xa5, 0xd7, 0xe5, 0xb6, 0xfc, 0x8a, 0xf2,
|
||||
0x25, 0x2e, 0xe1, 0xcf, 0x98, 0x1c, 0x7d, 0x8b, 0xb6, 0x98, 0xee, 0x71, 0x12, 0xe6, 0x86, 0x1d, 0x27, 0x98, 0xdf,
|
||||
0x58, 0x10, 0x43, 0x1d, 0x1e, 0x1d, 0x26, 0x42, 0xda, 0xaf, 0x67, 0xd3, 0x97, 0x04, 0x5e, 0x2d, 0x8c, 0x4d, 0x84,
|
||||
0x7f, 0x55, 0x7a, 0x00, 0x8f, 0x0c, 0x93, 0x38, 0xa9, 0x21, 0x52, 0x10, 0x68, 0x36, 0xbf, 0x18, 0xe3, 0x75, 0xe0,
|
||||
0x2a, 0x3e, 0x07, 0x55, 0xe5, 0xd9, 0x58, 0x69, 0x4c, 0x28, 0x51, 0x79, 0x0f, 0x05, 0x06, 0x10, 0xf3, 0x3e, 0x1f,
|
||||
0xf5, 0x90, 0x35, 0x78, 0x97, 0x70, 0xb4, 0x5e, 0x71, 0xfe, 0x05, 0xd5, 0xa8, 0x3b, 0x47, 0xd5, 0x14, 0x1e, 0x34,
|
||||
0x13, 0x8a, 0x96, 0xb0, 0xf8, 0x19, 0xb1, 0x14, 0xe9, 0x95, 0x22, 0x5a, 0x31, 0xa5, 0x71, 0xd3, 0xcd, 0xe4, 0xa1,
|
||||
0xb5, 0x6b, 0x8c, 0x93, 0xea, 0x99, 0xd1, 0x95, 0x9f, 0x71, 0x14, 0x8e, 0x63, 0x8f, 0xc2, 0x5a, 0x76, 0x03, 0xcb,
|
||||
0xf4, 0xf3, 0x2b, 0xe9, 0x8f, 0x11, 0x29, 0x0c, 0x5b, 0x1b, 0x66, 0x30, 0xb2, 0x4f, 0xcf, 0xf6, 0xc1, 0x5f, 0xc9,
|
||||
0x41, 0xc6, 0x53, 0x49, 0x44, 0x96, 0xb5, 0xce, 0x38, 0x15, 0x6e, 0xe8, 0xe3, 0x22, 0x99, 0x38, 0x45, 0xaa, 0x0a,
|
||||
0x17, 0x25, 0x4a, 0x57, 0xf9, 0x1e, 0x42, 0x0f, 0x78, 0x7b, 0x5d, 0xc2, 0xe9, 0xc8, 0x64, 0x18, 0x09, 0x25, 0x84,
|
||||
0x16, 0x8e, 0x24, 0xf6, 0x65, 0x17, 0x55, 0x94, 0x37, 0x08, 0xc2, 0xf9, 0x82, 0x2a, 0xef, 0x67, 0xab, 0xb5, 0x55,
|
||||
0x14, 0x7a, 0x63, 0x9a, 0x50, 0xf2, 0x52, 0x71, 0x8b, 0x55, 0xd0, 0x99, 0x46, 0xa7, 0x3d, 0x2b, 0x05, 0x59, 0x50,
|
||||
0xb3, 0xe0, 0x77, 0xa3, 0x4c, 0x2f, 0x91, 0x93, 0x05, 0x3c, 0x4a, 0x8f, 0x41, 0x6d, 0xc6, 0xd2, 0x24, 0xa8, 0x8e,
|
||||
0x92, 0x54, 0x43, 0x15, 0xd8, 0x53, 0x79, 0x56, 0x4b, 0x06, 0xa8, 0x36, 0x5b, 0x76, 0xb4, 0xd7, 0x10, 0x82, 0x8c,
|
||||
0x63, 0x5f, 0xad, 0xcf, 0x2b, 0x67, 0x4b, 0xe4, 0xff, 0xb7, 0xa3, 0xbc, 0xaf, 0x9b, 0x2a, 0xaf, 0x1c, 0x80, 0xbe,
|
||||
0x1f, 0x7e, 0x05, 0xf4, 0x8a, 0xb8, 0x13, 0x10, 0xa8, 0x02, 0x05, 0xf7, 0xee, 0xc1, 0x89, 0x54, 0x7d, 0xc1, 0x4e,
|
||||
0x5a, 0x80, 0x38, 0x80, 0x09, 0x49, 0x86, 0xd6, 0xe1, 0x0b, 0x2b, 0x73, 0x13, 0x9a, 0xb0, 0xd0, 0xe6, 0x15, 0xa8,
|
||||
0xb9, 0x6e, 0x89, 0xbc, 0x8e, 0x2c, 0x73, 0x95, 0x9c, 0xe4, 0x91, 0x3c, 0xde, 0x74, 0x26, 0x49, 0xac, 0x7b, 0x24,
|
||||
0xa3, 0x50, 0x61, 0xa7, 0x88, 0xb6, 0xb5, 0xe5, 0x3c, 0xcb, 0xde, 0x94, 0x7d, 0x0a, 0x91, 0x91, 0x50, 0x3a, 0xd8,
|
||||
0x50, 0xed, 0x2b, 0xc8, 0x84, 0xcc, 0x11, 0x3d, 0xaf, 0x67, 0xd0, 0x84, 0x9a, 0x0a, 0x95, 0xe1, 0xc8, 0x87, 0xed,
|
||||
0xe5, 0xff, 0xaf, 0x12, 0xc6, 0x57, 0x5d, 0x27, 0x2a, 0x2a, 0x28, 0x93, 0xb6, 0x03, 0x1c, 0xb0, 0x97, 0x36, 0x3b,
|
||||
0xa6, 0xd3, 0x57, 0x82, 0x49, 0x42, 0x5f, 0x9b, 0xd4, 0x7b, 0x37, 0xdb, 0x16, 0x71, 0x1d, 0xec, 0xd7, 0xe2, 0x52,
|
||||
0x20, 0x93, 0xfa, 0x27, 0xd1, 0xd4, 0xfd, 0x19, 0x21, 0x46, 0xc7, 0x5c, 0x8c, 0x1a, 0x56, 0x3e, 0x0f, 0xf4, 0x36,
|
||||
0xda, 0x99, 0x55, 0xc1, 0x74, 0xaa, 0xf5, 0xdd, 0x0d, 0x4e, 0xfb, 0x50, 0x3e, 0xa5, 0x16, 0x52, 0xe4, 0x67, 0x20,
|
||||
0x38, 0xd4, 0x0a, 0x0e, 0xa9, 0x7e, 0xf6, 0xf9, 0xe8, 0x1f, 0xa8, 0xf7, 0xeb, 0xaa, 0xfc, 0x41, 0x93, 0xe8, 0xe5,
|
||||
0xae, 0xda, 0x6f, 0x53, 0x90, 0xb6, 0x3c, 0xb5, 0x0c, 0x6f, 0x7e, 0x2c, 0xbf, 0x17, 0x40, 0xd4, 0x3d, 0xfb, 0x85,
|
||||
0xaa, 0x78, 0xb8, 0xf8, 0x6d, 0x5f, 0xc6, 0x4c, 0x79, 0x5e, 0x9e, 0xce, 0x96, 0xc7, 0xe8, 0x0a, 0x39, 0xfa, 0x81,
|
||||
0x25, 0xcf, 0x6b, 0xe8, 0xd8, 0x3d, 0x60, 0x64, 0xc4, 0x73, 0x6a, 0x94, 0x96, 0x1d, 0x0c, 0xfe, 0xfc, 0x4a, 0x49,
|
||||
0xdd, 0xf3, 0x80, 0x32, 0x4f, 0x47, 0xb4, 0xf1, 0x72, 0x59, 0x79, 0xfc, 0x81, 0xcc, 0xe8, 0x39, 0xbe, 0x4a, 0xc2,
|
||||
0x3c, 0x3e, 0x4d, 0xe9, 0xbb, 0x2c, 0x36, 0x32, 0xed, 0xc2, 0xc2, 0x29, 0x4d, 0xfa, 0xad, 0x88, 0xb2, 0x1c, 0x25,
|
||||
0x9c, 0x91, 0x64, 0xd0, 0x61, 0x69, 0x97, 0x66, 0x57, 0xfb, 0xb3, 0x43, 0xfa, 0x75, 0x2c, 0x22, 0x06, 0x0c, 0xd2,
|
||||
0xac, 0xcb, 0x41, 0x07, 0x0e, 0x14, 0x45, 0x1a, 0x81, 0xf6, 0x43, 0x19, 0xe5, 0xdf, 0x24, 0x00, 0xac, 0x20, 0x5e,
|
||||
0x17, 0xc9, 0x01, 0x28, 0xe6, 0x9c, 0x9e, 0x88, 0x29, 0x9d, 0xc7, 0x52, 0xda, 0x72, 0xa5, 0x7d, 0x90, 0x31, 0x22,
|
||||
0xe0, 0x29, 0xc2, 0xb3, 0x50, 0x40, 0xff, 0x70, 0xde, 0xb1, 0xc8, 0xe1, 0x65, 0xd2, 0x95, 0x07, 0x97, 0x0d, 0x6d,
|
||||
0x26, 0xda, 0x1e, 0x61, 0xf2, 0x9a, 0x80, 0x07, 0x71, 0x32, 0xee, 0xd5, 0xd8, 0xda, 0x08, 0x35, 0xda, 0x8a, 0x72,
|
||||
0x40, 0x91, 0xff, 0x5c, 0x8e, 0x31, 0xce, 0x40, 0x6d, 0x32, 0xff, 0x32, 0xec, 0xaf, 0x4c, 0x79, 0x42, 0xd0, 0x6f,
|
||||
0xb3, 0xcd, 0x8b, 0xca, 0x73, 0x42, 0xc0, 0x03, 0x85, 0x78, 0xf5, 0x89, 0x93, 0x99, 0x19, 0x7d, 0x39, 0x13, 0xe1,
|
||||
0x4b, 0x63, 0xc0, 0x90, 0x10, 0xb5, 0x8f, 0xd3, 0xf2, 0x8e, 0x1d, 0x05, 0x55, 0xb5, 0xfa, 0xcc, 0x9c, 0xec, 0xee,
|
||||
0x6a, 0x6c, 0xe6, 0x39, 0x61, 0xda, 0x9d, 0x6d, 0xd9, 0x4d, 0x0c, 0x48, 0xd3, 0x30, 0xbe, 0xc2, 0x61, 0xac, 0x97,
|
||||
0x07, 0xa4, 0x12, 0x7f, 0xca, 0x23, 0xc0, 0xb7, 0x33, 0xe8, 0x65, 0xf7, 0x98, 0xd8, 0x16, 0x67, 0x8a, 0x21, 0x5b,
|
||||
0xea, 0x96, 0x1e, 0xa7, 0x64, 0xa2, 0xdc, 0xcb, 0x4a, 0xfa, 0xb0, 0xd8, 0xbc, 0xa6, 0x6c, 0x44, 0x77, 0x0f, 0xc4,
|
||||
0x98, 0xbc, 0x9f, 0xf5, 0x62, 0x20, 0x81, 0xa9, 0xab, 0xeb, 0xeb, 0xcf, 0x50, 0x67, 0x8c, 0x35, 0x3d, 0x27, 0x2a,
|
||||
0x79, 0xda, 0x11, 0xbb, 0x6d, 0xf4, 0x2a, 0x55, 0xcc, 0xd0, 0x11, 0x8b, 0xf5, 0x73, 0x72, 0xf8, 0x58, 0x26, 0x9e,
|
||||
0x32, 0xa4, 0x8a, 0x38, 0x0d, 0x14, 0x6b, 0xc3, 0x4a, 0x67, 0xf5, 0x72, 0x7f, 0xed, 0x2b, 0x4b, 0x8a, 0x26, 0x54,
|
||||
0xcb, 0x44, 0xb2, 0x45, 0x50, 0xc9, 0xb2, 0x22, 0x76, 0xaa, 0x82, 0xae, 0xa7, 0x57, 0x09, 0x11, 0x36, 0x8b, 0x99,
|
||||
0x32, 0x49, 0xa5, 0x51, 0xe6, 0x9c, 0x14, 0xc9, 0x4e, 0x9e, 0x33, 0x5e, 0x30, 0xdb, 0xc9, 0xa4, 0x43, 0x54, 0xdc,
|
||||
0x0f, 0x28, 0xed, 0xa7, 0xe9, 0x41, 0x4f, 0xd0, 0xe4, 0x54, 0x58, 0xdf, 0xe5, 0x95, 0x31, 0x35, 0x91, 0x10, 0x82,
|
||||
0xf0, 0xb0, 0xd8, 0x1b, 0x19, 0xdf, 0xb7, 0xb6, 0xb5, 0xad, 0xaf, 0x93, 0xff, 0x4c, 0xb3, 0xf2, 0x7e, 0x3b, 0xd1,
|
||||
0xea, 0x13, 0x36, 0x07, 0x09, 0x5c, 0x6d, 0xdb, 0x6c, 0xef, 0xb2, 0x05, 0x31, 0x4a, 0xff, 0x32, 0x3e, 0x2e, 0x8a,
|
||||
0x96, 0xbd, 0x1b, 0x01, 0x24, 0xac, 0x9c, 0x2b, 0x60, 0x8c, 0x64, 0x36, 0x64, 0x0a, 0x55, 0xa0, 0xb7, 0x11, 0x64,
|
||||
0xda, 0x82, 0x5a, 0x2e, 0xa8, 0x34, 0x13, 0x5f, 0xfd, 0x66, 0x1c, 0x8d, 0x2c, 0xe0, 0x55, 0xc5, 0xf6, 0x0f, 0x1d,
|
||||
0x9d, 0x8d, 0xed, 0x71, 0xfa, 0x8e, 0x1e, 0x2f, 0x7b, 0x4d, 0x72, 0xbe, 0xb9, 0x41, 0xc1, 0x0a, 0xde, 0x7c, 0x5d,
|
||||
0x31, 0x5d, 0xd1, 0x47, 0x4a, 0xb6, 0x6e, 0x06, 0x83, 0xb5, 0xde, 0xde, 0x24, 0x65, 0xed, 0x30, 0x79, 0xfb, 0xf8,
|
||||
0xa0, 0x23, 0xd4, 0x72, 0x2f, 0x9b, 0x36, 0xba, 0x05, 0x50, 0x0b, 0xbf, 0x3f, 0x72, 0xb0, 0xd1, 0x3b, 0x8f, 0xf9,
|
||||
0x1a, 0xf8, 0x38, 0x67, 0xb2, 0x32, 0xe0, 0xc1, 0x27, 0x43, 0x42, 0x1d, 0x0d, 0x29, 0x79, 0x54, 0x88, 0xbe, 0x98,
|
||||
0x02, 0xc5, 0xe5, 0xf1, 0x53, 0x44, 0x0d, 0xcc, 0xad, 0x3b, 0x10, 0x86, 0xbd, 0xdf, 0x6c, 0xdb, 0x7e, 0x17, 0x4d,
|
||||
0xec, 0x1a, 0x2d, 0xa5, 0x09, 0xa8, 0x60, 0xc6, 0x78, 0x2a, 0x0f, 0xed, 0xc9, 0xa5, 0x12, 0x0e, 0xfc, 0x8e, 0xd5,
|
||||
0x79, 0x75, 0xba, 0xb8, 0x2f, 0xa9, 0x5c, 0x0b, 0x27, 0x19, 0x5c, 0x2b, 0x07, 0x56, 0x45, 0x49, 0x31, 0x55, 0xb9,
|
||||
0x8f, 0x0a, 0xa5, 0x22, 0x05, 0xb4, 0x4f, 0x35, 0x5f, 0xa7, 0x84, 0x30, 0xc7, 0x6a, 0xab, 0xf1, 0x34, 0x9a, 0x32,
|
||||
0x3e, 0xc6, 0x56, 0xdb, 0xb1, 0x93, 0xaf, 0x93, 0x99, 0x35, 0x10, 0x85, 0xf7, 0x31, 0xee, 0x22, 0xd4, 0xf5, 0x81,
|
||||
0xe8, 0xf1, 0x3d, 0x39, 0xcf, 0x62, 0x8a, 0x00, 0xaf, 0xb4, 0x97, 0x32, 0x2f, 0xd5, 0x44, 0x5d, 0x9d, 0xa5, 0x64,
|
||||
0xa9, 0x6d, 0x65, 0x52, 0x6a, 0x70, 0x79, 0x6b, 0x7e, 0x19, 0x40, 0xb1, 0x9d, 0x98, 0x6a, 0x8b, 0x2d, 0x41, 0x82,
|
||||
0xd0, 0x97, 0x67, 0x31, 0x09, 0xf9, 0x41, 0xb1, 0xc9, 0x63, 0x4b, 0xd4, 0x5d, 0x27, 0xaa, 0x27, 0xd5, 0xcf, 0x3f,
|
||||
0x11, 0xf3, 0x0d, 0xc9, 0x81, 0x9b, 0xb2, 0xe7, 0x55, 0x27, 0xbe, 0x72, 0xe3, 0xd3, 0xd9, 0x9e, 0x64, 0x06, 0xcf,
|
||||
0x56, 0xde, 0xd2, 0x61, 0x3f, 0xa4, 0x68, 0x4b, 0xda, 0x22, 0x43, 0x8c, 0xb9, 0xba, 0xfb, 0x62, 0x4f, 0x7e, 0x13,
|
||||
0x0c, 0xed, 0x27, 0x08, 0x88, 0x54, 0x11, 0x71, 0x3e, 0x30, 0xd5, 0xff, 0x19, 0x49, 0x20, 0xb3, 0x0c, 0x09, 0xdc,
|
||||
0x46, 0xc4, 0x10, 0xb2, 0xd6, 0x60, 0xb7, 0xde, 0xdf, 0x73, 0x92, 0xc3, 0x4f, 0x6d, 0xe4, 0xe3, 0x69, 0x56, 0xda,
|
||||
0xa8, 0x6e, 0x96, 0x1b, 0xb4, 0x35, 0x32, 0xa8, 0xfb, 0x1b, 0x6a, 0x56, 0x7e, 0x21, 0x6e, 0xdc, 0xeb, 0xb0, 0x51,
|
||||
0x36, 0x49, 0x4d, 0x99, 0x35, 0x72, 0xe6, 0xea, 0x54, 0xf8, 0x64, 0x56, 0x33, 0x73, 0x22, 0x4b, 0x20, 0x33, 0x01,
|
||||
0x56, 0xb6, 0xee, 0xa3, 0xc8, 0x13, 0x16, 0xf9, 0xa2, 0x58, 0x28, 0x2b, 0x1f, 0xfa, 0x17, 0x7c, 0x4b, 0x1f, 0xa7,
|
||||
0xe2, 0xf0, 0xfb, 0xe4, 0x21, 0xbd, 0x59, 0x5e, 0x26, 0x6d, 0x54, 0x3a, 0x97, 0xdd, 0x04, 0x86, 0x6b, 0x8c, 0x49,
|
||||
0x9a, 0x1c, 0xa8, 0x68, 0xac, 0xa9, 0x31, 0x98, 0x52, 0xe5, 0xea, 0x47, 0x03, 0xaa, 0x68, 0x1c, 0x4a, 0x69, 0x14,
|
||||
0x8a, 0xd3, 0x84, 0x5a, 0xbb, 0x9c, 0x79, 0x92, 0x81, 0xcc, 0x92, 0x31, 0x73, 0xb0, 0x75, 0x5a, 0xb7, 0xaf, 0x04,
|
||||
0x26, 0x00, 0x16, 0x92, 0x69, 0x03, 0x7a, 0x61, 0x5a, 0x41, 0xd5, 0x97, 0x63, 0x00, 0x5f, 0x63, 0x30, 0x85, 0xcc,
|
||||
0x6b, 0x8e, 0x8a, 0xbb, 0xa3, 0xff, 0x25, 0x15, 0x54, 0x49, 0x76, 0x0d, 0x9a, 0xb2, 0xd9, 0x70, 0x04, 0x9f, 0xbe,
|
||||
0xfd, 0x25, 0x81, 0x50, 0x87, 0xcc, 0x54, 0x8d, 0x34, 0x32, 0x2b, 0x10, 0xc8, 0x82, 0x43, 0x11, 0x3a, 0xe0, 0x91,
|
||||
0xb4, 0xc7, 0xa3, 0x8c, 0x98, 0xfa, 0x59, 0x72, 0x9a, 0x92, 0x15, 0x0b, 0x03, 0x93, 0x0c, 0xee, 0xd0, 0x2e, 0x15,
|
||||
0xa7, 0x19, 0xcc, 0x62, 0x84, 0xce, 0xab, 0x19, 0x62, 0xa5, 0xf3, 0x01, 0x6d, 0xd4, 0x21, 0x6e, 0xe5, 0x9d, 0xe6,
|
||||
0x87, 0x56, 0xa5, 0x43, 0x40, 0x93, 0xa8, 0x09, 0xbd, 0x95, 0xfa, 0x87, 0xd6, 0x30, 0xb9, 0xf4, 0x65, 0x35, 0x07,
|
||||
0x93, 0xd4, 0x85, 0x9e, 0xa3, 0x98, 0x62, 0xb7, 0x0d, 0x81, 0xc4, 0xf2, 0xca, 0x1c, 0x02, 0x70, 0x73, 0x5c, 0x11,
|
||||
0xae, 0xac, 0x1e, 0x20, 0x4c, 0xac, 0x18, 0xe8, 0xa4, 0x14, 0xbf, 0x0a, 0x09, 0x3e, 0xf7, 0xd8, 0x2e, 0x07, 0xc1,
|
||||
0x9e, 0x13, 0x90, 0xce, 0xa6, 0x69, 0xdb, 0x5a, 0xf8, 0x47, 0x60, 0x1c, 0x4c, 0x71, 0xef, 0xd8, 0x8d, 0x7d, 0x11,
|
||||
0xbd, 0xce, 0x10, 0x1f, 0x8e, 0xf8, 0xa4, 0x58, 0x30, 0xad, 0xa1, 0xe3, 0xca, 0xb3, 0x2d, 0xc7, 0xd4, 0x52, 0xfe,
|
||||
0x8d, 0x18, 0xab, 0xd3, 0x22, 0x49, 0x6b, 0xa5, 0x8a, 0xcd, 0xec, 0x5d, 0x66, 0x2e, 0x1d, 0x88, 0xa6, 0xef, 0x03,
|
||||
0x15, 0x4c, 0x47, 0x47, 0x27, 0xd1, 0x9c, 0x91, 0x27, 0x8d, 0x2f, 0x14, 0x15, 0x0a, 0x8f, 0x03, 0x69, 0xba, 0xed,
|
||||
0x4e, 0x6b, 0x4b, 0x0b, 0x83, 0xec, 0xf9, 0x54, 0x08, 0x9a, 0xaa, 0xbc, 0x50, 0x18, 0x65, 0xd1, 0x37, 0x23, 0xda,
|
||||
0x28, 0x44, 0x7e, 0xb7, 0x4f, 0xe4, 0x80, 0xa8, 0xf8, 0x2f, 0xdc, 0xad, 0xaf, 0xb4, 0xfa, 0x7f,
|
||||
};
|
||||
|
||||
static const uint8_t MIXED[] = {
|
||||
0x4a, 0x2d, 0x2e, 0xc8, 0xc8, 0xcf, 0x4d, 0x55, 0xc8, 0x2f, 0x49, 0x54, 0x48, 0x49, 0x4d, 0xcb, 0x49, 0x2c, 0x49,
|
||||
0x55, 0x48, 0x1d, 0x15, 0x1b, 0x15, 0x1b, 0x15, 0x1b, 0x15, 0x1b, 0x84, 0x62, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
|
||||
0x00, 0xb8, 0x0b, 0x47, 0xf4, 0x53, 0xc3, 0x7d, 0x78, 0x8e, 0xb4, 0x4d, 0xb7, 0x48, 0x2f, 0x6d, 0x46, 0x3d, 0x19,
|
||||
0xe5, 0x70, 0x24, 0x4c, 0xbb, 0xa0, 0xe3, 0x58, 0xfc, 0x78, 0x74, 0xfa, 0x8c, 0xb1, 0x95, 0x5c, 0xaf, 0xb5, 0x32,
|
||||
0x12, 0x53, 0xfe, 0x93, 0xd1, 0x23, 0x2c, 0x45, 0xed, 0x4c, 0xe9, 0xc9, 0x99, 0x0d, 0x7d, 0xff, 0xdc, 0x01, 0x30,
|
||||
0x51, 0x55, 0x2c, 0x63, 0xa0, 0xb0, 0xc7, 0x6d, 0xee, 0xe4, 0xcc, 0x36, 0xd0, 0x32, 0x40, 0x96, 0x91, 0xdd, 0x43,
|
||||
0x6b, 0x26, 0xaa, 0xd8, 0x7c, 0xd6, 0x16, 0x75, 0x11, 0xa6, 0x5a, 0x4a, 0x4e, 0x86, 0x1f, 0x51, 0x53, 0x3c, 0x01,
|
||||
0x1a, 0x16, 0x14, 0xc6, 0x54, 0xfb, 0x44, 0x5b, 0x1a, 0x38, 0x21, 0x92, 0x03, 0xeb, 0x04, 0x9d, 0xe8, 0xf8, 0xfa,
|
||||
0x4a, 0x73, 0xa4, 0x2f, 0xfc, 0x6d, 0xf3, 0x18, 0x6d, 0xc4, 0xc1, 0x62, 0x25, 0x5d, 0xa3, 0x9d, 0xb9, 0x9f, 0x7b,
|
||||
0xa8, 0xc4, 0xbb, 0xdd, 0xdb, 0xa7, 0xbd, 0x25, 0xf7, 0x00, 0x54, 0x54, 0xce, 0xeb, 0x61, 0xaf, 0xb2, 0xfb, 0x42,
|
||||
0x16, 0x9f, 0xf7, 0xdb, 0x25, 0x28, 0x54, 0x68, 0x0c, 0x22, 0x76, 0x06, 0x2f, 0x12, 0xa7, 0xfa, 0x7c, 0x57, 0xd3,
|
||||
0xc8, 0x90, 0x17, 0x09, 0xf5, 0x89, 0xea, 0xb2, 0x96, 0xa9, 0x49, 0x8f, 0xa1, 0xb0, 0xb5, 0x74, 0xf0, 0xf6, 0xa7,
|
||||
0xc6, 0x14, 0x4a, 0x3a, 0xb6, 0xdf, 0x8d, 0x9a, 0x3a, 0xb0, 0x0e, 0x2c, 0xd0, 0x7c, 0xa5, 0x7b, 0xf2, 0xa1, 0x8e,
|
||||
0xe5, 0x58, 0x6b, 0x0b, 0x0a, 0xf0, 0x62, 0xb8, 0xf0, 0x9e, 0x59, 0xac, 0xf6, 0xb3, 0x38, 0x54, 0x7f, 0x2f, 0x84,
|
||||
0x10, 0x5a, 0xb7, 0xb3, 0x8a, 0xf3, 0x54, 0x32, 0xdb, 0x3b, 0xf1, 0x32, 0x5c, 0x59, 0x93, 0x36, 0x4c, 0x0d, 0x56,
|
||||
0x5e, 0x26, 0xe8, 0x2b, 0x71, 0xc0, 0x2e, 0x53, 0xab, 0x23, 0x86, 0x9a, 0x4c, 0x2e, 0x68, 0x54, 0xdd, 0xe9, 0x43,
|
||||
0x19, 0x40, 0xaa, 0x71, 0x40, 0x7f, 0xea, 0xdb, 0x1c, 0x51, 0xe4, 0x6c, 0xf9, 0x6b, 0xf3, 0x37, 0xd4, 0x8d, 0xa9,
|
||||
0x67, 0xde, 0x48, 0xae, 0xea, 0xaf, 0x8f, 0x5f, 0xdd, 0x4a, 0x05, 0x22, 0xb6, 0xd5, 0x00, 0x8b, 0x33, 0x15, 0x60,
|
||||
0x30, 0x06, 0xab, 0x13, 0x4c, 0x3d, 0x10, 0x63, 0x16, 0x73, 0x52, 0x06, 0xdf, 0xb8, 0x8c, 0xe4, 0xee, 0x41, 0x26,
|
||||
0xa6, 0x1c, 0xd0, 0xd2, 0x03, 0x2e, 0xe2, 0x41, 0xc9, 0xf5, 0x9a, 0xa9, 0xad, 0x27, 0x70, 0xf8, 0xd4, 0xfc, 0x99,
|
||||
0xd5, 0x1d, 0x88, 0x35, 0x5b, 0x35, 0xdb, 0x3b, 0x94, 0x58, 0xda, 0x24, 0xb7, 0xe7, 0xdc, 0x5a, 0x22, 0xaf, 0x04,
|
||||
0x5f, 0x16, 0xf3, 0x61, 0xbd, 0x34, 0x3f, 0xc6, 0xb2, 0xbb, 0xec, 0x6a, 0x97, 0x7f, 0x72, 0x40, 0x14, 0xa8, 0x70,
|
||||
0x15, 0x06, 0x30, 0x7d, 0x6b, 0x2b, 0x1a, 0xac, 0x17, 0x93, 0x73, 0xe1, 0x9c, 0xc7, 0x0a, 0xd7, 0x46, 0xb6, 0xee,
|
||||
0xed, 0x06, 0x63, 0xac, 0xb3, 0x11, 0x50, 0x45, 0x38, 0x37, 0xa9, 0xf1, 0x11, 0x04, 0x31, 0x97, 0x2a, 0x98, 0xed,
|
||||
0x07, 0x4c, 0x46, 0x92, 0xfd, 0x72, 0xef, 0xb0, 0xd6, 0xcb, 0x1d, 0x9b, 0x10, 0x8f, 0xde, 0x1c, 0x83, 0x82, 0x66,
|
||||
0xdc, 0x61, 0x49, 0x64, 0x8c, 0xef, 0x70, 0x20, 0xd5, 0x00, 0x37, 0x59, 0x03, 0x36, 0x1f, 0xe1, 0x71, 0xf8, 0x39,
|
||||
0xf4, 0xb2, 0x32, 0x29, 0x5d, 0x84, 0xcf, 0xfd, 0x47, 0x75, 0xf8, 0xb0, 0xe4, 0x53, 0x09, 0x7c, 0xbf, 0x55, 0x58,
|
||||
0xe3, 0xe2, 0x0a, 0xa5, 0x7c, 0xa7, 0x05, 0x5f, 0x7e, 0x5e, 0x45, 0x9c, 0x0e, 0xa4, 0x67, 0xd6, 0x48, 0x7e, 0x8b,
|
||||
0x66, 0x0f, 0x38, 0x06, 0xc2, 0x95, 0x00, 0xcc, 0x77, 0xa9, 0x41, 0x9b, 0xe4, 0xc3, 0xc1, 0xe8, 0xbc, 0xd1, 0x79,
|
||||
0x8a, 0x39, 0xbf, 0x38, 0x29, 0x21, 0xc9, 0xf6, 0x65, 0x7a, 0x80, 0xf9, 0xc6, 0x0c, 0x9d, 0xaa, 0x66, 0x9b, 0x89,
|
||||
0x34, 0x60, 0xe1, 0xa8, 0xe2, 0xf7, 0x4d, 0x69, 0x35, 0x86, 0x7e, 0x0f, 0xc8, 0x2c, 0x7e, 0x3c, 0xe4, 0x33, 0xbf,
|
||||
0x42, 0xe3, 0x44, 0xd6, 0x29, 0x45, 0x4d, 0xf9, 0x80, 0x94, 0x2e, 0x3a, 0xe4, 0xf8, 0x26, 0x80, 0x52, 0x99, 0x00,
|
||||
0x4a, 0x2c, 0xb7, 0xfd, 0x24, 0x0c, 0x8b, 0x80, 0xe5, 0x4c, 0xdd, 0x7c, 0xad, 0x52, 0x62, 0x9e, 0xa2, 0x9c, 0xdb,
|
||||
0x3a, 0x65, 0x8f, 0xee, 0xf6, 0x56, 0xff, 0xc3, 0x38, 0x8d, 0x7d, 0x5e, 0x50, 0x93, 0x64, 0xbf, 0x65, 0xe4, 0xa2,
|
||||
0xbb, 0x21, 0x25, 0x47, 0x98, 0x1c, 0x25, 0xcf, 0x6b, 0x09, 0x95, 0x30, 0x32, 0xa3, 0x87, 0xa2, 0xb1, 0x55, 0xa9,
|
||||
0x30, 0x0d, 0xac, 0x3e, 0x03, 0x29, 0x7d, 0xe0, 0x69, 0xc4, 0xd5, 0xf7, 0xa8, 0x4f, 0xa5, 0xf8, 0x85, 0x8f, 0x2a,
|
||||
0x5e, 0x93, 0xf7, 0x1e, 0x69, 0x3c, 0xc3, 0xa0, 0x99, 0x91, 0xd4, 0xe4, 0xe9, 0xd1, 0x4f, 0x9a, 0xcc, 0xbb, 0xf4,
|
||||
0x1f, 0xe8, 0x94, 0x3e, 0x66, 0x95, 0xf7, 0x3f, 0xa5, 0x14, 0x5f, 0x3a, 0xbf, 0x8f, 0x75, 0xfe, 0x74, 0xd5, 0x1a,
|
||||
0x05, 0x4b, 0xd2, 0x34, 0x50, 0x3b, 0xcf, 0x39, 0x00, 0x1c, 0x6f, 0x7d, 0xb4, 0xd0, 0x65, 0x3b, 0xa6, 0x30, 0xf6,
|
||||
0x65, 0x84, 0xb8, 0x32, 0x2c, 0x10, 0xf3, 0xf2, 0x4e, 0x76, 0xa5, 0x90, 0x22, 0x71, 0xba, 0x69, 0x64, 0x1c, 0xf1,
|
||||
0x14, 0xc1, 0x98, 0x48, 0x5f, 0x21, 0x63, 0x26, 0x0d, 0xb8, 0x73, 0x4b, 0x52, 0xcc, 0x16, 0x78, 0x0a, 0x44, 0x89,
|
||||
0xdd, 0xbd, 0xf4, 0x5a, 0x47, 0x54, 0xaa, 0x7e, 0x06, 0x97, 0xf8, 0x31, 0x9f, 0x6e, 0xbf, 0x91, 0x36, 0xd4, 0x80,
|
||||
0xf9, 0xba, 0x9a, 0x62, 0x1e, 0xce, 0xe1, 0x03, 0xec, 0x7a, 0x55, 0xff, 0x1e, 0x96, 0x2a, 0x41, 0x9f, 0xf2, 0xd7,
|
||||
0x0c, 0xa4, 0x46, 0x95, 0xc8, 0x86, 0xdd, 0x96, 0x8d, 0x60, 0x00, 0x06, 0x71, 0x6d, 0x23, 0xc2, 0x91, 0x1e, 0xd2,
|
||||
0xdb, 0xe2, 0xfe, 0x59, 0xc9, 0xb5, 0x46, 0x36, 0x6f, 0x0b, 0x3f, 0x3f, 0xd2, 0x9e, 0x5c, 0x93, 0x99, 0xac, 0x13,
|
||||
0x42, 0x44, 0x82, 0x7f, 0xbc, 0x2c, 0xcc, 0xb7, 0xfa, 0x3f, 0x9e, 0xec, 0x6e, 0x77, 0x41, 0x44, 0xab, 0x1f, 0xbe,
|
||||
0x7a, 0xd4, 0xc5, 0x2c, 0x32, 0xc6, 0xfe, 0xba, 0x1d, 0x05, 0xdc, 0x7c, 0xd1, 0x67, 0x30, 0xf6, 0x65, 0x83, 0x80,
|
||||
0x69, 0xd0, 0xd7, 0xc7, 0xdf, 0xff, 0xbb, 0xef, 0xf8, 0xb8, 0x09, 0x0f, 0x73, 0x31, 0x89, 0x64, 0x7c, 0x6f, 0x1f,
|
||||
0x11, 0xb8, 0x60, 0xb4, 0x97, 0x11, 0xb7, 0xe4, 0x12, 0x41, 0x8b, 0x6c, 0x39, 0x20, 0xaf, 0x51, 0x13, 0xae, 0xcf,
|
||||
0xd1, 0x7a, 0xe0, 0x4f, 0x0b, 0x51, 0x2b, 0xe3, 0x6d, 0x84, 0xd1, 0xee, 0xe1, 0xc4, 0xee, 0x9c, 0xb7, 0x00, 0x41,
|
||||
0xbe, 0x51, 0xa2, 0xbb, 0x68, 0x90, 0x8e, 0xca, 0x4c, 0x02, 0xdb, 0x62, 0xd5, 0xc8, 0x4f, 0xd0, 0x03, 0x48, 0x9d,
|
||||
0x3e, 0x09, 0x98, 0x5d, 0x05, 0xa8, 0xa5, 0xcf, 0xb6, 0x4a, 0x27, 0x50, 0xe6, 0xdd, 0x45, 0x98, 0xbd, 0x75, 0x07,
|
||||
0xb9, 0x3d, 0xa0, 0x7f, 0xd7, 0x53, 0x88, 0xb7, 0xa8, 0xa0, 0xcc, 0x59, 0xab, 0x04, 0x1b, 0x21, 0x27, 0xee, 0x94,
|
||||
0x03, 0xea, 0x66, 0xe1, 0x1b, 0xbf, 0xd7, 0x0d, 0x59, 0xac, 0x9e, 0x29, 0xe9, 0xf0, 0x53, 0xa3, 0x63, 0xbf, 0xda,
|
||||
0x61, 0xb7, 0xbb, 0x28, 0xa0, 0xd6, 0x32, 0xd5, 0x90, 0x21, 0x1a, 0x66, 0xab, 0x92, 0xcd, 0x58, 0xd9, 0xad, 0x85,
|
||||
0xec, 0x45, 0x24, 0x95, 0xb6, 0xfd, 0x4d, 0x6d, 0xe3, 0x4c, 0x44, 0x4b, 0x4d, 0xd7, 0xe0, 0xc2, 0x40, 0x7a, 0x56,
|
||||
0xec, 0x0a, 0xe0, 0xaf, 0x6e, 0x45, 0xe4, 0xeb, 0x30, 0xe3, 0xab, 0xf3, 0xd9, 0xfe, 0x7e, 0x40, 0x0d, 0x5d, 0x68,
|
||||
0x4c, 0x66, 0xc5, 0x93, 0xbb, 0x33, 0x06, 0x63, 0x49, 0xf3, 0xc1, 0x4f, 0x73, 0x90, 0xfa, 0x84, 0xe5, 0x5b, 0x61,
|
||||
0x38, 0xa6, 0xcb, 0x60, 0xce, 0x05, 0xf5, 0xe3, 0xaf, 0x43, 0xcb, 0xeb, 0xe2, 0xfd, 0x14, 0xd2, 0x71, 0x60, 0x2f,
|
||||
0x5c, 0x7c, 0x0b, 0x87, 0x81, 0x1a, 0xc2, 0xd5, 0xfd, 0xf3, 0xd9, 0x19, 0x93, 0x9e, 0x5b, 0x56, 0x25, 0xbb, 0xfd,
|
||||
0x10, 0x75, 0xd0, 0xc5, 0x86, 0xb9, 0xe4, 0x7a, 0xb0, 0xe0, 0xdd, 0xca, 0xf7, 0xa7, 0x9a, 0x3e, 0xb6, 0x5a, 0xd0,
|
||||
0xde, 0x75, 0x6b, 0xa5, 0xa3, 0xdf, 0xb4, 0x0e, 0xa1, 0x89, 0x8c, 0xe9, 0xf1, 0x62, 0x8b, 0xda, 0x5f, 0xf8, 0x1d,
|
||||
0xe6, 0xd9, 0x70, 0xc9, 0xd0, 0x92, 0x42, 0x3f, 0x36, 0xf9, 0xb9, 0x23, 0x6b, 0x5d, 0x26, 0x9c, 0x14, 0x5d, 0xe7,
|
||||
0x9b, 0x81, 0x11, 0x1b, 0xec, 0xd1, 0xf9, 0x22, 0xfe, 0xc4, 0xa9, 0xd7, 0x71, 0x5e, 0x32, 0x8d, 0x64, 0x41, 0x50,
|
||||
0xca, 0x7c, 0xc8, 0x55, 0xc6, 0xb5, 0xe3, 0xd8, 0xa1, 0xe8, 0xb5, 0x1c, 0x68, 0x20, 0xef, 0x42, 0xc6, 0x9d, 0xea,
|
||||
0x2f, 0x8a, 0xa4, 0x87, 0x3b, 0xdc, 0x0c, 0xc7, 0x9f, 0x3f, 0x89, 0x29, 0x9b, 0x46, 0xb7, 0xc7, 0x6a, 0x16, 0xe6,
|
||||
0x2f, 0xe6, 0x9f, 0xa8, 0x02, 0xfb, 0x99, 0x1b, 0x4f, 0xcd, 0x40, 0xf7, 0xad, 0xa9, 0xd0, 0x56, 0x1a, 0xad, 0xc0,
|
||||
0x47, 0x96, 0x36, 0xbe, 0x11, 0x7f, 0x0c, 0x6d, 0x47, 0xab, 0x4f, 0xe1, 0x90, 0x47, 0x21, 0xd6, 0x33, 0x72, 0x11,
|
||||
0xb4, 0x65, 0x99, 0x4a, 0x43, 0x52, 0x90, 0x80, 0x2e, 0xed, 0x75, 0x96, 0x39, 0x78, 0x45, 0x0f, 0x42, 0xd2, 0x3b,
|
||||
0x3b, 0xf9, 0x84, 0xed, 0x1d, 0x5e, 0x8a, 0x24, 0x1f, 0xff, 0xe1, 0x7e, 0x75, 0xef, 0xd4, 0xc5, 0x51, 0x85, 0x07,
|
||||
0x0e, 0xcb, 0xda, 0x40, 0x92, 0x8e, 0x00, 0xf9, 0x4c, 0x44, 0x03, 0xa6, 0x56, 0xbf, 0xa0, 0xc6, 0x04, 0xec, 0xc7,
|
||||
0xac, 0xbd, 0x78, 0xd2, 0x0a, 0x9d, 0x3f, 0x83, 0x42, 0xcc, 0x79, 0xc0, 0x6d, 0x9d, 0xa3, 0x0d, 0x27, 0x66, 0x2f,
|
||||
0xcd, 0x21, 0x22, 0xeb, 0x38, 0x64, 0xc7, 0x31, 0x1b, 0x66, 0x68, 0xd4, 0x53, 0xce, 0x0b, 0xc5, 0x07, 0x07, 0x48,
|
||||
0x89, 0xa9, 0x86, 0xa6, 0x5b, 0xaa, 0xdc, 0xb5, 0x20, 0x00, 0x7b, 0xeb, 0x0f, 0x58, 0x48, 0x3f, 0x1d, 0x1b, 0xe4,
|
||||
0x87, 0x29, 0x23, 0xba, 0x92, 0xec, 0x3a, 0xc8, 0x05, 0x9e, 0x56, 0x2e, 0xf6, 0x69, 0x97, 0x79, 0x4a, 0x8f, 0xfc,
|
||||
0xac, 0xcf, 0x5a, 0xe9, 0x12, 0x18, 0xc7, 0x59, 0xc6, 0x1c, 0xf1, 0xe3, 0xfe, 0x8d, 0x3f, 0x6e, 0x1c, 0xfa, 0x4d,
|
||||
0xb3, 0x73, 0xa4, 0x9b, 0x77, 0xd9, 0x20, 0xf8, 0x86, 0xf1, 0xb0, 0xac, 0x6e, 0x35, 0x62, 0x68, 0x01, 0xc6, 0xe6,
|
||||
0xee, 0x88, 0xf3, 0x30, 0x80, 0xc7, 0x8b, 0xd2, 0x0a, 0xb5, 0xe3, 0x17, 0x0e, 0xf8, 0xa6, 0xdf, 0x53, 0x22, 0x5f,
|
||||
0x3d, 0x4d, 0xae, 0xc7, 0xd1, 0x4b, 0xb9, 0xd0, 0xe6, 0x63, 0x80, 0x6e, 0x4c, 0x1d, 0x9d, 0x28, 0xf4, 0xe2, 0x01,
|
||||
0x62, 0x4d, 0x23, 0xb0, 0x67, 0x61, 0x49, 0x3f, 0x39, 0xae, 0x5f, 0x0f, 0x18, 0xc5, 0x81, 0x47, 0xd4, 0xa5, 0x04,
|
||||
0x93, 0xd3, 0xd5, 0x63, 0x9e, 0xe2, 0x43, 0xec, 0x50, 0xbc, 0xdf, 0x2e, 0xc7, 0x5a, 0xf7, 0x21, 0x17, 0x00, 0x51,
|
||||
0x14, 0xc2, 0x04, 0x0a, 0x57, 0xf6, 0x5d, 0x31, 0xac, 0x89, 0xef, 0x22, 0x6e, 0xb5, 0x98, 0xa4, 0x7f, 0x93, 0xfa,
|
||||
0xc2, 0xf3, 0x58, 0x07, 0x6a, 0x7e, 0x53, 0x4e, 0xc7, 0x9e, 0xa2, 0x07, 0x5e, 0x87, 0xb7, 0xdf, 0xea, 0xd3, 0x8f,
|
||||
0x84, 0xf8, 0xe6, 0xac, 0xf0, 0x42, 0x22, 0xd7, 0x76, 0xcd, 0xd0, 0x97, 0x8e, 0xc1, 0xc9, 0x6f, 0x61, 0x0c, 0xe8,
|
||||
0xdb, 0x13, 0xb5, 0x2f, 0x09, 0xd2, 0x00, 0xbc, 0x58, 0xa3, 0x47, 0x6a, 0x91, 0xe7, 0x93, 0x46, 0xe7, 0xb0, 0xfd,
|
||||
0xb8, 0xb0, 0xc6, 0xc7, 0x6d, 0xe1, 0x77, 0x39, 0x07, 0x4c, 0x22, 0x3d, 0x84, 0x98, 0x82, 0xba, 0x6f, 0x04, 0xbb,
|
||||
0xb0, 0xc9, 0xdb, 0x26, 0x18, 0xb4, 0xb6, 0xdd, 0x79, 0xe5, 0x74, 0x05, 0x4a, 0xc7, 0xfa, 0xde, 0x0b, 0x70, 0xab,
|
||||
0x8c, 0x22, 0x45, 0xa6, 0xa3, 0x76, 0x6b, 0xc2, 0x74, 0xcd, 0xf4, 0x4b, 0x19, 0xe6, 0xc6, 0x79, 0x42, 0x56, 0x4b,
|
||||
0xb4, 0xbe, 0x23, 0xdb, 0x8a, 0xc9, 0x22, 0xe9, 0x6c, 0x18, 0x10, 0xef, 0x2c, 0xa5, 0x73, 0x1a, 0x37, 0x3a, 0x2e,
|
||||
0xb5, 0x92, 0xc0, 0xe7, 0x57, 0x95, 0x45, 0x19, 0xcd, 0x6a, 0xce, 0xf8, 0xc5, 0x45, 0xe2, 0x08, 0x3f, 0x61, 0xd3,
|
||||
0x7b, 0xb3, 0xbe, 0xcb, 0x4f, 0x03, 0x9b, 0x9a, 0x24, 0x1f, 0xb5, 0x41, 0xde, 0x7a, 0x3e, 0x3e, 0xff, 0x30, 0x9c,
|
||||
0x95, 0xc1, 0xf4, 0xe6, 0xa3, 0xf6, 0xbb, 0x1f, 0xa2, 0xa0, 0x2a, 0x30, 0xfb, 0x50, 0xc0, 0xa7, 0x4f, 0x3f, 0xc3,
|
||||
0x32, 0x43, 0x2e, 0xec, 0xd9, 0x0f, 0xfd, 0xd1, 0xff, 0xc6, 0x0d, 0x16, 0x17, 0x63, 0x57, 0x53, 0x25, 0x97, 0x49,
|
||||
0xc4, 0xfb, 0x55, 0x64, 0xb4, 0x31, 0x19, 0x97, 0xa6, 0xe1, 0xfc, 0x59, 0x48, 0x27, 0x79, 0x88, 0x18, 0x5c, 0xfd,
|
||||
0x04, 0xd3, 0x0d, 0x30, 0x0a, 0xa2, 0xbd, 0x06, 0x52, 0x04, 0x5f, 0x84, 0xe8, 0x7a, 0x92, 0x52, 0xcc, 0xf4, 0x9a,
|
||||
0x06, 0x48, 0xfe, 0x22, 0x2a, 0x13, 0xaa, 0xb4, 0x13, 0x2a, 0x3c, 0xf4, 0x61, 0x6a, 0x98, 0xa0, 0x55, 0xee, 0x6c,
|
||||
0x48, 0xd6, 0x2b, 0x1d, 0xcc, 0x41, 0xcc, 0x73, 0x9a, 0xf4, 0x4e, 0x03, 0xa4, 0x98, 0x5c, 0x60, 0x24, 0x32, 0xe8,
|
||||
0x00, 0x0f, 0xe9, 0x0d, 0xf0, 0x5a, 0x95, 0xa8, 0x38, 0xef, 0x0b, 0xb0, 0x0c, 0x6e, 0x2b, 0x59, 0xb7, 0xa4, 0xa6,
|
||||
0xed, 0x47, 0xcc, 0x90, 0x65, 0xf9, 0x88, 0xa9, 0xca, 0x63, 0x9d, 0x6b, 0x4e, 0x64, 0x71, 0xd3, 0x29, 0xcb, 0x46,
|
||||
0xf0, 0x34, 0xca, 0x34, 0x2c, 0x48, 0x19, 0xe8, 0x5d, 0x55, 0xe9, 0x1f, 0x8b, 0x41, 0x8f, 0xe0, 0x7f, 0x86, 0xed,
|
||||
0x7c, 0x10, 0x8a, 0xa0, 0x46, 0x2d, 0xbd, 0xeb, 0x13, 0xa9, 0x75, 0x66, 0x70, 0xca, 0x89, 0x66, 0xa6, 0x8f, 0xaf,
|
||||
0x2b, 0x6e, 0xc5, 0x96, 0xcd, 0x74, 0xc8, 0xc2, 0xe3, 0x8e, 0x1a, 0x2b, 0xf8, 0xb9, 0xa5, 0x95, 0xaf, 0xd8, 0xd0,
|
||||
0xae, 0xb0, 0x2b, 0x44, 0xe9, 0x59, 0x90, 0x7b, 0x1d, 0x26, 0x7d, 0x0d, 0xdc, 0xdc, 0xb9, 0xba, 0x94, 0x78, 0xdd,
|
||||
0x36, 0x68, 0xdb, 0x8e, 0xb8, 0xcc, 0x32, 0x77, 0x41, 0xe3, 0x27, 0x09, 0xac, 0x98, 0xc9, 0xf2, 0x7a, 0x7e, 0x3c,
|
||||
0x5e, 0x5b, 0x68, 0x20, 0xf0, 0x7c, 0xc8, 0xc2, 0x7f, 0x94, 0xc8, 0x05, 0x91, 0xac, 0x2a, 0x0e, 0x98, 0xb1, 0xe0,
|
||||
0xb3, 0xee, 0xba, 0x6a, 0xa1, 0x92, 0x1a, 0xf3, 0x4f, 0xa0, 0x25, 0x2b, 0xa6, 0x92, 0xc3, 0xe3, 0x6d, 0x39, 0xb6,
|
||||
0x6a, 0x76, 0x79, 0xab, 0xa9, 0x8a, 0xc7, 0x02, 0x00, 0x15, 0x64, 0x5d, 0xdf, 0x92, 0x56, 0xea, 0x25, 0xb5, 0x2b,
|
||||
0x71, 0x39, 0x5a, 0x6d, 0x1c, 0xe9, 0x30, 0xe4, 0x0a, 0x05, 0x24, 0x8e, 0x92, 0xba, 0x90, 0x5f, 0x57, 0xb0, 0x20,
|
||||
0xb9, 0x10, 0xe3, 0x88, 0xa9, 0x14, 0x42, 0xe8, 0xe7, 0xa8, 0x09, 0xfa, 0x8c, 0x09, 0xdf, 0x01, 0x91, 0x38, 0xaf,
|
||||
0x71, 0x0b, 0x88, 0x46, 0x5f, 0x29, 0xe8, 0xb1, 0xa7, 0xe9, 0xf1, 0x54, 0xdf, 0x9d, 0xae, 0xca, 0xff, 0x21, 0x2f,
|
||||
0x80, 0xcc, 0xd9, 0xcc, 0x11, 0x09, 0x6d, 0x3a, 0x5f, 0x5d, 0x44, 0x4f, 0x75, 0x03, 0xc1, 0x95, 0x1f, 0x33, 0x40,
|
||||
0x90, 0x47, 0x54, 0xcf, 0xcf, 0x0e, 0xde, 0xac, 0xb5, 0xae, 0x11, 0x83, 0x05, 0x12, 0x57, 0x64, 0x2f, 0x32, 0x7a,
|
||||
0x86, 0x5c, 0x30, 0x86, 0xbe, 0x3b, 0x34, 0x7c, 0xbd, 0x89, 0x08, 0xbb, 0x0c, 0x63, 0x72, 0x2e, 0xc9, 0x4b, 0x55,
|
||||
0x36, 0x1f, 0xfc, 0x86, 0x56, 0x86, 0xed, 0x6f, 0xa1, 0xc0, 0xa7, 0x66, 0xe4, 0x8f, 0xc7, 0xcb, 0x93, 0x36, 0xd2,
|
||||
0xe4, 0x74, 0xb6, 0xbd, 0x78, 0x0d, 0xc5, 0x37, 0x2d, 0xcf, 0x8e, 0xbc, 0xa1, 0xff, 0x2c, 0x5a, 0x4b, 0x68, 0xe4,
|
||||
0x42, 0x10, 0xc2, 0x24, 0x0e, 0xa5, 0xe0, 0x3f, 0xd4, 0xa7, 0x9d, 0xe6, 0xee, 0x7b, 0x85, 0x66, 0x87, 0xe7, 0x42,
|
||||
0xa4, 0xe6, 0x6d, 0xcd, 0xd8, 0x7a, 0x6b, 0x50, 0x0c, 0xaa, 0xf4, 0xdd, 0x53, 0x59, 0x6c, 0xd1, 0xca, 0x3b, 0xe6,
|
||||
0x06, 0x50, 0xda, 0x3d, 0xbc, 0x05, 0x67, 0xf4, 0x45, 0x83, 0x41, 0xce, 0x72, 0xdf, 0x47, 0x2c, 0xc0, 0x5e, 0xde,
|
||||
0x2b, 0x42, 0xf7, 0xc1, 0x7a, 0x4e, 0x8d, 0x8b, 0xfc, 0xe7, 0xe9, 0x06, 0x21, 0xee, 0x79, 0x31, 0x04, 0x07, 0xca,
|
||||
0x13, 0x44, 0x4c, 0xc7, 0x42, 0xa4, 0xb4, 0xaf, 0x32, 0x62, 0x42, 0xd7, 0x3f, 0x58, 0xed, 0x25, 0x78, 0xd3, 0x52,
|
||||
0x48, 0x31, 0x36, 0x1c, 0xb8, 0x47, 0x4f, 0x2f, 0x71, 0x31, 0x75, 0x97, 0x6f, 0xcc, 0x66, 0x34, 0xe8, 0xe3, 0xe2,
|
||||
0x21, 0x4c, 0x7f, 0x06, 0xe9, 0xfd, 0xf4, 0x6a, 0x69, 0xce, 0xa8, 0xfa, 0x83, 0x3d, 0xa2, 0x95, 0x87, 0x70, 0xd6,
|
||||
0x67, 0x62, 0xf2, 0x33, 0x06, 0x84, 0x2a, 0x68, 0x4f, 0x93, 0x9f, 0x7a, 0xff, 0xd1, 0xee, 0x07, 0x10, 0x4d, 0x86,
|
||||
0x57, 0xda, 0xcd, 0x2a, 0x28, 0xe5, 0x77, 0x24, 0x36, 0x8f, 0x41, 0x4a, 0x8c, 0x62, 0x1e, 0xb2, 0x8d, 0x32, 0xe6,
|
||||
0x34, 0xc1, 0xf9, 0x01, 0xa4, 0x61, 0x73, 0xdb, 0xcc, 0xa1, 0x79, 0x08, 0x2c, 0xc0, 0x1f, 0x32, 0x71, 0xd0, 0x8c,
|
||||
0xc6, 0xb5, 0x45, 0x9c, 0x62, 0x7c, 0x40, 0x37, 0xfd, 0x6a, 0x99, 0x6f, 0xd4, 0xc6, 0xae, 0x5c, 0x18, 0xaf, 0xef,
|
||||
0xb7, 0x59, 0x20, 0x25, 0x39, 0xb0, 0xa5, 0x85, 0xb1, 0xaf, 0xda, 0x78, 0xe8, 0x09, 0xa9, 0x28, 0x34, 0x02, 0x3f,
|
||||
0xca, 0xde, 0x95, 0xd3, 0xae, 0x35, 0x67, 0x16, 0x08, 0x6f, 0x6e, 0x78, 0x7c, 0x43, 0x60, 0x21, 0x6b, 0x46, 0xde,
|
||||
0xaa, 0x00, 0x09, 0x5d, 0x9f, 0xf8, 0xf0, 0xd8, 0xb6, 0x35, 0xd1, 0x38, 0xcc, 0x02, 0x50, 0x7e, 0xa3, 0x24, 0xfd,
|
||||
0xb6, 0x5d, 0xa5, 0x2a, 0x9c, 0xb7, 0x60, 0x8d, 0x0b, 0x07, 0x4b, 0x9b, 0x29, 0xf4, 0x87, 0x9f, 0x54, 0xf7, 0x29,
|
||||
0x9c, 0xcb, 0x94, 0xc6, 0xe8, 0x1d, 0x59, 0xc1, 0x85, 0x52, 0x93, 0x54, 0x3e, 0xda, 0xd3, 0x5f, 0x86, 0x39, 0x24,
|
||||
0xf3, 0x10, 0x70, 0x09, 0x9e, 0x2d, 0x2a, 0x39, 0x74, 0xea, 0xac, 0x19, 0xe2, 0xe5, 0x79, 0xfd, 0x32, 0xf3, 0xc8,
|
||||
0x1f, 0xdd, 0x74, 0xa7, 0x5b, 0x94, 0x70, 0xeb, 0xb0, 0x0d, 0x7a, 0xde, 0x77, 0x8e, 0x41, 0xa8, 0x61, 0x3a, 0xf6,
|
||||
0x79, 0x32, 0x1e, 0x62, 0x7c, 0x3f, 0xfb, 0xc3, 0x7b, 0xa8, 0xd1, 0x6a, 0x52, 0x56, 0x30, 0x15, 0x15, 0xb3, 0x3e,
|
||||
0x0d, 0x01, 0x2c, 0x87, 0xff, 0x23, 0x68, 0x88, 0x9b, 0xca, 0x45, 0xf9, 0xee, 0xae, 0x97, 0xde, 0x80, 0xdd, 0x9f,
|
||||
0x4c, 0x2d, 0x69, 0x4d, 0xfc, 0xc3, 0xd3, 0x36, 0x91, 0x61, 0x36, 0x53, 0xa9, 0x8a, 0x33, 0x7f, 0xa5, 0x0c, 0xa0,
|
||||
0xaf, 0x39, 0x93, 0xef, 0xee, 0xb2, 0x0c, 0x60, 0x20, 0x0a, 0xbb, 0xe7, 0x73, 0xad, 0x1b, 0xdb, 0xa4, 0x09, 0x79,
|
||||
0x63, 0xf7, 0xd8, 0x4f, 0xa0, 0xf3, 0x2d, 0x61, 0x9a, 0xe1, 0x40, 0x99, 0xec, 0x03, 0xf9, 0xa3, 0x2f, 0x95, 0x3d,
|
||||
0x48, 0x28, 0x85, 0xfc, 0x8b, 0xb1, 0xf1, 0xf7, 0x86, 0x68, 0x64, 0x52, 0x01, 0x19, 0xd0, 0xdd, 0xd7, 0xec, 0x4b,
|
||||
0x22, 0x09, 0x4e, 0x8a, 0x2e, 0x9f, 0xa0, 0x1e, 0x20, 0x43, 0xa2, 0x70, 0x73, 0x9b, 0x9e, 0x7d, 0x0b, 0x69, 0x54,
|
||||
0x52, 0x01, 0x65, 0xa8, 0x47, 0x2e, 0xd6, 0x0e, 0xfb, 0x79, 0xf2, 0xb1, 0x13, 0xe1, 0xfb, 0x66, 0xb1, 0x49, 0x16,
|
||||
0x54, 0xb6, 0x07, 0xe9, 0x5f, 0xb8, 0x2a, 0xfc, 0x59, 0xc2, 0x8f, 0xcd, 0xe8, 0xce, 0xa3, 0xb0, 0x35, 0x03, 0xf5,
|
||||
0x6d, 0x59, 0xaf, 0x83, 0x98, 0x88, 0x03, 0xc0, 0xae, 0xfb, 0x90, 0x68, 0xf4, 0x9f, 0x85, 0x04, 0x10, 0x7f, 0xa5,
|
||||
0x3c, 0x64, 0xf2, 0x0b, 0xe0, 0x2e, 0x84, 0x9e, 0xb5, 0x60, 0xa5, 0x52, 0xff, 0x40, 0x14, 0x23, 0xd3, 0xc0, 0x09,
|
||||
0xd2, 0x19, 0x9b, 0x25, 0x5e, 0x63, 0x34, 0x1a, 0x41, 0x71, 0x2e, 0x1a, 0x70, 0x80, 0xca, 0x01, 0x10, 0x57, 0x04,
|
||||
0x41, 0xf8, 0x0f, 0x6d, 0x91, 0xea, 0xa5, 0xc7, 0x55, 0x91, 0x41, 0x62, 0xcc, 0x3a, 0x43, 0x39, 0xfb, 0x52, 0x13,
|
||||
0xcb, 0x5d, 0xa4, 0xa5, 0xbb, 0x47, 0x4f, 0xce, 0x27, 0x1d, 0x88, 0x4a, 0xc8, 0x37, 0x15, 0x89, 0xce, 0x90, 0x84,
|
||||
0x3e, 0x79, 0x34, 0x2f, 0xa5, 0x77, 0x68, 0xf1, 0x96, 0x01, 0x96, 0xa6, 0x4e, 0xb3, 0xff, 0x64, 0xf9, 0x2f, 0x1f,
|
||||
0x7b, 0xff, 0x72, 0xdf, 0x2d, 0x13, 0xf1, 0x7d, 0x2d, 0xfc, 0x7b, 0x3c, 0xd9, 0x21, 0xce, 0xcb, 0x37, 0xd7, 0xf6,
|
||||
0x76, 0xb1, 0x6b, 0x69, 0x0e, 0x90, 0xee, 0xe4, 0x99, 0x3a, 0xc3, 0x04, 0xba, 0x2b, 0xe9, 0xa3, 0xdf, 0xb5, 0x09,
|
||||
0xf8, 0x2c, 0x78, 0x3f, 0x6d, 0x2b, 0x9f, 0xa8, 0x3f, 0x30, 0xdf, 0xb0, 0xd8, 0x8d, 0x30, 0x19, 0xec, 0x7b, 0x4a,
|
||||
0xca, 0x55, 0xc3, 0xde, 0x5d, 0xaf, 0x2f, 0x99, 0x66, 0xb3, 0xb4, 0xda, 0x84, 0x54, 0x5c, 0x2d, 0x2a, 0x9b, 0xf5,
|
||||
0x8f, 0x2b, 0x43, 0x7c, 0x61, 0x07, 0x14, 0x46, 0x28, 0xf7, 0x00, 0xf4, 0x0a, 0xba, 0xff, 0x14, 0x08, 0x1e, 0xaa,
|
||||
0x97, 0xfc, 0x4d, 0x99, 0xf7, 0x52, 0xdd, 0x7e, 0x25, 0x86, 0x95, 0xfe, 0x33, 0x61, 0x00, 0x53, 0xc6, 0xf3, 0xb4,
|
||||
0xa2, 0x39, 0x4f, 0x5f, 0x1d, 0x92, 0x09, 0x96, 0xd8, 0x25, 0x70, 0x5e, 0x6c, 0x0a, 0x8c, 0x76, 0x4e, 0x40, 0xd6,
|
||||
0x6a, 0xed, 0x9e, 0xba, 0x59, 0x8d, 0x7d, 0xcd, 0x81, 0xe6, 0x27, 0xce, 0x8f, 0x7b, 0xfe, 0x5e, 0xa8, 0xbc, 0x6c,
|
||||
0x7f, 0x37, 0xdb, 0x8e, 0xce, 0x75, 0x6e, 0xa0, 0x80, 0xb9, 0xc9, 0x27, 0x1e, 0x85, 0x19, 0xe0, 0x00, 0x4c, 0x41,
|
||||
0x6b, 0x8b, 0x05, 0x74, 0xb7, 0x2a, 0x70, 0x97, 0x2c, 0x0d, 0x2b, 0x54, 0x9b, 0xa4, 0x74, 0xfe, 0xe7, 0xda, 0xbb,
|
||||
0x27, 0x70, 0x12, 0xef, 0x03, 0x43, 0xe2, 0x85, 0x7b, 0x02, 0x92, 0x48, 0x11, 0x94, 0x53, 0xe4, 0x76, 0x8d, 0x3f,
|
||||
0x30, 0xed, 0x5c, 0x15, 0x3e, 0x5d, 0x37, 0xb0, 0x24, 0x39, 0xc7, 0x4c, 0x89, 0x10, 0x93, 0x79, 0xef, 0xf3, 0x2d,
|
||||
0xdb, 0xc2, 0x8a, 0x00, 0x00, 0x00, 0xff, 0xff, 0x1b, 0xed, 0xbb, 0x8c, 0x8a, 0x8d, 0x8a, 0xe1, 0x16, 0x03, 0x00,
|
||||
};
|
||||
|
||||
static constexpr size_t WINDOW = 4096;
|
||||
static constexpr size_t PLAIN_SIZE = 16000;
|
||||
|
||||
@@ -223,18 +757,55 @@ static std::vector<uint8_t> build_plain() {
|
||||
return plain;
|
||||
}
|
||||
|
||||
// Text, incompressible noise that zlib stores, then text again
|
||||
static std::vector<uint8_t> build_mixed() {
|
||||
std::vector<uint8_t> plain;
|
||||
const char *text = "esphome ota deflate ";
|
||||
for (int i = 0; i < 60; i++)
|
||||
plain.insert(plain.end(), text, text + strlen(text));
|
||||
uint32_t x = 3;
|
||||
for (int i = 0; i < 3000; i++)
|
||||
plain.push_back(lcg_next(x));
|
||||
for (int i = 0; i < 40; i++)
|
||||
plain.insert(plain.end(), text, text + strlen(text));
|
||||
return plain;
|
||||
}
|
||||
|
||||
static std::vector<uint8_t> build_skewed() {
|
||||
std::vector<uint8_t> plain;
|
||||
const char *common = "etaoin ";
|
||||
uint32_t x = 7;
|
||||
for (int i = 0; i < 6000; i++) {
|
||||
uint8_t r = lcg_next(x);
|
||||
plain.push_back(r < 230 ? common[r % 7] : lcg_next(x));
|
||||
}
|
||||
return plain;
|
||||
}
|
||||
|
||||
// Mirrors the OTA session: chunked input through the read callback, window as output
|
||||
struct Session : OtaInflateState {
|
||||
const uint8_t *in;
|
||||
size_t in_len;
|
||||
size_t in_pos;
|
||||
size_t chunk;
|
||||
// Like the session where the ack follows the write: output is taken
|
||||
// before each read, up to dest
|
||||
bool flush_in_read;
|
||||
size_t flushed;
|
||||
std::vector<uint8_t> out;
|
||||
uint8_t window[WINDOW];
|
||||
};
|
||||
|
||||
static void take_output(Session &s) {
|
||||
const size_t produced = s.dest - s.window;
|
||||
s.out.insert(s.out.end(), s.window + s.flushed, s.window + produced);
|
||||
s.flushed = produced;
|
||||
}
|
||||
|
||||
static int read_cb(OtaInflateState *d) {
|
||||
auto *s = static_cast<Session *>(d);
|
||||
if (s->flush_in_read)
|
||||
take_output(*s);
|
||||
if (s->in_pos >= s->in_len)
|
||||
return -1;
|
||||
size_t n = std::min(s->chunk, s->in_len - s->in_pos);
|
||||
@@ -245,23 +816,26 @@ static int read_cb(OtaInflateState *d) {
|
||||
}
|
||||
|
||||
// Inflates the whole input; returns the decoder result and fills s.out
|
||||
static int inflate_all(Session &s, const uint8_t *in, size_t in_len, size_t chunk) {
|
||||
static int inflate_all(Session &s, const uint8_t *in, size_t in_len, size_t chunk, bool flush_in_read = false) {
|
||||
s.in = in;
|
||||
s.in_len = in_len;
|
||||
s.in_pos = 0;
|
||||
s.chunk = chunk;
|
||||
s.flush_in_read = flush_in_read;
|
||||
s.flushed = 0;
|
||||
s.out.clear();
|
||||
memset(s.window, 0, sizeof(s.window));
|
||||
ota_inflate_init(&s, s.window, WINDOW);
|
||||
s.source_read_cb = read_cb;
|
||||
int res;
|
||||
do {
|
||||
s.dest = s.window;
|
||||
s.dest_limit = s.window + WINDOW;
|
||||
// Starts the window over once the previous call filled it
|
||||
res = ota_inflate(&s);
|
||||
if (res < 0 || s.eof)
|
||||
return res < 0 ? res : OTA_INFLATE_DATA_ERROR;
|
||||
s.out.insert(s.out.end(), s.window, s.dest);
|
||||
take_output(s);
|
||||
// A full window is taken; the next call starts it over
|
||||
s.flushed = 0;
|
||||
if (s.out.size() > PLAIN_SIZE)
|
||||
return OTA_INFLATE_DATA_ERROR;
|
||||
} while (res != OTA_INFLATE_DONE);
|
||||
@@ -289,6 +863,36 @@ TEST(OtaInflate, StoredBlock) {
|
||||
EXPECT_EQ(s->out, plain);
|
||||
}
|
||||
|
||||
// Dynamic blocks, fixed Huffman blocks, codes longer than the lookup tables, and
|
||||
// stored blocks that start with read ahead bits in the bit buffer
|
||||
struct Stream {
|
||||
const uint8_t *data;
|
||||
size_t len;
|
||||
std::vector<uint8_t> (*plain)();
|
||||
};
|
||||
static const Stream STREAMS[] = {{DEFLATED, sizeof(DEFLATED), build_plain},
|
||||
{FIXED, sizeof(FIXED), build_plain},
|
||||
{SKEWED, sizeof(SKEWED), build_skewed},
|
||||
{MIXED, sizeof(MIXED), build_mixed}};
|
||||
|
||||
TEST(OtaInflate, EveryReadSizeGivesTheSameOutput) {
|
||||
// 1 byte reads never leave enough input for the fast loop, 11 to 13 straddle
|
||||
// its threshold, and the larger ones run it across read and window boundaries
|
||||
auto s = std::make_unique<Session>();
|
||||
for (const auto &stream : STREAMS) {
|
||||
const auto plain = stream.plain();
|
||||
for (bool flush_in_read : {false, true}) {
|
||||
for (size_t chunk : {size_t{1}, size_t{11}, size_t{12}, size_t{13}, size_t{300}, size_t{1040}, stream.len}) {
|
||||
ASSERT_EQ(inflate_all(*s, stream.data, stream.len, chunk, flush_in_read), OTA_INFLATE_DONE)
|
||||
<< "stream of " << stream.len << " B, read size " << chunk << ", flush in read " << flush_in_read;
|
||||
EXPECT_EQ(s->out, plain) << "stream of " << stream.len << " B, read size " << chunk << ", flush in read "
|
||||
<< flush_in_read;
|
||||
EXPECT_EQ(s->in_pos, stream.len);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(OtaInflate, TruncatedStreamFails) {
|
||||
auto s = std::make_unique<Session>();
|
||||
for (size_t cut : {size_t{1}, size_t{100}, size_t{1000}, sizeof(DEFLATED) - 1}) {
|
||||
@@ -305,12 +909,14 @@ TEST(OtaInflate, TruncatedStoredBlockFails) {
|
||||
TEST(OtaInflate, CorruptStreamsNeverEscapeTheWindow) {
|
||||
// Flipped bytes and garbage; the sanitizers check the decoder stays in bounds
|
||||
auto s = std::make_unique<Session>();
|
||||
std::vector<uint8_t> bad(DEFLATED, DEFLATED + sizeof(DEFLATED));
|
||||
// A coarse, non-aligned stride: neighbouring offsets hit the same paths
|
||||
for (size_t i = 0; i < bad.size(); i += 29) {
|
||||
bad[i] ^= 0x5a;
|
||||
inflate_all(*s, bad.data(), bad.size(), 1040);
|
||||
bad[i] ^= 0x5a;
|
||||
for (const auto &stream : STREAMS) {
|
||||
std::vector<uint8_t> bad(stream.data, stream.data + stream.len);
|
||||
// A coarse, non-aligned stride: neighbouring offsets hit the same paths
|
||||
for (size_t i = 0; i < bad.size(); i += 29) {
|
||||
bad[i] ^= 0x5a;
|
||||
inflate_all(*s, bad.data(), bad.size(), 1040);
|
||||
bad[i] ^= 0x5a;
|
||||
}
|
||||
}
|
||||
uint32_t x = 99;
|
||||
std::vector<uint8_t> garbage(2000);
|
||||
|
||||
@@ -17,7 +17,7 @@ class TestMicrophone : public Microphone {
|
||||
void start() override {}
|
||||
void stop() override {}
|
||||
|
||||
void publish(std::span<uint8_t> data, const audio::AudioStreamInfo &stream_info, int64_t capture_time_us) {
|
||||
void publish(std::span<const uint8_t> data, const audio::AudioStreamInfo &stream_info, int64_t capture_time_us) {
|
||||
this->publish_audio_(data, stream_info, capture_time_us);
|
||||
}
|
||||
bool has_callbacks() const { return this->has_data_callbacks_(); }
|
||||
@@ -56,24 +56,20 @@ TEST(MicrophoneDataCallbacks, CallbackGetsDataFormatAndCaptureTime) {
|
||||
});
|
||||
EXPECT_TRUE(mic.has_callbacks());
|
||||
|
||||
std::vector<uint8_t> buffer = SAMPLES;
|
||||
mic.publish(buffer, STEREO_48K, 123456);
|
||||
mic.publish(SAMPLES, STEREO_48K, 123456);
|
||||
EXPECT_EQ(data, SAMPLES);
|
||||
EXPECT_EQ(stream_info, STEREO_48K);
|
||||
EXPECT_EQ(capture_time_us, 123456);
|
||||
}
|
||||
|
||||
TEST(MicrophoneDataCallbacks, MuteZeroesTheBufferInPlace) {
|
||||
TEST(MicrophoneDataCallbacks, MutedCallbackGetsZeros) {
|
||||
TestMicrophone mic;
|
||||
std::vector<uint8_t> data;
|
||||
mic.add_data_callback([&](const AudioCapture &capture) { data.assign(capture.data.begin(), capture.data.end()); });
|
||||
|
||||
mic.set_mute_state(true);
|
||||
std::vector<uint8_t> buffer = SAMPLES;
|
||||
mic.publish(buffer, STEREO_48K, 0);
|
||||
const std::vector<uint8_t> zeros(SAMPLES.size(), 0);
|
||||
EXPECT_EQ(data, zeros);
|
||||
EXPECT_EQ(buffer, zeros);
|
||||
mic.publish(SAMPLES, STEREO_48K, 0);
|
||||
EXPECT_EQ(data, std::vector<uint8_t>(SAMPLES.size(), 0));
|
||||
}
|
||||
|
||||
TEST(MicrophoneDataCallbacks, DataTriggerPassesACopy) {
|
||||
@@ -119,17 +115,4 @@ TEST(MicrophoneDataCallbacks, DeprecatedCallUsesMicrophoneFormat) {
|
||||
EXPECT_EQ(capture_time_us, 0);
|
||||
}
|
||||
|
||||
// Remove in 2027.5.0 with the deprecated DataCallbackManager::call(data)
|
||||
TEST(MicrophoneDataCallbacks, DeprecatedCallDeliversZerosWhileMuted) {
|
||||
TestMicrophone mic;
|
||||
std::vector<uint8_t> data;
|
||||
mic.add_data_callback([&](const AudioCapture &capture) { data.assign(capture.data.begin(), capture.data.end()); });
|
||||
|
||||
mic.set_mute_state(true);
|
||||
const std::vector<uint8_t> buffer = SAMPLES;
|
||||
mic.publish_deprecated(buffer);
|
||||
EXPECT_EQ(data, std::vector<uint8_t>(SAMPLES.size(), 0));
|
||||
EXPECT_EQ(buffer, SAMPLES);
|
||||
}
|
||||
|
||||
} // namespace esphome::microphone::testing
|
||||
@@ -1,40 +0,0 @@
|
||||
packages:
|
||||
sendspin: !include common.yaml
|
||||
|
||||
microphone:
|
||||
- platform: i2s_audio
|
||||
id: sendspin_mic_id
|
||||
i2s_audio_id: i2s_audio_bus
|
||||
i2s_din_pin: ${i2s_din_pin}
|
||||
adc_type: external
|
||||
channel: stereo
|
||||
sample_rate: 48000
|
||||
bits_per_sample: 16bit
|
||||
|
||||
sendspin:
|
||||
source:
|
||||
microphone:
|
||||
microphone: sendspin_mic_id
|
||||
channels: [0, 1]
|
||||
bits_per_sample: 16
|
||||
gain_factor: 2
|
||||
task_stack_in_psram: true
|
||||
on_streaming_started:
|
||||
then:
|
||||
- logger.log: "Source streaming started"
|
||||
- sendspin.source.set_signal:
|
||||
present: true
|
||||
on_streaming_stopped:
|
||||
then:
|
||||
- logger.log: "Source streaming stopped"
|
||||
- sendspin.source.set_signal:
|
||||
present: !lambda return false;
|
||||
|
||||
interval:
|
||||
- interval: 10s
|
||||
then:
|
||||
- if:
|
||||
condition:
|
||||
sendspin.source.is_streaming:
|
||||
then:
|
||||
- logger.log: "Source is streaming"
|
||||
@@ -1,6 +0,0 @@
|
||||
substitutions:
|
||||
i2s_din_pin: GPIO39
|
||||
|
||||
packages:
|
||||
i2s_audio: !include ../../test_build_components/common/i2s_audio/esp32-idf.yaml
|
||||
sendspin: !include common-source.yaml
|
||||
@@ -1,21 +0,0 @@
|
||||
# The defaults, with a 24-bit mono source at 44.1 kHz
|
||||
substitutions:
|
||||
i2s_din_pin: GPIO39
|
||||
|
||||
packages:
|
||||
i2s_audio: !include ../../test_build_components/common/i2s_audio/esp32-idf.yaml
|
||||
sendspin: !include common.yaml
|
||||
|
||||
microphone:
|
||||
- platform: i2s_audio
|
||||
id: sendspin_mic_id
|
||||
i2s_audio_id: i2s_audio_bus
|
||||
i2s_din_pin: ${i2s_din_pin}
|
||||
adc_type: external
|
||||
sample_rate: 44100
|
||||
|
||||
sendspin:
|
||||
source:
|
||||
microphone:
|
||||
microphone: sendspin_mic_id
|
||||
bits_per_sample: 24
|
||||
@@ -7,9 +7,7 @@ audio_dac:
|
||||
enable_pin: GPIO12
|
||||
analog_gain: -15.5dB
|
||||
dac_mode: btl
|
||||
fault_output: adr
|
||||
mixer_mode: stereo
|
||||
modulation: 1SPW_MODE
|
||||
volume_min_db: -60dB
|
||||
volume_max_db: 0dB
|
||||
update_interval: 1s
|
||||
|
||||
@@ -9,4 +9,3 @@ audio_dac:
|
||||
dac_mode: PBTL
|
||||
mixer_mode: mono
|
||||
analog_gain: -3.5dB
|
||||
fault_output: none
|
||||
@@ -1,96 +0,0 @@
|
||||
esphome:
|
||||
name: uart-mock-ld2420-select-mode
|
||||
|
||||
host:
|
||||
api:
|
||||
batch_delay: 0ms # Disable batching to receive all state updates
|
||||
logger:
|
||||
level: VERBOSE
|
||||
|
||||
external_components:
|
||||
- source:
|
||||
type: local
|
||||
path: EXTERNAL_COMPONENT_PATH
|
||||
|
||||
# Dummy uart entry to satisfy ld2420's DEPENDENCIES = ["uart"]
|
||||
# The actual UART bus used is the uart_mock component below
|
||||
uart:
|
||||
baud_rate: 115200
|
||||
port: /dev/null
|
||||
|
||||
uart_mock:
|
||||
id: mock_uart
|
||||
baud_rate: 115200
|
||||
auto_start: false
|
||||
responses:
|
||||
# Firmware v2.0.0 (1.5.4 or newer), so setup picks energy reporting
|
||||
- expect_tx:
|
||||
[0xFD, 0xFC, 0xFB, 0xFA, 0x02, 0x00, 0x00, 0x00, 0x04, 0x03, 0x02, 0x01]
|
||||
inject_rx:
|
||||
[
|
||||
0xFD, 0xFC, 0xFB, 0xFA,
|
||||
0x0C, 0x00,
|
||||
0x00, 0x01,
|
||||
0x00, 0x00,
|
||||
0x06, 0x00,
|
||||
0x76, 0x32, 0x2E, 0x30, 0x2E, 0x30,
|
||||
0x04, 0x03, 0x02, 0x01,
|
||||
]
|
||||
|
||||
# Generic ACK for every other command
|
||||
- expect_tx: [0x04, 0x03, 0x02, 0x01]
|
||||
inject_rx:
|
||||
[
|
||||
0xFD, 0xFC, 0xFB, 0xFA,
|
||||
0x04, 0x00,
|
||||
0xFF, 0x01,
|
||||
0x00, 0x00,
|
||||
0x04, 0x03, 0x02, 0x01,
|
||||
]
|
||||
|
||||
injections:
|
||||
# Sent after the select switched the module to Simple: "ON Range 0035\r\n" is only
|
||||
# parsed while the component expects simple frames.
|
||||
- delay: 100ms
|
||||
inject_rx:
|
||||
[
|
||||
0x4F, 0x4E, 0x20, 0x52, 0x61, 0x6E, 0x67, 0x65, 0x20,
|
||||
0x30, 0x30, 0x33, 0x35,
|
||||
0x0D, 0x0A,
|
||||
]
|
||||
|
||||
button:
|
||||
- platform: template
|
||||
name: "Start Scenario"
|
||||
on_press:
|
||||
- lambda: 'id(mock_uart).start_scenario();'
|
||||
# A changed timeout gets apply_config_action() past its no-change check
|
||||
- platform: template
|
||||
name: "Apply Changed Config"
|
||||
on_press:
|
||||
- lambda: |-
|
||||
id(ld2420_dev).new_config.timeout++;
|
||||
id(ld2420_dev).apply_config_action();
|
||||
- platform: template
|
||||
name: "Inject Simple Frame"
|
||||
on_press:
|
||||
- lambda: |-
|
||||
// "ON Range 0040\r\n"
|
||||
id(mock_uart).inject_to_rx_buffer(std::vector<uint8_t>{
|
||||
0x4F, 0x4E, 0x20, 0x52, 0x61, 0x6E, 0x67, 0x65, 0x20, 0x30, 0x30, 0x34, 0x30, 0x0D, 0x0A});
|
||||
|
||||
ld2420:
|
||||
id: ld2420_dev
|
||||
uart_id: mock_uart
|
||||
|
||||
sensor:
|
||||
- platform: ld2420
|
||||
ld2420_id: ld2420_dev
|
||||
moving_distance:
|
||||
name: "Moving Distance"
|
||||
|
||||
select:
|
||||
- platform: ld2420
|
||||
ld2420_id: ld2420_dev
|
||||
operating_mode:
|
||||
name: "Operating Mode"
|
||||
@@ -1,73 +0,0 @@
|
||||
esphome:
|
||||
name: uart-mock-ld2420-mode-nack
|
||||
|
||||
host:
|
||||
api:
|
||||
batch_delay: 0ms # Disable batching to receive all state updates
|
||||
logger:
|
||||
level: VERBOSE
|
||||
|
||||
external_components:
|
||||
- source:
|
||||
type: local
|
||||
path: EXTERNAL_COMPONENT_PATH
|
||||
|
||||
# Dummy uart entry to satisfy ld2420's DEPENDENCIES = ["uart"]
|
||||
# The actual UART bus used is the uart_mock component below
|
||||
uart:
|
||||
baud_rate: 115200
|
||||
port: /dev/null
|
||||
|
||||
uart_mock:
|
||||
id: mock_uart
|
||||
baud_rate: 115200
|
||||
responses:
|
||||
# Firmware v2.0.0 (1.5.4 or newer), so setup picks energy reporting
|
||||
- expect_tx:
|
||||
[0xFD, 0xFC, 0xFB, 0xFA, 0x02, 0x00, 0x00, 0x00, 0x04, 0x03, 0x02, 0x01]
|
||||
inject_rx:
|
||||
[
|
||||
0xFD, 0xFC, 0xFB, 0xFA,
|
||||
0x0C, 0x00,
|
||||
0x00, 0x01,
|
||||
0x00, 0x00,
|
||||
0x06, 0x00,
|
||||
0x76, 0x32, 0x2E, 0x30, 0x2E, 0x30,
|
||||
0x04, 0x03, 0x02, 0x01,
|
||||
]
|
||||
|
||||
# The simple system mode write is refused (error word 1)
|
||||
- expect_tx:
|
||||
[
|
||||
0xFD, 0xFC, 0xFB, 0xFA, 0x08, 0x00, 0x12, 0x00,
|
||||
0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x04, 0x03, 0x02, 0x01,
|
||||
]
|
||||
inject_rx:
|
||||
[
|
||||
0xFD, 0xFC, 0xFB, 0xFA,
|
||||
0x04, 0x00,
|
||||
0x12, 0x01,
|
||||
0x01, 0x00,
|
||||
0x04, 0x03, 0x02, 0x01,
|
||||
]
|
||||
|
||||
# Generic ACK for every other command
|
||||
- expect_tx: [0x04, 0x03, 0x02, 0x01]
|
||||
inject_rx:
|
||||
[
|
||||
0xFD, 0xFC, 0xFB, 0xFA,
|
||||
0x04, 0x00,
|
||||
0xFF, 0x01,
|
||||
0x00, 0x00,
|
||||
0x04, 0x03, 0x02, 0x01,
|
||||
]
|
||||
|
||||
ld2420:
|
||||
id: ld2420_dev
|
||||
uart_id: mock_uart
|
||||
|
||||
select:
|
||||
- platform: ld2420
|
||||
ld2420_id: ld2420_dev
|
||||
operating_mode:
|
||||
name: "Operating Mode"
|
||||
@@ -1,128 +0,0 @@
|
||||
"""Integration test for the LD2420 operating mode select with a mock UART.
|
||||
|
||||
The module runs firmware v2.0.0, so it starts in energy reporting. Choosing Simple
|
||||
must write the simple system mode to the module and parse simple frames afterwards;
|
||||
choosing Normal again must write the energy system mode back.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import asyncio
|
||||
|
||||
from aioesphomeapi import ButtonInfo, EntityState, SelectInfo, SelectState
|
||||
import pytest
|
||||
|
||||
from .log_utils import LineWaiter
|
||||
from .state_utils import (
|
||||
SensorStateCollector,
|
||||
require_entity,
|
||||
subscribe_after_initial_states,
|
||||
)
|
||||
from .types import APIClientConnectedFactory, RunCompiledFunction
|
||||
from .wait_utils import wait_or_fail
|
||||
|
||||
# CMD_WRITE_SYS_PARAM (0x0012), parameter 0x0000 (system mode), then the mode and 0x0000
|
||||
WRITE_SIMPLE = "FD:FC:FB:FA:08:00:12:00:00:00:64:00:00:00:04:03:02:01"
|
||||
WRITE_ENERGY = "FD:FC:FB:FA:08:00:12:00:00:00:04:00:00:00:04:03:02:01"
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_uart_mock_ld2420_select_mode(
|
||||
yaml_config: str,
|
||||
run_compiled: RunCompiledFunction,
|
||||
api_client_connected: APIClientConnectedFactory,
|
||||
) -> None:
|
||||
"""The select switches the module between energy and simple reporting."""
|
||||
waiter = LineWaiter()
|
||||
collector = SensorStateCollector(sensor_names=["moving_distance"])
|
||||
simple_frame_parsed = collector.add_waiter(
|
||||
lambda: pytest.approx(35.0) in collector.sensor_states["moving_distance"]
|
||||
)
|
||||
second_frame_parsed = collector.add_waiter(
|
||||
lambda: pytest.approx(40.0) in collector.sensor_states["moving_distance"]
|
||||
)
|
||||
modes: list[str] = []
|
||||
back_to_normal = asyncio.Event()
|
||||
|
||||
def on_state(state: EntityState) -> None:
|
||||
collector.on_state(state)
|
||||
if isinstance(state, SelectState):
|
||||
modes.append(state.state)
|
||||
if modes[-2:] == ["Calibrate", "Normal"]:
|
||||
back_to_normal.set()
|
||||
|
||||
async with (
|
||||
run_compiled(yaml_config, line_callback=waiter.callback),
|
||||
api_client_connected() as client,
|
||||
):
|
||||
entities, _ = await client.list_entities_services()
|
||||
collector.build_key_mapping(entities)
|
||||
await subscribe_after_initial_states(client, entities, on_state=on_state)
|
||||
mode = require_entity(entities, "operating_mode", SelectInfo)
|
||||
apply_changed = require_entity(entities, "apply_changed_config", ButtonInfo)
|
||||
# Setup wrote energy mode for this firmware
|
||||
await waiter.wait_for("TX", WRITE_ENERGY)
|
||||
writes_before = waiter.count(WRITE_ENERGY)
|
||||
|
||||
client.select_command(mode.key, "Simple")
|
||||
await waiter.wait_for("TX", WRITE_SIMPLE)
|
||||
|
||||
client.button_command(
|
||||
require_entity(entities, "start_scenario", ButtonInfo).key
|
||||
)
|
||||
await wait_or_fail(simple_frame_parsed, 3.0, "Simple frame was not parsed")
|
||||
|
||||
# Applying a changed config in Simple keeps Simple
|
||||
client.button_command(apply_changed.key)
|
||||
await waiter.wait_for("Reconfiguring")
|
||||
inject = require_entity(entities, "inject_simple_frame", ButtonInfo)
|
||||
|
||||
async def inject_until_parsed() -> None:
|
||||
# Simple reports are rate limited, so keep sending until one is published
|
||||
while not second_frame_parsed.done():
|
||||
client.button_command(inject.key)
|
||||
await asyncio.sleep(0.2)
|
||||
|
||||
await wait_or_fail(inject_until_parsed(), 5.0, "Simple stopped after apply")
|
||||
assert modes[-1] == "Simple"
|
||||
|
||||
client.select_command(mode.key, "Normal")
|
||||
await waiter.wait_count(
|
||||
WRITE_ENERGY, writes_before + 1, 3.0, "Normal did not write energy mode"
|
||||
)
|
||||
assert waiter.count(WRITE_ENERGY) == writes_before + 1
|
||||
|
||||
# Applying a changed config ends calibration
|
||||
client.select_command(mode.key, "Calibrate")
|
||||
client.button_command(apply_changed.key)
|
||||
await wait_or_fail(back_to_normal, 5.0, "Apply did not end calibration")
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_uart_mock_ld2420_select_mode_nack(
|
||||
yaml_config: str,
|
||||
run_compiled: RunCompiledFunction,
|
||||
api_client_connected: APIClientConnectedFactory,
|
||||
) -> None:
|
||||
"""A refused Simple write puts the select back on the mode the module reports."""
|
||||
waiter = LineWaiter()
|
||||
states: list[str] = []
|
||||
back_to_normal = asyncio.Event()
|
||||
|
||||
def on_state(state: EntityState) -> None:
|
||||
if isinstance(state, SelectState):
|
||||
states.append(state.state)
|
||||
if states[-2:] == ["Simple", "Normal"]:
|
||||
back_to_normal.set()
|
||||
|
||||
async with (
|
||||
run_compiled(yaml_config, line_callback=waiter.callback),
|
||||
api_client_connected() as client,
|
||||
):
|
||||
entities, _ = await client.list_entities_services()
|
||||
await subscribe_after_initial_states(client, entities, on_state=on_state)
|
||||
mode = require_entity(entities, "operating_mode", SelectInfo)
|
||||
client.select_command(mode.key, "Simple")
|
||||
# Three tries of about a second each before the write is given up
|
||||
await wait_or_fail(back_to_normal, 6.0, "Select did not go back to Normal")
|
||||
assert waiter.count(WRITE_SIMPLE) == 3
|
||||
@@ -1,28 +0,0 @@
|
||||
"""Tests for the esp32 framework ``components:`` schema."""
|
||||
|
||||
import pytest
|
||||
|
||||
from esphome.components import esp32
|
||||
import esphome.config_validation as cv
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"source",
|
||||
[
|
||||
"https://github.com/owner/component.git",
|
||||
"git@github.com:owner/component.git",
|
||||
],
|
||||
)
|
||||
def test_component_source_accepts_repository_url(source: str) -> None:
|
||||
config = esp32.FRAMEWORK_SCHEMA(
|
||||
{"components": [{"name": "owner/component", "source": source}]}
|
||||
)
|
||||
assert config["components"][0]["source"] == source
|
||||
|
||||
|
||||
@pytest.mark.parametrize("source", [1.0, ""])
|
||||
def test_component_source_rejects_invalid(source: object) -> None:
|
||||
with pytest.raises(cv.Invalid):
|
||||
esp32.FRAMEWORK_SCHEMA(
|
||||
{"components": [{"name": "owner/component", "source": source}]}
|
||||
)
|
||||
@@ -3121,21 +3121,9 @@ def test_git_ref_valid() -> None:
|
||||
assert cv.git_ref("v1.2.3") == "v1.2.3"
|
||||
|
||||
|
||||
@pytest.mark.parametrize("ref", ["main", "release/v6.0", "feat+x", "a1b2c3d4"])
|
||||
def test_git_ref_valid_chars(ref: str) -> None:
|
||||
assert cv.git_ref(ref) == ref
|
||||
|
||||
|
||||
@pytest.mark.parametrize("ref", ["main hi there", "a:b", "x~1", "", "main\n"])
|
||||
def test_git_ref_invalid(ref: str) -> None:
|
||||
def test_git_ref_invalid() -> None:
|
||||
with pytest.raises(Invalid, match="Not a valid git ref"):
|
||||
cv.git_ref(ref)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("ref", [1.0, 2025, None])
|
||||
def test_git_ref_not_string(ref: object) -> None:
|
||||
with pytest.raises(Invalid, match="Must be string"):
|
||||
cv.git_ref(ref)
|
||||
cv.git_ref("!!!")
|
||||
|
||||
|
||||
def test_source_refresh_always() -> None:
|
||||
@@ -3303,34 +3291,6 @@ def test_validate_source_shorthand_github_pr(setup_core: Path) -> None:
|
||||
assert result[CONF_REF] == "pull/1234/head"
|
||||
|
||||
|
||||
def test_validate_source_shorthand_github_ref_with_slash(setup_core: Path) -> None:
|
||||
result = cv.validate_source_shorthand("github://user/repo@release/v1")
|
||||
assert result[CONF_REF] == "release/v1"
|
||||
|
||||
|
||||
def test_validate_source_shorthand_github_ref_keeps_all_chars(
|
||||
setup_core: Path,
|
||||
) -> None:
|
||||
result = cv.validate_source_shorthand("github://user/repo@feat+x")
|
||||
assert result[CONF_REF] == "feat+x"
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"value",
|
||||
[
|
||||
"github://esphome/esphome/esphome/components@dev",
|
||||
"github://user/repo/",
|
||||
"github://user/repo@main hi",
|
||||
"github://pr#1234abc",
|
||||
],
|
||||
)
|
||||
def test_validate_source_shorthand_rejects_trailing_text(
|
||||
setup_core: Path, value: str
|
||||
) -> None:
|
||||
with pytest.raises(Invalid, match="not a file system path"):
|
||||
cv.validate_source_shorthand(value)
|
||||
|
||||
|
||||
def test_validate_source_shorthand_invalid(setup_core: Path) -> None:
|
||||
with pytest.raises(Invalid, match="not a file system path"):
|
||||
cv.validate_source_shorthand("notvalid")
|
||||
|
||||
@@ -10,7 +10,6 @@ import threading
|
||||
import time
|
||||
from typing import Any
|
||||
from unittest.mock import Mock, patch
|
||||
import urllib.parse
|
||||
|
||||
from filelock import FileLock
|
||||
import pytest
|
||||
@@ -2098,48 +2097,6 @@ def test_recovery_reclone_keeps_credentials_and_cache_key(
|
||||
assert clone_url.count("@") == 1
|
||||
|
||||
|
||||
def test_clone_credentials_with_slash_are_escaped(
|
||||
tmp_path: Path, mock_run_git_command: Mock
|
||||
) -> None:
|
||||
"""A "/" in the username or password must be percent-encoded, or the
|
||||
userinfo ends at the "/" and git reports the password in its error."""
|
||||
CORE.config_path = tmp_path / "test.yaml"
|
||||
|
||||
url = "https://github.com/test/repo"
|
||||
domain = "test"
|
||||
repo_dir = _compute_repo_dir(url, None, domain)
|
||||
|
||||
def git_command_side_effect(
|
||||
cmd: list[str], cwd: str | None = None, **kwargs: Any
|
||||
) -> str:
|
||||
if _get_git_command_type(cmd) == "clone":
|
||||
_simulate_cloned_repo(repo_dir)
|
||||
return ""
|
||||
|
||||
mock_run_git_command.side_effect = git_command_side_effect
|
||||
|
||||
git.clone_or_update(
|
||||
url=url,
|
||||
ref=None,
|
||||
refresh=TimePeriodSeconds(days=1),
|
||||
domain=domain,
|
||||
username="team/user",
|
||||
password="ab/cd@ef",
|
||||
)
|
||||
|
||||
clone_cmds = [
|
||||
c[0][0]
|
||||
for c in mock_run_git_command.call_args_list
|
||||
if _get_git_command_type(c[0][0]) == "clone"
|
||||
]
|
||||
assert clone_cmds
|
||||
clone_url = clone_cmds[0][-2]
|
||||
assert clone_url == "https://team%2Fuser:ab%2Fcd%40ef@github.com/test/repo"
|
||||
assert urllib.parse.urlsplit(clone_url).hostname == "github.com"
|
||||
redacted = git._redact_url_credentials(f"fatal: unable to access '{clone_url}/'")
|
||||
assert redacted == "fatal: unable to access 'https://***@github.com/test/repo/'"
|
||||
|
||||
|
||||
def test_refresh_submodule_failure_recovers_then_raises(
|
||||
tmp_path: Path, mock_run_git_command: Mock
|
||||
) -> None:
|
||||
@@ -3332,26 +3289,6 @@ def test_git_file_from_shorthand_without_ref_or_query() -> None:
|
||||
assert gf == git.GitFile("codeberg.org", "owner", "repo", "file.yaml")
|
||||
|
||||
|
||||
def test_git_file_from_shorthand_keeps_whole_ref() -> None:
|
||||
gf = git.GitFile.from_shorthand("github://owner/repo/file.yaml@feat+x?full_config")
|
||||
|
||||
assert gf.ref == "feat+x"
|
||||
assert gf.query == "full_config"
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"shorthand",
|
||||
[
|
||||
"github://owner/repo/file.yaml@main hi",
|
||||
"github://owner/repo/my file.yaml",
|
||||
"github://owner/repo/file.yaml?full config",
|
||||
],
|
||||
)
|
||||
def test_git_file_from_shorthand_rejects_trailing_text(shorthand: str) -> None:
|
||||
with pytest.raises(ValueError, match="not in expected"):
|
||||
git.GitFile.from_shorthand(shorthand)
|
||||
|
||||
|
||||
def test_git_file_from_shorthand_requires_string() -> None:
|
||||
with pytest.raises(ValueError, match="must be a string"):
|
||||
git.GitFile.from_shorthand(123)
|
||||
|
||||
@@ -26,7 +26,6 @@ from esphome.loader import (
|
||||
clear_component_meta_finders,
|
||||
get_alias_metadata,
|
||||
get_component,
|
||||
get_platform,
|
||||
install_meta_finder,
|
||||
)
|
||||
from tests.testing_helpers import ComponentManifestOverride
|
||||
@@ -810,44 +809,6 @@ def test_lookup_module_import_error_missing_module_returns_none(
|
||||
assert "definitely_missing_component_xyz" not in _COMPONENT_CACHE
|
||||
|
||||
|
||||
def test_lookup_module_missing_platform_returns_none(
|
||||
caplog: pytest.LogCaptureFixture,
|
||||
) -> None:
|
||||
"""A platform file that does not exist is "not found", not an error."""
|
||||
with caplog.at_level(logging.INFO, logger="esphome.loader"):
|
||||
assert get_platform("definitely_missing_platform_xyz", "template") is None
|
||||
assert "Unable to import component template.definitely_missing_platform_xyz" in (
|
||||
caplog.text
|
||||
)
|
||||
assert not [r for r in caplog.records if r.levelno >= logging.ERROR]
|
||||
|
||||
|
||||
def test_lookup_module_missing_dependency_is_logged_as_error(
|
||||
tmp_path: Path, caplog: pytest.LogCaptureFixture
|
||||
) -> None:
|
||||
"""A component that exists but imports a missing package reports that
|
||||
package as an error, instead of looking like a missing component."""
|
||||
comp = tmp_path / "depfailcomp"
|
||||
comp.mkdir()
|
||||
(comp / "__init__.py").write_text("import definitely_missing_package_xyz\n")
|
||||
saved = list(sys.meta_path)
|
||||
try:
|
||||
install_meta_finder(tmp_path)
|
||||
with caplog.at_level(logging.INFO, logger="esphome.loader"):
|
||||
assert get_component("depfailcomp") is None
|
||||
finally:
|
||||
sys.meta_path[:] = saved
|
||||
for name in [
|
||||
m for m in sys.modules if m.startswith("esphome.components.depfailcomp")
|
||||
]:
|
||||
del sys.modules[name]
|
||||
errors = [r for r in caplog.records if r.levelno >= logging.ERROR]
|
||||
assert len(errors) == 1
|
||||
assert errors[0].getMessage() == "Unable to import component depfailcomp:"
|
||||
assert errors[0].exc_info is not None
|
||||
assert errors[0].exc_info[1].name == "definitely_missing_package_xyz"
|
||||
|
||||
|
||||
def test_lookup_module_missing_module_raises_when_requested() -> None:
|
||||
"""With ``exception=True`` the ImportError propagates."""
|
||||
with pytest.raises(ImportError):
|
||||
|
||||
Reference in new issue
Block a user