#!/usr/bin/env python
# -*- coding: utf-8 -*-
# encoding: utf-8
# BPscope v 1.2
# Author: hwmayer
# Site: hwmayer.blogspot.com
#
# USAGE:
# f - trigger on falling slope
# r - trigger on rising slope
# s - trigger off
# key_up     - trigger level++
# key_down   - trigger level--
# 9 - time scale++ (zoom out)
# 0 - time scale-- (zoom in)
# q - QUIT
#
# Modificado por C. Medrano, 
# Toma los datos de AIN0 de la tarjeta LabJack-U3 HV

import sys
import os
from time import sleep
from datetime import datetime
import struct
import threading
import queue
import ctypes
import copy

import pygame

import u3


class StreamDataReader(object):
  def __init__(self, device):
    self.device = device
    self.data = queue.Queue()
    self.dataCount = 0
    self.missed = 0
    self.running = False

  def readStreamData(self):
    self.running = True
    print('Running')
    start = datetime.now()
    self.device.streamStart()
    while self.running:
      # Calling with convert = False, because we are going to convert in
      # the main thread.
      returnDict = next(self.device.streamData(convert = False))
          
      self.data.put_nowait(copy.deepcopy(returnDict))
    print("stream stopped.")
    self.device.streamStop()
##
def getVoltage(sdr, d):
  result = sdr.data.get(True, 1)
  r = d.processStreamData(result['result'])
  return r['AIN0']
##
NO_SYNC = 0
RISING_SLOPE = 1
FALLING_SLOPE = 2


RES_X = 640
RES_Y = 480
MAX_VOLTAGE = 3
OFFSET = 200
TRIGGER_LEV_RES = 0.05
TRIG_CAL = 0.99
DEFAULT_TIME_DIV = 1
DEFAULT_TRIGGER_LEV = 1.0
DEFAULT_TRIGGER_MODE = 0

DATA_RATE = 20000.0 #measures/second

# Escala temporal de la pantalla completa
DEFAULT_TIME_SCALE = RES_X / DATA_RATE #default time in seconds to make one window fill

d=None
sdr=None

try:
  pygame.init()
  
  # Configure streaming in U3
  d=u3.U3()
  d.configU3()
  #
  ## For applying the proper calibration to readings.
  d.getCalibrationData()
  #
  ## Set the FIO0 to Analog
  d.configIO(FIOAnalog = 1) 
  #
  #print "configuring U3 stream"
  d.streamConfig( NumChannels = 1, PChannels = [ 0 ], NChannels = [ 31 ], Resolution = 3, SampleFrequency = 20000 )
  
  # Init window
  window = pygame.display.set_mode((RES_X, RES_Y)) 
  background = (0,0,0)
  line = (0,255,0)
  trig_color = (100,100,0)
  
  time_div = DEFAULT_TIME_DIV
  trigger_level = DEFAULT_TRIGGER_LEV
  trig_mode = DEFAULT_TRIGGER_MODE
  
  # Start streaming in thread
  sdr = StreamDataReader(d)
  
  sdrThread = threading.Thread(target = sdr.readStreamData)
  sdrThread.start()
  
  while True:
    if(not sdr.running): continue
    plot = {}
    voltage = [] # OJO rsto creo que es mejor rehacerlo
    maxv = 0
    minv = 100
    time_scale = DEFAULT_TIME_SCALE * time_div
    prev_voltage = 0
    if(trig_mode != NO_SYNC):
      for k in range(1,2000):
        if(len(voltage)==0): voltage=getVoltage(sdr,d)
        prev_voltage = voltage[0]
        voltage.pop(0)
        if(len(voltage)==0): voltage=getVoltage(sdr,d)
        #rising slope
        if((voltage[0] >= trigger_level) and (prev_voltage < (voltage[0] * TRIG_CAL)) and (trig_mode == RISING_SLOPE)):
            voltage.pop(0)
            break
        if((voltage[0] < trigger_level) and (voltage[0] > 0.01) and (prev_voltage > voltage[0]/TRIG_CAL) and (trig_mode == FALLING_SLOPE)):
            voltage.pop(0)
            break
    for i in range(RES_X):
      # time_div se cambia de forma que sea siempre entero
      for k in range(time_div - 1):
          if(len(voltage)==0): voltage=getVoltage(sdr,d)
          voltage.pop(0)
      if(len(voltage)==0): voltage=getVoltage(sdr,d)
      plot[i] = voltage[0]
      voltage.pop(0)
  ############
    for i in range(1,RES_X):
      if plot[i] > maxv:
        maxv = plot[i]
      if plot[i] < minv:
        minv = plot[i]
      ##############
      y = (RES_Y) - plot[i]*(RES_Y/MAX_VOLTAGE) - OFFSET
      x = i
      px = i-1;
      py = (RES_Y) - plot[i-1]*(RES_Y/MAX_VOLTAGE) - OFFSET
      pygame.draw.line(window, line, (px, py), (x, y))  
      trig_y = RES_Y - trigger_level * (RES_Y/MAX_VOLTAGE) - OFFSET
      pygame.draw.line(window, trig_color, (0, trig_y), (RES_X, trig_y))
    ##GUI
    font = pygame.font.Font(None, 19)
    text_max_voltage = font.render("Max: %f V" % maxv, 1, (255, 255, 255))
    text_min_voltage = font.render("Min: %f V" % minv, 1, (255, 255, 255))
    text_time_scale = font.render("Timescale: %f s" % time_scale, 1, (255, 255, 255))
    text_maxv_Rect = text_max_voltage.get_rect()
    text_minv_Rect = text_min_voltage.get_rect()
    text_time_scale_Rect = text_time_scale.get_rect()
    text_maxv_Rect.x = 10
    text_maxv_Rect.y = 10
    text_minv_Rect.x = 10 
    text_minv_Rect.y = 30
    text_time_scale_Rect.x = 10
    text_time_scale_Rect.y = 50
    window.blit(text_max_voltage, text_maxv_Rect)
    window.blit(text_min_voltage, text_minv_Rect)
    window.blit(text_time_scale, text_time_scale_Rect)
    ########
    pygame.display.flip() 
    #############
    for event in pygame.event.get(): 
      if event.type == pygame.QUIT:
        if(sdr is not None): sdr.running = False
        sleep(0.5) # wait for thread to stop stream ;)
        sys.exit(0)
      elif event.type == pygame.KEYDOWN:
        if event.key == pygame.K_0:
          print("timescale x 2")
          time_div = time_div * 2
        elif event.key == pygame.K_9:
          if (time_div >= 2):
            print("timescale / 2")
            time_div = time_div // 2
        elif event.key == pygame.K_s:
          print("Trigger of, no sync")
          trig_mode = NO_SYNC
        elif event.key == pygame.K_f:
          print("Trigger set to falling slope")
          trig_mode = FALLING_SLOPE
        elif event.key == pygame.K_r:
          print("Trigger set to rising slope")
          trig_mode = RISING_SLOPE
        elif event.key == pygame.K_UP:
          trigger_level += TRIGGER_LEV_RES
          print("Trigger level: %f" % trigger_level)
        elif event.key == pygame.K_DOWN:
          trigger_level -= TRIGGER_LEV_RES
          print("Trigger levelL: %f" % trigger_level)
        elif event.key == pygame.K_q:
          if(sdr is not None): sdr.running = False
          sleep(0.5)
          sys.exit(0)
    ###########
    window.fill(background)
finally:
  print('Clean')
  if(sdr is not None): sdr.running = False
#END


