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
|
||||
- AOAP (Android Open Accessory Protocol)
|
||||
- USB transport
|
||||
- TCP transport
|
||||
- USB hotplug
|
||||
- AndroidAuto(tm) protocol
|
||||
- SSL encryption
|
||||
|
|
|
@ -41,6 +41,7 @@ struct DataBuffer
|
|||
DataBuffer(void* _data, Data::size_type _size, Data::size_type offset = 0);
|
||||
explicit DataBuffer(Data& _data, Data::size_type offset = 0);
|
||||
bool operator==(const std::nullptr_t&) const;
|
||||
bool operator==(const DataBuffer& buffer) const;
|
||||
|
||||
Data::value_type* data;
|
||||
Data::size_type size;
|
||||
|
@ -54,6 +55,7 @@ struct DataConstBuffer
|
|||
DataConstBuffer(const void* _data, Data::size_type _size, 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 DataConstBuffer& buffer) const;
|
||||
|
||||
const Data::value_type* cdata;
|
||||
Data::size_type size;
|
||||
|
|
|
@ -41,6 +41,8 @@ public:
|
|||
|
||||
bool operator!() const;
|
||||
bool operator==(const Error& other) const;
|
||||
bool operator==(const ErrorCode& code) const;
|
||||
bool operator!=(const ErrorCode& code) const;
|
||||
|
||||
private:
|
||||
ErrorCode code_;
|
||||
|
|
|
@ -29,40 +29,40 @@ namespace error
|
|||
|
||||
enum class ErrorCode
|
||||
{
|
||||
NONE,
|
||||
USB_CLAIM_INTERFACE,
|
||||
USB_INVALID_CONFIG_DESCRIPTOR,
|
||||
USB_OBTAIN_INTERFACE_DESCRIPTOR,
|
||||
USB_EMPTY_INTERFACES,
|
||||
USB_INVALID_DEVICE_ENDPOINTS,
|
||||
USB_INVALID_TRANSFER_METHOD,
|
||||
USB_TRANSFER_ALLOCATION,
|
||||
USB_LIST_DEVICES,
|
||||
USB_OBTAIN_CONFIG_DESCRIPTOR,
|
||||
USB_TRANSFER,
|
||||
USB_SINK_COMMIT_OVERFLOW,
|
||||
USB_SINK_CONSUME_UNDERFLOW,
|
||||
USB_AOAP_PROTOCOL_VERSION,
|
||||
USB_EMPTY_DEVICE_LIST,
|
||||
USB_AOAP_DEVICE_NOT_FOUND,
|
||||
SSL_READ_CERTIFICATE,
|
||||
SSL_READ_PRIVATE_KEY,
|
||||
SSL_METHOD,
|
||||
SSL_CONTEXT_CREATION,
|
||||
SSL_USE_CERTIFICATE,
|
||||
SSL_USE_PRIVATE_KEY,
|
||||
SSL_HANDLER_CREATION,
|
||||
SSL_READ_BIO_CREATION,
|
||||
SSL_WRITE_BIO_CREATION,
|
||||
SSL_HANDSHAKE,
|
||||
SSL_WRITE,
|
||||
SSL_READ,
|
||||
SSL_BIO_READ,
|
||||
SSL_BIO_WRITE,
|
||||
MESSENGER_INTERTWINED_CHANNELS,
|
||||
OPERATION_ABORTED,
|
||||
OPERATION_IN_PROGRESS,
|
||||
PARSE_PAYLOAD
|
||||
NONE = 0,
|
||||
USB_CLAIM_INTERFACE = 1,
|
||||
USB_INVALID_CONFIG_DESCRIPTOR = 2,
|
||||
USB_OBTAIN_INTERFACE_DESCRIPTOR = 3,
|
||||
USB_EMPTY_INTERFACES = 4,
|
||||
USB_INVALID_DEVICE_ENDPOINTS = 5,
|
||||
USB_INVALID_TRANSFER_METHOD = 6,
|
||||
USB_TRANSFER_ALLOCATION = 7,
|
||||
USB_LIST_DEVICES = 8,
|
||||
USB_OBTAIN_CONFIG_DESCRIPTOR = 9,
|
||||
USB_TRANSFER = 10,
|
||||
DATA_SINK_COMMIT_OVERFLOW = 11,
|
||||
DATA_SINK_CONSUME_UNDERFLOW = 12,
|
||||
USB_AOAP_PROTOCOL_VERSION = 13,
|
||||
USB_AOAP_DEVICE_NOT_FOUND = 14,
|
||||
SSL_READ_CERTIFICATE = 15,
|
||||
SSL_READ_PRIVATE_KEY = 16,
|
||||
SSL_METHOD = 17,
|
||||
SSL_CONTEXT_CREATION = 18,
|
||||
SSL_USE_CERTIFICATE = 19,
|
||||
SSL_USE_PRIVATE_KEY = 20,
|
||||
SSL_HANDLER_CREATION = 21,
|
||||
SSL_READ_BIO_CREATION = 22,
|
||||
SSL_WRITE_BIO_CREATION = 23,
|
||||
SSL_HANDSHAKE = 24,
|
||||
SSL_WRITE = 25,
|
||||
SSL_READ = 26,
|
||||
SSL_BIO_READ = 27,
|
||||
SSL_BIO_WRITE = 28,
|
||||
MESSENGER_INTERTWINED_CHANNELS = 29,
|
||||
OPERATION_ABORTED = 30,
|
||||
OPERATION_IN_PROGRESS = 31,
|
||||
PARSE_PAYLOAD = 32,
|
||||
TCP_TRANSFER = 33
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -28,11 +28,9 @@ namespace aasdk
|
|||
namespace io
|
||||
{
|
||||
|
||||
class IOContextWrapper: boost::noncopyable
|
||||
class IOContextWrapper
|
||||
{
|
||||
public:
|
||||
typedef std::shared_ptr<IOContextWrapper> Pointer;
|
||||
|
||||
IOContextWrapper();
|
||||
explicit IOContextWrapper(boost::asio::io_service& ioService);
|
||||
explicit IOContextWrapper(boost::asio::io_service::strand& strand);
|
||||
|
|
|
@ -51,13 +51,13 @@ public:
|
|||
}
|
||||
|
||||
Promise(boost::asio::io_service& ioService)
|
||||
: ioContextWrapper_(std::make_shared<IOContextWrapper>(ioService))
|
||||
: ioContextWrapper_(ioService)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
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_);
|
||||
|
||||
resolveHandler_ = std::make_shared<ResolveHandler>(std::move(resolveHandler));
|
||||
rejectHandler_ = rejectHandler == nullptr ? nullptr : std::make_shared<RejectHandler>(std::move(rejectHandler));
|
||||
resolveHandler_ = std::move(resolveHandler);
|
||||
rejectHandler_ = std::move(rejectHandler);
|
||||
}
|
||||
|
||||
void resolve(ResolveArgumentType argument)
|
||||
|
@ -76,14 +76,13 @@ public:
|
|||
|
||||
if(resolveHandler_ != nullptr && this->isPending())
|
||||
{
|
||||
ioContextWrapper_->post([argument = std::move(argument), resolveHandler = std::move(resolveHandler_)]() mutable {
|
||||
(*resolveHandler)(std::move(argument));
|
||||
ioContextWrapper_.post([argument = std::move(argument), resolveHandler = std::move(resolveHandler_)]() mutable {
|
||||
resolveHandler(std::move(argument));
|
||||
});
|
||||
}
|
||||
|
||||
ioContextWrapper_->reset();
|
||||
ioContextWrapper_.reset();
|
||||
rejectHandler_.reset();
|
||||
rejectHandler_ = RejectHandler();
|
||||
}
|
||||
|
||||
void reject(ErrorArgumentType error)
|
||||
|
@ -92,25 +91,24 @@ public:
|
|||
|
||||
if(rejectHandler_ != nullptr && this->isPending())
|
||||
{
|
||||
ioContextWrapper_->post([error = std::move(error), rejectHandler = std::move(rejectHandler_)]() mutable {
|
||||
(*rejectHandler)(std::move(error));
|
||||
ioContextWrapper_.post([error = std::move(error), rejectHandler = std::move(rejectHandler_)]() mutable {
|
||||
rejectHandler(std::move(error));
|
||||
});
|
||||
}
|
||||
|
||||
ioContextWrapper_->reset();
|
||||
ioContextWrapper_.reset();
|
||||
resolveHandler_.reset();
|
||||
resolveHandler_ = ResolveHandler();
|
||||
}
|
||||
|
||||
private:
|
||||
bool isPending() const
|
||||
{
|
||||
return ioContextWrapper_ != nullptr && ioContextWrapper_->isActive();
|
||||
return ioContextWrapper_.isActive();
|
||||
}
|
||||
|
||||
std::shared_ptr<ResolveHandler> resolveHandler_;
|
||||
std::shared_ptr<RejectHandler> rejectHandler_;
|
||||
IOContextWrapper::Pointer ioContextWrapper_;
|
||||
ResolveHandler resolveHandler_;
|
||||
RejectHandler rejectHandler_;
|
||||
IOContextWrapper ioContextWrapper_;
|
||||
std::mutex mutex_;
|
||||
};
|
||||
|
||||
|
@ -134,13 +132,13 @@ public:
|
|||
}
|
||||
|
||||
Promise(boost::asio::io_service& ioService)
|
||||
: ioContextWrapper_(std::make_shared<IOContextWrapper>(ioService))
|
||||
: ioContextWrapper_(ioService)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
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_);
|
||||
|
||||
resolveHandler_ = std::make_shared<ResolveHandler>(std::move(resolveHandler));
|
||||
rejectHandler_ = rejectHandler == nullptr ? nullptr : std::make_shared<RejectHandler>(std::move(rejectHandler));
|
||||
resolveHandler_ = std::move(resolveHandler);
|
||||
rejectHandler_ = std::move(rejectHandler);
|
||||
}
|
||||
|
||||
void resolve()
|
||||
|
@ -159,14 +157,13 @@ public:
|
|||
|
||||
if(resolveHandler_ != nullptr && this->isPending())
|
||||
{
|
||||
ioContextWrapper_->post([resolveHandler = std::move(resolveHandler_)]() mutable {
|
||||
(*resolveHandler)();
|
||||
ioContextWrapper_.post([resolveHandler = std::move(resolveHandler_)]() mutable {
|
||||
resolveHandler();
|
||||
});
|
||||
}
|
||||
|
||||
ioContextWrapper_->reset();
|
||||
ioContextWrapper_.reset();
|
||||
rejectHandler_.reset();
|
||||
rejectHandler_ = RejectHandler();
|
||||
}
|
||||
|
||||
void reject(ErrorArgumentType error)
|
||||
|
@ -175,25 +172,24 @@ public:
|
|||
|
||||
if(rejectHandler_ != nullptr && this->isPending())
|
||||
{
|
||||
ioContextWrapper_->post([error = std::move(error), rejectHandler = std::move(rejectHandler_)]() mutable {
|
||||
(*rejectHandler)(std::move(error));
|
||||
ioContextWrapper_.post([error = std::move(error), rejectHandler = std::move(rejectHandler_)]() mutable {
|
||||
rejectHandler(std::move(error));
|
||||
});
|
||||
}
|
||||
|
||||
ioContextWrapper_->reset();
|
||||
ioContextWrapper_.reset();
|
||||
resolveHandler_.reset();
|
||||
resolveHandler_ = ResolveHandler();
|
||||
}
|
||||
|
||||
private:
|
||||
bool isPending() const
|
||||
{
|
||||
return ioContextWrapper_ != nullptr && ioContextWrapper_->isActive();
|
||||
return ioContextWrapper_.isActive();
|
||||
}
|
||||
|
||||
std::shared_ptr<ResolveHandler> resolveHandler_;
|
||||
std::shared_ptr<RejectHandler> rejectHandler_;
|
||||
IOContextWrapper::Pointer ioContextWrapper_;
|
||||
ResolveHandler resolveHandler_;
|
||||
RejectHandler rejectHandler_;
|
||||
IOContextWrapper ioContextWrapper_;
|
||||
std::mutex mutex_;
|
||||
};
|
||||
|
||||
|
@ -216,13 +212,13 @@ public:
|
|||
}
|
||||
|
||||
Promise(boost::asio::io_service& ioService)
|
||||
: ioContextWrapper_(std::make_shared<IOContextWrapper>(ioService))
|
||||
: ioContextWrapper_(ioService)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
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_);
|
||||
|
||||
resolveHandler_ = std::make_shared<ResolveHandler>(std::move(resolveHandler));
|
||||
rejectHandler_ = rejectHandler == nullptr ? nullptr : std::make_shared<RejectHandler>(std::move(rejectHandler));
|
||||
resolveHandler_ = std::move(resolveHandler);
|
||||
rejectHandler_ = std::move(rejectHandler);
|
||||
}
|
||||
|
||||
void resolve()
|
||||
|
@ -241,14 +237,13 @@ public:
|
|||
|
||||
if(resolveHandler_ != nullptr && this->isPending())
|
||||
{
|
||||
ioContextWrapper_->post([resolveHandler = std::move(resolveHandler_)]() mutable {
|
||||
(*resolveHandler)();
|
||||
ioContextWrapper_.post([resolveHandler = std::move(resolveHandler_)]() mutable {
|
||||
resolveHandler();
|
||||
});
|
||||
}
|
||||
|
||||
ioContextWrapper_->reset();
|
||||
ioContextWrapper_.reset();
|
||||
rejectHandler_.reset();
|
||||
rejectHandler_ = RejectHandler();
|
||||
}
|
||||
|
||||
void reject()
|
||||
|
@ -257,25 +252,24 @@ public:
|
|||
|
||||
if(rejectHandler_ != nullptr && this->isPending())
|
||||
{
|
||||
ioContextWrapper_->post([rejectHandler = std::move(rejectHandler_)]() mutable {
|
||||
(*rejectHandler)();
|
||||
ioContextWrapper_.post([rejectHandler = std::move(rejectHandler_)]() mutable {
|
||||
rejectHandler();
|
||||
});
|
||||
}
|
||||
|
||||
ioContextWrapper_->reset();
|
||||
ioContextWrapper_.reset();
|
||||
resolveHandler_.reset();
|
||||
resolveHandler_ = ResolveHandler();
|
||||
}
|
||||
|
||||
private:
|
||||
bool isPending() const
|
||||
{
|
||||
return ioContextWrapper_ != nullptr && ioContextWrapper_->isActive();
|
||||
return ioContextWrapper_.isActive();
|
||||
}
|
||||
|
||||
std::shared_ptr<ResolveHandler> resolveHandler_;
|
||||
std::shared_ptr<RejectHandler> rejectHandler_;
|
||||
IOContextWrapper::Pointer ioContextWrapper_;
|
||||
ResolveHandler resolveHandler_;
|
||||
RejectHandler rejectHandler_;
|
||||
IOContextWrapper ioContextWrapper_;
|
||||
std::mutex mutex_;
|
||||
};
|
||||
|
||||
|
@ -299,13 +293,13 @@ public:
|
|||
}
|
||||
|
||||
Promise(boost::asio::io_service& ioService)
|
||||
: ioContextWrapper_(std::make_shared<IOContextWrapper>(ioService))
|
||||
: ioContextWrapper_(ioService)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
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_);
|
||||
|
||||
resolveHandler_ = std::make_shared<ResolveHandler>(std::move(resolveHandler));
|
||||
rejectHandler_ = rejectHandler == nullptr ? nullptr : std::make_shared<RejectHandler>(std::move(rejectHandler));
|
||||
resolveHandler_ = std::move(resolveHandler);
|
||||
rejectHandler_ = std::move(rejectHandler);
|
||||
}
|
||||
|
||||
void resolve(ResolveArgumentType argument)
|
||||
|
@ -324,14 +318,13 @@ public:
|
|||
|
||||
if(resolveHandler_ != nullptr && this->isPending())
|
||||
{
|
||||
ioContextWrapper_->post([argument = std::move(argument), resolveHandler = std::move(resolveHandler_)]() mutable {
|
||||
(*resolveHandler)(std::move(argument));
|
||||
ioContextWrapper_.post([argument = std::move(argument), resolveHandler = std::move(resolveHandler_)]() mutable {
|
||||
resolveHandler(std::move(argument));
|
||||
});
|
||||
}
|
||||
|
||||
ioContextWrapper_->reset();
|
||||
ioContextWrapper_.reset();
|
||||
rejectHandler_.reset();
|
||||
rejectHandler_ = RejectHandler();
|
||||
}
|
||||
|
||||
void reject()
|
||||
|
@ -340,25 +333,24 @@ public:
|
|||
|
||||
if(rejectHandler_ != nullptr && this->isPending())
|
||||
{
|
||||
ioContextWrapper_->post([rejectHandler = std::move(rejectHandler_)]() mutable {
|
||||
(*rejectHandler)();
|
||||
ioContextWrapper_.post([rejectHandler = std::move(rejectHandler_)]() mutable {
|
||||
rejectHandler();
|
||||
});
|
||||
}
|
||||
|
||||
ioContextWrapper_->reset();
|
||||
ioContextWrapper_.reset();
|
||||
resolveHandler_.reset();
|
||||
resolveHandler_ = ResolveHandler();
|
||||
}
|
||||
|
||||
private:
|
||||
bool isPending() const
|
||||
{
|
||||
return ioContextWrapper_ != nullptr && ioContextWrapper_->isActive();
|
||||
return ioContextWrapper_.isActive();
|
||||
}
|
||||
|
||||
std::shared_ptr<ResolveHandler> resolveHandler_;
|
||||
std::shared_ptr<RejectHandler> rejectHandler_;
|
||||
IOContextWrapper::Pointer ioContextWrapper_;
|
||||
ResolveHandler resolveHandler_;
|
||||
RejectHandler rejectHandler_;
|
||||
IOContextWrapper ioContextWrapper_;
|
||||
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
|
||||
{
|
||||
|
||||
class USBDataSink
|
||||
class DataSink
|
||||
{
|
||||
public:
|
||||
USBDataSink();
|
||||
DataSink();
|
||||
|
||||
common::DataBuffer fill();
|
||||
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
|
||||
|
||||
#include <list>
|
||||
#include <queue>
|
||||
#include <boost/asio.hpp>
|
||||
#include <f1x/aasdk/Transport/ITransport.hpp>
|
||||
#include <f1x/aasdk/Transport/USBDataSink.hpp>
|
||||
#include <f1x/aasdk/Transport/Transport.hpp>
|
||||
#include <f1x/aasdk/USB/IAOAPDevice.hpp>
|
||||
|
||||
namespace f1x
|
||||
|
@ -32,35 +29,20 @@ namespace aasdk
|
|||
namespace transport
|
||||
{
|
||||
|
||||
class USBTransport: public ITransport, public std::enable_shared_from_this<USBTransport>, boost::noncopyable
|
||||
class USBTransport: public Transport
|
||||
{
|
||||
public:
|
||||
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;
|
||||
|
||||
private:
|
||||
typedef std::list<std::pair<size_t, ReceivePromise::Pointer>> InTransferQueue;
|
||||
typedef std::list<std::pair<common::Data, SendPromise::Pointer>> OutTransferQueue;
|
||||
|
||||
using std::enable_shared_from_this<USBTransport>::shared_from_this;
|
||||
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);
|
||||
void enqueueReceive(common::DataBuffer buffer) override;
|
||||
void enqueueSend(SendQueue::iterator queueElement) override;
|
||||
void doSend(SendQueue::iterator queueElement, common::Data::size_type offset);
|
||||
void sendHandler(SendQueue::iterator queueElement, common::Data::size_type offset, size_t bytesTransferred);
|
||||
|
||||
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 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
|
||||
|
||||
#include <boost/asio.hpp>
|
||||
#include <libusb.h>
|
||||
#include <list>
|
||||
#include <f1x/aasdk/USB/IUSBHub.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;
|
||||
}
|
||||
|
||||
bool DataBuffer::operator==(const DataBuffer& buffer) const
|
||||
{
|
||||
return data == buffer.data && size == buffer.size;
|
||||
}
|
||||
|
||||
DataConstBuffer::DataConstBuffer()
|
||||
: cdata(nullptr)
|
||||
, size(0)
|
||||
|
@ -109,6 +114,11 @@ bool DataConstBuffer::operator==(const std::nullptr_t&) const
|
|||
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 data;
|
||||
|
|
|
@ -57,7 +57,7 @@ const char* Error::what() const noexcept
|
|||
|
||||
bool Error::operator!() const
|
||||
{
|
||||
return code_ != ErrorCode::NONE || nativeCode_ != 0;
|
||||
return code_ == ErrorCode::NONE;
|
||||
}
|
||||
|
||||
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_;
|
||||
}
|
||||
|
||||
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()
|
||||
{
|
||||
this->rejectReceivePromiseQueue(error::Error(error::ErrorCode::OPERATION_ABORTED));
|
||||
this->rejectSendPromiseQueue(error::Error(error::ErrorCode::OPERATION_ABORTED));
|
||||
channelReceiveMessageQueue_.clear();
|
||||
receiveStrand_.dispatch([this, self = this->shared_from_this()]() {
|
||||
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 <f1x/aasdk/Transport/USBDataSink.hpp>
|
||||
#include <f1x/aasdk/Transport/DataSink.hpp>
|
||||
#include <f1x/aasdk/Error/Error.hpp>
|
||||
|
||||
namespace f1x
|
||||
|
@ -27,44 +27,45 @@ namespace aasdk
|
|||
namespace transport
|
||||
{
|
||||
|
||||
USBDataSink::USBDataSink()
|
||||
DataSink::DataSink()
|
||||
: data_(common::cStaticDataSize)
|
||||
{
|
||||
}
|
||||
|
||||
common::DataBuffer USBDataSink::fill()
|
||||
common::DataBuffer DataSink::fill()
|
||||
{
|
||||
const auto offset = data_.size();
|
||||
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)
|
||||
{
|
||||
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();
|
||||
}
|
||||
|
||||
common::Data USBDataSink::consume(common::Data::size_type size)
|
||||
common::Data DataSink::consume(common::Data::size_type 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::copy(data, common::DataConstBuffer(&data_[0], size));
|
||||
data_.erase(data_.begin(), data_.begin() + size);
|
||||
common::Data data(size, 0);
|
||||
std::copy(data_.begin(), data_.begin() + size, data.begin());
|
||||
data_.erase_begin(size);
|
||||
|
||||
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)
|
||||
: aoapDevice_(std::move(aoapDevice))
|
||||
, receiveStrand_(ioService)
|
||||
, sendStrand_(ioService)
|
||||
: Transport(ioService)
|
||||
, aoapDevice_(std::move(aoapDevice))
|
||||
{}
|
||||
|
||||
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 {
|
||||
receiveQueue_.emplace_back(std::make_pair(size, std::move(promise)));
|
||||
auto usbEndpointPromise = usb::IUSBEndpoint::Promise::defer(receiveStrand_);
|
||||
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)
|
||||
{
|
||||
try
|
||||
{
|
||||
this->distributeReceivedData();
|
||||
}
|
||||
catch(const error::Error& e)
|
||||
{
|
||||
this->rejectReceivePromises(e);
|
||||
}
|
||||
}
|
||||
});
|
||||
aoapDevice_->getInEndpoint().bulkTransfer(buffer, cReceiveTimeoutMs, std::move(usbEndpointPromise));
|
||||
}
|
||||
|
||||
void USBTransport::receiveHandler(size_t bytesTransferred)
|
||||
void USBTransport::enqueueSend(SendQueue::iterator queueElement)
|
||||
{
|
||||
try
|
||||
{
|
||||
usbReceivedDataSink_.commit(bytesTransferred);
|
||||
this->distributeReceivedData();
|
||||
}
|
||||
catch(const error::Error& e)
|
||||
{
|
||||
this->rejectReceivePromises(e);
|
||||
}
|
||||
this->doSend(queueElement, 0);
|
||||
}
|
||||
|
||||
void USBTransport::distributeReceivedData()
|
||||
{
|
||||
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)
|
||||
void USBTransport::doSend(SendQueue::iterator queueElement, common::Data::size_type offset)
|
||||
{
|
||||
auto usbEndpointPromise = usb::IUSBEndpoint::Promise::defer(sendStrand_);
|
||||
usbEndpointPromise->then([this, self = this->shared_from_this(), queueElementIter, offset](size_t bytesTransferred) mutable {
|
||||
this->sendHandler(queueElementIter, offset, bytesTransferred);
|
||||
usbEndpointPromise->then([this, self = this->shared_from_this(), queueElement, offset](size_t bytesTransferred) mutable {
|
||||
this->sendHandler(queueElement, offset, bytesTransferred);
|
||||
},
|
||||
[this, self = this->shared_from_this(), queueElementIter](const error::Error& e) mutable {
|
||||
queueElementIter->second->reject(e);
|
||||
sendQueue_.erase(queueElementIter);
|
||||
[this, self = this->shared_from_this(), queueElement](const error::Error& e) mutable {
|
||||
queueElement->second->reject(e);
|
||||
sendQueue_.erase(queueElement);
|
||||
|
||||
if(!sendQueue_.empty())
|
||||
{
|
||||
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
|
||||
{
|
||||
queueElementIter->second->resolve();
|
||||
sendQueue_.erase(queueElementIter);
|
||||
queueElement->second->resolve();
|
||||
sendQueue_.erase(queueElement);
|
||||
|
||||
if(!sendQueue_.empty())
|
||||
{
|
||||
|
|
|
@ -279,8 +279,7 @@ BOOST_FIXTURE_TEST_CASE(USBTransport_OnlyOneSendAtATime, USBTransportUnitTest)
|
|||
BOOST_FIXTURE_TEST_CASE(USBTransport_SendError, USBTransportUnitTest)
|
||||
{
|
||||
usb::IUSBEndpoint::Promise::Pointer usbEndpointPromise;
|
||||
common::DataBuffer buffer;
|
||||
EXPECT_CALL(outEndpointMock_, bulkTransfer(_, _, _)).Times(2).WillRepeatedly(DoAll(SaveArg<0>(&buffer), SaveArg<2>(&usbEndpointPromise)));
|
||||
EXPECT_CALL(outEndpointMock_, bulkTransfer(_, _, _)).Times(2).WillRepeatedly(SaveArg<2>(&usbEndpointPromise));
|
||||
|
||||
USBTransport::Pointer transport(std::make_shared<USBTransport>(ioService_, aoapDevice_));
|
||||
const common::Data expectedData1(1000, 0x5E);
|
||||
|
@ -288,13 +287,12 @@ BOOST_FIXTURE_TEST_CASE(USBTransport_SendError, USBTransportUnitTest)
|
|||
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));
|
||||
|
||||
const common::Data expectedData2(3000, 0x5F);
|
||||
transport->send(expectedData2, std::move(secondSendPromise));
|
||||
ioService_.run();
|
||||
ioService_.reset();
|
||||
|
|
|
@ -66,11 +66,13 @@ void AccessoryModeQueryChain::start(DeviceHandle handle, Promise::Pointer promis
|
|||
|
||||
void AccessoryModeQueryChain::cancel()
|
||||
{
|
||||
if(activeQuery_ != nullptr)
|
||||
{
|
||||
activeQuery_->cancel();
|
||||
activeQuery_.reset();
|
||||
}
|
||||
strand_.dispatch([this, self = this->shared_from_this()]() {
|
||||
if(activeQuery_ != nullptr)
|
||||
{
|
||||
activeQuery_->cancel();
|
||||
activeQuery_.reset();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
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);
|
||||
|
|
|
@ -283,7 +283,7 @@ BOOST_FIXTURE_TEST_CASE(USBEndpoint_BulkTransferFailed, USBEndpointUnitTest)
|
|||
transferCallback(&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);
|
||||
ioService_.run();
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue