#!/usr/bin/env python
import threading
import numpy
import signal
import time

from pcaspy import Driver, SimpleServer, Severity
from config import pvdb

T_UPDATE = 1/16/2

IS_WRITTEN_LIST =[
    'WL_WRITE', 'POW_WRITE', 'WL_MODON', 'WL_MODTYPE', 'WL_MODCPL', 'MODULE_ON'
]

class PcasDriver(Driver):
    def __init__(self, koheras):
        Driver.__init__(self)
        self.koheras = koheras

        self.setParam('MODULE_TYPE', self.koheras.type)
        self.setParam('MODULE_SN', self.koheras.SN)
        self.setParam('MODULE_SETUP', self.koheras.setup)
        self.setParam('MODULE_STATUS', self.koheras.status)

        self.setParam('WL_REF', self.koheras.wlref)
        self.setParam('WL_SET', self.koheras.wlset)
        self.setParam('POW_SET', self.koheras.pset)

        self.setParam('WL_WRITE', self.koheras.wlset)
        self.setParam('POW_WRITE', self.koheras.pset)

        modon = (self.koheras.setup & (1 << 2)) >> 2
        modtype = (self.koheras.setup & (1 << 1)) >> 1
        modcpl = (self.koheras.setup & (1 << 3)) >> 3
        self.setParam('WL_MODON', modon)
        self.setParam('WL_MODTYPE', modtype)
        self.setParam('WL_MODCPL', modcpl)

        emission = self.koheras.status & 1
        self.setParam('MODULE_ON', emission)

        self.updatePVs()

        self.eid = threading.Event()
        self.tid = threading.Thread(target = self.serialCom)
        self.tid.setDaemon(True)
        self.tid.start()

    def write(self, reason, value):
        # take proper actions
        if reason in IS_WRITTEN_LIST:
            written = 0

            if reason == "WL_WRITE":
                written += 1
            if reason == "POW_WRITE":
                written += 2
            if reason == "WL_MODON":
                written += 4
            if reason == "WL_MODTYPE":
                written += 8
            if reason == "WL_MODCPL":
                written += 16
            if reason == "MODULE_ON":
                written += 32

            self.setParam("WRITTEN", written)
            self.setParam(reason, value)

            self.updatePVs()

        return True

    def serialCom(self,):
        base_time = time.time()
        next_time = 0
        Updatetime = T_UPDATE
        while True:
            written = self.getParam("WRITTEN")

            if written:

                if written & (1 << 0):
                    wl_sp = self.getParam("WL_WRITE")
                    wl_written = self.koheras.wl_offset_sp_write(wl_sp)
                    if wl_written == wl_sp:
                        self.setParam("WL_SET", wl_sp)
                        written -= 1

                if written & (1 << 1):
                    pow_sp = self.getParam("POW_WRITE")
                    pow_written = self.koheras.power_sp_write(pow_sp)
                    if pow_written == pow_sp:
                        self.setParam("POW_SET", pow_sp)
                        written -= 2

                if written & (1 << 2):
                    modon = self.getParam("WL_MODON")
                    modon_written = self.koheras.wl_modulation(modon)
                    if modon_written == modon:
                        written -= 4

                if written & (1 << 3):
                    modtype = self.getParam("WL_MODTYPE")
                    modtype_written = self.koheras.wl_modtype(modtype)
                    if modtype_written == modtype:
                        written -= 8

                if written & (1 << 4):
                    modcpl = self.getParam("WL_MODCPL")
                    modcpl_written = self.koheras.wl_coupling(modcpl)
                    if modcpl_written == modcpl:
                        written -= 16

                if written & (1 << 5):
                    emission = self.getParam("MODULE_ON")
                    emission_written = self.koheras.emission(emission)
                    if emission_written == emission:
                        written -= 32

                self.setParam("WRITTEN", written)

            wl = self.koheras.wl_read()
            pow = self.koheras.power_read()
            temp = self.koheras.module_temp_read()
            vol = self.koheras.voltage_read()

            setup =self.koheras.setup_read()
            status =self.koheras.status_read()

            if wl:
                self.setParam('WL_READ', wl)
            if pow:
                self.setParam('POW_READ', pow)
            if temp:
                self.setParam('MODULE_TEMP', temp)
            if vol:
                self.setParam('MODULE_VOL', vol)
            if setup:
                self.setParam('MODULE_SETUP', setup)
            if status:
                self.setParam('MODULE_STATUS', status)

            self.updatePVs()

            next_time =((base_time - time.time()) % Updatetime) or Updatetime
            time.sleep(next_time)


    # def runSimScope(self):
        # simulate scope waveform
        # while True:
            # run = self.getParam('Run')
            # UpdateTime = self.getParam('UpdateTime')
            # signal.signal(signal.SIGALRM, self.scheduler)
            # signal.settimer(signal.ITIMER_REAL, UpdateTime, UpdateTime)

if __name__ == '__main__':

    import sys
    from koheras import Koheras

    port = sys.argv[1]
    koheras = Koheras(port)

    prefix = sys.argv[2]

    server = SimpleServer()
    server.createPV(prefix, pvdb)
    driver = PcasDriver(koheras)

    # process CA transactions
    while True:
        server.process(0.01)
