From 88243e4574277868642d175db48c064cb1abe771 Mon Sep 17 00:00:00 2001 From: SDRplay Date: Sun, 12 May 2024 07:50:18 +0100 Subject: [PATCH] Add RSPdxR2 Support --- README.md | 4 +- RSPdxR2/ExtIO_SDRplay.vcxproj | 162 + RSPdxR2/ExtIO_SDRplay_RSPdxR2.sln | 27 + RSPdxR2/Resources/SDRplay RSPdxR2 Diagram.bmp | Bin 0 -> 329794 bytes RSPdxR2/src/ExtIO_SDRplay.cpp | 6926 +++++++++++++++++ RSPdxR2/src/ExtIO_SDRplay.h | 18 + RSPdxR2/src/ExtIO_SDRplay.rc | 181 + RSPdxR2/src/dllmain.cpp | 21 + RSPdxR2/src/exports.def | 27 + RSPdxR2/src/resource.h | 122 + RSPdxR2/src/targetver.h | 8 + 11 files changed, 7495 insertions(+), 1 deletion(-) create mode 100644 RSPdxR2/ExtIO_SDRplay.vcxproj create mode 100644 RSPdxR2/ExtIO_SDRplay_RSPdxR2.sln create mode 100644 RSPdxR2/Resources/SDRplay RSPdxR2 Diagram.bmp create mode 100644 RSPdxR2/src/ExtIO_SDRplay.cpp create mode 100644 RSPdxR2/src/ExtIO_SDRplay.h create mode 100644 RSPdxR2/src/ExtIO_SDRplay.rc create mode 100644 RSPdxR2/src/dllmain.cpp create mode 100644 RSPdxR2/src/exports.def create mode 100644 RSPdxR2/src/resource.h create mode 100644 RSPdxR2/src/targetver.h diff --git a/README.md b/README.md index 5971af5..68aa418 100644 --- a/README.md +++ b/README.md @@ -6,12 +6,14 @@ All of these plugins require the API 3.07 or above. Note: The RSP1B ExtIO plugin requires API 3.14 MINIMUM +Note: The RSPdxR2 ExtIO plugin requires API 3.15 MINIMUM + Note: The RSPdx ExtIO plugin DOES NOT, AND WILL NOT, SUPPORT HDR MODE. Not possible to do with just the ExtIO protocol. This source code is all provide as is without support. The Releases section will contain a zip file of just the ExtIO plugins. -Go to https://www.sdrplay.com/downloads to get the relevant API +Go to https://www.sdrplay.com/api to get the relevant API SDRplay diff --git a/RSPdxR2/ExtIO_SDRplay.vcxproj b/RSPdxR2/ExtIO_SDRplay.vcxproj new file mode 100644 index 0000000..e6f8850 --- /dev/null +++ b/RSPdxR2/ExtIO_SDRplay.vcxproj @@ -0,0 +1,162 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {2F5638BD-6CEB-41F8-8ADF-BB270180EADE} + ExtIO_SDRplay + ExtIO_SDRplay_RSPdxR2 + 10.0 + + + + DynamicLibrary + true + v141_xp + MultiByte + + + DynamicLibrary + true + v141 + MultiByte + + + DynamicLibrary + false + v143 + true + MultiByte + + + DynamicLibrary + false + v141 + true + Unicode + + + + + + + + + + + + + + + + + + + $(SolutionDir)$(Configuration)\ + $(SolutionDir)$(Configuration)\$(ProjectName)\ + $(ProjectName) + + + $(SolutionDir)$(Configuration)\$(Platform)\ + $(SolutionDir)$(Configuration)\$(Platform)\$(ProjectName)\ + + + + Level3 + Disabled + C:\Program Files\SDRplay\API\inc + WINVER=0x0501;_WINDLL;SDRplaysdr_STATIC;LIBSDRplay_EXPORTS;%(PreprocessorDefinitions) + MultiThreadedDebug + + + true + $(SolutionDir)$(Configuration)\;%(AdditionalLibraryDirectories) + src\exports.def + advapi32.lib;%(AdditionalDependencies) + + + + + Level3 + Disabled + + + true + + + + + Level4 + MaxSpeed + C:\Program Files\SDRplay\API\inc + WINVER=0x0501;_WIN32;SDRplaysdr_STATIC;LIBSDRplay_EXPORTS;_WINDLL;%(PreprocessorDefinitions) + true + MultiThreaded + + + $(SolutionDir)$(Configuration)\;%(AdditionalLibraryDirectories) + Shlwapi.lib;advapi32.lib;%(AdditionalDependencies) + src\exports.def + 0.1 + Windows + $(OutDir)$(TargetName)$(TargetExt) + + + + + + Level3 + MaxSpeed + ..\rtl-sdr\include + WINVER=0x0501;_WIN32;rtlsdr_STATIC;LIBRTL_EXPORTS;_WINDLL;%(PreprocessorDefinitions) + true + MultiThreaded + + + $(SolutionDir)$(Configuration)\$(Platform)\;%(AdditionalLibraryDirectories) + libusb-1.0.lib;rtl-sdr.lib;%(AdditionalDependencies) + src\exports.def + + + + + + + + + + + + C:\Program Files\MiricsSDR\API\inc;..\rtl-sdr\include + false + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/RSPdxR2/ExtIO_SDRplay_RSPdxR2.sln b/RSPdxR2/ExtIO_SDRplay_RSPdxR2.sln new file mode 100644 index 0000000..2ab0ed5 --- /dev/null +++ b/RSPdxR2/ExtIO_SDRplay_RSPdxR2.sln @@ -0,0 +1,27 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Express 2013 for Windows Desktop +VisualStudioVersion = 12.0.30723.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ExtIO_SDRplay", "ExtIO_SDRplay.vcxproj", "{2F5638BD-6CEB-41F8-8ADF-BB270180EADE}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {2F5638BD-6CEB-41F8-8ADF-BB270180EADE}.Debug|Win32.ActiveCfg = Debug|Win32 + {2F5638BD-6CEB-41F8-8ADF-BB270180EADE}.Debug|Win32.Build.0 = Debug|Win32 + {2F5638BD-6CEB-41F8-8ADF-BB270180EADE}.Debug|x64.ActiveCfg = Debug|Win32 + {2F5638BD-6CEB-41F8-8ADF-BB270180EADE}.Release|Win32.ActiveCfg = Release|Win32 + {2F5638BD-6CEB-41F8-8ADF-BB270180EADE}.Release|Win32.Build.0 = Release|Win32 + {2F5638BD-6CEB-41F8-8ADF-BB270180EADE}.Release|x64.ActiveCfg = Release|x64 + {2F5638BD-6CEB-41F8-8ADF-BB270180EADE}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/RSPdxR2/Resources/SDRplay RSPdxR2 Diagram.bmp b/RSPdxR2/Resources/SDRplay RSPdxR2 Diagram.bmp new file mode 100644 index 0000000000000000000000000000000000000000..1663672bc042c2900f81ecb14d60307d3746a26b GIT binary patch literal 329794 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 KdIky{4*x#|Ht4?q literal 0 HcmV?d00001 diff --git a/RSPdxR2/src/ExtIO_SDRplay.cpp b/RSPdxR2/src/ExtIO_SDRplay.cpp new file mode 100644 index 0000000..229b067 --- /dev/null +++ b/RSPdxR2/src/ExtIO_SDRplay.cpp @@ -0,0 +1,6926 @@ + +/* *******************************************************************************/ +/* EXTIO Plugin Interface for SDRplay RSPdxR2 */ +/* V1.0 build 0512 */ +/* Version 1.0 built against API 3.15 */ +/*********************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "resource.h" +#include "ExtIO_SDRplay.h" +#include "sdrplay_api.h" +#include +#include +#include +#include "Shlwapi.h" +#include +#include +#include + +using namespace std; + +// main debug control - check output with debugview +//#define DEBUG_ENABLE + +// hardware debug output (watch with debugview) +#define RSP_DEBUG 0 +// station lookup debug - output to station control panel +//#define DEBUG_STATION + +#define NOT_USED(p) ((void)(p)) + +#define MAXNUMOFDEVS 16 +sdrplay_api_DeviceT devices[MAXNUMOFDEVS]; +sdrplay_api_DeviceT *chosenDev; +sdrplay_api_CallbackFnsT cbFns; +int chosenDevice; +unsigned int numDevs; + +sdrplay_api_DeviceParamsT *deviceParams; +sdrplay_api_RxChannelParamsT *chParams; + +#define GAIN_SLIDER_MIN (20) +#define GAIN_SLIDER_MAX (59) +#define INITIAL_GR (41) + +#define LNA_GAIN_SLIDER_MIN (0) +#define LNA_GAIN_SLIDER_MAX_0000_0012 (18) +#define LNA_GAIN_SLIDER_MAX_0012_0060 (19) +#define LNA_GAIN_SLIDER_MAX_0060_0250 (26) +#define LNA_GAIN_SLIDER_MAX_0250_0420 (27) +#define LNA_GAIN_SLIDER_MAX_0420_1000 (20) +#define LNA_GAIN_SLIDER_MAX_1000_2000 (18) + +#define EXTIO_HWTYPE_16B 3 +#define LO120MHz 24576000 +#define LO144MHz 22000000 +#define LO168MHz 19200000 +#define ID_AGCUPDATE 202 +#define IDC_BUFFER 200 +#define STATIC 0 +#define PERIODIC1 1 +#define PERIODIC2 2 +#define PERIODIC3 3 +#define ONESHOT 4 +#define CONTINUOUS 5 +#define DCTrackTimeInterval 2.93 +#define BUFFER_LEN (4096) +static bool profileChanged = false; +static bool stationLookup = false; +static bool localDBExists = false; +static bool workOffline = false; +int TACIndex = 0; +int ITUIndex = 0; + +typedef void (WINAPI *PGNSI)(LPSYSTEM_INFO); + +//Globals for monioring SDRplay Condition. +static int DcCompensationMode; +static int TrackingPeriod; +static int RefreshPeriodMemory; +static bool PostTunerDcCompensation; +double TrackTime; +static double Frequency = 98.8; // nominal / desired frequency +int LowerFqLimit; +int IFmodeIdx = 0; +float FqOffsetPPM = 0; +volatile int GainReduction = INITIAL_GR; // variables accessed from different threads should be volatile! +volatile int LNAGainReduction = 0; +int SystemGainReduction; +int ActualLNAGR = 0; +int zero = 0; +int *pZERO = &zero; // used to pass int pointer to Reinit where the value isn't used or the return value isn't significant +sdrplay_api_If_kHzT IFMode = sdrplay_api_IF_Zero; +sdrplay_api_Bw_MHzT Bandwidth = sdrplay_api_BW_1_536; +sdrplay_api_LoModeT LOMode = sdrplay_api_LO_Auto; +int notchEnable = 0; +int biasTEnable = 0; +int dabNotchEnable = 0; +bool slaveAttached = false; +int AntennaIdx = 0; + +volatile int BandwidthIdx = 3; + +int DecimationIdx = 0; + +int AGCsetpoint = -30; +bool AGCEnabled = true; +int down_conversion_enabled = 1; +int LOplan = LO120MHz; +bool LOplanAuto = true; +bool LOChangeNeeded = false; +TCHAR msgbuf[255]; +static int LastGrToggle = -1; +clock_t StartTime, CurrentTime; +int ExecutionTime; +static double lastFreq = -1.0; +static int lastGainReduction = -1; +bool invertSpectrum = false; +double FreqOffsetInvSpec = 0.0; +int SampleCount = 0; // number of I/Q frames +static bool loadedProfiles = false; +static bool definedHotkeys = false; +static char stationTTipText[8192]; +static bool displayStationTip = false; + +TCHAR apiVersion[32]; +TCHAR apiPath[255]; +WCHAR regPath[255]; + +//Other Globals +static int buffer_len_samples; // number of samples in one buffer (= 2 * number of I/Q frames) +HWND ghwndDlg = 0; +//UINT_PTR m_timer = 0; +volatile int ThreadExitFlag = 0; +bool Initiated = false; +bool Running = false; +static int ppm_default=0; +int SampleRateIdx = 0; +char demodMode; +int DecimateEnable = 0; +int DecimateFactor = 0; + +short CallbackBuffer[]; + +struct DEC +{ + int DecIndex; + int DecValue; +}; + +struct DEC Decimation[] = +{ + { 0, 1 }, + { 1, 2 }, + { 2, 4 }, + { 3, 8 }, + { 4, 16 }, + { 5, 32 }, + { 6, 64 } +}; + +typedef struct sr { + double value; + TCHAR *name; +} sr_t; + +static sr_t samplerates[] = { + { 2.0, TEXT("2.0 MHz") }, + { 3.0, TEXT("3.0 MHz") }, + { 4.0, TEXT("4.0 MHz") }, + { 5.0, TEXT("5.0 MHz") }, + { 6.0, TEXT("6.0 MHz") }, + { 7.0, TEXT("7.0 MHz") }, + { 8.0, TEXT("8.0 MHz") }, + { 9.0, TEXT("9.0 MHz") }, + {10.0, TEXT("10.0 MHz") } +}; + +struct bw_t { + sdrplay_api_Bw_MHzT bwType; + double BW; +}; + +static bw_t bandwidths[] = { + { sdrplay_api_BW_0_200, 0.2 }, + { sdrplay_api_BW_0_300, 0.3 }, + { sdrplay_api_BW_0_600, 0.6 }, + { sdrplay_api_BW_1_536, 1.536 }, + { sdrplay_api_BW_5_000, 5.000 }, + { sdrplay_api_BW_6_000, 6.000 }, + { sdrplay_api_BW_7_000, 7.000 }, + { sdrplay_api_BW_8_000, 8.000 } +}; + +TCHAR p1fname[MAX_PATH] = _T(""); +TCHAR p2fname[MAX_PATH] = _T(""); +TCHAR p3fname[MAX_PATH] = _T(""); +TCHAR p4fname[MAX_PATH] = _T(""); +TCHAR p5fname[MAX_PATH] = _T(""); +TCHAR p6fname[MAX_PATH] = _T(""); +TCHAR p7fname[MAX_PATH] = _T(""); +TCHAR p8fname[MAX_PATH] = _T(""); + +typedef struct { + char *targetAreaCode; + char *description; +} tac; + +typedef struct { + char *ituCode; + char *countryName; +} itu; + +typedef struct { + char *langCode; + char *description; + char *silcode; +} lang; + +struct station { + char *freq; + char *time; + char *days; + char *itu; + char *name; + char *language; + char *tac; + char minTime[5]; + char maxTime[5]; + struct station *next; +}; + +static itu ituCodes[] = { + { "ZZZ", "Do not do any country matching" }, + { "ABW", "Aruba" }, + { "AFG", "Afghanistan" }, + { "AFS", "South Africa" }, + { "AGL", "Angola" }, + { "AIA", "Anguilla" }, + { "ALB", "Albania" }, + { "ALG", "Algeria" }, + { "ALS", "Alaska" }, + { "AMS", "Saint Paul & Amsterdam Is." }, + { "AND", "Andorra" }, + { "AOE", "Western Sahara" }, + { "ARG", "Argentina" }, + { "ARM", "Armenia" }, + { "ARS", "Saudi Arabia" }, + { "ASC", "Ascension Island" }, + { "ATA", "Antarctica" }, + { "ATG", "Antigua and Barbuda" }, + { "ATN", "Netherlands Leeward Antilles(dissolved in 2010)" }, + { "AUS", "Australia" }, + { "AUT", "Austria" }, + { "AZE", "Azerbaijan" }, + { "AZR", "Azores" }, + { "B", "Brasil" }, + { "BAH", "Bahamas" }, + { "BDI", "Burundi" }, + { "BEL", "Belgium" }, + { "BEN", "Benin" }, + { "BER", "Bermuda" }, + { "BES", "Bonaire, St Eustatius, Saba(Dutch islands in the Caribbean)" }, + { "BFA", "Burkina Faso" }, + { "BGD", "Bangla Desh" }, + { "BHR", "Bahrain" }, + { "BIH", "Bosnia - Herzegovina" }, + { "BIO", "Chagos Is. (Diego Garcia) (British Indian Ocean Territory)" }, + { "BLM", "Saint - Barthelemy" }, + { "BLR", "Belarus" }, + { "BLZ", "Belize" }, + { "BOL", "Bolivia" }, + { "BOT", "Botswana" }, + { "BRB", "Barbados" }, + { "BRU", "Brunei Darussalam" }, + { "BTN", "Bhutan" }, + { "BUL", "Bulgaria" }, + { "BVT", "Bouvet" }, + { "CAB", "Cabinda *" }, + { "CAF", "Central African Republic" }, + { "CAN", "Canada" }, + { "CBG", "Cambodia" }, + { "CEU", "Ceuta *" }, + { "CG7", "Guantanamo Bay" }, + { "CHL", "Chile" }, + { "CHN", "China(People's Republic)" }, + { "CHR", "Christmas Island(Indian Ocean)" }, + { "CKH", "Cook Island" }, + { "CLA", "Clandestine stations *" }, + { "CLM", "Colombia" }, + { "CLN", "Sri Lanka" }, + { "CME", "Cameroon" }, + { "CNR", "Canary Islands" }, + { "COD", "Democratic Republic of Congo(capital Kinshasa)" }, + { "COG", "Republic of Congo(capital Brazzaville)" }, + { "COM", "Comores" }, + { "CPT", "Clipperton" }, + { "CPV", "Cape Verde Islands" }, + { "CRO", "Crozet Archipelago" }, + { "CTI", "Ivory Coast(Côte d'Ivoire)" }, + { "CTR", "Costa Rica" }, + { "CUB", "Cuba" }, + { "CUW", "Curacao" }, + { "CVA", "Vatican State" }, + { "CYM", "Cayman Islands" }, + { "CYP", "Cyprus" }, + { "CZE", "Czech Republic" }, + { "D", "Germany" }, + { "DJI", "Djibouti" }, + { "DMA", "Dominica" }, + { "DNK", "Denmark" }, + { "DOM", "Dominican Republic" }, + { "E", "Spain" }, + { "EGY", "Egypt" }, + { "EQA", "Ecuador" }, + { "ERI", "Eritrea" }, + { "EST", "Estonia" }, + { "ETH", "Ethiopia" }, + { "EUR", "Iles Europe & Bassas da India *" }, + { "F", "France" }, + { "FIN", "Finland" }, + { "FJI", "Fiji" }, + { "FLK", "Falkland Islands" }, + { "FRO", "Faroe Islands" }, + { "FSM", "Federated States of Micronesia" }, + { "G", "United Kingdom of Great Britain and Northern Ireland" }, + { "GAB", "Gabon" }, + { "GEO", "Georgia" }, + { "GHA", "Ghana" }, + { "GIB", "Gibraltar" }, + { "GLP", "Guadeloupe" }, + { "GMB", "Gambia" }, + { "GNB", "Guinea - Bissau" }, + { "GNE", "Equatorial Guinea" }, + { "GPG", "Galapagos *" }, + { "GRC", "Greece" }, + { "GRD", "Grenada" }, + { "GRL", "Greenland" }, + { "GTM", "Guatemala" }, + { "GUF", "French Guyana" }, + { "GUI", "Guinea" }, + { "GUM", "Guam / Guahan" }, + { "GUY", "Guyana" }, + { "HKG", "Hong Kong, part of China" }, + { "HMD", "Heard & McDonald Islands" }, + { "HND", "Honduras" }, + { "HNG", "Hungary" }, + { "HOL", "The Netherlands" }, + { "HRV", "Croatia" }, + { "HTI", "Haiti" }, + { "HWA", "Hawaii" }, + { "HWL", "Howland & Baker" }, + { "I", "Italy" }, + { "ICO", "Cocos(Keeling) Island" }, + { "IND", "India" }, + { "INS", "Indonesia" }, + { "IRL", "Ireland" }, + { "IRN", "Iran" }, + { "IRQ", "Iraq" }, + { "ISL", "Iceland" }, + { "ISR", "Israel" }, + { "IW", "International Waters" }, + { "IWA", "Ogasawara(Bonin, Iwo Jima) *" }, + { "J", "Japan" }, + { "JAR", "Jarvis Island" }, + { "JDN", "Juan de Nova *" }, + { "JMC", "Jamaica" }, + { "JMY", "Jan Mayen *" }, + { "JON", "Johnston Island" }, + { "JOR", "Jordan" }, + { "JUF", "Juan Fernandez Island *" }, + { "KAL", "Kaliningrad *" }, + { "KAZ", "Kazakstan / Kazakhstan" }, + { "KEN", "Kenya" }, + { "KER", "Kerguelen" }, + { "KGZ", "Kyrgyzstan" }, + { "KIR", "Kiribati" }, + { "KNA", "St Kitts and Nevis" }, + { "KOR", "Korea, South(Republic)" }, + { "KRE", "Korea, North(Democratic People's Republic)" }, + { "KWT", "Kuwait" }, + { "LAO", "Laos" }, + { "LBN", "Lebanon" }, + { "LBR", "Liberia" }, + { "LBY", "Libya" }, + { "LCA", "Saint Lucia" }, + { "LIE", "Liechtenstein" }, + { "LSO", "Lesotho" }, + { "LTU", "Lithuania" }, + { "LUX", "Luxembourg" }, + { "LVA", "Latvia" }, + { "MAC", "Macao" }, + { "MAF", "St Martin" }, + { "MAU", "Mauritius" }, + { "MCO", "Monaco" }, + { "MDA", "Moldova" }, + { "MDG", "Madagascar" }, + { "MDR", "Madeira" }, + { "MDW", "Midway Islands" }, + { "MEL", "Melilla *" }, + { "MEX", "Mexico" }, + { "MHL", "Marshall Islands" }, + { "MKD", "Macedonia(F.Y.R.)" }, + { "MLA", "Malaysia" }, + { "MLD", "Maldives" }, + { "MLI", "Mali" }, + { "MLT", "Malta" }, + { "MNE", "Montenegro" }, + { "MNG", "Mongolia" }, + { "MOZ", "Mozambique" }, + { "MRA", "Northern Mariana Islands" }, + { "MRC", "Morocco" }, + { "MRN", "Marion & Prince Edward Islands" }, + { "MRT", "Martinique" }, + { "MSR", "Montserrat" }, + { "MTN", "Mauritania" }, + { "MWI", "Malawi" }, + { "MYA", "Myanmar(Burma) (also BRM)" }, + { "MYT", "Mayotte" }, + { "NCG", "Nicaragua" }, + { "NCL", "New Caledonia" }, + { "NFK", "Norfolk Island" }, + { "NGR", "Niger" }, + { "NIG", "Nigeria" }, + { "NIU", "Niue" }, + { "NMB", "Namibia" }, + { "NOR", "Norway" }, + { "NPL", "Nepal" }, + { "NRU", "Nauru" }, + { "NZL", "New Zealand" }, + { "OCE", "French Polynesia" }, + { "OMA", "Oman" }, + { "PAK", "Pakistan" }, + { "PAQ", "Easter Island" }, + { "PHL", "Philippines" }, + { "PHX", "Phoenix Is." }, + { "PLM", "Palmyra Island" }, + { "PLW", "Palau" }, + { "PNG", "Papua New Guinea" }, + { "PNR", "Panama" }, + { "POL", "Poland" }, + { "POR", "Portugal" }, + { "PRG", "Paraguay" }, + { "PRU", "Peru" }, + { "PRV", "Okino - Tori - Shima(Parece Vela) *" }, + { "PSE", "Palestine" }, + { "PTC", "Pitcairn" }, + { "PTR", "Puerto Rico" }, + { "QAT", "Qatar" }, + { "REU", "La Réunion" }, + { "ROD", "Rodrigues" }, + { "ROU", "Romania" }, + { "RRW", "Rwanda" }, + { "RUS", "Russian Federation" }, + { "S", "Sweden" }, + { "SAP", "San Andres & Providencia *" }, + { "SDN", "Sudan" }, + { "SEN", "Senegal" }, + { "SEY", "Seychelles" }, + { "SGA", "South Georgia Islands *" }, + { "SHN", "Saint Helena" }, + { "SLM", "Solomon Islands" }, + { "SLV", "El Salvador" }, + { "SMA", "Samoa(American)" }, + { "SMO", "Samoa" }, + { "SMR", "San Marino" }, + { "SNG", "Singapore" }, + { "SOK", "South Orkney Islands *" }, + { "SOM", "Somalia" }, + { "SPM", "Saint Pierre et Miquelon" }, + { "SRB", "Serbia" }, + { "SRL", "Sierra Leone" }, + { "SSD", "South Sudan" }, + { "SSI", "South Sandwich Islands *" }, + { "STP", "Sao Tome & Principe" }, + { "SUI", "Switzerland" }, + { "SUR", "Suriname" }, + { "SVB", "Svalbard *" }, + { "SVK", "Slovakia" }, + { "SVN", "Slovenia" }, + { "SWZ", "Swaziland" }, + { "SXM", "Sint Maarten" }, + { "SYR", "Syria" }, + { "TCA", "Turks and Caicos Islands" }, + { "TCD", "Tchad" }, + { "TGO", "Togo" }, + { "THA", "Thailand" }, + { "TJK", "Tajikistan" }, + { "TKL", "Tokelau" }, + { "TKM", "Turkmenistan" }, + { "TLS", "Timor - Leste" }, + { "TON", "Tonga" }, + { "TRC", "Tristan da Cunha" }, + { "TRD", "Trinidad and Tobago" }, + { "TUN", "Tunisia" }, + { "TUR", "Turkey" }, + { "TUV", "Tuvalu" }, + { "TWN", "Taiwan *" }, + { "TZA", "Tanzania" }, + { "UAE", "United Arab Emirates" }, + { "UGA", "Uganda" }, + { "UKR", "Ukraine" }, + { "UN", "United Nations *" }, + { "URG", "Uruguay" }, + { "USA", "United States of America" }, + { "UZB", "Uzbekistan" }, + { "VCT", "Saint Vincent and the Grenadines" }, + { "VEN", "Venezuela" }, + { "VIR", "American Virgin Islands" }, + { "VRG", "British Virgin Islands" }, + { "VTN", "Vietnam" }, + { "VUT", "Vanuatu" }, + { "WAK", "Wake Island" }, + { "WAL", "Wallis and Futuna" }, + { "XBY", "Abyei area" }, + { "XGZ", "Gaza strip" }, + { "XSP", "Spratly Islands" }, + { "XUU", "Unidentified" }, + { "XWB", "West Bank" }, + { "YEM", "Yemen" }, + { "ZMB", "Zambia" }, + { "ZWE", "Zimbabwe" } +}; + +static tac targetAreaCodes[] = { + { "ZZZ", "Do not do any target area matching" }, + { "Af", "Africa" }, + { "Am", "America(s)" }, + { "As", "Asia" }, +// { "C", "Central" }, + { "Car", "Caribbean, Gulf of Mexico, Florida Waters" }, + { "Cau", "Caucasus" }, + { "CIS", "Commonwealth of Independent States (Former Soviet Union)" }, + { "CNA", "Central North America" }, +// { "E", "East" }, + { "ENA", "Eastern North America" }, + { "Eu", "Europe (often including North Africa/Middle East)" }, + { "FE", "Far East" }, + { "LAm", "Latin America (Central and South America)" }, + { "ME", "Middle East" }, +// { "N", "North" }, + { "NAO", "North Atlantic Ocean" }, + { "Oc", "Oceania (Australia, New Zealand, Pacific Ocean)" }, +// { "S", "South" }, + { "SAO", "South Atlantic Ocean" }, + { "SEA", "South East Asia" }, + { "SEE", "South East Europe" }, + { "Sib", "Siberia" }, + { "Tib", "Tibet" }, +// { "W", "West" }, + { "WIO", "Western Indian Ocean" }, + { "WNA", "Western North America" } +}; + +static lang languageCodes[] = { + { "-CW", "Morse Station", "[]" }, + { "-MX", "Music", "[]" }, + { "-TS", "Time Signal Station", "[]" }, + { "A", "Arabic(300m)", "[arb]" }, + { "AB", "Abkhaz : Georgia - Abkhazia(0.1m)", "[abk]" }, + { "AC", "Aceh : Indonesia - Sumatera(3m)", "[ace]" }, + { "ACH", "Achang / Ngac'ang: Myanmar, South China (60,000)", "[acn]" }, + { "AD", "Adygea / Adyghe / Circassian : Russia - Caucasus(0.5m)", "[ady]" }, + { "ADI", "Adi : India - Assam,Arunachal Pr. (0.1m)", "[adi]" }, + { "AF", "Afrikaans : South Africa, Namibia(5m)", "[afr]" }, + { "AFA", "Afar : Djibouti(0.3m), Ethiopia(0.45m), Eritrea(0.3m)", "[aar]" }, + { "AFG", "Pashto and Dari(main Afghan languages, see there)", "[]" }, + { "AH", "Amharic : Ethiopia(22m)", "[amh]" }, + { "AJ", "Adja / Aja - Gbe : Benin, Togo(0.5m)", "[ajg]" }, + { "AK", "Akha : Burma(0.2m), China - Yunnan(0.13m)", "[ahk]" }, + { "AL", "Albanian : Albania(Tosk)(3m), Macedonia / Yugoslavia(Gheg)(2m)", "[sqi]" }, + { "ALG", "Algerian(Arabic) : Algeria(28m)", "[arq]" }, + { "AM", "Amoy : S China(25m), Taiwan(15m), SoEaAsia(5m); dialect of Minnan", "[nan]" }, + { "AMD", "Tibetan Amdo(Tibet, Qinghai, Gansu, Sichuan: 2m)", "[adx]" }, + { "Ang", "Angelus programme of Vaticane Radio", "[]" }, + { "AR", "Armenian : Armenia(3m), USA(1m), RUS,GEO,SYR,LBN,IRN,EGY", "[hye]" }, + { "ARO", "Aromanian / Vlach : Greece, Albania, Macedonia(0.1m)", "[rup]" }, + { "ARU", "Languages of Arunachal, India(collectively)", "[]" }, + { "ASS", "Assamese : India - Assam(13m)", "[asm]" }, + { "ASY", "Assyrian / Syriac / Neo - Aramaic : Iraq, Iran, Syria(0.2m)", "[aii]" }, + { "ATS", "Atsi / Zaiwa : Myanmar(13,000), China - Yunnan(70,000)", "[atb]" }, + { "Aud", "Papal Audience(Vaticane Radio)", "[]" }, + { "AV", "Avar : Dagestan, S Russia(0.7m)", "[ava]" }, + { "AW", "Awadhi : N&Ce India(3m)", "[awa]" }, + { "AY", "Aymara : Bolivia(2m)", "[ayr]" }, + { "AZ", "Azeri / Azerbaijani : Azerbaijan(6m)", "[azj]" }, + { "BAD", "Badaga : India - Tamil Nadu(0.13m)", "[bfq]" }, + { "BAG", "Bagri : India - Punjab(0.6m), Pakistan(0.2m)", "[bgq]" }, + { "BAI", "Bai : China - Yunnan(1.2m)", "[bca]" }, + { "BAJ", "Bajau : Malaysia - Sabah(50,000)", "[bdr]" }, + { "BAL", "Balinese : Indonesia - Bali(3m)", "[ban]" }, + { "BAN", "Banjar / Banjarese : Indonesia - Kalimantan(3.5m)", "[bjn]" }, + { "BAO", "Baoulé : Cote d'Ivoire (2m)", "[bci]" }, + { "BAR", "Bari : South Sudan(0.4m)", "[bfa]" }, + { "BAS", "Bashkir / Bashkort : Russia - Bashkortostan(1m)", "[bak]" }, + { "BAY", "Bayash / Boyash(gypsy dialect of Romanian) : Serbia, Croatia(10,000)", "[]" }, + { "BB", "Braj Bhasa / Braj Bhasha / Brij : India - Rajasthan(0.6m)", "[bra]" }, + { "BC", "Baluchi : Pakistan(5m)", "[bal]" }, + { "BE", "Bengali / Bangla : Bangladesh(110m), India(82m)", "[ben]" }, + { "BED", "bedawiyet / Bedawi / Beja : Sudan(1m)", "[bej]" }, + { "BEM", "Bemba : Zambia(3m)", "[bem]" }, + { "BGL", "Bagheli : N India(3m)", "[bfy]" }, + { "BH", "Bhili : India - Madhya Pradesh, Gujarat(3.3m)", "[bhb]" }, + { "BHN", "Bahnar : Vietnam(160,000)", "[bdq]" }, + { "BHT", "Bhatri : India - Chhattisgarh,Maharashtra(0.2m)", "[bgw]" }, + { "BI", "Bilen / Bile : Eritrea - Keren(90,000)", "[byn]" }, + { "BID", "Bidayuh languages : Malaysia - Sarawak(70,000)", "[sdo]" }, + { "BIS", "Bisaya : Malaysia - Sarawak,Sabah(20,000), Brunei(40,000)", "[bsb]" }, + { "BJ", "Bhojpuri / Bihari : India(38m), Nepal(1.7m)", "[bho]" }, + { "BK", "Balkarian : Russia - Caucasus(0.3m)", "[krc]" }, + { "BLK", "Balkan Romani : Bulgaria(0.3m), Serbia(0.1m), Macedonia(0.1m)", "[rmn]" }, + { "BLT", "Balti : NE Pakistan(0.3m)", "[bft]" }, + { "BM", "Bambara / Bamanankan : Mali(4m)", "[bam]" }, + { "BNA", "Borana Oromo / Afan Oromo : Ethiopia(4m)", "[gax]" }, + { "BNG", "Bangala / Mbangala : Central Angola(0.4m)", "[mxg]" }, + { "BNI", "Baniua / Baniwa : Brazil - Amazonas(6,000)", "[bwi]" }, + { "BNJ", "Banjari / Banjara / Gormati / Lambadi : India(4m)", "[lmn]" }, + { "BNT", "Bantawa : Nepal(400,000)", "[bap]" }, + { "BON", "Bondo : India - Odisha(9000)", "[bfw]" }, + { "BOR", "Boro / Bodo : India - Assam,W Bengal(1.3m)", "[brx]" }, + { "BOS", "Bosnian(derived from Serbocroat) : Bosnia - Hercegovina(2m)", "[bos]" }, + { "BR", "Burmese / Barma / Myanmar : Myanmar(32m)", "[mya]" }, + { "BRA", "Brahui : Pakistan(4m), Afghanistan(0.2m)", "[brh]" }, + { "BRB", "Bariba / Baatonum : Benin(0.5m), Nigeria(0.1m)", "[bba]" }, + { "BRU", "Bru : Laos(30,000), Vietnam(55,000)", "[bru]" }, + { "BSL", "Bislama : Vanuatu(10,000)", "[bis]" }, + { "BT", "Black Tai / Tai Dam : Vietnam(0.7m)", "[blt]" }, + { "BTK", "Batak - Toba : Indonesia - Sumatra(2m)", "[bbc]" }, + { "BU", "Bulgarian : Bulgaria(6m)", "[bul]" }, + { "BUG", "Bugis / Buginese : Indonesia - Sulawesi(5m)", "[bug]" }, + { "BUK", "Bukharian / Bukhori : Israel(50,000), Uzbekistan(10,000)", "[bhh]" }, + { "BUN", "Bundeli / Bundelkhandi / Bundelkandi : India - Uttar,Madhya Pr. (3m)", "[bns]" }, + { "BUR", "Buryat : Russia - Buryatia, Lake Baikal(0.4m)", "[bxr]" }, + { "BY", "Byelorussian / Belarusian : Belarus, Poland, Ukraine(8m)", "[bel]" }, + { "C", "Chinese(not further specified)", "[]" }, + { "CA", "Cantonese / Yue : China - Guangdong(50m),Hongkong(6m),Malaysia(1m)", "[yue]" }, + { "CC", "Chaochow(dialect of Min - Nan) : China - Guangdong(10m), Thailand(1m)", "[nan]" }, + { "CD", "Chowdary / Chaudhry / Chodri : India - Gujarat(0.2m)", "[cdi]" }, + { "CEB", "Cebuano : Philippines(16m)", "[ceb]" }, + { "CH", "Chin(not further specified) : Myanmar; includes those below a.o.", "[]" }, + { "C-A", "Chin - Asho: Myanmar - Ayeyarwady,Rakhine(30,000)", "[csh]" }, + { "C-D", "Chin - Daai : Myanmar - Chin(37,000)", "[dao]" }, + { "C-F", "Chin - Falam / Halam : Myanmar - Chin, Bangladesh, India(0.1m)", "[cfm]" }, + { "C-H", "Chin - Haka : Myanmar - Chin(100,000)", "[cnh]" }, + { "CHA", "Cha'palaa / Chachi: Ecuador-Esmeraldas (10,000)", "[cbi]" }, + { "CHE", "Chechen : Russia - Chechnya(1.4m)", "[che]" }, + { "CHG", "Chhattisgarhi : India - Chhattisgarh, Odisha, Bihar(13m)", "[hne]" }, + { "CHI", "Chitrali / Khowar : NW Pakistan(0.2m)", "[khw]" }, + { "C-K", "Chin - Khumi : Myanmar - Chin,Rakhine(0.6m)", "[cnk]" }, + { "C-M", "Chin - Mro : Myanmar - Rakhine,Chin(75,000)", "[cmr]" }, + { "C-O", "Chin - Thado / Thadou - Kuki : India - Assam, Manipur(0.2m)", "[tcz]" }, + { "CHR", "Chrau : Vietnam(7,000)", "[crw]" }, + { "CHU", "Chuwabu : Mozambique(1m)", "[chw]" }, + { "C-T", "Chin - Tidim : Myanmar - Chin(0.2m), India - Mizoram,Manipur(0.15m)", "[ctd]" }, + { "C-Z", "Chin - Zomin / Zomi - Chin : Myanmar(60,000), India - Manipur(20,000)", "[zom]" }, + { "CKM", "Chakma : India - Mizoram,Tripura,Assam(0.2m), Bangladesh(0.15m)", "[ccp]" }, + { "CKW", "Chokwe : Angola(0.5m), DR Congo(0.5m)", "[cjk]" }, + { "COF", "Cofan / Cofán : Ecuador - Napo, Colombia(2000)", "[con]" }, + { "COK", "Cook Islands Maori / Rarotongan : Cook Islands(13,000)", "[rar]" }, + { "CR", "Creole / Haitian : Haiti(7m)", "[hat]" }, + { "CRU", "Chru : Vietnam(19,000)", "[cje]" }, + { "CT", "Catalan : Spain(7m), Andorra(31,000)", "[cat]" }, + { "CV", "Chuvash : Russia - Chuvashia(1m)", "[chv]" }, + { "CW", "Chewa / Chichewa / Nyanja / Chinyanja : Malawi(7m), MOZ(0.6m),ZMB(0.8m)", "[nya]" }, + { "CZ", "Czech : Czech Republic(9m)", "[ces]" }, + { "D", "German : Germany(80m), Austria, Switzerland, Belgium", "[deu]" }, + { "D-P", "Lower German(varieties in N.Germany, USA:Pennsylvania Dutch)", "[pdc]" }, + { "DA", "Danish : Denmark(5.5m)", "[dan]" }, + { "DAO", "Dao : Vietnam ethnic group speaking MIE and Kim Mun(0.7m)", "[]" }, + { "DAR", "Dargwa / Dargin : Russia - Dagestan(0.5m)", "[dar]" }, + { "DD", "Dhodiya / Dhodia : India - Gujarat(150,000)", "[dho]" }, + { "DEC", "Deccan / Deccani / Desi : India - Maharashtra(13m)", "[dcc]" }, + { "DEG", "Degar / Montagnard(Vietnam) : comprises JR, RAD, BHN, KOH, MNO, STI", "[]" }, + { "DEN", "Dendi : Benin(30,000)", "[ddn]" }, + { "DEO", "Deori : India - Assam(27,000)", "[der]" }, + { "DES", "Desiya / Deshiya : India - Odisha(50,000)", "[dso]" }, + { "DH", "Dhivehi : Maldives(0.3m)", "[div]" }, + { "DI", "Dinka : South Sudan(1.4m)", "[dip,diw,dik,dib,dks]" }, + { "DIM", "Dimasa / Dhimasa : India - Assam : (0.1m)", "[dis]" }, + { "DIT", "Ditamari : Benin(0.1m)", "[tbz]" }, + { "DO", "Dogri - Kangri : N India(4m)", "[doi]" }, + { "DR", "Dari / Eastern Farsi : Afghanistan(7m), Pakistan(2m)", "[prs]" }, + { "DU", "Dusun : Malaysia - Sabah(0.1m)", "[dtp]" }, + { "DUN", "Dungan : Kyrgyzstan(40,000)", "[dng]" }, + { "DY", "Dyula / Jula : Burkina Faso(1m), Ivory Coast(1.5m), Mali(50,000)", "[dyu]" }, + { "DZ", "Dzongkha : Bhutan(0.2m)", "[dzo]" }, + { "E", "English : UK(60m), USA(225m), India(200m), others", "[eng]" }, + { "EC", "Eastern Cham : Vietnam(70,000)", "[cjm]" }, + { "EGY", "Egyptian Arabic : Egypt(52m)", "[arz]" }, + { "EO", "Esperanto : Constructed language(2m)", "[epo]" }, + { "ES", "Estonian : Estonia(1m)", "[ekk]" }, + { "EWE", "Ewe / Éwé : Ghana(2m), Togo(1m)", "[ewe]" }, + { "F", "French : France(53m), Canada(7m), Belgium(4m), Switzerland(1m)", "[fra]" }, + { "FA", "Faroese : Faroe Islands(66,000)", "[fao]" }, + { "FI", "Finnish : Finland(5m)", "[fin]" }, + { "FJ", "Fijian : Fiji(0.3m)", "[fij]" }, + { "FON", "Fon / Fongbe : Benin(1.4m)", "[fon]" }, + { "FP", "Filipino(based on Tagalog) : Philippines(25m)", "[fil]" }, + { "FS", "Farsi / Iranian Persian : Iran(45m)", "[pes]" }, + { "FT", "Fiote / Vili : Rep.Congo(7000), Gabon(4000)", "[vif]" }, + { "FU", "Fulani / Fulfulde : Nigeria(8m), Niger(1m),Burkina Faso(1m)", "[fub,fuh,fuq]" }, + { "FUJ", "FutaJalon / Pular : Guinea(3m)", "[fuf]" }, + { "FUR", "Fur : Sudan - Darfur(0.5m)", "[fvr]" }, + { "GA", "Garhwali : India - Uttarakhand,Himachal Pr. (3m)", "[gbm]" }, + { "GAG", "Gagauz : Moldova(0.1m)", "[gag]" }, + { "GAR", "Garo : India - Meghalaya,Assam,Nagaland,Tripura(1m)", "[grt]" }, + { "GD", "Greenlandic Inuktikut : Greenland(50,000)", "[kal]" }, + { "GE", "Georgian : Georgia(4m)", "[kat]" }, + { "GI", "Gilaki : Iran(3m)", "[glk]" }, + { "GJ", "Gujari / Gojri : NW India(0.7m), Pakistan(0.3m)", "[gju]" }, + { "GL", "Galicic / Gallego : Spain(3m)", "[glg]" }, + { "GM", "Gamit : India - Gujarat(0.3m)", "[gbl]" }, + { "GNG", "Gurung(Eastern and Western) : Nepal(0.4m)", "[ggn,gvr]" }, + { "GO", "Gorontalo : Indonesia - Sulawesi(1m)", "[gor]" }, + { "GON", "Gondi : India - Madhya Pr.,Maharashtra(2m)", "[gno]" }, + { "GR", "Greek : Greece(10m), Cyprus(0.7m)", "[ell]" }, + { "GU", "Gujarati : India - Gujarat,Maharashtra,Rajasthan(46m)", "[guj]" }, + { "GUA", "Guaraní : Paraguay(5m)", "[grn]" }, + { "GUR", "Gurage / Guragena : Ethiopia(0.4m)", "[sgw]" }, + { "GZ", "Ge'ez / Geez (liturgic language of Ethiopia)", "[gez]" }, + { "HA", "Haussa : Nigeria(19m), Niger(5m), Benin(1m)", "[hau]" }, + { "HAD", "Hadiya : Ethiopia(1.2m)", "[hdy]" }, + { "HAR", "Haryanvi / Bangri / Harayanvi / Hariyanvi : India - Haryana(8m)", "[bgc]" }, + { "HAS", "Hassinya / Hassaniya : Mauritania(3m)", "[mey]" }, + { "HB", "Hebrew : Israel(5m)", "[heb]" }, + { "HD", "Hindko(Northern and Southern) : Pakistan(3m)", "[hnd,hno]" }, + { "HI", "Hindi : India(260m)", "[hin]" }, + { "HK", "Hakka : South China(26m), Taiwan(3m), Malaysia(1m)", "[hak]" }, + { "HM", "Hmong / Miao languages : S China, N Vietnam, N Laos, USA(3m)", "[hmn]" }, + { "HMA", "Hmar : India - Assam,Manipur,Mizoram(80,000)", "[hmr]" }, + { "HMB", "Hmong - Blue / Njua : Laos(0.1m), Thailand(60,000)", "[hnj]" }, + { "HMQ", "Hmong, Northern Qiandong / Black Hmong : S China(1m)", "[hea]" }, + { "HMW", "Hmong - White / Daw : Vietnam(1m), Laos(0.2m), S China(0.2m)", "[mww]" }, + { "HN", "Hani : China - Yunnan(0.7m)", "[hni]" }, + { "HO", "Ho : India - Jharkand,Odisha,W Bengal(1m)", "[hoc]" }, + { "HR", "Croatian / Hrvatski : Croatia(4m), BIH(0.5m), Serbia(0.1m)", "[hrv]" }, + { "HRE", "Hre : Vietnam(0.1m)", "[hre]" }, + { "HU", "Hungarian : Hungary(10m), Romania(1.5m), SVK(0.5m), SRB(0.3m)", "[hun]" }, + { "HUI", "Hui / Huizhou : China - Anhui,Zhejiang(5m)", "[czh]" }, + { "HZ", "Hazaragi : Afghanistan(1.8m), Iran(0.3m)", "[haz]" }, + { "I", "Italian : Italy(55m), Switzerland(0.5m), San Marino(25,000)", "[ita]" }, + { "IB", "Iban : Malaysia - Sarawak(0.7m)", "[iba]" }, + { "IF", "Ifè / Ife : Togo(0.1m), Benin(80,000)", "[ife]" }, + { "IG", "Igbo / Ibo : Nigeria(18m)", "[ibo]" }, + { "ILC", "Ilocano : Philippines(7m)", "[ilo]" }, + { "ILG", "Ilonggo : Philippines(6m)", "[hil]" }, + { "IN", "Indonesian / Bahasa Indonesia : Indonesia(140m)", "[ind]" }, + { "INU", "Inuktikut : Canada - Nunavut,N Quebec,Labrador(30,000)", "[ike]" }, + { "IRQ", "Iraqi Arabic : Iraq(12m), Iran(1m), Syria(2m)", "[acm]" }, + { "IS", "Icelandic : Iceland(0.2m)", "[isl]" }, + { "ISA", "Isan / Northeastern Thai : Thailand(15m)", "[tts]" }, + { "J", "Japanese : Japan(122m)", "[jpn]" }, + { "JEH", "Jeh : Vietnam(15,000), Laos(8,000)", "[jeh]" }, + { "JG", "Jingpho", "[]" }, + { "JOR", "Jordanian Arabic : Jordan(3.5m), Israel / Palestine(2.5m)", "[ajp]" }, + { "JR", "Jarai / Giarai / Jra : Vietnam(0.3m)", "[jra]" }, + { "JU", "Juba Arabic : South Sudan(60,000)", "[pga]" }, + { "JV", "Javanese : Indonesia - Java,Bali(84m)", "[jav]" }, + { "K", "Korean : Korea(62m), China - Jilin,Heilongjiang,Liaoning(2m)", "[kor]" }, + { "KA", "Karen(unspecified) : Myanmar(3m)", "[]" }, + { "K-G", "Karen - Geba : Myanmar(40,000)", "[kvq]" }, + { "K-K", "Karen - Geko / Gekho : Myanmar(17,000)", "[ghk]" }, + { "K-P", "Karen - Pao / Black Karen / Pa'o: Myanmar (0.5m)", "[blk]" }, + { "K-S", "Karen - Sgaw / S'gaw: Myanmar (1.3m), Thailand (0.2m)", "[ksw]" }, + { "K-W", "Karen - Pwo : Myanmar(1m); Northern variant : Thailand(60,000)", "[kjp,pww]" }, + { "KAD", "Kadazan : Malaysia - Sabah(80,000)", "[kzj,dtb]" }, + { "KAL", "Kalderash Romani(Dialect of Vlax) : Romania(0.2m)", "[rmy]" }, + { "KAB", "Kabardian : Russia - Caucasus(0.5m), Turkey(1m)", "[kbd]" }, + { "KAM", "Kambaata : Ethiopia(0.6m)", "[ktb]" }, + { "KAN", "Kannada : India - Karnataka,Andhra Pr.,Tamil Nadu(40m)", "[kan]" }, + { "KAO", "Kaonde : Zambia(0.2m)", "[kqn]" }, + { "KAR", "Karelian : Russia - Karelia(25,000), Finland(10,000)", "[krl]" }, + { "KAT", "Katu : Vietnam(50,000)", "[ktv]" }, + { "KAU", "Kau Bru / Riang : India - Tripura,Mizoram,Assam(77,000)", "[ria]" }, + { "KAY", "Kayan : Myanmar(0.1m)", "[pdu]" }, + { "KB", "Kabyle : Algeria(5m)", "[kab]" }, + { "KBO", "Kok Borok / Tripuri : India(0.8m)", "[trp]" }, + { "KC", "Kachin / Jingpho : Myanmar(0.9m)", "[kac]" }, + { "KG", "Kyrgyz / Kirghiz : Kyrgystan(2.5m), China(0.1m)", "[kir]" }, + { "KH", "Khmer : Cambodia(13m), Vietnam(1m)", "[khm]" }, + { "KHA", "Kham / Khams, Eastern : China - NE Tibet(1.4m)", "[khg]" }, + { "KHM", "Khmu : Laos(0.6m)", "[kjg]" }, + { "KHR", "Kharia / Khariya : India - Jharkand(0.2m)", "[khr]" }, + { "KHS", "Khasi / Kahasi : India - Meghalaya,Assam(0.8m)", "[kha]" }, + { "KHT", "Khota(India)", "[]" }, + { "KIM", "Kimwani : Mozambique(0.1m)", "[wmw]" }, + { "KIN", "Kinnauri / Kinori : India - Himachal Pr. (65,000)", "[kfk]" }, + { "KiR", "KiRundi : Burundi(9m)", "[run]" }, + { "KK", "KiKongo / Kongo : DR Congo, Angola(8m)", "[kng]" }, + { "KKN", "Kukna : India - Gujarat(0.1m)", "[kex]" }, + { "KMB", "Kimbundu / Mbundu / Luanda : Angola(4m)", "[kmb]" }, + { "KMY", "Kumyk : Russia - Dagestan(0.4m)", "[kum]" }, + { "KND", "Khandesi : India - Maharashtra(22,000)", "[khn]" }, + { "KNK", "KinyaRwanda - KiRundi service of the Voice of America / BBC", "[]" }, + { "KNU", "Kanuri : Nigeria(3.2m), Chad(0.1m), Niger(0.4m)", "[kau]" }, + { "KNY", "Konyak Naga : India - Assam,Nagaland(0.25m)", "[nbe]" }, + { "KOH", "Koho / Kohor : Vietnam(0.2m)", "[kpm]" }, + { "KOK", "Kokang Shan : Myanmar(dialect of Shan)", "[]" }, + { "KOM", "Komering : Indonesia - Sumatera(0.5m)", "[kge]" }, + { "KON", "Konkani : India - Maharashtra,Karnataka,Kerala(2.4m)", "[knn]" }, + { "KOT", "Kotokoli / Tem : Togo(0.2m), Benin(0.05m), Ghana(0.05m)", "[kdh]" }, + { "KOY", "Koya : India - Andhra Pr.,Odisha(0.4m)", "[kff]" }, + { "KPK", "Karakalpak : W Uzbekistan(0.4m)", "[kaa]" }, + { "KRB", "Karbi / Mikir / Manchati : India - Assam,Arunachal Pr. (0.4m)", "[mjw]" }, + { "KRI", "Krio : Sierra Leone(0.5m)", "[kri]" }, + { "KRW", "KinyaRwanda : Rwanda(7m), Uganda(0.4m), DR Congo(0.2m)", "[kin]" }, + { "KS", "Kashmiri : India(5m), Pakistan(0.1m)", "[kas]" }, + { "KT", "Kituba(simplified Kikongo) : DR Congo(4m)", "[ktu]" }, + { "KTW", "Kotwali(dialect of Bhili) : India - Gujarat,Maharshtra", "[bhb]" }, + { "KU", "Kurdish : Turkey(15m), Iraq(6.3m), Iran(6.5m), Syria(1m)", "[ckb,kmr,sdh]" }, + { "KuA", "Kurdish and Arabic", "[]" }, + { "KuF", "Kurdish and Farsi", "[]" }, + { "KUI", "Kui : India - Odisha,Ganjam,Andhra Pr. (1m)", "[kxu]" }, + { "KUL", "Kulina : Brazil - Acre(3500)", "[cul]" }, + { "KUM", "Kumaoni / Kumauni : India - Uttarakhand(2m)", "[kfy]" }, + { "KUN", "Kunama : Eritrea(0.2m)", "[kun]" }, + { "KUP", "Kupia / Kupiya : India - Andhra Pr. (6,000)", "[key]" }, + { "KUR", "Kurukh / Kurux : India - Chhatisgarh,Jharkhand,W.Bengal(2m)", "[kru]" }, + { "KUs", "Sorani(Central) Kurdish : Iraq(3.5m), Iran(3.3m)", "[ckb]" }, + { "KUT", "Kutchi : India - Gujarat(0.4m), Pakistan - Sindh(0.2m)", "[gjk]" }, + { "KUV", "Kuvi : India - Odisha(0.16m)", "[kxv]" }, + { "KVI", "Kulluvi / Kullu : India - Himachal Pr. (0.1m)", "[kfx]" }, + { "KWA", "Kwanyama / Kuanyama(dialect of OW) : Angola(0.4m), Namibia(0.2m)", "[kua]" }, + { "KYH", "Kayah : Myanmar(0.15m)", "[kyu]" }, + { "KZ", "Kazakh : Kazakhstan(7m), China(1m), Mongolia(0.1m)", "[kaz]" }, + { "L", "Latin : Official language of Catholic church", "[lat]" }, + { "LA", "Ladino", "[]" }, + { "LAD", "Ladakhi / Ladak : India - Jammu and Kashmir(0.1m)", "[lbj]" }, + { "LAH", "Lahu : China(0.3m), Myanmar(0.2m)", "[lhu]" }, + { "LAK", "Lak : Russia - Dagestan(0.15m)", "[lbe]" }, + { "LAM", "Lampung : Indonesia - Sumatera(1m)", "[abl,ljp]" }, + { "LAO", "Lao : Laos(3m)", "[lao]" }, + { "LB", "Lun Bawang / Murut : Malaysia - Sarawak(24,000), Indonesia(23,000)", "[lnd]" }, + { "LBN", "Lebanon Arabic(North Levantine) : Lebanon(4m), Syria(9m)", "[apc]" }, + { "LBO", "Limboo / Limbu : Nepal(0.3m), India - Sikkim,W.Bengal,Assam(40,000)", "[lif]" }, + { "LEP", "Lepcha : India - Sikkim,W.Bengal(50,000)", "[lep]" }, + { "LEZ", "Lezgi : Russia - Dagestan(0.4m), Azerbaijan(0.4m)", "[lez]" }, + { "LIM", "Limba : Sierra Leone(0.3m)", "[lia]" }, + { "LIN", "Lingala : DR Congo(2m), Rep.Congo(0.1m)", "[lin]" }, + { "LIS", "Lisu : China - West Yunnan(0.6m), Burma(0.3m)", "[lis]" }, + { "LND", "Lunda(see LU), in particular its dialect Ndembo : Angola(0.2m)", "[lun]" }, + { "LNG", "Lungeli Magar(possibly same as MGA ? )", "[]" }, + { "LO", "Lomwe / Ngulu : Mocambique(1.5m)", "[ngl]" }, + { "LOK", "Lokpa / Lukpa : Benin(50,000), Togo(14,000)", "[dop]" }, + { "LOZ", "Lozi / Silozi : Zambia(0.6m), ZWE(70,000), NMB - E Caprivi(30,000)", "[loz]" }, + { "LT", "Lithuanian : Lithuania(3m)", "[lit]" }, + { "LTO", "Oriental Liturgy of Vaticane Radio" , "[]" }, + { "LU", "Lunda : Zambia(0.5m)", "[lun]" }, + { "LUB", "Luba : DR Congo - Kasai(6m)", "[lua]" }, + { "LUC", "Luchazi : Angola(0.4m), Zambia(0.05m)", "[lch]" }, + { "LUG", "Luganda : Uganda(4m)[lug]" }, + { "LUN", "Lunyaneka / Nyaneka : Angola(0.3m)", "[nyk]" }, + { "LUR", "Luri, Northern and Southern : Iran(1.5m and 0.9m)", "[lrc,luz]" }, + { "LUV", "Luvale : Angola(0.5m), Zambia(0.2m)", "[lue]" }, + { "LV", "Latvian : Latvia(1.2m)", "[lvs]" }, + { "M", "Mandarin(Standard Chinese / Beijing dialect) : China(840m)", "[cmn]" }, + { "MA", "Maltese : Malta(0.3m)", "[mlt]" }, + { "MAD", "Madurese / Madura : Indonesia - Java(7m)", "[mad]" }, + { "MAG", "Maghi / Magahi / Maghai : India - Bihar,Jharkhand(14m)", "[mag]" }, + { "MAI", "Maithili / Maithali : India - Bihar(30m), Nepal(3m)", "[mai]" }, + { "MAK", "Makonde : Tanzania(1m), Mozambique(0.4m)", "[kde]" }, + { "MAL", "Malayalam : India - Kerala(33m)", "[mal]" }, + { "MAM", "Maay / Mamay / Rahanweyn : Somalia(2m)", "[ymm]" }, + { "MAO", "Maori : New Zealand(60,000)", "[mri]" }, + { "MAR", "Marathi : India - Maharashtra(72m)", "[mar]" }, + { "MAS", "Maasai / Massai / Masai : Kenya(0.8m), Tanzania(0.5m)", "[mas]" }, + { "MC", "Macedonian : Macedonia(1.4m), Albania(0.1m)", "[mkd]" }, + { "MCH", "Mavchi / Mouchi / Mauchi / Mawchi : India - Gujarat,Maharashtra(0.1m)", "[mke]" }, + { "MEI", "Meithei / Manipuri / Meitei : India - Manipur,Assam(1.5m)", "[mni]" }, + { "MEN", "Mende : Sierra Leone(1.5m)", "[men]" }, + { "MEW", "Mewari / Mewadi(a Rajasthani variety) : India - Rajasthan(5m)", "[mtr]" }, + { "MGA", "Magar(Western and Eastern) : Nepal(0.8m)", "[mrd,mgp]" }, + { "MIE", "Mien / Iu Mien : S China(0.4m), Vietnam(0.4m)", "[ium]" }, + { "MIS", "Mising : India - Assam,Arunachal Pr. (0.5m)", "[mrg]" }, + { "MKB", "Minangkabau : Indonesia - West Sumatra(5.5m)", "[min]" }, + { "MKS", "Makassar / Makasar : Indonesia - South Sulawesi(2m)", "[mak]" }, + { "MKU", "Makua / Makhuwa : Mocambique(3m)", "[vmw]" } , + { "ML", "Malay / Baku : Malaysia(10m), Singapore(0.4m), Indonesia(5m)", "[zsm,zlm]" }, + { "MLK", "Malinke / Maninka(We / Ea) : Guinea(3m), SEN(0.4m), Mali(0.8m)", "[emk,mlq]" }, + { "MLT", "Malto / Kumarbhag Paharia : India - Jharkhand(12,000)", "[kmj]" }, + { "MNA", "Mina / Gen : Togo(0.2m), Benin(0.1m)", "[gej]" }, + { "MNE", "Montenegrin(quite the same as SR) : Montenegro(0.2m)", "[srp]" }, + { "MNO", "Mnong(Ea,Ce,So) : Vietnam(90,000), Cambodia(40,000)", "[mng,cmo,mnn]" }, + { "MO", "Mongolian : Mongolia(Halh; 2m), China(Peripheral; 3m)", "[khk,mvf]" }, + { "MON", "Mon : Myanmar - Mon,Kayin(0.7m), Thailand(0.1m)", "[mnw]" }, + { "MOO", "Moore / Mòoré : Burkina Faso(5m)", "[mos]" }, + { "MOR", "Moro / Moru / Muro : Sudan - S Korodofan(30,000)", "[mor]" }, + { "MR", "Maronite / Cypriot Arabic : Cyprus(1300)", "[acy]" }, + { "MRC", "Moroccan / Mugrabian Arabic : Morocco(20m)", "[ary]" }, + { "MRI", "Mari : Russia - Mari(0.8m)", "[chm]" }, + { "MRU", "Maru / Lhao Vo : Burma - Kachin,Shan(0.1m)", "[mhx]" }, + { "MSY", "Malagasy : Madagaskar(16m)", "[mlg]" }, + { "MUN", "Mundari : India - Jharkhand,Odisha(1.1m)", "[unr]" }, + { "MUO", "Muong : Vietnam(1m)", "[mtq]" }, + { "MUR", "Murut : Malaysia - Sarawak,Sabah(4500)", "[kxi,mvv,tih]" }, + { "MW", "Marwari(a Rajasthani variety) : India - Rajasthan,Gujarat(6m)", "[rwr]" }, + { "MX", "Macuxi / Macushi : Brazil(16,000), Guyana(1,000)", "[mbc]" }, + { "MY", "Maya(Yucatec) : Mexico(0.7m), Belize(6000)", "[yua]" }, + { "MZ", "Mizo / Lushai : India - Mizoram(0.7m)", "[lus]" }, + { "NAG", "Naga(var.incl.Ao,Makware) : India - Nagaland, Assam(2m)", "[njh,njo,nmf,nph]" }, + { "NDA", "Ndau : Mocambique(1.6m), Zimbabwe(0.8m)", "[ndc]" }, + { "NDE", "Ndebele : Zimbabwe(1.5m), South Africa - Limpopo(0.6m)", "[nde,nbl]" }, + { "NE", "Nepali / Lhotshampa : Nepal(11m), India(3m), Bhutan(0.1m)", "[npi]" }, + { "NG", "Nagpuri / Sadani / Sadari / Sadri : India - Jharkhand,W.Bengal(3m)", "[sck]" }, + { "NGA", "Ngangela / Nyemba : Angola(0.2m)", "[nba]" }, + { "NIC", "Nicobari : India - Nicobar Islands(40,000)", "[caq]" }, + { "NIS", "Nishi / Nyishi : India - Arunachal Pradesh(0.2m)", "[njz]" }, + { "NIU", "Niuean : Niue(2,000)", "[niu]" }, + { "NL", "Dutch : Netherlands(16m), Belgium(6m), Suriname(0.2m)", "[nld]" }, + { "NLA", "Nga La / Matu Chin : Myanmar - Chin(30,000), India - Mizoram(10,000)", "[hlt]" }, + { "NO", "Norwegian : Norway(5m)", "[nor]" }, + { "NOC", "Nocte / Nockte : India - Assam,Arunachal Pr. (33,000)", "[njb]" }, + { "NP", "Nupe : Nigeria(0.8m)", "[nup]" }, + { "NTK", "Natakani / Netakani / Varhadi - Nagpuri : India - Maharashtra,M.Pr. (7m)", "[vah]" }, + { "NU", "Nuer : Sudan(0.8m), Ethiopia(0.2m)", "[nus]" }, + { "NUN", "Nung : Vietnam(1m)", "[nut]" }, + { "NW", "Newar / Newari : Nepal(0.8m)", "[new]" }, + { "NY", "Nyanja", "[]" }, + { "OG", "Ogan : Indonesia - Sumatera(less than 0.5m)", "[pse]" }, + { "OH", "Otjiherero service in Namibia(Languages : Herero, SeTswana)", "[]" }, + { "OO", "Oromo : Ethiopia(26m)", "[orm]" }, + { "OR", "Odia / Oriya / Orissa : India - Odisha,Chhattisgarh(32m)", "[ory]" }, + { "OS", "Ossetic : Russia(0.5m), Georgia(0.1m)", "[oss]" }, + { "OW", "Oshiwambo service in Angola and Namibia(Languages : Ovambo, Kwanyama)", "[]" }, + { "P", "Portuguese : Brazil(187m), Angola(14m), Portugal(10m)", "[por]" }, + { "PAL", "Palaung - Pale : Myanmar(0.3m)", "[pce]" }, + { "PAS", "Pasemah : Indonesia - Sumatera(less than 0.5m)", "[pse]" }, + { "PED", "Pedi : S Africa(4m)", "[nso]" }, + { "PJ", "Punjabi : Pakistan(60m), India - Punjab,Rajasthan(28m)", "[pnb,pan]" }, + { "PO", "Polish : Poland(37m)", "[pol]" }, + { "POR", "Po : Myanmar - Rakhine", "[]" }, + { "POT", "Pothwari : Pakistan(2.5m)", "[phr]" }, + { "PS", "Pashto / Pushtu : Afghanistan(6m), Pakistan(1m)", "[pbt]" }, + { "PU", "Pulaar : Senegal(3m), Gambia(0.3m)", "[fuc]" }, + { "Q", "Quechua : Peru, Bolivia, Ecuador(various varieties; 9m)", "[que,qvi]" }, + { "QQ", "Qashqai : Iran(1.5m)", "[qxq]" }, + { "R", "Russian : Russia(137m), Ukraine(8m), Kazakhstan(6m), Belarus(1m)", "[rus]" }, + { "RAD", "Rade / Ede : Vietnam(0.2m)", "[rad]" }, + { "REN", "Rengao : Vietnam(18,000)", "[ren]" }, + { "RGM", "Rengma Naga : India - Nagaland(34,000)", "[nre,nnl]" }, + { "RO", "Romanian : Romania(20m), Moldova(3m), Serbia - Vojvodina(0.2m)", "[ron]" }, + { "ROG", "Roglai(Northern, Southern) : Vietnam(0.1m)", "[rog,rgs]" }, + { "RON", "Rongmei Naga : India - Manipur,Nagaland,Assam(60,000)", "[nbu]" }, + { "Ros", "Rosary session of Vaticane Radio", "[]" }, + { "RU", "Rusyn / Ruthenian : Ukraine(0.5m), Serbia - Vojvodina(30,000)", "[rue]" }, + { "RWG", "Rawang : Myanmar - Kachin(60,000)", "[raw]" }, + { "S", "Spanish / Castellano : Spain(30m), Latin America(336m), USA(34m)", "[spa]" }, + { "SAH", "Saho : Eritrea(0.2m)", "[ssy]" }, + { "SAN", "Sango : Central African Rep. (0.4m)", "[sag]" }, + { "SAR", "Sara / Sar : Chad(0.2m)", "[mwm]" }, + { "SAS", "Sasak : Indonesia - Lombok(2m)", "[sas]" }, + { "SC", "Serbocroat(Yugoslav language up to national / linguistic separation)", "[hbs]" }, + { "SCA", "Scandinavian languages(Norwegian, Swedish, Finnish)", "[]" }, + { "SD", "Sindhi : Pakistan(19m), India(2m)", "[snd]" }, + { "SED", "Sedang : Vietnam(0.1m)", "[sed]" }, + { "SEF", "Sefardi / Judeo Spanish / Ladino : Israel(0.1m), Turkey(10,000)", "[lad]" }, + { "SEN", "Sena : Mocambique(1m)", "[seh]" }, + { "SFO", "Senoufo / Sénoufo - Syenara : Mali(0.15m)", "[shz]" }, + { "SGA", "Shangaan / Tsonga : Mocambique(2m), South Africa(2m)", "[tso]" }, + { "SGM", "Sara Gambai / Sara Ngambai : Chad(0.9m)", "[sba]" }, + { "SGO", "Songo : Angola(50,000)", "[nsx]" }, + { "SGT", "Sangtam : India - Nagaland(84,000)", "[nsa]" }, + { "SHA", "Shan : Myanmar(3m)", "[shn]" }, + { "SHk", "Shan - Khamti : Myanmar(8,000), India - Assam(5,000)", "[kht]" }, + { "SHC", "Sharchogpa / Sarchopa / Tshangla : E Bhutan(0.14m)", "[tsj]" }, + { "SHE", "Sheena / Shina : Pakistan(0.6m)", "[scl,plk]" }, + { "SHK", "Shiluk / Shilluk : South Sudan(0.2m)", "[shk]" }, + { "SHO", "Shona : Zimbabwe(11m)", "[sna]" }, + { "SHP", "Sherpa : Nepal(0.1m)", "[xsr]" }, + { "SHU", "Shuwa Arabic : Chad(1m), Nigeria(0.1m), N Cameroon(0.1m)", "[shu]" }, + { "SI", "Sinhalese / Sinhala : Sri Lanka(16m)", "[sin]" }, + { "SID", "Sidamo / Sidama : Ethiopia(3m)", "[sid]" }, + { "SIK", "Sikkimese / Bhutia : India - Sikkim,W.Bengal(70,000)", "[sip]" }, + { "SIR", "Siraiki / Seraiki : Pakistan(14m)", "[skr]" }, + { "SK", "Slovak : Slovakia(5m), Czech Republic(0.2m), Serbia(80,000)", "[slk]" }, + { "SLM", "Pijin / Solomon Islands Pidgin : Solomon Islands(0.3m)", "[pis]" }, + { "SLT", "Silte / East Gurage : Ethiopia(1m)", "[stv]" }, + { "SM", "Samoan : Samoa(0.2m), American Samoa(0.05m)", "[smo]" }, + { "SMP", "Sambalpuri / Sambealpuri : India - Odisha,Chhattisgarh(18m)", "[spv]" }, + { "SNK", "Sanskrit : India(0.2m)", "[san]" }, + { "SNT", "Santhali : India - Bihar,Jharkhand,Odisha(6m), Bangladesh(0.2m)", "[sat]" }, + { "SO", "Somali : Somalia(8m), Ethiopia(5m), Kenya(2m), Djibouti(0.3m)", "[som]" }, + { "SON", "Songhai : Mali(0.6m)", "[ses,khq]" }, + { "SOT", "SeSotho : South Africa(4m), Lesotho(2m)", "[sot]" }, + { "SR", "Serbian : Serbia(7m), Bosnia - Hercegovina(1.5m)", "[srp]" }, + { "SRA", "Soura / Sora : India - Odisha,Andhra Pr. (0.3m)", "[srb]" }, + { "STI", "Stieng : Vietnam(85,000)", "[sti,stt]" }, + { "SUA", "Shuar : Ecuador(35,000)", "[jiv]" }, + { "SUD", "Sudanese Arabic : Sudan and South Sudan(15m)", "[apd]" }, + { "SUM", "Sumi Naga : India - Nagaland(0.1m)", "[nsm]" }, + { "SUN", "Sunda / Sundanese : Indonesia - West Java(34m)", "[sun]" }, + { "SV", "Slovenian : Slovenia(1.7m), Italy(0.1m), Austria(18,000)", "[slv]" }, + { "SWA", "Swahili / Kisuaheli : Tanzania(15m), Kenya, Ea.DR Congo(9m)", "[swc,swh]" }, + { "SWE", "Swedish : Sweden(8m), Finland(0.3m)", "[swe]" }, + { "SWZ", "SiSwati : Swaziland(1m), South Africa(1m)", "[ssw]" }, + { "T", "Thai : Thailand(20m)", "[tha]" }, + { "TAG", "Tagalog : Philippines(22m)", "[tgl]" }, + { "TAH", "Tachelhit / Sous : Morocco, southern(4m), Algeria", "[shi]" }, + { "TAM", "Tamil : S.India(60m), Malaysia(4m), Sri Lanka(4m)", "[tam]" }, + { "TB", "Tibetan : Tibet(1m), India(0.1m)", "[bod]" }, + { "TBS", "Tabasaran : Russia - Dagestan(0.1m)", "[tab]" }, + { "TEL", "Telugu : India - Andhra Pr. (74m)", "[tel]" }, + { "TEM", "Temme / Temne : Sierra Leone(1.5m)", "[tem]" }, + { "TFT", "Tarifit : Morocco, northern(1.3m), Algeria", "[rif]" }, + { "TGK", "Tangkhul / Tangkul Naga : India - Manipur,Nagaland(0.15m)", "[nmf]" }, + { "TGR", "Tigre / Tigré : Eritrea(1m)", "[tig]" }, + { "TGS", "Tangsa / Naga - Tase : Myanmar(60,000), India - Arunachal Pr. (40,000)", "[nst]" }, + { "THA", "Tharu Buksa : India - Uttarakhand(43,000)", "[tkb]" }, + { "TIG", "Tigrinya / Tigray : Ethiopia(4m), Eritrea(3m)", "[tir]" }, + { "TJ", "Tajik : Tajikistan(3m), Uzbekistan(1m)", "[tgk]" }, + { "TK", "Turkmen : Turkmenistan(3m), Iran(2m), Afghanistan(1.5m)", "[tuk]" }, + { "TL", "Tai - Lu / Lu : China - Yunnan(0.3m), Myanmar(0.2m), Laos(0.1m)", "[khb]" }, + { "TM", "Tamazight : Morocco, central(3m)", "[zgh]" }, + { "TMG", "Tamang : Nepal(1.5m)", "[taj,tdg,tmk,tsf]" }, + { "TMJ", "Tamajeq : Niger(0.8m), Mali(0.44m), Algeria(40,000)", "[taq,thv,thz,ttq]" }, + { "TN", "Tai - Nua / Chinese Shan : China - Yunnan(0.5m), LAO / MYA / VTN(0.2m)", "[tdd]" }, + { "TNG", "Tonga : Zambia(1m), Zimbabwe(0.1m)", "[toi]" }, + { "TO", "Tongan : Tonga(0.1m)", "[ton]" }, + { "TOK", "Tokelau : Tokelau(1000)", "[tkl]" }, + { "TOR", "Torajanese / Toraja : Indonesia - Sulawesi(0.8m)", "[sda]" }, + { "TP", "Tok Pisin : Papua New Guinea(4m)", "[tpi]" }, + { "TS", "Tswana / SeTswana : Botswana(1m), South Africa(3m)", "[tsn]" }, + { "TSA", "Tsangla", "[]" }, + { "TSH", "Tshwa : Mocambique(1m)", "[tsc]" }, + { "TT", "Tatar : Russia - Tatarstan,Bashkortostan(5m)", "[tat]" }, + { "TTB", "Tatar - Bashkir service of Radio Liberty", "[]" }, + { "TU", "Turkish : Turkey(46m), Bulgaria(0.6m), N Cyprus(0.2m)", "[tur]" } , + { "TUL", "Tulu : India - Karnataka,Kerala(2m)", "[tcy]" }, + { "TUM", "Tumbuka : Malawi(2m), Zambia(0.5m)", "[tum]" }, + { "TUN", "Tunisian Arabic : Tunisia(9m)", "[aeb]" }, + { "TV", "Tuva / Tuvinic : Russia - Tannu Tuva(0.25m)", "[tyv]" }, + { "TW", "Taiwanese / Fujian / Hokkien / Min Nan(CHN 25m, TWN 15m, others 9m)", "[nan]" }, + { "TWI", "Twi / Akan : Ghana(8m)", "[aka]" }, + { "TWT", "Tachawit / Shawiya / Chaouia : Algeria(1.4m)", "[shy]" }, + { "TZ", "Tamazight / Berber : Morocco(2m)", "[zgh,tzm]" }, + { "UD", "Udmurt : Russia - Udmurtia(0.3m)", "[udm]" }, + { "UI", "Uighur : China - Xinjiang(8m), Kazakhstan(0.3m)", "[uig]" }, + { "UK", "Ukrainian : Ukraine(32m), Kazakhstan(0.9m), Moldova(0.6m)", "[ukr]" }, + { "UM", "Umbundu : Angola(6m)", "[umb]" }, + { "UR", "Urdu : Pakistan(104m), India(51m)", "[urd]" }, + { "UZ", "Uzbek : Uzbekistan(16m)", "[uzn]" }, + { "V", "Vasco / Basque / Euskera : Spain(0.6m), France(76,000)", "[eus]" }, + { "VAD", "Vadari / Waddar / Od : India - Andhra Pr. (0.2m)", "[wbq]" }, + { "VAR", "Varli / Warli : India - Maharashtra(0.6m)", "[vav]" }, + { "Ves", "Vespers(Vaticane Radio)", "[]" }, + { "Vn", "Vernacular = local language(s)", "[]" }, + { "VN", "Vietnamese : Vietnam(66m)", "[vie]" }, + { "VV", "Vasavi : India - Maharashtra,Gujarat(1m)", "[vas]" }, + { "VX", "Vlax Romani / Romanes / Gypsy : Romania(0.2m), Russia(0.1m)", "[rmy]" }, + { "W", "Wolof : Senegal(4m)", "[wol]" }, + { "WA", "Wa / Parauk : South China(0.4m), Myanmar(0.4m)", "[prk]" }, + { "WAO", "Waodani / Waorani : Ecuador(2000)", "[auc]" }, + { "WE", "Wenzhou : dialect of WU", "[]" }, + { "WT", "White Tai / Tai Don : Vietnam(0.3m), Laos(0.2m)", "[twh]" }, + { "WU", "Wu : China - Jiangsu,Zhejiang(80m)", "[wuu]" }, + { "XH", "Xhosa : South Africa(8m)", "[xho]" }, + { "YAO", "Yao / Yawo : Malawi(2m), Mocambique(0.5m), Tanzania(0.4m)", "[yao]" }, + { "YER", "Yerukula : India - Andhra Pr. (70,000)", "[yeu]" }, + { "YI", "Yi / Nosu : China - Sichuan(2m)", "[iii]" }, + { "YK", "Yakutian / Sakha : Russia - Sakha(0.5m)", "[sah]" }, + { "YO", "Yoruba : Nigeria(20m), Benin(0.5m)", "[yor]" }, + { "YOL", "Yolngu / Yuulngu : Australia - Northern Territory(4000)", "[djr]" }, + { "YUN", "Dialects / languages of Yunnan(China)", "[]" }, + { "YZ", "Yezidi program(Kurdish - Kurmanji language)", "[]" }, + { "Z", "Zulu : South Africa(10m), Lesotho(0.3m)", "[zul]" }, + { "ZA", "Zarma / Zama : Niger(2m)", "[dje]" }, + { "ZD", "Zande : DR Congo(0.7m), South Sudan(0.35m)", "[zne]" }, + { "ZG", "Zaghawa : Chad(87,000), Sudan(75,000)", "[zag]" }, + { "ZH", "Zhuang : Southern China, 16 varieties(15m)", "[zha]" }, + {"ZWE", "Languages of Zimbabwe", "[]" } +}; + +static int n_gains = ((GAIN_SLIDER_MAX - GAIN_SLIDER_MIN) + 1); +static int gains[((GAIN_SLIDER_MAX - GAIN_SLIDER_MIN) + 1)]; +static int last_gain; + +static HMODULE ApiDll = NULL; +HMODULE Dll = NULL; + +sdrplay_api_Init_t sdrplay_api_Init_fn = NULL; +sdrplay_api_Uninit_t sdrplay_api_Uninit_fn = NULL; +sdrplay_api_Open_t sdrplay_api_Open_fn = NULL; +sdrplay_api_Close_t sdrplay_api_Close_fn = NULL; +sdrplay_api_ApiVersion_t sdrplay_api_ApiVersion_fn = NULL; +sdrplay_api_LockDeviceApi_t sdrplay_api_LockDeviceApi_fn = NULL; +sdrplay_api_UnlockDeviceApi_t sdrplay_api_UnlockDeviceApi_fn = NULL; +sdrplay_api_GetDevices_t sdrplay_api_GetDevices_fn = NULL; +sdrplay_api_SelectDevice_t sdrplay_api_SelectDevice_fn = NULL; +sdrplay_api_ReleaseDevice_t sdrplay_api_ReleaseDevice_fn = NULL; +sdrplay_api_GetErrorString_t sdrplay_api_GetErrorString_fn = NULL; +sdrplay_api_DebugEnable_t sdrplay_api_DebugEnable_fn = NULL; +sdrplay_api_GetDeviceParams_t sdrplay_api_GetDeviceParams_fn = NULL; +sdrplay_api_Update_t sdrplay_api_Update_fn = NULL; +sdrplay_api_SwapRspDuoActiveTuner_t sdrplay_api_SwapRspDuoActiveTuner_fn = NULL; +sdrplay_api_SwapRspDuoDualTunerModeSampleRate_t sdrplay_api_SwapRspDuoDualTunerModeSampleRate_fn = NULL; + +static int buffer_sizes[] = // in kBytes +{ + 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024 +}; + +static int buffer_default=6; // 64kBytes + +short CallbackBuffer[1024 * 1024]; // This just allocates the max buffer size ever required so we don't need to worry about resizing it - buffer_len_samples handles the amount used +short IQBuffer[504 * 2 * 64]; // Maximum samples per packet is 504 and we can have upto 64 packets per callback in multithreaded mode +int BufferCounter = 0; + +typedef struct +{ + char vendor[256], product[256], serial[256]; +} device; + +static device *connected_devices = NULL; +static int device_count = 0; + +// Thread handle +HANDLE worker_handle=INVALID_HANDLE_VALUE; +int FindSampleRateIdx(double); +void SaveSettings(void); +void LoadSettings(void); +void ReinitAll(void); +void UpdateSR(void); + +/* ExtIO Callback */ +void (* WinradCallBack)(int, int, float, void *) = NULL; +#define WINRAD_SRCHANGE 100 +#define WINRAD_LOCHANGE 101 +#define WINRAD_LOBLOCKED 102 +#define WINRAD_LORELEASED 103 +#define WINRAD_TUNECHANGED 105 +#define WINRAD_DEMODCHANGED 106 +#define WINRAD_START 107 +#define WINRAD_STOP 108 +#define WINRAD_CHANGED_FILTER 109 + +int NUM_OF_HOTKEYS = 0; + +static INT_PTR CALLBACK MainDlgProc(HWND, UINT, WPARAM, LPARAM); +HWND h_dialog = NULL; + +static INT_PTR CALLBACK AdvancedDlgProc(HWND, UINT, WPARAM, LPARAM); +HWND h_AdvancedDialog = NULL; + +static INT_PTR CALLBACK StationDlgProc(HWND, UINT, WPARAM, LPARAM); +HWND h_StationDialog = NULL; + +static INT_PTR CALLBACK ProfilesDlgProc(HWND, UINT, WPARAM, LPARAM); +HWND h_ProfilesDialog = NULL; + +static INT_PTR CALLBACK HelpDlgProc(HWND, UINT, WPARAM, LPARAM); +HWND h_HelpDialog = NULL; + +static INT_PTR CALLBACK StationConfigDlgProc(HWND, UINT, WPARAM, LPARAM); + +void Reset_IFBW(); +void Reset_SAMPLERATE(HWND hwndDlg); +void Reset_DECIMATION(HWND hwndDlg); +void ApplyDecimation(int decValue); +void Update_IFBW(void); + +HWND h_StationConfigDialog = NULL; + +HWND h_SplashScreen = NULL; + +int pll_locked=0; +char FreqoffsetTxt[256]; +char GainReductionTxt[256]; +char AGCsetpointTxt[256]; +char FilenameTxt[256]; + +typedef LONG NTSTATUS; + +#ifndef STATUS_SUCCESS +#define STATUS_SUCCESS ((NTSTATUS)0x00000000L) +#endif + +#ifndef STATUS_BUFFER_TOO_SMALL +#define STATUS_BUFFER_TOO_SMALL ((NTSTATUS)0xC0000023L) +#endif + +std::wstring GetKeyPathFromKKEY(HKEY key) +{ + std::wstring keyPath; + if (key != NULL) + { + HMODULE dll = LoadLibrary("ntdll.dll"); + if (dll != NULL) { + typedef DWORD(__stdcall *NtQueryKeyType)( + HANDLE KeyHandle, + int KeyInformationClass, + PVOID KeyInformation, + ULONG Length, + PULONG ResultLength); + + NtQueryKeyType func = reinterpret_cast(::GetProcAddress(dll, "NtQueryKey")); + + if (func != NULL) { + DWORD size = 0; + DWORD result = 0; + result = func(key, 3, 0, 0, &size); + if (result == STATUS_BUFFER_TOO_SMALL) + { + size = size + 2; + wchar_t* buffer = new (std::nothrow) wchar_t[size / sizeof(wchar_t)]; // size is in bytes + if (buffer != NULL) + { + result = func(key, 3, buffer, size, &size); + if (result == STATUS_SUCCESS) + { + buffer[size / sizeof(wchar_t)] = L'\0'; + keyPath = std::wstring(buffer + 2); + } + delete[] buffer; + } + } + } + FreeLibrary(dll); + } + } + return keyPath; +} + +void string_realloc_and_copy(char **dest, const char *src) +{ + *dest = (char *)realloc(*dest, strlen(src) + 1); + strcpy_s(*dest, strlen(src) + 1, src); +} + +struct station* station_new() +{ + station *s = (station *)malloc(sizeof(station)); + s->days = NULL; + s->freq = NULL; + s->itu = NULL; + s->language = NULL; + s->name = NULL; + s->tac = NULL; + s->time = NULL; + s->next = NULL; + + return s; +} + +void station_free(station *s) +{ + ::free(s->days); + ::free(s->freq); + ::free(s->itu); + ::free(s->language); + ::free(s->name); + ::free(s->tac); + ::free(s->time); + ::free(s->minTime); + ::free(s->maxTime); + ::free(s->next); + ::free(s); +} + +void station_set_freq(station *s, const char *freq) +{ + string_realloc_and_copy(&s->freq, freq); +} + +void station_set_name(station *s, const char *name) +{ + string_realloc_and_copy(&s->name, name); +} + +void station_set_itu(station *s, const char *itu) +{ + string_realloc_and_copy(&s->itu, itu); +} + +void station_set_tac(station *s, const char *tac) +{ + string_realloc_and_copy(&s->tac, tac); +} + +void station_set_time(station *s, const char *time) +{ + string_realloc_and_copy(&s->time, time); +} + +void station_set_days(station *s, const char *days) +{ + string_realloc_and_copy(&s->days, days); +} + +void station_set_MinMaxTimes(station *s, const char *totalTime) +{ + s->minTime[0] = totalTime[0]; + s->minTime[1] = totalTime[1]; + s->minTime[2] = totalTime[2]; + s->minTime[3] = totalTime[3]; + s->minTime[4] = '\0'; + s->maxTime[0] = totalTime[5]; + s->maxTime[1] = totalTime[6]; + s->maxTime[2] = totalTime[7]; + s->maxTime[3] = totalTime[8]; + s->maxTime[4] = '\0'; +} + +bool copyCSVtoHDD(char *filename) +{ + char buffer[BUFFER_LEN]; + struct sockaddr_in serveraddr; + int sock; + + WSADATA wsaData; + USHORT port = 80; + string shost = "www.eibispace.de"; + string request = "GET /dx/sked-b18.csv HTTP/1.1\r\nHost: www.eibispace.de\r\n\r\n"; + + if (WSAStartup(MAKEWORD(2, 0), &wsaData) != 0) + { +#ifdef DEBUG_ENABLE + OutputDebugString("WSAStartup error"); +#endif + return false; + } + + if ((sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) + { +#ifdef DEBUG_ENABLE + OutputDebugString("socket error"); +#endif + return false; + } + + memset(&serveraddr, 0, sizeof(serveraddr)); + + hostent *record = gethostbyname(shost.c_str()); + +#ifdef DEBUG_ENABLE + char tmpString[1024]; + sprintf_s(tmpString, 1024, "%s", record->h_name); + OutputDebugString(tmpString); +#endif + + in_addr *address = (in_addr *)record->h_addr; + string ipd = inet_ntoa(*address); + const char *ipaddr = ipd.c_str(); + + serveraddr.sin_family = AF_INET; + serveraddr.sin_addr.s_addr = inet_addr(ipaddr); + serveraddr.sin_port = htons(port); + + if (connect(sock, (struct sockaddr *) &serveraddr, sizeof(serveraddr)) < 0) + { +#ifdef DEBUG_ENABLE + OutputDebugString("can't connect"); +#endif + localDBExists = false; + if (h_StationConfigDialog != NULL) + Edit_SetText(GetDlgItem(h_StationConfigDialog, IDC_STATIONCONFIG_STATUS), "Database Status: No route to host"); + return false; + } + + if (send(sock, request.c_str(), request.length(), 0) == INVALID_SOCKET) + { +#ifdef DEBUG_ENABLE + OutputDebugString("can't send"); +#endif + return false; + } +// shutdown(sock, SD_SEND); + + int nRecv, npos; + nRecv = recv(sock, (char *)&buffer, BUFFER_LEN, 0); + + if (nRecv == 0) + { +#ifdef DEBUG_ENABLE + OutputDebugString("received 0 bytes header"); +#endif + return false; + } + + if (nRecv == SOCKET_ERROR) + { +#ifdef DEBUG_ENABLE + OutputDebugString("nRecv initial socket error"); +#endif + return false; + } + + string str_buff = buffer; + npos = str_buff.find("\r\n\r\n"); + + HANDLE hFile; + hFile = CreateFileA(filename, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); + if (hFile == INVALID_HANDLE_VALUE) + { +#ifdef DEBUG_ENABLE + OutputDebugString("cannot create file"); +#endif + return false; + } + if (SetFilePointer(hFile, 0, NULL, FILE_BEGIN) != INVALID_SET_FILE_POINTER) + { + DWORD ss; + + while ((nRecv > 0) && (nRecv != INVALID_SOCKET)) + { + if (npos > 0) + { + char bf[BUFFER_LEN]; + memcpy(bf, buffer + (npos + 4), nRecv - (npos + 4)); + if (WriteFile(hFile, bf, nRecv - (npos + 4), &ss, NULL) == 0) + { +#ifdef DEBUG_ENABLE + OutputDebugString("initial write failed"); +#endif + return false; + } + } + else + { + if (WriteFile(hFile, buffer, nRecv, &ss, NULL) == 0) + { +#ifdef DEBUG_ENABLE + OutputDebugString("main write failed"); +#endif + return false; + } + } + + ZeroMemory(&buffer, sizeof(buffer)); + nRecv = recv(sock, (char *)&buffer, BUFFER_LEN, 0); + if (nRecv == SOCKET_ERROR) + { +#ifdef DEBUG_ENABLE + OutputDebugString("nRecv main socket error"); +#endif + return false; + } + str_buff = buffer; + npos = str_buff.find("\r\n\r\n"); + } + + if (nRecv == 0) + { +#ifdef DEBUG_ENABLE + OutputDebugString("nRecv == 0"); +#endif + } + + if (nRecv == INVALID_SOCKET) + { +#ifdef DEBUG_ENABLE + OutputDebugString("nRecv final invalid socket"); +#endif + return false; + } + + localDBExists = true; + if (h_StationConfigDialog != NULL) + Edit_SetText(GetDlgItem(h_StationConfigDialog, IDC_STATIONCONFIG_STATUS), "Database Status: Good"); + + CloseHandle(hFile); + closesocket(sock); + WSACleanup(); + return true; + } + else + { +#ifdef DEBUG_ENABLE + OutputDebugString("file pointer error"); +#endif + CloseHandle(hFile); + closesocket(sock); + WSACleanup(); + return false; + } +} + +#pragma comment(lib, "Shell32.lib") // Windows Shell Library + +bool DirectoryExists(LPCWSTR szPath) +{ + DWORD dwAttrib = GetFileAttributesW(szPath); + + return (dwAttrib != INVALID_FILE_ATTRIBUTES && + (dwAttrib & FILE_ATTRIBUTE_DIRECTORY)); +} + +bool FileExists(const char *filename) +{ + std::ifstream infile(filename); + return infile.good(); +} + +bool FileModifiedToday(char *pFileName) +{ + struct stat attrib; + time_t rawtime; + tm timeinfo; + tm timeinfoNow; + + ::time(&rawtime); + stat(pFileName, &attrib); + + gmtime_s(&timeinfo, &(attrib.st_mtime)); + gmtime_s(&timeinfoNow, &rawtime); + +#ifdef DEBUG_ENABLE + char tmpString[1204]; + sprintf_s(tmpString, 1024, "%d %d %d", (1900 + timeinfo.tm_year), (1 + timeinfo.tm_mon), timeinfo.tm_mday); + OutputDebugString(tmpString); + sprintf_s(tmpString, 1024, "%d %d %d", (1900 + timeinfoNow.tm_year), (1 + timeinfoNow.tm_mon), timeinfoNow.tm_mday); + OutputDebugString(tmpString); +#endif + + if ((timeinfo.tm_year == timeinfoNow.tm_year) && (timeinfo.tm_mon == timeinfoNow.tm_mon) && (timeinfo.tm_mday == timeinfoNow.tm_mday)) + { + return true; + } + return false; +} + +void startupPopUpWindow(void) +{ + h_SplashScreen = CreateWindowEx(WS_EX_CLIENTEDGE, "STATIC", "", WS_POPUP | WS_DLGFRAME, + GetSystemMetrics(SM_CXSCREEN)/2-150, GetSystemMetrics(SM_CYSCREEN)/2-40, 300, 80, NULL, NULL, NULL, NULL); + + SetBkMode((HDC)h_SplashScreen, TRANSPARENT); + HWND label = CreateWindow("static", "label", WS_CHILD | WS_VISIBLE, 20, 20, 260, 20, h_SplashScreen, NULL, NULL, NULL); + SetWindowText(label, "SDRplay ExtIO loading, please wait..."); + SetBkMode((HDC)label, TRANSPARENT); + ShowWindow(h_SplashScreen, SW_SHOWNORMAL); + UpdateWindow(h_SplashScreen); +} + +void closePopUpWindow(void) +{ + if (h_SplashScreen != NULL) + { + ShowWindow(h_SplashScreen, SW_HIDE); + DestroyWindow(h_SplashScreen); + } +} + +extern "C" +void LIBSDRplay_API __stdcall HideGUI() +{ +#ifdef DEBUG_ENABLE + OutputDebugString("HideGUI"); +#endif + int i; + for (i = 1; i <= NUM_OF_HOTKEYS; i++) + { + UnregisterHotKey(h_dialog, i); + } + ShowWindow(h_dialog, SW_HIDE); + definedHotkeys = false; +} + +extern "C" +void LIBSDRplay_API __stdcall StopHW() +{ +#ifdef DEBUG_ENABLE + OutputDebugString("StopHW"); +#endif + Running = false; +#ifdef DEBUG_ENABLE + OutputDebugString("Uninit"); +#endif + sdrplay_api_Uninit_fn(chosenDev->dev); +} + +extern "C" +void LIBSDRplay_API __stdcall CloseHW() +{ +#ifdef DEBUG_ENABLE + OutputDebugString("CloseHW"); +#endif + + SaveSettings(); + + if (h_dialog != NULL) + DestroyWindow(h_dialog); + if (h_AdvancedDialog != NULL) + DestroyWindow(h_AdvancedDialog); + if (h_ProfilesDialog != NULL) + DestroyWindow(h_ProfilesDialog); + if (h_HelpDialog != NULL) + DestroyWindow(h_HelpDialog); + if (h_StationDialog != NULL) + DestroyWindow(h_StationDialog); + if (h_StationConfigDialog != NULL) + DestroyWindow(h_StationConfigDialog); + + if (Running) + { +#ifdef DEBUG_ENABLE + OutputDebugString("Uninit"); +#endif + sdrplay_api_Uninit_fn(chosenDev->dev); + Running = false; + } +#ifdef DEBUG_ENABLE + OutputDebugString("ReleaseDevice"); +#endif + sdrplay_api_ReleaseDevice_fn(chosenDev); +#ifdef DEBUG_ENABLE + OutputDebugString("Close API"); +#endif + sdrplay_api_Close_fn(); +} + +extern "C" +bool LIBSDRplay_API __stdcall InitHW(char *name, char *model, int &type) +{ +#ifdef DEBUG_ENABLE + OutputDebugString("InitHW"); +#endif + char APIkeyValue[8192]; + char tmpStringA[8192]; + char str[1024 + 8192]; + DWORD APIkeyValue_length = 8192; + char APIver[32]; + DWORD APIver_length = 32; + HKEY APIkey; + HKEY Settingskey; + sdrplay_api_ErrT err; + int error, tempRB, tempRB2; + DWORD IntSz = sizeof(int); + WCHAR csvPath[8192]; + + for (int i = GAIN_SLIDER_MIN; i <= GAIN_SLIDER_MAX; i++) + { + gains[i - GAIN_SLIDER_MIN] = i; + } + + if (RegOpenKey(HKEY_LOCAL_MACHINE, TEXT("SOFTWARE\\SDRplay\\Service\\API"), &APIkey) != ERROR_SUCCESS) + { + error = GetLastError(); + _stprintf_s(str, TEXT("Failed to locate API registry entry\nHKEY_LOCAL_MACHINE\\SOFTWARE\\SDRplay\\Service\\API\nERROR %d\n"), error); + MessageBox(NULL, str ,TEXT("SDRplay ExtIO DLL"),MB_ICONERROR | MB_OK); + return false; + } + else + { + RegQueryValueEx(APIkey, "Install_Dir", NULL, NULL, (LPBYTE)&APIkeyValue, &APIkeyValue_length); + RegQueryValueEx(APIkey, "Version", NULL, NULL, (LPBYTE)&APIver, &APIver_length); + sprintf_s(apiVersion, sizeof(apiVersion), APIver); + wcscpy_s(regPath, GetKeyPathFromKKEY(APIkey).c_str()); + RegCloseKey(APIkey); + } + + #ifndef _WIN64 + sprintf_s(tmpStringA, 8192, "%s\\x86\\sdrplay_api.dll", APIkeyValue); + #else + sprintf_s(tmpStringA, 8192, "%s\\x64\\sdrplay_api.dll", APIkeyValue); + #endif + + sprintf_s(apiPath, sizeof(apiPath), "%s", tmpStringA); + + LPCSTR ApiDllName = (LPCSTR)tmpStringA; + + if (ApiDll == NULL) + { + ApiDll = LoadLibrary(ApiDllName); + } + if (ApiDll == NULL) + { + ApiDll = LoadLibrary("sdrplay_api.dll"); + } + if (ApiDll == NULL) + { + error = GetLastError(); + _stprintf_s(str, TEXT("Failed to load API DLL\n%s\nERROR %d\n"), ApiDllName, error); + MessageBox(NULL, str, TEXT("SDRplay ExtIO DLL"), MB_ICONERROR | MB_OK); + return false; + } + + sdrplay_api_Init_fn = (sdrplay_api_Init_t)GetProcAddress(ApiDll, "sdrplay_api_Init"); + sdrplay_api_Uninit_fn = (sdrplay_api_Uninit_t)GetProcAddress(ApiDll, "sdrplay_api_Uninit"); + sdrplay_api_Open_fn = (sdrplay_api_Open_t)GetProcAddress(ApiDll, "sdrplay_api_Open"); + sdrplay_api_Close_fn = (sdrplay_api_Close_t)GetProcAddress(ApiDll, "sdrplay_api_Close"); + sdrplay_api_ApiVersion_fn = (sdrplay_api_ApiVersion_t)GetProcAddress(ApiDll, "sdrplay_api_ApiVersion"); + sdrplay_api_LockDeviceApi_fn = (sdrplay_api_LockDeviceApi_t)GetProcAddress(ApiDll, "sdrplay_api_LockDeviceApi"); + sdrplay_api_UnlockDeviceApi_fn = (sdrplay_api_UnlockDeviceApi_t)GetProcAddress(ApiDll, "sdrplay_api_UnlockDeviceApi"); + sdrplay_api_GetDevices_fn = (sdrplay_api_GetDevices_t)GetProcAddress(ApiDll, "sdrplay_api_GetDevices"); + sdrplay_api_SelectDevice_fn = (sdrplay_api_SelectDevice_t)GetProcAddress(ApiDll, "sdrplay_api_SelectDevice"); + sdrplay_api_ReleaseDevice_fn = (sdrplay_api_ReleaseDevice_t)GetProcAddress(ApiDll, "sdrplay_api_ReleaseDevice"); + sdrplay_api_GetErrorString_fn = (sdrplay_api_GetErrorString_t)GetProcAddress(ApiDll, "sdrplay_api_GetErrorString"); + sdrplay_api_DebugEnable_fn = (sdrplay_api_DebugEnable_t)GetProcAddress(ApiDll, "sdrplay_api_DebugEnable"); + sdrplay_api_GetDeviceParams_fn = (sdrplay_api_GetDeviceParams_t)GetProcAddress(ApiDll, "sdrplay_api_GetDeviceParams"); + sdrplay_api_Update_fn = (sdrplay_api_Update_t)GetProcAddress(ApiDll, "sdrplay_api_Update"); + sdrplay_api_SwapRspDuoActiveTuner_fn = (sdrplay_api_SwapRspDuoActiveTuner_t)GetProcAddress(ApiDll, "sdrplay_api_SwapRspDuoActiveTuner"); + sdrplay_api_SwapRspDuoDualTunerModeSampleRate_fn = (sdrplay_api_SwapRspDuoDualTunerModeSampleRate_t)GetProcAddress(ApiDll, "sdrplay_api_SwapRspDuoDualTunerModeSampleRate"); + + if ((sdrplay_api_Init_fn == NULL) || + (sdrplay_api_Uninit_fn == NULL) || + (sdrplay_api_Open_fn == NULL) || + (sdrplay_api_Close_fn == NULL) || + (sdrplay_api_ApiVersion_fn == NULL) || + (sdrplay_api_LockDeviceApi_fn == NULL) || + (sdrplay_api_UnlockDeviceApi_fn == NULL) || + (sdrplay_api_GetDevices_fn == NULL) || + (sdrplay_api_SelectDevice_fn == NULL) || + (sdrplay_api_ReleaseDevice_fn == NULL) || + (sdrplay_api_GetErrorString_fn == NULL) || + (sdrplay_api_DebugEnable_fn == NULL) || + (sdrplay_api_GetDeviceParams_fn == NULL)|| + (sdrplay_api_Update_fn == NULL)|| + (sdrplay_api_SwapRspDuoActiveTuner_fn == NULL) || + (sdrplay_api_SwapRspDuoDualTunerModeSampleRate_fn == NULL) + ) + { + MessageBox(NULL, TEXT("Failed to map API DLL functions\n"), TEXT("SDRplay ExtIO DLL"), MB_ICONERROR | MB_OK); + FreeLibrary(ApiDll); + return false; + } + +#ifdef DEBUG_ENABLE + OutputDebugString("Open API"); +#endif + err = sdrplay_api_Open_fn(); + if (err != sdrplay_api_Success) + { + OutputDebugString("Cannot connect to API Service"); + MessageBox(NULL, TEXT("Unable to connect to API Service, restart service and try again"), TEXT("SDRplay ExtIO Error"), MB_ICONERROR | MB_OK); + return false; + } + + err = sdrplay_api_LockDeviceApi_fn(); + if (err != sdrplay_api_Success) + { + OutputDebugString("Cannot Lock the API"); + MessageBox(NULL, TEXT("Unable to lock the API"), TEXT("SDRplay ExtIO Error"), MB_ICONERROR | MB_OK); +#ifdef DEBUG_ENABLE + OutputDebugString("Close API"); +#endif + sdrplay_api_Close_fn(); + return false; + } + +#ifdef DEBUG_ENABLE + OutputDebugString("Get Device Information..."); + sdrplay_api_DebugEnable_fn(NULL, (sdrplay_api_DbgLvl_t)RSP_DEBUG); +#endif + bool foundRSPdxR2 = false; + sdrplay_api_GetDevices_fn(devices, &numDevs, MAXNUMOFDEVS); + if (devices != NULL) + { + unsigned int i; + for (i = 0; i < numDevs; i++) + { + _snprintf_s(msgbuf, 1024, "[%d/%d] SerNo=%s hwVer=%d", (i + 1), numDevs, devices[i].SerNo, devices[i].hwVer); + OutputDebugString(msgbuf); + if (devices[i].hwVer == SDRPLAY_RSPdxR2_ID) + { + chosenDevice = i; + chosenDev = &devices[chosenDevice]; + + err = sdrplay_api_SelectDevice_fn(chosenDev); + if (err != sdrplay_api_Success) + { + OutputDebugString("SelectDevice error"); + MessageBox(NULL, TEXT("Cannot open the device"), TEXT("SDRplay ExtIO Error"), MB_ICONERROR | MB_OK); +#ifdef DEBUG_ENABLE + OutputDebugString("UnlockDeviceApi"); +#endif + sdrplay_api_UnlockDeviceApi_fn(); +#ifdef DEBUG_ENABLE + OutputDebugString("Close API"); +#endif + sdrplay_api_Close_fn(); + return false; + } + foundRSPdxR2 = true; +#ifdef DEBUG_ENABLE + OutputDebugString("UnlockDeviceApi"); +#endif + sdrplay_api_UnlockDeviceApi_fn(); + break; + } + } + if (!foundRSPdxR2) { + OutputDebugString("No RSPdxR2s found."); + MessageBox(NULL, TEXT("Failed to find any available RSPdxR2s"), TEXT("SDRplay ExtIO Error"), MB_ICONERROR | MB_OK); +#ifdef DEBUG_ENABLE + OutputDebugString("UnlockDeviceApi"); +#endif + sdrplay_api_UnlockDeviceApi_fn(); +#ifdef DEBUG_ENABLE + OutputDebugString("Close API"); +#endif + sdrplay_api_Close_fn(); + return false; + } + } + else + { +#ifdef DEBUG_ENABLE + OutputDebugString("No RSPs found."); +#endif + MessageBox(NULL, TEXT("Failed to find any RSPs"), TEXT("SDRplay ExtIO Error"), MB_ICONERROR | MB_OK); +#ifdef DEBUG_ENABLE + OutputDebugString("UnlockDeviceApi"); +#endif + sdrplay_api_UnlockDeviceApi_fn(); +#ifdef DEBUG_ENABLE + OutputDebugString("Close API"); +#endif + sdrplay_api_Close_fn(); + return false; + } + + // We have a device at this point +#ifdef DEBUG_ENABLE + sdrplay_api_DebugEnable_fn(devices[chosenDevice].dev, 1); +#endif + + err = sdrplay_api_GetDeviceParams_fn(chosenDev->dev, &deviceParams); + if (err != sdrplay_api_Success) + { + sprintf_s(tmpStringA, "GetDeviceParams error (%s)", sdrplay_api_GetErrorString_fn(err)); + OutputDebugString(tmpStringA); +#ifdef DEBUG_ENABLE + OutputDebugString("UnlockDeviceApi"); +#endif + sdrplay_api_UnlockDeviceApi_fn(); +#ifdef DEBUG_ENABLE + OutputDebugString("Close API"); +#endif + sdrplay_api_Close_fn(); + return false; + } + + chParams = (chosenDev->tuner == sdrplay_api_Tuner_A) ? deviceParams->rxChannelA : deviceParams->rxChannelB; + + error = RegOpenKeyEx(HKEY_CURRENT_USER, TEXT("Software\\SDRplay\\RSPdxR2_Settings"), 0, KEY_ALL_ACCESS, &Settingskey); + if (error == ERROR_SUCCESS) + { + error = RegQueryValueEx(Settingskey, "StationLookup", NULL, NULL, (LPBYTE)&tempRB, &IntSz); + if (error != ERROR_SUCCESS) + { +#ifdef DEBUG_ENABLE + OutputDebugString("Failed to recall saved StationLookup state"); +#endif + stationLookup = false; + } + if (tempRB == 1) + stationLookup = true; + else + stationLookup = false; + + error = RegQueryValueEx(Settingskey, "WorkOffline", NULL, NULL, (LPBYTE)&tempRB2, &IntSz); + if (error != ERROR_SUCCESS) + { +#ifdef DEBUG_ENABLE + OutputDebugString("Failed to recall saved WorkOffline state"); +#endif + workOffline = false; + } + if (tempRB2 == 1) + workOffline = true; + else + workOffline = false; + + + if (stationLookup) + { + if (SUCCEEDED(SHGetFolderPathW(NULL, CSIDL_APPDATA | CSIDL_FLAG_CREATE, NULL, 0, csvPath))) + { + PathAppendW(csvPath, L"\\SDRplay"); + + LPCWSTR csvPathW = csvPath; + if (!DirectoryExists(csvPathW)) + SHCreateDirectory(0, csvPath); + + PathAppendW(csvPath, L"\\sked-b18.csv"); + char *newString = new char[wcslen(csvPath) + 1]; + size_t iSize; + wcstombs_s(&iSize, newString, 8192, csvPath, wcslen(csvPath)); + + if (FileExists(newString)) + { +#ifdef DEBUG_ENABLE + OutputDebugString("csv file exists"); +#endif + localDBExists = true; + if (!FileModifiedToday(newString) && !workOffline) + { +#ifdef DEBUG_ENABLE + OutputDebugString("old file, creating new"); +#endif + startupPopUpWindow(); + if (!copyCSVtoHDD(newString)) + { +#ifdef DEBUG_ENABLE + OutputDebugString("error during copy"); +#endif + localDBExists = false; + if (h_StationConfigDialog != NULL) + Edit_SetText(GetDlgItem(h_StationConfigDialog, IDC_STATIONCONFIG_STATUS), "Database Status: Copy failed"); + } + else + { + localDBExists = true; + if (h_StationConfigDialog != NULL) + Edit_SetText(GetDlgItem(h_StationConfigDialog, IDC_STATIONCONFIG_STATUS), "Database Status: Good"); + } + } + } + else + { +#ifdef DEBUG_ENABLE + OutputDebugString("no file exists"); +#endif + if (workOffline) + { + localDBExists = false; + if (h_StationConfigDialog != NULL) + Edit_SetText(GetDlgItem(h_StationConfigDialog, IDC_STATIONCONFIG_STATUS), "Database Status: No database"); + } + else + { + startupPopUpWindow(); + if (!copyCSVtoHDD(newString)) + { +#ifdef DEBUG_ENABLE + OutputDebugString("error during copy"); +#endif + localDBExists = false; + if (h_StationConfigDialog != NULL) + Edit_SetText(GetDlgItem(h_StationConfigDialog, IDC_STATIONCONFIG_STATUS), "Database Status: Copy failed"); + } + else + { + localDBExists = true; + if (h_StationConfigDialog != NULL) + Edit_SetText(GetDlgItem(h_StationConfigDialog, IDC_STATIONCONFIG_STATUS), "Database Status: Good"); + } + } + } + } + else + MessageBox(NULL, "Error locating local temporary storage", NULL, MB_OK); + } + } + +#ifdef DEBUG_ENABLE + OutputDebugString("Hardware sucessfully initalised & Registry paths found"); +#endif + sprintf_s(name, 32, "%s", "SDRplay RSP"); + sprintf_s(model, 32, "%s", "Radio Spectrum Processor"); + type = 3; + closePopUpWindow(); + return true; +} + +extern "C" +bool LIBSDRplay_API __stdcall OpenHW() +{ +#ifdef DEBUG_ENABLE + OutputDebugString("OpenHW"); +#endif + h_dialog=CreateDialog(hInst, MAKEINTRESOURCE(IDD_SDRPLAY_SETTINGS), NULL, (DLGPROC)MainDlgProc); + ShowWindow(h_dialog, SW_HIDE); + BringWindowToTop(h_dialog); + return true; +} + +extern "C" +long LIBSDRplay_API __stdcall SetHWLO(unsigned long freq) +{ + sdrplay_api_ErrT err; + + #ifdef DEBUG_ENABLE + OutputDebugString("SetHWLO"); + #endif + + #ifdef DEBUG_ENABLE + _snprintf_s(msgbuf, 1024, "%s %lu", "Frequency is", freq); + OutputDebugString(msgbuf); + #endif + WinradCallBack(-1, WINRAD_LOBLOCKED, 0, NULL); + if (freq > 2000000000) + { + MessageBox(NULL, "Warning Out of Range", TEXT("WARNING"), MB_OK | MB_SYSTEMMODAL | MB_TOPMOST | MB_ICONEXCLAMATION); + WinradCallBack(-1, WINRAD_LOCHANGE, 0, NULL); + WinradCallBack(-1, WINRAD_LORELEASED, 0, NULL); + return 2000000000; + } + if (freq < ((UINT)LowerFqLimit * 1000)) + { + MessageBox(NULL, "Warning Out of Range", TEXT("WARNING"), MB_OK | MB_SYSTEMMODAL | MB_TOPMOST | MB_ICONEXCLAMATION); + WinradCallBack(-1, WINRAD_LOCHANGE, 0, NULL); + WinradCallBack(-1, WINRAD_LORELEASED, 0, NULL); + return -100000; + } + + TCHAR LNAGainReductionTxt[255]; + + // if greater than 200 MHz and port C in use, then revert to 50 ohm port + if (freq >= 200000000 && (deviceParams->devParams->rspDxParams.antennaSel == sdrplay_api_RspDx_ANTENNA_C)) + { + // LNA Gain Reduction change limit + AntennaIdx = 0; + ComboBox_SetCurSel(GetDlgItem(h_dialog, IDC_ANTSELECT), AntennaIdx); + SendMessage(GetDlgItem(h_dialog, IDC_LNASLIDER), TBM_SETRANGEMAX, (WPARAM)true, (LPARAM)LNA_GAIN_SLIDER_MAX_0000_0012); + deviceParams->devParams->rspDxParams.antennaSel = sdrplay_api_RspDx_ANTENNA_A; + if (Running) + { + err = sdrplay_api_Update_fn(chosenDev->dev, chosenDev->tuner, sdrplay_api_Update_None, sdrplay_api_Update_RspDx_AntennaControl); + if (err != sdrplay_api_Success) + { + OutputDebugString("Switch To Port A Error"); + } + } + } + + if (freq >= 1000000000) { + if (LNAGainReduction > LNA_GAIN_SLIDER_MAX_1000_2000) + { + LNAGainReduction = LNA_GAIN_SLIDER_MAX_1000_2000; + sprintf_s(LNAGainReductionTxt, 254, "%d", LNAGainReduction); + SendMessage(GetDlgItem(h_dialog, IDC_LNASLIDER), TBM_SETPOS, (WPARAM)true, (LPARAM)LNAGainReduction); + Edit_SetText(GetDlgItem(h_dialog, IDC_LNAGRNO), LNAGainReductionTxt); + } + SendMessage(GetDlgItem(h_dialog, IDC_LNASLIDER), TBM_SETRANGEMAX, (WPARAM)true, (LPARAM)LNA_GAIN_SLIDER_MAX_1000_2000); + } + else if (freq >= 420000000) + { + if (LNAGainReduction > LNA_GAIN_SLIDER_MAX_0420_1000) + { + LNAGainReduction = LNA_GAIN_SLIDER_MAX_0420_1000; + sprintf_s(LNAGainReductionTxt, 254, "%d", LNAGainReduction); + SendMessage(GetDlgItem(h_dialog, IDC_LNASLIDER), TBM_SETPOS, (WPARAM)true, (LPARAM)LNAGainReduction); + Edit_SetText(GetDlgItem(h_dialog, IDC_LNAGRNO), LNAGainReductionTxt); + } + + SendMessage(GetDlgItem(h_dialog, IDC_LNASLIDER), TBM_SETRANGEMAX, (WPARAM)true, (LPARAM)LNA_GAIN_SLIDER_MAX_0420_1000); + } + else if (freq >= 250000000) + { + if (LNAGainReduction > LNA_GAIN_SLIDER_MAX_0250_0420) + { + LNAGainReduction = LNA_GAIN_SLIDER_MAX_0250_0420; + sprintf_s(LNAGainReductionTxt, 254, "%d", LNAGainReduction); + SendMessage(GetDlgItem(h_dialog, IDC_LNASLIDER), TBM_SETPOS, (WPARAM)true, (LPARAM)LNAGainReduction); + Edit_SetText(GetDlgItem(h_dialog, IDC_LNAGRNO), LNAGainReductionTxt); + } + + SendMessage(GetDlgItem(h_dialog, IDC_LNASLIDER), TBM_SETRANGEMAX, (WPARAM)true, (LPARAM)LNA_GAIN_SLIDER_MAX_0250_0420); + } + else if (freq >= 60000000) + { + if (LNAGainReduction > LNA_GAIN_SLIDER_MAX_0060_0250) + { + LNAGainReduction = LNA_GAIN_SLIDER_MAX_0060_0250; + sprintf_s(LNAGainReductionTxt, 254, "%d", LNAGainReduction); + SendMessage(GetDlgItem(h_dialog, IDC_LNASLIDER), TBM_SETPOS, (WPARAM)true, (LPARAM)LNAGainReduction); + Edit_SetText(GetDlgItem(h_dialog, IDC_LNAGRNO), LNAGainReductionTxt); + } + + SendMessage(GetDlgItem(h_dialog, IDC_LNASLIDER), TBM_SETRANGEMAX, (WPARAM)true, (LPARAM)LNA_GAIN_SLIDER_MAX_0060_0250); + } + else if (freq >= 12000000) + { + if (LNAGainReduction > LNA_GAIN_SLIDER_MAX_0012_0060) + { + LNAGainReduction = LNA_GAIN_SLIDER_MAX_0012_0060; + sprintf_s(LNAGainReductionTxt, 254, "%d", LNAGainReduction); + SendMessage(GetDlgItem(h_dialog, IDC_LNASLIDER), TBM_SETPOS, (WPARAM)true, (LPARAM)LNAGainReduction); + Edit_SetText(GetDlgItem(h_dialog, IDC_LNAGRNO), LNAGainReductionTxt); + } + + SendMessage(GetDlgItem(h_dialog, IDC_LNASLIDER), TBM_SETRANGEMAX, (WPARAM)true, (LPARAM)LNA_GAIN_SLIDER_MAX_0012_0060); + } + else // 0 - 12 MHz + { + if (LNAGainReduction > LNA_GAIN_SLIDER_MAX_0000_0012) + { + LNAGainReduction = LNA_GAIN_SLIDER_MAX_0000_0012; + sprintf_s(LNAGainReductionTxt, 254, "%d", LNAGainReduction); + SendMessage(GetDlgItem(h_dialog, IDC_LNASLIDER), TBM_SETPOS, (WPARAM)true, (LPARAM)LNAGainReduction); + Edit_SetText(GetDlgItem(h_dialog, IDC_LNAGRNO), LNAGainReductionTxt); + } + + SendMessage(GetDlgItem(h_dialog, IDC_LNASLIDER), TBM_SETRANGEMAX, (WPARAM)true, (LPARAM)LNA_GAIN_SLIDER_MAX_0000_0012); + } + + //Code to limit Dialog Box Movement + Frequency = (double)freq / 1000000; + + chParams->tunerParams.rfFreq.rfHz = freq; + if (Running) + { + err = sdrplay_api_Update_fn(chosenDev->dev, chosenDev->tuner, sdrplay_api_Update_Tuner_Frf, sdrplay_api_Update_Ext1_None); + if (err != sdrplay_api_Success) + { + OutputDebugString("Frequency program error"); + } + } + + WinradCallBack(-1, WINRAD_LORELEASED, 0, NULL); + return 0; +} + +sdrplay_api_LoModeT GetLoMode(void) +{ + if (LOplanAuto) + { + return sdrplay_api_LO_Auto; +} + else + { + switch (LOplan) + { + case LO120MHz: return sdrplay_api_LO_120MHz; + case LO144MHz: return sdrplay_api_LO_144MHz; + case LO168MHz: return sdrplay_api_LO_168MHz; + default: return sdrplay_api_LO_120MHz; + } + } +} + +void eventCallback(sdrplay_api_EventT eventId, sdrplay_api_TunerSelectT tunerS, sdrplay_api_EventParamsT *params, void *cBContext) +{ + (void *)tunerS; + (void *)cBContext; + char str[512]; + +#ifdef RSP_DEBUG + sprintf_s(str, sizeof(str), "gRdB: %d, lnaGrdB: %d", params->gainParams.gRdB, params->gainParams.lnaGRdB); + OutputDebugString(str); +#endif + + switch (eventId) + { + case sdrplay_api_GainChange: + + if (params->gainParams.gRdB < 200) + { + GainReduction = params->gainParams.gRdB; + sprintf_s(str, sizeof(str), "%d", GainReduction); + Edit_SetText(GetDlgItem(h_dialog, IDC_GR), str); + ActualLNAGR = params->gainParams.lnaGRdB; + SystemGainReduction = GainReduction + ActualLNAGR; + sprintf_s(str, sizeof(str), "Total System Gain Reduction %d dB", SystemGainReduction); + Edit_SetText(GetDlgItem(h_dialog, IDC_TOTALGR), str); + SendMessage(GetDlgItem(h_dialog, IDC_GAINSLIDER), TBM_SETPOS, (WPARAM)true, (LPARAM)GainReduction); + } + break; + case sdrplay_api_PowerOverloadChange: + + sdrplay_api_Update_fn(chosenDev->dev, chosenDev->tuner, sdrplay_api_Update_Ctrl_OverloadMsgAck, sdrplay_api_Update_Ext1_None); + + if (params->powerOverloadParams.powerOverloadChangeType == sdrplay_api_Overload_Detected) + { + OutputDebugString("*** ADC OVERLOAD DETECTED ***"); + sprintf_s(str, sizeof(str), "ADC OVERLOAD"); + Edit_SetText(GetDlgItem(h_dialog, IDC_OVERLOAD), str); + } + else + { + OutputDebugString("*** ADC OVERLOAD CORRECTED ***"); + sprintf_s(str, sizeof(str), ""); + Edit_SetText(GetDlgItem(h_dialog, IDC_OVERLOAD), str); + } + break; + case sdrplay_api_RspDuoModeChange: + + if (params->rspDuoModeParams.modeChangeType == sdrplay_api_SlaveAttached) + { +#ifdef DEBUG_ENABLE + OutputDebugString("Slave Attached"); +#endif + slaveAttached = true; + } + else if (params->rspDuoModeParams.modeChangeType == sdrplay_api_SlaveDetached) + { +#ifdef DEBUG_ENABLE + OutputDebugString("Slave Detatched"); +#endif + slaveAttached = false; + } + else if (params->rspDuoModeParams.modeChangeType == sdrplay_api_MasterInitialised) + { +#ifdef DEBUG_ENABLE + OutputDebugString("Master Initialised"); +#endif + } + else if (params->rspDuoModeParams.modeChangeType == sdrplay_api_SlaveInitialised) + { +#ifdef DEBUG_ENABLE + OutputDebugString("Slave Initialised"); +#endif + } + else if (params->rspDuoModeParams.modeChangeType == sdrplay_api_SlaveUninitialised) + { +#ifdef DEBUG_ENABLE + OutputDebugString("Slave Uninitialised"); +#endif + } + else if (params->rspDuoModeParams.modeChangeType == sdrplay_api_SlaveDllDisappeared) + { +#ifdef DEBUG_ENABLE + OutputDebugString("Slave Dll Disappeared"); +#endif + slaveAttached = false; + } + else if (params->rspDuoModeParams.modeChangeType == sdrplay_api_MasterDllDisappeared) + { +#ifdef DEBUG_ENABLE + OutputDebugString("Master Dll Disappeared"); +#endif + WinradCallBack(-1, WINRAD_STOP, 0, NULL); + HideGUI(); + StopHW(); + CloseHW(); + MessageBox(NULL, "The master stream no longer exists, which means that this slave stream has been stopped and the slave application will need to be closed before the stream can be restarted. This has probably occurred because the master application has either been closed or has crashed. Please always ensure that the slave application is closed before closing down or killing the master application.\n\nWarning: Trying to restart this stream could result in an error or an application crash", TEXT("Master tuner application closed"), MB_OK | MB_SYSTEMMODAL | MB_TOPMOST | MB_ICONEXCLAMATION); + } + break; + case sdrplay_api_DeviceRemoved: + if (Running) + { + Running = false; +#ifdef DEBUG_ENABLE + OutputDebugString("Uninit"); +#endif + sdrplay_api_Uninit_fn(chosenDev->dev); + } + break; + } +} + +void sdrplayCallbackA(short *xi, short *xq, sdrplay_api_StreamCbParamsT *params, unsigned int numSamples, unsigned int reset, void *cbContext) +{ + (void *)cbContext; + (void *)params; + int i; + int j; + int rem; + int DataCount = numSamples << 1; + static unsigned int lastNumSamps = 0; + + if (reset) + { +#ifdef DEBUG_ENABLE + char m_str[1024]; + sprintf_s(m_str, sizeof(m_str), "sdrplayCallbackA: %d", numSamples); + OutputDebugString(m_str); +#endif + BufferCounter = 0; + } + + //Interleave samples + for (i = 0, j = 0; i < DataCount; i += 2, j++) + { + IQBuffer[i] = xi[j]; + IQBuffer[i + 1] = xq[j]; + } + + //Fill the callback buffer + for (i = 0; i < DataCount;) + { + rem = DataCount - i; + if ((BufferCounter == 0) && (rem >= buffer_len_samples)) + { + // no need to copy, if CallbackBuffer empty and i .. i+buffer_len_samples <= DataCount + // this case looks impossible when DataCount = 504 ! + WinradCallBack(buffer_len_samples / 2, 0, 0, (void*)(&IQBuffer[i])); + i += buffer_len_samples; + } + else if ((BufferCounter + rem) >= buffer_len_samples) + { + // CallbackBuffer[] will be filled => and WinradCallBack() can be called + rem = buffer_len_samples - BufferCounter; + memcpy(&CallbackBuffer[BufferCounter], &IQBuffer[i], rem << 1); + WinradCallBack(buffer_len_samples / 2, 0, 0, (void*)CallbackBuffer); + i += rem; + BufferCounter = 0; + } + else // if (BufferCounter + rem < buffer_len_samples) + { + // no chance to fill CallbackBuffer[] + memcpy(&CallbackBuffer[BufferCounter], &IQBuffer[i], rem << 1); + BufferCounter += rem; + i += rem; + } + } + return; +} + +void sdrplayCallbackB(short *xi, short *xq, sdrplay_api_StreamCbParamsT *params, unsigned int numSamples, unsigned int reset, void *cbContext) +{ + (void *)cbContext; + (void *)params; + int i; + int j; + int rem; + int DataCount = numSamples << 1; + static unsigned int lastNumSamps = 0; + + if (reset) + { +#ifdef DEBUG_ENABLE + char m_str[1024]; + sprintf_s(m_str, sizeof(m_str), "sdrplayCallbackA: %d", numSamples); + OutputDebugString(m_str); +#endif + BufferCounter = 0; + } + + //Interleave samples + for (i = 0, j = 0; i < DataCount; i += 2, j++) + { + IQBuffer[i] = xi[j]; + IQBuffer[i + 1] = xq[j]; + } + + //Fill the callback buffer + for (i = 0; i < DataCount;) + { + rem = DataCount - i; + if ((BufferCounter == 0) && (rem >= buffer_len_samples)) + { + // no need to copy, if CallbackBuffer empty and i .. i+buffer_len_samples <= DataCount + // this case looks impossible when DataCount = 504 ! + WinradCallBack(buffer_len_samples / 2, 0, 0, (void*)(&IQBuffer[i])); + i += buffer_len_samples; + } + else if ((BufferCounter + rem) >= buffer_len_samples) + { + // CallbackBuffer[] will be filled => and WinradCallBack() can be called + rem = buffer_len_samples - BufferCounter; + memcpy(&CallbackBuffer[BufferCounter], &IQBuffer[i], rem << 1); + WinradCallBack(buffer_len_samples / 2, 0, 0, (void*)CallbackBuffer); + i += rem; + BufferCounter = 0; + } + else // if (BufferCounter + rem < buffer_len_samples) + { + // no chance to fill CallbackBuffer[] + memcpy(&CallbackBuffer[BufferCounter], &IQBuffer[i], rem << 1); + BufferCounter += rem; + i += rem; + } + } + return; +} + +extern "C" +bool LIBSDRplay_API __stdcall IQCompensation(bool Enable) +{ + sdrplay_api_ErrT Error; +#ifdef DEBUG_ENABLE + OutputDebugString("IQCompensation"); + char *errString = NULL; +#endif + + chParams->ctrlParams.dcOffset.DCenable = (unsigned int)Enable; + chParams->ctrlParams.dcOffset.IQenable = (unsigned int)Enable; + Error = sdrplay_api_Update_fn(chosenDev->dev, chosenDev->tuner, sdrplay_api_Update_Ctrl_DCoffsetIQimbalance, sdrplay_api_Update_Ext1_None); + if (Error != sdrplay_api_Success) + { +#ifdef DEBUG_ENABLE + sprintf_s(errString, 1024, "Enable/Disable DC/IQ Correction Failed (%s)", sdrplay_api_GetErrorString_fn(Error)); + OutputDebugString(errString); +#endif + return false; + } + return true; +} + +extern "C" +int LIBSDRplay_API __stdcall StartHW(unsigned long freq) +{ + double sampleRateLocal; + char str[255]; +#ifdef DEBUG_ENABLE + OutputDebugString("StartHW"); +#endif + + if (freq > 2000000000) + { + MessageBox(NULL, "Warning Out of Range", TEXT("WARNING"), MB_OK | MB_SYSTEMMODAL | MB_TOPMOST | MB_ICONEXCLAMATION); + WinradCallBack(-1, WINRAD_LOCHANGE, 0, NULL); + return -1; + } + if (freq < ((UINT)LowerFqLimit * 1000)) + { + MessageBox(NULL, "Warning Out of Range", TEXT("WARNING"), MB_OK | MB_SYSTEMMODAL | MB_TOPMOST | MB_ICONEXCLAMATION); + WinradCallBack(-1, WINRAD_LOCHANGE, 0, NULL); + return -1; + } + sdrplay_api_DebugEnable_fn(chosenDev->dev, (sdrplay_api_DbgLvl_t)RSP_DEBUG); + chParams->tunerParams.loMode = GetLoMode(); + deviceParams->devParams->ppm = (float)FqOffsetPPM; + +#ifdef DEBUG_ENABLE + OutputDebugString("Calling Init"); +#endif + + if (Frequency >= 200.0 && AntennaIdx == 2) // i.e. greater than 200MHz and port C in use, then revert to port A + { + // LNA Gain Reduction change limit + + AntennaIdx = 0; + ComboBox_SetCurSel(GetDlgItem(h_dialog, IDC_ANTSELECT), AntennaIdx); + SendMessage(GetDlgItem(h_dialog, IDC_LNASLIDER), TBM_SETRANGEMAX, (WPARAM)true, (LPARAM)LNA_GAIN_SLIDER_MAX_0000_0012); + deviceParams->devParams->rspDxParams.antennaSel = sdrplay_api_RspDx_ANTENNA_A; + } + + sampleRateLocal = samplerates[SampleRateIdx].value; + + if (GainReduction < 20) GainReduction = 20; + chParams->tunerParams.gain.gRdB = GainReduction; + chParams->tunerParams.gain.LNAstate = (unsigned char)LNAGainReduction; + + if (IFMode == sdrplay_api_IF_Zero) + deviceParams->devParams->fsFreq.fsHz = sampleRateLocal * 1e6; + else + deviceParams->devParams->fsFreq.fsHz = 6000000.0; + + chParams->tunerParams.bwType = Bandwidth; + chParams->tunerParams.ifType = IFMode; + chParams->tunerParams.rfFreq.rfHz = freq; + chParams->tunerParams.dcOffsetTuner.dcCal = (unsigned char)DcCompensationMode; + chParams->tunerParams.dcOffsetTuner.speedUp = 0; + chParams->ctrlParams.decimation.enable = (unsigned char)DecimateEnable; + chParams->ctrlParams.decimation.decimationFactor = (unsigned char)Decimation[DecimationIdx].DecValue; + if (chParams->ctrlParams.decimation.decimationFactor == 0) + chParams->ctrlParams.decimation.decimationFactor = 1; + chParams->ctrlParams.decimation.wideBandSignal = 1; + chParams->ctrlParams.agc.enable = (sdrplay_api_AgcControlT)AGCEnabled; + chParams->ctrlParams.agc.setPoint_dBfs = AGCsetpoint; + + cbFns.StreamACbFn = sdrplayCallbackA; + cbFns.StreamBCbFn = sdrplayCallbackB; + cbFns.EventCbFn = eventCallback; + + if (!Running) + { + sdrplay_api_ErrT err = sdrplay_api_Init_fn(chosenDev->dev, &cbFns, NULL); + +#ifdef DEBUG_ENABLE + OutputDebugString("sdrplay_api_Init_fn completed"); +#endif + if (err == sdrplay_api_Success) + { + Running = true; + IQCompensation(PostTunerDcCompensation); + return buffer_len_samples / 2; + } + else + { + sprintf_s(str, 255, "sdrplay_api_Init Error (%s)", sdrplay_api_GetErrorString_fn(err)); + OutputDebugString(str); + } + return 0; + } + else + { + return buffer_len_samples / 2; + } +} + +extern "C" +long LIBSDRplay_API __stdcall GetHWLO() +{ +#ifdef DEBUG_ENABLE + OutputDebugString("GetHWLO"); +#endif + long returnfreq = (long)(Frequency * 1000000.0 ); + return returnfreq; +} + +extern "C" +long LIBSDRplay_API __stdcall GetTune() +{ +#ifdef DEBUG_ENABLE + OutputDebugString("GetTune"); +#endif + long returnfreq = (long)(Frequency * 1000000.0); + return returnfreq; +} + +#pragma comment(lib, "ws2_32.lib") // Winsock Library + +void station_copy(station *dest, station *src) +{ + strcpy_s(dest->days, strlen(src->days) + 1, src->days); + strcpy_s(dest->freq, strlen(src->freq) + 1, src->freq); + strcpy_s(dest->itu, strlen(src->itu) + 1, src->itu); + strcpy_s(dest->language, strlen(src->language) + 1, src->language); + strcpy_s(dest->name, strlen(src->name) + 1, src->name); + strcpy_s(dest->tac, strlen(src->tac) + 1, src->tac); + strcpy_s(dest->time, strlen(src->time) + 1, src->time); +} + +char * dayOfTheWeek() +{ + const string DAY[] = { "Su", "Mo", "Tu", "We", "Th", "Fr", "Sa" }; + char *ret = NULL; + time_t rawtime; + tm timeinfo; + ::time(&rawtime); + gmtime_s(&timeinfo, &rawtime); + + int wday = timeinfo.tm_wday; + + sprintf_s(ret, 4, "%s", DAY[wday].c_str()); + + return ret; +} + +char * mystrsep(char **stringp, const char *delim) +{ + char *s; + const char *spanp; + int c, sc; + char *tok; + + if ((s = *stringp) == NULL) + return (NULL); + for (tok = s;;) + { + c = *s++; + spanp = delim; + do { + if ((sc = *spanp++) == c) + { + if (c == 0) + s = NULL; + else + s[-1] = 0; + *stringp = s; + return (tok); + } + } while (sc != 0); + } +} + +char * getfield(char *line, int num) +{ + char *stringp; + char *token; + int i = 1; + + stringp = line; + while (stringp != NULL) { + token = mystrsep(&stringp, ";"); + if (i == num) + return token; + i++; + } + return ""; +} + +bool checkStationTimes(char *min, char *max, char *loc) +{ + int minInt = stoi(min); + int maxInt = stoi(max); + int locInt = stoi(loc); + bool isOn = false; +#ifdef DEBUG_ENABLE + char tmpString[1024]; + sprintf_s(tmpString, 1024, "min: %d, loc: %d, max: %d", minInt, locInt, maxInt); + OutputDebugString(tmpString); +#endif + + if (maxInt > minInt) + { + if ((locInt >= minInt) && (locInt < maxInt)) + isOn = true; + } + else + { + if (((locInt >= minInt) && (locInt < 2400)) || ((locInt >= 0) && (locInt < maxInt))) + isOn = true; + } + return isOn; +} + +char * parseCSV(long freq) +{ + char line[1024]; + char localFreq[16]; + errno_t err; + FILE *stream; + int stationsFound = 0; + struct station *ptr = NULL, *head = NULL, *curr = NULL; + struct station *tacPtr = NULL, *tacHead = NULL, *tacCurr = NULL; + struct station *ituPtr = NULL, *ituHead = NULL, *ituCurr = NULL; + struct station *timePtr = NULL, *timeHead = NULL, *timeCurr = NULL; + struct station *dayPtr = NULL, *dayHead = NULL, *dayCurr = NULL; + char *tacConfig; + char *ituConfig; + int tacConfigIndex = 0; + int ituConfigIndex = 0; + int tacMatched = 0; + int ituMatched = 0; + int timeMatched = 0; + int dayMatched = 0; + char *ret = NULL; + char tacC[10], tacN[10], tacE[10], tacS[10], tacW[10]; + TCHAR csvPath[8192]; + static char retString[1024]; + +#ifdef DEBUG_ENABLE + char tmpStringA[1024]; + OutputDebugString("parseCSV"); +#endif + + sprintf_s(localFreq, 16, "%d", (int)(freq/1000)); + stationTTipText[0] = NULL; + displayStationTip = false; + + if (h_StationConfigDialog != NULL) + { + tacConfigIndex = ComboBox_GetCurSel(GetDlgItem(h_StationConfigDialog, IDC_STATIONCONFIG_TAC)); + ituConfigIndex = ComboBox_GetCurSel(GetDlgItem(h_StationConfigDialog, IDC_STATIONCONFIG_ITU)); + tacConfig = targetAreaCodes[tacConfigIndex].targetAreaCode; + ituConfig = ituCodes[ituConfigIndex].ituCode; + } + else + { + tacConfig = targetAreaCodes[0].targetAreaCode; + ituConfig = ituCodes[0].ituCode; + } + + if (SUCCEEDED(SHGetFolderPath(NULL, CSIDL_APPDATA | CSIDL_FLAG_CREATE, NULL, 0, csvPath))) + { + PathAppend(csvPath, TEXT("\\SDRplay")); + PathAppend(csvPath, TEXT("\\sked-b18.csv")); + } + else + { + MessageBox(NULL, "Error locating local temporary folder", NULL, MB_OK); + return "DB Error 1"; + } + + if ((err = fopen_s(&stream, csvPath, "r")) != 0) + { +#ifdef DEBUG_ENABLE + OutputDebugString("cannot open file"); +#endif + localDBExists = false; + return "DB Error 2"; + } + + while (fgets(line, 1024, stream)) + { + char *tmp0 = _strdup(line); + char *tmp1 = _strdup(line); + char *tmp2 = _strdup(line); + char *tmp3 = _strdup(line); + char *tmp4 = _strdup(line); + char *tmp5 = _strdup(line); + char *tmp7 = _strdup(line); + char *freqField = getfield(tmp0, 1); // frequency + + if (strcmp(freqField, localFreq) == 0) + { + ptr = station_new(); + station_set_tac(ptr, getfield(tmp7, 7)); + station_set_name(ptr, getfield(tmp5, 5)); + station_set_itu(ptr, getfield(tmp4, 4)); + station_set_days(ptr, getfield(tmp3, 3)); + station_set_time(ptr, getfield(tmp2, 2)); + station_set_freq(ptr, getfield(tmp1, 1)); + +#ifdef DEBUG_ENABLE + sprintf_s(tmpStringA, 1024, "Freq match: station %d, Freq: %s, Name: %s, TAC: %s", stationsFound, ptr->freq, ptr->name, ptr->tac); + OutputDebugString(tmpStringA); +#endif + if (stationsFound == 0) + head = curr = ptr; + else + { + curr->next = ptr; + curr = ptr; + } + stationsFound++; + } + ::free(tmp0); + ::free(tmp1); + ::free(tmp2); + ::free(tmp3); + ::free(tmp4); + ::free(tmp5); + ::free(tmp7); + ::free(freqField); + } + fclose(stream); + + if (stationsFound == 0) + { +#ifdef DEBUG_ENABLE + OutputDebugString("no station found"); +#endif + // no station found, return empty + return "No Station Found"; + } + if (strcmp(targetAreaCodes[tacConfigIndex].targetAreaCode, "ZZZ") != 0) // if no TAC selected then skip matching + { +#ifdef DEBUG_ENABLE + OutputDebugString("start tac match"); +#endif + sprintf_s(tacC, 5, "C%s", tacConfig); + sprintf_s(tacN, 5, "N%s", tacConfig); + sprintf_s(tacE, 5, "E%s", tacConfig); + sprintf_s(tacS, 5, "S%s", tacConfig); + sprintf_s(tacW, 5, "W%s", tacConfig); + + ptr = head; + while (ptr != NULL) + { + if ((strcmp(ptr->tac, tacConfig) == 0) || (strcmp(ptr->tac, tacC) == 0) || (strcmp(ptr->tac, tacN) == 0) + || (strcmp(ptr->tac, tacE) == 0) || (strcmp(ptr->tac, tacS) == 0) || (strcmp(ptr->tac, tacW) == 0) + || (strcmp(ptr->tac, ituConfig) == 0)) // perform TAC match filter + { +#ifdef DEBUG_ENABLE + sprintf_s(tmpStringA, 1024, "TAC match: station %d, Freq: %s, Name: %s, TAC: %s", tacMatched, ptr->freq, ptr->name, ptr->tac); + OutputDebugString(tmpStringA); +#endif + tacPtr = station_new(); + station_set_tac(tacPtr, ptr->tac); + station_set_name(tacPtr, ptr->name); + station_set_itu(tacPtr, ptr->itu); + station_set_days(tacPtr, ptr->days); + station_set_time(tacPtr, ptr->time); + station_set_freq(tacPtr, ptr->freq); + + if (tacMatched == 0) + tacHead = tacCurr = tacPtr; + else + { + tacCurr->next = tacPtr; + tacCurr = tacPtr; + } + tacMatched++; + } + ptr = ptr->next; + } +// if (tacMatched == 1) +// { +//#ifdef DEBUG_ENABLE +// OutputDebugString("only 1 tac match"); +//#endif +// ret = tacHead->name; +//// station_free(tacHead); +//// station_free(tacCurr); +//// station_free(tacPtr); +// return ret; +// } + } // end TAC matching + + if (strcmp(ituCodes[ituConfigIndex].ituCode, "ZZZ") != 0) // if no ITU selewted then skip matching + { +#ifdef DEBUG_ENABLE + OutputDebugString("start itu match"); +#endif + if (tacMatched > 0) + ptr = tacHead; + else + ptr = head; + + while (ptr != NULL) + { + if (strcmp(ptr->itu, ituConfig) == 0) + { + ituPtr = station_new(); + station_set_tac(ituPtr, ptr->tac); + station_set_name(ituPtr, ptr->name); + station_set_itu(ituPtr, ptr->itu); + station_set_days(ituPtr, ptr->days); + station_set_time(ituPtr, ptr->time); + station_set_freq(ituPtr, ptr->freq); +#ifdef DEBUG_ENABLE + sprintf_s(tmpStringA, 1024, "ITU match: station %d, Freq: %s, Name: %s, ITU: %s", ituMatched, ptr->freq, ptr->name, ptr->itu); + OutputDebugString(tmpStringA); +#endif + if (ituMatched == 0) + ituHead = ituCurr = ituPtr; + else + { + ituCurr->next = ituPtr; + ituCurr = ituPtr; + } + ituMatched++; + } + ptr = ptr->next; + } +// if (ituMatched == 1) +// { +//#ifdef DEBUG_ENABLE +// OutputDebugString("only 1 itu match"); +//#endif +// ret = ituHead->name; +//// station_free(ituHead); +//// station_free(ituCurr); +//// station_free(ituPtr); +// return ret; +// } // end ITU matching + } + + if (tacMatched > 0) + ptr = tacHead; + else if (ituMatched > 0) + ptr = ituHead; + else + ptr = head; + time_t epoch_time = ::time(NULL); + tm tm_p; + ::time(&epoch_time); + gmtime_s(&tm_p, &epoch_time); + + char locTime[5]; + sprintf_s(locTime, 5, "%d%02d", tm_p.tm_hour, tm_p.tm_min); + +#ifdef DEBUG_ENABLE + OutputDebugString(locTime); +#endif + while (ptr != NULL) + { + station_set_MinMaxTimes(ptr, ptr->time); + + if (checkStationTimes(ptr->minTime, ptr->maxTime, locTime)) + { + timePtr = station_new(); + station_set_tac(timePtr, ptr->tac); + station_set_name(timePtr, ptr->name); + station_set_itu(timePtr, ptr->itu); + station_set_days(timePtr, ptr->days); + station_set_time(timePtr, ptr->time); + station_set_freq(timePtr, ptr->freq); +#ifdef DEBUG_ENABLE + sprintf_s(tmpStringA, 1024, "Time match: station %d, Freq: %s, Name: %s, Time Min: %s, Loc Time: %s, Time Max: %s", timeMatched, ptr->freq, ptr->name, ptr->minTime, locTime, ptr->maxTime); + OutputDebugString(tmpStringA); +#endif + if (timeMatched == 0) + timeHead = timeCurr = timePtr; + else + { + timeCurr->next = timePtr; + timeCurr = timePtr; + } + timeMatched++; + } + ptr = ptr->next; + } + + if (timeMatched == 0) + { +#ifdef DEBUG_ENABLE + OutputDebugString("no station found"); +#endif + // no station found, return empty + return "No Station Found"; + } + else if (timeMatched == 1) + { +#ifdef DEBUG_ENABLE + OutputDebugString("only 1 time match"); +#endif + ret = timeHead->name; +// station_free(timeHead); +// station_free(timeCurr); +// station_free(timePtr); + return ret; + } // end time matching + + // day match - disable for now + bool runNow = false; + if (runNow) + { + ptr = timeHead; + + while (ptr != NULL) + { + if (strlen(ptr->days) < 1) + { + dayPtr = station_new(); + station_set_tac(dayPtr, ptr->tac); + station_set_name(dayPtr, ptr->name); + station_set_itu(dayPtr, ptr->itu); + station_set_days(dayPtr, ptr->days); + station_set_time(dayPtr, ptr->time); + station_set_freq(dayPtr, ptr->freq); +#ifdef DEBUG_ENABLE + sprintf_s(tmpStringA, 1024, "Day match: station %d, Freq: %s, Name: %s, Days: %s", dayMatched, ptr->freq, ptr->name, ptr->days); + OutputDebugString(tmpStringA); +#endif + if (dayMatched == 0) + dayHead = dayCurr = dayPtr; + else + { + dayCurr->next = dayPtr; + dayCurr = dayPtr; + } + dayMatched++; + } + ptr = ptr->next; + } + + if (dayMatched == 0) + { +#ifdef DEBUG_ENABLE + OutputDebugString("no station found"); +#endif + // no station found, return empty + return "No Station Found"; + } + else if (dayMatched == 1) + { +#ifdef DEBUG_ENABLE + OutputDebugString("only 1 day match"); +#endif + ret = dayHead->name; +// station_free(dayHead); +// station_free(dayCurr); +// station_free(dayPtr); + return ret; + } // end day matching + } + +#ifdef DEBUG_ENABLE + OutputDebugString("last resort"); +#endif + if (timeMatched > 1) + { + sprintf_s(retString, 1024, "%d stations found", timeMatched); + displayStationTip = true; + + ptr = timeHead; + int count = 0; + while (ptr != NULL) + { + if (count != 0) + strcat_s(stationTTipText, sizeof(stationTTipText), ", "); + strcat_s(stationTTipText, sizeof(stationTTipText), ptr->name); + ptr = ptr->next; + count++; + } + return retString; + } + else + { + ret = timeHead->name; +// station_free(timeHead); +// station_free(timeCurr); +// station_free(timePtr); + return ret; // last resort, pick the first station in the time list + } +// } +} + +extern "C" +void LIBSDRplay_API __stdcall TuneChanged(long vfoFreq) +{ +#ifdef DEBUG_ENABLE + OutputDebugString("TuneChanged"); +#endif + char stationName[256]; + static HWND hwndTip1 = NULL; + static HWND hwndTip2 = NULL; + static HWND hwndTool1 = NULL; + static HWND hwndTool2 = NULL; + static TOOLINFO toolInfo1; + static TOOLINFO toolInfo2; + char *result; + + if (stationLookup && localDBExists) + { + result = parseCSV(vfoFreq); + sprintf_s(stationName, 256, "Station: %s", result); +#ifdef DEBUG_ENABLE + OutputDebugString(stationName); +#endif + if (h_dialog != NULL) + { + hwndTool1 = GetDlgItem(h_dialog, IDC_STATIONNAME); + Edit_SetText(hwndTool1, stationName); + } + + if (h_StationDialog != NULL) + { + hwndTool2 = GetDlgItem(h_StationDialog, IDC_STATION_LABEL); + Edit_SetText(hwndTool2, stationName); + } + + if (displayStationTip && (hwndTip1 == NULL)) + hwndTip1 = CreateWindowEx(NULL, TOOLTIPS_CLASS, NULL, WS_POPUP | TTS_ALWAYSTIP, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, + h_dialog, NULL, hInst, NULL); + if (displayStationTip && (hwndTip2 == NULL)) + hwndTip2 = CreateWindowEx(NULL, TOOLTIPS_CLASS, NULL, WS_POPUP | TTS_ALWAYSTIP, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, + h_StationDialog, NULL, hInst, NULL); + + toolInfo1 = { 0 }; + toolInfo1.cbSize = sizeof(toolInfo1); + toolInfo1.hwnd = h_dialog; + toolInfo1.uFlags = TTF_IDISHWND | TTF_SUBCLASS; + toolInfo1.uId = (UINT_PTR)hwndTool1; + toolInfo1.lpszText = stationTTipText; + if (displayStationTip) + { + SendMessage(hwndTip1, TTM_ADDTOOL, 0, (LPARAM)&toolInfo1); + } + else + { + SendMessage(hwndTip1, TTM_DELTOOL, 0, (LPARAM)&toolInfo1); + DestroyWindow(hwndTip1); + hwndTip1 = NULL; + } + + toolInfo2 = { 0 }; + toolInfo2.cbSize = sizeof(toolInfo2); + toolInfo2.hwnd = h_StationDialog; + toolInfo2.uFlags = TTF_IDISHWND | TTF_SUBCLASS; + toolInfo2.uId = (UINT_PTR)hwndTool2; + toolInfo2.lpszText = stationTTipText; + if (displayStationTip) + { + SendMessage(hwndTip2, TTM_ADDTOOL, 0, (LPARAM)&toolInfo2); + } + else + { + SendMessage(hwndTip2, TTM_DELTOOL, 0, (LPARAM)&toolInfo2); + DestroyWindow(hwndTip2); + hwndTip2 = NULL; + } + } + else + { + sprintf_s(stationName, 256, "Station: Disabled"); + if (h_dialog != NULL) + Edit_SetText(GetDlgItem(h_dialog, IDC_STATIONNAME), stationName); + if (h_StationDialog != NULL) + Edit_SetText(GetDlgItem(h_StationDialog, IDC_STATION_LABEL), stationName); + } +} + +extern "C" +char LIBSDRplay_API __stdcall GetMode(void) +{ +#ifdef DEBUG_ENABLE + OutputDebugString("GetMode"); +#endif + return demodMode; +} + +extern "C" +void LIBSDRplay_API __stdcall ModeChanged(char) +{ +#ifdef DEBUG_ENABLE + OutputDebugString("ModeChanged"); +#endif + return; +} + +extern "C" +long LIBSDRplay_API __stdcall GetHWSR() +{ + TCHAR str[255]; +#ifdef DEBUG_ENABLE + OutputDebugString("GetHWSR"); + sprintf_s(str, 255, "SampleRateIdx: %d", SampleRateIdx); + OutputDebugString(str); +#endif + long SR = (long)(2.0 * 1e6); + + if (IFmodeIdx == 1) + { + if (DecimateEnable == 1 && (DecimationIdx > 0)) + { + SR = SR / Decimation[DecimationIdx].DecValue; + } + } + else + { + SR = (long)(samplerates[SampleRateIdx].value * 1e6); + if (DecimateEnable == 1 && (DecimationIdx > 0)) + { + SR = SR / Decimation[DecimationIdx].DecValue; + } + } +#ifdef DEBUG_ENABLE + sprintf_s(str, 255, "SR: %d", SR); + OutputDebugString(str); +#endif + sprintf_s(str, sizeof(str), "%.2f MHz", (SR / 1e6)); + Edit_SetText(GetDlgItem(h_dialog, IDC_FINALSR), str); + return SR; +} + +extern "C" +int LIBSDRplay_API __stdcall ExtIoGetSrates(int srate_idx, double *samplerate) +{ +#ifdef DEBUG_ENABLE + OutputDebugString("ExtIoGetSrates"); +#endif + if (srate_idx < (sizeof(samplerates) / sizeof(samplerates[0]))) + { + *samplerate = samplerates[srate_idx].value * 1000000; + return 0; + } + return 1; // ERROR +} + +extern "C" +int LIBSDRplay_API __stdcall ExtIoGetActualSrateIdx(void) +{ +#ifdef DEBUG_ENABLE + OutputDebugString("ExtIoGetActualSrateIdx"); +#endif + return 0; +} + +extern "C" +int LIBSDRplay_API __stdcall ExtIoSetSrate(int) +{ +#ifdef DEBUG_ENABLE + OutputDebugString("ExtIoSetSrate"); +#endif + return 1; // ERROR +} + +extern "C" +int LIBSDRplay_API __stdcall GetAttenuators(int atten_idx, float *attenuation) +{ +#ifdef DEBUG_ENABLE + OutputDebugString("GetAttenuators"); +#endif + if (atten_idx < n_gains) + { + *attenuation = gains[atten_idx] * 1.0f; + return 0; + } + return 1; // End or Error +} + +extern "C" +int LIBSDRplay_API __stdcall GetActualAttIdx(void) +{ +#ifdef DEBUG_ENABLE + OutputDebugString("GetActualAttIdx"); +#endif + for (int i = 0; i < n_gains; i++) + if (last_gain == gains[i]) + return i; + return -1; +} + +extern "C" +int LIBSDRplay_API __stdcall SetAttenuator(int atten_idx) +{ +#ifdef DEBUG_ENABLE + OutputDebugString("SetAttenuator"); +#endif + if (atten_idx < 0 || atten_idx >= n_gains) + return -1; + + int pos = gains[atten_idx]; + + if (!AGCEnabled) + { + if (pos != last_gain) + { + GainReduction = pos; + sprintf_s(GainReductionTxt, 254, "%d", GainReduction); + Edit_SetText(GetDlgItem(h_dialog, IDC_GR), GainReductionTxt); + SendMessage(GetDlgItem(h_dialog, IDC_GAINSLIDER), TBM_SETPOS, (WPARAM)true, (LPARAM)GainReduction); + last_gain = pos; + } + } + return 0; +} + +extern "C" +int LIBSDRplay_API __stdcall ExtIoGetAGCs(int, char *) +{ +#ifdef DEBUG_ENABLE + OutputDebugString("ExtIoGetAGCs"); +#endif + //To DO + return 1; // ERROR +} + +extern "C" +int LIBSDRplay_API __stdcall ExtIoGetActualAGCidx(void) +{ +#ifdef DEBUG_ENABLE + OutputDebugString("ExtIoGetActualAGCidx"); +#endif + // To do + return 0; +} + +extern "C" +int LIBSDRplay_API __stdcall ExtIoSetAGC(int) +{ +#ifdef DEBUG_ENABLE + OutputDebugString("ExtIoSetAGC"); +#endif + //To do + return 1; // ERROR +} + +extern "C" +int LIBSDRplay_API __stdcall ExtIoGetSetting(int idx, char *description, char *value) +{ +#ifdef DEBUG_ENABLE + OutputDebugString("ExtIoGetSetting"); +#endif + switch (idx) + { + case 0: + sprintf_s(description, 1024, "%s", "SampleRateIdx"); + sprintf_s(value, 1024, "%d", SampleRateIdx); + return 0; + case 1: + sprintf_s(description, 1024, "%s", "Tuner AGC"); + sprintf_s(value, 1024, "%d", 0); + return 0; + case 2: + sprintf_s(description, 1024, "%s", "RTL_AGC"); + sprintf_s(value, 1024, "%d", 0); + return 0; + case 3: + sprintf_s(description, 1024, "%s", "Frequency_Correction"); + sprintf_s(value, 1024, "%d", ppm_default); // TODO: expecting int?? FqOffsetPPM?? + return 0; + case 4: + sprintf_s(description, 1024, "%s", "Tuner_Gain"); + sprintf_s(value, 1024, "%d", GainReduction); // TODO: Gain Reduction vs Gain?? LNA?? + return 0; + case 5: + sprintf_s(description, 1024, "%s", "Buffer_Size"); + sprintf_s(value, 1024, "%d", buffer_default); // TODO: correct?? + return 0; + case 6: + sprintf_s(description, 1024, "%s", "Offset_Tuning"); + sprintf_s(value, 1024, "%d", 0); // TODO: correct?? + return 0; + case 7: + sprintf_s(description, 1024, "%s", "Direct_Sampling"); + sprintf_s(value, 1024, "%d", 0); // TODO: correct?? + return 0; + case 8: + sprintf_s(description, 1024, "%s", "Device"); + sprintf_s(value, 1024, "%d", 0); // TODO: only one device supported + return 0; + } + return -1; // ERROR +} + +extern "C" +void LIBSDRplay_API __stdcall ExtIoSetSetting(int idx, const char *value) +{ + int tempInt; +#ifdef DEBUG_ENABLE + OutputDebugString("ExtIoSetSetting"); +#endif + switch (idx) + { + case 0: // Sample Rate + tempInt = atoi(value); + if (tempInt >= 0 && tempInt < (sizeof(samplerates) / sizeof(samplerates[0]))) + { + SampleRateIdx = tempInt; + } + break; + case 1: // Tuner AGC + tempInt = atoi(value); + break; + case 2: // RTL AGC + tempInt = atoi(value); + break; + case 3: // PPM + tempInt = atoi(value); + ppm_default = tempInt; + break; + case 4: // Gain + tempInt = atoi(value); + GainReduction = tempInt; + break; + case 5: // Buffer Size + tempInt = atoi(value); + buffer_default = tempInt; + break; + case 6: // Offset Freq + tempInt = atoi(value); + break; + case 7: // Direct Sampling + tempInt = atoi(value); + break; + case 8: // Device + tempInt = atoi(value); + break; + } +} + +extern "C" +void LIBSDRplay_API __stdcall ShowGUI() // Hotkeys defined here +{ +#ifdef DEBUG_ENABLE + OutputDebugString("ShowGUI"); +#endif + if (h_dialog == NULL) + { + h_dialog = CreateDialog(hInst, MAKEINTRESOURCE(IDD_SDRPLAY_SETTINGS), NULL, (DLGPROC)MainDlgProc); + } + if (!definedHotkeys) + { + NUM_OF_HOTKEYS = 15; + RegisterHotKey(h_dialog, 1, MOD_ALT, 0x41); // ALT-A for AGC enable toggle + RegisterHotKey(h_dialog, 2, NULL, 0x6D); // - for Gain decrease (Gain reduction increase) (KEYPAD) + RegisterHotKey(h_dialog, 3, NULL, 0x6B); // + for Gain increase (Gain reduction decrease) (KEYPAD) + RegisterHotKey(h_dialog, 4, NULL, 0xBD); // - for Gain decrease (Gain reduction increase) + RegisterHotKey(h_dialog, 5, MOD_SHIFT, 0xBB); // SHIFT-+ for Gain increase (Gain reduction decrease) + RegisterHotKey(h_dialog, 6, MOD_SHIFT, 0x70); // SHIFT+F1 for loading stored profile 1 + RegisterHotKey(h_dialog, 7, MOD_SHIFT, 0x71); // SHIFT+F2 for loading stored profile 2 + RegisterHotKey(h_dialog, 8, MOD_SHIFT, 0x72); // SHIFT+F3 for loading stored profile 3 + RegisterHotKey(h_dialog, 9, MOD_SHIFT, 0x73); // SHIFT+F4 for loading stored profile 4 + RegisterHotKey(h_dialog, 10, MOD_SHIFT, 0x74); // SHIFT+F5 for loading stored profile 5 + RegisterHotKey(h_dialog, 11, MOD_SHIFT, 0x75); // SHIFT+F6 for loading stored profile 6 + RegisterHotKey(h_dialog, 12, MOD_SHIFT, 0x76); // SHIFT+F7 for loading stored profile 7 + RegisterHotKey(h_dialog, 13, MOD_SHIFT, 0x77); // SHIFT+F8 for loading stored profile 8 + RegisterHotKey(h_dialog, 14, MOD_ALT, 0x50); // ALT-P for Profile panel view toggle + RegisterHotKey(h_dialog, 15, MOD_ALT, 0x58); // ALT-X for EXTIO panel view toggle + definedHotkeys = true; + } + ShowWindow(h_dialog, SW_SHOW); + BringWindowToTop(h_dialog); +} + +extern "C" +void LIBSDRplay_API __stdcall SwitchGUI() // Hotkeys defined here +{ +#ifdef DEBUG_ENABLE + OutputDebugString("SwitchGUI"); +#endif + if (IsWindowVisible(h_dialog)) + { + int i; + for (i = 1; i <= NUM_OF_HOTKEYS; i++) + { + UnregisterHotKey(h_dialog, i); + } + ShowWindow(h_dialog, SW_HIDE); + definedHotkeys = false; + } + else + { + if (!definedHotkeys) + { + NUM_OF_HOTKEYS = 15; + RegisterHotKey(h_dialog, 1, MOD_ALT, 0x41); // ALT-A for AGC enable toggle + RegisterHotKey(h_dialog, 2, NULL, 0x6D); // - for Gain decrease (Gain reduction increase) (KEYPAD) + RegisterHotKey(h_dialog, 3, NULL, 0x6B); // + for Gain increase (Gain reduction decrease) (KEYPAD) + RegisterHotKey(h_dialog, 4, NULL, 0xBD); // - for Gain decrease (Gain reduction increase) + RegisterHotKey(h_dialog, 5, MOD_SHIFT, 0xBB); // SHIFT-+ for Gain increase (Gain reduction decrease) + RegisterHotKey(h_dialog, 6, MOD_SHIFT, 0x70); // SHIFT+F1 for loading stored profile 1 + RegisterHotKey(h_dialog, 7, MOD_SHIFT, 0x71); // SHIFT+F2 for loading stored profile 2 + RegisterHotKey(h_dialog, 8, MOD_SHIFT, 0x72); // SHIFT+F3 for loading stored profile 3 + RegisterHotKey(h_dialog, 9, MOD_SHIFT, 0x73); // SHIFT+F4 for loading stored profile 4 + RegisterHotKey(h_dialog, 10, MOD_SHIFT, 0x74); // SHIFT+F5 for loading stored profile 5 + RegisterHotKey(h_dialog, 11, MOD_SHIFT, 0x75); // SHIFT+F6 for loading stored profile 6 + RegisterHotKey(h_dialog, 12, MOD_SHIFT, 0x76); // SHIFT+F7 for loading stored profile 7 + RegisterHotKey(h_dialog, 13, MOD_SHIFT, 0x77); // SHIFT+F8 for loading stored profile 8 + RegisterHotKey(h_dialog, 14, MOD_ALT, 0x50); // ALT-P for Profile panel view toggle + RegisterHotKey(h_dialog, 15, MOD_ALT, 0x58); // ALT-X for EXTIO panel view toggle + definedHotkeys = true; + } + ShowWindow(h_dialog, SW_SHOW); + BringWindowToTop(h_dialog); + } +} + +extern "C" +void LIBSDRplay_API __stdcall SetCallback(void(*myCallBack)(int, int, float, void *)) +{ +#ifdef DEBUG_ENABLE + OutputDebugString("SetCallback"); +#endif + WinradCallBack = myCallBack; +} + +extern "C" +int LIBSDRplay_API __stdcall GetStatus() +{ +#ifdef DEBUG_ENABLE + OutputDebugString("GetStatus"); +#endif + return 0; +} + +int FindSampleRateIdx(double WantedSampleRate) +{ + int Found, i; + int SRiD = 0; + double SR; + + Found = 0; + for (i = 0; i < (sizeof(samplerates) / sizeof(samplerates[0])); i++) + { + SR = (samplerates[i].value) + 0.01; + if (SR > WantedSampleRate && Found == 0) + { + SRiD = i; + Found = 1; + } + } + return SRiD; +} + +void SaveSettings() +{ + HKEY Settingskey; + int error, AGC, LOAuto, PostDcComp, SL, tempVar; + DWORD dwDisposition; + + error = RegOpenKeyEx(HKEY_CURRENT_USER, TEXT("Software\\SDRplay\\RSPdxR2_Settings"), 0, KEY_ALL_ACCESS, &Settingskey); + if (error != ERROR_SUCCESS) + { + if (error == ERROR_FILE_NOT_FOUND) + { + //Need to create registry entry. + error = RegCreateKeyEx(HKEY_CURRENT_USER, TEXT("Software\\SDRplay\\RSPdxR2_Settings"), 0, NULL, 0, KEY_ALL_ACCESS, NULL, &Settingskey, &dwDisposition); + } + else + { + MessageBox(NULL, "Failed to locate Settings registry entry", NULL, MB_OK); + } + } + + error = RegSetValueEx(Settingskey, TEXT("DcCompensationMode"), 0, REG_DWORD, (LPBYTE)&DcCompensationMode, sizeof(DcCompensationMode)); + if (error != ERROR_SUCCESS) + MessageBox(NULL, "Failed to save DcCompensationMode", NULL, MB_OK); + + error = RegSetValueEx(Settingskey, TEXT("RefreshPeriodMemory"), 0, REG_DWORD, (LPBYTE)&RefreshPeriodMemory, sizeof(DcCompensationMode)); + if (error != ERROR_SUCCESS) + MessageBox(NULL, "Failed to save RefreshPeriodMemory", NULL, MB_OK); + + error = RegSetValueEx(Settingskey, TEXT("TrackingPeriod"), 0, REG_DWORD, (LPBYTE)&TrackingPeriod, sizeof(TrackingPeriod)); + if (error != ERROR_SUCCESS) + MessageBox(NULL, "Failed to save TrackingPeriod", NULL, MB_OK); + + error = RegSetValueEx(Settingskey, TEXT("FreqTrim"), 0, REG_DWORD, (LPBYTE)&FqOffsetPPM, sizeof(FqOffsetPPM)); + if (error != ERROR_SUCCESS) + MessageBox(NULL, "Failed to save Frequenct Trim", NULL, MB_OK); + + error = RegSetValueEx(Settingskey, TEXT("IFmodeIdx"), 0, REG_DWORD, (LPBYTE)&IFmodeIdx, sizeof(IFmodeIdx)); + if (error != ERROR_SUCCESS) + MessageBox(NULL, "Failed to save IF Mode", NULL, MB_OK); + + error = RegSetValueEx(Settingskey, TEXT("BandwidthIdx"), 0, REG_DWORD, (LPBYTE)&BandwidthIdx, sizeof(BandwidthIdx)); + if (error != ERROR_SUCCESS) + MessageBox(NULL, "Failed to save IF Bandwidth", NULL, MB_OK); + + error = RegSetValueEx(Settingskey, TEXT("SampleRateIdx"), 0, REG_DWORD, (LPBYTE)&SampleRateIdx, sizeof(SampleRateIdx)); + if (error != ERROR_SUCCESS) + MessageBox(NULL, "Failed to save Sample Rate", NULL, MB_OK); + + error = RegSetValueEx(Settingskey, TEXT("DecimationIdx"), 0, REG_DWORD, (LPBYTE)&DecimationIdx, sizeof(DecimationIdx)); + if (error != ERROR_SUCCESS) + MessageBox(NULL, "Failed to save Decimation Factor", NULL, MB_OK); + + error = RegSetValueEx(Settingskey, TEXT("AGCsetpoint"), 0, REG_DWORD, (LPBYTE)&AGCsetpoint, sizeof(AGCsetpoint)); + if (error != ERROR_SUCCESS) + MessageBox(NULL, "Failed to save AGC Setpoint", NULL, MB_OK); + + error = RegSetValueEx(Settingskey, TEXT("GainReduction"), 0, REG_DWORD, (LPBYTE)&GainReduction, sizeof(GainReduction)); + if (error != ERROR_SUCCESS) + MessageBox(NULL, "Failed to save Gain Reduction", NULL, MB_OK); + + error = RegSetValueEx(Settingskey, TEXT("LOplan"), 0, REG_DWORD, (LPBYTE)&LOplan, sizeof(LOplan)); + if (error != ERROR_SUCCESS) + MessageBox(NULL, "Failed to save LO Plan", NULL, MB_OK); + + error = RegSetValueEx(Settingskey, TEXT("Frequency"), 0, REG_BINARY, (LPBYTE)&Frequency, sizeof(Frequency)); + if (error != ERROR_SUCCESS) + MessageBox(NULL, "Failed to save Frequency", NULL, MB_OK); + + if (AGCEnabled) + AGC = 1; + else + AGC = 0; + error = RegSetValueEx(Settingskey, TEXT("AGCEnabled"), 0, REG_DWORD, (LPBYTE)&AGC, sizeof(AGC)); + if (error != ERROR_SUCCESS) + MessageBox(NULL, "Failed to save AGC Setting", NULL, MB_OK); + + if (stationLookup) + SL = 1; + else + SL = 0; + error = RegSetValueEx(Settingskey, TEXT("StationLookup"), 0, REG_DWORD, (LPBYTE)&SL, sizeof(SL)); + if (error != ERROR_SUCCESS) + MessageBox(NULL, "Failed to save StationLookup Setting", NULL, MB_OK); + + if (workOffline) + SL = 1; + else + SL = 0; + error = RegSetValueEx(Settingskey, TEXT("WorkOffline"), 0, REG_DWORD, (LPBYTE)&SL, sizeof(SL)); + if (error != ERROR_SUCCESS) + MessageBox(NULL, "Failed to save WorkOffline Setting", NULL, MB_OK); + + if (h_StationConfigDialog != NULL) + { + tempVar = ComboBox_GetCurSel(GetDlgItem(h_StationConfigDialog, IDC_STATIONCONFIG_TAC)); + error = RegSetValueEx(Settingskey, TEXT("TACIndex"), 0, REG_DWORD, (LPBYTE)&tempVar, sizeof(tempVar)); + if (error != ERROR_SUCCESS) + MessageBox(NULL, "Failed to save TAC Setting", NULL, MB_OK); + + tempVar = ComboBox_GetCurSel(GetDlgItem(h_StationConfigDialog, IDC_STATIONCONFIG_ITU)); + error = RegSetValueEx(Settingskey, TEXT("ITUIndex"), 0, REG_DWORD, (LPBYTE)&tempVar, sizeof(tempVar)); + if (error != ERROR_SUCCESS) + MessageBox(NULL, "Failed to save ITU Setting", NULL, MB_OK); + } + + if (LOplanAuto) + LOAuto = 1; + else + LOAuto = 0; + error = RegSetValueEx(Settingskey, TEXT("LOAuto"), 0, REG_DWORD, (LPBYTE)&LOAuto, sizeof(LOAuto)); + if (error != ERROR_SUCCESS) + MessageBox(NULL, "Failed to save LO Auto Setting", NULL, MB_OK); + + if (PostTunerDcCompensation) + PostDcComp = 1; + else + PostDcComp = 0; + error = RegSetValueEx(Settingskey, TEXT("PostDCComp"), 0, REG_DWORD, (LPBYTE)&PostDcComp, sizeof(PostDcComp)); + if (error != ERROR_SUCCESS) + MessageBox(NULL, "Failed to save Post DC Compensation Setting", NULL, MB_OK); + + error = RegSetValueEx(Settingskey, TEXT("LNAGainReduction"), 0, REG_DWORD, (LPBYTE)&LNAGainReduction, sizeof(LNAGainReduction)); + if (error != ERROR_SUCCESS) + MessageBox(NULL, "Failed to save LNA gain reduction value", NULL, MB_OK); + + error = RegSetValueEx(Settingskey, TEXT("AntennaIdx"), 0, REG_DWORD, (LPBYTE)&AntennaIdx, sizeof(AntennaIdx)); + if (error != ERROR_SUCCESS) + MessageBox(NULL, "Failed to save Tuner setting", NULL, MB_OK); + + error = RegSetValueEx(Settingskey, TEXT("NotchEnable"), 0, REG_DWORD, (LPBYTE)¬chEnable, sizeof(notchEnable)); + if (error != ERROR_SUCCESS) + MessageBox(NULL, "Failed to save Broadcast Notch setting", NULL, MB_OK); + + error = RegSetValueEx(Settingskey, TEXT("DABNotchEnable"), 0, REG_DWORD, (LPBYTE)&dabNotchEnable, sizeof(dabNotchEnable)); + if (error != ERROR_SUCCESS) + MessageBox(NULL, "Failed to save DAB Notch setting", NULL, MB_OK); + + error = RegSetValueEx(Settingskey, TEXT("BiasTEnable"), 0, REG_DWORD, (LPBYTE)&biasTEnable, sizeof(biasTEnable)); + if (error != ERROR_SUCCESS) + MessageBox(NULL, "Failed to save Bias T setting", NULL, MB_OK); + + if (_tcscmp(p1fname, _T("")) != 0) + { + error = RegSetValueEx(Settingskey, TEXT("P1"), 0, REG_SZ, (LPBYTE)&p1fname, sizeof(p1fname)); + if (error != ERROR_SUCCESS) + { + MessageBox(NULL, "Failed to save P1 setting", NULL, MB_OK); + } + } + else + { + error = RegDeleteValue(Settingskey, TEXT("P1")); + } + + if (_tcscmp(p2fname, _T("")) != 0) + { + error = RegSetValueEx(Settingskey, TEXT("P2"), 0, REG_SZ, (LPBYTE)&p2fname, sizeof(p2fname)); + if (error != ERROR_SUCCESS) + { + MessageBox(NULL, "Failed to save P2 setting", NULL, MB_OK); + } + } + else + { + error = RegDeleteValue(Settingskey, TEXT("P2")); + } + + if (_tcscmp(p3fname, _T("")) != 0) + { + error = RegSetValueEx(Settingskey, TEXT("P3"), 0, REG_SZ, (LPBYTE)&p3fname, sizeof(p3fname)); + if (error != ERROR_SUCCESS) + { + MessageBox(NULL, "Failed to save P3 setting", NULL, MB_OK); + } + } + else + { + error = RegDeleteValue(Settingskey, TEXT("P3")); + } + + if (_tcscmp(p4fname, _T("")) != 0) + { + error = RegSetValueEx(Settingskey, TEXT("P4"), 0, REG_SZ, (LPBYTE)&p4fname, sizeof(p4fname)); + if (error != ERROR_SUCCESS) + { + MessageBox(NULL, "Failed to save P4 setting", NULL, MB_OK); + } + } + else + { + error = RegDeleteValue(Settingskey, TEXT("P4")); + } + + if (_tcscmp(p5fname, _T("")) != 0) + { + error = RegSetValueEx(Settingskey, TEXT("P5"), 0, REG_SZ, (LPBYTE)&p5fname, sizeof(p5fname)); + if (error != ERROR_SUCCESS) + { + MessageBox(NULL, "Failed to save P5 setting", NULL, MB_OK); + } + } + else + { + error = RegDeleteValue(Settingskey, TEXT("P5")); + } + + if (_tcscmp(p6fname, _T("")) != 0) + { + error = RegSetValueEx(Settingskey, TEXT("P6"), 0, REG_SZ, (LPBYTE)&p6fname, sizeof(p6fname)); + if (error != ERROR_SUCCESS) + { + MessageBox(NULL, "Failed to save P6 setting", NULL, MB_OK); + } + } + else + { + error = RegDeleteValue(Settingskey, TEXT("P6")); + } + + if (_tcscmp(p7fname, _T("")) != 0) + { + error = RegSetValueEx(Settingskey, TEXT("P7"), 0, REG_SZ, (LPBYTE)&p7fname, sizeof(p7fname)); + if (error != ERROR_SUCCESS) + { + MessageBox(NULL, "Failed to save P7 setting", NULL, MB_OK); + } + } + else + { + error = RegDeleteValue(Settingskey, TEXT("P7")); + } + + if (_tcscmp(p8fname, _T("")) != 0) + { + error = RegSetValueEx(Settingskey, TEXT("P8"), 0, REG_SZ, (LPBYTE)&p8fname, sizeof(p8fname)); + if (error != ERROR_SUCCESS) + { + MessageBox(NULL, "Failed to save P8 setting", NULL, MB_OK); + } + } + else + { + error = RegDeleteValue(Settingskey, TEXT("P8")); + } + + RegCloseKey(Settingskey); +} + +void LoadSettings() +{ + HKEY Settingskey; + int error, tempRB; + DWORD DoubleSz, IntSz; + + DoubleSz = sizeof(double); + IntSz = sizeof(int); + + error = RegOpenKeyEx(HKEY_CURRENT_USER, TEXT("Software\\SDRplay\\RSPdxR2_Settings"), 0, KEY_ALL_ACCESS, &Settingskey); + if (error == ERROR_SUCCESS) + { + error = RegQueryValueEx(Settingskey, "LowerFqLimit", NULL, NULL, (LPBYTE)&LowerFqLimit, &IntSz); + if (error != ERROR_SUCCESS) + { +#ifdef DEBUG_ENABLE + OutputDebugString("Lower Frequency Limit set to 1 kHz"); +#endif + LowerFqLimit = 1; + } + + error = RegQueryValueEx(Settingskey, "DcCompensationMode", NULL, NULL, (LPBYTE)&DcCompensationMode, &IntSz); + if (error != ERROR_SUCCESS) + { +#ifdef DEBUG_ENABLE + OutputDebugString("Failed to recall DcCompensationMode"); +#endif + DcCompensationMode = 3; + } + + error = RegQueryValueEx(Settingskey, "RefreshPeriodMemory", NULL, NULL, (LPBYTE)&RefreshPeriodMemory, &IntSz); + if (error != ERROR_SUCCESS) + { +#ifdef DEBUG_ENABLE + OutputDebugString("Failed to recall Refresh Period"); +#endif + RefreshPeriodMemory = 2; + } + + error = RegQueryValueEx(Settingskey, "TrackingPeriod", NULL, NULL, (LPBYTE)&TrackingPeriod, &IntSz); + if (error != ERROR_SUCCESS) + { +#ifdef DEBUG_ENABLE + OutputDebugString("Failed to recall DC Compensation Tracking Period"); +#endif + TrackingPeriod = 20; + } + + error = RegQueryValueEx(Settingskey, "Frequency", NULL, NULL, (LPBYTE)&Frequency, &DoubleSz); + if (error != ERROR_SUCCESS) + { +#ifdef DEBUG_ENABLE + OutputDebugString("Failed to recall saved frequency state"); +#endif + Frequency = 98.8; + } + + error = RegQueryValueEx(Settingskey, "LOplan", NULL, NULL, (LPBYTE)&LOplan, &IntSz); + if (error != ERROR_SUCCESS) + { +#ifdef DEBUG_ENABLE + OutputDebugString("Failed to recall saved LO Plan"); +#endif + LOplan = LO120MHz; + } + + error = RegQueryValueEx(Settingskey, "GainReduction", NULL, NULL, (LPBYTE)&GainReduction, &IntSz); + if (error != ERROR_SUCCESS) + { +#ifdef DEBUG_ENABLE + OutputDebugString("Failed to recall saved Gain Reduction"); +#endif + GainReduction = INITIAL_GR; + } + + error = RegQueryValueEx(Settingskey, "AGCsetpoint", NULL, NULL, (LPBYTE)&AGCsetpoint, &IntSz); + if (error != ERROR_SUCCESS) + { +#ifdef DEBUG_ENABLE + OutputDebugString("Failed to recall saved AGC Setpoint"); +#endif + AGCsetpoint = -30; + } + + error = RegQueryValueEx(Settingskey, "AntennaIdx", NULL, NULL, (LPBYTE)&AntennaIdx, &IntSz); + if (error != ERROR_SUCCESS) + { +#ifdef DEBUG_ENABLE + OutputDebugString("Failed to recall saved Antenna Port"); +#endif + AntennaIdx = 0; + } + + error = RegQueryValueEx(Settingskey, "SampleRateIdx", NULL, NULL, (LPBYTE)&SampleRateIdx, &IntSz); + if (error != ERROR_SUCCESS) + { +#ifdef DEBUG_ENABLE + OutputDebugString("Failed to recall saved Sample Rate"); +#endif + SampleRateIdx = 0; + } + + error = RegQueryValueEx(Settingskey, "DecimationIdx", NULL, NULL, (LPBYTE)&DecimationIdx, &IntSz); + if (error != ERROR_SUCCESS) + { +#ifdef DEBUG_ENABLE + OutputDebugString("Failed to recall saved Decimation Factor"); +#endif + DecimationIdx = 0; + } + + error = RegQueryValueEx(Settingskey, "BandwidthIdx", NULL, NULL, (LPBYTE)&BandwidthIdx, &IntSz); + if (error != ERROR_SUCCESS) + { +#ifdef DEBUG_ENABLE + OutputDebugString("Failed to recall saved IF Bandwidth"); +#endif + BandwidthIdx = 3; + } + + error = RegQueryValueEx(Settingskey, "IFmodeIdx", NULL, NULL, (LPBYTE)&IFmodeIdx, &IntSz); + if (error != ERROR_SUCCESS) + { +#ifdef DEBUG_ENABLE + OutputDebugString("Failed to recall saved IF mode"); +#endif + IFmodeIdx = 1; + } + Edit_Enable(GetDlgItem(h_dialog, IDC_IFMODE), 1); + + error = RegQueryValueEx(Settingskey, "FreqTrim", NULL, NULL, (LPBYTE)&FqOffsetPPM, &IntSz); + if (error != ERROR_SUCCESS) + { +#ifdef DEBUG_ENABLE + OutputDebugString("Failed to recall saved FreqTrim"); +#endif + FqOffsetPPM = 0; + } + + tempRB = 0; + error = RegQueryValueEx(Settingskey, "AGCEnabled", NULL, NULL, (LPBYTE)&tempRB, &IntSz); + if (error != ERROR_SUCCESS) + { +#ifdef DEBUG_ENABLE + OutputDebugString("Failed to recall saved AGCEnabled state"); +#endif + AGCEnabled = false; + } + else + { + if (tempRB == 1) + AGCEnabled = true; + else + AGCEnabled = false; + } + + tempRB = 0; + error = RegQueryValueEx(Settingskey, "StationLookup", NULL, NULL, (LPBYTE)&tempRB, &IntSz); + if (error != ERROR_SUCCESS) + { +#ifdef DEBUG_ENABLE + OutputDebugString("Failed to recall saved StationLookup state"); +#endif + stationLookup = false; + } + else + { + if (tempRB == 1) + stationLookup = true; + else + stationLookup = false; + } + + tempRB = 0; + error = RegQueryValueEx(Settingskey, "WorkOffline", NULL, NULL, (LPBYTE)&tempRB, &IntSz); + if (error != ERROR_SUCCESS) + { +#ifdef DEBUG_ENABLE + OutputDebugString("Failed to recall saved WorkOffline state"); +#endif + workOffline = false; + } + else + { + if (tempRB == 1) + workOffline = true; + else + workOffline = false; + } + + tempRB = 0; + error = RegQueryValueEx(Settingskey, "TACIndex", NULL, NULL, (LPBYTE)&tempRB, &IntSz); + if (error != ERROR_SUCCESS) + { +#ifdef DEBUG_ENABLE + OutputDebugString("Failed to recall saved TAC setting"); +#endif + TACIndex = 0; + if (h_StationConfigDialog != NULL) + ComboBox_SetCurSel(GetDlgItem(h_StationConfigDialog, IDC_STATIONCONFIG_TAC), TACIndex); + } + else + { + TACIndex = tempRB; + if (h_StationConfigDialog != NULL) + ComboBox_SetCurSel(GetDlgItem(h_StationConfigDialog, IDC_STATIONCONFIG_TAC), TACIndex); + } + + tempRB = 0; + error = RegQueryValueEx(Settingskey, "ITUIndex", NULL, NULL, (LPBYTE)&tempRB, &IntSz); + if (error != ERROR_SUCCESS) + { +#ifdef DEBUG_ENABLE + OutputDebugString("Failed to recall saved ITU setting"); +#endif + ITUIndex = 0; + if (h_StationConfigDialog != NULL) + ComboBox_SetCurSel(GetDlgItem(h_StationConfigDialog, IDC_STATIONCONFIG_ITU), ITUIndex); + } + else + { + ITUIndex = tempRB; + if (h_StationConfigDialog != NULL) + ComboBox_SetCurSel(GetDlgItem(h_StationConfigDialog, IDC_STATIONCONFIG_ITU), ITUIndex); + } + + tempRB = 0; + error = RegQueryValueEx(Settingskey, "LOAuto", NULL, NULL, (LPBYTE)&tempRB, &IntSz); + if (error != ERROR_SUCCESS) + { +#ifdef DEBUG_ENABLE + OutputDebugString("Failed to recall saved LOAuto state"); +#endif + LOplanAuto = true; + } + else + { + if (tempRB == 1) + LOplanAuto = true; + else + LOplanAuto = false; + } + + tempRB = 0; + error = RegQueryValueEx(Settingskey, "PostDCComp", NULL, NULL, (LPBYTE)&tempRB, &IntSz); + if (error != ERROR_SUCCESS) + { +#ifdef DEBUG_ENABLE + OutputDebugString("Failed to recall saved Post DC Compensation state"); +#endif + PostTunerDcCompensation = true; + } + else + { + if (tempRB == 1) + PostTunerDcCompensation = true; + else + PostTunerDcCompensation = false; + } + + error = RegQueryValueEx(Settingskey, "LNAGainReduction", NULL, NULL, (LPBYTE)&LNAGainReduction, &IntSz); + if (error != ERROR_SUCCESS) + { +#ifdef DEBUG_ENABLE + OutputDebugString("Failed to recall saved LNAGainReduction value"); +#endif + LNAGainReduction = 4; + } + + error = RegQueryValueEx(Settingskey, "NotchEnable", NULL, NULL, (LPBYTE)¬chEnable, &IntSz); + if (error != ERROR_SUCCESS) + { +#ifdef DEBUG_ENABLE + OutputDebugString("Failed to recall saved Broadcast Notch value"); +#endif + notchEnable = 0; + } + + error = RegQueryValueEx(Settingskey, "DABNotchEnable", NULL, NULL, (LPBYTE)&dabNotchEnable, &IntSz); + if (error != ERROR_SUCCESS) + { +#ifdef DEBUG_ENABLE + OutputDebugString("Failed to recall saved DAB Notch value"); +#endif + dabNotchEnable = 0; + } + + error = RegQueryValueEx(Settingskey, "BiasTEnable", NULL, NULL, (LPBYTE)&biasTEnable, &IntSz); + if (error != ERROR_SUCCESS) + { +#ifdef DEBUG_ENABLE + OutputDebugString("Failed to recall saved Bias T value"); +#endif + biasTEnable = 0; + } + } + else + { + //If cannot find any registry settings loads some appropriate defaults +#ifdef DEBUG_ENABLE + OutputDebugString("Set Defaults"); +#endif + DcCompensationMode = 3; + TrackingPeriod = 20; + RefreshPeriodMemory = 2; + Frequency = 98.8; + LOplan = LO120MHz; + GainReduction = INITIAL_GR; + AGCsetpoint = -30; + SampleRateIdx = 0; + DecimationIdx = 0; + BandwidthIdx = 3; + IFmodeIdx = 1; + FqOffsetPPM = 0; + AGCEnabled = false; + LOplanAuto = true; + PostTunerDcCompensation = true; + LNAGainReduction = 4; + AntennaIdx = 0; + biasTEnable = 0; + notchEnable = 0; + dabNotchEnable = 0; + stationLookup = false; + workOffline = false; + ITUIndex = 0; + TACIndex = 0; + } + RegCloseKey(Settingskey); +} + +static INT_PTR CALLBACK MainDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + int SrCount = 0; + double SR = 0; + double BW = 0; + static HWND hGain; + static HBRUSH BRUSH_RED = CreateSolidBrush(RGB(255, 0, 0)); + static HBRUSH BRUSH_GREEN = CreateSolidBrush(RGB(0, 255, 0)); + static HBRUSH hBrush = CreateSolidBrush(RGB(255, 255, 255)); + DWORD CtrlID; + UINT nFrom; +// OPENFILENAME ofn = { 0 }; +// TCHAR szFileName[MAX_PATH] = _T(""); + TCHAR str[255]; + bool DeltaPosClick = false; + int i; + + switch (uMsg) + { + case WM_HOTKEY: + switch (LOWORD(wParam)) + { + case 1: + // ALT-A = AGC toggle + if (!AGCEnabled) + { + AGCEnabled = true; + SendMessage(GetDlgItem(hwndDlg, IDC_RSPAGC), BM_SETCHECK, (WPARAM)(1), 0); + Edit_Enable(GetDlgItem(hwndDlg, IDC_GR), 0); + Edit_Enable(GetDlgItem(hwndDlg, IDC_GAINSLIDER), 0); +// m_timer = SetTimer(hwndDlg, ID_AGCUPDATE, 600, NULL); + } + else + { + AGCEnabled = false; + SendMessage(GetDlgItem(hwndDlg, IDC_RSPAGC), BM_SETCHECK, (WPARAM)(0), 0); + Edit_Enable(GetDlgItem(hwndDlg, IDC_GR), 1); + Edit_Enable(GetDlgItem(hwndDlg, IDC_GAINSLIDER), 1); +// KillTimer(hwndDlg, ID_AGCUPDATE); + } + break; + + case 2: + case 4: + // - = Increase Gain Reduction + if (!AGCEnabled) + { + GainReduction += 1; + if (GainReduction > GAIN_SLIDER_MAX) + { + GainReduction = GAIN_SLIDER_MAX; + } + sprintf_s(GainReductionTxt, 254, "%d", GainReduction); + Edit_SetText(GetDlgItem(hwndDlg, IDC_GR), GainReductionTxt); + SendMessage(GetDlgItem(hwndDlg, IDC_GAINSLIDER), TBM_SETPOS, (WPARAM)true, (LPARAM)GainReduction); + } + break; + + case 3: + case 5: + // + = Decrease Gain Reduction + if (!AGCEnabled) + { + GainReduction -= 1; + if (GainReduction < GAIN_SLIDER_MIN) + { + GainReduction = GAIN_SLIDER_MIN; + } + sprintf_s(GainReductionTxt, 254, "%d", GainReduction); + Edit_SetText(GetDlgItem(hwndDlg, IDC_GR), GainReductionTxt); + SendMessage(GetDlgItem(hwndDlg, IDC_GAINSLIDER), TBM_SETPOS, (WPARAM)true, (LPARAM)GainReduction); + } + break; + + case 6: + // SHIFT+F1 = load profile 1 + if (_tcscmp(p1fname, "") != 0) + { + LoadProfile(1); + Edit_SetText(GetDlgItem(h_ProfilesDialog, IDC_PROF_BUTTON_ONE), "[P1]"); + Edit_SetText(GetDlgItem(h_ProfilesDialog, IDC_PROF_BUTTON_TWO), "P2"); + Edit_SetText(GetDlgItem(h_ProfilesDialog, IDC_PROF_BUTTON_THREE), "P3"); + Edit_SetText(GetDlgItem(h_ProfilesDialog, IDC_PROF_BUTTON_FOUR), "P4"); + Edit_SetText(GetDlgItem(h_ProfilesDialog, IDC_PROF_BUTTON_FIVE), "P5"); + Edit_SetText(GetDlgItem(h_ProfilesDialog, IDC_PROF_BUTTON_SIX), "P6"); + Edit_SetText(GetDlgItem(h_ProfilesDialog, IDC_PROF_BUTTON_SEVEN), "P7"); + Edit_SetText(GetDlgItem(h_ProfilesDialog, IDC_PROF_BUTTON_EIGHT), "P8"); + } + break; + + case 7: + // SHIFT+F2 = load profile 2 + if (_tcscmp(p2fname, "") != 0) + { + LoadProfile(2); + Edit_SetText(GetDlgItem(h_ProfilesDialog, IDC_PROF_BUTTON_ONE), "P1"); + Edit_SetText(GetDlgItem(h_ProfilesDialog, IDC_PROF_BUTTON_TWO), "[P2]"); + Edit_SetText(GetDlgItem(h_ProfilesDialog, IDC_PROF_BUTTON_THREE), "P3"); + Edit_SetText(GetDlgItem(h_ProfilesDialog, IDC_PROF_BUTTON_FOUR), "P4"); + Edit_SetText(GetDlgItem(h_ProfilesDialog, IDC_PROF_BUTTON_FIVE), "P5"); + Edit_SetText(GetDlgItem(h_ProfilesDialog, IDC_PROF_BUTTON_SIX), "P6"); + Edit_SetText(GetDlgItem(h_ProfilesDialog, IDC_PROF_BUTTON_SEVEN), "P7"); + Edit_SetText(GetDlgItem(h_ProfilesDialog, IDC_PROF_BUTTON_EIGHT), "P8"); + } + break; + + case 8: + // SHIFT+F3 = load profile 3 + if (_tcscmp(p3fname, "") != 0) + { + LoadProfile(3); + Edit_SetText(GetDlgItem(h_ProfilesDialog, IDC_PROF_BUTTON_ONE), "P1"); + Edit_SetText(GetDlgItem(h_ProfilesDialog, IDC_PROF_BUTTON_TWO), "P2"); + Edit_SetText(GetDlgItem(h_ProfilesDialog, IDC_PROF_BUTTON_THREE), "[P3]"); + Edit_SetText(GetDlgItem(h_ProfilesDialog, IDC_PROF_BUTTON_FOUR), "P4"); + Edit_SetText(GetDlgItem(h_ProfilesDialog, IDC_PROF_BUTTON_FIVE), "P5"); + Edit_SetText(GetDlgItem(h_ProfilesDialog, IDC_PROF_BUTTON_SIX), "P6"); + Edit_SetText(GetDlgItem(h_ProfilesDialog, IDC_PROF_BUTTON_SEVEN), "P7"); + Edit_SetText(GetDlgItem(h_ProfilesDialog, IDC_PROF_BUTTON_EIGHT), "P8"); + } + break; + + case 9: + // SHIFT+F4 = load profile 4 + if (_tcscmp(p4fname, "") != 0) + { + LoadProfile(4); + Edit_SetText(GetDlgItem(h_ProfilesDialog, IDC_PROF_BUTTON_ONE), "P1"); + Edit_SetText(GetDlgItem(h_ProfilesDialog, IDC_PROF_BUTTON_TWO), "P2"); + Edit_SetText(GetDlgItem(h_ProfilesDialog, IDC_PROF_BUTTON_THREE), "P3"); + Edit_SetText(GetDlgItem(h_ProfilesDialog, IDC_PROF_BUTTON_FOUR), "[P4]"); + Edit_SetText(GetDlgItem(h_ProfilesDialog, IDC_PROF_BUTTON_FIVE), "P5"); + Edit_SetText(GetDlgItem(h_ProfilesDialog, IDC_PROF_BUTTON_SIX), "P6"); + Edit_SetText(GetDlgItem(h_ProfilesDialog, IDC_PROF_BUTTON_SEVEN), "P7"); + Edit_SetText(GetDlgItem(h_ProfilesDialog, IDC_PROF_BUTTON_EIGHT), "P8"); + } + break; + + case 10: + // SHIFT+F5 = load profile 5 + if (_tcscmp(p5fname, "") != 0) + { + LoadProfile(5); + Edit_SetText(GetDlgItem(h_ProfilesDialog, IDC_PROF_BUTTON_ONE), "P1"); + Edit_SetText(GetDlgItem(h_ProfilesDialog, IDC_PROF_BUTTON_TWO), "P2"); + Edit_SetText(GetDlgItem(h_ProfilesDialog, IDC_PROF_BUTTON_THREE), "P3"); + Edit_SetText(GetDlgItem(h_ProfilesDialog, IDC_PROF_BUTTON_FOUR), "P4"); + Edit_SetText(GetDlgItem(h_ProfilesDialog, IDC_PROF_BUTTON_FIVE), "[P5]"); + Edit_SetText(GetDlgItem(h_ProfilesDialog, IDC_PROF_BUTTON_SIX), "P6"); + Edit_SetText(GetDlgItem(h_ProfilesDialog, IDC_PROF_BUTTON_SEVEN), "P7"); + Edit_SetText(GetDlgItem(h_ProfilesDialog, IDC_PROF_BUTTON_EIGHT), "P8"); + } + break; + + case 11: + // SHIFT+F6 = load profile 6 + if (_tcscmp(p6fname, "") != 0) + { + LoadProfile(6); + Edit_SetText(GetDlgItem(h_ProfilesDialog, IDC_PROF_BUTTON_ONE), "P1"); + Edit_SetText(GetDlgItem(h_ProfilesDialog, IDC_PROF_BUTTON_TWO), "P2"); + Edit_SetText(GetDlgItem(h_ProfilesDialog, IDC_PROF_BUTTON_THREE), "P3"); + Edit_SetText(GetDlgItem(h_ProfilesDialog, IDC_PROF_BUTTON_FOUR), "P4"); + Edit_SetText(GetDlgItem(h_ProfilesDialog, IDC_PROF_BUTTON_FIVE), "P5"); + Edit_SetText(GetDlgItem(h_ProfilesDialog, IDC_PROF_BUTTON_SIX), "[P6]"); + Edit_SetText(GetDlgItem(h_ProfilesDialog, IDC_PROF_BUTTON_SEVEN), "P7"); + Edit_SetText(GetDlgItem(h_ProfilesDialog, IDC_PROF_BUTTON_EIGHT), "P8"); + } + break; + + case 12: + // SHIFT+F7 = load profile 7 + if (_tcscmp(p7fname, "") != 0) + { + LoadProfile(7); + Edit_SetText(GetDlgItem(h_ProfilesDialog, IDC_PROF_BUTTON_ONE), "P1"); + Edit_SetText(GetDlgItem(h_ProfilesDialog, IDC_PROF_BUTTON_TWO), "P2"); + Edit_SetText(GetDlgItem(h_ProfilesDialog, IDC_PROF_BUTTON_THREE), "P3"); + Edit_SetText(GetDlgItem(h_ProfilesDialog, IDC_PROF_BUTTON_FOUR), "P4"); + Edit_SetText(GetDlgItem(h_ProfilesDialog, IDC_PROF_BUTTON_FIVE), "P5"); + Edit_SetText(GetDlgItem(h_ProfilesDialog, IDC_PROF_BUTTON_SIX), "P6"); + Edit_SetText(GetDlgItem(h_ProfilesDialog, IDC_PROF_BUTTON_SEVEN), "[P7]"); + Edit_SetText(GetDlgItem(h_ProfilesDialog, IDC_PROF_BUTTON_EIGHT), "P8"); + } + break; + + case 13: + // SHIFT+F8 = load profile 8 + if (_tcscmp(p8fname, "") != 0) + { + LoadProfile(8); + Edit_SetText(GetDlgItem(h_ProfilesDialog, IDC_PROF_BUTTON_ONE), "P1"); + Edit_SetText(GetDlgItem(h_ProfilesDialog, IDC_PROF_BUTTON_TWO), "P2"); + Edit_SetText(GetDlgItem(h_ProfilesDialog, IDC_PROF_BUTTON_THREE), "P3"); + Edit_SetText(GetDlgItem(h_ProfilesDialog, IDC_PROF_BUTTON_FOUR), "P4"); + Edit_SetText(GetDlgItem(h_ProfilesDialog, IDC_PROF_BUTTON_FIVE), "P5"); + Edit_SetText(GetDlgItem(h_ProfilesDialog, IDC_PROF_BUTTON_SIX), "P6"); + Edit_SetText(GetDlgItem(h_ProfilesDialog, IDC_PROF_BUTTON_SEVEN), "P7"); + Edit_SetText(GetDlgItem(h_ProfilesDialog, IDC_PROF_BUTTON_EIGHT), "[P8]"); + } + break; + + case 14: + // ALT-P = toggle Profile panel view + if (IsWindowVisible(h_ProfilesDialog)) + { + ShowWindow(h_ProfilesDialog, SW_HIDE); + } + else + { + ShowWindow(h_ProfilesDialog, SW_SHOW); + } + break; + + case 15: + // ALT-X = toggle EXTIO panel view + if (IsWindowVisible(h_dialog)) + { + for (i = 1; i <= (NUM_OF_HOTKEYS - 1); i++) // don't remove ALT-X + { + UnregisterHotKey(h_dialog, i); + } + definedHotkeys = false; + ShowWindow(h_dialog, SW_HIDE); + if (h_AdvancedDialog != NULL) + ShowWindow(h_AdvancedDialog, SW_HIDE); + if (h_ProfilesDialog != NULL) + ShowWindow(h_ProfilesDialog, SW_HIDE); + if (h_HelpDialog != NULL) + ShowWindow(h_HelpDialog, SW_HIDE); + } + else + { + NUM_OF_HOTKEYS = 15; + RegisterHotKey(h_dialog, 1, MOD_ALT, 0x41); // ALT-A for AGC enable toggle + RegisterHotKey(h_dialog, 2, NULL, 0x6D); // - for Gain decrease (Gain reduction increase) (KEYPAD) + RegisterHotKey(h_dialog, 3, NULL, 0x6B); // + for Gain increase (Gain reduction decrease) (KEYPAD) + RegisterHotKey(h_dialog, 4, NULL, 0xBD); // - for Gain decrease (Gain reduction increase) + RegisterHotKey(h_dialog, 5, MOD_SHIFT, 0xBB); // SHIFT-+ for Gain increase (Gain reduction decrease) + RegisterHotKey(h_dialog, 6, MOD_SHIFT, 0x70); // SHIFT+F1 for loading stored profile 1 + RegisterHotKey(h_dialog, 7, MOD_SHIFT, 0x71); // SHIFT+F2 for loading stored profile 2 + RegisterHotKey(h_dialog, 8, MOD_SHIFT, 0x72); // SHIFT+F3 for loading stored profile 3 + RegisterHotKey(h_dialog, 9, MOD_SHIFT, 0x73); // SHIFT+F4 for loading stored profile 4 + RegisterHotKey(h_dialog, 10, MOD_SHIFT, 0x74); // SHIFT+F5 for loading stored profile 5 + RegisterHotKey(h_dialog, 11, MOD_SHIFT, 0x75); // SHIFT+F6 for loading stored profile 6 + RegisterHotKey(h_dialog, 12, MOD_SHIFT, 0x76); // SHIFT+F7 for loading stored profile 7 + RegisterHotKey(h_dialog, 13, MOD_SHIFT, 0x77); // SHIFT+F8 for loading stored profile 8 + RegisterHotKey(h_dialog, 14, MOD_ALT, 0x50); // ALT-P for Profile panel view toggle + RegisterHotKey(h_dialog, 15, MOD_ALT, 0x58); // ALT-X for EXTIO panel view toggle + definedHotkeys = true; + ShowWindow(h_dialog, SW_SHOW); + } + return true; + break; + } + break; + + case WM_TIMER: + _stprintf_s(str, 255, TEXT("%d"), GainReduction); + Edit_Enable(GetDlgItem(hwndDlg, IDC_GR), 1); + SendMessage(GetDlgItem(hwndDlg, IDC_GR), WM_SETTEXT, (WPARAM)0, (LPARAM)str); + Edit_Enable(GetDlgItem(hwndDlg, IDC_GR), 0); + + Edit_Enable(GetDlgItem(hwndDlg, IDC_GAINSLIDER), 1); + SendMessage(GetDlgItem(hwndDlg, IDC_GAINSLIDER), TBM_SETPOS, (WPARAM)true, (LPARAM)GainReduction); + Edit_Enable(GetDlgItem(hwndDlg, IDC_GAINSLIDER), 0); + + sprintf_s(str, sizeof(str), "Total System Gain Reduction %d dB", SystemGainReduction); + Edit_SetText(GetDlgItem(hwndDlg, IDC_TOTALGR), str); + + break; + + case WM_NOTIFY: + nFrom = ((LPNMHDR)lParam)->code; + switch (nFrom) + { + case UDN_DELTAPOS: + { + if (((LPNMHDR)lParam)->idFrom == IDC_PPM_S) + { + TCHAR Offset[255]; + LPNMUPDOWN lpnmud = (LPNMUPDOWN)lParam; + + DeltaPosClick = true; + FqOffsetPPM = FqOffsetPPM - ((float)lpnmud->iDelta / 100); + sprintf_s(Offset, 254, "%.2f", FqOffsetPPM); + Edit_SetText(GetDlgItem(hwndDlg, IDC_PPM), Offset); +#ifdef DEBUG_ENABLE + sprintf_s(str, 255, "PPM adjust: %.2f", FqOffsetPPM); + OutputDebugString(str); +#endif + return false; + } + } + } + break; + + case WM_SYSCOMMAND: + switch (wParam & 0xFFF0) + { + case SC_SIZE: + case SC_MINIMIZE: + case SC_MAXIMIZE: + return true; + } + break; + + case WM_CLOSE: + for (i = 1; i <= NUM_OF_HOTKEYS; i++) + { + UnregisterHotKey(h_dialog, i); + } + definedHotkeys = false; + ShowWindow(h_dialog, SW_HIDE); + if (h_AdvancedDialog != NULL) + ShowWindow(h_AdvancedDialog, SW_HIDE); + if (h_ProfilesDialog != NULL) + ShowWindow(h_ProfilesDialog, SW_HIDE); + if (h_HelpDialog != NULL) + ShowWindow(h_HelpDialog, SW_HIDE); + if (h_StationConfigDialog != NULL) + ShowWindow(h_StationConfigDialog, SW_HIDE); + return true; + break; + + case WM_DESTROY: + for (i = 1; i <= NUM_OF_HOTKEYS; i++) + { + UnregisterHotKey(h_dialog, i); + } + definedHotkeys = false; + h_dialog = NULL; + return true; + break; + + case WM_VSCROLL: + if ((HWND)lParam == GetDlgItem(hwndDlg, IDC_GAINSLIDER)) + { +// TCHAR str1[255] = "dB"; +#ifdef DEBUG_ENABLE + OutputDebugString("Gain Slider VM Scroll"); +#endif + int pos = SendMessage(GetDlgItem(hwndDlg, IDC_GAINSLIDER), TBM_GETPOS, (WPARAM)0, (LPARAM)0); + GainReduction = pos; + sprintf_s(GainReductionTxt, 254, "%d", pos); + Edit_SetText(GetDlgItem(hwndDlg, IDC_GR), GainReductionTxt); + chParams->tunerParams.gain.gRdB = GainReduction; + if (!Running) + { + SystemGainReduction = GainReduction + ActualLNAGR; + } + else + { + sdrplay_api_Update_fn(chosenDev->dev, chosenDev->tuner, sdrplay_api_Update_Tuner_Gr, sdrplay_api_Update_Ext1_None); + } + sprintf_s(str, sizeof(str), "Total System Gain Reduction %d dB", SystemGainReduction); + Edit_SetText(GetDlgItem(hwndDlg, IDC_TOTALGR), str); + profileChanged = true; + break; + } + + if ((HWND)lParam == GetDlgItem(hwndDlg, IDC_LNASLIDER)) + { + TCHAR LNAGainReductionTxt[255]; +#ifdef DEBUG_ENABLE + OutputDebugString("LNA Slider VM Scroll"); +#endif + int pos = SendMessage(GetDlgItem(hwndDlg, IDC_LNASLIDER), TBM_GETPOS, (WPARAM)0, (LPARAM)0); + LNAGainReduction = pos; + sprintf_s(str, 255, "LNA Slider Position is = %d", LNAGainReduction); + OutputDebugString(str); + sprintf_s(LNAGainReductionTxt, 254, "%d", pos); + Edit_SetText(GetDlgItem(hwndDlg, IDC_LNAGRNO), LNAGainReductionTxt); + chParams->tunerParams.gain.LNAstate = (unsigned char)LNAGainReduction; + if (Running) + { + sdrplay_api_Update_fn(chosenDev->dev, chosenDev->tuner, sdrplay_api_Update_Tuner_Gr, sdrplay_api_Update_Ext1_None); + } + sprintf_s(str, sizeof(str), "Total System Gain Reduction %d dB", SystemGainReduction); + Edit_SetText(GetDlgItem(hwndDlg, IDC_TOTALGR), str); + profileChanged = true; + break; + } + break; + + case WM_INITDIALOG: + // Buffer size + + ghwndDlg = hwndDlg; + TCHAR LNAGainReductionTxt[255]; + + LoadSettings(); + //Buffer Size (currently not used) + for (i = 0; i < (sizeof(buffer_sizes) / sizeof(buffer_sizes[0])); i++) //Work out the size of the buffer. + { + _stprintf_s(str, 255, TEXT("%d kB"), buffer_sizes[i]); + ComboBox_AddString(GetDlgItem(hwndDlg, IDC_BUFFER), str); + } + ComboBox_SetCurSel(GetDlgItem(hwndDlg, IDC_BUFFER), buffer_default); + buffer_len_samples = buffer_sizes[buffer_default] * 1024; + + //Add IF mode strings and select stored IF mode + _stprintf_s(str, 255, "Zero IF"); + ComboBox_AddString(GetDlgItem(hwndDlg, IDC_IFMODE), str); + _stprintf_s(str, 255, "Low IF"); + ComboBox_AddString(GetDlgItem(hwndDlg, IDC_IFMODE), str); + + ComboBox_SetCurSel(GetDlgItem(hwndDlg, IDC_IFMODE), IFmodeIdx); + + if (IFmodeIdx == 1) + Edit_Enable(GetDlgItem(hwndDlg, IDC_SAMPLERATE), 0); + + //Add Filter BW based on IF mode Selection then select stored BW. + ComboBox_ResetContent(GetDlgItem(hwndDlg, IDC_IFBW)); + _stprintf_s(str, 255, "200 kHz"); + ComboBox_AddString(GetDlgItem(hwndDlg, IDC_IFBW), str); + _stprintf_s(str, 255, "300 kHz"); + ComboBox_AddString(GetDlgItem(hwndDlg, IDC_IFBW), str); + _stprintf_s(str, 255, "600 kHz"); + ComboBox_AddString(GetDlgItem(hwndDlg, IDC_IFBW), str); + _stprintf_s(str, 255, "1.536 MHz"); + ComboBox_AddString(GetDlgItem(hwndDlg, IDC_IFBW), str); + + if (IFmodeIdx == 0) + { + IFMode = sdrplay_api_IF_Zero; + _stprintf_s(str, 255, "5.000 MHz"); + ComboBox_AddString(GetDlgItem(hwndDlg, IDC_IFBW), str); + _stprintf_s(str, 255, "6.000 MHz"); + ComboBox_AddString(GetDlgItem(hwndDlg, IDC_IFBW), str); + _stprintf_s(str, 255, "7.000 MHz"); + ComboBox_AddString(GetDlgItem(hwndDlg, IDC_IFBW), str); + _stprintf_s(str, 255, "8.000 MHz"); + ComboBox_AddString(GetDlgItem(hwndDlg, IDC_IFBW), str); + } + + ComboBox_SetCurSel(GetDlgItem(hwndDlg, IDC_IFBW), BandwidthIdx); + Bandwidth = bandwidths[BandwidthIdx].bwType; + + //Add Samplerates based Filter BW & IF mode then select stored Samplerate. + if (IFmodeIdx == 1) + { + ComboBox_ResetContent(GetDlgItem(hwndDlg, IDC_SAMPLERATE)); + _stprintf_s(str, 255, TEXT("2.0")); + ComboBox_AddString(GetDlgItem(hwndDlg, IDC_SAMPLERATE), str); + + chParams->tunerParams.ifType = sdrplay_api_IF_1_620; + + if (Running) + sdrplay_api_Update_fn(chosenDev->dev, chosenDev->tuner, sdrplay_api_Update_Tuner_IfType, sdrplay_api_Update_Ext1_None); + + SampleRateIdx = 0; // Always 2.0 MHz + + ComboBox_SetCurSel(GetDlgItem(hwndDlg, IDC_SAMPLERATE), 0); + + //Disable Sample Rate Dialog Box if in LowIF mode + Edit_Enable(GetDlgItem(hwndDlg, IDC_SAMPLERATE), 0); + } + else + { + //Enable Sample Rate Display & Decimation Dialog Boxes + Edit_Enable(GetDlgItem(hwndDlg, IDC_SAMPLERATE), 1); + + //ZIF Mode + SrCount = (sizeof(samplerates) / sizeof(samplerates[0])); + + //calculate minimum SampleRate for stored BW & IF Settings + BW = (float)bandwidths[BandwidthIdx].BW; + + //Add Sample rates to dialog box based on calculated Minimum & identify chosen rate on way through. + Reset_SAMPLERATE(hwndDlg); + } + + //Populate Decimate Control With Appropriate Sample rates + ComboBox_ResetContent(GetDlgItem(hwndDlg, IDC_DECIMATION)); + _stprintf_s(str, 255, "None"); + ComboBox_AddString(GetDlgItem(hwndDlg, IDC_DECIMATION), str); + _stprintf_s(str, 255, "2"); + ComboBox_AddString(GetDlgItem(hwndDlg, IDC_DECIMATION), str); + _stprintf_s(str, 255, "4"); + ComboBox_AddString(GetDlgItem(hwndDlg, IDC_DECIMATION), str); + _stprintf_s(str, 255, "8"); + ComboBox_AddString(GetDlgItem(hwndDlg, IDC_DECIMATION), str); + + if (IFmodeIdx == 0 && SampleRateIdx >= 2) + { + _stprintf_s(str, 255, "16"); + ComboBox_AddString(GetDlgItem(hwndDlg, IDC_DECIMATION), str); + } + + if (IFmodeIdx == 0 && SampleRateIdx >= 6) + { + _stprintf_s(str, 255, "32"); + ComboBox_AddString(GetDlgItem(hwndDlg, IDC_DECIMATION), str); + } + + ComboBox_SetCurSel(GetDlgItem(hwndDlg, IDC_DECIMATION), DecimationIdx); + + DecimateEnable = 0; + if (DecimationIdx > 0) + DecimateEnable = 1; + + WinradCallBack(-1, WINRAD_SRCHANGE, 0, NULL); + + //Gain Reduction + sprintf_s(GainReductionTxt, 254, "%d", GainReduction); + SendMessage(GetDlgItem(hwndDlg, IDC_GAINSLIDER), TBM_SETRANGEMIN, (WPARAM)true, (LPARAM)GAIN_SLIDER_MIN); + SendMessage(GetDlgItem(hwndDlg, IDC_GAINSLIDER), TBM_SETRANGEMAX, (WPARAM)true, (LPARAM)GAIN_SLIDER_MAX); + SendMessage(GetDlgItem(hwndDlg, IDC_GAINSLIDER), TBM_SETPOS, (WPARAM)true, (LPARAM)GainReduction); + Edit_SetText(GetDlgItem(hwndDlg, IDC_GR), GainReductionTxt); + + // LNA Gain Reduction + sprintf_s(LNAGainReductionTxt, 254, "%d", LNAGainReduction); + SendMessage(GetDlgItem(hwndDlg, IDC_LNASLIDER), TBM_SETRANGEMIN, (WPARAM)true, (LPARAM)LNA_GAIN_SLIDER_MIN); + if (Frequency >= 1000.0) + SendMessage(GetDlgItem(hwndDlg, IDC_LNASLIDER), TBM_SETRANGEMAX, (WPARAM)true, (LPARAM)LNA_GAIN_SLIDER_MAX_1000_2000); + else if (Frequency >= 420.0) + SendMessage(GetDlgItem(hwndDlg, IDC_LNASLIDER), TBM_SETRANGEMAX, (WPARAM)true, (LPARAM)LNA_GAIN_SLIDER_MAX_0420_1000); + else if (Frequency >= 250.0) + SendMessage(GetDlgItem(hwndDlg, IDC_LNASLIDER), TBM_SETRANGEMAX, (WPARAM)true, (LPARAM)LNA_GAIN_SLIDER_MAX_0250_0420); + else if (Frequency >= 60.0) + SendMessage(GetDlgItem(hwndDlg, IDC_LNASLIDER), TBM_SETRANGEMAX, (WPARAM)true, (LPARAM)LNA_GAIN_SLIDER_MAX_0060_0250); + else if (Frequency >= 12.0) + SendMessage(GetDlgItem(hwndDlg, IDC_LNASLIDER), TBM_SETRANGEMAX, (WPARAM)true, (LPARAM)LNA_GAIN_SLIDER_MAX_0012_0060); + else + SendMessage(GetDlgItem(hwndDlg, IDC_LNASLIDER), TBM_SETRANGEMAX, (WPARAM)true, (LPARAM)LNA_GAIN_SLIDER_MAX_0000_0012); + SendMessage(GetDlgItem(hwndDlg, IDC_LNASLIDER), TBM_SETPOS, (WPARAM)true, (LPARAM)LNAGainReduction); + Edit_SetText(GetDlgItem(hwndDlg, IDC_LNAGRNO), LNAGainReductionTxt); + + //Configure for Antenna + ComboBox_ResetContent(GetDlgItem(hwndDlg, IDC_ANTSELECT)); + _stprintf_s(str, 255, "Port A"); + ComboBox_AddString(GetDlgItem(hwndDlg, IDC_ANTSELECT), str); + _stprintf_s(str, 255, "Port B"); + ComboBox_AddString(GetDlgItem(hwndDlg, IDC_ANTSELECT), str); + _stprintf_s(str, 255, "Port C"); + ComboBox_AddString(GetDlgItem(hwndDlg, IDC_ANTSELECT), str); + ComboBox_SetCurSel(GetDlgItem(hwndDlg, IDC_ANTSELECT), AntennaIdx); + + // Broadcast Notch Enable + SendMessage(GetDlgItem(hwndDlg, IDC_NOTCHENABLE), BM_SETCHECK, (WPARAM)(notchEnable ? BST_CHECKED : BST_UNCHECKED), (LPARAM)0); + + // DAB Notch Enable + SendMessage(GetDlgItem(hwndDlg, IDC_DABNOTCHENABLE), BM_SETCHECK, (WPARAM)(dabNotchEnable ? BST_CHECKED : BST_UNCHECKED), (LPARAM)0); + + // Bias T Enable + SendMessage(GetDlgItem(hwndDlg, IDC_BIASTENABLE), BM_SETCHECK, (WPARAM)(biasTEnable ? BST_CHECKED : BST_UNCHECKED), (LPARAM)0); + + //ADC Setpoint + sprintf_s(AGCsetpointTxt, 254, "%d", AGCsetpoint); + SendMessage(GetDlgItem(hwndDlg, IDC_SETPOINT_S), UDM_SETRANGE, (WPARAM)true, 0 | (-50 << 16)); + Edit_SetText(GetDlgItem(hwndDlg, IDC_SETPOINT), AGCsetpointTxt); + + //Frequency Offset + sprintf_s(FreqoffsetTxt, 254, "%.2f", FqOffsetPPM); + SendMessage(GetDlgItem(hwndDlg, IDC_PPM_S), UDM_SETRANGE, (WPARAM)0, (LPARAM)(100000 & 0xFFFF) | (((LPARAM)(-100000) << 16) & 0xFFFF0000)); + Edit_SetText(GetDlgItem(hwndDlg, IDC_PPM), FreqoffsetTxt); + + //AGC Enabled + SendMessage(GetDlgItem(hwndDlg, IDC_RSPAGC), BM_SETCHECK, (WPARAM)(AGCEnabled ? BST_CHECKED : BST_UNCHECKED), (LPARAM)0); + Edit_Enable(GetDlgItem(hwndDlg, IDC_GAINSLIDER), (AGCEnabled ? 0 : 1)); + SendMessage(GetDlgItem(hwndDlg, IDC_GR), WM_ENABLE, (WPARAM)(AGCEnabled ? 0 : 1), 1); +// if (AGCEnabled) +// m_timer = SetTimer(hwndDlg, ID_AGCUPDATE, 600, NULL); + + sprintf_s(str, sizeof(str), "Total System Gain Reduction %d dB", SystemGainReduction); + Edit_SetText(GetDlgItem(hwndDlg, IDC_TOTALGR), str); + + if (h_AdvancedDialog == NULL) + { + h_AdvancedDialog = CreateDialog(hInst, MAKEINTRESOURCE(IDD_ADVANCED), NULL, (DLGPROC)AdvancedDlgProc); //(DLGPROC)AdvancedDlgProc +// ShowWindow(h_AdvancedDialog, SW_SHOW); + ShowWindow(h_AdvancedDialog, SW_HIDE); + } + + if (h_ProfilesDialog == NULL) + { + h_ProfilesDialog = CreateDialog(hInst, MAKEINTRESOURCE(IDD_PROFILES_PANEL), NULL, (DLGPROC)ProfilesDlgProc); //(DLGPROC)ProfilesDlgProc +// ShowWindow(h_ProfilesDialog, SW_SHOW); + ShowWindow(h_ProfilesDialog, SW_HIDE); + } + + if (h_HelpDialog == NULL) + { + h_HelpDialog = CreateDialog(hInst, MAKEINTRESOURCE(IDD_HELP_PANEL), NULL, (DLGPROC)HelpDlgProc); + ShowWindow(h_HelpDialog, SW_HIDE); + } + + if (h_StationDialog == NULL) + { + h_StationDialog = CreateDialog(hInst, MAKEINTRESOURCE(IDD_STATION_PANEL), NULL, (DLGPROC)StationDlgProc); + ShowWindow(h_StationDialog, SW_HIDE); + } + + if (h_StationConfigDialog == NULL) + { + h_StationConfigDialog = CreateDialog(hInst, MAKEINTRESOURCE(IDD_STATIONCONFIG_PANEL), NULL, (DLGPROC)StationConfigDlgProc); + ShowWindow(h_StationConfigDialog, SW_HIDE); + } + + return true; + break; + + case WM_CTLCOLORSTATIC: + CtrlID = GetDlgCtrlID((HWND)lParam); + switch (CtrlID) + { + case (IDC_TOTALGR): + case (IDC_FINALSR): + case (IDC_BIASTENABLE): + case (IDC_PPMTXT): + case (IDC_NOTCHENABLE): + case (IDC_DABNOTCHENABLE): + case (IDC_OVERLOAD): + HDC hdcStatic = (HDC)wParam; + SetBkColor(hdcStatic, RGB(255, 255, 255)); + if (CtrlID == IDC_OVERLOAD) + { + SetTextColor(hdcStatic, RGB(255, 0, 0)); + } + return (INT_PTR)hBrush; + break; + } + break; + + case WM_COMMAND: + switch (GET_WM_COMMAND_ID(wParam, lParam)) + { + case IDC_Advanced: + if (GET_WM_COMMAND_CMD(wParam, lParam) == BN_CLICKED) + { + if (h_AdvancedDialog == NULL) + h_AdvancedDialog = CreateDialog(hInst, MAKEINTRESOURCE(IDD_ADVANCED), NULL, (DLGPROC)AdvancedDlgProc); + ShowWindow(h_AdvancedDialog, SW_SHOW); + SetForegroundWindow(h_AdvancedDialog); + return true; + } + break; + + case IDC_StationName_PopOut: + if (GET_WM_COMMAND_CMD(wParam, lParam) == BN_CLICKED) + { + if (h_StationDialog == NULL) + h_StationDialog = CreateDialog(hInst, MAKEINTRESOURCE(IDD_STATION_PANEL), NULL, (DLGPROC)StationDlgProc); + ShowWindow(h_StationDialog, SW_SHOW); + SetForegroundWindow(h_StationDialog); + return true; + } + break; + + case IDC_ProfilesButton: + if (GET_WM_COMMAND_CMD(wParam, lParam) == BN_CLICKED) + { + if (h_ProfilesDialog == NULL) + h_ProfilesDialog = CreateDialog(hInst, MAKEINTRESOURCE(IDD_PROFILES_PANEL), NULL, (DLGPROC)ProfilesDlgProc); + ShowWindow(h_ProfilesDialog, SW_SHOW); + SetForegroundWindow(h_ProfilesDialog); + return true; + } + break; + + case IDC_HELP_BUTTON: + if (GET_WM_COMMAND_CMD(wParam, lParam) == BN_CLICKED) + { + if (h_HelpDialog == NULL) + h_HelpDialog = CreateDialog(hInst, MAKEINTRESOURCE(IDD_HELP_PANEL), NULL, (DLGPROC)HelpDlgProc); + ShowWindow(h_HelpDialog, SW_SHOW); + SetForegroundWindow(h_HelpDialog); + return true; + } + break; + + case IDC_SAMPLERATE: + + if (GET_WM_COMMAND_CMD(wParam, lParam) == CBN_SELCHANGE) + { + if (ComboBox_GetCurSel(GET_WM_COMMAND_HWND(wParam, lParam)) != SampleRateIdx) + { +#ifdef DEBUG_ENABLE + OutputDebugString("IDC_SAMPLERATE"); +#endif + SampleRateIdx = ComboBox_GetCurSel(GET_WM_COMMAND_HWND(wParam, lParam)); + + deviceParams->devParams->fsFreq.fsHz = samplerates[SampleRateIdx].value * 1e6; + + Reset_DECIMATION(hwndDlg); + Update_IFBW(); + + ReinitAll(); + UpdateSR(); + } + } + break; + + case IDC_DECIMATION: + if (GET_WM_COMMAND_CMD(wParam, lParam) == CBN_SELCHANGE) + { + if (ComboBox_GetCurSel(GET_WM_COMMAND_HWND(wParam, lParam)) != DecimationIdx) + { +#ifdef DEBUG_ENABLE + OutputDebugString("IDC_DECIMATION"); +#endif + DecimationIdx = ComboBox_GetCurSel(GET_WM_COMMAND_HWND(wParam, lParam)); + + int decValue = Decimation[DecimationIdx].DecValue; + + Update_IFBW(); + + ApplyDecimation(decValue); + + UpdateSR(); + } + } + break; + + case IDC_BUFFER: + if (GET_WM_COMMAND_CMD(wParam, lParam) == CBN_SELCHANGE) + { + buffer_default = ComboBox_GetCurSel(GET_WM_COMMAND_HWND(wParam, lParam)); + if (Running) + { + buffer_len_samples = buffer_sizes[buffer_default] * 1024; + WinradCallBack(-1, WINRAD_SRCHANGE, 0, NULL); + ::Sleep(200); + } + else + buffer_len_samples = buffer_sizes[buffer_default] * 1024; + return true; + } + break; + + case IDC_BIASTENABLE: + if (ghwndDlg) // update only when already initialized! + { + if (GET_WM_COMMAND_CMD(wParam, lParam) == BST_UNCHECKED) + { + if (Button_GetCheck(GET_WM_COMMAND_HWND(wParam, lParam)) == BST_CHECKED) //it is checked + { + biasTEnable = 1; + deviceParams->devParams->rspDxParams.biasTEnable = (unsigned char)biasTEnable; + if (Running) + sdrplay_api_Update_fn(chosenDev->dev, chosenDev->tuner, sdrplay_api_Update_None, sdrplay_api_Update_RspDx_BiasTControl); + } + else + { + biasTEnable = 0; + deviceParams->devParams->rspDxParams.biasTEnable = (unsigned char)biasTEnable; + if (Running) + sdrplay_api_Update_fn(chosenDev->dev, chosenDev->tuner, sdrplay_api_Update_None, sdrplay_api_Update_RspDx_BiasTControl); + } + } + return true; + } + break; + + case IDC_NOTCHENABLE: + if (ghwndDlg) // update only when already initialized! + { + if (GET_WM_COMMAND_CMD(wParam, lParam) == BST_UNCHECKED) + { + if (Button_GetCheck(GET_WM_COMMAND_HWND(wParam, lParam)) == BST_CHECKED) //it is checked + { + notchEnable = 1; + deviceParams->devParams->rspDxParams.rfNotchEnable = (unsigned char)notchEnable; + if (Running) + sdrplay_api_Update_fn(chosenDev->dev, chosenDev->tuner, sdrplay_api_Update_None, sdrplay_api_Update_RspDx_RfNotchControl); + } + else + { + notchEnable = 0; + deviceParams->devParams->rspDxParams.rfNotchEnable = (unsigned char)notchEnable; + if (Running) + sdrplay_api_Update_fn(chosenDev->dev, chosenDev->tuner, sdrplay_api_Update_None, sdrplay_api_Update_RspDx_RfNotchControl); + } + } + return true; + } + break; + + case IDC_DABNOTCHENABLE: + if (ghwndDlg) // update only when already initialized! + { + if (GET_WM_COMMAND_CMD(wParam, lParam) == BST_UNCHECKED) + { + if (Button_GetCheck(GET_WM_COMMAND_HWND(wParam, lParam)) == BST_CHECKED) //it is checked + { + dabNotchEnable = 1; + deviceParams->devParams->rspDxParams.rfDabNotchEnable = (unsigned char)dabNotchEnable; + if (Running) + sdrplay_api_Update_fn(chosenDev->dev, chosenDev->tuner, sdrplay_api_Update_None, sdrplay_api_Update_RspDx_RfDabNotchControl); + } + else + { + dabNotchEnable = 0; + deviceParams->devParams->rspDxParams.rfDabNotchEnable = (unsigned char)dabNotchEnable; + if (Running) + sdrplay_api_Update_fn(chosenDev->dev, chosenDev->tuner, sdrplay_api_Update_None, sdrplay_api_Update_RspDx_RfDabNotchControl); + } + } + return true; + } + break; + + case IDC_RSPAGC: + if (ghwndDlg) // update only when already initialized! + { + if (GET_WM_COMMAND_CMD(wParam, lParam) == BST_UNCHECKED) + { + if (Button_GetCheck(GET_WM_COMMAND_HWND(wParam, lParam)) == BST_CHECKED) //it is checked + { + AGCEnabled = true; + chParams->ctrlParams.agc.enable = sdrplay_api_AGC_5HZ; + Edit_Enable(GetDlgItem(hwndDlg, IDC_GR), 0); + Edit_Enable(GetDlgItem(hwndDlg, IDC_GAINSLIDER), 0); +// m_timer = SetTimer(hwndDlg, ID_AGCUPDATE, 600, NULL); + //MessageBox(NULL, "Timer enabled", NULL, MB_OK); + } + else + { + AGCEnabled = false; + chParams->ctrlParams.agc.enable = sdrplay_api_AGC_DISABLE; + Edit_Enable(GetDlgItem(hwndDlg, IDC_GR), 1); + Edit_Enable(GetDlgItem(hwndDlg, IDC_GAINSLIDER), 1); +// KillTimer(hwndDlg, ID_AGCUPDATE); + } + if (Running) + { + sdrplay_api_Update_fn(chosenDev->dev, chosenDev->tuner, sdrplay_api_Update_Ctrl_Agc, sdrplay_api_Update_Ext1_None); + } + } + return true; + } + break; + + case IDC_SETPOINT: + if (GET_WM_COMMAND_CMD(wParam, lParam) == EN_UPDATE) + { + TCHAR SP[255]; + // need to have error checking applied here. + Edit_GetText((HWND)lParam, SP, 255); + if (ghwndDlg) // update only when already initialized! + { + AGCsetpoint = _ttoi(SP); + chParams->ctrlParams.agc.setPoint_dBfs = AGCsetpoint; + } + if (Running) + sdrplay_api_Update_fn(chosenDev->dev, chosenDev->tuner, sdrplay_api_Update_Ctrl_Agc, sdrplay_api_Update_Ext1_None); + return true; + } + break; + + case IDC_PPM: + if (GET_WM_COMMAND_CMD(wParam, lParam) == EN_UPDATE) + { + TCHAR Freqoffset[255]; + if (!DeltaPosClick) + Edit_GetText(GetDlgItem(hwndDlg, IDC_PPM), Freqoffset, 255); + FqOffsetPPM = (float)atof(Freqoffset); + deviceParams->devParams->ppm = FqOffsetPPM; + + DeltaPosClick = false; + if (Running) + sdrplay_api_Update_fn(chosenDev->dev, chosenDev->tuner, sdrplay_api_Update_Dev_Ppm, sdrplay_api_Update_Ext1_None); + return true; + } + break; + + case IDC_ANTSELECT: + if (GET_WM_COMMAND_CMD(wParam, lParam) == CBN_SELCHANGE) + { + AntennaIdx = ComboBox_GetCurSel(GET_WM_COMMAND_HWND(wParam, lParam)); +#ifdef DEBUG_ENABLE + sprintf_s(str, 255, "TunerIdx: %d", TunerIdx); + OutputDebugString(str); +#endif + if (AntennaIdx == 0 && deviceParams->devParams->rspDxParams.antennaSel != sdrplay_api_RspDx_ANTENNA_A) // Port A + { + deviceParams->devParams->rspDxParams.antennaSel = sdrplay_api_RspDx_ANTENNA_A; + if (Running) + { + sdrplay_api_Update_fn(chosenDev->dev, chosenDev->tuner, sdrplay_api_Update_None, sdrplay_api_Update_RspDx_AntennaControl); + } + } + else if (AntennaIdx == 1 && deviceParams->devParams->rspDxParams.antennaSel != sdrplay_api_RspDx_ANTENNA_B) // Port B + { + deviceParams->devParams->rspDxParams.antennaSel = sdrplay_api_RspDx_ANTENNA_B; + if (Running) + { + sdrplay_api_Update_fn(chosenDev->dev, chosenDev->tuner, sdrplay_api_Update_None, sdrplay_api_Update_RspDx_AntennaControl); + } + } + else if (AntennaIdx == 2 && deviceParams->devParams->rspDxParams.antennaSel != sdrplay_api_RspDx_ANTENNA_C) // Port B + { + if (Frequency < 200.0) + { + deviceParams->devParams->rspDxParams.antennaSel = sdrplay_api_RspDx_ANTENNA_C; + if (Running) + { + sdrplay_api_Update_fn(chosenDev->dev, chosenDev->tuner, sdrplay_api_Update_None, sdrplay_api_Update_RspDx_AntennaControl); + } + } + else + { + AntennaIdx = 0; + ComboBox_SetCurSel(GetDlgItem(hwndDlg, IDC_ANTSELECT), AntennaIdx); // Set Port A + } + } + return true; + } + break; + + case IDC_EXIT: + if (GET_WM_COMMAND_CMD(wParam, lParam) == BN_CLICKED) + { + for (i = 1; i <= NUM_OF_HOTKEYS; i++) + { + UnregisterHotKey(h_dialog, i); + } + definedHotkeys = false; + ShowWindow(h_dialog, SW_HIDE); + if (h_AdvancedDialog != NULL) + ShowWindow(h_AdvancedDialog, SW_HIDE); + if (h_ProfilesDialog != NULL) + ShowWindow(h_ProfilesDialog, SW_HIDE); + if (h_HelpDialog != NULL) + ShowWindow(h_HelpDialog, SW_HIDE); + return true; + } + break; + + case IDC_LoadDefaults: + if (GET_WM_COMMAND_CMD(wParam, lParam) == BN_CLICKED) + { + _stprintf_s(str, TEXT("Current Profile: Default")); + Edit_SetText(GetDlgItem(hwndDlg, IDC_ProfileFileName), str); + + Edit_Enable(GetDlgItem(hwndDlg, IDC_IFMODE), 1); + + IFmodeIdx = 1; + ComboBox_SetCurSel(GetDlgItem(hwndDlg, IDC_IFMODE), IFmodeIdx); + + //Bandwidth + ComboBox_ResetContent(GetDlgItem(hwndDlg, IDC_IFBW)); + _stprintf_s(str, 255, "200 kHz"); + ComboBox_AddString(GetDlgItem(hwndDlg, IDC_IFBW), str); + _stprintf_s(str, 255, "300 kHz"); + ComboBox_AddString(GetDlgItem(hwndDlg, IDC_IFBW), str); + _stprintf_s(str, 255, "600 kHz"); + ComboBox_AddString(GetDlgItem(hwndDlg, IDC_IFBW), str); + _stprintf_s(str, 255, "1.536 MHz"); + ComboBox_AddString(GetDlgItem(hwndDlg, IDC_IFBW), str); + BandwidthIdx = 3; + ComboBox_SetCurSel(GetDlgItem(hwndDlg, IDC_IFBW), BandwidthIdx); + Bandwidth = bandwidths[BandwidthIdx].bwType; + chParams->tunerParams.bwType = Bandwidth; + + SampleRateIdx = 0; + deviceParams->devParams->fsFreq.fsHz = 6000000.0; + IFMode = sdrplay_api_IF_1_620; + chParams->tunerParams.ifType = IFMode; + ComboBox_ResetContent(GetDlgItem(hwndDlg, IDC_SAMPLERATE)); + ComboBox_AddString(GetDlgItem(hwndDlg, IDC_SAMPLERATE), "2.0"); + ComboBox_SetCurSel(GetDlgItem(hwndDlg, IDC_SAMPLERATE), SampleRateIdx); + Edit_Enable(GetDlgItem(hwndDlg, IDC_SAMPLERATE), 0); + SR = 2.0; + + DecimationIdx = 0; + DecimateEnable = 0; + ComboBox_ResetContent(GetDlgItem(hwndDlg, IDC_DECIMATION)); + ComboBox_AddString(GetDlgItem(hwndDlg, IDC_DECIMATION), "None"); + ComboBox_AddString(GetDlgItem(hwndDlg, IDC_DECIMATION), "2"); + ComboBox_AddString(GetDlgItem(hwndDlg, IDC_DECIMATION), "4"); + ComboBox_AddString(GetDlgItem(hwndDlg, IDC_DECIMATION), "8"); + ComboBox_SetCurSel(GetDlgItem(hwndDlg, IDC_DECIMATION), DecimationIdx); + + // LNA gain reduction setup + LNAGainReduction = 4; + sprintf_s(LNAGainReductionTxt, 254, "%d", LNAGainReduction); + Edit_SetText(GetDlgItem(hwndDlg, IDC_LNAGRNO), LNAGainReductionTxt); + SendMessage(GetDlgItem(hwndDlg, IDC_LNASLIDER), TBM_SETPOS, (WPARAM)true, (LPARAM)LNAGainReduction); + + //Gain Reduction + GainReduction = INITIAL_GR; + sprintf_s(GainReductionTxt, 254, "%d", GainReduction); + Edit_SetText(GetDlgItem(hwndDlg, IDC_GR), GainReductionTxt); + SendMessage(GetDlgItem(hwndDlg, IDC_GAINSLIDER), TBM_SETPOS, (WPARAM)true, (LPARAM)GainReduction); + + sprintf_s(str, sizeof(str), "Total System Gain Reduction %d dB", 84); + Edit_SetText(GetDlgItem(hwndDlg, IDC_TOTALGR), str); + + //AGCSetpoint + AGCsetpoint = -30; + sprintf_s(AGCsetpointTxt, 254, "%d", AGCsetpoint); + Edit_SetText(GetDlgItem(hwndDlg, IDC_SETPOINT), AGCsetpointTxt); + + //Frequency Offset + FqOffsetPPM = 0; + sprintf_s(FreqoffsetTxt, 254, "%.2f", FqOffsetPPM); + Edit_SetText(GetDlgItem(hwndDlg, IDC_PPM), FreqoffsetTxt); + + //AGC + AGCEnabled = true; + SendMessage(GetDlgItem(hwndDlg, IDC_RSPAGC), BM_SETCHECK, (WPARAM)(1), 1); // (WPARAM)(1) = true + Edit_Enable(GetDlgItem(hwndDlg, IDC_GR), 0); + Edit_Enable(GetDlgItem(hwndDlg, IDC_GAINSLIDER), 0); + //m_timer = SetTimer(hwndDlg, ID_AGCUPDATE, 600, NULL); + + //LOPLan + LOplan = LO120MHz; + LOplanAuto = true; +// WinradCallBack(-1, WINRAD_SRCHANGE, 0, NULL); + + DcCompensationMode = PERIODIC3; + TrackingPeriod = 32; + RefreshPeriodMemory = 2; + PostTunerDcCompensation = true; + + // Port A + AntennaIdx = 0; + deviceParams->devParams->rspDxParams.antennaSel = sdrplay_api_RspDx_ANTENNA_A; + ComboBox_SetCurSel(GetDlgItem(hwndDlg, IDC_ANTSELECT), AntennaIdx); + + // Broadcast Notch Enable + notchEnable = 0; + SendMessage(GetDlgItem(hwndDlg, IDC_NOTCHENABLE), BM_SETCHECK, (WPARAM)(notchEnable ? BST_CHECKED : BST_UNCHECKED), (LPARAM)0); + + // DAB Notch Enable + dabNotchEnable = 0; + SendMessage(GetDlgItem(hwndDlg, IDC_DABNOTCHENABLE), BM_SETCHECK, (WPARAM)(dabNotchEnable ? BST_CHECKED : BST_UNCHECKED), (LPARAM)0); + + // Bias T Enable + biasTEnable = 0; + SendMessage(GetDlgItem(hwndDlg, IDC_BIASTENABLE), BM_SETCHECK, (WPARAM)(biasTEnable ? BST_CHECKED : BST_UNCHECKED), (LPARAM)0); + + ReinitAll(); + UpdateSR(); + + // Station Lookup + stationLookup = false; + workOffline = false; + ITUIndex = 0; + TACIndex = 0; + + if (h_StationConfigDialog != NULL) + { + SendMessage(GetDlgItem(h_StationConfigDialog, IDC_STATIONCONFIG_ENABLE), BM_SETCHECK, (WPARAM)(0), 0); + SendMessage(GetDlgItem(h_StationConfigDialog, IDC_STATIONCONFIG_OFFLINE), BM_SETCHECK, (WPARAM)(0), 0); + ComboBox_SetCurSel(GetDlgItem(h_StationConfigDialog, IDC_STATIONCONFIG_ITU), ITUIndex); + ComboBox_SetCurSel(GetDlgItem(h_StationConfigDialog, IDC_STATIONCONFIG_TAC), TACIndex); + } + return true; + } + break; + + case IDC_IFBW: + if (GET_WM_COMMAND_CMD(wParam, lParam) == CBN_SELCHANGE) + { +#ifdef DEBUG_ENABLE + OutputDebugString("IDC_IFBW"); +#endif + BandwidthIdx = ComboBox_GetCurSel(GET_WM_COMMAND_HWND(wParam, lParam)); + Bandwidth = bandwidths[BandwidthIdx].bwType; + + chParams->tunerParams.bwType = Bandwidth; + + if (Running) + sdrplay_api_Update_fn(chosenDev->dev, chosenDev->tuner, sdrplay_api_Update_Tuner_BwType, sdrplay_api_Update_Ext1_None); + + } + break; + + case IDC_IFMODE: + if (GET_WM_COMMAND_CMD(wParam, lParam) == CBN_SELCHANGE) + { +#ifdef DEBUG_ENABLE + OutputDebugString("IDC_IFMODE"); +#endif + IFmodeIdx = ComboBox_GetCurSel(GET_WM_COMMAND_HWND(wParam, lParam)); + + if (IFmodeIdx == 0) + { +#ifdef DEBUG_ENABLE + OutputDebugString("IFmodeIdx: 0"); +#endif + IFMode = sdrplay_api_IF_Zero; + chParams->tunerParams.ifType = IFMode; + } + else + { +#ifdef DEBUG_ENABLE + OutputDebugString("IFmodeIdx: 1"); +#endif + IFMode = sdrplay_api_IF_1_620; + chParams->tunerParams.ifType = IFMode; + } + + Reset_SAMPLERATE(hwndDlg); + Reset_DECIMATION(hwndDlg); + Reset_IFBW(); + + ReinitAll(); + + UpdateSR(); + + return true; + } + break; + } + } + return false; + } + +static INT_PTR CALLBACK AdvancedDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + static HWND hGain; + static HBRUSH BRUSH_RED = CreateSolidBrush(RGB(255, 0, 0)); + static HBRUSH BRUSH_GREEN = CreateSolidBrush(RGB(0, 255, 0)); + int periodic; + TCHAR str[255]; + static bool LOplanAutoLCL; + static int LOplanLCL; + static int DcCompensationModeLCL; + static int RefreshPeriodMemoryLCL; + static bool PostTunerDcCompensationLCL; + + switch (uMsg) + { + case WM_CLOSE: + ShowWindow(h_AdvancedDialog, SW_HIDE); + return true; + break; + + case WM_HSCROLL: + if ((HWND)lParam == GetDlgItem(hwndDlg, IDC_TRACKINGPERIOD)) + { + TrackingPeriod = SendMessage(GetDlgItem(hwndDlg, IDC_TRACKINGPERIOD), TBM_GETPOS, (WPARAM)0, (LPARAM)0); + TrackTime = TrackingPeriod *DCTrackTimeInterval; + sprintf_s(str, 254, "%.2f uS", TrackTime); + Edit_SetText(GetDlgItem(hwndDlg, IDC_TRACKTIME), str); + } + return true; + break; + + case WM_DESTROY: + h_AdvancedDialog = NULL; + return true; + break; + + case WM_INITDIALOG: + // LO Planning + if (LOplanAuto) + { + SendMessage(GetDlgItem(hwndDlg, IDC_LOAUTO), BM_SETCHECK, BST_CHECKED, 0); + Edit_SetText(GetDlgItem(hwndDlg, IDC_LOWARNING), "Full Coverage"); + Edit_SetText(GetDlgItem(hwndDlg, IDC_LOWARNING1), " "); + } + else + { + if (LOplan == LO120MHz) + { + SendMessage(GetDlgItem(hwndDlg, IDC_LO120), BM_SETCHECK, BST_CHECKED, 0); + Edit_SetText(GetDlgItem(hwndDlg, IDC_LOWARNING), "Coverage gap between 370MHz and 420MHz"); + Edit_SetText(GetDlgItem(hwndDlg, IDC_LOWARNING1), " "); + } + if (LOplan == LO144MHz) + { + SendMessage(GetDlgItem(hwndDlg, IDC_LO144), BM_SETCHECK, BST_CHECKED, 0); + Edit_SetText(GetDlgItem(hwndDlg, IDC_LOWARNING), "Coverage gaps between 250MHz to 255MHz"); + Edit_SetText(GetDlgItem(hwndDlg, IDC_LOWARNING1), "Coverage gaps between 400MHz to 420MHz"); + } + if (LOplan == LO168MHz) + { + SendMessage(GetDlgItem(hwndDlg, IDC_LO168), BM_SETCHECK, BST_CHECKED, 0); + Edit_SetText(GetDlgItem(hwndDlg, IDC_LOWARNING), "Coverage gap between 250MHz and 265MHz"); + Edit_SetText(GetDlgItem(hwndDlg, IDC_LOWARNING1), " "); + } + } + + //Tracking period + SendMessage(GetDlgItem(hwndDlg, IDC_TRACKINGPERIOD), TBM_SETRANGEMIN, (WPARAM)true, (LPARAM)1); + SendMessage(GetDlgItem(hwndDlg, IDC_TRACKINGPERIOD), TBM_SETRANGEMAX, (WPARAM)true, (LPARAM)63); + SendMessage(GetDlgItem(hwndDlg, IDC_TRACKINGPERIOD), TBM_SETPOS, (WPARAM)true, (LPARAM)TrackingPeriod); + TrackTime = TrackingPeriod *DCTrackTimeInterval; + sprintf_s(str, 254, "%.2f uS", TrackTime); + Edit_SetText(GetDlgItem(hwndDlg, IDC_TRACKTIME), str); + + //Populate the refresh period + ComboBox_ResetContent(GetDlgItem(hwndDlg, IDC_REFRESH)); + ComboBox_AddString(GetDlgItem(hwndDlg, IDC_REFRESH), "6mS"); + ComboBox_AddString(GetDlgItem(hwndDlg, IDC_REFRESH), "12mS"); + ComboBox_AddString(GetDlgItem(hwndDlg, IDC_REFRESH), "24mS"); + ComboBox_SetCurSel(GetDlgItem(hwndDlg, IDC_REFRESH), RefreshPeriodMemory); + + //DC Offset Compensation + if (DcCompensationMode == STATIC) + { + SendMessage(GetDlgItem(hwndDlg, IDC_DCSTAT), BM_SETCHECK, BST_CHECKED, 0); + Edit_Enable(GetDlgItem(hwndDlg, IDC_REFRESH), 0); + Edit_Enable(GetDlgItem(hwndDlg, IDC_TRACKINGPERIOD), 0); + Edit_Enable(GetDlgItem(hwndDlg, IDC_TRACKTIME), 0); + } + if (DcCompensationMode == ONESHOT) + { + SendMessage(GetDlgItem(hwndDlg, IDC_ONESHOT), BM_SETCHECK, BST_CHECKED, 0); + Edit_Enable(GetDlgItem(hwndDlg, IDC_REFRESH), 0); + Edit_Enable(GetDlgItem(hwndDlg, IDC_TRACKINGPERIOD), 1); + Edit_Enable(GetDlgItem(hwndDlg, IDC_TRACKTIME), 1); + } + if (DcCompensationMode == CONTINUOUS) + { + SendMessage(GetDlgItem(hwndDlg, IDC_CONTINUOUS), BM_SETCHECK, BST_CHECKED, 0); + Edit_Enable(GetDlgItem(hwndDlg, IDC_REFRESH), 0); + Edit_Enable(GetDlgItem(hwndDlg, IDC_TRACKINGPERIOD), 0); + Edit_Enable(GetDlgItem(hwndDlg, IDC_TRACKTIME), 0); + } + if (DcCompensationMode == PERIODIC1 || DcCompensationMode == PERIODIC2 || DcCompensationMode == PERIODIC3) + { + SendMessage(GetDlgItem(hwndDlg, IDC_PERIODIC), BM_SETCHECK, BST_CHECKED, 0); + Edit_Enable(GetDlgItem(hwndDlg, IDC_REFRESH), 1); + Edit_Enable(GetDlgItem(hwndDlg, IDC_TRACKINGPERIOD), 1); + Edit_Enable(GetDlgItem(hwndDlg, IDC_TRACKTIME), 1); + if (DcCompensationMode == PERIODIC1) + { + ComboBox_SetCurSel(GetDlgItem(hwndDlg, IDC_REFRESH), 0); + } + if (DcCompensationMode == PERIODIC2) + { + ComboBox_SetCurSel(GetDlgItem(hwndDlg, IDC_REFRESH), 1); + } + if (DcCompensationMode == PERIODIC3) + { + ComboBox_SetCurSel(GetDlgItem(hwndDlg, IDC_REFRESH), 2); + } + } + + //Post Tuner DC Compensdation + if (PostTunerDcCompensation) + SendMessage(GetDlgItem(hwndDlg, IDC_POSTDCOFFSET), BM_SETCHECK, BST_CHECKED, 0); + else + SendMessage(GetDlgItem(hwndDlg, IDC_POSTDCOFFSET), BM_SETCHECK, BST_UNCHECKED, 0); + + LOplanAutoLCL = LOplanAuto; + LOplanLCL = LOplan; + DcCompensationModeLCL = DcCompensationMode; + RefreshPeriodMemoryLCL = RefreshPeriodMemory; + PostTunerDcCompensationLCL = PostTunerDcCompensation; + return true; + break; + + case WM_COMMAND: + switch (GET_WM_COMMAND_ID(wParam, lParam)) + { + case IDC_ADVANCED_EXIT: + ShowWindow(h_AdvancedDialog, SW_HIDE); + return true; + break; + + case IDC_ADVANCED_APPLY: + if ((PostTunerDcCompensation != PostTunerDcCompensationLCL) || (LOplanAuto != LOplanAutoLCL) || (LOplan != LOplanLCL)) + { + PostTunerDcCompensation = PostTunerDcCompensationLCL; + IQCompensation(PostTunerDcCompensation); + LOplanAuto = LOplanAutoLCL; + LOplan = LOplanLCL; + LOMode = GetLoMode(); + DcCompensationMode = DcCompensationModeLCL; + RefreshPeriodMemory = RefreshPeriodMemoryLCL; + if (Running) + { + ReinitAll(); + UpdateSR(); + } + } + else + { + if ((DcCompensationMode != DcCompensationModeLCL) || (RefreshPeriodMemory != RefreshPeriodMemoryLCL)) + { + DcCompensationMode = DcCompensationModeLCL; + RefreshPeriodMemory = RefreshPeriodMemoryLCL; + chParams->tunerParams.dcOffsetTuner.dcCal = (unsigned char)DcCompensationMode; + chParams->tunerParams.dcOffsetTuner.speedUp = 0; + if (Running) + sdrplay_api_Update_fn(chosenDev->dev, chosenDev->tuner, sdrplay_api_Update_Tuner_DcOffset, sdrplay_api_Update_Ext1_None); + } + } + return true; + break; + + case IDC_ADVANCED_STATIONCONFIG: + if (GET_WM_COMMAND_CMD(wParam, lParam) == BN_CLICKED) + { + if (h_StationConfigDialog == NULL) + h_StationConfigDialog = CreateDialog(hInst, MAKEINTRESOURCE(IDD_STATIONCONFIG_PANEL), NULL, (DLGPROC)StationConfigDlgProc); + ShowWindow(h_StationConfigDialog, SW_SHOW); + SetForegroundWindow(h_StationConfigDialog); + return true; + } + + case IDC_LOAUTO: + if (GET_WM_COMMAND_CMD(wParam, lParam) == BN_CLICKED) + { + LOplanAutoLCL = true; + Edit_SetText(GetDlgItem(hwndDlg, IDC_LOWARNING), "Full Coverage"); + Edit_SetText(GetDlgItem(hwndDlg, IDC_LOWARNING1), " "); + } + return true; + break; + + case IDC_LO120: + if (GET_WM_COMMAND_CMD(wParam, lParam) == BN_CLICKED) + { + LOplanAutoLCL = false; + LOplanLCL = LO120MHz; + Edit_SetText(GetDlgItem(hwndDlg, IDC_LOWARNING), "Coverage gap between 370MHz and 420MHz"); + Edit_SetText(GetDlgItem(hwndDlg, IDC_LOWARNING1), " "); + MessageBox(NULL, "By selecting this LO PLan there will be a coverage gap between 370MHz and 420MHz", TEXT("SDRplay ExtIO DLL Warning"), MB_OK | MB_SYSTEMMODAL | MB_TOPMOST | MB_ICONEXCLAMATION); + } + return true; + break; + + case IDC_LO144: + if (GET_WM_COMMAND_CMD(wParam, lParam) == BN_CLICKED) + { + LOplanAutoLCL = false; + LOplanLCL = LO144MHz; + Edit_SetText(GetDlgItem(hwndDlg, IDC_LOWARNING), "Coverage gaps between 250MHz to 255MHz"); + Edit_SetText(GetDlgItem(hwndDlg, IDC_LOWARNING1), "Coverage gaps between 400MHz to 420MHz"); + MessageBox(NULL, "By selecting this LO PLan there will be coverage gaps between 250MHz to 255MHz and 400MHz to 420MHz", TEXT("SDRplay ExtIO DLL Warning"), MB_OK | MB_SYSTEMMODAL | MB_TOPMOST | MB_ICONEXCLAMATION); + } + return true; + break; + + case IDC_LO168: + if (GET_WM_COMMAND_CMD(wParam, lParam) == BN_CLICKED) + { + LOplanAutoLCL = false; + LOplanLCL = LO168MHz; + Edit_SetText(GetDlgItem(hwndDlg, IDC_LOWARNING), "Coverage gap between 250MHz and 265MHz"); + Edit_SetText(GetDlgItem(hwndDlg, IDC_LOWARNING1), " "); + MessageBox(NULL, "By selecting this LO PLan there will be a coverage gap between 250MHz and 265MHz", TEXT("SDRplay ExtIO DLL Warning"), MB_OK | MB_SYSTEMMODAL | MB_TOPMOST | MB_ICONEXCLAMATION); + } + return true; + break; + + case IDC_POSTDCOFFSET: + if (GET_WM_COMMAND_CMD(wParam, lParam) == BN_CLICKED) + { + if (Button_GetCheck(GET_WM_COMMAND_HWND(wParam, lParam)) == BST_CHECKED) + PostTunerDcCompensationLCL = true; + else + PostTunerDcCompensationLCL = false; + } + return true; + break; + + case IDC_DCSTAT: + if (GET_WM_COMMAND_CMD(wParam, lParam) == BN_CLICKED) + { + DcCompensationModeLCL = STATIC; + Edit_Enable(GetDlgItem(hwndDlg, IDC_REFRESH), 0); + Edit_Enable(GetDlgItem(hwndDlg, IDC_TRACKINGPERIOD), 0); + Edit_Enable(GetDlgItem(hwndDlg, IDC_TRACKTIME), 0); + } + return true; + break; + + case IDC_ONESHOT: + if (GET_WM_COMMAND_CMD(wParam, lParam) == BN_CLICKED) + { + DcCompensationModeLCL = ONESHOT; + Edit_Enable(GetDlgItem(hwndDlg, IDC_REFRESH), 0); + Edit_Enable(GetDlgItem(hwndDlg, IDC_TRACKINGPERIOD), 1); + Edit_Enable(GetDlgItem(hwndDlg, IDC_TRACKTIME), 1); + } + return true; + break; + + case IDC_CONTINUOUS: + if (GET_WM_COMMAND_CMD(wParam, lParam) == BN_CLICKED) + { + DcCompensationModeLCL = CONTINUOUS; + Edit_Enable(GetDlgItem(hwndDlg, IDC_REFRESH), 0); + Edit_Enable(GetDlgItem(hwndDlg, IDC_TRACKINGPERIOD), 0); + Edit_Enable(GetDlgItem(hwndDlg, IDC_TRACKTIME), 0); + } + return true; + break; + + case IDC_PERIODIC: + if (GET_WM_COMMAND_CMD(wParam, lParam) == BN_CLICKED) + { + Edit_Enable(GetDlgItem(hwndDlg, IDC_REFRESH), 1); + Edit_Enable(GetDlgItem(hwndDlg, IDC_TRACKINGPERIOD), 1); + Edit_Enable(GetDlgItem(hwndDlg, IDC_TRACKTIME), 1); + periodic = ComboBox_GetCurSel(GetDlgItem(hwndDlg, IDC_REFRESH)); + if (periodic == 0) + { + DcCompensationModeLCL = PERIODIC1; + RefreshPeriodMemoryLCL = 0; + } + if (periodic == 1) + { + DcCompensationModeLCL = PERIODIC2; + RefreshPeriodMemoryLCL = 1; + } + if (periodic == 2) + { + DcCompensationModeLCL = PERIODIC3; + RefreshPeriodMemoryLCL = 2; + } + } + return true; + break; + + case IDC_REFRESH: + if (GET_WM_COMMAND_CMD(wParam, lParam) == CBN_SELCHANGE) + { + periodic = ComboBox_GetCurSel(GET_WM_COMMAND_HWND(wParam, lParam)); + if (periodic == 0) + { + DcCompensationModeLCL = PERIODIC1; + RefreshPeriodMemoryLCL = 0; + } + if (periodic == 1) + { + DcCompensationModeLCL = PERIODIC2; + RefreshPeriodMemoryLCL = 1; + } + if (periodic == 2) + { + DcCompensationModeLCL = PERIODIC3; + RefreshPeriodMemoryLCL = 2; + } + } + return true; + break; + } + } + return false; +} + +static INT_PTR CALLBACK ProfilesDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM) +{ + static HBRUSH hBrushGreen = CreateSolidBrush(RGB(0, 255, 0)); + static HBRUSH hBrushBlack = CreateSolidBrush(RGB(0, 0, 0)); + OPENFILENAME ofn = { 0 }; + TCHAR szFileName[MAX_PATH] = _T(""); + DWORD nBytesWritten = 0; + HANDLE hFile = { 0 }; + TCHAR str[255]; + TCHAR subprofile[50]; + TCHAR vers[5] = TEXT("0001"); + TCHAR readvers[5]; + int _BandwidthIdx = 0; + int _GainReduction = 0; +// HBITMAP hbitmap1, hbitmap2; + + switch (uMsg) + { + case WM_INITDIALOG: + LoadProfilesReg(hwndDlg); + //hbitmap1 = LoadBitmap(hInst, MAKEINTRESOURCE(IDB_PROF_BUTTON_DISABLED)); + //hbitmap2 = LoadBitmap(hInst, MAKEINTRESOURCE(IDB_PROF_BUTTON_ASSIGN)); + //SendMessage(GetDlgItem(hwndDlg, IDC_PROF_BUTTON_ONE), BM_SETIMAGE, 0, (LPARAM)hbitmap1); + //SendMessage(GetDlgItem(hwndDlg, IDC_PROF_BUTTON_TWO), BM_SETIMAGE, 0, (LPARAM)hbitmap1); + //SendMessage(GetDlgItem(hwndDlg, IDC_PROF_BUTTON_THREE), BM_SETIMAGE, 0, (LPARAM)hbitmap1); + //SendMessage(GetDlgItem(hwndDlg, IDC_PROF_BUTTON_FOUR), BM_SETIMAGE, 0, (LPARAM)hbitmap1); + //SendMessage(GetDlgItem(hwndDlg, IDC_PROF_BUTTON_FIVE), BM_SETIMAGE, 0, (LPARAM)hbitmap1); + //SendMessage(GetDlgItem(hwndDlg, IDC_PROF_BUTTON_SIX), BM_SETIMAGE, 0, (LPARAM)hbitmap1); + //SendMessage(GetDlgItem(hwndDlg, IDC_PROF_BUTTON_SEVEN), BM_SETIMAGE, 0, (LPARAM)hbitmap1); + //SendMessage(GetDlgItem(hwndDlg, IDC_PROF_BUTTON_EIGHT), BM_SETIMAGE, 0, (LPARAM)hbitmap1); + //SendMessage(GetDlgItem(hwndDlg, IDC_PROF_BUTTON_ASSIGN_ONE), BM_SETIMAGE, 0, (LPARAM)hbitmap2); + //SendMessage(GetDlgItem(hwndDlg, IDC_PROF_BUTTON_ASSIGN_TWO), BM_SETIMAGE, 0, (LPARAM)hbitmap2); + //SendMessage(GetDlgItem(hwndDlg, IDC_PROF_BUTTON_ASSIGN_THREE), BM_SETIMAGE, 0, (LPARAM)hbitmap2); + //SendMessage(GetDlgItem(hwndDlg, IDC_PROF_BUTTON_ASSIGN_FOUR), BM_SETIMAGE, 0, (LPARAM)hbitmap2); + //SendMessage(GetDlgItem(hwndDlg, IDC_PROF_BUTTON_ASSIGN_FIVE), BM_SETIMAGE, 0, (LPARAM)hbitmap2); + //SendMessage(GetDlgItem(hwndDlg, IDC_PROF_BUTTON_ASSIGN_SIX), BM_SETIMAGE, 0, (LPARAM)hbitmap2); + //SendMessage(GetDlgItem(hwndDlg, IDC_PROF_BUTTON_ASSIGN_SEVEN), BM_SETIMAGE, 0, (LPARAM)hbitmap2); + //SendMessage(GetDlgItem(hwndDlg, IDC_PROF_BUTTON_ASSIGN_EIGHT), BM_SETIMAGE, 0, (LPARAM)hbitmap2); + return true; + break; + + case WM_CLOSE: + ShowWindow(h_ProfilesDialog, SW_HIDE); + return true; + break; + + case WM_DESTROY: + h_ProfilesDialog = NULL; + return true; + break; + + case WM_COMMAND: + switch (GET_WM_COMMAND_ID(wParam, lParam)) + { + case IDC_PROF_EXIT: + ShowWindow(h_ProfilesDialog, SW_HIDE); + return true; + break; + + case IDC_PROF_BUTTON_ONE: + // load profile 1 + if (_tcscmp(p1fname, "") != 0) + { + LoadProfile(1); + Edit_SetText(GetDlgItem(h_ProfilesDialog, IDC_PROF_BUTTON_ONE), "[P1]"); + Edit_SetText(GetDlgItem(h_ProfilesDialog, IDC_PROF_BUTTON_TWO), "P2"); + Edit_SetText(GetDlgItem(h_ProfilesDialog, IDC_PROF_BUTTON_THREE), "P3"); + Edit_SetText(GetDlgItem(h_ProfilesDialog, IDC_PROF_BUTTON_FOUR), "P4"); + Edit_SetText(GetDlgItem(h_ProfilesDialog, IDC_PROF_BUTTON_FIVE), "P5"); + Edit_SetText(GetDlgItem(h_ProfilesDialog, IDC_PROF_BUTTON_SIX), "P6"); + Edit_SetText(GetDlgItem(h_ProfilesDialog, IDC_PROF_BUTTON_SEVEN), "P7"); + Edit_SetText(GetDlgItem(h_ProfilesDialog, IDC_PROF_BUTTON_EIGHT), "P8"); + } + return true; + break; + + case IDC_PROF_BUTTON_TWO: + // load profile 2 + if (_tcscmp(p2fname, "") != 0) + { + LoadProfile(2); + Edit_SetText(GetDlgItem(h_ProfilesDialog, IDC_PROF_BUTTON_ONE), "P1"); + Edit_SetText(GetDlgItem(h_ProfilesDialog, IDC_PROF_BUTTON_TWO), "[P2]"); + Edit_SetText(GetDlgItem(h_ProfilesDialog, IDC_PROF_BUTTON_THREE), "P3"); + Edit_SetText(GetDlgItem(h_ProfilesDialog, IDC_PROF_BUTTON_FOUR), "P4"); + Edit_SetText(GetDlgItem(h_ProfilesDialog, IDC_PROF_BUTTON_FIVE), "P5"); + Edit_SetText(GetDlgItem(h_ProfilesDialog, IDC_PROF_BUTTON_SIX), "P6"); + Edit_SetText(GetDlgItem(h_ProfilesDialog, IDC_PROF_BUTTON_SEVEN), "P7"); + Edit_SetText(GetDlgItem(h_ProfilesDialog, IDC_PROF_BUTTON_EIGHT), "P8"); + } + return true; + break; + + case IDC_PROF_BUTTON_THREE: + // load profile 3 + if (_tcscmp(p3fname, "") != 0) + { + LoadProfile(3); + Edit_SetText(GetDlgItem(h_ProfilesDialog, IDC_PROF_BUTTON_ONE), "P1"); + Edit_SetText(GetDlgItem(h_ProfilesDialog, IDC_PROF_BUTTON_TWO), "P2"); + Edit_SetText(GetDlgItem(h_ProfilesDialog, IDC_PROF_BUTTON_THREE), "[P3]"); + Edit_SetText(GetDlgItem(h_ProfilesDialog, IDC_PROF_BUTTON_FOUR), "P4"); + Edit_SetText(GetDlgItem(h_ProfilesDialog, IDC_PROF_BUTTON_FIVE), "P5"); + Edit_SetText(GetDlgItem(h_ProfilesDialog, IDC_PROF_BUTTON_SIX), "P6"); + Edit_SetText(GetDlgItem(h_ProfilesDialog, IDC_PROF_BUTTON_SEVEN), "P7"); + Edit_SetText(GetDlgItem(h_ProfilesDialog, IDC_PROF_BUTTON_EIGHT), "P8"); + } + return true; + break; + + case IDC_PROF_BUTTON_FOUR: + // load profile 4 + if (_tcscmp(p4fname, "") != 0) + { + LoadProfile(4); + Edit_SetText(GetDlgItem(h_ProfilesDialog, IDC_PROF_BUTTON_ONE), "P1"); + Edit_SetText(GetDlgItem(h_ProfilesDialog, IDC_PROF_BUTTON_TWO), "P2"); + Edit_SetText(GetDlgItem(h_ProfilesDialog, IDC_PROF_BUTTON_THREE), "P3"); + Edit_SetText(GetDlgItem(h_ProfilesDialog, IDC_PROF_BUTTON_FOUR), "[P4]"); + Edit_SetText(GetDlgItem(h_ProfilesDialog, IDC_PROF_BUTTON_FIVE), "P5"); + Edit_SetText(GetDlgItem(h_ProfilesDialog, IDC_PROF_BUTTON_SIX), "P6"); + Edit_SetText(GetDlgItem(h_ProfilesDialog, IDC_PROF_BUTTON_SEVEN), "P7"); + Edit_SetText(GetDlgItem(h_ProfilesDialog, IDC_PROF_BUTTON_EIGHT), "P8"); + } + return true; + break; + + case IDC_PROF_BUTTON_FIVE: + // load profile 5 + if (_tcscmp(p5fname, "") != 0) + { + LoadProfile(5); + Edit_SetText(GetDlgItem(h_ProfilesDialog, IDC_PROF_BUTTON_ONE), "P1"); + Edit_SetText(GetDlgItem(h_ProfilesDialog, IDC_PROF_BUTTON_TWO), "P2"); + Edit_SetText(GetDlgItem(h_ProfilesDialog, IDC_PROF_BUTTON_THREE), "P3"); + Edit_SetText(GetDlgItem(h_ProfilesDialog, IDC_PROF_BUTTON_FOUR), "P4"); + Edit_SetText(GetDlgItem(h_ProfilesDialog, IDC_PROF_BUTTON_FIVE), "[P5]"); + Edit_SetText(GetDlgItem(h_ProfilesDialog, IDC_PROF_BUTTON_SIX), "P6"); + Edit_SetText(GetDlgItem(h_ProfilesDialog, IDC_PROF_BUTTON_SEVEN), "P7"); + Edit_SetText(GetDlgItem(h_ProfilesDialog, IDC_PROF_BUTTON_EIGHT), "P8"); + } + return true; + break; + + case IDC_PROF_BUTTON_SIX: + // load profile 6 + if (_tcscmp(p6fname, "") != 0) + { + LoadProfile(6); + Edit_SetText(GetDlgItem(h_ProfilesDialog, IDC_PROF_BUTTON_ONE), "P1"); + Edit_SetText(GetDlgItem(h_ProfilesDialog, IDC_PROF_BUTTON_TWO), "P2"); + Edit_SetText(GetDlgItem(h_ProfilesDialog, IDC_PROF_BUTTON_THREE), "P3"); + Edit_SetText(GetDlgItem(h_ProfilesDialog, IDC_PROF_BUTTON_FOUR), "P4"); + Edit_SetText(GetDlgItem(h_ProfilesDialog, IDC_PROF_BUTTON_FIVE), "P5"); + Edit_SetText(GetDlgItem(h_ProfilesDialog, IDC_PROF_BUTTON_SIX), "[P6]"); + Edit_SetText(GetDlgItem(h_ProfilesDialog, IDC_PROF_BUTTON_SEVEN), "P7"); + Edit_SetText(GetDlgItem(h_ProfilesDialog, IDC_PROF_BUTTON_EIGHT), "P8"); + } + return true; + break; + + case IDC_PROF_BUTTON_SEVEN: + // load profile 7 + if (_tcscmp(p7fname, "") != 0) + { + LoadProfile(7); + Edit_SetText(GetDlgItem(h_ProfilesDialog, IDC_PROF_BUTTON_ONE), "P1"); + Edit_SetText(GetDlgItem(h_ProfilesDialog, IDC_PROF_BUTTON_TWO), "P2"); + Edit_SetText(GetDlgItem(h_ProfilesDialog, IDC_PROF_BUTTON_THREE), "P3"); + Edit_SetText(GetDlgItem(h_ProfilesDialog, IDC_PROF_BUTTON_FOUR), "P4"); + Edit_SetText(GetDlgItem(h_ProfilesDialog, IDC_PROF_BUTTON_FIVE), "P5"); + Edit_SetText(GetDlgItem(h_ProfilesDialog, IDC_PROF_BUTTON_SIX), "P6"); + Edit_SetText(GetDlgItem(h_ProfilesDialog, IDC_PROF_BUTTON_SEVEN), "[P7]"); + Edit_SetText(GetDlgItem(h_ProfilesDialog, IDC_PROF_BUTTON_EIGHT), "P8"); + } + return true; + break; + + case IDC_PROF_BUTTON_EIGHT: + // load profile 8 + if (_tcscmp(p8fname, "") != 0) + { + LoadProfile(8); + Edit_SetText(GetDlgItem(h_ProfilesDialog, IDC_PROF_BUTTON_ONE), "P1"); + Edit_SetText(GetDlgItem(h_ProfilesDialog, IDC_PROF_BUTTON_TWO), "P2"); + Edit_SetText(GetDlgItem(h_ProfilesDialog, IDC_PROF_BUTTON_THREE), "P3"); + Edit_SetText(GetDlgItem(h_ProfilesDialog, IDC_PROF_BUTTON_FOUR), "P4"); + Edit_SetText(GetDlgItem(h_ProfilesDialog, IDC_PROF_BUTTON_FIVE), "P5"); + Edit_SetText(GetDlgItem(h_ProfilesDialog, IDC_PROF_BUTTON_SIX), "P6"); + Edit_SetText(GetDlgItem(h_ProfilesDialog, IDC_PROF_BUTTON_SEVEN), "P7"); + Edit_SetText(GetDlgItem(h_ProfilesDialog, IDC_PROF_BUTTON_EIGHT), "[P8]"); + } + return true; + break; + + case IDC_LOADPROFILE_P1: + ofn.lStructSize = sizeof(OPENFILENAME); + ofn.hwndOwner = h_ProfilesDialog; + ofn.lpstrFilter = _T("RSP Profiles (*.rsp)\0*.rsp\0\0"); + ofn.lpstrFile = szFileName; + ofn.lpstrDefExt = _T("rsp"); + ofn.nMaxFile = _MAX_PATH; + ofn.lpstrTitle = _T("Load RSP Profile"); + ofn.Flags = OFN_FILEMUSTEXIST | OFN_EXPLORER; + + if (GetOpenFileName(&ofn)) + { + _tcscpy_s(p1fname, szFileName); + PathRemoveExtension(szFileName); + _tcsnccpy_s(subprofile, PathFindFileName(szFileName), 30); + _stprintf_s(str, TEXT("\nPROFILE STORED: %s"), subprofile); + Edit_SetText(GetDlgItem(h_ProfilesDialog, IDC_PROF_DESC_ONE), str); + } + break; + + case IDC_LOADPROFILE_P2: + ofn.lStructSize = sizeof(OPENFILENAME); + ofn.hwndOwner = h_ProfilesDialog; + ofn.lpstrFilter = _T("RSP Profiles (*.rsp)\0*.rsp\0\0"); + ofn.lpstrFile = szFileName; + ofn.lpstrDefExt = _T("rsp"); + ofn.nMaxFile = _MAX_PATH; + ofn.lpstrTitle = _T("Load RSP Profile"); + ofn.Flags = OFN_FILEMUSTEXIST | OFN_EXPLORER; + + if (GetOpenFileName(&ofn)) + { + _tcscpy_s(p2fname, szFileName); + PathRemoveExtension(szFileName); + _tcsnccpy_s(subprofile, PathFindFileName(szFileName), 30); + _stprintf_s(str, TEXT("\nPROFILE STORED: %s"), subprofile); + Edit_SetText(GetDlgItem(h_ProfilesDialog, IDC_PROF_DESC_TWO), str); + } + break; + + case IDC_LOADPROFILE_P3: + ofn.lStructSize = sizeof(OPENFILENAME); + ofn.hwndOwner = h_ProfilesDialog; + ofn.lpstrFilter = _T("RSP Profiles (*.rsp)\0*.rsp\0\0"); + ofn.lpstrFile = szFileName; + ofn.lpstrDefExt = _T("rsp"); + ofn.nMaxFile = _MAX_PATH; + ofn.lpstrTitle = _T("Load RSP Profile"); + ofn.Flags = OFN_FILEMUSTEXIST | OFN_EXPLORER; + + if (GetOpenFileName(&ofn)) + { + _tcscpy_s(p3fname, szFileName); + PathRemoveExtension(szFileName); + _tcsnccpy_s(subprofile, PathFindFileName(szFileName), 30); + _stprintf_s(str, TEXT("\nPROFILE STORED: %s"), subprofile); + Edit_SetText(GetDlgItem(h_ProfilesDialog, IDC_PROF_DESC_THREE), str); + } + break; + + case IDC_LOADPROFILE_P4: + ofn.lStructSize = sizeof(OPENFILENAME); + ofn.hwndOwner = h_ProfilesDialog; + ofn.lpstrFilter = _T("RSP Profiles (*.rsp)\0*.rsp\0\0"); + ofn.lpstrFile = szFileName; + ofn.lpstrDefExt = _T("rsp"); + ofn.nMaxFile = _MAX_PATH; + ofn.lpstrTitle = _T("Load RSP Profile"); + ofn.Flags = OFN_FILEMUSTEXIST | OFN_EXPLORER; + + if (GetOpenFileName(&ofn)) + { + _tcscpy_s(p4fname, szFileName); + PathRemoveExtension(szFileName); + _tcsnccpy_s(subprofile, PathFindFileName(szFileName), 30); + _stprintf_s(str, TEXT("\nPROFILE STORED: %s"), subprofile); + Edit_SetText(GetDlgItem(h_ProfilesDialog, IDC_PROF_DESC_FOUR), str); + } + break; + + case IDC_LOADPROFILE_P5: + ofn.lStructSize = sizeof(OPENFILENAME); + ofn.hwndOwner = h_ProfilesDialog; + ofn.lpstrFilter = _T("RSP Profiles (*.rsp)\0*.rsp\0\0"); + ofn.lpstrFile = szFileName; + ofn.lpstrDefExt = _T("rsp"); + ofn.nMaxFile = _MAX_PATH; + ofn.lpstrTitle = _T("Load RSP Profile"); + ofn.Flags = OFN_FILEMUSTEXIST | OFN_EXPLORER; + + if (GetOpenFileName(&ofn)) + { + _tcscpy_s(p5fname, szFileName); + PathRemoveExtension(szFileName); + _tcsnccpy_s(subprofile, PathFindFileName(szFileName), 30); + _stprintf_s(str, TEXT("\nPROFILE STORED: %s"), subprofile); + Edit_SetText(GetDlgItem(h_ProfilesDialog, IDC_PROF_DESC_FIVE), str); + } + break; + + case IDC_LOADPROFILE_P6: + ofn.lStructSize = sizeof(OPENFILENAME); + ofn.hwndOwner = h_ProfilesDialog; + ofn.lpstrFilter = _T("RSP Profiles (*.rsp)\0*.rsp\0\0"); + ofn.lpstrFile = szFileName; + ofn.lpstrDefExt = _T("rsp"); + ofn.nMaxFile = _MAX_PATH; + ofn.lpstrTitle = _T("Load RSP Profile"); + ofn.Flags = OFN_FILEMUSTEXIST | OFN_EXPLORER; + + if (GetOpenFileName(&ofn)) + { + _tcscpy_s(p6fname, szFileName); + PathRemoveExtension(szFileName); + _tcsnccpy_s(subprofile, PathFindFileName(szFileName), 30); + _stprintf_s(str, TEXT("\nPROFILE STORED: %s"), subprofile); + Edit_SetText(GetDlgItem(h_ProfilesDialog, IDC_PROF_DESC_SIX), str); + } + break; + + case IDC_LOADPROFILE_P7: + ofn.lStructSize = sizeof(OPENFILENAME); + ofn.hwndOwner = h_ProfilesDialog; + ofn.lpstrFilter = _T("RSP Profiles (*.rsp)\0*.rsp\0\0"); + ofn.lpstrFile = szFileName; + ofn.lpstrDefExt = _T("rsp"); + ofn.nMaxFile = _MAX_PATH; + ofn.lpstrTitle = _T("Load RSP Profile"); + ofn.Flags = OFN_FILEMUSTEXIST | OFN_EXPLORER; + + if (GetOpenFileName(&ofn)) + { + _tcscpy_s(p7fname, szFileName); + PathRemoveExtension(szFileName); + _tcsnccpy_s(subprofile, PathFindFileName(szFileName), 30); + _stprintf_s(str, TEXT("\nPROFILE STORED: %s"), subprofile); + Edit_SetText(GetDlgItem(h_ProfilesDialog, IDC_PROF_DESC_SEVEN), str); + } + break; + + case IDC_LOADPROFILE_P8: + ofn.lStructSize = sizeof(OPENFILENAME); + ofn.hwndOwner = h_ProfilesDialog; + ofn.lpstrFilter = _T("RSP Profiles (*.rsp)\0*.rsp\0\0"); + ofn.lpstrFile = szFileName; + ofn.lpstrDefExt = _T("rsp"); + ofn.nMaxFile = _MAX_PATH; + ofn.lpstrTitle = _T("Load RSP Profile"); + ofn.Flags = OFN_FILEMUSTEXIST | OFN_EXPLORER; + + if (GetOpenFileName(&ofn)) + { + _tcscpy_s(p8fname, szFileName); + PathRemoveExtension(szFileName); + _tcsnccpy_s(subprofile, PathFindFileName(szFileName), 30); + _stprintf_s(str, TEXT("\nPROFILE STORED: %s"), subprofile); + Edit_SetText(GetDlgItem(h_ProfilesDialog, IDC_PROF_DESC_EIGHT), str); + } + break; + + case IDC_LoadProfile: + if (GET_WM_COMMAND_CMD(wParam, lParam) == BN_CLICKED) + { + ofn.lStructSize = sizeof(OPENFILENAME); + ofn.hwndOwner = h_ProfilesDialog; + ofn.lpstrFilter = _T("RSP Profiles (*.rsp)\0*.rsp\0\0"); + ofn.lpstrFile = szFileName; + ofn.lpstrDefExt = _T("rsp"); + ofn.nMaxFile = _MAX_PATH; + ofn.lpstrTitle = _T("Load RSP Profile"); + ofn.Flags = OFN_FILEMUSTEXIST | OFN_EXPLORER; + + if (GetOpenFileName(&ofn)) + { + hFile = CreateFile(szFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + + // Read file format version number + ReadFile(hFile, &readvers, sizeof(readvers), &nBytesWritten, NULL); + + if (strcmp(readvers, vers) != 0) { + CloseHandle(hFile); + _stprintf_s(str, TEXT("File format not supported: %s"), readvers); + MessageBox(NULL, str, "RSP Profile format error", MB_OK | MB_TOPMOST | MB_ICONERROR); + } + else + { + // IF Mode + ReadFile(hFile, &IFMode, sizeof(IFMode), &nBytesWritten, NULL); + ReadFile(hFile, &IFmodeIdx, sizeof(IFmodeIdx), &nBytesWritten, NULL); + + // IF Bandwidth + ReadFile(hFile, &Bandwidth, sizeof(Bandwidth), &nBytesWritten, NULL); + ReadFile(hFile, &_BandwidthIdx, sizeof(_BandwidthIdx), &nBytesWritten, NULL); + + BandwidthIdx = _BandwidthIdx; + ComboBox_SetCurSel(GetDlgItem(h_dialog, IDC_IFMODE), IFmodeIdx); + ComboBox_ResetContent(GetDlgItem(h_dialog, IDC_IFBW)); + _stprintf_s(str, 255, "200 kHz"); + ComboBox_AddString(GetDlgItem(h_dialog, IDC_IFBW), str); + _stprintf_s(str, 255, "300 kHz"); + ComboBox_AddString(GetDlgItem(h_dialog, IDC_IFBW), str); + _stprintf_s(str, 255, "600 kHz"); + ComboBox_AddString(GetDlgItem(h_dialog, IDC_IFBW), str); + _stprintf_s(str, 255, "1.536 MHz"); + ComboBox_AddString(GetDlgItem(h_dialog, IDC_IFBW), str); + if (IFmodeIdx == 0) + { + _stprintf_s(str, 255, "5.000 MHz"); + ComboBox_AddString(GetDlgItem(h_dialog, IDC_IFBW), str); + _stprintf_s(str, 255, "6.000 MHz"); + ComboBox_AddString(GetDlgItem(h_dialog, IDC_IFBW), str); + _stprintf_s(str, 255, "7.000 MHz"); + ComboBox_AddString(GetDlgItem(h_dialog, IDC_IFBW), str); + _stprintf_s(str, 255, "8.000 MHz"); + ComboBox_AddString(GetDlgItem(h_dialog, IDC_IFBW), str); + } + ComboBox_SetCurSel(GetDlgItem(h_dialog, IDC_IFBW), BandwidthIdx); + + // Sample Rate + ReadFile(hFile, &SampleRateIdx, sizeof(SampleRateIdx), &nBytesWritten, NULL); + ComboBox_SetCurSel(GetDlgItem(h_dialog, IDC_SAMPLERATE), SampleRateIdx); + + // Gain Reduction + ReadFile(hFile, &_GainReduction, sizeof(_GainReduction), &nBytesWritten, NULL); + GainReduction = _GainReduction; + sprintf_s(GainReductionTxt, 254, "%d", GainReduction); + Edit_SetText(GetDlgItem(h_dialog, IDC_GR), GainReductionTxt); + SendMessage(GetDlgItem(h_dialog, IDC_GAINSLIDER), TBM_SETPOS, (WPARAM)true, (LPARAM)GainReduction); + + // AGC Setpoint + ReadFile(hFile, &AGCsetpoint, sizeof(AGCsetpoint), &nBytesWritten, NULL); + sprintf_s(AGCsetpointTxt, 254, "%d", AGCsetpoint); + Edit_SetText(GetDlgItem(h_dialog, IDC_SETPOINT), AGCsetpointTxt); + + // Frequency Offset + ReadFile(hFile, &FqOffsetPPM, sizeof(FqOffsetPPM), &nBytesWritten, NULL); + sprintf_s(FreqoffsetTxt, 254, "%.2f", FqOffsetPPM); + Edit_SetText(GetDlgItem(h_dialog, IDC_PPM), FreqoffsetTxt); + + // AGC Enable + ReadFile(hFile, &AGCEnabled, sizeof(AGCEnabled), &nBytesWritten, NULL); + if (AGCEnabled) + { + SendMessage(GetDlgItem(h_dialog, IDC_RSPAGC), BM_SETCHECK, (WPARAM)(1), 0); + Edit_Enable(GetDlgItem(h_dialog, IDC_GR), 0); + Edit_Enable(GetDlgItem(h_dialog, IDC_GAINSLIDER), 0); +// m_timer = SetTimer(h_dialog, ID_AGCUPDATE, 600, NULL); + } + else + { + SendMessage(GetDlgItem(h_dialog, IDC_RSPAGC), BM_SETCHECK, (WPARAM)(0), 0); + Edit_Enable(GetDlgItem(h_dialog, IDC_GR), 1); + Edit_Enable(GetDlgItem(h_dialog, IDC_GAINSLIDER), 1); +// KillTimer(h_dialog, ID_AGCUPDATE); + } + + // LO Plan + ReadFile(hFile, &LOplan, sizeof(LOplan), &nBytesWritten, NULL); + ReadFile(hFile, &LOplanAuto, sizeof(LOplanAuto), &nBytesWritten, NULL); + if (LOplanAuto) + { + SendMessage(GetDlgItem(h_dialog, IDC_LOAUTO), BM_SETCHECK, BST_CHECKED, 0); + Edit_SetText(GetDlgItem(h_dialog, IDC_LOWARNING), "Full Coverage"); + Edit_SetText(GetDlgItem(h_dialog, IDC_LOWARNING1), " "); + } + else + { + if (LOplan == LO120MHz) + { + SendMessage(GetDlgItem(h_dialog, IDC_LO120), BM_SETCHECK, BST_CHECKED, 0); + Edit_SetText(GetDlgItem(h_dialog, IDC_LOWARNING), "Coverage gap between 370MHz and 420MHz"); + Edit_SetText(GetDlgItem(h_dialog, IDC_LOWARNING1), " "); + } + if (LOplan == LO144MHz) + { + SendMessage(GetDlgItem(h_dialog, IDC_LO144), BM_SETCHECK, BST_CHECKED, 0); + Edit_SetText(GetDlgItem(h_dialog, IDC_LOWARNING), "Coverage gaps between 250MHz to 255MHz"); + Edit_SetText(GetDlgItem(h_dialog, IDC_LOWARNING1), "Coverage gaps between 400MHz to 420MHz"); + } + if (LOplan == LO168MHz) + { + SendMessage(GetDlgItem(h_dialog, IDC_LO168), BM_SETCHECK, BST_CHECKED, 0); + Edit_SetText(GetDlgItem(h_dialog, IDC_LOWARNING), "Coverage gap between 250MHz and 265MHz"); + Edit_SetText(GetDlgItem(h_dialog, IDC_LOWARNING1), " "); + } + } + + WinradCallBack(-1, WINRAD_SRCHANGE, 0, NULL); + + if (Running) + { + ReinitAll(); + UpdateSR(); + } + + // DC compensation mode + ReadFile(hFile, &DcCompensationMode, sizeof(DcCompensationMode), &nBytesWritten, NULL); + + // Tracking period + ReadFile(hFile, &TrackingPeriod, sizeof(TrackingPeriod), &nBytesWritten, NULL); + + // Refresh Period + ReadFile(hFile, &RefreshPeriodMemory, sizeof(RefreshPeriodMemory), &nBytesWritten, NULL); + + // Post Tuner DC compensation + ReadFile(hFile, &PostTunerDcCompensation, sizeof(PostTunerDcCompensation), &nBytesWritten, NULL); + + CloseHandle(hFile); + + PathRemoveExtension(szFileName); + _tcsnccpy_s(subprofile, PathFindFileName(szFileName), 30); + _stprintf_s(str, TEXT("Current Profile: %s"), subprofile); + Edit_SetText(GetDlgItem(h_dialog, IDC_ProfileFileName), str); + } + } + } + return true; + + case IDC_SaveProfile: + if (GET_WM_COMMAND_CMD(wParam, lParam) == BN_CLICKED) + { + TCHAR writevers[5] = TEXT("0001"); + int _BandwidthIdx = BandwidthIdx; + int _GainReduction = GainReduction; + int _LNAGainReduction = LNAGainReduction; + ofn.lStructSize = sizeof(OPENFILENAME); + ofn.hwndOwner = h_ProfilesDialog; + ofn.lpstrFilter = _T("RSP Profiles (*.rsp)\0*.rsp\0\0"); + ofn.lpstrFile = szFileName; + ofn.lpstrDefExt = _T("rsp"); + ofn.nMaxFile = _MAX_PATH; + ofn.lpstrTitle = _T("Save RSP Profile"); + ofn.Flags = OFN_OVERWRITEPROMPT | OFN_HIDEREADONLY | OFN_EXPLORER; + + if (GetSaveFileName(&ofn)) + { + hFile = CreateFile(szFileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + + WriteFile(hFile, &writevers, sizeof(writevers), &nBytesWritten, NULL); // Version + WriteFile(hFile, &IFMode, sizeof(IFMode), &nBytesWritten, NULL); // IF Mode + WriteFile(hFile, &IFmodeIdx, sizeof(IFmodeIdx), &nBytesWritten, NULL); + WriteFile(hFile, &Bandwidth, sizeof(Bandwidth), &nBytesWritten, NULL); // IF Bandwidth + WriteFile(hFile, &_BandwidthIdx, sizeof(_BandwidthIdx), &nBytesWritten, NULL); + WriteFile(hFile, &SampleRateIdx, sizeof(SampleRateIdx), &nBytesWritten, NULL); // Sample Rate + WriteFile(hFile, &_GainReduction, sizeof(_GainReduction), &nBytesWritten, NULL); // Gain Reduction + WriteFile(hFile, &AGCsetpoint, sizeof(AGCsetpoint), &nBytesWritten, NULL); // AGC Setpoint + WriteFile(hFile, &FqOffsetPPM, sizeof(FqOffsetPPM), &nBytesWritten, NULL); // Frequency Offset + WriteFile(hFile, &AGCEnabled, sizeof(AGCEnabled), &nBytesWritten, NULL); // AGC Enable + WriteFile(hFile, &LOplan, sizeof(LOplan), &nBytesWritten, NULL); // LO plan + WriteFile(hFile, &LOplanAuto, sizeof(LOplanAuto), &nBytesWritten, NULL); // LO plan Auto + WriteFile(hFile, &DcCompensationMode, sizeof(DcCompensationMode), &nBytesWritten, NULL); // DC compensation mode + WriteFile(hFile, &TrackingPeriod, sizeof(TrackingPeriod), &nBytesWritten, NULL); // Tracking period + WriteFile(hFile, &RefreshPeriodMemory, sizeof(RefreshPeriodMemory), &nBytesWritten, NULL); // Refresh Period + WriteFile(hFile, &PostTunerDcCompensation, sizeof(PostTunerDcCompensation), &nBytesWritten, NULL); // Post Tuner DC compensation + WriteFile(hFile, &_LNAGainReduction, sizeof(_LNAGainReduction), &nBytesWritten, NULL); // LNA gain reduction value + WriteFile(hFile, &AntennaIdx, sizeof(AntennaIdx), &nBytesWritten, NULL); // Port + WriteFile(hFile, ¬chEnable, sizeof(notchEnable), &nBytesWritten, NULL); // Broadcast Notch filter enable + WriteFile(hFile, &dabNotchEnable, sizeof(dabNotchEnable), &nBytesWritten, NULL); // DAB Notch filter enable + WriteFile(hFile, &biasTEnable, sizeof(biasTEnable), &nBytesWritten, NULL); // Bias T enable + + CloseHandle(hFile); + + PathRemoveExtension(szFileName); + _tcsnccpy_s(subprofile, PathFindFileName(szFileName), 30); + _stprintf_s(str, TEXT("Current Profile: %s"), subprofile); + Edit_SetText(GetDlgItem(h_dialog, IDC_ProfileFileName), str); + } + } + return true; + } + } + return false; +} + +void LoadProfile(int profile) +{ + OPENFILENAME ofn = { 0 }; + DWORD nBytesWritten = 0; + HANDLE hFile = { 0 }; + TCHAR str[255]; + TCHAR subprofile[50]; + TCHAR copiedfn[MAX_PATH]; + TCHAR filename[MAX_PATH]; + + if (profile == 1) + { + _tcscpy_s(filename, p1fname); + } + else if (profile == 2) + { + _tcscpy_s(filename, p2fname); + } + else if (profile == 3) + { + _tcscpy_s(filename, p3fname); + } + else if (profile == 4) + { + _tcscpy_s(filename, p4fname); + } + else if (profile == 5) + { + _tcscpy_s(filename, p5fname); + } + else if (profile == 6) + { + _tcscpy_s(filename, p6fname); + } + else if (profile == 7) + { + _tcscpy_s(filename, p7fname); + } + else + { + _tcscpy_s(filename, p8fname); + } + + TCHAR vers[5] = TEXT("0001"); + TCHAR readvers[5]; + int _BandwidthIdx = 0; + int _GainReduction = 0; + int _LNAGainReduction = 0; + ofn.lStructSize = sizeof(OPENFILENAME); + ofn.hwndOwner = h_ProfilesDialog; + ofn.lpstrFilter = _T("RSP Profiles (*.rsp)\0*.rsp\0\0"); + ofn.lpstrFile = filename; + ofn.lpstrDefExt = _T("rsp"); + ofn.nMaxFile = _MAX_PATH; + ofn.lpstrTitle = _T("Load RSP Profile"); + ofn.Flags = OFN_FILEMUSTEXIST | OFN_EXPLORER; + + hFile = CreateFile(filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + + // Read file format version number + ReadFile(hFile, &readvers, sizeof(readvers), &nBytesWritten, NULL); + + if (strcmp(readvers, vers) != 0) + { + CloseHandle(hFile); + _stprintf_s(str, TEXT("File not found or format not supported: %s"), readvers); + MessageBox(NULL, str, "RSP Profile file error", MB_OK | MB_TOPMOST | MB_ICONERROR); + } + else + { + // IF Mode + ReadFile(hFile, &IFMode, sizeof(IFMode), &nBytesWritten, NULL); + ReadFile(hFile, &IFmodeIdx, sizeof(IFmodeIdx), &nBytesWritten, NULL); + + // IF Bandwidth + ReadFile(hFile, &Bandwidth, sizeof(Bandwidth), &nBytesWritten, NULL); + ReadFile(hFile, &_BandwidthIdx, sizeof(_BandwidthIdx), &nBytesWritten, NULL); + + BandwidthIdx = _BandwidthIdx; + ComboBox_SetCurSel(GetDlgItem(h_dialog, IDC_IFMODE), IFmodeIdx); + ComboBox_ResetContent(GetDlgItem(h_dialog, IDC_IFBW)); + _stprintf_s(str, 255, "200 kHz"); + ComboBox_AddString(GetDlgItem(h_dialog, IDC_IFBW), str); + _stprintf_s(str, 255, "300 kHz"); + ComboBox_AddString(GetDlgItem(h_dialog, IDC_IFBW), str); + _stprintf_s(str, 255, "600 kHz"); + ComboBox_AddString(GetDlgItem(h_dialog, IDC_IFBW), str); + _stprintf_s(str, 255, "1.536 MHz"); + ComboBox_AddString(GetDlgItem(h_dialog, IDC_IFBW), str); + if (IFmodeIdx == 0) + { + _stprintf_s(str, 255, "5.000 MHz"); + ComboBox_AddString(GetDlgItem(h_dialog, IDC_IFBW), str); + _stprintf_s(str, 255, "6.000 MHz"); + ComboBox_AddString(GetDlgItem(h_dialog, IDC_IFBW), str); + _stprintf_s(str, 255, "7.000 MHz"); + ComboBox_AddString(GetDlgItem(h_dialog, IDC_IFBW), str); + _stprintf_s(str, 255, "8.000 MHz"); + ComboBox_AddString(GetDlgItem(h_dialog, IDC_IFBW), str); + } + ComboBox_SetCurSel(GetDlgItem(h_dialog, IDC_IFBW), BandwidthIdx); + + // Sample Rate + ReadFile(hFile, &SampleRateIdx, sizeof(SampleRateIdx), &nBytesWritten, NULL); + ComboBox_SetCurSel(GetDlgItem(h_dialog, IDC_SAMPLERATE), SampleRateIdx); + + // Gain Reduction + ReadFile(hFile, &_GainReduction, sizeof(_GainReduction), &nBytesWritten, NULL); + GainReduction = _GainReduction; + sprintf_s(GainReductionTxt, 254, "%d", GainReduction); + Edit_SetText(GetDlgItem(h_dialog, IDC_GR), GainReductionTxt); + SendMessage(GetDlgItem(h_dialog, IDC_GAINSLIDER), TBM_SETPOS, (WPARAM)true, (LPARAM)GainReduction); + + // AGC Setpoint + ReadFile(hFile, &AGCsetpoint, sizeof(AGCsetpoint), &nBytesWritten, NULL); + sprintf_s(AGCsetpointTxt, 254, "%d", AGCsetpoint); + Edit_SetText(GetDlgItem(h_dialog, IDC_SETPOINT), AGCsetpointTxt); + + // Frequency Offset + ReadFile(hFile, &FqOffsetPPM, sizeof(FqOffsetPPM), &nBytesWritten, NULL); + sprintf_s(FreqoffsetTxt, 254, "%.2f", FqOffsetPPM); + Edit_SetText(GetDlgItem(h_dialog, IDC_PPM), FreqoffsetTxt); + + // AGC Enable + ReadFile(hFile, &AGCEnabled, sizeof(AGCEnabled), &nBytesWritten, NULL); + if (AGCEnabled) + { + SendMessage(GetDlgItem(h_dialog, IDC_RSPAGC), BM_SETCHECK, (WPARAM)(1), 0); + Edit_Enable(GetDlgItem(h_dialog, IDC_GR), 0); + Edit_Enable(GetDlgItem(h_dialog, IDC_GAINSLIDER), 0); +// m_timer = SetTimer(h_dialog, ID_AGCUPDATE, 600, NULL); + } + else + { + SendMessage(GetDlgItem(h_dialog, IDC_RSPAGC), BM_SETCHECK, (WPARAM)(0), 0); + Edit_Enable(GetDlgItem(h_dialog, IDC_GR), 1); + Edit_Enable(GetDlgItem(h_dialog, IDC_GAINSLIDER), 1); +// KillTimer(h_dialog, ID_AGCUPDATE); + } + + // LO Plan + ReadFile(hFile, &LOplan, sizeof(LOplan), &nBytesWritten, NULL); + ReadFile(hFile, &LOplanAuto, sizeof(LOplanAuto), &nBytesWritten, NULL); + if (LOplanAuto) + { + SendMessage(GetDlgItem(h_AdvancedDialog, IDC_LOAUTO), BM_SETCHECK, BST_CHECKED, 0); + Edit_SetText(GetDlgItem(h_AdvancedDialog, IDC_LOWARNING), "Full Coverage"); + Edit_SetText(GetDlgItem(h_AdvancedDialog, IDC_LOWARNING1), " "); + } + else + { + if (LOplan == LO120MHz) + { + SendMessage(GetDlgItem(h_AdvancedDialog, IDC_LO120), BM_SETCHECK, BST_CHECKED, 0); + Edit_SetText(GetDlgItem(h_AdvancedDialog, IDC_LOWARNING), "Coverage gap between 370MHz and 420MHz"); + Edit_SetText(GetDlgItem(h_AdvancedDialog, IDC_LOWARNING1), " "); + } + if (LOplan == LO144MHz) + { + SendMessage(GetDlgItem(h_AdvancedDialog, IDC_LO144), BM_SETCHECK, BST_CHECKED, 0); + Edit_SetText(GetDlgItem(h_AdvancedDialog, IDC_LOWARNING), "Coverage gaps between 250MHz to 255MHz"); + Edit_SetText(GetDlgItem(h_AdvancedDialog, IDC_LOWARNING1), "Coverage gaps between 400MHz to 420MHz"); + } + if (LOplan == LO168MHz) + { + SendMessage(GetDlgItem(h_AdvancedDialog, IDC_LO168), BM_SETCHECK, BST_CHECKED, 0); + Edit_SetText(GetDlgItem(h_AdvancedDialog, IDC_LOWARNING), "Coverage gap between 250MHz and 265MHz"); + Edit_SetText(GetDlgItem(h_AdvancedDialog, IDC_LOWARNING1), " "); + } + } + + // DC compensation mode + ReadFile(hFile, &DcCompensationMode, sizeof(DcCompensationMode), &nBytesWritten, NULL); + + // Tracking period + ReadFile(hFile, &TrackingPeriod, sizeof(TrackingPeriod), &nBytesWritten, NULL); + + // Refresh Period + ReadFile(hFile, &RefreshPeriodMemory, sizeof(RefreshPeriodMemory), &nBytesWritten, NULL); + + // Post Tuner DC compensation + ReadFile(hFile, &PostTunerDcCompensation, sizeof(PostTunerDcCompensation), &nBytesWritten, NULL); + + // LNA Enable + ReadFile(hFile, &_LNAGainReduction, sizeof(_LNAGainReduction), &nBytesWritten, NULL); + sprintf_s(str, sizeof(str), "Total System Gain Reduction %d dB", SystemGainReduction); + Edit_SetText(GetDlgItem(h_dialog, IDC_TOTALGR), str); + + // Port + ReadFile(hFile, &AntennaIdx, sizeof(AntennaIdx), &nBytesWritten, NULL); + ComboBox_SetCurSel(GetDlgItem(h_dialog, IDC_ANTSELECT), AntennaIdx); + if (AntennaIdx == 0) + deviceParams->devParams->rspDxParams.antennaSel = sdrplay_api_RspDx_ANTENNA_A; + else if (AntennaIdx == 1) + deviceParams->devParams->rspDxParams.antennaSel = sdrplay_api_RspDx_ANTENNA_B; + else if (AntennaIdx == 2) + deviceParams->devParams->rspDxParams.antennaSel = sdrplay_api_RspDx_ANTENNA_C; + + // Broadcast Notch Enable + ReadFile(hFile, ¬chEnable, sizeof(notchEnable), &nBytesWritten, NULL); + SendMessage(GetDlgItem(h_dialog, IDC_NOTCHENABLE), BM_SETCHECK, (WPARAM)(notchEnable ? BST_CHECKED : BST_UNCHECKED), (LPARAM)0); + + // DAB Notch Enable + ReadFile(hFile, &dabNotchEnable, sizeof(dabNotchEnable), &nBytesWritten, NULL); + SendMessage(GetDlgItem(h_dialog, IDC_DABNOTCHENABLE), BM_SETCHECK, (WPARAM)(dabNotchEnable ? BST_CHECKED : BST_UNCHECKED), (LPARAM)0); + + // Bias T Enable + ReadFile(hFile, &biasTEnable, sizeof(biasTEnable), &nBytesWritten, NULL); + SendMessage(GetDlgItem(h_dialog, IDC_BIASTENABLE), BM_SETCHECK, (WPARAM)(biasTEnable ? BST_CHECKED : BST_UNCHECKED), (LPARAM)0); + + CloseHandle(hFile); + + WinradCallBack(-1, WINRAD_SRCHANGE, 0, NULL); + + if (Running) + { + ReinitAll(); + UpdateSR(); + } + + _tcscpy_s(copiedfn, filename); + PathRemoveExtension(copiedfn); + _tcsnccpy_s(subprofile, PathFindFileName(copiedfn), 30); + _stprintf_s(str, TEXT("Current Profile: (P%d) %s"), profile, subprofile); + Edit_SetText(GetDlgItem(h_dialog, IDC_ProfileFileName), str); + } +} + +void LoadProfilesReg(HWND localDlg) +{ + HKEY Settingskey; + int error; + TCHAR tmpfn[MAX_PATH]; + TCHAR subprofile[40]; + TCHAR str[255]; + DWORD strSize = MAX_PATH; + DWORD type = REG_SZ; + + if (!loadedProfiles) + { + + error = RegOpenKeyEx(HKEY_CURRENT_USER, TEXT("Software\\SDRplay\\RSPdxR2_Settings"), 0, KEY_ALL_ACCESS, &Settingskey); + if (error == ERROR_SUCCESS) + { + error = RegQueryValueEx(Settingskey, "P1", NULL, &type, (LPBYTE)&p1fname, &strSize); + if (error == ERROR_SUCCESS) + { + ifstream ifile(p1fname); + if (ifile) + { + _tcscpy_s(tmpfn, p1fname); + PathRemoveExtension(tmpfn); + _tcsnccpy_s(subprofile, PathFindFileName(tmpfn), 30); + _stprintf_s(str, TEXT("\nPROFILE ASSIGNED: %s"), subprofile); + Edit_SetText(GetDlgItem(localDlg, IDC_PROF_DESC_ONE), str); + } + } + + error = RegQueryValueEx(Settingskey, "P2", NULL, &type, (LPBYTE)&p2fname, &strSize); + if (error == ERROR_SUCCESS) + { + ifstream ifile(p2fname); + if (ifile) + { + _tcscpy_s(tmpfn, p2fname); + PathRemoveExtension(tmpfn); + _tcsnccpy_s(subprofile, PathFindFileName(tmpfn), 30); + _stprintf_s(str, TEXT("\nPROFILE ASSIGNED: %s"), subprofile); + Edit_SetText(GetDlgItem(localDlg, IDC_PROF_DESC_TWO), str); + } + } + + error = RegQueryValueEx(Settingskey, "P3", NULL, &type, (LPBYTE)&p3fname, &strSize); + if (error == ERROR_SUCCESS) + { + ifstream ifile(p3fname); + if (ifile) + { + _tcscpy_s(tmpfn, p3fname); + PathRemoveExtension(tmpfn); + _tcsnccpy_s(subprofile, PathFindFileName(tmpfn), 30); + _stprintf_s(str, TEXT("\nPROFILE ASSIGNED: %s"), subprofile); + Edit_SetText(GetDlgItem(localDlg, IDC_PROF_DESC_THREE), str); + } + } + + error = RegQueryValueEx(Settingskey, "P4", NULL, &type, (LPBYTE)&p4fname, &strSize); + if (error == ERROR_SUCCESS) + { + ifstream ifile(p4fname); + if (ifile) + { + _tcscpy_s(tmpfn, p4fname); + PathRemoveExtension(tmpfn); + _tcsnccpy_s(subprofile, PathFindFileName(tmpfn), 30); + _stprintf_s(str, TEXT("\nPROFILE ASSIGNED: %s"), subprofile); + Edit_SetText(GetDlgItem(localDlg, IDC_PROF_DESC_FOUR), str); + } + } + + error = RegQueryValueEx(Settingskey, "P5", NULL, &type, (LPBYTE)&p5fname, &strSize); + if (error == ERROR_SUCCESS) + { + ifstream ifile(p5fname); + if (ifile) + { + _tcscpy_s(tmpfn, p5fname); + PathRemoveExtension(tmpfn); + _tcsnccpy_s(subprofile, PathFindFileName(tmpfn), 30); + _stprintf_s(str, TEXT("\nPROFILE ASSIGNED: %s"), subprofile); + Edit_SetText(GetDlgItem(localDlg, IDC_PROF_DESC_FIVE), str); + } + } + + error = RegQueryValueEx(Settingskey, "P6", NULL, &type, (LPBYTE)&p6fname, &strSize); + if (error == ERROR_SUCCESS) + { + ifstream ifile(p6fname); + if (ifile) + { + _tcscpy_s(tmpfn, p1fname); + PathRemoveExtension(tmpfn); + _tcsnccpy_s(subprofile, PathFindFileName(tmpfn), 30); + _stprintf_s(str, TEXT("\nPROFILE ASSIGNED: %s"), subprofile); + Edit_SetText(GetDlgItem(localDlg, IDC_PROF_DESC_SIX), str); + } + } + + error = RegQueryValueEx(Settingskey, "P7", NULL, &type, (LPBYTE)&p7fname, &strSize); + if (error == ERROR_SUCCESS) + { + ifstream ifile(p7fname); + if (ifile) + { + _tcscpy_s(tmpfn, p7fname); + PathRemoveExtension(tmpfn); + _tcsnccpy_s(subprofile, PathFindFileName(tmpfn), 30); + _stprintf_s(str, TEXT("\nPROFILE ASSIGNED: %s"), subprofile); + Edit_SetText(GetDlgItem(localDlg, IDC_PROF_DESC_SEVEN), str); + } + } + + error = RegQueryValueEx(Settingskey, "P8", NULL, &type, (LPBYTE)&p8fname, &strSize); + if (error == ERROR_SUCCESS) + { + ifstream ifile(p8fname); + if (ifile) + { + _tcscpy_s(tmpfn, p8fname); + PathRemoveExtension(tmpfn); + _tcsnccpy_s(subprofile, PathFindFileName(tmpfn), 30); + _stprintf_s(str, TEXT("\nPROFILE ASSIGNED: %s"), subprofile); + Edit_SetText(GetDlgItem(localDlg, IDC_PROF_DESC_EIGHT), str); + } + } + } + RegCloseKey(Settingskey); + } + loadedProfiles = true; +} + +static INT_PTR CALLBACK HelpDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM) +{ + TCHAR str[255]; + TCHAR tregPath[255]; + size_t out; + switch (uMsg) + { + case WM_INITDIALOG: + _stprintf_s(str, TEXT("API Version: %s"), apiVersion); + Edit_SetText(GetDlgItem(hwndDlg, IDC_APIVER), str); + _stprintf_s(str, TEXT("API Path:\n%s"), apiPath); + Edit_SetText(GetDlgItem(hwndDlg, IDC_APIPATH), str); + wcstombs_s(&out, tregPath, sizeof(tregPath), regPath, 255); + _stprintf_s(str, TEXT("Registry Path:\n%s"), tregPath); + Edit_SetText(GetDlgItem(hwndDlg, IDC_REGPATH), str); + return true; + break; + + case WM_CLOSE: + ShowWindow(h_HelpDialog, SW_HIDE); + return true; + break; + + case WM_DESTROY: + h_HelpDialog = NULL; + return true; + break; + + case WM_COMMAND: + switch (GET_WM_COMMAND_ID(wParam, lParam)) + { + case IDC_HELP_PANEL_EXIT: + ShowWindow(h_HelpDialog, SW_HIDE); + return true; + break; + + case IDC_HELP_LINK: + ShellExecute(0, 0, "http://www.sdrplay.com/docs/sdrplay_extio_user_guide.pdf", 0, 0, SW_SHOW); + return true; + break; + } + } + return false; +} + +static INT_PTR CALLBACK StationDlgProc(HWND, UINT uMsg, WPARAM, LPARAM) +{ + switch (uMsg) + { + case WM_INITDIALOG: + return true; + break; + + case WM_CLOSE: + ShowWindow(h_StationDialog, SW_HIDE); + return true; + break; + + case WM_DESTROY: + h_StationDialog = NULL; + return true; + break; + + } + return false; +} + +void UpdateProfile(void) +{ + if (profileChanged) + { + Edit_SetText(GetDlgItem(h_dialog, IDC_PROFILE_CHANGED), "(M)"); + } + else + { + Edit_SetText(GetDlgItem(h_dialog, IDC_PROFILE_CHANGED), ""); + } + return; +} + +BOOL EqualsMajorVersion(DWORD majorVersion) +{ + OSVERSIONINFOEX osVersionInfo; + ::ZeroMemory(&osVersionInfo, sizeof(OSVERSIONINFOEX)); + osVersionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); + osVersionInfo.dwMajorVersion = majorVersion; + ULONGLONG maskCondition = ::VerSetConditionMask(0, VER_MAJORVERSION, VER_EQUAL); + return ::VerifyVersionInfo(&osVersionInfo, VER_MAJORVERSION, maskCondition); +} +BOOL EqualsMinorVersion(DWORD minorVersion) +{ + OSVERSIONINFOEX osVersionInfo; + ::ZeroMemory(&osVersionInfo, sizeof(OSVERSIONINFOEX)); + osVersionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); + osVersionInfo.dwMinorVersion = minorVersion; + ULONGLONG maskCondition = ::VerSetConditionMask(0, VER_MINORVERSION, VER_EQUAL); + return ::VerifyVersionInfo(&osVersionInfo, VER_MINORVERSION, maskCondition); +} + +static INT_PTR CALLBACK StationConfigDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + int i; +#ifdef DEBUG_STATION + int arch = 0; + SYSTEM_INFO Info; + ZeroMemory(&Info, sizeof(SYSTEM_INFO)); + PGNSI pGetNativeSystemInfo = (PGNSI)GetProcAddress(GetModuleHandle(_T("kernel32.dll")), "GetNativeSystemInfo"); + if (pGetNativeSystemInfo != NULL) + pGetNativeSystemInfo(&Info); + else + GetSystemInfo(&Info); + + if (Info.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64) + arch = 64; + else + arch = 32; +#endif + + switch (uMsg) + { + case WM_INITDIALOG: + if (stationLookup) + { + SendMessage(GetDlgItem(hwndDlg, IDC_STATIONCONFIG_ENABLE), BM_SETCHECK, BST_CHECKED, 0); + if (!localDBExists) + Edit_SetText(GetDlgItem(hwndDlg, IDC_STATIONCONFIG_STATUS), "Database Status: No route to host"); + else + Edit_SetText(GetDlgItem(hwndDlg, IDC_STATIONCONFIG_STATUS), "Database Status: Good"); + } + else + { + SendMessage(GetDlgItem(hwndDlg, IDC_STATIONCONFIG_ENABLE), BM_SETCHECK, BST_UNCHECKED, 0); + Edit_SetText(GetDlgItem(hwndDlg, IDC_STATIONCONFIG_STATUS), "Database Status: disabled"); + } + + if (workOffline) + { + SendMessage(GetDlgItem(hwndDlg, IDC_STATIONCONFIG_OFFLINE), BM_SETCHECK, BST_CHECKED, 0); + if (localDBExists) + Edit_SetText(GetDlgItem(hwndDlg, IDC_STATIONCONFIG_STATUS), "Database Status: Good (offline)"); + else + Edit_SetText(GetDlgItem(hwndDlg, IDC_STATIONCONFIG_STATUS), "Database Status: No database and offline"); + } + else + SendMessage(GetDlgItem(hwndDlg, IDC_STATIONCONFIG_OFFLINE), BM_SETCHECK, BST_UNCHECKED, 0); + +#ifdef DEBUG_STATION + char tmpString[1024]; + if (EqualsMajorVersion(7) && EqualsMinorVersion(1)) + sprintf_s(tmpString, 1024, "major: 7, minor: 1, dll: %d, arch: %d", ((sizeof(void *)) * 8), arch); + else if (EqualsMajorVersion(7) && EqualsMinorVersion(0)) + sprintf_s(tmpString, 1024, "major: 7, minor: 0, dll: %d, arch: %d", ((sizeof(void *)) * 8), arch); + else if (EqualsMajorVersion(6) && EqualsMinorVersion(7)) + sprintf_s(tmpString, 1024, "major: 6, minor: 7, dll: %d, arch: %d", ((sizeof(void *)) * 8), arch); + else if (EqualsMajorVersion(6) && EqualsMinorVersion(6)) + sprintf_s(tmpString, 1024, "major: 6, minor: 6, dll: %d, arch: %d", ((sizeof(void *)) * 8), arch); + else if (EqualsMajorVersion(6) && EqualsMinorVersion(5)) + sprintf_s(tmpString, 1024, "major: 6, minor: 5, dll: %d, arch: %d", ((sizeof(void *)) * 8), arch); + else if (EqualsMajorVersion(6) && EqualsMinorVersion(4)) + sprintf_s(tmpString, 1024, "major: 6, minor: 4, dll: %d, arch: %d", ((sizeof(void *)) * 8), arch); + else if (EqualsMajorVersion(6) && EqualsMinorVersion(3)) + sprintf_s(tmpString, 1024, "major: 6, minor: 3, dll: %d, arch: %d", ((sizeof(void *)) * 8), arch); + else if (EqualsMajorVersion(6) && EqualsMinorVersion(2)) + sprintf_s(tmpString, 1024, "major: 6, minor: 2, dll: %d, arch: %d", ((sizeof(void *)) * 8), arch); + else if (EqualsMajorVersion(6) && EqualsMinorVersion(1)) + sprintf_s(tmpString, 1024, "major: 6, minor: 1, dll: %d, arch: %d", ((sizeof(void *)) * 8), arch); + else if (EqualsMajorVersion(6) && EqualsMinorVersion(0)) + sprintf_s(tmpString, 1024, "major: 6, minor: 0, dll: %d, arch: %d", ((sizeof(void *)) * 8), arch); + else if (EqualsMajorVersion(5) && EqualsMinorVersion(2)) + sprintf_s(tmpString, 1024, "major: 5, minor: 2, dll: %d, arch: %d", ((sizeof(void *)) * 8), arch); + else if (EqualsMajorVersion(5) && EqualsMinorVersion(1)) + sprintf_s(tmpString, 1024, "major: 5, minor: 1, dll: %d, arch: %d", ((sizeof(void *)) * 8), arch); + else + sprintf_s(tmpString, 1024, "major: 0, minor: 0, dll: %d, arch: %d", ((sizeof(void *)) * 8), arch); + OutputDebugString(tmpString); +#endif + + ComboBox_ResetContent(GetDlgItem(hwndDlg, IDC_STATIONCONFIG_TAC)); + for (i = 0; i < (sizeof(targetAreaCodes) / sizeof(targetAreaCodes[0])); i++) + { + ComboBox_AddString(GetDlgItem(hwndDlg, IDC_STATIONCONFIG_TAC), targetAreaCodes[i].description); + } + ComboBox_SetCurSel(GetDlgItem(hwndDlg, IDC_STATIONCONFIG_TAC), TACIndex); + + ComboBox_ResetContent(GetDlgItem(hwndDlg, IDC_STATIONCONFIG_ITU)); + for (i = 0; i < (sizeof(ituCodes) / sizeof(ituCodes[0])); i++) + { + ComboBox_AddString(GetDlgItem(hwndDlg, IDC_STATIONCONFIG_ITU), ituCodes[i].countryName); + } + ComboBox_SetCurSel(GetDlgItem(hwndDlg, IDC_STATIONCONFIG_ITU), ITUIndex); + + return true; + break; + + case WM_CLOSE: + ShowWindow(h_StationConfigDialog, SW_HIDE); + return true; + break; + + case WM_DESTROY: + h_StationConfigDialog = NULL; + return true; + break; + + case WM_COMMAND: + switch (GET_WM_COMMAND_ID(wParam, lParam)) + { + case IDC_STATIONCONFIG_PANEL_EXIT: + ShowWindow(h_StationConfigDialog, SW_HIDE); + return true; + break; + + case IDC_STATIONCONFIG_ENABLE: + if (GET_WM_COMMAND_CMD(wParam, lParam) == BST_UNCHECKED) + { + if (Button_GetCheck(GET_WM_COMMAND_HWND(wParam, lParam)) == BST_CHECKED) //it is checked + { + stationLookup = true; + } + else + { + stationLookup = false; + } + } + return true; + break; + + case IDC_STATIONCONFIG_OFFLINE: + if (GET_WM_COMMAND_CMD(wParam, lParam) == BST_UNCHECKED) + { + if (Button_GetCheck(GET_WM_COMMAND_HWND(wParam, lParam)) == BST_CHECKED) //it is checked + { + workOffline = true; + } + else + { + workOffline = false; + } + } + return true; + break; + } + } + return false; +} + +void ReinitAll(void) +{ +#ifdef DEBUG_ENABLE + OutputDebugString("ReinitAll"); +#endif + + chParams->tunerParams.gain.gRdB = GainReduction; + chParams->tunerParams.gain.LNAstate = (unsigned char)LNAGainReduction; + + if (AGCEnabled) + chParams->ctrlParams.agc.enable = sdrplay_api_AGC_5HZ; + else + chParams->ctrlParams.agc.enable = sdrplay_api_AGC_DISABLE; + + if (Running) + { + WinradCallBack(-1, WINRAD_SRCHANGE, 0, NULL); + } + else + { +#ifdef DEBUG_ENABLE + OutputDebugString("Initialise"); +#endif + chParams->tunerParams.rfFreq.rfHz = Frequency * 1e6; + sdrplay_api_Init_fn(chosenDev->dev, &cbFns, NULL); + Running = true; + WinradCallBack(-1, WINRAD_SRCHANGE, 0, NULL); + } +} + +void ApplyDecimation(int decValue) +{ +#ifdef DEBUG_ENABLE + OutputDebugString("ApplyDecimation"); +#endif + if (decValue < 2) + { +#ifdef DEBUG_ENABLE + OutputDebugString("Decimation disabled"); +#endif + DecimateEnable = 0; + chParams->ctrlParams.decimation.decimationFactor = 1; + } + else + { +#ifdef DEBUG_ENABLE + OutputDebugString("Decimation Enabled"); +#endif + DecimateEnable = 1; + chParams->ctrlParams.decimation.decimationFactor = (unsigned char)decValue; + } + + chParams->ctrlParams.decimation.enable = (unsigned char)DecimateEnable; + chParams->ctrlParams.decimation.wideBandSignal = 1; + + WinradCallBack(-1, WINRAD_SRCHANGE, 0, NULL); +} + +void Update_IFBW(void) +{ +#ifdef DEBUG_ENABLE + OutputDebugString("Update_IFBW"); +#endif + HWND ifbwMenu = GetDlgItem(h_dialog, IDC_IFBW); + char str[255]; + int bwArraySize = 4; + + ComboBox_ResetContent(ifbwMenu); + _stprintf_s(str, 255, "200 kHz"); + ComboBox_AddString(ifbwMenu, str); + _stprintf_s(str, 255, "300 kHz"); + ComboBox_AddString(ifbwMenu, str); + _stprintf_s(str, 255, "600 kHz"); + ComboBox_AddString(ifbwMenu, str); + _stprintf_s(str, 255, "1.536 MHz"); + ComboBox_AddString(ifbwMenu, str); + + if (IFmodeIdx == 0) + { + bwArraySize = 8; + // Zero IF + _stprintf_s(str, 255, "5.000 MHz"); + ComboBox_AddString(ifbwMenu, str); + _stprintf_s(str, 255, "6.000 MHz"); + ComboBox_AddString(ifbwMenu, str); + _stprintf_s(str, 255, "7.000 MHz"); + ComboBox_AddString(ifbwMenu, str); + _stprintf_s(str, 255, "8.000 MHz"); + ComboBox_AddString(ifbwMenu, str); + } + + int bot; + double _sr; + if (IFmodeIdx == 0) + { + _sr = samplerates[SampleRateIdx].value; + } + else + { + _sr = 2.0; + } + int _dec = Decimation[DecimationIdx].DecValue; + if (_dec < 1) _dec = 1; + + for (bot = (bwArraySize - 1); bot >= 0; bot--) + { + if ((_sr / _dec) >= bandwidths[bot].BW) + { +#ifdef DEBUG_ENABLE + _stprintf_s(str, 255, "Update_IFBW: bot: %d, _sr: %f, _dec: %d, bw: %f", bot, _sr, _dec, bandwidths[bot].BW); + OutputDebugString(str); +#endif + break; + } + else + { +#ifdef DEBUG_ENABLE + _stprintf_s(str, 255, "Update_IFBW: remove %d", bot); + OutputDebugString(str); +#endif + ComboBox_DeleteString(ifbwMenu, bot); + } + } + + ComboBox_SetCurSel(ifbwMenu, bot); + BandwidthIdx = bot; + Bandwidth = bandwidths[BandwidthIdx].bwType; + chParams->tunerParams.bwType = Bandwidth; +#ifdef DEBUG_ENABLE + _stprintf_s(str, 255, "Update_IFBW: bwType: %d", (int)chParams->tunerParams.bwType); + OutputDebugString(str); +#endif +} + +void Reset_SAMPLERATE(HWND hwndDlg) +{ +#ifdef DEBUG_ENABLE + OutputDebugString("Reset_SAMPLERATE"); +#endif + char str[255]; + HWND srMenu = GetDlgItem(hwndDlg, IDC_SAMPLERATE); + + if (SampleRateIdx < 0 || SampleRateIdx > 8) + { + SampleRateIdx = 0; + } + + Edit_Enable(srMenu, 1); + ComboBox_ResetContent(srMenu); + _stprintf_s(str, 255, "2.0"); + ComboBox_AddString(srMenu, str); + + if (IFmodeIdx == 0) + { + Edit_Enable(srMenu, 1); + _stprintf_s(str, 255, "3.0"); + ComboBox_AddString(srMenu, str); + _stprintf_s(str, 255, "4.0"); + ComboBox_AddString(srMenu, str); + _stprintf_s(str, 255, "5.0"); + ComboBox_AddString(srMenu, str); + _stprintf_s(str, 255, "6.0"); + ComboBox_AddString(srMenu, str); + _stprintf_s(str, 255, "7.0"); + ComboBox_AddString(srMenu, str); + _stprintf_s(str, 255, "8.0"); + ComboBox_AddString(srMenu, str); + _stprintf_s(str, 255, "9.0"); + ComboBox_AddString(srMenu, str); + _stprintf_s(str, 255, "10.0"); + ComboBox_AddString(srMenu, str); + } + else + { + Edit_Enable(srMenu, 0); + } + ComboBox_SetCurSel(srMenu, SampleRateIdx); + + if (IFmodeIdx == 0) + { + deviceParams->devParams->fsFreq.fsHz = samplerates[SampleRateIdx].value * 1e6; + } + else + { + deviceParams->devParams->fsFreq.fsHz = 6000000.0; + SampleRateIdx = 0; // 2.0 MHz + } +} + +void Reset_DECIMATION(HWND hwndDlg) +{ +#ifdef DEBUG_ENABLE + OutputDebugString("Reset_DECIMATION"); +#endif + char str[255]; + HWND decMenu = GetDlgItem(hwndDlg, IDC_DECIMATION); + + DecimationIdx = 0; + + ComboBox_ResetContent(decMenu); + _stprintf_s(str, 255, "None"); + ComboBox_AddString(decMenu, str); + _stprintf_s(str, 255, "2"); + ComboBox_AddString(decMenu, str); + _stprintf_s(str, 255, "4"); + ComboBox_AddString(decMenu, str); + _stprintf_s(str, 255, "8"); + ComboBox_AddString(decMenu, str); + + if (IFmodeIdx == 0 && (SampleRateIdx >= 2)) + { + _stprintf_s(str, 255, "16"); + ComboBox_AddString(decMenu, str); + } + + if (IFmodeIdx == 0 && (SampleRateIdx >= 6)) + { + _stprintf_s(str, 255, "32"); + ComboBox_AddString(decMenu, str); + } + + ComboBox_SetCurSel(decMenu, DecimationIdx); + + chParams->ctrlParams.decimation.enable = 0; + chParams->ctrlParams.decimation.decimationFactor = 1; + chParams->ctrlParams.decimation.wideBandSignal = 1; +} + +void Reset_IFBW() +{ +#ifdef DEBUG_ENABLE + OutputDebugString("Reset_IFBW"); +#endif + char str[255]; + HWND ifbwMenu = GetDlgItem(h_dialog, IDC_IFBW); + + ComboBox_ResetContent(ifbwMenu); + _stprintf_s(str, 255, "200 kHz"); + ComboBox_AddString(ifbwMenu, str); + _stprintf_s(str, 255, "300 kHz"); + ComboBox_AddString(ifbwMenu, str); + _stprintf_s(str, 255, "600 kHz"); + ComboBox_AddString(ifbwMenu, str); + _stprintf_s(str, 255, "1.536 MHz"); + ComboBox_AddString(ifbwMenu, str); + + if (IFmodeIdx == 0) + { + // Zero IF + _stprintf_s(str, 255, "5.000 MHz"); + ComboBox_AddString(ifbwMenu, str); + _stprintf_s(str, 255, "6.000 MHz"); + ComboBox_AddString(ifbwMenu, str); + _stprintf_s(str, 255, "7.000 MHz"); + ComboBox_AddString(ifbwMenu, str); + _stprintf_s(str, 255, "8.000 MHz"); + ComboBox_AddString(ifbwMenu, str); + } + + BandwidthIdx = 3; // 1536 kHz default BW + + ComboBox_SetCurSel(ifbwMenu, BandwidthIdx); + + Bandwidth = bandwidths[BandwidthIdx].bwType; + chParams->tunerParams.bwType = Bandwidth; + +#ifdef DEBUG_ENABLE + _stprintf_s(str, 255, "Reset_IFBW: bwType: %d", (int)chParams->tunerParams.bwType); + OutputDebugString(str); +#endif +} + +void UpdateSR(void) +{ +#ifdef DEBUG_ENABLE + OutputDebugString("UpdateSR"); +#endif + char str[255]; + long SR = (long)(2.0 * 1e6); + + if (IFmodeIdx == 1) + { + if (DecimateEnable == 1 && (DecimationIdx > 0)) + { + SR = SR / Decimation[DecimationIdx].DecValue; + } + } + else + { + SR = (long)(samplerates[SampleRateIdx].value * 1e6); + if (DecimateEnable == 1 && (DecimationIdx > 0)) + { + SR = SR / Decimation[DecimationIdx].DecValue; + } + } +#ifdef DEBUG_ENABLE + sprintf_s(str, 255, "SR: %d", SR); + OutputDebugString(str); +#endif + sprintf_s(str, sizeof(str), "%.2f MHz", (SR / 1e6)); + Edit_SetText(GetDlgItem(h_dialog, IDC_FINALSR), str); +} diff --git a/RSPdxR2/src/ExtIO_SDRplay.h b/RSPdxR2/src/ExtIO_SDRplay.h new file mode 100644 index 0000000..024eeed --- /dev/null +++ b/RSPdxR2/src/ExtIO_SDRplay.h @@ -0,0 +1,18 @@ +// The following ifdef block is the standard way of creating macros which make exporting +// from a DLL simpler. All files within this DLL are compiled with the LIBSDRplay_EXPORTS +// symbol defined on the command line. This symbol should not be defined on any project +// that uses this DLL. This way any other project whose source files include this file see +// LIBSDRplay_API functions as being imported from a DLL, whereas this DLL sees symbols +// defined with this macro as being exported. + +#ifdef LIBSDRplay_EXPORTS +#define LIBSDRplay_API __declspec(dllexport) +#else +#define LIBSDRplay_API __declspec(dllimport) +#endif + +extern HMODULE hInst; +void LoadProfile(int); +void LoadProfilesReg(HWND); +void LoadFreqsReg(HWND); +void UpdateProfile(void); \ No newline at end of file diff --git a/RSPdxR2/src/ExtIO_SDRplay.rc b/RSPdxR2/src/ExtIO_SDRplay.rc new file mode 100644 index 0000000..e58abc1 --- /dev/null +++ b/RSPdxR2/src/ExtIO_SDRplay.rc @@ -0,0 +1,181 @@ +// Generated by ResEdit 1.6.6 +// Copyright (C) 2006-2015 +// http://www.resedit.net + +#include +#include +#include +#include "resource.h" + +// +// Bitmap resources +// +LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL +IDB_RSPdxR2 BITMAP "..\\Resources\\SDRplay RSPdxR2 Diagram.bmp" + +// +// Dialog resources +// +LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL +IDD_ADVANCED DIALOG 0, 0, 227, 246 +STYLE DS_3DLOOK | DS_CENTER | DS_SETFONT | WS_CAPTION | WS_SYSMENU +EXSTYLE WS_EX_WINDOWEDGE | WS_EX_TOOLWINDOW | WS_EX_TOPMOST +CAPTION "SDRplay RSP Advanced Dialog" +FONT 8, "Ms Shell Dlg" +{ + PUSHBUTTON "Apply", IDC_ADVANCED_APPLY, 105, 226, 50, 14, 0, WS_EX_LEFT + GROUPBOX "LO Frequency Plan", ID_LOPLAN, 17, 15, 196, 59, 0, WS_EX_TRANSPARENT + AUTORADIOBUTTON "Auto", IDC_LOAUTO, 31, 33, 31, 8, WS_GROUP, WS_EX_LEFT + AUTORADIOBUTTON "120MHz", IDC_LO120, 65, 33, 43, 8, 0, WS_EX_LEFT + AUTORADIOBUTTON "144MHz", IDC_LO144, 112, 34, 43, 8, 0, WS_EX_LEFT + AUTORADIOBUTTON "168MHz", IDC_LO168, 159, 34, 43, 8, 0, WS_EX_LEFT + CONTROL "Static", IDC_LOWARNING, WC_STATIC, NOT WS_GROUP | SS_LEFTNOWORDWRAP | SS_CENTERIMAGE, 31, 50, 166, 8, WS_EX_LEFT + LTEXT "Static", IDC_LOWARNING1, 31, 62, 166, 9, SS_LEFT, WS_EX_LEFT + GROUPBOX "Tuner DC Offset Compensation", ID_TUNER_COMPENSATION, 19, 83, 192, 95, 0, WS_EX_TRANSPARENT + AUTORADIOBUTTON "Static", IDC_DCSTAT, 29, 103, 34, 8, WS_GROUP, WS_EX_LEFT + AUTORADIOBUTTON "One Shot", IDC_ONESHOT, 29, 120, 46, 8, 0, WS_EX_LEFT + AUTORADIOBUTTON "Periodic ", IDC_PERIODIC, 29, 138, 43, 8, 0, WS_EX_LEFT + AUTORADIOBUTTON "Continuous", IDC_CONTINUOUS, 29, 156, 51, 8, 0, WS_EX_LEFT + GROUPBOX "Refresh Period", ID_REFREASH, 104, 97, 92, 33, 0, WS_EX_LEFT + COMBOBOX IDC_REFRESH, 119, 110, 63, 250, CBS_DROPDOWNLIST | CBS_HASSTRINGS, WS_EX_LEFT + GROUPBOX "Tracking Period", ID_TRACKING, 103, 135, 93, 33, 0, WS_EX_LEFT + CONTROL "", IDC_TRACKINGPERIOD, TRACKBAR_CLASS, WS_TABSTOP | TBS_BOTH | TBS_NOTICKS, 109, 148, 43, 17, WS_EX_LEFT + LTEXT "Static", IDC_TRACKTIME, 156, 150, 36, 9, SS_LEFT, WS_EX_LEFT + PUSHBUTTON "Exit", IDC_ADVANCED_EXIT, 160, 226, 50, 14, 0, WS_EX_LEFT + GROUPBOX "Post Tuner DC/IQ Compensation", ID_COMPENSATION, 21, 184, 191, 35, 0, WS_EX_LEFT + AUTOCHECKBOX "Enable Post Tuner DC/IQ Compensation", IDC_POSTDCOFFSET, 35, 201, 150, 8, 0, WS_EX_LEFT + PUSHBUTTON "Station Config", IDC_ADVANCED_STATIONCONFIG, 20, 226, 60, 14, 0, WS_EX_LEFT +} + +LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL +IDD_HELP_PANEL DIALOG 0, 0, 250, 310 +STYLE DS_3DLOOK | DS_CENTER | DS_SETFONT | WS_CAPTION | WS_SYSMENU +EXSTYLE WS_EX_WINDOWEDGE | WS_EX_TOOLWINDOW | WS_EX_TOPMOST +CAPTION "SDRplay RSP Help Dialog" +FONT 8, "Ms Shell Dlg" +{ + LTEXT "SDRplay's EXTIO Plugin Quick Help Guide", IDC_HELP_STATIC1, 20, 20, 180, 15, SS_LEFT, WS_EX_LEFT + LTEXT "A more in depth user guide can be obtained by\nclicking the following button (internet connection required)", IDC_HELP_STATIC2, 20, 40, 180, 30, SS_LEFT, WS_EX_LEFT + PUSHBUTTON "Online User Guide", IDC_HELP_LINK, 60, 80, 100, 15, 0, WS_EX_LEFT + LTEXT "Hotkeys:\n\nALT-A = Toggle AGC enable\nALT-P = Toggle Profile Panel display\nALT-X = Toggle EXTIO Panel display\n+ = Gain increase (keypad and main keyboard)\n- = Gain decrease (keypad and main keyboard)\nSHIFT-F1 - SHIFT-F8 = activate stored profile (P1 - P8)", IDC_HELP_STATIC3, 20, 110, 180, 80, SS_LEFT, WS_EX_LEFT + LTEXT "Use the Profiles Panel to manage your profiles and\nto save profiles to a specified filename so that\nyou can recall them later\nSaved profiles can be shared with other SDRplay users", IDC_HELP_STATIC4, 20, 190, 180, 50, SS_LEFT, WS_EX_LEFT + PUSHBUTTON "Exit", IDC_HELP_PANEL_EXIT, 170, 240, 40, 15, 0, WS_EX_LEFT + LTEXT "", IDC_APIVER, 10, 240, 80, 15 + LTEXT "", IDC_APIPATH, 10, 255, 230, 30 + LTEXT "", IDC_REGPATH, 10, 275, 230, 45 +} + +LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL +IDD_PROFILES_PANEL DIALOG 0, 0, 290, 350 +STYLE DS_3DLOOK | DS_CENTER | DS_SETFONT | WS_CAPTION | WS_SYSMENU +EXSTYLE WS_EX_WINDOWEDGE | WS_EX_TOOLWINDOW | WS_EX_TOPMOST +CAPTION "SDRplay RSP Profiles Dialog" +FONT 8, "Ms Shell Dlg" +{ + PUSHBUTTON "Load a Profile and Activate", IDC_LoadProfile, 15, 306, 110, 15, 0, WS_EX_LEFT + PUSHBUTTON "Save Current Setup As a Profile", IDC_SaveProfile, 15, 325, 110, 15, 0, WS_EX_LEFT + PUSHBUTTON "Exit", IDC_PROF_EXIT, 230, 325, 40, 15, 0, WS_EX_LEFT + LTEXT "", IDC_PROF_BACK_ONE, 15, 15, 260, 30, NOT WS_GROUP | SS_LEFT | SS_SUNKEN, WS_EX_STATICEDGE + PUSHBUTTON "P1", IDC_PROF_BUTTON_ONE, 20, 20, 30, 20, 0, WS_EX_LEFT + CTEXT "\nNO PROFILE CURRENTLY ASSIGNED", IDC_PROF_DESC_ONE, 55, 20, 180, 20, WS_BORDER | SS_CENTER, WS_EX_LEFT + PUSHBUTTON "ASSIGN", IDC_LOADPROFILE_P1, 240, 20, 30, 20, 0, WS_EX_LEFT + LTEXT "", IDC_PROF_BACK_TWO, 15, 50, 260, 30, NOT WS_GROUP | SS_LEFT | SS_SUNKEN, WS_EX_STATICEDGE + PUSHBUTTON "P2", IDC_PROF_BUTTON_TWO, 20, 55, 30, 20, 0, WS_EX_LEFT + CTEXT "\nNO PROFILE CURRENTLY ASSIGNED", IDC_PROF_DESC_TWO, 55, 55, 180, 20, WS_BORDER | SS_CENTER, WS_EX_LEFT + PUSHBUTTON "ASSIGN", IDC_LOADPROFILE_P2, 240, 55, 30, 20, 0, WS_EX_LEFT + LTEXT "", IDC_PROF_BACK_THREE, 15, 85, 260, 30, NOT WS_GROUP | SS_LEFT | SS_SUNKEN, WS_EX_STATICEDGE + PUSHBUTTON "P3", IDC_PROF_BUTTON_THREE, 20, 90, 30, 20, 0, WS_EX_LEFT + CTEXT "\nNO PROFILE CURRENTLY ASSIGNED", IDC_PROF_DESC_THREE, 55, 90, 180, 20, WS_BORDER | SS_CENTER, WS_EX_LEFT + PUSHBUTTON "ASSIGN", IDC_LOADPROFILE_P3, 240, 90, 30, 20, 0, WS_EX_LEFT + LTEXT "", IDC_PROF_BACK_FOUR, 15, 120, 260, 30, NOT WS_GROUP | SS_LEFT | SS_SUNKEN, WS_EX_STATICEDGE + PUSHBUTTON "P4", IDC_PROF_BUTTON_FOUR, 20, 125, 30, 20, 0, WS_EX_LEFT + CTEXT "\nNO PROFILE CURRENTLY ASSIGNED", IDC_PROF_DESC_FOUR, 55, 125, 180, 20, WS_BORDER | SS_CENTER, WS_EX_LEFT + PUSHBUTTON "ASSIGN", IDC_LOADPROFILE_P4, 240, 125, 30, 20, 0, WS_EX_LEFT + LTEXT "", IDC_PROF_BACK_FIVE, 15, 155, 260, 30, NOT WS_GROUP | SS_LEFT | SS_SUNKEN, WS_EX_STATICEDGE + PUSHBUTTON "P5", IDC_PROF_BUTTON_FIVE, 20, 160, 30, 20, 0, WS_EX_LEFT + CTEXT "\nNO PROFILE CURRENTLY ASSIGNED", IDC_PROF_DESC_FIVE, 55, 160, 180, 20, WS_BORDER | SS_CENTER, WS_EX_LEFT + PUSHBUTTON "ASSIGN", IDC_LOADPROFILE_P5, 240, 160, 30, 20, 0, WS_EX_LEFT + LTEXT "", IDC_PROF_BACK_SIX, 15, 190, 260, 30, NOT WS_GROUP | SS_LEFT | SS_SUNKEN, WS_EX_STATICEDGE + PUSHBUTTON "P6", IDC_PROF_BUTTON_SIX, 20, 195, 30, 20, 0, WS_EX_LEFT + CTEXT "\nNO PROFILE CURRENTLY ASSIGNED", IDC_PROF_DESC_SIX, 55, 195, 180, 20, WS_BORDER | SS_CENTER, WS_EX_LEFT + PUSHBUTTON "ASSIGN", IDC_LOADPROFILE_P6, 240, 195, 30, 20, 0, WS_EX_LEFT + LTEXT "", IDC_PROF_BACK_SEVEN, 15, 225, 260, 30, NOT WS_GROUP | SS_LEFT | SS_SUNKEN, WS_EX_STATICEDGE + PUSHBUTTON "P7", IDC_PROF_BUTTON_SEVEN, 20, 230, 30, 20, 0, WS_EX_LEFT + CTEXT "\nNO PROFILE CURRENTLY ASSIGNED", IDC_PROF_DESC_SEVEN, 55, 230, 180, 20, WS_BORDER | SS_CENTER, WS_EX_LEFT + PUSHBUTTON "ASSIGN", IDC_LOADPROFILE_P7, 240, 230, 30, 20, 0, WS_EX_LEFT + LTEXT "", IDC_PROF_BACK_EIGHT, 15, 260, 260, 30, NOT WS_GROUP | SS_LEFT | SS_SUNKEN, WS_EX_STATICEDGE + PUSHBUTTON "P8", IDC_PROF_BUTTON_EIGHT, 20, 265, 30, 20, 0, WS_EX_LEFT + CTEXT "\nNO PROFILE CURRENTLY ASSIGNED", IDC_PROF_DESC_EIGHT, 55, 265, 180, 20, WS_BORDER | SS_CENTER, WS_EX_LEFT + PUSHBUTTON "ASSIGN", IDC_LOADPROFILE_P8, 240, 265, 30, 20, 0, WS_EX_LEFT +} + +LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL +IDD_SDRPLAY_SETTINGS DIALOG 0, 0, 565, 278 +STYLE DS_3DLOOK | DS_CENTER | DS_SETFONT | WS_CAPTION | WS_GROUP | WS_SYSMENU +EXSTYLE WS_EX_WINDOWEDGE | WS_EX_TOOLWINDOW | WS_EX_TOPMOST +CAPTION "SDRplay RSPdxR2 Device Controller" +FONT 8, "Ms Shell Dlg" +{ + PUSHBUTTON "Advanced", IDC_Advanced, 365, 258, 50, 17, 0, WS_EX_LEFT + CONTROL IDB_RSPdxR2, 0, WC_STATIC, SS_BITMAP | SS_CENTERIMAGE | SS_SUNKEN | SS_REALSIZECONTROL, 4294967295, 1, 565, 238, WS_EX_STATICEDGE + EDITTEXT IDC_LNAGRNO, 69, 136, 31, 14, WS_DISABLED | ES_AUTOHSCROLL | ES_NUMBER, WS_EX_LEFT + CONTROL "", IDC_LNASLIDER, TRACKBAR_CLASS, WS_TABSTOP | WS_BORDER | TBS_AUTOTICKS | TBS_VERT | TBS_BOTH | TBS_ENABLESELRANGE, 69, 74, 31, 62, WS_EX_LEFT + COMBOBOX IDC_IFMODE, 307, 79, 50, 100, CBS_DROPDOWNLIST | CBS_HASSTRINGS, WS_EX_LEFT + EDITTEXT IDC_PPM, 166, 87, 40, 14, ES_RIGHT | ES_AUTOHSCROLL, WS_EX_LEFT + CONTROL "", IDC_PPM_S, UPDOWN_CLASS, UDS_ALIGNRIGHT | UDS_ARROWKEYS | UDS_SETBUDDYINT, 206, 87, 11, 14, WS_EX_LEFT + COMBOBOX IDC_IFBW, 307, 103, 50, 100, CBS_DROPDOWNLIST | CBS_HASSTRINGS, WS_EX_LEFT + EDITTEXT IDC_SETPOINT, 435, 120, 35, 15, ES_RIGHT | ES_AUTOHSCROLL, WS_EX_LEFT + CONTROL "", IDC_SETPOINT_S, UPDOWN_CLASS, UDS_ALIGNRIGHT | UDS_ARROWKEYS | UDS_AUTOBUDDY | UDS_SETBUDDYINT, 459, 127, 10, 15, WS_EX_LEFT + COMBOBOX IDC_DECIMATION, 434, 100, 35, 20, CBS_DROPDOWNLIST | CBS_HASSTRINGS, WS_EX_LEFT + LTEXT " MHz", IDC_FINALSR, 435, 143, 35, 10, SS_LEFT, WS_EX_LEFT + EDITTEXT IDC_GR, 497, 167, 30, 14, WS_DISABLED | ES_RIGHT | ES_AUTOHSCROLL | ES_NUMBER, WS_EX_STATICEDGE + AUTOCHECKBOX "", IDC_RSPAGC, 474, 204, 10, 10, BS_LEFTTEXT | BS_CENTER | BS_NOTIFY, WS_EX_TRANSPARENT + COMBOBOX IDC_SAMPLERATE, 433, 75, 35, 175, CBS_DROPDOWNLIST | CBS_HASSTRINGS, WS_EX_LEFT + CONTROL "", IDC_GAINSLIDER, TRACKBAR_CLASS, WS_TABSTOP | TBS_VERT | TBS_BOTH | TBS_ENABLESELRANGE, 497, 78, 30, 90, WS_EX_STATICEDGE + LTEXT "SDRplay Ltd", IDC_STATIC2, 8, 257, 40, 9, SS_LEFT, WS_EX_LEFT + LTEXT "Version 1.0 Build 0512", IDC_STATIC3, 7, 266, 100, 9, SS_LEFT, WS_EX_LEFT + LTEXT "Station: ", IDC_STATIONNAME, 20, 247, 200, 9, SS_LEFT | SS_NOTIFY, WS_EX_LEFT + PUSHBUTTON "^", IDC_StationName_PopOut, 7, 246, 10, 10, 0, WS_EX_LEFT + PUSHBUTTON "Load Defaults", IDC_LoadDefaults, 420, 258, 60, 17, 0, WS_EX_LEFT + PUSHBUTTON "Exit", IDC_EXIT, 525, 258, 35, 17, 0, WS_EX_LEFT + PUSHBUTTON "Help", IDC_HELP_BUTTON, 485, 258, 35, 17, 0, WS_EX_LEFT + PUSHBUTTON "Profiles", IDC_ProfilesButton, 310, 258, 50, 17, 0, WS_EX_LEFT + LTEXT "Current Profile: ", IDC_ProfileFileName, 95, 265, 150, 9, SS_LEFT, WS_EX_LEFT + AUTOCHECKBOX "MW/FM", IDC_NOTCHENABLE, 115, 105, 38, 8, 0, WS_EX_LEFT + AUTOCHECKBOX "DAB", IDC_DABNOTCHENABLE, 115, 120, 38, 8, 0, WS_EX_LEFT + COMBOBOX IDC_ANTSELECT, 12, 199, 43, 14, CBS_DROPDOWNLIST | CBS_HASSTRINGS, WS_EX_LEFT + LTEXT "Total System Gain Reduction 78 dB", IDC_TOTALGR, 233, 225, 132, 10, SS_LEFT, WS_EX_LEFT + LTEXT "", IDC_PROFILE_CHANGED, 287, 260, 10, 9, SS_LEFT, WS_EX_LEFT + CTEXT "Frequency Correction (PPM)", IDC_PPMTXT, 162, 69, 64, 18, SS_CENTER, WS_EX_LEFT + AUTOCHECKBOX "ANT B Bias-T Enable", IDC_BIASTENABLE, 65, 226, 83, 8, 0, WS_EX_LEFT + LTEXT "", IDC_OVERLOAD, 160, 226, 60, 8, SS_LEFT, WS_EX_LEFT +} + +LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL +IDD_STATION_PANEL DIALOG 0, 0, 120, 20 +STYLE DS_3DLOOK | DS_CENTER | DS_SETFONT | WS_CAPTION | WS_SYSMENU +EXSTYLE WS_EX_WINDOWEDGE | WS_EX_TOOLWINDOW | WS_EX_TOPMOST | 0x80000000 +CAPTION "SDRplay RSP | Station Name" +FONT 8, "Ms Shell Dlg" +{ + LTEXT "Station Name: ", IDC_STATION_LABEL, 5, 5, 110, 15, SS_LEFT | SS_NOTIFY, WS_EX_LEFT +} + +LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL +IDD_STATIONCONFIG_PANEL DIALOG 0, 0, 310, 190 +STYLE DS_3DLOOK | DS_CENTER | DS_SETFONT | WS_CAPTION | WS_SYSMENU +EXSTYLE WS_EX_WINDOWEDGE | WS_EX_TOOLWINDOW | WS_EX_TOPMOST +CAPTION "SDRplay RSP Station Lookup Config" +FONT 8, "Ms Shell Dlg" +{ + AUTOCHECKBOX "Station Name System Enable", IDC_STATIONCONFIG_ENABLE, 10, 20, 120, 10, BS_LEFTTEXT | BS_CENTER | BS_NOTIFY, WS_EX_TRANSPARENT + AUTOCHECKBOX "Work Offline?", IDC_STATIONCONFIG_OFFLINE, 10, 50, 120, 10, BS_LEFTTEXT | BS_CENTER | BS_NOTIFY, WS_EX_TRANSPARENT + LTEXT "(note: station system enable requires restart of SDR application)", IDC_STATIONCONFIG_STATIC4, 20, 30, 250, 10, SS_LEFT, WS_EX_LEFT + LTEXT "Database Status: ", IDC_STATIONCONFIG_STATUS, 20, 70, 200, 10, SS_LEFT, WS_EX_LEFT + LTEXT "Select Target Area:", IDC_STATIONCONFIG_STATIC1, 20, 100, 80, 10, SS_LEFT, WS_EX_LEFT + COMBOBOX IDC_STATIONCONFIG_TAC, 90, 100, 210, 12, WS_VSCROLL | CBS_DROPDOWNLIST | CBS_HASSTRINGS | CBS_DISABLENOSCROLL, WS_EX_LEFT + LTEXT "Select Country:", IDC_STATIONCONFIG_STATIC2, 20, 120, 80, 10, SS_LEFT, WS_EX_LEFT + COMBOBOX IDC_STATIONCONFIG_ITU, 90, 120, 210, 12, WS_VSCROLL | CBS_DROPDOWNLIST | CBS_HASSTRINGS | CBS_DISABLENOSCROLL, WS_EX_LEFT + LTEXT "Target Area takes precedence over Country if both are selected.", IDC_STATIONCONFIG_STATIC3, 20, 140, 250, 10, SS_LEFT, WS_EX_LEFT + PUSHBUTTON "Exit", IDC_STATIONCONFIG_PANEL_EXIT, 150, 170, 40, 15, 0, WS_EX_LEFT +} diff --git a/RSPdxR2/src/dllmain.cpp b/RSPdxR2/src/dllmain.cpp new file mode 100644 index 0000000..0da7087 --- /dev/null +++ b/RSPdxR2/src/dllmain.cpp @@ -0,0 +1,21 @@ +// dllmain.cpp : Defines the entry point for the DLL application. +#include + +HMODULE hInst; + +BOOL APIENTRY DllMain(HMODULE hModule, + DWORD ul_reason_for_call, + LPVOID + ) +{ + switch (ul_reason_for_call) + { + case DLL_PROCESS_ATTACH: + hInst = hModule; + case DLL_THREAD_ATTACH: + case DLL_THREAD_DETACH: + case DLL_PROCESS_DETACH: + break; + } + return true; +} diff --git a/RSPdxR2/src/exports.def b/RSPdxR2/src/exports.def new file mode 100644 index 0000000..55a4aa0 --- /dev/null +++ b/RSPdxR2/src/exports.def @@ -0,0 +1,27 @@ +LIBRARY ExtIO_SDRplay_RSPdxR2 +EXPORTS +CloseHW +GetHWLO +GetHWSR +GetStatus +InitHW +OpenHW +SetCallback +SetHWLO +ShowGUI +HideGUI +SwitchGUI +StartHW +StopHW +ExtIoGetSrates +ExtIoGetActualSrateIdx +ExtIoSetSrate +ExtIoGetSetting +ExtIoSetSetting +GetAttenuators +GetActualAttIdx +SetAttenuator +TuneChanged +GetTune +ModeChanged +GetMode \ No newline at end of file diff --git a/RSPdxR2/src/resource.h b/RSPdxR2/src/resource.h new file mode 100644 index 0000000..da9efe5 --- /dev/null +++ b/RSPdxR2/src/resource.h @@ -0,0 +1,122 @@ +#ifndef IDC_STATIC +#define IDC_STATIC (-1) +#endif + +#define IDB_RSPdxR2 101 +#define IDB_SDRPlay 39995 +#define IDD_ADVANCED 39996 +#define IDC_PPM 39997 +#define IDC_GAINSLIDER 39998 +#define IDD_SDRPLAY_SETTINGS 39999 +#define IDC_ADVANCED_EXIT 40000 +#define IDC_LNASLIDER 40001 +#define IDC_PROFILE_CHANGED 40002 +#define IDC_LNAGRNO 40003 +#define IDC_LOWARNING 40004 +#define IDC_SETPOINT 40005 +#define IDC_LO120 40007 +#define IDC_NOTCHENABLE 40008 +#define IDC_ONESHOT 40009 +#define IDC_ADVANCED_APPLY 40010 +#define IDC_BIASTENABLE 40011 +#define IDC_REFCLOCKOUT 40012 +#define IDC_TRACKINGPERIOD 40013 +#define IDC_GR 40014 +#define IDC_TRACKTIME 40015 +#define IDC_PERIODIC 40016 +#define IDC_LO144 40017 +#define IDC_CONTINUOUS 40018 +#define IDC_LOWARNING1 40019 +#define IDC_LO168 40020 +#define IDC_IFMODE 40021 +#define IDC_REFRESH 40022 +#define IDC_LOAUTO 40023 +#define IDC_IFBW 40024 +#define IDC_DCSTAT 40025 +#define IDC_SETPOINT_S 40026 +#define IDC_RSPAGC 40027 +#define IDC_Advanced 40028 +#define IDC_LoadDefaults 40029 +#define IDC_EXIT 40030 +#define IDC_SAMPLERATE 40034 +#define IDC_LoadProfile 40035 +#define IDC_SaveProfile 40036 +#define IDC_ProfileFileName 40037 +#define IDC_STATIC2 40038 +#define IDC_STATIC3 40039 +#define IDC_PPM_S 40040 +#define ID_REFREASH 40041 +#define ID_COMPENSATION 40042 +#define IDC_POSTDCOFFSET 40043 +#define ID_TUNER_COMPENSATION 40044 +#define ID_LOPLAN 40045 +#define ID_TRACKING 40046 +#define IDC_LOADPROFILE_P1 40076 +#define IDC_LOADPROFILE_P2 40077 +#define IDC_LOADPROFILE_P3 40078 +#define IDC_LOADPROFILE_P4 40079 +#define IDC_LOADPROFILE_P5 40080 +#define IDC_LOADPROFILE_P6 40081 +#define IDC_LOADPROFILE_P7 40082 +#define IDC_LOADPROFILE_P8 40083 +#define IDC_ProfilesButton 40102 +#define IDD_PROFILES_PANEL 40104 +#define IDC_PROF_BACK_ONE 40121 +#define IDC_PROF_BACK_TWO 40122 +#define IDC_PROF_BACK_THREE 40123 +#define IDC_PROF_BACK_FOUR 40124 +#define IDC_PROF_BACK_FIVE 40125 +#define IDC_PROF_BACK_SIX 40126 +#define IDC_PROF_BACK_SEVEN 40127 +#define IDC_PROF_BACK_EIGHT 40128 +#define IDC_PROF_BUTTON_ONE 40131 +#define IDC_PROF_BUTTON_TWO 40132 +#define IDC_PROF_BUTTON_THREE 40133 +#define IDC_PROF_BUTTON_FOUR 40134 +#define IDC_PROF_BUTTON_FIVE 40135 +#define IDC_PROF_BUTTON_SIX 40136 +#define IDC_PROF_BUTTON_SEVEN 40137 +#define IDC_PROF_BUTTON_EIGHT 40138 +#define IDC_PROF_DESC_ONE 40141 +#define IDC_PROF_DESC_TWO 40142 +#define IDC_PROF_DESC_THREE 40143 +#define IDC_PROF_DESC_FOUR 40144 +#define IDC_PROF_DESC_FIVE 40145 +#define IDC_PROF_DESC_SIX 40146 +#define IDC_PROF_DESC_SEVEN 40147 +#define IDC_PROF_DESC_EIGHT 40148 +#define IDC_PROF_EXIT 40164 +#define IDC_HELP_BUTTON 40169 +#define IDD_HELP_PANEL 40170 +#define IDC_HELP_PANEL_EXIT 40171 +#define IDC_HELP_STATIC1 40172 +#define IDC_HELP_STATIC2 40173 +#define IDC_HELP_LINK 40174 +#define IDC_HELP_STATIC3 40175 +#define IDC_HELP_STATIC4 40176 +#define IDC_TOTALGR 40179 +#define IDC_STATIONNAME 40180 +#define IDD_STATION_PANEL 40181 +#define IDC_STATION_LABEL 40182 +#define IDC_StationName_PopOut 40183 +#define IDD_STATIONCONFIG_PANEL 40184 +#define IDC_STATIONCONFIG_ENABLE 40185 +#define IDC_STATIONCONFIG_PANEL_EXIT 40186 +#define IDC_ADVANCED_STATIONCONFIG 40187 +#define IDC_STATIONCONFIG_STATUS 40188 +#define IDC_STATIONCONFIG_TAC 40189 +#define IDC_STATIONCONFIG_STATIC1 40190 +#define IDC_STATIONCONFIG_ITU 40191 +#define IDC_STATIONCONFIG_STATIC2 40192 +#define IDC_STATIONCONFIG_STATIC3 40193 +#define IDC_STATIONCONFIG_STATIC4 40199 +#define IDC_STATIONCONFIG_OFFLINE 40200 +#define IDC_DECIMATION 40201 +#define IDC_FINALSR 40202 +#define IDC_PPMTXT 40204 +#define IDC_OVERLOAD 40205 +#define IDC_APIVER 40206 +#define IDC_APIPATH 40207 +#define IDC_REGPATH 40208 +#define IDC_DABNOTCHENABLE 40209 +#define IDC_ANTSELECT 40210 diff --git a/RSPdxR2/src/targetver.h b/RSPdxR2/src/targetver.h new file mode 100644 index 0000000..87c0086 --- /dev/null +++ b/RSPdxR2/src/targetver.h @@ -0,0 +1,8 @@ +#pragma once + +// Including SDKDDKVer.h defines the highest available Windows platform. + +// If you wish to build your application for a previous Windows platform, include WinSDKVer.h and +// set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h. + +#include