diff options
author | Karin Hedlund <karin.hedlund@stericsson.com> | 2011-05-20 16:56:58 +0200 |
---|---|---|
committer | Karin Hedlund <karin.hedlund@stericsson.com> | 2011-05-20 16:56:58 +0200 |
commit | b76c2437f1017bda4879a3a8ee6ddd00fdb5c281 (patch) | |
tree | fc3873776155e1d5ff021ae9370264d226893c69 /CDAL |
Initial commit
Diffstat (limited to 'CDAL')
-rwxr-xr-x | CDAL/AsyncCommunication.cpp | 177 | ||||
-rwxr-xr-x | CDAL/AsyncCommunication.h | 61 | ||||
-rwxr-xr-x | CDAL/CDAL.cpp | 223 | ||||
-rwxr-xr-x | CDAL/CDAL.h | 76 | ||||
-rwxr-xr-x | CDAL/CDAL.mk | 70 | ||||
-rwxr-xr-x | CDAL/CommDevice.cpp | 44 | ||||
-rwxr-xr-x | CDAL/CommDevice.h | 52 | ||||
-rwxr-xr-x | CDAL/CommDeviceManager.cpp | 56 | ||||
-rwxr-xr-x | CDAL/CommDeviceManager.h | 80 | ||||
-rwxr-xr-x | CDAL/CommException.cpp | 38 | ||||
-rwxr-xr-x | CDAL/CommException.h | 29 | ||||
-rwxr-xr-x | CDAL/Debug.h | 94 | ||||
-rwxr-xr-x | CDAL/LibusbDevice.cpp | 149 | ||||
-rwxr-xr-x | CDAL/LibusbDevice.h | 42 |
14 files changed, 1191 insertions, 0 deletions
diff --git a/CDAL/AsyncCommunication.cpp b/CDAL/AsyncCommunication.cpp new file mode 100755 index 0000000..e767a61 --- /dev/null +++ b/CDAL/AsyncCommunication.cpp @@ -0,0 +1,177 @@ +/* + * AsyncCommunication.cpp + * + * Copyright (C) ST-Ericsson SA 2011 + * Authors: Srimanta Panda <srimanta.panda@stericsson.com>, + * Ola Borgelin <ola.borgelin@stericsson.com>, + * Karin Hedlund <karin.hedlund@stericsson.com>, + * Markus Andersson <markus.m.andersson@stericsson.com> for ST-Ericsson. + * License terms: 3-clause BSD license + * + */ + +#include "AsyncCommunication.h" +#include "CommDevice.h" +#include "Debug.h" + +AsyncCommunication::AsyncCommunication(CommDevice* device): + device_(device) +{ + isReadInvoked_ = false; + isWriteInvoked_ = false; + + readRequest_.isActive = false; + readRequest_.isShutdown = false; + readRequest_.callback = NULL; + + writeRequest_.isActive = false; + writeRequest_.isShutdown = false; + writeRequest_.callback = NULL; + + readerThread_ = new Thread(AsyncCommunication::threadReadProc, this); + writerThread_ = new Thread(AsyncCommunication::threadWriteProc, this); +} + +AsyncCommunication::~AsyncCommunication(void) +{ + readRequest_.isShutdown = true; + readRequestEvent_.signal(); + writeRequest_.isShutdown = true; + writeRequestEvent_.signal(); + readerThread_->wait(); + writerThread_->wait(); + delete readerThread_; + delete writerThread_; +} + +int AsyncCommunication::readNoWait(void* buf, int len, DataCallback_t fn, void* param) +{ + int res = -1; + CSLock lock(&readCs_); + + do { + if (readRequest_.isActive) + break; + + readRequest_.buf = buf; + readRequest_.length = len; + readRequest_.isActive = true; + readRequest_.callback = fn; + readRequest_.param = param; + readRequestEvent_.signal(); + res = 0; + } while (0); + + return res; +} + +int AsyncCommunication::writeNoWait(void* buf, int len, DataCallback_t fn, void* param) +{ + int res = -1; + CSLock lock(&writeCs_); + + do { + if (writeRequest_.isActive) + break; + + writeRequest_.buf = buf; + writeRequest_.length = len; + writeRequest_.isActive = true; + writeRequest_.callback = fn; + writeRequest_.param = param; + writeRequestEvent_.signal(); + res = 0; + } while (0); + + return res; +} + +void* AsyncCommunication::threadReadProc(void* param) +{ + AsyncCommunication* asyncComm = (AsyncCommunication*)param; + + while (1) { + asyncComm->readRequestEvent_.wait(); + + if (asyncComm->readRequest_.isShutdown) { + Debug::info("read thread: shutdown requested"); + return 0; + } + + asyncComm->readCs_.enter(); + unsigned char* destBuf = static_cast<unsigned char*>(asyncComm->readRequest_.buf); + int length = asyncComm->readRequest_.length; + void* param = asyncComm->readRequest_.param; + DataCallback_t callback = asyncComm->readRequest_.callback; + asyncComm->readCs_.leave(); + + int readResult = asyncComm->device_->read(destBuf, length); + + asyncComm->readCs_.enter(); + asyncComm->readRequest_.isActive = false; + asyncComm->readCs_.leave(); + + if (readResult != CommDevice::COMM_DEVICE_SUCCESS) { + if (readResult == CommDevice::COMM_DEVICE_CANCEL) { + asyncComm->readCanceledEvent_.signal(); + } + + // if error occurs ignore the current request and wait for next one + // LCM should send the same request again after timeout + continue; + } + + if (callback) { + Debug::hexdump("read", destBuf, length); + callback(destBuf, length, param); + } + } + + return 0; +} + +void* AsyncCommunication::threadWriteProc(void *param) +{ + AsyncCommunication* asyncComm = (AsyncCommunication*)param; + + while (1) { + asyncComm->writeRequestEvent_.wait(); + + if (asyncComm->writeRequest_.isShutdown) { + Debug::info("write thread: shutdown requested"); + return 0; + } + + asyncComm->writeCs_.enter(); + unsigned char* srcBuf = static_cast<unsigned char*>(asyncComm->writeRequest_.buf); + int len = asyncComm->writeRequest_.length; + void* localParam = asyncComm->writeRequest_.param; + DataCallback_t callback = asyncComm->writeRequest_.callback; + asyncComm->writeCs_.leave(); + + int writeResult = asyncComm->device_->write(srcBuf, len); + + asyncComm->writeCs_.enter(); + asyncComm->writeRequest_.isActive = false; + asyncComm->writeCs_.leave(); + + if (writeResult != CommDevice::COMM_DEVICE_SUCCESS) { + // if error occurs ignore the current request and wait for next one + // LCM should send the same request again after timeout + continue; + } + + if (callback) { + Debug::hexdump("write", srcBuf, len); + callback(srcBuf, len, localParam); + } + } + + return 0; +} + +void AsyncCommunication::waitReadCanceled() +{ + readCanceledEvent_.wait(); + Debug::info("AsyncCommunication waitReadCanceled finished"); +} diff --git a/CDAL/AsyncCommunication.h b/CDAL/AsyncCommunication.h new file mode 100755 index 0000000..36ce5c7 --- /dev/null +++ b/CDAL/AsyncCommunication.h @@ -0,0 +1,61 @@ +/* + * AsyncCommunication.h + * + * Copyright (C) ST-Ericsson SA 2011 + * Authors: Srimanta Panda <srimanta.panda@stericsson.com>, + * Ola Borgelin <ola.borgelin@stericsson.com>, + * Karin Hedlund <karin.hedlund@stericsson.com>, + * Markus Andersson <markus.m.andersson@stericsson.com> for ST-Ericsson. + * License terms: 3-clause BSD license + * + */ + +#pragma once + +#include "CDAL.h" +#include "Event.h" +#include "Thread.h" +#include "CriticalSection.h" + +struct commRequest { + void* buf; + int length; + DataCallback_t callback; + void* param; + bool isShutdown; + bool isActive; +}; + +class AsyncCommunication +{ +public: + AsyncCommunication(CommDevice* device); + ~AsyncCommunication(); + + int readNoWait(void* buf, int len, DataCallback_t fn, void* param); + int writeNoWait(void* buf, int len, DataCallback_t fn, void* param); + + bool isReadActive() { + return readRequest_.isActive; + } + void waitReadCanceled(); +private: + CommDevice* device_; + bool isReadInvoked_; + bool isWriteInvoked_; + + commRequest readRequest_; + CriticalSection readCs_; + + commRequest writeRequest_; + CriticalSection writeCs_; + + Thread* readerThread_; + static void* threadReadProc(void*); + Event readRequestEvent_; + Event readCanceledEvent_; + + Thread* writerThread_; + static void* threadWriteProc(void*); + Event writeRequestEvent_; +}; diff --git a/CDAL/CDAL.cpp b/CDAL/CDAL.cpp new file mode 100755 index 0000000..24ded12 --- /dev/null +++ b/CDAL/CDAL.cpp @@ -0,0 +1,223 @@ +/* + * CDAL.cpp + * + * Copyright (C) ST-Ericsson SA 2011 + * Authors: Srimanta Panda <srimanta.panda@stericsson.com>, + * Ola Borgelin <ola.borgelin@stericsson.com>, + * Karin Hedlund <karin.hedlund@stericsson.com>, + * Markus Andersson <markus.m.andersson@stericsson.com> for ST-Ericsson. + * License terms: 3-clause BSD license + * + */ + +#include "CDAL.h" +#include "Debug.h" +#include "CommDevice.h" +#include "CommDeviceManager.h" +#include "CommException.h" +#include "Event.h" +#include "Thread.h" +#include "LibusbDevice.h" +#include <libusb.h> +#include <vector> +#include <stdio.h> +#include <stdlib.h> +using namespace std; + +static int DUT_VENDOR_ID = 0x04cc; +static int DUT_PRODUCT_ID = 0x8500; +static libusb_context* context; +static Thread* workerThread; +static void* LibusbWorker(void* arg); +bool shutdown = false; +int error = 0; + +static EventCallback_t OnDeviceCallback = NULL; + +void usb_init_driver(const char* vendorId, const char* productId) +{ + if (vendorId != NULL && *vendorId != '\0') { + DUT_VENDOR_ID = strtol(vendorId, NULL, 16); + } + + if (productId != NULL && *productId != '\0') { + DUT_PRODUCT_ID = strtol(productId, NULL, 16); + } + + libusb_init(&context); + libusb_set_debug(context, 3); + + workerThread = new Thread(LibusbWorker, 0); +} + +void usb_set_listen_callback(EventCallback_t callback) +{ + OnDeviceCallback = callback; +} + +void usb_deinit_driver() +{ + shutdown = true; + workerThread->wait(); + delete workerThread; + + CommDeviceManager::destroyAll(); + + libusb_exit(context); +} + +void usb_destroy_device(Device_t device, int error_code) +{ + device->cancel(); + error = error_code; +} + +int comm_read(Device_t device, void* buffer, size_t size) +{ + return device->read(buffer, size); +} + +int comm_read_nowait(void* buffer, size_t size, DataCallback_t cb, void* param) +{ + CommDevice* device = CommDeviceManager::getDevice<CommDevice>(param); + + if (NULL != device) { + return device->readNoWait(buffer, size, cb, param); + } else { + return COMM_DEVICE_OBJECT_NOT_MAPPED; + } +} + +int comm_write(Device_t device, void* buffer, size_t size) +{ + return device->write(buffer, size); +} + +int comm_write_nowait(void* buffer, size_t size, DataCallback_t cb, void* param) +{ + CommDevice* device = CommDeviceManager::getDevice<CommDevice>(param); + + if (NULL != device) { + return device->writeNoWait(buffer, size, cb, param); + } else { + return COMM_DEVICE_OBJECT_NOT_MAPPED; + } +} + +int comm_cancel(void* param) +{ + CommDevice* device = CommDeviceManager::getDevice<CommDevice>(param); + + if (NULL != device) { + return device->cancel(); + } else { + return COMM_DEVICE_OBJECT_NOT_MAPPED; + } +} + +unsigned long comm_get_physical_address(Device_t device) +{ + return device->getPhysicalAddress(); +} + +void** comm_get_object_storage(Device_t device) +{ + return device->getObjectStorage(); +} + +void comm_progress(void *Communication_p, unsigned long long totalbytes, + unsigned long long tranferedbytes) +{ + double precentage = (tranferedbytes * 100) / totalbytes; + + printf("\r%.1f %% ", precentage); + fflush(stdout); +} + +static void* LibusbWorker(void* arg __attribute__((unused))) +{ + timespec delay; + delay.tv_sec = 0; + delay.tv_nsec = 10 * 1000000; // 10ms + libusb_device** deviceList; + ssize_t deviceCount; + libusb_device_descriptor descriptor; + + while (!shutdown) { + deviceCount = libusb_get_device_list(context, &deviceList); + + if (deviceCount < 0) { + nanosleep(&delay, 0); + continue; + } + + for (int i = 0; i != deviceCount; ++i) { + int status = libusb_get_device_descriptor(deviceList[i], + &descriptor); + + if (status != LIBUSB_SUCCESS) { + Debug::error( + "Libusb worker: error while getting device descriptor for device %d from %d devices", + i, deviceCount); + continue; + } + + if (descriptor.idVendor == DUT_VENDOR_ID && descriptor.idProduct + == DUT_PRODUCT_ID && (!shutdown)) { + LibusbDevice* device = CommDeviceManager::getDevice < + LibusbDevice, libusb_device* > (deviceList[i]); + + if (0 == device) { + // new device found + try { + device = CommDeviceManager::createDevice < LibusbDevice, + libusb_device* > (deviceList[i]); + Debug::info("Libusb worker: Connected libusb device"); + OnDeviceCallback(COMM_DEVICE_SUCCESS, + LIBUSB_DEVICE_CONNECTED, device); + } catch (CommException e) { + Debug::error("Libusb worker: %s", e.what()); + OnDeviceCallback(e.getError(), + COMM_DEVICE_UNDEFINED_EVENT, 0); + } + } + } + } + + vector<CommDevice*> devices = CommDeviceManager::getAllDevices(); + + for (vector<CommDevice*>::iterator i = devices.begin(); i + != devices.end(); ++i) { + LibusbDevice* device = dynamic_cast<LibusbDevice*>(*i); + + if (0 == device) { + continue; + } + + bool connected = false; + + for (int j = 0; j != deviceCount; ++j) { + if (deviceList[j] == device->getPort()) { + if (error == 0) + connected = true; + + break; + } + } + + if (!connected) { + Debug::info("Libusb worker: Disconnected device with id %d", *i); + OnDeviceCallback(COMM_DEVICE_SUCCESS, + LIBUSB_DEVICE_DISCONNECTED, *i); + shutdown = true; + } + } + + libusb_free_device_list(deviceList, 1); + + nanosleep(&delay, 0); + } + + return 0; +} + diff --git a/CDAL/CDAL.h b/CDAL/CDAL.h new file mode 100755 index 0000000..d87b79b --- /dev/null +++ b/CDAL/CDAL.h @@ -0,0 +1,76 @@ +/* + * CDAL.h + * + * Copyright (C) ST-Ericsson SA 2011 + * Authors: Srimanta Panda <srimanta.panda@stericsson.com>, + * Ola Borgelin <ola.borgelin@stericsson.com>, + * Karin Hedlund <karin.hedlund@stericsson.com>, + * Markus Andersson <markus.m.andersson@stericsson.com> for ST-Ericsson. + * License terms: 3-clause BSD license + * + * CDAL API is implementation of communication device abstraction library, + * which adapts the usb driver interface. This device communication abstraction + * library is used to communicate with the device through the communication + * channel. + */ +#pragma once +#include <cstddef> +#ifdef CDAL_EXPORTS +#define CDAL_API __attribute__((visibility("default"))) +#else +#define CDAL_API +#endif + +// type of the device +typedef enum { + USB_DEVICE, + UART_DEVICE, + UNKNOWN_DEVICE +} DeviceType_t; + +// error status codes +typedef enum { + COMM_DEVICE_SUCCESS = 0, + COMM_DEVICE_GENERAL_ERROR = 1, + COMM_DEVICE_UNSUPPORTED_OPERATION = 2, + COMM_DEVICE_OBJECT_NOT_MAPPED = 3, + COMM_DEVICE_UART_FAILED_TO_OPEN_PORT = 4, + COMM_DEVICE_UART_FAILED_TO_CONFIGURE_PORT = 5, + COMM_DEVICE_LIBUSB_FAILED_TO_OPEN_PORT = 6, + COMM_DEVICE_LIBUSB_FAILED_TO_CLAIM_INTERFACE = 7, + COMM_DEVICE_PEEK_BUFFER_SIZE_ERROR = 8 +} DeviceStatus_t; + +// device events codes +typedef enum { + COMM_DEVICE_UNDEFINED_EVENT = -1, + MEFLASH_DEVICE_CONNECTED = 0, + MEFLASH_DEVICE_DISCONNECTED = 1, + LIBUSB_DEVICE_CONNECTED = 2, + LIBUSB_DEVICE_DISCONNECTED = 3, + NOMADIK_DEVICE_CONNECTED = 4, + NOMADIK_DEVICE_DISCONNECTED = 5 +} DeviceEvent_t; + +typedef struct CommDevice* Device_t; + +// event and id parameters are valid only if status is 0 (COMM_DEVICE_SUCCESS) +typedef void (*EventCallback_t)(DeviceStatus_t status, DeviceEvent_t event, Device_t id); + +typedef void (*DataCallback_t)(void* buffer, size_t len, void* param); + +extern "C" { + CDAL_API void usb_init_driver(const char* vendorID, const char* productID); + CDAL_API void usb_set_listen_callback(EventCallback_t callback); + CDAL_API void usb_deinit_driver(); + CDAL_API void usb_destroy_device(Device_t device, int error_code); + + CDAL_API int comm_read(Device_t device, void* buffer, size_t size); + CDAL_API int comm_read_nowait(void* buffer, size_t size, DataCallback_t cb, void* param); + CDAL_API int comm_write(Device_t device, void* buffer, size_t len); + CDAL_API int comm_write_nowait(void* buffer, size_t size, DataCallback_t cb, void* param); + CDAL_API int comm_cancel(void* param); + CDAL_API unsigned long comm_get_physical_address(Device_t device); + CDAL_API void** comm_get_object_storage(Device_t device); + CDAL_API void comm_progress(void *Communication_p, unsigned long long totalbytes, unsigned long long tranferedbytes); +} diff --git a/CDAL/CDAL.mk b/CDAL/CDAL.mk new file mode 100755 index 0000000..e324b7d --- /dev/null +++ b/CDAL/CDAL.mk @@ -0,0 +1,70 @@ +# Makefile - CDAL + +CXX=g++ +INCLUDE=-I../os_wrappers -fPIC -I/usr/include/libusb-1.0 +CFLAGS=-g $(INCLUDE) +CXXFLAGS=$(CFLAGS) +LIBS= -shared -lstdc++ -lusb-1.0 +LD=$(CXX) $(CXXFLAGS) + +ifndef TARGET +TARGET=libcdal.so +endif + +.PHONY: all +all: $(TARGET) + +%.o: %.cpp + $(CXX) $(CXXFLAGS) $(CPPFLAGS) -o $@ -c $^ + +SOURCE_FILES= \ + ./AsyncCommunication.cpp \ + ./CDAL.cpp \ + ./CommDevice.cpp \ + ./CommDeviceManager.cpp \ + ./CommException.cpp \ + ./LibusbDevice.cpp \ + ../os_wrappers/CriticalSection.cpp \ + ../os_wrappers/Event.cpp \ + ../os_wrappers/Thread.cpp \ + +HEADER_FILES= \ + ./AsyncCommunication.h \ + ./CDAL.h \ + ./CommDevice.h \ + ./CommDeviceManager.h \ + ./CommException.h \ + ./LibusbDevice.h \ + ./Debug.h \ + ../os_wrappers/CriticalSection.h \ + ../os_wrappers/Event.h \ + ../os_wrappers/Thread.h \ + ../os_wrappers/Utilities.h + +OBJS= \ + ./AsyncCommunication.o \ + ./CDAL.o \ + ./CommDevice.o \ + ./CommDeviceManager.o \ + ./CommException.o \ + ./LibusbDevice.o \ + ../os_wrappers/CriticalSection.o \ + ../os_wrappers/Event.o \ + ../os_wrappers/Thread.o \ + + +SRCS=$(SOURCE_FILES) $(HEADER_FILES) + +$(TARGET): $(OBJS) + $(LD) $(LDFLAGS) -o $@ $(OBJS) $(LIBS) + +.PHONY: clean +clean: + -rm -f -v $(OBJS) $(TARGET) CDAL.dep *.orig + +.PHONY: depends +depends: + -$(CXX) $(CXXFLAGS) $(CPPFLAGS) -MM $(filter %.c %.cc %.cpp %.cxx,$(SRCS)) > CDAL.dep + +-include CDAL.dep + diff --git a/CDAL/CommDevice.cpp b/CDAL/CommDevice.cpp new file mode 100755 index 0000000..d4c1f71 --- /dev/null +++ b/CDAL/CommDevice.cpp @@ -0,0 +1,44 @@ +/* + * CommDevice.cpp + * + * Copyright (C) ST-Ericsson SA 2011 + * Authors: Srimanta Panda <srimanta.panda@stericsson.com>, + * Ola Borgelin <ola.borgelin@stericsson.com>, + * Karin Hedlund <karin.hedlund@stericsson.com>, + * Markus Andersson <markus.m.andersson@stericsson.com> for ST-Ericsson. + * License terms: 3-clause BSD license + * + */ + +#include "CommDevice.h" +#include "AsyncCommunication.h" + +CommDevice::CommDevice(): isReadCanceled_(false) +{ + async_ = new AsyncCommunication(this); +} + +CommDevice::~CommDevice() +{ + delete async_; +} + +int CommDevice::readNoWait(void *buffer, size_t size, DataCallback_t cb, void *param) +{ + return async_->readNoWait(buffer, size, cb, param); +} + +int CommDevice::writeNoWait(void *buffer, size_t size, DataCallback_t cb, void *param) +{ + return async_->writeNoWait(buffer, size, cb, param); +} + +int CommDevice::cancel() +{ + if (async_->isReadActive()) { + isReadCanceled_ = true; + async_->waitReadCanceled(); + } + + return 0; +} diff --git a/CDAL/CommDevice.h b/CDAL/CommDevice.h new file mode 100755 index 0000000..98979fe --- /dev/null +++ b/CDAL/CommDevice.h @@ -0,0 +1,52 @@ +/* + * CommDevice.h + * + * Copyright (C) ST-Ericsson SA 2011 + * Authors: Srimanta Panda <srimanta.panda@stericsson.com>, + * Ola Borgelin <ola.borgelin@stericsson.com>, + * Karin Hedlund <karin.hedlund@stericsson.com>, + * Markus Andersson <markus.m.andersson@stericsson.com> for ST-Ericsson. + * License terms: 3-clause BSD license + * + */ + +#pragma once + +#include "AsyncCommunication.h" +#include "CDAL.h" +#include <cstring> + +struct CommDevice { +public: + enum Status { + COMM_DEVICE_SUCCESS, + COMM_DEVICE_CANCEL, + COMM_DEVICE_ERROR, + COMM_DEVICE_CLOSED + }; + + CommDevice(); + virtual ~CommDevice(); + + virtual int read(void* buffer, size_t size) = 0; + int readNoWait(void* buffer, size_t size, DataCallback_t cb, void* param); + + virtual int write(void* buffer, size_t size) = 0; + int writeNoWait(void* buffer, size_t size, DataCallback_t cb, void* param); + + int cancel(); + + virtual unsigned long getPhysicalAddress() = 0; + + void* getObject() { + return object_; + } + void** getObjectStorage() { + return &object_; + } +protected: + bool isReadCanceled_; +private: + void* object_; + AsyncCommunication* async_; +}; diff --git a/CDAL/CommDeviceManager.cpp b/CDAL/CommDeviceManager.cpp new file mode 100755 index 0000000..bd94651 --- /dev/null +++ b/CDAL/CommDeviceManager.cpp @@ -0,0 +1,56 @@ +/* + * CommDeviceManager.cpp + * + * Copyright (C) ST-Ericsson SA 2011 + * Authors: Srimanta Panda <srimanta.panda@stericsson.com>, + * Ola Borgelin <ola.borgelin@stericsson.com>, + * Karin Hedlund <karin.hedlund@stericsson.com>, + * Markus Andersson <markus.m.andersson@stericsson.com> for ST-Ericsson. + * License terms: 3-clause BSD license + * + */ + +#include "CommDeviceManager.h" +#include "CommDevice.h" +#include "CommException.h" +#include "Debug.h" +#include <vector> +using namespace std; + +vector<CommDevice*> CommDeviceManager::devices_; + +const vector<CommDevice*>& CommDeviceManager::getAllDevices() +{ + return devices_; +} + +void CommDeviceManager::destroyDevice(CommDevice* device) +{ + if (0 == device) { + return; + } + + vector<CommDevice*>::iterator i = devices_.begin(); + + while (i != devices_.end()) { + if (device == *i) { + delete device; + break; + } + + ++i; + } + + if (i != devices_.end()) { + devices_.erase(i); + } +} + +void CommDeviceManager::destroyAll() +{ + for (vector<CommDevice*>::iterator i = devices_.begin(); i != devices_.end(); ++i) { + delete *i; + } + + devices_.clear(); +} diff --git a/CDAL/CommDeviceManager.h b/CDAL/CommDeviceManager.h new file mode 100755 index 0000000..fef36de --- /dev/null +++ b/CDAL/CommDeviceManager.h @@ -0,0 +1,80 @@ +/* + * CommDeviceManager.h + * + * Copyright (C) ST-Ericsson SA 2011 + * Authors: Srimanta Panda <srimanta.panda@stericsson.com>, + * Ola Borgelin <ola.borgelin@stericsson.com>, + * Karin Hedlund <karin.hedlund@stericsson.com>, + * Markus Andersson <markus.m.andersson@stericsson.com> for ST-Ericsson. + * License terms: 3-clause BSD license + * + */ + +#pragma once + +#include "CDAL.h" +#include "CommDevice.h" +#include <vector> +#include <libusb.h> + +class CommDeviceManager +{ +public: + static const std::vector<CommDevice*>& getAllDevices(); + + static void destroyDevice(CommDevice* device); + static void destroyAll(); + + template <class T, class U> + static T* createDevice(U port) { + T* device = new T(port); + + T* existingDevice = dynamic_cast<T*>(getDevice<T>(port)); + + if (0 != existingDevice) { + destroyDevice(existingDevice); + } + + devices_.push_back(device); + + return device; + } + + template <class T, class U> + static T* getDevice(U port) { + T* device; + + for (std::vector<CommDevice*>::iterator i = devices_.begin(); i != devices_.end(); ++i) { + device = dynamic_cast<T*>(*i); + + if (0 != device && device->getPort() == port) { + return device; + } + } + + return 0; + } + + +private: + static std::vector<CommDevice*> devices_; +private: + CommDeviceManager() {} + CommDeviceManager(const CommDeviceManager&) {} + ~CommDeviceManager() {} +}; + +// template specialization used to get device for LCD object mapping +template <> +inline CommDevice* CommDeviceManager::getDevice<CommDevice, void*>(void* object) +{ + for (std::vector<CommDevice*>::iterator i = devices_.begin(); i != devices_.end(); ++i) { + if ((*i)->getObject() == object) { + return *i; + } + } + + return 0; +} + + diff --git a/CDAL/CommException.cpp b/CDAL/CommException.cpp new file mode 100755 index 0000000..4485cba --- /dev/null +++ b/CDAL/CommException.cpp @@ -0,0 +1,38 @@ +/* + * CommException.cpp + * + * Copyright (C) ST-Ericsson SA 2011 + * Authors: Srimanta Panda <srimanta.panda@stericsson.com>, + * Ola Borgelin <ola.borgelin@stericsson.com>, + * Karin Hedlund <karin.hedlund@stericsson.com>, + * Markus Andersson <markus.m.andersson@stericsson.com> for ST-Ericsson. + * License terms: 3-clause BSD license + * + */ + +#include "CommException.h" +#include <stdexcept> +#include <sstream> +using namespace std; + +CommException::CommException(const string& message, DeviceStatus_t error): + runtime_error(message), error_(error) +{ +} + +CommException::~CommException() throw() +{ +} + +const char* CommException::what() +{ + ostringstream message; + message << this->runtime_error::what() << " " << error_; + message_ = message.str(); + return message_.c_str(); +} + +DeviceStatus_t CommException::getError() +{ + return error_; +} diff --git a/CDAL/CommException.h b/CDAL/CommException.h new file mode 100755 index 0000000..fc4d576 --- /dev/null +++ b/CDAL/CommException.h @@ -0,0 +1,29 @@ +/* + * CommException.h + * + * Copyright (C) ST-Ericsson SA 2011 + * Authors: Srimanta Panda <srimanta.panda@stericsson.com>, + * Ola Borgelin <ola.borgelin@stericsson.com>, + * Karin Hedlund <karin.hedlund@stericsson.com>, + * Markus Andersson <markus.m.andersson@stericsson.com> for ST-Ericsson. + * License terms: 3-clause BSD license + * + */ + +#pragma once + +#include "CDAL.h" +#include <stdexcept> +#include <string> + +class CommException : public std::runtime_error +{ +public: + CommException(const std::string& message, DeviceStatus_t error); + virtual ~CommException() throw(); + virtual const char* what(); + DeviceStatus_t getError(); +private: + DeviceStatus_t error_; + std::string message_; +}; diff --git a/CDAL/Debug.h b/CDAL/Debug.h new file mode 100755 index 0000000..69e5112 --- /dev/null +++ b/CDAL/Debug.h @@ -0,0 +1,94 @@ +/* + * Debug.h + * + * Copyright (C) ST-Ericsson SA 2011 + * Authors: Srimanta Panda <srimanta.panda@stericsson.com>, + * Ola Borgelin <ola.borgelin@stericsson.com>, + * Karin Hedlund <karin.hedlund@stericsson.com>, + * Markus Andersson <markus.m.andersson@stericsson.com> for ST-Ericsson. + * License terms: 3-clause BSD license + * + */ + +#pragma once + +//#define _DEBUG +#ifdef _DEBUG +#define DEBUG_INFO +#define DEBUG_ERROR +#define DEBUG_HEXDUMP +#define DEBUG_HEXDUMP_SIZE 1024 +#endif + +#ifdef _WIN32 +#define flockfile _lock_file +#define funlockfile _unlock_file +#else +#include <cstddef> +#endif + +#if defined(DEBUG_ERROR) || defined(DEBUG_INFO) || defined(DEBUG_HEXDUMP) +#include <cstdio> +#include <cstdarg> +#endif + +class Debug +{ +public: + inline static void error(const char* format, ...) __attribute__((format(printf, 1, 0))) { +#ifdef DEBUG_ERROR + flockfile(stdout); + printf("ERROR - "); + va_list args; + va_start(args, format); + vprintf(format, args); + va_end(args); + printf("\n"); + fflush(stdout); + funlockfile(stdout); +#endif + } + + static inline void info(const char* format, ...) __attribute__((format(printf, 1, 0))) { +#ifdef DEBUG_INFO + flockfile(stdout); + printf("INFO - "); + va_list args; + va_start(args, format); + vprintf(format, args); + va_end(args); + printf("\n"); + fflush(stdout); + funlockfile(stdout); +#endif + } + + inline static void hexdump(const char* message, unsigned char* buffer, size_t length) { +#ifdef DEBUG_HEXDUMP + flockfile(stdout); + printf("%s (%d):\n", message, length); + size_t printLength = length < DEBUG_HEXDUMP_SIZE ? length : DEBUG_HEXDUMP_SIZE; + + for (size_t i = 0; i < printLength; i++) { + printf("%02x ", buffer[i]); + + if ((i + 1) % 16 == 0 && (i + 1) < printLength) + printf("\n"); + } + + printf("\n"); + + if (printLength != length) { + printf("%d bytes more...\n", length - printLength); + } + + printf("\n"); + fflush(stdout); + funlockfile(stdout); +#endif + } +private: + Debug() {} + ~Debug() {} + Debug(const Debug&) {} +}; diff --git a/CDAL/LibusbDevice.cpp b/CDAL/LibusbDevice.cpp new file mode 100755 index 0000000..337df46 --- /dev/null +++ b/CDAL/LibusbDevice.cpp @@ -0,0 +1,149 @@ +/* + * LibusbDevice.cpp + * + * Copyright (C) ST-Ericsson SA 2011 + * Authors: Srimanta Panda <srimanta.panda@stericsson.com>, + * Ola Borgelin <ola.borgelin@stericsson.com>, + * Karin Hedlund <karin.hedlund@stericsson.com>, + * Markus Andersson <markus.m.andersson@stericsson.com> for ST-Ericsson. + * License terms: 3-clause BSD license + * + */ + +#include "LibusbDevice.h" +#include "Debug.h" +#include "CommException.h" +#include <libusb.h> + +using namespace std; + +#define MIN(A, B) ((A) < (B) ? (A) : (B)) + +LibusbDevice::LibusbDevice(libusb_device* device): device_(device) +{ + int status = libusb_open(device_, &handle_); + + if (status != LIBUSB_SUCCESS) { + throw CommException("failed to open usb device", COMM_DEVICE_LIBUSB_FAILED_TO_OPEN_PORT); + } + + status = libusb_claim_interface(handle_, 0); + + if (status != LIBUSB_SUCCESS) { + libusb_close(handle_); + throw CommException("failed to claim device interface", COMM_DEVICE_LIBUSB_FAILED_TO_CLAIM_INTERFACE); + } + + libusb_config_descriptor* config; + libusb_get_active_config_descriptor(device, &config); + Debug::info("LibusbDevice: found %d endpoints", config->interface->altsetting->bNumEndpoints); + + for (int i = 0; i != config->interface->altsetting->bNumEndpoints; ++i) { + if (config->interface->altsetting->endpoint[i].bEndpointAddress & LIBUSB_ENDPOINT_IN) { + inEndpoint_ = config->interface->altsetting->endpoint[i].bEndpointAddress; + Debug::info("LibusbDevice: in endpoint set to 0x%02x", inEndpoint_); + } else { + outEndpoint_ = config->interface->altsetting->endpoint[i].bEndpointAddress; + Debug::info("LibusbDevice: out endpoint set to 0x%02x", outEndpoint_); + } + } + + libusb_free_config_descriptor(config); + + libusb_get_device_descriptor(device, &descriptor_); + + readBufferLength_ = 0; + readBufferHead_ = readBuffer_; +} + +LibusbDevice::~LibusbDevice() +{ + libusb_release_interface(handle_, 0); + libusb_close(handle_); +} + +int LibusbDevice::read(void *buffer, size_t size) +{ + Debug::info("LibusbDevice read: called with size %d", size); + unsigned char* dest = static_cast<unsigned char*>(buffer); + + while (true) { + if (readBufferLength_) { + size_t toCopy = MIN(readBufferLength_, size); + memcpy(dest, readBufferHead_, toCopy); + dest += toCopy; + size -= toCopy; + readBufferLength_ -= toCopy; + + if (readBufferLength_ != 0) { + readBufferHead_ += toCopy; + } else { + readBufferHead_ = readBuffer_; + } + } + + if (size == 0) { + break; + } + + int transfered; + int error = libusb_bulk_transfer(handle_, inEndpoint_, readBuffer_, READ_BUFFER_SIZE, &transfered, 100000); + + if (isReadCanceled_) { + Debug::info("LibusbDevice read: canceled..."); + Debug::hexdump("read canceled", dest, transfered); + isReadCanceled_ = false; + return COMM_DEVICE_CANCEL; + } + + if (error) { + if (error == LIBUSB_ERROR_TIMEOUT) { + continue; + } else { + Debug::info("LibusbDevice read: error %d occured", error); + return error; + } + } + + readBufferLength_ = transfered; + } + + Debug::info("LibusbDevice read: complete"); + return 0; +} + +int LibusbDevice::write(void *buffer, size_t size) +{ + Debug::info("LibusbDevice write: called with size %d", size); + unsigned char* src = static_cast<unsigned char*>(buffer); + + while (size) { + int transfered; + //Call with timeout to enable possible cancel + int error = libusb_bulk_transfer(handle_, outEndpoint_, src, size, &transfered, 0); + + if (error) { + if (error == LIBUSB_ERROR_TIMEOUT) { + continue; + } else { + return error; + } + } + + size -= transfered; + src += transfered; + } + + Debug::info("LibusbDevice write: complete"); + return 0; +} + +int LibusbDevice::getVendorId() +{ + return descriptor_.idVendor; +} + +libusb_device* LibusbDevice::getPort() +{ + return device_; +} diff --git a/CDAL/LibusbDevice.h b/CDAL/LibusbDevice.h new file mode 100755 index 0000000..1865605 --- /dev/null +++ b/CDAL/LibusbDevice.h @@ -0,0 +1,42 @@ +/* + * LibusbDevice.h + * + * Copyright (C) ST-Ericsson SA 2011 + * Authors: Srimanta Panda <srimanta.panda@stericsson.com>, + * Ola Borgelin <ola.borgelin@stericsson.com>, + * Karin Hedlund <karin.hedlund@stericsson.com>, + * Markus Andersson <markus.m.andersson@stericsson.com> for ST-Ericsson. + * License terms: 3-clause BSD license + * + */ + +#pragma once +#include <libusb.h> +#include "CommDevice.h" + +class LibusbDevice : public CommDevice +{ +public: + LibusbDevice(libusb_device* device); + ~LibusbDevice(); + + int read(void* buffer, size_t size); + int write(void* buffer, size_t size); + + int getVendorId(); + libusb_device* getPort(); + + unsigned long getPhysicalAddress() { + return 0; + } +private: + libusb_device* device_; + libusb_device_handle* handle_; + libusb_device_descriptor descriptor_; + int outEndpoint_; + int inEndpoint_; + static const int READ_BUFFER_SIZE = 4096; + unsigned char readBuffer_[READ_BUFFER_SIZE]; + unsigned char* readBufferHead_; + size_t readBufferLength_; +}; |