diff options
author | Romain Forlot <romain.forlot@iot.bzh> | 2017-06-20 10:24:05 +0000 |
---|---|---|
committer | Romain Forlot <romain.forlot@iot.bzh> | 2017-06-20 10:24:05 +0000 |
commit | 32e25cbca210a359b09768537b6f443fe90a3070 (patch) | |
tree | 3309794c15d8a8f8e9c1c08cad072ee1378813ba /low-can-binding/binding | |
parent | 76c43dec62b2e21cd6446360c00d4fe6b437533f (diff) |
Separation Generator to a dedicated repo
Change-Id: Id94831651c3266861435272a6e36c7884bef2c45
Signed-off-by: Romain Forlot <romain.forlot@iot.bzh>
Diffstat (limited to 'low-can-binding/binding')
-rw-r--r-- | low-can-binding/binding/application-generated.cpp | 564 | ||||
-rw-r--r-- | low-can-binding/binding/application.cpp | 78 | ||||
-rw-r--r-- | low-can-binding/binding/application.hpp | 104 | ||||
-rw-r--r-- | low-can-binding/binding/low-can-cb.cpp | 358 | ||||
-rw-r--r-- | low-can-binding/binding/low-can-hat.cpp | 73 | ||||
-rw-r--r-- | low-can-binding/binding/low-can-hat.hpp | 40 | ||||
-rw-r--r-- | low-can-binding/binding/low-can-subscription.cpp | 306 | ||||
-rw-r--r-- | low-can-binding/binding/low-can-subscription.hpp | 91 |
8 files changed, 1614 insertions, 0 deletions
diff --git a/low-can-binding/binding/application-generated.cpp b/low-can-binding/binding/application-generated.cpp new file mode 100644 index 00000000..60a21f51 --- /dev/null +++ b/low-can-binding/binding/application-generated.cpp @@ -0,0 +1,564 @@ +#include "application.hpp" +#include "../can/can-decoder.hpp" + +application_t::application_t() + : can_bus_manager_{utils::config_parser_t{"/etc/dev-mapping.conf"}} + , can_message_set_{ + {std::make_shared<can_message_set_t>(can_message_set_t{0,"example", + { // beginning can_message_definition_ vector + {std::make_shared<can_message_definition_t>(can_message_definition_t{"hs",0x3D9,can_message_format_t::STANDARD,frequency_clock_t(5.00000f),true, + { // beginning can_signals vector + {std::make_shared<can_signal_t> (can_signal_t{ + "engine.speed", + 16, + 16, + 0.250000f, + 0.00000, + 0, + 0, + frequency_clock_t(0.00000f), + true, + false, + { + }, + false, + nullptr, + nullptr, + false + })}, + {std::make_shared<can_signal_t> (can_signal_t{ + "fuel.level.low", + 55, + 1, + 1.00000f, + 0.00000, + 0, + 0, + frequency_clock_t(0.00000f), + true, + false, + { + }, + false, + decoder_t::booleanDecoder, + nullptr, + false + })}, + {std::make_shared<can_signal_t> (can_signal_t{ + "fuel.level", + 8, + 8, + 0.392157f, + 0.00000, + 0, + 0, + frequency_clock_t(0.00000f), + true, + false, + { + }, + false, + nullptr, + nullptr, + false + })} + } // end can_signals vector + })} // end can_message_definition entry +, {std::make_shared<can_message_definition_t>(can_message_definition_t{"hs",0x3E9,can_message_format_t::STANDARD,frequency_clock_t(5.00000f),true, + { // beginning can_signals vector + {std::make_shared<can_signal_t> (can_signal_t{ + "vehicle.average.speed", + 0, + 15, + 0.0156250f, + 0.00000, + 0, + 0, + frequency_clock_t(0.00000f), + true, + false, + { + }, + false, + nullptr, + nullptr, + false + })} + } // end can_signals vector + })} // end can_message_definition entry +, {std::make_shared<can_message_definition_t>(can_message_definition_t{"hs",0x4D1,can_message_format_t::STANDARD,frequency_clock_t(5.00000f),true, + { // beginning can_signals vector + {std::make_shared<can_signal_t> (can_signal_t{ + "engine.oil.temp", + 16, + 8, + 1.00000f, + 0.00000, + 0, + 0, + frequency_clock_t(0.00000f), + true, + false, + { + }, + false, + nullptr, + nullptr, + false + })}, + {std::make_shared<can_signal_t> (can_signal_t{ + "engine.oil.temp.high", + 7, + 1, + 1.00000f, + 0.00000, + 0, + 0, + frequency_clock_t(0.00000f), + true, + false, + { + }, + false, + decoder_t::booleanDecoder, + nullptr, + false + })} + } // end can_signals vector + })} // end can_message_definition entry +, {std::make_shared<can_message_definition_t>(can_message_definition_t{"hs",0x620,can_message_format_t::STANDARD,frequency_clock_t(5.00000f),true, + { // beginning can_signals vector + {std::make_shared<can_signal_t> (can_signal_t{ + "doors.boot.open", + 47, + 1, + 1.00000f, + 0.00000, + 0, + 0, + frequency_clock_t(0.00000f), + true, + false, + { + }, + false, + decoder_t::booleanDecoder, + nullptr, + false + })}, + {std::make_shared<can_signal_t> (can_signal_t{ + "doors.front_left.open", + 43, + 1, + 1.00000f, + 0.00000, + 0, + 0, + frequency_clock_t(0.00000f), + true, + false, + { + }, + false, + decoder_t::booleanDecoder, + nullptr, + false + })}, + {std::make_shared<can_signal_t> (can_signal_t{ + "doors.front_right.open", + 44, + 1, + 1.00000f, + 0.00000, + 0, + 0, + frequency_clock_t(0.00000f), + true, + false, + { + }, + false, + decoder_t::booleanDecoder, + nullptr, + false + })}, + {std::make_shared<can_signal_t> (can_signal_t{ + "doors.rear_left.open", + 46, + 1, + 1.00000f, + 0.00000, + 0, + 0, + frequency_clock_t(0.00000f), + true, + false, + { + }, + false, + decoder_t::booleanDecoder, + nullptr, + false + })}, + {std::make_shared<can_signal_t> (can_signal_t{ + "doors.rear_right.open", + 45, + 4, + 1.00000f, + 0.00000, + 0, + 0, + frequency_clock_t(0.00000f), + true, + false, + { + }, + false, + decoder_t::booleanDecoder, + nullptr, + false + })} + } // end can_signals vector + })} // end can_message_definition entry +, {std::make_shared<can_message_definition_t>(can_message_definition_t{"hs",0x799,can_message_format_t::STANDARD,frequency_clock_t(5.00000f),true, + { // beginning can_signals vector + {std::make_shared<can_signal_t> (can_signal_t{ + "windows.front_left.open", + 43, + 1, + 1.00000f, + 0.00000, + 0, + 0, + frequency_clock_t(0.00000f), + true, + false, + { + }, + false, + decoder_t::booleanDecoder, + nullptr, + false + })}, + {std::make_shared<can_signal_t> (can_signal_t{ + "windows.front_right.open", + 44, + 1, + 1.00000f, + 0.00000, + 0, + 0, + frequency_clock_t(0.00000f), + true, + false, + { + }, + false, + decoder_t::booleanDecoder, + nullptr, + false + })}, + {std::make_shared<can_signal_t> (can_signal_t{ + "windows.rear_left.open", + 46, + 1, + 1.00000f, + 0.00000, + 0, + 0, + frequency_clock_t(0.00000f), + true, + false, + { + }, + false, + decoder_t::booleanDecoder, + nullptr, + false + })}, + {std::make_shared<can_signal_t> (can_signal_t{ + "windows.rear_right.open", + 45, + 4, + 1.00000f, + 0.00000, + 0, + 0, + frequency_clock_t(0.00000f), + true, + false, + { + }, + false, + decoder_t::booleanDecoder, + nullptr, + false + })} + } // end can_signals vector + })} // end can_message_definition entry + + }, // end can_message_definition vector + { // beginning diagnostic_messages_ vector + {std::make_shared<diagnostic_message_t>(diagnostic_message_t{ + 4, + "engine.load", + 0, + 0, + UNIT::INVALID, + 5.00000f, + decoder_t::decode_obd2_response, + nullptr, + true + })} +, {std::make_shared<diagnostic_message_t>(diagnostic_message_t{ + 5, + "engine.coolant.temperature", + 0, + 0, + UNIT::INVALID, + 1.00000f, + decoder_t::decode_obd2_response, + nullptr, + true + })} +, {std::make_shared<diagnostic_message_t>(diagnostic_message_t{ + 10, + "fuel.pressure", + 0, + 0, + UNIT::INVALID, + 1.00000f, + decoder_t::decode_obd2_response, + nullptr, + true + })} +, {std::make_shared<diagnostic_message_t>(diagnostic_message_t{ + 11, + "intake.manifold.pressure", + 0, + 0, + UNIT::INVALID, + 1.00000f, + decoder_t::decode_obd2_response, + nullptr, + true + })} +, {std::make_shared<diagnostic_message_t>(diagnostic_message_t{ + 12, + "engine.speed", + 0, + 0, + UNIT::INVALID, + 5.00000f, + decoder_t::decode_obd2_response, + nullptr, + true + })} +, {std::make_shared<diagnostic_message_t>(diagnostic_message_t{ + 13, + "vehicle.speed", + 0, + 0, + UNIT::INVALID, + 5.00000f, + decoder_t::decode_obd2_response, + nullptr, + true + })} +, {std::make_shared<diagnostic_message_t>(diagnostic_message_t{ + 15, + "intake.air.temperature", + 0, + 0, + UNIT::INVALID, + 1.00000f, + decoder_t::decode_obd2_response, + nullptr, + true + })} +, {std::make_shared<diagnostic_message_t>(diagnostic_message_t{ + 16, + "mass.airflow", + 0, + 0, + UNIT::INVALID, + 5.00000f, + decoder_t::decode_obd2_response, + nullptr, + true + })} +, {std::make_shared<diagnostic_message_t>(diagnostic_message_t{ + 17, + "throttle.position", + 0, + 0, + UNIT::INVALID, + 5.00000f, + decoder_t::decode_obd2_response, + nullptr, + true + })} +, {std::make_shared<diagnostic_message_t>(diagnostic_message_t{ + 31, + "running.time", + 0, + 0, + UNIT::INVALID, + 1.00000f, + decoder_t::decode_obd2_response, + nullptr, + true + })} +, {std::make_shared<diagnostic_message_t>(diagnostic_message_t{ + 45, + "EGR.error", + 0, + 0, + UNIT::INVALID, + 0.00000f, + decoder_t::decode_obd2_response, + nullptr, + true + })} +, {std::make_shared<diagnostic_message_t>(diagnostic_message_t{ + 47, + "fuel.level", + 0, + 0, + UNIT::INVALID, + 1.00000f, + decoder_t::decode_obd2_response, + nullptr, + true + })} +, {std::make_shared<diagnostic_message_t>(diagnostic_message_t{ + 51, + "barometric.pressure", + 0, + 0, + UNIT::INVALID, + 1.00000f, + decoder_t::decode_obd2_response, + nullptr, + true + })} +, {std::make_shared<diagnostic_message_t>(diagnostic_message_t{ + 70, + "ambient.air.temperature", + 0, + 0, + UNIT::INVALID, + 1.00000f, + decoder_t::decode_obd2_response, + nullptr, + true + })} +, {std::make_shared<diagnostic_message_t>(diagnostic_message_t{ + 76, + "commanded.throttle.position", + 0, + 0, + UNIT::INVALID, + 1.00000f, + decoder_t::decode_obd2_response, + nullptr, + true + })} +, {std::make_shared<diagnostic_message_t>(diagnostic_message_t{ + 82, + "ethanol.fuel.percentage", + 0, + 0, + UNIT::INVALID, + 1.00000f, + decoder_t::decode_obd2_response, + nullptr, + true + })} +, {std::make_shared<diagnostic_message_t>(diagnostic_message_t{ + 90, + "accelerator.pedal.position", + 0, + 0, + UNIT::INVALID, + 5.00000f, + decoder_t::decode_obd2_response, + nullptr, + true + })} +, {std::make_shared<diagnostic_message_t>(diagnostic_message_t{ + 91, + "hybrid.battery-pack.remaining.life", + 0, + 0, + UNIT::INVALID, + 5.00000f, + decoder_t::decode_obd2_response, + nullptr, + true + })} +, {std::make_shared<diagnostic_message_t>(diagnostic_message_t{ + 92, + "engine.oil.temperature", + 0, + 0, + UNIT::INVALID, + 1.00000f, + decoder_t::decode_obd2_response, + nullptr, + true + })} +, {std::make_shared<diagnostic_message_t>(diagnostic_message_t{ + 94, + "engine.fuel.rate", + 0, + 0, + UNIT::INVALID, + 1.00000f, + decoder_t::decode_obd2_response, + nullptr, + true + })} +, {std::make_shared<diagnostic_message_t>(diagnostic_message_t{ + 99, + "engine.torque", + 0, + 0, + UNIT::INVALID, + 1.00000f, + decoder_t::decode_obd2_response, + nullptr, + true + })} + + } // end diagnostic_messages_ vector + })} // end can_message_set entry + } // end can_message_set vector +{ + for(auto& cms: can_message_set_) + { + std::vector<std::shared_ptr<can_message_definition_t> >& can_messages_definition = cms->get_can_message_definition(); + for(auto& cmd : can_messages_definition) + { + cmd->set_parent(cms.get()); + std::vector<std::shared_ptr<can_signal_t> >& can_signals = cmd->get_can_signals(); + for(auto& sig: can_signals) + { + sig->set_parent(cmd.get()); + } + } + + std::vector<std::shared_ptr<diagnostic_message_t> >& diagnostic_messages = cms->get_diagnostic_messages(); + for(auto& dm : diagnostic_messages) + { + dm->set_parent(cms.get()); + } + } + } + +const std::string application_t::get_diagnostic_bus() const +{ + return "hs"; +} + + diff --git a/low-can-binding/binding/application.cpp b/low-can-binding/binding/application.cpp new file mode 100644 index 00000000..6e6353b8 --- /dev/null +++ b/low-can-binding/binding/application.cpp @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2015, 2016 "IoT.bzh" + * Author "Romain Forlot" <romain.forlot@iot.bzh> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "application.hpp" + +#include "../utils/signals.hpp" +#include "../utils/openxc-utils.hpp" + +/// @brief Return singleton instance of configuration object. +application_t& application_t::instance() +{ + static application_t config; + return config; +} + +can_bus_t& application_t::get_can_bus_manager() +{ + return can_bus_manager_; +} + +diagnostic_manager_t& application_t::get_diagnostic_manager() +{ + return diagnostic_manager_; +} + +uint8_t application_t::get_active_message_set() const +{ + return active_message_set_; +} + +std::vector<std::shared_ptr<can_message_set_t> > application_t::get_can_message_set() +{ + return can_message_set_; +} + +std::vector<std::shared_ptr<can_signal_t> > application_t::get_all_can_signals() +{ + return can_message_set_[active_message_set_]->get_all_can_signals(); +} + +std::vector<std::shared_ptr<diagnostic_message_t> >& application_t::get_diagnostic_messages() +{ + return can_message_set_[active_message_set_]->get_diagnostic_messages(); +} + +std::vector<std::shared_ptr<can_message_definition_t> >& application_t::get_can_message_definition() +{ + return can_message_set_[active_message_set_]->get_can_message_definition(); +} + +uint32_t application_t::get_signal_id(diagnostic_message_t& sig) const +{ + return sig.get_pid(); +} + +uint32_t application_t::get_signal_id(can_signal_t& sig) const +{ + return sig.get_message()->get_id(); +} + +void application_t::set_active_message_set(uint8_t id) +{ + active_message_set_ = id; +} diff --git a/low-can-binding/binding/application.hpp b/low-can-binding/binding/application.hpp new file mode 100644 index 00000000..5fa64782 --- /dev/null +++ b/low-can-binding/binding/application.hpp @@ -0,0 +1,104 @@ +/* + * Copyright (C) 2015, 2016 "IoT.bzh" + * Author "Romain Forlot" <romain.forlot@iot.bzh> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <map> +#include <vector> +#include <string> +#include <memory> + +#include "../can/can-bus.hpp" +#include "../can/can-message-set.hpp" +#include "../can/can-signals.hpp" +#include "../diagnostic/diagnostic-manager.hpp" + +#include "low-can-hat.hpp" + +/// +/// @brief Class representing a configuration attached to the binding. +/// +/// It regroups all needed objects instance from other class +/// that will be used along the binding life. It gets a global vision +/// on which signals are implemented for that binding. +/// Here, it is only the definition of the class with predefined accessors +/// methods used in the binding. +/// +/// It will be the reference point to needed objects. +/// +class application_t +{ + private: + can_bus_t can_bus_manager_; ///< instanciate the CAN bus manager. It's the one in charge of initialize the CAN bus devices. + 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<std::shared_ptr<can_message_set_t> > can_message_set_; ///< Vector holding all message set from JSON signals description file + + application_t(); ///< Private constructor with implementation generated by the AGL generator. + + public: + static application_t& instance(); + + can_bus_t& get_can_bus_manager(); + + const std::string get_diagnostic_bus() const; + + diagnostic_manager_t& get_diagnostic_manager() ; + + uint8_t get_active_message_set() const; + + std::vector<std::shared_ptr<can_message_set_t> > get_can_message_set(); + + std::vector<std::shared_ptr<can_signal_t> > get_all_can_signals(); + + std::vector<std::shared_ptr<diagnostic_message_t> >& get_diagnostic_messages(); + + const std::vector<std::string>& get_signals_prefix() const; + + std::vector<std::shared_ptr<can_message_definition_t> >& get_can_message_definition(); + + uint32_t get_signal_id(diagnostic_message_t& sig) const; + + uint32_t get_signal_id(can_signal_t& sig) const; + + void set_active_message_set(uint8_t id); + +/* + /// TODO: implement this function as method into can_bus class + /// @brief Pre initialize actions made before CAN bus initialization + /// @param[in] bus A CanBus struct defining the bus's metadata + /// @param[in] writable Configure the controller in a writable mode. If false, it will be configured as "listen only" and will not allow writes or even CAN ACKs. + /// @param[in] buses An array of all CAN buses. + void pre_initialize(can_bus_dev_t* bus, bool writable, can_bus_dev_t* buses, const int busCount); + /// TODO: implement this function as method into can_bus class + /// @brief Post-initialize actions made after CAN bus initialization + /// @param[in] bus A CanBus struct defining the bus's metadata + /// @param[in] writable Configure the controller in a writable mode. If false, it will be configured as "listen only" and will not allow writes or even CAN ACKs. + /// @param[in] buses An array of all CAN buses. + void post_initialize(can_bus_dev_t* bus, bool writable, can_bus_dev_t* buses, const int busCount); + /// TODO: implement this function as method into can_bus class + /// @brief Check if the device is connected to an active CAN bus, i.e. it's received a message in the recent past. + /// @return true if a message was received on the CAN bus within CAN_ACTIVE_TIMEOUT_S seconds. + void logBusStatistics(can_bus_dev_t* buses, const int busCount); + /// TODO: implement this function as method into can_bus class + /// @brief Log transfer statistics about all active CAN buses to the debug log. + /// @param[in] buses An array of active CAN buses. + bool isBusActive(can_bus_dev_t* bus); + */ +}; + diff --git a/low-can-binding/binding/low-can-cb.cpp b/low-can-binding/binding/low-can-cb.cpp new file mode 100644 index 00000000..97b6d206 --- /dev/null +++ b/low-can-binding/binding/low-can-cb.cpp @@ -0,0 +1,358 @@ +/* + * Copyright (C) 2015, 2016 "IoT.bzh" + * Author "Romain Forlot" <romain.forlot@iot.bzh> + * Author "Loic Collignon" <loic.collignon@iot.bzh> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "low-can-hat.hpp" + +#include <map> +#include <queue> +#include <mutex> +#include <vector> +#include <thread> +#include <json-c/json.h> +#include <systemd/sd-event.h> + +#include "openxc.pb.h" +#include "application.hpp" +#include "../can/can-bus.hpp" +#include "../can/can-signals.hpp" +#include "../can/can-message.hpp" +#include "../utils/signals.hpp" +#include "../diagnostic/diagnostic-message.hpp" +#include "../utils/openxc-utils.hpp" + + +///****************************************************************************** +/// +/// SystemD event loop Callbacks +/// +///*******************************************************************************/ + +void on_no_clients(std::shared_ptr<low_can_subscription_t> can_subscription, uint32_t pid, std::map<int, std::shared_ptr<low_can_subscription_t> >& s) +{ + if( ! can_subscription->get_diagnostic_message().empty() && can_subscription->get_diagnostic_message(pid) != nullptr) + { + DiagnosticRequest diag_req = can_subscription->get_diagnostic_message(pid)->build_diagnostic_request(); + active_diagnostic_request_t* adr = application_t::instance().get_diagnostic_manager().find_recurring_request(diag_req); + if( adr != nullptr) + application_t::instance().get_diagnostic_manager().cleanup_request(adr, true); + } + + on_no_clients(can_subscription, s); +} + +void on_no_clients(std::shared_ptr<low_can_subscription_t> can_subscription, std::map<int, std::shared_ptr<low_can_subscription_t> >& s) +{ + auto it = s.find(can_subscription->get_index()); + s.erase(it); +} + +static void push_n_notify(const can_message_t& cm) +{ + can_bus_t& cbm = application_t::instance().get_can_bus_manager(); + { + std::lock_guard<std::mutex> can_message_lock(cbm.get_can_message_mutex()); + cbm.push_new_can_message(cm); + } + cbm.get_new_can_message_cv().notify_one(); +} + +int read_message(sd_event_source *event_source, int fd, uint32_t revents, void *userdata) +{ + low_can_subscription_t* can_subscription = (low_can_subscription_t*)userdata; + if ((revents & EPOLLIN) != 0) + { + can_message_t cm; + utils::socketcan_bcm_t& s = can_subscription->get_socket(); + s >> cm; + + // Sure we got a valid CAN message ? + if(! cm.get_id() == 0 && ! cm.get_length() == 0) + {push_n_notify(cm);} + } + + // check if error or hangup + if ((revents & (EPOLLERR|EPOLLRDHUP|EPOLLHUP)) != 0) + { + sd_event_source_unref(event_source); + can_subscription->get_socket().close(); + } + return 0; +} + +///****************************************************************************** +/// +/// Subscription and unsubscription +/// +///*******************************************************************************/ + +static int make_subscription_unsubscription(struct afb_req request, std::shared_ptr<low_can_subscription_t>& can_subscription, std::map<int, std::shared_ptr<low_can_subscription_t> >& s, bool subscribe) +{ + /* Make the subscription or unsubscription to the event */ + if (((subscribe ? afb_req_subscribe : afb_req_unsubscribe)(request, s[can_subscription->get_index()]->get_event())) < 0) + { + ERROR("Operation goes wrong for signal: %s", can_subscription->get_name().c_str()); + return -1; + } + return 0; +} + +static int create_event_handle(std::shared_ptr<low_can_subscription_t>& can_subscription, std::map<int, std::shared_ptr<low_can_subscription_t> >& s) +{ + int sub_index = can_subscription->get_index(); + can_subscription->set_event(afb_daemon_make_event(can_subscription->get_name().c_str())); + s[sub_index] = can_subscription; + if (!afb_event_is_valid(s[sub_index]->get_event())) + { + ERROR("Can't create an event for %s, something goes wrong.", can_subscription->get_name().c_str()); + return -1; + } + return 0; +} + +/// @brief Will determine if it is needed or not to create the event handle and checks it to be sure that +/// we got a valid afb_event to get subscribe or unsubscribe. Then launch the subscription or unsubscription +/// against the application framework using that event handle. +static int subscribe_unsubscribe_signal(struct afb_req request, bool subscribe, std::shared_ptr<low_can_subscription_t>& can_subscription, std::map<int, std::shared_ptr<low_can_subscription_t> >& s) +{ + int ret = -1; + int sub_index = can_subscription->get_index(); + + if (can_subscription && s.find(sub_index) != s.end()) + { + if (!afb_event_is_valid(s[sub_index]->get_event()) && !subscribe) + { + NOTICE("Event isn't valid, no need to unsubscribed."); + ret = -1; + } + ret = 0; + } + else + { + /* Event doesn't exist , so let's create it */ + can_subscription->set_event({nullptr, nullptr}); + s[sub_index] = can_subscription; + ret = create_event_handle(can_subscription, s); + } + + // Check whether or not the event handler has been correctly created and + // make the subscription/unsubscription operation is so. + if (ret < 0) + return ret; + return make_subscription_unsubscription(request, can_subscription, s, subscribe); +} + +static int add_to_event_loop(std::shared_ptr<low_can_subscription_t>& can_subscription) +{ + struct sd_event_source* event_source = nullptr; + return ( sd_event_add_io(afb_daemon_get_event_loop(), + &event_source, + can_subscription->get_socket().socket(), + EPOLLIN, + read_message, + can_subscription.get())); +} + +static int subscribe_unsubscribe_diagnostic_messages(struct afb_req request, bool subscribe, std::vector<std::shared_ptr<diagnostic_message_t> > diagnostic_messages, struct event_filter_t& event_filter, std::map<int, std::shared_ptr<low_can_subscription_t> >& s) +{ + int rets = 0; + application_t& app = application_t::instance(); + diagnostic_manager_t& diag_m = app.get_diagnostic_manager(); + + for(const auto& sig : diagnostic_messages) + { + DiagnosticRequest* diag_req = new DiagnosticRequest(sig->build_diagnostic_request()); + event_filter.frequency = std::isnan(event_filter.frequency) ? sig->get_frequency() : event_filter.frequency; + std::shared_ptr<low_can_subscription_t> can_subscription; + + auto it = std::find_if(s.begin(), s.end(), [&sig](std::pair<int, std::shared_ptr<low_can_subscription_t> > sub){ return (! sub.second->get_diagnostic_message().empty());}); + can_subscription = it != s.end() ? + it->second : + std::make_shared<low_can_subscription_t>(low_can_subscription_t(event_filter)); + // If the requested diagnostic message isn't supported by the car then unsubcribe it + // no matter what we want, worse case will be a fail unsubscription but at least we don't + // poll a PID for nothing. + //TODO: Adding callback requesting ignition status: diag_req, sig.c_str(), false, diagnostic_message_t::decode_obd2_response, diagnostic_message_t::check_ignition_status, frequency); + if(sig->get_supported() && subscribe) + { + diag_m.add_recurring_request(diag_req, sig->get_name().c_str(), false, sig->get_decoder(), sig->get_callback(), event_filter.frequency); + if(can_subscription->create_rx_filter(sig) < 0) + {return -1;} + DEBUG("Signal: %s subscribed", sig->get_name().c_str()); + if(it == s.end() && add_to_event_loop(can_subscription) < 0) + { + diag_m.cleanup_request( + diag_m.find_recurring_request(*diag_req), true); + WARNING("signal: %s isn't supported. Canceling operation.", sig->get_name().c_str()); + return -1; + } + } + else + { + if(sig->get_supported()) + {DEBUG("%s cancelled due to unsubscribe", sig->get_name().c_str());} + else + { + WARNING("signal: %s isn't supported. Canceling operation.", sig->get_name().c_str()); + return -1; + } + } + int ret = subscribe_unsubscribe_signal(request, subscribe, can_subscription, s); + if(ret < 0) + return ret; + + rets++; + } + + return rets; +} + +static int subscribe_unsubscribe_can_signals(struct afb_req request, bool subscribe, std::vector<std::shared_ptr<can_signal_t> > can_signals, struct event_filter_t& event_filter, std::map<int, std::shared_ptr<low_can_subscription_t> >& s) +{ + int rets = 0; + for(const auto& sig: can_signals) + { + auto it = std::find_if(s.begin(), s.end(), [&sig](std::pair<int, std::shared_ptr<low_can_subscription_t> > sub){ return sub.second->get_can_signal() == sig; }); + std::shared_ptr<low_can_subscription_t> can_subscription; + if(it != s.end()) + { + can_subscription = it->second; + } + else + { + can_subscription = std::make_shared<low_can_subscription_t>(low_can_subscription_t(event_filter)); + if(can_subscription->create_rx_filter(sig) < 0) + {return -1;} + if(add_to_event_loop(can_subscription) < 0) + {return -1;} + } + + if(subscribe_unsubscribe_signal(request, subscribe, can_subscription, s) < 0) + {return -1;} + + rets++; + DEBUG("signal: %s subscribed", sig->get_name().c_str()); + } + return rets; +} + +/// +/// @brief subscribe to all signals in the vector signals +/// +/// @param[in] afb_req request : contain original request use to subscribe or unsubscribe +/// @param[in] subscribe boolean value used to chose between a subscription operation or an unsubscription +/// @param[in] signals - struct containing vectors with can_signal_t and diagnostic_messages to subscribe +/// +/// @return Number of correctly subscribed signal +/// +static int subscribe_unsubscribe_signals(struct afb_req request, bool subscribe, const struct utils::signals_found& signals, struct event_filter_t& event_filter) +{ + int rets = 0; + utils::signals_manager_t& sm = utils::signals_manager_t::instance(); + + std::lock_guard<std::mutex> subscribed_signals_lock(sm.get_subscribed_signals_mutex()); + std::map<int, std::shared_ptr<low_can_subscription_t> >& s = sm.get_subscribed_signals(); + + rets += subscribe_unsubscribe_diagnostic_messages(request, subscribe, signals.diagnostic_messages, event_filter, s); + rets += subscribe_unsubscribe_can_signals(request, subscribe, signals.can_signals, event_filter, s); + + return rets; +} + +static int one_subscribe_unsubscribe(struct afb_req request, bool subscribe, const std::string& tag, json_object* args) +{ + int ret = 0; + struct event_filter_t event_filter; + struct json_object *filter, *obj; + struct utils::signals_found sf; + + // computes the filter + if (json_object_object_get_ex(args, "filter", &filter)) + { + if (json_object_object_get_ex(filter, "frequency", &obj) + && (json_object_is_type(obj, json_type_double) || json_object_is_type(obj, json_type_int))) + { + event_filter.frequency = (float)json_object_get_double(obj); + ret += 1; + } + if (json_object_object_get_ex(filter, "min", &obj) + && (json_object_is_type(obj, json_type_double) || json_object_is_type(obj, json_type_int))) + { + event_filter.min = (float)json_object_get_double(obj); + ret += 2; + } + if (json_object_object_get_ex(filter, "max", &obj) + && (json_object_is_type(obj, json_type_double) || json_object_is_type(obj, json_type_int))) + { + event_filter.max = (float)json_object_get_double(obj); + ret += 4; + } + } + + // subscribe or unsubscribe + openxc_DynamicField search_key = build_DynamicField(tag); + sf = utils::signals_manager_t::instance().find_signals(search_key); + if (sf.can_signals.empty() && sf.diagnostic_messages.empty()) + NOTICE("No signal(s) found for %s.", tag.c_str()); + else + ret = subscribe_unsubscribe_signals(request, subscribe, sf, event_filter); + + return ret; +} + +static void do_subscribe_unsubscribe(struct afb_req request, bool subscribe) +{ + int i, n, rc, rc2; + struct json_object *args, *event, *x; + + args = afb_req_json(request); + if (args == NULL || !json_object_object_get_ex(args, "event", &event)) + { + rc = one_subscribe_unsubscribe(request, subscribe, "*", args); + } + else if (json_object_get_type(event) != json_type_array) + { + rc = one_subscribe_unsubscribe(request, subscribe, json_object_get_string(event), args); + } + else + { + rc = 0; + n = json_object_array_length(event); + for (i = 0 ; i < n ; i++) + { + x = json_object_array_get_idx(event, i); + rc2 = one_subscribe_unsubscribe(request, subscribe, json_object_get_string(x), args); + if (rc >= 0) + rc = rc2 >= 0 ? rc + rc2 : rc2; + } + } + + if (rc >= 0) + afb_req_success(request, NULL, NULL); + else + afb_req_fail(request, "error", NULL); +} + +void subscribe(struct afb_req request) +{ + do_subscribe_unsubscribe(request, true); +} + +void unsubscribe(struct afb_req request) +{ + do_subscribe_unsubscribe(request, false); +} diff --git a/low-can-binding/binding/low-can-hat.cpp b/low-can-binding/binding/low-can-hat.cpp new file mode 100644 index 00000000..7113b69a --- /dev/null +++ b/low-can-binding/binding/low-can-hat.cpp @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2015, 2016 "IoT.bzh" + * Author "Romain Forlot" <romain.forlot@iot.bzh> + * Author "Loic Collignon" <loic.collignon@iot.bzh> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "low-can-hat.hpp" +#include "low-can-subscription.hpp" + +#include <map> +#include <queue> +#include <mutex> +#include <vector> +#include <json-c/json.h> + +#include "application.hpp" +#include "../can/can-bus.hpp" + +extern "C" +{ + static int initv2(); + + static const struct afb_verb_v2 verbs[]= + { + { .verb= "subscribe", .callback= subscribe, .auth= NULL, .session= AFB_SESSION_NONE}, + { .verb= "unsubscribe", .callback= unsubscribe, .auth= NULL, .session= AFB_SESSION_NONE}, + { .verb= NULL, .callback= NULL, .auth= NULL, .session= 0} + }; + + const struct afb_binding_v2 afbBindingV2 { + .api = "low-can", + .specification = NULL, + .verbs = verbs, + .preinit = NULL, + .init = initv2, + .onevent = NULL, + .noconcurrency = 0 + }; + + /// @brief Initialize the binding. + /// + /// @param[in] service Structure which represent the Application Framework Binder. + /// + /// @return Exit code, zero if success. + static int initv2() + { + can_bus_t& can_bus_manager = application_t::instance().get_can_bus_manager(); + + can_bus_manager.set_can_devices(); + can_bus_manager.start_threads(); + + /// Initialize Diagnostic manager that will handle obd2 requests. + /// We pass by default the first CAN bus device to its Initialization. + /// TODO: be able to choose the CAN bus device that will be use as Diagnostic bus. + if(application_t::instance().get_diagnostic_manager().initialize()) + return 0; + + ERROR("There was something wrong with CAN device Initialization."); + return 1; + } +}; diff --git a/low-can-binding/binding/low-can-hat.hpp b/low-can-binding/binding/low-can-hat.hpp new file mode 100644 index 00000000..cf3d999e --- /dev/null +++ b/low-can-binding/binding/low-can-hat.hpp @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2015, 2016 "IoT.bzh" + * Author "Romain Forlot" <romain.forlot@iot.bzh> + * Author "Loic Collignon" <loic.collignon@iot.bzh> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <cstddef> +#include <map> +#include <string> +#include <memory> +#include <systemd/sd-event.h> + +extern "C" +{ + #define AFB_BINDING_VERSION 2 + #include <afb/afb-binding.h> +}; + +class low_can_subscription_t; + +void on_no_clients(std::shared_ptr<low_can_subscription_t> can_subscription, std::map<int, std::shared_ptr<low_can_subscription_t> >& s); +void on_no_clients(std::shared_ptr<low_can_subscription_t> can_subscription, uint32_t pid, std::map<int, std::shared_ptr<low_can_subscription_t> >& s); +int read_message(sd_event_source *s, int fd, uint32_t revents, void *userdata); + +void subscribe(struct afb_req request); +void unsubscribe(struct afb_req request);
\ No newline at end of file diff --git a/low-can-binding/binding/low-can-subscription.cpp b/low-can-binding/binding/low-can-subscription.cpp new file mode 100644 index 00000000..5488cc53 --- /dev/null +++ b/low-can-binding/binding/low-can-subscription.cpp @@ -0,0 +1,306 @@ +/* + * Copyright (C) 2015, 2016 "IoT.bzh" + * Author "Romain Forlot" <romain.forlot@iot.bzh> + * Author "Loic Collignon" <loic.collignon@iot.bzh> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "low-can-hat.hpp" + +#include "low-can-subscription.hpp" +#include "application.hpp" +#include "canutil/write.h" + +low_can_subscription_t::low_can_subscription_t() + : index_{-1}, + event_filter_{event_filter_t()}, + socket_{} +{} + +low_can_subscription_t::low_can_subscription_t(struct event_filter_t event_filter) + : event_filter_{event_filter} +{} + +low_can_subscription_t::low_can_subscription_t( low_can_subscription_t&& s) + : index_{s.index_}, + event_filter_{s.event_filter_}, + socket_{std::move(s.socket_)} +{} + +low_can_subscription_t& low_can_subscription_t::operator=(const low_can_subscription_t& s) +{ + socket_ = std::move(s.socket_); + return *this; +} + +low_can_subscription_t::~low_can_subscription_t() +{ + socket_.close(); +} + +low_can_subscription_t::operator bool() const +{ + return ((can_signal_ != nullptr || ! diagnostic_message_.empty()) && afb_event_is_valid(event_)); +} + +struct afb_event& low_can_subscription_t::get_event() +{ + return event_; +} + +int low_can_subscription_t::get_index() const +{ + return index_; +} + +const std::shared_ptr<can_signal_t> low_can_subscription_t::get_can_signal() const +{ + return can_signal_; +} + +const std::vector<std::shared_ptr<diagnostic_message_t> > low_can_subscription_t::get_diagnostic_message() const +{ + return diagnostic_message_; +} + +/// @brief Retrieve a diagnostic_message subscribed from a pid +/// +/// @param[in] pid - Diagnostic messages PID to search for +/// +/// @return shared_ptr diagnostic_message_ if found and nullptr if not found +const std::shared_ptr<diagnostic_message_t> low_can_subscription_t::get_diagnostic_message(uint32_t pid) const +{ + for(const auto& diag: diagnostic_message_) + { + if(diag->get_pid() == pid) + { + return diag; + } + } + return nullptr; +} + +/// @brief Retrieve a diagnostic message search from its name +/// +/// @return shared_ptr diagnostic_message_ if found and nullptr if not found +const std::shared_ptr<diagnostic_message_t> low_can_subscription_t::get_diagnostic_message(const std::string& name) const +{ + for(const auto& diag: diagnostic_message_) + { + if(diag->get_name() == name) + { + return diag; + } + } + return nullptr; +} + +/// @brief Return the CAN signal name and empty string if not found +/// or no CAN signal subscribed +const std::string low_can_subscription_t::get_name() const +{ + if (can_signal_ != nullptr) + return can_signal_->get_name(); + + return ""; +} + +/// @brief Return name from a diagnostic message from a PID +/// +/// @param[in] pid - Diagnostic message PID +const std::string low_can_subscription_t::get_name(uint32_t pid) const +{ + if (!diagnostic_message_.empty()) + return get_diagnostic_message(pid)->get_name() ; + + return ""; +} + +float low_can_subscription_t::get_frequency() const +{ + return event_filter_.frequency; +} + +float low_can_subscription_t::get_min() const +{ + return event_filter_.min; +} + +float low_can_subscription_t::get_max() const +{ + return event_filter_.max; +} + +utils::socketcan_bcm_t& low_can_subscription_t::get_socket() +{ + return socket_; +} + +void low_can_subscription_t::set_event(struct afb_event event) +{ + event_ = event; +} + +void low_can_subscription_t::set_frequency(float freq) +{ + event_filter_.frequency = freq; +} + +void low_can_subscription_t::set_min(float min) +{ + event_filter_.min = min; +} + +void low_can_subscription_t::set_max(float max) +{ + event_filter_.max = max; +} + +/// @brief Based upon which object is subscribed CAN signal or diagnostic message +/// this will open the socket with the required CAN bus device name. +/// +/// @return INVALID_SOCKET on failure else positive integer +int low_can_subscription_t::open_socket() +{ + int ret = 0; + if(! socket_) + { + if( can_signal_ != nullptr) + {ret = socket_.open(can_signal_->get_message()->get_bus_device_name());} + else if (! diagnostic_message_ .empty()) + {ret = socket_.open(application_t::instance().get_diagnostic_manager().get_bus_device_name());} + index_ = (int)socket_.socket(); + } + return ret; +} + +/// @brief Build a BCM message head but don't set can_frame. +/// +/// @return a simple_bcm_msg with the msg_head parts set and can_frame +/// zeroed. +struct utils::simple_bcm_msg low_can_subscription_t::make_bcm_head(uint32_t can_id, uint32_t flags, const struct timeval& timeout, const struct timeval& frequency_thinning) const +{ + struct utils::simple_bcm_msg bcm_msg; + + memset(&bcm_msg, 0, sizeof(bcm_msg)); + + bcm_msg.msg_head.opcode = RX_SETUP; + bcm_msg.msg_head.can_id = can_id; + bcm_msg.msg_head.flags = flags; + bcm_msg.msg_head.ival1.tv_sec = timeout.tv_sec ; + bcm_msg.msg_head.ival1.tv_usec = timeout.tv_usec; + bcm_msg.msg_head.ival2.tv_sec = frequency_thinning.tv_sec ; + bcm_msg.msg_head.ival2.tv_usec = frequency_thinning.tv_usec; + + return bcm_msg; +} + +/// @brief Take an existing simple_bcm_msg struct and add a can_frame to it. +/// Only possible for now to add 1 uniq can_frame, it isn't possible to build +/// a multiplexed message with several can_frame. +void low_can_subscription_t::add_bcm_frame(const struct can_frame& cfd, struct utils::simple_bcm_msg& bcm_msg) const +{ + for(int i=0; i < CAN_MAX_DLEN; i++) + { + if(cfd.data[i] != 0) + { + bcm_msg.msg_head.nframes = 1; + bcm_msg.frames = cfd; + return; + } + } +} + +/// @brief Create a RX_SETUP receive job used by the BCM socket for a CAN signal +/// subscription +/// +/// @return 0 if ok else -1 +int low_can_subscription_t::create_rx_filter(std::shared_ptr<can_signal_t> sig) +{ + can_signal_= sig; + + struct can_frame cfd; + memset(&cfd, 0, sizeof(cfd)); + + float val = (float)(1 << can_signal_->get_bit_size()) - 1; + bitfield_encode_float(val, + can_signal_->get_bit_position(), + can_signal_->get_bit_size(), + can_signal_->get_factor(), + can_signal_->get_offset(), + cfd.data, + CAN_MAX_DLEN); + + struct timeval freq, timeout = {0, 0}; + frequency_clock_t f = std::isnan(event_filter_.frequency) ? can_signal_->get_frequency() : frequency_clock_t(event_filter_.frequency); + freq = f.get_timeval_from_period(); + + utils::simple_bcm_msg bcm_msg = make_bcm_head(can_signal_->get_message()->get_id(), SETTIMER|RX_NO_AUTOTIMER, timeout, freq); + add_bcm_frame(cfd, bcm_msg); + + return create_rx_filter(bcm_msg); +} + +/// @brief Create a RX_SETUP receive job used by the BCM socket for a +/// diagnostic message subscription. +/// +/// @return 0 if ok else -1 +int low_can_subscription_t::create_rx_filter(std::shared_ptr<diagnostic_message_t> sig) +{ + diagnostic_message_.push_back(sig); + + struct timeval freq = frequency_clock_t(event_filter_.frequency).get_timeval_from_period(); + //struct timeval timeout = frequency_clock_t(10).get_timeval_from_period(); + struct timeval timeout = {0,0}; + + utils::simple_bcm_msg bcm_msg = make_bcm_head(OBD2_FUNCTIONAL_BROADCAST_ID, SETTIMER|RX_NO_AUTOTIMER|RX_FILTER_ID, timeout, freq); + return create_rx_filter(bcm_msg); +} + +/// @brief Create a RX_SETUP receive job used by the BCM socket directly from +/// a simple_bcm_msg. You will not use this method directly but rather use the +/// two previous method with can_signal_t or diagnostic_message_t object. +/// +/// If the CAN arbitration ID is the OBD2 functional broadcast id the subscribed +/// to the 8 classics OBD2 functional response ID +/// +/// @return 0 if ok else -1 +int low_can_subscription_t::create_rx_filter(utils::simple_bcm_msg& bcm_msg) +{ + // Make sure that socket has been opened. + if(open_socket() < 0) + {return -1;} + + // If it isn't an OBD2 CAN ID then just add a simple RX_SETUP job + // else monitor all standard 8 CAN OBD2 ID response. + if(bcm_msg.msg_head.can_id != OBD2_FUNCTIONAL_BROADCAST_ID) + { + socket_ << bcm_msg; + if(! socket_) + return -1; + } + else + { + for(uint8_t i = 0; i < 8; i++) + { + bcm_msg.msg_head.can_id = OBD2_FUNCTIONAL_RESPONSE_START + i; + + socket_ << bcm_msg; + if(! socket_) + return -1; + } + } + + return 0; +}
\ No newline at end of file diff --git a/low-can-binding/binding/low-can-subscription.hpp b/low-can-binding/binding/low-can-subscription.hpp new file mode 100644 index 00000000..0ad7e3a2 --- /dev/null +++ b/low-can-binding/binding/low-can-subscription.hpp @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2015, 2016 "IoT.bzh" + * Author "Romain Forlot" <romain.forlot@iot.bzh> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + #pragma once + +#include <string> +#include <cmath> +#include <utility> + +#include "../can/can-signals.hpp" +#include "../diagnostic/diagnostic-message.hpp" +#include "../utils/socketcan-bcm.hpp" + +/// @brief Filtering values. Theses values has to be tested into +/// can_bus_t::apply_filter method. +struct event_filter_t +{ + float frequency; ///< frequency - Maximum frequency which will be received and pushed a subscribed event. + float min; ///< min - Minimum value that the signal don't have to go below to be pushed. + float max; ///< max - Maximum value that the signal don't have to go above to be pushed. + event_filter_t() : frequency{NAN}, min{NAN}, max{NAN} {} +}; + +/// @brief A subscription object used has a context that handle all needed values to describe a subscription +/// to the low-can binding. It can holds a CAN signal or diagnostic message. Diagnostic message for OBD2 is a kind +/// of special because there is only 1 listener to retrieve OBD2 requests. So it's needed that all diagnostic messages +/// subscriptions is to be in 1 object. +class low_can_subscription_t +{ +private: + int index_; ///< index_ - index number is the socket (int) casted + struct afb_event event_; ///< event_ - application framework event used to push on client + + /// Signal part + std::shared_ptr<can_signal_t> can_signal_; ///< can_signal_ - the CAN signal subscribed + std::vector<std::shared_ptr<diagnostic_message_t> > diagnostic_message_; ///< diagnostic_message_ - diagnostic messages meant to received OBD2 responses. + /// normal diagnostic request and response not tested for now. + + /// Filtering part + struct event_filter_t event_filter_; ///< event_filter_ - filtering values applied to a subscription + + utils::socketcan_bcm_t socket_; ///< socket_ - socket_ that receives CAN messages. +public: + low_can_subscription_t(); + low_can_subscription_t(struct event_filter_t event_filter); + low_can_subscription_t(const low_can_subscription_t& s) = delete; + low_can_subscription_t(low_can_subscription_t&& s); + ~low_can_subscription_t(); + + low_can_subscription_t& operator=(const low_can_subscription_t& s); + explicit operator bool() const; + + int get_index() const; + struct afb_event& get_event(); + const std::shared_ptr<can_signal_t> get_can_signal() const; + const std::shared_ptr<diagnostic_message_t> get_diagnostic_message(uint32_t pid) const; + const std::vector<std::shared_ptr<diagnostic_message_t> > get_diagnostic_message() const; + const std::shared_ptr<diagnostic_message_t> get_diagnostic_message(const std::string& name) const; + const std::string get_name() const; + const std::string get_name(uint32_t pid) const; + float get_frequency() const; + float get_min() const; + float get_max() const; + utils::socketcan_bcm_t& get_socket(); + + void set_event(struct afb_event event); + void set_frequency(float freq); + void set_min(float min); + void set_max(float max); + + struct utils::simple_bcm_msg make_bcm_head(uint32_t can_id, uint32_t flags, const struct timeval& timeout, const struct timeval& frequency_thinning) const; + void add_bcm_frame(const struct can_frame& cfd, struct utils::simple_bcm_msg& bcm_msg) const; + int open_socket(); + int create_rx_filter(std::shared_ptr<can_signal_t> sig); + int create_rx_filter(std::shared_ptr<diagnostic_message_t> sig); + int create_rx_filter(utils::simple_bcm_msg& bcm_msg); +}; |