
import serial
import numpy as np
import struct
			 
class Arduino():
    def __init__(self,port,data_size,baudrate=115200):
        self.ser = serial.Serial(port,baudrate=baudrate)
        self.GET_DATA = 10
        self.SET_DATA = 11
		self.data_size = data_size
        self.nb_data = len(data_size)
        # attente du premier caractère (valeur 0) envoyé par l'Arduino
        c_recu = self.ser.read(1)
        while ord(c_recu)!=0:
            c_recu = self.ser.read(1)

    def close(self):
        self.ser.close()

    def read_data(self,n):
        self.ser.write((self.GET_DATA).to_bytes(1,byteorder='big'))
        self.ser.write((n).to_bytes(1,byteorder='big'))
        data = self.ser.read(self.data_size[n]) # appel bloquant
        return data
        
    def read_int8(self,n,signed=True):
        if signed : fmt = '<b'
        else : fmt = '<B'
        data = self.read_data(n)
        x = struct.unpack(fmt,data)
        return x[0]
    
    def read_int8_array(self,n,signed=True):
        data = self.read_data(n)
        size = len(data)
        if signed :
            fmt = '<b'
            a = np.zeros(size,np.int8)
        else :
            fmt = '<B'
            a = np.zeros(size,np.uint8)
        for k in range(size):
            a[k] = data[k]
        return a

    def read_int16(self,n,signed=True):
        if signed : fmt = '<h'
        else : fmt = '<H'
        data = self.read_data(n)
        x = struct.unpack(fmt,data)
        return x[0]

    def read_int16_array(self,n,signed=True):
        data = self.read_data(n)
        size = len(data)//2
        if signed :
            fmt = '<h'
            a = np.zeros(size,np.int16)
        else :
            fmt = '<H'
            a = np.zeros(size,np.uint16)
        for k in range(size):
            i = 2*k
            x = struct.unpack(fmt,data[i:i+2])
            a[k] = x[0]
        return a

    def read_int32(self,n,signed=True):
        if signed : fmt = '<i'
        else : fmt = '<I'
        data = self.read_data(n)
        x = struct.unpack(fmt,data)
        return x[0]

    def read_int32_array(self,n,signed=True):
        data = self.read_data(n)
        size = len(data)//4
        if signed :
            fmt = '<i'
            a = np.zeros(size,np.int32)
        else :
            fmt = '<I'
            a = np.zeros(size,np.uint32)
        for k in range(size):
            i = 4*k
            x = struct.unpack(fmt,data[i:i+4])
            a[k] = x[0]
        return a


    def read_float(self,n):
        data = self.read_data(n)
        x = struct.unpack('<f',data)
        return np.float32(x[0])

    def read_float_array(self,n):
        data = self.read_data(n)
        size = len(data)//4
        a = np.zeros(size,np.float32)
        for k in range(size):
            i = 4*k
            x = struct.unpack('<f',data[i:i+4])
            a[k] = x[0]
        return a
		
    def write(self,n):
        self.ser.write((self.SET_DATA).to_bytes(1,byteorder='big'))
        self.ser.write((n).to_bytes(1,byteorder='big'))
		
    def write_int8(self,n,x,signed=True):
        self.ser.write((self.SET_DATA).to_bytes(1,byteorder='big'))
        self.ser.write((n).to_bytes(1,byteorder='big'))
        if signed: fmt = '<b'
        else: fmt = '<B'
        bts = struct.pack(fmt,x)
        for b in bts:
            self.ser.write((b).to_bytes(1,byteorder='big'))
			
			
    def write_int8_array(self,n,a,signed=True):
        self.ser.write((self.SET_DATA).to_bytes(1,byteorder='big'))
        if signed : fmt = '<b'
        else : fmt = '<B'
        self.ser.write((n).to_bytes(1,byteorder='big'))
        size = len(a)
        for k in range(size):
            bts = struct.pack(fmt,a[k])
            for b in bts:
                self.ser.write((b).to_bytes(1,byteorder='big'))

    def write_int16(self,n,x,signed=True):
        self.ser.write((self.SET_DATA).to_bytes(1,byteorder='big'))
        if signed : fmt = '<h'
        else : fmt = '<H'
        self.ser.write((n).to_bytes(1,byteorder='big'))
        bts = struct.pack(fmt,x)
        for b in bts:
            self.ser.write((b).to_bytes(1,byteorder='big'))

    def write_int16_array(self,n,a,signed=True):
        self.ser.write((self.SET_DATA).to_bytes(1,byteorder='big'))
        if signed : fmt = '<h'
        else : fmt = '<H'
        self.ser.write((n).to_bytes(1,byteorder='big'))
        size = len(a)
        for k in range(size):
            bts = struct.pack(fmt,a[k])
            for b in bts:
                self.ser.write((b).to_bytes(1,byteorder='big'))

    def write_int32(self,n,x,signed=True):
        self.ser.write((self.SET_DATA).to_bytes(1,byteorder='big'))
        if signed : fmt = '<i'
        else : fmt = '<I'
        self.ser.write((n).to_bytes(1,byteorder='big'))
        bts = struct.pack(fmt,x)
        for b in bts:
            self.ser.write((b).to_bytes(1,byteorder='big'))

    def write_int32_array(self,n,a,signed=True):
        self.ser.write((self.SET_DATA).to_bytes(1,byteorder='big'))
        if signed : fmt = '<i'
        else : fmt = '<I'
        self.ser.write((n).to_bytes(1,byteorder='big'))
        size = len(a)
        for k in range(size):
            bts = struct.pack(fmt,a[k])
            for b in bts:
                self.ser.write((b).to_bytes(1,byteorder='big'))

    def write_float(self,n,x):
        self.ser.write((self.SET_DATA).to_bytes(1,byteorder='big'))
        self.ser.write((n).to_bytes(1,byteorder='big'))
        bts = struct.pack('<f',x)
        for b in bts:
            self.ser.write((b).to_bytes(1,byteorder='big'))

    def write_float_array(self,n,a):
        self.ser.write((self.SET_DATA).to_bytes(1,byteorder='big'))
        self.ser.write((n).to_bytes(1,byteorder='big'))
        size = len(a)
        for k in range(size):
            bts = struct.pack('<f',a[k])
            for b in bts:
                self.ser.write((b).to_bytes(1,byteorder='big'))	

    def write_double(self,n,x):
        self.ser.write((self.SET_DATA).to_bytes(1,byteorder='big'))
        self.ser.write((n).to_bytes(1,byteorder='big'))
        bts = struct.pack('<d',x)
        for b in bts:
            self.ser.write((b).to_bytes(1,byteorder='big'))

    def write_double_array(self,n,a):
        self.ser.write((self.SET_DATA).to_bytes(1,byteorder='big'))
        self.ser.write((n).to_bytes(1,byteorder='big'))
        size = len(a)
        for k in range(size):
            bts = struct.pack('<d',a[k])
            for b in bts:
                self.ser.write((b).to_bytes(1,byteorder='big'))
			 
			 