mirror of https://github.com/opencardev/aasdk
commit
b2af4614e3
|
@ -12,6 +12,7 @@ C++ object-oriented library containing implementation of core AndroidAuto(tm) fu
|
||||||
### Supported functionalities
|
### Supported functionalities
|
||||||
- AOAP (Android Open Accessory Protocol)
|
- AOAP (Android Open Accessory Protocol)
|
||||||
- USB transport
|
- USB transport
|
||||||
|
- TCP transport
|
||||||
- USB hotplug
|
- USB hotplug
|
||||||
- AndroidAuto(tm) protocol
|
- AndroidAuto(tm) protocol
|
||||||
- SSL encryption
|
- SSL encryption
|
||||||
|
|
|
@ -41,6 +41,7 @@ struct DataBuffer
|
||||||
DataBuffer(void* _data, Data::size_type _size, Data::size_type offset = 0);
|
DataBuffer(void* _data, Data::size_type _size, Data::size_type offset = 0);
|
||||||
explicit DataBuffer(Data& _data, Data::size_type offset = 0);
|
explicit DataBuffer(Data& _data, Data::size_type offset = 0);
|
||||||
bool operator==(const std::nullptr_t&) const;
|
bool operator==(const std::nullptr_t&) const;
|
||||||
|
bool operator==(const DataBuffer& buffer) const;
|
||||||
|
|
||||||
Data::value_type* data;
|
Data::value_type* data;
|
||||||
Data::size_type size;
|
Data::size_type size;
|
||||||
|
@ -54,6 +55,7 @@ struct DataConstBuffer
|
||||||
DataConstBuffer(const void* _data, Data::size_type _size, Data::size_type offset = 0);
|
DataConstBuffer(const void* _data, Data::size_type _size, Data::size_type offset = 0);
|
||||||
explicit DataConstBuffer(const Data& _data, Data::size_type offset = 0);
|
explicit DataConstBuffer(const Data& _data, Data::size_type offset = 0);
|
||||||
bool operator==(const std::nullptr_t&) const;
|
bool operator==(const std::nullptr_t&) const;
|
||||||
|
bool operator==(const DataConstBuffer& buffer) const;
|
||||||
|
|
||||||
const Data::value_type* cdata;
|
const Data::value_type* cdata;
|
||||||
Data::size_type size;
|
Data::size_type size;
|
||||||
|
|
|
@ -41,6 +41,8 @@ public:
|
||||||
|
|
||||||
bool operator!() const;
|
bool operator!() const;
|
||||||
bool operator==(const Error& other) const;
|
bool operator==(const Error& other) const;
|
||||||
|
bool operator==(const ErrorCode& code) const;
|
||||||
|
bool operator!=(const ErrorCode& code) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ErrorCode code_;
|
ErrorCode code_;
|
||||||
|
|
|
@ -29,40 +29,40 @@ namespace error
|
||||||
|
|
||||||
enum class ErrorCode
|
enum class ErrorCode
|
||||||
{
|
{
|
||||||
NONE,
|
NONE = 0,
|
||||||
USB_CLAIM_INTERFACE,
|
USB_CLAIM_INTERFACE = 1,
|
||||||
USB_INVALID_CONFIG_DESCRIPTOR,
|
USB_INVALID_CONFIG_DESCRIPTOR = 2,
|
||||||
USB_OBTAIN_INTERFACE_DESCRIPTOR,
|
USB_OBTAIN_INTERFACE_DESCRIPTOR = 3,
|
||||||
USB_EMPTY_INTERFACES,
|
USB_EMPTY_INTERFACES = 4,
|
||||||
USB_INVALID_DEVICE_ENDPOINTS,
|
USB_INVALID_DEVICE_ENDPOINTS = 5,
|
||||||
USB_INVALID_TRANSFER_METHOD,
|
USB_INVALID_TRANSFER_METHOD = 6,
|
||||||
USB_TRANSFER_ALLOCATION,
|
USB_TRANSFER_ALLOCATION = 7,
|
||||||
USB_LIST_DEVICES,
|
USB_LIST_DEVICES = 8,
|
||||||
USB_OBTAIN_CONFIG_DESCRIPTOR,
|
USB_OBTAIN_CONFIG_DESCRIPTOR = 9,
|
||||||
USB_TRANSFER,
|
USB_TRANSFER = 10,
|
||||||
USB_SINK_COMMIT_OVERFLOW,
|
DATA_SINK_COMMIT_OVERFLOW = 11,
|
||||||
USB_SINK_CONSUME_UNDERFLOW,
|
DATA_SINK_CONSUME_UNDERFLOW = 12,
|
||||||
USB_AOAP_PROTOCOL_VERSION,
|
USB_AOAP_PROTOCOL_VERSION = 13,
|
||||||
USB_EMPTY_DEVICE_LIST,
|
USB_AOAP_DEVICE_NOT_FOUND = 14,
|
||||||
USB_AOAP_DEVICE_NOT_FOUND,
|
SSL_READ_CERTIFICATE = 15,
|
||||||
SSL_READ_CERTIFICATE,
|
SSL_READ_PRIVATE_KEY = 16,
|
||||||
SSL_READ_PRIVATE_KEY,
|
SSL_METHOD = 17,
|
||||||
SSL_METHOD,
|
SSL_CONTEXT_CREATION = 18,
|
||||||
SSL_CONTEXT_CREATION,
|
SSL_USE_CERTIFICATE = 19,
|
||||||
SSL_USE_CERTIFICATE,
|
SSL_USE_PRIVATE_KEY = 20,
|
||||||
SSL_USE_PRIVATE_KEY,
|
SSL_HANDLER_CREATION = 21,
|
||||||
SSL_HANDLER_CREATION,
|
SSL_READ_BIO_CREATION = 22,
|
||||||
SSL_READ_BIO_CREATION,
|
SSL_WRITE_BIO_CREATION = 23,
|
||||||
SSL_WRITE_BIO_CREATION,
|
SSL_HANDSHAKE = 24,
|
||||||
SSL_HANDSHAKE,
|
SSL_WRITE = 25,
|
||||||
SSL_WRITE,
|
SSL_READ = 26,
|
||||||
SSL_READ,
|
SSL_BIO_READ = 27,
|
||||||
SSL_BIO_READ,
|
SSL_BIO_WRITE = 28,
|
||||||
SSL_BIO_WRITE,
|
MESSENGER_INTERTWINED_CHANNELS = 29,
|
||||||
MESSENGER_INTERTWINED_CHANNELS,
|
OPERATION_ABORTED = 30,
|
||||||
OPERATION_ABORTED,
|
OPERATION_IN_PROGRESS = 31,
|
||||||
OPERATION_IN_PROGRESS,
|
PARSE_PAYLOAD = 32,
|
||||||
PARSE_PAYLOAD
|
TCP_TRANSFER = 33
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,11 +28,9 @@ namespace aasdk
|
||||||
namespace io
|
namespace io
|
||||||
{
|
{
|
||||||
|
|
||||||
class IOContextWrapper: boost::noncopyable
|
class IOContextWrapper
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
typedef std::shared_ptr<IOContextWrapper> Pointer;
|
|
||||||
|
|
||||||
IOContextWrapper();
|
IOContextWrapper();
|
||||||
explicit IOContextWrapper(boost::asio::io_service& ioService);
|
explicit IOContextWrapper(boost::asio::io_service& ioService);
|
||||||
explicit IOContextWrapper(boost::asio::io_service::strand& strand);
|
explicit IOContextWrapper(boost::asio::io_service::strand& strand);
|
||||||
|
|
|
@ -51,13 +51,13 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
Promise(boost::asio::io_service& ioService)
|
Promise(boost::asio::io_service& ioService)
|
||||||
: ioContextWrapper_(std::make_shared<IOContextWrapper>(ioService))
|
: ioContextWrapper_(ioService)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Promise(boost::asio::io_service::strand& strand)
|
Promise(boost::asio::io_service::strand& strand)
|
||||||
: ioContextWrapper_(std::make_shared<IOContextWrapper>(strand))
|
: ioContextWrapper_(strand)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -66,8 +66,8 @@ public:
|
||||||
{
|
{
|
||||||
std::lock_guard<decltype(mutex_)> lock(mutex_);
|
std::lock_guard<decltype(mutex_)> lock(mutex_);
|
||||||
|
|
||||||
resolveHandler_ = std::make_shared<ResolveHandler>(std::move(resolveHandler));
|
resolveHandler_ = std::move(resolveHandler);
|
||||||
rejectHandler_ = rejectHandler == nullptr ? nullptr : std::make_shared<RejectHandler>(std::move(rejectHandler));
|
rejectHandler_ = std::move(rejectHandler);
|
||||||
}
|
}
|
||||||
|
|
||||||
void resolve(ResolveArgumentType argument)
|
void resolve(ResolveArgumentType argument)
|
||||||
|
@ -76,14 +76,13 @@ public:
|
||||||
|
|
||||||
if(resolveHandler_ != nullptr && this->isPending())
|
if(resolveHandler_ != nullptr && this->isPending())
|
||||||
{
|
{
|
||||||
ioContextWrapper_->post([argument = std::move(argument), resolveHandler = std::move(resolveHandler_)]() mutable {
|
ioContextWrapper_.post([argument = std::move(argument), resolveHandler = std::move(resolveHandler_)]() mutable {
|
||||||
(*resolveHandler)(std::move(argument));
|
resolveHandler(std::move(argument));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
ioContextWrapper_->reset();
|
|
||||||
ioContextWrapper_.reset();
|
ioContextWrapper_.reset();
|
||||||
rejectHandler_.reset();
|
rejectHandler_ = RejectHandler();
|
||||||
}
|
}
|
||||||
|
|
||||||
void reject(ErrorArgumentType error)
|
void reject(ErrorArgumentType error)
|
||||||
|
@ -92,25 +91,24 @@ public:
|
||||||
|
|
||||||
if(rejectHandler_ != nullptr && this->isPending())
|
if(rejectHandler_ != nullptr && this->isPending())
|
||||||
{
|
{
|
||||||
ioContextWrapper_->post([error = std::move(error), rejectHandler = std::move(rejectHandler_)]() mutable {
|
ioContextWrapper_.post([error = std::move(error), rejectHandler = std::move(rejectHandler_)]() mutable {
|
||||||
(*rejectHandler)(std::move(error));
|
rejectHandler(std::move(error));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
ioContextWrapper_->reset();
|
|
||||||
ioContextWrapper_.reset();
|
ioContextWrapper_.reset();
|
||||||
resolveHandler_.reset();
|
resolveHandler_ = ResolveHandler();
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool isPending() const
|
bool isPending() const
|
||||||
{
|
{
|
||||||
return ioContextWrapper_ != nullptr && ioContextWrapper_->isActive();
|
return ioContextWrapper_.isActive();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<ResolveHandler> resolveHandler_;
|
ResolveHandler resolveHandler_;
|
||||||
std::shared_ptr<RejectHandler> rejectHandler_;
|
RejectHandler rejectHandler_;
|
||||||
IOContextWrapper::Pointer ioContextWrapper_;
|
IOContextWrapper ioContextWrapper_;
|
||||||
std::mutex mutex_;
|
std::mutex mutex_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -134,13 +132,13 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
Promise(boost::asio::io_service& ioService)
|
Promise(boost::asio::io_service& ioService)
|
||||||
: ioContextWrapper_(std::make_shared<IOContextWrapper>(ioService))
|
: ioContextWrapper_(ioService)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Promise(boost::asio::io_service::strand& strand)
|
Promise(boost::asio::io_service::strand& strand)
|
||||||
: ioContextWrapper_(std::make_shared<IOContextWrapper>(strand))
|
: ioContextWrapper_(strand)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -149,8 +147,8 @@ public:
|
||||||
{
|
{
|
||||||
std::lock_guard<decltype(mutex_)> lock(mutex_);
|
std::lock_guard<decltype(mutex_)> lock(mutex_);
|
||||||
|
|
||||||
resolveHandler_ = std::make_shared<ResolveHandler>(std::move(resolveHandler));
|
resolveHandler_ = std::move(resolveHandler);
|
||||||
rejectHandler_ = rejectHandler == nullptr ? nullptr : std::make_shared<RejectHandler>(std::move(rejectHandler));
|
rejectHandler_ = std::move(rejectHandler);
|
||||||
}
|
}
|
||||||
|
|
||||||
void resolve()
|
void resolve()
|
||||||
|
@ -159,14 +157,13 @@ public:
|
||||||
|
|
||||||
if(resolveHandler_ != nullptr && this->isPending())
|
if(resolveHandler_ != nullptr && this->isPending())
|
||||||
{
|
{
|
||||||
ioContextWrapper_->post([resolveHandler = std::move(resolveHandler_)]() mutable {
|
ioContextWrapper_.post([resolveHandler = std::move(resolveHandler_)]() mutable {
|
||||||
(*resolveHandler)();
|
resolveHandler();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
ioContextWrapper_->reset();
|
|
||||||
ioContextWrapper_.reset();
|
ioContextWrapper_.reset();
|
||||||
rejectHandler_.reset();
|
rejectHandler_ = RejectHandler();
|
||||||
}
|
}
|
||||||
|
|
||||||
void reject(ErrorArgumentType error)
|
void reject(ErrorArgumentType error)
|
||||||
|
@ -175,25 +172,24 @@ public:
|
||||||
|
|
||||||
if(rejectHandler_ != nullptr && this->isPending())
|
if(rejectHandler_ != nullptr && this->isPending())
|
||||||
{
|
{
|
||||||
ioContextWrapper_->post([error = std::move(error), rejectHandler = std::move(rejectHandler_)]() mutable {
|
ioContextWrapper_.post([error = std::move(error), rejectHandler = std::move(rejectHandler_)]() mutable {
|
||||||
(*rejectHandler)(std::move(error));
|
rejectHandler(std::move(error));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
ioContextWrapper_->reset();
|
|
||||||
ioContextWrapper_.reset();
|
ioContextWrapper_.reset();
|
||||||
resolveHandler_.reset();
|
resolveHandler_ = ResolveHandler();
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool isPending() const
|
bool isPending() const
|
||||||
{
|
{
|
||||||
return ioContextWrapper_ != nullptr && ioContextWrapper_->isActive();
|
return ioContextWrapper_.isActive();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<ResolveHandler> resolveHandler_;
|
ResolveHandler resolveHandler_;
|
||||||
std::shared_ptr<RejectHandler> rejectHandler_;
|
RejectHandler rejectHandler_;
|
||||||
IOContextWrapper::Pointer ioContextWrapper_;
|
IOContextWrapper ioContextWrapper_;
|
||||||
std::mutex mutex_;
|
std::mutex mutex_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -216,13 +212,13 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
Promise(boost::asio::io_service& ioService)
|
Promise(boost::asio::io_service& ioService)
|
||||||
: ioContextWrapper_(std::make_shared<IOContextWrapper>(ioService))
|
: ioContextWrapper_(ioService)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Promise(boost::asio::io_service::strand& strand)
|
Promise(boost::asio::io_service::strand& strand)
|
||||||
: ioContextWrapper_(std::make_shared<IOContextWrapper>(strand))
|
: ioContextWrapper_(strand)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -231,8 +227,8 @@ public:
|
||||||
{
|
{
|
||||||
std::lock_guard<decltype(mutex_)> lock(mutex_);
|
std::lock_guard<decltype(mutex_)> lock(mutex_);
|
||||||
|
|
||||||
resolveHandler_ = std::make_shared<ResolveHandler>(std::move(resolveHandler));
|
resolveHandler_ = std::move(resolveHandler);
|
||||||
rejectHandler_ = rejectHandler == nullptr ? nullptr : std::make_shared<RejectHandler>(std::move(rejectHandler));
|
rejectHandler_ = std::move(rejectHandler);
|
||||||
}
|
}
|
||||||
|
|
||||||
void resolve()
|
void resolve()
|
||||||
|
@ -241,14 +237,13 @@ public:
|
||||||
|
|
||||||
if(resolveHandler_ != nullptr && this->isPending())
|
if(resolveHandler_ != nullptr && this->isPending())
|
||||||
{
|
{
|
||||||
ioContextWrapper_->post([resolveHandler = std::move(resolveHandler_)]() mutable {
|
ioContextWrapper_.post([resolveHandler = std::move(resolveHandler_)]() mutable {
|
||||||
(*resolveHandler)();
|
resolveHandler();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
ioContextWrapper_->reset();
|
|
||||||
ioContextWrapper_.reset();
|
ioContextWrapper_.reset();
|
||||||
rejectHandler_.reset();
|
rejectHandler_ = RejectHandler();
|
||||||
}
|
}
|
||||||
|
|
||||||
void reject()
|
void reject()
|
||||||
|
@ -257,25 +252,24 @@ public:
|
||||||
|
|
||||||
if(rejectHandler_ != nullptr && this->isPending())
|
if(rejectHandler_ != nullptr && this->isPending())
|
||||||
{
|
{
|
||||||
ioContextWrapper_->post([rejectHandler = std::move(rejectHandler_)]() mutable {
|
ioContextWrapper_.post([rejectHandler = std::move(rejectHandler_)]() mutable {
|
||||||
(*rejectHandler)();
|
rejectHandler();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
ioContextWrapper_->reset();
|
|
||||||
ioContextWrapper_.reset();
|
ioContextWrapper_.reset();
|
||||||
resolveHandler_.reset();
|
resolveHandler_ = ResolveHandler();
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool isPending() const
|
bool isPending() const
|
||||||
{
|
{
|
||||||
return ioContextWrapper_ != nullptr && ioContextWrapper_->isActive();
|
return ioContextWrapper_.isActive();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<ResolveHandler> resolveHandler_;
|
ResolveHandler resolveHandler_;
|
||||||
std::shared_ptr<RejectHandler> rejectHandler_;
|
RejectHandler rejectHandler_;
|
||||||
IOContextWrapper::Pointer ioContextWrapper_;
|
IOContextWrapper ioContextWrapper_;
|
||||||
std::mutex mutex_;
|
std::mutex mutex_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -299,13 +293,13 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
Promise(boost::asio::io_service& ioService)
|
Promise(boost::asio::io_service& ioService)
|
||||||
: ioContextWrapper_(std::make_shared<IOContextWrapper>(ioService))
|
: ioContextWrapper_(ioService)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Promise(boost::asio::io_service::strand& strand)
|
Promise(boost::asio::io_service::strand& strand)
|
||||||
: ioContextWrapper_(std::make_shared<IOContextWrapper>(strand))
|
: ioContextWrapper_(strand)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -314,8 +308,8 @@ public:
|
||||||
{
|
{
|
||||||
std::lock_guard<decltype(mutex_)> lock(mutex_);
|
std::lock_guard<decltype(mutex_)> lock(mutex_);
|
||||||
|
|
||||||
resolveHandler_ = std::make_shared<ResolveHandler>(std::move(resolveHandler));
|
resolveHandler_ = std::move(resolveHandler);
|
||||||
rejectHandler_ = rejectHandler == nullptr ? nullptr : std::make_shared<RejectHandler>(std::move(rejectHandler));
|
rejectHandler_ = std::move(rejectHandler);
|
||||||
}
|
}
|
||||||
|
|
||||||
void resolve(ResolveArgumentType argument)
|
void resolve(ResolveArgumentType argument)
|
||||||
|
@ -324,14 +318,13 @@ public:
|
||||||
|
|
||||||
if(resolveHandler_ != nullptr && this->isPending())
|
if(resolveHandler_ != nullptr && this->isPending())
|
||||||
{
|
{
|
||||||
ioContextWrapper_->post([argument = std::move(argument), resolveHandler = std::move(resolveHandler_)]() mutable {
|
ioContextWrapper_.post([argument = std::move(argument), resolveHandler = std::move(resolveHandler_)]() mutable {
|
||||||
(*resolveHandler)(std::move(argument));
|
resolveHandler(std::move(argument));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
ioContextWrapper_->reset();
|
|
||||||
ioContextWrapper_.reset();
|
ioContextWrapper_.reset();
|
||||||
rejectHandler_.reset();
|
rejectHandler_ = RejectHandler();
|
||||||
}
|
}
|
||||||
|
|
||||||
void reject()
|
void reject()
|
||||||
|
@ -340,25 +333,24 @@ public:
|
||||||
|
|
||||||
if(rejectHandler_ != nullptr && this->isPending())
|
if(rejectHandler_ != nullptr && this->isPending())
|
||||||
{
|
{
|
||||||
ioContextWrapper_->post([rejectHandler = std::move(rejectHandler_)]() mutable {
|
ioContextWrapper_.post([rejectHandler = std::move(rejectHandler_)]() mutable {
|
||||||
(*rejectHandler)();
|
rejectHandler();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
ioContextWrapper_->reset();
|
|
||||||
ioContextWrapper_.reset();
|
ioContextWrapper_.reset();
|
||||||
resolveHandler_.reset();
|
resolveHandler_ = ResolveHandler();
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool isPending() const
|
bool isPending() const
|
||||||
{
|
{
|
||||||
return ioContextWrapper_ != nullptr && ioContextWrapper_->isActive();
|
return ioContextWrapper_.isActive();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<ResolveHandler> resolveHandler_;
|
ResolveHandler resolveHandler_;
|
||||||
std::shared_ptr<RejectHandler> rejectHandler_;
|
RejectHandler rejectHandler_;
|
||||||
IOContextWrapper::Pointer ioContextWrapper_;
|
IOContextWrapper ioContextWrapper_;
|
||||||
std::mutex mutex_;
|
std::mutex mutex_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,48 @@
|
||||||
|
/*
|
||||||
|
* This file is part of aasdk library project.
|
||||||
|
* Copyright (C) 2018 f1x.studio (Michal Szwaj)
|
||||||
|
*
|
||||||
|
* aasdk is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
|
||||||
|
* aasdk 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 General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with aasdk. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <f1x/aasdk/Common/Data.hpp>
|
||||||
|
#include <f1x/aasdk/IO/Promise.hpp>
|
||||||
|
|
||||||
|
namespace f1x
|
||||||
|
{
|
||||||
|
namespace aasdk
|
||||||
|
{
|
||||||
|
namespace tcp
|
||||||
|
{
|
||||||
|
|
||||||
|
class ITCPEndpoint
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typedef std::shared_ptr<ITCPEndpoint> Pointer;
|
||||||
|
typedef io::Promise<size_t> Promise;
|
||||||
|
typedef std::shared_ptr<boost::asio::ip::tcp::socket> SocketPointer;
|
||||||
|
|
||||||
|
virtual ~ITCPEndpoint() = default;
|
||||||
|
|
||||||
|
virtual void send(common::DataConstBuffer buffer, Promise::Pointer promise) = 0;
|
||||||
|
virtual void receive(common::DataBuffer buffer, Promise::Pointer promise) = 0;
|
||||||
|
virtual void stop() = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,49 @@
|
||||||
|
/*
|
||||||
|
* This file is part of aasdk library project.
|
||||||
|
* Copyright (C) 2018 f1x.studio (Michal Szwaj)
|
||||||
|
*
|
||||||
|
* aasdk is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
|
||||||
|
* aasdk 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 General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with aasdk. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
#include <boost/asio/ip/tcp.hpp>
|
||||||
|
#include <f1x/aasdk/Common/Data.hpp>
|
||||||
|
|
||||||
|
namespace f1x
|
||||||
|
{
|
||||||
|
namespace aasdk
|
||||||
|
{
|
||||||
|
namespace tcp
|
||||||
|
{
|
||||||
|
|
||||||
|
class ITCPWrapper
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typedef std::function<void(const boost::system::error_code&, size_t)> Handler;
|
||||||
|
typedef std::function<void(const boost::system::error_code&)> ConnectHandler;
|
||||||
|
|
||||||
|
virtual ~ITCPWrapper() = default;
|
||||||
|
|
||||||
|
virtual void asyncWrite(boost::asio::ip::tcp::socket& socket, common::DataConstBuffer buffer, Handler handler) = 0;
|
||||||
|
virtual void asyncRead(boost::asio::ip::tcp::socket& socket, common::DataBuffer buffer, Handler handler) = 0;
|
||||||
|
virtual void close(boost::asio::ip::tcp::socket& socket) = 0;
|
||||||
|
virtual void asyncConnect(boost::asio::ip::tcp::socket& socket, const std::string& hostname, uint16_t port, ConnectHandler handler) = 0;
|
||||||
|
virtual boost::system::error_code connect(boost::asio::ip::tcp::socket& socket, const std::string& hostname, uint16_t port) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,52 @@
|
||||||
|
/*
|
||||||
|
* This file is part of aasdk library project.
|
||||||
|
* Copyright (C) 2018 f1x.studio (Michal Szwaj)
|
||||||
|
*
|
||||||
|
* aasdk is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
|
||||||
|
* aasdk 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 General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with aasdk. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <boost/asio/ip/tcp.hpp>
|
||||||
|
#include <f1x/aasdk/TCP/ITCPEndpoint.hpp>
|
||||||
|
#include <f1x/aasdk/TCP/ITCPWrapper.hpp>
|
||||||
|
|
||||||
|
namespace f1x
|
||||||
|
{
|
||||||
|
namespace aasdk
|
||||||
|
{
|
||||||
|
namespace tcp
|
||||||
|
{
|
||||||
|
|
||||||
|
class TCPEndpoint: public ITCPEndpoint, public std::enable_shared_from_this<TCPEndpoint>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
TCPEndpoint(ITCPWrapper& tcpWrapper, SocketPointer socket);
|
||||||
|
|
||||||
|
void send(common::DataConstBuffer buffer, Promise::Pointer promise) override;
|
||||||
|
void receive(common::DataBuffer buffer, Promise::Pointer promise) override;
|
||||||
|
void stop() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
using std::enable_shared_from_this<TCPEndpoint>::shared_from_this;
|
||||||
|
|
||||||
|
void asyncOperationHandler(const boost::system::error_code& ec, size_t bytesTransferred, Promise::Pointer promise);
|
||||||
|
|
||||||
|
ITCPWrapper& tcpWrapper_;
|
||||||
|
SocketPointer socket_;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,42 @@
|
||||||
|
/*
|
||||||
|
* This file is part of aasdk library project.
|
||||||
|
* Copyright (C) 2018 f1x.studio (Michal Szwaj)
|
||||||
|
*
|
||||||
|
* aasdk is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
|
||||||
|
* aasdk 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 General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with aasdk. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <f1x/aasdk/TCP/ITCPWrapper.hpp>
|
||||||
|
|
||||||
|
namespace f1x
|
||||||
|
{
|
||||||
|
namespace aasdk
|
||||||
|
{
|
||||||
|
namespace tcp
|
||||||
|
{
|
||||||
|
|
||||||
|
class TCPWrapper: public ITCPWrapper
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void asyncWrite(boost::asio::ip::tcp::socket& socket, common::DataConstBuffer buffer, Handler handler) override;
|
||||||
|
void asyncRead(boost::asio::ip::tcp::socket& socket, common::DataBuffer buffer, Handler handler) override;
|
||||||
|
void close(boost::asio::ip::tcp::socket& socket) override;
|
||||||
|
void asyncConnect(boost::asio::ip::tcp::socket& socket, const std::string& hostname, uint16_t port, ConnectHandler handler) override;
|
||||||
|
boost::system::error_code connect(boost::asio::ip::tcp::socket& socket, const std::string& hostname, uint16_t port) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -30,10 +30,10 @@ namespace aasdk
|
||||||
namespace transport
|
namespace transport
|
||||||
{
|
{
|
||||||
|
|
||||||
class USBDataSink
|
class DataSink
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
USBDataSink();
|
DataSink();
|
||||||
|
|
||||||
common::DataBuffer fill();
|
common::DataBuffer fill();
|
||||||
void commit(common::Data::size_type size);
|
void commit(common::Data::size_type size);
|
|
@ -0,0 +1,48 @@
|
||||||
|
/*
|
||||||
|
* This file is part of aasdk library project.
|
||||||
|
* Copyright (C) 2018 f1x.studio (Michal Szwaj)
|
||||||
|
*
|
||||||
|
* aasdk is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
|
||||||
|
* aasdk 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 General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with aasdk. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <f1x/aasdk/TCP/ITCPEndpoint.hpp>
|
||||||
|
#include <f1x/aasdk/Transport/Transport.hpp>
|
||||||
|
|
||||||
|
namespace f1x
|
||||||
|
{
|
||||||
|
namespace aasdk
|
||||||
|
{
|
||||||
|
namespace transport
|
||||||
|
{
|
||||||
|
|
||||||
|
class TCPTransport: public Transport
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
TCPTransport(boost::asio::io_service& ioService, tcp::ITCPEndpoint::Pointer tcpEndpoint);
|
||||||
|
|
||||||
|
void stop() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void enqueueReceive(common::DataBuffer buffer) override;
|
||||||
|
void enqueueSend(SendQueue::iterator queueElement) override;
|
||||||
|
void sendHandler(SendQueue::iterator queueElement, const error::Error& e);
|
||||||
|
|
||||||
|
tcp::ITCPEndpoint::Pointer tcpEndpoint_;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,65 @@
|
||||||
|
/*
|
||||||
|
* This file is part of aasdk library project.
|
||||||
|
* Copyright (C) 2018 f1x.studio (Michal Szwaj)
|
||||||
|
*
|
||||||
|
* aasdk is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
|
||||||
|
* aasdk 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 General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with aasdk. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <list>
|
||||||
|
#include <queue>
|
||||||
|
#include <boost/asio.hpp>
|
||||||
|
#include <f1x/aasdk/Transport/ITransport.hpp>
|
||||||
|
#include <f1x/aasdk/Transport/DataSink.hpp>
|
||||||
|
|
||||||
|
namespace f1x
|
||||||
|
{
|
||||||
|
namespace aasdk
|
||||||
|
{
|
||||||
|
namespace transport
|
||||||
|
{
|
||||||
|
|
||||||
|
class Transport: public ITransport, public std::enable_shared_from_this<Transport>, boost::noncopyable
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Transport(boost::asio::io_service& ioService);
|
||||||
|
|
||||||
|
void receive(size_t size, ReceivePromise::Pointer promise) override;
|
||||||
|
void send(common::Data data, SendPromise::Pointer promise) override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
typedef std::list<std::pair<size_t, ReceivePromise::Pointer>> ReceiveQueue;
|
||||||
|
typedef std::list<std::pair<common::Data, SendPromise::Pointer>> SendQueue;
|
||||||
|
|
||||||
|
using std::enable_shared_from_this<Transport>::shared_from_this;
|
||||||
|
void receiveHandler(size_t bytesTransferred);
|
||||||
|
void distributeReceivedData();
|
||||||
|
void rejectReceivePromises(const error::Error& e);
|
||||||
|
|
||||||
|
virtual void enqueueReceive(common::DataBuffer buffer) = 0;
|
||||||
|
virtual void enqueueSend(SendQueue::iterator queueElement) = 0;
|
||||||
|
|
||||||
|
DataSink receivedDataSink_;
|
||||||
|
|
||||||
|
boost::asio::io_service::strand receiveStrand_;
|
||||||
|
ReceiveQueue receiveQueue_;
|
||||||
|
|
||||||
|
boost::asio::io_service::strand sendStrand_;
|
||||||
|
SendQueue sendQueue_;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -18,11 +18,8 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <list>
|
|
||||||
#include <queue>
|
|
||||||
#include <boost/asio.hpp>
|
#include <boost/asio.hpp>
|
||||||
#include <f1x/aasdk/Transport/ITransport.hpp>
|
#include <f1x/aasdk/Transport/Transport.hpp>
|
||||||
#include <f1x/aasdk/Transport/USBDataSink.hpp>
|
|
||||||
#include <f1x/aasdk/USB/IAOAPDevice.hpp>
|
#include <f1x/aasdk/USB/IAOAPDevice.hpp>
|
||||||
|
|
||||||
namespace f1x
|
namespace f1x
|
||||||
|
@ -32,35 +29,20 @@ namespace aasdk
|
||||||
namespace transport
|
namespace transport
|
||||||
{
|
{
|
||||||
|
|
||||||
class USBTransport: public ITransport, public std::enable_shared_from_this<USBTransport>, boost::noncopyable
|
class USBTransport: public Transport
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
USBTransport(boost::asio::io_service& ioService, usb::IAOAPDevice::Pointer aoapDevice);
|
USBTransport(boost::asio::io_service& ioService, usb::IAOAPDevice::Pointer aoapDevice);
|
||||||
|
|
||||||
void receive(size_t size, ReceivePromise::Pointer promise) override;
|
|
||||||
void send(common::Data data, SendPromise::Pointer promise) override;
|
|
||||||
void stop() override;
|
void stop() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
typedef std::list<std::pair<size_t, ReceivePromise::Pointer>> InTransferQueue;
|
void enqueueReceive(common::DataBuffer buffer) override;
|
||||||
typedef std::list<std::pair<common::Data, SendPromise::Pointer>> OutTransferQueue;
|
void enqueueSend(SendQueue::iterator queueElement) override;
|
||||||
|
void doSend(SendQueue::iterator queueElement, common::Data::size_type offset);
|
||||||
using std::enable_shared_from_this<USBTransport>::shared_from_this;
|
void sendHandler(SendQueue::iterator queueElement, common::Data::size_type offset, size_t bytesTransferred);
|
||||||
void receiveHandler(size_t bytesTransferred);
|
|
||||||
void distributeReceivedData();
|
|
||||||
void rejectReceivePromises(const error::Error& e);
|
|
||||||
|
|
||||||
void doSend(OutTransferQueue::iterator queueElementIter, common::Data::size_type offset);
|
|
||||||
void sendHandler(OutTransferQueue::iterator queueElementIter, common::Data::size_type offset, size_t bytesTransferred);
|
|
||||||
|
|
||||||
usb::IAOAPDevice::Pointer aoapDevice_;
|
usb::IAOAPDevice::Pointer aoapDevice_;
|
||||||
USBDataSink usbReceivedDataSink_;
|
|
||||||
|
|
||||||
boost::asio::io_service::strand receiveStrand_;
|
|
||||||
InTransferQueue receiveQueue_;
|
|
||||||
|
|
||||||
boost::asio::io_service::strand sendStrand_;
|
|
||||||
OutTransferQueue sendQueue_;
|
|
||||||
|
|
||||||
static constexpr uint32_t cSendTimeoutMs = 10000;
|
static constexpr uint32_t cSendTimeoutMs = 10000;
|
||||||
static constexpr uint32_t cReceiveTimeoutMs = 0;
|
static constexpr uint32_t cReceiveTimeoutMs = 0;
|
||||||
|
|
|
@ -0,0 +1,58 @@
|
||||||
|
/*
|
||||||
|
* This file is part of aasdk library project.
|
||||||
|
* Copyright (C) 2018 f1x.studio (Michal Szwaj)
|
||||||
|
*
|
||||||
|
* aasdk is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
|
||||||
|
* aasdk 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 General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with aasdk. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <boost/asio.hpp>
|
||||||
|
#include <f1x/aasdk/USB/IUSBWrapper.hpp>
|
||||||
|
#include <f1x/aasdk/USB/IAccessoryModeQueryChainFactory.hpp>
|
||||||
|
#include <f1x/aasdk/USB/IConnectedAccessoriesEnumerator.hpp>
|
||||||
|
|
||||||
|
namespace f1x
|
||||||
|
{
|
||||||
|
namespace aasdk
|
||||||
|
{
|
||||||
|
namespace usb
|
||||||
|
{
|
||||||
|
|
||||||
|
class ConnectedAccessoriesEnumerator: public IConnectedAccessoriesEnumerator, public std::enable_shared_from_this<ConnectedAccessoriesEnumerator>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ConnectedAccessoriesEnumerator(IUSBWrapper& usbWrapper, boost::asio::io_service& ioService, IAccessoryModeQueryChainFactory& queryChainFactory);
|
||||||
|
|
||||||
|
void enumerate(Promise::Pointer promise) override;
|
||||||
|
void cancel() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
using std::enable_shared_from_this<ConnectedAccessoriesEnumerator>::shared_from_this;
|
||||||
|
void queryNextDevice();
|
||||||
|
DeviceHandle getNextDeviceHandle();
|
||||||
|
void reset();
|
||||||
|
|
||||||
|
IUSBWrapper& usbWrapper_;
|
||||||
|
boost::asio::io_service::strand strand_;
|
||||||
|
IAccessoryModeQueryChainFactory& queryChainFactory_;
|
||||||
|
IAccessoryModeQueryChain::Pointer queryChain_;
|
||||||
|
Promise::Pointer promise_;
|
||||||
|
DeviceListHandle deviceListHandle_;
|
||||||
|
DeviceList::iterator actualDeviceIter_;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,44 @@
|
||||||
|
/*
|
||||||
|
* This file is part of aasdk library project.
|
||||||
|
* Copyright (C) 2018 f1x.studio (Michal Szwaj)
|
||||||
|
*
|
||||||
|
* aasdk is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
|
||||||
|
* aasdk 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 General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with aasdk. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <f1x/aasdk/IO/Promise.hpp>
|
||||||
|
|
||||||
|
namespace f1x
|
||||||
|
{
|
||||||
|
namespace aasdk
|
||||||
|
{
|
||||||
|
namespace usb
|
||||||
|
{
|
||||||
|
|
||||||
|
class IConnectedAccessoriesEnumerator
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typedef std::shared_ptr<IConnectedAccessoriesEnumerator> Pointer;
|
||||||
|
typedef io::Promise<bool> Promise;
|
||||||
|
|
||||||
|
virtual ~IConnectedAccessoriesEnumerator() = default;
|
||||||
|
virtual void enumerate(Promise::Pointer promise) = 0;
|
||||||
|
virtual void cancel() = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -19,7 +19,6 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <boost/asio.hpp>
|
#include <boost/asio.hpp>
|
||||||
#include <libusb.h>
|
|
||||||
#include <list>
|
#include <list>
|
||||||
#include <f1x/aasdk/USB/IUSBHub.hpp>
|
#include <f1x/aasdk/USB/IUSBHub.hpp>
|
||||||
#include <f1x/aasdk/USB/IAccessoryModeQueryChainFactory.hpp>
|
#include <f1x/aasdk/USB/IAccessoryModeQueryChainFactory.hpp>
|
||||||
|
|
|
@ -0,0 +1,44 @@
|
||||||
|
/*
|
||||||
|
* This file is part of aasdk library project.
|
||||||
|
* Copyright (C) 2018 f1x.studio (Michal Szwaj)
|
||||||
|
*
|
||||||
|
* aasdk is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
|
||||||
|
* aasdk 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 General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with aasdk. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <gmock/gmock.h>
|
||||||
|
#include <f1x/aasdk/TCP/ITCPEndpoint.hpp>
|
||||||
|
|
||||||
|
namespace f1x
|
||||||
|
{
|
||||||
|
namespace aasdk
|
||||||
|
{
|
||||||
|
namespace tcp
|
||||||
|
{
|
||||||
|
namespace ut
|
||||||
|
{
|
||||||
|
|
||||||
|
class TCPEndpointMock: public ITCPEndpoint
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
MOCK_METHOD2(send, void(common::DataConstBuffer buffer, Promise::Pointer promise));
|
||||||
|
MOCK_METHOD2(receive, void(common::DataBuffer buffer, Promise::Pointer promise));
|
||||||
|
MOCK_METHOD0(stop, void());
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,43 @@
|
||||||
|
/*
|
||||||
|
* This file is part of aasdk library project.
|
||||||
|
* Copyright (C) 2018 f1x.studio (Michal Szwaj)
|
||||||
|
*
|
||||||
|
* aasdk is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
|
||||||
|
* aasdk 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 General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with aasdk. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <gmock/gmock.h>
|
||||||
|
#include <f1x/aasdk/TCP/ITCPEndpoint.hpp>
|
||||||
|
|
||||||
|
namespace f1x
|
||||||
|
{
|
||||||
|
namespace aasdk
|
||||||
|
{
|
||||||
|
namespace tcp
|
||||||
|
{
|
||||||
|
namespace ut
|
||||||
|
{
|
||||||
|
|
||||||
|
class TCPEndpointPromiseHandlerMock
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
MOCK_METHOD1(onResolve, void(size_t transferredBytes));
|
||||||
|
MOCK_METHOD1(onReject, void(const error::Error& e));
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,46 @@
|
||||||
|
/*
|
||||||
|
* This file is part of aasdk library project.
|
||||||
|
* Copyright (C) 2018 f1x.studio (Michal Szwaj)
|
||||||
|
*
|
||||||
|
* aasdk is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
|
||||||
|
* aasdk 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 General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with aasdk. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <gmock/gmock.h>
|
||||||
|
#include <f1x/aasdk/TCP/ITCPWrapper.hpp>
|
||||||
|
|
||||||
|
namespace f1x
|
||||||
|
{
|
||||||
|
namespace aasdk
|
||||||
|
{
|
||||||
|
namespace tcp
|
||||||
|
{
|
||||||
|
namespace ut
|
||||||
|
{
|
||||||
|
|
||||||
|
class TCPWrapperMock: public ITCPWrapper
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
MOCK_METHOD3(asyncWrite, void(boost::asio::ip::tcp::socket& socket, common::DataConstBuffer buffer, Handler handler));
|
||||||
|
MOCK_METHOD3(asyncRead, void(boost::asio::ip::tcp::socket& socket, common::DataBuffer buffer, Handler handler));
|
||||||
|
MOCK_METHOD1(close, void(boost::asio::ip::tcp::socket& socket));
|
||||||
|
MOCK_METHOD4(asyncConnect, void(boost::asio::ip::tcp::socket& socket, const std::string& hostname, uint16_t port, ConnectHandler handler));
|
||||||
|
MOCK_METHOD3(connect, boost::system::error_code(boost::asio::ip::tcp::socket& socket, const std::string& hostname, uint16_t port));
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,44 @@
|
||||||
|
/*
|
||||||
|
* This file is part of aasdk library project.
|
||||||
|
* Copyright (C) 2018 f1x.studio (Michal Szwaj)
|
||||||
|
*
|
||||||
|
* aasdk is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
|
||||||
|
* aasdk 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 General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with aasdk. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <gmock/gmock.h>
|
||||||
|
#include <f1x/aasdk/USB/IUSBWrapper.hpp>
|
||||||
|
#include <f1x/aasdk/Error/Error.hpp>
|
||||||
|
|
||||||
|
namespace f1x
|
||||||
|
{
|
||||||
|
namespace aasdk
|
||||||
|
{
|
||||||
|
namespace usb
|
||||||
|
{
|
||||||
|
namespace ut
|
||||||
|
{
|
||||||
|
|
||||||
|
class ConnectedAccessoriesEnumeratorPromiseHandlerMock
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
MOCK_METHOD1(onResolve, void(bool result));
|
||||||
|
MOCK_METHOD1(onReject, void(const error::Error& e));
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -65,6 +65,11 @@ bool DataBuffer::operator==(const std::nullptr_t&) const
|
||||||
return data == nullptr || size == 0;
|
return data == nullptr || size == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool DataBuffer::operator==(const DataBuffer& buffer) const
|
||||||
|
{
|
||||||
|
return data == buffer.data && size == buffer.size;
|
||||||
|
}
|
||||||
|
|
||||||
DataConstBuffer::DataConstBuffer()
|
DataConstBuffer::DataConstBuffer()
|
||||||
: cdata(nullptr)
|
: cdata(nullptr)
|
||||||
, size(0)
|
, size(0)
|
||||||
|
@ -109,6 +114,11 @@ bool DataConstBuffer::operator==(const std::nullptr_t&) const
|
||||||
return cdata == nullptr || size == 0;
|
return cdata == nullptr || size == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool DataConstBuffer::operator==(const DataConstBuffer& buffer) const
|
||||||
|
{
|
||||||
|
return cdata == buffer.cdata && size == buffer.size;
|
||||||
|
}
|
||||||
|
|
||||||
common::Data createData(const DataConstBuffer& buffer)
|
common::Data createData(const DataConstBuffer& buffer)
|
||||||
{
|
{
|
||||||
common::Data data;
|
common::Data data;
|
||||||
|
|
|
@ -57,7 +57,7 @@ const char* Error::what() const noexcept
|
||||||
|
|
||||||
bool Error::operator!() const
|
bool Error::operator!() const
|
||||||
{
|
{
|
||||||
return code_ != ErrorCode::NONE || nativeCode_ != 0;
|
return code_ == ErrorCode::NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Error::operator==(const Error& other) const
|
bool Error::operator==(const Error& other) const
|
||||||
|
@ -65,6 +65,16 @@ bool Error::operator==(const Error& other) const
|
||||||
return code_ == other.code_ && nativeCode_ == other.nativeCode_;
|
return code_ == other.code_ && nativeCode_ == other.nativeCode_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Error::operator==(const ErrorCode& code) const
|
||||||
|
{
|
||||||
|
return code_ == code;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Error::operator!=(const ErrorCode& code) const
|
||||||
|
{
|
||||||
|
return !operator==(code);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -133,9 +133,9 @@ void Messenger::rejectSendPromiseQueue(const error::Error& e)
|
||||||
|
|
||||||
void Messenger::stop()
|
void Messenger::stop()
|
||||||
{
|
{
|
||||||
this->rejectReceivePromiseQueue(error::Error(error::ErrorCode::OPERATION_ABORTED));
|
receiveStrand_.dispatch([this, self = this->shared_from_this()]() {
|
||||||
this->rejectSendPromiseQueue(error::Error(error::ErrorCode::OPERATION_ABORTED));
|
channelReceiveMessageQueue_.clear();
|
||||||
channelReceiveMessageQueue_.clear();
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,75 @@
|
||||||
|
/*
|
||||||
|
* This file is part of aasdk library project.
|
||||||
|
* Copyright (C) 2018 f1x.studio (Michal Szwaj)
|
||||||
|
*
|
||||||
|
* aasdk is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
|
||||||
|
* aasdk 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 General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with aasdk. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <f1x/aasdk/TCP/TCPEndpoint.hpp>
|
||||||
|
|
||||||
|
namespace f1x
|
||||||
|
{
|
||||||
|
namespace aasdk
|
||||||
|
{
|
||||||
|
namespace tcp
|
||||||
|
{
|
||||||
|
|
||||||
|
TCPEndpoint::TCPEndpoint(ITCPWrapper& tcpWrapper, SocketPointer socket)
|
||||||
|
: tcpWrapper_(tcpWrapper)
|
||||||
|
, socket_(std::move(socket))
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void TCPEndpoint::send(common::DataConstBuffer buffer, Promise::Pointer promise)
|
||||||
|
{
|
||||||
|
tcpWrapper_.asyncWrite(*socket_, std::move(buffer),
|
||||||
|
std::bind(&TCPEndpoint::asyncOperationHandler,
|
||||||
|
this->shared_from_this(),
|
||||||
|
std::placeholders::_1,
|
||||||
|
std::placeholders::_2,
|
||||||
|
std::move(promise)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void TCPEndpoint::receive(common::DataBuffer buffer, Promise::Pointer promise)
|
||||||
|
{
|
||||||
|
tcpWrapper_.asyncRead(*socket_, std::move(buffer),
|
||||||
|
std::bind(&TCPEndpoint::asyncOperationHandler,
|
||||||
|
this->shared_from_this(),
|
||||||
|
std::placeholders::_1,
|
||||||
|
std::placeholders::_2,
|
||||||
|
std::move(promise)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void TCPEndpoint::stop()
|
||||||
|
{
|
||||||
|
tcpWrapper_.close(*socket_);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TCPEndpoint::asyncOperationHandler(const boost::system::error_code& ec, size_t bytesTransferred, Promise::Pointer promise)
|
||||||
|
{
|
||||||
|
if(!ec)
|
||||||
|
{
|
||||||
|
promise->resolve(bytesTransferred);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
auto error = ec == boost::asio::error::operation_aborted ? error::Error(error::ErrorCode::OPERATION_ABORTED) : error::Error(error::ErrorCode::TCP_TRANSFER, static_cast<uint32_t>(ec.value()));
|
||||||
|
promise->reject(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,132 @@
|
||||||
|
/*
|
||||||
|
* This file is part of aasdk library project.
|
||||||
|
* Copyright (C) 2018 f1x.studio (Michal Szwaj)
|
||||||
|
*
|
||||||
|
* aasdk is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
|
||||||
|
* aasdk 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 General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with aasdk. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <boost/test/unit_test.hpp>
|
||||||
|
#include <f1x/aasdk/TCP/UT/TCPWrapper.mock.hpp>
|
||||||
|
#include <f1x/aasdk/TCP/UT/TCPEndpointPromiseHandler.mock.hpp>
|
||||||
|
#include <f1x/aasdk/TCP/TCPEndpoint.hpp>
|
||||||
|
|
||||||
|
namespace f1x
|
||||||
|
{
|
||||||
|
namespace aasdk
|
||||||
|
{
|
||||||
|
namespace tcp
|
||||||
|
{
|
||||||
|
namespace ut
|
||||||
|
{
|
||||||
|
|
||||||
|
using ::testing::_;
|
||||||
|
using ::testing::SaveArg;
|
||||||
|
|
||||||
|
class TCPEndpointUnitTest
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
TCPEndpointUnitTest()
|
||||||
|
: socket_(std::make_shared<boost::asio::ip::tcp::socket>(ioService_))
|
||||||
|
, promise_(ITCPEndpoint::Promise::defer(ioService_))
|
||||||
|
{
|
||||||
|
promise_->then(std::bind(&TCPEndpointPromiseHandlerMock::onResolve, &promiseHandlerMock_, std::placeholders::_1),
|
||||||
|
std::bind(&TCPEndpointPromiseHandlerMock::onReject, &promiseHandlerMock_, std::placeholders::_1));
|
||||||
|
}
|
||||||
|
|
||||||
|
TCPWrapperMock tcpWrapperMock_;
|
||||||
|
TCPEndpointPromiseHandlerMock promiseHandlerMock_;
|
||||||
|
boost::asio::io_service ioService_;
|
||||||
|
ITCPEndpoint::SocketPointer socket_;
|
||||||
|
ITCPEndpoint::Promise::Pointer promise_;
|
||||||
|
};
|
||||||
|
|
||||||
|
BOOST_FIXTURE_TEST_CASE(TCPEndpoint_Receive, TCPEndpointUnitTest)
|
||||||
|
{
|
||||||
|
auto tcpEndpoint = std::make_shared<TCPEndpoint>(tcpWrapperMock_, std::move(socket_));
|
||||||
|
|
||||||
|
common::DataBuffer buffer;
|
||||||
|
ITCPWrapper::Handler handler;
|
||||||
|
EXPECT_CALL(tcpWrapperMock_, asyncRead(_, _, _)).WillOnce(DoAll(SaveArg<1>(&buffer), SaveArg<2>(&handler)));
|
||||||
|
|
||||||
|
common::Data actualData(100, 0);
|
||||||
|
tcpEndpoint->receive(common::DataBuffer(actualData), std::move(promise_));
|
||||||
|
|
||||||
|
const common::Data expectedData(actualData.size(), 0x5F);
|
||||||
|
std::copy(expectedData.begin(), expectedData.end(), buffer.data);
|
||||||
|
|
||||||
|
EXPECT_CALL(promiseHandlerMock_, onResolve(expectedData.size()));
|
||||||
|
EXPECT_CALL(promiseHandlerMock_, onReject(_)).Times(0);
|
||||||
|
handler(boost::system::error_code(), expectedData.size());
|
||||||
|
|
||||||
|
ioService_.run();
|
||||||
|
|
||||||
|
BOOST_CHECK_EQUAL_COLLECTIONS(actualData.begin(), actualData.end(), expectedData.begin(), expectedData.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_FIXTURE_TEST_CASE(TCPEndpoint_ReceiveError, TCPEndpointUnitTest)
|
||||||
|
{
|
||||||
|
auto tcpEndpoint = std::make_shared<TCPEndpoint>(tcpWrapperMock_, std::move(socket_));
|
||||||
|
|
||||||
|
common::DataBuffer buffer;
|
||||||
|
ITCPWrapper::Handler handler;
|
||||||
|
EXPECT_CALL(tcpWrapperMock_, asyncRead(_, _, _)).WillOnce(DoAll(SaveArg<1>(&buffer), SaveArg<2>(&handler)));
|
||||||
|
|
||||||
|
common::Data actualData(100, 0);
|
||||||
|
tcpEndpoint->receive(common::DataBuffer(actualData), std::move(promise_));
|
||||||
|
|
||||||
|
EXPECT_CALL(promiseHandlerMock_, onResolve(_)).Times(0);
|
||||||
|
EXPECT_CALL(promiseHandlerMock_, onReject(error::Error(error::ErrorCode::TCP_TRANSFER, boost::asio::error::bad_descriptor)));
|
||||||
|
handler(boost::asio::error::bad_descriptor, 0);
|
||||||
|
|
||||||
|
ioService_.run();
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_FIXTURE_TEST_CASE(TCPEndpoint_Send, TCPEndpointUnitTest)
|
||||||
|
{
|
||||||
|
auto tcpEndpoint = std::make_shared<TCPEndpoint>(tcpWrapperMock_, std::move(socket_));
|
||||||
|
|
||||||
|
common::Data actualData(100, 0);
|
||||||
|
common::DataConstBuffer buffer(actualData);
|
||||||
|
ITCPWrapper::Handler handler;
|
||||||
|
EXPECT_CALL(tcpWrapperMock_, asyncWrite(_, buffer, _)).WillOnce(SaveArg<2>(&handler));
|
||||||
|
tcpEndpoint->send(common::DataConstBuffer(actualData), std::move(promise_));
|
||||||
|
|
||||||
|
EXPECT_CALL(promiseHandlerMock_, onResolve(actualData.size()));
|
||||||
|
EXPECT_CALL(promiseHandlerMock_, onReject(_)).Times(0);
|
||||||
|
handler(boost::system::error_code(), actualData.size());
|
||||||
|
|
||||||
|
ioService_.run();
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_FIXTURE_TEST_CASE(TCPEndpoint_SendError, TCPEndpointUnitTest)
|
||||||
|
{
|
||||||
|
auto tcpEndpoint = std::make_shared<TCPEndpoint>(tcpWrapperMock_, std::move(socket_));
|
||||||
|
|
||||||
|
common::Data actualData(100, 0);
|
||||||
|
common::DataConstBuffer buffer(actualData);
|
||||||
|
ITCPWrapper::Handler handler;
|
||||||
|
EXPECT_CALL(tcpWrapperMock_, asyncWrite(_, buffer, _)).WillOnce(SaveArg<2>(&handler));
|
||||||
|
tcpEndpoint->send(common::DataConstBuffer(actualData), std::move(promise_));
|
||||||
|
|
||||||
|
EXPECT_CALL(promiseHandlerMock_, onResolve(_)).Times(0);
|
||||||
|
EXPECT_CALL(promiseHandlerMock_, onReject(error::Error(error::ErrorCode::OPERATION_ABORTED)));
|
||||||
|
handler(boost::asio::error::operation_aborted, 0);
|
||||||
|
|
||||||
|
ioService_.run();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,60 @@
|
||||||
|
/*
|
||||||
|
* This file is part of aasdk library project.
|
||||||
|
* Copyright (C) 2018 f1x.studio (Michal Szwaj)
|
||||||
|
*
|
||||||
|
* aasdk is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
|
||||||
|
* aasdk 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 General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with aasdk. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <boost/asio.hpp>
|
||||||
|
#include <f1x/aasdk/TCP/TCPWrapper.hpp>
|
||||||
|
|
||||||
|
namespace f1x
|
||||||
|
{
|
||||||
|
namespace aasdk
|
||||||
|
{
|
||||||
|
namespace tcp
|
||||||
|
{
|
||||||
|
|
||||||
|
void TCPWrapper::asyncWrite(boost::asio::ip::tcp::socket& socket, common::DataConstBuffer buffer, Handler handler)
|
||||||
|
{
|
||||||
|
boost::asio::async_write(socket, boost::asio::buffer(buffer.cdata, buffer.size), std::move(handler));
|
||||||
|
}
|
||||||
|
|
||||||
|
void TCPWrapper::asyncRead(boost::asio::ip::tcp::socket& socket, common::DataBuffer buffer, Handler handler)
|
||||||
|
{
|
||||||
|
socket.async_receive(boost::asio::buffer(buffer.data, buffer.size), std::move(handler));
|
||||||
|
}
|
||||||
|
|
||||||
|
void TCPWrapper::close(boost::asio::ip::tcp::socket& socket)
|
||||||
|
{
|
||||||
|
boost::system::error_code ec;
|
||||||
|
socket.shutdown(boost::asio::ip::tcp::socket::shutdown_both, ec);
|
||||||
|
socket.close(ec);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TCPWrapper::asyncConnect(boost::asio::ip::tcp::socket& socket, const std::string& hostname, uint16_t port, ConnectHandler handler)
|
||||||
|
{
|
||||||
|
socket.async_connect(boost::asio::ip::tcp::endpoint(boost::asio::ip::address::from_string(hostname), port), std::move(handler));
|
||||||
|
}
|
||||||
|
|
||||||
|
boost::system::error_code TCPWrapper::connect(boost::asio::ip::tcp::socket& socket, const std::string& hostname, uint16_t port)
|
||||||
|
{
|
||||||
|
boost::system::error_code ec;
|
||||||
|
socket.connect(boost::asio::ip::tcp::endpoint(boost::asio::ip::address::from_string(hostname), port), ec);
|
||||||
|
return ec;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -17,7 +17,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <f1x/aasdk/Transport/USBDataSink.hpp>
|
#include <f1x/aasdk/Transport/DataSink.hpp>
|
||||||
#include <f1x/aasdk/Error/Error.hpp>
|
#include <f1x/aasdk/Error/Error.hpp>
|
||||||
|
|
||||||
namespace f1x
|
namespace f1x
|
||||||
|
@ -27,44 +27,45 @@ namespace aasdk
|
||||||
namespace transport
|
namespace transport
|
||||||
{
|
{
|
||||||
|
|
||||||
USBDataSink::USBDataSink()
|
DataSink::DataSink()
|
||||||
: data_(common::cStaticDataSize)
|
: data_(common::cStaticDataSize)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
common::DataBuffer USBDataSink::fill()
|
common::DataBuffer DataSink::fill()
|
||||||
{
|
{
|
||||||
const auto offset = data_.size();
|
const auto offset = data_.size();
|
||||||
data_.resize(data_.size() + cChunkSize);
|
data_.resize(data_.size() + cChunkSize);
|
||||||
|
|
||||||
return common::DataBuffer(&data_[offset], cChunkSize);
|
auto ptr = data_.is_linearized() ? &data_[offset] : data_.linearize() + offset;
|
||||||
|
return common::DataBuffer(ptr, cChunkSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
void USBDataSink::commit(common::Data::size_type size)
|
void DataSink::commit(common::Data::size_type size)
|
||||||
{
|
{
|
||||||
if(size > cChunkSize)
|
if(size > cChunkSize)
|
||||||
{
|
{
|
||||||
throw error::Error(error::ErrorCode::USB_SINK_COMMIT_OVERFLOW);
|
throw error::Error(error::ErrorCode::DATA_SINK_COMMIT_OVERFLOW);
|
||||||
}
|
}
|
||||||
|
|
||||||
data_.resize(data_.size() - (cChunkSize - size));
|
data_.erase_end((cChunkSize - size));
|
||||||
}
|
}
|
||||||
|
|
||||||
common::Data::size_type USBDataSink::getAvailableSize()
|
common::Data::size_type DataSink::getAvailableSize()
|
||||||
{
|
{
|
||||||
return data_.size();
|
return data_.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
common::Data USBDataSink::consume(common::Data::size_type size)
|
common::Data DataSink::consume(common::Data::size_type size)
|
||||||
{
|
{
|
||||||
if(size > data_.size())
|
if(size > data_.size())
|
||||||
{
|
{
|
||||||
throw error::Error(error::ErrorCode::USB_SINK_CONSUME_UNDERFLOW);
|
throw error::Error(error::ErrorCode::DATA_SINK_CONSUME_UNDERFLOW);
|
||||||
}
|
}
|
||||||
|
|
||||||
common::Data data;
|
common::Data data(size, 0);
|
||||||
common::copy(data, common::DataConstBuffer(&data_[0], size));
|
std::copy(data_.begin(), data_.begin() + size, data.begin());
|
||||||
data_.erase(data_.begin(), data_.begin() + size);
|
data_.erase_begin(size);
|
||||||
|
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
|
@ -0,0 +1,88 @@
|
||||||
|
/*
|
||||||
|
* This file is part of aasdk library project.
|
||||||
|
* Copyright (C) 2018 f1x.studio (Michal Szwaj)
|
||||||
|
*
|
||||||
|
* aasdk is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
|
||||||
|
* aasdk 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 General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with aasdk. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <f1x/aasdk/Transport/TCPTransport.hpp>
|
||||||
|
|
||||||
|
namespace f1x
|
||||||
|
{
|
||||||
|
namespace aasdk
|
||||||
|
{
|
||||||
|
namespace transport
|
||||||
|
{
|
||||||
|
|
||||||
|
TCPTransport::TCPTransport(boost::asio::io_service& ioService, tcp::ITCPEndpoint::Pointer tcpEndpoint)
|
||||||
|
: Transport(ioService)
|
||||||
|
, tcpEndpoint_(std::move(tcpEndpoint))
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void TCPTransport::enqueueReceive(common::DataBuffer buffer)
|
||||||
|
{
|
||||||
|
auto receivePromise = tcp::ITCPEndpoint::Promise::defer(receiveStrand_);
|
||||||
|
receivePromise->then([this, self = this->shared_from_this()](auto bytesTransferred) {
|
||||||
|
this->receiveHandler(bytesTransferred);
|
||||||
|
},
|
||||||
|
[this, self = this->shared_from_this()](auto e) {
|
||||||
|
this->rejectReceivePromises(e);
|
||||||
|
});
|
||||||
|
|
||||||
|
tcpEndpoint_->receive(buffer, std::move(receivePromise));
|
||||||
|
}
|
||||||
|
|
||||||
|
void TCPTransport::enqueueSend(SendQueue::iterator queueElement)
|
||||||
|
{
|
||||||
|
auto sendPromise = tcp::ITCPEndpoint::Promise::defer(sendStrand_);
|
||||||
|
|
||||||
|
sendPromise->then([this, self = this->shared_from_this(), queueElement](auto) {
|
||||||
|
this->sendHandler(queueElement, error::Error());
|
||||||
|
},
|
||||||
|
[this, self = this->shared_from_this(), queueElement](auto e) {
|
||||||
|
this->sendHandler(queueElement, e);
|
||||||
|
});
|
||||||
|
|
||||||
|
tcpEndpoint_->send(common::DataConstBuffer(queueElement->first), std::move(sendPromise));
|
||||||
|
}
|
||||||
|
|
||||||
|
void TCPTransport::stop()
|
||||||
|
{
|
||||||
|
tcpEndpoint_->stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
void TCPTransport::sendHandler(SendQueue::iterator queueElement, const error::Error& e)
|
||||||
|
{
|
||||||
|
if(!e)
|
||||||
|
{
|
||||||
|
queueElement->second->resolve();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
queueElement->second->reject(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
sendQueue_.erase(queueElement);
|
||||||
|
|
||||||
|
if(!sendQueue_.empty())
|
||||||
|
{
|
||||||
|
this->enqueueSend(sendQueue_.begin());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,279 @@
|
||||||
|
/*
|
||||||
|
* This file is part of aasdk library project.
|
||||||
|
* Copyright (C) 2018 f1x.studio (Michal Szwaj)
|
||||||
|
*
|
||||||
|
* aasdk is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
|
||||||
|
* aasdk 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 General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with aasdk. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <boost/test/unit_test.hpp>
|
||||||
|
#include <f1x/aasdk/TCP/UT/TCPEndpoint.mock.hpp>
|
||||||
|
#include <f1x/aasdk/Transport/UT/TransportReceivePromiseHandler.mock.hpp>
|
||||||
|
#include <f1x/aasdk/Transport/UT/TransportSendPromiseHandler.mock.hpp>
|
||||||
|
#include <f1x/aasdk/Transport/TCPTransport.hpp>
|
||||||
|
|
||||||
|
namespace f1x
|
||||||
|
{
|
||||||
|
namespace aasdk
|
||||||
|
{
|
||||||
|
namespace transport
|
||||||
|
{
|
||||||
|
namespace ut
|
||||||
|
{
|
||||||
|
|
||||||
|
using ::testing::ReturnRef;
|
||||||
|
using ::testing::SaveArg;
|
||||||
|
using ::testing::_;
|
||||||
|
using ::testing::AtLeast;
|
||||||
|
|
||||||
|
class TCPTransportUnitTest
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
TCPTransportUnitTest()
|
||||||
|
: receivePromise_(ITransport::ReceivePromise::defer(ioService_))
|
||||||
|
, sendPromise_(ITransport::SendPromise::defer(ioService_))
|
||||||
|
, tcpEndpoint_(&tcpEndpointMock_, [](auto*) {})
|
||||||
|
{
|
||||||
|
receivePromise_->then(std::bind(&TransportReceivePromiseHandlerMock::onResolve, &receivePromiseHandlerMock_, std::placeholders::_1),
|
||||||
|
std::bind(&TransportReceivePromiseHandlerMock::onReject, &receivePromiseHandlerMock_, std::placeholders::_1));
|
||||||
|
|
||||||
|
sendPromise_->then(std::bind(&TransportSendPromiseHandlerMock::onResolve, &sendPromiseHandlerMock_),
|
||||||
|
std::bind(&TransportSendPromiseHandlerMock::onReject, &sendPromiseHandlerMock_, std::placeholders::_1));
|
||||||
|
}
|
||||||
|
|
||||||
|
boost::asio::io_service ioService_;
|
||||||
|
tcp::ut::TCPEndpointMock tcpEndpointMock_;
|
||||||
|
TransportReceivePromiseHandlerMock receivePromiseHandlerMock_;
|
||||||
|
ITransport::ReceivePromise::Pointer receivePromise_;
|
||||||
|
TransportSendPromiseHandlerMock sendPromiseHandlerMock_;
|
||||||
|
ITransport::SendPromise::Pointer sendPromise_;
|
||||||
|
tcp::ITCPEndpoint::Pointer tcpEndpoint_;
|
||||||
|
};
|
||||||
|
|
||||||
|
BOOST_FIXTURE_TEST_CASE(TCPTransport_ReceiveAtOnce, TCPTransportUnitTest)
|
||||||
|
{
|
||||||
|
const size_t receiveSize = 100;
|
||||||
|
|
||||||
|
tcp::ITCPEndpoint::Promise::Pointer tcpEndpointPromise;
|
||||||
|
common::DataBuffer dataBuffer;
|
||||||
|
EXPECT_CALL(tcpEndpointMock_, receive(_, _)).WillOnce(DoAll(SaveArg<0>(&dataBuffer), SaveArg<1>(&tcpEndpointPromise)));
|
||||||
|
|
||||||
|
auto transport(std::make_shared<TCPTransport>(ioService_, tcpEndpoint_));
|
||||||
|
transport->receive(receiveSize, std::move(receivePromise_));
|
||||||
|
ioService_.run();
|
||||||
|
ioService_.reset();
|
||||||
|
|
||||||
|
BOOST_TEST(dataBuffer.size >= receiveSize);
|
||||||
|
common::Data expectedData(receiveSize, 0x5E);
|
||||||
|
std::copy(expectedData.begin(), expectedData.end(), dataBuffer.data);
|
||||||
|
|
||||||
|
EXPECT_CALL(receivePromiseHandlerMock_, onResolve(expectedData)).Times(1);
|
||||||
|
EXPECT_CALL(receivePromiseHandlerMock_, onReject(_)).Times(0);
|
||||||
|
tcpEndpointPromise->resolve(receiveSize);
|
||||||
|
ioService_.run();
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_FIXTURE_TEST_CASE(TCPTransport_ReceiveInPieces, TCPTransportUnitTest)
|
||||||
|
{
|
||||||
|
const size_t stepsCount = 100;
|
||||||
|
const size_t receiveSize = 1000 * stepsCount;
|
||||||
|
const size_t stepSize = receiveSize / stepsCount;
|
||||||
|
|
||||||
|
auto transport(std::make_shared<TCPTransport>(ioService_, tcpEndpoint_));
|
||||||
|
transport->receive(receiveSize, std::move(receivePromise_));
|
||||||
|
|
||||||
|
tcp::ITCPEndpoint::Promise::Pointer tcpEndpointPromise;
|
||||||
|
common::DataBuffer dataBuffer;
|
||||||
|
EXPECT_CALL(tcpEndpointMock_, receive(_, _)).Times(AtLeast(stepsCount))
|
||||||
|
.WillRepeatedly(DoAll(SaveArg<0>(&dataBuffer), SaveArg<1>(&tcpEndpointPromise)));
|
||||||
|
|
||||||
|
common::Data expectedData(receiveSize, 0x5E);
|
||||||
|
EXPECT_CALL(receivePromiseHandlerMock_, onResolve(expectedData)).Times(1);
|
||||||
|
EXPECT_CALL(receivePromiseHandlerMock_, onReject(_)).Times(0);
|
||||||
|
|
||||||
|
for(size_t i = 0; i < stepsCount; ++i)
|
||||||
|
{
|
||||||
|
ioService_.run();
|
||||||
|
ioService_.reset();
|
||||||
|
|
||||||
|
BOOST_TEST(dataBuffer.size >= stepSize);
|
||||||
|
|
||||||
|
std::fill(dataBuffer.data, dataBuffer.data + stepSize, 0x5E);
|
||||||
|
tcpEndpointPromise->resolve(stepSize);
|
||||||
|
ioService_.run();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_FIXTURE_TEST_CASE(TCPTransport_OnlyOneReceiveAtATime, TCPTransportUnitTest)
|
||||||
|
{
|
||||||
|
const size_t receiveSize = 200;
|
||||||
|
const size_t stepSize = receiveSize / 2;
|
||||||
|
|
||||||
|
tcp::ITCPEndpoint::Promise::Pointer tcpEndpointPromise;
|
||||||
|
common::DataBuffer dataBuffer;
|
||||||
|
EXPECT_CALL(tcpEndpointMock_, receive(_, _)).WillOnce(DoAll(SaveArg<0>(&dataBuffer), SaveArg<1>(&tcpEndpointPromise)));
|
||||||
|
|
||||||
|
auto transport(std::make_shared<TCPTransport>(ioService_, tcpEndpoint_));
|
||||||
|
transport->receive(stepSize, std::move(receivePromise_));
|
||||||
|
ioService_.run();
|
||||||
|
ioService_.reset();
|
||||||
|
|
||||||
|
BOOST_TEST(dataBuffer.size >= receiveSize);
|
||||||
|
std::fill(dataBuffer.data, dataBuffer.data + stepSize, 0x5E);
|
||||||
|
std::fill(dataBuffer.data + stepSize, dataBuffer.data + receiveSize, 0x5F);
|
||||||
|
|
||||||
|
auto secondPromise = ITransport::ReceivePromise::defer(ioService_);
|
||||||
|
TransportReceivePromiseHandlerMock secondPromiseHandlerMock;
|
||||||
|
secondPromise->then(std::bind(&TransportReceivePromiseHandlerMock::onResolve, &secondPromiseHandlerMock, std::placeholders::_1),
|
||||||
|
std::bind(&TransportReceivePromiseHandlerMock::onReject, &secondPromiseHandlerMock, std::placeholders::_1));
|
||||||
|
|
||||||
|
transport->receive(stepSize, std::move(secondPromise));
|
||||||
|
ioService_.run();
|
||||||
|
ioService_.reset();
|
||||||
|
|
||||||
|
common::Data expectedData(stepSize, 0x5E);
|
||||||
|
EXPECT_CALL(receivePromiseHandlerMock_, onResolve(expectedData)).Times(1);
|
||||||
|
EXPECT_CALL(receivePromiseHandlerMock_, onReject(_)).Times(0);
|
||||||
|
|
||||||
|
common::Data secondExpectedData(stepSize, 0x5F);
|
||||||
|
EXPECT_CALL(secondPromiseHandlerMock, onResolve(secondExpectedData)).Times(1);
|
||||||
|
EXPECT_CALL(secondPromiseHandlerMock, onReject(_)).Times(0);
|
||||||
|
|
||||||
|
tcpEndpointPromise->resolve(receiveSize);
|
||||||
|
ioService_.run();
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_FIXTURE_TEST_CASE(TCPTransport_ReceiveError, TCPTransportUnitTest)
|
||||||
|
{
|
||||||
|
tcp::ITCPEndpoint::Promise::Pointer tcpEndpointPromise;
|
||||||
|
EXPECT_CALL(tcpEndpointMock_, receive(_, _)).WillOnce(SaveArg<1>(&tcpEndpointPromise));
|
||||||
|
|
||||||
|
auto transport(std::make_shared<TCPTransport>(ioService_, tcpEndpoint_));
|
||||||
|
transport->receive(1000, std::move(receivePromise_));
|
||||||
|
|
||||||
|
auto secondPromise = ITransport::ReceivePromise::defer(ioService_);
|
||||||
|
secondPromise->then(std::bind(&TransportReceivePromiseHandlerMock::onResolve, &receivePromiseHandlerMock_, std::placeholders::_1),
|
||||||
|
std::bind(&TransportReceivePromiseHandlerMock::onReject, &receivePromiseHandlerMock_, std::placeholders::_1));
|
||||||
|
|
||||||
|
transport->receive(1000, std::move(secondPromise));
|
||||||
|
ioService_.run();
|
||||||
|
ioService_.reset();
|
||||||
|
|
||||||
|
const error::Error e(error::ErrorCode::TCP_TRANSFER, 11);
|
||||||
|
EXPECT_CALL(receivePromiseHandlerMock_, onResolve(_)).Times(0);
|
||||||
|
EXPECT_CALL(receivePromiseHandlerMock_, onReject(e)).Times(2);
|
||||||
|
|
||||||
|
tcpEndpointPromise->reject(e);
|
||||||
|
ioService_.run();
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_FIXTURE_TEST_CASE(TCPTransport_Send, TCPTransportUnitTest)
|
||||||
|
{
|
||||||
|
tcp::ITCPEndpoint::Promise::Pointer tcpEndpointPromise;
|
||||||
|
common::DataConstBuffer buffer;
|
||||||
|
EXPECT_CALL(tcpEndpointMock_, send(_, _)).WillOnce(DoAll(SaveArg<0>(&buffer), SaveArg<1>(&tcpEndpointPromise)));
|
||||||
|
|
||||||
|
auto transport(std::make_shared<TCPTransport>(ioService_, tcpEndpoint_));
|
||||||
|
const common::Data expectedData(1000, 0x5E);
|
||||||
|
transport->send(expectedData, std::move(sendPromise_));
|
||||||
|
ioService_.run();
|
||||||
|
ioService_.reset();
|
||||||
|
|
||||||
|
common::Data actualData(buffer.cdata, buffer.cdata + buffer.size);
|
||||||
|
BOOST_CHECK_EQUAL_COLLECTIONS(actualData.begin(), actualData.end(), expectedData.begin(), expectedData.end());
|
||||||
|
|
||||||
|
EXPECT_CALL(sendPromiseHandlerMock_, onReject(_)).Times(0);
|
||||||
|
EXPECT_CALL(sendPromiseHandlerMock_, onResolve());
|
||||||
|
tcpEndpointPromise->resolve(expectedData.size());
|
||||||
|
ioService_.run();
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_FIXTURE_TEST_CASE(TCPTransport_OnlyOneSendAtATime, TCPTransportUnitTest)
|
||||||
|
{
|
||||||
|
tcp::ITCPEndpoint::Promise::Pointer tcpEndpointPromise;
|
||||||
|
common::DataConstBuffer buffer;
|
||||||
|
EXPECT_CALL(tcpEndpointMock_, send(_, _)).Times(2).WillRepeatedly(DoAll(SaveArg<0>(&buffer), SaveArg<1>(&tcpEndpointPromise)));
|
||||||
|
|
||||||
|
auto transport(std::make_shared<TCPTransport>(ioService_, tcpEndpoint_));
|
||||||
|
const common::Data expectedData1(1000, 0x5E);
|
||||||
|
transport->send(expectedData1, std::move(sendPromise_));
|
||||||
|
ioService_.run();
|
||||||
|
ioService_.reset();
|
||||||
|
|
||||||
|
const common::Data expectedData2(3000, 0x5F);
|
||||||
|
|
||||||
|
auto secondSendPromise = ITransport::SendPromise::defer(ioService_);
|
||||||
|
TransportSendPromiseHandlerMock secondSendPromiseHandlerMock;
|
||||||
|
secondSendPromise->then(std::bind(&TransportSendPromiseHandlerMock::onResolve, &secondSendPromiseHandlerMock),
|
||||||
|
std::bind(&TransportSendPromiseHandlerMock::onReject, &secondSendPromiseHandlerMock, std::placeholders::_1));
|
||||||
|
|
||||||
|
transport->send(expectedData2, std::move(secondSendPromise));
|
||||||
|
ioService_.run();
|
||||||
|
ioService_.reset();
|
||||||
|
|
||||||
|
common::Data actualData1(buffer.cdata, buffer.cdata + buffer.size);
|
||||||
|
BOOST_CHECK_EQUAL_COLLECTIONS(actualData1.begin(), actualData1.end(), expectedData1.begin(), expectedData1.end());
|
||||||
|
|
||||||
|
EXPECT_CALL(sendPromiseHandlerMock_, onReject(_)).Times(0);
|
||||||
|
EXPECT_CALL(sendPromiseHandlerMock_, onResolve());
|
||||||
|
tcpEndpointPromise->resolve(expectedData1.size());
|
||||||
|
ioService_.run();
|
||||||
|
ioService_.reset();
|
||||||
|
|
||||||
|
common::Data actualData2(buffer.cdata, buffer.cdata + buffer.size);
|
||||||
|
BOOST_CHECK_EQUAL_COLLECTIONS(actualData2.begin(), actualData2.end(), expectedData2.begin(), expectedData2.end());
|
||||||
|
|
||||||
|
EXPECT_CALL(secondSendPromiseHandlerMock, onReject(_)).Times(0);
|
||||||
|
EXPECT_CALL(secondSendPromiseHandlerMock, onResolve());
|
||||||
|
tcpEndpointPromise->resolve(expectedData2.size());
|
||||||
|
ioService_.run();
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_FIXTURE_TEST_CASE(TCPTransport_SendError, TCPTransportUnitTest)
|
||||||
|
{
|
||||||
|
tcp::ITCPEndpoint::Promise::Pointer tcpEndpointPromise;
|
||||||
|
EXPECT_CALL(tcpEndpointMock_, send(_, _)).Times(2).WillRepeatedly(SaveArg<1>(&tcpEndpointPromise));
|
||||||
|
|
||||||
|
auto transport(std::make_shared<TCPTransport>(ioService_, tcpEndpoint_));
|
||||||
|
const common::Data expectedData1(1000, 0x5E);
|
||||||
|
transport->send(expectedData1, std::move(sendPromise_));
|
||||||
|
ioService_.run();
|
||||||
|
ioService_.reset();
|
||||||
|
|
||||||
|
auto secondSendPromise = ITransport::SendPromise::defer(ioService_);
|
||||||
|
TransportSendPromiseHandlerMock secondSendPromiseHandlerMock;
|
||||||
|
secondSendPromise->then(std::bind(&TransportSendPromiseHandlerMock::onResolve, &secondSendPromiseHandlerMock),
|
||||||
|
std::bind(&TransportSendPromiseHandlerMock::onReject, &secondSendPromiseHandlerMock, std::placeholders::_1));
|
||||||
|
|
||||||
|
const common::Data expectedData2(3000, 0x5F);
|
||||||
|
transport->send(expectedData2, std::move(secondSendPromise));
|
||||||
|
ioService_.run();
|
||||||
|
ioService_.reset();
|
||||||
|
|
||||||
|
const error::Error e(error::ErrorCode::USB_TRANSFER, 15);
|
||||||
|
EXPECT_CALL(sendPromiseHandlerMock_, onReject(e));
|
||||||
|
EXPECT_CALL(sendPromiseHandlerMock_, onResolve()).Times(0);
|
||||||
|
tcpEndpointPromise->reject(e);
|
||||||
|
ioService_.run();
|
||||||
|
ioService_.reset();
|
||||||
|
|
||||||
|
EXPECT_CALL(secondSendPromiseHandlerMock, onReject(_)).Times(0);
|
||||||
|
EXPECT_CALL(secondSendPromiseHandlerMock, onResolve());
|
||||||
|
tcpEndpointPromise->resolve(expectedData2.size());
|
||||||
|
ioService_.run();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,109 @@
|
||||||
|
/*
|
||||||
|
* This file is part of aasdk library project.
|
||||||
|
* Copyright (C) 2018 f1x.studio (Michal Szwaj)
|
||||||
|
*
|
||||||
|
* aasdk is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
|
||||||
|
* aasdk 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 General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with aasdk. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <f1x/aasdk/Transport/Transport.hpp>
|
||||||
|
|
||||||
|
namespace f1x
|
||||||
|
{
|
||||||
|
namespace aasdk
|
||||||
|
{
|
||||||
|
namespace transport
|
||||||
|
{
|
||||||
|
|
||||||
|
Transport::Transport(boost::asio::io_service& ioService)
|
||||||
|
: receiveStrand_(ioService)
|
||||||
|
, sendStrand_(ioService)
|
||||||
|
{}
|
||||||
|
|
||||||
|
void Transport::receive(size_t size, ReceivePromise::Pointer promise)
|
||||||
|
{
|
||||||
|
receiveStrand_.dispatch([this, self = this->shared_from_this(), size, promise = std::move(promise)]() mutable {
|
||||||
|
receiveQueue_.emplace_back(std::make_pair(size, std::move(promise)));
|
||||||
|
|
||||||
|
if(receiveQueue_.size() == 1)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
this->distributeReceivedData();
|
||||||
|
}
|
||||||
|
catch(const error::Error& e)
|
||||||
|
{
|
||||||
|
this->rejectReceivePromises(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void Transport::receiveHandler(size_t bytesTransferred)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
receivedDataSink_.commit(bytesTransferred);
|
||||||
|
this->distributeReceivedData();
|
||||||
|
}
|
||||||
|
catch(const error::Error& e)
|
||||||
|
{
|
||||||
|
this->rejectReceivePromises(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Transport::distributeReceivedData()
|
||||||
|
{
|
||||||
|
for(auto queueElement = receiveQueue_.begin(); queueElement != receiveQueue_.end();)
|
||||||
|
{
|
||||||
|
if(receivedDataSink_.getAvailableSize() < queueElement->first)
|
||||||
|
{
|
||||||
|
auto buffer = receivedDataSink_.fill();
|
||||||
|
this->enqueueReceive(std::move(buffer));
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
auto data(receivedDataSink_.consume(queueElement->first));
|
||||||
|
queueElement->second->resolve(std::move(data));
|
||||||
|
queueElement = receiveQueue_.erase(queueElement);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Transport::rejectReceivePromises(const error::Error& e)
|
||||||
|
{
|
||||||
|
for(auto& queueElement : receiveQueue_)
|
||||||
|
{
|
||||||
|
queueElement.second->reject(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
receiveQueue_.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Transport::send(common::Data data, SendPromise::Pointer promise)
|
||||||
|
{
|
||||||
|
sendStrand_.dispatch([this, self = this->shared_from_this(), data = std::move(data), promise = std::move(promise)]() mutable {
|
||||||
|
sendQueue_.emplace_back(std::make_pair(std::move(data), std::move(promise)));
|
||||||
|
|
||||||
|
if(sendQueue_.size() == 1)
|
||||||
|
{
|
||||||
|
this->enqueueSend(sendQueue_.begin());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -26,116 +26,57 @@ namespace transport
|
||||||
{
|
{
|
||||||
|
|
||||||
USBTransport::USBTransport(boost::asio::io_service& ioService, usb::IAOAPDevice::Pointer aoapDevice)
|
USBTransport::USBTransport(boost::asio::io_service& ioService, usb::IAOAPDevice::Pointer aoapDevice)
|
||||||
: aoapDevice_(std::move(aoapDevice))
|
: Transport(ioService)
|
||||||
, receiveStrand_(ioService)
|
, aoapDevice_(std::move(aoapDevice))
|
||||||
, sendStrand_(ioService)
|
|
||||||
{}
|
{}
|
||||||
|
|
||||||
void USBTransport::receive(size_t size, ReceivePromise::Pointer promise)
|
void USBTransport::enqueueReceive(common::DataBuffer buffer)
|
||||||
{
|
{
|
||||||
receiveStrand_.dispatch([this, self = this->shared_from_this(), size, promise = std::move(promise)]() mutable {
|
auto usbEndpointPromise = usb::IUSBEndpoint::Promise::defer(receiveStrand_);
|
||||||
receiveQueue_.emplace_back(std::make_pair(size, std::move(promise)));
|
usbEndpointPromise->then([this, self = this->shared_from_this()](auto bytesTransferred) {
|
||||||
|
this->receiveHandler(bytesTransferred);
|
||||||
|
},
|
||||||
|
[this, self = this->shared_from_this()](auto e) {
|
||||||
|
this->rejectReceivePromises(e);
|
||||||
|
});
|
||||||
|
|
||||||
if(receiveQueue_.size() == 1)
|
aoapDevice_->getInEndpoint().bulkTransfer(buffer, cReceiveTimeoutMs, std::move(usbEndpointPromise));
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
this->distributeReceivedData();
|
|
||||||
}
|
|
||||||
catch(const error::Error& e)
|
|
||||||
{
|
|
||||||
this->rejectReceivePromises(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void USBTransport::receiveHandler(size_t bytesTransferred)
|
void USBTransport::enqueueSend(SendQueue::iterator queueElement)
|
||||||
{
|
{
|
||||||
try
|
this->doSend(queueElement, 0);
|
||||||
{
|
|
||||||
usbReceivedDataSink_.commit(bytesTransferred);
|
|
||||||
this->distributeReceivedData();
|
|
||||||
}
|
|
||||||
catch(const error::Error& e)
|
|
||||||
{
|
|
||||||
this->rejectReceivePromises(e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void USBTransport::distributeReceivedData()
|
void USBTransport::doSend(SendQueue::iterator queueElement, common::Data::size_type offset)
|
||||||
{
|
|
||||||
for(auto queueElement = receiveQueue_.begin(); queueElement != receiveQueue_.end();)
|
|
||||||
{
|
|
||||||
if(usbReceivedDataSink_.getAvailableSize() < queueElement->first)
|
|
||||||
{
|
|
||||||
auto buffer = usbReceivedDataSink_.fill();
|
|
||||||
|
|
||||||
auto usbEndpointPromise = usb::IUSBEndpoint::Promise::defer(receiveStrand_);
|
|
||||||
usbEndpointPromise->then(std::bind(&USBTransport::receiveHandler, this->shared_from_this(), std::placeholders::_1),
|
|
||||||
std::bind(&USBTransport::rejectReceivePromises, this->shared_from_this(), std::placeholders::_1));
|
|
||||||
aoapDevice_->getInEndpoint().bulkTransfer(buffer, cReceiveTimeoutMs, std::move(usbEndpointPromise));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
auto data(usbReceivedDataSink_.consume(queueElement->first));
|
|
||||||
queueElement->second->resolve(std::move(data));
|
|
||||||
queueElement = receiveQueue_.erase(queueElement);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void USBTransport::rejectReceivePromises(const error::Error& e)
|
|
||||||
{
|
|
||||||
for(auto& queueElement : receiveQueue_)
|
|
||||||
{
|
|
||||||
queueElement.second->reject(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
receiveQueue_.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
void USBTransport::send(common::Data data, SendPromise::Pointer promise)
|
|
||||||
{
|
|
||||||
sendStrand_.dispatch([this, self = this->shared_from_this(), data = std::move(data), promise = std::move(promise)]() mutable {
|
|
||||||
sendQueue_.emplace_back(std::make_pair(std::move(data), std::move(promise)));
|
|
||||||
|
|
||||||
if(sendQueue_.size() == 1)
|
|
||||||
{
|
|
||||||
this->doSend(sendQueue_.begin(), 0);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
void USBTransport::doSend(OutTransferQueue::iterator queueElementIter, common::Data::size_type offset)
|
|
||||||
{
|
{
|
||||||
auto usbEndpointPromise = usb::IUSBEndpoint::Promise::defer(sendStrand_);
|
auto usbEndpointPromise = usb::IUSBEndpoint::Promise::defer(sendStrand_);
|
||||||
usbEndpointPromise->then([this, self = this->shared_from_this(), queueElementIter, offset](size_t bytesTransferred) mutable {
|
usbEndpointPromise->then([this, self = this->shared_from_this(), queueElement, offset](size_t bytesTransferred) mutable {
|
||||||
this->sendHandler(queueElementIter, offset, bytesTransferred);
|
this->sendHandler(queueElement, offset, bytesTransferred);
|
||||||
},
|
},
|
||||||
[this, self = this->shared_from_this(), queueElementIter](const error::Error& e) mutable {
|
[this, self = this->shared_from_this(), queueElement](const error::Error& e) mutable {
|
||||||
queueElementIter->second->reject(e);
|
queueElement->second->reject(e);
|
||||||
sendQueue_.erase(queueElementIter);
|
sendQueue_.erase(queueElement);
|
||||||
|
|
||||||
if(!sendQueue_.empty())
|
if(!sendQueue_.empty())
|
||||||
{
|
{
|
||||||
this->doSend(sendQueue_.begin(), 0);
|
this->doSend(sendQueue_.begin(), 0);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
aoapDevice_->getOutEndpoint().bulkTransfer(common::DataBuffer(queueElementIter->first, offset), cSendTimeoutMs, std::move(usbEndpointPromise));
|
|
||||||
|
aoapDevice_->getOutEndpoint().bulkTransfer(common::DataBuffer(queueElement->first, offset), cSendTimeoutMs, std::move(usbEndpointPromise));
|
||||||
}
|
}
|
||||||
|
|
||||||
void USBTransport::sendHandler(OutTransferQueue::iterator queueElementIter, common::Data::size_type offset, size_t bytesTransferred)
|
void USBTransport::sendHandler(SendQueue::iterator queueElement, common::Data::size_type offset, size_t bytesTransferred)
|
||||||
{
|
{
|
||||||
if(offset + bytesTransferred < queueElementIter->first.size())
|
if(offset + bytesTransferred < queueElement->first.size())
|
||||||
{
|
{
|
||||||
this->doSend(queueElementIter, offset + bytesTransferred);
|
this->doSend(queueElement, offset + bytesTransferred);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
queueElementIter->second->resolve();
|
queueElement->second->resolve();
|
||||||
sendQueue_.erase(queueElementIter);
|
sendQueue_.erase(queueElement);
|
||||||
|
|
||||||
if(!sendQueue_.empty())
|
if(!sendQueue_.empty())
|
||||||
{
|
{
|
||||||
|
|
|
@ -279,8 +279,7 @@ BOOST_FIXTURE_TEST_CASE(USBTransport_OnlyOneSendAtATime, USBTransportUnitTest)
|
||||||
BOOST_FIXTURE_TEST_CASE(USBTransport_SendError, USBTransportUnitTest)
|
BOOST_FIXTURE_TEST_CASE(USBTransport_SendError, USBTransportUnitTest)
|
||||||
{
|
{
|
||||||
usb::IUSBEndpoint::Promise::Pointer usbEndpointPromise;
|
usb::IUSBEndpoint::Promise::Pointer usbEndpointPromise;
|
||||||
common::DataBuffer buffer;
|
EXPECT_CALL(outEndpointMock_, bulkTransfer(_, _, _)).Times(2).WillRepeatedly(SaveArg<2>(&usbEndpointPromise));
|
||||||
EXPECT_CALL(outEndpointMock_, bulkTransfer(_, _, _)).Times(2).WillRepeatedly(DoAll(SaveArg<0>(&buffer), SaveArg<2>(&usbEndpointPromise)));
|
|
||||||
|
|
||||||
USBTransport::Pointer transport(std::make_shared<USBTransport>(ioService_, aoapDevice_));
|
USBTransport::Pointer transport(std::make_shared<USBTransport>(ioService_, aoapDevice_));
|
||||||
const common::Data expectedData1(1000, 0x5E);
|
const common::Data expectedData1(1000, 0x5E);
|
||||||
|
@ -288,13 +287,12 @@ BOOST_FIXTURE_TEST_CASE(USBTransport_SendError, USBTransportUnitTest)
|
||||||
ioService_.run();
|
ioService_.run();
|
||||||
ioService_.reset();
|
ioService_.reset();
|
||||||
|
|
||||||
const common::Data expectedData2(3000, 0x5F);
|
|
||||||
|
|
||||||
auto secondSendPromise = ITransport::SendPromise::defer(ioService_);
|
auto secondSendPromise = ITransport::SendPromise::defer(ioService_);
|
||||||
TransportSendPromiseHandlerMock secondSendPromiseHandlerMock;
|
TransportSendPromiseHandlerMock secondSendPromiseHandlerMock;
|
||||||
secondSendPromise->then(std::bind(&TransportSendPromiseHandlerMock::onResolve, &secondSendPromiseHandlerMock),
|
secondSendPromise->then(std::bind(&TransportSendPromiseHandlerMock::onResolve, &secondSendPromiseHandlerMock),
|
||||||
std::bind(&TransportSendPromiseHandlerMock::onReject, &secondSendPromiseHandlerMock, std::placeholders::_1));
|
std::bind(&TransportSendPromiseHandlerMock::onReject, &secondSendPromiseHandlerMock, std::placeholders::_1));
|
||||||
|
|
||||||
|
const common::Data expectedData2(3000, 0x5F);
|
||||||
transport->send(expectedData2, std::move(secondSendPromise));
|
transport->send(expectedData2, std::move(secondSendPromise));
|
||||||
ioService_.run();
|
ioService_.run();
|
||||||
ioService_.reset();
|
ioService_.reset();
|
||||||
|
|
|
@ -66,11 +66,13 @@ void AccessoryModeQueryChain::start(DeviceHandle handle, Promise::Pointer promis
|
||||||
|
|
||||||
void AccessoryModeQueryChain::cancel()
|
void AccessoryModeQueryChain::cancel()
|
||||||
{
|
{
|
||||||
if(activeQuery_ != nullptr)
|
strand_.dispatch([this, self = this->shared_from_this()]() {
|
||||||
{
|
if(activeQuery_ != nullptr)
|
||||||
activeQuery_->cancel();
|
{
|
||||||
activeQuery_.reset();
|
activeQuery_->cancel();
|
||||||
}
|
activeQuery_.reset();
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void AccessoryModeQueryChain::startQuery(AccessoryModeQueryType queryType, IUSBEndpoint::Pointer usbEndpoint, IAccessoryModeQuery::Promise::Pointer queryPromise)
|
void AccessoryModeQueryChain::startQuery(AccessoryModeQueryType queryType, IUSBEndpoint::Pointer usbEndpoint, IAccessoryModeQuery::Promise::Pointer queryPromise)
|
||||||
|
|
|
@ -0,0 +1,134 @@
|
||||||
|
/*
|
||||||
|
* This file is part of aasdk library project.
|
||||||
|
* Copyright (C) 2018 f1x.studio (Michal Szwaj)
|
||||||
|
*
|
||||||
|
* aasdk is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
|
||||||
|
* aasdk 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 General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with aasdk. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <f1x/aasdk/USB/ConnectedAccessoriesEnumerator.hpp>
|
||||||
|
|
||||||
|
namespace f1x
|
||||||
|
{
|
||||||
|
namespace aasdk
|
||||||
|
{
|
||||||
|
namespace usb
|
||||||
|
{
|
||||||
|
|
||||||
|
ConnectedAccessoriesEnumerator::ConnectedAccessoriesEnumerator(IUSBWrapper& usbWrapper, boost::asio::io_service& ioService, IAccessoryModeQueryChainFactory& queryChainFactory)
|
||||||
|
: usbWrapper_(usbWrapper)
|
||||||
|
, strand_(ioService)
|
||||||
|
, queryChainFactory_(queryChainFactory)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConnectedAccessoriesEnumerator::enumerate(Promise::Pointer promise)
|
||||||
|
{
|
||||||
|
strand_.dispatch([this, self = this->shared_from_this(), promise = std::move(promise)]() mutable {
|
||||||
|
if(promise_ != nullptr)
|
||||||
|
{
|
||||||
|
promise->reject(error::Error(error::ErrorCode::OPERATION_IN_PROGRESS));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
promise_ = std::move(promise);
|
||||||
|
|
||||||
|
auto result = usbWrapper_.getDeviceList(deviceListHandle_);
|
||||||
|
|
||||||
|
if(result < 0)
|
||||||
|
{
|
||||||
|
promise_->reject(error::Error(error::ErrorCode::USB_LIST_DEVICES));
|
||||||
|
}
|
||||||
|
else if(deviceListHandle_->empty())
|
||||||
|
{
|
||||||
|
promise_->resolve(false);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
actualDeviceIter_ = deviceListHandle_->begin();
|
||||||
|
this->queryNextDevice();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConnectedAccessoriesEnumerator::cancel()
|
||||||
|
{
|
||||||
|
strand_.dispatch([this, self = this->shared_from_this()]() mutable {
|
||||||
|
if(queryChain_ != nullptr)
|
||||||
|
{
|
||||||
|
queryChain_->cancel();
|
||||||
|
queryChain_.reset();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConnectedAccessoriesEnumerator::queryNextDevice()
|
||||||
|
{
|
||||||
|
auto deviceHandle = this->getNextDeviceHandle();
|
||||||
|
|
||||||
|
if(deviceHandle != nullptr)
|
||||||
|
{
|
||||||
|
queryChain_ = queryChainFactory_.create();
|
||||||
|
auto queryChainPromise = IAccessoryModeQueryChain::Promise::defer(strand_);
|
||||||
|
|
||||||
|
queryChainPromise->then([this, self = this->shared_from_this()](DeviceHandle) mutable {
|
||||||
|
promise_->resolve(true);
|
||||||
|
this->reset();
|
||||||
|
},
|
||||||
|
[this, self = this->shared_from_this()](const error::Error& e) mutable {
|
||||||
|
if(e != error::ErrorCode::OPERATION_ABORTED)
|
||||||
|
{
|
||||||
|
this->queryNextDevice();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
queryChain_->start(std::move(deviceHandle), std::move(queryChainPromise));
|
||||||
|
}
|
||||||
|
else if(actualDeviceIter_ == deviceListHandle_->end())
|
||||||
|
{
|
||||||
|
promise_->resolve(false);
|
||||||
|
this->reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DeviceHandle ConnectedAccessoriesEnumerator::getNextDeviceHandle()
|
||||||
|
{
|
||||||
|
DeviceHandle handle;
|
||||||
|
|
||||||
|
while(actualDeviceIter_ != deviceListHandle_->end())
|
||||||
|
{
|
||||||
|
auto openResult = usbWrapper_.open(*actualDeviceIter_, handle);
|
||||||
|
++actualDeviceIter_;
|
||||||
|
|
||||||
|
if(openResult == 0)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConnectedAccessoriesEnumerator::reset()
|
||||||
|
{
|
||||||
|
queryChain_.reset();
|
||||||
|
deviceListHandle_.reset();
|
||||||
|
actualDeviceIter_ = DeviceList::iterator();
|
||||||
|
promise_.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,211 @@
|
||||||
|
/*
|
||||||
|
* This file is part of aasdk library project.
|
||||||
|
* Copyright (C) 2018 f1x.studio (Michal Szwaj)
|
||||||
|
*
|
||||||
|
* aasdk is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
|
||||||
|
* aasdk 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 General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with aasdk. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <boost/test/unit_test.hpp>
|
||||||
|
#include <f1x/aasdk/USB/UT/USBWrapper.mock.hpp>
|
||||||
|
#include <f1x/aasdk/USB/UT/AccessoryModeQueryChainFactory.mock.hpp>
|
||||||
|
#include <f1x/aasdk/USB/UT/AccessoryModeQueryChain.mock.hpp>
|
||||||
|
#include <f1x/aasdk/USB/UT/ConnectedAccessoriesEnumeratorPromiseHandler.mock.hpp>
|
||||||
|
#include <f1x/aasdk/USB/ConnectedAccessoriesEnumerator.hpp>
|
||||||
|
|
||||||
|
namespace f1x
|
||||||
|
{
|
||||||
|
namespace aasdk
|
||||||
|
{
|
||||||
|
namespace usb
|
||||||
|
{
|
||||||
|
namespace ut
|
||||||
|
{
|
||||||
|
|
||||||
|
using ::testing::_;
|
||||||
|
using ::testing::SetArgReferee;
|
||||||
|
using ::testing::Return;
|
||||||
|
using ::testing::SaveArg;
|
||||||
|
|
||||||
|
class ConnectedAccessoriesEnumeratorUnitTest
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
ConnectedAccessoriesEnumeratorUnitTest()
|
||||||
|
: queryChain_(&queryChainMock_, [](auto*) {})
|
||||||
|
, deviceListHandle_(&deviceList_, [](auto*) {})
|
||||||
|
, device_(reinterpret_cast<libusb_device*>(-1))
|
||||||
|
, deviceHandle_(reinterpret_cast<libusb_device_handle*>(&dummyDeviceHandle_), [](auto*) {})
|
||||||
|
, promise_(IConnectedAccessoriesEnumerator::Promise::defer(ioService_))
|
||||||
|
{
|
||||||
|
promise_->then(std::bind(&ConnectedAccessoriesEnumeratorPromiseHandlerMock::onResolve, &promiseHandlerMock_, std::placeholders::_1),
|
||||||
|
std::bind(&ConnectedAccessoriesEnumeratorPromiseHandlerMock::onReject, &promiseHandlerMock_, std::placeholders::_1));
|
||||||
|
}
|
||||||
|
|
||||||
|
boost::asio::io_service ioService_;
|
||||||
|
USBWrapperMock usbWrapperMock_;
|
||||||
|
AccessoryModeQueryChainFactoryMock queryChainFactoryMock_;
|
||||||
|
AccessoryModeQueryChainMock queryChainMock_;
|
||||||
|
IAccessoryModeQueryChain::Pointer queryChain_;
|
||||||
|
DeviceList deviceList_;
|
||||||
|
DeviceListHandle deviceListHandle_;
|
||||||
|
libusb_device* device_;
|
||||||
|
USBWrapperMock::DummyDeviceHandle dummyDeviceHandle_;
|
||||||
|
DeviceHandle deviceHandle_;
|
||||||
|
ConnectedAccessoriesEnumeratorPromiseHandlerMock promiseHandlerMock_;
|
||||||
|
IConnectedAccessoriesEnumerator::Promise::Pointer promise_;
|
||||||
|
};
|
||||||
|
|
||||||
|
BOOST_FIXTURE_TEST_CASE(ConnectedAccessoriesEnumerator_FirstDeviceIsAOAPCapables, ConnectedAccessoriesEnumeratorUnitTest)
|
||||||
|
{
|
||||||
|
deviceList_.push_back(reinterpret_cast<libusb_device*>(1));
|
||||||
|
EXPECT_CALL(queryChainFactoryMock_, create()).WillOnce(Return(queryChain_));
|
||||||
|
auto connectedAccessoriesEnumerator(std::make_shared<ConnectedAccessoriesEnumerator>(usbWrapperMock_, ioService_, queryChainFactoryMock_));
|
||||||
|
|
||||||
|
EXPECT_CALL(usbWrapperMock_, getDeviceList(_)).WillOnce(DoAll(SetArgReferee<0>(deviceListHandle_), Return(0)));
|
||||||
|
connectedAccessoriesEnumerator->enumerate(std::move(promise_));
|
||||||
|
|
||||||
|
EXPECT_CALL(usbWrapperMock_, open(*deviceList_.begin(), _)).WillOnce(DoAll(SetArgReferee<1>(deviceHandle_), Return(0)));
|
||||||
|
|
||||||
|
IAccessoryModeQueryChain::Promise::Pointer queryChainPromise;
|
||||||
|
EXPECT_CALL(queryChainMock_, start(deviceHandle_, _)).WillOnce(SaveArg<1>(&queryChainPromise));
|
||||||
|
ioService_.run();
|
||||||
|
ioService_.reset();
|
||||||
|
|
||||||
|
EXPECT_CALL(promiseHandlerMock_, onResolve(true));
|
||||||
|
EXPECT_CALL(promiseHandlerMock_, onReject(_)).Times(0);
|
||||||
|
queryChainPromise->resolve(deviceHandle_);
|
||||||
|
ioService_.run();
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_FIXTURE_TEST_CASE(ConnectedAccessoriesEnumerator_SecondDeviceIsAOAPCapable, ConnectedAccessoriesEnumeratorUnitTest)
|
||||||
|
{
|
||||||
|
deviceList_.push_back(reinterpret_cast<libusb_device*>(1));
|
||||||
|
deviceList_.push_back(reinterpret_cast<libusb_device*>(2));
|
||||||
|
auto connectedAccessoriesEnumerator(std::make_shared<ConnectedAccessoriesEnumerator>(usbWrapperMock_, ioService_, queryChainFactoryMock_));
|
||||||
|
|
||||||
|
EXPECT_CALL(queryChainFactoryMock_, create()).Times(deviceList_.size()).WillRepeatedly(Return(queryChain_));
|
||||||
|
EXPECT_CALL(usbWrapperMock_, getDeviceList(_)).WillOnce(DoAll(SetArgReferee<0>(deviceListHandle_), Return(0)));
|
||||||
|
connectedAccessoriesEnumerator->enumerate(std::move(promise_));
|
||||||
|
|
||||||
|
EXPECT_CALL(usbWrapperMock_, open(*deviceList_.begin(), _)).WillOnce(DoAll(SetArgReferee<1>(deviceHandle_), Return(0)));
|
||||||
|
IAccessoryModeQueryChain::Promise::Pointer queryChainPromise;
|
||||||
|
EXPECT_CALL(queryChainMock_, start(deviceHandle_, _)).WillRepeatedly(SaveArg<1>(&queryChainPromise));
|
||||||
|
ioService_.run();
|
||||||
|
ioService_.reset();
|
||||||
|
|
||||||
|
EXPECT_CALL(promiseHandlerMock_, onResolve(_)).Times(0);
|
||||||
|
EXPECT_CALL(promiseHandlerMock_, onReject(_)).Times(0);
|
||||||
|
|
||||||
|
// open second device
|
||||||
|
USBWrapperMock::DummyDeviceHandle dummyDeviceHandle2;
|
||||||
|
DeviceHandle deviceHandle2(reinterpret_cast<libusb_device_handle*>(&dummyDeviceHandle2), [](auto*) {});
|
||||||
|
EXPECT_CALL(usbWrapperMock_, open(*(++deviceList_.begin()), _)).WillOnce(DoAll(SetArgReferee<1>(deviceHandle2), Return(0)));
|
||||||
|
|
||||||
|
IAccessoryModeQueryChain::Promise::Pointer queryChainPromise2;
|
||||||
|
EXPECT_CALL(queryChainMock_, start(deviceHandle2, _)).WillRepeatedly(SaveArg<1>(&queryChainPromise2));
|
||||||
|
|
||||||
|
queryChainPromise->reject(error::Error(error::ErrorCode::USB_AOAP_PROTOCOL_VERSION));
|
||||||
|
ioService_.run();
|
||||||
|
ioService_.reset();
|
||||||
|
|
||||||
|
EXPECT_CALL(promiseHandlerMock_, onResolve(true));
|
||||||
|
EXPECT_CALL(promiseHandlerMock_, onReject(_)).Times(0);
|
||||||
|
queryChainPromise2->resolve(deviceHandle2);
|
||||||
|
ioService_.run();
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_FIXTURE_TEST_CASE(ConnectedAccessoriesEnumerator_NoAOAPCapableDevice, ConnectedAccessoriesEnumeratorUnitTest)
|
||||||
|
{
|
||||||
|
for(size_t i = 1; i < 1000; ++i)
|
||||||
|
{
|
||||||
|
deviceList_.push_back(reinterpret_cast<libusb_device*>(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
EXPECT_CALL(usbWrapperMock_, getDeviceList(_)).WillOnce(DoAll(SetArgReferee<0>(deviceListHandle_), Return(0)));
|
||||||
|
EXPECT_CALL(queryChainFactoryMock_, create()).Times(deviceList_.size()).WillRepeatedly(Return(queryChain_));
|
||||||
|
|
||||||
|
auto connectedAccessoriesEnumerator(std::make_shared<ConnectedAccessoriesEnumerator>(usbWrapperMock_, ioService_, queryChainFactoryMock_));
|
||||||
|
connectedAccessoriesEnumerator->enumerate(std::move(promise_));
|
||||||
|
|
||||||
|
EXPECT_CALL(promiseHandlerMock_, onResolve(false));
|
||||||
|
EXPECT_CALL(promiseHandlerMock_, onReject(_)).Times(0);
|
||||||
|
|
||||||
|
for(const auto& device : deviceList_)
|
||||||
|
{
|
||||||
|
USBWrapperMock::DummyDeviceHandle dummyDeviceHandle;
|
||||||
|
DeviceHandle deviceHandle(reinterpret_cast<libusb_device_handle*>(&dummyDeviceHandle), [](auto*) {});
|
||||||
|
EXPECT_CALL(usbWrapperMock_, open(device, _)).WillOnce(DoAll(SetArgReferee<1>(deviceHandle), Return(0)));
|
||||||
|
|
||||||
|
IAccessoryModeQueryChain::Promise::Pointer queryChainPromise;
|
||||||
|
EXPECT_CALL(queryChainMock_, start(deviceHandle, _)).WillRepeatedly(SaveArg<1>(&queryChainPromise));
|
||||||
|
|
||||||
|
ioService_.run();
|
||||||
|
ioService_.reset();
|
||||||
|
|
||||||
|
queryChainPromise->reject(error::Error(error::ErrorCode::USB_AOAP_PROTOCOL_VERSION));
|
||||||
|
}
|
||||||
|
|
||||||
|
ioService_.run();
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_FIXTURE_TEST_CASE(ConnectedAccessoriesEnumerator_GetDeviceListFailed, ConnectedAccessoriesEnumeratorUnitTest)
|
||||||
|
{
|
||||||
|
EXPECT_CALL(usbWrapperMock_, getDeviceList(_)).WillOnce(DoAll(SetArgReferee<0>(deviceListHandle_), Return(-1)));
|
||||||
|
EXPECT_CALL(promiseHandlerMock_, onResolve(_)).Times(0);
|
||||||
|
EXPECT_CALL(promiseHandlerMock_, onReject(error::Error(error::ErrorCode::USB_LIST_DEVICES)));
|
||||||
|
|
||||||
|
auto connectedAccessoriesEnumerator(std::make_shared<ConnectedAccessoriesEnumerator>(usbWrapperMock_, ioService_, queryChainFactoryMock_));
|
||||||
|
connectedAccessoriesEnumerator->enumerate(std::move(promise_));
|
||||||
|
|
||||||
|
ioService_.run();
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_FIXTURE_TEST_CASE(ConnectedAccessoriesEnumerator_EmptyDevicesList, ConnectedAccessoriesEnumeratorUnitTest)
|
||||||
|
{
|
||||||
|
EXPECT_CALL(usbWrapperMock_, getDeviceList(_)).WillOnce(DoAll(SetArgReferee<0>(deviceListHandle_), Return(0)));
|
||||||
|
EXPECT_CALL(promiseHandlerMock_, onResolve(false));
|
||||||
|
EXPECT_CALL(promiseHandlerMock_, onReject(_)).Times(0);
|
||||||
|
|
||||||
|
auto connectedAccessoriesEnumerator(std::make_shared<ConnectedAccessoriesEnumerator>(usbWrapperMock_, ioService_, queryChainFactoryMock_));
|
||||||
|
connectedAccessoriesEnumerator->enumerate(std::move(promise_));
|
||||||
|
|
||||||
|
ioService_.run();
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_FIXTURE_TEST_CASE(ConnectedAccessoriesEnumerator_OpenDeviceFailed, ConnectedAccessoriesEnumeratorUnitTest)
|
||||||
|
{
|
||||||
|
for(size_t i = 1; i < 1000; ++i)
|
||||||
|
{
|
||||||
|
deviceList_.push_back(reinterpret_cast<libusb_device*>(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
EXPECT_CALL(usbWrapperMock_, getDeviceList(_)).WillOnce(DoAll(SetArgReferee<0>(deviceListHandle_), Return(0)));
|
||||||
|
|
||||||
|
auto connectedAccessoriesEnumerator(std::make_shared<ConnectedAccessoriesEnumerator>(usbWrapperMock_, ioService_, queryChainFactoryMock_));
|
||||||
|
connectedAccessoriesEnumerator->enumerate(std::move(promise_));
|
||||||
|
|
||||||
|
EXPECT_CALL(promiseHandlerMock_, onResolve(false));
|
||||||
|
EXPECT_CALL(promiseHandlerMock_, onReject(_)).Times(0);
|
||||||
|
|
||||||
|
for(const auto& device : deviceList_)
|
||||||
|
{
|
||||||
|
EXPECT_CALL(usbWrapperMock_, open(device, _)).WillOnce(DoAll(SetArgReferee<1>(nullptr), Return(0xFFF)));
|
||||||
|
}
|
||||||
|
|
||||||
|
ioService_.run();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -159,7 +159,8 @@ void USBEndpoint::transferHandler(libusb_transfer *transfer)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
promise->reject(error::Error(error::ErrorCode::USB_TRANSFER, transfer->status));
|
auto error = transfer->status == LIBUSB_TRANSFER_CANCELLED ? error::Error(error::ErrorCode::OPERATION_ABORTED) : error::Error(error::ErrorCode::USB_TRANSFER, transfer->status);
|
||||||
|
promise->reject(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
self->usbWrapper_.freeTransfer(transfer);
|
self->usbWrapper_.freeTransfer(transfer);
|
||||||
|
|
|
@ -283,7 +283,7 @@ BOOST_FIXTURE_TEST_CASE(USBEndpoint_BulkTransferFailed, USBEndpointUnitTest)
|
||||||
transferCallback(&transfer);
|
transferCallback(&transfer);
|
||||||
|
|
||||||
EXPECT_CALL(usbWrapperMock_, freeTransfer(&transfer));
|
EXPECT_CALL(usbWrapperMock_, freeTransfer(&transfer));
|
||||||
EXPECT_CALL(promiseHandlerMock_, onReject(error::Error(error::ErrorCode::USB_TRANSFER, transfer.status))).Times(1);
|
EXPECT_CALL(promiseHandlerMock_, onReject(error::Error(error::ErrorCode::OPERATION_ABORTED))).Times(1);
|
||||||
EXPECT_CALL(promiseHandlerMock_, onResolve(_)).Times(0);
|
EXPECT_CALL(promiseHandlerMock_, onResolve(_)).Times(0);
|
||||||
ioService_.run();
|
ioService_.run();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue