mavtables  0.2.1
MAVLink router and firewall.
PacketParser.cpp
Go to the documentation of this file.
1 // MAVLink router and firewall.
2 // Copyright (C) 2018 Michael R. Shannon <mrshannon.aerospace@gmail.com>
3 //
4 // This program is free software; you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation; either version 2 of the License, or
7 // (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with this program. If not, see <http://www.gnu.org/licenses/>.
16 
17 
18 #include <iostream>
19 #include <memory>
20 #include <stdexcept>
21 #include <utility>
22 
23 #include "InvalidPacketIDError.hpp"
24 #include "mavlink.hpp"
25 #include "PacketParser.hpp"
26 #include "PacketVersion1.hpp"
27 #include "PacketVersion2.hpp"
28 
29 
30 /** Construct a \ref PacketParser.
31  */
33  : state_(WAITING_FOR_START_BYTE)
34 {
35  clear();
36 }
37 
38 
39 /** Return the number of bytes parsed on the current packet.
40  *
41  * \returns The number of bytes parsed on the current packet, 0 if no packet is
42  * currently being parsed.
43  */
45 {
46  return buffer_.size();
47 }
48 
49 
50 /** Reset packet parser so it can parse another packet.
51  *
52  * %If called while parsing a packet, that packet will be lost.
53  */
55 {
56  buffer_.clear();
57  buffer_.reserve(MAVLINK_MAX_PACKET_LEN);
58  state_ = WAITING_FOR_START_BYTE;
59  version_ = Packet::V2;
60  bytes_remaining_ = 0;
61 }
62 
63 
64 /** Parse a MAVLink wire protocol byte, v1.0 or v2.0.
65  *
66  * When a packet is completed it will be returned and the parser reset so it
67  * can be used to continue parsing.
68  *
69  * \param byte A byte from the MAVLink wire protocol.
70  * \returns A complete v1.0 or v2.0 packet. %If the parser has not yet parsed
71  * a complete packet, nullptr is returned.
72  */
73 std::unique_ptr<Packet> PacketParser::parse_byte(uint8_t byte)
74 {
75  std::unique_ptr<Packet> packet;
76 
77  switch (state_)
78  {
79  case WAITING_FOR_START_BYTE:
80  waiting_for_start_byte_(byte);
81  break;
82 
83  case WAITING_FOR_HEADER:
84  waiting_for_header_(byte);
85  break;
86 
87  case WAITING_FOR_PACKET:
88  packet = waiting_for_packet_(byte);
89  }
90 
91  return packet;
92 }
93 
94 
95 /** Check for start of packet.
96  *
97  * Start packet parsing if the given \p byte is a start byte for either v1.0 or
98  * v2.0 packets. Next state will be `WAITING_FOR_HEADER` if this is the case.
99  *
100  * \param byte The byte to attempt parsing.
101  */
102 void PacketParser::waiting_for_start_byte_(uint8_t byte)
103 {
104  if (byte == packet_v1::START_BYTE)
105  {
106  // Store start byte and begin receiving header.
107  buffer_.push_back(byte);
108  state_ = WAITING_FOR_HEADER;
109  version_ = packet_v1::VERSION;
110  }
111  else if (byte == packet_v2::START_BYTE)
112  {
113  // Store start byte and begin receiving header.
114  buffer_.push_back(byte);
115  state_ = WAITING_FOR_HEADER;
116  version_ = packet_v2::VERSION;
117  }
118 }
119 
120 
121 /** Parser header byte.
122  *
123  * Next state will be `WAITING_FOR_PACKET` if the given \p byte completes the
124  * header.
125  *
126  * \param byte The byte to attempt parsing.
127  */
128 void PacketParser::waiting_for_header_(uint8_t byte)
129 {
130  buffer_.push_back(byte);
131 
132  switch (version_)
133  {
134  case packet_v1::VERSION:
135  if (packet_v1::header_complete(buffer_))
136  {
137  // Set number of expected bytes and start waiting for
138  // remainder of packet.
139  bytes_remaining_ = packet_v1::header(buffer_)->len +
141  state_ = WAITING_FOR_PACKET;
142  }
143 
144  break;
145 
146  case packet_v2::VERSION:
147  if (packet_v2::header_complete(buffer_))
148  {
149  // Set number of expected bytes and start waiting for
150  // remainder of packet.
151  bytes_remaining_ = packet_v2::header(buffer_)->len +
153 
154  if (packet_v2::is_signed(buffer_))
155  {
156  bytes_remaining_ += packet_v2::SIGNATURE_LENGTH;
157  }
158 
159  state_ = WAITING_FOR_PACKET;
160  }
161 
162  break;
163  }
164 }
165 
166 
167 /** Parse packet bytes.
168  *
169  * %If this \p byte completes the packet a \ref std::unique_ptr to the packet
170  * is returned and the parser is reset to begin parsing another packet (next
171  * state WAITING_FOR_START_BYTE). Otherwise a nullptr is returned.
172  *
173  * \param byte The byte to attempt parsing.
174  * \returns A unique pointer to the complete packet. %If the packet is not
175  * complete a nullptr is returned.
176  */
177 std::unique_ptr<Packet> PacketParser::waiting_for_packet_(uint8_t byte)
178 {
179  buffer_.push_back(byte);
180  --bytes_remaining_;
181 
182  if (bytes_remaining_ == 0)
183  {
184  std::unique_ptr<Packet> packet;
185 
186  try
187  {
188  switch (version_)
189  {
190  case packet_v1::VERSION:
191  packet = std::make_unique<packet_v1::Packet>(
192  std::move(buffer_));
193  break;
194 
195  case packet_v2::VERSION:
196  packet = std::make_unique<packet_v2::Packet>(
197  std::move(buffer_));
198  break;
199  }
200  }
201  catch (const InvalidPacketIDError &err)
202  {
203  packet = nullptr;
204  std::cerr << err.what() << std::endl;
205  }
206 
207  clear();
208  return packet;
209  }
210 
211  return nullptr;
212 }
const size_t CHECKSUM_LENGTH
bool header_complete(const std::vector< uint8_t > &data)
size_t bytes_parsed() const
const struct mavlink::v2_header * header(const std::vector< uint8_t > &data)
const size_t SIGNATURE_LENGTH
MAVLink Version 2.0.
Definition: Packet.hpp:50
const size_t CHECKSUM_LENGTH
const uint8_t START_BYTE
const ::Packet::Version VERSION
const char * what() const noexcept
const ::Packet::Version VERSION
const uint8_t START_BYTE
bool is_signed(const std::vector< uint8_t > &data)
bool header_complete(const std::vector< uint8_t > &data)
std::unique_ptr< Packet > parse_byte(uint8_t byte)
const struct mavlink::v1_header * header(const std::vector< uint8_t > &data)