Files
openairinterface5g/targets/ARCH/LMSSDR/USERSPACE/LIB/lms7002m/connectionManager/ConnectionSPI.cpp
T

291 lines
6.6 KiB
C++

/**
@file ConnectionSPI.cpp
@author Lime Microsystems (www.limemicro.com)
@brief Implementation of communications through SPI port
*/
#include "ConnectionSPI.h"
#include "string.h"
#ifdef __unix__
#include <fstream>
#include <errno.h>
#include <unistd.h>
#include <termios.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/ioctl.h>
#include <linux/types.h>
#include <linux/spi/spidev.h>
#include <linux/i2c-dev.h>
#endif // LINUX
#include <iostream>
#include <sstream>
const int ConnectionSPI::cSPI_BUF_SIZE = 128;
const int ConnectionSPI::cSPI_SPEED_HZ = 2000000;
/** @brief Tries to read EEPROM for Novena board signature
@return true if Novena board
*/
bool IsNovenaBoard()
{
#ifdef __unix__
char data[8];
int count = 6;
memset(data, 0, 8);
int addr = 0;
struct i2c_rdwr_ioctl_data session;
struct i2c_msg messages[2];
char set_addr_buf[2];
memset(set_addr_buf, 0, sizeof(set_addr_buf));
memset(data, 0, count);
set_addr_buf[0] = addr>>8;
set_addr_buf[1] = addr;
messages[0].addr = 0xac>>1;
messages[0].flags = 0;
messages[0].len = sizeof(set_addr_buf);
messages[0].buf = set_addr_buf;
messages[1].addr = 0xac>>1;
messages[1].flags = I2C_M_RD;
messages[1].len = count;
messages[1].buf = data;
session.msgs = messages;
session.nmsgs = 2;
bool isNovena = false;
int fd = open("/dev/i2c-2", O_RDWR);
if(fd > 0)
{
if(ioctl(fd, I2C_RDWR, &session) < 0)
{
perror("Unable to communicate with i2c device");
isNovena = false;
}
if(strcmp("Novena", data) == 0)
isNovena = true;
}
close(fd);
return isNovena;
#else
return false;
#endif
}
/** @brief Initializes SPI port and exports needed GPIO
*/
ConnectionSPI::ConnectionSPI()
{
fd = -1;
m_connectionType = SPI_PORT;
std::fstream gpio;
//export SEN pin
gpio.open("/sys/class/gpio/export", ios::out);
if(gpio.good())
{
gpio << 122;
gpio.flush();
gpio.close();
gpio.open("/sys/class/gpio/gpio122/direction", ios::out);
gpio << "out";
gpio.flush();
gpio.close();
m_SEN.open("/sys/class/gpio/gpio122/value", ios::out);
m_SEN<< 1;
m_SEN.flush();
cout << "GPIO122: set to 1" << endl;
}
}
ConnectionSPI::~ConnectionSPI()
{
Close();
m_SEN.close();
}
/** @brief Opens connection to first found chip
@return 0-success
*/
IConnection::DeviceStatus ConnectionSPI::Open()
{
Close();
#ifdef __unix__
fd = open("/dev/spidev2.0", O_RDWR | O_SYNC);
if (fd < 0)
{
//MessageLog::getInstance()->write("SPI PORT: device not found\n", LOG_ERROR);
return IConnection::FAILURE;
}
int mode = SPI_MODE_0;
int ret = ioctl(fd, SPI_IOC_WR_MODE, &mode);
if (ret == -1)
printf("can't set spi mode");
ret = ioctl(fd, SPI_IOC_RD_MODE, &mode);
if (ret == -1)
printf("can't get spi mode");
/*
* bits per word
*/
int bits = 8;
ret = ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &bits);
if (ret == -1)
printf("can't set bits per word");
ret = ioctl(fd, SPI_IOC_RD_BITS_PER_WORD, &bits);
if (ret == -1)
printf("can't get bits per word");
/*
* max speed hz
*/
int speed = cSPI_SPEED_HZ;
ret = ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed);
if (ret == -1)
printf("can't set max speed hz");
ret = ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ, &speed);
if (ret == -1)
printf("can't get max speed hz");
printf("spi mode: 0x%x\n", mode);
printf("bits per word: %d\n", bits);
printf("max speed: %d Hz (%d KHz)\n", speed, speed/1000);
return IConnection::SUCCESS;
#else
return IConnection::FAILURE;
#endif
}
/** @brief Opens connection to selected chip
@param index chip index in device list
@return 0-success
*/
IConnection::DeviceStatus ConnectionSPI::Open(unsigned index)
{
return Open();
}
/** @brief Closes connection to chip
*/
void ConnectionSPI::Close()
{
#ifdef __unix__
close(fd);
fd = -1;
#endif
}
/** @brief Returns whether chip is connected
@return chip is connected
*/
bool ConnectionSPI::IsOpen()
{
return (fd >= 0);
}
/** @brief Sends data through SPI port
@param buffer data buffer to send
@param length size of data buffer
@param timeout_ms timeout limit for operation in milliseconds
@return Number of bytes sent
*/
int ConnectionSPI::Write(const unsigned char *buffer, int length, int timeout_ms)
{
#ifdef __unix__
if(fd < 0)
return 0;
m_SEN << 0;
m_SEN.flush();
unsigned long bytesWritten = 0;
rxbuf.clear();
int bytesReceived = 0;
char rxbytes[2];
while(bytesWritten < length)
{
int toWrite = length-bytesWritten > cSPI_BUF_SIZE ? cSPI_BUF_SIZE : length-bytesWritten;
for(int i=0; i<toWrite; i+=2)
{
if(buffer[i] < 0x80) //reading
{
write(fd, &buffer[i+bytesWritten], 2);
bytesReceived += read(fd, rxbytes, 2);
rxbuf.push_back(rxbytes[0]);
rxbuf.push_back(rxbytes[1]);
}
else //writing
{
write(fd, &buffer[i+bytesWritten], 4);
i+=2; //data bytes have been written
}
}
bytesWritten += toWrite;
}
m_SEN << 1;
m_SEN.flush();
return bytesWritten;
#else
return 0;
#endif
}
/** @brief Reads data from SPI port
@param buffer pointer to data buffer for receiving
@param length number of bytes to read
@param timeout_ms timeout limit for operation in milliseconds
@return Number of bytes received
*/
int ConnectionSPI::Read(unsigned char *buffer, int length, int timeout_ms)
{
#ifdef __unix__
if(fd < 0)
return 0;
//because transfer is done in full duplex, function returns data from last transfer
int tocpy = length > rxbuf.size() ? rxbuf.size() : length;
memcpy(buffer, &rxbuf[0], tocpy);
rxbuf.clear();
return tocpy;
#else
return 0;
#endif
}
/** @brief Finds SPI port
@return number of devices found
*/
int ConnectionSPI::RefreshDeviceList()
{
m_deviceNames.clear();
#ifdef __unix__
int spidev = open("/dev/spidev2.0", O_RDWR);
if (spidev >= 0)
{
if(IsNovenaBoard() == true)
m_deviceNames.push_back("SPI (Novena)");
else
m_deviceNames.push_back("SPI");
}
close(spidev);
#endif
return m_deviceNames.size();
}
/** @brief Returns found devices names
@return vector of device names
*/
vector<string> ConnectionSPI::GetDeviceNames()
{
return m_deviceNames;
}
int ConnectionSPI::GetOpenedIndex()
{
return 0;
}