/** @file ConnectionManager.cpp @author Lime Microsystems (www.limemicro.com) @brief Implementation of various connection types to devices */ #include "ConnectionManager.h" #include "ConnectionCOM.h" #ifdef ENABLE_USB_CONNECTION #include "ConnectionUSB.h" #endif #ifdef ENABLE_SPI_CONNECTION #include "ConnectionSPI.h" #endif #include <sstream> #include <iomanip> #include <iostream> /** @brief Creates connection interfaces */ ConnectionManager::ConnectionManager(const IConnection::eConnectionType port_type) : activeControlPort(NULL) { mLogData = false; mOpenedDevice = -1; if (port_type == IConnection::COM_PORT) m_connections[IConnection::COM_PORT] = new ConnectionCOM(); #ifdef ENABLE_USB_CONNECTION if (port_type == IConnection::USB_PORT) m_connections[IConnection::USB_PORT] = new ConnectionUSB(); #endif #ifdef ENABLE_SPI_CONNECTION m_connections[IConnection::SPI_PORT] = new ConnectionSPI(); #endif } /** @brief Destroys connection interfaces */ ConnectionManager::~ConnectionManager() { for (auto iter = m_connections.begin(); iter != m_connections.end(); ++iter) { delete iter->second; } } /** @brief Checks if connection to device is opened @return True if device is connected */ bool ConnectionManager::IsOpen() { return activeControlPort ? activeControlPort->IsOpen() : false; } /** @brief Opens connection to first available device @return True if connected to device */ bool ConnectionManager::Open() { return Open(0); } /** @brief Connects to selected device @param i device index from device list @return 1:Success, 0:failure */ int ConnectionManager::Open(unsigned i) { if(i >= mDevices.size()) return 0; if(activeControlPort) activeControlPort->Close(); switch(mDevices[i].port) { case IConnection::COM_PORT: activeControlPort = m_connections[IConnection::COM_PORT]; break; case IConnection::USB_PORT: activeControlPort = m_connections[IConnection::USB_PORT]; break; case IConnection::SPI_PORT: activeControlPort = m_connections[IConnection::SPI_PORT]; break; default: return 0; } mOpenedDevice = -1; if( i < mDevices.size() ) { if (activeControlPort->Open(mDevices[i].portIndex) == IConnection::SUCCESS) { mOpenedDevice = i; return 1; } } return 0; } /** @brief Closes connection to device */ void ConnectionManager::Close() { if(activeControlPort) { activeControlPort->Close(); //Notify(LMS_Message(MSG_BOARD_DISCONNECTED, "", 0, 0)); } mOpenedDevice = -1; } /** @brief Finds all currently connected devices and forms device list @return number of devices found */ int ConnectionManager::RefreshDeviceList() { mDeviceList.clear(); mDevices.clear(); DeviceInfo dev; for (auto iter = m_connections.begin(); iter != m_connections.end(); ++iter) { vector<string> names; IConnection *port = iter->second; if(port->RefreshDeviceList() > 0) { names = port->GetDeviceNames(); for(unsigned i=0; i<names.size(); ++i) { dev.name = names[i]; dev.port = iter->first; dev.portIndex = i; mDevices.push_back(dev); } } } for(unsigned i=0; i<mDevices.size(); ++i) mDeviceList.push_back(mDevices[i].name); return mDevices.size(); } /** @brief Returns currently opened connection index */ int ConnectionManager::GetOpenedIndex() { return mOpenedDevice; } /** @brief Writes given data to currently opened connection @param buffer outcomming data buffer @param length bytes to write @param timeout_ms timeout in milliseconds @return number of bytes written, on failure negative values */ int ConnectionManager::Write(const unsigned char *buffer, const int length, int timeout_ms) { if(activeControlPort) { int bytesTransferred = activeControlPort->Write(buffer, length, timeout_ms); #ifndef NDEBUG if(mLogData) { stringstream ss; ss << "WR(" << (bytesTransferred>=0?bytesTransferred: 0) << "): "; ss << std::hex << std::setfill('0'); int repeatedZeros = 0; for(int i=length-1; i>=0; --i) if(buffer[i] == 0) ++repeatedZeros; else break; if(repeatedZeros == 1) repeatedZeros = 0; repeatedZeros = repeatedZeros - (repeatedZeros & 0x1); for(int i=0; i<length-repeatedZeros; ++i) //casting to short to print as numbers ss << " " << std::setw(2) << (unsigned short)buffer[i]; if(repeatedZeros > 1) ss << " (00 x " << std::dec << repeatedZeros << " times)"; cout << ss.str() << endl; #ifndef __unix__ OutputDebugString(ss.str().c_str()); #endif } #endif return bytesTransferred; } return -1; } /** @brief Receives data from currently opened connection @param buffer incomming data buffer, must be big enough for length bytes @param length bytes to read @param timeout_ms timeout in milliseconds @return number of bytes received */ int ConnectionManager::Read(unsigned char *buffer, int length, int timeout_ms) { if(activeControlPort) { int bytesTransferred = activeControlPort->Read(buffer, length, timeout_ms); #ifndef NDEBUG if(mLogData) { stringstream ss; ss << "RD(" << (bytesTransferred>=0?bytesTransferred: 0) << "): "; ss << std::hex << std::setfill('0'); int repeatedZeros = 0; for(int i=length-1; i>=0; --i) if(buffer[i] == 0) ++repeatedZeros; else break; if(repeatedZeros == 2) repeatedZeros = 0; repeatedZeros = repeatedZeros - (repeatedZeros & 0x1); for(int i=0; i<length-repeatedZeros; ++i) //casting to short to print as numbers ss << " " << std::setw(2) << (unsigned short)buffer[i]; if(repeatedZeros > 2) ss << " (00 x " << std::dec << repeatedZeros << " times)"; cout << ss.str() << endl; } #endif return bytesTransferred; } return -1; } int ConnectionManager::WriteStream(const char *buffer, int length) { return 0; } int ConnectionManager::ReadStream(char *buffer, int length, unsigned int timeout_ms) { /*int handle = activeControlPort->BeginDataReading(buffer, length); activeControlPort->WaitForReading(handle, timeout_ms); long received = length; activeControlPort->FinishDataReading(buffer, received, handle); return received; */ long len = length; int status = activeControlPort->ReadDataBlocking(buffer, len, 0); return len; } int ConnectionManager::BeginDataReading(char *buffer, long length) { return activeControlPort->BeginDataReading(buffer, length); } /** @brief Blocks until data is received or set number of milliseconds have passed. @param contextHandle handle returned by BeginDataReading() @param timeout_ms number of milliseconds to wait @return 1-data received, 0-data not received */ int ConnectionManager::WaitForReading(int contextHandle, unsigned int timeout_ms) { return activeControlPort->WaitForReading(contextHandle, timeout_ms); } /** @brief Finished asynchronous data reading. @param buffer where to put received data @param length number of bytes to read, will be changed to actual number of bytes received @param contextHandle context handle returned by BeginDataReading() @return received data length */ int ConnectionManager::FinishDataReading(char *buffer, long &length, int contextHandle) { return activeControlPort->FinishDataReading(buffer, length, contextHandle); } /** @brief Aborts reading operations */ void ConnectionManager::AbortReading() { activeControlPort->AbortReading(); } /** @brief Start asynchronous data sending. @param buffer data buffer to be sent @param length number of bytes to send. @return context handle */ int ConnectionManager::BeginDataSending(const char *buffer, long length) { return activeControlPort->BeginDataSending(buffer, length); } /** @brief Blocks until data is sent or set number of miliseconds have passed. @param contextHandle handle returned by BeginDataReading() @param timeout_ms number of miliseconds to wait @return 1-data sent, 0-data not sent */ int ConnectionManager::WaitForSending(int contextHandle, unsigned int timeout_ms) { return activeControlPort->WaitForSending(contextHandle, timeout_ms); } /** @brief Finished asynchronous data sending. @param buffer where to put received data @param length number of bytes to send, will be changed to actual number of bytes sent @param contextHandle context handle returned by BeginDataReading() @return sent data length */ int ConnectionManager::FinishDataSending(const char *buffer, long &length, int contextHandle) { return activeControlPort->FinishDataSending(buffer, length, contextHandle); } /** @brief Aborts sending operations */ void ConnectionManager::AbortSending() { activeControlPort->AbortSending(); }