#![allow(unused, clippy::comparison_to_empty, clippy::manual_range_patterns)]
use crate::profile::{ProfileType, typedef};
use crate::proto::*;
fn is_expanded(state: &[u8], num: u8) -> bool {
match num {
5 | 28 => (state[num as usize >> 3] >> (num & 7)) & 1 == 1,
_ => false,
}
}
#[derive(Debug, Clone)]
pub struct Monitoring {
pub timestamp: typedef::DateTime,
pub device_index: typedef::DeviceIndex,
pub calories: u16,
pub distance: u32,
pub cycles: u32,
pub active_time: u32,
pub activity_type: typedef::ActivityType,
pub activity_subtype: typedef::ActivitySubtype,
pub activity_level: typedef::ActivityLevel,
pub distance_16: u16,
pub cycles_16: u16,
pub active_time_16: u16,
pub local_timestamp: typedef::LocalDateTime,
pub temperature: i16,
pub temperature_min: i16,
pub temperature_max: i16,
pub activity_time: [u16; 8],
pub active_calories: u16,
pub current_activity_type_intensity: u8,
pub timestamp_min_8: u8,
pub timestamp_16: u16,
pub heart_rate: u8,
pub intensity: u8,
pub duration_min: u16,
pub duration: u32,
pub ascent: u32,
pub descent: u32,
pub moderate_activity_minutes: u16,
pub vigorous_activity_minutes: u16,
state: [u8; 4], pub unknown_fields: Vec<Field>,
pub developer_fields: Vec<DeveloperField>,
}
impl Monitoring {
pub const TIMESTAMP: u8 = 253;
pub const DEVICE_INDEX: u8 = 0;
pub const CALORIES: u8 = 1;
pub const DISTANCE: u8 = 2;
pub const CYCLES: u8 = 3;
pub const ACTIVE_TIME: u8 = 4;
pub const ACTIVITY_TYPE: u8 = 5;
pub const ACTIVITY_SUBTYPE: u8 = 6;
pub const ACTIVITY_LEVEL: u8 = 7;
pub const DISTANCE_16: u8 = 8;
pub const CYCLES_16: u8 = 9;
pub const ACTIVE_TIME_16: u8 = 10;
pub const LOCAL_TIMESTAMP: u8 = 11;
pub const TEMPERATURE: u8 = 12;
pub const TEMPERATURE_MIN: u8 = 14;
pub const TEMPERATURE_MAX: u8 = 15;
pub const ACTIVITY_TIME: u8 = 16;
pub const ACTIVE_CALORIES: u8 = 19;
pub const CURRENT_ACTIVITY_TYPE_INTENSITY: u8 = 24;
pub const TIMESTAMP_MIN_8: u8 = 25;
pub const TIMESTAMP_16: u8 = 26;
pub const HEART_RATE: u8 = 27;
pub const INTENSITY: u8 = 28;
pub const DURATION_MIN: u8 = 29;
pub const DURATION: u8 = 30;
pub const ASCENT: u8 = 31;
pub const DESCENT: u8 = 32;
pub const MODERATE_ACTIVITY_MINUTES: u8 = 33;
pub const VIGOROUS_ACTIVITY_MINUTES: u8 = 34;
pub const fn new() -> Self {
Self {
timestamp: typedef::DateTime(u32::MAX),
device_index: typedef::DeviceIndex(u8::MAX),
calories: u16::MAX,
distance: u32::MAX,
cycles: u32::MAX,
active_time: u32::MAX,
activity_type: typedef::ActivityType(u8::MAX),
activity_subtype: typedef::ActivitySubtype(u8::MAX),
activity_level: typedef::ActivityLevel(u8::MAX),
distance_16: u16::MAX,
cycles_16: u16::MAX,
active_time_16: u16::MAX,
local_timestamp: typedef::LocalDateTime(u32::MAX),
temperature: i16::MAX,
temperature_min: i16::MAX,
temperature_max: i16::MAX,
activity_time: [u16::MAX; 8],
active_calories: u16::MAX,
current_activity_type_intensity: u8::MAX,
timestamp_min_8: u8::MAX,
timestamp_16: u16::MAX,
heart_rate: u8::MAX,
intensity: u8::MAX,
duration_min: u16::MAX,
duration: u32::MAX,
ascent: u32::MAX,
descent: u32::MAX,
moderate_activity_minutes: u16::MAX,
vigorous_activity_minutes: u16::MAX,
state: [0u8; 4],
unknown_fields: Vec::new(),
developer_fields: Vec::new(),
}
}
pub fn distance_scaled(&self) -> f64 {
if self.distance == u32::MAX {
return f64::from_bits(u64::MAX);
}
self.distance as f64 / 100.0 - 0.0
}
pub fn set_distance_scaled(&mut self, v: f64) -> &mut Monitoring {
let unscaled = (v + 0.0) * 100.0;
if unscaled.is_nan() || unscaled.is_infinite() || unscaled > u32::MAX as f64 {
self.distance = u32::MAX;
return self;
}
self.distance = unscaled as u32;
self
}
pub fn cycles_scaled(&self) -> f64 {
if self.cycles == u32::MAX {
return f64::from_bits(u64::MAX);
}
self.cycles as f64 / 2.0 - 0.0
}
pub fn set_cycles_scaled(&mut self, v: f64) -> &mut Monitoring {
let unscaled = (v + 0.0) * 2.0;
if unscaled.is_nan() || unscaled.is_infinite() || unscaled > u32::MAX as f64 {
self.cycles = u32::MAX;
return self;
}
self.cycles = unscaled as u32;
self
}
pub fn active_time_scaled(&self) -> f64 {
if self.active_time == u32::MAX {
return f64::from_bits(u64::MAX);
}
self.active_time as f64 / 1000.0 - 0.0
}
pub fn set_active_time_scaled(&mut self, v: f64) -> &mut Monitoring {
let unscaled = (v + 0.0) * 1000.0;
if unscaled.is_nan() || unscaled.is_infinite() || unscaled > u32::MAX as f64 {
self.active_time = u32::MAX;
return self;
}
self.active_time = unscaled as u32;
self
}
pub fn temperature_scaled(&self) -> f64 {
if self.temperature == i16::MAX {
return f64::from_bits(u64::MAX);
}
self.temperature as f64 / 100.0 - 0.0
}
pub fn set_temperature_scaled(&mut self, v: f64) -> &mut Monitoring {
let unscaled = (v + 0.0) * 100.0;
if unscaled.is_nan() || unscaled.is_infinite() || unscaled > i16::MAX as f64 {
self.temperature = i16::MAX;
return self;
}
self.temperature = unscaled as i16;
self
}
pub fn temperature_min_scaled(&self) -> f64 {
if self.temperature_min == i16::MAX {
return f64::from_bits(u64::MAX);
}
self.temperature_min as f64 / 100.0 - 0.0
}
pub fn set_temperature_min_scaled(&mut self, v: f64) -> &mut Monitoring {
let unscaled = (v + 0.0) * 100.0;
if unscaled.is_nan() || unscaled.is_infinite() || unscaled > i16::MAX as f64 {
self.temperature_min = i16::MAX;
return self;
}
self.temperature_min = unscaled as i16;
self
}
pub fn temperature_max_scaled(&self) -> f64 {
if self.temperature_max == i16::MAX {
return f64::from_bits(u64::MAX);
}
self.temperature_max as f64 / 100.0 - 0.0
}
pub fn set_temperature_max_scaled(&mut self, v: f64) -> &mut Monitoring {
let unscaled = (v + 0.0) * 100.0;
if unscaled.is_nan() || unscaled.is_infinite() || unscaled > i16::MAX as f64 {
self.temperature_max = i16::MAX;
return self;
}
self.temperature_max = unscaled as i16;
self
}
pub fn intensity_scaled(&self) -> f64 {
if self.intensity == u8::MAX {
return f64::from_bits(u64::MAX);
}
self.intensity as f64 / 10.0 - 0.0
}
pub fn set_intensity_scaled(&mut self, v: f64) -> &mut Monitoring {
let unscaled = (v + 0.0) * 10.0;
if unscaled.is_nan() || unscaled.is_infinite() || unscaled > u8::MAX as f64 {
self.intensity = u8::MAX;
return self;
}
self.intensity = unscaled as u8;
self
}
pub fn ascent_scaled(&self) -> f64 {
if self.ascent == u32::MAX {
return f64::from_bits(u64::MAX);
}
self.ascent as f64 / 1000.0 - 0.0
}
pub fn set_ascent_scaled(&mut self, v: f64) -> &mut Monitoring {
let unscaled = (v + 0.0) * 1000.0;
if unscaled.is_nan() || unscaled.is_infinite() || unscaled > u32::MAX as f64 {
self.ascent = u32::MAX;
return self;
}
self.ascent = unscaled as u32;
self
}
pub fn descent_scaled(&self) -> f64 {
if self.descent == u32::MAX {
return f64::from_bits(u64::MAX);
}
self.descent as f64 / 1000.0 - 0.0
}
pub fn set_descent_scaled(&mut self, v: f64) -> &mut Monitoring {
let unscaled = (v + 0.0) * 1000.0;
if unscaled.is_nan() || unscaled.is_infinite() || unscaled > u32::MAX as f64 {
self.descent = u32::MAX;
return self;
}
self.descent = unscaled as u32;
self
}
pub fn mark_as_expanded(&mut self, num: u8, flag: bool) -> bool {
match num {
5 | 28 => {
if flag {
self.state[num as usize >> 3] |= 1 << (num & 7)
} else {
self.state[num as usize >> 3] &= !(1 << (num & 7))
}
true
}
_ => false,
}
}
pub fn is_expanded(&self, num: u8) -> bool {
is_expanded(&self.state, num)
}
}
impl Default for Monitoring {
fn default() -> Self {
Self::new()
}
}
impl From<&Message> for Monitoring {
fn from(mesg: &Message) -> Self {
let mut vals: [&Value; 254] = [const { &Value::Invalid }; 254];
let mut state = [0u8; 4];
const KNOWN_NUMS: [u64; 4] = [34343608319, 0, 0, 2305843009213693952];
let mut n = 0u64;
for field in &mesg.fields {
n += (KNOWN_NUMS[field.num as usize >> 6] >> (field.num & 63)) & 1 ^ 1
}
let mut unknown_fields: Vec<Field> = Vec::with_capacity(n as usize);
for field in &mesg.fields {
if (KNOWN_NUMS[field.num as usize >> 6] >> (field.num & 63)) & 1 == 0 {
unknown_fields.push(field.clone());
continue;
}
if field.is_expanded && field.num < 29 {
state[field.num as usize >> 3] |= 1 << (field.num & 7)
}
vals[field.num as usize] = &field.value;
}
Self {
timestamp: typedef::DateTime(vals[253].as_u32()),
device_index: typedef::DeviceIndex(vals[0].as_u8()),
calories: vals[1].as_u16(),
distance: vals[2].as_u32(),
cycles: vals[3].as_u32(),
active_time: vals[4].as_u32(),
activity_type: typedef::ActivityType(vals[5].as_u8()),
activity_subtype: typedef::ActivitySubtype(vals[6].as_u8()),
activity_level: typedef::ActivityLevel(vals[7].as_u8()),
distance_16: vals[8].as_u16(),
cycles_16: vals[9].as_u16(),
active_time_16: vals[10].as_u16(),
local_timestamp: typedef::LocalDateTime(vals[11].as_u32()),
temperature: vals[12].as_i16(),
temperature_min: vals[14].as_i16(),
temperature_max: vals[15].as_i16(),
activity_time: match &vals[16] {
Value::VecUint16(v) => {
let mut arr: [u16; 8] = [u16::MAX; 8];
for (i, x) in v.iter().enumerate() {
arr[i] = *x;
}
arr
}
_ => [u16::MAX; 8],
},
active_calories: vals[19].as_u16(),
current_activity_type_intensity: vals[24].as_u8(),
timestamp_min_8: vals[25].as_u8(),
timestamp_16: vals[26].as_u16(),
heart_rate: vals[27].as_u8(),
intensity: vals[28].as_u8(),
duration_min: vals[29].as_u16(),
duration: vals[30].as_u32(),
ascent: vals[31].as_u32(),
descent: vals[32].as_u32(),
moderate_activity_minutes: vals[33].as_u16(),
vigorous_activity_minutes: vals[34].as_u16(),
state,
unknown_fields,
developer_fields: mesg.developer_fields.clone(),
}
}
}
impl From<Monitoring> for Message {
fn from(m: Monitoring) -> Self {
let mut arr = [const {
Field {
num: 0,
profile_type: ProfileType(0),
value: Value::Invalid,
is_expanded: false,
}
}; 29];
let mut len = 0usize;
let state = m.state;
if m.timestamp != typedef::DateTime(u32::MAX) {
arr[len] = Field {
num: 253,
profile_type: ProfileType::DATE_TIME,
value: Value::Uint32(m.timestamp.0),
is_expanded: false,
};
len += 1;
}
if m.device_index != typedef::DeviceIndex(u8::MAX) {
arr[len] = Field {
num: 0,
profile_type: ProfileType::DEVICE_INDEX,
value: Value::Uint8(m.device_index.0),
is_expanded: false,
};
len += 1;
}
if m.calories != u16::MAX {
arr[len] = Field {
num: 1,
profile_type: ProfileType::UINT16,
value: Value::Uint16(m.calories),
is_expanded: false,
};
len += 1;
}
if m.distance != u32::MAX {
arr[len] = Field {
num: 2,
profile_type: ProfileType::UINT32,
value: Value::Uint32(m.distance),
is_expanded: false,
};
len += 1;
}
if m.cycles != u32::MAX {
arr[len] = Field {
num: 3,
profile_type: ProfileType::UINT32,
value: Value::Uint32(m.cycles),
is_expanded: false,
};
len += 1;
}
if m.active_time != u32::MAX {
arr[len] = Field {
num: 4,
profile_type: ProfileType::UINT32,
value: Value::Uint32(m.active_time),
is_expanded: false,
};
len += 1;
}
if m.activity_type != typedef::ActivityType(u8::MAX) {
arr[len] = Field {
num: 5,
profile_type: ProfileType::ACTIVITY_TYPE,
value: Value::Uint8(m.activity_type.0),
is_expanded: is_expanded(&state, 5),
};
len += 1;
}
if m.activity_subtype != typedef::ActivitySubtype(u8::MAX) {
arr[len] = Field {
num: 6,
profile_type: ProfileType::ACTIVITY_SUBTYPE,
value: Value::Uint8(m.activity_subtype.0),
is_expanded: false,
};
len += 1;
}
if m.activity_level != typedef::ActivityLevel(u8::MAX) {
arr[len] = Field {
num: 7,
profile_type: ProfileType::ACTIVITY_LEVEL,
value: Value::Uint8(m.activity_level.0),
is_expanded: false,
};
len += 1;
}
if m.distance_16 != u16::MAX {
arr[len] = Field {
num: 8,
profile_type: ProfileType::UINT16,
value: Value::Uint16(m.distance_16),
is_expanded: false,
};
len += 1;
}
if m.cycles_16 != u16::MAX {
arr[len] = Field {
num: 9,
profile_type: ProfileType::UINT16,
value: Value::Uint16(m.cycles_16),
is_expanded: false,
};
len += 1;
}
if m.active_time_16 != u16::MAX {
arr[len] = Field {
num: 10,
profile_type: ProfileType::UINT16,
value: Value::Uint16(m.active_time_16),
is_expanded: false,
};
len += 1;
}
if m.local_timestamp != typedef::LocalDateTime(u32::MAX) {
arr[len] = Field {
num: 11,
profile_type: ProfileType::LOCAL_DATE_TIME,
value: Value::Uint32(m.local_timestamp.0),
is_expanded: false,
};
len += 1;
}
if m.temperature != i16::MAX {
arr[len] = Field {
num: 12,
profile_type: ProfileType::SINT16,
value: Value::Int16(m.temperature),
is_expanded: false,
};
len += 1;
}
if m.temperature_min != i16::MAX {
arr[len] = Field {
num: 14,
profile_type: ProfileType::SINT16,
value: Value::Int16(m.temperature_min),
is_expanded: false,
};
len += 1;
}
if m.temperature_max != i16::MAX {
arr[len] = Field {
num: 15,
profile_type: ProfileType::SINT16,
value: Value::Int16(m.temperature_max),
is_expanded: false,
};
len += 1;
}
if m.activity_time != [u16::MAX; 8] {
arr[len] = Field {
num: 16,
profile_type: ProfileType::UINT16,
value: Value::VecUint16(Vec::from(&m.activity_time)),
is_expanded: false,
};
len += 1;
}
if m.active_calories != u16::MAX {
arr[len] = Field {
num: 19,
profile_type: ProfileType::UINT16,
value: Value::Uint16(m.active_calories),
is_expanded: false,
};
len += 1;
}
if m.current_activity_type_intensity != u8::MAX {
arr[len] = Field {
num: 24,
profile_type: ProfileType::BYTE,
value: Value::Uint8(m.current_activity_type_intensity),
is_expanded: false,
};
len += 1;
}
if m.timestamp_min_8 != u8::MAX {
arr[len] = Field {
num: 25,
profile_type: ProfileType::UINT8,
value: Value::Uint8(m.timestamp_min_8),
is_expanded: false,
};
len += 1;
}
if m.timestamp_16 != u16::MAX {
arr[len] = Field {
num: 26,
profile_type: ProfileType::UINT16,
value: Value::Uint16(m.timestamp_16),
is_expanded: false,
};
len += 1;
}
if m.heart_rate != u8::MAX {
arr[len] = Field {
num: 27,
profile_type: ProfileType::UINT8,
value: Value::Uint8(m.heart_rate),
is_expanded: false,
};
len += 1;
}
if m.intensity != u8::MAX {
arr[len] = Field {
num: 28,
profile_type: ProfileType::UINT8,
value: Value::Uint8(m.intensity),
is_expanded: is_expanded(&state, 28),
};
len += 1;
}
if m.duration_min != u16::MAX {
arr[len] = Field {
num: 29,
profile_type: ProfileType::UINT16,
value: Value::Uint16(m.duration_min),
is_expanded: false,
};
len += 1;
}
if m.duration != u32::MAX {
arr[len] = Field {
num: 30,
profile_type: ProfileType::UINT32,
value: Value::Uint32(m.duration),
is_expanded: false,
};
len += 1;
}
if m.ascent != u32::MAX {
arr[len] = Field {
num: 31,
profile_type: ProfileType::UINT32,
value: Value::Uint32(m.ascent),
is_expanded: false,
};
len += 1;
}
if m.descent != u32::MAX {
arr[len] = Field {
num: 32,
profile_type: ProfileType::UINT32,
value: Value::Uint32(m.descent),
is_expanded: false,
};
len += 1;
}
if m.moderate_activity_minutes != u16::MAX {
arr[len] = Field {
num: 33,
profile_type: ProfileType::UINT16,
value: Value::Uint16(m.moderate_activity_minutes),
is_expanded: false,
};
len += 1;
}
if m.vigorous_activity_minutes != u16::MAX {
arr[len] = Field {
num: 34,
profile_type: ProfileType::UINT16,
value: Value::Uint16(m.vigorous_activity_minutes),
is_expanded: false,
};
len += 1;
}
Message {
header: 0,
num: typedef::MesgNum::MONITORING,
fields: {
let mut fields: Vec<Field> = Vec::with_capacity(len + m.unknown_fields.len());
fields.extend_from_slice(&arr[..len]);
fields.extend_from_slice(&m.unknown_fields);
fields
},
developer_fields: m.developer_fields,
}
}
}