RaspberrPi project source code
guowenxue
2024-03-14 7fa125e56f1de17c2f6aeb9a410ff02ac4e78e85
commit | author | age
d6b4a7 1 /*********************************************************************************
G 2  *      Copyright:  (C) 2023 LingYun IoT System Studio
3  *                  All rights reserved.
4  *
5  *       Filename:  tsl2561.c
6  *    Description:  This file is the Lux sensor TSL2561 code
7  *
8  *        Version:  1.0.0(10/08/23)
9  *         Author:  Guo Wenxue <guowenxue@gmail.com>
10  *      ChangeLog:  1, Release initial version on "10/08/23 17:52:00"
11  *
12  * Pin connection:
13  *               STH20 Module            Raspberry Pi Board
14  *                   VCC      <----->      #Pin1(3.3V)
15  *                   SDA0     <----->      #Pin27(SDA, BCM GPIO0)
16  *                   SCL0     <----->      #Pin28(SCL, BCM GPIO1)
17  *                   GND      <----->      GND
18  *
19  * /boot/config.txt:
20  *                  dtoverlay=i2c0,pins_0_1
21  *
22  ********************************************************************************/
23
24
25 #include <string.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <unistd.h>
29 #include <math.h>
30 #include <time.h>
31 #include <errno.h>
32 #include <libgen.h>
33 #include <getopt.h>
34 #include <fcntl.h>
35 #include <sys/ioctl.h>
36 #include <linux/i2c.h>
37 #include <linux/i2c-dev.h>
38 #include <sys/types.h>
39 #include <sys/stat.h>
40
41 #include "util_proc.h"
42 #include "logger.h"
43 #include "tsl2561.h"
44
45
46 #define CONTROL_REG                     0x80
47 #define REG_COUNT                       4
48
49 #define POWER_UP                        0x03
50 #define POWER_DOWN                      0x00
51
52 #define OFF                             0
53 #define ON                              1
54
55 /* Register Address  */
56 enum
57 {
58     /* Channel_0 = DATA0HIGH<<8 + DATA0LOW */
59     DATA0LOW = 0x8C,
60     DATA0HIGH,
61
62     /* Channel_1 = DATA1HIGH<<8 + DATA1LOW */
63     DATA1LOW,
64     DATA1HIGH,
65 };
66
67 static const int  regs_addr[REG_COUNT]={DATA0LOW, DATA0HIGH, DATA1LOW, DATA1HIGH};
68
69 void tsl2561_power(int fd, int cmd)
70 {
71     struct i2c_msg               msg;
72     struct i2c_rdwr_ioctl_data   data;
73     unsigned char                buf[2];
74
75     msg.addr= TSL2561_I2CADDR;
76     msg.flags=0;  /* write */
77     msg.len= 1;
78     msg.buf= buf;
79
80     data.nmsgs= 1;
81     data.msgs= &msg;
82
83     msg.buf[0]=CONTROL_REG;
84     if( ioctl(fd, I2C_RDWR, &data) < 0 )
85     {
86         log_error("%s() ioctl failure: %s\n", __func__, strerror(errno));
87         return ;
88     }
89
90
91     if( cmd )
92         msg.buf[0]=POWER_UP;
93     else
94         msg.buf[0]=POWER_DOWN;
95
96     if( ioctl(fd, I2C_RDWR, &data) < 0 )
97     {
98         log_error("%s() ioctl failure: %s\n", __func__, strerror(errno));
99         return ;
100     }
101
102     return ;
103 }
104
105 int tsl2561_readreg(int fd, unsigned char regaddr, unsigned char *regval)
106 {
107     struct i2c_msg               msg;
108     struct i2c_rdwr_ioctl_data   data;
109     unsigned char                buf[2];
110
111     msg.addr= TSL2561_I2CADDR;
112     msg.flags=0;  /* write */
113     msg.len= 1;
114     msg.buf= buf;
115     msg.buf[0] = regaddr;
116
117     data.nmsgs= 1;
118     data.msgs= &msg;
119
120     if( ioctl(fd, I2C_RDWR, &data) < 0 )
121     {
122         log_error("%s() ioctl failure: %s\n", __func__, strerror(errno));
123         return -1;
124     }
125
126     memset(buf, 0, sizeof(buf));
127
128     msg.addr= TSL2561_I2CADDR;
129     msg.flags=I2C_M_RD;  /* read */
130     msg.len= 1;
131     msg.buf= buf;
132
133     data.nmsgs= 1;
134     data.msgs= &msg;
135
136     if( ioctl(fd, I2C_RDWR, &data) < 0 )
137     {
138         log_error("%s() ioctl failure: %s\n", __func__, strerror(errno));
139         return -1;
140     }
141
142     *regval = msg.buf[0];
143     return 0;
144 }
145
146 int tsl2561_get_lux(float *lux)
147 {
148     int                 i, fd;
149     int                 rv = 0;
150     char               *dev = TSL2561_I2CDEV;
151     float               div = 0.0;
152
153     unsigned char       reg_data[REG_COUNT];
154     unsigned char       buf;
155     int                 chn0_data = 0;
156     int                 chn1_data = 0;
157
158     if( !lux )
159     {
160         log_error("Invalid input arguments\n");
161         return -1;
162     }
163
164     if( (fd=open(dev, O_RDWR)) < 0)
165     {
166         log_error("i2c device '%s' open failed: %s\n", dev, strerror(errno));
167         return -2;
168     }
169
170     tsl2561_power(fd, ON);
171
172     msleep(410);  /* t(CONV) MAX 400ms */
173
174     /* Read register Channel0 and channel1 data from register */
175     for(i=0; i<REG_COUNT; i++)
176     {
177         tsl2561_readreg(fd, regs_addr[i], &reg_data[i]);
178     }
179
180     chn0_data = reg_data[1]*256 + reg_data[0]; /* Channel0 = DATA0HIGH<<8 + DATA0LOW  */
181     chn1_data = reg_data[3]*256 + reg_data[2]; /* channel1 = DATA1HIGH<<8 +  DATA1LOW */
182
183     if( chn0_data<=0 || chn1_data<0 )
184     {
185         rv = -2;
186         goto OUT;
187     }
188
189     div = (float)chn1_data / (float)chn0_data;
190
191     if( div>0 && div<=0.5 )
192         *lux = 0.304*chn0_data-0.062*chn0_data*pow(div,1.4);
193
194     else if( div>0.5 && div<=0.61 )
195         *lux = 0.0224*chn0_data-0.031*chn1_data;
196
197     else if( div>0.61 && div<=0.8 )
198         *lux = 0.0128*chn0_data-0.0153*chn1_data;
199
200     else if( div>0.8 && div<=1.3 )
201         *lux = 0.00146*chn0_data-0.00112*chn1_data;
202
203     else if( div>1.3 )
204         *lux = 0.0;
205
206 OUT:
207     tsl2561_power(fd, OFF);
208     return rv;
209 }