00001
00010 #include "FindComPorts.h"
00011 #include "DetectOS.h"
00012 #ifdef WINDOWS_OS
00013 #include <windows.h>
00014 #include <setupapi.h>
00015 #include <deque>
00016 #include <algorithm>
00017
00018 #if defined(MSC)
00019 #pragma comment(lib, "setupapi.lib")
00020 #endif
00021
00022 #else
00023 #include <deque>
00024 #include <algorithm>
00025 #include <cstring>
00026 #include <dirent.h>
00027 #include <sys/stat.h>
00028 #endif
00029
00030 using namespace qrk;
00031 using namespace std;
00032
00033
00034 struct FindComPorts::pImpl
00035 {
00036 vector<string> base_names_;
00037 vector<string> driver_names_;
00038
00039
00040 pImpl(void)
00041 {
00042
00043
00044 #if defined(LINUX_OS)
00045 base_names_.push_back("/dev/ttyUSB");
00046 base_names_.push_back("/dev/usb/ttyUSB");
00047 #elif defined(MAC_OS)
00048 base_names_.push_back("/dev/tty.usbmodem");
00049 #endif
00050 }
00051
00052
00053 void addBaseName(const char* base_name)
00054 {
00055 base_names_.insert(base_names_.begin(), base_name);
00056 }
00057
00058
00059 void addDriverName(const char* driver_name)
00060 {
00061 driver_names_.push_back(driver_name);
00062 }
00063
00064
00065 void orderByDriver(deque<string>& ports, deque<string>& drivers,
00066 const char* driver_name,
00067 bool all_ports)
00068 {
00069 if (ports.empty()) {
00070 return;
00071 }
00072
00073 vector<string>::const_iterator it =
00074 std::find(driver_names_.begin(), driver_names_.end(), driver_name);
00075 if (it != driver_names_.end()) {
00076 ports.push_front(ports.back());
00077 ports.pop_back();
00078
00079 drivers.push_front(drivers.back());
00080 drivers.pop_back();
00081
00082 } else {
00083 if (! all_ports) {
00084 ports.pop_back();
00085 drivers.pop_back();
00086 }
00087 }
00088 }
00089
00090
00091 void addFoundPorts(vector<string>& found_ports,
00092 const string& port)
00093 {
00094 for (vector<string>::iterator it = found_ports.begin();
00095 it != found_ports.end(); ++it) {
00096
00097
00098
00099
00100 if (! port.compare(*it)) {
00101 return;
00102 }
00103 }
00104 found_ports.push_back(port);
00105 }
00106 };
00107
00108
00109 FindComPorts::FindComPorts(void) : pimpl(new pImpl)
00110 {
00111 }
00112
00113
00114 FindComPorts::~FindComPorts(void)
00115 {
00116 }
00117
00118
00119 void FindComPorts::clearBaseNames(void)
00120 {
00121 pimpl->base_names_.clear();
00122 }
00123
00124
00125 void FindComPorts::addBaseName(const char* base_name)
00126 {
00127 pimpl->addBaseName(base_name);
00128 }
00129
00130
00131 vector<string> FindComPorts::baseNames(void)
00132 {
00133 return pimpl->base_names_;
00134 }
00135
00136
00137 void FindComPorts::addDriverName(const char* driver_name)
00138 {
00139 pimpl->addDriverName(driver_name);
00140 }
00141
00142
00143 #ifdef WINDOWS_OS
00144
00145 size_t FindComPorts::find(std::vector<std::string>& ports,
00146 std::vector<std::string>& driver_names,
00147 bool all_ports)
00148 {
00149
00150 deque<string> found_ports;
00151 deque<string> found_drivers;
00152
00153
00154 GUID GUID_DEVINTERFACE_COM_DEVICE =
00155 {0x4D36E978L, 0xE325, 0x11CE,
00156 {0xBF, 0xC1, 0x08, 0x00, 0x2B, 0xE1, 0x03, 0x18 }
00157 };
00158
00159 HDEVINFO hdi = SetupDiGetClassDevs(&GUID_DEVINTERFACE_COM_DEVICE, 0, 0,
00160 DIGCF_PRESENT | DIGCF_INTERFACEDEVICE);
00161 if (hdi == INVALID_HANDLE_VALUE) {
00162 return 0;
00163 }
00164
00165 SP_DEVINFO_DATA sDevInfo;
00166 sDevInfo.cbSize = sizeof(SP_DEVINFO_DATA);
00167 for (DWORD i = 0; SetupDiEnumDeviceInfo(hdi, i, &sDevInfo); ++i){
00168
00169 enum { BufferSize = 256 };
00170 char buffer[BufferSize + 1];
00171 DWORD dwRegType;
00172 DWORD dwSize;
00173
00174
00175 SetupDiGetDeviceRegistryPropertyA(hdi, &sDevInfo, SPDRP_FRIENDLYNAME,
00176 &dwRegType, (BYTE*)buffer, BufferSize,
00177 &dwSize);
00178 enum { ComNameLengthMax = 7 };
00179 size_t n = strlen(buffer);
00180 if (n < ComNameLengthMax) {
00181
00182
00183 continue;
00184 }
00185
00186
00187 for (int j = n - 1; j > 0; --j) {
00188 if (buffer[j] == ')') {
00189 buffer[j] = '\0';
00190 break;
00191 }
00192 }
00193 char* p = strstr(&buffer[n - ComNameLengthMax], "COM");
00194 if (! p) {
00195 continue;
00196 }
00197 found_ports.push_back(p);
00198
00199
00200 SetupDiGetDeviceRegistryPropertyA(hdi, &sDevInfo, SPDRP_DEVICEDESC,
00201 &dwRegType, (BYTE*)buffer, BufferSize,
00202 &dwSize);
00203 found_drivers.push_back(buffer);
00204 pimpl->orderByDriver(found_ports, found_drivers, buffer, all_ports);
00205 }
00206 SetupDiDestroyDeviceInfoList(hdi);
00207
00208 ports.insert(ports.end(), found_ports.begin(), found_ports.end());
00209 driver_names.insert(driver_names.end(),
00210 found_drivers.begin(), found_drivers.end());
00211
00212 return ports.size();
00213 }
00214
00215
00216 #else
00217
00218 namespace
00219 {
00220 void searchFiles(vector<string>& ports, const string& dir_name)
00221 {
00222 DIR* dp = opendir(dir_name.c_str());
00223 if (! dp) {
00224 return;
00225 }
00226
00227 struct dirent* dir;
00228 while ((dir = readdir(dp))) {
00229 struct stat state;
00230 stat(dir->d_name, &state);
00231 if (S_ISDIR(state.st_mode)) {
00232 string file = dir_name + dir->d_name;
00233 ports.push_back(file);
00234 }
00235 }
00236 }
00237 }
00238
00239
00240
00241 size_t FindComPorts::find(std::vector<std::string>& ports,
00242 std::vector<std::string>& driver_names,
00243 bool all_ports)
00244 {
00245 static_cast<void>(all_ports);
00246 static_cast<void>(driver_names);
00247
00248 vector<string> found_ports;
00249
00250
00251 for (vector<string>::iterator it = pimpl->base_names_.begin();
00252 it != pimpl->base_names_.end(); ++it) {
00253
00254
00255 const char* path = it->c_str();
00256 const char* last_slash = strrchr(path, '/') + 1;
00257
00258 string dir_name = it->substr(0, last_slash - path);
00259 vector<string> ports;
00260 searchFiles(ports, dir_name);
00261
00262 size_t n = it->size();
00263 for (vector<string>::iterator fit = ports.begin();
00264 fit != ports.end(); ++fit) {
00265 if (! fit->compare(0, n, *it)) {
00266
00267 pimpl->addFoundPorts(found_ports, *fit);
00268 }
00269 }
00270 }
00271
00272 for (vector<string>::iterator it = found_ports.begin();
00273 it != found_ports.end(); ++it) {
00274 ports.push_back(*it);
00275 driver_names.push_back("");
00276 }
00277
00278 return found_ports.size();
00279 }
00280 #endif
00281
00282
00283 size_t FindComPorts::find(vector<string>& ports, bool all_ports)
00284 {
00285 vector<string> driver_names_dummy;
00286 return find(ports, driver_names_dummy, all_ports);
00287 }