def restartrs3(self, params): try: self.spec_controller.restart() utils.send(self.client, "rs3restarted", []) except: traceback.print_exc() utils.send(self.client, "rs3restartfailed", [])
def white_reference(self, params): if self.spec_controller.save_dir == "": utils.send(self.client, "noconfig", []) print("noconfig") return if self.spec_controller.numspectra is None: utils.send(self.client, "nonumspectra", []) print("nonumspectectra") return if self.computer == "old": filename = (self.spec_controller.save_dir + "\\" + self.spec_controller.basename + "." + self.spec_controller.nextnum) elif self.computer == "new" or self.computer == "desktop": filename = (self.spec_controller.save_dir + "\\" + self.spec_controller.basename + self.spec_controller.nextnum + ".asd") if os.path.isfile(filename): print("Warning: File exists. Overwriting.") try: self.spec_controller.white_reference() except: print("Exception during white reference") utils.send(self.client, "wrfailed", []) if self.spec_controller.wr_success == True: utils.send(self.client, "wrsuccess", []) else: utils.send(self.client, "wrfailed", []) self.spec_controller.wr_success = False self.spec_controller.wr_failure = False
def instrumentconfig(self, params): instrument_config_num = params[0] try: self.spec_controller.instrument_config(instrument_config_num) utils.send(self.client, "iconfigsuccess", []) except: utils.send(self.client, "iconfigfailure", [])
def transferdata(self, params): source = params[0] if "spec_temp_data_loc" in source: source = source.replace("spec_temp_data_loc", self.temp_data_loc) print(source) try: with open(source, "r") as file: data = file.readlines() batch_size = 100 utils.send(self.client, f"datatransferstarted{len(data)/batch_size}", []) batch = 0 next_message = "" for i, line in enumerate(data): next_message += line if i != 0 and i % batch_size == 0: utils.send(self.client, f"batch{batch}+", [next_message]) batch += 1 next_message = "" utils.send(self.client, f"batch{batch}+", [next_message]) batch += 1 utils.send(self.client, f"datatransfercomplete{batch}", []) except OSError: utils.send(self.client, "datafailure", [])
def rmfile(self, params): try: delme = params[0] + "\\" + params[1] + params[2] + ".asd" os.remove(delme) utils.send(self.client, "rmsuccess", []) except: utils.send(self.client, "rmfailure", [])
def restart(self, params, run_time): if run_time < 20: time.sleep(20) utils.send(self.client, "restarting", []) if run_time > 20: time.sleep(10) os.system("shutdown /r /t 1") else: print("Just restarted. Doing nothing.")
def check_writeable(self, params): try: try: os.mkdir(params[0] + "\\autospec_temp") except OSError: pass # This could happen if an autospec temp file was left hanging # (created but not deleted) earlier. os.rmdir(params[0] + "\\autospec_temp") utils.send(self.client, "yeswriteable", []) except (NotADirectoryError, PermissionError, OSError) as e: utils.send(self.client, "notwriteable", [])
def routine_file_check(self, path=None): if path is None: path = self.spec_controller.save_dir file = self.check_for_unexpected( path, self.spec_controller.hopefully_saved_files, self.data_files_to_ignore) unexpected_files = [] while file is not None: self.data_files_to_ignore.append(file) unexpected_files.append(file) file = self.check_for_unexpected( path, self.spec_controller.hopefully_saved_files, self.data_files_to_ignore) if len(unexpected_files) > 0: utils.send(self.client, "unexpectedfile", unexpected_files)
def saveconfig(self, params): save_path = params[0] print("Checking for unexpected files") self.routine_file_check(save_path) print("Done.") utils.send(self.client, "donelookingforunexpected", []) basename = params[1] startnum = params[2] filename = "" if self.computer == "old": filename = save_path + "\\" + basename + "." + startnum elif self.computer == "new" or self.computer == "desktop": filename = save_path + "\\" + basename + startnum + ".asd" if os.path.isfile(filename): utils.send(self.client, "saveconfigfailedfileexists", []) self.skip_spectrum() return try: self.spec_controller.spectrum_save(save_path, basename, startnum) if self.spec_controller.failed_to_open: self.spec_controller.failed_to_open = False utils.send(self.client, "saveconfigerror", []) self.skip_spectrum() else: self.logger.logfile = self.find_logfile(save_path) if self.logger.logfile is None: self.logger.logfile = self.make_logfile(save_path) self.data_files_to_ignore.append( self.logger.logfile.split("\\")[-1]) print("saveconfigsuccess") utils.send(self.client, "saveconfigsuccess", []) except Exception as e: self.spec_controller.failed_to_open = False utils.send(self.client, "saveconfigerror", []) self.skip_spectrum() instrument_config_num = None traceback.print_exc()
def opt(self, params): # This makes sure that there was always a save configuration set before optimizing. Data files # don't get saved during optimization, but this needs to happen anyway because we need to know # where to put the log file when we record that we optimized. if self.spec_controller.save_dir == "": print("Sending noconfig") utils.send(self.client, "noconfig", []) return # And, we do need to know how many spectra we are averaging so we know when to time out if self.spec_controller.numspectra is None: utils.send(self.client, "nonumspectra", []) return try: self.spec_controller.optimize() if self.spec_controller.opt_complete == True: self.logger.log_opt() utils.send(self.client, "optsuccess", []) else: utils.send(self.client, "optfailure", []) except: print("Exception occurred and optimization failed.") utils.send(self.client, "optfailure", [])
def listdir(self, params): dir = params[0] if not os.path.isdir(dir): utils.send(self.client, "listdirfailed", []) else: try: if dir[-1] != "\\": dir += "\\" cmdfilename = utils.cmd_to_filename("listdir", [params[0]]) files = os.listdir(dir) message = cmdfilename for file in files: if os.path.isdir(dir + file) and file[0] != ".": message += "&" + file utils.send(self.client, message, []) except (PermissionError): utils.send(self.client, "listdirfailedpermission", []) except: utils.send(self.client, "listdirfailed", [])
def mkdir(self, params): try: print(params[0]) os.makedirs(params[0]) if self.spec_controller.save_dir is not None and self.spec_controller.save_dir != "": print("setting spec save directory to new directory") if "\\".join(params[0].split("\\") [:-1]) == self.spec_controller.save_dir: expected = params[0].split( self.spec_controller.save_dir)[1].split("\\")[1] self.spec_controller.hopefully_saved_files.append(expected) utils.send(self.client, "mkdirsuccess", []) except (FileExistsError): utils.send(self.client, "mkdirfailedfileexists", []) except (PermissionError): utils.send(self.client, "mkdirfailedpermission", []) except: utils.send(self.client, "mkdirfailed", [])
def rmdir(self, params): try: shutil.rmtree(params[0]) if self.spec_controller.save_dir is not None and self.spec_controller.save_dir != "": if params[0] in self.spec_controller.save_dir: self.spec_controller.save_dir = None utils.send(self.client, "rmdirsuccess", []) except (PermissionError): utils.send(self.client, "rmdirfailedpermission", []) except: utils.send(self.client, "rmdirfailed", [])
def listcontents(self, params): try: dir = params[0] if dir[-1] != "\\": dir += "\\" cmdfilename = utils.cmd_to_filename("listcontents", [params[0]]) files = os.listdir(dir) sorted_files = [] for i, file in enumerate(files): if os.path.isdir(dir + file) and file[0] != ".": sorted_files.append(file) elif file[0] != ".": # This is a way for the control compy to differentiate files from directories sorted_files.append("~:" + file) sorted_files.sort() utils.send(self.client, cmdfilename, sorted_files) except (PermissionError): utils.send(self.client, "listdirfailedpermission", []) except: traceback.print_exc() utils.send(self.client, "listdirfailed", [])
def process(self, params): input_path = params[0] output_path = params[1] csv_name = params[2] print("**********") print(input_path) print(output_path) print(csv_name) logfile_for_reading = None # We'll find it in the data folder. if input_path == "spec_temp_data_loc": input_path = self.temp_data_loc if output_path == "spec_temp_data_loc": for file in os.listdir(self.temp_data_loc): os.remove(os.path.join(self.temp_data_loc, file)) output_path = self.temp_data_loc # check if the input directory exists. if not, send an error back if not os.path.exists(input_path): utils.send(self.client, "processerrornodirectory", []) return # Look through files in data directory until you find a log file for potential_log in os.listdir(input_path): if ".txt" in potential_log: try: with open(input_path + "\\" + potential_log, "r") as f: firstline = f.readline() if "#AutoSpec log" in firstline or "# Tanager log" in firstline: logfile_for_reading = input_path + "\\" + potential_log break except OSError as e: traceback.print_exc() if logfile_for_reading is None: print("ERROR: No logfile found in data directory") if os.path.isfile(output_path + "\\" + csv_name) and csv_name != "proc_temp.csv": utils.send(self.client, "processerrorfileexists", []) return elif os.path.isfile(output_path + "\\" + csv_name): writeable = os.access(output_path, os.W_OK) if not writeable: utils.send(self.client, "processerrorcannotwrite", []) return os.remove(output_path + "\\" + csv_name) writeable = os.access(output_path, os.W_OK) if not writeable: utils.send(self.client, "processerrorcannotwrite", []) return else: # If the specified output path is in the C drive, we can write straight to it. Otherwise, # we're going to temporarily store the file in the temp data location if output_path[0:3] != "C:\\": temp_output_path = self.temp_data_loc else: temp_output_path = output_path datafile = temp_output_path + "\\" + csv_name #Don't give warnings about all the temp files that get dropped into the save directroy print("*************************************************") print(input_path) print(self.spec_controller.save_dir) if input_path == self.spec_controller.save_dir: self.data_files_to_ignore.append(csv_name) batches = int( len(self.data_files_to_ignore) / self.process_controller.batch_size) + 1 base = csv_name.split(".csv")[0] for i in range(batches): ignore_file = f"{base}_{i}.csv" print(ignore_file) self.data_files_to_ignore.append(ignore_file) try: self.process_controller.process(input_path, temp_output_path, csv_name, self.watchdog_monitor) except Exception as e: self.process_controller.reset() utils.send(self.client, "processerror", []) traceback.print_exc() return # Check that the expected file arrived fine after processing. # This sometimes wasn't happening if you fed ViewSpecPro data without # taking a white referencetra or optimizing. saved = False t0 = time.perf_counter() t = time.perf_counter() while t - t0 < 200 and not saved: saved = os.path.isfile(datafile) time.sleep(0.2) t = time.perf_counter() corrected = False if not saved: print("Datafile not saved.") print(datafile) if saved: # Load headers from the logfile, then apply correction if logfile_for_reading is not None: print("Loading headers from log file") warnings = self.set_headers(datafile, logfile_for_reading) print( "Applying correction for non-Lambertian behavior of Spectralon" ) try: self.corrector.correct( datafile ) # applies a correction based on measured BRDF for spectralon corrected = True except Exception as e: raise e traceback.print_exc() print("Warning! correction not applied") else: print("Warning! No log file found!") self.tsv_to_csv(datafile) # still replace tabs with commas warnings = "no log found" print("done") final_datafile = ( output_path + "\\" + csv_name ) # May or may not be the same loc as temporary. data_base = ".".join(csv_name.split( ".")[0:-1]) # E.g. for a csv name of foo.csv, returns foo final_logfile = ( output_path + "\\" + data_base + "_log" ) # We're going to copy the logfile along with it, # givnig it a sensible name e.g. foo_log.txt # But first we have to make sure there isn't an existing file with that name. i = 1 logfile_base = final_logfile while os.path.isfile(final_logfile + ".txt"): final_logfile = logfile_base + "_" + str(i) i += 1 final_logfile += ".txt" # Ok, now copy! if logfile_for_reading is not None: os.system("copy " + logfile_for_reading + " " + final_logfile) if output_path == self.spec_controller.save_dir: self.data_files_to_ignore.append( final_logfile.split("\\")[-1]) # If we need to move the data to get it to its final destination, do it! if temp_output_path != output_path: tempfilename = datafile os.system("move " + tempfilename + " " + final_datafile) # Read data to send to control computer spec_data = "" with open(final_datafile, "r") as f: spec_data = f.read() log_data = "" with open(final_logfile, "r") as f: log_data = f.read() # If the output directory is the same (or within) the data directory, # there's no need to alert the user to an unexpected file being introduced # since clearly it was expected. if self.spec_controller.save_dir is not None and self.spec_controller.save_dir != "": if self.spec_controller.save_dir in final_datafile: expected = final_datafile.split( self.spec_controller.save_dir)[1].split("\\")[1] self.spec_controller.hopefully_saved_files.append( expected) if corrected == True and logfile_for_reading is not None: utils.send(self.client, "processsuccess", []) elif logfile_for_reading is not None: utils.send(self.client, "processsuccessnocorrection", []) else: utils.send(self.client, "processsuccessnolog", []) # We don't actually know for sure that processing failed because of failing # to optimize or white reference, but ViewSpecPro sometimes silently fails if # you haven't been doing those things. else: utils.send(self.client, "processerrorwropt", [])
def take_spectrum(self, params): if (self.spec_controller.save_dir == ""): # If there's no save configuration set on this computer, tell the control computer you need # one. This comes up if the script restarts on the spec compy but there is no restart on # the control compy. utils.send(self.client, "noconfig", []) return if ( self.spec_controller.numspectra is None ): # Same as above, but for instrument configuration (number of spectra to average) utils.send(self.client, "nonumspectra", []) return # We're going to need to know what filename to expect to be saved so that we can 1) check if the # file exists and warn the user beforehand and 2) confirm whether the spectrum was actually taken. # This filename will be based on a basename and number, both passed from control compy filename = "" if self.computer == "old": # There are different file formats for old and new RS3 versions. filename = params[0] + "\\" + params[1] + "." + params[2] elif self.computer == "new" or self.computer == "desktop": filename = params[0] + "\\" + params[1] + params[2] + ".asd" label = params[3] i = params[4] e = params[5] az = params[6] # Check if the file already exists. If it does, let the user know. They will have the option # to remove and retry. if os.path.isfile(filename): utils.send(self.client, "savespecfailedfileexists", []) return # After saving a spectrum, the spec_controller updates its list of expected files to include # one more. Wait for this number to change before moving on. # old=len(spec_controller.hopefully_saved_files) try: self.spec_controller.take_spectrum(filename) except: traceback.print_exc() utils.send(self.client, "specfailed", []) return # Now wait for the data file to turn up where it belongs. saved = False timeout = int(self.spec_controller.numspectra) while ( timeout > 0 and saved is False ): # Depending on the number of spectra we are averaging, this might take a while. saved = os.path.isfile(filename) time.sleep(0.2) timeout -= 0.2 if saved: self.logger.log_spectrum(self.spec_controller.numspectra, i, e, az, filename, label) utils.send(self.client, "savedfile", [filename]) print("Done") else: self.spec_controller.hopefully_saved_files.pop(-1) self.spec_controller.nextnum = str( int(self.spec_controller.nextnum) - 1) utils.send(self.client, "failedtosavefile", [filename])
def listen(self): print_connection_announcement = None run_time = 0 while True: run_time += 0.25 with open(os.path.join(self.temp_data_loc, "watchdog"), "w+") as f: pass # This file is looked for by the watchdog. # check connectivity with spectrometer connected = self.spec_controller.check_connectivity() if not connected: try: if ( print_connection_announcement is None or print_connection_announcement == False ): # If this is the first time we've realized we aren't connected. It will be None the first time through the loop and True or False afterward. print( "Waiting for RS³ to connect to the spectrometer..." ) print_connection_announcement = ( True # Use this to know to print an announcement if the spectrometer reconnects next time. ) if self.client.server_address is not None: utils.send(self.client, "lostconnection", []) except: pass time.sleep(1) if ( connected and print_connection_announcement == True ): # If we weren't connected before, let everyone know we are now! print_connection_announcement = False print("RS³ connected to the spectrometer. Listening!") # check for unexpected files in data directory self.command_interpreter.routine_file_check() # check for new commands in the tcp server queue while len(self.local_server.queue) > 0: if self.local_server.remote_server_address != self.client.server_address: print("Setting control computer address:") self.client.server_address = self.local_server.remote_server_address print(self.client.server_address) message = self.local_server.queue.pop(0) if message == "test": continue print(f"Message received: {message}") cmd, params = utils.filename_to_cmd(message) if cmd == "restartcomputer": self.command_interpreter.restart(params, run_time) elif cmd == "restartrs3": self.command_interpreter.restartrs3(params) elif "checkwriteable" in cmd: # Check whether you can write to a given directory self.command_interpreter.check_writeable(params) elif "spectrum" in cmd: # Take a spectrum self.command_interpreter.take_spectrum(params) elif cmd == "saveconfig": self.command_interpreter.saveconfig(params) elif cmd == "wr": self.command_interpreter.white_reference(params) elif cmd == "opt": self.command_interpreter.opt(params) elif "process" in cmd: self.command_interpreter.process(params) elif "instrumentconfig" in cmd: self.command_interpreter.instrumentconfig(params) elif "rmfile" in cmd: self.command_interpreter.rmfile(params) # Used for copying remote data over to the control compy for plotting, etc elif "transferdata" in cmd: self.command_interpreter.transferdata(params) # List directories within a folder for the remote file explorer on the control compy elif "listdir" in cmd: self.command_interpreter.listdir(params) # List directories and files in a folder for the remote file explorer on the control compy elif "listcontents" in cmd: self.command_interpreter.listcontents(params) # make a directory elif cmd == "mkdir": self.command_interpreter.mkdir(params) # Not implemented yet! elif "rmdir" in cmd: self.command_interpreter.rmdir(params) time.sleep(0.25)