vesc_packet_factory.cpp
Go to the documentation of this file.
1 // Copyright 2020 F1TENTH Foundation
2 //
3 // Redistribution and use in source and binary forms, with or without modification, are permitted
4 // provided that the following conditions are met:
5 //
6 // 1. Redistributions of source code must retain the above copyright notice, this list of conditions
7 // and the following disclaimer.
8 //
9 // 2. Redistributions in binary form must reproduce the above copyright notice, this list
10 // of conditions and the following disclaimer in the documentation and/or other materials
11 // provided with the distribution.
12 //
13 // 3. Neither the name of the copyright holder nor the names of its contributors may be used
14 // to endorse or promote products derived from this software without specific prior
15 // written permission.
16 //
17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
18 // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
19 // FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
20 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23 // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
24 // WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 
26 // -*- mode:c++; fill-column: 100; -*-
27 
29 
30 #include <cassert>
31 #include <iterator>
32 #include <memory>
33 #include <string>
34 
36 
37 namespace vesc_driver
38 {
39 
42 {
43  static FactoryMap m;
44  return &m;
45 }
46 
48 {
49  FactoryMap* p_map(getMap());
50  assert(0 == p_map->count(payload_id));
51  (*p_map)[payload_id] = fn;
52 }
53 
55 VescPacketPtr createFailed(int* p_num_bytes_needed, std::string* p_what,
56  const std::string& what, int num_bytes_needed = 0)
57 {
58  if (p_num_bytes_needed != NULL) *p_num_bytes_needed = num_bytes_needed;
59  if (p_what != NULL) *p_what = what;
60  return VescPacketPtr();
61 }
62 
63 VescPacketPtr VescPacketFactory::createPacket(const Buffer::const_iterator& begin,
64  const Buffer::const_iterator& end,
65  int* num_bytes_needed, std::string* what)
66 {
67  // initialize output variables
68  if (num_bytes_needed != NULL) *num_bytes_needed = 0;
69  if (what != NULL) what->clear();
70 
71  // need at least VESC_MIN_FRAME_SIZE bytes in buffer
72  int buffer_size(std::distance(begin, end));
73  if (buffer_size < VescFrame::VESC_MIN_FRAME_SIZE)
74  return createFailed(num_bytes_needed, what, "Buffer does not contain a complete frame",
75  VescFrame::VESC_MIN_FRAME_SIZE - buffer_size);
76 
77  // buffer must begin with a start-of-frame
80  return createFailed(num_bytes_needed, what, "Buffer must begin with start-of-frame character");
81 
82  // get a view of the payload
83  BufferRangeConst view_payload;
85  {
86  // payload size field is one byte
87  view_payload.first = begin + 2;
88  view_payload.second = view_payload.first + *(begin + 1);
89  }
90  else
91  {
92  assert(VescFrame::VESC_SOF_VAL_LARGE_FRAME == *begin);
93  // payload size field is two bytes
94  view_payload.first = begin + 3;
95  view_payload.second = view_payload.first + (*(begin + 1) << 8) + *(begin + 2);
96  }
97 
98  // check length
99  if (std::distance(view_payload.first, view_payload.second) > VescFrame::VESC_MAX_PAYLOAD_SIZE)
100  return createFailed(num_bytes_needed, what, "Invalid payload length");
101 
102  // get iterators to crc field, end-of-frame field, and a view of the whole frame
103  Buffer::const_iterator iter_crc(view_payload.second);
104  Buffer::const_iterator iter_eof(iter_crc + 2);
105  BufferRangeConst view_frame(begin, iter_eof + 1);
106 
107  // do we have enough data in the buffer to complete the frame?
108  int frame_size = std::distance(view_frame.first, view_frame.second);
109  if (buffer_size < frame_size)
110  return createFailed(num_bytes_needed, what, "Buffer does not contain a complete frame",
111  frame_size - buffer_size);
112 
113  // is the end-of-frame character valid?
114  if (VescFrame::VESC_EOF_VAL != *iter_eof)
115  return createFailed(num_bytes_needed, what, "Invalid end-of-frame character");
116 
117  // is the crc valid?
118  uint16_t crc = (static_cast<uint16_t>(*iter_crc) << 8) + *(iter_crc + 1);
119  if (crc != CRC::Calculate(
120  &(*view_payload.first), std::distance(view_payload.first, view_payload.second), VescFrame::CRC_TYPE))
121  return createFailed(num_bytes_needed, what, "Invalid checksum");
122 
123  // frame looks good, construct the raw frame
124  std::shared_ptr<VescFrame> raw_frame(new VescFrame(view_frame, view_payload));
125 
126  // if the packet has a payload, construct the corresponding subclass
127  if (std::distance(view_payload.first, view_payload.second) > 0)
128  {
129  // get constructor function from payload id
130  FactoryMap* p_map(getMap());
131  FactoryMap::const_iterator search(p_map->find(*view_payload.first));
132  if (search != p_map->end())
133  {
134  return search->second(raw_frame);
135  }
136  else
137  {
138  // no subclass constructor for this packet
139  return createFailed(num_bytes_needed, what, "Unkown payload type.");
140  }
141  }
142  else
143  {
144  // no payload
145  return createFailed(num_bytes_needed, what, "Frame does not have a payload");
146  }
147 }
148 
149 } // namespace vesc_driver
static constexpr CRC::Parameters< crcpp_uint16, 16 > CRC_TYPE
Definition: vesc_packet.h:68
std::pair< Buffer::const_iterator, Buffer::const_iterator > BufferRangeConst
Definition: vesc_packet.h:45
static VescPacketPtr createPacket(const Buffer::const_iterator &begin, const Buffer::const_iterator &end, int *num_bytes_needed, std::string *what)
static const int VESC_MIN_FRAME_SIZE
Smallest VESC frame size, in bytes.
Definition: vesc_packet.h:61
VescPacketPtr createFailed(int *p_num_bytes_needed, std::string *p_what, const std::string &what, int num_bytes_needed=0)
std::map< int, CreateFn > FactoryMap
static const int VESC_MAX_PAYLOAD_SIZE
Maximum VESC payload size, in bytes.
Definition: vesc_packet.h:60
static const unsigned int VESC_EOF_VAL
VESC end-of-frame value.
Definition: vesc_packet.h:65
static CRCType Calculate(const void *data, crcpp_size size, const Parameters< CRCType, CRCWidth > &parameters)
Computes a CRC.
Definition: crc.h:434
std::shared_ptr< VescPacket > VescPacketPtr
Definition: vesc_packet.h:106
static void registerPacketType(int payload_id, CreateFn fn)
std::function< VescPacketPtr(std::shared_ptr< VescFrame >)> CreateFn
static const unsigned int VESC_SOF_VAL_LARGE_FRAME
VESC start of "large" frame value.
Definition: vesc_packet.h:64
static const unsigned int VESC_SOF_VAL_SMALL_FRAME
VESC start of "small" frame value.
Definition: vesc_packet.h:63
ROSCPP_DECL bool search(const std::string &ns, const std::string &key, std::string &result)


vesc_driver
Author(s): Michael T. Boulet , Joshua Whitley
autogenerated on Sun Apr 18 2021 02:48:01