use cfg_mixin::cfg_mixin;
use serde::{Deserialize, Serialize};
use serde_repr::{Deserialize_repr, Serialize_repr};
use crate::joints::{JointFormat, JointRepr, JointTemplate, JointType, JointValue};
#[cfg_attr(feature = "py", pyo3::pyclass(from_py_object))]
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq)]
pub enum OnOff {
ON,
OFF,
}
pub type OnOnly = monostate::MustBe!("ON");
pub type OffOnly = monostate::MustBe!("OFF");
#[macro_export]
#[doc(hidden)]
macro_rules! impl_monostate_member {
($strct:ident.$name:ident = $value:expr) => {
::paste::paste! {
#[cfg_mixin(feature = "py")]
#[cfg_attr(feature = "py", pyo3::pymethods)]
impl $strct {
#[on(setter)]
pub fn [<set_ $name>](&mut self, on: bool) {
self.$name = if on { Some(::monostate::MustBe!($value)) } else { None };
}
#[on(getter)]
pub fn [<get_ $name>](&self) -> bool {
self.$name.is_some()
}
}
}
};
}
#[cfg_attr(feature = "py", pyo3::pyclass(from_py_object))]
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq)]
pub enum ApplicationType {
Handling,
Arc,
Spot,
Dispense,
}
#[cfg_attr(feature = "py", pyo3::pyclass(from_py_object))]
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq)]
pub enum PalletizingMode {
ZERODN,
ZEROUP,
PSPIDN,
PSPIUP,
MSPIDN,
MSPIUP,
}
#[cfg_attr(feature = "py", pyo3::pyclass(from_py_object))]
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq)]
pub struct FrameData {
pub x: f32,
pub y: f32,
pub z: f32,
pub w: f32,
pub p: f32,
pub r: f32,
}
#[cfg_attr(feature = "py", pyo3::pyclass(from_py_object))]
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq)]
pub struct Configuration {
#[serde(rename = "UToolNumber")]
pub u_tool_number: u8,
#[serde(rename = "UFrameNumber")]
pub u_frame_number: u8,
#[serde(rename = "Front")]
pub front: i8,
#[serde(rename = "Up")]
pub up: i8,
#[serde(rename = "Left")]
pub left: i8,
#[serde(rename = "Flip")]
pub flip: i8,
#[serde(rename = "Turn4")]
pub turn4: i8,
#[serde(rename = "Turn5")]
pub turn5: i8,
#[serde(rename = "Turn6")]
pub turn6: i8,
}
impl Default for Configuration {
fn default() -> Self {
Self {
u_tool_number: 1,
u_frame_number: 1,
front: 1,
up: 1,
left: 1,
flip: 0,
turn4: 0,
turn5: 0,
turn6: 0,
}
}
}
#[cfg_attr(feature = "py", pyo3::pyclass(from_py_object))]
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq)]
#[serde(rename_all = "PascalCase")]
pub struct Position {
pub x: f32,
pub y: f32,
pub z: f32,
pub w: f32,
pub p: f32,
pub r: f32,
pub ext1: f32,
pub ext2: f32,
pub ext3: f32,
}
impl Default for Position {
fn default() -> Self {
Self {
x: 0.0,
y: 0.0,
z: 0.0,
w: 0.0,
p: 0.0,
r: 0.0,
ext1: 0.0,
ext2: 0.0,
ext3: 0.0,
}
}
}
#[cfg_mixin(feature = "py")]
#[cfg_attr(feature = "py", pyo3::pyclass(str, from_py_object, get_all, set_all))]
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq)]
#[serde(rename_all = "PascalCase")]
pub struct JointAngles {
pub j1: f32,
pub j2: f32,
pub j3: f32,
pub j4: f32,
pub j5: f32,
pub j6: f32,
pub j7: f32,
pub j8: f32,
pub j9: f32,
}
#[cfg_mixin(feature = "py")]
#[cfg_attr(feature = "py", pyo3::pymethods)]
impl JointAngles {
#[on(new)]
#[on(pyo3(signature = (format, template, j1, j2, j3, j4, j5, j6, j7=0.0, j8=0.0, j9=0.0)))]
#[allow(clippy::too_many_arguments)]
pub fn new9(
format: JointFormat,
template: JointTemplate,
j1: f32,
j2: f32,
j3: f32,
j4: f32,
j5: f32,
j6: f32,
j7: f32,
j8: f32,
j9: f32,
) -> Self {
let slf = Self {
j1,
j2,
j3,
j4,
j5,
j6,
j7,
j8,
j9,
};
JointFormat::FanucDeg.convert_from(format, &template, slf)
}
#[cfg(off)]
#[allow(clippy::too_many_arguments)]
pub fn new6(
format: JointFormat,
template: JointTemplate,
j1: f32,
j2: f32,
j3: f32,
j4: f32,
j5: f32,
j6: f32,
) -> Self {
let slf = Self {
j1,
j2,
j3,
j4,
j5,
j6,
j7: 0.0,
j8: 0.0,
j9: 0.0,
};
JointFormat::FanucDeg.convert_from(format, &template, slf)
}
pub fn as_array(&self) -> [f32; 9] {
[
self.j1, self.j2, self.j3, self.j4, self.j5, self.j6, self.j7, self.j8, self.j9,
]
}
}
impl std::fmt::Display for JointAngles {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let json_string = serde_json::to_string_pretty(self).map_err(|_| std::fmt::Error)?;
write!(f, "{}", json_string)
}
}
impl JointRepr for JointAngles {
fn to_deg(mut self, mask: &[JointType]) -> Self {
if !mask.is_empty() && mask[0] == JointType::Rotary {
self.j1 = self.j1.to_degrees();
}
if mask.len() > 1 && mask[1] == JointType::Rotary {
self.j2 = self.j2.to_degrees();
}
if mask.len() > 2 && mask[2] == JointType::Rotary {
self.j3 = self.j3.to_degrees();
}
if mask.len() > 3 && mask[3] == JointType::Rotary {
self.j4 = self.j4.to_degrees();
}
if mask.len() > 4 && mask[4] == JointType::Rotary {
self.j5 = self.j5.to_degrees();
}
if mask.len() > 5 && mask[5] == JointType::Rotary {
self.j6 = self.j6.to_degrees();
}
if mask.len() > 6 && mask[6] == JointType::Rotary {
self.j7 = self.j7.to_degrees();
}
if mask.len() > 7 && mask[7] == JointType::Rotary {
self.j8 = self.j8.to_degrees();
}
if mask.len() > 8 && mask[8] == JointType::Rotary {
self.j9 = self.j9.to_degrees();
}
self
}
fn to_rad(mut self, mask: &[JointType]) -> Self {
if !mask.is_empty() && mask[0] == JointType::Rotary {
self.j1 = self.j1.to_radians();
}
if mask.len() > 1 && mask[1] == JointType::Rotary {
self.j2 = self.j2.to_radians();
}
if mask.len() > 2 && mask[2] == JointType::Rotary {
self.j3 = self.j3.to_radians();
}
if mask.len() > 3 && mask[3] == JointType::Rotary {
self.j4 = self.j4.to_radians();
}
if mask.len() > 4 && mask[4] == JointType::Rotary {
self.j5 = self.j5.to_radians();
}
if mask.len() > 5 && mask[5] == JointType::Rotary {
self.j6 = self.j6.to_radians();
}
if mask.len() > 6 && mask[6] == JointType::Rotary {
self.j7 = self.j7.to_radians();
}
if mask.len() > 7 && mask[7] == JointType::Rotary {
self.j8 = self.j8.to_radians();
}
if mask.len() > 8 && mask[8] == JointType::Rotary {
self.j9 = self.j9.to_radians();
}
self
}
fn to_abs(mut self) -> Self {
self.j3 += self.j2;
self
}
fn to_fanuc(mut self) -> Self {
self.j3 -= self.j2;
self
}
fn len(&self) -> usize {
9
}
fn to_array<const N: usize, D: JointValue>(
self,
_fill_missing_nan: bool,
) -> Result<[D; N], crate::joints::JointDataSizeError> {
if N > 9 {
return Err(crate::joints::JointDataSizeError(9));
}
let mut arr: [D; N] = [D::nan(); N];
let joints = [
self.j1, self.j2, self.j3, self.j4, self.j5, self.j6, self.j7, self.j8, self.j9,
];
for i in 0..N {
arr[i] = D::from_f32(joints[i]);
}
Ok(arr)
}
}
#[cfg_attr(feature = "py", pyo3::pyclass(from_py_object))]
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq)]
pub enum LcbType {
TB,
DB,
TA,
}
#[cfg_attr(feature = "py", pyo3::pyclass(from_py_object))]
#[derive(Serialize_repr, Deserialize_repr, Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u8)]
pub enum PortType {
DOUT = 1,
ROUT = 2,
}
#[cfg_mixin(feature = "py")]
#[cfg_attr(feature = "py", pyo3::pyclass(from_py_object))]
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq)]
pub struct LocalConditionBlock {
#[on(pyo3(get, set))]
#[serde(rename = "LCBType")]
pub lcb_type: LcbType,
#[on(pyo3(get, set))]
#[serde(rename = "LCBValue")]
pub lcb_value: u16,
#[on(pyo3(get, set))]
#[serde(rename = "PortType")]
pub port_type: PortType,
#[on(pyo3(get, set))]
#[serde(rename = "portNumber")]
pub port_number: u16,
#[on(pyo3(get, set))]
#[serde(rename = "portValue")]
pub port_value: OnOff,
}
#[cfg_mixin(feature = "py")]
#[cfg_attr(feature = "py", pyo3::pyclass(from_py_object))]
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Default)]
pub struct OffsetRegisterNumbers {
#[on(pyo3(get, set))]
#[serde(
rename = "OffsetPRNumber",
default,
skip_serializing_if = "Option::is_none"
)]
pub offset: Option<u16>,
#[on(pyo3(get, set))]
#[serde(
rename = "VisionPRNumber",
default,
skip_serializing_if = "Option::is_none"
)]
pub vision_offset: Option<u16>,
#[on(pyo3(get, set))]
#[serde(
rename = "ToolOffsetPRNumber",
default,
skip_serializing_if = "Option::is_none"
)]
pub tool_offset: Option<u16>,
}
#[cfg_attr(feature = "py", pyo3::pyclass(from_py_object))]
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq)]
pub enum TermType {
FINE,
CNT,
CR,
}
#[cfg_attr(feature = "py", pyo3::pyclass(from_py_object))]
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq)]
pub enum SpeedType {
#[serde(rename = "mmSec")]
MMSec, #[serde(rename = "InchMin")]
InchMin, #[serde(rename = "Time")]
TimeSec, #[serde(rename = "mSec")]
MilliSeconds, }
#[cfg(feature = "py")]
pub mod py {
use super::*;
use pyo3::prelude::*;
pub fn register(parent_module: &Bound<'_, PyModule>) -> PyResult<()> {
parent_module.add_class::<OnOff>()?;
parent_module.add_class::<ApplicationType>()?;
parent_module.add_class::<FrameData>()?;
parent_module.add_class::<Configuration>()?;
parent_module.add_class::<Position>()?;
parent_module.add_class::<JointAngles>()?;
parent_module.add_class::<LcbType>()?;
parent_module.add_class::<PortType>()?;
parent_module.add_class::<LocalConditionBlock>()?;
parent_module.add_class::<OffsetRegisterNumbers>()?;
parent_module.add_class::<TermType>()?;
parent_module.add_class::<SpeedType>()?;
Ok(())
}
}