epicsdev 2.0.1__tar.gz → 2.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: epicsdev
3
- Version: 2.0.1
3
+ Version: 2.1.0
4
4
  Summary: Helper module for creating EPICS PVAccess servers using p4p
5
5
  Project-URL: Homepage, https://github.com/ASukhanov/epicsdev
6
6
  Project-URL: Bug Tracker, https://github.com/ASukhanov/epicsdev
@@ -1,7 +1,10 @@
1
- """Pypet page for epicdev.multiadc module"""
2
- # format: pypeto 1.2+
3
- __version__ = 'v0.0.1 2026-01-23'#
4
- print(f'epicsScope {__version__}')
1
+ """Pypet page for epicdev.epicsdev.
2
+ Device instance is configured via environment variable EPICSDEV,
3
+ default instance is epicsdev0:."""
4
+ # pylint: disable=invalid-name
5
+ __version__ = 'v0.1.0 2026-01-31'#
6
+
7
+ import os
5
8
 
6
9
  #``````````````````Definitions````````````````````````````````````````````````
7
10
  # python expressions and functions, used in the spreadsheet
@@ -18,28 +21,27 @@ LargeFont = {'color':'light gray', **font(18), 'fgColor':'dark green'}
18
21
  ButtonFont = {'font':['Open Sans Extrabold',14]}# Comic Sans MS
19
22
  LYRow = {'ATTRIBUTES':{'color':'light yellow'}}
20
23
  lColor = color('lightGreen')
21
-
22
- # definition for plotting cell
23
24
  PyPath = 'python -m'
24
- PaneP2P = ' '.join([f'c{i+1:02d}Mean c{i+1:02d}Peak2Peak' for i in range(1)])
25
- PaneWF = ' '.join([f'c{i+1:02d}Waveform' for i in range(1)])
26
- #PaneT = 'timing[1] timing[3]'
27
- Plot = {'Plot':{'launch':
28
- f'{PyPath} pvplot Y-5:5 -aV:multiadc0: -#0"{PaneP2P}" -#1"{PaneWF}"',# -#2"{PaneT}"',
29
- **lColor, **ButtonFont}}
30
- print(f'Plot command: {Plot}')
25
+
26
+ try:
27
+ Instance = f"epicsDev{os.environ['EPICSDEV']}:"
28
+ except KeyError:
29
+ Instance = 'epicsDev0:'
30
+
31
31
  #``````````````````PyPage Object``````````````````````````````````````````````
32
32
  class PyPage():
33
- def __init__(self, instance='multiadc0:',
34
- title="Simulated oscilloscope", channels=6):
33
+ def __init__(self, instance=None,
34
+ title="epicsdev", channels=1):
35
35
  """instance: unique name of the page.
36
36
  For EPICS it is usually device prefix
37
37
  """
38
+ if instance is None:
39
+ instance = Instance
38
40
  print(f'Instantiating Page {instance,title} with {channels} channels')
39
41
 
40
42
  #``````````Mandatory class members starts here````````````````````````
41
43
  self.namespace = 'PVA'
42
- self.title = title
44
+ self.title = instance[:-1]
43
45
 
44
46
  #``````````Page attributes, optional`````````````````````````
45
47
  self.page = {**color(240,240,240)}
@@ -70,18 +72,22 @@ string or device:parameter and the value is dictionary of the features.
70
72
  #``````````Abbreviations, used in cell definitions
71
73
  def ChLine(suffix):
72
74
  return [f'{D}c{ch+1:02d}{suffix}' for ch in range(channels)]
73
- #FOption = ' -file '+logreqMap.get(D,'')
75
+ PaneP2P = ' '.join([f'c{i+1:02d}Mean c{i+1:02d}Peak2Peak' for i in range(channels)])
76
+ PaneWF = ' '.join([f'c{i+1:02d}Waveform' for i in range(channels)])
77
+ #PaneT = 'timing[1] timing[3]'
78
+ Plot = {'Plot':{'launch':
79
+ f'{PyPath} pvplot Y-5:5 -aV:{instance} -#0"{PaneP2P}" -#1"{PaneWF}"',# -#2"{PaneT}"',
80
+ **lColor, **ButtonFont}}
81
+ print(f'Plot command: {Plot}')
74
82
  #``````````mandatory member```````````````````````````````````````````
75
83
  self.rows = [
76
- ['Device:', D, {D+'version':span(2,1)},_, 'host:', D+'host',_],
77
- ['State:', D+'server','cycle:', D+'cycle',_,_,Plot], # 'Recall:', D+'setup',],
84
+ ['Device:',D, D+'server', D+'version', 'host:',D+'host',_],
78
85
  ['Status:', {D+'status': span(8,1)}],
79
- ['Polling Interval:', D+'polling', 'nPoints:', D+'recordLength',
80
- 'Noise:', D+'noiseLevel',_],
86
+ ['Cycle time:',D+'cycleTime', 'Sleep:',D+'sleep', 'Cycle:',D+'cycle', Plot],
87
+ ['nPoints:',D+'recordLength','Noise:',D+'noiseLevel',_,_,_],
81
88
  [{'ATTRIBUTES':{**color('lightCyan'),**just(1)}},
82
- 'Channels:','CH1','CH2','CH3','CH4','CH5','CH6'],
89
+ 'Channels:', 'CH1', 'CH2', 'CH3', 'CH4', 'CH5', 'CH6'],
83
90
  ['V/div:']+ChLine('VoltsPerDiv'),
84
91
  ['Mean:']+ChLine('Mean'),
85
92
  ['Peak2Peak:']+ChLine('Peak2Peak'),
86
- #['Waveform:']+ChLine('Waveform'),
87
93
  ]
@@ -0,0 +1,6 @@
1
+ """Pypet definition for device multiadc1"""
2
+ import multiadc_pp as module
3
+
4
+ def PyPage(**_):
5
+ return module.PyPage(instance='multiadc1:', title='multiadc1',
6
+ channels=6)
@@ -1,7 +1,10 @@
1
- """Pypet page for epicdev.epicsdev module"""
2
- # format: pypeto 1.2+
3
- __version__ = 'v0.0.1 2026-01-16'#
4
- print(f'epicsScope {__version__}')
1
+ """Pypet page for epicdev.multiadc, simulated multi-channel ADC device server.
2
+ Device instance is configured via environment variable MULTIADC,
3
+ default instance is multiadc0:."""
4
+ # pylint: disable=invalid-name
5
+ __version__ = 'v0.1.0 2026-01-31'#
6
+
7
+ import os
5
8
 
6
9
  #``````````````````Definitions````````````````````````````````````````````````
7
10
  # python expressions and functions, used in the spreadsheet
@@ -18,28 +21,27 @@ LargeFont = {'color':'light gray', **font(18), 'fgColor':'dark green'}
18
21
  ButtonFont = {'font':['Open Sans Extrabold',14]}# Comic Sans MS
19
22
  LYRow = {'ATTRIBUTES':{'color':'light yellow'}}
20
23
  lColor = color('lightGreen')
21
-
22
- # definition for plotting cell
23
24
  PyPath = 'python -m'
24
- PaneP2P = ' '.join([f'ch{i+1:01d}Mean ch{i+1:01d}Peak2Peak' for i in range(1)])
25
- PaneWF = ' '.join([f'ch{i+1:01d}Waveform' for i in range(1)])
26
- #PaneT = 'timing[1] timing[3]'
27
- Plot = {'Plot':{'launch':
28
- f'{PyPath} pvplot Y-5:5 -aV:epicsDev0: -#0"{PaneP2P}" -#1"{PaneWF}"',# -#2"{PaneT}"',
29
- **lColor, **ButtonFont}}
30
- print(f'Plot command: {Plot}')
31
- #``````````````````PyPage Object``````````````````````````````````````````````
25
+
26
+ try:
27
+ Instance = f"multiadc{os.environ['EPICSDEV_MULTIADC']}:"
28
+ except KeyError:
29
+ Instance = 'multiadc0:'
30
+
31
+ #``````````````````Mandatory object PyPage````````````````````````````````````
32
32
  class PyPage():
33
- def __init__(self, instance='epicsDev0:',
34
- title="Simulated oscilloscope", channels=1):
33
+ def __init__(self, instance=None,
34
+ title=None, channels=6):
35
35
  """instance: unique name of the page.
36
36
  For EPICS it is usually device prefix
37
37
  """
38
+ if instance is None:
39
+ instance = Instance
38
40
  print(f'Instantiating Page {instance,title} with {channels} channels')
39
41
 
40
42
  #``````````Mandatory class members starts here````````````````````````
41
43
  self.namespace = 'PVA'
42
- self.title = title
44
+ self.title = title if title is not None else instance[:-1]
43
45
 
44
46
  #``````````Page attributes, optional`````````````````````````
45
47
  self.page = {**color(240,240,240)}
@@ -69,18 +71,24 @@ string or device:parameter and the value is dictionary of the features.
69
71
 
70
72
  #``````````Abbreviations, used in cell definitions
71
73
  def ChLine(suffix):
72
- return [f'{D}ch{ch+1:01d}{suffix}' for ch in range(channels)]
73
- #FOption = ' -file '+logreqMap.get(D,'')
74
+ return [f'{D}c{ch+1:02d}{suffix}' for ch in range(channels)]
75
+ PaneP2P = ' '.join([f'c{i+1:02d}Mean c{i+1:02d}Peak2Peak' for i in range(channels)])
76
+ PaneWF = ' '.join([f'c{i+1:02d}Waveform' for i in range(channels)])
77
+ #PaneT = 'timing[1] timing[3]'
78
+ Plot = {'Plot':{'launch':
79
+ f'{PyPath} pvplot Y-5:5 -aV:{instance} -#0"{PaneP2P}" -#1"{PaneWF}"',# -#2"{PaneT}"',
80
+ **lColor, **ButtonFont}}
81
+ print(f'Plot command: {Plot}')
74
82
  #``````````mandatory member```````````````````````````````````````````
75
83
  self.rows = [
76
- ['Device:', D, {D+'version':span(2,1)},_, 'host:', D+'host',_],
77
- ['State:', D+'server', 'cycle:', D+'cycle',_,_, Plot], # 'Recall:', D+'setup',],
84
+ ['Device:',D, D+'server', D+'version', 'host:',D+'host',_],
78
85
  ['Status:', {D+'status': span(8,1)}],
79
- ['Polling Interval:', D+'polling', 'nPoints:', D+'recordLength',
80
- 'Noise:', D+'noiseLevel',_],
86
+ ['Cycle time:',D+'cycleTime', 'Sleep:',D+'sleep', 'Cycle:',D+'cycle', Plot],
87
+ ['nPoints:',D+'recordLength','Noise:',D+'noiseLevel', 'Channels:',D+'channels',_],
81
88
  [{'ATTRIBUTES':{**color('lightCyan'),**just(1)}},
82
- 'Channels:', 'CH1', 'CH2', 'CH3', 'CH4', 'CH5', 'CH6'],
89
+ 'Channels:','CH1','CH2','CH3','CH4','CH5','CH6'],
83
90
  ['V/div:']+ChLine('VoltsPerDiv'),
84
91
  ['Mean:']+ChLine('Mean'),
85
92
  ['Peak2Peak:']+ChLine('Peak2Peak'),
93
+ #['Waveform:']+ChLine('Waveform'),
86
94
  ]
@@ -1,12 +1,13 @@
1
1
  """Skeleton and helper functions for creating EPICS PVAccess server"""
2
2
  # pylint: disable=invalid-name
3
- __version__= 'v2.0.1 26-01-30'# added mandatory host PV
3
+ __version__= 'v2.1.0 26-01-31'# polling renamed to sleep. Sleep function added.
4
4
  #TODO add mandatory PV: host, to identify the server host.
5
5
  #Issue: There is no way in PVAccess to specify if string PV is writable.
6
6
  # As a workaround we append description with suffix ' Features: W' to indicate that.
7
7
 
8
8
  import sys
9
- from time import time, sleep, strftime, perf_counter as timer
9
+ import time
10
+ from time import perf_counter as timer
10
11
  import os
11
12
  from socket import gethostname
12
13
  from p4p.nt import NTScalar, NTEnum
@@ -15,6 +16,8 @@ from p4p.server import Server
15
16
  from p4p.server.thread import SharedPV
16
17
  from p4p.client.thread import Context
17
18
 
19
+ PeriodicUpdateInterval = 10. # seconds
20
+
18
21
  #``````````````````Module Storage`````````````````````````````````````````````
19
22
  def _serverStateChanged(newState:str):
20
23
  """Dummy serverStateChanged function"""
@@ -28,6 +31,10 @@ class C_():
28
31
  PVs = {}
29
32
  PVDefs = []
30
33
  serverStateChanged = _serverStateChanged
34
+ lastCycleTime = time.time()
35
+ lastUpdateTime = 0.
36
+ cycleTimeSum = 0.
37
+ cyclesAfterUpdate = 0
31
38
 
32
39
  #```````````````````Helper methods````````````````````````````````````````````
33
40
  def serverState():
@@ -35,7 +42,7 @@ def serverState():
35
42
  cached in C_ to avoid unnecessary get() calls."""
36
43
  return C_.serverState
37
44
  def _printTime():
38
- return strftime("%m%d:%H%M%S")
45
+ return time.strftime("%m%d:%H%M%S")
39
46
  def printi(msg):
40
47
  """Print info message and publish it to status PV."""
41
48
  print(f'inf_@{_printTime()}: {msg}')
@@ -81,7 +88,7 @@ def publish(pvName:str, value, ifChanged=False, t=None):
81
88
  print(f'WARNING: PV {pvName} not found. Cannot publish value.')
82
89
  return
83
90
  if t is None:
84
- t = time()
91
+ t = time.time()
85
92
  if not ifChanged or pv.current() != value:
86
93
  pv.post(value, timestamp=t)
87
94
 
@@ -127,7 +134,7 @@ def SPV(initial, meta='', vtype=None):
127
134
 
128
135
  #``````````````````create_PVs()```````````````````````````````````````````````
129
136
  def _create_PVs(pvDefs):
130
- ts = time()
137
+ ts = time.time()
131
138
  for defs in pvDefs:
132
139
  try:
133
140
  pname,desc,spv,extra = defs
@@ -174,7 +181,7 @@ def _create_PVs(pvDefs):
174
181
  if spv.writable:
175
182
  @spv.put
176
183
  def handle(spv, op):
177
- ct = time()
184
+ ct = time.time()
178
185
  vv = op.value()
179
186
  vr = vv.raw.value
180
187
  current = spv._wrap(spv.current())
@@ -259,8 +266,12 @@ def create_PVs(pvDefs=None):
259
266
  {'setter':set_server}],
260
267
  ['verbose', 'Debugging verbosity', SPV(C_.verbose,'W','u8'),
261
268
  {'setter':set_verbose, LL:0,LH:3}],
262
- ['polling', 'Polling interval', SPV(1.0,'W'), {U:'S', LL:0.001, LH:10.1}],
263
- ['cycle', 'Cycle number', SPV(0,'','u32'), {}],
269
+ ['sleep', 'Pause in the main loop, it could be useful for throttling the data output',
270
+ SPV(1.0,'W'), {U:'S', LL:0.001, LH:10.1}],
271
+ ['cycle', 'Cycle number, published every {PeriodicUpdateInterval} S.',
272
+ SPV(0,'','u32'), {}],
273
+ ['cycleTime','Average cycle time including sleep, published every {PeriodicUpdateInterval} S',
274
+ SPV(0.), {U:'S'}],
264
275
  ]
265
276
  # append application's PVs, defined in the pvDefs and create map of
266
277
  # providers
@@ -301,7 +312,8 @@ def init_epicsdev(prefix:str, pvDefs:list, verbose=0,
301
312
  host = repr(get_externalPV(prefix+'host')).replace("'",'')
302
313
  print(f'ERROR: Server for {prefix} already running at {host}. Exiting.')
303
314
  sys.exit(1)
304
- except TimeoutError: pass
315
+ except TimeoutError:
316
+ pass
305
317
 
306
318
  # No existing server found. Creating PVs.
307
319
  pvs = create_PVs(pvDefs)
@@ -315,8 +327,28 @@ def init_epicsdev(prefix:str, pvDefs:list, verbose=0,
315
327
  with open(filepath, 'w', encoding="utf-8") as f:
316
328
  for _pvname in pvs:
317
329
  f.write(_pvname + '\n')
330
+ printi(f'Hosting {len(pvs)} PVs')
318
331
  return pvs
319
332
 
333
+ def sleep():
334
+ """Sleep function to be called in the main loop. It updates cycleTime PV
335
+ and sleeps for the time specified in sleep PV."""
336
+ tnow = time.time()
337
+ C_.cycleTimeSum += tnow - C_.lastCycleTime
338
+ C_.lastCycleTime = tnow
339
+ C_.cyclesAfterUpdate += 1
340
+ C_.cycle += 1
341
+ printv(f'cycle {C_.cycle}')
342
+ if tnow - C_.lastUpdateTime > PeriodicUpdateInterval:
343
+ avgCycleTime = C_.cycleTimeSum / C_.cyclesAfterUpdate
344
+ printv(f'Average cycle time: {avgCycleTime:.6f} S.')
345
+ publish('cycle', C_.cycle)
346
+ publish('cycleTime', avgCycleTime)
347
+ C_.lastUpdateTime = tnow
348
+ C_.cycleTimeSum = 0.
349
+ C_.cyclesAfterUpdate = 0
350
+ time.sleep(pvv('sleep'))
351
+
320
352
  #``````````````````Demo````````````````````````````````````````````````````````
321
353
  if __name__ == "__main__":
322
354
  import numpy as np
@@ -331,11 +363,11 @@ if __name__ == "__main__":
331
363
  ['tAxis', 'Full scale of horizontal axis', SPV([0.]), {U:'S'}],
332
364
  ['recordLength','Max number of points', SPV(100,'W','u32'),
333
365
  {LL:4,LH:1000000, SET:set_recordLength}],
334
- ['ch1Offset', 'Offset', SPV(0.,'W'), {U:'du'}],
335
- ['ch1VoltsPerDiv', 'Vertical scale', SPV(1E-3,'W'), {U:'V/du'}],
336
- ['ch1Waveform', 'Waveform array', SPV([0.]), {U:'du'}],
337
- ['ch1Mean', 'Mean of the waveform', SPV(0.,'A'), {U:'du'}],
338
- ['ch1Peak2Peak','Peak-to-peak amplitude', SPV(0.,'A'), {U:'du',**alarm}],
366
+ ['c01Offset', 'Offset', SPV(0.,'W'), {U:'du'}],
367
+ ['c01VoltsPerDiv', 'Vertical scale', SPV(1E-3,'W'), {U:'V/du'}],
368
+ ['c01Waveform', 'Waveform array', SPV([0.]), {U:'du'}],
369
+ ['c01Mean', 'Mean of the waveform', SPV(0.,'A'), {U:'du'}],
370
+ ['c01Peak2Peak','Peak-to-peak amplitude', SPV(0.,'A'), {U:'du',**alarm}],
339
371
  ['alarm', 'PV with alarm', SPV(0,'WA'), {U:'du',**alarm}],
340
372
  ]
341
373
  nPatterns = 100 # number of waveform patterns.
@@ -363,23 +395,20 @@ if __name__ == "__main__":
363
395
  publish('noiseLevel', level)
364
396
 
365
397
  def init(recordLength):
366
- """Testing function. Do not use in production code."""
398
+ """Example of device initialization function"""
367
399
  set_recordLength(recordLength)
368
400
  #set_noise(pvv('noiseLevel')) # already called from set_recordLength
369
401
 
370
402
  def poll():
371
- """Example of polling function"""
403
+ """Example of polling function. Called every cycle when server is running."""
372
404
  #pattern = C_.cycle % nPatterns# produces sliding
373
405
  pattern = rng.integers(0, nPatterns)
374
- cycle = pvv('cycle')
375
- printv(f'cycle {repr(cycle)}')
376
- publish('cycle', cycle + 1)
377
406
  wf = pargs.noise[pattern:pattern+pvv('recordLength')].copy()
378
- wf /= pvv('ch1VoltsPerDiv')
379
- wf += pvv('ch1Offset')
380
- publish('ch1Waveform', wf)
381
- publish('ch1Peak2Peak', np.ptp(wf))
382
- publish('ch1Mean', np.mean(wf))
407
+ wf /= pvv('c01VoltsPerDiv')
408
+ wf += pvv('c01Offset')
409
+ publish('c01Waveform', wf)
410
+ publish('c01Peak2Peak', np.ptp(wf))
411
+ publish('c01Mean', np.mean(wf))
383
412
 
384
413
  # Argument parsing
385
414
  parser = argparse.ArgumentParser(description = __doc__,
@@ -389,7 +418,7 @@ if __name__ == "__main__":
389
418
  'Device name, the PV name will be <device><index>:')
390
419
  parser.add_argument('-i', '--index', default='0', help=
391
420
  'Device index, the PV name will be <device><index>:')
392
- parser.add_argument('-l', '--list', default='', nargs='?', help=(
421
+ parser.add_argument('-l', '--list', nargs='?', help=(
393
422
  'Directory to save list of all generated PVs, if no directory is given, '
394
423
  'then </tmp/pvlist/><prefix> is assumed.'))
395
424
  # The rest of options are not essential, they can be controlled at runtime using PVs.
@@ -413,12 +442,12 @@ if __name__ == "__main__":
413
442
 
414
443
  # Main loop
415
444
  server = Server(providers=[PVs])
416
- printi(f'Server started with polling interval {repr(pvv("polling"))} S.')
445
+ printi(f'Server started. Sleeping per cycle: {repr(pvv("sleep"))} S.')
417
446
  while True:
418
447
  state = serverState()
419
448
  if state.startswith('Exit'):
420
449
  break
421
450
  if not state.startswith('Stop'):
422
451
  poll()
423
- sleep(pvv("polling"))
452
+ sleep()
424
453
  printi('Server is exited')
@@ -1,6 +1,6 @@
1
1
  """Simulated multi-channel ADC device server using epicsdev module."""
2
2
  # pylint: disable=invalid-name
3
- __version__= 'v0.0.2 26-01-23'# refactored, adjusted for epicdev 2.0.1
3
+ __version__= 'v2.1.0 26-01-31'# updated for epicsdev v2.1.0
4
4
 
5
5
  import sys
6
6
  import time
@@ -9,7 +9,7 @@ import numpy as np
9
9
  import argparse
10
10
 
11
11
  from .epicsdev import Server, Context, init_epicsdev, serverState, publish
12
- from .epicsdev import pvv, printi, printv, SPV, set_server
12
+ from .epicsdev import pvv, printi, printv, SPV, set_server, sleep
13
13
 
14
14
 
15
15
  def myPVDefs():
@@ -17,6 +17,7 @@ def myPVDefs():
17
17
  SET,U,LL,LH = 'setter','units','limitLow','limitHigh'
18
18
  alarm = {'valueAlarm':{'lowAlarmLimit':-9., 'highAlarmLimit':9.}}
19
19
  pvDefs = [ # device-specific PVs
20
+ ['channels', 'Number of device channels', SPV(pargs.channels), {}],
20
21
  ['externalControl', 'Name of external PV, which controls the server',
21
22
  SPV('Start Stop Clear Exit Started Stopped Exited'.split(), 'WD'), {}],
22
23
  ['noiseLevel', 'Noise amplitude', SPV(1.E-4,'W'), {SET:set_noise, U:'V'}],
@@ -48,7 +49,7 @@ nPatterns = 100 # number of waveform patterns.
48
49
  rng = np.random.default_rng(nPatterns)
49
50
 
50
51
  #``````````````````Setter functions for PVs```````````````````````````````````
51
- def set_recordLength(value):
52
+ def set_recordLength(value, *_):
52
53
  """Record length have changed. The tAxis should be updated accordingly."""
53
54
  printi(f'Setting tAxis to {value}')
54
55
  publish('tAxis', np.arange(value)*1.E-6)
@@ -56,7 +57,7 @@ def set_recordLength(value):
56
57
  # Re-initialize noise array, because its size depends on recordLength
57
58
  set_noise(pvv('noiseLevel'))
58
59
 
59
- def set_noise(level):
60
+ def set_noise(level, *_):
60
61
  """Noise level have changed. Update noise array."""
61
62
  v = float(level)
62
63
  recordLength = pvv('recordLength')
@@ -66,7 +67,7 @@ def set_noise(level):
66
67
  printi(f'Noise array[{len(pargs.noise)}] updated with level {v:.4g} V. in {timer()-ts:.4g} S.')
67
68
  publish('noiseLevel', level)
68
69
 
69
- def set_externalControl(value):
70
+ def set_externalControl(value, *_):
70
71
  """External control PV have changed. Control the server accordingly."""
71
72
  pvname = str(value)
72
73
  if pvname in (None,'0'):
@@ -91,16 +92,12 @@ def serverStateChanged(newState:str):
91
92
  publish('cycle', 0)
92
93
 
93
94
  def init(recordLength):
94
- """Testing function. Do not use in production code."""
95
+ """Device initialization function"""
95
96
  set_recordLength(recordLength)
96
97
  #set_externalControl(pargs.prefix + pargs.external)
97
98
 
98
99
  def poll():
99
- """Example of polling function"""
100
- #pattern = C_.cycle % nPatterns# produces sliding
101
- cycle = pvv('cycle')
102
- printv(f'cycle {repr(cycle)}')
103
- publish('cycle', cycle + 1)
100
+ """Device polling function, called every cycle when server is running"""
104
101
  for ch in range(pargs.channels):
105
102
  pattern = rng.integers(0, nPatterns)
106
103
  chstr = f'c{ch+1:02}'
@@ -143,7 +140,6 @@ PVs = init_epicsdev(pargs.prefix, myPVDefs(), pargs.verbose,
143
140
  # print('List of PVs:')
144
141
  # for _pvname in PVs:
145
142
  # print(_pvname)
146
- printi(f'Hosting {len(PVs)} PVs')
147
143
 
148
144
  # Initialize the device, using pargs if needed.
149
145
  # That can be used to set the number of points in the waveform, for example.
@@ -154,12 +150,12 @@ set_server('Start')
154
150
 
155
151
  #``````````````````Main loop``````````````````````````````````````````````````
156
152
  server = Server(providers=[PVs])
157
- printi(f'Server started with polling interval {repr(pvv("polling"))} S.')
153
+ printi(f'Server started. Sleeping per cycle: {repr(pvv("sleep"))} S.')
158
154
  while True:
159
155
  state = serverState()
160
156
  if state.startswith('Exit'):
161
157
  break
162
158
  if not state.startswith('Stop'):
163
159
  poll()
164
- time.sleep(pvv("polling"))
160
+ sleep()
165
161
  printi('Server is exited')
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "epicsdev"
7
- version = "2.0.1"
7
+ version = "2.1.0"
8
8
  authors = [
9
9
  { name="Andrey Sukhanov", email="sukhanov@bnl.gov" },
10
10
  ]
File without changes
File without changes
File without changes
File without changes