text: # winspec.py, COM wrapper for use with Roper Scientific's Winspec
  # Reinier Heeres <reinier@heeres.eu>, 2009
  #
  # This program is free software; you can redistribute it and/or modify
  # it under the terms of the GNU General Public License as published by
  # the Free Software Foundation; either version 2 of the License, or
  # (at your option) any later version.
  #
  # This program is distributed in the hope that it will be useful,
  # but WITHOUT ANY WARRANTY; without even the implied warranty of
  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  # GNU General Public License for more details.
  #
  # You should have received a copy of the GNU General Public License
  # along with this program; if not, write to the Free Software
  # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  
  import time
  
  import numpy as np
  from comtypes.client import Constants, CreateObject
  
  _exp = None
  _app = None
  _const = None
  _spec_mgr = None
  _spec = None
  
  
  def _initialize():
      '''
      Create objects. Associated constants will be available in the _const
      object. Note that it's not possible to request the contents of that;
      one has to look in the Python file generated with gen_py.
      '''
      global _exp, _app, _const, _spec_mgr, _spec
      _exp = CreateObject('WinX32.ExpSetup.2')
      _app = CreateObject('WinX32.Winx32App.2')
      _const = Constants(_exp)
      _spec_mgr = CreateObject('WinX32.SpectroObjMgr')
      _spec = _spec_mgr.Current
      _spec.Process(_const.SPTP_INST_LOADCONFIGURATION)
  
  
  def _get_wavelen(coord, coeffs):
      val = 0
      for power, coef in enumerate(coeffs):
          val += coef * (coord + 1) ** power
      return val
  
  
  def get_exposure_time():
      return _exp.SGetParam(_const.EXP_EXPOSURE)[1]
  
  
  def set_exposure_time(val):
      return _exp.SetParam(_const.EXP_EXPOSURE, val)
  
  
  def get_use_new_window():
      return _exp.SGetParam(_const.EXP_NEWWINDOW)[1]
  
  
  def set_use_new_window(val):
      return _exp.SetParam(_const.EXP_NEWWINDOW, val)
  
  
  def get_file_inc_enable():
      return _exp.SGetParam(_const.EXP_FILEINCENABLE)[1]
  
  
  def set_file_inc_enable(val):
      return _exp.SetParam(_const.EXP_FILEINCENABLE, val)
  
  
  def get_autosave():
      return _exp.SGetParam(_const.EXP_AUTOSAVE)[1]
  
  
  def set_autosave(val):
      return _exp.SetParam(_const.EXP_AUTOSAVE, val)
  
  
  def get_grating():
      return _spec.GetParam(_const.SPT_CUR_GRATING)[1]
  
  
  def get_grating_grooves(gr):
      '''gr is the absolute grating number.'''
      return _spec.GetParam(_const.SPT_GRAT_GROOVES, gr)[1]
  
  
  def get_grating_name(gr):
      '''gr is the absolute grating number.'''
      return _spec.GetParam(_const.SPT_GRAT_USERNAME, gr)[1]
  
  
  def get_ngratings():
      '''Get number of gratings per turret.'''
      return _spec.GetParam(_const.SPT_GRATINGSPERTURRET)[1]
  
  
  def get_current_turret():
      return _spec.GetParam(_const.SPT_ACTIVE_TURRET_NUM)[1]
  
  
  def set_grating(val):
      _spec.SetParam(_const.SPT_NEW_GRATING, val)
      _spec.Move()
      return get_grating()
  
  
  def get_temperature():
      return _exp.SGetParam(_const.EXP_ACTUAL_TEMP)[1]
  
  
  def get_target_temperature():
      return _exp.SGetParam(_const.EXP_TEMPERATURE)[1]
  
  
  def set_target_temperature(val):
      return _exp.SetParam(_const.EXP_TEMPERATURE, val)
  
  
  def get_wavelength():
      return _spec.GetParam(_const.SPT_CUR_POSITION)[1]
  
  
  def set_wavelength(val):
      _spec.SetParam(_const.SPT_NEW_POSITION, float(val))
      _spec.Move()
      return get_wavelength()
  
  
  # Default maximum number of sleeps for 250sec
  MAX_SLEEPS = 5000
  doc = None
  
  
  def get_wavelengths():
      global doc
      if doc is None:
          doc = CreateObject('WinX32.DocFile.3')
  
      _exp.Start(doc)
      i = 0
      while i < MAX_SLEEPS:
          status = _exp.SGetParam(_const.EXP_RUNNING)[1]
          if status == 0:
              break
          i += 1
          time.sleep(0.05)
  
      if i == MAX_SLEEPS:
          print
          'Warning: maximum delay exceeded'
          return None
      xdim = doc.SGetParam(_const.DM_XDIM)[1]
      ydim = doc.SGetParam(_const.DM_YDIM)[1]
      if ydim != 1:
          raise ValueError('Can only get 1D spectra')
      calib = doc.GetCalibration()
      order = calib.Order
      coeffs = [calib.PolyCoeffs(i) for i in range(order + 1)]
      wlens = [_get_wavelen(i, coeffs) for i in range(xdim)]
      return wlens
  
  
  # def get_spectrum(wlen=True, wlenpoly=True, newdoc=False):
  def get_spectrum(wlen=False, wlenpoly=True, newdoc=False):
      '''
      Get a spectrum using winspec.
  
      If wlen is True it returns a 2D numpy array with wavelength and counts
      as the columns. If wlen is False it returns a 1D array with counts.
      If wlenpoly is True the polynomial approximation for determining the
      wavelength will be used, which is quite a bit faster than querying winspec
      for the individual pixels. It can be off by ~0.3nm.
      '''
  
      global doc
      if newdoc or doc is None:
          doc = CreateObject('WinX32.DocFile.3')
  
      _exp.Start(doc)
      i = 0
      while i < MAX_SLEEPS:
          status = _exp.SGetParam(_const.EXP_RUNNING)[1]
          if status == 0:
              break
          i += 1
          time.sleep(0.05)
  
      if i == MAX_SLEEPS:
          print
          'Warning: maximum delay exceeded'
          return None
  
      xdim = doc.SGetParam(_const.DM_XDIM)[1]
      ydim = doc.SGetParam(_const.DM_YDIM)[1]
      if ydim != 1:
          raise ValueError('Can only get 1D spectra')
  
      spectrum = np.array(doc.GetFrame(1), dtype=np.uint16).flatten()
      # spectrum = np.array(doc.GetFrame(1),dtype=np.uint16)
      # spectrum.flatten()
      if wlen:
          calib = doc.GetCalibration()
          if wlenpoly:
              order = calib.Order
              coeffs = [calib.PolyCoeffs(i) for i in range(order + 1)]
              wlens = [_get_wavelen(i, coeffs) for i in range(xdim)]
          else:
              wlens = [calib.Lambda(i + 1) for i in range(xdim)]
          spectrum = zip(wlens, spectrum)
  
      return spectrum
  
  
  _initialize()
  