import sys
import serial
import numpy as np
import scipy.fftpack
import scipy.signal
from PyQt5.QtCore import QThread, pyqtSignal
from PyQt5.QtWidgets import QApplication, QMainWindow
from mainwindow import Ui_MainWindow

# communication function
class SerialThread(QThread):
    dataReady = pyqtSignal(list)
    #SERIALPORT = '/dev/cu.usbmodem1411' #change value for respective port
    SERIALPORT = '/dev/cu.usbmodem1D11431' #change value for respective port
    BAUDRATE = 115200

    def __init__(self, serial_port=SERIALPORT, baud_rate=BAUDRATE, sample_rate = 256):
        super(SerialThread, self).__init__()
        self.uart = serial.Serial(serial_port, baud_rate, timeout=1)
        self.sample_rate = sample_rate
        self.sample_list = []

    def run(self):
        while True:
            self.sample = self.uart.readline()
            if len(self.sample) > 0:
                self.sample_list.append(self.sample)

                if(len(self.sample_list) is self.sample_rate):
                    self.dataReady.emit(self.sample_list)
                    self.sample_list = []
            else:
                self.sample = b''

class MaterialTester(QMainWindow, Ui_MainWindow):
    def __init__(self):
        super(MaterialTester, self).__init__()
        self.setupUi(self)

        self.uart = SerialThread()
        self.uart.dataReady.connect(self.getFreq)
        self.uart.start()

        self.calculateButton.clicked.connect(self.calculateMaterial)

        self.materialName.setText("Acrylic")
        self.materialLength.setText("302")
        self.materialWidth.setText("128")
        self.materialHeight.setText("4")  # thickness
        self.materialMass.setText("25")
        #self.materialFrequency.setText("Read Freq")


    def getFreq(self, sample_list):

        sample_list = [int(str(x, 'utf-8')) for x in sample_list]
        signal = np.array(sample_list)
        signal = np.subtract(signal, np.mean(signal), casting = 'unsafe')
        ffty = np.fft.fft(signal)
        freqs = np.fft.fftfreq(len(ffty))
        fft_abs = np.abs(ffty)
        fft_index = np.argmax(fft_abs)
        #print(fft_index)
        freq = freqs[fft_index]
        #print(freq)
        freq_in_hertz = abs(freq * 44100)
        print(freq_in_hertz)
        self.materialFrequency.setText(str(freq_in_hertz))

    def calculateMaterial(self):
        #equation: E = 0.9465*[(m*f^2)/width][(length^3)/thickness^]*T
        # m : mass in g
        # f : fundamental resonant freq in Hz
        # width, length, thickness in mm
        # T correction factor
        mass = int(self.materialMass.text()) #get mass
        freq = float(self.materialFrequency.text()) #get freq
        width = int(self.materialWidth.text()) #get width
        length = int(self.materialLength.text())
        thickness = int(self.materialHeight.text())

        elasticity = (mass*freq**2)/width
        elasticity = elasticity*(length**3/thickness**3)
        elasticity = elasticity*0.9465

        self.materialElasticity.setText(str(elasticity))


if __name__ == '__main__':
    app = QApplication(sys.argv)
    main_window = MaterialTester()
    main_window.show()
    sys.exit(app.exec_())