i think mio would still be good here
This commit is contained in:
@ -7,6 +7,7 @@ import struct
|
||||
|
||||
EXPERIMENT_ID = 278
|
||||
EXPERIMENT_APID = 1024 + EXPERIMENT_ID
|
||||
TCP_SERVER_PORT = 4096
|
||||
|
||||
|
||||
class EventSeverity(enum.IntEnum):
|
||||
|
@ -18,7 +18,7 @@ from spacepackets.ccsds.time import CdsShortTimestamp
|
||||
from tmtccmd import TcHandlerBase, ProcedureParamsWrapper
|
||||
from tmtccmd.core.base import BackendRequest
|
||||
from tmtccmd.pus import VerificationWrapper
|
||||
from tmtccmd.tmtc import CcsdsTmHandler, GenericApidHandlerBase, TelemetryListT
|
||||
from tmtccmd.tmtc import CcsdsTmHandler, GenericApidHandlerBase
|
||||
from tmtccmd.com import ComInterface
|
||||
from tmtccmd.config import (
|
||||
CmdTreeNode,
|
||||
@ -44,13 +44,12 @@ from tmtccmd.tmtc import (
|
||||
QueueWrapper,
|
||||
)
|
||||
from spacepackets.seqcount import FileSeqCountProvider, PusFileSeqCountProvider
|
||||
from tcp_server import TcpServer
|
||||
from tmtccmd.util.obj_id import ObjectIdDictT
|
||||
from collections import deque
|
||||
import socket
|
||||
|
||||
|
||||
import pus_tc
|
||||
from common import EXPERIMENT_APID, EventU32
|
||||
from common import EXPERIMENT_APID, EventU32, TCP_SERVER_PORT
|
||||
|
||||
_LOGGER = logging.getLogger()
|
||||
|
||||
@ -68,13 +67,17 @@ class SatRsConfigHook(HookBase):
|
||||
assert self.cfg_path is not None
|
||||
packet_id_list = []
|
||||
packet_id_list.append(PacketId(PacketType.TM, True, EXPERIMENT_APID))
|
||||
cfg = create_com_interface_cfg_default(
|
||||
com_if_key=com_if_key,
|
||||
json_cfg_path=self.cfg_path,
|
||||
space_packet_ids=packet_id_list,
|
||||
)
|
||||
assert cfg is not None
|
||||
return create_com_interface_default(cfg)
|
||||
if com_if_key == "tcp_server":
|
||||
tcp_server = TcpServer(TCP_SERVER_PORT)
|
||||
return tcp_server
|
||||
else:
|
||||
cfg = create_com_interface_cfg_default(
|
||||
com_if_key=com_if_key,
|
||||
json_cfg_path=self.cfg_path,
|
||||
space_packet_ids=packet_id_list,
|
||||
)
|
||||
assert cfg is not None
|
||||
return create_com_interface_default(cfg)
|
||||
|
||||
def get_command_definitions(self) -> CmdTreeNode:
|
||||
"""This function should return the root node of the command definition tree."""
|
||||
|
@ -1,4 +1,6 @@
|
||||
from typing import Any, Optional
|
||||
import select
|
||||
import time
|
||||
import socket
|
||||
import logging
|
||||
from threading import Thread, Event, Lock
|
||||
@ -16,6 +18,7 @@ class TcpServer(ComInterface):
|
||||
self.port = port
|
||||
self._max_num_packets_in_tc_queue = 500
|
||||
self._max_num_packets_in_tm_queue = 500
|
||||
self._default_timeout_secs = 0.5
|
||||
self._server_addr = ("localhost", self.port)
|
||||
self._tc_packet_queue = deque()
|
||||
self._tm_packet_queue = deque()
|
||||
@ -23,8 +26,11 @@ class TcpServer(ComInterface):
|
||||
self._tm_lock = Lock()
|
||||
self._kill_signal = Event()
|
||||
self._server_socket: Optional[socket.socket] = None
|
||||
self._server_thread = Thread(target=TcpServer._server_task, daemon=True)
|
||||
self._server_thread = Thread(target=self._server_task, daemon=True)
|
||||
self._connected = False
|
||||
self._conn_start = None
|
||||
self._writing_done = False
|
||||
self._reading_done = False
|
||||
|
||||
@property
|
||||
def connected(self) -> bool:
|
||||
@ -47,31 +53,44 @@ class TcpServer(ComInterface):
|
||||
"""
|
||||
if self.connected:
|
||||
return
|
||||
self.server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
self.server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
||||
# We need to check the kill signal periodically to allow closing the server.
|
||||
self.server_socket.settimeout(0.5)
|
||||
self.server_socket.bind(self._server_addr)
|
||||
self._connected = True
|
||||
self._server_thread.start()
|
||||
|
||||
def _server_task(self):
|
||||
assert self._server_socket is not None
|
||||
self._server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
self._server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
||||
# We need to check the kill signal periodically to allow closing the server.
|
||||
self._server_socket.settimeout(self._default_timeout_secs)
|
||||
self._server_socket.bind(self._server_addr)
|
||||
self._server_socket.listen()
|
||||
while True and not self._kill_signal.is_set():
|
||||
self._server_socket.listen()
|
||||
(conn_socket, conn_addr) = self._server_socket.accept()
|
||||
_LOGGER.info("TCP client {} connected", conn_addr)
|
||||
while True:
|
||||
bytes_recvd = conn_socket.recv(4096)
|
||||
if len(bytes_recvd) > 0:
|
||||
print(f"Received bytes from TCP client: {bytes_recvd.decode()}")
|
||||
with self._tm_lock:
|
||||
self._tm_packet_queue.append(bytes_recvd)
|
||||
elif len(bytes_recvd) == 0:
|
||||
break
|
||||
else:
|
||||
print("error receiving data from TCP client")
|
||||
try:
|
||||
(conn_socket, conn_addr) = self._server_socket.accept()
|
||||
self.conn_start = time.time()
|
||||
while True:
|
||||
self._handle_connection(conn_socket, conn_addr)
|
||||
if (
|
||||
self._reading_done and self._writing_done
|
||||
) or time.time() - self.conn_start > 0.5:
|
||||
print("reading and writing done")
|
||||
break
|
||||
except TimeoutError:
|
||||
print("timeout error")
|
||||
continue
|
||||
|
||||
def _handle_connection(self, conn_socket: socket.socket, conn_addr: Any):
|
||||
_LOGGER.info(f"TCP client {conn_addr} connected")
|
||||
(readable, writable, _) = select.select(
|
||||
[conn_socket],
|
||||
[conn_socket],
|
||||
[],
|
||||
0.1,
|
||||
)
|
||||
|
||||
# TODO: Why is the stupid conn socket never readable?
|
||||
print(f"Writable: {writable}")
|
||||
print(f"Readable: {readable}")
|
||||
if writable and writable[0]:
|
||||
queue_len = 0
|
||||
with self._tc_lock:
|
||||
queue_len = len(self._tc_packet_queue)
|
||||
@ -79,8 +98,23 @@ class TcpServer(ComInterface):
|
||||
next_packet = bytes()
|
||||
with self._tc_lock:
|
||||
next_packet = self._tc_packet_queue.popleft()
|
||||
conn_socket.sendall(next_packet)
|
||||
if len(next_packet) > 0:
|
||||
conn_socket.sendall(next_packet)
|
||||
queue_len -= 1
|
||||
self._writing_done = True
|
||||
if readable and readable[0]:
|
||||
print("reading shit")
|
||||
while True:
|
||||
bytes_recvd = conn_socket.recv(4096)
|
||||
if len(bytes_recvd) > 0:
|
||||
print(f"Received bytes from TCP client: {bytes_recvd.decode()}")
|
||||
with self._tm_lock:
|
||||
self._tm_packet_queue.append(bytes_recvd)
|
||||
elif len(bytes_recvd) == 0:
|
||||
self._reading_done = True
|
||||
break
|
||||
else:
|
||||
print("error receiving data from TCP client")
|
||||
|
||||
def is_open(self) -> bool:
|
||||
"""Can be used to check whether the communication interface is open. This is useful if
|
||||
@ -103,7 +137,6 @@ class TcpServer(ComInterface):
|
||||
:raises SendError: Sending failed for some reason.
|
||||
"""
|
||||
with self._tc_lock:
|
||||
# Deque is thread-safe according to the documentation.. so this should be fine.
|
||||
if len(self._tc_packet_queue) >= self._max_num_packets_in_tc_queue:
|
||||
# Remove oldest packet
|
||||
self._tc_packet_queue.popleft()
|
||||
|
Reference in New Issue
Block a user