mrfioc2  2.3.0
Macros | Functions | Variables
seqconst.c File Reference
#include <math.h>
#include <stdio.h>
#include <string.h>
#include <dbDefs.h>
#include <errlog.h>
#include <recGbl.h>
#include <alarm.h>
#include <registryFunction.h>
#include <menuFtype.h>
#include <aSubRecord.h>
#include <epicsExport.h>
Include dependency graph for seqconst.c:

Go to the source code of this file.

Macros

#define NINPUTS   (aSubRecordU - aSubRecordA)
 

Functions

long seq_repeat (aSubRecord *prec)
 Periodically repeat a given set of event codes and time delays. A bit mask selects if each possible repatition is actually populated. More...
 
long seq_merge (aSubRecord *prec)
 Merge several sorted sequences. More...
 
long seq_shift (aSubRecord *prec)
 Sequence shifter. More...
 
long seq_mask (aSubRecord *prec)
 Sequence masker. More...
 
 epicsExportRegistrar (asub_evg)
 
 epicsExportAddress (int, seqConstDebug)
 

Variables

int seqConstDebug = 0
 

Macro Definition Documentation

◆ NINPUTS

#define NINPUTS   (aSubRecordU - aSubRecordA)

Definition at line 26 of file seqconst.c.

Function Documentation

◆ epicsExportAddress()

epicsExportAddress ( int  ,
seqConstDebug   
)

◆ epicsExportRegistrar()

epicsExportRegistrar ( asub_evg  )

◆ seq_mask()

long seq_mask ( aSubRecord *  prec)

Sequence masker.

Inputs

Parameters
Acode waveform A UCHAR
Bevent selection mask B ULONG ...

Outputs

Parameters
VALAOutput code waveform VALA UCHAR

Definition at line 407 of file seqconst.c.

408 {
409  const epicsUInt8 *inp = (const epicsUInt8*)prec->a;
410  const epicsUInt32 *mask = (const epicsUInt32*)prec->b;
411  epicsUInt8 *out = (epicsUInt8*)prec->vala;
412  epicsUInt32 i, num = prec->neb*32;
413 
414  if(num>prec->nea)
415  num = prec->nea;
416  if(num>prec->nova)
417  num = prec->nova;
418 
419  for(i=0; i<num; i++) {
420  epicsUInt8 M = (mask[i/32]>>(i%32))&0x1;
421  out[i] = M ? inp[i] : 0;
422  }
423 
424  prec->neva = num;
425 
426  return 0;
427 }

◆ seq_merge()

long seq_merge ( aSubRecord *  prec)

Merge several sorted sequences.

Inputs

Parameters
AFirst time waveform A DOUBLE
BFirst code waveform B UCHAR
CSecond time waveform C DOUBLE
DSecond code waveform D UCHAR ...

Outputs

Parameters
VALAOutput time waveform VALA DOUBLE
VALBOutput code waveform VALB UCHAR

Definition at line 190 of file seqconst.c.

191 {
192  unsigned int i;
193  epicsUInt32 in_pos[NINPUTS/2]; // position in each pair of input times/codes
194  unsigned int ninputs;
195 
196  epicsUInt32 maxout = prec->nova;
197  double *out_T = prec->vala;
198  epicsUInt8 *out_C = prec->valb;
199 
200  if(prec->nsev>=INVALID_ALARM) /* Invalid inputs */
201  return -1;
202 
203  memset(in_pos, 0, sizeof(in_pos));
204 
205  if(maxout > prec->novb)
206  maxout = prec->novb;
207 
208  /* check output types */
209  if(prec->ftva!=menuFtypeDOUBLE || prec->ftvb!=menuFtypeUCHAR ||
210  prec->nova==0 || prec->novb==0)
211  {
212  epicsPrintf("%s: Invalid types for lengths for VALA and/or VALB\n", prec->name);
213  goto alarm;
214  }
215 
216  {
217  unsigned int N;
218  for(N=0; N<NINPUTS/2; N++) {
219  if((&prec->fta)[2*N]!=menuFtypeDOUBLE)
220  break;
221  if((&prec->fta)[2*N+1]!=menuFtypeUCHAR)
222  break;
223 
224  /* Fail unless lengths match */
225  if((&prec->nea)[2*N]!=(&prec->nea)[2*N+1]) {
226  epicsPrintf("%s: NE%c (%d) != NE%c (%d)\n",
227  prec->name,
228  (char)('A'+2*N), (&prec->nea)[2*N],
229  (char)('A'+2*N+1), (&prec->nea)[2*N+1]);
230  goto fail;
231  }
232  }
233 
234  ninputs = N;
235  }
236 
237  if(ninputs==0) {
238  epicsPrintf("%s: No inputs configured!\n", prec->name);
239  goto fail;
240  }
241 
242  if(seqConstDebug>1) {
243  printf("%s Merge\n", prec->name);
244  }
245 
246  for(i=0; i<maxout; i++) {
247  unsigned int N;
248  int found_element = -1;
249  double last_time = -1.0; /* Initial value not used, but silences warning */
250 
251  for(N=0; N<ninputs; N++) {
252  double *T;
253  epicsUInt8 *C;
254 
255  T = (double*)(&prec->a)[2*N];
256  C = (epicsUInt8*)(&prec->a)[2*N+1];
257 
258  while(in_pos[N]<(&prec->nea)[2*N] && C[in_pos[N]]==0)
259  in_pos[N]++; /* skip entries with code 0 */
260 
261  if(in_pos[N]==(&prec->nea)[2*N])
262  continue; /* This input completely consumed */
263 
264  if(found_element==-1 || T[in_pos[N]]<last_time) {
265  found_element = N;
266  out_T[i] = T[in_pos[N]];
267  out_C[i] = C[in_pos[N]];
268  last_time = out_T[i];
269 
270  } else if(T[in_pos[N]]==last_time && found_element!=-1) {
271  /* Duplicate timestamp! */
272  printf("%s: Dup timestamp. %c[%u] and %c[%u]\n",
273  prec->name,
274  'A'+(2*found_element), in_pos[found_element]-1,
275  'A'+(2*N), in_pos[N]);
276  printf(" Found element: %d\n", found_element);
277  printf(" i=%u, N=%u, ninputs=%u\n", i, N, ninputs);
278  printf(" Out %u C=%u T=%f [", i, out_C[i], out_T[i]);
279  for(N=0; N<ninputs; N++)
280  printf("%u, ", in_pos[N/2]);
281  printf("]\n");
282  goto fail;
283  }
284  }
285 
286  if(found_element==-1) {
287  /* All inputs consumed */
288  goto done;
289  } else if(i>0 && out_T[i] < out_T[i-1]) {
290  epicsPrintf("%s: input %c times not sorted!\n", prec->name, 'A'+(2*found_element));
291  goto fail;
292  } else {
293  in_pos[found_element]++;
294  }
295 
296  if(seqConstDebug>1) {
297  printf("Out %u C=%u T=%f [", i, out_C[i], out_T[i]);
298  for(N=0; N<ninputs; N++)
299  printf("%u, ", in_pos[N/2]);
300  printf("\n");
301  }
302  }
303 
304  if(seqConstDebug>0) {
305  epicsPrintf("%s: merge result has %u element\n", prec->name, i);
306  }
307 
308  {
309  unsigned int N;
310  unsigned int nogood = 0;
311  for(N=0; N<ninputs; N++) {
312  if(in_pos[N]!=(&prec->nea)[2*N]) {
313  epicsPrintf("%s.%c: Not completely consumed! %u of %u\n",
314  prec->name, 'A'+(2*N), in_pos[N], (&prec->nea)[2*N]);
315  nogood = 1;
316  }
317  }
318  if(nogood)
319  goto fail;
320  }
321 
322 done:
323  if(i==0) {
324  if(seqConstDebug>0)
325  epicsPrintf("%s: merged yields empty sequence\n", prec->name);
326  /* result is really empty */
327  out_T[0] = 0.0;
328  out_C[0] = 0;
329  i = 1;
330  }
331  prec->neva = i;
332  prec->nevb = i;
333 
334  return 0;
335 
336 fail:
337  /* when possible ensure a sane output (do nothing)
338  * in case the alarm is ignored.
339  */
340  out_T[0] = 0.0;
341  out_C[0] = 0;
342  prec->neva = 1;
343  prec->nevb = 1;
344 alarm:
345  recGblSetSevr(prec, CALC_ALARM, INVALID_ALARM);
346  return -1;
347 }
#define NINPUTS
Definition: seqconst.c:26
int seqConstDebug
Definition: seqconst.c:28

◆ seq_repeat()

long seq_repeat ( aSubRecord *  prec)

Periodically repeat a given set of event codes and time delays. A bit mask selects if each possible repatition is actually populated.

Inputs

Parameters
AOverall period. In sequencer system ticks A ULONG
B# of cycles in the overall period. B ULONG
CPeriod bit mask. Bit 0 is first repetition. C ULONG
DCycle timestamp waveform D DOUBLE
ECycle event code waveform E UCHAR

Outputs

Parameters
VALACycle time. (Overall period / # of cycles) VALA DOUBLE
VALBPeriod timestamp waveform VALB DOUBLE
VALCPeriod event code waveform VALB UCHAR

Definition at line 63 of file seqconst.c.

64 {
65  unsigned int N,i;
66 
67  /* Inputs */
68  epicsUInt32 period;
69  epicsUInt32 num_cycles, per_mask, len_in, len_out, num_out;
70  double add;
71  double *cycle_D = prec->d;
72  epicsUInt8 *cycle_C = prec->e;
73 
74  /* Outputs */
75  double *period_D = prec->valb;
76  epicsUInt8 *period_C = prec->valc;
77 
78  if(prec->nsev>=INVALID_ALARM) /* Invalid inputs */
79  return -1;
80 
81  /* Check type and length of inputs and outputs */
82 
83  for(i=0; i<NELEMENTS(seq_repeat_ft); i++) {
84  if((&prec->fta)[i]!=seq_repeat_ft[i]) {
85  epicsPrintf("%s: Invalid type for FT%c\n", prec->name, 'A'+i);
86  goto fail;
87  }
88  if((&prec->nea)[i]==0) {
89  epicsPrintf("%s.NE%c empty\n", prec->name, 'A'+i);
90  goto fail;
91  }
92  }
93 
94  for(i=0; i<NELEMENTS(seq_repeat_ftv); i++) {
95  if((&prec->ftva)[i]!=seq_repeat_ftv[i]) {
96  epicsPrintf("%s: Invalid type for FTV%c\n", prec->name, 'A'+i);
97  goto fail;
98  }
99  if((&prec->nova)[i]==0) {
100  epicsPrintf("%s.NOV%c empty\n", prec->name, 'A'+i);
101  goto fail;
102  }
103  }
104 
105  period = *(epicsUInt32*)prec->a;
106  num_cycles = *(epicsUInt32*)prec->b;
107  per_mask = *(epicsUInt32*)prec->c;
108 
109  len_in = prec->ned;
110  if(len_in > prec->nee)
111  len_in = prec->nee;
112 
113  len_out = prec->novb;
114  if(len_out > prec->novc)
115  len_out = prec->novc;
116 
117  if(num_cycles==0) {
118  goto fail;
119  } else if(num_cycles>32) {
120  epicsPrintf("%s: Num cycles is out of range", prec->name);
121  goto fail;
122  }
123 
124  /* amount to add per cycle */
125  add = period/num_cycles;
126 
127  if(len_in * num_cycles > len_out) {
128  epicsPrintf("%s: Not enough elements for result. Have %u, need %u\n",
129  prec->name, len_out, len_in * num_cycles);
130  goto fail;
131  }
132 
133  if( period%num_cycles ) {
134  epicsPrintf("%s: %u cycles does not evenly divide period %u", prec->name, num_cycles, period);
135  goto fail;
136  }
137 
138  *(double*)prec->vala = add;
139 
140  num_out = 0;
141  for(N=0; per_mask && N<num_cycles; N++, per_mask>>=1) {
142  if(!(per_mask&1))
143  continue;
144  for(i=0; i<len_in; i++) {
145  if(cycle_D[i]>=add) {
146  len_in = i; /* truncate */
147  break;
148  }
149  *period_D++ = cycle_D[i] + add*N;
150  *period_C++ = cycle_C[i];
151  }
152  num_out++;
153  }
154 
155  if(num_out==0 || len_in==0) {
156  /* 0 length arrays aren't handled so well, so have 1 length w/ 0 value */
157  *period_D++ = 0.0;
158  *period_C++ = 0;
159  prec->nevb = prec->nevc = 1;
160  } else {
161  prec->nevb = prec->nevc = num_out * len_in;
162  }
163 
164  return 0;
165 
166 fail:
167  recGblSetSevr(prec, CALC_ALARM, INVALID_ALARM);
168  return -1;
169 }

◆ seq_shift()

long seq_shift ( aSubRecord *  prec)

Sequence shifter.

Inputs

Parameters
ADelay A DOUBLE
Btime waveform B DOUBLE ...

Outputs

Parameters
VALAOutput time waveform VALA DOUBLE

Definition at line 362 of file seqconst.c.

363 {
364  double delay;
365  const double *input=(const double*)prec->b;
366  double *output=(double*)prec->vala;
367  epicsUInt32 i;
368 
369  if(prec->fta!=menuFtypeDOUBLE
370  || prec->ftb!=menuFtypeDOUBLE
371  || prec->ftva!=menuFtypeDOUBLE)
372  {
373  epicsPrintf("%s: invalid types\n", prec->name);
374  goto fail;
375  } else if(prec->nea==0 || prec->neb > prec->nova) {
376  epicsPrintf("%s: incorrect sizes\n", prec->name);
377  goto fail;
378  }
379 
380  delay = *(double*)prec->a;
381 
382  for(i=0; i<prec->neb; i++)
383  output[i] = input[i]+delay;
384 
385  prec->neva = prec->neb;
386 
387  return 0;
388 
389 fail:
390  recGblSetSevr(prec, CALC_ALARM, INVALID_ALARM);
391  return -1;
392 }

Variable Documentation

◆ seqConstDebug

int seqConstDebug = 0

Definition at line 28 of file seqconst.c.