micropb for rust - initial

This commit is contained in:
Игорь Жуков 2024-12-02 20:06:40 +03:00
parent 007e793ded
commit aae8f12a56
7 changed files with 209 additions and 23 deletions

View File

@ -32,6 +32,13 @@ embedded-alloc = "0.6.0"
# data structures
ringbuffer = { version = "0.15.0", features = [] }
#Protobuf
micropb = {version = "=0.1.0", features = ["alloc"]}
[build-dependencies]
# Allow types from `heapless` to be used for container fields
micropb-gen = { version = "0.1.0"}
[[bin]]
name = "MRTIC"
test = false

View File

@ -40,4 +40,12 @@ fn main() {
// Set the linker script to the one provided by cortex-m-rt.
println!("cargo:rustc-link-arg=-Tlink.x");
let mut gen = micropb_gen::Generator::new();
gen. use_container_alloc();
// Compile example.proto into a Rust module
gen.compile_protos(&["src/proto/meta.proto"], std::env::var("OUT_DIR").unwrap() + "/meta.rs").unwrap();
}

View File

@ -10,29 +10,37 @@ fn panic() -> ! {
cortex_m::asm::udf()
}
mod proto {
#![allow(clippy::all)]
#![allow(nonstandard_style, unused, irrefutable_let_patterns)]
include!(concat!(env!("OUT_DIR"), "/meta.rs"));
}
//use proto::space_::kscience_::dataforge_::io_::proto_::ProtoMeta_;
use proto::space_::kscience_::dataforge_::io_::proto_::ProtoMeta_::ProtoValue_::*;
//use proto::example_package_::*;
#[rtic::app(device = stm32f7xx_hal::pac, peripherals = true, dispatchers = [EXTI0])]
mod app {
use proto::space_::kscience_::dataforge_::io_::proto_::ProtoMeta;
use shared_resources::message_buffer_that_needs_to_be_locked;
//Declare Parameters
use core::fmt::Write;
systick_monotonic!(Mono, 1000);
use stm32f7xx_hal::{
gpio::{GpioExt, Output, PushPull, PI1},
pac::{Interrupt, USART1},
prelude::*,
rcc::RccExt,
serial::{self, Config, Event, Rx, Serial, Tx}
serial::{Config, Event, Rx, Serial, Tx}
};
use super::*;
use core::{fmt::Write, mem::size_of};
use rtic_monotonics::systick::prelude::*;
use alloc::string::String;
use embedded_alloc::LlffHeap as Heap;
use ringbuffer::{AllocRingBuffer, RingBuffer};
use micropb::{PbRead, PbEncoder, PbDecoder, MessageDecode, MessageEncode};
use alloc::string::String;
use alloc::vec::Vec;
systick_monotonic!(Mono, 1000);
#[global_allocator]
static HEAP: Heap = Heap::empty();
@ -55,22 +63,18 @@ mod app {
fn init(ctx: init::Context) -> (Shared, Local) {
//Allocator
{
{
use core::mem::MaybeUninit;
const HEAP_SIZE: usize = 2048;
static mut HEAP_MEM: [MaybeUninit<u8>; HEAP_SIZE] = [MaybeUninit::uninit(); HEAP_SIZE];
unsafe { HEAP.init(HEAP_MEM.as_ptr() as usize, HEAP_SIZE) }
}
rtic::pend(Interrupt::UART4);
}
// Cortex-M peripherals
let rcc = ctx.device.RCC.constrain();
let clocks = rcc.cfgr.sysclk(48.MHz()).freeze();
//Systick
Mono::start(ctx.core.SYST, 36_000_000);
//GPIO
@ -78,7 +82,6 @@ mod app {
let GPIOA = ctx.device.GPIOA.split();
let GPIOB = ctx.device.GPIOB.split();
//UART
let usart1_tx = GPIOA.pa9.into_alternate();
let usart1_rx = GPIOB.pb7.into_alternate();
@ -110,7 +113,13 @@ mod app {
//TASKS
blinker::spawn().ok();
//serial_task::spawn().ok();
proto_task::spawn().ok();
let mut stream: Vec<u8> = Vec::new();
// let mut decoder = PbDecoder::new(stream.as_slice());
// let mut meta_out: ProtoMeta = Default::default();
// meta_out.decode_len_delimited(&mut decoder);
defmt::info!("INITED");
(
@ -175,15 +184,52 @@ mod app {
fn usart1_handler(ctx: usart1_handler::Context){
let serial = ctx.local.rx_vcp;
let mut message_buffer = ctx.shared.message_buffer;
defmt::trace!("RX not empty");
if let Ok(byte) = serial.read() {
defmt::debug!("RX Byte value: {=u8:x}", byte);
}
if let Ok(byte) = serial.read() {
message_buffer.lock(|buf| {
buf.push(byte);
});
}
}
#[task(shared = [message_buffer], priority = 1)]
async fn proto_task(ctx: proto_task::Context)
{
let mut message_buffer = ctx.shared.message_buffer;
let mut buffer = Vec::new();
let mut meta_out:ProtoMeta = Default::default();
loop{
let mut is_empty = false;
message_buffer.lock(|buf| {
if buf.is_empty() {
is_empty = true;
} else {
defmt::info!("DATA!");
while let Some(byte) = buf.dequeue() {
buffer.push(byte);
}
}
});
if is_empty {
// Sleep for a while if the buffer is empty
Mono::delay(5000.millis()).await;
defmt::trace!("await for data");
continue;
}
let mut decoder = PbDecoder::new(buffer.as_slice());
if let Ok(message) = meta_out.decode_len_delimited(&mut decoder) {
defmt::info!("Received message: {:?}", message);
} else {
defmt::info!("Failed to parse message");
}
}
}
//APP ENDS
}

17
src/proto/example.proto Normal file
View File

@ -0,0 +1,17 @@
syntax = "proto3";
package example_package;
message Example {
int32 f_int32 = 1;
int64 f_int64 = 2;
uint32 f_uint32 = 3;
uint64 f_uint64 = 4;
sint32 f_sint32 = 5;
sint64 f_sint64 = 6;
bool f_bool = 7;
fixed32 f_fixed32 = 8;
fixed64 f_fixed64 = 9;
sfixed32 f_sfixed32 = 10;
sfixed64 f_sfixed64 = 11;
float f_float = 12;
double f_double = 13;
}

30
src/proto/meta.proto Normal file
View File

@ -0,0 +1,30 @@
syntax = "proto3";
package space.kscience.dataforge.io.proto;
message ProtoMeta {
message ProtoValue {
oneof value {
string stringValue = 2;
bool booleanValue = 3;
double doubleValue = 4;
float floatValue = 5;
int32 int32Value = 6;
int64 int64Value = 7;
bytes bytesValue = 8;
ProtoValueList listValue = 9;
Float64List float64ListValue = 10;
}
}
message ProtoValueList{
repeated ProtoValue values = 1;
}
message Float64List{
repeated double values = 1 [packed=true];
}
ProtoValue protoValue = 1;
map<string, ProtoMeta> items = 2;
}

48
src/proto/meta_pb2.py Normal file
View File

@ -0,0 +1,48 @@
# -*- coding: utf-8 -*-
# Generated by the protocol buffer compiler. DO NOT EDIT!
# NO CHECKED-IN PROTOBUF GENCODE
# source: meta.proto
# Protobuf Python Version: 5.27.0-rc3
"""Generated protocol buffer code."""
from google.protobuf import descriptor as _descriptor
from google.protobuf import descriptor_pool as _descriptor_pool
from google.protobuf import runtime_version as _runtime_version
from google.protobuf import symbol_database as _symbol_database
from google.protobuf.internal import builder as _builder
_runtime_version.ValidateProtobufRuntimeVersion(
_runtime_version.Domain.PUBLIC,
5,
27,
0,
'-rc3',
'meta.proto'
)
# @@protoc_insertion_point(imports)
_sym_db = _symbol_database.Default()
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\nmeta.proto\x12!space.kscience.dataforge.io.proto\"\xd8\x05\n\tProtoMeta\x12K\n\nprotoValue\x18\x01 \x01(\x0b\x32\x37.space.kscience.dataforge.io.proto.ProtoMeta.ProtoValue\x12\x46\n\x05items\x18\x02 \x03(\x0b\x32\x37.space.kscience.dataforge.io.proto.ProtoMeta.ItemsEntry\x1a\xdb\x02\n\nProtoValue\x12\x15\n\x0bstringValue\x18\x02 \x01(\tH\x00\x12\x16\n\x0c\x62ooleanValue\x18\x03 \x01(\x08H\x00\x12\x15\n\x0b\x64oubleValue\x18\x04 \x01(\x01H\x00\x12\x14\n\nfloatValue\x18\x05 \x01(\x02H\x00\x12\x14\n\nint32Value\x18\x06 \x01(\x05H\x00\x12\x14\n\nint64Value\x18\x07 \x01(\x03H\x00\x12\x14\n\nbytesValue\x18\x08 \x01(\x0cH\x00\x12P\n\tlistValue\x18\t \x01(\x0b\x32;.space.kscience.dataforge.io.proto.ProtoMeta.ProtoValueListH\x00\x12T\n\x10\x66loat64ListValue\x18\n \x01(\x0b\x32\x38.space.kscience.dataforge.io.proto.ProtoMeta.Float64ListH\x00\x42\x07\n\x05value\x1aY\n\x0eProtoValueList\x12G\n\x06values\x18\x01 \x03(\x0b\x32\x37.space.kscience.dataforge.io.proto.ProtoMeta.ProtoValue\x1a!\n\x0b\x46loat64List\x12\x12\n\x06values\x18\x01 \x03(\x01\x42\x02\x10\x01\x1aZ\n\nItemsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12;\n\x05value\x18\x02 \x01(\x0b\x32,.space.kscience.dataforge.io.proto.ProtoMeta:\x02\x38\x01\x62\x06proto3')
_globals = globals()
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'meta_pb2', _globals)
if not _descriptor._USE_C_DESCRIPTORS:
DESCRIPTOR._loaded_options = None
_globals['_PROTOMETA_FLOAT64LIST'].fields_by_name['values']._loaded_options = None
_globals['_PROTOMETA_FLOAT64LIST'].fields_by_name['values']._serialized_options = b'\020\001'
_globals['_PROTOMETA_ITEMSENTRY']._loaded_options = None
_globals['_PROTOMETA_ITEMSENTRY']._serialized_options = b'8\001'
_globals['_PROTOMETA']._serialized_start=50
_globals['_PROTOMETA']._serialized_end=778
_globals['_PROTOMETA_PROTOVALUE']._serialized_start=213
_globals['_PROTOMETA_PROTOVALUE']._serialized_end=560
_globals['_PROTOMETA_PROTOVALUELIST']._serialized_start=562
_globals['_PROTOMETA_PROTOVALUELIST']._serialized_end=651
_globals['_PROTOMETA_FLOAT64LIST']._serialized_start=653
_globals['_PROTOMETA_FLOAT64LIST']._serialized_end=686
_globals['_PROTOMETA_ITEMSENTRY']._serialized_start=688
_globals['_PROTOMETA_ITEMSENTRY']._serialized_end=778
# @@protoc_insertion_point(module_scope)

View File

@ -0,0 +1,30 @@
import serial
import numpy as np
import meta_pb2
# Create the Protobuf message
quaternion = meta_pb2.ProtoMeta(
protoValue=None,
items={
'quaternion': meta_pb2.ProtoMeta(
protoValue=meta_pb2.ProtoMeta.ProtoValue(
listValue=meta_pb2.ProtoMeta.ProtoValueList(
values=[
meta_pb2.ProtoMeta.ProtoValue(floatValue=np.float32(1.0)),
meta_pb2.ProtoMeta.ProtoValue(floatValue=np.float32(0.0)),
meta_pb2.ProtoMeta.ProtoValue(floatValue=np.float32(0.0)),
meta_pb2.ProtoMeta.ProtoValue(floatValue=np.float32(0.0))
]
)
)
)
}
)
# Serialize the message
serialized_message = quaternion.SerializeToString()
# Send the serialized message over COM3
with serial.Serial('COM3', 9600, timeout=1) as ser:
ser.write(serialized_message)
print("Message sent over COM3")