cpp-ru/ideas

Получение списка доступных последовательных портов (Boost.Asio)

ksrp1984 opened this issue · 10 comments

<Описание вашей идеи>
Метод получения доступных последовательных портов в системе
<Примеры, где ваша идея будет полезна. Чем больше примеров и чем большую аудиторию они охватывают - тем лучше>
Будет полезно в любом приложение работающее с COM портами
<Код c реализацией вашей идеи, если есть>
В качестве референса можно использовать реализацию в QT: "QList QSerialPortInfo::availablePorts()"(qserialportinfo_unix.cpp, qserialportinfo_win.cpp)

Полезные ссылки:

Чтоб далеко не бегать:

int enum_comports( void (*handler)(void* ctx, const char* name, const char* desc), void *ctx );

#ifdef WIN32

#include <windows.h>

int enum_comports( void (*handler)(void* ctx, const char* name,const char* desc), void *ctx ) {
	const char* path1="HARDWARE\\DEVICEMAP\\SERIALCOMM";
	LSTATUS st; DWORD nvalues=0; HKEY key=0;

	st=RegOpenKeyExA(HKEY_LOCAL_MACHINE,path1,0,KEY_READ,&key);
	if (st) {
		// fprintf(stderr,"no com ports. unable to open %s\n",path1);
		return 1;
	}
	st=RegQueryInfoKeyA(key,0,0,0,0,0,0,&nvalues,0,0,0,0);
	if (st) {
		// fprintf(stderr,"unable to get values count\n");
		nvalues=256;
	}
	for(int i=0;i<(int)nvalues;i++) {
		enum { name_max=256, value_max=256 };
		char name[name_max], value[value_max];
		DWORD name_len=name_max, value_len=value_max, val_type=0;
		name[0]=0; value[0]=0;
		st=RegEnumValueA(key,i,name,&name_len,0,&val_type,(LPBYTE)value,&value_len);
		if (st) {
			if (st==ERROR_NO_MORE_ITEMS) break;
			// fprintf(stderr,"error enum values %d\n",st);
			break;
		}
		if (val_type==REG_SZ ||
			val_type==REG_EXPAND_SZ ||
			val_type==REG_MULTI_SZ) {
				const char* desc=name;
				const char* prefix="\\Device\\";
				int i=0; while(prefix[i] && *desc==prefix[i]) { i++; desc++; }
				handler(ctx,value,desc);
		} else {
			// fprintf(stderr,"unexpected value type %d\n",val_type);
		}
	}
	RegCloseKey(key);
	return 0;
}

#else // linux

#include <stdio.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <termios.h>
#include <sys/ioctl.h>

#include <string.h>
#include <dirent.h>
#include <sys/stat.h>
#include <linux/serial.h>
#include <string>
using std::string;

static string comport_get_driver(const string& dir) {
	struct stat st;
	string devicedir = dir;

	devicedir += "/device";
	if (lstat(devicedir.c_str(), &st)==0 && S_ISLNK(st.st_mode)) {
		enum { buffer_max=1024 }; char buffer[buffer_max];
		memset(buffer, 0, sizeof(buffer));
		devicedir += "/driver";
		if (readlink(devicedir.c_str(), buffer, sizeof(buffer)) > 0) {
			return basename(buffer);
		}
	}
	return "";
}

static int comport_probe(const char *name) {
	struct serial_struct serinfo;
	int rc=1;
	int fd=open(name, O_RDWR | O_NONBLOCK | O_NOCTTY);
	if (fd>=0) {
		if (ioctl(fd, TIOCGSERIAL, &serinfo)==0) {
			if (serinfo.type!=PORT_UNKNOWN) rc=0;
		}
		close(fd);
	}
	return rc;
}

int enum_comports( void (*handler)(void* ctx, const char* name,const char* desc), void *ctx ) {
	int n; struct dirent **namelist;
	const char* sysdir = "/sys/class/tty/";

	n = scandir(sysdir, &namelist, NULL, NULL);
	if (n<0) perror("scandir");
	else {
		while (n--) {
			if (strcmp(namelist[n]->d_name,"..") && strcmp(namelist[n]->d_name,".")) {
				string devicedir = sysdir;
				devicedir += namelist[n]->d_name;
				string driver = comport_get_driver(devicedir.c_str());
				if (driver.size() > 0) {
					string devfile = string("/dev/") + basename(devicedir.c_str());
					bool invalid=0;
					if (driver == "serial8250") {
						invalid=comport_probe(devfile.c_str());
					}
					if (!invalid) handler(ctx,devfile.c_str(),driver.c_str());
				}
			}
			free(namelist[n]);
		}
		free(namelist);
	}
	return 1;
}

#endif

А много ли приложений пользуется COM портами? Звучит слишком ОС-зависимо и тем более у нас нет понятия устройств и прочего, в какую библиотеку это войдёт?

В промышленности последовательные порты повсеместно используются. Логичнее всего чтобы вошло в boost asio, т.к. в стандартной библиотеке ничего подобного нет. В boost же работа с последовательными портами реализована, а вот функции для получения доступных портов нет. По поводу "ОС-зависимо" - в Qt же реализовали, недавно собрал на Ubuntu одно свое приложение, которое изначально разрабатывалось под Windows, проблем не обнаружил, без каких либо изменений в коде приложение собралось и работало на Linux, список всех портов отображался корректно. Понятно что внутри в Qt код разный под разные платформы, но пользователь библиотеки об этом знать не должен.

Не знал, что сюда и для буста идеи можно кидать

Если подскажите можно куда перенести

Зачем это в стандарте? Это функции операционной системы. Какие COM порты скажем в Rabsbery Pi ? Получится что нет портов - зничит и нельзя раработать полностьтю удовлятеворяющую стандарту стандартную библиотеку.

Rasbery PI обычные последовательные порты, даже в arduino они есть.

Зачем это в стандарте? Это функции операционной системы. Какие COM порты скажем в Rabsbery Pi ? Получится что нет портов - зничит и нельзя раработать полностьтю удовлятеворяющую стандарту стандартную библиотеку.
А какие потоки, исключения, динамическая память на 8 битном МК (а вот последовательные порты даже там есть)? По этой логике много чего в стандарте лишнее. И речь все же не про стандартную библиотеку, а про boost в котором уже реализована работа с последовательными портами.

Не знал, что сюда и для буста идеи можно кидать

Вроде бы планируется в C++ добавить Networking, не знаю подразумевает ли он работу с последовательными портами, но логично было бы что ДА.

Зачем это в стандарте? Это функции операционной системы. Какие COM порты скажем в Rabsbery Pi ? Получится что нет портов - зничит и нельзя раработать полностьтю удовлятеворяющую стандарту стандартную библиотеку.

Для популярных ОС можно полноценно реализовать этот функционал. Для систем без ОС можно просто оставить стандартный интерфейс который должен реализовать пользователь.
Rabsbery Pi вродебы на Linux работает? Какие там могут быть проблемы?