# Christian Fiot 2020
# Accelerometer LIS3DH
#
#
# Usage:
# from LIS3DH import LIS3DH
#
# Acc = LIS3DH(0x018, traceDebug=True)
# Acc.begin()  # return True if chip found
# Acc.read()  # return value in G
#               Flat on a table, X and Y are close to 0 and Z will be about 1 g or ~9.8 m/s^2
#
# Credit  https://github.com/tinypico/tinypico-micropython/blob/master/lis3dh%20library/lis3dh.py
# Credit  LIS2HH12.py  from  pysense library
# https://iotdk.intel.com/docs/master/upm/classupm_1_1_l_i_s3_d_h.html#a20db62ec4124251ff355343c2e29d723
#

import utime
# import struct
import math
from trap import * # 2.2.9b
from machine import I2C # 2.2.18


class LIS3DH():

    def __init__(self, iicadr=0x19, i2c=None, sda='P22', scl='P21', traceDebug=False, sdAccess=False): # 2.2.9b
        self.trace = traceDebug
        self.adr = iicadr
        self.sdAccess = sdAccess # 2.2.9b

        self.x = 0
        self.y = 0
        self.z = 0
        self.pitch = 0

        self.C1 = bytearray(1) # For debug only

        # I2C bus declaration is extenal
        # MCP are connected on I2C bus #1   SDA-P22   SCL-P21
        #                      I2C bus #2   SDA-P18   SCL-P17
        #
        if i2c is not None: # 2.2.18
            self.i2c1 = i2c
        else:
            # from machine import I2C
            self.i2c1 = I2C(0, mode=I2C.MASTER, pins=(sda, scl))


    # Detect and init sensor
    def begin(self):
        int = 0 # 2.2.9b
        try:
            did = self.i2c1.readfrom_mem(self.adr, 0x0F,1)
            int = did[0]

            if self.trace :
                print("Read device ID:" + str(did[0]))

            # Set control registers
            # Section 8.12  CtrlReg5 $24   Reboot
            self.i2c1.writeto_mem(self.adr,0x024, 0x80)
            utime.sleep(0.25)

            # Section 8.8  CtrlReg1 $20  Enable all axes, normal mode 50 Hz
            self.i2c1.writeto_mem(self.adr,0x020, 0x47)

            # Section 8.11  CtrlReg4 $23 Full_Scale 4G=01 , HR=0, BDU=1   1 0 01 1 00 0
            # 4G => 32768
            self.i2c1.writeto_mem(self.adr,0x023, 0x90)

            # Section 8.7  TempCfgReg $1F  Temp sensor and ADC not used

            # Section 8.6  CtrlReg0 $1E  pull up connected to SA0
            # yet the default Adr is $18 instead of $19 ?

            # Section 8.19  FIFOCtrlReg $2E  Internal FIFO is bypass
            print('Detected LIS3DH - Accelerometer Adr:' + str(self.adr))

        except Exception as e: # 2.2.9b
            scratch = 'LIS3DH - Accelerometer (Adr:' + str(self.adr) + ') not found - ' # 2.2.9b  print('LIS3DH - Accelerometer (Adr:' + str(self.adr) + ') not found')
            file_errLog(0, scratch + str(e), self.sdAccess)  # 2.2.9b
            # 2.2.18 print('Begin I2C1 scan ...')
            # 2.2.18 print(self.i2c1.scan())
            int = 0

        finally:
            return int == 0x033


    def myRound(self, S1):
        if (S1 == 0):
            return 0
        else:
            return round(S1, 3)


    def read(self):

        # In BDU mode no INT is required
        # For sync in with BDU  read MSB first
        high = bytearray(1)
        low = bytearray(1)
        high = self.i2c1.readfrom_mem(self.adr, 0x29, 1)
        low = self.i2c1.readfrom_mem(self.adr, 0x28, 1)
        result = (high[0] << 8) | low[0]
        if result > 32767:
            result -= 65536
        self.x = result
        high = self.i2c1.readfrom_mem(self.adr, 0x2B, 1)
        low = self.i2c1.readfrom_mem(self.adr, 0x2A, 1)
        result = (high[0] << 8) | low[0]
        if result > 32767:
            result -= 65536
        self.y = result
        high = self.i2c1.readfrom_mem(self.adr, 0x2D, 1)
        low = self.i2c1.readfrom_mem(self.adr, 0x2C, 1)
        result = (high[0] << 8) | low[0]
        if result > 32767:
            result -= 65536
        self.z = result

        # With HR=0  or  HR=1
        # values are +/-2000  with  sensitivity @ 16G
        # values are +/-4000  with  sensitivity @ 8G
        # values are +/-8000  with  sensitivity @ 4G    is the default value
        # values are +/-16000  with  sensitivity @ 2G
        # The values are half of what expected may have to do with Resolution ? no

        # format result in G
        # Flat on a table, X and Y are close to 0 and Z will be about 1 g or ~9.8 m/s^2
        # 32767 = 4G
        # n    = xG
        self.x = (self.x * 4) / 32767
        self.y = (self.y * 4) / 32767
        self.z = (self.z * 4) / 32767


        _mult = 1 # self.SCALES[self.full_scale] / ACC_G_DIV

        # return round(self.x, 3), round(self.y, 3), round(self.z, 3)  # (self.x[0] * _mult, self.y[0] * _mult, self.z[0] * _mult)
        # return self.myRound(self.x), self.myRound(self.y), self.myRound(self.z)
        return self.x, self.y, self.z


    def do_Roll(self):
        x,y,z = self.read()
        rad = math.atan2(-x, z)
        # return self.myRound( (180 / math.pi) * rad )
        return (180 / math.pi) * rad

    def do_Pitch(self):
        x,y,z = self.read()
        rad = -math.atan2(y, (math.sqrt(x*x + z*z)))
        # return self.myRound ( (180 / math.pi) * rad )
        # return (180 / math.pi) * rad
        self.pitch = (180 / math.pi) * rad
        return self.pitch




"""
def status(self):
    self.C1 = self.i2c1.readfrom_mem(self.adr, 0x07,1)
    U1 = self.C1[0]
    return U1
"""

"""
# https://docs.python.org/3/library/struct.html
x = self.i2c1.readfrom_mem(self.adr , 0x028, 2)
self.x = struct.unpack('<h', x) # little short
# print("X1: %d" %self.x )
y = self.i2c1.readfrom_mem(self.adr , 0x02A, 2)
self.y = struct.unpack('<h', y)
z = self.i2c1.readfrom_mem(self.adr , 0x02C, 2)
self.z = struct.unpack('<h', z)
"""

"""
self.x, self.y, self.z = struct.unpack('<hhh', self.i2c1.readfrom_mem(self.adr, 0x28, 6))
print("X2: %d" %self.x )
"""

"""
data = bytearray(2)
data = self.i2c1.readfrom_mem(self.adr, 0x28, 2)
result = int.from_bytes(data, "little")
if result > 32767:
    result -= 65536
self.x = result
# print("X3: %d" %self.x )
data = self.i2c1.readfrom_mem(self.adr, 0x2A, 2)
result = int.from_bytes(data, "little")
if result > 32767:
    result -= 65536
self.y = result
data = self.i2c1.readfrom_mem(self.adr, 0x2C, 2)
result = int.from_bytes(data, "little")
if result > 32767:
    result -= 65536
self.z = result
"""
