damaris-backends/machines/general.cpp

277 lines
8.9 KiB
C++

/***************************************************************************
Author: Markus Rosenstihl
Created: June 2010
****************************************************************************/
#include "machines/hardware.h"
#include "core/core.h"
#include "drivers/PTS-Synthesizer/PTS.h"
#include "drivers/Spectrum-MI40xxSeries/Spectrum-MI40xxSeries.h"
#include "drivers/SpinCore-PulseBlaster24Bit/SpinCore-PulseBlaster24Bit.h"
#include <glib.h>
#include <time.h>
#include <fstream>
/**
\defgroup General NMR Spectrometer
\ingroup machines
Uses:
\li Spincore Pulseblaster 24 Bit
\li Spectrum MI4021 with gated sampling option (PB ref. clock is fed to Ext.Clock)
\li Programmed Test Sources PTS frequency synthesizer with phase control
This backend uses a configuration file for setting the various lines and configurations.
\par Starting the hardware
This procedure should assure the correct initialisation of the hardware:
\li Switch off main switches of SpinCore Pulseblaster and Computer (the main switch of the computer is at the rear)
\li Switch on Computer and start Windows or Linux
@{
*/
struct timespec start_delay;
class general_hardware: public hardware
{
PTS* my_pts;
SpinCorePulseBlaster24Bit* my_pulseblaster;
SpectrumMI40xxSeries* my_adc;
bool with_sync;
public:
general_hardware()
{
int SYSCONF = 0;
int USRCONF = 0;
GKeyFile* cfg_file;
GError *error = NULL;
char cfg_name[512];
const gchar* usr_configdir;
const gchar* const * sys_configdirs;
sys_configdirs = g_get_system_config_dirs();
usr_configdir = g_get_user_config_dir();
cfg_file = g_key_file_new();
for (int i = 0; i < 100; i++)
{
if (sys_configdirs[i] == NULL)
break;
else
{
snprintf(cfg_name, 512, "%s/damaris/backend.conf", sys_configdirs[i]);
fprintf(stdout, "reading backend configuration file (system: %i): %s...\n", i, cfg_name);
if (!g_key_file_load_from_file(cfg_file, cfg_name, G_KEY_FILE_NONE, &error))
{
if (error->code != 4)
{
fprintf(stdout, "%s","found!\n");
g_log(G_LOG_DOMAIN, G_LOG_LEVEL_WARNING, "%s", error->message);
}
else
printf("not found!\n");
}
else
SYSCONF = 1;
error = NULL; // reset error
}
}
snprintf(cfg_name, 512, "%s/damaris/backend.conf", usr_configdir);
fprintf(stdout, "reading backend configuration file (user): %s...\n", cfg_name);
if (!g_key_file_load_from_file(cfg_file, cfg_name, G_KEY_FILE_NONE, &error))
{
if (error->code != 4)
{
fprintf(stdout, "found!\n");
g_log(G_LOG_DOMAIN, G_LOG_LEVEL_WARNING,"%s", error->message);
}
else
printf("not found!\n");
error = NULL;
}
else
USRCONF = 1;
if (!(SYSCONF | USRCONF)) {
error = NULL;
throw(core_exception("configuration failed!\n"));
}
int start_delay_msec = g_key_file_get_integer(cfg_file, "PB", "start_delay_msec", &error);
::start_delay = { start_delay_msec/1000, start_delay_msec%1000 * 1000000L};
if (error)
g_error("%s",error->message);
printf("done!\n");
/* configure ADC card */
ttlout trigger;
trigger.id = g_key_file_get_integer(cfg_file, "ADC", "id", &error);
if (error)
g_error("%s",error->message);
error = NULL;
trigger.ttls = (channel_array) (1 << g_key_file_get_integer(cfg_file, "ADC", "trigger_line", &error));
if (error)
g_error("%s",error->message);
error = NULL;
int ext_reference_clock = (int) g_key_file_get_double(cfg_file, "ADC", "refclock", &error); // 50 MHz from PB24 SP17; defaults to 100MHz (PB24 SP 2)
if (error)
g_error("%s",error->message);
error = NULL;
double impedance = g_key_file_get_double(cfg_file, "ADC", "impedance", &error); // Ohm ( or 50 Ohm)
if (error)
g_error("%s",error->message);
error = NULL;
my_adc = new SpectrumMI40xxSeries(trigger, (float) impedance, ext_reference_clock);
/* configure PulseBlaster */
int pb_id = g_key_file_get_integer(cfg_file, "PB", "id", &error);
if (error)
g_error("%s",error->message);
error = NULL;
double pb_refclock = g_key_file_get_double(cfg_file, "PB", "refclock", &error);
if (error)
g_error("%s",error->message);
error = NULL;
int pb_sync_bit = g_key_file_get_integer(cfg_file, "PB", "sync_line", &error);
if (error)
g_error("%s",error->message);
error = NULL;
int pb_sync = 0;
if (pb_sync_bit != 128) {
pb_sync = 1 << pb_sync_bit;
with_sync = 1;
my_pulseblaster = new SpinCorePulseBlaster24Bit(pb_id, pb_refclock, pb_sync);
}
else {
with_sync = 0;
my_pulseblaster = new SpinCorePulseBlaster24Bit(pb_id, pb_refclock,0);
}
/* configure PTS */
int pts_id = g_key_file_get_integer(cfg_file, "PTS", "id", &error);
if (error)
g_error("%s",error->message);
error = NULL;
my_pts = new PTS_latched(pts_id);
// PTS 500 has 0.36 or 0.72 above 200MHz ; PTS 310 has 0.225 degrees/step
my_pts->phase_step = (float) g_key_file_get_double(cfg_file, "PTS", "phase_stepsize", &error);
if (error)
g_error("%s",error->message);
error = NULL;
// publish devices
the_pg = my_pulseblaster;
the_adc = my_adc;
the_fg = my_pts;
}
result* experiment(const state& exp)
{
result* r = NULL;
for (size_t tries = 0; r == NULL && core::term_signal == 0 && tries < 102; ++tries)
{
state* work_copy = exp.copy_flat();
if (work_copy == NULL)
return new error_result(1, "could not create work copy of experiment sequence");
try
{
if (the_fg != NULL)
the_fg->set_frequency(*work_copy);
if (the_adc != NULL)
the_adc->set_daq(*work_copy);
else
throw ADC_exception("the_adc == NULL\n");
// ADC configured wait start_delay_msec before loading and starting pulse card
nanosleep(&::start_delay, NULL);
// the pulse generator is necessary
if (with_sync) {
my_pulseblaster->run_pulse_program_w_sync(*work_copy, my_adc->get_sample_clock_frequency());
}
else {
//experiment_prepare_dacs(work_copy);
//experiment_run_pulse_program(work_copy);
the_pg->run_pulse_program(*work_copy);
}
// wait for pulse generator
the_pg->wait_till_end();
// after that, the result must be available
if (the_adc != NULL) {
r = the_adc->get_samples();
}
else {
r = new adc_result(1, 0, NULL);
throw ADC_exception("ADC result not available");
}
}
catch (const RecoverableException &e)
{
// there is a weird bug with string memory allocation for large messages, resize manually to cure this
std::string str;
str.resize(strlen(e.what()));
str = e.what();
r = new error_result(1, str);
}
delete work_copy;
if (core::quit_signal != 0)
break;
}
return r;
}
virtual ~general_hardware()
{
if (the_adc != NULL)
delete the_adc;
if (the_fg != NULL)
delete the_fg;
if (the_pg != NULL)
delete the_pg;
}
};
/**
\brief brings standard core together with the general NMR hardware
*/
class general_core: public core
{
std::string the_name;
public:
general_core(const core_config& conf) :
core(conf)
{
the_hardware = new general_hardware();
the_name = "general core";
}
virtual const std::string& core_name() const
{
return the_name;
}
};
/**
@}
*/
int main(int argc, const char** argv)
{
int return_result = 0;
try
{
core_config my_conf(argv, argc);
// setup input and output
general_core my_core(my_conf);
// start core application
my_core.run();
}
catch (const DamarisException& e)
{
fprintf(stderr, "%s\n", e.what());
return_result = 1;
}
return return_result;
}