From c2a2b12c1ec1a4e17a3c95ceb8f010ce961a909e Mon Sep 17 00:00:00 2001 From: Romain Forlot Date: Tue, 14 Feb 2017 14:32:55 +0100 Subject: Move sources into src directory make some cleaning Signed-off-by: Romain Forlot --- .gitmodules | 16 +- CMakeLists.txt | 92 ---------- can-decoder.cpp | 93 ---------- can-decoder.h | 146 --------------- can-signals.cpp | 40 ----- can-signals.h | 84 --------- can-utils.cpp | 226 ----------------------- can-utils.h | 396 ----------------------------------------- can_decoder.cpp | 40 ----- can_event_push.cpp | 38 ---- can_reader.cpp | 66 ------- config.xml.in | 11 -- export.map | 1 - icon.png | Bin 4035 -> 0 bytes libs/bitfield-c | 1 - libs/nanopb | 1 - libs/openxc-message-format | 1 - libs/uds-c | 1 - low-can-binding.cpp | 253 -------------------------- obd2.cpp | 59 ------ obd2.h | 150 ---------------- src/CMakeLists.txt | 92 ++++++++++ src/can-decoder.cpp | 93 ++++++++++ src/can-decoder.h | 146 +++++++++++++++ src/can-signals.cpp | 40 +++++ src/can-signals.h | 84 +++++++++ src/can-utils.cpp | 226 +++++++++++++++++++++++ src/can-utils.h | 396 +++++++++++++++++++++++++++++++++++++++++ src/can_decode_message.cpp | 40 +++++ src/can_event_push.cpp | 38 ++++ src/can_reader.cpp | 66 +++++++ src/config.xml.in | 11 ++ src/export.map | 1 + src/icon.png | Bin 0 -> 4035 bytes src/libs/bitfield-c | 1 + src/libs/nanopb | 1 + src/libs/openxc-message-format | 1 + src/libs/uds-c | 1 + src/low-can-binding.cpp | 253 ++++++++++++++++++++++++++ src/obd2.cpp | 59 ++++++ src/obd2.h | 150 ++++++++++++++++ src/timer.h | 33 ++++ timer.h | 33 ---- 43 files changed, 1740 insertions(+), 1740 deletions(-) delete mode 100644 CMakeLists.txt delete mode 100644 can-decoder.cpp delete mode 100644 can-decoder.h delete mode 100644 can-signals.cpp delete mode 100644 can-signals.h delete mode 100644 can-utils.cpp delete mode 100644 can-utils.h delete mode 100644 can_decoder.cpp delete mode 100644 can_event_push.cpp delete mode 100644 can_reader.cpp delete mode 100644 config.xml.in delete mode 100644 export.map delete mode 100644 icon.png delete mode 160000 libs/bitfield-c delete mode 160000 libs/nanopb delete mode 160000 libs/openxc-message-format delete mode 160000 libs/uds-c delete mode 100644 low-can-binding.cpp delete mode 100644 obd2.cpp delete mode 100644 obd2.h create mode 100644 src/CMakeLists.txt create mode 100644 src/can-decoder.cpp create mode 100644 src/can-decoder.h create mode 100644 src/can-signals.cpp create mode 100644 src/can-signals.h create mode 100644 src/can-utils.cpp create mode 100644 src/can-utils.h create mode 100644 src/can_decode_message.cpp create mode 100644 src/can_event_push.cpp create mode 100644 src/can_reader.cpp create mode 100644 src/config.xml.in create mode 100644 src/export.map create mode 100644 src/icon.png create mode 160000 src/libs/bitfield-c create mode 160000 src/libs/nanopb create mode 160000 src/libs/openxc-message-format create mode 160000 src/libs/uds-c create mode 100644 src/low-can-binding.cpp create mode 100644 src/obd2.cpp create mode 100644 src/obd2.h create mode 100644 src/timer.h delete mode 100644 timer.h diff --git a/.gitmodules b/.gitmodules index 2faeffad..6b8fd5aa 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,12 +1,12 @@ -[submodule "libs/openxc-message-format"] - path = libs/openxc-message-format +[submodule "src/libs/openxc-message-format"] + path = src/libs/openxc-message-format url = git@github.com:openxc/openxc-message-format.git -[submodule "libs/nanopb"] - path = libs/nanopb +[submodule "src/libs/nanopb"] + path = src/libs/nanopb url = git@github.com:nanopb/nanopb.git -[submodule "libs/uds-c"] - path = libs/uds-c +[submodule "src/libs/uds-c"] + path = src/libs/uds-c url = git@github.com:openxc/uds-c.git -[submodule "libs/bitfield-c"] - path = libs/bitfield-c +[submodule "src/libs/bitfield-c"] + path = src/libs/bitfield-c url = git@github.com:openxc/bitfield-c.git diff --git a/CMakeLists.txt b/CMakeLists.txt deleted file mode 100644 index 768d6b47..00000000 --- a/CMakeLists.txt +++ /dev/null @@ -1,92 +0,0 @@ -########################################################################### -# Copyright 2016 IoT.bzh -# -# author: José Bollo -# author: Stéphane Desneux -# -# 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. -########################################################################### - -project(ll-can) - -cmake_minimum_required(VERSION 3.3) - -include(GNUInstallDirs) - -set(PROJECT_VERSION "0.1") -set(PROJECT_ICON "icon.png") -set(PROJECT_LIBDIR "libs") - -set(CMAKE_BUILD_TYPE Debug) - -########################################################################### - -link_libraries(-Wl,--as-needed -Wl,--gc-sections) - -add_compile_options(-Wall -Wextra -Wconversion) -add_compile_options(-Wno-unused-parameter) # frankly not using a parameter does it care? -add_compile_options(-Werror=maybe-uninitialized) -add_compile_options(-Werror=implicit-function-declaration) -add_compile_options(-ffunction-sections -fdata-sections) -add_compile_options(-Wl,--as-needed -Wl,--gc-sections) -add_compile_options(-fPIC) - -set(CMAKE_C_FLAGS_PROFILING "-g -O0 -pg -Wp,-U_FORTIFY_SOURCE") -set(CMAKE_C_FLAGS_DEBUG "-g -O0 -ggdb -Wp,-U_FORTIFY_SOURCE") -set(CMAKE_C_FLAGS_RELEASE "-g -O2") -set(CMAKE_C_FLAGS_CCOV "-g -O2 --coverage") - -set(CMAKE_CXX_FLAGS_PROFILING "-g -O0 -pg -Wp,-U_FORTIFY_SOURCE") -set(CMAKE_CXX_FLAGS_DEBUG "-g -O0 -ggdb -Wp,-U_FORTIFY_SOURCE") -set(CMAKE_CXX_FLAGS_RELEASE "-g -O2") -set(CMAKE_CXX_FLAGS_CCOV "-g -O2 --coverage") - -########################################################################### - -include(FindPkgConfig) - -pkg_check_modules(EXTRAS REQUIRED json-c afb-daemon) -add_compile_options(${EXTRAS_CFLAGS}) -include_directories(${EXTRAS_INCLUDE_DIRS} ${PROJECT_LIBDIR}/openxc-message-format/gen/cpp ${PROJECT_LIBDIR}/nanopb/) -link_libraries(${EXTRAS_LIBRARIES}) - -########################################################################### -# the binding for afb - -message(STATUS "Creation of ${PROJECT_NAME} binding for AFB-DAEMON") -########################################################################### -add_library(${PROJECT_NAME}-binding MODULE ${PROJECT_NAME}-binding.c) - -set_target_properties(${PROJECT_NAME}-binding PROPERTIES - PREFIX "" - LINK_FLAGS "-Wl,--version-script=${CMAKE_CURRENT_SOURCE_DIR}/export.map" -) - -########################################################################### -# WGT packaging - -message(STATUS "Creation of ${PROJECT_NAME}.wgt package for AppFW") -############################################################### -configure_file(config.xml.in config.xml) - -add_custom_command( - OUTPUT ${PROJECT_NAME}.wgt - DEPENDS ${PROJECT_NAME}-binding - COMMAND rm -rf package - COMMAND mkdir -p package/${PROJECT_LIBDIR} package/htdocs - COMMAND cp config.xml package/ - COMMAND cp ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_ICON} package/icon.png - COMMAND cp ${PROJECT_NAME}-binding.so package - COMMAND wgtpkg-pack -f -o ${PROJECT_NAME}.wgt package -) -add_custom_target(widget ALL DEPENDS ${PROJECT_NAME}.wgt) diff --git a/can-decoder.cpp b/can-decoder.cpp deleted file mode 100644 index 000db2ac..00000000 --- a/can-decoder.cpp +++ /dev/null @@ -1,93 +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. - */ - -Decoder::Decoder -{ - 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) -{ - 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) -{ - decoded_value = { .has_type = true, - .type = openxc_DynamicField_Type_NUM, - .has_numeric_value = true, - .numeric_value = value }; - return decoded_value; -} - -openxc_DynamicField Decoder::booleanDecoder(CanSignal* signal, - CanSignal* signals, int signalCount, float value, bool* send) -{ - decoded_value = { .has_type = true, - .type = openxc_DynamicField_Type_BOOL, - .has_boolean_value = true, - .numeric_value = value == 0.0 ? false : true }; - return decoded_value; -} - -openxc_DynamicField Decoder::ignoreDecoder(CanSignal* signal, - CanSignal* signals, int signalCount, float value, bool* 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 decoded_value = {0}; - decoded_value.has_type = true; - decoded_value.type = openxc_DynamicField_Type_STRING; - decoded_value.has_string_value = true; - - const CanSignalState* signalState = lookupSignalState(value, signal); - if(signalState != NULL) { - 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) -{ - SignalDecoder decoder = signal->decoder == NULL ? - noopDecoder : signal->decoder; - openxc_DynamicField decoded_value = decoder(signal, signals, - signalCount, value, send); - return decoded_value; -} - -openxc_DynamicField Decoder::decodeSignal(CanSignal* signal, - const CanMessage* message, CanSignal* signals, int signalCount, - bool* send) { - float value = parseSignalBitfield(signal, message); - return decodeSignal(signal, value, signals, signalCount, send); -} \ No newline at end of file diff --git a/can-decoder.h b/can-decoder.h deleted file mode 100644 index 249d5b00..00000000 --- a/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_c -{ - 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/can-signals.cpp b/can-signals.cpp deleted file mode 100644 index 13ff30b1..00000000 --- a/can-signals.cpp +++ /dev/null @@ -1,40 +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. - */ - -#include -#include "can-signals.h" - -bool match(const std::string &first, const std::string &second) -{ - -} - -CanSignal* getSignals(std::string name) -{ - int n_signals, i; - CanSignal ret_signals[]; - - n_signals = size(SIGNALS); - - for(i=0; i<=n_signals; i++) - { - if(SIGNALS[i].generic_name == name) - return &SIGNALS[i]; - i++; - } - return 0; -} diff --git a/can-signals.h b/can-signals.h deleted file mode 100644 index f34c743e..00000000 --- a/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/can-utils.cpp b/can-utils.cpp deleted file mode 100644 index 67214105..00000000 --- a/can-utils.cpp +++ /dev/null @@ -1,226 +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 - -/******************************************************************************** -* -* CanBus method implementation -* -*********************************************************************************/ - -CanBus_c::CanBus_c(afb_binding_interface *itf, const std:string& dev_name) -{ - interface = itf; - deviceName = dev_name; -} - -int CanBus_c::open() -{ - const int canfd_on = 1; - struct ifreq ifr; - struct timeval timeout = {1, 0}; - - DEBUG(interface, "open_can_dev: CAN Handler socket : %d", socket); - if (socket >= 0) - close(socket); - - socket = socket(PF_CAN, SOCK_RAW, CAN_RAW); - if (socket < 0) - { - ERROR(interface, "open_can_dev: socket could not be created"); - } - else - { - /* Set timeout for read */ - setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(timeout)); - /* try to switch the socket into CAN_FD mode */ - if (setsockopt(socket, SOL_CAN_RAW, CAN_RAW_FD_FRAMES, &canfd_on, sizeof(canfd_on)) < 0) - { - NOTICE(interface, "open_can_dev: Can not switch into CAN Extended frame format."); - is_fdmode_on = false; - } else { - is_fdmode_on = true; - } - - /* Attempts to open a socket to CAN bus */ - strcpy(ifr.ifr_name, device); - if(ioctl(socket, SIOCGIFINDEX, &ifr) < 0) - ERROR(interface, "open_can_dev: ioctl failed"); - else - { - txAddress.can_family = AF_CAN; - txAddress.can_ifindex = ifr.ifr_ifindex; - - /* And bind it to txAddress */ - if (bind(socket, (struct sockaddr *)&txAddress, sizeof(txAddress)) < 0) - { - ERROR(interface, "open_can_dev: bind failed"); - } - else - { - fcntl(socket, F_SETFL, O_NONBLOCK); - return 0; - } - } - close(socket); - socket = -1; - } - return -1; -} - -int CanBus_c::close() -{ - close(socket); - socket = -1; -} - -void CanBus_c::start_threads() -{ - std::queue can_message_q; - - th_reading = std::thread(can_reader, interface, socket, can_message_q); - th_decoding = std::thread(can_decoder, interface, can_message_q, can_message_q); - th_pushing = std::thread(can_event_push, interface, can_message_q); -} - -/* - * Send a can message from a CanMessage_c object. - */ -int CanBus_c::send_can_message(CanMessage_c can_msg) -{ - int nbytes; - canfd_frame *f; - - f = can_msg.convert_to_canfd_frame(); - - if(socket >= 0) - { - nbytes = sendto(socket, &f, sizeof(struct canfd_frame), 0, - (struct sockaddr*)&txAddress, sizeof(txAddress)); - - if (nbytes == -1) - { - ERROR(interface, "send_can_message: Sending CAN frame failed."); - return -1; - } - return nbytes; - } - else - { - ERROR(interface, "send_can_message: socket not initialized. Attempt to reopen can device socket."); - open_can_dev(); - } - return 0; -} - -/******************************************************************************** -* -* CanMessage method implementation -* -*********************************************************************************/ - -uint32_t CanMessage_c::get_id() -{ - return id; -} - -int CanMessage_c::get_format() -{ - return format; -} - -uint8_t CanMessage_c::get_data() -{ - return data; -} -uint8_t CanMessage_c::get_lenght() -{ - return lenght; -} - -void CanMessage_c::set_id(uint32_t new_id) -{ - switch(format): - case CanMessageFormat::SIMPLE: - id = new_id & CAN_SFF_MASK; - case CanMessageFormat::EXTENDED: - id = new_id & CAN_EFF_MASK; - default: - ERROR(interface, "ERROR: Can set id, not a compatible format or format not set prior to set id."); -} - -void CanMessage_c::set_format(CanMessageFormat new_format) -{ - if(new_format == CanMessageFormat::SIMPLE || new_format == CanMessageFormat::EXTENDED) - format = new_format; - else - ERROR(interface, "ERROR: Can set format, wrong format chosen"); -} - -void CanMessage_c::set_data(uint8_t new_data) -{ - data = new_data; -} - -void CanMessage_c::set_lenght(uint8_t new_length) -{ - lenght = new_lenght; -} - -/* - * This is the preferred way to initialize a CanMessage object - * from a read canfd_frame message. - * - * params: canfd_frame pointer - */ -void CanMessage_c::convert_from_canfd_frame(canfd_frame *frame) -{ - - lenght = (canfd_frame->len > maxdlen) ? maxdlen : canfd_frame->len; - - switch (canfd_frame->can_id): - case (canfd_frame->can_id & CAN_ERR_FLAG): - id = canfd_frame->can_id & (CAN_ERR_MASK|CAN_ERR_FLAG); - break; - case (canfd_frame->can_id & CAN_EFF_FLAG): - id = canfd_frame->can_id & CAN_EFF_MASK; - format = CanMessageFormat::EXTENDED; - break; - default: - format = CanMessageFormat::STANDARD; - id = canfd_frame->can_id & CAN_SFF_MASK; - break; - - if (sizeof(canfd_frame->data) <= sizeof(data)) - { - memcpy(data, canfd_frame->data, lenght); - return 0; - } else if (sizeof(canfd_frame->data) >= CAN_MAX_DLEN) - ERROR(interface, "CanMessage_c: canfd_frame data too long to be stored into CanMessage object"); -} - -canfd_frame* convert_to_canfd_frame() -{ - canfd_frame frame; - - frame.id = can_msg.get_id(); - frame.len = can_msg.get_lenght(); - frame.data = can_msg.get_data(); - - return &frame; -} diff --git a/can-utils.h b/can-utils.h deleted file mode 100644 index 8c850e6e..00000000 --- a/can-utils.h +++ /dev/null @@ -1,396 +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 CanBus_c { - private: - afb_binding_interface *interface; - - /* Got from conf file */ - std::string deviceName; - - int socket; - bool is_fdmode_on; - struct sockaddr_can txAddress; - - std::thread th_reading; - std::thread th_decoding; - std::thread th_pushing; - std::queue can_message_q; - std::queue VehicleMessage_q; - - public: - int open(); - int close(); - - void start_threads(); - int send_can_message(CanMessage_c can_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 CanMessage_c { - private: - uint32_t id; - CanMessageFormat format; - uint8_t data[CAN_MESSAGE_SIZE]; - uint8_t length; - - public: - uint32_t get_id(); - int get_format(); - uint8_t get_data(); - uint8_t get_lenght(); - - 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(CanMessage_c, 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; - */ - class CanSignalState_c { - private: - const int value; - const char *name; -}; - -/* 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; - - struct afb_event event; -}; -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; - */ -class CanMessageSet_c { - private: - uint8_t index; - const char * name; - uint8_t busCount; - unsigned short messageCount; - unsigned short signalCount; - unsigned short commandCount; -}; - -/* 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/can_decoder.cpp b/can_decoder.cpp deleted file mode 100644 index 5de6eda9..00000000 --- a/can_decoder.cpp +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (C) 2015, 2016 "IoT.bzh" - * Author "Romain Forlot" - * Author "Loic Collignon" - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include -#include - -#include - -#include "can-utils.h" -#include "openxc.pb.h" - -void decode_can_message(CanBus_c *can_bus) -{ - CanMessage_c can_message; - - while(true) - { - if(! can_bus->can_message_q.empty()) - { - can_message = can_bus->can_message_q.front(); - can_bus->can_message_q.pop(); - } - } -} diff --git a/can_event_push.cpp b/can_event_push.cpp deleted file mode 100644 index b08619b8..00000000 --- a/can_event_push.cpp +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (C) 2015, 2016 "IoT.bzh" - * Author "Romain Forlot" - * Author "Loic Collignon" - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include -#include - -#include - -#include "can-utils.h" -#include "openxc.pb.h" - -void can_event_push(CanBus_c *can_bus) -{ - while(true) - { - if(! can_bus->vehicle_message_q.empty()) - { - vehicle_message = can_bus->vehicle_message_q.front(); - can_bus->vehicle_message_q.pop(); - } - } -} diff --git a/can_reader.cpp b/can_reader.cpp deleted file mode 100644 index d9b3e671..00000000 --- a/can_reader.cpp +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (C) 2015, 2016 "IoT.bzh" - * Author "Romain Forlot" - * Author "Loic Collignon" - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include - -#include - -#include "can-utils.h" - -void can_reader(CanBus_c *can_bus)) -{ - ssize_t nbytes; - int maxdlen; - CanMessage_c can_message; - canfd_frame canfd_frame; - - /* Test that socket is really opened */ - if ( can_bus->socket < 0) - { - ERROR(interface, "read_can: Socket unavailable"); - return -1; - } - - while(true) - { - nbytes = read(can_bus->socket, &canfd_frame, CANFD_MTU); - - switch(nbytes) - { - case CANFD_MTU: - DEBUG(interface, "read_can: Got an CAN FD frame with length %d", canfd_frame.len); - maxdlen = CANFD_MAX_DLEN; - break; - case CAN_MTU: - DEBUG(interface, "read_can: Got a legacy CAN frame with length %d", canfd_frame.len); - maxdlen = CAN_MAX_DLEN; - break; - default: - if (errno == ENETDOWN) - ERROR(interface, "read_can: %s interface down", device); - - ERROR(interface, "read_can: Error reading CAN bus"); - return -2; - } - - can_message.convert_from_canfd_frame(canfd_frame); - - can_message_q.push(can_message); - } -} diff --git a/config.xml.in b/config.xml.in deleted file mode 100644 index 33a8ff85..00000000 --- a/config.xml.in +++ /dev/null @@ -1,11 +0,0 @@ - - - @PROJECT_NAME@ - - - This is a demo application used to control and dialog with HVAC system - Romain Forlot <romain.forlot@iot.bzh> - APL 2.0 - - - diff --git a/export.map b/export.map deleted file mode 100644 index 52c1b4aa..00000000 --- a/export.map +++ /dev/null @@ -1 +0,0 @@ -{ global: afbBindingV1*; local: *; }; diff --git a/icon.png b/icon.png deleted file mode 100644 index 9bd6a6e4..00000000 Binary files a/icon.png and /dev/null differ diff --git a/libs/bitfield-c b/libs/bitfield-c deleted file mode 160000 index a34745ec..00000000 --- a/libs/bitfield-c +++ /dev/null @@ -1 +0,0 @@ -Subproject commit a34745ec93ae0a1d4f1b640dba8fb6702331a8e9 diff --git a/libs/nanopb b/libs/nanopb deleted file mode 160000 index ffe4aff8..00000000 --- a/libs/nanopb +++ /dev/null @@ -1 +0,0 @@ -Subproject commit ffe4aff87cc3a15863c09aa808adf2381c8f2fb7 diff --git a/libs/openxc-message-format b/libs/openxc-message-format deleted file mode 160000 index d9f54f97..00000000 --- a/libs/openxc-message-format +++ /dev/null @@ -1 +0,0 @@ -Subproject commit d9f54f97578429773421abce98d5f6579717afcc diff --git a/libs/uds-c b/libs/uds-c deleted file mode 160000 index e506334e..00000000 --- a/libs/uds-c +++ /dev/null @@ -1 +0,0 @@ -Subproject commit e506334e270d77b20c0bc259ac6c7d8c9b702b7a diff --git a/low-can-binding.cpp b/low-can-binding.cpp deleted file mode 100644 index b6098907..00000000 --- a/low-can-binding.cpp +++ /dev/null @@ -1,253 +0,0 @@ -/* - * Copyright (C) 2015, 2016 "IoT.bzh" - * Author "Romain Forlot" - * Author "Loic Collignon" - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include - -#include "ll-can-binding.h" -#include "obd2.h" - -/* - * Interface between the daemon and the binding - */ -static const struct afb_binding_interface *interface; - -/******************************************************************************** -* -* Event management -* -*********************************************************************************/ - -/* - * TBF TBF TBF - * called on an event on the CAN bus - */ -static int on_event(sd_event_source *s, int fd, uint32_t revents, void *userdata) -{ - openxc_CanMessage can_message; - - can_message = openxc_CanMessage_init_default; - - /* read available data */ - if ((revents & EPOLLIN) != 0) - { - read_can(&can_message); - send_event(); - } - - /* check if error or hangup */ - if ((revents & (EPOLLERR|EPOLLRDHUP|EPOLLHUP)) != 0) - { - sd_event_source_unref(s); - close(fd); - connect_to_event_loop(); - } - - return 0; -} - -/* - * USELESS SINCE THREADS SEPARATION - * - * Get the event loop running. - * Will trigger on_event function on EPOLLIN event on socket - * - * Return 0 or positive value on success. Else negative value for failure. -static int connect_to_event_loop(CanBus &CanBus_handler) -{ - sd_event *event_loop; - sd_event_source *source; - int rc; - - if (CanBus_handler.socket < 0) - { - return CanBus_handler.socket; - } - - event_loop = afb_daemon_get_event_loop(interface->daemon); - rc = sd_event_add_io(event_loop, &source, CanBus_handler.socket, EPOLLIN, on_event, NULL); - if (rc < 0) - { - CanBus_handler.close(); - ERROR(interface, "Can't connect CAN bus %s to the event loop", CanBus_handler.device); - } else - { - NOTICE(interface, "Connected CAN bus %s to the event loop", CanBus_handler.device); - } - - return rc; -} - */ - -/******************************************************************************** -* -* Subscription and unsubscription -* -*********************************************************************************/ - -static int subscribe_unsubscribe_sig(struct afb_req request, int subscribe, struct signal *sig) -{ - if (!afb_event_is_valid(sig->event)) { - if (!subscribe) - return 1; - sig->event = afb_daemon_make_event(afbitf->daemon, sig->name); - if (!afb_event_is_valid(sig->event)) { - return 0; - } - } - - if (((subscribe ? afb_req_subscribe : afb_req_unsubscribe)(request, sig->event)) < 0) { - return 0; - } - - return 1; -} - -static int subscribe_unsubscribe_all(struct afb_req request, int subscribe) -{ - int i, n, e; - - n = sizeof OBD2_PIDS / sizeof * OBD2_PIDS; - e = 0; - for (i = 0 ; i < n ; i++) - e += !subscribe_unsubscribe_sig(request, subscribe, &OBD2_PIDS[i]); - return e == 0; -} - -static int subscribe_unsubscribe_name(struct afb_req request, int subscribe, const char *name) -{ - struct signal *sig; - - if (0 == strcmp(name, "*")) - return subscribe_unsubscribe_all(request, subscribe); - - sig = getSignal(name); - if (sig == NULL) { - return 0; - } - - return subscribe_unsubscribe_sig(request, subscribe, sig); -} - -static void subscribe_unsubscribe(struct afb_req request, int subscribe) -{ - int ok, i, n; - struct json_object *args, *a, *x; - - /* makes the subscription/unsubscription */ - args = afb_req_json(request); - if (args == NULL || !json_object_object_get_ex(args, "event", &a)) { - ok = subscribe_unsubscribe_all(request, subscribe); - } else if (json_object_get_type(a) != json_type_array) { - ok = subscribe_unsubscribe_name(request, subscribe, json_object_get_string(a)); - } else { - n = json_object_array_length(a); - ok = 0; - for (i = 0 ; i < n ; i++) { - x = json_object_array_get_idx(a, i); - if (subscribe_unsubscribe_name(request, subscribe, json_object_get_string(x))) - ok++; - } - ok = (ok == n); - } - - /* send the report */ - if (ok) - afb_req_success(request, NULL, NULL); - else - afb_req_fail(request, "error", NULL); -} - -static void subscribe(struct afb_req request) -{ - subscribe_unsubscribe(request, 1); -} - -static void unsubscribe(struct afb_req request) -{ - subscribe_unsubscribe(request, 0); -} -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." }, - {NULL} -}; - -static const struct afb_binding binding_desc = { - .type = AFB_BINDING_VERSION_1, - .v1 = { - .info = "CAN bus service", - .prefix = "can", - .verbs = verbs - } -}; - -const struct afb_binding *afbBindingV1Register (const struct afb_binding_interface *itf) -{ - interface = itf; - - return &binding_desc; -} - -int afbBindingV1ServiceInit(struct afb_service service) -{ - std::ifstream fd_conf; - std::string fd_conf_content; - json_object jo_canbus; - - /* Open JSON conf file */ - jo_canbus = json_object_new_object(); - fd_conf = afb_daemon_rootdir_open_locale(interface->daemon, "canbus.json", O_RDONLY, NULL); - if (fd_conf) - { - fd_conf.seekg(0, std::ios::end); - fd_conf_content.resize(fd_conf.tellg()); - fd_conf.seekg(0, std::ios::beg); - fd_conf.read(&fd_conf_content[0], fd_conf_content.size()); - fd_conf.close(); - } - - jo_canbus = json_tokener_parse(&fd_conf_content); - - /* Open CAN socket */ - CanBus_c CanBus_handler(interface, json_object_get_string(json_object_object_get(jo_canbus, "deviceName")); - CanBus_handler.open(); - CanBus_handler.start_threads(); -} diff --git a/obd2.cpp b/obd2.cpp deleted file mode 100644 index 7db5d97d..00000000 --- a/obd2.cpp +++ /dev/null @@ -1,59 +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. - */ - - -void shims_logger(afb_binding_interface *itf) -{ - //DEBUG(itf, "dd"); -} - -void shims_timer() -{ -} - -/* - * Will scan for supported Obd2 pids - */ -Obd2Handler::Obd2Handler(afb_binding_interface *itf, CanBus_c cb) -{ - CanBus_c can_bus = cb; - DiagnosticShims shims = diagnostic_init_shims(shims_logger, can_bus.send_can_message, NULL); - - int n_pids, i; - - n_pids = size(Obd2Pid); - for(i=0; i<=n_pids; i++) - { - } -} - -Obd2Handler::add_request(int pid) -{ - DiagnosticRequest request = { - arbitration_id: OBD2_FUNCTIONAL_BROADCAST_ID, - mode: 0x1, has_pid: true, pid: pid}; -} - -Obd2Handler::is_obd2_request(DiagnosticRequest* request) -{ - return request->mode == 0x1 && request->has_pid && request->pid < 0xff; -} - -Obd2Handler::decode_obd2_response(DiagnosticResponse* responce) -{ - return diagnostic_decode_obd2_pid(response); -} diff --git a/obd2.h b/obd2.h deleted file mode 100644 index 862c04a2..00000000 --- a/obd2.h +++ /dev/null @@ -1,150 +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 Obd2Handler_c { - private: - /* - * 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: - Obd2Handler_c(); - - bool isObd2Request(request); -} diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt new file mode 100644 index 00000000..768d6b47 --- /dev/null +++ b/src/CMakeLists.txt @@ -0,0 +1,92 @@ +########################################################################### +# Copyright 2016 IoT.bzh +# +# author: José Bollo +# author: Stéphane Desneux +# +# 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. +########################################################################### + +project(ll-can) + +cmake_minimum_required(VERSION 3.3) + +include(GNUInstallDirs) + +set(PROJECT_VERSION "0.1") +set(PROJECT_ICON "icon.png") +set(PROJECT_LIBDIR "libs") + +set(CMAKE_BUILD_TYPE Debug) + +########################################################################### + +link_libraries(-Wl,--as-needed -Wl,--gc-sections) + +add_compile_options(-Wall -Wextra -Wconversion) +add_compile_options(-Wno-unused-parameter) # frankly not using a parameter does it care? +add_compile_options(-Werror=maybe-uninitialized) +add_compile_options(-Werror=implicit-function-declaration) +add_compile_options(-ffunction-sections -fdata-sections) +add_compile_options(-Wl,--as-needed -Wl,--gc-sections) +add_compile_options(-fPIC) + +set(CMAKE_C_FLAGS_PROFILING "-g -O0 -pg -Wp,-U_FORTIFY_SOURCE") +set(CMAKE_C_FLAGS_DEBUG "-g -O0 -ggdb -Wp,-U_FORTIFY_SOURCE") +set(CMAKE_C_FLAGS_RELEASE "-g -O2") +set(CMAKE_C_FLAGS_CCOV "-g -O2 --coverage") + +set(CMAKE_CXX_FLAGS_PROFILING "-g -O0 -pg -Wp,-U_FORTIFY_SOURCE") +set(CMAKE_CXX_FLAGS_DEBUG "-g -O0 -ggdb -Wp,-U_FORTIFY_SOURCE") +set(CMAKE_CXX_FLAGS_RELEASE "-g -O2") +set(CMAKE_CXX_FLAGS_CCOV "-g -O2 --coverage") + +########################################################################### + +include(FindPkgConfig) + +pkg_check_modules(EXTRAS REQUIRED json-c afb-daemon) +add_compile_options(${EXTRAS_CFLAGS}) +include_directories(${EXTRAS_INCLUDE_DIRS} ${PROJECT_LIBDIR}/openxc-message-format/gen/cpp ${PROJECT_LIBDIR}/nanopb/) +link_libraries(${EXTRAS_LIBRARIES}) + +########################################################################### +# the binding for afb + +message(STATUS "Creation of ${PROJECT_NAME} binding for AFB-DAEMON") +########################################################################### +add_library(${PROJECT_NAME}-binding MODULE ${PROJECT_NAME}-binding.c) + +set_target_properties(${PROJECT_NAME}-binding PROPERTIES + PREFIX "" + LINK_FLAGS "-Wl,--version-script=${CMAKE_CURRENT_SOURCE_DIR}/export.map" +) + +########################################################################### +# WGT packaging + +message(STATUS "Creation of ${PROJECT_NAME}.wgt package for AppFW") +############################################################### +configure_file(config.xml.in config.xml) + +add_custom_command( + OUTPUT ${PROJECT_NAME}.wgt + DEPENDS ${PROJECT_NAME}-binding + COMMAND rm -rf package + COMMAND mkdir -p package/${PROJECT_LIBDIR} package/htdocs + COMMAND cp config.xml package/ + COMMAND cp ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_ICON} package/icon.png + COMMAND cp ${PROJECT_NAME}-binding.so package + COMMAND wgtpkg-pack -f -o ${PROJECT_NAME}.wgt package +) +add_custom_target(widget ALL DEPENDS ${PROJECT_NAME}.wgt) diff --git a/src/can-decoder.cpp b/src/can-decoder.cpp new file mode 100644 index 00000000..000db2ac --- /dev/null +++ b/src/can-decoder.cpp @@ -0,0 +1,93 @@ +/* + * 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. + */ + +Decoder::Decoder +{ + 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) +{ + 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) +{ + decoded_value = { .has_type = true, + .type = openxc_DynamicField_Type_NUM, + .has_numeric_value = true, + .numeric_value = value }; + return decoded_value; +} + +openxc_DynamicField Decoder::booleanDecoder(CanSignal* signal, + CanSignal* signals, int signalCount, float value, bool* send) +{ + decoded_value = { .has_type = true, + .type = openxc_DynamicField_Type_BOOL, + .has_boolean_value = true, + .numeric_value = value == 0.0 ? false : true }; + return decoded_value; +} + +openxc_DynamicField Decoder::ignoreDecoder(CanSignal* signal, + CanSignal* signals, int signalCount, float value, bool* 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 decoded_value = {0}; + decoded_value.has_type = true; + decoded_value.type = openxc_DynamicField_Type_STRING; + decoded_value.has_string_value = true; + + const CanSignalState* signalState = lookupSignalState(value, signal); + if(signalState != NULL) { + 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) +{ + SignalDecoder decoder = signal->decoder == NULL ? + noopDecoder : signal->decoder; + openxc_DynamicField decoded_value = decoder(signal, signals, + signalCount, value, send); + return decoded_value; +} + +openxc_DynamicField Decoder::decodeSignal(CanSignal* signal, + const CanMessage* message, CanSignal* signals, int signalCount, + bool* send) { + float value = parseSignalBitfield(signal, message); + return decodeSignal(signal, value, signals, signalCount, send); +} \ No newline at end of file diff --git a/src/can-decoder.h b/src/can-decoder.h new file mode 100644 index 00000000..249d5b00 --- /dev/null +++ b/src/can-decoder.h @@ -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_c +{ + 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-signals.cpp b/src/can-signals.cpp new file mode 100644 index 00000000..13ff30b1 --- /dev/null +++ b/src/can-signals.cpp @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2015, 2016 "IoT.bzh" + * Author "Romain Forlot" + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include "can-signals.h" + +bool match(const std::string &first, const std::string &second) +{ + +} + +CanSignal* getSignals(std::string name) +{ + int n_signals, i; + CanSignal ret_signals[]; + + n_signals = size(SIGNALS); + + for(i=0; i<=n_signals; i++) + { + if(SIGNALS[i].generic_name == name) + return &SIGNALS[i]; + i++; + } + return 0; +} diff --git a/src/can-signals.h b/src/can-signals.h new file mode 100644 index 00000000..f34c743e --- /dev/null +++ b/src/can-signals.h @@ -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 new file mode 100644 index 00000000..67214105 --- /dev/null +++ b/src/can-utils.cpp @@ -0,0 +1,226 @@ +/* + * 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 + +/******************************************************************************** +* +* CanBus method implementation +* +*********************************************************************************/ + +CanBus_c::CanBus_c(afb_binding_interface *itf, const std:string& dev_name) +{ + interface = itf; + deviceName = dev_name; +} + +int CanBus_c::open() +{ + const int canfd_on = 1; + struct ifreq ifr; + struct timeval timeout = {1, 0}; + + DEBUG(interface, "open_can_dev: CAN Handler socket : %d", socket); + if (socket >= 0) + close(socket); + + socket = socket(PF_CAN, SOCK_RAW, CAN_RAW); + if (socket < 0) + { + ERROR(interface, "open_can_dev: socket could not be created"); + } + else + { + /* Set timeout for read */ + setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(timeout)); + /* try to switch the socket into CAN_FD mode */ + if (setsockopt(socket, SOL_CAN_RAW, CAN_RAW_FD_FRAMES, &canfd_on, sizeof(canfd_on)) < 0) + { + NOTICE(interface, "open_can_dev: Can not switch into CAN Extended frame format."); + is_fdmode_on = false; + } else { + is_fdmode_on = true; + } + + /* Attempts to open a socket to CAN bus */ + strcpy(ifr.ifr_name, device); + if(ioctl(socket, SIOCGIFINDEX, &ifr) < 0) + ERROR(interface, "open_can_dev: ioctl failed"); + else + { + txAddress.can_family = AF_CAN; + txAddress.can_ifindex = ifr.ifr_ifindex; + + /* And bind it to txAddress */ + if (bind(socket, (struct sockaddr *)&txAddress, sizeof(txAddress)) < 0) + { + ERROR(interface, "open_can_dev: bind failed"); + } + else + { + fcntl(socket, F_SETFL, O_NONBLOCK); + return 0; + } + } + close(socket); + socket = -1; + } + return -1; +} + +int CanBus_c::close() +{ + close(socket); + socket = -1; +} + +void CanBus_c::start_threads() +{ + std::queue can_message_q; + + th_reading = std::thread(can_reader, interface, socket, can_message_q); + th_decoding = std::thread(can_decoder, interface, can_message_q, can_message_q); + th_pushing = std::thread(can_event_push, interface, can_message_q); +} + +/* + * Send a can message from a CanMessage_c object. + */ +int CanBus_c::send_can_message(CanMessage_c can_msg) +{ + int nbytes; + canfd_frame *f; + + f = can_msg.convert_to_canfd_frame(); + + if(socket >= 0) + { + nbytes = sendto(socket, &f, sizeof(struct canfd_frame), 0, + (struct sockaddr*)&txAddress, sizeof(txAddress)); + + if (nbytes == -1) + { + ERROR(interface, "send_can_message: Sending CAN frame failed."); + return -1; + } + return nbytes; + } + else + { + ERROR(interface, "send_can_message: socket not initialized. Attempt to reopen can device socket."); + open_can_dev(); + } + return 0; +} + +/******************************************************************************** +* +* CanMessage method implementation +* +*********************************************************************************/ + +uint32_t CanMessage_c::get_id() +{ + return id; +} + +int CanMessage_c::get_format() +{ + return format; +} + +uint8_t CanMessage_c::get_data() +{ + return data; +} +uint8_t CanMessage_c::get_lenght() +{ + return lenght; +} + +void CanMessage_c::set_id(uint32_t new_id) +{ + switch(format): + case CanMessageFormat::SIMPLE: + id = new_id & CAN_SFF_MASK; + case CanMessageFormat::EXTENDED: + id = new_id & CAN_EFF_MASK; + default: + ERROR(interface, "ERROR: Can set id, not a compatible format or format not set prior to set id."); +} + +void CanMessage_c::set_format(CanMessageFormat new_format) +{ + if(new_format == CanMessageFormat::SIMPLE || new_format == CanMessageFormat::EXTENDED) + format = new_format; + else + ERROR(interface, "ERROR: Can set format, wrong format chosen"); +} + +void CanMessage_c::set_data(uint8_t new_data) +{ + data = new_data; +} + +void CanMessage_c::set_lenght(uint8_t new_length) +{ + lenght = new_lenght; +} + +/* + * This is the preferred way to initialize a CanMessage object + * from a read canfd_frame message. + * + * params: canfd_frame pointer + */ +void CanMessage_c::convert_from_canfd_frame(canfd_frame *frame) +{ + + lenght = (canfd_frame->len > maxdlen) ? maxdlen : canfd_frame->len; + + switch (canfd_frame->can_id): + case (canfd_frame->can_id & CAN_ERR_FLAG): + id = canfd_frame->can_id & (CAN_ERR_MASK|CAN_ERR_FLAG); + break; + case (canfd_frame->can_id & CAN_EFF_FLAG): + id = canfd_frame->can_id & CAN_EFF_MASK; + format = CanMessageFormat::EXTENDED; + break; + default: + format = CanMessageFormat::STANDARD; + id = canfd_frame->can_id & CAN_SFF_MASK; + break; + + if (sizeof(canfd_frame->data) <= sizeof(data)) + { + memcpy(data, canfd_frame->data, lenght); + return 0; + } else if (sizeof(canfd_frame->data) >= CAN_MAX_DLEN) + ERROR(interface, "CanMessage_c: canfd_frame data too long to be stored into CanMessage object"); +} + +canfd_frame* convert_to_canfd_frame() +{ + canfd_frame frame; + + frame.id = can_msg.get_id(); + frame.len = can_msg.get_lenght(); + frame.data = can_msg.get_data(); + + return &frame; +} diff --git a/src/can-utils.h b/src/can-utils.h new file mode 100644 index 00000000..8c850e6e --- /dev/null +++ b/src/can-utils.h @@ -0,0 +1,396 @@ +/* + * 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 CanBus_c { + private: + afb_binding_interface *interface; + + /* Got from conf file */ + std::string deviceName; + + int socket; + bool is_fdmode_on; + struct sockaddr_can txAddress; + + std::thread th_reading; + std::thread th_decoding; + std::thread th_pushing; + std::queue can_message_q; + std::queue VehicleMessage_q; + + public: + int open(); + int close(); + + void start_threads(); + int send_can_message(CanMessage_c can_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 CanMessage_c { + private: + uint32_t id; + CanMessageFormat format; + uint8_t data[CAN_MESSAGE_SIZE]; + uint8_t length; + + public: + uint32_t get_id(); + int get_format(); + uint8_t get_data(); + uint8_t get_lenght(); + + 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(CanMessage_c, 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; + */ + class CanSignalState_c { + private: + const int value; + const char *name; +}; + +/* 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; + + struct afb_event event; +}; +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; + */ +class CanMessageSet_c { + private: + uint8_t index; + const char * name; + uint8_t busCount; + unsigned short messageCount; + unsigned short signalCount; + unsigned short commandCount; +}; + +/* 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 new file mode 100644 index 00000000..ba822026 --- /dev/null +++ b/src/can_decode_message.cpp @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2015, 2016 "IoT.bzh" + * Author "Romain Forlot" + * Author "Loic Collignon" + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include + +#include + +#include "can-utils.h" +#include "openxc.pb.h" + +void can_decode_message(CanBus_c *can_bus) +{ + CanMessage_c can_message; + + while(true) + { + if(! can_bus->can_message_q.empty()) + { + can_message = can_bus->can_message_q.front(); + can_bus->can_message_q.pop(); + } + } +} \ No newline at end of file diff --git a/src/can_event_push.cpp b/src/can_event_push.cpp new file mode 100644 index 00000000..b08619b8 --- /dev/null +++ b/src/can_event_push.cpp @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2015, 2016 "IoT.bzh" + * Author "Romain Forlot" + * Author "Loic Collignon" + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include + +#include + +#include "can-utils.h" +#include "openxc.pb.h" + +void can_event_push(CanBus_c *can_bus) +{ + while(true) + { + if(! can_bus->vehicle_message_q.empty()) + { + vehicle_message = can_bus->vehicle_message_q.front(); + can_bus->vehicle_message_q.pop(); + } + } +} diff --git a/src/can_reader.cpp b/src/can_reader.cpp new file mode 100644 index 00000000..d9b3e671 --- /dev/null +++ b/src/can_reader.cpp @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2015, 2016 "IoT.bzh" + * Author "Romain Forlot" + * Author "Loic Collignon" + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#include + +#include "can-utils.h" + +void can_reader(CanBus_c *can_bus)) +{ + ssize_t nbytes; + int maxdlen; + CanMessage_c can_message; + canfd_frame canfd_frame; + + /* Test that socket is really opened */ + if ( can_bus->socket < 0) + { + ERROR(interface, "read_can: Socket unavailable"); + return -1; + } + + while(true) + { + nbytes = read(can_bus->socket, &canfd_frame, CANFD_MTU); + + switch(nbytes) + { + case CANFD_MTU: + DEBUG(interface, "read_can: Got an CAN FD frame with length %d", canfd_frame.len); + maxdlen = CANFD_MAX_DLEN; + break; + case CAN_MTU: + DEBUG(interface, "read_can: Got a legacy CAN frame with length %d", canfd_frame.len); + maxdlen = CAN_MAX_DLEN; + break; + default: + if (errno == ENETDOWN) + ERROR(interface, "read_can: %s interface down", device); + + ERROR(interface, "read_can: Error reading CAN bus"); + return -2; + } + + can_message.convert_from_canfd_frame(canfd_frame); + + can_message_q.push(can_message); + } +} diff --git a/src/config.xml.in b/src/config.xml.in new file mode 100644 index 00000000..33a8ff85 --- /dev/null +++ b/src/config.xml.in @@ -0,0 +1,11 @@ + + + @PROJECT_NAME@ + + + This is a demo application used to control and dialog with HVAC system + Romain Forlot <romain.forlot@iot.bzh> + APL 2.0 + + + diff --git a/src/export.map b/src/export.map new file mode 100644 index 00000000..52c1b4aa --- /dev/null +++ b/src/export.map @@ -0,0 +1 @@ +{ global: afbBindingV1*; local: *; }; diff --git a/src/icon.png b/src/icon.png new file mode 100644 index 00000000..9bd6a6e4 Binary files /dev/null and b/src/icon.png differ diff --git a/src/libs/bitfield-c b/src/libs/bitfield-c new file mode 160000 index 00000000..a34745ec --- /dev/null +++ b/src/libs/bitfield-c @@ -0,0 +1 @@ +Subproject commit a34745ec93ae0a1d4f1b640dba8fb6702331a8e9 diff --git a/src/libs/nanopb b/src/libs/nanopb new file mode 160000 index 00000000..ffe4aff8 --- /dev/null +++ b/src/libs/nanopb @@ -0,0 +1 @@ +Subproject commit ffe4aff87cc3a15863c09aa808adf2381c8f2fb7 diff --git a/src/libs/openxc-message-format b/src/libs/openxc-message-format new file mode 160000 index 00000000..d9f54f97 --- /dev/null +++ b/src/libs/openxc-message-format @@ -0,0 +1 @@ +Subproject commit d9f54f97578429773421abce98d5f6579717afcc diff --git a/src/libs/uds-c b/src/libs/uds-c new file mode 160000 index 00000000..e506334e --- /dev/null +++ b/src/libs/uds-c @@ -0,0 +1 @@ +Subproject commit e506334e270d77b20c0bc259ac6c7d8c9b702b7a diff --git a/src/low-can-binding.cpp b/src/low-can-binding.cpp new file mode 100644 index 00000000..b6098907 --- /dev/null +++ b/src/low-can-binding.cpp @@ -0,0 +1,253 @@ +/* + * Copyright (C) 2015, 2016 "IoT.bzh" + * Author "Romain Forlot" + * Author "Loic Collignon" + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include "ll-can-binding.h" +#include "obd2.h" + +/* + * Interface between the daemon and the binding + */ +static const struct afb_binding_interface *interface; + +/******************************************************************************** +* +* Event management +* +*********************************************************************************/ + +/* + * TBF TBF TBF + * called on an event on the CAN bus + */ +static int on_event(sd_event_source *s, int fd, uint32_t revents, void *userdata) +{ + openxc_CanMessage can_message; + + can_message = openxc_CanMessage_init_default; + + /* read available data */ + if ((revents & EPOLLIN) != 0) + { + read_can(&can_message); + send_event(); + } + + /* check if error or hangup */ + if ((revents & (EPOLLERR|EPOLLRDHUP|EPOLLHUP)) != 0) + { + sd_event_source_unref(s); + close(fd); + connect_to_event_loop(); + } + + return 0; +} + +/* + * USELESS SINCE THREADS SEPARATION + * + * Get the event loop running. + * Will trigger on_event function on EPOLLIN event on socket + * + * Return 0 or positive value on success. Else negative value for failure. +static int connect_to_event_loop(CanBus &CanBus_handler) +{ + sd_event *event_loop; + sd_event_source *source; + int rc; + + if (CanBus_handler.socket < 0) + { + return CanBus_handler.socket; + } + + event_loop = afb_daemon_get_event_loop(interface->daemon); + rc = sd_event_add_io(event_loop, &source, CanBus_handler.socket, EPOLLIN, on_event, NULL); + if (rc < 0) + { + CanBus_handler.close(); + ERROR(interface, "Can't connect CAN bus %s to the event loop", CanBus_handler.device); + } else + { + NOTICE(interface, "Connected CAN bus %s to the event loop", CanBus_handler.device); + } + + return rc; +} + */ + +/******************************************************************************** +* +* Subscription and unsubscription +* +*********************************************************************************/ + +static int subscribe_unsubscribe_sig(struct afb_req request, int subscribe, struct signal *sig) +{ + if (!afb_event_is_valid(sig->event)) { + if (!subscribe) + return 1; + sig->event = afb_daemon_make_event(afbitf->daemon, sig->name); + if (!afb_event_is_valid(sig->event)) { + return 0; + } + } + + if (((subscribe ? afb_req_subscribe : afb_req_unsubscribe)(request, sig->event)) < 0) { + return 0; + } + + return 1; +} + +static int subscribe_unsubscribe_all(struct afb_req request, int subscribe) +{ + int i, n, e; + + n = sizeof OBD2_PIDS / sizeof * OBD2_PIDS; + e = 0; + for (i = 0 ; i < n ; i++) + e += !subscribe_unsubscribe_sig(request, subscribe, &OBD2_PIDS[i]); + return e == 0; +} + +static int subscribe_unsubscribe_name(struct afb_req request, int subscribe, const char *name) +{ + struct signal *sig; + + if (0 == strcmp(name, "*")) + return subscribe_unsubscribe_all(request, subscribe); + + sig = getSignal(name); + if (sig == NULL) { + return 0; + } + + return subscribe_unsubscribe_sig(request, subscribe, sig); +} + +static void subscribe_unsubscribe(struct afb_req request, int subscribe) +{ + int ok, i, n; + struct json_object *args, *a, *x; + + /* makes the subscription/unsubscription */ + args = afb_req_json(request); + if (args == NULL || !json_object_object_get_ex(args, "event", &a)) { + ok = subscribe_unsubscribe_all(request, subscribe); + } else if (json_object_get_type(a) != json_type_array) { + ok = subscribe_unsubscribe_name(request, subscribe, json_object_get_string(a)); + } else { + n = json_object_array_length(a); + ok = 0; + for (i = 0 ; i < n ; i++) { + x = json_object_array_get_idx(a, i); + if (subscribe_unsubscribe_name(request, subscribe, json_object_get_string(x))) + ok++; + } + ok = (ok == n); + } + + /* send the report */ + if (ok) + afb_req_success(request, NULL, NULL); + else + afb_req_fail(request, "error", NULL); +} + +static void subscribe(struct afb_req request) +{ + subscribe_unsubscribe(request, 1); +} + +static void unsubscribe(struct afb_req request) +{ + subscribe_unsubscribe(request, 0); +} +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." }, + {NULL} +}; + +static const struct afb_binding binding_desc = { + .type = AFB_BINDING_VERSION_1, + .v1 = { + .info = "CAN bus service", + .prefix = "can", + .verbs = verbs + } +}; + +const struct afb_binding *afbBindingV1Register (const struct afb_binding_interface *itf) +{ + interface = itf; + + return &binding_desc; +} + +int afbBindingV1ServiceInit(struct afb_service service) +{ + std::ifstream fd_conf; + std::string fd_conf_content; + json_object jo_canbus; + + /* Open JSON conf file */ + jo_canbus = json_object_new_object(); + fd_conf = afb_daemon_rootdir_open_locale(interface->daemon, "canbus.json", O_RDONLY, NULL); + if (fd_conf) + { + fd_conf.seekg(0, std::ios::end); + fd_conf_content.resize(fd_conf.tellg()); + fd_conf.seekg(0, std::ios::beg); + fd_conf.read(&fd_conf_content[0], fd_conf_content.size()); + fd_conf.close(); + } + + jo_canbus = json_tokener_parse(&fd_conf_content); + + /* Open CAN socket */ + CanBus_c CanBus_handler(interface, json_object_get_string(json_object_object_get(jo_canbus, "deviceName")); + CanBus_handler.open(); + CanBus_handler.start_threads(); +} diff --git a/src/obd2.cpp b/src/obd2.cpp new file mode 100644 index 00000000..7db5d97d --- /dev/null +++ b/src/obd2.cpp @@ -0,0 +1,59 @@ +/* + * 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. + */ + + +void shims_logger(afb_binding_interface *itf) +{ + //DEBUG(itf, "dd"); +} + +void shims_timer() +{ +} + +/* + * Will scan for supported Obd2 pids + */ +Obd2Handler::Obd2Handler(afb_binding_interface *itf, CanBus_c cb) +{ + CanBus_c can_bus = cb; + DiagnosticShims shims = diagnostic_init_shims(shims_logger, can_bus.send_can_message, NULL); + + int n_pids, i; + + n_pids = size(Obd2Pid); + for(i=0; i<=n_pids; i++) + { + } +} + +Obd2Handler::add_request(int pid) +{ + DiagnosticRequest request = { + arbitration_id: OBD2_FUNCTIONAL_BROADCAST_ID, + mode: 0x1, has_pid: true, pid: pid}; +} + +Obd2Handler::is_obd2_request(DiagnosticRequest* request) +{ + return request->mode == 0x1 && request->has_pid && request->pid < 0xff; +} + +Obd2Handler::decode_obd2_response(DiagnosticResponse* responce) +{ + return diagnostic_decode_obd2_pid(response); +} diff --git a/src/obd2.h b/src/obd2.h new file mode 100644 index 00000000..862c04a2 --- /dev/null +++ b/src/obd2.h @@ -0,0 +1,150 @@ +/* + * 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 Obd2Handler_c { + private: + /* + * 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: + Obd2Handler_c(); + + bool isObd2Request(request); +} diff --git a/src/timer.h b/src/timer.h new file mode 100644 index 00000000..76eb51df --- /dev/null +++ b/src/timer.h @@ -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; diff --git a/timer.h b/timer.h deleted file mode 100644 index 76eb51df..00000000 --- a/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; -- cgit 1.2.3-korg