From 754cefd36a4c4eadd928228e2adffb0392f9e53e Mon Sep 17 00:00:00 2001 From: Jim Ewald Date: Fri, 10 Feb 2017 09:30:23 -0800 Subject: [PATCH 1/2] Add stub code for macos support --- BlocklyLogger.py | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/BlocklyLogger.py b/BlocklyLogger.py index f336966..5bc3348 100644 --- a/BlocklyLogger.py +++ b/BlocklyLogger.py @@ -1,7 +1,9 @@ +import os import logging from sys import platform from subprocess import Popen, PIPE, check_output, CalledProcessError +# Define error constants # Logging path try: # Python 2.7+ @@ -39,6 +41,8 @@ def emit(self, record): def init(): logger.info("Logger has been started.") + + # Debian linux if platform == 'linux2': if is_module_loaded() != 0: return @@ -46,6 +50,14 @@ def init(): if check_system_messages() != 0: return + # MacOS + if platform == 'darwin': + if is_macos_ftdi_module_installed() != 0: + return 101 + + if is_macos_ftdi_module_loaded != 0: + return 102 + def is_module_loaded(): try: @@ -69,3 +81,39 @@ def check_system_messages(): except CalledProcessError: logger.warning('Serial port is not assigned.') return 1 + + +def check_macos_logpath(): + user_home = os.path.expanduser('~') + log_path = user_home + '/Library/Logs/BlocklyProp' + + # Does the log directory exist + try: + os.stat(log_path) + return 0 + + except OSError: + # Create a new log path + try: + os.mkdirs(log_path) + + except OSError: + return 1 + + return 0 + + +def is_macos_ftdi_module_loaded(): + try: + process = Popen(['kextstat'], stdout=PIPE, stderr=PIPE) + output = check_output(('grep', 'FTDI'), stdin=process.stdout) + logger.debug('FTDI module load state') + logger.debug(output) + return 0 + except CalledProcessError: + logger.warning('No FTDI modules detected.') + return 1 + + +def is_macos_ftdi_module_installed(): + return 0 From 37701387d6a663c55343c15bd1ff5bb954ed1663 Mon Sep 17 00:00:00 2001 From: Jim Ewald Date: Fri, 10 Feb 2017 14:54:35 -0800 Subject: [PATCH 2/2] Create BlocklyHardware and moved FTDI detection code from BlocklyLogger to here. Add code to support logging under MacOS. Add UI widgets to display log file location. --- BlocklyHardware.py | 94 +++++++++++++++++++++++++++++ BlocklyLogger.py | 140 ++++++++++++++++--------------------------- BlocklyPropClient.py | 63 +++++++++++++++---- 3 files changed, 198 insertions(+), 99 deletions(-) create mode 100644 BlocklyHardware.py diff --git a/BlocklyHardware.py b/BlocklyHardware.py new file mode 100644 index 0000000..26be7e0 --- /dev/null +++ b/BlocklyHardware.py @@ -0,0 +1,94 @@ +import os +import logging +from sys import platform +from subprocess import Popen, PIPE, check_output, CalledProcessError + +# Define platform constants +PLATFORM_MACOS = 'darwin' +PLATFORM_UBUNTU = 'linux2' + +# Define error constants +FTDI_DRIVER_NOT_INSTALLED = 201 +FTDI_DRIVER_NOT_LOADED = 202 +PLATFORM_UNKNOWN = 2 + +# Enable logging +__module_logger = logging.getLogger('blockly') + + +def init(): + result = is_module_installed() + if result != 0: + return result + + result = is_module_loaded() + if result != 0: + return result + + +def is_module_installed(): + if platform == PLATFORM_MACOS: + return __is_module_installed_macos() + elif platform == PLATFORM_UBUNTU: + return __is_module_installed_ubuntu() + else: + return PLATFORM_UNKNOWN + + +def is_module_loaded(): + if platform == PLATFORM_MACOS: + return __is_module_loaded_macos() + elif platform == PLATFORM_UBUNTU: + return __is_module_loaded_ubuntu() + else: + return PLATFORM_UNKNOWN + + +# Ubuntu implementation +def __is_module_installed_ubuntu(): + try: + process = Popen(['cat', '/proc/modules'], stdout=PIPE, stderr=PIPE) + output = check_output(('grep', 'ftdi'), stdin=process.stdout) + __module_logger.debug('FTDI module load state') + __module_logger.debug(output) + return 0 + except CalledProcessError: + __module_logger.warning('No FTDI modules detected.') + return FTDI_DRIVER_NOT_INSTALLED + + +def __is_module_loaded_ubuntu(): + try: + process = Popen(['dmesg', '-H', '-x'], stdout=PIPE, stderr=PIPE) + output = check_output(('grep', 'ftdi'), stdin=process.stdout) + process.wait() + __module_logger.debug(output) + return 0 + except CalledProcessError: + __module_logger.warning('Serial port is not assigned.') + return FTDI_DRIVER_NOT_LOADED + + +# MacOS implementation +def __is_module_installed_macos(): + try: + # Does the log directory exist + os.stat('/Library/Extensions/FTDIUSBSerialDriver.kext') + __module_logger.info('FTDI driver is installed') + return 0 + + except OSError: + __module_logger.error('Cannot find FTDI installation') + return FTDI_DRIVER_NOT_INSTALLED + + +def __is_module_loaded_macos(): + try: + process = Popen(['kextstat'], stdout=PIPE, stderr=PIPE) + output = check_output(('grep', 'FTDI'), stdin=process.stdout) + __module_logger.debug('FTDI module load state') + __module_logger.debug(output) + return 0 + except CalledProcessError: + __module_logger.warning('No FTDI modules detected.') + return 1 \ No newline at end of file diff --git a/BlocklyLogger.py b/BlocklyLogger.py index 5bc3348..42694e4 100644 --- a/BlocklyLogger.py +++ b/BlocklyLogger.py @@ -1,119 +1,85 @@ +"""" +BlocklyPropLogger manages the application logging process. + + +""" + import os import logging from sys import platform -from subprocess import Popen, PIPE, check_output, CalledProcessError - -# Define error constants -# Logging path -try: # Python 2.7+ - from logging import NullHandler -except ImportError: - class NullHandler(logging.Handler): - def emit(self, record): - pass +__author__ = 'Jim Ewald' -logging.getLogger(__name__).addHandler(NullHandler()) +# Constants +PLATFORM_MACOS = 'darwin' -# Create a logger -logger = logging.getLogger('blockly') -logger.setLevel(logging.DEBUG) +path = None -# create a file handler to log events to the debug level. Log file -# is overwritten each time the app runs. -handler = logging.FileHandler('BlocklyPropClient.log', mode='w') -#handler = logging.FileHandler('BlocklyPropClient.log') -handler.setLevel(logging.DEBUG) +def init(filename = 'BlocklyPropClient.log'): + global path -# create a console handler for error-level events -console = logging.StreamHandler() -console.setLevel(logging.ERROR) + # Set a default log file name + logfile_name = filename -# create a logging format -formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') -handler.setFormatter(formatter) -console.setFormatter(formatter) - -# add the handlers to the logger -logger.addHandler(handler) -logger.addHandler(console) + # Set correct log file location + if platform == PLATFORM_MACOS: + logfile_name = __set_macos_logpath(filename) + if logfile_name is None: + return 1 + path = logfile_name -def init(): - logger.info("Logger has been started.") + # Logging path + try: # Python 2.7+ + from logging import NullHandler + except ImportError: + class NullHandler(logging.Handler): + def emit(self, record): + pass - # Debian linux - if platform == 'linux2': - if is_module_loaded() != 0: - return + logging.getLogger(__name__).addHandler(NullHandler()) - if check_system_messages() != 0: - return + # Create a logger + logger = logging.getLogger('blockly') + logger.setLevel(logging.DEBUG) - # MacOS - if platform == 'darwin': - if is_macos_ftdi_module_installed() != 0: - return 101 + # create a file handler to log events to the debug level. Log file + # is overwritten each time the app runs. + __log_file_location = logfile_name + handler = logging.FileHandler(logfile_name, mode='w') + handler.setLevel(logging.DEBUG) - if is_macos_ftdi_module_loaded != 0: - return 102 + # create a console handler for error-level events + console = logging.StreamHandler() + console.setLevel(logging.ERROR) + # create a logging format + formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') + handler.setFormatter(formatter) + console.setFormatter(formatter) -def is_module_loaded(): - try: - process = Popen(['cat', '/proc/modules'], stdout=PIPE, stderr=PIPE) - output = check_output(('grep', 'ftdi'), stdin=process.stdout) - logger.debug('FTDI module load state') - logger.debug(output) - return 0 - except CalledProcessError: - logger.warning('No FTDI modules detected.') - return 1 + # add the handlers to the logger + logger.addHandler(handler) + logger.addHandler(console) - -def check_system_messages(): - try: - process = Popen(['dmesg', '-H', '-x'], stdout=PIPE, stderr=PIPE) - output = check_output(('grep', 'ftdi'), stdin=process.stdout) - process.wait() - logger.debug(output) - return 0 - except CalledProcessError: - logger.warning('Serial port is not assigned.') - return 1 + logger.info("Logger has been started.") -def check_macos_logpath(): +def __set_macos_logpath(filename): user_home = os.path.expanduser('~') - log_path = user_home + '/Library/Logs/BlocklyProp' + log_path = user_home + '/Library/Logs/Parallax' # Does the log directory exist try: os.stat(log_path) - return 0 + return log_path + '/' + filename except OSError: # Create a new log path try: - os.mkdirs(log_path) + os.makedirs(log_path) except OSError: - return 1 + return None - return 0 - - -def is_macos_ftdi_module_loaded(): - try: - process = Popen(['kextstat'], stdout=PIPE, stderr=PIPE) - output = check_output(('grep', 'FTDI'), stdin=process.stdout) - logger.debug('FTDI module load state') - logger.debug(output) - return 0 - except CalledProcessError: - logger.warning('No FTDI modules detected.') - return 1 - - -def is_macos_ftdi_module_installed(): - return 0 + return log_path + '/' + filename diff --git a/BlocklyPropClient.py b/BlocklyPropClient.py index 30c4b56..1d2fd45 100644 --- a/BlocklyPropClient.py +++ b/BlocklyPropClient.py @@ -1,3 +1,7 @@ +""" + BlocklyProp Client + +""" import Tkinter as tk import ttk as ttk import tkMessageBox @@ -13,6 +17,7 @@ import logging import BlocklyServer import BlocklyLogger +import BlocklyHardware __author__ = 'Michel & Vale' @@ -20,15 +25,22 @@ PORT = 6009 VERSION = "0.5.1" + # Enable logging for functions outside of the class definition module_logger = logging.getLogger('blockly') + class BlocklyPropClient(tk.Tk): def __init__(self, *args, **kwargs): + + # Enable application logging BlocklyLogger.init() self.logger = logging.getLogger('blockly.main') self.logger.info('Creating logger.') + BlocklyHardware.init() + + # Init Tk tk.Tk.__init__(self, *args, **kwargs) # initialize values @@ -43,6 +55,7 @@ def __init__(self, *args, **kwargs): self.ip_address = tk.StringVar() self.port = tk.StringVar() self.trace_log = tk.IntVar() + self.logfile = tk.StringVar() # Default trace to enabled or logging level 1, not sure which it is self.trace_log.set(1) @@ -59,6 +72,7 @@ def __init__(self, *args, **kwargs): self.initialize() self.initialize_menu() + # Verify the hardware is connected and available def set_version(self, version): self.logger.info('Application version is %s', version) @@ -66,25 +80,51 @@ def set_version(self, version): def initialize(self): self.logger.info('Initializing the UI') + + # Display the client screen self.grid() + # IP address label self.lbl_ip_address = ttk.Label(self, anchor=tk.E, text='IP Address :') self.lbl_ip_address.grid(column=0, row=0, sticky='nesw') - self.ent_ip_address = ttk.Entry(self, state='readonly', textvariable=self.ip_address) - self.ent_ip_address.grid(column=1, row=0, sticky='nesw', padx=3, pady=3) - + # TCP port number label self.lbl_port = ttk.Label(self, anchor=tk.E, text='Port :') self.lbl_port.grid(column=0, row=1, sticky='nesw') + # Log file label + self.lbl_logfile = ttk.Label(self, anchor=tk.E, text='Log File :') + self.lbl_logfile.grid(column=0, row=2, sticky='nesw') + + # Open browser button self.btn_open_browser = ttk.Button(self, text='Open Browser', command=self.handle_browser) - self.btn_open_browser.grid(column=0, row=2, sticky='nesw', padx=3, pady=3) + self.btn_open_browser.grid(column=0, row=3, sticky='nesw', padx=3, pady=3) + + # Trace label + self.lbl_log = ttk.Label(self, anchor=tk.W, text='Trace :') + self.lbl_log.grid(column=0, row=4, sticky='nesw', padx=3, pady=3) + + # Trace log display window + self.ent_log = ScrolledText.ScrolledText(self, state='disabled') + self.ent_log.grid(column=0, row=5, columnspan=2, sticky='nesw', padx=3, pady=3) + + # IP address text box + self.ent_ip_address = ttk.Entry(self, state='readonly', textvariable=self.ip_address) + self.ent_ip_address.grid(column=1, row=0, sticky='nesw', padx=3, pady=3) + + # TCP port text box self.ent_port = ttk.Entry(self, textvariable=self.port) self.ent_port.grid(column=1, row=1, sticky='nesw', padx=3, pady=3) + # Log file text box + self.ent_logfile = ttk.Entry(self, textvariable=self.logfile) + self.ent_logfile.grid(column=1, row=2, sticky='nesw', padx=3, pady=3) + + + # Connect to device button self.btn_connect = ttk.Button(self, text='Connect', command=self.handle_connect) - self.btn_connect.grid(column=1, row=2, sticky='nesw', padx=3, pady=3) + self.btn_connect.grid(column=1, row=3, sticky='nesw', padx=3, pady=3) #self.lbl_current_code = ttk.Label( self, anchor=tk.E, text='Code most recently compiled :' ) #self.lbl_current_code.grid(column=0, row=5, sticky='nesw', padx=3, pady=3) @@ -92,18 +132,13 @@ def initialize(self): #self.current_code = ScrolledText.ScrolledText( self, state='disabled') #self.current_code.grid(column=0, row=6, columnspan=2, sticky='nesw', padx=3, pady=3) - self.lbl_log = ttk.Label(self, anchor=tk.W, text='Log :') - self.lbl_log.grid(column=0, row=3, sticky='nesw', padx=3, pady=3) + self.check_log_trace = tk.Checkbutton(self, anchor=tk.E, text='Trace logging', variable=self.trace_log, offvalue=1, onvalue=0) + self.check_log_trace.grid(column=1, row=4, sticky='nesw', padx=3, pady=3) - self.ent_log = ScrolledText.ScrolledText(self, state='disabled') - self.ent_log.grid(column=0, row=4, columnspan=2, sticky='nesw', padx=3, pady=3) #s = ttk.Style() #s.configure('Right.TCheckbutton', anchor='e') #self.check_log_trace = ttk.Checkbutton(self, style='Right.TCheckbutton', text='Trace logging', variable=self.trace_log) - self.check_log_trace = tk.Checkbutton(self, anchor=tk.E, text='Trace logging', variable=self.trace_log, offvalue=1, onvalue=0) - self.check_log_trace.grid(column=1, row=3, sticky='nesw', padx=3, pady=3) - #self.btn_log_checkbox = ttk.Button(self, text='Low level logging: Currently False', command=self.handle_lowlevel_logging) #self.btn_log_checkbox.grid(column=1, row=3, sticky='nesw', padx=3, pady=3) @@ -121,6 +156,10 @@ def initialize(self): self.port.set(PORT) self.logger.info('Port number is: %s', self.port.get()) + + self.logfile.set(BlocklyLogger.path) + self.logger.info('Disk log file location is: %s', BlocklyLogger.path) + self.server_process = None self.q = multiprocessing.Queue()