Skip to content

Commit

Permalink
chore: Add comprehensive error codes to app_config.json in COMMonitor V2
Browse files Browse the repository at this point in the history
- 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.
  • Loading branch information
YounesElMehdi committed Aug 15, 2024
1 parent 7acb13a commit 9ee47de
Show file tree
Hide file tree
Showing 3 changed files with 111 additions and 29 deletions.
2 changes: 1 addition & 1 deletion .idea/COMMonitor.iml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

34 changes: 34 additions & 0 deletions app_config.json
Original file line number Diff line number Diff line change
@@ -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."
}
}
104 changes: 76 additions & 28 deletions main.py
Original file line number Diff line number Diff line change
Expand Up @@ -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")


Expand All @@ -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

Expand All @@ -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)
Expand All @@ -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)
Expand All @@ -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
Expand All @@ -107,37 +124,64 @@ 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}")


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:
Expand All @@ -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.")


Expand All @@ -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.")


Expand All @@ -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:
Expand All @@ -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.")


Expand Down

0 comments on commit 9ee47de

Please sign in to comment.