tcpip-to-serial-agent.py 3.76 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

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


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


class ConfigKeys(enum.IntEnum):
    MAX_BUF_SLOTS = 0
    BAUDRATE = 1
    SERIAL_PORT = 2


Robin Mueller's avatar
Robin Mueller committed
27
def main():
Robin Mueller's avatar
Robin Mueller committed
28
    print('-- Starting TCP/IP to Serial Agent for the iOBC --')
29
30
31
32
    error_setup()
    try:
        start_application()
    except ServiceExit:
Robin Mueller's avatar
Robin Mueller committed
33
        LOGGER.info('Closing TCP/IP to Serial Agent')
Robin Mueller's avatar
Robin Mueller committed
34

35
36
37

def start_application():
    cfg_dict = args_setup()
Robin Mueller's avatar
Robin Mueller committed
38
    set_max_slots(max_slots=cfg_dict[ConfigKeys.MAX_BUF_SLOTS])
Robin Mueller's avatar
Robin Mueller committed
39
40
    init_reception_buffer()

Robin Mueller's avatar
Robin Mueller committed
41
42
43
    ser_handler = SerialHandler(
        serial_port=cfg_dict[ConfigKeys.SERIAL_PORT], baud_rate=cfg_dict[ConfigKeys.BAUDRATE]
    )
Robin Mueller's avatar
Robin Mueller committed
44
45
    tcp_handler = TcpHandler()

Robin Mueller's avatar
Robin Mueller committed
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
    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
64
    finally:
65
        LOGGER.warning('TCP/IP to Serial Agent exited unexpectedly')
Robin Mueller's avatar
Robin Mueller committed
66
67


68
def error_setup():
Robin Mueller's avatar
Robin Mueller committed
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
    # 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')
    arg_parser.add_argument('-p', '--port', dest='port', type=str, help='Serial port')
    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
85
        '-d', '--delete', dest='del_conf', action='store_true', help='Delete configuration JSON'
Robin Mueller's avatar
Robin Mueller committed
86
87
88
89
90
    )
    args = arg_parser.parse_args()

    check_json_file(JSON_CONF_NAME)
    serial_port = ''
Robin Mueller's avatar
Robin Mueller committed
91
    if args.del_conf:
92
        LOGGER.info(f'Deleting JSON configuration file {JSON_CONF_NAME}')
Robin Mueller's avatar
Robin Mueller committed
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
        os.remove(JSON_CONF_NAME)
    if args.port is not None:
        LOGGER.info(f'Serial port {args.port} was specified')
        serial_port = args.port
    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:
            serial_port = determine_com_port(json_cfg_path=JSON_CONF_NAME)
    if args.baud is not None:
        baudrate = args.baud
    else:
        baudrate = DEFAULT_BAUDRATE
    if args.buf_slots is not None:
        max_buf_slots = args.buf_slots
    else:
        max_buf_slots = DEFAULT_MAX_DEQUE_SLOTS

    cfg_dict[ConfigKeys.SERIAL_PORT] = serial_port
    cfg_dict[ConfigKeys.MAX_BUF_SLOTS] = max_buf_slots
    cfg_dict[ConfigKeys.BAUDRATE] = baudrate
    return cfg_dict
Robin Mueller's avatar
Robin Mueller committed
116
117
118
119


if __name__ == "__main__":
    main()