From 9ee47de7668bec0f0607c5be5fe6a6956c83a856 Mon Sep 17 00:00:00 2001 From: YounesMDev Date: Thu, 15 Aug 2024 19:19:55 +0200 Subject: [PATCH] chore: Add comprehensive error codes to app_config.json in COMMonitor V2 - Included a wide range of common serial communication error codes and their descriptions in the configuration file. - Updated the error code lookup functionality to fetch descriptions from the JSON config. - Improved maintainability by centralizing fixed data in app_config.json. --- .idea/COMMonitor.iml | 2 +- app_config.json | 34 ++++++++++++++ main.py | 104 +++++++++++++++++++++++++++++++------------ 3 files changed, 111 insertions(+), 29 deletions(-) create mode 100644 app_config.json diff --git a/.idea/COMMonitor.iml b/.idea/COMMonitor.iml index 2c80e12..50d98fc 100644 --- a/.idea/COMMonitor.iml +++ b/.idea/COMMonitor.iml @@ -4,7 +4,7 @@ - + \ No newline at end of file diff --git a/app_config.json b/app_config.json new file mode 100644 index 0000000..adbda2a --- /dev/null +++ b/app_config.json @@ -0,0 +1,34 @@ +{ + "terminal_size": { + "width": 80, + "height": 24 + }, + "log_settings": { + "log_filename": "COMMonitor", + "log_level": "INFO", + "log_format": "%(asctime)s - %(levelname)s - %(message)s", + "log_date_format": "%Y-%m-%d %H:%M:%S" + }, + "error_codes": { + "1": "Incorrect function. This could happen if a function is called on a COM port that does not support it.", + "2": "File Not Found (The specified COM port could not be found or is disabled.)", + "5": "Access Denied (The COM port is in use by another application.)", + "6": "The handle is invalid. This might happen if there’s a problem with how the port was opened or managed.", + "10": "The environment is incorrect. This might indicate an issue with the configuration of the COM port.", + "20": "The system cannot find the device specified. Similar to ERROR_FILE_NOT_FOUND, it might indicate that the COM port is missing.", + "21": "The device is not ready. This might occur if the COM port device is not ready to receive data.", + "22": "The device does not recognize the command given to it. This could indicate that the command or data sent to the COM port is not valid.", + "24": "The length of the data provided to a system call is invalid.", + "31": "A device attached to the system is not functioning. This could indicate hardware issues with the port.", + "87": "The parameter is incorrect. This might occur if the port is being accessed with incorrect settings or configurations.", + "110": "The system cannot open the device or file specified.", + "121": "The semaphore timeout period has expired. This might occur if the device connected to the port is not responding.", + "122": "The data area passed to a system call is too small.", + "234": "More data is available. This might occur if a buffer is too small to hold the data being received.", + "995": "The I/O operation has been aborted due to thread exit or application request.", + "998": "Invalid access to memory location. This might happen if the memory associated with the COM port is not accessible.", + "1117": "The request could not be performed because of an I/O device error. This indicates a general problem with the hardware.", + "1167": "The device is not connected. This usually occurs when the device was physically disconnected or powered off.", + "1460": "This operation returned because the timeout period expired." + } +} diff --git a/main.py b/main.py index 270a06b..735f85a 100644 --- a/main.py +++ b/main.py @@ -2,38 +2,55 @@ import serial.tools.list_ports import sys import logging +import json from datetime import datetime +from colorama import Fore, Style, init + +# Initialize Colorama for cross-platform colored text +init() + +# Load configuration from JSON file +with open('app_config.json', 'r') as config_file: + config = json.load(config_file) + +# Set the terminal size +sys.stdout.write(f"\x1b[8;{config['terminal_size']['height']};{config['terminal_size']['width']}t") # Set up logging +log_filename = f"{config['log_settings']['log_filename']}_{datetime.now().strftime('%Y%m%d_%H%M%S')}.log" logging.basicConfig( - filename=f'COMMonitor_{datetime.now().strftime("%Y%m%d_%H%M%S")}.log', - level=logging.INFO, - format='%(asctime)s - %(levelname)s - %(message)s', - datefmt='%Y-%m-%d %H:%M:%S' + filename=log_filename, + level=getattr(logging, config['log_settings']['log_level']), + format=config['log_settings']['log_format'], + datefmt=config['log_settings']['log_date_format'] ) def welcome(): - print(''' + print(Fore.CYAN + ''' ********************************** * Welcome to COMMonitor * ********************************** - * Version: 1.0 * + * Version: 2.0 * * Developed for offline stations * * Diagnose and test serial ports * + * * + * Developer: Yelmehdi * ********************************** - ''') + ''' + Style.RESET_ALL) logging.info("COMMonitor App Started") def main_menu(): - print(''' + print(Fore.YELLOW + ''' Main Menu: 1. List and Check COM Ports 2. Perform Stress Test 3. Perform Loopback Test - 4. Exit Application - ''') + 4. Error Code Lookup + 5. Run Basic Diagnostic Script + 6. Exit Application + ''' + Style.RESET_ALL) logging.info("Displayed Main Menu") @@ -45,7 +62,7 @@ def list_ports(): print(f"{i}. {port.name} - {port.description}") return ports else: - print("No Serial Ports Detected") + print(Fore.RED + "No Serial Ports Detected" + Style.RESET_ALL) logging.warning("No Serial Ports Detected") return None @@ -54,7 +71,7 @@ def check_port_status(port): try: with serial.Serial(port.device, timeout=1) as ser: status = "Ready to Use" - print(f"Port {port.name} is {status}.") + print(Fore.GREEN + f"Port {port.name} is {status}." + Style.RESET_ALL) logging.info(f"Port {port.name} is {status}.") received_data = ser.read(100) @@ -76,7 +93,7 @@ def check_port_status(port): else: status = "Unknown Error" - print(f"Port {port.name} is {status}.") + print(Fore.RED + f"Port {port.name} is {status}." + Style.RESET_ALL) logging.error(f"Port {port.name} is {status}. Error: {e}") log_port_info(port, status) @@ -94,7 +111,7 @@ def port_stress_test(port, duration=10): try: with serial.Serial(port.device, timeout=1) as ser: start_time = datetime.now() - print(f"Starting stress test on {port.name} for {duration} seconds...") + print(Fore.YELLOW + f"Starting stress test on {port.name} for {duration} seconds..." + Style.RESET_ALL) logging.info(f"Starting stress test on {port.name} for {duration} seconds.") data_to_send = b'0123456789ABCDEF' * 64 @@ -107,13 +124,13 @@ def port_stress_test(port, duration=10): logging.warning(f"Data mismatch detected on {port.name}.") if errors == 0: - print(f"Stress test passed for {port.name}. No errors detected.") + print(Fore.GREEN + f"Stress test passed for {port.name}. No errors detected." + Style.RESET_ALL) logging.info(f"Stress test passed for {port.name}. No errors detected.") else: - print(f"Stress test failed for {port.name}. {errors} errors detected.") + print(Fore.RED + f"Stress test failed for {port.name}. {errors} errors detected." + Style.RESET_ALL) logging.error(f"Stress test failed for {port.name}. {errors} errors detected.") except serial.SerialException as e: - print(f"Error during stress test on {port.name}: {e}") + print(Fore.RED + f"Error during stress test on {port.name}: {e}" + Style.RESET_ALL) logging.error(f"Error during stress test on {port.name}: {e}") @@ -121,23 +138,50 @@ def loopback_test(port): try: with serial.Serial(port.device, timeout=1) as ser: test_data = b'LOOPBACK_TEST' - print(f"Performing loopback test on {port.name}...") + print(Fore.YELLOW + f"Performing loopback test on {port.name}..." + Style.RESET_ALL) logging.info(f"Performing loopback test on {port.name}...") ser.write(test_data) received_data = ser.read(len(test_data)) if received_data == test_data: - print(f"Loopback test passed for {port.name}. Data matched.") + print(Fore.GREEN + f"Loopback test passed for {port.name}. Data matched." + Style.RESET_ALL) logging.info(f"Loopback test passed for {port.name}. Data matched.") else: - print(f"Loopback test failed for {port.name}. Data did not match.") + print(Fore.RED + f"Loopback test failed for {port.name}. Data did not match." + Style.RESET_ALL) logging.error(f"Loopback test failed for {port.name}. Data did not match.") except serial.SerialException as e: - print(f"Error during loopback test on {port.name}: {e}") + print(Fore.RED + f"Error during loopback test on {port.name}: {e}" + Style.RESET_ALL) logging.error(f"Error during loopback test on {port.name}: {e}") +def error_code_lookup(): + print(Fore.YELLOW + "Error Code Lookup" + Style.RESET_ALL) + while True: + try: + code = int(input("Enter the error code you want to look up (or type 0 to return to the Main Menu): ").strip()) + if code == 0: + break + description = config['error_codes'].get(str(code), "Error code not recognized.") + print(Fore.CYAN + f"Error Code {code}: {description}" + Style.RESET_ALL) + except ValueError: + print(Fore.RED + "Invalid input. Please enter a valid error code." + Style.RESET_ALL) + + +def run_diagnostic_script(): + print(Fore.YELLOW + "Running Basic Diagnostic Script..." + Style.RESET_ALL) + try: + ports = list_ports() + if ports: + for port in ports: + check_port_status(port) + print(Fore.GREEN + "Diagnostic script completed." + Style.RESET_ALL) + logging.info("Basic diagnostic script completed.") + except Exception as e: + print(Fore.RED + f"An error occurred while running the diagnostic script: {e}" + Style.RESET_ALL) + logging.error(f"An error occurred while running the diagnostic script: {e}") + + def select_port_for_test(ports, test_type): while True: try: @@ -151,7 +195,7 @@ def select_port_for_test(ports, test_type): loopback_test(selected_port) break except (ValueError, IndexError): - print("Invalid selection. Please enter a valid port number.") + print(Fore.RED + "Invalid selection. Please enter a valid port number." + Style.RESET_ALL) logging.warning("Invalid selection made by user.") @@ -161,15 +205,15 @@ def ask_for_exit_confirmation(): "Do you want to exit the application? Type 'yes' to exit or 'no' to return to the Main Menu: ").strip().lower() if user_input in ('yes', 'y'): - print("Exiting the application...") + print(Fore.YELLOW + "Exiting the application..." + Style.RESET_ALL) logging.info("User chose to exit the application.") exit() elif user_input in ('no', 'n'): - print("Returning to the Main Menu...\n") + print(Fore.GREEN + "Returning to the Main Menu...\n" + Style.RESET_ALL) logging.info("User chose to return to the Main Menu.") main_menu_handler() else: - print("Invalid input. Please type 'yes' or 'no'.") + print(Fore.RED + "Invalid input. Please type 'yes' or 'no'." + Style.RESET_ALL) logging.warning("User entered invalid input for exit confirmation.") @@ -178,7 +222,7 @@ def main_menu_handler(): while True: main_menu() try: - choice = int(input("Enter your choice (1-4): ").strip()) + choice = int(input("Enter your choice (1-6): ").strip()) if choice == 1: ports = list_ports() if ports: @@ -192,12 +236,16 @@ def main_menu_handler(): if ports: select_port_for_test(ports, "perform loopback test") elif choice == 4: + error_code_lookup() + elif choice == 5: + run_diagnostic_script() + elif choice == 6: ask_for_exit_confirmation() else: - print("Invalid choice. Please enter a number between 1 and 4.") + print(Fore.RED + "Invalid choice. Please enter a number between 1 and 6." + Style.RESET_ALL) logging.warning("Invalid menu choice made by user.") except ValueError: - print("Invalid input. Please enter a number.") + print(Fore.RED + "Invalid input. Please enter a number." + Style.RESET_ALL) logging.warning("Invalid input for menu choice.")