source: hvcontrol/src/HV.cc@ 70

Last change on this file since 70 was 35, checked in by lstark, 16 years ago
Calibration table (DAC - HV values) integrated
File size: 16.2 KB
Line 
1
2/********************************************************************\
3
4 Name: HV.cc
5
6 Created by: Sebastian Commichau, November 2008
7 commichau@phys.ethz.ch
8
9 Contents: Main class for HV supply
10
11 Requirements: Both libftdi and libusb are required for the
12 communication - see manual for more details.
13
14 libftdi: library for talking with FTDI USB <-> Serial
15 converter, UM245R.
16 http://www.intra2net.com/de/produkte/opensource/ftdi/
17
18 libusb: library for talking to USB devices from
19 user-space. Also needed by libftdi.
20 http://libusb.wiki.sourceforge.net/
21
22\********************************************************************/
23
24
25#include "HV.h"
26
27
28HV::HV(char** usbdevice, int* usbdevicenumber, FILE* f): fNumberOfBoards(0) {
29
30 int i = 0, j = 0, ret = 0;
31
32 char manufacturer[STR_LENGTH], type[STR_LENGTH], serial[STR_LENGTH];
33
34 bzero(manufacturer, sizeof(manufacturer));
35 bzero(type, sizeof(type));
36 bzero(serial, sizeof(serial));
37
38 fprintf(stdout,"Scan: ");
39
40 // Search for FTDI devices
41 for (i = 0;i<MAX_NUM_HVBOARDS;i++)
42 ftdi_init(&ftdic[i]);
43
44 ftdi_init(&ftdic_dummy);
45
46 if ((i = ftdi_usb_find_all(&ftdic_dummy, &devlist, USB_VENDOR, USB_PRODUCT)) < 0)
47 fprintf(stderr,"error: ftdi_usb_find_all failed: %d (%s)\n", i, ftdi_get_error_string(&ftdic_dummy));
48
49 fprintf(stdout,"found %d FTDI device(s)\n", i);
50 i = 0;
51
52 // Obtain information on FTDI devices
53 for (curdev = devlist; (curdev != NULL && i<MAX_NUM_HVBOARDS); i++) {
54
55 fprintf(stdout,"Device %d:\n", i);
56
57 if ((ret = ftdi_usb_get_strings(&ftdic_dummy, curdev->dev, manufacturer, STR_LENGTH, type, STR_LENGTH, serial, STR_LENGTH)) < 0) {
58 fprintf(stderr," Error: ftdi_usb_get_strings failed: %d (%s)\n", ret, ftdi_get_error_string(&ftdic_dummy));
59 break;
60 }
61
62 fprintf(stdout," Manufacturer: %s - Type: %s - Serial: %s\n", manufacturer, type, serial);
63
64 // Fixme: the following code should be revised!
65 while (j<MAX_NUM_HVBOARDS) {
66 if (strcmp(serial,usbdevice[j])==0)
67 break;
68 j++;
69 }
70
71 if (j<MAX_NUM_HVBOARDS) {
72 ret = ftdi_usb_open_desc(&ftdic[fNumberOfBoards], USB_VENDOR, USB_PRODUCT, type, serial);
73
74 // Fixme: this function does not work properly if there is more than one device???!!!
75 // ret = ftdi_usb_open(&ftdic[fNumberOfBoards], USB_VENDOR, USB_PRODUCT);
76
77 if (ret < 0 && ret != -5)
78 fprintf(stderr," Error: unable to open FTDI device: %d (%s)\n", i, ftdi_get_error_string(&ftdic[fNumberOfBoards]));
79 else {
80
81 ftdi_set_baudrate(&ftdic[fNumberOfBoards], USB_BAUDRATE);
82 ftdi_usb_reset(&ftdic[fNumberOfBoards]);
83 ftdi_usb_purge_buffers(&ftdic[fNumberOfBoards]);
84 /*
85 The FTDI chip keeps data in the internal buffer for a specific
86 amount of time if the buffer is not full yet to decrease load on the usb bus.
87 */
88 ftdi_set_latency_timer(&ftdic[fNumberOfBoards], USB_LATENCY_TIMER);
89
90 fHVBoard[fNumberOfBoards] = new HVBoard(serial, usbdevicenumber[j], &ftdic[fNumberOfBoards]);
91 fNumberOfBoards++;
92 /*
93 fprintf(stdout," FTDI open succeeded\n");
94 fprintf(stdout," Baudrate: %d\n", ftdic[i].baudrate);
95 fprintf(stdout," USB_read_timeout: %d\n", ftdic[i].usb_read_timeout);
96 fprintf(stdout," USB_write_timeout: %d\n", ftdic[i].usb_write_timeout);
97 */
98 }
99
100 }
101 else
102 fprintf(stdout," Warning: found new USB device - check configuration file!\n");
103
104 j=0;
105
106 curdev = curdev->next;
107 }
108
109 // Re-order board numbering otherwise it is determined by the connection sequence
110 ArrangeHVBoards(fHVBoard,fNumberOfBoards);
111
112}
113
114
115/* Bubble-sort HV boards according to board number */
116void HV::ArrangeHVBoards(HVBoard** fHVBoard, int size) {
117
118 HVBoard* tmp;
119
120 for (int i=size-1;i>0;--i)
121 for (int pos=0;pos<i;++pos)
122 if (fHVBoard[pos]->GetBoardNumber()>fHVBoard[pos+1]->GetBoardNumber()) {
123 tmp = fHVBoard[pos];
124 fHVBoard[pos] = fHVBoard[pos+1];
125 fHVBoard[pos+1] = tmp;
126 }
127
128}
129
130
131HV::~HV() {
132
133 int i, ret = 0;
134
135 for (i=0;i<fNumberOfBoards;i++) {
136 fprintf(stdout,"Device %d: ",i);
137
138 ret = ftdi_usb_close(&ftdic[i]);
139
140 if (ret < 0)
141 fprintf(stderr, "Unable to close FTDI device: %d (%s)\n", i, ftdi_get_error_string(&ftdic[i]));
142 else
143 fprintf(stdout, "FTDI close succeeded\n");
144
145 delete fHVBoard[i];
146 }
147
148 fprintf(stdout,"FTDI list free\n");
149 ftdi_list_free(&devlist);
150
151 for (i=0;i<MAX_NUM_HVBOARDS;i++)
152 ftdi_deinit(&ftdic[i]);
153
154 ftdi_deinit(&ftdic_dummy);
155
156}
157
158
159HVBoard::HVBoard(char* serial, int number, struct ftdi_context* ftdic) : fTimeOut(.5)
160{
161
162 FTDI_C = ftdic;
163 sprintf(Serial,"%s",serial);
164 BoardNumber = number;
165
166}
167
168
169HVBoard::~HVBoard() {
170
171}
172
173
174/* For test purposes only - never use this function with a real HV board!!! */
175void HVBoard::TestIO() {
176
177 int ret = 0, werrors = 0, rerrors = 0, mismatches = 0;
178
179 unsigned char wbuf[BUFFER_LENGTH], rbuf[BUFFER_LENGTH];
180
181 for (int i=0;i<=0XFF;i++) {
182
183 wbuf[0] = (unsigned char)i;
184
185#ifdef DO_CAST
186 ret = ftdi_write_data(FTDI_C,(char*)wbuf,1);
187#endif
188 ret = ftdi_write_data(FTDI_C,wbuf,1);
189
190 if (ret < 0)
191 werrors++;
192
193#ifdef DO_CAST
194 ret = ftdi_read_data(FTDI_C,(char*)rbuf,1);
195#endif
196 ret = ftdi_write_data(FTDI_C,wbuf,1);
197
198 if (ret < 0)
199 rerrors++;
200
201 if (rbuf[0]!=wbuf[0]) {
202 mismatches++;
203 fprintf(stdout,"Mismatch - written: 0X%.2X read: 0X%.2X\n",wbuf[0],rbuf[0]);
204 }
205 }
206 fprintf(stdout, "Result: %d write errors, %d read errors, %d mismatches\n",werrors,rerrors,mismatches);
207}
208
209
210int HVBoard::Write(unsigned char* data, int size) {
211#ifdef DO_CAST
212 return ftdi_write_data(FTDI_C, (char*)data, size);
213#endif
214 return ftdi_write_data(FTDI_C, data, size);
215}
216
217
218int HVBoard::Read(unsigned char* data, int size) {
219#ifdef DO_CAST
220 return ftdi_read_data(FTDI_C, (char*)data, size);
221#endif
222 return ftdi_read_data(FTDI_C, data, size);
223}
224
225
226/*
227 TRead: read from HV Board until fTimeOut has been reached
228
229 Returns:
230 0 if a read error has occured
231 1 on success
232 -1 if fTimeOut [s] has been exceeded
233*/
234int HVBoard::TRead(FILE* fptr, unsigned char* rbuf, bool verbose) {
235
236 char str[STR_LENGTH];
237
238 long int t1, t2;
239 int ret = 0;
240
241 t1 = GetMicroSeconds();
242
243 do {
244
245 if ((ret = Read(rbuf,BUFFER_LENGTH)) < 1) {
246 if (verbose)
247 if (ret < 0) {
248 fprintf(stderr, " Read error: %d (%s)\n", ret, ftdi_get_error_string(FTDI_C));
249 return 0;
250 }
251 }
252 else {
253
254 if (verbose)
255 fprintf(fptr," %d byte(s) read:\n",ret);
256
257 for (int i=0;i<ret;i++) {
258 sPrintByteBin(rbuf[i],str);
259 if (verbose)
260 fprintf(fptr," Byte %d: %s| 0X%.2X\n",i,str,rbuf[i]);
261 }
262 return 1;
263 }
264
265 t2 = GetMicroSeconds();
266
267 if ((t2-t1)/1000000. >= fTimeOut) {
268 fprintf(fptr," Warning: timeout exceeded\n");
269 return -1;
270 }
271
272 } while(1);
273
274}
275
276
277/* Reset HV board - uses TRead() and has same return values */
278int HVBoard::Reset(FILE* fptr, unsigned char* rbuf, bool verbose) {
279
280 char str[STR_LENGTH];
281
282 unsigned char wbuf[] = {REG_RESET,0,0};
283
284 if (Write(wbuf,3) < 1) {
285 fprintf(fptr," Error: could not write to HV board\n");
286 return 0;
287 }
288
289 if (verbose)
290 fprintf(fptr," 3 bytes written:\n");
291
292 for (int i=0;i<3;i++) {
293 sPrintByteBin(wbuf[i],str);
294 if (verbose)
295 fprintf(fptr," Byte %d: %s| 0X%.2X\n",i,str,wbuf[i]);
296 }
297
298 return TRead(fptr,rbuf,verbose);
299
300}
301
302
303/* Read status register - uses TRead() and has same return values */
304int HVBoard::GetStatus(FILE* fptr, unsigned char* rbuf, bool verbose) {
305
306 char str[STR_LENGTH];
307
308 unsigned char wbuf[] = {REG_STATUS,0,0};
309
310 if (Write(wbuf,3) < 1) {
311 if (verbose)
312 fprintf(fptr," Error: could not write to HV board\n");
313 return 0;
314 }
315
316 if (verbose)
317 fprintf(fptr," 3 bytes written:\n");
318
319 for (int i=0;i<3;i++) {
320 sPrintByteBin(wbuf[i],str);
321 if (verbose)
322 fprintf(fptr," Byte %d: %s| 0X%.2X\n",i,str,wbuf[i]);
323 }
324
325 return TRead(fptr,rbuf,verbose);
326
327}
328
329
330/* Set high voltage - uses TRead() and has same return values */
331int HVBoard::SetHV(FILE* fptr, int chain, unsigned int channel, unsigned int hv, unsigned char* rbuf, bool verbose) {
332
333 char str[STR_LENGTH];
334
335 unsigned char wbuf[] = {0,0,0};
336
337 if (!(hv>=0.0 && hv<=0X3FFF)) {
338 fprintf(fptr," Error: HV beyond limits [0 - 0x3FFF]\n");
339 return 0;
340 }
341
342
343 switch (chain) {
344
345 case 0: wbuf[0] = REG_HV0; break;
346 case 1: wbuf[0] = REG_HV1; break;
347 case 2: wbuf[0] = REG_HV2; break;
348 case 3: wbuf[0] = REG_HV3; break;
349
350 default : fprintf(fptr," Error: chain %d does not exist\n",chain); return 0;
351
352 }
353
354 // Assemble bytes
355 wbuf[0] |= (unsigned char)((channel >> 2) & 0X00000007); // Add address [A4-A3]
356 wbuf[1] |= (unsigned char)((hv >> 8) & 0X000000FF); // Add [D13-D8]
357 wbuf[1] |= (unsigned char)((channel << 6) & 0X000000C0); // Add [A1-A0]
358 wbuf[2] |= (unsigned char)(hv & 0X000000FF); // Add [D7-D0]
359
360
361 if (Write(wbuf,3) < 1) {
362 fprintf(fptr," Error: could not write to HV board\n");
363 return 0;
364 }
365
366 if (verbose)
367 fprintf(fptr," 3 bytes written:\n");
368
369 for (int i=0;i<3;i++) {
370 sPrintByteBin(wbuf[i],str);
371 if (verbose)
372 fprintf(fptr," Byte %d: %s| 0X%.2X\n",i,str,wbuf[i]);
373 }
374
375 return TRead(fptr,rbuf,verbose);
376
377}
378
379
380/* Set reference voltage - uses TRead() and has same return values */
381int HVBoard::SetVRef(FILE* fptr, int chain, unsigned int vref, unsigned char* rbuf, bool verbose) {
382
383 char str[STR_LENGTH];
384
385 unsigned char wbuf[] = {0,0,0};
386
387 if (!(vref>=0 && vref<=0X3FFF)) {
388 if (verbose)
389 fprintf(fptr," Error: vref beyond limits\n");
390 return 0;
391 }
392
393 switch (chain) {
394
395 case 0: wbuf[0] = REG_VREF0; break;
396 case 1: wbuf[0] = REG_VREF1; break;
397 case 2: wbuf[0] = REG_VREF2; break;
398 case 3: wbuf[0] = REG_VREF3; break;
399
400 default : fprintf(fptr," Error: chain %d does not exist\n",chain); return 0;
401
402 }
403
404 // Assemble bytes
405 wbuf[0] |= (unsigned char)((vref >> 13) & 0X0000000F); // Add [D13]
406 wbuf[1] |= (unsigned char)((vref >> 5) & 0X000000FF); // Add [D12-D5]
407 wbuf[2] |= (unsigned char)((vref << 3) & 0X000000FF); // Add [D4-D0]
408
409 // PD bits (device clear) are not used
410 wbuf[0] &= ~REG_PD1;
411 wbuf[0] &= ~REG_PD2;
412
413 if (Write(wbuf,3) < 1) {
414 fprintf(fptr," Error: could not write to HV board\n");
415 return 0;
416 }
417
418 if (verbose)
419 fprintf(fptr," 3 bytes written:\n");
420
421 for (int i=0;i<3;i++) {
422 sPrintByteBin(wbuf[i],str);
423 if (verbose)
424 fprintf(fptr," Byte %d: %s| 0X%.2X\n",i,str,wbuf[i]);
425 }
426
427 return TRead(fptr,rbuf,verbose);
428
429}
430
431
432/*
433 Init: initialize (synchronize) HV board - to be used before any other access!
434
435 Returns 0 if an error has occured, 1 on success.
436
437 Before any other access the HV board communication has to be synchronized.
438 Each write access requires three bytes to be sent from the computer to the
439 HV board. The HV board sends back one byte containing status information.
440
441 The normal initialization procedure would be the following:
442
443 1. send one byte (0X80 = REG_STATUS).
444 1.1. try reading as long as fTimeOut is not exceeded.
445
446 2. send again one byte (0X00).
447 2.1. try reading as long as fTimeOut is not exceeded.
448
449 3. send again one byte (0X00).
450 3.1. try reading again as long as fTimeOut is not exceeded.
451
452 Note: from time to time there are problems when performing only 3 trials! Reason:
453 the first byte written by libftdi can get lost somewhere between
454 libusb <-> kernel <-> FTDI chip. I haven't found yet any solution to this.
455 To solve the issue, another byte is sent to assure a proper synchronization,
456 even though the first byte was lost:
457
458 4. send again one byte (0X00).
459 4.1. try reading again as long as fTimeOut is not exceeded; if fTimeOut
460 has been exceeded return.
461
462 See also: http://lists.omnipotent.net/pipermail/lcdproc/2008-June/012235.html
463*/
464int HVBoard::Init(bool verbose) {
465
466 unsigned char wbuf = REG_STATUS;
467 unsigned char rbuf[STR_LENGTH];
468
469 int trial = 1;
470 int ret = 0;
471
472 long int t1, t2;
473
474
475 // First send 0X80
476 if (Write(&wbuf,1) < 1) {
477 if (verbose)
478 fprintf(stdout," Error: could not write to HV board\n");
479 return 0;
480 }
481 else
482 if (verbose)
483 fprintf(stdout," 1 byte written: 0X%.2X\n",wbuf);
484
485
486 t1 = GetMicroSeconds();
487
488
489 // Read - first trial
490 do {
491
492 t2 = GetMicroSeconds();
493
494 if ((ret = Read(rbuf,BUFFER_LENGTH)) < 1) {
495 if (verbose)
496 if (ret < 0) {
497 fprintf(stderr, " Read error: %d (%s)\n",ret,ftdi_get_error_string(FTDI_C));
498 return 0;
499 }
500 }
501 else {
502 if (verbose)
503 fprintf(stdout," %d byte(s) read:",ret);
504 for (int i=0;i<ret;i++)
505 if (verbose)
506 fprintf(stdout," 0X%.2X",rbuf[i]);
507 if (verbose)
508 fprintf(stdout,"\n");
509 fprintf(stdout," Success: initialization done (%d trial)\n",trial);
510 return 1;
511 }
512
513 if ((t2-t1)/1000000. > fTimeOut) {
514 if (verbose)
515 fprintf(stdout," Warning: timeout exceeded\n");
516 trial++;
517
518 // Second write
519 wbuf = 0;
520 if (Write(&wbuf,1) < 1) {
521 if (verbose)
522 fprintf(stdout," Error: could not write to HV board\n");
523 return 0;
524 }
525 else
526 if (verbose)
527 fprintf(stdout," 1 byte written: 0X%.2X\n",wbuf);
528
529 t1 = GetMicroSeconds();
530
531 // Read - second trial
532 do {
533
534 t2 = GetMicroSeconds();
535
536 if ((ret = Read(rbuf,BUFFER_LENGTH)) < 1) {
537 if (verbose)
538 if (ret < 0) {
539 fprintf(stderr, " Read error: %d (%s)\n",ret,ftdi_get_error_string(FTDI_C));
540 return 0;
541 }
542 }
543 else {
544 if (verbose)
545 fprintf(stdout," %d byte(s) read:",ret);
546 for (int i=0;i<ret;i++)
547 if (verbose)
548 fprintf(stdout," 0X%.2X",rbuf[i]);
549 if (verbose)
550 fprintf(stdout,"\n");
551 fprintf(stdout," Success: initialization done (%d trials)\n",trial);
552 return 1;
553 }
554
555 if ((t2-t1)/1000000. > fTimeOut) {
556 if (verbose)
557 fprintf(stdout," Warning: timeout exceeded\n");
558 trial++;
559
560 // Third write
561 wbuf = 0;
562 if (Write(&wbuf,1) < 1) {
563 if (verbose)
564 fprintf(stdout," Error: could not write to HV board\n");
565 return 0;
566 }
567 else
568 if (verbose)
569 fprintf(stdout," 1 byte written: 0X%.2X\n",wbuf);
570
571
572 // Read - third trial
573 do {
574
575 t2 = GetMicroSeconds();
576
577 if ((ret = Read(rbuf,BUFFER_LENGTH)) < 1) {
578 if (verbose)
579 if (ret < 0) {
580 fprintf(stderr, " Read error: %d (%s)\n",ret,ftdi_get_error_string(FTDI_C));
581 return 0;
582 }
583 }
584 else {
585 if (verbose)
586 fprintf(stdout," %d byte(s) read:",ret);
587 for (int i=0;i<ret;i++)
588 if (verbose)
589 fprintf(stdout," 0X%.2X",rbuf[i]);
590 if (verbose)
591 fprintf(stdout,"\n");
592 fprintf(stdout," Success: initialization done (%d trials)\n",trial);
593 return 1;
594 }
595
596
597 if ((t2-t1)/1000000. > fTimeOut) {
598 if (verbose)
599 fprintf(stdout," Warning: timeout exceeded\n");
600 trial++;
601
602 // Fourth write
603 wbuf = 0;
604 if (Write(&wbuf,1) < 1) {
605 if (verbose)
606 fprintf(stdout," Error: could not write to HV board\n");
607 return 0;
608 }
609 else
610 if (verbose)
611 fprintf(stdout," 1 byte written: 0X%.2X\n",wbuf);
612
613
614 // Read - fourth and last trial
615 do {
616
617 t2 = GetMicroSeconds();
618
619 if ((ret = Read(rbuf,BUFFER_LENGTH)) < 1) {
620 if (verbose)
621 if (ret < 0) {
622 fprintf(stderr, " Read error: %d (%s)\n",ret,ftdi_get_error_string(FTDI_C));
623 return 0;
624 }
625 }
626 else {
627 if (verbose)
628 fprintf(stdout," %d byte(s) read:",ret);
629 for (int i=0;i<ret;i++)
630 if (verbose)
631 fprintf(stdout," 0X%.2X",rbuf[i]);
632 if (verbose)
633 fprintf(stdout,"\n");
634 fprintf(stdout," Success: initialization done (%d trials)\n",trial);
635 return 1;
636 }
637
638 if ((t2-t1)/1000000. > fTimeOut) {
639 if (verbose)
640 fprintf(stdout," Error: timeout exceeded - initialization failed (%d trials)\n",trial);
641 return 0;
642
643 }
644
645 } while (1);
646
647 }
648
649 } while (1);
650
651 }
652
653 } while (1);
654
655 }
656
657 } while (1);
658
659
660 return 0;
661}
662
663
664/* Decode wrap counter */
665int HVBoard::DecodeWrap(unsigned char* rbuf) {
666
667 return (*rbuf & 0X07);
668
669}
670
671
672/* Decode over current bits */
673void HVBoard::DecodeOC(bool OC[], unsigned char* rbuf) {
674
675 for (int i=0;i<MAX_NUM_CHAINS;i++)
676 OC[i]=(*rbuf & (0X08 << i));
677}
678
679
680/* Decode bit indicating manual reset */
681bool HVBoard::DecodeReset(unsigned char* rbuf) {
682
683 return (bool)(*rbuf & 0X80);
684
685}
686
687
Note: See TracBrowser for help on using the repository browser.