"""
Copyright (C) 2015-2020 Alibaba Group Holding Limited

The driver for AP3216C chip, The AP3216C is an integrated ALS & PS module
that includes a digital ambient light sensor [ALS], a proximity sensor [PS],
and an IR LED in a single package.
"""
from micropython import const
from driver import I2C
from utime import sleep_ms
import math

AP3216C_ADDR      = const(0x1e)

# System Register
AP3216C_SYS_CONFIGURATION_REG    = const(0x00)
AP3216C_SYS_INT_STATUS_REG       = const(0x01)
AP3216C_SYS_INT_CLEAR_MANNER_REG = const(0x02)
AP3216C_IR_DATA_L_REG            = const(0x0A)
AP3216C_IR_DATA_H_REG            = const(0x0B)
AP3216C_ALS_DATA_L_REG           = const(0x0C)
AP3216C_ALS_DATA_H_REG           = const(0x0D)
AP3216C_PS_DATA_L_REG            = const(0x0E)
AP3216C_PS_DATA_H_REG            = const(0x0F)

# ALS Register
AP3216C_ALS_CONFIGURATION_REG    = const(0x10)
AP3216C_ALS_CALIBRATION_REG      = const(0x19)
AP3216C_ALS_THRESHOLD_LOW_L_REG  = const(0x1A)
AP3216C_ALS_THRESHOLD_LOW_H_REG  = const(0x1B)
AP3216C_ALS_THRESHOLD_HIGH_L_REG = const(0x1C)
AP3216C_ALS_THRESHOLD_HIGH_H_REG = const(0x1D)

# PS Register
AP3216C_PS_CONFIGURATION_REG    = const(0x20)
AP3216C_PS_LED_DRIVER_REG       = const(0x21)
AP3216C_PS_INT_FORM_REG         = const(0x22)
AP3216C_PS_MEAN_TIME_REG        = const(0x23)
AP3216C_PS_LED_WAITING_TIME_REG = const(0x24)
AP3216C_PS_CALIBRATION_L_REG    = const(0x28)
AP3216C_PS_CALIBRATION_H_REG    = const(0x29)
AP3216C_PS_THRESHOLD_LOW_L_REG  = const(0x2A)
AP3216C_PS_THRESHOLD_LOW_H_REG  = const(0x2B)
AP3216C_PS_THRESHOLD_HIGH_L_REG = const(0x2C)
AP3216C_PS_THRESHOLD_HIGH_H_REG = const(0x2D)

#mode value
AP3216C_MODE_POWER_DOWN    = const(0x0)
AP3216C_MODE_ALS           = const(0x1)
AP3216C_MODE_PS            = const(0x2)
AP3216C_MODE_ALS_AND_PS    = const(0x3)
AP3216C_MODE_SW_RESET      = const(0x4)
AP3216C_MODE_ALS_ONCE      = const(0x5)
AP3216C_MODE_PS_ONCE       = const(0x6)
AP3216C_MODE_ALS_AND_PS_ONCE  = const(0x7)

#ap3216c_int_clear_manner
AP3216C_INT_CLEAR_MANNER_BY_READING    = const(0x0)
AP3216C_ALS_CLEAR_MANNER_BY_SOFTWARE   = const(0x1)

#als_range
AP3216C_ALS_RANGE_20661    = const(0x0)
AP3216C_ALS_RANGE_5162     = const(0x1)
AP3216C_ALS_RANGE_1291     = const(0x2)
AP3216C_ALS_RANGE_323    = const(0x3)

#als_range
AP3216C_PS_GAIN1    = const(0x0)
AP3216C_PS_GAIN2     = const(0x1)
AP3216C_PS_GAIN4     = const(0x2)
AP3216C_PS_GAIN8    = const(0x3)

AP3216C_SYSTEM_MODE          = const(0x0)
AP3216C_INT_PARAM            = const(0x1)
AP3216C_ALS_RANGE            = const(0x2)
AP3216C_ALS_PERSIST          = const(0x3)
AP3216C_ALS_CALIBRATION      = const(0x4)
AP3216C_ALS_LOW_THRESHOLD_L  = const(0x5)
AP3216C_ALS_LOW_THRESHOLD_H  = const(0x6)
AP3216C_ALS_HIGH_THRESHOLD_L = const(0x7)
AP3216C_ALS_HIGH_THRESHOLD_H = const(0x8)
AP3216C_PS_INTEGRATED_TIME   = const(0x9)
AP3216C_PS_GAIN              = const(0xa)
AP3216C_PS_PERSIST           = const(0xb)
AP3216C_PS_LED_CONTROL       = const(0xc)
AP3216C_PS_LED_DRIVER_RATIO  = const(0xd)
AP3216C_PS_INT_MODE          = const(0xe)
AP3216C_PS_MEAN_TIME         = const(0xf)
AP3216C_PS_WAITING_TIME      = const(0x10)
AP3216C_PS_CALIBRATION_L     = const(0x11)
AP3216C_PS_CALIBRATION_H     = const(0x12)
AP3216C_PS_LOW_THRESHOLD_L   = const(0x13)
AP3216C_PS_LOW_THRESHOLD_H   = const(0x14)
AP3216C_PS_HIGH_THRESHOLD_L  = const(0x15)
AP3216C_PS_HIGH_THRESHOLD_H  = const(0x16)

class AP3216CError(Exception):
    def __init__(self, value=0, msg="ap3216c common error"):
        self.value = value
        self.msg = msg

    def __str__(self):
        return "Error code:%d, Error message: %s" % (self.value, str(self.msg))

    __repr__ = __str__

class AP3216C(object):
    """
    This class implements ap3216c chip's defs.
    """
    def __init__(self):
        self.i2cDev = None

    def open(self, devid):
        self.i2cDev = I2C()
        self.i2cDev.open(devid)

# 写寄存器的值
    def write_reg(self, addr, data):
        msgbuf = bytearray([data])
        self.i2cDev.writeReg(addr, msgbuf)
        print("--> write addr " + str(addr) + ", value = " + str(msgbuf))

# 读寄存器的值
    def read_regs(self, addr, len):
        buf = bytearray(len)
        self.i2cDev.readReg(addr, buf)
        print("--> read " + str(len) + " bytes from addr " + str(addr) + ", " + str(len) + " bytes value = " + str(buf))
        return buf;

    # 软件复位传感器
    def reset_sensor(self):
        self.write_reg(AP3216C_SYS_CONFIGURATION_REG, AP3216C_MODE_SW_RESET); # reset

    def read_low_and_high(self, reg, len):
        # buf

        # buf[0] = self.read_regs(reg, len) # 读低字节
        # buf[1] = self.read_regs(reg + 1, len)  # 读高字节
        data = self.read_regs(reg, len)[0] | (self.read_regs(reg + 1, len)[0] << len * 8) # 合并数据

        if (data > (1 << 15)):
            data = data - (1<<16)

        return data

    def ap3216c_get_IntStatus(self):
        # 读中断状态寄存器
        IntStatus = self.read_regs(AP3216C_SYS_INT_STATUS_REG, 1)[0]
        # IntStatus 第 0 位表示 ALS 中断，第 1 位表示 PS 中断。
        return IntStatus # 返回状态

    def ap3216c_int_init(self):
        print("ap3216c_int_init")
    #配置 中断输入引脚
    def ap3216c_int_Config(self):
        print("ap3216c_int_Config")

    #初始化入口
    def init(self):
        # reset ap3216c
        self.reset_sensor()
        sleep_ms(100)
        self.ap3216c_set_param(AP3216C_SYSTEM_MODE, AP3216C_MODE_ALS_AND_PS)
        sleep_ms(150) # delay at least 112.5ms

        self.ap3216c_int_Config()
        self.ap3216c_int_init()


    # This function reads light by ap3216c sensor measurement
    # @param no
    # @return the ambient light converted to float data.
    #
    def ap3216c_read_ambient_light(self):
        read_data = self.read_low_and_high(AP3216C_ALS_DATA_L_REG, 1)
        range = self.ap3216c_get_param(AP3216C_ALS_RANGE)
        print("ap3216c_read_ambient_light read_data is " , read_data, range)
        if (range == AP3216C_ALS_RANGE_20661):
            brightness = 0.35 * read_data # sensor ambient light converse to reality
        elif (range == AP3216C_ALS_RANGE_5162):
            brightness = 0.0788 * read_data # sensor ambient light converse to reality
        elif (range == AP3216C_ALS_RANGE_1291):
            brightness = 0.0197 * read_data # sensor ambient light converse to reality
        elif (range == AP3216C_ALS_RANGE_323):
            brightness = 0.0049 * read_data # sensor ambient light converse to reality

        return brightness

    #This function reads proximity by ap3216c sensor measurement
    #@param no
    #@return the proximity data.
    def ap3216c_read_ps_data(self):
        read_data = self.read_low_and_high(AP3216C_PS_DATA_L_REG, 1) # read two data
        print("ap3216c_read_ps_data read_data is " , read_data);
        if (1 == ((read_data >> 6) & 0x01 or (read_data >> 14) & 0x01)) :
            return 55555 # 红外过高（IR），PS无效 返回一个 55555 的无效数据

        proximity = (read_data & 0x000f) + (((read_data >> 8) & 0x3f) << 4)
        # sensor proximity converse to reality
        if (proximity > (1 << 15)) :
            proximity = proximity - (1<<16)

        proximity |= read_data & 0x8000 # 取最高位，0 表示物体远离，1 表示物体靠近
        return proximity # proximity 后十位是数据位，最高位为状态位


    #This function reads ir by ap3216c sensor measurement
    #@param no
    #@return the ir data.
    def ap3216c_read_ir_data(self):
        read_data = self.read_low_and_high(AP3216C_IR_DATA_L_REG, 1) # read two data
        print("ap3216c_read_ir_data read_data is" , read_data);
        proximity = (read_data & 0x0003) + ((read_data >> 8) & 0xFF)
        # sensor proximity converse to reality
        if (proximity > (1 << 15)) :
            proximity = proximity - (1<<16)

        return proximity

    #This function sets parameter of ap3216c sensor
    #@param cmd the parameter cmd of device
    #@param value for setting value in cmd register
    #@return the setting parameter status,RT_EOK reprensents setting successfully.

    def ap3216c_set_param(self, cmd, value):
        if cmd == AP3216C_SYSTEM_MODE:
            # default 000,power down
            self.write_reg(AP3216C_SYS_CONFIGURATION_REG, value)
        elif cmd == AP3216C_INT_PARAM:
            self.write_reg(AP3216C_SYS_INT_CLEAR_MANNER_REG, value)
        elif cmd == AP3216C_ALS_RANGE:
            args = self.read_regs(AP3216C_ALS_CONFIGURATION_REG, 1)[0]
            args &= 0xcf
            args |= value << 4
            self.write_reg(AP3216C_ALS_CONFIGURATION_REG, args)
        elif cmd == AP3216C_ALS_PERSIST:
            args = self.read_regs(AP3216C_ALS_CONFIGURATION_REG, 1)[0]
            args &= 0xf0
            args |= value
            self.write_reg(AP3216C_ALS_CONFIGURATION_REG, args)
        elif cmd == AP3216C_ALS_LOW_THRESHOLD_L:
            self.write_reg(AP3216C_ALS_THRESHOLD_LOW_L_REG, value)
        elif cmd == AP3216C_ALS_LOW_THRESHOLD_H:
           self.write_reg(AP3216C_ALS_THRESHOLD_LOW_H_REG, value)
        elif cmd == AP3216C_ALS_HIGH_THRESHOLD_L:
            self.write_reg(AP3216C_ALS_THRESHOLD_HIGH_L_REG, value)
        elif cmd == AP3216C_ALS_HIGH_THRESHOLD_H:
            self.write_reg(AP3216C_ALS_THRESHOLD_HIGH_H_REG, value)
        elif cmd == AP3216C_PS_GAIN:
            args = self.read_regs(AP3216C_PS_CONFIGURATION_REG, 1)[0]
            args &= 0xf3
            args |= value
            self.write_reg(AP3216C_PS_CONFIGURATION_REG, args)
        elif cmd == AP3216C_PS_PERSIST:
            args = self.read_regs(AP3216C_PS_CONFIGURATION_REG, 1)[0]
            args &= 0xfc
            args |= value
            self.write_reg(AP3216C_PS_CONFIGURATION_REG, args)
        elif cmd == AP3216C_PS_LOW_THRESHOLD_L:
            self.write_reg(AP3216C_PS_THRESHOLD_LOW_L_REG, value)
        elif cmd == AP3216C_PS_LOW_THRESHOLD_H:
            self.write_reg(AP3216C_PS_THRESHOLD_LOW_H_REG, value)
        elif cmd == AP3216C_PS_HIGH_THRESHOLD_L:
            self.write_reg(AP3216C_PS_THRESHOLD_HIGH_L_REG, value)
        elif cmd == AP3216C_PS_HIGH_THRESHOLD_H:
            self.write_reg(AP3216C_PS_THRESHOLD_HIGH_H_REG, value)

    #This function gets parameter of ap3216c sensor
    #@param cmd the parameter cmd of device
    #@param value to get value in cmd register
    #@return the getting parameter status,RT_EOK reprensents getting successfully.
    def ap3216c_get_param(self, cmd):
        if cmd == AP3216C_SYSTEM_MODE:
            value = self.read_regs(AP3216C_SYS_CONFIGURATION_REG, 1)[0]
        elif cmd == AP3216C_INT_PARAM:
            value = self.read_regs(AP3216C_SYS_INT_CLEAR_MANNER_REG, 1)[0]
        elif cmd == AP3216C_ALS_RANGE:
            value = self.read_regs(AP3216C_ALS_CONFIGURATION_REG, 1)[0]
            temp = (value & 0xff) >> 4
            value = temp
        elif cmd == AP3216C_ALS_PERSIST:
            temp = self.read_regs(AP3216C_ALS_CONFIGURATION_REG, 1)[0]
            temp = value & 0x0f
            value = temp
        elif cmd == AP3216C_ALS_LOW_THRESHOLD_L:
            value = self.read_regs(AP3216C_ALS_THRESHOLD_LOW_L_REG, 1)[0]
        elif cmd == AP3216C_ALS_LOW_THRESHOLD_H:
            value = self.read_regs(AP3216C_ALS_THRESHOLD_LOW_H_REG, 1)[0]
        elif cmd == AP3216C_ALS_HIGH_THRESHOLD_L:
            value = self.read_regs(AP3216C_ALS_THRESHOLD_HIGH_L_REG, 1)[0]
        elif cmd == AP3216C_ALS_HIGH_THRESHOLD_H:
            value = self.read_regs(AP3216C_ALS_THRESHOLD_HIGH_H_REG, 1)[0]
        elif cmd == AP3216C_PS_GAIN:
            temp = self.read_regs(AP3216C_PS_CONFIGURATION_REG, 1)[0]
            value = (temp & 0xc) >> 2
        elif cmd == AP3216C_PS_PERSIST:
            temp = self.read_regs(AP3216C_PS_CONFIGURATION_REG, 1)[0]
            value = temp & 0x3
        elif cmd == AP3216C_PS_LOW_THRESHOLD_L:
            value = self.read_regs(AP3216C_PS_THRESHOLD_LOW_L_REG, 1)[0]
        elif cmd == AP3216C_PS_LOW_THRESHOLD_H:
            value = self.read_regs(AP3216C_PS_THRESHOLD_LOW_H_REG, 1)[0]
        elif cmd == AP3216C_PS_HIGH_THRESHOLD_L:
            value = self.read_regs(AP3216C_PS_THRESHOLD_HIGH_L_REG, 1)[0]
        elif cmd == AP3216C_PS_HIGH_THRESHOLD_H:
            value = self.read_regs(AP3216C_PS_THRESHOLD_HIGH_H_REG, 1)[0]

        return value

    def close(self):
        self.i2cDev.close()
