From 4a59ef5894bfe3bb676e7efee0bc53183f8b7c97 Mon Sep 17 00:00:00 2001 From: Ajit Kurup Date: Tue, 14 Oct 2025 15:37:46 +0100 Subject: [PATCH 1/6] Updated pvrecipe and config_reader to allow using custom rule configs --- p4pillon/config_reader.py | 14 ++++++++++---- p4pillon/pvrecipe.py | 9 +++++++-- 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/p4pillon/config_reader.py b/p4pillon/config_reader.py index 36e1e9c..ccea459 100644 --- a/p4pillon/config_reader.py +++ b/p4pillon/config_reader.py @@ -116,12 +116,18 @@ def process_config(pvname: str, pvdetails: dict[str, Any]) -> BasePVRecipe: else: pvrecipe = PVScalarRecipe(PVTypes[pvdetails["type"]], pvdetails["description"], initial) - supported_configs = [("read_only", bool), ("calc", dict)] - for config, config_type in supported_configs: - # Process variables in the configuration that are attributes of the pvrecipe class + # Set read only + temp_config = pvdetails.get("read_only") + if temp_config is not None and isinstance(temp_config, bool): + pvrecipe.read_only = temp_config + + # Process configuration in the yaml specific to a supported rule + # and add this to pvrecipe.rule_configs + rule_configs = [("calc", dict), ("cps_write", dict)] + for config, config_type in rule_configs: temp_config = pvdetails.get(config) if temp_config is not None and isinstance(temp_config, config_type): - setattr(pvrecipe, config, temp_config) + pvrecipe.rule_configs[config] = temp_config if "control" in pvdetails: pvrecipe.set_control_limits(**get_field_config(pvdetails, "control")) diff --git a/p4pillon/pvrecipe.py b/p4pillon/pvrecipe.py index 7e4fde4..e8d654e 100644 --- a/p4pillon/pvrecipe.py +++ b/p4pillon/pvrecipe.py @@ -102,6 +102,9 @@ def __post_init__(self): self.construct_settings = {} self.config_settings = {} + # Rule specific configs to be passed to SharedNT + self.rule_configs = {} + self.construct_settings["valtype"] = self.pvtype.value self.construct_settings["extra"] = [("descriptor", "s")] self.config_settings["descriptor"] = self.description @@ -132,8 +135,10 @@ def build_pv( ) kwargs = {} - if hasattr(self, "calc"): - kwargs["calc"] = self.calc + for name,config in self.rule_configs.items(): + kwargs[name] = config + # if hasattr(self, "calc"): + # kwargs["calc"] = self.calc logger.debug(debug_str) From 03613e5878ddc912ac6ed1208dc81b0c9c53399c Mon Sep 17 00:00:00 2001 From: Ajit Kurup Date: Wed, 15 Oct 2025 12:11:49 +0100 Subject: [PATCH 2/6] Added post option to server.put_pv_value --- p4pillon/server/server.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/p4pillon/server/server.py b/p4pillon/server/server.py index d4894d3..999cdd0 100644 --- a/p4pillon/server/server.py +++ b/p4pillon/server/server.py @@ -146,5 +146,10 @@ def put_pv_value(self, pv_name: str, value): """ Put the value to a PV using the server Context member self._ctxt """ - logger.debug("Trying putting value %r to pv %s", value, pv_name) - self._ctxt.put(pv_name, value) + shared_pv = self[pv_name] + if shared_pv: + logger.debug("Trying SharedNT post to pv %s with value %r ", pv_name, value) + shared_pv.post(value) + else: + logger.debug("Trying Context put to pv %s with value %r ", pv_name, value) + self._ctxt.put(pv_name, value) From 6f392f20ff700591ce330cabc9f6628f6319ed88 Mon Sep 17 00:00:00 2001 From: Ajit Kurup Date: Wed, 15 Oct 2025 12:26:32 +0100 Subject: [PATCH 3/6] Fixed linting issue --- p4pillon/pvrecipe.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/p4pillon/pvrecipe.py b/p4pillon/pvrecipe.py index e8d654e..a844fbd 100644 --- a/p4pillon/pvrecipe.py +++ b/p4pillon/pvrecipe.py @@ -135,10 +135,8 @@ def build_pv( ) kwargs = {} - for name,config in self.rule_configs.items(): + for name, config in self.rule_configs.items(): kwargs[name] = config - # if hasattr(self, "calc"): - # kwargs["calc"] = self.calc logger.debug(debug_str) From d7f56ca2a0252e6e2a187e292ad3dd89b47fd10a Mon Sep 17 00:00:00 2001 From: Ajit Kurup Date: Wed, 29 Oct 2025 12:17:45 +0000 Subject: [PATCH 4/6] Bug fix for calc rule --- p4pillon/config_reader.py | 6 +++--- p4pillon/rules/calc_rule.py | 17 ++--------------- 2 files changed, 5 insertions(+), 18 deletions(-) diff --git a/p4pillon/config_reader.py b/p4pillon/config_reader.py index ccea459..f454c5f 100644 --- a/p4pillon/config_reader.py +++ b/p4pillon/config_reader.py @@ -53,9 +53,9 @@ def parse_config(yaml_obj: dict[str, dict[str, Any]], server: Server | None = No pvrecipes[name] = recipe if server is not None: - if hasattr(recipe, "calc"): - recipe.calc["server"] = server - recipe.calc["pv_name"] = name + if "calc" in recipe.rule_configs: + recipe.rule_configs["calc"]["server"] = server + recipe.rule_configs["calc"]["pv_name"] = name server.add_pv(name, recipe) return pvrecipes diff --git a/p4pillon/rules/calc_rule.py b/p4pillon/rules/calc_rule.py index 48d60c1..c43d667 100644 --- a/p4pillon/rules/calc_rule.py +++ b/p4pillon/rules/calc_rule.py @@ -33,26 +33,13 @@ def __init__(self, **kwargs): super().__init__() self._variables = [] self._calc_str: str = "" - if "calc" in kwargs: - self.set_calc(kwargs["calc"]) + self.set_calc(calc=kwargs) name = "calc" nttypes = [SupportedNTTypes.ALL] fields = [] add_automatically = False - # @property - # def name(self) -> str: - # return "calc" - - # @property - # def fields(self) -> None: - # """ - # A return value of None means this rule is not dependent on any fields in the PV and - # will thus always be applicable. - # """ - # return None - class MonitorCB: """ The MonitorCB class is used to provide call back methods for subscribing to Context.monitor @@ -71,7 +58,7 @@ def cb(self, v: Value): See https://epics-base.github.io/p4p/client.html#monitor for further information.""" self._server.put_pv_value(self._pv_name, {}) - def set_calc(self, calc) -> None: + def set_calc(self, calc: dict) -> None: """ Define the calculation to be performed. The required argument calc is a dictionary with the following keys: From 58f89faed0892b95927065e21d47ef235a222934 Mon Sep 17 00:00:00 2001 From: Ajit Kurup Date: Tue, 4 Nov 2025 14:33:27 +0000 Subject: [PATCH 5/6] Fixed rule_configs to remove cps _write tag. --- p4pillon/config_reader.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/p4pillon/config_reader.py b/p4pillon/config_reader.py index f454c5f..ba74761 100644 --- a/p4pillon/config_reader.py +++ b/p4pillon/config_reader.py @@ -14,6 +14,12 @@ logger = logging.getLogger(__name__) +# A list of rule/handler specific configs in the YAML to be passed to a non-standard rule/handler. +# The list contains tuples of a tag name (the string used to identify the parameters for this rule) +# and the parameter type, e.g. dictionary, integer. +# The tag in the YAML must have the same name as the rule for it to be processed +# correctly by SharedNT. +rule_configs = [("calc", dict)] def parse_config_file(filename: str, server: Server | None = None) -> dict[str, BasePVRecipe]: """ @@ -123,7 +129,6 @@ def process_config(pvname: str, pvdetails: dict[str, Any]) -> BasePVRecipe: # Process configuration in the yaml specific to a supported rule # and add this to pvrecipe.rule_configs - rule_configs = [("calc", dict), ("cps_write", dict)] for config, config_type in rule_configs: temp_config = pvdetails.get(config) if temp_config is not None and isinstance(temp_config, config_type): From 590d43c6913338b30d6d25b5ebb3ec4ad1054441 Mon Sep 17 00:00:00 2001 From: Ajit Kurup Date: Tue, 4 Nov 2025 18:46:32 +0000 Subject: [PATCH 6/6] Fixed linting. --- p4pillon/config_reader.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/p4pillon/config_reader.py b/p4pillon/config_reader.py index ba74761..7e2d6ea 100644 --- a/p4pillon/config_reader.py +++ b/p4pillon/config_reader.py @@ -18,9 +18,10 @@ # The list contains tuples of a tag name (the string used to identify the parameters for this rule) # and the parameter type, e.g. dictionary, integer. # The tag in the YAML must have the same name as the rule for it to be processed -# correctly by SharedNT. +# correctly by SharedNT. rule_configs = [("calc", dict)] + def parse_config_file(filename: str, server: Server | None = None) -> dict[str, BasePVRecipe]: """ Parse a yaml file and return a dictionary of PVScalarRecipe objects.