From 901a27b0631909647137f49ccf12f4e9bfe38817 Mon Sep 17 00:00:00 2001
From: Romain Forlot <romain.forlot@iot.bzh>
Date: Mon, 24 Apr 2017 19:09:28 +0200
Subject: Rename and handling write on socket using stream instead of specific
 method

Created special struct to handle bcm messages with can_frame and canfd_frame.
We can now just send both of them seamlessly.

Change-Id: Ia84e9cf2ab1dd0716cb09f6bb342a208e54f8e06
Signed-off-by: Romain Forlot <romain.forlot@iot.bzh>
---
 CAN-binder/low-can-binding/CMakeLists.txt      |   2 +-
 CAN-binder/low-can-binding/can/can-bus-dev.cpp |  20 ++-
 CAN-binder/low-can-binding/utils/socket.cpp    | 146 --------------------
 CAN-binder/low-can-binding/utils/socket.hpp    |  49 -------
 CAN-binder/low-can-binding/utils/socketcan.cpp | 176 +++++++++++++++++++++++++
 CAN-binder/low-can-binding/utils/socketcan.hpp |  80 +++++++++++
 6 files changed, 265 insertions(+), 208 deletions(-)
 delete mode 100644 CAN-binder/low-can-binding/utils/socket.cpp
 delete mode 100644 CAN-binder/low-can-binding/utils/socket.hpp
 create mode 100644 CAN-binder/low-can-binding/utils/socketcan.cpp
 create mode 100644 CAN-binder/low-can-binding/utils/socketcan.hpp

diff --git a/CAN-binder/low-can-binding/CMakeLists.txt b/CAN-binder/low-can-binding/CMakeLists.txt
index 84abfaf..a68ea2a 100644
--- a/CAN-binder/low-can-binding/CMakeLists.txt
+++ b/CAN-binder/low-can-binding/CMakeLists.txt
@@ -24,7 +24,7 @@ PROJECT_TARGET_ADD(low-can-binding)
 	add_library(${TARGET_NAME} MODULE ${TARGET_NAME}.cpp configuration.cpp configuration-generated.cpp
 		can/can-bus.cpp can/can-bus-dev.cpp can/can-message-set.cpp can/can-message-definition.cpp can/can-message.cpp can/can-signals.cpp can/can-decoder.cpp
 		diagnostic/diagnostic-message.cpp diagnostic/diagnostic-manager.cpp diagnostic/active-diagnostic-request.cpp
-		utils/signals.cpp utils/openxc-utils.cpp utils/timer.cpp utils/socket.cpp utils/config-parser.cpp)
+		utils/signals.cpp utils/openxc-utils.cpp utils/timer.cpp utils/socketcan.cpp utils/config-parser.cpp)
 
 	# Binder exposes a unique public entry point
 	SET_TARGET_PROPERTIES(${TARGET_NAME} PROPERTIES
diff --git a/CAN-binder/low-can-binding/can/can-bus-dev.cpp b/CAN-binder/low-can-binding/can/can-bus-dev.cpp
index d097dc6..8470156 100644
--- a/CAN-binder/low-can-binding/can/can-bus-dev.cpp
+++ b/CAN-binder/low-can-binding/can/can-bus-dev.cpp
@@ -151,24 +151,21 @@ void can_bus_dev_t::can_reader(can_bus_t& can_bus)
 /// @return 0 if message snet, -1 if something wrong.
 int can_bus_dev_t::send(can_message_t& can_msg)
 {
-	ssize_t nbytes;
 	canfd_frame f;
-
 	f = can_msg.convert_to_canfd_frame();
 
 	if(can_socket_)
 	{
-		nbytes = can_socket_.send(f);
-		if (nbytes == -1)
+		can_socket_ << f;
+		if(!can_socket_)
 		{
-			ERROR(binder_interface, "send_can_message: Sending CAN frame failed.");
+			ERROR(binder_interface, "%s: Sending CAN frame failed.", __FUNCTION__);
 			return -1;
 		}
-		return (int)nbytes;
 	}
 	else
 	{
-		ERROR(binder_interface, "send_can_message: socket not initialized. Attempt to reopen can device socket.");
+		ERROR(binder_interface, "%s: socket not initialized. Attempt to reopen can device socket.", __FUNCTION__);
 		open();
 		return -1;
 	}
@@ -187,7 +184,6 @@ int can_bus_dev_t::send(can_message_t& can_msg)
 /// @return True if message sent, false if not.
 bool can_bus_dev_t::shims_send(const uint32_t arbitration_id, const uint8_t* data, const uint8_t size)
 {
-	ssize_t nbytes;
 	canfd_frame f;
 
 	f.can_id = arbitration_id;
@@ -196,18 +192,18 @@ bool can_bus_dev_t::shims_send(const uint32_t arbitration_id, const uint8_t* dat
 
 	if(can_socket_)
 	{
-		nbytes = can_socket_.send(f);
-		if (nbytes == -1)
+		can_socket_ << f;
+		if (!can_socket_)
 		{
 			ERROR(binder_interface, "send_can_message: Sending CAN frame failed.");
 			return false;
 		}
-		return true;
 	}
 	else
 	{
 		ERROR(binder_interface, "send_can_message: socket not initialized. Attempt to reopen can device socket.");
 		open();
+		return false;
 	}
-	return false;
+	return true;
 }
diff --git a/CAN-binder/low-can-binding/utils/socket.cpp b/CAN-binder/low-can-binding/utils/socket.cpp
deleted file mode 100644
index 9decaa8..0000000
--- a/CAN-binder/low-can-binding/utils/socket.cpp
+++ /dev/null
@@ -1,146 +0,0 @@
-/*
- * Copyright (C) 2015, 2016 ,2017 "IoT.bzh"
- * Author "Romain Forlot" <romain.forlot@iot.bzh>
- * Author "Loïc Collignon" <loic.collignon@iot.bzh>
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *	 http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <unistd.h>
-#include <string>
-#include <string.h>
-#include <linux/can/raw.h>
-#include <net/if.h>
-#include <sys/ioctl.h>
-
-#include "socket.hpp"
-#include "low-can-binding.hpp"
-
-namespace utils
-{
-	/// @brief Construct a default, invalid, socket.
-	socketcan_t::socketcan_t()
-		: socket_{INVALID_SOCKET}
-	{}
-
-	/// @brief Construct a socket by moving an existing one.
-	socketcan_t::socketcan_t(socketcan_t&& s)
-		: socket_{s.socket_}
-	{
-		s.socket_ = INVALID_SOCKET;
-	}
-
-	/// @brief Destruct the socket.
-	socketcan_t::~socketcan_t()
-	{
-		if(socket_ != INVALID_SOCKET)
-			::close(socket_);
-	}
-
-	/// @brief Test if socket is valid.
-	/// @return true if valid, false otherwise.
-	socketcan_t::operator bool() const
-	{
-		return socket_ != INVALID_SOCKET;
-	}
-
-	/// @brief Open the socket.
-	/// @param[in] domain Specifies the communications domain in which a socket is to be created.
-	/// @param[in] type Specifies the type of socket to be created.
-	/// @param[in] protocol Specifies a particular protocol to be used with the socket. Specifying a protocol of 0 causes socket() to use an unspecified default protocol appropriate for the requested socket type.
-	/// @return Upon successful completion, shall return a non-negative integer, the socket file descriptor. Otherwise, a value of -1 shall be returned and errno set to indicate the error.
-	int socketcan_t::open(int domain, int type, int protocol)
-	{
-		close();
-		socket_ = ::socket(domain, type, protocol);
-		return socket_;
-	}
-
-	/// @brief Close the socket.
-	/// @return 0 if success.
-	int socketcan_t::close()
-	{
-		return socket_ != INVALID_SOCKET ? ::close(socket_) : 0;
-	}
-
-	/// @brief Set socket option.
-	/// @return 0 if success.
-	int socketcan_t::setopt(int level, int optname, const void* optval, socklen_t optlen)
-	{
-		return socket_ != INVALID_SOCKET ? ::setsockopt(socket_, level, optname, optval, optlen) : 0;
-	}
-
-	/// @brief Bind the socket.
-	/// @return 0 if success.
-	int socketcan_t::bind(const struct sockaddr* addr, socklen_t len)
-	{
-		return socket_ != INVALID_SOCKET ? ::bind(socket_, addr, len) : 0;
-	}
-
-	/// @brief Connect the socket.
-	/// @return 0 if success.
-	int socketcan_t::connect(const struct sockaddr* addr, socklen_t len)
-	{
-		return socket_ != INVALID_SOCKET ? ::connect(socket_, addr, len) : 0;
-	}
-
-	/// @brief Get the file descriptor.
-	/// @return The socket's file descriptor
-	int socketcan_t::socket() const
-	{
-		return socket_;
-	}
-
-	/// @brief Open a raw socket CAN.
-	/// @param[in] device_name is the kernel network device name of the CAN interface.
-	///
-	/// @return Upon successful completion, shall return a non-negative integer, the socket file descriptor. Otherwise, a value of -1 shall be returned and errno set to indicate the error.
-	int socketcan_t::open(std::string device_name)
-	{
-		close();
-		
-		struct ifreq ifr;
-		socket_ = ::socket(PF_CAN, SOCK_DGRAM, CAN_BCM);
-
-		// Attempts to open a socket to CAN bus
-		::strcpy(ifr.ifr_name, device_name.c_str());
-		DEBUG(binder_interface, "%s: ifr_name is : %s", __FUNCTION__, ifr.ifr_name);
-		if(::ioctl(socket_, SIOCGIFINDEX, &ifr) < 0)
-		{
-			ERROR(binder_interface, "%s: ioctl failed. Error was : %s", __FUNCTION__, strerror(errno));
-			close();
-		}
-		else
-		{
-			txAddress_.can_family = AF_CAN;
-			txAddress_.can_ifindex = ifr.ifr_ifindex;
-
-			if(connect((struct sockaddr *)&txAddress_, sizeof(txAddress_)) < 0)
-			{
-				ERROR(binder_interface, "%s: Connect failed. %s", __FUNCTION__, strerror(errno));
-				close();
-			}
-		}
-		return socket_;
-	}
-
-	/// @brief Send a CAN message through the socket.
-	///
-	/// @param[in] f - the CAN FD frame to send
-	///
-	/// @return number of sent bytes if message sent, 0 on invalid socket and -1 if something wrong.
-	ssize_t socketcan_t::send(const struct canfd_frame& f)
-	{
-		return socket_ != INVALID_SOCKET ? ::sendto(socket_, &f, sizeof(struct canfd_frame), 0,
-			(struct sockaddr*)&txAddress_, sizeof(txAddress_)) : 0;
-	}
-}
diff --git a/CAN-binder/low-can-binding/utils/socket.hpp b/CAN-binder/low-can-binding/utils/socket.hpp
deleted file mode 100644
index b981ad3..0000000
--- a/CAN-binder/low-can-binding/utils/socket.hpp
+++ /dev/null
@@ -1,49 +0,0 @@
-#pragma once
-
-/*
- * Copyright (C) 2015, 2016 ,2017 "IoT.bzh"
- * Author "Romain Forlot" <romain.forlot@iot.bzh>
- * Author "Loïc Collignon" <loic.collignon@iot.bzh>
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *	 http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <sys/socket.h>
-
-#define INVALID_SOCKET -1
-
-namespace utils
-{
-	class socketcan_t
-	{
-	public:
-		socketcan_t();
-		socketcan_t(const socketcan_t&) = delete;
-		socketcan_t(socketcan_t&&);
-		~socketcan_t();
-
-		explicit operator bool() const;
-
-		int socket() const;
-		int open(std::string device_name);
-		int setopt(int level, int optname, const void* optval, socklen_t optlen);
-		ssize_t send(const struct canfd_frame& f);
-		int close();
-	private:
-		int socket_;
-		struct sockaddr_can txAddress_; /// < internal member using to bind to the socket
-
-		int open(int domain, int type, int protocol);
-		int bind(const struct sockaddr* addr, socklen_t len);
-		int connect(const struct sockaddr* addr, socklen_t len);
-	};
-}
diff --git a/CAN-binder/low-can-binding/utils/socketcan.cpp b/CAN-binder/low-can-binding/utils/socketcan.cpp
new file mode 100644
index 0000000..17ce6ce
--- /dev/null
+++ b/CAN-binder/low-can-binding/utils/socketcan.cpp
@@ -0,0 +1,176 @@
+/*
+ * Copyright (C) 2015, 2016 ,2017 "IoT.bzh"
+ * Author "Romain Forlot" <romain.forlot@iot.bzh>
+ * Author "Loïc Collignon" <loic.collignon@iot.bzh>
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *	 http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <unistd.h>
+#include <string>
+#include <string.h>
+#include <linux/can/raw.h>
+#include <net/if.h>
+#include <sys/ioctl.h>
+
+#include "socketcan.hpp"
+#include "low-can-binding.hpp"
+
+namespace utils
+{
+
+	/// @brief Construct a default, invalid, socket.
+	socketcan_t::socketcan_t()
+		: socket_{INVALID_SOCKET}
+	{}
+
+	/// @brief Construct a socket by moving an existing one.
+	socketcan_t::socketcan_t(socketcan_t&& s)
+		: socket_{s.socket_}
+	{
+		s.socket_ = INVALID_SOCKET;
+	}
+
+	/// @brief Destruct the socket.
+	socketcan_t::~socketcan_t()
+	{
+		if(socket_ != INVALID_SOCKET)
+			::close(socket_);
+	}
+
+	const struct sockaddr_can& socketcan_t::get_tx_address() const
+	{
+		return tx_address_;
+	}
+
+	/// @brief Test if socket is valid.
+	/// @return true if valid, false otherwise.
+	socketcan_t::operator bool() const
+	{
+		return socket_ != INVALID_SOCKET;
+	}
+
+	/// @brief Open the socket.
+	/// @param[in] domain Specifies the communications domain in which a socket is to be created.
+	/// @param[in] type Specifies the type of socket to be created.
+	/// @param[in] protocol Specifies a particular protocol to be used with the socket. Specifying a protocol of 0 causes socket() to use an unspecified default protocol appropriate for the requested socket type.
+	/// @return Upon successful completion, shall return a non-negative integer, the socket file descriptor. Otherwise, a value of -1 shall be returned and errno set to indicate the error.
+	int socketcan_t::open(int domain, int type, int protocol)
+	{
+		close();
+		socket_ = ::socket(domain, type, protocol);
+		return socket_;
+	}
+
+	/// @brief Close the socket.
+	/// @return 0 if success.
+	int socketcan_t::close()
+	{
+		return socket_ != INVALID_SOCKET ? ::close(socket_) : 0;
+	}
+
+	/// @brief Set socket option.
+	/// @return 0 if success.
+	int socketcan_t::setopt(int level, int optname, const void* optval, socklen_t optlen)
+	{
+		return socket_ != INVALID_SOCKET ? ::setsockopt(socket_, level, optname, optval, optlen) : 0;
+	}
+
+	/// @brief Bind the socket.
+	/// @return 0 if success.
+	int socketcan_t::bind(const struct sockaddr* addr, socklen_t len)
+	{
+		return socket_ != INVALID_SOCKET ? ::bind(socket_, addr, len) : 0;
+	}
+
+	/// @brief Connect the socket.
+	/// @return 0 if success.
+	int socketcan_t::connect(const struct sockaddr* addr, socklen_t len)
+	{
+		return socket_ != INVALID_SOCKET ? ::connect(socket_, addr, len) : 0;
+	}
+
+	/// @brief Get the file descriptor.
+	/// @return The socket's file descriptor
+	int socketcan_t::socket() const
+	{
+		return socket_;
+	}
+
+	/// @brief Open a raw socket CAN.
+	/// @param[in] device_name is the kernel network device name of the CAN interface.
+	///
+	/// @return Upon successful completion, shall return a non-negative integer, the socket file descriptor. Otherwise, a value of -1 shall be returned and errno set to indicate the error.
+	int socketcan_t::open(std::string device_name)
+	{
+		close();
+		
+		struct ifreq ifr;
+		socket_ = ::socket(PF_CAN, SOCK_DGRAM, CAN_BCM);
+
+		// Attempts to open a socket to CAN bus
+		::strcpy(ifr.ifr_name, device_name.c_str());
+		DEBUG(binder_interface, "%s: ifr_name is : %s", __FUNCTION__, ifr.ifr_name);
+		if(::ioctl(socket_, SIOCGIFINDEX, &ifr) < 0)
+		{
+			ERROR(binder_interface, "%s: ioctl failed. Error was : %s", __FUNCTION__, strerror(errno));
+			close();
+		}
+		else
+		{
+			tx_address_.can_family = AF_CAN;
+			tx_address_.can_ifindex = ifr.ifr_ifindex;
+
+			if(connect((struct sockaddr *)&tx_address_, sizeof(tx_address_)) < 0)
+			{
+				ERROR(binder_interface, "%s: Connect failed. %s", __FUNCTION__, strerror(errno));
+				close();
+			}
+		}
+		return socket_;
+	}
+
+	socketcan_t& operator<<(socketcan_t& s, const struct bcm_msg_head& obj)
+	{
+		struct sockaddr_can addr = s.get_tx_address();
+		::sendto(s.socket(), &obj, sizeof(bcm_msg_head), 0, (struct sockaddr*)&addr, sizeof(addr));
+		return s;
+	}
+
+	socketcan_t& operator<<(socketcan_t& s, const struct canfd_frame& obj)
+	{
+		struct sockaddr_can addr = s.get_tx_address();
+		::sendto(s.socket(), &obj, sizeof(canfd_frame), 0, (struct sockaddr*)&addr, sizeof(addr));
+		return s;
+	}
+
+	socketcan_t& operator<<(socketcan_t& s, const struct can_frame& obj)
+	{
+		struct sockaddr_can addr = s.get_tx_address();
+		::sendto(s.socket(), &obj, sizeof(can_frame), 0, (struct sockaddr*)&addr, sizeof(addr));
+		return s;
+	}
+
+	socketcan_t& operator<<(socketcan_t& s, const struct basic_bcm_msg<struct can_frame>& obj)
+	{
+		s << obj.msg_head;
+		s << obj.frames;
+		return s;
+	}
+
+	socketcan_t& operator<<(socketcan_t& s, const struct canfd_bcm_msg& obj)
+	{
+		s << obj.msg_head;
+		s << obj.frames;
+		return s;
+	}
+}
\ No newline at end of file
diff --git a/CAN-binder/low-can-binding/utils/socketcan.hpp b/CAN-binder/low-can-binding/utils/socketcan.hpp
new file mode 100644
index 0000000..2c79036
--- /dev/null
+++ b/CAN-binder/low-can-binding/utils/socketcan.hpp
@@ -0,0 +1,80 @@
+#pragma once
+
+/*
+ * Copyright (C) 2015, 2016 ,2017 "IoT.bzh"
+ * Author "Romain Forlot" <romain.forlot@iot.bzh>
+ * Author "Loïc Collignon" <loic.collignon@iot.bzh>
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *	 http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <sys/socket.h>
+#include <linux/can/bcm.h>
+
+#include <vector>
+
+#define INVALID_SOCKET -1
+
+namespace utils
+{
+
+	template <typename T>
+	struct basic_bcm_msg
+	{
+		bcm_msg_head msg_head;
+		std::vector<T> frames;
+	};
+
+	struct canfd_bcm_msg : public basic_bcm_msg<canfd_frame>
+	{
+	canfd_bcm_msg() { msg_head.flags |= CAN_FD_FRAME; }
+	};
+
+	class socketcan_t
+	{
+	public:
+		socketcan_t();
+		socketcan_t(const socketcan_t&) = delete;
+		socketcan_t(socketcan_t&&);
+		~socketcan_t();
+
+		const struct sockaddr_can& get_tx_address() const;
+		explicit operator bool() const;
+
+		int socket() const;
+		int open(std::string device_name);
+		int setopt(int level, int optname, const void* optval, socklen_t optlen);
+		int close();
+
+	private:
+		int socket_;
+		struct sockaddr_can tx_address_;
+
+		int open(int domain, int type, int protocol);
+		int bind(const struct sockaddr* addr, socklen_t len);
+		int connect(const struct sockaddr* addr, socklen_t len);
+	};
+
+	template <typename T>
+	socketcan_t& operator<<(socketcan_t& s, const std::vector<T>& vobj)
+	{
+		for(const auto& obj : vobj)
+			s << obj;
+		return s;
+	}
+
+	socketcan_t& operator<<(socketcan_t& s, const canfd_frame& frame);
+	socketcan_t& operator<<(socketcan_t& s, const can_frame& frame);
+	socketcan_t& operator<<(socketcan_t& s, const struct basic_bcm_msg<can_frame>& obj);
+	socketcan_t& operator<<(socketcan_t& s, const struct canfd_bcm_msg& obj);
+	socketcan_t& operator<<(socketcan_t& s, const struct bcm_msg_head& obj);
+}
-- 
cgit 1.2.3-korg