#!/usr/bin/env python
# -*- coding:utf-8 -*- 


##############################################################################
## license :
##============================================================================
##
## File :        Skippy.py
## 
## Project :     SCPI
##
## This file is part of Tango device class.
## 
## Tango is free software: you can redistribute it and/or modify
## it under the terms of the GNU General Public License as published by
## the Free Software Foundation, either version 3 of the License, or
## (at your option) any later version.
## 
## Tango is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
## GNU General Public License for more details.
## 
## You should have received a copy of the GNU General Public License
## along with Tango.  If not, see <http://www.gnu.org/licenses/>.
## 
##
## $Author :      sblanch$
##
## $Revision :    $
##
## $Date :        $
##
## $HeadUrl :     $
##============================================================================
##            This file is generated by POGO
##    (Program Obviously used to Generate tango Object)
##
##        (c) - Software Engineering Group - ESRF
##############################################################################

"""Standard Commands for Programmable Instruments (SCPI) DeviceServer """

__all__ = ["Skippy", "SkippyClass", "main"]

__docformat__ = 'restructuredtext'

import PyTango
import sys
# Add additional import
#----- PROTECTED REGION ID(Skippy.additionnal_import) ENABLED START -----#
import copy
import numpy
from skippylib import AttrExc
from skippylib import Skippy as SkippyObj
import struct
import threading
import time
import traceback
from types import StringType

MINIMUM_RECOVERY_DELAY = 3.0
DEFAULT_RECOVERY_DELAY = 600.0
DEFAULT_ERRORS_THRESHOLD = 1
RECONNECT_THREAD_DELETE_TRIES = 3
#----- PROTECTED REGION END -----#  //  Skippy.additionnal_import

## Device States Description
## OFF : No connection stablished with the instrument.
## ON : Connection stablished with the instrument.
## RUNNING : Connection stablished and active monitoring.
## ALARM : Reported errors from the instrument.
## FAULT : Communication error with the instrument.
## INIT : Initialization stage.
## STANDBY : 

class Skippy (PyTango.Device_4Impl):

    #--------- Add you global variables here --------------------------
    #----- PROTECTED REGION ID(Skippy.global_variables) ENABLED START -----#

    ######
    # section to resolve instrument property ---
    def _buildSkippyObj(self):
        '''Builder of object that will manage the communications with the
           specified instrument in the properties.
           To have this object made only means that this device has recognized
           if the communications will be made using socket connection or using
           the VISA protocol provided by a lower level tango device.
           The expected result of this method is to have the skippy tango
           device in OFF state.
        '''
        self.debug_stream("In _buildSkippyObj()")
        #try:
        self.skippy = None
        try:
            attr2Monitor = self.__str2listProperty(self.MonitoredAttributes)
            self.skippy = SkippyObj(name=self.Instrument,
                                    parent=self,
                                    terminator=self.TxTerminator,
                                    port=self.Port,
                                    baudrate=self.SerialBaudrate,
                                    bytesize=self.SerialBytesize,
                                    parity=self.SerialParity,
                                    stopbits=self.SerialStopbits,
                                    timeout=self.SerialTimeout,
                                    xonxoff=self.SerialXonXoff,
                                    nChannels=self.NumChannels,
                                    nFunctions=self.NumFunctions,
                                    nMultiple=self.NumMultiple,
                                    attrs2Monitor=attr2Monitor)
            self.updateDynamicAttributes()
        except Exception as e:
            self.error_stream("Exception building SkippyObj: %s" % (e))
            traceback.print_exc()
            return False
        return True
    # done section to resolve instrument property ---
    ######

    ######
    # dynamic attributes builder section ---


    def __read_attr_procedure(self, data, fromMonitor=False):
        '''This method is the read_attr_hardware, but we had to distinguish
           between monitoring calls for events than the direct requests to the
           device. This is because, direct requests of monitored attributes
           should not do a real hardware read.
           TODO: as all the readers (external or any of the monitors) will call
           this method, here is the place to implement the priorities.
        '''
        self.skippy._readAttrProcedure(data)

    def doHardwareRead(self, query):
        # return self.__hardwareRead(query)
        return self.skippy.Read(query)

    # def doHardwareWrite(self, cmd):
    #     # self.__hardwareWrite(cmd)
    #     self.skippy.Write(cmd)

    @AttrExc
    def read_attr(self, attr):
        if self.get_state() in [PyTango.DevState.FAULT]:
            # Try to return a quality invalid without knowing yet if the
            # attribute is a number or an string.
            try:
                attr.set_value_date_quality(
                    0, time.time(), PyTango.AttrQuality.ATTR_INVALID)
                return
            except:
                pass
            try:
                attr.set_value_date_quality(
                    "", time.time(), PyTango.AttrQuality.ATTR_INVALID)
                return
            except:
                pass
            return
        attrName = attr.get_name()
        if attrName in self.skippy.attributes:
            attrStruct = self.skippy.attributes[attrName]
            value = attrStruct.lastReadValue
            timestamp = attrStruct.timestamp
            quality = attrStruct.quality
            if attrStruct.dim == 0:
                if value is None:
                    if attrStruct.type in [PyTango.DevString]:
                        value = ""
                    else:
                        value = 0
                    attr.set_value_date_quality(
                        value, time.time(), PyTango.AttrQuality.ATTR_INVALID)
                else:
                    attr.set_value_date_quality(value, timestamp, quality)
            elif attrStruct.dim == 1:
                if value is None:
                    attr.set_value_date_quality([0], time.time(),
                                                PyTango.AttrQuality.
                                                ATTR_INVALID, 1)
                else:
                    attr.set_value_date_quality(value, timestamp, quality,
                                                len(value))
            if attrStruct.isWritable():
                wvalue = attrStruct.lastWriteValue
                if wvalue is not None:
                    attr.set_write_value(wvalue)
                else:
                    attr.set_write_value(value)
                # when there has been no read (yet) avoid the Non-initialised.
        elif attrName.endswith("Step"):
            parentAttrName = attrName.split('Step')[0]
            parentAttrStruct = self.skippy.attributes[parentAttrName]
            value = parentAttrStruct.getRampObj().rampStep
            if value is None:
                attr.set_value_date_quality(0, time.time(),
                                            PyTango.AttrQuality.ATTR_INVALID)
            else:
                attr.set_value(value)
        elif attrName.endswith("StepSpeed"):
            parentAttrName = attrName.split('StepSpeed')[0]
            parentAttrStruct = self.skippy.attributes[parentAttrName]
            value = parentAttrStruct.getRampObj().rampStepSpeed
            if value is None:
                attr.set_value_date_quality(0, time.time(),
                                            PyTango.AttrQuality.ATTR_INVALID)
            else:
                attr.set_value(value)
        else:
            raise AttributeError("Invalid read of the attribute %s"
                                 % (attrName))

    @AttrExc
    def write_attr(self, attr):
        '''The execution of this method starts with three different branches:
           - An instrument attribute to be send. This splits in two branches
             also:
             - Direct write
             - Launch a thread (if not yet) to drive a ramp to the setpoint
           - The other two are the internal ramp attributes
           - Other case, raise an exception
        '''
        if self.get_state() in [PyTango.DevState.FAULT]:
            raise EnvironmentError("Not allowed to write in %s state"
                                   % (self.get_state()))
        attrName = attr.get_name()
        data = []
        attr.get_write_value(data)
        value = data[0]
        if attrName in self.skippy.attributes:
            self.__write_instrument_attr(attr, attrName, value)
        elif attrName.endswith("Step"):
            parentAttrName = attrName.split('Step')[0]
            self.skippy.attributes[parentAttrName].getRampObj().rampStep = value
        elif attrName.endswith("StepSpeed"):
            parentAttrName = attrName.split('StepSpeed')[0]
            self.skippy.attributes[parentAttrName].getRampObj().rampStepSpeed = value
        else:
            raise AttributeError("Invalid write of the attribute %s"
                                 % (attrName))

    def __write_instrument_attr(self, attr, attrName, value):
        self.skippy.attributes[attrName].lastWriteValue = value
        # Normal case, non rampeable attribute
        if not self.skippy.attributes[attrName].isWritable():
            raise AttributeError("%s is not writable attribute"
                                 % (attr.get_name()))
        if not self.skippy.attributes[attrName].isRampeable():
            cmd = self.skippy.attributes[attrName].writeCmd(value)
            # filter the write value if the attribute was configured this way
            if self.skippy.attributes[attrName].hasWriteValues() and \
                    not str(value).upper() in \
                    self.skippy.attributes[attrName].writeValues:
                self.error_stream("In __write_instrument_attr() avoid to "
                                  "send: %s because it is not in %s"
                                  % (cmd,
                                     self.skippy.attributes[attrName].writeValues))
                raise AttributeError("Invalid write value %r of the "
                                     "attribute %s" % (value, attrName))
            else:
                self.info_stream("In __write_instrument_attr() sending: %s "
                                 "= %r" % (attrName, cmd))
                # self.doHardwareWrite(cmd)
                self.skippy.attributes[attrName]._write(cmd)
        else:
            # rampeable but invalid ramp
            rampObj = self.skippy.attributes[attrName].getRampObj()
            rampStep = rampObj.rampStep
            rampStepSpeed = rampObj.rampStepSpeed
            if rampStep in [None, 0.0] or rampStepSpeed in [None, 0.0]:
                self.warn_stream("In __write_instrument_attr() No ramp "
                                 "parameters defined, direct setpoint for %s"
                                 % (attrName))
                cmd = self.skippy.attributes[attrName].writeCmd(value)
                self.info_stream("In __write_instrument_attr() sending: %s"
                                 % (cmd))
                # self.doHardwareWrite(cmd)
                self.skippy.attributes[attrName]._write(cmd)
            else:
                # rampeable and create a thread, if it doesn't exist
                if not self.skippy.attributes[attrName].getRampObj().isRamping():
                    if not rampObj.prepareRamping():
                        self.error_stream("In __write_instrument_attr() "
                                          "ramping procedure cannot be "
                                          "prepared")
                        raise RuntimeError("Ramp construction failed in "
                                           "preparation")
                    if not rampObj.launchRamp():
                        self.error_stream("In __write_instrument_attr() "
                                          "ramping procedure cannot be "
                                          "started")
                        raise RuntimeError("Ramp construction failed in "
                                           "start")
                    self.info_stream("In __write_instrument_attr() launched "
                                     "ramp procedure for %s to setpoint %g"
                                     % (attrName,
                                        self.skippy.attributes[attrName].
                                        lastWriteValue))
                else:
                    self.info_stream("In __write_instrument_attr(), attribute"
                                     "%s already with an ongoing ramp. Final "
                                     "setpoint changed to %g."
                                     % (attrName,
                                        self.skippy.attributes[attrName].
                                        lastWriteValue))
                # no else need because during the ramp the it goes to
                # 'lastWriteValue' and it has been already updated.

    # done dynamic attributes builder section ---
    ######

    ######
    # event manager section ---
    def fireEventsList(self, eventsAttrList):
        timestamp = time.time()
        for attrEvent in eventsAttrList:
            try:
                attrName = attrEvent[0]
                value = attrEvent[1]
                if value == None:
                    value = 0
                    quality = PyTango.AttrQuality.ATTR_INVALID
                elif len(attrEvent) == 3:  # if it specifies quality
                    quality = attrEvent[2]
                else:
                    quality = PyTango.AttrQuality.ATTR_VALID
                self.push_change_event(attrName, value, timestamp, quality)
            except Exception as e:
                self.error_stream("In fireEventsList() Exception with "
                                  "attribute %s (value %s, timestamp %s, "
                                  "quality %s): %s" % (attrEvent[0], value,
                                                       timestamp, quality, e))
    # done event manager section ---
    ######

    ######
    # attribute monitor section ---
    def _checkArginNameAndPeriod(self, argin):
        try:
            self.debug_stream("Checking %s argin" % (argin))
            if type(argin) == str:
                self.debug_stream("%s is an string" % (argin))
                if argin.count('[') == 1 and argin.count(']') == 1:
                    self.debug_stream("%s has brakets" % (argin))
                    lst = argin[argin.index('[')+1:argin.rindex(']')]
                else:
                    self.debug_stream("%s haven't brakets" % (argin))
                    lst = argin
                if lst.count(',') == 1 or lst.count(':') == 1:
                    # attrName,attrPeriod or attrName:attrPeriod or
                    # [attrName,attrPeriod] or [attrName:attrPeriod]
                    self.debug_stream("%s contains attrPeriod" % (argin))
                    if lst.count(',') == 1:
                        attrName, attrPeriod = argin.split(',')
                    elif lst.count(':') == 1:
                        attrName, attrPeriod = argin.split(':')
                    attrPeriod = float(attrPeriod)
                else:  # attrName or [attrName]
                    self.debug_stream("%s contain only the attrName" % (argin))
                    attrName = lst
                    attrPeriod = None
                if attrName.count('\''):
                    attrName = attrName.strip('\'')
                return attrName, attrPeriod
            if type(argin) == list:
                if len(argin) == 1:
                    attrName = argin[0]
                    attrPeriod = None
                elif len(argin) == 2:
                    attrName = argin[0]
                    attrPeriod = float(argin[1])
                else:
                    raise AttributeError("Invalid arguments, use [attrName] "
                                         "or [attrName, attrPeriod]")
                return attrName, attrPeriod
        except Exception as e:
            raise SyntaxError("Invalid arguments, use [attrName] "
                              "or [attrName, attrPeriod] and check reason "
                              "%s" % (e))

    def __appendToAlarmCausingList(self, attrList):
        for attrName in attrList:
            if attrName not in self._alarmDueToMonitoring:
                self._alarmDueToMonitoring.append(attrName)
        self.skippy._change_state_status(rebuild=True)  # self.rebuildStatus()

    def __removeFromAlarmCausingList(self, attrList):
        for attrName in attrList:
            if self._alarmDueToMonitoring.count(attrName):
                self._alarmDueToMonitoring.pop(
                    self._alarmDueToMonitoring.index(attrName))
        self.skippy._change_state_status(rebuild=True)  # self.rebuildStatus()

    def __appendPropertyElement(self, propertyName, element):
        db = PyTango.Database()
        propertiesDict = db.get_device_property(self.get_name(), propertyName)
        self.debug_stream("propertyName was: %r"
                          % (propertiesDict[propertyName]))
        propertiesDict[propertyName].append(element)
        propertyLst = propertiesDict[propertyName]
        propertyStr = self.__list2strProperty(propertyLst)
        propertiesDict[propertyName] = propertyStr
        self.debug_stream("propertyName now: %r"
                          % (propertiesDict[propertyName]))
        db.put_device_property(self.get_name(), propertiesDict)
        return propertyLst

    def __popPropertyElement(self, propertyName, element):
        db = PyTango.Database()
        propertiesDict = db.get_device_property(self.get_name(), propertyName)
        self.debug_stream("propertyName was: %r"
                          % (propertiesDict[propertyName]))
        propertyList = propertiesDict[propertyName][0].split('\n')
        index = None
        try:
            index = propertyList.index(element)
        except:
            # in case is an specially monitored, previous will
            # throw an exception
            for name in propertyList:
                if name.count(':'):
                    # find, for each element with an special period
                    if element == name.split(':')[0]:
                        # if one corresponds
                        index = propertyList.index(name)
                        break
        if index is None:
            self.warning("In __popPropertyElement() %s not found"
                         % (propertyName))
            return propertyList
        self.debug_stream("In __popPropertyElement() removing %s (index %d)"
                          % (propertyName, index))
        propertyList.pop(index)
        propertiesDict[propertyName] = self.__list2strProperty(propertyList)
        db.put_device_property(self.get_name(), propertiesDict)
        return propertyList

    def __list2strProperty(self, lst):
        strLst = ''.join("%s\n" % each for each in lst)
        self.debug_stream("In __list2strProperty(%s): %r" % (lst, strLst))
        return strLst[:-1]

    def __str2listProperty(self, input):
        lst = []
        if isinstance(input, list) or \
                isinstance(input, PyTango.StdStringVector):
            for each in input:
                lst += self.__str2listProperty(each)
        else:
            self.debug_stream("In __str2listProperty(%s) argin is %s" % (input, type(input)))
            return input.split('\n')
        return lst
    #----- done attribute monitor section
    ######

#----- PROTECTED REGION END -----#  //  Skippy.global_variables

    def __init__(self,cl, name):
        PyTango.Device_4Impl.__init__(self,cl,name)
        self.debug_stream("In __init__()")
        Skippy.init_device(self)
        #----- PROTECTED REGION ID(Skippy.__init__) ENABLED START -----#

        #----- PROTECTED REGION END -----#  //  Skippy.__init__
        
    def delete_device(self):
        self.debug_stream("In delete_device()")
        #----- PROTECTED REGION ID(Skippy.delete_device) ENABLED START -----#

        #----- PROTECTED REGION END -----#  //  Skippy.delete_device

    def init_device(self):
        self.debug_stream("In init_device()")
        self.get_device_properties(self.get_device_class())
        self.attr_Idn_read = ''
        self.attr_QueryWindow_read = 0
        self.attr_TimeStampsThreshold_read = 0.0
        self.attr_ReadAfterWrite_read = False
        self.attr_Version_read = ''
        #----- PROTECTED REGION ID(Skippy.init_device) ENABLED START -----#
        if self.get_state() in [PyTango.DevState.FAULT]:
            self.info_stream("Init() call from a fault state")
        else:
            # DS_MODULE = __import__(self.__class__.__module__)
            # kM = dir(DS_MODULE)
            # vM = map(DS_MODULE.__getattribute__, kM)
            self._globals = globals()  # dict(zip(kM, vM))
            # self._globals['self'] = self
            # self._globals['module'] = DS_MODULE
            self._locals = {'self': self}
            # prepare the attribute building
            self.set_change_event('State', True, False)
            self.set_change_event('Status', True, False)
        self._buildSkippyObj()
        #----- PROTECTED REGION END -----#  //  Skippy.init_device

    def always_executed_hook(self):
        # self.debug_stream("In always_excuted_hook()")
        #----- PROTECTED REGION ID(Skippy.always_executed_hook) ENABLED START -----#
        pass
        #----- PROTECTED REGION END -----#  //  Skippy.always_executed_hook

    #-----------------------------------------------------------------------------
    #    Skippy read/write attribute methods
    #-----------------------------------------------------------------------------

    def read_Idn(self, attr):
        self.debug_stream("In read_Idn()")
        #----- PROTECTED REGION ID(Skippy.Idn_read) ENABLED START -----#
        try:
            self.attr_Idn_read = self.skippy.idn
            attr.set_value(self.attr_Idn_read)
        except Exception as e:
            self.error_stream("Couldn't read the IDN attribute: %s" % (e))
            attr.set_value_date_quality("", time.time(),
                                        PyTango.AttrQuality.ATTR_INVALID)
        #----- PROTECTED REGION END -----#  //  Skippy.Idn_read
        
    def is_Idn_allowed(self, attr):
        self.debug_stream("In is_Idn_allowed()")
        if attr==PyTango.AttReqType.READ_REQ:
            state_ok = not(self.get_state() in [PyTango.DevState.OFF,
                PyTango.DevState.FAULT,
                PyTango.DevState.INIT])
        else:
            state_ok = not(self.get_state() in [])
        #----- PROTECTED REGION ID(Skippy.is_Idn_allowed) ENABLED START -----#

        #----- PROTECTED REGION END -----#  //  Skippy.is_Idn_allowed
        return state_ok
        
    def read_QueryWindow(self, attr):
        self.debug_stream("In read_QueryWindow()")
        #----- PROTECTED REGION ID(Skippy.QueryWindow_read) ENABLED START -----#
        try:
            self.attr_QueryWindow_read = self.skippy.queryWindow
            attr.set_value(self.attr_QueryWindow_read)
        except Exception as e:
            self.error_stream("Couldn't read the QueryWindow attribute: %s"
                              % (e))
            attr.set_value_date_quality(0, time.time(),
                                        PyTango.AttrQuality.ATTR_INVALID)
        #----- PROTECTED REGION END -----#  //  Skippy.QueryWindow_read
        
    def write_QueryWindow(self, attr):
        self.debug_stream("In write_QueryWindow()")
        data=attr.get_write_value()
        #----- PROTECTED REGION ID(Skippy.QueryWindow_write) ENABLED START -----#
        if hasattr(self, 'skippy') and self.skippy is not None:
            self.skippy.queryWindow = int(data)
            self.attr_QueryWindow_read = self.skippy.queryWindow
        #----- PROTECTED REGION END -----#  //  Skippy.QueryWindow_write
        
    def read_TimeStampsThreshold(self, attr):
        self.debug_stream("In read_TimeStampsThreshold()")
        #----- PROTECTED REGION ID(Skippy.TimeStampsThreshold_read) ENABLED START -----#
        try:
            self.attr_TimeStampsThreshold_read = \
                self.skippy.timestampsThreshold
            attr.set_value(self.attr_TimeStampsThreshold_read)
        except Exception as e:
            self.error_stream("Couldn't read the TimeStampsThreshold "
                              "attribute: %s" % (e))
            attr.set_value_date_quality(0, time.time(),
                                        PyTango.AttrQuality.ATTR_INVALID)
        #----- PROTECTED REGION END -----#  //  Skippy.TimeStampsThreshold_read
        
    def write_TimeStampsThreshold(self, attr):
        self.debug_stream("In write_TimeStampsThreshold()")
        data=attr.get_write_value()
        #----- PROTECTED REGION ID(Skippy.TimeStampsThreshold_write) ENABLED START -----#
        if hasattr(self, 'skippy') and self.skippy is not None:
            self.skippy.timestampsThreshold = float(data)
            self.attr_TimeStampsThreshold_read = \
                self.skippy.timestampsThreshold
        ## TODO: function of an instrument attribute ---
        #        for a lower limit or to force as unique possibility.
        #----- PROTECTED REGION END -----#  //  Skippy.TimeStampsThreshold_write

    def read_ReadAfterWrite(self, attr):
        self.debug_stream("In read_ReadAfterWrite()")
        #----- PROTECTED REGION ID(Skippy.ReadAfterWrite_read) ENABLED START -----#
        try:
            read_after_write = self.skippy.read_after_write
            if read_after_write is None:
                raise Exception
            self.attr_ReadAfterWrite_read = read_after_write
            attr.set_value(self.attr_ReadAfterWrite_read)
        except Exception as e:
            self.error_stream("Couldn't read the ReadAfterWrite "
                              "attribute: %s" % (e))
            attr.set_value_date_quality(False, time.time(),
                                        PyTango.AttrQuality.ATTR_INVALID)
        #----- PROTECTED REGION END -----#  //  Skippy.ReadAfterWrite_read

    def write_ReadAfterWrite(self, attr):
        self.debug_stream("In write_ReadAfterWrite()")
        data=attr.get_write_value()
        #----- PROTECTED REGION ID(Skippy.ReadAfterWrite_write) ENABLED START -----#
        if hasattr(self, 'skippy') and self.skippy is not None:
            self.skippy.read_after_write = float(data)
            self.attr_ReadAfterWrite_read = \
                self.skippy.read_after_write
        ## TODO: function of an instrument attribute ---
        #        for a lower limit or to force as unique possibility.
        #----- PROTECTED REGION END -----#  //  Skippy.ReadAfterWrite_write

    def read_Version(self, attr):
        self.debug_stream("In read_Version()")
        #----- PROTECTED REGION ID(Skippy.Version_read) ENABLED START -----#
        try:
            self.attr_Version_read = self.skippy.version
            attr.set_value(self.attr_Version_read)
        except Exception as e:
            self.error_stream("Couldn't read the Version attribute: %s" % (e))
            attr.set_value_date_quality("", time.time(),
                                        PyTango.AttrQuality.ATTR_INVALID)
        #----- PROTECTED REGION END -----#  //  Skippy.Version_read
    
        #----- PROTECTED REGION ID(Skippy.initialize_dynamic_attributes) ENABLED START -----#
    def initialize_dynamic_attributes(self):
        pass
        #----- PROTECTED REGION END -----#  //  Skippy.initialize_dynamic_attributes
            
    def read_attr_hardware(self, data):
        self.debug_stream("In read_attr_hardware()")
        #----- PROTECTED REGION ID(Skippy.read_attr_hardware) ENABLED START -----#
        if not hasattr(self, 'skippy') or self.skippy is None:
            self.debug_stream("Avoid read procedure when not yet build "
                              "SkippyObj")
            return
        self.__read_attr_procedure(data)
        #----- PROTECTED REGION END -----#  //  Skippy.read_attr_hardware


    #-----------------------------------------------------------------------------
    #    Skippy command methods
    #-----------------------------------------------------------------------------

    def IDN(self):
        """ Request identification to the instrument.
        
        :param : 
        :type: PyTango.DevVoid
        :return: 
        :rtype: PyTango.DevString """
        self.debug_stream("In IDN()")
        argout = ''
        #----- PROTECTED REGION ID(Skippy.IDN) ENABLED START -----#
        idn = self.skippy.Read("*IDN?")
        if self.skippy.idn != idn:
            self.warn_stream("In IDN(): current identity %r has changed to %r"
                             % (self.skippy.idn, idn))
            self.skippy.idn = idn
        if self.skippy.idn:
            argout = self.skippy.idn
        else:
            argout = ''
        #----- PROTECTED REGION END -----#  //  Skippy.IDN
        return argout
        
    def is_IDN_allowed(self):
        self.debug_stream("In is_IDN_allowed()")
        state_ok = not(self.get_state() in [PyTango.DevState.OFF,
            PyTango.DevState.FAULT,PyTango.DevState.DISABLE,
            PyTango.DevState.INIT])
        #----- PROTECTED REGION ID(Skippy.is_IDN_allowed) ENABLED START -----#

        #----- PROTECTED REGION END -----#  //  Skippy.is_IDN_allowed
        return state_ok
        
    def Start(self):
        """ Start an active monitoring.
        
        :param : 
        :type: PyTango.DevVoid
        :return: 
        :rtype: PyTango.DevBoolean """
        self.debug_stream("In Start()")
        argout = False
        #----- PROTECTED REGION ID(Skippy.Start) ENABLED START -----#
        argout = self.skippy.Start()
        #----- PROTECTED REGION END -----#  //  Skippy.Start
        return argout
        
    def is_Start_allowed(self):
        self.debug_stream("In is_Start_allowed()")
        state_ok = not(self.get_state() in [PyTango.DevState.OFF,
            PyTango.DevState.RUNNING,
            PyTango.DevState.FAULT,
            PyTango.DevState.INIT,
            PyTango.DevState.STANDBY])
        #----- PROTECTED REGION ID(Skippy.is_Start_allowed) ENABLED START -----#

        #----- PROTECTED REGION END -----#  //  Skippy.is_Start_allowed
        return state_ok
        
    def Stop(self):
        """ Stop the active monitoring.
        
        :param : 
        :type: PyTango.DevVoid
        :return: 
        :rtype: PyTango.DevBoolean """
        self.debug_stream("In Stop()")
        argout = False
        #----- PROTECTED REGION ID(Skippy.Stop) ENABLED START -----#
        argout = self.skippy.Stop()
        #----- PROTECTED REGION END -----#  //  Skippy.Stop
        return argout
        
    def is_Stop_allowed(self):
        self.debug_stream("In is_Stop_allowed()")
        state_ok = not(self.get_state() in [PyTango.DevState.OFF,
            PyTango.DevState.ON,
            PyTango.DevState.FAULT,
            PyTango.DevState.INIT,
            PyTango.DevState.STANDBY])
        #----- PROTECTED REGION ID(Skippy.is_Stop_allowed) ENABLED START -----#

        #----- PROTECTED REGION END -----#  //  Skippy.is_Stop_allowed
        return state_ok
        
    def On(self):
        """ Allow communication with the instrument.
        
        :param : 
        :type: PyTango.DevVoid
        :return: 
        :rtype: PyTango.DevBoolean """
        self.debug_stream("In On()")
        argout = False
        #----- PROTECTED REGION ID(Skippy.On) ENABLED START -----#
        argout = self.skippy.On()
        #----- PROTECTED REGION END -----#  //  Skippy.On
        return argout
        
    def is_On_allowed(self):
        self.debug_stream("In is_On_allowed()")
        state_ok = not(self.get_state() in [PyTango.DevState.ON,
            PyTango.DevState.RUNNING,
            PyTango.DevState.FAULT,
            PyTango.DevState.INIT])
        #----- PROTECTED REGION ID(Skippy.is_On_allowed) ENABLED START -----#

        #----- PROTECTED REGION END -----#  //  Skippy.is_On_allowed
        return state_ok
        
    def Off(self):
        """ Release the communication with the instrument.
        
        :param : 
        :type: PyTango.DevVoid
        :return: 
        :rtype: PyTango.DevBoolean """
        self.debug_stream("In Off()")
        argout = False
        #----- PROTECTED REGION ID(Skippy.Off) ENABLED START -----#
        argout = self.skippy.Off()
        #----- PROTECTED REGION END -----#  //  Skippy.Off
        return argout
        
    def is_Off_allowed(self):
        self.debug_stream("In is_Off_allowed()")
        state_ok = not(self.get_state() in [PyTango.DevState.OFF,
            PyTango.DevState.RUNNING,
            PyTango.DevState.FAULT,
            PyTango.DevState.INIT])
        #----- PROTECTED REGION ID(Skippy.is_Off_allowed) ENABLED START -----#

        #----- PROTECTED REGION END -----#  //  Skippy.is_Off_allowed
        return state_ok
        
    def Exec(self, argin):
        """ evaluate python code inside the device server. This command can be very helpful and dangerous.
        
        :param argin: 
        :type: PyTango.DevString
        :return: 
        :rtype: PyTango.DevString """
        self.debug_stream("In Exec()")
        argout = ''
        #----- PROTECTED REGION ID(Skippy.Exec) ENABLED START -----#
        self.debug_stream("argin %s" % (repr(argin)))
        if argin.count("=") == 0:
            try:
                argout = eval(argin, self._globals, self._locals)
            except SyntaxError as expression_exception:
                self.warn_stream("Interpreting as expression Exception: "
                                 "{0}".format(expression_exception))
                argout = traceback.format_exc()
        else:
            try:
                exec argin in self._globals, self._locals
                argout = self._locals.get("y")
            except Exception as statement_exception:
                self.warn_stream("Interpreting as statement Exception: "
                                 "{0}".format(statement_exception))
                argout = traceback.format_exc()
        if type(argout) == StringType:
            pass  # return argout
        elif isinstance(argout, BaseException):
            argout = "%s!\n%s" % (argout.__class__.__name__, str(argout))
        else:
            try:
                argout = pprint.pformat(argout)
            except Exception:
                argout = str(argout)
        try:
            self.debug_stream("argout {0!r}".format(argout))
        except Exception as exc:
            self.error_stream(
                "In Exec command: "
                "couldn't format string the argout: {0}".format(exc))
        #----- PROTECTED REGION END -----#  //  Skippy.Exec
        return argout
        
    def AddMonitoring(self, argin):
        """ Add an attribute to the list of monitored attributes
        
        :param argin: 
        :type: PyTango.DevString
        :return: 
        :rtype: PyTango.DevBoolean """
        self.debug_stream("In AddMonitoring()")
        argout = False
        #----- PROTECTED REGION ID(Skippy.AddMonitoring) ENABLED START -----#
        try:
            attrName, attrPeriod = self._checkArginNameAndPeriod(argin)
            multiattr = self.get_device_attr()
            attrId = multiattr.get_attr_ind_by_name(attrName)
            if not attrName in self.skippy.attributes.keys():
                raise AttributeError("No attribute named %s" % (attrName))
            elif attrId in self._monitoredAttributeIds:
                raise AttributeError("Attribute %s already monitored"
                                     % (attrName))
            else:
                self.info_stream("In AddMonitoring(): Adding %s attribute "\
                                 "to monitoring." % (attrName))
                # manage the property
                try:
                    self.MonitoredAttributes = \
                        self.__appendPropertyElement('MonitoredAttributes',
                                                     attrName)
                    self.debug_stream("In AddMonitoring(%s), added to "
                                     "properties" % (attrName))
                except Exception as e:
                    self.error_stream("In AddMonitoring(%s) cannot append "
                                      "to the property: %s"
                                      %(attrName, e))
                    raise e
                if self.skippy.monitorInsert(attrName, attrPeriod):
                    argout = True
        except Exception as e:
            self.error_stream("In AddMonitoring(%s) exception: %s"
                              % (argin, e))
            raise e
        #----- PROTECTED REGION END -----#  //  Skippy.AddMonitoring
        return argout
        
    def is_AddMonitoring_allowed(self):
        self.debug_stream("In is_AddMonitoring_allowed()")
        state_ok = not(self.get_state() in [PyTango.DevState.OFF,
            PyTango.DevState.FAULT,
            PyTango.DevState.INIT])
        #----- PROTECTED REGION ID(Skippy.is_AddMonitoring_allowed) ENABLED START -----#

        #----- PROTECTED REGION END -----#  //  Skippy.is_AddMonitoring_allowed
        return state_ok
        
    def RemoveMonitoring(self, argin):
        """ Remove an attribute from the list of monitored attributes
        
        :param argin: 
        :type: PyTango.DevString
        :return: 
        :rtype: PyTango.DevBoolean """
        self.debug_stream("In RemoveMonitoring()")
        argout = False
        #----- PROTECTED REGION ID(Skippy.RemoveMonitoring) ENABLED START -----#
        try:
            multiattr = self.get_device_attr()
            attrId = multiattr.get_attr_ind_by_name(argin)
            if not argin in self.skippy.attributes.keys():
                raise AttributeError("No attribute named %s" % (argin))
            elif not attrId in self._monitoredAttributeIds:
                raise AttributeError("Attribute %s is not monitored" % (argin))
            else:
                argout = self.skippy.monitorRemove(attrId)
                # manage the property
                try:
                    self.MonitoredAttributes = \
                        self.__popPropertyElement('MonitoredAttributes', argin)
                    argout = True
                except Exception as e:
                    self.error_stream("In RemoveMonitoring(%s) cannot remove "
                                      "from the property: %s"
                                      % (argin, e))
                    raise e
        except Exception as e:
            self.error_stream("In RemoveMonitoring(%s) exception: %s"
                              % (argin, e))
            raise e
        #----- PROTECTED REGION END -----#  //  Skippy.RemoveMonitoring
        return argout
        
    def is_RemoveMonitoring_allowed(self):
        self.debug_stream("In is_RemoveMonitoring_allowed()")
        state_ok = not(self.get_state() in [PyTango.DevState.OFF,
            PyTango.DevState.FAULT,
            PyTango.DevState.INIT])
        #----- PROTECTED REGION ID(Skippy.is_RemoveMonitoring_allowed) ENABLED START -----#

        #----- PROTECTED REGION END -----#  //  Skippy.is_RemoveMonitoring_allowed
        return state_ok

    def SetMonitoringPeriod(self, argin):
        """ From the list of already monitored attributes, stablish (or change) the period that it is checked.
        
        :param argin: 
        :type: PyTango.DevVarStringArray
        :return: 
        :rtype: PyTango.DevBoolean """
        self.debug_stream("In SetMonitoringPeriod()")
        argout = False
        #----- PROTECTED REGION ID(Skippy.SetMonitoringPeriod) ENABLED START -----#
        try:
            if not len(argin) == 2:
                raise AttributeError("Invalid arguments, "\
                                     "use [attrName, AttrPeriod]")
            else:
                if argin[0].count("'") == 2:
                    attrName = str(argin[0].split("'")[1])
                else:
                    attrName = argin[0]
                if argin[1].count("'") == 2:
                    attrPeriod = float(argin[1].split("'")[1])
                else:
                    attrPeriod = float(argin[1])
                self.info_stream("In SetMonitoringPeriod(%s, %f)"
                                 % (attrName, attrPeriod))
            multiattr = self.get_device_attr()
            attrId = multiattr.get_attr_ind_by_name(attrName)
            if not attrName in self.skippy.attributes.keys():
                raise AttributeError("No attribute named %s" % (attrName))
            elif not attrId in self._monitoredAttributeIds:
                raise AttributeError("Attribute %s is not monitored"
                                     % (attrName))
            elif attrPeriod < 0:
                raise AttributeError("Invalid period %f" % (attrPeriod))
            else:
                if self.skippy.monitorRemove(attrId):
                    self.MonitoredAttributes = \
                        self.__popPropertyElement('MonitoredAttributes',
                                                  attrName)
                    # distinguish if the command should send it to 
                    # the generic or not
                    monitorTag = str(attrPeriod)
                    if attrPeriod == 0:
                        monitorTag = 'Generic'
                    else:
                        monitorTag = str(attrPeriod)
                    self.skippy.monitorInsert(attrName, attrPeriod)
                    if attrPeriod == 0:
                        self.MonitoredAttributes = \
                            self.__appendPropertyElement('MonitoredAttributes',
                                                         "%s" % (attrName))
                    else:
                        self.MonitoredAttributes = \
                            self.__appendPropertyElement('MonitoredAttributes',
                                                         "%s:%6.3f"
                                                         % (attrName,
                                                            attrPeriod))
                    argout = True
        except Exception as e:
            self.error_stream("In SetMonitoringPeriod(%s) exception: %s"
                              % (argin, e))
            raise e
        #----- PROTECTED REGION END -----#  //  Skippy.SetMonitoringPeriod
        return argout
        
    def is_SetMonitoringPeriod_allowed(self):
        self.debug_stream("In is_SetMonitoringPeriod_allowed()")
        state_ok = not(self.get_state() in [PyTango.DevState.OFF,
            PyTango.DevState.FAULT,
            PyTango.DevState.INIT])
        #----- PROTECTED REGION ID(Skippy.is_SetMonitoringPeriod_allowed) ENABLED START -----#

        #----- PROTECTED REGION END -----#  //  Skippy.is_SetMonitoringPeriod_allowed
        return state_ok
        
    def GetMonitoringPeriod(self, argin):
        """ Get the period that is checked an attribute monitored.
        
        :param argin: 
        :type: PyTango.DevString
        :return: 
        :rtype: PyTango.DevFloat """
        self.debug_stream("In GetMonitoringPeriod()")
        argout = 0.0
        #----- PROTECTED REGION ID(Skippy.GetMonitoringPeriod) ENABLED START -----#
        try:
            attrName = argin
            multiattr = self.get_device_attr()
            attrId = multiattr.get_attr_ind_by_name(attrName)
            if not attrName in self.skippy.attributes.keys():
                raise AttributeError("No attribute named %s" % (attrName))
            elif not attrId in self._monitoredAttributeIds:
                raise AttributeError("Attribute %s is not monitored"
                                     % (attrName))
            argout = self.skippy.getMonitorPeriod(attrId)
        except Exception as e:
            self.error_stream("In GetMonitoringPeriod(%r) exception: %s"
                              % (argin, e))
            raise e
        #----- PROTECTED REGION END -----#  //  Skippy.GetMonitoringPeriod
        return argout
        
    def is_GetMonitoringPeriod_allowed(self):
        self.debug_stream("In is_GetMonitoringPeriod_allowed()")
        state_ok = not(self.get_state() in [PyTango.DevState.OFF,
            PyTango.DevState.FAULT,
            PyTango.DevState.INIT])
        #----- PROTECTED REGION ID(Skippy.is_GetMonitoringPeriod_allowed) ENABLED START -----#

        #----- PROTECTED REGION END -----#  //  Skippy.is_GetMonitoringPeriod_allowed
        return state_ok
        
    def CMD(self, argin):
        """ Expert command for a direct send of a SCPI command and read the answer.
        
        :param argin: 
        :type: PyTango.DevString
        :return: 
        :rtype: PyTango.DevString """
        self.debug_stream("In CMD()")
        argout = ''
        #----- PROTECTED REGION ID(Skippy.CMD) ENABLED START -----#
        argin = str(argin)
        self.info_stream("In CMD(%r)" % (argin))
        try:
            if argin.find('?') >= 0:
                # argout = self.skippy.instrument.ask(argin)
                argout = self.skippy.Read(argin) or ''
            else:
                # self.skippy.instrument.write(argin)
                self.skippy.Write(argin)
                argout = ""
            self.info_stream("In CMD(%r): %r" % (argin, argout))
        except Exception as e:
            self.error_stream("In CMD(%r) Exception: %s" % (argin, e))
            argout = ""
            self.skippy._change_state_status(
                newState=PyTango.DevState.FAULT,
                newLine="Exception while executing CMD()")
            # self.__reconnectInstrumentObj()
        #----- PROTECTED REGION END -----#  //  Skippy.CMD
        return argout
        
    def is_CMD_allowed(self):
        self.debug_stream("In is_CMD_allowed()")
        state_ok = not(self.get_state() in [PyTango.DevState.OFF,
            PyTango.DevState.FAULT,
            PyTango.DevState.INIT])
        #----- PROTECTED REGION ID(Skippy.is_CMD_allowed) ENABLED START -----#

        #----- PROTECTED REGION END -----#  //  Skippy.is_CMD_allowed
        return state_ok
        
    # def CMDfloat(self, argin):
    #     """ Expert command for a direct send of a SCPI command and read the answer converted to a float list.
    #
    #     :param argin:
    #     :type: PyTango.DevString
    #     :return:
    #     :rtype: PyTango.DevVarFloatArray """
    #     self.debug_stream("In CMDfloat()")
    #     argout = [0.0]
    #     #----- PROTECTED REGION ID(Skippy.CMDfloat) ENABLED START -----#
    #     argin = str(argin)
    #     self.info_stream("In %s::CMDfloat(%r)" % (self.get_name(), argin))
    #     try:
    #         if argin.find('?') >= 0:
    #             # argout = self.skippy.instrument.ask_for_values(argin)
    #             argout = self.skippy.Read(argin, ask_for_values=True)
    #         else:
    #             # self.skippy.instrument.write(argin)
    #             self.skippy.Write(argin)
    #             argout = float("NaN")
    #         self.info_stream("In CMDfloat(%r): %r" % (argin, argout))
    #     except Exception as e:
    #         self.error_stream("In CMDfloat(%r) Exception: %s" % (argin, e))
    #         argout = ""
    #         self.skippy._change_state_status(
    #             newState=PyTango.DevState.FAULT,
    #             newLine="Exception while executing CMDfloat()")
    #         # self.__reconnectInstrumentObj()
    #     #----- PROTECTED REGION END -----#  //  Skippy.CMDfloat
    #     return argout
        
    # def is_CMDfloat_allowed(self):
    #     self.debug_stream("In is_CMDfloat_allowed()")
    #     state_ok = not(self.get_state() in [PyTango.DevState.OFF,
    #         PyTango.DevState.FAULT,
    #         PyTango.DevState.INIT])
    #     #----- PROTECTED REGION ID(Skippy.is_CMDfloat_allowed) ENABLED START -----#
    #
    #     #----- PROTECTED REGION END -----#  //  Skippy.is_CMDfloat_allowed
    #     return state_ok
        
    def Standby(self):
        """ Stablish communication with the instrument.
        
        :param : 
        :type: PyTango.DevVoid
        :return: 
        :rtype: PyTango.DevBoolean """
        self.debug_stream("In Standby()")
        argout = False
        #----- PROTECTED REGION ID(Skippy.Standby) ENABLED START -----#
        argout = self.skippy.Standby()
        #----- PROTECTED REGION END -----#  //  Skippy.Standby
        return argout

    def updateDynamicAttributes(self):
        """ Passes the content in the DynamicAttributes property to the
        internal skippy object to inject some extra attributes defined in the
        property.

        :param :
        :type: PyTango.DevVoid
        :return:
        :rtype: PyTango.DevBoolean """
        self.debug_stream("In Standby()")
        argout = False
        # ----- PROTECTED REGION ID(Skippy.Standby) ENABLED START -----#
        self.get_device_properties(self.get_device_class())  # reload from db
        argout = self.skippy.inject_extra_attributes(
                '\n'.join(["{0}".format(element)
                           for element in self.DynamicAttributes]))
        # ----- PROTECTED REGION END -----#  //  Skippy.Standby
        return argout

    #----- PROTECTED REGION ID(Skippy.programmer_methods) ENABLED START -----#
    
    #----- PROTECTED REGION END -----#  //  Skippy.programmer_methods

class SkippyClass(PyTango.DeviceClass):
    #--------- Add you global class variables here --------------------------
    #----- PROTECTED REGION ID(Skippy.global_class_variables) ENABLED START -----#

    #----- PROTECTED REGION END -----#  //  Skippy.global_class_variables

    def dyn_attr(self, dev_list):
        """Invoked to create dynamic attributes for the given devices.
        Default implementation calls
        :meth:`Skippy.initialize_dynamic_attributes` for each device
    
        :param dev_list: list of devices
        :type dev_list: :class:`PyTango.DeviceImpl`"""
    
        for dev in dev_list:
            try:
                dev.initialize_dynamic_attributes()
            except:
                import traceback
                dev.warn_stream("Failed to initialize dynamic attributes")
                dev.debug_stream("Details: " + traceback.format_exc())
        #----- PROTECTED REGION ID(Skippy.dyn_attr) ENABLED START -----#

        #----- PROTECTED REGION END -----#  //  Skippy.dyn_attr

    #    Class Properties
    class_property_list = {
        }


    #    Device Properties
    device_property_list = {
        'Instrument':
            [PyTango.DevString,
            "The name of the instrument to use. This may be:\
                1: host name to connect to\
                2: PyVisa tango device name to connect to\
                3: Serial or PySerial tango device to connect to\
                4: serial device name for direct connection (e.g. /dev/ttyS0)",
            [] ],
        'Port':
            [PyTango.DevUShort,
            "In case of socket interface the port value can be changed",
            [5025]],
        'SerialBaudrate':
            [PyTango.DevULong,
            "Baudrate of serial port (only for direct serial connection)",
            [9600]],
        'SerialBytesize':
            [PyTango.DevUShort,
            "Bytesize of serial port (only for direct serial connection)",
            [8]],
        'SerialParity':
            [PyTango.DevString,
            "Parity of serial port (only for direct serial connection)",
            ["N"]],
        'SerialStopbits':
            [PyTango.DevUShort,
            "Stopbits of serial port (only for direct serial connection)",
            [1]],
        'SerialTimeout':
            [PyTango.DevULong,
            "Timeout of serial port: use -1 for None (only for direct serial connection)",
            [-1]],
        'SerialXonXoff':
            [PyTango.DevBoolean,
            "Enable software flow control of serial port: use -1 for None (only for direct serial connection)",
            [False]],
        'TxTerminator':
            [PyTango.DevString,
             "Symbol to be append to the end of the scpi string send to the instrument",
             ["\n"]],
        'NumChannels':
            [PyTango.DevUShort,
            "Number of channels available in the instrument, if it has",
            [0]],
        'NumFunctions':
            [PyTango.DevUShort,
            "Number of functions available in the instrument, if it has",
            [0]],
        'NumMultiple':
            [PyTango.DevVarStringArray,
            "From the generalisation of channels and functions, a list of pairs with the 'scpiPrefix' and how many shall be build",
            [] ],
        'MonitoredAttributes':
            [PyTango.DevVarStringArray,
            "When the device is in RUNNING state, the attributes listed here will be monitored (having events) with a period said in the attribute TimeStampsThreashold (or different if specified with a : separator after the attrName)",
            [] ],
        'AutoOn':
            [PyTango.DevBoolean,
            "When device startup, try an on() to connect to the instrument authomatically",
            [True]],
        'AutoStart':
            [PyTango.DevBoolean,
            "When device startup, try an Start() to monitor attributes, if MonitoredAttributes is configuredc, authomatically",
            [True]],
        'AutoStandby':
            [PyTango.DevBoolean,
            "When device startup, try an standby() to connect to the instrument authomatically.",
            [True]],
        'DynamicAttributes':
            [PyTango.DevVarStringArray,
             "Way to define specific attributes on a single instrument. Like the ones in the definition file.",
             []],
        }


    #    Command definitions
    cmd_list = {
        'IDN':
            [[PyTango.DevVoid, "none"],
            [PyTango.DevString, "none"]],
        'Start':
            [[PyTango.DevVoid, "none"],
            [PyTango.DevBoolean, "none"]],
        'Stop':
            [[PyTango.DevVoid, "none"],
            [PyTango.DevBoolean, "none"]],
        'On':
            [[PyTango.DevVoid, "none"],
            [PyTango.DevBoolean, "none"]],
        'Off':
            [[PyTango.DevVoid, "none"],
            [PyTango.DevBoolean, "none"]],
        'Exec':
            [[PyTango.DevString, "none"],
            [PyTango.DevString, "none"],
            {
                'Display level': PyTango.DispLevel.EXPERT,
            } ],
        'AddMonitoring':
            [[PyTango.DevString, "none"],
            [PyTango.DevBoolean, "none"]],
        'RemoveMonitoring':
            [[PyTango.DevString, "none"],
            [PyTango.DevBoolean, "none"]],
        'SetMonitoringPeriod':
            [[PyTango.DevVarStringArray, "none"],
            [PyTango.DevBoolean, "none"]],
        'GetMonitoringPeriod':
            [[PyTango.DevString, "none"],
            [PyTango.DevFloat, "none"]],
        'CMD':
            [[PyTango.DevString, "none"],
            [PyTango.DevString, "none"],
            {
                'Display level': PyTango.DispLevel.EXPERT,
            } ],
        # 'CMDfloat':
        #     [[PyTango.DevString, "none"],
        #     [PyTango.DevVarFloatArray, "none"],
        #     {
        #         'Display level': PyTango.DispLevel.EXPERT,
        #     } ],
        'Standby':
            [[PyTango.DevVoid, "none"],
            [PyTango.DevBoolean, "none"]],
        'updateDynamicAttributes':
            [[PyTango.DevVoid, "none"],
            [PyTango.DevBoolean, "none"]],
        }


    #    Attribute definitions
    attr_list = {
        'Idn':
            [[PyTango.DevString,
            PyTango.SCALAR,
            PyTango.READ],
            {
                'description': "Instrument identification",
            } ],
        'QueryWindow':
            [[PyTango.DevUShort,
            PyTango.SCALAR,
            PyTango.READ_WRITE],
            {
                'label': "Query Window",
                'unit': "queries",
                'format': "%2d",
                'min value': "1",
                'max warning': "20",
                'description': "When many attributes are requested at the same time, they are grouped in subqueries of this size",
                'Display level': PyTango.DispLevel.EXPERT,
                'Memorized':"true"
            } ],
        'TimeStampsThreshold':
            [[PyTango.DevFloat,
            PyTango.SCALAR,
            PyTango.READ_WRITE],
            {
                'label': "Time stamps threshold",
                'unit': "seconds",
                'format': "%3.2g",
                'max value': "3",
                'min value': "0.1",
                'description': "This value sets the threshold time to use a cached value or hardware read it",
                'Display level': PyTango.DispLevel.EXPERT,
                'Memorized':"true"
            } ],
        'ReadAfterWrite':
            [[PyTango.DevBoolean,
              PyTango.SCALAR,
              PyTango.READ_WRITE],
             {
                 'label': "Read after write",
                 'description': "This boolean says the device to read the ACK answer after a write",
                 'Display level': PyTango.DispLevel.EXPERT,
                 'Memorized': "true"
             }],
        'Version':
            [[PyTango.DevString,
            PyTango.SCALAR,
            PyTango.READ],
            {
                'description': "version of the sources of the device",
            } ],
        }


def main():
    try:
        py = PyTango.Util(sys.argv)
        py.add_class(SkippyClass,Skippy,'Skippy')
        #----- PROTECTED REGION ID(Skippy.add_classes) ENABLED START -----#

        #----- PROTECTED REGION END -----#  //  Skippy.add_classes

        U = PyTango.Util.instance()
        U.server_init()
        U.server_run()

    except PyTango.DevFailed as e:
        print('-------> Received a DevFailed exception:',e)
    except Exception as e:
        print('-------> An unforeseen exception occured....',e)

if __name__ == '__main__':
    main()
