Firmware SDK
 All Data Structures Functions Variables Typedefs Enumerations Enumerator Groups Pages
bc_opt3001.c
1 #include <bc_opt3001.h>
2 
3 #define _BC_OPT3001_DELAY_RUN 50
4 #define _BC_OPT3001_DELAY_INITIALIZATION 50
5 #define _BC_OPT3001_DELAY_MEASUREMENT 1000
6 
7 static void _bc_opt3001_task_interval(void *param);
8 
9 static void _bc_opt3001_task_measure(void *param);
10 
11 void bc_opt3001_init(bc_opt3001_t *self, bc_i2c_channel_t i2c_channel, uint8_t i2c_address)
12 {
13  memset(self, 0, sizeof(*self));
14 
15  self->_i2c_channel = i2c_channel;
16  self->_i2c_address = i2c_address;
17 
18  self->_task_id_interval = bc_scheduler_register(_bc_opt3001_task_interval, self, BC_TICK_INFINITY);
19  self->_task_id_measure = bc_scheduler_register(_bc_opt3001_task_measure, self, _BC_OPT3001_DELAY_RUN);
20 
21  self->_tick_ready = _BC_OPT3001_DELAY_RUN;
22 
23  bc_i2c_init(self->_i2c_channel, BC_I2C_SPEED_400_KHZ);
24 }
25 
26 void bc_opt3001_set_event_handler(bc_opt3001_t *self, void (*event_handler)(bc_opt3001_t *, bc_opt3001_event_t, void *), void *event_param)
27 {
28  self->_event_handler = event_handler;
29  self->_event_param = event_param;
30 }
31 
33 {
34  self->_update_interval = interval;
35 
36  if (self->_update_interval == BC_TICK_INFINITY)
37  {
38  bc_scheduler_plan_absolute(self->_task_id_interval, BC_TICK_INFINITY);
39  }
40  else
41  {
42  bc_scheduler_plan_relative(self->_task_id_interval, self->_update_interval);
43 
44  bc_opt3001_measure(self);
45  }
46 }
47 
49 {
50  if (self->_measurement_active)
51  {
52  return false;
53  }
54 
55  self->_measurement_active = true;
56 
57  bc_scheduler_plan_absolute(self->_task_id_measure, self->_tick_ready);
58 
59  return true;
60 }
61 
62 bool bc_opt3001_get_illuminance_raw(bc_opt3001_t *self, uint16_t *raw)
63 {
64  if (!self->_illuminance_valid)
65  {
66  return false;
67  }
68 
69  *raw = self->_reg_result;
70 
71  return true;
72 }
73 
75 {
76  uint16_t raw;
77 
78  if (!bc_opt3001_get_illuminance_raw(self, &raw))
79  {
80  return false;
81  }
82 
83  *lux = 0.01f * (float) (1 << (raw >> 12)) * (float) (raw & 0xfff);
84 
85  return true;
86 }
87 
88 static void _bc_opt3001_task_interval(void *param)
89 {
90  bc_opt3001_t *self = param;
91 
92  bc_opt3001_measure(self);
93 
94  bc_scheduler_plan_current_relative(self->_update_interval);
95 }
96 
97 static void _bc_opt3001_task_measure(void *param)
98 {
99  bc_opt3001_t *self = param;
100 
101 start:
102 
103  switch (self->_state)
104  {
105  case BC_OPT3001_STATE_ERROR:
106  {
107  self->_illuminance_valid = false;
108 
109  self->_measurement_active = false;
110 
111  if (self->_event_handler != NULL)
112  {
113  self->_event_handler(self, BC_OPT3001_EVENT_ERROR, self->_event_param);
114  }
115 
116  self->_state = BC_OPT3001_STATE_INITIALIZE;
117 
118  return;
119  }
120  case BC_OPT3001_STATE_INITIALIZE:
121  {
122  self->_state = BC_OPT3001_STATE_ERROR;
123 
124  if (!bc_i2c_memory_write_16b(self->_i2c_channel, self->_i2c_address, 0x01, 0xc810))
125  {
126  goto start;
127  }
128 
129  self->_state = BC_OPT3001_STATE_MEASURE;
130 
131  self->_tick_ready = bc_tick_get() + _BC_OPT3001_DELAY_INITIALIZATION;
132 
133  if (self->_measurement_active)
134  {
135  bc_scheduler_plan_current_absolute(self->_tick_ready);
136  }
137 
138  return;
139  }
140  case BC_OPT3001_STATE_MEASURE:
141  {
142  self->_state = BC_OPT3001_STATE_ERROR;
143 
144  if (!bc_i2c_memory_write_16b(self->_i2c_channel, self->_i2c_address, 0x01, 0xca10))
145  {
146  goto start;
147  }
148 
149  self->_state = BC_OPT3001_STATE_READ;
150 
151  bc_scheduler_plan_current_from_now(_BC_OPT3001_DELAY_MEASUREMENT);
152 
153  return;
154  }
155  case BC_OPT3001_STATE_READ:
156  {
157  self->_state = BC_OPT3001_STATE_ERROR;
158 
159  uint16_t reg_configuration;
160 
161  if (!bc_i2c_memory_read_16b(self->_i2c_channel, self->_i2c_address, 0x01, &reg_configuration))
162  {
163  goto start;
164  }
165 
166  if ((reg_configuration & 0x0680) != 0x0080)
167  {
168  goto start;
169  }
170 
171  if (!bc_i2c_memory_read_16b(self->_i2c_channel, self->_i2c_address, 0x00, &self->_reg_result))
172  {
173  goto start;
174  }
175 
176  self->_illuminance_valid = true;
177 
178  self->_state = BC_OPT3001_STATE_UPDATE;
179 
180  goto start;
181  }
182  case BC_OPT3001_STATE_UPDATE:
183  {
184  self->_measurement_active = false;
185 
186  if (self->_event_handler != NULL)
187  {
188  self->_event_handler(self, BC_OPT3001_EVENT_UPDATE, self->_event_param);
189  }
190 
191  self->_state = BC_OPT3001_STATE_MEASURE;
192 
193  return;
194  }
195  default:
196  {
197  self->_state = BC_OPT3001_STATE_ERROR;
198 
199  goto start;
200  }
201  }
202 }
void bc_opt3001_set_event_handler(bc_opt3001_t *self, void(*event_handler)(bc_opt3001_t *, bc_opt3001_event_t, void *), void *event_param)
Set callback function.
Definition: bc_opt3001.c:26
uint64_t bc_tick_t
Timestamp data type.
Definition: bc_tick.h:16
bool bc_i2c_memory_write_16b(bc_i2c_channel_t channel, uint8_t device_address, uint32_t memory_address, uint16_t data)
Memory write 2 bytes to I2C channel.
Definition: bc_i2c.c:414
I2C communication speed is 400 kHz.
Definition: bc_i2c.h:36
void bc_opt3001_set_update_interval(bc_opt3001_t *self, bc_tick_t interval)
Set measurement interval.
Definition: bc_opt3001.c:32
void bc_scheduler_plan_absolute(bc_scheduler_task_id_t task_id, bc_tick_t tick)
Schedule specified task to absolute tick.
Definition: bc_scheduler.c:124
bool bc_opt3001_measure(bc_opt3001_t *self)
Start measurement manually.
Definition: bc_opt3001.c:48
bc_scheduler_task_id_t bc_scheduler_register(void(*task)(void *), void *param, bc_tick_t tick)
Register task in scheduler.
Definition: bc_scheduler.c:56
void bc_scheduler_plan_current_absolute(bc_tick_t tick)
Schedule current task to absolute tick.
Definition: bc_scheduler.c:144
void bc_i2c_init(bc_i2c_channel_t channel, bc_i2c_speed_t speed)
Initialize I2C channel.
Definition: bc_i2c.c:54
bool bc_opt3001_get_illuminance_lux(bc_opt3001_t *self, float *lux)
Get measured illuminance in lux.
Definition: bc_opt3001.c:74
bc_tick_t bc_tick_get(void)
Get absolute timestamp since start of program.
Definition: bc_tick.c:7
void bc_scheduler_plan_current_relative(bc_tick_t tick)
Schedule current task to tick relative from current spin.
Definition: bc_scheduler.c:149
void bc_opt3001_init(bc_opt3001_t *self, bc_i2c_channel_t i2c_channel, uint8_t i2c_address)
Initialize OPT3001 driver.
Definition: bc_opt3001.c:11
void bc_scheduler_plan_relative(bc_scheduler_task_id_t task_id, bc_tick_t tick)
Schedule specified task to tick relative from current spin.
Definition: bc_scheduler.c:129
bool bc_opt3001_get_illuminance_raw(bc_opt3001_t *self, uint16_t *raw)
Get measured illuminance as raw value.
Definition: bc_opt3001.c:62
bc_opt3001_event_t
Callback events.
Definition: bc_opt3001.h:13
Error event.
Definition: bc_opt3001.h:16
bc_i2c_channel_t
I2C channels.
Definition: bc_i2c.h:15
struct bc_opt3001_t bc_opt3001_t
OPT3001 instance.
Definition: bc_opt3001.h:25
void bc_scheduler_plan_current_from_now(bc_tick_t tick)
Schedule current task to tick relative from now.
Definition: bc_scheduler.c:154
#define BC_TICK_INFINITY
Maximum timestamp value.
Definition: bc_tick.h:12
Update event.
Definition: bc_opt3001.h:19
bool bc_i2c_memory_read_16b(bc_i2c_channel_t channel, uint8_t device_address, uint32_t memory_address, uint16_t *data)
Memory read 2 bytes from I2C channel.
Definition: bc_i2c.c:443