Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions pcaspy-template-generator/project-name/py_project_name/csdev.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
"""PVs definition for the IOC."""

from siriuspy import csdev as _csdev


class Const(_csdev.Const):
"""Const class."""
_register = _csdev.Const.register

DisconnConn = _register("DisconnConn", _csdev.ETypes.DISCONN_CONN)


pvs_database = {

'Version-Cte': {'type': 'str', 'value': 'UNDEF'},
'TimestampBoot-Cte': {
'type': 'float', 'value': 0,
'prec': 7, 'unit': 'timestamp'},
'TimestampUpdate-Mon': {
'type': 'float', 'value': 0,
'prec': 7, 'unit': 'timestamp'},
'Log-Mon': {'type': 'str', 'value': 'Starting...'},
'ConnStatus-Mon': {
'type': 'enum', 'value': Const.DisconnConn.Disconnected,
'enums': _csdev.ETypes.DISCONN_CONN,
'unit': 'DisconnConn',
},

}
85 changes: 63 additions & 22 deletions pcaspy-template-generator/project-name/py_project_name/main.py
Original file line number Diff line number Diff line change
@@ -1,50 +1,91 @@
"""Main Module of the IOC Logic."""

import pvs as _pvs
import logging as _log
import time as _time

__version__ = _pvs.__version__
from siriuspy import epics as _epics
from siriuspy.callbacks import Callback as _Callback
from siriuspy.devices import DeviceSet as _DeviceSet

from . import csdev as _csdev

class App:
"""Main Class of the IOC Logic."""

pvs_database = _pvs.pvs_database
class App(_DeviceSet, _Callback):
"""Main Class of the IOC Logic."""

def get_database(self):
"""Get the database."""
db = dict()
for pre, pvs in self.pvs_database.items():
for pvname, info in pvs.items():
db[pre + pvname] = info
return db
SCAN_FREQUENCY = 1 # [Hz]

def __init__(self, driver=None):
"""Initialize the instance."""
self._driver = driver
_Callback.__init__(self)

@property
def driver(self):
"""Set the driver of the App."""
return self._driver
self.driver = driver
devs = tuple()
_DeviceSet.__init__(self, devices=devs)

@driver.setter
def driver(self, driver):
self._driver = driver
self._pvs_database = _csdev.pvs_database

# status scanning
self.quit = False
self.scanning = False
self.thread_check_conns = _epics.CAThread(
target=self._run_updates, daemon=True)
self.thread_check_conns.start()

def init_database(self):
"""Set initial PV values."""
pvn2vals = {
'TimestampUpdate-Mon': _time.time(),
'Log-Mon': 'Started.',
}
for pvn, val in pvn2vals.items():
self.run_callbacks(pvn, val)

@property
def pvs_database(self):
"""Return pvs_database."""
return self._pvs_database

def process(self, interval):
"""Trigger connection to external PVs in other classes."""
"""Sleep."""
_time.sleep(interval)

def read(self, reason):
"""Read PV from database."""
# implementation here
# The default behavior is to return None and let the driver read
# from the database.
return None
value = None
return value

def write(self, reason, value):
"""Write PV in the model."""
# implementation here
# this should be used in case PV state change.
return True # return True for successful write and False otherwise.

def _run_updates(self):
# scan
tplanned = 1.0 / App.SCAN_FREQUENCY
while not self.quit:
if not self.scanning:
_time.sleep(tplanned)
continue

_t0 = _time.time()

# update sections status
self.run_callbacks('TimestampUpdate-Mon', _time.time())
self.run_callbacks('ConnStatus-Mon', self.connected)

# time mgmnt
ttook = _time.time() - _t0
tsleep = tplanned - ttook
if tsleep > 0:
_time.sleep(tsleep)
else:
logstr = (
'Connections check took more than planned... '
'{0:.3f}/{1:.3f} s'.format(ttook, tplanned)
)
_log.warning(logstr)
14 changes: 0 additions & 14 deletions pcaspy-template-generator/project-name/py_project_name/pvs.py

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,28 +1,53 @@
#!/usr/bin/env python-sirius
"""."""

import logging as _log
import os as _os
import signal as _signal
import sys as _sys
import time as _time

import pcaspy as _pcaspy
import pcaspy.tools as _pcaspy_tools
import signal as _signal
import main as _main
from siriuspy import util as _util
from siriuspy.envars import VACA_PREFIX as _VACA_PREFIX

from .main import App as _App

INTERVAL = 0.1
stop_event = False
PREFIX = ''
STOP_EVENT = False

IOC_PREFIX = 'AS-Glob:AP-DEVICE:'
IOC_NAME = 'AS-AP-DEVICE'


def _stop_now(signum, frame):
print(' - SIGNAL received.')
global stop_event
stop_event = True
_ = frame
sname = _signal.Signals(signum).name
tstamp = _util.get_timestamp()
strf = f'{sname} received at {tstamp}'
_log.warning(strf)
_sys.stdout.flush()
_sys.stderr.flush()
global STOP_EVENT
STOP_EVENT = True


def _attribute_access_security_group(server, dbase):
for k, val in dbase.items():
if k.endswith(('-RB', '-Sts', '-Cte', '-Mon')):
val.update({'asg': 'rbpv'})
path_ = _os.path.abspath(_os.path.dirname(__file__))
server.initAccessSecurityFile(path_ + '/access_rules.as')


class _PCASDriver(_pcaspy.Driver):

def __init__(self, app=None):
def __init__(self, app):
super().__init__()
self.app = app or _main.App()
self.app = app
self.app.driver = self
self.app.add_callback(self.update_pv)

def read(self, reason):
value = self.app.read(reason)
Expand All @@ -32,11 +57,18 @@ def read(self, reason):
return value

def write(self, reason, value):
app_ret = self.app.write(reason, value)
if app_ret:
self.setParam(reason, value)
self.updatePVs()
return app_ret
ret_val = self.app.write(reason, value)
if reason.endswith('-Cmd'):
value = self.getParam(reason) + 1
if ret_val:
return super().write(reason, value)
return False

def update_pv(self, pvname, value, **kwargs):
"""Update PV."""
_ = kwargs
self.setParam(pvname, value)
self.updatePV(pvname)


def run():
Expand All @@ -45,32 +77,50 @@ def run():
_signal.signal(_signal.SIGINT, _stop_now)
_signal.signal(_signal.SIGTERM, _stop_now)

# create the application model
app = _main.App()

db = app.get_database()
# configure log file
_util.configure_log_file()

# define IOC, init pvs database and create app object
_version = _util.get_last_commit_hash()
_ioc_prefix = _VACA_PREFIX + ('-' if _VACA_PREFIX else '')
_ioc_prefix += IOC_PREFIX
app = _App()
dbase = app.pvs_database
dbase['Version-Cte']['value'] = _version
dbase['TimestampBoot-Cte']['value'] = _time.time()

# check if another IOC is running
pvname = _ioc_prefix + next(iter(dbase))
if _util.check_pv_online(pvname, use_prefix=False):
raise ValueError('Another instance of this IOC is already running!')

# check if another IOC is running
_util.print_ioc_banner(
ioc_name=IOC_NAME,
db=dbase,
description=IOC_NAME + ' Soft IOC',
version=_version,
prefix=_ioc_prefix)

# create a new simple pcaspy server and driver to respond client's requests
server = _pcaspy.SimpleServer()
server.createPV(PREFIX, db)

# create the driver
pcas_driver = _PCASDriver(app)
_attribute_access_security_group(server, dbase)
server.createPV(_ioc_prefix, dbase)
driver = _PCASDriver(app)
app.init_database()

# initiate a new thread responsible for listening for client connections
server_thread = _pcaspy_tools.ServerThread(server)
server_thread.start()

# main loop
# while not stop_event.is_set():
while not stop_event:
pcas_driver.app.process(INTERVAL)
driver.app.scanning = True
while not STOP_EVENT:
driver.app.process(INTERVAL)

print('exiting...')
# send stop signal to server thread
driver.app.scanning = False
driver.app.quit = True

# sends stop signal to server thread
server_thread.stop()
server_thread.join()


if __name__ == '__main__':
run()