source: hvcontrol/src/HV.cc@ 89

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