2 Copyright (C) 2012 Intel Corporation
3 Copyright (C) 2015 Cogent Embedded Inc.
4 Copyright (C) 2015 Renesas Electronics Corporation
6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
11 This library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public
17 License along with this library; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 #include <sys/ioctl.h>
24 #include <sys/socket.h>
26 #include <timestamp.h>
28 #include "cansocketbcm.h"
29 #include "timestamp.h"
31 CANSocketBCM::CANSocketBCM() :
37 bool CANSocketBCM::start(const char* ifName)
46 LOG_ERROR("Socket error");
50 // can_err_mask_t errorMask = 0xFFFFFFFF;
51 // if(!enableCANErrors(errorMask)) {
52 // LOG_ERROR("Socket error");
57 mPoll.events = POLLIN | POLLPRI;
60 memset(&ifr, 0, sizeof(ifr));
61 strcpy(ifr.ifr_name, ifName);
62 if(!locateInterfaceIndex(ifr)) {
63 LOG_ERROR("Socket error");
68 struct sockaddr_can addr;
69 memset(&addr, 0, sizeof(addr));
70 addr.can_family = AF_CAN;
71 addr.can_ifindex = ifr.ifr_ifindex;
72 if(!connectSocket(addr)) {
73 LOG_ERROR("Socket error");
81 void CANSocketBCM::stop()
91 bool CANSocketBCM::write(const struct CANFrameInfo &message)
95 return writeFrameOneTime(message.frame);
98 CANSocket::CANSocketReadSuccess CANSocketBCM::read(struct CANFrameInfo& message, unsigned int timeout)
100 LOG_TRACE("timeout: " << timeout);
102 CANSocket::CANSocketReadSuccess success;
103 memset(&message, 0, sizeof(message));
105 switch(waitData(timeout)) {
107 LOG_ERROR("reading error");
108 success = CANSocket::READING_FAILED;
111 success = CANSocket::READING_TIMED_OUT;
114 success = readMessage(message);
121 bool CANSocketBCM::createSocket()
123 return ((mSocket = ::socket(PF_CAN, SOCK_DGRAM, CAN_BCM)) >= 0);
126 bool CANSocketBCM::locateInterfaceIndex(struct ifreq& ifr)
128 return (::ioctl(mSocket, SIOCGIFINDEX, &ifr) == 0);
131 bool CANSocketBCM::connectSocket(struct sockaddr_can& addr)
133 return (::connect(mSocket, (struct sockaddr*)&addr, sizeof(addr)) == 0);
136 bool CANSocketBCM::closeSocket()
138 return (::close(mSocket) == 0);
141 int CANSocketBCM::waitData(unsigned int timeout)
143 return ::poll(&mPoll, 1, timeout);
147 * BCM header with one message.
148 * @note hdr.nframes must always be 0 or 1.
150 struct __attribute__ ((__packed__)) bcm_msg_one{
151 struct bcm_msg_head hdr;
152 struct can_frame frames[1];
155 bool CANSocketBCM::writeFrameOneTime(const can_frame& frame)
157 struct bcm_msg_one bcms;
159 // fill in the header
160 memset(&bcms.hdr, 0, sizeof(bcms.hdr));
161 bcms.hdr.opcode = TX_SEND;
162 bcms.hdr.nframes = 1;
163 bcms.hdr.can_id = frame.can_id;
166 memcpy(&bcms.frames[0], &frame, sizeof(frame));
168 // and write everything
169 ssize_t nbytes = ::write(mSocket, &bcms, sizeof(bcms));
170 return nbytes == sizeof(bcms);
173 CANSocket::CANSocketReadSuccess CANSocketBCM::readMessage(CANFrameInfo& message)
175 struct bcm_msg_one bcms;
177 // clear the destination
178 memset(&message, 0, sizeof(message));
180 // get data from socket
181 size_t nbytes = ::recv(mSocket, &bcms, sizeof(bcms), 0);
182 if ( nbytes < sizeof(bcms.hdr))
184 LOG_ERROR("Socket error");
185 return CANSocket::CANSocketReadSuccess::READING_FAILED;
187 //TODO: implement better timestamps
188 message.timestamp = amb::currentTime();
190 switch (bcms.hdr.opcode)
193 if (bcms.hdr.nframes >= 1 && nbytes == sizeof(bcms))
195 if (bcms.hdr.nframes > 1)
197 LOG_WARNING("Dropped " << bcms.hdr.nframes - 1 << " updates from CAN bus.");
200 // copy the first frame
201 memcpy(&message.frame, &bcms.frames[0], sizeof(bcms.frames[0]));
202 message.status = CANFrameInfo::CANMessageStatus::GOOD;
203 return CANSocket::CANSocketReadSuccess::READING_SUCCEEDED;
207 LOG_ERROR("Unexpected data from the socket"
208 << " " << bcms.hdr.opcode
209 << " " << bcms.hdr.nframes
211 return CANSocket::CANSocketReadSuccess::READING_FAILED;
214 memcpy(&message.frame, &bcms.frames[0], sizeof(bcms.frames[0]));
215 message.frame.can_id = bcms.hdr.can_id; //doubtful. Do we need to override this?
216 message.status = CANFrameInfo::CANMessageStatus::TIMEOUT;
217 return CANSocket::CANSocketReadSuccess::READING_SUCCEEDED;
221 return CANSocket::CANSocketReadSuccess::READING_TIMED_OUT;
224 LOG_ERROR("Unexpected opcode " << bcms.hdr.opcode);
225 return CANSocket::CANSocketReadSuccess::READING_FAILED;
230 4.2.5 Broadcast Manager receive filter timers
232 The timer values ival1 or ival2 may be set to non-zero values at RX_SETUP.
233 When the SET_TIMER flag is set the timers are enabled:
235 ival1: Send RX_TIMEOUT when a received message is not received again within
236 the given time. When START_TIMER is set at RX_SETUP the timeout detection
237 is activated directly - even without a former CAN frame reception.
239 ival2: Throttle the received message rate down to the value of ival2. This
240 is useful to reduce messages for the application when the signal inside the
241 CAN frame is stateless as state changes within the ival2 periode may get
245 bool CANSocketBCM::registerCyclicMessageForReceive(int canId, double minCycleTime, double maxCycleTime)
247 struct bcm_msg_head hdr;
249 // fill in the header
250 memset(&hdr, 0, sizeof(hdr));
251 hdr.opcode = RX_SETUP;
252 // set RX_FILTER_ID | RX_CHECK_DLC because we don't differentiate messages by dlc or content yet. Only by id
253 // setting RX_ANNOUNCE_RESUME may lead to duplicates in data which should be filtered by amb core.
254 // However, we won't miss any data.
255 hdr.flags = RX_FILTER_ID | RX_CHECK_DLC | SETTIMER | STARTTIMER | RX_ANNOUNCE_RESUME;
258 hdr.ival1 = amb::Timestamp::toTimeval(maxCycleTime);
259 hdr.ival2 = amb::Timestamp::toTimeval(minCycleTime);
262 ssize_t nbytes = ::write(mSocket, &hdr, sizeof(hdr));
263 return nbytes == sizeof(hdr);
266 bool CANSocketBCM::unregisterMessageForReceive(int canId)
268 struct bcm_msg_head hdr;
270 // fill in the header
271 memset(&hdr, 0, sizeof(hdr));
272 hdr.opcode = RX_DELETE;
276 ssize_t nbytes = ::write(mSocket, &hdr, sizeof(hdr));
277 return nbytes == sizeof(hdr);