/* 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 . */ #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 # include # include # include # 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; sock = 0; } PICAN::~PICAN() { stop(); close(); } 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)); }