Share lossless voice prefixes across companion announcements
This commit is contained in:
1 parent
d4f88680e7
commit
f0828e025a
18 files changed
+2284
-2018
No files matched your search
@@ -346,7 +346,10 @@ jobs:
|
||||
python3 -B test/test_button_voice_generator.py -v
|
||||
python3 -B test/test_button_voice_preview.py -v
|
||||
python3 -B test/test_g726_voice.py -v
|
||||
MESH_G726_TEST_SANITIZERS=1 python3 -B test/test_g726_voice.py -v
|
||||
python3 -B test/test_g726_voice_generator.py -v
|
||||
python3 -B test/test_voice_prefixes.py -v
|
||||
MESH_VOICE_TEST_SANITIZERS=1 python3 -B test/test_voice_prefixes.py -v
|
||||
python3 -B test/test_nimble_companion.py
|
||||
python3 -B test/test_bluetooth_pairing_ui.py
|
||||
python3 -B test/test_companion_pairing_display.py
|
||||
|
||||
@@ -77,6 +77,24 @@ Power-on and wake wiring remain board-specific. Speech is nonblocking and uses
|
||||
the existing nRF52 PWM player; each buzzer still needs a physical listening
|
||||
test for intelligibility. All spoken button, alert-mode and GPS recordings use
|
||||
Microsoft Zira Desktop with the selected compressed Companion voice profile.
|
||||
GPS on/off use three stored audio spans: one shared encoded GPS prefix and two
|
||||
phrase tails. Advert queued/failed also share an identical encoded prefix;
|
||||
Sound off/Sound only share one only on `HAS_DRV2605` boards. The tails are not
|
||||
independently decodable words. Playback treats each prefix and tail as one
|
||||
continuous compressed stream, without resetting its codec, bit position,
|
||||
interpolation or DMA at the seam. The approved full-phrase PCM and PWM output
|
||||
remain bit-for-bit identical, including pronunciation and pauses.
|
||||
|
||||
The IMA audio payload is 3,881 bytes smaller on ordinary voice boards, or
|
||||
4,971 bytes smaller on vibration-equipped boards, before the small segmented
|
||||
descriptor/decoder overhead. Tiny shared silence prefixes are not split.
|
||||
A representative Cortex-M4 GCC 14.2 size-optimized/LTO player-and-catalog
|
||||
build saves 3,732 or 4,792 bytes respectively after that overhead; final
|
||||
firmware savings can vary with toolchain and surrounding code.
|
||||
The existing generators still synthesize the two complete GPS phrases and
|
||||
button confirmations, then share byte-identical encoded prefixes; they do not
|
||||
try to identify word boundaries or splice independently spoken words. Windows
|
||||
Zira synthesis still requires Windows' local `System.Speech` tooling.
|
||||
R1 Neo's buzzer pin aliases its optional QSPI clock, so voice is
|
||||
not default-enabled when `QSPIFLASH` is selected. ThinkNode M4 is deliberately
|
||||
excluded: its former
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
import argparse
|
||||
from pathlib import Path
|
||||
|
||||
from generate_gps_voice import encode, read
|
||||
from generate_gps_voice import encode, read, shared_prefix, emit_array
|
||||
|
||||
PHRASES = (
|
||||
('ready', 'Ready'),
|
||||
@@ -22,6 +22,64 @@ PHRASES = (
|
||||
('alertsSilent', 'Silent'),
|
||||
)
|
||||
|
||||
# Only meaningful byte-identical prefixes are shared. These retain the exact
|
||||
# approved phrase prosody; adaptive compressed tails are not standalone words.
|
||||
PREFIX_GROUPS = (
|
||||
('advertPrefix', 'advertQueued', 'advertFailed'),
|
||||
('soundPrefix', 'soundOff', 'alertsSoundOnly'),
|
||||
)
|
||||
|
||||
def split_catalog(encoded):
|
||||
tails = dict(encoded)
|
||||
prefixes = {}
|
||||
references = {}
|
||||
for prefix_name, first, second in PREFIX_GROUPS:
|
||||
prefix, one, two = shared_prefix(encoded[first], encoded[second])
|
||||
# Tiny shared silence does not justify additional metadata/storage.
|
||||
if len(prefix) < 64:
|
||||
continue
|
||||
prefixes[prefix_name] = prefix
|
||||
tails[first], tails[second] = one, two
|
||||
references[first] = references[second] = prefix_name
|
||||
return prefixes, tails, references
|
||||
|
||||
def emit_clip(lines, name, data, count, rate=8000, *, prefix=None, codec=None):
|
||||
emit_array(lines, name, data)
|
||||
fields = f' {name}Data, sizeof({name}Data), {count}, {rate}'
|
||||
if codec:
|
||||
fields += f', VoiceCodec::{codec}'
|
||||
if prefix:
|
||||
fields += f', {prefix}Data, sizeof({prefix}Data)'
|
||||
lines.extend([f'static constexpr VoiceClip {name}Clip = {{', fields, '};'])
|
||||
|
||||
def emit_catalog(lines, samples, encoded, *, codec=None):
|
||||
prefixes, tails, references = split_catalog(encoded)
|
||||
for prefix_name, data in prefixes.items():
|
||||
if prefix_name == 'soundPrefix':
|
||||
lines.append('#ifdef HAS_DRV2605')
|
||||
lines.append('// Shared encoded prefix; keep adaptive state at the seam.')
|
||||
emit_array(lines, prefix_name, data)
|
||||
if prefix_name == 'soundPrefix':
|
||||
lines.append('#endif // HAS_DRV2605')
|
||||
for name, phrase in PHRASES:
|
||||
if name == 'alertsSoundVibration':
|
||||
lines.append('#ifdef HAS_DRV2605')
|
||||
lines.append(f'// "{phrase}"')
|
||||
if name == 'soundOff' and name in references:
|
||||
# Non-vibration boards have no second consumer for this prefix.
|
||||
# Keep their original contiguous phrase, without extra span data.
|
||||
lines.append('#ifdef HAS_DRV2605')
|
||||
emit_clip(lines, name, tails[name], len(samples[name]),
|
||||
prefix=references[name], codec=codec)
|
||||
lines.append('#else')
|
||||
emit_clip(lines, name, encoded[name], len(samples[name]), codec=codec)
|
||||
lines.append('#endif // HAS_DRV2605')
|
||||
else:
|
||||
emit_clip(lines, name, tails[name], len(samples[name]),
|
||||
prefix=references.get(name), codec=codec)
|
||||
lines.append('#endif // HAS_DRV2605')
|
||||
return sum(map(len, prefixes.values()))
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
@@ -39,27 +97,21 @@ def main():
|
||||
]
|
||||
if args.voice is not None:
|
||||
lines.insert(2, f'// Voice: {args.voice}')
|
||||
total = 0
|
||||
samples_by_name = {}
|
||||
encoded_by_name = {}
|
||||
for name, phrase in PHRASES:
|
||||
samples = read(args.directory / (name + '.wav'))
|
||||
# Shutdown drains audio nonblockingly for at most five seconds.
|
||||
if not samples or len(samples) > 32000:
|
||||
raise ValueError(f'{phrase}: expected a nonempty clip under four seconds')
|
||||
encoded = encode(samples)
|
||||
total += len(encoded)
|
||||
if name == 'alertsSoundVibration':
|
||||
# Only buzzer+vibration devices need the additional mode catalog.
|
||||
lines.append('#ifdef HAS_DRV2605')
|
||||
lines.extend([f'// "{phrase}"', f'static const uint8_t {name}Data[] = {{'])
|
||||
for offset in range(0, len(encoded), 20):
|
||||
lines.append(' ' + ','.join(f'0x{b:02x}' for b in encoded[offset:offset + 20]) + ',')
|
||||
lines.extend(['};', f'static constexpr VoiceClip {name}Clip = {{',
|
||||
f' {name}Data, sizeof({name}Data), {len(samples)}, 8000', '};'])
|
||||
samples_by_name[name] = samples
|
||||
encoded_by_name[name] = encoded
|
||||
print(f'{phrase}: {len(samples) / 8000:.3f}s, {len(encoded)} bytes')
|
||||
lines.append('#endif // HAS_DRV2605')
|
||||
saved = emit_catalog(lines, samples_by_name, encoded_by_name)
|
||||
lines.append('}} // namespace mesh::audio')
|
||||
args.output.write_text('\n'.join(lines) + '\n', encoding='utf-8')
|
||||
print(f'Button confirmations: {total} audio bytes')
|
||||
print(f'Button confirmations: {sum(map(len, encoded_by_name.values())) - saved} audio bytes')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
@@ -10,8 +10,8 @@ import struct
|
||||
import subprocess
|
||||
from pathlib import Path
|
||||
|
||||
from generate_button_voice import PHRASES
|
||||
from generate_gps_voice import read
|
||||
from generate_button_voice import PHRASES, emit_catalog, emit_clip
|
||||
from generate_gps_voice import read, shared_prefix, emit_array
|
||||
|
||||
|
||||
def encode(samples, bitrate, ffmpeg="ffmpeg"):
|
||||
@@ -59,22 +59,21 @@ def main():
|
||||
]
|
||||
for bitrate in (16, 24):
|
||||
lines.append(f"#if MESH_GPS_VOICE_G726_BITRATE == {bitrate}")
|
||||
total = 0
|
||||
for name, phrase, pcm in samples:
|
||||
mode = name.startswith("alerts")
|
||||
if mode:
|
||||
lines.append("#ifdef HAS_DRV2605")
|
||||
data = encode(pcm, bitrate, args.ffmpeg)
|
||||
total += len(data)
|
||||
lines += [f'// "{phrase}"', f"static const uint8_t {name}Data[] = {{"]
|
||||
for offset in range(0, len(data), 20):
|
||||
lines.append(" " + ",".join(f"0x{b:02x}" for b in data[offset:offset + 20]) + ",")
|
||||
lines += ["};", f"static constexpr VoiceClip {name}Clip = {{",
|
||||
f" {name}Data, sizeof({name}Data), {len(pcm)}, 8000, VoiceCodec::G726{bitrate}", "};"]
|
||||
if mode:
|
||||
lines.append("#endif // HAS_DRV2605")
|
||||
pcm_by_name = {name: pcm for name, _, pcm in samples}
|
||||
encoded = {name: encode(pcm, bitrate, args.ffmpeg) for name, _, pcm in samples}
|
||||
saved = emit_catalog(lines, pcm_by_name, encoded, codec=f'G726{bitrate}')
|
||||
prefix, on, off = shared_prefix(encoded['gpsOn'], encoded['gpsOff'])
|
||||
if len(prefix) < 64:
|
||||
prefix, on, off = b'', encoded['gpsOn'], encoded['gpsOff']
|
||||
if prefix:
|
||||
lines.append('// GPS spans form one continuous stream, including cross-byte codes.')
|
||||
emit_array(lines, 'gps', prefix)
|
||||
for name, data in (('gpsOn', on), ('gpsOff', off)):
|
||||
emit_clip(lines, name, data, len(pcm_by_name[name]),
|
||||
prefix='gps' if prefix else None, codec=f'G726{bitrate}')
|
||||
lines.append(f"#endif // {bitrate} kbps")
|
||||
print(f"G.726-{bitrate}: {total} bytes across all 16 clips")
|
||||
total = sum(map(len, encoded.values())) - saved - len(prefix)
|
||||
print(f"G.726-{bitrate}: {total} bytes across all 16 phrases")
|
||||
lines.append("}} // namespace mesh::audio")
|
||||
args.output.write_text("\n".join(lines) + "\n", encoding="utf-8")
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Encode 8/16 kHz mono 16-bit WAV speech as independent IMA ADPCM clips."""
|
||||
"""Encode GPS phrases, sharing their identical encoded prefix without loss."""
|
||||
import argparse
|
||||
from pathlib import Path
|
||||
import struct
|
||||
@@ -41,6 +41,25 @@ def read(path, rate=8000):
|
||||
data = wav.readframes(wav.getnframes())
|
||||
return struct.unpack('<' + 'h' * (len(data)//2),data)
|
||||
|
||||
def shared_prefix(on, off):
|
||||
"""Return three spans whose concatenations exactly restore both streams.
|
||||
|
||||
A split is byte-based, not a word/codec boundary. Playback must preserve
|
||||
adaptive codec state and bit position at the seam. Leave a nonempty tail
|
||||
for both phrases, including identical or very short fixture recordings.
|
||||
"""
|
||||
limit = min(len(on), len(off)) - 1
|
||||
split = 0
|
||||
while split < limit and on[split] == off[split]:
|
||||
split += 1
|
||||
return on[:split], on[split:], off[split:]
|
||||
|
||||
def emit_array(lines, name, data):
|
||||
lines.append(f'static const uint8_t {name}Data[] = {{')
|
||||
for i in range(0,len(data),20):
|
||||
lines.append(' '+','.join(f'0x{b:02x}' for b in data[i:i+20])+',')
|
||||
lines.append('};')
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument('--on',type=Path,required=True)
|
||||
@@ -57,15 +76,25 @@ def main():
|
||||
'namespace mesh { namespace audio {']
|
||||
if args.voice is not None:
|
||||
lines.insert(2, f'// Voice: {args.voice}')
|
||||
for name,path in (('On',args.on),('Off',args.off)):
|
||||
samples = read(path,args.rate)
|
||||
encoded = encode(samples)
|
||||
lines.append(f'static const uint8_t gps{name}Data[] = {{')
|
||||
for i in range(0,len(encoded),20):
|
||||
lines.append(' '+','.join(f'0x{b:02x}' for b in encoded[i:i+20])+',')
|
||||
lines.extend(['};',f'static constexpr VoiceClip gps{name}Clip = {{',
|
||||
f' gps{name}Data, sizeof(gps{name}Data), {len(samples)}, {args.rate}', '};'])
|
||||
print(f'GPS {name.lower()}: {len(samples)/args.rate:.3f}s, {len(encoded)} bytes')
|
||||
phrases = [read(path,args.rate) for path in (args.on,args.off)]
|
||||
if any(not samples or len(samples) > args.rate * 4 for samples in phrases):
|
||||
raise ValueError('GPS phrases must be nonempty clips under four seconds')
|
||||
encoded = [encode(samples) for samples in phrases]
|
||||
prefix, on, off = shared_prefix(*encoded)
|
||||
if len(prefix) < 64:
|
||||
prefix, on, off = b'', *encoded
|
||||
if prefix:
|
||||
lines.append('// Three stored spans; preserve decoder state across the shared prefix.')
|
||||
emit_array(lines, 'gps', prefix)
|
||||
for name,samples,data in zip(('On','Off'),phrases,(on,off)):
|
||||
emit_array(lines, 'gps'+name, data)
|
||||
fields = f' gps{name}Data, sizeof(gps{name}Data), {len(samples)}, {args.rate}'
|
||||
if prefix:
|
||||
fields += ', gpsData, sizeof(gpsData)'
|
||||
lines.extend([f'static constexpr VoiceClip gps{name}Clip = {{',
|
||||
fields, '};'])
|
||||
print(f'GPS {name.lower()}: {len(samples)/args.rate:.3f}s, {len(data)} tail bytes')
|
||||
print(f'GPS shared prefix: {len(prefix)} bytes; audio saved: {len(prefix)} bytes')
|
||||
lines.append('}} // namespace mesh::audio')
|
||||
args.output.write_text('\n'.join(lines)+'\n',encoding='utf-8')
|
||||
|
||||
|
||||
+585
-523
File diff suppressed because it is too large.
Load diff
+1011
-1095
File diff suppressed because it is too large.
Load diff
+34
-12
@@ -22,18 +22,24 @@ enum class VoiceCodec : uint8_t { Ima, G72616, G72624 };
|
||||
#endif
|
||||
|
||||
// Low nibble first, independent IMA ADPCM stream starting at predictor/index 0.
|
||||
// An optional shared prefix and the data span form ONE encoded stream. Never
|
||||
// reset adaptive state between them: the spans can even divide a G.726 code.
|
||||
// The samples live in flash; playback only needs two small DMA buffers in RAM.
|
||||
struct VoiceClip {
|
||||
const uint8_t* data;
|
||||
size_t bytes;
|
||||
uint32_t samples;
|
||||
uint32_t sample_rate;
|
||||
const uint8_t* prefix;
|
||||
size_t prefix_bytes;
|
||||
#if defined(MESH_GPS_VOICE_G726_BITRATE)
|
||||
VoiceCodec codec;
|
||||
constexpr VoiceClip(const uint8_t* data = nullptr, size_t bytes = 0,
|
||||
uint32_t samples = 0, uint32_t sample_rate = 8000,
|
||||
VoiceCodec codec = VoiceCodec::Ima)
|
||||
: data(data), bytes(bytes), samples(samples), sample_rate(sample_rate), codec(codec) {}
|
||||
VoiceCodec codec = VoiceCodec::Ima,
|
||||
const uint8_t* prefix = nullptr, size_t prefix_bytes = 0)
|
||||
: data(data), bytes(bytes), samples(samples), sample_rate(sample_rate),
|
||||
prefix(prefix), prefix_bytes(prefix_bytes), codec(codec) {}
|
||||
unsigned bits() const {
|
||||
if (codec == VoiceCodec::Ima) return 4;
|
||||
#if MESH_GPS_VOICE_G726_BITRATE == 16
|
||||
@@ -50,15 +56,30 @@ struct VoiceClip {
|
||||
return (count / 8) * b + ((count % 8) * b + 7) / 8;
|
||||
}
|
||||
bool valid() const {
|
||||
return data && samples && bits() && bytes >= requiredBytes(samples)
|
||||
return data && (!prefix_bytes || prefix) && samples && bits()
|
||||
&& hasBytes(requiredBytes(samples))
|
||||
&& (codec == VoiceCodec::Ima ? (sample_rate == 8000 || sample_rate == 16000)
|
||||
: sample_rate == 8000);
|
||||
}
|
||||
#else
|
||||
constexpr VoiceClip(const uint8_t* data = nullptr, size_t bytes = 0,
|
||||
uint32_t samples = 0, uint32_t sample_rate = 8000)
|
||||
: data(data), bytes(bytes), samples(samples), sample_rate(sample_rate) {}
|
||||
uint32_t samples = 0, uint32_t sample_rate = 8000,
|
||||
const uint8_t* prefix = nullptr, size_t prefix_bytes = 0)
|
||||
: data(data), bytes(bytes), samples(samples), sample_rate(sample_rate),
|
||||
prefix(prefix), prefix_bytes(prefix_bytes) {}
|
||||
bool valid() const {
|
||||
return data && (!prefix_bytes || prefix) && samples
|
||||
&& hasBytes(samples / 2 + (samples & 1))
|
||||
&& (sample_rate == 8000 || sample_rate == 16000);
|
||||
}
|
||||
#endif
|
||||
// Subtract instead of adding the spans, so SIZE_MAX metadata cannot wrap.
|
||||
bool hasBytes(size_t count) const {
|
||||
return count <= prefix_bytes || count - prefix_bytes <= bytes;
|
||||
}
|
||||
uint8_t byteAt(size_t position) const {
|
||||
return position < prefix_bytes ? prefix[position] : data[position - prefix_bytes];
|
||||
}
|
||||
};
|
||||
|
||||
class VoiceDecoder {
|
||||
@@ -82,11 +103,12 @@ public:
|
||||
uint32_t position() const { return position_; }
|
||||
bool done() const {
|
||||
#if defined(MESH_GPS_VOICE_G726_BITRATE)
|
||||
return !clip_.data || !clip_.bits() || position_ >= clip_.samples
|
||||
|| clip_.requiredBytes(position_ + 1) > clip_.bytes;
|
||||
return !clip_.data || (clip_.prefix_bytes && !clip_.prefix) || !clip_.bits()
|
||||
|| position_ >= clip_.samples
|
||||
|| !clip_.hasBytes(clip_.requiredBytes(position_ + 1));
|
||||
#else
|
||||
return !clip_.data || position_ >= clip_.samples
|
||||
|| position_ / 2 >= clip_.bytes;
|
||||
return !clip_.data || (clip_.prefix_bytes && !clip_.prefix)
|
||||
|| position_ >= clip_.samples || !clip_.hasBytes(position_ / 2 + 1);
|
||||
#endif
|
||||
}
|
||||
int16_t next() {
|
||||
@@ -105,17 +127,17 @@ public:
|
||||
const unsigned bits = clip_.bits();
|
||||
const unsigned bit = ((position_ % 8) * bits) % 8;
|
||||
const size_t byte = (position_ / 8) * bits + ((position_ % 8) * bits) / 8;
|
||||
unsigned word = clip_.data[byte];
|
||||
unsigned word = clip_.byteAt(byte);
|
||||
unsigned shift;
|
||||
if (bit + bits > 8) {
|
||||
word = (word << 8) | clip_.data[byte + 1];
|
||||
word = (word << 8) | clip_.byteAt(byte + 1);
|
||||
shift = 16 - bit - bits;
|
||||
} else shift = 8 - bit - bits;
|
||||
++position_;
|
||||
return g726_decode(&g726_, (word >> shift) & ((1u << bits) - 1), bits);
|
||||
}
|
||||
#endif
|
||||
const uint8_t code = (clip_.data[position_ / 2]
|
||||
const uint8_t code = (clip_.byteAt(position_ / 2)
|
||||
>> ((position_ & 1) * 4)) & 15;
|
||||
++position_;
|
||||
const int32_t step = steps[index_];
|
||||
|
||||
+153
-306
@@ -4,7 +4,8 @@
|
||||
#pragma once
|
||||
#include <helpers/ui/GpsVoice.h>
|
||||
namespace mesh { namespace audio {
|
||||
static const uint8_t gpsOnData[] = {
|
||||
// Three stored spans; preserve decoder state across the shared prefix.
|
||||
static const uint8_t gpsData[] = {
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x70,
|
||||
0x7f,0xf7,0xf7,0x61,0x5c,0x8b,0xd1,0x04,0x4a,0x8c,0xb3,0x83,0x90,0x98,0x91,0x22,0x2d,0x89,0x28,0xd1,
|
||||
0xa3,0x20,0x0a,0x80,0xf1,0xb7,0x01,0x5d,0x1a,0x88,0x91,0x18,0x2a,0xa0,0xb5,0x81,0x38,0x2c,0x88,0x2b,
|
||||
@@ -161,84 +162,86 @@ static const uint8_t gpsOnData[] = {
|
||||
0xc9,0x10,0x08,0x16,0x9e,0x22,0x1c,0xb3,0x0b,0x10,0x78,0x98,0x88,0x88,0x00,0x87,0x0c,0x81,0x19,0xc4,
|
||||
0x08,0x20,0x3c,0xa8,0xe2,0x93,0x11,0x3b,0x0c,0x82,0xa1,0xb2,0x2b,0x79,0x89,0xf2,0x82,0x18,0x88,0x11,
|
||||
0x1b,0x20,0x9e,0x94,0x09,0x01,0x2c,0x90,0x13,0xf0,0x48,0x80,0x29,0x0b,0x4b,0xd1,0x10,0xb0,0x7e,0xa0,
|
||||
0x80,0xd3,0x10,0x82,0x4c,0x89,0xa0,0xb3,0x92,0x08,0x38,0x8b,0xf5,0x01,0x92,0x19,0x8b,0x86,0x91,0x1b,
|
||||
0x38,0x6a,0x8a,0x99,0xa4,0x20,0x08,0x0f,0xa5,0x88,0xa3,0x1c,0x34,0x1f,0x08,0x09,0x92,0xc0,0x02,0x1a,
|
||||
0x80,0xb3,0x28,0x39,0x0f,0xa2,0x08,0x82,0x2c,0xa1,0x13,0xf0,0x40,0x9a,0x95,0x98,0x18,0x80,0x3b,0x3f,
|
||||
0x4b,0xb1,0x91,0x11,0x4f,0x19,0x99,0x92,0x98,0x13,0x2b,0x7c,0x1c,0x28,0x9a,0xb4,0x28,0x41,0x0f,0x81,
|
||||
0xb0,0x84,0x9a,0x52,0x0d,0x10,0x88,0x11,0xd8,0x20,0xb0,0x10,0xe3,0x28,0x92,0x4c,0x2b,0xa9,0x94,0x49,
|
||||
0x90,0x88,0xe4,0x28,0x88,0x18,0xb0,0x02,0x48,0x80,0x0f,0x12,0x19,0xa8,0x0e,0x80,0x15,0xca,0x41,0x08,
|
||||
0x3a,0xb9,0x2e,0xa5,0x09,0x80,0x08,0x24,0xcb,0x85,0x8c,0x22,0xb0,0x1a,0x84,0x2f,0x12,0x9d,0x92,0x18,
|
||||
0x86,0x0a,0xa8,0x4c,0x83,0x8a,0xc1,0x38,0x22,0x9b,0xca,0xa2,0x07,0x09,0x3b,0x88,0x13,0xf8,0x1b,0x95,
|
||||
0x01,0x80,0x99,0x88,0x7b,0x39,0xb8,0xb2,0xb5,0x5d,0x28,0x1b,0xc1,0xc4,0x02,0x2b,0x59,0xc9,0x82,0xc3,
|
||||
0x49,0x89,0x4b,0xe3,0x91,0x83,0x19,0x10,0x0e,0x81,0xa9,0x24,0xc8,0x28,0x98,0x5c,0x00,0xa8,0xa3,0x18,
|
||||
0x30,0x8b,0xba,0x3b,0x96,0x94,0x81,0x99,0xb9,0x05,0x68,0x8a,0x99,0xa8,0x63,0x01,0x2a,0xf9,0x92,0xa4,
|
||||
0x4b,0x1a,0x0b,0x97,0x90,0x88,0x3b,0x60,0xc1,0x90,0xa4,0x29,0x20,0x8e,0x03,0xc0,0x99,0x28,0x38,0x89,
|
||||
0x02,0x05,0x20,0x00,0xb8,0xab,0x00,0xef,0x11,0xb8,0x49,0x89,0x1c,0x15,0x00,0x12,0xa8,0x70,0xa1,0xbb,
|
||||
0xa1,0xac,0x59,0x00,0x18,0x84,0x89,0x30,0x98,0x11,0x84,0x1a,0x09,0xbc,0xa1,0x77,0x90,0x9d,0xa8,0xa8,
|
||||
0x42,0x20,0x10,0x92,0xa8,0x30,0x18,0x30,0x94,0xca,0x98,0x9c,0x2b,0x77,0xb0,0x8d,0x99,0x89,0x24,0x12,
|
||||
0x28,0x90,0xba,0x14,0x02,0x50,0x88,0xcb,0xa0,0xa8,0x7a,0x17,0xda,0x89,0x98,0x39,0x33,0xa2,0x01,0xa9,
|
||||
0x0c,0x33,0x83,0x14,0xa8,0x9f,0x88,0xa0,0x74,0x84,0xbc,0x8a,0x9a,0x48,0x24,0x80,0x80,0xb8,0x19,0x34,
|
||||
0x11,0x11,0xf9,0x9a,0x00,0x88,0x73,0x87,0xdb,0x98,0x88,0x30,0x32,0x88,0x98,0xb8,0x38,0x45,0x00,0x88,
|
||||
0xc9,0x9a,0x30,0x18,0x71,0x87,0xcc,0x89,0x08,0x20,0x24,0xa8,0x88,0x09,0x39,0x16,0xa2,0x88,0x9b,0x0c,
|
||||
0x21,0x92,0x70,0x87,0xcd,0x88,0x01,0x28,0x22,0xa8,0x99,0x81,0x20,0x44,0x90,0xa9,0xa9,0x89,0x32,0x82,
|
||||
0x7a,0x07,0xce,0x09,0x01,0x28,0x22,0xc0,0x89,0x20,0x28,0x33,0xc2,0xca,0x08,0x19,0x30,0xa2,0x3c,0x67,
|
||||
0xeb,0x8b,0x12,0x80,0x22,0xa2,0xbb,0x21,0x22,0x32,0x94,0xbc,0x8b,0x01,0x13,0x92,0xbc,0x77,0xd1,0x9e,
|
||||
0x11,0x81,0x28,0x01,0xaa,0x19,0x23,0x11,0x01,0xca,0x9b,0x38,0x22,0x80,0xeb,0x7a,0x17,0xec,0x09,0x12,
|
||||
0x88,0x21,0x90,0xab,0x31,0x23,0x80,0x89,0xab,0x8b,0x15,0x84,0x8a,0x8c,0x71,0x97,0xcd,0x10,0x02,0x88,
|
||||
0x11,0xa0,0xaa,0x52,0x21,0x0a,0x8a,0xb0,0x90,0x43,0x00,0xad,0xa9,0x77,0xb1,0x9e,0x10,0x82,0x08,0x11,
|
||||
0xa8,0x0c,0x41,0x82,0xa8,0x08,0x09,0x8a,0x14,0xa3,0xac,0x2b,0x77,0xb0,0x9e,0x20,0x01,0x09,0x11,0xa0,
|
||||
0x8c,0x41,0x03,0xa9,0x89,0x80,0x99,0x42,0x93,0xcc,0x0a,0x75,0x92,0xbf,0x28,0x12,0x89,0x20,0x91,0xcb,
|
||||
0x40,0x23,0xa8,0x9b,0x82,0xb0,0x20,0x25,0xca,0x9c,0x21,0x67,0xc0,0xac,0x20,0x02,0x90,0x11,0x98,0x9c,
|
||||
0x41,0x04,0xb0,0x99,0x01,0x09,0x39,0x13,0xfa,0x9a,0x41,0x46,0xb8,0xbf,0x20,0x12,0x88,0x10,0x88,0x9c,
|
||||
0x40,0x04,0xa0,0x9a,0x10,0x08,0x08,0x13,0xd9,0x9c,0x21,0x76,0x91,0xbe,0x19,0x13,0x81,0x09,0x00,0xb9,
|
||||
0x29,0x36,0x91,0xbb,0x08,0x02,0x88,0x30,0xa0,0xce,0x18,0x53,0x27,0xf9,0x9b,0x30,0x12,0x98,0x08,0x90,
|
||||
0xa9,0x61,0x23,0xb9,0x9c,0x11,0x11,0x89,0x10,0xc8,0xbb,0x50,0x52,0x17,0xf8,0xab,0x30,0x23,0xa8,0x09,
|
||||
0x80,0x98,0x40,0x34,0xb8,0xad,0x20,0x83,0xa0,0x08,0x90,0xac,0x08,0x24,0x77,0xa1,0xbf,0x18,0x23,0x91,
|
||||
0x8a,0x18,0x88,0x09,0x35,0x92,0xbc,0x1a,0x33,0xa1,0xa9,0x10,0xca,0x8c,0x73,0x21,0x16,0xf8,0xad,0x20,
|
||||
0x23,0xa0,0x8a,0x00,0x80,0x28,0x25,0xb1,0xbc,0x28,0x24,0x98,0x8a,0x08,0xaa,0x1a,0x34,0xb2,0x70,0x27,
|
||||
0xee,0x89,0x32,0x82,0x9a,0x19,0x01,0x89,0x41,0x13,0xca,0x8c,0x31,0x83,0xb9,0x09,0x80,0xbb,0x38,0x16,
|
||||
0xb8,0x77,0xa1,0xbf,0x29,0x33,0x90,0x9a,0x20,0x90,0x09,0x44,0x82,0xbc,0x2a,0x43,0xa0,0x9a,0x10,0xa9,
|
||||
0x8c,0x41,0x82,0xdb,0x71,0x07,0xcc,0x0a,0x33,0x81,0x8b,0x28,0x91,0xaa,0x73,0x12,0xba,0x8b,0x32,0x92,
|
||||
0x9a,0x38,0xa9,0xaf,0x11,0x04,0xb8,0x3b,0x77,0xd1,0xac,0x30,0x13,0xa8,0x09,0x01,0xa9,0x38,0x27,0xa0,
|
||||
0xbb,0x20,0x23,0x99,0x1a,0x80,0xbd,0x1a,0x53,0x90,0xbb,0x69,0x77,0xc8,0x9c,0x30,0x02,0x98,0x18,0x81,
|
||||
0xaa,0x48,0x34,0xb0,0xbb,0x30,0x11,0xa9,0x01,0xc3,0xcc,0x2a,0x32,0xa8,0xb9,0x83,0x77,0x87,0xcc,0x1a,
|
||||
0x22,0x81,0x89,0x01,0xa8,0x0a,0x35,0x84,0xba,0x0a,0x12,0xa1,0x00,0x21,0xbe,0x8c,0x22,0x83,0xba,0x09,
|
||||
0x00,0x78,0x77,0xd9,0x8b,0x31,0x02,0x99,0x01,0xa0,0x8b,0x71,0x22,0xc8,0xa9,0x11,0x01,0x09,0x20,0xc9,
|
||||
0xcb,0x11,0x04,0x98,0x8a,0x00,0x98,0x77,0x97,0xad,0x18,0x12,0x90,0x08,0x01,0xb9,0x19,0x36,0x91,0xab,
|
||||
0x18,0x82,0x99,0x21,0x92,0xce,0x1a,0x32,0x88,0x9b,0x00,0xb1,0x39,0x77,0x97,0xaf,0x10,0x12,0x88,0x18,
|
||||
0x80,0xab,0x48,0x34,0xa0,0xab,0x20,0x80,0x09,0x42,0xb0,0xaf,0x08,0x11,0x01,0x80,0x99,0xab,0x38,0x74,
|
||||
0x67,0xd9,0x9b,0x31,0x01,0x88,0x11,0xc8,0x9a,0x62,0x12,0xa9,0x89,0x81,0x98,0x31,0x13,0xfb,0x9a,0x11,
|
||||
0x81,0x19,0x29,0xcb,0xaa,0x34,0x73,0x47,0xf9,0x8b,0x21,0x81,0x18,0x10,0xb9,0x8c,0x62,0x02,0x99,0x88,
|
||||
0x90,0x98,0x32,0x04,0xbc,0x9a,0x11,0x88,0x28,0x20,0xbe,0x99,0x05,0x92,0x76,0x94,0xbe,0x08,0x03,0x08,
|
||||
0x30,0x98,0xdb,0x20,0x24,0x80,0x1a,0x98,0xd8,0x11,0x23,0xa9,0x9c,0x88,0xa8,0x30,0x12,0xcb,0xaa,0x02,
|
||||
0x13,0x12,0x77,0x27,0xcf,0x18,0x81,0x00,0x21,0x98,0x9c,0x20,0x23,0x81,0x08,0xaa,0x9b,0x42,0x03,0xa9,
|
||||
0xaa,0xac,0x0a,0x23,0x92,0xab,0x0f,0x19,0x20,0x05,0x72,0x77,0xdb,0x09,0x81,0x18,0x31,0xa0,0x9c,0x10,
|
||||
0x12,0x31,0x02,0xbb,0x9b,0x22,0x31,0x39,0xcc,0xfa,0x90,0x01,0x38,0x09,0xbc,0xa0,0x83,0x42,0x11,0x77,
|
||||
0x87,0xad,0x08,0x90,0x20,0x14,0xaa,0x89,0x01,0x11,0x34,0x88,0x9c,0x88,0x92,0x12,0x10,0x8f,0x8a,0x88,
|
||||
0x80,0x92,0xa0,0x8a,0x09,0x82,0x87,0xa3,0x77,0x87,0xad,0x80,0xa0,0x31,0x03,0x9b,0x09,0xb1,0x42,0x25,
|
||||
0x0a,0x0a,0xa8,0x80,0x05,0x98,0x98,0xaa,0x8a,0x11,0x80,0x0a,0xbc,0x1c,0x43,0x01,0x85,0x73,0x67,0xdb,
|
||||
0x88,0x99,0x38,0x23,0xa9,0x81,0xc8,0x40,0x33,0x09,0x80,0xd1,0x8a,0x13,0x3a,0x3a,0xfb,0xb0,0x92,0x08,
|
||||
0x38,0x8b,0x8b,0xc3,0xa3,0x25,0x29,0x77,0xa7,0x0c,0xa9,0x8a,0x24,0x91,0x10,0x88,0x1d,0x22,0x91,0x12,
|
||||
0xb1,0x0c,0x21,0x9b,0x12,0xf1,0x8a,0x81,0x8a,0x48,0xb8,0xa0,0x96,0x80,0x30,0x99,0x78,0x77,0x99,0x98,
|
||||
0xac,0x19,0x80,0x29,0x11,0x89,0x43,0x03,0x42,0x12,0x8a,0x20,0xd8,0x88,0xb0,0x9d,0x89,0xbb,0x09,0xc0,
|
||||
0x80,0x14,0x49,0x78,0x18,0x20,0x77,0x92,0x09,0xdb,0xab,0x90,0x9a,0x10,0x80,0x40,0x24,0x31,0x25,0x02,
|
||||
0x22,0x91,0xa9,0xb8,0xaf,0x9b,0xdb,0xa9,0xa0,0x09,0x30,0x31,0x42,0x24,0x33,0x75,0x17,0x08,0xa0,0xcb,
|
||||
0x9a,0xbb,0x9b,0xa8,0x98,0x43,0x31,0x73,0x23,0x32,0x15,0x01,0x21,0x99,0x9b,0xcb,0xcd,0xb8,0xba,0x8b,
|
||||
0x8b,0x1b,0x11,0x03,0x47,0x77,0x00,0x10,0x99,0xaa,0xc0,0xaa,0x89,0x9a,0x29,0x81,0x22,0x17,0x22,0x52,
|
||||
0x20,0x20,0x82,0xa1,0x81,0xac,0x9b,0xbd,0xcb,0xb9,0xbb,0x89,0x8b,0x81,0x77,0x17,0x18,0x01,0xbb,0x89,
|
||||
0xcc,0x8a,0xa8,0x1a,0x21,0x20,0x36,0x13,0x43,0x14,0x20,0x21,0x98,0x90,0xe9,0x9a,0xcb,0x9c,0xaa,0xbb,
|
||||
0x99,0xb8,0x21,0x79,0x77,0x11,0x01,0xba,0x8a,0xcc,0xaa,0x98,0x0a,0x32,0x20,0x27,0x13,0x52,0x21,0x10,
|
||||
0x01,0x98,0x98,0xcb,0x9c,0xca,0xba,0xb9,0x9b,0x0a,0x0b,0x10,0x45,0x77,0x13,0x21,0xca,0xab,0xea,0x9b,
|
||||
0x99,0x9a,0x22,0x11,0x45,0x23,0x52,0x22,0x20,0x02,0xa0,0x90,0xdb,0xab,0xdb,0xab,0xb9,0xba,0x80,0x98,
|
||||
0x58,0x20,0x77,0x05,0x11,0xb9,0xaa,0xea,0x9b,0x99,0x8a,0x21,0x11,0x45,0x23,0x52,0x12,0x11,0x02,0x98,
|
||||
0x88,0xbb,0xad,0xda,0xaa,0xb9,0x8c,0x89,0x9a,0x01,0x70,0x77,0x18,0x01,0xaa,0x99,0xdb,0x9a,0x99,0x0a,
|
||||
0x02,0x21,0x37,0x21,0x43,0x02,0x22,0x82,0x09,0x98,0xad,0xaa,0x9c,0xba,0xba,0xbb,0xae,0xa9,0xb9,0x77,
|
||||
0x03,0x21,0xb1,0xab,0xe9,0x9d,0x98,0x9a,0x11,0x02,0x72,0x12,0x32,0x23,0x11,0x13,0x90,0x18,0xbc,0xac,
|
||||
0xda,0xbb,0xa9,0x9d,0x99,0xa9,0x10,0x79,0x57,0x10,0x01,0xba,0x9a,0xec,0x99,0xa9,0x09,0x01,0x20,0x35,
|
||||
0x22,0x35,0x12,0x32,0x82,0x00,0xa0,0xac,0xb9,0xae,0x9a,0xcb,0x09,0xa9,0x09,0x00,0x77,0x13,0x21,0xca,
|
||||
0xaa,0xfb,0x9b,0x9a,0x9b,0x00,0x11,0x54,0x22,0x53,0x13,0x32,0x13,0x00,0x02,0x9b,0xa9,0xfb,0x9a,0xbb,
|
||||
0x9d,0x1a,0x80,0x80,0x08,0x80,0x08,0x80,0x08,0x80,0x08,0x80,0x08,0x80,0x08,0x08,0x08,0x08,0x80,0x80,
|
||||
0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x80,0xd3,0x10,0x82,0x4c,0x89,0xa0,0xb3,0x92,0x08,0x38,0x8b,0xf5,0x01,0x92,
|
||||
};
|
||||
static const uint8_t gpsOnData[] = {
|
||||
0x19,0x8b,0x86,0x91,0x1b,0x38,0x6a,0x8a,0x99,0xa4,0x20,0x08,0x0f,0xa5,0x88,0xa3,0x1c,0x34,0x1f,0x08,
|
||||
0x09,0x92,0xc0,0x02,0x1a,0x80,0xb3,0x28,0x39,0x0f,0xa2,0x08,0x82,0x2c,0xa1,0x13,0xf0,0x40,0x9a,0x95,
|
||||
0x98,0x18,0x80,0x3b,0x3f,0x4b,0xb1,0x91,0x11,0x4f,0x19,0x99,0x92,0x98,0x13,0x2b,0x7c,0x1c,0x28,0x9a,
|
||||
0xb4,0x28,0x41,0x0f,0x81,0xb0,0x84,0x9a,0x52,0x0d,0x10,0x88,0x11,0xd8,0x20,0xb0,0x10,0xe3,0x28,0x92,
|
||||
0x4c,0x2b,0xa9,0x94,0x49,0x90,0x88,0xe4,0x28,0x88,0x18,0xb0,0x02,0x48,0x80,0x0f,0x12,0x19,0xa8,0x0e,
|
||||
0x80,0x15,0xca,0x41,0x08,0x3a,0xb9,0x2e,0xa5,0x09,0x80,0x08,0x24,0xcb,0x85,0x8c,0x22,0xb0,0x1a,0x84,
|
||||
0x2f,0x12,0x9d,0x92,0x18,0x86,0x0a,0xa8,0x4c,0x83,0x8a,0xc1,0x38,0x22,0x9b,0xca,0xa2,0x07,0x09,0x3b,
|
||||
0x88,0x13,0xf8,0x1b,0x95,0x01,0x80,0x99,0x88,0x7b,0x39,0xb8,0xb2,0xb5,0x5d,0x28,0x1b,0xc1,0xc4,0x02,
|
||||
0x2b,0x59,0xc9,0x82,0xc3,0x49,0x89,0x4b,0xe3,0x91,0x83,0x19,0x10,0x0e,0x81,0xa9,0x24,0xc8,0x28,0x98,
|
||||
0x5c,0x00,0xa8,0xa3,0x18,0x30,0x8b,0xba,0x3b,0x96,0x94,0x81,0x99,0xb9,0x05,0x68,0x8a,0x99,0xa8,0x63,
|
||||
0x01,0x2a,0xf9,0x92,0xa4,0x4b,0x1a,0x0b,0x97,0x90,0x88,0x3b,0x60,0xc1,0x90,0xa4,0x29,0x20,0x8e,0x03,
|
||||
0xc0,0x99,0x28,0x38,0x89,0x02,0x05,0x20,0x00,0xb8,0xab,0x00,0xef,0x11,0xb8,0x49,0x89,0x1c,0x15,0x00,
|
||||
0x12,0xa8,0x70,0xa1,0xbb,0xa1,0xac,0x59,0x00,0x18,0x84,0x89,0x30,0x98,0x11,0x84,0x1a,0x09,0xbc,0xa1,
|
||||
0x77,0x90,0x9d,0xa8,0xa8,0x42,0x20,0x10,0x92,0xa8,0x30,0x18,0x30,0x94,0xca,0x98,0x9c,0x2b,0x77,0xb0,
|
||||
0x8d,0x99,0x89,0x24,0x12,0x28,0x90,0xba,0x14,0x02,0x50,0x88,0xcb,0xa0,0xa8,0x7a,0x17,0xda,0x89,0x98,
|
||||
0x39,0x33,0xa2,0x01,0xa9,0x0c,0x33,0x83,0x14,0xa8,0x9f,0x88,0xa0,0x74,0x84,0xbc,0x8a,0x9a,0x48,0x24,
|
||||
0x80,0x80,0xb8,0x19,0x34,0x11,0x11,0xf9,0x9a,0x00,0x88,0x73,0x87,0xdb,0x98,0x88,0x30,0x32,0x88,0x98,
|
||||
0xb8,0x38,0x45,0x00,0x88,0xc9,0x9a,0x30,0x18,0x71,0x87,0xcc,0x89,0x08,0x20,0x24,0xa8,0x88,0x09,0x39,
|
||||
0x16,0xa2,0x88,0x9b,0x0c,0x21,0x92,0x70,0x87,0xcd,0x88,0x01,0x28,0x22,0xa8,0x99,0x81,0x20,0x44,0x90,
|
||||
0xa9,0xa9,0x89,0x32,0x82,0x7a,0x07,0xce,0x09,0x01,0x28,0x22,0xc0,0x89,0x20,0x28,0x33,0xc2,0xca,0x08,
|
||||
0x19,0x30,0xa2,0x3c,0x67,0xeb,0x8b,0x12,0x80,0x22,0xa2,0xbb,0x21,0x22,0x32,0x94,0xbc,0x8b,0x01,0x13,
|
||||
0x92,0xbc,0x77,0xd1,0x9e,0x11,0x81,0x28,0x01,0xaa,0x19,0x23,0x11,0x01,0xca,0x9b,0x38,0x22,0x80,0xeb,
|
||||
0x7a,0x17,0xec,0x09,0x12,0x88,0x21,0x90,0xab,0x31,0x23,0x80,0x89,0xab,0x8b,0x15,0x84,0x8a,0x8c,0x71,
|
||||
0x97,0xcd,0x10,0x02,0x88,0x11,0xa0,0xaa,0x52,0x21,0x0a,0x8a,0xb0,0x90,0x43,0x00,0xad,0xa9,0x77,0xb1,
|
||||
0x9e,0x10,0x82,0x08,0x11,0xa8,0x0c,0x41,0x82,0xa8,0x08,0x09,0x8a,0x14,0xa3,0xac,0x2b,0x77,0xb0,0x9e,
|
||||
0x20,0x01,0x09,0x11,0xa0,0x8c,0x41,0x03,0xa9,0x89,0x80,0x99,0x42,0x93,0xcc,0x0a,0x75,0x92,0xbf,0x28,
|
||||
0x12,0x89,0x20,0x91,0xcb,0x40,0x23,0xa8,0x9b,0x82,0xb0,0x20,0x25,0xca,0x9c,0x21,0x67,0xc0,0xac,0x20,
|
||||
0x02,0x90,0x11,0x98,0x9c,0x41,0x04,0xb0,0x99,0x01,0x09,0x39,0x13,0xfa,0x9a,0x41,0x46,0xb8,0xbf,0x20,
|
||||
0x12,0x88,0x10,0x88,0x9c,0x40,0x04,0xa0,0x9a,0x10,0x08,0x08,0x13,0xd9,0x9c,0x21,0x76,0x91,0xbe,0x19,
|
||||
0x13,0x81,0x09,0x00,0xb9,0x29,0x36,0x91,0xbb,0x08,0x02,0x88,0x30,0xa0,0xce,0x18,0x53,0x27,0xf9,0x9b,
|
||||
0x30,0x12,0x98,0x08,0x90,0xa9,0x61,0x23,0xb9,0x9c,0x11,0x11,0x89,0x10,0xc8,0xbb,0x50,0x52,0x17,0xf8,
|
||||
0xab,0x30,0x23,0xa8,0x09,0x80,0x98,0x40,0x34,0xb8,0xad,0x20,0x83,0xa0,0x08,0x90,0xac,0x08,0x24,0x77,
|
||||
0xa1,0xbf,0x18,0x23,0x91,0x8a,0x18,0x88,0x09,0x35,0x92,0xbc,0x1a,0x33,0xa1,0xa9,0x10,0xca,0x8c,0x73,
|
||||
0x21,0x16,0xf8,0xad,0x20,0x23,0xa0,0x8a,0x00,0x80,0x28,0x25,0xb1,0xbc,0x28,0x24,0x98,0x8a,0x08,0xaa,
|
||||
0x1a,0x34,0xb2,0x70,0x27,0xee,0x89,0x32,0x82,0x9a,0x19,0x01,0x89,0x41,0x13,0xca,0x8c,0x31,0x83,0xb9,
|
||||
0x09,0x80,0xbb,0x38,0x16,0xb8,0x77,0xa1,0xbf,0x29,0x33,0x90,0x9a,0x20,0x90,0x09,0x44,0x82,0xbc,0x2a,
|
||||
0x43,0xa0,0x9a,0x10,0xa9,0x8c,0x41,0x82,0xdb,0x71,0x07,0xcc,0x0a,0x33,0x81,0x8b,0x28,0x91,0xaa,0x73,
|
||||
0x12,0xba,0x8b,0x32,0x92,0x9a,0x38,0xa9,0xaf,0x11,0x04,0xb8,0x3b,0x77,0xd1,0xac,0x30,0x13,0xa8,0x09,
|
||||
0x01,0xa9,0x38,0x27,0xa0,0xbb,0x20,0x23,0x99,0x1a,0x80,0xbd,0x1a,0x53,0x90,0xbb,0x69,0x77,0xc8,0x9c,
|
||||
0x30,0x02,0x98,0x18,0x81,0xaa,0x48,0x34,0xb0,0xbb,0x30,0x11,0xa9,0x01,0xc3,0xcc,0x2a,0x32,0xa8,0xb9,
|
||||
0x83,0x77,0x87,0xcc,0x1a,0x22,0x81,0x89,0x01,0xa8,0x0a,0x35,0x84,0xba,0x0a,0x12,0xa1,0x00,0x21,0xbe,
|
||||
0x8c,0x22,0x83,0xba,0x09,0x00,0x78,0x77,0xd9,0x8b,0x31,0x02,0x99,0x01,0xa0,0x8b,0x71,0x22,0xc8,0xa9,
|
||||
0x11,0x01,0x09,0x20,0xc9,0xcb,0x11,0x04,0x98,0x8a,0x00,0x98,0x77,0x97,0xad,0x18,0x12,0x90,0x08,0x01,
|
||||
0xb9,0x19,0x36,0x91,0xab,0x18,0x82,0x99,0x21,0x92,0xce,0x1a,0x32,0x88,0x9b,0x00,0xb1,0x39,0x77,0x97,
|
||||
0xaf,0x10,0x12,0x88,0x18,0x80,0xab,0x48,0x34,0xa0,0xab,0x20,0x80,0x09,0x42,0xb0,0xaf,0x08,0x11,0x01,
|
||||
0x80,0x99,0xab,0x38,0x74,0x67,0xd9,0x9b,0x31,0x01,0x88,0x11,0xc8,0x9a,0x62,0x12,0xa9,0x89,0x81,0x98,
|
||||
0x31,0x13,0xfb,0x9a,0x11,0x81,0x19,0x29,0xcb,0xaa,0x34,0x73,0x47,0xf9,0x8b,0x21,0x81,0x18,0x10,0xb9,
|
||||
0x8c,0x62,0x02,0x99,0x88,0x90,0x98,0x32,0x04,0xbc,0x9a,0x11,0x88,0x28,0x20,0xbe,0x99,0x05,0x92,0x76,
|
||||
0x94,0xbe,0x08,0x03,0x08,0x30,0x98,0xdb,0x20,0x24,0x80,0x1a,0x98,0xd8,0x11,0x23,0xa9,0x9c,0x88,0xa8,
|
||||
0x30,0x12,0xcb,0xaa,0x02,0x13,0x12,0x77,0x27,0xcf,0x18,0x81,0x00,0x21,0x98,0x9c,0x20,0x23,0x81,0x08,
|
||||
0xaa,0x9b,0x42,0x03,0xa9,0xaa,0xac,0x0a,0x23,0x92,0xab,0x0f,0x19,0x20,0x05,0x72,0x77,0xdb,0x09,0x81,
|
||||
0x18,0x31,0xa0,0x9c,0x10,0x12,0x31,0x02,0xbb,0x9b,0x22,0x31,0x39,0xcc,0xfa,0x90,0x01,0x38,0x09,0xbc,
|
||||
0xa0,0x83,0x42,0x11,0x77,0x87,0xad,0x08,0x90,0x20,0x14,0xaa,0x89,0x01,0x11,0x34,0x88,0x9c,0x88,0x92,
|
||||
0x12,0x10,0x8f,0x8a,0x88,0x80,0x92,0xa0,0x8a,0x09,0x82,0x87,0xa3,0x77,0x87,0xad,0x80,0xa0,0x31,0x03,
|
||||
0x9b,0x09,0xb1,0x42,0x25,0x0a,0x0a,0xa8,0x80,0x05,0x98,0x98,0xaa,0x8a,0x11,0x80,0x0a,0xbc,0x1c,0x43,
|
||||
0x01,0x85,0x73,0x67,0xdb,0x88,0x99,0x38,0x23,0xa9,0x81,0xc8,0x40,0x33,0x09,0x80,0xd1,0x8a,0x13,0x3a,
|
||||
0x3a,0xfb,0xb0,0x92,0x08,0x38,0x8b,0x8b,0xc3,0xa3,0x25,0x29,0x77,0xa7,0x0c,0xa9,0x8a,0x24,0x91,0x10,
|
||||
0x88,0x1d,0x22,0x91,0x12,0xb1,0x0c,0x21,0x9b,0x12,0xf1,0x8a,0x81,0x8a,0x48,0xb8,0xa0,0x96,0x80,0x30,
|
||||
0x99,0x78,0x77,0x99,0x98,0xac,0x19,0x80,0x29,0x11,0x89,0x43,0x03,0x42,0x12,0x8a,0x20,0xd8,0x88,0xb0,
|
||||
0x9d,0x89,0xbb,0x09,0xc0,0x80,0x14,0x49,0x78,0x18,0x20,0x77,0x92,0x09,0xdb,0xab,0x90,0x9a,0x10,0x80,
|
||||
0x40,0x24,0x31,0x25,0x02,0x22,0x91,0xa9,0xb8,0xaf,0x9b,0xdb,0xa9,0xa0,0x09,0x30,0x31,0x42,0x24,0x33,
|
||||
0x75,0x17,0x08,0xa0,0xcb,0x9a,0xbb,0x9b,0xa8,0x98,0x43,0x31,0x73,0x23,0x32,0x15,0x01,0x21,0x99,0x9b,
|
||||
0xcb,0xcd,0xb8,0xba,0x8b,0x8b,0x1b,0x11,0x03,0x47,0x77,0x00,0x10,0x99,0xaa,0xc0,0xaa,0x89,0x9a,0x29,
|
||||
0x81,0x22,0x17,0x22,0x52,0x20,0x20,0x82,0xa1,0x81,0xac,0x9b,0xbd,0xcb,0xb9,0xbb,0x89,0x8b,0x81,0x77,
|
||||
0x17,0x18,0x01,0xbb,0x89,0xcc,0x8a,0xa8,0x1a,0x21,0x20,0x36,0x13,0x43,0x14,0x20,0x21,0x98,0x90,0xe9,
|
||||
0x9a,0xcb,0x9c,0xaa,0xbb,0x99,0xb8,0x21,0x79,0x77,0x11,0x01,0xba,0x8a,0xcc,0xaa,0x98,0x0a,0x32,0x20,
|
||||
0x27,0x13,0x52,0x21,0x10,0x01,0x98,0x98,0xcb,0x9c,0xca,0xba,0xb9,0x9b,0x0a,0x0b,0x10,0x45,0x77,0x13,
|
||||
0x21,0xca,0xab,0xea,0x9b,0x99,0x9a,0x22,0x11,0x45,0x23,0x52,0x22,0x20,0x02,0xa0,0x90,0xdb,0xab,0xdb,
|
||||
0xab,0xb9,0xba,0x80,0x98,0x58,0x20,0x77,0x05,0x11,0xb9,0xaa,0xea,0x9b,0x99,0x8a,0x21,0x11,0x45,0x23,
|
||||
0x52,0x12,0x11,0x02,0x98,0x88,0xbb,0xad,0xda,0xaa,0xb9,0x8c,0x89,0x9a,0x01,0x70,0x77,0x18,0x01,0xaa,
|
||||
0x99,0xdb,0x9a,0x99,0x0a,0x02,0x21,0x37,0x21,0x43,0x02,0x22,0x82,0x09,0x98,0xad,0xaa,0x9c,0xba,0xba,
|
||||
0xbb,0xae,0xa9,0xb9,0x77,0x03,0x21,0xb1,0xab,0xe9,0x9d,0x98,0x9a,0x11,0x02,0x72,0x12,0x32,0x23,0x11,
|
||||
0x13,0x90,0x18,0xbc,0xac,0xda,0xbb,0xa9,0x9d,0x99,0xa9,0x10,0x79,0x57,0x10,0x01,0xba,0x9a,0xec,0x99,
|
||||
0xa9,0x09,0x01,0x20,0x35,0x22,0x35,0x12,0x32,0x82,0x00,0xa0,0xac,0xb9,0xae,0x9a,0xcb,0x09,0xa9,0x09,
|
||||
0x00,0x77,0x13,0x21,0xca,0xaa,0xfb,0x9b,0x9a,0x9b,0x00,0x11,0x54,0x22,0x53,0x13,0x32,0x13,0x00,0x02,
|
||||
0x9b,0xa9,0xfb,0x9a,0xbb,0x9d,0x1a,0x80,0x80,0x08,0x80,0x08,0x80,0x08,0x80,0x08,0x80,0x08,0x80,0x08,
|
||||
0x08,0x08,0x08,0x80,0x80,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
@@ -247,235 +250,78 @@ static const uint8_t gpsOnData[] = {
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
};
|
||||
static constexpr VoiceClip gpsOnClip = {
|
||||
gpsOnData, sizeof(gpsOnData), 9683, 8000
|
||||
gpsOnData, sizeof(gpsOnData), 9683, 8000, gpsData, sizeof(gpsData)
|
||||
};
|
||||
static const uint8_t gpsOffData[] = {
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x70,
|
||||
0x7f,0xf7,0xf7,0x61,0x5c,0x8b,0xd1,0x04,0x4a,0x8c,0xb3,0x83,0x90,0x98,0x91,0x22,0x2d,0x89,0x28,0xd1,
|
||||
0xa3,0x20,0x0a,0x80,0xf1,0xb7,0x01,0x5d,0x1a,0x88,0x91,0x18,0x2a,0xa0,0xb5,0x81,0x38,0x2c,0x88,0x2b,
|
||||
0x5a,0xb9,0xa7,0xa1,0xb4,0xc3,0x51,0x1d,0x08,0x90,0x20,0x3c,0x1b,0xf3,0xa3,0x81,0x28,0x1b,0x98,0xb4,
|
||||
0x82,0x6c,0x8a,0xc3,0xc4,0x11,0x09,0x00,0x0a,0xb1,0xa5,0x20,0x2c,0x39,0x4f,0x8a,0xa2,0x01,0x5b,0x0a,
|
||||
0xc1,0xb6,0x82,0x4a,0x8a,0xb2,0x02,0x5c,0x1b,0xa1,0xa2,0x01,0x3a,0x2a,0x3b,0x99,0xf7,0xa3,0x30,0x2d,
|
||||
0x19,0x29,0x2c,0xc0,0xb5,0x21,0x3c,0x2b,0xc0,0xb4,0xb4,0x11,0x2a,0x1a,0x98,0x82,0x3a,0x89,0x10,0xb9,
|
||||
0xb7,0x82,0x5a,0x2b,0xe0,0xc6,0x82,0x49,0x2c,0x89,0xc3,0x82,0x29,0x4b,0x8a,0xd4,0xa3,0x20,0x4d,0x0a,
|
||||
0xc2,0x82,0x29,0x2b,0xb0,0xb5,0x02,0x4b,0x3b,0x8a,0xd4,0xb4,0x01,0x29,0x4b,0x2b,0xd0,0xb6,0x82,0x39,
|
||||
0x2c,0x89,0xb2,0xa3,0x10,0x1a,0x90,0xa2,0x50,0x2e,0xe1,0xb4,0x02,0x5c,0x2b,0x89,0xa2,0x01,0x19,0x09,
|
||||
0xc2,0x11,0x3b,0x4c,0xa9,0xb5,0x11,0x5b,0x1b,0xc1,0x83,0x5b,0x0a,0xc2,0x82,0x39,0x2c,0x88,0x29,0x89,
|
||||
0x93,0x4d,0x99,0xe6,0xb5,0x82,0x5b,0x2b,0x98,0xc3,0x82,0x49,0x3d,0x99,0xc4,0x82,0x39,0x3d,0x99,0xc3,
|
||||
0x93,0x39,0x2c,0x09,0xb1,0xa4,0x10,0x3b,0x89,0xb2,0x12,0x3d,0xc8,0xb5,0x21,0x4f,0x2b,0xa0,0xb3,0x92,
|
||||
0x18,0x19,0x4a,0x3c,0x0a,0x00,0x3a,0x0a,0xf5,0xc5,0x21,0x3d,0x0a,0xa1,0xa3,0x80,0xb1,0x03,0x6e,0x2c,
|
||||
0x98,0xb3,0x92,0x00,0x5b,0x1a,0x88,0x00,0x19,0x98,0xc6,0x21,0x4f,0x0a,0xa0,0xb4,0x82,0x08,0x19,0x08,
|
||||
0x4a,0x1a,0x29,0xb8,0xb4,0xc5,0x21,0x3c,0x4b,0x9a,0xc5,0x82,0x39,0x3d,0x0a,0xb1,0xa4,0x81,0x18,0x2a,
|
||||
0xa8,0xa4,0x28,0xb0,0x31,0x2e,0xa0,0xc3,0xb3,0x70,0x4f,0x0a,0xc1,0xa3,0x20,0x4d,0x1a,0xb0,0xa5,0x10,
|
||||
0x4b,0x0a,0xa1,0xc3,0x82,0x19,0x19,0xa0,0x11,0x3b,0x1b,0xf5,0xa3,0x10,0x4c,0x0a,0x80,0x30,0x9a,0xb7,
|
||||
0x11,0x2c,0x8a,0xb0,0xb2,0x21,0x6c,0x19,0x91,0x93,0x02,0x29,0x2b,0x0b,0x8b,0xf8,0x24,0x3f,0xc0,0xa3,
|
||||
0x88,0x8a,0x1a,0x9a,0xa4,0x13,0x32,0x34,0x50,0x18,0x98,0xd1,0xb0,0x99,0x1f,0xb3,0x78,0x2b,0xd1,0x00,
|
||||
0x0c,0xa8,0x00,0x18,0x12,0x52,0x12,0x32,0x39,0xb9,0xd0,0xaa,0xcb,0x2a,0xf3,0x04,0x5c,0x9a,0xb2,0x19,
|
||||
0x9b,0x91,0x30,0x41,0x62,0x21,0x83,0x11,0x1c,0xbb,0xe8,0x99,0x59,0x2d,0xc1,0x83,0x2c,0xaa,0xb1,0x08,
|
||||
0x00,0x42,0x51,0x03,0x15,0x10,0x89,0xa9,0xca,0xba,0x0c,0xf2,0x12,0x4d,0xb8,0xb4,0x39,0x0c,0x90,0x11,
|
||||
0x20,0x14,0x42,0x20,0x91,0xb1,0xc9,0xca,0xab,0x6b,0x1d,0xe2,0x83,0x3b,0x9b,0xb2,0x18,0x90,0x06,0x60,
|
||||
0x10,0x83,0x11,0x0a,0xb8,0x9b,0x9e,0x1a,0xd9,0xb7,0x30,0x1d,0xc0,0x92,0x29,0x09,0x11,0x31,0x13,0x15,
|
||||
0x30,0x1a,0xb9,0xf9,0xb8,0x8a,0xe2,0x12,0x3e,0xc9,0xb4,0x39,0x1c,0x90,0x02,0x12,0x14,0x42,0x28,0x98,
|
||||
0xc1,0xa9,0x9c,0x0c,0xf2,0x83,0x4c,0xa9,0xc3,0x18,0x8a,0x81,0x40,0x38,0x13,0x24,0x01,0xa2,0x98,0x9e,
|
||||
0xca,0x99,0xf3,0x83,0x4d,0xa9,0xd3,0x10,0x1b,0xa0,0x84,0x31,0x21,0x42,0x28,0xb0,0xd3,0x1a,0x0f,0x0a,
|
||||
0xd1,0xb5,0x20,0x1d,0xa8,0x92,0x19,0x08,0x12,0x60,0x01,0x94,0x12,0x3c,0xab,0xf2,0x80,0x4a,0x1c,0xc1,
|
||||
0xa4,0x39,0x0c,0xa0,0x81,0x18,0x01,0x33,0x70,0x08,0xb3,0x82,0x1c,0x8c,0xc8,0xb3,0x58,0x1c,0xb0,0x81,
|
||||
0x1d,0xb8,0x93,0x69,0x18,0x85,0x22,0x28,0xa0,0xc2,0x89,0x9c,0xa9,0xc5,0x12,0x3d,0x9a,0xd2,0x08,0x8a,
|
||||
0xa2,0x32,0x40,0x14,0x33,0x38,0xb0,0xe2,0x0a,0x8f,0x00,0x3b,0xf0,0xb4,0x38,0x1e,0xb0,0xa3,0x20,0x29,
|
||||
0x12,0x41,0x18,0xb3,0x92,0x2d,0x8d,0x99,0xd3,0x83,0x4c,0x8b,0xb0,0x19,0x8c,0xb2,0x24,0x79,0x10,0x03,
|
||||
0x82,0x81,0x09,0x0e,0xab,0x01,0x3c,0xf0,0xa4,0x4a,0x0d,0xb0,0x82,0x18,0x81,0x14,0x50,0x18,0x91,0xa2,
|
||||
0x09,0x0d,0x8b,0xf4,0x93,0x6b,0x0b,0xc1,0x81,0x1a,0x98,0x12,0x48,0x01,0x85,0x12,0x08,0x98,0x0a,0x0f,
|
||||
0x88,0x09,0xe1,0xb3,0x4a,0x0d,0xa8,0x81,0x28,0x01,0x15,0x60,0x18,0xa2,0x82,0x0b,0xca,0x88,0xb0,0x94,
|
||||
0x5d,0x0c,0xc0,0xa1,0x88,0x08,0x30,0x30,0x86,0x86,0x21,0x19,0x89,0xa9,0xd9,0x82,0x4e,0x9a,0xc3,0x00,
|
||||
0x1c,0x99,0x00,0x4a,0x00,0x85,0x32,0x38,0x81,0x92,0x8a,0xad,0xc9,0xa3,0x7b,0x1c,0xe2,0x81,0x2b,0x9b,
|
||||
0xc3,0x31,0x5a,0x01,0x04,0x21,0x18,0x98,0x99,0xbb,0x9b,0xf3,0x02,0x5f,0x8b,0xe2,0x81,0x2a,0x0a,0x81,
|
||||
0x12,0x12,0x24,0x40,0x29,0x99,0xf1,0xa0,0x1a,0xa8,0x93,0x5d,0x8b,0xe2,0x00,0x2b,0x8a,0x93,0x04,0x32,
|
||||
0x61,0x28,0x91,0xb2,0xa0,0x0d,0x9c,0xc3,0x58,0x2d,0xc0,0x92,0x2b,0x9b,0xc3,0x31,0x5a,0x01,0x14,0x31,
|
||||
0x08,0xa1,0x99,0x9d,0xba,0x3b,0xbb,0xc7,0x33,0x2f,0xaa,0xd3,0x00,0x2a,0x08,0x03,0x43,0x31,0x12,0x10,
|
||||
0x9a,0xf9,0xb8,0x8b,0x4c,0x1b,0xe5,0x83,0x4c,0x8b,0xc1,0x01,0x2a,0x00,0x31,0x30,0x85,0x13,0x4b,0xaa,
|
||||
0xd1,0x99,0x8b,0x3a,0x2c,0xe5,0x83,0x5b,0x9b,0xd3,0x00,0x1a,0x81,0x13,0x31,0x04,0x32,0x1a,0xe0,0xa0,
|
||||
0x0d,0x9b,0x08,0xd2,0x85,0x6a,0x8a,0xd2,0x00,0x1b,0x98,0x82,0x22,0x41,0x41,0x11,0x92,0x88,0x8c,0xbc,
|
||||
0xb9,0xaa,0x42,0x5d,0xb1,0x84,0x2b,0xbb,0xe1,0x08,0x2a,0x10,0x15,0x43,0x31,0x11,0xa1,0xa8,0xad,0xac,
|
||||
0xba,0x9a,0x87,0x58,0x88,0xa2,0x09,0x8d,0xba,0xa0,0x48,0x48,0x23,0x17,0x31,0x00,0xa1,0xa8,0x9d,0xbb,
|
||||
0xca,0x09,0x42,0x38,0x85,0x91,0x0a,0xaf,0xc8,0x89,0x19,0x11,0x25,0x34,0x42,0x11,0x81,0x98,0xac,0xdb,
|
||||
0xba,0x9a,0x39,0x12,0x25,0x21,0x80,0xd8,0xca,0xbb,0x8c,0xa8,0xa8,0x72,0x43,0x24,0x32,0x21,0x00,0x99,
|
||||
0xcb,0xbc,0xab,0xa9,0x00,0x08,0x80,0xa1,0xaa,0xbd,0xdb,0xa9,0x0a,0x30,0x44,0x35,0x34,0x24,0x23,0x12,
|
||||
0x81,0xa8,0xbb,0x09,0x8b,0xb9,0xfb,0xbd,0xbd,0xdb,0xaa,0x9b,0x89,0x11,0x44,0x53,0x33,0x24,0x23,0x12,
|
||||
0x00,0xa8,0xba,0x9d,0x91,0x18,0x80,0xb8,0xdc,0xbc,0xcd,0xba,0xba,0x9a,0x18,0x41,0x44,0x43,0x24,0x33,
|
||||
0x32,0x21,0x80,0xa8,0x1b,0xc9,0xa8,0xdb,0xcb,0xad,0xdb,0xaa,0xab,0x9a,0x88,0x30,0x52,0x34,0x34,0x34,
|
||||
0x32,0x23,0x22,0x01,0xa1,0x35,0x1b,0xa8,0xcc,0xbd,0xbd,0xdb,0xaa,0xab,0x9a,0x89,0x11,0x35,0x63,0x42,
|
||||
0x32,0x32,0x32,0x12,0x01,0xb0,0x54,0x8d,0xa8,0xdb,0xbb,0xbc,0xac,0xaa,0x99,0x00,0x33,0x45,0x53,0x32,
|
||||
0x23,0x14,0x02,0x81,0xa8,0xba,0xcd,0x21,0x9f,0xa8,0xc9,0xa9,0xaa,0xa9,0x10,0x41,0x51,0x43,0x23,0x24,
|
||||
0x23,0x12,0x00,0xa9,0xcc,0xda,0xba,0xda,0x32,0x0e,0x08,0x99,0xa9,0x80,0x88,0x41,0x32,0x34,0x43,0x33,
|
||||
0x32,0x93,0xb1,0xda,0xdb,0xca,0xaa,0xdb,0xb8,0x67,0x0a,0x00,0x08,0xba,0x29,0xba,0xb5,0x87,0x08,0x01,
|
||||
0x08,0x11,0xa5,0x21,0x1e,0xa8,0xa0,0xa2,0x1b,0x31,0x88,0xf1,0x38,0xc0,0x12,0x91,0x70,0x80,0x98,0x19,
|
||||
0x8b,0xa2,0x5c,0xc0,0x80,0x21,0x18,0x79,0xa8,0x97,0xa2,0x19,0x9b,0xa9,0x0a,0x8e,0x7b,0xa1,0x81,0x20,
|
||||
0x19,0x88,0x07,0x88,0x1a,0x14,0x3a,0x59,0xc8,0x90,0x82,0x9d,0x00,0x89,0xe1,0x13,0x28,0x3d,0x89,0x80,
|
||||
0x11,0x09,0xf9,0x89,0x29,0xe4,0x08,0x83,0x49,0x5a,0x90,0x18,0xb1,0x29,0x4b,0x90,0x11,0xb3,0x1f,0x1a,
|
||||
0x99,0x18,0xb9,0xb2,0x87,0x41,0x69,0x00,0x19,0x0b,0xcb,0xaa,0xb7,0x11,0x00,0x90,0x9e,0x80,0x42,0x8d,
|
||||
0x30,0xa0,0xa6,0x04,0x0a,0x00,0x99,0x01,0xd3,0x21,0x1f,0x89,0xa0,0x08,0x18,0x02,0x02,0x51,0x95,0x22,
|
||||
0x89,0x8f,0xc1,0x90,0x19,0x91,0xa8,0x5b,0x3d,0x98,0x02,0xa2,0x1f,0x9a,0x96,0x02,0x2a,0x11,0x42,0x5a,
|
||||
0x08,0xb1,0x00,0xa8,0x9f,0xc2,0xa9,0xa0,0x8e,0x21,0x6b,0x10,0x83,0x1a,0x11,0xb0,0x82,0xd1,0x90,0x30,
|
||||
0x4c,0x09,0xa3,0x9a,0xc8,0xf1,0xb8,0x07,0x1b,0x89,0xb3,0x91,0x70,0x09,0x81,0x6a,0xb2,0x2d,0x14,0xb9,
|
||||
0x33,0xf9,0x38,0xa9,0x9a,0x10,0x1c,0x93,0x7b,0xb1,0x18,0x04,0xf0,0x7f,0xb1,0x3a,0x08,0x9a,0x07,0x0b,
|
||||
0xa6,0x0a,0x12,0x0a,0x80,0xf3,0x21,0x1a,0x2f,0xb0,0x01,0x93,0x1a,0x0a,0x8a,0x17,0x5d,0xa0,0xaa,0x07,
|
||||
0x3d,0x88,0x00,0x88,0x2a,0xc0,0x95,0x29,0x18,0x0f,0xa4,0x90,0x02,0x48,0x9d,0x05,0x0d,0xa4,0x3b,0xb1,
|
||||
0x38,0xc1,0x01,0x92,0x5b,0xa9,0x95,0x3a,0x08,0x1e,0xc4,0x28,0x88,0x08,0xb4,0x80,0x58,0x8d,0x94,0x0a,
|
||||
0x93,0x5d,0xc0,0x21,0xb8,0x22,0x0b,0xb1,0x41,0xac,0x14,0x1d,0x92,0x98,0x83,0x4e,0xa8,0x11,0xb8,0x22,
|
||||
0x8c,0x01,0x09,0x28,0xc2,0x7a,0xe8,0x84,0x88,0x39,0xb8,0x11,0xf1,0x22,0x2e,0x90,0x08,0xb2,0x30,0xaa,
|
||||
0x12,0x1d,0xc3,0x11,0xa9,0xa7,0x49,0xaa,0xa6,0x38,0x8a,0x10,0xa9,0xa5,0x49,0x0a,0x81,0x2a,0xe1,0x94,
|
||||
0x39,0x0a,0x29,0xd8,0xa6,0x10,0x1a,0x90,0x28,0xa8,0x93,0x88,0x90,0x20,0x9c,0xc7,0x21,0x89,0x30,0x1d,
|
||||
0x98,0xc5,0x11,0x0a,0x38,0x2d,0xd1,0xa4,0x28,0x1a,0x19,0xd2,0x02,0x4c,0x0a,0xa2,0x18,0xc0,0xb5,0x02,
|
||||
0x5b,0x2b,0x99,0xd6,0x93,0x28,0x2b,0x19,0x1a,0xe2,0xb4,0x82,0x4a,0x1b,0xd1,0xb4,0x12,0x4c,0x0a,0xa0,
|
||||
0xb4,0x02,0x5b,0x2b,0x09,0xb0,0xb7,0xa3,0x38,0x3d,0x0a,0x90,0x91,0xb3,0x40,0x2c,0x89,0xa1,0x02,0xa8,
|
||||
0x31,0x3c,0xc8,0xb7,0x81,0x00,0x4c,0x8a,0xa2,0x20,0xb8,0x44,0x3f,0xb9,0xb6,0x01,0x2a,0x88,0x6a,0x1b,
|
||||
0xb1,0xc6,0x93,0x38,0x3e,0x0a,0xb1,0xa3,0x18,0x18,0x19,0x4a,0x8a,0x21,0x1e,0xe2,0xb5,0x20,0x3b,0x0a,
|
||||
0x00,0xc0,0xa5,0x01,0x6b,0x2c,0x19,0x88,0xc2,0xb3,0x31,0x1f,0x80,0x08,0x80,0xb1,0xb4,0x42,0x3e,0x89,
|
||||
0x90,0x88,0xc1,0xa3,0x48,0x3c,0x09,0x91,0x01,0x90,0x92,0x38,0x3c,0x9a,0x17,0x7a,0x0a,0xc0,0x80,0x0c,
|
||||
0xa9,0xa2,0x11,0x20,0x22,0x51,0x10,0xa2,0xb3,0x80,0x3c,0xb7,0x51,0x2f,0xa9,0x91,0x8a,0xc8,0xb3,0x40,
|
||||
0x4b,0x00,0x03,0x11,0xa2,0xa4,0x18,0x4f,0xa8,0xa5,0x18,0x8b,0xd8,0x90,0x0a,0x89,0x02,0x51,0x30,0x03,
|
||||
0x14,0x38,0x1b,0xab,0x7a,0xb8,0xc7,0x82,0x2d,0x9b,0xb0,0x08,0x09,0x02,0x53,0x58,0x01,0x83,0x10,0x8a,
|
||||
0xd8,0x22,0x3f,0xb9,0xc5,0x08,0x8b,0xb8,0x00,0x4a,0x00,0x05,0x41,0x28,0x81,0x81,0x1a,0x0c,0xe5,0x93,
|
||||
0x5b,0x8c,0xa0,0x88,0x8a,0xc2,0x13,0x7a,0x18,0x82,0x12,0x19,0x98,0x98,0x48,0x3e,0xc9,0xc3,0x09,0x8c,
|
||||
0xb8,0x10,0x4a,0x81,0x87,0x22,0x38,0x80,0x91,0x8a,0x0c,0xf3,0x83,0x3d,0x9b,0xf2,0x80,0x2b,0x99,0x83,
|
||||
0x50,0x10,0x04,0x21,0x29,0xb8,0xd1,0x20,0x2e,0xc8,0xc3,0x19,0x0d,0xa8,0x00,0x39,0x00,0x06,0x31,0x38,
|
||||
0x91,0x92,0x0a,0x1e,0xf3,0xa3,0x39,0x0e,0xb8,0x09,0x0b,0xb1,0x85,0x41,0x30,0x22,0x40,0x09,0xe1,0xb1,
|
||||
0x58,0x2e,0xa8,0xc3,0x18,0x0c,0xa8,0x28,0x4c,0x88,0x95,0x22,0x39,0x80,0x81,0x1a,0x8c,0xf5,0xa3,0x39,
|
||||
0x0d,0xa8,0x80,0x1a,0xb0,0x96,0x31,0x39,0x02,0x03,0x38,0x0c,0xb9,0x21,0x3f,0xcb,0xd6,0x00,0x1b,0xa9,
|
||||
0x92,0x59,0x3a,0x92,0x86,0x02,0x00,0x00,0x1b,0x1c,0xf1,0xb3,0x38,0x1e,0xa9,0x90,0x1a,0x89,0x93,0x14,
|
||||
0x32,0x24,0x32,0x39,0xb8,0xf2,0xd4,0x20,0x2f,0x9a,0xb1,0x08,0x8b,0xb2,0x13,0x50,0x11,0x05,0x21,0x08,
|
||||
0xb1,0x98,0x7a,0x3e,0xaa,0xd4,0x91,0x1a,0x8a,0x88,0x39,0x10,0x96,0x85,0x21,0x18,0x80,0x09,0x5c,0x0b,
|
||||
0xf3,0x91,0x1a,0x8c,0x98,0x19,0x19,0xa3,0x07,0x31,0x48,0x18,0x90,0xb1,0x88,0xf2,0xa3,0x5c,0x0d,0xc0,
|
||||
0xa2,0x08,0x09,0x92,0x32,0x58,0x01,0x83,0x20,0x1c,0xd8,0xc5,0x11,0x3d,0x9b,0xb1,0x08,0x0b,0xc1,0x84,
|
||||
0x40,0x38,0x11,0x02,0x92,0xc2,0xa1,0x91,0x6c,0x1e,0xa9,0xc1,0x88,0x9a,0xb2,0x32,0x7a,0x01,0x95,0x13,
|
||||
0x29,0x89,0x98,0xb3,0x6a,0x1e,0xc9,0xc2,0x08,0x0b,0x88,0x21,0x79,0x00,0x84,0x02,0x10,0x89,0x98,0x91,
|
||||
0x7b,0x1e,0xc8,0xc2,0x80,0x1a,0x09,0x01,0x31,0x31,0x04,0x04,0x48,0x1b,0xe8,0xb5,0x20,0x2f,0x9a,0xb1,
|
||||
0x08,0x0a,0xa1,0x84,0x60,0x29,0x82,0x03,0x28,0x8a,0xb8,0xd6,0x92,0x3b,0x0f,0xa8,0x90,0x09,0xa0,0x95,
|
||||
0x42,0x59,0x00,0x92,0x01,0x89,0x39,0x0c,0xf1,0xc2,0x88,0x8b,0x8a,0x1a,0x18,0x04,0x15,0x23,0x13,0x22,
|
||||
0x3a,0x8e,0x81,0x4c,0x9c,0xf1,0xa0,0x0a,0x1b,0x09,0x11,0x32,0x35,0x33,0x13,0x02,0x89,0x1f,0xf1,0xc3,
|
||||
0x29,0x0f,0xa8,0xa1,0x28,0x2a,0x92,0x15,0x40,0x18,0x92,0x92,0x89,0x28,0x2f,0xca,0xf4,0x91,0x2a,0x0b,
|
||||
0x90,0x83,0x22,0x31,0x22,0x32,0x29,0x9a,0x8b,0xf6,0xa2,0x3c,0x8e,0xc0,0x80,0x2a,0xa0,0x86,0x31,0x59,
|
||||
0x80,0x92,0x81,0x8a,0x80,0x4c,0x8c,0xf1,0xa1,0x09,0x0a,0x90,0x12,0x51,0x40,0x10,0x93,0x93,0x09,0x1d,
|
||||
0xf2,0xb3,0x3a,0x8f,0xb0,0xa1,0x29,0x08,0x04,0x42,0x48,0x81,0x93,0x08,0xab,0x82,0x4f,0x9c,0xf3,0x80,
|
||||
0x1a,0x99,0x82,0x30,0x48,0x02,0x85,0x01,0x19,0x8a,0x9a,0xe6,0x93,0x4b,0x8c,0xc0,0x80,0x09,0x91,0x23,
|
||||
0x70,0x10,0x82,0x01,0x0a,0xba,0x82,0x3f,0xab,0xf3,0x08,0x0b,0xa8,0x11,0x30,0x04,0x25,0x48,0x08,0xb1,
|
||||
0x88,0x2e,0xe1,0x93,0x5b,0x8c,0xc1,0x00,0x2b,0x90,0x04,0x50,0x18,0x92,0x01,0x8a,0xe0,0x21,0x3e,0xa9,
|
||||
0xd4,0x00,0x0b,0xa8,0x10,0x4a,0x01,0x15,0x30,0x00,0xa2,0x89,0x9d,0xd1,0x18,0x1c,0xc0,0x92,0x09,0x98,
|
||||
0x02,0x58,0x00,0x85,0x22,0x29,0x98,0xb0,0x19,0xf2,0x82,0x2e,0xac,0xd1,0x08,0x1a,0x11,0x33,0x14,0x04,
|
||||
0x10,0x99,0xb9,0x9a,0x3c,0xd2,0x96,0x29,0x8d,0xb9,0x99,0x88,0x42,0x70,0x11,0x82,0x82,0x89,0x8b,0xaa,
|
||||
0xb0,0x87,0x40,0x0d,0xc8,0x98,0x8a,0x18,0x40,0x32,0x14,0x02,0x00,0x9a,0xba,0xa9,0x98,0x37,0x3c,0xe9,
|
||||
0xc0,0x99,0x8a,0x38,0x41,0x14,0x13,0x11,0x09,0x0c,0x9a,0x88,0x10,0x7a,0xd4,0xa2,0x0d,0xab,0x88,0x00,
|
||||
0x24,0x51,0x10,0x01,0x09,0x98,0x08,0x19,0x90,0xa0,0x79,0xa9,0xf4,0xaa,0xaa,0x29,0x38,0x25,0x52,0x18,
|
||||
0x81,0xa1,0x81,0x39,0x1c,0xa8,0xf0,0x38,0xf2,0x00,0x8e,0xb1,0x98,0x11,0x61,0x28,0x92,0x11,0x19,0x29,
|
||||
0x0b,0xd2,0xa0,0xb8,0xb9,0x77,0x2d,0xc8,0x90,0x98,0x11,0x38,0x85,0x12,0x08,0x2b,0xaa,0xb4,0x01,0x1b,
|
||||
0xca,0xf2,0xa1,0x77,0x1b,0xd0,0x88,0x99,0x31,0x48,0x02,0x80,0xe1,0x28,0x1b,0x92,0x91,0x92,0x2f,0x8c,
|
||||
0x01,0x79,0xb7,0x10,0x8d,0x88,0x88,0x85,0x30,0x88,0x09,0xb9,0x83,0x3a,0x92,0x2a,0xf9,0x00,0x98,0x23,
|
||||
0x7d,0xe3,0xa2,0xaa,0x10,0x4a,0x83,0x12,0xa8,0x1a,0x9c,0x84,0x20,0xa0,0x98,0xaa,0x39,0x29,0x06,0x58,
|
||||
0xb7,0x4b,0x9e,0x00,0x80,0x15,0x19,0xa0,0x99,0xa1,0x50,0x19,0x00,0xaa,0x88,0x0a,0x04,0x31,0x3a,0x7f,
|
||||
0xf3,0x80,0x0b,0x38,0x88,0x87,0x08,0x89,0x1b,0xb2,0x23,0x08,0x2a,0xad,0x91,0x21,0x41,0x89,0xe1,0x79,
|
||||
0xe2,0x00,0xaa,0x21,0x19,0x15,0x89,0xa1,0x0c,0x80,0x48,0xa2,0x10,0xbb,0x88,0x88,0x17,0x29,0x98,0xca,
|
||||
0x57,0x0d,0xb0,0x09,0x82,0x60,0x80,0x80,0xc8,0x10,0x1a,0x12,0x98,0x91,0x0d,0x08,0x10,0x94,0x18,0x99,
|
||||
0x3c,0x07,0x3d,0xdb,0x08,0xa2,0x44,0x08,0x90,0xc9,0x82,0x5b,0x10,0x98,0xc1,0x09,0x19,0x38,0xa3,0x83,
|
||||
0xab,0x5c,0x07,0x2c,0xea,0x08,0x80,0x43,0x80,0x81,0xbb,0x81,0x19,0x05,0x19,0xc0,0x8a,0x80,0x69,0x91,
|
||||
0x01,0xa9,0x39,0x37,0x2f,0xdb,0x08,0x91,0x63,0x08,0x80,0xb9,0x01,0x3b,0x12,0xa8,0xd3,0x1b,0x89,0x11,
|
||||
0xa7,0x11,0x8b,0xb0,0x77,0x0a,0xc8,0x8a,0x81,0x50,0x01,0x00,0xb8,0x29,0x0a,0x12,0xa1,0x91,0x8f,0x90,
|
||||
0x10,0x23,0x2b,0xb8,0x9a,0x77,0xe2,0xa2,0x8d,0x18,0x28,0x05,0x18,0x99,0x8a,0xa1,0x31,0x81,0x89,0xe9,
|
||||
0x18,0x00,0x31,0xa0,0x08,0xac,0x70,0xa7,0x00,0xae,0x18,0x00,0x25,0x90,0x08,0xac,0x11,0x00,0x13,0x9b,
|
||||
0x99,0x0d,0x03,0x01,0x94,0x0c,0x89,0x39,0x77,0x1b,0xcb,0x8a,0x84,0x51,0x00,0x89,0xb8,0x28,0x01,0x20,
|
||||
0xe1,0x09,0x99,0x30,0xa3,0x02,0xba,0x4d,0x1a,0x57,0x8b,0xbb,0x8d,0x05,0x21,0x11,0x8c,0xa8,0x18,0x13,
|
||||
0x29,0xb8,0xac,0x01,0x69,0x01,0x89,0xb8,0x19,0x41,0x77,0x9b,0xaa,0x8b,0x15,0x31,0x82,0xac,0x90,0x28,
|
||||
0x33,0x99,0xe1,0x9a,0x30,0x39,0x94,0xc8,0x08,0x2b,0x61,0x27,0x8d,0xab,0x8b,0x07,0x11,0x01,0x9c,0x80,
|
||||
0x00,0x23,0x8a,0x99,0xbb,0x24,0x01,0x21,0xae,0x18,0x88,0x34,0x47,0x9e,0x99,0x8b,0x16,0x01,0x00,0xbb,
|
||||
0x01,0x82,0x52,0x9a,0x9a,0xc0,0x42,0x10,0x0a,0xf0,0x00,0x20,0x4a,0x07,0xbb,0x8a,0x8c,0x34,0x82,0x10,
|
||||
0xbc,0x28,0x93,0x33,0xc8,0x0d,0x98,0x21,0x03,0x8b,0xb8,0x1c,0x53,0x10,0x57,0xbc,0x9a,0xaa,0x36,0x01,
|
||||
0x18,0xca,0x18,0x02,0x40,0xb0,0x9b,0x88,0x49,0x04,0xa9,0x90,0x9c,0x42,0x11,0x77,0xba,0x8a,0xab,0x53,
|
||||
0x02,0x28,0xc9,0x09,0x03,0x40,0x81,0x9d,0xa0,0x08,0x43,0x99,0x90,0xda,0x31,0x28,0x77,0xb9,0x9a,0xba,
|
||||
0x42,0x13,0x20,0xc8,0x0b,0x12,0x31,0x86,0xab,0xa8,0x8a,0x34,0x90,0x18,0xbd,0x29,0x92,0x77,0xa2,0xac,
|
||||
0xd9,0x28,0x22,0x20,0xb2,0xab,0x30,0x59,0x33,0xc8,0xa8,0xbb,0x40,0x10,0x11,0xf0,0x89,0x88,0x71,0x87,
|
||||
0xa9,0xb9,0x0d,0x21,0x11,0x04,0xb9,0x08,0x08,0x63,0x81,0x88,0xc9,0x0b,0x11,0x30,0x83,0xbd,0x99,0x1b,
|
||||
0x77,0x91,0x9a,0xdc,0x08,0x02,0x42,0x81,0x9a,0xa0,0x38,0x44,0x28,0xa1,0xfa,0x88,0x19,0x30,0xa1,0xa0,
|
||||
0xe9,0x78,0x82,0x98,0xf8,0x8a,0x18,0x38,0x04,0xa1,0x92,0x0c,0x40,0x00,0x04,0xb1,0x1a,0x8c,0x29,0xb2,
|
||||
0x83,0x98,0x2f,0x07,0x98,0xb8,0x9f,0x09,0x88,0x15,0x00,0x18,0x9a,0x10,0x94,0x43,0x00,0x3a,0xc9,0x80,
|
||||
0xa2,0x38,0x1a,0x8e,0x61,0xa5,0xa0,0xbc,0x8e,0x88,0x81,0x23,0x89,0x82,0x2a,0x11,0x12,0x07,0x10,0x10,
|
||||
0x1a,0x81,0x80,0x02,0x0a,0xb9,0x77,0x92,0x8c,0xbf,0x98,0x98,0x22,0x19,0x29,0x9b,0x13,0x12,0x15,0x00,
|
||||
0x31,0x5a,0x11,0x94,0xa5,0x82,0x49,0x2c,0x57,0xab,0xa0,0x9d,0x02,0xa1,0x5a,0x1d,0x0a,0xb2,0xa3,0x84,
|
||||
0x2a,0x0a,0x2f,0x82,0x96,0x99,0x68,0x4b,0x08,0xc1,0xa1,0x02,0x79,0x99,0x38,0xd9,0x12,0xc8,0x10,0x1c,
|
||||
0x18,0xc0,0xb3,0x92,0x7a,0x3a,0x1a,0xb1,0x84,0x93,0x10,0x8c,0x7a,0xa0,0x08,0xa8,0x4a,0xa8,0x1a,0xf4,
|
||||
0x00,0x01,0x38,0x29,0x1c,0x82,0xb0,0x95,0xb3,0x20,0x1f,0x8a,0x92,0xd1,0x98,0x33,0x48,0x0e,0x18,0x21,
|
||||
0xa0,0xc8,0x92,0x58,0x08,0x9f,0x94,0x08,0x82,0x1f,0x30,0x0a,0xc4,0xa0,0x12,0x29,0x99,0xaa,0x95,0x12,
|
||||
0xc9,0x10,0x08,0x16,0x9e,0x22,0x1c,0xb3,0x0b,0x10,0x78,0x98,0x88,0x88,0x00,0x87,0x0c,0x81,0x19,0xc4,
|
||||
0x08,0x20,0x3c,0xa8,0xe2,0x93,0x11,0x3b,0x0c,0x82,0xa1,0xb2,0x2b,0x79,0x89,0xf2,0x82,0x18,0x88,0x11,
|
||||
0x1b,0x20,0x9e,0x94,0x09,0x01,0x2c,0x90,0x13,0xf0,0x48,0x80,0x29,0x0b,0x4b,0xd1,0x10,0xb0,0x7e,0xa0,
|
||||
0x80,0xd3,0x10,0x82,0x4c,0x89,0xa0,0xb3,0x92,0x08,0x38,0x8b,0xf5,0x01,0x92,0x29,0x8c,0x84,0xa2,0x1b,
|
||||
0x38,0x7a,0x8a,0xa8,0xa4,0x20,0x08,0x0f,0xa4,0x90,0x94,0x1c,0x33,0x0f,0x00,0x09,0x92,0xd0,0x02,0x1a,
|
||||
0x80,0xb3,0x28,0x28,0x0f,0x92,0x88,0x82,0x2c,0xa1,0x13,0xf0,0x40,0x9a,0x95,0x98,0x18,0x80,0x3b,0x3f,
|
||||
0x4b,0xb1,0x91,0x11,0x3f,0x18,0x8a,0xa2,0xa0,0x04,0x2a,0x6c,0x1c,0x28,0x9a,0xb4,0x38,0x40,0x0f,0x81,
|
||||
0xb0,0x84,0x8b,0x52,0x0d,0x10,0x90,0x11,0xd8,0x20,0xc0,0x20,0xe2,0x10,0x81,0x4b,0x2c,0xa8,0x93,0x6a,
|
||||
0x88,0x88,0xe3,0x28,0x88,0x18,0xb0,0x02,0x59,0x80,0x0e,0x03,0x19,0xb0,0x0e,0x80,0x15,0xca,0x41,0x08,
|
||||
0x3a,0xb9,0x2e,0xa5,0x09,0x80,0x08,0x24,0xcb,0x85,0x8c,0x13,0xb0,0x1a,0x84,0x2f,0x12,0x9d,0xa2,0x10,
|
||||
0x86,0x0a,0xa8,0x4c,0x83,0x8a,0xc1,0x38,0x22,0x9b,0xca,0xa2,0x07,0x09,0x3b,0x88,0x04,0xd8,0x1b,0x95,
|
||||
0x01,0x91,0x99,0x98,0x7b,0x49,0xa8,0xa1,0xc4,0x7b,0x18,0x0a,0xb1,0xc4,0x12,0x1c,0x59,0xc8,0x82,0xb2,
|
||||
0x49,0x0a,0x4c,0xd2,0x91,0x83,0x19,0x20,0x0f,0x91,0x98,0x23,0xc8,0x18,0x90,0x4c,0x01,0xa9,0xa5,0x08,
|
||||
0x21,0x9a,0xa9,0x3b,0x85,0xb3,0x82,0xb8,0xb8,0x06,0x7a,0x0a,0x99,0xb0,0x34,0x01,0x4b,0xea,0xa3,0xa5,
|
||||
0x4b,0x1a,0x1b,0xa6,0x90,0x08,0x2c,0x41,0xd2,0x90,0xa4,0x29,0x20,0x0e,0x93,0xc0,0x99,0x28,0x38,0x89,
|
||||
0x14,0x12,0x48,0x08,0xc0,0x9a,0x18,0xbf,0x11,0xc8,0x48,0x9a,0x4b,0x14,0x10,0x13,0xa9,0x70,0xa2,0xad,
|
||||
0xa0,0xbb,0x48,0x02,0x21,0x04,0x1a,0x39,0x99,0x85,0x82,0x19,0xbb,0xeb,0x91,0x18,0x4a,0x98,0xb0,0x84,
|
||||
0x29,0x58,0x81,0xb2,0x77,0xa4,0x9f,0x90,0x99,0x51,0x10,0x08,0x92,0xa9,0x58,0x00,0x88,0xa3,0xba,0x1b,
|
||||
0x99,0x90,0x07,0x98,0x29,0x19,0x1a,0x05,0x92,0x28,0xa9,0x77,0xb5,0xaf,0x10,0x88,0x30,0x14,0xa9,0x19,
|
||||
0xa8,0x18,0x16,0x98,0x89,0x99,0x8b,0x22,0x82,0x29,0x89,0x9d,0x81,0x13,0x62,0x00,0xba,0xc0,0x77,0xa3,
|
||||
0xbf,0x08,0x00,0x40,0x22,0xc8,0x98,0x00,0x29,0x14,0xc2,0x9a,0x1a,0x0c,0x12,0x94,0x99,0x19,0x8a,0x12,
|
||||
0x07,0x88,0x2b,0x9a,0xb2,0x77,0x94,0xdc,0x09,0x10,0x20,0x22,0xc0,0x8b,0x30,0x00,0x13,0xb1,0xaf,0x19,
|
||||
0x82,0x11,0x01,0xbc,0x98,0x14,0x20,0x20,0xba,0x9c,0x31,0x30,0x7a,0x57,0xfb,0x0b,0x21,0x82,0x11,0x90,
|
||||
0x9e,0x11,0x03,0x08,0x09,0xbc,0x08,0x15,0x08,0x09,0xb9,0x88,0x63,0x00,0x9a,0x90,0x98,0x51,0x10,0xba,
|
||||
0x77,0xa1,0xbf,0x28,0x13,0x00,0x00,0xd9,0x1a,0x43,0xa1,0x98,0x99,0x8b,0x53,0x93,0xab,0x1a,0x80,0x22,
|
||||
0x14,0xcb,0x0b,0x22,0x82,0x10,0x9a,0x9f,0x77,0xd2,0x9e,0x11,0x03,0x08,0x08,0xba,0x28,0x35,0xa9,0xab,
|
||||
0x01,0x18,0x60,0x90,0xbb,0x20,0x32,0x0a,0x88,0xe8,0x18,0x42,0x08,0xaa,0xc8,0x28,0x77,0xd2,0x9f,0x21,
|
||||
0x12,0x89,0x89,0x98,0x38,0x43,0xc8,0xab,0x21,0x11,0x18,0xb0,0xdb,0x48,0x33,0xc0,0xaa,0x28,0x28,0x12,
|
||||
0xa0,0x9e,0x39,0x84,0x71,0x97,0xec,0x19,0x33,0x91,0xaa,0x08,0x18,0x41,0xa3,0xcc,0x2a,0x23,0xa1,0x98,
|
||||
0x8a,0x8a,0x16,0x82,0x9c,0x09,0x83,0x02,0x18,0xac,0x98,0x15,0xa1,0x77,0xc0,0x9f,0x20,0x14,0x99,0x8a,
|
||||
0x81,0x01,0x22,0xa8,0xae,0x11,0x23,0xa9,0x99,0x98,0x20,0x24,0xb8,0xac,0x30,0x23,0x89,0xa9,0xb9,0x50,
|
||||
0x51,0x49,0x67,0xfa,0x0d,0x31,0x02,0xaa,0x1a,0x10,0x11,0x12,0xe9,0x9b,0x42,0x83,0xb9,0x8a,0x18,0x21,
|
||||
0x83,0xd8,0x8b,0x31,0x04,0xa8,0x9a,0x08,0x12,0x86,0x59,0x57,0xfa,0x8d,0x32,0x02,0xba,0x09,0x11,0x02,
|
||||
0x11,0xba,0xad,0x33,0x14,0xab,0x8c,0x81,0x13,0x10,0xab,0xba,0x34,0x33,0xcb,0xab,0x22,0x42,0x09,0x6a,
|
||||
0x77,0xe9,0x8d,0x31,0x84,0xa9,0x1a,0x11,0x81,0x02,0x9a,0x8d,0x21,0x04,0x9a,0x8c,0x00,0x03,0x10,0x8c,
|
||||
0xa9,0x03,0x14,0x0a,0xab,0x92,0x14,0x10,0xab,0x77,0xc5,0xaf,0x30,0x14,0x99,0x9b,0x11,0x03,0x01,0x99,
|
||||
0xbb,0x11,0x26,0x98,0xac,0x08,0x13,0x82,0xaa,0x9b,0x31,0x43,0xb8,0xcb,0x41,0x32,0xb9,0xd8,0x77,0x93,
|
||||
0xef,0x18,0x32,0x90,0x9c,0x10,0x12,0x18,0x99,0xa9,0x10,0x52,0x88,0xcb,0x08,0x41,0x00,0xb9,0x99,0x30,
|
||||
0x22,0xb0,0xc9,0x29,0x51,0x81,0xb9,0x77,0x94,0xcf,0x29,0x43,0xa0,0xab,0x20,0x22,0x08,0xa0,0xba,0x49,
|
||||
0x53,0xb0,0xd9,0x18,0x21,0x80,0xb8,0x99,0x48,0x21,0xc1,0xb8,0x19,0x68,0x02,0xd1,0x72,0x84,0xdf,0x08,
|
||||
0x24,0x98,0xaa,0x20,0x12,0x08,0x88,0xba,0x20,0x44,0x98,0xac,0x18,0x31,0x18,0xaa,0xba,0x30,0x25,0xb0,
|
||||
0xbb,0x38,0x61,0x80,0xc8,0x77,0x92,0xcf,0x18,0x33,0xa0,0xac,0x11,0x12,0x00,0x98,0xaa,0x28,0x35,0xb0,
|
||||
0xbc,0x10,0x23,0x90,0xaa,0x9b,0x30,0x16,0xa0,0x9c,0x18,0x05,0x81,0x1b,0x77,0xc2,0xbf,0x30,0x14,0xb8,
|
||||
0x8b,0x21,0x12,0x10,0x99,0x9d,0x30,0x15,0xa9,0xab,0x21,0x21,0x98,0xca,0x80,0x32,0x82,0xca,0x99,0x41,
|
||||
0x21,0xb8,0x78,0x77,0xfb,0x0a,0x42,0x81,0xba,0x18,0x21,0x01,0x81,0xbb,0x0c,0x35,0x81,0xac,0x1a,0x12,
|
||||
0x01,0x89,0xbb,0x08,0x35,0x81,0xad,0x88,0x04,0x11,0x1b,0x77,0xd2,0xae,0x20,0x14,0xa8,0x8b,0x11,0x12,
|
||||
0x10,0xa8,0xbc,0x51,0x23,0xca,0x9a,0x11,0x12,0x88,0xb9,0x8b,0x30,0x33,0xa1,0xe9,0x09,0x51,0x01,0x70,
|
||||
0x17,0xfc,0x0b,0x43,0xa2,0xaa,0x19,0x22,0x01,0x81,0xcb,0x2b,0x45,0x91,0xac,0x19,0x31,0x80,0xb8,0xb9,
|
||||
0x28,0x44,0xa1,0xcb,0x18,0x42,0x80,0x49,0x57,0xf9,0x8c,0x31,0x83,0xba,0x1a,0x03,0x02,0x21,0xca,0x9c,
|
||||
0x53,0x02,0xcb,0x09,0x11,0x00,0x80,0xc9,0x0a,0x62,0x00,0xba,0x19,0x22,0x00,0x19,0x77,0xd3,0xaf,0x20,
|
||||
0x14,0x99,0x8b,0x01,0x12,0x30,0xa9,0xad,0x41,0x23,0xca,0x9a,0x11,0x20,0x80,0xc9,0x0b,0x68,0x02,0xb9,
|
||||
0x8a,0x21,0x12,0x91,0x77,0xa4,0xde,0x08,0x43,0x98,0x9a,0x00,0x11,0x21,0x90,0xdb,0x28,0x34,0xa8,0xab,
|
||||
0x08,0x21,0x01,0xb1,0x9f,0x3a,0x33,0xb0,0xbb,0x4a,0x21,0x93,0x74,0x17,0xed,0x0a,0x42,0x91,0xa9,0x08,
|
||||
0x10,0x12,0x93,0xca,0x1b,0x34,0x93,0xca,0x0a,0x28,0x21,0xa1,0xdb,0x0a,0x22,0x83,0xc9,0x8b,0x10,0x06,
|
||||
0x70,0x27,0xfa,0x8c,0x31,0x02,0xaa,0x0a,0x10,0x22,0x13,0xca,0x9c,0x42,0x13,0x9a,0x9c,0x00,0x31,0x00,
|
||||
0xe9,0xa9,0x40,0x11,0xb8,0xa9,0x39,0x68,0x78,0x07,0xe9,0x0c,0x30,0x83,0xb9,0x1a,0x18,0x12,0x04,0xa9,
|
||||
0x8d,0x31,0x14,0x9a,0x9b,0x00,0x22,0x02,0xda,0xab,0x31,0x33,0xbb,0xbc,0x01,0x61,0x79,0x27,0xfa,0x0c,
|
||||
0x30,0x82,0x99,0x0a,0x08,0x03,0x15,0x9a,0x8d,0x22,0x12,0x8a,0xaa,0x80,0x41,0x30,0xea,0x99,0x20,0x21,
|
||||
0xa9,0xa9,0x1b,0x58,0x71,0x37,0xfb,0x0d,0x21,0x92,0xa8,0x09,0x88,0x22,0x24,0xba,0x9c,0x23,0x23,0x0a,
|
||||
0xc9,0xc0,0x41,0x30,0xc9,0xc8,0x20,0x28,0x88,0xb0,0x1c,0x0a,0x73,0x17,0xeb,0x1b,0x21,0x92,0x08,0x8a,
|
||||
0xba,0x34,0x24,0xab,0xa9,0x04,0x30,0x20,0xd0,0x99,0x69,0x10,0xa0,0x98,0x0a,0x28,0x11,0xaa,0x9c,0x08,
|
||||
0x79,0x17,0xdd,0x28,0x00,0x90,0x82,0xba,0x39,0x24,0x90,0x09,0x80,0x01,0x16,0xa8,0x08,0x30,0x4a,0x19,
|
||||
0xa9,0xb8,0x96,0x00,0x1c,0x9a,0x98,0x01,0x7f,0xc7,0x99,0x11,0x1a,0x80,0xb0,0x29,0x23,0xa8,0x11,0x2a,
|
||||
0x93,0xa7,0x92,0x69,0x2a,0x88,0x91,0x2a,0x88,0xb2,0x89,0xe0,0x25,0x8f,0x32,0x8f,0x2a,0xc2,0xa5,0x18,
|
||||
0x39,0x8f,0x84,0xa0,0x10,0xa0,0x01,0x41,0x2d,0x09,0xc2,0x90,0x82,0xf3,0x88,0x31,0x9c,0x32,0xba,0xa1,
|
||||
0x83,0x88,0xa7,0x3c,0x22,0x1f,0xc5,0x91,0x21,0x1e,0x90,0xb2,0x11,0x2b,0xc0,0x81,0x97,0x5a,0x1a,0xb8,
|
||||
0xa3,0x94,0x1b,0x83,0x0b,0x18,0x98,0x30,0xf5,0x28,0x91,0x7b,0xa8,0xd3,0x93,0x10,0x2e,0x88,0xb1,0x13,
|
||||
0x1e,0x01,0xe1,0x21,0x89,0x3a,0xc0,0x48,0xc0,0x80,0x94,0x90,0x21,0x0d,0x10,0x91,0x0a,0xb2,0x39,0x08,
|
||||
0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x88,0x00,0x88,0x00,0x08,0x08,0x08,0x08,0x88,0x80,0x80,
|
||||
0x80,0x80,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x29,0x8c,0x84,0xa2,0x1b,0x38,0x7a,0x8a,0xa8,0xa4,0x20,0x08,0x0f,0xa4,0x90,0x94,0x1c,0x33,0x0f,0x00,
|
||||
0x09,0x92,0xd0,0x02,0x1a,0x80,0xb3,0x28,0x28,0x0f,0x92,0x88,0x82,0x2c,0xa1,0x13,0xf0,0x40,0x9a,0x95,
|
||||
0x98,0x18,0x80,0x3b,0x3f,0x4b,0xb1,0x91,0x11,0x3f,0x18,0x8a,0xa2,0xa0,0x04,0x2a,0x6c,0x1c,0x28,0x9a,
|
||||
0xb4,0x38,0x40,0x0f,0x81,0xb0,0x84,0x8b,0x52,0x0d,0x10,0x90,0x11,0xd8,0x20,0xc0,0x20,0xe2,0x10,0x81,
|
||||
0x4b,0x2c,0xa8,0x93,0x6a,0x88,0x88,0xe3,0x28,0x88,0x18,0xb0,0x02,0x59,0x80,0x0e,0x03,0x19,0xb0,0x0e,
|
||||
0x80,0x15,0xca,0x41,0x08,0x3a,0xb9,0x2e,0xa5,0x09,0x80,0x08,0x24,0xcb,0x85,0x8c,0x13,0xb0,0x1a,0x84,
|
||||
0x2f,0x12,0x9d,0xa2,0x10,0x86,0x0a,0xa8,0x4c,0x83,0x8a,0xc1,0x38,0x22,0x9b,0xca,0xa2,0x07,0x09,0x3b,
|
||||
0x88,0x04,0xd8,0x1b,0x95,0x01,0x91,0x99,0x98,0x7b,0x49,0xa8,0xa1,0xc4,0x7b,0x18,0x0a,0xb1,0xc4,0x12,
|
||||
0x1c,0x59,0xc8,0x82,0xb2,0x49,0x0a,0x4c,0xd2,0x91,0x83,0x19,0x20,0x0f,0x91,0x98,0x23,0xc8,0x18,0x90,
|
||||
0x4c,0x01,0xa9,0xa5,0x08,0x21,0x9a,0xa9,0x3b,0x85,0xb3,0x82,0xb8,0xb8,0x06,0x7a,0x0a,0x99,0xb0,0x34,
|
||||
0x01,0x4b,0xea,0xa3,0xa5,0x4b,0x1a,0x1b,0xa6,0x90,0x08,0x2c,0x41,0xd2,0x90,0xa4,0x29,0x20,0x0e,0x93,
|
||||
0xc0,0x99,0x28,0x38,0x89,0x14,0x12,0x48,0x08,0xc0,0x9a,0x18,0xbf,0x11,0xc8,0x48,0x9a,0x4b,0x14,0x10,
|
||||
0x13,0xa9,0x70,0xa2,0xad,0xa0,0xbb,0x48,0x02,0x21,0x04,0x1a,0x39,0x99,0x85,0x82,0x19,0xbb,0xeb,0x91,
|
||||
0x18,0x4a,0x98,0xb0,0x84,0x29,0x58,0x81,0xb2,0x77,0xa4,0x9f,0x90,0x99,0x51,0x10,0x08,0x92,0xa9,0x58,
|
||||
0x00,0x88,0xa3,0xba,0x1b,0x99,0x90,0x07,0x98,0x29,0x19,0x1a,0x05,0x92,0x28,0xa9,0x77,0xb5,0xaf,0x10,
|
||||
0x88,0x30,0x14,0xa9,0x19,0xa8,0x18,0x16,0x98,0x89,0x99,0x8b,0x22,0x82,0x29,0x89,0x9d,0x81,0x13,0x62,
|
||||
0x00,0xba,0xc0,0x77,0xa3,0xbf,0x08,0x00,0x40,0x22,0xc8,0x98,0x00,0x29,0x14,0xc2,0x9a,0x1a,0x0c,0x12,
|
||||
0x94,0x99,0x19,0x8a,0x12,0x07,0x88,0x2b,0x9a,0xb2,0x77,0x94,0xdc,0x09,0x10,0x20,0x22,0xc0,0x8b,0x30,
|
||||
0x00,0x13,0xb1,0xaf,0x19,0x82,0x11,0x01,0xbc,0x98,0x14,0x20,0x20,0xba,0x9c,0x31,0x30,0x7a,0x57,0xfb,
|
||||
0x0b,0x21,0x82,0x11,0x90,0x9e,0x11,0x03,0x08,0x09,0xbc,0x08,0x15,0x08,0x09,0xb9,0x88,0x63,0x00,0x9a,
|
||||
0x90,0x98,0x51,0x10,0xba,0x77,0xa1,0xbf,0x28,0x13,0x00,0x00,0xd9,0x1a,0x43,0xa1,0x98,0x99,0x8b,0x53,
|
||||
0x93,0xab,0x1a,0x80,0x22,0x14,0xcb,0x0b,0x22,0x82,0x10,0x9a,0x9f,0x77,0xd2,0x9e,0x11,0x03,0x08,0x08,
|
||||
0xba,0x28,0x35,0xa9,0xab,0x01,0x18,0x60,0x90,0xbb,0x20,0x32,0x0a,0x88,0xe8,0x18,0x42,0x08,0xaa,0xc8,
|
||||
0x28,0x77,0xd2,0x9f,0x21,0x12,0x89,0x89,0x98,0x38,0x43,0xc8,0xab,0x21,0x11,0x18,0xb0,0xdb,0x48,0x33,
|
||||
0xc0,0xaa,0x28,0x28,0x12,0xa0,0x9e,0x39,0x84,0x71,0x97,0xec,0x19,0x33,0x91,0xaa,0x08,0x18,0x41,0xa3,
|
||||
0xcc,0x2a,0x23,0xa1,0x98,0x8a,0x8a,0x16,0x82,0x9c,0x09,0x83,0x02,0x18,0xac,0x98,0x15,0xa1,0x77,0xc0,
|
||||
0x9f,0x20,0x14,0x99,0x8a,0x81,0x01,0x22,0xa8,0xae,0x11,0x23,0xa9,0x99,0x98,0x20,0x24,0xb8,0xac,0x30,
|
||||
0x23,0x89,0xa9,0xb9,0x50,0x51,0x49,0x67,0xfa,0x0d,0x31,0x02,0xaa,0x1a,0x10,0x11,0x12,0xe9,0x9b,0x42,
|
||||
0x83,0xb9,0x8a,0x18,0x21,0x83,0xd8,0x8b,0x31,0x04,0xa8,0x9a,0x08,0x12,0x86,0x59,0x57,0xfa,0x8d,0x32,
|
||||
0x02,0xba,0x09,0x11,0x02,0x11,0xba,0xad,0x33,0x14,0xab,0x8c,0x81,0x13,0x10,0xab,0xba,0x34,0x33,0xcb,
|
||||
0xab,0x22,0x42,0x09,0x6a,0x77,0xe9,0x8d,0x31,0x84,0xa9,0x1a,0x11,0x81,0x02,0x9a,0x8d,0x21,0x04,0x9a,
|
||||
0x8c,0x00,0x03,0x10,0x8c,0xa9,0x03,0x14,0x0a,0xab,0x92,0x14,0x10,0xab,0x77,0xc5,0xaf,0x30,0x14,0x99,
|
||||
0x9b,0x11,0x03,0x01,0x99,0xbb,0x11,0x26,0x98,0xac,0x08,0x13,0x82,0xaa,0x9b,0x31,0x43,0xb8,0xcb,0x41,
|
||||
0x32,0xb9,0xd8,0x77,0x93,0xef,0x18,0x32,0x90,0x9c,0x10,0x12,0x18,0x99,0xa9,0x10,0x52,0x88,0xcb,0x08,
|
||||
0x41,0x00,0xb9,0x99,0x30,0x22,0xb0,0xc9,0x29,0x51,0x81,0xb9,0x77,0x94,0xcf,0x29,0x43,0xa0,0xab,0x20,
|
||||
0x22,0x08,0xa0,0xba,0x49,0x53,0xb0,0xd9,0x18,0x21,0x80,0xb8,0x99,0x48,0x21,0xc1,0xb8,0x19,0x68,0x02,
|
||||
0xd1,0x72,0x84,0xdf,0x08,0x24,0x98,0xaa,0x20,0x12,0x08,0x88,0xba,0x20,0x44,0x98,0xac,0x18,0x31,0x18,
|
||||
0xaa,0xba,0x30,0x25,0xb0,0xbb,0x38,0x61,0x80,0xc8,0x77,0x92,0xcf,0x18,0x33,0xa0,0xac,0x11,0x12,0x00,
|
||||
0x98,0xaa,0x28,0x35,0xb0,0xbc,0x10,0x23,0x90,0xaa,0x9b,0x30,0x16,0xa0,0x9c,0x18,0x05,0x81,0x1b,0x77,
|
||||
0xc2,0xbf,0x30,0x14,0xb8,0x8b,0x21,0x12,0x10,0x99,0x9d,0x30,0x15,0xa9,0xab,0x21,0x21,0x98,0xca,0x80,
|
||||
0x32,0x82,0xca,0x99,0x41,0x21,0xb8,0x78,0x77,0xfb,0x0a,0x42,0x81,0xba,0x18,0x21,0x01,0x81,0xbb,0x0c,
|
||||
0x35,0x81,0xac,0x1a,0x12,0x01,0x89,0xbb,0x08,0x35,0x81,0xad,0x88,0x04,0x11,0x1b,0x77,0xd2,0xae,0x20,
|
||||
0x14,0xa8,0x8b,0x11,0x12,0x10,0xa8,0xbc,0x51,0x23,0xca,0x9a,0x11,0x12,0x88,0xb9,0x8b,0x30,0x33,0xa1,
|
||||
0xe9,0x09,0x51,0x01,0x70,0x17,0xfc,0x0b,0x43,0xa2,0xaa,0x19,0x22,0x01,0x81,0xcb,0x2b,0x45,0x91,0xac,
|
||||
0x19,0x31,0x80,0xb8,0xb9,0x28,0x44,0xa1,0xcb,0x18,0x42,0x80,0x49,0x57,0xf9,0x8c,0x31,0x83,0xba,0x1a,
|
||||
0x03,0x02,0x21,0xca,0x9c,0x53,0x02,0xcb,0x09,0x11,0x00,0x80,0xc9,0x0a,0x62,0x00,0xba,0x19,0x22,0x00,
|
||||
0x19,0x77,0xd3,0xaf,0x20,0x14,0x99,0x8b,0x01,0x12,0x30,0xa9,0xad,0x41,0x23,0xca,0x9a,0x11,0x20,0x80,
|
||||
0xc9,0x0b,0x68,0x02,0xb9,0x8a,0x21,0x12,0x91,0x77,0xa4,0xde,0x08,0x43,0x98,0x9a,0x00,0x11,0x21,0x90,
|
||||
0xdb,0x28,0x34,0xa8,0xab,0x08,0x21,0x01,0xb1,0x9f,0x3a,0x33,0xb0,0xbb,0x4a,0x21,0x93,0x74,0x17,0xed,
|
||||
0x0a,0x42,0x91,0xa9,0x08,0x10,0x12,0x93,0xca,0x1b,0x34,0x93,0xca,0x0a,0x28,0x21,0xa1,0xdb,0x0a,0x22,
|
||||
0x83,0xc9,0x8b,0x10,0x06,0x70,0x27,0xfa,0x8c,0x31,0x02,0xaa,0x0a,0x10,0x22,0x13,0xca,0x9c,0x42,0x13,
|
||||
0x9a,0x9c,0x00,0x31,0x00,0xe9,0xa9,0x40,0x11,0xb8,0xa9,0x39,0x68,0x78,0x07,0xe9,0x0c,0x30,0x83,0xb9,
|
||||
0x1a,0x18,0x12,0x04,0xa9,0x8d,0x31,0x14,0x9a,0x9b,0x00,0x22,0x02,0xda,0xab,0x31,0x33,0xbb,0xbc,0x01,
|
||||
0x61,0x79,0x27,0xfa,0x0c,0x30,0x82,0x99,0x0a,0x08,0x03,0x15,0x9a,0x8d,0x22,0x12,0x8a,0xaa,0x80,0x41,
|
||||
0x30,0xea,0x99,0x20,0x21,0xa9,0xa9,0x1b,0x58,0x71,0x37,0xfb,0x0d,0x21,0x92,0xa8,0x09,0x88,0x22,0x24,
|
||||
0xba,0x9c,0x23,0x23,0x0a,0xc9,0xc0,0x41,0x30,0xc9,0xc8,0x20,0x28,0x88,0xb0,0x1c,0x0a,0x73,0x17,0xeb,
|
||||
0x1b,0x21,0x92,0x08,0x8a,0xba,0x34,0x24,0xab,0xa9,0x04,0x30,0x20,0xd0,0x99,0x69,0x10,0xa0,0x98,0x0a,
|
||||
0x28,0x11,0xaa,0x9c,0x08,0x79,0x17,0xdd,0x28,0x00,0x90,0x82,0xba,0x39,0x24,0x90,0x09,0x80,0x01,0x16,
|
||||
0xa8,0x08,0x30,0x4a,0x19,0xa9,0xb8,0x96,0x00,0x1c,0x9a,0x98,0x01,0x7f,0xc7,0x99,0x11,0x1a,0x80,0xb0,
|
||||
0x29,0x23,0xa8,0x11,0x2a,0x93,0xa7,0x92,0x69,0x2a,0x88,0x91,0x2a,0x88,0xb2,0x89,0xe0,0x25,0x8f,0x32,
|
||||
0x8f,0x2a,0xc2,0xa5,0x18,0x39,0x8f,0x84,0xa0,0x10,0xa0,0x01,0x41,0x2d,0x09,0xc2,0x90,0x82,0xf3,0x88,
|
||||
0x31,0x9c,0x32,0xba,0xa1,0x83,0x88,0xa7,0x3c,0x22,0x1f,0xc5,0x91,0x21,0x1e,0x90,0xb2,0x11,0x2b,0xc0,
|
||||
0x81,0x97,0x5a,0x1a,0xb8,0xa3,0x94,0x1b,0x83,0x0b,0x18,0x98,0x30,0xf5,0x28,0x91,0x7b,0xa8,0xd3,0x93,
|
||||
0x10,0x2e,0x88,0xb1,0x13,0x1e,0x01,0xe1,0x21,0x89,0x3a,0xc0,0x48,0xc0,0x80,0x94,0x90,0x21,0x0d,0x10,
|
||||
0x91,0x0a,0xb2,0x39,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x88,0x00,0x88,0x00,0x08,0x08,
|
||||
0x08,0x08,0x88,0x80,0x80,0x80,0x80,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
@@ -483,9 +329,10 @@ static const uint8_t gpsOffData[] = {
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,
|
||||
};
|
||||
static constexpr VoiceClip gpsOffClip = {
|
||||
gpsOffData, sizeof(gpsOffData), 9237, 8000
|
||||
gpsOffData, sizeof(gpsOffData), 9237, 8000, gpsData, sizeof(gpsData)
|
||||
};
|
||||
}} // namespace mesh::audio
|
||||
@@ -78,13 +78,7 @@ class GpsVoicePlayer {
|
||||
public:
|
||||
bool start(VoiceClip clip) {
|
||||
stop();
|
||||
#if defined(MESH_GPS_VOICE_G726_BITRATE)
|
||||
if (!clip.valid() || !HwPWM3.takeOwnership(OWNER)) return false;
|
||||
#else
|
||||
if (!clip.data || !clip.samples || clip.samples > clip.bytes * 2
|
||||
|| (clip.sample_rate != 8000 && clip.sample_rate != 16000)
|
||||
|| !HwPWM3.takeOwnership(OWNER)) return false;
|
||||
#endif
|
||||
owned_ = true;
|
||||
if (!HwPWM3.addPin(PIN_BUZZER)) { stop(); return false; }
|
||||
decoder_.begin(clip);
|
||||
|
||||
+66
@@ -0,0 +1,66 @@
|
||||
#include <cassert>
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <initializer_list>
|
||||
#define PIN_BUZZER 25
|
||||
#define MESH_BUTTON_AUDIO_HIL 1
|
||||
#if defined(MESH_GPS_VOICE_G726_BITRATE)
|
||||
#include <helpers/ui/G726VoiceData.h>
|
||||
#else
|
||||
#include <helpers/ui/ButtonVoiceData.h>
|
||||
#include <helpers/ui/GpsVoiceData.h>
|
||||
#endif
|
||||
#include <helpers/ui/nrf52/GpsVoicePlayer.h>
|
||||
uint32_t now_ms=0;
|
||||
int main() {
|
||||
using namespace mesh::audio;
|
||||
const VoiceClip clips[]={readyClip,notificationClearedClip,advertQueuedClip,
|
||||
advertFailedClip,soundOnClip,soundOffClip,actionFailedClip,usbSetupClip,
|
||||
shuttingDownClip,restartingClip,gpsOnClip,gpsOffClip,
|
||||
#ifdef HAS_DRV2605
|
||||
alertsSoundVibrationClip,alertsSoundOnlyClip,alertsVibrationOnlyClip,alertsSilentClip,
|
||||
#endif
|
||||
};
|
||||
for (auto clip:clips) {
|
||||
#ifdef PWM_OUTPUT
|
||||
GpsVoicePlayer player;
|
||||
assert(player.setGain(2));
|
||||
assert(player.start(clip));
|
||||
uint16_t first[2][128];
|
||||
for(unsigned i=0;i<2;++i)
|
||||
std::memcpy(first[i],reinterpret_cast<const void*>(registers.SEQ[i].PTR),sizeof(first[i]));
|
||||
unsigned sequence=0,events=0;
|
||||
while (player.playing()) {
|
||||
assert(++events<1000);
|
||||
const auto data=reinterpret_cast<const uint16_t*>(registers.SEQ[sequence].PTR);
|
||||
assert(std::fwrite(data,sizeof(*data),registers.SEQ[sequence].CNT,stdout)==registers.SEQ[sequence].CNT);
|
||||
registers.EVENTS_SEQEND[sequence]=1;player.interrupt();sequence^=1;
|
||||
}
|
||||
assert(player.played()==clip.samples);
|
||||
assert(player.completed()==1&&player.cancelled()==0);
|
||||
player.service();assert(!player.active()&&!HwPWM3.owned&&!irq_enabled);
|
||||
// Cancel before and after the GPS prefix seam, then restart. A tail must
|
||||
// never inherit another announcement's adaptive/interpolation state.
|
||||
for(unsigned fraction:{1u,3u}) {
|
||||
assert(player.start(clip));unsigned seq=0;
|
||||
while(player.playing()&&player.played()<clip.samples*fraction/4) {
|
||||
registers.EVENTS_SEQEND[seq]=1;player.interrupt();seq^=1;
|
||||
}
|
||||
assert(player.playing());player.stop();
|
||||
assert(!player.active()&&!HwPWM3.owned&&!irq_enabled);
|
||||
assert(player.start(clip));
|
||||
for(unsigned i=0;i<2;++i)
|
||||
assert(std::memcmp(first[i],reinterpret_cast<const void*>(registers.SEQ[i].PTR),sizeof(first[i]))==0);
|
||||
player.stop();
|
||||
}
|
||||
assert(player.started()==5&&player.completed()==1&&player.cancelled()==4);
|
||||
#else
|
||||
VoiceDecoder decoder;decoder.begin(clip);
|
||||
for(uint32_t sample=0;sample<clip.samples;++sample) {
|
||||
assert(!decoder.done());const int16_t value=decoder.next();
|
||||
assert(std::fwrite(&value,sizeof(value),1,stdout)==1);
|
||||
}
|
||||
assert(decoder.done()&&decoder.position()==clip.samples&&decoder.next()==0);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -59,8 +59,9 @@ int main(){
|
||||
for(const auto& entry:mappings){
|
||||
auto actual=buttonVoiceClip(entry.prompt);
|
||||
assert(actual.data==entry.clip.data&&actual.bytes==entry.clip.bytes);
|
||||
assert(actual.prefix==entry.clip.prefix&&actual.prefix_bytes==entry.clip.prefix_bytes);
|
||||
assert(actual.samples==entry.clip.samples&&actual.sample_rate==entry.clip.sample_rate);
|
||||
assert(actual.data&&actual.bytes==(actual.samples+1)/2);
|
||||
assert(actual.valid()&&actual.bytes+actual.prefix_bytes==(actual.samples+1)/2);
|
||||
assert(actual.sample_rate==8000||actual.sample_rate==16000);
|
||||
VoiceDecoder decoder;decoder.begin(actual);
|
||||
unsigned count=0,nonzero=0;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
"""Validate the fixed prerecorded catalog without speech synthesis or hardware."""
|
||||
from pathlib import Path
|
||||
import hashlib
|
||||
import importlib.util
|
||||
import re
|
||||
import shutil
|
||||
import struct
|
||||
@@ -64,22 +65,69 @@ def write_wav(path, samples, *, rate=8000, channels=1, width=2):
|
||||
wav.writeframes(payload)
|
||||
|
||||
|
||||
def parse_header(source):
|
||||
arrays = {
|
||||
def select_vibration(source, enabled=True):
|
||||
"""Select the generated catalog's HAS_DRV2605 branches for asset tests."""
|
||||
lines = []
|
||||
stack = [True]
|
||||
for line in source.splitlines():
|
||||
if line == '#ifdef HAS_DRV2605':
|
||||
stack.append(stack[-1] and enabled)
|
||||
elif line == '#else' and len(stack) > 1:
|
||||
stack[-1] = stack[-2] and not stack[-1]
|
||||
elif line == '#endif // HAS_DRV2605':
|
||||
stack.pop()
|
||||
elif stack[-1]:
|
||||
lines.append(line)
|
||||
assert len(stack) == 1
|
||||
return '\n'.join(lines)
|
||||
|
||||
|
||||
def parse_header(source, has_drv2605=True):
|
||||
source = select_vibration(source, has_drv2605)
|
||||
spans = {
|
||||
name: bytes(int(value, 16) for value in re.findall(r"0x([0-9a-fA-F]{2})", body))
|
||||
for name, body in re.findall(
|
||||
r"static const uint8_t (\w+)Data\[\] = \{(.*?)\};", source, re.S)
|
||||
}
|
||||
clips = {
|
||||
name: (data, size, int(samples), int(rate))
|
||||
for name, data, size, samples, rate in re.findall(
|
||||
arrays, clips = {}, {}
|
||||
for name, data, size, samples, rate, prefix, prefix_size in re.findall(
|
||||
r"static constexpr VoiceClip (\w+)Clip = \{\s*"
|
||||
r"(\w+)Data, sizeof\((\w+)Data\), (\d+), (\d+)\s*\};", source)
|
||||
}
|
||||
r"(\w+)Data, sizeof\((\w+)Data\), (\d+), (\d+)"
|
||||
r"(?:, (\w+)Data, sizeof\((\w+)Data\))?\s*\};", source):
|
||||
assert data == size and prefix == prefix_size
|
||||
clips[name] = (data, size, int(samples), int(rate))
|
||||
arrays[name] = (spans[prefix] if prefix else b'') + spans[data]
|
||||
return arrays, clips
|
||||
|
||||
|
||||
class EncoderTests(unittest.TestCase):
|
||||
def test_profitable_prefix_groups_regenerate_exact_phrases_for_both_board_policies(self):
|
||||
with tempfile.TemporaryDirectory() as temporary:
|
||||
directory = Path(temporary)
|
||||
samples = self.fixtures(directory)
|
||||
common = [((i*997)%18001)-9000 for i in range(257)]
|
||||
for name, tail in (('advertQueued',[1000,-1000]), ('advertFailed',[-3000,3000]),
|
||||
('soundOff',[2000,-2000]), ('alertsSoundOnly',[-4000,4000])):
|
||||
samples[name] = common+tail*80
|
||||
write_wav(directory/(name+'.wav'), samples[name])
|
||||
source = directory/'shared.h'
|
||||
self.assertEqual(self.generate(directory,source).returncode,0)
|
||||
header = source.read_text()
|
||||
self.assertIn('advertPrefixData',header)
|
||||
self.assertIn('soundPrefixData',header)
|
||||
# Compare to the original independently encoded fixture bytes.
|
||||
spec = importlib.util.spec_from_file_location(
|
||||
'fixture_gps_encoder',ROOT/'scripts/generate_gps_voice.py')
|
||||
encoder = importlib.util.module_from_spec(spec)
|
||||
spec.loader.exec_module(encoder)
|
||||
for vibration in (False,True):
|
||||
arrays, clips = parse_header(header,vibration)
|
||||
names = CATALOG if vibration else CATALOG[:10]
|
||||
for name,_ in names:
|
||||
self.assertEqual(arrays[name],encoder.encode(samples[name]))
|
||||
self.assertEqual(clips[name],(name,name,len(samples[name]),8000))
|
||||
self.assertEqual('soundPrefixData' in select_vibration(header,vibration),vibration)
|
||||
|
||||
def fixtures(self, directory):
|
||||
samples = {}
|
||||
for index, (name, _) in enumerate(CATALOG):
|
||||
@@ -175,12 +223,12 @@ class EncoderTests(unittest.TestCase):
|
||||
self.assertEqual(clips[name], (name, name, samples, 8000))
|
||||
|
||||
def assert_x1_only_recordings_are_guarded(self, source):
|
||||
start = source.index('#ifdef HAS_DRV2605')
|
||||
end = source.index('#endif', start)
|
||||
self.assertLess(source.index('restartingClip'), start)
|
||||
for name, _ in CATALOG[10:]:
|
||||
self.assertLess(start, source.index(name+'Data'))
|
||||
self.assertLess(source.index(name+'Clip'), end)
|
||||
arrays, clips = parse_header(source, has_drv2605=False)
|
||||
self.assertEqual(tuple(arrays), tuple(name for name, _ in CATALOG[:10]))
|
||||
self.assertEqual(tuple(clips), tuple(arrays))
|
||||
# The optional shared Sound prefix must not add storage on boards
|
||||
# which have no sound-only alert-mode announcement.
|
||||
self.assertNotIn('soundPrefixData', select_vibration(source, False))
|
||||
|
||||
def test_changed_source_wav_replaces_only_its_matching_clip(self):
|
||||
with tempfile.TemporaryDirectory() as temporary:
|
||||
|
||||
+34
-1
@@ -17,7 +17,8 @@ ROOT = Path(__file__).resolve().parents[1]
|
||||
CC = shutil.which('gcc')
|
||||
CXX = shutil.which('g++')
|
||||
DECODER = ROOT / 'src/helpers/ui/g726/g726_decoder.c'
|
||||
SANITIZERS = (['-fsanitize=address,undefined', '-fno-omit-frame-pointer']
|
||||
SANITIZERS = (['-fsanitize=address,undefined', '-fno-sanitize-recover=all',
|
||||
'-fno-omit-frame-pointer', '-fno-pie', '-no-pie']
|
||||
if os.environ.get('MESH_G726_TEST_SANITIZERS') == '1' else [])
|
||||
|
||||
# FFmpeg 7.1 g726 encoder/decoder, 8 kHz mono, continuous MSB-first packing.
|
||||
@@ -230,6 +231,38 @@ class Tests(unittest.TestCase):
|
||||
for bitrate in VECTORS:
|
||||
with self.subTest(bitrate=bitrate):self.build(self.fixture(PLAYER_MAIN,bitrate),bitrate)
|
||||
|
||||
def test_segmented_stream_preserves_cross_byte_codes_adaptive_state_and_bounds(self):
|
||||
source = DECODE_MAIN.split('int main(){', 1)[1].split(' assert(full.valid()', 1)[0]
|
||||
source = 'int main(){' + source + r'''
|
||||
for(size_t split=0;split<sizeof(data);++split){
|
||||
VoiceClip clip{data+split,sizeof(data)-split,count,8000,codec,data,split};
|
||||
assert(clip.valid());VoiceDecoder decoder;decoder.begin(clip);
|
||||
for(unsigned i=0;i<count;++i){assert(!decoder.done());assert(decoder.next()==expected[i]);}
|
||||
assert(decoder.done()&&decoder.position()==count);
|
||||
for(size_t tail=0;tail<sizeof(data)-split;++tail){
|
||||
std::vector<uint8_t> prefix(data,data+split),suffix(data+split,data+split+tail);
|
||||
// A non-null placeholder is legal when the suffix's declared length is
|
||||
// zero. ASan bounds the actual prefix/tail allocation independently.
|
||||
VoiceClip short_clip{tail?suffix.data():data,tail,count,8000,codec,
|
||||
split?prefix.data():nullptr,split};
|
||||
assert(!short_clip.valid());decoder.begin(short_clip);
|
||||
const unsigned available=static_cast<unsigned>((split+tail)*8/bits);
|
||||
for(unsigned i=0;i<available;++i){assert(!decoder.done());assert(decoder.next()==expected[i]);}
|
||||
assert(decoder.done()&&decoder.position()==available&&decoder.next()==0);
|
||||
}
|
||||
}
|
||||
VoiceClip missing_prefix{data,sizeof(data),count,8000,codec,nullptr,1};
|
||||
assert(!missing_prefix.valid());VoiceDecoder decoder;decoder.begin(missing_prefix);
|
||||
assert(decoder.done()&&decoder.next()==0);
|
||||
VoiceClip huge{data,std::numeric_limits<size_t>::max(),
|
||||
std::numeric_limits<uint32_t>::max(),8000,codec,data,1};
|
||||
assert(huge.valid()&&huge.hasBytes(std::numeric_limits<size_t>::max()));
|
||||
GpsVoicePlayer player;assert(!player.start(missing_prefix)&&!player.active());
|
||||
}
|
||||
'''
|
||||
for bitrate in VECTORS:
|
||||
with self.subTest(bitrate=bitrate):self.build(self.fixture(source,bitrate),bitrate)
|
||||
|
||||
def test_invalid_bitrates_or_missing_laboratory_gate_cannot_compile(self):
|
||||
for flags,error in (
|
||||
('#define MESH_GPS_VOICE_G726_BITRATE 16\n','opt-in MESH_BUTTON_AUDIO_HIL'),
|
||||
|
||||
@@ -12,7 +12,7 @@ from types import SimpleNamespace
|
||||
import unittest
|
||||
from unittest import mock
|
||||
|
||||
from test_button_voice_generator import CATALOG, ZIRA_RECORDINGS
|
||||
from test_button_voice_generator import CATALOG, ZIRA_RECORDINGS, select_vibration
|
||||
from test_gps_voice_generator import ZIRA_GPS_RECORDINGS
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
@@ -114,8 +114,9 @@ class CatalogTests(unittest.TestCase):
|
||||
for name in names:
|
||||
count=len(source_samples[name])
|
||||
self.assertIn(f'{name}Data, sizeof({name}Data), {count}, 8000, VoiceCodec::G726{bitrate}',body)
|
||||
self.assertEqual(body.count('#ifdef HAS_DRV2605'),4)
|
||||
self.assertEqual(body.count('#endif // HAS_DRV2605'),4)
|
||||
plain = select_vibration(body, False)
|
||||
for name in names:
|
||||
self.assertEqual(f'{name}Clip' in plain, not name.startswith('alerts'))
|
||||
|
||||
def test_invalid_source_lengths_preserve_existing_experimental_header(self):
|
||||
for count in (0,32001):
|
||||
@@ -143,30 +144,28 @@ class CatalogTests(unittest.TestCase):
|
||||
with self.subTest(bitrate=bitrate):
|
||||
body=source.split(f'#if MESH_GPS_VOICE_G726_BITRATE == {bitrate}\n',1)[1]
|
||||
body=body.split(f'#endif // {bitrate} kbps',1)[0]
|
||||
arrays={name:bytes(int(value,16) for value in re.findall(r'0x([0-9a-fA-F]{2})',data))
|
||||
for name,data in re.findall(r'static const uint8_t (\w+)Data\[\] = \{(.*?)\};',body,re.S)}
|
||||
clips={name:(data,size,int(count),int(rate),int(codec))
|
||||
for name,data,size,count,rate,codec in re.findall(
|
||||
selected = select_vibration(body)
|
||||
spans={name:bytes(int(value,16) for value in re.findall(r'0x([0-9a-fA-F]{2})',data))
|
||||
for name,data in re.findall(r'static const uint8_t (\w+)Data\[\] = \{(.*?)\};',selected,re.S)}
|
||||
arrays, clips = {}, {}
|
||||
for name,data,size,count,rate,codec,prefix,prefix_size in re.findall(
|
||||
r'static constexpr VoiceClip (\w+)Clip = \{\s*'
|
||||
r'(\w+)Data, sizeof\((\w+)Data\), (\d+), (\d+), VoiceCodec::G726(\d+)\s*\};',body)}
|
||||
r'(\w+)Data, sizeof\((\w+)Data\), (\d+), (\d+), VoiceCodec::G726(\d+)'
|
||||
r'(?:, (\w+)Data, sizeof\((\w+)Data\))?\s*\};',selected):
|
||||
self.assertEqual(data,size)
|
||||
self.assertEqual(prefix,prefix_size)
|
||||
arrays[name]=(spans[prefix] if prefix else b'')+spans[data]
|
||||
clips[name]=(data,size,int(count),int(rate),int(codec))
|
||||
self.assertEqual(tuple(arrays),names)
|
||||
self.assertEqual(tuple(clips),names)
|
||||
for name in names:
|
||||
self.assertEqual(clips[name],(name,name,samples[name],8000,bitrate))
|
||||
self.assertEqual(len(arrays[name]),(samples[name]*(bitrate//8)+7)//8)
|
||||
self.assertEqual(hashlib.sha256(arrays[name]).hexdigest(),GOLDENS[name][index],name)
|
||||
# Each optional mode must be inside a HAS_DRV2605 guard; the
|
||||
# common twelve clips must remain outside those guards.
|
||||
guarded=False
|
||||
for line in body.splitlines():
|
||||
if line=='#ifdef HAS_DRV2605':
|
||||
self.assertFalse(guarded);guarded=True
|
||||
elif line=='#endif // HAS_DRV2605':
|
||||
self.assertTrue(guarded);guarded=False
|
||||
else:
|
||||
match=re.match(r'static const uint8_t (\w+)Data',line)
|
||||
if match:self.assertEqual(guarded,match[1].startswith('alerts'),match[1])
|
||||
self.assertFalse(guarded)
|
||||
plain=select_vibration(body,False)
|
||||
self.assertNotIn('soundPrefixData',plain)
|
||||
for name in names:
|
||||
self.assertEqual(f'{name}Clip' in plain,not name.startswith('alerts'))
|
||||
|
||||
def test_cli_refuses_production_filenames_and_invalid_voice_without_touching_existing_files(self):
|
||||
with tempfile.TemporaryDirectory() as temporary:
|
||||
|
||||
@@ -451,7 +451,7 @@ class Tests(unittest.TestCase):
|
||||
self.build(PLAYER_PDM)
|
||||
source=PLAYER_PDM.replace('gpsOnClip', 'clip')
|
||||
source=source.replace('GpsVoicePlayer player;',
|
||||
'GpsVoicePlayer player; VoiceClip clip{gpsOnClip.data,gpsOnClip.bytes,gpsOnClip.samples,16000};')
|
||||
'GpsVoicePlayer player; auto clip=gpsOnClip; clip.sample_rate=16000;')
|
||||
source=source.replace('interpolator.begin();','interpolator.begin(clip.sample_rate);')
|
||||
source=source.replace('clip.samples*8','clip.samples*4')
|
||||
self.build(source)
|
||||
|
||||
@@ -7,6 +7,7 @@ import sys
|
||||
import tempfile
|
||||
import unittest
|
||||
from test_button_voice_generator import parse_header, write_wav
|
||||
import importlib.util
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
POWERSHELL = shutil.which("pwsh") or shutil.which("powershell")
|
||||
@@ -33,6 +34,37 @@ ZIRA_GPS_RECORDINGS = {
|
||||
|
||||
|
||||
class AssetTests(unittest.TestCase):
|
||||
def test_generator_shares_only_profitable_exact_encoded_prefixes(self):
|
||||
spec = importlib.util.spec_from_file_location('gps_encoder', ROOT/'scripts/generate_gps_voice.py')
|
||||
encoder = importlib.util.module_from_spec(spec)
|
||||
spec.loader.exec_module(encoder)
|
||||
for rate in (8000, 16000):
|
||||
with self.subTest(rate=rate), tempfile.TemporaryDirectory() as temporary:
|
||||
directory = Path(temporary)
|
||||
common = [((i*997)%18001)-9000 for i in range(257)]
|
||||
phrases = {'gpsOn': common+[1000,-1000]*80,
|
||||
'gpsOff': common+[-3000,3000]*77}
|
||||
for name, samples in phrases.items():
|
||||
write_wav(directory/(name+'.wav'), samples, rate=rate)
|
||||
output = directory/'shared.h'
|
||||
command = [sys.executable, str(ROOT/'scripts/generate_gps_voice.py'),
|
||||
'--on', str(directory/'gpsOn.wav'), '--off', str(directory/'gpsOff.wav'),
|
||||
'--rate', str(rate), '--output', str(output)]
|
||||
subprocess.run(command, check=True, capture_output=True, timeout=30)
|
||||
source = output.read_text()
|
||||
self.assertEqual(source.count('static const uint8_t '), 3)
|
||||
arrays, clips = parse_header(source)
|
||||
for name, samples in phrases.items():
|
||||
self.assertEqual(arrays[name], encoder.encode(samples))
|
||||
self.assertEqual(clips[name], (name,name,len(samples),rate))
|
||||
# A completely different second phrase must not add a useless
|
||||
# shared/empty blob merely to keep the nominal count at three.
|
||||
write_wav(directory/'gpsOff.wav', [3000,-3000]*80, rate=rate)
|
||||
subprocess.run(command, check=True, capture_output=True, timeout=30)
|
||||
source = output.read_text()
|
||||
self.assertEqual(source.count('static const uint8_t '), 2)
|
||||
self.assertNotIn('gpsData', source)
|
||||
|
||||
def test_production_gps_recordings_are_the_approved_zira_audio_and_metadata(self):
|
||||
source = (ROOT / 'src/helpers/ui/GpsVoiceData.h').read_text(encoding='utf-8')
|
||||
self.assertEqual([line for line in source.splitlines() if line.startswith('// Voice:')],
|
||||
|
||||
@@ -0,0 +1,145 @@
|
||||
"""Preserve original speech PCM/DMA output while sharing encoded flash spans."""
|
||||
from pathlib import Path
|
||||
import hashlib
|
||||
import os
|
||||
import re
|
||||
import shutil
|
||||
import subprocess
|
||||
import tempfile
|
||||
import unittest
|
||||
|
||||
import test_gps_voice_buttons as shared
|
||||
from test_button_voice_generator import select_vibration
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
CC, CXX = shutil.which('gcc'), shutil.which('g++')
|
||||
SANITIZERS = (['-fsanitize=address,undefined', '-fno-sanitize-recover=all',
|
||||
'-fno-omit-frame-pointer', '-fno-pie', '-no-pie']
|
||||
if os.environ.get('MESH_VOICE_TEST_SANITIZERS') == '1' else [])
|
||||
|
||||
# Pinned from the original contiguous approved catalogs and the original
|
||||
# decoder/player before any sharing changes. PCM is s16le; DMA words are u16le
|
||||
# at gain 2. These checks include every clip, final padding, IRQ refill and
|
||||
# interpolation tail, not hashes derived from the implementation under test.
|
||||
ORIGINAL_OUTPUT = {
|
||||
(0, False): ('481630ba68b1a29d5148fb1b552ca9bb78477ddc576bf9bad6d124d193dc994c',
|
||||
'7438e1cc35538956c8959adf9056aeffbd77c20e4fbd23b1204c3c17ab15a9c0'),
|
||||
(0, True): ('4e7ba541d3909bf8bbc4ae94c220f3a3d6a2304efaf53e3335a0844574475e87',
|
||||
'6b0419e83310946342b136661460eed5795fa92b23eb9da6f43056d840d0c025'),
|
||||
(16, False): ('f61a12157647ba21320ec65fb7a4bdcee260703ca593b57e5770af45076c7972',
|
||||
'f8bdd21166fe8606622abfb8cff27136612e65e61e9f18d02e95c41e62897196'),
|
||||
(16, True): ('86e13b896a20c5c77ca9dae9d71c52a1da78f7603a8c8e260a6c6c74d51567d6',
|
||||
'10fb34b5487048a738a75c2bd4388c4ff370cbaebb54ed3a52006738dd86f425'),
|
||||
(24, False): ('e37d6bbd0c7f9ddd0018c7f50d3929b1deef27b405a7432c492b2fb67c46e11b',
|
||||
'2a7815a6ea01302b0cfe2d2bb3d6a57adeeec155ba70ac8aa9e1e3965d8d54be'),
|
||||
(24, True): ('59167abf199c939cc62b3b03d9dbfcffd973c495104f89de29a6dd852100cdf2',
|
||||
'2915281db72ebe103e7599a797f0413eb7245346ba55879c4a0a9ca1f61be293'),
|
||||
}
|
||||
|
||||
|
||||
@unittest.skipUnless(CC and CXX, 'Native C/C++ compilers are required')
|
||||
class Tests(unittest.TestCase):
|
||||
def test_every_original_phrase_and_full_dma_stream_remains_bit_identical(self):
|
||||
with tempfile.TemporaryDirectory() as temporary:
|
||||
directory = Path(temporary)
|
||||
(directory/'Arduino.h').write_text(shared.ARDUINO)
|
||||
(directory/'HardwarePWM.h').write_text(shared.PWM)
|
||||
for (rate, vibration), fingerprints in ORIGINAL_OUTPUT.items():
|
||||
flags = ['-DMESH_BUTTON_AUDIO_HIL=1']
|
||||
if rate:
|
||||
flags.append(f'-DMESH_GPS_VOICE_G726_BITRATE={rate}')
|
||||
if vibration:
|
||||
flags.append('-DHAS_DRV2605=1')
|
||||
objects = []
|
||||
if rate:
|
||||
obj = directory/'g726.o'
|
||||
subprocess.run([CC, '-std=c99', '-Wall', '-Wextra', '-Werror',
|
||||
*SANITIZERS, *flags, '-I'+str(ROOT/'src'), '-c',
|
||||
str(ROOT/'src/helpers/ui/g726/g726_decoder.c'),
|
||||
'-o', str(obj)], check=True, timeout=30)
|
||||
objects.append(str(obj))
|
||||
for pwm, fingerprint in enumerate(fingerprints):
|
||||
with self.subTest(rate=rate, vibration=vibration, pwm=bool(pwm)):
|
||||
binary = directory/'catalog'
|
||||
subprocess.run([CXX, '-std=c++17', '-Wall', '-Wextra', '-Werror',
|
||||
*SANITIZERS, *flags,
|
||||
*(['-DPWM_OUTPUT=1'] if pwm else []),
|
||||
'-I'+str(directory), '-I'+str(ROOT/'src'),
|
||||
str(ROOT/'test/fixtures/voice_prefixes/catalog.cpp'),
|
||||
*objects, '-o', str(binary)], check=True, timeout=30)
|
||||
result = subprocess.run([str(binary)], check=True,
|
||||
capture_output=True, timeout=30)
|
||||
self.assertEqual(hashlib.sha256(result.stdout).hexdigest(), fingerprint)
|
||||
|
||||
def test_ima_seams_odd_lengths_truncation_and_invalid_metadata(self):
|
||||
source = r'''
|
||||
#include <cassert>
|
||||
#include <initializer_list>
|
||||
#include <limits>
|
||||
#include <vector>
|
||||
#include <helpers/ui/GpsVoice.h>
|
||||
int main(){
|
||||
using namespace mesh::audio;
|
||||
const uint8_t encoded[]={0x77,0x1f,0xca,0x26,0x84,0x92,0xbb};
|
||||
for(unsigned samples:{1u,2u,3u,7u,13u,14u}){
|
||||
VoiceDecoder original;original.begin({encoded,sizeof(encoded),samples});
|
||||
std::vector<int16_t> expected;
|
||||
while(!original.done())expected.push_back(original.next());
|
||||
for(size_t split=0;split<sizeof(encoded);++split){
|
||||
VoiceClip clip{encoded+split,sizeof(encoded)-split,samples,8000,encoded,split};
|
||||
assert(clip.valid());VoiceDecoder decoder;decoder.begin(clip);
|
||||
for(auto value:expected){assert(!decoder.done());assert(decoder.next()==value);}
|
||||
assert(decoder.done()&&decoder.position()==samples&&decoder.next()==0);
|
||||
for(size_t tail=0;tail<sizeof(encoded)-split;++tail){
|
||||
std::vector<uint8_t> prefix(encoded,encoded+split),suffix(encoded+split,encoded+split+tail);
|
||||
VoiceClip short_clip{tail?suffix.data():encoded,tail,samples,8000,
|
||||
split?prefix.data():nullptr,split};
|
||||
decoder.begin(short_clip);
|
||||
unsigned count=0;
|
||||
while(!decoder.done()){assert(decoder.next()==expected[count++]);}
|
||||
assert(count==((split+tail)*2<samples?(split+tail)*2:samples));
|
||||
assert(short_clip.valid()==(count==samples));
|
||||
}
|
||||
}
|
||||
}
|
||||
VoiceClip bad{encoded,sizeof(encoded),14,8000,nullptr,1};
|
||||
assert(!bad.valid());VoiceDecoder decoder;decoder.begin(bad);
|
||||
assert(decoder.done()&&decoder.next()==0);
|
||||
VoiceClip huge{encoded,std::numeric_limits<size_t>::max(),
|
||||
std::numeric_limits<uint32_t>::max(),8000,encoded,1};
|
||||
assert(huge.valid()&&huge.hasBytes(std::numeric_limits<size_t>::max()));
|
||||
}
|
||||
'''
|
||||
with tempfile.TemporaryDirectory() as temporary:
|
||||
directory = Path(temporary)
|
||||
path, binary = directory/'seams.cpp', directory/'seams'
|
||||
path.write_text(source)
|
||||
subprocess.run([CXX, '-std=c++17', '-Wall', '-Wextra', '-Werror',
|
||||
*SANITIZERS, '-I'+str(ROOT/'src'), str(path), '-o', str(binary)],
|
||||
check=True, timeout=30)
|
||||
subprocess.run([str(binary)], check=True, timeout=30)
|
||||
|
||||
def test_only_profitable_shared_spans_are_stored_and_optional_sound_is_gated(self):
|
||||
expected = {0: (3135, 746, 1090), 16: (1535, 268, 545), 24: (1967, 427, 817)}
|
||||
for rate, sizes in expected.items():
|
||||
if rate:
|
||||
source = (ROOT/'src/helpers/ui/G726VoiceData.h').read_text()
|
||||
source = source.split(f'#if MESH_GPS_VOICE_G726_BITRATE == {rate}\n')[1]
|
||||
source = source.split(f'#endif // {rate} kbps')[0]
|
||||
else:
|
||||
source = ((ROOT/'src/helpers/ui/GpsVoiceData.h').read_text() + '\n'
|
||||
+ (ROOT/'src/helpers/ui/ButtonVoiceData.h').read_text())
|
||||
for vibration in (False, True):
|
||||
body = select_vibration(source, vibration)
|
||||
arrays = {name:bytes.fromhex(' '.join(re.findall(r'0x([0-9a-f]{2})',data)))
|
||||
for name,data in re.findall(r'static const uint8_t (\w+)Data\[\] = \{(.*?)\};',body,re.S)}
|
||||
self.assertEqual(len(arrays['gps']), sizes[0])
|
||||
self.assertEqual(len(arrays['advertPrefix']), sizes[1])
|
||||
self.assertEqual('soundPrefix' in arrays, vibration)
|
||||
if vibration:
|
||||
self.assertEqual(len(arrays['soundPrefix']), sizes[2])
|
||||
self.assertEqual(sum(name.startswith('gps') for name in arrays), 3)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
Reference in new issue
Block a user