1 /**
2     @file Connection_uLimeSDREntry.cpp
3     @author Lime Microsystems
4     @brief Implementation of uLimeSDR board connection.
5 */
6 
7 #include "ConnectionFT601.h"
8 #include "Logger.h"
9 #include "threadHelper.h"
10 using namespace lime;
11 
12 #ifdef __unix__
handle_libusb_events()13 void ConnectionFT601Entry::handle_libusb_events()
14 {
15     struct timeval tv;
16     tv.tv_sec = 0;
17     tv.tv_usec = 250000;
18     while(mProcessUSBEvents.load() == true)
19     {
20         int r = libusb_handle_events_timeout_completed(ctx, &tv, NULL);
21         if(r != 0) lime::error("error libusb_handle_events %s", libusb_strerror(libusb_error(r)));
22     }
23 }
24 #endif // __UNIX__
25 
26 //! make a static-initialized entry in the registry
__loadConnectionFT601Entry(void)27 void __loadConnectionFT601Entry(void) //TODO fixme replace with LoadLibrary/dlopen
28 {
29     static ConnectionFT601Entry FTDIEntry;
30 }
31 
ConnectionFT601Entry(void)32 ConnectionFT601Entry::ConnectionFT601Entry(void):
33     ConnectionRegistryEntry("FT601")
34 {
35 #ifndef __unix__
36     //m_pDriver = new CDriverInterface();
37 #else
38     int r = libusb_init(&ctx); //initialize the library for the session we just declared
39     if(r < 0)
40         lime::error("Init Error %i", r); //there was an error
41 #if LIBUSBX_API_VERSION < 0x01000106
42     libusb_set_debug(ctx, 3); //set verbosity level to 3, as suggested in the documentation
43 #else
44     libusb_set_option(ctx, LIBUSB_OPTION_LOG_LEVEL, 3); //set verbosity level to 3, as suggested in the documentation
45 #endif
46     mProcessUSBEvents.store(true);
47     mUSBProcessingThread = std::thread(&ConnectionFT601Entry::handle_libusb_events, this);
48     SetOSThreadPriority(ThreadPriority::NORMAL, ThreadPolicy::REALTIME, &mUSBProcessingThread);
49 #endif
50 }
51 
~ConnectionFT601Entry(void)52 ConnectionFT601Entry::~ConnectionFT601Entry(void)
53 {
54 #ifndef __unix__
55     //delete m_pDriver;
56 #else
57     mProcessUSBEvents.store(false);
58     mUSBProcessingThread.join();
59     libusb_exit(ctx);
60 #endif
61 }
62 
enumerate(const ConnectionHandle & hint)63 std::vector<ConnectionHandle> ConnectionFT601Entry::enumerate(const ConnectionHandle &hint)
64 {
65     std::vector<ConnectionHandle> handles;
66 
67 #ifndef __unix__
68     FT_STATUS ftStatus=FT_OK;
69     static DWORD numDevs = 0;
70 
71     ftStatus = FT_CreateDeviceInfoList(&numDevs);
72 
73     if (!FT_FAILED(ftStatus) && numDevs > 0)
74     {
75         DWORD Flags = 0;
76         char SerialNumber[16] = { 0 };
77         char Description[32] = { 0 };
78         for (DWORD i = 0; i < numDevs; i++)
79         {
80             ftStatus = FT_GetDeviceInfoDetail(i, &Flags, nullptr, nullptr, nullptr, SerialNumber, Description, nullptr);
81             if (!FT_FAILED(ftStatus))
82             {
83                 ConnectionHandle handle;
84                 handle.media = Flags & FT_FLAGS_SUPERSPEED ? "USB 3" : Flags & FT_FLAGS_HISPEED ? "USB 2" : "USB";
85                 handle.name = Description;
86                 handle.index = i;
87                 handle.serial = SerialNumber;
88                 //add handle conditionally, filter by serial number
89                 if (hint.serial.empty() || handle.serial.find(hint.serial) != std::string::npos)
90                     handles.push_back(handle);
91             }
92         }
93     }
94 #else
95     libusb_device **devs; //pointer to pointer of device, used to retrieve a list of devices
96     int usbDeviceCount = libusb_get_device_list(ctx, &devs);
97 
98     if (usbDeviceCount < 0) {
99         lime::error("failed to get libusb device list: %s", libusb_strerror(libusb_error(usbDeviceCount)));
100         return handles;
101     }
102 
103     libusb_device_descriptor desc;
104     for(int i=0; i<usbDeviceCount; ++i)
105     {
106         int r = libusb_get_device_descriptor(devs[i], &desc);
107         if(r<0)
108             lime::error("failed to get device description");
109         int pid = desc.idProduct;
110         int vid = desc.idVendor;
111 
112         if( vid == 0x0403)
113         {
114             if(pid == 0x601F)
115             {
116                 libusb_device_handle *tempDev_handle(nullptr);
117                 if(libusb_open(devs[i], &tempDev_handle) != 0 || tempDev_handle == nullptr)
118                     continue;
119 
120                 ConnectionHandle handle;
121                 //check operating speed
122                 int speed = libusb_get_device_speed(devs[i]);
123                 if(speed == LIBUSB_SPEED_HIGH)
124                     handle.media = "USB 2.0";
125                 else if(speed == LIBUSB_SPEED_SUPER)
126                     handle.media = "USB 3.0";
127                 else
128                     handle.media = "USB";
129                 //read device name
130                 char data[255];
131                 memset(data, 0, 255);
132                 int st = libusb_get_string_descriptor_ascii(tempDev_handle, LIBUSB_CLASS_COMM, (unsigned char*)data, 255);
133                 if(st < 0)
134                     lime::error("Error getting usb descriptor");
135                 else
136                     handle.name = std::string(data, size_t(st));
137                 handle.addr = std::to_string(int(pid))+":"+std::to_string(int(vid));
138 
139                 if (desc.iSerialNumber > 0)
140                 {
141                     r = libusb_get_string_descriptor_ascii(tempDev_handle,desc.iSerialNumber,(unsigned char*)data, sizeof(data));
142                     if(r<0)
143                         lime::error("failed to get serial number");
144                     else
145                         handle.serial = std::string(data, size_t(r));
146                 }
147                 libusb_close(tempDev_handle);
148 
149                 //add handle conditionally, filter by serial number
150                 if (hint.serial.empty() or handle.serial.find(hint.serial) != std::string::npos)
151                 {
152                     handles.push_back(handle);
153                 }
154             }
155         }
156     }
157 
158     libusb_free_device_list(devs, 1);
159 #endif
160     return handles;
161 }
162 
make(const ConnectionHandle & handle)163 IConnection *ConnectionFT601Entry::make(const ConnectionHandle &handle)
164 {
165 #ifndef __unix__
166     return new ConnectionFT601(mFTHandle, handle);
167 #else
168     return new ConnectionFT601(ctx, handle);
169 #endif
170 }
171