From 3bee5b6d09b00ac68fb713a887d976f5015739f5 Mon Sep 17 00:00:00 2001 From: Lachezar Lechev Date: Fri, 1 May 2020 16:12:38 +0300 Subject: [PATCH 01/14] arsdk - Add more `BufferID`s --- arsdk-rs/src/frame.rs | 59 ++++++++++++++++++++++++++++++++++++++----- 1 file changed, 52 insertions(+), 7 deletions(-) diff --git a/arsdk-rs/src/frame.rs b/arsdk-rs/src/frame.rs index b503951..3890e6c 100644 --- a/arsdk-rs/src/frame.rs +++ b/arsdk-rs/src/frame.rs @@ -76,13 +76,56 @@ pub enum Type { #[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)] pub enum BufferID { - CDNonAck = 10, //#define BD_NET_CD_NONACK_ID 10 - CDAck = 11, //#define BD_NET_CD_ACK_ID 11 - CDEmergency = 12, // #define BD_NET_CD_EMERGENCY_ID 12 - CDVideoAck = 13, // #define BD_NET_CD_VIDEO_ACK_ID 13 - DCVideo = 125, // #define BD_NET_DC_VIDEO_DATA_ID 125 - DCEvent = 126, // #define BD_NET_DC_EVENT_ID 126 - DCNavdata = 127, // #define BD_NET_DC_NAVDATA_ID 127 + /// pings from device + PING = 0, + /// respond to pings + PONG = 1, + /// C: + /// #define BD_NET_CD_NONACK_ID 10 + /// + /// PyParrot: + /// 'SEND_NO_ACK': 10, # not-ack commandsandsensors (piloting and camera rotations) + CDNonAck = 10, + /// C: + /// `#define BD_NET_CD_ACK_ID 11` + /// + /// PyParrot: + /// 'SEND_WITH_ACK': 11, # ack commandsandsensors (all piloting commandsandsensors) + CDAck = 11, + /// C: + /// `#define BD_NET_CD_EMERGENCY_ID 12` + /// + /// PyParrot: + /// `'SEND_HIGH_PRIORITY': 12, # emergency commandsandsensors` + CDEmergency = 12, + /// C: + /// #define BD_NET_CD_VIDEO_ACK_ID 13 + /// + /// PyParrot: + /// `'VIDEO_ACK': 13, # ack for video` + CDVideoAck = 13, + /// C: + /// #define BD_NET_DC_VIDEO_DATA_ID 125 + /// + /// PyParrot: + /// `'VIDEO_DATA' : 125, # video data` + DCVideo = 125, + /// C: + /// #define BD_NET_DC_EVENT_ID 126 + /// + /// PyParrot: + // 'NO_ACK_DRONE_DATA' : 126, # data from drone (including battery and others), no ack + /// + DCEvent = 126, + /// C: + /// #define BD_NET_DC_NAVDATA_ID 127 + /// + /// PyParrot: + /// `'ACK_DRONE_DATA' : 127, # drone data that needs an ack` + DCNavdata = 127, + // @TODO: Find the corresponding C definition if there is one and name the new enum variant! + // PyParrot: + // `'ACK_FROM_SEND_WITH_ACK': 139 # 128 + buffer id for 'SEND_WITH_ACK' is 139` } // --------------------- Conversion impls --------------------- // @@ -133,6 +176,8 @@ impl TryFrom for BufferID { impl Into for BufferID { fn into(self) -> u8 { match self { + Self::PING => 0, + Self::PONG => 1, Self::CDNonAck => 10, Self::CDAck => 11, Self::CDEmergency => 12, From 1c121ce26aec936228a9ffeaccd05719d9d67877 Mon Sep 17 00:00:00 2001 From: Lachezar Lechev Date: Fri, 1 May 2020 16:14:32 +0300 Subject: [PATCH 02/14] arsdk - PING & PONG - impl TryFrom for BufferID --- arsdk-rs/src/frame.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arsdk-rs/src/frame.rs b/arsdk-rs/src/frame.rs index 3890e6c..a52c7e8 100644 --- a/arsdk-rs/src/frame.rs +++ b/arsdk-rs/src/frame.rs @@ -161,6 +161,8 @@ impl TryFrom for BufferID { type Error = AnyError; fn try_from(v: u8) -> AnyResult { match v { + 0 => Ok(Self::PING), + 1 => Ok(Self::PONG), 10 => Ok(Self::CDNonAck), 11 => Ok(Self::CDAck), 12 => Ok(Self::CDEmergency), From a3751a38b7404d492505c5d0a4d0fa4fdb3d70d0 Mon Sep 17 00:00:00 2001 From: Lachezar Lechev Date: Fri, 1 May 2020 20:50:36 +0300 Subject: [PATCH 03/14] scroll - (de)serialization --- Cargo.lock | 19 +++++ arsdk-rs/Cargo.toml | 2 + arsdk-rs/src/ardrone3.rs | 42 +++++++++-- arsdk-rs/src/command.rs | 64 ++++++++++++++++- arsdk-rs/src/common.rs | 104 ++++++++++++++++++++++++++- arsdk-rs/src/frame.rs | 119 +++++++++++++++++++++++++++++- arsdk-rs/src/jumping_sumo.rs | 136 +++++++++++++++++++++++++++++++++-- bebop2/src/lib.rs | 3 + 8 files changed, 475 insertions(+), 14 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0b8e330..cb3d9aa 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -32,6 +32,8 @@ dependencies = [ "chrono", "dashmap", "pnet", + "scroll", + "scroll_derive", "serde", "serde_json", ] @@ -373,6 +375,23 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed3d612bc64430efeb3f7ee6ef26d590dce0c43249217bddc62112540c7941e1" +[[package]] +name = "scroll" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abb2332cb595d33f7edd5700f4cbf94892e680c7f0ae56adab58a35190b66cb1" + +[[package]] +name = "scroll_derive" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8584eea9b9ff42825b46faf46a8c24d2cff13ec152fa2a50df788b87c07ee28" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "serde" version = "1.0.106" diff --git a/arsdk-rs/Cargo.toml b/arsdk-rs/Cargo.toml index 8c0e742..c668557 100644 --- a/arsdk-rs/Cargo.toml +++ b/arsdk-rs/Cargo.toml @@ -14,3 +14,5 @@ serde = {version = "1.0", features = ["derive"]} serde_json = "1.0" dashmap = "3.11" chrono = "0.4" +scroll = "0.10" +scroll_derive = "0.10" diff --git a/arsdk-rs/src/ardrone3.rs b/arsdk-rs/src/ardrone3.rs index 661e3a5..39e9f59 100644 --- a/arsdk-rs/src/ardrone3.rs +++ b/arsdk-rs/src/ardrone3.rs @@ -1,7 +1,6 @@ use crate::frame::Data; /// eARCOMMANDS_ID_ARDRONE3_PILOTING_CMD -#[repr(u8)] #[derive(Debug, Clone, Copy, Eq, PartialEq)] pub enum ArDrone3 { /// ARCOMMANDS_ID_ARDRONE3_PILOTING_CMD_FLATTRIM = 0 @@ -29,17 +28,52 @@ pub enum ArDrone3 { /// ARCOMMANDS_ID_ARDRONE3_PILOTING_CMD_CANCELMOVETO = 11 CancelMoveTo = 11, /// ARCOMMANDS_ID_ARDRONE3_PILOTING_CMD_STARTPILOTEDPOI = 12 - StartPilotdPOI = 12, + StartPilotedPOI = 12, /// ARCOMMANDS_ID_ARDRONE3_PILOTING_CMD_STOPPILOTEDPOI = 13 StopPilotedPOI = 13, } impl Data for ArDrone3 { fn serialize(&self) -> Vec { - // todo: Fix this hardcoded value - let take_off: u16 = 1; take_off.to_le_bytes().to_vec() } } + +pub mod scroll_impl { + use super::*; + use scroll::{ctx, Endian, Pread}; + + impl<'a> ctx::TryFromCtx<'a, Endian> for ArDrone3 { + type Error = scroll::Error; + + // and the lifetime annotation on `&'a [u8]` here + fn try_from_ctx(src: &'a [u8], endian: Endian) -> Result<(Self, usize), Self::Error> { + use ArDrone3::*; + + let offset = &mut 0; + + let ardrone3 = match src.gread_with::(offset, endian)? { + 0 => FlatTrim, + 1 => TakeOff, + 2 => PCMD, + 3 => Landing, + 4 => Emergency, + 5 => NavigateHome, + 6 => AutoTakeOffMode, + 7 => MoveBy, + 8 => UserTakeOff, + 9 => Circle, + 10 => MoveTo, + 11 => CancelMoveTo, + 12 => StartPilotedPOI, + 13 => StopPilotedPOI, + _ => return Err(scroll::Error::Custom("Out of range".into())) + }; + + Ok((ardrone3, *offset)) + } + + } +} diff --git a/arsdk-rs/src/command.rs b/arsdk-rs/src/command.rs index 81cf1f4..39f1f8b 100644 --- a/arsdk-rs/src/command.rs +++ b/arsdk-rs/src/command.rs @@ -2,7 +2,7 @@ use crate::ardrone3::ArDrone3; use crate::common; use crate::frame::Data; use crate::jumping_sumo; -#[derive(Debug, PartialEq, Clone, Copy)] +#[derive(Debug, PartialEq, Eq, Clone, Copy)] pub enum Feature { Common(common::Class), // ARCOMMANDS_ID_FEATURE_COMMON = 0, @@ -72,6 +72,68 @@ impl Data for Feature { } } +pub mod scroll_impl { + use super::*; + use scroll::{ctx, Endian, Pread, Pwrite}; + + impl<'a> ctx::TryFromCtx<'a, Endian> for Feature { + type Error = scroll::Error; + + // and the lifetime annotation on `&'a [u8]` here + fn try_from_ctx(src: &'a [u8], endian: Endian) -> Result<(Self, usize), Self::Error> { + let mut offset = 0; + + let feature = match src.gread_with::(&mut offset, endian)? { + 0 => { + let common = src.gread_with(&mut offset, endian)?; + + Self::Common(common) + }, + 1 => { + let ardrone3 = src.gread_with(&mut offset, endian)?; + + Self::ArDrone3(ardrone3) + }, + 2 => Self::Minidrone, + 3 => { + let js_class = src.gread_with(&mut offset, endian)?; + + Self::JumpingSumo(js_class) + }, + 4 => Self::SkyController, + 8 => Self::PowerUp, + 133 => Self::Generic, + 134 => Self::FollowMe, + 135 => Self::Wifi, + 136 => Self::RC, + 137 => Self::DroneManager, + 138 => Self::Mapper, + 139 => Self::Debug, + 140 => Self::ControllerInfo, + 141 => Self::MapperMini, + 142 => Self::ThermalCam, + 144 => Self::Animation, + 147 => Self::SequoiaCam, + _ => return Err(scroll::Error::Custom("Out of range".into())) + }; + + Ok((feature, offset)) + } + } + + impl<'a> ctx::TryIntoCtx for Feature { + type Error = scroll::Error; + + fn try_into_ctx(self, this: &mut [u8], _ctx: Endian) -> Result { + let ser_feature = self.serialize(); + let written = this.pwrite_with(ser_feature.as_slice(), 0, ())?; + + + Ok(written) + } + } +} + // --------------------- Tests --------------------- // #[cfg(test)] diff --git a/arsdk-rs/src/common.rs b/arsdk-rs/src/common.rs index 3f24b21..a5ec272 100644 --- a/arsdk-rs/src/common.rs +++ b/arsdk-rs/src/common.rs @@ -1,7 +1,7 @@ use crate::frame::Data; use chrono::{offset::Utc, DateTime}; -#[derive(Debug, PartialEq, Clone, Copy)] +#[derive(Debug, PartialEq, Eq, Clone, Copy)] pub enum Class { Network, // ARCOMMANDS_ID_COMMON_CLASS_NETWORK = 0, NetworkEvent, // ARCOMMANDS_ID_COMMON_CLASS_NETWORKEVENT = 1, @@ -39,7 +39,7 @@ pub enum Class { Factory, // ARCOMMANDS_ID_COMMON_CLASS_FACTORY = 31, } -#[derive(Debug, PartialEq, Clone, Copy)] +#[derive(Debug, PartialEq, Eq, Clone, Copy)] pub enum Common { AllStates, // ARCOMMANDS_ID_COMMON_COMMON_CMD_ALLSTATES = 0, CurrentDate(DateTime), // ARCOMMANDS_ID_COMMON_COMMON_CMD_CURRENTDATE = 1, @@ -144,6 +144,106 @@ impl Into for Common { } } +pub mod scroll_impl { + use super::*; + use scroll::{ctx, Endian, Pread, Pwrite}; + + impl<'a> ctx::TryFromCtx<'a, Endian> for Class { + type Error = scroll::Error; + + // and the lifetime annotation on `&'a [u8]` here + fn try_from_ctx(src: &'a [u8], endian: Endian) -> Result<(Self, usize), Self::Error> { + let mut offset = 0; + + let class = match src.gread_with::(&mut offset, endian)? { + 0 => Self::Network, + 1 => Self::NetworkEvent, + 2 => Self::Settings, + 3 => Self::SettingsState, + 4 => { + let common = src.gread_with(&mut offset, endian)?; + + Self::Common(common) + } + 5 => Self::CommonState, + 6 => Self::Overheat, + 7 => Self::OverheatState, + 8 => Self::Controller, + 9 => Self::WifiSettings, + 10 => Self::WifiSettingsState, + 11 => Self::Mavlink, + 12 => Self::MavlinkState, + 13 => Self::Calibration, + 14 => Self::CalibrationState, + 15 => Self::CameraSettingsState, + 16 => Self::Gps, + 17 => Self::FlightPlanState, + 18 => Self::ArLibsVersionsState, + 19 => Self::FlightPlanEvent, + 20 => Self::Audio, + 21 => Self::AudioState, + 22 => Self::HeadLights, + 23 => Self::HeadLightsState, + 24 => Self::Animations, + 25 => Self::AnimationsState, + 26 => Self::Accessory, + 27 => Self::AccessoryState, + 28 => Self::Charger, + 29 => Self::ChargerState, + 30 => Self::Runstate, + 31 => Self::Factory, + 32 => Self::FlightPlanSettings, + 33 => Self::FlightPlanSettingsState, + _ => return Err(scroll::Error::Custom("Out of range".into())), + }; + + Ok((class, offset)) + } + } + + impl<'a> ctx::TryIntoCtx for Common { + type Error = scroll::Error; + + fn try_into_ctx(self, this: &mut [u8], _ctx: Endian) -> Result { + let ser_common = self.serialize(); + let written = this.pwrite_with(ser_common.as_slice(), 0, ())?; + + Ok(written) + } + } + + impl<'a> ctx::TryFromCtx<'a, Endian> for Common { + type Error = scroll::Error; + + fn try_from_ctx(src: &'a [u8], endian: Endian) -> Result<(Self, usize), Self::Error> { + use Common::*; + let mut offset = 0; + + let common = match src.gread_with::(&mut offset, endian)? { + 0 => AllStates, + // @TODO: FIX THIS! + 1 => CurrentDate(Utc::now()), + // @TODO: FIX THIS! + 2 => CurrentTime(Utc::now()), + 3 => Reboot, + _ => return Err(scroll::Error::Custom("Out of range".into())), + }; + + Ok((common, offset)) + } + } + + impl<'a> ctx::TryIntoCtx for Class { + type Error = scroll::Error; + + fn try_into_ctx(self, this: &mut [u8], _ctx: Endian) -> Result { + let ser_class = self.serialize(); + let written = this.pwrite_with(ser_class.as_slice(), 0, ())?; + + Ok(written) + } + } +} // --------------------- Tests --------------------- // #[cfg(test)] diff --git a/arsdk-rs/src/frame.rs b/arsdk-rs/src/frame.rs index a52c7e8..4050474 100644 --- a/arsdk-rs/src/frame.rs +++ b/arsdk-rs/src/frame.rs @@ -11,7 +11,7 @@ pub trait Data { fn serialize(&self) -> Vec; } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, PartialEq, Eq)] pub struct Frame { frame_type: Type, buffer_id: BufferID, @@ -64,7 +64,7 @@ impl IntoRawFrame for Frame { // --------------------- Types --------------------- // -#[derive(Debug, PartialEq, Clone, Copy)] +#[derive(Debug, PartialEq, Eq, Clone, Copy)] pub enum Type { Uninitialized = 0, // ARNETWORKAL_FRAME_TYPE_UNINITIALIZED 0 Ack = 1, // ARNETWORKAL_FRAME_TYPE_ACK 1 @@ -191,6 +191,121 @@ impl Into for BufferID { } } +pub mod impl_scroll { + use super::*; + use crate::command::Feature; + + use scroll::{ctx, Endian, Pread, Pwrite}; + + impl<'a> ctx::TryFromCtx<'a, Endian> for Frame { + type Error = scroll::Error; + + // and the lifetime annotation on `&'a [u8]` here + fn try_from_ctx(src: &'a [u8], endian: Endian) -> Result<(Self, usize), Self::Error> { + let offset = &mut 0; + + let frame_type = src.gread_with(offset, endian)?; + let buffer_id = src.gread_with(offset, endian)?; + let sequence_id = src.gread_with(offset, endian)?; + let buf_len: u32 = src.gread_with(offset, endian)?; + let feature = src.gread_with(offset, endian)?; + + if buf_len != *offset as u32 { + // type u8 buffer_id: u8 sequence_id: u8 buf_len: u32 feature + let error = format!("Expected {} got {} bytes of whole Frame", buf_len, *offset - 1); + return Err(scroll::Error::Custom(error)); + } + + Ok((Frame { frame_type, buffer_id, sequence_id, feature }, *offset)) + } + } + + impl<'a> ctx::TryIntoCtx for Frame { + type Error = scroll::Error; + + fn try_into_ctx(self, this: &mut [u8], ctx: Endian) -> Result { + let offset = &mut 0; + + this.gwrite_with::(self.frame_type.into(), offset, ctx)?; + this.gwrite_with::(self.buffer_id.into(), offset, ctx)?; + this.gwrite_with::(self.sequence_id.into(), offset, ctx)?; + + let buf_length_offset = *offset; + // reserve bytes for the buffer length (u32) + this.gwrite_with::(0, offset, ctx)?; + let feature_length = this.gwrite_with::(self.feature, offset, ctx)?; + // 7 bytes + feature_length bytes = buf.length + let written = 7 + feature_length; + this.pwrite_with::(written as u32, buf_length_offset, ctx)?; + + Ok(written) + } + } + + impl<'a> ctx::TryFromCtx<'a, Endian> for Type { + type Error = scroll::Error; + + // and the lifetime annotation on `&'a [u8]` here + fn try_from_ctx(src: &'a [u8], _endian: Endian) -> Result<(Self, usize), Self::Error> { + let offset = &mut 0; + let frame_value = src.gread::(offset)?; + + Type::try_from(frame_value) + .map(|frame_type| (frame_type, *offset)) + .map_err(|err| scroll::Error::Custom(err.to_string())) + } + } + + impl<'a> ctx::TryFromCtx<'a, Endian> for BufferID { + type Error = scroll::Error; + + // and the lifetime annotation on `&'a [u8]` here + fn try_from_ctx(src: &'a [u8], _endian: Endian) -> Result<(Self, usize), Self::Error> { + let offset = &mut 0; + let id_value = src.gread::(offset)?; + + BufferID::try_from(id_value) + .map(|buffer_id| (buffer_id, *offset)) + .map_err(|err| scroll::Error::Custom(err.to_string())) + } + } + + #[cfg(test)] + mod test { + use super::*; + use crate::jumping_sumo::*; + use scroll::{LE, Pwrite}; + + #[test] + fn test_full_frame() { + let message: [u8; 14] = [0x2, 0xa, 0x67, 0xe, 0x0, 0x0, 0x0, 0x3, 0x0, 0x0, 0x0, 0x1, 0x0, 0x9c]; + + let pilot_state = PilotState { + flag: true, + speed: 0, + turn: -100, + }; + + let expected_frame = Frame { + frame_type: Type::Data, + buffer_id: BufferID::CDNonAck, + sequence_id: 103, + feature: command::Feature::JumpingSumo(Class::Piloting(PilotingID::Pilot(pilot_state))), + }; + + let actual_frame: Frame = message.pread_with(0, LE).unwrap(); + + assert_eq!(expected_frame, actual_frame); + + let mut actual_message: [u8; 14] = [0; 14]; + actual_message.pwrite_with(actual_frame, 0, LE).expect("whoopsy"); + + assert_eq!(message, actual_message) + } + + } +} + // --------------------- Tests --------------------- // #[cfg(test)] diff --git a/arsdk-rs/src/jumping_sumo.rs b/arsdk-rs/src/jumping_sumo.rs index 45e155a..a568828 100644 --- a/arsdk-rs/src/jumping_sumo.rs +++ b/arsdk-rs/src/jumping_sumo.rs @@ -1,13 +1,13 @@ use crate::frame::Data; -#[derive(Debug, PartialEq, Clone, Copy)] +#[derive(Debug, PartialEq, Eq, Clone, Copy)] pub enum JumpType { LONG, // ARCOMMANDS_ID_JUMPINGSUMO_CLASS_PILOTING = 0, HIGH, // ARCOMMANDS_ID_JUMPINGSUMO_CLASS_PILOTING = 0, DEFAULT, // ARCOMMANDS_ID_JUMPINGSUMO_CLASS_PILOTING = 0, } -#[derive(Debug, PartialEq, Clone, Copy)] +#[derive(Debug, PartialEq, Eq, Clone, Copy)] pub enum Class { Piloting(PilotingID), // ARCOMMANDS_ID_JUMPINGSUMO_CLASS_PILOTING = 0, PilotingState, // ARCOMMANDS_ID_JUMPINGSUMO_CLASS_PILOTINGSTATE = 1, @@ -33,7 +33,7 @@ pub enum Class { VideoSettingsState, // ARCOMMANDS_ID_JUMPINGSUMO_CLASS_VIDEOSETTINGSSTATE = 22, } -#[derive(Debug, PartialEq, Clone, Copy)] +#[derive(Debug, PartialEq, Eq, Clone, Copy)] pub enum Anim { JumpStop = 0, // ARCOMMANDS_ID_JUMPINGSUMO_ANIMATIONS_CMD_JUMPSTOP = 0, JumpCancel = 1, // ARCOMMANDS_ID_JUMPINGSUMO_ANIMATIONS_CMD_JUMPCANCEL = 1, @@ -42,14 +42,14 @@ pub enum Anim { SimpleAnimation = 4, // ARCOMMANDS_ID_JUMPINGSUMO_ANIMATIONS_CMD_SIMPLEANIMATION = 4, } -#[derive(Debug, PartialEq, Clone, Copy)] +#[derive(Debug, PartialEq, Eq, Clone, Copy)] pub enum PilotingID { Pilot(PilotState), // ARCOMMANDS_ID_JUMPINGSUMO_PILOTING_CMD_PCMD = 0, Posture, // ARCOMMANDS_ID_JUMPINGSUMO_PILOTING_CMD_POSTURE = 1, AddCapOffset, // ARCOMMANDS_ID_JUMPINGSUMO_PILOTING_CMD_ADDCAPOFFSET = 2, } -#[derive(Default, Debug, PartialEq, Clone, Copy)] +#[derive(Default, Debug, PartialEq, Eq, Clone, Copy)] pub struct PilotState { pub flag: bool, pub speed: i8, @@ -150,6 +150,132 @@ impl Into for PilotingID { } } } +pub mod scroll_impl { + use super::*; + use scroll::{ctx, Endian, Pread, Pwrite}; + + impl<'a> ctx::TryFromCtx<'a, Endian> for Class { + type Error = scroll::Error; + + // and the lifetime annotation on `&'a [u8]` here + fn try_from_ctx(src: &'a [u8], endian: Endian) -> Result<(Self, usize), Self::Error> { + let mut offset = 0; + + let class = match src.gread_with::(&mut offset, endian)? { + 0 => { + let pilot_state = src.gread_with(&mut offset, endian)?; + + Self::Piloting(pilot_state) + } + 1 => Self::PilotingState, + // TODO: Impl animcation `TryFromCtx` + 2 => Self::Animations(Anim::Jump), + 3 => Self::AnimationsState, + 5 => Self::SettingsState, + 6 => Self::MediaRecord, + 7 => Self::MediaRecordState, + 8 => Self::NetworkSettings, + 9 => Self::NetworkSettingsState, + 10 => Self::Network, + 11 => Self::NetworkState, + 12 => Self::AutioSettings, + 13 => Self::AudioSettingsState, + 14 => Self::Roadplan, + 15 => Self::RoadplanState, + 16 => Self::SpeedSettings, + 17 => Self::SpeedSettingsState, + 18 => Self::MediaStreaming, + 19 => Self::MediaStreamingState, + 20 => Self::MediaRecordEvent, + 21 => Self::VideoSettings, + 22 => Self::VideoSettingsState, + _ => return Err(scroll::Error::Custom("Out of range".into())), + }; + + Ok((class, offset)) + } + } + + impl<'a> ctx::TryIntoCtx for Class { + type Error = scroll::Error; + + fn try_into_ctx(self, this: &mut [u8], _ctx: Endian) -> Result { + let ser_class = self.serialize(); + let written = this.pwrite_with(ser_class.as_slice(), 0, ())?; + + Ok(written) + } + } + + impl<'a> ctx::TryFromCtx<'a, Endian> for PilotingID { + type Error = scroll::Error; + + // and the lifetime annotation on `&'a [u8]` here + fn try_from_ctx(src: &'a [u8], endian: Endian) -> Result<(Self, usize), Self::Error> { + let mut offset = 0; + + let piloting_id = match src.gread_with::(&mut offset, endian)? { + 0 => { + let pilot_state = src.gread_with(&mut offset, endian)?; + + Self::Pilot(pilot_state) + } + 1 => Self::Posture, + 2 => Self::AddCapOffset, + _ => return Err(scroll::Error::Custom("Out of range".into())), + }; + + Ok((piloting_id, offset)) + } + } + + impl<'a> ctx::TryIntoCtx for PilotingID { + type Error = scroll::Error; + + fn try_into_ctx(self, this: &mut [u8], _ctx: Endian) -> Result { + let ser_class = self.serialize(); + let written = this.pwrite_with(ser_class.as_slice(), 0, ())?; + + Ok(written) + } + } + + impl<'a> ctx::TryFromCtx<'a, Endian> for PilotState { + type Error = scroll::Error; + + // and the lifetime annotation on `&'a [u8]` here + fn try_from_ctx(src: &'a [u8], endian: Endian) -> Result<(Self, usize), Self::Error> { + let mut offset = 0; + + let flag = match src.gread_with::(&mut offset, endian)? { + 0 => false, + 1 => true, + _ => { + return Err(scroll::Error::Custom( + "`flag` is out of range it can only be true or false".into(), + )) + } + }; + let speed: i8 = src.gread_with(&mut offset, endian)?; + let turn: i8 = src.gread_with(&mut offset, endian)?; + + let pilot_state = PilotState { flag, speed, turn }; + + Ok((pilot_state, offset)) + } + } + + impl<'a> ctx::TryIntoCtx for PilotState { + type Error = scroll::Error; + + fn try_into_ctx(self, this: &mut [u8], _ctx: Endian) -> Result { + let ser_class = self.serialize(); + let written = this.pwrite_with(ser_class.as_slice(), 0, ())?; + + Ok(written) + } + } +} // --------------------- Tests --------------------- // diff --git a/bebop2/src/lib.rs b/bebop2/src/lib.rs index 5c3691c..a6b425c 100644 --- a/bebop2/src/lib.rs +++ b/bebop2/src/lib.rs @@ -22,6 +22,9 @@ impl Bebop2 { Ok(Self { drone }) } + // ARCOMMANDS_ID_ARDRONE3_PILOTING_CMD_NAVIGATEHOME + // ARCOMMANDS_ID_ARDRONE3_PILOTING_CMD_AUTOTAKEOFFMODE + pub fn take_off(&self) -> AnyResult<()> { // Ardrone3 // ARCOMMANDS_ID_ARDRONE3_CLASS_PILOTING From a64ce4c5a102cdbd200e10540ec98a6f4d661a73 Mon Sep 17 00:00:00 2001 From: Lachezar Lechev Date: Sat, 2 May 2020 09:47:07 +0300 Subject: [PATCH 04/14] thiserror: - Cargo - add `thiserror` - enum MessageError --- Cargo.lock | 21 +++++++++++++++++++++ arsdk-rs/Cargo.toml | 1 + arsdk-rs/src/lib.rs | 18 +++++++++++++++++- 3 files changed, 39 insertions(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index cb3d9aa..a215c45 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -36,6 +36,7 @@ dependencies = [ "scroll_derive", "serde", "serde_json", + "thiserror", ] [[package]] @@ -493,6 +494,26 @@ dependencies = [ "winapi 0.2.8", ] +[[package]] +name = "thiserror" +version = "1.0.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d12a1dae4add0f0d568eebc7bf142f145ba1aa2544cafb195c76f0f409091b60" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f34e0c1caaa462fd840ec6b768946ea1e7842620d94fe29d5b847138f521269" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "thread_local" version = "0.3.6" diff --git a/arsdk-rs/Cargo.toml b/arsdk-rs/Cargo.toml index c668557..3917e87 100644 --- a/arsdk-rs/Cargo.toml +++ b/arsdk-rs/Cargo.toml @@ -9,6 +9,7 @@ keywords = ["drone", "parrot"] [dependencies] anyhow = "1.0" +thiserror = "1.0" pnet = "0.25" serde = {version = "1.0", features = ["derive"]} serde_json = "1.0" diff --git a/arsdk-rs/src/lib.rs b/arsdk-rs/src/lib.rs index 3861f6f..03c2096 100644 --- a/arsdk-rs/src/lib.rs +++ b/arsdk-rs/src/lib.rs @@ -4,6 +4,7 @@ use dashmap::DashMap; use pnet::datalink; use std::net::{IpAddr, Ipv4Addr, SocketAddr, ToSocketAddrs, UdpSocket}; use std::sync::mpsc::{channel, Sender}; +use thiserror::Error; pub const INIT_PORT: u16 = 44444; pub const LISTEN_PORT: u16 = 43210; @@ -27,6 +28,18 @@ pub mod prelude { pub use crate::{Config, Drone, PARROT_SPHINX_CONFIG, PARROT_SPHINX_IP}; } +#[derive(Debug, Error)] +pub enum MessageError { + #[error("Message parsing error")] + Scroll(#[from] scroll::Error), + #[error("Out of bound value {value}")] + Invalid { + // TODO: See how should we handle this for each individual case + // Use the largest possible value + value: u64, + }, +} + #[derive(Debug)] pub struct Config { pub drone_addr: IpAddr, @@ -137,7 +150,10 @@ fn spawn_listener(addr: impl ToSocketAddrs) -> AnyResult<()> { let mut buf = [0; 256]; if let Ok((bytes_read, origin)) = listener.recv_from(&mut buf) { println!("Read {} bytes from {} ", bytes_read, origin.ip()); - let octal: Vec = buf[0..bytes_read].iter().map(|byte| format!("{:#o}", byte)).collect(); + let octal: Vec = buf[0..bytes_read] + .iter() + .map(|byte| format!("{:#o}", byte)) + .collect(); println!("{}", octal.join(" ")); } }); From a23fadfee909b1ec893e6461aead9fb5a40be9d9 Mon Sep 17 00:00:00 2001 From: Lachezar Lechev Date: Sat, 2 May 2020 09:48:20 +0300 Subject: [PATCH 05/14] rustfmt & clippy --- arsdk-rs/src/ardrone3.rs | 3 +-- arsdk-rs/src/command.rs | 9 ++++---- arsdk-rs/src/frame.rs | 43 +++++++++++++++++++++++++++------------ arsdk-rs/src/handshake.rs | 7 ++----- 4 files changed, 37 insertions(+), 25 deletions(-) diff --git a/arsdk-rs/src/ardrone3.rs b/arsdk-rs/src/ardrone3.rs index 39e9f59..7c122b2 100644 --- a/arsdk-rs/src/ardrone3.rs +++ b/arsdk-rs/src/ardrone3.rs @@ -69,11 +69,10 @@ pub mod scroll_impl { 11 => CancelMoveTo, 12 => StartPilotedPOI, 13 => StopPilotedPOI, - _ => return Err(scroll::Error::Custom("Out of range".into())) + _ => return Err(scroll::Error::Custom("Out of range".into())), }; Ok((ardrone3, *offset)) } - } } diff --git a/arsdk-rs/src/command.rs b/arsdk-rs/src/command.rs index 39f1f8b..3a34b31 100644 --- a/arsdk-rs/src/command.rs +++ b/arsdk-rs/src/command.rs @@ -88,18 +88,18 @@ pub mod scroll_impl { let common = src.gread_with(&mut offset, endian)?; Self::Common(common) - }, + } 1 => { let ardrone3 = src.gread_with(&mut offset, endian)?; Self::ArDrone3(ardrone3) - }, + } 2 => Self::Minidrone, 3 => { let js_class = src.gread_with(&mut offset, endian)?; Self::JumpingSumo(js_class) - }, + } 4 => Self::SkyController, 8 => Self::PowerUp, 133 => Self::Generic, @@ -114,7 +114,7 @@ pub mod scroll_impl { 142 => Self::ThermalCam, 144 => Self::Animation, 147 => Self::SequoiaCam, - _ => return Err(scroll::Error::Custom("Out of range".into())) + _ => return Err(scroll::Error::Custom("Out of range".into())), }; Ok((feature, offset)) @@ -128,7 +128,6 @@ pub mod scroll_impl { let ser_feature = self.serialize(); let written = this.pwrite_with(ser_feature.as_slice(), 0, ())?; - Ok(written) } } diff --git a/arsdk-rs/src/frame.rs b/arsdk-rs/src/frame.rs index 4050474..e4359e2 100644 --- a/arsdk-rs/src/frame.rs +++ b/arsdk-rs/src/frame.rs @@ -211,12 +211,24 @@ pub mod impl_scroll { let feature = src.gread_with(offset, endian)?; if buf_len != *offset as u32 { - // type u8 buffer_id: u8 sequence_id: u8 buf_len: u32 feature - let error = format!("Expected {} got {} bytes of whole Frame", buf_len, *offset - 1); + let error = format!( + "Expected {} bytes got {} bytes in Frame", + buf_len, + *offset - 1 + ); + return Err(scroll::Error::Custom(error)); } - Ok((Frame { frame_type, buffer_id, sequence_id, feature }, *offset)) + Ok(( + Frame { + frame_type, + buffer_id, + sequence_id, + feature, + }, + *offset, + )) } } @@ -228,7 +240,7 @@ pub mod impl_scroll { this.gwrite_with::(self.frame_type.into(), offset, ctx)?; this.gwrite_with::(self.buffer_id.into(), offset, ctx)?; - this.gwrite_with::(self.sequence_id.into(), offset, ctx)?; + this.gwrite_with::(self.sequence_id, offset, ctx)?; let buf_length_offset = *offset; // reserve bytes for the buffer length (u32) @@ -251,8 +263,8 @@ pub mod impl_scroll { let frame_value = src.gread::(offset)?; Type::try_from(frame_value) - .map(|frame_type| (frame_type, *offset)) - .map_err(|err| scroll::Error::Custom(err.to_string())) + .map(|frame_type| (frame_type, *offset)) + .map_err(|err| scroll::Error::Custom(err.to_string())) } } @@ -265,8 +277,8 @@ pub mod impl_scroll { let id_value = src.gread::(offset)?; BufferID::try_from(id_value) - .map(|buffer_id| (buffer_id, *offset)) - .map_err(|err| scroll::Error::Custom(err.to_string())) + .map(|buffer_id| (buffer_id, *offset)) + .map_err(|err| scroll::Error::Custom(err.to_string())) } } @@ -274,11 +286,13 @@ pub mod impl_scroll { mod test { use super::*; use crate::jumping_sumo::*; - use scroll::{LE, Pwrite}; + use scroll::{Pwrite, LE}; #[test] fn test_full_frame() { - let message: [u8; 14] = [0x2, 0xa, 0x67, 0xe, 0x0, 0x0, 0x0, 0x3, 0x0, 0x0, 0x0, 0x1, 0x0, 0x9c]; + let message: [u8; 14] = [ + 0x2, 0xa, 0x67, 0xe, 0x0, 0x0, 0x0, 0x3, 0x0, 0x0, 0x0, 0x1, 0x0, 0x9c, + ]; let pilot_state = PilotState { flag: true, @@ -290,7 +304,9 @@ pub mod impl_scroll { frame_type: Type::Data, buffer_id: BufferID::CDNonAck, sequence_id: 103, - feature: command::Feature::JumpingSumo(Class::Piloting(PilotingID::Pilot(pilot_state))), + feature: command::Feature::JumpingSumo(Class::Piloting(PilotingID::Pilot( + pilot_state, + ))), }; let actual_frame: Frame = message.pread_with(0, LE).unwrap(); @@ -298,11 +314,12 @@ pub mod impl_scroll { assert_eq!(expected_frame, actual_frame); let mut actual_message: [u8; 14] = [0; 14]; - actual_message.pwrite_with(actual_frame, 0, LE).expect("whoopsy"); + actual_message + .pwrite_with(actual_frame, 0, LE) + .expect("whoopsy"); assert_eq!(message, actual_message) } - } } diff --git a/arsdk-rs/src/handshake.rs b/arsdk-rs/src/handshake.rs index 4dfdf49..8c09015 100644 --- a/arsdk-rs/src/handshake.rs +++ b/arsdk-rs/src/handshake.rs @@ -46,10 +46,7 @@ pub(crate) fn perform_handshake(target: SocketAddr, d2c_port: u16) -> Result Result Date: Sat, 2 May 2020 10:19:04 +0300 Subject: [PATCH 06/14] use MessageError for scroll::ctx::TryFromCtx impls --- arsdk-rs/src/command.rs | 10 ++++++++-- arsdk-rs/src/frame.rs | 16 +++++++--------- arsdk-rs/src/jumping_sumo.rs | 22 ++++++++++------------ arsdk-rs/src/lib.rs | 20 +++++++++++++------- 4 files changed, 38 insertions(+), 30 deletions(-) diff --git a/arsdk-rs/src/command.rs b/arsdk-rs/src/command.rs index 3a34b31..db5e27e 100644 --- a/arsdk-rs/src/command.rs +++ b/arsdk-rs/src/command.rs @@ -74,10 +74,11 @@ impl Data for Feature { pub mod scroll_impl { use super::*; + use crate::MessageError; use scroll::{ctx, Endian, Pread, Pwrite}; impl<'a> ctx::TryFromCtx<'a, Endian> for Feature { - type Error = scroll::Error; + type Error = MessageError; // and the lifetime annotation on `&'a [u8]` here fn try_from_ctx(src: &'a [u8], endian: Endian) -> Result<(Self, usize), Self::Error> { @@ -114,7 +115,12 @@ pub mod scroll_impl { 142 => Self::ThermalCam, 144 => Self::Animation, 147 => Self::SequoiaCam, - _ => return Err(scroll::Error::Custom("Out of range".into())), + value => { + return Err(Self::Error::OutOfBound { + value: value.into(), + param: "Feature".to_string(), + }) + } }; Ok((feature, offset)) diff --git a/arsdk-rs/src/frame.rs b/arsdk-rs/src/frame.rs index e4359e2..f7446d5 100644 --- a/arsdk-rs/src/frame.rs +++ b/arsdk-rs/src/frame.rs @@ -194,11 +194,12 @@ impl Into for BufferID { pub mod impl_scroll { use super::*; use crate::command::Feature; + use crate::MessageError; use scroll::{ctx, Endian, Pread, Pwrite}; impl<'a> ctx::TryFromCtx<'a, Endian> for Frame { - type Error = scroll::Error; + type Error = MessageError; // and the lifetime annotation on `&'a [u8]` here fn try_from_ctx(src: &'a [u8], endian: Endian) -> Result<(Self, usize), Self::Error> { @@ -209,15 +210,12 @@ pub mod impl_scroll { let sequence_id = src.gread_with(offset, endian)?; let buf_len: u32 = src.gread_with(offset, endian)?; let feature = src.gread_with(offset, endian)?; - + // @TODO: offset as u32 can fail (TryFrom is impled for usize) if buf_len != *offset as u32 { - let error = format!( - "Expected {} bytes got {} bytes in Frame", - buf_len, - *offset - 1 - ); - - return Err(scroll::Error::Custom(error)); + return Err(Self::Error::BytesLength { + expected: buf_len, + actual: *offset as u32, + }); } Ok(( diff --git a/arsdk-rs/src/jumping_sumo.rs b/arsdk-rs/src/jumping_sumo.rs index a568828..891d477 100644 --- a/arsdk-rs/src/jumping_sumo.rs +++ b/arsdk-rs/src/jumping_sumo.rs @@ -152,10 +152,11 @@ impl Into for PilotingID { } pub mod scroll_impl { use super::*; + use crate::MessageError; use scroll::{ctx, Endian, Pread, Pwrite}; impl<'a> ctx::TryFromCtx<'a, Endian> for Class { - type Error = scroll::Error; + type Error = MessageError; // and the lifetime annotation on `&'a [u8]` here fn try_from_ctx(src: &'a [u8], endian: Endian) -> Result<(Self, usize), Self::Error> { @@ -189,7 +190,7 @@ pub mod scroll_impl { 20 => Self::MediaRecordEvent, 21 => Self::VideoSettings, 22 => Self::VideoSettingsState, - _ => return Err(scroll::Error::Custom("Out of range".into())), + value => return Err(Self::Error::OutOfBound{ value: value.into(), param: "Class".to_string() }), }; Ok((class, offset)) @@ -208,7 +209,7 @@ pub mod scroll_impl { } impl<'a> ctx::TryFromCtx<'a, Endian> for PilotingID { - type Error = scroll::Error; + type Error = MessageError; // and the lifetime annotation on `&'a [u8]` here fn try_from_ctx(src: &'a [u8], endian: Endian) -> Result<(Self, usize), Self::Error> { @@ -222,7 +223,7 @@ pub mod scroll_impl { } 1 => Self::Posture, 2 => Self::AddCapOffset, - _ => return Err(scroll::Error::Custom("Out of range".into())), + value => return Err(Self::Error::OutOfBound{ value: value.into(), param: "PilotingId".to_string() }), }; Ok((piloting_id, offset)) @@ -230,7 +231,7 @@ pub mod scroll_impl { } impl<'a> ctx::TryIntoCtx for PilotingID { - type Error = scroll::Error; + type Error = MessageError; fn try_into_ctx(self, this: &mut [u8], _ctx: Endian) -> Result { let ser_class = self.serialize(); @@ -241,7 +242,7 @@ pub mod scroll_impl { } impl<'a> ctx::TryFromCtx<'a, Endian> for PilotState { - type Error = scroll::Error; + type Error = MessageError; // and the lifetime annotation on `&'a [u8]` here fn try_from_ctx(src: &'a [u8], endian: Endian) -> Result<(Self, usize), Self::Error> { @@ -250,11 +251,8 @@ pub mod scroll_impl { let flag = match src.gread_with::(&mut offset, endian)? { 0 => false, 1 => true, - _ => { - return Err(scroll::Error::Custom( - "`flag` is out of range it can only be true or false".into(), - )) - } + // @TODO: should we mention that it is for PilotState as well and how? + value => return Err(Self::Error::OutOfBound{ value: value.into(), param: "flag".to_string() }), }; let speed: i8 = src.gread_with(&mut offset, endian)?; let turn: i8 = src.gread_with(&mut offset, endian)?; @@ -266,7 +264,7 @@ pub mod scroll_impl { } impl<'a> ctx::TryIntoCtx for PilotState { - type Error = scroll::Error; + type Error = MessageError; fn try_into_ctx(self, this: &mut [u8], _ctx: Endian) -> Result { let ser_class = self.serialize(); diff --git a/arsdk-rs/src/lib.rs b/arsdk-rs/src/lib.rs index 03c2096..7bd1733 100644 --- a/arsdk-rs/src/lib.rs +++ b/arsdk-rs/src/lib.rs @@ -32,18 +32,24 @@ pub mod prelude { pub enum MessageError { #[error("Message parsing error")] Scroll(#[from] scroll::Error), - #[error("Out of bound value {value}")] - Invalid { + #[error("Out of bound value {value} for {param}")] + OutOfBound { // TODO: See how should we handle this for each individual case // Use the largest possible value value: u64, + param: String, }, + #[error("Expected {expected} bytes, got {actual}")] + BytesLength { + expected: u32, + actual: u32, + } } #[derive(Debug)] pub struct Config { pub drone_addr: IpAddr, - /// Wheather or not it should send: + /// Wheather or not to set after connecting (by sending a frame) the current DateTime to the Drone: /// /// ```rust /// let now: DateTime = Utc::now() @@ -150,11 +156,11 @@ fn spawn_listener(addr: impl ToSocketAddrs) -> AnyResult<()> { let mut buf = [0; 256]; if let Ok((bytes_read, origin)) = listener.recv_from(&mut buf) { println!("Read {} bytes from {} ", bytes_read, origin.ip()); - let octal: Vec = buf[0..bytes_read] + let hex: Vec = buf[0..bytes_read] .iter() - .map(|byte| format!("{:#o}", byte)) + .map(|byte| format!("{:#x}", byte)) .collect(); - println!("{}", octal.join(" ")); + println!("{}", hex.join(" ")); } }); @@ -163,7 +169,7 @@ fn spawn_listener(addr: impl ToSocketAddrs) -> AnyResult<()> { fn print_message(buf: &[u8]) { for b in buf.iter() { - print!("{:#o}", b); + print!("{:#x}", b); } println!(); } From 184aa8c6c0f5aa61165e34782ba4e3a0d71f0bc3 Mon Sep 17 00:00:00 2001 From: Lachezar Lechev Date: Sat, 2 May 2020 16:42:04 +0300 Subject: [PATCH 07/14] impl Ping-Pong --- Cargo.lock | 30 +++++++++++ arsdk-rs/Cargo.toml | 1 + arsdk-rs/src/frame.rs | 71 +++++++++++++----------- arsdk-rs/src/lib.rs | 104 +++++++++++++++++++++++------------- bebop2/examples/take_off.rs | 2 +- bebop2/src/lib.rs | 2 +- 6 files changed, 140 insertions(+), 70 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a215c45..4178b33 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -37,6 +37,7 @@ dependencies = [ "serde", "serde_json", "thiserror", + "tokio", ] [[package]] @@ -59,6 +60,12 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4f67931368edf3a9a51d29886d245f1c3db2f1ef0dcc9e35ff70341b78c10d23" +[[package]] +name = "bytes" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "130aac562c0dd69c56b3b1cc8ffd2e17be31d0b6c25b61c96b76231aa23e39e1" + [[package]] name = "cfg-if" version = "0.1.10" @@ -107,6 +114,12 @@ dependencies = [ "num_cpus", ] +[[package]] +name = "fnv" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fad85553e09a6f881f739c29f0b00b0f01357c743266d478b68951ce23285f3" + [[package]] name = "getrandom" version = "0.1.14" @@ -232,6 +245,12 @@ dependencies = [ "libc", ] +[[package]] +name = "pin-project-lite" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "237844750cfbb86f67afe27eee600dfbbcb6188d734139b534cbfbf4f96792ae" + [[package]] name = "pnet" version = "0.25.0" @@ -533,6 +552,17 @@ dependencies = [ "winapi 0.3.8", ] +[[package]] +name = "tokio" +version = "0.2.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05c1d570eb1a36f0345a5ce9c6c6e665b70b73d11236912c0b477616aeec47b1" +dependencies = [ + "bytes", + "fnv", + "pin-project-lite", +] + [[package]] name = "unicode-xid" version = "0.0.3" diff --git a/arsdk-rs/Cargo.toml b/arsdk-rs/Cargo.toml index 3917e87..895a784 100644 --- a/arsdk-rs/Cargo.toml +++ b/arsdk-rs/Cargo.toml @@ -17,3 +17,4 @@ dashmap = "3.11" chrono = "0.4" scroll = "0.10" scroll_derive = "0.10" +tokio = {version = "0.2", features=["sync"]} diff --git a/arsdk-rs/src/frame.rs b/arsdk-rs/src/frame.rs index f7446d5..a1aab49 100644 --- a/arsdk-rs/src/frame.rs +++ b/arsdk-rs/src/frame.rs @@ -1,11 +1,6 @@ use crate::{command, Drone}; use anyhow::{anyhow, Error as AnyError, Result as AnyResult}; -use std::convert::TryFrom; - -pub trait IntoRawFrame { - fn into_raw(self) -> RawFrame; -} -pub struct RawFrame(pub Vec); +use std::{convert::TryFrom}; pub trait Data { fn serialize(&self) -> Vec; @@ -16,7 +11,7 @@ pub struct Frame { frame_type: Type, buffer_id: BufferID, sequence_id: u8, - feature: command::Feature, + feature: Option, } impl Frame { @@ -24,7 +19,7 @@ impl Frame { frame_type: Type, buffer_id: BufferID, sequence_id: u8, - feature: command::Feature, + feature: Option, ) -> Self { Self { frame_type, @@ -38,29 +33,32 @@ impl Frame { drone: &Drone, frame_type: Type, buffer_id: BufferID, - feature: command::Feature, + feature: Option, ) -> Frame { - Frame::new(frame_type, buffer_id, drone.sequence_id(buffer_id), feature) + Frame::new(frame_type, buffer_id, drone.inner.sequence_id(buffer_id), feature) } } -impl IntoRawFrame for Frame { - fn into_raw(self) -> RawFrame { - let ser_feature = self.feature.serialize(); - // Frame size 3 bytes + 4 bytes (u32) + ser_feature.len() - let buf_len = 7 + ser_feature.len(); - - let mut buf = Vec::with_capacity(buf_len); - buf.push(self.frame_type.into()); - buf.push(self.buffer_id.into()); - buf.push(self.sequence_id); - // buffer size as u32 (4 bytes) - buf.extend(&(buf_len as u32).to_le_bytes()); - buf.extend(ser_feature); - - RawFrame(buf) - } -} +// impl IntoRawMessage for Frame { +// fn into_raw(self) -> RawMessage { +// let ser_feature = self.feature.map(|f| f.serialize()); +// // Frame size 3 bytes + 4 bytes (u32) + ser_feature.len() +// let buf_len = 7 + ser_feature.as_ref().map(|f| f.len()).unwrap_or_default(); + +// let mut buf = Vec::with_capacity(buf_len); +// buf.push(self.frame_type.into()); +// buf.push(self.buffer_id.into()); +// buf.push(self.sequence_id); +// // buffer size as u32 (4 bytes) +// buf.extend(&(buf_len as u32).to_le_bytes()); + +// if let Some(feature) = ser_feature { +// buf.extend(feature); +// } + +// RawMessage(buf) +// } +// } // --------------------- Types --------------------- // @@ -126,6 +124,7 @@ pub enum BufferID { // @TODO: Find the corresponding C definition if there is one and name the new enum variant! // PyParrot: // `'ACK_FROM_SEND_WITH_ACK': 139 # 128 + buffer id for 'SEND_WITH_ACK' is 139` + // ACKFromSendWithAck = 139, } // --------------------- Conversion impls --------------------- // @@ -193,8 +192,7 @@ impl Into for BufferID { pub mod impl_scroll { use super::*; - use crate::command::Feature; - use crate::MessageError; + use crate::{MessageError, command::Feature}; use scroll::{ctx, Endian, Pread, Pwrite}; @@ -209,7 +207,13 @@ pub mod impl_scroll { let buffer_id = src.gread_with(offset, endian)?; let sequence_id = src.gread_with(offset, endian)?; let buf_len: u32 = src.gread_with(offset, endian)?; - let feature = src.gread_with(offset, endian)?; + + let feature = if buf_len > 7 { + Some(src.gread_with(offset, endian)?) + }else { + None + }; + // @TODO: offset as u32 can fail (TryFrom is impled for usize) if buf_len != *offset as u32 { return Err(Self::Error::BytesLength { @@ -243,7 +247,12 @@ pub mod impl_scroll { let buf_length_offset = *offset; // reserve bytes for the buffer length (u32) this.gwrite_with::(0, offset, ctx)?; - let feature_length = this.gwrite_with::(self.feature, offset, ctx)?; + + let feature_length = match self.feature { + Some(feature) => this.gwrite_with::(feature, offset, ctx)?, + None => 0 + }; + // 7 bytes + feature_length bytes = buf.length let written = 7 + feature_length; this.pwrite_with::(written as u32, buf_length_offset, ctx)?; diff --git a/arsdk-rs/src/lib.rs b/arsdk-rs/src/lib.rs index 7bd1733..87cb9da 100644 --- a/arsdk-rs/src/lib.rs +++ b/arsdk-rs/src/lib.rs @@ -3,8 +3,10 @@ use chrono::{DateTime, Utc}; use dashmap::DashMap; use pnet::datalink; use std::net::{IpAddr, Ipv4Addr, SocketAddr, ToSocketAddrs, UdpSocket}; -use std::sync::mpsc::{channel, Sender}; +use std::sync::{Arc, mpsc::{sync_channel, SyncSender, Receiver}}; use thiserror::Error; +use scroll::Pread; +use crate::frame::Frame; pub const INIT_PORT: u16 = 44444; pub const LISTEN_PORT: u16 = 43210; @@ -57,10 +59,16 @@ pub struct Config { pub send_datetime: bool, } +#[derive(Clone, Debug)] pub struct Drone { + inner: Arc, +} + +#[derive(Debug)] +struct DroneInner { // Each frame::BufferID gets its own sequence_id sequence_ids: DashMap, - sender: Sender>, + sender: SyncSender>, } impl Drone { @@ -77,8 +85,18 @@ impl Drone { ) })?; + // @TODO: Check if we're going to miss any messages between spawning the listener and the receiver of commands + let (tx_cmd, rx_cmd) = sync_channel(200); + + let drone = Self { + inner: Arc::new(DroneInner { + sequence_ids: DashMap::new(), + sender: tx_cmd.clone(), + }) + }; + let local_listener = SocketAddr::new(local_ip, LISTEN_PORT); - spawn_listener(local_listener)?; + spawn_listener(drone.clone(), local_listener)?; let init_addr = SocketAddr::new(config.drone_addr, INIT_PORT); let handshake_response = perform_handshake(init_addr, local_listener.port())?; @@ -86,12 +104,7 @@ impl Drone { let cmd_sender_target = SocketAddr::new(config.drone_addr, handshake_response.c2d_port); println!("spawning cmd sender on {}", cmd_sender_target); - let sender = spawn_cmd_sender(local_ip, cmd_sender_target)?; - - let drone = Self { - sequence_ids: DashMap::new(), - sender, - }; + spawn_cmd_sender(rx_cmd, local_ip, cmd_sender_target)?; if config.send_datetime { drone.send_datetime(Utc::now())?; @@ -101,34 +114,37 @@ impl Drone { } pub fn send_frame(&self, frame: frame::Frame) -> AnyResult<()> { - self.send_raw_frame_unchecked(frame) - } + use scroll::{LE, ctx::TryIntoCtx}; + + let mut raw_message = [0_u8; 2048]; + let written = frame.try_into_ctx(&mut raw_message, LE)?; - pub fn send_raw_frame_unchecked(&self, frame: impl frame::IntoRawFrame) -> AnyResult<()> { - self.send(frame.into_raw().0) + self.send_raw_message(&raw_message[0..written]) } - fn send(&self, raw_frame: Vec) -> AnyResult<()> { - self.sender.send(raw_frame).map_err(AnyError::new) + pub fn send_raw_message(&self, raw_message: &[u8]) -> AnyResult<()> { + self.inner.sender.send(raw_message.to_vec()).map_err(AnyError::new) } pub fn send_datetime(&self, date: DateTime) -> AnyResult<()> { use command::Feature::Common; use common::Class; - use frame::{BufferID, Frame, Type}; + use frame::{BufferID, Type}; let date_feature = Common(Class::Common(common::Common::CurrentDate(date))); - let frame = Frame::for_drone(self, Type::DataWithAck, BufferID::CDAck, date_feature); + let frame = Frame::for_drone(&self, Type::DataWithAck, BufferID::CDAck, Some(date_feature)); self.send_frame(frame)?; let time_feature = Common(Class::Common(common::Common::CurrentTime(date))); - let frame = Frame::for_drone(self, Type::DataWithAck, BufferID::CDAck, time_feature); + let frame = Frame::for_drone(&self, Type::DataWithAck, BufferID::CDAck, Some(time_feature)); self.send_frame(frame) } +} +impl DroneInner { pub(crate) fn sequence_id(&self, buffer_id: frame::BufferID) -> u8 { if let Some(mut sequence_id) = self.sequence_ids.get_mut(&buffer_id) { let command_id = *sequence_id; @@ -150,45 +166,59 @@ fn local_ip(target: IpAddr) -> Option { .next() } -fn spawn_listener(addr: impl ToSocketAddrs) -> AnyResult<()> { +// TODO: We need a RawFrame(Vec) to be able to separate messages to parse +// fn read_messages(buf: &[u8]) -> Vec> { +// buf.pread::() +// } + +fn spawn_listener(drone: Drone, addr: impl ToSocketAddrs) -> AnyResult<()> { let listener = UdpSocket::bind(addr)?; - std::thread::spawn(move || loop { - let mut buf = [0; 256]; + std::thread::spawn(move || { + let drone = drone.clone(); + loop { + let mut buf = [0_u8; 256]; if let Ok((bytes_read, origin)) = listener.recv_from(&mut buf) { - println!("Read {} bytes from {} ", bytes_read, origin.ip()); - let hex: Vec = buf[0..bytes_read] - .iter() - .map(|byte| format!("{:#x}", byte)) - .collect(); - println!("{}", hex.join(" ")); + if buf[1] == frame::BufferID::PING as u8 { + println!("Received: {} bytes from {} Bytes: {}", bytes_read, origin, print_buf(&buf)); + + let frame_type = frame::Type::Data; + let buffer_id = frame::BufferID::PONG; + let pong = frame::Frame::for_drone(&drone, frame_type, buffer_id, None); + + drone.send_frame(pong).expect("Should PONG successfully!"); + } + } + } }); Ok(()) } -fn print_message(buf: &[u8]) { - for b in buf.iter() { - print!("{:#x}", b); - } - println!(); +fn print_buf(buf: &[u8]) -> String { + buf.iter().map(|byte| format!("{:#x}", byte)).collect::>().join(" ") } -fn spawn_cmd_sender(local_ip: IpAddr, target_addr: SocketAddr) -> AnyResult>> { +fn spawn_cmd_sender(rx: Receiver>, local_ip: IpAddr, target_addr: SocketAddr) -> AnyResult<()> { let local_addr = SocketAddr::new(local_ip, target_addr.port()); let socket = UdpSocket::bind(local_addr) .map_err(|e| anyhow!("Couldn't bind to local socket {} - {}", local_addr, e))?; - let (tx, rx) = channel::>(); std::thread::spawn(move || loop { let frame_to_send = rx.recv().expect("couldn't receive frame."); - print_message(&frame_to_send); + use scroll::LE; + let frame = frame_to_send.pread_with::(0, LE); + + println!("Frame length: {} => {:#?}", frame_to_send.len(), &frame); + let size = socket .send_to(&frame_to_send, target_addr) .expect("something terrible happened"); - println!("sent {}", size); + + assert_eq!(size, frame_to_send.len()) }); - Ok(tx) + + Ok(()) } diff --git a/bebop2/examples/take_off.rs b/bebop2/examples/take_off.rs index 168b65b..ca4f753 100644 --- a/bebop2/examples/take_off.rs +++ b/bebop2/examples/take_off.rs @@ -5,7 +5,7 @@ use bebop2::prelude::*; fn main() -> Result<(), Box> { let drone = Bebop2::connect(PARROT_SPHINX_CONFIG)?; - drone.take_off()?; + // drone.take_off()?; std::thread::sleep(std::time::Duration::from_secs(20)); diff --git a/bebop2/src/lib.rs b/bebop2/src/lib.rs index a6b425c..5761b50 100644 --- a/bebop2/src/lib.rs +++ b/bebop2/src/lib.rs @@ -34,7 +34,7 @@ impl Bebop2 { let feature = Feature::ArDrone3(ArDrone3::TakeOff); - let frame = Frame::for_drone(&self.drone, Type::DataWithAck, BufferID::CDAck, feature); + let frame = Frame::for_drone(&self.drone, Type::DataWithAck, BufferID::CDAck, Some(feature)); self.drone.send_frame(frame) } From b3d969eece32ed094282d108b61fcd33f794abf8 Mon Sep 17 00:00:00 2001 From: Lachezar Lechev Date: Sat, 2 May 2020 17:14:36 +0300 Subject: [PATCH 08/14] rustfmt & fix tests --- arsdk-rs/src/frame.rs | 64 +++++++++++++------------- arsdk-rs/src/jumping_sumo.rs | 21 +++++++-- arsdk-rs/src/lib.rs | 87 ++++++++++++++++++++++++------------ bebop2/src/lib.rs | 7 ++- jumpingsumo-rs/src/lib.rs | 4 +- 5 files changed, 118 insertions(+), 65 deletions(-) diff --git a/arsdk-rs/src/frame.rs b/arsdk-rs/src/frame.rs index a1aab49..2ab6e08 100644 --- a/arsdk-rs/src/frame.rs +++ b/arsdk-rs/src/frame.rs @@ -1,6 +1,6 @@ use crate::{command, Drone}; use anyhow::{anyhow, Error as AnyError, Result as AnyResult}; -use std::{convert::TryFrom}; +use std::convert::TryFrom; pub trait Data { fn serialize(&self) -> Vec; @@ -35,7 +35,12 @@ impl Frame { buffer_id: BufferID, feature: Option, ) -> Frame { - Frame::new(frame_type, buffer_id, drone.inner.sequence_id(buffer_id), feature) + Frame::new( + frame_type, + buffer_id, + drone.inner.sequence_id(buffer_id), + feature, + ) } } @@ -192,7 +197,7 @@ impl Into for BufferID { pub mod impl_scroll { use super::*; - use crate::{MessageError, command::Feature}; + use crate::{command::Feature, MessageError}; use scroll::{ctx, Endian, Pread, Pwrite}; @@ -210,7 +215,7 @@ pub mod impl_scroll { let feature = if buf_len > 7 { Some(src.gread_with(offset, endian)?) - }else { + } else { None }; @@ -250,7 +255,7 @@ pub mod impl_scroll { let feature_length = match self.feature { Some(feature) => this.gwrite_with::(feature, offset, ctx)?, - None => 0 + None => 0, }; // 7 bytes + feature_length bytes = buf.length @@ -311,9 +316,9 @@ pub mod impl_scroll { frame_type: Type::Data, buffer_id: BufferID::CDNonAck, sequence_id: 103, - feature: command::Feature::JumpingSumo(Class::Piloting(PilotingID::Pilot( + feature: Some(command::Feature::JumpingSumo(Class::Piloting(PilotingID::Pilot( pilot_state, - ))), + )))), }; let actual_frame: Frame = message.pread_with(0, LE).unwrap(); @@ -338,12 +343,13 @@ mod frame_tests { use crate::common::{self, Class as CommonClass}; use crate::jumping_sumo::*; use chrono::{TimeZone, Utc}; + use scroll::{LE, Pread, Pwrite}; use std::convert::TryInto; #[test] fn test_common_date_command() { - let expected_message = "0x4 0xb 0x1 0x15 0x0 0x0 0x0 0x4 0x1 0x0 0x32 0x30 0x32 0x30 0x2d 0x30 0x34 0x2d 0x32 0x36 0x0"; + let expected_message = [0x4, 0xb, 0x1, 0x15, 0x0, 0x0, 0x0, 0x4, 0x1, 0x0, 0x32, 0x30, 0x32, 0x30, 0x2d, 0x30, 0x34, 0x2d, 0x32, 0x36, 0x0]; let date = Utc.ymd(2020, 04, 26).and_hms(15, 06, 11); @@ -351,17 +357,17 @@ mod frame_tests { frame_type: Type::DataWithAck, buffer_id: BufferID::CDAck, sequence_id: 1, - feature: command::Feature::Common(CommonClass::Common(common::Common::CurrentDate( + feature: Some(command::Feature::Common(CommonClass::Common(common::Common::CurrentDate( date, - ))), + )))), }; - assert_frames_match(expected_message, frame); + assert_frames_match(&expected_message, frame); } #[test] fn test_common_time_command() { - let expected_message = "0x4 0xb 0x2 0x15 0x0 0x0 0x0 0x4 0x2 0x0 0x54 0x31 0x35 0x30 0x36 0x31 0x31 0x30 0x30 0x30 0x0"; + let expected_message = [0x4, 0xb, 0x2, 0x15, 0x0, 0x0, 0x0, 0x4, 0x2, 0x0, 0x54, 0x31, 0x35, 0x30, 0x36, 0x31, 0x31, 0x30, 0x30, 0x30, 0x0]; let date = Utc.ymd(2020, 04, 26).and_hms(15, 06, 11); @@ -369,17 +375,17 @@ mod frame_tests { frame_type: Type::DataWithAck, buffer_id: BufferID::CDAck, sequence_id: 2, - feature: command::Feature::Common(CommonClass::Common(common::Common::CurrentTime( + feature: Some(command::Feature::Common(CommonClass::Common(common::Common::CurrentTime( date, - ))), + )))), }; - assert_frames_match(expected_message, frame); + assert_frames_match(&expected_message, frame); } #[test] fn test_jumpingsumo_move_command() { - let expected_message = "0x2 0xa 0x67 0xe 0x0 0x0 0x0 0x3 0x0 0x0 0x0 0x1 0x0 0x9c"; + let expected_message = [0x2, 0xa, 0x67, 0xe, 0x0, 0x0, 0x0, 0x3, 0x0, 0x0, 0x0, 0x1, 0x0, 0x9c]; let pilot_state = PilotState { flag: true, @@ -391,38 +397,36 @@ mod frame_tests { frame_type: Type::Data, buffer_id: BufferID::CDNonAck, sequence_id: 103, - feature: command::Feature::JumpingSumo(Class::Piloting(PilotingID::Pilot(pilot_state))), + feature: Some(command::Feature::JumpingSumo(Class::Piloting(PilotingID::Pilot(pilot_state)))), }; - assert_frames_match(expected_message, frame); + assert_frames_match(&expected_message, frame); } #[test] fn test_jumpingsumo_jump_command() { - let expected_message = "0x4 0xb 0x1 0xf 0x0 0x0 0x0 0x3 0x2 0x3 0x0 0x0 0x0 0x0 0x0"; + let expected_message = [0x4, 0xb, 0x1, 0xf, 0x0, 0x0, 0x0, 0x3, 0x2, 0x3, 0x0, 0x0, 0x0, 0x0, 0x0]; let frame = Frame { frame_type: Type::DataWithAck, buffer_id: BufferID::CDAck, sequence_id: 1, - feature: command::Feature::JumpingSumo(Class::Animations(Anim::Jump)), + feature: Some(command::Feature::JumpingSumo(Class::Animations(Anim::Jump))), }; - assert_frames_match(expected_message, frame); + assert_frames_match(&expected_message, frame); } - // 0x2 0xb 0x1 0xf 0x0 0x0 0x0 0x3 0x2 0x3 0x0 0x0 0x0 0x0 0x0 - fn assert_frames_match(output: &str, frame: Frame) { - let buf = frame.into_raw().0; + fn assert_frames_match(expected: &[u8], frame: Frame) { + assert_eq!(expected.pread_with::(0, LE).expect("Should deserialize"), frame); + let mut actual = vec![]; + + actual.pwrite_with::(frame, 0, LE).expect("Should serialize"); - let actual_message = buf - .iter() - .map(|b| format!("0x{:x}", b)) - .collect::>() - .join(" "); - assert_eq!(output, actual_message); + assert_eq!(&expected, &actual.as_slice()); } + // 0x2 0xb 0x1 0xf 0x0 0x0 0x0 0x3 0x2 0x3 0x0 0x0 0x0 0x0 0x0 #[test] fn test_frame() { diff --git a/arsdk-rs/src/jumping_sumo.rs b/arsdk-rs/src/jumping_sumo.rs index 891d477..08d804f 100644 --- a/arsdk-rs/src/jumping_sumo.rs +++ b/arsdk-rs/src/jumping_sumo.rs @@ -190,7 +190,12 @@ pub mod scroll_impl { 20 => Self::MediaRecordEvent, 21 => Self::VideoSettings, 22 => Self::VideoSettingsState, - value => return Err(Self::Error::OutOfBound{ value: value.into(), param: "Class".to_string() }), + value => { + return Err(Self::Error::OutOfBound { + value: value.into(), + param: "Class".to_string(), + }) + } }; Ok((class, offset)) @@ -223,7 +228,12 @@ pub mod scroll_impl { } 1 => Self::Posture, 2 => Self::AddCapOffset, - value => return Err(Self::Error::OutOfBound{ value: value.into(), param: "PilotingId".to_string() }), + value => { + return Err(Self::Error::OutOfBound { + value: value.into(), + param: "PilotingId".to_string(), + }) + } }; Ok((piloting_id, offset)) @@ -252,7 +262,12 @@ pub mod scroll_impl { 0 => false, 1 => true, // @TODO: should we mention that it is for PilotState as well and how? - value => return Err(Self::Error::OutOfBound{ value: value.into(), param: "flag".to_string() }), + value => { + return Err(Self::Error::OutOfBound { + value: value.into(), + param: "flag".to_string(), + }) + } }; let speed: i8 = src.gread_with(&mut offset, endian)?; let turn: i8 = src.gread_with(&mut offset, endian)?; diff --git a/arsdk-rs/src/lib.rs b/arsdk-rs/src/lib.rs index 87cb9da..b60d6e9 100644 --- a/arsdk-rs/src/lib.rs +++ b/arsdk-rs/src/lib.rs @@ -1,12 +1,15 @@ +use crate::frame::Frame; use anyhow::{anyhow, Error as AnyError, Result as AnyResult}; use chrono::{DateTime, Utc}; use dashmap::DashMap; use pnet::datalink; +use scroll::Pread; use std::net::{IpAddr, Ipv4Addr, SocketAddr, ToSocketAddrs, UdpSocket}; -use std::sync::{Arc, mpsc::{sync_channel, SyncSender, Receiver}}; +use std::sync::{ + mpsc::{sync_channel, Receiver, SyncSender}, + Arc, +}; use thiserror::Error; -use scroll::Pread; -use crate::frame::Frame; pub const INIT_PORT: u16 = 44444; pub const LISTEN_PORT: u16 = 43210; @@ -42,10 +45,7 @@ pub enum MessageError { param: String, }, #[error("Expected {expected} bytes, got {actual}")] - BytesLength { - expected: u32, - actual: u32, - } + BytesLength { expected: u32, actual: u32 }, } #[derive(Debug)] @@ -90,9 +90,9 @@ impl Drone { let drone = Self { inner: Arc::new(DroneInner { - sequence_ids: DashMap::new(), - sender: tx_cmd.clone(), - }) + sequence_ids: DashMap::new(), + sender: tx_cmd.clone(), + }), }; let local_listener = SocketAddr::new(local_ip, LISTEN_PORT); @@ -114,7 +114,7 @@ impl Drone { } pub fn send_frame(&self, frame: frame::Frame) -> AnyResult<()> { - use scroll::{LE, ctx::TryIntoCtx}; + use scroll::{ctx::TryIntoCtx, LE}; let mut raw_message = [0_u8; 2048]; let written = frame.try_into_ctx(&mut raw_message, LE)?; @@ -123,7 +123,10 @@ impl Drone { } pub fn send_raw_message(&self, raw_message: &[u8]) -> AnyResult<()> { - self.inner.sender.send(raw_message.to_vec()).map_err(AnyError::new) + self.inner + .sender + .send(raw_message.to_vec()) + .map_err(AnyError::new) } pub fn send_datetime(&self, date: DateTime) -> AnyResult<()> { @@ -133,12 +136,22 @@ impl Drone { let date_feature = Common(Class::Common(common::Common::CurrentDate(date))); - let frame = Frame::for_drone(&self, Type::DataWithAck, BufferID::CDAck, Some(date_feature)); + let frame = Frame::for_drone( + &self, + Type::DataWithAck, + BufferID::CDAck, + Some(date_feature), + ); self.send_frame(frame)?; let time_feature = Common(Class::Common(common::Common::CurrentTime(date))); - let frame = Frame::for_drone(&self, Type::DataWithAck, BufferID::CDAck, Some(time_feature)); + let frame = Frame::for_drone( + &self, + Type::DataWithAck, + BufferID::CDAck, + Some(time_feature), + ); self.send_frame(frame) } @@ -176,30 +189,42 @@ fn spawn_listener(drone: Drone, addr: impl ToSocketAddrs) -> AnyResult<()> { std::thread::spawn(move || { let drone = drone.clone(); loop { - let mut buf = [0_u8; 256]; - if let Ok((bytes_read, origin)) = listener.recv_from(&mut buf) { - if buf[1] == frame::BufferID::PING as u8 { - println!("Received: {} bytes from {} Bytes: {}", bytes_read, origin, print_buf(&buf)); - - let frame_type = frame::Type::Data; - let buffer_id = frame::BufferID::PONG; - let pong = frame::Frame::for_drone(&drone, frame_type, buffer_id, None); - - drone.send_frame(pong).expect("Should PONG successfully!"); + let mut buf = [0_u8; 256]; + if let Ok((bytes_read, origin)) = listener.recv_from(&mut buf) { + if buf[1] == frame::BufferID::PING as u8 { + println!( + "Received: {} bytes from {} Bytes: {}", + bytes_read, + origin, + print_buf(&buf) + ); + + let frame_type = frame::Type::Data; + let buffer_id = frame::BufferID::PONG; + + let pong = frame::Frame::for_drone(&drone, frame_type, buffer_id, None); + + drone.send_frame(pong).expect("Should PONG successfully!"); + } } - } - } }); Ok(()) } fn print_buf(buf: &[u8]) -> String { - buf.iter().map(|byte| format!("{:#x}", byte)).collect::>().join(" ") + buf.iter() + .map(|byte| format!("{:#x}", byte)) + .collect::>() + .join(" ") } -fn spawn_cmd_sender(rx: Receiver>, local_ip: IpAddr, target_addr: SocketAddr) -> AnyResult<()> { +fn spawn_cmd_sender( + rx: Receiver>, + local_ip: IpAddr, + target_addr: SocketAddr, +) -> AnyResult<()> { let local_addr = SocketAddr::new(local_ip, target_addr.port()); let socket = UdpSocket::bind(local_addr) @@ -211,7 +236,11 @@ fn spawn_cmd_sender(rx: Receiver>, local_ip: IpAddr, target_addr: Socket use scroll::LE; let frame = frame_to_send.pread_with::(0, LE); - println!("Frame length: {} => {:#?}", frame_to_send.len(), &frame); + println!( + "Sent Frame (length: {}) => {:#?}", + frame_to_send.len(), + &frame + ); let size = socket .send_to(&frame_to_send, target_addr) diff --git a/bebop2/src/lib.rs b/bebop2/src/lib.rs index 5761b50..00db768 100644 --- a/bebop2/src/lib.rs +++ b/bebop2/src/lib.rs @@ -34,7 +34,12 @@ impl Bebop2 { let feature = Feature::ArDrone3(ArDrone3::TakeOff); - let frame = Frame::for_drone(&self.drone, Type::DataWithAck, BufferID::CDAck, Some(feature)); + let frame = Frame::for_drone( + &self.drone, + Type::DataWithAck, + BufferID::CDAck, + Some(feature), + ); self.drone.send_frame(frame) } diff --git a/jumpingsumo-rs/src/lib.rs b/jumpingsumo-rs/src/lib.rs index 8875be5..b4fa885 100644 --- a/jumpingsumo-rs/src/lib.rs +++ b/jumpingsumo-rs/src/lib.rs @@ -68,7 +68,7 @@ impl JumpingSumo { pub fn drive(&self, state: PilotState) -> AnyResult<()> { let feature = JumpingSumoFeature(Piloting(Pilot(state))); - let frame = Frame::for_drone(&self.drone, FrameType::Data, BufferID::CDNonAck, feature); + let frame = Frame::for_drone(&self.drone, FrameType::Data, BufferID::CDNonAck, Some(feature)); self.drone.send_frame(frame) } @@ -79,7 +79,7 @@ impl JumpingSumo { &self.drone, FrameType::DataWithAck, BufferID::CDAck, - feature, + Some(feature), ); self.drone.send_frame(frame) From 3395cc95a74c83854eddced34dda11532e48f018 Mon Sep 17 00:00:00 2001 From: Lachezar Lechev Date: Sat, 2 May 2020 17:37:08 +0300 Subject: [PATCH 09/14] impl (de)serializtion for Anim + fix test assertion --- arsdk-rs/src/frame.rs | 6 ++--- arsdk-rs/src/jumping_sumo.rs | 46 ++++++++++++++++++++++++++++++++++-- 2 files changed, 47 insertions(+), 5 deletions(-) diff --git a/arsdk-rs/src/frame.rs b/arsdk-rs/src/frame.rs index 2ab6e08..0d31a7f 100644 --- a/arsdk-rs/src/frame.rs +++ b/arsdk-rs/src/frame.rs @@ -420,11 +420,11 @@ mod frame_tests { fn assert_frames_match(expected: &[u8], frame: Frame) { assert_eq!(expected.pread_with::(0, LE).expect("Should deserialize"), frame); - let mut actual = vec![]; + let mut actual = [0_u8; 4086]; - actual.pwrite_with::(frame, 0, LE).expect("Should serialize"); + let actual_written = actual.pwrite_with::(frame, 0, LE).expect("Should serialize"); - assert_eq!(&expected, &actual.as_slice()); + assert_eq!(expected, &actual[..actual_written]); } // 0x2 0xb 0x1 0xf 0x0 0x0 0x0 0x3 0x2 0x3 0x0 0x0 0x0 0x0 0x0 diff --git a/arsdk-rs/src/jumping_sumo.rs b/arsdk-rs/src/jumping_sumo.rs index 08d804f..299d177 100644 --- a/arsdk-rs/src/jumping_sumo.rs +++ b/arsdk-rs/src/jumping_sumo.rs @@ -169,8 +169,11 @@ pub mod scroll_impl { Self::Piloting(pilot_state) } 1 => Self::PilotingState, - // TODO: Impl animcation `TryFromCtx` - 2 => Self::Animations(Anim::Jump), + 2 => { + let anim = src.gread_with(&mut offset, endian)?; + + Self::Animations(anim) + }, 3 => Self::AnimationsState, 5 => Self::SettingsState, 6 => Self::MediaRecord, @@ -288,6 +291,45 @@ pub mod scroll_impl { Ok(written) } } + + impl<'a> ctx::TryFromCtx<'a, Endian> for Anim { + type Error = MessageError; + + // and the lifetime annotation on `&'a [u8]` here + fn try_from_ctx(src: &'a [u8], endian: Endian) -> Result<(Self, usize), Self::Error> { + let mut offset = 0; + + let class = match src.gread_with::(&mut offset, endian)? { + 0 => Self::JumpStop, + 1 => Self::JumpCancel, + 2 => Self::JumpLoad, + 2 => Self::Jump, + 4 => Self::SimpleAnimation, + value => { + return Err(Self::Error::OutOfBound { + value: value.into(), + param: "Class".to_string(), + }) + } + }; + + Ok((class, offset)) + } + } + + impl<'a> ctx::TryIntoCtx for Anim { + type Error = scroll::Error; + + fn try_into_ctx(self, this: &mut [u8], ctx: Endian) -> Result { + let offset = &mut 0; + let mut written = this.gwrite_with::(self.into(), offset, ctx)?; + // TODO: FIX THIS! + let dummy_anim = [0_u8, 0, 0, 0, 0]; + written += this.gwrite_with(dummy_anim.as_ref(), offset, ())?; + + Ok(written) + } + } } // --------------------- Tests --------------------- // From c8e0cd34f68d529bdcf6687746de03801be924cb Mon Sep 17 00:00:00 2001 From: Lachezar Lechev Date: Sat, 2 May 2020 18:49:23 +0300 Subject: [PATCH 10/14] WIP Deserialization is broken for jump command --- arsdk-rs/src/command.rs | 36 ++++---------- arsdk-rs/src/frame.rs | 38 ++++++++++----- arsdk-rs/src/jumping_sumo.rs | 92 ++++++++++++------------------------ 3 files changed, 67 insertions(+), 99 deletions(-) diff --git a/arsdk-rs/src/command.rs b/arsdk-rs/src/command.rs index db5e27e..cb875c4 100644 --- a/arsdk-rs/src/command.rs +++ b/arsdk-rs/src/command.rs @@ -2,8 +2,8 @@ use crate::ardrone3::ArDrone3; use crate::common; use crate::frame::Data; use crate::jumping_sumo; -#[derive(Debug, PartialEq, Eq, Clone, Copy)] +#[derive(Debug, PartialEq, Eq, Clone, Copy)] pub enum Feature { Common(common::Class), // ARCOMMANDS_ID_FEATURE_COMMON = 0, ArDrone3(ArDrone3), // ARCOMMANDS_ID_FEATURE_ARDRONE3 = 1, @@ -52,26 +52,6 @@ impl Into for Feature { } } -impl Data for Feature { - fn serialize(&self) -> Vec { - let mut buf = Vec::new(); - buf.push(self.clone().into()); - match &self { - Feature::JumpingSumo(js) => { - buf.extend(js.serialize()); - } - Feature::Common(common) => { - buf.extend(common.serialize()); - } - Feature::ArDrone3(drone) => { - buf.extend(drone.serialize()); - } - _ => {} - } - buf - } -} - pub mod scroll_impl { use super::*; use crate::MessageError; @@ -99,7 +79,7 @@ pub mod scroll_impl { 3 => { let js_class = src.gread_with(&mut offset, endian)?; - Self::JumpingSumo(js_class) + Feature::JumpingSumo(js_class) } 4 => Self::SkyController, 8 => Self::PowerUp, @@ -130,11 +110,15 @@ pub mod scroll_impl { impl<'a> ctx::TryIntoCtx for Feature { type Error = scroll::Error; - fn try_into_ctx(self, this: &mut [u8], _ctx: Endian) -> Result { - let ser_feature = self.serialize(); - let written = this.pwrite_with(ser_feature.as_slice(), 0, ())?; + fn try_into_ctx(self, this: &mut [u8], ctx: Endian) -> Result { + let mut offset = 0; + + // @TODO: FIX THIS! + this.gwrite_with::(self.into(), &mut offset, ctx)?; + let ser_feature: [u8; 5] = [1_u8; 5]; - Ok(written) + let written = this.gwrite_with(ser_feature.as_ref(), &mut offset, ())?; + Ok(dbg!(written)) } } } diff --git a/arsdk-rs/src/frame.rs b/arsdk-rs/src/frame.rs index 0d31a7f..28f6adf 100644 --- a/arsdk-rs/src/frame.rs +++ b/arsdk-rs/src/frame.rs @@ -206,24 +206,33 @@ pub mod impl_scroll { // and the lifetime annotation on `&'a [u8]` here fn try_from_ctx(src: &'a [u8], endian: Endian) -> Result<(Self, usize), Self::Error> { - let offset = &mut 0; + let mut offset: usize = 0; - let frame_type = src.gread_with(offset, endian)?; - let buffer_id = src.gread_with(offset, endian)?; - let sequence_id = src.gread_with(offset, endian)?; - let buf_len: u32 = src.gread_with(offset, endian)?; + let frame_type = src.gread_with(&mut offset, endian)?; + let buffer_id = src.gread_with(&mut offset, endian)?; + let sequence_id = src.gread_with(&mut offset, endian)?; + let buf_len: u32 = src.gread_with(&mut offset, endian)?; let feature = if buf_len > 7 { - Some(src.gread_with(offset, endian)?) + let mut feature_len = 0; + let srcc = src[7..].to_vec(); + let feature = srcc.gread_with::(&mut feature_len, endian)?; + dbg!(&offset, &feature_len, &offset + feature_len, srcc); + offset += feature_len; + + Some(feature) } else { None }; + // dbg!(&offset); + + // dbg!(feature); // @TODO: offset as u32 can fail (TryFrom is impled for usize) - if buf_len != *offset as u32 { + if buf_len != offset as u32 { return Err(Self::Error::BytesLength { expected: buf_len, - actual: *offset as u32, + actual: offset as u32, }); } @@ -234,7 +243,7 @@ pub mod impl_scroll { sequence_id, feature, }, - *offset, + offset, )) } } @@ -362,7 +371,7 @@ mod frame_tests { )))), }; - assert_frames_match(&expected_message, frame); + // assert_frames_match(&expected_message, frame); } #[test] @@ -380,7 +389,7 @@ mod frame_tests { )))), }; - assert_frames_match(&expected_message, frame); + // assert_frames_match(&expected_message, frame); } #[test] @@ -405,7 +414,13 @@ mod frame_tests { #[test] fn test_jumpingsumo_jump_command() { + + // type buf seq [ len ] [JS Anim Jump DATA ] let expected_message = [0x4, 0xb, 0x1, 0xf, 0x0, 0x0, 0x0, 0x3, 0x2, 0x3, 0x0, 0x0, 0x0, 0x0, 0x0]; + let buf_len: u32 = (&expected_message[3..7]).pread_with(0, LE).expect("should read a u32"); + + assert_eq!(buf_len, 15); + assert_eq!(buf_len as usize, expected_message.len()); let frame = Frame { frame_type: Type::DataWithAck, @@ -421,7 +436,6 @@ mod frame_tests { fn assert_frames_match(expected: &[u8], frame: Frame) { assert_eq!(expected.pread_with::(0, LE).expect("Should deserialize"), frame); let mut actual = [0_u8; 4086]; - let actual_written = actual.pwrite_with::(frame, 0, LE).expect("Should serialize"); assert_eq!(expected, &actual[..actual_written]); diff --git a/arsdk-rs/src/jumping_sumo.rs b/arsdk-rs/src/jumping_sumo.rs index 299d177..a4e09f5 100644 --- a/arsdk-rs/src/jumping_sumo.rs +++ b/arsdk-rs/src/jumping_sumo.rs @@ -56,48 +56,6 @@ pub struct PilotState { pub turn: i8, } -impl Data for Class { - fn serialize(&self) -> Vec { - let mut buf = Vec::new(); - buf.push(self.clone().into()); - match &self { - Class::Piloting(piloting_id) => { - buf.extend(piloting_id.serialize()); - } - Class::Animations(animation) => { - buf.push(animation.clone().into()); - // TODO: FIX THIS - buf.extend(vec![0, 0, 0, 0, 0]); - } - _ => {} - } - - buf - } -} - -impl Data for PilotingID { - fn serialize(&self) -> Vec { - let mut buf = Vec::with_capacity(2); - let piloting_u16: u16 = self.clone().into(); - buf.push((piloting_u16 >> 8) as u8); - buf.push(piloting_u16 as u8); - match self { - PilotingID::Pilot(pilot_state) => { - buf.extend(pilot_state.serialize()); - } - _ => {} - } - buf - } -} - -impl Data for PilotState { - fn serialize(&self) -> Vec { - vec![self.flag as u8, self.speed as u8, self.turn as u8] - } -} - // --------------------- Conversion impls --------------------- // impl Into for Class { @@ -162,7 +120,7 @@ pub mod scroll_impl { fn try_from_ctx(src: &'a [u8], endian: Endian) -> Result<(Self, usize), Self::Error> { let mut offset = 0; - let class = match src.gread_with::(&mut offset, endian)? { + let class = match src.gread_with::(&mut offset, endian)? { 0 => { let pilot_state = src.gread_with(&mut offset, endian)?; @@ -208,9 +166,10 @@ pub mod scroll_impl { impl<'a> ctx::TryIntoCtx for Class { type Error = scroll::Error; - fn try_into_ctx(self, this: &mut [u8], _ctx: Endian) -> Result { - let ser_class = self.serialize(); - let written = this.pwrite_with(ser_class.as_slice(), 0, ())?; + fn try_into_ctx(self, this: &mut [u8], ctx: Endian) -> Result { + let mut offset = 0; + + let written = this.gwrite_with::(self.into(), &mut offset, ctx)?; Ok(written) } @@ -246,11 +205,18 @@ pub mod scroll_impl { impl<'a> ctx::TryIntoCtx for PilotingID { type Error = MessageError; - fn try_into_ctx(self, this: &mut [u8], _ctx: Endian) -> Result { - let ser_class = self.serialize(); - let written = this.pwrite_with(ser_class.as_slice(), 0, ())?; + fn try_into_ctx(self, this: &mut [u8], ctx: Endian) -> Result { + let mut offset = 0; + this.gwrite_with::(self.into(), &mut offset, ctx)?; - Ok(written) + match self { + Self::Pilot(state) => { + this.gwrite_with(state, &mut offset, ctx)?; + }, + _ => {} + } + + Ok(offset + 1) } } @@ -284,11 +250,13 @@ pub mod scroll_impl { impl<'a> ctx::TryIntoCtx for PilotState { type Error = MessageError; - fn try_into_ctx(self, this: &mut [u8], _ctx: Endian) -> Result { - let ser_class = self.serialize(); - let written = this.pwrite_with(ser_class.as_slice(), 0, ())?; + fn try_into_ctx(self, this: &mut [u8], ctx: Endian) -> Result { + let mut offset = 0; + this.gwrite_with::(self.flag.into(), &mut offset, ctx)?; + this.gwrite_with(self.speed, &mut offset, ctx)?; + this.gwrite_with(self.turn, &mut offset, ctx)?; - Ok(written) + Ok(offset + 1) } } @@ -303,16 +271,18 @@ pub mod scroll_impl { 0 => Self::JumpStop, 1 => Self::JumpCancel, 2 => Self::JumpLoad, - 2 => Self::Jump, + 3 => Self::Jump, 4 => Self::SimpleAnimation, value => { return Err(Self::Error::OutOfBound { value: value.into(), - param: "Class".to_string(), + param: "Anim".to_string(), }) } }; + + Ok((class, offset)) } } @@ -321,13 +291,13 @@ pub mod scroll_impl { type Error = scroll::Error; fn try_into_ctx(self, this: &mut [u8], ctx: Endian) -> Result { - let offset = &mut 0; - let mut written = this.gwrite_with::(self.into(), offset, ctx)?; + let mut offset: usize = 0; + this.gwrite_with::(self.into(), &mut offset, ctx)?; // TODO: FIX THIS! - let dummy_anim = [0_u8, 0, 0, 0, 0]; - written += this.gwrite_with(dummy_anim.as_ref(), offset, ())?; + let dummy_anim = [1_u8; 5]; + this.gwrite_with(dummy_anim.as_ref(), &mut offset, ())?; - Ok(written) + Ok(offset) } } } From b11581ef1cb07469f76dbb8c91cb3a230e9ffe28 Mon Sep 17 00:00:00 2001 From: Lachezar Lechev Date: Sun, 3 May 2020 08:13:23 +0300 Subject: [PATCH 11/14] All tests compile and everything de(serialize) --- arsdk-rs/src/ardrone3.rs | 31 ++++--- arsdk-rs/src/command.rs | 20 +++-- arsdk-rs/src/common.rs | 98 ++++++++++----------- arsdk-rs/src/frame.rs | 165 +++++++++++++++++++---------------- arsdk-rs/src/jumping_sumo.rs | 38 ++++---- arsdk-rs/src/lib.rs | 10 +-- jumpingsumo-rs/src/lib.rs | 7 +- 7 files changed, 202 insertions(+), 167 deletions(-) diff --git a/arsdk-rs/src/ardrone3.rs b/arsdk-rs/src/ardrone3.rs index 7c122b2..088e700 100644 --- a/arsdk-rs/src/ardrone3.rs +++ b/arsdk-rs/src/ardrone3.rs @@ -1,5 +1,3 @@ -use crate::frame::Data; - /// eARCOMMANDS_ID_ARDRONE3_PILOTING_CMD #[derive(Debug, Clone, Copy, Eq, PartialEq)] pub enum ArDrone3 { @@ -33,20 +31,13 @@ pub enum ArDrone3 { StopPilotedPOI = 13, } -impl Data for ArDrone3 { - fn serialize(&self) -> Vec { - let take_off: u16 = 1; - - take_off.to_le_bytes().to_vec() - } -} - pub mod scroll_impl { use super::*; - use scroll::{ctx, Endian, Pread}; + use crate::MessageError; + use scroll::{ctx, Endian, Pread, Pwrite}; impl<'a> ctx::TryFromCtx<'a, Endian> for ArDrone3 { - type Error = scroll::Error; + type Error = MessageError; // and the lifetime annotation on `&'a [u8]` here fn try_from_ctx(src: &'a [u8], endian: Endian) -> Result<(Self, usize), Self::Error> { @@ -69,10 +60,24 @@ pub mod scroll_impl { 11 => CancelMoveTo, 12 => StartPilotedPOI, 13 => StopPilotedPOI, - _ => return Err(scroll::Error::Custom("Out of range".into())), + value => { + return Err(MessageError::OutOfBound { + value: value.into(), + param: "ArDrone3".to_string(), + }) + } }; Ok((ardrone3, *offset)) } } + + impl<'a> ctx::TryIntoCtx for ArDrone3 { + type Error = MessageError; + + fn try_into_ctx(self, this: &mut [u8], ctx: Endian) -> Result { + // TODO: Fix when we have more options + Ok(this.pwrite_with::(self as u16, 0, ctx)?) + } + } } diff --git a/arsdk-rs/src/command.rs b/arsdk-rs/src/command.rs index cb875c4..29d3149 100644 --- a/arsdk-rs/src/command.rs +++ b/arsdk-rs/src/command.rs @@ -1,6 +1,5 @@ use crate::ardrone3::ArDrone3; use crate::common; -use crate::frame::Data; use crate::jumping_sumo; #[derive(Debug, PartialEq, Eq, Clone, Copy)] @@ -63,7 +62,6 @@ pub mod scroll_impl { // and the lifetime annotation on `&'a [u8]` here fn try_from_ctx(src: &'a [u8], endian: Endian) -> Result<(Self, usize), Self::Error> { let mut offset = 0; - let feature = match src.gread_with::(&mut offset, endian)? { 0 => { let common = src.gread_with(&mut offset, endian)?; @@ -108,17 +106,25 @@ pub mod scroll_impl { } impl<'a> ctx::TryIntoCtx for Feature { - type Error = scroll::Error; + type Error = MessageError; fn try_into_ctx(self, this: &mut [u8], ctx: Endian) -> Result { let mut offset = 0; - // @TODO: FIX THIS! this.gwrite_with::(self.into(), &mut offset, ctx)?; - let ser_feature: [u8; 5] = [1_u8; 5]; - let written = this.gwrite_with(ser_feature.as_ref(), &mut offset, ())?; - Ok(dbg!(written)) + match self { + Self::Common(common) => { + this.gwrite_with(common, &mut offset, ctx)?; + }, + // Self::ArDrone3(ardrone3) => this.gwrite_with(ardrone3, &mut offset, ctx)?, + Self::JumpingSumo(js) => { + this.gwrite_with(js, &mut offset, ctx)?; + }, + _ => unimplemented!(), + } + + Ok(offset) } } } diff --git a/arsdk-rs/src/common.rs b/arsdk-rs/src/common.rs index a5ec272..71990c9 100644 --- a/arsdk-rs/src/common.rs +++ b/arsdk-rs/src/common.rs @@ -1,4 +1,3 @@ -use crate::frame::Data; use chrono::{offset::Utc, DateTime}; #[derive(Debug, PartialEq, Eq, Clone, Copy)] @@ -47,40 +46,6 @@ pub enum Common { Reboot, // ARCOMMANDS_ID_COMMON_COMMON_CMD_REBOOT = 3, } -impl Data for Class { - fn serialize(&self) -> Vec { - let mut buf = Vec::new(); - buf.push(self.clone().into()); - match self { - Self::Common(common_command) => { - buf.extend(common_command.serialize()); - } - _ => {} - } - buf - } -} - -impl Data for Common { - fn serialize(&self) -> Vec { - let mut buf = Vec::new(); - buf.push(self.clone().into()); - match self { - Self::CurrentDate(date) => { - buf.extend(format_date(date)); - // null terminated C string - buf.push(0); - } - Self::CurrentTime(time) => { - buf.extend(format_time(time)); // null terminated C string - buf.push(0); - } - _ => {} - } - buf - } -} - // "yyyy-MM-dd"forCommon.Common.CurrentDate. Ex:2015-08-27 fn format_date(date: &DateTime) -> Vec { date.format("%Y-%m-%d").to_string().as_bytes().to_vec() @@ -147,9 +112,10 @@ impl Into for Common { pub mod scroll_impl { use super::*; use scroll::{ctx, Endian, Pread, Pwrite}; + use crate::MessageError; impl<'a> ctx::TryFromCtx<'a, Endian> for Class { - type Error = scroll::Error; + type Error = MessageError; // and the lifetime annotation on `&'a [u8]` here fn try_from_ctx(src: &'a [u8], endian: Endian) -> Result<(Self, usize), Self::Error> { @@ -194,7 +160,12 @@ pub mod scroll_impl { 31 => Self::Factory, 32 => Self::FlightPlanSettings, 33 => Self::FlightPlanSettingsState, - _ => return Err(scroll::Error::Custom("Out of range".into())), + value => { + return Err(MessageError::OutOfBound { + value: value.into(), + param: "Class".to_string(), + }) + } }; Ok((class, offset)) @@ -202,18 +173,35 @@ pub mod scroll_impl { } impl<'a> ctx::TryIntoCtx for Common { - type Error = scroll::Error; + type Error = MessageError; + + fn try_into_ctx(self, this: &mut [u8], ctx: Endian) -> Result { + let mut offset = 0; + + this.gwrite_with::(self.into(), &mut offset, ctx)?; - fn try_into_ctx(self, this: &mut [u8], _ctx: Endian) -> Result { - let ser_common = self.serialize(); - let written = this.pwrite_with(ser_common.as_slice(), 0, ())?; + match self { + Self::CurrentDate(date) => { + let mut date = format_date(&date); + // null terminated C string + date.push(0); + this.gwrite_with::<&[u8]>(date.as_ref(), &mut offset, ())?; + } + Self::CurrentTime(time) => { + // null terminated C string + let mut time = format_time(&time); + time.push(0); + this.gwrite_with::<&[u8]>(time.as_ref(), &mut offset, ())?; + } + _ => unimplemented!(), + } - Ok(written) + Ok(offset) } } impl<'a> ctx::TryFromCtx<'a, Endian> for Common { - type Error = scroll::Error; + type Error = MessageError; fn try_from_ctx(src: &'a [u8], endian: Endian) -> Result<(Self, usize), Self::Error> { use Common::*; @@ -226,7 +214,12 @@ pub mod scroll_impl { // @TODO: FIX THIS! 2 => CurrentTime(Utc::now()), 3 => Reboot, - _ => return Err(scroll::Error::Custom("Out of range".into())), + value => { + return Err(MessageError::OutOfBound { + value: value.into(), + param: "Common".to_string(), + }) + } }; Ok((common, offset)) @@ -234,13 +227,20 @@ pub mod scroll_impl { } impl<'a> ctx::TryIntoCtx for Class { - type Error = scroll::Error; + type Error = MessageError; - fn try_into_ctx(self, this: &mut [u8], _ctx: Endian) -> Result { - let ser_class = self.serialize(); - let written = this.pwrite_with(ser_class.as_slice(), 0, ())?; + fn try_into_ctx(self, this: &mut [u8], ctx: Endian) -> Result { + let mut offset = 0; + this.gwrite_with::(self.into(), &mut offset, ctx)?; + + match self { + Self::Common(common) => { + this.gwrite_with(common, &mut offset, ctx)?; + }, + _ => unimplemented!(), + }; - Ok(written) + Ok(offset) } } } diff --git a/arsdk-rs/src/frame.rs b/arsdk-rs/src/frame.rs index 28f6adf..4ddc298 100644 --- a/arsdk-rs/src/frame.rs +++ b/arsdk-rs/src/frame.rs @@ -2,10 +2,6 @@ use crate::{command, Drone}; use anyhow::{anyhow, Error as AnyError, Result as AnyResult}; use std::convert::TryFrom; -pub trait Data { - fn serialize(&self) -> Vec; -} - #[derive(Debug, Clone, PartialEq, Eq)] pub struct Frame { frame_type: Type, @@ -44,27 +40,6 @@ impl Frame { } } -// impl IntoRawMessage for Frame { -// fn into_raw(self) -> RawMessage { -// let ser_feature = self.feature.map(|f| f.serialize()); -// // Frame size 3 bytes + 4 bytes (u32) + ser_feature.len() -// let buf_len = 7 + ser_feature.as_ref().map(|f| f.len()).unwrap_or_default(); - -// let mut buf = Vec::with_capacity(buf_len); -// buf.push(self.frame_type.into()); -// buf.push(self.buffer_id.into()); -// buf.push(self.sequence_id); -// // buffer size as u32 (4 bytes) -// buf.extend(&(buf_len as u32).to_le_bytes()); - -// if let Some(feature) = ser_feature { -// buf.extend(feature); -// } - -// RawMessage(buf) -// } -// } - // --------------------- Types --------------------- // #[derive(Debug, PartialEq, Eq, Clone, Copy)] @@ -214,19 +189,11 @@ pub mod impl_scroll { let buf_len: u32 = src.gread_with(&mut offset, endian)?; let feature = if buf_len > 7 { - let mut feature_len = 0; - let srcc = src[7..].to_vec(); - let feature = srcc.gread_with::(&mut feature_len, endian)?; - dbg!(&offset, &feature_len, &offset + feature_len, srcc); - offset += feature_len; - + let feature = src.gread_with::(&mut offset, endian)?; Some(feature) } else { None }; - // dbg!(&offset); - - // dbg!(feature); // @TODO: offset as u32 can fail (TryFrom is impled for usize) if buf_len != offset as u32 { @@ -249,21 +216,21 @@ pub mod impl_scroll { } impl<'a> ctx::TryIntoCtx for Frame { - type Error = scroll::Error; + type Error = MessageError; fn try_into_ctx(self, this: &mut [u8], ctx: Endian) -> Result { - let offset = &mut 0; + let mut offset = 0; - this.gwrite_with::(self.frame_type.into(), offset, ctx)?; - this.gwrite_with::(self.buffer_id.into(), offset, ctx)?; - this.gwrite_with::(self.sequence_id, offset, ctx)?; + this.gwrite_with::(self.frame_type.into(), &mut offset, ctx)?; + this.gwrite_with::(self.buffer_id.into(), &mut offset, ctx)?; + this.gwrite_with::(self.sequence_id, &mut offset, ctx)?; - let buf_length_offset = *offset; + let buf_length_offset = offset; // reserve bytes for the buffer length (u32) - this.gwrite_with::(0, offset, ctx)?; + this.gwrite_with::(0, &mut offset, ctx)?; let feature_length = match self.feature { - Some(feature) => this.gwrite_with::(feature, offset, ctx)?, + Some(feature) => this.gwrite_with::(feature, &mut offset, ctx)?, None => 0, }; @@ -276,30 +243,59 @@ pub mod impl_scroll { } impl<'a> ctx::TryFromCtx<'a, Endian> for Type { - type Error = scroll::Error; + type Error = MessageError; // and the lifetime annotation on `&'a [u8]` here fn try_from_ctx(src: &'a [u8], _endian: Endian) -> Result<(Self, usize), Self::Error> { - let offset = &mut 0; - let frame_value = src.gread::(offset)?; + let mut offset = 0; + let frame_value = src.gread::(&mut offset)?; + + let frame_type = match frame_value { + 0 => Self::Uninitialized, + 1 => Self::Ack, + 2 => Self::Data, + 3 => Self::LowLatency, + 4 => Self::DataWithAck, + 5 => Self::Max, + value => { + return Err(MessageError::OutOfBound { + value: value.into(), + param: "Type".to_string(), + }) + } + }; - Type::try_from(frame_value) - .map(|frame_type| (frame_type, *offset)) - .map_err(|err| scroll::Error::Custom(err.to_string())) + Ok((frame_type, offset)) } } impl<'a> ctx::TryFromCtx<'a, Endian> for BufferID { - type Error = scroll::Error; + type Error = MessageError; // and the lifetime annotation on `&'a [u8]` here - fn try_from_ctx(src: &'a [u8], _endian: Endian) -> Result<(Self, usize), Self::Error> { - let offset = &mut 0; - let id_value = src.gread::(offset)?; + fn try_from_ctx(src: &'a [u8], endian: Endian) -> Result<(Self, usize), Self::Error> { + let mut offset = 0; + let id_value = src.gread::(&mut offset)?; + + let buffer_id = match id_value { + 0 => Self::PING, + 1 => Self::PONG, + 10 => Self::CDNonAck, + 11 => Self::CDAck, + 12 => Self::CDEmergency, + 13 => Self::CDVideoAck, + 125 => Self::DCVideo, + 126 => Self::DCEvent, + 127 => Self::DCNavdata, + value => { + return Err(MessageError::OutOfBound { + value: value.into(), + param: "BufferID".to_string(), + }) + } + }; - BufferID::try_from(id_value) - .map(|buffer_id| (buffer_id, *offset)) - .map_err(|err| scroll::Error::Custom(err.to_string())) + Ok((buffer_id, offset)) } } @@ -325,9 +321,9 @@ pub mod impl_scroll { frame_type: Type::Data, buffer_id: BufferID::CDNonAck, sequence_id: 103, - feature: Some(command::Feature::JumpingSumo(Class::Piloting(PilotingID::Pilot( - pilot_state, - )))), + feature: Some(command::Feature::JumpingSumo(Class::Piloting( + PilotingID::Pilot(pilot_state), + ))), }; let actual_frame: Frame = message.pread_with(0, LE).unwrap(); @@ -352,13 +348,16 @@ mod frame_tests { use crate::common::{self, Class as CommonClass}; use crate::jumping_sumo::*; use chrono::{TimeZone, Utc}; - use scroll::{LE, Pread, Pwrite}; + use scroll::{Pread, Pwrite, LE}; use std::convert::TryInto; #[test] fn test_common_date_command() { - let expected_message = [0x4, 0xb, 0x1, 0x15, 0x0, 0x0, 0x0, 0x4, 0x1, 0x0, 0x32, 0x30, 0x32, 0x30, 0x2d, 0x30, 0x34, 0x2d, 0x32, 0x36, 0x0]; + let expected_message = [ + 0x4, 0xb, 0x1, 0x15, 0x0, 0x0, 0x0, 0x4, 0x1, 0x0, 0x32, 0x30, 0x32, 0x30, 0x2d, 0x30, + 0x34, 0x2d, 0x32, 0x36, 0x0, + ]; let date = Utc.ymd(2020, 04, 26).and_hms(15, 06, 11); @@ -366,9 +365,9 @@ mod frame_tests { frame_type: Type::DataWithAck, buffer_id: BufferID::CDAck, sequence_id: 1, - feature: Some(command::Feature::Common(CommonClass::Common(common::Common::CurrentDate( - date, - )))), + feature: Some(command::Feature::Common(CommonClass::Common( + common::Common::CurrentDate(date), + ))), }; // assert_frames_match(&expected_message, frame); @@ -376,7 +375,10 @@ mod frame_tests { #[test] fn test_common_time_command() { - let expected_message = [0x4, 0xb, 0x2, 0x15, 0x0, 0x0, 0x0, 0x4, 0x2, 0x0, 0x54, 0x31, 0x35, 0x30, 0x36, 0x31, 0x31, 0x30, 0x30, 0x30, 0x0]; + let expected_message = [ + 0x4, 0xb, 0x2, 0x15, 0x0, 0x0, 0x0, 0x4, 0x2, 0x0, 0x54, 0x31, 0x35, 0x30, 0x36, 0x31, + 0x31, 0x30, 0x30, 0x30, 0x0, + ]; let date = Utc.ymd(2020, 04, 26).and_hms(15, 06, 11); @@ -384,9 +386,9 @@ mod frame_tests { frame_type: Type::DataWithAck, buffer_id: BufferID::CDAck, sequence_id: 2, - feature: Some(command::Feature::Common(CommonClass::Common(common::Common::CurrentTime( - date, - )))), + feature: Some(command::Feature::Common(CommonClass::Common( + common::Common::CurrentTime(date), + ))), }; // assert_frames_match(&expected_message, frame); @@ -394,7 +396,9 @@ mod frame_tests { #[test] fn test_jumpingsumo_move_command() { - let expected_message = [0x2, 0xa, 0x67, 0xe, 0x0, 0x0, 0x0, 0x3, 0x0, 0x0, 0x0, 0x1, 0x0, 0x9c]; + let expected_message = [ + 0x2, 0xa, 0x67, 0xe, 0x0, 0x0, 0x0, 0x3, 0x0, 0x0, 0x0, 0x1, 0x0, 0x9c, + ]; let pilot_state = PilotState { flag: true, @@ -406,7 +410,9 @@ mod frame_tests { frame_type: Type::Data, buffer_id: BufferID::CDNonAck, sequence_id: 103, - feature: Some(command::Feature::JumpingSumo(Class::Piloting(PilotingID::Pilot(pilot_state)))), + feature: Some(command::Feature::JumpingSumo(Class::Piloting( + PilotingID::Pilot(pilot_state), + ))), }; assert_frames_match(&expected_message, frame); @@ -414,10 +420,13 @@ mod frame_tests { #[test] fn test_jumpingsumo_jump_command() { - // type buf seq [ len ] [JS Anim Jump DATA ] - let expected_message = [0x4, 0xb, 0x1, 0xf, 0x0, 0x0, 0x0, 0x3, 0x2, 0x3, 0x0, 0x0, 0x0, 0x0, 0x0]; - let buf_len: u32 = (&expected_message[3..7]).pread_with(0, LE).expect("should read a u32"); + let expected_message = [ + 0x4, 0xb, 0x1, 0xf, 0x0, 0x0, 0x0, 0x3, 0x2, 0x3, 0x0, 0x0, 0x0, 0x0, 0x0, + ]; + let buf_len: u32 = (&expected_message[3..7]) + .pread_with(0, LE) + .expect("should read a u32"); assert_eq!(buf_len, 15); assert_eq!(buf_len as usize, expected_message.len()); @@ -432,11 +441,17 @@ mod frame_tests { assert_frames_match(&expected_message, frame); } - fn assert_frames_match(expected: &[u8], frame: Frame) { - assert_eq!(expected.pread_with::(0, LE).expect("Should deserialize"), frame); + assert_eq!( + expected + .pread_with::(0, LE) + .expect("Should deserialize"), + frame + ); let mut actual = [0_u8; 4086]; - let actual_written = actual.pwrite_with::(frame, 0, LE).expect("Should serialize"); + let actual_written = actual + .pwrite_with::(frame, 0, LE) + .expect("Should serialize"); assert_eq!(expected, &actual[..actual_written]); } diff --git a/arsdk-rs/src/jumping_sumo.rs b/arsdk-rs/src/jumping_sumo.rs index a4e09f5..9fd129d 100644 --- a/arsdk-rs/src/jumping_sumo.rs +++ b/arsdk-rs/src/jumping_sumo.rs @@ -1,5 +1,3 @@ -use crate::frame::Data; - #[derive(Debug, PartialEq, Eq, Clone, Copy)] pub enum JumpType { LONG, // ARCOMMANDS_ID_JUMPINGSUMO_CLASS_PILOTING = 0, @@ -120,7 +118,7 @@ pub mod scroll_impl { fn try_from_ctx(src: &'a [u8], endian: Endian) -> Result<(Self, usize), Self::Error> { let mut offset = 0; - let class = match src.gread_with::(&mut offset, endian)? { + let class = match src.gread_with::(&mut offset, endian)? { 0 => { let pilot_state = src.gread_with(&mut offset, endian)?; @@ -131,7 +129,7 @@ pub mod scroll_impl { let anim = src.gread_with(&mut offset, endian)?; Self::Animations(anim) - }, + } 3 => Self::AnimationsState, 5 => Self::SettingsState, 6 => Self::MediaRecord, @@ -164,14 +162,23 @@ pub mod scroll_impl { } impl<'a> ctx::TryIntoCtx for Class { - type Error = scroll::Error; + type Error = MessageError; fn try_into_ctx(self, this: &mut [u8], ctx: Endian) -> Result { let mut offset = 0; - let written = this.gwrite_with::(self.into(), &mut offset, ctx)?; + this.gwrite_with::(self.into(), &mut offset, ctx)?; + match self { + Self::Piloting(piloting_id) => { + this.gwrite_with(piloting_id, &mut offset, ctx)?; + }, + Self::Animations(anim) => { + this.gwrite_with(anim, &mut offset, ctx)?; + } + _ => {}, + } - Ok(written) + Ok(offset) } } @@ -212,11 +219,11 @@ pub mod scroll_impl { match self { Self::Pilot(state) => { this.gwrite_with(state, &mut offset, ctx)?; - }, + } _ => {} } - Ok(offset + 1) + Ok(offset) } } @@ -256,7 +263,7 @@ pub mod scroll_impl { this.gwrite_with(self.speed, &mut offset, ctx)?; this.gwrite_with(self.turn, &mut offset, ctx)?; - Ok(offset + 1) + Ok(offset) } } @@ -267,7 +274,7 @@ pub mod scroll_impl { fn try_from_ctx(src: &'a [u8], endian: Endian) -> Result<(Self, usize), Self::Error> { let mut offset = 0; - let class = match src.gread_with::(&mut offset, endian)? { + let anim = match src.gread_with::(&mut offset, endian)? { 0 => Self::JumpStop, 1 => Self::JumpCancel, 2 => Self::JumpLoad, @@ -281,20 +288,21 @@ pub mod scroll_impl { } }; + let mut anim_data = [0_u8; 5]; + src.gread_inout_with(&mut offset, &mut anim_data, endian)?; - - Ok((class, offset)) + Ok((anim, offset)) } } impl<'a> ctx::TryIntoCtx for Anim { - type Error = scroll::Error; + type Error = MessageError; fn try_into_ctx(self, this: &mut [u8], ctx: Endian) -> Result { let mut offset: usize = 0; this.gwrite_with::(self.into(), &mut offset, ctx)?; // TODO: FIX THIS! - let dummy_anim = [1_u8; 5]; + let dummy_anim = [0_u8; 5]; this.gwrite_with(dummy_anim.as_ref(), &mut offset, ())?; Ok(offset) diff --git a/arsdk-rs/src/lib.rs b/arsdk-rs/src/lib.rs index b60d6e9..c243c46 100644 --- a/arsdk-rs/src/lib.rs +++ b/arsdk-rs/src/lib.rs @@ -54,7 +54,8 @@ pub struct Config { /// Wheather or not to set after connecting (by sending a frame) the current DateTime to the Drone: /// /// ```rust - /// let now: DateTime = Utc::now() + /// use chrono::{DateTime, Utc}; + /// let now: DateTime = Utc::now(); /// ``` pub send_datetime: bool, } @@ -91,7 +92,7 @@ impl Drone { let drone = Self { inner: Arc::new(DroneInner { sequence_ids: DashMap::new(), - sender: tx_cmd.clone(), + sender: tx_cmd, }), }; @@ -179,11 +180,6 @@ fn local_ip(target: IpAddr) -> Option { .next() } -// TODO: We need a RawFrame(Vec) to be able to separate messages to parse -// fn read_messages(buf: &[u8]) -> Vec> { -// buf.pread::() -// } - fn spawn_listener(drone: Drone, addr: impl ToSocketAddrs) -> AnyResult<()> { let listener = UdpSocket::bind(addr)?; std::thread::spawn(move || { diff --git a/jumpingsumo-rs/src/lib.rs b/jumpingsumo-rs/src/lib.rs index b4fa885..1b27fe2 100644 --- a/jumpingsumo-rs/src/lib.rs +++ b/jumpingsumo-rs/src/lib.rs @@ -68,7 +68,12 @@ impl JumpingSumo { pub fn drive(&self, state: PilotState) -> AnyResult<()> { let feature = JumpingSumoFeature(Piloting(Pilot(state))); - let frame = Frame::for_drone(&self.drone, FrameType::Data, BufferID::CDNonAck, Some(feature)); + let frame = Frame::for_drone( + &self.drone, + FrameType::Data, + BufferID::CDNonAck, + Some(feature), + ); self.drone.send_frame(frame) } From f05ade1f4117727d0cde5553954ef0e5ebf5e337 Mon Sep 17 00:00:00 2001 From: Lachezar Lechev Date: Sun, 3 May 2020 08:35:06 +0300 Subject: [PATCH 12/14] impl TryIntoCtx for BufferID & Type & uncomment test assertions --- arsdk-rs/src/command.rs | 4 ++-- arsdk-rs/src/common.rs | 4 ++-- arsdk-rs/src/frame.rs | 21 ++++++++++++++++++--- arsdk-rs/src/jumping_sumo.rs | 4 ++-- 4 files changed, 24 insertions(+), 9 deletions(-) diff --git a/arsdk-rs/src/command.rs b/arsdk-rs/src/command.rs index 29d3149..592b48c 100644 --- a/arsdk-rs/src/command.rs +++ b/arsdk-rs/src/command.rs @@ -116,11 +116,11 @@ pub mod scroll_impl { match self { Self::Common(common) => { this.gwrite_with(common, &mut offset, ctx)?; - }, + } // Self::ArDrone3(ardrone3) => this.gwrite_with(ardrone3, &mut offset, ctx)?, Self::JumpingSumo(js) => { this.gwrite_with(js, &mut offset, ctx)?; - }, + } _ => unimplemented!(), } diff --git a/arsdk-rs/src/common.rs b/arsdk-rs/src/common.rs index 71990c9..44931f1 100644 --- a/arsdk-rs/src/common.rs +++ b/arsdk-rs/src/common.rs @@ -111,8 +111,8 @@ impl Into for Common { pub mod scroll_impl { use super::*; - use scroll::{ctx, Endian, Pread, Pwrite}; use crate::MessageError; + use scroll::{ctx, Endian, Pread, Pwrite}; impl<'a> ctx::TryFromCtx<'a, Endian> for Class { type Error = MessageError; @@ -236,7 +236,7 @@ pub mod scroll_impl { match self { Self::Common(common) => { this.gwrite_with(common, &mut offset, ctx)?; - }, + } _ => unimplemented!(), }; diff --git a/arsdk-rs/src/frame.rs b/arsdk-rs/src/frame.rs index 4ddc298..bcf3453 100644 --- a/arsdk-rs/src/frame.rs +++ b/arsdk-rs/src/frame.rs @@ -269,11 +269,19 @@ pub mod impl_scroll { } } + impl<'a> ctx::TryIntoCtx for Type { + type Error = MessageError; + + fn try_into_ctx(self, this: &mut [u8], ctx: Endian) -> Result { + Ok(this.pwrite_with::(self.into(), 0, ctx)?) + } + } + impl<'a> ctx::TryFromCtx<'a, Endian> for BufferID { type Error = MessageError; // and the lifetime annotation on `&'a [u8]` here - fn try_from_ctx(src: &'a [u8], endian: Endian) -> Result<(Self, usize), Self::Error> { + fn try_from_ctx(src: &'a [u8], _ctx: Endian) -> Result<(Self, usize), Self::Error> { let mut offset = 0; let id_value = src.gread::(&mut offset)?; @@ -299,6 +307,13 @@ pub mod impl_scroll { } } + impl<'a> ctx::TryIntoCtx for BufferID { + type Error = MessageError; + + fn try_into_ctx(self, this: &mut [u8], ctx: Endian) -> Result { + Ok(this.pwrite_with::(self.into(), 0, ctx)?) + } + } #[cfg(test)] mod test { use super::*; @@ -370,7 +385,7 @@ mod frame_tests { ))), }; - // assert_frames_match(&expected_message, frame); + assert_frames_match(&expected_message, frame); } #[test] @@ -391,7 +406,7 @@ mod frame_tests { ))), }; - // assert_frames_match(&expected_message, frame); + assert_frames_match(&expected_message, frame); } #[test] diff --git a/arsdk-rs/src/jumping_sumo.rs b/arsdk-rs/src/jumping_sumo.rs index 9fd129d..266d670 100644 --- a/arsdk-rs/src/jumping_sumo.rs +++ b/arsdk-rs/src/jumping_sumo.rs @@ -171,11 +171,11 @@ pub mod scroll_impl { match self { Self::Piloting(piloting_id) => { this.gwrite_with(piloting_id, &mut offset, ctx)?; - }, + } Self::Animations(anim) => { this.gwrite_with(anim, &mut offset, ctx)?; } - _ => {}, + _ => {} } Ok(offset) From 382f1031d4c191ec6b9b07e596af252a091d9c2c Mon Sep 17 00:00:00 2001 From: Lachezar Lechev Date: Sun, 3 May 2020 08:38:12 +0300 Subject: [PATCH 13/14] arsdk-rs - Cargo - remove unused crates --- Cargo.lock | 42 ------------------------------------------ arsdk-rs/Cargo.toml | 2 -- 2 files changed, 44 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4178b33..cca4ac7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -33,11 +33,9 @@ dependencies = [ "dashmap", "pnet", "scroll", - "scroll_derive", "serde", "serde_json", "thiserror", - "tokio", ] [[package]] @@ -60,12 +58,6 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4f67931368edf3a9a51d29886d245f1c3db2f1ef0dcc9e35ff70341b78c10d23" -[[package]] -name = "bytes" -version = "0.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "130aac562c0dd69c56b3b1cc8ffd2e17be31d0b6c25b61c96b76231aa23e39e1" - [[package]] name = "cfg-if" version = "0.1.10" @@ -114,12 +106,6 @@ dependencies = [ "num_cpus", ] -[[package]] -name = "fnv" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fad85553e09a6f881f739c29f0b00b0f01357c743266d478b68951ce23285f3" - [[package]] name = "getrandom" version = "0.1.14" @@ -245,12 +231,6 @@ dependencies = [ "libc", ] -[[package]] -name = "pin-project-lite" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "237844750cfbb86f67afe27eee600dfbbcb6188d734139b534cbfbf4f96792ae" - [[package]] name = "pnet" version = "0.25.0" @@ -401,17 +381,6 @@ version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "abb2332cb595d33f7edd5700f4cbf94892e680c7f0ae56adab58a35190b66cb1" -[[package]] -name = "scroll_derive" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8584eea9b9ff42825b46faf46a8c24d2cff13ec152fa2a50df788b87c07ee28" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "serde" version = "1.0.106" @@ -552,17 +521,6 @@ dependencies = [ "winapi 0.3.8", ] -[[package]] -name = "tokio" -version = "0.2.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05c1d570eb1a36f0345a5ce9c6c6e665b70b73d11236912c0b477616aeec47b1" -dependencies = [ - "bytes", - "fnv", - "pin-project-lite", -] - [[package]] name = "unicode-xid" version = "0.0.3" diff --git a/arsdk-rs/Cargo.toml b/arsdk-rs/Cargo.toml index 895a784..e908de7 100644 --- a/arsdk-rs/Cargo.toml +++ b/arsdk-rs/Cargo.toml @@ -16,5 +16,3 @@ serde_json = "1.0" dashmap = "3.11" chrono = "0.4" scroll = "0.10" -scroll_derive = "0.10" -tokio = {version = "0.2", features=["sync"]} From ee8ab5b0168cea75607cc73989ee393f9539421a Mon Sep 17 00:00:00 2001 From: Lachezar Lechev Date: Sun, 3 May 2020 08:45:31 +0300 Subject: [PATCH 14/14] Clean-up and add details of unimpled items --- arsdk-rs/src/command.rs | 6 ++++-- arsdk-rs/src/common.rs | 4 ++-- arsdk-rs/src/jumping_sumo.rs | 4 ++-- arsdk-rs/src/lib.rs | 2 +- bebop2/examples/take_off.rs | 6 ++++-- 5 files changed, 13 insertions(+), 9 deletions(-) diff --git a/arsdk-rs/src/command.rs b/arsdk-rs/src/command.rs index 592b48c..77b2693 100644 --- a/arsdk-rs/src/command.rs +++ b/arsdk-rs/src/command.rs @@ -117,11 +117,13 @@ pub mod scroll_impl { Self::Common(common) => { this.gwrite_with(common, &mut offset, ctx)?; } - // Self::ArDrone3(ardrone3) => this.gwrite_with(ardrone3, &mut offset, ctx)?, + Self::ArDrone3(ardrone3) => { + this.gwrite_with(ardrone3, &mut offset, ctx)?; + } Self::JumpingSumo(js) => { this.gwrite_with(js, &mut offset, ctx)?; } - _ => unimplemented!(), + _ => unimplemented!("Not all Features are impled"), } Ok(offset) diff --git a/arsdk-rs/src/common.rs b/arsdk-rs/src/common.rs index 44931f1..030ddef 100644 --- a/arsdk-rs/src/common.rs +++ b/arsdk-rs/src/common.rs @@ -193,7 +193,7 @@ pub mod scroll_impl { time.push(0); this.gwrite_with::<&[u8]>(time.as_ref(), &mut offset, ())?; } - _ => unimplemented!(), + _ => unimplemented!("Not all Common are impled"), } Ok(offset) @@ -237,7 +237,7 @@ pub mod scroll_impl { Self::Common(common) => { this.gwrite_with(common, &mut offset, ctx)?; } - _ => unimplemented!(), + _ => unimplemented!("Not all Class are impled"), }; Ok(offset) diff --git a/arsdk-rs/src/jumping_sumo.rs b/arsdk-rs/src/jumping_sumo.rs index 266d670..fdc586e 100644 --- a/arsdk-rs/src/jumping_sumo.rs +++ b/arsdk-rs/src/jumping_sumo.rs @@ -175,7 +175,7 @@ pub mod scroll_impl { Self::Animations(anim) => { this.gwrite_with(anim, &mut offset, ctx)?; } - _ => {} + _ => unimplemented!("Not all Class are impled"), } Ok(offset) @@ -220,7 +220,7 @@ pub mod scroll_impl { Self::Pilot(state) => { this.gwrite_with(state, &mut offset, ctx)?; } - _ => {} + _ => unimplemented!("Not all PilotingID are impled"), } Ok(offset) diff --git a/arsdk-rs/src/lib.rs b/arsdk-rs/src/lib.rs index c243c46..2ca960a 100644 --- a/arsdk-rs/src/lib.rs +++ b/arsdk-rs/src/lib.rs @@ -192,7 +192,7 @@ fn spawn_listener(drone: Drone, addr: impl ToSocketAddrs) -> AnyResult<()> { "Received: {} bytes from {} Bytes: {}", bytes_read, origin, - print_buf(&buf) + print_buf(&buf[..bytes_read - 1]) ); let frame_type = frame::Type::Data; diff --git a/bebop2/examples/take_off.rs b/bebop2/examples/take_off.rs index ca4f753..d7e1a69 100644 --- a/bebop2/examples/take_off.rs +++ b/bebop2/examples/take_off.rs @@ -5,9 +5,11 @@ use bebop2::prelude::*; fn main() -> Result<(), Box> { let drone = Bebop2::connect(PARROT_SPHINX_CONFIG)?; - // drone.take_off()?; - + std::thread::sleep(std::time::Duration::from_secs(20)); + drone.take_off()?; + std::thread::sleep(std::time::Duration::from_secs(20)); std::thread::sleep(std::time::Duration::from_secs(20)); + println!("commands ended"); Ok(()) }