// mess.cxx
//
// This file is part of galvani.
// 
// Copyright (C) 2020-2024 Burkard Lutz <b.lutz@online.de>
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.


#include <glib.h>
#include <gtkmm.h>
#include <gtkmm/drawingarea.h>
#include <string>
#include <cairomm/context.h>
#include <gtkmm/window.h>
#include <ctime>
#include <glibmm/main.h>
#include <iostream>
#include <cmath>
#include <libserial/SerialPort.h>
#include <glibmm/i18n.h>
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <thread>
#include "spline.h"

#include "mess.h"

using namespace std;


//////////////// Multimeter /////////////////////////

Multimeter::Multimeter ()	//Standard: Digitalmultimeter mit Standardwerten
{
	dmm_name = "";
	int_face = "";
	dmm_typ = DMM;
	dmm_baud = LibSerial::BaudRate::BAUD_9600;
	dmm_charsize = LibSerial::CharacterSize::CHAR_SIZE_7;
	dmm_flowcontrol = LibSerial::FlowControl::FLOW_CONTROL_NONE;
	dmm_stopbits = LibSerial::StopBits::STOP_BITS_2;
	dmm_parity = LibSerial::Parity::PARITY_NONE;
	dmm_polling = true;
	scpi = false;
	usb = false;
	num_bytes = 0;
	num_val = 1;
	ms_timeout = 100;
	m_funkt = _("DC Voltage");
	m_range = "2 V";
	remote_cfg = false;
	remote_ctrl_strings [0] = {DCV, ""};
	remote_ctrl_strings [1] = {ACV, ""};
	remote_ctrl_strings [2] = {DCmA, ""};
	remote_ctrl_strings [3] = {ACmA, ""};
	remote_ctrl_strings [4] = {DCA, ""};
	remote_ctrl_strings [5] = {ACA, ""};
	remote_ctrl_strings [6] = {Res, ""};
	remote_ctrl_strings [7] = {Cond, ""};
	remote_ctrl_strings [8] = {pH, ""};
	remote_ctrl_strings [9] = {Temp, ""};	
}

Multimeter::~Multimeter ()
{

}

void Multimeter::set_ctrlstr (mfkt funktion, std::string ctrl)
{
	for (int i=0; i<=9; i++)
	{
		
		if (remote_ctrl_strings[i].fkt == funktion) 
		{
			remote_ctrl_strings[i].ctrl = ctrl;
			break;
		}
	}
	return;
}

std::string Multimeter::get_ctrlstr (mfkt funktion)
{
	std::string ctrl;
	for (int i=0; i<=9; i++)
	{
		if (remote_ctrl_strings[i].fkt == funktion) 
		{
			ctrl = remote_ctrl_strings[i].ctrl;
			break;
		}
	}
	return ctrl;
}

int Multimeter::random_nr (int min, int max)
{
	int	rand_nr;
	
	rand_nr = rand() % max + min;
	return rand_nr;
}

bool Multimeter::connect_usb (std::string port)
{
	int flags;
	
	usb_port = open(port.c_str(), O_RDWR);
		
    if (usb_port == -1) 
	{
		return false;
    }
    else
	{
    	flags = fcntl(usb_port, F_GETFL, 0);
    	fcntl(usb_port, F_SETFL, flags | O_NONBLOCK);
		return true;
	}
}

void Multimeter::connect_dmm (std::string int_face)
{
	int usb_port, tty;
	std::string mstr="", error_str; 
	std::string mwert="";
	
	if ((dmm_typ != DMM) && (dmm_typ != DEVICE))	//simulation
	{
		srand (time(NULL));
		m = 0.1 * random_nr (1, 10);
		a = 0.1 * random_nr (1, 10);
		k = 0.01 * random_nr (1, 10);
		n = random_nr(5, 20);
		for (int i=0;i<=n;i++)
		{
			P[i] = 0.00001 * random_nr (1, 10000);
			rt[i] = random_nr (1, 180);
			b[i] = 0.005 * random_nr (1, 100);
		}
		drift = 0.000005 * random_nr (0, 10);
		if (dmm_typ == PH)
		{
			set_tit_data (ha.npks);
		}		
		connected = true;
	}
	else
	{
		// detect connection port: USB or RS232C?
		usb_port = int_face.find ("usb");
		tty = int_face.find ("tty");
		if ((usb_port <= int_face.size()) && (tty > int_face.size())) usb = true;
		else usb = false;
		if (usb) connected = connect_usb (int_face);
		else		//RS232C
		{
			try
			{
				dmm_port.Open (int_face);
			}
			catch (const std::exception& err) 
			{					
				return;
			}
			if (!dmm_port.IsOpen())
			{
				return;
			} 
			//Baudrate
			dmm_port.SetBaudRate (dmm_baud);
			//Zeichenbreite
			dmm_port.SetCharacterSize (dmm_charsize);
			//FlowControl
			dmm_port.SetFlowControl (dmm_flowcontrol);
			//Stopbits
			dmm_port.SetStopBits (dmm_stopbits);
			//Parity
			dmm_port.SetParity(dmm_parity) ;
			//DTR
			dmm_port.SetDTR (true);
			//RTS
			dmm_port.SetRTS (false);
			if (dmm_flowcontrol == LibSerial::FlowControl::FLOW_CONTROL_SOFTWARE)	//only for Impo DMI4 ?
			{
				writeto_dmm ("V");	//say hello
				try
				{
					dmm_port.Read(mwert, num_bytes, ms_timeout); //read answer from dmm
				}
				catch (const LibSerial::ReadTimeout&) 
				{
					if (mwert.size() == 0) return;
				}
			}
			connected = true;
		}
	}
	return;
}

void Multimeter::disconnect_dmm ()
{
	if ((dmm_typ == DMM) || (dmm_typ == DEVICE))
	{
		if (usb) close(usb_port);
		else
		{
			try
			{
				dmm_port.Close ();
			}
			catch (...) 
			{
				return;
			}
		}
	}		
	connected = false;
	return;
}

void Multimeter::writeto_dmm (std::string wstr)
{
	const char* cstr;
	
	wstr.append ("\r");	//append CR
	cstr = wstr.c_str();
	if (usb) 
	{
		int result = write(usb_port, cstr, strlen(cstr));	// if result == -1 write failed
	}
	else dmm_port.Write(wstr);	//RS232C
	return;
}

std::string Multimeter::readfrom_dmm ()
{
	std::string mwert, extra_str;	// Data transmitted bei device. extra_str is omitted.
	std::string error_str;
	char buffer[1024];			// buffer to read from usb
	std::string poll;			// Polling character 

	if (scpi) 
	{
		dmm_polling = true;
		poll = "MEAS?"; 
	}
	else poll = "D";
	
	if (usb)
	{
		if (dmm_polling) writeto_dmm (poll);
		int result = read(usb_port, buffer, 1024);
    	if (result == -1) 
		{
        	error_str = _("Device unreachable: ") + dmm_name;
			fehler(error_str);
			connected = false;
        	close(usb_port);
			return ("");
    	}
    	buffer[result] = '\0';
		mwert.assign(buffer, result);
	}
	else 	//RS232C
	{
		if (!dmm_port.IsOpen())
			{
				error_str = _("Device unreachable: ") + dmm_name;
				fehler(error_str);
				connected = false;
				return ("");
			}
		dmm_port.DrainWriteBuffer();
		if (dmm_polling) writeto_dmm (poll);
		try
    	{
			dmm_port.Read(mwert, num_bytes, ms_timeout);
			if (num_val > 1) for (int i=1; i <= num_val; i++) dmm_port.Read(extra_str, num_bytes, ms_timeout);
    	}
		catch (const LibSerial::ReadTimeout&) {}
		
		if ((mwert.size() < 4)  && (dmm_name != "Impo DMI4"))
		// device unreachable or device error -> retry
		// Impo DMI4 sends several strings of different length
		{
			dmm_port.DrainWriteBuffer();
			usleep (100000);		//wait 100 msec
			if (dmm_polling) writeto_dmm (poll);
			try
    		{
				dmm_port.Read(mwert, num_bytes, ms_timeout);
				if (num_val > 1) for (int i=1; i <= num_val; i++) dmm_port.Read(extra_str, num_bytes, ms_timeout);
    		}
			catch (const LibSerial::ReadTimeout&) {}
		}
	}
	
	return mwert;
}

void Multimeter::setup (std::string funkt, std::string range)
{
	char prefix;
	std::string ctrl, error_str;

	if (range.length () > 0) prefix = range.at(range.length() - 1);	// get range-prefix
	if (funkt == _("DC Voltage")) ctrl = get_ctrlstr (DCV);
	else if (funkt == _("AC Voltage"))  ctrl = get_ctrlstr (ACV);
	else if (funkt == _("DC Current"))
	{
		if (prefix == ' ')  ctrl = get_ctrlstr (DCA);
		else  ctrl = get_ctrlstr (DCmA);
	}
	else if (funkt == _("AC Current"))
	{
		if (prefix == ' ')  ctrl = get_ctrlstr (ACA);
		else  ctrl = get_ctrlstr (ACmA);
	}
	else if (funkt == _("Resistance")) ctrl = get_ctrlstr (Res);
	else if (funkt == _("Conductivity")) ctrl = get_ctrlstr (Cond);
	else if (funkt == _("pH")) ctrl = get_ctrlstr (pH);
	else if (funkt == _("Temperature")) ctrl = get_ctrlstr (Temp);
	else 
	{
		error_str = _("Funktion not set: ") + funkt;
		fehler(error_str);
	}
	writeto_dmm (ctrl);
	
	return;
}

double Multimeter::sim_linear (double x)
{
	double result, r;
	
	srand (time(NULL));
	r = 0.02 * random_nr (1, 10);
	result = m * x + r;
	return result;
}

double Multimeter::sim_exp (double x)
{
	double result, r;

	srand (time(NULL));
	r = 0.001 * random_nr (1, 10);
	result = a * exp (-k * x) + r;
	return result;
}


double Multimeter::sim_ph (double x)
{
	double result;
	mw_data val;

	int i=0;
	while (i<tit_data.size())
	{
		val = tit_data.at(i);
		if (val.x > x) break;
		i++;
	}
	result = val.y;

	return result;
}

void Multimeter::set_tit_data (int npks)
// calculate titration curve according to 
// R. de Levie: "General expressions for acid-base titrations of arbitrary mixtures",
// Washington, 1995 (Technical report #7, Chemistry Department, Georgetown)
{
	double fa, ch, coh, vb, ph;
	const double kw = 1.0e-14;
	mw_data val;
	double ks[3];

	ph = 0.0;
	tit_data.clear ();
	while (ph < 14.0)
	{
		ch = pow(10,-ph);
		coh = kw / ch;
		for (int i=0; i<npks; i++) ks[i] = pow(10,-ha.pks[i]);
		if (npks==1) fa = ks[0] /(ch + ks[0]);
		else if (npks == 2) fa = ch * ks[0] / (pow(ch,2) + ch*ks[0] + ks[0]*ks[1]) + 2 * ks[1] / (ch + ks[1]);
		else if (npks == 3) fa = (pow(ch,2)*ks[0] + 2*ch*ks[0]*ks[1])/ (pow(ch,3) + pow(ch,2)*ks[0] + ch*ks[0]*ks[1] + ks[0]*ks[1]*ks[2])
									+ 3*ks[2]/(ch + ks[2]);		
		vb = va*(fa * ca - ch + coh) / (cb + ch - coh);
		val.x = vb / tit_volspeed;		// ml -> sec 
		val.y = ph;
		tit_data.push_back(val);
		ph += 0.01;	
	}
	
	return;
}


double Multimeter::sim_peak (double x)
{
	double result;

	result = 0;
	// Gauss-Funktion
	for (int i=0;i<=n;i++)
	{
		result = result + P[i] * exp(-0.5 * pow((x - rt[i])/b[i],2));
	}
	result = result + drift * x;
	return result;
}


double Multimeter::sim_spekt (double x)
{
	double result;

	result = 0;
	// Lorentz-Funktion
	for (int i=0;i<=n;i++)	
	{
		result = result + 5*P[i] * 1 / (1 + pow((x - rt[i]),2) / 5*b[i]);
	}
		
	
	return result;
}

m_record Multimeter::get_mwert_dmm (std::string mwert)	// Voltcraft, Metex and others
{
	m_record messw;
	std::string mwert_funkt, mwert_digits, mwert_unit, dezimal;
	int i, digit_start, digit_end, dotpos;
	struct lconv *lc  = localeconv();
	
	lc=localeconv();
	dezimal = lc->decimal_point;
	for (i=0; i<mwert.size();i++)				// find 1.number
	{
		if ((mwert.at(i) > 44) && (mwert.at(i) < 58)) 	// number, minus or decimal point (+ /)
		{
			digit_start = i;
			break;
		}
	}
	if (i == mwert.size()) 	// No data -> OL	mw=0?!
	{
		fehler (_("Device Error"));
		messw.digits = 0.0;
		
		return messw;
	}
	for (i=digit_start; i<mwert.size(); i++)	// find last number
	{
		if ((mwert.at(i) < 44) || (mwert.at(i) > 58))	// number, minus or decimal point
		{
			digit_end = i;
			break;
		}
	}
	if (mwert.at(digit_start -1) == '-') digit_start--;	//negative value?
	mwert_funkt = mwert.substr(0, digit_start);
	mwert_unit = mwert.substr(digit_end, mwert.size());
	mwert_digits = mwert.substr(digit_start, digit_end - digit_start);
	if (dezimal == ",")
	{
		dotpos = mwert_digits.find (".");
		if (dotpos <= mwert_digits.length()) mwert_digits.replace (dotpos,1,",");
	}
	messw.digits = get_dbstr(mwert_digits);

	/////// Messfunktion finden  //////////////
	if ((mwert_funkt.find ("DC") <= mwert_funkt.length()) && (mwert_unit.find ("V") <= mwert_unit.length())) 
		mwert_funkt = _("DC Voltage");
	else if ((mwert_funkt.find ("AC") <= mwert_funkt.length()) && (mwert_unit.find ("V") <= mwert_unit.length())) 
		mwert_funkt = _("AC Voltage");
	else if ((mwert_funkt.find ("DC") <= mwert_funkt.length()) && (mwert_unit.find ("A") <= mwert_unit.length())) 
		mwert_funkt = _("DC Current");
	else if ((mwert_funkt.find ("AC") <= mwert_funkt.length()) && (mwert_unit.find ("A") <= mwert_unit.length())) 
		mwert_funkt = _("AC Current");
	else if (mwert_unit.find ("C") <= mwert_unit.length()) mwert_funkt = _("Temperature");
	else if (mwert_unit.find ("O") <= mwert_unit.length()) mwert_funkt = _("Resistance");
	else if (mwert_unit.find ("o") <= mwert_unit.length()) mwert_funkt = _("Resistance");
	else if (mwert_unit.find ("pH") <= mwert_unit.length()) mwert_funkt = _("pH");
	else if (mwert_unit.find ("S") <= mwert_unit.length()) mwert_funkt = _("Conductivity");
	else 
	{
		mwert_funkt = "?";
		fehler (_("unknown function"));
	}
	messw.funktion = mwert_funkt;
	
	///// Einheit finden /////////
	
	if (mwert_unit.find ("mV") <= mwert_unit.length()) mwert_unit = "mV";
	else if (mwert_unit.find ("uV") <= mwert_unit.length()) mwert_unit = "uV";
	else if (mwert_unit.find ("nV") <= mwert_unit.length()) mwert_unit = "nV";
	else if (mwert_unit.find ("kV") <= mwert_unit.length()) mwert_unit = "kV";
	else if (mwert_unit.find ("V") <= mwert_unit.length()) mwert_unit = "V";
	
	else if (mwert_unit.find ("mA") <= mwert_unit.length()) mwert_unit = "mA";
	else if (mwert_unit.find ("uA") <= mwert_unit.length()) mwert_unit = "uA";
	else if (mwert_unit.find ("nA") <= mwert_unit.length()) mwert_unit = "nA";
	else if (mwert_unit.find ("A") <= mwert_unit.length()) mwert_unit = "A";
	
	else if (mwert_unit.find ("C") <= mwert_unit.length()) mwert_unit = "°C";
	
	else if (mwert_unit.find ("kO") <= mwert_unit.length()) mwert_unit = "kOhm";
	else if (mwert_unit.find ("ko") <= mwert_unit.length()) mwert_unit = "kOhm";
	else if (mwert_unit.find ("MO") <= mwert_unit.length()) mwert_unit = "MOhm";
	else if (mwert_unit.find ("Mo") <= mwert_unit.length()) mwert_unit = "MOhm";
	else if (mwert_unit.find ("O") <= mwert_unit.length()) mwert_unit = "Ohm";
	else if (mwert_unit.find ("o") <= mwert_unit.length()) mwert_unit = "Ohm";
	
	else if (mwert_unit.find ("pH") <= mwert_unit.length()) mwert_unit = "pH";
	
	else if (mwert_unit.find ("mS") <= mwert_unit.length()) mwert_unit = "mS/cm";
	else if (mwert_unit.find ("uS") <= mwert_unit.length()) mwert_unit = "uS/cm";
	else if (mwert_unit.find ("S") <= mwert_unit.length()) mwert_unit = "S/cm";
	else 
	{
		mwert_unit = "?";
		fehler (_("unknown unit"));
	}
	messw.unit = mwert_unit;
	return messw;
}

m_record Multimeter::get_mwert_scpi (std::string mwert)		// dmm with scpi
{
	m_record messw;
	std::string error_str;

	messw.digits = get_dbstr(mwert);
	messw.funktion = get_scpi_funkt();
	if (messw.funktion.find("?") <= messw.funktion.size())	// unknown function? ->retry
	{
		messw.funktion = get_scpi_funkt();
		if (messw.funktion.find("?") <= messw.funktion.size())
		{
			messw.funktion.erase(messw.funktion.find("?"),1); // still unknown? -> return message from dmm
			error_str = _("unknown function");
			error_str += ": ";
			error_str += messw.funktion;
			fehler (error_str);
		}
	}
	messw.unit = set_std_unit (messw.funktion);		// set standard unit
	
	return messw;
}

std::string Multimeter::get_scpi_funkt()
{
	std::string funkt, msg;

	writeto_dmm ("FUNC?");
	usleep (100);		//wait for device to become ready
	msg = readfrom_dmm ();
	while (msg.find('"') <= msg.size())		// delete extra characters
	{
		msg.erase (msg.find('"'),1);
	} 
	msg.erase (msg.find("\n"),1);
	if (msg == "VOLT") funkt = _("DC Voltage");
	else if (msg == "VOLT AC") funkt = _("AC Voltage");
	else if (msg == "CURR") funkt = _("DC Current");
	else if (msg == "CURR AC") funkt = _("AC Current");
	else if (msg == "RES") funkt =  _("Resistance");
	else if (msg == "TEMP") funkt =  _("Temperature");
	else if (msg == "PH") funkt =   _("pH");
	else 
	{
		funkt = "?";
		funkt += msg;
	}
	return funkt;
}

m_record Multimeter::get_mwert_impo_dmi4 (std::string mwert)	// Impo DMI4
{
	m_record messw;
	std::string mval1, mval2, mval3, mval4;
	char prefix;
	int i, start;
	

	i=0;
	start = 0;
	mval1 = mval2 = mval3 = mval4 = "";		// received data-string consists of 3 or 4 values
	
	//split mwert
	while (i<=mwert.length())
	{
		if (mwert.at(i) == 44) break;	// ","
		else i++;
	}
	mval1 = mwert.substr(start, i);		// Temperature
	start = ++i;
	while (i<=mwert.length())
	{
		if (mwert.at(i) == 44) break;
		else i++;
	}
	mval2 = mwert.substr(start, i-start);		// pH
	start = ++i;
	while (i<mwert.length())
	{
		if (mwert.at(i) == 44) break;
		else i++;
	}
	mval3 = mwert.substr(start, i-start);		// pressure -> omitted
	if (mwert.length() > i)
	{
		start = ++i;
		mval4 = mwert.substr(start);		// other function
	}
	if (m_funkt == _("Temperature"))
	{
		messw.digits = get_dbstr (mval1);
		messw.funktion = m_funkt;
		messw.unit = "°C";
	}
	else if (m_funkt == _("pH"))
	{
		messw.digits = get_dbstr (mval2);
		messw.funktion = m_funkt;
		messw.unit = "pH";
	}
	else
	{
		messw.digits = get_dbstr (mval4);
		messw.funktion = m_funkt;
		if ((m_funkt == _("DC Voltage")) || (m_funkt == _("AC Voltage"))) messw.unit = "V";
		else if ((m_funkt == _("DC Current")) || (m_funkt == _("AC Current"))) messw.unit = "A";
		/*{
			prefix = m_range.at(m_range.length() - 1);	// get range-prefix
			if (prefix == ' ') messw.unit = "A";
			else messw.unit = "mA";
		}*/
		else if (m_funkt == _("Resistance")) messw.unit = "Ohm";
		else if (m_funkt == _("Conductivity")) messw.unit = "S";
	}
	
	return messw;
}


m_record Multimeter::read_mm ()		// converts strings from dmm to records 
{
	m_record messw;					// result of measurement	
	std::string mwert;	
	std::string error_str;
	
	mwert = "";
	mwert = readfrom_dmm ();
	
	if ((mwert.size() < 4)  && (dmm_name != "Impo DMI4"))
		// device unreachable or device error -> retry
		// Impo DMI4 sends several strings of different length
	{
		error_str = _("Transmission error: ") + dmm_name + " " + _("Measurement aborted");
		fehler(error_str);
		messw.digits = 0.0;
		messw.funktion = "?";
		messw.unit = "?";
		stop_mess ();
		if (connected) disconnect_dmm();
		return messw;
    }
	if (dmm_name == "Impo DMI4") messw = get_mwert_impo_dmi4 (mwert);
	else if (scpi) messw = get_mwert_scpi (mwert);
	else messw = get_mwert_dmm (mwert);
	
	return messw;
}

m_record Multimeter::read_dmm ()
{
	m_record messw;
	std::string dialog;
		
	messw.funktion = m_funkt;
	messw.unit = set_std_unit (messw.funktion);	//?
	switch (dmm_typ)
	{
		case LINEAR:
			messw.digits = sim_linear(mt);
			break;
		case EXP:
			messw.digits = sim_exp(mt);
			break;
		case PH:
			messw.digits = sim_ph(mt);
			messw.funktion = "pH";
			break;
		case PEAK:
			messw.digits = sim_peak(mt);
			break;
		case SPEKTRUM:
			messw.digits = sim_spekt(mt);
			messw.funktion = _("Absorption");
			messw.unit = _("Intensity");
			break;
		case DEVICE:
			messw = read_device();
			break;
		default:
			messw = read_mm();
	}
	if ((messw.funktion != m_funkt) && (messw.funktion != "?") && (messw.funktion != ""))
	{
		dialog = _("Multimeter function");
		dialog += " (";
		dialog += messw.funktion;
		dialog += ") ";
		dialog += _("differs from Project function");
		dialog += " (";
		dialog += m_funkt;
		dialog += ") ";
		dialog +=_("- continue measurement?");
		if (!dialog_ok (dialog))
		{
			stop_mess ();
			end_mess ();
		}
	}
	//delete unit prefix and multiply value with appropiate faktor
	if ((messw.funktion != "pH") && (messw.funktion != "?")) messw = get_std_unit (messw);
	return messw;
}

m_record Multimeter::read_lutron_ph207 ()
{
	m_record messw;
	std::string mwert, mstr, error_str, val_str;
	int dim;
	char chr;
	
	
	if (!dmm_port.IsOpen())
		{
			error_str = _("Device unreachable: ") + dmm_name;
			fehler(error_str);
			messw.digits = 0.0;
			return (messw);
		}
	messw.funktion = "pH";
	messw.unit = "pH";
	mwert = "";
	dmm_port.FlushInputBuffer(); 	// forget all data in input buffer
	while (mwert.length () < 16)
	{
		mstr = "";
		try
    	{
			dmm_port.Read(mstr, num_bytes, ms_timeout);		
    	}
		catch (const LibSerial::ReadTimeout&)
    	{
       		//fehler (_("Device Error"));
    	}
		if (mstr.length() == 0)
		{
			error_str = _("Device unreachable: ") + dmm_name;
			fehler(error_str);
			messw.digits = 0.0;
			disconnect_dmm ();
			return messw;
		}
		
		// drop character < '0' and > '?' (ReadError)
		for (int i=1; i < mstr.length(); i++)
		{
			chr = mstr.at(i);
			if (( chr < 48 ) || (chr > 63)) mstr.erase (i,1);
		}
		mwert += mstr;		
	}
	
	dim = get_intstr (mwert.substr(6,1));
	val_str = mwert.substr(11,4);
	messw.digits = get_dbstr(val_str) / pow (10, dim);	
	
	return messw;
}


m_record Multimeter::read_device ()
{
	m_record messw;

	if (dmm[1].dmm_name == "Lutron PH-207") messw = read_lutron_ph207 ();

	return messw;
}

m_record Multimeter::get_std_unit (m_record messw)	//delete unit prefix and multiply value with appropiate faktor
{
	double faktor;
	char16_t dim;
		
	if (messw.unit.size() > 1)
	{
		dim = messw.unit.at(0);
		switch(dim)
		{
			case 'p':
				faktor = 1.0e-12;
				messw.unit.erase(0,1);
				break;
			case 'n':
				faktor = 1.0e-9;
				messw.unit.erase(0,1);
				break;
			case 'u':
				faktor = 1.0e-6;
				messw.unit.erase(0,1);
				break;
			case 'm':
				faktor = 1.0e-3;
				messw.unit.erase(0,1);
				break;
			case 'k':
				faktor = 1.0e+3;
				messw.unit.erase(0,1);
				break;
			case 'M':
				faktor = 1.0e+6;
				messw.unit.erase(0,1);
				break;
			case 'G':
				faktor = 1.0e+9;
				messw.unit.erase(0,1);
				break;
			default:
				faktor = 1.0;
		}	
		messw.digits = faktor * messw.digits;
	}

	return messw;
}


//////////////// Diagramm ///////////////////////////

Diagramm::Diagramm(GtkDrawingArea* cobject, const Glib::RefPtr<Gtk::Builder> &builder)
: Gtk::DrawingArea(cobject) 

{
	this->signal_draw().connect(sigc::mem_fun(this, &Diagramm::on_draw));
	
}

Diagramm::Diagramm()
{
	this->signal_draw().connect(sigc::mem_fun(this, &Diagramm::on_draw));
}

Diagramm::~Diagramm()
{
}


void Diagramm::draw_background (const Cairo::RefPtr<Cairo::Context> &ct)
{
	//Background
	ct->save();
	ct->set_source_rgb(bkcol_r, bkcol_g, bkcol_b);
    ct->paint();
	ct->stroke();
	ct->restore();
}

void Diagramm::draw_coord (const Cairo::RefPtr<Cairo::Context> &ct)
{
	string st, xystr;
	int pos, dec;
	int text_width, text_height;
			
	//Draw Axes
	ct->save();
	ct->set_source_rgb(axcol_r, axcol_g, axcol_b);
    ct->set_line_width(ps*scalefactor);
    ct->move_to(pxmin, pymax);
    ct->line_to(pxmin, pymin);
	ct->line_to(pxmax, pymin);
	font.set_size(pf*scalefactor*10*Pango::SCALE);
	diag_layout->set_font_description(font);
	
	//Axis marks
	dx = dxax*xscale; 		//Scale axis
	dy = dyax*yscale;
	dec = 2;
	if (xscale < 10) dec = 3;
	if (xscale < 1) dec = 4;
	if (xscale < 0.1) dec = 5;
	if (xscale < 0.01) dec = 6;
	n=1;
	do {
		x_n = xmin + n*ax_dx*dx;
		axp = round((x_n - xmin)/xscale*(pxmax-pxmin))+pxmin;
		ct->move_to(axp, pymin);
		ct->line_to(axp,pymin+20);
		xystr = to_string(x_n);
		pos=xystr.find(',');
		xystr.resize(pos+dec);
		diag_layout->set_text(xystr);
		diag_layout->get_pixel_size(text_width, text_height);
		diag_layout->update_from_cairo_context (ct);
		ct->move_to(axp - text_width/2, pymin + margin/3 - text_height/2);
		diag_layout->show_in_cairo_context(ct);
		n++;
	} while(axp<pxmax);
	dec = 2;
	if (yscale < 10) dec = 3;
	if (yscale < 1) dec = 4;
	if (yscale < 0.1) dec = 5;
	if (yscale < 0.01) dec = 6;
	n=1;
	axp=pymin;
	while(axp>pymax) {
		y_n = ymin + n*ax_dy*dy;
		axp = pymin-round((y_n - ymin)/yscale*(pymin-pymax));
		ct->move_to(pxmin,axp);
		ct->line_to(pxmin-20,axp);
		xystr = to_string(y_n);
		pos=xystr.find(',');
		xystr.resize(pos+dec);
		diag_layout->set_text(xystr);
		diag_layout->get_pixel_size(text_width, text_height);
		diag_layout->update_from_cairo_context (ct);
		ct->move_to(pxmin - text_width - 0.2*margin, axp - text_height/2);
		diag_layout->show_in_cairo_context(ct);
		n++;
	}
	
	//Axis labeling and diagram title
	if (showtitle)
	{
		st = project->title;
		font.set_size(pf*scalefactor*14*Pango::SCALE);
		diag_layout->set_font_description(font);
		diag_layout->set_text(st);
		diag_layout->get_pixel_size(text_width, text_height);
		diag_layout->update_from_cairo_context (ct);
		ct->move_to(width/2 - text_width/2, pymax - margin/2 - text_height/2);
		diag_layout->show_in_cairo_context(ct);
	}
	st = unit_y;
	pos = st.find("u");
	if (pos <= st.length()) st.replace(pos,1,"µ");
	st = funktion_y + " [" + st +"]";
	font.set_size(pf*scalefactor*10*Pango::SCALE);
	diag_layout->set_font_description(font);
	diag_layout->set_text(st);
	diag_layout->get_pixel_size(text_width, text_height);
	diag_layout->update_from_cairo_context (ct);
	ct->move_to(pxmin-margin+10,pymax-2*text_height);
	diag_layout->show_in_cairo_context(ct);
	st = unit_x;
	pos = st.find("u");
	if (pos <= st.length()) st.replace(pos,1,"µ");
	st = funktion_x + " [" + st +"]";
	diag_layout->set_text(st);
	diag_layout->get_pixel_size(text_width, text_height);
	diag_layout->update_from_cairo_context (ct);
	ct->move_to(pxmax-text_width,pymin + 0.60*margin - text_height/2);
	diag_layout->show_in_cairo_context(ct);
		
	ct->stroke();
	ct->restore();
	
	//show grid
	if (grid)
	{
		ct->save();
		ct->set_source_rgb(gridcol_r, gridcol_g, gridcol_b);
    	ct->set_line_width(ps*0.5*scalefactor);
 		n=1;
		do {
			x_n = xmin + n*grid_dx*dx;
			axp = round((x_n - xmin)/xscale*(pxmax-pxmin))+pxmin;
			ct->move_to(axp, pymin);
			ct->line_to(axp,pymax);
			n++;
		} while(axp<pxmax);
	
		n=1;
		axp=pymin;
		while(axp>pymax) {
			y_n = ymin + n*grid_dy*dy;
			axp = pymin-round((y_n - ymin)/yscale*(pymin-pymax));
			ct->move_to(pxmin,axp);
			ct->line_to(pxmax,axp);
			n++;
		}
	    ct->stroke();
		ct->restore();
	}
}

void Diagramm::find_xy_minmax ()	//find minima and maxima of values
{
	mw_data val;

	val = trafo (mw.at(0));
	xminval = xmaxval = val.x;
	yminval = ymaxval = val.y;
	for (unsigned long long int i=1; i<mi;i++)
	{
		val = trafo (mw.at(i));
		if (val.x < xminval) xminval = val.x;
		else if (val.x > xmaxval) xmaxval = val.x;
		if (val.y < yminval) yminval = val.y;
		else if (val.y > ymaxval) ymaxval = val.y;	
	}
	xabsmax = abs(xmaxval);		// get absolute maximum
	yabsmax = abs(ymaxval);
	if (abs(xminval) > xabsmax) xabsmax = abs(xminval);
	if (abs(yminval) > yabsmax) yabsmax = abs(yminval);
	
	return;
}


void Diagramm::set_coord_limits ()		//set limits for coordinate system
{
	double dx,dy,exp;
	
	// X
	xmin = xrange * xminval;
	xmax = xrange * xmaxval;
	if (xmin == xmax) 
	{
		xmax += 1.0;
		xmin -= 1.0;
	}
	xscale = xmax - xmin;
	// Y
	ymin = yrange * yminval;
	ymax = yrange * ymaxval;
	if (ymin == ymax) 
	{
		ymax += 1.0;
		ymin -= 1.0;
	}
	yscale = ymax - ymin;
	dy=yscale/10;
	exp = round(log10(dy));
	dy /= pow(10,exp);
	if (dy<0.1) dy= 0.1;
	else if (dy<0.2) dy= 0.2;
	else if (dy<0.5) dy= 0.5;
	else if (dy<1.0) dy= 1.0;
	else if (dy<2.0) dy= 2.0;
	else if (dy<5.0) dy= 5.0;
	else if (dy<10.0) dy= 10.0;
	dy *= pow(10,exp);
	yscale = 10.0 * dy;
	ymin = floor(ymin/dy)*dy;
	ymax = ymin + yscale;
	if (funktion_y == "pH") 
	{
		ymin = 0.0;
		ymax = 14.0;
		yscale = 14.0;
	}
	dx=xscale/10;
	exp = round(log10(dx));
	dx /= pow(10,exp);
	if (dx<0.1) dx= 0.1;
	else if (dx<0.2) dx= 0.2;
	else if (dx<0.5) dx= 0.5;
	else if (dx<1.0) dx= 1.0;
	else if (dx<2.0) dx= 2.0;
	else if (dx<5.0) dx= 5.0;
	else if (dx<10.0) dx= 10.0;
	dx *= pow(10,exp);
	xscale = 10.0 * dx;
	xmin = floor(xmin/dx)*dx;
	xmax = xmin + xscale;

	if (funktion_x == _("Wavelength")) 
	{
		xmin = 400.0;
		xmax = 800.0;
		xscale = 400.0;
	}
		
	return;
}

int Diagramm::scale_x (double x)
{
	int px;

	px = (x - xmin)/xscale*(pxmax-pxmin) + pxmin;
	return px;
}

int Diagramm::scale_y (double y)
{
	int py;

	py = pymin - (y - ymin)/yscale*(pymin-pymax);
	return py;
}

double Diagramm::get_xcoord (double xp)
{
	double x;

	x = (scalefactor*xp - pxmin) / (pxmax - pxmin) * xscale + xmin;
	return x;
}

double Diagramm::get_ycoord (double yp)
{
	double y;

	y = ymin - (scalefactor*yp - pymin) / (pymin - pymax) * yscale;
	return y;
}

void Diagramm::draw_cross (const Cairo::RefPtr<Cairo::Context> &ct, int symwidth)
{
	ct->rel_move_to(0, symwidth);
	ct->rel_line_to (0, -2*symwidth);
	ct->rel_move_to(-symwidth, symwidth);
	ct->rel_line_to (2*symwidth, 0);
	
	return;
}

void Diagramm::draw_square (const Cairo::RefPtr<Cairo::Context> &ct, int symwidth, bool filled)
{
	ct->rel_move_to(-symwidth, symwidth);
	ct->rel_line_to (0, -2*symwidth);
	ct->rel_line_to (2*symwidth, 0);
	ct->rel_line_to (0, 2*symwidth);
	ct->rel_line_to (-2*symwidth, 0);
	ct->close_path ();
	if (filled) ct->fill_preserve (); 
	return;
}

void Diagramm::draw_diamond (const Cairo::RefPtr<Cairo::Context> &ct, int symwidth, bool filled)
{
	ct->rel_move_to(0, symwidth);
	ct->rel_line_to (-symwidth, -symwidth);
	ct->rel_line_to (symwidth, -symwidth);
	ct->rel_line_to (symwidth, symwidth);
	ct->rel_line_to (-symwidth, symwidth);
	ct->close_path ();
	if (filled) ct->fill_preserve ();
	return;
}

void Diagramm::draw_circle (int x, int y, int symwidth, bool filled, const Cairo::RefPtr<Cairo::Context> &ct)
{
	ct->begin_new_sub_path();
	ct->arc(x,y,symwidth,0,2*M_PI);
	if (filled) ct->fill_preserve ();
	return;
}

void Diagramm::draw_symbol (int x, int y, symbol symb, int symwidth, bool filled, const Cairo::RefPtr<Cairo::Context> &ct)
{
	ct->move_to (x,y);
	switch(symb)
	{
		case cross: draw_cross(ct, symwidth); break;
		case square: draw_square(ct, symwidth, filled); break;
		case diamond: draw_diamond(ct, symwidth, filled); break;
		case circle: draw_circle(x,y, symwidth, filled, ct); break;
	}
	
	return;
}



void Diagramm::draw_xysymbol (const Cairo::RefPtr<Cairo::Context> &ct)
{	
	int px,py;
	mw_data val;
	
	ct->save();
	ct->set_source_rgb(xycol_r, xycol_g, xycol_b);
    ct->set_line_width(ps*0.5*scalefactor);
	for (unsigned long long int i=0; i<mi;i++)
	{
		val = trafo (mw.at(i));
		px = scale_x(xrange*val.x);
		py = scale_y(yrange*val.y);
		if ((py <= pymin) && (py >= pymax) && (px >= pxmin) && (px <= pxmax)) draw_symbol(px,py, mw_symbol, symw, symbol_filled, ct);
	}
	
	ct->stroke();
	ct->restore();
	return;
}


void Diagramm::draw_xyline (const Cairo::RefPtr<Cairo::Context> &ct)
{	
	int px,py;
	mw_data val;
	std::vector<double> pattern_pointed = {1,2};
	std::vector<double> pattern_dashed = {4,4,4};
	
	ct->save();
	// don't draw across border!
	ct->rectangle(margin,margin,width - 2*margin, height - 2*margin);
	ct->clip();
	ct->set_source_rgb(xycol_r, xycol_g, xycol_b);
    ct->set_line_width(ps*scalefactor);
	if (mw_linestyle == pointed) ct->set_dash(pattern_pointed,0.0);
	else if (mw_linestyle == dashed) ct->set_dash(pattern_dashed,0.0);
	val = trafo (mw.at(0));
	px = scale_x(xrange*val.x);
	py = scale_y(yrange*val.y);
	ct->move_to(px,py);
	for (unsigned long long int i=1; i<mi;i++)
	{
		val = trafo (mw.at(i));
		px = scale_x(xrange*val.x);
		py = scale_y(yrange*val.y);
		ct->line_to(px,py);
	}
	
	ct->stroke();
	ct->restore();
		
    return;
}

bool sort_mwx (mw_data i, mw_data j) {return (i.x < j.x);}

void Diagramm::draw_xycurve (const Cairo::RefPtr<Cairo::Context> &ct)
{
	tk::spline::spline_type type = tk::spline::cspline_hermite;
    tk::spline s;
	int n=1000;   				//number of points to plot the spline
	std::vector<mw_data> seg;	//segment of measured values (mw)
	std::vector<mw_data> t_mw;	//vector holds transformed values
	int np=100;					//max. number of values in segment
	int nps;					//number of values in actual segment
	unsigned long long int id,si=0;	//start position of segment in mw-array 
	mw_data val;
	int px,py;
	std::vector<double> pattern_pointed = {1,2};
	std::vector<double> pattern_dashed = {4,4,4};
	std::string error_str;

	ct->save();
	// don't draw across border!
	ct->rectangle(margin,margin,width - 2*margin, height - 2*margin);
	ct->clip();		
	ct->set_source_rgb(xycol_r, xycol_g, xycol_b);
    ct->set_line_width(ps*scalefactor);
	if (mw_linestyle == pointed) ct->set_dash(pattern_pointed,0.0);
	else if (mw_linestyle == dashed) ct->set_dash(pattern_dashed,0.0);

	try
	{
		t_mw = mw;
	}
	catch (...) 
	{
		error_str = _("Not enough space to calculate splines");
		fehler(error_str);
		return;
	}
	//transform values if selected
	for (unsigned long long i=0; i<t_mw.size(); i++)
	{
		t_mw.at(i) = trafo (t_mw.at(i));
	}
	// x-values must be ascending for calculation of splines
	if (t_mw.at(1).x < t_mw.at(0).x) std::sort (t_mw.begin(), t_mw.end(), sort_mwx);
	val = t_mw.at(0);
	px = scale_x(xrange*val.x);
	py = scale_y(yrange*val.y);
	ct->move_to(px,py);
	if (mi < 4)		//splines cannot be calculated -> draw lines
	{
		for (int i=1; i<mi;i++)
		{
			val = t_mw.at(i);
			px = scale_x(xrange*val.x);
			py = scale_y(yrange*val.y);
			ct->line_to(px,py);
		}
	}
	else
	{
		while (si < mi)
		{
			seg.clear ();		//split data values in segments to calculate splines
			for (int i=0; i<np; i++)
			{
				id = si + i;
				if (id<mi) seg.push_back(t_mw.at(id));
				else break;
			}
			nps = seg.size();
			if (nps < 3)		//splines cannot be calculated -> draw lines
			{
				for (int k=0; k<nps;k++)
				{
					val = seg.at(k);
					px = scale_x(xrange*val.x);
					py = scale_y(yrange*val.y);
					ct->line_to(px,py);
				}
				si += nps;	//last segment
			}
			else
			{
				// calculate spline coefficients
				if (s.set_points(seg,type) != 0)
				{
					error_str = _("Error calculating splines");
					fehler (error_str);
					return;
				}
    			s.make_monotonic();     // adjusts spline coefficients to be monotonic		
				for(int i=1; i<n; i++) 
				{
        			double x = seg.at(0).x + i*(seg.at(nps-1).x - seg.at(0).x)/n;
        			px = scale_x(xrange*x);	
					py = scale_y(yrange*s(x));
        			ct->line_to(px,py);
				}
				si += nps-1;		// begin next segment at last point of actual segment
			}			
		}
	}

	ct->stroke();
	ct->restore();
		
	return;
}


void Diagramm::draw_lin_regression(const Cairo::RefPtr<Cairo::Context> &ct)
{
	double y;
	int px,py;
	
	ct->save();
	// don't draw across border!
	ct->rectangle(margin,margin,width - 2*margin, height - 2*margin);
	ct->clip();
	
	ct->set_source_rgb(funktcol_r, funktcol_g, funktcol_b);
    ct->set_line_width(ps*scalefactor);
	y = mw_axis + mw_slope * xmin;
	px = pxmin;
	py = scale_y(yrange*y);
	ct->move_to(px,py);
	y = mw_axis + mw_slope * xmax;	
	px = pxmax;
	py = scale_y(yrange*y);
	ct->line_to (px,py);
	ct->stroke();
	ct->restore();
	
	return;
}


void Diagramm::draw_diff_funktion (const Cairo::RefPtr<Cairo::Context> &ct)
{
	int px,py;
	int text_width, text_height;
	mw_data val, val_1, val_2;
	double dx,dy,dxy;
	mw_data pxy;
	std::vector<mw_data> p; 	//array for calculating moving average of n values
	std::vector<mw_data> av;	//array for triangular data averages
	int np;						//size of dp
	int mp;						//center of p
				
	
	ct->save();
	// don't draw across border!
	ct->rectangle(margin,margin,width - 2*margin, height - 2*margin);
	ct->clip();	
	ct->set_source_rgb(funktcol_r, funktcol_g, funktcol_b);
    ct->set_line_width(ps*0.5*scalefactor);	
	val = val_1 = trafo(mw.at(0));	//Differential 1. value
	val_2 = trafo(mw.at(1)); 
	px = scale_x(xrange*val.x);
	dy = yrange*(val_2.y - val_1.y) / xrange*(val_2.x - val_1.x);
	py = pymin - (dy - diff_min)/(diff_max - diff_min)*0.8*(pymin-pymax);
	ct->move_to(px,py);	
	np = 5;				//set size of p
	mp = trunc (np / 2);		//calculate center of p
	
	for (unsigned long long int i=mp;i<mi-3*mp;i++)
	{
		av.clear();					//calculate triangular averages
		for (int k=0;k<np;k++)
		{
			p.clear();
			for (int n=0; n<np; n++)	// fill array with neighbours of value
			{
				pxy = trafo (mw.at(i-mp+n+k));					p.push_back (pxy);
			}
			pxy= mv_av(p);
			av.push_back (pxy);
		}
		dx = xrange*(av.at(mp+1).x - av.at(mp-1).x);	//calculate derivatives
		dy = yrange*(av.at(mp+1).y - av.at(mp-1).y);
		if (dx !=0) 
		{
			dxy = dy/dx;
			pxy.x = xrange*(av.at(mp).x);
			pxy.y = dxy;
			px = scale_x(pxy.x);
			py = pymin - (pxy.y - diff_min)/(diff_max - diff_min)*0.8*(pymin-pymax);
			draw_symbol (px,py,diamond, 5, true, ct);
		}
	}
	
	if (ndiff != 0)
	{
		//draw gauss fit of maxima
		dx = xscale /1000;
		pxy.x = xmin;
		pxy.y = 0;
		for (int k=0;k<ndiff;k++)
			{
				pxy.y += diff.at(k).P * exp (-0.5 * pow((pxy.x - diff.at(k).m),2) / pow(diff.at(k).b,2));
			}
		px = scale_x(pxy.x);
		py = pymin - (pxy.y - diff_min)/(diff_max - diff_min)*0.8*(pymin-pymax);
		ct->move_to(px,py);
		for (int i=0;i<1000;i++)
		{
			pxy.x += dx;
			pxy.y = 0;
			for (int k=0;k<ndiff;k++)
			{
				pxy.y += diff.at(k).P * exp (-0.5 * pow((pxy.x - diff.at(k).m),2) / pow(diff.at(k).b,2));
			}
			px = scale_x(pxy.x);
			py = pymin - (pxy.y - diff_min)/(diff_max - diff_min)*0.8*(pymin-pymax);
			ct->line_to(px,py);
		}
	}		
	
	//label curve
	ct->reset_clip();
	font.set_size(pf*scalefactor*10*Pango::SCALE);
	diag_layout->set_font_description(font);
	if (ndiff != 0) diag_layout->set_text(_("Derivative with Gauss model"));
	else diag_layout->set_text(_("Derivative"));
	diag_layout->get_pixel_size(text_width, text_height);
	diag_layout->update_from_cairo_context (ct);
	ct->move_to(pxmax-text_width ,pymax-2*text_height);
	diag_layout->show_in_cairo_context(ct);	
	
	ct->stroke();
	ct->restore();
	
	return;
}


void Diagramm::draw_peak_integration (const Cairo::RefPtr<Cairo::Context> &ct)
{
	int n;
	int px, py;
	mw_data val;
		
	ct->save();
	// don't draw across border!
	ct->rectangle(margin,margin,width - 2*margin, height - 2*margin);
	ct->clip();
	if (show_peakarea)
	{
		ct->set_source_rgb(funktcol_r, funktcol_g, funktcol_b);
    	ct->set_line_width(ps*2*scalefactor);
		for (n=0; n<peaks.size (); n++)	//draw line for each Peak at Max. (Length is equal to percentage)
		{
			px = scale_x (peaks[n].max.x);
			py = pymin;		
			ct->move_to (px, py);
			py = pymin - peaks[n].area/peaks_area * (pymin-pymax);
			ct->line_to(px, py);		
		}
	}
	ct->stroke();
	ct->restore();
	
	if (show_baseline)
	{
		ct->save();
		ct->set_source_rgb(gridcol_r, gridcol_g, gridcol_b);
		px = pxmin;
		yb = yb_a1 * xmin/xrange + yb_a0;
		py = scale_y(yrange*yb);
		ct->move_to (px, py);
		px = pxmax;
		yb = yb_a1 * xmax/xrange + yb_a0;
		py = scale_y(yrange*yb);
		ct->line_to (px, py);
		ct->stroke();
		ct->restore();
	}
	if (show_peaklimits)
	{
		ct->save();
		ct->set_source_rgb(gridcol_r, gridcol_g, gridcol_b);
		for (n=0; n<peaks.size (); n++)	//draw limits for each Peak
		{
			val = trafo(mw.at(peaks[n].xb1));
			px = scale_x (xrange*val.x);
			py = pymin;		
			ct->move_to (px, py);
			yb = yb_a1 * val.x + yb_a0;
			py = scale_y(yrange*yb);
			ct->line_to(px, py);
			val = trafo(mw.at(peaks[n].xb2));
			px = scale_x (xrange*val.x);
			py = pymin;		
			ct->move_to (px, py);
			yb = yb_a1 * val.x + yb_a0;
			py = scale_y(yrange*yb);
			ct->line_to(px, py);
		}
		ct->stroke();
		ct->restore();
	}
	
	
	
	return;
}



bool Diagramm::on_draw(const Cairo::RefPtr<Cairo::Context> &ccontext)
{
	double x,y;
	mw_data val;
	
	Gtk::Allocation allocation = get_allocation();
	diag_width = allocation.get_width();
	diag_height = allocation.get_height();
	width = trunc (scalefactor * diag_width);
	height = trunc(scalefactor * diag_height);
	diag_sf = Cairo::ImageSurface::create(Cairo::FORMAT_ARGB32, width, height);
	diag_ct = Cairo::Context::create (diag_sf);
	diag_layout = Pango::Layout::create(diag_ct);
	diag_layout->update_from_cairo_context (diag_ct);
	font = Pango::FontDescription("Sans 10"); 
	diag_layout->set_font_description(font);
	width = diag_sf->get_width();
	height = diag_sf->get_height();
	
	//margin of axes
	margin = trunc(0.05*width + scalefactor * 20);

	//origin of diagram and maximum extent
	pxmin = margin;
	pymin = height-margin;
	pxmax = width-margin;
	pymax = margin;

	//set function and unit
	funktion_x = eval_funkt(0,project->funktion_x);
	unit_x = eval_unit(0,project->unit_x);
	funktion_y = eval_funkt(1,project->funktion_y);
	unit_y = eval_unit(1,project->unit_y);	

	diag_ct->set_operator (Cairo::OPERATOR_CLEAR);	//clear drawing area
	diag_ct->paint ();
	diag_ct->set_operator (Cairo::OPERATOR_OVER);
	draw_background (ccontext);
	if (!reset_diag) 
	{
		if (mw.size() != 0) 
		{
			find_xy_minmax();	// find minmima and maxima of values
			set_unit();			// set unit prefix and rearrange values
			if (autoscale) set_coord_limits();	// set limits for coordinate system
			//display values
			if (show_display) 
			{
				val = trafo(mw.at(mi-1));
				x = xrange * val.x;
				y = yrange * val.y;
				m_record xmval;
				xmval.digits = x;
				xmval.funktion = funktion_x;
				xmval.unit = unit_x;
				m_record ymval;
				ymval.digits = y;
				ymval.funktion = funktion_y;
				ymval.unit = unit_y;
				display_mw  (xmval, ymval);
			}
		}
		draw_coord (diag_ct);	 //draw coordinates
		if (mw.size() != 0) 
		{
			if (mw_symbol != none) draw_xysymbol(diag_ct);		//draw points
			if (mw_line) draw_xyline(diag_ct);					//draw line
			else if (mw_curve) draw_xycurve(diag_ct);
			if (eval_reglin) draw_lin_regression(diag_ct);
			if (eval_diff) draw_diff_funktion (diag_ct);
			if (eval_integration) draw_peak_integration (diag_ct);
			if (selection_frame) draw_selection_frame (xmin_new, ymax_new, xmax_new, ymin_new, diag_ct);
		}
	}

	scale_width = diag_width;
	scale_width /= width;
	scale_height = diag_height;
	scale_height /= height;
	ccontext->scale (scale_width, scale_height);
	ccontext->set_source (diag_sf, 0, 0);
	ccontext->paint();
	
	///////////////////////////////
		
    return true;	
}

bool Diagramm::on_timeout()
{
	if (mw.size() != 0) 
	{
		get_val();
		queue_draw ();	// redraw diagram
	}
	
    return true;
}


bool Diagramm::start_mt()
{
	if (!timeout_handler.connected())timeout_handler = Glib::signal_timeout().connect( sigc::mem_fun(*this, &Diagramm::on_timeout), mtime );
	if (timeout_handler.blocked()) timeout_handler.unblock();
	return true;
}

bool Diagramm::stop_mt()
{
	timeout_handler.block();
	return true;
}

void Diagramm::draw_selection_frame (double x_1, double y_1, double x_2, double y_2, const Cairo::RefPtr<Cairo::Context> &ct)
{
	int px1, py1, px2, py2, width, height;

	ct->save();	
	ct->set_source_rgba(0.0, 0.2, 1.0, 0.8);
	ct->set_line_width(scalefactor);
	px1 = scale_x (x_1);
	px2 = scale_x (x_2);
	py1 = scale_y (y_1);
	py2 = scale_y (y_2);
	width = px2 - px1;
	height = py2 - py1;
	ct->rectangle (px1, py1, width, height);
	ct->stroke_preserve ();	
	ct->set_source_rgba(0.0, 0.2, 1.0, 0.1);
	ct->fill();
	
	ct->stroke ();
	ct->restore ();
	
	
	return;
}

bool Diagramm::on_motion_notify_event (GdkEventMotion *motion)
{
	m_record xval, yval;
	
	xval.digits = get_xcoord(motion->x);
	xval.unit = unit_x;
	yval.digits = get_ycoord(motion->y);
	yval.unit = unit_y;
	display_mw (xval, yval);
	
	if (motion->state == GDK_BUTTON_MOTION_MASK + GDK_BUTTON_PRESS_MASK)
	{
		xmax_new = get_xcoord(motion->x);
		ymin_new = get_ycoord(motion->y);
		selection_frame = true;
		queue_draw ();
	}
		
	return true;
}

bool Diagramm::on_button_press_event (GdkEventButton *pos)
{
	xmin_new = get_xcoord(pos->x);
	ymax_new = get_ycoord(pos->y);
	
	return true;
}

bool Diagramm::on_button_release_event (GdkEventButton *pos)
{
	double x1, y1, x2, y2, ex;
	int n;

	save_autoscale = autoscale; // save autoscale state
	autoscale = false;
	if (!coord_saved)
	{
		xmin_reset = xmin;
		ymin_reset = ymin;
		xmax_reset = xmax;
		ymax_reset = ymax;
		coord_saved = true;
	}
	if (xmax_new < xmin_new) 
	{
		x1 = xmax_new;
		x2 = xmin_new;
	}
	else
	{
		x1 = xmin_new;
		x2 = xmax_new;
	}
	if (ymax_new < ymin_new) 
	{
		y1 = ymax_new;
		y2 = ymin_new;
	}
	else
	{
		y1 = ymin_new;
		y2 = ymax_new;
	}
	if (x1 > xmin) xmin = x1;
	if (x2 < xmax) xmax = x2;
	if (y1 > ymin) ymin = y1;
	if (y2 < ymax) ymax = y2;
	xscale = xmax - xmin;
	yscale = ymax - ymin;
	button_reset_scale->show();
	selection_frame = false;	
	queue_draw ();
	return true;
}

void Diagramm::reset_diagscale ()
{
	xmin = xmin_reset;
	ymin = ymin_reset;
	xmax = xmax_reset;
	ymax = ymax_reset;
	xscale = xmax - xmin;
	yscale = ymax - ymin;
	button_reset_scale->hide();
	queue_draw ();
	autoscale = save_autoscale;	//reset state
	return;
}

void Diagramm::set_unit()
{
	xrange=1.0;		//Initialize range
	yrange=1.0;
	
	// set unit for x values 
	if (funktion_x == _("Time"))
	{
		while ((xrange*xabsmax > 60) && (unit_x != "h"))
		{
			xrange = 0.0166666667 * xrange;
			unit_x = upgrade_unit (unit_x);
		}
	}	
	else if (funktion_x != _("Wavelength"))
	{
		while ((xrange*xabsmax < 0.001) && (xabsmax != 0) && (unit_x.at(0) != 'p'))
		{
			xrange = 1000 * xrange;
			unit_x = downgrade_unit (unit_x);
		}
		while ((xrange*xabsmax > 1000) && (unit_x.at(0) != 'G'))
		{
			xrange = 0.001 * xrange;
			unit_x = upgrade_unit (unit_x);
		}
	}
	//set unit for y values
	if ((funktion_y != "pH") && (funktion_y != _("Temperature")) && (funktion_y != _("Absorption")))
	{
		while ((yrange*yabsmax < 0.001) && (yabsmax != 0) && (unit_y.at(0) != 'p'))
		{
			yrange = 1000 * yrange;
			unit_y = downgrade_unit (unit_y);
		}
		while ((yrange*yabsmax > 1000) && (unit_y.at(0) != 'G'))
		{
			yrange = 0.001 * yrange;
			unit_y = upgrade_unit (unit_y);
		}
	}
		
	return;
}

std::string Diagramm::upgrade_unit (std::string unit)
{
	char16_t dim;
		
	if (unit == "s") unit = "min";
	else if (unit == "min") unit = "h";
	else if (unit == "h") return (unit);
	else
	{
		dim = unit.at(0);
		switch(dim)
		{
			case 'p':
				unit.replace(0,1,"n");
				break;
			case 'n':
				unit.replace(0,1,"u");
				break;
			case 'u':
				unit.replace(0,1,"m");
				break;
			case 'm':
				unit.erase(0,1);
				break;
			case 'k':
				unit.replace(0,1,"M");
				break;
			case 'M':
				unit.replace(0,1,"G");
				break;
			case 'G':
				break;
			default:
				unit.insert(0,"k");
		}
	}
	return unit;
}

std::string Diagramm::downgrade_unit (std::string unit)
{
	char16_t dim;	
	
	dim = unit.at(0);
	switch(dim)
	{
		case 'p':
			break;
		case 'n':
			unit.replace(0,1,"p");
			break;
		case 'u':
			unit.replace(0,1,"n");
			break;
		case 'm':
			unit.replace(0,1,"u");
			break;
		case 'k':
			unit.erase(0,1);
			break;
		case 'M':
			unit.replace(0,1,"k");
			break;
		case 'G':
			unit.replace(0,1,"M");
			break;
		default:
			unit.insert(0,"m");
	}
		
	return unit;
}


/////////////////  Prepare, start and stop Measurement   /////////////////////

void new_project ()
{
	if (!data_saved) if (dialog_ok(_("Save data?"))) save_data();
	reset_mw();
	datum = std::time(nullptr);
	project->datum = std::asctime(std::localtime(&datum));
	project->title = "";
	project->comment = "";
	project->evalresults = "";
	define_project ();
	data_saved = true;
	return;
}

void show_settings_device_x ()
{
	std::string function_x;

	function_x = func_x->get_active_text();
	//if (dmm[0].dmm_typ == TIME)
	if (function_x == _("Time"))
	{
		device_x->hide();
	}
	else if (dmm[0].dmm_typ == DMM)
	{
		if (dmm[0].dmm_name == "") device_x->set_label (_("device not configured"));
		else device_x->set_label (dmm[0].dmm_name);
		device_x->show();
	}
	else	// simulation (linear): DEVICE  and other sim-types can't be selected for channel X
	{
		device_x->set_label (_("Simulation (linear)"));
		device_x->show();
	}
}

void show_settings_device_y ()
{
	std::string function_y;

	function_y = func_y->get_active_text();
	if ((dmm[1].dmm_typ == DMM) || (dmm[1].dmm_typ == DEVICE))
	{
		if (dmm[1].dmm_name == "") device_y->set_label (_("device not configured"));
		else device_y->set_label (dmm[1].dmm_name);
		device_y->show();
		tit_options->hide();
	}
	else // simulation
	{
		if (dmm[1].dmm_typ == LINEAR) device_y->set_label (_("Simulation (linear)"));
		else if (dmm[1].dmm_typ == EXP) device_y->set_label (_("Simulation (exponential)"));
		else if (dmm[1].dmm_typ == PH) 
		{
			device_y->set_label (_("Simulation (pH)"));
			tit_options->show();
		}
		else if (dmm[1].dmm_typ == PEAK) device_y->set_label (_("Simulation (chromatogramm)"));
		else if (dmm[1].dmm_typ == SPEKTRUM) device_y->set_label (_("Simulation (spectrum)"));
		device_y->show();
	}
}

void configure_settings_device_x()
{
	set_options_device_x();
	func_x->set_active_text (project->funktion_x);
	show_settings_device_x ();
	projekt_prop->queue_draw ();
}

void configure_settings_device_y()
{
	set_options_device_y();
	func_y->set_active_text (project->funktion_y);
	show_settings_device_y ();
	projekt_prop->queue_draw ();
}

void define_project ()
{
	std::string error_str;
		
	projekt_title->set_text (project->title);
	if (dmm[1].dmm_typ == SPEKTRUM)
	{
		func_x->append (project->funktion_x);
		func_y->append (project->funktion_y);
	}
	func_x->set_active_text (project->funktion_x);
	func_y->set_active_text (project->funktion_y);
	show_settings_device_x ();
	show_settings_device_y ();
	projekt_comment = Gtk::TextBuffer::create();
	projekt_comment->set_text(project->comment);
	projekt_comment_view->set_buffer(projekt_comment);
	if (dmm[1].dmm_typ == PH)	// pH simulation
	{
		tit_ha->set_active_text(ha.name);
		tit_haconc->set_value (dmm[1].ca);
		tit_baseconc->set_value (dmm[1].cb);
		tit_havol->set_value (dmm[1].va);
		tit_speed->set_value(60.0 * tit_volspeed);	// ml/sec -> ml/min
		show_tit_options();
	}
	//existing data? -> deactivate editing
	if (mw.size()!=0) projekt_options->set_sensitive (false);
	else projekt_options->set_sensitive (true);
		
	int result = projekt_prop->run();
	switch(result)
  	{
    	case(Gtk::RESPONSE_ACCEPT):
    	{
			project->title = projekt_title->get_text();
			set_messfunkt (0, func_x->get_active_text());
			set_messfunkt (1, func_y->get_active_text());
			project->comment = projekt_comment->get_text();
			if ((mw.size()==0) && (dmm[1].dmm_typ == PH))	// pH simulation
			{
				ha.name = tit_ha->get_active_text();
				dmm[1].ca = tit_haconc->get_value ();
				dmm[1].cb = tit_baseconc->get_value ();
				dmm[1].va = tit_havol->get_value ();
				ai = get_acid_index (ha.name);
				if (ai == -1)
				{
					error_str = _("No titration data set");
					fehler (error_str);
					projekt_prop->hide();
					return;
				}
				else
				{
					ha.npks = acid.at(ai).npks;
					ha.pks[0] = acid.at(ai).pks[0];
					ha.pks[1] = acid.at(ai).pks[1];
					ha.pks[2] = acid.at(ai).pks[2];
				}
				tit_volspeed = tit_speed->get_value() / 60.0;	// ml/min -> ml/sec
				if (dmm[1].connected) dmm[1].set_tit_data (ha.npks);
			}
			break;
    	}
    	case(Gtk::RESPONSE_CANCEL):
    	{
			projekt_prop->hide();
			return;
			break;
    	}
  	}
	//set unit
	project->unit_x = set_std_unit (project->funktion_x);
	dmm[0].m_range = set_std_range (project->funktion_x);
	project->unit_y = set_std_unit (project->funktion_y);
	dmm[1].m_range = set_std_range (project->funktion_y);
	
	projekt_prop->hide();
	project_defined=true;
	return;
}

int get_acid_index(std::string name)	// get index of acid
{
	int i;
	bool found;

	found = false;
	for (i=0; i< acid.size(); i++)
	{
		if (acid.at(i).name == name)
		{
			found = true;
			break;
		}
	}
	if (!found) i=-1;
	return i;
}

void show_tit_options()
{
	std::string funkt_y;
	funkt_y = func_y->get_active_text();
	if ((dmm[1].dmm_typ == PH) && (funkt_y == "pH")) 
	{
		tit_options->show ();
		eval_titvolumen = true;
	}
	else 
	{
		tit_options->hide();
		eval_titvolumen = false;
		if (dmm[1].dmm_typ == PH) dmm[1].dmm_typ = LINEAR;	// reset simulation type
	}
	return;
}

void set_messfunkt (int kanal, std::string funkt)
{
	if (kanal == 0) project->funktion_x = funkt;
	else project->funktion_y = funkt;
	dmm[kanal].m_funkt = funkt;
	if (dmm[kanal].dmm_name == _("Simulation"))
	{
		if (funkt == "pH") dmm[kanal].dmm_typ = PH;
	}
	return;
}


std::string set_std_unit (std::string funkt)	// set standard unit
{
	std::string unit;
	
	if (funkt == _("Time")) unit = "s";
	else if ((funkt == _("DC Voltage")) || (funkt == _("AC Voltage"))) unit = "V";
	else if ((funkt == _("DC Current")) || (funkt == _("AC Current"))) unit = "A";
	else if (funkt == _("Resistance")) unit = "Ohm";
	else if (funkt == _("Conductivity")) unit = "S";
	else if (funkt == "pH") unit = "pH";
	else if (funkt == _("Temperature")) unit = "°C";
	else if (funkt == _("Wavelength")) unit = "nm";
	else if (funkt == _("Absorption")) unit = _("Intensity");
	else unit = "?";
	return unit;
}


std::string set_std_range (std::string funkt)	// set standard range
{
	std::string range;
	
	if ((funkt == _("DC Voltage")) || (funkt == _("AC Voltage"))) range = "2 V";
	else if ((funkt == _("DC Current")) || (funkt == _("AC Current"))) range = "200 mA";
	else if (funkt == _("Resistance")) range = "200 Ohm";
	else if (funkt == _("Conductivity")) range = "200 mS";
	else if (funkt == _("pH")) range = "pH";
	else if (funkt == _("Temperature")) range = "°C";
	else if (funkt == _("Wavelength")) range = "400 - 800 nm";
	else if (funkt == _("Absorption")) range = "1";
	else range = "";
	
	return range;
}


void reset_mw ()
{
	//Initialize value indices
	mi = 0;
	mw.clear();
	reset_evaloptions ();
	
	mess_done = false;
	
	return;
}


void init_diag ()
{
	diag->reset_diag = false;
	if (diag->autoscale) //reset coordinate limits if not manually set
	{
		diag->xmin = 0.0;
		diag->ymin = 0.0;
		diag->xmax = 10.0;
		diag->ymax = 1.0;
		diag->dxax = 0.01;
		diag->dyax = 0.01;
		diag->xscale = 10.0;
		diag->yscale = 1.0;
		diag->xrange = 1.0;
		diag->yrange = 1.0;
		if (project->funktion_y == "pH") 
		{
			diag->yscale = 14.0;
			diag->ymin = 0.0;
			diag->ymax = 14.0;
			diag->dyax = 0.00714285714286;
		}
		else if (project->funktion_y == _("Absorption")) 
		{
			diag->yscale = 1.0;
			diag->ymax = 1.0;
			diag->xmin = 400;
			diag->xmax = 800;
			diag->xscale = 400.0;
		}
	}
	return;
}


void begin_mess()	//Prepare measurement
{
	if (!project_defined) define_project ();
	else
	{
		project->unit_x = set_std_unit (project->funktion_x);
		project->unit_y = set_std_unit (project->funktion_y);
	}
	if (!project_defined) return;
	// name and interface of device defined?
	if (project->funktion_x != _("Time"))
	{
		if ((dmm[0].dmm_typ == DMM) || (dmm[0].dmm_typ == DEVICE))
		{
			if (dmm[0].dmm_name == "")
			{
				fehlercode = _("Data channel");
				fehlercode += " ";
				fehlercode += "1 (X): ";
				fehlercode += _("Device name not set");
				fehler (fehlercode);
				return;
			}
			if (dmm[0].int_face == "")
			{
				fehlercode = _("Data channel");
				fehlercode += " ";
				fehlercode += "1 (X): ";
				fehlercode += _("Interface not set");
				fehler (fehlercode);
				return;
			}
		}
	}
	if ((dmm[1].dmm_typ == DMM) || (dmm[1].dmm_typ == DEVICE))
	{
		if (dmm[1].dmm_name == "")
		{
			fehlercode = _("Data channel");
			fehlercode += " ";
			fehlercode += "2 (Y): ";
			fehlercode += _("Device name not set");
			fehler (fehlercode);
			return;
		}
		if (dmm[1].int_face == "")
		{
			fehlercode = _("Data channel");
			fehlercode += " ";
			fehlercode += "2 (Y): ";
			fehlercode += _("Interface not set");
			fehler (fehlercode);
			return;
		}
	}
	reset_mw ();
	init_diag ();
	mt = 0.0;	// reset time
	dmm[1].connect_dmm(dmm[1].int_face);	//Channel Y-values
	if (!dmm[1].connected)
	{
		fehlercode = _("Device unreachable: ");
		fehlercode += dmm[1].dmm_name;
		fehler (fehlercode);
		diag->reset_diag = true;
		diag->queue_draw ();
		return;
	}
	if ((dmm[1].dmm_typ == DMM) && (dmm[1].remote_cfg)) dmm[1].setup(dmm[1].m_funkt, dmm[1].m_range);
	
	if ((project->funktion_x != _("Time")) && (project->funktion_x != _("Wavelength")))
	{
		dmm[0].connect_dmm(dmm[0].int_face);	//Channel X-Values
		if (!dmm[0].connected)
		{
			fehlercode = _("Device unreachable: ");
			fehlercode += dmm[0].dmm_name;
			fehler (fehlercode);
			diag->reset_diag = true;
			diag->queue_draw ();
			return;
		}
		if ( (dmm[0].dmm_typ == DMM) && (dmm[0].remote_cfg)) dmm[0].setup(dmm[0].m_funkt, dmm[0].m_range);
	}
	
	else 
	{
		if (project->funktion_x == _("Wavelength")) project->unit_x = "nm";
		else project->unit_x = "s";
	}
	if (project->funktion_y == _("Absorption")) project->unit_y = _("Intensity");
	
	diag->queue_draw();
	button_messung->hide();
	button_start->show();
	button_start->signal_clicked().connect(sigc::ptr_fun(start_mess));
	button_timer->show();
	button_timer->signal_clicked().connect(sigc::ptr_fun(start_mess_with_timer));
	button_cancel->show();
	menu_mess_neu->set_sensitive (false);
	menu_mess_start->set_sensitive (true);
	menu_mess_cancel->set_sensitive (true);
	menu_mess_start_timer->set_sensitive (true);
	menu_eval_data->set_sensitive (false);
	mtimer = g_timer_new ();
	return;
}

void cancel_mess ()
{
	stop_mess ();
	end_mess ();
	button_start->hide();
	button_timer->hide();
	button_cancel->hide();
	menu_mess_start->set_sensitive (false);
	menu_mess_start_timer->set_sensitive (false);
	menu_mess_cancel->set_sensitive (false);
	return;
}

void start_mess()
{
	data_saved = false;
	mess_done = true;
	button_start->hide();
	button_timer->hide();
	button_cancel->hide();
	button_stop->show();
	menu_mess_start->set_sensitive (false);
	menu_mess_start_timer->set_sensitive (false);
	menu_mess_cancel->set_sensitive (false);
	menu_mess_stop->set_sensitive (true);
	menu_options_diag->set_sensitive (false);
	menu_options_deviceX->set_sensitive (false);
	menu_options_deviceY->set_sensitive (false);
	tit_options->set_sensitive (false);
	g_timer_start(mtimer);
	get_val();	//read value for t=0
	diag->start_mt();	//start measurement
	diag->m_started = true;
		
	return;
}

bool show_countdown_progress ()
{
	double fraction;

	fraction = count_down_progress->get_fraction () + 1/timer_start->get_value ();
	count_down_progress->set_fraction (fraction);
	timer_cd = fraction;
	
	return true;
}

void show_countdown ()
{
	timer_cd = timer_start->get_value ();
	timer_dialog->hide();
	// initialize timeout for measurement countdown of 1 sec
	if (!countdown_timeout.connected()) countdown_timeout = Glib::signal_timeout().connect(sigc::ptr_fun(show_countdown_progress), 1000);
	if (countdown_timeout.blocked()) countdown_timeout.unblock();
	
	count_down_start->show();
	count_down_progress->set_fraction (0.0);
	count_down_progress->show();
	timer_cd = count_down_progress->get_fraction();
	while (timer_cd < 1.0)
	{
		while (gtk_events_pending())
        gtk_main_iteration();
	}
	count_down_start->hide();
	count_down_progress->hide();	
	countdown_timeout.block();
	
	
	return;
}

void start_mess_with_timer ()
{
	timer_cd = 10.0;
	timer_start->set_value (timer_cd);
	
	int result = timer_dialog->run();
    switch(result)
  	{
  	  case(Gtk::RESPONSE_ACCEPT):
		show_countdown ();
		start_mess ();
		break;
					
	  case(Gtk::RESPONSE_CANCEL):
		timer_dialog->hide();
		break;
    }
	timer_dialog->close();
	return;
}


void stop_mess()
{
	button_stop->hide();
	button_reset->show();
	menu_mess_stop->set_sensitive (false);
	menu_mess_delete->set_sensitive (true);
	diag->stop_mt();	//stop measurement
	diag->m_started = false;
	g_timer_stop(mtimer);
	display_x->hide();
	display_y->hide();
	menu_eval_data->set_sensitive (true);
	menu_options_diag->set_sensitive (true);
	menu_options_deviceX->set_sensitive (true);
	menu_options_deviceY->set_sensitive (true);
	return;
}

void end_mess()
{	
	button_reset->hide();
	menu_mess_delete->set_sensitive (false);
	if (mess_done)
	{
		if (!dialog_ok (_("Delete diagram?"))) 
		{
			button_reset->show();
			return;
		}
		if (!data_saved) 
		{
			if (dialog_ok(_("Save data?"))) save_data();
		}
	}
	diag->reset_diag=true;
	diag->queue_draw ();	
	button_messung->show();
	menu_mess_neu->set_sensitive (true);
	tit_options->set_sensitive (true);
	msg_dialog->close();
	if (dmm[0].connected) dmm[0].disconnect_dmm();
	if (dmm[1].connected) dmm[1].disconnect_dmm();
	g_timer_destroy(mtimer);
	
	mw.clear();		// delete values
	mess_done = false;
	
	return;
}

/////////////////   Arrange, gain and show Values   /////////////////

void new_val(mw_data val)	// add value to mw-array and prepare next value
{
	mw.push_back (val);
	if (mi >= mw.max_size ()) 	//array full
	{	
		fehler(_("Maximum number of values reached"));
		if (diag->m_started) stop_mess (); 
	}
	else mi++;	//increase Index
	return;
}


void get_val()
{
	m_record xmval, ymval;
	mw_data val;

	mt = g_timer_elapsed (mtimer, microsec);	//detect time variable at beginning of measurement
	if (dmm[1].connected) ymval = dmm[1].read_dmm();
	else 	//Device unreachable?
	{
		stop_mess ();	//Stop measurement
		return;
	}
	set_messfunkt (1, ymval.funktion);	//read function and unit from device
	if (ymval.funktion == "?") return;
	if (project->funktion_x == _("Time")) 
	{
		xmval.digits = mt;
		xmval.funktion = _("Time");
		xmval.unit = project->unit_x;
	}
	else if (project->funktion_x == _("Wavelength")) 
	{
		xmval.digits = 400/180* mt + 400;
		xmval.funktion = _("Wavelength");
		xmval.unit = "nm";
		if (xmval.digits > 800) stop_mess ();
	}
	else 
	{
		xmval = dmm[0].read_dmm();
		set_messfunkt (0, xmval.funktion);	//read function and unit from device
	}
	if (xmval.funktion == "?") return;
	val.x = xmval.digits;
	val.y = ymval.digits;
	new_val (val); 	//Insert value in array	
			
	return;
}


void display_mw (m_record xval, m_record yval)
{
	std::string mwstring;
	int pos;

	mwstring = std::to_string(xval.digits);
	pos = mwstring.find (',');
	mwstring.resize (pos+5);
	mwstring = "X= " + mwstring + " " + xval.unit;
	pos = mwstring.find("u");
	if (pos <= mwstring.length()) mwstring.replace(pos,1,"µ");
	display_x->set_text (mwstring);
	display_x->show();
	mwstring = std::to_string(yval.digits);
	pos = mwstring.find (',');
	mwstring.resize (pos+5);
	mwstring = "Y= " + mwstring + " " + yval.unit;
	pos = mwstring.find("u");
	if (pos <= mwstring.length()) mwstring.replace(pos,1,"µ");
	display_y->set_text (mwstring);
	display_y->show();
	
	return;
}

void toggle_display ()
{
	show_display = menu_view_display->get_active();
	return;
}

//////////// Error messages and infos ////////////////////
void fehler(std::string fehler_text)
{
 	error_dialog->set_secondary_text(fehler_text);
	int result = error_dialog->run();
    switch(result)
  	{
  	  case(Gtk::RESPONSE_OK): break;
    }
	error_dialog->hide();
  	return;
}

bool dialog_ok (std::string msg)
{
	bool resp;
	
	msg_dialog->set_message(msg);
	int result = msg_dialog->run();
	switch(result)
  	{
    	case(Gtk::RESPONSE_OK): resp = true; break;
		case(Gtk::RESPONSE_ACCEPT): resp = true; break;
        case(Gtk::RESPONSE_CANCEL):	resp = false; break;
		default: resp = false;
    }
	msg_dialog->hide();
	
	return resp;
}





