mirror of
https://github.com/fpagliughi/sockpp.git
synced 2026-01-12 00:04:45 +08:00
Started support for Linux SocketCAN
This commit is contained in:
@@ -59,6 +59,7 @@ endif()
|
||||
option(SOCKPP_BUILD_EXAMPLES "Build example applications" OFF)
|
||||
option(SOCKPP_BUILD_TESTS "Build unit tests" OFF)
|
||||
option(SOCKPP_BUILD_DOCUMENTATION "Create Doxygen reference documentation" OFF)
|
||||
option(SOCKPP_BUILD_CAN "Build the Linux SocketCAN components" OFF)
|
||||
|
||||
# --- C++14 build flags ---
|
||||
|
||||
@@ -107,8 +108,8 @@ if(SOCKPP_BUILD_SHARED)
|
||||
|
||||
add_library(${SOCKPP} SHARED $<TARGET_OBJECTS:sockpp-objs>)
|
||||
|
||||
## add dependencies to the shared library
|
||||
target_link_libraries(${SOCKPP} ${LIBS_SYSTEM})
|
||||
## add dependencies to the shared library
|
||||
target_link_libraries(${SOCKPP} ${LIBS_SYSTEM})
|
||||
|
||||
target_include_directories(${SOCKPP}
|
||||
PUBLIC
|
||||
@@ -117,6 +118,11 @@ if(SOCKPP_BUILD_SHARED)
|
||||
${CMAKE_CURRENT_BINARY_DIR}/generated
|
||||
)
|
||||
|
||||
target_compile_options(${SOCKPP} PRIVATE
|
||||
$<$<CXX_COMPILER_ID:MSVC>:/W3>
|
||||
$<$<NOT:$<CXX_COMPILER_ID:MSVC>>:-Wall -Wextra -Wpedantic>
|
||||
)
|
||||
|
||||
set_target_properties(${SOCKPP} PROPERTIES
|
||||
VERSION ${PROJECT_VERSION}
|
||||
SOVERSION ${PROJECT_VERSION_MAJOR})
|
||||
@@ -135,8 +141,8 @@ if(SOCKPP_BUILD_STATIC)
|
||||
|
||||
add_library(${SOCKPP_STATIC} STATIC $<TARGET_OBJECTS:sockpp-objs>)
|
||||
|
||||
## add dependencies to the static library
|
||||
target_link_libraries(${SOCKPP_STATIC} ${LIBS_SYSTEM})
|
||||
## add dependencies to the static library
|
||||
target_link_libraries(${SOCKPP_STATIC} ${LIBS_SYSTEM})
|
||||
|
||||
target_include_directories(${SOCKPP_STATIC}
|
||||
PUBLIC
|
||||
@@ -145,6 +151,11 @@ if(SOCKPP_BUILD_STATIC)
|
||||
${CMAKE_CURRENT_BINARY_DIR}/generated
|
||||
)
|
||||
|
||||
target_compile_options(${SOCKPP_STATIC} PRIVATE
|
||||
$<$<CXX_COMPILER_ID:MSVC>:/W3>
|
||||
$<$<NOT:$<CXX_COMPILER_ID:MSVC>>:-Wall -Wextra -Wpedantic>
|
||||
)
|
||||
|
||||
install(TARGETS ${SOCKPP}-static
|
||||
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR})
|
||||
@@ -187,6 +198,9 @@ if(SOCKPP_BUILD_EXAMPLES)
|
||||
add_subdirectory(examples/udp)
|
||||
if(UNIX)
|
||||
add_subdirectory(examples/unix)
|
||||
if(SOCKPP_BUILD_CAN)
|
||||
add_subdirectory(examples/linux)
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
|
||||
69
examples/linux/CMakeLists.txt
Normal file
69
examples/linux/CMakeLists.txt
Normal file
@@ -0,0 +1,69 @@
|
||||
# CMakeLists.txt
|
||||
#
|
||||
# CMake file for the Linux SocketCAN sample applications in the
|
||||
# 'sockpp' library.
|
||||
#
|
||||
# ---------------------------------------------------------------------------
|
||||
# This file is part of the "sockpp" C++ socket library.
|
||||
#
|
||||
# Copyright (c) 2021 Frank Pagliughi
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are
|
||||
# met:
|
||||
#
|
||||
# 1. Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
#
|
||||
# 2. Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in the
|
||||
# documentation and/or other materials provided with the distribution.
|
||||
#
|
||||
# 3. Neither the name of the copyright holder nor the names of its
|
||||
# contributors may be used to endorse or promote products derived from this
|
||||
# software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
# IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||||
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
# --- For apps that use threads ---
|
||||
|
||||
set(THREADS_PREFER_PTHREAD_FLAG ON)
|
||||
find_package(Threads REQUIRED)
|
||||
|
||||
# --- Executables ---
|
||||
|
||||
add_executable(cantime cantime.cpp)
|
||||
add_executable(canrecv canrecv.cpp)
|
||||
|
||||
# --- Link for executables ---
|
||||
|
||||
message(STATUS "Using library for SocketCAN samples: ${SOCKPP_LIB}")
|
||||
|
||||
target_link_libraries(cantime ${SOCKPP_LIB})
|
||||
target_link_libraries(canrecv ${SOCKPP_LIB})
|
||||
#target_link_libraries(unechosvr ${SOCKPP_LIB} Threads::Threads)
|
||||
|
||||
# --- Install ---
|
||||
|
||||
set(INSTALL_TARGETS
|
||||
cantime
|
||||
canrecv
|
||||
)
|
||||
|
||||
install(TARGETS ${INSTALL_TARGETS}
|
||||
RUNTIME DESTINATION bin
|
||||
LIBRARY DESTINATION lib
|
||||
)
|
||||
|
||||
96
examples/linux/canrecv.cpp
Normal file
96
examples/linux/canrecv.cpp
Normal file
@@ -0,0 +1,96 @@
|
||||
// canrecv.cpp
|
||||
//
|
||||
// Linux SoxketCAN reader example.
|
||||
//
|
||||
//
|
||||
// --------------------------------------------------------------------------
|
||||
// This file is part of the "sockpp" C++ socket library.
|
||||
//
|
||||
// Copyright (c) 2021 Frank Pagliughi
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
//
|
||||
// 3. Neither the name of the copyright holder nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from this
|
||||
// software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||||
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <string>
|
||||
#include <chrono>
|
||||
#include <thread>
|
||||
#include "sockpp/can_socket.h"
|
||||
#include "sockpp/can_frame.h"
|
||||
#include "sockpp/version.h"
|
||||
|
||||
#include <net/if.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
using namespace std;
|
||||
|
||||
// The clock to use to get time and pace the app.
|
||||
using sysclock = chrono::system_clock;
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
cout << "Sample SocketCAN writer for 'sockpp' "
|
||||
<< sockpp::SOCKPP_VERSION << endl;
|
||||
|
||||
string canIface = (argc > 1) ? argv[1] : "can0";
|
||||
canid_t canID = (argc > 2) ? atoi(argv[2]) : 0x20;
|
||||
|
||||
sockpp::socket_initializer sockInit;
|
||||
|
||||
sockpp::can_address addr(canIface);
|
||||
sockpp::can_socket sock(addr);
|
||||
|
||||
if (!sock) {
|
||||
cerr << "Error binding to the CAN interface " << canIface << "\n\t"
|
||||
<< sock.last_error_str() << endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
cout << "Created CAN socket on " << sock.address() << endl;
|
||||
time_t t = sysclock::to_time_t(sysclock::now());
|
||||
|
||||
cout.setf(ios::fixed, ios::floatfield);
|
||||
cout << setfill('0');
|
||||
|
||||
while (true) {
|
||||
sockpp::can_frame frame;
|
||||
sock.recv(&frame);
|
||||
auto t = sock.last_frame_timestamp();
|
||||
|
||||
cout << t << " ";
|
||||
for (uint8_t i=0; i<frame.can_dlc; ++i)
|
||||
cout << hex << uppercase << setw(2) << unsigned(frame.data[i]) << " ";
|
||||
cout << endl;
|
||||
}
|
||||
|
||||
return (!sock) ? 1 : 0;
|
||||
}
|
||||
98
examples/linux/cantime.cpp
Normal file
98
examples/linux/cantime.cpp
Normal file
@@ -0,0 +1,98 @@
|
||||
// cantime.cpp
|
||||
//
|
||||
// Linux SoxketCAN writer example.
|
||||
//
|
||||
// This writes the 1-sec, 32-bit, Linux time_t value to the CAN bus each
|
||||
// time it ticks. This is a simple (though not overly precise) way to
|
||||
// synchronize the time for nodes on the bus
|
||||
//
|
||||
// --------------------------------------------------------------------------
|
||||
// This file is part of the "sockpp" C++ socket library.
|
||||
//
|
||||
// Copyright (c) 2021 Frank Pagliughi
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
//
|
||||
// 3. Neither the name of the copyright holder nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from this
|
||||
// software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||||
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <chrono>
|
||||
#include <thread>
|
||||
#include "sockpp/can_socket.h"
|
||||
#include "sockpp/can_frame.h"
|
||||
#include "sockpp/version.h"
|
||||
|
||||
#include <net/if.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
using namespace std;
|
||||
|
||||
// The clock to use to get time and pace the app.
|
||||
using sysclock = chrono::system_clock;
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
cout << "Sample SocketCAN writer for 'sockpp' "
|
||||
<< sockpp::SOCKPP_VERSION << endl;
|
||||
|
||||
string canIface = (argc > 1) ? argv[1] : "can0";
|
||||
canid_t canID = (argc > 2) ? atoi(argv[2]) : 0x20;
|
||||
|
||||
sockpp::socket_initializer sockInit;
|
||||
|
||||
sockpp::can_address addr(canIface);
|
||||
sockpp::can_socket sock(addr);
|
||||
|
||||
if (!sock) {
|
||||
cerr << "Error binding to the CAN interface " << canIface << "\n\t"
|
||||
<< sock.last_error_str() << endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
cout << "Created CAN socket on " << sock.address() << endl;
|
||||
time_t t = sysclock::to_time_t(sysclock::now());
|
||||
|
||||
while (true) {
|
||||
// Sleep until the clock ticks to the next second
|
||||
this_thread::sleep_until(sysclock::from_time_t(t+1));
|
||||
|
||||
// Re-read the time in case we fell behind
|
||||
t = sysclock::to_time_t(sysclock::now());
|
||||
|
||||
// Write the time to the CAN bus as a 32-bit int
|
||||
auto nt = uint32_t(t);
|
||||
|
||||
sockpp::can_frame frame { canID, &nt, sizeof(nt) };
|
||||
sock.send(frame);
|
||||
}
|
||||
|
||||
return (!sock) ? 1 : 0;
|
||||
}
|
||||
201
include/sockpp/can_address.h
Normal file
201
include/sockpp/can_address.h
Normal file
@@ -0,0 +1,201 @@
|
||||
/**
|
||||
* @file can_address.h
|
||||
*
|
||||
* Class for the Linux SocketCAN socket address.
|
||||
*
|
||||
* @author Frank Pagliughi
|
||||
* @author SoRo Systems, Inc.
|
||||
* @author www.sorosys.com
|
||||
*
|
||||
* @date March 2021
|
||||
*/
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// This file is part of the "sockpp" C++ socket library.
|
||||
//
|
||||
// Copyright (c) 2014-2021 Frank Pagliughi
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
//
|
||||
// 3. Neither the name of the copyright holder nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from this
|
||||
// software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||||
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
#ifndef __sockpp_can_addr_h
|
||||
#define __sockpp_can_addr_h
|
||||
|
||||
#include "sockpp/platform.h"
|
||||
#include "sockpp/sock_address.h"
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <cstring>
|
||||
#include <sys/un.h>
|
||||
|
||||
#include <linux/can.h>
|
||||
|
||||
namespace sockpp {
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* Class that represents a Linux SocketCAN address.
|
||||
* This inherits from the CAN form of a socket address, @em sockaddr_can.
|
||||
*/
|
||||
class can_address : public sock_address
|
||||
{
|
||||
/** The underlying C struct for SocketCAN addresses */
|
||||
sockaddr_can addr_;
|
||||
|
||||
/** The size of the underlying address struct, in bytes */
|
||||
static constexpr size_t SZ = sizeof(sockaddr_can);
|
||||
|
||||
public:
|
||||
/** The address family for this type of address */
|
||||
static constexpr sa_family_t ADDRESS_FAMILY = AF_CAN;
|
||||
|
||||
/** Iface to use to indicate binding to all interfaces */
|
||||
static const unsigned ALL_IFACE = 0;
|
||||
|
||||
/**
|
||||
* Constructs an empty address.
|
||||
* The address is initialized to all zeroes.
|
||||
*/
|
||||
can_address() : addr_() {}
|
||||
/**
|
||||
* Creates an address for binding to a specific CAN interface
|
||||
* @param ifindex The interface index to use. This must, obviously, be
|
||||
* an index to a CAN interface.
|
||||
*/
|
||||
explicit can_address(unsigned ifindex);
|
||||
/**
|
||||
* Constructs an address for the specified CAN interface.
|
||||
* The interface might be "can0", "can1", "vcan0", etc.
|
||||
* @param iface The name of the CAN interface
|
||||
*/
|
||||
can_address(const std::string& iface);
|
||||
/**
|
||||
* Constructs the address by copying the specified structure.
|
||||
* @param addr The generic address
|
||||
* @throws std::invalid_argument if the address is not a SocketCAN
|
||||
* address (i.e. family is not AF_CAN)
|
||||
*/
|
||||
explicit can_address(const sockaddr& addr);
|
||||
/**
|
||||
* Constructs the address by copying the specified structure.
|
||||
* @param addr The other address
|
||||
*/
|
||||
can_address(const sock_address& addr) {
|
||||
std::memcpy(&addr_, addr.sockaddr_ptr(), SZ);
|
||||
}
|
||||
/**
|
||||
* Constructs the address by copying the specified structure.
|
||||
* @param addr The other address
|
||||
* @throws std::invalid_argument if the address is not properly
|
||||
* initialized as a SocketCAN address (i.e. family is not
|
||||
* AF_CAN)
|
||||
*/
|
||||
can_address(const sockaddr_can& addr) : addr_(addr) {}
|
||||
/**
|
||||
* Constructs the address by copying the specified address.
|
||||
* @param addr The other address
|
||||
*/
|
||||
can_address(const can_address& addr) : addr_(addr.addr_) {}
|
||||
/**
|
||||
* Checks if the address is set to some value.
|
||||
* This doesn't attempt to determine if the address is valid, simply
|
||||
* that it's not all zero.
|
||||
* @return @em true if the address has been set, @em false otherwise.
|
||||
*/
|
||||
bool is_set() const { return family() != AF_UNSPEC; }
|
||||
/**
|
||||
* Gets the name of the CAN interface to which this address refers.
|
||||
* @return The name of the CAN interface to which this address refers.
|
||||
*/
|
||||
std::string iface() const;
|
||||
/**
|
||||
* Gets the size of the address structure.
|
||||
* Note: In this implementation, this should return sizeof(this) but
|
||||
* more convenient in some places, and the implementation might change
|
||||
* in the future, so it might be more compatible with future revisions
|
||||
* to use this call.
|
||||
* @return The size of the address structure.
|
||||
*/
|
||||
socklen_t size() const override { return socklen_t(SZ); }
|
||||
|
||||
// TODO: Do we need a:
|
||||
// create(iface)
|
||||
// to mimic the inet_address behavior?
|
||||
|
||||
/**
|
||||
* Gets a pointer to this object cast to a const @em sockaddr.
|
||||
* @return A pointer to this object cast to a const @em sockaddr.
|
||||
*/
|
||||
const sockaddr* sockaddr_ptr() const override {
|
||||
return reinterpret_cast<const sockaddr*>(&addr_);
|
||||
}
|
||||
/**
|
||||
* Gets a pointer to this object cast to a @em sockaddr.
|
||||
* @return A pointer to this object cast to a @em sockaddr.
|
||||
*/
|
||||
sockaddr* sockaddr_ptr() override {
|
||||
return reinterpret_cast<sockaddr*>(&addr_);
|
||||
}
|
||||
/**
|
||||
* Gets a const pointer to this object cast to a @em sockaddr_can.
|
||||
* @return const sockaddr_can pointer to this object.
|
||||
*/
|
||||
const sockaddr_can* sockaddr_can_ptr() const { return &addr_; }
|
||||
/**
|
||||
* Gets a pointer to this object cast to a @em sockaddr_can.
|
||||
* @return sockaddr_can pointer to this object.
|
||||
*/
|
||||
sockaddr_can* sockaddr_can_ptr() { return &addr_; }
|
||||
/**
|
||||
* Gets a printable string for the address.
|
||||
* @return A string representation of the address in the form
|
||||
* "unix:<path>"
|
||||
*/
|
||||
std::string to_string() const {
|
||||
return std::string("can:") + iface();
|
||||
}
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Stream inserter for the address.
|
||||
* @param os The output stream
|
||||
* @param addr The address
|
||||
* @return A reference to the output stream.
|
||||
*/
|
||||
std::ostream& operator<<(std::ostream& os, const can_address& addr);
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// end namespace sockpp
|
||||
}
|
||||
|
||||
#endif // __sockpp_can_addr_h
|
||||
|
||||
103
include/sockpp/can_frame.h
Normal file
103
include/sockpp/can_frame.h
Normal file
@@ -0,0 +1,103 @@
|
||||
/**
|
||||
* @file can_frame.h
|
||||
*
|
||||
* Class for the Linux SocketCAN frames.
|
||||
*
|
||||
* @author Frank Pagliughi
|
||||
* @author SoRo Systems, Inc.
|
||||
* @author www.sorosys.com
|
||||
*
|
||||
* @date March 2021
|
||||
*/
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// This file is part of the "sockpp" C++ socket library.
|
||||
//
|
||||
// Copyright (c) 2021 Frank Pagliughi
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
//
|
||||
// 3. Neither the name of the copyright holder nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from this
|
||||
// software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||||
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
#ifndef __sockpp_can_frame_h
|
||||
#define __sockpp_can_frame_h
|
||||
|
||||
#include "sockpp/platform.h"
|
||||
#include <string>
|
||||
#include <cstring>
|
||||
//#include <sys/un.h>
|
||||
#include <linux/can.h>
|
||||
|
||||
namespace sockpp {
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* Class that represents a Linux SocketCAN frame.
|
||||
* This inherits from the Linux CAN frame struct, just providing easier
|
||||
construction.
|
||||
*/
|
||||
class can_frame : public ::can_frame
|
||||
{
|
||||
using base = ::can_frame;
|
||||
|
||||
/** The size of the underlying address struct, in bytes */
|
||||
static constexpr size_t SZ = sizeof(::can_frame);
|
||||
|
||||
public:
|
||||
/**
|
||||
* Constructs an empty frame.
|
||||
* The frame is initialized to all zeroes.
|
||||
*/
|
||||
can_frame() : base{} {}
|
||||
/**
|
||||
* Constructs a frame with the specified ID and data.
|
||||
* @param canID The CAN identifier for the frame
|
||||
* @param data The data field for the frame
|
||||
*/
|
||||
can_frame(canid_t canID, const std::string& data)
|
||||
: can_frame{ canID, data.data(), data.length() } {}
|
||||
/**
|
||||
* Constructs a frame with the specified ID and data.
|
||||
* @param canID The CAN identifier for the frame
|
||||
* @param data The data field for the frame
|
||||
* @param n The number of bytes in the data field
|
||||
*/
|
||||
can_frame(canid_t canID, const void* data, size_t n) : base{} {
|
||||
this->can_id = canID;
|
||||
this->can_dlc = n;
|
||||
::memcpy(&this->data, data, n);
|
||||
}
|
||||
};
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// end namespace sockpp
|
||||
}
|
||||
|
||||
#endif // __sockpp_can_frame_h
|
||||
|
||||
206
include/sockpp/can_socket.h
Normal file
206
include/sockpp/can_socket.h
Normal file
@@ -0,0 +1,206 @@
|
||||
/**
|
||||
* @file can_socket.h
|
||||
*
|
||||
* Class (typedef) for Linux SocketCAN socket.
|
||||
*
|
||||
* @author Frank Pagliughi
|
||||
* @author SoRo Systems, Inc.
|
||||
* @author www.sorosys.com
|
||||
*
|
||||
* @date March 2021
|
||||
*/
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// This file is part of the "sockpp" C++ socket library.
|
||||
//
|
||||
// Copyright (c) 2021 Frank Pagliughi
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
//
|
||||
// 3. Neither the name of the copyright holder nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from this
|
||||
// software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||||
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
#ifndef __sockpp_can_socket_h
|
||||
#define __sockpp_can_socket_h
|
||||
|
||||
#include "sockpp/datagram_socket.h"
|
||||
#include "sockpp/can_address.h"
|
||||
#include "sockpp/can_frame.h"
|
||||
|
||||
namespace sockpp {
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* Socket type for Linux SocketCAN.
|
||||
*
|
||||
* Note that technically these are RAW sockets, not DGRAM. We can/should
|
||||
* organize the underlying hierarch to properly indicate this, but for
|
||||
* practical usge, it doesn't matter too MUCH.
|
||||
* The BCM CAN sockets are DGRAM sockets, but those aren't implemented yet.
|
||||
* It wouldn't take too much to add them, though.
|
||||
*/
|
||||
class can_socket : public datagram_socket
|
||||
{
|
||||
/** The base class */
|
||||
using base = datagram_socket;
|
||||
|
||||
// Non-copyable
|
||||
can_socket(const can_socket&) =delete;
|
||||
can_socket& operator=(const can_socket&) =delete;
|
||||
|
||||
/**
|
||||
* We can't connect to a raw CAN socket;
|
||||
* we can only bind the address/iface.
|
||||
*/
|
||||
bool connect(const sock_address&) =delete;
|
||||
|
||||
protected:
|
||||
static socket_t create_handle(int type, int protocol) {
|
||||
return socket_t(::socket(PROTOCOL_FAMILY, type, protocol));
|
||||
}
|
||||
|
||||
public:
|
||||
/**
|
||||
* The SocketCAN protocol family.
|
||||
* Note that AF_CAN == PF_CAN, which is used in many of the CAN
|
||||
* examples.
|
||||
*/
|
||||
static const int PROTOCOL_FAMILY = AF_CAN;
|
||||
|
||||
/** The socket 'type' for communications semantics. */
|
||||
static constexpr int COMM_TYPE = SOCK_RAW;
|
||||
|
||||
/**
|
||||
* Creates an uninitialized CAN socket.
|
||||
*/
|
||||
can_socket() {}
|
||||
/**
|
||||
* Creates a CAN socket from an existing OS socket handle and
|
||||
* claims ownership of the handle.
|
||||
* @param handle A socket handle from the operating system.
|
||||
*/
|
||||
explicit can_socket(socket_t handle) : base(handle) {}
|
||||
/**
|
||||
* Creates a CAN socket and binds it to the address.
|
||||
* @param addr The address to bind.
|
||||
*/
|
||||
explicit can_socket(const can_address& addr);
|
||||
/**
|
||||
* Move constructor.
|
||||
* @param other The other socket to move to this one
|
||||
*/
|
||||
can_socket(can_socket&& other) : base(std::move(other)) {}
|
||||
/**
|
||||
* Move assignment.
|
||||
* @param rhs The other socket to move into this one.
|
||||
* @return A reference to this object.
|
||||
*/
|
||||
can_socket& operator=(can_socket&& rhs) {
|
||||
base::operator=(std::move(rhs));
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the system time of the last frame read from the socket.
|
||||
* @return The system time of the last frame read from the socket with
|
||||
* microsecond precision.
|
||||
*/
|
||||
std::chrono::system_clock::time_point last_frame_time();
|
||||
/**
|
||||
* Gets a floating point timestamp of the last frame read from the
|
||||
* socket.
|
||||
* This is the number of seconds since the Unix epoch (time_t), with
|
||||
* floating-point, microsecond precision.
|
||||
* @return A floating-point timestamp with microsecond precision.
|
||||
*/
|
||||
double last_frame_timestamp();
|
||||
|
||||
// ----- I/O -----
|
||||
|
||||
/**
|
||||
* Sends a frame to the CAN interfacce at the specified address.
|
||||
* @param frame The CAN frame to send.
|
||||
* @param flags The flags. See send(2).
|
||||
* @param addr The remote destination of the data.
|
||||
* @return the number of bytes sent on success or, @em -1 on failure.
|
||||
*/
|
||||
ssize_t send_to(const can_frame& frame, int flags, const can_address& addr) {
|
||||
return check_ret(
|
||||
::sendto(handle(), &frame, sizeof(can_frame), flags,
|
||||
addr.sockaddr_ptr(), addr.size())
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a frame to the CAN interface at the specified address.
|
||||
* @param frame The CAN frame to send.
|
||||
* @param addr The remote destination of the data.
|
||||
* @return the number of bytes sent on success or, @em -1 on failure.
|
||||
*/
|
||||
ssize_t send_to(const can_frame& frame, const can_address& addr) {
|
||||
return check_ret(
|
||||
::sendto(handle(), &frame, sizeof(can_frame), 0,
|
||||
addr.sockaddr_ptr(), addr.size())
|
||||
);
|
||||
}
|
||||
/**
|
||||
* Sends a frame to the CAN bus.
|
||||
* The socket should be bound before calling this.
|
||||
* @param frame The CAN frame to send.
|
||||
* @param flags The option bit flags. See send(2).
|
||||
* @return @em zero on success, @em -1 on failure.
|
||||
*/
|
||||
ssize_t send(const can_frame& frame, int flags=0) {
|
||||
return check_ret(::send(handle(), &frame, sizeof(can_frame), flags));
|
||||
}
|
||||
/**
|
||||
* Receives a message from the CAN interface at the specified address.
|
||||
* @param frame CAN frame to get the incoming data.
|
||||
* @param flags The option bit flags. See send(2).
|
||||
* @param srcAddr Receives the address of the peer that sent the
|
||||
* message
|
||||
* @return The number of bytes read or @em -1 on error.
|
||||
*/
|
||||
ssize_t recv_from(can_frame* frame, int flags, can_address* srcAddr=nullptr);
|
||||
/**
|
||||
* Receives a message on the socket.
|
||||
* @param frame CAN frame to get the incoming data.
|
||||
* @param flags The option bit flags. See send(2).
|
||||
* @return The number of bytes read or @em -1 on error.
|
||||
*/
|
||||
ssize_t recv(can_frame* frame, int flags=0) {
|
||||
return check_ret(::recv(handle(), frame, sizeof(can_frame), flags));
|
||||
}
|
||||
};
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// end namespace sockpp
|
||||
}
|
||||
|
||||
#endif // __sockpp_can_socket_h
|
||||
|
||||
@@ -69,8 +69,12 @@ class datagram_socket : public socket
|
||||
datagram_socket& operator=(const datagram_socket&) =delete;
|
||||
|
||||
protected:
|
||||
static socket_t create_handle(int domain) {
|
||||
return socket_t(::socket(domain, COMM_TYPE, 0));
|
||||
static socket_t create_handle(int domain, int protocol=0) {
|
||||
return socket_t(::socket(domain, COMM_TYPE, protocol));
|
||||
}
|
||||
|
||||
static socket_t create_handle(int domain, int type, int protocol) {
|
||||
return socket_t(::socket(domain, type, protocol));
|
||||
}
|
||||
|
||||
public:
|
||||
@@ -265,7 +269,7 @@ public:
|
||||
*/
|
||||
datagram_socket_tmpl(socket_t handle) : base(handle) {}
|
||||
/**
|
||||
* Creates a UDP socket and binds it to the address.
|
||||
* Creates a datagram socket and binds it to the address.
|
||||
* @param addr The address to bind.
|
||||
*/
|
||||
datagram_socket_tmpl(const ADDR& addr) : base(addr) {}
|
||||
|
||||
@@ -62,14 +62,47 @@ namespace sockpp {
|
||||
#define SOCKPP_SOCKET_T_DEFINED
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* Converts a number of microseconds to a relative timeval.
|
||||
* @param dur A chrono duration of microseconds.
|
||||
* @return A timeval
|
||||
*/
|
||||
timeval to_timeval(const std::chrono::microseconds& dur);
|
||||
|
||||
/**
|
||||
* Converts a chrono duration to a relative timeval.
|
||||
* @param dur A chrono duration.
|
||||
* @return A timeval.
|
||||
*/
|
||||
template<class Rep, class Period>
|
||||
timeval to_timeval(const std::chrono::duration<Rep,Period>& dur) {
|
||||
return to_timeval(std::chrono::duration_cast<std::chrono::microseconds>(dur));
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a relative timeval to a chrono duration.
|
||||
* @param tv A timeval.
|
||||
* @return A chrono duration.
|
||||
*/
|
||||
inline std::chrono::microseconds to_duration(const timeval& tv)
|
||||
{
|
||||
auto dur = std::chrono::seconds{tv.tv_sec}
|
||||
+ std::chrono::microseconds{tv.tv_usec};
|
||||
return std::chrono::duration_cast<std::chrono::microseconds>(dur);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts an absolute timeval to a chrono time_point.
|
||||
* @param tv A timeval.
|
||||
* @return A chrono time_point.
|
||||
*/
|
||||
inline std::chrono::system_clock::time_point to_timepoint(const timeval& tv)
|
||||
{
|
||||
return std::chrono::system_clock::time_point {
|
||||
std::chrono::duration_cast<std::chrono::system_clock::duration>(to_duration(tv))
|
||||
};
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
add_library(sockpp-objs OBJECT
|
||||
acceptor.cpp
|
||||
acceptor.cpp
|
||||
connector.cpp
|
||||
datagram_socket.cpp
|
||||
exception.cpp
|
||||
@@ -49,8 +49,14 @@ add_library(sockpp-objs OBJECT
|
||||
|
||||
if(UNIX)
|
||||
target_sources(sockpp-objs PUBLIC
|
||||
unix/unix_address.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/unix/unix_address.cpp
|
||||
)
|
||||
if(SOCKPP_BUILD_CAN)
|
||||
target_sources(sockpp-objs PUBLIC
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/linux/can_address.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/linux/can_socket.cpp
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# This is only necessary for older compilers, but doesn't hurt
|
||||
|
||||
@@ -43,7 +43,7 @@ using namespace std::chrono;
|
||||
namespace sockpp {
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// udp_socket
|
||||
// datagram_socket
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
datagram_socket::datagram_socket(const sock_address& addr)
|
||||
@@ -53,6 +53,7 @@ datagram_socket::datagram_socket(const sock_address& addr)
|
||||
|
||||
if (check_socket_bool(h)) {
|
||||
reset(h);
|
||||
// TODO: If the bind fails, should we close the socket and fail completely?
|
||||
bind(addr);
|
||||
}
|
||||
}
|
||||
|
||||
104
src/linux/can_address.cpp
Normal file
104
src/linux/can_address.cpp
Normal file
@@ -0,0 +1,104 @@
|
||||
// can_address.cpp
|
||||
//
|
||||
// --------------------------------------------------------------------------
|
||||
// This file is part of the "sockpp" C++ socket library.
|
||||
//
|
||||
// Copyright (c) 2014-2021 Frank Pagliughi
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
//
|
||||
// 3. Neither the name of the copyright holder nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from this
|
||||
// software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||||
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
#include "sockpp/can_address.h"
|
||||
#include "sockpp/socket.h"
|
||||
#include <cstring>
|
||||
#include <stdexcept>
|
||||
#include <sys/ioctl.h>
|
||||
#include <net/if.h>
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace sockpp {
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
constexpr sa_family_t can_address::ADDRESS_FAMILY;
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
can_address::can_address(unsigned ifindex) : addr_{}
|
||||
{
|
||||
addr_.can_family = AF_CAN;
|
||||
addr_.can_ifindex = ifindex;
|
||||
}
|
||||
|
||||
can_address::can_address(const string& iface) : addr_{}
|
||||
{
|
||||
unsigned idx = if_nametoindex(iface.c_str());
|
||||
|
||||
if (idx != 0) {
|
||||
addr_.can_family = AF_CAN;
|
||||
addr_.can_ifindex = idx;
|
||||
}
|
||||
}
|
||||
|
||||
can_address::can_address(const sockaddr& addr)
|
||||
{
|
||||
auto domain = addr.sa_family;
|
||||
if (domain != AF_CAN)
|
||||
throw std::invalid_argument("Not a SocketCAN address");
|
||||
|
||||
std::memcpy(&addr_, &addr, sizeof(sockaddr));
|
||||
}
|
||||
|
||||
string can_address::iface() const
|
||||
{
|
||||
if (addr_.can_family == AF_UNSPEC)
|
||||
return string("none");
|
||||
|
||||
if (addr_.can_ifindex == 0)
|
||||
return string("any");
|
||||
|
||||
char buf[IF_NAMESIZE];
|
||||
const char* iface = if_indextoname(addr_.can_ifindex, buf);
|
||||
|
||||
return string(iface ? iface : "unknown");
|
||||
}
|
||||
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
ostream& operator<<(ostream& os, const can_address& addr)
|
||||
{
|
||||
os << "can:" << addr.iface();
|
||||
return os;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// End namespace sockpp
|
||||
}
|
||||
92
src/linux/can_socket.cpp
Normal file
92
src/linux/can_socket.cpp
Normal file
@@ -0,0 +1,92 @@
|
||||
// can_socket.cpp
|
||||
//
|
||||
// --------------------------------------------------------------------------
|
||||
// This file is part of the "sockpp" C++ socket library.
|
||||
//
|
||||
// Copyright (c) 2021 Frank Pagliughi
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
//
|
||||
// 3. Neither the name of the copyright holder nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from this
|
||||
// software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||||
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
#include "sockpp/can_socket.h"
|
||||
#include "sockpp/socket.h"
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
using namespace std;
|
||||
using namespace std::chrono;
|
||||
|
||||
namespace sockpp {
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
can_socket::can_socket(const can_address& addr)
|
||||
{
|
||||
socket_t h = create_handle(SOCK_RAW, CAN_RAW);
|
||||
|
||||
if (check_socket_bool(h)) {
|
||||
reset(h);
|
||||
bind(addr);
|
||||
}
|
||||
}
|
||||
|
||||
system_clock::time_point can_socket::last_frame_time()
|
||||
{
|
||||
timeval tv {};
|
||||
|
||||
// TODO: Handle error
|
||||
::ioctl(handle(), SIOCGSTAMP, &tv);
|
||||
return to_timepoint(tv);
|
||||
}
|
||||
|
||||
double can_socket::last_frame_timestamp()
|
||||
{
|
||||
timeval tv {};
|
||||
|
||||
// TODO: Handle error
|
||||
::ioctl(handle(), SIOCGSTAMP, &tv);
|
||||
return double(tv.tv_sec) + 1.0e-6 * tv.tv_usec;
|
||||
}
|
||||
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
ssize_t can_socket::recv_from(can_frame *frame, int flags,
|
||||
can_address* srcAddr /*=nullptr*/)
|
||||
{
|
||||
sockaddr* p = srcAddr ? srcAddr->sockaddr_ptr() : nullptr;
|
||||
socklen_t len = srcAddr ? srcAddr->size() : 0;
|
||||
|
||||
// TODO: Check returned length
|
||||
return check_ret(::recvfrom(handle(), frame, sizeof(can_frame),
|
||||
flags, p, &len));
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// End namespace sockpp
|
||||
}
|
||||
Reference in New Issue
Block a user