From 9384102e8c24b2d89640a8a878887dc9cc57e0cf Mon Sep 17 00:00:00 2001 From: OH1KH Date: Sat, 7 May 2022 09:28:21 +0300 Subject: [PATCH 1/2] Fixes to mode/submode handling This fix does not affect "classic" modes CW,AM,FM and SSB that already has had conversion from USB/LSB to SSB. How ever there are hundreds of submodes in adif standard. IMHO the idea of mode and submode is not very clever. I would like to see all submodes to be modes, and then then there would be modegroups instead. This way mode would be mandatory information and modegroup just makes genres of them if that is needed for awards or other kinds of grouping. But we have to live with this. This fix makes conversion from mode+submode to "CqrMode" that mainly is submode in ADIF standard. How ever there are some exceptions. A part of submodes are "for import only" by ADIF standard. They should be accepted in import, but never exported. It seems that at least eQSL does not follow that standard sending mode:RTTY submode:ASCI in doenwload if user has uploaded it that way to eQSL. Another execptions come from Cqrlog itself. Mentioned submodes LSB and USB are logged in Cqrlog as SSB (that is the mode, not submode). Then rigctld may set mode to PACKET, USBPACKET... etc. with Icom rigs in data mode. This, if logged that way, is not ADIF standard mode and must be converted to PKT that is ADIF standard mode. To do these conversions we need function/procedure "ModeToCqr()" and "ModeFromCqr()" Those functions use conversion tables from files "submode_mode.txt" (the main mode/submode table), "import_mode.txt" (table of import only submodes) and "exception_mode.txt" (special conversion for Cqrlog in/out) If files do not exist they are created at Cqrlog start to ~/.config/cqrlog folder with breaf "README_modefiles" explanation file. After that files are not touched and user can make changes by himself without programming and compile if something changes in ADIF standard. Files are loaded to string lists at Cqrlog start. "ModeToCqr()" and "ModeFromCqr()" usage is added to all routines that uses ADIF import or export. Excluding online logging. I do not use them, can not test, and did not find explanation of their API and mode/submode usage there. There is still work to do with exports as I have seen that there are many export routines doing same kind of jobs that could be combined to one "common export" or "create adif record" procedure. That maybe later... --------------- Help files updated (Quick start/modes) --------------- Improved external database server's backups script. Makes now one common mysqldump from all cqr* databases and separate dumps from each one with date/time stamp on filename. --------------- Squashed commit of the following: commit dc1ca22633eefa9365961a551e6b9d1585f23cc8 Author: OH1KH Date: Fri May 6 17:35:47 2022 +0300 Fixed some comments commit 4ec5ddf25c37de627a5d8fc876add35aee5f6de9 Author: OH1KH Date: Thu May 5 20:03:17 2022 +0300 Changed modefile directory. Updated help files commit 7a0c5de47f5e3de58f4ab9f364892bdc92f1aa62 Author: OH1KH Date: Thu May 5 13:10:03 2022 +0300 Assigned and tested eQSL and LoTW uploads. For other uploads: checked them, but cannot be sure with online logs (I can not test them) commit dfb35ef2df5bec37913d3150f9dc5afb2386b477 Author: OH1KH Date: Thu May 5 11:18:45 2022 +0300 Tested eQSl and LoTW downloads commit 79a2072d21cc82db4028362b4da58a02f637d5ea Author: OH1KH Date: Wed May 4 19:06:11 2022 +0300 Fixed debug printing. Tested: adif export and import commit 5f86f8899c6c9b3d8fbd849115d8ef3147166e73 Author: OH1KH Date: Wed May 4 11:47:53 2022 +0300 Tested: fldigi remote ipc and xmlrpc, fldigi (old version) xmlrpc, adif remote commit 88774fcd12556fb59043805f211be07f7d9dd7c7 Author: OH1KH Date: Wed May 4 10:31:27 2022 +0300 Fixed external database's backups script commit 3f4198f0ce4dfb1d227cd9b06798294ec1a7d457 Author: OH1KH Date: Tue May 3 11:48:35 2022 +0300 fixed adif import and export. TODO: test all adif import/export, lotw/eqsl import/export, remotes: fldigi ipc/xml, adif commit 891674a2346e0f402d301711e32a7dcdba697aef Author: OH1KH Date: Sun May 1 17:35:33 2022 +0300 new conversion now in: fldigixml,adifremote, fldigiipc,lotw and eqsl import. Partilly added also to adif import but this is not finished yet commit 050b35f3e69ea7254c71590874c50d46f7a9f3f6 Author: OH1KH Date: Sat Apr 30 10:01:56 2022 +0300 Ficed naming, created a debug procedure and put in use with fldigi(others still need appending) commit a03c1758851d19a5f7f5fccbf09b5638da583f6f Author: OH1KH Date: Fri Apr 29 13:30:31 2022 +0300 Mode conversion idea works now. creates convert files if they do not exist in ctyfiles folder. Fileas are loaded from Cqrlog start, so user can edit files if needed new mode conversions without doing compile. fxfldigi.pas still has testing lines, must remove todo take conversions in use (adif ex/import, eQSL, Lotw, adif remote, fldigi remote) --- help/h1.html | 43 ++++++- src/dLogUpload.pas | 4 + src/dUtils.lfm | 14 +-- src/dUtils.pas | 270 +++++++++++++++++++++++++++++++++++++++- src/fAdifImport.pas | 99 +++++++-------- src/fCabrilloExport.pas | 2 + src/fDbSqlSel.pas | 30 ++++- src/fEDIExport.pas | 2 + src/fExportProgress.pas | 124 ++---------------- src/fImportProgress.pas | 186 ++++++++++++++------------- src/fLoTWExport.pas | 48 +++---- src/fMain.pas | 3 +- src/fNewQSO.pas | 47 +++---- src/fSOTAExport.pas | 3 + src/fXfldigi.pas | 9 +- src/feQSLUpload.pas | 45 +++---- src/uADIFhash.pas | 1 + src/uVersion.pas | 2 +- 18 files changed, 562 insertions(+), 370 deletions(-) diff --git a/help/h1.html b/help/h1.html index 7c4b567..40c00d6 100644 --- a/help/h1.html +++ b/help/h1.html @@ -320,8 +320,47 @@ Some TRX like ICOM don't have support for this in HamLib. To get mode se all values to 0 (zero).

User definable digital modes can be set up in a separate box. Use comma as a separator, ie. MYMODE1,MYMODE2 etc.
-If user adds digital modes (submode names) exactly as written in this table ADIF.org: Mode_Enumeration ADIF export will place correct mode and submode tags to exported file. - Submode list is copied at 2021-08-25 and may need updating of source code some day in future. +user should add digital modes (submode names) exactly as written in this table ADIF.org: Mode_Enumeration +If mode is missing from NewQSO/mode selection list and not added to User defined digital modes it may prevent ADIF import causing "wrong mode" error. +

+Note:
+Cqrlog uses internally modefied mode name. We call it here CqrMode. CqrMode is created from ADIF mode and submode with conversion table. CqrMode is mainly ADIF submode if it exist, with some exceptions. +
Cqrlog will create four files in ~/.config/cqrlog folder for this use if they do not exist. One is a brief README_modefiles explaining three other files purposes. +

If files exist they are not overwritten keeping possible user changes there. How ever user must do backups by himself if files are edited from original format. +These files apply to all logs created. They are not log based. +

    +
  • submode_mode.txt +
    This file holds submode=mode pairs used to convert incoming mode+submode pair to CqrMode that mainly is the submode. +

    All pairs must be in uppercase format. User can add or delete mode pairs with text editor if definition at +
    ADIF.org: Mode_Enumeration changes. +
    "Self invented" mode names should not be used! Just one mode pair is accepted in one line. +
    The first line is never read (lower case). It just shows the order of submode and mode. +

    This file is used also when qso record is ADIF exported. Then CqrMode is converted back to mode+sumbode tags. +
    +
  • +
  • import_mode.txt +
    This file holds a list of deprecated ADIF submodes that are accepted only for input. They are used in CqrModes but they will never be ADIF exported out from Cqrlog. +

    All lines must be in uppercase format. User can add or delete lines with text editor if definition at +
    ADIF.org: Mode_Enumeration changes. +
    "Self invented" mode names should not be used! Just one mode is accepted in one line. +
    The first line is never read (lower case). It just shows the meaning of then list. +

    This file is used also when qso record is ADIF exported. It prevents submode in list to export and only mode is exported. +
    + +
  • +
  • exception_mode.txt +
    This file holds submode=mode pairs used to convert incoming mode+submode pair to CqrMode when CqrMode can not use ADIF submode directly. +
    For example by ADIF definition mode SSB has submodes USB and LSB. How ever Cqrlog does not use those as CqrMode, but uses only SSB. + Then CqrMode is converted as SSB. How ever after exception the mode can not have it's submode back when exporting ADIF from Cqrlog. +

    This file can also have conversion from rigctld given mode to ADIF mode. For example with IC7300 rigctld shows mode PACKETUSB if rig is set to usb and data mode: +
    then this file can convert PACKETUSB to PKT that is ADIF standard format. +

    All pairs must be in uppercase format. User can add or delete mode pairs with text editor when needed. +
    How ever in case of outgoing modes (outgoing mode is at right side of mode pair) ADIF.org: Mode_Enumeration should be used. +
    "Self invented" mode names should not be used! Just one mode pair is accepted in one line. +
    The first line is never read (lower case). It just shows the order of submode and mode. +
  • +
+

QTH Profiles

diff --git a/src/dLogUpload.pas b/src/dLogUpload.pas index 660385d..06a72f9 100644 --- a/src/dLogUpload.pas +++ b/src/dLogUpload.pas @@ -514,6 +514,10 @@ begin time_on := Q2.FieldByName('time_on').AsString; time_on := copy(time_on,1,2) + copy(time_on,4,2); + //2022-05-05 OH1KH I do not know (I can not test) are mode+submode pairs needed with log uploads + // or is the CqrMode ok here ??????? + //If mode+submode needed then use dmUtils.ModeFromCqr to get mode and submode at this point + // (look sample from fLoTWExport.pas line 453-460) adif := GetAdifValue('QSO_DATE',qsodate)+GetAdifValue('TIME_ON',time_on)+ GetAdifValue('CALL',Q2.FieldByName('callsign').AsString)+ GetAdifValue('BAND',Q2.FieldByName('band').AsString)+ diff --git a/src/dUtils.lfm b/src/dUtils.lfm index beb3064..2b4cc45 100644 --- a/src/dUtils.lfm +++ b/src/dUtils.lfm @@ -1,26 +1,26 @@ object dmUtils: TdmUtils OnCreate = DataModuleCreate + OnDestroy = DataModuleDestroy OldCreateOrder = False Height = 300 HorizontalOffset = 365 VerticalOffset = 366 Width = 400 - PPI = 96 object HelpDatabase: THTMLHelpDatabase BaseURL = 'file:///usr/share/cqrlog/help' AutoRegister = True KeywordPrefix = 'help/' - left = 176 - top = 40 + Left = 176 + Top = 40 end object HelpViewer: THTMLBrowserHelpViewer BrowserParams = '%s' AutoRegister = True - left = 272 - top = 40 + Left = 272 + Top = 40 end object Datasource1: TDataSource - left = 56 - top = 48 + Left = 56 + Top = 48 end end diff --git a/src/dUtils.pas b/src/dUtils.pas index de78870..dc3560e 100644 --- a/src/dUtils.pas +++ b/src/dUtils.pas @@ -88,6 +88,12 @@ const 'NAME_INTL', 'NOTES_INTL', 'QSLMSG_INTL', 'QTH_INTL', 'RIG_INTL', 'SIG_INTL', 'SIG_INFO_INTL'); + c_MODEFILE_DIR = ''; // 'ctyfiles/'; + C_SUBMODE_FILE = 'submode_mode.txt'; + C_IMPORTMODE_FILE = 'import_mode.txt'; + C_EXCEPMODE_FILE = 'exception_mode.txt'; + C_READMEMODE_FILE = 'README_modefiles'; + type { TdmUtils } @@ -97,16 +103,21 @@ type HelpViewer: THTMLBrowserHelpViewer; HelpDatabase: THTMLHelpDatabase; procedure DataModuleCreate(Sender: TObject); + procedure DataModuleDestroy(Sender: TObject); private fTimeOffset: currency; fGrayLineOffset: currency; fQRZSession: string; fHamQTHSession: string; fSysUTC: boolean; - + SubmodeMode: TStringList; + ImportMode : TStringlist; + ExceptMode : TStringlist; procedure LoadRigList(RigCtlBinaryPath : String;RigList : TStringList); procedure LoadRigListCombo(CurrentRigId : String; RigList : TStringList; RigComboBox : TComboBox); + procedure ModeConvListsCreate(SetUp:boolean); + procedure MakeMissingModeFile(num:integer); function nr(ch: char): integer; function GetTagValue(Data, tg: string): string; @@ -116,6 +127,7 @@ type var nick, qth, address, zip, grid, state, county, qsl, iota, waz, itu, ErrMsg: string): boolean; function GetHamQTHInfo(call: string; var nick, qth, address, zip, grid, state, county, qsl, iota, waz, itu, dok, ErrMsg: string): boolean; + public s136: string; s630: string; @@ -152,6 +164,7 @@ type //list of bands, band labels BandFreq : array [0..cMaxBandsCount - 1]of BandVsFreq; + property TimeOffset: currency read fTimeOffset write fTimeOffset; property GrayLineOffset: currency read fGraylineOffset write fGrayLineOffset; property SysUTC: boolean read fSysUTC write fSysUTC; @@ -204,11 +217,12 @@ type procedure LoadRigsToComboBox(CurrentRigId : String; RigCtlBinaryPath : String; RigComboBox : TComboBox); procedure GetShorterCoordinates(latitude,longitude : Currency; var lat, long : String); procedure LoadListOfFiles(Path, Mask : String; ListOfFiles : TStringList); - procedure BandFromDbase; + procedure BandFromDbase; procedure UpdateHelpBrowser; + procedure ModeFromCqr(CqrMode:String;var OutMode,OutSubmode:String;dbg:Boolean); function BandFromArray(tmp:Currency):string; - function MyDefaultBrowser:String; + function MyDefaultBrowser:String; function StrToDateFormat(sDate : String) : TDateTime; function DateToSQLIteDate(date : TDateTime) : String; function GetBandFromFreq(MHz : string): String; @@ -297,6 +311,8 @@ type function LoadVisibleColumnsConfiguration : TColumnVisibleArray; function StdFormatLocator(loc:string):String; function IsHeDx(call:String; CqDir:String = ''):boolean; + function ModeToCqr(InMode,InSubmode:String;dbg:boolean=False):String; + end; @@ -598,7 +614,14 @@ begin USstates[49] := 'WV, West Virginia'; USstates[50] := 'WY, Wyoming'; + ModeConvListsCreate(True); end; + +procedure TdmUtils.DataModuleDestroy(Sender: TObject); +begin + ModeConvListsCreate(False); +end; + procedure TdmUtils.InsertContests(cmbContestName: TComboBox); var ListOfContests : TStringList; @@ -4774,5 +4797,246 @@ begin Writeln('My continent is:', mycont, ' His continent is:', cont,' is DX/CQ for me:',Result); end; end; + +procedure TdmUtils.ModeFromCqr(CqrMode:String;var OutMode,OutSubmode:String;dbg:Boolean); +//encodes Cqrlog's mode to mode and submode pair +//returns empty string to submode if not exist +var + e: integer; + +Begin + if dbg then + Writeln('ModeFromCqr: ',CqrMode); + Cqrmode:=uppercase(CqrMode); //this is for sure + //cqrmode -> ex_mode + e:= ExceptMode.IndexOfName(CqrMode); + if e > -1 then + Begin + OutMode := uppercase(ExceptMode.Values[CqrMode]); + OutSubmode:=''; + if dbg then + begin + Writeln('ex_mode=cqrlogmode line: ',e+1); + Writeln('Cqrlog will export adif as mode: ',OutMode,' submode: ',OutSubmode); + end; + exit; + end; + // cqrmode -> mode+submode + e:= SubmodeMode.IndexOfName(CqrMode); + if e > -1 then + Begin + OutMode := uppercase(SubmodeMode.Values[CqrMode]); + OutSubmode := CqrMode; + if dbg then + Writeln('submode=mode line: ',e+1); + + //is submode import only + e:=ImportMode.IndexOf(CqrMode); + if e > -1 then + begin + if dbg then + Writeln('submode for_import_only line: ',e+1); + OutSubmode :=''; + end; + end + else + //no submodes + Begin + OutMode := CqrMode; + OutSubmode:=''; + end; + if dbg then + Writeln('Cqrlog will export adif as mode: ',OutMode,' submode: ',OutSubmode); +end; +function TdmUtils.ModeToCqr(InMode,InSubmode:String;dbg:boolean=False):String; +//decodes mode and submode pair to mode used by Cqrlog internally +var + e: integer; + +Begin + if dbg then + Writeln('ModeToCqr mode: ',InMode,' submode: ',InSubmode); + InMode:=uppercase(InMode); //this is for sure + InSubmode:=uppercase(InSubmode); + + Result:=InMode; //defaults to InMode + if InSubmode='' then + Begin + if dbg then + writeln('Cqrlog internal mode will be: ',Result); + exit; + end; + + e:= SubmodeMode.IndexOfName(InSubmode); + if (e > -1 ) then //it exist + Begin + if dbg then + Writeln('submode=mode line: ',e+1); + Result:=InSubmode; + end; + + e:= ExceptMode.IndexOfName(Result); + if e > -1 then //it exist + begin + if dbg then + Writeln('ex_mode=cqrlogmode line: ',e+1); + Result:= ExceptMode.ValueFromIndex[e]; + end; + + Result:=uppercase(Result); //this is for sure + if dbg then + writeln('Cqrlog internal mode will be: ',Result); +end; +procedure TdmUtils.ModeConvListsCreate(SetUp:boolean); + +Begin + if not SetUp then + Begin + if assigned(SubmodeMode) then FreeAndNil(SubmodeMode); + if assigned(ImportMode) then FreeAndNil(ImportMode); + if assigned(ExceptMode) then FreeAndNil(ExceptMode); + exit; + end; + + SubmodeMode:= TStringList.Create; + ImportMode := TStringlist.Create; + ExceptMode := TStringlist.Create; + + //if we do not find one of these files we create it + if FileSearch(C_SUBMODE_FILE,dmData.HomeDir+C_MODEFILE_DIR,[])='' then + MakeMissingModeFile(1); + if FileSearch(C_IMPORTMODE_FILE,dmData.HomeDir+C_MODEFILE_DIR,[])='' then + MakeMissingModeFile(2); + if FileSearch(C_EXCEPMODE_FILE,dmData.HomeDir+C_MODEFILE_DIR,[])='' then + MakeMissingModeFile(3); + if FileSearch(C_READMEMODE_FILE,dmData.HomeDir+C_MODEFILE_DIR,[])='' then + MakeMissingModeFile(4); + try + SubmodeMode.LoadFromFile(dmData.HomeDir+C_MODEFILE_DIR+C_SUBMODE_FILE); + ImportMode .LoadFromFile(dmData.HomeDir+C_MODEFILE_DIR+C_IMPORTMODE_FILE); + ExceptMode.LoadFromFile(dmData.HomeDir+C_MODEFILE_DIR+C_EXCEPMODE_FILE); + except + on E : Exception do writeln('Could not load mode conversion files!'); + end; + + if dmData.DebugLevel>=1 then + Begin + Writeln('Loaded mode conversion files:'); + Writeln(' ',SubmodeMode.Strings[0]); + Writeln(' ',ImportMode.Strings[0]); + Writeln(' ',ExceptMode.Strings[0]); + end; + + +end; + + +procedure TdmUtils.MakeMissingModeFile(num:integer); +//the idea not to use const for conversion is that when they are put in files +//later additions and deletions can be done by user without compile +Const + S_file: array [1..168] of string = ( + 'submode=mode','8PSK125=PSK','8PSK125F=PSK','8PSK125FL=PSK','8PSK250=PSK','8PSK250F=PSK','8PSK250FL=PSK','8PSK500=PSK','8PSK500F=PSK','8PSK1000=PSK', + '8PSK1000F=PSK','8PSK1200F=PSK','AMTORFEC=TOR','ASCI=RTTY','CHIP64=CHIP','CHIP128=CHIP','DOM-M=DOMINO','DOM4=DOMINO','DOM5=DOMINO','DOM8=DOMINO', + 'DOM11=DOMINO','DOM16=DOMINO','DOM22=DOMINO','DOM44=DOMINO','DOM88=DOMINO','DOMINOEX=DOMINO','DOMINOF=DOMINO','FMHELL=HELL','FSK31=PSK','FSKHELL=HELL', + 'FSQCALL=MFSK','FST4=MFSK','FST4W=MFSK','FT4=MFSK','GTOR=TOR','HELL80=HELL','HELLX5=HELL','HELLX9=HELL','HFSK=HELL','ISCAT-A=ISCAT', + 'ISCAT-B=ISCAT','JS8=MFSK','JT4A=JT4','JT4B=JT4','JT4C=JT4','JT4D=JT4','JT4E=JT4','JT4F=JT4','JT4G=JT4','JT9-1=JT9', + 'JT9-2=JT9','JT9-5=JT9','JT9-10=JT9','JT9-30=JT9','JT9A=JT9','JT9B=JT9','JT9C=JT9','JT9D=JT9','JT9E=JT9','JT9E=FAST', + 'JT9F=JT9','JT9F=FAST','JT9G=JT9','JT9G=FAST','JT9H=JT9','JT9H=FAST','JT65A=JT65','JT65B=JT65','JT65B2=JT65','JT65C=JT65', + 'JT65C2=JT65','JTMS=MFSK','LSB=SSB','MFSK4=MFSK','MFSK8=MFSK','MFSK11=MFSK','MFSK16=MFSK','MFSK22=MFSK','MFSK31=MFSK','MFSK32=MFSK', + 'MFSK64=MFSK','MFSK64L=MFSK','MFSK128=MFSK','MFSK128L=MFSK','NAVTEX=TOR','OLIVIA 4/125=OLIVIA','OLIVIA 4/250=OLIVIA','OLIVIA 8/250=OLIVIA','OLIVIA 8/500=OLIVIA','OLIVIA 16/500=OLIVIA', + 'OLIVIA 16/1000=OLIVIA','OLIVIA 32/1000=OLIVIA','OPERA-BEACON=OPERA','OPERA-QSO=OPERA','PAC2=PAC','PAC3=PAC','PAC4=PAC','PAX2=PAX','PCW=CW','PSK10=PSK', + 'PSK31=PSK','PSK63=PSK','PSK63F=PSK','PSK63RC10=PSK','PSK63RC20=PSK','PSK63RC32=PSK','PSK63RC4=PSK','PSK63RC5=PSK','PSK125=PSK','PSK125RC10=PSK','PSK125RC12=PSK', + 'PSK125RC16=PSK','PSK125RC4=PSK','PSK125RC5=PSK','PSK250=PSK','PSK250RC2=PSK','PSK250RC3=PSK','PSK250RC5=PSK','PSK250RC6=PSK','PSK250RC7=PSK','PSK500=PSK', + 'PSK500RC2=PSK','PSK500RC3=PSK','PSK500RC4=PSK','PSK800RC2=PSK','PSK1000=PSK','PSK1000RC2=PSK','PSKAM10=PSK','PSKAM31=PSK','PSKAM50=PSK','PSKFEC31=PSK', + 'PSKHELL=HELL','QPSK31=PSK','Q65=MFSK','QPSK63=PSK','QPSK125=PSK','QPSK250=PSK','QPSK500=PSK','QRA64A=QRA64','QRA64B=QRA64','QRA64C=QRA64', + 'QRA64D=QRA64','QRA64E=QRA64','ROS-EME=ROS','ROS-HF=ROS','ROS-MF=ROS','SIM31=PSK','SITORB=TOR','SLOWHELL=HELL','THOR-M=THOR','THOR4=THOR', + 'THOR5=THOR','THOR8=THOR','THOR11=THOR','THOR16=THOR','THOR22=THOR','THOR25X4=THOR','THOR50X1=THOR','THOR50X2=THOR','THOR100=THOR','THRBX=THRB', + 'THRBX1=THRB','THRBX2=THRB','THRBX4=THRB','THROB1=THRB','THROB2=THRB','THROB4=THRB','USB=SSB' + ); + I_file: array [1 .. 41] of string = ( + 'for_import_only','AMTORFEC','ASCI','CHIP64','CHIP128','DOMINOF','FMHELL','FSK31','GTOR','HELL80', + 'HFSK','JT4A','JT4B','JT4C','JT4D','JT4E','JT4F','JT4G','JT65A','JT65B', + 'JT65C','MFSK8','MFSK16','PAC2','PAC3','PAX2','PCW','PSK10','PSK31','PSK63', + 'PSK63F','PSK125','PSKAM10','PSKAM31','PSKAM50','PSKFEC31','PSKHELL','QPSK31','QPSK63','QPSK125', + 'THRBX' + ); + + {Exceptions file: + Cqrlog uses SSB for both USB and LSB + Cqrlog uses RTTY, some programs may export ASCI even when it is import only! + 'PACKET': + these modes come from ICOM rig (IC7300) when DATA is selected with USB,LSB,FM or AM + and checkbox "auto" for mode is selected in NewQSO we put them all to PKT category here + as it is in ADIF standard + } + E_file: array [1 .. 9] of string = ( + 'ex_mode=cqrlogmode', + 'USB=SSB', + 'LSB=SSB', + 'ASCI=RTTY', + 'PACKET=PKT', + 'PKTUSB=PKT', + 'PKTLSB=PKT', + 'PKTFM=PKT', + 'PKTAM=PKT' + ); + R_file: array [1 .. 22] of string = ( + 'Files to modify ADIF mode+submode to fit with Cqrlog.', + 'Cqrlog internally uses submodes as mode. (only one database column -> mode)', + '', + 'These files are manually created and can be changed if needed:', + 'Contents are read to TStringLists at program start.', + '', + 'submode_mode.txt', + ' Submode=Mode', + ' Used en/decoding mode-submode pairs for Cqrlog.', + '', + 'import_mode.txt', + ' Submode list for import only', + ' Used to define deprecated submodes that are used ony for adif input.', + ' These submodes do not export.', + '', + 'exception_mode.txt', + ' mode=cqrlogmode', + ' Exceptions between "true" (sub)modes and internal cqrlog mode', + ' Converts also in export "non adif" modes from rigctld like PACKET -> PKT', + '', + 'Two first files created by https://adif.org/312/ADIF_312_annotated.htm#Mode_Enumeration', + 'informations 2022-04-29,' + ); + var f:TextFile; + + +//-------------------------------------------------------- + procedure CreaFile(Fname:string;items:array of string); + var + i: integer; + itemsmax:integer; + + begin + itemsmax:=length(items); + AssignFile(f,Fname); + try + rewrite(f); + try + for i:= 0 to itemsmax-1 do + Writeln(f, items[i]); + finally + CloseFile(f); + end; + except + on E: EInOutError do + ShowMessage('File handling error occurred. Details: ' + E.ClassName + '/' + E.Message); + end; + end; +//-------------------------------------------------------- +Begin + if num=1 then CreaFile(dmData.HomeDir+C_MODEFILE_DIR+C_SUBMODE_FILE,S_file); + if num=2 then CreaFile(dmData.HomeDir+C_MODEFILE_DIR+C_IMPORTMODE_FILE,I_file); + if num=3 then CreaFile(dmData.HomeDir+C_MODEFILE_DIR+C_EXCEPMODE_FILE,E_file); + if num=4 then CreaFile(dmData.HomeDir+C_MODEFILE_DIR+C_READMEMODE_FILE,R_file); +end; + end. diff --git a/src/fAdifImport.pas b/src/fAdifImport.pas index 8d01b41..0021cc2 100644 --- a/src/fAdifImport.pas +++ b/src/fAdifImport.pas @@ -46,6 +46,7 @@ type TnewQSOEntry=record //represents a new qso entry in the log LOTW_QSL_RCVD:string[l_LOTW_QSL_RCVD]; LOTW_QSL_SENT:string[l_LOTW_QSL_SENT]; MODE:string[l_MODE]; + SUBMODE:string[l_SUBMODE]; //we need this while processing cqrmode MY_GRIDSQUARE:string[l_MY_GRIDSQUARE]; NAME:string[l_NAME]; NOTES:string[l_NOTES]; @@ -140,7 +141,6 @@ type procedure mnueditClick(Sender: TObject); procedure mnuImportClick(Sender: TObject); private - LockSubMode : boolean; //if we replace mode with submode we set lock in case that submode and mode are in opposite order in qso record. LocalDbg : Boolean; AbortImport : boolean; ERR_FILE : String; @@ -296,58 +296,44 @@ function TfrmAdifImport.fillTypeVariableWithTagData(h:longint;var data:string;va h_LOTW_QSL_RCVD :d.LOTW_QSL_RCVD:=TrimDataLen(adifTag,data,l_LOTW_QSL_RCVD); h_LOTW_QSL_SENT :d.LOTW_QSL_SENT:=TrimDataLen(adifTag,data,l_LOTW_QSL_SENT); - // DL7OAP: because MODE-field in cqrlog database does not match completely - // with MODE field of ADIF specification, we have to transfer the - // ADIF MODES/SUBMODES (JS8, FT4, FST4,PKT) to MODE-field in cqrlog database + h_MODE :d.MODE := UpperCase(TrimDataLen(adifTag,data,l_MODE)); + h_SUBMODE :d.SUBMODE := UpperCase(TrimDataLen(adifTag,data,l_SUBMODE)); - //OH1KH: we can put all submodes to mode when importing - - h_MODE : begin - if not LockSubMode then //do not override mode if already set by submode - if data = 'PKT' then d.MODE:='PACKET' - else d.MODE:=UpperCase(TrimDataLen(adifTag,data,l_MODE)); - end; - h_SUBMODE : begin - // Cqrlog does not use USB and LSB (submodes) - // but it is fixed in function saveNewEntryFromADIFinDatabase - d.MODE:=UpperCase(TrimDataLen(adifTag,data,l_MODE)); - LockSubMode:=true; - end; - h_MY_GRIDSQUARE :d.MY_GRIDSQUARE:=dmUtils.StdFormatLocator(data); - h_NAME :d.NAME:=TrimDataLen(adifTag,data,l_NAME); - h_NOTES :d.NOTES:=TrimDataLen(adifTag,data,l_NOTES); - h_PFX :d.PFX:=UpperCase(TrimDataLen(adifTag,data,l_PFX)); - h_QSLMSG :d.QSLMSG:=TrimDataLen(adifTag,data,l_QSLMSG); - h_QSLRDATE :d.QSLRDATE:=TrimDataLen(adifTag,data,l_QSLRDATE); - h_QSLSDATE :d.QSLSDATE:=TrimDataLen(adifTag,data,l_QSLSDATE); - h_QSL_RCVD :d.QSL_RCVD:=TrimDataLen(adifTag,data,l_QSL_RCVD); - h_QSL_SENT :d.QSL_SENT:=TrimDataLen(adifTag,data,l_QSL_SENT); - h_QSL_VIA :d.QSL_VIA:=TrimDataLen(adifTag,data,l_QSL_VIA); - h_QSO_DATE :d.QSO_DATE:=TrimDataLen(adifTag,data,l_QSO_DATE); - h_QTH :d.QTH:=TrimDataLen(adifTag,data,l_QTH); - h_RST_RCVD :d.RST_RCVD:=TrimDataLen(adifTag,data,l_RST_RCVD); - h_RST_SENT :d.RST_SENT:=TrimDataLen(adifTag,data,l_RST_SENT); - h_SRX :d.SRX:=TrimDataLen(adifTag,data,l_SRX); - h_SRX_STRING :d.SRX_STRING:=TrimDataLen(adifTag,data,l_SRX_STRING); - h_STX :d.STX:=TrimDataLen(adifTag,data,l_STX); - h_STX_STRING :d.STX_STRING:=TrimDataLen(adifTag,data,l_STX_STRING); - h_CONTEST_ID :d.CONTEST_ID:=TrimDataLen(adifTag,data,l_CONTEST_ID); - h_DARC_DOK :d.DARC_DOK:=TrimDataLen(adifTag,data,l_DARC_DOK); - h_TIME_OFF :d.TIME_OFF:=copy(data,1,4);//can be HHMMSS but cqrlog uses HHMM both - h_TIME_ON :d.TIME_ON:=copy(data,1,4); //are valid adif forms so no Trim/Err here - h_TX_PWR :d.TX_PWR:=TrimDataLen(adifTag,data,l_TX_PWR); - h_APP_CQRLOG_DXCC :d.APP_CQRLOG_DXCC:=TrimDataLen(adifTag,data,l_APP_CQRLOG_DXCC); - h_APP_CQRLOG_QSLS :d.APP_CQRLOG_QSLS:=TrimDataLen(adifTag,data,l_APP_CQRLOG_QSLS); - h_APP_CQRLOG_PROFILE :d.APP_CQRLOG_PROFILE:=TrimDataLen(adifTag,data,l_APP_CQRLOG_PROFILE); - h_APP_CQRLOG_QSLR :d.APP_CQRLOG_QSLR:=TrimDataLen(adifTag,data,l_APP_CQRLOG_QSLR); - h_APP_CQRLOG_COUNTY :d.APP_CQRLOG_COUNTY:=TrimDataLen(adifTag,data,l_APP_CQRLOG_COUNTY); - h_CQZ :d.CQZ:=TrimDataLen(adifTag,data,l_CQZ); - h_STATE :d.STATE:=UpperCase(TrimDataLen(adifTag,data,l_STATE)); - h_AWARD :d.AWARD:=TrimDataLen(adifTag,data,l_AWARD); - h_PROP_MODE :d.PROP_MODE:=TrimDataLen(adifTag,data,l_PROP_MODE); - h_SAT_NAME :d.SAT_NAME:=TrimDataLen(adifTag,data,l_SAT_NAME); - h_FREQ_RX :d.FREQ_RX:=TrimDataLen(adifTag,data,l_FREQ_RX); - h_OP :d.OP:=TrimDataLen(adifTag,data,l_OP); + h_MY_GRIDSQUARE :d.MY_GRIDSQUARE:=dmUtils.StdFormatLocator(data); + h_NAME :d.NAME:=TrimDataLen(adifTag,data,l_NAME); + h_NOTES :d.NOTES:=TrimDataLen(adifTag,data,l_NOTES); + h_PFX :d.PFX:=UpperCase(TrimDataLen(adifTag,data,l_PFX)); + h_QSLMSG :d.QSLMSG:=TrimDataLen(adifTag,data,l_QSLMSG); + h_QSLRDATE :d.QSLRDATE:=TrimDataLen(adifTag,data,l_QSLRDATE); + h_QSLSDATE :d.QSLSDATE:=TrimDataLen(adifTag,data,l_QSLSDATE); + h_QSL_RCVD :d.QSL_RCVD:=TrimDataLen(adifTag,data,l_QSL_RCVD); + h_QSL_SENT :d.QSL_SENT:=TrimDataLen(adifTag,data,l_QSL_SENT); + h_QSL_VIA :d.QSL_VIA:=TrimDataLen(adifTag,data,l_QSL_VIA); + h_QSO_DATE :d.QSO_DATE:=TrimDataLen(adifTag,data,l_QSO_DATE); + h_QTH :d.QTH:=TrimDataLen(adifTag,data,l_QTH); + h_RST_RCVD :d.RST_RCVD:=TrimDataLen(adifTag,data,l_RST_RCVD); + h_RST_SENT :d.RST_SENT:=TrimDataLen(adifTag,data,l_RST_SENT); + h_SRX :d.SRX:=TrimDataLen(adifTag,data,l_SRX); + h_SRX_STRING :d.SRX_STRING:=TrimDataLen(adifTag,data,l_SRX_STRING); + h_STX :d.STX:=TrimDataLen(adifTag,data,l_STX); + h_STX_STRING :d.STX_STRING:=TrimDataLen(adifTag,data,l_STX_STRING); + h_CONTEST_ID :d.CONTEST_ID:=TrimDataLen(adifTag,data,l_CONTEST_ID); + h_DARC_DOK :d.DARC_DOK:=TrimDataLen(adifTag,data,l_DARC_DOK); + h_TIME_OFF :d.TIME_OFF:=copy(data,1,4);//can be HHMMSS but cqrlog uses HHMM both + h_TIME_ON :d.TIME_ON:=copy(data,1,4); //are valid adif forms so no Trim/Err here + h_TX_PWR :d.TX_PWR:=TrimDataLen(adifTag,data,l_TX_PWR); + h_APP_CQRLOG_DXCC :d.APP_CQRLOG_DXCC:=TrimDataLen(adifTag,data,l_APP_CQRLOG_DXCC); + h_APP_CQRLOG_QSLS :d.APP_CQRLOG_QSLS:=TrimDataLen(adifTag,data,l_APP_CQRLOG_QSLS); + h_APP_CQRLOG_PROFILE :d.APP_CQRLOG_PROFILE:=TrimDataLen(adifTag,data,l_APP_CQRLOG_PROFILE); + h_APP_CQRLOG_QSLR :d.APP_CQRLOG_QSLR:=TrimDataLen(adifTag,data,l_APP_CQRLOG_QSLR); + h_APP_CQRLOG_COUNTY :d.APP_CQRLOG_COUNTY:=TrimDataLen(adifTag,data,l_APP_CQRLOG_COUNTY); + h_CQZ :d.CQZ:=TrimDataLen(adifTag,data,l_CQZ); + h_STATE :d.STATE:=UpperCase(TrimDataLen(adifTag,data,l_STATE)); + h_AWARD :d.AWARD:=TrimDataLen(adifTag,data,l_AWARD); + h_PROP_MODE :d.PROP_MODE:=TrimDataLen(adifTag,data,l_PROP_MODE); + h_SAT_NAME :d.SAT_NAME:=TrimDataLen(adifTag,data,l_SAT_NAME); + h_FREQ_RX :d.FREQ_RX:=TrimDataLen(adifTag,data,l_FREQ_RX); + h_OP :d.OP:=TrimDataLen(adifTag,data,l_OP); else begin { writeln('Unnamed...>',pom,'<');fillTypeVariableWithTagData:=false;exit;} @@ -396,9 +382,11 @@ begin if (not dmUtils.IsLocOK(d.MY_GRIDSQUARE)) or chkOverrideLocator.Checked then d.MY_GRIDSQUARE := FMyLoc; d.CALL := UpperCase(d.CALL); - if (d.MODE = 'USB') or (d.MODE ='LSB') then - d.MODE := 'SSB'; - if (d.FREQ = '') or (d.FREQ = '0') then + + //convert mode and submode to cqrmode here + d.MODE:=dmUtils.ModeToCqr(d.MODE,d.SUBMODE,LocalDbg); + + if (d.FREQ = '') or (d.FREQ = '0') then d.FREQ := dmUtils.FreqFromBand(d.BAND,d.MODE); d.QSO_DATE := dmUtils.ADIFDateToDate(d.QSO_DATE); @@ -837,7 +825,6 @@ begin WriteWrongADIF(tmp,'Imported with shrink(s):'+#10+CutErrText); CutErrText:=''; tmp:=''; - LockSubMode :=false; end; fillTypeVariableWithTagData(h,data,D,adifTag); end; diff --git a/src/fCabrilloExport.pas b/src/fCabrilloExport.pas index ee68e9d..61152cf 100644 --- a/src/fCabrilloExport.pas +++ b/src/fCabrilloExport.pas @@ -208,6 +208,8 @@ begin end; function TfrmCabrilloExport.CabrilloMode(mode: string): String; +//2022-05-05 OH1KH It seems that Cabrilllo mode can be CqrMode (mainly CW,SSB,AM,FM,RTTY)(I.E. no mode+submode pairs needed) +//otherwise use dmUtils.ModeFromCqr to get mode and submode at this function begin Result := ''; case mode of diff --git a/src/fDbSqlSel.pas b/src/fDbSqlSel.pas index 3609d62..a98292c 100644 --- a/src/fDbSqlSel.pas +++ b/src/fDbSqlSel.pas @@ -167,14 +167,34 @@ begin rewrite(f); Writeln(f, '#!/bin/bash'); Writeln(f); - Writeln(f, 'echo -e "\nCreating backup of all CQRLOG logs in database to /tmp/allcqrlogs.sql\n"'); + Writeln(f, 'stamp=$(date +_%Y%m%d-%H%M)'); + Writeln(f, 'echo -e "\nStarted$stamp"'); + Writeln(f, 'echo -e "Creating common backup of all CQRLOG logs in database to /tmp/allcqrlogs$stamp.sql"'); Writeln(f, '$(mysql -u' + user + ' -p' + pass + ' -B -N -h' + ip + ' -P' + port + - ' -e " show databases like ' + #$27 + 'cqr%' + #$27 + '" |\'); + ' -e " show databases like ' + #$27 + 'cqr%' + #$27 + '" |\'); Writeln(f, 'xargs echo -n mysqldump -q -h' + ip + ' -P' + port + ' -u' + - user + ' -p' + pass + ' --databases) > /tmp/allcqrlogs.sql'); - Writeln(f, 'echo -e "Done!\nCopy backup file to your safe place.\nIt will be erased from /tmp at next Linux start\n\nTo restore all CQRLOG logs use command:\n"'); + user + ' -p' + pass + ' --databases) > /tmp/allcqrlogs$stamp.sql'); + + Writeln(f, 'echo -e "Creating separate backups of each CQRLOG logXXX in database to /tmp/cqrlogXXX$stamp.sql(s)\n"'); + Writeln(f, 'mysql -u' + user + ' -p' + pass + ' -B -N -h' + ip + ' -P' + port + + ' -e " show databases like ' + #$27 + 'cqr%' + #$27 + '" |\'); + Writeln(f, 'xargs -d\ | while read line; do if [[ $line != "" ]];then\'); + Writeln(f, ' echo "mysqldump -q -h' + ip + ' -P' + port + ' -u' + + user + ' -p' + pass + ' $line > /tmp/$line$stamp.sql";fi;done > /tmp/sepsql.sh'); + Writeln(f, 'chmod a+x /tmp/sepsql.sh'); + Writeln(f, '/tmp/sepsql.sh'); + Writeln(f, 'rm /tmp/sepsql.sh'); + + + Writeln(f, 'echo -e "\nDone!\nCopy backup files to your safe place.\n'+ + 'They will be erased from /tmp at next Linux start\n\n"'); + Writeln(f, 'echo "To restore all CQRLOG logs use command:"'); + Writeln(f, 'echo -e "mysql -h' + ip + ' -P' + port + ' -u' + user + ' -p' + pass + + ' < /tmp/allcqrlogs$stamp.sql\n\n"'); + Writeln(f, 'echo "To restore single a log use command:"'); Writeln(f, 'echo "mysql -h' + ip + ' -P' + port + ' -u' + user + ' -p' + pass + - ' < /tmp/allcqrlogs.sql"'); + ' cqrlog001 < /tmp/cqrlog001$stamp.sql"'); + Writeln(f, 'echo -e "\nBe sure that both log numbers used in line are equal"'); closeFile(f); dmUtils.ExecuteCommand('chmod a+rwx ' + UsrHome + 'backup_all_cqr.sh'); end; diff --git a/src/fEDIExport.pas b/src/fEDIExport.pas index 1fd0b7e..2d5ebbb 100644 --- a/src/fEDIExport.pas +++ b/src/fEDIExport.pas @@ -102,6 +102,8 @@ begin end; function TfrmEDIExport.EdiMode(mode: string): String; +//2022-05-05 OH1KH It seems that EDI mode can be CqrMode (I.E. no mode+submode pairs needed) +//otherwise use dmUtils.ModeFromCqr to get mode and submode at this point begin Result := '0'; case mode of diff --git a/src/fExportProgress.pas b/src/fExportProgress.pas index 4af4fcd..4ecc129 100644 --- a/src/fExportProgress.pas +++ b/src/fExportProgress.pas @@ -188,7 +188,10 @@ var srx, stx_string, srx_string, contestname, Darc_Dok : String); var - station_callsign : String; + station_callsign : String; + OutMode, + OutSubmode :String; + begin station_callsign := cqrini.ReadString('Station', 'Call', ''); leng := 0; @@ -219,120 +222,11 @@ var if ExCall then SaveTag(dmUtils.StringToADIF(''+Mode;SaveTag(tmp,leng);end; - 'PCW' : begin tmp := 'CW'+Mode;SaveTag(tmp,leng);end; - 'DOM-M','DOM4','DOM5', - 'DOM8','DOM11','DOM16', - 'DOM22','DOM44','DOM88', - 'DOMINOEX','DOMINOF' : begin tmp := 'DOMINO'+Mode;SaveTag(tmp,leng);end; - 'FELDHELL', //this is non standard that fldigi uses - 'FMHELL','FSKHELL', - 'HELL80','HELLX5', - 'HELLX9','HFSK', - 'PSKHELL','SLOWHELL' : begin tmp := 'HELL'+Mode;SaveTag(tmp,leng);end; - 'ISCAT-A','ISCAT-B' : begin tmp := 'ISCAT'+Mode;SaveTag(tmp,leng);end; - 'JT4A','JT4B','JT4C', - 'JT4D','JT4E','JT4F', - 'JT4G' : begin tmp := 'JT4'+Mode;SaveTag(tmp,leng);end; - 'JT9-1','JT9-2','JT9-5', - 'JT9-10','JT9-30', - 'JT9A','JT9B','JT9C', - 'JT9D','JT9E','JT9E FAST', - 'JT9F','JT9F FAST','JT9G', - 'JT9G FAST','JT9H', - 'JT9H FAST' : begin tmp := 'JT9'+Mode;SaveTag(tmp,leng);end; - 'FSQCALL','FST4','FST4W', - 'FT4','JS8','JTMS','MFSK4', - 'MFSK8','MFSK11','MFSK16', - 'MFSK22','MFSK31','MFSK32', - 'MFSK64','MFSK64L', - 'MFSK128' : begin tmp := 'MFSK'+Mode;SaveTag(tmp,leng);end; - //OLIVIA is exception #1 - 'OPERA-BEACON', - 'OPERA-QSO' : begin tmp := 'OPERA'+Mode;SaveTag(tmp,leng);end; - 'PAC2','PAC3','PAC4' : begin tmp := 'PAC'+Mode;SaveTag(tmp,leng);end; - 'PAX2' : begin tmp := 'PAX'+Mode;SaveTag(tmp,leng);end; - '8PSK125','8PSK125F', - '8PSK125FL','8PSK250', - '8PSK250F','8PSK250FL', - '8PSK500','8PSK500F', - '8PSK1000','8PSK1000F', - '8PSK1200F','FSK31','PSK10', - 'PSK31','PSK63','PSK63F', - 'PSK63RC4','PSK63RC5', - 'PSK63RC10','PSK63RC20', - 'PSK63RC32','PSK125', - 'PSK125C12','PSK125R', - 'PSK125RC10','PSK125RC12', - 'PSK125RC16','PSK125RC4', - 'PSK125RC5','PSK250', - 'PSK250C6','PSK250R', - 'PSK250RC2','PSK250RC3', - 'PSK250RC5','PSK250RC6', - 'PSK250RC7','PSK500', - 'PSK500C2','PSK500C4', - 'PSK500R','PSK500RC2', - 'PSK500RC3','PSK500RC4', - 'PSK800C2','PSK800RC2', - 'PSK1000','PSK1000C2', - 'PSK1000R','PSK1000RC2', - 'PSKAM10','PSKAM31', - 'PSKAM50','PSKFEC31', - 'QPSK31','QPSK63', - 'QPSK125','QPSK250', - 'QPSK500','SIM31' : begin tmp := 'PSK'+Mode;SaveTag(tmp,leng);end; - 'QRA64A','QRA64B','QRA64C', - 'QRA64D','QRA64E' : begin tmp := 'QRA64'+Mode;SaveTag(tmp,leng);end; - 'ROS-EME','ROS-HF', - 'ROS-MF' : begin tmp := 'ROS'+Mode;SaveTag(tmp,leng);end; - 'ASCI','ASCII' : begin tmp := 'RTTY'+Mode;SaveTag(tmp,leng);end; - 'LSB','USB' : begin tmp := 'SSB'+Mode;SaveTag(tmp,leng);end; - 'THOR-M','THOR4','THOR5', - 'THOR8','THOR11','THOR16', - 'THOR22','THOR25X4', - 'THOR50X1','THOR50X2', - 'THOR100' : begin tmp := 'THOR'+Mode;SaveTag(tmp,leng);end; - 'THRBX','THRBX1','THRBX2', - 'THRBX4','THROB1','THROB2', - 'THROB4' : begin tmp := 'THRB'+Mode;SaveTag(tmp,leng);end; - 'AMTORFEC','GTOR','NAVTEX', - 'SITORB' : begin tmp := 'TOR'+Mode;SaveTag(tmp,leng);end; - - else begin - //exceptions follow - if pos('OLIVIA',mode)=1 then - //fldigi marks them with "-" that is against standard " " - //also there are more BW definitions than standard: will pass them all - begin - mode := StringReplace(mode,'-',' ',[rfReplaceAll]); - tmp := 'OLIVIA'+Mode;SaveTag(tmp,leng); - end - else - //exceptions end - Begin - tmp := '=1); + SaveTag(dmUtils.StringToADIF(''' then + SaveTag(dmUtils.StringToADIF('',uppercase(Buf))=1; - //execption is SSB. Cqrlog does not use USB and LSB (submodes) - if (mode='USB') or (mode='LSB') then - mode:='SSB'; + //store original modes + modeorig:=uppercase(mode); + submodeorig:=uppercase(submode); + //after this line mode will be changed to Cqrmode. submodeorig & modeorig has orignal ones stored for possible error reports + mode :=dmUtils.ModeToCqr(mode,submode,LocalDbg); end; -procedure TfrmImportProgress.WriteErrorRecord(f:char;call,band,mode,qsodate,time_on,qslr,qslrdate, +procedure TfrmImportProgress.WriteErrorRecord(f:char;call,band,modeorig,submodeorig,qsodate,time_on,qslr,qslrdate, cqz,ituz,iota,grid,state,county,qsorecord:string;var s:Tstringlist); var l, @@ -649,7 +649,8 @@ Begin +'QSO NOT FOUND in log'+LineEnding +'Call: '+call+LineEnding +'Band: '+band+LineEnding - +'Mode: '+mode+LineEnding + +'Mode: '+modeorig+LineEnding + +'Submode: '+submodeorig+lineEnding +'QSO_date: '+qsodate+LineEnding +'Time_on: '+time_on+LineEnding; if f='L' then @@ -685,21 +686,22 @@ var f : TextFile; PosEOH : Word; PosEOR : Word; - qsorecord: String; - call : String; - band : String; - mode : String; - //submode not needed with lotw - submode : String; - qsodate : String; - time_on : String; - qslr : String; - qslrdate : String; - cqz : String; - ituz : String; - iota : String; - grid : String; - state : String; + qsorecord, + call, + band, + mode, + modeorig, + submode, + submodeorig, + qsodate, + time_on, + qslr, + qslrdate, + cqz, + ituz, + iota, + grid, + state, county : String; qso_in_log : Boolean = False; @@ -753,7 +755,9 @@ begin call := ''; band := ''; mode := ''; + modeorig := ''; submode := ''; + submodeorig := ''; qsodate := ''; time_on := ''; qslr := ''; @@ -768,9 +772,9 @@ begin while not ((PosEOR > 0) or eof(f)) do //read all records begin qso_in_log := False; - CommonImport(PosEOR,f,call,band,mode,submode,qsodate,time_on,qslr, + CommonImport(PosEOR,f,call,band,modeorig,mode,submodeorig,submode,qsodate,time_on,qslr, qslrdate,cqz,ituz,iota,grid,state,county,qsorecord); - + //for now on the mode is converted Cqrmode if PosEOR > 0 then begin if LocalDbg then @@ -779,7 +783,9 @@ begin Writeln('Record Number: ',IntToStr(qsln)); Writeln('Call: ',call); Writeln('Band: ',band); - Writeln('Mode: ',mode); + Writeln('Mode: ',modeorig); + Writeln('Submode: ',submodeorig); + Writeln('Cqrmode: ',mode); Writeln('QSO_date: ',qsodate); Writeln('Time_on: ',time_on); Writeln('QSLR: ',qslr); @@ -796,15 +802,19 @@ begin qsodate := dmUtils.ADIFDateToDate(qsodate); qslrdate := dmUtils.ADIFDateToDate(qslrdate); - mode := UpperCase(mode); - if mode='JT65' then - mode := 'JT65A'; - dmData.Q.Close; + //we compare Cqrmode in log to mode and submode received and Cqrmode created. + //If any of these is ok, qso is ok by mode. + //this makes backward compatible to old cqrlog loggings. + //Actually qso is ok even without mode check if other items fit! dmData.Q.SQL.Text := 'select time_on,lotw_qslr,waz,itu,iota,loc,state,county,id_cqrlog_main from cqrlog_main ' + 'where (qsodate ='+QuotedStr(qsodate)+') '+ 'and (band = ' + QuotedStr(band) + ')'+ -// 'and (mode = ' + QuotedStr(mode) + ') and (band = ' + QuotedStr(band) + ')'+ + 'and ('+ + '(mode = ' + QuotedStr(mode) +') or '+ + '(mode = ' + QuotedStr(modeorig)+') or '+ + '(mode = ' + QuotedStr(submodeorig)+') '+ + ')' + 'and (callsign = ' + QuotedStr(call) + ')'; if LocalDbg then Writeln(dmData.Q.SQL.Text); //if dmData.trQ.Active then dmData.trQ.Rollback; @@ -872,7 +882,7 @@ begin end; if not qso_in_log then begin - WriteErrorRecord('L',call,band,mode,qsodate,time_on,qslr,qslrdate,cqz,ituz,iota,grid,state,county,qsorecord,l); + WriteErrorRecord('L',call,band,modeorig,submodeorig,qsodate,time_on,qslr,qslrdate,cqz,ituz,iota,grid,state,county,qsorecord,l); inc(ErrorCount) end end @@ -1019,45 +1029,47 @@ end; procedure TfrmImportProgress.ImporteQSLAdif; var - num : Word = 1; - size : Word; - sSize : String; - a : String; - orig : String; f : TextFile; - PosEOH : Word; + num : Word = 1; + size, + PosEOH, PosEOR : Word; - qsorecord: String; - call : String; - band : String; - mode : String; - submode : String; - qsodate : String; - time_on : String; - qslr : String; - qslrdate : String; - cqz : String; - ituz : String; - iota : String; - grid : String; - state : String; - county : String; - Buf : String; + sSize, + a, + orig, + qsorecord, + call, + band, + mode, + modeorig, + submode, + submodeorig, + qsodate, + time_on, + qslr, + qslrdate, + cqz, + ituz, + iota, + grid, + state, + county, + Buf : String; - PosCall : Word; - PosBand : Word; - PosMode : Word; - PosSubmode : Word; - PosQsoDate : Word; - PosTime_on : Word; + PosCall, + PosBand, + PosMode, + PosSubmode, + PosQsoDate, + PosTime_on, PosQslr : Word; qso_in_log : Boolean = False; ErrorCount : Word = 0; l : TStringList; - t_eQSL : TDateTime; - t_eQSL_min : TDateTime; - t_eQSL_max : TDateTime; + t_eQSL, + t_eQSL_min, + t_eQSL_max, t_log : TDateTime; begin @@ -1099,7 +1111,10 @@ begin begin call := ''; band := ''; + modeorig := ''; mode := ''; + submodeorig + := ''; submode := ''; qsodate := ''; time_on := ''; @@ -1119,9 +1134,9 @@ begin while not ((PosEOR > 0) or eof(f)) do begin qso_in_log := False; - CommonImport(PosEOR,f,call,band,mode,submode,qsodate,time_on,qslr, + CommonImport(PosEOR,f,call,band,modeorig,mode,submodeorig,submode,qsodate,time_on,qslr, qslrdate,cqz,ituz,iota,grid,state,county,qsorecord); - + //for now on the mode is converted Cqrmode if PosEOR > 0 then begin if LocalDbg then @@ -1129,8 +1144,9 @@ begin Writeln('------------------------------------------------'); Writeln('Call: ',call); Writeln('Band: ',band); - Writeln('Mode: ',mode); - Writeln('Submode: ',submode); + Writeln('Mode: ',modeorig); + Writeln('Submode: ',submodeorig); + Writeln('CqrMode: ',mode); Writeln('QSO_date: ',qsodate); Writeln('Time_on: ',time_on); Writeln('QSLR: ',qslr); @@ -1140,22 +1156,20 @@ begin dmData.Q.Close; - if (mode='JT65') then //since implementing submodes below, this can most probably be removed - begin - dmData.Q.SQL.Text := 'select id_cqrlog_main,eqsl_qsl_rcvd,time_on from cqrlog_main ' + + //we compare Cqrmode in log to mode and submode received and Cqrmode created. + //If any of these is ok, qso is ok by mode. + //this makes backward compatible to old cqrlog loggings. + //Actually qso is ok even without mode check if other items fit! + dmData.Q.SQL.Text := 'select id_cqrlog_main,eqsl_qsl_rcvd,time_on from cqrlog_main ' + 'where (qsodate ='+QuotedStr(qsodate)+') '+ - 'and ((mode = ' + QuotedStr('JT65') + ') or (mode='+QuotedStr('JT65A')+') '+ - 'or (mode='+QuotedStr('JT65B')+') or (mode='+QuotedStr('JT65C')+')) '+ + 'and ('+ + '(mode = ' + QuotedStr(mode) +') or '+ + '(mode = ' + QuotedStr(modeorig)+') or '+ + '(mode = ' + QuotedStr(submodeorig)+') '+ + ')' + 'and (band = ' + QuotedStr(band) + ') '+ - 'and (callsign = ' + QuotedStr(call) + ')' - end - else begin - dmData.Q.SQL.Text := 'select id_cqrlog_main,eqsl_qsl_rcvd,time_on from cqrlog_main ' + - 'where (qsodate ='+QuotedStr(qsodate)+') '+ - 'and ((mode = ' + QuotedStr(mode) + ') or (mode = ' + QuotedStr(submode) + ')) '+ - 'and (band = ' + QuotedStr(band) + ') '+ - 'and (callsign = ' + QuotedStr(call) + ')' - end; + 'and (callsign = ' + QuotedStr(call) + ')'; + if LocalDbg then Writeln(dmData.Q.SQL.Text); //if dmData.trQ.Active then dmData.trQ.Rollback; //dmData.trQ.StartTransaction; @@ -1206,7 +1220,7 @@ begin end; if not qso_in_log then begin - WriteErrorRecord('E',call,band,mode,qsodate,time_on,qslr,qslrdate,cqz,ituz,iota,grid,state,county,qsorecord,l); + WriteErrorRecord('E',call,band,modeorig,submodeorig,qsodate,time_on,qslr,qslrdate,cqz,ituz,iota,grid,state,county,qsorecord,l); inc(ErrorCount) end end diff --git a/src/fLoTWExport.pas b/src/fLoTWExport.pas index f82cac7..8218137 100644 --- a/src/fLoTWExport.pas +++ b/src/fLoTWExport.pas @@ -365,10 +365,12 @@ end; function TfrmLoTWExport.ExportToAdif : Word; var - f : TextFile; - tmp : String = ''; - nr : Integer = 1; - date : String; + f : TextFile; + tmp : String = ''; + nr : Integer = 1; + date, + ModeOut, + SubmodeOut: String; begin if FileExists(FileName) then DeleteFile(FileName); @@ -447,35 +449,15 @@ begin tmp := dmUtils.StringToADIF('= 1); + tmp := dmUtils.StringToADIF(''' then + Begin + tmp := dmUtils.StringToADIF('= 1 then + WriteLn(dmData.Q.SQL.Text); dmData.trQ.StartTransaction; dmData.Q.ExecSQL; dmData.trQ.Commit diff --git a/src/fNewQSO.pas b/src/fNewQSO.pas index 001fc06..e988f92 100644 --- a/src/fNewQSO.pas +++ b/src/fNewQSO.pas @@ -1928,6 +1928,7 @@ var Mo :TStringList; mhz, mode, + submode, Mask, data : String; begin @@ -2026,12 +2027,12 @@ begin //first set mode by mode, then if submode exist replace mode with it. //Here no problem with SSB/USB/LSB combination - cmbMode.Text := logged.ValueFromIndex[logged.IndexOfName('mode')]; + mode := logged.ValueFromIndex[logged.IndexOfName('mode')]; if logged.IndexOfName('submode')> -1 then - Begin - mode := logged.ValueFromIndex[logged.IndexOfName('submode')]; - if mode<>'' then cmbMode.Text := mode; - end; + submode := logged.ValueFromIndex[logged.IndexOfName('submode')] + else + submode:=''; + cmbMode.Text:=dmUtils.ModeToCqr(mode,submode,dmData.DebugLevel>=1); //set frquency mhz := logged.ValueFromIndex[logged.IndexOfName('mhz')]; @@ -2045,10 +2046,7 @@ begin edtMyRST.Text := logged.ValueFromIndex[logged.IndexOfName('rx')]; //then override with possible defaults for frequency, mode and RST from Cqrlog settings - //Buggy Lazarus GUI creates under this one extra "end;" because of "try/finally/end" above. - //Remove it! - - case cqrini.ReadInteger('fldigi','freq',0) of + case cqrini.ReadInteger('fldigi','freq',0) of 0 : if frmTRXControl.GetModeFreqNewQSO(mode,mhz) then cmbFreq.Text := mhz; 2 : cmbFreq.Text := cqrini.ReadString('fldigi','deffreq','3.600') end; @@ -2075,15 +2073,14 @@ end; procedure TfrmNewQSO.tmrADIFTimer(Sender: TObject); var Buf, buf2, - prik,data :string; - chkDuplicates, - submodeExist :boolean; + prik,data :string; + chkDuplicates :boolean; i :longint; a,b,l :integer; fixed :Boolean; + mode,submode :string; begin - fixed:=false; tmrADIF.Enabled:=false; chkDuplicates:=false; @@ -2151,10 +2148,11 @@ begin if pos(' 0 then Begin if dmData.DebugLevel>=1 then writeln('Handle qso record: ',Buf); + mode:=''; + submode:=''; //this is fake as call info(qslmgr) needs date. We use current date if call tag comes before qso_date tag //qso_date will then replace this edtDate.Text := FormatDateTime('YYYY-MM-DD',now()); - submodeExist:=false; repeat begin if frmAdifImport.getNextAdifTag(Buf,prik,data) then @@ -2176,14 +2174,8 @@ begin if pos(data,edtGrid.Text)=0 then //if qso loc does not fit to QRZ loc , or qrz loc is empty edtGrid.Text := data; //replace qrz loc, otherwise keep it end; - 'MODE' : if not submodeExist - then cmbMode.Text := uppercase(data); - //now this overrides MODE, if exists - 'SUBMODE' : Begin - //we need lock in case submode found before mode tag - submodeExist:=true; - cmbMode.Text := uppercase(data); - end; + 'MODE' : mode := uppercase(data); + 'SUBMODE' : submode := uppercase(data); 'FREQ' : cmbFreq.Text := data; 'FREQ_RX' : edtRXFreq.Text := data; 'RST_SENT' : edtHisRST.Text := data; @@ -2221,9 +2213,10 @@ begin end; //case end; //repeat until pos('',uppercase(Buf))=1; - //execption is SSB. Cqrlog does not use USB and LSB (submodes) - if (cmbMode.Text ='USB') or (cmbMode.Text='LSB') then - cmbMode.Text:='SSB'; + + //set the final Cqrlmode + cmbMode.Text:=dmUtils.ModeToCqr(mode,submode,dmData.DebugLevel>=1 ); + SaveRemote; //these do not reset in qso save, so they must be cleared here in case there was @@ -7551,8 +7544,8 @@ begin cbOffline.Enabled := True; btnSave.Enabled := True; edtCall.SetFocus; - - + //clear TMPQSO mode on close. Otherwise it shows up on next remote mode (procedure ClearAll makes it) + cqrini.WriteString('TMPQSO','Mode',''); end; procedure TfrmNewQSO.SaveRemote; Begin diff --git a/src/fSOTAExport.pas b/src/fSOTAExport.pas index 4f5b361..d12ee4d 100644 --- a/src/fSOTAExport.pas +++ b/src/fSOTAExport.pas @@ -199,7 +199,10 @@ begin dmUtils.DateInSOTAFormat(dmData.Q.FieldByName('qsodate').AsDateTime)+',', StringReplace(dmData.Q.FieldByName('time_on').AsString,':','',[rfReplaceAll, rfIgnoreCase])+',', FormatFloat('0.00;;',dmData.Q.FieldByName('freq').AsFloat),'MHz,', + //2022-05-05 OH1KH It seems that SOTA mode can be CqrMode (mainly CW,SSB,FM,AM)(I.E. no mode+submode pairs needed) + //otherwise use dmUtils.ModeFromCqr to get mode and submode at this point dmData.Q.FieldByName('mode').AsString,',', + dmData.Q.FieldByName('callsign').AsString,',', //his callsign HisSota+',', //his summit note //comments diff --git a/src/fXfldigi.pas b/src/fXfldigi.pas index 5f7aebe..e9fe653 100644 --- a/src/fXfldigi.pas +++ b/src/fXfldigi.pas @@ -237,6 +237,7 @@ var Drop :integer; tmp :extended; + begin frmNewQSO.tmrFldigi.Enabled := false; SockOK := true; @@ -281,10 +282,12 @@ begin mode:='';submode:=''; if SockOK then SockOK := PollFldigi('modem.get_mode',mode); if SockOK then SockOK := PollFldigi('modem.get_submode',submode); - if mode='' then //old version of fldigi, make different query + if mode='' then //old version of fldigi get_mode not supported, make different query + Begin if SockOK then SockOK := PollFldigi('modem.get_name',mode); - //cqrlog saves submode as mode - if submode<>'' then mode := submode; + end + else + mode:=dmUtils.ModeToCqr(mode,submode,dmData.DebugLevel>=1 ); end; 2 : begin mode := cqrini.ReadString('fldigi','defmode','RTTY'); diff --git a/src/feQSLUpload.pas b/src/feQSLUpload.pas index 724ea4d..ab3d4d2 100644 --- a/src/feQSLUpload.pas +++ b/src/feQSLUpload.pas @@ -69,9 +69,12 @@ end; function TfrmeQSLUpload.ExportData(const FileName : String) : Boolean; var - nr : integer = 0; - tmp : String = ''; - f : TextFile; + nr : integer = 0; + tmp : String = ''; + ModeOut, + SubmodeOut : String; + f : TextFile; + begin QSOCount := 0; Result := True; @@ -132,34 +135,14 @@ begin tmp := dmUtils.StringToADIF('= 1); + tmp := dmUtils.StringToADIF(''' then + Begin + tmp := dmUtils.StringToADIF(' Date: Tue, 10 May 2022 13:41:20 +0300 Subject: [PATCH 2/2] Fix for adif headers Added one linefeed before first line of adif header. This makes linux command 'file' to detect adi files as text instead of music file. --- src/fAdifImport.pas | 1 + src/fExportProgress.pas | 1 + src/fLoTWExport.pas | 1 + src/feQSLUpload.pas | 1 + 4 files changed, 4 insertions(+) diff --git a/src/fAdifImport.pas b/src/fAdifImport.pas index 8d01b41..badbc9a 100644 --- a/src/fAdifImport.pas +++ b/src/fAdifImport.pas @@ -1047,6 +1047,7 @@ begin else begin AssignFile(f,dmData.UsrHomeDir + ERR_FILE); Rewrite(f); + Writeln(f); Writeln(f,'ADIF export from CQRLOG for Linux version ' + dmData.VersionString); Writeln(f,'Copyright (C) ',YearOf(now),' by Petr, OK2CQR and Martin, OK1RR'); Writeln(f,'Internet: http://www.cqrlog.com'); diff --git a/src/fExportProgress.pas b/src/fExportProgress.pas index 4af4fcd..da91a40 100644 --- a/src/fExportProgress.pas +++ b/src/fExportProgress.pas @@ -547,6 +547,7 @@ begin //TfrmExportProgress AssignFile(f, FileName); Rewrite(f); + Writeln(f); Writeln(f, 'ADIF export from CQRLOG for Linux version '+dmData.VersionString); Writeln(f, 'Copyright (C) ',YearOf(now),' by Petr, OK2CQR and Martin, OK1RR'); Writeln(f); diff --git a/src/fLoTWExport.pas b/src/fLoTWExport.pas index f82cac7..6dee9aa 100644 --- a/src/fLoTWExport.pas +++ b/src/fLoTWExport.pas @@ -385,6 +385,7 @@ begin end; date := FormatDateTime('yyyy-mm-dd',now); + Writeln(f); Writeln(f, '3.1.0'); Writeln(f, '',FormatDateTime('YYYYMMDD hhmmss',dmUtils.GetDateTime(0))); Writeln(f, 'ADIF export from CQRLOG for Linux version '+dmData.VersionString); diff --git a/src/feQSLUpload.pas b/src/feQSLUpload.pas index 724ea4d..684dfe6 100644 --- a/src/feQSLUpload.pas +++ b/src/feQSLUpload.pas @@ -104,6 +104,7 @@ begin AssignFile(f,FileName); try try Rewrite(f); + Writeln(f); Writeln(f, 'ADIF export from CQRLOG for Linux version '+dmData.VersionString); Writeln(f, 'Copyright (C) ',YearOf(now),' by Petr, OK2CQR and Martin, OK1RR'); Writeln(f);