PyFT8 3.6.6__tar.gz → 3.7.0__tar.gz

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.
Files changed (42) hide show
  1. {pyft8-3.6.6 → pyft8-3.7.0}/PKG-INFO +1 -1
  2. {pyft8-3.6.6 → pyft8-3.7.0}/PyFT8/gui.py +36 -47
  3. {pyft8-3.6.6 → pyft8-3.7.0}/PyFT8/message_broker.py +1 -2
  4. {pyft8-3.6.6 → pyft8-3.7.0}/PyFT8/pyft8.py +2 -2
  5. {pyft8-3.6.6 → pyft8-3.7.0}/PyFT8/receiver.py +1 -1
  6. {pyft8-3.6.6 → pyft8-3.7.0}/PyFT8.egg-info/PKG-INFO +1 -1
  7. {pyft8-3.6.6 → pyft8-3.7.0}/pyproject.toml +1 -1
  8. {pyft8-3.6.6 → pyft8-3.7.0}/LICENSE +0 -0
  9. {pyft8-3.6.6 → pyft8-3.7.0}/MANIFEST.in +0 -0
  10. {pyft8-3.6.6 → pyft8-3.7.0}/PyFT8/__init__.py +0 -0
  11. {pyft8-3.6.6 → pyft8-3.7.0}/PyFT8/databases.py +0 -0
  12. {pyft8-3.6.6 → pyft8-3.7.0}/PyFT8/osd.py +0 -0
  13. {pyft8-3.6.6 → pyft8-3.7.0}/PyFT8/pskreporter.py +0 -0
  14. {pyft8-3.6.6 → pyft8-3.7.0}/PyFT8/qso_manager.py +0 -0
  15. {pyft8-3.6.6 → pyft8-3.7.0}/PyFT8/rigctrl.py +0 -0
  16. {pyft8-3.6.6 → pyft8-3.7.0}/PyFT8/time_utils.py +0 -0
  17. {pyft8-3.6.6 → pyft8-3.7.0}/PyFT8/transmitter.py +0 -0
  18. {pyft8-3.6.6 → pyft8-3.7.0}/PyFT8.egg-info/SOURCES.txt +0 -0
  19. {pyft8-3.6.6 → pyft8-3.7.0}/PyFT8.egg-info/dependency_links.txt +0 -0
  20. {pyft8-3.6.6 → pyft8-3.7.0}/PyFT8.egg-info/entry_points.txt +0 -0
  21. {pyft8-3.6.6 → pyft8-3.7.0}/PyFT8.egg-info/requires.txt +0 -0
  22. {pyft8-3.6.6 → pyft8-3.7.0}/PyFT8.egg-info/top_level.txt +0 -0
  23. {pyft8-3.6.6 → pyft8-3.7.0}/README.md +0 -0
  24. {pyft8-3.6.6 → pyft8-3.7.0}/setup.cfg +0 -0
  25. {pyft8-3.6.6 → pyft8-3.7.0}/tests/misc/CQ AAAA.py +0 -0
  26. {pyft8-3.6.6 → pyft8-3.7.0}/tests/misc/animation.py +0 -0
  27. {pyft8-3.6.6 → pyft8-3.7.0}/tests/misc/bits_loopback.py +0 -0
  28. {pyft8-3.6.6 → pyft8-3.7.0}/tests/misc/bits_loopback_short.py +0 -0
  29. {pyft8-3.6.6 → pyft8-3.7.0}/tests/misc/osd.py +0 -0
  30. {pyft8-3.6.6 → pyft8-3.7.0}/tests/misc/symbols_loopback.py +0 -0
  31. {pyft8-3.6.6 → pyft8-3.7.0}/tests/misc/test_generate_wav.py +0 -0
  32. {pyft8-3.6.6 → pyft8-3.7.0}/tests/misc/test_loopback_performance.py +0 -0
  33. {pyft8-3.6.6 → pyft8-3.7.0}/tests/misc/text.py +0 -0
  34. {pyft8-3.6.6 → pyft8-3.7.0}/tests/misc/view_worked_before.py +0 -0
  35. {pyft8-3.6.6 → pyft8-3.7.0}/tests/pipeline/Fine tuning compare IOS_PC.py +0 -0
  36. {pyft8-3.6.6 → pyft8-3.7.0}/tests/pipeline/Targetted tests.py +0 -0
  37. {pyft8-3.6.6 → pyft8-3.7.0}/tests/pipeline/test_01.wav +0 -0
  38. {pyft8-3.6.6 → pyft8-3.7.0}/tests/play_wavs.py +0 -0
  39. {pyft8-3.6.6 → pyft8-3.7.0}/tests/plot_decode_times.py +0 -0
  40. {pyft8-3.6.6 → pyft8-3.7.0}/tests/spare.py +0 -0
  41. {pyft8-3.6.6 → pyft8-3.7.0}/tests/spare2.py +0 -0
  42. {pyft8-3.6.6 → pyft8-3.7.0}/tests/test_batch_and_live.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: PyFT8
3
- Version: 3.6.6
3
+ Version: 3.7.0
4
4
  Summary: FT8 Decoding and Encoding in Python with test/loopback code
5
5
  Author-email: G1OJS <g1ojs@yahoo.com>
6
6
  License-Expression: GPL-3.0-or-later
@@ -25,13 +25,12 @@ def add_my_axes(fig, pos):
25
25
  ax.set_facecolor(TEXT_BACKGROUND_COLOR)
26
26
  return ax
27
27
 
28
- MESSAGE_TYPES = {'generic':{'bg':'blue', 'fg':'white', 'alpha':0.5}, 'CQ':{'bg':'green', 'fg':'white', 'alpha':0.8},
29
- 'from_me': {'bg':'yellow', 'fg':'black', 'alpha':0.95}, 'to_me':{'bg':'red', 'fg':'white', 'alpha':0.9}}
28
+ MESSAGE_TYPES = {'generic':{'bg':'blue', 'fg':'white', 'alpha':0.4}, 'CQ':{'bg':'green', 'fg':'white', 'alpha':0.7},
29
+ 'from_me': {'bg':'yellow', 'fg':'black', 'alpha':0.9}, 'to_me':{'bg':'red', 'fg':'white', 'alpha':0.9}}
30
30
  class Msg_box:
31
- def __init__(self, fig, ax, x, y, w, h, message):
31
+ def __init__(self, fig, ax, w, h):
32
32
  from matplotlib.patches import Rectangle
33
33
  self.fig, self.ax = fig, ax
34
- message_type_params = MESSAGE_TYPES[message['message_type']]
35
34
  rect = Rectangle((0, 0), w, h, edgecolor='lime', lw=2)
36
35
  self.patch = self.ax.add_patch(rect)
37
36
  self.patch.set_visible(False)
@@ -39,7 +38,6 @@ class Msg_box:
39
38
  self.text_inst.set_visible(False)
40
39
  self.text_inst.set_fontfamily('monospace')
41
40
  self.artists = [self.patch, self.text_inst]
42
- self.set_props(x, y, message)
43
41
 
44
42
  def set_props(self, x, y, message):
45
43
  self.xy = (x, y)
@@ -177,10 +175,10 @@ class Gui:
177
175
  self.cid = self.fig.canvas.mpl_connect('button_press_event', self._oncanvasclick)
178
176
 
179
177
  def main_loop(self):
180
- last_ptr = 0
181
178
  self.plt.show(block = False)
182
- target_update_time = 0.25
179
+ target_update_time = 0.15
183
180
  while True:
181
+ self.fig.canvas.flush_events() # for clicks
184
182
  tstart_wf_redraw = time_utils.time()
185
183
  self.image.set_data(self.waterfall_data['data'])
186
184
  if self.needs_redraw:
@@ -188,42 +186,30 @@ class Gui:
188
186
  plt.pause(0.01)
189
187
  else:
190
188
  self.ax_wf.draw_artist(self.image)
191
- t = time_utils.time()
189
+ self.fig.canvas.flush_events() # for clicks
192
190
  for mb in self.msg_boxes:
193
- mb.draw()
194
- #print(f"Drew {len(self.msg_boxes)} in {time_utils.time() - t:6.2f}s")
195
- self.fig.canvas.blit(self.ax_wf.bbox)
196
- #self.fig.canvas.update()
191
+ if mb.patch.get_visible():
192
+ mb.draw()
193
+ self.fig.canvas.flush_events() # for clicks
194
+ self.fig.canvas.blit(self.ax_wf.bbox) #self.fig.canvas.update()
197
195
  self.fig.canvas.flush_events()
198
- #print(f"Updated at {time_utils.cycle_time():6.2f}s")
199
196
  tdelay = target_update_time - (time_utils.time() - tstart_wf_redraw)
200
- #print(tdelay)
201
197
  if tdelay > 0.01:
202
198
  time_utils.sleep(tdelay)
203
199
 
204
- def before_search(self, curr_cycle):
205
- self._hide_msg_boxes(curr_cycle) # hide boxes overlapping new decodes
200
+ def before_search(self, curr_cycle): # would be better with a local trigger
201
+ #self._hide_msg_boxes(curr_cycle) # hide boxes overlapping new decodes
206
202
  self._hide_msg_boxes(curr_cycle = None) # hide all boxes
207
-
208
- def after_search(self, curr_cycle):
209
- self._refresh_hearing()
210
- self._refresh_band_buttons()
211
203
  self._refresh_home_panel()
212
- #self._clear_msg_boxes(curr_cycle)
204
+ self._refresh_band_buttons()
205
+ self._refresh_hearing()
213
206
 
214
207
  def display_message(self, message):
208
+ mb = self._get_message_box()
215
209
  x = int(message['t0'] / self.waterfall_data['dt'] + message['their_tx_cycle'] * self.waterfall_data['pixels_per_cycle'])
216
210
  y = int(message['fHz'] / self.waterfall_data['df'])
217
- mb = None
218
- for mb1 in self.msg_boxes:
219
- if not mb1.patch.get_visible():
220
- mb1.set_props(x, y, message)
221
- mb = mb1
222
- break
223
- if not mb:
224
- mb = Msg_box(self.fig, self.ax_wf, x, y, self.waterfall_data['sig_w'], self.waterfall_data['sig_h'], message)
225
- self.msg_boxes.append(mb)
226
- #print(f"{len(self.msg_boxes)} message boxes")
211
+ mb.set_props(x, y, message)
212
+ self.msg_boxes.append(mb)
227
213
 
228
214
  def update_message(self, display_text, update_dict):
229
215
  for mb in self.msg_boxes:
@@ -252,17 +238,34 @@ class Gui:
252
238
  color = row_text['color'])
253
239
  self.needs_redraw = True
254
240
 
241
+ def _get_message_box(self):
242
+ mb = None
243
+ for mb1 in self.msg_boxes:
244
+ if not mb1.patch.get_visible():
245
+ mb = mb1
246
+ break
247
+ if not mb:
248
+ mb = Msg_box(self.fig, self.ax_wf, self.waterfall_data['sig_w'], self.waterfall_data['sig_h'])
249
+ return mb
250
+
255
251
  def _set_band(self, band):
256
252
  if band in self.configured_bands:
257
253
  self.band_info = {'current_band':band, 'fMHz':self.configured_bands[band], 'time_set':time_utils.time()}
258
254
  self.console_print(f"[PyFT8] Set band: {self.band_info['current_band']} {self.band_info['fMHz']}")
259
- self._clear_msg_boxes()
255
+ for mb in self.msg_boxes:
256
+ mb.hide()
257
+ mb.remove()
258
+ self.msg_boxes = []
259
+ self._refresh_home_panel()
260
+ self._refresh_band_buttons()
261
+ self._refresh_hearing()
262
+ self.needs_redraw = True
260
263
 
261
264
  def _oncanvasclick(self, clickargs):
262
265
  if clickargs.inaxes is self.ax_wf:
263
266
  for mb in self.msg_boxes:
264
267
  if mb.contains(clickargs.x, clickargs.y):
265
- self.console_print(f"[GUI] Clicked on message '{mb.message['msg_text']}'")
268
+ self.console_print(f"[GUI] Clicked on message '{mb.message['msg_text']}")
266
269
  self.qso_manager.on_click({'action':"MESSAGE_CLICK", 'message':mb.message})
267
270
  return
268
271
  for bb in self.button_boxes:
@@ -271,7 +274,6 @@ class Gui:
271
274
  self.needs_redraw = True
272
275
  self._set_band(bb.id)
273
276
  self.qso_manager.on_click({'action':"SET_BAND", 'fMHz':self.configured_bands[bb.id]})
274
- self.after_search(curr_cycle = None)
275
277
  else:
276
278
  action = ["CQ", "RPT_LAST", "TX_OFF"][['CQ', 'Repeat last', 'Tx off'].index(bb.id)]
277
279
  self.qso_manager.on_click({'action':action})
@@ -281,19 +283,6 @@ class Gui:
281
283
  for mb in to_hide:
282
284
  mb.hide()
283
285
  self.needs_redraw = True
284
-
285
- def _clear_msg_boxes(self, curr_cycle = None):
286
- to_remove = [mb for mb in self.msg_boxes if (mb.cycle == curr_cycle) or (curr_cycle is None)]
287
- self.msg_boxes = [mb for mb in self.msg_boxes if (mb.cycle != curr_cycle) and not (curr_cycle is None)]
288
- for mb in to_remove:
289
- mb.hide()
290
- mb.remove()
291
- self.needs_redraw = True
292
-
293
- def _text_row(self, ax, x, y, text = '', color = 'white', **args):
294
- art = ax.text(x, y, text, color = color)
295
- art.set_fontfamily('monospace')
296
- return art
297
286
 
298
287
  def _refresh_home_panel(self):
299
288
  current_band = self.band_info['current_band']
@@ -34,7 +34,7 @@ class Broker():
34
34
  self.on_decode(message_dict)
35
35
  m = message_dict
36
36
  screen_format = f"{cyclestart_string} {their_snr} {m['dt']:4.1f} {m['fHz']:4.0f} ~ {hail} {their_call} {grid_rpt}"
37
- print(f"{screen_format:50s} decoded@ {m['decode_completed']:5.1f}s, dec = {m['decode_status']}")
37
+ print(f"{screen_format:50s} decoded@ {m['decode_completed'] %15:5.1f}s, dec = {m['decode_status']}")
38
38
  self.message_queue_non_time_critical.put(message_dict)
39
39
 
40
40
  def _process_message_ntc(self):
@@ -55,7 +55,6 @@ class Broker():
55
55
  new_display_text = f"{m['display_text']} {hearing_me} {wb_text} {geo_text}"
56
56
  self.gui.update_message( m['display_text'], {'hearing_me':hearing_me, 'wb_text':wb_text,
57
57
  'geo_text':geo_text, 'display_text':new_display_text } )
58
-
59
58
  if band_info:
60
59
  if m['their_call'] != 'not':
61
60
  if self.history:
@@ -11,7 +11,7 @@ from PyFT8.databases import ADIF
11
11
  from PyFT8.qso_manager import QSO_manager
12
12
  from PyFT8.message_broker import Broker
13
13
 
14
- VER = '3.6.6'
14
+ VER = '3.7.0'
15
15
  PSKR_REFRESH_MINS = 20
16
16
  message_broker = None
17
17
 
@@ -136,7 +136,7 @@ def cli():
136
136
  qso_manager = QSO_manager(message_broker, rig_control, console_print)
137
137
  message_broker.gui.register_qso_manager(qso_manager)
138
138
  message_broker.rx.register_before_search(message_broker.gui.before_search)
139
- message_broker.rx.register_after_search(message_broker.gui.after_search)
139
+ #message_broker.rx.register_after_search(message_broker.gui.after_search)
140
140
  message_broker.history.incorporate_log_data(qso_manager.adif_logging.cache)
141
141
  message_broker.history.start_collect_new()
142
142
 
@@ -592,7 +592,7 @@ class Receiver():
592
592
  'msg_text':f"{hail} {their_call} {grid_rpt}",
593
593
  'their_snr':f"{c.snr:+03d}", 'their_tx_cycle':c.origin['odd_even'],
594
594
  't0':c.origin['t0'], 'dt':c.origin['t0'] - 0.5, 'fHz':c.origin['f0'],
595
- 'decode_status':c.decode_status, 'decode_completed':time_utils.cycle_time()}
595
+ 'decode_status':c.decode_status, 'decode_completed':time_utils.time()}
596
596
  self.process_message(message_dict)
597
597
 
598
598
  if len(to_decode):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: PyFT8
3
- Version: 3.6.6
3
+ Version: 3.7.0
4
4
  Summary: FT8 Decoding and Encoding in Python with test/loopback code
5
5
  Author-email: G1OJS <g1ojs@yahoo.com>
6
6
  License-Expression: GPL-3.0-or-later
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "PyFT8"
3
- version = "3.6.6"
3
+ version = "3.7.0"
4
4
  license = "GPL-3.0-or-later"
5
5
 
6
6
  authors = [
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes