not1mm 24.6.1__py3-none-any.whl → 24.7.13__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- not1mm/__main__.py +27 -24
- not1mm/data/MASTER.SCP +1556 -1049
- not1mm/data/configuration.ui +34 -34
- not1mm/data/cty.json +1 -1
- not1mm/data/main.ui +94 -94
- not1mm/data/settings.ui +5 -5
- not1mm/lib/cat_interface.py +20 -0
- not1mm/lib/ham_utility.py +1 -1
- not1mm/lib/n1mm.py +23 -0
- not1mm/lib/version.py +1 -1
- not1mm/plugins/k1usn_sst.py +343 -0
- not1mm/plugins/phone_weekly_test.py +1 -1
- {not1mm-24.6.1.dist-info → not1mm-24.7.13.dist-info}/METADATA +73 -27
- {not1mm-24.6.1.dist-info → not1mm-24.7.13.dist-info}/RECORD +18 -18
- {not1mm-24.6.1.dist-info → not1mm-24.7.13.dist-info}/WHEEL +1 -1
- {not1mm-24.6.1.dist-info → not1mm-24.7.13.dist-info}/LICENSE +0 -0
- {not1mm-24.6.1.dist-info → not1mm-24.7.13.dist-info}/entry_points.txt +0 -0
- {not1mm-24.6.1.dist-info → not1mm-24.7.13.dist-info}/top_level.txt +0 -0
not1mm/data/settings.ui
CHANGED
@@ -1255,7 +1255,7 @@
|
|
1255
1255
|
</palette>
|
1256
1256
|
</property>
|
1257
1257
|
<property name="focusPolicy">
|
1258
|
-
<enum>Qt::StrongFocus</enum>
|
1258
|
+
<enum>Qt::FocusPolicy::StrongFocus</enum>
|
1259
1259
|
</property>
|
1260
1260
|
<property name="accessibleName">
|
1261
1261
|
<string>c q zone</string>
|
@@ -1374,7 +1374,7 @@
|
|
1374
1374
|
<item>
|
1375
1375
|
<spacer name="horizontalSpacer_2">
|
1376
1376
|
<property name="orientation">
|
1377
|
-
<enum>Qt::Horizontal</enum>
|
1377
|
+
<enum>Qt::Orientation::Horizontal</enum>
|
1378
1378
|
</property>
|
1379
1379
|
<property name="sizeHint" stdset="0">
|
1380
1380
|
<size>
|
@@ -1387,10 +1387,10 @@
|
|
1387
1387
|
<item>
|
1388
1388
|
<widget class="QDialogButtonBox" name="buttonBox">
|
1389
1389
|
<property name="orientation">
|
1390
|
-
<enum>Qt::Horizontal</enum>
|
1390
|
+
<enum>Qt::Orientation::Horizontal</enum>
|
1391
1391
|
</property>
|
1392
1392
|
<property name="standardButtons">
|
1393
|
-
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
1393
|
+
<set>QDialogButtonBox::StandardButton::Cancel|QDialogButtonBox::StandardButton::Ok</set>
|
1394
1394
|
</property>
|
1395
1395
|
<property name="centerButtons">
|
1396
1396
|
<bool>true</bool>
|
@@ -1400,7 +1400,7 @@
|
|
1400
1400
|
<item>
|
1401
1401
|
<spacer name="horizontalSpacer">
|
1402
1402
|
<property name="orientation">
|
1403
|
-
<enum>Qt::Horizontal</enum>
|
1403
|
+
<enum>Qt::Orientation::Horizontal</enum>
|
1404
1404
|
</property>
|
1405
1405
|
<property name="sizeHint" stdset="0">
|
1406
1406
|
<size>
|
not1mm/lib/cat_interface.py
CHANGED
@@ -138,6 +138,8 @@ class CAT:
|
|
138
138
|
ConnectionRefusedError,
|
139
139
|
xmlrpc.client.Fault,
|
140
140
|
http.client.BadStatusLine,
|
141
|
+
http.client.CannotSendRequest,
|
142
|
+
http.client.ResponseNotReady,
|
141
143
|
) as exception:
|
142
144
|
self.online = False
|
143
145
|
logger.debug("getvfo_flrig: %s", f"{exception}")
|
@@ -177,6 +179,8 @@ class CAT:
|
|
177
179
|
ConnectionRefusedError,
|
178
180
|
xmlrpc.client.Fault,
|
179
181
|
http.client.BadStatusLine,
|
182
|
+
http.client.CannotSendRequest,
|
183
|
+
http.client.ResponseNotReady,
|
180
184
|
) as exception:
|
181
185
|
self.online = False
|
182
186
|
logger.debug("%s", f"{exception}")
|
@@ -220,6 +224,8 @@ class CAT:
|
|
220
224
|
ConnectionRefusedError,
|
221
225
|
xmlrpc.client.Fault,
|
222
226
|
http.client.BadStatusLine,
|
227
|
+
http.client.CannotSendRequest,
|
228
|
+
http.client.ResponseNotReady,
|
223
229
|
) as exception:
|
224
230
|
self.online = False
|
225
231
|
logger.debug("getbw_flrig: %s", f"{exception}")
|
@@ -261,6 +267,8 @@ class CAT:
|
|
261
267
|
ConnectionRefusedError,
|
262
268
|
xmlrpc.client.Fault,
|
263
269
|
http.client.BadStatusLine,
|
270
|
+
http.client.CannotSendRequest,
|
271
|
+
http.client.ResponseNotReady,
|
264
272
|
) as exception:
|
265
273
|
self.online = False
|
266
274
|
logger.debug("getpower_flrig: %s", f"{exception}")
|
@@ -295,6 +303,8 @@ class CAT:
|
|
295
303
|
ConnectionRefusedError,
|
296
304
|
xmlrpc.client.Fault,
|
297
305
|
http.client.BadStatusLine,
|
306
|
+
http.client.CannotSendRequest,
|
307
|
+
http.client.ResponseNotReady,
|
298
308
|
) as exception:
|
299
309
|
self.online = False
|
300
310
|
logger.debug("%s", f"{exception}")
|
@@ -333,6 +343,8 @@ class CAT:
|
|
333
343
|
ConnectionRefusedError,
|
334
344
|
xmlrpc.client.Fault,
|
335
345
|
http.client.BadStatusLine,
|
346
|
+
http.client.CannotSendRequest,
|
347
|
+
http.client.ResponseNotReady,
|
336
348
|
) as exception:
|
337
349
|
self.online = False
|
338
350
|
logger.debug("setvfo_flrig: %s", f"{exception}")
|
@@ -371,6 +383,8 @@ class CAT:
|
|
371
383
|
ConnectionRefusedError,
|
372
384
|
xmlrpc.client.Fault,
|
373
385
|
http.client.BadStatusLine,
|
386
|
+
http.client.CannotSendRequest,
|
387
|
+
http.client.ResponseNotReady,
|
374
388
|
) as exception:
|
375
389
|
self.online = False
|
376
390
|
logger.debug("setmode_flrig: %s", f"{exception}")
|
@@ -408,6 +422,8 @@ class CAT:
|
|
408
422
|
ConnectionRefusedError,
|
409
423
|
xmlrpc.client.Fault,
|
410
424
|
http.client.BadStatusLine,
|
425
|
+
http.client.CannotSendRequest,
|
426
|
+
http.client.ResponseNotReady,
|
411
427
|
) as exception:
|
412
428
|
self.online = False
|
413
429
|
logger.debug("setpower_flrig: %s", f"{exception}")
|
@@ -462,6 +478,8 @@ class CAT:
|
|
462
478
|
ConnectionRefusedError,
|
463
479
|
xmlrpc.client.Fault,
|
464
480
|
http.client.BadStatusLine,
|
481
|
+
http.client.CannotSendRequest,
|
482
|
+
http.client.ResponseNotReady,
|
465
483
|
) as exception:
|
466
484
|
self.online = False
|
467
485
|
logger.debug("%s", f"{exception}")
|
@@ -496,6 +514,8 @@ class CAT:
|
|
496
514
|
ConnectionRefusedError,
|
497
515
|
xmlrpc.client.Fault,
|
498
516
|
http.client.BadStatusLine,
|
517
|
+
http.client.CannotSendRequest,
|
518
|
+
http.client.ResponseNotReady,
|
499
519
|
) as exception:
|
500
520
|
self.online = False
|
501
521
|
logger.debug("%s", f"{exception}")
|
not1mm/lib/ham_utility.py
CHANGED
@@ -242,7 +242,7 @@ def fakefreq(band: str, mode: str) -> str:
|
|
242
242
|
"80": ["3530", "3559", "3970"],
|
243
243
|
"60": ["5332", "5373", "5405"],
|
244
244
|
"40": ["7030", "7040", "7250"],
|
245
|
-
"30": ["10130", "10130", "
|
245
|
+
"30": ["10130", "10130", "10130"],
|
246
246
|
"20": ["14030", "14070", "14250"],
|
247
247
|
"17": ["18080", "18100", "18150"],
|
248
248
|
"15": ["21065", "21070", "21200"],
|
not1mm/lib/n1mm.py
CHANGED
@@ -102,6 +102,21 @@ class N1MM:
|
|
102
102
|
"ID": "",
|
103
103
|
}
|
104
104
|
|
105
|
+
score_report = {
|
106
|
+
"app": "NOT1MM",
|
107
|
+
"contest": "",
|
108
|
+
"call": "",
|
109
|
+
"class": {
|
110
|
+
"ops": "SINGLE-OP",
|
111
|
+
"mode": "MIXED",
|
112
|
+
"power": "LOW",
|
113
|
+
"bands": "ALL",
|
114
|
+
"transmitter": "ONE",
|
115
|
+
},
|
116
|
+
"score": 0,
|
117
|
+
"timestamp": "",
|
118
|
+
}
|
119
|
+
|
105
120
|
def __init__(
|
106
121
|
self,
|
107
122
|
radioport="127.0.0.1:12060",
|
@@ -159,6 +174,14 @@ class N1MM:
|
|
159
174
|
"""Send lookup request"""
|
160
175
|
self._send(self.lookup_port, self.contact_info, "lookupinfo")
|
161
176
|
|
177
|
+
def send_score(self):
|
178
|
+
"""Send score"""
|
179
|
+
self._send(self.score_port, self.score_report, "scoreinfo")
|
180
|
+
|
181
|
+
def send_realtime_score(self):
|
182
|
+
"""Send score"""
|
183
|
+
self._send(self.score_port, self.score_report, "dynamicresults")
|
184
|
+
|
162
185
|
def _send(self, port_list, payload, package_name):
|
163
186
|
"""Send XML data"""
|
164
187
|
# bytes_to_send = dicttoxml(
|
not1mm/lib/version.py
CHANGED
not1mm/plugins/k1usn_sst.py
CHANGED
@@ -21,4 +21,347 @@
|
|
21
21
|
# Find rules at: http://www.k1usn.com/sst.html
|
22
22
|
|
23
23
|
import datetime
|
24
|
+
import logging
|
25
|
+
import platform
|
24
26
|
|
27
|
+
from pathlib import Path
|
28
|
+
|
29
|
+
from PyQt6 import QtWidgets
|
30
|
+
|
31
|
+
from not1mm.lib.plugin_common import gen_adif, get_points
|
32
|
+
from not1mm.lib.version import __version__
|
33
|
+
|
34
|
+
logger = logging.getLogger(__name__)
|
35
|
+
|
36
|
+
EXCHANGE_HINT = "Name or Name + SPC"
|
37
|
+
|
38
|
+
name = "PHONE WEEKLY TEST"
|
39
|
+
cabrillo_name = "PHONE-WEEKLY-TEST"
|
40
|
+
mode = "SSB" # CW SSB BOTH RTTY
|
41
|
+
# columns = [0, 1, 2, 3, 4, 10, 11, 14, 15]
|
42
|
+
columns = [
|
43
|
+
"YYYY-MM-DD HH:MM:SS",
|
44
|
+
"Call",
|
45
|
+
"Freq",
|
46
|
+
"Name",
|
47
|
+
"Sect",
|
48
|
+
"M1",
|
49
|
+
"PTS",
|
50
|
+
]
|
51
|
+
|
52
|
+
advance_on_space = [True, True, True, True, True]
|
53
|
+
|
54
|
+
# 1 once per contest, 2 work each band, 3 each band/mode, 4 no dupe checking
|
55
|
+
dupe_type = 2
|
56
|
+
|
57
|
+
|
58
|
+
def init_contest(self):
|
59
|
+
"""setup plugin"""
|
60
|
+
set_tab_next(self)
|
61
|
+
set_tab_prev(self)
|
62
|
+
interface(self)
|
63
|
+
self.next_field = self.other_1
|
64
|
+
|
65
|
+
|
66
|
+
def interface(self):
|
67
|
+
"""Setup user interface"""
|
68
|
+
self.field1.hide()
|
69
|
+
self.field2.hide()
|
70
|
+
self.field3.show()
|
71
|
+
self.field4.show()
|
72
|
+
namefield = self.field3.findChild(QtWidgets.QLabel)
|
73
|
+
namefield.setText("Name")
|
74
|
+
self.field3.setAccessibleName("Name")
|
75
|
+
spc = self.field4.findChild(QtWidgets.QLabel)
|
76
|
+
spc.setText("State")
|
77
|
+
self.field4.setAccessibleName("State")
|
78
|
+
|
79
|
+
|
80
|
+
def reset_label(self):
|
81
|
+
"""reset label after field cleared"""
|
82
|
+
|
83
|
+
|
84
|
+
def set_tab_next(self):
|
85
|
+
"""Set TAB Advances"""
|
86
|
+
self.tab_next = {
|
87
|
+
self.callsign: self.field3.findChild(QtWidgets.QLineEdit),
|
88
|
+
self.field3.findChild(QtWidgets.QLineEdit): self.field4.findChild(
|
89
|
+
QtWidgets.QLineEdit
|
90
|
+
),
|
91
|
+
self.field4.findChild(QtWidgets.QLineEdit): self.callsign,
|
92
|
+
}
|
93
|
+
|
94
|
+
|
95
|
+
def set_tab_prev(self):
|
96
|
+
"""Set TAB Advances"""
|
97
|
+
self.tab_prev = {
|
98
|
+
self.callsign: self.field4.findChild(QtWidgets.QLineEdit),
|
99
|
+
self.field3.findChild(QtWidgets.QLineEdit): self.callsign,
|
100
|
+
self.field4.findChild(QtWidgets.QLineEdit): self.field3.findChild(
|
101
|
+
QtWidgets.QLineEdit
|
102
|
+
),
|
103
|
+
}
|
104
|
+
|
105
|
+
|
106
|
+
def set_contact_vars(self):
|
107
|
+
"""Contest Specific"""
|
108
|
+
self.contact["SNT"] = self.sent.text()
|
109
|
+
self.contact["RCV"] = self.receive.text()
|
110
|
+
self.contact["Name"] = self.other_1.text().upper()
|
111
|
+
self.contact["Sect"] = self.other_2.text().upper()
|
112
|
+
self.contact["SentNr"] = self.contest_settings.get("SentExchange", 0)
|
113
|
+
|
114
|
+
if self.contact.get("Sect", ""):
|
115
|
+
result = self.database.fetch_sect_band_exists(
|
116
|
+
self.contact.get("Sect", ""), self.contact.get("Band", "")
|
117
|
+
)
|
118
|
+
if result.get("sect_count", ""):
|
119
|
+
self.contact["IsMultiplier1"] = 0
|
120
|
+
else:
|
121
|
+
self.contact["IsMultiplier1"] = 1
|
122
|
+
|
123
|
+
|
124
|
+
def predupe(self):
|
125
|
+
"""called after callsign entered"""
|
126
|
+
|
127
|
+
|
128
|
+
def prefill(self):
|
129
|
+
"""Fill sentnr"""
|
130
|
+
|
131
|
+
|
132
|
+
def points(self):
|
133
|
+
"""Calc point"""
|
134
|
+
return 1
|
135
|
+
|
136
|
+
|
137
|
+
def show_mults(self):
|
138
|
+
"""Return display string for mults"""
|
139
|
+
result = self.database.fetch_section_band_count_nodx()
|
140
|
+
if result:
|
141
|
+
return int(result.get("sb_count", 0))
|
142
|
+
return 0
|
143
|
+
|
144
|
+
|
145
|
+
def show_qso(self):
|
146
|
+
"""Return qso count"""
|
147
|
+
result = self.database.fetch_qso_count()
|
148
|
+
if result:
|
149
|
+
return int(result.get("qsos", 0))
|
150
|
+
return 0
|
151
|
+
|
152
|
+
|
153
|
+
def calc_score(self):
|
154
|
+
"""Return calculated score"""
|
155
|
+
result = self.database.fetch_points()
|
156
|
+
if result is not None:
|
157
|
+
score = result.get("Points", "0")
|
158
|
+
if score is None:
|
159
|
+
score = "0"
|
160
|
+
contest_points = int(score)
|
161
|
+
mults = show_mults(self)
|
162
|
+
return contest_points * mults
|
163
|
+
return 0
|
164
|
+
|
165
|
+
|
166
|
+
def adif(self):
|
167
|
+
"""Call the generate ADIF function"""
|
168
|
+
gen_adif(self, cabrillo_name, "K1USN-SST")
|
169
|
+
|
170
|
+
|
171
|
+
def cabrillo(self):
|
172
|
+
"""Generates Cabrillo file. Maybe."""
|
173
|
+
# https://www.cqwpx.com/cabrillo.htm
|
174
|
+
logger.debug("******Cabrillo*****")
|
175
|
+
logger.debug("Station: %s", f"{self.station}")
|
176
|
+
logger.debug("Contest: %s", f"{self.contest_settings}")
|
177
|
+
now = datetime.datetime.now()
|
178
|
+
date_time = now.strftime("%Y-%m-%d_%H-%M-%S")
|
179
|
+
filename = (
|
180
|
+
str(Path.home())
|
181
|
+
+ "/"
|
182
|
+
+ f"{self.station.get('Call','').upper()}_{cabrillo_name}_{date_time}.log"
|
183
|
+
)
|
184
|
+
logger.debug("%s", filename)
|
185
|
+
log = self.database.fetch_all_contacts_asc()
|
186
|
+
try:
|
187
|
+
with open(filename, "w", encoding="ascii") as file_descriptor:
|
188
|
+
print("START-OF-LOG: 3.0", end="\r\n", file=file_descriptor)
|
189
|
+
print(
|
190
|
+
f"CREATED-BY: Not1MM v{__version__}",
|
191
|
+
end="\r\n",
|
192
|
+
file=file_descriptor,
|
193
|
+
)
|
194
|
+
print(
|
195
|
+
f"CONTEST: {cabrillo_name}",
|
196
|
+
end="\r\n",
|
197
|
+
file=file_descriptor,
|
198
|
+
)
|
199
|
+
if self.station.get("Club", ""):
|
200
|
+
print(
|
201
|
+
f"CLUB: {self.station.get('Club', '').upper()}",
|
202
|
+
end="\r\n",
|
203
|
+
file=file_descriptor,
|
204
|
+
)
|
205
|
+
print(
|
206
|
+
f"CALLSIGN: {self.station.get('Call','')}",
|
207
|
+
end="\r\n",
|
208
|
+
file=file_descriptor,
|
209
|
+
)
|
210
|
+
print(
|
211
|
+
f"LOCATION: {self.station.get('ARRLSection', '')}",
|
212
|
+
end="\r\n",
|
213
|
+
file=file_descriptor,
|
214
|
+
)
|
215
|
+
# print(
|
216
|
+
# f"ARRL-SECTION: {self.pref.get('section', '')}",
|
217
|
+
# end="\r\n",
|
218
|
+
# file=file_descriptor,
|
219
|
+
# )
|
220
|
+
print(
|
221
|
+
f"CATEGORY-OPERATOR: {self.contest_settings.get('OperatorCategory','')}",
|
222
|
+
end="\r\n",
|
223
|
+
file=file_descriptor,
|
224
|
+
)
|
225
|
+
print(
|
226
|
+
f"CATEGORY-ASSISTED: {self.contest_settings.get('AssistedCategory','')}",
|
227
|
+
end="\r\n",
|
228
|
+
file=file_descriptor,
|
229
|
+
)
|
230
|
+
print(
|
231
|
+
f"CATEGORY-BAND: {self.contest_settings.get('BandCategory','')}",
|
232
|
+
end="\r\n",
|
233
|
+
file=file_descriptor,
|
234
|
+
)
|
235
|
+
print(
|
236
|
+
f"CATEGORY-MODE: {self.contest_settings.get('ModeCategory','')}",
|
237
|
+
end="\r\n",
|
238
|
+
file=file_descriptor,
|
239
|
+
)
|
240
|
+
print(
|
241
|
+
f"CATEGORY-TRANSMITTER: {self.contest_settings.get('TransmitterCategory','')}",
|
242
|
+
end="\r\n",
|
243
|
+
file=file_descriptor,
|
244
|
+
)
|
245
|
+
if self.contest_settings.get("OverlayCategory", "") != "N/A":
|
246
|
+
print(
|
247
|
+
f"CATEGORY-OVERLAY: {self.contest_settings.get('OverlayCategory','')}",
|
248
|
+
end="\r\n",
|
249
|
+
file=file_descriptor,
|
250
|
+
)
|
251
|
+
print(
|
252
|
+
f"GRID-LOCATOR: {self.station.get('GridSquare','')}",
|
253
|
+
end="\r\n",
|
254
|
+
file=file_descriptor,
|
255
|
+
)
|
256
|
+
# print(
|
257
|
+
# f"CATEGORY: {None}",
|
258
|
+
# end="\r\n",
|
259
|
+
# file=file_descriptor,
|
260
|
+
# )
|
261
|
+
print(
|
262
|
+
f"CATEGORY-POWER: {self.contest_settings.get('PowerCategory','')}",
|
263
|
+
end="\r\n",
|
264
|
+
file=file_descriptor,
|
265
|
+
)
|
266
|
+
|
267
|
+
print(
|
268
|
+
f"CLAIMED-SCORE: {calc_score(self)}",
|
269
|
+
end="\r\n",
|
270
|
+
file=file_descriptor,
|
271
|
+
)
|
272
|
+
ops = f"@{self.station.get('Call','')}"
|
273
|
+
list_of_ops = self.database.get_ops()
|
274
|
+
for op in list_of_ops:
|
275
|
+
ops += f", {op.get('Operator', '')}"
|
276
|
+
print(
|
277
|
+
f"OPERATORS: {ops}",
|
278
|
+
end="\r\n",
|
279
|
+
file=file_descriptor,
|
280
|
+
)
|
281
|
+
print(
|
282
|
+
f"NAME: {self.station.get('Name', '')}",
|
283
|
+
end="\r\n",
|
284
|
+
file=file_descriptor,
|
285
|
+
)
|
286
|
+
print(
|
287
|
+
f"ADDRESS: {self.station.get('Street1', '')}",
|
288
|
+
end="\r\n",
|
289
|
+
file=file_descriptor,
|
290
|
+
)
|
291
|
+
print(
|
292
|
+
f"ADDRESS-CITY: {self.station.get('City', '')}",
|
293
|
+
end="\r\n",
|
294
|
+
file=file_descriptor,
|
295
|
+
)
|
296
|
+
print(
|
297
|
+
f"ADDRESS-STATE-PROVINCE: {self.station.get('State', '')}",
|
298
|
+
end="\r\n",
|
299
|
+
file=file_descriptor,
|
300
|
+
)
|
301
|
+
print(
|
302
|
+
f"ADDRESS-POSTALCODE: {self.station.get('Zip', '')}",
|
303
|
+
end="\r\n",
|
304
|
+
file=file_descriptor,
|
305
|
+
)
|
306
|
+
print(
|
307
|
+
f"ADDRESS-COUNTRY: {self.station.get('Country', '')}",
|
308
|
+
end="\r\n",
|
309
|
+
file=file_descriptor,
|
310
|
+
)
|
311
|
+
print(
|
312
|
+
f"EMAIL: {self.station.get('Email', '')}",
|
313
|
+
end="\r\n",
|
314
|
+
file=file_descriptor,
|
315
|
+
)
|
316
|
+
for contact in log:
|
317
|
+
the_date_and_time = contact.get("TS", "")
|
318
|
+
themode = contact.get("Mode", "")
|
319
|
+
if themode == "LSB" or themode == "USB":
|
320
|
+
themode = "PH"
|
321
|
+
frequency = str(int(contact.get("Freq", "0"))).rjust(5)
|
322
|
+
|
323
|
+
loggeddate = the_date_and_time[:10]
|
324
|
+
loggedtime = the_date_and_time[11:13] + the_date_and_time[14:16]
|
325
|
+
print(
|
326
|
+
f"QSO: {frequency} {themode} {loggeddate} {loggedtime} "
|
327
|
+
f"{contact.get('StationPrefix', '').ljust(13)} "
|
328
|
+
f"{str(contact.get('SentNr', '')).upper()} "
|
329
|
+
f"{contact.get('Call', '').ljust(13)} "
|
330
|
+
f"{str(contact.get('Name', '')).ljust(11)} "
|
331
|
+
f"{str(contact.get('Sect', '')).ljust(5)}",
|
332
|
+
end="\r\n",
|
333
|
+
file=file_descriptor,
|
334
|
+
)
|
335
|
+
print("END-OF-LOG:", end="\r\n", file=file_descriptor)
|
336
|
+
self.show_message_box(f"Cabrillo saved to: {filename}")
|
337
|
+
except IOError as exception:
|
338
|
+
logger.critical("cabrillo: IO error: %s, writing to %s", exception, filename)
|
339
|
+
self.show_message_box(f"Error saving Cabrillo: {exception} {filename}")
|
340
|
+
return
|
341
|
+
|
342
|
+
|
343
|
+
def recalculate_mults(self):
|
344
|
+
"""Recalculates multipliers after change in logged qso."""
|
345
|
+
|
346
|
+
all_contacts = self.database.fetch_all_contacts_asc()
|
347
|
+
for contact in all_contacts:
|
348
|
+
time_stamp = contact.get("TS", "")
|
349
|
+
sect = contact.get("Sect", "")
|
350
|
+
band = contact.get("Band", "")
|
351
|
+
query = (
|
352
|
+
f"select count(*) as sect_count from dxlog where TS < '{time_stamp}' "
|
353
|
+
f"and Sect = '{sect}' "
|
354
|
+
f"and Band = '{band}' "
|
355
|
+
f"and ContestNR = {self.pref.get('contest', '1')};"
|
356
|
+
)
|
357
|
+
result = self.database.exec_sql(query)
|
358
|
+
count = result.get("sect_count", 1)
|
359
|
+
if count == 0 and contact.get("Points", 0) == 1 and sect != "DX":
|
360
|
+
contact["IsMultiplier1"] = 1
|
361
|
+
else:
|
362
|
+
contact["IsMultiplier1"] = 0
|
363
|
+
self.database.change_contact(contact)
|
364
|
+
cmd = {}
|
365
|
+
cmd["cmd"] = "UPDATELOG"
|
366
|
+
cmd["station"] = platform.node()
|
367
|
+
self.multicast_interface.send_as_json(cmd)
|