Diag-Client-Lib
doip_vehicle_identification_handler.cpp
Go to the documentation of this file.
1 /* Diagnostic Client library
2 * Copyright (C) 2024 Avijit Dey
3 *
4 * This Source Code Form is subject to the terms of the Mozilla Public
5 * License, v. 2.0. If a copy of the MPL was not distributed with this
6 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
7 */
8 
10 
13 #include "common/logger.h"
14 #include "utility/state.h"
15 #include "utility/sync_timer.h"
16 
17 namespace doip_client {
18 namespace channel {
19 namespace udp_channel {
20 namespace {
21 
25 using VehiclePayloadType = std::pair<std::uint16_t, std::uint8_t>;
26 
30 enum class VehicleIdentificationState : std::uint8_t {
31  kIdle = 0U,
35 };
36 
40 class kIdle final : public utility::state::State<VehicleIdentificationState> {
41  public:
47  explicit kIdle(VehicleIdentificationState state) : State<VehicleIdentificationState>(state) {}
48 
52  void Start() override {}
53 
57  void Stop() override {}
58 };
59 
63 class kSendVehicleIdentificationReq final : public utility::state::State<VehicleIdentificationState> {
64  public:
71 
75  void Start() override {}
76 
80  void Stop() override {}
81 };
82 
86 class kWaitForVehicleIdentificationRes final : public utility::state::State<VehicleIdentificationState> {
87  public:
94  : State<VehicleIdentificationState>(state) {}
95 
99  void Start() override {}
100 
104  void Stop() override {}
105 };
106 
110 class kDoIPCtrlTimeout final : public utility::state::State<VehicleIdentificationState> {
111  public:
118 
122  void Start() override {}
123 
127  void Stop() override {}
128 };
129 
133 void CreateDoipGenericHeader(std::vector<std::uint8_t> &doip_header_buffer, std::uint16_t payload_type,
134  std::uint32_t payload_len) {
135  doip_header_buffer.emplace_back(kDoip_ProtocolVersion);
136  doip_header_buffer.emplace_back(~(static_cast<std::uint8_t>(kDoip_ProtocolVersion)));
137  doip_header_buffer.emplace_back(static_cast<std::uint8_t>((payload_type & 0xFF00) >> 8));
138  doip_header_buffer.emplace_back(static_cast<std::uint8_t>(payload_type & 0x00FF));
139  doip_header_buffer.emplace_back(static_cast<std::uint8_t>((payload_len & 0xFF000000) >> 24));
140  doip_header_buffer.emplace_back(static_cast<std::uint8_t>((payload_len & 0x00FF0000) >> 16));
141  doip_header_buffer.emplace_back(static_cast<std::uint8_t>((payload_len & 0x0000FF00) >> 8));
142  doip_header_buffer.emplace_back(static_cast<std::uint8_t>(payload_len & 0x000000FF));
143 }
144 
151 auto GetVehicleIdentificationPayloadType(std::uint8_t preselection_mode) noexcept -> VehiclePayloadType {
152  std::uint16_t vehicle_identification_type{0u};
153  std::uint8_t vehicle_identification_length{0u};
154  switch (preselection_mode) {
155  case 0U:
156  vehicle_identification_type = kDoip_VehicleIdentification_ReqType;
157  vehicle_identification_length = kDoip_VehicleIdentification_ReqLen;
158  break;
159  case 1U:
160  vehicle_identification_type = kDoip_VehicleIdentificationVIN_ReqType;
161  vehicle_identification_length = kDoip_VehicleIdentificationVIN_ReqLen;
162  break;
163  case 2U:
164  vehicle_identification_type = kDoip_VehicleIdentificationEID_ReqType;
165  vehicle_identification_length = kDoip_VehicleIdentificationEID_ReqLen;
166  break;
167  default:
168  break;
169  }
170  return VehiclePayloadType{vehicle_identification_type, vehicle_identification_length};
171 }
172 
173 } // namespace
174 
179  public:
184 
189 
196  : udp_socket_handler_{udp_socket_handler},
197  channel_{channel},
198  state_context_{} {
199  // create and add state for vehicle identification
200  // kIdle
201  state_context_.AddState(VehicleIdentificationState::kIdle,
202  std::make_unique<kIdle>(VehicleIdentificationState::kIdle));
203  // kSendVehicleIdentificationReq
205  VehicleIdentificationState::kSendVehicleIdentificationReq,
206  std::make_unique<kSendVehicleIdentificationReq>(VehicleIdentificationState::kSendVehicleIdentificationReq));
207  // kWaitForVehicleIdentificationRes
208  state_context_.AddState(VehicleIdentificationState::kWaitForVehicleIdentificationRes,
209  std::make_unique<kWaitForVehicleIdentificationRes>(
210  VehicleIdentificationState::kWaitForVehicleIdentificationRes));
211  // kDoIPCtrlTimeout
212  state_context_.AddState(VehicleIdentificationState::kDoIPCtrlTimeout,
213  std::make_unique<kDoIPCtrlTimeout>(VehicleIdentificationState::kDoIPCtrlTimeout));
214  // Transit to idle state
215  state_context_.TransitionTo(VehicleIdentificationState::kIdle);
216  }
217 
223 
228  auto GetSocketHandler() noexcept -> sockets::UdpSocketHandler & { return udp_socket_handler_; }
229 
234  auto GetDoipChannel() noexcept -> DoipUdpChannel & { return channel_; }
235 
240  auto GetSyncTimer() noexcept -> SyncTimer & { return sync_timer_; }
241 
242  private:
247 
252 
257 
262 };
263 
265  DoipUdpChannel &channel)
266  : handler_impl_{std::make_unique<VehicleIdentificationHandlerImpl>(udp_socket_handler, channel)} {}
267 
269 
271  uds_transport::UdsMessageConstPtr vehicle_identification_request) noexcept
275  if (handler_impl_->GetStateContext().GetActiveState().GetState() == VehicleIdentificationState::kIdle) {
276  // change state before sending if SendVehicleIdentificationRequest call takes more time to return and in the
277  // same time async reception starts
278  handler_impl_->GetStateContext().TransitionTo(VehicleIdentificationState::kWaitForVehicleIdentificationRes);
279  if (SendVehicleIdentificationRequest(std::move(vehicle_identification_request)) ==
282  // Wait for 2 sec to collect all the vehicle identification response
283  handler_impl_->GetSyncTimer().WaitForTimeout(
284  [&]() {
285  handler_impl_->GetStateContext().TransitionTo(VehicleIdentificationState::kDoIPCtrlTimeout);
286  // Todo: Send data to upper layer here
287  },
288  [&]() {
289  // no cancellation
290  },
291  std::chrono::milliseconds{kDoIPCtrl});
292  handler_impl_->GetStateContext().TransitionTo(VehicleIdentificationState::kIdle);
293  } else {
294  // failed, do nothing
295  handler_impl_->GetStateContext().TransitionTo(VehicleIdentificationState::kIdle);
296  logger::DoipClientLogger::GetDiagClientLogger().GetLogger().LogError(
297  __FILE__, __LINE__, "",
298  [](std::stringstream &msg) { msg << "Vehicle Identification request transmission Failed"; });
299  }
300  } else {
301  // not free, state already in idle state
302  }
303  return ret_val;
304 }
305 
307  if (handler_impl_->GetStateContext().GetActiveState().GetState() ==
308  VehicleIdentificationState::kWaitForVehicleIdentificationRes) {
309  // Deserialize data to indicate to upper layer
310  std::pair<uds_transport::UdsTransportProtocolMgr::IndicationResult, uds_transport::UdsMessagePtr> ret_val{
311  handler_impl_->GetDoipChannel().IndicateMessage(
313  uds_transport::UdsMessage::TargetAddressType::kPhysical, 0U, doip_payload.GetPayload().size(), 0U,
314  "DoIPUdp", doip_payload.GetPayload())};
316  (ret_val.second != nullptr)) {
317  // Add meta info about ip address
319  {"kRemoteIpAddress", std::string{doip_payload.GetHostIpAddress()}}};
320  ret_val.second->AddMetaInfo(std::make_shared<uds_transport::UdsMessage::MetaInfoMap>(meta_info_map));
321  // copy to application buffer
322  (void) std::copy(doip_payload.GetPayload().begin(), doip_payload.GetPayload().end(),
323  ret_val.second->GetPayload().begin());
324  handler_impl_->GetDoipChannel().HandleMessage(std::move(ret_val.second));
325  }
326  } else {
327  // ignore
328  }
329 }
330 
332  uds_transport::UdsMessageConstPtr vehicle_identification_request) noexcept
336  UdpMessagePtr doip_vehicle_identification_req{std::make_unique<UdpMessage>(
337  vehicle_identification_request->GetHostIpAddress(), vehicle_identification_request->GetHostPortNumber())};
338 
339  // Get preselection mode
340  std::uint8_t preselection_mode{vehicle_identification_request->GetPayload()[BYTE_POS_ONE]};
341  // Get the payload type & length from preselection mode
342  VehiclePayloadType const doip_vehicle_payload_type{GetVehicleIdentificationPayloadType(preselection_mode)};
343 
344  // create header
345  CreateDoipGenericHeader(doip_vehicle_identification_req->GetTxBuffer(), doip_vehicle_payload_type.first,
346  doip_vehicle_payload_type.second);
347  // Copy only if containing VIN / EID
348  if (doip_vehicle_payload_type.first != kDoip_VehicleIdentification_ReqType) {
349  doip_vehicle_identification_req->GetTxBuffer().insert(
350  doip_vehicle_identification_req->GetTxBuffer().begin() + kDoipheadrSize,
351  vehicle_identification_request->GetPayload().begin() + 2U, vehicle_identification_request->GetPayload().end());
352  }
353  if (handler_impl_->GetSocketHandler().Transmit(std::move(doip_vehicle_identification_req))) {
355  }
356  return ret_val;
357 }
358 
359 } // namespace udp_channel
360 } // namespace channel
361 } // namespace doip_client
Immutable class to store received doip message.
Definition: doip_message.h:21
Class to manage a udp channel as per DoIP protocol.
VehicleIdentificationHandlerImpl(sockets::UdpSocketHandler &udp_socket_handler, DoipUdpChannel &channel)
Constructs an instance of VehicleDiscoveryHandlerImpl.
auto GetStateContext() noexcept -> VehicleIdentificationStateContext &
Function to get the Vehicle Identification State context.
auto GetSocketHandler() noexcept -> sockets::UdpSocketHandler &
Function to get the socket handler.
auto SendVehicleIdentificationRequest(uds_transport::UdsMessageConstPtr vehicle_identification_request) noexcept -> uds_transport::UdsTransportProtocolMgr::TransmissionResult
Function to send vehicle identification request.
~VehicleIdentificationHandler()
Destruct an instance of VehicleIdentificationHandler.
auto HandleVehicleIdentificationRequest(uds_transport::UdsMessageConstPtr vehicle_identification_request) noexcept -> uds_transport::UdsTransportProtocolMgr::TransmissionResult
Function to handle sending of vehicle identification request.
void ProcessVehicleIdentificationResponse(DoipMessage &doip_payload) noexcept
Function to process received vehicle identification response.
VehicleIdentificationHandler(sockets::UdpSocketHandler &udp_socket_handler, DoipUdpChannel &channel)
Constructs an instance of VehicleIdentificationHandler.
sockets::UdpSocketHandler::UdpMessagePtr UdpMessagePtr
Type alias for Tcp message pointer.
kWaitForVehicleIdentificationRes(VehicleIdentificationState state)
Constructs an instance of kWaitForVehicleIdentificationRes.
static auto GetDiagClientLogger() noexcept -> DoipClientLogger &
Definition: logger.h:20
Class used to create a udp socket for handling transmission and reception of udp message from driver.
std::map< std::string, std::string > MetaInfoMap
Definition: uds_message.h:28
void TransitionTo(EnumState state)
Definition: state.h:69
void AddState(EnumState state, std::unique_ptr< State< EnumState >> state_ptr)
Definition: state.h:58
constexpr uint8_t BYTE_POS_ONE
Definition: common_header.h:32
std::pair< std::uint16_t, std::uint8_t > VehiclePayloadType
Type alias of vehicle payload type.
void CreateDoipGenericHeader(std::vector< std::uint8_t > &doip_header_buffer, std::uint16_t payload_type, std::uint32_t payload_len)
Create the doip generic header.
auto GetVehicleIdentificationPayloadType(std::uint8_t preselection_mode) noexcept -> VehiclePayloadType
Get the vehicle identification payload type based on preselection mode.
constexpr std::uint8_t kDoipheadrSize
constexpr std::uint16_t kDoip_VehicleIdentification_ReqType
constexpr std::uint32_t kDoIPCtrl
constexpr std::uint32_t kDoip_VehicleIdentification_ReqLen
constexpr std::uint8_t kDoip_ProtocolVersion
constexpr std::uint32_t kDoip_VehicleIdentificationVIN_ReqLen
constexpr std::uint16_t kDoip_VehicleIdentificationVIN_ReqType
constexpr std::uint32_t kDoip_VehicleIdentificationEID_ReqLen
constexpr std::uint16_t kDoip_VehicleIdentificationEID_ReqType
std::unique_ptr< const UdsMessage > UdsMessageConstPtr
Definition: uds_message.h:69