1"""
2Copyright (C) 2015-2020 Alibaba Group Holding Limited
3
4The driver for AP3216C chip, The AP3216C is an integrated ALS & PS module
5that includes a digital ambient light sensor [ALS], a proximity sensor [PS],
6and an IR LED in a single package.
7"""
8from micropython import const
9from driver import I2C
10from utime import sleep_ms
11import math
12
13AP3216C_ADDR      = const(0x1e)
14
15# System Register
16AP3216C_SYS_CONFIGURATION_REG    = const(0x00)
17AP3216C_SYS_INT_STATUS_REG       = const(0x01)
18AP3216C_SYS_INT_CLEAR_MANNER_REG = const(0x02)
19AP3216C_IR_DATA_L_REG            = const(0x0A)
20AP3216C_IR_DATA_H_REG            = const(0x0B)
21AP3216C_ALS_DATA_L_REG           = const(0x0C)
22AP3216C_ALS_DATA_H_REG           = const(0x0D)
23AP3216C_PS_DATA_L_REG            = const(0x0E)
24AP3216C_PS_DATA_H_REG            = const(0x0F)
25
26# ALS Register
27AP3216C_ALS_CONFIGURATION_REG    = const(0x10)
28AP3216C_ALS_CALIBRATION_REG      = const(0x19)
29AP3216C_ALS_THRESHOLD_LOW_L_REG  = const(0x1A)
30AP3216C_ALS_THRESHOLD_LOW_H_REG  = const(0x1B)
31AP3216C_ALS_THRESHOLD_HIGH_L_REG = const(0x1C)
32AP3216C_ALS_THRESHOLD_HIGH_H_REG = const(0x1D)
33
34# PS Register
35AP3216C_PS_CONFIGURATION_REG    = const(0x20)
36AP3216C_PS_LED_DRIVER_REG       = const(0x21)
37AP3216C_PS_INT_FORM_REG         = const(0x22)
38AP3216C_PS_MEAN_TIME_REG        = const(0x23)
39AP3216C_PS_LED_WAITING_TIME_REG = const(0x24)
40AP3216C_PS_CALIBRATION_L_REG    = const(0x28)
41AP3216C_PS_CALIBRATION_H_REG    = const(0x29)
42AP3216C_PS_THRESHOLD_LOW_L_REG  = const(0x2A)
43AP3216C_PS_THRESHOLD_LOW_H_REG  = const(0x2B)
44AP3216C_PS_THRESHOLD_HIGH_L_REG = const(0x2C)
45AP3216C_PS_THRESHOLD_HIGH_H_REG = const(0x2D)
46
47#mode value
48AP3216C_MODE_POWER_DOWN    = const(0x0)
49AP3216C_MODE_ALS           = const(0x1)
50AP3216C_MODE_PS            = const(0x2)
51AP3216C_MODE_ALS_AND_PS    = const(0x3)
52AP3216C_MODE_SW_RESET      = const(0x4)
53AP3216C_MODE_ALS_ONCE      = const(0x5)
54AP3216C_MODE_PS_ONCE       = const(0x6)
55AP3216C_MODE_ALS_AND_PS_ONCE  = const(0x7)
56
57#ap3216c_int_clear_manner
58AP3216C_INT_CLEAR_MANNER_BY_READING    = const(0x0)
59AP3216C_ALS_CLEAR_MANNER_BY_SOFTWARE   = const(0x1)
60
61#als_range
62AP3216C_ALS_RANGE_20661    = const(0x0)
63AP3216C_ALS_RANGE_5162     = const(0x1)
64AP3216C_ALS_RANGE_1291     = const(0x2)
65AP3216C_ALS_RANGE_323    = const(0x3)
66
67#als_range
68AP3216C_PS_GAIN1    = const(0x0)
69AP3216C_PS_GAIN2     = const(0x1)
70AP3216C_PS_GAIN4     = const(0x2)
71AP3216C_PS_GAIN8    = const(0x3)
72
73AP3216C_SYSTEM_MODE          = const(0x0)
74AP3216C_INT_PARAM            = const(0x1)
75AP3216C_ALS_RANGE            = const(0x2)
76AP3216C_ALS_PERSIST          = const(0x3)
77AP3216C_ALS_CALIBRATION      = const(0x4)
78AP3216C_ALS_LOW_THRESHOLD_L  = const(0x5)
79AP3216C_ALS_LOW_THRESHOLD_H  = const(0x6)
80AP3216C_ALS_HIGH_THRESHOLD_L = const(0x7)
81AP3216C_ALS_HIGH_THRESHOLD_H = const(0x8)
82AP3216C_PS_INTEGRATED_TIME   = const(0x9)
83AP3216C_PS_GAIN              = const(0xa)
84AP3216C_PS_PERSIST           = const(0xb)
85AP3216C_PS_LED_CONTROL       = const(0xc)
86AP3216C_PS_LED_DRIVER_RATIO  = const(0xd)
87AP3216C_PS_INT_MODE          = const(0xe)
88AP3216C_PS_MEAN_TIME         = const(0xf)
89AP3216C_PS_WAITING_TIME      = const(0x10)
90AP3216C_PS_CALIBRATION_L     = const(0x11)
91AP3216C_PS_CALIBRATION_H     = const(0x12)
92AP3216C_PS_LOW_THRESHOLD_L   = const(0x13)
93AP3216C_PS_LOW_THRESHOLD_H   = const(0x14)
94AP3216C_PS_HIGH_THRESHOLD_L  = const(0x15)
95AP3216C_PS_HIGH_THRESHOLD_H  = const(0x16)
96
97class AP3216CError(Exception):
98    def __init__(self, value=0, msg="ap3216c common error"):
99        self.value = value
100        self.msg = msg
101
102    def __str__(self):
103        return "Error code:%d, Error message: %s" % (self.value, str(self.msg))
104
105    __repr__ = __str__
106
107class AP3216C(object):
108    """
109    This class implements ap3216c chip's defs.
110    """
111    def __init__(self):
112        self.i2cDev = None
113
114    def open(self, devid):
115        self.i2cDev = I2C()
116        self.i2cDev.open(devid)
117
118# 写寄存器的值
119    def write_reg(self, addr, data):
120        msgbuf = bytearray([data])
121        self.i2cDev.writeReg(addr, msgbuf)
122        print("--> write addr " + str(addr) + ", value = " + str(msgbuf))
123
124# 读寄存器的值
125    def read_regs(self, addr, len):
126        buf = bytearray(len)
127        self.i2cDev.readReg(addr, buf)
128        print("--> read " + str(len) + " bytes from addr " + str(addr) + ", " + str(len) + " bytes value = " + str(buf))
129        return buf;
130
131    # 软件复位传感器
132    def reset_sensor(self):
133        self.write_reg(AP3216C_SYS_CONFIGURATION_REG, AP3216C_MODE_SW_RESET); # reset
134
135    def read_low_and_high(self, reg, len):
136        # buf
137
138        # buf[0] = self.read_regs(reg, len) # 读低字节
139        # buf[1] = self.read_regs(reg + 1, len)  # 读高字节
140        data = self.read_regs(reg, len)[0] | (self.read_regs(reg + 1, len)[0] << len * 8) # 合并数据
141
142        if (data > (1 << 15)):
143            data = data - (1<<16)
144
145        return data
146
147    def ap3216c_get_IntStatus(self):
148        # 读中断状态寄存器
149        IntStatus = self.read_regs(AP3216C_SYS_INT_STATUS_REG, 1)[0]
150        # IntStatus 第 0 位表示 ALS 中断,第 1 位表示 PS 中断。
151        return IntStatus # 返回状态
152
153    def ap3216c_int_init(self):
154        print("ap3216c_int_init")
155    #配置 中断输入引脚
156    def ap3216c_int_Config(self):
157        print("ap3216c_int_Config")
158
159    #初始化入口
160    def init(self):
161        # reset ap3216c
162        self.reset_sensor()
163        sleep_ms(100)
164        self.ap3216c_set_param(AP3216C_SYSTEM_MODE, AP3216C_MODE_ALS_AND_PS)
165        sleep_ms(150) # delay at least 112.5ms
166
167        self.ap3216c_int_Config()
168        self.ap3216c_int_init()
169
170
171    # This function reads light by ap3216c sensor measurement
172    # @param no
173    # @return the ambient light converted to float data.
174    #
175    def ap3216c_read_ambient_light(self):
176        read_data = self.read_low_and_high(AP3216C_ALS_DATA_L_REG, 1)
177        range = self.ap3216c_get_param(AP3216C_ALS_RANGE)
178        print("ap3216c_read_ambient_light read_data is " , read_data, range)
179        if (range == AP3216C_ALS_RANGE_20661):
180            brightness = 0.35 * read_data # sensor ambient light converse to reality
181        elif (range == AP3216C_ALS_RANGE_5162):
182            brightness = 0.0788 * read_data # sensor ambient light converse to reality
183        elif (range == AP3216C_ALS_RANGE_1291):
184            brightness = 0.0197 * read_data # sensor ambient light converse to reality
185        elif (range == AP3216C_ALS_RANGE_323):
186            brightness = 0.0049 * read_data # sensor ambient light converse to reality
187
188        return brightness
189
190    #This function reads proximity by ap3216c sensor measurement
191    #@param no
192    #@return the proximity data.
193    def ap3216c_read_ps_data(self):
194        read_data = self.read_low_and_high(AP3216C_PS_DATA_L_REG, 1) # read two data
195        print("ap3216c_read_ps_data read_data is " , read_data);
196        if (1 == ((read_data >> 6) & 0x01 or (read_data >> 14) & 0x01)) :
197            return 55555 # 红外过高(IR),PS无效 返回一个 55555 的无效数据
198
199        proximity = (read_data & 0x000f) + (((read_data >> 8) & 0x3f) << 4)
200        # sensor proximity converse to reality
201        if (proximity > (1 << 15)) :
202            proximity = proximity - (1<<16)
203
204        proximity |= read_data & 0x8000 # 取最高位,0 表示物体远离,1 表示物体靠近
205        return proximity # proximity 后十位是数据位,最高位为状态位
206
207
208    #This function reads ir by ap3216c sensor measurement
209    #@param no
210    #@return the ir data.
211    def ap3216c_read_ir_data(self):
212        read_data = self.read_low_and_high(AP3216C_IR_DATA_L_REG, 1) # read two data
213        print("ap3216c_read_ir_data read_data is" , read_data);
214        proximity = (read_data & 0x0003) + ((read_data >> 8) & 0xFF)
215        # sensor proximity converse to reality
216        if (proximity > (1 << 15)) :
217            proximity = proximity - (1<<16)
218
219        return proximity
220
221    #This function sets parameter of ap3216c sensor
222    #@param cmd the parameter cmd of device
223    #@param value for setting value in cmd register
224    #@return the setting parameter status,RT_EOK reprensents setting successfully.
225
226    def ap3216c_set_param(self, cmd, value):
227        if cmd == AP3216C_SYSTEM_MODE:
228            # default 000,power down
229            self.write_reg(AP3216C_SYS_CONFIGURATION_REG, value)
230        elif cmd == AP3216C_INT_PARAM:
231            self.write_reg(AP3216C_SYS_INT_CLEAR_MANNER_REG, value)
232        elif cmd == AP3216C_ALS_RANGE:
233            args = self.read_regs(AP3216C_ALS_CONFIGURATION_REG, 1)[0]
234            args &= 0xcf
235            args |= value << 4
236            self.write_reg(AP3216C_ALS_CONFIGURATION_REG, args)
237        elif cmd == AP3216C_ALS_PERSIST:
238            args = self.read_regs(AP3216C_ALS_CONFIGURATION_REG, 1)[0]
239            args &= 0xf0
240            args |= value
241            self.write_reg(AP3216C_ALS_CONFIGURATION_REG, args)
242        elif cmd == AP3216C_ALS_LOW_THRESHOLD_L:
243            self.write_reg(AP3216C_ALS_THRESHOLD_LOW_L_REG, value)
244        elif cmd == AP3216C_ALS_LOW_THRESHOLD_H:
245           self.write_reg(AP3216C_ALS_THRESHOLD_LOW_H_REG, value)
246        elif cmd == AP3216C_ALS_HIGH_THRESHOLD_L:
247            self.write_reg(AP3216C_ALS_THRESHOLD_HIGH_L_REG, value)
248        elif cmd == AP3216C_ALS_HIGH_THRESHOLD_H:
249            self.write_reg(AP3216C_ALS_THRESHOLD_HIGH_H_REG, value)
250        elif cmd == AP3216C_PS_GAIN:
251            args = self.read_regs(AP3216C_PS_CONFIGURATION_REG, 1)[0]
252            args &= 0xf3
253            args |= value
254            self.write_reg(AP3216C_PS_CONFIGURATION_REG, args)
255        elif cmd == AP3216C_PS_PERSIST:
256            args = self.read_regs(AP3216C_PS_CONFIGURATION_REG, 1)[0]
257            args &= 0xfc
258            args |= value
259            self.write_reg(AP3216C_PS_CONFIGURATION_REG, args)
260        elif cmd == AP3216C_PS_LOW_THRESHOLD_L:
261            self.write_reg(AP3216C_PS_THRESHOLD_LOW_L_REG, value)
262        elif cmd == AP3216C_PS_LOW_THRESHOLD_H:
263            self.write_reg(AP3216C_PS_THRESHOLD_LOW_H_REG, value)
264        elif cmd == AP3216C_PS_HIGH_THRESHOLD_L:
265            self.write_reg(AP3216C_PS_THRESHOLD_HIGH_L_REG, value)
266        elif cmd == AP3216C_PS_HIGH_THRESHOLD_H:
267            self.write_reg(AP3216C_PS_THRESHOLD_HIGH_H_REG, value)
268
269    #This function gets parameter of ap3216c sensor
270    #@param cmd the parameter cmd of device
271    #@param value to get value in cmd register
272    #@return the getting parameter status,RT_EOK reprensents getting successfully.
273    def ap3216c_get_param(self, cmd):
274        if cmd == AP3216C_SYSTEM_MODE:
275            value = self.read_regs(AP3216C_SYS_CONFIGURATION_REG, 1)[0]
276        elif cmd == AP3216C_INT_PARAM:
277            value = self.read_regs(AP3216C_SYS_INT_CLEAR_MANNER_REG, 1)[0]
278        elif cmd == AP3216C_ALS_RANGE:
279            value = self.read_regs(AP3216C_ALS_CONFIGURATION_REG, 1)[0]
280            temp = (value & 0xff) >> 4
281            value = temp
282        elif cmd == AP3216C_ALS_PERSIST:
283            temp = self.read_regs(AP3216C_ALS_CONFIGURATION_REG, 1)[0]
284            temp = value & 0x0f
285            value = temp
286        elif cmd == AP3216C_ALS_LOW_THRESHOLD_L:
287            value = self.read_regs(AP3216C_ALS_THRESHOLD_LOW_L_REG, 1)[0]
288        elif cmd == AP3216C_ALS_LOW_THRESHOLD_H:
289            value = self.read_regs(AP3216C_ALS_THRESHOLD_LOW_H_REG, 1)[0]
290        elif cmd == AP3216C_ALS_HIGH_THRESHOLD_L:
291            value = self.read_regs(AP3216C_ALS_THRESHOLD_HIGH_L_REG, 1)[0]
292        elif cmd == AP3216C_ALS_HIGH_THRESHOLD_H:
293            value = self.read_regs(AP3216C_ALS_THRESHOLD_HIGH_H_REG, 1)[0]
294        elif cmd == AP3216C_PS_GAIN:
295            temp = self.read_regs(AP3216C_PS_CONFIGURATION_REG, 1)[0]
296            value = (temp & 0xc) >> 2
297        elif cmd == AP3216C_PS_PERSIST:
298            temp = self.read_regs(AP3216C_PS_CONFIGURATION_REG, 1)[0]
299            value = temp & 0x3
300        elif cmd == AP3216C_PS_LOW_THRESHOLD_L:
301            value = self.read_regs(AP3216C_PS_THRESHOLD_LOW_L_REG, 1)[0]
302        elif cmd == AP3216C_PS_LOW_THRESHOLD_H:
303            value = self.read_regs(AP3216C_PS_THRESHOLD_LOW_H_REG, 1)[0]
304        elif cmd == AP3216C_PS_HIGH_THRESHOLD_L:
305            value = self.read_regs(AP3216C_PS_THRESHOLD_HIGH_L_REG, 1)[0]
306        elif cmd == AP3216C_PS_HIGH_THRESHOLD_H:
307            value = self.read_regs(AP3216C_PS_THRESHOLD_HIGH_H_REG, 1)[0]
308
309        return value
310
311    def close(self):
312        self.i2cDev.close()
313