Fix: exception unsubscribe all at start
[apps/agl-service-can-low-level.git] / CAN-binder / low-can-binding / diagnostic / diagnostic-manager.cpp
index 7539634..7dab749 100644 (file)
@@ -23,7 +23,7 @@
 
 #include "../utils/openxc-utils.hpp"
 #include "../utils/signals.hpp"
-#include "../binding/configuration.hpp"
+#include "../binding/application.hpp"
 
 #define MAX_RECURRING_DIAGNOSTIC_FREQUENCY_HZ 10
 #define MAX_SIMULTANEOUS_DIAG_REQUESTS 50
@@ -46,10 +46,9 @@ diagnostic_manager_t::diagnostic_manager_t()
 bool diagnostic_manager_t::initialize()
 {
        // Mandatory to set the bus before intialize shims.
-       bus_ = configuration_t::instance().get_diagnostic_bus();
+       bus_ = application_t::instance().get_diagnostic_bus();
 
        init_diagnostic_shims();
-       event_source_ = nullptr;
        reset();
 
        initialized_ = true;
@@ -57,21 +56,6 @@ bool diagnostic_manager_t::initialize()
        return initialized_;
 }
 
-void diagnostic_manager_t::read_socket()
-{
-       can_message_t msg;
-       can_bus_t& cbm = configuration_t::instance().get_can_bus_manager();
-       socket_ >> msg;
-       std::lock_guard<std::mutex> can_message_lock(cbm.get_can_message_mutex());
-       { cbm.push_new_can_message(msg); }
-       cbm.get_new_can_message_cv().notify_one();
-}
-
-utils::socketcan_bcm_t& diagnostic_manager_t::get_socket()
-{
-       return socket_;
-}
-
 /// @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.
@@ -88,51 +72,6 @@ void diagnostic_manager_t::reset()
        cleanup_active_requests(true);
 }
 
-/// @brief Adds 8 RX_SETUP jobs to the BCM rx_socket_ then diagnotic manager
-///  listens on CAN ID range 7E8 - 7EF affected to the OBD2 communications.
-///
-/// @return -1 or negative value on error, 0 if ok.
-int diagnostic_manager_t::add_rx_filter(uint32_t can_id)
-{
-       // Make sure that socket has been opened.
-       if(! socket_)
-               socket_.open(bus_);
-
-       struct utils::simple_bcm_msg bcm_msg;
-       memset(&bcm_msg.msg_head, 0, sizeof(bcm_msg.msg_head));
-
-       const struct timeval freq =  recurring_requests_.back()->get_timeout_clock().get_timeval_from_period();
-
-       bcm_msg.msg_head.opcode  = RX_SETUP;
-       bcm_msg.msg_head.flags = SETTIMER|RX_FILTER_ID;
-       bcm_msg.msg_head.ival2.tv_sec = freq.tv_sec;
-       bcm_msg.msg_head.ival2.tv_usec = freq.tv_usec;
-
-       // If it isn't an OBD2 CAN ID then just add a simple RX_SETUP job
-       if(can_id != OBD2_FUNCTIONAL_BROADCAST_ID) 
-       {
-               bcm_msg.msg_head.can_id  = can_id;
-
-               socket_ << bcm_msg;
-                       if(! socket_)
-                               return -1;
-       }
-       else
-       {
-               for(uint8_t i = 0; i < 8; i++)
-               {
-                       can_id  =  OBD2_FUNCTIONAL_RESPONSE_START + i;
-                       bcm_msg.msg_head.can_id  = can_id;
-
-                       socket_ << bcm_msg;
-                       if(! socket_)
-                               return -1;
-               }
-       }
-
-       return 0;
-}
-
 /// @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.
@@ -145,14 +84,14 @@ int diagnostic_manager_t::add_rx_filter(uint32_t can_id)
 /// @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)
 {
-       diagnostic_manager_t& dm = configuration_t::instance().get_diagnostic_manager();
+       diagnostic_manager_t& dm = application_t::instance().get_diagnostic_manager();
        active_diagnostic_request_t* current_adr = dm.get_last_recurring_requests();
        utils::socketcan_bcm_t& tx_socket = current_adr->get_socket();
 
        // Make sure that socket has been opened.
        if(! tx_socket)
                tx_socket.open(
-                       dm.get_can_bus());
+                       dm.get_bus_device_name());
 
        struct utils::simple_bcm_msg bcm_msg;
        struct can_frame cfd;
@@ -168,6 +107,7 @@ bool diagnostic_manager_t::shims_send(const uint32_t arbitration_id, const uint8
        bcm_msg.msg_head.ival2.tv_sec = freq.tv_sec;
        bcm_msg.msg_head.ival2.tv_usec = freq.tv_usec;
        bcm_msg.msg_head.nframes = 1;
+       cfd.can_dlc = size;
        ::memcpy(cfd.data, data, size);
 
        bcm_msg.frames = cfd;
@@ -194,17 +134,24 @@ void diagnostic_manager_t::shims_logger(const char* format, ...)
        vsnprintf(buffer, 256, format, args);
 
        DEBUG(binder_interface, "%s: %s", __FUNCTION__, buffer);
+       va_end(args);
 }
 
 /// @brief The type signature for a... OpenXC TODO: not used yet.
 void diagnostic_manager_t::shims_timer()
 {}
 
-std::string diagnostic_manager_t::get_can_bus()
+const std::string diagnostic_manager_t::get_bus_name() const
 {
        return bus_;
 }
 
+const std::string diagnostic_manager_t::get_bus_device_name() const
+{
+       return application_t::instance().get_can_bus_manager()
+               .get_can_device_name(bus_);
+}
+
 active_diagnostic_request_t* diagnostic_manager_t::get_last_recurring_requests() const
 {
        return recurring_requests_.back();
@@ -216,6 +163,15 @@ DiagnosticShims& diagnostic_manager_t::get_shims()
        return shims_;
 }
 
+bool diagnostic_manager_t::is_active_requests_running()
+{
+       if(non_recurring_requests_.empty() && recurring_requests_.empty())
+       {
+               return true;
+       }
+       return false;
+}
+
 /// @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
@@ -234,6 +190,8 @@ void diagnostic_manager_t::find_and_erase(active_diagnostic_request_t* entry, st
 void diagnostic_manager_t::cancel_request(active_diagnostic_request_t* entry)
 {
        entry->get_socket().close();
+       delete entry;
+       entry = nullptr;
 }
 
 /// @brief Cleanup a specific request if it isn't running and get complete. As it is almost
@@ -244,24 +202,22 @@ void diagnostic_manager_t::cancel_request(active_diagnostic_request_t* entry)
 /// @param[in] force - Force the cleaning or not ?
 void diagnostic_manager_t::cleanup_request(active_diagnostic_request_t* entry, bool force)
 {
-       if((force || (entry != nullptr && entry->get_in_flight() && entry->request_completed())))
+       if(entry != nullptr && (force || entry->response_received()))
        {
-               entry->set_in_flight(false);
-
                char request_string[128] = {0};
                diagnostic_request_to_string(&entry->get_handle()->request,
                        request_string, sizeof(request_string));
                if(force && entry->get_recurring())
                {
-                       find_and_erase(entry, recurring_requests_);
                        cancel_request(entry);
+                       find_and_erase(entry, recurring_requests_);
                        DEBUG(binder_interface, "%s: Cancelling completed, recurring request: %s", __FUNCTION__, request_string);
                }
-               else
+               else if (!entry->get_recurring())
                {
                        DEBUG(binder_interface, "%s: Cancelling completed, non-recurring request: %s", __FUNCTION__, request_string);
-                       find_and_erase(entry, non_recurring_requests_);
                        cancel_request(entry);
+                       find_and_erase(entry, non_recurring_requests_);
                }
        }
 }
@@ -273,12 +229,16 @@ void diagnostic_manager_t::cleanup_request(active_diagnostic_request_t* entry, b
 void diagnostic_manager_t::cleanup_active_requests(bool force)
 {
        for(auto& entry : non_recurring_requests_)
+       {
                if (entry != nullptr)
                        cleanup_request(entry, force);
+       }
 
        for(auto& entry : recurring_requests_)
+        {
                if (entry != nullptr)
                        cleanup_request(entry, force);
+        }
 }
 
 /// @brief Will return the active_diagnostic_request_t pointer for theDiagnosticRequest or nullptr if
@@ -286,17 +246,14 @@ void diagnostic_manager_t::cleanup_active_requests(bool force)
 ///
 /// @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)
+active_diagnostic_request_t* diagnostic_manager_t::find_recurring_request(DiagnosticRequest& request)
 {
        for (auto& entry : recurring_requests_)
        {
                if(entry != nullptr)
                {
-                       if(diagnostic_request_equals(&entry->get_handle()->request, request))
-                       {
-                               return entry;
-                               break;
-                       }
+                       if(diagnostic_request_equals(&entry->get_handle()->request, &request))
+                               {return entry;}
                }
        }
        return nullptr;
@@ -328,7 +285,7 @@ active_diagnostic_request_t* diagnostic_manager_t::find_recurring_request(const
 /// @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,
-active_diagnostic_request_t* diagnostic_manager_t::add_request(DiagnosticRequest* request, const std::string name,
+active_diagnostic_request_t* diagnostic_manager_t::add_request(DiagnosticRequest* request, const std::string& name,
        bool wait_for_multiple_responses, const DiagnosticResponseDecoder decoder,
        const DiagnosticResponseCallback callback)
 {
@@ -340,7 +297,7 @@ active_diagnostic_request_t* diagnostic_manager_t::add_request(DiagnosticRequest
        {
                // TODO: implement Acceptance Filter
                //      if(updateRequiredAcceptanceFilters(bus, request)) {
-                       active_diagnostic_request_t* entry = new active_diagnostic_request_t(bus_, request, name,
+                       active_diagnostic_request_t* entry = new active_diagnostic_request_t(bus_, request->arbitration_id, name,
                                        wait_for_multiple_responses, decoder, callback, 0);
                        entry->set_handle(shims_, request);
 
@@ -348,7 +305,8 @@ active_diagnostic_request_t* diagnostic_manager_t::add_request(DiagnosticRequest
                        diagnostic_request_to_string(&entry->get_handle()->request, request_string,
                                        sizeof(request_string));
 
-                       find_and_erase(entry, non_recurring_requests_);
+                       // Erase any existing request not already cleaned.
+                       cleanup_request(entry, true);
                        DEBUG(binder_interface, "%s: Added one-time diagnostic request on bus %s: %s", __FUNCTION__,
                                        bus_.c_str(), request_string);
 
@@ -435,34 +393,16 @@ active_diagnostic_request_t* diagnostic_manager_t::add_recurring_request(Diagnos
 
        cleanup_active_requests(false);
 
-       if(find_recurring_request(request) == nullptr)
+       if(find_recurring_request(*request) == nullptr)
        {
                if(recurring_requests_.size() <= MAX_SIMULTANEOUS_DIAG_REQUESTS)
                {
-                       // TODO: implement Acceptance Filter
-                       //if(updateRequiredAcceptanceFilters(bus, request)) {
-                       entry = new active_diagnostic_request_t(bus_, request, name,
+                       entry = new active_diagnostic_request_t(bus_, request->arbitration_id, name,
                                        wait_for_multiple_responses, decoder, callback, frequencyHz);
                        recurring_requests_.push_back(entry);
 
                        entry->set_handle(shims_, request);
-                       if(add_rx_filter(OBD2_FUNCTIONAL_BROADCAST_ID) < 0)
-                               { recurring_requests_.pop_back(); }
-                       else
-                               {
-                                       start_diagnostic_request(&shims_, entry->get_handle()); 
-                                       if(event_source_ == nullptr && sd_event_add_io(afb_daemon_get_event_loop(binder_interface->daemon), 
-                                               &event_source_,
-                                               socket_.socket(),
-                                               EPOLLIN,
-                                               read_diagnostic_message,
-                                               nullptr) < 0)
-                                       {
-                                               cleanup_request(entry, true);
-                                               WARNING(binder_interface, "%s: signal: %s isn't supported. Canceling operation.", __FUNCTION__, entry->get_name().c_str());
-                                               return entry;
-                                       }
-                               }
+                       start_diagnostic_request(&shims_, entry->get_handle()); 
                }
                else
                {
@@ -475,41 +415,6 @@ active_diagnostic_request_t* diagnostic_manager_t::add_recurring_request(Diagnos
        return entry;
 }
 
-/// @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 &&
-                       candidate->get_can_bus_dev() == request->get_can_bus_dev() &&
-                       candidate->get_id() == request->get_id());
-}
-
-
-/// @brief Returns true if there are no other active requests to the same arbitration ID
-/// and if there aren't more than 8 requests in flight at the same time.
-bool diagnostic_manager_t::clear_to_send(active_diagnostic_request_t* request) const
-{
-       int total_in_flight = 0;
-       for ( auto entry : non_recurring_requests_)
-       {
-               if(conflicting(request, entry))
-                       return false;
-               if(entry->get_in_flight())
-                       total_in_flight++;
-       }
-
-       for ( auto entry : recurring_requests_)
-       {
-               if(conflicting(request, entry))
-                       return false;
-               if(entry->get_in_flight())
-                       total_in_flight++;
-       }
-
-       if(total_in_flight > MAX_SIMULTANEOUS_IN_FLIGHT_REQUESTS)
-               return false;
-       return true;
-}
-
 /// @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
@@ -530,10 +435,12 @@ openxc_VehicleMessage diagnostic_manager_t::relay_diagnostic_response(active_dia
                // If name, include 'value' instead of payload, and leave of response
                // details.
                message = build_VehicleMessage(build_SimpleMessage(adr->get_name(), build_DynamicField(value)));
+               message.has_diagnostic_response = true;
+               message.diagnostic_response = build_VehicleMessage(adr, response, value).diagnostic_response;
        }
        else
        {
-               // If no name, send full details of response but still include 'value'
+               // If no name, only send full details of response but still include 'value'
                // instead of 'payload' if they provided a decoder. The one case you
                // can't get is the full detailed response with 'value'. We could add
                // another parameter for that but it's onerous to carry that around.
@@ -557,7 +464,7 @@ openxc_VehicleMessage diagnostic_manager_t::relay_diagnostic_response(active_dia
        }
 
        // Reset the completed flag handle to make sure that it will be reprocessed the next time.
-       adr->get_handle()->completed = false;
+       adr->get_handle()->success = false;
        return message;
 }
 
@@ -580,7 +487,8 @@ openxc_VehicleMessage diagnostic_manager_t::relay_diagnostic_handle(active_diagn
        else if(!response.completed && response.multi_frame)
        {
                // Reset the timeout clock while completing the multi-frame receive
-               entry->get_timeout_clock().tick();
+               entry->get_timeout_clock().tick(
+                       entry->get_timeout_clock().get_time_function()());
        }
 
        return build_VehicleMessage();