• Main Page
  • Modules
  • Data Structures
  • Files
  • File List
  • Globals

src/di194/di194.cpp

Go to the documentation of this file.
00001 /***************************************************************************
00002                           di194.cpp  -  Linux driver for DI-194 series
00003                                         acquisition device manufactured by
00004                                         DATAQ Instruments, Inc.
00005                              -------------------
00006     begin                : Mon Jun 7 2004
00007     author               : Ioan S. Popescu
00008 
00009 Changes:
00010 Mon Sep 17 2007 * Corrected the algorithm used to determine the sample rate on
00011                   line 712 then, 717 now.
00012                   From "+ 1 - m_SampleRate);" -> "/ m_SampleRate);".
00013 
00014 Copyright (C) 2004 DATAQ Instruments, Inc. <develop@dataq.com>
00015 
00016 This program is free software; you can redistribute it and/or 
00017 modify it under the terms of the GNU General Public License 
00018 as published by the Free Software Foundation; either 
00019 version 2 of the License, or (at your option) any later 
00020 version.
00021 
00022 This program 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 this program; if not, write to the Free Software
00029 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00030  ***************************************************************************/
00031 
00032 #include "di194.h"
00033 
00047 di194_dsdk::di194_dsdk():dsdk()
00048 {
00049   chan_order[0] = 0;
00050   m_ADChannelCount = 1;
00051   // create new lists
00052   m_ADChannelList = new int[m_ADChannelCount];
00053   m_ADMethodList = new int[m_ADChannelCount];
00054   for(int i=0; i<m_ADChannelCount; i++)
00055   {
00056     m_ADChannelList[i] = i;
00057     m_ADMethodList[i] = IOS_AVERAGE;
00058     chan_order[i] = i * DI194_CHAN_SIZE;
00059   }
00060 
00061   digital_chan = false;
00062 
00063   m_MaxBurstRate = 240.00;
00064   // set to default sample rate based on channels activated
00065   SampleRate(m_SampleRate);
00066 }
00067 
00072 di194_dsdk::~di194_dsdk()
00073 {
00074   DeviceDisconnect();
00075 
00076   if(m_ADChannelList != 0)
00077   {
00078     delete [] m_ADChannelList;
00079     m_ADChannelList = 0;
00080   }
00081   if(m_ADDiffList != 0)
00082   {
00083     delete [] m_ADDiffList;
00084     m_ADDiffList = 0;
00085   }
00086   if(m_ADGainList != 0)
00087   {
00088     delete [] m_ADGainList;
00089     m_ADGainList = 0;
00090   }
00091   if(m_ADMethodList != 0)
00092   {
00093     delete [] m_ADMethodList;
00094     m_ADMethodList = 0;
00095   }
00096   if(m_device_file != 0)
00097   {
00098     delete [] m_device_file;
00099     m_device_file = 0;
00100   }
00101 }
00102 
00103 // Get "Properties"
00104 
00108 const int di194_dsdk::ADChannelCount()
00109 {
00110   return m_ADChannelCount;
00111 }
00112 
00117 const long int di194_dsdk::AvailableData()
00118 {
00119   // no data if not acquiring
00120   if(!m_acquiring_data)
00121     return 0;
00122 
00123   return m_connection.bytes_in_receive()/DI194_CHAN_SIZE; 
00124 }
00125 
00129 const long int di194_dsdk::EventPoint()
00130 {
00131   return m_EventPoint;
00132 }
00133 
00147 const char *const di194_dsdk::InfoSerial()
00148 {
00149   // can't get serial number while acquiring data
00150   if(m_acquiring_data)
00151   {
00152     m_last_error = EBUSY;
00153     return 0;
00154   }
00155   // must be connected
00156   if(!m_connection.is_comm_open())
00157   {
00158     m_last_error = ENOLINK;
00159     return 0;
00160   }
00161 
00162   char *sn = new char[DI194_SN_LENGTH];
00163   if(!Ncmd(m_connection, sn))
00164     m_last_error = my_errno;
00165 
00166   return sn;
00167 }
00168 
00172 const double di194_dsdk::SampleRate()
00173 {
00174   return m_SampleRate;
00175 }
00176 
00177 // Set "Properties"
00178 
00207 void di194_dsdk::ADChannelCount(const int ChannelCount)
00208 {
00209   // can't set while acquiring data
00210   if(m_acquiring_data)
00211   {
00212     m_last_error = EBUSY;
00213     return;
00214   }
00215   // must be connected
00216   if(!m_connection.is_comm_open())
00217   {
00218     m_last_error = ENOLINK;
00219     return;
00220   }
00221   // bounds check
00222   if(ChannelCount > DI194_CHANNELS || ChannelCount < 1)
00223   {
00224     m_last_error = EBOUNDS;
00225     return;
00226   }
00227   // pointer check
00228   if(m_ADChannelList != 0)
00229   {
00230     delete [] m_ADChannelList;
00231     m_ADChannelList = 0;
00232   }
00233   // pointer check
00234   if(m_ADMethodList != 0)
00235   {
00236     delete [] m_ADMethodList;
00237     m_ADMethodList = 0;
00238   }
00239 
00240   m_ADChannelCount = ChannelCount;
00241   m_ADChannelList = new int[m_ADChannelCount];
00242   m_ADMethodList = new int[m_ADChannelCount];
00243   // initialize with default values
00244   for(int i=0; i<m_ADChannelCount; i++)
00245   {
00246     m_ADChannelList[i] = i;
00247     m_ADMethodList[i] = IOS_AVERAGE;
00248   }
00249   
00250   // check if all channels requested
00251   // if so, change last channel to digital
00252   if(m_ADChannelCount == DI194_CHANNELS)
00253   {
00254     m_ADChannelList[DI194_CHANNELS-1] = -1;
00255     // 'all channels' includes digital ports
00256     digital_chan = true;
00257     // last point makes more sense for digital
00258     m_ADMethodList[DI194_CHANNELS-1] = IOS_LAST_POINT;
00259     // setup channel order (used in conversion)
00260     for(int i=0; i<DI194_CHANNELS-1; i++)
00261       chan_order[i] = i;
00262   }
00263   else // no digital
00264   {
00265     digital_chan = false;
00266     for(int i=0; i<m_ADChannelCount; i++)
00267       chan_order[i] = i;
00268   }
00269 
00270   // set sample rate according to new channels
00271   SampleRate(m_SampleRate);
00272 
00273   /* set channels to scan for acquisition
00274   1   -   analog channel 1
00275   2   -   analog channel 2
00276   4   -   analog channel 3
00277   8   -   analog channel 4
00278 
00279   add together to get any combination of channels
00280       OR
00281   each bit is a channel: 4 (left) to 1 (right) using above scheme
00282   channel 1, binary: 0001     (decimal: 1)
00283   channel 2,3 binary: 0110    (decimal: 6) */
00284   u_int8_t chan = 0;
00285   for(int i=0; i<m_ADChannelCount; i++)
00286   {
00287     if(m_ADChannelList[i] > -1)
00288       chan |= (0x01 << m_ADChannelList[i]);
00289   }
00290   // enable digital channel input
00291   if(digital_chan)
00292   {
00293     if(!Dcmd(m_connection, 1))
00294     {
00295       m_last_error = my_errno;
00296       return;
00297     }
00298   }
00299   else  // disable digital channel input
00300   {
00301     if(!Dcmd(m_connection, 0))
00302     {
00303       m_last_error = my_errno;
00304       return;
00305     }
00306   }
00307   // enable analog channels
00308   if(!Ccmd(m_connection, chan))
00309   {
00310     m_last_error = my_errno;
00311     return;
00312   }
00313 }
00314 
00319 void di194_dsdk::EventPoint(const long int EventPnt)
00320 {
00321   if(EventPnt < 0)
00322     m_EventPoint = 0;
00323   else if(EventPnt > 32767)
00324     m_EventPoint = 32767;
00325   else
00326     m_EventPoint = EventPnt;
00327   
00328   return;
00329 }
00330 
00342 void di194_dsdk::SampleRate(const double SampleRt)
00343 {
00344   // can't set while acquiring data
00345   if(m_acquiring_data)
00346   {
00347     m_last_error = EBUSY;
00348     return;
00349   }
00350 
00351   double maxsr = 0;
00352   double minsr = 0;
00353   
00354   if(digital_chan)  // don't include digital channel in count
00355   {
00356     if(m_ADChannelCount == 1)
00357     {
00358       maxsr = DI194_MAXBURSTRATE; // don't divide by 0
00359       minsr = DI194_MINBURSTRATE; // don't multiply by 0
00360     }
00361     else
00362     { // subtract out the digital channel
00363       maxsr = DI194_MAXBURSTRATE / (m_ADChannelCount - 1);
00364       minsr = DI194_MINBURSTRATE * (m_ADChannelCount - 1);
00365     }
00366   }
00367   else  // no digital channel to worry about
00368   {
00369     maxsr = DI194_MAXBURSTRATE / m_ADChannelCount;
00370     minsr = DI194_MINBURSTRATE * m_ADChannelCount;
00371   }
00372   // user wants minimum, set to minimum
00373   if(SampleRt <= minsr)
00374     m_SampleRate = minsr;
00375   // user wants maximum, set to maximum
00376   else if(SampleRt >= maxsr)
00377     m_SampleRate = maxsr;
00378   else  // inbetween, user is within bounds
00379     m_SampleRate = SampleRt;
00380 }
00381 
00382 // "Methods"
00383 
00408 void di194_dsdk::ADChannelList(const int *const ChannelList)
00409 {
00410   // can't set while acquiring data
00411   if(m_acquiring_data)
00412   {
00413     m_last_error = EBUSY;
00414     return;
00415   }
00416   // must be connected
00417   if(!m_connection.is_comm_open())
00418   {
00419     m_last_error = ENOLINK;
00420     return;
00421   }
00422   // pointer check
00423   if(ChannelList == 0)
00424   {
00425     m_last_error = EINVAL;
00426     return;
00427   }
00428   // used to check if multiple digital channels are specified,
00429   // there shouldn't be
00430   bool check_digital = false;
00431   // bounds check
00432   for(int i=0; i<m_ADChannelCount; i++)
00433   {
00434     if(ChannelList[i] >= DI194_CHANNELS-1 || ChannelList[i] < -1)
00435     {
00436       m_last_error = EBOUNDS;
00437       return;
00438     }
00439     // make sure only one digital channel is specified
00440     if(ChannelList[i] == -1 && !check_digital)
00441       check_digital = true;
00442     else if(ChannelList[i] == -1)
00443     {
00444       m_last_error = EBOUNDS;
00445       return;
00446     }
00447   }
00448 
00449   // must have at least one analog channel enabled
00450   if(m_ADChannelCount == 1 && check_digital)
00451   {
00452     m_last_error = EBOUNDS;
00453     return;
00454   }
00455 
00456   // temporary, used for setting up channel order
00457   int temp_chan[DI194_CHANNELS] = {0};
00458 
00459   // set digital channel setting to what was determined in bounds check
00460   digital_chan = check_digital;
00461 
00462   // copy the channel list
00463   for(int i=0; i<m_ADChannelCount; i++)
00464   {
00465     m_ADChannelList[i] = ChannelList[i];
00466     temp_chan[i] = ChannelList[i];
00467   }
00468 
00469   // sort channel list, it's only 5 channels max,
00470   // bubble sort will work
00471   for(int i=1; i<m_ADChannelCount; i++)
00472   {
00473     for(int j=0; j<m_ADChannelCount-i; j++)
00474     {
00475       if(temp_chan[j] > temp_chan[j+1]) // need to swap?
00476       {
00477         temp_chan[j] = temp_chan[j] ^ temp_chan[j+1];
00478         temp_chan[j+1] = temp_chan[j] ^ temp_chan[j+1];
00479         temp_chan[j] = temp_chan[j] ^ temp_chan[j+1];
00480       }
00481     }
00482   }
00483 
00484   if(digital_chan)
00485   {
00486     // setup channel order
00487     for(int i=1; i<m_ADChannelCount; i++)
00488       chan_order[temp_chan[i]] = (i-1) * DI194_CHAN_SIZE;
00489   }
00490   else
00491   {
00492     // setup channel order
00493     for(int i=0; i<m_ADChannelCount; i++)
00494         chan_order[temp_chan[i]] = i * DI194_CHAN_SIZE;
00495   }
00496 
00497   /* set channels to scan for acquisition
00498   1   -   analog channel 1
00499   2   -   analog channel 2
00500   4   -   analog channel 3
00501   8   -   analog channel 4
00502 
00503   add together to get any combination of channels
00504       OR
00505   each bit is a channel: 4 (left) to 1 (right) using above scheme
00506   channel 1, binary: 0001     (decimal: 1)
00507   channel 2,3 binary: 0110    (decimal: 6) */
00508   u_int8_t chan = 0;
00509   for(int i=0; i<m_ADChannelCount; i++)
00510   {
00511     if(m_ADChannelList[i] != -1)
00512       chan |= (0x01 << m_ADChannelList[i]);
00513   }
00514   // enable digital channel input
00515   if(digital_chan)
00516   {
00517     if(!Dcmd(m_connection, 1))
00518     {
00519       m_last_error = my_errno;
00520       return;
00521     }
00522   }
00523   else  // disable digital channel input
00524   {
00525     if(!Dcmd(m_connection, 0))
00526     {
00527       m_last_error = my_errno;
00528       return;
00529     }
00530   }
00531   // enable analog channels
00532   if(!Ccmd(m_connection, chan))
00533   {
00534     m_last_error = my_errno;
00535     return;
00536   }
00537 }
00538 
00553 void di194_dsdk::ADMethodList(const int *const MethodList)
00554 {
00555   // can't set while acquiring data
00556   if(m_acquiring_data)
00557   {
00558     m_last_error = EBUSY;
00559     return;
00560   }
00561   // pointer check
00562   if(MethodList == 0)
00563   {
00564     m_last_error = EINVAL;
00565     return;
00566   }
00567 
00568   // bounds check
00569   for(int i=0; i<m_ADChannelCount; i++)
00570   {
00571     if(MethodList[i] > IOS_GREATEST || MethodList[i] < IOS_SMALLEST)
00572     {
00573       m_last_error = EBOUNDS;
00574       return;
00575     }
00576   }
00577 
00578   // copy the list
00579   for(int i=0; i<m_ADChannelCount; i++)
00580     m_ADMethodList[i] = MethodList[i];
00581 }
00582 
00598 void di194_dsdk::DeviceConnect()
00599 {
00600   // can't set while acquiring data
00601   if(m_acquiring_data)
00602   {
00603     m_last_error = EBUSY;
00604     return;
00605   }
00606   // device file hasn't been set
00607   if(m_device_file == 0)
00608   {
00609     m_last_error = ENODEV;
00610     return;
00611   }
00612   // already connected
00613   if(m_connection.is_comm_open())
00614   {
00615     m_last_error = EALREADY;
00616     return;
00617   }
00618 
00619   // open the serial port
00620   // setup the serial port
00621   my_errno = m_connection.connect(m_device_file, 1);
00622   if(my_errno != 0)
00623   {
00624     m_last_error = my_errno;
00625     DeviceDisconnect();
00626     return;
00627   }
00628 
00629   // make sure device is stopped
00630   m_acquiring_data = true;
00631   Stop();
00632 }
00633 
00645 void di194_dsdk::DeviceDisconnect()
00646 {
00647   // check if user forgot to stop acquiring
00648   if(m_acquiring_data)
00649     // stop acquiring first
00650     Stop();
00651   m_acquiring_data = false;
00652   // check if already disconnected
00653   if(!m_connection.is_comm_open())
00654     return;
00655   // restore original serial port settings and
00656   // try to close the serial port
00657   m_last_error = m_connection.disconnect();
00658 }
00659 
00690 void di194_dsdk::GetDataEx(short int *iArray, const int Count)
00691 {
00692   // bounds check
00693   if(Count > 32767 || Count < 1)
00694   {
00695     m_last_error = EBOUNDS;
00696     return;
00697   }
00698   // pointer check
00699   if(iArray == 0)
00700   {
00701     m_last_error = EINVAL;
00702     return;
00703   }
00704   // must be acquiring
00705   if(!m_acquiring_data)
00706   {
00707     m_last_error = ENODATA;
00708     return;
00709   }
00710 
00711   u_int8_t di_data[DI194_CHAN_SIZE*(DI194_CHANNELS-1)] = {0};
00712   int mCount = 0;
00713   // number of oversamples per real sample
00714   int srinterval = static_cast<int>(m_MaxBurstRate/ (digital_chan
00715                                           ? m_ADChannelCount-1
00716                                           : m_ADChannelCount)
00717                                           / m_SampleRate);
00718   if(srinterval <= 0)
00719     srinterval = 1;
00720   // temporarily holds original data to perform calculation
00721   short int temp[DI194_CHANNELS] = {0};
00722   // in case user asks for less data points than in a normal scan
00723   int small_sample = m_ADChannelCount < Count ? m_ADChannelCount : Count;
00724   // holds intermittent values for IOS_AVERAGE
00725   int64_t ios_avg[DI194_CHANNELS] = {0};
00726   bool first_time = true;
00727   u_int16_t amount = 0;
00728   if(digital_chan) // digital channel is embedded
00729   {
00730     amount = DI194_CHAN_SIZE*(m_ADChannelCount-1);
00731   }
00732   else  // no digital channel
00733   {
00734     amount = DI194_CHAN_SIZE*m_ADChannelCount;
00735   }
00736 
00737   // loop until enough data points have been gathered,
00738   // as far as blocks of enabled channels go
00739   for(int c=0, d=0, e=0; c<Count; c += small_sample, d=0)
00740   {
00741     first_time = true;
00742     for(e=0; e<small_sample; e++)
00743       ios_avg[e] = 0;
00744 
00745     // loop until the right number of samples have been gathered for
00746     // the specific sample rate
00747     for(int timer=0; timer<srinterval; timer++)
00748     {
00749       // get data
00750       if(m_connection.di_read(&di_data[0], amount, static_cast<u_int8_t>(amount)))
00751       {
00752         m_last_error = my_errno; // error occurred
00753         return;
00754       }
00755       // copy original values
00756       for(e=0; e<small_sample; e++)
00757         temp[e] = iArray[c+e];
00758       // convert new data to counts and store in array
00759       for(e=0; e<small_sample; e++)
00760         iArray[c + e] = static_cast<short int>(convert(&di_data[0], e));
00761       // increment number of oversamples per scan
00762       d++;
00763       // don't perform any calculations the first time through
00764       if(first_time)
00765       {
00766         first_time = false;
00767         for(e=0; e<small_sample; e++)
00768           ios_avg[e] += iArray[c+e];
00769         continue;
00770       }
00771       // apply method to 'original' and 'new' data values
00772       for(e=0; e<small_sample; e++)
00773       {
00774         switch(m_ADMethodList[e])
00775         {
00776           case IOS_RMS:  // not implemented
00777           case IOS_FREQ: // not implemented
00778           case IOS_LAST_POINT:  // last point
00779             // this happens by default, nothing to do
00780             break;
00781           case IOS_AVERAGE: // average of points
00782             ios_avg[e] += iArray[c+e];     // adds up values, after conversion above
00783             iArray[c+e] = ios_avg[e] / d;  // stores new average
00784             break;
00785           case IOS_MIN: // minimum of points
00786             if(temp[e] < iArray[c+e])
00787               iArray[c+e] = temp[e];
00788             break;
00789           case IOS_MAX: // maximum of points
00790             if(temp[e] > iArray[c+e])
00791               iArray[c+e] = temp[e];
00792             break;
00793         }
00794       }
00795     }
00796   }
00797 
00798   // any amount left that wasn't an even divisor of scanned blocks?
00799   // just use the next scanned packet
00800   mCount = Count % m_ADChannelCount;
00801   if(mCount != 0) // true if not done
00802   {
00803     // grab some more data
00804     if(m_connection.di_read(&di_data[0], amount, static_cast<u_int8_t>(amount)))
00805     {
00806       m_last_error = my_errno; // error occurred
00807       return;
00808     }
00809     // and store part of it
00810     for(int e=0; e<mCount; e++)
00811       iArray[Count - mCount + e] = static_cast<short int>(convert(&di_data[0], e));
00812   }
00813 }
00814 
00827 void di194_dsdk::Start()
00828 {
00829   // don't send command if already acquiring, this is an error because
00830   // there is data in the buffer
00831   if(m_acquiring_data)
00832   {
00833     m_last_error = EALREADY;
00834     return;
00835   }
00836   if(!m_connection.is_comm_open()) // don't bother if not connected
00837   {
00838     m_last_error = ENOLINK;
00839     return;
00840   }
00841 
00842   // send command
00843   if(!Scmd(m_connection, 1))
00844   {
00845     m_last_error = my_errno;
00846     return;
00847   }
00848 
00849   m_acquiring_data = true;
00850 }
00851 
00863 void di194_dsdk::Stop()
00864 {
00865   // can't set while not acquiring data,
00866   // not really an error
00867   if(!m_acquiring_data)
00868     return;
00869   // must be connected
00870   if(!m_connection.is_comm_open())
00871   {
00872     m_last_error = ENOLINK;
00873     return;
00874   }
00875 
00876   // send command
00877   if(!Scmd(m_connection))
00878   {
00879     m_last_error = my_errno;
00880     return;
00881   }
00882 
00883   m_acquiring_data = false;
00884 }
00885 
00886 // "Event Occur" Methods
00887 
00899 const bool di194_dsdk::OverRun()
00900 {
00901   // must be connected
00902   if(!m_connection.is_comm_open())
00903   {
00904     m_last_error = ENOLINK;
00905     return false;
00906   }
00907 
00908   // doesn't set an error because this function represents an error
00909   if(m_connection.bytes_in_receive() >= DI_SERIAL_BUFFER_SIZE)
00910     return true;
00911 
00912   return false;
00913 }
00914 
00921 const short int di194_dsdk::convert(const u_int8_t *const di_data,
00922                                     const u_int8_t num_chan)
00923 {
00924   short int temp = 0;
00925   // extract and convert to counts
00926   // find out whether it's an analog or digital channel
00927   if(m_ADChannelList[num_chan] != -1) // analog channel
00928   {
00929     temp = static_cast<short int>(di_data[chan_order[m_ADChannelList[num_chan]]]
00930                    & 0xE0) >> 5;
00931     temp |= (static_cast<short int>(di_data[chan_order[m_ADChannelList[num_chan]]+1]
00932                    & 0xFE) << 2);
00933     temp <<= 6; // left justify the number
00934     temp ^= 0x8000;
00935   }
00936   else // digital bits
00937     temp = (di_data[0] & 0x0E) >> 1;
00938 
00939   return temp;
00940 }
00941 

Generated on Thu Jun 2 2011 22:45:28 for DataQSdk by  doxygen 1.7.2