add boolean type

This commit is contained in:
2025-12-25 12:44:26 -05:00
parent ebbf864af9
commit 8cfaf468e9
12 changed files with 113 additions and 14 deletions

View File

@@ -170,6 +170,9 @@ async fn main() -> Result<(), Box<dyn Error>> {
let cos_tlm_handle = tlm let cos_tlm_handle = tlm
.register("simple_producer/cos".into(), TelemetryDataType::Float64) .register("simple_producer/cos".into(), TelemetryDataType::Float64)
.await?; .await?;
let bool_tlm_handle = tlm
.register("simple_producer/bool".into(), TelemetryDataType::Boolean)
.await?;
let sin2_tlm_handle = tlm let sin2_tlm_handle = tlm
.register("simple_producer/sin2".into(), TelemetryDataType::Float32) .register("simple_producer/sin2".into(), TelemetryDataType::Float32)
@@ -239,6 +242,7 @@ async fn main() -> Result<(), Box<dyn Error>> {
Value::Float64((f64::TAU() * (index as f64) / (1000.0_f64)).cos()), Value::Float64((f64::TAU() * (index as f64) / (1000.0_f64)).cos()),
publish_time, publish_time,
)); ));
tasks.push(bool_tlm_handle.publish(Value::Boolean(index % 1000 > 500), publish_time));
tasks.push(sin2_tlm_handle.publish( tasks.push(sin2_tlm_handle.publish(
Value::Float32((f32::TAU() * (index as f32) / (500.0_f32)).sin()), Value::Float32((f32::TAU() * (index as f32) / (500.0_f32)).sin()),
publish_time, publish_time,

View File

@@ -0,0 +1,29 @@
<script setup lang="ts">
import { computed, watch } from 'vue';
const props = defineProps<{
value: boolean;
}>();
const emit = defineEmits<{
(e: 'update', value: string): void;
}>();
const display_value = computed(() => {
return props.value ? 'true' : 'false';
});
watch(
[display_value],
([display_str]) => {
emit('update', display_str);
},
{
immediate: true,
},
);
</script>
<template>
{{ display_value }}
</template>
<style scoped lang="scss"></style>

View File

@@ -6,6 +6,7 @@ const props = defineProps<{
value: number; value: number;
max_width: number; max_width: number;
copyable?: boolean; copyable?: boolean;
include_span?: boolean;
}>(); }>();
const emit = defineEmits<{ const emit = defineEmits<{
(e: 'update', value: string): void; (e: 'update', value: string): void;
@@ -14,6 +15,9 @@ const emit = defineEmits<{
const copyable = computed(() => { const copyable = computed(() => {
return props.copyable || false; return props.copyable || false;
}); });
const include_span = computed(() => {
return props.include_span || false;
});
const display_value = computed(() => { const display_value = computed(() => {
if (props.value == 0) { if (props.value == 0) {
@@ -61,9 +65,15 @@ const display_value = computed(() => {
} }
return precision; return precision;
}); });
watch([display_value], ([display_str]) => { watch(
emit('update', display_str); [display_value],
}); ([display_str]) => {
emit('update', display_str);
},
{
immediate: true,
},
);
</script> </script>
<template> <template>
@@ -73,11 +83,14 @@ watch([display_value], ([display_str]) => {
v-bind="$attrs" v-bind="$attrs"
></CopyableDynamicSpan> ></CopyableDynamicSpan>
</template> </template>
<template v-else> <template v-else-if="include_span">
<span v-bind="$attrs"> <span v-bind="$attrs">
{{ display_value }} {{ display_value }}
</span> </span>
</template> </template>
<template v-else>
{{ display_value }}
</template>
</template> </template>
<style scoped lang="scss"></style> <style scoped lang="scss"></style>

View File

@@ -96,12 +96,21 @@ watch([value], ([val]) => {
if (val) { if (val) {
const val_t = Date.parse(val.timestamp); const val_t = Date.parse(val.timestamp);
if (val_t >= min_x) { if (val_t >= min_x) {
const item_val = val.value[ const raw_item_val = val.value[telemetry_data.value!.data_type];
telemetry_data.value!.data_type let item_val = 0;
] as number; if (
['Float32', 'Float64'].some(
(e) => e == telemetry_data.value!.data_type,
)
) {
item_val = raw_item_val as number;
} else if (telemetry_data.value!.data_type == 'Boolean') {
item_val = (raw_item_val as boolean) ? 1 : 0;
}
const new_item = { const new_item = {
x: val_t, x: val_t,
y: item_val, y: item_val,
value: raw_item_val,
} as Point; } as Point;
memo.value.insert(new_item, data_min_sep.value); memo.value.insert(new_item, data_min_sep.value);
if (item_val < min.value) { if (item_val < min.value) {
@@ -131,10 +140,21 @@ watch(
const response = (await res.json()) as TelemetryDataItem[]; const response = (await res.json()) as TelemetryDataItem[];
for (const data_item of response) { for (const data_item of response) {
const val_t = Date.parse(data_item.timestamp); const val_t = Date.parse(data_item.timestamp);
const item_val = data_item.value[type] as number; const raw_item_val = data_item.value[type];
let item_val = 0;
if (
['Float32', 'Float64'].some(
(e) => e == telemetry_data.value!.data_type,
)
) {
item_val = raw_item_val as number;
} else if (type == 'Boolean') {
item_val = (raw_item_val as boolean) ? 1 : 0;
}
const new_item = { const new_item = {
x: val_t, x: val_t,
y: item_val, y: item_val,
value: raw_item_val,
} as Point; } as Point;
memo.value.insert(new_item); memo.value.insert(new_item);
if (item_val < min.value) { if (item_val < min.value) {
@@ -392,7 +412,7 @@ function onMouseExit(event: MouseEvent) {
class="fade_other_selected label" class="fade_other_selected label"
:x="graph_data.x_map(toValue(graph_data.max_x)) + text_offset" :x="graph_data.x_map(toValue(graph_data.max_x)) + text_offset"
:y="axis_data.y_map(current_data_point.y)" :y="axis_data.y_map(current_data_point.y)"
:value="current_data_point.y" :value="current_data_point.value"
> >
</ValueLabel> </ValueLabel>
<template v-if="toValue(graph_data.legend_enabled)"> <template v-if="toValue(graph_data.legend_enabled)">
@@ -445,9 +465,10 @@ function onMouseExit(event: MouseEvent) {
<span>{{ telemetry_data?.data_type }}</span> <span>{{ telemetry_data?.data_type }}</span>
</div> </div>
<div class="row"> <div class="row">
<span>{{ <span v-if="current_data_point !== undefined">{{
current_data_point?.y || 'Missing Data' current_data_point.value
}}</span> }}</span>
<span v-else>Missing Data</span>
</div> </div>
</template> </template>
<template v-else> <template v-else>

View File

@@ -55,6 +55,7 @@ const numeric_data = computed(() => {
v-bind="$attrs" v-bind="$attrs"
:value="numeric_data" :value="numeric_data"
:max_width="10" :max_width="10"
include_span
></NumericText> ></NumericText>
<span v-else v-bind="$attrs"> <span v-else v-bind="$attrs">
Cannot Display Data of Type {{ telemetry_data!.data_type }} Cannot Display Data of Type {{ telemetry_data!.data_type }}

View File

@@ -1,12 +1,12 @@
<script setup lang="ts"> <script setup lang="ts">
import { computed, ref, useTemplateRef, watch } from 'vue'; import { computed, ref, useTemplateRef, watch } from 'vue';
import NumericText from '@/components/NumericText.vue'; import NumericText from '@/components/NumericText.vue';
import BooleanText from '@/components/BooleanText.vue';
defineProps<{ defineProps<{
x: number; x: number;
y: number; y: number;
value: number; value: number | boolean;
class?: string;
}>(); }>();
const background_offset = computed(() => 5); const background_offset = computed(() => 5);
@@ -34,7 +34,7 @@ function update_value_text(text: string) {
<template> <template>
<rect <rect
:class="$props.class" :class="$attrs.class"
:x="x - background_offset" :x="x - background_offset"
:y="y - y_offset - background_offset" :y="y - y_offset - background_offset"
:width="label_width + background_offset * 2" :width="label_width + background_offset * 2"
@@ -42,10 +42,16 @@ function update_value_text(text: string) {
></rect> ></rect>
<text :class="$props.class" ref="label-ref" :x="x" :y="y"> <text :class="$props.class" ref="label-ref" :x="x" :y="y">
<NumericText <NumericText
v-if="typeof value == 'number'"
:value="value" :value="value"
:max_width="6" :max_width="6"
@update="update_value_text" @update="update_value_text"
></NumericText> ></NumericText>
<BooleanText
v-else-if="typeof value == 'boolean'"
:value="value"
@update="update_value_text"
></BooleanText>
</text> </text>
</template> </template>

View File

@@ -1,6 +1,7 @@
export interface Point { export interface Point {
x: number; x: number;
y: number; y: number;
value: number | boolean;
} }
export class PointLine { export class PointLine {

View File

@@ -5,12 +5,14 @@ package core;
enum TelemetryDataType { enum TelemetryDataType {
Float32 = 0; Float32 = 0;
Float64 = 1; Float64 = 1;
Boolean = 2;
} }
message TelemetryValue { message TelemetryValue {
oneof value { oneof value {
float float_32 = 1; float float_32 = 1;
double float_64 = 2; double float_64 = 2;
bool boolean = 3;
} }
} }

View File

@@ -111,6 +111,7 @@ impl CoreTelemetryService {
let expected_type = match value { let expected_type = match value {
Value::Float32(_) => TelemetryDataType::Float32, Value::Float32(_) => TelemetryDataType::Float32,
Value::Float64(_) => TelemetryDataType::Float64, Value::Float64(_) => TelemetryDataType::Float64,
Value::Boolean(_) => TelemetryDataType::Boolean,
}; };
if expected_type != tlm_data.data.definition.data_type { if expected_type != tlm_data.data.definition.data_type {
return Err(Status::failed_precondition("Data Type Mismatch")); return Err(Status::failed_precondition("Data Type Mismatch"));
@@ -124,6 +125,7 @@ impl CoreTelemetryService {
let value = match value { let value = match value {
Value::Float32(x) => TelemetryDataValue::Float32(x), Value::Float32(x) => TelemetryDataValue::Float32(x),
Value::Float64(x) => TelemetryDataValue::Float64(x), Value::Float64(x) => TelemetryDataValue::Float64(x),
Value::Boolean(x) => TelemetryDataValue::Boolean(x),
}; };
let _ = tlm_data.data.data.send_replace(Some(TelemetryDataItem { let _ = tlm_data.data.data.send_replace(Some(TelemetryDataItem {
value: value.clone(), value: value.clone(),

View File

@@ -30,3 +30,16 @@ primitive_write_read!(i8, 1);
primitive_write_read!(f64, 8); primitive_write_read!(f64, 8);
primitive_write_read!(f32, 4); primitive_write_read!(f32, 4);
impl FileWriteableType for bool {
fn write_to_file(self, file: &mut impl Write) -> std::io::Result<()> {
file.write_all(&[if self { 0x01 } else { 0x00 }])
}
}
impl FileReadableType for bool {
fn read_from_file(file: &mut impl Read) -> std::io::Result<Self> {
let mut buffer = [0u8; 1];
file.read_exact(&mut buffer)?;
Ok(buffer[0] != 0x00)
}
}

View File

@@ -4,4 +4,5 @@ use serde::{Deserialize, Serialize};
pub enum TelemetryDataValue { pub enum TelemetryDataValue {
Float32(f32), Float32(f32),
Float64(f64), Float64(f64),
Boolean(bool),
} }

View File

@@ -198,6 +198,7 @@ impl HistorySegmentFile {
match value { match value {
TelemetryDataValue::Float32(value) => file.write_data::<f32>(*value)?, TelemetryDataValue::Float32(value) => file.write_data::<f32>(*value)?,
TelemetryDataValue::Float64(value) => file.write_data::<f64>(*value)?, TelemetryDataValue::Float64(value) => file.write_data::<f64>(*value)?,
TelemetryDataValue::Boolean(value) => file.write_data::<bool>(*value)?,
} }
} }
@@ -346,6 +347,10 @@ impl HistorySegmentFile {
self.file_position += 8; self.file_position += 8;
Ok(TelemetryDataValue::Float64(self.file.read_data::<f64>()?)) Ok(TelemetryDataValue::Float64(self.file.read_data::<f64>()?))
} }
TelemetryDataType::Boolean => {
self.file_position += 1;
Ok(TelemetryDataValue::Boolean(self.file.read_data::<bool>()?))
}
} }
} }
@@ -357,6 +362,7 @@ impl HistorySegmentFile {
let item_length = match telemetry_data_type { let item_length = match telemetry_data_type {
TelemetryDataType::Float32 => 4, TelemetryDataType::Float32 => 4,
TelemetryDataType::Float64 => 8, TelemetryDataType::Float64 => 8,
TelemetryDataType::Boolean => 1,
}; };
let desired_position = let desired_position =
Self::HEADER_LENGTH + self.length * Self::TIMESTAMP_LENGTH + index * item_length; Self::HEADER_LENGTH + self.length * Self::TIMESTAMP_LENGTH + index * item_length;