ideas icon indicating copy to clipboard operation
ideas copied to clipboard

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

Open ksrp1984 opened this issue 1 year ago • 10 comments

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

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

  • https://www.qt.io/download-open-source - исходники QT

ksrp1984 avatar Jul 01 '23 18:07 ksrp1984

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

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

kov-serg avatar Jul 01 '23 19:07 kov-serg

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

GitSparTV avatar Jul 01 '23 20:07 GitSparTV

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

ksrp1984 avatar Jul 02 '23 06:07 ksrp1984

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

GitSparTV avatar Jul 02 '23 08:07 GitSparTV

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

ksrp1984 avatar Jul 03 '23 04:07 ksrp1984

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

incoder1 avatar Jul 08 '23 13:07 incoder1

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

kov-serg avatar Jul 08 '23 15:07 kov-serg

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

ksrp1984 avatar Jul 08 '23 18:07 ksrp1984

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

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

ksrp1984 avatar Nov 25 '23 14:11 ksrp1984

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

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

ksrp1984 avatar Nov 25 '23 14:11 ksrp1984