API
ttyUSB.cpp
Go to the documentation of this file.
1 /** \file ttyUSB.cpp
2  * \author Jared R. Males
3  * \brief Find the details for USB serial devices
4  *
5  * \ingroup tty_files
6  *
7  */
8 
9 
10 #include <iostream>
11 
12 #include <libudev.h>
13 
14 #include <string>
15 #include <cstring>
16 
17 #include <boost/filesystem.hpp>
18 #include <mx/ioutils/fileUtils.hpp>
19 
20 #include "ttyUSB.hpp"
21 
22 #include "ttyErrors.hpp"
23 
24 
25 namespace MagAOX
26 {
27 namespace tty
28 {
29 
30 int ttyUSBDevName( std::string & devName, // [out] the /dev/ttyUSBX device name.
31  const std::string & vendor, // [in] the 4-digit vendor identifier.
32  const std::string & product, // [in] the 4-digit product identifier.
33  const std::string & serial // [in] the serial number. Can be "".
34  )
35 {
36  std::vector<std::string> devNames;
37 
38  devName = "";
39  devNames = mx::ioutils::getFileNames("/sys/class/tty/", "ttyUSB", "", "");
40 
41  if(devNames.size() == 0) return TTY_E_NODEVNAMES;
42 
43  struct udev *udev;
44 
45 
46  /* Create the udev object */
47  udev = udev_new();
48  if (!udev) return TTY_E_UDEVNEWFAILED;
49 
50  for(size_t i=0; i< devNames.size(); ++i)
51  {
52  struct udev_device *dev0;
53 
54  dev0 = udev_device_new_from_syspath(udev, devNames[i].c_str());
55 
56  if(!dev0)
57  {
58  std::cerr << "udev_device_new_from_syspath failed: " << strerror(errno) << "\n";
59  perror("");
60  continue;
61  }
62 
63  struct udev_device *dev;
64 
65  dev = udev_device_get_parent_with_subsystem_devtype( dev0, "usb", "usb_device");
66 
67  if (!dev)
68  {
69  std::cerr << "udev_device_get_parent_with_subsystem_devtype failed: " << strerror(errno) << "\n";
70  perror("");
71  udev_device_unref(dev0);
72  continue;
73  }
74 
75  const char * idVendor = udev_device_get_sysattr_value( dev, "idVendor" );
76 
77  if(idVendor == nullptr)
78  {
79  udev_device_unref(dev0);
80  continue;
81  }
82 
83  if( strcmp( idVendor, vendor.c_str()) != 0)
84  {
85  udev_device_unref(dev0);
86  continue;
87  }
88 
89  const char * idProduct = udev_device_get_sysattr_value( dev, "idProduct" );
90 
91  if(idProduct == nullptr)
92  {
93  udev_device_unref(dev0);
94  continue;
95  }
96 
97  if( strcmp( idProduct, product.c_str()) != 0)
98  {
99  udev_device_unref(dev0);
100  continue;
101  }
102 
103  const char * dserial = udev_device_get_sysattr_value( dev, "serial" );
104 
105  if(dserial == nullptr)
106  {
107  if( serial != "")
108  {
109  udev_device_unref(dev0);
110  continue;
111  }
112  }
113  else if( strcmp( dserial, serial.c_str()) != 0 )
114  {
115  udev_device_unref(dev0);
116  continue;
117  }
118 
119  //If we make it through all comparisons we found it!
120  boost::filesystem::path p(devNames[i]);
121  devName = "/dev/" + p.filename().string();
122 
123  udev_device_unref(dev0);
124 
125  udev_unref(udev);
126 
127  return TTY_E_NOERROR;
128  }
129 
130  devName = "";
131 
132  udev_unref(udev);
133 
134  return TTY_E_DEVNOTFOUND;
135 }
136 
137 int ttyUSBDevNames( std::vector<std::string> & devNames, // [out] the /dev/ttyUSBX device names for all matching devices.
138  const std::string & vendor, // [in] the 4-digit vendor identifier.
139  const std::string & product // [in] the 4-digit product identifier.
140  )
141 {
142  std::vector<std::string> pdevNames;
143 
144  devNames.clear();
145 
146  pdevNames = mx::ioutils::getFileNames("/sys/class/tty/", "ttyUSB", "", "");
147 
148  if(pdevNames.size() == 0) return TTY_E_NODEVNAMES;
149 
150  struct udev *udev;
151 
152  /* Create the udev object */
153  udev = udev_new();
154  if (!udev) return TTY_E_UDEVNEWFAILED;
155 
156  for(size_t i=0; i< pdevNames.size(); ++i)
157  {
158  struct udev_device *dev0;
159 
160  dev0 = udev_device_new_from_syspath(udev, pdevNames[i].c_str());
161 
162  if(!dev0)
163  {
164  continue;
165  }
166 
167  struct udev_device * dev;
168  dev = udev_device_get_parent_with_subsystem_devtype( dev0, "usb", "usb_device");
169 
170  if (!dev)
171  {
172  udev_device_unref(dev0);
173  continue;
174  }
175 
176  const char * idVendor = udev_device_get_sysattr_value( dev, "idVendor" );
177 
178  if(idVendor == nullptr)
179  {
180  udev_device_unref(dev0);
181  continue;
182  }
183 
184  if( strcmp( idVendor, vendor.c_str()) != 0)
185  {
186  udev_device_unref(dev0);
187  continue;
188  }
189 
190  const char * idProduct = udev_device_get_sysattr_value( dev, "idProduct" );
191 
192  if(idProduct == nullptr)
193  {
194  udev_device_unref(dev0);
195  continue;
196  }
197 
198  if( strcmp( idProduct, product.c_str()) != 0)
199  {
200  udev_device_unref(dev0);
201  continue;
202  }
203 
204  //If we make it through all comparisons we found it!
205  boost::filesystem::path p(pdevNames[i]);
206  devNames.push_back( "/dev/" + p.filename().string());
207 
208  udev_device_unref(dev0);
209  }
210 
211  udev_unref(udev);
212 
213  if( devNames.size() > 0) return TTY_E_NOERROR;
214  else return TTY_E_DEVNOTFOUND;
215 
216 }
217 } //namespace tty
218 } //namespace MagAOX
219 
int ttyUSBDevName(std::string &devName, const std::string &vendor, const std::string &product, const std::string &serial)
Get the ttyUSB device name for a specific device.
Definition: ttyUSB.cpp:30
int ttyUSBDevNames(std::vector< std::string > &devNames, const std::string &vendor, const std::string &product)
Get the ttyUSB device name for a set of devices specified by their vendor and product ids.
Definition: ttyUSB.cpp:137
std::ostream & cerr()
Definition: dm.hpp:24
Error numbers for the tty utilities.
#define TTY_E_UDEVNEWFAILED
Definition: ttyErrors.hpp:29
#define TTY_E_NODEVNAMES
Definition: ttyErrors.hpp:28
#define TTY_E_DEVNOTFOUND
Definition: ttyErrors.hpp:30
#define TTY_E_NOERROR
Definition: ttyErrors.hpp:15
Find the details for USB serial devices.