From ab625de57db814f153243e8c690539c37b751e2c Mon Sep 17 00:00:00 2001
From: Emmanuel Papillon <papillon@esrf.fr>
Date: Wed, 8 Apr 2020 10:24:01 +0200
Subject: [PATCH 01/24] add parsing of marana 4.2 model add reading of pixel
 size from library change trigger mode handling: list of triggers read from
 sdk (no static enum) internal trigger mode in lima unit (IntTrig, ...) remove
 andor3 functions set/getTriggerMode : trigger mode has to be set using lima
 standards set/getTrigMode

---
 include/Andor3Camera.h |  14 +-
 sip/Andor3Camera.sip   |   6 +-
 src/Andor3Camera.cpp   | 282 ++++++++++++++++++++---------------------
 tango/Andor3.py        |  11 ++
 4 files changed, 159 insertions(+), 154 deletions(-)

diff --git a/include/Andor3Camera.h b/include/Andor3Camera.h
index ef6f210..8e44939 100644
--- a/include/Andor3Camera.h
+++ b/include/Andor3Camera.h
@@ -70,7 +70,8 @@ namespace lima
       // In the same order/index as 'BitDepth'
       enum A3_BitDepth { b11 = 0, b16= 1 };
       // The camera trigger mode (in the enum order) :
-      enum A3_TriggerMode { Internal = 0, ExternalLevelTransition = 1, ExternalStart = 2, ExternalExposure = 3, Software = 4, Advanced = 5, External = 6 };
+//      enum A3_TriggerMode { Internal = 0, ExternalLevelTransition = 1, ExternalStart = 2, ExternalExposure = 3, Software = 4, Advanced = 5, External = 6 };
+
       // The binning system of andor3 :
       enum A3_Binning { B1x1=0, B2x2=1, B3x3=2, B4x4=3, B8x8=4};
       // The fan speed
@@ -167,8 +168,8 @@ namespace lima
       void getBitDepthString(std::string &oDepthString) const;
       void getPxEncoding(A3_PixelEncoding &oPxEncoding) const;
       void getPxEncodingString(std::string &oPxEncoding) const;
-      void setTriggerMode(A3_TriggerMode iMode);
-      void getTriggerMode(A3_TriggerMode &oMode) const;
+      // void setTriggerMode(A3_TriggerMode iMode);
+      // void getTriggerMode(A3_TriggerMode &oMode) const;
       void getTriggerModeString(std::string &oModeString) const;
       void setTemperatureSP(double temp);  // à exporter (avec le get)
       void getTemperatureSP(double& temp) const;
@@ -220,6 +221,8 @@ namespace lima
       void _setStatus(Camera::Status iStatus, bool iForce);
       
     private:
+      void initTrigMode();
+
       // -- andor3 Lower level functions
       int printInfoForProp(const AT_WC * iPropName, A3_TypeInfo iPropType) const;
       bool propImplemented(const AT_WC * iPropName) const;
@@ -294,12 +297,13 @@ namespace lima
       A3_ReadOutRate	          m_adc_rate;
       A3_ShutterMode		  m_electronic_shutter_mode;
       A3_BitDepth                 m_bit_depth;
-      A3_TriggerMode              m_trig_mode;
       bool                        m_cooler;
       double                      m_temperature_sp;
       bool                        m_temperature_control_available;
 
-      // std::map<TrigMode, int>     m_trig_mode_maps;
+      TrigMode                    m_trig_mode;
+      // A3_TriggerMode		  m_trig_mode;
+      std::map<TrigMode, int>     m_trig_mode_map;
 
       static int                  sAndorSDK3InittedCounter;
     
diff --git a/sip/Andor3Camera.sip b/sip/Andor3Camera.sip
index c7c95f4..3b4312a 100644
--- a/sip/Andor3Camera.sip
+++ b/sip/Andor3Camera.sip
@@ -36,7 +36,7 @@ namespace Andor3
     enum A3_ShutterMode { Rolling = 0, Global = 1 };
     enum A3_ReadOutRate { MHz10 = 0, MHz100 = 1, MHz200 = 2, MHz280 = 3 };
     enum A3_BitDepth { b11 = 0, b16= 1 };
-    enum A3_TriggerMode { Internal = 0, ExternalLevelTransition = 1, ExternalStart = 2, ExternalExposure = 3, Software = 4, Advanced = 5, External = 6 };
+//    enum A3_TriggerMode { Internal = 0, ExternalLevelTransition = 1, ExternalStart = 2, ExternalExposure = 3, Software = 4, Advanced = 5, External = 6 };
     enum A3_Binning { B1x1=0, B2x2=1, B3x3=2, B4x4=3, B8x8=4};
     enum A3_FanSpeed { Off=0, Low=1, On=2};
     enum A3_PixelEncoding {Mono12=0, Mono12Packed = 1, Mono16=2, Mono32=3};
@@ -107,8 +107,8 @@ namespace Andor3
    void getBitDepth(A3_BitDepth &oMode /Out/ ) const;
    void getBitDepthString(std::string &oDepthString /Out/ ) const;
    void getPxEncodingString(std::string &oPxEncoding /Out/ ) const;
-   void setTriggerMode(A3_TriggerMode iMode /In/ );
-   void getTriggerMode(A3_TriggerMode &oMode /Out/ ) const;
+//   void setTriggerMode(A3_TriggerMode iMode /In/ );
+//   void getTriggerMode(A3_TriggerMode &oMode /Out/ ) const;
    void getTriggerModeString(std::string &oModeString /Out/ ) const;
    void setTemperatureSP(double temp /In/ );
    void getTemperatureSP(double& temp /Out/ ) const;
diff --git a/src/Andor3Camera.cpp b/src/Andor3Camera.cpp
index 3f4caff..33273c0 100644
--- a/src/Andor3Camera.cpp
+++ b/src/Andor3Camera.cpp
@@ -73,6 +73,8 @@ namespace lima {
     static const AT_WC* Overlap = L"Overlap";
     static const AT_WC* PixelEncoding = L"PixelEncoding";
     static const AT_WC* PixelReadoutRate = L"PixelReadoutRate";
+    static const AT_WC* PixelHeight = L"PixelHeight";
+    static const AT_WC* PixelWidth = L"PixelWidth";
     static const AT_WC* PreAmpGainControl = L"PreAmpGainControl";
     static const AT_WC* ReadoutTime = L"ReadoutTime";
     static const AT_WC* SensorCooling = L"SensorCooling";
@@ -168,7 +170,7 @@ m_simple_gain(b16_lh_gain),
 m_adc_rate(MHz100),
 m_electronic_shutter_mode(Rolling),
 m_bit_depth(b16),
-m_trig_mode(Internal),
+m_trig_mode(IntTrig),
 m_cooler(true),
 m_temperature_sp(5.0),
 m_temperature_control_available(true),
@@ -254,7 +256,9 @@ m_maximage_size_cb_active(false)
   if (! m_detector_model.compare(0, 7, "ZYLA5.5")) {
     m_detector_type = std::string("Zyla-5.5");    
   }
-  
+  if (! m_detector_model.compare(0, 12, "MARANA-4BV11")) {
+    m_detector_type = std::string("Marana-4.2");
+  }
   
   if ( m_detector_model != "SIMCAM CMOS" ) {
     std::string		the_serial, the_fw;
@@ -291,7 +295,14 @@ m_maximage_size_cb_active(false)
 		       "Cannot get detector Y size");
 
   m_detector_size= Size(static_cast<int>(xmax), static_cast<int>(ymax));
-  
+
+  // --- init trigger modes
+  initTrigMode();
+
+  // printInfoForProp(andor3::ElectronicShutteringMode, Enum);
+  // printInfoForProp(andor3::PixelReadoutRate, Enum);
+  // printInfoForProp(andor3::PixelEncoding, Enum);
+
   // --- Initialise deeper parameters of the controller
   initialiseController();
   
@@ -451,7 +462,7 @@ lima::Andor3::Camera::prepareAcq()
  
   // Better to use continuous mode, smaller ring-buffer allocated by SDK. L.Claustre
   // excepted if the trigger mode is IntTrigMult (e.i Software)
-  if (m_trig_mode == Software)
+  if (m_trig_mode == IntTrigMult)
     {
       DEB_TRACE()<< "Software trigger ON, set CycleMode to Fixed mode";
       AT_64  nb_frames = static_cast<AT_64>(m_nb_frames_to_collect);
@@ -498,7 +509,7 @@ lima::Andor3::Camera::startAcq()
     sendCommand(andor3::AcquisitionStart);
   }
   
-  if ( Software == m_trig_mode ) {
+  if ( IntTrigMult == m_trig_mode ) {
     // If we are in software trigger mode, the call to startAcq serves as the trigger :
     sendCommand(andor3::SoftwareTrigger);
   }
@@ -614,86 +625,97 @@ lima::Andor3::Camera::getBufferCtrlObj()
 }
 
 //-- Synch control object
+
+void
+lima::Andor3::Camera::initTrigMode()
+{
+  DEB_MEMBER_FUNCT();
+  AT_BOOL	b_value;
+  int		enum_count;
+  AT_WC		s_value[1024];
+  std::string   s_mode;
+
+  AT_GetEnumCount(m_camera_handle, andor3::TriggerMode, &enum_count);
+
+  for (int idx=0; enum_count != idx; ++idx) {
+    AT_GetEnumStringByIndex(m_camera_handle, andor3::TriggerMode, idx, s_value, 1024);
+    AT_IsEnumIndexImplemented(m_camera_handle, andor3::TriggerMode, idx, &b_value);
+    if (b_value) {
+      s_mode = WStringToString(s_value);
+      if ( s_mode == "Internal" ) {
+        m_trig_mode_map.emplace(IntTrig, idx);
+        DEB_TRACE() << "Found IntTrig mode" ;
+      } else if ( s_mode == "Software" ) {
+        m_trig_mode_map.emplace(IntTrigMult, idx);
+        DEB_TRACE() << "Found IntTrigMult mode" ;
+      } else if ( s_mode == "External" ) {
+        m_trig_mode_map.emplace(ExtTrigMult, idx);
+        DEB_TRACE() << "Found ExtTrigMult mode" ;
+      } else if ( s_mode == "External Start" ) {
+        m_trig_mode_map.emplace(ExtTrigSingle, idx);
+        DEB_TRACE() << "Found ExtTrigSingle mode" ;
+      } else if ( s_mode == "External Exposure" ) {
+        m_trig_mode_map.emplace(ExtGate, idx);
+        DEB_TRACE() << "Found ExtGate mode" ;
+      }
+    }
+  }
+}
+     
 bool
 lima::Andor3::Camera::checkTrigMode(TrigMode mode)
 {
-  switch (mode) {
-    case IntTrig:
-    case IntTrigMult:
-    case ExtTrigSingle:
-    case ExtTrigMult:
-    case ExtGate:
-      return true;
-      break;
-      
-    default:
-      return false;
-      break;
-  }
+  std::map<TrigMode,int>::iterator it;
+
+  it = m_trig_mode_map.find(mode);
+  if (it != m_trig_mode_map.end())
+    return true;
+  else
+    return false;
 }
 
 void
-lima::Andor3::Camera::setTrigMode(TrigMode  mode)
+lima::Andor3::Camera::setTrigMode(TrigMode mode)
 {
   DEB_MEMBER_FUNCT();
-  A3_TriggerMode		the_trigger_mode;
-  switch (mode) {
-    case 	IntTrig:
-      the_trigger_mode = Internal;
-      break;
-    case IntTrigMult:
-      the_trigger_mode = Software;
-      break;
-    case ExtTrigSingle:
-      the_trigger_mode = ExternalStart;
-      break;
-    case ExtTrigMult:
-      the_trigger_mode = External;
-      break;
-    case ExtGate:
-      the_trigger_mode = ExternalExposure;
-      break;
-      
-    case ExtStartStop:
-    case ExtTrigReadout:
-    default:
-      the_trigger_mode = Internal;
-      THROW_HW_ERROR(Error) << "The triggering mode " << mode
-      << " is NOT implemented in this SDK";
-      break;
+  std::map<TrigMode,int>::iterator it;
+  int i_setmode, i_getmode;
+
+  if (m_real_camera) {
+    it = m_trig_mode_map.find(mode);
+    if (it == m_trig_mode_map.end())
+        THROW_HW_ERROR(Error) << "The triggering mode " << mode
+        << " is NOT implemented in this SDK";
+
+    i_setmode = it->second;
+    setEnumIndex(andor3::TriggerMode, i_setmode);
+
+    getEnumIndex(andor3::TriggerMode, &i_getmode);
+    if ( i_setmode != i_getmode ) {
+        DEB_ERROR() << "Proof-reading the trigger mode :"
+        << "\n\tGot " << i_getmode << ", while requesting " << i_setmode;
+        for (it=m_trig_mode_map.begin(); it!=m_trig_mode_map.end(); ++it) {
+          if (i_getmode == it->second) {
+            m_trig_mode = it->first;
+          }
+        }
+    } else {
+        m_trig_mode = mode;
+    }
   }
-  setTriggerMode(the_trigger_mode);
+  else {
+    setEnumString(andor3::TriggerMode, L"Advanced");
+    DEB_TRACE() << "SIMCAM - forcing trigger mode to Advanced";
+    m_trig_mode = mode;
+  }
+  DEB_TRACE() << "Trigger Mode is now : " << m_trig_mode;
 }
-
+  
 void
 lima::Andor3::Camera::getTrigMode(TrigMode& mode)
 {
   DEB_MEMBER_FUNCT();
-  A3_TriggerMode		the_trigger_mode;
-  getTriggerMode(the_trigger_mode);
-  
-  switch (the_trigger_mode) {
-    case Internal:
-      mode = IntTrig;
-      break;
-    case Software:
-      mode = IntTrigMult;
-      break;
-    case ExternalStart:
-      mode = ExtTrigSingle;
-      break;
-    case External:
-      mode = ExtTrigMult;
-      break;
-    case ExternalExposure:
-      mode = ExtGate;
-      break;
-    default:
-      mode = IntTrig;
-      THROW_HW_ERROR(Error) << "The triggering mode of the SDK " << the_trigger_mode
-      << " does not correspond to any mode of LIMA, returning " << mode;
-      break;
-  }
+  mode = m_trig_mode;
 }
 
 void
@@ -825,7 +847,7 @@ lima::Andor3::Camera::checkRoi(const Roi& set_roi, Roi& hw_roi)
       {2592,  304,  929,    1,    1, 1297, 1297},
       { 240,  256,  953, 1169, 1177, 1289, 1297},
       { 144,  128, 1017, 1217, 1225, 1289, 1297},
-      NULL
+    //  NULL
     };
     
     // Trying to take the smallest enclosing possible ROI (depending on the bit-depth of the image) :
@@ -1116,7 +1138,8 @@ void
 lima::Andor3::Camera::getPixelSize(double& sizex, double& sizey)
 {
   DEB_MEMBER_FUNCT();
-  sizex = sizey = 6.5; // in micron ?
+  getFloat(andor3::PixelWidth, &sizex);
+  getFloat(andor3::PixelHeight, &sizey);
 }
 
 void
@@ -1127,7 +1150,7 @@ lima::Andor3::Camera::getStatus(Camera::Status& status)
   status = m_status;
   //Check if the camera is not waiting for soft. trigger
   if (status == Camera::Readout && 
-      m_trig_mode == Software)
+      m_trig_mode == IntTrigMult)
     {
       status = Camera::Ready;
     }
@@ -1161,7 +1184,7 @@ lima::Andor3::Camera::initialiseController()
   
   // Carefully crafting the order, since some are affecting others...
   setElectronicShutterMode(m_electronic_shutter_mode);
-  setTriggerMode(m_trig_mode);
+  setTrigMode(m_trig_mode);
   setSimpleGain(the_simple_gain);
   setAdcRate(the_rate);
   setBitDepth(the_bd);
@@ -1393,52 +1416,19 @@ lima::Andor3::Camera::getPxEncoding(A3_PixelEncoding &oPxEncoding) const
   oPxEncoding = static_cast<A3_PixelEncoding>(oPxEncoding);
 }
 
-
-/*!
- @brief Setting the trigger mode of the camera through the SDK settings.
- @param iMode : the mode to select
- */
-void
-lima::Andor3::Camera::setTriggerMode(A3_TriggerMode iMode)
-{
-  DEB_MEMBER_FUNCT();
-  if ( m_real_camera ) {
-    int the_mode;
-    setEnumIndex(andor3::TriggerMode, static_cast<int>(iMode));
-    getEnumIndex(andor3::TriggerMode, &the_mode);
-    m_trig_mode = static_cast<A3_TriggerMode>(the_mode);
-    if ( m_trig_mode != iMode ) {
-      DEB_ERROR() << "Proof-reading the trigger mode :"
-      << "\n\tGot " << m_trig_mode << " back,"
-      << "\n\twhile requesting " << iMode;
-    }
-  }
-  else { // Simulated camera -> setting it forcibly to «Advanced»
-    int the_mode;
-    setEnumIndex(andor3::TriggerMode, 5);
-    getEnumIndex(andor3::TriggerMode, &the_mode);
-    m_trig_mode = static_cast<A3_TriggerMode>(the_mode);
-    DEB_TRACE() << "The SIMCAM has only one trigger-mode setting (Advanced), making sure that's what we are doing now";
-  }
-}
-
-/*!
- @brief Getting the triggering mode the camera is in
- @param oMode : the mode selected upon return
- */
-void
-lima::Andor3::Camera::getTriggerMode(A3_TriggerMode &oMode) const
-{
-  DEB_MEMBER_FUNCT();
-  oMode = m_trig_mode;
-}
-
 void
 lima::Andor3::Camera::getTriggerModeString(std::string &oModeString) const
 {
   AT_WC		the_string[256];
-  getEnumStringByIndex(andor3::TriggerMode, m_trig_mode, the_string, 255);
-  oModeString = WStringToString(std::wstring(the_string));
+  int		i_trig;
+  if (m_real_camera) {
+    i_trig = m_trig_mode_map.at(m_trig_mode);
+    getEnumStringByIndex(andor3::TriggerMode, m_trig_mode, the_string, 255);
+    oModeString = WStringToString(std::wstring(the_string));
+  }
+  else {
+    oModeString = "Advanced";
+  }
 }
 
 
@@ -2033,41 +2023,41 @@ lima::Andor3::Camera::printInfoForProp(const AT_WC * iPropName, A3_TypeInfo iPro
   AT_BOOL b_writable;
   AT_BOOL b_readable;
   
-  DEB_TRACE() << "Retrieving information on property named \"" << WStringToString(iPropName) << "\".\n";
+  DEB_ALWAYS() << "Retrieving information on property named \"" << WStringToString(iPropName) << "\".\n";
   
   int ret_code;
   // Implemented
   if ( AT_SUCCESS != (ret_code = AT_IsImplemented(m_camera_handle, iPropName, &b_exists)) ) {
-    DEB_TRACE() << "Error in printInfoForProp : " << error_code(ret_code);
+    DEB_ALWAYS() << "Error in printInfoForProp : " << error_code(ret_code);
     return i_err;
   }
-  DEB_TRACE() << "\tIsImplemented = " << atBoolToString(b_exists);
+  DEB_ALWAYS() << "\tIsImplemented = " << atBoolToString(b_exists);
   
   if ( ! b_exists ) {
-    DEB_TRACE() << "No more information to query, since the feature does not \"exists\" for this camera/driver/SDK.";
+    DEB_ALWAYS() << "No more information to query, since the feature does not \"exists\" for this camera/driver/SDK.";
     return i_err;
   }
   
   // ReadOnly
   AT_IsReadOnly(m_camera_handle, iPropName, &b_readonly);
-  DEB_TRACE() << "\tIsReadOnly = " << atBoolToString(b_readonly);
+  DEB_ALWAYS() << "\tIsReadOnly = " << atBoolToString(b_readonly);
   
   // Writable
   AT_IsWritable(m_camera_handle, iPropName, &b_writable);
-  DEB_TRACE() << "\tIsWritable = " << atBoolToString(b_writable);
+  DEB_ALWAYS() << "\tIsWritable = " << atBoolToString(b_writable);
   
   // Readable
   AT_IsReadable(m_camera_handle, iPropName, &b_readable);
-  DEB_TRACE() << "\tIsReadable = " << atBoolToString(b_readable);
+  DEB_ALWAYS() << "\tIsReadable = " << atBoolToString(b_readable);
   
   if ( ! b_readable ) {
-    DEB_TRACE() << "Since the property is not readable at this time, we will stop here.";
+    DEB_ALWAYS() << "Since the property is not readable at this time, we will stop here.";
     return i_err;
   }
   
   // Now getting the value itself : we absolutely need now to know the type of the feature :
   if ( Camera::Unknown == iPropType ) {
-    DEB_TRACE() << "Could not retrieve information on a property of unknown type !!\n"
+    DEB_ALWAYS() << "Could not retrieve information on a property of unknown type !!\n"
     << "Returning error code!!";
     return -1;
   }
@@ -2125,47 +2115,47 @@ lima::Andor3::Camera::printInfoForProp(const AT_WC * iPropName, A3_TypeInfo iPro
       break;
       
     case Camera::Enum:
-      DEB_TRACE() << "\tFeature of type ENUM";
+      DEB_ALWAYS() << "\tFeature of type ENUM";
       if ( AT_SUCCESS == (ret_code = AT_GetEnumIndex(m_camera_handle, iPropName, &enum_Value)) ) {
-        DEB_TRACE() << "\tValue = (" << enum_Value << ")";
+        DEB_ALWAYS() << "\tValue = (" << enum_Value << ")";
         if ( AT_SUCCESS == (ret_code = AT_GetEnumStringByIndex(m_camera_handle, iPropName, enum_Value, s_Value, 1024)) )
-          DEB_TRACE() << " \"" << WStringToString(s_Value) << "\"";
+          DEB_ALWAYS() << " \"" << WStringToString(s_Value) << "\"";
         else
-          DEB_TRACE() << "\tError message : " << error_code(ret_code);
+          DEB_ALWAYS() << "\tError message : " << error_code(ret_code);
         if ( AT_SUCCESS == (ret_code = AT_IsEnumIndexImplemented(m_camera_handle, iPropName, enum_Value, &b_Value)) )
-          DEB_TRACE() << "; implemented = " << atBoolToString(b_Value);
+          DEB_ALWAYS() << "; implemented = " << atBoolToString(b_Value);
         else
-          DEB_TRACE() << "\tError message : " << error_code(ret_code);
+          DEB_ALWAYS() << "\tError message : " << error_code(ret_code);
         if ( AT_SUCCESS == (ret_code = AT_IsEnumIndexAvailable(m_camera_handle, iPropName, enum_Value, &b_Value)) )
-          DEB_TRACE() << "; available = " << atBoolToString(b_Value);
+          DEB_ALWAYS() << "; available = " << atBoolToString(b_Value);
         else
-          DEB_TRACE() << "\tError message : " << error_code(ret_code);
-        DEB_TRACE() << ".";
+          DEB_ALWAYS() << "\tError message : " << error_code(ret_code);
+        DEB_ALWAYS() << ".";
       }
       else
-        DEB_TRACE() << "\tError message : " << error_code(ret_code);
+        DEB_ALWAYS() << "\tError message : " << error_code(ret_code);
       
       if ( AT_SUCCESS == (ret_code = AT_GetEnumCount(m_camera_handle, iPropName, &enum_Count)) ) {
-        DEB_TRACE() << "\tAvailable choices are (" << enum_Count << ") :";
+        DEB_ALWAYS() << "\tAvailable choices are (" << enum_Count << ") :";
         for ( int i=0; enum_Count != i; ++i ) {
-          DEB_TRACE() << "\t\t(" << i << ")";
+          DEB_ALWAYS() << "\t\t(" << i << ")";
           if ( AT_SUCCESS == (ret_code = AT_GetEnumStringByIndex(m_camera_handle, iPropName, i, s_Value, 1024)) )
-            DEB_TRACE() << " \"" << WStringToString(s_Value) << "\"";
+            DEB_ALWAYS() << " \"" << WStringToString(s_Value) << "\"";
           else
-            DEB_TRACE() << "\tError message : " << error_code(ret_code);
+            DEB_ALWAYS() << "\tError message : " << error_code(ret_code);
           if ( AT_SUCCESS == (ret_code = AT_IsEnumIndexImplemented(m_camera_handle, iPropName, i, &b_Value)) )
-            DEB_TRACE() << "; implemented = " << atBoolToString(b_Value);
+            DEB_ALWAYS() << "; implemented = " << atBoolToString(b_Value);
           else
-            DEB_TRACE() << "\tError message : " << error_code(ret_code);
+            DEB_ALWAYS() << "\tError message : " << error_code(ret_code);
           if ( AT_SUCCESS == (ret_code = AT_IsEnumIndexAvailable(m_camera_handle, iPropName, i, &b_Value)) )
-            DEB_TRACE() << "; available = " << atBoolToString(b_Value);
+            DEB_ALWAYS() << "; available = " << atBoolToString(b_Value);
           else
-            DEB_TRACE() << "\tError message : " << error_code(ret_code);
-          DEB_TRACE() << ".";
+            DEB_ALWAYS() << "\tError message : " << error_code(ret_code);
+          DEB_ALWAYS() << ".";
         }
       }
       else
-        DEB_TRACE() << "\tError message : " << error_code(ret_code);
+        DEB_ALWAYS() << "\tError message : " << error_code(ret_code);
       
       break;
       
diff --git a/tango/Andor3.py b/tango/Andor3.py
index 7c3f901..7812858 100644
--- a/tango/Andor3.py
+++ b/tango/Andor3.py
@@ -105,6 +105,7 @@ class Andor3(PyTango.Device_4Impl):
                                          'readout_time': 'ReadoutTime',
                                          'overlap': 'Overlap',
                                          'spurious_noise_filter': 'SpuriousNoiseFilter',
+                                         'serial_number': 'SerialNumber',
                                          }
         self.init_device()
                                                
@@ -344,6 +345,16 @@ class Andor3Class(PyTango.DeviceClass):
              'format': '',
              'description': 'OFF or ON',
              }],
+        'serial_number':
+        [[PyTango.DevString,
+          PyTango.SCALAR,
+          PyTango.READ],
+         {
+             'label':'Read camera serial number',
+             'unit': 'N/A',
+             'format': '',
+             'description': 'camera serial number',
+             }],
         }
 
 #------------------------------------------------------------------
-- 
GitLab


From 7c89bd33b4d5492a82fe805cc10d4b0a21e3a1b7 Mon Sep 17 00:00:00 2001
From: Emmanuel Papillon <papillon@esrf.fr>
Date: Thu, 9 Apr 2020 13:49:00 +0200
Subject: [PATCH 02/24] added gate and trigger level (normal or inverted)

---
 include/Andor3Camera.h | 13 ++++++---
 sip/Andor3Camera.sip   |  6 ++++
 src/Andor3Camera.cpp   | 66 +++++++++++++++++++++++++++++++++++++++---
 tango/Andor3.py        | 29 +++++++++++++++++++
 4 files changed, 106 insertions(+), 8 deletions(-)

diff --git a/include/Andor3Camera.h b/include/Andor3Camera.h
index 8e44939..2b412b5 100644
--- a/include/Andor3Camera.h
+++ b/include/Andor3Camera.h
@@ -69,14 +69,16 @@ namespace lima
       enum A3_ReadOutRate { MHz10 = 0, MHz100 = 1, MHz200 = 2, MHz280 = 3 };
       // In the same order/index as 'BitDepth'
       enum A3_BitDepth { b11 = 0, b16= 1 };
-      // The camera trigger mode (in the enum order) :
-//      enum A3_TriggerMode { Internal = 0, ExternalLevelTransition = 1, ExternalStart = 2, ExternalExposure = 3, Software = 4, Advanced = 5, External = 6 };
+      // Gain Mode for Marana detector
+      enum A3_GainMode { FastFrameRate=0, HighDynamicRange=1 };
 
       // The binning system of andor3 :
       enum A3_Binning { B1x1=0, B2x2=1, B3x3=2, B4x4=3, B8x8=4};
       // The fan speed
       enum A3_FanSpeed { Off=0, Low=1, On=2};
       enum A3_PixelEncoding {Mono12=0, Mono12Packed = 1, Mono16=2, Mono32=3};
+
+      enum A3_SignalLevel { Normal=0, Inverted=1};
       
       struct SdkFrameDim {       
 	AT_64 width;
@@ -157,6 +159,11 @@ namespace lima
       void getAdcGain(A3_Gain &oGain) const;
       void getAdcGainString(std::string &oGainString) const;
 
+      void setGateLevel(A3_SignalLevel iLevel);
+      void getGateLevel(A3_SignalLevel &iLevel);
+      void setTriggerLevel(A3_SignalLevel iLevel);
+      void getTriggerLevel(A3_SignalLevel &iLevel);
+
       void setAdcRate(A3_ReadOutRate iRate);  // à exporter (avec le get)
       void getAdcRate(A3_ReadOutRate &oRate) const;
       void getAdcRateString(std::string &oRateString) const;
@@ -168,8 +175,6 @@ namespace lima
       void getBitDepthString(std::string &oDepthString) const;
       void getPxEncoding(A3_PixelEncoding &oPxEncoding) const;
       void getPxEncodingString(std::string &oPxEncoding) const;
-      // void setTriggerMode(A3_TriggerMode iMode);
-      // void getTriggerMode(A3_TriggerMode &oMode) const;
       void getTriggerModeString(std::string &oModeString) const;
       void setTemperatureSP(double temp);  // à exporter (avec le get)
       void getTemperatureSP(double& temp) const;
diff --git a/sip/Andor3Camera.sip b/sip/Andor3Camera.sip
index 3b4312a..09b0436 100644
--- a/sip/Andor3Camera.sip
+++ b/sip/Andor3Camera.sip
@@ -40,6 +40,7 @@ namespace Andor3
     enum A3_Binning { B1x1=0, B2x2=1, B3x3=2, B4x4=3, B8x8=4};
     enum A3_FanSpeed { Off=0, Low=1, On=2};
     enum A3_PixelEncoding {Mono12=0, Mono12Packed = 1, Mono16=2, Mono32=3};
+    enum A3_SignalLevel {Normal=0, Inverted=1};
 
     Camera(const std::string& bitflow_path, int camera_number=0);
     ~Camera();
@@ -94,6 +95,11 @@ namespace Andor3
 // -- andor3 specific, LIMA don't worry about it !
    void initialiseController();
 
+   void setGateLevel(A3_SignalLevel iLevel /In/ );
+   void getGateLevel(A3_SignalLevel &iLevel /Out/ );
+   void setTriggerLevel(A3_SignalLevel iLevel /In/ );
+   void getTriggerLevel(A3_SignalLevel &iLevel /Out/ );
+
    void setAdcGain(A3_Gain iGain /In/ );
    void getAdcGain(A3_Gain &oGain /Out/ ) const;
    void getAdcGainString(std::string &oGainString /Out/ ) const;
diff --git a/src/Andor3Camera.cpp b/src/Andor3Camera.cpp
index 33273c0..1157325 100644
--- a/src/Andor3Camera.cpp
+++ b/src/Andor3Camera.cpp
@@ -92,6 +92,9 @@ namespace lima {
     static const AT_WC* TriggerMode = L"TriggerMode";
     static const AT_WC* FrameCount = L"FrameCount";
 
+    static const AT_WC* IOSelector = L"IOSelector";
+    static const AT_WC* IOInvert = L"IOInvert";
+
     // For future !!
     //    static const AT_WC* AccumulateCount = L"AccumulateCount";
     //    static const AT_WC* BaselineLevel = L"BaselineLevel";
@@ -299,9 +302,13 @@ m_maximage_size_cb_active(false)
   // --- init trigger modes
   initTrigMode();
 
-  // printInfoForProp(andor3::ElectronicShutteringMode, Enum);
-  // printInfoForProp(andor3::PixelReadoutRate, Enum);
-  // printInfoForProp(andor3::PixelEncoding, Enum);
+// --- to investiagte cam features
+//  printInfoForProp(andor3::ElectronicShutteringMode, Enum);
+//  printInfoForProp(andor3::PixelReadoutRate, Enum);
+//  printInfoForProp(andor3::PixelEncoding, Enum);
+//  printInfoForProp(andor3::SimplePreAmpGainControl, Enum);
+//  printInfoForProp(andor3::FanSpeed, Enum);
+//  printInfoForProp(andor3::BitDepth, Enum);
 
   // --- Initialise deeper parameters of the controller
   initialiseController();
@@ -1431,6 +1438,53 @@ lima::Andor3::Camera::getTriggerModeString(std::string &oModeString) const
   }
 }
 
+void
+lima::Andor3::Camera::setGateLevel(A3_SignalLevel iLevel)
+{
+  DEB_MEMBER_FUNCT();
+  bool flag;
+  if (iLevel == Inverted) flag= true;
+  else flag= false;
+  setEnumString(andor3::IOSelector, L"External Exposure");
+  setBool(andor3::IOInvert, flag);
+}
+
+void
+lima::Andor3::Camera::getGateLevel(A3_SignalLevel &iLevel)
+{
+  DEB_MEMBER_FUNCT();
+  bool flag;
+  setEnumString(andor3::IOSelector, L"External Exposure");
+  getBool(andor3::IOInvert, &flag);
+  if (flag)
+    iLevel = Inverted;
+  else
+    iLevel = Normal;
+}
+
+void
+lima::Andor3::Camera::setTriggerLevel(A3_SignalLevel iLevel)
+{
+  DEB_MEMBER_FUNCT();
+  bool flag;
+  if (iLevel == Inverted) flag= true;
+  else flag= false;
+  setEnumString(andor3::IOSelector, L"External Trigger");
+  setBool(andor3::IOInvert, flag);
+}
+
+void
+lima::Andor3::Camera::getTriggerLevel(A3_SignalLevel &iLevel)
+{
+  DEB_MEMBER_FUNCT();
+  bool flag;
+  setEnumString(andor3::IOSelector, L"External Trigger");
+  getBool(andor3::IOInvert, &flag);
+  if (flag)
+    iLevel = Inverted;
+  else
+    iLevel = Normal;
+}
 
 //-----------------------------------------------------
 // @brief	set the temperature set-point // DONE
@@ -1620,7 +1674,11 @@ lima::Andor3::Camera::setSimpleGain(A3_SimpleGain i_gain)
 {
   DEB_MEMBER_FUNCT();
   if ( propImplemented(andor3::SimplePreAmpGainControl) ) {
-    setEnumIndex(andor3::SimplePreAmpGainControl, i_gain);
+    int the_err_code = setEnumIndex(andor3::SimplePreAmpGainControl, i_gain);
+    if ( AT_SUCCESS != the_err_code ) {
+      DEB_ERROR() << "Cannot set SimplePreAmpGainControl to " << i_gain
+                  << " - " << DEB_VAR1(error_code(the_err_code));
+    }
   }
   else {
     DEB_TRACE() << "SimplePreAmpGainControl not implemented, emulating it in software";
diff --git a/tango/Andor3.py b/tango/Andor3.py
index 7812858..e60c44a 100644
--- a/tango/Andor3.py
+++ b/tango/Andor3.py
@@ -92,6 +92,13 @@ class Andor3(PyTango.Device_4Impl):
                          'OFF': False}
         self.__SpuriousNoiseFilter = {'ON':  True,
                          'OFF': False}
+        self.__GateLevel = { 'NORMAL': _Andor3Camera.Normal,
+                             'INVERTED': _Andor3Camera.Inverted,
+                           }
+        self.__TriggerLevel = { 'NORMAL': _Andor3Camera.Normal,
+                                'INVERTED': _Andor3Camera.Inverted,
+                              }
+
         self.__Attribute2FunctionBase = {'adc_gain': 'SimpleGain',
                                          'adc_rate': 'AdcRate',
                                          'temperature': 'Temperature',
@@ -106,6 +113,8 @@ class Andor3(PyTango.Device_4Impl):
                                          'overlap': 'Overlap',
                                          'spurious_noise_filter': 'SpuriousNoiseFilter',
                                          'serial_number': 'SerialNumber',
+                                         'gate_level': 'GateLevel',
+                                         'trigger_level': 'TriggerLevel',
                                          }
         self.init_device()
                                                
@@ -355,6 +364,26 @@ class Andor3Class(PyTango.DeviceClass):
              'format': '',
              'description': 'camera serial number',
              }],
+        'trigger_level':
+        [[PyTango.DevString,
+          PyTango.SCALAR,
+          PyTango.READ_WRITE],
+         {
+             'label':'External trigger level',
+             'unit': 'N/A',
+             'format': '',
+             'description': 'NORMAl or INVERTED'
+             }],
+        'gate_level':
+        [[PyTango.DevString,
+          PyTango.SCALAR,
+          PyTango.READ_WRITE],
+         {
+             'label':'External gate level',
+             'unit': 'N/A',
+             'format': '',
+             'description': 'NORMAl or INVERTED'
+             }],
         }
 
 #------------------------------------------------------------------
-- 
GitLab


From ef7d8f141ec6b201821342a13e4d3c284cada275 Mon Sep 17 00:00:00 2001
From: Emmanuel Papillon <papillon@esrf.fr>
Date: Fri, 18 Sep 2020 17:14:12 +0200
Subject: [PATCH 03/24] added output signal selection

---
 include/Andor3Camera.h |  7 +++++++
 sip/Andor3Camera.sip   |  3 +++
 src/Andor3Camera.cpp   | 27 +++++++++++++++++++++++++++
 tango/Andor3.py        | 16 ++++++++++++++++
 4 files changed, 53 insertions(+)

diff --git a/include/Andor3Camera.h b/include/Andor3Camera.h
index 2b412b5..d6379cf 100644
--- a/include/Andor3Camera.h
+++ b/include/Andor3Camera.h
@@ -78,7 +78,11 @@ namespace lima
       enum A3_FanSpeed { Off=0, Low=1, On=2};
       enum A3_PixelEncoding {Mono12=0, Mono12Packed = 1, Mono16=2, Mono32=3};
 
+      // trigger / gate level
       enum A3_SignalLevel { Normal=0, Inverted=1};
+
+      // output signal
+      enum A3_OutputSignal { FireRow1=0, FireRowN=1, FireAll=2, FireAny=3 };
       
       struct SdkFrameDim {       
 	AT_64 width;
@@ -164,6 +168,9 @@ namespace lima
       void setTriggerLevel(A3_SignalLevel iLevel);
       void getTriggerLevel(A3_SignalLevel &iLevel);
 
+      void setOutputSignal(A3_OutputSignal iSignal);
+      void getOutputSignal(A3_OutputSignal &oSignal) const;
+
       void setAdcRate(A3_ReadOutRate iRate);  // à exporter (avec le get)
       void getAdcRate(A3_ReadOutRate &oRate) const;
       void getAdcRateString(std::string &oRateString) const;
diff --git a/sip/Andor3Camera.sip b/sip/Andor3Camera.sip
index 09b0436..5a120c4 100644
--- a/sip/Andor3Camera.sip
+++ b/sip/Andor3Camera.sip
@@ -41,6 +41,7 @@ namespace Andor3
     enum A3_FanSpeed { Off=0, Low=1, On=2};
     enum A3_PixelEncoding {Mono12=0, Mono12Packed = 1, Mono16=2, Mono32=3};
     enum A3_SignalLevel {Normal=0, Inverted=1};
+    enum A3_OutputSignal {FireRow1=0, FireRowN=1, FireAll=2, FireAny=3};
 
     Camera(const std::string& bitflow_path, int camera_number=0);
     ~Camera();
@@ -99,6 +100,8 @@ namespace Andor3
    void getGateLevel(A3_SignalLevel &iLevel /Out/ );
    void setTriggerLevel(A3_SignalLevel iLevel /In/ );
    void getTriggerLevel(A3_SignalLevel &iLevel /Out/ );
+   void setOutputSignal(A3_OutputSignal iSignal /In/ );
+   void getOutputSignal(A3_OutputSignal &oSignal /Out/ ) const;
 
    void setAdcGain(A3_Gain iGain /In/ );
    void getAdcGain(A3_Gain &oGain /Out/ ) const;
diff --git a/src/Andor3Camera.cpp b/src/Andor3Camera.cpp
index 1157325..ed03706 100644
--- a/src/Andor3Camera.cpp
+++ b/src/Andor3Camera.cpp
@@ -94,6 +94,7 @@ namespace lima {
 
     static const AT_WC* IOSelector = L"IOSelector";
     static const AT_WC* IOInvert = L"IOInvert";
+    static const AT_WC* AuxiliaryOutSource = L"AuxiliaryOutSource";
 
     // For future !!
     //    static const AT_WC* AccumulateCount = L"AccumulateCount";
@@ -1486,6 +1487,32 @@ lima::Andor3::Camera::getTriggerLevel(A3_SignalLevel &iLevel)
     iLevel = Normal;
 }
 
+void
+lima::Andor3::Camera::setOutputSignal(A3_OutputSignal iSignal)
+{
+  DEB_MEMBER_FUNCT();
+  if ( propImplemented(andor3::AuxiliaryOutSource) ) {
+    setEnumIndex(andor3::AuxiliaryOutSource, iSignal);
+  }
+  else {
+    DEB_TRACE() << "The camera has no fan speed setting... Do nothing !";
+  }
+}
+
+void
+lima::Andor3::Camera::getOutputSignal(A3_OutputSignal &oSignal) const
+{
+  DEB_MEMBER_FUNCT();
+  if ( propImplemented(andor3::AuxiliaryOutSource) ) {
+    int  value;
+    getEnumIndex(andor3::AuxiliaryOutSource, &value);
+    oSignal = static_cast<A3_OutputSignal>(value);
+  }
+  else {
+    DEB_TRACE() << "The camera has no fan speed setting... Do nothing !";
+  }  
+}
+
 //-----------------------------------------------------
 // @brief	set the temperature set-point // DONE
 // @param	temperature in centigrade
diff --git a/tango/Andor3.py b/tango/Andor3.py
index e60c44a..854ad6f 100644
--- a/tango/Andor3.py
+++ b/tango/Andor3.py
@@ -98,6 +98,11 @@ class Andor3(PyTango.Device_4Impl):
         self.__TriggerLevel = { 'NORMAL': _Andor3Camera.Normal,
                                 'INVERTED': _Andor3Camera.Inverted,
                               }
+        self.__OutputSignal = { 'FIREROW1': _Andor3Camera.FireRow1,
+                                'FIREROWN': _Andor3Camera.FireRowN,
+                                'FIREALL': _Andor3Camera.FireAll,
+                                'FIREANY': _Andor3Camera.FireAny,
+                              }
 
         self.__Attribute2FunctionBase = {'adc_gain': 'SimpleGain',
                                          'adc_rate': 'AdcRate',
@@ -115,6 +120,7 @@ class Andor3(PyTango.Device_4Impl):
                                          'serial_number': 'SerialNumber',
                                          'gate_level': 'GateLevel',
                                          'trigger_level': 'TriggerLevel',
+                                         'output_signal': 'OutputSignal',
                                          }
         self.init_device()
                                                
@@ -384,6 +390,16 @@ class Andor3Class(PyTango.DeviceClass):
              'format': '',
              'description': 'NORMAl or INVERTED'
              }],
+        'output_signal':
+        [[PyTango.DevString,
+          PyTango.SCALAR,
+          PyTango.READ_WRITE],
+         {
+             'label':'Output signal selection',
+             'unit': 'N/A',
+             'format': '',
+             'description': 'FireRow1, FireRowN, FireAny, FireAll',
+             }],
         }
 
 #------------------------------------------------------------------
-- 
GitLab


From b103df0db909658eecd56de096940df6e640fde2 Mon Sep 17 00:00:00 2001
From: Emmanuel Papillon <papillon@esrf.fr>
Date: Tue, 12 Jan 2021 15:16:22 +0100
Subject: [PATCH 04/24] update server properties

---
 tango/Andor3.py | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/tango/Andor3.py b/tango/Andor3.py
index 854ad6f..9895f22 100644
--- a/tango/Andor3.py
+++ b/tango/Andor3.py
@@ -143,16 +143,19 @@ class Andor3(PyTango.Device_4Impl):
 
         # Apply properties if any
         if self.adc_gain:
-            _Andor3Interface.setAdcGain(self.__AdcGain[self.adc_gain])
+            _Andor3Camera.setSimpleGain(self.__AdcGain[self.adc_gain])
             
         if self.adc_rate:
-            _Andor3Interface.setAdcRate(self.__AdcRate[self.adc_rate])
+            _Andor3Camera.setAdcRate(self.__AdcRate[self.adc_rate])
             
         if self.temperature_sp:            
             _Andor3Camera.setTemperatureSP(self.temperature_sp)
             
         if self.cooler:
             _Andor3Camera.setCooler(self.__Cooler[self.cooler])
+
+        if self.overlap:
+            _Andor3Camera.setOverlap(self.__Overlap[self.overlap])
             
 
 #==================================================================
@@ -217,6 +220,9 @@ class Andor3Class(PyTango.DeviceClass):
         'cooler':
         [PyTango.DevString,
          'Start or stop the cooler ("ON"/"OFF")', []],
+        'overlap':
+        [PyTango.DevString,
+         'Overlap mode', []],
         }
 
 
-- 
GitLab


From 6efb02281312b6c4eb7cf00ac8a42012acdd9683 Mon Sep 17 00:00:00 2001
From: Emmanuel Papillon <papillon@esrf.fr>
Date: Wed, 23 Mar 2022 14:07:01 +0100
Subject: [PATCH 05/24] Rework temperature control so it can work also for
 Marana detector. This detector has a predefined set of set-point values while
 other detector can set temperature to any value.

---
 include/Andor3Camera.h |   6 +-
 src/Andor3Camera.cpp   | 123 ++++++++++++++++++++++++++++-------------
 2 files changed, 90 insertions(+), 39 deletions(-)

diff --git a/include/Andor3Camera.h b/include/Andor3Camera.h
index d6379cf..cc1d0a5 100644
--- a/include/Andor3Camera.h
+++ b/include/Andor3Camera.h
@@ -28,6 +28,7 @@
 #include <stdlib.h>
 #include <limits>
 #include <ostream>
+#include <vector>
 
 // Camera SDK headers :
 #include <atcore.h>
@@ -234,6 +235,7 @@ namespace lima
       
     private:
       void initTrigMode();
+      void initTemperature();
 
       // -- andor3 Lower level functions
       int printInfoForProp(const AT_WC * iPropName, A3_TypeInfo iPropType) const;
@@ -311,7 +313,9 @@ namespace lima
       A3_BitDepth                 m_bit_depth;
       bool                        m_cooler;
       double                      m_temperature_sp;
-      bool                        m_temperature_control_available;
+      bool			  m_has_temperature_sp;
+      bool                        m_has_temperature_control;
+      std::vector<float>	  m_temperature_control_values;
 
       TrigMode                    m_trig_mode;
       // A3_TriggerMode		  m_trig_mode;
diff --git a/src/Andor3Camera.cpp b/src/Andor3Camera.cpp
index ed03706..4341b8a 100644
--- a/src/Andor3Camera.cpp
+++ b/src/Andor3Camera.cpp
@@ -115,7 +115,7 @@ namespace lima {
     //    static const AT_WC* RowNExposureEndEvent = L"RowNExposureEndEvent";
     //    static const AT_WC* RowNExposureStartEvent = L"RowNExposureStartEvent";
     //    static const AT_WC* SoftwareVersion = L"SoftwareVersion";
-    //    static const AT_WC* TemperatureControl = L"TemperatureControl";
+        static const AT_WC* TemperatureControl = L"TemperatureControl";
     //    static const AT_WC* TimestampClock = L"TimestampClock";
     //    static const AT_WC* TimestampClockFrequency = L"TimestampClockFrequency";
     //    static const AT_WC* TimestampClockReset = L"TimestampClockReset";
@@ -176,8 +176,9 @@ m_electronic_shutter_mode(Rolling),
 m_bit_depth(b16),
 m_trig_mode(IntTrig),
 m_cooler(true),
-m_temperature_sp(5.0),
-m_temperature_control_available(true),
+m_temperature_sp(999.99),
+m_has_temperature_sp(false),
+m_has_temperature_control(false),
 m_maximage_size_cb_active(false)
 {
   DEB_CONSTRUCTOR();
@@ -310,6 +311,8 @@ m_maximage_size_cb_active(false)
 //  printInfoForProp(andor3::SimplePreAmpGainControl, Enum);
 //  printInfoForProp(andor3::FanSpeed, Enum);
 //  printInfoForProp(andor3::BitDepth, Enum);
+//  printInfoForProp(andor3::TemperatureControl, Enum);
+//  printInfoForProp(andor3::AuxiliaryOutSource, Enum);
 
   // --- Initialise deeper parameters of the controller
   initialiseController();
@@ -326,7 +329,7 @@ lima::Andor3::Camera::~Camera()
   m_acq_thread = NULL;
  
   // Close camera
-  if (m_cooler && m_temperature_control_available) {
+  if (m_cooler && m_has_temperature_sp) {
     DEB_ERROR() <<"Please stop the cooling before shuting dowm the camera\n"
     << "brutale heating could damage the sensor.\n"
     << "And wait until temperature rises above 5 deg, before shuting down.";
@@ -1197,7 +1200,7 @@ lima::Andor3::Camera::initialiseController()
   setAdcRate(the_rate);
   setBitDepth(the_bd);
   setCooler(m_cooler);
-  setTemperatureSP(m_temperature_sp);
+  initTemperature();
   setExpTime(m_exp_time);
   
   setSpuriousNoiseFilter(false);
@@ -1513,6 +1516,36 @@ lima::Andor3::Camera::getOutputSignal(A3_OutputSignal &oSignal) const
   }  
 }
 
+//-----------------------------------------------------
+// @brief	retrieve temperature capabilities
+//-----------------------------------------------------
+void
+lima::Andor3::Camera::initTemperature()
+{
+  DEB_MEMBER_FUNCT();
+  if ( propImplemented(andor3::TargetSensorTemperature) && m_detector_model.find("ZYLA5.5")==std::string::npos ) {
+    m_has_temperature_sp = true;
+    getFloat(andor3::TargetSensorTemperature, &m_temperature_sp);
+  } 
+  else if ( propImplemented(andor3::TemperatureControl) ) {
+    int ntemp, current_idx;
+    AT_WC at_string[256];
+    float value;
+
+    m_has_temperature_control = true;
+    DEB_ALWAYS() << "Camera has temperature setpoints pre-defined";
+    getEnumCount(m_camera_handle, andor3::TemperatureControl, &ntemp);
+    for (int idx=0; idx != ntemp; ++idx) {
+      AT_GetEnumStringByIndex(m_camera_handle, andor3::TemperatureControl, idx, at_string, 255);
+      value = std::stof(WStringToString(at_string));
+      m_temperature_control_values.push_back(value);
+      DEB_ALWAYS() << "Index " << idx << " Setpoint " << value;
+    }
+    getEnumIndex(andor3::TemperatureControl, &current_idx);
+    m_temperature_sp = m_temperature_control_values[current_idx];
+  }
+}
+  
 //-----------------------------------------------------
 // @brief	set the temperature set-point // DONE
 // @param	temperature in centigrade
@@ -1522,8 +1555,8 @@ void
 lima::Andor3::Camera::setTemperatureSP(double temp)
 {
   DEB_MEMBER_FUNCT();
-  // Zyla-5.5 camera is supposed to not have this feature, but propImplemented returned True !!!
-  if ( propImplemented(andor3::TargetSensorTemperature) && m_detector_model.find("ZYLA5.5")==std::string::npos ) {
+
+  if (m_has_temperature_sp) {
     setFloat(andor3::TargetSensorTemperature, temp);
     getFloat(andor3::TargetSensorTemperature, &m_temperature_sp);
     if ( abs(m_temperature_sp - temp) > 0.1) {
@@ -1533,9 +1566,23 @@ lima::Andor3::Camera::setTemperatureSP(double temp)
       THROW_HW_ERROR(Error) << "Failed on setting temperature set-point";
     }
   }
+  else if (m_has_temperature_control) {
+    float temp_idx = 0;
+    int size = m_temperature_control_values.size();
+    int current_idx;
+    for (int idx=size-1; idx>= 0; --idx) {
+      if (temp <= m_temperature_control_values[idx]) {
+         temp_idx = idx;
+         break;
+      }
+    }
+    setEnumIndex(andor3::TemperatureControl, temp_idx);
+    getEnumIndex(andor3::TemperatureControl, &current_idx);
+    m_temperature_sp = m_temperature_control_values[current_idx];
+  }
   else {
-    DEB_ALWAYS() << "This camera has no temperature set-point control !";
-    m_temperature_control_available = false;
+    DEB_ERROR() << "Camera has no temperature set-point control";
+    THROW_HW_ERROR(Error) << "Camera has no temperature set-point control";
   }
 }
 
@@ -2108,41 +2155,41 @@ lima::Andor3::Camera::printInfoForProp(const AT_WC * iPropName, A3_TypeInfo iPro
   AT_BOOL b_writable;
   AT_BOOL b_readable;
   
-  DEB_ALWAYS() << "Retrieving information on property named \"" << WStringToString(iPropName) << "\".\n";
+  std::cout << "\nRetrieving information on property named \"" << WStringToString(iPropName) << "\".\n";
   
   int ret_code;
   // Implemented
   if ( AT_SUCCESS != (ret_code = AT_IsImplemented(m_camera_handle, iPropName, &b_exists)) ) {
-    DEB_ALWAYS() << "Error in printInfoForProp : " << error_code(ret_code);
+    std::cout << "Error in printInfoForProp : " << error_code(ret_code);
     return i_err;
   }
-  DEB_ALWAYS() << "\tIsImplemented = " << atBoolToString(b_exists);
+  std::cout << "\tIsImplemented = " << atBoolToString(b_exists);
   
   if ( ! b_exists ) {
-    DEB_ALWAYS() << "No more information to query, since the feature does not \"exists\" for this camera/driver/SDK.";
+    std::cout << "No more information to query, since the feature does not \"exists\" for this camera/driver/SDK.";
     return i_err;
   }
   
   // ReadOnly
   AT_IsReadOnly(m_camera_handle, iPropName, &b_readonly);
-  DEB_ALWAYS() << "\tIsReadOnly = " << atBoolToString(b_readonly);
+  std::cout << "\tIsReadOnly = " << atBoolToString(b_readonly);
   
   // Writable
   AT_IsWritable(m_camera_handle, iPropName, &b_writable);
-  DEB_ALWAYS() << "\tIsWritable = " << atBoolToString(b_writable);
+  std::cout << "\tIsWritable = " << atBoolToString(b_writable);
   
   // Readable
   AT_IsReadable(m_camera_handle, iPropName, &b_readable);
-  DEB_ALWAYS() << "\tIsReadable = " << atBoolToString(b_readable);
+  std::cout << "\tIsReadable = " << atBoolToString(b_readable);
   
   if ( ! b_readable ) {
-    DEB_ALWAYS() << "Since the property is not readable at this time, we will stop here.";
+    std::cout << "Since the property is not readable at this time, we will stop here.";
     return i_err;
   }
   
   // Now getting the value itself : we absolutely need now to know the type of the feature :
   if ( Camera::Unknown == iPropType ) {
-    DEB_ALWAYS() << "Could not retrieve information on a property of unknown type !!\n"
+    std::cout << "Could not retrieve information on a property of unknown type !!\n"
     << "Returning error code!!";
     return -1;
   }
@@ -2200,47 +2247,47 @@ lima::Andor3::Camera::printInfoForProp(const AT_WC * iPropName, A3_TypeInfo iPro
       break;
       
     case Camera::Enum:
-      DEB_ALWAYS() << "\tFeature of type ENUM";
+      std::cout << "\n\tFeature of type ENUM";
       if ( AT_SUCCESS == (ret_code = AT_GetEnumIndex(m_camera_handle, iPropName, &enum_Value)) ) {
-        DEB_ALWAYS() << "\tValue = (" << enum_Value << ")";
+        std::cout << "\n\tValue = (" << enum_Value << ")";
         if ( AT_SUCCESS == (ret_code = AT_GetEnumStringByIndex(m_camera_handle, iPropName, enum_Value, s_Value, 1024)) )
-          DEB_ALWAYS() << " \"" << WStringToString(s_Value) << "\"";
+          std::cout << " \"" << WStringToString(s_Value) << "\"";
         else
-          DEB_ALWAYS() << "\tError message : " << error_code(ret_code);
+          std::cout << "\tError message : " << error_code(ret_code);
         if ( AT_SUCCESS == (ret_code = AT_IsEnumIndexImplemented(m_camera_handle, iPropName, enum_Value, &b_Value)) )
-          DEB_ALWAYS() << "; implemented = " << atBoolToString(b_Value);
+          std::cout << "; implemented = " << atBoolToString(b_Value);
         else
-          DEB_ALWAYS() << "\tError message : " << error_code(ret_code);
+          std::cout << "\tError message : " << error_code(ret_code);
         if ( AT_SUCCESS == (ret_code = AT_IsEnumIndexAvailable(m_camera_handle, iPropName, enum_Value, &b_Value)) )
-          DEB_ALWAYS() << "; available = " << atBoolToString(b_Value);
+          std::cout << "; available = " << atBoolToString(b_Value);
         else
-          DEB_ALWAYS() << "\tError message : " << error_code(ret_code);
-        DEB_ALWAYS() << ".";
+          std::cout << "\tError message : " << error_code(ret_code);
+        std::cout << ".";
       }
       else
-        DEB_ALWAYS() << "\tError message : " << error_code(ret_code);
+        std::cout << "\tError message : " << error_code(ret_code);
       
       if ( AT_SUCCESS == (ret_code = AT_GetEnumCount(m_camera_handle, iPropName, &enum_Count)) ) {
-        DEB_ALWAYS() << "\tAvailable choices are (" << enum_Count << ") :";
+        std::cout << "\n\tAvailable choices are (" << enum_Count << ") :";
         for ( int i=0; enum_Count != i; ++i ) {
-          DEB_ALWAYS() << "\t\t(" << i << ")";
+          std::cout << "\n\t\t(" << i << ")";
           if ( AT_SUCCESS == (ret_code = AT_GetEnumStringByIndex(m_camera_handle, iPropName, i, s_Value, 1024)) )
-            DEB_ALWAYS() << " \"" << WStringToString(s_Value) << "\"";
+            std::cout << " \"" << WStringToString(s_Value) << "\"";
           else
-            DEB_ALWAYS() << "\tError message : " << error_code(ret_code);
+            std::cout << "\tError message : " << error_code(ret_code);
           if ( AT_SUCCESS == (ret_code = AT_IsEnumIndexImplemented(m_camera_handle, iPropName, i, &b_Value)) )
-            DEB_ALWAYS() << "; implemented = " << atBoolToString(b_Value);
+            std::cout << "; implemented = " << atBoolToString(b_Value);
           else
-            DEB_ALWAYS() << "\tError message : " << error_code(ret_code);
+            std::cout << "\tError message : " << error_code(ret_code);
           if ( AT_SUCCESS == (ret_code = AT_IsEnumIndexAvailable(m_camera_handle, iPropName, i, &b_Value)) )
-            DEB_ALWAYS() << "; available = " << atBoolToString(b_Value);
+            std::cout << "; available = " << atBoolToString(b_Value);
           else
-            DEB_ALWAYS() << "\tError message : " << error_code(ret_code);
-          DEB_ALWAYS() << ".";
+            std::cout << "\tError message : " << error_code(ret_code);
+          std::cout << ".";
         }
       }
       else
-        DEB_ALWAYS() << "\tError message : " << error_code(ret_code);
+        std::cout << "\tError message : " << error_code(ret_code);
       
       break;
       
-- 
GitLab


From 325f3bb1cdcb8bcfd4663703548087220147f8e4 Mon Sep 17 00:00:00 2001
From: Emmanuel Papillon <papillon@esrf.fr>
Date: Wed, 23 Mar 2022 16:08:04 +0100
Subject: [PATCH 06/24] Change fan speed set/get to work with strings. The list
 of possible values are camera-dependant and can be retrieved by
 getFanSpeedList. Removed the previous fixed enum.

---
 include/Andor3Camera.h | 10 +++++-----
 sip/Andor3Camera.sip   |  9 +++++----
 src/Andor3Camera.cpp   | 41 +++++++++++++++++++----------------------
 tango/Andor3.py        | 16 ++++++++++++----
 4 files changed, 41 insertions(+), 35 deletions(-)

diff --git a/include/Andor3Camera.h b/include/Andor3Camera.h
index cc1d0a5..7113e03 100644
--- a/include/Andor3Camera.h
+++ b/include/Andor3Camera.h
@@ -75,8 +75,6 @@ namespace lima
 
       // The binning system of andor3 :
       enum A3_Binning { B1x1=0, B2x2=1, B3x3=2, B4x4=3, B8x8=4};
-      // The fan speed
-      enum A3_FanSpeed { Off=0, Low=1, On=2};
       enum A3_PixelEncoding {Mono12=0, Mono12Packed = 1, Mono16=2, Mono32=3};
 
       // trigger / gate level
@@ -193,9 +191,11 @@ namespace lima
       
       void setBufferOverflow(bool i_overflow);
       void getBufferOverflow(bool &o_overflow) const;
-      void setFanSpeed(A3_FanSpeed iFS);
-      void getFanSpeed(A3_FanSpeed &oFS) const;
-      void getFanSpeedString(std::string &oFSString) const;
+
+      void setFanSpeed(std::string fan_speed);
+      void getFanSpeed(std::string &fan_speed) const;
+      void getFanSpeedList(std::vector<std::string> &fan_speed_list) const;
+
       void setOverlap(bool i_overlap);
       void getOverlap(bool &o_overlap) const;
       void setSimpleGain(A3_SimpleGain i_gain);
diff --git a/sip/Andor3Camera.sip b/sip/Andor3Camera.sip
index 5a120c4..97d8b5a 100644
--- a/sip/Andor3Camera.sip
+++ b/sip/Andor3Camera.sip
@@ -38,7 +38,6 @@ namespace Andor3
     enum A3_BitDepth { b11 = 0, b16= 1 };
 //    enum A3_TriggerMode { Internal = 0, ExternalLevelTransition = 1, ExternalStart = 2, ExternalExposure = 3, Software = 4, Advanced = 5, External = 6 };
     enum A3_Binning { B1x1=0, B2x2=1, B3x3=2, B4x4=3, B8x8=4};
-    enum A3_FanSpeed { Off=0, Low=1, On=2};
     enum A3_PixelEncoding {Mono12=0, Mono12Packed = 1, Mono16=2, Mono32=3};
     enum A3_SignalLevel {Normal=0, Inverted=1};
     enum A3_OutputSignal {FireRow1=0, FireRowN=1, FireAll=2, FireAny=3};
@@ -128,9 +127,11 @@ namespace Andor3
 
    void setBufferOverflow(bool i_overflow /In/ );
    void getBufferOverflow(bool &o_overflow /Out/ ) const;
-   void setFanSpeed(A3_FanSpeed iFS /In/ );
-   void getFanSpeed(A3_FanSpeed &oFS /Out/ ) const;
-   void getFanSpeedString(std::string &oFSString /Out/ ) const;
+
+   void setFanSpeed(std::string fan_speed /In/ );
+   void getFanSpeed(std::string &fan_speed /Out/ ) const;
+   void getFanSpeedList(std::vector<std::string> &fs_list /Out/ ) const;
+
    void setOverlap(bool i_overlap /In/ );
    void getOverlap(bool &o_overlap /Out/ ) const;
    void setSimpleGain(A3_SimpleGain i_gain /In/ );
diff --git a/src/Andor3Camera.cpp b/src/Andor3Camera.cpp
index 4341b8a..467dd17 100644
--- a/src/Andor3Camera.cpp
+++ b/src/Andor3Camera.cpp
@@ -107,8 +107,6 @@ namespace lima {
     //    static const AT_WC* MetadataFrame = L"MetadataFrame";
     //    static const AT_WC* MetadataTimestamp = L"MetadataTimestamp";
     //    static const AT_WC* PixelCorrection = L"PixelCorrection";
-    //    static const AT_WC* PixelHeight = L"PixelHeight";
-    //    static const AT_WC* PixelWidth = L"PixelWidth";
     //    static const AT_WC* PreAmpGain = L"PreAmpGain"; // Deprecated
     //    static const AT_WC* PreAmpGainChannel = L"PreAmpGainChannel"; // Deprecated
     //    static const AT_WC* PreAmpGainSelector = L"PreAmpGainSelector"; // Deprecated
@@ -1681,48 +1679,47 @@ lima::Andor3::Camera::getBufferOverflow(bool &o_overflow) const
 
 
 void
-lima::Andor3::Camera::setFanSpeed(A3_FanSpeed iFS)
+lima::Andor3::Camera::getFanSpeedList(std::vector<std::string> &fan_speed_list) const
 {
-  DEB_MEMBER_FUNCT();
-  if ( propImplemented(andor3::FanSpeed) ) {
-    setEnumIndex(andor3::FanSpeed, iFS);
-  }
-  else {
-    DEB_TRACE() << "The camera has no fan speed setting... Do nothing !";
+  int		enum_count;
+  AT_WC		s_value[1024];
+  
+  AT_GetEnumCount(m_camera_handle, andor3::FanSpeed, &enum_count);
+
+  for (int idx=0; enum_count != idx; ++idx) {
+    AT_GetEnumStringByIndex(m_camera_handle, andor3::FanSpeed, idx, s_value, 1024);
+    fan_speed_list.push_back(WStringToString(s_value));
   }
 }
 
 void
-lima::Andor3::Camera::getFanSpeed(A3_FanSpeed &oFS) const
+lima::Andor3::Camera::setFanSpeed(std::string fan_speed)
 {
   DEB_MEMBER_FUNCT();
   if ( propImplemented(andor3::FanSpeed) ) {
-    int  the_fs;
-    getEnumIndex(andor3::FanSpeed, &the_fs);
-    oFS = static_cast<A3_FanSpeed>(the_fs);
+    const std::wstring fan_set = StringToWString(fan_speed);
+    setEnumString(andor3::FanSpeed, fan_set.c_str());
   }
   else {
     DEB_TRACE() << "The camera has no fan speed setting... Do nothing !";
-  }  
+  }
 }
 
-
 void
-lima::Andor3::Camera::getFanSpeedString(std::string &oFSString) const
+lima::Andor3::Camera::getFanSpeed(std::string &fan_speed) const
 {
   DEB_MEMBER_FUNCT();
   if ( propImplemented(andor3::FanSpeed) ) {
-    AT_WC		the_string[256];
-    getEnumString(andor3::FanSpeed, the_string, 255);
-    oFSString = WStringToString(std::wstring(the_string));
+    AT_WC fan_string[256];
+    getEnumString(andor3::FanSpeed, fan_string, 255);
+    fan_speed = WStringToString(fan_string);
   }
   else {
     DEB_TRACE() << "The camera has no fan speed setting... Do nothing !";
-    oFSString = "not implemented";
-  }
+    fan_speed = "not implemented";
+  }  
 }
 
-
 void
 lima::Andor3::Camera::setOverlap(bool i_overlap)
 {
diff --git a/tango/Andor3.py b/tango/Andor3.py
index 9895f22..95b4ce5 100644
--- a/tango/Andor3.py
+++ b/tango/Andor3.py
@@ -48,6 +48,15 @@ from Lima import Andor3 as Andor3Module
 # and Lima interfaces.
 from Lima.Server import AttrHelper
 
+def andor_list2dict(alist):
+     adict = dict()
+     for name in alist:
+         newname = name.upper().strip()
+         newname = newname.replace("(", "").replace(")", "").replace("-", "_").replace(" ", "_")
+         adict[newname] = name
+     return adict
+
+         
 class Andor3(PyTango.Device_4Impl):
 
     Core.DEB_CLASS(Core.DebModApplication, 'LimaCCDs')
@@ -81,10 +90,6 @@ class Andor3(PyTango.Device_4Impl):
                           }
         self.__Cooler = {'ON':  True,
                          'OFF': False}
-        self.__FanSpeed = {'OFF':  _Andor3Camera.Off,
-                           'LOW':  _Andor3Camera.Low,
-                           'HIGH': _Andor3Camera.On,
-                           }
         self.__ElectronicShutterMode = {'ROLLING': _Andor3Camera.Rolling,
                                         'GLOBAL': _Andor3Camera.Global,
                                         }
@@ -103,6 +108,7 @@ class Andor3(PyTango.Device_4Impl):
                                 'FIREALL': _Andor3Camera.FireAll,
                                 'FIREANY': _Andor3Camera.FireAny,
                               }
+        self.__FanSpeed = andor_list2dict(_Andor3Camera.getFanSpeedList())
 
         self.__Attribute2FunctionBase = {'adc_gain': 'SimpleGain',
                                          'adc_rate': 'AdcRate',
@@ -122,6 +128,8 @@ class Andor3(PyTango.Device_4Impl):
                                          'trigger_level': 'TriggerLevel',
                                          'output_signal': 'OutputSignal',
                                          }
+
+
         self.init_device()
                                                
 #------------------------------------------------------------------
-- 
GitLab


From 2ab026faa89f1436d557e146cff60a4c4a78f0e2 Mon Sep 17 00:00:00 2001
From: Emmanuel Papillon <papillon@esrf.fr>
Date: Thu, 24 Mar 2022 11:00:28 +0100
Subject: [PATCH 07/24] Change private methods to use std::string instead of
 AT_WC* when setting/getting string andor parameters

---
 include/Andor3Camera.h |  13 ++--
 src/Andor3Camera.cpp   | 152 +++++++++++++++++++----------------------
 2 files changed, 78 insertions(+), 87 deletions(-)

diff --git a/include/Andor3Camera.h b/include/Andor3Camera.h
index 7113e03..31ed347 100644
--- a/include/Andor3Camera.h
+++ b/include/Andor3Camera.h
@@ -258,17 +258,18 @@ namespace lima
       int getBool(const AT_WC* Feature, bool* Value) const;
       
       int setEnumIndex(const AT_WC* Feature, int Value);
-      int setEnumString(const AT_WC* Feature, const AT_WC* String);
       int getEnumIndex(const AT_WC* Feature, int* Value) const;
-      int getEnumString(const AT_WC* Feature, AT_WC* String, int StringLength) const;
+      int setEnumString(const AT_WC* Feature, std::string Value);
+      int getEnumString(const AT_WC* Feature, std::string& Value) const;
       int getEnumCount(AT_H Hndl,const  AT_WC* Feature, int* Count) const;
       int isEnumIndexAvailable(const AT_WC* Feature, int Index, bool* Available) const;
       int isEnumIndexImplemented(const AT_WC* Feature, int Index, bool* Implemented) const;
-      int getEnumStringByIndex(const AT_WC* Feature, int Index, AT_WC* String, int StringLength) const;
-      int getEnumIndexByString(const AT_WC* Feature, AT_WC* String, int *Index) const;
+
+      int getEnumStringByIndex(const AT_WC* Feature, int Index, std::string& Value) const;
+      int getEnumIndexByString(const AT_WC* Feature, std::string Value, int *Index) const;
       
-      int setString(const AT_WC* Feature, const AT_WC* String);
-      int getString(const AT_WC* Feature, AT_WC* String, int StringLength) const;
+      int setString(const AT_WC* Feature, std::string Value);
+      int getString(const AT_WC* Feature, std::string& Value) const;
       
       int sendCommand(const AT_WC* Feature);
 
diff --git a/src/Andor3Camera.cpp b/src/Andor3Camera.cpp
index 467dd17..13096cc 100644
--- a/src/Andor3Camera.cpp
+++ b/src/Andor3Camera.cpp
@@ -233,12 +233,9 @@ m_maximage_size_cb_active(false)
   }
   
   // --- Get Camera model (and all other parameters which are not changing during camera setup and usage )
-  AT_WC	model[1024];
-  THROW_IF_NOT_SUCCESS(getString(andor3::CameraModel, model, 1024),
+  THROW_IF_NOT_SUCCESS(getString(andor3::CameraModel, m_detector_model),
 		       "Cannot get camera model");
 
-  m_detector_model = WStringToString(std::wstring(model));
-  
   // Adding some extra information on the model (more human readable) :
   // DC-152 -> Neo
   if ( ! m_detector_model.compare(0, 6, "DC-152 ")) {
@@ -282,12 +279,9 @@ m_maximage_size_cb_active(false)
   }
 
   // --- Get Camera Serial number
-  AT_WC	serial[1024];
-  THROW_IF_NOT_SUCCESS(getString(andor3::SerialNumber, serial, 1024),
+  THROW_IF_NOT_SUCCESS(getString(andor3::SerialNumber, m_detector_serial),
 		       "Cannot get camera serial number");
 
-  m_detector_serial = WStringToString(std::wstring(serial));
-
   // --- Get Camera maximum image size 
   AT_64 xmax, ymax;
   // --- Get the max image size of the detector
@@ -476,16 +470,16 @@ lima::Andor3::Camera::prepareAcq()
       DEB_TRACE()<< "Software trigger ON, set CycleMode to Fixed mode";
       AT_64  nb_frames = static_cast<AT_64>(m_nb_frames_to_collect);
       setInt(andor3::FrameCount, nb_frames);
-      setEnumString(andor3::CycleMode, L"Fixed");    
+      setEnumString(andor3::CycleMode, "Fixed");    
     }
   else
     {
-      setEnumString(andor3::CycleMode, L"Continuous");    
+      setEnumString(andor3::CycleMode, "Continuous");    
     }
   
-  AT_WC          the_string[256];
-  getEnumString(andor3::CycleMode, the_string, 255); 
-  DEB_TRACE() << "At the end of prepareAcq, the CycleMode is " << WStringToString(std::wstring(the_string));
+  std::string cycle_mode;
+  getEnumString(andor3::CycleMode, cycle_mode); 
+  DEB_TRACE() << "At the end of prepareAcq, the CycleMode is " << cycle_mode;
 }
 
 
@@ -713,7 +707,7 @@ lima::Andor3::Camera::setTrigMode(TrigMode mode)
     }
   }
   else {
-    setEnumString(andor3::TriggerMode, L"Advanced");
+    setEnumString(andor3::TriggerMode, "Advanced");
     DEB_TRACE() << "SIMCAM - forcing trigger mode to Advanced";
     m_trig_mode = mode;
   }
@@ -1278,9 +1272,7 @@ lima::Andor3::Camera::getAdcGain(A3_Gain &oGain) const
 void
 lima::Andor3::Camera::getAdcGainString(std::string &oGainString) const
 {
-  AT_WC		the_string[256];
-  getEnumString(andor3::PreAmpGainControl, the_string, 255);
-  oGainString = WStringToString(std::wstring(the_string));
+  getEnumString(andor3::PreAmpGainControl, oGainString);
 }
 
 
@@ -1321,9 +1313,7 @@ lima::Andor3::Camera::getAdcRate(A3_ReadOutRate &oRate) const
 void
 lima::Andor3::Camera::getAdcRateString(std::string &oRateString) const
 {
-  AT_WC		the_string[256];
-  getEnumString(andor3::PixelReadoutRate, the_string, 255);
-  oRateString = WStringToString(std::wstring(the_string));
+  getEnumString(andor3::PixelReadoutRate, oRateString);
 }
 
 void
@@ -1361,9 +1351,7 @@ lima::Andor3::Camera::getElectronicShutterMode(A3_ShutterMode &oMode) const
 void
 lima::Andor3::Camera::getElectronicShutterModeString(std::string &oModeString) const
 {
-  AT_WC		the_string[256];
-  getEnumStringByIndex(andor3::ElectronicShutteringMode, m_electronic_shutter_mode, the_string, 255);
-  oModeString = WStringToString(std::wstring(the_string));
+  getEnumStringByIndex(andor3::ElectronicShutteringMode, m_electronic_shutter_mode, oModeString);
 }
 
 void
@@ -1383,10 +1371,10 @@ lima::Andor3::Camera::setBitDepth(A3_BitDepth iMode)
   // Making sure that the pixel encoding is a predictable one, depending on the bit-depth.
   switch (m_bit_depth) {
     case b11:
-      setEnumString(andor3::PixelEncoding, L"Mono12");
+      setEnumString(andor3::PixelEncoding, "Mono12");
       break;
     case b16:
-      setEnumString(andor3::PixelEncoding, L"Mono16");
+      setEnumString(andor3::PixelEncoding, "Mono16");
       break;
     default:
       break;
@@ -1403,17 +1391,13 @@ lima::Andor3::Camera::getBitDepth(A3_BitDepth &oMode) const
 void
 lima::Andor3::Camera::getBitDepthString(std::string &oDepthString) const
 {
-  AT_WC		the_string[256];
-  getEnumStringByIndex(andor3::BitDepth, m_bit_depth, the_string, 255);
-  oDepthString = WStringToString(std::wstring(the_string));
+  getEnumStringByIndex(andor3::BitDepth, m_bit_depth, oDepthString);
 }
 
 void
 lima::Andor3::Camera::getPxEncodingString(std::string &oPxEncodingString) const
 {
-  AT_WC		the_string[256];
-  getEnumString(andor3::PixelEncoding, the_string, 255);
-  oPxEncodingString = WStringToString(std::wstring(the_string));
+  getEnumString(andor3::PixelEncoding, oPxEncodingString);
 }
 
 void
@@ -1428,12 +1412,9 @@ lima::Andor3::Camera::getPxEncoding(A3_PixelEncoding &oPxEncoding) const
 void
 lima::Andor3::Camera::getTriggerModeString(std::string &oModeString) const
 {
-  AT_WC		the_string[256];
-  int		i_trig;
   if (m_real_camera) {
-    i_trig = m_trig_mode_map.at(m_trig_mode);
-    getEnumStringByIndex(andor3::TriggerMode, m_trig_mode, the_string, 255);
-    oModeString = WStringToString(std::wstring(the_string));
+    int i_trig = m_trig_mode_map.at(m_trig_mode);
+    getEnumStringByIndex(andor3::TriggerMode, i_trig, oModeString);
   }
   else {
     oModeString = "Advanced";
@@ -1447,7 +1428,7 @@ lima::Andor3::Camera::setGateLevel(A3_SignalLevel iLevel)
   bool flag;
   if (iLevel == Inverted) flag= true;
   else flag= false;
-  setEnumString(andor3::IOSelector, L"External Exposure");
+  setEnumString(andor3::IOSelector, "External Exposure");
   setBool(andor3::IOInvert, flag);
 }
 
@@ -1456,7 +1437,7 @@ lima::Andor3::Camera::getGateLevel(A3_SignalLevel &iLevel)
 {
   DEB_MEMBER_FUNCT();
   bool flag;
-  setEnumString(andor3::IOSelector, L"External Exposure");
+  setEnumString(andor3::IOSelector, "External Exposure");
   getBool(andor3::IOInvert, &flag);
   if (flag)
     iLevel = Inverted;
@@ -1471,7 +1452,7 @@ lima::Andor3::Camera::setTriggerLevel(A3_SignalLevel iLevel)
   bool flag;
   if (iLevel == Inverted) flag= true;
   else flag= false;
-  setEnumString(andor3::IOSelector, L"External Trigger");
+  setEnumString(andor3::IOSelector, "External Trigger");
   setBool(andor3::IOInvert, flag);
 }
 
@@ -1480,7 +1461,7 @@ lima::Andor3::Camera::getTriggerLevel(A3_SignalLevel &iLevel)
 {
   DEB_MEMBER_FUNCT();
   bool flag;
-  setEnumString(andor3::IOSelector, L"External Trigger");
+  setEnumString(andor3::IOSelector, "External Trigger");
   getBool(andor3::IOInvert, &flag);
   if (flag)
     iLevel = Inverted;
@@ -1648,12 +1629,11 @@ lima::Andor3::Camera::getCoolingStatus(std::string& status) const
 {
   DEB_MEMBER_FUNCT();
   if ( m_real_camera ) {
-    wchar_t		wcs_status_string[32];
-    getEnumString(andor3::TemperatureStatus, wcs_status_string, 31);
-    status = WStringToString(wcs_status_string);
+    getEnumString(andor3::TemperatureStatus, status);
   }
   else {
     DEB_TRACE() << "This has no signification on SIMCAM";
+    status = "unknown";
   }
 }
 
@@ -1697,8 +1677,7 @@ lima::Andor3::Camera::setFanSpeed(std::string fan_speed)
 {
   DEB_MEMBER_FUNCT();
   if ( propImplemented(andor3::FanSpeed) ) {
-    const std::wstring fan_set = StringToWString(fan_speed);
-    setEnumString(andor3::FanSpeed, fan_set.c_str());
+    setEnumString(andor3::FanSpeed, fan_speed);
   }
   else {
     DEB_TRACE() << "The camera has no fan speed setting... Do nothing !";
@@ -1710,9 +1689,7 @@ lima::Andor3::Camera::getFanSpeed(std::string &fan_speed) const
 {
   DEB_MEMBER_FUNCT();
   if ( propImplemented(andor3::FanSpeed) ) {
-    AT_WC fan_string[256];
-    getEnumString(andor3::FanSpeed, fan_string, 255);
-    fan_speed = WStringToString(fan_string);
+    getEnumString(andor3::FanSpeed, fan_speed);
   }
   else {
     DEB_TRACE() << "The camera has no fan speed setting... Do nothing !";
@@ -1853,9 +1830,7 @@ lima::Andor3::Camera::getSimpleGainString(std::string &o_gainString) const
 {
   DEB_MEMBER_FUNCT();
   if ( propImplemented(andor3::SimplePreAmpGainControl) ) {
-    AT_WC		the_string[256];
-    getEnumString(andor3::SimplePreAmpGainControl, the_string, 255);
-    o_gainString = WStringToString(std::wstring(the_string));
+    getEnumString(andor3::SimplePreAmpGainControl, o_gainString);
   }
   else {
     DEB_TRACE() << "The camera has no simple gain control setting... Do nothing !";
@@ -1916,9 +1891,7 @@ void
 lima::Andor3::Camera::getFirmwareVersion(std::string &o_fwv) const
 {
   DEB_MEMBER_FUNCT();
-  AT_WC	the_fwv[1024];
-  getString(andor3::FirmwareVersion, the_fwv, 1024);
-  o_fwv = WStringToString(the_fwv);
+  getString(andor3::FirmwareVersion, o_fwv);
 }
 
 
@@ -1998,9 +1971,7 @@ void
 lima::Andor3::Camera::getSerialNumber(std::string &o_sn) const
 {
   DEB_MEMBER_FUNCT();
-  AT_WC	the_sn[1024];
-  getString(andor3::SerialNumber, the_sn, 1024);
-  o_sn = WStringToString(the_sn);
+  getString(andor3::SerialNumber, o_sn);
 }
 
 
@@ -2428,28 +2399,37 @@ lima::Andor3::Camera::setEnumIndex(const AT_WC* Feature, int Value)
 }
 
 int
-lima::Andor3::Camera::setEnumString(const AT_WC* Feature, const AT_WC* String)
+lima::Andor3::Camera::getEnumIndex(const AT_WC* Feature, int* Value) const
 {
   DEB_MEMBER_FUNCT();
-  return AT_SetEnumString(m_camera_handle, Feature, String);
+  return AT_GetEnumIndex(m_camera_handle, Feature, Value);
 }
 
 int
-lima::Andor3::Camera::getEnumIndex(const AT_WC* Feature, int* Value) const
+lima::Andor3::Camera::setEnumString(const AT_WC* Feature, std::string Value)
 {
   DEB_MEMBER_FUNCT();
-  return AT_GetEnumIndex(m_camera_handle, Feature, Value);
+  const std::wstring value_set = StringToWString(Value);
+  return AT_SetEnumString(m_camera_handle, Feature, value_set.c_str());
 }
 
 int
-lima::Andor3::Camera::getEnumString(const AT_WC* Feature, AT_WC* String, int StringLength) const
+lima::Andor3::Camera::getEnumString(const AT_WC* Feature, std::string& Value) const
 {
   DEB_MEMBER_FUNCT();
-  int Value;
-  int i_Err = AT_GetEnumIndex(m_camera_handle, Feature, &Value);
-  if ( AT_SUCCESS != i_Err )
-    return i_Err;
-  return AT_GetEnumStringByIndex(m_camera_handle, Feature, Value, String, StringLength);
+  int value_idx, ierr;
+
+  ierr = AT_GetEnumIndex(m_camera_handle, Feature, &value_idx);
+  if (AT_SUCCESS != ierr)
+    return ierr;
+
+  AT_WC value_str[256];
+  ierr = AT_GetEnumStringByIndex(m_camera_handle, Feature, value_idx, value_str, 255);
+  if (AT_SUCCESS != ierr)
+    return ierr;
+
+  Value = WStringToString(value_str);
+  return ierr;
 }
 
 int
@@ -2468,6 +2448,7 @@ lima::Andor3::Camera::isEnumIndexAvailable(const AT_WC* Feature, int Index, bool
   *Available = isAvailable;
   return i_Err;
 }
+
 int
 lima::Andor3::Camera::isEnumIndexImplemented(const AT_WC* Feature, int Index, bool* Implemented) const
 {
@@ -2479,38 +2460,40 @@ lima::Andor3::Camera::isEnumIndexImplemented(const AT_WC* Feature, int Index, bo
 }
 
 int
-lima::Andor3::Camera::getEnumStringByIndex(const AT_WC* Feature, int Index, AT_WC* String, int StringLength) const
+lima::Andor3::Camera::getEnumStringByIndex(const AT_WC* Feature, int Index, std::string& Value) const
 {
   DEB_MEMBER_FUNCT();
-  return AT_GetEnumStringByIndex(m_camera_handle, Feature, Index, String, StringLength);
+  AT_WC	the_string[256];
+  int ierr = AT_GetEnumStringByIndex(m_camera_handle, Feature, Index, the_string, 255);
+  Value = WStringToString(std::wstring(the_string));
+  return ierr;
 }
 
 int
-lima::Andor3::Camera::getEnumIndexByString(const AT_WC* Feature, AT_WC* String, int *Index) const
+lima::Andor3::Camera::getEnumIndexByString(const AT_WC* Feature, std::string Value, int *Index) const
 {
   DEB_MEMBER_FUNCT();
   
-  int       i_Err;
-  int   		i_enumCount;
+  int		i_Err;
+  int   	i_enumCount;
   int     	i_enumIndex;
-  const int i_maxStringLen = 1024;
-  AT_WC   	wcs_enumString[i_maxStringLen + 5];
+  std::string   s_enumString;
   
   if ( AT_SUCCESS != (i_Err = getEnumCount(m_camera_handle, Feature, &i_enumCount)) ) {
     DEB_ERROR() << "Failed to get Enum Count" << " : error code = " << error_code(i_Err);
     return i_Err;
   }
   for (i_enumIndex = 0; i_enumCount != i_enumIndex; ++i_enumIndex) {
-    if ( AT_SUCCESS != getEnumStringByIndex(Feature, i_enumIndex, wcs_enumString, i_maxStringLen) ) {
+    if ( AT_SUCCESS != getEnumStringByIndex(Feature, i_enumIndex, s_enumString) ) {
       DEB_ERROR() << "Failed to get Enum String" << " : error code = " << error_code(i_Err);
       return i_Err;
     }
-    if ( ! wcscmp(wcs_enumString, String) ) {
+    if ( s_enumString == Value) {
       break;
     }
   }
   if ( i_enumCount == i_enumIndex ) {
-    DEB_ERROR() << "Unable to find index of enum string '" << WStringToString(String) << "' in '" << WStringToString(Feature) << "' : no such choice.";
+    DEB_ERROR() << "Unable to find index of enum string '" << Value << "' in '" << WStringToString(Feature) << "' : no such choice.";
     *Index = -1;
     i_Err = AT_ERR_INDEXNOTAVAILABLE;
   }
@@ -2522,17 +2505,24 @@ lima::Andor3::Camera::getEnumIndexByString(const AT_WC* Feature, AT_WC* String,
 }
 
 int
-lima::Andor3::Camera::setString(const AT_WC* Feature, const AT_WC* String)
+lima::Andor3::Camera::setString(const AT_WC* Feature, std::string Value)
 {
   DEB_MEMBER_FUNCT();
-  return AT_SetString(m_camera_handle, Feature, String);
+  const std::wstring value_set = StringToWString(Value);
+  return AT_SetString(m_camera_handle, Feature, value_set.c_str());
 }
 
 int
-lima::Andor3::Camera::getString(const AT_WC* Feature, AT_WC* String, int StringLength) const
+lima::Andor3::Camera::getString(const AT_WC* Feature, std::string &Value) const
 {
   DEB_MEMBER_FUNCT();
-  return AT_GetString(m_camera_handle, Feature, String, StringLength);
+  AT_WC value_str[1024];
+  int ierr = AT_GetString(m_camera_handle, Feature, value_str, 1023);
+  if (AT_SUCCESS != ierr)
+    return ierr;
+
+  Value = WStringToString(value_str);
+  return ierr;
 }
 
 int
-- 
GitLab


From 85223d11c0e130b9aa8cb67b132334b038e1835f Mon Sep 17 00:00:00 2001
From: Emmanuel Papillon <papillon@esrf.fr>
Date: Thu, 24 Mar 2022 12:04:14 +0100
Subject: [PATCH 08/24] Change output signal methods to use string/bool instead
 of enums

---
 include/Andor3Camera.h | 16 ++++++------
 sip/Andor3Camera.sip   | 18 ++++++-------
 src/Andor3Camera.cpp   | 57 ++++++++++++++++++++----------------------
 tango/Andor3.py        | 39 +++++++++++------------------
 4 files changed, 56 insertions(+), 74 deletions(-)

diff --git a/include/Andor3Camera.h b/include/Andor3Camera.h
index 31ed347..6e971d8 100644
--- a/include/Andor3Camera.h
+++ b/include/Andor3Camera.h
@@ -80,9 +80,6 @@ namespace lima
       // trigger / gate level
       enum A3_SignalLevel { Normal=0, Inverted=1};
 
-      // output signal
-      enum A3_OutputSignal { FireRow1=0, FireRowN=1, FireAll=2, FireAny=3 };
-      
       struct SdkFrameDim {       
 	AT_64 width;
 	AT_64 height;
@@ -162,13 +159,14 @@ namespace lima
       void getAdcGain(A3_Gain &oGain) const;
       void getAdcGainString(std::string &oGainString) const;
 
-      void setGateLevel(A3_SignalLevel iLevel);
-      void getGateLevel(A3_SignalLevel &iLevel);
-      void setTriggerLevel(A3_SignalLevel iLevel);
-      void getTriggerLevel(A3_SignalLevel &iLevel);
+      void setGateInverted(bool inverted);
+      void getGateInverted(bool& inverted);
+      void setTriggerInverted(bool inverted);
+      void getTriggerInverted(bool& inverted);
 
-      void setOutputSignal(A3_OutputSignal iSignal);
-      void getOutputSignal(A3_OutputSignal &oSignal) const;
+      void setOutputSignal(std::string signal);
+      void getOutputSignal(std::string &signal) const;
+      void getOutputSignalList(std::vector<std::string> &signal_list) const;
 
       void setAdcRate(A3_ReadOutRate iRate);  // à exporter (avec le get)
       void getAdcRate(A3_ReadOutRate &oRate) const;
diff --git a/sip/Andor3Camera.sip b/sip/Andor3Camera.sip
index 97d8b5a..c2aa10e 100644
--- a/sip/Andor3Camera.sip
+++ b/sip/Andor3Camera.sip
@@ -39,8 +39,6 @@ namespace Andor3
 //    enum A3_TriggerMode { Internal = 0, ExternalLevelTransition = 1, ExternalStart = 2, ExternalExposure = 3, Software = 4, Advanced = 5, External = 6 };
     enum A3_Binning { B1x1=0, B2x2=1, B3x3=2, B4x4=3, B8x8=4};
     enum A3_PixelEncoding {Mono12=0, Mono12Packed = 1, Mono16=2, Mono32=3};
-    enum A3_SignalLevel {Normal=0, Inverted=1};
-    enum A3_OutputSignal {FireRow1=0, FireRowN=1, FireAll=2, FireAny=3};
 
     Camera(const std::string& bitflow_path, int camera_number=0);
     ~Camera();
@@ -95,12 +93,14 @@ namespace Andor3
 // -- andor3 specific, LIMA don't worry about it !
    void initialiseController();
 
-   void setGateLevel(A3_SignalLevel iLevel /In/ );
-   void getGateLevel(A3_SignalLevel &iLevel /Out/ );
-   void setTriggerLevel(A3_SignalLevel iLevel /In/ );
-   void getTriggerLevel(A3_SignalLevel &iLevel /Out/ );
-   void setOutputSignal(A3_OutputSignal iSignal /In/ );
-   void getOutputSignal(A3_OutputSignal &oSignal /Out/ ) const;
+   void setGateInverted(bool inverted /In/ );
+   void getGateInverted(bool &inverted /Out/ );
+   void setTriggerInverted(bool inverted /In/ );
+   void getTriggerInverted(bool &inverted /Out/ );
+
+   void setOutputSignal(std::string signal /In/ );
+   void getOutputSignal(std::string &signal /Out/ ) const;
+   void getOutputSignalList(std::vector<std::string> &signal_list /Out/ ) const;
 
    void setAdcGain(A3_Gain iGain /In/ );
    void getAdcGain(A3_Gain &oGain /Out/ ) const;
@@ -115,8 +115,6 @@ namespace Andor3
    void getBitDepth(A3_BitDepth &oMode /Out/ ) const;
    void getBitDepthString(std::string &oDepthString /Out/ ) const;
    void getPxEncodingString(std::string &oPxEncoding /Out/ ) const;
-//   void setTriggerMode(A3_TriggerMode iMode /In/ );
-//   void getTriggerMode(A3_TriggerMode &oMode /Out/ ) const;
    void getTriggerModeString(std::string &oModeString /Out/ ) const;
    void setTemperatureSP(double temp /In/ );
    void getTemperatureSP(double& temp /Out/ ) const;
diff --git a/src/Andor3Camera.cpp b/src/Andor3Camera.cpp
index 13096cc..47a37b7 100644
--- a/src/Andor3Camera.cpp
+++ b/src/Andor3Camera.cpp
@@ -1422,59 +1422,43 @@ lima::Andor3::Camera::getTriggerModeString(std::string &oModeString) const
 }
 
 void
-lima::Andor3::Camera::setGateLevel(A3_SignalLevel iLevel)
+lima::Andor3::Camera::setGateInverted(bool inverted)
 {
   DEB_MEMBER_FUNCT();
-  bool flag;
-  if (iLevel == Inverted) flag= true;
-  else flag= false;
   setEnumString(andor3::IOSelector, "External Exposure");
-  setBool(andor3::IOInvert, flag);
+  setBool(andor3::IOInvert, inverted);
 }
 
 void
-lima::Andor3::Camera::getGateLevel(A3_SignalLevel &iLevel)
+lima::Andor3::Camera::getGateInverted(bool& inverted)
 {
   DEB_MEMBER_FUNCT();
-  bool flag;
   setEnumString(andor3::IOSelector, "External Exposure");
-  getBool(andor3::IOInvert, &flag);
-  if (flag)
-    iLevel = Inverted;
-  else
-    iLevel = Normal;
+  getBool(andor3::IOInvert, &inverted);
 }
 
 void
-lima::Andor3::Camera::setTriggerLevel(A3_SignalLevel iLevel)
+lima::Andor3::Camera::setTriggerInverted(bool inverted)
 {
   DEB_MEMBER_FUNCT();
-  bool flag;
-  if (iLevel == Inverted) flag= true;
-  else flag= false;
   setEnumString(andor3::IOSelector, "External Trigger");
-  setBool(andor3::IOInvert, flag);
+  setBool(andor3::IOInvert, inverted);
 }
 
 void
-lima::Andor3::Camera::getTriggerLevel(A3_SignalLevel &iLevel)
+lima::Andor3::Camera::getTriggerInverted(bool& inverted)
 {
   DEB_MEMBER_FUNCT();
-  bool flag;
   setEnumString(andor3::IOSelector, "External Trigger");
-  getBool(andor3::IOInvert, &flag);
-  if (flag)
-    iLevel = Inverted;
-  else
-    iLevel = Normal;
+  getBool(andor3::IOInvert, &inverted);
 }
 
 void
-lima::Andor3::Camera::setOutputSignal(A3_OutputSignal iSignal)
+lima::Andor3::Camera::setOutputSignal(std::string iSignal)
 {
   DEB_MEMBER_FUNCT();
   if ( propImplemented(andor3::AuxiliaryOutSource) ) {
-    setEnumIndex(andor3::AuxiliaryOutSource, iSignal);
+    setEnumString(andor3::AuxiliaryOutSource, iSignal);
   }
   else {
     DEB_TRACE() << "The camera has no fan speed setting... Do nothing !";
@@ -1482,19 +1466,32 @@ lima::Andor3::Camera::setOutputSignal(A3_OutputSignal iSignal)
 }
 
 void
-lima::Andor3::Camera::getOutputSignal(A3_OutputSignal &oSignal) const
+lima::Andor3::Camera::getOutputSignal(std::string &oSignal) const
 {
   DEB_MEMBER_FUNCT();
   if ( propImplemented(andor3::AuxiliaryOutSource) ) {
-    int  value;
-    getEnumIndex(andor3::AuxiliaryOutSource, &value);
-    oSignal = static_cast<A3_OutputSignal>(value);
+    getEnumString(andor3::AuxiliaryOutSource, oSignal);
   }
   else {
     DEB_TRACE() << "The camera has no fan speed setting... Do nothing !";
+    oSignal = "not implemented";
   }  
 }
 
+void
+lima::Andor3::Camera::getOutputSignalList(std::vector<std::string> &signal_list) const
+{
+  int		enum_count;
+  std::string	s_value;
+  
+  AT_GetEnumCount(m_camera_handle, andor3::AuxiliaryOutSource, &enum_count);
+
+  for (int idx=0; enum_count != idx; ++idx) {
+    getEnumStringByIndex(andor3::AuxiliaryOutSource, idx, s_value);
+    signal_list.push_back(s_value);
+  }
+}
+
 //-----------------------------------------------------
 // @brief	retrieve temperature capabilities
 //-----------------------------------------------------
diff --git a/tango/Andor3.py b/tango/Andor3.py
index 95b4ce5..6c3b3a7 100644
--- a/tango/Andor3.py
+++ b/tango/Andor3.py
@@ -88,26 +88,15 @@ class Andor3(PyTango.Device_4Impl):
                           'MHZ200': _Andor3Camera.MHz200,
                           'MHZ280': _Andor3Camera.MHz280,
                           }
-        self.__Cooler = {'ON':  True,
-                         'OFF': False}
+        self.__Cooler = {'ON':  True, 'OFF': False}
         self.__ElectronicShutterMode = {'ROLLING': _Andor3Camera.Rolling,
                                         'GLOBAL': _Andor3Camera.Global,
                                         }
-        self.__Overlap = {'ON':  True,
-                         'OFF': False}
-        self.__SpuriousNoiseFilter = {'ON':  True,
-                         'OFF': False}
-        self.__GateLevel = { 'NORMAL': _Andor3Camera.Normal,
-                             'INVERTED': _Andor3Camera.Inverted,
-                           }
-        self.__TriggerLevel = { 'NORMAL': _Andor3Camera.Normal,
-                                'INVERTED': _Andor3Camera.Inverted,
-                              }
-        self.__OutputSignal = { 'FIREROW1': _Andor3Camera.FireRow1,
-                                'FIREROWN': _Andor3Camera.FireRowN,
-                                'FIREALL': _Andor3Camera.FireAll,
-                                'FIREANY': _Andor3Camera.FireAny,
-                              }
+        self.__Overlap = {'ON':  True, 'OFF': False}
+        self.__SpuriousNoiseFilter = {'ON':  True, 'OFF': False}
+        self.__GateInverted = { 'YES': True, 'NO': False }
+        self.__TriggerInverted = { 'YES': True, 'NO': False }
+        self.__OutputSignal = andor_list2dict(_Andor3Camera.getOutputSignalList())
         self.__FanSpeed = andor_list2dict(_Andor3Camera.getFanSpeedList())
 
         self.__Attribute2FunctionBase = {'adc_gain': 'SimpleGain',
@@ -124,8 +113,8 @@ class Andor3(PyTango.Device_4Impl):
                                          'overlap': 'Overlap',
                                          'spurious_noise_filter': 'SpuriousNoiseFilter',
                                          'serial_number': 'SerialNumber',
-                                         'gate_level': 'GateLevel',
-                                         'trigger_level': 'TriggerLevel',
+                                         'gate_inverted': 'GateInverted',
+                                         'trigger_inverted': 'TriggerInverted',
                                          'output_signal': 'OutputSignal',
                                          }
 
@@ -384,25 +373,25 @@ class Andor3Class(PyTango.DeviceClass):
              'format': '',
              'description': 'camera serial number',
              }],
-        'trigger_level':
+        'trigger_inverted':
         [[PyTango.DevString,
           PyTango.SCALAR,
           PyTango.READ_WRITE],
          {
-             'label':'External trigger level',
+             'label':'trigger signal inverted',
              'unit': 'N/A',
              'format': '',
-             'description': 'NORMAl or INVERTED'
+             'description': 'YES or NO'
              }],
-        'gate_level':
+        'gate_inverted':
         [[PyTango.DevString,
           PyTango.SCALAR,
           PyTango.READ_WRITE],
          {
-             'label':'External gate level',
+             'label':'gate signal inverted',
              'unit': 'N/A',
              'format': '',
-             'description': 'NORMAl or INVERTED'
+             'description': 'YES or NO'
              }],
         'output_signal':
         [[PyTango.DevString,
-- 
GitLab


From 95ee37914423b20f70d15236edb8478dbdee3af7 Mon Sep 17 00:00:00 2001
From: Emmanuel Papillon <papillon@esrf.fr>
Date: Thu, 24 Mar 2022 17:17:05 +0100
Subject: [PATCH 09/24] Rework SimpleGain to work with strings. Possible gain
 are camera-dependant and are read from the sdk

---
 include/Andor3Camera.h    |  15 +++---
 include/Andor3Interface.h |   6 +--
 sip/Andor3Camera.sip      |   9 ++--
 sip/Andor3Interface.sip   |   6 +--
 src/Andor3Camera.cpp      | 104 +++++++++++++++++++-------------------
 src/Andor3Interface.cpp   |   8 +--
 tango/Andor3.py           |   5 +-
 7 files changed, 76 insertions(+), 77 deletions(-)

diff --git a/include/Andor3Camera.h b/include/Andor3Camera.h
index 6e971d8..ce37d60 100644
--- a/include/Andor3Camera.h
+++ b/include/Andor3Camera.h
@@ -63,7 +63,10 @@ namespace lima
       // In the same order/index as "PreAmpGainControl"
       enum A3_Gain { Gain1 = 0, Gain2 = 1, Gain3 = 2, Gain4 = 3, Gain1_Gain3 = 4, Gain1_Gain4 = 5, Gain2_Gain3 = 6, Gain2_Gain4 = 7 };
       // The "simple" version :
-      enum A3_SimpleGain { b11_hi_gain=0, b11_low_gain=1, b16_lh_gain=2, none=31};
+      // enum A3_SimpleGain { b11_hi_gain=0, b11_low_gain=1, b16_lh_gain=2, none=31};
+
+      const std::vector<std::string> A3_SimpleGainString = {"b11_hi_gain", "b11_low_gain", "b16_lh_gain"};
+
       // In the same order/index as "ElectronicShutteringMode"
       enum A3_ShutterMode { Rolling = 0, Global = 1 };
       // In the same order/index as "PixelReadoutRate"
@@ -196,9 +199,11 @@ namespace lima
 
       void setOverlap(bool i_overlap);
       void getOverlap(bool &o_overlap) const;
-      void setSimpleGain(A3_SimpleGain i_gain);
-      void getSimpleGain(A3_SimpleGain &o_gain) const;
-      void getSimpleGainString(std::string &o_gainString) const;
+
+      void setSimpleGain(std::string i_gain);
+      void getSimpleGain(std::string &o_gain) const;
+      void getSimpleGainList(std::vector<std::string> &gain_list) const;
+
       void setSpuriousNoiseFilter(bool i_filter);
       void getSpuriousNoiseFilter(bool &o_filter) const;
       void setSyncTriggering(bool i_sync);
@@ -306,7 +311,6 @@ namespace lima
       int                         m_camera_number;
       AT_H                        m_camera_handle;
       A3_Gain                     m_adc_gain;
-      A3_SimpleGain               m_simple_gain;
       A3_ReadOutRate	          m_adc_rate;
       A3_ShutterMode		  m_electronic_shutter_mode;
       A3_BitDepth                 m_bit_depth;
@@ -317,7 +321,6 @@ namespace lima
       std::vector<float>	  m_temperature_control_values;
 
       TrigMode                    m_trig_mode;
-      // A3_TriggerMode		  m_trig_mode;
       std::map<TrigMode, int>     m_trig_mode_map;
 
       static int                  sAndorSDK3InittedCounter;
diff --git a/include/Andor3Interface.h b/include/Andor3Interface.h
index efa9cfe..047983c 100644
--- a/include/Andor3Interface.h
+++ b/include/Andor3Interface.h
@@ -71,9 +71,9 @@ namespace lima
       virtual void		setAdcGain(Camera::A3_Gain iGain);
       virtual void		getAdcGain(Camera::A3_Gain &oGain) const;
       virtual void		getAdcGainString(std::string &oGainString) const;
-      virtual void		setSimpleGain(Camera::A3_SimpleGain iGain);
-      virtual void		getSimpleGain(Camera::A3_SimpleGain &oGain) const;
-      virtual void		getSimpleGainString(std::string &oGainString) const;
+      virtual void		setSimpleGain(std::string iGain);
+      virtual void		getSimpleGain(std::string &oGain) const;
+      virtual void		getSimpleGainList(std::vector<std::string> &gain_list) const;
       virtual void		setAdcRate(Camera::A3_ReadOutRate iRate);
       virtual void		getAdcRate(Camera::A3_ReadOutRate &oRate) const;
       virtual void		getAdcRateString(std::string &oRateString) const;
diff --git a/sip/Andor3Camera.sip b/sip/Andor3Camera.sip
index c2aa10e..af9e834 100644
--- a/sip/Andor3Camera.sip
+++ b/sip/Andor3Camera.sip
@@ -32,7 +32,6 @@ namespace Andor3
     enum A3_TypeInfo { Unknown, Int, Float, Bool, Enum, String };
 
     enum A3_Gain { Gain1 = 0, Gain2 = 1, Gain3 = 2, Gain4 = 3, Gain1_Gain3 = 4, Gain1_Gain4 = 5, Gain2_Gain3 = 6, Gain2_Gain4 = 7 };
-    enum A3_SimpleGain { b11_hi_gain=0, b11_low_gain=1, b16_lh_gain=2, none=31};
     enum A3_ShutterMode { Rolling = 0, Global = 1 };
     enum A3_ReadOutRate { MHz10 = 0, MHz100 = 1, MHz200 = 2, MHz280 = 3 };
     enum A3_BitDepth { b11 = 0, b16= 1 };
@@ -132,9 +131,11 @@ namespace Andor3
 
    void setOverlap(bool i_overlap /In/ );
    void getOverlap(bool &o_overlap /Out/ ) const;
-   void setSimpleGain(A3_SimpleGain i_gain /In/ );
-   void getSimpleGain(A3_SimpleGain &o_gain /Out/ ) const;
-   void getSimpleGainString(std::string &o_gainString /Out/ ) const;
+
+   void setSimpleGain(std::string i_gain /In/ );
+   void getSimpleGain(std::string &o_gain /Out/ ) const;
+   void getSimpleGainList(std::vector<std::string> &gain_list /Out/ ) const;
+
    void setSpuriousNoiseFilter(bool i_filter /In/ );
    void getSpuriousNoiseFilter(bool &o_filter /Out/ ) const;
    void setSyncTriggering(bool i_sync /In/ );
diff --git a/sip/Andor3Interface.sip b/sip/Andor3Interface.sip
index a0e57f7..270616b 100644
--- a/sip/Andor3Interface.sip
+++ b/sip/Andor3Interface.sip
@@ -50,9 +50,9 @@ namespace Andor3
     virtual void		setAdcGain(Andor3::Camera::A3_Gain iGain /In/ );
     virtual void		getAdcGain(Andor3::Camera::A3_Gain &oGain /Out/ ) const;
     virtual void		getAdcGainString(std::string &oGainString /Out/ ) const;
-    virtual void		setSimpleGain(Andor3::Camera::A3_SimpleGain iGain /In/ );
-    virtual void		getSimpleGain(Andor3::Camera::A3_SimpleGain &oGain /Out/ ) const;
-    virtual void		getSimpleGainString(std::string &oGainString /Out/ ) const;
+    virtual void		setSimpleGain(std::string iGain /In/ );
+    virtual void		getSimpleGain(std::string &oGain /Out/ ) const;
+    virtual void		getSimpleGainList(std::vector<std::string> &gain_list /Out/ ) const;
     virtual void		setAdcRate(Andor3::Camera::A3_ReadOutRate iRate /In/ );
     virtual void		getAdcRate(Andor3::Camera::A3_ReadOutRate &oRate /Out/ ) const;
     virtual void		getAdcRateString(std::string &oRateString /Out/ ) const;
diff --git a/src/Andor3Camera.cpp b/src/Andor3Camera.cpp
index 47a37b7..8e2a887 100644
--- a/src/Andor3Camera.cpp
+++ b/src/Andor3Camera.cpp
@@ -168,7 +168,6 @@ m_bitflow_path(bitflow_path),
 m_camera_number(camera_number),
 m_camera_handle(AT_HANDLE_UNINITIALISED),
 m_adc_gain(Gain1_Gain4),
-m_simple_gain(b16_lh_gain),
 m_adc_rate(MHz100),
 m_electronic_shutter_mode(Rolling),
 m_bit_depth(b16),
@@ -1182,13 +1181,12 @@ lima::Andor3::Camera::initialiseController()
 {
   DEB_MEMBER_FUNCT();
   A3_BitDepth		the_bd = m_bit_depth;
-  A3_SimpleGain 	the_simple_gain = m_simple_gain;
   A3_ReadOutRate	the_rate = m_adc_rate;
   
   // Carefully crafting the order, since some are affecting others...
   setElectronicShutterMode(m_electronic_shutter_mode);
   setTrigMode(m_trig_mode);
-  setSimpleGain(the_simple_gain);
+  //setSimpleGain(the_simple_gain);
   setAdcRate(the_rate);
   setBitDepth(the_bd);
   setCooler(m_cooler);
@@ -1330,11 +1328,12 @@ lima::Andor3::Camera::setElectronicShutterMode(A3_ShutterMode iMode)
     << "\n\twhile requesting " << iMode;
   }
   // Setting the trigger mode might change the ADCGain and ADCRate :
-  int		the_gain, the_rate;
-  
-  getEnumIndex(andor3::SimplePreAmpGainControl, &the_gain);
+  int		the_rate;
+  std::string	the_gain;
+ 
+  getSimpleGain(the_gain); 
   getEnumIndex(andor3::PixelReadoutRate, &the_rate);
-  setSimpleGain(static_cast<A3_SimpleGain>(the_gain));
+  setSimpleGain(the_gain);
   setAdcRate(static_cast<A3_ReadOutRate>(the_rate));
 }
 
@@ -1715,50 +1714,42 @@ lima::Andor3::Camera::getOverlap(bool &o_overlap) const
 }
 
 void
-lima::Andor3::Camera::setSimpleGain(A3_SimpleGain i_gain)
+lima::Andor3::Camera::setSimpleGain(std::string i_gain)
 {
   DEB_MEMBER_FUNCT();
   if ( propImplemented(andor3::SimplePreAmpGainControl) ) {
-    int the_err_code = setEnumIndex(andor3::SimplePreAmpGainControl, i_gain);
-    if ( AT_SUCCESS != the_err_code ) {
-      DEB_ERROR() << "Cannot set SimplePreAmpGainControl to " << i_gain
-                  << " - " << DEB_VAR1(error_code(the_err_code));
-    }
+    THROW_IF_NOT_SUCCESS(setEnumString(andor3::SimplePreAmpGainControl, i_gain), \
+                         "failed to set simple gain");
   }
   else {
     DEB_TRACE() << "SimplePreAmpGainControl not implemented, emulating it in software";
     A3_ShutterMode		the_shutter;
     
     getElectronicShutterMode(the_shutter);
-    
-    switch (i_gain) {
-      case b11_low_gain:
-        setAdcGain(Gain1);
-        break;
-        
-      case b11_hi_gain:
-        if ( Rolling == the_shutter )
-          setAdcGain(Gain4);
-        else
-          setAdcGain(Gain3);
-        break;
-        
-      case b16_lh_gain:
-        if ( Rolling == the_shutter )
-          setAdcGain(Gain1_Gain4);
-        else
-          setAdcGain(Gain1_Gain3);
-        break;
-        
-      default:
-        DEB_TRACE() << "Not performing any settings since you provided an unavailable value";
-        break;
+
+    if (i_gain == "b11_low_gain") {
+      setAdcGain(Gain1);
+    }
+    else if (i_gain == "b11_hi_gain") {
+      if ( Rolling == the_shutter )
+        setAdcGain(Gain4);
+      else
+        setAdcGain(Gain3);
+    }
+    else if (i_gain == "b16_lh_gain") {
+      if ( Rolling == the_shutter )
+        setAdcGain(Gain1_Gain4);
+      else
+        setAdcGain(Gain1_Gain3);
+    }
+    else {
+      THROW_HW_ERROR(Error)<<"Invalid emulated simple gain";
     }
   }
 }
 
 void
-lima::Andor3::Camera::getSimpleGain(A3_SimpleGain &o_gain) const
+lima::Andor3::Camera::getSimpleGain(std::string &o_gain) const
 {
   DEB_MEMBER_FUNCT();
 
@@ -1771,14 +1762,12 @@ lima::Andor3::Camera::getSimpleGain(A3_SimpleGain &o_gain) const
   //  (6) "Gain 2 Gain 3 (16 bit)"; implemented = true; available = true.
   //  (7) "Gain 2 Gain 4 (16 bit)"; implemented = true; available = true.
   if ( propImplemented(andor3::SimplePreAmpGainControl) ) {
-    int			the_gain;
-    getEnumIndex(andor3::SimplePreAmpGainControl, &the_gain);
-    o_gain = static_cast<A3_SimpleGain>(the_gain);
+    getEnumString(andor3::SimplePreAmpGainControl, o_gain);
   }
   else {
     DEB_TRACE() << "SimplePreAmpGainControl not implemented, emulating it in software";
 
-    A3_Gain					the_gain;
+    A3_Gain		the_gain;
     A3_ShutterMode	the_shutter;
     
     getAdcGain(the_gain);
@@ -1787,34 +1776,34 @@ lima::Andor3::Camera::getSimpleGain(A3_SimpleGain &o_gain) const
     if ( Rolling == the_shutter ) {
       switch (the_gain) {
         case Gain1:
-          o_gain = b11_low_gain;
+          o_gain = "b11_low_gain";
           break;
         case Gain4:
-          o_gain = b11_hi_gain;
+          o_gain = "b11_hi_gain";
           break;
         case Gain1_Gain4:
-          o_gain = b16_lh_gain;
+          o_gain = "b16_lh_gain";
           break;
           
         default:
-          o_gain = none;
+          o_gain = "none";
           break;
       }
     }
     else {
       switch (the_gain) {
         case Gain1:
-          o_gain = b11_low_gain;
+          o_gain = "b11_low_gain";
           break;
         case Gain3:
-          o_gain = b11_hi_gain;
+          o_gain = "b11_hi_gain";
           break;
         case Gain1_Gain3:
-          o_gain = b16_lh_gain;
+          o_gain = "b16_lh_gain";
           break;
           
         default:
-          o_gain = none;
+          o_gain = "none";
           break;
       }      
     }
@@ -1823,15 +1812,24 @@ lima::Andor3::Camera::getSimpleGain(A3_SimpleGain &o_gain) const
 
 
 void
-lima::Andor3::Camera::getSimpleGainString(std::string &o_gainString) const
+lima::Andor3::Camera::getSimpleGainList(std::vector<std::string> &gain_list) const
 {
   DEB_MEMBER_FUNCT();
   if ( propImplemented(andor3::SimplePreAmpGainControl) ) {
-    getEnumString(andor3::SimplePreAmpGainControl, o_gainString);
+    int		enum_count;
+    std::string	s_value;
+    AT_GetEnumCount(m_camera_handle, andor3::SimplePreAmpGainControl, &enum_count);
+
+    for (int idx=0; enum_count != idx; ++idx) {
+      getEnumStringByIndex(andor3::SimplePreAmpGainControl, idx, s_value);
+      gain_list.push_back(s_value);
+    }
   }
   else {
-    DEB_TRACE() << "The camera has no simple gain control setting... Do nothing !";
-    o_gainString = "not implemented";
+    DEB_TRACE() << "SimplePreAmpGainControl not implemented, emulating it in software";
+    gain_list.push_back("b11_low_gain");
+    gain_list.push_back("b11_hi_gain");
+    gain_list.push_back("b16_lh_gain");
   }
 }
 
diff --git a/src/Andor3Interface.cpp b/src/Andor3Interface.cpp
index 15dc541..59b6d1c 100644
--- a/src/Andor3Interface.cpp
+++ b/src/Andor3Interface.cpp
@@ -190,7 +190,7 @@ lima::Andor3::Interface::getAdcGainString(std::string &oGainString) const
 }
 
 void
-lima::Andor3::Interface::setSimpleGain(Camera::A3_SimpleGain iGain)
+lima::Andor3::Interface::setSimpleGain(std::string iGain)
 {
   DEB_MEMBER_FUNCT();
   m_cam.setSimpleGain(iGain);
@@ -198,17 +198,17 @@ lima::Andor3::Interface::setSimpleGain(Camera::A3_SimpleGain iGain)
 }
 
 void
-lima::Andor3::Interface::getSimpleGain(Camera::A3_SimpleGain &oGain) const
+lima::Andor3::Interface::getSimpleGain(std::string &oGain) const
 {
   DEB_MEMBER_FUNCT();
   m_cam.getSimpleGain(oGain);
 }
 
 void
-lima::Andor3::Interface::getSimpleGainString(std::string &oGainString) const
+lima::Andor3::Interface::getSimpleGainList(std::vector<std::string> &gain_list) const
 {
   DEB_MEMBER_FUNCT();
-  m_cam.getSimpleGainString(oGainString);
+  m_cam.getSimpleGainList(gain_list);
 }
 
 
diff --git a/tango/Andor3.py b/tango/Andor3.py
index 6c3b3a7..f1b7c98 100644
--- a/tango/Andor3.py
+++ b/tango/Andor3.py
@@ -79,10 +79,7 @@ class Andor3(PyTango.Device_4Impl):
     def __init__(self,cl, name):
         PyTango.Device_4Impl.__init__(self,cl,name)
         # dictionnaries to be used with AttrHelper.get_attr_4u
-        self.__AdcGain = {'B11_HI_GAIN':  _Andor3Camera.b11_hi_gain,
-                             'B11_LOW_GAIN': _Andor3Camera.b11_low_gain,
-                             'B16_LH_GAIN':  _Andor3Camera.b16_lh_gain,
-                          }
+        self.__AdcGain = andor_list2dict(_Andor3Camera.getSimpleGainList())
         self.__AdcRate = {'MHZ10':  _Andor3Camera.MHz10,
                           'MHZ100': _Andor3Camera.MHz100,
                           'MHZ200': _Andor3Camera.MHz200,
-- 
GitLab


From 7051bb1a4285c3059a090f75cafa701926f1075d Mon Sep 17 00:00:00 2001
From: Emmanuel Papillon <papillon@esrf.fr>
Date: Wed, 30 Mar 2022 09:33:26 +0200
Subject: [PATCH 10/24] add make to conda recipe

---
 conda/camera/meta.yaml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/conda/camera/meta.yaml b/conda/camera/meta.yaml
index 826785f..c8f6329 100644
--- a/conda/camera/meta.yaml
+++ b/conda/camera/meta.yaml
@@ -23,7 +23,7 @@ requirements:
     - lima-core
     - andor3-sdk
   build:
-    - git
+    - make
     - cmake
     - {{ compiler('cxx') }}
   run:
-- 
GitLab


From 232b4a52f4728ffe34115079d70c6826716db913 Mon Sep 17 00:00:00 2001
From: Emmanuel Papillon <papillon@esrf.fr>
Date: Wed, 30 Mar 2022 09:34:34 +0200
Subject: [PATCH 11/24] add make to conda tango recipe

---
 conda/tango/meta.yaml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/conda/tango/meta.yaml b/conda/tango/meta.yaml
index 081eb89..c35b1c3 100644
--- a/conda/tango/meta.yaml
+++ b/conda/tango/meta.yaml
@@ -19,7 +19,7 @@ build:
 requirements:
   build:
     - cmake
-    - git
+    - make
     - lima-core
   run:
     - lima-tango-server
-- 
GitLab


From 76c973566fa19c1e045a0244014152d2be6a3c51 Mon Sep 17 00:00:00 2001
From: Emmanuel Papillon <papillon@esrf.fr>
Date: Wed, 30 Mar 2022 09:53:12 +0200
Subject: [PATCH 12/24] conda build on python 3.7 oonly

---
 conda/camera/conda_build_config.yaml | 2 --
 1 file changed, 2 deletions(-)

diff --git a/conda/camera/conda_build_config.yaml b/conda/camera/conda_build_config.yaml
index 37b36eb..2479ceb 100644
--- a/conda/camera/conda_build_config.yaml
+++ b/conda/camera/conda_build_config.yaml
@@ -5,8 +5,6 @@ c_compiler:
 cxx_compiler:
   - vs2017                     # [win]
 python:
-  - 2.7                        # [linux]
-  - 3.6
   - 3.7
 # This differs from target_platform in that it determines what subdir the compiler
 #    will target, not what subdir the compiler package will be itself.
-- 
GitLab


From bcb95ee47a35d9ca676fdae808b60c0d8fe1d2ce Mon Sep 17 00:00:00 2001
From: Emmanuel Papillon <papillon@esrf.fr>
Date: Wed, 30 Mar 2022 09:57:49 +0200
Subject: [PATCH 13/24] convert pixel size in meters

---
 include/Andor3Camera.h | 2 --
 src/Andor3Camera.cpp   | 2 ++
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/include/Andor3Camera.h b/include/Andor3Camera.h
index ce37d60..e89981e 100644
--- a/include/Andor3Camera.h
+++ b/include/Andor3Camera.h
@@ -62,8 +62,6 @@ namespace lima
       //! @TODO : later on should do a map (string to int and vice-versa) from parsed enum info for the next 3 :
       // In the same order/index as "PreAmpGainControl"
       enum A3_Gain { Gain1 = 0, Gain2 = 1, Gain3 = 2, Gain4 = 3, Gain1_Gain3 = 4, Gain1_Gain4 = 5, Gain2_Gain3 = 6, Gain2_Gain4 = 7 };
-      // The "simple" version :
-      // enum A3_SimpleGain { b11_hi_gain=0, b11_low_gain=1, b16_lh_gain=2, none=31};
 
       const std::vector<std::string> A3_SimpleGainString = {"b11_hi_gain", "b11_low_gain", "b16_lh_gain"};
 
diff --git a/src/Andor3Camera.cpp b/src/Andor3Camera.cpp
index 8e2a887..95abf5e 100644
--- a/src/Andor3Camera.cpp
+++ b/src/Andor3Camera.cpp
@@ -1142,6 +1142,8 @@ lima::Andor3::Camera::getPixelSize(double& sizex, double& sizey)
   DEB_MEMBER_FUNCT();
   getFloat(andor3::PixelWidth, &sizex);
   getFloat(andor3::PixelHeight, &sizey);
+  sizex *= 1e-6;
+  sizey *= 1e-6;
 }
 
 void
-- 
GitLab


From 40840ee769c1d34abb407551bd6a008f04b28f17 Mon Sep 17 00:00:00 2001
From: Emmanuel Papillon <papillon@esrf.fr>
Date: Wed, 30 Mar 2022 10:03:03 +0200
Subject: [PATCH 14/24] remove numpy from conda meta pin andor3-sdk version to
 3.14 (3.15 does not work on USB3 cameras)

---
 conda/camera/meta.yaml | 7 +++----
 1 file changed, 3 insertions(+), 4 deletions(-)

diff --git a/conda/camera/meta.yaml b/conda/camera/meta.yaml
index c8f6329..7d82904 100644
--- a/conda/camera/meta.yaml
+++ b/conda/camera/meta.yaml
@@ -18,19 +18,18 @@ build:
 requirements:
   host:
     - python {{ python }}
-    - numpy
     - sip 4.19.8              # For compatibility with pyqt 5.9.2
     - lima-core
-    - andor3-sdk
+    - andor3-sdk 3.14
   build:
-    - make
     - cmake
+    - make
     - {{ compiler('cxx') }}
   run:
     - python {{ python }}
     - sip >=4.19.4, <=4.19.8  # For compatibility with pyqt 5.9.2
     - {{ pin_compatible('lima-core', max_pin='x.x') }}
-    - andor3-sdk
+    - andor3-sdk 3.14
 
 test:
   requires:
-- 
GitLab


From da149dd402f8283ec3bf2204df3b3c94b2783d42 Mon Sep 17 00:00:00 2001
From: Laurent Claustre <claustre@esrf.fr>
Date: Wed, 30 Mar 2022 11:19:14 +0200
Subject: [PATCH 15/24] add conda-forge as first channel otherwise conda get
 lz4-c from bcu-ci an mpi version made by Sam

---
 .gitlab-ci.yml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index e8a1c81..39a044c 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -14,7 +14,7 @@ stages:
 build-linux:
   <<: *build-conda
   script:
-    - conda build ./conda/camera --prefix-length=80 --output-folder=dist/ --channel=http://bcu-ci.esrf.fr/stable
+    - conda build ./conda/camera --prefix-length=80 --output-folder=dist/ -c conda-forge --channel=http://bcu-ci.esrf.fr/stable
   tags:
     - linux
 
-- 
GitLab


From e286e943865f16c4d598ae0e6ffa9167df01afb8 Mon Sep 17 00:00:00 2001
From: Emmanuel Papillon <papillon@esrf.fr>
Date: Fri, 1 Apr 2022 15:13:21 +0200
Subject: [PATCH 16/24] Convert adc rate fixed enum to strings

---
 include/Andor3Camera.h    | 25 ++++++++++---------
 include/Andor3Interface.h |  6 ++---
 sip/Andor3Camera.sip      | 11 ++++++---
 sip/Andor3Interface.sip   |  6 ++---
 src/Andor3Camera.cpp      | 51 ++++++++++++++-------------------------
 src/Andor3Interface.cpp   |  8 +++---
 tango/Andor3.py           |  6 +----
 7 files changed, 49 insertions(+), 64 deletions(-)

diff --git a/include/Andor3Camera.h b/include/Andor3Camera.h
index e89981e..7b771b7 100644
--- a/include/Andor3Camera.h
+++ b/include/Andor3Camera.h
@@ -61,26 +61,27 @@ namespace lima
 
       //! @TODO : later on should do a map (string to int and vice-versa) from parsed enum info for the next 3 :
       // In the same order/index as "PreAmpGainControl"
-      enum A3_Gain { Gain1 = 0, Gain2 = 1, Gain3 = 2, Gain4 = 3, Gain1_Gain3 = 4, Gain1_Gain4 = 5, Gain2_Gain3 = 6, Gain2_Gain4 = 7 };
+      enum A3_Gain { Gain1 = 0, 
+                     Gain2 = 1, 
+                     Gain3 = 2, 
+                     Gain4 = 3, 
+                     Gain1_Gain3 = 4, 
+                     Gain1_Gain4 = 5, 
+                     Gain2_Gain3 = 6, 
+                     Gain2_Gain4 = 7,
+      };
 
       const std::vector<std::string> A3_SimpleGainString = {"b11_hi_gain", "b11_low_gain", "b16_lh_gain"};
 
       // In the same order/index as "ElectronicShutteringMode"
       enum A3_ShutterMode { Rolling = 0, Global = 1 };
-      // In the same order/index as "PixelReadoutRate"
-      enum A3_ReadOutRate { MHz10 = 0, MHz100 = 1, MHz200 = 2, MHz280 = 3 };
       // In the same order/index as 'BitDepth'
       enum A3_BitDepth { b11 = 0, b16= 1 };
-      // Gain Mode for Marana detector
-      enum A3_GainMode { FastFrameRate=0, HighDynamicRange=1 };
 
       // The binning system of andor3 :
       enum A3_Binning { B1x1=0, B2x2=1, B3x3=2, B4x4=3, B8x8=4};
       enum A3_PixelEncoding {Mono12=0, Mono12Packed = 1, Mono16=2, Mono32=3};
 
-      // trigger / gate level
-      enum A3_SignalLevel { Normal=0, Inverted=1};
-
       struct SdkFrameDim {       
 	AT_64 width;
 	AT_64 height;
@@ -169,9 +170,10 @@ namespace lima
       void getOutputSignal(std::string &signal) const;
       void getOutputSignalList(std::vector<std::string> &signal_list) const;
 
-      void setAdcRate(A3_ReadOutRate iRate);  // à exporter (avec le get)
-      void getAdcRate(A3_ReadOutRate &oRate) const;
-      void getAdcRateString(std::string &oRateString) const;
+      void setAdcRate(std::string adc_rate);
+      void getAdcRate(std::string &adc_rate) const;
+      void getAdcRateList(std::vector<std::string> &adc_rate_list) const;
+
       void setElectronicShutterMode(A3_ShutterMode iMode);  // à exporter (avec le get)
       void getElectronicShutterMode(A3_ShutterMode &oMode) const;
       void getElectronicShutterModeString(std::string &oModeString) const;
@@ -309,7 +311,6 @@ namespace lima
       int                         m_camera_number;
       AT_H                        m_camera_handle;
       A3_Gain                     m_adc_gain;
-      A3_ReadOutRate	          m_adc_rate;
       A3_ShutterMode		  m_electronic_shutter_mode;
       A3_BitDepth                 m_bit_depth;
       bool                        m_cooler;
diff --git a/include/Andor3Interface.h b/include/Andor3Interface.h
index 047983c..c4624f0 100644
--- a/include/Andor3Interface.h
+++ b/include/Andor3Interface.h
@@ -74,9 +74,9 @@ namespace lima
       virtual void		setSimpleGain(std::string iGain);
       virtual void		getSimpleGain(std::string &oGain) const;
       virtual void		getSimpleGainList(std::vector<std::string> &gain_list) const;
-      virtual void		setAdcRate(Camera::A3_ReadOutRate iRate);
-      virtual void		getAdcRate(Camera::A3_ReadOutRate &oRate) const;
-      virtual void		getAdcRateString(std::string &oRateString) const;
+      virtual void		setAdcRate(std::string iRate);
+      virtual void		getAdcRate(std::string &oRate) const;
+      virtual void		getAdcRateList(std::vector<std::string> &oRateList) const;
       virtual void		setElectronicShutterMode(Camera::A3_ShutterMode iMode);
       virtual void		getElectronicShutterMode(Camera::A3_ShutterMode &oMode) const;
       virtual void		getElectronicShutterModeString(std::string &oModeString) const;
diff --git a/sip/Andor3Camera.sip b/sip/Andor3Camera.sip
index af9e834..4117dea 100644
--- a/sip/Andor3Camera.sip
+++ b/sip/Andor3Camera.sip
@@ -33,7 +33,6 @@ namespace Andor3
 
     enum A3_Gain { Gain1 = 0, Gain2 = 1, Gain3 = 2, Gain4 = 3, Gain1_Gain3 = 4, Gain1_Gain4 = 5, Gain2_Gain3 = 6, Gain2_Gain4 = 7 };
     enum A3_ShutterMode { Rolling = 0, Global = 1 };
-    enum A3_ReadOutRate { MHz10 = 0, MHz100 = 1, MHz200 = 2, MHz280 = 3 };
     enum A3_BitDepth { b11 = 0, b16= 1 };
 //    enum A3_TriggerMode { Internal = 0, ExternalLevelTransition = 1, ExternalStart = 2, ExternalExposure = 3, Software = 4, Advanced = 5, External = 6 };
     enum A3_Binning { B1x1=0, B2x2=1, B3x3=2, B4x4=3, B8x8=4};
@@ -104,17 +103,21 @@ namespace Andor3
    void setAdcGain(A3_Gain iGain /In/ );
    void getAdcGain(A3_Gain &oGain /Out/ ) const;
    void getAdcGainString(std::string &oGainString /Out/ ) const;
-   void setAdcRate(A3_ReadOutRate iRate /In/ );
-   void getAdcRate(A3_ReadOutRate &oRate /Out/ ) const;
-   void getAdcRateString(std::string &oRateString /Out/ ) const;
+
+   void setAdcRate(std::string adc_rate /In/ );
+   void getAdcRate(std::string &adc_rate /Out/ ) const;
+   void getAdcRateList(std::vector<std::string> &adc_rate_list /Out/ ) const;
+
    void setElectronicShutterMode(A3_ShutterMode iMode /In/ );
    void getElectronicShutterMode(A3_ShutterMode &oMode /Out/ ) const;
    void getElectronicShutterModeString(std::string &oModeString /Out/) const;
+
    void setBitDepth(A3_BitDepth iMode /In/ );
    void getBitDepth(A3_BitDepth &oMode /Out/ ) const;
    void getBitDepthString(std::string &oDepthString /Out/ ) const;
    void getPxEncodingString(std::string &oPxEncoding /Out/ ) const;
    void getTriggerModeString(std::string &oModeString /Out/ ) const;
+
    void setTemperatureSP(double temp /In/ );
    void getTemperatureSP(double& temp /Out/ ) const;
    void getTemperature(double& temp /Out/ ) const;
diff --git a/sip/Andor3Interface.sip b/sip/Andor3Interface.sip
index 270616b..194cd4e 100644
--- a/sip/Andor3Interface.sip
+++ b/sip/Andor3Interface.sip
@@ -53,9 +53,9 @@ namespace Andor3
     virtual void		setSimpleGain(std::string iGain /In/ );
     virtual void		getSimpleGain(std::string &oGain /Out/ ) const;
     virtual void		getSimpleGainList(std::vector<std::string> &gain_list /Out/ ) const;
-    virtual void		setAdcRate(Andor3::Camera::A3_ReadOutRate iRate /In/ );
-    virtual void		getAdcRate(Andor3::Camera::A3_ReadOutRate &oRate /Out/ ) const;
-    virtual void		getAdcRateString(std::string &oRateString /Out/ ) const;
+    virtual void		setAdcRate(std::string iRate /In/ );
+    virtual void		getAdcRate(std::string &oRate /Out/ ) const;
+    virtual void		getAdcRateList(std::vector<std::string> &oRateList /Out/ ) const;
     virtual void		setElectronicShutterMode(Andor3::Camera::A3_ShutterMode iMode /In/ );
     virtual void		getElectronicShutterMode(Andor3::Camera::A3_ShutterMode &oMode /Out/ ) const;
     virtual void		getElectronicShutterModeString(std::string &oModeString /Out/ ) const;
diff --git a/src/Andor3Camera.cpp b/src/Andor3Camera.cpp
index 95abf5e..3a3a7b9 100644
--- a/src/Andor3Camera.cpp
+++ b/src/Andor3Camera.cpp
@@ -168,7 +168,6 @@ m_bitflow_path(bitflow_path),
 m_camera_number(camera_number),
 m_camera_handle(AT_HANDLE_UNINITIALISED),
 m_adc_gain(Gain1_Gain4),
-m_adc_rate(MHz100),
 m_electronic_shutter_mode(Rolling),
 m_bit_depth(b16),
 m_trig_mode(IntTrig),
@@ -1183,13 +1182,10 @@ lima::Andor3::Camera::initialiseController()
 {
   DEB_MEMBER_FUNCT();
   A3_BitDepth		the_bd = m_bit_depth;
-  A3_ReadOutRate	the_rate = m_adc_rate;
   
   // Carefully crafting the order, since some are affecting others...
   setElectronicShutterMode(m_electronic_shutter_mode);
   setTrigMode(m_trig_mode);
-  //setSimpleGain(the_simple_gain);
-  setAdcRate(the_rate);
   setBitDepth(the_bd);
   setCooler(m_cooler);
   initTemperature();
@@ -1277,43 +1273,32 @@ lima::Andor3::Camera::getAdcGainString(std::string &oGainString) const
 
 
 void
-lima::Andor3::Camera::setAdcRate(A3_ReadOutRate iRate)
+lima::Andor3::Camera::setAdcRate(std::string adc_rate)
 {
   DEB_MEMBER_FUNCT();
-  if ( m_real_camera ) {
-    int the_rate;
-    setEnumIndex(andor3::PixelReadoutRate, iRate);
-    getEnumIndex(andor3::PixelReadoutRate, &the_rate);
-    m_adc_rate = static_cast<A3_ReadOutRate>(the_rate);
-    if ( m_adc_rate != iRate ) {
-      DEB_ERROR() << "Proof-reading the ADC readout rate :"
-      << "\n\tGot " << m_adc_rate << " back,"
-      << "\n\twhile requesting " << iRate;
-    }
-  }
-  else {
-    int the_rate;
-    setEnumIndex(andor3::PixelReadoutRate, 0);
-    getEnumIndex(andor3::PixelReadoutRate, &the_rate);
-    m_adc_rate = static_cast<A3_ReadOutRate>(the_rate);
-    DEB_TRACE() << "The SIMCAM has only one rate setting (550MHz), making sure that's what we are doing now";
-  }
+  THROW_IF_NOT_SUCCESS(setEnumString(andor3::PixelReadoutRate, adc_rate),
+                       "Failed to set ADC Pixel Rate")
 }
 
 void
-lima::Andor3::Camera::getAdcRate(A3_ReadOutRate &oRate) const
+lima::Andor3::Camera::getAdcRate(std::string &adc_rate) const
 {
   DEB_MEMBER_FUNCT();
-//  int the_rate;
-//  getEnumIndex(andor3::PixelReadoutRate, &the_rate);
-//  oRate = static_cast<A3_ReadOutRate>(the_rate);
-  oRate = m_adc_rate;
+  getEnumString(andor3::PixelReadoutRate, adc_rate);
 }
 
 void
-lima::Andor3::Camera::getAdcRateString(std::string &oRateString) const
+lima::Andor3::Camera::getAdcRateList(std::vector<std::string> &adc_rate_list) const
 {
-  getEnumString(andor3::PixelReadoutRate, oRateString);
+  int		enum_count;
+  AT_WC		s_value[1024];
+  
+  AT_GetEnumCount(m_camera_handle, andor3::PixelReadoutRate, &enum_count);
+
+  for (int idx=0; enum_count != idx; ++idx) {
+    AT_GetEnumStringByIndex(m_camera_handle, andor3::PixelReadoutRate, idx, s_value, 1024);
+    adc_rate_list.push_back(WStringToString(s_value));
+  }
 }
 
 void
@@ -1330,13 +1315,13 @@ lima::Andor3::Camera::setElectronicShutterMode(A3_ShutterMode iMode)
     << "\n\twhile requesting " << iMode;
   }
   // Setting the trigger mode might change the ADCGain and ADCRate :
-  int		the_rate;
+  std::string	the_rate;
   std::string	the_gain;
  
   getSimpleGain(the_gain); 
-  getEnumIndex(andor3::PixelReadoutRate, &the_rate);
+  getAdcRate(the_rate);
   setSimpleGain(the_gain);
-  setAdcRate(static_cast<A3_ReadOutRate>(the_rate));
+  setAdcRate(the_rate);
 }
 
 void
diff --git a/src/Andor3Interface.cpp b/src/Andor3Interface.cpp
index 59b6d1c..98e6274 100644
--- a/src/Andor3Interface.cpp
+++ b/src/Andor3Interface.cpp
@@ -214,7 +214,7 @@ lima::Andor3::Interface::getSimpleGainList(std::vector<std::string> &gain_list)
 
 
 void
-lima::Andor3::Interface::setAdcRate(Camera::A3_ReadOutRate iRate)
+lima::Andor3::Interface::setAdcRate(std::string iRate)
 {
   DEB_MEMBER_FUNCT();
   m_cam.setAdcRate(iRate);
@@ -222,17 +222,17 @@ lima::Andor3::Interface::setAdcRate(Camera::A3_ReadOutRate iRate)
 }
 
 void
-lima::Andor3::Interface::getAdcRate(Camera::A3_ReadOutRate &oRate) const
+lima::Andor3::Interface::getAdcRate(std::string &oRate) const
 {
   DEB_MEMBER_FUNCT();
   m_cam.getAdcRate(oRate);
 }
 
 void
-lima::Andor3::Interface::getAdcRateString(std::string &oRateString) const
+lima::Andor3::Interface::getAdcRateList(std::vector<std::string> &oRateList) const
 {
   DEB_MEMBER_FUNCT();
-  m_cam.getAdcRateString(oRateString);
+  m_cam.getAdcRateList(oRateList);
 }
 
 void
diff --git a/tango/Andor3.py b/tango/Andor3.py
index f1b7c98..4eb4ba8 100644
--- a/tango/Andor3.py
+++ b/tango/Andor3.py
@@ -80,11 +80,7 @@ class Andor3(PyTango.Device_4Impl):
         PyTango.Device_4Impl.__init__(self,cl,name)
         # dictionnaries to be used with AttrHelper.get_attr_4u
         self.__AdcGain = andor_list2dict(_Andor3Camera.getSimpleGainList())
-        self.__AdcRate = {'MHZ10':  _Andor3Camera.MHz10,
-                          'MHZ100': _Andor3Camera.MHz100,
-                          'MHZ200': _Andor3Camera.MHz200,
-                          'MHZ280': _Andor3Camera.MHz280,
-                          }
+        self.__AdcRate = andor_list2dict(_Andor3Camera.getAdcRateList())
         self.__Cooler = {'ON':  True, 'OFF': False}
         self.__ElectronicShutterMode = {'ROLLING': _Andor3Camera.Rolling,
                                         'GLOBAL': _Andor3Camera.Global,
-- 
GitLab


From 31cecb739b73079cfb8a272a7e1dc9732aa62e70 Mon Sep 17 00:00:00 2001
From: Emmanuel Papillon <papillon@esrf.fr>
Date: Fri, 1 Apr 2022 15:35:12 +0200
Subject: [PATCH 17/24]  throw error if setting fan_speed/output_signal fails

---
 src/Andor3Camera.cpp | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/src/Andor3Camera.cpp b/src/Andor3Camera.cpp
index 3a3a7b9..1e71356 100644
--- a/src/Andor3Camera.cpp
+++ b/src/Andor3Camera.cpp
@@ -1444,7 +1444,8 @@ lima::Andor3::Camera::setOutputSignal(std::string iSignal)
 {
   DEB_MEMBER_FUNCT();
   if ( propImplemented(andor3::AuxiliaryOutSource) ) {
-    setEnumString(andor3::AuxiliaryOutSource, iSignal);
+    THROW_IF_NOT_SUCCESS(setEnumString(andor3::AuxiliaryOutSource, iSignal),
+                         "Failed to set output signal");
   }
   else {
     DEB_TRACE() << "The camera has no fan speed setting... Do nothing !";
@@ -1660,7 +1661,8 @@ lima::Andor3::Camera::setFanSpeed(std::string fan_speed)
 {
   DEB_MEMBER_FUNCT();
   if ( propImplemented(andor3::FanSpeed) ) {
-    setEnumString(andor3::FanSpeed, fan_speed);
+    THROW_IF_NOT_SUCCESS(setEnumString(andor3::FanSpeed, fan_speed),
+                        "Failed to set fan speed");
   }
   else {
     DEB_TRACE() << "The camera has no fan speed setting... Do nothing !";
-- 
GitLab


From f153b0130f950596867143a4603f5f707abf4567 Mon Sep 17 00:00:00 2001
From: Emmanuel Papillon <papillon@esrf.fr>
Date: Fri, 1 Apr 2022 16:22:22 +0200
Subject: [PATCH 18/24] Convert electronic shutter mode to string list intead
 of enum. Some cameras have only Rolling while others also have Global

---
 include/Andor3Camera.h    | 21 ++++++++---------
 include/Andor3Interface.h |  6 ++---
 sip/Andor3Camera.sip      |  8 +++----
 sip/Andor3Interface.sip   |  6 ++---
 src/Andor3Camera.cpp      | 47 +++++++++++++++++++++------------------
 src/Andor3Interface.cpp   |  8 +++----
 tango/Andor3.py           | 10 ++++-----
 7 files changed, 53 insertions(+), 53 deletions(-)

diff --git a/include/Andor3Camera.h b/include/Andor3Camera.h
index 7b771b7..2d6c1bf 100644
--- a/include/Andor3Camera.h
+++ b/include/Andor3Camera.h
@@ -73,8 +73,9 @@ namespace lima
 
       const std::vector<std::string> A3_SimpleGainString = {"b11_hi_gain", "b11_low_gain", "b16_lh_gain"};
 
-      // In the same order/index as "ElectronicShutteringMode"
-      enum A3_ShutterMode { Rolling = 0, Global = 1 };
+      // Rolling Shutter mode
+      const std::string RollingShutterMode = "Rolling";
+
       // In the same order/index as 'BitDepth'
       enum A3_BitDepth { b11 = 0, b16= 1 };
 
@@ -174,21 +175,22 @@ namespace lima
       void getAdcRate(std::string &adc_rate) const;
       void getAdcRateList(std::vector<std::string> &adc_rate_list) const;
 
-      void setElectronicShutterMode(A3_ShutterMode iMode);  // à exporter (avec le get)
-      void getElectronicShutterMode(A3_ShutterMode &oMode) const;
-      void getElectronicShutterModeString(std::string &oModeString) const;
+      void setElectronicShutterMode(std::string shut_mode);
+      void getElectronicShutterMode(std::string &shut_mode) const;
+      void getElectronicShutterModeList(std::vector<std::string> &shut_mode_list) const;
+
       void setBitDepth(A3_BitDepth iMode);
       void getBitDepth(A3_BitDepth &oMode) const;
       void getBitDepthString(std::string &oDepthString) const;
       void getPxEncoding(A3_PixelEncoding &oPxEncoding) const;
       void getPxEncodingString(std::string &oPxEncoding) const;
       void getTriggerModeString(std::string &oModeString) const;
-      void setTemperatureSP(double temp);  // à exporter (avec le get)
+      void setTemperatureSP(double temp);
       void getTemperatureSP(double& temp) const;
-      void getTemperature(double& temp) const;   // à exporter (read-only)
-      void setCooler(bool flag);					 // à exporter (avec le get)
+      void getTemperature(double& temp) const;
+      void setCooler(bool flag);
       void getCooler(bool& flag) const;
-      void getCoolingStatus(std::string& status) const;  // à exporter (read-only)
+      void getCoolingStatus(std::string& status) const;
       
       void setBufferOverflow(bool i_overflow);
       void getBufferOverflow(bool &o_overflow) const;
@@ -311,7 +313,6 @@ namespace lima
       int                         m_camera_number;
       AT_H                        m_camera_handle;
       A3_Gain                     m_adc_gain;
-      A3_ShutterMode		  m_electronic_shutter_mode;
       A3_BitDepth                 m_bit_depth;
       bool                        m_cooler;
       double                      m_temperature_sp;
diff --git a/include/Andor3Interface.h b/include/Andor3Interface.h
index c4624f0..0a1be8f 100644
--- a/include/Andor3Interface.h
+++ b/include/Andor3Interface.h
@@ -77,9 +77,9 @@ namespace lima
       virtual void		setAdcRate(std::string iRate);
       virtual void		getAdcRate(std::string &oRate) const;
       virtual void		getAdcRateList(std::vector<std::string> &oRateList) const;
-      virtual void		setElectronicShutterMode(Camera::A3_ShutterMode iMode);
-      virtual void		getElectronicShutterMode(Camera::A3_ShutterMode &oMode) const;
-      virtual void		getElectronicShutterModeString(std::string &oModeString) const;
+      virtual void		setElectronicShutterMode(std::string iMode);
+      virtual void		getElectronicShutterMode(std::string &oMode) const;
+      virtual void		getElectronicShutterModeList(std::vector<std::string> &oModeList) const;
 
       virtual void setOverlap(bool i_overlap);
       virtual void getOverlap(bool &o_overlap) const;
diff --git a/sip/Andor3Camera.sip b/sip/Andor3Camera.sip
index 4117dea..7520178 100644
--- a/sip/Andor3Camera.sip
+++ b/sip/Andor3Camera.sip
@@ -32,9 +32,7 @@ namespace Andor3
     enum A3_TypeInfo { Unknown, Int, Float, Bool, Enum, String };
 
     enum A3_Gain { Gain1 = 0, Gain2 = 1, Gain3 = 2, Gain4 = 3, Gain1_Gain3 = 4, Gain1_Gain4 = 5, Gain2_Gain3 = 6, Gain2_Gain4 = 7 };
-    enum A3_ShutterMode { Rolling = 0, Global = 1 };
     enum A3_BitDepth { b11 = 0, b16= 1 };
-//    enum A3_TriggerMode { Internal = 0, ExternalLevelTransition = 1, ExternalStart = 2, ExternalExposure = 3, Software = 4, Advanced = 5, External = 6 };
     enum A3_Binning { B1x1=0, B2x2=1, B3x3=2, B4x4=3, B8x8=4};
     enum A3_PixelEncoding {Mono12=0, Mono12Packed = 1, Mono16=2, Mono32=3};
 
@@ -108,9 +106,9 @@ namespace Andor3
    void getAdcRate(std::string &adc_rate /Out/ ) const;
    void getAdcRateList(std::vector<std::string> &adc_rate_list /Out/ ) const;
 
-   void setElectronicShutterMode(A3_ShutterMode iMode /In/ );
-   void getElectronicShutterMode(A3_ShutterMode &oMode /Out/ ) const;
-   void getElectronicShutterModeString(std::string &oModeString /Out/) const;
+   void setElectronicShutterMode(std::string iMode /In/ );
+   void getElectronicShutterMode(std::string &oMode /Out/ ) const;
+   void getElectronicShutterModeList(std::vector<std::string> &oModeList /Out/) const;
 
    void setBitDepth(A3_BitDepth iMode /In/ );
    void getBitDepth(A3_BitDepth &oMode /Out/ ) const;
diff --git a/sip/Andor3Interface.sip b/sip/Andor3Interface.sip
index 194cd4e..610cd4b 100644
--- a/sip/Andor3Interface.sip
+++ b/sip/Andor3Interface.sip
@@ -56,9 +56,9 @@ namespace Andor3
     virtual void		setAdcRate(std::string iRate /In/ );
     virtual void		getAdcRate(std::string &oRate /Out/ ) const;
     virtual void		getAdcRateList(std::vector<std::string> &oRateList /Out/ ) const;
-    virtual void		setElectronicShutterMode(Andor3::Camera::A3_ShutterMode iMode /In/ );
-    virtual void		getElectronicShutterMode(Andor3::Camera::A3_ShutterMode &oMode /Out/ ) const;
-    virtual void		getElectronicShutterModeString(std::string &oModeString /Out/ ) const;
+    virtual void		setElectronicShutterMode(std::string iMode /In/ );
+    virtual void		getElectronicShutterMode(std::string &oMode /Out/ ) const;
+    virtual void		getElectronicShutterModeList(std::vector<std::string> &oModeList /Out/ ) const;
 
     virtual void setOverlap(bool i_overlap /In/ );
     virtual void getOverlap(bool &o_overlap /Out/ ) const;
diff --git a/src/Andor3Camera.cpp b/src/Andor3Camera.cpp
index 1e71356..9091923 100644
--- a/src/Andor3Camera.cpp
+++ b/src/Andor3Camera.cpp
@@ -168,7 +168,6 @@ m_bitflow_path(bitflow_path),
 m_camera_number(camera_number),
 m_camera_handle(AT_HANDLE_UNINITIALISED),
 m_adc_gain(Gain1_Gain4),
-m_electronic_shutter_mode(Rolling),
 m_bit_depth(b16),
 m_trig_mode(IntTrig),
 m_cooler(true),
@@ -1184,7 +1183,7 @@ lima::Andor3::Camera::initialiseController()
   A3_BitDepth		the_bd = m_bit_depth;
   
   // Carefully crafting the order, since some are affecting others...
-  setElectronicShutterMode(m_electronic_shutter_mode);
+  setElectronicShutterMode(RollingShutterMode);
   setTrigMode(m_trig_mode);
   setBitDepth(the_bd);
   setCooler(m_cooler);
@@ -1302,17 +1301,16 @@ lima::Andor3::Camera::getAdcRateList(std::vector<std::string> &adc_rate_list) co
 }
 
 void
-lima::Andor3::Camera::setElectronicShutterMode(A3_ShutterMode iMode)
+lima::Andor3::Camera::setElectronicShutterMode(std::string shut_mode)
 {
   DEB_MEMBER_FUNCT();
-  int the_mode;
-  setEnumIndex(andor3::ElectronicShutteringMode, iMode);
-  getEnumIndex(andor3::ElectronicShutteringMode, &the_mode);
-  m_electronic_shutter_mode = static_cast<A3_ShutterMode>(the_mode);
-  if ( m_electronic_shutter_mode != iMode ) {
+  std::string set_mode;
+  setEnumString(andor3::ElectronicShutteringMode, shut_mode);
+  getEnumString(andor3::ElectronicShutteringMode, set_mode);
+  if ( set_mode != shut_mode ) {
     DEB_ERROR() << "Proof-reading the electronic shutter mode :"
-    << "\n\tGot " << m_electronic_shutter_mode << " back,"
-    << "\n\twhile requesting " << iMode;
+    << "\n\tGot " << set_mode << " back,"
+    << "\n\twhile requesting " << shut_mode;
   }
   // Setting the trigger mode might change the ADCGain and ADCRate :
   std::string	the_rate;
@@ -1325,19 +1323,24 @@ lima::Andor3::Camera::setElectronicShutterMode(A3_ShutterMode iMode)
 }
 
 void
-lima::Andor3::Camera::getElectronicShutterMode(A3_ShutterMode &oMode) const
+lima::Andor3::Camera::getElectronicShutterMode(std::string &shut_mode) const
 {
   DEB_MEMBER_FUNCT();
-//  int the_mode;
-//  getEnumIndex(andor3::ElectronicShutteringMode, &the_mode);
-//  oMode = static_cast<A3_ShutterMode>(the_mode);
-  oMode = m_electronic_shutter_mode;
+  getEnumString(andor3::ElectronicShutteringMode, shut_mode);
 }
 
 void
-lima::Andor3::Camera::getElectronicShutterModeString(std::string &oModeString) const
+lima::Andor3::Camera::getElectronicShutterModeList(std::vector<std::string> &shut_mode_list) const
 {
-  getEnumStringByIndex(andor3::ElectronicShutteringMode, m_electronic_shutter_mode, oModeString);
+  int		enum_count;
+  AT_WC		s_value[1024];
+  
+  AT_GetEnumCount(m_camera_handle, andor3::ElectronicShutteringMode, &enum_count);
+
+  for (int idx=0; enum_count != idx; ++idx) {
+    AT_GetEnumStringByIndex(m_camera_handle, andor3::ElectronicShutteringMode, idx, s_value, 1024);
+    shut_mode_list.push_back(WStringToString(s_value));
+  }
 }
 
 void
@@ -1712,7 +1715,7 @@ lima::Andor3::Camera::setSimpleGain(std::string i_gain)
   }
   else {
     DEB_TRACE() << "SimplePreAmpGainControl not implemented, emulating it in software";
-    A3_ShutterMode		the_shutter;
+    std::string		the_shutter;
     
     getElectronicShutterMode(the_shutter);
 
@@ -1720,13 +1723,13 @@ lima::Andor3::Camera::setSimpleGain(std::string i_gain)
       setAdcGain(Gain1);
     }
     else if (i_gain == "b11_hi_gain") {
-      if ( Rolling == the_shutter )
+      if ( RollingShutterMode == the_shutter )
         setAdcGain(Gain4);
       else
         setAdcGain(Gain3);
     }
     else if (i_gain == "b16_lh_gain") {
-      if ( Rolling == the_shutter )
+      if ( RollingShutterMode == the_shutter )
         setAdcGain(Gain1_Gain4);
       else
         setAdcGain(Gain1_Gain3);
@@ -1757,12 +1760,12 @@ lima::Andor3::Camera::getSimpleGain(std::string &o_gain) const
     DEB_TRACE() << "SimplePreAmpGainControl not implemented, emulating it in software";
 
     A3_Gain		the_gain;
-    A3_ShutterMode	the_shutter;
+    std::string 	the_shutter;
     
     getAdcGain(the_gain);
     getElectronicShutterMode(the_shutter);
 
-    if ( Rolling == the_shutter ) {
+    if ( RollingShutterMode == the_shutter ) {
       switch (the_gain) {
         case Gain1:
           o_gain = "b11_low_gain";
diff --git a/src/Andor3Interface.cpp b/src/Andor3Interface.cpp
index 98e6274..b37e450 100644
--- a/src/Andor3Interface.cpp
+++ b/src/Andor3Interface.cpp
@@ -236,7 +236,7 @@ lima::Andor3::Interface::getAdcRateList(std::vector<std::string> &oRateList) con
 }
 
 void
-lima::Andor3::Interface::setElectronicShutterMode(Camera::A3_ShutterMode iMode)
+lima::Andor3::Interface::setElectronicShutterMode(std::string iMode)
 {
   DEB_MEMBER_FUNCT();
   m_cam.setElectronicShutterMode(iMode);
@@ -244,17 +244,17 @@ lima::Andor3::Interface::setElectronicShutterMode(Camera::A3_ShutterMode iMode)
 }
 
 void
-lima::Andor3::Interface::getElectronicShutterMode(Camera::A3_ShutterMode &oMode) const
+lima::Andor3::Interface::getElectronicShutterMode(std::string &oMode) const
 {
   DEB_MEMBER_FUNCT();
   m_cam.getElectronicShutterMode(oMode);
 }
 
 void
-lima::Andor3::Interface::getElectronicShutterModeString(std::string &oModeString) const
+lima::Andor3::Interface::getElectronicShutterModeList(std::vector<std::string> &oModeList) const
 {
   DEB_MEMBER_FUNCT();
-  m_cam.getElectronicShutterModeString(oModeString);
+  m_cam.getElectronicShutterModeList(oModeList);
 }
 
 void
diff --git a/tango/Andor3.py b/tango/Andor3.py
index 4eb4ba8..e8fe3e4 100644
--- a/tango/Andor3.py
+++ b/tango/Andor3.py
@@ -81,10 +81,8 @@ class Andor3(PyTango.Device_4Impl):
         # dictionnaries to be used with AttrHelper.get_attr_4u
         self.__AdcGain = andor_list2dict(_Andor3Camera.getSimpleGainList())
         self.__AdcRate = andor_list2dict(_Andor3Camera.getAdcRateList())
+        self.__ElectronicShutterMode = andor_list2dict(_Andor3Camera.getElectronicShutterModeList())
         self.__Cooler = {'ON':  True, 'OFF': False}
-        self.__ElectronicShutterMode = {'ROLLING': _Andor3Camera.Rolling,
-                                        'GLOBAL': _Andor3Camera.Global,
-                                        }
         self.__Overlap = {'ON':  True, 'OFF': False}
         self.__SpuriousNoiseFilter = {'ON':  True, 'OFF': False}
         self.__GateInverted = { 'YES': True, 'NO': False }
@@ -261,10 +259,10 @@ class Andor3Class(PyTango.DeviceClass):
           PyTango.SCALAR,
           PyTango.READ],
          {
-             'label':'Fast trigger mode, see manual for usage',
+             'label':'Cooling status',
              'unit': 'N/A',
              'format': '',
-             'description': '0-OFF / 1-ON',
+             'description': 'Cooling status',
              }],
         'adc_gain':
         [[PyTango.DevString,
@@ -304,7 +302,7 @@ class Andor3Class(PyTango.DeviceClass):
             'label':'Fan speed',
             'unit': 'N/A',
             'format': '',
-            'description': 'Fan speed, off, low or High',
+            'description': 'Fan speed setting',
             }],
         'frame_rate':
         [[PyTango.DevDouble,
-- 
GitLab


From e46c2f3ecb70b90eba8c75f88cda6ae74416f3bf Mon Sep 17 00:00:00 2001
From: Emmanuel Papillon <papillon@esrf.fr>
Date: Fri, 1 Apr 2022 16:37:59 +0200
Subject: [PATCH 19/24] Introduce getEnumStringList to get the list of possible
 string values for a given andor feature.

---
 include/Andor3Camera.h |  1 +
 src/Andor3Camera.cpp   | 71 ++++++++++++++++--------------------------
 2 files changed, 28 insertions(+), 44 deletions(-)

diff --git a/include/Andor3Camera.h b/include/Andor3Camera.h
index 2d6c1bf..bf6971d 100644
--- a/include/Andor3Camera.h
+++ b/include/Andor3Camera.h
@@ -266,6 +266,7 @@ namespace lima
       int getEnumIndex(const AT_WC* Feature, int* Value) const;
       int setEnumString(const AT_WC* Feature, std::string Value);
       int getEnumString(const AT_WC* Feature, std::string& Value) const;
+      int getEnumStringList(const AT_WC* Feature, std::vector<std::string> &ValueList) const;
       int getEnumCount(AT_H Hndl,const  AT_WC* Feature, int* Count) const;
       int isEnumIndexAvailable(const AT_WC* Feature, int Index, bool* Available) const;
       int isEnumIndexImplemented(const AT_WC* Feature, int Index, bool* Implemented) const;
diff --git a/src/Andor3Camera.cpp b/src/Andor3Camera.cpp
index 9091923..ebea63a 100644
--- a/src/Andor3Camera.cpp
+++ b/src/Andor3Camera.cpp
@@ -1289,15 +1289,8 @@ lima::Andor3::Camera::getAdcRate(std::string &adc_rate) const
 void
 lima::Andor3::Camera::getAdcRateList(std::vector<std::string> &adc_rate_list) const
 {
-  int		enum_count;
-  AT_WC		s_value[1024];
-  
-  AT_GetEnumCount(m_camera_handle, andor3::PixelReadoutRate, &enum_count);
-
-  for (int idx=0; enum_count != idx; ++idx) {
-    AT_GetEnumStringByIndex(m_camera_handle, andor3::PixelReadoutRate, idx, s_value, 1024);
-    adc_rate_list.push_back(WStringToString(s_value));
-  }
+  DEB_MEMBER_FUNCT();
+  getEnumStringList(andor3::PixelReadoutRate, adc_rate_list);
 }
 
 void
@@ -1332,15 +1325,8 @@ lima::Andor3::Camera::getElectronicShutterMode(std::string &shut_mode) const
 void
 lima::Andor3::Camera::getElectronicShutterModeList(std::vector<std::string> &shut_mode_list) const
 {
-  int		enum_count;
-  AT_WC		s_value[1024];
-  
-  AT_GetEnumCount(m_camera_handle, andor3::ElectronicShutteringMode, &enum_count);
-
-  for (int idx=0; enum_count != idx; ++idx) {
-    AT_GetEnumStringByIndex(m_camera_handle, andor3::ElectronicShutteringMode, idx, s_value, 1024);
-    shut_mode_list.push_back(WStringToString(s_value));
-  }
+  DEB_MEMBER_FUNCT();
+  getEnumStringList(andor3::ElectronicShutteringMode, shut_mode_list);
 }
 
 void
@@ -1471,15 +1457,8 @@ lima::Andor3::Camera::getOutputSignal(std::string &oSignal) const
 void
 lima::Andor3::Camera::getOutputSignalList(std::vector<std::string> &signal_list) const
 {
-  int		enum_count;
-  std::string	s_value;
-  
-  AT_GetEnumCount(m_camera_handle, andor3::AuxiliaryOutSource, &enum_count);
-
-  for (int idx=0; enum_count != idx; ++idx) {
-    getEnumStringByIndex(andor3::AuxiliaryOutSource, idx, s_value);
-    signal_list.push_back(s_value);
-  }
+  DEB_MEMBER_FUNCT();
+  getEnumStringList(andor3::AuxiliaryOutSource, signal_list);
 }
 
 //-----------------------------------------------------
@@ -1648,15 +1627,8 @@ lima::Andor3::Camera::getBufferOverflow(bool &o_overflow) const
 void
 lima::Andor3::Camera::getFanSpeedList(std::vector<std::string> &fan_speed_list) const
 {
-  int		enum_count;
-  AT_WC		s_value[1024];
-  
-  AT_GetEnumCount(m_camera_handle, andor3::FanSpeed, &enum_count);
-
-  for (int idx=0; enum_count != idx; ++idx) {
-    AT_GetEnumStringByIndex(m_camera_handle, andor3::FanSpeed, idx, s_value, 1024);
-    fan_speed_list.push_back(WStringToString(s_value));
-  }
+  DEB_MEMBER_FUNCT();
+  getEnumStringList(andor3::FanSpeed, fan_speed_list);
 }
 
 void
@@ -1808,14 +1780,7 @@ lima::Andor3::Camera::getSimpleGainList(std::vector<std::string> &gain_list) con
 {
   DEB_MEMBER_FUNCT();
   if ( propImplemented(andor3::SimplePreAmpGainControl) ) {
-    int		enum_count;
-    std::string	s_value;
-    AT_GetEnumCount(m_camera_handle, andor3::SimplePreAmpGainControl, &enum_count);
-
-    for (int idx=0; enum_count != idx; ++idx) {
-      getEnumStringByIndex(andor3::SimplePreAmpGainControl, idx, s_value);
-      gain_list.push_back(s_value);
-    }
+    getEnumStringList(andor3::SimplePreAmpGainControl, gain_list);
   }
   else {
     DEB_TRACE() << "SimplePreAmpGainControl not implemented, emulating it in software";
@@ -2419,6 +2384,24 @@ lima::Andor3::Camera::getEnumString(const AT_WC* Feature, std::string& Value) co
   return ierr;
 }
 
+int
+lima::Andor3::Camera::getEnumStringList(const AT_WC* Feature, std::vector<std::string> &value_list) const
+{
+  int		ierr, enum_count;
+  AT_WC		s_value[1024];
+  
+  ierr = AT_GetEnumCount(m_camera_handle, Feature, &enum_count);
+  if (AT_SUCCESS != ierr)
+    return ierr;
+
+  for (int idx=0; enum_count != idx; ++idx) {
+    ierr = AT_GetEnumStringByIndex(m_camera_handle, Feature, idx, s_value, 1024);
+    if (AT_SUCCESS != ierr)
+      return ierr;
+    value_list.push_back(WStringToString(s_value));
+  }
+}
+
 int
 lima::Andor3::Camera::getEnumCount(AT_H m_camera_handle,const  AT_WC* Feature, int* Count) const
 {
-- 
GitLab


From d00fdba11af7c354ff67187448c5c568ba9b935a Mon Sep 17 00:00:00 2001
From: Emmanuel Papillon <papillon@esrf.fr>
Date: Mon, 4 Apr 2022 16:57:53 +0200
Subject: [PATCH 20/24] add a serial_number to camera initialisation: if
 serial_number is set, try to find camera with the correct serial number if
 serial_number not set, use the first real camera connected if serial_number
 set to "SIMULATION", use a simulated camera

this allow to have 2 servers on the same PC, specifying the serial_number
for each camera.
---
 include/Andor3Camera.h |  2 +-
 sip/Andor3Camera.sip   |  2 +-
 src/Andor3Camera.cpp   | 77 ++++++++++++++++++++++++++++--------------
 tango/Andor3.py        | 10 +++---
 4 files changed, 59 insertions(+), 32 deletions(-)

diff --git a/include/Andor3Camera.h b/include/Andor3Camera.h
index bf6971d..f708ec2 100644
--- a/include/Andor3Camera.h
+++ b/include/Andor3Camera.h
@@ -98,7 +98,7 @@ namespace lima
       
       int getHwBitDepth(int *bit_depth);
       
-      Camera(const std::string& bitflow_path, int camera_number=0);
+      Camera(const std::string& bitflow_path, std::string serial_number="");
       ~Camera();
 
       // Preparing the camera's SDK to acquire frames
diff --git a/sip/Andor3Camera.sip b/sip/Andor3Camera.sip
index 7520178..ed1bf76 100644
--- a/sip/Andor3Camera.sip
+++ b/sip/Andor3Camera.sip
@@ -36,7 +36,7 @@ namespace Andor3
     enum A3_Binning { B1x1=0, B2x2=1, B3x3=2, B4x4=3, B8x8=4};
     enum A3_PixelEncoding {Mono12=0, Mono12Packed = 1, Mono16=2, Mono32=3};
 
-    Camera(const std::string& bitflow_path, int camera_number=0);
+    Camera(const std::string& bitflow_path, std::string serial_number="");
     ~Camera();
 
     void prepareAcq();
diff --git a/src/Andor3Camera.cpp b/src/Andor3Camera.cpp
index ebea63a..db3b331 100644
--- a/src/Andor3Camera.cpp
+++ b/src/Andor3Camera.cpp
@@ -148,7 +148,7 @@ namespace lima {
 }
 
 
-lima::Andor3::Camera::Camera(const std::string& bitflow_path, int camera_number) :
+lima::Andor3::Camera::Camera(const std::string& bitflow_path, std::string serial_number) :
 m_acq_thread(NULL),
 m_cond(),
 m_acq_thread_waiting(true),
@@ -165,7 +165,7 @@ m_detector_serial("un-inited"),
 m_detector_size(1,1),
 m_exp_time(1.0),
 m_bitflow_path(bitflow_path),
-m_camera_number(camera_number),
+m_camera_number(-1),
 m_camera_handle(AT_HANDLE_UNINITIALISED),
 m_adc_gain(Gain1_Gain4),
 m_bit_depth(b16),
@@ -209,30 +209,58 @@ m_maximage_size_cb_active(false)
   }
   pthread_mutex_unlock(&sdkInitMutex);
 
-  // --- Get available cameras and select the choosen one.
+  // --- Get available cameras and found the serial_number asked
+  // --- if serial_number == "SIMULATION", use a simulation camera
+  // --- if serial_number == "", use first real camera
   AT_64 numCameras;
+  int iErr;
   DEB_TRACE() << "Get all attached cameras";
   THROW_IF_NOT_SUCCESS(getIntSystem(andor3::DeviceCount, &numCameras),
 		       "No camera present!");
 
   DEB_TRACE() << "Found "<< numCameras << " camera" << ((numCameras>1)? "s": "");
-  DEB_TRACE() << "Try to set current camera to number " << m_camera_number;
-  
-  if ( m_camera_number < numCameras && m_camera_number >=0 ) {
-    // Getting the m_camera_handle WITH some error checking :
-    THROW_IF_NOT_SUCCESS(AT_Open(m_camera_number, &m_camera_handle),
-			 "Cannot get camera handle");
-  }
-  else {
-    THROW_HW_ERROR(InvalidValue) << "Invalid camera number " 
-				 << m_camera_number << ", there is "
-				 << numCameras << " available";
+  if (serial_number.length() > 0) {
+    DEB_ALWAYS() << "Looking for camera with serial number " << serial_number;
+  }
+  for (int iCam = 0; iCam < numCameras; iCam++) {
+    iErr = AT_Open(iCam, &m_camera_handle);
+    if (iErr != AT_SUCCESS) {
+      DEB_ALWAYS() << "Camera " << iCam << " : Cannot open camera";
+      continue;
+    }
+
+    iErr = getString(andor3::CameraModel, m_detector_model);
+    if (iErr != AT_SUCCESS) {
+      DEB_ALWAYS() << "Camera " << iCam << " : Cannot get camera model";
+      m_detector_model = "unknown";
+    }
+      
+    iErr = getString(andor3::SerialNumber, m_detector_serial);
+    if (iErr != AT_SUCCESS) {
+      DEB_ALWAYS() << "Camera " << iCam << " : Cannot get camera serial";
+      m_detector_serial = "unknown";
+    }
+
+    DEB_ALWAYS() << "Camera " << iCam << " : Model " << m_detector_model << " SerialNumber " << m_detector_serial;
+
+    if ((m_detector_serial == serial_number) ||
+        ((serial_number.compare(0, 4, "SIMU")==0) && (m_detector_model.compare(0, 6, "SIMCAM")==0)) ||
+        ((serial_number.length()==0) && (m_detector_model.compare(0, 5, "SIMCAM")!=0))) {
+      DEB_ALWAYS() << "Found camera asked " << serial_number;
+      m_camera_number = iCam;
+      break;
+    }
+
+    iErr = AT_Close(m_camera_handle);
+    if (iErr != AT_SUCCESS) {
+      DEB_ALWAYS() << "Camera " << iCam << " : Cannot close connection";
+    }
   }
-  
-  // --- Get Camera model (and all other parameters which are not changing during camera setup and usage )
-  THROW_IF_NOT_SUCCESS(getString(andor3::CameraModel, m_detector_model),
-		       "Cannot get camera model");
 
+  if (m_camera_number == -1) {
+    THROW_HW_ERROR(Error) << "Cannot find asked camera serial " << serial_number;
+  }
+    
   // Adding some extra information on the model (more human readable) :
   // DC-152 -> Neo
   if ( ! m_detector_model.compare(0, 6, "DC-152 ")) {
@@ -258,12 +286,11 @@ m_maximage_size_cb_active(false)
   }
   
   if ( m_detector_model != "SIMCAM CMOS" ) {
-    std::string		the_serial, the_fw;
+    std::string	the_fw;
 
-    getSerialNumber(the_serial);
     getFirmwareVersion(the_fw);
     m_real_camera = true;
-    m_detector_model += " (SN : " + the_serial + ", firmware " + the_fw + ")";
+    m_detector_model += " (SN : " + m_detector_serial + ", firmware " + the_fw + ")";
     
     DEB_ALWAYS() << "Camera is ready: type " << m_detector_type << ", model "<< m_detector_model;
   }
@@ -276,8 +303,8 @@ m_maximage_size_cb_active(false)
   }
 
   // --- Get Camera Serial number
-  THROW_IF_NOT_SUCCESS(getString(andor3::SerialNumber, m_detector_serial),
-		       "Cannot get camera serial number");
+//  THROW_IF_NOT_SUCCESS(getString(andor3::SerialNumber, m_detector_serial),
+//		       "Cannot get camera serial number");
 
   // --- Get Camera maximum image size 
   AT_64 xmax, ymax;
@@ -1478,13 +1505,13 @@ lima::Andor3::Camera::initTemperature()
     float value;
 
     m_has_temperature_control = true;
-    DEB_ALWAYS() << "Camera has temperature setpoints pre-defined";
+    DEB_ALWAYS() << "Camera has temperature setpoints pre-defined :";
     getEnumCount(m_camera_handle, andor3::TemperatureControl, &ntemp);
     for (int idx=0; idx != ntemp; ++idx) {
       AT_GetEnumStringByIndex(m_camera_handle, andor3::TemperatureControl, idx, at_string, 255);
       value = std::stof(WStringToString(at_string));
       m_temperature_control_values.push_back(value);
-      DEB_ALWAYS() << "Index " << idx << " Setpoint " << value;
+      DEB_ALWAYS() << " - Setpoint = " << value;
     }
     getEnumIndex(andor3::TemperatureControl, &current_idx);
     m_temperature_sp = m_temperature_control_values[current_idx];
diff --git a/tango/Andor3.py b/tango/Andor3.py
index e8fe3e4..4726d36 100644
--- a/tango/Andor3.py
+++ b/tango/Andor3.py
@@ -193,8 +193,8 @@ class Andor3Class(PyTango.DeviceClass):
         'config_path':
         [PyTango.DevString,
          'configuration path directory', []],
-        'camera_number':
-        [PyTango.DevShort,
+        'serial_number':
+        [PyTango.DevString,
          'Camera number', []],
         'adc_gain':
         [PyTango.DevString,
@@ -412,15 +412,15 @@ from Lima  import Andor3 as Andor3Acq
 _Andor3Camera = None
 _Andor3Interface = None
 
-def get_control(config_path='/users/blissadm/local/Andor3/andor/bitflow', camera_number = '0', **keys) :
+def get_control(config_path='/users/blissadm/local/Andor3/andor/bitflow', serial_number = '', **keys) :
     #properties are passed here as string
     global _Andor3Camera
     global _Andor3Interface
     if _Andor3Camera is None:
         print ('\n\nStarting and configuring the Andor3 camera ...')
-        _Andor3Camera = Andor3Acq.Camera(config_path, int(camera_number))
+        _Andor3Camera = Andor3Acq.Camera(config_path, serial_number)
         _Andor3Interface = Andor3Acq.Interface(_Andor3Camera)
-        print ('\n\nAndor3 Camera #%s (%s:%s) is started'%(camera_number,_Andor3Camera.getDetectorType(),_Andor3Camera.getDetectorModel()))
+        print ('\n\nAndor3 Camera (%s:%s) is started'%(_Andor3Camera.getDetectorType(),_Andor3Camera.getDetectorModel()))
     return Core.CtControl(_Andor3Interface)
 
     
-- 
GitLab


From 6a090c796423199552cb2cc6f216efa1509145e2 Mon Sep 17 00:00:00 2001
From: Emmanuel Papillon <papillon@esrf.fr>
Date: Mon, 4 Apr 2022 17:38:13 +0200
Subject: [PATCH 21/24] use mambabuild in conda

---
 .gitlab-ci.yml | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 39a044c..bb631e7 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -14,7 +14,7 @@ stages:
 build-linux:
   <<: *build-conda
   script:
-    - conda build ./conda/camera --prefix-length=80 --output-folder=dist/ -c conda-forge --channel=http://bcu-ci.esrf.fr/stable
+    - conda mambabuild ./conda/camera --prefix-length=80 --output-folder=dist/ --channel=http://bcu-ci.esrf.fr/stable
   tags:
     - linux
 
@@ -22,7 +22,7 @@ build-noarch:
   <<: *build-conda
   stage: build-noarch
   script:
-    - conda build ./conda/tango --prefix-length=80 --output-folder=dist/ -c tango-controls --channel=http://bcu-ci.esrf.fr/stable
+    - conda mambabuild ./conda/tango --prefix-length=80 --output-folder=dist/ --channel=http://bcu-ci.esrf.fr/stable
   dependencies:
     - build-linux
 
-- 
GitLab


From 39580c77c2a7911f7577f016bec207b221f30dec Mon Sep 17 00:00:00 2001
From: Emmanuel Papillon <papillon@esrf.fr>
Date: Fri, 8 Apr 2022 09:48:24 +0200
Subject: [PATCH 22/24] add python 3.* in conda packages

---
 conda/camera/conda_build_config.yaml | 2 ++
 conda/camera/meta.yaml               | 4 ++--
 2 files changed, 4 insertions(+), 2 deletions(-)

diff --git a/conda/camera/conda_build_config.yaml b/conda/camera/conda_build_config.yaml
index 2479ceb..2188672 100644
--- a/conda/camera/conda_build_config.yaml
+++ b/conda/camera/conda_build_config.yaml
@@ -6,6 +6,8 @@ cxx_compiler:
   - vs2017                     # [win]
 python:
   - 3.7
+  - 3.8
+  - 3.9
 # This differs from target_platform in that it determines what subdir the compiler
 #    will target, not what subdir the compiler package will be itself.
 #    For example, we need a win-64 vs2008_win-32 package, so that we compile win-32
diff --git a/conda/camera/meta.yaml b/conda/camera/meta.yaml
index 7d82904..b68c7dc 100644
--- a/conda/camera/meta.yaml
+++ b/conda/camera/meta.yaml
@@ -18,7 +18,7 @@ build:
 requirements:
   host:
     - python {{ python }}
-    - sip 4.19.8              # For compatibility with pyqt 5.9.2
+    - sip 4.19*
     - lima-core
     - andor3-sdk 3.14
   build:
@@ -27,7 +27,7 @@ requirements:
     - {{ compiler('cxx') }}
   run:
     - python {{ python }}
-    - sip >=4.19.4, <=4.19.8  # For compatibility with pyqt 5.9.2
+    - {{ pin_compatible('sip', min_pin='x.x.x', max_pin='x') }}
     - {{ pin_compatible('lima-core', max_pin='x.x') }}
     - andor3-sdk 3.14
 
-- 
GitLab


From ccab0463a9783042a9256cf23e13ff27b5e63734 Mon Sep 17 00:00:00 2001
From: Emmanuel Papillon <papillon@esrf.fr>
Date: Fri, 8 Apr 2022 09:57:56 +0200
Subject: [PATCH 23/24] add copy-constrcutor in sip

---
 sip/Andor3Interface.sip | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/sip/Andor3Interface.sip b/sip/Andor3Interface.sip
index 610cd4b..a5330e8 100644
--- a/sip/Andor3Interface.sip
+++ b/sip/Andor3Interface.sip
@@ -64,5 +64,8 @@ namespace Andor3
     virtual void getOverlap(bool &o_overlap /Out/ ) const;
     virtual void setSyncTriggering(bool i_sync /In/ );
     virtual void getSyncTriggering(bool &o_sync /Out/ ) const;
+
+  private:
+    Interface(const Andor3::Camera&);
   };
 };
-- 
GitLab


From dfccfafcd311ac2a29850a2acd7568a1f823ae63 Mon Sep 17 00:00:00 2001
From: Emmanuel Papillon <papillon@esrf.fr>
Date: Fri, 8 Apr 2022 10:12:17 +0200
Subject: [PATCH 24/24] bug in sip

---
 sip/Andor3Interface.sip | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/sip/Andor3Interface.sip b/sip/Andor3Interface.sip
index a5330e8..795f608 100644
--- a/sip/Andor3Interface.sip
+++ b/sip/Andor3Interface.sip
@@ -66,6 +66,6 @@ namespace Andor3
     virtual void getSyncTriggering(bool &o_sync /Out/ ) const;
 
   private:
-    Interface(const Andor3::Camera&);
+    Interface(const Andor3::Interface&);
   };
 };
-- 
GitLab