174 lines
4.3 KiB
C++
174 lines
4.3 KiB
C++
/*
|
|
PIP - Platform Independent Primitives
|
|
CAN
|
|
Andrey Bychkov work.a.b@yandex.ru
|
|
|
|
This program is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU Lesser General Public License as published by
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU Lesser General Public License for more details.
|
|
|
|
You should have received a copy of the GNU Lesser General Public License
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
#include "pican.h"
|
|
#include "pipropertystorage.h"
|
|
#include "piincludes_p.h"
|
|
#if !defined(WINDOWS) && !defined(MAC_OS) && !defined(FREERTOS)
|
|
# define PIP_CAN
|
|
#endif
|
|
#ifdef PIP_CAN
|
|
# include <sys/ioctl.h>
|
|
# include <net/if.h>
|
|
# include <linux/can.h>
|
|
# include <linux/can/raw.h>
|
|
# ifndef AF_CAN
|
|
# define AF_CAN 29
|
|
# endif
|
|
# ifndef PF_CAN
|
|
# define PF_CAN AF_CAN
|
|
# endif
|
|
#endif
|
|
|
|
|
|
REGISTER_DEVICE(PICAN)
|
|
|
|
|
|
PICAN::PICAN(const PIString & path, PIIODevice::DeviceMode mode) : PIIODevice(path, mode) {
|
|
setThreadedReadBufferSize(256);
|
|
setPath(path);
|
|
can_id = 0;
|
|
}
|
|
|
|
|
|
bool PICAN::openDevice() {
|
|
#ifdef PIP_CAN
|
|
piCout << "PICAN open device" << path();
|
|
sock = socket(PF_CAN, SOCK_RAW, CAN_RAW);
|
|
if(sock < 0){
|
|
piCoutObj << "Error! while opening socket";
|
|
return false;
|
|
}
|
|
ifreq ifr;
|
|
strcpy(ifr.ifr_name, path().dataAscii());
|
|
piCout << "PICAN try to get interface index...";
|
|
if(ioctl(sock, SIOCGIFINDEX, &ifr) < 0){
|
|
piCoutObj << "Error! while determin the interface ioctl";
|
|
return false;
|
|
}
|
|
struct timeval tv;
|
|
tv.tv_sec = 1;
|
|
tv.tv_usec = 0;
|
|
setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (const char*)&tv, sizeof tv);
|
|
// bind socket to all CAN interface
|
|
sockaddr_can addr;
|
|
addr.can_family = AF_CAN;
|
|
addr.can_ifindex = ifr.ifr_ifindex;
|
|
piCout << "PICAN try to bind socket to interface" << ifr.ifr_ifindex;
|
|
if(bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0){
|
|
piCoutObj << "Error! while binding socket";
|
|
return false;
|
|
}
|
|
piCout << "PICAN Open OK!";
|
|
return true;
|
|
#else
|
|
piCoutObj << "PICAN not implemented on windows";
|
|
return false;
|
|
#endif
|
|
}
|
|
|
|
|
|
bool PICAN::closeDevice() {
|
|
#ifdef PIP_CAN
|
|
if (sock > 0) ::close(sock);
|
|
#endif
|
|
return true;
|
|
}
|
|
|
|
|
|
int PICAN::readDevice(void * read_to, int max_size) {
|
|
#ifdef PIP_CAN
|
|
//piCout << "PICAN read";
|
|
can_frame frame;
|
|
int ret = 0;
|
|
ret = ::read(sock, &frame, sizeof(can_frame));
|
|
if(ret < 0) {/*piCoutObj << "Error while read CAN frame " << ret;*/ return -1;}
|
|
//piCoutObj << "receive CAN frame Id =" << frame.can_id;
|
|
memcpy(read_to, frame.data, piMini(frame.can_dlc, max_size));
|
|
readed_id = frame.can_id;
|
|
return piMini(frame.can_dlc, max_size);
|
|
#endif
|
|
return 0;
|
|
}
|
|
|
|
|
|
int PICAN::writeDevice(const void * data, int max_size) {
|
|
#ifdef PIP_CAN
|
|
//piCout << "PICAN write" << can_id << max_size;
|
|
if (max_size > 8) {piCoutObj << "Can't send CAN frame bigger than 8 bytes (requested " << max_size << ")!"; return -1;}
|
|
can_frame frame;
|
|
frame.can_id = can_id;
|
|
frame.can_dlc = max_size;
|
|
memcpy(frame.data, data, max_size);
|
|
int ret = 0;
|
|
ret = ::write(sock, &frame, sizeof(can_frame));
|
|
if(ret < 0) {piCoutObj << "Error while send CAN frame " << ret; return -1;}
|
|
return max_size;
|
|
#endif
|
|
return 0;
|
|
}
|
|
|
|
|
|
void PICAN::setCANID(int id) {
|
|
can_id = id;
|
|
}
|
|
|
|
|
|
int PICAN::CANID() const {
|
|
return can_id;
|
|
}
|
|
|
|
|
|
int PICAN::readedCANID() const {
|
|
return readed_id;
|
|
}
|
|
|
|
|
|
PIString PICAN::constructFullPathDevice() const {
|
|
PIString ret;
|
|
ret << path() << ":" << PIString::fromNumber(CANID(),16);
|
|
return ret;
|
|
}
|
|
|
|
|
|
void PICAN::configureFromFullPathDevice(const PIString & full_path) {
|
|
PIStringList pl = full_path.split(":");
|
|
for (int i = 0; i < pl.size_s(); ++i) {
|
|
PIString p(pl[i]);
|
|
switch (i) {
|
|
case 0: setPath(p); break;
|
|
case 1: setCANID(p.toInt(16)); break;
|
|
default: break;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
PIPropertyStorage PICAN::constructVariantDevice() const {
|
|
PIPropertyStorage ret;
|
|
ret.addProperty("path", path());
|
|
ret.addProperty("CAN ID", PIString::fromNumber(CANID(),16));
|
|
return ret;
|
|
}
|
|
|
|
|
|
void PICAN::configureFromVariantDevice(const PIPropertyStorage & d) {
|
|
setPath(d.propertyValueByName("path").toString());
|
|
setCANID(d.propertyValueByName("CAN ID").toString().toInt(16));
|
|
}
|