fix: terminate on SIGINT (Ctrl+C)

This commit is contained in:
Christos Falas 2025-01-26 17:26:39 +00:00
parent 4658f3d9f5
commit 99ea06bc91
No known key found for this signature in database
3 changed files with 38 additions and 24 deletions

View File

@ -5,7 +5,7 @@ from . import cli
logging.basicConfig( logging.basicConfig(
level=logging.INFO, level=logging.INFO,
format="%(asctime)s %(name)-40s %(levelname)-8s %(message)s", format="%(asctime)s %(name)-50s %(levelname)-8s %(message)s",
) )
if __name__ == "__main__": if __name__ == "__main__":

View File

@ -5,10 +5,11 @@ import numpy as np
import numpy.typing as npt import numpy.typing as npt
import typer import typer
from . import config, visualise from .. import config, visualise
from .collection import ingest from ..collection import ingest
from .processing.aoa import AoA from ..processing.aoa import AoA
from .processing.preprocess import Preprocessor from ..processing.preprocess import Preprocessor
from . import file
app = typer.Typer() app = typer.Typer()
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -23,7 +24,7 @@ def antennas() -> None:
print the antenna identifier. When you are done, press Ctrl+C to stop the script and print the antenna identifier. When you are done, press Ctrl+C to stop the script and
get the final order. get the final order.
""" """
from .utils import antenna_order from ..utils import antenna_order
antenna_order.main() antenna_order.main()
@ -32,7 +33,8 @@ def antennas() -> None:
def heatmap() -> None: def heatmap() -> None:
preprocessor = Preprocessor() preprocessor = Preprocessor()
aoa = AoA() aoa = AoA()
webapp_queue: "mp.Queue[AoA]" = mp.Queue(config.SAMPLE_RATE) manager = mp.Manager()
webapp_queue: "mp.Queue[AoA]" = manager.Queue(config.SAMPLE_RATE)
# Start webapp in background process # Start webapp in background process
webapp = mp.Process(target=visualise.start, args=(webapp_queue,)) webapp = mp.Process(target=visualise.start, args=(webapp_queue,))
webapp.start() webapp.start()

View File

@ -6,7 +6,7 @@ import subprocess
import threading import threading
import time import time
from datetime import datetime from datetime import datetime
from typing import Callable, NamedTuple, NoReturn from typing import Callable, NamedTuple
import numpy as np import numpy as np
import numpy.typing as npt import numpy.typing as npt
@ -25,6 +25,7 @@ class FeitHost:
self.logger = logging.getLogger( self.logger = logging.getLogger(
f"{__name__}.{self.__class__.__name__}-{self.host[0]}" f"{__name__}.{self.__class__.__name__}-{self.host[0]}"
) )
self.active = True
self.checker = threading.Thread(target=self.check_continuous) self.checker = threading.Thread(target=self.check_continuous)
self.checker.start() self.checker.start()
@ -44,7 +45,7 @@ class FeitHost:
self.server.send(self.command.encode()) self.server.send(self.command.encode())
self.logger.info(f"Connected to {self.host}") self.logger.info(f"Connected to {self.host}")
def check_continuous(self) -> NoReturn: def check_continuous(self) -> None:
""" """
Repeatedly check if the FeitCSI service is running Repeatedly check if the FeitCSI service is running
@ -53,7 +54,7 @@ class FeitHost:
and logs continuously if the service is running. and logs continuously if the service is running.
""" """
last_status = False last_status = False
while True: while self.active:
if not self.check_connection(): if not self.check_connection():
self.logger.error(f"FeitCSI is not running on {self.host[0]}") self.logger.error(f"FeitCSI is not running on {self.host[0]}")
last_status = False last_status = False
@ -62,6 +63,7 @@ class FeitHost:
self.connect() self.connect()
last_status = True last_status = True
time.sleep(1) time.sleep(1)
self.logger.info("Stopping host checker")
class FeitTransmitter(FeitHost): class FeitTransmitter(FeitHost):
@ -86,10 +88,10 @@ class FeitReceiver(FeitHost):
) )
super().__init__(host, command) super().__init__(host, command)
def listen(self, queue: "mp.Queue[CSI]") -> NoReturn: def listen(self, queue: "mp.Queue[CSI]") -> None:
prev_time = datetime.now() prev_time = datetime.now()
self.logger.info("Listening for CSI data") self.logger.info("Listening for CSI data")
while True: while self.active:
while not hasattr(self, "server"): while not hasattr(self, "server"):
time.sleep(0.1) time.sleep(0.1)
# This is the max size of a UDP packet. The size of the actual CSI # This is the max size of a UDP packet. The size of the actual CSI
@ -105,6 +107,7 @@ class FeitReceiver(FeitHost):
queue.put(csidata) queue.put(csidata)
except struct.error: except struct.error:
self.logger.error("Failed to parse CSI data") self.logger.error("Failed to parse CSI data")
self.logger.info("Stopping CSI receiver")
class CSIProcessor: class CSIProcessor:
@ -117,6 +120,7 @@ class CSIProcessor:
self.logger = logging.getLogger(f"{__name__}.{self.__class__.__name__}") self.logger = logging.getLogger(f"{__name__}.{self.__class__.__name__}")
self.last_processed = datetime.now() self.last_processed = datetime.now()
self.connections = receiver_connections self.connections = receiver_connections
self.active = True
def add_data(self, host: Host, data: CSI) -> None: def add_data(self, host: Host, data: CSI) -> None:
if ( if (
@ -164,16 +168,19 @@ class CSIProcessor:
self, self,
callback: CSICallback | None = None, callback: CSICallback | None = None,
pre_merge_callback: Callable[[dict[Host, CSI]], None] | None = None, pre_merge_callback: Callable[[dict[Host, CSI]], None] | None = None,
) -> NoReturn: ) -> None:
while True: try:
for ip, queue in self.connections.items(): while self.active:
while not queue.empty(): for ip, queue in self.connections.items():
self.add_data(ip, queue.get()) while not queue.empty():
if self.is_ready(): self.add_data(ip, queue.get())
self.process_data(callback, pre_merge_callback=pre_merge_callback) if self.is_ready():
else: self.process_data(callback, pre_merge_callback=pre_merge_callback)
self.logger.debug("Not all data is ready") else:
time.sleep(0.0005) self.logger.debug("Not all data is ready")
time.sleep(0.0005)
except KeyboardInterrupt:
self.logger.info("Exiting CSI processing")
class Receiver(NamedTuple): class Receiver(NamedTuple):
@ -191,7 +198,7 @@ def start_processing(
for ip in config.RECEIVE_HOSTS for ip in config.RECEIVE_HOSTS
] ]
FeitTransmitter() transmitter = FeitTransmitter()
# Start injecting CSI frames # Start injecting CSI frames
processor = CSIProcessor({r.ip: r.queue for r in receivers}) processor = CSIProcessor({r.ip: r.queue for r in receivers})
@ -208,6 +215,11 @@ def start_processing(
) )
processing_thread.start() processing_thread.start()
try: try:
processing_thread.join() while True:
time.sleep(100)
except KeyboardInterrupt: except KeyboardInterrupt:
for r in receivers:
r.receiver.active = False
transmitter.active = False
processor.active = False
return return