// generated 2002/7/3 16:33:25 COT by andres@control.(none)
// using glademm V0.6.4
//
// newer (non customized) versions of this file go to control_window.cc_new

// This file is for your program, I won't touch it again!

#include <sstream>
#include <string>
#include <iostream>
#include <gnome--/main.h>
#include <gdk--/color.h>
#include <gtk--/menuitem.h>
#include <gtk--/menu.h>
#include <gnome--/messagebox.h>
#include <pthread.h>
#include <sched.h>
#include <sys/mman.h>
#include <stdio.h>
#include <config.h>

#include "control_window.hh"
#include "setup_dialog.hh"
#include "datos.h"
#include "control_module.h"
#include "lxrt_wrapper.h"

#define volt2spd(v) (0.41118*(v)-0.0006594)

control_window::control_window()
  : control_window_glade()
{
  table4->attach(*vbox1, 0, 1, 1, 2);
  setup= manage(new setup_dialog());
  setup->set_transient_for(*this);
  init_databox(volt_box);
  init_databox(spd_box);
  volt_x= 0;
  volt_y= 0;
  spd_x= 0;
  spd_y= 0;
  stop_control= 1;

  set_nonroot_mode();
  if(create_ui_task() != 0)
    Gnome::Main::quit();
  if(create_mbxs() != 0)
    {
      delete_task();
      Gnome::Main::quit();
    }
}

control_window::~control_window()
{
  if(volt_x)
    delete[] volt_x;
  if(volt_y)
    delete[] volt_y;
  if(spd_x)
    delete[] spd_x;
  if(spd_y)
    delete[] spd_y;
  delete_task();
}

void control_window::init_databox(Databox* db)
{
  db->show_rulers();
  db->hide_scrollbars();
  db->hide_cross();
  db->enable_zoom();
}

void control_window::start_control()
{
  comedi_data_str comd;
  input_data_str inpd;
  comedi_range rrange, wrange;
  int mbxl;
    
  gint ans= setup->run_and_close();
  if(ans == 1)
    return;

  MenuItem *it= setup->dev_option->get_menu()->get_active();
  gint dev_num= g_list_index(GTK_MENU_SHELL(setup->dev_option
					    ->get_menu()->gtkobj())
			     ->children,
			     it->gtkobj());

  data_period= data_show_spin->get_value_as_int();
  data_cnt= 0;
  spd_cnt= 0;
  volt_cnt= 0;

  start_timer();

  comd.dev= dev_num;
  comd.rchan= comd.wchan= comd.rrange= comd.wrange=0;
  comd.rref= comd.wref= AREF_GROUND;

  period_ms= sample_period_spin->get_value_as_int();
  
  inpd.ident= ident_check->get_active()? 1: 0;
  inpd.ref= ref_spin->get_value_as_float();
  
  stop_control= 0;
  exit= 0;

#ifdef DEBUG
  std::cout << "Iniciando hilo de control..." << std::endl;
#endif

  if(pthread_create(&ctrl_thread, 0, control_thread, (void *) 0) != 0)
  {
    std::cerr << __PRETTY_FUNCTION__ << ": No se pudo crear el hilo de control"
	      << std::endl;
    stop_timer();
    stop_control= 1;
    return;
  }

#ifdef DEBUG
  std::cout << "Esperando hilo de control..." << std::endl;
#endif
  if(wait_control_task() != 0)
  {
    pthread_join(ctrl_thread, NULL);
    stop_timer();
    return;
  }

#ifdef DEBUG
  std::cout << "Enviando datos comedi..." << std::endl;
#endif
  mbxl= mbx_send(DATA_MBX, &comd, sizeof(comd));
#ifdef DEBUG
  std::cout << "Faltaron " << mbxl << " de " << sizeof(comd)
	    << ". Enviando datos input..." << std::endl;
#endif
  mbxl= mbx_send(DATA_MBX, &inpd, sizeof(inpd));
#ifdef DEBUG
  std::cout << "Faltaron " << mbxl << " de " << sizeof(inpd)
	    << ". Enviando periodo..." << std::endl;
#endif
  mbxl= mbx_send(PERIOD_MBX, &period_ms, sizeof(period_ms));
  
#ifdef DEBUG
  std::cout << "Faltaron " << mbxl << " de " << sizeof(period_ms) 
	    << ". Verificando hilo de control..." << std::endl;
#endif
  if(!exist_control())
  {
    pthread_join(ctrl_thread, NULL);
    stop_timer();
    return;
  }

#ifdef DEBUG
  std::cout << "Recibiendo read_range..." << std::endl;
#endif
  mbxl= mbx_receive(DATA_MBX, &rrange, sizeof(rrange));
#ifdef DEBUG
  std::cout << "Faltaron " << mbxl << " de " << sizeof(rrange)
	    << " rrange.min= " << rrange.min
	    << " rrange.max= " << rrange.max << std::endl
	    << "Recibiendo write_range..." << std::endl;
#endif
  mbx_receive(DATA_MBX, &wrange, sizeof(wrange));
#ifdef DEBUG
  std::cout << "Faltaron " << mbxl << " de " << sizeof(wrange)
	    << " wrange.min= " << wrange.min
	    << " wrange.max= " << wrange.max << std::endl;
#endif

  read_range_min= rrange.min;
  read_range_max= rrange.max;
  write_range_min= wrange.min;
  write_range_max= wrange.max;

  volt_samples_changed();
  spd_samples_changed();

  while(!stop_control)
  {
    neuro_data_str neurod;

    if(!exist_control())
    {
      stop_control= 1;
      break;
    }

    mbx_receive(DATA_MBX, &neurod, sizeof(neurod));

    show_spd(neurod.volt);
    show_volt(neurod.u);

    if(data_cnt >= (data_period / period_ms))
    {
      std::ostringstream a0str;
      a0str << neurod.a0;
      a0_ent->set_text(a0str.str());
  
      std::ostringstream a1str;
      a1str << neurod.a1;
      a1_ent->set_text(a1str.str());
  
      std::ostringstream a2str;
      a2str << neurod.a2;
      a2_ent->set_text(a2str.str());

      std::ostringstream b0str;
      b0str << neurod.b0;
      b0_ent->set_text(b0str.str());
  
      std::ostringstream b1str;
      b1str << neurod.b1;
      b1_ent->set_text(b1str.str());
  
      std::ostringstream b2str;
      b2str << neurod.b2;
      b2_ent->set_text(b2str.str());
  
      std::ostringstream ustr;
      ustr << neurod.u;
      control_ent->set_text(ustr.str());
  
      std::ostringstream spdstr;
      spdstr << neurod.vel;
      speed_ent->set_text(spdstr.str());
  
      std::ostringstream est_spdstr;
      est_spdstr << neurod.vel_est;
      est_speed_ent->set_text(est_spdstr.str());
  
      std::ostringstream errorstr;
      errorstr << neurod.error;
      error_ent->set_text(errorstr.str());

      data_cnt= 0;
    }
    ++data_cnt;
  
    while(Main::events_pending())
      Main::iteration(false);
  }

  mbx_send(STOP_MBX, &stop_control, sizeof(unsigned char));

  if(pthread_join(ctrl_thread, 0) != 0)
    std::cerr << __PRETTY_FUNCTION__ <<": Problemas terminando hilo de control"
	      << std::endl;
  stop_timer();
  if(exit)
    Gnome::Main::quit();
}

void control_window::identify()
{
  input_data_str inpd;
  
  inpd.ident= ident_check->get_active()? 1: 0;
  inpd.ref= ref_spin->get_value_as_float();

  mbx_send(INPUT_MBX, &inpd, sizeof(inpd));
}

void control_window::stop_ctrl()
{
  stop_control= 1;
}

void control_window::exit_program()
{
  if(!stop_control)
  {
    stop_ctrl();
    exit= 1;
  }
  else
    Gnome::Main::quit();
}

void control_window::volt_samples_changed()
{  
  volt_box->data_remove_all();
  int voltl= volt_samples_spin->get_value_as_int();
  if(volt_x)
    delete[] volt_x;
  if(volt_y)
    delete[] volt_y;
  volt_x= new gfloat[voltl];
  volt_y= new gfloat[voltl];
  for(int i= 0; i < voltl; i++)
  {
    volt_x[i]= i * period_ms * 1E-3;
    volt_y[i]= 0.0;
  }
  Gdk_Color color;
  color.set_rgb(0, 0, 0);
  volt_box->data_add_x_y(voltl, volt_x, volt_y, color, GTK_DATABOX_LINES, 1);
  GtkDataboxValue min;
  GtkDataboxValue max;
  voltl--;
  min.x= 0;
  max.x= (voltl * period_ms) * 1E-3;
  min.y= write_range_min * 1.1;
  max.y= write_range_max * 1.1;
  volt_box->rescale_with_values(min, max);
  volt_box->redraw();
}

void control_window::spd_samples_changed()
{  
  spd_box->data_remove_all();
  int spdl= spd_samples_spin->get_value_as_int();
  if(spd_x)
    delete[] spd_x;
  if(spd_y)
    delete[] spd_y;
  spd_x= new gfloat[spdl];
  spd_y= new gfloat[spdl];
  for(int i= 0; i < spdl; i++)
  {
    spd_x[i]= i * period_ms * 1E-3;
    spd_y[i]= 0.0;
  }
  Gdk_Color color;
  color.set_rgb(0, 0, 0);
  spd_box->data_add_x_y(spdl, spd_x, spd_y, color, GTK_DATABOX_LINES, 1);
  GtkDataboxValue min;
  GtkDataboxValue max;
  spdl--;
  min.x= 0;
  max.x= (spdl * period_ms) * 1E-3;
  min.y= volt2spd(read_range_min) * 1.1;
  max.y= volt2spd(read_range_max) * 1.1;
  spd_box->rescale_with_values(min, max);
  spd_box->redraw();
}

void control_window::sample_period_changed()
{
  period_ms= static_cast<unsigned int>(sample_period_spin->get_value_as_int());
  mbx_send(PERIOD_MBX, &period_ms, sizeof(period_ms));
  //Reiniciar osciloscopios
  volt_samples_changed();
  spd_samples_changed();
}

void control_window::show_spd(float volt)
{
  unsigned int num_spd_samples= spd_samples_spin->get_value_as_int();
  ++spd_cnt;
  if(spd_cnt == num_spd_samples)
  {
    std::memset(spd_y, 0, num_spd_samples * sizeof(gfloat));
    spd_cnt= 0;
  }
  spd_y[spd_cnt]= volt2spd(volt);
  spd_box->redraw();
}

void control_window::show_volt(float volt)
{
  unsigned int num_samples= volt_samples_spin->get_value_as_int();
  ++volt_cnt;
  if(volt_cnt == num_samples)
  {
    std::memset(volt_y, 0, num_samples * sizeof(gfloat));
    volt_cnt= 0;
  }
  volt_y[volt_cnt]= volt;
  volt_box->redraw();
}

void control_window::data_show_changed()
{
  data_period= data_show_spin->get_value_as_int();
}
