Skip to main content

stm_32/peripherals/
bmi08x.rs

1// ******************************************************************************
2// * File     : platforms/stm_32/src/peripherals/bmi08x.rs
3// * Date     : June 28, 2026
4// ******************************************************************************
5// *
6// * Copyright (c) 2023, AeroVironment, Inc.
7// * All rights reserved.
8// *
9// * Redistribution and use in source and binary forms, with or without
10// * modification, are permitted provided that the following conditions are met:
11// *
12// * 1.Redistributions of source code must retain the above copyright notice, this
13// * list of conditions and the following disclaimer.
14// *
15// * 2.Redistributions in binary form must reproduce the above copyright notice,
16// * this list of conditions and the following disclaimer in the documentation
17// * and/or other materials provided with the distribution.
18// *
19// * 3.Neither the name of the copyright holder nor the names of its
20// * contributors may be used to endorse or promote products derived from
21// * this software without specific prior written permission.
22// *
23// * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
24// * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25// * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
26// * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
27// * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28// * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
29// * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
30// * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
31// * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
32// * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33// *
34// ******************************************************************************
35
36use embassy_stm32::exti::ExtiInput;
37use embassy_stm32::gpio::Output;
38use embassy_stm32::mode::Async;
39use embassy_stm32::spi;
40use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
41use embassy_sync::signal::Signal;
42use embassy_time::Instant;
43use embassy_time::Timer;
44
45#[cfg(feature = "runtime-diagnostics")]
46use core::sync::atomic::{AtomicU32, Ordering};
47
48use veloxity_core::errors;
49use veloxity_core::packets;
50
51use embassy_embedded_hal::shared_bus::asynch::spi::SpiDevice;
52use embedded_hal_async::spi::SpiDevice as _;
53
54pub static IMU_SIGNAL: Signal<
55    CriticalSectionRawMutex,
56    Result<packets::ImuPacket<f64>, errors::SensorError>,
57> = Signal::<CriticalSectionRawMutex, Result<packets::ImuPacket<f64>, errors::SensorError>>::new();
58
59#[cfg(feature = "runtime-diagnostics")]
60#[unsafe(no_mangle)]
61pub static VELOXITY_DIAG_BMI_DRDY: AtomicU32 = AtomicU32::new(0);
62#[cfg(feature = "runtime-diagnostics")]
63#[unsafe(no_mangle)]
64pub static VELOXITY_DIAG_BMI_DRDY_INTERVALS: AtomicU32 = AtomicU32::new(0);
65#[cfg(feature = "runtime-diagnostics")]
66#[unsafe(no_mangle)]
67pub static VELOXITY_DIAG_BMI_DRDY_INTERVAL_SUM_US: AtomicU32 = AtomicU32::new(0);
68#[cfg(feature = "runtime-diagnostics")]
69#[unsafe(no_mangle)]
70pub static VELOXITY_DIAG_BMI_DRDY_INTERVAL_MAX_US: AtomicU32 = AtomicU32::new(0);
71#[cfg(feature = "runtime-diagnostics")]
72#[unsafe(no_mangle)]
73pub static VELOXITY_DIAG_BMI_SAMPLE_COMPLETE: AtomicU32 = AtomicU32::new(0);
74#[cfg(feature = "runtime-diagnostics")]
75#[unsafe(no_mangle)]
76pub static VELOXITY_DIAG_BMI_SAMPLE_TIME_SUM_US: AtomicU32 = AtomicU32::new(0);
77#[cfg(feature = "runtime-diagnostics")]
78#[unsafe(no_mangle)]
79pub static VELOXITY_DIAG_BMI_SAMPLE_TIME_MAX_US: AtomicU32 = AtomicU32::new(0);
80#[cfg(feature = "runtime-diagnostics")]
81#[unsafe(no_mangle)]
82pub static VELOXITY_DIAG_BMI_SENSOR_GAP_EVENTS: AtomicU32 = AtomicU32::new(0);
83#[cfg(feature = "runtime-diagnostics")]
84#[unsafe(no_mangle)]
85pub static VELOXITY_DIAG_BMI_SENSOR_MISSING: AtomicU32 = AtomicU32::new(0);
86#[cfg(feature = "runtime-diagnostics")]
87#[unsafe(no_mangle)]
88pub static VELOXITY_DIAG_BMI_SIGNAL_OVERWRITE: AtomicU32 = AtomicU32::new(0);
89#[cfg(feature = "runtime-diagnostics")]
90#[unsafe(no_mangle)]
91pub static VELOXITY_DIAG_BMI_SIGNAL_PUBLISH: AtomicU32 = AtomicU32::new(0);
92
93// 3 blocks of 2048 bytes
94// 192 blocks of 32 bytes
95static BMI_CONFIG: [u8; 6144] = [
96    0xc8, 0x2e, 0x00, 0x2e, 0x80, 0x2e, 0x48, 0xb4, 0xc8, 0x2e, 0x00, 0x2e, 0x80, 0x2e, 0x6d, 0xb4,
97    0xc8, 0x2e, 0x00, 0x2e, 0x80, 0x2e, 0xd4, 0xb3, 0x80, 0x2e, 0xb0, 0xb3, 0x80, 0x2e, 0x12, 0xb4,
98    0x50, 0x39, 0x21, 0x2e, 0xb0, 0xf0, 0x10, 0x30, 0x21, 0x2e, 0x16, 0xf0, 0x80, 0x2e, 0xfe, 0xb4,
99    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
100    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x45, 0x79, 0x80, 0x2e, 0x18, 0x00,
101    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
102    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
103    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
104    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
105    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
106    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
107    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
108    0x80, 0x2e, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
109    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
110    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
111    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
112    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
113    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
114    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
115    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x50, 0xfb, 0x7f,
116    0x98, 0x2e, 0x03, 0xb1, 0x12, 0x24, 0x67, 0x00, 0x90, 0x42, 0x81, 0x42, 0xba, 0x82, 0xd1, 0x7f,
117    0xe2, 0x7f, 0x98, 0x2e, 0x3c, 0xb0, 0xd1, 0x6f, 0x00, 0x2e, 0x41, 0x40, 0x40, 0xb2, 0x4c, 0x2f,
118    0xe1, 0x6f, 0x44, 0x86, 0x03, 0x2e, 0x67, 0x00, 0xc2, 0x40, 0xf7, 0x86, 0x4a, 0x04, 0xc1, 0x42,
119    0x00, 0x2e, 0xc2, 0x40, 0x80, 0xac, 0x01, 0x2f, 0x23, 0x2e, 0x63, 0x00, 0xd1, 0x40, 0xd2, 0x40,
120    0x0a, 0x0f, 0x01, 0x2f, 0x40, 0xac, 0x02, 0x2f, 0x01, 0x30, 0x23, 0x2e, 0x63, 0x00, 0xfe, 0x82,
121    0xc2, 0x40, 0x43, 0x40, 0xd3, 0x04, 0x46, 0x84, 0xc3, 0x7f, 0x85, 0x86, 0xc5, 0x82, 0x45, 0x80,
122    0x44, 0x40, 0xc1, 0x6f, 0xc3, 0x40, 0xe0, 0x7f, 0xd1, 0x7f, 0x00, 0x2e, 0x82, 0x40, 0x98, 0x2e,
123    0x00, 0xb0, 0xe1, 0x6f, 0x72, 0x84, 0x40, 0x42, 0x85, 0x86, 0xc5, 0x82, 0x45, 0x80, 0x44, 0x40,
124    0xc3, 0x40, 0xd1, 0x6f, 0xe0, 0x7f, 0x00, 0x2e, 0x82, 0x40, 0x98, 0x2e, 0x00, 0xb0, 0xe1, 0x6f,
125    0x72, 0x84, 0x40, 0x42, 0x85, 0x86, 0xc5, 0x82, 0x45, 0x80, 0x44, 0x40, 0xc3, 0x40, 0xd1, 0x6f,
126    0xe0, 0x7f, 0x00, 0x2e, 0x82, 0x40, 0x98, 0x2e, 0x00, 0xb0, 0xe1, 0x6f, 0x00, 0x2e, 0x40, 0x42,
127    0x98, 0x2e, 0xa5, 0xb0, 0x11, 0x30, 0x23, 0x2e, 0x5e, 0xf0, 0xfb, 0x6f, 0xc0, 0x5f, 0xb8, 0x2e,
128    0xaa, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x01, 0x00, 0xed, 0x8f, 0xd9, 0x31,
129    0x00, 0x00, 0xc6, 0x01, 0x8c, 0x03, 0xc6, 0x01, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x0e, 0x00,
130    0x00, 0x00, 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, 0x50,
131    0xf0, 0x7f, 0x00, 0x2e, 0x01, 0x2e, 0x01, 0x01, 0x02, 0xbc, 0x0f, 0xb8, 0xe0, 0x7f, 0x00, 0x2e,
132    0x01, 0x2e, 0x01, 0x01, 0x01, 0xbc, 0x0f, 0xb8, 0xd0, 0x7f, 0x00, 0x2e, 0x01, 0x2e, 0x01, 0x01,
133    0x0f, 0xb8, 0xc0, 0x7f, 0x02, 0x30, 0xe6, 0x6f, 0xd4, 0x6f, 0xc3, 0x6f, 0x80, 0x91, 0x04, 0x2f,
134    0x00, 0x91, 0x02, 0x2f, 0xc0, 0xb2, 0x90, 0x2e, 0xf6, 0x01, 0xf0, 0x6f, 0x0b, 0x2e, 0x24, 0x00,
135    0x01, 0x82, 0x40, 0x91, 0x14, 0x2f, 0x41, 0x87, 0x27, 0x2e, 0x24, 0x00, 0x00, 0x40, 0x21, 0x2e,
136    0x1b, 0x00, 0x53, 0x40, 0x10, 0x24, 0x1c, 0x00, 0x13, 0x42, 0x00, 0x2e, 0x41, 0x40, 0x01, 0x42,
137    0x25, 0x2e, 0x18, 0x00, 0x25, 0x2e, 0x19, 0x00, 0x25, 0x2e, 0x1e, 0x00, 0x50, 0x5f, 0xb8, 0x2e,
138    0x0b, 0x2e, 0x00, 0x01, 0xd5, 0xbe, 0xd5, 0xba, 0xb5, 0x7f, 0x00, 0x2e, 0x0b, 0x2e, 0x01, 0x01,
139    0xd3, 0xbe, 0xd3, 0xba, 0xa5, 0x7f, 0x00, 0x2e, 0x0b, 0x2e, 0x00, 0x01, 0xd4, 0xbe, 0xdf, 0xba,
140    0x95, 0x7f, 0x00, 0x2e, 0x95, 0x6f, 0x0f, 0x2e, 0x1a, 0x00, 0x3d, 0x1a, 0x05, 0x2f, 0x25, 0x2e,
141    0x18, 0x00, 0x25, 0x2e, 0x19, 0x00, 0x2b, 0x2e, 0x1a, 0x00, 0x80, 0x91, 0x01, 0x2f, 0x06, 0x30,
142    0x07, 0x2d, 0x06, 0x40, 0x0f, 0x2e, 0x1b, 0x00, 0xb7, 0x05, 0x80, 0xa9, 0xd6, 0x05, 0xb7, 0x23,
143    0x86, 0x7f, 0x00, 0x91, 0x01, 0x2f, 0x04, 0x30, 0x07, 0x2d, 0x44, 0x40, 0x0d, 0x2e, 0x1c, 0x00,
144    0x26, 0x05, 0x00, 0xa9, 0x94, 0x05, 0x26, 0x23, 0x74, 0x7f, 0xc0, 0x90, 0x01, 0x2f, 0x00, 0x2e,
145    0x09, 0x2d, 0x02, 0x86, 0x00, 0x2e, 0xc3, 0x40, 0x09, 0x2e, 0x1d, 0x00, 0xdc, 0x04, 0xc0, 0xa8,
146    0x93, 0x04, 0x9a, 0x22, 0x62, 0x7f, 0x12, 0x30, 0x84, 0x6f, 0xb3, 0x6f, 0x63, 0x0f, 0x14, 0x30,
147    0x08, 0x2f, 0x74, 0x6f, 0x63, 0x0f, 0x14, 0x30, 0x04, 0x2f, 0x64, 0x6f, 0x63, 0x0f, 0x14, 0x30,
148    0x00, 0x2f, 0x04, 0x30, 0x54, 0x7f, 0x40, 0x91, 0x0b, 0x2e, 0x18, 0x00, 0x54, 0x6f, 0xa3, 0x6f,
149    0x6a, 0x29, 0x1d, 0x2f, 0x00, 0x91, 0x06, 0x30, 0x14, 0x24, 0x1c, 0x00, 0x0d, 0x2f, 0x2d, 0x2e,
150    0x18, 0x00, 0x05, 0x2e, 0x19, 0x00, 0x81, 0x84, 0x25, 0x2e, 0x19, 0x00, 0x05, 0x2e, 0x19, 0x00,
151    0x53, 0x0e, 0x2b, 0x2f, 0x2d, 0x2e, 0x1e, 0x00, 0x29, 0x2d, 0x2b, 0x2e, 0x18, 0x00, 0x2d, 0x2e,
152    0x19, 0x00, 0x0b, 0x2e, 0x18, 0x00, 0x6b, 0x0e, 0x20, 0x2f, 0x25, 0x2e, 0x1e, 0x00, 0x1e, 0x2d,
153    0x00, 0xb3, 0x05, 0x2f, 0x02, 0x30, 0x25, 0x2e, 0x18, 0x00, 0x25, 0x2e, 0x1e, 0x00, 0x08, 0x2d,
154    0x2b, 0x2e, 0x18, 0x00, 0x09, 0x2e, 0x18, 0x00, 0x63, 0x0e, 0x01, 0x2f, 0x25, 0x2e, 0x1e, 0x00,
155    0x02, 0x40, 0x25, 0x2e, 0x1b, 0x00, 0x31, 0x25, 0x00, 0x2e, 0xd5, 0x40, 0x12, 0x24, 0x1c, 0x00,
156    0x42, 0x25, 0x95, 0x42, 0x00, 0x2e, 0xc3, 0x40, 0x83, 0x42, 0x00, 0x2e, 0x05, 0x2e, 0x1e, 0x00,
157    0x80, 0xb2, 0x0d, 0x2f, 0x00, 0x40, 0x21, 0x2e, 0x1b, 0x00, 0x50, 0x40, 0x10, 0x43, 0x00, 0x2e,
158    0x40, 0x40, 0x00, 0x43, 0x20, 0x30, 0x21, 0x2e, 0x5e, 0xf0, 0x02, 0x2d, 0x25, 0x2e, 0x24, 0x00,
159    0x50, 0x5f, 0xb8, 0x2e, 0x40, 0x30, 0x21, 0x2e, 0xba, 0xf0, 0xb8, 0x2e, 0x80, 0x2e, 0x18, 0x00,
160    0x70, 0x50, 0xf4, 0x7f, 0xe3, 0x7f, 0xd2, 0x7f, 0xc1, 0x7f, 0x12, 0x30, 0x03, 0x2e, 0x66, 0x00,
161    0x91, 0x14, 0x92, 0x7f, 0x00, 0x31, 0xc4, 0x6f, 0x95, 0x6f, 0xe3, 0x6f, 0xa5, 0x0f, 0x70, 0x84,
162    0x01, 0x04, 0x14, 0x2f, 0xd5, 0x6f, 0x00, 0xa9, 0x01, 0x2f, 0xa5, 0x7f, 0x21, 0x2d, 0xdd, 0x04,
163    0xb3, 0x7f, 0x40, 0xb2, 0xb3, 0x6f, 0x1c, 0x18, 0x06, 0x2f, 0x50, 0xa0, 0x01, 0x2f, 0xba, 0x11,
164    0x03, 0x2d, 0x71, 0x12, 0xb8, 0x14, 0x8a, 0x0b, 0x6e, 0x00, 0xa1, 0x7f, 0x11, 0x2d, 0xf7, 0x6f,
165    0xfb, 0x05, 0xb7, 0x7f, 0x25, 0x05, 0xb5, 0x6f, 0x2c, 0x18, 0x40, 0xb2, 0x06, 0x2f, 0x50, 0xa0,
166    0x01, 0x2f, 0xba, 0x11, 0x03, 0x2d, 0x71, 0x12, 0xb8, 0x14, 0x8a, 0x0b, 0x5e, 0x00, 0xa1, 0x7f,
167    0x00, 0x2e, 0xa0, 0x6f, 0x90, 0x5f, 0xb8, 0x2e, 0x01, 0x2e, 0x02, 0x01, 0x8e, 0xbc, 0x01, 0x2e,
168    0x62, 0x00, 0x9e, 0xb8, 0x01, 0x1a, 0x5f, 0x2f, 0x01, 0x2e, 0x02, 0x01, 0x0e, 0xbc, 0x0e, 0xb8,
169    0x21, 0x2e, 0x62, 0x00, 0x03, 0x2e, 0x62, 0x00, 0x43, 0xb2, 0x10, 0x24, 0x65, 0x00, 0x3c, 0x2f,
170    0x42, 0xb2, 0x22, 0x2f, 0x41, 0xb2, 0x06, 0x2f, 0x01, 0x30, 0x11, 0x42, 0x01, 0x42, 0x3e, 0x80,
171    0x00, 0x2e, 0x01, 0x42, 0xb8, 0x2e, 0x03, 0x2e, 0x9d, 0x00, 0x5f, 0x90, 0x62, 0x30, 0x11, 0x24,
172    0x81, 0x00, 0x07, 0x2f, 0x30, 0x25, 0x34, 0x37, 0xd4, 0x42, 0xc2, 0x42, 0xfe, 0x86, 0x00, 0x2e,
173    0xc1, 0x42, 0x00, 0x2e, 0x07, 0x2e, 0x9d, 0x00, 0xde, 0x90, 0x35, 0x2f, 0x63, 0x36, 0x13, 0x42,
174    0x02, 0x42, 0x3e, 0x80, 0x00, 0x2e, 0x01, 0x42, 0xb8, 0x2e, 0x03, 0x2e, 0x9d, 0x00, 0x5f, 0xb2,
175    0x52, 0x30, 0x21, 0x32, 0x0a, 0x2f, 0x07, 0x2e, 0x9d, 0x00, 0xde, 0x90, 0x24, 0x2f, 0x23, 0x31,
176    0x13, 0x42, 0x02, 0x42, 0x3e, 0x80, 0x00, 0x2e, 0x01, 0x42, 0xb8, 0x2e, 0x03, 0x32, 0x13, 0x42,
177    0x02, 0x42, 0x3e, 0x80, 0x00, 0x2e, 0x01, 0x42, 0xb8, 0x2e, 0x03, 0x2e, 0x9d, 0x00, 0x5f, 0xb2,
178    0x42, 0x30, 0x11, 0x31, 0x0a, 0x2f, 0x07, 0x2e, 0x9d, 0x00, 0xde, 0x90, 0x0c, 0x2f, 0xa3, 0x30,
179    0x13, 0x42, 0x02, 0x42, 0x3e, 0x80, 0x00, 0x2e, 0x01, 0x42, 0xb8, 0x2e, 0x63, 0x31, 0x13, 0x42,
180    0x02, 0x42, 0x3e, 0x80, 0x00, 0x2e, 0x01, 0x42, 0xb8, 0x2e, 0x10, 0x24, 0x78, 0x00, 0x11, 0x24,
181    0x52, 0xf0, 0x12, 0x40, 0x52, 0x42, 0x28, 0xb5, 0x52, 0x42, 0x00, 0x2e, 0x12, 0x40, 0x42, 0x42,
182    0x42, 0x82, 0x00, 0x40, 0x50, 0x42, 0x08, 0xb4, 0x40, 0x42, 0x7e, 0x80, 0xa8, 0xb4, 0x01, 0x42,
183    0xb8, 0x2e, 0x12, 0x24, 0x71, 0x00, 0x90, 0x40, 0x84, 0x82, 0x20, 0x50, 0x50, 0x42, 0x77, 0x80,
184    0x82, 0x40, 0x42, 0x42, 0xfb, 0x7f, 0x05, 0x82, 0x00, 0x40, 0x40, 0x42, 0x7c, 0x80, 0x05, 0x82,
185    0x00, 0x40, 0x40, 0x42, 0x7c, 0x80, 0x05, 0x82, 0x00, 0x40, 0x40, 0x42, 0x77, 0x84, 0x00, 0x2e,
186    0x90, 0x40, 0x84, 0x82, 0x82, 0x40, 0x50, 0x42, 0x77, 0x80, 0x42, 0x42, 0x05, 0x82, 0x00, 0x40,
187    0x40, 0x42, 0x7c, 0x80, 0x05, 0x82, 0x00, 0x40, 0x40, 0x42, 0x7c, 0x80, 0x05, 0x82, 0x00, 0x40,
188    0x40, 0x42, 0x7c, 0x82, 0xe1, 0x7f, 0x98, 0x2e, 0x03, 0xb1, 0xe2, 0x6f, 0x00, 0x2e, 0x90, 0x42,
189    0x81, 0x42, 0xbc, 0x82, 0x10, 0x24, 0x33, 0xf0, 0x23, 0x40, 0x02, 0x40, 0xb8, 0xbd, 0x9a, 0x0a,
190    0x03, 0x80, 0x52, 0x42, 0x00, 0x2e, 0x23, 0x40, 0x02, 0x40, 0xb8, 0xbd, 0x9a, 0x0a, 0x03, 0x80,
191    0x52, 0x42, 0x00, 0x2e, 0x22, 0x40, 0x00, 0x40, 0x28, 0xbd, 0x10, 0x0a, 0x40, 0x42, 0x00, 0x2e,
192    0xfb, 0x6f, 0xe0, 0x5f, 0xb8, 0x2e, 0x11, 0x24, 0x28, 0xf0, 0x50, 0x50, 0x60, 0x40, 0xf0, 0x7f,
193    0x51, 0x25, 0x60, 0x40, 0xe0, 0x7f, 0x00, 0x2e, 0x41, 0x40, 0xd1, 0x7f, 0x00, 0x2e, 0xe2, 0x6f,
194    0xd0, 0x6f, 0x00, 0xb2, 0xf3, 0x6f, 0xa8, 0xb8, 0x28, 0xbe, 0x59, 0x0a, 0x20, 0x0a, 0x01, 0x2f,
195    0xb0, 0x5f, 0xb8, 0x2e, 0x45, 0x41, 0xc5, 0x7f, 0x00, 0x2e, 0xc5, 0x6f, 0x40, 0x91, 0x09, 0x2f,
196    0x05, 0x2e, 0x28, 0xf0, 0xb2, 0x7f, 0x00, 0x2e, 0xb2, 0x6f, 0x1a, 0x1a, 0x07, 0x2f, 0xf0, 0x3f,
197    0x13, 0x25, 0x05, 0x2d, 0x15, 0x1a, 0x02, 0x2f, 0x10, 0x24, 0xff, 0x00, 0x20, 0x0a, 0xb0, 0x5f,
198    0xb8, 0x2e, 0x01, 0x2e, 0x03, 0x01, 0x8f, 0xbc, 0x01, 0x2e, 0x1f, 0x00, 0x9f, 0xb8, 0x01, 0x1a,
199    0x12, 0x2f, 0x01, 0x2e, 0x03, 0x01, 0x0f, 0xbc, 0x0f, 0xb8, 0x21, 0x2e, 0x1f, 0x00, 0x11, 0x30,
200    0x05, 0x2e, 0x1f, 0x00, 0x51, 0x08, 0xd2, 0x3f, 0x01, 0x2e, 0x07, 0xf0, 0x02, 0x08, 0x91, 0xbc,
201    0x01, 0x0a, 0x21, 0x2e, 0x07, 0xf0, 0xb8, 0x2e, 0xb8, 0x2e, 0x50, 0x50, 0xf2, 0x7f, 0xe1, 0x7f,
202    0x01, 0x30, 0xd1, 0x7f, 0xc1, 0x7f, 0x10, 0x24, 0x91, 0x04, 0xf2, 0x6f, 0xe3, 0x6f, 0x1c, 0x2d,
203    0xc4, 0x6f, 0x9c, 0x01, 0xd5, 0x6f, 0x86, 0x41, 0x6e, 0x0d, 0xd5, 0x7f, 0xb1, 0x7f, 0x0e, 0x2d,
204    0xd6, 0x6f, 0xef, 0xba, 0x61, 0xbf, 0x40, 0x91, 0x01, 0x2f, 0xd6, 0x7f, 0x03, 0x2d, 0x70, 0x0d,
205    0xd5, 0x7f, 0x00, 0x2e, 0xb5, 0x6f, 0x41, 0x8b, 0xb5, 0x7f, 0x00, 0x2e, 0xb5, 0x6f, 0x50, 0xa3,
206    0xee, 0x2f, 0x01, 0x89, 0xc4, 0x7f, 0x00, 0x2e, 0xc4, 0x6f, 0x62, 0x0e, 0xe0, 0x2f, 0xd0, 0x6f,
207    0xb0, 0x5f, 0xb8, 0x2e, 0x90, 0x50, 0xd3, 0x7f, 0xfb, 0x7f, 0xc2, 0x7f, 0xb1, 0x7f, 0x11, 0x30,
208    0xa1, 0x7f, 0x1a, 0x25, 0xc2, 0x6f, 0x72, 0x7f, 0x77, 0x82, 0xb2, 0x6f, 0x82, 0x7f, 0xe2, 0x7f,
209    0x22, 0x30, 0x98, 0x2e, 0x4d, 0xb1, 0x90, 0x7f, 0x00, 0x2e, 0xe1, 0x6f, 0xd0, 0x6f, 0x41, 0x16,
210    0x92, 0x6f, 0x01, 0x08, 0x51, 0x08, 0x48, 0x1a, 0x01, 0x2f, 0x01, 0x30, 0xa1, 0x7f, 0x00, 0x2e,
211    0xfb, 0x6f, 0xa0, 0x6f, 0x70, 0x5f, 0xb8, 0x2e, 0x70, 0x50, 0xe3, 0x7f, 0xfb, 0x7f, 0xc1, 0x7f,
212    0xd2, 0x7f, 0x1a, 0x25, 0xc0, 0x6f, 0xd2, 0x6f, 0x90, 0x7f, 0xa2, 0x7f, 0x79, 0x82, 0xe2, 0x6f,
213    0xb2, 0x7f, 0x32, 0x30, 0x98, 0x2e, 0x4d, 0xb1, 0xfb, 0x6f, 0x90, 0x5f, 0xb8, 0x2e, 0xb0, 0x50,
214    0xa4, 0x7f, 0xfb, 0x7f, 0x93, 0x7f, 0x82, 0x7f, 0x71, 0x7f, 0x00, 0x30, 0xa1, 0x6f, 0xe1, 0x7f,
215    0x40, 0x42, 0x00, 0x2e, 0x92, 0x6f, 0x83, 0x6f, 0x71, 0x6f, 0xd3, 0x7f, 0xc2, 0x7f, 0xb1, 0x7f,
216    0x98, 0x2e, 0x7a, 0xb1, 0x60, 0x7f, 0x00, 0x2e, 0x60, 0x6f, 0x01, 0xb2, 0x1e, 0x2f, 0xb1, 0x6f,
217    0xf2, 0x30, 0x8a, 0x08, 0x13, 0x24, 0xf0, 0x00, 0x4b, 0x08, 0x24, 0xbd, 0x94, 0xb8, 0x51, 0x0a,
218    0x51, 0x7f, 0x00, 0x2e, 0x51, 0x6f, 0x81, 0x16, 0xd3, 0x6f, 0x9a, 0x08, 0xc4, 0x6f, 0xe1, 0x08,
219    0xe1, 0x6f, 0x93, 0x0a, 0x42, 0x42, 0x12, 0x24, 0x00, 0xff, 0x43, 0x40, 0x9a, 0x08, 0x14, 0x24,
220    0xff, 0x00, 0xdc, 0x08, 0xb8, 0xbd, 0x28, 0xb9, 0x9a, 0x0a, 0x42, 0x42, 0x00, 0x2e, 0xfb, 0x6f,
221    0x50, 0x5f, 0xb8, 0x2e, 0x70, 0x50, 0xd4, 0x7f, 0xfb, 0x7f, 0xc3, 0x7f, 0xa1, 0x7f, 0xb2, 0x7f,
222    0x02, 0x30, 0x92, 0x7f, 0x00, 0x2e, 0x05, 0x2e, 0x20, 0x00, 0xc4, 0x6f, 0x80, 0xb2, 0x0c, 0x2f,
223    0x81, 0x90, 0x1a, 0x2f, 0xd2, 0x6f, 0x07, 0x2e, 0x21, 0x00, 0xa1, 0x32, 0x98, 0x2e, 0xaf, 0xb1,
224    0x02, 0x30, 0x25, 0x2e, 0x20, 0x00, 0x92, 0x7f, 0x10, 0x2d, 0xa1, 0x6f, 0xb2, 0x6f, 0xe4, 0x7f,
225    0xa3, 0x32, 0x98, 0x2e, 0x9c, 0xb1, 0x21, 0x2e, 0x21, 0x00, 0xe2, 0x6f, 0x03, 0x2e, 0x21, 0x00,
226    0x81, 0x42, 0x12, 0x30, 0x25, 0x2e, 0x20, 0x00, 0x92, 0x7f, 0x00, 0x2e, 0xfb, 0x6f, 0x90, 0x6f,
227    0x90, 0x5f, 0xb8, 0x2e, 0x10, 0x50, 0x00, 0x30, 0xf0, 0x7f, 0x12, 0x24, 0x86, 0x00, 0x1b, 0x2d,
228    0xf1, 0x6f, 0xd1, 0x00, 0x00, 0x2e, 0xc0, 0x42, 0xbc, 0x84, 0xd1, 0x00, 0x00, 0x2e, 0xc0, 0x42,
229    0x8c, 0x84, 0xd1, 0x00, 0x00, 0x2e, 0xc0, 0x42, 0xbc, 0x84, 0xd1, 0x00, 0x00, 0x2e, 0xc0, 0x42,
230    0x8c, 0x84, 0xd1, 0x00, 0x00, 0x2e, 0xc0, 0x42, 0xbc, 0x84, 0xd1, 0x00, 0x00, 0x2e, 0xc0, 0x42,
231    0x41, 0x82, 0xf1, 0x7f, 0xb4, 0x84, 0xf1, 0x6f, 0x43, 0xa2, 0xe1, 0x2f, 0xf0, 0x5f, 0xb8, 0x2e,
232    0xc0, 0x50, 0x92, 0x7f, 0xfb, 0x7f, 0x81, 0x7f, 0x00, 0x30, 0x60, 0x7f, 0x70, 0x7f, 0x50, 0x7f,
233    0x00, 0x2e, 0x03, 0x2e, 0x04, 0x01, 0x9d, 0xbc, 0x9e, 0xb8, 0x41, 0x7f, 0x00, 0x2e, 0x42, 0x6f,
234    0x52, 0x7f, 0xe2, 0x7f, 0x00, 0x2e, 0x83, 0x6f, 0xc4, 0x82, 0xd3, 0x7f, 0x0c, 0x2d, 0x55, 0x6f,
235    0x7f, 0x89, 0xdc, 0x01, 0x9d, 0x01, 0xcb, 0x41, 0x8b, 0x43, 0xcc, 0x01, 0x4d, 0x01, 0xc7, 0x41,
236    0x47, 0x43, 0x54, 0x7f, 0x00, 0x2e, 0x54, 0x6f, 0x00, 0xab, 0xf0, 0x2f, 0x9b, 0x6f, 0x8a, 0x00,
237    0x4b, 0x42, 0xc2, 0x7f, 0xb1, 0x7f, 0x50, 0x7f, 0x7c, 0x80, 0xa0, 0x7f, 0x13, 0x24, 0x09, 0x01,
238    0x3f, 0x2d, 0x50, 0x6f, 0x18, 0x01, 0xc8, 0x84, 0xc8, 0x00, 0x50, 0x00, 0x05, 0x41, 0xc7, 0x40,
239    0x44, 0x40, 0x61, 0x6f, 0x73, 0x6f, 0x2f, 0x18, 0x00, 0xb3, 0x0b, 0x2f, 0x10, 0xa1, 0x03, 0x2f,
240    0x30, 0x89, 0xbc, 0x11, 0xce, 0x17, 0x06, 0x2d, 0x74, 0x13, 0x06, 0x31, 0xb4, 0x05, 0xbe, 0x15,
241    0xfc, 0x11, 0xae, 0x0b, 0x4e, 0x00, 0xdf, 0x02, 0x61, 0x7f, 0x73, 0x7f, 0xb4, 0x84, 0x01, 0x82,
242    0xd1, 0x00, 0x88, 0x80, 0xa2, 0x6f, 0x11, 0x01, 0x81, 0x00, 0xc3, 0x40, 0x05, 0x41, 0x84, 0x40,
243    0x1d, 0x18, 0x72, 0x6f, 0x00, 0xb3, 0x63, 0x6f, 0x0b, 0x2f, 0x10, 0xa1, 0x03, 0x2f, 0x30, 0x89,
244    0xbc, 0x11, 0xce, 0x17, 0x06, 0x2d, 0x74, 0x13, 0x06, 0x31, 0xb4, 0x05, 0xbe, 0x15, 0xfc, 0x11,
245    0xae, 0x0b, 0xde, 0x04, 0x97, 0x06, 0x63, 0x7f, 0x72, 0x7f, 0x51, 0x7f, 0x3c, 0x86, 0xb1, 0x6f,
246    0xe2, 0x6f, 0x50, 0x6f, 0x42, 0x0e, 0xbc, 0x2f, 0xe0, 0x6f, 0xc8, 0x82, 0x98, 0x00, 0x48, 0x00,
247    0xc0, 0x6f, 0x83, 0x40, 0x04, 0x40, 0x42, 0x40, 0x61, 0x6f, 0x70, 0x6f, 0x80, 0xb2, 0x1c, 0x18,
248    0x0b, 0x2f, 0x90, 0xa0, 0x03, 0x2f, 0xb0, 0x84, 0xba, 0x11, 0xce, 0x17, 0x06, 0x2d, 0x03, 0x31,
249    0xda, 0x04, 0xfb, 0x14, 0x32, 0x13, 0xfa, 0x11, 0xa3, 0x0b, 0x4e, 0x00, 0x07, 0x02, 0x61, 0x7f,
250    0x70, 0x7f, 0x00, 0x2e, 0x72, 0x6f, 0x80, 0xa8, 0x60, 0x6f, 0xd1, 0x6f, 0x13, 0x2f, 0x80, 0x90,
251    0x03, 0x2f, 0x13, 0x24, 0xff, 0x7f, 0x43, 0x0f, 0x0d, 0x2f, 0xbf, 0xa0, 0x07, 0x2f, 0xbf, 0x90,
252    0x03, 0x2f, 0x12, 0x24, 0x00, 0x80, 0x42, 0x0e, 0x01, 0x2f, 0x40, 0x42, 0x07, 0x2d, 0x10, 0x24,
253    0x00, 0x80, 0x40, 0x42, 0x03, 0x2d, 0x10, 0x24, 0xff, 0x7f, 0x40, 0x42, 0x00, 0x2e, 0xfb, 0x6f,
254    0x40, 0x5f, 0x40, 0x40, 0xb8, 0x2e, 0x11, 0x24, 0x7b, 0x00, 0x30, 0x50, 0x10, 0x30, 0x50, 0x42,
255    0xfb, 0x7f, 0x10, 0x24, 0x33, 0xf0, 0x23, 0x40, 0x02, 0x40, 0xb8, 0xbd, 0x9a, 0x0a, 0x03, 0x80,
256    0x52, 0x42, 0x00, 0x2e, 0x23, 0x40, 0x02, 0x40, 0xb8, 0xbd, 0x9a, 0x0a, 0x03, 0x80, 0x52, 0x42,
257    0x00, 0x2e, 0x23, 0x40, 0x02, 0x40, 0xb8, 0xbd, 0x9a, 0x0a, 0x3c, 0x80, 0x42, 0x42, 0x7e, 0x84,
258    0xe0, 0x7f, 0x86, 0x82, 0xd1, 0x7f, 0x00, 0x2e, 0x82, 0x40, 0x98, 0x2e, 0x40, 0xb2, 0xd1, 0x6f,
259    0x7d, 0x82, 0x00, 0x2e, 0x40, 0x42, 0x7e, 0x80, 0x0d, 0x82, 0x02, 0x40, 0xd1, 0x7f, 0x98, 0x2e,
260    0x40, 0xb2, 0xd1, 0x6f, 0x76, 0x82, 0x00, 0x2e, 0x40, 0x42, 0x7e, 0x80, 0x14, 0x82, 0x02, 0x40,
261    0xd1, 0x7f, 0x98, 0x2e, 0x40, 0xb2, 0xd1, 0x6f, 0x6f, 0x82, 0x00, 0x2e, 0x40, 0x42, 0x7e, 0x80,
262    0xe1, 0x6f, 0x12, 0x40, 0x52, 0x42, 0x28, 0xb5, 0x52, 0x42, 0x00, 0x2e, 0x12, 0x40, 0x52, 0x42,
263    0x28, 0xb5, 0x52, 0x42, 0x00, 0x2e, 0x00, 0x40, 0x50, 0x42, 0x08, 0xb4, 0x40, 0x42, 0x00, 0x2e,
264    0xfb, 0x6f, 0xd0, 0x5f, 0xb8, 0x2e, 0x10, 0x50, 0x01, 0x2e, 0x55, 0xf0, 0xf0, 0x7f, 0x00, 0x2e,
265    0xf0, 0x6f, 0x21, 0x2e, 0x55, 0xf0, 0xf0, 0x5f, 0xb8, 0x2e, 0x20, 0x50, 0x00, 0x30, 0xe0, 0x7f,
266    0xfb, 0x7f, 0x11, 0x24, 0xb1, 0xf0, 0x42, 0x40, 0x43, 0x30, 0x93, 0x0a, 0x42, 0x42, 0x58, 0x82,
267    0x12, 0x24, 0xaf, 0x00, 0x62, 0x42, 0x12, 0x24, 0xff, 0x00, 0x42, 0x42, 0x69, 0x82, 0x72, 0x3c,
268    0x43, 0x40, 0x9a, 0x08, 0x83, 0x32, 0x93, 0x0a, 0x42, 0x42, 0x42, 0x82, 0x02, 0x3f, 0x43, 0x40,
269    0x9a, 0x08, 0x52, 0x42, 0x0b, 0x31, 0x4b, 0x42, 0x7e, 0x82, 0x72, 0x31, 0x42, 0x42, 0x00, 0x2e,
270    0x03, 0x2e, 0x40, 0xf0, 0x5f, 0xb2, 0x03, 0x2f, 0x03, 0x2e, 0x40, 0xf0, 0x5e, 0x90, 0x27, 0x2f,
271    0x11, 0x24, 0x00, 0x02, 0x12, 0x24, 0x05, 0x80, 0x13, 0x24, 0xff, 0xb7, 0x1b, 0x24, 0x00, 0xb0,
272    0x04, 0x30, 0x05, 0x30, 0x56, 0x32, 0x6e, 0x1a, 0x00, 0x2f, 0x25, 0x36, 0x69, 0x1a, 0x01, 0x2f,
273    0x5b, 0x25, 0x00, 0x2e, 0x56, 0x41, 0x26, 0x0d, 0x06, 0x30, 0xcf, 0xbb, 0x41, 0xbe, 0xc0, 0x91,
274    0x01, 0x2f, 0x00, 0x2e, 0x01, 0x2d, 0x22, 0x0d, 0x81, 0x8d, 0x90, 0xa1, 0xf5, 0x2f, 0xeb, 0x0e,
275    0xe8, 0x2f, 0x01, 0x2e, 0x25, 0x00, 0x20, 0x1a, 0x05, 0x2f, 0x20, 0x30, 0xe0, 0x7f, 0x03, 0x2d,
276    0x30, 0x30, 0xe0, 0x7f, 0x00, 0x2e, 0xe0, 0x6f, 0x00, 0xb2, 0x06, 0x2f, 0x21, 0x2e, 0x59, 0xf0,
277    0x98, 0x2e, 0x43, 0xb3, 0x00, 0x2e, 0x00, 0x2e, 0xd0, 0x2e, 0xfb, 0x6f, 0xe0, 0x5f, 0xb8, 0x2e,
278    0xa0, 0x50, 0x80, 0x7f, 0xe7, 0x7f, 0xd5, 0x7f, 0xc4, 0x7f, 0xb3, 0x7f, 0xa2, 0x7f, 0x91, 0x7f,
279    0xf6, 0x7f, 0x7b, 0x7f, 0x00, 0x2e, 0x01, 0x2e, 0x43, 0xf0, 0x08, 0xbc, 0x0f, 0xb8, 0x60, 0x7f,
280    0x00, 0x2e, 0x60, 0x6f, 0x00, 0xb2, 0x01, 0x2f, 0x98, 0x2e, 0xb9, 0xb0, 0x40, 0x30, 0x21, 0x2e,
281    0xb8, 0xf0, 0xf6, 0x6f, 0x91, 0x6f, 0xa2, 0x6f, 0xb3, 0x6f, 0xc4, 0x6f, 0xd5, 0x6f, 0xe7, 0x6f,
282    0x7b, 0x6f, 0x80, 0x6f, 0x60, 0x5f, 0xc8, 0x2e, 0xa0, 0x50, 0x80, 0x7f, 0xe7, 0x7f, 0xd5, 0x7f,
283    0xc4, 0x7f, 0xb3, 0x7f, 0xa2, 0x7f, 0x91, 0x7f, 0xf6, 0x7f, 0x7b, 0x7f, 0x00, 0x2e, 0x01, 0x2e,
284    0x29, 0xf0, 0x08, 0xbc, 0x0f, 0xb8, 0x60, 0x7f, 0x00, 0x2e, 0x60, 0x6f, 0x01, 0x90, 0x1b, 0x2f,
285    0x01, 0x2e, 0x02, 0x01, 0x0e, 0xbc, 0x0e, 0xb8, 0x00, 0x90, 0x05, 0x2f, 0x01, 0x2e, 0x04, 0x01,
286    0x0f, 0xbc, 0x0f, 0xb8, 0x01, 0xb2, 0x0d, 0x2f, 0x01, 0x2e, 0x7b, 0x00, 0x01, 0x90, 0x04, 0x2f,
287    0x98, 0x2e, 0x1a, 0xb2, 0x00, 0x30, 0x21, 0x2e, 0x7b, 0x00, 0x01, 0x2e, 0x37, 0xf0, 0x21, 0x2e,
288    0x37, 0xf0, 0x02, 0x2d, 0x98, 0x2e, 0xf3, 0xb2, 0x80, 0x30, 0x21, 0x2e, 0xb8, 0xf0, 0xf6, 0x6f,
289    0x91, 0x6f, 0xa2, 0x6f, 0xb3, 0x6f, 0xc4, 0x6f, 0xd5, 0x6f, 0xe7, 0x6f, 0x7b, 0x6f, 0x80, 0x6f,
290    0x60, 0x5f, 0xc8, 0x2e, 0x60, 0x50, 0xe7, 0x7f, 0xf6, 0x7f, 0x36, 0x30, 0x0f, 0x2e, 0x01, 0xf0,
291    0xfe, 0xbf, 0xfe, 0xbb, 0xb7, 0x05, 0xa6, 0x7f, 0xd3, 0x7f, 0xc4, 0x7f, 0xb5, 0x7f, 0x14, 0x24,
292    0x89, 0xf0, 0x3f, 0x8b, 0x03, 0x41, 0x44, 0x41, 0xb8, 0xbd, 0x9c, 0x0b, 0xa3, 0x6f, 0x14, 0x24,
293    0x9a, 0x00, 0xb3, 0x11, 0x43, 0x8b, 0x16, 0x43, 0x00, 0x2e, 0x67, 0x41, 0x46, 0x41, 0xf8, 0xbf,
294    0xbe, 0x0b, 0xb3, 0x11, 0x16, 0x43, 0x43, 0x8d, 0x00, 0x2e, 0xa5, 0x41, 0x86, 0x41, 0xd8, 0xbe,
295    0x6e, 0x0b, 0xeb, 0x10, 0x03, 0x43, 0x13, 0x30, 0x27, 0x2e, 0x22, 0x00, 0x03, 0x31, 0x27, 0x2e,
296    0xb8, 0xf0, 0xf6, 0x6f, 0xe7, 0x6f, 0xc4, 0x6f, 0xb5, 0x6f, 0xd3, 0x6f, 0xa0, 0x5f, 0xc8, 0x2e,
297    0xa0, 0x50, 0x80, 0x7f, 0x91, 0x7f, 0xe7, 0x7f, 0xd5, 0x7f, 0xc4, 0x7f, 0xb3, 0x7f, 0xa2, 0x7f,
298    0xf6, 0x7f, 0x7b, 0x7f, 0x00, 0x2e, 0x01, 0x2e, 0xb9, 0xf0, 0x60, 0x7f, 0x10, 0x30, 0x61, 0x6f,
299    0x08, 0x08, 0x00, 0xb2, 0x01, 0x2f, 0x98, 0x2e, 0x9e, 0x00, 0x10, 0x30, 0x21, 0x2e, 0xb9, 0xf0,
300    0x21, 0x2e, 0x5f, 0xf0, 0xf6, 0x6f, 0x91, 0x6f, 0xa2, 0x6f, 0xb3, 0x6f, 0xc4, 0x6f, 0xd5, 0x6f,
301    0xe7, 0x6f, 0x7b, 0x6f, 0x80, 0x6f, 0x60, 0x5f, 0xc8, 0x2e, 0x20, 0x50, 0xe7, 0x7f, 0xf6, 0x7f,
302    0x56, 0x32, 0x0f, 0x2e, 0x58, 0xf0, 0x7e, 0x1a, 0x02, 0x2f, 0x16, 0x30, 0x2d, 0x2e, 0x23, 0x00,
303    0x16, 0x24, 0x80, 0x00, 0x2d, 0x2e, 0xb9, 0xf0, 0xe7, 0x6f, 0xf6, 0x6f, 0xe0, 0x5f, 0xc8, 0x2e,
304    0x30, 0x50, 0x04, 0x30, 0xd4, 0x7f, 0xe4, 0x7f, 0xfb, 0x7f, 0x13, 0x24, 0x26, 0xf0, 0xc2, 0x40,
305    0xc1, 0x86, 0xe4, 0x7f, 0xd2, 0x7f, 0x00, 0x2e, 0xd1, 0x40, 0x18, 0xbc, 0x18, 0xba, 0xd2, 0x6f,
306    0xe1, 0x6f, 0x90, 0x0a, 0x0c, 0x0b, 0xd2, 0x7f, 0xe4, 0x7f, 0x00, 0x2e, 0xe4, 0x6f, 0xc3, 0x40,
307    0xe3, 0x0a, 0xdb, 0x6f, 0xdb, 0x7f, 0xe3, 0x7f, 0x13, 0x24, 0x15, 0x01, 0xe2, 0x6f, 0x09, 0x2e,
308    0x16, 0x01, 0xd1, 0x6f, 0x98, 0x2e, 0xea, 0xb1, 0x21, 0x2e, 0x58, 0xf0, 0x98, 0x2e, 0x43, 0xb3,
309    0xfb, 0x6f, 0xd0, 0x5f, 0xb8, 0x2e, 0x98, 0x2e, 0x4d, 0xb3, 0x20, 0x26, 0x98, 0x2e, 0xfa, 0x01,
310    0x98, 0x2e, 0xf5, 0xb4, 0x98, 0x2e, 0xf1, 0xb4, 0x98, 0x2e, 0xde, 0xb4, 0x98, 0x2e, 0xf9, 0xb4,
311    0x01, 0x2e, 0x40, 0xf0, 0x21, 0x2e, 0x9d, 0x00, 0x10, 0x30, 0x21, 0x2e, 0x59, 0xf0, 0x98, 0x2e,
312    0x43, 0xb3, 0x21, 0x30, 0x10, 0x24, 0x9a, 0x00, 0x00, 0x2e, 0x00, 0x2e, 0xd0, 0x2e, 0x05, 0x2e,
313    0x22, 0x00, 0x80, 0xb2, 0x02, 0x30, 0x05, 0x2f, 0x23, 0x2e, 0x5f, 0xf0, 0x25, 0x2e, 0x22, 0x00,
314    0x98, 0x2e, 0x17, 0x01, 0x98, 0x2e, 0x31, 0xb1, 0x01, 0x2e, 0x23, 0x00, 0x01, 0x90, 0x00, 0x30,
315    0xe7, 0x2f, 0x21, 0x2e, 0x23, 0x00, 0x98, 0x2e, 0x80, 0xb4, 0xe3, 0x2d, 0x80, 0x30, 0x21, 0x2e,
316    0xba, 0xf0, 0x10, 0x24, 0x80, 0x00, 0x03, 0x2e, 0x06, 0xf0, 0x08, 0x0a, 0x21, 0x2e, 0x06, 0xf0,
317    0x00, 0x3e, 0x03, 0x2e, 0x06, 0xf0, 0x08, 0x08, 0x51, 0x30, 0x01, 0x0a, 0x21, 0x2e, 0x06, 0xf0,
318    0xb8, 0x2e, 0x00, 0x31, 0x21, 0x2e, 0xba, 0xf0, 0xb8, 0x2e, 0x10, 0x30, 0x21, 0x2e, 0xbb, 0xf0,
319    0xb8, 0x2e, 0x10, 0x24, 0x80, 0x00, 0x21, 0x2e, 0xbb, 0xf0, 0xb8, 0x2e, 0x1a, 0x24, 0x26, 0x00,
320    0x80, 0x2e, 0xab, 0xb4, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
321    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
322    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
323    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
324    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
325    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
326    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
327    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
328    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
329    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
330    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
331    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
332    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
333    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
334    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
335    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
336    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
337    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
338    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
339    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
340    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
341    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
342    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
343    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
344    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
345    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
346    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
347    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
348    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
349    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
350    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
351    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
352    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
353    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
354    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
355    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
356    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
357    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
358    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
359    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
360    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
361    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
362    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
363    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
364    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
365    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
366    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
367    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
368    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
369    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
370    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
371    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
372    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
373    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
374    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
375    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
376    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
377    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
378    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
379    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
380    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
381    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
382    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
383    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
384    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
385    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
386    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
387    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
388    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
389    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
390    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
391    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
392    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
393    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
394    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
395    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
396    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
397    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
398    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
399    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
400    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
401    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
402    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
403    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
404    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
405    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
406    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
407    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
408    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
409    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
410    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
411    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
412    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
413    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
414    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
415    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
416    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
417    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
418    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
419    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
420    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
421    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
422    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
423    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
424    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
425    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
426    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
427    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
428    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
429    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
430    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
431    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
432    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
433    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
434    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
435    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
436    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
437    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
438    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
439    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
440    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
441    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
442    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
443    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
444    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
445    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
446    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
447    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
448    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
449    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
450    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
451    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
452    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
453    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
454    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
455    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
456    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
457    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
458    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
459    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
460    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
461    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
462    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
463    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
464    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
465    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
466    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
467    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
468    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
469    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
470    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
471    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
472    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
473    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
474    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
475    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
476    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
477    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
478    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
479    0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00,
480];
481
482// 0,1,2,3 --> 3,6,12,24g for BMI088;
483#[repr(u32)]
484#[derive(Clone, Copy)]
485pub enum AccelRange088 {
486    Max3G = 0,
487    Max6G = 1,
488    Max12G = 2,
489    Max24G = 3,
490}
491// 0,1,2,3 --> 3,6,12,24g for BMI088;
492#[repr(u32)]
493#[derive(Clone, Copy)]
494pub enum AccelRange085 {
495    Max2g = 0,
496    Max4g = 1,
497    Max8g = 2,
498    Max16g = 3,
499}
500
501pub enum AccelRange {
502    Bmi088(AccelRange088),
503    Bmi085(AccelRange085),
504}
505
506// 0,1,2,3,4 --> 2000,1000,500,250,125 deg/s
507#[repr(u8)]
508#[derive(Clone, Copy)]
509pub enum GyroRange {
510    Max125dps = 0x04,
511    Max250dps = 0x03,
512    Max500dps = 0x02,
513    Max1000dps = 0x01,
514    Max2000dps = 0x00,
515}
516
517#[repr(u8)]
518#[derive(Clone, Copy)]
519pub enum GyroBandwidth {
520    Odr2000Hz = 0x01, // BMI08_GYRO_BW_230_ODR_2000_HZ
521    Odr1000Hz = 0x02, // BMI08_GYRO_BW_116_ODR_1000_HZ
522    Odr400Hz = 0x03,  // BMI08_GYRO_BW_47_ODR_400_HZ
523}
524
525#[repr(u8)]
526#[derive(Clone, Copy)]
527pub enum SampleRate {
528    Odr2000Hz = 0x03, // BMI08_ACCEL_DATA_SYNC_MODE_2000HZ
529    Odr1000Hz = 0x02, // BMI08_ACCEL_DATA_SYNC_MODE_1000HZ
530    Odr400Hz = 0x01,  // BMI08_ACCEL_DATA_SYNC_MODE_400HZ
531}
532
533const SPI_READ: u8 = 0x80;
534const SPI_WRITE: u8 = 0x00;
535const CELSIUS_TO_KELVIN: f32 = 273.15;
536
537pub struct Bmi08xSensor {
538    pub dev_a: SpiDevice<
539        'static,
540        CriticalSectionRawMutex,
541        spi::Spi<'static, Async, spi::mode::Master>,
542        Output<'static>,
543    >,
544    pub dev_g: SpiDevice<
545        'static,
546        CriticalSectionRawMutex,
547        spi::Spi<'static, Async, spi::mode::Master>,
548        Output<'static>,
549    >,
550
551    pub sample_rate: SampleRate,
552
553    pub drdy_a: ExtiInput<'static, Async>,
554    pub drdy_g: ExtiInput<'static, Async>,
555    pub jumper: Output<'static>,
556
557    pub range_a: AccelRange,
558    pub range_g: GyroRange,
559    /// Fixed sensor-to-board axis signs, applied before configurable IMU rotation and calibration.
560    pub board_axis_signs: [f64; 3],
561}
562
563impl Bmi08xSensor {
564    async fn read_register_a(&mut self, reg_addr: u8) -> u8 {
565        let tx = [reg_addr | SPI_READ, 0x00, 0x00];
566        let mut rx = [0u8; 3];
567        let _ = self.dev_a.transfer(&mut rx, &tx).await;
568        rx[2]
569    }
570    async fn read_register_g(&mut self, reg_addr: u8) -> u8 {
571        let tx = [reg_addr | SPI_READ, 0x00];
572        let mut rx = [0u8; 2];
573        let _ = self.dev_g.transfer(&mut rx, &tx).await;
574        rx[1]
575    }
576
577    async fn write_register_a(&mut self, reg_addr: u8, value: u8) {
578        let tx = [reg_addr | SPI_WRITE, value];
579        let _ = self.dev_a.write(&tx).await; // Soft Reset
580    }
581
582    async fn write_register_g(&mut self, reg_addr: u8, value: u8) {
583        let tx = [reg_addr | SPI_WRITE, value];
584        let _ = self.dev_g.write(&tx).await; // Soft Reset
585    }
586
587    pub async fn run(&mut self) {
588        // time for power-on
589        Timer::after_millis(50).await;
590
591        const ACCEL_PROD_ID_REG: u8 = 0x00; //BMI08_REG_ACCEL_CHIP_ID
592        const ACCEL_PROD_ID_088: u8 = 0x1E;
593        const ACCEL_PROD_ID_085: u8 = 0x1F;
594
595        // Check Accel ID  (0x80)
596        let _ = self.read_register_a(ACCEL_PROD_ID_REG).await; // Lock to SPI mode
597
598        // Second Read is to get the ID
599        let accel_id = self.read_register_a(ACCEL_PROD_ID_REG).await;
600        let mut accel_range: f64 = 0f64;
601
602        if accel_id == ACCEL_PROD_ID_088 {
603            accel_range = match &self.range_a {
604                AccelRange::Bmi088(range) => {
605                    3.0 * ((0x0001 << (*range as u32)) as f64) * 9.80665f64
606                }
607                AccelRange::Bmi085(range) => {
608                    2.0 * ((0x0001 << (*range as u32)) as f64) * 9.80665f64
609                }
610            };
611        } else if accel_id == ACCEL_PROD_ID_085 {
612            accel_range = match &self.range_a {
613                AccelRange::Bmi088(range) => {
614                    3.0 * ((0x0001 << (*range as u32)) as f64) * 9.80665f64
615                }
616                AccelRange::Bmi085(range) => {
617                    2.0 * ((0x0001 << (*range as u32)) as f64) * 9.80665f64
618                }
619            };
620        }
621
622        const GYRO_PROD_ID_REG: u8 = 0x00; // BMI08_REG_GYRO_CHIP_ID
623        const GYRO_PROD_ID: u8 = 0x0F;
624
625        // Second Read is to get the ID
626        let gyro_id = self.read_register_g(GYRO_PROD_ID_REG).await;
627        let mut gyro_range: f64 = 0f64;
628
629        if gyro_id == GYRO_PROD_ID {
630            gyro_range = match &self.range_g {
631                GyroRange::Max125dps => 125.0f64,
632                GyroRange::Max250dps => 250.0f64,
633                GyroRange::Max500dps => 500.0f64,
634                GyroRange::Max1000dps => 1000.0f64,
635                GyroRange::Max2000dps => 2000.0f64,
636            } * 0.017453292519943295f64;
637        }
638
639        // Accel Soft Reset (0x7E, 0xB6) //BMI08_REG_ACCEL_SOFTRESET
640        self.write_register_a(0x7E, 0xB6).await;
641        Timer::after_micros(1000).await; // required
642
643        // Lock to SPI mode again (after soft reset)
644        self.read_register_a(ACCEL_PROD_ID_REG).await;
645        Timer::after_micros(4900).await; // not needed? It's in the Bosh code
646
647        // Activate Accel (0x7C,0x00) //BMI08_REG_ACCEL_PWR_CONF
648        self.write_register_a(0x7C, 0x00).await;
649        Timer::after_micros(450).await; // required
650
651        // Disable "Config Loading" (0x59, 0x00) // BMI08_REG_ACCEL_INIT_CTRL
652        self.write_register_a(0x59, 0x00).await;
653
654        // Write Sensor Program
655        const BLOCK_SIZE: usize = 32;
656        for (index, block) in BMI_CONFIG.chunks(BLOCK_SIZE).enumerate() {
657            self.write_register_a(0x5B, 0x00).await; //BMI08_REG_ACCEL_RESERVED_5B
658            self.write_register_a(0x5C, index as u8).await; //BMI08_REG_ACCEL_RESERVED_5C
659            let mut tx = [0u8; BLOCK_SIZE + 1];
660            tx[0] = 0x5E | SPI_WRITE; // BMI08_REG_ACCEL_FEATURE_CFG
661            for (i, &item) in block.iter().enumerate() {
662                tx[i + 1] = item;
663            }
664            let _ = self.dev_a.write(&tx).await;
665        }
666
667        // Re-enable "Config Loading"
668        self.write_register_a(0x59, 0x01).await;
669        Timer::after_micros(150000).await; // required?
670
671        // Unknown status register read (0x2A|SPI_READ)
672        // BMI08_REG_ACCEL_INIT_CTRL = 0x2A   (0xAA)
673        let _ = self.read_register_a(0x2A).await;
674
675        // Activate Accel, again (0x7C,0x00)
676        // BMI08_REG_ACCEL_PWR_CONF = 0x7C
677        self.write_register_a(0x7C, 0x00).await;
678        Timer::after_micros(450).await; // required, was 5000us, using 450us like above
679
680        // Accelerometer ON (0x7D,0x04)
681        // BMI08_REG_ACCEL_PWR_CTRL = 0x7D
682        self.write_register_a(0x7D, 0x04).await; //
683        Timer::after_micros(100).await;
684
685        // Read/Write Low Power Mode
686        // BMI08_REG_GYRO_LPM1 = 0x11 (0x91)
687        let _ = self.read_register_g(0x11).await;
688        self.write_register_g(0x11, 0x00).await;
689        Timer::after_millis(30).await;
690
691        // Read/Write Gyro Bandwidth
692        // BMI08_REG_GYRO_BANDWIDTH = 0x10 (0x90)
693        let gyro_bw = match self.sample_rate {
694            SampleRate::Odr2000Hz => GyroBandwidth::Odr2000Hz as u8,
695            SampleRate::Odr1000Hz => GyroBandwidth::Odr1000Hz as u8,
696            SampleRate::Odr400Hz => GyroBandwidth::Odr400Hz as u8,
697        };
698        let _ = self.read_register_g(0x10).await;
699        self.write_register_g(0x10, gyro_bw).await;
700
701        // Read/Write Gyro Range
702        // BMI08_REG_GYRO_RANGE = 0x0F (0x8F)
703        let _ = self.read_register_g(0x0F).await;
704        self.write_register_g(0x0F, self.range_g as u8).await;
705        Timer::after_micros(10000).await; // do we need this delay??
706
707        // Read/Write BMI08_REG_ACCEL_FEATURE_CFG 7+1 bytes
708        // This is undocumented, from Bosh drivers
709        const BMI08_REG_ACCEL_FEATURE_CFG: u8 = 0x5E; //(0xDE)
710        const BMI08_ACCEL_DATA_SYNC_MODE_MASK: u8 = 0x03;
711        let mut tx = [0u8; 8];
712        let mut sync_cfg = [0u8; 8];
713        tx[0] = BMI08_REG_ACCEL_FEATURE_CFG | SPI_READ;
714        let _ = self.dev_a.transfer(&mut sync_cfg, &tx).await;
715
716        // Unclear why this is 16-bit data, just following what Bosh does
717        sync_cfg[1] = BMI08_REG_ACCEL_FEATURE_CFG | SPI_WRITE; // 0x5E
718        let sync_cfg_mode = self.sample_rate as u8;
719        let reg_data = sync_cfg_mode & BMI08_ACCEL_DATA_SYNC_MODE_MASK;
720        sync_cfg[6] = reg_data; // low byte
721        sync_cfg[7] = 0; // high byte
722        let _ = self.dev_a.write(&sync_cfg[1..]).await;
723
724        Timer::after_micros(100000).await; // delay of 100ms for data sync to take effect.
725
726        // BMI08_REG_ACCEL_INT2_IO_CONF = 0x54 (0xD4)
727        let _ = self.read_register_a(0x54).await;
728        self.write_register_a(0x54, 0x13).await; //Int2 as input, active high, reserved[0] = 1
729        // BMI08_REG_ACCEL_INT1_MAP = 0x56
730        self.write_register_a(0x56, 0x01).await; // undocumented
731        // BMI08_INT1_INT2_MAP_DATA = 0x58
732        self.write_register_a(0x58, 0x04).await; // !! change, map data ready interrupt to Int1
733
734        // BMI08_REG_ACCEL_INT1_IO_CONF = 0x53 (0xD3)
735        let _ = self.read_register_a(0x53).await;
736        self.write_register_a(0x53, 0x0A).await; //Int1 as output, active high
737
738        // BMI08_REG_ACCEL_CONF = 0x40
739        //	readRegisterA(BMI08_REG_ACCEL_CONF); 		// (0x40)
740        //	writeRegisterA(BMI08_REG_ACCEL_CONF, rangeA_);// (0x40,0x0A) Int1 as output, active high
741
742        // BMI08_REG_GYRO_INT3_INT4_IO_MAP = 0x18 (0x98)
743        let _ = self.read_register_g(0x18).await;
744        self.write_register_g(0x18, 0x81).await; //(0x18,0x80) 0x81 to map drdy to both int3 and int4
745
746        // BMI08_REG_GYRO_INT3_INT4_IO_CONF = 0x16 (0x96)
747        let _ = self.read_register_g(0x16).await; // (0x96)
748        self.write_register_g(0x16, 0x05).await; // (0x16,0x05)
749        //BMI08_REG_GYRO_INT_CTRL = 0x15
750        self.write_register_g(0x15, 0x80).await; //(0x15,0x80) Enable drdy interrupt on new data
751
752        // yes this is a repeat sequence
753        // BMI08_REG_GYRO_INT3_INT4_IO_MAP = 0x18 (0x98)
754        let _ = self.read_register_g(0x18).await;
755        self.write_register_g(0x18, 0x81).await; //(0x18,0x80) 0x81 to map drdy to both int3 and int4
756
757        // BMI08_REG_GYRO_INT3_INT4_IO_CONF = 0x16 (0x96)
758        let _ = self.read_register_g(0x16).await; // (0x16)
759        self.write_register_g(0x16, 0x05).await; // (0x16,0x05)
760        //BMI08_REG_GYRO_INT_CTRL = 0x15
761        self.write_register_g(0x15, 0x80).await; //(0x15,0x80) Enable drdy interrupt on new data
762
763        // Done Initializations
764
765        let scale_factor_a = accel_range / 32767f64 / 4.0f64; // m/s^2
766        let scale_factor_g = gyro_range / 32767f64; // to rad/s
767
768        #[cfg(feature = "runtime-diagnostics")]
769        let mut previous_drdy: Option<Instant> = None;
770        #[cfg(feature = "runtime-diagnostics")]
771        let mut previous_sensor_time_us: Option<u32> = None;
772
773        loop {
774            self.drdy_g.wait_for_rising_edge().await;
775
776            #[cfg(feature = "runtime-diagnostics")]
777            let drdy_time = Instant::now();
778            #[cfg(feature = "runtime-diagnostics")]
779            {
780                VELOXITY_DIAG_BMI_DRDY.fetch_add(1, Ordering::Relaxed);
781                if let Some(previous) = previous_drdy.replace(drdy_time) {
782                    let interval_us = drdy_time
783                        .duration_since(previous)
784                        .as_micros()
785                        .min(u32::MAX as u64) as u32;
786                    VELOXITY_DIAG_BMI_DRDY_INTERVALS.fetch_add(1, Ordering::Relaxed);
787                    VELOXITY_DIAG_BMI_DRDY_INTERVAL_SUM_US
788                        .fetch_add(interval_us, Ordering::Relaxed);
789                    VELOXITY_DIAG_BMI_DRDY_INTERVAL_MAX_US
790                        .fetch_max(interval_us, Ordering::Relaxed);
791                }
792            }
793
794            self.jumper.set_high();
795            Timer::after_micros(60).await;
796            self.jumper.set_low();
797
798            let timestamp = Instant::now();
799
800            // read temperature, ax, and ay
801            const BMI_ACCEL_CMD: u8 = 0x12;
802            const BMI_ACCEL_BYTES: usize = 20;
803            let mut rx = [0u8; BMI_ACCEL_BYTES];
804            let mut tx = [0u8; BMI_ACCEL_BYTES];
805            tx[0] = BMI_ACCEL_CMD | SPI_READ;
806            let _ = self.dev_a.transfer(&mut rx, &tx).await;
807
808            let seq = ((rx[8] as u64 | (rx[9] as u64) << 8 | (rx[10] as u64) << 16) * 625u64
809                / 16u64) as u32; // 625/64 = 39.0625us/count
810            #[cfg(feature = "runtime-diagnostics")]
811            if let Some(previous) = previous_sensor_time_us.replace(seq) {
812                let interval_us = seq.wrapping_sub(previous);
813                // Data-sync mode is nominally 400 Hz. Allow half an interval
814                // of tolerance before classifying a sensor-clock discontinuity.
815                if interval_us > 3_750 {
816                    let elapsed_samples = interval_us.saturating_add(1_250) / 2_500;
817                    VELOXITY_DIAG_BMI_SENSOR_GAP_EVENTS.fetch_add(1, Ordering::Relaxed);
818                    VELOXITY_DIAG_BMI_SENSOR_MISSING
819                        .fetch_add(elapsed_samples.saturating_sub(1), Ordering::Relaxed);
820                }
821            }
822            let mut temperature = ((rx[18] as u32) << 3 | (((rx[19] as u32) >> 6) & 0x0003)) as f32;
823
824            if temperature > 1023.0 {
825                temperature -= 2048.0;
826            }
827
828            temperature *= 0.125;
829            temperature += 23.0 + CELSIUS_TO_KELVIN;
830
831            let mut accel = [0f64; 3];
832            accel[0] = scale_factor_a * (((rx[15] as i16) << 8 | (rx[14] as i16)) as f64);
833            accel[1] = scale_factor_a * (((rx[17] as i16) << 8 | (rx[16] as i16)) as f64);
834
835            // Read az
836            const BMI_ACCEL_SYNC_CMD: u8 = 0x27;
837            const BMI_ACCEL_SYNC_BYTES: usize = 4;
838            let mut rx = [0u8; BMI_ACCEL_SYNC_BYTES];
839            let mut tx = [0u8; BMI_ACCEL_SYNC_BYTES];
840            tx[0] = BMI_ACCEL_SYNC_CMD | SPI_READ;
841            let _ = self.dev_a.transfer(&mut rx, &tx).await;
842
843            accel[2] = scale_factor_a * (((rx[3] as i16) << 8 | (rx[2] as i16)) as f64);
844
845            // Read gyro
846            const BMI_GYRO_CMD: u8 = 0x02;
847            const BMI_GYRO_BYTES: usize = 7;
848            let mut rx = [0u8; BMI_GYRO_BYTES];
849            let mut tx = [0u8; BMI_GYRO_BYTES];
850            tx[0] = BMI_GYRO_CMD | SPI_READ;
851            let _ = self.dev_g.transfer(&mut rx, &tx).await;
852
853            let mut gyro = [0f64; 3];
854            gyro[0] = scale_factor_g * (((rx[2] as i16) << 8 | (rx[1] as i16)) as f64);
855            gyro[1] = scale_factor_g * (((rx[4] as i16) << 8 | (rx[3] as i16)) as f64);
856            gyro[2] = scale_factor_g * (((rx[6] as i16) << 8 | (rx[5] as i16)) as f64);
857
858            for axis in 0..3 {
859                accel[axis] *= self.board_axis_signs[axis];
860                gyro[axis] *= self.board_axis_signs[axis];
861            }
862
863            let status = 0u16; // dummy value
864            let header = packets::RosflightPacketHeader {
865                timestamp: timestamp.as_micros(),
866                status,
867            };
868            let imu_packet = packets::ImuPacket {
869                header,
870                accel,
871                gyro,
872                temperature,
873                seq,
874            };
875            #[cfg(feature = "runtime-diagnostics")]
876            {
877                let sample_time_us = Instant::now()
878                    .duration_since(drdy_time)
879                    .as_micros()
880                    .min(u32::MAX as u64) as u32;
881                VELOXITY_DIAG_BMI_SAMPLE_COMPLETE.fetch_add(1, Ordering::Relaxed);
882                VELOXITY_DIAG_BMI_SAMPLE_TIME_SUM_US.fetch_add(sample_time_us, Ordering::Relaxed);
883                VELOXITY_DIAG_BMI_SAMPLE_TIME_MAX_US.fetch_max(sample_time_us, Ordering::Relaxed);
884                if IMU_SIGNAL.signaled() {
885                    VELOXITY_DIAG_BMI_SIGNAL_OVERWRITE.fetch_add(1, Ordering::Relaxed);
886                }
887                VELOXITY_DIAG_BMI_SIGNAL_PUBLISH.fetch_add(1, Ordering::Relaxed);
888            }
889            IMU_SIGNAL.signal(Ok(imu_packet));
890        }
891    }
892}
893
894#[embassy_executor::task]
895pub async fn task(mut bmi: Bmi08xSensor) {
896    bmi.run().await;
897}