/* * Copyright (C) 2015, 2016 "IoT.bzh" * Author "Romain Forlot" * * 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 "can-decoder.hpp" #include "canutil/read.h" #include "../utils/openxc-utils.hpp" /* Public: Parse the signal's bitfield from the given data and return the raw * value. * * @param[in] signal - The signal to parse from the data. * @param[in] message - can_message_t to parse * * @return Returns the raw value of the signal parsed as a bitfield from the given byte * array. */ float decoder_t::parseSignalBitfield(can_signal_t& signal, const can_message_t& message) { return bitfield_parse_float(message.get_data(), CAN_MESSAGE_SIZE, signal.get_bit_position(), signal.get_bit_size(), signal.get_factor(), signal.get_offset()); } /* Public: Wrap a raw CAN signal value in a DynamicField without modification. * * This is an implementation of the SignalDecoder type signature, and can be * used directly in the can_signal_t.decoder field. * * @param[in] signal - The details of the signal that contains the state mapping. * @param[in] signals - The list of all signals * @param[in] value - The numerical value that will be wrapped in a DynamicField. * @param[out]send - An output argument that will be set to false if the value should * not be sent for any reason. * * @return Returns a DynamicField with the original, unmodified raw CAN signal value as * its numeric value. The 'send' argument will not be modified as this decoder * always succeeds. */ openxc_DynamicField decoder_t::noopDecoder(can_signal_t& signal, const std::vector& signals, float value, bool* send) { openxc_DynamicField decoded_value = build_DynamicField(value); return decoded_value; } /* Public: Coerces a numerical value to a boolean. * * This is an implementation of the SignalDecoder type signature, and can be * used directly in the can_signal_t.decoder field. * * @param[in] signal - The details of the signal that contains the state mapping. * @param[in] signals - The list of all signals * @param[in] value - The numerical value that will be converted to a boolean. * @param[out] send - An output argument that will be set to false if the value should * not be sent for any reason. * * @return Returns a DynamicField with a boolean value of false if the raw signal value * is 0.0, otherwise true. The 'send' argument will not be modified as this * decoder always succeeds. */ openxc_DynamicField decoder_t::booleanDecoder(can_signal_t& signal, const std::vector& signals, float value, bool* send) { openxc_DynamicField decoded_value = build_DynamicField(value == 0.0 ? false : true); return decoded_value; } /* Public: Update the metadata for a signal and the newly received value. * * This is an implementation of the SignalDecoder type signature, and can be * used directly in the can_signal_t.decoder field. * * This function always flips 'send' to false. * * @param[in] signal - The details of the signal that contains the state mapping. * @param[in] signals - The list of all signals. * @param[in] value - The numerical value that will be converted to a boolean. * @param[out] send - This output argument will always be set to false, so the caller will * know not to publish this value to the pipeline. * * @return Return value is undefined. */ openxc_DynamicField decoder_t::ignoreDecoder(can_signal_t& signal, const std::vector& signals, float value, bool* send) { if(send) *send = false; openxc_DynamicField decoded_value; return decoded_value; } /* Public: Find and return the corresponding string state for a CAN signal's * raw integer value. * * This is an implementation of the SignalDecoder type signature, and can be * used directly in the can_signal_t.decoder field. * * @param[in] signal - The details of the signal that contains the state mapping. * @param[in] signals - The list of all signals. * @param[in] value - The numerical value that should map to a state. * @param[out] send - An output argument that will be set to false if the value should * not be sent for any reason. * * @return Returns a DynamicField with a string value if a matching state is found in * the signal. If an equivalent isn't found, send is sent to false and the * return value is undefined. */ openxc_DynamicField decoder_t::stateDecoder(can_signal_t& signal, const std::vector& signals, float value, bool* send) { const std::string signal_state = signal.get_states(value); openxc_DynamicField decoded_value = build_DynamicField(signal_state); if(signal_state.size() <= 0) { *send = false; ERROR(binder_interface, "stateDecoder: No state found with index: %d", (int)value); } return decoded_value; } /* Public: Parse a signal from a CAN message, apply any required transforations * to get a human readable value and public the result to the pipeline. * * If the can_signal_t has a non-NULL 'decoder' field, the raw CAN signal value * will be passed to the decoder before publishing. * * @param[in] signal - The details of the signal to decode and forward. * @param[in] message - The received CAN message that should contain this signal. * @param[in] signals - an array of all active signals. * * The decoder returns an openxc_DynamicField, which may contain a number, * string or boolean. */ openxc_DynamicField decoder_t::translateSignal(can_signal_t& signal, can_message_t& message, const std::vector& signals) { if(&signal == nullptr || &message == nullptr) { openxc_DynamicField ret = {0, openxc_DynamicField_Type_BOOL, 0, "", 0, 0, 0, 0}; return ret; } float value = decoder_t::parseSignalBitfield(signal, message); DEBUG(binder_interface, "translateSignal: Decoded message from parseSignalBitfield: %f", value); bool send = true; // Must call the decoders every time, regardless of if we are going to // decide to send the signal or not. openxc_DynamicField decoded_value = decoder_t::decodeSignal(signal, value, signals, &send); signal.set_received(true); signal.set_last_value(value); return decoded_value; } /* Public: 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 * will be passed to the decoder before returning. * * @param[in] signal - The details of the signal to decode and forward. * @param[in] value - The numerical value that will be converted to a boolean. * @param[in] signals - an array of all active signals. * @param[out] send - An output parameter that will be flipped to false if the value could * not be decoded. * * @return The decoder returns an openxc_DynamicField, which may contain a number, * string or boolean. If 'send' is false, the return value is undefined. */ openxc_DynamicField decoder_t::decodeSignal( can_signal_t& signal, float value, const std::vector& signals, bool* send) { SignalDecoder decoder = signal.get_decoder() == nullptr ? noopDecoder : signal.get_decoder(); openxc_DynamicField decoded_value = decoder(signal, signals, value, send); return decoded_value; } /* Public: Decode a transformed, human readable value from an raw CAN signal * already parsed from a CAN message. * * This is the same as decodeSignal but you must parse the bitfield value of the signal from the CAN * message yourself. This is useful if you need that raw value for something * else. * * @param[in] signal - The details of the signal to decode and forward. * @param[in] value - The numerical value that will be converted to a boolean. * @param[in] signals - an array of all active signals. * @param[out] send - An output parameter that will be flipped to false if the value could * not be decoded. */ openxc_DynamicField decoder_t::decodeSignal( can_signal_t& signal, const can_message_t& message, const std::vector& signals, bool* send) { float value = parseSignalBitfield(signal, message); return decodeSignal(signal, value, signals, send); }