From bb6e3bbc0f0a6c4ac126f56ba75b39d0dfac01a6 Mon Sep 17 00:00:00 2001
From: cslashm <cslashm@gmail.com>
Date: Wed, 1 Aug 2018 09:24:53 +0200
Subject: Replace USB-CCID (smartcard) by USB-HID

Remove PCSC dependencies which is a bit hard (not user friendly) to install on linux and Mac

Split Ledger logic and device IO
---
 src/device/CMakeLists.txt    |  19 ++-
 src/device/device.cpp        |   4 +-
 src/device/device.hpp        |   3 +-
 src/device/device_io.hpp     |  56 +++++++++
 src/device/device_io_hid.cpp | 288 +++++++++++++++++++++++++++++++++++++++++++
 src/device/device_io_hid.hpp | 112 +++++++++++++++++
 src/device/device_ledger.cpp | 200 +++++++++---------------------
 src/device/device_ledger.hpp |  38 +++---
 src/device/log.cpp           |  41 +++---
 src/device/log.hpp           |   7 +-
 10 files changed, 578 insertions(+), 190 deletions(-)
 create mode 100644 src/device/device_io.hpp
 create mode 100644 src/device/device_io_hid.cpp
 create mode 100644 src/device/device_io_hid.hpp

(limited to 'src')

diff --git a/src/device/CMakeLists.txt b/src/device/CMakeLists.txt
index cc2d20a54..8f446f42a 100644
--- a/src/device/CMakeLists.txt
+++ b/src/device/CMakeLists.txt
@@ -32,18 +32,27 @@ set(device_sources
   log.cpp
   )
 
-if(PCSC_FOUND)
-  set(device_sources ${device_sources} device_ledger.cpp)
+if(HIDAPI_FOUND)
+  set(device_sources 
+    ${device_sources} 
+    device_ledger.cpp
+    device_io_hid.cpp
+    )
 endif()
 
 set(device_headers
   device.hpp
+  device_io.hpp
   device_default.hpp
   log.hpp
  )
 
-if(PCSC_FOUND)
-  set(device_headers ${device_headers} device_ledger.hpp)
+if(HIDAPI_FOUND)
+  set(device_headers 
+    ${device_headers} 
+    device_ledger.hpp
+    device_io_hid.hpp
+    )
 endif()
 
 set(device_private_headers)
@@ -65,7 +74,7 @@ monero_add_library(device
 
 target_link_libraries(device
   PUBLIC
-    ${PCSC_LIBRARIES}
+    ${HIDAPI_LIBRARIES}
     cncrypto
     ringct_basic
     ${OPENSSL_CRYPTO_LIBRARIES}
diff --git a/src/device/device.cpp b/src/device/device.cpp
index 8a8b40061..50041baef 100644
--- a/src/device/device.cpp
+++ b/src/device/device.cpp
@@ -29,7 +29,7 @@
 
 #include "device.hpp"
 #include "device_default.hpp"
-#ifdef HAVE_PCSC
+#ifdef WITH_DEVICE_LEDGER
 #include "device_ledger.hpp"
 #endif
 #include "misc_log_ex.h"
@@ -45,7 +45,7 @@ namespace hw {
 
     device_registry::device_registry(){
         hw::core::register_all(registry);
-        #ifdef HAVE_PCSC
+        #ifdef WITH_DEVICE_LEDGER
         hw::ledger::register_all(registry);
         #endif
     }
diff --git a/src/device/device.hpp b/src/device/device.hpp
index 87f1430f4..cb9117650 100644
--- a/src/device/device.hpp
+++ b/src/device/device.hpp
@@ -48,11 +48,12 @@
 #include "crypto/chacha.h"
 #include "ringct/rctTypes.h"
 
+
 #ifndef USE_DEVICE_LEDGER
 #define USE_DEVICE_LEDGER 1
 #endif
 
-#if !defined(HAVE_PCSC) 
+#if !defined(HAVE_HIDAPI) 
 #undef  USE_DEVICE_LEDGER
 #define USE_DEVICE_LEDGER 0
 #endif
diff --git a/src/device/device_io.hpp b/src/device/device_io.hpp
new file mode 100644
index 000000000..96163a211
--- /dev/null
+++ b/src/device/device_io.hpp
@@ -0,0 +1,56 @@
+// Copyright (c) 2017-2018, The Monero Project
+// 
+// All rights reserved.
+// 
+// Redistribution and use in source and binary forms, with or without modification, are
+// permitted provided that the following conditions are met:
+// 
+// 1. Redistributions of source code must retain the above copyright notice, this list of
+//    conditions and the following disclaimer.
+// 
+// 2. Redistributions in binary form must reproduce the above copyright notice, this list
+//    of conditions and the following disclaimer in the documentation and/or other
+//    materials provided with the distribution.
+// 
+// 3. Neither the name of the copyright holder nor the names of its contributors may be
+//    used to endorse or promote products derived from this software without specific
+//    prior written permission.
+// 
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
+// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+
+
+
+
+#pragma once
+
+
+namespace hw {
+  namespace io {
+
+    class device_io {
+
+    public:
+
+      device_io()   {};
+      ~device_io() {};
+
+      virtual void init()  = 0;
+      virtual void release() = 0;
+
+      virtual void connect(void *parms) = 0;
+      virtual void disconnect() = 0;
+      virtual bool connected() const = 0;
+
+      virtual int  exchange(unsigned char *command, unsigned int cmd_len, unsigned char *response, unsigned int max_resp_len) = 0;
+    };
+  };
+};
diff --git a/src/device/device_io_hid.cpp b/src/device/device_io_hid.cpp
new file mode 100644
index 000000000..562aca8b8
--- /dev/null
+++ b/src/device/device_io_hid.cpp
@@ -0,0 +1,288 @@
+//    used to endorse or promote products derived from this software without specific
+//    prior written permission.
+// 
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
+// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+#if defined(HAVE_HIDAPI) 
+
+#include "log.hpp"
+#include "device_io_hid.hpp"
+
+namespace hw {
+  namespace io {
+ 
+    #undef MONERO_DEFAULT_LOG_CATEGORY
+    #define MONERO_DEFAULT_LOG_CATEGORY "device.io"
+ 
+    #define ASSERT_X(exp,msg)    CHECK_AND_ASSERT_THROW_MES(exp, msg); 
+
+    #define MAX_BLOCK  64
+    
+    static std::string safe_hid_error(hid_device *hwdev) {
+      if (hwdev) {
+        return  std::string((char*)hid_error(hwdev));
+      }
+      return std::string("NULL device");
+    }
+
+    static std::string safe_hid_path(const hid_device_info *hwdev_info) {
+      if (hwdev_info && hwdev_info->path) {
+        return  std::string(hwdev_info->path);
+      }
+      return std::string("NULL path");
+    }
+
+    device_io_hid::device_io_hid(unsigned short c, unsigned char t, unsigned int ps, unsigned int to) : 
+      channel(c), 
+      tag(t), 
+      packet_size(ps), 
+      timeout(to),
+      usb_vid(0),
+      usb_pid(0),
+      usb_device(NULL) {
+    }
+
+    device_io_hid::device_io_hid() : device_io_hid(DEFAULT_CHANNEL, DEFAULT_TAG, DEFAULT_PACKET_SIZE, DEFAULT_TIMEOUT) {
+    }
+
+    void device_io_hid::io_hid_log(int read, unsigned char* buffer, int block_len) {
+      if (hid_verbose) {
+        char  strbuffer[1024];
+        hw::buffer_to_str(strbuffer, sizeof(strbuffer), (char*)buffer, block_len);
+        MDEBUG( "HID " << (read?"<":">") <<" : "<<strbuffer);
+      }
+    }
+ 
+    void device_io_hid::init() {
+      int r;
+      r = hid_init();
+      ASSERT_X(r>=0, "Unable to init hidapi library. Error "+std::to_string(r)+": "+safe_hid_error(this->usb_device));
+    }
+
+    void device_io_hid::connect(void *params) {
+      hid_conn_params *p = (struct hid_conn_params*)params;
+      this->connect(p->vid, p->pid, p->interface_number, p->usage_page, p->interface_OR_page);
+    }
+
+    void device_io_hid::connect(unsigned int vid, unsigned  int pid, unsigned int interface_number, unsigned int usage_page, bool interface_OR_page ) {
+      hid_device_info *hwdev_info, *hwdev_info_list;
+      hid_device      *hwdev;
+
+      this->disconnect();
+
+      hwdev_info_list = hid_enumerate(vid, pid);
+      ASSERT_X(hwdev_info_list, "Unable to enumerate device "+std::to_string(vid)+":"+std::to_string(vid)+  ": "+ safe_hid_error(this->usb_device));
+      hwdev = NULL;
+      hwdev_info = hwdev_info_list;
+      while (hwdev_info) {
+        if ((interface_OR_page && ((usage_page == 0xffa0) || (interface_number == 0))) ||
+                                  ((usage_page == 0xffa0) && (interface_number == 0)) ) {
+          MDEBUG("HID Device found: " << safe_hid_path(hwdev_info));
+          hwdev = hid_open_path(hwdev_info->path);
+          break;
+        } else {
+          MDEBUG("HID Device discard: " << safe_hid_path(hwdev_info) << "("+std::to_string(hwdev_info->usage_page) << "," << std::to_string(hwdev_info->interface_number) << ")");
+        }
+        hwdev_info = hwdev_info->next;
+      }
+      hid_free_enumeration(hwdev_info_list);
+      ASSERT_X(hwdev, "Unable to open device "+std::to_string(pid)+":"+std::to_string(vid));
+      this->usb_vid = vid;
+      this->usb_pid = pid;
+      this->usb_device = hwdev;
+    }
+
+
+    bool device_io_hid::connected() const {
+      return this->usb_device != NULL;
+    }
+
+    int device_io_hid::exchange(unsigned char *command, unsigned int cmd_len, unsigned char *response, unsigned int max_resp_len)  {
+      unsigned char buffer[400];
+      unsigned char padding_buffer[MAX_BLOCK+1];
+      unsigned int  result;
+               int  hid_ret;
+      unsigned int  sw_offset;
+      unsigned int  remaining;
+      unsigned int  offset = 0;
+
+      ASSERT_X(this->usb_device,"No device opened");
+
+      //Split command in several HID packet
+      memset(buffer, 0, sizeof(buffer));
+      result = this->wrapCommand(command, cmd_len, buffer, sizeof(buffer));
+      remaining = result;
+
+      while (remaining > 0) {
+        int block_size = (remaining > MAX_BLOCK ? MAX_BLOCK : remaining);
+        memset(padding_buffer, 0, sizeof(padding_buffer));
+        memcpy(padding_buffer+1, buffer + offset, block_size);
+        io_hid_log(0, padding_buffer, block_size+1);
+        hid_ret = hid_write(this->usb_device, padding_buffer, block_size+1);
+        ASSERT_X(hid_ret>=0, "Unable to send hidapi command. Error "+std::to_string(result)+": "+ safe_hid_error(this->usb_device));
+        offset += block_size;
+        remaining -= block_size;
+      }
+
+      //get first response
+      memset(buffer, 0, sizeof(buffer));
+      hid_ret = hid_read_timeout(this->usb_device, buffer, MAX_BLOCK, this->timeout);
+      ASSERT_X(hid_ret>=0, "Unable to read hidapi response. Error "+std::to_string(result)+": "+ safe_hid_error(this->usb_device));
+      result = (unsigned int)hid_ret;
+      io_hid_log(1, buffer, result); 
+      offset = MAX_BLOCK;
+      //parse first response and get others if any
+      for (;;) {
+        result = this->unwrapReponse(buffer, offset, response, max_resp_len);
+        if (result != 0) {
+          break;
+        }
+        hid_ret = hid_read_timeout(this->usb_device, buffer + offset, MAX_BLOCK, this->timeout);
+        ASSERT_X(hid_ret>=0, "Unable to receive hidapi response. Error "+std::to_string(result)+": "+ safe_hid_error(this->usb_device));
+        result = (unsigned int)hid_ret;
+        io_hid_log(1, buffer + offset, result);
+        offset += MAX_BLOCK;
+      }      
+      return result;
+    }
+
+    void device_io_hid::disconnect(void)  {
+      if (this->usb_device) {
+        hid_close(this->usb_device);
+      }
+      this->usb_vid = 0;
+      this->usb_pid = 0;
+      this->usb_device = NULL;
+    }
+
+    void device_io_hid::release()  {
+      /* Do not exit, as the lib context is global*/
+      //hid_exit();
+    }
+
+    unsigned int device_io_hid::wrapCommand(const unsigned char *command, size_t command_len, unsigned char *out, size_t out_len) {
+      unsigned int sequence_idx = 0;
+      unsigned int offset = 0;
+      unsigned int offset_out = 0;
+      unsigned int block_size;
+
+      ASSERT_X(this->packet_size >= 3, "Invalid Packet size: "+std::to_string(this->packet_size)) ;
+      ASSERT_X(out_len >= 7,  "out_len too short: "+std::to_string(out_len));
+
+      out_len -= 7;
+      out[offset_out++] = ((this->channel >> 8) & 0xff);
+      out[offset_out++] = (this->channel & 0xff);
+      out[offset_out++] = this->tag;
+      out[offset_out++] = ((sequence_idx >> 8) & 0xff);
+      out[offset_out++] = (sequence_idx & 0xff);
+      sequence_idx++;
+      out[offset_out++] = ((command_len >> 8) & 0xff);
+      out[offset_out++] = (command_len & 0xff);
+      block_size = (command_len > this->packet_size - 7 ? this->packet_size - 7 : command_len);
+      ASSERT_X(out_len >= block_size,  "out_len too short: "+std::to_string(out_len));
+      out_len -= block_size;
+      memcpy(out + offset_out, command + offset, block_size);
+      offset_out += block_size;
+      offset += block_size;
+      while (offset != command_len) {
+        ASSERT_X(out_len >= 5,  "out_len too short: "+std::to_string(out_len));
+        out_len -= 5;
+        out[offset_out++] = ((this->channel >> 8) & 0xff);
+        out[offset_out++] = (this->channel & 0xff);
+        out[offset_out++] = this->tag;
+        out[offset_out++] = ((sequence_idx >> 8) & 0xff);
+        out[offset_out++] = (sequence_idx & 0xff);
+        sequence_idx++;
+        block_size = ((command_len - offset) > this->packet_size - 5 ? this->packet_size - 5 : command_len - offset);
+        ASSERT_X(out_len >= block_size,  "out_len too short: "+std::to_string(out_len));
+        out_len -= block_size;
+        memcpy(out + offset_out, command + offset, block_size);
+        offset_out += block_size;
+        offset += block_size;
+      }
+      while ((offset_out % this->packet_size) != 0) {
+        ASSERT_X(out_len >= 1,  "out_len too short: "+std::to_string(out_len));
+        out_len--;
+        out[offset_out++] = 0;
+      }
+      return offset_out;
+    }
+
+    /*
+     * return  0 if more data are needed
+    *         >0 if response is fully available
+     */
+    unsigned int device_io_hid::unwrapReponse(const unsigned char *data, size_t data_len, unsigned char *out, size_t out_len) {
+      unsigned int sequence_idx = 0;
+      unsigned int offset = 0;
+      unsigned int offset_out = 0;
+      unsigned int response_len;
+      unsigned int block_size;
+      unsigned int val;
+
+      //end?
+      if ((data == NULL) || (data_len < 7 + 5)) { 
+        return 0;
+      }
+
+      //check hid header
+      val = (data[offset]<<8) + data[offset+1];
+      offset += 2;
+      ASSERT_X(val == this->channel, "Wrong Channel");
+      val =  data[offset];
+      offset++;
+      ASSERT_X(val == this->tag, "Wrong TAG");      
+      val = (data[offset]<<8) + data[offset+1];
+      offset += 2;
+      ASSERT_X(val == sequence_idx, "Wrong sequence_idx");
+
+      //fetch
+      response_len = (data[offset++] << 8);
+      response_len |= data[offset++];
+      ASSERT_X(out_len >= response_len, "Out Buffer too short");
+      if (data_len < (7 + response_len)) {
+        return 0;
+      }
+      block_size = (response_len > (this->packet_size - 7) ? this->packet_size - 7 : response_len);
+      memcpy(out + offset_out, data + offset, block_size);
+      offset += block_size;
+      offset_out += block_size;
+      while (offset_out != response_len) {
+        sequence_idx++;
+        if (offset == data_len) {
+          return 0;
+        }
+        val = (data[offset]<<8) + data[offset+1];
+        offset += 2;
+        ASSERT_X(val == this->channel, "Wrong Channel");
+        val =  data[offset];
+        offset++;
+        ASSERT_X(val == this->tag, "Wrong TAG");      
+        val = (data[offset]<<8) + data[offset+1];
+        offset += 2;
+        ASSERT_X(val == sequence_idx, "Wrong sequence_idx");
+
+        block_size = ((response_len - offset_out) > this->packet_size - 5 ? this->packet_size - 5 : response_len - offset_out);
+        if (block_size > (data_len - offset)) {
+          return 0;
+        }
+        memcpy(out + offset_out, data + offset, block_size);
+        offset += block_size;
+        offset_out += block_size;
+      }
+      return offset_out;
+    }
+
+
+  }
+}
+
+#endif //#if defined(HAVE_HIDAPI) 
diff --git a/src/device/device_io_hid.hpp b/src/device/device_io_hid.hpp
new file mode 100644
index 000000000..560208c77
--- /dev/null
+++ b/src/device/device_io_hid.hpp
@@ -0,0 +1,112 @@
+// Copyright (c) 2017-2018, The Monero Project
+// 
+// All rights reserved.
+// 
+// Redistribution and use in source and binary forms, with or without modification, are
+// permitted provided that the following conditions are met:
+// 
+// 1. Redistributions of source code must retain the above copyright notice, this list of
+//    conditions and the following disclaimer.
+// 
+// 2. Redistributions in binary form must reproduce the above copyright notice, this list
+//    of conditions and the following disclaimer in the documentation and/or other
+//    materials provided with the distribution.
+// 
+// 3. Neither the name of the copyright holder nor the names of its contributors may be
+//    used to endorse or promote products derived from this software without specific
+//    prior written permission.
+// 
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
+// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+
+#if defined(HAVE_HIDAPI) 
+
+#include <hidapi/hidapi.h>
+#include "device_io.hpp"
+
+#pragma once
+
+namespace hw {
+  namespace io {
+
+
+
+    /** HID class base. Commands are formated as follow:
+     *
+     * |----------------------------------------------------------|
+     * |  2 bytes  |  1 byte  |  2 bytes  | 2 bytes  |  len bytes |
+     * |-----------|----------|-----------|----------|------------|
+     * |  channel  |    tag   |  sequence |   len    |  payload   |
+     * |----------------------------------------------------------|
+     */
+
+
+    struct hid_conn_params {
+      unsigned int vid; 
+      unsigned int pid; 
+      unsigned int interface_number;
+      unsigned int usage_page;
+      bool interface_OR_page ;
+    };
+    
+
+    class device_io_hid: device_io {
+      
+
+    private:
+     
+
+      unsigned short channel;
+      unsigned char  tag;
+      unsigned int   packet_size; 
+      unsigned int   timeout;
+
+      unsigned int   usb_vid;
+      unsigned int   usb_pid;
+      hid_device     *usb_device;
+
+      void io_hid_log(int read, unsigned char* buf, int buf_len);
+      void io_hid_init();
+      void io_hid_exit() ;
+      void io_hid_open(int vid, int pid,  int mode);
+      void io_hid_close (void);
+
+      unsigned int wrapCommand(const unsigned char *command, size_t command_len, unsigned char *out, size_t out_len);
+      unsigned int unwrapReponse(const unsigned char *data, size_t data_len, unsigned char *out, size_t out_len);
+ 
+ 
+    public:
+      bool hid_verbose = false;
+
+      const unsigned int  OR_SELECT = 1;
+      const unsigned int  AND_SELECT = 2;
+
+      const unsigned char DEFAULT_CHANNEL     = 0x0001;
+      const unsigned char DEFAULT_TAG         = 0x01;
+      const unsigned int  DEFAULT_PACKET_SIZE = 64;
+      const unsigned int  DEFAULT_TIMEOUT     = 120000;
+
+      device_io_hid(unsigned short channel, unsigned char tag, unsigned int packet_zize, unsigned int timeout);
+      device_io_hid();
+      ~device_io_hid() {};
+
+      void init();  
+      void connect(void *params);
+      void connect(unsigned int vid, unsigned  int pid, unsigned int interface_number, unsigned int usage_page, bool interface_OR_page );
+      bool connected() const;
+      int  exchange(unsigned char *command, unsigned int cmd_len, unsigned char *response, unsigned int max_resp_len);
+      void disconnect();
+      void release();
+    };
+  };
+};
+
+#endif //#if defined(HAVE_HIDAPI) 
diff --git a/src/device/device_ledger.cpp b/src/device/device_ledger.cpp
index 9b5ea0fd7..456eda739 100644
--- a/src/device/device_ledger.cpp
+++ b/src/device/device_ledger.cpp
@@ -185,41 +185,8 @@ namespace hw {
     #define INS_GET_RESPONSE                    0xc0
 
 
-    void device_ledger::logCMD() {
-      if (apdu_verbose) {
-        char  strbuffer[1024];
-        snprintf(strbuffer, sizeof(strbuffer), "%.02x %.02x %.02x %.02x %.02x ",
-          this->buffer_send[0],
-          this->buffer_send[1],
-          this->buffer_send[2],
-          this->buffer_send[3],
-          this->buffer_send[4]
-          );
-        const size_t len = strlen(strbuffer);
-        buffer_to_str(strbuffer+len, sizeof(strbuffer)-len, (char*)(this->buffer_send+5), this->length_send-5);
-        MDEBUG( "CMD  :" << strbuffer);
-      }
-    }
-
-    void device_ledger::logRESP() {
-      if (apdu_verbose) {
-        char  strbuffer[1024];
-        snprintf(strbuffer, sizeof(strbuffer), "%.02x%.02x ",
-          this->buffer_recv[this->length_recv-2],
-          this->buffer_recv[this->length_recv-1]
-          );
-        const size_t len = strlen(strbuffer);
-        buffer_to_str(strbuffer+len, sizeof(strbuffer)-len, (char*)(this->buffer_recv), this->length_recv-2);
-        MDEBUG( "RESP :" << strbuffer);
-
-      }
-    }
-
-    /* -------------------------------------------------------------- */
-    device_ledger::device_ledger() {
+    device_ledger::device_ledger(): hw_device(0x0101, 0x05, 64, 10000) {
       this->id = device_id++;
-      this->hCard   = 0;
-      this->hContext = 0;
       this->reset_buffer();      
       this->mode = NONE;
       this->has_view_key = false;
@@ -272,10 +239,39 @@ namespace hw {
       MDEBUG( "Device "<<this->name << " UNLOCKed");
     }
 
+  
     /* ======================================================================= */
-    /*                                   MISC                                  */
+    /*                                     IO                                  */
     /* ======================================================================= */
-    int device_ledger::set_command_header(BYTE ins, BYTE p1, BYTE p2) {
+
+      void device_ledger::logCMD() {
+      if (apdu_verbose) {
+        char  strbuffer[1024];
+        snprintf(strbuffer, sizeof(strbuffer), "%.02x %.02x %.02x %.02x %.02x ",
+          this->buffer_send[0],
+          this->buffer_send[1],
+          this->buffer_send[2],
+          this->buffer_send[3],
+          this->buffer_send[4]
+          );
+        const size_t len = strlen(strbuffer);
+        buffer_to_str(strbuffer+len, sizeof(strbuffer)-len, (char*)(this->buffer_send+5), this->length_send-5);
+        MDEBUG( "CMD  : " << strbuffer);
+      }
+    }
+
+    void device_ledger::logRESP() {
+      if (apdu_verbose) {
+        char  strbuffer[1024];
+        snprintf(strbuffer, sizeof(strbuffer), "%.04x ", this->sw);
+        const size_t len = strlen(strbuffer);
+        buffer_to_str(strbuffer+len, sizeof(strbuffer)-len, (char*)(this->buffer_recv), this->length_recv);
+        MDEBUG( "RESP : " << strbuffer);
+
+      }
+    }
+
+    int device_ledger::set_command_header(unsigned char ins, unsigned char p1, unsigned char p2) {
       reset_buffer();
       int offset = 0;
       this->buffer_send[0] = 0x00;
@@ -286,7 +282,7 @@ namespace hw {
       return 5;
     }
 
-    int device_ledger::set_command_header_noopt(BYTE ins, BYTE p1, BYTE p2) {
+    int device_ledger::set_command_header_noopt(unsigned char ins, unsigned char p1, unsigned char p2) {
       int offset = set_command_header(ins, p1, p2);
       //options
       this->buffer_send[offset++] = 0;
@@ -294,7 +290,7 @@ namespace hw {
       return offset;
     }
 
-    void device_ledger::send_simple(BYTE ins, BYTE p1) {
+    void device_ledger::send_simple(unsigned char ins, unsigned char p1) {
       this->length_send = set_command_header_noopt(ins, p1);
       this->exchange();
     }
@@ -305,23 +301,17 @@ namespace hw {
     }
      
     unsigned int device_ledger::exchange(unsigned int ok, unsigned int mask) {
-      LONG rv;
-      unsigned int sw;
-
-      ASSERT_T0(this->length_send <= BUFFER_SEND_SIZE);
       logCMD();
-      this->length_recv = BUFFER_RECV_SIZE;
-      rv = SCardTransmit(this->hCard,
-                         SCARD_PCI_T0, this->buffer_send, this->length_send,
-                         NULL,         this->buffer_recv, &this->length_recv);
-      ASSERT_RV(rv);
-      ASSERT_T0(this->length_recv >= 2);
-      ASSERT_T0(this->length_recv <= BUFFER_RECV_SIZE);
-      logRESP();
 
-      sw = (this->buffer_recv[this->length_recv-2]<<8) | this->buffer_recv[this->length_recv-1];
-      ASSERT_SW(sw,ok,msk);
-      return sw;
+      this->length_recv =  hw_device.exchange(this->buffer_send, this->length_send, this->buffer_recv, BUFFER_SEND_SIZE);
+      ASSERT_X(this->length_recv>=2, "Communication error, less than tow bytes received");
+
+      this->length_recv -= 2;
+      this->sw = (this->buffer_recv[length_recv]<<8) | this->buffer_recv[length_recv+1];
+      ASSERT_SW(this->sw,ok,msk);
+
+      logRESP();
+      return this->sw;
     }
 
     void device_ledger::reset_buffer() {
@@ -341,101 +331,25 @@ namespace hw {
     }
 
     const std::string device_ledger::get_name() const {
-      if (this->full_name.empty() || (this->hCard == 0)) {
+      if (this->full_name.empty() || !this->connected()) {
         return std::string("<disconnected:").append(this->name).append(">");
       }
-      return this->full_name;
+      return this->name;
     }
 
     bool device_ledger::init(void) {
       #ifdef DEBUG_HWDEVICE
       this->controle_device = &hw::get_device("default");
       #endif
-      LONG  rv;
       this->release();
-      rv = SCardEstablishContext(SCARD_SCOPE_SYSTEM,0,0, &this->hContext);
-      ASSERT_RV(rv);
-      MDEBUG( "Device "<<this->id <<" SCardContext created: hContext="<<this->hContext);
-      this->hCard = 0;
-      return true;
-    }
-
-    bool device_ledger::release() {
-      this->disconnect();
-      if (this->hContext) {
-        SCardReleaseContext(this->hContext);
-        MDEBUG( "Device "<<this->id <<" SCardContext released: hContext="<<this->hContext);
-        this->hContext = 0;
-        this->full_name.clear();
-      }
+      hw_device.init();      
+      MDEBUG( "Device "<<this->id <<" HIDUSB inited");
       return true;
     }
 
     bool device_ledger::connect(void) {
-      BYTE  pbAtr[MAX_ATR_SIZE];
-      LPSTR mszReaders;
-      DWORD dwReaders;
-      LONG  rv;
-      DWORD dwState, dwProtocol, dwAtrLen, dwReaderLen;
-
       this->disconnect();
-#ifdef SCARD_AUTOALLOCATE
-      dwReaders = SCARD_AUTOALLOCATE;
-      rv = SCardListReaders(this->hContext, NULL, (LPSTR)&mszReaders, &dwReaders);
-#else
-      dwReaders = 0;
-      rv = SCardListReaders(this->hContext, NULL, NULL, &dwReaders);
-      if (rv != SCARD_S_SUCCESS)
-        return false;
-      mszReaders = (LPSTR)calloc(dwReaders, sizeof(char));
-      rv = SCardListReaders(this->hContext, NULL, mszReaders, &dwReaders);
-#endif
-      if (rv == SCARD_S_SUCCESS) {
-        char* p;
-        const char* prefix = this->name.c_str();
-
-        p = mszReaders;
-        MDEBUG( "Looking for " << std::string(prefix));
-        while (*p) {
-          MDEBUG( "Device Found: " <<  std::string(p));
-          if ((strncmp(prefix, p, strlen(prefix))==0)) {
-            MDEBUG( "Device Match: " <<  std::string(p));
-            if ((rv = SCardConnect(this->hContext,
-                                   p, SCARD_SHARE_EXCLUSIVE, SCARD_PROTOCOL_T0,
-                                   &this->hCard, &dwProtocol))!=SCARD_S_SUCCESS) {
-              break;
-            }
-            MDEBUG( "Device "<<this->id <<" Connected: hCard="<<this->hCard);
-            dwAtrLen = sizeof(pbAtr);
-            if ((rv = SCardStatus(this->hCard, NULL, &dwReaderLen, &dwState, &dwProtocol, pbAtr, &dwAtrLen))!=SCARD_S_SUCCESS) {
-              break;
-            }
-            MDEBUG( "Device "<<this->id <<" Status OK");
-            rv = SCARD_S_SUCCESS ;
-            this->full_name = std::string(p);
-            break;
-          }
-          p += strlen(p) +1;
-        }
-      }
-
-      if (rv == SCARD_S_SUCCESS && mszReaders) {
-        #ifdef SCARD_AUTOALLOCATE
-        SCardFreeMemory(this->hContext, mszReaders);
-        #else
-        free(mszReaders);
-        #endif
-        mszReaders = NULL;
-      }
-      if (rv != SCARD_S_SUCCESS) {
-        if ( hCard) {
-          SCardDisconnect(this->hCard, SCARD_UNPOWER_CARD);
-          MDEBUG( "Device "<<this->id <<" disconnected: hCard="<<this->hCard);
-          this->hCard = 0;
-        }
-      }
-      ASSERT_RV(rv);
-
+      hw_device.connect(0x2c97,0x0001, 0, 0xffa0, hw_device.OR_SELECT);
       this->reset();
       #ifdef DEBUG_HWDEVICE
       cryptonote::account_public_address pubkey;
@@ -445,15 +359,21 @@ namespace hw {
       crypto::secret_key skey;
       this->get_secret_keys(vkey,skey);
 
-      return rv==SCARD_S_SUCCESS;
+      return true;
+    }
+
+    bool device_ledger::connected(void) const {
+      return hw_device.connected();
     }
 
     bool device_ledger::disconnect() {
-      if (this->hCard) {
-        SCardDisconnect(this->hCard, SCARD_UNPOWER_CARD);
-        MDEBUG( "Device "<<this->id <<" disconnected: hCard="<<this->hCard); 
-        this->hCard = 0;
-      }
+      hw_device.disconnect();
+      return true;
+    }
+
+    bool device_ledger::release() {
+      this->disconnect();
+      hw_device.release();
       return true;
     }
 
diff --git a/src/device/device_ledger.hpp b/src/device/device_ledger.hpp
index 4a3625b2b..87b65996d 100644
--- a/src/device/device_ledger.hpp
+++ b/src/device/device_ledger.hpp
@@ -33,13 +33,7 @@
 #include <cstddef>
 #include <string>
 #include "device.hpp"
-#ifdef WIN32
-#include <winscard.h>
-#define MAX_ATR_SIZE            33
-#else
-#include <PCSC/winscard.h>
-#include <PCSC/wintypes.h>
-#endif
+#include "device_io_hid.hpp"
 #include <boost/thread/mutex.hpp>
 #include <boost/thread/recursive_mutex.hpp>
 
@@ -89,22 +83,23 @@ namespace hw {
         mutable boost::recursive_mutex   device_locker;
         mutable boost::mutex   command_locker;
 
-        //PCSC management 
-        std::string  full_name;
-        SCARDCONTEXT hContext;
-        SCARDHANDLE  hCard;
-        DWORD        length_send;
-        BYTE         buffer_send[BUFFER_SEND_SIZE];
-        DWORD        length_recv;
-        BYTE         buffer_recv[BUFFER_RECV_SIZE];
-        unsigned int id;
+        //IO
+        hw::io::device_io_hid hw_device;
+        std::string   full_name;        
+        unsigned int  length_send;
+        unsigned char buffer_send[BUFFER_SEND_SIZE];
+        unsigned int  length_recv;
+        unsigned char buffer_recv[BUFFER_RECV_SIZE];
+        unsigned int  sw;
+        unsigned int  id;
         void logCMD(void);
         void logRESP(void);
-        unsigned int  exchange(unsigned int ok=0x9000, unsigned int mask=0xFFFF);
+        unsigned int exchange(unsigned int ok=0x9000, unsigned int mask=0xFFFF);
         void reset_buffer(void);
-        int set_command_header(BYTE ins, BYTE p1 = 0x00, BYTE p2 = 0x00);
-        int set_command_header_noopt(BYTE ins, BYTE p1 = 0x00, BYTE p2 = 0x00);
-        void send_simple(BYTE ins, BYTE p1 = 0x00);
+        int  set_command_header(unsigned char ins, unsigned char p1 = 0x00, unsigned char p2 = 0x00);
+        int  set_command_header_noopt(unsigned char ins, unsigned char p1 = 0x00, unsigned char p2 = 0x00);
+        void send_simple(unsigned char ins, unsigned char p1 = 0x00);
+
 
         // hw running mode
         device_mode mode;
@@ -127,7 +122,7 @@ namespace hw {
         device_ledger(const device_ledger &device) = delete ;
         device_ledger& operator=(const device_ledger &device) = delete;
 
-        explicit operator bool() const override {return this->hContext != 0;}
+        explicit operator bool() const override {return this->connected(); }
 
         bool  reset(void);
 
@@ -141,6 +136,7 @@ namespace hw {
         bool release() override;
         bool connect(void) override;
         bool disconnect() override;
+        bool connected(void) const;
 
         bool set_mode(device_mode mode) override;
 
diff --git a/src/device/log.cpp b/src/device/log.cpp
index 1707524fb..c9d3b551b 100644
--- a/src/device/log.cpp
+++ b/src/device/log.cpp
@@ -32,29 +32,34 @@
 
 namespace hw {
 
-    #ifdef WITH_DEVICE_LEDGER    
-    namespace ledger {
-    
-    #undef MONERO_DEFAULT_LOG_CATEGORY
-    #define MONERO_DEFAULT_LOG_CATEGORY "device.ledger"
+  #undef MONERO_DEFAULT_LOG_CATEGORY
+  #define MONERO_DEFAULT_LOG_CATEGORY "device"
 
-    void buffer_to_str(char *to_buff,  size_t to_len, const char *buff, size_t len) {
-      CHECK_AND_ASSERT_THROW_MES(to_len > (len*2), "destination buffer too short. At least" << (len*2+1) << " bytes required");
-      for (size_t i=0; i<len; i++) {
-        sprintf(to_buff+2*i, "%.02x", (unsigned char)buff[i]);
-      }
+  void buffer_to_str(char *to_buff,  size_t to_len, const char *buff, size_t len) {
+    CHECK_AND_ASSERT_THROW_MES(to_len > (len*2), "destination buffer too short. At least" << (len*2+1) << " bytes required");
+    for (size_t i=0; i<len; i++) {
+      sprintf(to_buff+2*i, "%.02x", (unsigned char)buff[i]);
     }
+  }
 
-    void log_hexbuffer(const std::string &msg,  const char* buff, size_t len) {
-      char logstr[1025];
-      buffer_to_str(logstr, sizeof(logstr),  buff, len);
-      MDEBUG(msg<< ": " << logstr);
-    }
+  void log_hexbuffer(const std::string &msg,  const char* buff, size_t len) {
+    char logstr[1025];
+    buffer_to_str(logstr, sizeof(logstr),  buff, len);
+    MDEBUG(msg<< ": " << logstr);
+  }
 
-    void log_message(const std::string &msg, const std::string &info ) {
-      MDEBUG(msg << ": " << info);
-    }
+  void log_message(const std::string &msg, const std::string &info ) {
+    MDEBUG(msg << ": " << info);
+  }
+
+
+  #ifdef WITH_DEVICE_LEDGER    
+    namespace ledger {
+    
+    #undef MONERO_DEFAULT_LOG_CATEGORY
+    #define MONERO_DEFAULT_LOG_CATEGORY "device.ledger"
 
+    
     #ifdef DEBUG_HWDEVICE
     extern crypto::secret_key dbg_viewkey;
     extern crypto::secret_key dbg_spendkey;
diff --git a/src/device/log.hpp b/src/device/log.hpp
index 1d1635dc1..25a214a6c 100644
--- a/src/device/log.hpp
+++ b/src/device/log.hpp
@@ -40,12 +40,13 @@
 
 namespace hw {
 
+    void buffer_to_str(char *to_buff,  size_t to_len, const char *buff, size_t len) ;
+    void log_hexbuffer(const std::string &msg,  const char* buff, size_t len);
+    void log_message(const std::string &msg, const std::string &info );
+
     #ifdef WITH_DEVICE_LEDGER    
     namespace ledger {
 
-        void buffer_to_str(char *to_buff,  size_t to_len, const char *buff, size_t len) ;
-        void log_hexbuffer(const std::string &msg,  const char* buff, size_t len);
-        void log_message(const std::string &msg, const std::string &info );
         #ifdef DEBUG_HWDEVICE
         #define TRACK printf("file %s:%d\n",__FILE__, __LINE__)
         //#define TRACK MCDEBUG("ledger"," At file " << __FILE__ << ":" << __LINE__)
-- 
cgit v1.2.3