diff options
author | Szczepan Zalega <szczepan@nitrokey.com> | 2017-03-11 17:18:59 +0100 |
---|---|---|
committer | Szczepan Zalega <szczepan@nitrokey.com> | 2017-03-11 17:18:59 +0100 |
commit | 22d05ce647281056d71fbd3c31df3bcd6396188d (patch) | |
tree | 90208930f54c47987bfd5ffcf0a0acaaad2510da /device.cc | |
parent | ed5044da43172d86a1aa475473561a4818b7c69c (diff) | |
parent | ac6b9c18ef55f4cd36e85069cf0cf82c14e04404 (diff) | |
download | libnitrokey-22d05ce647281056d71fbd3c31df3bcd6396188d.tar.gz libnitrokey-22d05ce647281056d71fbd3c31df3bcd6396188d.tar.bz2 |
Merge branch 'libnitrokey_3'
Diffstat (limited to 'device.cc')
-rw-r--r-- | device.cc | 201 |
1 files changed, 153 insertions, 48 deletions
@@ -2,81 +2,131 @@ #include <thread> #include <cstddef> #include <stdexcept> -#include <hidapi/hidapi.h> +#include "hidapi/hidapi.h" #include "include/misc.h" #include "include/device.h" #include "include/log.h" +#include <mutex> +#include "DeviceCommunicationExceptions.h" + +std::mutex mex_dev_com; using namespace nitrokey::device; using namespace nitrokey::log; +using namespace std::chrono; + +std::atomic_int Device::instances_count{0}; -Device::Device() - : m_vid(0), - m_pid(0), +Device::Device(const uint16_t vid, const uint16_t pid, const DeviceModel model, + const milliseconds send_receive_delay, const int retry_receiving_count, + const milliseconds retry_timeout) + : m_vid(vid), + m_pid(pid), m_retry_sending_count(3), - m_retry_receiving_count(40), - m_retry_timeout(100), - mp_devhandle(NULL), - last_command_status(0){} + m_retry_receiving_count(retry_receiving_count), + m_retry_timeout(retry_timeout), + mp_devhandle(nullptr), + last_command_status(0), + m_model(model), + m_send_receive_delay(send_receive_delay) +{ + instances_count++; +} bool Device::disconnect() { - Log::instance()(__PRETTY_FUNCTION__, Loglevel::DEBUG_L2); + //called in object's destructor + LOG(__FUNCTION__, Loglevel::DEBUG_L2); + std::lock_guard<std::mutex> lock(mex_dev_com); + return _disconnect(); +} + +bool Device::_disconnect() { + LOG(std::string(__FUNCTION__) + std::string(m_model == DeviceModel::PRO ? "PRO" : "STORAGE"), Loglevel::DEBUG_L2); + LOG(std::string(__FUNCTION__) + std::string(" *IN* "), Loglevel::DEBUG_L2); + + LOG(std::string("Disconnection success: ") + std::to_string(mp_devhandle == nullptr), Loglevel::DEBUG_L2); + if(mp_devhandle == nullptr) return false; - if(mp_devhandle== nullptr) return false; hid_close(mp_devhandle); - mp_devhandle = NULL; - hid_exit(); + mp_devhandle = nullptr; + if (instances_count == 1){ + LOG(std::string("Calling hid_exit"), Loglevel::DEBUG_L2); + hid_exit(); + } return true; } + bool Device::connect() { - Log::instance()(__PRETTY_FUNCTION__, Loglevel::DEBUG_L2); + LOG(__FUNCTION__, Loglevel::DEBUG_L2); + std::lock_guard<std::mutex> lock(mex_dev_com); + return _connect(); +} + +bool Device::_connect() { + LOG(std::string(__FUNCTION__) + std::string(" *IN* "), Loglevel::DEBUG_L2); -// hid_init(); - mp_devhandle = hid_open(m_vid, m_pid, NULL); - // hid_init(); - return mp_devhandle != NULL; +// hid_init(); // done automatically on hid_open + mp_devhandle = hid_open(m_vid, m_pid, nullptr); + const auto success = mp_devhandle != nullptr; + LOG(std::string("Connection success: ") + std::to_string(success), Loglevel::DEBUG_L2); + return success; } int Device::send(const void *packet) { - Log::instance()(__PRETTY_FUNCTION__, Loglevel::DEBUG_L2); + LOG(__FUNCTION__, Loglevel::DEBUG_L2); + std::lock_guard<std::mutex> lock(mex_dev_com); + LOG(std::string(__FUNCTION__) + std::string(" *IN* "), Loglevel::DEBUG_L2); - if (mp_devhandle == NULL) - throw std::runtime_error("Attempted HID send on an invalid descriptor."); + int send_feature_report = -1; - return (hid_send_feature_report( - mp_devhandle, (const unsigned char *)(packet), HID_REPORT_SIZE)); + for (int i = 0; i < 3 && send_feature_report < 0; ++i) { + if (mp_devhandle == nullptr) { + LOG(std::string("Connection fail") , Loglevel::DEBUG_L2); + throw DeviceNotConnected("Attempted HID send on an invalid descriptor."); + } + send_feature_report = hid_send_feature_report( + mp_devhandle, (const unsigned char *)(packet), HID_REPORT_SIZE); + if (send_feature_report < 0) _reconnect(); + //add thread sleep? + LOG(std::string("Sending attempt: ")+std::to_string(i) + " / 3" , Loglevel::DEBUG_L2); + } + return send_feature_report; } int Device::recv(void *packet) { + LOG(__FUNCTION__, Loglevel::DEBUG_L2); + std::lock_guard<std::mutex> lock(mex_dev_com); + LOG(std::string(__FUNCTION__) + std::string(" *IN* "), Loglevel::DEBUG_L2); int status; int retry_count = 0; - Log::instance()(__PRETTY_FUNCTION__, Loglevel::DEBUG_L2); - - if (mp_devhandle == NULL) - throw std::runtime_error("Attempted HID receive on an invalid descriptor."); - - // FIXME extract error handling and repeating to parent function in - // device_proto:192 for (;;) { + if (mp_devhandle == nullptr){ + LOG(std::string("Connection fail") , Loglevel::DEBUG_L2); + throw DeviceNotConnected("Attempted HID receive on an invalid descriptor."); + } + status = (hid_get_feature_report(mp_devhandle, (unsigned char *)(packet), HID_REPORT_SIZE)); - // FIXME handle getting libhid error message somewhere else auto pwherr = hid_error(mp_devhandle); - std::wstring wherr = (pwherr != NULL) ? pwherr : L"No error message"; + std::wstring wherr = (pwherr != nullptr) ? pwherr : L"No error message"; std::string herr(wherr.begin(), wherr.end()); - Log::instance()(std::string("libhid error message: ") + herr, + LOG(std::string("libhid error message: ") + herr, Loglevel::DEBUG_L2); if (status > 0) break; // success if (retry_count++ >= m_retry_receiving_count) { - Log::instance()( - "Maximum retry count reached" + std::to_string(retry_count), + LOG( + "Maximum retry count reached: " + std::to_string(retry_count), Loglevel::WARNING); + LOG( + std::string("Counter stats: ") + m_counters.get_as_string(), + Loglevel::DEBUG); break; } - Log::instance()("Retrying... " + std::to_string(retry_count), + _reconnect(); + LOG("Retrying... " + std::to_string(retry_count), Loglevel::DEBUG); std::this_thread::sleep_for(m_retry_timeout); } @@ -84,19 +134,74 @@ int Device::recv(void *packet) { return status; } -Stick10::Stick10() { - m_vid = 0x20a0; - m_pid = 0x4108; - m_model = DeviceModel::PRO; - m_send_receive_delay = 100ms; - m_retry_receiving_count = 100; +bool Device::could_be_enumerated() { + LOG(__FUNCTION__, Loglevel::DEBUG_L2); + std::lock_guard<std::mutex> lock(mex_dev_com); + if (mp_devhandle==nullptr){ + return false; + } + auto pInfo = hid_enumerate(m_vid, m_pid); + if (pInfo != nullptr){ + hid_free_enumeration(pInfo); + return true; + } + return false; + +// alternative: +// unsigned char buf[1]; +// return hid_read_timeout(mp_devhandle, buf, sizeof(buf), 20) != -1; +} + +void Device::show_stats() { + auto s = m_counters.get_as_string(); + LOG(s, Loglevel::DEBUG_L2); +} + +void Device::_reconnect() { + LOG(__FUNCTION__, Loglevel::DEBUG_L2); + ++m_counters.low_level_reconnect; + _disconnect(); + _connect(); +} + +Device::~Device() { + show_stats(); + disconnect(); + instances_count--; } -Stick20::Stick20() { - m_vid = 0x20a0; - m_pid = 0x4109; - m_retry_timeout = 200ms; - m_model = DeviceModel::STORAGE; - m_send_receive_delay = 200ms; - m_retry_receiving_count = 40; +Stick10::Stick10(): + Device(0x20a0, 0x4108, DeviceModel::PRO, 100ms, 5, 100ms) + {} + + +Stick20::Stick20(): + Device(0x20a0, 0x4109, DeviceModel::STORAGE, 20ms, 20, 20ms) + {} + +#include <sstream> +#define p(x) ss << #x << " " << x << ", "; +std::string Device::ErrorCounters::get_as_string() { + std::stringstream ss; + p(total_comm_runs); + p(communication_successful); + ss << "("; + p(command_successful_recv); + p(command_result_not_equal_0_recv); + ss << "), "; + p(sends_executed); + p(recv_executed); + p(successful_storage_commands); + p(total_retries); + ss << "("; + p(busy); + p(busy_progressbar); + p(CRC_other_than_awaited); + p(wrong_CRC); + ss << "), "; + p(low_level_reconnect); + p(sending_error); + p(receiving_error); + return ss.str(); } +#undef p
\ No newline at end of file |