├── .circleci └── config.yml ├── .gitignore ├── CMakeLists.txt ├── LICENSE ├── README.md ├── examples ├── parse_types.cpp └── read_dbc.cpp ├── include ├── attribute.hpp ├── bus_node.hpp ├── comment.hpp ├── common_defs.hpp ├── database.hpp ├── message.hpp └── signal.hpp └── src ├── attribute.cpp ├── bus_node.cpp ├── comment.cpp ├── database.cpp ├── message.cpp └── signal.cpp /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | jobs: 3 | build: 4 | docker: 5 | - image: autonomoustuff/docker-builds:bionic-non-root 6 | steps: 7 | - run: 8 | name: Set Up Container 9 | command: | 10 | sudo apt-get -qqq update 11 | sudo apt-get -qqq --no-install-recommends install build-essential cmake wget git 12 | - checkout 13 | - run: 14 | name: Build 15 | command: | 16 | mkdir build && cd build 17 | cmake .. 18 | make 19 | - run: 20 | name: Run Examples 21 | command: | 22 | cd build 23 | wget --no-check-certificate -O example.dbc https://raw.githubusercontent.com/astuff/pacmod_dbc/v3/as_pacmod.dbc 24 | ./parse_types 25 | ./read_dbc 26 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.swp 2 | build/ 3 | lib/ 4 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5) 2 | project(can_dbc_loader) 3 | 4 | if(NOT CMAKE_CXX_STANDARD) 5 | set(CMAKE_CXX_STANDARD 14) 6 | endif() 7 | 8 | set(BUILD_EXAMPLES ON) 9 | 10 | include_directories(include) 11 | 12 | add_library( 13 | can_dbc_loader SHARED 14 | src/attribute.cpp 15 | src/bus_node.cpp 16 | src/comment.cpp 17 | src/signal.cpp 18 | src/message.cpp 19 | src/database.cpp 20 | ) 21 | 22 | if(BUILD_EXAMPLES) 23 | add_executable( 24 | parse_types 25 | examples/parse_types.cpp 26 | ) 27 | 28 | target_link_libraries( 29 | parse_types 30 | can_dbc_loader 31 | ) 32 | 33 | add_executable( 34 | read_dbc 35 | examples/read_dbc.cpp 36 | ) 37 | 38 | target_link_libraries( 39 | read_dbc 40 | can_dbc_loader 41 | ) 42 | endif() 43 | 44 | install( 45 | TARGETS can_dbc_loader 46 | ARCHIVE DESTINATION ${CMAKE_SOURCE_DIR}/lib 47 | LIBRARY DESTINATION ${CMAKE_SOURCE_DIR}/lib 48 | RUNTIME DESTINATION ${CMAKE_SOURCE_DIR}/bin 49 | ) 50 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2019 AutonomouStuff, LLC 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # CAN DBC Loader [![CircleCI](https://circleci.com/gh/astuff/can_dbc_loader/tree/master.svg?style=svg)](https://circleci.com/gh/astuff/can_dbc_loader/tree/master) 2 | 3 | This is a C++ tool designed to load a Vector DBC file into a set of classes and structures in memory 4 | and allow encoding/decoding of CAN message data in real-time. 5 | -------------------------------------------------------------------------------- /examples/parse_types.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2019 AutonomouStuff, LLC 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 16 | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | #include 22 | #include 23 | 24 | #include 25 | 26 | static std::string message_text = "BO_ 1045 OCCUPANCY_RPT: 2 PACMOD"; 27 | static std::string signal_text = " SG_ VEHICLE_SPEED : 7|16@0- (0.01,0) [-327.68|327.67] \"m/s\" CUSTOMER_ECU"; 28 | 29 | using AS::CAN::DbcLoader::Message; 30 | using AS::CAN::DbcLoader::Order; 31 | using AS::CAN::DbcLoader::Signal; 32 | 33 | int main(int argc, char ** argv) 34 | { 35 | Message msg(std::move(message_text)); 36 | 37 | std::cout << "Message ID: 0x" << std::hex << msg.getId() << std::endl; 38 | std::cout << "Message name: " << msg.getName() << std::endl; 39 | std::cout << "Message DLC: " << msg.getDlc() << std::endl; 40 | std::cout << "Message transmitting node: " << msg.getTransmittingNode().getName(); 41 | std::cout << std::endl << std::endl; 42 | 43 | Signal sig(std::move(signal_text)); 44 | 45 | std::cout << "Signal name: " << sig.getName() << std::endl; 46 | std::cout << "Signal is multiplex def: " << (sig.isMultiplexDef() ? "true" : "false") << std::endl; 47 | 48 | if (sig.getMultiplexId() != nullptr) { 49 | std::cout << "Signal multiplex identifier: " << *(sig.getMultiplexId()) << std::endl; 50 | } 51 | 52 | std::cout << "Signal start bit: " << static_cast(sig.getStartBit()) << std::endl; 53 | std::cout << "Signal length: " << static_cast(sig.getLength()) << std::endl; 54 | std::cout << "Signal endianness: " << (sig.getEndianness() == Order::BE ? "big-endian" : "little-endian") << std::endl; 55 | std::cout << "Signal is signed: " << (sig.isSigned() ? "true" : "false") << std::endl; 56 | std::cout << "Signal factor: " << sig.getFactor() << std::endl; 57 | std::cout << "Signal offset: " << sig.getOffset() << std::endl; 58 | std::cout << "Signal min value: " << sig.getMinVal() << std::endl; 59 | std::cout << "Signal max value: " << sig.getMaxVal() << std::endl; 60 | std::cout << "Signal unit: " << sig.getUnit() << std::endl; 61 | std::cout << "Signal receiving bus nodes: "; 62 | 63 | for (auto & node : sig.getReceivingNodes()) { 64 | std::cout << node->getName() << " "; 65 | } 66 | 67 | std::cout << std::endl; 68 | 69 | return 0; 70 | } 71 | -------------------------------------------------------------------------------- /examples/read_dbc.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2019 AutonomouStuff, LLC 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 16 | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | #include 22 | 23 | #include 24 | #include 25 | 26 | static std::string dbc_file = "example.dbc"; 27 | 28 | using AS::CAN::DbcLoader::AttributeType; 29 | using AS::CAN::DbcLoader::Database; 30 | using AS::CAN::DbcLoader::DbcObjType; 31 | using AS::CAN::DbcLoader::EnumAttribute; 32 | using AS::CAN::DbcLoader::FloatAttribute; 33 | using AS::CAN::DbcLoader::IntAttribute; 34 | using AS::CAN::DbcLoader::StringAttribute; 35 | 36 | int main(int argc, char ** argv) 37 | { 38 | Database dbc(dbc_file); 39 | 40 | size_t signal_counter = 0; 41 | size_t bus_node_comment_counter = 0; 42 | size_t message_comment_counter = 0; 43 | size_t signal_comment_counter = 0; 44 | size_t bus_node_attr_counter = 0; 45 | size_t message_attr_counter = 0; 46 | size_t signal_attr_counter = 0; 47 | size_t attr_def_default_counter = 0; 48 | 49 | auto bus_nodes = dbc.getBusNodes(); 50 | auto messages = dbc.getMessages(); 51 | auto attr_defs = dbc.getAttributeDefinitions(); 52 | 53 | for (auto & bus_node : bus_nodes) { 54 | if (bus_node->getComment() != nullptr) { 55 | bus_node_comment_counter++; 56 | } 57 | } 58 | 59 | for (auto & msg : messages) { 60 | auto signals = msg.second->getSignals(); 61 | 62 | if (msg.second->getComment() != nullptr) { 63 | message_comment_counter++; 64 | } 65 | 66 | signal_counter += signals.size(); 67 | 68 | for (auto & sig : signals) { 69 | if (sig.second->getComment() != nullptr) { 70 | signal_comment_counter++; 71 | } 72 | } 73 | } 74 | 75 | for (const auto & attr_def : attr_defs) { 76 | switch (attr_def->getDbcObjType()) { 77 | case DbcObjType::BUS_NODES: 78 | bus_node_attr_counter++; 79 | break; 80 | case DbcObjType::MESSAGE: 81 | message_attr_counter++; 82 | break; 83 | case DbcObjType::SIGNAL: 84 | signal_attr_counter++; 85 | break; 86 | } 87 | 88 | if (attr_def->getAttrType() == AttributeType::ENUM) { 89 | auto temp_attr = dynamic_cast(attr_def); 90 | 91 | if (temp_attr->getDefaultValue() != nullptr) { 92 | attr_def_default_counter++; 93 | } 94 | } else if (attr_def->getAttrType() == AttributeType::FLOAT) { 95 | auto temp_attr = dynamic_cast(attr_def); 96 | 97 | if (temp_attr->getDefaultValue() != nullptr) { 98 | attr_def_default_counter++; 99 | } 100 | } else if (attr_def->getAttrType() == AttributeType::INT) { 101 | auto temp_attr = dynamic_cast(attr_def); 102 | 103 | if (temp_attr->getDefaultValue() != nullptr) { 104 | attr_def_default_counter++; 105 | } 106 | } else if (attr_def->getAttrType() == AttributeType::STRING) { 107 | auto temp_attr = dynamic_cast(attr_def); 108 | 109 | if (temp_attr->getDefaultValue() != nullptr) { 110 | attr_def_default_counter++; 111 | } 112 | } 113 | } 114 | 115 | std::cout << "Found " << bus_nodes.size() << " bus nodes.\n"; 116 | std::cout << "Found " << dbc.getMessages().size() << " messages.\n"; 117 | std::cout << "Found " << signal_counter << " signals.\n"; 118 | 119 | size_t total_comments = bus_node_comment_counter + message_comment_counter + signal_comment_counter; 120 | 121 | std::cout << "Found " << total_comments << " comments (Bus nodes: " << bus_node_comment_counter; 122 | std::cout << ", Messages: " << message_comment_counter << ", Signals: " << signal_comment_counter << ").\n"; 123 | std::cout << "Found " << attr_defs.size() << " attribute definitions (Bus nodes: " << bus_node_attr_counter; 124 | std::cout << ", Messages: " << message_attr_counter << ", Signals: " << signal_attr_counter << ").\n"; 125 | std::cout << "Found " << attr_def_default_counter << " attribute default values."; 126 | std::cout << std::endl; 127 | 128 | return 0; 129 | } 130 | -------------------------------------------------------------------------------- /include/attribute.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2019 AutonomouStuff, LLC 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 16 | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | #ifndef ATTRIBUTE_HPP_ 22 | #define ATTRIBUTE_HPP_ 23 | 24 | #include "common_defs.hpp" 25 | 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | namespace AS 32 | { 33 | namespace CAN 34 | { 35 | namespace DbcLoader 36 | { 37 | 38 | class Attribute 39 | : public DbcObj 40 | { 41 | public: 42 | virtual std::string getDefaultValueDbcText() const; 43 | virtual std::string getName() const; 44 | virtual DbcObjType getDbcObjType() const; 45 | virtual AttributeType getAttrType() const = 0; 46 | 47 | protected: 48 | void generateText() override; 49 | void parse() override; 50 | 51 | std::string default_value_dbc_text_; 52 | std::string name_; 53 | DbcObjType dbc_obj_type_; 54 | 55 | private: 56 | virtual void generateDefaultValueText() = 0; 57 | virtual std::string generateTypeSpecificText() = 0; 58 | virtual void parseDefaultValue() = 0; 59 | virtual void parseTypeSpecificValues(std::istringstream & stream) = 0; 60 | }; 61 | 62 | class EnumAttribute 63 | : public Attribute 64 | { 65 | public: 66 | EnumAttribute( 67 | std::string && dbc_text, 68 | std::string && default_value_dbc_text); 69 | EnumAttribute( 70 | std::string && name, 71 | DbcObjType && dbc_obj_type, 72 | std::vector && enum_values, 73 | std::string * default_value = nullptr); 74 | ~EnumAttribute() = default; 75 | EnumAttribute(const EnumAttribute & other); 76 | EnumAttribute(EnumAttribute && other) = default; 77 | EnumAttribute & operator=(const EnumAttribute & other); 78 | EnumAttribute & operator=(EnumAttribute && other) = default; 79 | 80 | std::vector getEnumValues() const; 81 | const std::string * getDefaultValue() const; 82 | AttributeType getAttrType() const { return AttributeType::ENUM; }; 83 | 84 | private: 85 | void generateDefaultValueText(); 86 | std::string generateTypeSpecificText(); 87 | void parseDefaultValue(); 88 | void parseTypeSpecificValues(std::istringstream & stream); 89 | 90 | std::vector enum_values_; 91 | std::unique_ptr default_value_; 92 | }; 93 | 94 | class FloatAttribute 95 | : public Attribute 96 | { 97 | public: 98 | FloatAttribute( 99 | std::string && dbc_text, 100 | std::string && default_value_dbc_text); 101 | FloatAttribute( 102 | std::string && name, 103 | DbcObjType && dbc_obj_type, 104 | float min, float max, 105 | float * default_value = nullptr); 106 | ~FloatAttribute() = default; 107 | FloatAttribute(const FloatAttribute & other); 108 | FloatAttribute(FloatAttribute && other) = default; 109 | FloatAttribute & operator=(const FloatAttribute & other); 110 | FloatAttribute & operator=(FloatAttribute && other) = default; 111 | 112 | float getMin() const; 113 | float getMax() const; 114 | const float * getDefaultValue() const; 115 | AttributeType getAttrType() const { return AttributeType::FLOAT; }; 116 | 117 | private: 118 | void generateDefaultValueText(); 119 | std::string generateTypeSpecificText(); 120 | void parseDefaultValue(); 121 | void parseTypeSpecificValues(std::istringstream & stream); 122 | 123 | float min_, max_; 124 | std::unique_ptr default_value_; 125 | }; 126 | 127 | class IntAttribute 128 | : public Attribute 129 | { 130 | public: 131 | IntAttribute( 132 | std::string && dbc_text, 133 | std::string && default_value_dbc_text); 134 | IntAttribute( 135 | std::string && name, 136 | DbcObjType && dbc_obj_type, 137 | int min, int max, 138 | int * default_value = nullptr); 139 | ~IntAttribute() = default; 140 | IntAttribute(const IntAttribute & other); 141 | IntAttribute(IntAttribute && other) = default; 142 | IntAttribute & operator=(const IntAttribute & other); 143 | IntAttribute & operator=(IntAttribute && other) = default; 144 | 145 | int getMin() const; 146 | int getMax() const; 147 | const int * getDefaultValue() const; 148 | AttributeType getAttrType() const { return AttributeType::INT; }; 149 | 150 | private: 151 | void generateDefaultValueText(); 152 | std::string generateTypeSpecificText(); 153 | void parseDefaultValue(); 154 | void parseTypeSpecificValues(std::istringstream & stream); 155 | 156 | int min_, max_; 157 | std::unique_ptr default_value_; 158 | }; 159 | 160 | class StringAttribute 161 | : public Attribute 162 | { 163 | public: 164 | StringAttribute( 165 | std::string && dbc_text, 166 | std::string && default_value_dbc_text); 167 | StringAttribute( 168 | std::string && name, 169 | DbcObjType && dbc_obj_type, 170 | std::string * default_value = nullptr); 171 | ~StringAttribute() = default; 172 | StringAttribute(const StringAttribute & other); 173 | StringAttribute(StringAttribute && other) = default; 174 | StringAttribute & operator=(const StringAttribute & other); 175 | StringAttribute & operator=(StringAttribute && other) = default; 176 | 177 | AttributeType getAttrType() const { return AttributeType::STRING; }; 178 | const std::string * getDefaultValue() const; 179 | 180 | private: 181 | void generateDefaultValueText(); 182 | std::string generateTypeSpecificText(); 183 | void parseDefaultValue(); 184 | void parseTypeSpecificValues(std::istringstream & stream); 185 | 186 | std::unique_ptr default_value_; 187 | }; 188 | 189 | } // namespace DbcLoader 190 | } // namespace CAN 191 | } // namespace AS 192 | 193 | #endif // ATTRIBUTE_HPP_ 194 | -------------------------------------------------------------------------------- /include/bus_node.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2019 AutonomouStuff, LLC 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 16 | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | #ifndef BUS_NODE_HPP_ 22 | #define BUS_NODE_HPP_ 23 | 24 | #include "common_defs.hpp" 25 | #include "comment.hpp" 26 | 27 | #include 28 | #include 29 | 30 | namespace AS 31 | { 32 | namespace CAN 33 | { 34 | namespace DbcLoader 35 | { 36 | 37 | class BusNode 38 | : public AttrObj 39 | { 40 | public: 41 | BusNode(std::string && node_name); 42 | ~BusNode() = default; 43 | BusNode(const BusNode & other); 44 | BusNode(BusNode && other) = default; 45 | BusNode & operator=(const BusNode & other); 46 | BusNode & operator=(BusNode && other) = default; 47 | 48 | std::string getName() const; 49 | const std::string * getComment() const; 50 | 51 | friend class Database; 52 | friend class Message; 53 | friend class Signal; 54 | 55 | private: 56 | std::string name_; 57 | std::unique_ptr comment_; 58 | }; 59 | 60 | } // namespace DbcLoader 61 | } // namespace CAN 62 | } // namespace AS 63 | 64 | #endif // BUS_NODE_HPP_ 65 | -------------------------------------------------------------------------------- /include/comment.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2019 AutonomouStuff, LLC 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 16 | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | #ifndef COMMENT_HPP_ 22 | #define COMMENT_HPP_ 23 | 24 | #include "common_defs.hpp" 25 | 26 | #include 27 | 28 | namespace AS 29 | { 30 | namespace CAN 31 | { 32 | namespace DbcLoader 33 | { 34 | 35 | class Comment 36 | { 37 | public: 38 | std::string getComment() const; 39 | 40 | friend class BusNode; 41 | friend class Database; 42 | friend class Message; 43 | friend class Signal; 44 | 45 | protected: 46 | std::string comment_; 47 | }; 48 | 49 | class BusNodeComment 50 | : public Comment, public DbcObj 51 | { 52 | public: 53 | BusNodeComment(std::string && dbc_text); 54 | BusNodeComment( 55 | std::string && node_name, 56 | std::string && comment); 57 | 58 | std::string getNodeName() const; 59 | 60 | friend class BusNode; 61 | 62 | private: 63 | void generateText() override; 64 | void parse() override; 65 | 66 | std::string node_name_; 67 | }; 68 | 69 | class MessageComment 70 | : public Comment, public DbcObj 71 | { 72 | public: 73 | MessageComment(std::string && dbc_text); 74 | MessageComment(unsigned int msg_id, std::string && comment); 75 | 76 | unsigned int getMsgId() const; 77 | 78 | friend class Message; 79 | 80 | private: 81 | void generateText() override; 82 | void parse() override; 83 | 84 | unsigned int msg_id_; 85 | }; 86 | 87 | class SignalComment 88 | : public Comment, public DbcObj 89 | { 90 | public: 91 | SignalComment(std::string && dbc_text); 92 | SignalComment( 93 | unsigned int msg_id, 94 | std::string && signal_name, 95 | std::string && comment); 96 | 97 | unsigned int getMsgId() const; 98 | std::string getSignalName() const; 99 | 100 | friend class Signal; 101 | 102 | private: 103 | void generateText() override; 104 | void parse() override; 105 | 106 | unsigned int msg_id_; 107 | std::string signal_name_; 108 | }; 109 | 110 | } // namespace DbcLoader 111 | } // namespace CAN 112 | } // namespace AS 113 | 114 | #endif // COMMENT_HPP_ 115 | -------------------------------------------------------------------------------- /include/common_defs.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2019 AutonomouStuff, LLC 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 16 | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | #ifndef COMMON_DEFS_HPP_ 22 | #define COMMON_DEFS_HPP_ 23 | 24 | #include 25 | #include 26 | #include 27 | 28 | namespace AS 29 | { 30 | namespace CAN 31 | { 32 | namespace DbcLoader 33 | { 34 | 35 | static constexpr unsigned int MAX_CAN_ID = 0x1FFFFFFF; 36 | 37 | static constexpr std::array DLC_LENGTH = 38 | { 0, 1, 2, 3, 4, 5, 6, 7, 39 | 8, 12, 16, 20, 24, 32, 48, 64 }; 40 | 41 | // Currently unsupported types: 42 | // BA_DEF_DEF_REL_ 43 | // BA_DEF_REL_ 44 | // BA_DEF_SGTYPE_ 45 | // BA_REL_ 46 | // BA_SGTYPE_ 47 | // BO_TX_BU_ 48 | // BU_BO_REL_ 49 | // BU_EV_REL_ 50 | // BU_SG_REL_ 51 | // CAT_ 52 | // CAT_DEF_ 53 | // ENVVAR_DATA_ 54 | // EV_ 55 | // EV_DATA_ 56 | // FILTER 57 | // NS_DESC_ 58 | // SGTYPE_ 59 | // SGTYPE_VAL_ 60 | // SG_MUL_VAL_ 61 | // SIGTYPE_VALTYPE_ 62 | // SIG_GROUP_ 63 | // SIG_TYPE_REF_ 64 | // SIG_VALTYPE_ 65 | // VAL_TABLE_ 66 | 67 | static const std::array PREAMBLES = 68 | { 69 | "VERSION", // VERSION 70 | "BS_:", // BUS CONFIG 71 | "BU_:", // BUS NODES 72 | "BO_", // MESSAGE 73 | "SG_", // SIGNAL 74 | "CM_", // COMMENT 75 | "VAL_", // SIGNAL VALUE LIST 76 | "BA_DEF_", // ATTRIBUTE DEFINITION 77 | "BA_DEF_DEF_", // ATTRIBUTE DEFAULT VALUE 78 | "BA_" // ATTRIBUTE VALUE 79 | }; 80 | 81 | enum class AttributeType 82 | { 83 | ENUM, 84 | FLOAT, 85 | HEX, 86 | INT, 87 | STRING 88 | }; 89 | 90 | enum class DbcObjType 91 | { 92 | VERSION, 93 | BUS_CONFIG, 94 | BUS_NODES, 95 | MESSAGE, 96 | SIGNAL, 97 | DESCRIPTION, 98 | SIGNAL_VAL_DEF, 99 | ATTRIBUTE_DEF, 100 | ATTRIBUTE_VAL 101 | }; 102 | 103 | enum class Order 104 | { 105 | BE, 106 | LE 107 | }; 108 | 109 | enum class TranscodeErrorType 110 | { 111 | NONE 112 | }; 113 | 114 | struct DbcReadException 115 | : public std::exception 116 | { 117 | const char * what() const throw() 118 | { 119 | return "Exception when reading DBC file from disk."; 120 | } 121 | }; 122 | 123 | struct DbcWriteException 124 | : public std::exception 125 | { 126 | const char * what() const throw() 127 | { 128 | return "Exception when writing DBC file to disk."; 129 | } 130 | }; 131 | 132 | struct DbcParseException 133 | : public std::exception 134 | { 135 | const char * what() const throw() 136 | { 137 | return "Exception when parsing DBC object."; 138 | } 139 | }; 140 | 141 | class DbcObj 142 | { 143 | public: 144 | virtual ~DbcObj() {}; 145 | const std::string getDbcText() 146 | { 147 | return dbc_text_; 148 | } 149 | 150 | friend class Database; 151 | 152 | protected: 153 | std::string dbc_text_; 154 | 155 | private: 156 | virtual void generateText() = 0; 157 | virtual void parse() = 0; 158 | }; 159 | 160 | class AttrObj 161 | { 162 | public: 163 | const std::unordered_map getAttributeValues() 164 | { 165 | return attribute_values_; 166 | } 167 | 168 | const bool hasAttributeValues() 169 | { 170 | return (attribute_values_.size() < 1); 171 | } 172 | 173 | protected: 174 | std::unordered_map attribute_values_; 175 | }; 176 | 177 | struct TranscodeError 178 | { 179 | TranscodeError(TranscodeErrorType type, std::string desc) 180 | : type(type), desc(desc) {}; 181 | TranscodeErrorType type; 182 | std::string desc; 183 | }; 184 | 185 | } // namespace DbcLoader 186 | } // namespace CAN 187 | } // namespace AS 188 | 189 | #endif // COMMON_DEFS_HPP_ 190 | -------------------------------------------------------------------------------- /include/database.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2019 AutonomouStuff, LLC 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 16 | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | #ifndef DATABASE_HPP_ 22 | #define DATABASE_HPP_ 23 | 24 | #include "common_defs.hpp" 25 | #include "attribute.hpp" 26 | #include "bus_node.hpp" 27 | #include "comment.hpp" 28 | #include "message.hpp" 29 | 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | 38 | namespace AS 39 | { 40 | namespace CAN 41 | { 42 | namespace DbcLoader 43 | { 44 | 45 | class Database 46 | { 47 | public: 48 | Database(const std::string & dbc_path); 49 | Database(std::istream & mem_stream); 50 | Database( 51 | std::string && version, 52 | std::string && bus_config, 53 | std::vector && bus_nodes, 54 | std::unordered_map && messages, 55 | std::vector && attribute_definitions); 56 | 57 | std::string getVersion() const; 58 | std::string getBusConfig() const; 59 | std::vector getBusNodes() const; 60 | std::unordered_map getMessages() const; 61 | std::vector getAttributeDefinitions() const; 62 | void writeDbcToFile(const std::string & dbc_path) const; 63 | void writeDbcToStream(std::ostream & mem_stream) const; 64 | std::unordered_map getTranscoders(); 65 | 66 | private: 67 | std::string version_; 68 | std::string bus_config_; 69 | std::vector bus_nodes_; 70 | std::unordered_map messages_; 71 | std::vector> attribute_defs_; 72 | 73 | void generate(std::ostream & writer) const; 74 | void parse(std::istream & reader); 75 | void saveMsg(std::unique_ptr & msg_ptr); 76 | }; 77 | 78 | } // namespace DbcLoader 79 | } // namespace CAN 80 | } // namespace AS 81 | 82 | #endif 83 | -------------------------------------------------------------------------------- /include/message.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2019 AutonomouStuff, LLC 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 16 | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | #ifndef MESSAGE_HPP_ 22 | #define MESSAGE_HPP_ 23 | 24 | #include "common_defs.hpp" 25 | #include "bus_node.hpp" 26 | #include "comment.hpp" 27 | #include "signal.hpp" 28 | 29 | #include 30 | #include 31 | #include 32 | #include 33 | 34 | namespace AS 35 | { 36 | namespace CAN 37 | { 38 | namespace DbcLoader 39 | { 40 | 41 | class Message 42 | : public DbcObj, public AttrObj 43 | { 44 | public: 45 | Message(std::string && dbc_text); 46 | Message( 47 | unsigned int id, 48 | std::string && name, 49 | unsigned char dlc, 50 | BusNode && transmitting_node, 51 | std::vector && signals); 52 | ~Message() = default; 53 | Message(const Message & other); 54 | Message(Message && other) = default; 55 | Message & operator=(const Message & other); 56 | Message & operator=(Message && other) = default; 57 | 58 | unsigned int getId() const; 59 | std::string getName() const; 60 | unsigned char getDlc() const; 61 | unsigned char getLength() const; 62 | BusNode getTransmittingNode() const; 63 | std::unordered_map getSignals() const; 64 | const std::string * getComment() const; 65 | 66 | static unsigned char dlcToLength(const unsigned char & dlc); 67 | 68 | friend class Database; 69 | friend class MessageTranscoder; 70 | 71 | private: 72 | unsigned int id_; 73 | std::string name_; 74 | unsigned char dlc_; 75 | BusNode transmitting_node_; 76 | std::unordered_map signals_; 77 | std::unique_ptr comment_; 78 | 79 | void generateText() override; 80 | void parse() override; 81 | }; 82 | 83 | class MessageTranscoder 84 | { 85 | public: 86 | MessageTranscoder(Message * dbc_msg); 87 | 88 | const Message * getMessageDef(); 89 | void decode(std::vector && raw_data, TranscodeError * err = nullptr); 90 | std::vector encode(TranscodeError * err = nullptr); 91 | 92 | private: 93 | void decodeRawData(TranscodeError * err); 94 | 95 | Message * msg_def_; 96 | std::vector data_; 97 | std::unordered_map signal_xcoders_; 98 | }; 99 | 100 | } // namespace DbcLoader 101 | } // namespace CAN 102 | } // namespace AS 103 | 104 | #endif // MESSAGE_HPP_ 105 | -------------------------------------------------------------------------------- /include/signal.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2019 AutonomouStuff, LLC 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 16 | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | #ifndef SIGNAL_HPP_ 22 | #define SIGNAL_HPP_ 23 | 24 | #include "common_defs.hpp" 25 | #include "bus_node.hpp" 26 | #include "comment.hpp" 27 | 28 | #include 29 | #include 30 | #include 31 | #include 32 | 33 | namespace AS 34 | { 35 | namespace CAN 36 | { 37 | namespace DbcLoader 38 | { 39 | 40 | class Signal 41 | : public DbcObj, public AttrObj 42 | { 43 | public: 44 | Signal(std::string && dbc_text); 45 | Signal( 46 | std::string && name, 47 | bool is_multiplex_def, 48 | unsigned int multiplex_id, 49 | unsigned char start_bit, 50 | unsigned char length, 51 | Order endianness, 52 | bool is_signed, 53 | float factor, 54 | float offset, 55 | float min, 56 | float max, 57 | std::string && unit, 58 | std::vector && receiving_nodes, 59 | std::map && value_descriptions = 60 | std::map()); 61 | ~Signal() = default; 62 | Signal(const Signal & other); 63 | Signal(Signal && other) = default; 64 | Signal & operator=(const Signal & other); 65 | Signal & operator=(Signal && other) = default; 66 | 67 | std::string getName() const; 68 | bool isMultiplexDef() const; 69 | const unsigned int * getMultiplexId() const; 70 | unsigned char getStartBit() const; 71 | unsigned char getLength() const; 72 | Order getEndianness() const; 73 | bool isSigned() const; 74 | float getFactor() const; 75 | float getOffset() const; 76 | float getMinVal() const; 77 | float getMaxVal() const; 78 | std::string getUnit() const; 79 | std::vector getReceivingNodes() const; 80 | std::map getValueDescriptions() const; 81 | const std::string * getComment() const; 82 | 83 | friend class Database; 84 | friend class Message; 85 | 86 | private: 87 | std::string name_; 88 | bool is_multiplex_def_; 89 | std::unique_ptr multiplex_id_; 90 | unsigned char start_bit_; 91 | unsigned char length_; 92 | Order endianness_; 93 | bool is_signed_; 94 | float factor_; 95 | float offset_; 96 | float min_; 97 | float max_; 98 | std::string unit_; 99 | std::vector receiving_nodes_; 100 | std::map value_descs_; 101 | std::unique_ptr comment_; 102 | 103 | void generateText() override; 104 | void parse() override; 105 | }; 106 | 107 | class SignalTranscoder 108 | { 109 | public: 110 | SignalTranscoder(Signal * dbc_sig); 111 | 112 | private: 113 | Signal * sig_def_; 114 | }; 115 | 116 | } // namespace DbcLoader 117 | } // namespace CAN 118 | } // namespace AS 119 | 120 | #endif // SIGNAL_HPP_ 121 | -------------------------------------------------------------------------------- /src/attribute.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2019 AutonomouStuff, LLC 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 16 | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | #include "common_defs.hpp" 22 | #include "attribute.hpp" 23 | 24 | #include 25 | #include 26 | #include 27 | 28 | namespace AS 29 | { 30 | namespace CAN 31 | { 32 | namespace DbcLoader 33 | { 34 | 35 | // Begin Attribute Base Class 36 | 37 | std::string Attribute::getDefaultValueDbcText() const 38 | { 39 | return default_value_dbc_text_; 40 | } 41 | 42 | std::string Attribute::getName() const 43 | { 44 | return name_; 45 | } 46 | 47 | DbcObjType Attribute::getDbcObjType() const 48 | { 49 | return dbc_obj_type_; 50 | } 51 | 52 | void Attribute::generateText() 53 | { 54 | std::ostringstream output; 55 | 56 | output << "BA_DEF_ "; 57 | 58 | switch (dbc_obj_type_) { 59 | case DbcObjType::BUS_NODES: 60 | output << "BU_ "; 61 | break; 62 | case DbcObjType::MESSAGE: 63 | output << "BO_ "; 64 | break; 65 | case DbcObjType::SIGNAL: 66 | output << "SG_ "; 67 | break; 68 | } 69 | 70 | output << "\"" << name_ << "\" "; 71 | output << generateTypeSpecificText(); 72 | output << ";" << std::endl; 73 | 74 | dbc_text_ = output.str(); 75 | 76 | generateDefaultValueText(); 77 | } 78 | 79 | void Attribute::parse() 80 | { 81 | std::istringstream input(dbc_text_); 82 | std::string temp_string; 83 | 84 | input.ignore(8); 85 | input >> temp_string; 86 | 87 | // Sometimes two spaces between preamble and def 88 | if (temp_string.empty()) { 89 | input >> temp_string; 90 | } 91 | 92 | if (temp_string == "BO_") { 93 | dbc_obj_type_ = DbcObjType::MESSAGE; 94 | } else if (temp_string == "BU_") { 95 | dbc_obj_type_ = DbcObjType::BUS_NODES; 96 | } else if (temp_string == "EV_") { 97 | return; // NOT SUPPORTED 98 | } else if (temp_string == "SG_") { 99 | dbc_obj_type_ = DbcObjType::SIGNAL; 100 | } 101 | 102 | // Attribute name 103 | input >> name_; 104 | // Attribute type 105 | input >> temp_string; 106 | 107 | parseTypeSpecificValues(input); 108 | parseDefaultValue(); 109 | } 110 | 111 | // End Attribute Base Class 112 | // Begin EnumAttribute 113 | 114 | EnumAttribute::EnumAttribute( 115 | std::string && dbc_text, 116 | std::string && default_value_dbc_text) 117 | { 118 | dbc_text_ = dbc_text; 119 | default_value_dbc_text_ = default_value_dbc_text; 120 | parse(); 121 | } 122 | 123 | EnumAttribute::EnumAttribute( 124 | std::string && name, 125 | DbcObjType && dbc_obj_type, 126 | std::vector && enum_values, 127 | std::string * default_value) 128 | : enum_values_(enum_values) 129 | { 130 | name_ = name; 131 | dbc_obj_type_ = dbc_obj_type; 132 | enum_values_ = enum_values; 133 | 134 | if (default_value != nullptr) { 135 | default_value_ = std::make_unique(*default_value); 136 | } else { 137 | default_value_ = nullptr; 138 | } 139 | 140 | generateText(); 141 | } 142 | 143 | EnumAttribute::EnumAttribute(const EnumAttribute & other) 144 | : enum_values_(other.enum_values_) 145 | { 146 | dbc_text_ = other.dbc_text_; 147 | default_value_dbc_text_ = other.default_value_dbc_text_; 148 | name_ = other.name_; 149 | dbc_obj_type_ = other.dbc_obj_type_; 150 | 151 | if (other.default_value_) { 152 | default_value_ = std::make_unique(*(other.default_value_)); 153 | } else { 154 | default_value_ = nullptr; 155 | } 156 | } 157 | 158 | EnumAttribute & EnumAttribute::operator=(const EnumAttribute & other) 159 | { 160 | return *this = EnumAttribute(other); 161 | } 162 | 163 | std::vector EnumAttribute::getEnumValues() const 164 | { 165 | std::vector enum_ptrs_; 166 | 167 | for (const auto & enum_val_ : enum_values_) { 168 | enum_ptrs_.push_back(&enum_val_); 169 | } 170 | 171 | return enum_ptrs_; 172 | } 173 | 174 | const std::string * EnumAttribute::getDefaultValue() const 175 | { 176 | return default_value_.get(); 177 | } 178 | 179 | void EnumAttribute::generateDefaultValueText() 180 | { 181 | if (default_value_ != nullptr) { 182 | std::ostringstream output; 183 | 184 | output << "BA_DEF_DEF_ \"" << name_ << "\" ENUM \""; 185 | output << *default_value_ << "\";" << std::endl; 186 | 187 | default_value_dbc_text_ = output.str(); 188 | } 189 | } 190 | 191 | std::string EnumAttribute::generateTypeSpecificText() 192 | { 193 | std::ostringstream output; 194 | 195 | output << "ENUM "; 196 | 197 | for (const auto & val : enum_values_) { 198 | output << "\"" << val << "\""; 199 | 200 | if (val != enum_values_[enum_values_.size() - 1]) { 201 | output << ","; 202 | } 203 | } 204 | 205 | return output.str(); 206 | } 207 | 208 | void EnumAttribute::parseTypeSpecificValues(std::istringstream & input) 209 | { 210 | std::string temp_string; 211 | std::string enum_val; 212 | 213 | // Get values list 214 | input >> temp_string; 215 | 216 | // Sometimes two spaces between type and values 217 | if (temp_string.empty()) { 218 | input >> temp_string; 219 | } 220 | 221 | auto first_comma = temp_string.find(","); 222 | 223 | if (first_comma != std::string::npos) { 224 | std::istringstream temp_stream(temp_string); 225 | 226 | while (std::getline(temp_stream, enum_val, ',')) { 227 | enum_val = enum_val.substr(1, enum_val.length() - 2); 228 | 229 | // Remove ending semicolon 230 | if (enum_val[enum_val.length() - 1] == ';') { 231 | enum_val = enum_val.substr(0, enum_val.length() - 1); 232 | } 233 | 234 | enum_values_.emplace_back(std::move(enum_val)); 235 | } 236 | } else { 237 | // Remove parentheses and ending semicolon 238 | temp_string = temp_string.substr(1, temp_string.length() - 3); 239 | enum_values_.emplace_back(std::move(temp_string)); 240 | } 241 | } 242 | 243 | void EnumAttribute::parseDefaultValue() 244 | { 245 | if (!default_value_dbc_text_.empty()) { 246 | std::istringstream input(default_value_dbc_text_); 247 | std::string temp_string; 248 | 249 | input.ignore(12); 250 | input >> temp_string; 251 | 252 | // Sometimes 2 spaces between preamble and def 253 | if (temp_string.empty()) { 254 | input >> temp_string; 255 | } 256 | 257 | // Attribute name 258 | input >> temp_string; 259 | // Default value 260 | input >> temp_string; 261 | 262 | default_value_ = std::make_unique(std::move(temp_string)); 263 | } 264 | } 265 | 266 | // End EnumAttribute 267 | // Begin FloatAttribute 268 | 269 | FloatAttribute::FloatAttribute( 270 | std::string && dbc_text, 271 | std::string && default_value_dbc_text) 272 | { 273 | dbc_text_ = dbc_text; 274 | default_value_dbc_text_ = default_value_dbc_text; 275 | parse(); 276 | } 277 | 278 | FloatAttribute::FloatAttribute( 279 | std::string && name, 280 | DbcObjType && dbc_obj_type, 281 | float min, float max, 282 | float * default_value) 283 | : min_(min), max_(max) 284 | { 285 | name_ = std::move(name); 286 | dbc_obj_type_ = dbc_obj_type; 287 | 288 | if (default_value != nullptr) { 289 | default_value_ = std::make_unique(*default_value); 290 | } else { 291 | default_value_ = nullptr; 292 | } 293 | 294 | generateText(); 295 | } 296 | 297 | FloatAttribute::FloatAttribute(const FloatAttribute & other) 298 | : min_(other.min_), max_(other.max_) 299 | { 300 | dbc_text_ = other.dbc_text_; 301 | default_value_dbc_text_ = other.default_value_dbc_text_; 302 | name_ = other.name_; 303 | dbc_obj_type_ = other.dbc_obj_type_; 304 | 305 | if (other.default_value_) { 306 | default_value_ = std::make_unique(*(other.default_value_)); 307 | } else { 308 | default_value_ = nullptr; 309 | } 310 | } 311 | 312 | FloatAttribute & FloatAttribute::operator=(const FloatAttribute & other) 313 | { 314 | return *this = FloatAttribute(other); 315 | } 316 | 317 | float FloatAttribute::getMin() const 318 | { 319 | return min_; 320 | } 321 | 322 | float FloatAttribute::getMax() const 323 | { 324 | return max_; 325 | } 326 | 327 | const float * FloatAttribute::getDefaultValue() const 328 | { 329 | return default_value_.get(); 330 | } 331 | 332 | void FloatAttribute::generateDefaultValueText() 333 | { 334 | if (default_value_ != nullptr) { 335 | std::ostringstream output; 336 | 337 | output << "BA_DEF_DEF_ \"" << name_ << "\" FLOAT "; 338 | output << *default_value_ << ";" << std::endl; 339 | 340 | default_value_dbc_text_ = output.str(); 341 | } 342 | } 343 | 344 | std::string FloatAttribute::generateTypeSpecificText() 345 | { 346 | std::ostringstream output; 347 | 348 | output << "FLOAT " << min_ << " " << max_; 349 | 350 | return output.str(); 351 | } 352 | 353 | void FloatAttribute::parseTypeSpecificValues(std::istringstream & input) 354 | { 355 | std::string temp_string; 356 | input >> temp_string; 357 | 358 | // Sometimes two spaces between type and values 359 | if (temp_string.empty()) { 360 | input >> temp_string; 361 | } 362 | 363 | min_ = std::stof(temp_string); 364 | input >> temp_string; 365 | 366 | // Remove ending semicolon 367 | temp_string = temp_string.substr(0, temp_string.length() - 1); 368 | 369 | max_ = std::stof(temp_string); 370 | } 371 | 372 | void FloatAttribute::parseDefaultValue() 373 | { 374 | if (!default_value_dbc_text_.empty()) { 375 | std::istringstream input(default_value_dbc_text_); 376 | std::string temp_string; 377 | 378 | input.ignore(12); 379 | 380 | input >> temp_string; 381 | 382 | // Sometimes 2 spaces between preamble and def 383 | if (temp_string.empty()) { 384 | input >> temp_string; 385 | } 386 | 387 | // Attribute name 388 | input >> temp_string; 389 | // Default value 390 | input >> temp_string; 391 | 392 | default_value_ = std::make_unique(std::stof(temp_string)); 393 | } 394 | } 395 | 396 | // End FloatAttribute 397 | // Begin IntAttribute 398 | 399 | IntAttribute::IntAttribute( 400 | std::string && dbc_text, 401 | std::string && default_value_dbc_text) 402 | { 403 | dbc_text_ = dbc_text; 404 | default_value_dbc_text_ = default_value_dbc_text; 405 | parse(); 406 | } 407 | 408 | IntAttribute::IntAttribute( 409 | std::string && name, 410 | DbcObjType && dbc_obj_type, 411 | int min, int max, 412 | int * default_value) 413 | : min_(min), max_(max) 414 | { 415 | name_ = name; 416 | dbc_obj_type_ = dbc_obj_type; 417 | 418 | if (default_value != nullptr) { 419 | default_value_ = std::make_unique(*default_value); 420 | } else { 421 | default_value_ = nullptr; 422 | } 423 | 424 | generateText(); 425 | } 426 | 427 | IntAttribute::IntAttribute(const IntAttribute & other) 428 | : min_(other.min_), max_(other.max_) 429 | { 430 | dbc_text_ = other.dbc_text_; 431 | default_value_dbc_text_ = other.default_value_dbc_text_; 432 | name_ = other.name_; 433 | dbc_obj_type_ = other.dbc_obj_type_; 434 | 435 | if (other.default_value_) { 436 | default_value_ = std::make_unique(*(other.default_value_)); 437 | } else { 438 | default_value_ = nullptr; 439 | } 440 | } 441 | 442 | IntAttribute & IntAttribute::operator=(const IntAttribute & other) 443 | { 444 | return *this = IntAttribute(other); 445 | } 446 | 447 | int IntAttribute::getMin() const 448 | { 449 | return min_; 450 | } 451 | 452 | int IntAttribute::getMax() const 453 | { 454 | return max_; 455 | } 456 | 457 | const int * IntAttribute::getDefaultValue() const 458 | { 459 | return default_value_.get(); 460 | } 461 | 462 | void IntAttribute::generateDefaultValueText() 463 | { 464 | if (default_value_ != nullptr) { 465 | std::ostringstream output; 466 | 467 | output << "BA_DEF_DEF_ \"" << name_ << "\" INT "; 468 | output << *default_value_ << ";" << std::endl; 469 | 470 | default_value_dbc_text_ = output.str(); 471 | } 472 | } 473 | 474 | std::string IntAttribute::generateTypeSpecificText() 475 | { 476 | std::ostringstream output; 477 | 478 | output << "INT " << min_ << " " << max_; 479 | 480 | return output.str(); 481 | } 482 | 483 | void IntAttribute::parseTypeSpecificValues(std::istringstream & input) 484 | { 485 | std::string temp_string; 486 | input >> temp_string; 487 | 488 | // Sometimes two spaces between type and values 489 | if (temp_string.empty()) { 490 | input >> temp_string; 491 | } 492 | 493 | min_ = std::stoi(temp_string); 494 | input >> temp_string; 495 | 496 | // Remove ending semicolon 497 | temp_string = temp_string.substr(0, temp_string.length() - 1); 498 | 499 | max_ = std::stoi(temp_string); 500 | } 501 | 502 | void IntAttribute::parseDefaultValue() 503 | { 504 | if (!default_value_dbc_text_.empty()) { 505 | std::istringstream input(default_value_dbc_text_); 506 | std::string temp_string; 507 | 508 | input.ignore(12); 509 | 510 | input >> temp_string; 511 | 512 | // Sometimes 2 spaces between preamble and def 513 | if (temp_string.empty()) { 514 | input >> temp_string; 515 | } 516 | 517 | // Attribute name 518 | input >> temp_string; 519 | // Default value 520 | input >> temp_string; 521 | 522 | default_value_ = std::make_unique(std::stoi(temp_string)); 523 | } 524 | } 525 | 526 | // End IntAttribute 527 | // Begin StringAttribute 528 | 529 | StringAttribute::StringAttribute( 530 | std::string && dbc_text, 531 | std::string && default_value_dbc_text) 532 | { 533 | dbc_text_ = dbc_text; 534 | default_value_dbc_text_ = default_value_dbc_text; 535 | parse(); 536 | } 537 | 538 | StringAttribute::StringAttribute( 539 | std::string && name, 540 | DbcObjType && dbc_obj_type, 541 | std::string * default_value) 542 | { 543 | name_ = name; 544 | dbc_obj_type_ = dbc_obj_type; 545 | 546 | if (default_value != nullptr) { 547 | default_value_ = std::make_unique(*default_value); 548 | } else { 549 | default_value_ = nullptr; 550 | } 551 | 552 | generateText(); 553 | } 554 | 555 | StringAttribute::StringAttribute(const StringAttribute & other) 556 | { 557 | dbc_text_ = other.dbc_text_; 558 | default_value_dbc_text_ = other.default_value_dbc_text_; 559 | name_ = other.name_; 560 | dbc_obj_type_ = other.dbc_obj_type_; 561 | 562 | if (other.default_value_) { 563 | default_value_ = std::make_unique(*(other.default_value_)); 564 | } else { 565 | default_value_ = nullptr; 566 | } 567 | } 568 | 569 | StringAttribute & StringAttribute::operator=(const StringAttribute & other) 570 | { 571 | return *this = StringAttribute(other); 572 | } 573 | 574 | const std::string * StringAttribute::getDefaultValue() const 575 | { 576 | return default_value_.get(); 577 | } 578 | 579 | void StringAttribute::generateDefaultValueText() 580 | { 581 | if (default_value_ != nullptr) { 582 | std::ostringstream output; 583 | 584 | output << "BA_DEF_DEF_ \"" << name_ << "\" \""; 585 | output << *default_value_ << "\";" << std::endl; 586 | 587 | default_value_dbc_text_ = output.str(); 588 | } 589 | } 590 | 591 | std::string StringAttribute::generateTypeSpecificText() 592 | { 593 | return std::string(""); 594 | } 595 | 596 | void StringAttribute::parseTypeSpecificValues(std::istringstream & input) 597 | { 598 | (void)input; 599 | return; 600 | } 601 | 602 | void StringAttribute::parseDefaultValue() 603 | { 604 | if (!default_value_dbc_text_.empty()) { 605 | std::istringstream input(default_value_dbc_text_); 606 | std::string temp_string; 607 | 608 | input.ignore(12); 609 | 610 | input >> temp_string; 611 | 612 | // Sometimes 2 spaces between preamble and def 613 | if (temp_string.empty()) { 614 | input >> temp_string; 615 | } 616 | 617 | // Attribute name 618 | input >> temp_string; 619 | // Default value 620 | input >> temp_string; 621 | 622 | default_value_ = std::make_unique(std::move(temp_string)); 623 | } 624 | } 625 | 626 | // End StringAttribute 627 | 628 | } // namespace DbcLoader 629 | } // namespace CAN 630 | } // namespace AS 631 | -------------------------------------------------------------------------------- /src/bus_node.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2019 AutonomouStuff, LLC 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 16 | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | #include "bus_node.hpp" 22 | 23 | #include 24 | 25 | namespace AS 26 | { 27 | namespace CAN 28 | { 29 | namespace DbcLoader 30 | { 31 | 32 | BusNode::BusNode(std::string && node_name) 33 | : name_(node_name), 34 | comment_(nullptr) 35 | { 36 | } 37 | 38 | BusNode::BusNode(const BusNode & other) 39 | : name_(other.name_) 40 | { 41 | if (comment_) { 42 | comment_ = std::make_unique(*(other.comment_)); 43 | } else { 44 | comment_ = nullptr; 45 | } 46 | } 47 | 48 | BusNode & BusNode::operator=(const BusNode & other) 49 | { 50 | return *this = BusNode(other); 51 | } 52 | 53 | std::string BusNode::getName() const 54 | { 55 | return name_; 56 | } 57 | 58 | const std::string * BusNode::getComment() const 59 | { 60 | return comment_.get(); 61 | } 62 | 63 | } // namespace DbcLoader 64 | } // namespace CAN 65 | } // namespace AS 66 | -------------------------------------------------------------------------------- /src/comment.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2019 AutonomouStuff, LLC 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 16 | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | #include "comment.hpp" 22 | 23 | #include 24 | #include 25 | #include 26 | 27 | namespace AS 28 | { 29 | namespace CAN 30 | { 31 | namespace DbcLoader 32 | { 33 | 34 | std::string Comment::getComment() const 35 | { 36 | return comment_; 37 | } 38 | 39 | BusNodeComment::BusNodeComment(std::string && dbc_text) 40 | { 41 | dbc_text_ = dbc_text; 42 | parse(); 43 | } 44 | 45 | BusNodeComment::BusNodeComment(std::string && node_name, std::string && comment) 46 | : node_name_(node_name) 47 | { 48 | comment_ = comment; 49 | generateText(); 50 | } 51 | 52 | std::string BusNodeComment::getNodeName() const 53 | { 54 | return node_name_; 55 | } 56 | 57 | void BusNodeComment::generateText() 58 | { 59 | std::ostringstream output; 60 | 61 | output << "CM_ BU_ " << node_name_ << " \""; 62 | output << comment_ << "\";" << std::endl; 63 | 64 | dbc_text_ = output.str(); 65 | } 66 | 67 | void BusNodeComment::parse() 68 | { 69 | std::istringstream input(dbc_text_); 70 | 71 | // Ignore the preamble and comment type 72 | input.ignore(8); 73 | input >> node_name_; 74 | 75 | // Comments can contain spaces so we have to look for the semicolon at the end 76 | std::getline(input, comment_, ';'); 77 | 78 | // Remove surrounding parentheses 79 | comment_ = comment_.substr(1, comment_.length() - 2); 80 | } 81 | 82 | MessageComment::MessageComment(std::string && dbc_text) 83 | { 84 | dbc_text_ = dbc_text; 85 | parse(); 86 | } 87 | 88 | MessageComment::MessageComment(unsigned int msg_id, std::string && comment) 89 | : msg_id_(msg_id) 90 | { 91 | comment_ = comment; 92 | generateText(); 93 | } 94 | 95 | unsigned int MessageComment::getMsgId() const 96 | { 97 | return msg_id_; 98 | } 99 | 100 | void MessageComment::generateText() 101 | { 102 | std::ostringstream output; 103 | 104 | output << "CM_ BO_ " << msg_id_ << " \""; 105 | output << comment_ << "\";" << std::endl; 106 | 107 | dbc_text_ = output.str(); 108 | } 109 | 110 | void MessageComment::parse() 111 | { 112 | std::istringstream input(dbc_text_); 113 | 114 | // Ignore the preamble and comment type 115 | input.ignore(8); 116 | input >> msg_id_; 117 | 118 | // Comments can contain spaces so we have to look for the semicolon at the end 119 | std::getline(input, comment_, ';'); 120 | 121 | // Remove surrounding parentheses 122 | comment_ = comment_.substr(1, comment_.length() - 2); 123 | } 124 | 125 | SignalComment::SignalComment(std::string && dbc_text) 126 | { 127 | dbc_text_ = dbc_text; 128 | parse(); 129 | } 130 | 131 | SignalComment::SignalComment( 132 | unsigned int msg_id, 133 | std::string && signal_name, 134 | std::string && comment) 135 | : msg_id_(msg_id), 136 | signal_name_(signal_name) 137 | { 138 | comment_ = comment; 139 | generateText(); 140 | } 141 | 142 | unsigned int SignalComment::getMsgId() const 143 | { 144 | return msg_id_; 145 | } 146 | 147 | std::string SignalComment::getSignalName() const 148 | { 149 | return signal_name_; 150 | } 151 | 152 | void SignalComment::generateText() 153 | { 154 | std::ostringstream output; 155 | 156 | output << "CM_ SG_ " << msg_id_ << " "; 157 | output << signal_name_ << " \""; 158 | output << comment_ << "\";" << std::endl; 159 | 160 | dbc_text_ = output.str(); 161 | } 162 | 163 | void SignalComment::parse() 164 | { 165 | std::istringstream input(dbc_text_); 166 | 167 | // Ignore the preamble and comment type 168 | input.ignore(8); 169 | 170 | input >> msg_id_; 171 | input >> signal_name_; 172 | 173 | // Comments can contain spaces so we have to look for the semicolon at the end 174 | std::getline(input, comment_, ';'); 175 | 176 | // Remove surrounding parentheses 177 | comment_ = comment_.substr(1, comment_.length() - 2); 178 | } 179 | 180 | } // namespace DbcLoader 181 | } // namespace CAN 182 | } // namespace AS 183 | -------------------------------------------------------------------------------- /src/database.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2019 AutonomouStuff, LLC 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 16 | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | #include "database.hpp" 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | 35 | namespace AS 36 | { 37 | namespace CAN 38 | { 39 | namespace DbcLoader 40 | { 41 | 42 | Database::Database(const std::string & dbc_path) 43 | { 44 | std::ifstream file_reader; 45 | file_reader.open(dbc_path); 46 | 47 | if (file_reader.is_open()) { 48 | parse(file_reader); 49 | } else { 50 | throw DbcReadException(); 51 | } 52 | 53 | file_reader.close(); 54 | } 55 | 56 | Database::Database(std::istream & mem_stream) 57 | { 58 | parse(mem_stream); 59 | } 60 | 61 | Database::Database( 62 | std::string && version, 63 | std::string && bus_config, 64 | std::vector && bus_nodes, 65 | std::unordered_map && messages, 66 | std::vector && attribute_definitions) 67 | : version_(version), 68 | bus_config_(bus_config), 69 | bus_nodes_(bus_nodes), 70 | messages_(messages) 71 | { 72 | for (auto & attr : attribute_definitions) { 73 | auto attr_type = attr->getAttrType(); 74 | 75 | if (attr_type == AttributeType::ENUM) { 76 | attribute_defs_.emplace_back(std::move(dynamic_cast(attr))); 77 | } else if (attr_type == AttributeType::FLOAT) { 78 | attribute_defs_.emplace_back(std::move(dynamic_cast(attr))); 79 | } else if (attr_type == AttributeType::INT) { 80 | attribute_defs_.emplace_back(std::move(dynamic_cast(attr))); 81 | } else if (attr_type == AttributeType::STRING) { 82 | attribute_defs_.emplace_back(std::move(dynamic_cast(attr))); 83 | } 84 | } 85 | } 86 | 87 | std::string Database::getVersion() const 88 | { 89 | return version_; 90 | } 91 | 92 | std::string Database::getBusConfig() const 93 | { 94 | return bus_config_; 95 | } 96 | 97 | std::vector Database::getBusNodes() const 98 | { 99 | std::vector nodes; 100 | 101 | for (auto & node : bus_nodes_) { 102 | nodes.emplace_back(&node); 103 | } 104 | 105 | return nodes; 106 | } 107 | 108 | std::unordered_map Database::getMessages() const 109 | { 110 | std::unordered_map msgs; 111 | 112 | for (auto & msg : messages_) { 113 | msgs[msg.first] = &(msg.second); 114 | } 115 | 116 | return msgs; 117 | } 118 | 119 | std::vector Database::getAttributeDefinitions() const 120 | { 121 | std::vector temp_attr_defs; 122 | 123 | for (auto & attr : attribute_defs_) { 124 | auto attr_type = attr->getAttrType(); 125 | 126 | switch (attr_type) { 127 | case AttributeType::ENUM: 128 | { 129 | auto enum_ptr = dynamic_cast(attr.get()); 130 | temp_attr_defs.emplace_back(std::move(enum_ptr)); 131 | } break; 132 | case AttributeType::FLOAT: 133 | { 134 | auto float_ptr = dynamic_cast(attr.get()); 135 | temp_attr_defs.emplace_back(std::move(float_ptr)); 136 | } break; 137 | case AttributeType::INT: 138 | { 139 | auto int_ptr = dynamic_cast(attr.get()); 140 | temp_attr_defs.emplace_back(std::move(int_ptr)); 141 | } break; 142 | case AttributeType::STRING: 143 | { 144 | auto str_ptr = dynamic_cast(attr.get()); 145 | temp_attr_defs.emplace_back(std::move(str_ptr)); 146 | } break; 147 | } 148 | } 149 | 150 | return temp_attr_defs; 151 | } 152 | 153 | void Database::writeDbcToFile(const std::string & dbc_path) const 154 | { 155 | std::ofstream file_writer; 156 | file_writer.open(dbc_path); 157 | 158 | if (file_writer.is_open()) { 159 | generate(file_writer); 160 | } else { 161 | throw DbcWriteException(); 162 | } 163 | 164 | file_writer.close(); 165 | } 166 | 167 | void Database::writeDbcToStream(std::ostream & mem_stream) const 168 | { 169 | generate(mem_stream); 170 | } 171 | 172 | std::unordered_map Database::getTranscoders() 173 | { 174 | std::unordered_map xcoders; 175 | 176 | for (auto msg = messages_.begin(); msg != messages_.end(); ++msg) { 177 | xcoders.emplace(msg->first, &(msg->second)); 178 | } 179 | 180 | return xcoders; 181 | } 182 | 183 | void Database::generate(std::ostream & output) const 184 | { 185 | std::vector bus_node_comments; 186 | std::vector message_comments; 187 | std::vector signal_comments; 188 | 189 | output << "VERSION \"" << version_ << "\"\n\n\n"; 190 | output << "NS_ :\n"; 191 | output << "\tNS_DESC_\n"; 192 | output << "\tCM_\n"; 193 | output << "\tBA_DEF_\n"; 194 | output << "\tBA_\n"; 195 | output << "\tVAL_\n"; 196 | output << "\tCAT_DEF_\n"; 197 | output << "\tCAT_\n"; 198 | output << "\tFILTER\n"; 199 | output << "\tBA_DEF_DEF_\n"; 200 | output << "\tEV_DATA_\n"; 201 | output << "\tENVVAR_DATA_\n"; 202 | output << "\tSGTYPE_\n"; 203 | output << "\tSGTYPE_VAL_\n"; 204 | output << "\tBA_DEF_SGTYPE_\n"; 205 | output << "\tBA_SGTYPE_\n"; 206 | output << "\tSIG_TYPE_REF_\n"; 207 | output << "\tVAL_TABLE_\n"; 208 | output << "\tSIG_GROUP_\n"; 209 | output << "\tSIG_VALTYPE_\n"; 210 | output << "\tSIGTYPE_VALTYPE_\n"; 211 | output << "\tBO_TX_BU_\n"; 212 | output << "\tBA_DEF_REL_\n"; 213 | output << "\tBA_REL_\n"; 214 | output << "\tBA_DEF_DEF_REL_\n"; 215 | output << "\tBU_SG_REL_\n"; 216 | output << "\tBU_EV_REL_\n"; 217 | output << "\tBU_BO_REL_\n"; 218 | output << "\tSG_MUL_VAL_\n" << std::endl; 219 | output << "BS_: " << bus_config_ << "\n\n"; 220 | output << "BU_: "; 221 | 222 | for (auto i = 0; i < bus_nodes_.size(); ++i) { 223 | output << bus_nodes_[i].name_; 224 | 225 | if (bus_nodes_[i].comment_ != nullptr) { 226 | std::string comment = *(bus_nodes_[i].getComment()); 227 | bus_node_comments.emplace_back( 228 | bus_nodes_[i].getName(), 229 | std::move(comment)); 230 | } 231 | 232 | if (i != bus_nodes_.size() - 1) { 233 | output << ","; 234 | } 235 | } 236 | 237 | output << "\n\n" << std::endl; 238 | 239 | for (auto & msg : messages_) { 240 | output << msg.second.dbc_text_; 241 | 242 | if (msg.second.comment_ != nullptr) { 243 | std::string comment = *(msg.second.getComment()); 244 | message_comments.emplace_back( 245 | msg.second.getId(), 246 | std::move(comment)); 247 | } 248 | 249 | for (auto & sig : msg.second.signals_) { 250 | if (sig.second.comment_ != nullptr) { 251 | std::string comment = *(sig.second.getComment()); 252 | signal_comments.emplace_back( 253 | msg.second.getId(), 254 | sig.second.getName(), 255 | std::move(comment)); 256 | } 257 | 258 | output << sig.second.dbc_text_; 259 | } 260 | 261 | output << std::endl; 262 | } 263 | 264 | for (auto & comment : bus_node_comments) { 265 | output << comment.dbc_text_; 266 | } 267 | 268 | for (auto & comment : message_comments) { 269 | output << comment.dbc_text_; 270 | } 271 | 272 | for (auto & comment : signal_comments) { 273 | output << comment.dbc_text_; 274 | } 275 | 276 | // TODO(jwhitleyastuff): Write out attribute defs 277 | // TODO(jwhitleyastuff): Write out attribute default values 278 | // TODO(jwhitleyastuff): Write out attribute values 279 | // TODO(jwhitleyastuff): Write out signal value lists 280 | } 281 | 282 | void Database::parse(std::istream & reader) 283 | { 284 | std::string line; 285 | bool version_found = false; 286 | bool bus_config_found = false; 287 | bool bus_nodes_found = false; 288 | std::unique_ptr current_msg(nullptr); 289 | std::vector bus_node_comments; 290 | std::vector message_comments; 291 | std::vector signal_comments; 292 | std::unordered_map> attr_texts; 293 | std::unordered_map attr_def_val_texts; 294 | 295 | while (std::getline(reader, line)) { 296 | // Ignore empty lines and lines starting with tab 297 | if (!line.empty() && line.rfind("\t") != 0) { 298 | std::istringstream iss_line(line); 299 | std::string preamble; 300 | 301 | iss_line >> preamble; 302 | 303 | if (!version_found && preamble == PREAMBLES[0]) { // VERSION 304 | iss_line >> version_; 305 | 306 | // Remove parentheses 307 | version_ = version_.substr(1, version_.length() - 2); 308 | version_found = true; 309 | } else if (!bus_config_found && preamble == PREAMBLES[1]) { // BUS CONFIG 310 | iss_line >> bus_config_; 311 | bus_config_found = true; 312 | } else if (!bus_nodes_found && preamble == PREAMBLES[2]) { // BUS NODES 313 | std::string node; 314 | 315 | // Get everything after 'BU_: ' and split by spaces 316 | while (iss_line >> node) { 317 | bus_nodes_.emplace_back(std::move(node)); 318 | } 319 | 320 | bus_nodes_found = true; 321 | } else if (preamble == PREAMBLES[3]) { // MESSAGE 322 | saveMsg(current_msg); 323 | 324 | // Create new message 325 | current_msg = std::unique_ptr(new Message(std::move(line))); 326 | } else if (preamble == PREAMBLES[4]) { // SIGNAL 327 | if (current_msg) { 328 | // Signal found and current message is active 329 | // Add signal to existing message 330 | Signal temp_sig(std::move(line)); 331 | current_msg->signals_.emplace(std::make_pair(temp_sig.getName(), std::move(temp_sig))); 332 | } else { 333 | throw DbcParseException(); 334 | } 335 | } else if (preamble == PREAMBLES[5]) { // COMMENT 336 | saveMsg(current_msg); 337 | 338 | // Comments can only be added to their associated 339 | // database objects after the rest of the DBC has been parsed. 340 | // This is why they are stored in separate vectors here. 341 | std::string desc_type; 342 | iss_line >> desc_type; 343 | 344 | if (desc_type == "BU_") { // BUS NODE COMMENT 345 | bus_node_comments.emplace_back(std::move(line)); 346 | } else if (desc_type == PREAMBLES[3]) { // MESSAGE COMMENT 347 | message_comments.emplace_back(std::move(line)); 348 | } else if (desc_type == PREAMBLES[4]) { // SIGNAL COMMENT 349 | signal_comments.emplace_back(std::move(line)); 350 | } 351 | } else if (preamble == PREAMBLES[6]) { // SIGNAL VALUE LIST 352 | saveMsg(current_msg); 353 | 354 | std::map value_descs; 355 | 356 | std::string temp_string; 357 | std::string sig_name; 358 | 359 | // Message ID 360 | iss_line >> temp_string; 361 | 362 | unsigned int id = std::stoul(temp_string); 363 | 364 | // Signal Name 365 | iss_line >> sig_name; 366 | 367 | // Get all remaining values up to the ending semicolon 368 | std::getline(iss_line, temp_string, ';'); 369 | 370 | // TODO(jwhitleyastuff): Finish parsing values 371 | } else if (preamble == PREAMBLES[7]) { // ATTRIBUTE DEFINITION 372 | saveMsg(current_msg); 373 | 374 | std::string attr_name, temp_type; 375 | AttributeType attr_type; 376 | iss_line.ignore(4); 377 | iss_line >> attr_name; 378 | 379 | // Sometimes two spaces between preamble and name 380 | if (attr_name.empty()) { 381 | iss_line >> attr_name; 382 | } 383 | 384 | iss_line >> temp_type; 385 | 386 | if (temp_type == "ENUM") { 387 | attr_type = AttributeType::ENUM; 388 | } else if (temp_type == "FLOAT") { 389 | attr_type = AttributeType::FLOAT; 390 | } else if (temp_type == "HEX" || temp_type == "INT") { 391 | attr_type = AttributeType::INT; 392 | } else if (temp_type.rfind("STRING", 0) == 0) { 393 | attr_type = AttributeType::STRING; 394 | } 395 | 396 | attr_texts[attr_name] = std::make_pair(attr_type, std::move(line)); 397 | } else if (preamble == PREAMBLES[8]) { // ATTRIBUTE DEFAULT VALUE 398 | saveMsg(current_msg); 399 | 400 | std::string attr_name; 401 | iss_line >> attr_name; 402 | 403 | // Sometimes two spaces between preamble and name 404 | if (attr_name.empty()) { 405 | iss_line >> attr_name; 406 | } 407 | 408 | attr_def_val_texts[attr_name] = std::move(line); 409 | } else if (preamble == PREAMBLES[9]) { // ATTRIBUTE VALUE 410 | saveMsg(current_msg); 411 | } 412 | } 413 | } 414 | 415 | // Just in case we still have a message open 416 | saveMsg(current_msg); 417 | 418 | // Add bus node comments 419 | for (auto & bus_node_comment : bus_node_comments) { 420 | for (auto & bus_node : bus_nodes_) { 421 | if (bus_node.name_ == bus_node_comment.getNodeName()) { 422 | bus_node.comment_ = std::make_unique(std::move(bus_node_comment.comment_)); 423 | } 424 | } 425 | } 426 | 427 | // Add message comments 428 | for (auto & message_comment : message_comments) { 429 | auto msg_itr = messages_.find(message_comment.getMsgId()); 430 | 431 | if (msg_itr != messages_.end()) { 432 | msg_itr->second.comment_ = std::make_unique(std::move(message_comment.comment_)); 433 | } 434 | } 435 | 436 | // Add signal comments 437 | for (auto & signal_comment : signal_comments) { 438 | auto msg_itr = messages_.find(signal_comment.getMsgId()); 439 | 440 | if (msg_itr != messages_.end()) { 441 | auto signal_itr = msg_itr->second.signals_.find(signal_comment.getSignalName()); 442 | 443 | if (signal_itr != msg_itr->second.signals_.end()) { 444 | signal_itr->second.comment_ = std::make_unique(std::move(signal_comment.comment_)); 445 | } 446 | } 447 | } 448 | 449 | // Add attribute definitions 450 | for (auto & attr : attr_texts) { 451 | auto found_def_val = attr_def_val_texts.find(attr.first); 452 | 453 | std::string dbc_text = std::move(attr.second.second); 454 | std::string def_val_dbc_text = ""; 455 | 456 | if (found_def_val != attr_def_val_texts.end()) { 457 | def_val_dbc_text = std::move(found_def_val->second); 458 | } 459 | 460 | switch (attr.second.first) { 461 | case AttributeType::ENUM: 462 | { 463 | EnumAttribute enum_attr(std::move(dbc_text), std::move(def_val_dbc_text)); 464 | std::unique_ptr temp_attr = std::make_unique(enum_attr); 465 | attribute_defs_.push_back(std::move(temp_attr)); 466 | } break; 467 | case AttributeType::FLOAT: 468 | { 469 | FloatAttribute float_attr(std::move(dbc_text), std::move(def_val_dbc_text)); 470 | std::unique_ptr temp_attr = std::make_unique(float_attr); 471 | attribute_defs_.push_back(std::move(temp_attr)); 472 | } break; 473 | case AttributeType::INT: 474 | { 475 | IntAttribute int_attr(std::move(dbc_text), std::move(def_val_dbc_text)); 476 | std::unique_ptr temp_attr = std::make_unique(int_attr); 477 | attribute_defs_.push_back(std::move(temp_attr)); 478 | } break; 479 | case AttributeType::STRING: 480 | { 481 | StringAttribute str_attr(std::move(dbc_text), std::move(def_val_dbc_text)); 482 | std::unique_ptr temp_attr = std::make_unique(str_attr); 483 | attribute_defs_.push_back(std::move(temp_attr)); 484 | } break; 485 | } 486 | } 487 | 488 | // TODO(jwhitleyastuff): Apply attributes to DB objects 489 | 490 | // TODO(jwhitleyastuff): Add signal value description lists to signals 491 | } 492 | 493 | void Database::saveMsg(std::unique_ptr & msg_ptr) 494 | { 495 | if (msg_ptr) { 496 | unsigned int id = msg_ptr->getId(); 497 | 498 | // Some diagnostic messages are created by Vector tools 499 | // with CAN IDs > 29 bits. Don't add them. 500 | if (id <= MAX_CAN_ID) { 501 | messages_.emplace(id, std::move(*(msg_ptr.release()))); 502 | } 503 | } 504 | } 505 | 506 | } // namespace DbcLoader 507 | } // namespace CAN 508 | } // namespace AS 509 | -------------------------------------------------------------------------------- /src/message.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2019 AutonomouStuff, LLC 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 16 | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | #include "message.hpp" 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | namespace AS 29 | { 30 | namespace CAN 31 | { 32 | namespace DbcLoader 33 | { 34 | 35 | Message::Message(std::string && message_text) 36 | : transmitting_node_(BusNode("")), 37 | comment_(nullptr) 38 | { 39 | dbc_text_ = std::move(message_text); 40 | parse(); 41 | } 42 | 43 | Message::Message( 44 | unsigned int id, 45 | std::string && name, 46 | unsigned char dlc, 47 | BusNode && transmitting_node, 48 | std::vector && signals) 49 | : id_(id), 50 | name_(name), 51 | dlc_(dlc), 52 | transmitting_node_(transmitting_node), 53 | comment_(nullptr) 54 | { 55 | for (auto & signal : signals) { 56 | signals_.emplace(std::make_pair(signal.getName(), std::move(signal))); 57 | } 58 | 59 | generateText(); 60 | } 61 | 62 | Message::Message(const Message & other) 63 | : id_(other.id_), 64 | name_(other.name_), 65 | dlc_(other.dlc_), 66 | transmitting_node_(other.transmitting_node_), 67 | signals_(other.signals_) 68 | { 69 | if (other.comment_) { 70 | comment_ = std::make_unique(*(other.comment_)); 71 | } else { 72 | comment_ = nullptr; 73 | } 74 | } 75 | 76 | Message & Message::operator=(const Message & other) 77 | { 78 | return *this = Message(other); 79 | } 80 | 81 | unsigned int Message::getId() const 82 | { 83 | return id_; 84 | } 85 | 86 | std::string Message::getName() const 87 | { 88 | return name_; 89 | } 90 | 91 | unsigned char Message::getDlc() const 92 | { 93 | return dlc_; 94 | } 95 | 96 | unsigned char Message::getLength() const 97 | { 98 | return dlcToLength(dlc_); 99 | } 100 | 101 | BusNode Message::getTransmittingNode() const 102 | { 103 | return BusNode(transmitting_node_); 104 | } 105 | 106 | std::unordered_map Message::getSignals() const 107 | { 108 | std::unordered_map sigs; 109 | 110 | for (auto & sig : signals_) { 111 | sigs[sig.first] = &(sig.second); 112 | } 113 | 114 | return sigs; 115 | } 116 | 117 | const std::string * Message::getComment() const 118 | { 119 | return comment_.get(); 120 | } 121 | 122 | void Message::generateText() 123 | { 124 | std::ostringstream output; 125 | 126 | output << "BO_ " << id_ << " "; 127 | output << name_ << ": "; 128 | output << dlc_ << " "; 129 | output << transmitting_node_.name_; 130 | output << std::endl; 131 | 132 | dbc_text_ = output.str(); 133 | } 134 | 135 | void Message::parse() 136 | { 137 | std::istringstream input(dbc_text_); 138 | 139 | input.ignore(4); 140 | input >> id_; 141 | input >> name_; 142 | input >> dlc_; 143 | input >> transmitting_node_.name_; 144 | 145 | // Remove colon after name 146 | name_ = name_.substr(0, name_.length() - 1); 147 | } 148 | 149 | unsigned char Message::dlcToLength(const unsigned char & dlc) 150 | { 151 | return DLC_LENGTH[dlc]; 152 | } 153 | 154 | MessageTranscoder::MessageTranscoder(Message * dbc_msg) 155 | : msg_def_(dbc_msg), 156 | data_() 157 | { 158 | data_.assign(Message::dlcToLength(dbc_msg->getDlc()), 0); 159 | 160 | for (auto sig = msg_def_->signals_.begin(); sig != msg_def_->signals_.end(); ++sig) { 161 | signal_xcoders_.emplace(sig->first, &(sig->second)); 162 | } 163 | } 164 | 165 | const Message * MessageTranscoder::getMessageDef() 166 | { 167 | return msg_def_; 168 | } 169 | 170 | void MessageTranscoder::decode(std::vector && raw_data, TranscodeError * err) 171 | { 172 | data_ = std::move(raw_data); 173 | decodeRawData(err); 174 | } 175 | 176 | void MessageTranscoder::decodeRawData(TranscodeError * err) 177 | { 178 | err = new TranscodeError(TranscodeErrorType::NONE, ""); 179 | 180 | // TODO(jwhitleyastuff): Do the thing. 181 | } 182 | 183 | std::vector MessageTranscoder::encode(TranscodeError * err) 184 | { 185 | return std::vector(data_.begin(), data_.end()); 186 | } 187 | 188 | } // namespace DbcLoader 189 | } // namespace CAN 190 | } // namespace AS 191 | -------------------------------------------------------------------------------- /src/signal.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2019 AutonomouStuff, LLC 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 16 | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | #include "signal.hpp" 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | namespace AS 30 | { 31 | namespace CAN 32 | { 33 | namespace DbcLoader 34 | { 35 | 36 | Signal::Signal(std::string && dbc_text) 37 | { 38 | dbc_text_ = std::move(dbc_text); 39 | parse(); 40 | } 41 | 42 | Signal::Signal( 43 | std::string && name, 44 | bool is_multiplex_def, 45 | unsigned int multiplex_id, 46 | unsigned char start_bit, 47 | unsigned char length, 48 | Order endianness, 49 | bool is_signed, 50 | float factor, 51 | float offset, 52 | float min, 53 | float max, 54 | std::string && unit, 55 | std::vector && receiving_nodes, 56 | std::map && value_descriptions) 57 | : name_(name), 58 | is_multiplex_def_(is_multiplex_def), 59 | multiplex_id_(new unsigned int(multiplex_id)), 60 | start_bit_(start_bit), 61 | length_(length), 62 | endianness_(endianness), 63 | is_signed_(is_signed), 64 | factor_(factor), 65 | offset_(offset), 66 | min_(min), 67 | max_(max), 68 | unit_(unit), 69 | receiving_nodes_(receiving_nodes), 70 | value_descs_(value_descriptions), 71 | comment_(nullptr) 72 | { 73 | generateText(); 74 | } 75 | 76 | Signal::Signal(const Signal & other) 77 | : name_(other.name_), 78 | is_multiplex_def_(other.is_multiplex_def_), 79 | start_bit_(other.start_bit_), 80 | length_(other.length_), 81 | endianness_(other.endianness_), 82 | is_signed_(other.is_signed_), 83 | factor_(other.factor_), 84 | offset_(other.offset_), 85 | min_(other.min_), 86 | max_(other.max_), 87 | unit_(other.unit_), 88 | receiving_nodes_(other.receiving_nodes_), 89 | value_descs_(other.value_descs_) 90 | { 91 | if (other.multiplex_id_) { 92 | multiplex_id_ = std::make_unique(*(other.multiplex_id_)); 93 | } else { 94 | multiplex_id_ = nullptr; 95 | } 96 | 97 | if (other.comment_) { 98 | comment_ = std::make_unique(*(other.comment_)); 99 | } else { 100 | comment_ = nullptr; 101 | } 102 | } 103 | 104 | Signal & Signal::operator=(const Signal & other) 105 | { 106 | return *this = Signal(other); 107 | } 108 | 109 | std::string Signal::getName() const 110 | { 111 | return name_; 112 | } 113 | 114 | bool Signal::isMultiplexDef() const 115 | { 116 | return is_multiplex_def_; 117 | } 118 | 119 | const unsigned int * Signal::getMultiplexId() const 120 | { 121 | return multiplex_id_.get(); 122 | } 123 | 124 | unsigned char Signal::getStartBit() const 125 | { 126 | return start_bit_; 127 | } 128 | 129 | unsigned char Signal::getLength() const 130 | { 131 | return length_; 132 | } 133 | 134 | Order Signal::getEndianness() const 135 | { 136 | return endianness_; 137 | } 138 | 139 | bool Signal::isSigned() const 140 | { 141 | return is_signed_; 142 | } 143 | 144 | float Signal::getFactor() const 145 | { 146 | return factor_; 147 | } 148 | 149 | float Signal::getOffset() const 150 | { 151 | return offset_; 152 | } 153 | 154 | float Signal::getMinVal() const 155 | { 156 | return min_; 157 | } 158 | 159 | float Signal::getMaxVal() const 160 | { 161 | return max_; 162 | } 163 | 164 | std::string Signal::getUnit() const 165 | { 166 | return unit_; 167 | } 168 | 169 | std::vector Signal::getReceivingNodes() const 170 | { 171 | std::vector nodes; 172 | 173 | for (auto & node : receiving_nodes_) { 174 | nodes.push_back(&node); 175 | } 176 | 177 | return nodes; 178 | } 179 | 180 | std::map Signal::getValueDescriptions() const 181 | { 182 | std::map descs; 183 | 184 | for (auto & desc : value_descs_) { 185 | descs[desc.first] = &(desc.second); 186 | } 187 | 188 | return descs; 189 | } 190 | 191 | const std::string * Signal::getComment() const 192 | { 193 | return comment_.get(); 194 | } 195 | 196 | void Signal::generateText() 197 | { 198 | std::ostringstream output; 199 | 200 | output << " SG_ " << name_; 201 | 202 | if (is_multiplex_def_) { 203 | output << " M"; 204 | } else if (multiplex_id_) { 205 | output << " m" << *multiplex_id_; 206 | } 207 | 208 | output << " : " << start_bit_ << "|"; 209 | output << length_ << "@"; 210 | 211 | if (endianness_ == Order::LE) { 212 | output << 1; 213 | } else { 214 | output << 0; 215 | } 216 | 217 | if (is_signed_) { 218 | output << "-"; 219 | } else { 220 | output << "+"; 221 | } 222 | 223 | output << " (" << factor_ << ","; 224 | output << offset_ << ") ["; 225 | output << min_ << "|" << max_ << "] \""; 226 | output << unit_ << "\" "; 227 | 228 | if (receiving_nodes_.size() < 1) { 229 | output << "Vector__XXX"; 230 | } else { 231 | for (auto i = 0; i < receiving_nodes_.size(); ++i) { 232 | output << receiving_nodes_[i].name_; 233 | 234 | if (i != receiving_nodes_.size() - 1) { 235 | output << ","; 236 | } 237 | } 238 | } 239 | 240 | output << std::endl; 241 | 242 | dbc_text_ = output.str(); 243 | } 244 | 245 | void Signal::parse() 246 | { 247 | std::istringstream input(dbc_text_); 248 | std::string temp_string; 249 | 250 | input.ignore(5); 251 | input >> name_; 252 | input >> temp_string; 253 | 254 | if (temp_string != ":") { 255 | if (temp_string == "M") { 256 | is_multiplex_def_ = true; 257 | } else { 258 | // Assumed to be multiplex identifier 259 | multiplex_id_ = std::make_unique( 260 | static_cast( 261 | std::stoul( 262 | temp_string.substr(1, temp_string.length() - 1)))); 263 | } 264 | 265 | input.ignore(3); 266 | } 267 | 268 | input >> temp_string; 269 | 270 | auto bar = temp_string.find("|"); 271 | auto at = temp_string.find("@"); 272 | 273 | if (bar != std::string::npos && at != std::string::npos) { 274 | start_bit_ = static_cast(std::stoul(temp_string.substr(0, bar))); 275 | length_ = static_cast(std::stoul(temp_string.substr(bar + 1, at - bar - 1))); 276 | 277 | if (temp_string[at + 1] == '0') { 278 | endianness_ = Order::BE; 279 | } else if (temp_string[at + 1] == '1') { 280 | endianness_ = Order::LE; 281 | } else { 282 | throw DbcParseException(); 283 | } 284 | 285 | if (temp_string[at + 2] == '+') { 286 | is_signed_ = false; 287 | } else if (temp_string[at + 2] == '-') { 288 | is_signed_ = true; 289 | } else { 290 | throw DbcParseException(); 291 | } 292 | } else { 293 | throw DbcParseException(); 294 | } 295 | 296 | input >> temp_string; 297 | 298 | auto comma = temp_string.find(","); 299 | 300 | if (comma != std::string::npos) { 301 | factor_ = std::stof(temp_string.substr(1, comma - 1)); 302 | offset_ = std::stof(temp_string.substr(comma + 1, temp_string.length() - comma - 2)); 303 | } else { 304 | throw DbcParseException(); 305 | } 306 | 307 | input >> temp_string; 308 | 309 | bar = temp_string.find("|"); 310 | 311 | if (bar != std::string::npos) { 312 | min_ = std::stof(temp_string.substr(1, bar - 1)); 313 | max_ = std::stof(temp_string.substr(bar + 1, temp_string.length() - bar - 2)); 314 | } else { 315 | throw DbcParseException(); 316 | } 317 | 318 | input >> temp_string; 319 | 320 | if (temp_string.length() > 3) { 321 | unit_ = temp_string.substr(1, temp_string.length() - 2); 322 | } 323 | 324 | input >> temp_string; 325 | 326 | if (temp_string.empty()) { 327 | // There are sometimes 2 spaces after the unit 328 | input >> temp_string; 329 | } 330 | 331 | auto first_comma = temp_string.find(","); 332 | 333 | if (first_comma != std::string::npos) { 334 | while (std::getline(input, temp_string, ',')) { 335 | if (temp_string != "Vector__XXX") { 336 | receiving_nodes_.emplace_back(std::move(temp_string)); 337 | } 338 | } 339 | } else { 340 | receiving_nodes_.emplace_back(std::move(temp_string)); 341 | } 342 | } 343 | 344 | SignalTranscoder::SignalTranscoder(Signal * dbc_sig) 345 | : sig_def_(dbc_sig) 346 | { 347 | } 348 | 349 | } // namespace DbcLoader 350 | } // namespace CAN 351 | } // namespace AS 352 | --------------------------------------------------------------------------------