#odczet z mojego rejestratora 8 kanałowego
#oprocz tego z RIGOL-ow.

from http.client import LineTooLong
import itertools
from logging import NullHandler
import numpy as np
from matplotlib import dates
import matplotlib.pyplot as plt
import matplotlib.animation as animation
import datetime as dt
plt.rcParams['toolbar'] = 'toolmanager'
from matplotlib.backend_tools import ToolBase, ToolToggleBase

import serial
import time

import pandas as pd

import pyvisa
import time

from tkinter import filedialog as fd
from tkinter import simpledialog as sd
from tkinter.messagebox import askyesno

serials = []
inst = None
stop = False



def connect():
    global serials, inst
    for ser in serials:
        if ser:
            ser.close()
    serials = []
    try:
        ser=serial.Serial(
        port='COM99',
        baudrate=9600,
        parity=serial.PARITY_NONE,
        stopbits=serial.STOPBITS_ONE,
        bytesize=serial.EIGHTBITS,
        timeout=1
        )
        if ser.isOpen():
            print('Połączyłem się z portem ' + ser.name )
        serials.append(ser)
    except:
        print("Nie mogłem połączyć się z portem")
        ser = None

    try:
        ser=serial.Serial(
        port='COM99',
        baudrate=115200,
        parity=serial.PARITY_NONE,
        stopbits=serial.STOPBITS_ONE,
        bytesize=serial.EIGHTBITS,
        timeout=1
        )
        if ser.isOpen():
            print('Połączyłem się z portem ' + ser.name )
        serials.append(ser)
    except:
        print("Nie mogłem połączyć się z portem")
        ser = None


    try:
        ser=serial.Serial(
        port='COM22',
        baudrate=115200,
        parity=serial.PARITY_NONE,
        stopbits=serial.STOPBITS_ONE,
        bytesize=serial.EIGHTBITS,
        timeout=1
        )
        if ser.isOpen():
            print('Połączyłem się z portem ' + ser.name )
        serials.append(ser)
    except:
        print("Nie mogłem połączyć się z portem COM ")
        ser = None
    try:
        #https://www.batronix.com/pdf/Rigol/ProgrammingGuide/DM3058_ProgrammingGuide_EN.pdf
        rm = pyvisa.ResourceManager()
        print(rm.list_resources())
        # RIGOL 3058E absługuje dwa kanały (lab C50) nie obsługuje komendy :READ? sensor (n.p.PT100) definiowany tylko poprzez tabelę są wgrane typowe czujniki 
        inst = rm.open_resource('USB0::0x1AB1::0x09C4::DM3R200300164::INSTR')  

        # RIGOL DM3068 obsługuje tylko jeden kanał, działa komenda :READ? sensory definiowane oprócz tabel przez współczynniki n.p. dla PT100: alva RO
        #inst = rm.open_resource('USB0::0x1AB1::0x0C94::DM3O205100932::INSTR') # u mnie
        #inst = rm.open_resource('USB0::0x1AB1::0x0C94::DM3O202800594::INSTR') # od Kali

        print("Połączona się z RIGOLEM ")

        # pomiar prądu
        # inst.write(":FUNCtion:CURRent:DC")   # ustawienie na IDC

        # pomiar napięcie, jeśli jest obsługiwany drugi kanał to na drugim kanale
        # inst.write(":FUNCtion2:VOLTage:DC")   # ustawienie 2 na VDC

        # pomiar rezystancji
        # inst.write(":FUNCtion:RESistance")   # ustawienie na RES

        # pomiar sensor - PT-100
        #inst.write(":FUNCtion")   # ustawienie na SEN
        inst.write(":FUNCtion:SENsor")   # ustawienie na SEN

        print("Ustawiono RIGOL na ", inst.query("*IDN?"))


    except:
        print("Nie mogłem połączyć się z RIGOLEM")
        inst = None



step_min = 1
nt = np.datetime64(dt.datetime.now())
st = np.timedelta64(step_min, 'm')


#fig, (axT, axC, axU) = plt.subplots(3, sharex=True, sharey=False)
fig, (axT) = plt.subplots(1, sharex=True, sharey=False)
#fig, (axT, axS) = plt.subplots(2, sharex=True, sharey=False)

lineT = []

axT.set_xlim(nt, nt + st)
axT.set_ylim(22, 23)
axT.grid()

for t in range(10):
    l, = axT.plot([], [], '-')
    lineT.append(l)

if 'axC' in globals():
    lineC, = axC.plot([], [], '-b')
    axC.grid()
    axC.set_ylabel("I [uA]")
    axC.set_xlim(nt, nt + st)
    axC.set_ylim(0, 0.000001)
else:
  lineC = None

if 'axU' in globals():
    lineU, = axC.plot([], [], '-r')
    axU.grid()
    axU.set_ylabel("U [V]")
    axU.set_xlim(nt, nt + st)
    axU.set_ylim(0, 10)
else:
  lineU = None

if 'axR' in globals():
    lineR, = axR.plot([], [], '-r')
    axR.grid()
    axR.set_ylabel("$R [\Omega]$")
    axR.set_xlim(nt, nt + st)
    axR.set_ylim(0, 10)
else:
  lineR = None


df = pd.DataFrame(data=[]) #, columns=['Czas','Temp0','Cur','Vol'])

#plt.xticks(rotation=45, ha='right')
hfmt = dates.DateFormatter('%H:%M:%S')
axT.xaxis.set_major_formatter(hfmt)

#fig.canvas.set_window_title("pomiary-plot")
fig.canvas.setWindowTitle("pomiary-plot")

plt.xlabel("Czas [g:m:s]")
axT.set_ylabel("$T [°C]$")
plt.tight_layout()

plt.legend()



# obsługa paska narzędzi
# https://matplotlib.org/stable/gallery/user_interfaces/toolmanager_sgskip.html
class Zapisz(ToolBase):
    default_keymap = 'm'
    description = 'Zapis do CSV'
    def trigger(self, *args, **kwargs):
        filename = fd.asksaveasfilename(filetypes=[("Plik CSV","*.csv")], defaultextension = "*.csv") 
        if filename != '':
            df.to_csv(filename, sep = ';', decimal = '.', index=False)
            print("Zapisano do pliku {}\n".format(filename))
        

class ReConnect(ToolBase):
    default_keymap = 'x'
    description = 'Reconect'
    def trigger(self, *args, **kwargs): 
        connect()


def nStop():
    global stop, ani
    if not stop:
        ani.event_source.stop()
    else:
        ani.event_source.start()
    stop = not stop


class StopStart(ToolBase):
    global stop
    default_keymap = 'z'
    if stop:
        description = 'Start'
    else:
        description = 'Stop'

    def trigger(self, *args, **kwargs): 
        nStop()
        ZmianaToolBar()

class Otworz(ToolBase):
    default_keymap = 'm'
    description = 'Otwórz CSV'
    def trigger(self, *args, **kwargs):
        filename = fd.askopenfilename(filetypes=[("Plik CSV","*.csv")], defaultextension = "*.csv") 
        if filename != '':
            global df
            dfr = pd.read_csv(filename, sep = ';', decimal = '.')
            df = df.append(dfr, ignore_index=True)
            print(df)

            lineT[0].set_data(df['Czas'], df['Temp'])
            lineC.set_data(df['Czas'], df['Cur'])
            lineU.set_data(df['Czas'], df['Vol'])
            min = df['Czas'].min()
            max = df['Czas'].max()
            axT.set_xlim(min, max)
            axC.set_xlim(min, max)
            axU.set_xlim(min, max)

            axT.set_ylim(df['Temp'].min(), df['Temp'].max())
            try:
                axC.set_ylim(df['Cur'].min(), df['Cur'].max())
            except:
                axC.set_ylim(0, 0.000001)

            try:
                axU.set_ylim(df['Vol'].min(), df['Vol'].max())
            except:
                axU.set_ylim(0, 10)

            fig.canvas.draw_idle()

class Czysc(ToolBase):
    default_keymap = 'c'
    description = 'Czyść dane'
    def trigger(self, *args, **kwargs):
        
        if askyesno(title='Potwierdzenie', message='Czy na pewno usunąć wszystkie dane?'):
            global df
            df = df[0:0]
            for t in range(len(lineT)):
                lineT[t].set_data(df['Czas'], df['Temp0'])
            lineC.set_data(df['Czas'], df['Cur'])
            lineU.set_data(df['Czas'], df['Vol'])
            t = np.datetime64(dt.datetime.now())
            st = np.timedelta64(step_min, 'm')
            axT.set_xlim(t, t + st)
            axC.set_xlim(t, t + st)
            axU.set_xlim(t, t + st)
            fig.canvas.draw_idle()


def ZmianaToolBar():
    global stop
    if fig.canvas.manager.toolmanager.get_tool('Zapisz'):
        fig.canvas.manager.toolmanager.remove_tool('Zapisz') 
    fig.canvas.manager.toolmanager.add_tool('Zapisz', Zapisz)
    fig.canvas.manager.toolbar.add_tool('Zapisz', 'navigation', 1)

    if fig.canvas.manager.toolmanager.get_tool('ReConnect'):
        fig.canvas.manager.toolmanager.remove_tool('ReConnect') 
    fig.canvas.manager.toolmanager.add_tool('ReConnect', ReConnect)
    fig.canvas.manager.toolbar.add_tool('ReConnect', 'navigation', 1)

    if stop:
        if fig.canvas.manager.toolmanager.get_tool('Stop'):
            fig.canvas.manager.toolmanager.remove_tool('Stop')  
        fig.canvas.manager.toolmanager.add_tool('Start', StopStart)
        fig.canvas.manager.toolbar.add_tool('Start', 'navigation', 1)
    else:
        if fig.canvas.manager.toolmanager.get_tool('Start'):
            fig.canvas.manager.toolmanager.remove_tool('Start') 
        fig.canvas.manager.toolmanager.add_tool('Stop', StopStart)
        fig.canvas.manager.toolbar.add_tool('Stop', 'navigation', 1)

    if fig.canvas.manager.toolmanager.get_tool('Otwórz'):
        fig.canvas.manager.toolmanager.remove_tool('Otwórz') 
    fig.canvas.manager.toolmanager.add_tool('Otwórz', Otworz)
    fig.canvas.manager.toolbar.add_tool('Otwórz', 'navigation', 1)

    if fig.canvas.manager.toolmanager.get_tool('Czyść'):
        fig.canvas.manager.toolmanager.remove_tool('Czyść') 
    fig.canvas.manager.toolmanager.add_tool('Czyść', Czysc)
    fig.canvas.manager.toolbar.add_tool('Czyść', 'navigation', 1)


ZmianaToolBar()


def filter(s):
    r = ''
    for c in s:
        if chr(c) in ['0','1','2','3','4','5','6','7','8','9','.','-',';',',']:
            r = r + chr(c)
    return r

def data_gen():
    global serials, inst, stop, df
    for cnt in itertools.count():
        temps = []
        for ser in serials:
            if ser:
                if 1:
                    ser.write(str.encode('t'))
                    r =  filter(ser.readline())
                    r = r.replace(';',',')
                    #r = r.replace(' ','')
                    t = r.split(',')
                    for i in range(len(t)):
                       if  t[i] == "":
                           continue
                       if float(t[i]) > - 100:
                            temps.append(float(t[i]))
                       else:
                            temps.append(None)
#                except:
#                    pass
                    
#                    temps = None
#                    ser = None
#            else:
#                temps = None
        print('temps=')
        print(temps)
        # pomar temperatury przez RIGOL-a
        try:
            #ts = inst.query(":READ?")
            ts = inst.query(":FUNCtion2:VALUe1?")
            t = float(ts)
            temps.append(t)
        except:
            ii = 0

        cur = None
        vol = None
        res = None

#
#        try:
#            cur = abs(float(inst.query(":FUNCtion2:VALUe1?")))
#        except:
#            cur = None

#        try:
#            vol = abs(float(inst.query(":FUNCtion2:VALUe2?")))
#        except:
#            vol = None

#        try:
#            res = abs(float(inst.query(":FUNCtion2:VALUe1?")))
#        except:
#            res = None

        czas = np.datetime64(dt.datetime.now())
        #print(czas, temp, cur, vol)
        #print(df.count())

        yield czas, temps, cur, vol, res



def run(data):
    # update the data
    global df
    czas, temps, cur, vol, res = data

    row = {}
    row['Czas'] = czas
    for i in range(len(temps)):
        row['Temp{}'.format(i+1)] = temps[i]

    if lineC:
        row['Cur'] = cur
    if lineU:
        row['Vol'] = vol
    if lineR:
        row['Res'] = res


    #df = df.append(row,ignore_index=True)
    df = pd.concat([df, pd.DataFrame(row, index=[0])],ignore_index=True)

    print(df.tail(1))

    xmin, xmax = axT.get_xlim()
    temp_min, temp_max = axT.get_ylim()

    if lineC:
        cur_min, cur_max = axC.get_ylim()
    if lineU:
        vol_min, vol_max = axU.get_ylim()
    if lineR:
        res_min, res_max = axR.get_ylim()

    tt = dates.date2num(czas)
  
    if tt >= xmax:
        axT.set_xlim(xmin, tt + 0.001)
        axT.figure.canvas.draw()
        if lineC:
            axC.set_xlim(xmin, tt + 0.001)
            axC.figure.canvas.draw()
        if lineU:
            axU.set_xlim(xmin, tt + 0.001)
            axU.figure.canvas.draw()

    for temp in temps:
        if temp:
            if temp >= temp_max:
                temp_max = temp
                axT.set_ylim(temp_min, temp + 1)
                axT.figure.canvas.draw()

            if temp <= temp_min:
                temp_min = temp
                axT.set_ylim(temp-1, temp_max)
                axT.figure.canvas.draw()

        
    if cur and lineC:
        if cur >= cur_max:
            axC.set_ylim(cur_min, cur + 1e-6)
            axC.figure.canvas.draw()

        if cur <= cur_min:
            axC.set_ylim(cur - 1e-6, cur_max)
            axC.figure.canvas.draw()

    if vol and lineU:
        if vol >= vol_max:
            axU.set_ylim(vol_min, vol + 10)
            axU.figure.canvas.draw()

        if vol <= vol_min:
            axU.set_ylim(vol - 10, vol_max)
            axU.figure.canvas.draw()

    if res and lineR:
        if res >= res_max:
            axR.set_ylim(res_min, res + 10)
            axR.figure.canvas.draw()

        if res <= res_min:
            axR.set_ylim(res - 10, res_max)
            axR.figure.canvas.draw()


    for t in range(len(temps)):
        lineT[t].set_data(df['Czas'], df['Temp{}'.format(t+1)])
        lineT[t].set_label('$T_{}$'.format(t+1))
        axT.legend(loc='lower left')

    if lineC:
        lineC.set_data(df['Czas'], df['Cur'])
    if lineU:
        lineU.set_data(df['Czas'], df['Vol'])
    if lineR:
        lineR.set_data(df['Czas'], df['Res'])
   
    return None# lineT, lineC, lineU

connect()
ani = animation.FuncAnimation(fig, run, data_gen, interval=200)#, init_func=init)
plt.show()
