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/can | |
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/can')
-rw-r--r-- | low-can-binding/can/can-encoder.cpp | 114 | ||||
-rw-r--r-- | low-can-binding/can/can-encoder.hpp | 7 | ||||
-rw-r--r-- | low-can-binding/can/message-definition.cpp | 10 | ||||
-rw-r--r-- | low-can-binding/can/message-definition.hpp | 2 | ||||
-rw-r--r-- | low-can-binding/can/message/can-message.cpp | 58 | ||||
-rw-r--r-- | low-can-binding/can/message/can-message.hpp | 10 | ||||
-rw-r--r-- | low-can-binding/can/message/j1939-message.cpp | 77 | ||||
-rw-r--r-- | low-can-binding/can/message/j1939-message.hpp | 12 | ||||
-rw-r--r-- | low-can-binding/can/message/message.cpp | 59 | ||||
-rw-r--r-- | low-can-binding/can/message/message.hpp | 12 |
10 files changed, 313 insertions, 48 deletions
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; }; |