1be0d2d4fd6b4780d8cbf213a417b25095e4b7b8
[apps/agl-service-can-low-level.git] / src / can / 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/can-message.hpp"
19
20 #include <cstring>
21
22 #include "low-can-binding.hpp"
23
24 /********************************************************************************
25 *
26 *               CanMessage method implementation
27 *
28 *********************************************************************************/
29 /**
30 * @brief Class constructor
31 *
32 * Constructor about can_message_t class.
33 */
34 can_message_t::can_message_t()
35         : id_{0}, rtr_flag_{false}, length_{0}, flags_{0}, format_{can_message_format_t::ERROR}, maxdlen_{0}
36 {}
37
38 /**
39 * @brief Retrieve id_ member value.
40 *
41 * @return id_ class member
42 */
43 uint32_t can_message_t::get_id() const
44 {
45         return id_;
46 }
47
48 /**
49 * @brief Retrieve RTR flag member.
50 *
51 * @return rtr_flags_ class member
52 */
53 bool can_message_t::get_rtr_flag_() const
54 {
55         return rtr_flag_;
56 }
57
58 /**
59 * @brief Retrieve format_ member value.
60 *
61 * @return format_ class member
62 */
63 can_message_format_t can_message_t::get_format() const
64 {
65         if (format_ != can_message_format_t::STANDARD || format_ != can_message_format_t::EXTENDED)
66                 return can_message_format_t::ERROR;
67         return format_;
68 }
69
70 /**
71 * @brief Retrieve flags_ member value.
72 *
73 * @return flags_ class member 
74 */
75 uint8_t can_message_t::get_flags() const
76 {
77         return flags_;
78 }
79
80 /**
81 * @brief Retrieve data_ member value.
82 *
83 * @return pointer to the first element 
84 *  of class member data_
85 */
86 const uint8_t* can_message_t::get_data() const
87 {
88         return data_.data();
89 }
90
91 /**
92 * @brief Retrieve length_ member value.
93 *
94 * @return length_ class member
95 */
96 uint8_t can_message_t::get_length() const
97 {
98         return length_;
99 }
100
101 /**
102 * @brief Control whether the object is correctly initialized
103 *  to be sent over the CAN bus
104 *
105 * @return true if object correctly initialized and false if not.
106 */
107 bool can_message_t::is_correct_to_send()
108 {
109         if (id_ != 0 && length_ != 0 && format_ != can_message_format_t::ERROR)
110         {
111                 int i;
112                 for(i=0;i<CAN_MESSAGE_SIZE;i++)
113                         if(data_[i] != 0)
114                                 return true;
115         }
116         return false;
117 }
118
119 /**
120 * @brief Set format_ member value.
121 *
122 * Preferred way to initialize these members by using 
123 * convert_from_canfd_frame method.
124 *
125 * @param[in] new_format - class member
126 */
127 void can_message_t::set_format(const can_message_format_t new_format)
128 {
129         if(new_format == can_message_format_t::STANDARD || new_format == can_message_format_t::EXTENDED || new_format == can_message_format_t::ERROR)
130                 format_ = new_format;
131         else
132                 ERROR(binder_interface, "ERROR: Can set format, wrong format chosen");
133 }
134
135 /**
136 * @brief Take a canfd_frame struct to initialize class members
137 *
138 * This is the preferred way to initialize class members.
139 *
140 * @param[in] args - struct read from can bus device.
141 */
142 can_message_t can_message_t::convert_to_canfd_frame(const struct canfd_frame& frame, size_t nbytes)
143 {
144         switch(nbytes)
145         {
146                 case CANFD_MTU:
147                         DEBUG(binder_interface, "set_max_data_length: Got an CAN FD frame");
148                         maxdlen_ = CANFD_MAX_DLEN;
149                         break;
150                 case CAN_MTU:
151                         DEBUG(binder_interface, "set_max_data_length: Got a legacy CAN frame");
152                         maxdlen_ = CAN_MAX_DLEN;
153                         break;
154                 default:
155                         ERROR(binder_interface, "set_max_data_length: unsupported CAN frame");
156                         break;
157         }
158
159         if(rtr_flag_)
160                 length_ = frame.len& 0xF;
161         else
162         {
163                 length_ = (frame.len > maxdlen_) ? maxdlen_ : frame.len;
164         }
165         
166         if (frame.can_id & CAN_ERR_FLAG)
167                 format_ = can_message_format_t::ERROR;
168         else if (frame.can_id & CAN_EFF_FLAG)
169                 format_ = can_message_format_t::EXTENDED;
170         else
171                 format_ = can_message_format_t::STANDARD;
172                 
173         switch(format_)
174         {
175                 case can_message_format_t::STANDARD:
176                         id_ = frame.can_id & CAN_SFF_MASK;
177                         break;
178                 case can_message_format_t::EXTENDED:
179                         id_ = frame.can_id & CAN_EFF_MASK;
180                         break;
181                 case can_message_format_t::ERROR:
182                         id_ = frame.can_id & (CAN_ERR_MASK|CAN_ERR_FLAG);
183                         break;
184                 default:
185                         ERROR(binder_interface, "ERROR: Can set id, not a compatible format or format not set prior to set id.");
186                         break;
187         }
188         
189         /* Overwrite lenght_ if RTR flags is detected.
190          * standard CAN frames may have RTR enabled. There are no ERR frames with RTR */
191         if (frame.can_id & CAN_RTR_FLAG)
192         {
193                 rtr_flag_ = true;
194                 if(frame.len && frame.len <= CAN_MAX_DLC)
195                 {
196         if(rtr_flag_)
197                 length_ = frame.len& 0xF;
198         else
199         {
200                 length_ = (frame.len > maxdlen_) ? maxdlen_ : frame.len;
201         }       
202                 }
203         }
204         else
205         {
206         /* Flags field only present for CAN FD frames*/
207         if(maxdlen_ == CANFD_MAX_DLEN)
208                         flags_ = frame.flags & 0xF;
209   
210         if (data_.capacity() < maxdlen_)
211                 data_.reserve(maxdlen_);
212                         int i;
213
214                 data_.clear();
215                 /* maxdlen_ is now set at CAN_MAX_DLEN or CANFD_MAX_DLEN, respectively 8 and 64 bytes*/
216                 for(i=0;i<maxdlen_;i++)
217                 {
218                         data_.push_back(frame.data[i]);
219                 };
220   
221         DEBUG(binder_interface, "convert_from_canfd_frame: Found id: %X, format: %X, length: %X, data %02X%02X%02X%02X%02X%02X%02X%02X", id_, format_, length_,
222                                                         data_[0], data_[1], data_[2], data_[3], data_[4], data_[5], data_[6], data_[7]);
223         }
224 }
225
226 /**
227 * @brief Take all initialized class's members and build an 
228 * canfd_frame struct that can be use to send a CAN message over
229 * the bus.
230 *
231 * @return canfd_frame struct built from class members.
232 */
233 canfd_frame can_message_t::convert_to_canfd_frame()
234 {
235         canfd_frame frame;
236
237         if(is_correct_to_send())
238         {
239                 frame.can_id = get_id();
240                 frame.len = get_length();
241                 ::memcpy(frame.data, get_data(), length_);
242         }
243         else
244                 ERROR(binder_interface, "can_message_t not correctly initialized to be sent");
245         
246         return frame;
247 }
248
249 /********************************************************************************
250 *
251 *               can_message_definition_t method implementation
252 *
253 *********************************************************************************/
254
255 can_message_definition_t::can_message_definition_t()
256   : last_value_(CAN_MESSAGE_SIZE)
257 {}
258
259 uint32_t get_id() const
260 {
261   return id_;
262 }
263 }