tcpip-to-serial-agent.py 4.51 KB
Newer Older
Robin Mueller's avatar
Robin Mueller committed
1
#!/usr/bin/env python3
Robin Mueller's avatar
Robin Mueller committed
2
import argparse
Robin Mueller's avatar
Robin Mueller committed
3
import enum
Robin Mueller's avatar
Robin Mueller committed
4
import threading
Robin Mueller's avatar
Robin Mueller committed
5
import signal
Robin Mueller's avatar
Robin Mueller committed
6
import os
Robin Mueller's avatar
Robin Mueller committed
7
import time
Robin Mueller's avatar
Robin Mueller committed
8

9
from . import __version__
Robin Mueller's avatar
Robin Mueller committed
10
11
from agent.log import get_console_logger
from agent.tcp_handler import TcpHandler
Robin Mueller's avatar
Robin Mueller committed
12
from agent.conf import JSON_CONF_FILE, DEFAULT_BAUDRATE, DEFAULT_MAX_DEQUE_SLOTS, DEFAULT_TCP_PORT
13
from agent.json import check_json_file, determine_debug_packets
Robin Mueller's avatar
Robin Mueller committed
14
from agent.serial_handler import SerialHandler, determine_com_port, find_com_port_from_hint
Robin Mueller's avatar
Robin Mueller committed
15
from agent.buffer import init_reception_buffer, set_max_slots
Robin Mueller's avatar
Robin Mueller committed
16
from agent.exit_handler import service_shutdown, ServiceExit, self_destruct_signalled
Robin Mueller's avatar
Robin Mueller committed
17
18


Robin Mueller's avatar
Robin Mueller committed
19
20
21
22
23
LOGGER = get_console_logger()


class ConfigKeys(enum.IntEnum):
    MAX_BUF_SLOTS = 0
Robin Mueller's avatar
Robin Mueller committed
24
    BAUD_RATE = 1
Robin Mueller's avatar
Robin Mueller committed
25
    SERIAL_PORT = 2
Robin Mueller's avatar
Robin Mueller committed
26
    TCP_PORT = 3
27
    DEBUG_PACKETS = 4
Robin Mueller's avatar
Robin Mueller committed
28
29


Robin Mueller's avatar
Robin Mueller committed
30
def main():
31
    print(f'-- Starting TCP/IP to Serial Agent {__version__}for the iOBC --')
32
33
34
35
    error_setup()
    try:
        start_application()
    except ServiceExit:
Robin Mueller's avatar
Robin Mueller committed
36
        LOGGER.info('Closing TCP/IP to Serial Agent')
Robin Mueller's avatar
Robin Mueller committed
37

38
39
40

def start_application():
    cfg_dict = args_setup()
Robin Mueller's avatar
Robin Mueller committed
41
    set_max_slots(max_slots=cfg_dict[ConfigKeys.MAX_BUF_SLOTS])
Robin Mueller's avatar
Robin Mueller committed
42
43
    init_reception_buffer()

Robin Mueller's avatar
Robin Mueller committed
44
    ser_handler = SerialHandler(
Robin Mueller's avatar
Robin Mueller committed
45
        serial_port=cfg_dict[ConfigKeys.SERIAL_PORT], baud_rate=cfg_dict[ConfigKeys.BAUD_RATE]
Robin Mueller's avatar
Robin Mueller committed
46
    )
47
    tcp_handler = TcpHandler(
Robin Mueller's avatar
Robin Mueller committed
48
49
        serial_handler=ser_handler, port=cfg_dict[ConfigKeys.TCP_PORT],
        debug_packets=cfg_dict[ConfigKeys.DEBUG_PACKETS]
50
    )
Robin Mueller's avatar
Robin Mueller committed
51

Robin Mueller's avatar
Robin Mueller committed
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
    serial_polling_thread = None
    tcp_thread = None
    try:
        serial_polling_thread = threading.Thread(target=ser_handler.run)
        tcp_thread = threading.Thread(target=tcp_handler.run)
        serial_polling_thread.start()
        tcp_thread.start()
        # Keep the main thread running, otherwise signals are ignored.
        while True:
            if self_destruct_signalled():
                raise ServiceExit
            time.sleep(0.5)
    except ServiceExit:
        # Graceful exit
        ser_handler.stop()
        tcp_handler.stop()
        serial_polling_thread.join()
        tcp_thread.join()
Robin Mueller's avatar
Robin Mueller committed
70
    finally:
71
        LOGGER.warning('TCP/IP to Serial Agent exited unexpectedly')
Robin Mueller's avatar
Robin Mueller committed
72
73


74
def error_setup():
Robin Mueller's avatar
Robin Mueller committed
75
76
77
78
79
80
81
82
83
    # atexit.register(keyboard_interrupt_handler)
    # Register the signal handlers
    signal.signal(signal.SIGTERM, service_shutdown)
    signal.signal(signal.SIGINT, service_shutdown)


def args_setup() -> dict:
    cfg_dict = dict()
    arg_parser = argparse.ArgumentParser(description='TCP/IP to Serial Bridge for the iOBC')
Robin Mueller's avatar
Robin Mueller committed
84
85
    arg_parser.add_argument('-p', '--tcp_port', dest='tcp_port', type=str, help='TCP server port')
    arg_parser.add_argument('-s', '--ser_port', dest='ser_port', type=str, help='Serial port')
Robin Mueller's avatar
Robin Mueller committed
86
87
88
89
90
91
    arg_parser.add_argument('-b', '--baudrate', dest='baud', type=int, help='Serial baudrate')
    arg_parser.add_argument('--hint', dest='hint', type=str, help='Hint for serial port name')
    arg_parser.add_argument(
        '--buf_slots', dest='buf_slots', type=int, help='Buffer slots for TM reception queue'
    )
    arg_parser.add_argument(
Robin Mueller's avatar
Robin Mueller committed
92
        '-d', '--delete', dest='del_conf', action='store_true', help='Delete configuration JSON'
Robin Mueller's avatar
Robin Mueller committed
93
94
95
    )
    args = arg_parser.parse_args()

Robin Mueller's avatar
Robin Mueller committed
96
    LOGGER.info(f'Checking JSON configuration file {JSON_CONF_FILE}')
97
    check_json_file(JSON_CONF_FILE)
Robin Mueller's avatar
Robin Mueller committed
98
    serial_port = ''
Robin Mueller's avatar
Robin Mueller committed
99
    if args.del_conf:
100
101
        LOGGER.info(f'Deleting JSON configuration file {JSON_CONF_FILE}')
        os.remove(JSON_CONF_FILE)
Robin Mueller's avatar
Robin Mueller committed
102
103
104
    if args.ser_port is not None:
        LOGGER.info(f'Serial port {args.ser_port} was specified')
        serial_port = args.ser_port
Robin Mueller's avatar
Robin Mueller committed
105
106
107
108
109
    else:
        com_port_found = False
        if args.hint is not None:
            com_port_found, serial_port = find_com_port_from_hint(hint=args.hint)
        if not com_port_found:
110
            serial_port = determine_com_port(json_cfg_path=JSON_CONF_FILE)
Robin Mueller's avatar
Robin Mueller committed
111
    if args.baud is not None:
112
        baud_rate = args.baud
Robin Mueller's avatar
Robin Mueller committed
113
    else:
114
115
        LOGGER.info(f'Using default baud rate {DEFAULT_BAUDRATE}')
        baud_rate = DEFAULT_BAUDRATE
Robin Mueller's avatar
Robin Mueller committed
116
117
118
119
    if args.buf_slots is not None:
        max_buf_slots = args.buf_slots
    else:
        max_buf_slots = DEFAULT_MAX_DEQUE_SLOTS
Robin Mueller's avatar
Robin Mueller committed
120
121
122
123
    if args.tcp_port is not None:
        tcp_port = args.tcp_port
    else:
        tcp_port = DEFAULT_TCP_PORT
Robin Mueller's avatar
Robin Mueller committed
124
125
    cfg_dict[ConfigKeys.SERIAL_PORT] = serial_port
    cfg_dict[ConfigKeys.MAX_BUF_SLOTS] = max_buf_slots
126
    cfg_dict[ConfigKeys.BAUD_RATE] = baud_rate
Robin Mueller's avatar
Robin Mueller committed
127
    cfg_dict[ConfigKeys.TCP_PORT] = tcp_port
128
    cfg_dict[ConfigKeys.DEBUG_PACKETS] = determine_debug_packets(json_cfg_path=JSON_CONF_FILE)
Robin Mueller's avatar
Robin Mueller committed
129
    return cfg_dict
Robin Mueller's avatar
Robin Mueller committed
130
131
132
133


if __name__ == "__main__":
    main()