# LAN/COM/USB-CDC/USB-TMC/GP-IB Access Sample                Ver1.00
# 本サンプルはWindowsでのみ動作確認となります。
# NI-VISAのフルインストール版が必要です。
# 対象電源はPDW/GPPシリーズﾉ2chモデルです。
# PythonからVISAの機器と通信する場合はpyVISAモジュールを利用します。
# GUI表示はTkinterを使用しています。
# デバイスを検索し一覧表示から選択し通信を行います。
# Socketデバイスの場合はNI-MAXに登録してから利用してください。

# coding:utf-8
import pyvisa as visa   # VISAモジュール
import tkinter as tk    # tkモジュール
import time
from time import sleep
from tkinter import ttk
import datetime
import csv
import tkinter.filedialog
import os
import sys

rm = visa.ResourceManager()                 #rmとinstrをグローバルとして定義
instr = None

def Find_clicked():
    try:
# デバイスを検索し一覧表示します
        cbDevList['values']=['']

        instruments = rm.list_resources('?*')
        if len(instruments) > 0:
            cbDevList['values']=instruments
            cbDevList.current(0)              # Error処理
            btn3['state'] = tk.NORMAL 
    except:
        print('Device Error')

def Exit_clicked():                           #Exitボタン処理

    rm.close()          # デバイスとの通信を終了します。
    root.destroy()

def Open_clicked():
    global instr 
    visaAddr = cbDevList.get()
    if( visaAddr == '' ):
        print('No Device!')
    else:
        try:
            instr = rm.open_resource(visaAddr)
            if instr.resource_name.startswith('ASRL'):
                instr.read_termination = '\n'
                instr.write_termination = '\n'
                instr.baud_rate = int(txtOption.get())


            if instr.resource_name.endswith('SOCKET'):
                instr.read_termination = '\n'
                instr.write_termination = '\n'
        
            btn2['state'] = tk.DISABLED     # OPEN/EXIT禁止､CLOSE/Send/Recive有効
            btn3['state'] = tk.DISABLED
            btn4['state'] = tk.NORMAL
            btn5['state'] = tk.NORMAL
            instr.write(':ALLOUTOFF')
            instr.write('LOAD1:CC ON,FAST')
            instr.write('LOAD2:CC OFF,FAST')

# Error処理
        except:
            print('No Device!')


def cmb_Sel(event):                              #コンボボックス選択処理
    txtOption.delete(0,tk.END)
    cbuff = cbDevList.get()
    if('ASRL' in cbuff):
        txtOption['state'] = tk.NORMAL
        txtOption.insert(tk.END,'9600')
    else:
        txtOption['state'] = tk.DISABLED


def Close_clicked():                             #Closeボタン処理
    global instr                                 #Globalのinstr変数を利用

    instr.write('syst:loc')

    btn2['state'] = tk.NORMAL     # OPEN/EXIT有効､CLOSE/Send/Recive禁止
    btn3['state'] = tk.NORMAL
    btn4['state'] = tk.DISABLED
    btn5['state'] = tk.DISABLED
    btn6['state'] = tk.DISABLED

    instr.close()                                #VISAデバイスをクロース


def SAVE_clicked():                             #ダイアログを表示してCSV保存
    filename = tkinter.filedialog.asksaveasfilename(title = "名前を付けて保存",\
         filetypes = [("CSV", ".csv")], initialdir = "./", defaultextension = "csv" )

    with open(filename, "w", newline="", encoding="utf-8") as file:
       writer = csv.writer(file)
       
       file.write('Charge Cap.:')
       file.write(label17.cget('text'))
       file.write(',   Discharge Cap.:')
       file.writelines(label19.cget('text')+'\r\n')

       writer.writerow(["Date/Time", "Chrg/Dis", "Volt", "Curr"])
       for child in tree.get_children():
            writer.writerow(tree.item(child)["values"])  

def CLR_clicked():                              #ログクリア
    for item in tree.get_children():
        tree.delete(item)

def LOOP_clicked():
    global loopFlg
    global duration
    global Holdtime
    global integCurr
    btn5['state'] = tk.DISABLED
    btn6['state'] = tk.NORMAL 


# プリ放電
    instr.write(':ALLOUTOFF')
    instr.write('LOAD1:CC ON,FAST')
    instr.write('LOAD2:CC OFF,FAST')
    txtSend = 'ISET1 '+ txtdCurr.get()
    instr.write(txtSend)
    instr.write('OUTP1 ON')
    txtSend = 'ISET2 '+ txtcCurr.get()
    instr.write(txtSend)
    txtSend = 'VSET2 '+ txtcVolt.get()
    instr.write(txtSend)
    sleep(0.5)

    Holdtime = float(txtdTime.get())
    loopFlg = 1 
    duration = time.perf_counter()
    integCurr = 0
    interval_work()

def STOP_clicked():
    global loopFlg
    
    loopFlg = 0
    btn6['state'] = tk.DISABLED
    btn5['state'] = tk.NORMAL 

def interval_work():                            # インターバルで行う処理を記述
    global loopFlg
    global instr
    global duration
    global Holdtime
    global integCurr

    if (loopFlg > 0):
        root.after(997, interval_work)        # 次のインターバルの時間(ms)を指定  
  
    txt2nd = ''

    if (loopFlg == 2):
        instr.write(':MEAS2:all?')
    else:
        instr.write(':MEAS1:all?')

    sleep(0.1)
    txtRcv = instr.read()                        #応答を受信

    txtTime = datetime.datetime.now()           #日時を取得

    if (loopFlg == 2):
        txtModes ='Chg'
    else:
        txtModes ='Dis'

    txtRead = txtRcv.split(',')                  #受信データを';'で分割
    txt1st = txtRead[0]
    if (len(txtRead) > 1):                       #2個目以後があれば引き当て
        txt2nd = txtRead[1]
    else:
        sleep(0.1)
        txt2nd = instr.read()                    #応答を受信

                                                 #最終行にログを追加
    tree.insert(parent='', index='end', text='TIME',values=(txtTime ,txtModes,txt1st,txt2nd))

    children = tree.get_children()              # 最終行へスクロール
    if children:
        last_item = children[-1]
        tree.see(last_item)

    integCurr += float(txt2nd)
    if (loopFlg == 2):
        label17['text'] = str(int(integCurr/3.6)) + 'mAh'
    else:
        label19['text'] = str(int(integCurr/3.6)) + 'mAh'

    if (float(txt2nd) < 0.01):                    #充放電完了
       next_flg = 1
    elif ((time.perf_counter() - duration) > float(Holdtime) * 3600):      #時間オーバー
       next_flg = 1
    else:       
       next_flg = 0

    if (next_flg == 1):
        instr.write(':ALLOUTOFF')
        label20['text'] = txtTime

        if (loopFlg == 1):        # 充電へ移行
            instr.write('OUTP2 ON')
            Holdtime = float(txtcTime.get())
            duration = time.perf_counter()
            loopFlg = 2

        elif(loopFlg == 2):       # 放電へ移行
            instr.write('OUTP1 ON')
            Holdtime = float(txtdTime.get())
            duration = time.perf_counter()
            loopFlg = 3

        else:                     # 終了 
            loopFlg = 0
            btn6['state'] = tk.DISABLED
            btn5['state'] = tk.NORMAL 

root = tk.Tk()
root.geometry('450x400')
root.title('Battery Test Demo for PDW')
root.iconbitmap(default= os.path.join(os.path.dirname(sys.argv[0]), "icons", "battery4.ico"))

label1 = tk.Label(root, text = 'Device List  :  ')
label1.grid(row=0, column=0)
label2 = tk.Label(root,text = 'Serial Baud :' )
label2.grid(row=1, column=0 )

cbDevList= ttk.Combobox(root , width=50 )
cbDevList.grid(row=0 , column=1 , columnspan = 3)
cbDevList.bind('<<ComboboxSelected>>',cmb_Sel)

txtOption = ttk.Entry(root , width=50 ,   state =tk.DISABLED )
txtOption.grid(row=1 , column=1 , columnspan = 3)

btn1 = tk.Button( root, text='Find'   , command=Find_clicked,width= 7)
btn1.grid(row = 2 , column=0)
btn2 = tk.Button( root, text='Exit'   , command=Exit_clicked,width= 7)
btn2.grid(row = 2 , column=3)
btn3 = tk.Button( root, text='Open'   , command=Open_clicked,   state =tk.DISABLED ,width= 7)
btn3.grid(row = 2 , column=1)
btn4 = tk.Button( root, text='Close'  , command=Close_clicked,  state =tk.DISABLED ,width= 7)
btn4.grid(row = 2 , column=2)

label3 = tk.Label(root, text = 'Charge:')
label3.grid(row=4 , column=0)
label4 = tk.Label(root, text = 'CH2')
label4.grid(row=4 , column=1 )
label5 = tk.Label(root, text = 'Discharge:')
label5.grid(row=4 , column=2)
label6 = tk.Label(root, text = 'CH1')
label6.grid(row=4 , column=3 )

label7 = tk.Label(root, text = 'Volt[V]')
label7.grid(row=5 , column=0)
#label8 = tk.Label(root, text = 'Volt[V]')
#label8.grid(row=5 , column=2 )
label9 = tk.Label(root, text = 'Current[A]')
label9.grid(row=6 , column=0)
label10 = tk.Label(root, text = 'Current[A]')
label10.grid(row=6 , column=2 )
label11 = tk.Label(root, text = 'Time[Hour]')
label11.grid(row=7 , column=0)
label12 = tk.Label(root, text = 'Time[Hour]')
label12.grid(row=7 , column=2 )

txtcVolt = ttk.Entry(root , width=10 ,justify="right" )
txtcVolt.grid(row=5 , column=1,padx = 10)
txtcVolt.insert(0,'5.1')
#txtdVolt = ttk.Entry(root , width=10)
#txtdVolt.grid(row=5 , column=3,padx = 10)

txtcCurr = ttk.Entry(root , width=10 ,justify="right")
txtcCurr.grid(row=6 , column=1,padx = 10)
txtcCurr.insert(0,'2.5')
txtdCurr = ttk.Entry(root , width=10 ,justify="right")
txtdCurr.grid(row=6 , column=3,padx = 10)
txtdCurr.insert(0,'2.5')

txtcTime = ttk.Entry(root , width=10,justify="right")
txtcTime.grid(row=7 , column=1,padx = 10)
txtdTime = ttk.Entry(root , width=10,justify="right")
txtdTime.grid(row=7 , column=3,padx = 10)
txtcTime.insert(0,'5.0')
txtdTime.insert(0,'5.0')

label13 = tk.Label(root, text = 'Log')
label13.grid(row=9 , column=0 )
label14 = tk.Label(root, text = ' ')
label14.grid(row=3 , column=0 )
label16 = tk.Label(root, text = 'Cap.:')
label16.grid(row=8 , column=0 )
label17 = tk.Label(root, text = ' 0mAh')
label17.grid(row=8 , column=1 )
label18 = tk.Label(root, text = 'Cap.:')
label18.grid(row=8 , column=2 )
label19 = tk.Label(root, text = '0mAh')
label19.grid(row=8 , column=3 )
        
frame = tk.Frame(root)
frame.grid(row=11   , column=1, sticky="nsew" , columnspan = 3)
tree = ttk.Treeview(frame, columns=("TIME","MODE","Volt","Curr"),height=5)
tree.grid(row = 11  , column=1)
tree.column('#0'   ,width=0, stretch='no')
tree.column('TIME' , anchor='w', width=150)
tree.column('MODE' ,anchor='w', width=40)
tree.column('Volt' ,anchor='w', width=72)
tree.column('Curr' , anchor='w', width=72)
tree.heading('TIME', text='TIME',anchor='w')
tree.heading('MODE', text='C/D', anchor='w')
tree.heading('Volt', text='Volt', anchor='w')
tree.heading('Curr',text='Curr', anchor='w')

scrollbar = ttk.Scrollbar(frame, orient=tk.VERTICAL, command=tree.yview)
tree.configure(yscroll=scrollbar.set)
tree.pack(side=tk.LEFT)
scrollbar.pack(side=tk.RIGHT, fill=tk.Y)

label20 = tk.Label(root, text = ' ')
label20.grid(row=12 , column=1 )

btn5 = tk.Button( root, text='START'  , command=LOOP_clicked,  state =tk.DISABLED ,width= 7)
btn5.grid(row = 13 , column=0)
btn6 = tk.Button( root, text='STOP'  , command=STOP_clicked,  state =tk.DISABLED,  width= 7)
btn6.grid(row = 13 , column=1)
btn7 = tk.Button( root, text='SAVE'  , command=SAVE_clicked,  width= 7)
btn7.grid(row = 13 , column=2)
btn8 = tk.Button( root, text='CLR'   , command=CLR_clicked,   width= 7)
btn8.grid(row = 13 , column=3)

root.mainloop()

