i think mio would still be good here

This commit is contained in:
2024-04-18 20:08:08 +02:00
parent c510df3154
commit 7d51c2813d
7 changed files with 152 additions and 80 deletions

View File

@ -7,6 +7,7 @@ import struct
EXPERIMENT_ID = 278
EXPERIMENT_APID = 1024 + EXPERIMENT_ID
TCP_SERVER_PORT = 4096
class EventSeverity(enum.IntEnum):

View File

@ -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."""

View File

@ -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()