TOBI SignalServer  0.1
/home/breidi/Dropbox/signalserver/src/hardware/g_mobilab.cpp
Go to the documentation of this file.
00001 /*
00002     This file is part of the TOBI SignalServer.
00003 
00004     Commercial Usage
00005     Licensees holding valid Graz University of Technology Commercial
00006     licenses may use this file in accordance with the Graz University
00007     of Technology Commercial License Agreement provided with the
00008     Software or, alternatively, in accordance with the terms contained in
00009     a written agreement between you and Graz University of Technology.
00010 
00011     --------------------------------------------------
00012 
00013     GNU General Public License Usage
00014     Alternatively, this file may be used under the terms of the GNU
00015     General Public License version 3.0 as published by the Free Software
00016     Foundation and appearing in the file gpl.txt included in the
00017     packaging of this file.  Please review the following information to
00018     ensure the GNU General Public License version 3.0 requirements will be
00019     met: http://www.gnu.org/copyleft/gpl.html.
00020 
00021     In case of GNU General Public License Usage ,the TOBI SignalServer
00022     is distributed in the hope that it will be useful,
00023     but WITHOUT ANY WARRANTY; without even the implied warranty of
00024     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00025     GNU General Public License for more details.
00026 
00027     You should have received a copy of the GNU General Public License
00028     along with the TOBI SignalServer. If not, see <http://www.gnu.org/licenses/>.
00029 
00030     Copyright 2010 Graz University of Technology
00031     Contact: SignalServer@tobi-project.org
00032 */
00033 
00038 #include "hardware/g_mobilab.h"
00039 #include "hardware/hw_thread_builder.h"
00040 
00041 #include <vector>
00042 #include <boost/bind.hpp>
00043 #include <boost/lexical_cast.hpp>
00044 
00045 namespace tobiss
00046 {
00047 
00048 using std::vector;
00049 using std::string;
00050 using std::map;
00051 
00052 using std::cout;
00053 using std::cerr;
00054 using std::endl;
00055 using std::flush;
00056 
00057 using boost::uint16_t;
00058 using boost::uint32_t;
00059 
00060 static const unsigned int MOBILAB_MAX_NR_OF_CHANNELS    = 8;
00061 static const double MOBILAB_DAQ_RESOLUTION_BIT    = 16;
00062 static const unsigned int MOBILAB_DAQ_RESOLUTION_BYTE   = 2;
00063 static const unsigned int MOBILAB_SAMPLING_RATE  = 256;  // Hz
00064 
00065 static const float MOBILAB_EEG_SENSITIVITY =       500;  //micro volts
00066 static const float MOBILAB_EOG_SENSITIVITY =      2000;  //micro volts
00067 static const float MOBILAB_EMG_SENSITIVITY =      5000;  //micro volts
00068 static const float MOBILAB_ANALOG_SENSITIVITY = 250000;  //micro volts
00069 
00070 static const double MOBILAB_COMMON_LOWPASS  =  100;  // Hz
00071 static const double MOBILAB_EEG_HIGHPASS    =  0.5;  // Hz
00072 static const double MOBILAB_EOG_HIGHPASS    =  0.01;  // Hz
00073 static const double MOBILAB_EMG_HIGHPASS    =  0.5;  // Hz
00074 
00075 static const unsigned int MOBILAB_BAUD_RATE    = 57600;
00076 static const unsigned int MOBILAB_CHAR_SIZE    = 8;
00077 static const std::string  MOBILAB_FLOW_CONTROL = "none";
00078 static const std::string  MOBILAB_STOP_BITS    = "1";
00079 static const std::string  MOBILAB_PARITY       = "none";
00080 
00081 
00082 const string GMobilab::hw_mobilab_serial_port_("serial_port");
00083 const string GMobilab::hw_mobilab_type_("mobilab_type");
00084 const string GMobilab::hw_mobilab_eeg_("eeg");
00085 const string GMobilab::hw_mobilab_multi_("multi");
00086 
00087 //-----------------------------------------------------------------------------
00088 
00089 #ifndef WIN32
00090 
00091   #include <termios.h>
00092 
00093   // very very bad hack ... taken from ttylog
00094   // don't know if something similar has to be done for windows
00095   // if this code is not executed, the mobilab does not respond
00096   // don't know why
00097   // only starting ttylog before the sigserver was enough, otherwise
00098   // the mobilab did not respond
00099   // maybe some pins have to be set manually
00100   void DO_BAD_SERIAL_PORT_HACK(std::string dev)
00101   {
00102     unsigned int count = 2;
00103     while(count)
00104     {
00105       FILE *logfile;
00106       int fd;
00107       fd_set rfds;
00108       struct termios oldtio, newtio;
00109 
00110       logfile = fopen (dev.c_str(), "rb");
00111 
00112       fd = fileno (logfile);
00113 
00114       tcgetattr (fd, &oldtio); /* save current serial port settings */
00115       bzero (&newtio, sizeof (newtio)); /* clear struct for new port settings */
00116 
00117       newtio.c_cflag = B57600 | CRTSCTS | CS8 | CLOCAL | CREAD;
00118       newtio.c_iflag = IGNPAR | IGNCR;
00119       newtio.c_oflag = 0;
00120       newtio.c_lflag = ICANON;
00121 
00122       tcflush (fd, TCIFLUSH);
00123       tcsetattr (fd, TCSANOW, &newtio);
00124 
00125       /* Clear the device */
00126       FD_ZERO (&rfds);
00127       FD_SET (fd, &rfds);
00128 
00129       fclose (logfile);
00130       tcsetattr (fd, TCSANOW, &oldtio);
00131 
00132       count--;
00133       usleep(20000);
00134     }
00135   }
00136 
00137 #endif
00138 
00139 const HWThreadBuilderTemplateRegistrator<GMobilab> GMobilab::factory_registrator_ ("mobilab", "mobilab+", "g.mobilab", "g.mobilab+");
00140 
00141 //-----------------------------------------------------------------------------
00142 GMobilab::GMobilab(boost::asio::io_service& io, ticpp::Iterator<ticpp::Element> hw)
00143   : SerialPortBase(io), HWThread(), mobilab_type_(MOBILAB_EEG), async_acqu_thread_(0)
00144 {
00145   setType("g.Mobilab");
00146   setHardware(hw);
00147 
00148   checkNrOfChannels();
00149   setScalingValues();
00150 
00151 #ifndef WIN32
00152   DO_BAD_SERIAL_PORT_HACK(getSerialPortName());
00153 #endif
00154 
00155   open();
00156   setBaudRate(MOBILAB_BAUD_RATE);
00157   setFlowControl(MOBILAB_FLOW_CONTROL);
00158   setParity(MOBILAB_PARITY);
00159   setStopBits(MOBILAB_STOP_BITS);
00160   setCharacterSize(MOBILAB_CHAR_SIZE);
00161 
00162   raw_data_.resize(nr_ch_, 0);
00163 
00164   samples_.reserve(4 * nr_ch_);
00165   samples_.resize(nr_ch_, 0);
00166 
00167   if(blocks_ != 1)
00168     throw(std::invalid_argument("Blocksize > 1 not supported yet!") );
00169 
00170   std::vector<unsigned char> command;
00171   std::vector<unsigned char> reply(1,0);
00172 
00173   unsigned char channel_code = getChannelCode();
00174 
00175   // command to set channels ... sniffed from serial communication
00176   command.push_back(0x63);
00177   command.push_back(channel_code);
00178   command.push_back(0x20);
00179 
00180   sync_write(command);
00181   sync_read(reply);
00182 
00183   // response from mobilab if channel setting was ok -- don't know other messages
00184   if(reply[0] != 0x63)
00185     throw(std::runtime_error("GMobilab::Constructor -- Wrong hardware response from mobilab!") );
00186 
00187   data_.init(blocks_ , nr_ch_ , channel_types_);
00188 
00189 }
00190 
00191 //-----------------------------------------------------------------------------
00192 
00193 void GMobilab::run()
00194 {
00195 
00196   // command to start data transmission
00197   std::vector<unsigned char> command(1, 0x61);
00198   sync_write(command);
00199 
00200   if(mode_ == SLAVE)
00201     async_acqu_thread_ = new boost::thread( boost::bind(&GMobilab::acquireData, this) );
00202 
00203   running_ = true;
00204 }
00205 
00206 //-----------------------------------------------------------------------------
00207 
00208 GMobilab::~GMobilab()
00209 {
00210   async_acqu_thread_->join();
00211   close();
00212   if(async_acqu_thread_)
00213     delete async_acqu_thread_;
00214 }
00215 
00216 //-----------------------------------------------------------------------------
00217 
00218 void GMobilab::stop()
00219 {
00220   running_ = false;
00221   boost::unique_lock<boost::shared_mutex> lock(rw_);
00222 
00223   // command to stop data transmission
00224   std::vector<unsigned char> command(1,0x62);
00225   sync_write(command);
00226 
00227 }
00228 
00229 //-----------------------------------------------------------------------------
00230 
00231 SampleBlock<double> GMobilab::getSyncData()
00232 {
00233   if(running_)
00234   {
00235     boost::unique_lock<boost::shared_mutex> lock(rw_);
00236 
00237     sync_read(raw_data_);
00238 
00239     for(unsigned int n = 0; n < raw_data_.size(); n++)
00240       samples_[n] = raw_data_[n]* scaling_factors_[n];
00241 
00242     data_.setSamples(samples_);
00243   }
00244   return(data_);
00245 }
00246 
00247 //-----------------------------------------------------------------------------
00248 
00249 SampleBlock<double> GMobilab::getAsyncData()
00250 {
00251   if(running_)
00252   {
00253     boost::unique_lock<boost::shared_mutex> lock(rw_);
00254 
00255     data_.setSamples(samples_);
00256 
00257   }
00258 
00259   return(data_);
00260 }
00261 
00262 //-----------------------------------------------------------------------------
00263 
00264 void GMobilab::setHardware(ticpp::Iterator<ticpp::Element>const &hw)
00265 {
00266   #ifdef DEBUG
00267     std::cout << "GMobilab: setHardware" << std::endl;
00268   #endif
00269 
00270   checkMandatoryHardwareTags(hw);
00271   ticpp::Iterator<ticpp::Element> ds(hw->FirstChildElement(hw_devset_, true));
00272 
00273   setDeviceSettings(ds);
00274 
00275   ticpp::Iterator<ticpp::Element> cs(hw->FirstChildElement(hw_chset_, false));
00276   if (cs != cs.end())
00277   {
00278     for(ticpp::Iterator<ticpp::Element> it(cs); ++it != it.end(); )
00279       if(it->Value() == hw_chset_)
00280       {
00281         string ex_str(type_ + " -- ");
00282         ex_str += "Multiple channel_settings found!";
00283         throw(std::invalid_argument(ex_str));
00284       }
00285       setChannelSettings(cs);
00286   }
00287 }
00288 
00289 //-----------------------------------------------------------------------------
00290 
00291 void GMobilab::setDeviceSettings(ticpp::Iterator<ticpp::Element>const &father)
00292 {
00293   #ifdef DEBUG
00294     std::cout << "GMobilab: setDeviceSettings" << std::endl;
00295   #endif
00296 
00297   fs_ = MOBILAB_SAMPLING_RATE;
00298 
00299   ticpp::Iterator<ticpp::Element>elem = father->FirstChildElement(hw_mobilab_serial_port_,true);
00300   setPortName(elem->GetText(true));
00301 
00302   elem = father->FirstChildElement(hw_mobilab_type_,true);
00303   if(elem->GetText(true) == hw_mobilab_eeg_)
00304     mobilab_type_ = MOBILAB_EEG;
00305   else if(elem->GetText(true) == hw_mobilab_multi_)
00306     mobilab_type_ = MOBILAB_MULTI;
00307   else
00308     throw(std::invalid_argument(
00309         "GMobilab::setDeviceSettings() -- type not supported or wrong:") );
00310 
00311   elem = father->FirstChildElement(hw_channels_,false);
00312   if(elem != elem.end())
00313     setDeviceChannels(elem);
00314 
00315   elem = father->FirstChildElement(hw_blocksize_,false);
00316   if(elem != elem.end())
00317     setBlocks(elem);
00318 }
00319 
00320 //---------------------------------------------------------------------------------------
00321 
00322 void GMobilab::setChannelSettings(ticpp::Iterator<ticpp::Element>const &father)
00323 {
00324   #ifdef DEBUG
00325     std::cout << "GMobilab: setChannelSettings" << std::endl;
00326   #endif
00327 
00328   ticpp::Iterator<ticpp::Element> elem(father->FirstChildElement(hw_chset_sel_,false));
00329   if (elem != elem.end())
00330     setChannelSelection(elem);
00331 }
00332 
00333 //---------------------------------------------------------------------------------------
00334 
00335 void GMobilab::setScalingValues()
00336 {
00337   // use only 50% of the sensitivity to get a correct scaling
00338 
00339   if(mobilab_type_ == MOBILAB_EEG)
00340   {
00341     std::map<boost::uint16_t, std::pair<std::string, boost::uint32_t> >::iterator it;
00342     for(it = channel_info_.begin(); it != channel_info_.end(); it++)
00343     {
00344       scaling_factors_.push_back(
00345           MOBILAB_EEG_SENSITIVITY/(2.0 * pow(2.0 ,MOBILAB_DAQ_RESOLUTION_BIT) ) );
00346     }
00347   }
00348   if(mobilab_type_ == MOBILAB_MULTI)
00349   {
00350     double scaling = 0;
00351     double sensitivity = 0;
00352     boost::uint16_t channel = 0;
00353 
00354     std::map<boost::uint16_t, std::pair<std::string, boost::uint32_t> >::iterator it;
00355     for(it = channel_info_.begin(); it != channel_info_.end(); it++)
00356     {
00357       channel = (*it).first;
00358 
00359       std::cout << " GMobilab::setScalingValues() -- channel numbers: ";
00360       std::cout <<  channel << std::flush << std::endl;
00361 
00362       if(channel == 1 || channel == 2)
00363         sensitivity = MOBILAB_EEG_SENSITIVITY;
00364       if(channel == 3 || channel == 4)
00365         sensitivity = MOBILAB_EOG_SENSITIVITY;
00366       if(channel == 5 || channel == 6)
00367         sensitivity = MOBILAB_EMG_SENSITIVITY;
00368       if(channel == 7 || channel == 8)
00369         sensitivity = MOBILAB_ANALOG_SENSITIVITY;
00370 
00371       scaling = sensitivity/pow(2.0 ,MOBILAB_DAQ_RESOLUTION_BIT);
00372       scaling_factors_.push_back(scaling/2.0);
00373 
00374     }
00375   }
00376 }
00377 
00378 //---------------------------------------------------------------------------------------
00379 
00380 unsigned char GMobilab::getChannelCode()
00381 {
00382   // binary channel coding for the mobilab
00383   channel_coding_[1] = 0x80;
00384   channel_coding_[2] = 0x40;
00385   channel_coding_[3] = 0x20;
00386   channel_coding_[4] = 0x10;
00387   channel_coding_[5] = 0x08;
00388   channel_coding_[6] = 0x04;
00389   channel_coding_[7] = 0x02;
00390   channel_coding_[8] = 0x01;
00391 
00392   unsigned char code = 0;
00393   std::map<boost::uint16_t, std::pair<std::string, boost::uint32_t> >::iterator it;
00394   for(it = channel_info_.begin(); it != channel_info_.end(); it++)
00395     code |= channel_coding_[ (*it).first ];
00396 
00397   return(code);
00398 }
00399 
00400 //---------------------------------------------------------------------------------------
00401 
00402 void GMobilab::checkNrOfChannels()
00403 {
00404   #ifdef DEBUG
00405     cout << "USBamp: checkNrOfChannels" << endl;
00406   #endif
00407 
00408   if(nr_ch_ > MOBILAB_MAX_NR_OF_CHANNELS )
00409     throw(std::invalid_argument("Too many channels defined -- maximum nr of channels: "\
00410                                 +boost::lexical_cast<string>(MOBILAB_MAX_NR_OF_CHANNELS)) );
00411 
00412   map<uint16_t, std::pair<string, uint32_t> >::iterator it(channel_info_.begin());
00413 
00414   for(  ; it != channel_info_.end(); it++ )
00415     if(it->first > MOBILAB_MAX_NR_OF_CHANNELS )
00416       throw(std::invalid_argument("Channel number too high -- maximum nr of channels: "\
00417       +boost::lexical_cast<string>(MOBILAB_MAX_NR_OF_CHANNELS)) );
00418 }
00419 
00420 //---------------------------------------------------------------------------------------
00421 
00422 void GMobilab::acquireData()
00423 {
00424   while(running_)
00425   {
00426     sync_read(raw_data_);
00427 
00428     boost::unique_lock<boost::shared_mutex> lock(rw_);
00429     for(unsigned int n = 0; n < raw_data_.size(); n++)
00430       samples_[n] = raw_data_[n]* scaling_factors_[n];
00431     lock.unlock();
00432   }
00433 }
00434 
00435 //---------------------------------------------------------------------------------------
00436 
00437 } // Namespace tobiss
00438 
 All Data Structures Files Functions Variables