108{
109 std::vector<SerialPortInfo> output;
110
111#ifdef _WIN32
112 SP_DEVINFO_DATA devInfoData = { 0 };
113 devInfoData.cbSize = sizeof(devInfoData);
114
115 HDEVINFO hDeviceInfo = SetupDiGetClassDevs(&GUID_DEVCLASS_PORTS, 0, nullptr, DIGCF_PRESENT);
116 if (hDeviceInfo != INVALID_HANDLE_VALUE) {
117
118 for (int nDevice = 0; SetupDiEnumDeviceInfo(hDeviceInfo, nDevice, &devInfoData); ++ nDevice) {
120
121 HKEY hDeviceKey = SetupDiOpenDevRegKey(hDeviceInfo, &devInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_QUERY_VALUE);
122 if (hDeviceKey) {
123
124 wchar_t pszPortName[4096];
125 DWORD dwSize = sizeof(pszPortName);
126 DWORD dwType = 0;
127 if (RegQueryValueEx(hDeviceKey,
L"PortName", NULL, &dwType, (LPBYTE)pszPortName, &dwSize) == ERROR_SUCCESS)
129 RegCloseKey(hDeviceKey);
130 if (port_info.
port.empty())
131 continue;
132 }
133
134
135 DWORD regDataType;
136 DWORD reqSize = 0;
137 SetupDiGetDeviceRegistryProperty(hDeviceInfo, &devInfoData, SPDRP_HARDWAREID, nullptr, nullptr, 0, &reqSize);
138 std::vector<wchar_t> hardware_id(reqSize > 1 ? reqSize : 1);
139
140 if (! SetupDiGetDeviceRegistryProperty(hDeviceInfo, &devInfoData, SPDRP_HARDWAREID, ®DataType, (BYTE*)hardware_id.data(), reqSize, nullptr))
141 continue;
143
144
145 reqSize = 0;
146 SetupDiGetDeviceRegistryProperty(hDeviceInfo, &devInfoData, SPDRP_FRIENDLYNAME, nullptr, nullptr, 0, &reqSize);
147 std::vector<wchar_t> friendly_name;
148 friendly_name.reserve(reqSize > 1 ? reqSize : 1);
149
150 if (! SetupDiGetDeviceRegistryProperty(hDeviceInfo, &devInfoData, SPDRP_FRIENDLYNAME, nullptr, (BYTE*)friendly_name.data(), reqSize, nullptr)) {
152 } else {
155 }
156 output.emplace_back(std::move(port_info));
157 }
158 }
159#elif __APPLE__
160
161 CFMutableDictionaryRef classes = IOServiceMatching(kIOSerialBSDServiceValue);
162 if (classes != 0) {
163 io_iterator_t iter;
164 if (IOServiceGetMatchingServices(kIOMasterPortDefault, classes, &iter) == KERN_SUCCESS) {
165 io_object_t port;
166 while ((port = IOIteratorNext(iter)) != 0) {
167 CFTypeRef cf_property = IORegistryEntryCreateCFProperty(port, CFSTR(kIOCalloutDeviceKey), kCFAllocatorDefault, 0);
168 if (cf_property) {
170 Boolean result = CFStringGetCString((CFStringRef)cf_property, path, sizeof(path), kCFStringEncodingUTF8);
171 CFRelease(cf_property);
172 if (result) {
173 SerialPortInfo port_info;
174 port_info.
port = path;
175
176
177 if ((cf_property = IORegistryEntrySearchCFProperty(port, kIOServicePlane,
178 CFSTR("USB Interface Name"), kCFAllocatorDefault,
179 kIORegistryIterateRecursively | kIORegistryIterateParents)) ||
180 (cf_property = IORegistryEntrySearchCFProperty(port, kIOServicePlane,
181 CFSTR("USB Product Name"), kCFAllocatorDefault,
182 kIORegistryIterateRecursively | kIORegistryIterateParents)) ||
183 (cf_property = IORegistryEntrySearchCFProperty(port, kIOServicePlane,
184 CFSTR("Product Name"), kCFAllocatorDefault,
185 kIORegistryIterateRecursively | kIORegistryIterateParents)) ||
186 (cf_property = IORegistryEntryCreateCFProperty(port,
187 CFSTR(kIOTTYDeviceKey), kCFAllocatorDefault, 0))) {
188
189 char description[128];
190 if (CFStringGetCString((CFStringRef)cf_property, description, sizeof(description), kCFStringEncodingUTF8)) {
191 port_info.friendly_name = std::string(description) + " (" + port_info.port + ")";
193 }
194 CFRelease(cf_property);
195 }
196 if (port_info.friendly_name.empty())
197 port_info.friendly_name = port_info.port;
198
199
200 int vid, pid;
201 auto cf_vendor = IORegistryEntrySearchCFProperty(port, kIOServicePlane, CFSTR("idVendor"),
202 kCFAllocatorDefault, kIORegistryIterateRecursively | kIORegistryIterateParents);
203 auto cf_product = IORegistryEntrySearchCFProperty(port, kIOServicePlane, CFSTR("idProduct"),
204 kCFAllocatorDefault, kIORegistryIterateRecursively | kIORegistryIterateParents);
205 if (cf_vendor && cf_product) {
206 if (CFNumberGetValue((CFNumberRef)cf_vendor, kCFNumberIntType, &vid) &&
207 CFNumberGetValue((CFNumberRef)cf_product, kCFNumberIntType, &pid)) {
208 port_info.id_vendor = vid;
209 port_info.id_product = pid;
210 }
211 }
212 if (cf_vendor) { CFRelease(cf_vendor); }
213 if (cf_product) { CFRelease(cf_product); }
214
215 output.emplace_back(std::move(port_info));
216 }
217 }
218 IOObjectRelease(port);
219 }
220 }
221 }
222#else
223
224 std::initializer_list<const char*> prefixes { "ttyUSB" , "ttyACM", "tty.", "cu.", "rfcomm" };
225 for (
auto &dir_entry :
boost::filesystem::directory_iterator(
boost::filesystem::path(
"/dev"))) {
226 std::string name = dir_entry.path().filename().string();
227 for (const char *prefix : prefixes) {
228 if (boost::starts_with(name, prefix)) {
229 const auto path = dir_entry.path().string();
230 SerialPortInfo spi;
231 spi.port = path;
232#ifdef __linux__
233 auto friendly_name = sysfs_tty_prop(name, "product");
234 if (friendly_name) {
236 spi.friendly_name = (boost::format("%1% (%2%)") % *friendly_name % path).str();
237 } else {
238 spi.friendly_name = path;
239 }
240 auto vid = sysfs_tty_prop_hex(name, "idVendor");
241 auto pid = sysfs_tty_prop_hex(name, "idProduct");
242 if (vid && pid) {
243 spi.id_vendor = *vid;
244 spi.id_product = *pid;
245 }
246#else
247 spi.friendly_name = path;
248#endif
249 output.emplace_back(std::move(spi));
250 break;
251 }
252 }
253 }
254#endif
255
256 output.erase(std::remove_if(output.begin(), output.end(),
257 [](const SerialPortInfo &info) {
258 return boost::starts_with(info.port, "Bluetooth") || boost::starts_with(info.port, "FireFly");
259 }),
260 output.end());
261 return output;
262}
#define PATH_MAX
Definition libavrdude.h:51
static bool looks_like_printer(const std::string &friendly_name)
Definition Serial.cpp:65
char * narrow(char *output, size_t output_size, wchar_t const *source)
Convert NULL terminated UTF source string to NULL terminated output string of size at most output_siz...
Definition convert.hpp:73
#define L(s)
Definition I18N.hpp:18
std::string friendly_name
Definition Serial.hpp:17