Beispiel #1
0
        def Read(self):
            if debug.on(debug.Ble): logfile.Write("BleInterface.Read() ...")
            rtn = False
            self.jsondata = None
            if self.interface:
                #-----------------------------------------------------------
                # Read from bluetooth interface
                #-----------------------------------------------------------
                try:
                    r = requests.get(f'http://{self.host}:{self.port}/ant')
                except Exception as e:
                    logfile.Console("... requests.get() error " + str(e))
                else:
                    #-------------------------------------------------------
                    # Now we have a response object r
                    # Which should contain a JSON object
                    #-------------------------------------------------------
                    if r.ok and r.text != "":
                        try:
                            self.jsondata = json.loads(r.text)
                        except Exception as e:
                            logfile.Console("... json.loads() error " + str(e))
                        else:
                            rtn = True

            if debug.on(debug.Ble):
                logfile.Write("... returns: %s (%s)" % (rtn, self.jsondata))
            return rtn
Beispiel #2
0
    def CheckShutdown(self, FortiusAntGui=None):
        repeat = 7  # timeout = n * .25 seconds        # 5 blinks is enough
        # 7 because the first two cycles are blink to allow
        #       for a "short button press" without messages.
        rtn = True  # Assume button will remain pressed
        # If we don't use leds/buttons ==> False
        ResetLeds = False

        if OnRaspberry and not IsShutdownRequested():
            # ------------------------------------------------------------------
            # Switch off shutdown led, just in case (only local)
            # ------------------------------------------------------------------
            self._Shutdown(False)

            # ------------------------------------------------------------------
            # Blink the (red) Shutdown led while button pressed
            # ------------------------------------------------------------------
            while repeat:
                if self.ShutdownButtonIsHeld():
                    if repeat <= 5:
                        self.SetLeds(False, False, False, True, False)
                        if FortiusAntGui != None:
                            FortiusAntGui.SetLeds(False, False, False, True,
                                                  False)
                        logfile.Console('Raspberry will be shutdown ... %s ' %
                                        repeat)
                    ResetLeds = True
                    time.sleep(.25)
                else:
                    rtn = False
                    break
                repeat -= 1

            # ------------------------------------------------------------------
            # Final warning
            # ------------------------------------------------------------------
            if rtn:
                self.PowerupTest()
                rtn = self.ShutdownButtonIsHeld()

            # ------------------------------------------------------------------
            # Now it's sure we will shutdown
            # The application has to do it, though.
            # ------------------------------------------------------------------
            if rtn:
                logfile.Console('Raspberry will shutdown')
                PrepareShutdown()

            # ------------------------------------------------------------------
            # If leds were touched, switch off all - application must set again
            # ------------------------------------------------------------------
            if not rtn and ResetLeds:
                self.SetLeds(False, False, False, False, False)
                if FortiusAntGui != None:
                    FortiusAntGui.SetLeds(False, False, False, False, False)

        # ----------------------------------------------------------------------
        # Return True/False; may be of previous shutdown-request!
        # ----------------------------------------------------------------------
        return IsShutdownRequested()
Beispiel #3
0
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')

    FortiusAntBody.Initialize(clv)

    # --------------------------------------------------------------------------
    # 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')
Beispiel #4
0
    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)
Beispiel #5
0
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
Beispiel #6
0
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
Beispiel #7
0
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)
            time.sleep(1)
        logfile.Console('Runoff done')
        rtn = True
    else:
        rtn = FortiusAntBody.Runoff(self)
    return rtn
Beispiel #8
0
    def SetValues(self,
                  fSpeed,
                  iRevs,
                  iPower,
                  iTargetMode,
                  iTargetPower,
                  fTargetGrade,
                  iTacx,
                  iHeartRate,
                  iTeeth,
                  extra=None):
        # ----------------------------------------------------------------------
        # 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 iTargetMode == gui.mode_Power:
                sTarget = "%3.0fW" % iTargetPower
            elif iTargetMode == gui.mode_Grade:
                sTarget = "%3.1f%%" % fTargetGrade
                if iTargetPower > 0:  # 2020-01-22
                    sTarget += "(%iW)" % iTargetPower  # Target power added for reference
            else:
                sTarget = "None"
            msg = "Target=%s Speed=%4.1fkmh hr=%3.0f Current=%3.0fW Cad=%3.0f r=%4.0f T=%3.0f" % \
                  (  sTarget,    fSpeed,  iHeartRate,       iPower,     iRevs,  iTacx, int(iTeeth) )
            logfile.Console(msg)
Beispiel #9
0
        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
                    pass
                else:
                    logfile.Console(
                        '%s active but unknown response received (%s, %s); the message is ignored.'
                        % (command, cmd, rtn))
                    break
            return rtn
Beispiel #10
0
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
Beispiel #11
0
    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
Beispiel #12
0
        def Open(self):
            self.OK = False
            self.Message = ", Bluetooth interface cannot be opened"
            if debug.on(debug.Ble): logfile.Write("BleInterface.Open() ...")

            if self.interface:
                if debug.on(debug.Ble): logfile.Write('... already open')
            else:
                #-----------------------------------------------------------
                # path to find ./node (in the parent of the directory where
                # 'we' are located) assuming directory structure:
                # ./node
                # ./pythoncode
                # ./WindowsExecutable
                #-----------------------------------------------------------
                if getattr(sys, 'frozen', False):
                    dirname = os.path.realpath(
                        sys.argv[0])  # the started executable
                else:
                    dirname = str(lib_programname.get_path_executed_script()
                                  )  # type: pathlib.Path
                dirname = os.path.dirname(
                    dirname)  # Remove /filename.py or /filename.exe
                dirname = dirname.replace('\\', '/')  # Unify separator = /
                dirname = dirname[0:dirname.rfind('/')]  # Remove last level

                #-----------------------------------------------------------
                # Create interface as sub-process
                #-----------------------------------------------------------
                command = ["node", "server.js"]
                directory = dirname + "/node"
                if debug.on(debug.Ble):
                    logfile.Write("... Popen(%s,%s)" % (directory, command))
                try:
                    if debug.on(debug.Any):
                        self.interface = subprocess.Popen(
                            command,
                            cwd=directory,
                            stdout=logfile.fLogfile,
                            stderr=logfile.fLogfile)
                    else:
                        self.interface = subprocess.Popen(command,
                                                          cwd=directory)
                except Exception as e:
                    self.Message += "; " + str(e)
                    if debug.on(debug.Ble): logfile.Write("... " + str(e))
                else:
                    if debug.on(debug.Ble): logfile.Write('... completed')
                    self.Message = ", Bluetooth interface open"
                    self.OK = True

            if self.OK:
                logfile.Console(
                    "FortiusANT exchanges data with a bluetooth Cycling Training Program"
                )
            return self.OK
Beispiel #13
0
 def Write(self, data):
     rtn = False
     if debug.on(debug.Ble):
         logfile.Write('BleInterface.Write(%s)' % data)
     if self.interface:
         url = f'http://{self.host}:{self.port}/ant'
         try:
             r = requests.post(url, data=data)
         except Exception as e:
             logfile.Console("... requests.post() error " + str(e))
         else:
             rtn = r.ok
     return rtn
Beispiel #14
0
    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)
Beispiel #15
0
 def print(self):
     try:
         v = debug.on(
             debug.Any
         )  # Verbose: print all command-line variables with values
         if self.autostart: logfile.Console("-a")
         if self.SimulateTrainer: logfile.Console("-s")
         if v or self.args.debug:
             logfile.Console("-d %s (%s)" % (self.debug, bin(self.debug)))
         if v or self.args.dongle:
             logfile.Console("-D %s (%s)" % (self.dongle, hex(self.dongle)))
         if v or self.args.hrm:
             logfile.Console("-H %s (%s)" % (self.hrm, hex(self.hrm)))
         if v or self.args.fe:
             logfile.Console("-F %s (%s)" % (self.fe, hex(self.fe)))
         if v or self.args.scs:
             logfile.Console("-S %s (%s)" % (self.scs, hex(self.scs)))
         if v or self.args.vtx:
             logfile.Console("-V %s (%s)" % (self.vtx, hex(self.vtx)))
     except:
         pass  # May occur when incorrect command line parameters, error already given before
Beispiel #16
0
 def Write(self, data):
     rtn = False
     retry = 10
     if debug.on(debug.Ble):
         logfile.Write('BleInterface.Write(%s)' % data)
     while retry and not rtn and self.interface:
         url = f'http://{self.host}:{self.port}/ant'
         try:
             r = requests.post(url, data=data)
         except Exception as e:
             msg = "... requests.post() error " + str(e)
             if retry and '[Errno 111]' in msg:
                 retry -= 1
                 time.sleep(0.250)
                 logfile.Write(msg)
             else:
                 retry = 0
                 logfile.Console(msg)
         else:
             rtn = r.ok
     return rtn
Beispiel #17
0
        def Open(self):
            self.OK = False
            self.Message = ", Bluetooth interface cannot be opened"
            if debug.on(debug.Ble): logfile.Write("BleInterface.Open() ...")

            if self.interface:
                if debug.on(debug.Ble): logfile.Write('... already open')
            else:
                #-----------------------------------------------------------
                # Create interface as sub-process
                #-----------------------------------------------------------
                command = ["node", "server.js"]
                directory = Path.cwd().parent / "node"
                if debug.on(debug.Ble):
                    logfile.Write("... Popen(%s,%s)" % (directory, command))
                try:
                    if debug.on(debug.Any):
                        self.interface = subprocess.Popen(
                            command,
                            cwd=directory,
                            stdout=logfile.fLogfile,
                            stderr=logfile.fLogfile)
                    else:
                        self.interface = subprocess.Popen(command,
                                                          cwd=directory)
                except Exception as e:
                    self.Message += "; " + str(e)
                    if debug.on(debug.Ble): logfile.Write("... " + str(e))
                else:
                    if debug.on(debug.Ble): logfile.Write('... completed')
                    self.Message = ", Bluetooth interface opened to CTP"
                    self.OK = True

            if self.OK:
                logfile.Console(
                    "FortiusANT exchanges data with a bluetooth Cycling Training Program"
                )
            return self.OK
    def print(self):
        try:
            v = debug.on(
                debug.Any
            )  # Verbose: print all command-line variables with values
            if self.autostart: logfile.Console("-a")
            if self.PedalStrokeAnalysis: logfile.Console("-A")
            if v or self.args.debug:
                logfile.Console("-d %s (%s)" % (self.debug, bin(self.debug)))
            if self.gui: logfile.Console("-g")
            if v or self.args.hrm: logfile.Console("-H %s" % self.hrm)
            if self.manual: logfile.Console("-m")
            if self.manualGrade: logfile.Console("-M")
            if not self.args.calibrate: logfile.Console("-n")
            if v or self.args.factor:
                logfile.Console("-p %s" % self.PowerFactor)
            if self.args.PowerMode: logfile.Console("-P")
            if self.args.simulate: logfile.Console("-s")
            #scs        if      self.args.scs:           logfile.Console("-S %s" % self.scs )
            if self.args.TacxType: logfile.Console("-t %s" % self.TacxType)
            if self.uphill: logfile.Console("-u")

            #-------------------------------------------------------------------
            # Deprecated
            #-------------------------------------------------------------------
#           if v or self.args.bicycle:       logfile.Console("-b %s,%s/%s,%s/%s" % (self.tyre, self.fL, self.fS, self.rS, self.rL))
#           if v or self.args.ftp:           logfile.Console("-f %s" % self.ftp )
#           if v or self.args.resistance:    logfile.Console("-r %s/%s" % (self.ResistanceH, self.ResistanceL))
        except:
            pass  # May occur when incorrect command line parameters, error already given before
Beispiel #19
0
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 % ('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 % ('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 % ('settings',             settings.__version__ ))
        logfile.Write(s % ('structConstants',            sc.__version__ ))
        logfile.Write(s % ('TCXexport',           TCXexport.__version__ ))
        logfile.Write(s % ('usbTrainer',         usbTrainer.__version__ ))

        logfile.Write(s % ('argparse',             argparse.__version__ ))
    #   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("------------------")

    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
    # ------------------------------------------------------------------------------
    if debug.on(debug.Any):
        logfile.Console('FortiusAnt ended')
        logfile.Close()
Beispiel #20
0
    def __init__(self, clv):
        global MySelf
        # ----------------------------------------------------------------------
        # Initialize
        # ----------------------------------------------------------------------
        self.clv = clv
        self.OK = OnRaspberry
        MySelf = self

        # ----------------------------------------------------------------------
        # Activate leds, if -l defined
        # Reason for -l is that usage of GPIO might be conflicting with other
        #       applications on the Raspberry
        # Activate display, if -O defined
        # ----------------------------------------------------------------------
        if self.OK:
            if OnRaspberry: self.StatusLeds = clv.StatusLeds  # boolean
            if OnRaspberry:
                self.OutputDisplay = clv.OutputDisplay and UseOutputDisplay  # string

            self.OK = self.StatusLeds or self.OutputDisplay

        # ----------------------------------------------------------------------
        # Create 5 leds on these Pins as outputs.
        # The numbers are the numbers of the IO-Pins of the Raspi
        # Don't forget to add the series resistor of 470 Ohm
        # ----------------------------------------------------------------------
        if self.StatusLeds:
            self.LedTacx = gpiozero.LED(clv.rpiTacx)  # Orange
            self.LedShutdown = gpiozero.LED(clv.rpiShutdown)  # Red
            self.LedCadence = gpiozero.LED(clv.rpiCadence)  # White
            self.LedBLE = gpiozero.LED(clv.rpiBLE)  # Blue
            self.LedANT = gpiozero.LED(clv.rpiANT)  # Green

            self.BtnShutdown = gpiozero.Button(clv.rpiButton)

        # ----------------------------------------------------------------------
        # Initialize OLED display
        # If NO display, the callable functions do nothing!
        # ----------------------------------------------------------------------
        # Currently the module is only written for st77889 240x240 pixels
        # future requests to implement other displays will reveal how much
        # must be changed to accomodate.
        # ----------------------------------------------------------------------
        self.DisplayState = self._DisplayStateConsole  # If invalid, on console
        self.SetValues = self._SetValuesConsole  # If invalid, on console
        self.DrawLeds = self._DrawLedsConsole  # If invalid, on console

        if clv.OutputDisplay == False:  # Not specified, no output
            self.DisplayState = self._DisplayStateNone
            self.SetValues = self._SetValuesNone
            self.DrawLeds = self._DrawLedsNone

        elif clv.OutputDisplay == 'console':  # Test output on console
            pass

        elif clv.OutputDisplay in ('st7789',
                                   'st7789b'):  # TFT mini OLED Display
            self.rotation = clv.OutputDisplayR
            if self._SetupDisplaySt7789(clv.OutputDisplay):
                self.DisplayState = self._DisplayStateSt7789
                self.SetValues = self._SetValuesSt7789
                self.DrawLeds = self._DrawLedsSt7789

        else:
            logfile.Console('Unexpected value for -O %s' % clv.OutputDisplay)

        self.DisplayState()

        # ----------------------------------------------------------------------
        # Show leds for power-up
        # ----------------------------------------------------------------------
        if self.StatusLeds:
            self.PowerupTest()
Beispiel #21
0
def ReceiveFromTrainer(devTrainer):
    global trainer_type

    Axis = 0
    Buttons = 0
    Cadence = 0
    CurrentPower = 0
    CurrentResistance = 0
    Error = ""
    HeartRate = 0
    PedalEcho = 0
    Speed = 0
    TargetResistance = 0

    #-----------------------------------------------------------------------------
    #  Read from trainer
    #-----------------------------------------------------------------------------
    data = ""
    try:
        data = devTrainer.read(0x82, 64, 30)
    except TimeoutError:
        pass
    except Exception as e:
        if "timeout error" in str(e) or "timed out" in str(
                e):  # trainer did not return any data
            pass
        else:
            logfile.Console("ReceiveFromTrainer: USB READ ERROR: " + str(e))
    if debug.on(debug.Data2):
        logfile.Write("Trainer recv data=%s (len=%s)" %
                      (logfile.HexSpace(data), len(data)))

    #-----------------------------------------------------------------------------
    # Handle data when > 40 bytes (boundary as derived from antifier)
    #-----------------------------------------------------------------------------
    if len(data) > 40 and LegacyProtocol == False:
        #---------------------------------------------------------------------------
        # Define buffer format
        #---------------------------------------------------------------------------
        nDeviceSerial = 0  # 0...1
        fDeviceSerial = sc.unsigned_short

        fFiller2_7 = sc.pad * (7 - 1)  # 2...7

        nYearProduction = 1  # 8
        fYearProduction = sc.unsigned_char

        fFiller9_11 = sc.pad * (11 - 8)  # 9...11

        nHeartRate = 2  # 12
        fHeartRate = sc.unsigned_char

        nButtons = 3  # 13
        fButtons = sc.unsigned_char

        nHeartDetect = 4  # 14
        fHeartDetect = sc.unsigned_char

        nErrorCount = 5  # 15
        fErrorCount = sc.unsigned_char

        nAxis0 = 6  # 16-17
        fAxis0 = sc.unsigned_short

        nAxis1 = 7  # 18-19
        fAxis1 = sc.unsigned_short

        nAxis2 = 8  # 20-21
        fAxis2 = sc.unsigned_short

        nAxis3 = 9  # 22-23
        fAxis3 = sc.unsigned_short

        nHeader = 10  # 24-27
        fHeader = sc.unsigned_int

        nDistance = 11  # 28-31
        fDistance = sc.unsigned_int

        nSpeed = 12  # 32, 33            Wheel speed (Speed = WheelSpeed / SpeedScale in km/h)
        fSpeed = sc.unsigned_short

        fFiller34_35 = sc.pad * 2  # 34...35           Increases if you accellerate?
        fFiller36_37 = sc.pad * 2  # 36...37           Average power?

        nCurrentResistance = 13  # 38, 39
        fCurrentResistance = sc.short

        nTargetResistance = 14  # 40, 41
        fTargetResistance = sc.short

        nEvents = 15  # 42
        fEvents = sc.unsigned_char

        fFiller43 = sc.pad  # 43

        nCadence = 16  # 44
        fCadence = sc.unsigned_char

        fFiller45 = sc.pad  # 45

        nModeEcho = 17  # 46
        fModeEcho = sc.unsigned_char

        nChecksumLSB = 18  # 47
        fChecksumLSB = sc.unsigned_char

        nChecksumMSB = 19  # 48
        fChecksumMSB = sc.unsigned_char

        fFiller49_63 = sc.pad * (63 - 48)  # 49...63

        format = sc.no_alignment + fDeviceSerial + fFiller2_7 + fYearProduction + \
                 fFiller9_11 + fHeartRate + fButtons + fHeartDetect + fErrorCount + \
                 fAxis0 + fAxis1 + fAxis2 + fAxis3 + fHeader + fDistance + fSpeed + \
                 fFiller34_35 + fFiller36_37 + fCurrentResistance + fTargetResistance + \
                 fEvents + fFiller43 + fCadence + fFiller45 + fModeEcho + \
                 fChecksumLSB + fChecksumMSB + fFiller49_63

        #---------------------------------------------------------------------------
        # Buffer must be 64 characters (struct.calcsize(format)),
        # Note that tt_FortiusSB returns 48 bytes only; append with dummy
        #---------------------------------------------------------------------------
        for v in range(64 - len(data)):
            data.append(0)

        #---------------------------------------------------------------------------
        # Parse buffer
        #---------------------------------------------------------------------------
        tuple = struct.unpack(format, data)
        Cadence = tuple[nCadence]
        HeartRate = tuple[nHeartRate]
        PedalEcho = tuple[nEvents]
        TargetResistance = tuple[nTargetResistance]
        CurrentResistance = tuple[nCurrentResistance]
        Speed = Wheel2Speed(tuple[nSpeed])
        CurrentPower = Resistance2Power(tuple[nCurrentResistance], Speed)

        Buttons = tuple[nButtons]
        Axis = tuple[nAxis1]

    elif LegacyProtocol == True:
        #---------------------------------------------------------------------------
        # Define buffer format
        #---------------------------------------------------------------------------
        nStatusAndCursors = 0  # 0
        fStatusAndCursors = sc.unsigned_char

        nSpeed = 1  # 1, 2      Wheel speed (Speed = WheelSpeed / SpeedScale in km/h)
        fSpeed = sc.unsigned_short

        nCadence = 2  # 3
        fCadence = sc.unsigned_char

        nHeartRate = 3  # 4
        fHeartRate = sc.unsigned_char

        nStopWatch = 4
        fStopWatch = sc.unsigned_int  # 5,6,7,8

        nCurrentResistance = 5  # 9
        fCurrentResistance = sc.unsigned_char

        nPedalSensor = 6  # 10
        fPedalSensor = sc.unsigned_char

        nAxis0 = 7  # 11
        fAxis0 = sc.unsigned_char

        nAxis1 = 8  # 12
        fAxis1 = sc.unsigned_char

        nAxis2 = 9  # 13
        fAxis2 = sc.unsigned_char

        nAxis3 = 10  # 14
        fAxis3 = sc.unsigned_char

        nCounter = 11  # 15
        fCounter = sc.unsigned_char

        nWheelCount = 12  # 16
        fWheelCount = sc.unsigned_char

        nYearProduction = 13  # 17
        fYearProduction = sc.unsigned_char

        nDeviceSerial = 14  # 18, 19
        fDeviceSerial = sc.unsigned_short

        nFirmwareVersion = 15  # 20
        fFirmwareVersion = sc.unsigned_char

        #---------------------------------------------------------------------------
        # Parse buffer
        # Note that the button-bits have an inversed logic:
        #   1=not pushed, 0=pushed. Hence the xor.
        #---------------------------------------------------------------------------
        format = sc.no_alignment + fStatusAndCursors + fSpeed + fCadence + fHeartRate + fStopWatch + fCurrentResistance + \
                 fPedalSensor + fAxis0 + fAxis1 + fAxis2 + fAxis3 + fCounter + fWheelCount + \
                 fYearProduction + fDeviceSerial + fFirmwareVersion
        tuple = struct.unpack(format, data)

        Cadence = tuple[nCadence]
        HeartRate = tuple[nHeartRate]
        PedalEcho = tuple[nPedalSensor]
        CurrentResistance = tuple[nCurrentResistance]
        TargetResistance = CurrentResistance  # Is not separately returned
        # is displayed by FortiusANT!
        Speed = Wheel2Speed(tuple[nSpeed])
        Buttons = ((tuple[nStatusAndCursors] & 0xf0) >> 4) ^ 0x0f
        Axis = tuple[nAxis1]

        CurrentPower = Resistance2Power(CurrentResistance, Speed)

    else:
        Error = "Not Found"

    if debug.on(debug.Function):
        logfile.Write ("ReceiveFromTrainer() = hr=%s Cadence=%s Speed=%s TargetRes=%s CurrentRes=%s CurrentPower=%s, pe=%s %s" % \
                                        (  HeartRate,   Cadence,   Speed, TargetResistance, CurrentResistance, CurrentPower, PedalEcho, Error) \
                      )

    return Error, Speed, PedalEcho, HeartRate, CurrentPower, Cadence, TargetResistance, CurrentResistance, Buttons, Axis
    def print(self):
        try:
            v = self.debug  # Verbose: print all command-line variables with values
            if self.autostart: logfile.Console("-a")
            if self.PedalStrokeAnalysis: logfile.Console("-A")
            if self.ble: logfile.Console("-b")
            if v or self.args.DeviceNumberBase:
                logfile.Console("-B %s" % self.DeviceNumberBase)
            if v or self.args.CalibrateRR:
                logfile.Console("-c %s" % self.CalibrateRR)
            if v or self.CTRL_SerialL or self.CTRL_SerialR:
                logfile.Console("-C %s/%s" %
                                (self.CTRL_SerialL, self.CTRL_SerialR))
            if v or self.args.debug:
                logfile.Console("-d %s (%s)" % (self.debug, bin(self.debug)))
            if v or self.args.antDeviceID:
                logfile.Console("-D %s" % self.antDeviceID)
            if v or self.args.GradeAdjust:
                if self.GradeAdjust == 1:                    logfile.Console("-G defines Grade = antGrade * %s" \
                              % (self.GradeFactor ) )
                if self.GradeAdjust == 2:                    logfile.Console("-G defines Grade = antGrade * %s [* %s (downhill)]" \
                              % (self.GradeFactor, self.GradeFactorDH) )
                if self.GradeAdjust == 3:                    logfile.Console("-G defines Grade = (antGrade - %s) * %s [* %s (downhill)]" \
                              % (self.GradeShift, self.GradeFactor, self.GradeFactorDH) )
            if self.gui: logfile.Console("-g")
            if self.homeTrainer: logfile.Console("-e")
            if v or self.args.hrm: logfile.Console("-H %s" % self.hrm)
            if self.StatusLeds: logfile.Console("-l")
            if OnRaspberry and (v or self.args.gpioLayout):
                logfile.Console(
                    "-L %s/%s/%s/%s/%s/%s" %
                    (self.rpiButton, self.rpiTacx, self.rpiShutdown,
                     self.rpiCadence, self.rpiBLE, self.rpiANT))
            if self.manual: logfile.Console("-m")
            if self.manualGrade: logfile.Console("-M")
            if self.imperial: logfile.Console("-i")
            if not self.args.calibrate: logfile.Console("-n")
            if v or self.args.factor:
                logfile.Console("-p %s" % self.PowerFactor)
            if v or self.args.OutputDisplay:
                logfile.Console("-O %s" % self.OutputDisplay)
            if self.args.PowerMode: logfile.Console("-P")
            if self.args.Resistance: logfile.Console("-r")
            if v or self.args.Runoff:                logfile.Console("-R defines Runoff: maxSpeed=%s dip=%s minSpeed=%s targetTime=%s power=%s" % \
(self.RunoffMaxSpeed, self.RunoffDip, self.RunoffMinSpeed, self.RunoffTime, self.RunoffPower) )
            if self.args.simulate: logfile.Console("-s")
            #scs        if v or self.args.scs:           logfile.Console("-S %s" % self.scs )
            if v or self.args.TacxType:
                logfile.Console("-t %s" % self.TacxType)
            #           if v or self.args.Transmission != constants.Transmission:
            if v or self.args.Transmission:
                logfile.Console('-T %s x %s (start=%sx%s)' % \
                                        (self.Cranckset, self.Cassette, \
                                         self.Cranckset[self.CrancksetStart], \
                                         self.Cassette [self.CassetteStart]) )
            if self.exportTCX: logfile.Console("-x")

        except:
            pass  # May occur when incorrect command line parameters, error already given before
Beispiel #23
0
# Description:  Show all dongles available
#               Open defined dongle
#               Start listening what's going on in the air
#
# Output:       Console/logfile
#
# Returns:      None
# ------------------------------------------------------------------------------

debug.deactivate()
clv = cmd.CommandLineVariables()
debug.activate(clv.debug)

if True or debug.on(debug.Any):
    logfile.Open('ExplorANT')
    logfile.Console("ExplorANT started")

    s = " %17s = %s"
    logfile.Console(s % ('ExplorANT', __version__))
    logfile.Console(s % ('antDongle', ant.__version__))

    clv.print()
    logfile.Console("--------------------")

# ------------------------------------------------------------------------------
# First enumerate all dongles
# ------------------------------------------------------------------------------
ant.EnumerateAll()

# ------------------------------------------------------------------------------
# Open dongle; either the defined one or default
Beispiel #24
0
    def _SetupDisplaySt7789(self, clv_OutputDisplay):
        rtn = True
        # ----------------------------------------------------------------------
        # Create the ST7789 display (this is 240x240 version):
        # ----------------------------------------------------------------------
        cs_pin = digitalio.DigitalInOut(board.CE0)
        dc_pin = digitalio.DigitalInOut(board.D25)
        reset_pin = None

        BAUDRATE = 64000000  # Default max is 24Mhz
        try:
            spi = board.SPI()  # Setup SPI bus using hardware SPI
        except Exception as e:
            logfile.Console("OLED display st7789 cannot be initialized: %s" %
                            e)
            rtn = False
        else:
            # ------------------------------------------------------------------
            # Now initialize the display
            # ------------------------------------------------------------------
            self.st7789 = st7789.ST7789(
                spi,
                cs=cs_pin,
                dc=dc_pin,
                rst=reset_pin,
                baudrate=BAUDRATE,
                width=240,
                height=240,
                x_offset=0,
                y_offset=80,
            )

            # ------------------------------------------------------------------
            # As copied from https://learn.adafruit.com
            # For testing
            # ------------------------------------------------------------------
            self.backlight = digitalio.DigitalInOut(board.D22)
            self.backlight.switch_to_output()
            self.backlight.value = True

            assert (clv_OutputDisplay in ('st7789', 'st7789b'))
            if clv_OutputDisplay == 'st7789':
                self.buttonA = digitalio.DigitalInOut(board.D23)
                self.buttonB = digitalio.DigitalInOut(board.D24)

            elif clv_OutputDisplay == 'st7789b':  # Add Waveshare 1.3 LCD
                self.buttonA = digitalio.DigitalInOut(board.D20)
                self.buttonB = digitalio.DigitalInOut(board.D16)
                # --------------------------------------------------------------
                # The Waveshare is missing the reset circuit from the Adafruit
                # display, the reset_pin needs to be defined.
                # --------------------------------------------------------------
                cs_pin = digitalio.DigitalInOut(board.CE0)
                dc_pin = digitalio.DigitalInOut(board.D25)
                reset_pin = digitalio.DigitalInOut(board.D27)

            self.buttonA.switch_to_input(digitalio.Pull.UP)
            self.buttonB.switch_to_input(digitalio.Pull.UP)

            self.ButtonDefaultValue = self.buttonA.value
            # ------------------------------------------------------------------
            # Startup image is in directory of the .py [or embedded in .exe]
            # ------------------------------------------------------------------
            dirname = os.path.dirname(__file__)
            FortiusAnt_jpg = os.path.join(dirname, "FortiusAnt.jpg")
            self.faImage = Image.open(FortiusAnt_jpg)

            # ------------------------------------------------------------------
            # Scale the image to the smaller screen dimension:
            # ------------------------------------------------------------------
            image_ratio = self.faImage.width / self.faImage.height
            screen_ratio = self.st7789.width / self.st7789.height
            if screen_ratio < image_ratio:
                scaled_width = self.faImage.width * self.st7789.height // self.faImage.height
                scaled_height = self.st7789.height
            else:
                scaled_width = self.st7789.width
                scaled_height = self.faImage.height * self.st7789.width // self.faImage.width
            self.faImage = self.faImage.resize((scaled_width, scaled_height),
                                               Image.BICUBIC)

            # ------------------------------------------------------------------
            # Crop and center the image:
            # ------------------------------------------------------------------
            x_jpg = scaled_width // 2 - self.st7789.width // 2
            y_jpg = scaled_height // 2 - self.st7789.height // 2
            self.faImage = self.faImage.crop(
                (x_jpg, y_jpg, x_jpg + self.st7789.width,
                 y_jpg + self.st7789.height))

            #-------------------------------------------------------------------
            # Load a TTF font - other good fonts available from: http://www.dafont.com/bitmap.php
            #-------------------------------------------------------------------
            self.fontS = ImageFont.truetype(
                "/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf", 22)
            self.fontLb = ImageFont.truetype(
                "/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf", 36)

            # ------------------------------------------------------------------
            # Display image, for at least three seconds
            # ------------------------------------------------------------------
            self._ShowImage()
            time.sleep(3)

            #-------------------------------------------------------------------
            # Part 2: display control text
            # Create blank image for drawing with mode 'RGB' for full color
            # Get drawing object to draw on image
            #-------------------------------------------------------------------
            self.image = Image.new("RGB",
                                   (self.st7789.width, self.st7789.height))
            self.draw = ImageDraw.Draw(self.image)

        return rtn
    def __init__(self):
        global clv
        clv = self
        #-----------------------------------------------------------------------
        # Define and process command line
        # Ref: https://docs.python.org/3/library/argparse.html
        #-----------------------------------------------------------------------
        parser = argparse.ArgumentParser(
            description=
            'FortiusAnt exchanges data between USB or ANT+ Tacx trainer with an ANT+ or BLE Cycling Training Program'
        )
        parser.add_argument('-a',
                            dest='autostart',
                            help=constants.help_a,
                            required=False,
                            action='store_true')
        if UseGui:
            parser.add_argument('-A',
                                dest='PedalStrokeAnalysis',
                                help=constants.help_A,
                                required=False,
                                action='store_true')
        else:
            parser.add_argument('-A',
                                dest='A_IgnoredIfDefined',
                                help=argparse.SUPPRESS,
                                required=False,
                                action='store_true')
        if UseBluetooth:
            parser.add_argument('-b',
                                dest='ble',
                                help=constants.help_b,
                                required=False,
                                action='store_true')
        else:
            pass  # If -b is requested but not available, then an error is appropriate
        parser.add_argument('-B',
                            dest='DeviceNumberBase',
                            metavar='0...65535',
                            help=constants.help_B,
                            required=False,
                            default=False,
                            type=int)
        parser.add_argument('-c',
                            dest='CalibrateRR',
                            metavar='0...100',
                            help=constants.help_c,
                            required=False,
                            default=False,
                            type=int)
        #       parser.add_argument   ('-C', dest='CtrlCommand',        metavar='ANT+DeviceID', help=constants.help_C,  required=False, default=False, type=int)
        parser.add_argument('-C',
                            dest='CtrlCommand',
                            metavar='ANT+DeviceID',
                            help=argparse.SUPPRESS,
                            required=False,
                            default=False,
                            type=int)
        parser.add_argument('-d',
                            dest='debug',
                            metavar='0...255',
                            help=constants.help_d,
                            required=False,
                            default=False,
                            type=int)
        parser.add_argument('-D',
                            dest='antDeviceID',
                            metavar='USB-DeviceID',
                            help=constants.help_D,
                            required=False,
                            default=False,
                            type=int)
        parser.add_argument('-e',
                            dest='homeTrainer',
                            help=constants.help_e,
                            required=False,
                            action='store_true')
        #                       -h     help!!
        if UseGui:
            parser.add_argument('-g',
                                dest='gui',
                                help=constants.help_g,
                                required=False,
                                action='store_true')
        else:
            parser.add_argument('-g',
                                dest='g_IgnoredIfDefined',
                                help=argparse.SUPPRESS,
                                required=False,
                                action='store_true')
        parser.add_argument('-G',
                            dest='GradeAdjust',
                            metavar='% / % / %',
                            help=constants.help_G,
                            required=False,
                            default=False)
        parser.add_argument('-H',
                            dest='hrm',
                            metavar='ANT+DeviceID',
                            help=constants.help_H,
                            required=False,
                            default=False,
                            type=int)
        parser.add_argument('-i',
                            dest='imperial',
                            help=constants.help_i,
                            required=False,
                            action='store_true')
        if UseGui or OnRaspberry:
            parser.add_argument('-l',
                                dest='StatusLeds',
                                help=constants.help_l,
                                required=False,
                                action='store_true')
        else:
            parser.add_argument('-l',
                                dest='l_IgnoredIfDefined',
                                help=argparse.SUPPRESS,
                                required=False,
                                action='store_true')
        if OnRaspberry:
            parser.add_argument('-L',
                                dest='gpioLayout',
                                metavar='gpioLayout',
                                help=constants.help_L,
                                required=False,
                                default=False)
        else:
            parser.add_argument('-L',
                                dest='-L_IgnoredIfDefined',
                                help=argparse.SUPPRESS,
                                required=False,
                                default=False)
        parser.add_argument('-m',
                            dest='manual',
                            help=constants.help_m,
                            required=False,
                            action='store_true')
        parser.add_argument('-M',
                            dest='manualGrade',
                            help=constants.help_M,
                            required=False,
                            action='store_true')
        parser.add_argument('-n',
                            dest='calibrate',
                            help=constants.help_n,
                            required=False,
                            action='store_false')
        if OnRaspberry:
            parser.add_argument('-O',
                                dest='OutputDisplay',
                                metavar='see text',
                                help=constants.help_O,
                                required=False,
                                default=False)
        else:
            parser.add_argument('-O',
                                dest='O_IgnoredIfDefined',
                                help=argparse.SUPPRESS,
                                required=False,
                                default=False)
        parser.add_argument('-p',
                            dest='factor',
                            metavar='%',
                            help=constants.help_p,
                            required=False,
                            default=False,
                            type=int)
        parser.add_argument('-P',
                            dest='PowerMode',
                            help=constants.help_P,
                            required=False,
                            action='store_true')
        parser.add_argument('-r',
                            dest='Resistance',
                            help=constants.help_r,
                            required=False,
                            action='store_true')
        parser.add_argument('-R',
                            dest='Runoff',
                            metavar='see text',
                            help=constants.help_R,
                            required=False,
                            default=False)
        parser.add_argument('-s',
                            dest='simulate',
                            help=constants.help_s,
                            required=False,
                            action='store_true')
        #scs    parser.add_argument   ('-S', dest='scs',                metavar='ANT+ DeviceID',help=constants.help_S,  required=False, default=False, type=int)
        parser.add_argument('-T',
                            dest='Transmission',
                            metavar='see text',
                            help=constants.help_T,
                            required=False,
                            default=False)
        self.ant_tacx_models = [
            'Bushido', 'Genius', 'Vortex', 'Magneticbrake', 'Motorbrake'
        ]
        parser.add_argument   ('-t', dest='TacxType',                                   help=constants.help_t, required=False, default=False, \
                    choices=self.ant_tacx_models + ['i-Vortex'])
        # i-Vortex is still allowed for compatibility
        parser.add_argument('-x',
                            dest='exportTCX',
                            help=constants.help_x,
                            required=False,
                            action='store_true')

        #-----------------------------------------------------------------------
        # Parse command line
        # Overwrite from json file if present
        #-----------------------------------------------------------------------
        self.args = parser.parse_args()
        jsonLoaded = settings.ReadJsonFile(self.args)

        #-----------------------------------------------------------------------
        # If nothing specified at all, use sensible defaults
        #-----------------------------------------------------------------------
        if len(sys.argv) == 1 and not jsonLoaded:
            pgm = max(sys.argv[0].rfind('/'), sys.argv[0].rfind('\\')) + 1
            pgm = sys.argv[0][pgm:]
            print(
                '---------------------------------------------------------------'
            )
            print('Hello!')
            print(
                'You have started FortiusANT without command-line parameters.')
            print(' ')
            print('Therefore we start with a best-practice setting:')
            print('     %s -a -g -H0 -A -l' % pgm)
            print(' ')
            print('If you want to start without the graphical user interface:')
            print('     %s -a' % pgm)
            print(' ')
            print('For more info, please refer to the wiki on github.')
            print('Success!')
            self.args.autostart = True
            self.args.gui = UseGui  # Show gui
            self.args.hrm = 0  # Pair with HRM
            self.args.PedalStrokeAnalysis = UseGui  # Show it
            self.args.StatusLeds = UseGui  # Show it

        #-----------------------------------------------------------------------
        # Display welcome message
        #-----------------------------------------------------------------------
        print(
            '---------------------------------------------------------------')
        print('FortiusANT is open source and can be used freely.')
        print('')
        print('Just for the fun of knowing where you all are training,')
        print('put yourself on the FortiusANT map by making yourself known')
        print('by leaving a message with name/location/trainer on')
        print('https://github.com/WouterJD/FortiusANT/issues/14')
        print('')
        print(
            'or visit the sponsoring page https://github.com/sponsors/WouterJD'
        )
        print(
            '---------------------------------------------------------------')

        #-----------------------------------------------------------------------
        # Booleans; either True or False
        #-----------------------------------------------------------------------
        self.autostart = self.args.autostart
        if UseBluetooth:
            self.ble = self.args.ble
        if UseGui:
            self.gui = self.args.gui
        self.homeTrainer = self.args.homeTrainer  # Exersize Bike
        self.StatusLeds = self.args.StatusLeds
        self.imperial = self.args.imperial
        self.manual = self.args.manual
        self.manualGrade = self.args.manualGrade
        self.calibrate = self.args.calibrate
        self.PowerMode = self.args.PowerMode
        if UseGui:
            self.PedalStrokeAnalysis = self.args.PedalStrokeAnalysis
        self.Resistance = self.args.Resistance
        self.SimulateTrainer = self.args.simulate
        self.exportTCX = self.args.exportTCX or self.homeTrainer or self.manual or self.manualGrade

        i = 0
        if self.homeTrainer: i += 1
        if self.manual: i += 1
        if self.manualGrade: i += 1

        if i > 1:
            logfile.Console(
                "Only one of -h, -m and -M may be specified; manual power selected"
            )
            self.homeTrainer = False
            self.manual = True
            self.manualGrade = False

        if (self.homeTrainer or self.manual
                or self.manualGrade) and self.SimulateTrainer:
            logfile.Console(
                "-e/-m/-M and -s both specified, most likely for program test purpose"
            )

        #-----------------------------------------------------------------------
        # Get DeviceNumberBase
        #-----------------------------------------------------------------------
        if self.args.DeviceNumberBase:
            try:
                self.DeviceNumberBase = int(self.args.DeviceNumberBase)
            except:
                logfile.Console(
                    'Command line error; -B incorrect DeviceNumber Base=%s' %
                    self.args.DeviceNumberBase)

        #-----------------------------------------------------------------------
        # Get calibration of Rolling Resistance
        # Not limitted to a range here, because can be different for different
        #       types of brakes, although initially only used for Magnetic Brake
        #-----------------------------------------------------------------------
        if self.args.CalibrateRR:
            try:
                self.CalibrateRR = float(
                    self.args.CalibrateRR.replace(',', '.'))
            except:
                logfile.Console(
                    'Command line error; -c incorrect calibration of Rolling Resistance=%s'
                    % self.args.CalibrateRR)

        #-----------------------------------------------------------------------
        # Get CtrlCommand = Serial#1/Serial#2
        #-----------------------------------------------------------------------
        if self.args.CtrlCommand:
            s = self.args.CtrlCommand.split("/")
            try:
                assert (len(s) <= 2)

                if len(s) >= 1: self.CTRL_SerialL = int(s[0])
                if len(s) >= 2: self.CTRL_SerialR = int(s[1])

                assert (self.CTRL_SerialL >= 0)
                assert (self.CTRL_SerialR >= 0)
            except:
                logfile.Console(
                    'Command line error; -C incorrect SerialNumber in %s' %
                    self.args.CtrlCommand)

        #-----------------------------------------------------------------------
        # Get OutputDisplay
        #-----------------------------------------------------------------------
        if OnRaspberry and self.args.OutputDisplay:
            s = self.args.OutputDisplay.split("/")
            try:
                assert (len(s) <= 2)

                if len(s) >= 1: self.OutputDisplay = s[0]
                if len(s) >= 2: self.OutputDisplayR = int(s[1])  # Rotation

                if self.OutputDisplay == 'display':
                    self.OutputDisplay = 'st7789'  # Default device driver
                    # As long as no more devices supported, no reason to bother user
                    # Like this we're ready for other devices in future

                assert (self.OutputDisplay in ('console', 'st7789'))
                assert (self.OutputDisplayR in (0, 90, 180, 270))

                assert (self.CTRL_SerialL >= 0)
                assert (self.CTRL_SerialR >= 0)
            except:
                logfile.Console(
                    'Command line error; -O incorrect OutputDisplay in %s' %
                    self.args.CtrlCommand)

            #---------------------------------------------------------------
            # OutputDisplay uses first 24 pins, so our button moves
            # Refer to pinlayout in raspberry.py
            #---------------------------------------------------------------
            if self.OutputDisplay == 'st7789':
                self.rpiButton = 16

        #-----------------------------------------------------------------------
        # Get Raspberry GPIO Layout = Button/Tacx/Shutdown/Cadence/BLE/ANT
        #-----------------------------------------------------------------------
        if OnRaspberry and self.args.gpioLayout:
            s = self.args.gpioLayout.split("/")
            try:
                e = 'Too many GPIO pins defined'
                assert (len(s) <= 6)

                e = 'Pin number not numeric'
                if len(s) >= 1: self.rpiButton = int(s[0])
                if len(s) >= 2: self.rpiTacx = int(s[1])
                if len(s) >= 3: self.rpiShutdown = int(s[2])
                if len(s) >= 4: self.rpiCadence = int(s[3])
                if len(s) >= 5: self.rpiBLE = int(s[4])
                if len(s) >= 6: self.rpiANT = int(s[5])

                # https://gpiozero.readthedocs.io/en/stable/recipes.html#pin-numbering
                e = 'Pin number not in range 2...27'
                assert (self.rpiButton in range(2, 28))
                assert (self.rpiTacx in range(2, 28))
                assert (self.rpiShutdown in range(2, 28))
                assert (self.rpiCadence in range(2, 28))
                assert (self.rpiBLE in range(2, 28))
                assert (self.rpiANT in range(2, 28))

                e = 'Pin number used twice'
                assert (self.rpiButton
                        not in (self.rpiTacx, self.rpiShutdown,
                                self.rpiCadence, self.rpiBLE, self.rpiANT))
                assert (self.rpiTacx
                        not in (self.rpiButton, self.rpiShutdown,
                                self.rpiCadence, self.rpiBLE, self.rpiANT))
                assert (self.rpiShutdown
                        not in (self.rpiButton, self.rpiTacx, self.rpiCadence,
                                self.rpiBLE, self.rpiANT))
                assert (self.rpiCadence
                        not in (self.rpiButton, self.rpiTacx, self.rpiShutdown,
                                self.rpiBLE, self.rpiANT))
                assert (self.rpiBLE
                        not in (self.rpiButton, self.rpiTacx, self.rpiShutdown,
                                self.rpiCadence, self.rpiANT))
                assert (self.rpiANT
                        not in (self.rpiButton, self.rpiTacx, self.rpiShutdown,
                                self.rpiCadence, self.rpiBLE))
            except:
                logfile.Console(
                    'Command line error; -L incorrect pin-number in %s; %s' %
                    (self.args.gpioLayout, e))

        #-----------------------------------------------------------------------
        # Get debug-flags, used in debug module
        #-----------------------------------------------------------------------
        if self.args.debug:
            try:
                self.debug = int(self.args.debug)
            except:
                logfile.Console(
                    'Command line error; -d incorrect debugging flags=%s' %
                    self.args.debug)

        #-----------------------------------------------------------------------
        # Get antDeviceID
        #-----------------------------------------------------------------------
        if self.args.antDeviceID:
            try:
                self.antDeviceID = int(self.args.antDeviceID)
            except:
                logfile.Console(
                    'Command line error; -D incorrect antDeviceID=%s' %
                    self.args.antDeviceID)

        #-----------------------------------------------------------------------
        # Get HRM
        # - None: read HRM from Tacx Fortius and broadcast as HRM master device
        # - -1  : no master and no slave device
        # - 0   : pair with the first ANT+ HRM that is found
        # - next: pair with the defined ANT+ HRM monitor
        #             the number can be found with ExplorANT
        #-----------------------------------------------------------------------
        if self.args.hrm:
            try:
                self.hrm = int(self.args.hrm)
            except:
                logfile.Console('Command line error; -H incorrect HRM=%s' %
                                self.args.hrm)

        #-----------------------------------------------------------------------
        # Get SCS
        # - None: No Speed Cadence Sensor
        # - 0   : pair with the first ANT+ SCS that is found
        # - next: pair with the defined ANT+ SCS
        #             the number can be found with ExplorANT
        #-----------------------------------------------------------------------
#scs    if self.args.scs:
#scs        try:
#scs            self.scs = int(self.args.scs)
#scs        except:
#scs            logfile.Console('Command line error; -S incorrect SCS=%s' % self.args.scs)

#-----------------------------------------------------------------------
# Get powerfactor
#-----------------------------------------------------------------------
        if self.args.factor:
            try:
                self.PowerFactor = int(self.args.factor) / 100
                # I would expect +/- 15% would be enough for compensation, but
                # reactions from "the field" have reported 35% difference.
                # So the range became 50% ... 150%
                #
                # If the power is good and you specify 50% then you will report
                # 500 Watt when producing 250Watt and ... you're cheating...
                #
                # HomeTrainer users may want a low resistance but a reasonable
                # power on Zwift or Strava, otherwise the mountain becomes
                # endless. So the lower range is set to 20%.
                # When producing 50 Watts, Rouvy will receive 250 Watt and you
                # can cycle uphill.
                self.PowerFactor = max(0.2, min(1.5, self.PowerFactor))
            except:
                logfile.Console(
                    'Command line error; -p incorrect power factor=%s' %
                    self.args.factor)

        #-----------------------------------------------------------------------
        # Get GradeAdjust = shift/factor
        # Motor Brake default              = -G 100/100
        # Magnetic Brake suggested (Rouvy) = -G  50/100
        #-----------------------------------------------------------------------
        if self.args.GradeAdjust:
            s = self.args.GradeAdjust.split("/")
            self.GradeAdjust = len(s)
            #-------------------------------------------------------------------
            # parameter1: factor (default = 1, allowed = 0...100%)
            # The target slope is divided by this number.
            # Factor = 50 means: requested slope = 20% --> 10%
            #-------------------------------------------------------------------
            # parameter2: factor (default = 1, allowed = 0...100%)
            # The target slope is divided by this number (if negative).
            # Factor = 50 means: requested slope = -20% --> -10%
            #-------------------------------------------------------------------
            # parameter3: shift percentage (default = 0, allowed = 0...20)
            # The target slope is incremented by this number.
            # Shift = 10 means: requested slope = -10% --> 0%
            #-------------------------------------------------------------------
            try:
                assert (len(s) <= 3)
                if len(s) >= 1 and s[0]:
                    self.GradeFactor = max(0, min(1, int(s[0]) / 100))
                if len(s) >= 2 and s[1]:
                    self.GradeFactorDH = max(0, min(1, int(s[1]) / 100))
                if len(s) >= 3 and s[2]:
                    self.GradeShift = max(0, min(20, int(s[2])))
            except:
                logfile.Console(
                    'Command line error; -G incorrect Grade Adjust=%s' %
                    self.args.GradeAdjust)
                self.GradeAdjust = 0

        #-----------------------------------------------------------------------
        # Get RunOff definition
        # All defined as int (float seems not useful) with exception of Time
        #-----------------------------------------------------------------------
        if self.args.Runoff:
            s = self.args.Runoff.split("/")
            try:
                assert (len(s) <= 5)
                if len(s) >= 1 and s[0]:
                    self.RunoffMaxSpeed = max(20, min(50, int(s[0])))  # km/hr
                if len(s) >= 2 and s[1]:
                    self.RunoffDip = max(0, min(5, int(s[1])))  # km/hr
                if len(s) >= 3 and s[2]:
                    self.RunoffMinSpeed = max(0, min(10, int(s[2])))  # km/hr
                if len(s) >= 4 and s[3]:
                    self.RunoffTime = max(0, min(10, float(s[3])))  # seconds
                if len(s) >= 5 and s[4]:
                    self.RunoffPower = max(0, min(500, int(s[4])))  # Watt
                assert (self.RunoffMinSpeed <=
                        self.RunoffMaxSpeed - self.RunoffDip * 2)
            except:
                logfile.Console(
                    'Command line error; -R incorrect Runoff definition %s' %
                    self.args.Runoff)

        #-----------------------------------------------------------------------
        # Get TacxType
        #-----------------------------------------------------------------------
        AntRequired = False
        if self.args.TacxType:
            self.TacxType = self.args.TacxType
            if 'Vortex' in self.TacxType:
                self.Tacx_Vortex = True
                self.Tacx_Cadence = False
                AntRequired = True
            elif 'Genius' in self.TacxType:
                self.Tacx_Genius = True
                self.Tacx_Cadence = False
                AntRequired = True
            elif 'Bushido' in self.TacxType:
                self.Tacx_Bushido = True
                self.Tacx_Cadence = False
                AntRequired = True
            elif 'Magneticbrake' in self.TacxType:
                self.Tacx_Magneticbrake = True
            elif 'Motorbrake' in self.TacxType:
                self.Tacx_MotorBrake = True
            else:
                logfile.Console('Command line error; -t incorrect value=%s' %
                                self.args.TacxType)
                self.args.TacxType = False

        if AntRequired and self.antDeviceID == -1:
            logfile.Console(
                'You have selected an ANT-trainer (-t %s) and de-selected ANT-dongle (-D-1); -D-1 ignored.'
                % self.TacxType)
            self.antDeviceID = None

        #-----------------------------------------------------------------------
        # Get Transmission
        # Default    = "34-50    x 34-30-27-25-23-21-19-17-15-13-11"
        # MTB single = "32       x 50-42-36-32-28-24-21-18-16-14-12-10"
        # MTB double = "24-36    x 36-32-28-24-21-19-17-15-13-11"
        # MTB triple = "22-34-44 x 36-32-28-24-21-19-17-15-13-11"
        # MTB 3 x 13 = "22-34-44 x 50-42-36-32-28-24-21-18-16-14-12-10"
        #-----------------------------------------------------------------------
        self.Transmission = self.args.Transmission
        while True:
            #-------------------------------------------------------------------
            # Use command-line value, if fails - use default
            #-------------------------------------------------------------------
            try:
                self.Cranckset = []
                self.CrancksetStart = 0  # The initial value of index
                self.CrancksetMax = 0  # Corresponds to full WH of the drawing area

                self.Cassette = []
                self.CassetteStart = 0  # The initial value of index
                self.CassetteMax = 0  # Corresponds to full WH of the drawing area

                self.Transmission = self.Transmission.replace(' ', '')
                #---------------------------------------------------------------
                # Split in crackset and cassette
                #---------------------------------------------------------------
                s1 = self.Transmission.split("x")
                assert (len(s1) == 2)
                #---------------------------------------------------------------
                # Split cranckset into chainrings (max 3)
                #---------------------------------------------------------------
                s2 = s1[0].split("-")
                for i in range(0, len(s2)):
                    chainring = s2[i]
                    if (chainring.find('*') != -1):
                        self.CrancksetStart = i
                        chainring = chainring.replace('*', '')
                    self.Cranckset.append(int(chainring))
                    if int(chainring) > self.CrancksetMax:
                        self.CrancksetMax = int(chainring)
                    if i == 2: break
                #---------------------------------------------------------------
                # Split cassette into sprockets (max 13)
                #---------------------------------------------------------------
                s2 = s1[1].split("-")
                for i in range(0, len(s2)):
                    sprocket = s2[i]
                    if (sprocket.find('*') != -1):
                        self.CassetteStart = i
                        sprocket = sprocket.replace('*', '')
                    self.Cassette.append(int(sprocket))
                    if int(sprocket) > self.CassetteMax:
                        self.CassetteMax = int(sprocket)
                    if i == 12: break
            except:
                if self.Transmission:
                    logfile.Console(
                        'Command line error; -T incorrect Transmission=%s' %
                        self.args.Transmission)
                self.Transmission = constants.Transmission
            else:
                break
        #-----------------------------------------------------------------------
        # If no start defined, take middle position
        #-----------------------------------------------------------------------
        if self.CrancksetStart == 0:
            self.CrancksetStart = int(round(len(self.Cranckset) / 2 - 0.5))
        if self.CassetteStart == 0:
            self.CassetteStart = int(round(len(self.Cassette) / 2 - 0.5))

        #-----------------------------------------------------------------------
        # Check pedal stroke analysis
        #-----------------------------------------------------------------------
        if self.PedalStrokeAnalysis and (not self.args.gui or self.Tacx_Vortex
                                         or self.Tacx_Genius
                                         or self.Tacx_Bushido):
            logfile.Console(
                "Pedal stroke analysis is not possible in console mode or this Tacx type"
            )
            self.PedalStrokeAnalysis = False
    def print(self):
        try:
            v = debug.on(debug.Any)     # Verbose: print all command-line variables with values
            if      self.autostart:          logfile.Console("-a")
            if      self.PedalStrokeAnalysis:logfile.Console("-A")
            if v or self.args.CalibrateRR:   logfile.Console("-c %s" % self.CalibrateRR )
            if v or self.args.debug:         logfile.Console("-d %s (%s)" % (self.debug, bin(self.debug) ) )
            if v or self.args.antDeviceID:   logfile.Console("-D %s" % self.antDeviceID )
            if v or self.args.GradeAdjust:
                if self.GradeAdjust == 1: logfile.Console("-G defines Grade = antGrade * %s" \
                                                    % (self.GradeFactor ) )
                if self.GradeAdjust == 2: logfile.Console("-G defines Grade = antGrade * %s [* %s (downhill)]" \
                                                    % (self.GradeFactor, self.GradeFactorDH) )
                if self.GradeAdjust == 3: logfile.Console("-G defines Grade = (antGrade - %s) * %s [* %s (downhill)]" \
                                                    % (self.GradeShift, self.GradeFactor, self.GradeFactorDH) )
            if      self.gui:                logfile.Console("-g")
            if v or self.args.hrm:           logfile.Console("-H %s" % self.hrm )
            if      self.manual:             logfile.Console("-m")
            if      self.manualGrade:        logfile.Console("-M")
            if      not self.args.calibrate: logfile.Console("-n")
            if v or self.args.factor:        logfile.Console("-p %s" % self.PowerFactor )
            if      self.args.PowerMode:     logfile.Console("-P")
            if      self.args.Resistance:    logfile.Console("-r")
            if      self.args.simulate:      logfile.Console("-s")
#scs        if v or self.args.scs:           logfile.Console("-S %s" % self.scs )
            if v or self.args.TacxType:      logfile.Console("-t %s" % self.TacxType)
            if      self.exportTCX:          logfile.Console("-x")

        except:
            pass # May occur when incorrect command line parameters, error already given before
    def __init__(self):
        global clv
        clv = self
        #-----------------------------------------------------------------------
        # Define and process command line
        #-----------------------------------------------------------------------
        parser = argparse.ArgumentParser(description='Program to broadcast data from USB Tacx Fortius trainer, and to receive resistance data for the trainer')
        parser.add_argument('-a','--autostart', help='Automatically start',                                 required=False, action='store_true')
        parser.add_argument('-A','--PedalStrokeAnalysis', help='Pedal Stroke Analysis',                     required=False, action='store_true')
        parser.add_argument('-c','--CalibrateRR',help='calibrate Rolling Resistance for Magnetic Brake',    required=False, default=False)
        parser.add_argument('-d','--debug',     help='Show debugging data',                                 required=False, default=False)
        parser.add_argument('-D','--antDeviceID',help='Use this antDongle type only',                       required=False, default=False)
        parser.add_argument('-g','--gui',       help='Run with graphical user interface',                   required=False, action='store_true')
        parser.add_argument('-G','--GradeAdjust',help='Adjust slope%% in GradeMode (factor/factorDownhill)',required=False, default=False)
        parser.add_argument('-H','--hrm',       help='Pair this ANT+ Heart Rate Monitor (0: any, -1: none); Tacx HRM is used if not specified',
                                                                                                            required=False, default=False)
        parser.add_argument('-m','--manual',    help='Run manual power (ignore target from ANT+ Dongle)',   required=False, action='store_true')
        parser.add_argument('-M','--manualGrade',help='Run manual grade (ignore target from ANT+ Dongle)',  required=False, action='store_true')
        parser.add_argument('-n','--calibrate', help='Do not calibrate before start',                       required=False, action='store_false')
        parser.add_argument('-p','--factor',    help='Adjust target Power by multiplying by this factor for static calibration',
                                                                                                            required=False, default=False)
        parser.add_argument('-P','--PowerMode', help='Power mode has preference over Resistance mode (for 30 seconds)',
                                                                                                            required=False, action='store_true')
        parser.add_argument('-r','--Resistance',help='Target Resistance = Target Power (to create power curve)',
                                                                                                            required=False, action='store_true')
        parser.add_argument('-s','--simulate',  help='Simulated trainer to test ANT+ connectivity',         required=False, action='store_true')
#scs    parser.add_argument('-S','--scs',       help='Pair this Speed Cadence Sensor (0: default device)',  required=False, default=False)
        parser.add_argument('-t','--TacxType',  help='Specify Tacx Type; e.g. i-Vortex, default=autodetect',required=False, default=False)
        parser.add_argument('-x','--exportTCX', help='Export TCX file',                                     required=False, action='store_true')

        #-----------------------------------------------------------------------
        # Parse
        #-----------------------------------------------------------------------
        args                        = parser.parse_args()
        self.args                   = args

        #-----------------------------------------------------------------------
        # Booleans; either True or False
        #-----------------------------------------------------------------------
        self.autostart              = args.autostart
        self.gui                    = args.gui
        self.manual                 = args.manual
        self.manualGrade            = args.manualGrade
        self.calibrate              = args.calibrate
        self.PowerMode              = args.PowerMode
        self.PedalStrokeAnalysis    = args.PedalStrokeAnalysis
        self.Resistance             = args.Resistance
        self.SimulateTrainer        = args.simulate
        self.exportTCX              = args.exportTCX or self.manual or self.manualGrade

        if self.manual and self.manualGrade:
            logfile.Console("-m and -M are mutually exclusive; manual power selected")
            self.manualGrade = False        # Mutually exclusive

        if (self.manual or self.manualGrade) and self.SimulateTrainer:
            logfile.Console("-m/-M and -s both specified, most likely for program test purpose")

        #-----------------------------------------------------------------------
        # Get calibration of Rolling Resistance
        #-----------------------------------------------------------------------
        if args.CalibrateRR:
            try:
                self.CalibrateRR = float(args.CalibrateRR.replace(',', '.'))
            except:
                logfile.Console('Command line error; -c incorrect calibration of Rolling Resistance=%s' % args.CalibrateRR)

        #-----------------------------------------------------------------------
        # Get debug-flags, used in debug module
        #-----------------------------------------------------------------------
        if args.debug:
            try:
                self.debug = int(args.debug)
            except:
                logfile.Console('Command line error; -d incorrect debugging flags=%s' % args.debug)

        #-----------------------------------------------------------------------
        # Get antDeviceID
        #-----------------------------------------------------------------------
        if args.antDeviceID:
            try:
                self.antDeviceID = int(args.antDeviceID)
            except:
                logfile.Console('Command line error; -D incorrect antDeviceID=%s' % args.antDeviceID)

        #-----------------------------------------------------------------------
        # Get HRM
        # - None: read HRM from Tacx Fortius and broadcast as HRM master device
        # - -1  : no master and no slave device
        # - 0   : pair with the first ANT+ HRM that is found
        # - next: pair with the defined ANT+ HRM monitor
        #             the number can be found with ExplorANT
        #-----------------------------------------------------------------------
        if args.hrm:
            try:
                self.hrm = int(args.hrm)
            except:
                logfile.Console('Command line error; -H incorrect HRM=%s' % args.hrm)

        #-----------------------------------------------------------------------
        # Get SCS
        # - None: No Speed Cadence Sensor
        # - 0   : pair with the first ANT+ SCS that is found
        # - next: pair with the defined ANT+ SCS
        #             the number can be found with ExplorANT
        #-----------------------------------------------------------------------
#scs    if args.scs:
#scs        try:
#scs            self.scs = int(args.scs)
#scs        except:
#scs            logfile.Console('Command line error; -S incorrect SCS=%s' % args.scs)

        #-----------------------------------------------------------------------
        # Get powerfactor
        #-----------------------------------------------------------------------
        if args.factor:
            try:
                self.PowerFactor = int(args.factor)/100
            except:
                logfile.Console('Command line error; -f incorrect power factor=%s' % args.factor)

        #-----------------------------------------------------------------------
        # Get GradeAdjust = shift/factor
        # Motor Brake default              = -G 100/100
        # Magnetic Brake suggested (Rouvy) = -G  50/100
        #-----------------------------------------------------------------------
        if args.GradeAdjust:
            s = args.GradeAdjust.split("/")
            self.GradeAdjust = len(s)
            #-------------------------------------------------------------------
            # parameter1: factor (default = 1, allowed = 0...100%)
            # The target slope is divided by this number.
            # Factor = 5 means: requested slope = 20% --> 4%
            #-------------------------------------------------------------------
            if len(s) >= 1:
                try:
                    self.GradeFactor = int(s[0]) / 100
                    self.GradeFactor = max( 0, self.GradeFactor)
                    self.GradeFactor = min( 1, self.GradeFactor)
                except:
                    logfile.Console('Command line error; -G incorrect Grade Adjust=%s' % args.GradeAdjust)
                    self.GradeAdjust = 0

            #-------------------------------------------------------------------
            # parameter2: factor (default = 1, allowed = 0...100%)
            # The target slope is divided by this number.
            # Factor = 5 means: requested slope = 20% --> 4%
            #-------------------------------------------------------------------
            if len(s) >= 2:
                try:
                    self.GradeFactorDH = int(s[1]) / 100
                    self.GradeFactorDH = max( 0, self.GradeFactorDH)
                    self.GradeFactorDH = min( 1, self.GradeFactorDH)
                except:
                    logfile.Console('Command line error; -G incorrect Grade Adjust=%s' % args.GradeAdjust)
                    self.GradeAdjust = 0

            #-------------------------------------------------------------------
            # parameter3: shift percentage (default = 0, allowed = 0...20)
            # The target slope is incremented by this number.
            # Shift = 10 means: requested slope = -10% --> 0%
            #-------------------------------------------------------------------
            if len(s) >= 3:
                try:
                    self.GradeShift = int(s[2])
                    self.GradeShift = max( 0, self.GradeShift)
                    self.GradeShift = min(20, self.GradeShift)
                except:
                    logfile.Console('Command line error; -G incorrect Grade Adjust=%s' % args.GradeAdjust)
                    self.GradeAdjust = 0

        #-----------------------------------------------------------------------
        # Get TacxType
        #-----------------------------------------------------------------------
        if args.TacxType:
            self.TacxType = args.TacxType
            if self.TacxType in ('i-Vortex'):
                self.Tacx_iVortex = True
            else:
                logfile.Console('Command line error; -t incorrect value=%s' % args.TacxType)
                args.TacxType = False

        #-----------------------------------------------------------------------
        # Check pedal stroke analysis
        #-----------------------------------------------------------------------
        if args.PedalStrokeAnalysis and (not args.gui or self.Tacx_iVortex):
            logfile.Console("Pedal stroke analysis is not possible in console mode or this Tacx type")
            self.PedalStrokeAnalysis = False

        #-----------------------------------------------------------------------
        # If nothing specified at all, help the poor windows-users
        #-----------------------------------------------------------------------
        if len(sys.argv) == 1:
            pgm = max(sys.argv[0].rfind('/'), sys.argv[0].rfind('\\')) + 1
            pgm = sys.argv[0][pgm:]
            print('---------------------------------------------------------------')
            print('Hello!')
            print('You have started FortiusANT without command-line parameters.')
            print(' ')
            print('Therefore we start with a best-practice setting:')
            print('     %s -a -g -H0 -A' % pgm)
            print(' ')
            print('If you want to start without the graphical user interface:')
            print('     %s -a' % pgm)
            print(' ')
            print('For more info, please refer to the wiki on github.')
            print('Succes!')
            print('---------------------------------------------------------------')
            print('FortiusANT is open source and can freely be used.')
            print('')
            print('A free gift would be appreciated:')
            print('Put yourself on the FortiusANT map by making yourself known')
            print('by leaving a message with name/location/trainer on')
            print('https://github.com/WouterJD/FortiusANT/issues/14')
            print('')
            print('Just for the fun of knowing where we are training.')
            print('---------------------------------------------------------------')
            self.autostart              = True
            self.gui                    = True      # Show gui
            self.hrm                    = 0         # Pair with HRM
            self.PedalStrokeAnalysis    = True      # Show it
Beispiel #28
0
# ==============================================================================
if __name__ == "__main__":
    multiprocessing.freeze_support()
    global clv

    # --------------------------------------------------------------------------
    # Initialize
    # --------------------------------------------------------------------------
    debug.deactivate()
    clv = cmd.CommandLineVariables()
    debug.activate(clv.debug)
    FortiusAntBody.Initialize(clv)

    if debug.on(debug.Any):
        logfile.Open()
        logfile.Console("FortiusANT started")
        clv.print()
        logfile.Console("------------------")

    #-------------------------------------------------------------------------------
    # Component info
    #-------------------------------------------------------------------------------
    if debug.on(debug.Any):
        logfile.Write('Version info for the components')
        s = " %20s = %s"
        logfile.Write(s % ('FortiusAnt', __version__))
        logfile.Write(s % ('antDongle', ant.__version__))
        logfile.Write(s % ('antHRM', hrm.__version__))
        logfile.Write(s % ('antFE', fe.__version__))
        logfile.Write(s % ('debug', debug.__version__))
        logfile.Write(s % ('FortiusAntBody', FortiusAntBody.__version__))
    def __init__(self):
        global clv
        clv = self
        #-----------------------------------------------------------------------
        # Define and process command line
        #-----------------------------------------------------------------------
        parser = argparse.ArgumentParser(
            description=
            'Program to broadcast data from USB Tacx Fortius trainer, and to receive resistance data for the trainer'
        )
        parser.add_argument('-a',
                            '--autostart',
                            help='Automatically start',
                            required=False,
                            action='store_true')
        parser.add_argument('-A',
                            '--PedalStrokeAnalysis',
                            help='Pedal Stroke Analysis',
                            required=False,
                            action='store_true')
        parser.add_argument('-d',
                            '--debug',
                            help='Show debugging data',
                            required=False,
                            default=False)
        parser.add_argument('-g',
                            '--gui',
                            help='Run with graphical user interface',
                            required=False,
                            action='store_true')
        parser.add_argument(
            '-H',
            '--hrm',
            help='Pair this Heart Rate Monitor (0: any, -1: none)',
            required=False,
            default=False)
        parser.add_argument(
            '-m',
            '--manual',
            help='Run manual power (ignore target from ANT+ Dongle)',
            required=False,
            action='store_true')
        parser.add_argument(
            '-M',
            '--manualGrade',
            help='Run manual grade (ignore target from ANT+ Dongle)',
            required=False,
            action='store_true')
        parser.add_argument('-n',
                            '--calibrate',
                            help='Do not calibrate before start',
                            required=False,
                            action='store_false')
        parser.add_argument(
            '-p',
            '--factor',
            help=
            'Adjust target Power by multiplying by this factor for static calibration',
            required=False,
            default=False)
        parser.add_argument(
            '-P',
            '--PowerMode',
            help=
            'Power mode has preference over Resistance mode (for 30 seconds)',
            required=False,
            action='store_true')
        parser.add_argument('-s',
                            '--simulate',
                            help='Simulated trainer to test ANT+ connectivity',
                            required=False,
                            action='store_true')
        #scs    parser.add_argument('-S','--scs',       help='Pair this Speed Cadence Sensor (0: default device)',  required=False, default=False)
        parser.add_argument(
            '-t',
            '--TacxType',
            help='Specify Tacx Type; e.g. i-Vortex, default=autodetect',
            required=False,
            default=False)
        parser.add_argument('-u',
                            '--uphill',
                            help='Uphill only; negative grade is ignored',
                            required=False,
                            action='store_true')

        #-----------------------------------------------------------------------
        # Deprecated
        #-----------------------------------------------------------------------
        # s = '%s,%s/%s,%s/%s' % (self.__tyre__, self.__fL__, self.__fS__, self.__rS__, self.__rL__)
        # parser.add_argument('-b','--bicycle',   help='Bicycle definition, default=' + s,                    required=False, default=False)
        # parser.add_argument('-f','--ftp',       help='FTP of the rider, default=%s' % self.__ftp__,         required=False, default=False)
        # parser.add_argument('-r','--resistance',help='FTP percentages for resistance mode, default=150/100',required=False, default=False)

        #-----------------------------------------------------------------------
        # Parse
        #-----------------------------------------------------------------------
        args = parser.parse_args()
        self.args = args

        #-----------------------------------------------------------------------
        # Booleans; either True or False
        #-----------------------------------------------------------------------
        self.autostart = args.autostart
        self.gui = args.gui
        self.manual = args.manual
        self.manualGrade = args.manualGrade
        self.calibrate = args.calibrate
        self.PowerMode = args.PowerMode
        self.PedalStrokeAnalysis = args.PedalStrokeAnalysis
        self.SimulateTrainer = args.simulate
        self.uphill = args.uphill

        if self.manual and self.manualGrade:
            logfile.Console(
                "-m and -M are mutually exclusive; manual power selected")
            self.manualGrade = False  # Mutually exclusive

        if (self.manual or self.manualGrade) and self.SimulateTrainer:
            logfile.Console(
                "-m/-M and -s both specified, most likely for program test purpose"
            )

        #-----------------------------------------------------------------------
        # Bicycle definition to be parsed; three parameters
        # format=tyre,chainring,cassette, e.g. "2.096,50/34,15/25"
        #-----------------------------------------------------------------------
        # if args.bicycle:
        #     b = args.bicycle.split(",")
        #     #-------------------------------------------------------------------
        #     # parameter1: Tyre defined?
        #     #-------------------------------------------------------------------
        #     if len(b) >= 1:
        #         try:
        #             self.tyre = float(b[0])
        #             if self.tyre < 1: self.tyre = self.__tyre__
        #         except:
        #             logfile.Console('Command line error; -b incorrect tyre=%s' % b[0])
        #             self.tyre = self.__tyre__

        #     #-------------------------------------------------------------------
        #     # parameter2: Chainring, large/small separated by /
        #     # format=large/small, e.g. 50/34
        #     # If one value is specified, e.g. "50" 50/50 is assumed
        #     #-------------------------------------------------------------------
        #     if len(b) >= 2:
        #         s = b[1].split('/')
        #         if len(s) >= 0:
        #             try:
        #                 self.fL = int(s[0])
        #             except:
        #                 logfile.Console('Command line error; -b incorrect large chainring=%s' % s[0])

        #         self.fS = self.fL                       # Default is single chainring
        #         if len(s) >= 1:
        #             try:
        #                 self.fS = int(s[1])
        #             except:
        #                 logfile.Console('Command line error; -b incorrect small chainring=%s' % s[1])

        #     #-------------------------------------------------------------------
        #     # parameter3: Cassette, small/large separated by /
        #     # If one value is specified, e.g. "15" 15/15 is assumed
        #     #-------------------------------------------------------------------
        #     if len(b) >= 3:
        #         s = b[2].split('/')
        #         if len(s) >= 0:
        #             try:
        #                 self.rS = int(s[0])
        #             except:
        #                 logfile.Console('Command line error; -b incorrect small cassette=%s' % s[0])

        #         self.rL = self.rS               # Default is single speed cassette
        #         if len(s) >= 1:
        #             try:
        #                 self.rL = int(s[1])
        #             except:
        #                 logfile.Console('Command line error; -b incorrect large cassette=%s' % s[1])

        #-----------------------------------------------------------------------
        # Get debug-flags, used in debug module
        #-----------------------------------------------------------------------
        if args.debug:
            try:
                self.debug = int(args.debug)
            except:
                logfile.Console(
                    'Command line error; -d incorrect debugging flags=%s' %
                    args.debug)

        #-----------------------------------------------------------------------
        # Get riders FTP
        #-----------------------------------------------------------------------
        # if args.ftp:
        #     try:
        #         self.ftp = int(args.ftp)
        #         if self.ftp < 50: self.ftp = self.__ftp__
        #     except:
        #         logfile.Console('Command line error; -f incorrect ftp=%s' % args.ftp)

        #-----------------------------------------------------------------------
        # Get HRM
        # - None: read HRM from Tacx Fortius and broadcast as HRM master device
        # - -1  : no master and no slave device
        # - 0   : pair with the first ANT+ HRM that is found
        # - next: pair with the defined ANT+ HRM monitor
        #             the number can be found with ExplorANT
        #-----------------------------------------------------------------------
        if args.hrm:
            try:
                self.hrm = int(args.hrm)
            except:
                logfile.Console('Command line error; -H incorrect HRM=%s' %
                                args.hrm)

        #-----------------------------------------------------------------------
        # Get SCS
        # - None: No Speed Cadence Sensor
        # - 0   : pair with the first ANT+ SCS that is found
        # - next: pair with the defined ANT+ SCS
        #             the number can be found with ExplorANT
        #-----------------------------------------------------------------------
#scs    if args.scs:
#scs        try:
#scs            self.scs = int(args.scs)
#scs        except:
#scs            logfile.Console('Command line error; -S incorrect SCS=%s' % args.scs)

#-----------------------------------------------------------------------
# Get powerfactor
#-----------------------------------------------------------------------
        if args.factor:
            try:
                self.PowerFactor = float(args.factor)
            except:
                logfile.Console(
                    'Command line error; -f incorrect power factor=%s' %
                    args.factor)

        #-----------------------------------------------------------------------
        # Parse Resistance
        #-----------------------------------------------------------------------
        # if args.resistance:
        #     s = args.resistance.split('/')
        #     if len(s) >= 0:
        #         try:
        #             self.ResistanceH = int(s[0])
        #         except:
        #             logfile.Console('Command line error; -r incorrect high resistance=%s' % s[0])

        #     if len(s) >= 1:
        #         try:
        #             self.ResistanceL = int(s[1])
        #         except:
        #             logfile.Console('Command line error; -r incorrect low resistance=%s' % s[1])

        #-----------------------------------------------------------------------
        # Get TacxType
        #-----------------------------------------------------------------------
        if args.TacxType:
            self.TacxType = args.TacxType
            if self.TacxType in ('i-Vortex'):
                self.Tacx_iVortex = True
            else:
                logfile.Console('Command line error; -t incorrect value=%s' %
                                args.TacxType)
                args.TacxType = False

        #-----------------------------------------------------------------------
        # Check pedal stroke analysis
        #-----------------------------------------------------------------------
        if args.PedalStrokeAnalysis and (not args.gui or self.Tacx_iVortex):
            logfile.Console(
                "Pedal stroke analysis is not possible in console mode or this Tacx type"
            )
            self.PedalStrokeAnalysis = False

        #-----------------------------------------------------------------------
        # If nothing specified at all, help the poor windows-users
        #-----------------------------------------------------------------------
        if len(sys.argv) == 1:
            pgm = max(sys.argv[0].rfind('/'), sys.argv[0].rfind('\\')) + 1
            pgm = sys.argv[0][pgm:]
            print(
                '---------------------------------------------------------------'
            )
            print('Hello!')
            print(
                'You have started FortiusANT without command-line parameters.')
            print(' ')
            print('Therefore we start with a best-practice setting:')
            print('     %s -a -g -H0 -A' % pgm)
            print(' ')
            print('If you want to start without the graphical user interface:')
            print('     %s -a' % pgm)
            print(' ')
            print('For more info, please refer to the wiki on github.')
            print('Succes!')
            print(
                '---------------------------------------------------------------'
            )
            print('FortiusANT is open source and can freely be used.')
            print('')
            print('A free gift would be appreciated:')
            print(
                'Put yourself on the FortiusANT map by making yourself known')
            print('by leaving a message with name/location/trainer on')
            print('https://github.com/WouterJD/FortiusANT/issues/14')
            print('')
            print('Just for the fun of knowing where we are training.')
            print(
                '---------------------------------------------------------------'
            )
            self.autostart = True
            self.gui = True  # Show gui
            self.hrm = 0  # Pair with HRM
            self.PedalStrokeAnalysis = True  # Show it
    def __init__(self):
        #-----------------------------------------------------------------------
        # Define and process command line
        #-----------------------------------------------------------------------
        parser = argparse.ArgumentParser(description='Program to broadcast data from USB Tacx Fortius trainer, and to receive resistance data for the trainer')
        parser.add_argument('-a','--autostart', help='Automatically start',                                 required=False, action='store_true')
        s = '%s,%s/%s,%s/%s' % (self.__tyre__, self.__fL__, self.__fS__, self.__rS__, self.__rL__)
        parser.add_argument('-b','--bicycle',   help='Bicycle definition, default=' + s,                    required=False, default=False)
        parser.add_argument('-d','--debug',     help='Show debugging data',                                 required=False, default=False)
        parser.add_argument('-f','--ftp',       help='FTP of the rider, default=%s' % self.__ftp__,         required=False, default=False)
        parser.add_argument('-g','--gui',       help='Run with graphical user interface',                   required=False, action='store_true')
        parser.add_argument('-H','--hrm',       help='Use this Heart Rate Monitor (0: default, -1: none)',  required=False, default=False)
        parser.add_argument('-m','--manual',    help='Run manual power (ignore target from antDongle)',     required=False, action='store_true')
        parser.add_argument('-M','--manualGrade',help='Run manual grade (ignore target from antDongle)',    required=False, action='store_true')
        parser.add_argument('-n','--calibrate', help='Do not calibrate before start',                       required=False, action='store_false')
        parser.add_argument('-p','--factor',    help='Adjust target Power by multiplying by this factor for static calibration',
                                                                                                            required=False, default=False)
        parser.add_argument('-P','--PowerMode', help='Power mode has preference over Resistance mode (for 30 seconds)',
                                                                                                            required=False, action='store_true')
        parser.add_argument('-r','--resistance',help='FTP percentages for resistance mode, default=150/100',required=False, default=False)
        parser.add_argument('-s','--simulate',  help='Simulated trainer to test ANT+ connectivity',         required=False, action='store_true')
#scs    parser.add_argument('-S','--scs',       help='Use this Speed Cadence Sensor (0: default device)',   required=False, default=False)
        args                 = parser.parse_args()
        self.args            = args

        #-----------------------------------------------------------------------
        # Booleans; either True or False
        #-----------------------------------------------------------------------
        self.autostart       = args.autostart
        self.gui             = args.gui
        self.manual          = args.manual
        self.manualGrade     = args.manualGrade
        self.calibrate       = args.calibrate
        self.PowerMode       = args.PowerMode
        self.SimulateTrainer = args.simulate
        
        if self.manual and self.manualGrade:
            logfile.Console("-m and -M are mutually exclusive; manual power selected")
            self.manualGrade = False        # Mutually exclusive
        
        if (self.manual or self.manualGrade) and self.SimulateTrainer:
            logfile.Console("-m/-M and -s both specified, most likely for program test purpose")
        
        #-----------------------------------------------------------------------
        # Bicycle definition to be parsed; three parameters
        # format=tyre,chainring,cassette, e.g. "2.096,50/34,15/25"
        #-----------------------------------------------------------------------
        if args.bicycle:
            b = args.bicycle.split(",")
            #-------------------------------------------------------------------
            # parameter1: Tyre defined?
            #-------------------------------------------------------------------
            if len(b) >= 1:
                try:
                    self.tyre = float(b[0])
                    if self.tyre < 1: self.tyre = self.__tyre__
                except:
                    logfile.Console('Command line error; -b incorrect tyre=%s' % b[0])
                    self.tyre = self.__tyre__
            
            #-------------------------------------------------------------------
            # parameter2: Chainring, large/small separated by /
            # format=large/small, e.g. 50/34
            # If one value is specified, e.g. "50" 50/50 is assumed
            #-------------------------------------------------------------------
            if len(b) >= 2:
                s = b[1].split('/')
                if len(s) >= 0:
                    try:
                        self.fL = int(s[0])
                    except:
                        logfile.Console('Command line error; -b incorrect large chainring=%s' % s[0])

                self.fS = self.fL                       # Default is single chainring
                if len(s) >= 1:
                    try:
                        self.fS = int(s[1])
                    except:
                        logfile.Console('Command line error; -b incorrect small chainring=%s' % s[1])

            #-------------------------------------------------------------------
            # parameter3: Cassette, small/large separated by /
            # If one value is specified, e.g. "15" 15/15 is assumed
            #-------------------------------------------------------------------
            if len(b) >= 3:
                s = b[2].split('/')
                if len(s) >= 0:
                    try:
                        self.rS = int(s[0])
                    except:
                        logfile.Console('Command line error; -b incorrect small cassette=%s' % s[0])

                self.rL = self.rS               # Default is single speed cassette
                if len(s) >= 1:
                    try:
                        self.rL = int(s[1])
                    except:
                        logfile.Console('Command line error; -b incorrect large cassette=%s' % s[1])

        #-----------------------------------------------------------------------
        # Get debug-flags, used in debug module
        #-----------------------------------------------------------------------
        if args.debug:
            try:
                self.debug = int(args.debug)
            except:
                logfile.Console('Command line error; -d incorrect debugging flags=%s' % args.debug)

        #-----------------------------------------------------------------------
        # Get riders FTP
        #-----------------------------------------------------------------------
        if args.ftp:
            try:
                self.ftp = int(args.ftp)
                if self.ftp < 50: self.ftp = self.__ftp__
            except:
                logfile.Console('Command line error; -f incorrect ftp=%s' % args.ftp)

        #-----------------------------------------------------------------------
        # Get HRM
        # - None: read HRM from Tacx Fortius and broadcast as HRM master device
        # - -1  : no master and no slave device
        # - 0   : pair with the first ANT+ HRM that is found
        # - next: pair with the defined ANT+ HRM monitor
        #             the number can be found with ExplorANT
        #-----------------------------------------------------------------------
        if args.hrm:
            try:
                self.hrm = int(args.hrm)
            except:
                logfile.Console('Command line error; -H incorrect HRM=%s' % args.hrm)

        #-----------------------------------------------------------------------
        # Get SCS
        # - None: No Speed Cadence Sensor
        # - 0   : pair with the first ANT+ SCS that is found
        # - next: pair with the defined ANT+ SCS
        #             the number can be found with ExplorANT
        #-----------------------------------------------------------------------
#scs    if args.scs:
#scs        try:
#scs            self.scs = int(args.scs)
#scs        except:
#scs            logfile.Console('Command line error; -S incorrect SCS=%s' % args.scs)

        #-----------------------------------------------------------------------
        # Get powerfactor
        #-----------------------------------------------------------------------
        if args.factor:
            try:
                self.PowerFactor = float(args.factor)
            except:
                logfile.Console('Command line error; -f incorrect power factor=%s' % args.factor)

        #-----------------------------------------------------------------------
        # Parse Resistance
        #-----------------------------------------------------------------------
        if args.resistance:
            s = args.resistance.split('/')
            if len(s) >= 0:
                try:
                    self.ResistanceH = int(s[0])
                except:
                    logfile.Console('Command line error; -r incorrect high resistance=%s' % s[0])

            if len(s) >= 1:
                try:
                    self.ResistanceL = int(s[1])
                except:
                    logfile.Console('Command line error; -r incorrect low resistance=%s' % s[1])