-
-
Notifications
You must be signed in to change notification settings - Fork 77
/
FortiusAnt.py
745 lines (660 loc) · 34.6 KB
/
FortiusAnt.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
#-------------------------------------------------------------------------------
# Version info
#-------------------------------------------------------------------------------
__version__ = "2023-03-17"
# 2023-03-17 #422 importlib not found; ignore that issue
# 2022-11-19 importlib_metadata_version used to print bless.version
# 2022-03-08 bleBless, bleBlessClass added
# 2021-04-29 If no hrm used (-H-1) thgen do not show on console.
# Leds shown on console
# 2021-03-22 Added; SetLeds
# 2021-03-03 Change 2020-12-16 undone; modification moved to GUI itself
# so that raspberry can powerdown.
# 2021-03-01 raspberry added
# 2021-02-25 Console message modified to fit on one line
# 2021-02-18 FortiusAntBody.Initialize() not called in the GUI-process
# FortiusAntBody.Terminate() before ending main()
# 2021-01-10 Digital gearbox changed to front/rear index
# 2021-01-06 settings added (+ missing other files for version check)
# 2020-12-24 usage of UseGui implemented
# 2020-12-20 Constants used from constants.py
# 2020-11-18 Logfile shows what version is started; windows exe or python
# 2020-12-16 Stopping the program is no longer possible from the head unit
# (#164 - to restart you have to get off your bike)
# 2020-11-13 Logfile was not closed on end
# 2020-11-05 New files added, githubWindowTitle() used
# 2020-05-24 WindowTitle in logfile
# 2020-04-23 First version; core functions separated into FortiusAntBody.py
# This module contains program startup, GUI-binding and
# multi-processing functionality only
#-------------------------------------------------------------------------------
from constants import mode_Power, mode_Grade, UseGui, UseBluetooth, UseMultiProcessing, OnRaspberry, mile
import constants # for __version__
import argparse
from datetime import datetime
try:
from importlib.metadata import version as importlib_metadata_version
except:
pass
import multiprocessing
import numpy
import pickle
import platform, glob
import os
import random
import sys
import struct
import threading
import time
import usb.core
import antCTRL
import antDongle as ant
import antHRM as hrm
import antFE as fe
import antPWR as pwr
import antSCS as scs
import bleBless
import bleBlessClass
import bleDongle
import debug
import logfile
import FortiusAntBody
import FortiusAntCommand as cmd
from FortiusAntTitle import githubWindowTitle
import raspberry
import settings
import structConstants as sc
import TCXexport
import usbTrainer
if UseGui:
import wx
import FortiusAntGui as gui
import RadarGraph
#-------------------------------------------------------------------------------
# Directives for this module
#-------------------------------------------------------------------------------
testMode = False # Production version should be False
#-------------------------------------------------------------------------------
# Constants between the two processes, exchanged through the pipe
#-------------------------------------------------------------------------------
cmd_EndExecution = 19590 # Child->Main; No response expected
cmd_Idle = 19591 # Child->Main; Response = Buttons
cmd_LocateHW = 19592 # Child->Main; Response = True/False for success/failure
cmd_Runoff = 19593 # Child->Main; Response = True
cmd_Tacx2Dongle = 19594 # Child->Main; Response = True
cmd_StopButton = 19595 # Child->Main; Response = True
cmd_Settings = 19596 # Child->Main; Response = True
cmd_SetMessages = 19596 # Main->Child; No response expected
cmd_SetValues = 19597 # Main->Child; No response expected
cmd_PedalStrokeAnalysis = 19598 # Main->Child; No response expected
cmd_SetLeds = 19599 # Main->Child; No response expected
# ==============================================================================
# The following functions are called from the GUI, Console or multi-processing
# parent process.
# The functions are used to test the multi-processing and/or GUI without
# being bothered by the actual FortiusAntBody/usbTrainer/antDongle functionality.
# ==============================================================================
def Settings(self, pRestartApplication, pclv):
global RestartApplication, clv
RestartApplication = pRestartApplication
clv = pclv
if debug.on(debug.Function):
logfile.Write ("FortiusAnt.Settings(%s, %s)" % (pRestartApplication, pclv.debug))
if testMode:
print('')
logfile.Console ('Transfer settings')
time.sleep(1)
logfile.Console ('Done')
rtn = True
else:
rtn = FortiusAntBody.Settings(self, pRestartApplication, pclv)
return rtn
def IdleFunction(self):
if testMode:
print ('i', end='')
sys.stdout.flush()
s = time.gmtime().tm_sec
if s % 4 == 0:
Buttons = usbTrainer.DownButton
else:
Buttons = 0
else:
Buttons = FortiusAntBody.IdleFunction(self)
return Buttons
def LocateHW(self):
if testMode:
print('')
logfile.Console ('Checking for HW')
time.sleep(1)
logfile.Console ('Done')
rtn = True
else:
rtn = FortiusAntBody.LocateHW(self)
return rtn
def Runoff(self):
if testMode:
print('')
while self.RunningSwitch:
logfile.Console ('Doing runoff')
self.SetMessages('Doing runoff', datetime.utcnow().strftime('%Y-%m-%d %H-%M-%S'), str(time.gmtime().tm_sec))
self.SetValues(0,1,time.gmtime().tm_sec,3,4,5,6,7,8,9,10)
time.sleep(1)
logfile.Console ('Runoff done')
rtn = True
else:
rtn = FortiusAntBody.Runoff(self)
return rtn
def Tacx2Dongle(self):
if testMode:
print('')
while self.RunningSwitch:
logfile.Console ('Translate Tacx 2 Dongle')
self.SetMessages('Translate Tacx 2 Dongle', datetime.utcnow().strftime('%Y-%m-%d %H-%M-%S'), str(time.gmtime().tm_sec))
self.SetValues(0,1,time.gmtime().tm_sec,3,4,5,6,7,8,9,10)
time.sleep(1)
logfile.Console ('Tacx2Dongle done')
rtn = True
else:
rtn = FortiusAntBody.Tacx2Dongle(self)
return rtn
# ==============================================================================
# Subclass FortiusAnt GUI with our directly called functions
# ------------------------------------------------------------------------------
# Called: IdleFunction, LocateHW(), Runoff() and Tacx2Dongle() are called
# to provide the required functionality.
# ==============================================================================
if UseGui:
class frmFortiusAnt(gui.frmFortiusAntGui):
def callSettings(self, RestartApplication, pclv):
return Settings(self, RestartApplication, pclv)
def callIdleFunction(self):
Buttons = IdleFunction(self)
# ----------------------------------------------------------------------
# IdleFunction checks trainer for headunit button press
# Since the GUI does not know the usbTrainer, we do this here
# ----------------------------------------------------------------------
if Buttons == usbTrainer.EnterButton: self.Navigate_Enter()
elif Buttons == usbTrainer.DownButton: self.Navigate_Down()
elif Buttons == usbTrainer.UpButton: self.Navigate_Up()
elif Buttons == usbTrainer.CancelButton:self.Navigate_Back()
else: pass
return True
def callLocateHW(self):
return LocateHW(self)
def callRunoff(self):
return Runoff(self)
def callTacx2Dongle(self):
return Tacx2Dongle(self)
# ==============================================================================
# Class to create a Console-GUI
# ------------------------------------------------------------------------------
# Functions: Autostart() is similar to frmFortiusAntGui.autostart
# and executes all program-functionality
# SetValues() and SetMessages() to show the progress on the console
#
# Called: LocateHW() and Tacx2Dongle() are called to provide the required
# functionality.
# ==============================================================================
class clsFortiusAntConsole:
def __init__(self):
self.RunningSwitch = False
self.LastTime = 0
self.leds = "- - -" # Remember leds for SetValues() on console
self.StatusLeds = [False,False,False,False,False] # 5 True/False flags
def Autostart(self):
if LocateHW(self):
self.RunningSwitch = True
Tacx2Dongle(self)
def SetValues(self, fSpeed, iRevs, iPower, iTargetMode, iTargetPower, \
fTargetGrade, iTacx, iHeartRate, iCrancksetIndex, iCassetteIndex, fReduction):
global clv
# ----------------------------------------------------------------------
# Console: Update current readings, once per second
# ----------------------------------------------------------------------
delta = time.time() - self.LastTime # Delta time since previous
if delta >= 1 and (not clv.gui or debug.on(debug.Application)):
self.LastTime = time.time() # Time in seconds
if clv.imperial:
s1 = fSpeed / mile
s2 = "mph"
else:
s1 = fSpeed
s2 = "km/h"
if iTargetMode == mode_Power:
sTarget = "%3.0fW" % iTargetPower
elif iTargetMode == mode_Grade:
sTarget = "%3.1f%%" % fTargetGrade
if iTargetPower > 0: # 2020-01-22
sTarget += "(%iW)" % iTargetPower # Target power added for reference
else:
sTarget = "None"
if clv.hrm == -1:
h = ""
else:
h = "hr=%3.0f " % iHeartRate
all = False
self.leds = ""
if all or True: # Led 1 = Tacx trainer; USB, ANT or Simulated
self.leds += "t" if self.StatusLeds[0] else "-"
if all or OnRaspberry: # Led 2 = on raspberry only
self.leds += "s" if self.StatusLeds[1] else "-"
if all or clv.Tacx_Cadence: # Led 3 = Cadence sensor (black because backgroup is white)
self.leds += "c" if self.StatusLeds[2] else "-"
if all or clv.ble: # Led 4 = Bluetooth CTP
self.leds += "b" if self.StatusLeds[3] else "-"
if all or clv.antDeviceID != -1: # Led 5 = ANT CTP
self.leds += "a" if self.StatusLeds[4] else "-"
msg = "Target=%s %4.1f%s %sCurrent=%3.0fW Cad=%3.0f r=%4.0f %3s%% %s" % \
(sTarget, s1,s2, h, iPower, iRevs, iTacx, int(fReduction*100), self.leds)
logfile.Console (msg)
def SetMessages(self, Tacx=None, Dongle=None, HRM=None):
if Tacx != None:
logfile.Console ("Tacx - " + Tacx)
if Dongle != None:
logfile.Console ("Dongle - " + Dongle)
if HRM != None:
logfile.Console ("AntHRM - " + HRM)
def SetLeds(self, ANT=None, BLE=None, Cadence=None, Shutdown=None, Tacx=None):
if self.leds != "":
self.leds = "" # leds only change after that the are displayed in SetValues()
# print (ANT, BLE, Cadence, Shutdown, Tacx, self.StatusLeds)
if Tacx != None: self.StatusLeds[0] = not self.StatusLeds[0] if Tacx else False
if Shutdown != None: self.StatusLeds[1] = not self.StatusLeds[1] if Shutdown else False
if Cadence != None: self.StatusLeds[2] = not self.StatusLeds[2] if Cadence else False
if BLE != None: self.StatusLeds[3] = not self.StatusLeds[3] if BLE else False
if ANT != None: self.StatusLeds[4] = not self.StatusLeds[4] if ANT else False
# ==============================================================================
# Subclass FortiusAnt GUI with our multi-processing functions
# ------------------------------------------------------------------------------
# Description: This class is functionally identical to frmFortiusAnt, with that
# difference that the required functions are not called, but
# requested through the multiprocessing pipe.
#
# Called: cmd_IdleFunction, cmd_LocateHW, cmd_Runoff and cmd_Tacx2Dongle
# are sent to the main process for execution and the response is
# received.
#
# Functions: For this purpose, GuiMessageToMain() is available.
# ==============================================================================
if UseGui:
class frmFortiusAntChild(gui.frmFortiusAntGui):
# --------------------------------------------------------------------------
# gui_conn is the child-connection to the parent process
# --------------------------------------------------------------------------
def __init__(self, parent, conn, pclv):
self.gui_conn = conn
super(frmFortiusAntChild, self).__init__(parent, pclv)
def GuiMessageToMain(self, command, wait=True, p1=None, p2=None):
# ----------------------------------------------------------------------
# Step 1. GUI sends a command to main
# ----------------------------------------------------------------------
if debug.on(debug.MultiProcessing) and not (command == cmd_Idle):
logfile.Write ("mp-GuiMessageToMain(conn, %s, %s, %s, %s)" % (command, wait, p1, p2))
self.gui_conn.send((command, p1, p2))
rtn = True
while wait:
# ------------------------------------------------------------------
# Check if requested command is ended
# OR that information is received from Main
# ------------------------------------------------------------------
# Will be more efficient than self.gui_conn.poll() / sleep loop...
# ------------------------------------------------------------------
# Step 4. GUI receives the response (command, rtn)
# ------------------------------------------------------------------
msg = self.gui_conn.recv()
cmd = msg[0]
rtn = msg[1]
if debug.on(debug.MultiProcessing) and not (command == cmd_Idle and rtn == 0):
logfile.Write ("mp-GuiAnswerFromMain(conn) returns (%s, %s)" % (cmd, rtn))
# ------------------------------------------------------------------
# We wait for the response on the command
# and in the meantime receive data to displayed
#
# cmd_StopButton is treated differently, since that command is sent
# while we are waiting for the response on cmd_Runoff or cmd_Tacx2Dongle
# we ignore the response here and cmd_StopButton does not start wait-loop
# to avoid some sort of nesting or so.
# ------------------------------------------------------------------
if cmd == command:
break # command is ready
elif cmd == cmd_StopButton:
pass
elif cmd == cmd_SetValues:
self.SetValues(rtn[0], rtn[1], rtn[2], rtn[3], rtn[4], rtn[5], rtn[6], rtn[7], rtn[8], rtn[9], rtn[10])# rtn is tuple
elif cmd == cmd_SetMessages:
self.SetMessages(rtn[0], rtn[1], rtn[2])# rtn is (Tacx, Dongle, HRM) tuple
elif cmd == cmd_PedalStrokeAnalysis:
self.PedalStrokeAnalysis(rtn[0], rtn[1])# rtn is (info, Cadence) tuple
elif cmd == cmd_SetLeds:
self.SetLeds(rtn[0], rtn[1], rtn[2], rtn[3], rtn[4])# rtn is (ANT, BLE, Cadence, Shutdown, Tacx) tuple
else:
logfile.Console('%s active but unknown response received (%s, %s); the message is ignored.' % (command, cmd, rtn))
break
return rtn
# --------------------------------------------------------------------------
# Multiprocessing;
# a command is sent to the parent process and the function waits for
# a response.
# Idle/LocateHW: the only response expected is the answer from the function
# Runoff/Tacx2Dongle: the main process can also send information to be displayed!
# --------------------------------------------------------------------------
def callSettings(self, RestartApplication, pclv):
rtn = self.GuiMessageToMain(cmd_Settings, True, RestartApplication, self.clv)
return rtn
def callIdleFunction(self):
Buttons = self.GuiMessageToMain(cmd_Idle) # Send command and wait response
# ----------------------------------------------------------------------
# IdleFunction checks trainer for headunit button press
# Since the GUI does not know the usbTrainer, we do this here
# ----------------------------------------------------------------------
if Buttons == usbTrainer.EnterButton: self.Navigate_Enter()
elif Buttons == usbTrainer.DownButton: self.Navigate_Down()
elif Buttons == usbTrainer.UpButton: self.Navigate_Up()
elif Buttons == usbTrainer.CancelButton:self.Navigate_Back()
else: pass
return True
def callLocateHW(self):
rtn = self.GuiMessageToMain(cmd_LocateHW) # Send command and wait response
return rtn
def callRunoff(self):
rtn = self.GuiMessageToMain(cmd_Runoff)
return rtn
def callTacx2Dongle(self):
rtn = self.GuiMessageToMain(cmd_Tacx2Dongle)
return rtn
def OnClick_btnStop(self, event=False):
gui.frmFortiusAntGui.OnClick_btnStop(self, event)
self.GuiMessageToMain(cmd_StopButton, False)
def OnClose(self, event):
if self.RunningSwitch == True: # Thread is running
self.GuiMessageToMain(cmd_StopButton, False)
gui.frmFortiusAntGui.OnClose(self, event)
# ==============================================================================
# Class to create a parent-process
# ------------------------------------------------------------------------------
# Description: This class creates the parent, which receives commands from the
# GUI child process, calls the required function and returns the
# result.
#
# Called: cmd_IdleFunction, cmd_LocateHW, cmd_Runoff and cmd_Tacx2Dongle
# are called and the response is sent to the child process.
#
# Functions: For this purpose, MainCommandFromGui() and MainRespondToGUI()
# are available.
#
# SetMessages() and SetValues() are called by the functions and
# send the data to be displayed to the child, not awaiting an
# answer.
#
# RunoffThread() and Tacx2DongleThread() act as function to create
# a thread to execute the functions, whilst not blocking the
# the process to receive messages from the GUI client, which can
# order to stop.
# ==============================================================================
class clsFortiusAntParent:
def __init__(self, app_conn):
self.RunningSwitch = False
self.app_conn = app_conn
self.LastTime = 0
self.PreviousMessages = None
def MainCommandFromGui(self): # Step 2. Main receives command from GUI
msg = self.app_conn.recv()
command = msg[0]
p1 = msg[1]
p2 = msg[2]
if debug.on(debug.MultiProcessing) and not (command == cmd_Idle):
logfile.Write ("mp-MainCommandFromGui() returns (%s, %s, %s)" % (command, p1, p2))
return command, p1, p2
def MainRespondToGUI(self, command, rtn):
if debug.on(debug.MultiProcessing) and not (command == cmd_Idle and rtn == 0):
logfile.Write ("mp-MainRespondToGUI(%s, %s)" % (command, rtn))
self.app_conn.send((command, rtn)) # Step 3. Main sends the response to GUI
def SetValues(self, fSpeed, iRevs, iPower, iTargetMode, iTargetPower, fTargetGrade, iTacx, iHeartRate, iCrancksetIndex, iCassetteIndex, fReduction):
delta = time.time() - self.LastTime # Delta time since previous call
if delta >= 1: # Do not send faster than once per second
self.LastTime = time.time() # Time in seconds
if debug.on(debug.MultiProcessing): logfile.Write ("mp-MainDataToGUI(%s, (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s))" % \
(cmd_SetValues, fSpeed, iRevs, iPower, iTargetMode, iTargetPower, fTargetGrade, iTacx, iHeartRate, iCrancksetIndex, iCassetteIndex, fReduction))
self.app_conn.send((cmd_SetValues, (fSpeed, iRevs, iPower, iTargetMode, iTargetPower, fTargetGrade, iTacx, iHeartRate, iCrancksetIndex, iCassetteIndex, fReduction)))
def SetMessages(self, Tacx=None, Dongle=None, HRM=None):
newMessages = (Tacx, Dongle, HRM)
if newMessages != self.PreviousMessages: # Send immediatly if changed
self.PreviousMessages = newMessages
if debug.on(debug.MultiProcessing): logfile.Write ("mp-MainDataToGUI(%s, (%s, %s, %s))" % (cmd_SetMessages, Tacx, Dongle, HRM))
self.app_conn.send((cmd_SetMessages, (Tacx, Dongle, HRM))) # x. Main sends messages to GUI; no response expected
def PedalStrokeAnalysis(self, info, Cadence):
if debug.on(debug.MultiProcessing): logfile.Write ("mp-MainDataToGUI(%s, (info, %s))" % (cmd_PedalStrokeAnalysis, Cadence))
self.app_conn.send((cmd_PedalStrokeAnalysis, (info, Cadence))) # x. Main sends messages to GUI; no response expected
def SetLeds(self, ANT=None, BLE=None, Cadence=None, Shutdown=None, Tacx=None):
if debug.on(debug.MultiProcessing): logfile.Write ("mp-MainDataToGUI(%s, (%s, %s, %s, %d, %s))" % (cmd_SetLeds, Tacx, Shutdown, Cadence, BLE, ANT))
self.app_conn.send((cmd_SetLeds, (ANT, BLE, Cadence, Shutdown, Tacx))) # x. Main sends messages to GUI; no response expected
def RunoffThread(self):
rtn = Runoff(self)
self.MainRespondToGUI(cmd_Runoff, rtn)
def Tacx2DongleThread(self):
rtn = Tacx2Dongle(self)
self.MainRespondToGUI(cmd_Tacx2Dongle, rtn)
def ListenToChild(self):
# ----------------------------------------------------------------------
# Poll the GUI what we are expected to do
# Note that we never end (on our initiative)!!
# ----------------------------------------------------------------------
while True:
gui_command, gui_p1, gui_p2 = self.MainCommandFromGui()
if gui_command == cmd_EndExecution:
break
elif gui_command == cmd_Settings:
rtn = Settings(self, gui_p1, gui_p2)
self.MainRespondToGUI(cmd_Settings, rtn)
elif gui_command == cmd_Idle:
rtn = IdleFunction(self)
self.MainRespondToGUI(cmd_Idle, rtn)
elif gui_command == cmd_LocateHW:
rtn = LocateHW(self)
self.MainRespondToGUI(cmd_LocateHW, rtn)
elif gui_command == cmd_Runoff:
self.RunningSwitch = True
thread = threading.Thread(target=self.RunoffThread)
thread.start()
elif gui_command == cmd_Tacx2Dongle:
self.RunningSwitch = True
thread = threading.Thread(target=self.Tacx2DongleThread)
thread.start()
elif gui_command == cmd_StopButton:
if testMode:
print('')
logfile.Console ('Stop button pressed')
self.RunningSwitch = False
self.MainRespondToGUI(cmd_StopButton, True)
else:
logfile.Console('Unexpected command from GUI: %s' % gui_command)
rtn = False
# ------------------------------------------------------------------------------
# F o r t i u s A n t C h i l d
# ------------------------------------------------------------------------------
# Input: clv Command line variables
# conn the child-side of the multiprocessing pipe
#
# Description: Here the user-interface is created.
# The user-interface will call the callback functions as defined
# above.
#
# Output: none
# ------------------------------------------------------------------------------
def FortiusAntChild(clv, conn):
# --------------------------------------------------------------------------
# Initialize the child process, create our own logfile
# --------------------------------------------------------------------------
debug.activate(clv.debug)
if debug.on(debug.Any):
logfile.Open('FortiusAntGUI')
logfile.Console('FortiusAnt GUI started in child-process')
# --------------------------------------------------------------------------
# Start the user-interface
# --------------------------------------------------------------------------
app = wx.App(0)
frame = frmFortiusAntChild(None, conn, clv)
app.SetTopWindow(frame)
frame.Show()
if clv.autostart:
frame.Autostart()
app.MainLoop()
# --------------------------------------------------------------------------
# Signal parent that we're done
# --------------------------------------------------------------------------
frame.GuiMessageToMain(cmd_EndExecution, False)
if debug.on(debug.Any):
logfile.Console('FortiusAnt GUI ended')
# ==============================================================================
# Main program
# ==============================================================================
def mainProgram():
global RestartApplication, clv
# --------------------------------------------------------------------------
# Initialize
# --------------------------------------------------------------------------
debug.deactivate()
if not RestartApplication: clv = cmd.CommandLineVariables()
debug.activate(clv.debug)
FortiusAntBody.Initialize(clv)
if debug.on(debug.Any):
logfile.Open()
logfile.Console("FortiusANT started")
logfile.Write (' Restart=%s debug=%s' % (RestartApplication, clv.debug))
clv.print()
logfile.Console("------------------")
RestartApplication = False
#-------------------------------------------------------------------------------
# Component info
#-------------------------------------------------------------------------------
if debug.on(debug.Any):
# ----------------------------------------------------------------------
if getattr(sys, 'frozen', False):
logfile.Write('Windows executable started')
else:
logfile.Write('Python version started')
# ----------------------------------------------------------------------
logfile.Write('Version info for the components' )
logfile.Write(githubWindowTitle())
s = " %20s = %s"
logfile.Write(s % ('FortiusAnt', __version__ ))
logfile.Write(s % ('antCTRL', antCTRL.__version__ ))
logfile.Write(s % ('antDongle', ant.__version__ ))
logfile.Write(s % ('antFE', fe.__version__ ))
logfile.Write(s % ('antHRM', hrm.__version__ ))
logfile.Write(s % ('antPWR', pwr.__version__ ))
logfile.Write(s % ('antSCS', scs.__version__ ))
logfile.Write(s % ('bleBless', bleBless.__version__ ))
logfile.Write(s % ('bleBlessClass', bleBlessClass.__version__ ))
logfile.Write(s % ('bleDongle', bleDongle.__version__ ))
logfile.Write(s % ('constants', constants.__version__ ))
logfile.Write(s % ('debug', debug.__version__ ))
logfile.Write(s % ('FortiusAntBody', FortiusAntBody.__version__ ))
logfile.Write(s % ('FortiusAntCommand', cmd.__version__ ))
if UseGui:
logfile.Write(s % ('FortiusAntGui', gui.__version__ ))
logfile.Write(s % ('logfile', logfile.__version__ ))
if UseGui:
logfile.Write(s % ('RadarGraph', RadarGraph.__version__ ))
logfile.Write(s % ('raspberry', raspberry.__version__ ))
logfile.Write(s % ('settings', settings.__version__ ))
logfile.Write(s % ('structConstants', sc.__version__ ))
logfile.Write(s % ('TCXexport', TCXexport.__version__ ))
logfile.Write(s % ('usbTrainer', usbTrainer.__version__ ))
# See https://github.com/kevincar/bless/issues/98
# importlib_metadata_version("modulename")
# does not work for argparse, binascii, math or os
# but works for bless and numpy
# I did not try them all.
logfile.Write(s % ('argparse', argparse.__version__ ))
try:
logfile.Write(s % ('bless', importlib_metadata_version("bless") ))
except:
pass
# logfile.Write(s % ('binascii', binascii.__version__ ))
# logfile.Write(s % ('math', math.__version__ ))
logfile.Write(s % ('numpy', numpy.__version__ ))
logfile.Write(s % ('os', os.name ))
if os.name == 'nt':
v = sys.getwindowsversion()
logfile.Write((s + '.%s') % ('windows', v.major, v.minor))
logfile.Write(s % ('pickle', pickle.format_version ))
logfile.Write(s % ('platform', platform.__version__ ))
# logfile.Write(s % ('glob', glob.__version__ ))
# logfile.Write(s % ('random', random.__version__ ))
logfile.Write(s % ('sys (python)', sys.version ))
# logfile.Write(s % ('struct', struct.__version__ ))
# logfile.Write(s % ('threading', threading.__version__ ))
# logfile.Write(s % ('time', time.__version__ ))
logfile.Write(s % ('usb', usb.__version__ ))
if UseGui:
logfile.Write(s % ('wx', wx.__version__ ))
logfile.Write('FortiusANT code flags')
logfile.Write(s % ('UseMultiProcessing', UseMultiProcessing))
logfile.Write(s % ('UseGui', UseGui))
logfile.Write(s % ('UseBluetooth', UseBluetooth))
logfile.Write("------------------")
#-------------------------------------------------------------------------------
# Modify ANT deviceNumbers if requested
#-------------------------------------------------------------------------------
if clv.DeviceNumberBase:
ant.DeviceNumberBase(clv.DeviceNumberBase)
if not clv.gui:
# --------------------------------------------------------------------------
# Console only, no multiprocessing required to separate GUI
# --------------------------------------------------------------------------
Console = clsFortiusAntConsole()
Console.Autostart()
elif not UseMultiProcessing:
# --------------------------------------------------------------------------
# No multiprocessing wanted, start GUI immediatly
# --------------------------------------------------------------------------
clv.PedalStrokeAnalysis = False
app = wx.App(0)
frame = frmFortiusAnt(None, clv)
app.SetTopWindow(frame)
frame.Show()
if clv.autostart:
frame.Autostart()
app.MainLoop()
else:
# --------------------------------------------------------------------------
# Multiprocessing wanted, start GUI in it's own process
# --------------------------------------------------------------------------
# https://docs.python.org/3/library/multiprocessing.html
# Create queue and sub-process
# --------------------------------------------------------------------------
app_conn, gui_conn = multiprocessing.Pipe(True)
pChild = multiprocessing.Process(target=FortiusAntChild, args=(clv, gui_conn) )
pChild.start()
# --------------------------------------------------------------------------
# Poll child-process untill done
# --------------------------------------------------------------------------
parent = clsFortiusAntParent(app_conn) # The child process has the GUI
parent.ListenToChild()
# --------------------------------------------------------------------------
# Wait for child-process to complete
# --------------------------------------------------------------------------
pChild.join()
# ------------------------------------------------------------------------------
# We're done
# ------------------------------------------------------------------------------
FortiusAntBody.Terminate()
if debug.on(debug.Any):
logfile.Console('FortiusAnt ended')
logfile.Close()
#-----------------------------------------------------------------------------------
# Main program; when restart is required due to new parameters we will loop
#-----------------------------------------------------------------------------------
if __name__ == "__main__":
multiprocessing.freeze_support()
global RestartApplication, clv
RestartApplication = False
while True:
mainProgram()
if not RestartApplication: break
# ------------------------------------------------------------------------------
# If so requested, shutdown Raspberry pi
# ------------------------------------------------------------------------------
if OnRaspberry:
raspberry.ShutdownIfRequested()