diff options
-rw-r--r-- | src/CMakeLists.txt | 2 | ||||
-rw-r--r-- | src/can-signals.cpp | 70 | ||||
-rw-r--r-- | src/can-signals.hpp | 68 | ||||
-rw-r--r-- | src/can-utils.cpp | 28 | ||||
-rw-r--r-- | src/can-utils.hpp | 174 | ||||
-rw-r--r-- | src/can_decode_message.cpp | 105 | ||||
-rw-r--r-- | src/can_event_push.cpp | 39 | ||||
-rw-r--r-- | src/low-can-binding.cpp | 121 | ||||
-rw-r--r-- | src/low-can-binding.hpp | 63 | ||||
-rw-r--r-- | src/obd2.cpp | 2 | ||||
-rw-r--r-- | src/obd2.hpp | 54 | ||||
-rw-r--r-- | src/openxc-utils.cpp | 127 | ||||
-rw-r--r-- | src/openxc-utils.hpp | 53 |
13 files changed, 533 insertions, 373 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 84e8ecf..4f95cce 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -65,7 +65,7 @@ link_libraries(${EXTRAS_LIBRARIES}) message(STATUS "Creation of ${PROJECT_NAME} binding for AFB-DAEMON") ########################################################################### -add_library(${PROJECT_NAME}-binding MODULE ${PROJECT_NAME}-binding.cpp can-signals.cpp) +add_library(${PROJECT_NAME}-binding MODULE ${PROJECT_NAME}-binding.cpp can-signals.cpp can-utils.cpp obd2.cpp) set_target_properties(${PROJECT_NAME}-binding PROPERTIES PREFIX "" diff --git a/src/can-signals.cpp b/src/can-signals.cpp index b299693..c6a8ae9 100644 --- a/src/can-signals.cpp +++ b/src/can-signals.cpp @@ -15,57 +15,65 @@ * limitations under the License. */ -#include <string> -#include <vector> -#include <fnmatch.h> -#include "can-signals.h" +#include "can-signals.hpp" -/* Can signal event map making access to afb_event - * external to openxc existing structure. - */ -std::map <CanSignal, struct afb_event> subscribed_signals; -std::map <CanSignal, struct afb_event>::iterator subscribed_signals_i; +const std::vector<CanSignal> getSignals() +{ + return SIGNALS[MESSAGE_SET_ID]; +} -#define MESSAGE_SET_ID 0 -std::vector <CanSignal> find_can_signals(openxc_DynamicField &key) +size_t getSignalCount() { - std::vector <CanSignal> signals; - int n_signals, i; + return SIGNALS[MESSAGE_SET_ID].size(); +} - n_signals = getSignalCount(); +std::vector<CanSignal> find_can_signals(openxc_DynamicField& key) +{ + std::vector<CanSignal> signals; - switch(key->type): + switch(key.type) { case openxc_DynamicField_Type::openxc_DynamicField_Type_STRING: - for(const CanSignal& s : SIGNALS[MESSAGE_SET_ID]) + for(const CanSignal& s : getSignals()) { - if(fnmatch(key->string_value, s.genericName) == 0) + if(fnmatch(key.string_value, s.genericName, FNM_CASEFOLD) == 0) signals.push_back(s); } break; case openxc_DynamicField_Type::openxc_DynamicField_Type_NUM: - for(const CanSignal& s : SIGNALS[MESSAGE_SET_ID]) + for(const CanSignal& s : getSignals()) { CanMessageDefinition *msg_def = s.message; - if(msg_def->id == key->numeric_value) - signals.push_back(s) + if(msg_def->id == key.numeric_value) + signals.push_back(s); } break; default: ERROR(interface, "find_can_signals: wrong openxc_DynamicField specified. Use openxc_DynamicField_Type_NUM or openxc_DynamicField_Type_STRING type only."); - return NULL; + CanSignal cs; + ::memset(&cs, 0, sizeof(CanSignal)); + signals.push_back(cs); + return signals; break; } - return signals; } -std::vector<CanSignal>& getSignals() -{ - return SIGNALS[MESSAGE_SET_ID]; -} - -int getSignalCount() -{ - return SIGNALS[MESSAGE_SET_ID].size(); -}
\ No newline at end of file + 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;
\ No newline at end of file diff --git a/src/can-signals.hpp b/src/can-signals.hpp index 2720513..b115263 100644 --- a/src/can-signals.hpp +++ b/src/can-signals.hpp @@ -17,30 +17,53 @@ #pragma once -#include "can-utils.hpp" +#include <queue> #include <string> +#include <vector> +#include <fnmatch.h> +#include <linux/can.h> + +#include "can-utils.hpp" +#include "low-can-binding.hpp" + +#define MESSAGE_SET_ID 0 + +/** Can signal event map making access to afb_event + * external to openxc existing structure. + */ +static std::map<std::string, struct afb_event> subscribed_signals; +static std::map<std::string, struct afb_event>::iterator subscribed_signals_i; + +/** + * @brief Dumb SIGNALS array. It is composed by CanMessageSet + * SIGNALS[MESSAGE_SET_ID][CanSignal] + */ +std::vector<std::vector<CanSignal>> SIGNALS { + { // message set: example + } +}; /** 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. - * */ + * + * 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. - * */ + * 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. - * */ + * configuration. + */ CanMessageDefinition* getMessages(); /* Public: Return signals from an signals array filtered on name. @@ -48,10 +71,10 @@ CanMessageDefinition* getMessages(); 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. + * 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(); @@ -59,17 +82,17 @@ CanCommand* getCommands(); int getCommandCount(); /* Public: Return the length of the array returned by getSignals(). */ -int getSignalCount(); +size_t 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. - * */ +/** + * @brief 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(); - /** * @brief Find one or many signals based on its name or id * passed through openxc_DynamicField. @@ -77,6 +100,11 @@ CanBus* getCanBuses(); * params[openxc_DynamicField&] - a const reference with the key to search into signal. * Key is either a signal name or its CAN arbitration id. * - * return[std::vector<CanSignal>] return found CanSignal array. + * return[std::vector<std::string>] return found CanSignal generic name vector. */ -std::vector <CanSignal> find_can_signals(const openxc_DynamicField &key)
\ No newline at end of file +std::vector<CanSignal> find_can_signals(const openxc_DynamicField &key); + +uint32_t get_CanSignal_id(const CanSignal& sig) +{ + return sig.message->id; +}
\ No newline at end of file diff --git a/src/can-utils.cpp b/src/can-utils.cpp index 8d5f025..72f00aa 100644 --- a/src/can-utils.cpp +++ b/src/can-utils.cpp @@ -15,7 +15,7 @@ * limitations under the License. */ -#pragma once +#include "can-utils.hpp" /******************************************************************************** * @@ -23,8 +23,7 @@ * *********************************************************************************/ - -can_bus_dev_t::can_bus_dev_t(afb_binding_interface *itf, const std:string &dev_name) +can_bus_dev_t::can_bus_dev_t(const std::string &dev_name) : device_name_{dev_name} { } @@ -59,7 +58,7 @@ int can_bus_dev_t::open() /* Attempts to open a socket to CAN bus */ ::strcpy(ifr.ifr_name, device); - if(ioctl(can_socket_, SIOCGIFINDEX, &ifr) < 0) + if(::ioctl(can_socket_, SIOCGIFINDEX, &ifr) < 0) ERROR(interface_, "open_can_dev: ioctl failed"); else { @@ -119,6 +118,7 @@ canfd_frame can_bus_dev_t::read() ERROR(interface_, "read_can: %s interface down", device); ERROR(interface_, "read_can: Error reading CAN bus"); ::memset(&canfd_frame, 0, sizeof(canfd_frame)); + is_running_ = false; break; } @@ -189,8 +189,8 @@ bool can_bus_dev_t::has_can_message() const * *********************************************************************************/ -can_bus_t::can_bus_t(afb_binding_interface *itf, std::ifstream& conf_file) - : interface{itf}, conf_file_{conf_file} +can_bus_t::can_bus_t(const afb_binding_interface *itf, int& conf_file) + : interface_{itf}, conf_file_{conf_file} { } @@ -205,7 +205,6 @@ void can_bus_t::start_threads() th_pushing_ = std::thread(can_event_push, this); } - /** * @brief Initialize as many as can_bus_dev_t objects with their respective reading thread * @@ -245,18 +244,17 @@ int init_can_dev() std::vector<std::string> read_conf() { std::vector<std::string> ret; - std::string fd_conf_content; json_object jo, canbus; int n, i, ok; - /* Open JSON conf file */ if (conf_file_) { - conf_file_.seekg(0, std::ios::end); - conf_file_.resize(conf_file_.tellg()); - conf_file_.seekg(0, std::ios::beg); - conf_file_.read(&fd_conf_content[0], fd_conf_content.size()); - conf_file_.close(); + std::string fd_conf_content; + std::fseek(conf_file_, 0, SEEK_END); + fd_conf_content.resize(std::ftell(conf_file_)); + std::rewind(fp); + std::fread(&fd_conf_content[0], 1, fd_conf_content.size(), conf_file_); + std::fclose(conf_file_); jo = json_tokener_parse(&fd_conf_content); @@ -441,7 +439,7 @@ void can_message_t::convert_from_canfd_frame(canfd_frame &frame) ERROR(interface_, "can_message_t: canfd_frame data too long to be stored into CanMessage object"); } -canfd_frame convert_to_canfd_frame() +canfd_frame can_message_t::convert_to_canfd_frame() { canfd_frame frame; diff --git a/src/can-utils.hpp b/src/can-utils.hpp index db97b4b..0b0971d 100644 --- a/src/can-utils.hpp +++ b/src/can-utils.hpp @@ -17,9 +17,18 @@ #pragma once +#include <map> +#include <queue> +#include <vector> +#include <cstdio> #include <string> +#include <thread> +#include <linux/can.h> + #include "timer.hpp" #include "openxc.pb.h" +#include <afb/afb-binding.h> +#include <afb/afb-service-itf.h> // TODO actual max is 32 but dropped to 24 for memory considerations #define MAX_ACCEPTANCE_FILTERS 24 @@ -30,20 +39,21 @@ #define CAN_ACTIVE_TIMEOUT_S 30 -/* Public: The type signature for a CAN signal decoder. +/** + * @brief The type signature for a CAN signal decoder. * - * A SignalDecoder transforms a raw floating point CAN signal into a number, + * @desc 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. + * @param[in] CanSignal signal - The CAN signal that we are decoding. + * @param[in] CanSignal signals - The list of all signals. + * @param[in] int signalCount - The length of the signals array. + * @param[in] float value - The CAN signal parsed from the message as a raw floating point + * value. + * @param[out] bool 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. + * @return a decoded value in an openxc_DynamicField struct. */ typedef openxc_DynamicField (*SignalDecoder)(struct CanSignal* signal, CanSignal* signals, int signalCount, float value, bool* send); @@ -51,7 +61,7 @@ typedef openxc_DynamicField (*SignalDecoder)(struct CanSignal* signal, /** * @brief: The type signature for a CAN signal encoder. * - * A SignalEncoder transforms a number, string or boolean into a raw floating + * @desc 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. @@ -62,7 +72,8 @@ typedef openxc_DynamicField (*SignalDecoder)(struct CanSignal* signal, typedef uint64_t (*SignalEncoder)(struct CanSignal* signal, openxc_DynamicField* value, bool* send); -/* Public: The ID format for a CAN message. +/** + * @brief The ID format for a CAN message. * * STANDARD - standard 11-bit CAN arbitration ID. * EXTENDED - an extended frame, with a 29-bit arbitration ID. @@ -73,13 +84,17 @@ enum CanMessageFormat { }; typedef enum CanMessageFormat CanMessageFormat; -/* A compact representation of a single CAN message, meant to be used in in/out +/** + * @brief 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). + * param[in] uint32_t id - The ID of the message. + * param[in] CanMessageFormat format - the format of the message's ID. + * param[in] uint8_t data - The message's data field. + * @param[in] uint8_t length - the length of the data array (max 8). +************************* +* old CanMessage struct * +************************* struct CanMessage { uint32_t id; CanMessageFormat format; @@ -90,7 +105,7 @@ typedef struct CanMessage CanMessage; */ class can_message_t { private: - afb_binding_interface interface_; + const struct afb_binding_interface *interface_; uint32_t id_; CanMessageFormat format_; uint8_t data_[CAN_MESSAGE_SIZE]; @@ -115,9 +130,7 @@ class can_message_t { * @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. - * + * @params[in] std::string device_name_ - name of the linux device handling the can bus. Generally vcan0, can0, etc. */ class can_bus_dev_t { private: @@ -133,6 +146,8 @@ class can_bus_dev_t { bool is_running_; public: + can_bus_dev_t(const std::string& dev_name); + int open(); int close(); bool is_running(); @@ -145,13 +160,13 @@ class can_bus_dev_t { /** * @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. + * @params[in] interface_ - afb_binding_interface pointer to the binder. Used to log messages + * @params[in] conf_file_ - configuration file handle used to initialize can_bus_dev_t objects. */ class can_bus_t { private: - afb_binding_interface *interface_; + const struct afb_binding_interface *interface_; + int conf_file_; std::thread th_decoding_; std::thread th_pushing_; @@ -160,6 +175,7 @@ class can_bus_t { std::queue <openxc_VehicleMessage> vehicle_message_q_; public: + can_bus_t(const struct afb_binding_interface *itf, int& conf_file); int init_can_dev(); std::vector<std::string> read_conf(); @@ -172,11 +188,12 @@ class can_bus_t { bool has_vehicle_message() const; }; -/* Public: A state encoded (SED) signal's mapping from numerical values to +/** + * @brief 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. + * @param[in] in value - The integer value of the state on the CAN bus. + * @param[in] char* name - The corresponding string name for the state in OpenXC. */ struct CanSignalState { const int value; @@ -184,38 +201,39 @@ struct CanSignalState { }; typedef struct CanSignalState CanSignalState; -/* Public: A CAN signal to decode from the bus and output over USB. +/** + * @brief 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 + * @param[in] message - The message this signal is a part of. + * @param[in] genericName - The name of the signal to be output over USB. + * @param[in] 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 + * @param[in] bitSize - The width of the bit field in the CAN message. + * @param[in] 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 + * @param[in] 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 + * @param[in] minValue - The minimum value for the processed signal. + * @param[in] maxValue - The maximum value for the processed signal. + * @param[in] 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 + * @param[in] sendSame - If true, will re-send even if the value hasn't changed. + * @param[in] forceSendChanged - If true, regardless of the frequency, it will send the * value if it has changed. - * states - An array of CanSignalState describing the mapping + * @param[in] 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 + * @param[in] stateCount - The length of the states array. + * @param[in] 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 + * @param[in] decoder - An optional function to decode a signal from the bus to a human + * readable value. If NULL, the default numerical decoder is used. + * @param[in] 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, + * @param[in] received - True if this signal has ever been received. + * @param[in] lastValue - The last received value of the signal. If 'received' is false, * this value is undefined. */ struct CanSignal { @@ -240,19 +258,20 @@ struct CanSignal { }; typedef struct CanSignal CanSignal; -/* Public: The definition of a CAN message. This includes a lot of metadata, so +/** + * @brief 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 + * @param[in] bus - A pointer to the bus this message is on. + * @param[in] id - The ID of the message. + * @param[in] format - the format of the message's ID. + * @param[in] 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 + * @param[in] 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. + * @param[in] 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. */ @@ -292,18 +311,19 @@ struct CanMessageDefinitionListEntry { LIST_HEAD(CanMessageDefinitionList, CanMessageDefinitionListEntry); */ -/** Public: A parent wrapper for a particular set of CAN messages and associated +/** + * @brief 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 + * @param[in] 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 + * @param[in] name - The name of the message set. + * @param[in] busCount - The number of CAN buses defined for this message set. + * @param[in] 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 + * @param[in] signalCount - The number of CAN signals (across all messages) defined for * this message set. - * commandCount - The number of CanCommmands defined for this message set. + * @param[in] commandCount - The number of CanCommmands defined for this message set. */ typedef struct { uint8_t index; @@ -314,15 +334,16 @@ LIST_HEAD(CanMessageDefinitionList, CanMessageDefinitionListEntry); unsigned short commandCount; } CanMessageSet; -/* Public: The type signature for a function to handle a custom OpenXC command. +/** + * @brief 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 + * @param[in] char* name - the name of the received command. + * @param[in] openxc_DynamicField* 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 + * @param[in] openxc_DynamicField* 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. + * @param[in] CanSignal* signals - The list of all signals. + * @param[in] int signalCount - The length of the signals array. */ typedef void (*CommandHandler)(const char* name, openxc_DynamicField* value, openxc_DynamicField* event, CanSignal* signals, int signalCount); @@ -349,15 +370,16 @@ typedef struct { CommandHandler handler; } CanCommand; -/* Pre initialize actions made before CAN bus initialization +/** + * @brief 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 + * @param[in] can_bus_dev_t bus - A CanBus struct defining the bus's metadata + * @param[in] bool 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. + * @param[in] buses - An array of all CAN buses. + * @param[in] int busCount - The length of the buses array. */ -void pre_initialize(CanBus* bus, bool writable, CanBus* buses, const int busCount); +void pre_initialize(can_bus_dev_t* bus, bool writable, CanBus* buses, const int busCount); /* Post-initialize actions made after CAN bus initialization and before the * event loop connection. @@ -368,7 +390,7 @@ void pre_initialize(CanBus* bus, bool writable, CanBus* buses, const int busCoun * 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); +void post_initialize(can_bus_dev_t* 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. @@ -376,7 +398,7 @@ void post_initialize(CanBus* bus, bool writable, CanBus* buses, const int busCou * Returns true if a message was received on the CAN bus within * CAN_ACTIVE_TIMEOUT_S seconds. */ -bool isBusActive(CanBus* bus); +bool isBusActive(can_bus_dev_t* bus); /* Public: Log transfer statistics about all active CAN buses to the debug log. * diff --git a/src/can_decode_message.cpp b/src/can_decode_message.cpp index 7e20f88..a28fa18 100644 --- a/src/can_decode_message.cpp +++ b/src/can_decode_message.cpp @@ -26,13 +26,7 @@ #include "can-utils.hpp" #include "can-decoder.hpp" #include "openxc.pb.h" - -union DynamicField -{ - char string[100]; - double numeric_value; - bool boolean_value; -}; +#include "openxc-utils.hpp" void can_decode_message(can_bus_t &can_bus) { @@ -57,7 +51,7 @@ void can_decode_message(can_bus_t &can_bus) /* Decoding the message ! Don't kill the messenger ! */ for(const auto& sig : signals) { - subscribed_signals_i = subscribed_signals.find(sig); + subscribed_signals_i = subscribed_signals.find(sig.genericName); if(subscribed_signals_i != subscribed_signals.end() && afb_event_is_valid(subscribed_signals_i->second)) @@ -73,98 +67,3 @@ 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, - 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; - - 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; - } - - 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(const std::string& name, const openxc_DynamicField& 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 depending what we pass as argument - */ -openxc_DynamicField build_DynamicField(double value) -{ - openxc_DynamicField d = {0} - d.has_type = true; - d.type = openxc_DynamicField_Type_NUM; - - 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_event_push.cpp b/src/can_event_push.cpp index 3964f97..d3f4cbd 100644 --- a/src/can_event_push.cpp +++ b/src/can_event_push.cpp @@ -23,6 +23,7 @@ #include <afb/afb-binding.h> #include "can-utils.h" +#include "openxc-utils.hpp" #include "openxc.pb.h" #include "json-c/json.h" @@ -37,43 +38,9 @@ void can_event_push(can_bus_t& can_bus) if(v_message = can_bus->next_vehicle_message()) { s_message = get_simple_message(v_msg); - const auto& it_event = subscribed_signals.find(s_msg.name); + const auto& it_event = subscribed_signals.find(s_message.name); if(! it_event->end() && afb_event_is_valid(it_event->second)) - afb_event_push(it_event->second, jsonify_simple(s_msg)); + afb_event_push(it_event->second, jsonify_simple(s_message)); } } } - -void jsonify_DynamicField(const openxc_DynamicField& field, const json_object& value) -{ - if(field.has_numeric_value) - json_object_object_add(value, "value", json_object_new_double(field.numeric_value)); - else if(field.has_boolean_value) - json_object_object_add(value, "value", json_object_new_boolean(field.boolean_value)); - else if(field.has_string_value) - json_object_object_add(value, "value", json_object_new_string(field.string_value)); - - return value; -} - -/* Extract the simple message value from an openxc_VehicleMessage - * and return it, or null if there isn't. - */ -openxc_SimpleMessage get_simple_message(const openxc_VehicleMessage& v_msg) -{ - return v_msg.has_simple_message ? v_msg.simple_message : {0}; -} - -json_object jsonify_simple(const openxc_SimpleMessage& s_msg) -{ - json_object *json; - json = nullptr; - - if(s_msg->has_name) - { - json = json_object_new_object(); - json_object_object_add(json, "name", json_object_new_string(s_msg->name)); - jsonify_DynamicField(&s_msg->value, json); - } - return json; -}
\ No newline at end of file diff --git a/src/low-can-binding.cpp b/src/low-can-binding.cpp index c5fadbe..23aaf90 100644 --- a/src/low-can-binding.cpp +++ b/src/low-can-binding.cpp @@ -33,24 +33,16 @@ #include <functional> #include <memory> #include <thread> -#include <fstream> #include <json-c/json.h> #include <openxc.pb.h> -#include <afb/afb-binding.h> -#include <afb/afb-service-itf.h> - +#include "low-can-binding.hpp" +#include "openxc-utils.hpp" #include "obd2.hpp" #include "can-utils.hpp" #include "can-signals.hpp" -/* - * Interface between the daemon and the binding - */ -static const struct afb_binding_interface *interface; -static obd2_handler_t obd2_handler(); - /******************************************************************************** * * Event management @@ -63,11 +55,11 @@ static obd2_handler_t obd2_handler(); * *********************************************************************************/ -static int subscribe_unsubscribe_signal(struct afb_req request, bool subscribe, std::vector<CanSignal>::const_iterator& sig_i) +static int subscribe_unsubscribe_signal(struct afb_req request, bool subscribe, const CanSignal& sig) { int ret; - const auto& ss_i = subscribed_signals.find(sig_i); + const auto& ss_i = subscribed_signals.find(sig.genericName); if (ss_i != subscribed_signals.end()) { if(!afb_event_is_valid(ss_i->second)) @@ -79,7 +71,7 @@ static int subscribe_unsubscribe_signal(struct afb_req request, bool subscribe, } else { - ss_i->second = afb_daemon_make_event(interface->daemon, ss_i->first.genericName); + ss_i->second = afb_daemon_make_event(interface->daemon, ss_i->first.c_str()); if (!afb_event_is_valid(ss_i->second)) { ERROR(interface, "Can't create an event, something goes wrong."); @@ -90,7 +82,7 @@ static int subscribe_unsubscribe_signal(struct afb_req request, bool subscribe, } else { - subscribed_signals[sig_i] = afb_daemon_make_event(interface->daemon, sig_i->genericName); + subscribed_signals[sig.genericName] = afb_daemon_make_event(interface->daemon, sig.genericName); if (!afb_event_is_valid(ss_i->second)) { ERROR(interface, "Can't create an event, something goes wrong."); @@ -98,9 +90,9 @@ static int subscribe_unsubscribe_signal(struct afb_req request, bool subscribe, } } - if (((subscribe ? afb_req_subscribe : afb_req_unsubscribe)(request, subscribed_signals[sig_i])) < 0) + if (((subscribe ? afb_req_subscribe : afb_req_unsubscribe)(request, subscribed_signals[sig.genericName])) < 0) { - ERROR(interface, "Operation goes wrong for signal: %s", sig_i->genericName); + ERROR(interface, "Operation goes wrong for signal: %s", sig.genericName); ret = 0; } else @@ -124,12 +116,11 @@ static int subscribe_unsubscribe_signals(struct afb_req request, bool subscribe, static int subscribe_unsubscribe_all(struct afb_req request, bool subscribe) { - int n, e; + int e = 0; - n = obd2_handler.OBD2_PIDS.size(); - e = 0; - for (const auto& pid : obd2_handler.OBD2_PIDS) - e += !subscribe_unsubscribe_signals(request, subscribe, pid); + //for (const auto& sig : SIGNALS) + // e += !subscribe_unsubscribe_signals(request, subscribe, sig); + e += !subscribe_unsubscribe_signals(request, subscribe, SIGNALS[MESSAGE_SET_ID]); return e == 0; } @@ -150,7 +141,8 @@ static int subscribe_unsubscribe_name(struct afb_req request, bool subscribe, co } else { - sig = find_can_signals(name); + openxc_DynamicField search_key = build_DynamicField(name); + sig = find_can_signals(search_key); if (sig.empty()) ret = 0; } @@ -188,57 +180,60 @@ static void subscribe_unsubscribe(struct afb_req request, bool subscribe) afb_req_fail(request, "error", NULL); } -static void subscribe(struct afb_req request) -{ - subscribe_unsubscribe(request, true); -} - -static void unsubscribe(struct afb_req request) -{ - subscribe_unsubscribe(request, false); -} - static const struct afb_verb_desc_v1 verbs[]= { - { .name= "subscribe", .session= AFB_SESSION_NONE, .callback= subscribe, .info= "subscribe to notification of CAN bus messages." }, - { .name= "unsubscribe", .session= AFB_SESSION_NONE, .callback= unsubscribe, .info= "unsubscribe a previous subscription." } + { .name= "subscribe", .session= AFB_SESSION_NONE, .callback= subscribe, .info= "subscribe to notification of CAN bus messages." }, + { .name= "unsubscribe", .session= AFB_SESSION_NONE, .callback= unsubscribe, .info= "unsubscribe a previous subscription." } }; -static const struct afb_binding binding_desc = { - .type = AFB_BINDING_VERSION_1, - .v1 = { - .info = "CAN bus service", - .prefix = "can", - .verbs = verbs +static const struct afb_binding binding_desc { + AFB_BINDING_VERSION_1, + { + "CAN bus service", + "can", + verbs } }; -const struct afb_binding *afbBindingV1Register (const struct afb_binding_interface *itf) +extern "C" { - interface = itf; - - return &binding_desc; -} + static void subscribe(struct afb_req request) + { + subscribe_unsubscribe(request, true); + } -/** - * @brief Initialize the binding. - * - * @param[in] service Structure which represent the Application Framework Binder. - * - * @return Exit code, zero if success. - */ -int afbBindingV1ServiceInit(struct afb_service service) -{ - std::ifstream fd_conf; - fd_conf = afb_daemon_rootdir_open_locale(interface->daemon, "can_bus.json", O_RDONLY, NULL); + static void unsubscribe(struct afb_req request) + { + subscribe_unsubscribe(request, false); + } - /* Open CAN socket */ - can_bus_t can_bus_handler(interface, fd_conf); - if(can_bus_handler.init_can_dev() == 0) + const struct afb_binding *afbBindingV1Register (const struct afb_binding_interface *itf) { - can_bus_handler.start_threads(); - return 0; + interface = itf; + + return &binding_desc; } - return 1; -} + /** + * @brief Initialize the binding. + * + * @param[in] service Structure which represent the Application Framework Binder. + * + * @return Exit code, zero if success. + */ + int afbBindingV1ServiceInit(struct afb_service service) + { + int fd_conf; + fd_conf = afb_daemon_rootdir_open_locale(interface->daemon, "can_bus.json", O_RDONLY, NULL); + + /* Open CAN socket */ + can_bus_t can_bus_handler(interface, fd_conf); + if(can_bus_handler.init_can_dev() == 0) + { + can_bus_handler.start_threads(); + return 0; + } + + return 1; + } +}
\ No newline at end of file diff --git a/src/low-can-binding.hpp b/src/low-can-binding.hpp new file mode 100644 index 0000000..20dc5dc --- /dev/null +++ b/src/low-can-binding.hpp @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2015, 2016 "IoT.bzh" + * Author "Romain Forlot" <romain.forlot@iot.bzh> + * Author "Loic Collignon" <loic.collignon@iot.bzh> + * + * 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-signals.hpp" + +extern "C" +{ + #include <afb/afb-binding.h> + #include <afb/afb-service-itf.h> + + static void subscribe(struct afb_req request); + static void unsubscribe(struct afb_req request); + + /** + * @brief Register the binding. + * + * @desc - A binding V1 MUST have a function of this name and signature. + * This function is called during loading of the binding. It + * receives an 'interface' that should be recorded for later access to + * functions provided by the framework. + * + * This function MUST return the address of a structure that describes + * the binding and its implemented verbs. + * + * In case of initialisation error, NULL must be returned. + * + * @param[in] const struct afb_binding_interface *itf - interface to the application framework binder. + * + * @return pointer to the binding or NULL in case of error + */ + const struct afb_binding *afbBindingV1Register (const struct afb_binding_interface *itf); + + /** + * @brief Initialize the binding. + * + * @param[in] service Structure which represent the Application Framework Binder. + * + * @return Exit code, zero if success. + */ + int afbBindingV1ServiceInit(struct afb_service service); +} + +/* + * Interface between the daemon and the binding + */ +static const struct afb_binding_interface *interface;
\ No newline at end of file diff --git a/src/obd2.cpp b/src/obd2.cpp index 96b6c08..25416cd 100644 --- a/src/obd2.cpp +++ b/src/obd2.cpp @@ -55,7 +55,7 @@ bool obd2_handler_t::is_obd2_request(DiagnosticRequest* request) bool obd2_handler_t::is_obd2_signal(const char *name) { - if(fnmatch("obd2.*", name, NULL) == 0) + if(fnmatch("obd2.*", name, FNM_CASEFOLD) == 0) return true; return false; } diff --git a/src/obd2.hpp b/src/obd2.hpp index b5bd0f8..365c683 100644 --- a/src/obd2.hpp +++ b/src/obd2.hpp @@ -68,6 +68,31 @@ typedef struct _Obd2Pid { struct afb_event event; } Obd2Pid; +/* + * Pre-defined OBD-II PIDs to query for if supported by the vehicle. + */ +const std::vector<Obd2Pid> OBD2_PIDS { + { pid: 0x04, name: "obd2.engine.load", min:0, max: 100, unit: POURCENT, frequency: 5, supported: false, event: {nullptr, nullptr} }, + { pid: 0x05, name: "obd2.engine.coolant.temperature", min: -40, max: 215, unit: DEGREES_CELSIUS, frequency: 1, supported: false, event: {nullptr, nullptr} }, + { pid: 0x0a, name: "obd2.fuel.pressure", min: 0, max: 765, unit: KPA, frequency: 1, supported: false, event: {nullptr, nullptr} }, + { pid: 0x0b, name: "obd2.intake.manifold.pressure", min: 0, max: 255, unit: KPA, frequency: 1, supported: false, event: {nullptr, nullptr} }, + { pid: 0x0c, name: "obd2.engine.speed", min: 0, max: 16383, unit: RPM, frequency: 5, supported: false, event: {nullptr, nullptr} }, + { pid: 0x0d, name: "obd2.vehicle.speed", min: 0, max: 255, unit: KM_H, frequency: 5, supported: false, event: {nullptr, nullptr} }, + { pid: 0x0f, name: "obd2.intake.air.temperature", min: -40, max:215, unit: DEGREES_CELSIUS, frequency: 1, supported: false, event: {nullptr, nullptr} }, + { pid: 0x10, name: "obd2.mass.airflow", min: 0, max: 655, unit: GRAMS_SEC, frequency: 5, supported: false, event: {nullptr, nullptr} }, + { pid: 0x11, name: "obd2.throttle.position", min: 0, max: 100, unit: POURCENT, frequency: 5, supported: false, event: {nullptr, nullptr} }, + { pid: 0x1f, name: "obd2.running.time", min: 0, max: 65535, unit: SECONDS, frequency: 1, supported: false, event: {nullptr, nullptr} }, + { pid: 0x2d, name: "obd2.EGR.error", min: -100, max: 99, unit: POURCENT, frequency: 0, supported: false, event: {nullptr, nullptr} }, + { pid: 0x2f, name: "obd2.fuel.level", min: 0, max: 100, unit: POURCENT, frequency: 1, supported: false, event: {nullptr, nullptr} }, + { pid: 0x33, name: "obd2.barometric.pressure", min: 0, max: 255, unit: KPA, frequency: 1, supported: false, event: {nullptr, nullptr} }, + { pid: 0x4c, name: "obd2.commanded.throttle.position", min: 0, max: 100, unit: POURCENT, frequency: 1, supported: false, event: {nullptr, nullptr} }, + { pid: 0x52, name: "obd2.ethanol.fuel.percentage", min: 0, max: 100, unit: POURCENT, frequency: 1, supported: false, event: {nullptr, nullptr} }, + { pid: 0x5a, name: "obd2.accelerator.pedal.position", min: 0, max: 100, unit: POURCENT, frequency: 5, supported: false, event: {nullptr, nullptr} }, + { pid: 0x5b, name: "obd2.hybrid.battery-pack.remaining.life", min: 0, max: 100, unit: POURCENT, frequency: 5, supported: false, event: {nullptr, nullptr} }, + { pid: 0x5c, name: "obd2.engine.oil.temperature",min: -40, max: 210, unit: DEGREES_CELSIUS, frequency: 1, supported: false, event: {nullptr, nullptr} }, + { pid: 0x63, name: "obd2.engine.torque", min: 0, max: 65535, unit: NM, frequency: 1, supported: false, event: {nullptr, nullptr} } +}; + /* 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. @@ -83,39 +108,14 @@ bool isObd2Request(DiagnosticRequest* request); */ float handleObd2Pid(const DiagnosticResponse* response, float parsedPayload); -/* - * Object to handle obd2 session with pre-scan of supported pid +/** + * @brief - Object to handle obd2 session with pre-scan of supported pid * then request them regularly */ class obd2_handler_t { 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, event: nullptr }, - { pid: 0x05, name: "obd2.engine.coolant.temperature", min: -40, max: 215, unit: DEGREES_CELSIUS, frequency: 1, supported: false, event: nullptr}, - { pid: 0x0a, name: "obd2.fuel.pressure", min: 0, max: 765, unit: KPA, frequency: 1, supported: false, event: nullptr }, - { pid: 0x0b, name: "obd2.intake.manifold.pressure", min: 0, max: 255, unit: KPA, frequency: 1, supported: false, event: nullptr }, - { pid: 0x0c, name: "obd2.engine.speed", min: 0, max: 16383, unit: RPM, frequency: 5, supported: false, event: nullptr }, - { pid: 0x0d, name: "obd2.vehicle.speed", min: 0, max: 255, unit: KM_H, frequency: 5, supported: false, event: nullptr }, - { pid: 0x0f, name: "obd2.intake.air.temperature", min: -40, max:215, unit: DEGREES_CELSIUS, frequency: 1, supported: false, event: nullptr }, - { pid: 0x10, name: "obd2.mass.airflow", min: 0, max: 655, unit: GRAMS_SEC, frequency: 5, supported: false, event: nullptr }, - { pid: 0x11, name: "obd2.throttle.position", min: 0, max: 100, unit: POURCENT, frequency: 5, supported: false, event: nullptr }, - { pid: 0x1f, name: "obd2.running.time", min: 0, max: 65535, unit: SECONDS, frequency: 1, supported: false, event: nullptr }, - { pid: 0x2d, name: "obd2.EGR.error", min: -100, max: 99, unit: POURCENT, frequency: 0, supported: false, event: nullptr }, - { pid: 0x2f, name: "obd2.fuel.level", min: 0, max: 100, unit: POURCENT, frequency: 1, supported: false, event: nullptr }, - { pid: 0x33, name: "obd2.barometric.pressure", min: 0, max: 255, unit: KPA, frequency: 1, supported: false, event: nullptr }, - { pid: 0x4c, name: "obd2.commanded.throttle.position", min: 0, max: 100, unit: POURCENT, frequency: 1, supported: false, event: nullptr }, - { pid: 0x52, name: "obd2.ethanol.fuel.percentage", min: 0, max: 100, unit: POURCENT, frequency: 1, supported: false, event: nullptr }, - { pid: 0x5a, name: "obd2.accelerator.pedal.position", min: 0, max: 100, unit: POURCENT, frequency: 5, supported: false, event: nullptr }, - { pid: 0x5b, name: "obd2.hybrid.battery-pack.remaining.life", min: 0, max: 100, unit: POURCENT, frequency: 5, supported: false, event: nullptr }, - { pid: 0x5c, name: "obd2.engine.oil.temperature",min: -40, max: 210, unit: DEGREES_CELSIUS, frequency: 1, supported: false, event: nullptr }, - { pid: 0x63, name: "obd2.engine.torque", min: 0, max: 65535, unit: NM, frequency: 1, supported: false, event: nullptr } - }; - /** * @brief: * diff --git a/src/openxc-utils.cpp b/src/openxc-utils.cpp new file mode 100644 index 0000000..b53a5eb --- /dev/null +++ b/src/openxc-utils.cpp @@ -0,0 +1,127 @@ +/* + * Copyright (C) 2015, 2016 "IoT.bzh" + * Author "Romain Forlot" <romain.forlot@iot.bzh> + * Author "Loic Collignon" <loic.collignon@iot.bzh> + * + * 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. + */ + +openxc_VehicleMessage build_VehicleMessage_with_SimpleMessage(openxc_DynamicField_Type type, + 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; + + 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; + } + + v.has_type = true, + v.type = openxc_VehicleMessage_Type::openxc_VehicleMessage_Type_SIMPLE; + v.has_simple_message = true; + v.simple_message = message; + + return v; +} + +openxc_SimpleMessage build_SimpleMessage(const std::string& name, const openxc_DynamicField& 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; +} + +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; +} + +openxc_DynamicField build_DynamicField(double value) +{ + openxc_DynamicField d = {0} + d.has_type = true; + d.type = openxc_DynamicField_Type_NUM; + + d.has_numeric_value = true; + d.numeric_value = field; + + return d; +} + +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; +} + +void jsonify_DynamicField(const openxc_DynamicField& field, const json_object& value) +{ + if(field.has_numeric_value) + json_object_object_add(value, "value", json_object_new_double(field.numeric_value)); + else if(field.has_boolean_value) + json_object_object_add(value, "value", json_object_new_boolean(field.boolean_value)); + else if(field.has_string_value) + json_object_object_add(value, "value", json_object_new_string(field.string_value)); + + return value; +} + +openxc_SimpleMessage get_simple_message(const openxc_VehicleMessage& v_msg) +{ + return v_msg.has_simple_message ? v_msg.simple_message : {0}; +} + +json_object jsonify_simple(const openxc_SimpleMessage& s_msg) +{ + json_object *json; + json = nullptr; + + if(s_msg->has_name) + { + json = json_object_new_object(); + json_object_object_add(json, "name", json_object_new_string(s_msg->name)); + jsonify_DynamicField(&s_msg->value, json); + } + return json; +}
\ No newline at end of file diff --git a/src/openxc-utils.hpp b/src/openxc-utils.hpp new file mode 100644 index 0000000..f078c6e --- /dev/null +++ b/src/openxc-utils.hpp @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2015, 2016 "IoT.bzh" + * Author "Romain Forlot" <romain.forlot@iot.bzh> + * Author "Loic Collignon" <loic.collignon@iot.bzh> + * + * 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 + +/* + * Build a specific VehicleMessage containing a SimpleMessage. + */ +openxc_VehicleMessage build_VehicleMessage_with_SimpleMessage(openxc_DynamicField_Type type, + const openxc_SimpleMessage& message); + +/* + * Build an openxc_SimpleMessage associating a name to an openxc_DynamicField + */ +openxc_SimpleMessage build_SimpleMessage(const std::string& name, const openxc_DynamicField& value); +/* + * Build an openxc_DynamicField depending what we pass as argument + */ +openxc_DynamicField build_DynamicField(const std::string& value); + +/* + * Build an openxc_DynamicField depending what we pass as argument + */ +openxc_DynamicField build_DynamicField(double value); + +/* + * Build an openxc_DynamicField depending what we pass as argument + */ +openxc_DynamicField build_DynamicField(bool value); + +void jsonify_DynamicField(const openxc_DynamicField& field, const json_object& value); + +/* Extract the simple message value from an openxc_VehicleMessage + * and return it, or null if there isn't. + */ +openxc_SimpleMessage get_simple_message(const openxc_VehicleMessage& v_msg); + +json_object jsonify_simple(const openxc_SimpleMessage& s_msg);
\ No newline at end of file |