arduino-2020-06-18-1051.py
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---->