piglet_client 0.4.0

A bare-bones client for controlling IP-based Hamilton robots
Documentation
use crate::client::{Error, Error::ConnectionError, RobotClient};
use crate::object_address::ObjectAddress;
use crate::values::{PigletDeserialize, PigletSerialize};
use anyhow::anyhow;
use bytes::{Buf, Bytes, BytesMut};
use std::sync::Arc;

#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub struct Enum {
    pub labels: Vec<String>,
    pub name: String,
    pub values: Vec<i32>,
}

#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub struct Interface {
    pub label: String,
    pub id: u8,
}

#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub struct Method {
    pub call_type: u8,
    pub interface_id: u8,
    pub method_id: u16,
    pub name: String,
    pub parameter_labels: Vec<String>,
    pub parameter_types: Vec<u8>,
}

#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub struct Object {
    pub address: ObjectAddress,
    pub name: String,
    pub version: String,
    pub method_count: u32,
    pub subobject_count: u16,
}

#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub struct Struct {
    pub element_labels: Vec<String>,
    pub element_types: Vec<u8>,
    pub name: String,
}

pub struct DynamicObject {
    address: ObjectAddress,
    robot: Arc<RobotClient>,
}

impl DynamicObject {
    pub fn new(address: &ObjectAddress, robot: &Arc<RobotClient>) -> Self {
        Self {
            address: address.clone(),
            robot: robot.clone(),
        }
    }

    pub async fn get_object(&self) -> Result<Object, Error> {
        let (count, mut stream) = self.robot.act(&self.address, 0, 0, 1, Bytes::new()).await?;
        if count != 4 {
            return Err(ConnectionError(anyhow!("Expected 4 values, not {}", count)));
        }
        let name = String::deserialize(&mut stream)?;
        let version = String::deserialize(&mut stream)?;
        let method_count = u32::deserialize(&mut stream)?;
        let subobject_count = u16::deserialize(&mut stream)?;
        Ok(Object {
            address: self.address.clone(),
            name,
            version,
            method_count,
            subobject_count,
        })
    }

    pub async fn get_subobject_address(&self, index: u16) -> Result<ObjectAddress, Error> {
        let mut args = BytesMut::new();
        index.serialize(&mut args);
        let (count, mut stream) = self
            .robot
            .act(&self.address, 0, 0, 3, args.freeze())
            .await?;
        if count != 3 {
            return Err(ConnectionError(anyhow!("Expected 3 values, not {}", count)));
        }
        let module_id = u16::deserialize(&mut stream)?;
        let node_id = u16::deserialize(&mut stream)?;
        let object_id = u16::deserialize(&mut stream)?;
        Ok(ObjectAddress {
            module_id,
            node_id,
            object_id,
        })
    }

    pub async fn get_enums(&self, interface_id: u8) -> Result<Vec<Enum>, Error> {
        let mut args = BytesMut::new();
        interface_id.serialize(&mut args);
        let (count, mut stream) = self
            .robot
            .act(&self.address, 0, 0, 5, args.freeze())
            .await?;
        if count != 4 {
            return Err(ConnectionError(anyhow!("Expected 4 values, not {}", count)));
        }
        let names = Vec::<String>::deserialize(&mut stream)?;
        let numbers = Vec::<u32>::deserialize(&mut stream)?;
        let enum_values = Vec::<i32>::deserialize(&mut stream)?;
        let descriptions = Vec::<String>::deserialize(&mut stream)?;

        let mut enums = Vec::new();
        let mut offset = 0;
        for i in 0..names.len() {
            let count = numbers[i] as usize;
            enums.push(Enum {
                name: names[i].clone(),
                labels: descriptions[offset..(offset + count)].to_vec(),
                values: enum_values[offset..(offset + count)].to_vec(),
            });
            offset += count;
        }
        Ok(enums)
    }

    pub async fn get_interfaces(&self) -> Result<Vec<Interface>, Error> {
        let (count, mut stream) = self.robot.act(&self.address, 0, 0, 4, Bytes::new()).await?;
        if count != 2 {
            return Err(ConnectionError(anyhow!("Expected 2 values, not {}", count)));
        }
        let ids = Vec::<u8>::deserialize(&mut stream)?;
        let descriptions = Vec::<String>::deserialize(&mut stream)?;
        let mut interfaces = Vec::new();
        for i in 0..ids.len() {
            interfaces.push(Interface {
                id: ids[i],
                label: descriptions[i].clone(),
            });
        }
        Ok(interfaces)
    }

    pub async fn get_method(&self, index: u32) -> Result<Method, Error> {
        let mut args = BytesMut::new();
        index.serialize(&mut args);
        let (count, mut stream) = self
            .robot
            .act(&self.address, 0, 0, 2, args.freeze())
            .await?;
        if count != 6 {
            return Err(ConnectionError(anyhow!("Expected 6 values, not {}", count)));
        }
        let interface_id = u8::deserialize(&mut stream)?;
        let call_type = u8::deserialize(&mut stream)?;
        let method_id = u16::deserialize(&mut stream)?;
        let name = String::deserialize(&mut stream)?;
        let parameter_types = String::deserialize(&mut stream)?.as_bytes().to_vec();
        let parameter_labels = if stream.remaining() > 0 {
            let s = String::deserialize(&mut stream)?;
            if s.len() > 0 {
                s.split(",").map(|s| s.to_string()).collect()
            } else {
                Vec::new()
            }
        } else {
            vec![]
        };
        Ok(Method {
            call_type,
            interface_id,
            method_id,
            name,
            parameter_labels,
            parameter_types,
        })
    }

    pub async fn get_structs(&self, interface_id: u8) -> Result<Vec<Struct>, Error> {
        let mut args = BytesMut::new();
        interface_id.serialize(&mut args);
        let (count, mut stream) = self
            .robot
            .act(&self.address, 0, 0, 6, args.freeze())
            .await?;
        if count != 4 {
            return Err(ConnectionError(anyhow!("Expected 4 values, not {}", count)));
        }
        let names = Vec::<String>::deserialize(&mut stream)?;
        let numbers = Vec::<u32>::deserialize(&mut stream)?;
        let element_types = Vec::<u8>::deserialize(&mut stream)?;
        let element_labels = Vec::<String>::deserialize(&mut stream)?;

        let mut structs = Vec::new();
        let mut labels_offset = 0;
        let mut types_offset = 0;
        for i in 0..names.len() {
            let labels_count = numbers[i] as usize;
            let mut types_count = 0;
            for _i in 0..labels_count {
                let jump = match element_types[types_offset + types_count] {
                    30 => 3,
                    32 => 3,
                    _ => 1,
                };
                types_count += jump;
            }
            structs.push(Struct {
                name: names[i].clone(),
                element_labels: element_labels[labels_offset..(labels_offset + labels_count)]
                    .to_vec(),
                element_types: element_types[types_offset..(types_offset + types_count)].to_vec(),
            });
            labels_offset += labels_count;
            types_offset += types_count;
        }
        Ok(structs)
    }
}