Add feature to build messages and fix some functions
[apps/agl-service-can-low-level.git] / low-can-binding / can / can-encoder.cpp
index e0015da..ccd4972 100644 (file)
 
 #include "canutil/write.h"
 #include "../utils/openxc-utils.hpp"
-#include "can-message-definition.hpp"
-#include "../binding/low-can-hat.hpp"
+#include "message-definition.hpp"
 
-/// @brief Write a value into a CAN signal in the destination buffer.
+/// @brief Write a value in a CAN signal in the destination buffer.
 ///
 /// @param[in] signal - The CAN signal to write, including the bit position and bit size.
-/// @param[in] value - The encoded integer value to write into the CAN signal.
+/// @param[in] value - The encoded integer value to write in the CAN signal.
 /// @param[out] data - The destination buffer.
 /// @param[in] length - The length of the destination buffer.
 ///
-/// @return Returns a can_frame struct initialized and ready to be send.
-const can_frame encoder_t::build_frame(const std::shared_ptr<can_signal_t>& signal, uint64_t value)
+/// @return Returns a canfd_frame struct initialized and ready to be send.
+const canfd_frame encoder_t::build_frame(const std::shared_ptr<signal_t>& signal, uint64_t value)
 {
-       struct can_frame cf;
+       struct canfd_frame cf;
        ::memset(&cf, 0, sizeof(cf));
 
        cf.can_id = signal->get_message()->get_id();
-       cf.can_dlc = CAN_MAX_DLEN;
+       cf.len = signal->get_message()->is_fd() ?
+                CANFD_MAX_DLEN : CAN_MAX_DLEN;
 
        signal->set_last_value((float)value);
 
-       for(const auto& sig: signal->get_message()->get_can_signals())
+       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(),
-                                                       cf.data,
-                                                       CAN_MAX_DLEN);
+                                       sig->get_bit_position(),
+                                       sig->get_bit_size(),
+                                       sig->get_factor(),
+                                       sig->get_offset(),
+                                       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*,
@@ -69,7 +181,7 @@ const can_frame encoder_t::build_frame(const std::shared_ptr<can_signal_t>& sign
 /// @return Returns the encoded integer. If 'send' is changed to false, the field could
 /// not be encoded and the return value is undefined.
 ///
-uint64_t encoder_t::encode_boolean(const can_signal_t& signal, bool value, bool* send)
+uint64_t encoder_t::encode_boolean(const signal_t& signal, bool value, bool* send)
 {
        return encode_number(signal, float(value), send);
 }
@@ -87,7 +199,7 @@ uint64_t encoder_t::encode_boolean(const can_signal_t& signal, bool value, bool*
 /// @return Returns the encoded integer. If 'send' is changed to false, the field could
 /// not be encoded and the return value is undefined.
 ///
-uint64_t encoder_t::encode_number(const can_signal_t& signal, float value, bool* send)
+uint64_t encoder_t::encode_number(const signal_t& signal, float value, bool* send)
 {
        return float_to_fixed_point(value, signal.get_factor(), signal.get_offset());
 }
@@ -109,7 +221,7 @@ uint64_t encoder_t::encode_number(const can_signal_t& signal, float value, bool*
 /// @return Returns the encoded integer. If 'send' is changed to false, the field could
 /// not be encoded and the return value is undefined.
 ///
-uint64_t encoder_t::encode_state(const can_signal_t& signal, const std::string& state, bool* send)
+uint64_t encoder_t::encode_state(const signal_t& signal, const std::string& state, bool* send)
 {
        uint64_t value = 0;
        if(state == "")
@@ -133,7 +245,7 @@ uint64_t encoder_t::encode_state(const can_signal_t& signal, const std::string&
 /// @brief Parse a signal from a CAN message and apply any required
 /// transforations to get a human readable value.
 ///
-/// If the can_signal_t has a non-NULL 'decoder' field, the raw CAN signal value
+/// If the signal_t has a non-NULL 'decoder' field, the raw CAN signal value
 /// will be passed to the decoder before returning.
 ///
 /// @param[in] signal - The details of the signal to decode and forward.
@@ -144,7 +256,7 @@ uint64_t encoder_t::encode_state(const can_signal_t& signal, const std::string&
 /// @return The decoder returns an openxc_DynamicField, which may contain a number,
 /// string or boolean. If 'send' is false, the return value is undefined.
 ///
-uint64_t encoder_t::encode_DynamicField( can_signal_t& signal, const openxc_DynamicField& field, bool* send)
+uint64_t encoder_t::encode_DynamicField( signal_t& signal, const openxc_DynamicField& field, bool* send)
 {
        uint64_t value = 0;
        switch(field.type) {