diff --git a/.gitignore b/.gitignore index f9ab1f9..f8da70e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ /build /dist -OutGaugeInterpreter.spec \ No newline at end of file +OutGaugeInterpreter.spec +*.csv \ No newline at end of file diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 0000000..aab1162 --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,17 @@ +{ + // See https://go.microsoft.com/fwlink/?LinkId=733558 + // for the documentation about the tasks.json format + "version": "2.0.0", + "tasks": [ + { + "label": "echo", + "type": "shell", + "command": "echo Hello" + }, + { + "label": "build exe windows", + "type": "shell", + "command": "pyinstaller.exe --add-data .\\GAME_METHODS\\*:.\\GAME_METHODS\\ --onefile --noconsole --optimize 2 .\\OutGaugeInterpreter.py" + } + ] +} \ No newline at end of file diff --git a/GAME_METHODS/BEAMNG_METHODS.py b/GAME_METHODS/BEAMNG_METHODS.py index 7b8eecd..cfca7c0 100644 --- a/GAME_METHODS/BEAMNG_METHODS.py +++ b/GAME_METHODS/BEAMNG_METHODS.py @@ -28,9 +28,9 @@ def unpackData(unpackedData): carData = {"time":unpackedData[0], "carName":unpackedData[1].decode("utf-8"), "flags": decodeFlag(unpackedData[2]), - "gear": unpackedData[3], + "Gear": unpackedData[3], "PLID": unpackedData[4], - "speed": unpackedData[5], + "Speed": unpackedData[5], "rpm": unpackedData[6], "turboPressure":unpackedData[7], "engTemp":unpackedData[8], diff --git a/GAME_METHODS/__pycache__/BEAMNG_METHODS.cpython-311.pyc b/GAME_METHODS/__pycache__/BEAMNG_METHODS.cpython-311.pyc index f266701..3f7861a 100644 Binary files a/GAME_METHODS/__pycache__/BEAMNG_METHODS.cpython-311.pyc and b/GAME_METHODS/__pycache__/BEAMNG_METHODS.cpython-311.pyc differ diff --git a/GAME_METHODS/__pycache__/FORZA_METHODS.cpython-311.pyc b/GAME_METHODS/__pycache__/FORZA_METHODS.cpython-311.pyc index e16d4b2..f82d1ff 100644 Binary files a/GAME_METHODS/__pycache__/FORZA_METHODS.cpython-311.pyc and b/GAME_METHODS/__pycache__/FORZA_METHODS.cpython-311.pyc differ diff --git a/GAME_METHODS/__pycache__/__init__.cpython-311.pyc b/GAME_METHODS/__pycache__/__init__.cpython-311.pyc index dad73e2..cccac09 100644 Binary files a/GAME_METHODS/__pycache__/__init__.cpython-311.pyc and b/GAME_METHODS/__pycache__/__init__.cpython-311.pyc differ diff --git a/OutGaugeInterpreter.py b/OutGaugeInterpreter.py index 9504e38..a7d6f98 100644 --- a/OutGaugeInterpreter.py +++ b/OutGaugeInterpreter.py @@ -1,18 +1,25 @@ #please use python 3.11 import socket import struct +import tkinter.ttk import serial import time import platform import sys +import threading from enum import Enum +import tkinter from GAME_METHODS import * +import functools #used for passing variables into callbacks ##check if python 3.11 is running code and exit if not if not(sys.version_info[0] == 3 and sys.version_info[1] == 11): raise Exception("code must be run in python verion 3.11.\ninput struct for network needs to be changed per python version.") + + +##system init runningOs = platform.system() UDP_IP = "0.0.0.0" @@ -20,21 +27,42 @@ BEAMNG_UDP_PORT = 4444 FORZA_UDP_PORT= 4843 SERIAL_PORT = "" firstRun= True #used to do the headers for csv files +pushingToArduino = False +stopThread = False + +class outputValue(Enum): + SPEED = "Speed" + GEAR = "Gear" class GameType(Enum): NONE=0 BEAMNG = "BEAMNG" FORZA = "FORZA" +class ProgramState(Enum): + PUSHING_DATA = 1 + WAITNG = 2 + ERROR = 3 + +appState =ProgramState.WAITNG connectedArduino = False connectedWebSocket = False gameSelected = False portToConnect= 0 -gameType= GameType.NONE carData = 0 csvOut = False #Functions <------------------------------------------------------------------------------------------- +def checkBoxChange(): + if tkLoggingEnabled.get()==True: + loggingLocationEntry.config(state='normal') + loggingLocationText.set(value= "./"+ tkGametype.get()+"_"+str(int(time.time()))+".csv") + loggingLocationEntry.insert(0,loggingLocationText.get()) + else: + loggingLocationText.set(value="") + loggingLocationEntry.delete(0,tkinter.END) + loggingLocationEntry.config(state='disabled') + def csvWriteOut(firstRun,carData,csvFile): if firstRun == True: out="" @@ -46,6 +74,66 @@ def csvWriteOut(firstRun,carData,csvFile): outString = outString + str(num) +"," csvFile.write(outString+"\n") +def runningThread(): + global stopThread + gameType= tkGametype.get() + + #check everything is connected + if gameType==GameType.BEAMNG.value: + portToConnect=BEAMNG_UDP_PORT + elif gameType==GameType.FORZA.value: + portToConnect=FORZA_UDP_PORT + + try: + sock = socket.socket(socket.AF_INET,socket.SOCK_DGRAM) + sock.bind((UDP_IP,portToConnect)) + except: + print("please check you are able to open the socket on this system\ntired to open port: "+str(portToConnect)) + exit() + + try: + toPi=serial.Serial(SERIAL_PORT,115200,timeout=2) #connect to arduino + except: + print("please check connection to arduino and verify the correct serial port") + exit() + + csvOut = tkLoggingEnabled.get() + + if csvOut == True: + csvFile = open(loggingLocationText.get(),"a") + + + + while not stopThread: + data, addr = sock.recvfrom(1024) + if gameType == GameType.BEAMNG.value: + unpackedData = struct.unpack(BEAMNG_METHODS.BEAMNG_DATA_FORMAT,data) + carData = BEAMNG_METHODS.unpackData(unpackedData) + kmh=carData[tkDataTypeOut.get()] + if tkDataTypeOut.get() == "Gear": + kmh = kmh -1 + if csvOut == True: + csvWriteOut(firstRun,carData,csvFile) + firstRun=False + elif gameType == GameType.FORZA.value: + unpackedData = struct.unpack(FORZA_METHODS.FORZA_DATA_FORMAT,data) + carData = FORZA_METHODS.unpackData(unpackedData) + kmh = carData[tkDataTypeOut.get()] + if csvOut == True: + csvWriteOut(firstRun,carData,csvFile) + firstRun=False + + try: + if (tkDataTypeOut.get() == outputValue.SPEED.value): + kmh = kmh*3.6 + + toPi.write(str(kmh).encode()+":".encode()) + except: + print("arduino disconnected please check connection\n") + + + + #code runs from here<----------------------------------------------------------------------------------------------------------- if runningOs == 'Windows': @@ -58,71 +146,86 @@ else: print("OS detection failed setting serial port to 'COM5'\n") SERIAL_PORT = 'COM5' -#select game -while gameSelected == False: - gameNo = input("1:BEAMNG\n2:FORZA\n\n7:Toggle CSV out ("+str(csvOut)+")\n9:SET SERIAL PORT ("+SERIAL_PORT+")\n") - if gameNo == "1": - portToConnect = BEAMNG_UDP_PORT - gameSelected = True - gameType=GameType.BEAMNG - print("BeamNG Selected") - elif gameNo == "2": - portToConnect = FORZA_UDP_PORT - gameType=GameType.FORZA - gameSelected=True - print("Forza Selected") - elif gameNo == "7": - if csvOut == True: - csvOut=False - elif csvOut ==False: - csvOut =True - elif gameNo == "9": - SERIAL_PORT = input("set serial port: ") - else: - print("please select a number from the list") +def startStopButtonFunc(): + global appState + if appState == ProgramState.WAITNG: + startStopButton.config(text="stop") + appState = ProgramState.PUSHING_DATA + stopThread=False + workThread = threading.Thread(target=runningThread) + workThread.start() + statusTextVar.set("Running...") + + elif appState == ProgramState.PUSHING_DATA: + startStopButton.config(text="start") + appState = ProgramState.WAITNG + statusTextVar.set("Waiting...") + stopThread = True + -#check everything is connected -while connectedWebSocket == False: - try: - sock = socket.socket(socket.AF_INET,socket.SOCK_DGRAM) - sock.bind((UDP_IP,portToConnect)) - connectedWebSocket = True - except: - print("please check you are able to open the socket on this system\ntired to open port: "+portToConnect) - exit() + ##GUI init +rootFrameGui= tkinter.Tk() +rootFrameGui.title("Car speed to arduino") +##rootFrameGui.geometry("400x200") -while connectedArduino == False: - try: - toPi=serial.Serial(SERIAL_PORT,115200,timeout=2) #connect to arduino - connectedArduino = True - except: - print("please check connection to arduino and verify the correct serial port") - time.sleep(1) - -if csvOut == True: - csvFile = open(gameType.value+"_"+str(int(time.time()))+'.csv',"a") +bottomBarFrameGui = tkinter.ttk.Frame(rootFrameGui,padding=0,relief="groove",borderwidth=2,) +bottomBarFrameGui.pack(anchor="se",side="bottom",fill="x") +firstFrameGui=tkinter.ttk.Frame(rootFrameGui,padding=2,relief="groove",borderwidth=2) +firstFrameGui.pack(anchor="ne",side="left",expand=True) +secondFrameGui=tkinter.ttk.Frame(rootFrameGui,padding=2,relief="groove",borderwidth=2) +secondFrameGui.pack(anchor="nw",side="right",expand=True) +serialFrameGui = tkinter.ttk.Frame(firstFrameGui,padding=5,relief="groove",borderwidth=2) +serialFrameGui.pack(anchor="nw") +serialLableText =tkinter.StringVar() +serialLableText.set("Serial Port:") +serialLable = tkinter.Label(serialFrameGui,textvariable=serialLableText) +serialLable.pack(side="top") +serialEntry=tkinter.Entry(serialFrameGui) +serialEntry.insert(0,SERIAL_PORT) +serialEntry.pack(side="left") +tkGametype = tkinter.StringVar() +tkGametype.set(GameType.BEAMNG.value) +gameSelectFrame= tkinter.ttk.Frame(secondFrameGui,padding=5,relief="groove",borderwidth=2) +gameSelectFrame.pack(anchor="se") +gameSelectText= tkinter.StringVar() +gameSelectText.set("Select Game:") +gameSelectLable = tkinter.Label(gameSelectFrame,textvariable=gameSelectText) +gameSelectLable.pack(side="top") +tkinter.Label(gameSelectFrame,textvariable=gameSelectText) +gameSelectLOptions= [GameType.BEAMNG,GameType.FORZA] +##gameSelectRadioButtons +##space after text is so the buttons are the same size +tkinter.Radiobutton(gameSelectFrame,text="BeamNG ",variable=tkGametype,value=GameType.BEAMNG.value,command=checkBoxChange).pack(anchor="w") +tkinter.Radiobutton(gameSelectFrame,text="Forza ",variable=tkGametype,value=GameType.FORZA.value,command=checkBoxChange).pack(anchor="w") +tkDataTypeOut = tkinter.StringVar() +tkDataTypeOut.set(outputValue.SPEED.value) +dataTypeFrame = tkinter.ttk.Frame(secondFrameGui,padding=5,relief="groove",borderwidth=2) +dataTypeFrame.pack() +dataTypeLableText = tkinter.StringVar() +dataTypeLableText.set(value="Select Data Type:") +dataTypeLable = tkinter.Label(dataTypeFrame,textvariable=dataTypeLableText).pack(side="top") +tkinter.Radiobutton(dataTypeFrame,text="Speed",variable=tkDataTypeOut,value=outputValue.SPEED.value).pack(anchor="w") +tkinter.Radiobutton(dataTypeFrame,text="Gear",variable=tkDataTypeOut,value=outputValue.GEAR.value).pack(anchor="w") +loggingFrameGui= tkinter.ttk.Frame(firstFrameGui,padding=5,relief="groove",borderwidth=2) +loggingFrameGui.pack(anchor="nw") +tkLoggingEnabled=tkinter.BooleanVar() +tkLoggingEnabled.set(False) +tkinter.Checkbutton(loggingFrameGui,text="Enable Logging",variable=tkLoggingEnabled,onvalue=True,offvalue=False,command=checkBoxChange).pack(side="top") +loggingLocationText = tkinter.StringVar(value="") +loggingLocationEntry = tkinter.Entry(loggingFrameGui) +loggingLocationEntry.insert(0,loggingLocationText.get()) +loggingLocationEntry.config(state='disabled') +loggingLocationEntry.pack(side="bottom") +startStopButton= tkinter.Button(bottomBarFrameGui,text= "start",command= startStopButtonFunc) +startStopButton.pack(side="right",fill="x") +statusTextVar = tkinter.StringVar(value="waiting...") +statusLable = tkinter.Label(bottomBarFrameGui,textvariable= statusTextVar) +statusLable.pack(anchor="w") +arduinoConnectedFrameGui = tkinter.ttk.Frame(secondFrameGui,padding=5,relief="groove",borderwidth=2) +arduinoConnectedFrameGui.pack() +arduinoConnectedStatusText=tkinter.StringVar(value="Connected OK") +arduinoConnectedLable = tkinter.Label(arduinoConnectedFrameGui,textvariable=arduinoConnectedStatusText) +arduinoConnectedLable.pack() - -print("ready:\n") -while True: - data, addr = sock.recvfrom(1024) - if gameType == GameType.BEAMNG: - unpackedData = struct.unpack(BEAMNG_METHODS.BEAMNG_DATA_FORMAT,data) - carData = BEAMNG_METHODS.unpackData(unpackedData) - kmh=carData["speed"]*3.6 - if csvOut == True: - csvWriteOut(firstRun,carData,csvFile) - firstRun=False - elif gameType == GameType.FORZA: - unpackedData = struct.unpack(FORZA_METHODS.FORZA_DATA_FORMAT,data) - carData = FORZA_METHODS.unpackData(unpackedData) - kmh = carData["Speed"]*3.6 - if csvOut == True: - csvWriteOut(firstRun,carData,csvFile) - firstRun=False - try: - toPi.write(str(kmh).encode()+":".encode()) - except: - print("arduino disconnected please check connection\n") - +rootFrameGui.mainloop() diff --git a/createExe.sh b/createExe.sh index cb71036..32b0fe2 100644 --- a/createExe.sh +++ b/createExe.sh @@ -1 +1,3 @@ -pyinstaller.exe --add-data .\GAME_METHODS\*:.\GAME_METHODS\ --onefile .\OutGaugeInterpreter.py \ No newline at end of file +pyinstaller.exe --add-data .\GAME_METHODS\*:.\GAME_METHODS\ --onefile .\OutGaugeInterpreter.py +pyinstaller.exe --add-data .\GAME_METHODS\*:.\GAME_METHODS\ --onefile --noconsole --optimize 2 .\OutGaugeInterpreter.py +pyinstaller --add-data ./GAME_METHODS/*:./GAME_METHODS/ --onefile ./OutGaugeInterpreter.py \ No newline at end of file diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index d0dfd58..0000000 --- a/requirements.txt +++ /dev/null @@ -1 +0,0 @@ -pyserial==3.5