DVB/SDR переключение драйвера

#1
Не хватает возможности автоматического переключения драйвера в режим DVB (из SDR). Для астрометы и подобных SDR-совместимых тюнеров.
Как бы это приделать к ProgDVB?
Чтобы при запуске ProgDVB - был какой-то плагин, проверяющий состояние драйвера и далее запускающий переключение режима в DVB при необходимости (или выдающий какой-то флаг отказа дальнейшего запуска ProgDVB если драйвер в режиме SDR).

Есть конечно радикальное решение - написать лоадер для ProgDVB…

Re: DVB/SDR переключение драйвера

#3
Prog wrote:
Mon Oct 03, 2022 10:51 am
А внутри bda.device, как сейчас для астрометы - уже поздно переключать?
Поздно.
Дело в том что в режиме SDR - вообще другой драйвер, и нет никакого BDA устройства.

Детект текущего режима делается сканированием SetupDi…(), поиском там VEN_ID/DEV_ID тюнера и проверкой установленного для устройства драйвера (SetupDiGetDeviceProperty DEVPKEY_Device_Children DEVPKEY_Device_DeviceDesc DEVPKEY_Device_Service). Это для Vista+. Для WinXP всё сложнее (CM_Get_Child CM_Get_Device_ID CM_Get_Sibling). Тюнер - композитное USB-устройство…

Если драйвер не подходящий - то для его переключения надо найти в системе все подходящие драйвера (SetupDiEnumDriverInfo) и переустановить нужный (DiInstallDevice). Причём нужно повышение привилегий и отдельные сборки для 64 и 32 бит (DiInstallDevice не работает в среде wow64, там надо запускать 64 битную версию программы).

Надо какой-то внешний модуль делать. Который бы вызывался при запуске ProgDVB. И проверял бы состояние.
И логику действий разную предусмотреть.
1. если тюнер в режиме DVB - продолжается нормальный запуск
2. если тюнер в режиме SDR и запуск был вручную - создать/выгрузить и запустить внешнюю (через UAC) программу для переключения.
3. если попытка переключения в DVB не удалась - тоже ошибка и отмена запуска.
4. если тюнер в режиме SDR и запуск был автоматический (подтвердить UAC некому) - то отмена запуска, ошибка.

Re: DVB/SDR переключение драйвера

#5
Prog wrote:
Mon Oct 03, 2022 11:47 am
Но этот sdr будет один для всех(разных) устройств? Или его в ebda для каждого устройства нужно
В идеале конечно для каждого устройства отдельно.
Но я думаю что это врядли кому-то надо - те у кого одновременно несколько тюнеров стоят - занимаются какой-то профессиональной деятельностью и переключение DVB/SDR им не нужно.
Поэтому API для переключения может быть вообще без привязки к конкретному тюнеру.

А как привязывать к конкретному тюнеру - я не очень представляю. Поскольку это надо делать на уровне физического устройства (когда например драйвера может совсем не быть некоторое время), а не после драйвера. Разве что по пути InstanceID к устройству. Но перевтыкание в другой порт - и путь другой.

Re: DVB/SDR переключение драйвера

#8
Prog wrote:
Mon Oct 03, 2022 12:21 pm
А от ProgDVB какие то параметры нужны?
Ну, наверно hWnd окна (относительного которого выводить MessageBox с ошибкой например).
И коды возврата, влияющие на дальнейшую работу ProgDVB - продолжать запуск, прекратить запуск.

Например:
// Проверка состояния тюнера,
// возвращает 1 если OK (тюнер в режиме DVB), 0 если тюнер в SDR-режиме, -1 если что-то не понятное (тюнера нет, не идентифицирован режим и т.п.).
INT IsDVBmode(HWND)

// Переключение тюнера в режим DVB. Вызывается только если (0 == IsDVBmode), при 1 или -1 - не вызывается.
// Возвращает 1 если переключение успешно, 0 если переключения не было, -1 ну тоже какая-то нештатная проблема с переключением и переключения не было.
INT SwitchToDVB(HWND)


Prog wrote:
Mon Oct 03, 2022 1:06 pm
Что бы была площадка для эксперементов, могу при первом старта BDA предварительно просто загружатать например sdr.dll. Или sdr.ebda, что бы передавать какие то базовые параметры.
А стартует ли BDA если твтюнера в системе вообще нет?

Re: DVB/SDR переключение драйвера

#11
Prog wrote:
Mon Oct 03, 2022 11:47 am
Но этот sdr будет один для всех(разных) устройств? Или его в ebda для каждого устройства нужно
Я вот подумал… Очевидно что не так много тюнеров переключаемых в SDR режим, и для каждого переключаемого тюнера видимо свой алгоритм. Наверно надо в рамках доп.API это делать, например вот если выбрано дополнительное API - астромета…

Например получив ошибку «[bda.a3fb] Device not started!» не выводить её, а сделать проверку на SDR и далее по итогам (если тюнер в режиме SDR) - выводить окно типа «Тюнер в режиме SDR. Выполнить переключение в режим DVB?» Переключить/Игнорировать/Выход.

Или просто «Тюнер в режиме SDR.» Игнорировать/Выход.

Re: DVB/SDR переключение драйвера

#12
Вот можно например для начала просто усовершенствовать обработку ошибок, если не удалось запустить BDA и при этом было API астрометы для него.
Тогда делать проверку IsDVBmodeAstrometa131() и выводить подсказку про SDR если обнаружен режим SDR…

Важно что подсказка должна быть если обнаружен SDR, а не если не обнаружен DVB
Астромета есть ещё 135, но там нет SDR режима, поэтому для неё никакой доп.проверки нет.
Т.е. считать что тюнер в режиме SDR можно только по явному обнаружению SDR, а не методом исключения.

Code: Select all

BOOL sub_device(HDEVINFO hSubDevInfo, wchar_t* id, LPWSTR tDeviceDesc, LPWSTR tService, LPWSTR tDriverVersion)
{
	SP_DEVINFO_DATA DeviceInfoData;
	WCHAR Buff_InstanceId[MAX_PATH] = L"";
	DEVPROPTYPE dpt = 0;

	for (UINT index = 0; ; index++) {
		DeviceInfoData.cbSize = sizeof(DeviceInfoData);
		if (!SetupDiEnumDeviceInfo(hSubDevInfo, index, &DeviceInfoData))
		{
			return FALSE;
		}
		if (!SetupDiGetDevicePropertyW(hSubDevInfo, &DeviceInfoData, &DEVPKEY_Device_InstanceId, &dpt, (PBYTE)Buff_InstanceId, sizeof(Buff_InstanceId), NULL, 0))
		{
			continue;
		}

		if (StrCmpIW(Buff_InstanceId, id) == 0)
		{
			tDeviceDesc[0] = 0;
			tService[0] = 0;
			tDriverVersion[0] = 0;
			SetupDiGetDevicePropertyW(hSubDevInfo, &DeviceInfoData, &DEVPKEY_Device_DeviceDesc, &dpt, (PBYTE)tDeviceDesc, 100*2, NULL, 0);
			SetupDiGetDevicePropertyW(hSubDevInfo, &DeviceInfoData, &DEVPKEY_Device_Service, &dpt, (PBYTE)tService, 100*2, NULL, 0);
			SetupDiGetDevicePropertyW(hSubDevInfo, &DeviceInfoData, &DEVPKEY_Device_DriverVersion, &dpt, (PBYTE)tDriverVersion, 50*2, NULL, 0);

			return TRUE;
		}
	}
	return FALSE;
}

// -1 = тюнер не опознан, или может это астромета-135 (а не 131)
// 0 = тюнер в режиме SDR, надо вывести предупреждение пользователю типа «BDA устройство не запущено потому что тюнер в режиме SDR»
// 1 = тюнер в режиме DVB
INT IsDVBmodeAstrometa131()
{
	WCHAR text_tuner0131_DeviceDesc[100] = { 0 };
	WCHAR text_tuner0131_Service[100] = { 0 };
	WCHAR text_tuner0131_DriverVersion[50] = { 0 };
	INT result = -1;
	HDEVINFO hDevInfo;
	SP_DEVICE_INTERFACE_DATA DeviceInterfaceData;
	BYTE DeviceInterfaceDetailDataB[MAX_PATH * 2 + 100];
	SP_DEVICE_INTERFACE_DETAIL_DATA* DeviceInterfaceDetailData = reinterpret_cast<SP_DEVICE_INTERFACE_DETAIL_DATA*>(DeviceInterfaceDetailDataB);
	DEVPROPTYPE dpt = 0;
	WCHAR ChildrenListBuffer[1000];
	SP_DEVINFO_DATA DeviceInfo;
	HDEVINFO hSubDevInfo;

	hDevInfo = SetupDiGetClassDevsW(&(GUID_DEVINTERFACE_USB_DEVICE), 0, 0, DIGCF_DEVICEINTERFACE | DIGCF_ALLCLASSES); // корневые (композитные/составные) устройства
	if (hDevInfo != INVALID_HANDLE_VALUE)
	{
		hSubDevInfo = SetupDiGetClassDevsW(&(GUID_DEVINTERFACE_USB_DEVICE), L"USB", NULL, DIGCF_ALLCLASSES); // все устройства включая дочерние устройства
		if (hSubDevInfo != INVALID_HANDLE_VALUE)
		{
			for (UINT index = 0; ; index++)
			{
				DeviceInterfaceData.cbSize = sizeof(DeviceInterfaceData);
				if (!SetupDiEnumDeviceInterfaces(hDevInfo, 0, &(GUID_CLASS_USB_DEVICE), index, &DeviceInterfaceData))
				{
					break;
				}

				DeviceInterfaceDetailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
				DeviceInterfaceDetailData->DevicePath[0] = 0;
				DeviceInfo.cbSize = sizeof(DeviceInfo);
				if (SetupDiGetDeviceInterfaceDetailW(hDevInfo, &DeviceInterfaceData, DeviceInterfaceDetailData, sizeof(DeviceInterfaceDetailDataB), 0, &DeviceInfo))
				{
					if (StrCmpNIW(DeviceInterfaceDetailData->DevicePath, L"\\\\?\\usb#vid_15f4&pid_0131#", 26) == 0)
					{
						ChildrenListBuffer[0] = 0;
						ChildrenListBuffer[1] = 0;
						if (SetupDiGetDevicePropertyW(hDevInfo, &DeviceInfo, &DEVPKEY_Device_Children, &dpt, (PBYTE)ChildrenListBuffer, sizeof(ChildrenListBuffer), NULL, 0))
						{
							flag_tuner0131_present = 1;
							wchar_t* p = ChildrenListBuffer;
							while (true) {
								if (p[0] == 0) break;
								if (StrCmpNIW(p, L"USB\\VID_15F4&PID_0131&MI_00\\", 28) == 0)
								{
									if (sub_device(hSubDevInfo, p, text_tuner0131_DeviceDesc, text_tuner0131_Service, text_tuner0131_DriverVersion))
									{
										if (StrCmpIW(text_tuner0131_Service, L"AMDVBT2USB") == 0)
										{
											result = 1;
										}
										else if (StrCmpIW(text_tuner0131_Service, L"WinUSB") == 0)
										{
											result = 0;
										}
										else
										{
											result = -1;
										}
									}
								}
								p += lstrlenW(p) + 1;
							}
						}
					}
				}
			}
			SetupDiDestroyDeviceInfoList(hSubDevInfo);
		}
		SetupDiDestroyDeviceInfoList(hDevInfo);
	}
	return result;
}

Re: DVB/SDR переключение драйвера

#14
Prog wrote:
Mon Oct 03, 2022 8:47 pm
Ведь SDR к ProgDVB не имеет отношения?
Да.
Prog wrote:
Mon Oct 03, 2022 8:47 pm
Нужно только опредить режим? Или есть какая то польза?
Да. Чтобы не запускать впустую ProgDVB, если тюнер в режиме SDR. И чтобы было понятнее почему ошибка Device not started! - то ли тюнер вывалился физически, то ли его забыли в SDR.

В идеале бы ещё и переключение режима сделать, но это требует запуска через UAC и админские права…

Для SDR - куча разных софтовых радиоприёмников. Причём не только для любителей слушать рации, а и например обычное FM-радио в ассортименте под SDR написано. Даже стереозвук декодируют и RDS тексты принимают.
Штатная астрометовская утилита для FM-радио - весьма тормозная и глючная.
А сторонний софт под WDM-устройства с радио практически не существует, более-менее разве что в capture-режиме в VirtualDub можно добраться до FM-радио.
И получается что SDR режим нужен даже чтобы просто FM-радио послушать на астромете.