Permalink
Show file tree
Hide file tree
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Showing
9 changed files
with
635 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -9,3 +9,7 @@ install_manifest.txt | ||
compile_commands.json | ||
CTestTestfile.cmake | ||
_deps | ||
|
||
bin/ | ||
src_autogen/ | ||
lib/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
cmake_minimum_required(VERSION 3.0) | ||
set(CMAKE_CXX_STANDARD 17) | ||
|
||
project(dbc_example C CXX) | ||
|
||
# location of source code files | ||
include_directories( include ) | ||
|
||
# tell cmake where to put the executables that it creates | ||
file( MAKE_DIRECTORY bin ) | ||
set( CMAKE_RUNTIME_OUTPUT_DIRECTORY bin ) | ||
|
||
# where to put the object files it creates | ||
file( MAKE_DIRECTORY lib ) | ||
SET( LIBRARY_OUTPUT_PATH lib ) | ||
|
||
# autogenerate code from the DBC file | ||
file( MAKE_DIRECTORY src_autogen ) | ||
add_custom_command( OUTPUT src_autogen/data.h src_autogen/data.c | ||
COMMAND python3 -m cantools generate_c_source data.dbc -o src_autogen | ||
MAIN_DEPENDENCY data.dbc | ||
COMMENT "Autogenerate code from DBC file" ) | ||
|
||
# create shared library of the autogenerated code from the DBC file | ||
add_library( data SHARED src_autogen/data.c ) | ||
target_include_directories( data PUBLIC src_autogen ) | ||
|
||
add_executable( demo_dbc src/demo_dbc.cpp ) | ||
target_link_libraries( demo_dbc PRIVATE data ) | ||
|
||
add_executable( demo src/demo.cpp ) | ||
|
||
add_executable( demo_raw_decode src/demo_raw_decode.cpp ) | ||
|
||
add_executable( demo_send src/demo_send.cpp ) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
VERSION "" | ||
|
||
|
||
NS_ : | ||
NS_DESC_ | ||
CM_ | ||
BA_DEF_ | ||
BA_ | ||
VAL_ | ||
CAT_DEF_ | ||
CAT_ | ||
FILTER | ||
BA_DEF_DEF_ | ||
EV_DATA_ | ||
ENVVAR_DATA_ | ||
SGTYPE_ | ||
SGTYPE_VAL_ | ||
BA_DEF_SGTYPE_ | ||
BA_SGTYPE_ | ||
SIG_TYPE_REF_ | ||
VAL_TABLE_ | ||
SIG_GROUP_ | ||
SIG_VALTYPE_ | ||
SIGTYPE_VALTYPE_ | ||
BO_TX_BU_ | ||
BA_DEF_REL_ | ||
BA_REL_ | ||
BA_DEF_DEF_REL_ | ||
BU_SG_REL_ | ||
BU_EV_REL_ | ||
BU_BO_REL_ | ||
SG_MUL_VAL_ | ||
|
||
BS_: | ||
|
||
BU_: Auto VCU | ||
BU_: Auto DASH | ||
|
||
BO_ 392 indicator_control: 4 DASH | ||
SG_ Right_indicator : 1|1@1+ (1,0) [0|1] "" Vector__XXX | ||
SG_ Left_indicator : 0|1@1+ (1,0) [0|1] "" Vector__XXX | ||
|
||
VAL_ 392 Right_indicator 0 "OFF" 1 "ON"; | ||
VAL_ 392 Left_indicator 0 "OFF" 1 "ON"; | ||
|
||
BO_ 580 speed: 5 ECU | ||
SG_ Speed : 31|16@0+ (1,0) [0|48280] "dam/h" Vector__XXX | ||
|
||
CM_ "SG_ Speed : 31|16@0+ (1,0) [0|48280] \"dam/h\" Vector__XXX | ||
Is an example using decameters per hour. This is the format of the raw | ||
data actually sent over the CAN bus. | ||
Dam/h is not, however, a commonly used unit of measurement and so the | ||
following message specification might be preferable. The scale factor | ||
is used to adjust the raw values. | ||
SG_ Speed : 31|16@0+ (0.01,0) [0|482.8] \"km/h\" Vector__XXX"; | ||
|
||
|
||
BA_DEF_ "BusType" STRING ; | ||
BA_DEF_DEF_ "BusType" "CAN"; | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,193 @@ | ||
#ifndef CAN_WRAP_H | ||
#define CAN_WRAP_H | ||
|
||
#include <net/if.h> | ||
#include <sys/ioctl.h> | ||
#include <sys/socket.h> | ||
#include <unistd.h> | ||
|
||
#include <linux/can.h> | ||
#include <linux/can/raw.h> | ||
|
||
#include <cstring> | ||
#include <iomanip> | ||
#include <iostream> | ||
#include <stdexcept> | ||
|
||
namespace can | ||
{ | ||
/** | ||
* @brief Opens socket for CAN bus communication via socketcan. | ||
* Returns socket identifier which is used as an argument for | ||
* future can::read(), can::write() and can::close() calls. | ||
* | ||
* @throws std::runtime_error If socket creation failed. | ||
* @throws std::runtime_error If could not enable CANFD. | ||
* @throws std::runtime_error If could not bind socket. | ||
* | ||
* @param fd Open as normal CAN or CANFD. | ||
* @param channel Network channel to use, e.g. can0 or vcan0. | ||
* @return const int Socket identifier. | ||
*/ | ||
const int _connect( const bool fd, const std::string& channel ) | ||
{ | ||
const int canSocket = socket( PF_CAN, SOCK_RAW, CAN_RAW ); | ||
if( canSocket < 0 ) | ||
throw std::runtime_error( "Create socket failed" ); | ||
|
||
struct ifreq ifr; | ||
std::strncpy( ifr.ifr_name, channel.c_str(), sizeof(ifr.ifr_name)-1 ); | ||
ioctl( canSocket, SIOCGIFINDEX, &ifr ); | ||
|
||
struct sockaddr_can addr; | ||
std::memset( &addr, 0, sizeof(addr) ); | ||
addr.can_family = AF_CAN; | ||
addr.can_ifindex = ifr.ifr_ifindex; | ||
|
||
int enableCanFd = 1; | ||
if( fd && setsockopt( canSocket, SOL_CAN_RAW, CAN_RAW_FD_FRAMES, | ||
&enableCanFd, sizeof(enableCanFd) ) ) | ||
throw std::runtime_error( "Enable CAN FD failed" ); | ||
|
||
if( bind( canSocket, reinterpret_cast<sockaddr*>(&addr), sizeof(addr) ) < 0 ) | ||
throw std::runtime_error( "Bind socket failed" ); | ||
|
||
return canSocket; | ||
} | ||
|
||
/** | ||
* @brief Passes call to can::_connect with fd argument as false. | ||
*/ | ||
inline const int connect( const std::string channel="vcan0" ) | ||
{ | ||
return _connect( false, channel ); | ||
} | ||
|
||
/** | ||
* @brief Passes call to can::_connect with fd argument as true. | ||
*/ | ||
inline const int connectfd( const std::string channel="vcan0" ) | ||
{ | ||
return _connect( true, channel ); | ||
} | ||
|
||
/** | ||
* @brief Close specified socketcan socket. | ||
* | ||
* @throws std::runtime_error If close failed. | ||
* | ||
* @param socket Socket identifer as returned from can::connect(). | ||
*/ | ||
void close( const int socket ) | ||
{ | ||
if( ::close( socket ) < 0 ) | ||
throw std::runtime_error( "Socket close failed" ); | ||
} | ||
|
||
/** | ||
* @brief Read next frame from CAN bus. | ||
* | ||
* @warning This function will block until a frame is available. | ||
* | ||
* @throws std::runtime_error If read failed. | ||
* | ||
* @param socket Socket identifer as returned from can::connect(). | ||
* @return const can_frame | ||
*/ | ||
template<typename FRAME> | ||
const FRAME _read( const int socket ) | ||
{ | ||
FRAME frame; | ||
|
||
if( read( socket, &frame, sizeof(frame) ) < 0 ) | ||
throw std::runtime_error( "Read failed" ); | ||
|
||
return frame; | ||
} | ||
|
||
/** | ||
* @brief Passes call to can::_read<can_frame>() to read standard CAN frame. | ||
* | ||
* @param socket Socket identifer as returned from can::connect(). | ||
* @return const can_frame | ||
*/ | ||
inline const can_frame read( const int socket ) | ||
{ | ||
return _read<can_frame>( socket ); | ||
} | ||
|
||
/** | ||
* @brief Passes call to can::_read<canfd_frame>() to read CANFD frame. | ||
* | ||
* @param socket Socket identifer as returned from can::connect(). | ||
* @return const canfd_frame | ||
*/ | ||
inline const canfd_frame readfd( const int socket ) | ||
{ | ||
return _read<canfd_frame>( socket ); | ||
} | ||
|
||
/** | ||
* @brief Send CAN frame. | ||
* | ||
* @throws std::runtime_error If write failed. | ||
* | ||
* @tparam FRAME can_frame or canfd_frame | ||
* @param socket Socket identifer as returned from can::connect(). | ||
* @param frame CAN or CANFD frame to be sent. | ||
* @param numBytes Number of bytes to be written. | ||
*/ | ||
template<typename FRAME> | ||
void _write( const int socket, const FRAME& frame, const uint8_t numBytes ) | ||
{ | ||
if( write( socket, &frame, numBytes ) != numBytes ) | ||
std::runtime_error( "Write failed" ); | ||
} | ||
|
||
/** | ||
* @brief Passes call to can::_write<can_frame>() to write standard CAN frame. | ||
* | ||
* @param socket Socket identifer as returned from can::connect(). | ||
* @param frame CAN frame to be sent. | ||
*/ | ||
void write( const int socket, const can_frame& frame ) | ||
{ | ||
// 8 bytes for the frame header and the rest for the actual data. | ||
_write( socket, frame, sizeof(can_frame) ); | ||
} | ||
|
||
/** | ||
* @brief Passes call to can::_write<canfd_frame>() to write CANFD frame. | ||
* | ||
* @param socket Socket identifer as returned from can::connect(). | ||
* @param frame CANFD frame to be sent. | ||
*/ | ||
void write( const int socket, const canfd_frame& frame ) | ||
{ | ||
// 8 bytes for the frame header and the rest for the actual data. | ||
_write( socket, frame, sizeof(canfd_frame) ); | ||
} | ||
|
||
|
||
std::ostream& operator<<( std::ostream &os, const can_frame& frame ) | ||
{ | ||
os << "0x" << std::setw(3) << frame.can_id << | ||
" [" << static_cast<int>(frame.can_dlc) << ']'; | ||
for( int i=0; i<frame.can_dlc; ++i ) | ||
os << ' ' << std::setw(2) << static_cast<int>(frame.data[i]); | ||
|
||
return os; | ||
} | ||
|
||
std::ostream& operator<<( std::ostream &os, const canfd_frame& frame ) | ||
{ | ||
os << "0x" << std::setw(3) << frame.can_id << | ||
" [" << static_cast<int>(frame.len) << ']'; | ||
for( int i=0; i<frame.len; ++i ) | ||
os << ' ' << std::setw(2) << static_cast<int>(frame.data[i]); | ||
|
||
return os; | ||
} | ||
} | ||
|
||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
#include <stdio.h> | ||
#include <stdlib.h> | ||
#include <string.h> | ||
#include <unistd.h> | ||
|
||
#include <iomanip> | ||
#include <iostream> | ||
#include <string> | ||
|
||
#include "can_wrap.h" | ||
using can::operator<<; | ||
|
||
int main( int argc, char* argv[] ) | ||
{ | ||
const std::string canChannel = "vcan0"; | ||
const int canSocket = can::connect( canChannel ); | ||
|
||
std::cout << std::hex << std::uppercase << std::setfill('0'); | ||
|
||
for( int c=0; c<100; ++c ) | ||
{ | ||
auto frame = can::read( canSocket ); | ||
|
||
std::cout << frame << std::endl; | ||
} | ||
|
||
can::close( canSocket ); | ||
|
||
return 0; | ||
} |
Oops, something went wrong.