source: hvcontrol/src/HV.cc@ 20

Last change on this file since 20 was 14, checked in by lstark, 16 years ago
first version of hvcontrol added
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 switch (chain) {
343
344 case 0: wbuf[0] = REG_HV0; break;
345 case 1: wbuf[0] = REG_HV1; break;
346 case 2: wbuf[0] = REG_HV2; break;
347 case 3: wbuf[0] = REG_HV3; break;
348
349 default : fprintf(fptr," Error: chain %d does not exist\n",chain); return 0;
350
351 }
352
353 // Assemble bytes
354 wbuf[0] |= (unsigned char)((channel >> 2) & 0X00000007); // Add address [A4-A3]
355 wbuf[1] |= (unsigned char)((hv >> 8) & 0X000000FF); // Add [D13-D8]
356 wbuf[1] |= (unsigned char)((channel << 6) & 0X000000C0); // Add [A1-A0]
357 wbuf[2] |= (unsigned char)(hv & 0X000000FF); // Add [D7-D0]
358
359
360 if (Write(wbuf,3) < 1) {
361 fprintf(fptr," Error: could not write to HV board\n");
362 return 0;
363 }
364
365 if (verbose)
366 fprintf(fptr," 3 bytes written:\n");
367
368 for (int i=0;i<3;i++) {
369 sPrintByteBin(wbuf[i],str);
370 if (verbose)
371 fprintf(fptr," Byte %d: %s| 0X%.2X\n",i,str,wbuf[i]);
372 }
373
374 return TRead(fptr,rbuf,verbose);
375
376}
377
378
379/* Set reference voltage - uses TRead() and has same return values */
380int HVBoard::SetVRef(FILE* fptr, int chain, unsigned int vref, unsigned char* rbuf, bool verbose) {
381
382 char str[STR_LENGTH];
383
384 unsigned char wbuf[] = {0,0,0};
385
386 if (!(vref>=0 && vref<=0X3FFF)) {
387 if (verbose)
388 fprintf(fptr," Error: vref beyond limits\n");
389 return 0;
390 }
391
392 switch (chain) {
393
394 case 0: wbuf[0] = REG_VREF0; break;
395 case 1: wbuf[0] = REG_VREF1; break;
396 case 2: wbuf[0] = REG_VREF2; break;
397 case 3: wbuf[0] = REG_VREF3; break;
398
399 default : fprintf(fptr," Error: chain %d does not exist\n",chain); return 0;
400
401 }
402
403 // Assemble bytes
404 wbuf[0] |= (unsigned char)((vref >> 13) & 0X0000000F); // Add [D13]
405 wbuf[1] |= (unsigned char)((vref >> 5) & 0X000000FF); // Add [D12-D5]
406 wbuf[2] |= (unsigned char)((vref << 3) & 0X000000FF); // Add [D4-D0]
407
408 // PD bits (device clear) are not used
409 wbuf[0] &= ~REG_PD1;
410 wbuf[0] &= ~REG_PD2;
411
412 if (Write(wbuf,3) < 1) {
413 fprintf(fptr," Error: could not write to HV board\n");
414 return 0;
415 }
416
417 if (verbose)
418 fprintf(fptr," 3 bytes written:\n");
419
420 for (int i=0;i<3;i++) {
421 sPrintByteBin(wbuf[i],str);
422 if (verbose)
423 fprintf(fptr," Byte %d: %s| 0X%.2X\n",i,str,wbuf[i]);
424 }
425
426 return TRead(fptr,rbuf,verbose);
427
428}
429
430
431/*
432 Init: initialize (synchronize) HV board - to be used before any other access!
433
434 Returns 0 if an error has occured, 1 on success.
435
436 Before any other access the HV board communication has to be synchronized.
437 Each write access requires three bytes to be sent from the computer to the
438 HV board. The HV board sends back one byte containing status information.
439
440 The normal initialization procedure would be the following:
441
442 1. send one byte (0X80 = REG_STATUS).
443 1.1. try reading as long as fTimeOut is not exceeded.
444
445 2. send again one byte (0X00).
446 2.1. try reading as long as fTimeOut is not exceeded.
447
448 3. send again one byte (0X00).
449 3.1. try reading again as long as fTimeOut is not exceeded.
450
451 Note: from time to time there are problems when performing only 3 trials! Reason:
452 the first byte written by libftdi can get lost somewhere between
453 libusb <-> kernel <-> FTDI chip. I haven't found yet any solution to this.
454 To solve the issue, another byte is sent to assure a proper synchronization,
455 even though the first byte was lost:
456
457 4. send again one byte (0X00).
458 4.1. try reading again as long as fTimeOut is not exceeded; if fTimeOut
459 has been exceeded return.
460
461 See also: http://lists.omnipotent.net/pipermail/lcdproc/2008-June/012235.html
462*/
463int HVBoard::Init(bool verbose) {
464
465 unsigned char wbuf = REG_STATUS;
466 unsigned char rbuf[STR_LENGTH];
467
468 int trial = 1;
469 int ret = 0;
470
471 long int t1, t2;
472
473
474 // First send 0X80
475 if (Write(&wbuf,1) < 1) {
476 if (verbose)
477 fprintf(stdout," Error: could not write to HV board\n");
478 return 0;
479 }
480 else
481 if (verbose)
482 fprintf(stdout," 1 byte written: 0X%.2X\n",wbuf);
483
484
485 t1 = GetMicroSeconds();
486
487
488 // Read - first trial
489 do {
490
491 t2 = GetMicroSeconds();
492
493 if ((ret = Read(rbuf,BUFFER_LENGTH)) < 1) {
494 if (verbose)
495 if (ret < 0) {
496 fprintf(stderr, " Read error: %d (%s)\n",ret,ftdi_get_error_string(FTDI_C));
497 return 0;
498 }
499 }
500 else {
501 if (verbose)
502 fprintf(stdout," %d byte(s) read:",ret);
503 for (int i=0;i<ret;i++)
504 if (verbose)
505 fprintf(stdout," 0X%.2X",rbuf[i]);
506 if (verbose)
507 fprintf(stdout,"\n");
508 fprintf(stdout," Success: initialization done (%d trial)\n",trial);
509 return 1;
510 }
511
512 if ((t2-t1)/1000000. > fTimeOut) {
513 if (verbose)
514 fprintf(stdout," Warning: timeout exceeded\n");
515 trial++;
516
517 // Second write
518 wbuf = 0;
519 if (Write(&wbuf,1) < 1) {
520 if (verbose)
521 fprintf(stdout," Error: could not write to HV board\n");
522 return 0;
523 }
524 else
525 if (verbose)
526 fprintf(stdout," 1 byte written: 0X%.2X\n",wbuf);
527
528 t1 = GetMicroSeconds();
529
530 // Read - second trial
531 do {
532
533 t2 = GetMicroSeconds();
534
535 if ((ret = Read(rbuf,BUFFER_LENGTH)) < 1) {
536 if (verbose)
537 if (ret < 0) {
538 fprintf(stderr, " Read error: %d (%s)\n",ret,ftdi_get_error_string(FTDI_C));
539 return 0;
540 }
541 }
542 else {
543 if (verbose)
544 fprintf(stdout," %d byte(s) read:",ret);
545 for (int i=0;i<ret;i++)
546 if (verbose)
547 fprintf(stdout," 0X%.2X",rbuf[i]);
548 if (verbose)
549 fprintf(stdout,"\n");
550 fprintf(stdout," Success: initialization done (%d trials)\n",trial);
551 return 1;
552 }
553
554 if ((t2-t1)/1000000. > fTimeOut) {
555 if (verbose)
556 fprintf(stdout," Warning: timeout exceeded\n");
557 trial++;
558
559 // Third write
560 wbuf = 0;
561 if (Write(&wbuf,1) < 1) {
562 if (verbose)
563 fprintf(stdout," Error: could not write to HV board\n");
564 return 0;
565 }
566 else
567 if (verbose)
568 fprintf(stdout," 1 byte written: 0X%.2X\n",wbuf);
569
570
571 // Read - third trial
572 do {
573
574 t2 = GetMicroSeconds();
575
576 if ((ret = Read(rbuf,BUFFER_LENGTH)) < 1) {
577 if (verbose)
578 if (ret < 0) {
579 fprintf(stderr, " Read error: %d (%s)\n",ret,ftdi_get_error_string(FTDI_C));
580 return 0;
581 }
582 }
583 else {
584 if (verbose)
585 fprintf(stdout," %d byte(s) read:",ret);
586 for (int i=0;i<ret;i++)
587 if (verbose)
588 fprintf(stdout," 0X%.2X",rbuf[i]);
589 if (verbose)
590 fprintf(stdout,"\n");
591 fprintf(stdout," Success: initialization done (%d trials)\n",trial);
592 return 1;
593 }
594
595
596 if ((t2-t1)/1000000. > fTimeOut) {
597 if (verbose)
598 fprintf(stdout," Warning: timeout exceeded\n");
599 trial++;
600
601 // Fourth write
602 wbuf = 0;
603 if (Write(&wbuf,1) < 1) {
604 if (verbose)
605 fprintf(stdout," Error: could not write to HV board\n");
606 return 0;
607 }
608 else
609 if (verbose)
610 fprintf(stdout," 1 byte written: 0X%.2X\n",wbuf);
611
612
613 // Read - fourth and last trial
614 do {
615
616 t2 = GetMicroSeconds();
617
618 if ((ret = Read(rbuf,BUFFER_LENGTH)) < 1) {
619 if (verbose)
620 if (ret < 0) {
621 fprintf(stderr, " Read error: %d (%s)\n",ret,ftdi_get_error_string(FTDI_C));
622 return 0;
623 }
624 }
625 else {
626 if (verbose)
627 fprintf(stdout," %d byte(s) read:",ret);
628 for (int i=0;i<ret;i++)
629 if (verbose)
630 fprintf(stdout," 0X%.2X",rbuf[i]);
631 if (verbose)
632 fprintf(stdout,"\n");
633 fprintf(stdout," Success: initialization done (%d trials)\n",trial);
634 return 1;
635 }
636
637 if ((t2-t1)/1000000. > fTimeOut) {
638 if (verbose)
639 fprintf(stdout," Error: timeout exceeded - initialization failed (%d trials)\n",trial);
640 return 0;
641
642 }
643
644 } while (1);
645
646 }
647
648 } while (1);
649
650 }
651
652 } while (1);
653
654 }
655
656 } while (1);
657
658
659 return 0;
660}
661
662
663/* Decode wrap counter */
664int HVBoard::DecodeWrap(unsigned char* rbuf) {
665
666 return (*rbuf & 0X07);
667
668}
669
670
671/* Decode over current bits */
672void HVBoard::DecodeOC(bool OC[], unsigned char* rbuf) {
673
674 for (int i=0;i<MAX_NUM_CHAINS;i++)
675 OC[i]=(*rbuf & (0X08 << i));
676}
677
678
679/* Decode bit indicating manual reset */
680bool HVBoard::DecodeReset(unsigned char* rbuf) {
681
682 return (bool)(*rbuf & 0X80);
683
684}
685
686
Note: See TracBrowser for help on using the repository browser.