"""Module is the entry point for the RaSCSI Control Board UI""" import argparse import sys import logging from config import CtrlboardConfig from ctrlboard_hw.ctrlboard_hw import CtrlBoardHardware from ctrlboard_hw.ctrlboard_hw_constants import CtrlBoardHardwareConstants from ctrlboard_event_handler.ctrlboard_menu_update_event_handler \ import CtrlBoardMenuUpdateEventHandler from ctrlboard_menu_builder import CtrlBoardMenuBuilder from menu.menu_renderer_config import MenuRendererConfig from menu.menu_renderer_luma_oled import MenuRendererLumaOled from rascsi.exceptions import (EmptySocketChunkException, InvalidProtobufResponse, FailedSocketConnectionException) from rascsi.ractl_cmds import RaCtlCmds from rascsi.socket_cmds import SocketCmds from rascsi_menu_controller import RascsiMenuController def parse_config(): """Parses the command line parameters and configured the RaSCSI Control Board UI accordingly""" config = CtrlboardConfig() cmdline_args_parser = argparse.ArgumentParser(description='RaSCSI ctrlboard service') cmdline_args_parser.add_argument( "--rotation", type=int, choices=[0, 90, 180, 270], default=180, action="store", help="The rotation of the screen buffer in degrees. Default: 180", ) cmdline_args_parser.add_argument( "--height", type=int, choices=[64], default=64, action="store", help="The pixel height of the screen buffer. Default: 64", ) cmdline_args_parser.add_argument( "--rascsi-host", type=str, default="localhost", action="store", help="RaSCSI host. Default: localhost", ) cmdline_args_parser.add_argument( "--rascsi-port", type=int, default=6868, action="store", help="RaSCSI port. Default: 6868", ) cmdline_args_parser.add_argument( "--password", type=str, default="", action="store", help="Token password string for authenticating with RaSCSI", ) cmdline_args_parser.add_argument( "--loglevel", type=int, choices=[0, 10, 30, 40, 50], default=logging.WARN, action="store", help="Loglevel. Valid values: 0 (notset), 10 (debug), 30 (warning), " "40 (error), 50 (critical). Default: Warning", ) cmdline_args_parser.add_argument( "--transitions", type=int, choices=[0, 1], default=1, action="store", help="Transition animations. Valid values: 0 (disabled), 1 (enabled). Default: 1", ) args = cmdline_args_parser.parse_args() config.ROTATION = args.rotation if args.height == 64: config.HEIGHT = 64 config.LINES = 8 elif args.height == 32: config.HEIGHT = 32 config.LINES = 4 config.TOKEN = args.password config.WIDTH = 128 config.BORDER = 5 config.RASCSI_HOST = args.rascsi_host config.RASCSI_PORT = args.rascsi_port config.LOG_LEVEL = args.loglevel config.TRANSITIONS = bool(args.transitions) return config def check_rascsi_connection(ractl_cmd): """Checks whether a RaSCSI connection exists by polling the RaSCSI server info. Returns true if connection works, false if connection fails.""" try: info = ractl_cmd.get_reserved_ids() return bool(info["status"] is True) except FailedSocketConnectionException: log = logging.getLogger(__name__) log.error("Could not establish connection. Stopping service") exit(1) def main(): """Main function for the RaSCSI Control Board UI""" config = parse_config() log_format = "%(asctime)s:%(name)s:%(levelname)s - %(message)s" logging.basicConfig(stream=sys.stdout, format=log_format, level=config.LOG_LEVEL) log = logging.getLogger(__name__) log.debug("RaSCSI ctrlboard service started.") ctrlboard_hw = CtrlBoardHardware(display_i2c_address=config.DISPLAY_I2C_ADDRESS, pca9554_i2c_address=config.PCA9554_I2C_ADDRESS) # for now, we require the complete rascsi ctrlboard hardware. # Oled only will be supported as well at some later point in time. if ctrlboard_hw.rascsi_controlboard_detected is False: log.error("Ctrlboard hardware not detected. Stopping service") exit(1) sock_cmd = None ractl_cmd = None try: sock_cmd = SocketCmds(host=config.RASCSI_HOST, port=config.RASCSI_PORT) ractl_cmd = RaCtlCmds(sock_cmd=sock_cmd, token=config.TOKEN) except EmptySocketChunkException: log.error("Retrieved empty data from RaSCSI. Stopping service") exit(1) except InvalidProtobufResponse: log.error("Retrieved unexpected data from RaSCSI. Stopping service") exit(1) if check_rascsi_connection(ractl_cmd) is False: log.error("Communication with RaSCSI failed. Please check if password token must be set " "and whether is set correctly.") exit(1) menu_renderer_config = MenuRendererConfig() if config.TRANSITIONS is False: menu_renderer_config.transition = None menu_renderer_config.i2c_address = CtrlBoardHardwareConstants.DISPLAY_I2C_ADDRESS menu_renderer_config.rotation = config.ROTATION menu_builder = CtrlBoardMenuBuilder(ractl_cmd) menu_controller = RascsiMenuController(config.MENU_REFRESH_INTERVAL, menu_builder=menu_builder, menu_renderer=MenuRendererLumaOled(menu_renderer_config), menu_renderer_config=menu_renderer_config) menu_controller.add(CtrlBoardMenuBuilder.SCSI_ID_MENU) menu_controller.add(CtrlBoardMenuBuilder.ACTION_MENU) menu_controller.show_splash_screen(f"resources/splash_start_64.bmp") menu_update_event_handler = CtrlBoardMenuUpdateEventHandler(menu_controller, sock_cmd=sock_cmd, ractl_cmd=ractl_cmd) ctrlboard_hw.attach(menu_update_event_handler) menu_controller.set_active_menu(CtrlBoardMenuBuilder.SCSI_ID_MENU) while True: # pylint: disable=broad-except try: ctrlboard_hw.process_events() menu_update_event_handler.update_events() menu_controller.update() except KeyboardInterrupt: ctrlboard_hw.cleanup() break except Exception as ex: print(ex) if __name__ == '__main__': main()