mrfioc2  2.3.0
drvemCML.cpp
Go to the documentation of this file.
1 /*************************************************************************\
2 * Copyright (c) 2010 Brookhaven Science Associates, as Operator of
3 * Brookhaven National Laboratory.
4 * mrfioc2 is distributed subject to a Software License Agreement found
5 * in file LICENSE that is included with this distribution.
6 \*************************************************************************/
7 /*
8  * Author: Michael Davidsaver <mdavidsaver@gmail.com>
9  */
10 
11 #include <stdexcept>
12 #include <algorithm>
13 #include <stdio.h>
14 
15 #include <epicsMath.h>
16 
17 #include <mrfCommonIO.h>
18 #include <mrfBitOps.h>
19 #include "evrRegMap.h"
20 
21 
22 #include "drvem.h"
23 #include "drvemCML.h"
24 
25 MRMCML::MRMCML(const std::string& n, unsigned char i,EVRMRM& o, outkind k, formFactor f)
26  :CML(n)
27  // CML word length
28  ,mult(f==formFactor_CPCIFULL || f==formFactor_mTCA ? 40 : 20)
29  // # of 32-bit dwords used to store 1 CML word
30  // 40 bits fit in 2 dwords, 20 bits fit in 1
31  ,wordlen(f==formFactor_CPCIFULL || f==formFactor_mTCA ? 2 : 1)
32  ,base(o.base)
33  ,N(i)
34  ,owner(o)
35  ,shadowEnable(0)
36  ,shadowWaveformlength(0)
37  ,kind(k)
38 {
39  epicsUInt32 val=READ32(base, OutputCMLEna(N));
40 
42 
43  switch(kind) {
44  case typeCML: break;
45  case typeTG203: val|=OutputCMLEna_type_203; break;
46  case typeTG300: val|=OutputCMLEna_type_300; break;
47  default:
48  throw std::invalid_argument("Invalid CML kind");
49  }
50 
51  for(size_t i=0; i<NELEMENTS(shadowPattern); i++) {
52  epicsUInt32 L = wordlen * (lenPatternMax((pattern)i)/mult);
53  shadowPattern[i] = new epicsUInt32[L];
54  std::fill(shadowPattern[i], shadowPattern[i]+L, 0);
55  }
56 
57  shadowEnable=val;
58 }
59 
61 {
62  for(size_t i=0; i<NELEMENTS(shadowPattern); i++)
63  delete[] shadowPattern[i];
64 }
65 
66 void MRMCML::lock() const{owner.lock();};
67 void MRMCML::unlock() const{owner.unlock();};
68 
69 cmlMode
70 MRMCML::mode() const
71 {
72  switch(shadowEnable&OutputCMLEna_mode_mask) {
74  return cmlModeOrig;
76  return cmlModeFreq;
78  return cmlModePattern;
79  default:
80  return cmlModeInvalid;
81  }
82 }
83 
84 void
86 {
87  epicsUInt32 mask=0;
88  switch(m) {
89  case cmlModeOrig: mask |= OutputCMLEna_mode_orig; break;
90  case cmlModeFreq: mask |= OutputCMLEna_mode_freq; break;
91  case cmlModePattern: mask |= OutputCMLEna_mode_patt; break;
92  default:
93  throw std::out_of_range("Invalid CML Mode");
94  }
95  bool wasenabled = enabled();
96  shadowEnable &= ~OutputCMLEna_ena; // disable while syncing
97  shadowEnable &= ~OutputCMLEna_mode_mask;
98  shadowEnable |= mask;
99  WRITE32(base, OutputCMLEna(N), shadowEnable);
100 
101 
102  switch(m) {
103  case cmlModeOrig:
104  WRITE32(base, OutputCMLPatLength(N), 0);
105  syncPattern(patternFall);
106  syncPattern(patternHigh);
107  syncPattern(patternLow);
108  syncPattern(patternRise);
109  break;
110 
111  case cmlModePattern:
112  WRITE32(base, OutputCMLPatLength(N), shadowWaveformlength-1);
113  syncPattern(patternWaveform);
114  break;
115 
116  default:
117  break;
118  }
119 
120  if(wasenabled)
121  shadowEnable |= OutputCMLEna_ena; // enable after syncing
122  WRITE32(base, OutputCMLEna(N), shadowEnable);
123 }
124 
125 bool
127 {
128  return shadowEnable&OutputCMLEna_ena;
129 }
130 
131 void
133 {
134  if(s)
135  shadowEnable |= OutputCMLEna_ena;
136  else
137  shadowEnable &= ~OutputCMLEna_ena;
138  WRITE32(base, OutputCMLEna(N), shadowEnable);
139 }
140 
141 bool
143 {
144  return (shadowEnable & OutputCMLEna_rst) != 0;
145 }
146 
147 void
149 {
150  if(s)
151  shadowEnable |= OutputCMLEna_rst;
152  else
153  shadowEnable &= ~OutputCMLEna_rst;
154  WRITE32(base, OutputCMLEna(N), shadowEnable);
155 }
156 
157 bool
159 {
160  return !(shadowEnable & OutputCMLEna_pow);
161 }
162 
163 void
165 {
166  if(!s)
167  shadowEnable |= OutputCMLEna_pow;
168  else
169  shadowEnable &= ~OutputCMLEna_pow;
170  WRITE32(base, OutputCMLEna(N), shadowEnable);
171 }
172 
173 double
175 {
176  // The GTX output fine delay is an external chip
177  // and not related to the clock frequency.
178  // So just scale it to [0, 1) and use ESLO for the
179  // actual calibration
180  return READ32(base, GTXDelay(N))/1024.0;
181 }
182 
183 void
185 {
186  if(v>1024.0){
187  printf("Delay will be set to 1024 instead of %f\n", v);
188  v=1024.0;
189  }
190  WRITE32(base, GTXDelay(N), roundToUInt(v*1024.0));
191 }
192 
193 void
195 {
196  if(s)
197  shadowEnable |= OutputCMLEna_ftrg;
198  else
199  shadowEnable &= ~OutputCMLEna_ftrg;
200  WRITE32(base, OutputCMLEna(N), shadowEnable);
201 }
202 
203 bool
205 {
206  return (shadowEnable & OutputCMLEna_ftrg) != 0;
207 }
208 
209 epicsUInt32
211 {
212  epicsUInt32 val = READ32(base, OutputCMLCount(N));
213  val >>= OutputCMLCount_high_shft;
214  return val & OutputCMLCount_mask;
215 }
216 
217 epicsUInt32
219 {
220  epicsUInt32 val = READ32(base, OutputCMLCount(N));
221  val >>= OutputCMLCount_low_shft;
222  return val & OutputCMLCount_mask;
223 }
224 
225 
226 epicsUInt32
228 {
229  epicsUInt32 v = shadowEnable & OutputCMLEna_ftrig_mask;
230  return v >> OutputCMLEna_ftrig_shft;
231 }
232 
233 void
234 MRMCML::setCountHigh(epicsUInt32 v)
235 {
236  v = std::max(kind==typeTG300?40u:20u, std::min(v, 65535u));
237 
238  epicsUInt32 val = READ32(base, OutputCMLCount(N));
240  val |= v << OutputCMLCount_high_shft;
241  WRITE32(base, OutputCMLCount(N), val);
242 }
243 
244 void
245 MRMCML::setCountLow (epicsUInt32 v)
246 {
247  v = std::max(kind==typeTG300?40u:20u, std::min(v, 65535u));
248 
249  epicsUInt32 val = READ32(base, OutputCMLCount(N));
251  val |= v << OutputCMLCount_low_shft;
252  WRITE32(base, OutputCMLCount(N), val);
253 }
254 
255 void
256 MRMCML::setCountInit (epicsUInt32 v)
257 {
258  v = std::min(v, 65535u);
259 
261  shadowEnable &= ~OutputCMLEna_ftrig_mask;
262  shadowEnable |= v;
263  WRITE32(base, OutputCMLEna(N), shadowEnable);
264 }
265 
266 double
268 {
269  double period=1.0/(mult*owner.clock());
270 
271  return countHigh()*period;
272 }
273 
274 double
276 {
277  double period=1.0/(mult*owner.clock());
278 
279  return countLow()*period;
280 }
281 
282 double
284 {
285  double period=1.0/(mult*owner.clock());
286 
287  return countInit()*period;
288 }
289 
290 void
292 {
293  double period=1.0/(mult*owner.clock());
294 
295  setCountHigh(roundToUInt(v/period));
296 }
297 
298 void
300 {
301  double period=1.0/(mult*owner.clock());
302 
303  setCountLow(roundToUInt(v/period));
304 }
305 
306 void
308 {
309  double period=1.0/(mult*owner.clock());
310 
311  setCountInit(roundToUInt(v/period));
312 }
313 
314  // For Pattern mode
315 
316 bool
318 {
319  return (shadowEnable & OutputCMLEna_cycl) != 0;
320 }
321 
322 void
324 {
325  if(s)
326  shadowEnable |= OutputCMLEna_cycl;
327  else
328  shadowEnable &= ~OutputCMLEna_cycl;
329  WRITE32(base, OutputCMLEna(N), shadowEnable);
330 }
331 
332 epicsUInt32
334 {
335  if(p==patternWaveform)
336  return mult*shadowWaveformlength;
337  else
338  return mult;
339 }
340 
341 epicsUInt32
343 {
344  if(p==patternWaveform)
345  return mult*OutputCMLPatLengthMax;
346  else
347  return mult;
348 }
349 
350 epicsUInt32
351 MRMCML::getPattern(pattern p, unsigned char *buf, epicsUInt32 blen) const
352 {
353  epicsUInt32 plen=lenPattern(p);
354 
355  // number of bytes of 'buf' to fill
356  blen = std::min(plen, blen);
357 
358  epicsUInt32 val=0;
359  for(epicsUInt32 i=0; i<blen; i++) {
360  size_t cmlword = (i/mult);
361  size_t cmlbit = (i%mult);
362 
363  size_t cpuword, cpubit;
364  bool first; // first bit in CPU word
365 
366  if(mult<32) {
367  first = cmlbit==0;
368  cpuword = cmlword;
369  cpubit = 19 - cmlbit;
370  } else {
371  first = cmlbit==0 || cmlbit==8;
372  cpuword = 2*cmlword + (cmlbit<8 ? 0 : 1);
373  cpubit = cmlbit<8 ? 7-cmlbit : 31-(cmlbit-8);
374  }
375 
376  if(first) {
377  val=shadowPattern[p][cpuword];
378  }
379 
380  buf[i]=val>>cpubit;
381  buf[i]&=0x1;
382 
383  }
384  return blen;
385 }
386 
387 void
388 MRMCML::setPattern(pattern p, const unsigned char *buf, epicsUInt32 blen)
389 {
390  // If we are given a length that is not a multiple of CML word size
391  // then truncate.
392  if(blen%mult){
393  printf("Given length is not a multiple of %u (CML word size). Truncating...\n", mult);
394  blen-=blen%mult;
395  }
396 
397  if(blen>lenPatternMax(p))
398  throw std::out_of_range("Pattern is too long");
399 
400 
401  epicsUInt32 val=0;
402  for(epicsUInt32 i=0; i<blen; i++) {
403  size_t cmlword = (i/mult);
404  size_t cmlbit = (i%mult);
405  size_t cpuword, cpubit;
406  if(mult<32) {
407  cpuword = cmlword;
408  cpubit = 19 - cmlbit;
409  } else {
410  cpuword = 2*cmlword + (cmlbit<8 ? 0 : 1);
411  cpubit = cmlbit<8 ? 7-cmlbit : 31-(cmlbit-8);
412  }
413 
414  val|=(!!buf[i])<<cpubit;
415 
416  // cpubit is counting down.
417  // write complete dword after the last bit is set
418  if(cpubit==0) {
419  shadowPattern[p][cpuword] = val;
420  val=0;
421  }
422  }
423 
424  if(p==patternWaveform)
425  shadowWaveformlength = blen/mult;
426 
427  // temporarly disable when changing multi dword patterns
428  // to prevent output of incomplete patterns
429  bool active=enabled();
430  if(active)
431  enable(false);
432 
433  if(mode()==cmlModePattern)
434  WRITE32(base, OutputCMLPatLength(N), shadowWaveformlength-1);
435 
436  syncPattern(p);
437 
438  if(active)
439  enable(true);
440 }
441 
442 void
443 MRMCML::syncPattern(pattern p)
444 {
445  if(mult==20 && p!=patternWaveform) {
446  // for 20 bit patterns modifying the 4x pattern
447  // can be done without effecting the waveform pattern
448  switch(p) {
449  case patternHigh:
450  WRITE32(base, OutputCMLHigh(N), shadowPattern[patternHigh][0]); return;
451  case patternFall:
452  WRITE32(base, OutputCMLFall(N), shadowPattern[patternFall][0]); return;
453  case patternLow:
454  WRITE32(base, OutputCMLLow(N), shadowPattern[patternLow][0]); return;
455  case patternRise:
456  WRITE32(base, OutputCMLRise(N), shadowPattern[patternRise][0]); return;
457  default:
458  throw std::logic_error("syncPattern: invalid state 20");
459  }
460  }
461 
462  cmlMode curmode=mode();
463  if(curmode==cmlModeFreq)
464  return; // Don't know which pattern to sync...
465 
466  switch(curmode) {
467  case cmlModeOrig:
468 
469  switch(p) {
470  case patternLow:
471  WRITE32(base, OutputCMLPat(N, 0), shadowPattern[patternLow][0]);
472  WRITE32(base, OutputCMLPat(N, 1), shadowPattern[patternLow][1]);
473  break;
474 
475  case patternRise:
476  WRITE32(base, OutputCMLPat(N, 2), shadowPattern[patternRise][0]);
477  WRITE32(base, OutputCMLPat(N, 3), shadowPattern[patternRise][1]);
478  break;
479 
480  case patternFall:
481  WRITE32(base, OutputCMLPat(N, 4), shadowPattern[patternFall][0]);
482  WRITE32(base, OutputCMLPat(N, 5), shadowPattern[patternFall][1]);
483  break;
484 
485  case patternHigh:
486  WRITE32(base, OutputCMLPat(N, 6), shadowPattern[patternHigh][0]);
487  WRITE32(base, OutputCMLPat(N, 7), shadowPattern[patternHigh][1]);
488  break;
489 
490  case patternWaveform:
491  break; // not safe to sync
492  }
493  break;
494 
495  case cmlModePattern:
496  switch(p) {
497  case patternWaveform:
498  for(size_t i=0; i<shadowWaveformlength*wordlen; i++)
499  WRITE32(base, OutputCMLPat(N, i), shadowPattern[patternWaveform][i]);
500  break;
501  default:
502  break; // not safe to sync
503  }
504 
505  break;
506 
507  default:
508  throw std::logic_error("syncPattern: invalid state 40");
509  }
510 }
#define OutputCMLEna_ena
Definition: evrRegMap.h:310
virtual void setTimeLow(double) OVERRIDE FINAL
Definition: drvemCML.cpp:299
virtual double timeInit() const OVERRIDE FINAL
Definition: drvemCML.cpp:283
virtual void setFineDelay(double) OVERRIDE FINAL
Definition: drvemCML.cpp:184
virtual bool inReset() const OVERRIDE FINAL
Definition: drvemCML.cpp:142
virtual double timeLow() const OVERRIDE FINAL
Definition: drvemCML.cpp:275
#define READ32(base, offset)
Definition: mrfCommonIO.h:114
virtual double clock() const OVERRIDE FINAL
Definition: drvem.h:141
#define OutputCMLEna_pow
Definition: evrRegMap.h:309
#define OutputCMLEna_cycl
Definition: evrRegMap.h:302
#define OutputCMLCount_mask
Definition: evrRegMap.h:312
outkind
Definition: drvemCML.h:23
virtual double timeHigh() const OVERRIDE FINAL
Definition: drvemCML.cpp:267
epicsUInt32 lenPatternMax() const
Definition: cml.h:94
#define OutputCMLEna_mode_mask
Definition: evrRegMap.h:304
virtual epicsUInt32 countInit() const OVERRIDE FINAL
Definition: drvemCML.cpp:227
virtual void setTimeHigh(double) OVERRIDE FINAL
Definition: drvemCML.cpp:291
#define OutputCMLEna_type_203
Definition: evrRegMap.h:298
virtual bool polarityInvert() const OVERRIDE FINAL
Trigger level.
Definition: drvemCML.cpp:204
Modular Register Map Event Receivers.
Definition: drvem.h:86
formFactor
pattern
Definition: cml.h:28
virtual epicsUInt32 countHigh() const OVERRIDE FINAL
Definition: drvemCML.cpp:210
#define OutputCMLEna_ftrig_shft
Definition: evrRegMap.h:295
Definition: cml.h:25
#define OutputCMLCount_low_shft
Definition: evrRegMap.h:314
#define OutputCMLEna_ftrg
Definition: evrRegMap.h:303
#define OutputCMLEna_mode_patt
Definition: evrRegMap.h:307
#define OutputCMLEna_ftrig_mask
Definition: evrRegMap.h:294
virtual double fineDelay() const OVERRIDE FINAL
delay by fraction of one event clock period. Units of sec
Definition: drvemCML.cpp:174
MRMCML(const std::string &, unsigned char, EVRMRM &, outkind, formFactor)
Definition: drvemCML.cpp:25
virtual void setTimeInit(double) OVERRIDE FINAL
Definition: drvemCML.cpp:307
virtual void setRecyclePat(bool) OVERRIDE FINAL
Definition: drvemCML.cpp:323
#define OutputCMLEna_type_300
Definition: evrRegMap.h:297
virtual void lock() const OVERRIDE FINAL
Definition: drvem.h:121
virtual ~MRMCML()
Definition: drvemCML.cpp:60
virtual void setCountHigh(epicsUInt32) OVERRIDE FINAL
Definition: drvemCML.cpp:234
virtual void setCountLow(epicsUInt32) OVERRIDE FINAL
Definition: drvemCML.cpp:245
#define OutputCMLEna_type_mask
Definition: evrRegMap.h:296
#define OutputCMLEna_mode_freq
Definition: evrRegMap.h:306
virtual void power(bool) OVERRIDE FINAL
Definition: drvemCML.cpp:164
virtual void reset(bool) OVERRIDE FINAL
Definition: drvemCML.cpp:148
virtual cmlMode mode() const OVERRIDE FINAL
Definition: drvemCML.cpp:70
virtual bool recyclePat() const OVERRIDE FINAL
Definition: drvemCML.cpp:317
virtual bool enabled() const OVERRIDE FINAL
Definition: drvemCML.cpp:126
unsigned char active
Definition: drvemTSBuffer.h:70
#define OutputCMLCount_high_shft
Definition: evrRegMap.h:313
virtual void setMode(cmlMode) OVERRIDE FINAL
Definition: drvemCML.cpp:85
virtual epicsUInt32 countLow() const OVERRIDE FINAL
Definition: drvemCML.cpp:218
#define OutputCMLEna_rst
Definition: evrRegMap.h:308
virtual void setCountInit(epicsUInt32) OVERRIDE FINAL
Definition: drvemCML.cpp:256
virtual void unlock() const OVERRIDE FINAL
Definition: drvemCML.cpp:67
virtual bool powered() const OVERRIDE FINAL
Definition: drvemCML.cpp:158
cmlMode
Definition: cml.h:18
virtual epicsUInt32 getPattern(pattern, unsigned char *, epicsUInt32) const OVERRIDE FINAL
Definition: drvemCML.cpp:351
virtual void lock() const OVERRIDE FINAL
Definition: drvemCML.cpp:66
#define OutputCMLPatLengthMax
Definition: evrRegMap.h:316
epicsUInt32 roundToUInt(double val, epicsUInt32 max)
Definition: mrfCommon.cpp:43
virtual void setPattern(pattern, const unsigned char *, epicsUInt32) OVERRIDE FINAL
Definition: drvemCML.cpp:388
epicsUInt32 lenPattern() const
Definition: cml.h:92
#define WRITE32(base, offset, value)
Definition: mrfCommonIO.h:119
virtual void setPolarityInvert(bool) OVERRIDE FINAL
Definition: drvemCML.cpp:194
virtual void enable(bool) OVERRIDE FINAL
Definition: drvemCML.cpp:132
#define OutputCMLEna_mode_orig
Definition: evrRegMap.h:305
virtual void unlock() const OVERRIDE FINAL
Definition: drvem.h:122