Skip to content

Commit

Permalink
Add FrameReceiver controllers and tests
Browse files Browse the repository at this point in the history
Move FrameProccesor controllers to odin_data.py
  • Loading branch information
jsouter committed Aug 29, 2024
1 parent d00e26e commit 29e7c3a
Show file tree
Hide file tree
Showing 10 changed files with 331 additions and 50 deletions.
2 changes: 1 addition & 1 deletion dev/one_node_fp/odin_server.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ adapters = fp, fr, mw
logging = error

[adapter.fr]
module = odin_data.control.frame_receiver_adapter.FrameReceiverAdapter
module = odin_data.control.odin_data_adapter.OdinDataAdapter
endpoints = 127.0.0.1:10000
update_interval = 0.2

Expand Down
2 changes: 1 addition & 1 deletion dev/two_node_fp/odin_server.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ adapters = fp, fr, mw
logging = error

[adapter.fr]
module = odin_data.control.frame_receiver_adapter.FrameReceiverAdapter
module = odin_data.control.odin_data_adapter.OdinDataAdapter
endpoints = 127.0.0.1:10000, 127.0.0.1:10010
update_interval = 0.2

Expand Down
4 changes: 1 addition & 3 deletions src/odin_fastcs/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,7 @@
from fastcs.backends.epics.gui import EpicsGUIOptions
from fastcs.connections.ip_connection import IPConnectionSettings

from odin_fastcs.odin_controller import (
OdinController,
)
from odin_fastcs.odin_controller import OdinController

from . import __version__

Expand Down
5 changes: 0 additions & 5 deletions src/odin_fastcs/frame_receiver.py

This file was deleted.

4 changes: 1 addition & 3 deletions src/odin_fastcs/odin_adapter_controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,7 @@
from fastcs.util import snake_to_pascal

from odin_fastcs.http_connection import HTTPConnection
from odin_fastcs.util import (
OdinParameter,
)
from odin_fastcs.util import OdinParameter

types = {"float": Float(), "int": Int(), "bool": Bool(), "str": String()}

Expand Down
9 changes: 8 additions & 1 deletion src/odin_fastcs/odin_controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,13 @@
from fastcs.datatypes import Bool, Float, Int, String

from odin_fastcs.eiger_fan import EigerFanAdapterController
from odin_fastcs.frame_processor import FrameProcessorAdapterController
from odin_fastcs.http_connection import HTTPConnection
from odin_fastcs.meta_writer import MetaWriterAdapterController
from odin_fastcs.odin_adapter_controller import OdinAdapterController
from odin_fastcs.odin_data import (
FrameProcessorAdapterController,
FrameReceiverAdapterController,
)
from odin_fastcs.util import OdinParameter, create_odin_parameters

types = {"float": Float(), "int": Int(), "bool": Bool(), "str": String()}
Expand Down Expand Up @@ -70,6 +73,10 @@ def _create_adapter_controller(
return FrameProcessorAdapterController(
connection, parameters, f"{self.API_PREFIX}/fp"
)
case "fr":
return FrameReceiverAdapterController(

Check warning on line 77 in src/odin_fastcs/odin_controller.py

View check run for this annotation

Codecov / codecov/patch

src/odin_fastcs/odin_controller.py#L76-L77

Added lines #L76 - L77 were not covered by tests
connection, parameters, f"{self.API_PREFIX}/fr"
)
case "mw":
return MetaWriterAdapterController(
connection, parameters, f"{self.API_PREFIX}/mw"
Expand Down
110 changes: 81 additions & 29 deletions src/odin_fastcs/frame_processor.py → src/odin_fastcs/odin_data.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import logging
import re
from collections.abc import Iterable, Sequence

Expand All @@ -12,27 +13,32 @@
)
from odin_fastcs.util import OdinParameter, partition

UNIQUE_FP_CONFIG = [
"rank",
"number",
"ctrl_endpoint",
"meta_endpoint",
"fr_ready_cnxn",
"fr_release_cnxn",
]

class OdinDataController(OdinAdapterController):
def _remove_metadata_fields_paths(self):
# paths ending in name or description are invalid in Odin's BaseParameterTree
self._parameters, invalid = partition(
self._parameters, lambda p: p.uri[-1] not in ["name", "description"]
)
if invalid:
invalid_names = ["/".join(param.uri) for param in invalid]
logging.warning(f"Removing parameters with invalid names: {invalid_names}")

class FrameProcessorAdapterController(OdinAdapterController):
def _process_parameters(self):
self._remove_metadata_fields_paths()
for parameter in self._parameters:
# Remove duplicate index from uri
parameter.uri = parameter.uri[1:]
# Remove redundant status/config from parameter path
parameter.set_path(parameter.uri[1:])


class OdinDataAdapterController(OdinAdapterController):
"""Sub controller for the frame processor adapter in an odin control server."""

frames_written: AttrR = AttrR(
Int(),
handler=StatusSummaryUpdater([re.compile("FP*"), "HDF"], "frames_written", sum),
)
writing: AttrR = AttrR(
Bool(),
handler=StatusSummaryUpdater([re.compile("FP*"), "HDF"], "writing", any),
)
_unique_config: list[str] = []
_subcontroller_label: str = "OD"
_subcontroller_cls: type[OdinDataController] = OdinDataController

async def initialise(self):
idx_parameters, self._parameters = partition(
Expand All @@ -45,12 +51,14 @@ async def initialise(self):
idx_parameters, lambda p, idx=idx: p.uri[0] == idx
)

adapter_controller = FrameProcessorController(
adapter_controller = self._subcontroller_cls(
self._connection,
fp_parameters,
f"{self._api_prefix}/{idx}",
)
self.register_sub_controller(f"FP{idx}", adapter_controller)
self.register_sub_controller(
f"{self._subcontroller_label}{idx}", adapter_controller
)
await adapter_controller.initialise()

self._create_attributes()
Expand All @@ -62,11 +70,11 @@ def _create_config_fan_attributes(self):
for sub_controller in get_all_sub_controllers(self):
for parameter in sub_controller._parameters:
mode, key = parameter.uri[0], parameter.uri[-1]
if mode == "config" and key not in UNIQUE_FP_CONFIG:
if mode == "config" and key not in self._unique_config:
try:
attr = getattr(sub_controller, parameter.name)
except AttributeError:
print(
logging.warning(

Check warning on line 77 in src/odin_fastcs/odin_data.py

View check run for this annotation

Codecov / codecov/patch

src/odin_fastcs/odin_data.py#L77

Added line #L77 was not covered by tests
f"Controller has parameter {parameter}, "
f"but no corresponding attribute {parameter.name}"
)
Expand All @@ -88,7 +96,37 @@ def _create_config_fan_attributes(self):
)


class FrameProcessorController(OdinAdapterController):
class FrameReceiverController(OdinDataController):
async def initialise(self):
self._process_parameters()

def __decoder_parameter(parameter: OdinParameter):
return "decoder" in parameter.path[:-1]

decoder_parameters, self._parameters = partition(
self._parameters, __decoder_parameter
)
decoder_controller = FrameReceiverDecoderController(
self._connection, decoder_parameters, f"{self._api_prefix}"
)
self.register_sub_controller("DECODER", decoder_controller)
await decoder_controller.initialise()
self._create_attributes()


class FrameReceiverAdapterController(OdinDataAdapterController):
_subcontroller_label = "FR"
_subcontroller_cls = FrameReceiverController


class FrameReceiverDecoderController(OdinAdapterController):
def _process_parameters(self):
for parameter in self._parameters:
# remove redundant status/decoder part from path
parameter.set_path(parameter.uri[2:])


class FrameProcessorController(OdinDataController):
"""Sub controller for a frame processor application."""

async def initialise(self):
Expand All @@ -109,13 +147,6 @@ async def initialise(self):
await self._create_plugin_sub_controllers(plugins)
self._create_attributes()

def _process_parameters(self):
for parameter in self._parameters:
# Remove duplicate index from uri
parameter.uri = parameter.uri[1:]
# Remove redundant status/config from parameter path
parameter.set_path(parameter.uri[1:])

async def _create_plugin_sub_controllers(self, plugins: Sequence[str]):
for plugin in plugins:

Expand All @@ -136,6 +167,27 @@ def __parameter_in_plugin(
await plugin_controller.initialise()


class FrameProcessorAdapterController(OdinDataAdapterController):
frames_written: AttrR = AttrR(
Int(),
handler=StatusSummaryUpdater([re.compile("FP*"), "HDF"], "frames_written", sum),
)
writing: AttrR = AttrR(
Bool(),
handler=StatusSummaryUpdater([re.compile("FP*"), "HDF"], "writing", any),
)
_unique_config = [
"rank",
"number",
"ctrl_endpoint",
"meta_endpoint",
"fr_ready_cnxn",
"fr_release_cnxn",
]
_subcontroller_label = "FP"
_subcontroller_cls = FrameProcessorController


class FrameProcessorPluginController(OdinAdapterController):
"""SubController for a plugin in a frameProcessor application."""

Expand Down
154 changes: 154 additions & 0 deletions tests/input/two_node_fr_response.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
{
"api": {
"value": 0.1,
"writeable": false,
"type": "float"
},
"module": {
"value": "OdinDataAdapter",
"writeable": false,
"type": "str"
},
"endpoints": [
{
"ip_address": {
"value": "127.0.0.1",
"writeable": false,
"type": "str"
},
"port": {
"value": 10000,
"writeable": false,
"type": "int"
}
},
{
"ip_address": {
"value": "127.0.0.1",
"writeable": false,
"type": "str"
},
"port": {
"value": 10010,
"writeable": false,
"type": "int"
}
}
],
"count": {
"value": 2,
"writeable": false,
"type": "int"
},
"update_interval": {
"value": 0.2,
"writeable": false,
"type": "float"
},
"0": {
"status": {
"status": {
"ipc_configured": true,
"decoder_configured": true,
"buffer_manager_configured": true,
"rx_thread_configured": true,
"configuration_complete": true
},
"decoder": {
"name": "DummyUDPFrameDecoder",
"status_get_count": 7,
"packets_received": 0,
"packets_lost": 0,
"packets_dropped": 0
},
"buffers": {
"total": 292,
"empty": 292,
"mapped": 0
},
"frames": {
"timedout": 0,
"received": 0,
"released": 0,
"dropped": 0
},
"timestamp": "2024-08-29T13:56:17.796578",
"error": [],
"connected": true
},
"config": {
"ctrl_endpoint": "tcp://0.0.0.0:10000",
"rx_endpoint": "inproc://rx_channel",
"frame_ready_endpoint": "tcp://127.0.0.1:10001",
"frame_release_endpoint": "tcp://127.0.0.1:10002",
"decoder_path": "/scratch/hqv85942/scratchprojects/fast2/odin-data/prefix//lib",
"decoder_type": "DummyUDP",
"decoder_config": {
"enable_packet_logging": false,
"frame_timeout_ms": 1000,
"udp_packets_per_frame": 359,
"udp_packet_size": 8000
},
"shared_buffer_name": "OdinDataBuffer",
"max_buffer_mem": 840000000,
"rx_type": "udp",
"rx_address": "0.0.0.0",
"rx_ports": "61649",
"rx_recv_buffer_size": 30000000,
"frame_count": 1953718630
}
},
"1": {
"status": {
"status": {
"ipc_configured": true,
"decoder_configured": true,
"buffer_manager_configured": true,
"rx_thread_configured": true,
"configuration_complete": true
},
"decoder": {
"name": "DummyUDPFrameDecoder",
"status_get_count": 7,
"packets_received": 0,
"packets_lost": 0,
"packets_dropped": 0
},
"buffers": {
"total": 292,
"empty": 292,
"mapped": 0
},
"frames": {
"timedout": 0,
"received": 0,
"released": 0,
"dropped": 0
},
"timestamp": "2024-08-29T13:56:17.817041",
"error": [],
"connected": true
},
"config": {
"ctrl_endpoint": "tcp://0.0.0.0:10010",
"rx_endpoint": "inproc://rx_channel",
"frame_ready_endpoint": "tcp://127.0.0.1:10011",
"frame_release_endpoint": "tcp://127.0.0.1:10012",
"decoder_path": "/scratch/hqv85942/scratchprojects/fast2/odin-data/prefix//lib",
"decoder_type": "DummyUDP",
"decoder_config": {
"enable_packet_logging": false,
"frame_timeout_ms": 1000,
"udp_packets_per_frame": 359,
"udp_packet_size": 8000
},
"shared_buffer_name": "OdinDataBuffer",
"max_buffer_mem": 840000000,
"rx_type": "udp",
"rx_address": "0.0.0.0",
"rx_ports": "61650",
"rx_recv_buffer_size": 30000000,
"frame_count": 1953718630
}
}
}
Loading

0 comments on commit 29e7c3a

Please sign in to comment.