Commit 19c38b28 authored by Achim Morschhauser's avatar Achim Morschhauser
Browse files

Merge branch 'master' into testrasp

parents cc947d62 0b26e80b
SRC_DIR=./src/
OBJ_DIR=./lib/
HDR_DIR=./include/
SRC_DIR=src/
OBJ_DIR=lib/
HDR_DIR=include/
LIB_DIR=./lib/
USR_DIR=./usr/
BIN_DIR=./bin/
USR_DIR=usr/
BIN_DIR=bin/
#--------------------------------------
#--------------------------------------
......@@ -18,7 +19,7 @@ CCFLAGS=-g -lrt -std=c++11 -pthread
EXCL=driver_serial_emulate.o
# Uncomment to use virtual serial port. Run 'make clean all' afterwards
#EXCL=driver_serial.o
EXCL=driver_serial.o
.SECONDARY:
......@@ -28,12 +29,17 @@ all: $(USR_TARGET:%=$(BIN_DIR)%)
@echo ---- DONE ----
$(BIN_DIR)%: $(filter-out $(OBJ_DIR)$(EXCL) ,$(OBJ_FILES)) $(USR_DIR)%.cpp
$(CC) $(CCFLAGS) -o $(@) $^ -I./include/
$(BIN_DIR)%: $(USR_DIR)%.cpp $(LIB_DIR)libLogger.so
$(CC) $(CCFLAGS) -no-pie $< -o $@ -I$(HDR_DIR) -L$(LIB_DIR) -Wl,-rpath,"\$$ORIGIN/../$(LIB_DIR)" -lLogger
# $(CC) $(CCFLAGS) $< -o $@ -I$(HDR_DIR) -L$(LIB_DIR) -lLogger
$(OBJ_DIR)%.o: $(SRC_DIR)%.cpp
$(CC) $(CCFLAGS) -c -o $@ $< -I$(HDR_DIR)
$(CC) $(CCFLAGS) -fPIC -c -o $@ $< -I$(HDR_DIR)
$(LIB_DIR)libLogger.so: $(filter-out $(OBJ_DIR)$(EXCL) ,$(OBJ_FILES))
$(CC) $^ -shared -o $@
clean:
rm $(BIN_DIR)*
rm $(OBJ_DIR)*
rm -f $(BIN_DIR)*
rm -f $(OBJ_DIR)*
rm -f $(LIB_DIR)libLogger.so
/*
* Driver_Obs_Serial.h
*
* Created on: May 12, 2016
* Author: mors
*/
#ifndef INCLUDE_DRIVER_OBS_SERIAL_HPP_
#define INCLUDE_DRIVER_OBS_SERIAL_HPP_
#include <driver_serial_emulate.hpp>
//#include <driver_serial.hpp>
#include <driver_obs.hpp>
class Driver_Obs_Serial: protected driver_obs {
//
// Private class variables
//
/** The serial driver to use */
private: driver_serial_emulate serial;
//private: driver_serial serial;
//
// Constructors
//
public:
/** Constructor with baud rate */
Driver_Obs_Serial(std::string port, buffer_obs* buffer);
/**
* Constructors of derived classes must call set_term(term,termlen)
* and set_baud(const char* init_char) or set_baud(int baud).
*/
//
// Public Methods
//
/** Take a single measurement. An object data_obs with the timestamp is returned.
This method must be implemented as specified in the abstract class driver_obs */
public: virtual int get(data_obs* data)=0;
/** Take continuous measurement in triggered mode */
public: virtual int run(int freq)=0;
/** Take continuous measurement in freerun mode */
public: virtual int freerun(int freq)=0;
/** Stop continuous measurements */
public: virtual int stop()=0;
//
// Private Methods
//
protected:
/** Receive raw from serial port without time information. */
virtual int receive_raw(char *buf, int buflen, double timeout);
/** Receive from serial port without time information. */
virtual int receive(char *buf, int buflen, double timeout);
/** Receive from serial port with time information. */
virtual int receive(char *buf, int buflen, double timeout,
struct timespec *recv_time);
/** Send a command to the serial port. */
virtual int send(const char* cmd);
/** Send a command to the serial port. */
virtual int send(char* cmd);
/** Flush the buffer of the serial port. */
virtual int flush();
/** Initialize the instrument with automatic determination of the baud rate */
virtual int set_baud(const char* init_char);
/** Initialize the instrument with given baud rate */
virtual int set_baud(int baud);
/** Set the termination characters. */
virtual int set_term(const char* term,int termlen);
};
#endif /* INCLUDE_DRIVER_OBS_SERIAL_HPP_ */
......@@ -32,6 +32,9 @@ buffer_obs* buffer;
/** The calibration constants of the instrument */
Obs_Calibration* cal;
/** The selected sampling frequency */
double freq;
//
// Public Methods
//
......
/********************************************************************************
* WRITTEN BY ACHIM MORSCHHAUSER, GFZ POTSDAM, April 2016 *
* mors//gfz-potsdam.de *
* *
* This class provides the driver for an OBSDAQ ADC. *
* *
* It is based on the abstract observatory driver class driver_obs. *
* *
********************************************************************************/
#ifndef _DRIVER_OBS_OBSDAQ_H
#define _DRIVER_OBS_OBSDAQ_H
#include <string>
#include <Driver_Obs_Serial.hpp>
#include <data_obs_vector.hpp>
#include <data_obs.hpp>
#include <buffer_obs.hpp>
class driver_obs_obsdaq : protected Driver_Obs_Serial
{
//
// Private class variables
//
private:
/** The address to use (RS-485) */
int RS485_addr;
std::string RS485_addrstr;
/** The quartz crystal frequency */
int quartz_freq;
//
// Constructors
//
/** Standard constructor */
public: driver_obs_obsdaq(std::string port, buffer_obs* buffer);
/** Standard constructor */
public: driver_obs_obsdaq(std::string port, buffer_obs* buffer, int addr);
/** Standard constructor */
public: driver_obs_obsdaq(std::string port, buffer_obs* buffer, int baud, int addr);
//
// Public Methods
//
public:
/** Take a single measurement. An object data_obs with the timestamp is returned.
This method must be implemented as specified in the abstract class driver_obs */
int get(data_obs* data);
/** Take a single measurement and return all data */
int get(data_obs_vector* data);
/** Take continuous measurement in triggered mode */
int run(int freq);
/** Take continuous measurement in freerun mode */
int freerun(int freq);
/** Stop continuous measurements */
int stop();
//
// Private Methods
//
private:
/** Send an OBSDAQ-type command to address of RS-485 serial port */
int send(const char* cmd);
/** Send an OBSDAQ-type command to address of RS-485 serial port, check and get response */
int checked_send(const char* cmd, const char* reply, int digits, double timeout,
std::string* recv);
/** Send an OBSDAQ-type command to address of RS-485 serial port and check response */
int checked_send(const char* cmd, const char* reply, int digits, double timeout);
/** Initialize the instrument */
int init();
protected:
/** Set the termination characters for serial comm. */
int set_term();
};
#endif /* _DRIVER_OBS_OBSDAQ_H */
/********************************************************************************
* WRITTEN BY ACHIM MORSCHHAUSER, GFZ POTSDAM, April 2016 *
* mors//gfz-potsdam.de *
* *
* This class provides a container for observatory data. *
* It can store only timestamping data, but may be extended to store more data. *
* For example, see the classes data_olbs_scalar and data_obs_vector. *
* *
********************************************************************************/
/*******************************************************************************
* WRITTEN BY ACHIM MORSCHHAUSER, GFZ POTSDAM, April 2016 *
* mors//gfz-potsdam.de *
* *
* This class provides a container for observatory data. *
* It can store only timestamping data, but may be extended to store more data.*
* For example, see the classes data_obs_scalar and data_obs_vector. *
* *
******************************************************************************/
// C++ Headers
#include <iomanip> // For parsing strings
......
......@@ -101,9 +101,6 @@ driver_obs_obsdaq::driver_obs_obsdaq(std::string port, buffer_obs* buffer,
// Set the ObsDAQ baud rate
// Stop the measurement
stop();
// Initialize
init();
......@@ -261,7 +258,7 @@ int driver_obs_obsdaq::run(double freq) {
/****************************************************************************
* *
* Run the OBSDAQ in freerun mode (no triggering). *
* Run the OBSDAQ in freerun mode (no triggering). *
* *
***************************************************************************/
int driver_obs_obsdaq::freerun(double freq) {
......@@ -278,6 +275,9 @@ int driver_obs_obsdaq::freerun(double freq) {
data_obs_vector data;
// The receive buffer
char buf[200];
// 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;
/////////////////////////////////////////////////////////////////////////
//
......@@ -301,10 +301,20 @@ int driver_obs_obsdaq::freerun(double freq) {
send("#PP00000000");
usleep(2e5);
// Use ASCII mode
//checked_send("#CS","",0,1);
// Use binary mode
checked_send("#CS","",0,1);
// Flush
usleep(1e6);
flush();
if (freq < 10.0){
// 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;
}
/////////////////////////////////////////////////////////////////////////
//
......@@ -327,12 +337,10 @@ int driver_obs_obsdaq::freerun(double freq) {
data.set_time(&recv_time);
// Parse data from answer
if ( (this->*parse_data)(&data, buf) >= 0 ){
if (parse_data_ascii(&data, buf) >= 0){
//parse_data_ascii(&data, buf);
// Calibrate the measurement/ASCII
driver_obs::cal->calibrate(&data);
// Calibrate the measurement/ASCII
driver_obs::cal->calibrate(&data);
}
......@@ -405,15 +413,12 @@ int driver_obs_obsdaq::auto_calibrate(int channel, int repeat){
send("#PP00000000");
usleep(1e6);
/////////////////////////////////////////////////////////////////////////
//
// Calibration
//
/////////////////////////////////////////////////////////////////////////
//
// Repeat calibration step
//
for (int k=1; k<=repeat; k++){
......@@ -427,6 +432,7 @@ int driver_obs_obsdaq::auto_calibrate(int channel, int repeat){
// Check if calibration is finished
sprintf(cmd,"$%1dRR",channel);
usleep(4.0/freq*1e6);
while (checked_send(cmd,"R0",2,5)<0){
}
......@@ -434,12 +440,13 @@ int driver_obs_obsdaq::auto_calibrate(int channel, int repeat){
sprintf(cmd,"$%1dRO",channel);
send(cmd);
//TODO Repeat loop instead of just omitting
if (receive(recv,sizeof(recv),5)==0) {
// Parse the offset value and add to average
n32 = (uint32_t) strtoul(&recv[3], NULL, 16);
num=0x800000L;
offset += (double) (n32 ^ num) - (double) num;
offset += (double) (n32 ^ num) - (double) num;
}
// Necessary to avoid time outs
......@@ -449,6 +456,7 @@ int driver_obs_obsdaq::auto_calibrate(int channel, int repeat){
sprintf(cmd,"$%1dRF",channel);
send(cmd);
//TODO Repeat loop instead of just omitting
if (receive(recv,sizeof(recv),5)==0) {
// Parse the full-scale value and add to average
......@@ -463,6 +471,14 @@ int driver_obs_obsdaq::auto_calibrate(int channel, int repeat){
// Calculate the average of calibration constants and send them to
// OBSDAQ.
//
// Offset
n32 = ((int32_t) (scale/repeat) + (int32_t) 0x800000L)
^ (int32_t) 0x800000L ;
sprintf(cmd,"$%1dWF%06X",channel,n32);
send(cmd);
std::cerr << "Set offset: " << scale/repeat << " " << cmd << std::endl;
// Full-scale
n32 = ((int32_t) (offset/repeat) + (int32_t) 0x800000L)
......@@ -470,15 +486,7 @@ int driver_obs_obsdaq::auto_calibrate(int channel, int repeat){
sprintf(cmd,"$%1dWO%06X",channel,n32);
send(cmd);
std::cerr << "AUTO CAL: " << scale/repeat << " " << cmd << std::endl;
// Offset
n32 = ((int32_t) (scale/repeat) + (int32_t) 0x800000L)
^ (int32_t) 0x800000L ;
sprintf(cmd,"$%1dWF%06X",channel,n32);
send(cmd);
std::cerr << "AUTO CAL: " << scale/repeat << " " << cmd << std::endl;
std::cerr << "Set scale: " << scale/repeat << " " << cmd << std::endl;
return(0);
......@@ -738,9 +746,6 @@ int driver_obs_obsdaq::parse_data_ascii(data_obs_vector* data, char* buf) {
***************************************************************************/
int driver_obs_obsdaq::parse_data_bin(data_obs_vector* data, char* buf) {
// TODO Use for sampling rates higher than 10 Hz (else, suppl. data is
// not returned).
// OBSDAQ uses LittleEndian
/////////////////////////////////////////////////////////////////////////
//
......@@ -760,6 +765,19 @@ int driver_obs_obsdaq::parse_data_bin(data_obs_vector* data, char* buf) {
// Set data to missing
data->set_data_MD();
////////////////////////////////////////////////////////////////////////
// TODO Use for sampling rates higher than 10 Hz (else, suppl. data is
// not returned).
// OBSDAQ uses LittleEndian
////////////////////////////////////////////////////////////////////////
if (freq < 10.0){
std::cerr << "ERROR: Binary mode not available for sampling rate "
<< "of lower than 10 Hz. Current sampling rate is " << freq
<< " Hz." << std::endl;
return(-1);
}
////////////////////////////////////////////////////////////////////////
//
// Parse the binary data (Manual 12.5.2).
......@@ -769,7 +787,7 @@ int driver_obs_obsdaq::parse_data_bin(data_obs_vector* data, char* buf) {
//
// Some checks on data consistency are performed
//
// Check for supplementary channels
if (buf[1] & (unsigned char) 64){
reclen = 14;
......@@ -777,9 +795,12 @@ int driver_obs_obsdaq::parse_data_bin(data_obs_vector* data, char* buf) {
// Check 7th bits
for (int i=0; i<strlen(buf);i++){
if (buf[i]<32 || buf[i]>159){
fprintf(stderr,"Faulty data: 7th bit check failed for %d.",
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);
return(-1);
}
......@@ -944,14 +965,14 @@ int driver_obs_obsdaq::init() {
}
// Define the filter commands (Table 6 in Manual)
filter_cmds[0] = "03\0";
filter_cmds[1] = "13\0";
filter_cmds[0] = "03";
filter_cmds[1] = "13";
filter_cmds[2] = "23";
filter_cmds[3] = "33";
filter_cmds[4] = "43\0";
filter_cmds[4] = "43";
filter_cmds[5] = "53";
filter_cmds[6] = "63";
filter_cmds[7] = "72\0";
filter_cmds[7] = "72";
filter_cmds[8] = "82";
filter_cmds[9] = "92";
filter_cmds[10] = "A1";
......@@ -972,105 +993,109 @@ int driver_obs_obsdaq::init() {
***************************************************************************/
int driver_obs_obsdaq::init_run(double freq){
// The receive buffer
char buf[200];
// A command to send
char cmd[20];
// Index of the selected frequency
int freq_sel;
// ADC calibration
int adc_scale, adc_offset;
/////////////////////////////////////////////////////////////////////
//
// Set frequency.
//
/////////////////////////////////////////////////////////////////////
// Set triggering off
send("#PP00000000");
usleep(1e6);
// The receive buffer
char buf[200];
// A command to send
char cmd[20];
// Index of the selected frequency
int freq_sel;
// Find the closest possible valid frequency lower or equal to the one
// requested.
for (int i=0; i<valid_filter_rates_num; i++){
if (valid_filter_rates[i]>freq){
freq_sel=i;
break;
}
}
// ADC calibration
int adc_scale, adc_offset;
/////////////////////////////////////////////////////////////////////
//
// Set frequency.
//
/////////////////////////////////////////////////////////////////////
// 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]);
send(cmd); waitanswer(5);
// Find the closest possible valid frequency.
for (int i=0; i<valid_filter_rates_num; i++){
if (valid_filter_rates[i]>=freq){
freq_sel = i;
break;
}
}
// Print used and requested frequency
fprintf(stderr,"Frequency set to: %6.2f Hz. "
"Requested frequency: %6.2f Hz.\n",
valid_filter_rates[freq_sel],freq);
// Set the frequency
driver_obs::freq = valid_filter_rates[freq_sel];
/////////////////////////////////////////////////////////////////////////
//
// Calibrate.
//
/////////////////////////////////////////////////////////////////////////
// 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]);
send(cmd); waitanswer(5);
}
// Iterate over all three channels
for (int i=0; i<3; i++){
// Print used and requested frequency
fprintf(stderr,"Frequency set to: %6.2f Hz. "
"Requested frequency: %6.2f Hz.\n",
valid_filter_rates[freq_sel],freq);
/////////////////////////////////////////////////////////////////////////
//
// Calibrate.
//
/////////////////////////////////////////////////////////////////////////
int config=0;
// Get current 24-bit configuration (Manual 12.4.9)
sprintf(cmd,"$%1dRS",i);
send(cmd);
receive(buf,sizeof(buf),1);
fprintf(stderr,"REC_CONFIG: %s\n",buf);
// Iterate over all three channels
for (int i=0; i<3; i++){
// Get the last four bytes ("ccdd") and add channel number
config= (i<<16) + strtoul(&buf[7],NULL,16);
int config=0;
// Check if calibration for the given config
// was pre-determined
if (driver_obs::cal->get_adc_calibrate
(&adc_offset, &adc_scale, config)<0){
// Get current 24-bit configuration (Manual 12.4.9)
usleep(0.5*1e6);
flush();
sprintf(cmd,"$%1dRS",i);
send(cmd);
receive(buf,sizeof(buf),1);
fprintf(stderr,"REC_CONFIG: %s\n",buf);
// Automatic Calibration
auto_calibrate(i,1);
// Get the last four bytes ("ccdd") and add channel number
config= (i<<16) + strtoul(&buf[7],NULL,16);
} else {
// Check if calibration for the given config
// was pre-determined
if (driver_obs::cal->get_adc_calibrate
(&adc_offset, &adc_scale, config)<0){
// Set the pre-determined calibration constant
sprintf(cmd,"$%1dWO%06X",i,adc_offset);
send(cmd); waitanswer(5);
sprintf(cmd,"$%1dWF%06X",i,adc_scale);
send(cmd); waitanswer(5);
// Automatic Calibration
// auto_calibrate(i,1);
}
} else {
//printf("============ GOT: %06X %06X\n",adc_offset,adc_scale);
// Set the pre-determined calibration constant
sprintf(cmd,"$%1dWO%06X",i,adc_offset);
send(cmd); waitanswer(5);
sprintf(cmd,"$%1dWF%06X",i,adc_scale);
send(cmd); waitanswer(5);
}
//printf("============ GOT: %06X %06X\n",adc_offset,adc_scale);