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


# ############################################################################
#  license :
# ============================================================================
#
#  File :        SRS_SIM928.py
#
#  Project :     SRS_SIM928
#
# 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 MIT licence.
# 
#
#  $Author :      mellguth$
#
#  $Revision :    $
#
#  $Date :        $
#
#  $HeadUrl :     $
# ============================================================================
#            This file is generated by POGO
#     (Program Obviously used to Generate tango Object)
# ############################################################################

__all__ = ["SRS_SIM928", "SRS_SIM928Class", "main"]

__docformat__ = 'restructuredtext'

import PyTango
import sys
# Add additional import
#----- PROTECTED REGION ID(SRS_SIM928.additionnal_import) ENABLED START -----#
import time
from threading import Thread
from SRS_SIM928_Hardware import SRS_SIM928_Hardware
#----- PROTECTED REGION END -----#	//	SRS_SIM928.additionnal_import

# Device States Description
# No states for this device


class SRS_SIM928 (PyTango.Device_4Impl):
    """SRS SIM928 Isolated VOltage Source"""
    
    # -------- Add you global variables here --------------------------
    #----- PROTECTED REGION ID(SRS_SIM928.global_variables) ENABLED START -----#
    
    #----- PROTECTED REGION END -----#	//	SRS_SIM928.global_variables

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

        #----- PROTECTED REGION END -----#	//	SRS_SIM928.__init__
        
    def delete_device(self):
        self.debug_stream("In delete_device()")
        #----- PROTECTED REGION ID(SRS_SIM928.delete_device) ENABLED START -----#
        self.polling_thread_stop = True
        self.polling_thread.join()
        #----- PROTECTED REGION END -----#	//	SRS_SIM928.delete_device

    def init_device(self):
        self.debug_stream("In init_device()")
        self.get_device_properties(self.get_device_class())
        self.attr_VoltSet_read = 0.0
        self.attr_Volt_read = 0.0
        self.attr_OutputOn_read = False
        self.attr_OutputOnSet_read = False
        self.attr_Battery1State_read = 0
        self.attr_Battery1StateStr_read = ""
        self.attr_Battery2State_read = 0
        self.attr_Battery2StateStr_read = ""
        self.attr_BatteryInfo_read = ""
        self.attr_DevIdent_read = ""
        self.attr_Trigger_BatChargeOverride_read = 0
        self.attr_Connected_read = False
        self.attr_BatteryService_read = False
        self.attr_Trigger_Reconnect_read = 0
        self.attr_Trigger_Disconnect_read = 0
        #----- PROTECTED REGION ID(SRS_SIM928.init_device) ENABLED START -----#
        self.hw = SRS_SIM928_Hardware()
        self.hw.add_connection_listener(self.on_hw_connection_change)
        self.hw.connect(self.SerialDevice, baudrate=self.Baudrate)
        ###
        self.init_info_thread = Thread(target=self.init_sim928_info_thread_body)
        self.init_info_thread.daemon = True
        self.init_info_thread.start()
        ###
        self.polling_thread_stop = False
        self.polling_thread = Thread(target=self.polling_thread_body)
        self.polling_thread.start()
        
        #----- PROTECTED REGION END -----#	//	SRS_SIM928.init_device

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

    # -------------------------------------------------------------------------
    #    SRS_SIM928 read/write attribute methods
    # -------------------------------------------------------------------------
    
    def read_VoltSet(self, attr):
        self.debug_stream("In read_VoltSet()")
        #----- PROTECTED REGION ID(SRS_SIM928.VoltSet_read) ENABLED START -----#
        attr.set_value(self.attr_VoltSet_read)
        
        #----- PROTECTED REGION END -----#	//	SRS_SIM928.VoltSet_read
        
    def write_VoltSet(self, attr):
        self.debug_stream("In write_VoltSet()")
        data = attr.get_write_value()
        #----- PROTECTED REGION ID(SRS_SIM928.VoltSet_write) ENABLED START -----#
        if self.hw.connected:
            self.hw.write_volt(data)
        self.attr_VoltSet_read = data
        #----- PROTECTED REGION END -----#	//	SRS_SIM928.VoltSet_write
        
    def read_Volt(self, attr):
        self.debug_stream("In read_Volt()")
        #----- PROTECTED REGION ID(SRS_SIM928.Volt_read) ENABLED START -----#
        attr.set_value(self.attr_Volt_read)
        
        #----- PROTECTED REGION END -----#	//	SRS_SIM928.Volt_read
        
    def read_OutputOn(self, attr):
        self.debug_stream("In read_OutputOn()")
        #----- PROTECTED REGION ID(SRS_SIM928.OutputOn_read) ENABLED START -----#
        attr.set_value(self.attr_OutputOn_read)
        
        #----- PROTECTED REGION END -----#	//	SRS_SIM928.OutputOn_read
        
    def read_OutputOnSet(self, attr):
        self.debug_stream("In read_OutputOnSet()")
        #----- PROTECTED REGION ID(SRS_SIM928.OutputOnSet_read) ENABLED START -----#
        attr.set_value(self.attr_OutputOnSet_read)
        
        #----- PROTECTED REGION END -----#	//	SRS_SIM928.OutputOnSet_read
        
    def write_OutputOnSet(self, attr):
        self.debug_stream("In write_OutputOnSet()")
        data = attr.get_write_value()
        #----- PROTECTED REGION ID(SRS_SIM928.OutputOnSet_write) ENABLED START -----#
        if data==True and self.hw.connected:
            self.hw.write_output_on(True)
        elif data==False and self.hw.connected:
            self.hw.write_output_on(False)
        self.attr_OutputOnSet_read = data
        #----- PROTECTED REGION END -----#	//	SRS_SIM928.OutputOnSet_write
        
    def read_Battery1State(self, attr):
        self.debug_stream("In read_Battery1State()")
        #----- PROTECTED REGION ID(SRS_SIM928.Battery1State_read) ENABLED START -----#
        attr.set_value(self.attr_Battery1State_read)
        
        #----- PROTECTED REGION END -----#	//	SRS_SIM928.Battery1State_read
        
    def read_Battery1StateStr(self, attr):
        self.debug_stream("In read_Battery1StateStr()")
        #----- PROTECTED REGION ID(SRS_SIM928.Battery1StateStr_read) ENABLED START -----#
        attr.set_value(self.attr_Battery1StateStr_read)
        
        #----- PROTECTED REGION END -----#	//	SRS_SIM928.Battery1StateStr_read
        
    def read_Battery2State(self, attr):
        self.debug_stream("In read_Battery2State()")
        #----- PROTECTED REGION ID(SRS_SIM928.Battery2State_read) ENABLED START -----#
        attr.set_value(self.attr_Battery2State_read)
        
        #----- PROTECTED REGION END -----#	//	SRS_SIM928.Battery2State_read
        
    def read_Battery2StateStr(self, attr):
        self.debug_stream("In read_Battery2StateStr()")
        #----- PROTECTED REGION ID(SRS_SIM928.Battery2StateStr_read) ENABLED START -----#
        attr.set_value(self.attr_Battery2StateStr_read)
        
        #----- PROTECTED REGION END -----#	//	SRS_SIM928.Battery2StateStr_read
        
    def read_BatteryInfo(self, attr):
        self.debug_stream("In read_BatteryInfo()")
        #----- PROTECTED REGION ID(SRS_SIM928.BatteryInfo_read) ENABLED START -----#
        attr.set_value(self.attr_BatteryInfo_read)
        
        #----- PROTECTED REGION END -----#	//	SRS_SIM928.BatteryInfo_read
        
    def read_DevIdent(self, attr):
        self.debug_stream("In read_DevIdent()")
        #----- PROTECTED REGION ID(SRS_SIM928.DevIdent_read) ENABLED START -----#
        attr.set_value(self.attr_DevIdent_read)
        
        #----- PROTECTED REGION END -----#	//	SRS_SIM928.DevIdent_read
        
    def read_Trigger_BatChargeOverride(self, attr):
        self.debug_stream("In read_Trigger_BatChargeOverride()")
        #----- PROTECTED REGION ID(SRS_SIM928.Trigger_BatChargeOverride_read) ENABLED START -----#
        attr.set_value(self.attr_Trigger_BatChargeOverride_read)
        
        #----- PROTECTED REGION END -----#	//	SRS_SIM928.Trigger_BatChargeOverride_read
        
    def write_Trigger_BatChargeOverride(self, attr):
        self.debug_stream("In write_Trigger_BatChargeOverride()")
        data = attr.get_write_value()
        #----- PROTECTED REGION ID(SRS_SIM928.Trigger_BatChargeOverride_write) ENABLED START -----#
        self.BatChargeOverride()
        #----- PROTECTED REGION END -----#	//	SRS_SIM928.Trigger_BatChargeOverride_write
        
    def read_Connected(self, attr):
        self.debug_stream("In read_Connected()")
        #----- PROTECTED REGION ID(SRS_SIM928.Connected_read) ENABLED START -----#
        attr.set_value(self.attr_Connected_read)
        
        #----- PROTECTED REGION END -----#	//	SRS_SIM928.Connected_read
        
    def read_BatteryService(self, attr):
        self.debug_stream("In read_BatteryService()")
        #----- PROTECTED REGION ID(SRS_SIM928.BatteryService_read) ENABLED START -----#
        attr.set_value(self.attr_BatteryService_read)
        
        #----- PROTECTED REGION END -----#	//	SRS_SIM928.BatteryService_read
        
    def read_Trigger_Reconnect(self, attr):
        self.debug_stream("In read_Trigger_Reconnect()")
        #----- PROTECTED REGION ID(SRS_SIM928.Trigger_Reconnect_read) ENABLED START -----#
        attr.set_value(self.attr_Trigger_Reconnect_read)
        
        #----- PROTECTED REGION END -----#	//	SRS_SIM928.Trigger_Reconnect_read
        
    def write_Trigger_Reconnect(self, attr):
        self.debug_stream("In write_Trigger_Reconnect()")
        data = attr.get_write_value()
        #----- PROTECTED REGION ID(SRS_SIM928.Trigger_Reconnect_write) ENABLED START -----#
        self.Reconnect()
        #----- PROTECTED REGION END -----#	//	SRS_SIM928.Trigger_Reconnect_write
        
    def read_Trigger_Disconnect(self, attr):
        self.debug_stream("In read_Trigger_Disconnect()")
        #----- PROTECTED REGION ID(SRS_SIM928.Trigger_Disconnect_read) ENABLED START -----#
        attr.set_value(self.attr_Trigger_Disconnect_read)
        
        #----- PROTECTED REGION END -----#	//	SRS_SIM928.Trigger_Disconnect_read
        
    def write_Trigger_Disconnect(self, attr):
        self.debug_stream("In write_Trigger_Disconnect()")
        data = attr.get_write_value()
        #----- PROTECTED REGION ID(SRS_SIM928.Trigger_Disconnect_write) ENABLED START -----#
        self.Disconnect()
        #----- PROTECTED REGION END -----#	//	SRS_SIM928.Trigger_Disconnect_write
        
    
    
            
    def read_attr_hardware(self, data):
        self.debug_stream("In read_attr_hardware()")
        #----- PROTECTED REGION ID(SRS_SIM928.read_attr_hardware) ENABLED START -----#
        
        #----- PROTECTED REGION END -----#	//	SRS_SIM928.read_attr_hardware


    # -------------------------------------------------------------------------
    #    SRS_SIM928 command methods
    # -------------------------------------------------------------------------
    
    def Reconnect(self):
        """ 
        """
        self.debug_stream("In Reconnect()")
        #----- PROTECTED REGION ID(SRS_SIM928.Reconnect) ENABLED START -----#
        if self.hw.connected:
            return
        self.hw.connect(self.SerialDevice, baudrate=self.Baudrate)
        #----- PROTECTED REGION END -----#	//	SRS_SIM928.Reconnect
        
    def Disconnect(self):
        """ 
        """
        self.debug_stream("In Disconnect()")
        #----- PROTECTED REGION ID(SRS_SIM928.Disconnect) ENABLED START -----#
        if not self.hw.connected:
            return
        self.hw.disconnect()
        #----- PROTECTED REGION END -----#	//	SRS_SIM928.Disconnect
        
    def BatChargeOverride(self):
        """ Forces the SIM928 to switch the active output battery
        """
        self.debug_stream("In BatChargeOverride()")
        #----- PROTECTED REGION ID(SRS_SIM928.BatChargeOverride) ENABLED START -----#
        if self.attr_Connected_read:
            self.hw.write_bat_charge_override()
        #----- PROTECTED REGION END -----#	//	SRS_SIM928.BatChargeOverride
        

    #----- PROTECTED REGION ID(SRS_SIM928.programmer_methods) ENABLED START -----#
    
    def on_hw_connection_change(self, connected):
        if connected:
            self.set_state(PyTango.DevState.ON)
            self.attr_Connected_read = True
        else:
            self.set_state(PyTango.DevState.OFF)
            self.attr_Connected_read = False
    
    def init_sim928_info_thread_body(self):
        while not self.attr_Connected_read:
            time.sleep(0.5)
        self.attr_DevIdent_read = self.hw.read_ident()
        time.sleep(0.2)
        pnum = self.hw.read_battery_info(0)
        time.sleep(0.2)
        ser = self.hw.read_battery_info(1)
        time.sleep(0.2)
        maxcy = self.hw.read_battery_info(2)
        time.sleep(0.2)
        nrcy = self.hw.read_battery_info(3)
        time.sleep(0.2)
        pdate = self.hw.read_battery_info(4)
        batinfo = ""
        batinfo = batinfo + "Battery pack part number  :  {p}\n".format(p=pnum)
        batinfo = batinfo + "Battery pack serial number  :  {p}\n".format(p=ser)
        batinfo = batinfo + "Design life, nr of charge cycles  :  {p}\n".format(p=maxcy)
        batinfo = batinfo + "nr of charge cycles used  :  {p}\n".format(p=nrcy)
        batinfo = batinfo + "Battery pack production date  :  {p}\n".format(p=pdate)
        self.attr_BatteryInfo_read = batinfo
    
    def polling_thread_body(self):
        while not self.attr_Connected_read and not self.polling_thread_stop:
            time.sleep(0.5)
        if self.polling_thread_stop:
            return
        time.sleep(4.0) # wait x seconds before starting to poll the device
        loopidx = 0
        while not self.polling_thread_stop:
            if not self.attr_Connected_read:
                time.sleep(1.0)
                continue
            if loopidx % 10 == 1:
                bstate = self.hw.read_battery_state()
                bstatestr = self.hw.battery_state_str
                try:
                    self.attr_Battery1State_read = bstate[0]
                    self.attr_Battery2State_read = bstate[1]
                    self.attr_Battery1StateStr_read = bstatestr[0]
                    self.attr_Battery2StateStr_read = bstatestr[1]
                    self.attr_BatteryService_read = bstate[2]==1
                except Exception as e:
                    print("Exception in polling thread: ")
                    print(e)
                time.sleep(0.1)
            outputon = self.hw.read_output_on()
            self.attr_OutputOn_read = outputon
            time.sleep(0.1)
            voltval = self.hw.read_volt()
            if voltval!=None:
                self.attr_Volt_read = voltval
            time.sleep(0.4)
            loopidx = (loopidx + 1) % 1000
            
    #----- PROTECTED REGION END -----#	//	SRS_SIM928.programmer_methods

class SRS_SIM928Class(PyTango.DeviceClass):
    # -------- Add you global class variables here --------------------------
    #----- PROTECTED REGION ID(SRS_SIM928.global_class_variables) ENABLED START -----#
    
    #----- PROTECTED REGION END -----#	//	SRS_SIM928.global_class_variables


    #    Class Properties
    class_property_list = {
        }


    #    Device Properties
    device_property_list = {
        'SerialDevice':
            [PyTango.DevString, 
            "Device file for serial\n(the first RS232 PCI card on Ubuntu 14.04\ntypically gets /dev/ttyS4 and /dev/ttyS5 if it\nhas two RS232 ports)",
            [] ],
        'Baudrate':
            [PyTango.DevString, 
            "Baudrate for RS232 connection\ndefault: 9600",
            [] ],
        }


    #    Command definitions
    cmd_list = {
        'Reconnect':
            [[PyTango.DevVoid, "none"],
            [PyTango.DevVoid, "none"]],
        'Disconnect':
            [[PyTango.DevVoid, "none"],
            [PyTango.DevVoid, "none"]],
        'BatChargeOverride':
            [[PyTango.DevVoid, "none"],
            [PyTango.DevVoid, "none"]],
        }


    #    Attribute definitions
    attr_list = {
        'VoltSet':
            [[PyTango.DevDouble,
            PyTango.SCALAR,
            PyTango.READ_WRITE],
            {
                'label': "Voltage Setpoint",
                'unit': "V",
                'standard unit': "V",
                'display unit': "V",
                'format': "%7.3f",
                'max value': "20.0",
                'min value': "-20.0",
                'Memorized':"true_without_hard_applied"
            } ],
        'Volt':
            [[PyTango.DevDouble,
            PyTango.SCALAR,
            PyTango.READ],
            {
                'label': "Voltage Readback",
                'unit': "V",
                'standard unit': "V",
                'display unit': "V",
                'format': "%7.3f",
                'max value': "20.0",
                'min value': "-20.0",
            } ],
        'OutputOn':
            [[PyTango.DevBoolean,
            PyTango.SCALAR,
            PyTango.READ]],
        'OutputOnSet':
            [[PyTango.DevBoolean,
            PyTango.SCALAR,
            PyTango.READ_WRITE]],
        'Battery1State':
            [[PyTango.DevLong,
            PyTango.SCALAR,
            PyTango.READ]],
        'Battery1StateStr':
            [[PyTango.DevString,
            PyTango.SCALAR,
            PyTango.READ]],
        'Battery2State':
            [[PyTango.DevLong,
            PyTango.SCALAR,
            PyTango.READ]],
        'Battery2StateStr':
            [[PyTango.DevString,
            PyTango.SCALAR,
            PyTango.READ]],
        'BatteryInfo':
            [[PyTango.DevString,
            PyTango.SCALAR,
            PyTango.READ]],
        'DevIdent':
            [[PyTango.DevString,
            PyTango.SCALAR,
            PyTango.READ]],
        'Trigger_BatChargeOverride':
            [[PyTango.DevLong,
            PyTango.SCALAR,
            PyTango.READ_WRITE],
            {
                'description': "Triggers execution of the BatChargeOverride command when written to",
            } ],
        'Connected':
            [[PyTango.DevBoolean,
            PyTango.SCALAR,
            PyTango.READ]],
        'BatteryService':
            [[PyTango.DevBoolean,
            PyTango.SCALAR,
            PyTango.READ],
            {
                'description': "True if service batteries LED on the SIM928 is lit.",
            } ],
        'Trigger_Reconnect':
            [[PyTango.DevLong,
            PyTango.SCALAR,
            PyTango.READ_WRITE]],
        'Trigger_Disconnect':
            [[PyTango.DevLong,
            PyTango.SCALAR,
            PyTango.READ_WRITE]],
        }


def main():
    try:
        py = PyTango.Util(sys.argv)
        py.add_class(SRS_SIM928Class, SRS_SIM928, 'SRS_SIM928')
        #----- PROTECTED REGION ID(SRS_SIM928.add_classes) ENABLED START -----#
        
        #----- PROTECTED REGION END -----#	//	SRS_SIM928.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()
