libpath = '/home/l_samenv/frappy/cetoniSDK/CETONI_SDK_Raspi_64bit_v20220627/python/src/'
import sys
if libpath not in sys.path:
    sys.path.append(libpath)

from frappy.core import Drivable, Readable, StringIO, HasIO, FloatRange, IntRange, StringType, BoolType, EnumType, \
    Parameter, Property, PersistentParam, Command, IDLE, BUSY, ERROR, Attached
from qmixsdk import qmixbus
from qmixsdk import qmixpump
from qmixsdk import qmixvalve
from qmixsdk.qmixbus import UnitPrefix, TimeUnit

class LabCannBus(Readable):
    deviceconfig = Property('config files', StringType(),default="/home/l_samenv/frappy/cetoniSDK/CETONI_SDK_Raspi_64bit_v20220627/config/dual_pumps")

    def earlyInit(self):
        super().earlyInit()
        self.bus = qmixbus.Bus()
        self.bus.open(self.deviceconfig, "")

    def initModule(self):
        super().initModule()
        self.bus.start()

    def shutdownModule(self):
        """Not so gracefully close the connection"""
        self.bus.stop()
        self.bus.close()

class SyringePump(Drivable):
    io = Attached()
    pump_name = Property('name of pump', StringType(),default="Nemesys_S_1_Pump")
    valve_name = Property('name of valve', StringType(),default="Nemesys_S_1_Valve")
    
    inner_diameter_set = Property('inner diameter', FloatRange(), default=1)
    piston_stroke_set = Property('piston stroke', FloatRange(), default=60)
    
    value = PersistentParam('volume', FloatRange(unit='mL'))
    status = PersistentParam()
    
    max_flow_rate = Parameter('max flow rate', FloatRange(0,100000, unit='mL/min',), readonly=True)
    max_volume = Parameter('max volume', FloatRange(0,100000, unit='mL',), readonly=True)
    target_flow_rate = Parameter('target flow rate', FloatRange(unit='mL/min'), readonly=False)
    real_flow_rate = Parameter('actual flow rate', FloatRange(unit='mL/min'), readonly=True)
    target = Parameter('target volume', FloatRange(unit='mL'), readonly=False)

    no_of_valve_pos = Property('number of valve positions', IntRange(0,10), default=1)
    valve_pos = Parameter('valve position', EnumType('valve', CLOSED=0, APP=1, RES=2, OPEN=3), readonly=False)

    def initModule(self):
        super().initModule()

        self.pump = qmixpump.Pump()
        self.pump.lookup_by_name(self.pump_name)

        self.valve = qmixvalve.Valve()
        self.valve.lookup_by_name(self.valve_name)


    def initialReads(self):
        if self.pump.is_in_fault_state():
            self.pump.clear_fault()
        
        if not self.pump.is_enabled():
            self.pump.enable(True)
        
        self.pump.set_syringe_param(self.inner_diameter_set, self.piston_stroke_set)

        self.pump.set_volume_unit(qmixpump.UnitPrefix.milli, qmixpump.VolumeUnit.litres)

        self.pump.set_flow_unit(qmixpump.UnitPrefix.milli, qmixpump.VolumeUnit.litres, qmixpump.TimeUnit.per_minute)
        
        self.max_flow_rate = self.pump.get_flow_rate_max()
        self.max_volume = self.pump.get_volume_max()
        self.no_of_valve_pos = self.valve.number_of_valve_positions()
        self.valve_pos = self.valve.actual_valve_position()

        self.target_flow_rate = self.max_flow_rate * 0.5
        self.target = self.pump.get_fill_level()
    
    def read_value(self):
        return self.pump.get_fill_level()

    def write_target(self, target):
        self.pump.set_fill_level(target, self.target_flow_rate)
        self.status = BUSY, 'Target changed'
        return target

    def write_target_flow_rate(self, rate):
        self.pump.target_flow_rate = rate
        return rate

    def read_real_flow_rate(self):
        return self.pump.get_flow_is()

    def read_valve_pos(self):
        return self.valve.actual_valve_position()

    def write_valve_pos(self, target_pos):
        self.valve.switch_valve_to_position(target_pos)
        return target_pos

    def read_status(self):
        fault_state = self.pump.is_in_fault_state()
        pumping = self.pump.is_pumping()
        if fault_state == True:
            return ERROR, 'Pump in fault state'
        elif pumping == True:
            return BUSY, 'Pumping'
        else:
            return IDLE, ''

    @Command
    def stop(self):
        self.pump.stop_pumping()
        self.target = self.pump.get_fill_level()
