139 lines
6.1 KiB
Python
139 lines
6.1 KiB
Python
from ui import Frame
|
|
from read_arduino import *
|
|
from serial_plotter import *
|
|
from multiprocessing import *
|
|
import os, sys, json, wx, importlib, warnings
|
|
import serial.tools.list_ports
|
|
import numpy as np
|
|
|
|
warnings.filterwarnings("ignore", category=DeprecationWarning)
|
|
|
|
# acknowledgement: https://stackoverflow.com/a/68666505. handles splash screens
|
|
if '_PYIBoot_SPLASH' in os.environ and importlib.util.find_spec("pyi_splash"):
|
|
import pyi_splash
|
|
|
|
pyi_splash.update_text('UI Loaded ...')
|
|
pyi_splash.close()
|
|
|
|
HEIGHT = 800
|
|
WIDTH = 800
|
|
|
|
global ani, t1
|
|
|
|
# TODO: add the option to change the font size of the graph
|
|
def main():
|
|
#################### USER INPUTS ###########################
|
|
r_ref = np.array(
|
|
[frame.r_ref_1.GetValue(), frame.r_ref_2.GetValue(), frame.r_ref_3.GetValue(), frame.r_ref_4.GetValue(),
|
|
0]) # resisters for each An port, where n is an integer from 0-3. Use 0 if none. in Ohms
|
|
r_ref[r_ref == ''] = '0' # correcting the emply values
|
|
resistors = r_ref.astype(np.float32).tolist() # convert string to numbers
|
|
input_voltage = float(frame.input_voltage.GetValue())
|
|
# bit_rate = float(frame.adjusted_volt.GetValue())
|
|
port = frame.dev_list.GetValue()
|
|
# typical window size: 50
|
|
window_size = int(frame.m_textCtrl26.GetValue())
|
|
|
|
#################### END USER INPUTS ########################
|
|
|
|
# filename, disable customize name but should inform the user the current name of the data file on the front end
|
|
# alternatively, could be default input if no other input given. But if there is might have problem...
|
|
dat_folder = "RecordedData"
|
|
os.makedirs(dat_folder, exist_ok=True)
|
|
filename = os.path.join(os.getcwd(), dat_folder, f"{datetime.now().strftime('%Y-%m-%d_%H%M%S')}.csv")
|
|
delay = 1000 # millisec per data point, defined in the firmware
|
|
# for now we have 5 reference resistors, there is an extra one (we set 4 on the UI) just in case if needed in the future
|
|
if not (len(resistors) == 5):
|
|
raise ValueError(f"expecting 5 resistor values, but got {len(resistors)}!!!")
|
|
|
|
gen_settings(resistors, input_voltage, port, filename, window_size, delay)
|
|
|
|
|
|
def gen_settings(resistors, input_voltage, port, filename, window_size, delay):
|
|
"""
|
|
export all inputs from main() to a .json file
|
|
:param resistors: list of reference resistances of the sensors
|
|
:param input_voltage: Vin of the voltage divider
|
|
:param bits: ADC resolution for the board. Usualy 12-bits for ESP32 (and 10 bits for Arduino Mega)
|
|
:param port: serial port the board is connected to on the computer
|
|
:param filename: file name and absolute directory which the serial data will be recorded to
|
|
:param window_size: numbers of x values to display on the graph, or the x interval
|
|
:param delay: amount of time to wait for a task's next start. 1000 ms for now to be consistent with the firmware
|
|
"""
|
|
name = "settings.json"
|
|
settings = {}
|
|
settings["refRes"] = resistors
|
|
settings["sensor_ports"] = np.where(np.array(resistors) > 0)[0].tolist()
|
|
settings["v_in"] = input_voltage
|
|
settings["port"] = port
|
|
# settings["resolution"] = bits
|
|
settings["winSize"] = window_size
|
|
settings["file_name"] = filename
|
|
settings["delay"] = delay
|
|
settings["font_size"] = frame.fontSize.GetValue()
|
|
open(name, 'w').write(json.dumps(settings, indent=4))
|
|
open(filename, "a", newline="", encoding="utf-8")
|
|
|
|
|
|
def run(e):
|
|
"""
|
|
run the read_arduino.py and Serial Plotter in parallel
|
|
"""
|
|
global ani, t1 # the variables to call the plotter and the read_arduino.py, we want them to get tossed around between functions and even programs
|
|
main()
|
|
if 't1' in globals():
|
|
t1.terminate() # end the previous serial reads, if there is any
|
|
|
|
# place the read() function from read_arduino into another process to run it in background
|
|
t1 = Process(target=read, args=())
|
|
t1.start()
|
|
# run the plotter. Note that we should not put the plotter class, or function, in another process since
|
|
# matplot's FuncAnimation doesn't like that
|
|
plotter = SerialPlotter(frame)
|
|
ani = plotter.plotting()
|
|
plotter.fig.show()
|
|
|
|
frame.btLaunch.SetLabelText("Plot") # change the text on the "launch" button to "plot"
|
|
if not frame.show_msg.GetValue():
|
|
frame.Hide()
|
|
|
|
|
|
if __name__ == '__main__':
|
|
console_title = 'Program Crashed! Here are the details' # this is there for now to redirect any errors
|
|
|
|
# Acknowledgement: https://stackoverflow.com/a/27694505
|
|
if sys.platform.startswith('win'):
|
|
# On Windows calling this function is necessary.
|
|
freeze_support()
|
|
app = wx.App(useBestVisual=True)
|
|
frame = Frame(None)
|
|
app.SetTopWindow(frame)
|
|
# set where the uncaught errors should be displayed
|
|
console = wx.PyOnDemandOutputWindow(console_title)
|
|
console.SetParent(frame)
|
|
sys.stderr = console
|
|
sys.stdout.write("this is an alpha version of the design. This debug terminal will be gone on official release\n")
|
|
ports = [comport.device for comport in serial.tools.list_ports.comports()] # get all available ports
|
|
frame.dev_list.AppendItems(ports)
|
|
frame.SetTitle("SeeDatResistance - Beta 0.1.1")
|
|
frame.btLaunch.Bind(wx.EVT_BUTTON, run)
|
|
if os.path.isfile("settings.json"):
|
|
try:
|
|
sys.stdout.write("Found existing settings.json, auto-fill previous inputs!\n")
|
|
settings = json.load(open('settings.json', 'r'))
|
|
frame.r_ref_1.SetValue(str(settings["refRes"][0]))
|
|
frame.r_ref_2.SetValue(str(settings["refRes"][1]))
|
|
frame.r_ref_3.SetValue(str(settings["refRes"][2]))
|
|
frame.r_ref_4.SetValue(str(settings["refRes"][3]))
|
|
frame.input_voltage.SetValue(str(settings["v_in"]))
|
|
# frame.adjusted_volt.SetValue(str(settings["resolution"]))
|
|
frame.m_textCtrl26.SetValue(str(settings["winSize"]))
|
|
if settings["port"] in ports: # auto-select device port if exist
|
|
frame.dev_list.SetValue(settings["port"])
|
|
except json.decoder.JSONDecodeError: # invalid settings file, ignore
|
|
pass
|
|
frame.Show()
|
|
app.MainLoop()
|
|
if 't1' in globals():
|
|
t1.terminate() # gracefully end the read_arduino process if it has been started
|