01234567890123456789012345678901234567890123456789012345678901234567890123456789
567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859 286287288289290291292293294295296297298299300301302303304305 306307308309310311 312313314315316317318 319320 321322323324325326327328329330 331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365 366367368369370371372373374375376377378379380381382383384385386387 636637638639640641642643644645646647648649650651652653654655 656657658659660661662663664665666667668669670671672673674675 689690691692693694695696697698699700701702703704705706707708 709710711712713714715716717718719720721722723724725726727728 12981299130013011302130313041305130613071308130913101311131213131314131513161317 13181319132013211322132313241325132613271328132913301331133213331334133513361337 | <----SKIPPED LINES----> import random import struct import subprocess import sys import termios import time import psutil import serial import serial.tools.list_ports from pySerialTransfer import pySerialTransfer from constants import ( RASPBERRY_PI, MESSAGEBOARD_PATH, WEBSERVER_PATH, SHUTDOWN_TEXT) import messageboard ARDUINO_LOG = 'arduino_log.txt' ARDUINO_ROLLING_LOG = 'arduino_rolling_log.txt' SERIALS_LOG = 'arduino_serials_log.txt' VERBOSE = False # log additional fine-grained details into ARDUINO_LOG LOG_SERIALS = False # log serial data sent from Arduino to ARDUINO_LOG SIMULATE_ARDUINO = False REMOTE_DISPLAY_MODE = 'display_mode.txt' SERVO_SIMULATED_IN = 'servo_in.txt' SERVO_SIMULATED_OUT = 'servo_out.txt' REMOTE_SIMULATED_IN = 'remote_in.txt' REMOTE_SIMULATED_OUT = 'remote_out.txt' if RASPBERRY_PI: ARDUINO_LOG = MESSAGEBOARD_PATH + ARDUINO_LOG SERIALS_LOG = MESSAGEBOARD_PATH + SERIALS_LOG SERVO_SIMULATED_OUT = MESSAGEBOARD_PATH + SERVO_SIMULATED_OUT SERVO_SIMULATED_IN = MESSAGEBOARD_PATH + SERVO_SIMULATED_IN REMOTE_SIMULATED_OUT = MESSAGEBOARD_PATH + REMOTE_SIMULATED_OUT REMOTE_SIMULATED_IN = MESSAGEBOARD_PATH + REMOTE_SIMULATED_IN REMOTE_DISPLAY_MODE = MESSAGEBOARD_PATH + REMOTE_DISPLAY_MODE ARDUINO_ROLLING_LOG = WEBSERVER_PATH + ARDUINO_ROLLING_LOG CONNECTION_FLAG_BLUETOOTH = 1 CONNECTION_FLAG_USB = 2 CONNECTION_FLAG_SIMULATED = 3 RASPBERRY_PI = psutil.sys.platform.title() == 'Linux' SN_SERVO = '5583834303435111C1A0' SERVO_CONNECTION = (CONNECTION_FLAG_BLUETOOTH, (2, '98:D3:11:FC:42:16', 1)) SN_REMOTE = '75835343130351802272' REMOTE_CONNECTION = (CONNECTION_FLAG_BLUETOOTH, (1, '98:D3:91:FD:B3:C9', 1)) LASER_OFF = (False, False, False) <----SKIPPED LINES----> Args: format_string: String of the form expected by struct.pack bytes_read: if passed, the bytes that are read are appended to the list. Returns: Tuple of values matching that as identified in format_string. """ if self.connection_type == CONNECTION_FLAG_SIMULATED: if ( self.__simulated_reads__ and # time for next time.time() - self.start_time > self.__simulated_reads__[0][0]): next_line = self.__simulated_reads__.pop(0) return next_line[1] return () if not format_string: format_string = self.read_format try: data = Read(self.link, format_string, bytes_read=bytes_read) except OSError as e: failure_message = 'Failed to read from %s: %s' % (self.name, e) if self.error_pin: self.to_parent_q.put(('pin', (self.error_pin, True, failure_message))) self.Reopen(log_message=failure_message) return self.Read(format_string=format_string) self.last_read = time.time() if data: self.last_receipt = time.time() if LOG_SERIALS: ts = time.time() - self.start_time str_data = str( ['%7.2f' % d if isinstance(d, float) else str(d) for d in data]) with open(SERIALS_LOG, 'a') as f: f.write('%10.3f RECD@%s: %s\n' % (ts, self.name, str_data)) if ( self.read_timeout and self.last_read - self.last_receipt > self.read_timeout): failure_message = ( 'Heartbeat not received in %.2f seconds (expected: %.2f) on %s' % ( self.last_read - self.last_receipt, self.read_timeout, self.name)) if self.error_pin: self.to_parent_q.put(('pin', (self.error_pin, True, failure_message))) self.Reopen(log_message=failure_message) return self.Read(format_string=format_string) return data def Write(self, values, format_string=None): """Writes to an open serial. Writes to an open serial values as identified in the format_string provided here, or if not provided in this call, as saved on the Serial instance. If an OSError exception is detected, this method will attempt to reopen the connection. Args: values: tuple of values to send matching that as identified in format_string. format_string: String of the form expected by struct.pack """ ts = time.time() - self.start_time str_values = str( ['%7.2f' % v if isinstance(v, float) else str(v) for v in values]) if self.connection_type == CONNECTION_FLAG_SIMULATED: with open(self.connection_tuple[1], 'a') as f: f.write('%10.3f: %s\n' % (ts, str_values)) return if not format_string: format_string = self.write_format try: Write(self.link, values, format_string) except OSError as e: failure_message = 'Failed to write: %s' % e if self.error_pin: self.to_parent_q.put(('pin', (self.error_pin, True, failure_message))) self.Reopen(log_message=failure_message) self.Write(values) if LOG_SERIALS: with open(SERIALS_LOG, 'a') as f: f.write('%10.3f SENT@%s: %s\n' % (ts, self.name, str_values)) def HasReset(self): """Indicates exactly once whether serial has reset since last called.""" if self.connection_type == CONNECTION_FLAG_SIMULATED: raise NotImplementedError('Not implemented for simulations') flag = self.reset_flag self.reset_flag = False return flag def RunCommand(cmd, sleep_seconds=1, log=True): """Runs shell command, checking if it completed within timeout.""" conn = subprocess.Popen(cmd, shell=True) time.sleep(sleep_seconds) conn.poll() if conn.returncode is None: Log('ERROR: %s did not complete within %d seconds' % (cmd, sleep_seconds)) <----SKIPPED LINES----> azimuth = angles['azimuth_degrees'] altitude = angles['altitude_degrees'] return (azimuth, altitude) def DrainQueue(q): """Empties a queue, returning the last-retrieved value.""" value = None while not q.empty(): value = q.get(block=False) return value def InitialMessageValues(q): """Initializes the arduino main processes with values from messageboard.""" v = DrainQueue(q) if v: return v return {}, {}, {}, {} def ServoTestOrdinal(link): """Point laser at each of 0, 90, 180, 270 and hold with different colors.""" link.Write((0, 0, *LASER_ALL)) time.sleep(1) link.Write((90, 0, *LASER_RED)) time.sleep(1) link.Write((180, 0, *LASER_GREEN)) time.sleep(1) link.Write((270, 0, *LASER_BLUE)) time.sleep(1) def ServoTestSweep(link, altitude=45): """Sweep red laser around 360 degrees.""" for azimuth in range(0, 360, 10): link.Write((azimuth, altitude, *LASER_RED)) time.sleep(WRITE_DELAY_TIME) def ServoMain(to_arduino_q, to_parent_q, shutdown): <----SKIPPED LINES----> to_parent_q.cancel_join_thread() # write_format: azimuth, altitude, R, G, & B intensity # read heartbeat: millis link = Serial( *SERVO_CONNECTION, read_timeout=60, error_pin=messageboard.GPIO_ERROR_ARDUINO_SERVO_CONNECTION, to_parent_q=to_parent_q, read_format='l', write_format='ff???', name='Servo') link.Open() last_flight = {} last_angles = (0, 0) flight, json_desc_dict, configuration, additional_attr = InitialMessageValues( to_arduino_q) next_read = 0 next_write = 0 now = GetNow(json_desc_dict, additional_attr) while not shutdown.value: if not to_arduino_q.empty(): flight, json_desc_dict, configuration, additional_attr = to_arduino_q.get( block=False) if 'test_servos_ordinal' in configuration: messageboard.RemoveSetting(configuration, 'test_servos_ordinal') ServoTestOrdinal(link) elif 'test_servos_sweep' in configuration: messageboard.RemoveSetting(configuration, 'test_servos_sweep') ServoTestSweep(link) new_flight = DifferentFlights(flight, last_flight) if new_flight: Log('Flight changed from %s to %s' % ( messageboard.DisplayFlightNumber(last_flight), messageboard.DisplayFlightNumber(flight) ), ser=link) # Turn off laser so line isn't traced while it moves to new position link.Write((*last_angles, *LASER_OFF)) <----SKIPPED LINES----> *REMOTE_CONNECTION, read_timeout=60, error_pin=messageboard.GPIO_ERROR_ARDUINO_REMOTE_CONNECTION, to_parent_q=to_parent_q, read_format=read_format_string, write_format=write_format_string, name='Remote') link.Open() # Read in the saved display mode, if it exists display_mode = messageboard.ReadFile(REMOTE_DISPLAY_MODE, log_exception=False) if not display_mode: display_mode = DISP_LAST_FLIGHT_NUMB_ORIG_DEST else: display_mode = int(display_mode) flight, json_desc_dict, configuration, additional_attr = InitialMessageValues( to_arduino_q) next_read = 0 next_write = 0 while not shutdown.value: if not to_arduino_q.empty(): to_arduino_message = to_arduino_q.get(block=False) (flight, json_desc_dict, configuration, additional_attr) = to_arduino_message if 'test_remote' in configuration: messageboard.RemoveSetting(configuration, 'test_remote') def TestDisplayMode(m): SendRemoteMessage( flight, json_desc_dict, configuration, additional_attr, m, write_keys, write_format_tuple, link) time.sleep(1) TestDisplayMode(DISP_LAST_FLIGHT_NUMB_ORIG_DEST) TestDisplayMode(DISP_LAST_FLIGHT_AZIMUTH_ELEVATION) TestDisplayMode(DISP_FLIGHT_COUNT_LAST_SEEN) TestDisplayMode(DISP_RADIO_RANGE) if time.time() >= next_write: <----SKIPPED LINES----> |
01234567890123456789012345678901234567890123456789012345678901234567890123456789
567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859 286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405 654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702 716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756 13261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366 | <----SKIPPED LINES----> import random import struct import subprocess import sys import termios import time import psutil import serial import serial.tools.list_ports from pySerialTransfer import pySerialTransfer from constants import ( RASPBERRY_PI, MESSAGEBOARD_PATH, WEBSERVER_PATH, SHUTDOWN_TEXT) import messageboard ARDUINO_LOG = 'arduino_log.txt' ARDUINO_ROLLING_LOG = 'arduino_rolling_log.txt' #SERIALS_LOG = 'arduino_serials_log.txt' VERBOSE = False # log additional fine-grained details into ARDUINO_LOG LOG_SERIALS = False # log serial data sent from Arduino to ARDUINO_LOG SIMULATE_ARDUINO = False REMOTE_DISPLAY_MODE = 'display_mode.txt' SERVO_SIMULATED_IN = 'servo_in.txt' SERVO_SIMULATED_OUT = 'servo_out.txt' REMOTE_SIMULATED_IN = 'remote_in.txt' REMOTE_SIMULATED_OUT = 'remote_out.txt' if RASPBERRY_PI: ARDUINO_LOG = MESSAGEBOARD_PATH + ARDUINO_LOG #SERIALS_LOG = MESSAGEBOARD_PATH + SERIALS_LOG SERVO_SIMULATED_OUT = MESSAGEBOARD_PATH + SERVO_SIMULATED_OUT SERVO_SIMULATED_IN = MESSAGEBOARD_PATH + SERVO_SIMULATED_IN REMOTE_SIMULATED_OUT = MESSAGEBOARD_PATH + REMOTE_SIMULATED_OUT REMOTE_SIMULATED_IN = MESSAGEBOARD_PATH + REMOTE_SIMULATED_IN REMOTE_DISPLAY_MODE = MESSAGEBOARD_PATH + REMOTE_DISPLAY_MODE ARDUINO_ROLLING_LOG = WEBSERVER_PATH + ARDUINO_ROLLING_LOG CONNECTION_FLAG_BLUETOOTH = 1 CONNECTION_FLAG_USB = 2 CONNECTION_FLAG_SIMULATED = 3 RASPBERRY_PI = psutil.sys.platform.title() == 'Linux' SN_SERVO = '5583834303435111C1A0' SERVO_CONNECTION = (CONNECTION_FLAG_BLUETOOTH, (2, '98:D3:11:FC:42:16', 1)) SN_REMOTE = '75835343130351802272' REMOTE_CONNECTION = (CONNECTION_FLAG_BLUETOOTH, (1, '98:D3:91:FD:B3:C9', 1)) LASER_OFF = (False, False, False) <----SKIPPED LINES----> Args: format_string: String of the form expected by struct.pack bytes_read: if passed, the bytes that are read are appended to the list. Returns: Tuple of values matching that as identified in format_string. """ if self.connection_type == CONNECTION_FLAG_SIMULATED: if ( self.__simulated_reads__ and # time for next time.time() - self.start_time > self.__simulated_reads__[0][0]): next_line = self.__simulated_reads__.pop(0) return next_line[1] return () if not format_string: format_string = self.read_format try: data = Read(self.link, format_string, bytes_read=bytes_read) # on OSError, record a disconnection and attempt to reconnect & re-read except OSError as e: failure_message = 'Failed to read from %s: %s' % (self.name, e) if self.error_pin: self.to_parent_q.put(('pin', (self.error_pin, True, failure_message))) self.Reopen(log_message=failure_message) return self.Read(format_string=format_string) self.last_read = time.time() if data: self.last_receipt = time.time() if LOG_SERIALS: ts = time.time() - self.start_time str_data = str( ['%7.2f' % d if isinstance(d, float) else str(d) for d in data]) message = '%10.3f RECD@%s: %s\n' % (ts, self.name, str_data) Log(message) #with open(SERIALS_LOG, 'a') as f: # f.write(message) # If we haven't received data (despite reading) in more than the timeout, # close and reopen. if ( self.read_timeout and self.last_read - self.last_receipt > self.read_timeout): failure_message = ( 'Heartbeat not received in %.2f seconds (expected: %.2f) on %s' % ( self.last_read - self.last_receipt, self.read_timeout, self.name)) if self.error_pin: self.to_parent_q.put(('pin', (self.error_pin, True, failure_message))) self.Reopen(log_message=failure_message) return self.Read(format_string=format_string) if self.read_timeout and VERBOSE: Log('%s: last_read: %.1f; last_receipt: %.1f; ' 'delta: %.1f; read_timeout: %.1f' % ( self.name, self.last_read, self.last_receipt, self.last_read - self.last_receipt, self.read_timeout)) elif VERBOSE: Log('%s: read_timeout: %s' % (self.name, self.read_timeout)) return data def Write(self, values, format_string=None): """Writes to an open serial. Writes to an open serial values as identified in the format_string provided here, or if not provided in this call, as saved on the Serial instance. If an OSError exception is detected, this method will attempt to reopen the connection. Args: values: tuple of values to send matching that as identified in format_string. format_string: String of the form expected by struct.pack """ ts = time.time() - self.start_time str_values = str( ['%7.2f' % v if isinstance(v, float) else str(v) for v in values]) if self.connection_type == CONNECTION_FLAG_SIMULATED: with open(self.connection_tuple[1], 'a') as f: f.write('%10.3f: %s\n' % (ts, str_values)) return if not format_string: format_string = self.write_format try: Write(self.link, values, format_string) except OSError as e: failure_message = 'Failed to write: %s' % e if self.error_pin: self.to_parent_q.put(('pin', (self.error_pin, True, failure_message))) self.Reopen(log_message=failure_message) self.Write(values) if LOG_SERIALS: message = '%10.3f SENT@%s: %s\n' % (ts, self.name, str_values) Log(message) #with open(SERIALS_LOG, 'a') as f: # f.write(message) def HasReset(self): """Indicates exactly once whether serial has reset since last called.""" if self.connection_type == CONNECTION_FLAG_SIMULATED: raise NotImplementedError('Not implemented for simulations') flag = self.reset_flag self.reset_flag = False return flag def RunCommand(cmd, sleep_seconds=1, log=True): """Runs shell command, checking if it completed within timeout.""" conn = subprocess.Popen(cmd, shell=True) time.sleep(sleep_seconds) conn.poll() if conn.returncode is None: Log('ERROR: %s did not complete within %d seconds' % (cmd, sleep_seconds)) <----SKIPPED LINES----> azimuth = angles['azimuth_degrees'] altitude = angles['altitude_degrees'] return (azimuth, altitude) def DrainQueue(q): """Empties a queue, returning the last-retrieved value.""" value = None while not q.empty(): value = q.get(block=False) return value def InitialMessageValues(q): """Initializes the arduino main processes with values from messageboard.""" v = DrainQueue(q) if v: return v return {}, {}, {}, {} def SetLoggingGlobals(configuration): """Sets the logging globals based on values in the config file.""" global VERBOSE VERBOSE = 'arduino_verbose' in configuration global LOG_SERIALS LOG_SERIALS = 'arduino_log_serials' in configuration def ServoTestOrdinal(link): """Point laser at each of 0, 90, 180, 270 and hold with different colors.""" link.Write((0, 0, *LASER_ALL)) time.sleep(1) link.Write((90, 0, *LASER_RED)) time.sleep(1) link.Write((180, 0, *LASER_GREEN)) time.sleep(1) link.Write((270, 0, *LASER_BLUE)) time.sleep(1) def ServoTestSweep(link, altitude=45): """Sweep red laser around 360 degrees.""" for azimuth in range(0, 360, 10): link.Write((azimuth, altitude, *LASER_RED)) time.sleep(WRITE_DELAY_TIME) def ServoMain(to_arduino_q, to_parent_q, shutdown): <----SKIPPED LINES----> to_parent_q.cancel_join_thread() # write_format: azimuth, altitude, R, G, & B intensity # read heartbeat: millis link = Serial( *SERVO_CONNECTION, read_timeout=60, error_pin=messageboard.GPIO_ERROR_ARDUINO_SERVO_CONNECTION, to_parent_q=to_parent_q, read_format='l', write_format='ff???', name='Servo') link.Open() last_flight = {} last_angles = (0, 0) flight, json_desc_dict, configuration, additional_attr = InitialMessageValues( to_arduino_q) next_read = 0 next_write = 0 now = GetNow(json_desc_dict, additional_attr) while not shutdown.value: SetLoggingGlobals(configuration) if not to_arduino_q.empty(): flight, json_desc_dict, configuration, additional_attr = to_arduino_q.get( block=False) if 'test_servos_ordinal' in configuration: messageboard.RemoveSetting(configuration, 'test_servos_ordinal') ServoTestOrdinal(link) elif 'test_servos_sweep' in configuration: messageboard.RemoveSetting(configuration, 'test_servos_sweep') ServoTestSweep(link) new_flight = DifferentFlights(flight, last_flight) if new_flight: Log('Flight changed from %s to %s' % ( messageboard.DisplayFlightNumber(last_flight), messageboard.DisplayFlightNumber(flight) ), ser=link) # Turn off laser so line isn't traced while it moves to new position link.Write((*last_angles, *LASER_OFF)) <----SKIPPED LINES----> *REMOTE_CONNECTION, read_timeout=60, error_pin=messageboard.GPIO_ERROR_ARDUINO_REMOTE_CONNECTION, to_parent_q=to_parent_q, read_format=read_format_string, write_format=write_format_string, name='Remote') link.Open() # Read in the saved display mode, if it exists display_mode = messageboard.ReadFile(REMOTE_DISPLAY_MODE, log_exception=False) if not display_mode: display_mode = DISP_LAST_FLIGHT_NUMB_ORIG_DEST else: display_mode = int(display_mode) flight, json_desc_dict, configuration, additional_attr = InitialMessageValues( to_arduino_q) next_read = 0 next_write = 0 while not shutdown.value: SetLoggingGlobals(configuration) if not to_arduino_q.empty(): to_arduino_message = to_arduino_q.get(block=False) (flight, json_desc_dict, configuration, additional_attr) = to_arduino_message if 'test_remote' in configuration: messageboard.RemoveSetting(configuration, 'test_remote') def TestDisplayMode(m): SendRemoteMessage( flight, json_desc_dict, configuration, additional_attr, m, write_keys, write_format_tuple, link) time.sleep(1) TestDisplayMode(DISP_LAST_FLIGHT_NUMB_ORIG_DEST) TestDisplayMode(DISP_LAST_FLIGHT_AZIMUTH_ELEVATION) TestDisplayMode(DISP_FLIGHT_COUNT_LAST_SEEN) TestDisplayMode(DISP_RADIO_RANGE) if time.time() >= next_write: <----SKIPPED LINES----> |