From d952c0f8dd36acf9a072603237975b7ff2e915de Mon Sep 17 00:00:00 2001 From: Romain Forlot Date: Thu, 16 Mar 2017 13:14:02 +0100 Subject: Adding missing doxygen comments. Made some cleaning about unused things or obsolete. Review existing comments, adding missing comments. Reformat some long long constructor. Change-Id: Ibae247d1295a7a85b49d0ecee473022755d42b8b Signed-off-by: Romain Forlot --- src/can/can-message-definition.cpp | 28 +++- src/can/can-message.cpp | 16 +- src/configuration-generated.cpp | 5 +- src/configuration.cpp | 50 ++---- src/configuration.hpp | 17 +- src/diagnostic/active-diagnostic-request.cpp | 22 ++- src/diagnostic/active-diagnostic-request.hpp | 95 ++++++----- src/diagnostic/diagnostic-manager.cpp | 238 +++++++++++++++++++++------ src/diagnostic/diagnostic-manager.hpp | 9 +- src/diagnostic/diagnostic-message.cpp | 8 +- src/diagnostic/diagnostic-message.hpp | 2 +- src/low-can-binding.cpp | 4 +- 12 files changed, 332 insertions(+), 162 deletions(-) diff --git a/src/can/can-message-definition.cpp b/src/can/can-message-definition.cpp index fb7efce..206d0b0 100644 --- a/src/can/can-message-definition.cpp +++ b/src/can/can-message-definition.cpp @@ -21,12 +21,32 @@ can_message_definition_t::can_message_definition_t(std::uint8_t message_set_id, : message_set_id_{message_set_id}, bus_{bus}, last_value_{CAN_MESSAGE_SIZE} {} -can_message_definition_t::can_message_definition_t(std::uint8_t message_set_id, const std::string bus, uint32_t id, frequency_clock_t frequency_clock, bool force_send_changed) - : message_set_id_{message_set_id}, bus_{bus}, id_{id}, frequency_clock_{frequency_clock}, force_send_changed_{force_send_changed}, last_value_{CAN_MESSAGE_SIZE} +can_message_definition_t::can_message_definition_t(std::uint8_t message_set_id, + const std::string bus, + uint32_t id, + frequency_clock_t frequency_clock, + bool force_send_changed) + : message_set_id_{message_set_id}, + bus_{bus}, + id_{id}, + frequency_clock_{frequency_clock}, + force_send_changed_{force_send_changed}, + last_value_{CAN_MESSAGE_SIZE} {} -can_message_definition_t::can_message_definition_t(std::uint8_t message_set_id, const std::string bus, uint32_t id, can_message_format_t format, frequency_clock_t frequency_clock, bool force_send_changed) - : message_set_id_{message_set_id}, bus_{bus}, id_{id}, format_{format}, frequency_clock_{frequency_clock}, force_send_changed_{force_send_changed}, last_value_{CAN_MESSAGE_SIZE} +can_message_definition_t::can_message_definition_t(std::uint8_t message_set_id, + const std::string bus, + uint32_t id, + can_message_format_t format, + frequency_clock_t frequency_clock, + bool force_send_changed) + : message_set_id_{message_set_id}, + bus_{bus}, + id_{id}, + format_{format}, + frequency_clock_{frequency_clock}, + force_send_changed_{force_send_changed}, + last_value_{CAN_MESSAGE_SIZE} {} uint32_t can_message_definition_t::get_id() const diff --git a/src/can/can-message.cpp b/src/can/can-message.cpp index 6b40d91..5d8c9cb 100644 --- a/src/can/can-message.cpp +++ b/src/can/can-message.cpp @@ -30,8 +30,20 @@ can_message_t::can_message_t() : maxdlen_{0}, id_{0}, length_{0}, format_{can_message_format_t::ERROR}, rtr_flag_{false}, flags_{0} {} -can_message_t::can_message_t(uint8_t maxdlen, uint32_t id, uint8_t length, can_message_format_t format, bool rtr_flag, uint8_t flags, std::vector data) - : maxdlen_{maxdlen}, id_{id}, length_{length}, format_{format}, rtr_flag_{rtr_flag}, flags_{flags}, data_{data} +can_message_t::can_message_t(uint8_t maxdlen, + uint32_t id, + uint8_t length, + can_message_format_t format, + bool rtr_flag, + uint8_t flags, + std::vector data) + : maxdlen_{maxdlen}, + id_{id}, + length_{length}, + format_{format}, + rtr_flag_{rtr_flag}, + flags_{flags}, + data_{data} {} /** diff --git a/src/configuration-generated.cpp b/src/configuration-generated.cpp index a2e8d2c..dbbd9b0 100644 --- a/src/configuration-generated.cpp +++ b/src/configuration-generated.cpp @@ -167,4 +167,7 @@ configuration_t::configuration_t() { } - +const std::string configuration_t::get_diagnostic_bus() const +{ + return "vcan0"; +} diff --git a/src/configuration.cpp b/src/configuration.cpp index 8a2df90..184d468 100644 --- a/src/configuration.cpp +++ b/src/configuration.cpp @@ -19,24 +19,13 @@ #include "utils/signals.hpp" -// Dumb signals and message implementation. To get compile. -/*std::vector CAN_MESSAGE_SET; - -std::vector> CAN_MESSAGES_DEFINITION; - -std::vector> SIGNALS;*/ - +/// @brief Return singleton instance of configuration object. configuration_t& configuration_t::instance() { static configuration_t config; return config; } -configuration_t& configuration_t::get_configuration() -{ - return *this; -} - can_bus_t& configuration_t::get_can_bus_manager() { return can_bus_manager_; @@ -72,11 +61,6 @@ std::vector& configuration_t::get_diagnostic_messages() return diagnostic_messages_[active_message_set_]; } -const std::vector& configuration_t::get_signals_prefix() const -{ - return signals_prefix_; -} - const std::vector& configuration_t::get_can_message_definition() { return can_message_definition_[active_message_set_]; @@ -102,15 +86,12 @@ void configuration_t::set_active_message_set(uint8_t id) active_message_set_ = id; } -/** - * @fn std::vector find_can_signals(const openxc_DynamicField &key) - * @brief return signals name found searching through CAN_signals and OBD2 pid - * - * @param[in] key - can contain numeric or string value in order to search against - * can signals or obd2 signals name. - * - * @return Vector of signals name found. - */ +/// @brief return diagnostic messages name found searching through diagnostic messages list. +/// +/// @param[in] key - can contain numeric or string value in order to search against +/// can signals or obd2 signals name. +/// @param[out] found_signals - Vector of signals name found. +/// void configuration_t::find_diagnostic_messages(const openxc_DynamicField &key, std::vector& found_signals) { switch(key.type) @@ -128,15 +109,12 @@ void configuration_t::find_diagnostic_messages(const openxc_DynamicField &key, s DEBUG(binder_interface, "find_diagnostic_messages: Found %d signal(s)", (int)found_signals.size()); } -/** - * @fn void find_can_signals(const openxc_DynamicField& key, std::vector& found_signals) - * @brief return signals name found searching through CAN_signals and OBD2 pid - * - * @param[in] key - can contain numeric or string value in order to search against - * can signals or obd2 signals name. - * @param[out] found_signals - provided vector to fill with ponter to signals matched. - * - */ +/// @brief return signals name found searching through CAN signals list. +/// +/// @param[in] key - can contain numeric or string value in order to search against +/// can signals or obd2 signals name. +/// @param[out] found_signals - provided vector to fill with pointer to matched signals. +/// void configuration_t::find_can_signals(const openxc_DynamicField& key, std::vector& found_signals) { switch(key.type) @@ -152,4 +130,4 @@ void configuration_t::find_can_signals(const openxc_DynamicField& key, std::vect break; } DEBUG(binder_interface, "find_can_signals: Found %d signal(s)", (int)found_signals.size()); -} \ No newline at end of file +} diff --git a/src/configuration.hpp b/src/configuration.hpp index fb7b840..2112ee9 100644 --- a/src/configuration.hpp +++ b/src/configuration.hpp @@ -41,24 +41,23 @@ class configuration_t { private: - can_bus_t can_bus_manager_ = can_bus_t(afb_daemon_rootdir_open_locale(binder_interface->daemon, "etc/can_buses.json", O_RDONLY, NULL)); - diagnostic_manager_t diagnostic_manager_; - uint8_t active_message_set_ = 0; - std::vector signals_prefix_; + can_bus_t can_bus_manager_ = can_bus_t( + afb_daemon_rootdir_open_locale( + binder_interface->daemon, "etc/can_buses.json", O_RDONLY, NULL)); ///< instanciate the CAN bus + ///< This will read the configuration file and initialize all CAN devices specified in it. + diagnostic_manager_t diagnostic_manager_; ///< Diagnostic manager use to manage diagnostic message communication. + uint8_t active_message_set_ = 0; ///< Which is the active message set ? Default to 0. std::vector can_message_set_; std::vector> can_message_definition_; std::vector> can_signals_; std::vector> diagnostic_messages_; - /// Private constructor with implementation generated by the AGL generator. - configuration_t(); + configuration_t(); ///< Private constructor with implementation generated by the AGL generator. public: static configuration_t& instance(); - configuration_t& get_configuration() ; - can_bus_t& get_can_bus_manager(); const std::map>& get_can_bus_devices(); @@ -114,5 +113,3 @@ class configuration_t */ }; -// TEMP Function to access OBD2_PIDS vector -std::vector get_predefined_obd2(); diff --git a/src/diagnostic/active-diagnostic-request.cpp b/src/diagnostic/active-diagnostic-request.cpp index a21f730..8cb047d 100644 --- a/src/diagnostic/active-diagnostic-request.cpp +++ b/src/diagnostic/active-diagnostic-request.cpp @@ -24,6 +24,7 @@ #define ERROR_PID 0xFF +// @brief std::string active_diagnostic_request_t::prefix_ = "diagnostic_messages"; bool active_diagnostic_request_t::operator==(const active_diagnostic_request_t& b) @@ -137,11 +138,14 @@ void active_diagnostic_request_t::set_in_flight(bool val) in_flight_ = val; } -/** -* @brief Check if requested signal name is an obd2 pid -* -* @return true if name began with obd2 else false. -*/ +/// +/// @brief Check if requested signal name is a diagnostic message. If the name +/// begin with the diagnostic message prefix then true else false. +/// +/// @param[in] name - A signal name. +/// +/// @return true if name began with the diagnostic message prefix else false. +/// bool active_diagnostic_request_t::is_diagnostic_signal(const std::string& name) { const std::string p = active_diagnostic_request_t::prefix_ + "*"; @@ -150,6 +154,11 @@ bool active_diagnostic_request_t::is_diagnostic_signal(const std::string& name) return false; } +/// @brief Check is the request should be sent or not +/// +/// @return true if the request isn't already running and not +/// recurring nor completed, or it is recurring its clock elapsed so it's +/// time to send another one. bool active_diagnostic_request_t::should_send() { return !get_in_flight() && ( @@ -157,6 +166,9 @@ bool active_diagnostic_request_t::should_send() (get_recurring() && get_frequency_clock().elapsed(true))); } +/// @brief check if the timeout clock has elapsed +/// +/// @return true if elapsed, so it is a timeout, else false. bool active_diagnostic_request_t::timed_out() { // don't use staggered start with the timeout clock diff --git a/src/diagnostic/active-diagnostic-request.hpp b/src/diagnostic/active-diagnostic-request.hpp index cb9b1d0..22bf850 100644 --- a/src/diagnostic/active-diagnostic-request.hpp +++ b/src/diagnostic/active-diagnostic-request.hpp @@ -29,56 +29,63 @@ class active_diagnostic_request_t; class diagnostic_manager_t; -/* Public: The signature for an optional function that can apply the neccessary - * formula to translate the binary payload into meaningful data. - * - * response - the received DiagnosticResponse (the data is in response.payload, - * a byte array). This is most often used when the byte order is - * signiticant, i.e. with many OBD-II PID formulas. - * parsed_payload - the entire payload of the response parsed as an int. - */ +/// @brief The signature for an optional function that can apply the neccessary +/// formula to translate the binary payload into meaningful data. +/// +/// @param[in] response - the received DiagnosticResponse (the data is in response.payload, +/// a byte array). This is most often used when the byte order is signiticant, i.e. with many OBD-II PID formulas. +/// @param[in] parsed_payload - the entire payload of the response parsed as an int. +/// +/// @return float value after decoding. +/// typedef float (*DiagnosticResponseDecoder)(const DiagnosticResponse* response, float parsed_payload); -/* Public: The signature for an optional function to handle a new diagnostic - * response. - * - * manager - The DiagnosticsManager providing this response. - * request - The original diagnostic request. - * response - The response object that was just received. - * parsed_payload - The payload of the response, parsed as a float. - */ +/// @brief: The signature for an optional function to handle a new diagnostic +/// response. +/// +/// @param[in] request - The original diagnostic request. +/// @param[in] response - The response object that was just received. +/// @param[in] parsed_payload - The payload of the response, parsed as a float. +/// typedef void (*DiagnosticResponseCallback)(const active_diagnostic_request_t* request, const DiagnosticResponse* response, float parsed_payload); -/** - * @brief An active diagnostic request, either recurring or one-time. - */ +/// +/// @brief An active diagnostic request, either recurring or one-time. +/// +/// @desc Will host a diagnostic_message_t class members to describe an on going +/// diagnostic request on the CAN bus. Diagnostic message will be converted to +/// a DiagnosticRequest using ad-hoc method build_diagnostic_request from diagnostic message. +/// Then missing member, that can not be hosted into a DiagnosticRequest struct, will be passed +/// as argument when adding the request to (non)-recurrent vector. Argument will be used to instanciate +/// an active_diagnostic_request_t object before sending it. +/// class active_diagnostic_request_t { private: - std::string bus_; /*!< bus_ - The CAN bus this request should be made on, or is currently in flight-on*/ - uint32_t id_; /*!< id_ - The arbitration ID (aka message ID) for the request.*/ - DiagnosticRequestHandle* handle_; /*!< handle_ - A handle for the request to keep track of it between - * sending the frames of the request and receiving all frames of the response.*/ - std::string name_; /*!< name_ - An optional human readable name this response, to be used when publishing received - * responses. If the name is NULL, the published output will use the raw OBD-II response format.*/ - static std::string prefix_; /*!< prefix_ - generic_name_ will be prefixed with it. It has to reflect the used protocol. - * which make easier to sort message when the come in.*/ - DiagnosticResponseDecoder decoder_; /*!< decoder_ - An optional DiagnosticResponseDecoder to parse the payload of responses - * to this request. If the decoder is NULL, the output will include the raw payload - * instead of a parsed value.*/ - DiagnosticResponseCallback callback_; /*!< callback_ - An optional DiagnosticResponseCallback to be notified whenever a - * response is received for this request.*/ - bool recurring_; /*!< bool recurring_ - If true, this is a recurring request and it will remain as active until explicitly cancelled. - * The frequencyClock attribute controls how often a recurrin request is made.*/ - bool wait_for_multiple_responses_; /*!< wait_for_multiple_responses_ - False by default, when any response is received for a request - * it will be removed from the active list. If true, the request will remain active until the timeout - * clock expires, to allow it to receive multiple response (e.g. to a functional broadcast request).*/ - bool in_flight_; /*!< in_flight_ - True if the request has been sent and we are waiting for a response.*/ - frequency_clock_t frequency_clock_; /*!< frequency_clock_ - A frequency_clock_t object to control the send rate for a - * recurring request. If the request is not reecurring, this attribute is not used.*/ - frequency_clock_t timeout_clock_; /*!< timeout_clock_ - A frequency_clock_t object to monitor how long it's been since - * this request was sent.*/ + std::string bus_; ///< bus_ - The CAN bus this request should be made on, or is currently in flight-on + uint32_t id_; ///< id_ - The arbitration ID (aka message ID) for the request. + DiagnosticRequestHandle* handle_; ///< handle_ - A handle for the request to keep track of it between + ///< sending the frames of the request and receiving all frames of the response. + std::string name_; ///< name_ - Human readable name, to be used when publishing received responses. + ///< TODO: If the name is NULL, the published output will use the raw OBD-II response format. + static std::string prefix_; ///< prefix_ - It has to reflect the JSON object which it comes from. It makes easier sorting + ///< incoming CAN messages. + DiagnosticResponseDecoder decoder_; ///< decoder_ - An optional DiagnosticResponseDecoder to parse the payload of responses + ///< to this request. If the decoder is NULL, the output will include the raw payload + ///< instead of a parsed value. + DiagnosticResponseCallback callback_; ///< callback_ - An optional DiagnosticResponseCallback to be notified whenever a + ///< response is received for this request. + bool recurring_; ///< bool recurring_ - If true, this is a recurring request and it will remain as active until explicitly cancelled. + ///< The frequencyClock attribute controls how often a recurrin request is made. + bool wait_for_multiple_responses_; ///< wait_for_multiple_responses_ - False by default, when any response is received for a request + ///< it will be removed from the active list. If true, the request will remain active until the timeout + ///< clock expires, to allow it to receive multiple response (e.g. to a functional broadcast request). + bool in_flight_; ///< in_flight_ - True if the request has been sent and we are waiting for a response. + frequency_clock_t frequency_clock_; ///< frequency_clock_ - A frequency_clock_t object to control the send rate for a + ///< recurring request. If the request is not reecurring, this attribute is not used. + frequency_clock_t timeout_clock_; ///< timeout_clock_ - A frequency_clock_t object to monitor how long it's been since + ///< this request was sent. public: bool operator==(const active_diagnostic_request_t& b); active_diagnostic_request_t& operator=(const active_diagnostic_request_t& adr); @@ -89,7 +96,7 @@ public: const std::string& name, bool wait_for_multiple_responses, const DiagnosticResponseDecoder decoder, const DiagnosticResponseCallback callback, float frequencyHz); - + uint32_t get_id() const; const std::shared_ptr get_can_bus_dev() const; DiagnosticRequestHandle* get_handle(); @@ -102,7 +109,7 @@ public: bool get_in_flight() const; frequency_clock_t& get_frequency_clock(); frequency_clock_t& get_timeout_clock(); - + void set_handle(DiagnosticShims& shims, DiagnosticRequest* request); void set_in_flight(bool val); diff --git a/src/diagnostic/diagnostic-manager.cpp b/src/diagnostic/diagnostic-manager.cpp index 2c0a4d9..7ff8644 100644 --- a/src/diagnostic/diagnostic-manager.cpp +++ b/src/diagnostic/diagnostic-manager.cpp @@ -33,9 +33,16 @@ diagnostic_manager_t::diagnostic_manager_t() : initialized_{false} {} +/// @brief Diagnostic manager isn't initialized at launch but after +/// CAN bus devices initialization. For the moment, it is only possible +/// to have 1 diagnostic bus which are the first bus declared in the JSON +/// description file. Configuration instance will return it. +/// +/// @desc this will initialize DiagnosticShims and cancel all active requests +/// if there are any. bool diagnostic_manager_t::initialize() { - // Mandatory to set the bus before intiliaze shims. + // Mandatory to set the bus before intialize shims. bus_ = configuration_t::instance().get_diagnostic_bus(); init_diagnostic_shims(); @@ -46,27 +53,78 @@ bool diagnostic_manager_t::initialize() return initialized_; } -/** - * @brief initialize shims used by UDS lib and set initialized_ to true. - * It is needed before used the diagnostic manager fully because shims are - * required by most member functions. - */ +/// @brief initialize shims used by UDS lib and set initialized_ to true. +/// It is needed before used the diagnostic manager fully because shims are +/// required by most member functions. void diagnostic_manager_t::init_diagnostic_shims() { shims_ = diagnostic_init_shims(shims_logger, shims_send, NULL); DEBUG(binder_interface, "init_diagnostic_shims: Shims initialized"); } +/// @brief Force cleanup all active requests. void diagnostic_manager_t::reset() { - if(initialized_) - { - DEBUG(binder_interface, "Clearing existing diagnostic requests"); - cleanup_active_requests(true); - } + DEBUG(binder_interface, "Clearing existing diagnostic requests"); + cleanup_active_requests(true); } +/// @brief send function use by diagnostic library. Only one bus used for now +/// so diagnostic request is sent using the default diagnostic bus not matter of +/// which is specified in the diagnostic message definition. +/// +/// @param[in] arbitration_id - CAN arbitration ID to use when send message. OBD2 broadcast ID +/// is 0x7DF by example. +/// @param[in] data - The data payload for the message. NULL is valid if size is also 0. +/// @param[in] size - The size of the data payload, in bytes. +/// +/// @return true if the CAN message was sent successfully. +bool diagnostic_manager_t::shims_send(const uint32_t arbitration_id, const uint8_t* data, const uint8_t size) +{ + std::shared_ptr can_bus_dev = can_bus_t::get_can_device(configuration_t::instance().get_diagnostic_manager().bus_); + return can_bus_dev->shims_send(arbitration_id, data, size); +} +/// @brief The type signature for an optional logging function, if the user +/// wishes to provide one. It should print, store or otherwise display the +/// message. +/// +/// message - A format string to log using the given parameters. +/// ... (vargs) - the parameters for the format string. +/// +void diagnostic_manager_t::shims_logger(const char* format, ...) +{ + va_list args; + va_start(args, format); + + char buffer[256]; + vsnprintf(buffer, 256, format, args); + + DEBUG(binder_interface, "shims_logger: %s", buffer); +} + +/// @brief The type signature for a... OpenXC TODO: not used yet. +void diagnostic_manager_t::shims_timer() +{} + +std::shared_ptr diagnostic_manager_t::get_can_bus_dev() +{ + return can_bus_t::get_can_device(bus_); +} + +/// @brief Return diagnostic manager shims member. +DiagnosticShims& diagnostic_manager_t::get_shims() +{ + return shims_; +} + +/// @brief Search for a specific active diagnostic request in the provided requests list +/// and erase it from the vector. This is useful at unsubscription to clean up the list otherwize +/// all received CAN messages will be passed to DiagnosticRequestHandle of all active diagnostic request +/// contained in the vector but no event if connected to, so we will decode uneeded request. +/// +/// @param[in] entry - a pointer of an active_diagnostic_request instance to clean up +/// @param[in] requests_list - a vector where to make the search and cleaning. void diagnostic_manager_t::find_and_erase(active_diagnostic_request_t* entry, std::vector& requests_list) { auto i = std::find(requests_list.begin(), requests_list.end(), entry); @@ -74,8 +132,7 @@ void diagnostic_manager_t::find_and_erase(active_diagnostic_request_t* entry, st requests_list.erase(i); } -/// Move the entry to the free list and decrement the lock count for any -/// CAN filters it used. +// @brief TODO: implement cancel_request if needed... Don't know. void diagnostic_manager_t::cancel_request(active_diagnostic_request_t* entry) { @@ -97,6 +154,12 @@ void diagnostic_manager_t::cancel_request(active_diagnostic_request_t* entry) }*/ } +/// @brief Cleanup a specific request if it isn't running and get complete. As it is almost +/// impossible to get that state for a recurring request without waiting for that, you can +/// force the cleaning operation. +/// +/// @param[in] entry - the request to clean +/// @param[in] force - Force the cleaning or not ? void diagnostic_manager_t::cleanup_request(active_diagnostic_request_t* entry, bool force) { if(force || (entry->get_in_flight() && entry->request_completed())) @@ -122,7 +185,10 @@ void diagnostic_manager_t::cleanup_request(active_diagnostic_request_t* entry, b } } -/// @brief Clean up the request list +/// @brief Clean up all requests lists, recurring and not recurring. +/// +/// @param[in] force - Force the cleaning or not ? If true, that will do +/// the same effect as a call to reset(). void diagnostic_manager_t::cleanup_active_requests(bool force) { for(auto& entry : non_recurring_requests_) @@ -134,8 +200,11 @@ void diagnostic_manager_t::cleanup_active_requests(bool force) cleanup_request(entry, force); } -/// @brief Will return the active_diagnostic_request_t pointer of found request or nullptr if +/// @brief Will return the active_diagnostic_request_t pointer for theDiagnosticRequest or nullptr if /// not found. +/// +/// @param[in] request - Search key, method will go through recurring list to see if it find that request +/// holded by the DiagnosticHandle member. active_diagnostic_request_t* diagnostic_manager_t::find_recurring_request(const DiagnosticRequest* request) { for (auto& entry : recurring_requests_) @@ -152,11 +221,32 @@ active_diagnostic_request_t* diagnostic_manager_t::find_recurring_request(const return nullptr; } -std::shared_ptr diagnostic_manager_t::get_can_bus_dev() -{ - return can_bus_t::get_can_device(bus_); -} - +/// @brief Add and send a new one-time diagnostic request. +/// +/// @desc A one-time (aka non-recurring) request can existing in parallel with a +/// recurring request for the same PID or mode, that's not a problem. +/// +/// For an example, see the docs for addRecurringRequest. This function is very +/// similar but leaves out the frequencyHz parameter. +/// +/// @param[in] request - The parameters for the request. +/// @param[in] name - Human readable name this response, to be used when +/// publishing received responses. TODO: If the name is NULL, the published output +/// will use the raw OBD-II response format. +/// @param[in] waitForMultipleResponses - If false, When any response is received +/// for this request it will be removed from the active list. If true, the +/// request will remain active until the timeout clock expires, to allow it +/// to receive multiple response. Functional broadcast requests will always +/// waint for the timeout, regardless of this parameter. +/// @param[in] decoder - An optional DiagnosticResponseDecoder to parse the payload of +/// responses to this request. If the decoder is NULL, the output will +/// include the raw payload instead of a parsed value. +/// @param[in] callback - An optional DiagnosticResponseCallback to be notified whenever a +/// response is received for this request. +/// +/// @return true if the request was added successfully. Returns false if there +/// wasn't a free active request entry, if the frequency was too high or if the +/// CAN acceptance filters could not be configured, bool diagnostic_manager_t::add_request(DiagnosticRequest* request, const std::string name, bool wait_for_multiple_responses, const DiagnosticResponseDecoder decoder, const DiagnosticResponseCallback callback) @@ -202,6 +292,59 @@ bool diagnostic_manager_t::validate_optional_request_attributes(float frequencyH return true; } +/// @brief Add and send a new recurring diagnostic request. +/// +/// At most one recurring request can be active for the same arbitration ID, mode +/// and (if set) PID on the same bus at one time. If you try and call +/// addRecurringRequest with the same key, it will return an error. +/// +/// TODO: This also adds any neccessary CAN acceptance filters so we can receive the +/// response. If the request is to the functional broadcast ID (0x7df) filters +/// are added for all functional addresses (0x7e8 to 0x7f0). +/// +/// Example: +/// +/// // Creating a functional broadcast, mode 1 request for PID 2. +/// DiagnosticRequest request = { +/// arbitration_id: 0x7df, +/// mode: 1, +/// has_pid: true, +/// pid: 2 +/// }; +/// +/// // Add a recurring request, to be sent at 1Hz, and published with the +/// // name "my_pid_request" +/// addRecurringRequest(&getConfiguration()->diagnosticsManager, +/// canBus, +/// &request, +/// "my_pid_request", +/// false, +/// NULL, +/// NULL, +/// 1); +/// +/// @param[in] request - The parameters for the request. +/// @param[in] name - An optional human readable name this response, to be used when +/// publishing received responses. If the name is NULL, the published output +/// will use the raw OBD-II response format. +/// @param[in] waitForMultipleResponses - If false, When any response is received +/// for this request it will be removed from the active list. If true, the +/// request will remain active until the timeout clock expires, to allow it +/// to receive multiple response. Functional broadcast requests will always +/// waint for the timeout, regardless of this parameter. +/// @param[in] decoder - An optional DiagnosticResponseDecoder to parse the payload of +/// responses to this request. If the decoder is NULL, the output will +/// include the raw payload instead of a parsed value. +/// @param[in] callback - An optional DiagnosticResponseCallback to be notified whenever a +/// response is received for this request. +/// @param[in] frequencyHz - The frequency (in Hz) to send the request. A frequency above +/// MAX_RECURRING_DIAGNOSTIC_FREQUENCY_HZ is not allowed, and will make this +/// function return false. +/// +/// @return true if the request was added successfully. Returns false if there +/// was too much already running requests, if the frequency was too high TODO:or if the +/// CAN acceptance filters could not be configured, +/// bool diagnostic_manager_t::add_recurring_request(DiagnosticRequest* request, const char* name, bool wait_for_multiple_responses, const DiagnosticResponseDecoder decoder, const DiagnosticResponseCallback callback, float frequencyHz) @@ -255,7 +398,7 @@ bool diagnostic_manager_t::add_recurring_request(DiagnosticRequest* request, con return added; } - +/// @brief Returns true if there are two active requests running for the same arbitration ID. bool diagnostic_manager_t::conflicting(active_diagnostic_request_t* request, active_diagnostic_request_t* candidate) const { return (candidate->get_in_flight() && candidate != request && @@ -281,6 +424,17 @@ bool diagnostic_manager_t::clear_to_send(active_diagnostic_request_t* request) c return true; } +/// @brief Systemd timer event callback use to send CAN messages at regular interval. Depending +/// on the diagnostic message frequency. +/// +/// This should be called from systemd binder event loop and the event is created on add_recurring_request +/// +/// @param[in] s - Systemd event source pointer used to reschedule the new iteration. +/// @param[in] usec - previous call timestamp in microseconds. +/// @param[in] userdata - the DiagnosticRequest struct, use to retrieve the active request from the list. +/// +/// @return positive integer if sent and rescheduled or negative value if something wrong. If an error occurs +/// event will be disabled. int diagnostic_manager_t::send_request(sd_event_source *s, uint64_t usec, void *userdata) { diagnostic_manager_t& dm = configuration_t::instance().get_diagnostic_manager(); @@ -296,7 +450,8 @@ int diagnostic_manager_t::send_request(sd_event_source *s, uint64_t usec, void * if(adr->get_handle()->completed && !adr->get_handle()->success) { DEBUG(binder_interface, "send_request: Fatal error sending diagnostic request"); - return 0; + sd_event_source_unref(s); + return -1; } adr->get_timeout_clock().tick(); adr->set_in_flight(true); @@ -307,14 +462,24 @@ int diagnostic_manager_t::send_request(sd_event_source *s, uint64_t usec, void * DEBUG(binder_interface, "send_request: Event loop state: %d. usec: %ld", sd_event_get_state(afb_daemon_get_event_loop(binder_interface->daemon)), usec); if(sd_event_source_set_time(s, usec+1000000) >= 0) if(sd_event_source_set_enabled(s, SD_EVENT_ON) >= 0) - return 1; + { + sd_event_source_unref(s); + return -2; + } + return 1; } } sd_event_source_unref(s); ERROR(binder_interface, "send_request: Something goes wrong when submitting a new request to the CAN bus"); - return -1; + return -3; } +/// @brief Will decode the diagnostic response and build the final openxc_VehicleMessage to return. +/// +/// @param[in] adr - A pointer to an active diagnostic request holding a valid diagnostic handle +/// @param[in] response - The response to decode from which the Vehicle message will be built and returned +/// +/// @return A filled openxc_VehicleMessage or a zeroed struct if there is an error. openxc_VehicleMessage diagnostic_manager_t::relay_diagnostic_response(active_diagnostic_request_t* adr, const DiagnosticResponse& response) { openxc_VehicleMessage message = build_VehicleMessage(); @@ -423,28 +588,3 @@ bool diagnostic_manager_t::is_diagnostic_response(const can_message_t& cm) return true; return false; } - -DiagnosticShims& diagnostic_manager_t::get_shims() -{ - return shims_; -} - -bool diagnostic_manager_t::shims_send(const uint32_t arbitration_id, const uint8_t* data, const uint8_t size) -{ - std::shared_ptr can_bus_dev = can_bus_t::get_can_device(configuration_t::instance().get_diagnostic_manager().bus_); - return can_bus_dev->shims_send(arbitration_id, data, size); -} - -void diagnostic_manager_t::shims_logger(const char* format, ...) -{ - va_list args; - va_start(args, format); - - char buffer[256]; - vsnprintf(buffer, 256, format, args); - - DEBUG(binder_interface, "shims_logger: %s", buffer); -} - -void diagnostic_manager_t::shims_timer() -{} diff --git a/src/diagnostic/diagnostic-manager.hpp b/src/diagnostic/diagnostic-manager.hpp index 60b8dec..01aa5cf 100644 --- a/src/diagnostic/diagnostic-manager.hpp +++ b/src/diagnostic/diagnostic-manager.hpp @@ -29,7 +29,7 @@ #include "../low-can-binding.hpp" -/* Private: Each CAN bus needs its own set of shim functions, so this should +/* Each CAN bus needs its own set of shim functions, so this should * match the maximum CAN controller count. */ #define MAX_SHIM_COUNT can_bus_t.get_can_devices().size() @@ -38,10 +38,10 @@ class active_diagnostic_request_t; /** - * @brief The core structure for running the diagnostics module on the VI. + * @brief The core structure for running the diagnostics module by the binding. * * @desc This stores details about the active requests and shims required to connect - * the diagnostics library to the VI's CAN peripheral. + * the diagnostics library to the CAN device. */ class diagnostic_manager_t { protected: @@ -75,8 +75,6 @@ public: void cleanup_active_requests(bool force); active_diagnostic_request_t* find_recurring_request(const DiagnosticRequest* request); - bool validate_optional_request_attributes(float frequencyHz); - void checkSupportedPids(const active_diagnostic_request_t& request, const DiagnosticResponse& response, float parsedPayload); @@ -84,6 +82,7 @@ public: bool add_request(DiagnosticRequest* request, const std::string name, bool waitForMultipleResponses, const DiagnosticResponseDecoder decoder, const DiagnosticResponseCallback callback); + bool validate_optional_request_attributes(float frequencyHz); bool add_recurring_request(DiagnosticRequest* request, const char* name, bool waitForMultipleResponses, const DiagnosticResponseDecoder decoder, const DiagnosticResponseCallback callback, float frequencyHz); diff --git a/src/diagnostic/diagnostic-message.cpp b/src/diagnostic/diagnostic-message.cpp index 62da0dc..c37bbd0 100644 --- a/src/diagnostic/diagnostic-message.cpp +++ b/src/diagnostic/diagnostic-message.cpp @@ -33,9 +33,11 @@ const char *UNIT_NAMES[10] = { "NM" }; -diagnostic_message_t::diagnostic_message_t(uint8_t pid, const std::string generic_name, const int min, const int max, enum UNIT unit, float frequency, - DiagnosticResponseDecoder decoder, DiagnosticResponseCallback callback, bool supported) - : pid_{pid}, generic_name_{generic_name}, min_{min}, max_{max}, unit_{unit}, frequency_{frequency}, decoder_{decoder}, callback_{callback}, supported_{supported} +diagnostic_message_t::diagnostic_message_t(uint8_t pid, const std::string generic_name, const int min, + const int max, enum UNIT unit, float frequency, DiagnosticResponseDecoder decoder, + DiagnosticResponseCallback callback, bool supported) + : pid_{pid}, generic_name_{generic_name}, min_{min}, max_{max}, unit_{unit}, + frequency_{frequency}, decoder_{decoder}, callback_{callback}, supported_{supported} {} uint32_t diagnostic_message_t::get_pid() diff --git a/src/diagnostic/diagnostic-message.hpp b/src/diagnostic/diagnostic-message.hpp index ae37d7d..686a8b4 100644 --- a/src/diagnostic/diagnostic-message.hpp +++ b/src/diagnostic/diagnostic-message.hpp @@ -56,7 +56,7 @@ class diagnostic_message_t { * instead of a parsed value.*/ DiagnosticResponseCallback callback_; /*!< callback_ - An optional DiagnosticResponseCallback to be notified whenever a * response is received for this request.*/ - + bool supported_; /*!< supported_ - boolean indicating whether this pid is supported by the vehicle or not.*/ public: diff --git a/src/low-can-binding.cpp b/src/low-can-binding.cpp index 0830193..d9703e8 100644 --- a/src/low-can-binding.cpp +++ b/src/low-can-binding.cpp @@ -88,7 +88,7 @@ static int subscribe_unsubscribe_signal(struct afb_req request, bool subscribe, } /*else { - // Event it isn't valid annymore, recreate it + // Event it isn't valid annymore, recreate it ret = create_event_handle(sig, s); }*/ } @@ -133,7 +133,7 @@ static int subscribe_unsubscribe_signals(struct afb_req request, bool subscribe, std::vector found; configuration_t::instance().find_diagnostic_messages(build_DynamicField(sig), found); DiagnosticRequest* diag_req = new DiagnosticRequest(found.front()->build_diagnostic_request()); - + // If the requested diagnostic message isn't supported by the car then unssubcribe. // no matter what we want, worse case will be a fail unsubscription but at least we don't // poll a PID for nothing. -- cgit 1.2.3-korg