From 860d6bd4a829ee5aca50b93122474c9bf68fff9d Mon Sep 17 00:00:00 2001 From: Romain Forlot Date: Fri, 17 Feb 2017 09:10:10 +0000 Subject: Rename header file to hpp. Change-Id: I399e0c0f39b18e63e254825b6322faf77896a264 Signed-off-by: Romain Forlot --- src/can-decoder.cpp | 44 +++-- src/can-decoder.h | 146 ----------------- src/can-decoder.hpp | 146 +++++++++++++++++ src/can-signals.h | 84 ---------- src/can-signals.hpp | 84 ++++++++++ src/can-utils.cpp | 83 +++++----- src/can-utils.h | 393 -------------------------------------------- src/can-utils.hpp | 394 +++++++++++++++++++++++++++++++++++++++++++++ src/can_decode_message.cpp | 125 ++++++++------ src/can_reader.cpp | 2 +- src/low-can-binding.cpp | 2 +- src/obd2.h | 173 -------------------- src/obd2.hpp | 173 ++++++++++++++++++++ src/timer.h | 33 ---- src/timer.hpp | 33 ++++ 15 files changed, 971 insertions(+), 944 deletions(-) delete mode 100644 src/can-decoder.h create mode 100644 src/can-decoder.hpp delete mode 100644 src/can-signals.h create mode 100644 src/can-signals.hpp delete mode 100644 src/can-utils.h create mode 100644 src/can-utils.hpp delete mode 100644 src/obd2.h create mode 100644 src/obd2.hpp delete mode 100644 src/timer.h create mode 100644 src/timer.hpp (limited to 'src') diff --git a/src/can-decoder.cpp b/src/can-decoder.cpp index 000db2ac..0c8c8039 100644 --- a/src/can-decoder.cpp +++ b/src/can-decoder.cpp @@ -15,23 +15,20 @@ * limitations under the License. */ -Decoder::Decoder +decoder_t::decoder_t() + : decoded_value{false, openxc_DynamicField_Type_STRING, false, "", false, 0, false, false} { - decoded_value = { .has_type = false, - .has_numeric_value = false, - .has_boolean_value = false, - .has_string_value = false }; } -float Decoder::parseSignalBitfield(CanSignal* signal, const CanMessage* message) +float decoder_t::parseSignalBitfield(const CanSignal& signal, const CanMessage& message) { return bitfield_parse_float(message->data, CAN_MESSAGE_SIZE, signal->bitPosition, signal->bitSize, signal->factor, signal->offset); } -openxc_DynamicField Decoder::noopDecoder(CanSignal* signal, - CanSignal* signals, int signalCount, float value, bool* send) +openxc_DynamicField decoder_t::noopDecoder(const CanSignal& signal, + const CanSignal& signals, float value, bool* send) { decoded_value = { .has_type = true, .type = openxc_DynamicField_Type_NUM, @@ -40,8 +37,8 @@ openxc_DynamicField Decoder::noopDecoder(CanSignal* signal, return decoded_value; } -openxc_DynamicField Decoder::booleanDecoder(CanSignal* signal, - CanSignal* signals, int signalCount, float value, bool* send) +openxc_DynamicField decoder_t::booleanDecoder(const CanSignal& signal, + const CanSignal& signals, float value, bool* send) { decoded_value = { .has_type = true, .type = openxc_DynamicField_Type_BOOL, @@ -50,16 +47,18 @@ openxc_DynamicField Decoder::booleanDecoder(CanSignal* signal, return decoded_value; } -openxc_DynamicField Decoder::ignoreDecoder(CanSignal* signal, - CanSignal* signals, int signalCount, float value, bool* send) +openxc_DynamicField decoder_t::ignoreDecoder(const CanSignal& signal, + const CanSignal& signals, float value, bool* send) { - *send = false; + if(send) + *send = false; + openxc_DynamicField decoded_value = {0}; return decoded_value; } -openxc_DynamicField Decoder::stateDecoder(CanSignal* signal, - CanSignal* signals, int signalCount, float value, bool* send) +openxc_DynamicField decoder_t::stateDecoder(const CanSignal& signal, + const CanSignal& signals, float value, bool* send) { openxc_DynamicField decoded_value = {0}; decoded_value.has_type = true; @@ -68,26 +67,25 @@ openxc_DynamicField Decoder::stateDecoder(CanSignal* signal, const CanSignalState* signalState = lookupSignalState(value, signal); if(signalState != NULL) { - strcpy(decoded_value.string_value, signalState->name); + ::strcpy(decoded_value.string_value, signalState->name); } else { *send = false; } return decoded_value; } -openxc_DynamicField Decoder::decodeSignal(CanSignal* signal, - float value, CanSignal* signals, int signalCount, bool* send) +openxc_DynamicField decoder_t::decodeSignal(const CanSignal& signal, + float value, const CanSignal& signals, bool* send) { SignalDecoder decoder = signal->decoder == NULL ? noopDecoder : signal->decoder; openxc_DynamicField decoded_value = decoder(signal, signals, - signalCount, value, send); + value, send); return decoded_value; } -openxc_DynamicField Decoder::decodeSignal(CanSignal* signal, - const CanMessage* message, CanSignal* signals, int signalCount, - bool* send) { +openxc_DynamicField decoder_t::decodeSignal(const CanSignal& signal, + const CanMessage& message, const CanSignal& signals, bool* send) { float value = parseSignalBitfield(signal, message); - return decodeSignal(signal, value, signals, signalCount, send); + return decodeSignal(signal, value, signals, send); } \ No newline at end of file diff --git a/src/can-decoder.h b/src/can-decoder.h deleted file mode 100644 index 3754baef..00000000 --- a/src/can-decoder.h +++ /dev/null @@ -1,146 +0,0 @@ -/* - * 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. - */ - -#pragma once - - -class decoder_t -{ - private: - openxc_DynamicField decoded_value; - - public: - /* Public: Parse the signal's bitfield from the given data and return the raw - * value. - * - * signal - The signal to parse from the data. - * data - The data to parse the signal from. - * length - The length of the data array. - * - * Returns the raw value of the signal parsed as a bitfield from the given byte - * array. - */ - float parseSignalBitfield(CanSignal* signal, const CanMessage* message); - - /* 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 CanSignal.decoder field. - * - * signal - The details of the signal that contains the state mapping. - * signals - The list of all signals. - * signalCount - the length of the signals array. - * value - The numerical value that should map to a state. - * send - An output argument that will be set to false if the value should - * not be sent for any reason. - * - * 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 stateDecoder(CanSignal* signal, CanSignal* signals, - int signalCount, float value, bool* send); - - /* Public: Coerces a numerical value to a boolean. - * - * This is an implementation of the SignalDecoder type signature, and can be - * used directly in the CanSignal.decoder field. - * - * signal - The details of the signal that contains the state mapping. - * signals - The list of all signals - * signalCount - The length of the signals array - * value - The numerical value that will be converted to a boolean. - * send - An output argument that will be set to false if the value should - * not be sent for any reason. - * - * 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 booleanDecoder(CanSignal* signal, CanSignal* signals, - int signalCount, float value, bool* send); - - /* 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 CanSignal.decoder field. - * - * This function always flips 'send' to false. - * - * signal - The details of the signal that contains the state mapping. - * signals - The list of all signals. - * signalCount - The length of the signals array. - * value - The numerical value that will be converted to a boolean. - * send - This output argument will always be set to false, so the caller will - * know not to publish this value to the pipeline. - * - * The return value is undefined. - */ - openxc_DynamicField ignoreDecoder(CanSignal* signal, CanSignal* signals, - int signalCount, float value, bool* send); - - /* 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 CanSignal.decoder field. - * - * signal - The details of the signal that contains the state mapping. - * signals - The list of all signals - * signalCount - The length of the signals array - * value - The numerical value that will be wrapped in a DynamicField. - * send - An output argument that will be set to false if the value should - * not be sent for any reason. - * - * 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 noopDecoder(CanSignal* signal, CanSignal* signals, - int signalCount, float value, bool* send); - - /* Public: Parse a signal from a CAN message and apply any required - * transforations to get a human readable value. - * - * If the CanSignal has a non-NULL 'decoder' field, the raw CAN signal value - * will be passed to the decoder before returning. - * - * signal - The details of the signal to decode and forward. - * message - The CAN message that contains the signal. - * signals - an array of all active signals. - * signalCount - The length of the signals array. - * send - An output parameter that will be flipped to false if the value could - * not be decoded. - * - * 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 decodeSignal(CanSignal* signal, - const CanMessage* message, CanSignal* signals, int signalCount, - bool* send); - - /* Public: Decode a transformed, human readable value from an raw CAN signal - * already parsed from a CAN message. - * - * This is the same as decodeSignal(CanSignal*, CanMessage*, CanSignal*, int, - * bool*) 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. - */ - openxc_DynamicField decodeSignal(CanSignal* signal, float value, - CanSignal* signals, int signalCount, bool* send); -} \ No newline at end of file diff --git a/src/can-decoder.hpp b/src/can-decoder.hpp new file mode 100644 index 00000000..b6234b52 --- /dev/null +++ b/src/can-decoder.hpp @@ -0,0 +1,146 @@ +/* + * 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. + */ + +#pragma once + + +class decoder_t +{ + private: + openxc_DynamicField decoded_value; + + public: + /* Public: Parse the signal's bitfield from the given data and return the raw + * value. + * + * signal - The signal to parse from the data. + * data - The data to parse the signal from. + * length - The length of the data array. + * + * Returns the raw value of the signal parsed as a bitfield from the given byte + * array. + */ + float parseSignalBitfield(const CanSignal& signal, const CanMessage& message); + + /* 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 CanSignal.decoder field. + * + * signal - The details of the signal that contains the state mapping. + * signals - The list of all signals. + * signalCount - the length of the signals array. + * value - The numerical value that should map to a state. + * send - An output argument that will be set to false if the value should + * not be sent for any reason. + * + * 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 stateDecoder(const CanSignal& signal, const CanSignal& signals, + float value, bool* send); + + /* Public: Coerces a numerical value to a boolean. + * + * This is an implementation of the SignalDecoder type signature, and can be + * used directly in the CanSignal.decoder field. + * + * signal - The details of the signal that contains the state mapping. + * signals - The list of all signals + * signalCount - The length of the signals array + * value - The numerical value that will be converted to a boolean. + * send - An output argument that will be set to false if the value should + * not be sent for any reason. + * + * 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 booleanDecoder(const CanSignal& signal, const CanSignal& signals, + float value, bool* send); + + /* 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 CanSignal.decoder field. + * + * This function always flips 'send' to false. + * + * signal - The details of the signal that contains the state mapping. + * signals - The list of all signals. + * signalCount - The length of the signals array. + * value - The numerical value that will be converted to a boolean. + * send - This output argument will always be set to false, so the caller will + * know not to publish this value to the pipeline. + * + * The return value is undefined. + */ + openxc_DynamicField ignoreDecoder(const CanSignal& signal, const CanSignal& signals, + float value, bool* send); + + /* 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 CanSignal.decoder field. + * + * signal - The details of the signal that contains the state mapping. + * signals - The list of all signals + * signalCount - The length of the signals array + * value - The numerical value that will be wrapped in a DynamicField. + * send - An output argument that will be set to false if the value should + * not be sent for any reason. + * + * 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 noopDecoder(const CanSignal& signal, const CanSignal& signals, + float value, bool* send); + + /* Public: Parse a signal from a CAN message and apply any required + * transforations to get a human readable value. + * + * If the CanSignal has a non-NULL 'decoder' field, the raw CAN signal value + * will be passed to the decoder before returning. + * + * signal - The details of the signal to decode and forward. + * message - The CAN message that contains the signal. + * signals - an array of all active signals. + * signalCount - The length of the signals array. + * send - An output parameter that will be flipped to false if the value could + * not be decoded. + * + * 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 decodeSignal(const CanSignal& signal, + const CanMessage& message, const CanSignal& signals, + bool* send); + + /* Public: Decode a transformed, human readable value from an raw CAN signal + * already parsed from a CAN message. + * + * This is the same as decodeSignal(const CanSignal&, CanMessage*, const CanSignal&, int, + * bool*) 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. + */ + openxc_DynamicField decodeSignal(const CanSignal& signal, float value, + const CanSignal& signals, bool* send); +} \ No newline at end of file diff --git a/src/can-signals.h b/src/can-signals.h deleted file mode 100644 index f34c743e..00000000 --- a/src/can-signals.h +++ /dev/null @@ -1,84 +0,0 @@ -/* - * 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. - */ - -#pragma once - -#include "can-utils.h" -#include - -/** Public: Return the currently active CAN configuration. */ -CanMessageSet* getActiveMessageSet(); - -/** Public: Retrive a list of all possible CAN configurations. - * * - * * Returns a pointer to an array of all configurations. - * */ -CanMessageSet* getMessageSets(); - -/** Public: Return the length of the array returned by getMessageSets() */ -int getMessageSetCount(); - -/* Public: Return the number of CAN buses configured in the active - * * configuration. This is limited to 2, as the hardware controller only has 2 - * * CAN channels. - * */ -int getCanBusCount(); - -/* Public: Return an array of all CAN messages to be processed in the active - * * configuration. - * */ -CanMessageDefinition* getMessages(); - -/* Public: Return signals from an signals array filtered on name. - */ -CanSignal* getSignals(std::string name); - -/* Public: Return an array of all OpenXC CAN commands enabled in the active - * * configuration that can write back to CAN with a custom handler. - * * - * * Commands not defined here are handled using a 1-1 mapping from the signals - * * list. - * */ -CanCommand* getCommands(); - -/* Public: Return the length of the array returned by getCommandCount(). */ -int getCommandCount(); - -/* Public: Return the length of the array returned by getSignals(). */ -int getSignalCount(); - -/* Public: Return the length of the array returned by getMessages(). */ -int getMessageCount(); - -/* Public: Return an array of the metadata for the 2 CAN buses you want to - * * monitor. The size of this array is fixed at 2. - * */ -CanBus* getCanBuses(); - -/* Public: Decode CAN signals from raw CAN messages, translate from engineering - * * units to something more human readable, and send the resulting value over USB - * * as an OpenXC-style JSON message. - * * - * * This is the main workhorse function of the VI. Every time a new - * * CAN message is received that matches one of the signals in the list returend - * * by getSignals(), this function is called with the message ID and 64-bit data - * * field. - * * - * * bus - The CAN bus this message was received on. - * * message - The received CAN message. - * */ -void decodeCanMessage(openxc::pipeline::Pipeline* pipeline, CanBus* bus, CanMessage* message); diff --git a/src/can-signals.hpp b/src/can-signals.hpp new file mode 100644 index 00000000..f34c743e --- /dev/null +++ b/src/can-signals.hpp @@ -0,0 +1,84 @@ +/* + * 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. + */ + +#pragma once + +#include "can-utils.h" +#include + +/** Public: Return the currently active CAN configuration. */ +CanMessageSet* getActiveMessageSet(); + +/** Public: Retrive a list of all possible CAN configurations. + * * + * * Returns a pointer to an array of all configurations. + * */ +CanMessageSet* getMessageSets(); + +/** Public: Return the length of the array returned by getMessageSets() */ +int getMessageSetCount(); + +/* Public: Return the number of CAN buses configured in the active + * * configuration. This is limited to 2, as the hardware controller only has 2 + * * CAN channels. + * */ +int getCanBusCount(); + +/* Public: Return an array of all CAN messages to be processed in the active + * * configuration. + * */ +CanMessageDefinition* getMessages(); + +/* Public: Return signals from an signals array filtered on name. + */ +CanSignal* getSignals(std::string name); + +/* Public: Return an array of all OpenXC CAN commands enabled in the active + * * configuration that can write back to CAN with a custom handler. + * * + * * Commands not defined here are handled using a 1-1 mapping from the signals + * * list. + * */ +CanCommand* getCommands(); + +/* Public: Return the length of the array returned by getCommandCount(). */ +int getCommandCount(); + +/* Public: Return the length of the array returned by getSignals(). */ +int getSignalCount(); + +/* Public: Return the length of the array returned by getMessages(). */ +int getMessageCount(); + +/* Public: Return an array of the metadata for the 2 CAN buses you want to + * * monitor. The size of this array is fixed at 2. + * */ +CanBus* getCanBuses(); + +/* Public: Decode CAN signals from raw CAN messages, translate from engineering + * * units to something more human readable, and send the resulting value over USB + * * as an OpenXC-style JSON message. + * * + * * This is the main workhorse function of the VI. Every time a new + * * CAN message is received that matches one of the signals in the list returend + * * by getSignals(), this function is called with the message ID and 64-bit data + * * field. + * * + * * bus - The CAN bus this message was received on. + * * message - The received CAN message. + * */ +void decodeCanMessage(openxc::pipeline::Pipeline* pipeline, CanBus* bus, CanMessage* message); diff --git a/src/can-utils.cpp b/src/can-utils.cpp index e978cae5..e41230b9 100644 --- a/src/can-utils.cpp +++ b/src/can-utils.cpp @@ -23,12 +23,12 @@ * *********************************************************************************/ -can_bus_t::can_bus_t(afb_binding_interface *itf, const std:string &dev_name) - : interface{itf}, deviceName{dev_name} +can_bus_dev_t::can_bus_dev_t(afb_binding_interface *itf, const std:string &dev_name) + : interface{itf}, deviceName{dev_name} { } -int can_bus_t::open() +int can_bus_dev_t::open() { const int canfd_on = 1; struct ifreq ifr; @@ -81,14 +81,14 @@ int can_bus_t::open() return -1; } -int can_bus_t::close() +int can_bus_dev_t::close() { ::close(can_socket_); can_socket_ = -1; } -canfd_frame can_bus_t::can_read() +canfd_frame can_bus_dev_t::read() { ssize_t nbytes; //int maxdlen; @@ -124,6 +124,19 @@ canfd_frame can_bus_t::can_read() return canfd_frame; } +/* + * Return is_running_ bool + */ +bool can_bus_dev_t::is_running() +{ + return is_running_; +} + +can_bus_t::can_bus_t(afb_binding_interface *itf, const std:string &dev_name) + : interface{itf} +{ +} + void can_bus_t::start_threads() { th_reading_ = std::thread(can_reader, interface, socket, can_message_q_); @@ -134,11 +147,33 @@ void can_bus_t::start_threads() } /* - * Return is_running_ bool + * Get a CanMessage from can_message_q and return it + * then point to the next CanMessage in queue. + * + * Return the next queue element or NULL if queue is empty. */ -bool can_bus_t::is_running() +can_message_t can_bus_dev_t::next_can_message() { - return is_running_; + if(! can_message_q_.empty()) + { + can_message_t can_msg = can_message_q_.front(); + can_message_q_.pop() + return &can_msg; + } + has_can_message_ = false; +} + +/** + * @return has_can_message_ bool + */ +bool can_bus_dev_t::has_can_message() const +{ + return has_can_message_; +} + +void can_bus_dev_t::push_new_can_message(const can_message_t& can_msg) +{ + can_message_q_.push(can_msg); } /* @@ -171,36 +206,6 @@ int can_bus_t::send_can_message(can_message_t &can_msg) return 0; } -/* - * Get a CanMessage from can_message_q and return it - * then point to the next CanMessage in queue. - * - * Return the next queue element or NULL if queue is empty. - */ -can_message_t* can_bus_t::next_can_message() -{ - if(! can_message_q_.empty()) - { - can_message_t can_msg = can_message_q_.front(); - can_message_q_.pop() - return &can_msg; - } - has_can_message_ = false; -} - -/** - * @return has_can_message_ bool - */ -bool can_bus_t::has_can_message() const -{ - return has_can_message_; -} - -void can_bus_t::insert_new_can_message(can_message_t &can_msg) -{ - can_message_q_.push(can_msg); -} - /* * Get a VehicleMessage from vehicle_message_q and return it * then point to the next VehicleMessage in queue. @@ -219,7 +224,7 @@ openxc_VehicleMessage* can_bus_t::next_vehicle_message() has_vehicle_message_ = false; } -void can_bus_t::insert_new_vehicle_message(openxc_VehicleMessage *v_msg) +void can_bus_t::push_new_vehicle_message(const openxc_VehicleMessage& v_msg) { vehicle_message_q_.push(v_msg); has_vehicle_message_ = true; diff --git a/src/can-utils.h b/src/can-utils.h deleted file mode 100644 index 16763926..00000000 --- a/src/can-utils.h +++ /dev/null @@ -1,393 +0,0 @@ -/* - * 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. - */ - -#pragma once - -#include -#include "timer.h" -#include "openxc.pb.h" - -// TODO actual max is 32 but dropped to 24 for memory considerations -#define MAX_ACCEPTANCE_FILTERS 24 -// TODO this takes up a ton of memory -#define MAX_DYNAMIC_MESSAGE_COUNT 12 - -#define CAN_MESSAGE_SIZE 8 - -#define CAN_ACTIVE_TIMEOUT_S 30 - -#define QUEUE_DECLARE(type, max_length) \ -static const int queue_##type##_max_length = max_length; \ -static const int queue_##type##_max_internal_length = max_length + 1; \ -typedef struct queue_##type##_s { \ - int head; \ - int tail; \ - type elements[max_length + 1]; \ -} queue_##type; \ -\ -bool queue_##type##_push(queue_##type* queue, type value); \ -\ -type queue_##type##_pop(queue_##type* queue); \ -\ -type queue_##type##_peek(queue_##type* queue); \ -void queue_##type##_init(queue_##type* queue); \ -int queue_##type##_length(queue_##type* queue); \ -int queue_##type##_available(queue_##type* queue); \ -bool queue_##type##_full(queue_##type* queue); \ -bool queue_##type##_empty(queue_##type* queue); \ -void queue_##type##_snapshot(queue_##type* queue, type* snapshot, int max); - -/* Public: The type signature for a CAN signal decoder. - * - * A SignalDecoder transforms a raw floating point CAN signal into a number, - * string or boolean. - * - * signal - The CAN signal that we are decoding. - * signals - The list of all signals. - * signalCount - The length of the signals array. - * value - The CAN signal parsed from the message as a raw floating point - * value. - * send - An output parameter. If the decoding failed or the CAN signal should - * not send for some other reason, this should be flipped to false. - * - * Returns a decoded value in an openxc_DynamicField struct. - */ -typedef openxc_DynamicField (*SignalDecoder)(struct CanSignal* signal, - CanSignal* signals, int signalCount, float value, bool* send); - -/* Public: The type signature for a CAN signal encoder. - * - * A SignalEncoder transforms a number, string or boolean into a raw floating - * point value that fits in the CAN signal. - * - * signal - The CAN signal to encode. - * value - The dynamic field to encode. - * send - An output parameter. If the encoding failed or the CAN signal should - * not be encoded for some other reason, this will be flipped to false. - */ -typedef uint64_t (*SignalEncoder)(struct CanSignal* signal, - openxc_DynamicField* value, bool* send); - -/* - * CanBus represent a can device definition gotten from configuraiton file - */ -class can_bus_t { - private: - afb_binding_interface *interface_; - - /* Got from conf file */ - std::string device_name; - - int can_socket_; - bool is_fdmode_on_; - struct sockaddr_can txAddress_; - - std::thread th_reading_; - bool is_running_; - std::thread th_decoding_; - std::thread th_pushing_; - - std::queue can_message_q_; - std::queue vehicle_message_q_; - - public: - int open(); - int close(); - - void start_threads(); - bool is_running(); - - int send_can_message(can_message_t can_msg); - - can_message_t* next_can_message(); - void insert_new_can_message(can_message_t &can_msg); - bool has_can_message_; - - openxc_VehicleMessage* next_vehicle_message(); - void insert_new_vehicle_message(openxc_VehicleMessage *v_msg); - bool has_vehicle_message_; -}; - -/* A compact representation of a single CAN message, meant to be used in in/out - * buffers. - * - * id - The ID of the message. - * format - the format of the message's ID. - * data - The message's data field. - * length - the length of the data array (max 8). -struct CanMessage { - uint32_t id; - CanMessageFormat format; - uint8_t data[CAN_MESSAGE_SIZE]; - uint8_t length; -}; -typedef struct CanMessage CanMessage; -*/ -class can_message_t { - private: - afb_binding_interface interface_; - uint32_t id_; - CanMessageFormat format_; - uint8_t data_[CAN_MESSAGE_SIZE]; - uint8_t length_; - - public: - uint32_t get_id() const; - int get_format() const; - uint8_t get_data() const; - uint8_t get_lenght() const; - - void set_id(uint32_t id); - void set_format(CanMessageFormat format); - void set_data(uint8_t data); - void set_lenght(uint8_t length); - - void convert_from_canfd_frame(canfd_frame frame); - canfd_frame convert_to_canfd_frame(); -}; - -QUEUE_DECLARE(can_message_t, 8); - -/* Public: The ID format for a CAN message. - * - * STANDARD - standard 11-bit CAN arbitration ID. - * EXTENDED - an extended frame, with a 29-bit arbitration ID. - */ -enum CanMessageFormat { - STANDARD, - EXTENDED, -}; -typedef enum CanMessageFormat CanMessageFormat; - -/* Public: A state encoded (SED) signal's mapping from numerical values to - * OpenXC state names. - * - * value - The integer value of the state on the CAN bus. - * name - The corresponding string name for the state in OpenXC. - */ -struct CanSignalState { - const int value; - const char* name; -}; -typedef struct CanSignalState CanSignalState; - -/* Public: A CAN signal to decode from the bus and output over USB. - * - * message - The message this signal is a part of. - * genericName - The name of the signal to be output over USB. - * bitPosition - The starting bit of the signal in its CAN message (assuming - * non-inverted bit numbering, i.e. the most significant bit of - * each byte is 0) - * bitSize - The width of the bit field in the CAN message. - * factor - The final value will be multiplied by this factor. Use 1 if you - * don't need a factor. - * offset - The final value will be added to this offset. Use 0 if you - * don't need an offset. - * minValue - The minimum value for the processed signal. - * maxValue - The maximum value for the processed signal. - * frequencyClock - A FrequencyClock struct to control the maximum frequency to - * process and send this signal. To process every value, set the - * clock's frequency to 0. - * sendSame - If true, will re-send even if the value hasn't changed. - * forceSendChanged - If true, regardless of the frequency, it will send the - * value if it has changed. - * states - An array of CanSignalState describing the mapping - * between numerical and string values for valid states. - * stateCount - The length of the states array. - * writable - True if the signal is allowed to be written from the USB host - * back to CAN. Defaults to false. - * decoder - An optional function to decode a signal from the bus to a human - * readable value. If NULL, the default numerical decoder is used. - * encoder - An optional function to encode a signal value to be written to - * CAN into a byte array. If NULL, the default numerical encoder - * is used. - * received - True if this signal has ever been received. - * lastValue - The last received value of the signal. If 'received' is false, - * this value is undefined. - */ -struct CanSignal { - struct CanMessageDefinition* message; - const char* genericName; - uint8_t bitPosition; - uint8_t bitSize; - float factor; - float offset; - float minValue; - float maxValue; - FrequencyClock frequencyClock; - bool sendSame; - bool forceSendChanged; - const CanSignalState* states; - uint8_t stateCount; - bool writable; - SignalDecoder decoder; - SignalEncoder encoder; - bool received; - float lastValue; -}; -typedef struct CanSignal CanSignal; - -/* Public: The definition of a CAN message. This includes a lot of metadata, so - * to save memory this struct should not be used for storing incoming and - * outgoing CAN messages. - * - * bus - A pointer to the bus this message is on. - * id - The ID of the message. - * format - the format of the message's ID. - * clock - an optional frequency clock to control the output of this - * message, if sent raw, or simply to mark the max frequency for custom - * handlers to retrieve. - * forceSendChanged - If true, regardless of the frequency, it will send CAN - * message if it has changed when using raw passthrough. - * lastValue - The last received value of the message. Defaults to undefined. - * This is required for the forceSendChanged functionality, as the stack - * needs to compare an incoming CAN message with the previous frame. - */ -struct CanMessageDefinition { - struct CanBus* bus; - uint32_t id; - CanMessageFormat format; - FrequencyClock frequencyClock; - bool forceSendChanged; - uint8_t lastValue[CAN_MESSAGE_SIZE]; -}; -typedef struct CanMessageDefinition CanMessageDefinition; - -/* Private: An entry in the list of acceptance filters for each CanBus. - * - * This struct is meant to be used with a LIST type from . - * - * filter - the value for the CAN acceptance filter. - * activeUserCount - The number of active consumers of this filter's messages. - * When 0, this filter can be removed. - * format - the format of the ID for the filter. -struct AcceptanceFilterListEntry { - uint32_t filter; - uint8_t activeUserCount; - CanMessageFormat format; - LIST_ENTRY(AcceptanceFilterListEntry) entries; -}; - */ - -/* Private: A type of list containing CAN acceptance filters. -LIST_HEAD(AcceptanceFilterList, AcceptanceFilterListEntry); - -struct CanMessageDefinitionListEntry { - CanMessageDefinition definition; - LIST_ENTRY(CanMessageDefinitionListEntry) entries; -}; -LIST_HEAD(CanMessageDefinitionList, CanMessageDefinitionListEntry); - */ - -/** Public: A parent wrapper for a particular set of CAN messages and associated - * CAN buses(e.g. a vehicle or program). - * - * index - A numerical ID for the message set, ideally the index in an array - * for fast lookup - * name - The name of the message set. - * busCount - The number of CAN buses defined for this message set. - * messageCount - The number of CAN messages (across all buses) defined for - * this message set. - * signalCount - The number of CAN signals (across all messages) defined for - * this message set. - * commandCount - The number of CanCommmands defined for this message set. - */ - typedef struct { - uint8_t index; - const char* name; - uint8_t busCount; - unsigned short messageCount; - unsigned short signalCount; - unsigned short commandCount; -} CanMessageSet; - -/* Public: The type signature for a function to handle a custom OpenXC command. - * - * name - the name of the received command. - * value - the value of the received command, in a DynamicField. The actual type - * may be a number, string or bool. - * event - an optional event from the received command, in a DynamicField. The - * actual type may be a number, string or bool. - * signals - The list of all signals. - * signalCount - The length of the signals array. - */ -typedef void (*CommandHandler)(const char* name, openxc_DynamicField* value, - openxc_DynamicField* event, CanSignal* signals, int signalCount); - -/* Public: The structure to represent a supported custom OpenXC command. - * - * For completely customized CAN commands without a 1-1 mapping between an - * OpenXC message from the host and a CAN signal, you can define the name of the - * command and a custom function to handle it in the VI. An example is - * the "turn_signal_status" command in OpenXC, which has a value of "left" or - * "right". The vehicle may have separate CAN signals for the left and right - * turn signals, so you will need to implement a custom command handler to send - * the correct signals. - * - * Command handlers are also useful if you want to trigger multiple CAN messages - * or signals from a signal OpenXC message. - * - * genericName - The name of the command. - * handler - An function to process the received command's data and perform some - * action. -typedef struct { - const char* genericName; - CommandHandler handler; -} CanCommand; - */ - -class CanCommand_c { - private: - const char* genericName; - CommandHandler handler; -}; - -/* Pre initialize actions made before CAN bus initialization - * - * bus - A CanBus struct defining the bus's metadata - * writable - configure the controller in a writable mode. If false, it will be - * configured as "listen only" and will not allow writes or even CAN ACKs. - * buses - An array of all CAN buses. - * busCount - The length of the buses array. - */ -void pre_initialize(CanBus* bus, bool writable, CanBus* buses, const int busCount); - -/* Post-initialize actions made after CAN bus initialization and before the - * event loop connection. - * - * bus - A CanBus struct defining the bus's metadata - * writable - configure the controller in a writable mode. If false, it will be - * configured as "listen only" and will not allow writes or even CAN ACKs. - * buses - An array of all CAN buses. - * busCount - The length of the buses array. - */ -void post_initialize(CanBus* bus, bool writable, CanBus* buses, const int busCount); - -/* Public: Check if the device is connected to an active CAN bus, i.e. it's - * received a message in the recent past. - * - * Returns true if a message was received on the CAN bus within - * CAN_ACTIVE_TIMEOUT_S seconds. - */ -bool isBusActive(CanBus* bus); - -/* Public: Log transfer statistics about all active CAN buses to the debug log. - * - * buses - an array of active CAN buses. - * busCount - the length of the buses array. - */ -void logBusStatistics(CanBus* buses, const int busCount); diff --git a/src/can-utils.hpp b/src/can-utils.hpp new file mode 100644 index 00000000..da5f81ca --- /dev/null +++ b/src/can-utils.hpp @@ -0,0 +1,394 @@ +/* + * 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. + */ + +#pragma once + +#include +#include "timer.h" +#include "openxc.pb.h" + +// TODO actual max is 32 but dropped to 24 for memory considerations +#define MAX_ACCEPTANCE_FILTERS 24 +// TODO this takes up a ton of memory +#define MAX_DYNAMIC_MESSAGE_COUNT 12 + +#define CAN_MESSAGE_SIZE 8 + +#define CAN_ACTIVE_TIMEOUT_S 30 + +/* Public: The type signature for a CAN signal decoder. + * + * A SignalDecoder transforms a raw floating point CAN signal into a number, + * string or boolean. + * + * signal - The CAN signal that we are decoding. + * signals - The list of all signals. + * signalCount - The length of the signals array. + * value - The CAN signal parsed from the message as a raw floating point + * value. + * send - An output parameter. If the decoding failed or the CAN signal should + * not send for some other reason, this should be flipped to false. + * + * Returns a decoded value in an openxc_DynamicField struct. + */ +typedef openxc_DynamicField (*SignalDecoder)(struct CanSignal* signal, + CanSignal* signals, int signalCount, float value, bool* send); + +/** + * @brief: The type signature for a CAN signal encoder. + * + * A SignalEncoder transforms a number, string or boolean into a raw floating + * point value that fits in the CAN signal. + * + * @params[signal] - The CAN signal to encode. + * @params[value] - The dynamic field to encode. + * @params[send] - An output parameter. If the encoding failed or the CAN signal should + * not be encoded for some other reason, this will be flipped to false. + */ +typedef uint64_t (*SignalEncoder)(struct CanSignal* signal, + openxc_DynamicField* value, bool* send); + +/** + * @brief Object representing a can device. Handle opening, closing and reading on the + * socket. This is the low level object to be use by can_bus_t. + * + * @params[*interface_] - afb_binding_interface to the binder. Used to log messages + * @params[device_name_] - name of the linux device handling the can bus. Generally vcan0, can0, etc. + * + */ +class can_bus_dev_t { + private: + std::string device_name_; + int can_socket_; + + int can_socket_; + bool is_fdmode_on_; + struct sockaddr_can txAddress_; + + bool has_can_message_; + std::queue can_message_q_; + + std::thread th_reading_; + bool is_running_; + + public: + int open(); + int close(); + bool is_running(); + + can_message_t* next_can_message(); + void push_new_can_message(const can_message_t& can_msg); +} + + +/** + * @brief Object used to handle decoding and manage event queue to be pushed. + * + * @params[*interface_] - afb_binding_interface to the binder. Used to log messages + * @params[conf_file_ifstream_] - stream of configuration file used to initialize + * can_bus_dev_t objects. + */ +class can_bus_t { + private: + afb_binding_interface *interface_; + + std::vector devices; + + std::thread th_decoding_; + std::thread th_pushing_; + + bool has_vehicle_message_; + std::queue vehicle_message_q_; + + public: + void start_threads(); + + int send_can_message(can_message_t can_msg); + + openxc_VehicleMessage& next_vehicle_message(); + void push_new_vehicle_message(const openxc_VehicleMessage& v_msg); +}; + +/* A compact representation of a single CAN message, meant to be used in in/out + * buffers. + * + * id - The ID of the message. + * format - the format of the message's ID. + * data - The message's data field. + * length - the length of the data array (max 8). +struct CanMessage { + uint32_t id; + CanMessageFormat format; + uint8_t data[CAN_MESSAGE_SIZE]; + uint8_t length; +}; +typedef struct CanMessage CanMessage; +*/ +class can_message_t { + private: + afb_binding_interface interface_; + uint32_t id_; + CanMessageFormat format_; + uint8_t data_[CAN_MESSAGE_SIZE]; + uint8_t length_; + + public: + uint32_t get_id() const; + int get_format() const; + uint8_t get_data() const; + uint8_t get_lenght() const; + + void set_id(uint32_t id); + void set_format(CanMessageFormat format); + void set_data(uint8_t data); + void set_lenght(uint8_t length); + + void convert_from_canfd_frame(canfd_frame frame); + canfd_frame convert_to_canfd_frame(); +}; + +QUEUE_DECLARE(can_message_t, 8); + +/* Public: The ID format for a CAN message. + * + * STANDARD - standard 11-bit CAN arbitration ID. + * EXTENDED - an extended frame, with a 29-bit arbitration ID. + */ +enum CanMessageFormat { + STANDARD, + EXTENDED, +}; +typedef enum CanMessageFormat CanMessageFormat; + +/* Public: A state encoded (SED) signal's mapping from numerical values to + * OpenXC state names. + * + * value - The integer value of the state on the CAN bus. + * name - The corresponding string name for the state in OpenXC. + */ +struct CanSignalState { + const int value; + const char* name; +}; +typedef struct CanSignalState CanSignalState; + +/* Public: A CAN signal to decode from the bus and output over USB. + * + * message - The message this signal is a part of. + * genericName - The name of the signal to be output over USB. + * bitPosition - The starting bit of the signal in its CAN message (assuming + * non-inverted bit numbering, i.e. the most significant bit of + * each byte is 0) + * bitSize - The width of the bit field in the CAN message. + * factor - The final value will be multiplied by this factor. Use 1 if you + * don't need a factor. + * offset - The final value will be added to this offset. Use 0 if you + * don't need an offset. + * minValue - The minimum value for the processed signal. + * maxValue - The maximum value for the processed signal. + * frequencyClock - A FrequencyClock struct to control the maximum frequency to + * process and send this signal. To process every value, set the + * clock's frequency to 0. + * sendSame - If true, will re-send even if the value hasn't changed. + * forceSendChanged - If true, regardless of the frequency, it will send the + * value if it has changed. + * states - An array of CanSignalState describing the mapping + * between numerical and string values for valid states. + * stateCount - The length of the states array. + * writable - True if the signal is allowed to be written from the USB host + * back to CAN. Defaults to false. + * decoder - An optional function to decode a signal from the bus to a human + * readable value. If NULL, the default numerical decoder is used. + * encoder - An optional function to encode a signal value to be written to + * CAN into a byte array. If NULL, the default numerical encoder + * is used. + * received - True if this signal has ever been received. + * lastValue - The last received value of the signal. If 'received' is false, + * this value is undefined. + */ +struct CanSignal { + struct CanMessageDefinition* message; + const char* genericName; + uint8_t bitPosition; + uint8_t bitSize; + float factor; + float offset; + float minValue; + float maxValue; + FrequencyClock frequencyClock; + bool sendSame; + bool forceSendChanged; + const CanSignalState* states; + uint8_t stateCount; + bool writable; + SignalDecoder decoder; + SignalEncoder encoder; + bool received; + float lastValue; +}; +typedef struct CanSignal CanSignal; + +/* Public: The definition of a CAN message. This includes a lot of metadata, so + * to save memory this struct should not be used for storing incoming and + * outgoing CAN messages. + * + * bus - A pointer to the bus this message is on. + * id - The ID of the message. + * format - the format of the message's ID. + * clock - an optional frequency clock to control the output of this + * message, if sent raw, or simply to mark the max frequency for custom + * handlers to retrieve. + * forceSendChanged - If true, regardless of the frequency, it will send CAN + * message if it has changed when using raw passthrough. + * lastValue - The last received value of the message. Defaults to undefined. + * This is required for the forceSendChanged functionality, as the stack + * needs to compare an incoming CAN message with the previous frame. + */ +struct CanMessageDefinition { + struct CanBus* bus; + uint32_t id; + CanMessageFormat format; + FrequencyClock frequencyClock; + bool forceSendChanged; + uint8_t lastValue[CAN_MESSAGE_SIZE]; +}; +typedef struct CanMessageDefinition CanMessageDefinition; + +/* Private: An entry in the list of acceptance filters for each CanBus. + * + * This struct is meant to be used with a LIST type from . + * + * filter - the value for the CAN acceptance filter. + * activeUserCount - The number of active consumers of this filter's messages. + * When 0, this filter can be removed. + * format - the format of the ID for the filter. +struct AcceptanceFilterListEntry { + uint32_t filter; + uint8_t activeUserCount; + CanMessageFormat format; + LIST_ENTRY(AcceptanceFilterListEntry) entries; +}; + */ + +/* Private: A type of list containing CAN acceptance filters. +LIST_HEAD(AcceptanceFilterList, AcceptanceFilterListEntry); + +struct CanMessageDefinitionListEntry { + CanMessageDefinition definition; + LIST_ENTRY(CanMessageDefinitionListEntry) entries; +}; +LIST_HEAD(CanMessageDefinitionList, CanMessageDefinitionListEntry); + */ + +/** Public: A parent wrapper for a particular set of CAN messages and associated + * CAN buses(e.g. a vehicle or program). + * + * index - A numerical ID for the message set, ideally the index in an array + * for fast lookup + * name - The name of the message set. + * busCount - The number of CAN buses defined for this message set. + * messageCount - The number of CAN messages (across all buses) defined for + * this message set. + * signalCount - The number of CAN signals (across all messages) defined for + * this message set. + * commandCount - The number of CanCommmands defined for this message set. + */ + typedef struct { + uint8_t index; + const char* name; + uint8_t busCount; + unsigned short messageCount; + unsigned short signalCount; + unsigned short commandCount; +} CanMessageSet; + +/* Public: The type signature for a function to handle a custom OpenXC command. + * + * name - the name of the received command. + * value - the value of the received command, in a DynamicField. The actual type + * may be a number, string or bool. + * event - an optional event from the received command, in a DynamicField. The + * actual type may be a number, string or bool. + * signals - The list of all signals. + * signalCount - The length of the signals array. + */ +typedef void (*CommandHandler)(const char* name, openxc_DynamicField* value, + openxc_DynamicField* event, CanSignal* signals, int signalCount); + +/* Public: The structure to represent a supported custom OpenXC command. + * + * For completely customized CAN commands without a 1-1 mapping between an + * OpenXC message from the host and a CAN signal, you can define the name of the + * command and a custom function to handle it in the VI. An example is + * the "turn_signal_status" command in OpenXC, which has a value of "left" or + * "right". The vehicle may have separate CAN signals for the left and right + * turn signals, so you will need to implement a custom command handler to send + * the correct signals. + * + * Command handlers are also useful if you want to trigger multiple CAN messages + * or signals from a signal OpenXC message. + * + * genericName - The name of the command. + * handler - An function to process the received command's data and perform some + * action. +typedef struct { + const char* genericName; + CommandHandler handler; +} CanCommand; + */ + +class CanCommand_c { + private: + const char* genericName; + CommandHandler handler; +}; + +/* Pre initialize actions made before CAN bus initialization + * + * bus - A CanBus struct defining the bus's metadata + * writable - configure the controller in a writable mode. If false, it will be + * configured as "listen only" and will not allow writes or even CAN ACKs. + * buses - An array of all CAN buses. + * busCount - The length of the buses array. + */ +void pre_initialize(CanBus* bus, bool writable, CanBus* buses, const int busCount); + +/* Post-initialize actions made after CAN bus initialization and before the + * event loop connection. + * + * bus - A CanBus struct defining the bus's metadata + * writable - configure the controller in a writable mode. If false, it will be + * configured as "listen only" and will not allow writes or even CAN ACKs. + * buses - An array of all CAN buses. + * busCount - The length of the buses array. + */ +void post_initialize(CanBus* bus, bool writable, CanBus* buses, const int busCount); + +/* Public: Check if the device is connected to an active CAN bus, i.e. it's + * received a message in the recent past. + * + * Returns true if a message was received on the CAN bus within + * CAN_ACTIVE_TIMEOUT_S seconds. + */ +bool isBusActive(CanBus* bus); + +/* Public: Log transfer statistics about all active CAN buses to the debug log. + * + * buses - an array of active CAN buses. + * busCount - the length of the buses array. + */ +void logBusStatistics(CanBus* buses, const int busCount); diff --git a/src/can_decode_message.cpp b/src/can_decode_message.cpp index 6bb6459f..7e20f882 100644 --- a/src/can_decode_message.cpp +++ b/src/can_decode_message.cpp @@ -23,8 +23,8 @@ #include -#include "can-utils.h" -#include "can-decoder.h" +#include "can-utils.hpp" +#include "can-decoder.hpp" #include "openxc.pb.h" union DynamicField @@ -36,36 +36,35 @@ union DynamicField void can_decode_message(can_bus_t &can_bus) { - can_message_t *can_message; + can_message_t can_message; std:vector signals; std:vector ::iterator signals_i; openxc_VehicleMessage vehicle_message; openxc_DynamicField search_key, ret; + bool send = true; decoder_t decoder(); - while(true) { if(can_message = can_bus.next_can_message()) { /* First we have to found which CanSignal is */ - DynamicField signal_id = (double)can_message.get_id(); - search_key = build_DynamicField(openxc_DynamicField_Type_NUM, signal_id) + search_key = build_DynamicField(openxc_DynamicField_Type::openxc_DynamicField_Type_NUM, (double)can_message.get_id()) - signals = find_signals(search_key); + signals = find_can_signals(search_key); /* Decoding the message ! Don't kill the messenger ! */ - for(signals_i=signals.begin(); signal_i != signals.end(); signals_i++) - { - subscribed_signals_i = subscribed_signals.find(signals_i); + for(const auto& sig : signals) + { + subscribed_signals_i = subscribed_signals.find(sig); if(subscribed_signals_i != subscribed_signals.end() && afb_event_is_valid(subscribed_signals_i->second)) { - ret = decoder.decodeSignal(&sig, can_message, SIGNALS, SIGNALS.size(), true); + ret = decoder.decodeSignal(sig, can_message, getSignals(), &send); - s_message = build_SimpleMessage(subscribed_signals_i->first->genericName, ret); + s_message = build_SimpleMessage(sig.genericName, ret); vehicle_message = build_VehicleMessage_with_SimpleMessage(openxc_DynamicField_Type::openxc_DynamicField_Type_NUM, s_message); vehicle_message_q.push(vehicle_message); @@ -79,69 +78,93 @@ void can_decode_message(can_bus_t &can_bus) * Build a specific VehicleMessage containing a SimpleMessage. */ openxc_VehicleMessage build_VehicleMessage_with_SimpleMessage(openxc_DynamicField_Type type, - openxc_SimpleMessage message) + const openxc_SimpleMessage& message) { struct timeb t_msec; long long int timestamp_msec; + + openxc_VehicleMessage v = {0}; + if(!ftime(&t_msec)) { timestamp_msec = ((long long int) t_msec.time) * 1000ll + (long long int) t_msec.millitm; - return openxc_VehicleMessage v = {.has_type = true, - .type = openxc_VehicleMessage_Type::openxc_VehicleMessage_Type_SIMPLE, - .has_simple_message = true, - .simple_message = message, - .has_timestamp = true, - .timestamp = timestamp_msec}; + v.has_type = true: + v.type = openxc_VehicleMessage_Type::openxc_VehicleMessage_Type_SIMPLE; + v.has_simple_message = true; + v.simple_message = message; + v.has_timestamp = true; + v.timestamp = timestamp_msec; + + return v; } - return openxc_VehicleMessage v = {.has_type = true, - .type = openxc_VehicleMessage_Type::openxc_VehicleMessage_Type_SIMPLE, - .has_simple_message = true, - .simple_message = message}; + v.has_type = true, + v.type = openxc_VehicleMessage_Type::openxc_VehicleMessage_Type_SIMPLE; + v.has_simple_message = true; + v.simple_message = message; + + return v; } /* * Build an openxc_SimpleMessage associating a name to an openxc_DynamicField */ -openxc_SimpleMessage build_SimpleMessage(std:string name, openxc_DynamicField value) +openxc_SimpleMessage build_SimpleMessage(const std::string& name, const openxc_DynamicField& value) { - return openxc_SimpleMessage s = {.has_name = true, - .name = name, - .has_value = true, - .value = value}; + + openxc_SimpleMessage s = {0}; + + s.has_name = true; + ::strncpy(s.name, name.c_str(), 100); + s.has_value = true; + s.value = value; + + return s; } - +/* + * Build an openxc_DynamicField depending what we pass as argument + */ +openxc_DynamicField build_DynamicField(const std::string& value) +{ + openxc_DynamicField d = {0} + d.has_type = true; + d.type = openxc_DynamicField_Type_STRING; + + d.has_string_value = true; + ::strncpy(d.string_value, value.c_tr(), 100); + + return d; } /* - * Build an openxc_DynamicField using its type and an union. - * Why do not use of union in first place anyway... + * Build an openxc_DynamicField depending what we pass as argument */ -openxc_DynamicField build_DynamicField(openxc_DynamicField_Type type, DynamicField field) +openxc_DynamicField build_DynamicField(double value) { - openxc_DynamicField d = {.has_type = true, - .type = type}; + openxc_DynamicField d = {0} + d.has_type = true; + d.type = openxc_DynamicField_Type_NUM; - switch(type) - { - case openxc_DynamicField_Type_BOOL: - d.has_boolean_value = true; - d.boolean_value = field; - break; - case openxc_DynamicField_Type_NUM: - d.has_numeric_value = true; - d.numeric_value = field; - break; - case openxc_DynamicField_Type_STRING: - d.has_string_value = true; - strcpy(d.string_value, field); - break; - default: - return nullptr; - } + d.has_numeric_value = true; + d.numeric_value = field; + + return d; +} +/* + * Build an openxc_DynamicField depending what we pass as argument + */ +openxc_DynamicField build_DynamicField(bool value) +{ + openxc_DynamicField d = {0} + d.has_type = true; + d.type = openxc_DynamicField_Type_BOOL; + + d.has_boolean_value = true; + d.boolean_value = field; + return d; } \ No newline at end of file diff --git a/src/can_reader.cpp b/src/can_reader.cpp index aab47b65..a8c5cf6c 100644 --- a/src/can_reader.cpp +++ b/src/can_reader.cpp @@ -30,6 +30,6 @@ void can_reader(can_bus_t &can_bus) while(can_bus.is_running()) { can_message.convert_from_canfd_frame(canbus.read()); - can_bus.insert_new_can_message(can_message); + can_bus.push_new_can_message(can_message); } } \ No newline at end of file diff --git a/src/low-can-binding.cpp b/src/low-can-binding.cpp index d5c116f8..b895adcc 100644 --- a/src/low-can-binding.cpp +++ b/src/low-can-binding.cpp @@ -40,7 +40,7 @@ #include #include -#include "obd2.h" +#include "obd2.hpp" /* * Interface between the daemon and the binding diff --git a/src/obd2.h b/src/obd2.h deleted file mode 100644 index cd362c79..00000000 --- a/src/obd2.h +++ /dev/null @@ -1,173 +0,0 @@ -/* - * 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. - */ - -/* - * A representation of an OBD-II PID. - * - * pid - The 1 byte PID. - * name - A human readable name to use for this PID when published. - * frequency - The frequency to request this PID if supported by the vehicle - * when automatic, recurring OBD-II requests are enabled. - */ - -enum UNIT { - POURCENT, - DEGREES_CELSIUS, - KPA, - RPM, - GRAMS_SEC, - SECONDS, - KM, - KM_H, - PA, - NM -}; - -const char *UNIT_NAMES[10] = { - "POURCENT", - "DEGREES_CELSIUS", - "KPA", - "RPM", - "GRAMS_SEC", - "SECONDS", - "KM", - "KM_H", - "PA", - "NM" -}; - -/* - * A representation of an OBD-II PID. - * - * pid - The 1 byte PID. - * name - A human readable name to use for this PID when published. - * min - minimum value for this pid - * max - maximum value for this pid - * unit - unit used - * frequency - The frequency to request this PID if supported by the vehicle - * when automatic, recurring OBD-II requests are enabled. - * supported - is it supported by the vehicle. Initialized after scan - * event - application framework event handler. - */ -typedef struct _Obd2Pid { - uint8_t pid; - const char* name; - const int min; - const int max; - enum UNIT unit; - int frequency; - bool supported; - struct afb_event event; -} Obd2Pid; - -/* - { pid: 0x4, name: "engine.load", frequency: 5 }, - { pid: 0x5, name: "engine.coolant.temperature", frequency: 1 }, - { pid: 0xa, name: "fuel.pressure", frequency: 1 }, - { pid: 0xb, name: "intake.manifold.pressure", frequency: 1 }, - { pid: 0xc, name: "engine.speed", frequency: 5 }, - { pid: 0xd, name: "vehicle.speed", frequency: 5 }, - { pid: 0xf, name: "intake.air.temperature", frequency: 1 }, - { pid: 0x10, name: "mass.airflow", frequency: 5 }, - { pid: 0x11, name: "throttle.position", frequency: 5 }, - { pid: 0x1f, name: "running.time", frequency: 1 }, - { pid: 0x27, name: "fuel.level", frequency: 1 }, - { pid: 0x33, name: "barometric.pressure", frequency: 1 }, - { pid: 0x4c, name: "commanded.throttle.position", frequency: 1 }, - { pid: 0x52, name: "ethanol.fuel.percentage", frequency: 1 }, - { pid: 0x5a, name: "accelerator.pedal.position", frequency: 5 }, - { pid: 0x5c, name: "engine.oil.temperature", frequency: 1 }, - { pid: 0x63, name: "engine.torque", frequency: 1 }, -}; - */ - -/* Public: Check if a request is an OBD-II PID request. - * - * Returns true if the request is a mode 1 request and it has a 1 byte PID. - */ -bool isObd2Request(DiagnosticRequest* request); - -/* Public: Decode the payload of an OBD-II PID. - * - * This function matches the type signature for a DiagnosticResponseDecoder, so - * it can be used as the decoder for a DiagnosticRequest. It returns the decoded - * value of the PID, using the standard formulas (see - * http://en.wikipedia.org/wiki/OBD-II_PIDs#Mode_01). - */ -float handleObd2Pid(const DiagnosticResponse* response, float parsedPayload); - -/* - * Object to handle obd2 session with pre-scan of supported pid - * then request them regularly - */ -class obd2_handler_c { - private: - - public: - /* - * Pre-defined OBD-II PIDs to query for if supported by the vehicle. - */ - const Obd2Pid OBD2_PIDS[] = { - { pid: 0x04, name: "obd2.engine.load", min:0, max: 100, unit: POURCENT, frequency: 5, supported: false }, - { pid: 0x05, name: "obd2.engine.coolant.temperature", min: -40, max: 215, unit: DEGREES_CELSIUS, frequency: 1, supported: false }, - { pid: 0x0a, name: "obd2.fuel.pressure", min: 0, max: 765, unit: KPA, frequency: 1, supported: false }, - { pid: 0x0b, name: "obd2.intake.manifold.pressure", min: 0, max: 255, unit: KPA, frequency: 1, supported: false }, - { pid: 0x0c, name: "obd2.engine.speed", min: 0, max: 16383, unit: RPM, frequency: 5, supported: false }, - { pid: 0x0d, name: "obd2.vehicle.speed", min: 0, max: 255, unit: KM_H, frequency: 5, supported: false }, - { pid: 0x0f, name: "obd2.intake.air.temperature", min: -40, max:215, unit: DEGREES_CELSIUS, frequency: 1, supported: false }, - { pid: 0x10, name: "obd2.mass.airflow", min: 0, max: 655, unit: GRAMS_SEC, frequency: 5, supported: false }, - { pid: 0x11, name: "obd2.throttle.position", min: 0, max: 100, unit: POURCENT, frequency: 5, supported: false }, - { pid: 0x1f, name: "obd2.running.time", min: 0, max: 65535, unit: SECONDS, frequency: 1, supported: false }, - { pid: 0x2d, name: "obd2.EGR.error", min: -100, max: 99, unit: POURCENT, frequency: 0, supported: false }, - { pid: 0x2f, name: "obd2.fuel.level", min: 0, max: 100, unit: POURCENT, frequency: 1, supported: false }, - { pid: 0x33, name: "obd2.barometric.pressure", min: 0, max: 255, unit: KPA, frequency: 1, supported: false }, - { pid: 0x4c, name: "obd2.commanded.throttle.position", min: 0, max: 100, unit: POURCENT, frequency: 1, supported: false }, - { pid: 0x52, name: "obd2.ethanol.fuel.percentage", min: 0, max: 100, unit: POURCENT, frequency: 1, supported: false }, - { pid: 0x5a, name: "obd2.accelerator.pedal.position", min: 0, max: 100, unit: POURCENT, frequency: 5, supported: false }, - { pid: 0x5b, name: "obd2.hybrid.battery-pack.remaining.life", min: 0, max: 100, unit: POURCENT, frequency: 5, supported: false }, - { pid: 0x5c, name: "obd2.engine.oil.temperature",min: -40, max: 210, unit: DEGREES_CELSIUS, frequency: 1, supported: false }, - { pid: 0x63, name: "obd2.engine.torque", min: 0, max: 65535, unit: NM, frequency: 1, supported: false }, - }; - - - /* Public: Check if a request is an OBD-II PID request. - * - * Returns true if the request is a mode 1 request and it has a 1 byte PID. - */ - void find_obd2_pid(const char *name, std::Vector *pids); - - /* Public: Check if a request is an OBD-II PID request. - * - * Returns true if the request is a mode 1 request and it has a 1 byte PID. - */ - bool is_obd2_request(DiagnosticRequest *request); - - /* - * Public: Check if requested signal name is an obd2 pid - * - * Returns true if name began with ob2.* else false. - */ - bool is_obd2_signal(const char *name); - - /* - * Public: pass response to UDS-C library function - * diagnostic_decode_obd2_pid() - * - * Return: float number representing the requested value. - */ - bool decode_obd2_response(DiagnosticResponse* responce); -} \ No newline at end of file diff --git a/src/obd2.hpp b/src/obd2.hpp new file mode 100644 index 00000000..cd362c79 --- /dev/null +++ b/src/obd2.hpp @@ -0,0 +1,173 @@ +/* + * 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. + */ + +/* + * A representation of an OBD-II PID. + * + * pid - The 1 byte PID. + * name - A human readable name to use for this PID when published. + * frequency - The frequency to request this PID if supported by the vehicle + * when automatic, recurring OBD-II requests are enabled. + */ + +enum UNIT { + POURCENT, + DEGREES_CELSIUS, + KPA, + RPM, + GRAMS_SEC, + SECONDS, + KM, + KM_H, + PA, + NM +}; + +const char *UNIT_NAMES[10] = { + "POURCENT", + "DEGREES_CELSIUS", + "KPA", + "RPM", + "GRAMS_SEC", + "SECONDS", + "KM", + "KM_H", + "PA", + "NM" +}; + +/* + * A representation of an OBD-II PID. + * + * pid - The 1 byte PID. + * name - A human readable name to use for this PID when published. + * min - minimum value for this pid + * max - maximum value for this pid + * unit - unit used + * frequency - The frequency to request this PID if supported by the vehicle + * when automatic, recurring OBD-II requests are enabled. + * supported - is it supported by the vehicle. Initialized after scan + * event - application framework event handler. + */ +typedef struct _Obd2Pid { + uint8_t pid; + const char* name; + const int min; + const int max; + enum UNIT unit; + int frequency; + bool supported; + struct afb_event event; +} Obd2Pid; + +/* + { pid: 0x4, name: "engine.load", frequency: 5 }, + { pid: 0x5, name: "engine.coolant.temperature", frequency: 1 }, + { pid: 0xa, name: "fuel.pressure", frequency: 1 }, + { pid: 0xb, name: "intake.manifold.pressure", frequency: 1 }, + { pid: 0xc, name: "engine.speed", frequency: 5 }, + { pid: 0xd, name: "vehicle.speed", frequency: 5 }, + { pid: 0xf, name: "intake.air.temperature", frequency: 1 }, + { pid: 0x10, name: "mass.airflow", frequency: 5 }, + { pid: 0x11, name: "throttle.position", frequency: 5 }, + { pid: 0x1f, name: "running.time", frequency: 1 }, + { pid: 0x27, name: "fuel.level", frequency: 1 }, + { pid: 0x33, name: "barometric.pressure", frequency: 1 }, + { pid: 0x4c, name: "commanded.throttle.position", frequency: 1 }, + { pid: 0x52, name: "ethanol.fuel.percentage", frequency: 1 }, + { pid: 0x5a, name: "accelerator.pedal.position", frequency: 5 }, + { pid: 0x5c, name: "engine.oil.temperature", frequency: 1 }, + { pid: 0x63, name: "engine.torque", frequency: 1 }, +}; + */ + +/* Public: Check if a request is an OBD-II PID request. + * + * Returns true if the request is a mode 1 request and it has a 1 byte PID. + */ +bool isObd2Request(DiagnosticRequest* request); + +/* Public: Decode the payload of an OBD-II PID. + * + * This function matches the type signature for a DiagnosticResponseDecoder, so + * it can be used as the decoder for a DiagnosticRequest. It returns the decoded + * value of the PID, using the standard formulas (see + * http://en.wikipedia.org/wiki/OBD-II_PIDs#Mode_01). + */ +float handleObd2Pid(const DiagnosticResponse* response, float parsedPayload); + +/* + * Object to handle obd2 session with pre-scan of supported pid + * then request them regularly + */ +class obd2_handler_c { + private: + + public: + /* + * Pre-defined OBD-II PIDs to query for if supported by the vehicle. + */ + const Obd2Pid OBD2_PIDS[] = { + { pid: 0x04, name: "obd2.engine.load", min:0, max: 100, unit: POURCENT, frequency: 5, supported: false }, + { pid: 0x05, name: "obd2.engine.coolant.temperature", min: -40, max: 215, unit: DEGREES_CELSIUS, frequency: 1, supported: false }, + { pid: 0x0a, name: "obd2.fuel.pressure", min: 0, max: 765, unit: KPA, frequency: 1, supported: false }, + { pid: 0x0b, name: "obd2.intake.manifold.pressure", min: 0, max: 255, unit: KPA, frequency: 1, supported: false }, + { pid: 0x0c, name: "obd2.engine.speed", min: 0, max: 16383, unit: RPM, frequency: 5, supported: false }, + { pid: 0x0d, name: "obd2.vehicle.speed", min: 0, max: 255, unit: KM_H, frequency: 5, supported: false }, + { pid: 0x0f, name: "obd2.intake.air.temperature", min: -40, max:215, unit: DEGREES_CELSIUS, frequency: 1, supported: false }, + { pid: 0x10, name: "obd2.mass.airflow", min: 0, max: 655, unit: GRAMS_SEC, frequency: 5, supported: false }, + { pid: 0x11, name: "obd2.throttle.position", min: 0, max: 100, unit: POURCENT, frequency: 5, supported: false }, + { pid: 0x1f, name: "obd2.running.time", min: 0, max: 65535, unit: SECONDS, frequency: 1, supported: false }, + { pid: 0x2d, name: "obd2.EGR.error", min: -100, max: 99, unit: POURCENT, frequency: 0, supported: false }, + { pid: 0x2f, name: "obd2.fuel.level", min: 0, max: 100, unit: POURCENT, frequency: 1, supported: false }, + { pid: 0x33, name: "obd2.barometric.pressure", min: 0, max: 255, unit: KPA, frequency: 1, supported: false }, + { pid: 0x4c, name: "obd2.commanded.throttle.position", min: 0, max: 100, unit: POURCENT, frequency: 1, supported: false }, + { pid: 0x52, name: "obd2.ethanol.fuel.percentage", min: 0, max: 100, unit: POURCENT, frequency: 1, supported: false }, + { pid: 0x5a, name: "obd2.accelerator.pedal.position", min: 0, max: 100, unit: POURCENT, frequency: 5, supported: false }, + { pid: 0x5b, name: "obd2.hybrid.battery-pack.remaining.life", min: 0, max: 100, unit: POURCENT, frequency: 5, supported: false }, + { pid: 0x5c, name: "obd2.engine.oil.temperature",min: -40, max: 210, unit: DEGREES_CELSIUS, frequency: 1, supported: false }, + { pid: 0x63, name: "obd2.engine.torque", min: 0, max: 65535, unit: NM, frequency: 1, supported: false }, + }; + + + /* Public: Check if a request is an OBD-II PID request. + * + * Returns true if the request is a mode 1 request and it has a 1 byte PID. + */ + void find_obd2_pid(const char *name, std::Vector *pids); + + /* Public: Check if a request is an OBD-II PID request. + * + * Returns true if the request is a mode 1 request and it has a 1 byte PID. + */ + bool is_obd2_request(DiagnosticRequest *request); + + /* + * Public: Check if requested signal name is an obd2 pid + * + * Returns true if name began with ob2.* else false. + */ + bool is_obd2_signal(const char *name); + + /* + * Public: pass response to UDS-C library function + * diagnostic_decode_obd2_pid() + * + * Return: float number representing the requested value. + */ + bool decode_obd2_response(DiagnosticResponse* responce); +} \ No newline at end of file diff --git a/src/timer.h b/src/timer.h deleted file mode 100644 index 76eb51df..00000000 --- a/src/timer.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * 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. - */ - -#pragma once - -//typedef unsigned long (*TimeFunction)(); - -/* Public: A frequency counting clock. - * - * frequency - the clock frequency in Hz. - * last_time - the last time (in milliseconds since startup) that the clock - * ticked. - * time_function - a function returning current time in ms - */ -typedef struct { - float frequency; - unsigned long lastTick; - TimeFunction timeFunction; -} FrequencyClock; diff --git a/src/timer.hpp b/src/timer.hpp new file mode 100644 index 00000000..76eb51df --- /dev/null +++ b/src/timer.hpp @@ -0,0 +1,33 @@ +/* + * 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. + */ + +#pragma once + +//typedef unsigned long (*TimeFunction)(); + +/* Public: A frequency counting clock. + * + * frequency - the clock frequency in Hz. + * last_time - the last time (in milliseconds since startup) that the clock + * ticked. + * time_function - a function returning current time in ms + */ +typedef struct { + float frequency; + unsigned long lastTick; + TimeFunction timeFunction; +} FrequencyClock; -- cgit 1.2.3-korg