import time
class newadc(Device):
	process = cpt(EpicsSignal,'Trigger')
	process.trigger_value=1
	value = cpt(EpicsSignal,'.VAL')
	it = cpt(EpicsSignal,'IntegralTime')
	ready = cpt(EpicsSignal,'Ready')
	ch0 = cpt(EpicsSignal,'CH0')
	ch1 = cpt(EpicsSignal,'CH1')
	ch2 = cpt(EpicsSignal,'CH2')
	xafs = cpt(EpicsSignal,'XAFS')
	mode = cpt(EpicsSignal,'Mode')

	def trigger(self):
		signals = self.trigger_signals
		if len(signals) > 1:
			raise NotImplementedError("more than one trigger signal")
		status = DeviceStatus(self)
		if not signals:
			status._finished()
			return status
		acq_signal, = signals
		self.subscribe(status._finished, event_type=self.SUB_ACQ_DONE, run = False)
		def done_acquisition(**ignored_kwargs):
			self._done_acquisition()
		
		self.process.put(1)
		if self.mode.get() == 1:
			print('ERROR:The mode is monitor\n')
			return -1
		time.sleep(self.it.get())	
		while(self.ready.get()!=1):
			time.sleep(0.001)
		self.ch0.get()
		self.ch1.get()
		self.ch2.get()
		self.xafs.get()
		self._done_acquiring()
		return status
class adc(Device):
	process = cpt(EpicsSignal,'.PROC')
	process.trigger_value=1
	value = cpt(EpicsSignal,'.VAL')
	def trigger(self):
		signals = self.trigger_signals
		if len(signals) > 1:
			raise NotImplementedError("more than one trigger signal")
		status = DeviceStatus(self)
		if not signals:
			status._finished()
			return status
		acq_signal, = signals
		self.subscribe(status._finished, event_type=self.SUB_ACQ_DONE, run = False)
		def done_acquisition(**ignored_kwargs):
			self._done_acquisition()
		self.process.put(1)
		self._done_acquiring()
		return status

import logging

import logging

from ophyd.utils.epics_pvs import fmt_time

from ophyd.signal import (EpicsSignal, EpicsSignalRO)
from ophyd.utils import DisconnectedError
from ophyd.utils.epics_pvs import (raise_if_disconnected, AlarmSeverity)
from ophyd.positioner import PositionerBase
from ophyd.device import (Device, Component as Cpt)
from ophyd.status import wait as status_wait
from enum import Enum


logger = logging.getLogger(__name__)


class HomeEnum(str, Enum):
    forward = "forward"
    reverse = "reverse"


class blcg(Device, PositionerBase):
    '''An EPICS motor record, wrapped in a :class:`Positioner`

    Keyword arguments are passed through to the base class, Positioner

    Parameters
    ----------
    prefix : str
        The record to use
    read_attrs : sequence of attribute names
        The signals to be read during data acquisition (i.e., in read() and
        describe() calls)
    name : str, optional
        The name of the device
    parent : instance or None
        The instance of the parent device, if applicable
    settle_time : float, optional
        The amount of time to wait after moves to report status completion
    timeout : float, optional
        The default timeout to use for motion requests, in seconds.
    '''
    # position
    user_readback = Cpt(EpicsSignalRO, 'EnergyReadback', kind='hinted')
    user_setpoint = Cpt(EpicsSignal, 'EnergySet', limits=True)

    # calibration dial <-> user
    user_offset = Cpt(EpicsSignal, 'BraggTop.OFF', kind='config')
    user_offset_dir = Cpt(EpicsSignal, 'BraggTop.DIR', kind='config')
    offset_freeze_switch = Cpt(EpicsSignal, 'BraggTop.FOFF', kind='omitted')
    set_use_switch = Cpt(EpicsSignal, 'BraggTop.SET', kind='omitted')

    # configuration
    velocity = Cpt(EpicsSignal, 'BraggTop.VELO', kind='config')
    acceleration = Cpt(EpicsSignal, 'BraggTop.ACCL', kind='config')
    motor_egu = Cpt(EpicsSignal, 'BraggTop.EGU', kind='config')

    # motor status
    motor_is_moving = Cpt(EpicsSignalRO, 'BraggTop.MOVN', kind='omitted')
    motor_done_move = Cpt(EpicsSignalRO, 'BraggTop.DMOV', kind='omitted')
    high_limit_switch = Cpt(EpicsSignal, 'BraggTop.HLS', kind='omitted')
    low_limit_switch = Cpt(EpicsSignal, 'BraggTop.LLS', kind='omitted')
    direction_of_travel = Cpt(EpicsSignal, 'BraggTop.TDIR', kind='omitted')

    # commands
    motor_stop = Cpt(EpicsSignal, 'BraggTop.STOP', kind='omitted')
    home_forward = Cpt(EpicsSignal, 'BraggTop.HOMF', kind='omitted')
    home_reverse = Cpt(EpicsSignal, 'BraggTop.HOMR', kind='omitted')

    # alarm information
    tolerated_alarm = AlarmSeverity.NO_ALARM

    def __init__(self, *args, **kwargs):

        super().__init__(*args, **kwargs)

        # Make the default alias for the user_readback the name of the
        # motor itself.
        self.user_readback.name = self.name

        self.motor_done_move.subscribe(self._move_changed)
        self.user_readback.subscribe(self._pos_changed)

    @property
    @raise_if_disconnected
    def precision(self):
        '''The precision of the readback PV, as reported by EPICS'''
        return self.user_readback.precision

    @property
    @raise_if_disconnected
    def egu(self):
        '''The engineering units (EGU) for a position'''
        return self.motor_egu.get()

    @property
    @raise_if_disconnected
    def limits(self):
        return self.user_setpoint.limits

    @property
    @raise_if_disconnected
    def moving(self):
        '''Whether or not the motor is moving

        Returns
        -------
        moving : bool
        '''
        return bool(self.motor_is_moving.get(use_monitor=False))

    @raise_if_disconnected
    def stop(self, *, success=False):
        self.motor_stop.put(1, wait=False)
        super().stop(success=success)

    @raise_if_disconnected
    def move(self, position, wait=True, **kwargs):
        '''Move to a specified position, optionally waiting for motion to
        complete.

        Parameters
        ----------
        position
            Position to move to
        moved_cb : callable
            Call this callback when movement has finished. This callback must
            accept one keyword argument: 'obj' which will be set to this
            positioner instance.
        timeout : float, optional
            Maximum time to wait for the motion. If None, the default timeout
            for this positioner is used.

        Returns
        -------
        status : MoveStatus

        Raises
        ------
        TimeoutError
            When motion takes longer than `timeout`
        ValueError
            On invalid positions
        RuntimeError
            If motion fails other than timing out
        '''
        self._started_moving = False

        status = super().move(position, **kwargs)
        self.user_setpoint.put(position, wait=False)
        try:
            if wait:
                status_wait(status)
        except KeyboardInterrupt:
            self.stop()
            raise

        return status

    @property
    @raise_if_disconnected
    def position(self):
        '''The current position of the motor in its engineering units

        Returns
        -------
        position : float
        '''
        return self._position

    @raise_if_disconnected
    def set_current_position(self, pos):
        '''Configure the motor user position to the given value

        Parameters
        ----------
        pos
           Position to set.

        '''
        self.set_use_switch.put(1, wait=True)
        self.user_setpoint.put(pos, wait=True)
        self.set_use_switch.put(0, wait=True)

    @raise_if_disconnected
    def home(self, direction, wait=True, **kwargs):
        '''Perform the default homing function in the desired direction

        Parameters
        ----------
        direction : HomeEnum
           Direction in which to perform the home search.
        '''
        direction = HomeEnum(direction)

        self._started_moving = False
        position = (self.low_limit+self.high_limit)/2
        status = super().move(position, **kwargs)

        if direction == HomeEnum.forward:
            self.home_forward.put(1, wait=False)
        else:
            self.home_reverse.put(1, wait=False)

        try:
            if wait:
                status_wait(status)
        except KeyboardInterrupt:
            self.stop()
            raise

        return status

    def check_value(self, pos):
        '''Check that the position is within the soft limits'''
        self.user_setpoint.check_value(pos)

    def _pos_changed(self, timestamp=None, value=None, **kwargs):
        '''Callback from EPICS, indicating a change in position'''
        self._set_position(value)

    def _move_changed(self, timestamp=None, value=None, sub_type=None,
                      **kwargs):
        '''Callback from EPICS, indicating that movement status has changed'''
        was_moving = self._moving
        self._moving = (value != 1)

        started = False
        if not self._started_moving:
            started = self._started_moving = (not was_moving and self._moving)

        self.log.debug('[ts=%s] %s moving: %s (value=%s)', fmt_time(timestamp),
                       self, self._moving, value)

        if started:
            self._run_subs(sub_type=self.SUB_START, timestamp=timestamp,
                           value=value, **kwargs)

        if was_moving and not self._moving:
            success = True
            # Check if we are moving towards the low limit switch
            if self.direction_of_travel.get() == 0:
                if self.low_limit_switch.get() == 1:
                    success = False
            # No, we are going to the high limit switch
            else:
                if self.high_limit_switch.get() == 1:
                    success = False

            # Check the severity of the alarm field after motion is complete.
            # If there is any alarm at all warn the user, and if the alarm is
            # greater than what is tolerated, mark the move as unsuccessful
            severity = self.user_readback.alarm_severity

            if severity != AlarmSeverity.NO_ALARM:
                status = self.user_readback.alarm_status
                if severity > self.tolerated_alarm:
                    self.log.error('Motion failed: %s is in an alarm state '
                                   'status=%s severity=%s',
                                   self.name, status, severity)
                    success = False
                else:
                    self.log.warning('Motor %s raised an alarm during motion '
                                     'status=%s severity %s',
                                     self.name, status, severity)
            self._done_moving(success=success, timestamp=timestamp,
                              value=value)

    @property
    def report(self):
        try:
            rep = super().report
        except DisconnectedError:
            # TODO there might be more in this that gets lost
            rep = {'position': 'disconnected'}
        rep['pv'] = self.user_readback.pvname
        return rep

