/* ************************************************************************** Author: Holger Stork, Achim Gaedke Created: January 2005 ****************************************************************************/ #include "Eurotherm-2000Series.h" #include #include #include #include #include #include #include #include Eurotherm2000Series::Eurotherm2000Series(const std::string& dev_name, int dev_address, int failure_status_mask): tempcont() { /* initialization of serial device */ device_name=dev_name; failure_mask=failure_status_mask; serial_dev=open(dev_name.c_str(),O_RDWR|O_NONBLOCK); if (serial_dev<0) throw Eurotherm2000Series_error("could not open serial device"); // set attributes now termios the_attributes; the_attributes.c_iflag=0; the_attributes.c_oflag=0; // 7 bit per byte, even parity, reciever enabled the_attributes.c_cflag=CS7|PARENB|CREAD; the_attributes.c_lflag=0; // baud rate cfsetospeed(&the_attributes,B19200); cfsetispeed(&the_attributes,B19200); if(tcsetattr(serial_dev,TCSANOW,&the_attributes)!=0) throw Eurotherm2000Series_error("could not configure serial line"); address=dev_address; (void)setlocale(LC_NUMERIC,"C"); fp_format="%05.1f"; int_format="%05d."; hex_format=">%04x"; std::map config; // configure for �K output config["Q1"]="2."; // configure for nnn.n format output/precision config["QD"]="1."; configure(config); set_history_stepsize(1); device_failed=0; } void Eurotherm2000Series::configure(const std::map& config) { std::string error_message; try { std::string mode; const char config_mode[]="0002."; read_value("IM",mode); for (std::map::const_iterator i=config.begin();i!=config.end();++i) { try { std::string value; read_value(i->first, value); fprintf(stderr, "%s: %s (%s)", i->first.c_str(), value.c_str(), i->second.c_str()); if (value!=i->second) { if (mode!=config_mode) set_value("IM",config_mode); set_value(i->first,i->second); mode=config_mode; } } catch (Eurotherm2000Series_error e){error_message+=i->first+"->"+i->second+", ";} } if (mode==config_mode) { set_value("IM","0000."); // read superficial zero byte char buffer[1]; while (read(serial_dev,buffer,1)<=0) sleep(1); // wait for restarted communication int timeout=10; while (1) { if (timeout<0) throw Eurotherm2000Series_error("could not establish connection after configuring"); try {get_summary_status();} catch(Eurotherm2000Series_error){--timeout;sleep(1); continue;} break; } } } catch (const Eurotherm2000Series_error& e) { throw Eurotherm2000Series_error("got error while configuration: "+std::string(e.what())); } if (error_message.size()!=0) { throw Eurotherm2000Series_error("Could not set "+error_message.substr(0,error_message.size()-1)); } } void Eurotherm2000Series::reset() { set_value("IM","0000."); // read superficial zero byte char buffer[1]; while (read(serial_dev,buffer,1)<=0) sleep(1); // wait for restarted communication int timeout=10; while (1) { if (timeout<0) throw Eurotherm2000Series_error("could not establish connection after reset"); try {get_summary_status();} catch(Eurotherm2000Series_error){--timeout; sleep(1); continue;} break; } } Eurotherm2000Series::~Eurotherm2000Series() { /** close serial device, clean up */ close(serial_dev); } void Eurotherm2000Series::read_value(const std::string& param_name, std::string& return_value) const{ // assemble message without channel std::string message; message+=4; message+='0'+(address/10); message+='0'+(address/10); message+='0'+(address%10); message+='0'+(address%10); message+=param_name; message+=5; // write message to device pthread_mutex_lock((pthread_mutex_t*)&device_lock); write(serial_dev,message.c_str(),message.size()); // read answer unsigned char got_byte=0; return_value.clear(); // sleep minimum latency time for parameter reading timespec read_latency; read_latency.tv_sec=0; read_latency.tv_nsec=2000000; nanosleep(&read_latency,NULL); // now use shorter steps int timeout=100; read_latency.tv_nsec=1000000; while (return_value.size()<2 || return_value[return_value.size()-2]!=3) { int result=read(serial_dev,&got_byte,1); if (result<=0) { if (result<0 && errno!=EAGAIN) { return_value.clear(); pthread_mutex_unlock((pthread_mutex_t*)&device_lock); throw Eurotherm2000Series_error("read_value: error while reading"); } if (timeout<0) { return_value.clear(); pthread_mutex_unlock((pthread_mutex_t*)&device_lock); throw Eurotherm2000Series_error("read_value: timeout while reading"); } // go on sleeping for a while nanosleep(&read_latency,NULL); timeout--; continue; } if (return_value.size()==0 && got_byte==4) throw Eurotherm2000Series_error("read_value: invalid register"); return_value+=got_byte; } pthread_mutex_unlock((pthread_mutex_t*)&device_lock); if (0) { for (std::string::const_iterator i=return_value.begin();i!=return_value.end();++i) fprintf(stderr,"%02x",*i); fprintf(stderr,"\n"); } // test bcc unsigned char bcc=return_value[1]; for (size_t i=2;i1e-4) { if (i<0) throw Eurotherm2000Series_error("could not confirm setpoint value settings, timeout"); nanosleep(&write_latency,NULL); --i; } return ct; } double Eurotherm2000Series::get_setpoint() const { std::string answer; read_value("SL",answer); return strtod(answer.c_str(),NULL); } int Eurotherm2000Series::get_summary_status() const { std::string answer; read_value("SO",answer); if (answer[0]!='>') throw Eurotherm2000Series_error("could not handle status data format \'"+answer+"\'"); answer.erase(0,1); return strtol(answer.c_str(),NULL,16); } void Eurotherm2000Series::get_setpoint_limits(double& min, double& max) const { std::string answer; read_value("LS",answer); min=strtod(answer.c_str(),NULL); read_value("HS",answer); max=strtod(answer.c_str(),NULL); }