Exemple #1
0
def acMain(ac_version): #app window init; global variables for later updating go here
    global appWindow
    appWindow = ac.newApp(appName)
    ac.setTitle(appWindow, appName)
    ac.setSize(appWindow, width, height)

    ac.log("z3D Gauge loaded")
    ac.console("z3D Gauge console test")

    ####################################################declaring gauge elements
    # gonna need new textures like
    # rpm_bar = ac.newTexture(app_path + theme_path + "rpm_bar.png")

    global l_kmph, l_rpm, l_gear, acceleration
    global ascii_RPM
    l_kmph = ac.addLabel(appWindow, "KMPH")
    l_rpm = ac.addLabel(appWindow, "RPM")
    l_gear = ac.addLabel(appWindow, "Current gear")
    ascii_RPM = ac.addLabel(appWindow, "")
    acceleration = ac.addLabel(appWindow, "")
    #l_TC = ac.addLabel(appWindow, "TC on/off")      #non-functional
    #l_ABS = ac.addLabel(appWindow, "ABS on/off")    #non-functional

    ac.setPosition(l_kmph, 3, 30)
    ac.setPosition(l_rpm, 3, 60)
    ac.setPosition(l_gear, 3, 80)
    ac.setPosition(ascii_RPM, 3, 160)
    ac.setPosition(acceleration, 3, 580)

    ac.addRenderCallback(appWindow, appGL) # -> links this app's window to an OpenGL render function

    return appName
Exemple #2
0
def acUpdate(ms):
    global BEST_LOGGED_LAP, LAP_HISTORY, UPDATE_DELTA, CURRENT_LAP_VALID, LAP_VALID_INDICATOR

    if ACTIVE:
        if CURRENT_LAP_VALID and info.physics.numberOfTyresOut > TIRES_THRESHOLD:
            ac.setText(LAP_VALID_INDICATOR, 'Dirty')
            CURRENT_LAP_VALID = False

        #UPDATE_DELTA += ms
        #if UPDATE_DELTA < UPDATE_THRESHOLD:
        #    return
        #UPDATE_DELTA = 0

        last_lap = ac.getCarState(DRIVER_ID_SELF, acsys.CS.LastLap)
        valid = CURRENT_LAP_VALID and not ac.getCarState(
            DRIVER_ID_SELF, acsys.CS.LapInvalidated)

        if last_lap and (not LAP_HISTORY or not last_lap == LAP_HISTORY[-1]):
            ac.console('Last lap: %s%s' %
                       (last_lap, '' if valid else ' (invalid)'))

            reportLap({
                'driver': DRIVER,
                'track': TRACK,
                'car': CAR,
                'lap': last_lap
            })

            refreshLapDisplay()

            # reset lap tracking
            ac.setText(LAP_VALID_INDICATOR, 'Clean')
            CURRENT_LAP_VALID = True
            LAP_HISTORY.append(last_lap)
Exemple #3
0
def loadCarData():
    global CarData
    carName = ac.getCarName(0)

    try:
        carsFile = os.path.join(os.path.dirname(__file__), "cardata.json")
        with open(carsFile, "r") as f:
            jsonData = json.load(f)

    except OSError:
        ac.log("Reventach ERROR: loadCarData cardata.json not found")

    else:
        try:
            CarData["totalGears"] = jsonData[carName]["gears"]
            CarData["maxRPM"] = jsonData[carName]["maxRPM"]
            ac.console("Car data found for " + carName)

        except KeyError:  # Doesn't exist in official, look for custom data
            try:
                carsFile = os.path.join(os.path.dirname(__file__),
                                        "cardata-custom.json")
                with open(carsFile, "r") as f:
                    jsonData = json.load(f)
                    CarData["totalGears"] = jsonData[carName]["gears"]
                    CarData["maxRPM"] = jsonData[carName]["maxRPM"]

            except (OSError, KeyError) as e:
                ac.log(
                    "Reventach ERROR: loadCarData: No custom car data found for this car"
                )

            else:
                ac.console("Custom car data found for " + carName)
Exemple #4
0
def acMain(ac_version):
    global appWindow, label1, logPrefix, appName, cfg, ui_enableButton
    ac.console(logPrefix + "acMain")
    try:
        appWindow = ac.newApp(appName)

        cfg = Configuration()
        cfg.load()

        ac.setTitle(appWindow, "")
        ac.setSize(appWindow, 400, 200)
        ac.drawBorder(appWindow, 0)
        ac.setBackgroundOpacity(appWindow, 0)

        ac.addRenderCallback(appWindow, onRender)

        ui_enableButton = ac.addButton(appWindow, "Enable")
        ac.setPosition(ui_enableButton, 0, 30)
        ac.setSize(ui_enableButton, 70, 30)
        ac.addOnClickedListener(ui_enableButton, onEnableButtonClicked)

        label1 = ac.addLabel(appWindow, "____")
        ac.setPosition(label1, 0, 65)

        if cfg.enable > 0:
            ac.setText(ui_enableButton, "Disable")
            startTelemetry()

        ac.console(logPrefix + "Initialized")
    except:
        printExceptionInfo("acMain")

    return appName
    def marshall(self):
        """Simple comma seperated transmission, client will need to be aware of positions of various data items
        Add any new data items to the end so existing apps are not affected
        """
        try:
            data = ["x02"] #start token
            data.extend(ac.getCarState(0, acsys.CS.CurrentTyresCoreTemp)) #0-3 - Core tyre temperatures, Degrees celcius
            data.extend(info.physics.tyreWear) #4-7 #tyre wear
            data.extend(ac.getCarState(0, acsys.CS.DynamicPressure)) #8-11 pressure of each tyre in PSI
            data.extend(ac.getCarState(0, acsys.CS.TyreDirtyLevel)) #12-15 amount of dirt on each tyre
            data.append(ac.getCarState(0, acsys.CS.SpeedMS)) #16 speed in metres/sec
            data.append(ac.getCarState(0, acsys.CS.Gear)) #17 gear number
            data.append(ac.getCarState(0, acsys.CS.BestLap)) #18 best lap time in ms
            data.append(ac.getCarState(0, acsys.CS.RPM)) #19 rpm
            data.append(ac.getCarState(0, acsys.CS.LapCount)) #20 lap count
            data.append(ac.getCarState(0, acsys.CS.LapInvalidated)) #21 is lap invalid? 0-no, 1-yes
            data.append(ac.getCarState(0, acsys.CS.LapTime)) #22 current lap time in ms
            data.append(ac.getCarState(0, acsys.CS.LastLap)) #23 last lap in ms
            data.append(ac.getCarState(0, acsys.CS.PerformanceMeter)) #24 delta time in ms from best lap?? (haven't checked)
            data.append(ac.getCarState(0, acsys.CS.Steer)) #25 steering rotation in radians
            data.append(ac.getCarName(0)) #26 name of car being driven by player
            data.append(ac.getTrackName(0)) #27 track name

            data.append("x04") #end token
        except Exception as e:
            ac.console("{}".format(e))
        return ",".join(str(v) for v in data).encode()
Exemple #6
0
def acMain(ac_version):
    global app
    global lap_count, lap_current, lap_last, lap_best, lap_delta, lap_diff
    global car_speed, car_gear, car_rpm, car_pos, car_fuel, car_prev, car_next
    global car_tyre_1, car_tyre_2, car_tyre_3, car_tyre_4

    try:
        app = gui.App("ACBIB", "", APP_WIDTH, APP_HEIGHT,
                      gui.Color(0, 0, 0, 0.8))
        app.setRenderCallback(glRender)

        grid = gui.Grid(app, 5, 5)
        #ac.console("{}{}".format(self.pos[0], self.pos[1]))

        lap_count = gui.Label(None, app)
        car_pos = gui.Label(None, app)
        car_fuel = gui.Label(None, app)

        lap_best = gui.Label(None, app)
        lap_last = gui.Label(None, app)
        lap_current = gui.Label(None, app)

        car_prev = gui.Label(None, app, "", gui.Color(1, 0, 0, 1))
        lap_diff = gui.DiffBar(None, app, True)
        car_next = gui.Label(None, app, "", gui.Color(0, 1, 0, 1))

        car_speed = gui.Label(None, app)
        car_gear = gui.Label(None, app)
        car_rpm = gui.Label(None, app)

        car_tyre_1 = gui.Label(None, app)
        car_tyre_2 = gui.Label(None, app)
        car_tyre_3 = gui.Label(None, app)
        car_tyre_4 = gui.Label(None, app)

        grid.add(lap_count, 0, 0)
        grid.add(car_pos, 0, 1)
        grid.add(car_fuel, 0, 2)

        grid.add(lap_best, 1, 0)
        grid.add(lap_last, 1, 1)
        grid.add(lap_current, 1, 2)

        grid.add(car_prev, 0, 4)
        grid.add(lap_diff, 2, 3)
        grid.add(car_next, 4, 4)

        grid.add(car_speed, 2, 0)
        grid.add(car_gear, 2, 1)
        grid.add(car_rpm, 2, 2)

        grid.add(car_tyre_1, 3, 0, 1, 2)
        grid.add(car_tyre_2, 4, 0, 1, 2)
        grid.add(car_tyre_3, 3, 2, 1, 2)
        grid.add(car_tyre_4, 4, 2, 1, 2)

    except TypeError:
        ac.console(" ACBIB: Error while initializing.")

    return "ACBIB"
Exemple #7
0
    def read_and_validate_config():
        config = ConfigParser(defaults=DEFAULT_CONFIG_DICT, default_section=INI_SECTION)
        if not os.path.isfile(INI_FILE):
            with open(INI_FILE, 'w') as f:
                config.write(f)
        with open(INI_FILE) as f:
            config.read_file(f)

        bt_forward = config.get(INI_SECTION, BUTTON_FORWARD, fallback=DEFAULT_CONFIG_DICT[BUTTON_FORWARD])
        bt_back = config.get(INI_SECTION, BUTTON_BACK, fallback=DEFAULT_CONFIG_DICT[BUTTON_BACK])
        raspberry_ip = config.get(INI_SECTION, RASPBERRY_IP, fallback=DEFAULT_CONFIG_DICT[RASPBERRY_IP])
        raspberry_udp_port = config.get(INI_SECTION, RASPBERRY_UDP_PORT, fallback=DEFAULT_CONFIG_DICT[RASPBERRY_UDP_PORT])
        hz = config.get(INI_SECTION, HZ, fallback=DEFAULT_CONFIG_DICT[HZ])
        show_debug_window = config.getboolean(INI_SECTION, SHOW_DEBUG_WINDOW, fallback=False)

        try:
            bt_forward = int(bt_forward)
            bt_back = int(bt_back)
            raspberry_udp_port = int(raspberry_udp_port)
            hz = int(hz)
            if not validate_ip(raspberry_ip):
                raise Exception('IP for Raspberry PI is not valid')
            if not 1024 < raspberry_udp_port <= 65535:
                raise Exception('UDP Port for Raspberry PI is not valid')
        except Exception as e:
            ac.log(str(e))
            ac.console(str(e))
            return DEFAULT_CONFIG_DICT, False
        return dict(button_forward=bt_forward, button_back=bt_back, raspberry_ip=raspberry_ip,
                    raspberry_udp_port=raspberry_udp_port, hz=hz, show_debug_window=show_debug_window), True
def acUpdate(deltaT):
    global timer, timer1, timer2, flagtype, appWindow

    timer += deltaT
    timer1 += deltaT
    if timer2 < 5:
        timer2 += deltaT

    # for keeping the app visible at beginning
    if timer2 <= 5:
        start_info()

    # normal app functionality
    else:
        # Limit frequency to 60hz
        if timer > 0.0166:
            timer = 0
            flagtype = info.graphics.flag
            check_flag_type()
            ac.console(str(flagtype))

        # Limit frequency to 0.5 hz to keep app background visible for 2 seconds
        if timer1 > 2:
            timer1 = 0
            ac.setBackgroundOpacity(appWindow, 0)
def acMain(ac_version):
    global appWindow, label1, logPrefix, appName, splitsRenderer
    ac.console(logPrefix + "acMain")
    try:
        appWindow = ac.newApp(appName)
        ac.setTitle(appWindow, "")
        ac.setSize(appWindow, 300, 300)
        ac.drawBorder(appWindow, 0)
        ac.setBackgroundOpacity(appWindow, 0.3)

        resetBtn = ac.addButton(appWindow, "R")
        ac.setPosition(resetBtn, 5, 30)
        ac.setSize(resetBtn, 30, 30)
        ac.addOnClickedListener(resetBtn, onResetClicked)

        newSplitBtn = ac.addButton(appWindow, "N")
        ac.setPosition(newSplitBtn, 40, 30)
        ac.setSize(newSplitBtn, 30, 30)
        ac.addOnClickedListener(newSplitBtn, onNewSplitClicked)

        #label1 = ac.addLabel(appWindow, "____")
        #ac.setPosition(label1, 0, 70)

        splitsRenderer = SplitsRenderer(2, 62, 10, 10)

        ac.addRenderCallback(appWindow, onRender)
        ac.addOnAppActivatedListener(appWindow, onActivate)
        ac.addOnAppDismissedListener(appWindow, onDismiss)

        ac.console(logPrefix + "Initialized")
    except:
        printExceptionInfo("acMain")

    return appName
def loadDRSZones():
    zones = []
    try:
        track_name = ac.getTrackName(0)
        track_config = ac.getTrackConfiguration(0)
        if track_config is not None:
            drsIni = "content\\tracks\\%s\\%s\\%s" % (track_name, track_config,
                                                      "data\\drs_zones.ini")
        else:
            drsIni = "content\\tracks\\%s\\%s" % (track_name,
                                                  "data\\drs_zones.ini")
        drsExists = os.path.isfile(drsIni)

        if drsExists:
            config = configparser.ConfigParser()
            config.read(drsIni)
            for zone in config.sections():
                zone_info = {
                    "detection": float(config[zone]['DETECTION']),
                    "start": float(config[zone]['START']),
                    "end": float(config[zone]['END'])
                }
                zones.append(zone_info)
        else:
            ac.console(APP_NAME + ": could not find drs_zones.ini file")
            return False
    except Exception as e:
        ac.console(APP_NAME + ": Error in loadDrsZones: %s" % e)
    return zones
Exemple #11
0
def printExceptionInfo(contextName=''):
    global logPrefix
    ac.console(
        logPrefix +
        "Exception[{}]: {}".format(contextName, traceback.format_exc(1)))
    ac.log(logPrefix +
           "Exception[{}]: {}".format(contextName, traceback.format_exc()))
def onResetClicked(*args):
    global logPrefix, multisplitapp
    ac.console(logPrefix + "onResetClicked()")
    try:
        if multisplitapp:
            multisplitapp.reset()
    except:
        printExceptionInfo("onResetClicked")
def onDismiss(*args):
    global logPrefix, multisplitapp
    ac.console(logPrefix + "onDismiss()")
    try:
        if multisplitapp:
            multisplitapp = None
    except:
        printExceptionInfo("onDismiss")
Exemple #14
0
def acUpdate(deltaT):
	try:
		global ov1_info
		# init the app updates
		ov1_info.on_update(deltaT)
		
	except Exception as e:
		ac.console("OV1: Error in function acUpate(): %s" % e)
		ac.log("OV1: Error in function acUpate(): %s" % e)
def getTrackLength():
    try:
        trackLengthFloat = ac.getTrackLength(0)

        return trackLengthFloat
    except Exception as e:
        ac.console(APP_NAME + ": Error in getTrackLength: %s" % e)
        ac.log(APP_NAME + ": Error in getTrackLength: %s" % e)
        return 0
Exemple #16
0
def onFormRender(deltaT):
	try:
		global ov1_info
		# init on_render function
		ov1_info.on_render()

	except Exception as e:
		ac.console("OV1: Error in function onFormRender(): %s" % e)
		ac.log("OV1: Error in function onFormRender(): %s" % e)
Exemple #17
0
def acShutdown():
	try:
		global ov1_info
		# init on_render function
		ov1_info.on_shutdown()

	except Exception as e:
		ac.console("OV1: Error in function acShutdown(): %s" % e)
		ac.log("OV1: Error in function acShutdown(): %s" % e)
Exemple #18
0
def log(message, console=True, app_log=True):
    """ Logs a message on the log and console. """
    time_str = datetime.utcnow().strftime("%H:%M:%S.%f")
    formated = "[LT][{}] {}".format(time_str, message)

    if console:
        ac.console(formated)

    if app_log:
        ac.log(formated)
Exemple #19
0
def debug(message):
    global appName

    fileDebug = False
    consoleDebug = False

    if fileDebug:
        ac.log(appName + ": " + message)
    if consoleDebug:
        ac.console(appName + ": " + message)
    def __init__(self, appWindow, x, y):
        # Init containers
        self.lapCount = 0
        self.bestLap = 0
        self.bestLapNum = 0
        self.lastLap = 0
        self.currentLap = 0
        self.lapValid = True

        ac.console("Lap valid? {}".format(self.lapValid))
Exemple #21
0
def acMain(ac_version):
    global app, APPNAME
    try:
        """ Must init Pygame now and must be first before trying to access the gamedevice.device object"""
        pygame.init()
        app = PDU1800DataProvider(APPNAME)
        return APPNAME
    except Exception as e:
        ac.log("Error in acMain: {}".format(str(e)))
        ac.console("Error in acMain: {}".format(str(e)))
Exemple #22
0
def acUpdate(deltaT):
    global s, addr, client_stat, ai_lane, fileDest
    global sct, monitor, seq
    global csvfile, writer, starttime
    try:
        recv = s.recvfrom(1024)
        client_stat = recv[0].decode().split('\n')[0]
        addr = recv[1]
        if client_stat == 'init':
            s.sendto((fileDest + '\n').encode(), addr)
        elif client_stat == 'query':
            ego_stat['time'] = time.time() - starttime
            s.sendto((json.dumps(ego_stat) + '\n').encode(), addr)
        elif client_stat == 'imquery':
            im = sct.grab(monitor)
            fname = "{:02d}.png".format(seq)
            mss.tools.to_png(im.rgb,
                             im.size,
                             level=1,
                             output=("apps/python/aclab_py/captures/" + fname))
            s.sendto((os.path.join(os.getcwd(), 'apps', 'python', 'aclab_py',
                                   'captures', fname) + '\n').encode(), addr)
            seq = (seq + 1) % 10
    except:
        # ac.console(client_stat)
        ego_stat['gas'] = info.physics.gas
        ego_stat['brake'] = info.physics.brake
        ego_stat['steerAngle'] = info.physics.steerAngle
        ego_stat['velocity'] = info.physics.velocity[:]
        ego_stat['accG'] = info.physics.accG[:]
        ego_stat['wheelSlip'] = info.physics.wheelSlip[:]
        ego_stat['wheelLoad'] = info.physics.wheelLoad[:]
        ego_stat['heading'] = info.physics.heading
        ego_stat['pitch'] = info.physics.pitch
        ego_stat['roll'] = info.physics.roll
        ego_stat['localAngularVel'] = info.physics.localAngularVel[:]
        ego_stat['localVelocity'] = info.physics.localVelocity[:]
        ego_stat['normalizedCarPosition'] = info.graphics.normalizedCarPosition
        ego_stat['carCoordinates'] = info.graphics.carCoordinates[:]
        ego_stat['surfaceGrip'] = info.graphics.surfaceGrip
        ego_stat['numCars'] = info.static.numCars
        for car in range(info.static.numCars):
            if car is 0:
                continue
            env_stat['velocity'] = ac.getCarState(car, acsys.CS.Velocity)
            env_stat['normalizedCarPosition'] = ac.getCarState(
                car, acsys.CS.NormalizedSplinePosition)
            env_stat['carCoordinates'] = ac.getCarState(
                car, acsys.CS.WorldPosition)
            ego_stat['env_stat'][car] = copy.deepcopy(env_stat)
            # ac.console(json.dumps(ego_stat)+'\n')
        ac.console(str(time.time() - starttime - ego_stat['time']))
        if time.time() - starttime - ego_stat['time'] > 0.99:
            writer.writerow(ego_stat)
            ego_stat['time'] = time.time() - starttime
Exemple #23
0
	def __init__(self, path, filename):
		self.file = path + filename
		self.parser = 0
		
		try:
			self.parser = configparser.RawConfigParser()
		except:
			ac.console("OV1: Config -- Failed to initialize ConfigParser.")
		
		# read the file
		self._read()
Exemple #24
0
	def has(self, section=None, option=None):
		if section is not None:
			# if option is not specified, search only for the section
			if option is None:
				return self.parser.has_section(section)
			# else, search for the option within the specified section
			else:
				return self.parser.has_option(section, option)
		# if section is not specified
		else:
			ac.console("OV1: Config.has -- section must be specified.")
Exemple #25
0
def debug(e):
    exc_type, exc_obj, tb = sys.exc_info()
    f = tb.tb_frame
    lineno = tb.tb_lineno
    filename = f.f_code.co_filename
    linecache.checkcache(filename)
    line = linecache.getline(filename, lineno, f.f_globals)
    #ac.console( 'CamTool 2: EXCEPTION IN ({}, LINE {} "{}"): {}'.format(filename, lineno, line.strip(), exc_obj) )
    ac.console('CamTool 2: EXCEPTION IN (LINE {}): {}'.format(lineno, exc_obj))
    ac.log('CamTool 2: EXCEPTION IN ({} LINE {}): {}'.format(
        filename, lineno, exc_obj))
Exemple #26
0
def WriteData():

    ac.console("[PV]Tires:" + Tires + ",Fuel:" + Gas + "Fix body:" + FixBody + "Fix engine:" + FixEngine + "Fix suspension:" + FixSuspension)
    ac.log("[PV]Tires:" + Tires + ",Fuel:" + Gas + "Fix body:" + FixBody + "Fix engine:" + FixEngine + "Fix suspension:" + FixSuspension)
    
    with open('apps/python/PitVoice/Pit.txt', 'w') as f:
          f.write(Tires + "\n")
          f.write(Gas + "\n")
          f.write(FixBody + "\n")
          f.write(FixEngine + "\n")
          f.write(FixSuspension)
          f.close()
def onActivate(*args):
    global logPrefix, multisplitapp
    ac.console(logPrefix + "onActivate()")
    try:
        trackName = ac.getTrackName(0)
        trackConfig = ac.getTrackConfiguration(0)

        multisplitapp = Multisplit(trackName, trackConfig)
        #ac.setText(label1, multisplitapp.getInfoText())

    except:
        printExceptionInfo("onActivate")
Exemple #28
0
def cout(x, y=""):
    if running_in_ac:
        if y == "":
            ac.console("CamTool 2: {}".format(x))
            ac.log("CamTool 2: {}".format(x))
        else:
            ac.console("CamTool 2: {} -> {}".format(x, y))
            ac.log("CamTool 2: {} -> {}".format(x, y))
    else:
        if y == "":
            print("CamTool 2: {}".format(x))
        else:
            print("CamTool 2: {} -> {}".format(x, y))
Exemple #29
0
def acUpdate(deltaT):
    global l_lapcount, lapcount, l_laptime, laptime

    # Don't write anything to the console from here unless it's in an if statement - it causes a crash, deltaT must
    # be approx every ms

    # Update current lap time in app window
    laptime = (ac.getCarState(0, acsys.CS.LapTime)) / 1000
    ac.setText(l_laptime, "Current lap (s): {}".format(laptime))

    # if statement using difference between lapcount and the laps output from AC to record data

    laps = ac.getCarState(0, acsys.CS.LapCount)

    if laps > lapcount:
        # Uses the difference between laps and lap count to limit recording to once per lap
        lapcount = laps
        ac.setText(l_lapcount, "Laps Completed: {}".format(lapcount))

        # Write last lap data to csv
        last_lap_raw = ((ac.getCarState(0, acsys.CS.LastLap))) / 1000
        ac.console("**Last_lap recorded")
        last_lap_m = last_lap_raw // 60
        last_lap_s = last_lap_raw % 60
        ac.console("**Last_lap split into minutes and seconds")
        with open('stintoutputfile.csv', 'a') as f:
            f.write("{},{:.0f}:{:.3f}\n".format(lapcount, last_lap_m,
                                                last_lap_s))
            ac.console("** stint tracker: lap written to file")
            ac.console("{},{:.0f}:{:.3f}\n".format(lapcount, last_lap_m,
                                                   last_lap_s))
Exemple #30
0
	def w(message):
		exc_type, exc_value, exc_traceback = sys.exc_info()
		lines = traceback.format_exception(exc_type, exc_value, exc_traceback)
		ac.console(message + ":")		
		for line in lines:               
			ac.log(line)
		for line in lines:
			if line.find("Traceback")>=0:
				continue
			s = line.replace("\n"," -> ")
			s = s.replace("  ","")
			if s[-4:] == " -> ":
				s=s[:-4]			
			ac.console(s)
Exemple #31
0
def acMain(ac_version):
    global scorelabel, currentscorelabel
    appWindow = ac.newApp("clubhighscores")
    ac.setSize(appWindow, 200, 200)
    ac.console("Club highsscores active!")
    currentscorelabel = ac.addLabel(appWindow, "")
    ac.setPosition(currentscorelabel, 3, 27)
    #lastlaptimelabel = ac.addLabel(appWindow, "");
    #ac.setPosition(lastlaptimelabel, 3, 50);
    scorelabel = ac.addLabel(appWindow, "No connection to Server")
    ac.setPosition(scorelabel, 3, 50)
    #73
    UpdateScores()
    return "clubhighscores"
Exemple #32
0
def acParse(aiFile):
    with open(aiFile, 'rb') as ai:
        header = struct.unpack('IIII', ai.read(16))
        lineLen = header[1]
        fmt = {}
        fmt['pathX'] = [0] * lineLen
        fmt['pathY'] = [0] * lineLen
        fmt['pathZ'] = [0] * lineLen
        fmt['travel'] = [0] * lineLen
        fmt['speed'] = [0] * lineLen
        fmt['accel'] = [0] * lineLen
        fmt['yawrate'] = [0] * lineLen
        fmt['radius'] = [0] * lineLen
        fmt['offLeft'] = [0] * lineLen
        fmt['offRight'] = [0] * lineLen
        fmt['nPidx'] = [0] * lineLen  # Int
        fmt['direction'] = [0] * lineLen
        fmt['pathLeftX'] = [0] * lineLen
        fmt['pathLeftY'] = [0] * lineLen
        fmt['pathRightX'] = [0] * lineLen
        fmt['pathRightY'] = [0] * lineLen

        for i in range(lineLen):
            temp = struct.unpack('ffffI', ai.read(20))
            fmt['pathX'][i] = temp[0]
            fmt['pathZ'][i] = temp[1]
            fmt['pathY'][i] = temp[2]
            fmt['travel'][i] = temp[3]
            fmt['nPidx'][i] = temp[3] / trackLength

        for i in range(lineLen):
            temp = struct.unpack('f' * 18, ai.read(72))
            fmt['speed'][i] = temp[1]
            fmt['accel'][i] = temp[2]
            fmt['yawrate'][i] = temp[4]
            fmt['radius'][i] = temp[5]
            fmt['offLeft'][i] = temp[6]
            fmt['offRight'][i] = temp[7]
            fmt['direction'][i] = math.atan2(temp[16], temp[14])
            fmt['pathLeftX'][i] = fmt['pathX'][i] + math.sin(
                fmt['direction'][i]) * temp[6]
            fmt['pathLeftY'][i] = fmt['pathY'][i] - math.cos(
                fmt['direction'][i]) * temp[6]
            fmt['pathRightX'][i] = fmt['pathX'][i] - math.sin(
                fmt['direction'][i]) * temp[6]
            fmt['pathRightY'][i] = fmt['pathY'][i] + math.cos(
                fmt['direction'][i]) * temp[6]
    ac.console('End Parsing AI lane')
    return fmt
Exemple #33
0
def onEnableButtonClicked():
    global cfg, ui_enableButton

    ac.console(logPrefix + "Enable button clicked")

    if cfg.enable > 0:
        cfg.enable = 0
        ac.setText(ui_enableButton, "Enable")
        stopTelemetry()
    else:
        cfg.enable = 1
        ac.setText(ui_enableButton, "Disable")
        startTelemetry()

    cfg.save()
Exemple #34
0
def getActualFollow():
    global viewers,CHAN,PASS,fetching
    fetching = True
    try:
        headers = {'Accept': 'application/vnd.twitchtv.v3+json'}
        r = urllib.get('https://api.twitch.tv/kraken/streams/'+CHAN[1:]+'?oauth_token='+PASS[6:], headers=headers)
        jsonData = r.json()
        ac.console('json {}'.format(jsonData))
        if jsonData['stream'] != None:
            viewers = str(jsonData['stream']['viewers'])
        else:
            viewers = 'offline'
    except:
        pass
    fetching = False
Exemple #35
0
 def load_delta(self):
     self.deltaLoaded = True
     file = self.get_delta_file_path()
     if os.path.exists(file):
         try:
             with gzip.open(file, 'rt') as data_file:
                 data = json.load(data_file)
                 self.referenceLapTime.setValue(data["lap"])
                 times = data["times"]
                 self.referenceLap = []
                 for t in times:
                     self.referenceLap.append(raceGaps(t[0], t[1]))
                 ac.console("AC Delta: File loaded")
         except:
             Log.w("Error tower")
Exemple #36
0
 def loadDelta(self):
     self.deltaLoaded = True
     file = self.getDeltaFilePath()
     if os.path.exists(file):
         try:
             with gzip.open(file, "rt") as data_file:
                 data = json.load(data_file)
                 self.referenceLapTime.setValue(data["lap"])
                 times = data["times"]
                 self.referenceLap = []
                 for t in times:
                     self.referenceLap.append(raceGaps(t[0], t[1]))
                 ac.console("AC Delta: File loaded")
         except:
             Log.w("Error tower")
Exemple #37
0
def acMain(ac_version):
	try:
		global ov1_info
		# initialize the app
		ov1_info = App()
		# create the app objects
		ov1_info.start_up()
		# add render callback
		ov1_info.window.onRenderCallback(onFormRender)
		# return the app's ID
		return "OV1Info"
	
	except Exception as e:
		ac.console("OV1: Error in function acMain(): %s" % e)
		ac.log("OV1: Error in function acMain(): %s" % e)
Exemple #38
0
def acMain(ac_version):
  global appWindow,sharedMem

  appWindow = ac.newApp("CrewChiefEx")

  ac.setTitle(appWindow, "CrewChiefEx")
  ac.setSize(appWindow, 300, 40)

  ac.log("CrewChief Was Here! damage report ?")
  ac.console("CrewChief Was Here! damage report ?")

  sharedmem = sharedMem.getsharedmem()
  sharedmem.serverName = ac.getServerName().encode('utf-8')

  return "CrewChiefEx"
Exemple #39
0
def acMain(ac_version):
    global l_lapcount, b_benzina

    appWindow = ac.newApp("benza")
    ac.setSize(appWindow, 200, 200)

    ac.log("Benza Start")
    ac.console("Benza is running")

    l_lapcount = ac.addLabel(appWindow, "Laps: 0")
    b_benzina = ac.addLabel(appWindow, "Fuel: 0")

    ac.setPosition(l_lapcount, 3, 30)

    return "benza"
Exemple #40
0
def acMain(ac_version):
    global appWindow, sharedMem

    appWindow = ac.newApp("SecondMonitorEx")

    ac.setTitle(appWindow, "SecondMonitorEx")
    ac.setSize(appWindow, 300, 40)

    ac.log("SecondMonitor Shared memory Initialized")
    ac.console("SecondMonitor Shared memory Initialized")

    sharedmem = sharedMem.getsharedmem()
    sharedmem.serverName = ac.getServerName().encode('utf-8')
    sharedmem.acInstallPath = os.path.abspath(os.curdir).encode('utf-8')
    sharedmem.pluginVersion = pluginVersion.encode('utf-8')
    return "SecondMonitorEx"
def acMain(ac_version):

    global l_lapcount

    # render app widget
    appWindow = ac.newApp("Lap Counter")
    ac.setSize(appWindow, 200, 75)

    # output to console and python log
    ac.console("Simple Lap Counter - loaded")
    ac.log("Simple Lap Counter - loaded")

    # displaying labels
    l_lapcount = ac.addLabel(appWindow, "Laps: 0")
    ac.setPosition(l_lapcount, 10, 40)
    return "Lap Counter"
Exemple #42
0
	def set(self, section=None, option=None, value=None):
		if section is not None:
			# if option is not specified, add the specified section
			if option is None:
				self.parser.add_section(section)
				self._write()
			# else, add the option within the specified section
			else:
				if not self.has(section, option) and value is None:
					ac.console("OV1: Config.set -- a value must be passed.")
				else:
					self.parser.set(section, option, value)
					self._write()
		# if sections is not specified
		else:
			ac.console("OV1: Config.set -- section must be specified.")
def acMain(ac_version):
    global l_lapcount, b_benzina


    appWindow = ac.newApp("benza")
    ac.setSize(appWindow, 200, 200)

    ac.log("Benza Start")
    ac.console("Benza is running")

    l_lapcount = ac.addLabel(appWindow, "Laps: 0");
    b_benzina  = ac.addLabel(appWindow, "Fuel: 0");

    ac.setPosition(l_lapcount, 3, 30)

    return "benza"
def acMain(ac_version):

	appWindow = ac.newApp("Pedal Circles")
	ac.setSize(appWindow, 412, 250)
	ac.setTitle(appWindow, "")
	# ac.setBackgroundOpacity(appWindow, 0) ~ doesn't change anything
	ac.setIconPosition(appWindow, 0, -10000)
	ac.console("Hello Assetto, this is Pedal Circles")

	brake_display = ac.addLabel(appWindow, "")
	ac.setPosition(brake_display, 3, 25)
	ac.setSize(brake_display, 200, 200)

	gas_display = ac.addLabel(appWindow, "")
	ac.setPosition(gas_display, 207, 25)
	ac.setSize(gas_display, 200, 200) 

	return "brake"
def acMain(ac_version):
    try:
        global appHeight, appWidth, appWindow, flLabel, frLabel, rlLabel, rrLabel, upperDistance, distanceFromLeft, tyreWidth, tyreHeight
        distanceFromLeft = tyreWidth * 3
        upperDistance = distanceFromLeft
        appWindow = ac.newApp("Traction Loss")
        appWidth = distanceFromLeft * 2 + tyreWidth * 3
        appHeight = upperDistance * 2 + tyreHeight * 3
        ac.setSize(appWindow, appWidth, appHeight)
        define_tachometer()
        if debug:
            create_debug_labels()

        #ac.drawBorder(appWindow, 0)
        ac.addRenderCallback(appWindow, on_update)

        return "Traction Loss"
    except Exception as e:
        ac.console("TractionLoss: Error in function acMain(): %s" % e)
        ac.log("TractionLoss: Error in function acMain(): %s" % e)
def pyroserver():
  Pyro4.config.SERIALIZER = 'pickle'
  Pyro4.config.PICKLE_PROTOCOL_VERSION = 3
  Pyro4.config.SERIALIZERS_ACCEPTED = set(['pickle'])
  Pyro4.config.SOCK_REUSE = True
  Pyro4.config.DETAILED_TRACEBACK = True
  Pyro4.config.FLAME_ENABLED = True

  try:
    # FIXME: Listening on '' is not working here
    # it listens properly, but the Pyro client then reconnects to localhost
#    daemon = Pyro4.core.Daemon(host='', port=9999)  # FIXME
# EDIT the IP below
    daemon = Pyro4.core.Daemon(host='192.168.1.77', port=9999)  # hot_app
    uri = Pyro4.utils.flame.start(daemon)
    ac.console('uri %s' % uri)
    daemon.requestLoop()
    daemon.close()
  except:
    log_error()
    raise
Exemple #47
0
def acMain(ac_version):
    global appWindow, trackname, tracklength, l_lapcount, l_distance, l_fuel, conn, c

    appWindow = ac.newApp("acOdometer")
    ac.setSize(appWindow, 142, 142)

    l_lapcount = ac.addLabel(appWindow, "Laps: Outlap")
    ac.setPosition(l_lapcount, 3, 30)
    l_distance = ac.addLabel(appWindow, "Kilometers: Outlap")
    ac.setPosition(l_distance, 3, 45)
    l_fuel = ac.addLabel(appWindow, "Fuel used: 0")
    ac.setPosition(l_fuel, 3, 60)

    trackname = ac.getTrackName(0)
    carname = ac.getCarName(0)
    t = int(time.time())
    c.execute("INSERT INTO session('date', 'track', 'car') values (?, ?, ?)", (t, trackname, carname)) # Commited atomically at end of session
    ac.log("*************************** NEW SESSION\n********* " + trackname)
    ac.log("acOdometer loaded, racing {} which has {:.3f} miles per lap".format(trackname, tracklength[trackname]))
    ac.console("acOdometer loaded, racing {} which has {:.3f} kilometers per lap.".format(trackname, tracklength[trackname]))
    return "acOdometer"
Exemple #48
0
def acUpdate(deltaT):
    global PitButton,Speed,DoPitOnce
    
    
    Speed = ac.getCarState(0,acsys.CS.SpeedMS)
    
    if Speed <= 0.060 and DoPitOnce == 0:
    	PitButton = "1"
    	DoPitOnce = 1
    	PushPitButton()
		
    if DoPitOnce == 1:
        PitButton = "0"
        PushPitButton()
    	
    if Speed > 0.060:
    	DoPitOnce = 0
    	PushPitButton()

    ResponseWit()
    ac.console("[PV]Refresh at " + str(datetime.datetime.now()))
    ac.log("[PV]Refresh at " + str(datetime.datetime.now()))
Exemple #49
0
def acUpdate(deltaT):
    global tick, trackname, lapcount, l_lapcount, l_distance, l_fuel, distance, in_tank, fuel
    tick += 1

    # info.physics.fuel is 0 until the outlap begins
    if in_tank == 0:
        in_tank = info.physics.fuel

    current_tank = info.physics.fuel
    difference = in_tank - round(current_tank, 2)
    if difference > 0.01:
        in_tank = current_tank
        fuel += difference
        ac.setText(l_fuel, "Fuel used: {:.3f}".format(fuel))

    laps = ac.getCarState(0, acsys.CS.LapCount)
    if laps > lapcount:
        lapcount = laps
        distance += tracklength[trackname]
        ac.log("{} laps of {}. That's {:.3f} kilometers this session".format(lapcount, trackname, distance))
        ac.console("{} laps of {}. That's {:.3f} kilometers this session".format(lapcount, trackname, distance))
        ac.setText(l_lapcount, "Laps: {}".format(lapcount))
        ac.setText(l_distance, "Kilometers: {:.3f}".format(distance))
 def text_align(self, value):
     self._text_align = value
     if value in ('left', 'center', 'right'):
         ac.setFontAlignment(self.id, value)
     else:
         ac.console("Text align <{}> is not supported.".format(value))
#PIT STOP CONFIG ON TRACK (REAL TIME) PLUGIN

import sys
import ac
import acsys

def acMain(ac_version):
    appWindow = ac.newApp("pitstop_on_track")
    ac.setSize(appWindow, 300, 300)
    return "pitstop_on_track"

ac.log("Hello, Assetto Corsa application world!")
ac.console("Hello, Assetto Corsa console!")

def log_error():
  msg = 'Exception: {}\n{}'.format(time.asctime(), traceback.format_exc())
  ac.log(msg)
  ac.console(msg)
  logged_errors.append(msg)
Exemple #53
0
def acShutdown():    
    ac.console("shutting down actv")

    
def acShutdown():
    ac.log("Benza exit")
    ac.console("Benza exit")
Exemple #55
0
	def remSection(self, section):
		if self.has(section):
			self.parser.remove_section(section)
			self._write()
		else:
			ac.console("Prunn: Config.remSection -- section not found.")
Exemple #56
0
	def remOption(self, section, option):
		if self.has(section) and self.has(section, option):
			self.parser.remove_option(section, option)
			self._write()
		else:
			ac.console("OV1: Config.remOption -- option not found.")
Exemple #57
0
    def onUpdate(self, sim_info):
        if self.__class__.configChanged:
            self.saveCFG()
            self.__class__.configChanged = False
        if not self.deltaLoaded:
            thread_load = threading.Thread(target=self.loadDelta)
            thread_load.daemon = True
            thread_load.start()
        if self.__class__.resetPressed:
            self.referenceLapTime.setValue(0)
            self.referenceLap = []
            self.__class__.resetPressed = False
        self.session.setValue(sim_info.graphics.session)
        self.manageWindow()
        self.lbl_delta.animate()
        self.lbl_lap.animate()
        sim_info_status = sim_info.graphics.status
        if sim_info_status == 2:  # LIVE
            sessionTimeLeft = sim_info.graphics.sessionTimeLeft
            if math.isinf(
                sessionTimeLeft
            ):  # or (sim_info.graphics.iCurrentTime == 0 and sim_info.graphics.completedLaps == 0):
                self.resetData()
            elif self.session.value == 2 and sessionTimeLeft > 1800000:
                self.resetData()
            elif bool(ac.isCarInPitline(0)) or bool(ac.isCarInPit(0)):
                self.resetData()
            self.spline.setValue(round(ac.getCarState(0, acsys.CS.NormalizedSplinePosition), 3))

            if self.lastLapIsValid and sim_info.physics.numberOfTyresOut >= 4:
                self.lastLapIsValid = False

            if self.spline.hasChanged():
                self.laptime.setValue(round(ac.getCarState(0, acsys.CS.LapTime), 3))
                self.lastLapTime.setValue(ac.getCarState(0, acsys.CS.LastLap))
                gap = self.getPerformanceGap(self.spline.value, self.laptime.value)
                if gap != False:
                    self.performance.setValue(gap)
                # new lap
                if self.lastLapTime.hasChanged():
                    # ac.console("newlap----")(self.laptime.old > self.laptime.value) or
                    # ac.console("lastLap=currentLap---waiting " + str(self.laptime.old) + ":" + str(self.laptime.value))
                    # ac.log(str(time.time()) +" lastLap=currentLap---waiting " + str(self.laptime.old) + ":" + str(self.laptime.value))
                    if (
                        (self.referenceLapTime.value == 0 or self.lastLapTime.value < self.referenceLapTime.value)
                        and self.lastLapIsValid
                        and self.lastLapTime.value > 0
                        and self.lapCount < ac.getCarState(0, acsys.CS.LapCount)
                    ):
                        self.referenceLapTime.setValue(self.lastLapTime.value)
                        # self.referenceLap=list(self.lastLap)
                        self.referenceLap = list(self.currentLap)
                        if len(self.referenceLap) > 2000:  # 2laps in
                            ac.console("too many laps in reference----")
                            ac.log("too many laps in reference----")
                            how_much = math.floor(len(self.referenceLap) / 1000)
                            del self.referenceLap[0 : math.floor(len(self.referenceLap) / how_much)]
                        # self.referenceLap=self.lastLap#self.lastLap=list(self.currentLap)
                        # ac.log(str(time.time()) +" referenceLap=lastlap --- lets save")
                        # ac.console("referenceLap=lastlap --- lets save")
                        thread_save = threading.Thread(target=self.saveDelta)
                        thread_save.daemon = True
                        thread_save.start()
                        # make it green for 5 sec
                        self.highlight_end = sim_info.graphics.sessionTimeLeft - 6000
                        self.lbl_lap.setColor(Colors.green(), True)
                    # else:
                    #    ac.log(str(time.time()) +" dismissed")
                    # self.lastLap=self.currentLap
                    self.currentLap = []
                    self.lapCount = ac.getCarState(0, acsys.CS.LapCount)
                    self.lastLapIsValid = True

                self.currentLap.append(raceGaps(self.spline.value, self.laptime.value))
                # ac.console("--currentLap : " + str(len(self.currentLap)) + " --lastLap : " + str(len(self.lastLap)) + " --referenceLap : " + str(len(self.referenceLap)))

            # update graphics
            if not math.isinf(sessionTimeLeft):
                self.TimeLeftUpdate.setValue(int(sessionTimeLeft / 500))
            if self.TimeLeftUpdate.hasChanged():
                if self.performance.hasChanged():
                    time_prefix = ""
                    color = Colors.white()
                    if self.performance.value > 0:
                        time_prefix = "+"
                        if self.lastLapIsValid:
                            color = Colors.yellow()
                        else:
                            color = Colors.red()
                    elif self.performance.value < 0:
                        time_prefix = "-"
                        if self.lastLapIsValid:
                            color = Colors.green()
                        else:
                            color = Colors.orange()
                    else:
                        if not self.lastLapIsValid:
                            color = Colors.red()
                    self.lbl_delta.setText(
                        time_prefix + self.time_splitting(abs(self.performance.value), "yes")
                    ).setColor(color, True)

            if self.referenceLapTime.hasChanged():
                self.lbl_lap.setText(self.time_splitting(self.referenceLapTime.value, "yes"))
            if self.highlight_end == 0 or sessionTimeLeft < self.highlight_end:
                self.lbl_lap.setColor(Colors.white(), True)
def acUpdate(deltaT):
	global window_width, have_setup, indicated_max_rpm, max_rpm, indicated_max_speed
	global rpm_pivot_x, rpm_pivot_y, speed_pivot_x, speed_pivot_y, tach_radius, speedo_radius, max_fuel
	global fuel_warning_label, dt_ratio
	global draw_boost_gauge
	global rpms_file
	ac.setBackgroundOpacity(window,0)
	if have_setup:
		telemetry_client.tick()
	if debug_mode:
		ac.setText(debug_label,"%2.2f" % (ac.getCarState(0,acsys.CS.DriveTrainSpeed)/ac.getCarState(0,acsys.CS.SpeedKMH)))
	if have_setup == 0:
		max_rpm = sim_info.static.maxRpm
		ac.console("Maximum RPM for car %s: %d" %(ac.getCarName(0),max_rpm))
		if max_rpm < 500:
			if rpms_file.has_section(ac.getCarName(0)):
				max_rpm = int(rpms_file[ac.getCarName(0)]['max_rpm'])
			else:
				ac.console("Don't know max RPMs for this car, go play with it in practice mode first!")
				max_rpm = 20000
		else:
			if not rpms_file.has_section(ac.getCarName(0)):
				rpms_file.add_section(ac.getCarName(0))
			rpms_file[ac.getCarName(0)]['max_rpm'] = str(max_rpm)
			with open('apps/python/AnalogInstruments/rpms.ini','w') as file:
				rpms_file.write(file)
			ac.console("Learned max RPM for this car")
		telemetry_client.connect()
		ac.log("Opening car info file")
		carinfo_file = configparser.ConfigParser()
		carinfo_file.read("apps/python/AnalogInstruments/carinfo.ini")
		ac.log("Got car info file")
		if carinfo_file.has_section(ac.getCarName(0)):
			ac.log("Found car in file")
			dt_ratio = float(carinfo_file[ac.getCarName(0)]['ratio'])
			ac.log("Got ratio")
			indicated_max_speed = int(carinfo_file[ac.getCarName(0)]['top_speed'])
			ac.log("Got top speed")
			has_turbo = carinfo_file[ac.getCarName(0)].getboolean('has_turbo')
			ac.log("Got turbo")
		else:
			ac.console("Car %s isn't in carinfo.ini!" % ac.getCarName(0))
			dt_ratio = 1
			indicated_max_speed = 320
			has_turbo = True
		if (not has_turbo or not draw_boost_gauge) and draw_background:
			ac.setBackgroundTexture(window,background_image_path_noboost)
			draw_boost_gauge = False
		# Max fuel
		ac.log("Getting things from SHM")
		max_fuel = sim_info.static.maxFuel
		car_model = sim_info.static.carModel
		compound  = str(sim_info.graphics.tyreCompound)#FIXME
		ac.log("Got things from SHM")
		# Optimal tyre temp range as taken from that forum post
		if "exos_125_s1" in car_model:
			if "SuperSoft" in compound:
				tyre_optimal_temp = range(85,111)
			elif "Soft" in compound:
				tyre_optimal_temp = range(105,126)
			elif "Medium" in compound:
				tyre_optimal_temp = range(90,116)
			elif "Hard" in compound:
				tyre_optimal_temp = range(110,136)
		elif "exos_125" in car_model:
			tyre_optimal_temp = range(90,121)
		elif "Semislick" in compound:
			tyre_optimal_temp = range(75,101)
		elif "Street" in compound:
			tyre_optimal_temp = range(75,86)
		elif "_gt2" in car_model:
			if "SuperSoft" in compound:
				tyre_optimal_temp = range(90,106)
			elif "Soft" in compound:
				tyre_optimal_temp = range(90,106)
			elif "Medium" in compound:
				tyre_optimal_temp = range(85,106)
			elif "Hard" in compound:
				tyre_optimal_temp = range(80,101)
			elif "SuperHard" in compound:
				tyre_optimal_temp = range(80,101)
		elif "70F1" in compound:
			tyre_optimal_temp = range(50,91)
		elif "Soft" in compound:
			tyre_optimal_temp = range(80,111)
		elif "Medium" in compound:
			tyre_optimal_temp = range(75,106)
		elif "Hard" in compound:
			tyre_optimal_temp = range(70,101)
		ac.log("Setting up tach")
		if draw_tachometer:
			# Tach setup
			indicated_max_rpm = max_rpm + 1000 - (max_rpm % 1000)
			# Tach labels
			for i in range(0,indicated_max_rpm+1,1000):
				r = abs(tach_min_angle - tach_max_angle)
				rad  = math.radians(tach_max_angle - (i/indicated_max_rpm)*r)
				label = ac.addLabel(window," ")
				ac.setText(label,"%d" % (i/1000))
				x_offset = 0
				y_offset = 0
				if rad < math.pi/2:
					x_offset = 15 - math.sin(rad)*15
					y_offset = math.cos(rad)*5
				ac.setPosition(label,math.cos(rad)*(tach_radius*4/5)+rpm_pivot_x-x_offset,rpm_pivot_y - math.sin(rad)*(tach_radius*4/5)-y_offset)
		ac.log("Setting up speedo")
		if draw_speedometer:
			# Speedo setup
			if imperial:
				indicated_max_speed = int(indicated_max_speed/1.6) #TODO: round up to multiple of 20
			# Speedo labels
			for i in range(0,indicated_max_speed+1,20):
				r = abs(speedo_min_angle - speedo_max_angle)
				rad = math.radians(speedo_max_angle - (i/indicated_max_speed)*r)
				label = ac.addLabel(window," ")
				ac.setText(label,"%d" % i)
				x_offset = 0
				y_offset = 0
				if rad < math.pi/2:
					x_offset = 23 - math.sin(rad)*23
					y_offset = math.cos(rad)*5
				ac.setPosition(label,math.cos(rad)*speedo_radius*4/5+speed_pivot_x-x_offset,speed_pivot_y - math.sin(rad)*speedo_radius*4/5-y_offset)
		have_setup = 1