Reworking diagnostic manager to use BCM sockets.
[apps/low-level-can-service.git] / CAN-binder / low-can-binding / diagnostic / active-diagnostic-request.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 <map>
19 #include <fnmatch.h>
20
21 #include "active-diagnostic-request.hpp"
22
23 #include "../binding/configuration.hpp"
24
25 #define ERROR_PID 0xFF
26
27 std::string active_diagnostic_request_t::prefix_ = "diagnostic_messages";
28
29 bool active_diagnostic_request_t::operator==(const active_diagnostic_request_t& b)
30 {
31         return (bus_ == b.bus_ && id_ == b.id_ && handle_ == b.handle_);
32 }
33
34 active_diagnostic_request_t& active_diagnostic_request_t::operator=(const active_diagnostic_request_t& adr)
35 {
36         if (this != &adr)
37         {
38                 bus_ = adr.bus_;
39                 id_ = adr.id_;
40                 handle_ = adr.handle_;
41                 name_ = adr.name_;
42                 decoder_ = adr.decoder_;
43                 callback_ = adr.callback_;
44                 recurring_ = adr.recurring_; 
45                 wait_for_multiple_responses_ = adr.wait_for_multiple_responses_;
46                 in_flight_ = adr.in_flight_;
47                 frequency_clock_ = adr.frequency_clock_;
48                 timeout_clock_ = adr.timeout_clock_;
49         }
50         
51         return *this;
52 }
53
54 active_diagnostic_request_t::active_diagnostic_request_t()
55         : bus_{nullptr},
56           id_{0},
57           handle_{nullptr},
58           name_{""},
59           decoder_{nullptr},
60           callback_{nullptr},
61           recurring_{false},
62           wait_for_multiple_responses_{false},
63           in_flight_{false},
64           frequency_clock_{frequency_clock_t()},
65           timeout_clock_{frequency_clock_t()}
66 {}
67
68 active_diagnostic_request_t::active_diagnostic_request_t(const std::string& bus, DiagnosticRequest* request,
69                 const std::string& name,
70                 bool wait_for_multiple_responses,
71                 const DiagnosticResponseDecoder decoder,
72                 const DiagnosticResponseCallback callback,
73                 float frequencyHz)
74         : bus_{bus},
75           id_{request->arbitration_id},
76           handle_{nullptr},
77           name_{name},
78           decoder_{decoder},
79           callback_{callback},
80           recurring_{frequencyHz ? true : false},
81           wait_for_multiple_responses_{wait_for_multiple_responses},
82           in_flight_{false},
83           frequency_clock_{frequency_clock_t(frequencyHz)},
84           timeout_clock_{frequency_clock_t(10)}
85 {}
86
87 uint32_t active_diagnostic_request_t::get_id() const
88 {
89         return id_;
90 }
91
92 const std::shared_ptr<can_bus_dev_t> active_diagnostic_request_t::get_can_bus_dev() const
93 {
94         return can_bus_t::get_can_device(bus_);
95 }
96
97 uint16_t active_diagnostic_request_t::get_pid() const
98 {
99         if (handle_->request.has_pid)
100                 return handle_->request.pid;
101         return ERROR_PID;
102 }
103
104 DiagnosticRequestHandle* active_diagnostic_request_t::get_handle()
105 {
106         return handle_;
107 }
108
109 const std::string active_diagnostic_request_t::get_name() const
110 {
111         return name_;
112 }
113
114 std::string& active_diagnostic_request_t::get_prefix()
115 {
116         return active_diagnostic_request_t::prefix_;
117 }
118
119 DiagnosticResponseDecoder& active_diagnostic_request_t::get_decoder()
120 {
121         return decoder_;
122 }
123
124 DiagnosticResponseCallback& active_diagnostic_request_t::get_callback()
125 {
126         return callback_;
127 }
128
129 bool active_diagnostic_request_t::get_recurring() const
130 {
131         return recurring_;
132 }
133
134 bool active_diagnostic_request_t::get_in_flight() const
135 {
136         return in_flight_;
137 }
138
139 frequency_clock_t& active_diagnostic_request_t::get_frequency_clock()
140 {
141         return frequency_clock_;
142 }
143
144 frequency_clock_t& active_diagnostic_request_t::get_timeout_clock()
145 {
146         return timeout_clock_;
147 }
148
149 utils::socketcan_bcm_t& active_diagnostic_request_t::get_socket()
150 {
151         return socket_;
152 }
153
154 void active_diagnostic_request_t::set_handle(DiagnosticShims& shims, DiagnosticRequest* request)
155 {
156         handle_ = new DiagnosticRequestHandle(generate_diagnostic_request(&shims, request, nullptr));
157 }
158
159 void active_diagnostic_request_t::set_in_flight(bool val)
160 {
161         in_flight_ = val;
162 }
163
164 ///
165 /// @brief Check if requested signal name is a diagnostic message. If the name
166 ///  begin with the diagnostic message prefix then true else false.
167 ///
168 /// @param[in] name - A signal name.
169 ///
170 /// @return true if name began with the diagnostic message prefix else false.
171 ///
172 bool active_diagnostic_request_t::is_diagnostic_signal(const std::string& name)
173 {
174         const std::string p = active_diagnostic_request_t::prefix_ + "*";
175         if(::fnmatch(p.c_str(), name.c_str(), FNM_CASEFOLD) == 0)
176                 return true;
177         return false;
178 }
179
180 /// @brief Check is the request should be sent or not
181 ///
182 /// @return true if the request is not running or recurring nor completed,
183 /// or it's recurring, its clock elapsed
184 /// so it's time to send another one.
185 bool active_diagnostic_request_t::should_send()
186 {
187         return !in_flight_ && ( (!recurring_ && !request_completed()) ||
188                         (recurring_ && frequency_clock_.elapsed(true)) );
189 }
190
191 /// @brief check if the timeout clock has elapsed
192 ///
193 /// @return true if elapsed, so it is a timeout, else false.
194 bool active_diagnostic_request_t::timed_out()
195 {
196         // don't use staggered start with the timeout clock
197         return timeout_clock_.elapsed(false);
198 }
199
200 /// @brief Returns true if a sufficient response has been received for a
201 /// diagnostic request.
202 ///
203 /// This is true when at least one response has been received and the request is
204 /// configured to not wait for multiple responses. Functional broadcast requests
205 /// may often wish to wait the full 100ms for modules to respond.
206 bool active_diagnostic_request_t::response_received() const
207 {
208         return !wait_for_multiple_responses_ &&
209                                 handle_->completed;
210 }
211
212 /// @brief Returns true if the request has timed out waiting for a response,
213 /// or a sufficient number of responses has been received.
214 bool active_diagnostic_request_t::request_completed()
215 {
216         return response_received() || 
217                 (timed_out() && diagnostic_request_sent(handle_));
218 }