File Coverage

blib/lib/UAV/Pilot/ArdupilotProtocol/PacketFactory.pm
Criterion Covered Total %
statement 7 9 77.7
branch n/a
condition n/a
subroutine 3 3 100.0
pod n/a
total 10 12 83.3


line stmt bran cond sub pod time code
1             # Copyright (c) 2014 Timm Murray
2             # All rights reserved.
3             #
4             # Redistribution and use in source and binary forms, with or without
5             # modification, are permitted provided that the following conditions are met:
6             #
7             # * Redistributions of source code must retain the above copyright notice,
8             # this list of conditions and the following disclaimer.
9             # * Redistributions in binary form must reproduce the above copyright
10             # notice, this list of conditions and the following disclaimer in the
11             # documentation and/or other materials provided with the distribution.
12             #
13             # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
14             # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15             # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16             # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
17             # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18             # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19             # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20             # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21             # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22             # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
23             # POSSIBILITY OF SUCH DAMAGE.
24             package UAV::Pilot::ArdupilotProtocol::PacketFactory;
25 2     2   26614 use v5.14;
  2         7  
  2         123  
26 2     2   13 use warnings;
  2         5  
  2         66  
27 2     2   2018 use UAV::Pilot;
  0            
  0            
28             use UAV::Pilot::Exceptions;
29             use UAV::Pilot::ArdupilotProtocol::Packet;
30             use UAV::Pilot::ArdupilotProtocol::Packet::Ack;
31             use UAV::Pilot::ArdupilotProtocol::Packet::Heartbeat;
32             use UAV::Pilot::ArdupilotProtocol::Packet::RequestStartupMessage;
33             use UAV::Pilot::ArdupilotProtocol::Packet::StartupMessage;
34             use UAV::Pilot::ArdupilotProtocol::Packet::RadioTrims;
35             use UAV::Pilot::ArdupilotProtocol::Packet::RadioMins;
36             use UAV::Pilot::ArdupilotProtocol::Packet::RadioMaxes;
37             use UAV::Pilot::ArdupilotProtocol::Packet::RadioOutputs;
38              
39              
40             use constant PACKET_CLASS_PREFIX => 'UAV::Pilot::ArdupilotProtocol::Packet::';
41             use constant PREAMBLE => 0x3444;
42             use constant MESSAGE_ID_CLASS_MAP => {
43             0x00 => 'Ack',
44             0x01 => 'Heartbeat',
45             0x07 => 'RequestStartupMessage',
46             0x08 => 'StartupMessage',
47             0x50 => 'RadioTrims',
48             0x51 => 'RadioMins',
49             0x52 => 'RadioMaxes',
50             0x53 => 'RadioOutputs',
51             };
52              
53              
54             sub read_packet
55             {
56             my ($self, $packet) = @_;
57             my @packet = unpack 'C*', $packet;
58              
59             my $preamble = ($packet[0] << 8 ) | $packet[1];
60             UAV::Pilot::ArdupilotPacketException::BadHeader->throw({
61             got_header => $preamble,
62             }) if $self->PREAMBLE != $preamble;
63              
64             my $payload_length = $packet[2];
65             my $message_id = $packet[3];
66             my $version = $packet[4];
67              
68             my $last_payload_i = 4 + $payload_length;
69             my @payload = @packet[5..$last_payload_i];
70             my $checksum1 = $packet[$last_payload_i + 1];
71             my $checksum2 = $packet[$last_payload_i + 2];
72              
73             my ($expect_checksum1, $expect_checksum2) = UAV::Pilot->checksum_fletcher8(
74             $payload_length, $message_id, $version, @payload );
75             UAV::Pilot::ArdupilotPacketException::BadChecksum->throw({
76             got_checksum1 => $checksum1,
77             got_checksum2 => $checksum2,
78             expected_checksum1 => $expect_checksum1,
79             expected_checksum2 => $expect_checksum2,
80             }) if ($expect_checksum1 != $checksum1) || ($expect_checksum2 != $checksum2);
81              
82             if(! exists $self->MESSAGE_ID_CLASS_MAP->{$message_id}) {
83             warn sprintf( 'No class found for message ID 0x%02x', $message_id )
84             . "\n";
85             return undef;
86             }
87             my $class = $self->PACKET_CLASS_PREFIX
88             . $self->MESSAGE_ID_CLASS_MAP->{$message_id};
89             my $new_packet = $class->new({
90             preamble => $preamble,
91             version => $version,
92             checksum1 => $checksum1,
93             checksum2 => $checksum2,
94             payload => \@payload,
95             });
96             return $new_packet;
97             }
98              
99             sub fresh_packet
100             {
101             my ($self, $type) = @_;
102             my $class = $self->PACKET_CLASS_PREFIX . $type;
103              
104             my $packet = eval {
105             $class->new({
106             fresh => 1,
107             });
108             };
109             if( $@ ) {
110             die "[PacketFactory] Could not init '$class': $@\n";
111             }
112              
113             return $packet;
114             }
115              
116              
117             1;
118             __END__