1use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
131use chrono::prelude::*;
132use crc::{crc16, crc8};
133use drone_state::{FlightData, LightInfo, LogMessage, WifiInfo};
134use std::convert::TryFrom;
135use std::io::{Cursor, Read, Seek, SeekFrom, Write};
136use std::net::{SocketAddr, UdpSocket};
137use std::sync::atomic::{AtomicU16, Ordering};
138use std::time::SystemTime;
139
140pub mod command_mode;
141mod crc;
142pub mod drone_state;
143pub mod odometry;
144mod rc_state;
145
146pub use command_mode::CommandMode;
147pub use drone_state::DroneMeta;
148pub use rc_state::RCState;
149
150static SEQ_NO: AtomicU16 = AtomicU16::new(1);
151
152type Result = std::result::Result<(), ()>;
153
154#[derive(Debug, Clone)]
156struct VideoSettings {
157 pub port: u16,
158 pub enabled: bool,
159 pub mode: VideoMode,
160 pub level: u8,
161 pub encoding_rate: u8,
162 pub last_video_poll: SystemTime,
163}
164
165#[derive(Debug)]
167pub struct Drone {
168 peer_ip: String,
169
170 socket: UdpSocket,
171 video_socket: Option<UdpSocket>,
172 video: VideoSettings,
173 last_stick_command: SystemTime,
174
175 pub rc_state: RCState,
177
178 pub drone_meta: DroneMeta,
180
181 status_counter: u32,
183}
184
185const START_OF_PACKET: u8 = 0xcc;
186
187#[derive(Debug, Clone, Copy, PartialEq)]
189#[repr(u16)]
190pub enum CommandIds {
191 Undefined = 0x0000,
192 SsidMsg = 0x0011,
193 SsidCmd = 0x0012,
194 SsidPasswordMsg = 0x0013,
195 SsidPasswordCmd = 0x0014,
196 WifiRegionMsg = 0x0015,
197 WifiRegionCmd = 0x0016,
198 WifiMsg = 0x001a,
199 VideoEncoderRateCmd = 0x0020,
200 VideoDynAdjRateCmd = 0x0021,
201 EisCmd = 0x0024,
202 VideoStartCmd = 0x0025,
203 VideoRateQuery = 0x0028,
204 TakePictureCommand = 0x0030,
205 VideoModeCmd = 0x0031,
206 VideoRecordCmd = 0x0032,
207 ExposureCmd = 0x0034,
208 LightMsg = 0x0035,
209 JpegQualityMsg = 0x0037,
210 Error1Msg = 0x0043,
211 Error2Msg = 0x0044,
212 VersionMsg = 0x0045,
213 TimeCmd = 0x0046,
214 ActivationTimeMsg = 0x0047,
215 LoaderVersionMsg = 0x0049,
216 StickCmd = 0x0050,
217 TakeoffCmd = 0x0054,
218 LandCmd = 0x0055,
219 FlightMsg = 0x0056,
220 AltLimitCmd = 0x0058,
221 FlipCmd = 0x005c,
222 ThrowAndGoCmd = 0x005d,
223 PalmLandCmd = 0x005e,
224 TelloCmdFileSize = 0x0062,
225 TelloCmdFileData = 0x0063,
226 TelloCmdFileComplete = 0x0064,
227 SmartVideoCmd = 0x0080,
228 SmartVideoStatusMsg = 0x0081,
229 LogHeaderMsg = 0x1050,
230 LogDataMsg = 0x1051,
231 LogConfigMsg = 0x1052,
232 BounceCmd = 0x1053,
233 CalibrateCmd = 0x1054,
234 LowBatThresholdCmd = 0x1055,
235 AltLimitMsg = 0x1056,
236 LowBatThresholdMsg = 0x1057,
237 AttLimitCmd = 0x1058,
238 AttLimitMsg = 0x1059,
239}
240
241impl From<u16> for CommandIds {
242 fn from(value: u16) -> CommandIds {
243 match value {
244 0x0011 => CommandIds::SsidMsg,
245 0x0012 => CommandIds::SsidCmd,
246 0x0013 => CommandIds::SsidPasswordMsg,
247 0x0014 => CommandIds::SsidPasswordCmd,
248 0x0015 => CommandIds::WifiRegionMsg,
249 0x0016 => CommandIds::WifiRegionCmd,
250 0x001a => CommandIds::WifiMsg,
251 0x0020 => CommandIds::VideoEncoderRateCmd,
252 0x0021 => CommandIds::VideoDynAdjRateCmd,
253 0x0024 => CommandIds::EisCmd,
254 0x0025 => CommandIds::VideoStartCmd,
255 0x0028 => CommandIds::VideoRateQuery,
256 0x0030 => CommandIds::TakePictureCommand,
257 0x0031 => CommandIds::VideoModeCmd,
258 0x0032 => CommandIds::VideoRecordCmd,
259 0x0034 => CommandIds::ExposureCmd,
260 0x0035 => CommandIds::LightMsg,
261 0x0037 => CommandIds::JpegQualityMsg,
262 0x0043 => CommandIds::Error1Msg,
263 0x0044 => CommandIds::Error2Msg,
264 0x0045 => CommandIds::VersionMsg,
265 0x0046 => CommandIds::TimeCmd,
266 0x0047 => CommandIds::ActivationTimeMsg,
267 0x0049 => CommandIds::LoaderVersionMsg,
268 0x0050 => CommandIds::StickCmd,
269 0x0054 => CommandIds::TakeoffCmd,
270 0x0055 => CommandIds::LandCmd,
271 0x0056 => CommandIds::FlightMsg,
272 0x0058 => CommandIds::AltLimitCmd,
273 0x005c => CommandIds::FlipCmd,
274 0x005d => CommandIds::ThrowAndGoCmd,
275 0x005e => CommandIds::PalmLandCmd,
276 0x0062 => CommandIds::TelloCmdFileSize,
277 0x0063 => CommandIds::TelloCmdFileData,
278 0x0064 => CommandIds::TelloCmdFileComplete,
279 0x0080 => CommandIds::SmartVideoCmd,
280 0x0081 => CommandIds::SmartVideoStatusMsg,
281 0x1050 => CommandIds::LogHeaderMsg,
282 0x1051 => CommandIds::LogDataMsg,
283 0x1052 => CommandIds::LogConfigMsg,
284 0x1053 => CommandIds::BounceCmd,
285 0x1054 => CommandIds::CalibrateCmd,
286 0x1055 => CommandIds::LowBatThresholdCmd,
287 0x1056 => CommandIds::AltLimitMsg,
288 0x1057 => CommandIds::LowBatThresholdMsg,
289 0x1058 => CommandIds::AttLimitCmd,
290 0x1059 => CommandIds::AttLimitMsg,
291 _ => CommandIds::Undefined,
292 }
293 }
294}
295#[derive(Debug, Clone)]
297pub enum ResponseMsg {
298 Connected(String),
299 UnknownCommand(CommandIds),
300}
301
302#[derive(Debug, Clone, Copy)]
305#[repr(u8)]
306pub enum PackageTypes {
307 X48 = 0x48,
308 X50 = 0x50,
309 X60 = 0x60,
310 X70 = 0x70,
311 X68 = 0x68,
312}
313
314pub enum Flip {
316 Forward = 0,
318 Left = 1,
320 Back = 2,
322 Right = 3,
324 ForwardLeft = 4,
326 BackLeft = 5,
328 BackRight = 6,
330 ForwardRight = 7,
332}
333
334#[derive(Debug, Clone)]
336pub enum VideoMode {
337 M960x720 = 0,
338 M1280x720 = 1,
339}
340
341impl Drone {
342 pub fn new(ip: &str) -> Drone {
357 let peer_ip = ip.to_string();
358 let socket = UdpSocket::bind(&SocketAddr::from(([0, 0, 0, 0], 8889)))
359 .expect("couldn't bind to command address");
360 socket.set_nonblocking(true).unwrap();
361 socket.connect(ip).expect("connect command socket failed");
362
363 let video = VideoSettings {
364 port: 0,
365 enabled: false,
366 mode: VideoMode::M960x720,
367 level: 1,
368 encoding_rate: 4,
369 last_video_poll: SystemTime::now(),
370 };
371
372 let rc_state = RCState::default();
373 let drone_meta = DroneMeta::default();
374
375 Drone {
376 peer_ip,
377 socket,
378 video_socket: None,
379 video,
380 status_counter: 0,
381 last_stick_command: SystemTime::now(),
382 rc_state,
383 drone_meta,
384 }
385 }
386
387 pub fn connect(&mut self, video_port: u16) -> usize {
392 let mut data = b"conn_req: ".to_vec();
393 let mut cur = Cursor::new(&mut data);
394 cur.set_position(9);
395 cur.write_u16::<LittleEndian>(video_port).unwrap();
396 self.video.port = video_port;
397 self.start_video().unwrap();
398
399 let video_socket = UdpSocket::bind(&SocketAddr::from(([0, 0, 0, 0], self.video.port)))
400 .expect("couldn't bind to video address");
401 video_socket.set_nonblocking(true).unwrap();
402 self.video_socket = Some(video_socket);
403
404 self.socket.send(&data).expect("network should be usable")
405 }
406
407 pub fn send(&self, command: UdpCommand) -> Result {
410 let data: Vec<u8> = command.into();
411
412 if self.socket.send(&data).is_ok() {
413 Ok(())
414 } else {
415 Err(())
416 }
417 }
418
419 fn send_ack_log(&self, id: u16) -> Result {
422 let mut cmd = UdpCommand::new_with_zero_sqn(CommandIds::LogHeaderMsg, PackageTypes::X50);
423 cmd.write_u16(id);
424 self.send(cmd)
425 }
426
427 fn receive_video_frame(&self, socket: &UdpSocket) -> Option<Message> {
429 let mut read_buf = [0; 1440];
430
431 socket.set_nonblocking(true).unwrap();
432 if let Ok(received) = socket.recv(&mut read_buf) {
433 let active_frame_id = read_buf[0];
434 let mut sqn = read_buf[1];
435 let mut frame_buffer = read_buf[2..received].to_owned();
436
437 if sqn != 0 {
439 return None;
440 }
441
442 socket.set_nonblocking(false).unwrap();
443 'recVideo: loop {
444 if sqn >= 120 {
445 break 'recVideo Some(Message::Frame(active_frame_id, frame_buffer));
446 }
447 if let Ok(received) = socket.recv(&mut read_buf) {
448 let frame_id = read_buf[0];
449 if frame_id != active_frame_id {
450 break 'recVideo None;
452 }
453
454 sqn = read_buf[1];
455 let mut data = read_buf[2..received].to_owned();
456
457 frame_buffer.append(&mut data);
458 } else {
459 break 'recVideo None;
460 }
461 }
462 } else {
463 None
464 }
465 }
466
467 pub fn poll(&mut self) -> Option<Message> {
476 let now = SystemTime::now();
477
478 let delta = now.duration_since(self.last_stick_command).unwrap();
479 if delta.as_millis() > 1000 / 30 {
480 let (pitch, nick, roll, yaw, fast) = self.rc_state.get_stick_parameter();
481 self.send_stick(pitch, nick, roll, yaw, fast).unwrap();
482 self.last_stick_command = now.clone();
483 }
484
485 if self.video.enabled {
487 let delta = now.duration_since(self.video.last_video_poll).unwrap();
488 if delta.as_secs() > 1 {
489 self.video.last_video_poll = now;
490 self.poll_key_frame().unwrap();
491 }
492 if let Some(socket) = self.video_socket.as_ref() {
493 let frame = self.receive_video_frame(&socket);
494 if frame.is_some() {
495 return frame;
496 }
497 }
498 }
499
500 let mut read_buf = [0; 1440];
502 if let Ok(received) = self.socket.recv(&mut read_buf) {
503 let data = read_buf[..received].to_vec();
504 match Message::try_from(data) {
505 Ok(msg) => {
506 match &msg {
507 Message::Response(ResponseMsg::Connected(_)) => self.status_counter = 0,
508 Message::Data(Package {
509 data: PackageData::LogMessage(log),
510 ..
511 }) => self.send_ack_log(log.id).unwrap(),
512 Message::Data(Package { cmd, .. }) if *cmd == CommandIds::TimeCmd => {
513 self.send_date_time().unwrap()
514 }
515 Message::Data(Package { cmd, data, .. })
516 if *cmd == CommandIds::FlightMsg =>
517 {
518 self.drone_meta.update(&data);
519
520 self.status_counter += 1;
521 if self.status_counter == 3 {
522 self.get_version().unwrap();
523 self.set_video_bitrate(4).unwrap();
524 self.get_alt_limit().unwrap();
525 self.get_battery_threshold().unwrap();
526 self.get_att_angle().unwrap();
527 self.get_region().unwrap();
528 self.set_exposure(2).unwrap();
529 };
530 }
531 Message::Data(Package { data, .. }) => {
532 self.drone_meta.update(&data);
533 }
534 _ => (),
535 };
536
537 Some(msg)
538 }
539 Err(_e) => None,
540 }
541 } else {
542 None
543 }
544 }
545}
546
547impl Drone {
548 pub fn command_mode(self) -> CommandMode {
555 CommandMode::from(self.peer_ip.parse::<SocketAddr>().unwrap())
556 }
557}
558
559impl Drone {
560 pub fn take_off(&self) -> Result {
561 self.send(UdpCommand::new(CommandIds::TakeoffCmd, PackageTypes::X68))
562 }
563 pub fn throw_and_go(&self) -> Result {
564 let mut cmd = UdpCommand::new(CommandIds::ThrowAndGoCmd, PackageTypes::X48);
565 cmd.write_u8(0);
566 self.send(cmd)
567 }
568 pub fn land(&self) -> Result {
569 let mut command = UdpCommand::new(CommandIds::LandCmd, PackageTypes::X68);
570 command.write_u8(0x00);
571 self.send(command)
572 }
573 pub fn stop_land(&self) -> Result {
574 let mut command = UdpCommand::new(CommandIds::LandCmd, PackageTypes::X68);
575 command.write_u8(0x00);
576 self.send(command)
577 }
578 pub fn palm_land(&self) -> Result {
579 let mut cmd = UdpCommand::new(CommandIds::PalmLandCmd, PackageTypes::X68);
580 cmd.write_u8(0);
581 self.send(cmd)
582 }
583
584 pub fn flip(&self, direction: Flip) -> Result {
585 let mut cmd = UdpCommand::new_with_zero_sqn(CommandIds::FlipCmd, PackageTypes::X70);
586 cmd.write_u8(direction as u8);
587 self.send(cmd)
588 }
589 pub fn bounce(&self) -> Result {
590 let mut cmd = UdpCommand::new(CommandIds::BounceCmd, PackageTypes::X68);
591 cmd.write_u8(0x30);
592 self.send(cmd)
593 }
594 pub fn bounce_stop(&self) -> Result {
595 let mut cmd = UdpCommand::new(CommandIds::BounceCmd, PackageTypes::X68);
596 cmd.write_u8(0x31);
597 self.send(cmd)
598 }
599
600 pub fn get_version(&self) -> Result {
601 self.send(UdpCommand::new(CommandIds::VersionMsg, PackageTypes::X48))
602 }
603 pub fn get_alt_limit(&self) -> Result {
604 self.send(UdpCommand::new(CommandIds::AltLimitMsg, PackageTypes::X68))
605 }
606 pub fn set_alt_limit(&self, limit: u8) -> Result {
607 let mut cmd = UdpCommand::new(CommandIds::AltLimitCmd, PackageTypes::X68);
608 cmd.write_u8(limit);
609 cmd.write_u8(0);
610 self.send(cmd)
611 }
612 pub fn get_att_angle(&self) -> Result {
613 self.send(UdpCommand::new(CommandIds::AttLimitMsg, PackageTypes::X68))
614 }
615 pub fn set_att_angle(&self) -> Result {
616 let mut cmd = UdpCommand::new(CommandIds::AttLimitCmd, PackageTypes::X68);
617 cmd.write_u8(0);
618 cmd.write_u8(0);
619 cmd.write_u8(10);
622 cmd.write_u8(0x41);
623 self.send(cmd)
624 }
625
626 pub fn get_battery_threshold(&self) -> Result {
627 self.send(UdpCommand::new(
628 CommandIds::LowBatThresholdMsg,
629 PackageTypes::X68,
630 ))
631 }
632 pub fn set_battery_threshold(&self, threshold: u8) -> Result {
633 let mut cmd = UdpCommand::new(CommandIds::LowBatThresholdCmd, PackageTypes::X68);
634 cmd.write_u8(threshold);
635 self.send(cmd)
636 }
637
638 pub fn get_region(&self) -> Result {
639 self.send(UdpCommand::new(
640 CommandIds::WifiRegionCmd,
641 PackageTypes::X48,
642 ))
643 }
644
645 pub fn send_stick(&self, pitch: f32, nick: f32, roll: f32, yaw: f32, fast: bool) -> Result {
652 let mut cmd = UdpCommand::new_with_zero_sqn(CommandIds::StickCmd, PackageTypes::X60);
653
654 let pitch_u = (1024.0 + 660.0 * pitch) as i64;
656
657 let nick_u = (1024.0 + 660.0 * nick) as i64;
659
660 let roll_u = (1024.0 + 660.0 * roll) as i64;
662
663 let yaw_u = (1024.0 + 660.0 * yaw) as i64;
665
666 let throttle_u = if fast { 1i64 } else { 0i64 };
668
669 let packed_axis: i64 = (roll_u & 0x7FF)
671 | (nick_u & 0x7FF) << 11
672 | (pitch_u & 0x7FF) << 22
673 | (yaw_u & 0x7FF) << 33
674 | throttle_u << 44;
675
676 cmd.write_u8(((packed_axis) & 0xFF) as u8);
679 cmd.write_u8(((packed_axis >> 8) & 0xFF) as u8);
680 cmd.write_u8(((packed_axis >> 16) & 0xFF) as u8);
681 cmd.write_u8(((packed_axis >> 24) & 0xFF) as u8);
682 cmd.write_u8(((packed_axis >> 32) & 0xFF) as u8);
683 cmd.write_u8(((packed_axis >> 40) & 0xFF) as u8);
684
685 self.send(Drone::add_time(cmd))
686 }
687
688 pub fn send_date_time(&self) -> Result {
690 let command = UdpCommand::new(CommandIds::TimeCmd, PackageTypes::X50);
691 self.send(Drone::add_date_time(command))
692 }
693
694 pub fn add_time(mut command: UdpCommand) -> UdpCommand {
695 let now = Local::now();
696 let millis = now.nanosecond() / 1_000_000;
697 command.write_u8(now.hour() as u8);
698 command.write_u8(now.minute() as u8);
699 command.write_u8(now.second() as u8);
700 command.write_u16(millis as u16);
701 command
702 }
703
704 pub fn add_date_time(mut command: UdpCommand) -> UdpCommand {
705 let now = Local::now();
706 let millis = now.nanosecond() / 1_000_000;
707 command.write_u8(0);
708 command.write_u16(now.year() as u16);
709 command.write_u16(now.month() as u16);
710 command.write_u16(now.day() as u16);
711 command.write_u16(now.hour() as u16);
712 command.write_u16(now.minute() as u16);
713 command.write_u16(now.second() as u16);
714 command.write_u16(millis as u16);
715 command
716 }
717}
718
719impl Drone {
720 pub fn start_video(&mut self) -> Result {
733 self.video.enabled = true;
734 self.video.last_video_poll = SystemTime::now();
735 self.send(UdpCommand::new_with_zero_sqn(
736 CommandIds::VideoStartCmd,
737 PackageTypes::X60,
738 ))
739 }
740
741 pub fn poll_key_frame(&mut self) -> Result {
745 self.start_video()
746 }
747
748 pub fn set_video_mode(&mut self, mode: VideoMode) -> Result {
759 self.video.mode = mode.clone();
760 let mut cmd = UdpCommand::new_with_zero_sqn(CommandIds::VideoStartCmd, PackageTypes::X68);
761 cmd.write_u8(mode as u8);
762 self.send(cmd)
763 }
764
765 pub fn set_exposure(&mut self, level: u8) -> Result {
776 let mut cmd = UdpCommand::new(CommandIds::ExposureCmd, PackageTypes::X48);
777 cmd.write_u8(level);
778 self.send(cmd)
779 }
780
781 pub fn set_video_bitrate(&mut self, rate: u8) -> Result {
792 self.video.encoding_rate = rate;
793 let mut cmd = UdpCommand::new(CommandIds::VideoEncoderRateCmd, PackageTypes::X68);
794 cmd.write_u8(rate);
795 self.send(cmd)
796 }
797
798 pub fn take_picture(&self) -> Result {
810 self.send(UdpCommand::new(
811 CommandIds::TakePictureCommand,
812 PackageTypes::X68,
813 ))
814 }
815}
816
817#[derive(Debug, Clone)]
821pub struct UdpCommand {
822 cmd: CommandIds,
823 pkt_type: PackageTypes,
824 zero_sqn: bool,
825 inner: Vec<u8>,
826}
827
828impl UdpCommand {
829 pub fn new(cmd: CommandIds, pkt_type: PackageTypes) -> UdpCommand {
831 UdpCommand {
832 cmd,
833 pkt_type,
834 zero_sqn: false,
835 inner: Vec::new(),
836 }
837 }
838 pub fn new_with_zero_sqn(cmd: CommandIds, pkt_type: PackageTypes) -> UdpCommand {
839 UdpCommand {
840 cmd,
841 pkt_type,
842 zero_sqn: true,
843 inner: Vec::new(),
844 }
845 }
846}
847
848impl UdpCommand {
849 pub fn write(&mut self, bytes: &[u8]) {
850 self.inner.append(&mut bytes.to_owned())
851 }
852 pub fn write_u8(&mut self, byte: u8) {
853 self.inner.push(byte)
854 }
855 pub fn write_u16(&mut self, value: u16) {
856 let mut cur = Cursor::new(&mut self.inner);
857 cur.seek(SeekFrom::End(0)).expect("");
858 cur.write_u16::<LittleEndian>(value).expect("");
859 }
860 pub fn write_u64(&mut self, value: u64) {
861 let mut cur = Cursor::new(&mut self.inner);
862 cur.seek(SeekFrom::End(0)).expect("");
863 cur.write_u64::<LittleEndian>(value).expect("");
864 }
865}
866
867impl Into<Vec<u8>> for UdpCommand {
868 fn into(self) -> Vec<u8> {
869 let mut data = {
870 let lng = self.inner.len();
871 let data: &[u8] = &self.inner;
872
873 let mut cur = Cursor::new(Vec::new());
874 cur.write_u8(START_OF_PACKET).expect("");
875 cur.write_u16::<LittleEndian>((lng as u16 + 11) << 3)
876 .expect("");
877 cur.write_u8(crc8(cur.clone().into_inner())).expect("");
878 cur.write_u8(self.pkt_type as u8).expect("");
879 cur.write_u16::<LittleEndian>(self.cmd as u16).expect("");
880
881 if self.zero_sqn {
882 cur.write_u16::<LittleEndian>(0).expect("");
883 } else {
884 let nr = SEQ_NO.fetch_add(1, Ordering::SeqCst);
885 cur.write_u16::<LittleEndian>(nr).expect("");
886 }
887
888 if lng > 0 {
889 cur.write_all(&data).unwrap();
890 }
891
892 cur.into_inner()
893 };
894
895 data.write_u16::<LittleEndian>(crc16(data.clone()))
896 .expect("");
897
898 data
899 }
900}
901
902#[derive(Debug, Clone)]
904pub struct Package {
905 pub cmd: CommandIds,
906 pub size: u16,
907 pub sq_nr: u16,
908 pub data: PackageData,
909}
910
911#[derive(Debug, Clone)]
913pub enum Message {
914 Data(Package),
915 Response(ResponseMsg),
916 Frame(u8, Vec<u8>),
917}
918
919impl TryFrom<Vec<u8>> for Message {
920 type Error = String;
921
922 fn try_from(data: Vec<u8>) -> std::result::Result<Self, Self::Error> {
923 let mut cur = Cursor::new(data);
924 if let Ok(START_OF_PACKET) = cur.read_u8() {
925 let size = (cur.read_u16::<LittleEndian>().unwrap() >> 3) - 11;
926 let _crc8 = cur.read_u8().unwrap();
927 let _pkt_type = cur.read_u8().unwrap();
928 let cmd = CommandIds::from(cur.read_u16::<LittleEndian>().unwrap());
929 let sq_nr = cur.read_u16::<LittleEndian>().unwrap();
930 let data = if size > 0 {
931 let mut data: Vec<u8> = Vec::with_capacity(size as usize);
932 cur.read_to_end(&mut data).unwrap();
933 if data.len() >= 2 {
934 let _crc16: u16 =
935 (data.pop().unwrap() as u16) + ((data.pop().unwrap() as u16) << 8);
936 }
937 match cmd {
938 CommandIds::FlightMsg => PackageData::FlightData(FlightData::from(data)),
939 CommandIds::WifiMsg => PackageData::WifiInfo(WifiInfo::from(data)),
940 CommandIds::LightMsg => PackageData::LightInfo(LightInfo::from(data)),
941 CommandIds::VersionMsg => PackageData::Version(
942 String::from_utf8(data[1..].to_vec())
943 .expect("version is not valid")
944 .trim_matches(char::from(0))
945 .to_string(),
946 ),
947 CommandIds::AltLimitMsg => {
948 let mut c = Cursor::new(data);
949 let _ = c.read_u8().unwrap();
950 let h = c.read_u16::<LittleEndian>().unwrap();
951 PackageData::AtlInfo(h)
952 }
953
954 CommandIds::LogHeaderMsg => PackageData::LogMessage(LogMessage::from(data)),
955 _ => PackageData::Unknown(data),
956 }
957 } else {
958 PackageData::NoData()
959 };
960
961 Ok(Message::Data(Package {
962 cmd,
963 size,
964 sq_nr,
965 data,
966 }))
967 } else {
968 let data = cur.into_inner();
969 if data[0..9].to_vec() == b"conn_ack:" {
970 return Ok(Message::Response(ResponseMsg::Connected(
971 String::from_utf8(data).unwrap(),
972 )));
973 } else if data[0..16].to_vec() == b"unknown command:" {
974 let mut cur = Cursor::new(data[17..].to_owned());
975 let command = CommandIds::from(cur.read_u16::<LittleEndian>().unwrap());
976 return Ok(Message::Response(ResponseMsg::UnknownCommand(command)));
977 }
978
979 let msg = String::from_utf8(data.clone()[0..5].to_vec()).unwrap_or_default();
980 Err(format!("invalid package {:x?}", msg))
981 }
982 }
983}
984
985#[derive(Debug, Clone)]
987pub enum PackageData {
988 NoData(),
989 AtlInfo(u16),
990 FlightData(FlightData),
991 LightInfo(LightInfo),
992 LogMessage(LogMessage),
993 Version(String),
994 WifiInfo(WifiInfo),
995 Unknown(Vec<u8>),
996}