From f2b682a952ad3e08ce8b38cb09be6345bf0d5d62 Mon Sep 17 00:00:00 2001 From: Oscar Steila Date: Thu, 4 Nov 2021 15:40:33 +0100 Subject: [PATCH] two devices manual selection (#210) * in the USBdescriptor of FX3 the serial number has been added ( thanks to Franco ideas and code ) * Ver 1.3.0 RC1 FW 2.02 ExtIO_sddc enumerates all the Cypress FX3 connected devices. A dialogBox ask to select one of many if required. --- Core/FX3Class.h | 2 +- Core/arch/linux/FX3handler.cpp | 5 ++ Core/arch/linux/FX3handler.h | 1 + Core/arch/win32/FX3handler.cpp | 131 +++++++++--------------------- Core/arch/win32/FX3handler.h | 5 +- Core/config.h | 6 +- ExtIO_sddc/ExtIO_sddc.cpp | 25 +++++- ExtIO_sddc/resource.h | 2 + ExtIO_sddc/resource.rc | 15 ++++ ExtIO_sddc/tdialog.cpp | 63 +++++++++++++++ ExtIO_sddc/tdialog.h | 7 ++ Interface.h | 2 +- SDDC_FX3.img | Bin 145388 -> 146188 bytes SDDC_FX3/RunApplication.c | 4 +- SDDC_FX3/USBdescriptor.c | 141 ++++++++++++++++++++++++++------- SDDC_FX3/USBhandler.c | 6 +- unittest/core_test.cpp | 5 ++ 17 files changed, 286 insertions(+), 134 deletions(-) diff --git a/Core/FX3Class.h b/Core/FX3Class.h index 9cb9622b..4cd9df72 100644 --- a/Core/FX3Class.h +++ b/Core/FX3Class.h @@ -29,7 +29,7 @@ class fx3class virtual bool ReadDebugTrace(uint8_t* pdata, uint8_t len) = 0; virtual void StartStream(ringbuffer& input, int numofblock) = 0; virtual void StopStream() = 0; - + virtual bool Enumerate(unsigned char& idx, char* lbuf, uint8_t* fw_data, uint32_t fw_size) = 0; }; extern "C" fx3class* CreateUsbHandler(); diff --git a/Core/arch/linux/FX3handler.cpp b/Core/arch/linux/FX3handler.cpp index 8d4a94bd..ca40e5ce 100644 --- a/Core/arch/linux/FX3handler.cpp +++ b/Core/arch/linux/FX3handler.cpp @@ -93,3 +93,8 @@ bool fx3handler::ReadDebugTrace(uint8_t* pdata, uint8_t len) { return true; } + +bool fx3handler::Enumerate(unsigned char &idx, char *lbuf, uint8_t* fw_data, uint32_t fw_size) +{ + return true; // TBD +} diff --git a/Core/arch/linux/FX3handler.h b/Core/arch/linux/FX3handler.h index 104b1051..73d77a2c 100644 --- a/Core/arch/linux/FX3handler.h +++ b/Core/arch/linux/FX3handler.h @@ -26,6 +26,7 @@ class fx3handler : public fx3class bool ReadDebugTrace(uint8_t* pdata, uint8_t len); void StartStream(ringbuffer& input, int numofblock); void StopStream(); + bool Enumerate(unsigned char &idx, char *lbuf, uint8_t* fw_data, uint32_t fw_size); private: bool ReadUsb(uint8_t command, uint16_t value, uint16_t index, uint8_t *data, size_t size); diff --git a/Core/arch/win32/FX3handler.cpp b/Core/arch/win32/FX3handler.cpp index 8e72d497..437966da 100644 --- a/Core/arch/win32/FX3handler.cpp +++ b/Core/arch/win32/FX3handler.cpp @@ -21,7 +21,8 @@ fx3class* CreateUsbHandler() fx3handler::fx3handler(): fx3dev (nullptr), - Fx3IsOn (false) + Fx3IsOn (false), + devidx (0) { } @@ -33,111 +34,57 @@ fx3handler::~fx3handler() // reset USB device and exit Close(); } -bool fx3handler::GetFx3Device() { - bool r = false; - if (fx3dev == nullptr) return r; // no device - int n = fx3dev->DeviceCount(); - if (n == 0) return r; // no one - - // Walk through all devices looking for VENDOR_ID/STREAMER_ID - for (int i = 0; i <= n; i++) { - fx3dev->Open(i); // go down the list of devices to find our device - if ((fx3dev->VendorID == VENDOR_ID) && (fx3dev->ProductID == STREAMER_ID)) - { - r = true; - break; - } +char* wchar2char(const wchar_t* wchar) +{ + char* m_char; + int len = WideCharToMultiByte(CP_ACP, 0, wchar, wcslen(wchar), NULL, 0, NULL, NULL); + m_char = new char[len + 1]; + WideCharToMultiByte(CP_ACP, 0, wchar, wcslen(wchar), m_char, len, NULL, NULL); + m_char[len] = '\0'; + return m_char; +} - if ((fx3dev->VendorID == VENDOR_ID) && (fx3dev->ProductID == BOOTLOADER_ID)) - { - r = true; - break; - } - } +bool fx3handler::GetFx3DeviceStreamer() { // open class + bool r = false; + if (fx3dev == NULL) return r; + fx3dev->Open(devidx); + if ((fx3dev->VendorID == VENDOR_ID) && (fx3dev->ProductID == STREAMER_ID)) r = true; if (r == false) fx3dev->Close(); return r; } -bool fx3handler::GetFx3DeviceStreamer(void) { // open class +bool fx3handler::Enumerate(unsigned char& idx, char* lbuf, uint8_t* fw_data, uint32_t fw_size) +{ bool r = false; - if (fx3dev == NULL) return r; - int n = fx3dev->DeviceCount(); - // Walk through all devices looking for VENDOR_ID/STREAMER_ID - if (n == 0) return r; - // go down the list of devices to find STREAMER_ID device - for (int i = 0; i <= n; i++) { - fx3dev->Open(i); - if ((fx3dev->VendorID == VENDOR_ID) && (fx3dev->ProductID == STREAMER_ID)) - { - r = true; - break; + strcpy(lbuf, ""); + if (fx3dev == nullptr) + fx3dev = new CCyFX3Device; // instantiate the device + if (fx3dev == nullptr) return r; // return if failed + if (!fx3dev->Open(idx)) return r; + if (fx3dev->IsBootLoaderRunning()) { + if (fx3dev->DownloadFwToRam(fw_data, fw_size) != SUCCESS) { + DbgPrintf("Failed to DownloadFwToRam device(%x)\n", idx); + } + else { + fx3dev->Close(); + Sleep(800); // wait after firmware change ? + fx3dev->Open(idx); } } - if (r == false) - fx3dev->Close(); - return r; + strcpy (lbuf, fx3dev->DeviceName); + while (strlen(lbuf) < 18) strcat(lbuf, " "); + strcat(lbuf, "sn:"); + strcat(lbuf, wchar2char((wchar_t*)fx3dev->SerialNumber)); + fx3dev->Close(); + devidx = idx; // -> devidx + return true; } bool fx3handler::Open(uint8_t* fw_data, uint32_t fw_size) { bool r = false; - fx3dev = new CCyFX3Device; // instantiate the device - if (fx3dev == nullptr) return r; // return if failed - int n = fx3dev->DeviceCount(); - if (n == 0) return r; // return if no devices connected - if (!GetFx3Device()) return r; // NO FX3 device connected - -#ifdef _DEBUG - if (!fx3dev->IsBootLoaderRunning()) { // if not bootloader device - Control(RESETFX3); // reset the fx3 firmware via CyU3PDeviceReset(false) - DbgPrintf("DEBUG - Reset Firmware\n"); - Sleep(300); - fx3dev->Close(); // close class - delete fx3dev; // destroy class - Sleep(300); - fx3dev = new CCyFX3Device; // create class - GetFx3Device(); // open class - } -#endif - FX3_FWDWNLOAD_ERROR_CODE dlf = SUCCESS; - if (fx3dev->IsBootLoaderRunning()) - { - dlf = fx3dev->DownloadFwToRam(fw_data, fw_size); - Sleep(500); // wait for download to finish - } - - if (dlf != 0) - { - DbgPrintf("MISSING/OLD FIRMWARE\n"); - return false; - } - int x = 0; - int maxretry = 30; - CCyFX3Device* expdev = nullptr; - while (x++ < maxretry) // wait new firmware setup - { - bool r = false; - expdev = new CCyFX3Device; // instantiate the device - if (expdev != NULL) - int n = expdev->DeviceCount(); - if (n > 0) - { - expdev->Open(0); - // go down the list of devices to find our device - for (int i = 1; i <= n; i++) - { - if ((expdev->VendorID == VENDOR_ID) && (expdev->ProductID == STREAMER_ID)) - { - x = maxretry; //got it exit - } - } - } - expdev->Close(); // close class - delete expdev; // destroy class - } - GetFx3DeviceStreamer(); // open class with new ram firmware - if (!fx3dev->IsOpen()) { + if (!GetFx3DeviceStreamer()) { DbgPrintf("Failed to open device\n"); return r; } diff --git a/Core/arch/win32/FX3handler.h b/Core/arch/win32/FX3handler.h index 3ca6ec15..97252e52 100644 --- a/Core/arch/win32/FX3handler.h +++ b/Core/arch/win32/FX3handler.h @@ -34,6 +34,7 @@ class fx3handler : public fx3class public: fx3handler(); virtual ~fx3handler(void); + bool Open(uint8_t* fw_data, uint32_t fw_size); bool IsOn() { return Fx3IsOn; } bool Control(FX3Command command, uint8_t data); @@ -44,7 +45,7 @@ class fx3handler : public fx3class bool ReadDebugTrace(uint8_t* pdata, uint8_t len); void StartStream(ringbuffer& input, int numofblock); void StopStream(); - + bool Enumerate(unsigned char &idx, char *lbuf, uint8_t* fw_data, uint32_t fw_size); private: bool SendI2cbytes(uint8_t i2caddr, uint8_t regaddr, uint8_t* pdata, uint8_t len); bool ReadI2cbytes(uint8_t i2caddr, uint8_t regaddr, uint8_t* pdata, uint8_t len); @@ -58,7 +59,6 @@ class fx3handler : public fx3class std::thread *adc_samples_thread; - bool GetFx3Device(); bool GetFx3DeviceStreamer(); bool Fx3IsOn; bool Close(void); @@ -67,6 +67,7 @@ class fx3handler : public fx3class ringbuffer *inputbuffer; int numofblock; bool run; + UCHAR devidx; }; diff --git a/Core/config.h b/Core/config.h index 610d3d43..5eacba42 100644 --- a/Core/config.h +++ b/Core/config.h @@ -45,8 +45,7 @@ inline void null_func(const char *format, ...) { } #define DbgPrintf DbgEmpty #endif -#define VERSION (1.2) // Dll version number x.xx -#define SWVERSION "1.2.1" +#define SWVERSION "1.3.0 RC1" #define SETTINGS_IDENTIFIER "sddc_1.06" #define SWNAME "ExtIO_sddc.dll" @@ -77,6 +76,9 @@ enum rf_mode { NOMODE = 0, HFMODE = 0x1, VHFMODE = 0x2 }; #define URL_HDSR "http://www.hdsdr.de/" #define URL_HDSDRA "http://www.hdsdr.de/" +#define MAXNDEV (4) // max number of SDR device connected to PC +#define MAXDEVSTRLEN (64) //max char len of SDR device description + extern bool saveADCsamplesflag; extern uint32_t adcnominalfreq; diff --git a/ExtIO_sddc/ExtIO_sddc.cpp b/ExtIO_sddc/ExtIO_sddc.cpp index 0ec9918b..418ed196 100644 --- a/ExtIO_sddc/ExtIO_sddc.cpp +++ b/ExtIO_sddc/ExtIO_sddc.cpp @@ -54,6 +54,8 @@ RadioHandlerClass RadioHandler; HWND h_dialog = NULL; +DevContext devicelist; // list of FX3 devices + SplashWindow splashW; #define IDD_SDDC_SETTINGS 100 @@ -212,12 +214,31 @@ bool __declspec(dllexport) __stdcall InitHW(char *name, char *model, int& type) } auto Fx3 = CreateUsbHandler(); + unsigned char idx = 0; + int selected = 0; + while (Fx3->Enumerate(idx, devicelist.dev[idx], res_data, res_size) && (idx < MAXNDEV)) + { + // https://en.wikipedia.org/wiki/West_Bridge + int retry = 2; + while ((strncmp("WestBridge", devicelist.dev[idx],sizeof("WestBridge")) != NULL) && retry-- > 0) + Fx3->Enumerate(idx, devicelist.dev[idx], res_data, res_size); // if it enumerates as BootLoader retry + idx++; + } + devicelist.numdev = idx; + if (idx > 1){ + selected = DialogBoxParam(hInst, MAKEINTRESOURCE(IDD_SELECTDEVICE), NULL, DlgSelectDevice, (LPARAM) &devicelist); + } + DbgPrintf("selected %d \n",selected); + idx = selected; + Fx3->Enumerate(idx, devicelist.dev[idx], res_data, res_size); + gbInitHW = Fx3->Open(res_data, res_size) && - RadioHandler.Init(Fx3, Callback ); // Check if it there hardware + RadioHandler.Init(Fx3, Callback); // Check if it there hardware + #ifdef _DEBUG RadioHandler.EnableDebug( printf_USB_cb , GetConsoleInput); #endif - + if (!gbInitHW) { MessageBox(NULL, "Is SDR powered on and connected ?\r\n\r\nPlease start HDSDR again", diff --git a/ExtIO_sddc/resource.h b/ExtIO_sddc/resource.h index bb40773e..630eb0ac 100644 --- a/ExtIO_sddc/resource.h +++ b/ExtIO_sddc/resource.h @@ -9,6 +9,7 @@ #define IDB_BITMAP2 106 #define IDD_DLG_HDSDR 107 #define IDD_DLG_HDSDR281 108 +#define IDD_SELECTDEVICE 109 #define IDC_LW 1001 #define IDC_HF 1002 #define IDC_VHF 1003 @@ -30,6 +31,7 @@ #define IDC_CORRUPDATE 1019 #define IDC_FREQCANC 1020 #define IDC_CORRCANC 1021 +#define IDC_LISTDEV 1030 #define RES_BIN_FIRMWARE 2000 #define IHK_CR 5001 #define IDE_EDIT_MAIN 40002 diff --git a/ExtIO_sddc/resource.rc b/ExtIO_sddc/resource.rc index 3020943d..4c0fc190 100644 --- a/ExtIO_sddc/resource.rc +++ b/ExtIO_sddc/resource.rc @@ -164,6 +164,21 @@ PUSHBUTTON "Save ADC", IDC_ADCSAMPLES, 150, 70, 48, 13, BS_FLAT END +///////////////////////////////////////////////////////////////////////////// +// +// Dialog SELECT DEVICE +// + +IDD_SELECTDEVICE DIALOG DISCARDABLE 0, 0, 200, 68 +STYLE DS_SETFONT | WS_CAPTION | WS_SYSMENU | DS_CENTER +CAPTION "ExtIO_sddc.dll Select FX3 Device" +//FONT 8, "Ms Shell Dlg" +FONT 10, "Lucida Console" +BEGIN +DEFPUSHBUTTON "OK", IDOK, 80, 48, 40, 14, WS_DISABLED | WS_TABSTOP +LISTBOX IDC_LISTDEV, 5, 5, 190, 48, WS_TABSTOP +END + ///////////////////////////////////////////////////////////////////////////// // // RT_MANIFEST diff --git a/ExtIO_sddc/tdialog.cpp b/ExtIO_sddc/tdialog.cpp index a653e460..ce582470 100644 --- a/ExtIO_sddc/tdialog.cpp +++ b/ExtIO_sddc/tdialog.cpp @@ -468,3 +468,66 @@ BOOL CALLBACK DlgMainFn(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) return FALSE; } + + + +BOOL CALLBACK DlgSelectDevice(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + int selindex = 0; + DevContext* p_devicelist; + + // check message type + switch (uMsg) + { + case WM_INITDIALOG: + p_devicelist = (DevContext*) lParam; + for (int i = 0; i < p_devicelist->numdev; i++) { + ListBox_AddString(GetDlgItem(hWnd, IDC_LISTDEV), p_devicelist->dev[i]); + } + break; + + case WM_CTLCOLORDLG: + case WM_CTLCOLOREDIT: + case WM_CTLCOLORLISTBOX: + case WM_CTLCOLORSCROLLBAR: + case WM_CTLCOLORSTATIC: + { + HDC hDc = (HDC)wParam; + SetBkMode(hDc, TRANSPARENT); + return (LONG)g_hbrBackground; + } + case WM_COMMAND: + switch (LOWORD(wParam)) + { + case IDOK: + case IDCANCEL: + selindex = ListBox_GetCurSel(GetDlgItem(hWnd, IDC_LISTDEV)); + if (selindex < 0) selindex = 0; // if not selected select 0 + EndDialog(hWnd, selindex); + break; + + case IDC_LISTDEV: + switch (HIWORD(wParam)) + { + case LBN_SELCHANGE: + EnableWindow(GetDlgItem(hWnd, IDOK), TRUE); + break; + case LBN_DBLCLK: + selindex = ListBox_GetCurSel(GetDlgItem(hWnd, IDC_LISTDEV)); + if (selindex < 0) selindex = 0; // if not selected select 0 + EndDialog(hWnd, selindex); + break; + } + break; + } + break; + + + default: + // return zero if we do not process this message + return FALSE; + } + + // return nonzero if we did process the message + return TRUE; +} \ No newline at end of file diff --git a/ExtIO_sddc/tdialog.h b/ExtIO_sddc/tdialog.h index cb381f2f..9f99535d 100644 --- a/ExtIO_sddc/tdialog.h +++ b/ExtIO_sddc/tdialog.h @@ -12,4 +12,11 @@ extern void UpdatePPM(HWND hWnd); BOOL CALLBACK DlgMainFn(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); +BOOL CALLBACK DlgSelectDevice(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); + +struct DevContext +{ + unsigned char numdev; + char dev[MAXNDEV][MAXDEVSTRLEN]; +}; #endif // _TABDIALOGH_ diff --git a/Interface.h b/Interface.h index 0a323bff..db100d0b 100644 --- a/Interface.h +++ b/Interface.h @@ -1,7 +1,7 @@ #pragma once #define FIRMWARE_VER_MAJOR 2 -#define FIRMWARE_VER_MINOR 1 +#define FIRMWARE_VER_MINOR 2 // HF103 commands !!! enum FX3Command { diff --git a/SDDC_FX3.img b/SDDC_FX3.img index 8b3b08abd7d120c817defbd4286d510ae7c4b73e..f1c0f3d67324ad7003372c0872f851e0bf9557fb 100644 GIT binary patch delta 23593 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 delta 22805 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 4; + CyFxUSBSerialNumberDscr[30] = hexdigits[FX3_ID[0] & 0xf]; FX3_ID[0] >>= 4; + CyFxUSBSerialNumberDscr[28] = hexdigits[FX3_ID[0] & 0xf]; FX3_ID[0] >>= 4; + CyFxUSBSerialNumberDscr[26] = hexdigits[FX3_ID[0] & 0xf]; FX3_ID[0] >>= 4; + CyFxUSBSerialNumberDscr[24] = hexdigits[FX3_ID[0] & 0xf]; FX3_ID[0] >>= 4; + CyFxUSBSerialNumberDscr[22] = hexdigits[FX3_ID[0] & 0xf]; FX3_ID[0] >>= 4; + CyFxUSBSerialNumberDscr[20] = hexdigits[FX3_ID[0] & 0xf]; FX3_ID[0] >>= 4; + CyFxUSBSerialNumberDscr[18] = hexdigits[FX3_ID[0] & 0xf]; FX3_ID[0] >>= 4; + CyFxUSBSerialNumberDscr[16] = hexdigits[FX3_ID[1] & 0xf]; FX3_ID[1] >>= 4; + CyFxUSBSerialNumberDscr[14] = hexdigits[FX3_ID[1] & 0xf]; FX3_ID[1] >>= 4; + CyFxUSBSerialNumberDscr[12] = hexdigits[FX3_ID[1] & 0xf]; FX3_ID[1] >>= 4; + CyFxUSBSerialNumberDscr[10] = hexdigits[FX3_ID[1] & 0xf]; FX3_ID[1] >>= 4; + CyFxUSBSerialNumberDscr[ 8] = hexdigits[FX3_ID[1] & 0xf]; FX3_ID[1] >>= 4; + CyFxUSBSerialNumberDscr[ 6] = hexdigits[FX3_ID[1] & 0xf]; FX3_ID[1] >>= 4; + CyFxUSBSerialNumberDscr[ 4] = hexdigits[FX3_ID[1] & 0xf]; FX3_ID[1] >>= 4; + CyFxUSBSerialNumberDscr[ 2] = hexdigits[FX3_ID[1] & 0xf]; FX3_ID[1] >>= 4; + OverallStatus |= Status = CyU3PUsbSetDesc(CY_U3P_USB_SET_STRING_DESCR, 3, (uint8_t *)CyFxUSBSerialNumberDscr); + CheckStatus("SET_STRING3_DESCR", Status); + + return OverallStatus; } diff --git a/SDDC_FX3/USBhandler.c b/SDDC_FX3/USBhandler.c index 2c069ecf..40a187d1 100644 --- a/SDDC_FX3/USBhandler.c +++ b/SDDC_FX3/USBhandler.c @@ -23,7 +23,7 @@ extern void CheckStatus(char* StringPtr, CyU3PReturnStatus_t Status); extern void StartApplication(void); extern void StopApplication(void); -extern CyU3PReturnStatus_t SetUSBdescriptors(void); +extern CyU3PReturnStatus_t SetUSBdescriptors(uint8_t hwconfig); extern void WriteAttenuator(uint8_t value); void si5351aSetFrequencyA(UINT32 freq); @@ -604,7 +604,7 @@ CyBool_t LPMRequest_Callback ( CyU3PUsbLinkPowerMode link_mode) // Spin up USB, let the USB driver handle enumeration -CyU3PReturnStatus_t InitializeUSB(void) +CyU3PReturnStatus_t InitializeUSB(uint8_t hwconfig) { CyU3PReturnStatus_t Status; CyBool_t NeedToRenumerate = CyTrue; @@ -627,7 +627,7 @@ CyU3PReturnStatus_t InitializeUSB(void) CyU3PUsbRegisterLPMRequestCallback( LPMRequest_Callback ); // Driver needs all of the descriptors so it can supply them to the host when requested - Status = SetUSBdescriptors(); + Status = SetUSBdescriptors(hwconfig); CheckStatus("Set USB Descriptors", Status); // Connect the USB Pins with SuperSpeed operation enabled if (NeedToRenumerate) diff --git a/unittest/core_test.cpp b/unittest/core_test.cpp index b7ff43d6..c9ea6b82 100644 --- a/unittest/core_test.cpp +++ b/unittest/core_test.cpp @@ -46,6 +46,11 @@ class fx3handler : public fx3class return true; } + bool Enumerate(unsigned char& idx, char* lbuf, uint8_t* fw_data, uint32_t fw_size) + { + return true; + } + bool ReadDebugTrace(uint8_t* pdata, uint8_t len) { return true; }