not1mm 23.4.13__py3-none-any.whl → 23.4.18__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 CHANGED
@@ -29,6 +29,8 @@ from PyQt5.QtWidgets import QFileDialog
29
29
  from PyQt5.QtCore import QPoint # pylint: disable=no-name-in-module
30
30
  from PyQt5.QtCore import QDir, QRect, QSize, Qt
31
31
  from PyQt5.QtGui import QFontDatabase # pylint: disable=no-name-in-module
32
+ import sounddevice as sd
33
+ import soundfile as sf
32
34
 
33
35
  from not1mm.lib.about import About
34
36
  from not1mm.lib.cat_interface import CAT
@@ -220,7 +222,7 @@ class MainWindow(QtWidgets.QMainWindow):
220
222
  self.actionNew_Database.triggered.connect(self.new_database)
221
223
  self.actionOpen_Database.triggered.connect(self.open_database)
222
224
 
223
- self.actionEdit_CW_Macros.triggered.connect(self.edit_cw_macros)
225
+ self.actionEdit_Macros.triggered.connect(self.edit_cw_macros)
224
226
 
225
227
  self.actionAbout.triggered.connect(self.show_about_dialog)
226
228
 
@@ -290,6 +292,7 @@ class MainWindow(QtWidgets.QMainWindow):
290
292
  self.station = {}
291
293
  self.contact = self.database.empty_contact
292
294
  self.current_op = self.station.get("Call", "")
295
+ self.make_op_dir()
293
296
  if self.pref.get("contest"):
294
297
  self.load_contest()
295
298
 
@@ -379,6 +382,7 @@ class MainWindow(QtWidgets.QMainWindow):
379
382
  if self.station is None:
380
383
  self.station = {}
381
384
  self.current_op = self.station.get("Call", "")
385
+ self.make_op_dir()
382
386
  cmd = {}
383
387
  cmd["cmd"] = "NEWDB"
384
388
  self.multicast_interface.send_as_json(cmd)
@@ -400,6 +404,7 @@ class MainWindow(QtWidgets.QMainWindow):
400
404
  if self.station.get("Call", "") == "":
401
405
  self.edit_station_settings()
402
406
  self.current_op = self.station.get("Call", "")
407
+ self.make_op_dir()
403
408
  cmd = {}
404
409
  cmd["cmd"] = "NEWDB"
405
410
  self.multicast_interface.send_as_json(cmd)
@@ -732,8 +737,8 @@ class MainWindow(QtWidgets.QMainWindow):
732
737
  """Clears the text input fields and sets focus to callsign field."""
733
738
  self.dupe_indicator.hide()
734
739
  self.contact = self.database.empty_contact
735
- self.heading_distance.setText("No Heading")
736
- self.dx_entity.setText("dxentity")
740
+ self.heading_distance.setText("")
741
+ self.dx_entity.setText("")
737
742
  if self.contest:
738
743
  mults = self.contest.show_mults(self)
739
744
  qsos = self.contest.show_qso(self)
@@ -955,6 +960,7 @@ class MainWindow(QtWidgets.QMainWindow):
955
960
  self.settings_dialog.close()
956
961
  if self.current_op == "":
957
962
  self.current_op = self.station.get("Call", "")
963
+ self.make_op_dir()
958
964
  contest_count = self.database.fetch_all_contests()
959
965
  if len(contest_count) == 0:
960
966
  self.new_contest_dialog()
@@ -1040,15 +1046,48 @@ class MainWindow(QtWidgets.QMainWindow):
1040
1046
  def process_macro(self, macro: str) -> str:
1041
1047
  """Process CW macro substitutions"""
1042
1048
  macro = macro.upper()
1043
- macro = macro.replace("{MYCALL}", self.station.get("Call"))
1049
+ macro = macro.replace("{MYCALL}", self.station.get("Call", ""))
1044
1050
  macro = macro.replace("{HISCALL}", self.callsign.text())
1045
- macro = macro.replace("{SNT}", self.sent.text().replace("9", "n"))
1051
+ if self.radio_state.get("mode") == "CW":
1052
+ macro = macro.replace("{SNT}", self.sent.text().replace("9", "n"))
1053
+ else:
1054
+ macro = macro.replace("{SNT}", self.sent.text())
1046
1055
  macro = macro.replace("{SENTNR}", self.other_1.text())
1047
1056
  return macro
1048
1057
 
1058
+ def voice_string(self, the_string: str) -> None:
1059
+ """voices string using nato phonetics"""
1060
+ logger.debug("Voicing: %s", the_string)
1061
+ op_path = Path(DATA_PATH) / self.current_op
1062
+ if "[" in the_string:
1063
+ sub_string = the_string.strip("[]").lower()
1064
+ filename = f"{str(op_path)}/{sub_string}.wav"
1065
+ if Path(filename).is_file():
1066
+ logger.debug("Voicing: %s", filename)
1067
+ data, fs = sf.read(filename, dtype="float32")
1068
+
1069
+ sd.play(data, fs)
1070
+ _status = sd.wait()
1071
+ return
1072
+
1073
+ for letter in the_string.lower():
1074
+ if letter in "abcdefghijklmnopqrstuvwxyz 1234567890":
1075
+ if letter == " ":
1076
+ letter = "space"
1077
+ filename = f"{str(op_path)}/{letter}.wav"
1078
+ if Path(filename).is_file():
1079
+ logger.debug("Voicing: %s", filename)
1080
+ data, fs = sf.read(filename, dtype="float32")
1081
+
1082
+ sd.play(data, fs)
1083
+ _status = sd.wait()
1084
+
1049
1085
  def sendf1(self):
1050
1086
  """stub"""
1051
1087
  logger.debug("F1 Clicked")
1088
+ if self.radio_state.get("mode") in ["USB", "SSB"]:
1089
+ self.voice_string(self.process_macro(self.F1.toolTip()))
1090
+ return
1052
1091
  if self.cw:
1053
1092
  # if self.preference.get("send_n1mm_packets"):
1054
1093
  # self.n1mm.radio_info["FunctionKeyCaption"] = self.F1.text()
@@ -1057,66 +1096,99 @@ class MainWindow(QtWidgets.QMainWindow):
1057
1096
  def sendf2(self):
1058
1097
  """stub"""
1059
1098
  logger.debug("F2 Clicked")
1099
+ if self.radio_state.get("mode") in ["USB", "SSB"]:
1100
+ self.voice_string(self.process_macro(self.F2.toolTip()))
1101
+ return
1060
1102
  if self.cw:
1061
1103
  self.cw.sendcw(self.process_macro(self.F2.toolTip()))
1062
1104
 
1063
1105
  def sendf3(self):
1064
1106
  """stub"""
1065
1107
  logger.debug("F3 Clicked")
1108
+ if self.radio_state.get("mode") in ["USB", "SSB"]:
1109
+ self.voice_string(self.process_macro(self.F3.toolTip()))
1110
+ return
1066
1111
  if self.cw:
1067
1112
  self.cw.sendcw(self.process_macro(self.F3.toolTip()))
1068
1113
 
1069
1114
  def sendf4(self):
1070
1115
  """stub"""
1071
1116
  logger.debug("F4 Clicked")
1117
+ if self.radio_state.get("mode") in ["USB", "SSB"]:
1118
+ self.voice_string(self.process_macro(self.F4.toolTip()))
1119
+ return
1072
1120
  if self.cw:
1073
1121
  self.cw.sendcw(self.process_macro(self.F4.toolTip()))
1074
1122
 
1075
1123
  def sendf5(self):
1076
1124
  """stub"""
1077
1125
  logger.debug("F5 Clicked")
1126
+ if self.radio_state.get("mode") in ["USB", "SSB"]:
1127
+ self.voice_string(self.process_macro(self.F5.toolTip()))
1128
+ return
1078
1129
  if self.cw:
1079
1130
  self.cw.sendcw(self.process_macro(self.F5.toolTip()))
1080
1131
 
1081
1132
  def sendf6(self):
1082
1133
  """stub"""
1083
1134
  logger.debug("F6 Clicked")
1135
+ if self.radio_state.get("mode") in ["USB", "SSB"]:
1136
+ self.voice_string(self.process_macro(self.F6.toolTip()))
1137
+ return
1084
1138
  if self.cw:
1085
1139
  self.cw.sendcw(self.process_macro(self.F6.toolTip()))
1086
1140
 
1087
1141
  def sendf7(self):
1088
1142
  """stub"""
1089
1143
  logger.debug("F7 Clicked")
1144
+ if self.radio_state.get("mode") in ["USB", "SSB"]:
1145
+ self.voice_string(self.process_macro(self.F7.toolTip()))
1146
+ return
1090
1147
  if self.cw:
1091
1148
  self.cw.sendcw(self.process_macro(self.F7.toolTip()))
1092
1149
 
1093
1150
  def sendf8(self):
1094
1151
  """stub"""
1095
1152
  logger.debug("F8 Clicked")
1153
+ if self.radio_state.get("mode") in ["USB", "SSB"]:
1154
+ self.voice_string(self.process_macro(self.F8.toolTip()))
1155
+ return
1096
1156
  if self.cw:
1097
1157
  self.cw.sendcw(self.process_macro(self.F8.toolTip()))
1098
1158
 
1099
1159
  def sendf9(self):
1100
1160
  """stub"""
1101
1161
  logger.debug("F9 Clicked")
1162
+ if self.radio_state.get("mode") in ["USB", "SSB"]:
1163
+ self.voice_string(self.process_macro(self.F9.toolTip()))
1164
+ return
1102
1165
  if self.cw:
1103
1166
  self.cw.sendcw(self.process_macro(self.F9.toolTip()))
1104
1167
 
1105
1168
  def sendf10(self):
1106
1169
  """stub"""
1107
1170
  logger.debug("F10 Clicked")
1171
+ if self.radio_state.get("mode") in ["USB", "SSB"]:
1172
+ self.voice_string(self.process_macro(self.F10.toolTip()))
1173
+ return
1108
1174
  if self.cw:
1109
1175
  self.cw.sendcw(self.process_macro(self.F10.toolTip()))
1110
1176
 
1111
1177
  def sendf11(self):
1112
1178
  """stub"""
1113
1179
  logger.debug("F11 Clicked")
1180
+ if self.radio_state.get("mode") in ["USB", "SSB"]:
1181
+ self.voice_string(self.process_macro(self.F11.toolTip()))
1182
+ return
1114
1183
  if self.cw:
1115
1184
  self.cw.sendcw(self.process_macro(self.F11.toolTip()))
1116
1185
 
1117
1186
  def sendf12(self):
1118
1187
  """stub"""
1119
1188
  logger.debug("F12 Clicked")
1189
+ if self.radio_state.get("mode") in ["USB", "SSB"]:
1190
+ self.voice_string(self.process_macro(self.F12.toolTip()))
1191
+ return
1120
1192
  if self.cw:
1121
1193
  self.cw.sendcw(self.process_macro(self.F12.toolTip()))
1122
1194
 
@@ -1380,6 +1452,7 @@ class MainWindow(QtWidgets.QMainWindow):
1380
1452
  self.rig_control.set_mode("CW")
1381
1453
  self.set_window_title()
1382
1454
  self.clearinputs()
1455
+ self.read_cw_macros()
1383
1456
  return
1384
1457
  if stripped_text == "RTTY":
1385
1458
  self.setmode("RTTY")
@@ -1401,6 +1474,7 @@ class MainWindow(QtWidgets.QMainWindow):
1401
1474
  if self.rig_control:
1402
1475
  self.rig_control.set_mode(self.radio_state.get("mode"))
1403
1476
  self.clearinputs()
1477
+ self.read_cw_macros()
1404
1478
  return
1405
1479
  if stripped_text == "OPON":
1406
1480
  self.get_opon()
@@ -1468,7 +1542,8 @@ class MainWindow(QtWidgets.QMainWindow):
1468
1542
  f"{primary_pfx}: {continent}/{entity} cq:{cq} itu:{itu}"
1469
1543
  )
1470
1544
  if len(callsign) > 2:
1471
- self.contest.prefill(self)
1545
+ if self.contest:
1546
+ self.contest.prefill(self)
1472
1547
 
1473
1548
  def check_callsign2(self, callsign):
1474
1549
  """Check call once entered"""
@@ -1544,9 +1619,26 @@ class MainWindow(QtWidgets.QMainWindow):
1544
1619
  """Save new OP"""
1545
1620
  if self.opon_dialog.NewOperator.text():
1546
1621
  self.current_op = self.opon_dialog.NewOperator.text().upper()
1547
-
1548
1622
  self.opon_dialog.close()
1549
1623
  logger.debug("New Op: %s", self.current_op)
1624
+ self.make_op_dir()
1625
+
1626
+ def make_op_dir(self):
1627
+ """Create OP directory if it does not exist."""
1628
+ if self.current_op:
1629
+ op_path = Path(DATA_PATH) / self.current_op
1630
+ logger.debug("op_path: %s", str(op_path))
1631
+ if op_path.is_dir() is False:
1632
+ logger.debug("Creating Op Directory: %s", str(op_path))
1633
+ os.mkdir(str(op_path))
1634
+ if op_path.is_dir():
1635
+ source_path = Path(WORKING_PATH) / "data" / "phonetics"
1636
+ logger.debug("source_path: %s", str(source_path))
1637
+ for child in source_path.iterdir():
1638
+ destination_file = op_path / child.name
1639
+ logger.debug("Destination: %s", str(destination_file))
1640
+ if destination_file.is_file() is False:
1641
+ destination_file.write_bytes(child.read_bytes())
1550
1642
 
1551
1643
  def poll_radio(self):
1552
1644
  """stub"""
@@ -1572,10 +1664,15 @@ class MainWindow(QtWidgets.QMainWindow):
1572
1664
  """
1573
1665
  Calls the default text editor to edit the CW macro file.
1574
1666
  """
1575
- if not Path(DATA_PATH + "/cwmacros.txt").exists():
1667
+ # FIXME
1668
+ if self.radio_state.get("mode") == "CW":
1669
+ macro_file = "/cwmacros.txt"
1670
+ else:
1671
+ macro_file = "/ssbmacros.txt"
1672
+ if not Path(DATA_PATH + macro_file).exists():
1576
1673
  logger.debug("read_cw_macros: copying default macro file.")
1577
- copyfile(WORKING_PATH + "/data/cwmacros.txt", DATA_PATH + "/cwmacros.txt")
1578
- os.system(f"xdg-open {DATA_PATH}/cwmacros.txt")
1674
+ copyfile(WORKING_PATH + "/data" + macro_file, DATA_PATH + macro_file)
1675
+ os.system(f"xdg-open {DATA_PATH}{macro_file}")
1579
1676
  self.read_cw_macros()
1580
1677
 
1581
1678
  def read_cw_macros(self) -> None:
@@ -1585,12 +1682,15 @@ class MainWindow(QtWidgets.QMainWindow):
1585
1682
  temp directory this is running from... In theory.
1586
1683
  """
1587
1684
 
1588
- if not Path(DATA_PATH + "/cwmacros.txt").exists():
1685
+ if self.radio_state.get("mode") == "CW":
1686
+ macro_file = "/cwmacros.txt"
1687
+ else:
1688
+ macro_file = "/ssbmacros.txt"
1689
+
1690
+ if not Path(DATA_PATH + macro_file).exists():
1589
1691
  logger.debug("read_cw_macros: copying default macro file.")
1590
- copyfile(WORKING_PATH + "/data/cwmacros.txt", DATA_PATH + "/cwmacros.txt")
1591
- with open(
1592
- DATA_PATH + "/cwmacros.txt", "r", encoding="utf-8"
1593
- ) as file_descriptor:
1692
+ copyfile(WORKING_PATH + "/data" + macro_file, DATA_PATH + macro_file)
1693
+ with open(DATA_PATH + macro_file, "r", encoding="utf-8") as file_descriptor:
1594
1694
  for line in file_descriptor:
1595
1695
  try:
1596
1696
  mode, fkey, buttonname, cwtext = line.split("|")
@@ -0,0 +1,4 @@
1
+ alpha, bravo, charlie, delta, echo, foxtrot, golf, hotel, india, juliet, kilowatt, lima, mike, november, oscar, papa, quebec, romeo, sierra, tango, uniform, victor, whiskey, xray, yankee, zulu
2
+
3
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9
4
+
@@ -16,7 +16,7 @@
16
16
  </font>
17
17
  </property>
18
18
  <property name="windowTitle">
19
- <string>Settings</string>
19
+ <string>Configuration Settings</string>
20
20
  </property>
21
21
  <property name="styleSheet">
22
22
  <string notr="true">background-color: rgb(46, 52, 54);
@@ -54,6 +54,9 @@ color: rgb(211, 215, 207);</string>
54
54
  </item>
55
55
  <item row="0" column="0">
56
56
  <widget class="QTabWidget" name="tabWidget">
57
+ <property name="enabled">
58
+ <bool>true</bool>
59
+ </property>
57
60
  <property name="font">
58
61
  <font>
59
62
  <family>JetBrains Mono</family>
@@ -67,7 +70,7 @@ color: rgb(211, 215, 207);</string>
67
70
  <enum>QTabWidget::Rounded</enum>
68
71
  </property>
69
72
  <property name="currentIndex">
70
- <number>0</number>
73
+ <number>2</number>
71
74
  </property>
72
75
  <property name="elideMode">
73
76
  <enum>Qt::ElideNone</enum>
@@ -84,7 +87,12 @@ color: rgb(211, 215, 207);</string>
84
87
  <property name="tabBarAutoHide">
85
88
  <bool>false</bool>
86
89
  </property>
87
- <widget class="QWidget" name="tab_1">
90
+ <widget class="QWidget" name="lookup_tab">
91
+ <property name="font">
92
+ <font>
93
+ <family>JetBrains Mono</family>
94
+ </font>
95
+ </property>
88
96
  <attribute name="title">
89
97
  <string>Lookup</string>
90
98
  </attribute>
@@ -116,6 +124,9 @@ color: rgb(211, 215, 207);</string>
116
124
  </font>
117
125
  </property>
118
126
  <property name="text">
127
+ <string/>
128
+ </property>
129
+ <property name="placeholderText">
119
130
  <string>W1AW</string>
120
131
  </property>
121
132
  </widget>
@@ -147,7 +158,10 @@ color: rgb(211, 215, 207);</string>
147
158
  </font>
148
159
  </property>
149
160
  <property name="text">
150
- <string>Secret</string>
161
+ <string/>
162
+ </property>
163
+ <property name="placeholderText">
164
+ <string>Your Password</string>
151
165
  </property>
152
166
  </widget>
153
167
  </item>
@@ -230,7 +244,15 @@ color: rgb(211, 215, 207);</string>
230
244
  </item>
231
245
  </layout>
232
246
  </widget>
233
- <widget class="QWidget" name="tab_2">
247
+ <widget class="QWidget" name="cloudlog_tab">
248
+ <property name="enabled">
249
+ <bool>false</bool>
250
+ </property>
251
+ <property name="font">
252
+ <font>
253
+ <family>JetBrains Mono</family>
254
+ </font>
255
+ </property>
234
256
  <attribute name="title">
235
257
  <string>Cloudlog</string>
236
258
  </attribute>
@@ -262,7 +284,10 @@ color: rgb(211, 215, 207);</string>
262
284
  </font>
263
285
  </property>
264
286
  <property name="text">
265
- <string>cl12345678901234567890</string>
287
+ <string/>
288
+ </property>
289
+ <property name="placeholderText">
290
+ <string>Your API Key</string>
266
291
  </property>
267
292
  </widget>
268
293
  </item>
@@ -279,6 +304,9 @@ color: rgb(211, 215, 207);</string>
279
304
  <set>Qt::ImhUrlCharactersOnly</set>
280
305
  </property>
281
306
  <property name="text">
307
+ <string/>
308
+ </property>
309
+ <property name="placeholderText">
282
310
  <string>http://Cloudlog.com/Cloudlog/index.php/api/qso</string>
283
311
  </property>
284
312
  </widget>
@@ -319,7 +347,12 @@ color: rgb(211, 215, 207);</string>
319
347
  </item>
320
348
  </layout>
321
349
  </widget>
322
- <widget class="QWidget" name="tab_3">
350
+ <widget class="QWidget" name="cat_tab">
351
+ <property name="font">
352
+ <font>
353
+ <family>JetBrains Mono</family>
354
+ </font>
355
+ </property>
323
356
  <attribute name="title">
324
357
  <string>CAT</string>
325
358
  </attribute>
@@ -498,7 +531,12 @@ color: rgb(211, 215, 207);</string>
498
531
  </item>
499
532
  </layout>
500
533
  </widget>
501
- <widget class="QWidget" name="tab">
534
+ <widget class="QWidget" name="cw_tab">
535
+ <property name="font">
536
+ <font>
537
+ <family>JetBrains Mono</family>
538
+ </font>
539
+ </property>
502
540
  <attribute name="title">
503
541
  <string>CW</string>
504
542
  </attribute>
@@ -605,7 +643,15 @@ color: rgb(211, 215, 207);</string>
605
643
  </item>
606
644
  </layout>
607
645
  </widget>
608
- <widget class="QWidget" name="tab_5">
646
+ <widget class="QWidget" name="group_tab">
647
+ <property name="enabled">
648
+ <bool>false</bool>
649
+ </property>
650
+ <property name="font">
651
+ <font>
652
+ <family>JetBrains Mono</family>
653
+ </font>
654
+ </property>
609
655
  <attribute name="title">
610
656
  <string>Group Operation</string>
611
657
  </attribute>
@@ -715,7 +761,15 @@ color: rgb(211, 215, 207);</string>
715
761
  </item>
716
762
  </layout>
717
763
  </widget>
718
- <widget class="QWidget" name="tab_6">
764
+ <widget class="QWidget" name="n1mm_tab">
765
+ <property name="enabled">
766
+ <bool>false</bool>
767
+ </property>
768
+ <property name="font">
769
+ <font>
770
+ <family>JetBrains Mono</family>
771
+ </font>
772
+ </property>
719
773
  <attribute name="title">
720
774
  <string>N1MM</string>
721
775
  </attribute>
not1mm/data/main.ui CHANGED
@@ -1023,7 +1023,7 @@
1023
1023
  <addaction name="actionConfiguration_Settings"/>
1024
1024
  <addaction name="actionStationSettings"/>
1025
1025
  <addaction name="separator"/>
1026
- <addaction name="actionEdit_CW_Macros"/>
1026
+ <addaction name="actionEdit_Macros"/>
1027
1027
  </widget>
1028
1028
  <widget class="QMenu" name="menuHelp">
1029
1029
  <property name="title">
@@ -1225,6 +1225,11 @@
1225
1225
  <property name="text">
1226
1226
  <string>Generate Cabrillo</string>
1227
1227
  </property>
1228
+ <property name="font">
1229
+ <font>
1230
+ <family>JetBrains Mono</family>
1231
+ </font>
1232
+ </property>
1228
1233
  <property name="autoRepeat">
1229
1234
  <bool>false</bool>
1230
1235
  </property>
@@ -1239,6 +1244,11 @@
1239
1244
  <property name="text">
1240
1245
  <string>Log Window</string>
1241
1246
  </property>
1247
+ <property name="font">
1248
+ <font>
1249
+ <family>JetBrains Mono</family>
1250
+ </font>
1251
+ </property>
1242
1252
  <property name="autoRepeat">
1243
1253
  <bool>false</bool>
1244
1254
  </property>
@@ -1253,6 +1263,11 @@
1253
1263
  <property name="text">
1254
1264
  <string>Generate ADIF</string>
1255
1265
  </property>
1266
+ <property name="font">
1267
+ <font>
1268
+ <family>JetBrains Mono</family>
1269
+ </font>
1270
+ </property>
1256
1271
  <property name="shortcut">
1257
1272
  <string/>
1258
1273
  </property>
@@ -1270,6 +1285,11 @@
1270
1285
  <property name="text">
1271
1286
  <string>Recalculate Mults</string>
1272
1287
  </property>
1288
+ <property name="font">
1289
+ <font>
1290
+ <family>JetBrains Mono</family>
1291
+ </font>
1292
+ </property>
1273
1293
  <property name="autoRepeat">
1274
1294
  <bool>false</bool>
1275
1295
  </property>
@@ -1284,6 +1304,11 @@
1284
1304
  <property name="text">
1285
1305
  <string>New Contest</string>
1286
1306
  </property>
1307
+ <property name="font">
1308
+ <font>
1309
+ <family>JetBrains Mono</family>
1310
+ </font>
1311
+ </property>
1287
1312
  <property name="autoRepeat">
1288
1313
  <bool>false</bool>
1289
1314
  </property>
@@ -1298,6 +1323,11 @@
1298
1323
  <property name="text">
1299
1324
  <string>New Database</string>
1300
1325
  </property>
1326
+ <property name="font">
1327
+ <font>
1328
+ <family>JetBrains Mono</family>
1329
+ </font>
1330
+ </property>
1301
1331
  <property name="autoRepeat">
1302
1332
  <bool>false</bool>
1303
1333
  </property>
@@ -1312,6 +1342,11 @@
1312
1342
  <property name="text">
1313
1343
  <string>Open Database</string>
1314
1344
  </property>
1345
+ <property name="font">
1346
+ <font>
1347
+ <family>JetBrains Mono</family>
1348
+ </font>
1349
+ </property>
1315
1350
  <property name="autoRepeat">
1316
1351
  <bool>false</bool>
1317
1352
  </property>
@@ -1326,6 +1361,11 @@
1326
1361
  <property name="text">
1327
1362
  <string>Open Contest</string>
1328
1363
  </property>
1364
+ <property name="font">
1365
+ <font>
1366
+ <family>JetBrains Mono</family>
1367
+ </font>
1368
+ </property>
1329
1369
  <property name="autoRepeat">
1330
1370
  <bool>false</bool>
1331
1371
  </property>
@@ -1336,9 +1376,14 @@
1336
1376
  <bool>false</bool>
1337
1377
  </property>
1338
1378
  </action>
1339
- <action name="actionEdit_CW_Macros">
1379
+ <action name="actionEdit_Macros">
1340
1380
  <property name="text">
1341
- <string>Edit CW Macros</string>
1381
+ <string>Edit Macros</string>
1382
+ </property>
1383
+ <property name="font">
1384
+ <font>
1385
+ <family>JetBrains Mono</family>
1386
+ </font>
1342
1387
  </property>
1343
1388
  <property name="autoRepeat">
1344
1389
  <bool>false</bool>
@@ -203,7 +203,7 @@
203
203
  <widget class="QDateTimeEdit" name="dateTimeEdit">
204
204
  <property name="time">
205
205
  <time>
206
- <hour>0</hour>
206
+ <hour>8</hour>
207
207
  <minute>0</minute>
208
208
  <second>0</second>
209
209
  </time>
@@ -654,6 +654,21 @@
654
654
  </item>
655
655
  </layout>
656
656
  </widget>
657
+ <tabstops>
658
+ <tabstop>contest</tabstop>
659
+ <tabstop>dateTimeEdit</tabstop>
660
+ <tabstop>operator_class</tabstop>
661
+ <tabstop>band</tabstop>
662
+ <tabstop>power</tabstop>
663
+ <tabstop>mode</tabstop>
664
+ <tabstop>overlay</tabstop>
665
+ <tabstop>station</tabstop>
666
+ <tabstop>assisted</tabstop>
667
+ <tabstop>transmitter</tabstop>
668
+ <tabstop>exchange</tabstop>
669
+ <tabstop>operators</tabstop>
670
+ <tabstop>soapbox</tabstop>
671
+ </tabstops>
657
672
  <resources/>
658
673
  <connections>
659
674
  <connection>
not1mm/data/settings.ui CHANGED
@@ -16,7 +16,7 @@
16
16
  </font>
17
17
  </property>
18
18
  <property name="windowTitle">
19
- <string>Settings</string>
19
+ <string>Station Settings</string>
20
20
  </property>
21
21
  <layout class="QGridLayout" name="gridLayout" columnstretch="0,10,0,0,10,0,10">
22
22
  <item row="6" column="3">
@@ -0,0 +1,24 @@
1
+ S|F1|MyCall|{MYCALL}
2
+ S|F2|Exch|{SNT} {SENTNR}
3
+ S|F3|My NR|{SENTNR}
4
+ S|F4|empty|
5
+ S|F5|AGN|[again]
6
+ S|F6|empty|
7
+ S|F7|Roger|[roger]
8
+ S|F8|73|[73]
9
+ S|F9|empty|
10
+ S|F10|Call?|[yourcall]
11
+ S|F11|NR??|[mynumber]
12
+ S|F12|TU|[thankyou]
13
+ R|F1|Run CQ|[cq]
14
+ R|F2|HisCall|{HISCALL}
15
+ R|F3|Run Exch|{HISCALL} {SNT} {SENTNR}
16
+ R|F4|Run TU|[thankyouqrz]
17
+ R|F5|MyCall|{MYCALL}
18
+ R|F6|MyNR|{SENTNR}
19
+ R|F7|empty|
20
+ R|F8|Roger|[roger]
21
+ R|F9|AGN|[again]
22
+ R|F10|Call?|[yourcall]
23
+ R|F11|NR?|[mynumber]
24
+ R|F12|empty|
not1mm/lib/version.py CHANGED
@@ -1,2 +1,2 @@
1
1
  """It's the version"""
2
- __version__ = "23.4.13"
2
+ __version__ = "23.4.18"
not1mm/test.py CHANGED
@@ -5,6 +5,8 @@ Email: michael.bridak@gmail.com
5
5
  GPL V3
6
6
  """
7
7
 
8
+ # playing with sound
9
+
8
10
  # pylint: disable=too-many-lines
9
11
  # pylint: disable=invalid-name
10
12
  # pylint: disable=no-member
@@ -12,119 +14,42 @@ GPL V3
12
14
  # pylint: disable=c-extension-no-member
13
15
  # pylint: disable=unused-import
14
16
 
15
- from math import radians, sin, cos, atan2, sqrt, asin, pi
16
- import sys
17
- import socket
18
- import os
19
- import logging
20
- import threading
21
- import uuid
22
- import queue
23
- import time
24
- from itertools import chain
25
-
26
- from json import dumps, loads, JSONDecodeError
27
- from datetime import datetime, timedelta
28
- from pathlib import Path
29
- from shutil import copyfile
30
-
31
- import requests
32
-
33
- try:
34
- from not1mm.lib.database import DataBase
35
- from not1mm.lib.version import __version__
36
- except ModuleNotFoundError:
37
- from lib.database import DataBase
38
- from lib.version import __version__
39
-
40
-
41
- class main:
42
- """test"""
43
-
44
- def __init__(self):
45
- # create the DB
46
- # self.db = DataBase("file::memory:?cache=shared")
47
- self.db = DataBase("testdb.db", ".")
48
- self.db_object = None
49
-
50
- def run(self):
51
- """run"""
52
- # Set persistent values for contact
53
- # self.db.empty_contact["app"] = "K6GTELogger"
54
- self.db.empty_contact["StationPrefix"] = "K6GTE"
55
- self.db.empty_contact["Operator"] = "K6GTE"
56
- self.db.empty_contact["ContestName"] = "CQWWCW"
57
- self.db.empty_contact["ContestNR"] = "1"
58
- # self.db.empty_contact["StationName"] = "20M CW"
59
-
60
- # get clean contact object with persistent changes from above
61
- self.db_object = self.db.get_empty()
62
-
63
- # Make changes to save to the DB
64
- self.db_object["ID"] = uuid.uuid4().hex
65
- self.db_object["TS"] = datetime.utcnow().strftime("%Y-%m-%d %H:%M:%S")
66
- self.db_object["Band"] = 14.0
67
- self.db_object["QSXFreq"] = 14030.0
68
- self.db_object["Freq"] = 14030.0
69
- self.db_object["CountryPrefix"] = "K"
70
- self.db_object["Continent"] = "NA"
71
- self.db_object["SNT"] = "599"
72
- self.db_object["SentNr"] = 1
73
- self.db_object["RCV"] = "599"
74
- self.db_object["NR"] = 37
75
- self.db_object["GridSquare"] = "DM13at"
76
- self.db_object["Sect"] = "ORG"
77
- self.db_object["QTH"] = "Their Home"
78
- self.db_object["Name"] = "Russ"
79
- self.db_object["Power"] = "100"
80
- self.db_object["Points"] = 2
81
- self.db_object["Call"] = "K5TUX"
82
- self.db_object["Mode"] = "CW"
17
+ # import threading
83
18
 
84
- # Save the contact to the DB
85
- self.db.log_contact(self.db_object)
86
- print(f"\nSaved Data:\n{self.db.fetch_all_contacts_asc()}\n\n")
19
+ import sounddevice as sd
20
+ import soundfile as sf
87
21
 
88
- # save changes
89
- self.db_object["QSXFreq"] = 14027.0
90
- self.db_object["Freq"] = 14027.0
91
- self.db.change_contact(self.db_object)
92
- print(f"\nUpdated Data:\n{self.db.fetch_all_contacts_asc()}\n\n")
22
+ print(f"{sd.query_devices(kind='output')}")
93
23
 
94
- # get unique id of record
95
- # uniqid = self.db.get_unique_id(1)
96
- # print(f"Unique ID: {uniqid}")
24
+ # FILENAME = "/home/mbridak/.local/share/not1mm/K6GTE/z.wav"
25
+ # current_frame = 0
26
+ # event = threading.Event()
97
27
 
98
- # fetch descending
99
- print(f"\nSorted Descending Data:\n{self.db.fetch_all_contacts_desc()}\n\n")
28
+ callsign = "k6gte 599 org"
100
29
 
101
- # fetch last record
102
- print(f"\nGet last contact:\n{self.db.fetch_last_contact()}\n\n")
103
30
 
104
- # fetch all dirty
105
- # print(f"\nGet all marked dirty:\n{self.db.fetch_all_dirty_contacts()}\n\n")
31
+ # def callback(outdata, frames, _time, status):
32
+ # """docstring"""
33
+ # global current_frame
34
+ # if status:
35
+ # print(status)
36
+ # chunksize = min(len(data) - current_frame, frames)
37
+ # outdata[:chunksize] = data[current_frame : current_frame + chunksize]
38
+ # if chunksize < frames:
39
+ # outdata[chunksize:] = 0
40
+ # raise sd.CallbackStop()
41
+ # current_frame += chunksize
106
42
 
107
- # fetch all dirty
108
- print(f"\nDeleting Contact:\n{self.db.delete_contact(1)}\n\n")
109
43
 
44
+ # data, fs = sf.read(FILENAME)
110
45
 
111
- logger = logging.getLogger("__main__")
112
- handler = logging.StreamHandler()
113
- formatter = logging.Formatter(
114
- datefmt="%H:%M:%S",
115
- fmt="[%(asctime)s] %(levelname)s %(module)s - %(funcName)s Line %(lineno)d:\n%(message)s",
116
- )
117
- handler.setFormatter(formatter)
118
- logger.addHandler(handler)
119
46
 
120
- if Path("./debug").exists():
121
- # if True:
122
- logger.setLevel(logging.DEBUG)
123
- logger.debug("debugging on")
124
- else:
125
- logger.setLevel(logging.WARNING)
126
- logger.warning("debugging off")
47
+ for letter in callsign:
48
+ if letter == " ":
49
+ letter = "space"
50
+ filename = f"/home/mbridak/.local/share/not1mm/K6GTE/{letter}.wav"
51
+ print(filename)
52
+ data, fs = sf.read(filename, dtype="float32")
127
53
 
128
- if __name__ == "__main__":
129
- app = main()
130
- app.run()
54
+ sd.play(data, fs)
55
+ _status = sd.wait()
@@ -1,12 +1,12 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: not1mm
3
- Version: 23.4.13
3
+ Version: 23.4.18
4
4
  Summary: NOT1MM Logger
5
5
  Author-email: Michael Bridak <michael.bridak@gmail.com>
6
6
  Project-URL: Homepage, https://github.com/mbridak/not1mm
7
7
  Project-URL: Bug Tracker, https://github.com/mbridak/not1mm/issues
8
8
  Classifier: Programming Language :: Python :: 3
9
- Classifier: Development Status :: 1 - Planning
9
+ Classifier: Development Status :: 4 - Beta
10
10
  Classifier: License :: OSI Approved :: GNU General Public License v3 (GPLv3)
11
11
  Classifier: Environment :: X11 Applications :: Qt
12
12
  Classifier: Operating System :: POSIX :: Linux
@@ -21,6 +21,8 @@ Requires-Dist: requests
21
21
  Requires-Dist: dicttoxml
22
22
  Requires-Dist: xmltodict
23
23
  Requires-Dist: psutil
24
+ Requires-Dist: sounddevice
25
+ Requires-Dist: soundfile
24
26
 
25
27
  # Not1MM
26
28
 
@@ -48,11 +50,16 @@ Requires-Dist: psutil
48
50
  - [Revisiting an old friend](#revisiting-an-old-friend)
49
51
  - [Station Settings dialog](#station-settings-dialog)
50
52
  - [Changing station information](#changing-station-information)
51
- - [Adding a contest](#adding-a-contest)
52
- - [Selecting an added contest as the current contest](#selecting-an-added-contest-as-the-current-contest)
53
+ - [Adding a contest to the current dababase](#adding-a-contest-to-the-current-dababase)
54
+ - [Selecting an existing contest as the current contest](#selecting-an-existing-contest-as-the-current-contest)
53
55
  - [Configuration Settings](#configuration-settings)
56
+ - [Lookup](#lookup)
57
+ - [CAT](#cat)
58
+ - [CW Keyer interface](#cw-keyer-interface)
54
59
  - [Hiding screen elements](#hiding-screen-elements)
55
60
  - [Editing macro keys](#editing-macro-keys)
61
+ - [Macro substitutions](#macro-substitutions)
62
+ - [Macro use with voice](#macro-use-with-voice)
56
63
  - [cty.dat and QRZ lookups for distance and bearing](#ctydat-and-qrz-lookups-for-distance-and-bearing)
57
64
  - [Other uses for the call field](#other-uses-for-the-call-field)
58
65
  - [Log Display](#log-display)
@@ -61,8 +68,6 @@ Requires-Dist: psutil
61
68
  - [Cabrillo](#cabrillo)
62
69
  - [ADIF](#adif)
63
70
  - [Dupe checking](#dupe-checking)
64
- - [CAT](#cat)
65
- - [CW Keyer interface](#cw-keyer-interface)
66
71
 
67
72
  ## What and why is Not1MM
68
73
 
@@ -101,6 +106,8 @@ Feature complete. I'm only one guy, and I'm not what you'd consider to be a cont
101
106
 
102
107
  ## Changes of note
103
108
 
109
+ - [23-4-18] Added voice keying. Fixed a bunch of crashes.
110
+ - [23-4-15] Corrected tabstops on new contest screen. Changed project state to BETA.
104
111
  - [23-4-12] Dynamic log window columns. Reload settings after changes saved. Altered JIDX displayed log columns.
105
112
  - [23-4-11] Add about dialog. Fix crash when previous working DB is erased. Add CQ WW CW and SSB. When entering station settings, after entering callsign and grid, the cqzone, ituzone, country, latitude and longitude will auto fill.
106
113
  - [23-4-10] Added Configure Settings dialog. Added CW keyer and CAT control settings to Configure Settings dialog.
@@ -179,7 +186,7 @@ not1mm
179
186
 
180
187
  ### Data
181
188
 
182
- If your system has an `XDG_DATA_HOME` environment variable set, the databases can be found there. Otherwise they will be found at `yourhome/.local/share/not1mm`
189
+ If your system has an `XDG_DATA_HOME` environment variable set, the database and CW macro files can be found there. Otherwise they will be found at `yourhome/.local/share/not1mm`
183
190
 
184
191
  ### Config
185
192
 
@@ -201,7 +208,7 @@ You can create a new database by selecting `File` > `New Database` from the main
201
208
 
202
209
  ### Revisiting an old friend
203
210
 
204
- You can select previously created databases by selecting `File` > `Open Database`.
211
+ You can select a previously created databases for use by selecting `File` > `Open Database`.
205
212
 
206
213
  ## Station Settings dialog
207
214
 
@@ -219,13 +226,13 @@ You can fill. You can fill. Everyone look at your keys.
219
226
 
220
227
  Station information can be changed any time by going to `File` > `Station Settings` and editing the information.
221
228
 
222
- ## Adding a contest
229
+ ## Adding a contest to the current dababase
223
230
 
224
231
  Select `File` > `New Contest`
225
232
 
226
233
  ![New Contest Dialog](https://github.com/mbridak/not1mm/raw/master/pic/new_contest.png)
227
234
 
228
- ## Selecting an added contest as the current contest
235
+ ## Selecting an existing contest as the current contest
229
236
 
230
237
  Select `File` > `Open Contest`
231
238
 
@@ -233,10 +240,25 @@ Select `File` > `Open Contest`
233
240
 
234
241
  ## Configuration Settings
235
242
 
236
- Select `File` > `Configuration Settings`
243
+ To setup your CAT control, CW keyer, Callsign lookups, select `File` > `Configuration Settings`
244
+
245
+ The tabs for cloudlog, groups and n1mm are disabled and are for future expansion.
237
246
 
238
247
  ![Configuration Settings screen](https://github.com/mbridak/not1mm/raw/master/pic/configuration_settings.png)
239
248
 
249
+ ### Lookup
250
+
251
+ For callsign lookup, several services are supported. QRZ, HamQTH and HamDB. If your service of choice requires a username and password, Enter it here.
252
+
253
+ ### CAT
254
+
255
+ Under the `CAT` TAB, you can choose either `rigctld` normally with an IP of `127.0.0.1` and a port of `4532`. Or `flrig`, IP normally of `127.0.0.1` and a port of `12345`. `None` is always an option, but is it really?
256
+
257
+ ### CW Keyer interface
258
+
259
+ Under the `CW` TAB, There are three options. `cwdaemon`, which normally uses IP `127.0.0.1` and port `6789`. `pywinkeyer` which normally uses IP `127.0.0.1` and port `8000`. Or `None`, if you want to Morse it like it's 1899.
260
+
261
+
240
262
  ## Hiding screen elements
241
263
 
242
264
  You can show or hide certain buttons/indicators by checking and unchecking their boxes under the view menu. You can then resize the screen to make it more compact.
@@ -247,15 +269,27 @@ The your choices will be remembered when you relaunch the program.
247
269
 
248
270
  ## Editing macro keys
249
271
 
250
- To edit the CW macros, choose `File` > `Edit CW Macros`. This will open your systems registered text editor with current macros loaded. When your done just save the file and close the editor.
272
+ To edit the macros, choose `File` > `Edit Macros`. This will open your systems registered text editor with current macros loaded. When your done just save the file and close the editor. The file loaded to edit will be determined by your current operating mode.
273
+
274
+ ### Macro substitutions
251
275
 
252
276
  You can include a limited set of substitution instructions.
253
277
 
254
278
  - {MYCALL} Sends the station call.
255
279
  - {HISCALL} Send what's in the callsign field.
256
- - {SNT} Sends 5nn
280
+ - {SNT} Sends 5nn (cw) or 599 (ssb)
257
281
  - {SENTNR} Sends whats in the SentNR field.
258
282
 
283
+ ### Macro use with voice
284
+
285
+ The macros when used with voice, will also accept filenames of WAV files to play, excluding the file extension. The filename must be enclosed by brackets. For example `[CQ]` will play `cq.wav`, `[again]` will play `again.wav`. The wav files are stored in the operators personal data directory. The filenames must be in lowercase. See [Various data file locations](#various-data-file-locations) above for the location of your data files. For me, the macro `[cq]` will play `/home/mbridak/.local/share/not1mm/K6GTE/cq.wav`
286
+
287
+ The current wav files in place are not the ones you will want to use. They sound like some little kid. You can use something like Audacity to record new wav files in your own voice.
288
+
289
+ Aside from the `[filename]` wav files, there are also NATO phonetic wav files for each letter and number. So if your macro key holds `{HISCALL} {SNT} {SENTNR}` and you have entered K5TUX in callsign field during CQ WW SSB while in CQ Zone 3. You'll here Kilo 5 Tango Uniform X-ray, 5 9 9, 3. Hopefully not in a little kids voice.
290
+
291
+ Right now, the sound is played out of the default sound device. This is NOT what we want. I still have to code up the dialog to choose the correct sound device to use.
292
+
259
293
  ## cty.dat and QRZ lookups for distance and bearing
260
294
 
261
295
  When a callsign is entered, a look up is first done in a cty.dat file to determin the country of origin, geographic center, cq zone and ITU region. Great circle calculations are done to determin the heading and distance from your gridsquare to the grographic center. This information then displayed at the bottom left.
@@ -280,7 +314,7 @@ The Log display gets updated automatically when a contact is entered. The top ha
280
314
 
281
315
  ![Log Display Window](https://github.com/mbridak/not1mm/raw/master/pic/logdisplay.png)
282
316
 
283
- The bottom half of the log displays contacts sorted by what's currently in the call entry field.
317
+ The bottom half of the log displays contacts sorted by what's currently in the call entry field. The columns displayed in the log window are dependant on what contests is currently active.
284
318
 
285
319
  ## Editing a contact
286
320
 
@@ -321,11 +355,3 @@ Boom... ADIF
321
355
  ## Dupe checking
322
356
 
323
357
  Added dupe checking. Big Red 'Dupe' will appear if it's a dupe...
324
-
325
- ## CAT
326
-
327
- Go to `File` > `Configuration Settings`, You will find a `CAT` TAB. You can choose either `rigctld` normally with an IP of `127.0.0.1` and a port of `4532`. Or `flrig`, IP normally of `127.0.0.1` and a port of `12345`. `None` is always an option, but is it really?
328
-
329
- ## CW Keyer interface
330
-
331
- Go to `File` > `Configuration Settings`, You will find a `CW` TAB. There are three options. `cwdaemon`, IP `127.0.0.1`, port `6789`. `pywinkeyer`, IP `127.0.0.1`, port `8000`. And `None` if you want to Morse it like it's 1899.
@@ -1,13 +1,14 @@
1
1
  not1mm/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
- not1mm/__main__.py,sha256=oTy_DOwsdOAmq4AbgZdRcqdJLnLemCo3_ICjHYSWsAM,67232
2
+ not1mm/__main__.py,sha256=hVYIWuReXv9iqijMXDc4TZizwMwL_AY1S8Ied_yKmks,71628
3
3
  not1mm/logwindow.py,sha256=FSa6jcKx0dn_DDbubyF20LfSb2IxyUZpuvIaumFf4jo,29725
4
- not1mm/test.py,sha256=sCAd6OZQlakGm2gMbjhwZ17UyI-Y5L2CCqsYymx7IPQ,3906
4
+ not1mm/test.py,sha256=k1kJefypzE3NBcUpAcGy7jOe7VEwFs_qgGyDRTeYKuE,1263
5
5
  not1mm/data/Combinear.qss,sha256=SKqM0g8GvNXay1ovgtwCw3Egt0eLfN5P3iTREInC1eE,16590
6
6
  not1mm/data/JetBrainsMono-Regular.ttf,sha256=UOHctAKY_PzCGh7zy-6f6egnCcSK0wzmF0csBqO9lDY,203952
7
7
  not1mm/data/MASTER.SCP,sha256=oqUB3Fvy40vU-ra-R3-cvTeBnZWW04Da1Et011UITbI,542666
8
8
  not1mm/data/about.ui,sha256=ll-3ZSghbok0kW9MLSAoo2dW3EV3lM4m4nR-kUJ6oNw,2352
9
+ not1mm/data/alpha bravo charlie delta.txt,sha256=d5QMmSWEUAe4Rj1XbNjTPLa_5Be4Se6u5LUIqAYidOQ,224
9
10
  not1mm/data/check.png,sha256=UvFOLr8V-79qnjW8wUaGItXk_OSP8m8hqPevs8NDlFY,387
10
- not1mm/data/configuration.ui,sha256=BiiqKpqmaY0T8y5uJ2hsQUXxsvZ1yOBGy3Z14LwKpqE,29268
11
+ not1mm/data/configuration.ui,sha256=eBbNJgwrtkLcyRbvMxOfm9or4YybOC1HXwzU5NvpLHI,30635
11
12
  not1mm/data/contests.sql,sha256=4hmJCDvrbxnA_Y5S4T5o52TZieeFk6QUwFerwlFePNA,89307
12
13
  not1mm/data/cty.json,sha256=Y0c74JmGSlYKfkDHIUbaupVaAGqS01YzlQAP3IyWGYA,4534539
13
14
  not1mm/data/cwmacros.txt,sha256=PvJ7TxGILq-ErHb6Gbrm-08x76BbCdXb8AY8a7st5mg,451
@@ -19,12 +20,13 @@ not1mm/data/k6gte.not1mm-128.png,sha256=vWqt3Cgsaguj-BBiIoSJApzzhisPxldM8HZQbZ05
19
20
  not1mm/data/k6gte.not1mm-32.png,sha256=yucSwzlmqv3NegdWUvPvZzSgP7G22Ky3se8TWRXvzfI,1108
20
21
  not1mm/data/k6gte.not1mm-64.png,sha256=1KQvk0WBckUds79BvIFUt-KdTwQKKvTz6hiJu8MiT68,2152
21
22
  not1mm/data/logwindow.ui,sha256=_-wobHhIjALzCswyXIrqNadnLdc88eay1GNF23a-Qh0,970
22
- not1mm/data/main.ui,sha256=WM4BnZaY5kzoK8S26jEpKbMhzbJOFgo5cHAHmLS18EQ,41569
23
- not1mm/data/new_contest.ui,sha256=o8x97aY0QBV1Oiwvm5M10Tyr9iHbc_vd0qeiPi3wq04,16312
23
+ not1mm/data/main.ui,sha256=GHQ_7qZnRad4Q_spTHTls2G7vq_EO76nku6hTjEEJ-c,42469
24
+ not1mm/data/new_contest.ui,sha256=mn0ieMu2WwcZK7PNzZBf_aChb024VIbUejbvJhMygE0,16726
24
25
  not1mm/data/opon.ui,sha256=6r9_6ORGfNqwOnpzQjaJ1tWP_81amuXqLYlx1hHgdME,2018
25
26
  not1mm/data/pickcontest.ui,sha256=_9JFiJw4l-bRRgNDtVg1DpxreylYd_UqEq0wfcr9gJc,1600
26
27
  not1mm/data/reddot.png,sha256=M33jEMoU8W4rQ4_MVyzzKxDPDte1ypKBch5VnUMNLKE,565
27
- not1mm/data/settings.ui,sha256=-uEW4fQWolcv6QrNVpQ_TYhpJLCnhnCiggVSMR27cpA,35558
28
+ not1mm/data/settings.ui,sha256=sK5K5AXSPCMpMFIdqjTvgjxz525AjRiYuQLHid8P3hY,35566
29
+ not1mm/data/ssbmacros.txt,sha256=0Qccj4y0nlK-w5da9a9ti-jILkURtwztoDuL_D0pEJM,470
28
30
  not1mm/lib/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
29
31
  not1mm/lib/about.py,sha256=O9i8ypv2W9KZkPAp2bcRI0J5RgPE5R1vMfU8ZGlok_E,379
30
32
  not1mm/lib/cat_interface.py,sha256=4hJ3HRybf_Izg_O_jQTilgfPrfc6U-2y5-dGC3xV1go,10342
@@ -41,7 +43,7 @@ not1mm/lib/n1mm.py,sha256=bK5d21Yfn6xRpQcu2RdpL2zR8lOlRWOadD6Ai4_lFdc,4434
41
43
  not1mm/lib/new_contest.py,sha256=mHKNCS3iKOKN-bT9d8ZK3JemThOZFQ0ikfUSS0-ZTpY,354
42
44
  not1mm/lib/select_contest.py,sha256=XQdRUkPAIHIMVsilm82M54b_v9yWpYrZ1nfInJrtZoo,363
43
45
  not1mm/lib/settings.py,sha256=em4A1vQ4EMl53UP0EWeakrotIs2o2nOhjk6H6BJ7oTM,5409
44
- not1mm/lib/version.py,sha256=HiagaMNA74vR8RQzAxl6XSYkORD6pPxJG1wzHYj_y6k,47
46
+ not1mm/lib/version.py,sha256=1-6sWQIQrJbev_9kEVAX_xdffdPsQrYtrILQdlNJjVM,47
45
47
  not1mm/plugins/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
46
48
  not1mm/plugins/arrl_dx_cw.py,sha256=IMT3ybtVQp3t8GyIkTE4VyX83d4OFld-gI6VDLDPv3I,2521
47
49
  not1mm/plugins/arrl_dx_phone.py,sha256=w23Q6GO0IiVnCY6F9IDtLduIxG6NhChan5dZZdkzzlc,2524
@@ -60,9 +62,9 @@ not1mm/plugins/winter_field_day.py,sha256=NVCzdhJrw-F56mMQ7czZNcsS0bMtttks1VOBIy
60
62
  not1mm/testing/test.py,sha256=wsEa05WGFGYSYBRa0e-sxTc13tcibUgkPMiypnHRemc,2297
61
63
  testing/test.py,sha256=0jvT_UcvgcAGwkJNnB9PBDmQhLHQl85NQyT5f9GKBuQ,2248
62
64
  testing/text2.py,sha256=ehbwRI6zimJhOzKBRE540IEITzhvssdvMC4yZ7WcjuU,861
63
- not1mm-23.4.13.dist-info/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
64
- not1mm-23.4.13.dist-info/METADATA,sha256=tyrJpgvAHN_aiMlN66CqoJFevRV4GN3Lf6neipv8Ksc,14624
65
- not1mm-23.4.13.dist-info/WHEEL,sha256=pkctZYzUS4AYVn6dJ-7367OJZivF2e8RA9b_ZBjif18,92
66
- not1mm-23.4.13.dist-info/entry_points.txt,sha256=pMcZk_0dxFgLkcUkF0Q874ojpwOmF3OL6EKw9LgvocM,47
67
- not1mm-23.4.13.dist-info/top_level.txt,sha256=-NwUrh4k1kzpOvf720xYWSTKSlr-zNSIz3D_eplrxLs,15
68
- not1mm-23.4.13.dist-info/RECORD,,
65
+ not1mm-23.4.18.dist-info/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
66
+ not1mm-23.4.18.dist-info/METADATA,sha256=t4biScZUhbs2pr0fFhA3Hq0OHPxBqQeQe53TkViczC0,16745
67
+ not1mm-23.4.18.dist-info/WHEEL,sha256=pkctZYzUS4AYVn6dJ-7367OJZivF2e8RA9b_ZBjif18,92
68
+ not1mm-23.4.18.dist-info/entry_points.txt,sha256=pMcZk_0dxFgLkcUkF0Q874ojpwOmF3OL6EKw9LgvocM,47
69
+ not1mm-23.4.18.dist-info/top_level.txt,sha256=-NwUrh4k1kzpOvf720xYWSTKSlr-zNSIz3D_eplrxLs,15
70
+ not1mm-23.4.18.dist-info/RECORD,,