driver_obs_obsdaq.cpp 37.4 KB
Newer Older
Achim Morschhauser's avatar
Achim Morschhauser committed
1
2
3
4
5
6
7
8
9
10
11
12
/*******************************************************************************
 *******************************************************************************
 * 
 *  WRITTEN BY ACHIM MORSCHHAUSER, GFZ POTSDAM, 2016-2018                     
 *  mors//gfz-potsdam.de							       
 *									       
 * This class provides the driver for an OBSDAQ ADC.			       
 * 									       
 * It is based on the abstract observatory driver class driver_obs.		
 *									
 *******************************************************************************
 ******************************************************************************/
Achim Morschhauser's avatar
Achim Morschhauser committed
13
14
15
16
17
18
19
20
21
22
23
24
25

// C headers
#include <time.h>     				// System time functions
#include <unistd.h>   				// usleep
#include <stdio.h>    				// printf
#include <stdlib.h>   				// itoa
#include <string.h>   				// strcmp
#include <inttypes.h> 				// int32_t

// C++ headers
#include <sstream>
#include <iostream>
#include <iomanip>
Achim Morschhauser's avatar
Achim Morschhauser committed
26
#include <unordered_map>
27
#include <algorithm>				// for making string uppercase
Achim Morschhauser's avatar
Achim Morschhauser committed
28

Achim Morschhauser's avatar
Achim Morschhauser committed
29
// Library C++ headers
Achim Morschhauser's avatar
Achim Morschhauser committed
30
#include <buffer_obs.hpp>     		// Buffer for data
Achim Morschhauser's avatar
Achim Morschhauser committed
31
#include <data_obs_vector.hpp>          // Vector data structure
Achim Morschhauser's avatar
Achim Morschhauser committed
32
#include <driver_obs_obsdaq.hpp>	// Generic observatory driver
33
#include <Obs_Calibration_Vector.hpp>   // Calibration routines
Achim Morschhauser's avatar
Achim Morschhauser committed
34

Achim Morschhauser's avatar
Achim Morschhauser committed
35
36
37
38
39
40
41
42
43
44
45
/*******************************************************************************
 *******************************************************************************
 *																			*
 * 				Initialize static variables												*
 *																			*
 *******************************************************************************
 ******************************************************************************/

// Baud rate codes (Table 5 of Manual)
const std::unordered_map<int,std::string> driver_obs_obsdaq::map_baud(
    {{1200,"03"},{2400,"04"},{4800,"05"},{9600,"06"},{19200,"07"},
Achim Morschhauser's avatar
Achim Morschhauser committed
46
     {38400,"08"},{57600,"09"},{115200,"0A"},{307200,"0B"},{614400,"0C"}});
Achim Morschhauser's avatar
Achim Morschhauser committed
47

Achim Morschhauser's avatar
Achim Morschhauser committed
48
49
/*******************************************************************************
 *******************************************************************************
Achim Morschhauser's avatar
Achim Morschhauser committed
50
51
52
 *																			*
 * 				Constructors.												*
 *																			*
Achim Morschhauser's avatar
Achim Morschhauser committed
53
54
 *******************************************************************************
 ******************************************************************************/
Achim Morschhauser's avatar
Achim Morschhauser committed
55

Achim Morschhauser's avatar
Achim Morschhauser committed
56
/*******************************************************************************
Achim Morschhauser's avatar
Achim Morschhauser committed
57
58
59
60
61
*																			*
* Automatically determine the baud rate.									*
*																			*
* Default address is broadcast address: 0x0F.								*
*																			*
Achim Morschhauser's avatar
Achim Morschhauser committed
62
*******************************************************************************/
Achim Morschhauser's avatar
Achim Morschhauser committed
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
driver_obs_obsdaq::driver_obs_obsdaq(std::string port, buffer_obs* buffer,
		Obs_Calibration_Vector* cal, int addr) :
		Driver_Obs_Serial(port, buffer, cal) {

	// Set the termination characters for the serial port driver
	set_term();

	// Set the RS485 address
	RS485_addr = addr;
	char addr_str[3];
	sprintf(addr_str, "%02X", addr);
	RS485_addrstr = std::string(addr_str);

	// Check for baud rate with the right address.
	// Stop any running measurement when doing so.
Achim Morschhauser's avatar
Achim Morschhauser committed
78
        find_baud();
79
        stop();
Achim Morschhauser's avatar
Achim Morschhauser committed
80
81
82
83
84
85
86
87
88
89
90
91
92

	// Initialize the OBSDAQ
	init();

}

/****************************************************************************
*																			*
* Pre-defined baud rate.													*
* 																			*
* Default address is broadcast address: 0x0F.								*
*																			*
****************************************************************************/
Achim Morschhauser's avatar
Achim Morschhauser committed
93
94
driver_obs_obsdaq::driver_obs_obsdaq(std::string port, int baud, 
                buffer_obs* buffer, Obs_Calibration_Vector* cal, int addr) :
Achim Morschhauser's avatar
Achim Morschhauser committed
95
				Driver_Obs_Serial(port, buffer, cal) {
Achim Morschhauser's avatar
Achim Morschhauser committed
96
97

	// Set the termination characters for serial port driver
98
	set_term();
Achim Morschhauser's avatar
Achim Morschhauser committed
99
100
101
102
103
104
105

	// Set the RS485 address
	RS485_addr = addr;
	char addr_str[3];
	sprintf(addr_str, "%02X", addr);
	RS485_addrstr = std::string(addr_str);

Achim Morschhauser's avatar
Achim Morschhauser committed
106
107
108
109
110
111
112
113
114
115
116
117
118
119
	// Check if given baud rate is correct
	// Find correct baudrate if necessary
	switch (check_baud(baud)) {
	case 2:
		stop();
		break;
	case 1:
		break;
	default:
		find_baud();
		stop();
		set_baud(baud);
		break;
	}
120
        
Achim Morschhauser's avatar
Achim Morschhauser committed
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
	// Initialize
	init();

}

/****************************************************************************
 ****************************************************************************
 *																			*
 * 			      Public Methods.											*
 *																			*
 ****************************************************************************
 ***************************************************************************/

/****************************************************************************
 *																		 	*
 * Take a single measurement.												*
 *																			*
 * Only passes the time, as data_obs can't store data values.				*
 *																			*
 ***************************************************************************/

int driver_obs_obsdaq::get(data_obs* data) {

	data_obs_vector fdata = data_obs_vector();
	get(&fdata);
	data->set_time(&fdata);

	return (0);

}

/****************************************************************************
 *																		 	*
 * Take a single measurement.												*
 *																			*
 ***************************************************************************/
int driver_obs_obsdaq::get(data_obs_vector* data) {

	/////////////////////////////////////////////////////////////////////////
	//
	// Some variables.
	//
	/////////////////////////////////////////////////////////////////////////

	// Time of measurement
	struct timespec recv_time;

	// Receive buffer
169
	char buf[100]="";
Achim Morschhauser's avatar
Achim Morschhauser committed
170
171
172
173
174
175
176
177
178
179
180
181
182
183

	/////////////////////////////////////////////////////////////////////////
	//
	// Do the measurement.
	//
	/////////////////////////////////////////////////////////////////////////

	// Stop free-run mode (just in case).
	stop();

	// Synchronize channels
	send("#PP10000500");
	usleep(200e3);
	send("#PP00000000");
Tobias Bjerg's avatar
Tobias Bjerg committed
184
185
	int res=sleep(5);
        std::cerr << "PROBLEM WIH SLEEP: " << res << std::endl;
Achim Morschhauser's avatar
Achim Morschhauser committed
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227

	// Ask for latest values.
	send("#A");

	// Wait for answer
	if (receive(buf, sizeof(buf), 1, &recv_time) >= 0) {

		// Parse data from answer
		if (parse_data_ascii(data, buf) >= 0){

			// Set the time
			data->set_time(&recv_time);

			return(0);

		}

	}

	return (-1);

}

/****************************************************************************
 *									 										*
 * Run the OBSDAQ in triggered mode (NOT YET WORKING).						*
 *																			*
 ***************************************************************************/
//TODO This is a stub.
int driver_obs_obsdaq::run(double freq) {

	/////////////////////////////////////////////////////////////////////////
	//
	// Some variables.
	//
	/////////////////////////////////////////////////////////////////////////

	// Time of measurement
	struct timespec recv_time, time;
	// The data
	data_obs_vector data;
	// The receive buffer
228
	char buf[200]="";
Achim Morschhauser's avatar
Achim Morschhauser committed
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278

	/////////////////////////////////////////////////////////////////////////
	//
	// Initialize: Set frequency and calibrate.
	//
	/////////////////////////////////////////////////////////////////////////

	if (init_run(freq)<0){
		return(-1);
	}

	/////////////////////////////////////////////////////////////////////////
	//
	// Start continuous measurement
	//
	/////////////////////////////////////////////////////////////////////////

	/////////////////////////////////////////////////////////////////////////
	//
	// Listen to continuous measurement
	//
	/////////////////////////////////////////////////////////////////////////
	// Infinite loop
	while (1) {

		// Get the current time
		clock_gettime(CLOCK_REALTIME, &time);

		// Wait for answer
		if (receive(buf, sizeof(buf), 1, &recv_time) >= 0) {

			// Parse data from answer
			if (parse_data_ascii(&data, buf) >= 0){

				// Set the time
				data.set_time(&recv_time);

				// Write measurement to buffer
				buffer->put(&data);

			}

		}

	}

}

/****************************************************************************
 *									 										*
Achim Morschhauser's avatar
Achim Morschhauser committed
279
 * Run the OBSDAQ in freerun mode (no triggering).							*
Achim Morschhauser's avatar
Achim Morschhauser committed
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
 *																			*
 ***************************************************************************/
int driver_obs_obsdaq::freerun(double freq) {

	/////////////////////////////////////////////////////////////////////////
	//
	// Some variables.
	//
	/////////////////////////////////////////////////////////////////////////

	// Time of measurement
	struct timespec recv_time, time;
	// The vector data
	data_obs_vector data;
	// The receive buffer
295
	char buf[200]="";
Achim Morschhauser's avatar
Achim Morschhauser committed
296
297
298
	// Data parser function
	int (driver_obs_obsdaq::*parse_data)(data_obs_vector* data, char* buf);
	//std::function<int(data_obs_vector* data, char* buf)> &parse_data;
Achim Morschhauser's avatar
Achim Morschhauser committed
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317

	/////////////////////////////////////////////////////////////////////////
	//
	// Initialize: Set frequency and calibrate.
	//
	/////////////////////////////////////////////////////////////////////////

	if (init_run(freq)<0){
		return(-1);
	}

	/////////////////////////////////////////////////////////////////////////
	//
	// Starting freerun mode.
	//
	/////////////////////////////////////////////////////////////////////////

	// Channel synchronization
	send("#PP10000500");
Tobias Bjerg's avatar
Tobias Bjerg committed
318
	usleep(200e3);
Achim Morschhauser's avatar
Achim Morschhauser committed
319
	send("#PP00000000");
Tobias Bjerg's avatar
Tobias Bjerg committed
320
	usleep(2e6);
Achim Morschhauser's avatar
Achim Morschhauser committed
321

Achim Morschhauser's avatar
GNUPLOT    
Achim Morschhauser committed
322
	// Flush
323
        usleep(1e6);
Achim Morschhauser's avatar
GNUPLOT    
Achim Morschhauser committed
324
325
	flush();
	
Achim Morschhauser's avatar
Achim Morschhauser committed
326
	if (driver_obs::freq < 10.0){
Achim Morschhauser's avatar
Achim Morschhauser committed
327
328
329
330
331
332
333
334
		// Use ASCII mode
		checked_send("#CS","",0,1);
		parse_data = &driver_obs_obsdaq::parse_data_ascii;
	} else {
		// Use binary mode
		checked_send("#CB","",0,1);
		parse_data = &driver_obs_obsdaq::parse_data_bin;
	}
Achim Morschhauser's avatar
GNUPLOT    
Achim Morschhauser committed
335
		
Achim Morschhauser's avatar
Achim Morschhauser committed
336
337
338
339
340
341
342
343
344
345
346
347
348
349

	/////////////////////////////////////////////////////////////////////////
	//
	// Listen to continuous measurement
	//
	/////////////////////////////////////////////////////////////////////////

	// Counting variable (Class variable)
	supp_count=0;

	// Infinite loop
	while (1) {

		// Receive data
Achim Morschhauser's avatar
Achim Morschhauser committed
350
		if (receive(buf, sizeof(buf), 0, &recv_time) >= 0) {
Achim Morschhauser's avatar
Achim Morschhauser committed
351

352
			//fprintf(stderr,"Received: %s\n",buf);
Achim Morschhauser's avatar
Achim Morschhauser committed
353
354
355
356
357

			// Set the time
			data.set_time(&recv_time);

			// Parse data from answer
Achim Morschhauser's avatar
Achim Morschhauser committed
358
			if ( (this->*parse_data)(&data, buf) >= 0 ){
Achim Morschhauser's avatar
Achim Morschhauser committed
359

360
361
                            // Calibrate the measurement/ASCII
                            driver_obs::cal->calibrate(&data);
Achim Morschhauser's avatar
Achim Morschhauser committed
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383

			}

			// Write measurement to buffer
			buffer->put(&data);

		}

	}

	return (0);

}

/****************************************************************************
 *									 										*
 * 			Stop the running mode of the OBSDAQ.							*
 *																			*
 ***************************************************************************/
int driver_obs_obsdaq::stop() {

	// Receive buffer
384
	char stopstr[41]="||||||||||||||||||||||||||||||||||||||||";
Achim Morschhauser's avatar
Achim Morschhauser committed
385
386

	// Stop free-run mode
387
388
389
	send(stopstr);
	while (checked_send("$M","<ObsDaq",7,1,0) != 0) {
            send(stopstr);
Achim Morschhauser's avatar
Achim Morschhauser committed
390
391
392
393
394
395
396
	}

	return (0);

}

/****************************************************************************
397
398
399
400
401
402
403
404
405
406
 *
 * Auto-calibrate.
 *
 * Channels are auto-calibrated based on actual channel settings.
 * Calibration is not stored.
 *
 * IN:
 *  - repeat	int 	Number of calibration steps.
 *  		        Individual calibration steps are averaged.
 *
Achim Morschhauser's avatar
Achim Morschhauser committed
407
 ***************************************************************************/
408
409
int driver_obs_obsdaq::auto_calibrate(int channel, int repeat, 
        std::string config){
Achim Morschhauser's avatar
Achim Morschhauser committed
410

Achim Morschhauser's avatar
Achim Morschhauser committed
411
412
413
414
415
    /////////////////////////////////////////////////////////////////////////
    //
    // Some variables.
    //
    /////////////////////////////////////////////////////////////////////////
Achim Morschhauser's avatar
Achim Morschhauser committed
416

417
    char cmd[50], recv[50]="";
Achim Morschhauser's avatar
Achim Morschhauser committed
418

Achim Morschhauser's avatar
Achim Morschhauser committed
419
    uint32_t n32, num;
Achim Morschhauser's avatar
Achim Morschhauser committed
420

Achim Morschhauser's avatar
Achim Morschhauser committed
421
422
    // The calibration constants
    double offset=0, scale=0;
423
424
    // Calibration constants as string
    std::string offset_str, scale_str;
Achim Morschhauser's avatar
Achim Morschhauser committed
425

Achim Morschhauser's avatar
Achim Morschhauser committed
426
427
428
429
430
    /////////////////////////////////////////////////////////////////////////
    //
    // Initialize: Set triggering off.
    //
    /////////////////////////////////////////////////////////////////////////
Achim Morschhauser's avatar
Achim Morschhauser committed
431

Achim Morschhauser's avatar
Achim Morschhauser committed
432
433
434
    // Set triggering off
    send("#PP00000000");
    usleep(1e6);
Achim Morschhauser's avatar
Achim Morschhauser committed
435

Achim Morschhauser's avatar
Achim Morschhauser committed
436
437
438
439
440
    /////////////////////////////////////////////////////////////////////////
    //
    // Calibration
    //
    /////////////////////////////////////////////////////////////////////////
Achim Morschhauser's avatar
Update    
Achim Morschhauser committed
441
442
443
444

    //
    // Repeat calibration step
    //
Achim Morschhauser's avatar
Achim Morschhauser committed
445
446
447
448
449
450
451
452
453
454
455
456
457
    
    for (int k=1; k<=repeat; k++){

        usleep(1e6);

        // Calibration command (Manual 12.4.15)
        
        sprintf(cmd,"$%1dWCF0",channel);
        send(cmd);

        // Check if calibration is finished
        
        sprintf(cmd,"$%1dRR",channel);
Achim Morschhauser's avatar
Achim Morschhauser committed
458
        usleep(4.0/driver_obs::freq*1e6);
Achim Morschhauser's avatar
Achim Morschhauser committed
459
460
461
        while (checked_send(cmd,"R0",2,5)<0){
        }

462
        // Read the full-scale value
Achim Morschhauser's avatar
Achim Morschhauser committed
463
        
464
        sprintf(cmd,"$%1dRF",channel);
Achim Morschhauser's avatar
Achim Morschhauser committed
465
466
467
        send(cmd);
        //TODO Repeat loop instead of just omitting
        if (receive(recv,sizeof(recv),5)==0) {
468
                // Parse the full-scale value and add to average
Achim Morschhauser's avatar
Achim Morschhauser committed
469
470
                n32 = (uint32_t) strtoul(&recv[3], NULL, 16);
                num=0x800000L;
471
                scale += (double) (n32 ^ num) - (double) num;
Achim Morschhauser's avatar
Achim Morschhauser committed
472
        }
473
474
        
        // Necessary to avoid timeouts
Achim Morschhauser's avatar
Achim Morschhauser committed
475
476
        usleep(1e6);
        
477
478
479
        // Read the offset value
        
        sprintf(cmd,"$%1dRO",channel);
Achim Morschhauser's avatar
Achim Morschhauser committed
480
481
482
        send(cmd);
        //TODO Repeat loop instead of just omitting
        if (receive(recv,sizeof(recv),5)==0) {
483
                // Parse the offset value and add to average
Achim Morschhauser's avatar
Achim Morschhauser committed
484
485
                n32 = (uint32_t) strtoul(&recv[3], NULL, 16);
                num=0x800000L;
486
                offset += (double) (n32 ^ num) - (double) num;
Achim Morschhauser's avatar
Achim Morschhauser committed
487
488
489
        }

    }
Achim Morschhauser's avatar
Achim Morschhauser committed
490

Achim Morschhauser's avatar
Achim Morschhauser committed
491
492
493
494
    //
    // Calculate the average of calibration constants and send them to
    // OBSDAQ.
    //
495
    
496
    // Full-scale
497
498
499
500
    n32 = ((int32_t) (scale/repeat)  + (int32_t) 0x800000L)
                    ^ (int32_t) 0x800000L ;
    sprintf(cmd,"$%1dWF%06X",channel,n32);
    send(cmd);
Achim Morschhauser's avatar
Achim Morschhauser committed
501
    scale_str=std::string(cmd).substr(4,6);
502
    waitanswer(1);
Achim Morschhauser's avatar
Achim Morschhauser committed
503

504
    std::cerr << "Set scale: " << scale/repeat << " " << cmd << std::endl;
Achim Morschhauser's avatar
Achim Morschhauser committed
505

506
    // Offset
Achim Morschhauser's avatar
Achim Morschhauser committed
507
508
509
510
    n32 = ((int32_t) (offset/repeat) + (int32_t) 0x800000L)
                    ^ (int32_t) 0x800000L;
    sprintf(cmd,"$%1dWO%06X",channel,n32);
    send(cmd);
511
512
    offset_str=std::string(cmd).substr(4,6);
    waitanswer(1);
Achim Morschhauser's avatar
Achim Morschhauser committed
513

514
    std::cerr << "Set offset: " << offset/repeat << " " << cmd << std::endl;
Achim Morschhauser's avatar
Achim Morschhauser committed
515

516
517
518
519
520
    /////////////////////////////////////////////////////////////////////////
    //
    // Store the new calibration values
    //
    /////////////////////////////////////////////////////////////////////////
Achim Morschhauser's avatar
Achim Morschhauser committed
521
    cal->add_adc_calibrate(config,offset_str,scale_str,"AUTO-CALIBRATE");
522
    
Achim Morschhauser's avatar
Achim Morschhauser committed
523
    return(0);
Achim Morschhauser's avatar
Achim Morschhauser committed
524
525
526

}

527
528
529
530
531
532
533
534
535
536
537
538
539
540
/***************************************************************************
 *
 * Auto-calibrate.
 *
 * Channels are auto-calibrated based on actual channel settings.
 * Calibration is not stored.
 *
 * IN:
 *  - repeat	int 	Number of calibration steps.
 *  		        Individual calibration steps are averaged.
 *
 ***************************************************************************/
int driver_obs_obsdaq::full_calibrate(int channel, int repeat){
    
Achim Morschhauser's avatar
Achim Morschhauser committed
541
    return(0);
542
    
Achim Morschhauser's avatar
Achim Morschhauser committed
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
}

/****************************************************************************
 ****************************************************************************
 *																			*
 * 			      Protected Methods.											*
 *																			*
 ****************************************************************************
 ***************************************************************************/

/****************************************************************************
 *									 										*
 *	       Set the termination characters for OBSDAQ.						*
 *																			*
 ***************************************************************************/
int driver_obs_obsdaq::set_term() {

	char term[1];

	term[0] = 13;

	if (Driver_Obs_Serial::set_term(term, 1) < 0) {
		return (-1);
	}

	return (0);

}

/****************************************************************************
 ****************************************************************************
 *																			*
 * 			      Private Methods.											*
 *																			*
 ****************************************************************************
 ***************************************************************************/

/****************************************************************************
 *								 											*
 *	       Send an OBSDAQ command.											*
 *																			*
 ***************************************************************************/
int driver_obs_obsdaq::send(const char* cmd) {

	return (send((char *) cmd));

}

/****************************************************************************
 *																			*
 *	       Send an OBSDAQ command.											*
 *																			*
 ***************************************************************************/
int driver_obs_obsdaq::send(char* cmd) {

	std::string cmd_send;

	cmd_send = cmd[0] + RS485_addrstr + &cmd[1] + (char) 13;

	//TODO Customization with waiting time for baud 115200 should go here!
	//     Currently, this is done in driver_serial::send

	Driver_Obs_Serial::send(cmd_send.c_str());

	return (0);

}

/****************************************************************************
 *									 										*
 *	    Send an OBSDAQ command to address of serial port and check reply	*
 *																			*
 * IN:																		*
 *  - cmd		const char*			Command to send							*
 *  - reply		const char*			Expected reply							*
 *  - digits	int					Number of 'digits' first characters 	*
 *                                  that are checked to match the received	*
 *                                  answer.									*
 *  - timeout	double				Time in [s] to wait for answer			*
 *  - verbose	int					Print error messages					*
 *																			*
 ***************************************************************************/
int driver_obs_obsdaq::checked_send(const char* cmd, const char* reply,
		int digits, double timeout, int verbose) {

	std::string recv;

	return(checked_send(cmd, reply, digits, timeout, &recv, verbose));

}

/****************************************************************************
635
636
637
638
639
640
641
642
643
644
645
646
647
 *
 *	    Send an OBSDAQ command to address of serial port and check reply
 *
 * IN:
 *  - cmd	const char*		Command to send
 *  - reply	const char*		Expected reply
 *  - digits	int			Number of 'digits' first characters
 *                                      that are checked to match the received
 *                                      answer.
 *  - timeout	double			Time in [s] to wait for answer
 *  - recv	std::string*		Received answer
 *  - verbose	int			Print error messages
 *
Achim Morschhauser's avatar
Achim Morschhauser committed
648
649
650
651
 ***************************************************************************/
int driver_obs_obsdaq::checked_send(const char* cmd, const char* reply,
		int digits, double timeout, std::string* recv, int verbose) {

652
    flush();
Achim Morschhauser's avatar
Achim Morschhauser committed
653

654
655
656
657
658
    /////////////////////////////////////////////////////////////////////////
    //
    // Initialize some variables.
    //
    /////////////////////////////////////////////////////////////////////////
Achim Morschhauser's avatar
Achim Morschhauser committed
659
660


661
662
663
    char buf[1000]="";
    std::string strbuf;
    std::string expected;
Achim Morschhauser's avatar
Achim Morschhauser committed
664

665
666
667
668
669
    /////////////////////////////////////////////////////////////////////////
    //
    // Send command and check answer.
    //
    /////////////////////////////////////////////////////////////////////////
Achim Morschhauser's avatar
Achim Morschhauser committed
670

671
672
    // Send the command
    send(cmd);
Achim Morschhauser's avatar
Achim Morschhauser committed
673

674
675
676
677
678
679
680
    // Wait for an answer
    if (receive(buf, sizeof(buf), timeout) < 0) {
        if (verbose) {
            fprintf(stderr,"Reply not received for cmd: %s\n",cmd);
        }
        return (-1);
    }
Achim Morschhauser's avatar
Achim Morschhauser committed
681

682

683
684
685
686
687
    strbuf=std::string(buf);

    // Construct expected answer
    expected = "!" + RS485_addrstr + reply;

688
689
690
691
692
693
694
695
696
697
    // Convert to uppercase for comparison !! FIND STHG BETTER HERE !!
    std::transform(expected.begin(), expected.end(),expected.begin(), ::toupper);
    int i=0;
    while (buf[i] != '\0') {
       if (buf[i] >= 'a' && buf[i] <= 'z') {
          buf[i] = buf[i] - 32;
       }
       i++;
    }

698
699
700
701
702
703
    // Check address part of answer
    if ((expected.compare(1, 2, &buf[1], 2) != 0)
            && (RS485_addr != 0x0F)){
        if (verbose) {
            std::cerr << "Wrong address received." << " Expected: "
                      << expected.substr(1, 2) << " Received: " << &buf[1]
Achim Morschhauser's avatar
Achim Morschhauser committed
704
                      <<std::endl;
705
706
707
        }
        return (-2);
    }
Achim Morschhauser's avatar
Achim Morschhauser committed
708

709
710
711
712
713
    // Check response part of answer
    if ((expected.compare(3, digits, &buf[3], digits) != 0)) {
        if (verbose) {
            std::cerr << "Wrong answer received." << " Expected: "
                      << expected.substr(3, digits) << " Received: "
Achim Morschhauser's avatar
Achim Morschhauser committed
714
                      << strbuf.substr(3, digits) << " | " << strbuf.c_str() << std::endl;
715
716
717
        }
        return (-3);
    }
Achim Morschhauser's avatar
Achim Morschhauser committed
718

719
720
    // Return response
    *recv = &buf[3 + digits];
Achim Morschhauser's avatar
Achim Morschhauser committed
721

722
    return (0);
Achim Morschhauser's avatar
Achim Morschhauser committed
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738

}

/****************************************************************************
 *									 										*
 * Parse the input in ASCII format											*
 * 																			*
 ***************************************************************************/
int driver_obs_obsdaq::parse_data_ascii(data_obs_vector* data, char* buf) {

	/////////////////////////////////////////////////////////////////////////
	//
	// Some variables.
	//
	/////////////////////////////////////////////////////////////////////////

Achim Morschhauser's avatar
Achim Morschhauser committed
739
	double n[5];
Achim Morschhauser's avatar
Achim Morschhauser committed
740
741
742
743
	uint32_t n32, num;

	// Set data to missing
	data->set_data_MD();
Achim Morschhauser's avatar
Achim Morschhauser committed
744
        std::fill(n,n+5,data->get_MD());
Achim Morschhauser's avatar
Achim Morschhauser committed
745
746
747
748
749
750
751
752
753
754
755
756
757

	/////////////////////////////////////////////////////////////////////////
	//
	// Parse each channel (Manual 12.5.1).
	//
	/////////////////////////////////////////////////////////////////////////

	// Initialize
	int pos = 1;
	int i = 0;

	// Channels 1-3
	char tmp[7];
758
	num = (int32_t) 0x800000L; // was uint32_t
Achim Morschhauser's avatar
Achim Morschhauser committed
759
760
761
762
	while (i < 3) {
		strncpy(tmp, &buf[pos], 6);
		tmp[6] = 0;
		pos += 6;
763
		n32 = (int32_t) strtol(tmp, NULL, 16); // was strtoul // was uint32_t
Achim Morschhauser's avatar
Achim Morschhauser committed
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
		n[i++] = ((double) ((int32_t) ((n32 ^ num) - num))) * M;
	}

	// If free-run format
	if (strncmp(buf, "*", 1) == 0) {
		pos = pos + 2;
	}

	// Channels 4-6 (CH4,CH5,CH6)
	// ObsDaq Voltage and Temperature is not read
	if (strlen(buf)>pos){
		pos += 8;
		num = (uint32_t) 0x8000;
		while (i < 5) {
			strncpy(tmp, &buf[pos], 4);
			tmp[4] = 0;
			pos += 4;
			n32 = (uint32_t) strtoul(tmp, NULL, 16);
			n[i++] = ((double) ((int32_t) ((n32 ^ num) - num))) / 8000.0;
		}
	}

	/*
	// ObsDAQ T
	n[3]=n[3]/128;
	// ObsDAQ V
	n[4]=n[4]*0.000575+1.0;
	*/

	// Save the data
	data->set_data(n);
Achim Morschhauser's avatar
Achim Morschhauser committed
795
796
        
        return(0);
Achim Morschhauser's avatar
Achim Morschhauser committed
797
798
799
800
801
802
803
804
805
806
807

}

/****************************************************************************
 *									 										*
 * 			     Parse the input in binary format							*
 * 			     															*
 ***************************************************************************/
int driver_obs_obsdaq::parse_data_bin(data_obs_vector* data, char* buf) {


808
809
810
811
812
    /////////////////////////////////////////////////////////////////////////
    //
    // Some variables.
    //
    /////////////////////////////////////////////////////////////////////////
Achim Morschhauser's avatar
Achim Morschhauser committed
813

Achim Morschhauser's avatar
Achim Morschhauser committed
814
    double n[5];
815
    uint32_t n32, num;
Achim Morschhauser's avatar
Achim Morschhauser committed
816

817
818
    // Record length (is updated below)
    unsigned char reclen=12;
Achim Morschhauser's avatar
Achim Morschhauser committed
819

820
821
    // Temporary variable
    int tmp_d;
Achim Morschhauser's avatar
Achim Morschhauser committed
822

823
824
    // Set data to missing
    data->set_data_MD();
Achim Morschhauser's avatar
Achim Morschhauser committed
825
    std::fill(n,n+5,data->get_MD());
Achim Morschhauser's avatar
Achim Morschhauser committed
826

827
828
829
830
831
    ////////////////////////////////////////////////////////////////////////
    // TODO Use for sampling rates higher than 10 Hz (else, suppl. data is
    //      not returned).
    // OBSDAQ uses LittleEndian
    ////////////////////////////////////////////////////////////////////////
Achim Morschhauser's avatar
Achim Morschhauser committed
832

833
834
835
836
837
838
839
    if (driver_obs::freq < 10.0){
        std::cerr << "ERROR: Binary mode not available for sampling rate "
            << "of lower than 10 Hz. Current sampling rate is "
            << driver_obs::freq 
            << " Hz." << std::endl;
        return(-1);
    }
Achim Morschhauser's avatar
Achim Morschhauser committed
840

841
842
843
844
845
    ////////////////////////////////////////////////////////////////////////
    //
    // Parse the binary data (Manual 12.5.2).
    //
    /////////////////////////////////////////////////////////////////////////
Achim Morschhauser's avatar
Update    
Achim Morschhauser committed
846

847
848
849
    //
    // Some checks on data consistency are performed
    //
Achim Morschhauser's avatar
Achim Morschhauser committed
850

851
852
853
854
    // Check for supplementary channels
    if (buf[1] & (unsigned char) 64){
        reclen = 14;
    }
Achim Morschhauser's avatar
Achim Morschhauser committed
855

856
857
858
859
860
861
862
863
    // Check 7th bits
    for (int i=0; i<strlen(buf);i++){
        if ((unsigned char) buf[i]<32 || (unsigned  char) buf[i]>159){
            fprintf(stderr,"Faulty data: 7th bit check failed for byte %d: %d.\n",
                            i,(unsigned char) buf[i]);
            //fprintf(stderr,"%d %d %d %d %d %d %d %d\n",buf[i]&1,(buf[i]&2)/2,
            //        (buf[i]&4)/4,(buf[i]&8)/8,(buf[i]&16)/16,(buf[i]&32)/32,
            //        (buf[i]&64)/64,(buf[i]&128)/128);
Achim Morschhauser's avatar
Achim Morschhauser committed
864

865
866
867
            return(-1);
        }
    }
Achim Morschhauser's avatar
Achim Morschhauser committed
868

869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
    // Check checksum byte
    tmp_d=0;
    // Sum over N-1 data bytes
    for (int i=0; i<reclen-1; i++){
            tmp_d += buf[i];
    }
    // Last byte must contain sum of last (N-1) bytes in bits 0-6
    if ( (tmp_d&127) != (buf[reclen-1]&127) ){
        fprintf(stderr,"Faulty data: Control sum check failed for ");
        for (int i=0; i<reclen-1;i++){
            fprintf(stderr,"%d ",buf[i]);
        }
        fprintf(stderr,"and values %d %d %d.\n",
                        tmp_d,tmp_d&127,buf[reclen-1]);
        return(-2);
    }
Achim Morschhauser's avatar
Achim Morschhauser committed
885

886
    // Check supplementary data
Achim Morschhauser's avatar
Achim Morschhauser committed
887
888
    if (buf[1] & (unsigned char) 64){
        if (buf[1] & 1){
889
            supp_count=1;
Achim Morschhauser's avatar
Achim Morschhauser committed
890
        } else {
891
892
893
894
895
896
897
            supp_count+=1;
        }
    }

    //
    // Extract data from channels 1-3
    //
Achim Morschhauser's avatar
Achim Morschhauser committed
898

899
    num = (uint32_t) 0x800000L;
Achim Morschhauser's avatar
Achim Morschhauser committed
900

901
902
903
904
905
    // Channel 1
    n32  = ( ( (buf[2 ]&127) + ((buf[0]&32)<<2) ) <<16 )
         + ( ( (buf[3 ]&127) + ((buf[0]&16)<<3) ) <<8  )
         + ( ( (buf[4 ]&127) + ((buf[0]&8 )<<4) )      );
    n[0] = ((double) ((int32_t) ((n32 ^ num) - num))) * M;
906
    //fprintf(stderr,"XYZ: %u %u %f\n",buf[2]&127,n32,n[1]);
Achim Morschhauser's avatar
Achim Morschhauser committed
907

908
909
910
911
912
    // Channel 2
    n32  = ( ( (buf[5 ]&127) + ((buf[0]&4 )<<5) ) <<16 )
         + ( ( (buf[6 ]&127) + ((buf[0]&2 )<<6) ) <<8  )
         + ( ( (buf[7 ]&127) + ((buf[0]&1 )<<7) )      );
    n[1] = ((double) ((int32_t) ((n32 ^ num) - num))) * M;
913
    //fprintf(stderr,"XYZ: %u %f\n",n32,n[2]);
Achim Morschhauser's avatar
Achim Morschhauser committed
914
915
916
917
918
919

    // Channel 3
    n32  = ( ( (buf[8 ]&127) + ((buf[1]&32)<<2) ) <<16 )
         + ( ( (buf[9 ]&127) + ((buf[1]&16)<<3))  <<8  )
         + ( ( (buf[10]&127) + ((buf[1]&8 )<<4))       );
    n[2] = ((double) ((int32_t) ((n32 ^ num) - num))) * M;
920
	//fprintf(stderr,"XYZ: %u %f\n",n32,n[3]);
Achim Morschhauser's avatar
Achim Morschhauser committed
921
922

    //
923
    // Extract data from supplementary channels
Achim Morschhauser's avatar
Achim Morschhauser committed
924
    //
Achim Morschhauser's avatar
Achim Morschhauser committed
925
    
926
    num = (uint32_t) 0x8000;
Achim Morschhauser's avatar
Achim Morschhauser committed
927
928
    if ((buf[1]&64) && supp_count >= 1 && supp_count <= 2){
        
929
930
            n32  = ( ( (buf[11 ]&127) + ((buf[1]&4 )<<5) ) <<8  )
                 + ( ( (buf[12 ]&127) + ((buf[1]&2 )<<6) )      );
Achim Morschhauser's avatar
Achim Morschhauser committed
931
932
933
934
935
936
937
938
939
940
941
942
943
944
            
            switch (supp_count) {
                case 1: 
                    n[3] = ((double) ((int32_t) ((n32 ^ num) - num)))
                         * 0.000575 + 1.0; break;
                case 2:
                    n[4] = ((double) ((int32_t) ((n32 ^ num) - num)))
                         / 128.0; break;
                default:
                    n[supp_count] = ((double) ((int32_t) ((n32 ^ num) - num)))
                                  / 8000.0; break;

            }
            
945
    }
Achim Morschhauser's avatar
Achim Morschhauser committed
946

947
948
    // Save the data
    data->set_data(n);
Achim Morschhauser's avatar
Achim Morschhauser committed
949

950
    return(0);
Achim Morschhauser's avatar
Achim Morschhauser committed
951
952
953
954
955
956
957
958
959
960
961

}

/****************************************************************************
 *									 										*
 * 			     Initialize the OBSDAQ.										*
 *																			*
 * Set filter rates.														*
 *																			*
 ***************************************************************************/
int driver_obs_obsdaq::init() {
Achim Morschhauser's avatar
Achim Morschhauser committed
962
    
963
964
    std::string recv;
    
Achim Morschhauser's avatar
Achim Morschhauser committed
965
966
967
968
969
    /////////////////////////////////////////////////////////////////////////
    //
    // Stop running data acquisition.
    //
    /////////////////////////////////////////////////////////////////////////
Achim Morschhauser's avatar
Achim Morschhauser committed
970

971
972
    // Should never run, as private method
    //stop();
Achim Morschhauser's avatar
Achim Morschhauser committed
973

Achim Morschhauser's avatar
Achim Morschhauser committed
974
975
976
977
978
    /////////////////////////////////////////////////////////////////////////
    //
    // Stop the internal trigger.
    //
    /////////////////////////////////////////////////////////////////////////
Achim Morschhauser's avatar
Achim Morschhauser committed
979

Achim Morschhauser's avatar
Achim Morschhauser committed
980
981
    send("#PP00000000");
    usleep(2e6);
Achim Morschhauser's avatar
Achim Morschhauser committed
982

983
984
985
986
987
988
989
990
991
    /////////////////////////////////////////////////////////////////////////
    //
    // Get the serial number
    //
    /////////////////////////////////////////////////////////////////////////
    
    checked_send("$SN", "SN", 2, 1, &recv);
    sn = recv;    
    
Achim Morschhauser's avatar
Achim Morschhauser committed
992
993
994
995
996
    /////////////////////////////////////////////////////////////////////////
    //
    // Get the quartz crystal frequency.
    //
    /////////////////////////////////////////////////////////////////////////
Achim Morschhauser's avatar
Achim Morschhauser committed
997

Achim Morschhauser's avatar
Achim Morschhauser committed
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
    checked_send("$QF", "R", 1, 1, &recv);
    std::cerr << "Received: " << recv << std::endl;

    quartz_freq = atoi(recv.c_str());

    // Set the valid output rates of the digital filter (Table 6 in Manual)

    switch (quartz_freq) {

    case 76:
            // 7.6800 MHz
            valid_filter_rates[0] = 2.5;
            valid_filter_rates[1] = 5.0;
            valid_filter_rates[2] = 10.0;
            valid_filter_rates[3] = 15.0;
            valid_filter_rates[4] = 25.0;
            valid_filter_rates[5] = 30.0;
            valid_filter_rates[6] = 50.0;
            valid_filter_rates[7] = 60.0;
            valid_filter_rates[8] = 100.0;
            valid_filter_rates[9] = 500.0;
            valid_filter_rates[10] = 1000.0;
            break;
    case 92:
            // 9.2160 MHz
            valid_filter_rates[0] = 3.0;
            valid_filter_rates[1] = 6.0;
            valid_filter_rates[2] = 12.0;
            valid_filter_rates[3] = 18.0;
            valid_filter_rates[4] = 30.0;
            valid_filter_rates[5] = 36.0;
            valid_filter_rates[6] = 60.0;
            valid_filter_rates[7] = 72.0;
            valid_filter_rates[8] = 120.0;
            valid_filter_rates[9] = 600.0;
            valid_filter_rates[10] = 1200.0;
            break;
    case 98:
            // 9.8304 MHz (default)
            valid_filter_rates[0] = 3.2;
            valid_filter_rates[1] = 6.4;
            valid_filter_rates[2] = 12.8;
            valid_filter_rates[3] = 19.2;
            valid_filter_rates[4] = 32.0;
            valid_filter_rates[5] = 38.4;
            valid_filter_rates[6] = 64.0;
            valid_filter_rates[7] = 76.8;
            valid_filter_rates[8] = 128.0;
            valid_filter_rates[9] = 640.0;
            valid_filter_rates[10] = 1280.0;
            break;
    }
Achim Morschhauser's avatar
Achim Morschhauser committed
1050

Achim Morschhauser's avatar
Achim Morschhauser committed
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
    // Define the filter commands (Table 6 in Manual)
    filter_cmds[0]  = "03";
    filter_cmds[1]  = "13";
    filter_cmds[2]  = "23";
    filter_cmds[3]  = "33";
    filter_cmds[4]  = "43";
    filter_cmds[5]  = "53";
    filter_cmds[6]  = "63";
    filter_cmds[7]  = "72";
    filter_cmds[8]  = "82";
    filter_cmds[9]  = "92";
    filter_cmds[10] = "A1";

    return (0);
Achim Morschhauser's avatar
Achim Morschhauser committed
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079

}

/****************************************************************************
 *									 										*
 * Prepare data acquisition.												*
 * This is common code for freerun and triggered mode.						*
 * 																			*
 * - Set the frequency														*
 * - Calibration of channels												*
 * - TODO Reset appropriate baud rate (should this be done automatically ?)	*
 *																			*
 ***************************************************************************/
int driver_obs_obsdaq::init_run(double freq){

1080
    // The receive buffer
Achim Morschhauser's avatar
Achim Morschhauser committed
1081
    std::string str_recv;
1082
    char recv[20]="";
1083
1084
1085
1086
    // A command to send
    char cmd[20];
    // Index of the selected frequency
    int freq_sel;
Achim Morschhauser's avatar
Achim Morschhauser committed
1087

1088
    // ADC calibration
Achim Morschhauser's avatar
Achim Morschhauser committed
1089
    std::string config, adc_scale, adc_offset;
Achim Morschhauser's avatar
Achim Morschhauser committed
1090

1091
1092
1093
1094
1095
    /////////////////////////////////////////////////////////////////////
    //
    // Set frequency.
    //
    /////////////////////////////////////////////////////////////////////
Achim Morschhauser's avatar
Achim Morschhauser committed
1096

Achim Morschhauser's avatar
Achim Morschhauser committed
1097
1098
1099
1100
    // Set triggering off
    //TODO Check if necessary here
    send("#PP00000000");
    usleep(1e6);
Achim Morschhauser's avatar
Achim Morschhauser committed
1101

Achim Morschhauser's avatar
Achim Morschhauser committed
1102
1103
    // Find the closest possible valid frequency larger or equal to
    // the one requested.
1104
1105
1106
1107
    for (int i=0; i<valid_filter_rates_num; i++){
        if (valid_filter_rates[i]>=freq){
            freq_sel = i;
            break;
Achim Morschhauser's avatar
Achim Morschhauser committed
1108
        }
1109
    }
Achim Morschhauser's avatar
Achim Morschhauser committed
1110

1111
1112
    // Set the frequency
    driver_obs::freq = valid_filter_rates[freq_sel];
Achim Morschhauser's avatar
Achim Morschhauser committed
1113

1114
1115
1116
    // Set range to +10V and set frequency of digital filter
    for (int i=0; i<3; i++){
        sprintf(cmd,"$%1dWS020102%s",i,filter_cmds[freq_sel]);
1117
1118
        send(cmd);
        waitanswer(5);
1119
    }
Achim Morschhauser's avatar
Achim Morschhauser committed
1120

1121
1122
1123
    // Print used and requested frequency
    fprintf(stderr,"Frequency set to: %6.2f Hz. "
            "Requested frequency: %6.2f Hz.\n",
1124
            driver_obs::freq,freq);
1125
1126
1127
1128
1129

    /////////////////////////////////////////////////////////////////////////
    //
    // Calibrate.
    //
Achim Morschhauser's avatar
Achim Morschhauser committed
1130
    ///////////////////////////////////////////////////////////////////////// 
Achim Morschhauser's avatar
Achim Morschhauser committed
1131

Achim Morschhauser's avatar
Achim Morschhauser committed
1132
    int auto_cal=0;
Achim Morschhauser's avatar
Achim Morschhauser committed
1133
    
1134
1135
1136
    // Iterate over all three channels
    for (int i=0; i<3; i++){
        // Get current 24-bit configuration (Manual 12.4.9)
1137
        flush();
1138
        sprintf(cmd,"$%1dRS",i);
1139
1140
        send(cmd);
        receive(recv,sizeof(recv),5);
Achim Morschhauser's avatar
Achim Morschhauser committed
1141
        str_recv = std::string(recv);
1142
        //checked_send(cmd,"02",2,1,&recv,1);
DTU RPi3's avatar
DTU RPi3 committed
1143
        std::cerr << "REC CONFIG: " << recv << std::endl;
Achim Morschhauser's avatar
Achim Morschhauser committed
1144

1145
        // Get the last four bytes ("ccdd") and add channel number
Achim Morschhauser's avatar
Achim Morschhauser committed
1146
        config= sn + "/" + str_recv.substr(7,4) + "/" + std::to_string(i);
1147
        fprintf(stderr,"----- CONFIG: %s\n",config.c_str());
Achim Morschhauser's avatar
Achim Morschhauser committed
1148

1149
1150
1151
        // Check if calibration for the given config
        // was pre-determined
        if (driver_obs::cal->get_adc_calibrate
Achim Morschhauser's avatar
Achim Morschhauser committed
1152
                (config, adc_offset, adc_scale)<0){
1153
            // Automatic Calibration
Achim Morschhauser's avatar
Achim Morschhauser committed
1154
            auto_calibrate(i,5,config);
Achim Morschhauser's avatar
Achim Morschhauser committed
1155
            auto_cal=1;
1156
1157
        } else {
            // Set the pre-determined calibration constant
1158
            sprintf(cmd,"$%1dWO%s",i,adc_offset.c_str());
Achim Morschhauser's avatar
Achim Morschhauser committed
1159
            checked_send(cmd,adc_offset.c_str(),6,4);
1160
            sprintf(cmd,"$%1dWF%s",i,adc_scale.c_str());
Achim Morschhauser's avatar
Achim Morschhauser committed
1161
            checked_send(cmd,adc_offset.c_str(),6,4);
Achim Morschhauser's avatar
Achim Morschhauser committed
1162
        }
1163

1164
        //fprintf(stderr,"============ GOT: %06X %06X\n",adc_offset,adc_scale);
1165

1166
    }
Achim Morschhauser's avatar
Achim Morschhauser committed
1167
1168
    
    // Save calibration constants
1169
1170
1171
1172
1173
    if (auto_cal) {
        driver_obs::cal->save_adc_calibrate();
        std::cerr << "New calibration constants written to " 
                  << cal->get_adc_calibrate() << std::endl;
    }
1174
1175


1176
1177
1178
1179
1180
    /////////////////////////////////////////////////////////////////////////
    //
    // Set the scaling parameter (Manual 12.5.1).
    //
    /////////////////////////////////////////////////////////////////////////
1181

1182
1183
1184
1185
1186
1187
    //TODO Automatically set the calibration parameters
    // Set the conversion parameters
    //FULLSCALE=42.5; // Self-Gain calibration
    //FULLSCALE=40.0; // System-Gain calibration
    //GAIN=4.0; // +/- 10V range
    //GAIN=8.0; // +/- 5V range
1188
1189


1190
    M = 40.0 / 4.0 / (double) 0x800000;
1191
    //fprintf(stderr,"M: %f\n",M);
1192
1193
    
    return(0);
Achim Morschhauser's avatar
Achim Morschhauser committed
1194

Achim Morschhauser's avatar
Achim Morschhauser committed
1195
1196

}
Achim Morschhauser's avatar
Achim Morschhauser committed
1197
1198
1199

/****************************************************************************
 *
1200
 * 		     Set the baud rate (Manual 12.4.5)
Achim Morschhauser's avatar
Achim Morschhauser committed
1201
1202
1203
1204
1205
1206
1207
 *
 * Set filter rates.
 *
 ***************************************************************************/
int driver_obs_obsdaq::set_baud(int baud) {

    std::string cmd;
1208

Achim Morschhauser's avatar
Achim Morschhauser committed
1209
1210
1211
    
    ////////////////////////////////////////////////////////////////////////
    //
1212
    // Set the baud rate of ObsDAQ 
Achim Morschhauser's avatar
Achim Morschhauser committed
1213
1214
    //
    ////////////////////////////////////////////////////////////////////////
1215
1216
1217
1218
1219
    
    it_map_baud = map_baud.find(baud);
    
    cmd = "%" + RS485_addrstr + "00" + it_map_baud->second + "00";
    send(cmd.c_str());
Achim Morschhauser's avatar
Achim Morschhauser committed
1220
1221
    

1222

Achim Morschhauser's avatar
Achim Morschhauser committed
1223
1224
1225
1226
1227
1228
1229
1230
    ////////////////////////////////////////////////////////////////////////
    //
    // Set the baud rate of serial port
    //
    ////////////////////////////////////////////////////////////////////////
    if (Driver_Obs_Serial::set_baud(baud) < 0) {
            return (-1);
    }
1231
    
1232
1233
1234
1235
1236
    ////////////////////////////////////////////////////////////////////////
    //
    // Check for response
    //
    ////////////////////////////////////////////////////////////////////////
Achim Morschhauser's avatar
Achim Morschhauser committed
1237
    waitanswer(1);
1238
1239
1240
1241
1242
1243
    if (checked_send("$M","<ObsDaq",7,0.2,0) != 0){
       return(-1);
    }

    return (0);
    
Achim Morschhauser's avatar
Achim Morschhauser committed
1244
1245
1246
1247
1248
1249
1250
1251
}

/****************************************************************************
 *
 * 			     Find the correct baud rate.
 *
 ***************************************************************************/
int driver_obs_obsdaq::find_baud() {
1252
1253
1254
1255
1256
    
    // Try to find serial port
    Driver_Obs_Serial::find_baud(this,
            static_cast <int (Driver_Obs_Serial::*) (int)> 
            (&driver_obs_obsdaq::check_baud));
Achim Morschhauser's avatar
Achim Morschhauser committed
1257
1258
1259

    return(0);
    
Achim Morschhauser's avatar
Achim Morschhauser committed
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
}


/****************************************************************************
 *
 * 			 Check if the specified baud rate is correct
 *
 ***************************************************************************/
int driver_obs_obsdaq::check_baud(int baud){
 
1270
1271
    fprintf(stderr,"----- CHECK BAUD -----\n");
    
1272
1273
1274
1275
1276
1277
1278
1279
    ////////////////////////////////////////////////////////////////////////
    //
    // Set the baud rate of serial port
    //
    ////////////////////////////////////////////////////////////////////////
    if (Driver_Obs_Serial::set_baud(baud) < 0) {
            return (-1);
    }
Achim Morschhauser's avatar
Achim Morschhauser committed
1280

Achim Morschhauser's avatar
Achim Morschhauser committed
1281
    
1282
1283
1284
1285
1286
    ////////////////////////////////////////////////////////////////////////
    //
    // Check for response
    //
    ////////////////////////////////////////////////////////////////////////
1287
        
Achim Morschhauser's avatar
Achim Morschhauser committed
1288
    //send("$M");
1289
    // Check for expected response
1290
    if (checked_send("$M","<OBSDAQ",7,0.2,1) != 0) {
1291
1292
        // No response, but freerun mode might be running, so check for data
        int n=0;
Achim Morschhauser's avatar
Achim Morschhauser committed
1293
        for (int i=0; i<5; i++) {
1294
1295
1296
            if (waitanswer(0.4)==0) n++;
        }
        fprintf(stderr,"N: %d\n",n);
Achim Morschhauser's avatar
Achim Morschhauser committed
1297
        if (n<2) {
Achim Morschhauser's avatar
Achim Morschhauser committed
1298
            fprintf(stderr,"----- CHECK BAUD FAILED -----\n");
1299
            return(-1);
Achim Morschhauser's avatar
Achim Morschhauser committed
1300
1301
1302
        } else {
        	fprintf(stderr,"----- CHECK BAUD DONE -----\n");
        	return(2);
1303
        }
1304
1305
    }
    
Achim Morschhauser's avatar
Achim Morschhauser committed
1306
1307
    fprintf(stderr,"----- CHECK BAUD DONE -----\n");

1308
1309
1310
    return(1);

    
1311
}