pulserdriversh.cpp
1 /***************************************************************************
2  Copyright (C) 2002-2015 Kentaro Kitagawa
3  kitagawa@phys.s.u-tokyo.ac.jp
4 
5  This program is free software; you can redistribute it and/or
6  modify it under the terms of the GNU Library General Public
7  License as published by the Free Software Foundation; either
8  version 2 of the License, or (at your option) any later version.
9 
10  You should have received a copy of the GNU Library General
11  Public License and a list of authors along with this program;
12  see the files COPYING and AUTHORS.
13 ***************************************************************************/
14 #include "pulserdriversh.h"
15 #include "charinterface.h"
16 
17 REGISTER_TYPE(XDriverList, SHPulser, "NMR pulser handmade-SH2");
18 
19 using std::max;
20 using std::min;
21 
22 //[ms]
23 #define DMA_PERIOD (1.0/(28.64e3/2))
24 
25 double XSHPulser::resolution() const {
26  return DMA_PERIOD;
27 }
28 
29 //[ms]
30 #define MIN_MTU_LEN 50e-3
31 //[ms]
32 #define MTU_PERIOD (1.0/(28.64e3/1))
33 
34 
35 #define NUM_BANK 2u
36 #define PATTERNS_ZIPPED_MAX 40000u
37 
38 //dma time commands
39 const unsigned char XSHPulser::PATTERN_ZIPPED_COMMAND_DMA_END = 0;
40 //+1: a phase by 90deg.
41 //+2,3: from DMA start
42 //+4,5: src neg. offset from here
43 const unsigned char XSHPulser::PATTERN_ZIPPED_COMMAND_DMA_COPY_HBURST = 1;
44 //+1,2: time to appear
45 //+2,3: pattern to appear
46 const unsigned char XSHPulser::PATTERN_ZIPPED_COMMAND_DMA_LSET_LONG = 2;
47 //+0: time to appear + START
48 //+1,2: pattern to appear
49 const unsigned char XSHPulser::PATTERN_ZIPPED_COMMAND_DMA_LSET_START = 0x10;
50 const unsigned char XSHPulser::PATTERN_ZIPPED_COMMAND_DMA_LSET_END = 0xffu;
51 
52 //off-dma time commands
53 const unsigned char XSHPulser::PATTERN_ZIPPED_COMMAND_END = 0;
54 //+1,2 : TimerL
55 const unsigned char XSHPulser::PATTERN_ZIPPED_COMMAND_WAIT = 1;
56 //+1,2 : TimerL
57 //+3,4: LSW of TimerU
58 const unsigned char XSHPulser::PATTERN_ZIPPED_COMMAND_WAIT_LONG = 2;
59 //+1,2 : TimerL
60 //+3,4: MSW of TimerU
61 //+5,6: LSW of TimerU
62 const unsigned char XSHPulser::PATTERN_ZIPPED_COMMAND_WAIT_LONG_LONG = 3;
63 //+1: byte
64 const unsigned char XSHPulser::PATTERN_ZIPPED_COMMAND_AUX1 = 4;
65 //+1: byte
66 const unsigned char XSHPulser::PATTERN_ZIPPED_COMMAND_AUX3 = 5;
67 //+1: address
68 //+2,3: value
69 const unsigned char XSHPulser::PATTERN_ZIPPED_COMMAND_AUX2_DA = 6;
70 //+1,2: loops
71 const unsigned char XSHPulser::PATTERN_ZIPPED_COMMAND_DO = 7;
72 const unsigned char XSHPulser::PATTERN_ZIPPED_COMMAND_LOOP = 8;
73 const unsigned char XSHPulser::PATTERN_ZIPPED_COMMAND_LOOP_INF = 9;
74 const unsigned char XSHPulser::PATTERN_ZIPPED_COMMAND_BREAKPOINT = 0xa;
75 const unsigned char XSHPulser::PATTERN_ZIPPED_COMMAND_PULSEON = 0xb;
76 //+1,2: last pattern
77 const unsigned char XSHPulser::PATTERN_ZIPPED_COMMAND_DMA_SET = 0xc;
78 //+1,2: size
79 //+2n: patterns
80 const unsigned char XSHPulser::PATTERN_ZIPPED_COMMAND_DMA_HBURST = 0xd;
81 //+1 (signed char): QAM1 offset
82 //+2 (signed char): QAM2 offset
83 const unsigned char XSHPulser::PATTERN_ZIPPED_COMMAND_SET_DA_TUNE_OFFSET = 0xe;
84 //+1 (signed char): QAM1 level
85 //+2 (signed char): QAM2 level
86 const unsigned char XSHPulser::PATTERN_ZIPPED_COMMAND_SET_DA_TUNE_LEVEL = 0xf;
87 //+1 (signed char): QAM1 delay
88 //+2 (signed char): QAM2 delay
89 const unsigned char XSHPulser::PATTERN_ZIPPED_COMMAND_SET_DA_TUNE_DELAY = 0x10;
90 
91 XSHPulser::XSHPulser(const char *name, bool runtime,
92  Transaction &tr_meas, const shared_ptr<XMeasure> &meas) :
93  XCharDeviceDriver<XPulser>(name, runtime, ref(tr_meas), meas) {
94 
95  interface()->setEOS("\n");
96  interface()->setSerialBaudRate(115200);
97  interface()->setSerialStopBits(2);
98 
99  const int ports[] = {
100  PORTSEL_GATE, PORTSEL_PREGATE, PORTSEL_TRIG1, PORTSEL_TRIG2,
101  PORTSEL_GATE3, PORTSEL_COMB, PORTSEL_QSW, PORTSEL_ASW,
102  PORTSEL_PULSE1, PORTSEL_PULSE2, PORTSEL_COMB_FM, PORTSEL_COMB
103  };
104  iterate_commit([=](Transaction &tr){
105  for(unsigned int i = 0; i < sizeof(ports)/sizeof(int); i++) {
106  tr[ *portSel(i)] = ports[i];
107  }
108  });
109 }
110 
111 void
113  const Snapshot &shot(tr);
114  //dry-run to determin LastPattern, DMATime
115  tr[ *this].m_dmaTerm = 0;
116  tr[ *this].m_lastPattern = 0;
117  uint32_t pat = 0;
118  insertPreamble(tr, (uint16_t)pat);
119  for(Payload::RelPatList::const_iterator it = shot[ *this].relPatList().begin();
120  it != shot[ *this].relPatList().end(); it++) {
121  pulseAdd(tr, it->toappear, it->pattern, (it == shot[ *this].relPatList().begin() ), true );
122  pat = it->pattern;
123  }
124 
125  insertPreamble(tr, (uint16_t)pat);
126 
127  for(unsigned int i = 0; i < PAT_QAM_PULSE_IDX_MASK/PAT_QAM_PULSE_IDX; i++) {
128  const uint16_t word = shot[ *this].qamWaveForm(i).size();
129  if(!word) continue;
130  tr[ *this].m_waveformPos[i] = shot[ *this].m_zippedPatterns.size();
131  tr[ *this].m_zippedPatterns.push_back(PATTERN_ZIPPED_COMMAND_DMA_HBURST);
132  tr[ *this].m_zippedPatterns.push_back((unsigned char)(word / 0x100) );
133  tr[ *this].m_zippedPatterns.push_back((unsigned char)(word % 0x100) );
134  for(std::vector<std::complex<double> >::const_iterator it =
135  shot[ *this].qamWaveForm(i).begin(); it != shot[ *this].qamWaveForm(i).end(); it++) {
136  double x = max(min(it->real() * 125.0, 124.0), -124.0);
137  double y = max(min(it->imag() * 125.0, 124.0), -124.0);
138  tr[ *this].m_zippedPatterns.push_back( (unsigned char)(char)x );
139  tr[ *this].m_zippedPatterns.push_back( (unsigned char)(char)y );
140  }
141  }
142 
143  tr[ *this].m_zippedPatterns.push_back(PATTERN_ZIPPED_COMMAND_DO);
144  tr[ *this].m_zippedPatterns.push_back(0);
145  tr[ *this].m_zippedPatterns.push_back(0);
146  for(Payload::RelPatList::const_iterator it = shot[ *this].relPatList().begin();
147  it != shot[ *this].relPatList().end(); it++) {
148  pulseAdd(tr, it->toappear, it->pattern, (it == shot[ *this].relPatList().begin() ), false );
149  pat = it->pattern;
150  }
151  finishPulse(tr);
152 
153  tr[ *this].m_zippedPatterns.push_back(PATTERN_ZIPPED_COMMAND_END);
154 }
155 
156 int
157 XSHPulser::setAUX2DA(Transaction &tr, double volt, int addr) {
158  tr[ *this].m_zippedPatterns.push_back(PATTERN_ZIPPED_COMMAND_AUX2_DA);
159  tr[ *this].m_zippedPatterns.push_back((unsigned char) addr);
160  volt = max(volt, 0.0);
161  uint16_t word = (uint16_t)rint(4096u * volt / 2 / 2.5);
162  word = min(word, (uint16_t)4095u);
163  tr[ *this].m_zippedPatterns.push_back((unsigned char)(word / 0x100) );
164  tr[ *this].m_zippedPatterns.push_back((unsigned char)(word % 0x100) );
165  return 0;
166 }
167 int
168 XSHPulser::insertPreamble(Transaction &tr, uint16_t startpattern) {
169  const Snapshot &shot(tr);
170  const double masterlevel = pow(10.0, shot[ *this].masterLevel() / 20.0);
171  const double qamlevel1 = shot[ *qamLevel1()];
172  const double qamlevel2 = shot[ *qamLevel2()];
173  tr[ *this].m_zippedPatterns.clear();
174 
175  tr[ *this].m_zippedPatterns.push_back(PATTERN_ZIPPED_COMMAND_SET_DA_TUNE_OFFSET);
176  tr[ *this].m_zippedPatterns.push_back((unsigned char)(signed char)rint(
177  127.5 * shot[ *qamOffset1()] *1e-2 / masterlevel ) );
178  tr[ *this].m_zippedPatterns.push_back((unsigned char)(signed char)rint(
179  127.5 * shot[ *qamOffset2()] *1e-2 / masterlevel ) );
180  tr[ *this].m_zippedPatterns.push_back(PATTERN_ZIPPED_COMMAND_SET_DA_TUNE_LEVEL);
181  tr[ *this].m_zippedPatterns.push_back((unsigned char)(signed char)rint(qamlevel1 * 0x100) );
182  tr[ *this].m_zippedPatterns.push_back((unsigned char)(signed char)rint(qamlevel2 * 0x100) );
183  tr[ *this].m_zippedPatterns.push_back(PATTERN_ZIPPED_COMMAND_SET_DA_TUNE_DELAY);
184 //obsolete
185 // m_zippedPatterns.push_back((unsigned char)(signed char)rint(*qamDelay1() / DMA_PERIOD * 1e-3) );
186 // m_zippedPatterns.push_back((unsigned char)(signed char)rint(*qamDelay2() / DMA_PERIOD * 1e-3) );
187  tr[ *this].m_zippedPatterns.push_back((unsigned char)(signed char)rint(0) );
188  tr[ *this].m_zippedPatterns.push_back((unsigned char)(signed char)rint(0) );
189 
190  uint32_t len;
191  //wait for 1 ms
192  len = lrint(1.0 / MTU_PERIOD);
193  tr[ *this].m_zippedPatterns.push_back(PATTERN_ZIPPED_COMMAND_WAIT_LONG);
194  tr[ *this].m_zippedPatterns.push_back((unsigned char)((len % 0x10000) / 0x100) );
195  tr[ *this].m_zippedPatterns.push_back((unsigned char)((len % 0x10000) % 0x100) );
196  tr[ *this].m_zippedPatterns.push_back((unsigned char)((len / 0x10000) / 0x100) );
197  tr[ *this].m_zippedPatterns.push_back((unsigned char)((len / 0x10000) % 0x100) );
198  tr[ *this].m_zippedPatterns.push_back(PATTERN_ZIPPED_COMMAND_DMA_SET);
199  tr[ *this].m_zippedPatterns.push_back((unsigned char)(startpattern / 0x100) );
200  tr[ *this].m_zippedPatterns.push_back((unsigned char)(startpattern % 0x100) );
201  tr[ *this].m_zippedPatterns.push_back(PATTERN_ZIPPED_COMMAND_DMA_LSET_START + 2);
202  tr[ *this].m_zippedPatterns.push_back((unsigned char)(startpattern / 0x100) );
203  tr[ *this].m_zippedPatterns.push_back((unsigned char)(startpattern % 0x100) );
204  tr[ *this].m_zippedPatterns.push_back(PATTERN_ZIPPED_COMMAND_DMA_END);
205 
206  tr[ *this].m_zippedPatterns.push_back(PATTERN_ZIPPED_COMMAND_PULSEON);
207 
208  //wait for 10 ms
209  len = lrint(10.0 / MTU_PERIOD);
210  tr[ *this].m_zippedPatterns.push_back(PATTERN_ZIPPED_COMMAND_WAIT_LONG);
211  tr[ *this].m_zippedPatterns.push_back((unsigned char)((len % 0x10000) / 0x100) );
212  tr[ *this].m_zippedPatterns.push_back((unsigned char)((len % 0x10000) % 0x100) );
213  tr[ *this].m_zippedPatterns.push_back((unsigned char)((len / 0x10000) / 0x100) );
214  tr[ *this].m_zippedPatterns.push_back((unsigned char)((len / 0x10000) % 0x100) );
215 
216 /* m_zippedPatterns.push_back(PATTERN_ZIPPED_COMMAND_AUX1);
217  int aswfilter = 3;
218  if(aswFilter()->to_str() == ASW_FILTER_1) aswfilter = 1;
219  if(aswFilter()->to_str() == ASW_FILTER_2) aswfilter = 2;
220  m_zippedPatterns.push_back((unsigned char)aswfilter);
221 */
222  tr[ *this].m_zippedPatterns.push_back(PATTERN_ZIPPED_COMMAND_AUX1);
223  tr[ *this].m_zippedPatterns.push_back((unsigned char)3);
224 /* setAUX2DA(*portLevel8(), 1);
225  setAUX2DA(*portLevel9(), 2);
226  setAUX2DA(*portLevel10(), 3);
227  setAUX2DA(*portLevel11(), 4);
228  setAUX2DA(*portLevel12(), 5);
229  setAUX2DA(*portLevel13(), 6);
230  setAUX2DA(*portLevel14(), 7);*/
231  setAUX2DA(tr, 0.0, 1);
232  setAUX2DA(tr, 0.0, 2);
233  setAUX2DA(tr, 0.0, 3);
234  setAUX2DA(tr, 0.0, 4);
235  setAUX2DA(tr, 0.0, 5);
236  setAUX2DA(tr, 0.0, 6);
237  setAUX2DA(tr, 0.0, 7);
238  setAUX2DA(tr, 1.6 * masterlevel, 0); //tobe 5V
239 
240  return 0;
241 }
242 int
243 XSHPulser::finishPulse(Transaction &tr) {
244  tr[ *this].m_zippedPatterns.push_back(PATTERN_ZIPPED_COMMAND_DMA_END);
245  tr[ *this].m_zippedPatterns.push_back(PATTERN_ZIPPED_COMMAND_LOOP_INF);
246  return 0;
247 }
248 int
249 XSHPulser::pulseAdd(Transaction &tr, uint64_t term, uint32_t pattern, bool firsttime, bool dryrun) {
250  const Snapshot &shot(tr);
251  const double msec = term * resolution();
252  int64_t mtu_term = term * llrint(resolution() / MTU_PERIOD);
253  if( (msec > MIN_MTU_LEN) &&
254  ((shot[ *this].m_lastPattern & PAT_QAM_PULSE_IDX_MASK)/PAT_QAM_PULSE_IDX == 0) ) {
255  //insert long wait
256  if( !firsttime) {
257  tr[ *this].m_zippedPatterns.push_back(PATTERN_ZIPPED_COMMAND_DMA_END);
258  }
259  mtu_term += shot[ *this].m_dmaTerm;
260  uint32_t ulen = (uint32_t)(mtu_term / 0x10000uLL);
261  uint16_t ulenh = (uint16_t)(ulen / 0x10000uL);
262  uint16_t ulenl = (uint16_t)(ulen % 0x10000uL);
263  uint16_t dlen = (uint32_t)(mtu_term % 0x10000uLL);
264  if(ulenh) {
265  tr[ *this].m_zippedPatterns.push_back(PATTERN_ZIPPED_COMMAND_WAIT_LONG_LONG);
266  tr[ *this].m_zippedPatterns.push_back((unsigned char)(dlen / 0x100) );
267  tr[ *this].m_zippedPatterns.push_back((unsigned char)(dlen % 0x100) );
268  tr[ *this].m_zippedPatterns.push_back((unsigned char)(ulenh / 0x100) );
269  tr[ *this].m_zippedPatterns.push_back((unsigned char)(ulenh % 0x100) );
270  tr[ *this].m_zippedPatterns.push_back((unsigned char)(ulenl / 0x100) );
271  tr[ *this].m_zippedPatterns.push_back((unsigned char)(ulenl % 0x100) );
272  }
273  else { if(ulenl) {
274  tr[ *this].m_zippedPatterns.push_back(PATTERN_ZIPPED_COMMAND_WAIT_LONG);
275  tr[ *this].m_zippedPatterns.push_back((unsigned char)(dlen / 0x100) );
276  tr[ *this].m_zippedPatterns.push_back((unsigned char)(dlen % 0x100) );
277  tr[ *this].m_zippedPatterns.push_back((unsigned char)(ulenl / 0x100) );
278  tr[ *this].m_zippedPatterns.push_back((unsigned char)(ulenl % 0x100) );
279  }
280  else {
281  tr[ *this].m_zippedPatterns.push_back(PATTERN_ZIPPED_COMMAND_WAIT);
282  tr[ *this].m_zippedPatterns.push_back((unsigned char)(dlen / 0x100) );
283  tr[ *this].m_zippedPatterns.push_back((unsigned char)(dlen % 0x100) );
284  }
285  }
286  mtu_term -= ulen*0x10000uL + dlen;
287  mtu_term = max(0LL, mtu_term);
288  tr[ *this].m_zippedPatterns.push_back(PATTERN_ZIPPED_COMMAND_DMA_SET);
289  tr[ *this].m_zippedPatterns.push_back((unsigned char)(shot[ *this].m_lastPattern / 0x100) );
290  tr[ *this].m_zippedPatterns.push_back((unsigned char)(shot[ *this].m_lastPattern % 0x100) );
291  tr[ *this].m_dmaTerm = 0;
292  }
293  tr[ *this].m_dmaTerm += mtu_term;
294  unsigned long pos_l = shot[ *this].m_dmaTerm / llrint(resolution() / MTU_PERIOD);
295  if(pos_l >= 0x7000u)
296  throw XInterface::XInterfaceError(i18n("Too long DMA."), __FILE__, __LINE__);
297  uint16_t pos = (uint16_t)pos_l;
298  uint16_t len = mtu_term / llrint(resolution() / MTU_PERIOD);
299  if( ((shot[ *this].m_lastPattern & PAT_QAM_PULSE_IDX_MASK)/PAT_QAM_PULSE_IDX == 0) &&
300  ((pattern & PAT_QAM_PULSE_IDX_MASK)/PAT_QAM_PULSE_IDX > 0) ) {
301  uint16_t qam_pos = shot[ *this].m_waveformPos[(pattern & PAT_QAM_PULSE_IDX_MASK)/PAT_QAM_PULSE_IDX - 1];
302  if(!dryrun) {
303  if(!qam_pos || (shot[ *this].m_zippedPatterns[qam_pos] != PATTERN_ZIPPED_COMMAND_DMA_HBURST))
304  throw XInterface::XInterfaceError(i18n("No waveform."), __FILE__, __LINE__);
305  uint16_t word = shot[ *this].m_zippedPatterns.size() - qam_pos;
306  tr[ *this].m_zippedPatterns.push_back(PATTERN_ZIPPED_COMMAND_DMA_COPY_HBURST);
307  tr[ *this].m_zippedPatterns.push_back((unsigned char)((pattern & PAT_QAM_PHASE_MASK)/PAT_QAM_PHASE));
308  tr[ *this].m_zippedPatterns.push_back((unsigned char)(pos / 0x100) );
309  tr[ *this].m_zippedPatterns.push_back((unsigned char)(pos % 0x100) );
310  tr[ *this].m_zippedPatterns.push_back((unsigned char)(word / 0x100) );
311  tr[ *this].m_zippedPatterns.push_back((unsigned char)(word % 0x100) );
312  }
313  }
314  if(len > PATTERN_ZIPPED_COMMAND_DMA_LSET_END - PATTERN_ZIPPED_COMMAND_DMA_LSET_START) {
315  tr[ *this].m_zippedPatterns.push_back(PATTERN_ZIPPED_COMMAND_DMA_LSET_LONG);
316  tr[ *this].m_zippedPatterns.push_back((unsigned char)(len / 0x100) );
317  tr[ *this].m_zippedPatterns.push_back((unsigned char)(len % 0x100) );
318  tr[ *this].m_zippedPatterns.push_back((unsigned char)(pattern / 0x100) );
319  tr[ *this].m_zippedPatterns.push_back((unsigned char)(pattern % 0x100) );
320  }
321  else {
322  tr[ *this].m_zippedPatterns.push_back(PATTERN_ZIPPED_COMMAND_DMA_LSET_START + (unsigned char)len);
323  tr[ *this].m_zippedPatterns.push_back((unsigned char)(pattern / 0x100) );
324  tr[ *this].m_zippedPatterns.push_back((unsigned char)(pattern % 0x100) );
325  }
326  tr[ *this].m_lastPattern = pattern;
327  return 0;
328 }
329 
330 void
331 XSHPulser::changeOutput(const Snapshot &shot, bool output, unsigned int /*blankpattern*/) {
332  XScopedLock<XInterface> lock( *interface());
333  if( !interface()->isOpened())
334  return;
335 
336  if(output) {
337  if(shot[ *this].m_zippedPatterns.empty())
338  throw XInterface::XInterfaceError(i18n("Pulser Invalid pattern"), __FILE__, __LINE__);
339  for(unsigned int retry = 0; ; retry++) {
340  try {
341  interface()->write("!", 1); //poff
342  interface()->receive();
343  char buf[4];
344  if((interface()->scanf("Pulse %3s", buf) != 1) || strncmp(buf, "Off", 3))
345  throw XInterface::XConvError(__FILE__, __LINE__);
346  unsigned int size = shot[ *this].m_zippedPatterns.size();
347  interface()->sendf("$pload %x", size );
348  interface()->receive();
349  interface()->write(">", 1);
350  uint16_t sum = 0;
351  for(unsigned int i = 0; i < shot[ *this].m_zippedPatterns.size(); i++) {
352  sum += shot[ *this].m_zippedPatterns[i];
353  }
354  msecsleep(1);
355  interface()->write((char*) &shot[ *this].m_zippedPatterns[0], size);
356 
357  interface()->receive();
358  unsigned int ret;
359  if(interface()->scanf("%x", &ret) != 1)
360  throw XInterface::XConvError(__FILE__, __LINE__);
361  if(ret != sum)
362  throw XInterface::XInterfaceError(i18n("Pulser Check Sum Error"), __FILE__, __LINE__);
363  interface()->send("$pon");
364  interface()->receive();
365  if((interface()->scanf("Pulse %2s", buf) != 1) || strncmp(buf, "On", 2))
366  throw XInterface::XConvError(__FILE__, __LINE__);
367  }
368  catch (XKameError &e) {
369  if(retry > 1) throw e;
370  e.print(getLabel() + ": " + i18n("try to continue") + ", ");
371  continue;
372  }
373  break;
374  }
375  }
376  else {
377  //Pulser turned off.
378  interface()->write("!", 1); //poff
379  interface()->receive();
380  }
381 }
382 

Generated for KAME4 by  doxygen 1.8.3