from ctypes import *
from ctypes.wintypes import *
import ctypes
import time
import numpy as np

import os

# Load the DLL that sits next to this script.
_HERE = os.path.dirname(os.path.abspath(__file__))

def stream_to_txt(data, count ,filename, chunk_size=1000):
    with open(filename, 'a+') as f:
      lines = [f"{data[i]}\n" for i in range(count)]
      f.writelines(lines)

def doErrCheck(err_code, descr):
  if err_code < 0:
    print(str(descr) + " errCode: " + str(err_code))
  return err_code

hllDll = WinDLL(os.path.join(_HERE, "DSRemoteConnect64.dll"))

# Uncomment if you are using 32-bit python
#hllDll = WinDLL ("DSRemoteConnect.dll")

dsconInstance = HANDLE()
doErrCheck(hllDll.dsconCreateInstance(pointer(dsconInstance), 1), "dsconCreateInstance")
charArray = create_string_buffer("localhost:8999:8001".encode())
doErrCheck(hllDll.dsconConnect(dsconInstance, charArray), "dsconConnect")

#Show Dewesoft
doErrCheck(hllDll.dsconSetAppWindowVisible(dsconInstance, True), "dsconSetAppWindowVisible")
#doErrCheck(hllDll.dsconLoadSetup(dsconInstance, c_char_p(os.path.join(_HERE, 'DSConnTest1.dxs').encode())), "dsconLoadSetup")

numChannels = c_size_t()
doErrCheck(hllDll.dsconGetChannelCount(dsconInstance, byref(numChannels)), "dsconGetChannelCount")
print("NrOfChnls: ", numChannels.value)
doErrCheck(hllDll.dsconSetAppWindowVisible(dsconInstance, True), "dsconSetAppWindowVisible")

doErrCheck(hllDll.dsconInitChannelIdEnum(dsconInstance), "dsconInitChannelIdEnum")
localValue = c_size_t(0)
#size of string for preallocation
doErrCheck(hllDll.dsconGetNextChannelIdSize(dsconInstance, byref(localValue)), "dsconGetNextChannelIdSize") 
id_str = ctypes.cast((c_char * (localValue.value))(), c_char_p)
ch_name = ctypes.cast((c_char * 50)(), c_char_p)
ch_instances = []
while(doErrCheck(hllDll.dsconGetNextChannelId(dsconInstance, id_str), "dsconGetNextChannelId") == 0):
  ch_instance = HANDLE()
  doErrCheck(hllDll.dsconCreateChannelInstance(dsconInstance, id_str, pointer(ch_instance)), "dsconCreateChannelInstance")
  ch_instances.append(ch_instance)
  doErrCheck(hllDll.dsconChannelGetName(ch_instance, ch_name, 50), "dsconChannelGetName")
  print("ChName: " + str(ch_name.value) + " iD: " + str(id_str.value))
  # Resize id_str for the *next* channel - dsconGetNextChannelId does not bound
  # check, so a longer id (e.g. "0,10" after "0,9") overruns a stale buffer.
  localValue = c_size_t(0)
  doErrCheck(hllDll.dsconGetNextChannelIdSize(dsconInstance, byref(localValue)), "dsconGetNextChannelIdSize")
  id_str = ctypes.cast((c_char * (localValue.value))(), c_char_p)

# The last channel is reported with DSX_END_OF_ENUM, so the loop above exits
# without creating its instance - create it here.
ch_instance = HANDLE()
doErrCheck(hllDll.dsconCreateChannelInstance(dsconInstance, id_str, pointer(ch_instance)), "dsconCreateChannelInstance")
ch_instances.append(ch_instance)
doErrCheck(hllDll.dsconChannelGetName(ch_instance, ch_name, 50), "dsconChannelGetName")
print("ChName: " + str(ch_name.value) + " iD: " + str(id_str.value))

doErrCheck(hllDll.dsconStartMeasurement(dsconInstance), "dsconStartMeasurement")
        
data2 = ctypes.cast((c_double * 5000)(), POINTER(c_double))
time_stamps2 = ctypes.cast((c_double * 5000)(), POINTER(c_double))
print("Stop while loop by pressing CTRL+C")     

time.sleep(5)
count = 0
while True:
  try:
    time.sleep(3)
    countData2 = c_size_t(100)
    data2 = ctypes.cast((c_double * 100000)(), POINTER(c_double))
    time_stamps2 = ctypes.cast((c_double * 100000)(), POINTER(c_double)) 

    for i in range(0, len(ch_instances)):
      #print(f'CH {i}')
      doErrCheck(hllDll.dsconChannelReadScalarData_2(ch_instances[i], data2, time_stamps2, byref(countData2)), "dsconChannelReadScalarData_2")
      #print(countData2.value)
      #for i in range(10): #range(cnt) goes from 0 to cnt-1
        #print(i, "; ", time_stamps2[i], "; ", data2[i])
        
  except:
    print("While interrupted")
    break

#finally:
print("Finally")

doErrCheck(hllDll.dsconStopMeasurement(dsconInstance), "dsconStopMeasurement")
doErrCheck(hllDll.dsconDisconnect(dsconInstance), "") # this will close Dewesoft.exe and clear the DCOM

for i in range(0, len(ch_instances)):
  doErrCheck(hllDll.dsconFreeChannelInstance(ch_instances[i]), "dsconFreeChannelInstance") # this will free chnl instances of dll

doErrCheck(hllDll.dsconDestroyInstance(dsconInstance), "dsconDestroyInstance") # this will free dll instance
