/* PIP - Platform Independent Primitives SPI 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 "pispi.h" #include "piincludes_p.h" #include "pipropertystorage.h" #ifdef LINUX # define PIP_SPI #endif #ifdef PIP_SPI # include # include # include #endif PRIVATE_DEFINITION_START(PISPI) #ifdef PIP_SPI int fd; spi_ioc_transfer spi_ioc_tr; #endif PRIVATE_DEFINITION_END(PISPI) REGISTER_DEVICE(PISPI) PISPI::PISPI(const PIString & path, uint speed, PIIODevice::DeviceMode mode): PIIODevice(path, mode) { #ifdef MICRO_PIP setThreadedReadBufferSize(512); #else setThreadedReadBufferSize(1024); #endif setPath(path); setSpeed(speed); setBits(8); spi_mode = 0; if (mode == ReadOnly) piCoutObj << "error, SPI can't work in ReadOnly mode"; #ifdef PIP_SPI PRIVATE->fd = 0; #endif } PISPI::~PISPI() { stop(); close(); } void PISPI::setSpeed(uint speed_hz) { spi_speed = speed_hz; } void PISPI::setBits(uchar bits) { spi_bits = bits; } void PISPI::setParameter(PISPI::Parameters parameter, bool on) { PIFlags cp = (PIFlags)spi_mode; cp.setFlag(parameter, on); spi_mode = (int)cp; } bool PISPI::isParameterSet(PISPI::Parameters parameter) const { PIFlags cp = (PIFlags)spi_mode; return cp[parameter]; } ssize_t PISPI::bytesAvailable() const { return recv_buf.size(); } bool PISPI::openDevice() { #ifdef PIP_SPI int ret = 0; // piCoutObj << "open device" << path(); PRIVATE->fd = ::open(path().dataAscii(), O_RDWR); if (PRIVATE->fd < 0) { piCoutObj << "can't open device"; return false; } // piCoutObj << "set mode" << spi_mode; ret = ioctl(PRIVATE->fd, SPI_IOC_WR_MODE, &spi_mode); if (ret == -1) { piCoutObj << "can't set spi write mode"; return false; } // piCoutObj << "set bits" << spi_bits; ret = ioctl(PRIVATE->fd, SPI_IOC_WR_BITS_PER_WORD, &spi_bits); if (ret == -1) { piCoutObj << "can't set bits per word"; return false; } // piCoutObj << "set speed" << spi_speed; ret = ioctl(PRIVATE->fd, SPI_IOC_WR_MAX_SPEED_HZ, &spi_speed); if (ret == -1) { piCoutObj << "can't set max write speed hz"; return false; } piCoutObj << "SPI open" << path() << "speed:" << spi_speed / 1000 << "KHz" << "mode" << spi_mode << "bits" << spi_bits; PRIVATE->spi_ioc_tr.delay_usecs = 0; PRIVATE->spi_ioc_tr.speed_hz = 0; PRIVATE->spi_ioc_tr.bits_per_word = spi_bits; return true; #else piCoutObj << "PISPI not implemented on windows"; return false; #endif } bool PISPI::closeDevice() { #ifdef PIP_SPI if (PRIVATE->fd) ::close(PRIVATE->fd); #endif return true; } ssize_t PISPI::readDevice(void * read_to, ssize_t max_size) { ssize_t sz = piMini(recv_buf.size_s(), max_size); memcpy(read_to, recv_buf.data(), sz); recv_buf.remove(0, sz); return sz; } ssize_t PISPI::writeDevice(const void * data, ssize_t max_size) { #ifdef PIP_SPI if (max_size > 0) { if (tx_buf.size_s() != max_size) { tx_buf.resize(max_size); rx_buf.resize(max_size); PRIVATE->spi_ioc_tr.tx_buf = (ulong)(tx_buf.data()); PRIVATE->spi_ioc_tr.rx_buf = (ulong)(rx_buf.data()); PRIVATE->spi_ioc_tr.len = max_size; } memcpy(tx_buf.data(), data, max_size); int ret; // piCoutObj << "write" << max_size << tx_buf.size(); ret = ioctl(PRIVATE->fd, SPI_IOC_MESSAGE(1), &PRIVATE->spi_ioc_tr); if (ret < 1) { piCoutObj << "can't send spi message" << ret; return -1; } if (canRead()) recv_buf.append(rx_buf); if (recv_buf.size_s() > threadedReadBufferSize()) recv_buf.resize(threadedReadBufferSize()); return max_size; } #endif return 0; } PIString PISPI::constructFullPathDevice() const { PIString ret; ret += path() + ":" + PIString::fromNumber((int)speed()) + ":" + PIString::fromNumber((int)bits()) + ":" + PIString::fromNumber((int)parameters()); return ret; } void PISPI::configureFromFullPathDevice(const PIString & full_path) { PIStringList pl = full_path.split(":"); for (int i = 0; i < pl.size_s(); ++i) { PIString p(pl[i].trimmed()); switch (i) { case 0: setPath(p); break; case 1: setSpeed(p.toInt()); break; case 2: setBits(p.toInt()); break; case 3: setParameters(p.toInt()); break; default: break; } } } PIPropertyStorage PISPI::constructVariantDevice() const { PIPropertyStorage ret; ret.addProperty("path", path()); ret.addProperty("speed", int(speed())); ret.addProperty("bits", int(bits())); ret.addProperty("clock inverse", isParameterSet(ClockInverse)); ret.addProperty("clock phase shift", isParameterSet(ClockPhaseShift)); return ret; } void PISPI::configureFromVariantDevice(const PIPropertyStorage & d) { setPath(d.propertyValueByName("path").toString()); setSpeed(d.propertyValueByName("speed").toInt()); setBits(d.propertyValueByName("bits").toInt()); setParameter(ClockInverse, d.propertyValueByName("clock inverse").toBool()); setParameter(ClockPhaseShift, d.propertyValueByName("clock phase shift").toBool()); }