/* 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 "piwaitevent_p.h" #if !defined(WINDOWS) && !defined(MAC_OS) && !defined(MICRO_PIP) # 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) PRIVATE_DEFINITION_START(PICAN) PIWaitEvent event; PRIVATE_DEFINITION_END(PICAN) PICAN::PICAN(const PIString & path, PIIODevice::DeviceMode mode): PIIODevice(path, mode) { setThreadedReadBufferSize(256); setPath(path); can_id = 0; sock = 0; PRIVATE->event.create(); } PICAN::~PICAN() { stopAndWait(); close(); PRIVATE->event.destroy(); } 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 interrupt(); if (sock > 0) ::close(sock); #endif return true; } ssize_t PICAN::readDevice(void * read_to, ssize_t max_size) { #ifdef PIP_CAN // piCout << "PICAN read"; can_frame frame; ssize_t ret = 0; if (PRIVATE->event.wait(sock)) 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; } ssize_t PICAN::writeDevice(const void * data, ssize_t 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); ssize_t 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; } void PICAN::interrupt() { PRIVATE->event.interrupt(); } 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.trimmed().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)); }