2 * Copyright (C) 2015, 2016 "IoT.bzh"
3 * Author "Romain Forlot" <romain.forlot@iot.bzh>
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
18 #include "can-encoder.hpp"
20 #include "canutil/write.h"
21 #include "../utils/openxc-utils.hpp"
22 #include "can-message-definition.hpp"
24 /// @brief Write a value into a CAN signal in the destination buffer.
26 /// @param[in] signal - The CAN signal to write, including the bit position and bit size.
27 /// @param[in] value - The encoded integer value to write into the CAN signal.
28 /// @param[out] data - The destination buffer.
29 /// @param[in] length - The length of the destination buffer.
31 /// @return Returns a can_frame struct initialized and ready to be send.
32 const can_frame encoder_t::build_frame(const std::shared_ptr<can_signal_t>& signal, uint64_t value)
35 ::memset(&cf, 0, sizeof(cf));
37 cf.can_id = signal->get_message()->get_id();
38 cf.can_dlc = CAN_MAX_DLEN;
40 signal->set_last_value((float)value);
42 for(const auto& sig: signal->get_message()->get_can_signals())
44 float last_value = sig->get_last_value();
45 bitfield_encode_float(last_value,
46 sig->get_bit_position(),
57 /// @brief Encode a boolean into an integer, fit for a CAN signal bitfield.
59 /// This is a shortcut for encodeDynamicField(CanSignal*, openxc_DynamicField*,
60 /// bool*) that takes care of creating the DynamicField object for you with the
63 /// @param[in] signal - The CAN signal to encode this value for..
64 /// @param[in] value - The boolean value to encode
65 /// @param[out] send - An output argument that will be set to false if the value should
66 /// not be sent for any reason.
68 /// @return Returns the encoded integer. If 'send' is changed to false, the field could
69 /// not be encoded and the return value is undefined.
71 uint64_t encoder_t::encode_boolean(const can_signal_t& signal, bool value, bool* send)
73 return encode_number(signal, float(value), send);
75 /// @brief Encode a float into an integer, fit for a CAN signal's bitfield.
77 /// This is a shortcut for encodeDynamicField(CanSignal*, openxc_DynamicField*,
78 /// bool*) that takes care of creating the DynamicField object for you with the
81 /// @param[in] signal - The CAN signal to encode this value for.
82 /// @param[in] value - The float value to encode.
83 /// @param[out] send - This output argument will always be set to false, so the caller will
84 /// know not to publish this value to the pipeline.
86 /// @return Returns the encoded integer. If 'send' is changed to false, the field could
87 /// not be encoded and the return value is undefined.
89 uint64_t encoder_t::encode_number(const can_signal_t& signal, float value, bool* send)
91 return float_to_fixed_point(value, signal.get_factor(), signal.get_offset());
94 /// @brief Encode a string into an integer, fit for a CAN signal's bitfield.
96 /// Be aware that the behavior is undefined if there are multiple values assigned
97 /// to a single state. See https://github.com/openxc/vi-firmware/issues/185.
99 /// This is a shortcut for encodeDynamicField(CanSignal*, openxc_DynamicField*,
100 /// bool*) that takes care of creating the DynamicField object for you with the
101 /// string state value.
103 /// @param[in] signal - The details of the signal that contains the state mapping.
104 /// @param[in] value - The string state value to encode.
105 /// @param[out] send - An output argument that will be set to false if the value should
106 /// not be sent for any reason.
108 /// @return Returns the encoded integer. If 'send' is changed to false, the field could
109 /// not be encoded and the return value is undefined.
111 uint64_t encoder_t::encode_state(const can_signal_t& signal, const std::string& state, bool* send)
116 AFB_DEBUG("Can't write state of "" -- not sending");
121 uint64_t signal_state = signal.get_states(state);
122 if(signal_state != -1) {
123 value = signal_state;
125 AFB_DEBUG("Couldn't find a valid signal state for %s", state.c_str());
132 /// @brief Parse a signal from a CAN message and apply any required
133 /// transforations to get a human readable value.
135 /// If the can_signal_t has a non-NULL 'decoder' field, the raw CAN signal value
136 /// will be passed to the decoder before returning.
138 /// @param[in] signal - The details of the signal to decode and forward.
139 /// @param[in] value - The numerical value that will be converted to a boolean.
140 /// @param[out] send - An output parameter that will be flipped to false if the value could
143 /// @return The decoder returns an openxc_DynamicField, which may contain a number,
144 /// string or boolean. If 'send' is false, the return value is undefined.
146 uint64_t encoder_t::encode_DynamicField( can_signal_t& signal, const openxc_DynamicField& field, bool* send)
150 case openxc_DynamicField_Type_STRING:
151 value = encode_state(signal, field.string_value, send);
153 case openxc_DynamicField_Type_NUM:
154 value = encode_number(signal, (float)field.numeric_value, send);
156 case openxc_DynamicField_Type_BOOL:
157 value = encode_boolean(signal, field.boolean_value, send);
160 AFB_DEBUG("Dynamic field didn't have a value, can't encode");