Move attributes flags and maxdlen
[apps/agl-service-can-low-level.git] / low-can-binding / can / message / can-message.cpp
1 /*
2  * Copyright (C) 2015, 2016 "IoT.bzh"
3  * Author "Romain Forlot" <romain.forlot@iot.bzh>
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *       http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17
18 #include "./can-message.hpp"
19
20 #include <cstring>
21
22 #include "../../binding/low-can-hat.hpp"
23
24 ///
25 /// @brief Class constructor
26 ///
27 /// can_message_t class constructor.
28 ///
29 can_message_t::can_message_t()
30         : message_t(),
31          id_{0},
32          rtr_flag_{false}
33 {}
34
35 can_message_t::can_message_t(uint32_t maxdlen,
36         uint32_t id,
37         uint32_t length,
38         message_format_t format,
39         bool rtr_flag,
40         uint32_t flags,
41         std::vector<uint8_t>& data,
42         uint64_t timestamp)
43         : message_t(maxdlen, length, format, data, timestamp, flags),
44         id_{id},
45         rtr_flag_{rtr_flag}
46 {}
47
48 ///
49 /// @brief Retrieve id_ member value.
50 ///
51 /// @return id_ class member
52 ///
53 uint32_t can_message_t::get_id() const
54 {
55         return id_;
56 }
57
58
59 /// @brief Control whether the object is correctly initialized
60 ///  to be sent over the CAN bus
61 ///
62 /// @return True if object correctly initialized and false if not.
63 bool can_message_t::is_correct_to_send()
64 {
65         if (id_ != 0 && length_ != 0 && format_ != message_format_t::INVALID)
66         {
67                 int i;
68                 for(i=0;i<length_;i++)
69                         if(data_[i] != 0)
70                                 return true;
71         }
72         return false;
73 }
74
75 /// @brief Take a canfd_frame struct to initialize class members
76 ///
77 /// This is the preferred way to initialize class members.
78 ///
79 /// @param[in] frame - canfd_frame to convert coming from a read of CAN socket
80 /// @param[in] nbytes - bytes read from socket read operation.
81 ///
82 /// @return A can_message_t object fully initialized with canfd_frame values.
83 std::shared_ptr<can_message_t> can_message_t::convert_from_frame(const struct canfd_frame& frame, size_t nbytes, uint64_t timestamp)
84 {
85         uint32_t maxdlen = 0, length = 0;
86         uint8_t flags = 0;
87         uint32_t id;
88         message_format_t format;
89         bool rtr_flag;
90         std::vector<uint8_t> data;
91
92         switch(nbytes)
93         {
94                 case CANFD_MTU:
95                         AFB_DEBUG("Got an CAN FD frame");
96                         maxdlen = CANFD_MAX_DLEN;
97                         break;
98                 case CAN_MTU:
99                         AFB_DEBUG("Got a legacy CAN frame");
100                         maxdlen = CAN_MAX_DLEN;
101                         break;
102                 default:
103                         AFB_ERROR("unsupported CAN frame");
104                         break;
105         }
106
107         if (frame.can_id & CAN_ERR_FLAG)
108         {
109                 format = message_format_t::INVALID;
110                 id = frame.can_id & (CAN_ERR_MASK|CAN_ERR_FLAG);
111         }
112         else if (frame.can_id & CAN_EFF_FLAG)
113         {
114                 format = message_format_t::EXTENDED;
115                 id = frame.can_id & CAN_EFF_MASK;
116         }
117         else
118         {
119                 format = message_format_t::STANDARD;
120                 id = frame.can_id & CAN_SFF_MASK;
121         }
122
123         /* Overwrite length_ if RTR flags is detected.
124          * standard CAN frames may have RTR enabled. There are no ERR frames with RTR */
125         if (frame.can_id & CAN_RTR_FLAG)
126         {
127                 rtr_flag = true;
128                 if(frame.len && frame.len <= CAN_MAX_DLC)
129                 {
130                         if(rtr_flag)
131                                 length = frame.len& 0xF;
132                         else
133                         {
134                                 length = (frame.len > maxdlen) ? maxdlen : frame.len;
135                         }
136                 }
137         }
138         else
139         {
140                 length = (frame.len > maxdlen) ? maxdlen : frame.len;
141
142                 /* Flags field only present for CAN FD frames*/
143                 if(maxdlen == CANFD_MAX_DLEN)
144                                 flags = frame.flags & 0xF;
145
146                 if (data.capacity() < maxdlen)
147                         data.reserve(maxdlen);
148                                 int i;
149
150                         data.clear();
151                         /* maxdlen_ is now set at CAN_MAX_DLEN or CANFD_MAX_DLEN, respectively 8 and 64 bytes*/
152                         for(i=0;i<maxdlen;i++)
153                         {
154                                 data.push_back(frame.data[i]);
155                         };
156
157                 AFB_DEBUG("Found id: %X, format: %X, length: %X, data %02X%02X%02X%02X%02X%02X%02X%02X",
158                                                                 id, (uint8_t)format, length, data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7]);
159         }
160
161         return std::make_shared<can_message_t>(can_message_t(maxdlen, id, length, format, rtr_flag, flags, data, timestamp));
162 }
163
164 /// @brief Take all initialized class members and build a
165 /// canfd_frame struct that can be use to send a CAN message over
166 /// the bus.
167 ///
168 /// @return canfd_frame struct built from class members.
169 struct canfd_frame can_message_t::convert_to_canfd_frame()
170 {
171         canfd_frame frame;
172
173         if(is_correct_to_send())
174         {
175                 frame.can_id = get_id();
176                 frame.len = (uint8_t) get_length();
177                 ::memcpy(frame.data, get_data(), length_);
178         }
179         else
180                 AFB_ERROR("can_message_t not correctly initialized to be sent");
181
182         return frame;
183 }
184
185 /// @brief Take all initialized class members and build a
186 /// canfd_frame struct that can be use to send a CAN message over
187 /// the bus.
188 ///
189 /// @return canfd_frame struct built from class members.
190 struct std::vector<canfd_frame> can_message_t::convert_to_canfd_frame_vector()
191 {
192         std::vector<canfd_frame> ret;
193         if(is_correct_to_send())
194         {
195                 if(flags_ & CAN_FD_FRAME)
196                 {
197                         int i=0;
198                         do
199                         {
200                                 canfd_frame frame;
201                                 frame.can_id = id_;
202                                 frame.len = 64;
203                                 std::vector<uint8_t> data = get_data_vector((i*64),(i*64)+63);
204                                 if(data.size()<64)
205                                 {
206                                         ::memset(frame.data,0,sizeof(frame.data));
207                                         ::memcpy(frame.data,data.data(),data.size());
208                                 }
209                                 else
210                                 {
211                                         ::memcpy(frame.data,data.data(),64);
212                                 }
213                                 ret.push_back(frame);
214                                 i++;
215                         } while (i<(length_ >> 6));
216                 }
217                 else
218                 {
219                         int i=0;
220                         do
221                         {
222                                 canfd_frame frame;
223                                 frame.can_id = id_;
224                                 frame.len = 8;
225                                 std::vector<uint8_t> data = get_data_vector(i*8,(i*8)+7);
226                                 if(data.size()<8)
227                                 {
228                                         ::memset(frame.data,0,sizeof(frame.data));
229                                         ::memcpy(frame.data,data.data(),data.size());
230                                 }
231                                 else
232                                 {
233                                         ::memset(frame.data,0,sizeof(frame.data));
234                                         ::memcpy(frame.data,data.data(),8);
235                                 }
236                                 ret.push_back(frame);
237                                 i++;
238                         } while (i<(length_ >> 3));
239                 }
240         }
241         else
242                 AFB_ERROR("can_message_t not correctly initialized to be sent");
243
244         return ret;
245 }
246
247 /// @brief Take all initialized class members and build a
248 /// can_frame struct that can be use to send a CAN message over
249 /// the bus.
250 ///
251 /// @return can_frame struct built from class members.
252 struct can_frame can_message_t::convert_to_can_frame()
253 {
254         can_frame frame;
255
256         if(is_correct_to_send())
257         {
258                 frame.can_id = get_id();
259                 frame.can_dlc = (uint8_t) get_length();
260                 ::memcpy(frame.data, get_data(), length_);
261         }
262         else
263                 AFB_ERROR("can_message_t not correctly initialized to be sent");
264
265         return frame;
266 }
267
268 bool can_message_t::is_set()
269 {
270         return (id_ != 0 && length_ != 0);
271 }
272
273 std::string can_message_t::get_debug_message()
274 {
275         std::string ret = "";
276         ret = ret + "Here is the next can message : id " + std::to_string(id_)  + " length " + std::to_string(length_) + ", data ";
277         for (size_t i = 0; i < data_.size(); i++)
278         {
279                 ret = ret + std::to_string(data_[i]);
280         }
281
282         return ret;
283 }
284
285 struct bcm_msg can_message_t::get_bcm_msg()
286 {
287         return bcm_msg_;
288 }
289
290 void can_message_t::set_bcm_msg(struct bcm_msg bcm_msg)
291 {
292         bcm_msg_ = bcm_msg;
293 }