diff options
author | Romain Forlot <romain.forlot@iot.bzh> | 2019-11-26 16:18:36 +0100 |
---|---|---|
committer | Romain Forlot <romain.forlot@iot.bzh> | 2019-11-28 16:11:46 +0100 |
commit | 68d8bc019fab3e73654a330baf6b8dd7c11859ca (patch) | |
tree | e2a01ddfb0d640e1237ccae06e7be5e922cb237b /low-can-binding | |
parent | 006598ee46a227f52bcac7be172cd45a8a364aff (diff) |
Add feature to build messages and fix some functions
Allows to build a message (J1939,BCM) with a signal and a value.
Bug-AGL: SPEC-2386
Bug-AGL: SPEC-2976
Signed-off-by: Arthur Guyader <arthur.guyader@iot.bzh>
Change-Id: Iadca13a927ff83f713f39da441c88356695a1285
Signed-off-by: Romain Forlot <romain.forlot@iot.bzh>
Diffstat (limited to 'low-can-binding')
22 files changed, 524 insertions, 133 deletions
diff --git a/low-can-binding/binding/low-can-cb.cpp b/low-can-binding/binding/low-can-cb.cpp index dbeaa555..9c21b675 100644 --- a/low-can-binding/binding/low-can-cb.cpp +++ b/low-can-binding/binding/low-can-cb.cpp @@ -197,7 +197,10 @@ static int subscribe_unsubscribe_diagnostic_messages(afb_req_t request, event_filter.frequency = event_filter.frequency == 0 ? 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());}); + 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)); @@ -250,7 +253,10 @@ static int subscribe_unsubscribe_signals(afb_req_t request, int rets = 0; for(const auto& sig: signals) { - auto it = std::find_if(s.begin(), s.end(), [&sig, &event_filter](std::pair<int, std::shared_ptr<low_can_subscription_t> > sub){ return sub.second->is_signal_subscription_corresponding(sig, event_filter) ; }); + auto it = std::find_if(s.begin(), s.end(), [&sig, &event_filter](std::pair<int, std::shared_ptr<low_can_subscription_t> > sub) + { + return sub.second->is_signal_subscription_corresponding(sig, event_filter) ; + }); std::shared_ptr<low_can_subscription_t> can_subscription; if(it != s.end()) {can_subscription = it->second;} @@ -374,14 +380,14 @@ static int process_one_subscribe_args(afb_req_t request, bool subscribe, json_ob // 2 cases : ID(PGN) and event - json_bool test_event = json_object_object_get_ex(args,"event",&event); + json_object_object_get_ex(args,"event",&event); json_bool test_id = json_object_object_get_ex(args,"id",&id); if(!test_id) { - json_object_object_get_ex(args,"pgn",&id); + test_id = json_object_object_get_ex(args,"pgn",&id); } - if( args == NULL || (!test_event && !id)) + if( args == NULL || (id && ((std::string)json_object_get_string(id)).compare("*") == 0)) { rc = one_subscribe_unsubscribe_events(request, subscribe, "*", args); } @@ -467,55 +473,122 @@ void unsubscribe(afb_req_t request) do_subscribe_unsubscribe(request, false); } -static int send_frame(struct canfd_frame& cfd, const std::string& bus_name) +/* +static int send_frame(struct canfd_frame& cfd, const std::string& bus_name, socket_type type) { - if(bus_name.empty()) { + if(bus_name.empty()) + { return -1; } std::map<std::string, std::shared_ptr<low_can_subscription_t> >& cd = application_t::instance().get_can_devices(); if( cd.count(bus_name) == 0) - {cd[bus_name] = std::make_shared<low_can_subscription_t>(low_can_subscription_t());} + { + cd[bus_name] = std::make_shared<low_can_subscription_t>(low_can_subscription_t()); + } - return low_can_subscription_t::tx_send(*cd[bus_name], cfd, bus_name); -} -static void write_raw_frame(afb_req_t request, const std::string& bus_name, json_object *json_value) + if(type == socket_type::BCM) + { + return low_can_subscription_t::tx_send(*cd[bus_name], cfd, bus_name); + } + else{ + return -1; + } +} +*/ +static int send_message(message_t *message, const std::string& bus_name, socket_type type) { - struct canfd_frame cfd; - struct json_object *can_data = nullptr; + if(bus_name.empty()) + { + return -1; + } - ::memset(&cfd, 0, sizeof(cfd)); + std::map<std::string, std::shared_ptr<low_can_subscription_t> >& cd = application_t::instance().get_can_devices(); - if(wrap_json_unpack(json_value, "{si, si, so !}", - "can_id", &cfd.can_id, - "can_dlc", &cfd.len, - "can_data", &can_data)) + if( cd.count(bus_name) == 0) { - afb_req_fail(request, "Invalid", "Frame object malformed"); - return; + cd[bus_name] = std::make_shared<low_can_subscription_t>(low_can_subscription_t()); + } + + + if(type == socket_type::BCM) + { + return low_can_subscription_t::tx_send(*cd[bus_name], message, bus_name); + } + else + { + return -1; } +} + - if(cfd.len <= 8 && cfd.len > 0) +static void write_raw_frame(afb_req_t request, const std::string& bus_name, message_t *message, struct json_object *can_data, socket_type type) +{ + if((message->get_length() <= 8 && message->get_length() > 0 && type == socket_type::BCM) +#ifdef USE_FEATURE_J1939 + || (message->get_length() < J1939_MAX_DLEN && type == socket_type::J1939) +#endif + ) { - for (int i = 0 ; i < cfd.len ; i++) + + std::vector<uint8_t> data; + for (int i = 0 ; i < message->get_length() ; i++) { struct json_object *one_can_data = json_object_array_get_idx(can_data, i); - cfd.data[i] = (json_object_is_type(one_can_data, json_type_int)) ? - (uint8_t)json_object_get_int(one_can_data) : 0; + data.push_back((json_object_is_type(one_can_data, json_type_int)) ? + (uint8_t)json_object_get_int(one_can_data) : 0); } + message->set_data(data); } else { - afb_req_fail(request, "Invalid", "Data array must hold 1 to 8 values."); + if(type == socket_type::BCM) + { + afb_req_fail(request, "Invalid", "Data array must hold 1 to 8 values."); + } + else + { + afb_req_fail(request, "Invalid", "Invalid socket type"); + } return; } - if(! send_frame(cfd, application_t::instance().get_can_bus_manager().get_can_device_name(bus_name))) + if(! send_message(message, application_t::instance().get_can_bus_manager().get_can_device_name(bus_name),type)) + { afb_req_success(request, nullptr, "Message correctly sent"); + } else + { afb_req_fail(request, "Error", "sending the message. See the log for more details."); + } +} + +static void write_frame(afb_req_t request, const std::string& bus_name, json_object *json_value) +{ + message_t *message; + int id; + int length; + struct json_object *can_data = nullptr; + std::vector<uint8_t> data; + + AFB_DEBUG("JSON content %s",json_object_get_string(json_value)); + + if(!wrap_json_unpack(json_value, "{si, si, so !}", + "can_id", &id, + "can_dlc", &length, + "can_data", &can_data)) + { + message = new can_message_t(CANFD_MAX_DLEN,(uint32_t)id,(uint32_t)length,message_format_t::STANDARD,false,0,data,0); + write_raw_frame(request,bus_name,message,can_data,socket_type::BCM); + } + else + { + afb_req_fail(request, "Invalid", "Frame object malformed"); + return; + } + delete message; } static void write_signal(afb_req_t request, const std::string& name, json_object *json_value) @@ -548,11 +621,39 @@ static void write_signal(afb_req_t request, const std::string& name, json_object encoder(*sig, dynafield_value, &send) : encoder_t::encode_DynamicField(*sig, dynafield_value, &send); - cfd = encoder_t::build_frame(sig, value); - if(! send_frame(cfd, sig->get_message()->get_bus_device_name()) && send) + socket_type type = socket_type::INVALID; + + if(sig->get_message()->is_j1939()) + { + type = socket_type::J1939; + } + else + { + type = socket_type::BCM; + } + +// cfd = encoder_t::build_frame(sig, value); + message_t *message = encoder_t::build_message(sig,value); + + if(! send_message(message, sig->get_message()->get_bus_device_name(), type) && send) + { afb_req_success(request, nullptr, "Message correctly sent"); + } else + { afb_req_fail(request, "Error", "Sending the message. See the log for more details."); + } + + if(sig->get_message()->is_j1939()) + { +#ifdef USE_FEATURE_J1939 + delete (j1939_message_t*) message; +#endif + } + else + { + delete (can_message_t*) message; + } } void write(afb_req_t request) @@ -566,7 +667,7 @@ void write(afb_req_t request) if (args != NULL && ! wrap_json_unpack(args, "{ss, so !}", "bus_name", &name, "frame", &json_value)) - write_raw_frame(request, name, json_value); + write_frame(request, name, json_value); // Search signal then encode value. else if(args != NULL && @@ -683,9 +784,13 @@ void list(afb_req_t request) rc = -1; if (rc >= 0) + { afb_req_success(request, ans, NULL); + } else + { afb_req_fail(request, "error", NULL); + } } /// @brief Initialize the binding. diff --git a/low-can-binding/binding/low-can-subscription.cpp b/low-can-binding/binding/low-can-subscription.cpp index c2f31a03..b31fe48e 100644 --- a/low-can-binding/binding/low-can-subscription.cpp +++ b/low-can-binding/binding/low-can-subscription.cpp @@ -427,9 +427,9 @@ int low_can_subscription_t::create_rx_filter_bcm(low_can_subscription_t &subscri // If it's not an OBD2 CAN ID then just add a simple RX_SETUP job // else monitor all standard 8 CAN OBD2 ID response. - std::shared_ptr<can_message_t> msg = std::make_shared<can_message_t>(); + can_message_t msg = can_message_t(); - msg->set_bcm_msg(bcm_msg); + msg.set_bcm_msg(bcm_msg); if(bcm_msg.msg_head.can_id != OBD2_FUNCTIONAL_BROADCAST_ID) { @@ -442,7 +442,7 @@ int low_can_subscription_t::create_rx_filter_bcm(low_can_subscription_t &subscri for(uint8_t i = 0; i < 8; i++) { bcm_msg.msg_head.can_id = OBD2_FUNCTIONAL_RESPONSE_START + i; - msg->set_bcm_msg(bcm_msg); + msg.set_bcm_msg(bcm_msg); subscription.socket_->write_message(msg); if(! subscription.socket_) return -1; @@ -455,22 +455,23 @@ int low_can_subscription_t::create_rx_filter_bcm(low_can_subscription_t &subscri /// send a message /// /// @return 0 if ok else -1 -int low_can_subscription_t::tx_send(low_can_subscription_t &subscription, struct canfd_frame& cfd, const std::string& bus_name) +int low_can_subscription_t::tx_send(low_can_subscription_t &subscription, message_t *message, const std::string& bus_name) { - struct bcm_msg bcm_msg = subscription.make_bcm_head(TX_SEND, cfd.can_id); + can_message_t *cm = static_cast<can_message_t*>(message); + + struct bcm_msg bcm_msg = subscription.make_bcm_head(TX_SEND, cm->get_id(),cm->get_flags()); + canfd_frame cfd = cm->convert_to_canfd_frame(); subscription.add_one_bcm_frame(cfd, bcm_msg); if(subscription.open_socket(subscription, bus_name) < 0) {return -1;} - - std::shared_ptr<can_message_t> msg = std::make_shared<can_message_t>(); - - msg->set_bcm_msg(bcm_msg); - - subscription.socket_->write_message(msg); + cm->set_bcm_msg(bcm_msg); + subscription.socket_->write_message(*cm); if(! subscription.socket_.get()) - return -1; + { + 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 index 61c354d1..5ea1cf17 100644 --- a/low-can-binding/binding/low-can-subscription.hpp +++ b/low-can-binding/binding/low-can-subscription.hpp @@ -101,5 +101,5 @@ public: static int create_rx_filter_j1939(low_can_subscription_t &subscription, std::shared_ptr<signal_t> sig); static int create_rx_filter_bcm(low_can_subscription_t &subscription, bcm_msg& bcm_msg); - static int tx_send(low_can_subscription_t &subscription, struct canfd_frame& cfd, const std::string& bus_name); + static int tx_send(low_can_subscription_t &subscription, message_t *message, const std::string& bus_name); }; diff --git a/low-can-binding/can/can-encoder.cpp b/low-can-binding/can/can-encoder.cpp index a11dedfc..ccd49722 100644 --- a/low-can-binding/can/can-encoder.cpp +++ b/low-can-binding/can/can-encoder.cpp @@ -51,10 +51,122 @@ const canfd_frame encoder_t::build_frame(const std::shared_ptr<signal_t>& signal cf.data, cf.len); } - return cf; } + +/** + * @brief Allows to build a single frame message with correct data to be send + * + * @param signal The CAN signal to write, including the bit position and bit size. + * @param value The encoded integer value to write in the CAN signal. + * @param message A single frame message to complete + * @return message_t* The message that is generated + */ +message_t* encoder_t::build_one_frame_message(const std::shared_ptr<signal_t>& signal, uint64_t value, message_t *message) +{ + signal->set_last_value((float)value); + uint8_t data_tab[message->get_length()]; + ::memset(&data_tab, 0, sizeof(data_tab)); + std::vector<uint8_t> data; + + for(const auto& sig: signal->get_message()->get_signals()) + { + float last_value = sig->get_last_value(); + bitfield_encode_float(last_value, + sig->get_bit_position(), + sig->get_bit_size(), + sig->get_factor(), + sig->get_offset(), + data_tab, + (uint8_t)message->get_length()); + } + + for (size_t i = 0; i < (uint8_t) message->get_length(); i++) + { + data.push_back(data_tab[i]); + } + + message->set_data(data); + return message; +} + +/** + * @brief Allows to build a multi frame message with correct data to be send + * + * @param signal The CAN signal to write, including the bit position and bit size. + * @param value The encoded integer value to write in the CAN signal. + * @param message A multi frame message to complete + * @return message_t* The message that is generated + */ +message_t* encoder_t::build_multi_frame_message(const std::shared_ptr<signal_t>& signal, uint64_t value, message_t *message) +{ + signal->set_last_value((float)value); + std::vector<uint8_t> data; + + uint32_t msgs_len = signal->get_message()->get_length(); // multi frame - number of bytes + int number_of_frame = (int) msgs_len / 8; + + uint8_t data_tab[number_of_frame][8] = {0}; + + for(const auto& sig: signal->get_message()->get_signals()) + { + + int frame_position = (int) sig->get_bit_position() / 64; + float last_value = sig->get_last_value(); + uint8_t bit_position = sig->get_bit_position() - ((uint8_t)(64 * frame_position)); + + bitfield_encode_float(last_value, + bit_position, + sig->get_bit_size(), + sig->get_factor(), + sig->get_offset(), + data_tab[frame_position], + 8); + } + + for (size_t i = 0; i < number_of_frame; i++) + { + for(size_t j = 0; j < 8 ; j++) + { + data.push_back(data_tab[i][j]); + } + } + + message->set_data(data); + return message; +} + +/** + * @brief Allows to build a message_t with correct data to be send + * + * @param signal The CAN signal to write, including the bit position and bit size. + * @param value The encoded integer value to write in the CAN signal. + * @return message_t* The message that is generated + */ +message_t* encoder_t::build_message(const std::shared_ptr<signal_t>& signal, uint64_t value) +{ + message_t *message; + std::vector<uint8_t> data; + if(signal->get_message()->is_fd()) + { + message = new can_message_t(CANFD_MAX_DLEN,signal->get_message()->get_id(),CANFD_MAX_DLEN,signal->get_message()->get_format(),false,CAN_FD_FRAME,data,0); + return build_one_frame_message(signal,value,message); + } +#ifdef USE_FEATURE_J1939 + else if(signal->get_message()->is_j1939()) + { + message = new j1939_message_t(J1939_MAX_DLEN,signal->get_message()->get_length(),signal->get_message()->get_format(),data,0,J1939_NO_NAME,signal->get_message()->get_id(),J1939_NO_ADDR); + return build_multi_frame_message(signal,value,message); + } +#endif + else + { + message = new can_message_t(CAN_MAX_DLEN,signal->get_message()->get_id(),CAN_MAX_DLEN,signal->get_message()->get_format(),false,0,data,0); + return build_one_frame_message(signal,value,message); + } +} + /// @brief Encode a boolean into an integer, fit for a CAN signal bitfield. /// /// This is a shortcut for encodeDynamicField(CanSignal*, openxc_DynamicField*, diff --git a/low-can-binding/can/can-encoder.hpp b/low-can-binding/can/can-encoder.hpp index 6ae786a1..c37521f4 100644 --- a/low-can-binding/can/can-encoder.hpp +++ b/low-can-binding/can/can-encoder.hpp @@ -20,11 +20,18 @@ #include "signals.hpp" #include "message/can-message.hpp" #include "openxc.pb.h" +#include "message/can-message.hpp" +#ifdef USE_FEATURE_J1939 +#include "message/j1939-message.hpp" +#endif class encoder_t { public: static const canfd_frame build_frame(const std::shared_ptr<signal_t>& signal, uint64_t value); + static message_t* build_message(const std::shared_ptr<signal_t>& signal, uint64_t value); + static message_t* build_one_frame_message(const std::shared_ptr<signal_t>& signal, uint64_t value, message_t *message); + static message_t* build_multi_frame_message(const std::shared_ptr<signal_t>& signal, uint64_t value, message_t *message); static uint64_t encode_state(const signal_t& signal, const std::string& value, bool* send); static uint64_t encode_boolean(const signal_t& signal, bool value, bool* send); static uint64_t encode_number(const signal_t& signal, float value, bool* send); diff --git a/low-can-binding/can/message-definition.cpp b/low-can-binding/can/message-definition.cpp index efc72f07..064b2c17 100644 --- a/low-can-binding/can/message-definition.cpp +++ b/low-can-binding/can/message-definition.cpp @@ -102,3 +102,13 @@ void message_definition_t::set_last_value(std::shared_ptr<message_t> m) { last_value_= m->get_data_vector(); } + +uint32_t message_definition_t::get_length() const +{ + return length_; +} + +message_format_t message_definition_t::get_format() const +{ + return format_; +}
\ No newline at end of file diff --git a/low-can-binding/can/message-definition.hpp b/low-can-binding/can/message-definition.hpp index 1773e6b8..f39bb71e 100644 --- a/low-can-binding/can/message-definition.hpp +++ b/low-can-binding/can/message-definition.hpp @@ -86,6 +86,8 @@ public: bool is_fd() const; bool is_j1939() const; std::vector<std::shared_ptr<signal_t>>& get_signals(); + uint32_t get_length() const; + message_format_t get_format() const; void set_parent(std::shared_ptr<message_set_t> parent); void set_last_value(std::shared_ptr<message_t> m); diff --git a/low-can-binding/can/message/can-message.cpp b/low-can-binding/can/message/can-message.cpp index b012bbe5..945c0ba7 100644 --- a/low-can-binding/can/message/can-message.cpp +++ b/low-can-binding/can/message/can-message.cpp @@ -28,22 +28,20 @@ /// can_message_t::can_message_t() : message_t(), - maxdlen_{0}, id_{0}, rtr_flag_{false}, flags_{0} {} -can_message_t::can_message_t(uint8_t maxdlen, +can_message_t::can_message_t(uint32_t maxdlen, uint32_t id, - uint8_t length, + uint32_t length, message_format_t format, bool rtr_flag, - uint8_t flags, + uint32_t flags, std::vector<uint8_t>& data, uint64_t timestamp) - : message_t(length, format, data, timestamp), - maxdlen_{maxdlen}, + : message_t(maxdlen, length, format, data, timestamp), id_{id}, rtr_flag_{rtr_flag}, flags_{flags} @@ -86,7 +84,8 @@ bool can_message_t::is_correct_to_send() /// @return A can_message_t object fully initialized with canfd_frame values. std::shared_ptr<can_message_t> can_message_t::convert_from_frame(const struct canfd_frame& frame, size_t nbytes, uint64_t timestamp) { - uint8_t maxdlen = 0, length = 0, flags = 0; + uint32_t maxdlen = 0, length = 0; + uint8_t flags = 0; uint32_t id; message_format_t format; bool rtr_flag; @@ -164,6 +163,47 @@ std::shared_ptr<can_message_t> can_message_t::convert_from_frame(const struct ca return std::make_shared<can_message_t>(can_message_t(maxdlen, id, length, format, rtr_flag, flags, data, timestamp)); } +/// @brief Take all initialized class members and build a +/// canfd_frame struct that can be use to send a CAN message over +/// the bus. +/// +/// @return canfd_frame struct built from class members. +struct canfd_frame can_message_t::convert_to_canfd_frame() +{ + canfd_frame frame; + + if(is_correct_to_send()) + { + frame.can_id = get_id(); + frame.len = (uint8_t) get_length(); + ::memcpy(frame.data, get_data(), length_); + } + else + AFB_ERROR("can_message_t not correctly initialized to be sent"); + + return frame; +} + +/// @brief Take all initialized class members and build a +/// can_frame struct that can be use to send a CAN message over +/// the bus. +/// +/// @return can_frame struct built from class members. +struct can_frame can_message_t::convert_to_can_frame() +{ + can_frame frame; + + if(is_correct_to_send()) + { + frame.can_id = get_id(); + frame.can_dlc = (uint8_t) get_length(); + ::memcpy(frame.data, get_data(), length_); + } + else + AFB_ERROR("can_message_t not correctly initialized to be sent"); + + return frame; +} bool can_message_t::is_set() { @@ -192,3 +232,7 @@ void can_message_t::set_bcm_msg(struct bcm_msg bcm_msg) bcm_msg_ = bcm_msg; } +uint32_t can_message_t::get_flags() +{ + return flags_; +}
\ No newline at end of file diff --git a/low-can-binding/can/message/can-message.hpp b/low-can-binding/can/message/can-message.hpp index df0d2a19..7625cc17 100644 --- a/low-can-binding/can/message/can-message.hpp +++ b/low-can-binding/can/message/can-message.hpp @@ -26,24 +26,26 @@ /// buffers. It is a wrapper of a can_frame struct with some sugar around it for binding purposes. class can_message_t : public message_t { private: - uint8_t maxdlen_; ///< maxdlen_ - Max data length deduce from number of bytes read from the socket.*/ uint32_t id_; ///< id_ - The ID of the message. */ bool rtr_flag_; ///< rtr_flag_ - Telling if the frame has RTR flag positionned. Then frame hasn't data field*/ - uint8_t flags_; ///< flags_ - flags of a CAN FD frame. Needed if we catch FD frames.*/ + uint32_t flags_; ///< flags_ - flags of a CAN FD frame. Needed if we catch FD frames.*/ struct bcm_msg bcm_msg_; public: can_message_t(); - can_message_t(uint8_t maxdlen, uint32_t id, uint8_t length, message_format_t format, bool rtr_flag_, uint8_t flags, std::vector<uint8_t>& data, uint64_t timestamp); + can_message_t(uint32_t maxdlen, uint32_t id, uint32_t length, message_format_t format, bool rtr_flag_, uint32_t flags, std::vector<uint8_t>& data, uint64_t timestamp); uint32_t get_id() const; static std::shared_ptr<can_message_t> convert_from_frame(const canfd_frame& frame, size_t nbytes, uint64_t timestamp); + struct canfd_frame convert_to_canfd_frame(); + struct can_frame convert_to_can_frame(); + bool is_correct_to_send(); bool is_set(); struct bcm_msg get_bcm_msg(); void set_bcm_msg(struct bcm_msg bcm_msg); std::string get_debug_message(); - + uint32_t get_flags(); }; diff --git a/low-can-binding/can/message/j1939-message.cpp b/low-can-binding/can/message/j1939-message.cpp index dad8e7f1..08fc1302 100644 --- a/low-can-binding/can/message/j1939-message.cpp +++ b/low-can-binding/can/message/j1939-message.cpp @@ -16,14 +16,16 @@ */ #include <cstring> +#include <sstream> +#include <iomanip> +#include <net/if.h> #include "../../binding/low-can-hat.hpp" #include "j1939-message.hpp" -/// -/// @brief Class constructor -/// -/// j1939_message_t class constructor. -/// +/** + * @brief Construct a new j1939 message t::j1939 message t object + * + */ j1939_message_t::j1939_message_t(): message_t(), name_{0}, @@ -31,14 +33,27 @@ j1939_message_t::j1939_message_t(): addr_{0} {} -j1939_message_t::j1939_message_t(uint8_t length, +/** + * @brief Construct a new j1939 message t::j1939 message t object + * + * @param maxdlen The max length of the message + * @param length The length of the message + * @param format The format of the message + * @param data The vector data of the message + * @param timestamp The timetamp of the message + * @param name The name of the message + * @param pgn The PGN of the message + * @param addr The address of the message + */ +j1939_message_t::j1939_message_t(uint32_t maxdlen, + uint32_t length, message_format_t format, std::vector<uint8_t>& data, uint64_t timestamp, name_t name, pgn_t pgn, uint8_t addr): - message_t(length, format, data, timestamp), + message_t(maxdlen,length, format, data, timestamp), name_{name}, pgn_{pgn}, addr_{addr} @@ -71,6 +86,23 @@ uint8_t j1939_message_t::get_addr() const{ return addr_; } +/** + * @brief Convert hex data to string + * + * @param data An array of data + * @param length The length of the data + * @return std::string The string data + */ +std::string to_hex( uint8_t data[], const size_t length) +{ + std::stringstream stream; + stream << std::hex << std::setfill('0'); + for(int i = 0; i < length; i++) + { + stream << std::hex << ((int) data[i]); + } + return stream.str(); +} /// @brief Take a sockaddr_can struct and array of data to initialize class members /// @@ -84,9 +116,10 @@ uint8_t j1939_message_t::get_addr() const{ /// @return A j1939_message_t object fully initialized with sockaddr_can and data values. std::shared_ptr<j1939_message_t> j1939_message_t::convert_from_addr(struct sockaddr_can& addr, uint8_t (&data)[128],size_t nbytes, uint64_t timestamp) { - uint8_t length = 0; - message_format_t format; - std::vector<uint8_t> dataVector; + int i; + uint32_t length = 0; + message_format_t format; + std::vector<uint8_t> data_vector; if(nbytes > J1939_MAX_DLEN) { @@ -95,23 +128,27 @@ std::shared_ptr<j1939_message_t> j1939_message_t::convert_from_addr(struct socka } else { - AFB_DEBUG("Got a j1939 frame"); + //AFB_DEBUG("Got a j1939 frame"); format = message_format_t::J1939; } - length = (uint8_t) nbytes; - dataVector.reserve(length); - int i; - dataVector.clear(); + length = (uint32_t) nbytes; + data_vector.reserve(length); + + data_vector.clear(); + + std::string data_string; + data_string = to_hex(data,length); + for(i=0;i<length;i++) { - dataVector.push_back(data[i]); + data_vector.push_back(data[i]); }; - AFB_DEBUG("Found pgn: %X, format: %X, length: %X, data %02X%02X%02X%02X%02X%02X%02X%02X", - addr.can_addr.j1939.pgn, (uint8_t)format, length, data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7]); + AFB_DEBUG("Found pgn: %X, format: %X, length: %X, data %s", + addr.can_addr.j1939.pgn, (uint8_t)format, length, data_string.c_str()); - return std::make_shared<j1939_message_t>(j1939_message_t(length, format, dataVector, timestamp,addr.can_addr.j1939.name,addr.can_addr.j1939.pgn,addr.can_addr.j1939.addr)); + return std::make_shared<j1939_message_t>(j1939_message_t(J1939_MAX_DLEN,length, format, data_vector, timestamp,addr.can_addr.j1939.name,addr.can_addr.j1939.pgn,addr.can_addr.j1939.addr)); } /// @brief Test if members pgn_ and length are set. @@ -143,7 +180,7 @@ std::string j1939_message_t::get_debug_message() /// uint32_t j1939_message_t::get_id() const { - AFB_WARNING("Prefer method get_pgn() for j1939 messages"); + AFB_DEBUG("Prefer method get_pgn() for j1939 messages"); return get_pgn(); } diff --git a/low-can-binding/can/message/j1939-message.hpp b/low-can-binding/can/message/j1939-message.hpp index 482f167d..aad62a1f 100644 --- a/low-can-binding/can/message/j1939-message.hpp +++ b/low-can-binding/can/message/j1939-message.hpp @@ -19,11 +19,12 @@ #include <linux/can/j1939.h> #include "message.hpp" -#include "../../utils/socketcan-j1939.hpp" + #define J1939_MAX_MULTIPACKETS 255 #define J1939_MAX_DLEN J1939_MAX_MULTIPACKETS * CAN_MAX_DLEN + class j1939_message_t : public message_t { private: @@ -54,12 +55,19 @@ class j1939_message_t : public message_t /* J1939 Address + 0-255 */ uint8_t addr_; + /** + * @brief The sockanme to send a message to + * an other ECU + */ + struct sockaddr_can sockname_; + public: j1939_message_t(); - j1939_message_t(uint8_t length, message_format_t format, std::vector<uint8_t>& data, uint64_t timestamp, name_t name, pgn_t pgn, uint8_t addr); + j1939_message_t(uint32_t maxdlen, uint32_t length, message_format_t format, std::vector<uint8_t>& data, uint64_t timestamp, name_t name, pgn_t pgn, uint8_t addr); uint64_t get_name() const; uint32_t get_pgn() const; uint8_t get_addr() const; diff --git a/low-can-binding/can/message/message.cpp b/low-can-binding/can/message/message.cpp index 2ae095cb..5384c021 100644 --- a/low-can-binding/can/message/message.cpp +++ b/low-can-binding/can/message/message.cpp @@ -21,29 +21,45 @@ #include "../../binding/low-can-hat.hpp" -/// -/// @brief Class constructor -/// -/// message_t class constructor. -/// +/** + * @brief Construct a new message t::message t object + * + */ message_t::message_t() - : length_{0}, + : maxdlen_{0}, + length_{0}, format_{message_format_t::INVALID}, timestamp_{0}, sub_id_{-1} {} -message_t::message_t(uint8_t length, +/** + * @brief Construct a new message t::message t object + * + * @param maxdlen The maxdlen of a message + * @param length The length of the message + * @param format The format of the message + * @param data The data vector of the message + * @param timestamp The timestamp of the message + */ +message_t::message_t(uint32_t maxdlen, + uint32_t length, message_format_t format, std::vector<uint8_t>& data, uint64_t timestamp) - : length_{length}, + : maxdlen_{maxdlen}, + length_{length}, format_{format}, data_{data}, timestamp_{timestamp}, sub_id_{-1} {} +/** + * @brief Return the sub_id of the message + * + * @return int The sub_id of the message + */ int message_t::get_sub_id() const { return sub_id_; @@ -75,21 +91,46 @@ const std::vector<uint8_t> message_t::get_data_vector() const /// /// @return length_ class member /// -uint8_t message_t::get_length() const +uint32_t message_t::get_length() const { return length_; } +/** + * @brief Set data vector of the message + * + * @param data A vector of data + */ +void message_t::set_data(std::vector<uint8_t> &data) +{ + data_ = data; +} + +/** + * @brief Set sub_id of the message + * + * @param sub_id The sub_id to set + */ void message_t::set_sub_id(int sub_id) { sub_id_ = sub_id; } +/** + * @brief Return the timestamp of the message + * + * @return uint64_t The timestamp + */ uint64_t message_t::get_timestamp() const { return timestamp_; } +/** + * @brief Return the format of the message + * + * @return message_format_t The message format + */ message_format_t message_t::get_msg_format() { return format_; diff --git a/low-can-binding/can/message/message.hpp b/low-can-binding/can/message/message.hpp index e62b6c6b..5be1ff18 100644 --- a/low-can-binding/can/message/message.hpp +++ b/low-can-binding/can/message/message.hpp @@ -57,30 +57,32 @@ enum class message_format_t { /// buffers. It is a wrapper of a can_frame struct with some sugar around it for binding purposes. class message_t { protected: - uint8_t length_; ///< length_ - the length of the data array (max 8). */ + uint32_t maxdlen_; ///< maxdlen_ - Max data length deduce from number of bytes read from the socket.*/ + uint32_t length_; ///< length_ - the length of the data array. */ message_format_t format_; ///< format_ - the format of the message's ID.*/ std::vector<uint8_t> data_; ///< data_ - The message's data field with a size of 8 which is the standard about CAN bus messages.*/ uint64_t timestamp_; ///< timestamp_ - timestamp of the received message*/ int sub_id_; ///< sub_id_ - Subscription index. */ + public: message_t(); - message_t(uint8_t length, message_format_t format, std::vector<uint8_t>& data, uint64_t timestamp); + message_t(uint32_t maxdlen, uint32_t length, message_format_t format, std::vector<uint8_t>& data, uint64_t timestamp); + virtual ~message_t() = default; int get_sub_id() const; const uint8_t* get_data() const; const std::vector<uint8_t> get_data_vector() const; - uint8_t get_length() const; + uint32_t get_length() const; uint64_t get_timestamp() const; + void set_data(std::vector<uint8_t> &data); void set_sub_id(int sub_id); void set_timestamp(uint64_t timestamp); message_format_t get_msg_format(); virtual bool is_set() = 0; virtual std::string get_debug_message() = 0; virtual uint32_t get_id() const = 0; - virtual struct bcm_msg get_bcm_msg() = 0; - virtual void set_bcm_msg(struct bcm_msg bcm_msg) = 0; }; diff --git a/low-can-binding/diagnostic/diagnostic-manager.cpp b/low-can-binding/diagnostic/diagnostic-manager.cpp index d78c7755..ad1f3a7f 100644 --- a/low-can-binding/diagnostic/diagnostic-manager.cpp +++ b/low-can-binding/diagnostic/diagnostic-manager.cpp @@ -124,9 +124,9 @@ bool diagnostic_manager_t::shims_send(const uint32_t arbitration_id, const uint8 bcm_msg.frames[0] = cf; - std::shared_ptr<can_message_t> msg = std::make_shared<can_message_t>(); + can_message_t msg = can_message_t(); - msg->set_bcm_msg(bcm_msg); + msg.set_bcm_msg(bcm_msg); tx_socket.write_message(msg); if(tx_socket) @@ -473,7 +473,7 @@ openxc_VehicleMessage diagnostic_manager_t::relay_diagnostic_response(active_dia /// @return A pointer to a filled openxc_VehicleMessage or a nullptr if nothing has been found. openxc_VehicleMessage diagnostic_manager_t::relay_diagnostic_handle(active_diagnostic_request_t* entry, std::shared_ptr<message_t> m) { - DiagnosticResponse response = diagnostic_receive_can_frame(&shims_, entry->get_handle(), m->get_id(), m->get_data(), m->get_length()); + DiagnosticResponse response = diagnostic_receive_can_frame(&shims_, entry->get_handle(), m->get_id(), m->get_data(), (uint8_t)m->get_length()); if(response.completed && entry->get_handle()->completed) { if(entry->get_handle()->success) diff --git a/low-can-binding/utils/socketcan-bcm.cpp b/low-can-binding/utils/socketcan-bcm.cpp index 0f6bc75c..df41fba2 100644 --- a/low-can-binding/utils/socketcan-bcm.cpp +++ b/low-can-binding/utils/socketcan-bcm.cpp @@ -25,12 +25,6 @@ namespace utils { - /// @brief Connect the socket. - /// @return 0 if success. - int socketcan_bcm_t::connect(const struct sockaddr* addr, socklen_t len) - { - return socket_ != INVALID_SOCKET ? ::connect(socket_, addr, len) : 0; - } /// @brief Open a raw socket CAN. /// @param[in] device_name is the kernel network device name of the CAN interface. @@ -104,19 +98,19 @@ namespace utils return cm; } - void socketcan_bcm_t::write_message(std::vector<std::shared_ptr<message_t>>& vobj) + int socketcan_bcm_t::write_message(message_t& m) { - for(const auto& obj : vobj) - write_message(obj); - } - void socketcan_bcm_t::write_message(std::shared_ptr<message_t> m) - { - struct bcm_msg obj = m->get_bcm_msg(); + can_message_t& cm = reinterpret_cast<can_message_t&>(m); + struct bcm_msg obj = cm.get_bcm_msg(); size_t size = (obj.msg_head.flags & CAN_FD_FRAME) ? (size_t)((char*)&obj.fd_frames[obj.msg_head.nframes] - (char*)&obj): (size_t)((char*)&obj.frames[obj.msg_head.nframes] - (char*)&obj); if (::sendto(socket(), &obj, size, 0, (const struct sockaddr*)&get_tx_address(), sizeof(get_tx_address())) < 0) - AFB_API_ERROR(afbBindingV3root, "Error sending : %i %s", errno, ::strerror(errno)); + { + AFB_ERROR("Error sending : %i %s", errno, ::strerror(errno)); + return -1; + } + return 0; } } diff --git a/low-can-binding/utils/socketcan-bcm.hpp b/low-can-binding/utils/socketcan-bcm.hpp index 5e86aa4f..1f5ec50c 100644 --- a/low-can-binding/utils/socketcan-bcm.hpp +++ b/low-can-binding/utils/socketcan-bcm.hpp @@ -30,11 +30,8 @@ namespace utils virtual int open(std::string device_name); virtual std::shared_ptr<message_t> read_message(); - virtual void write_message(std::vector<std::shared_ptr<message_t>>& vobj); - virtual void write_message(std::shared_ptr<message_t> obj); + virtual int write_message(message_t& obj); - private: - int connect(const struct sockaddr* addr, socklen_t len); }; diff --git a/low-can-binding/utils/socketcan-j1939.cpp b/low-can-binding/utils/socketcan-j1939.cpp index 5f977f04..a7938d61 100644 --- a/low-can-binding/utils/socketcan-j1939.cpp +++ b/low-can-binding/utils/socketcan-j1939.cpp @@ -79,7 +79,8 @@ namespace utils } ++filter_on; } - if(filter_on){ + if(filter_on) + { setopt(SOL_CAN_J1939, SO_J1939_FILTER, &filter, sizeof(filter)); } } diff --git a/low-can-binding/utils/socketcan-j1939.hpp b/low-can-binding/utils/socketcan-j1939.hpp index d3b01fc4..2b370179 100644 --- a/low-can-binding/utils/socketcan-j1939.hpp +++ b/low-can-binding/utils/socketcan-j1939.hpp @@ -34,6 +34,7 @@ namespace utils virtual std::shared_ptr<message_t> read_message(); virtual void write_message(std::shared_ptr<message_t> obj); virtual void write_message(std::vector<std::shared_ptr<message_t>>& vobj); + virtual int write_message(message_t& obj); private: int connect(const struct sockaddr* addr, socklen_t len); diff --git a/low-can-binding/utils/socketcan-raw.cpp b/low-can-binding/utils/socketcan-raw.cpp index 6bd41c3b..31387c72 100644 --- a/low-can-binding/utils/socketcan-raw.cpp +++ b/low-can-binding/utils/socketcan-raw.cpp @@ -22,12 +22,6 @@ namespace utils { - /// @brief Bind the socket. - /// @return 0 if success. - int socketcan_raw_t::bind(const struct sockaddr* addr, socklen_t len) - { - return socket_ != INVALID_SOCKET ? ::bind(socket_, addr, len) : 0; - } /// @brief Open a raw socket CAN. /// @param[in] device_name is the kernel network device name of the CAN interface. @@ -75,7 +69,7 @@ namespace utils ifr.ifr_ifindex = addr.can_ifindex; ioctl(socket(), SIOCGIFNAME, &ifr); - AFB_DEBUG("Data available: %i bytes read", (int)nbytes); + //AFB_DEBUG("Data available: %i bytes read", (int)nbytes); AFB_DEBUG("read: Found on bus %s:\n id: %X, length: %X, data %02X%02X%02X%02X%02X%02X%02X%02X", ifr.ifr_name, frame.can_id, frame.len, frame.data[0], frame.data[1], frame.data[2], frame.data[3], frame.data[4], frame.data[5], frame.data[6], frame.data[7]); @@ -87,13 +81,9 @@ namespace utils return cm; } - void socketcan_raw_t::write_message(std::vector<std::shared_ptr<message_t>>& vobj) - { - AFB_WARNING("Not implemented"); - } - - void socketcan_raw_t::write_message(std::shared_ptr<message_t> cm) + int socketcan_raw_t::write_message(message_t& m) { AFB_WARNING("Not implemented"); + return -1; } } diff --git a/low-can-binding/utils/socketcan-raw.hpp b/low-can-binding/utils/socketcan-raw.hpp index 42e98746..966bf351 100644 --- a/low-can-binding/utils/socketcan-raw.hpp +++ b/low-can-binding/utils/socketcan-raw.hpp @@ -27,11 +27,7 @@ namespace utils using socketcan_t::socketcan_t; virtual int open(std::string device_name); virtual std::shared_ptr<message_t> read_message(); - virtual void write_message(std::shared_ptr<message_t> cm); - virtual void write_message(std::vector<std::shared_ptr<message_t>>& vobj); - - private: - int bind(const struct sockaddr* addr, socklen_t len); + virtual int write_message(message_t& cm); }; } diff --git a/low-can-binding/utils/socketcan.cpp b/low-can-binding/utils/socketcan.cpp index b943d1d7..f542f4e8 100644 --- a/low-can-binding/utils/socketcan.cpp +++ b/low-can-binding/utils/socketcan.cpp @@ -96,4 +96,32 @@ namespace utils { return socket_; } + + /// @brief Connect the socket. + /// @return 0 if success. + int socketcan_t::connect(const struct sockaddr* addr, socklen_t len) + { + return socket_ != INVALID_SOCKET ? ::connect(socket_, addr, len) : 0; + } + + /// @brief Bind the socket. + /// @return 0 if success. + int socketcan_t::bind(const struct sockaddr* addr, socklen_t len) + { + return socket_ != INVALID_SOCKET ? ::bind(socket_, addr, len) : 0; + } + + int socketcan_t::write_message(std::vector<message_t>& vobj) + { + for(int i=0;i<vobj.size();i++) + { + if(write_message(vobj[i])<0) + { + AFB_ERROR("Error send message %d",i); + return -1; + } + } + return 0; + } + } diff --git a/low-can-binding/utils/socketcan.hpp b/low-can-binding/utils/socketcan.hpp index fdf8c949..2a7077eb 100644 --- a/low-can-binding/utils/socketcan.hpp +++ b/low-can-binding/utils/socketcan.hpp @@ -28,6 +28,17 @@ #define INVALID_SOCKET -1 +/** + * @enum socket_type + * @brief The type of socket + */ +enum class socket_type { + BCM, ///< BCM - Socket BCM + J1939_ADDR_CLAIM, ///< J1939 - Socket J1939 + J1939, ///< J1939 - Socket J1939 + INVALID +}; + namespace utils { @@ -48,13 +59,15 @@ namespace utils int setopt(int level, int optname, const void* optval, socklen_t optlen); virtual int close(); virtual std::shared_ptr<message_t> read_message() = 0; - virtual void write_message(std::shared_ptr<message_t> obj) = 0; - virtual void write_message(std::vector<std::shared_ptr<message_t>>& vobj) = 0; + virtual int write_message(message_t& obj) = 0; + virtual int write_message(std::vector<message_t>& vobj); protected: int socket_; struct sockaddr_can tx_address_; int open(int domain, int type, int protocol); + int bind(const struct sockaddr* addr, socklen_t len); + int connect(const struct sockaddr* addr, socklen_t len); }; |