Skip to content

Commit 77d6522

Browse files
authored
feat: support interrupts and power saving mode
1 parent 82c4aa0 commit 77d6522

File tree

9 files changed

+418
-40
lines changed

9 files changed

+418
-40
lines changed

lib/veml7700.ex

Lines changed: 102 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ defmodule VEML7700 do
6565
end
6666

6767
@doc """
68-
Get the ambient light settings.
68+
Get the ambient light sensor settings.
6969
"""
7070
@spec get_als_config(GenServer.server()) ::
7171
{:error, any} | {:ok, {setting_names :: [atom], resolution :: float}}
@@ -74,14 +74,72 @@ defmodule VEML7700 do
7474
end
7575

7676
@doc """
77-
Set the ambient light settings.
77+
Set the ambient light sensor settings.
7878
"""
7979
@spec set_als_config(GenServer.server(), als_gain | als_integration_time) ::
8080
{:error, any} | {:ok, {setting_names :: [atom], resolution :: float}}
8181
def set_als_config(server \\ __MODULE__, als_setting_names) do
8282
GenServer.call(server, {:set_als_config, als_setting_names})
8383
end
8484

85+
@doc """
86+
Get the low threshold.
87+
"""
88+
@spec get_low_threshold(GenServer.server()) :: {:error, any} | {:ok, 0..0xFFFF}
89+
def get_low_threshold(server \\ __MODULE__) do
90+
GenServer.call(server, :get_low_threshold)
91+
end
92+
93+
@doc """
94+
Set the low threshold.
95+
"""
96+
@spec set_low_threshold(GenServer.server(), 0..0xFFFF) :: {:error, any} | :ok
97+
def set_low_threshold(server \\ __MODULE__, value) do
98+
GenServer.call(server, {:set_low_threshold, value})
99+
end
100+
101+
@doc """
102+
Get the high threshold.
103+
"""
104+
@spec get_high_threshold(GenServer.server()) :: {:error, any} | {:ok, 0..0xFFFF}
105+
def get_high_threshold(server \\ __MODULE__) do
106+
GenServer.call(server, :get_high_threshold)
107+
end
108+
109+
@doc """
110+
Set the high threshold.
111+
"""
112+
@spec set_high_threshold(GenServer.server(), 0..0xFFFF) :: {:error, any} | :ok
113+
def set_high_threshold(server \\ __MODULE__, value) do
114+
GenServer.call(server, {:set_high_threshold, value})
115+
end
116+
117+
@doc """
118+
Get the power saving mode.
119+
"""
120+
@spec get_power_saving(GenServer.server()) ::
121+
{:error, any} | {:ok, {mode :: 0..3, enabled :: boolean}}
122+
def get_power_saving(server \\ __MODULE__) do
123+
GenServer.call(server, :get_power_saving)
124+
end
125+
126+
@doc """
127+
Set the power saving mode.
128+
"""
129+
@spec set_power_saving(GenServer.server(), mode :: 0..3, enabled :: boolean) ::
130+
{:error, any} | :ok
131+
def set_power_saving(server \\ __MODULE__, mode, enabled) do
132+
GenServer.call(server, {:set_power_saving, mode, enabled})
133+
end
134+
135+
@doc """
136+
Get the interrupt status.
137+
"""
138+
@spec get_interrupt_status(GenServer.server()) :: {:error, any} | {:ok, 0..0xFFFF}
139+
def get_interrupt_status(server \\ __MODULE__) do
140+
GenServer.call(server, :get_interrupt_status)
141+
end
142+
85143
## GenServer callbacks
86144

87145
@impl GenServer
@@ -165,6 +223,48 @@ defmodule VEML7700 do
165223
end
166224
end
167225

226+
def handle_call(:get_low_threshold, _from, state) do
227+
result = Comm.read_low_threshold(state.transport)
228+
229+
{:reply, result, state}
230+
end
231+
232+
def handle_call({:set_low_threshold, value}, _from, state) do
233+
result = Comm.write_low_threshold(state.transport, value)
234+
235+
{:reply, result, state}
236+
end
237+
238+
def handle_call(:get_high_threshold, _from, state) do
239+
result = Comm.read_high_threshold(state.transport)
240+
241+
{:reply, result, state}
242+
end
243+
244+
def handle_call({:set_high_threshold, value}, _from, state) do
245+
result = Comm.write_high_threshold(state.transport, value)
246+
247+
{:reply, result, state}
248+
end
249+
250+
def handle_call(:get_power_saving, _from, state) do
251+
result = Comm.read_power_saving(state.transport)
252+
253+
{:reply, result, state}
254+
end
255+
256+
def handle_call({:set_power_saving, mode, enable}, _from, state) do
257+
result = Comm.write_power_saving(state.transport, mode, enable)
258+
259+
{:reply, result, state}
260+
end
261+
262+
def handle_call(:get_interrupt_status, _from, state) do
263+
result = Comm.read_interrupt_status(state.transport)
264+
265+
{:reply, result, state}
266+
end
267+
168268
@impl GenServer
169269
def handle_info(:perform_measurement, state) do
170270
new_state =

lib/veml7700/comm.ex

Lines changed: 84 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,16 @@ defmodule VEML7700.Comm do
2626
|> Register.Configuration.set(als_setting_names)
2727
|> Register.Configuration.to_integer()
2828

29-
:ok = write_register(transport, :als_config, new_value)
30-
read_als_config(transport)
29+
case write_register(transport, :als_config, new_value) do
30+
:ok ->
31+
read_als_config(transport)
3132

32-
error ->
33-
error
33+
{:error, error} ->
34+
{:error, error}
35+
end
36+
37+
{:error, error} ->
38+
{:error, error}
3439
end
3540
end
3641

@@ -51,6 +56,67 @@ defmodule VEML7700.Comm do
5156
end
5257
end
5358

59+
## register 01
60+
61+
@spec write_high_threshold(Transport.t(), 0..0xFFFF) :: {:error, any} | :ok
62+
def write_high_threshold(transport, value) do
63+
write_register(transport, :als_threshold_high, value)
64+
end
65+
66+
@spec read_high_threshold(Transport.t()) :: {:error, any} | {:ok, 0..0xFFFF}
67+
def read_high_threshold(transport) do
68+
read_register(transport, :als_threshold_high)
69+
end
70+
71+
## register 02
72+
73+
@spec write_low_threshold(Transport.t(), 0..0xFFFF) :: {:error, any} | :ok
74+
def write_low_threshold(transport, value) do
75+
write_register(transport, :als_threshold_low, value)
76+
end
77+
78+
@spec read_low_threshold(Transport.t()) :: {:error, any} | {:ok, 0..0xFFFF}
79+
def read_low_threshold(transport) do
80+
read_register(transport, :als_threshold_low)
81+
end
82+
83+
## register 03
84+
85+
@spec write_power_saving(Transport.t(), 0..3, boolean) :: {:error, any} | :ok
86+
def write_power_saving(transport, mode, enable) do
87+
case read_register(transport, :als_power_saving) do
88+
{:ok, current_value} ->
89+
new_value =
90+
current_value
91+
|> Register.PowerSaving.from_integer()
92+
|> Register.PowerSaving.set_enabled(enable)
93+
|> Register.PowerSaving.set_mode(mode)
94+
|> Register.PowerSaving.to_integer()
95+
96+
write_register(transport, :als_power_saving, new_value)
97+
98+
{:error, error} ->
99+
{:error, error}
100+
end
101+
end
102+
103+
@spec read_power_saving(Transport.t()) ::
104+
{:error, any} | {:ok, {mode :: 0..3, enabled :: boolean}}
105+
def read_power_saving(transport) do
106+
case read_register(transport, :als_power_saving) do
107+
{:ok, current_value} ->
108+
{mode, enabled} =
109+
current_value
110+
|> Register.PowerSaving.from_integer()
111+
|> Register.PowerSaving.to_tuple()
112+
113+
{:ok, {mode, enabled}}
114+
115+
{:error, error} ->
116+
{:error, error}
117+
end
118+
end
119+
54120
## register 04
55121

56122
@spec read_als_output(Transport.t(), number) :: {:error, any} | {:ok, Measurement.t()}
@@ -64,6 +130,20 @@ defmodule VEML7700.Comm do
64130
end
65131
end
66132

133+
## register 06
134+
135+
@spec read_interrupt_status(Transport.t()) ::
136+
{:error, any} | {:ok, [:high_threshold_crossed | :low_threshold_crossed]}
137+
def read_interrupt_status(transport) do
138+
case read_register(transport, :interrupt_status) do
139+
{:ok, new_value} ->
140+
{:ok, Register.InterruptStatus.from_integer(new_value)}
141+
142+
{:error, error} ->
143+
{:error, error}
144+
end
145+
end
146+
67147
## generic read and write
68148

69149
# Write value with command name

lib/veml7700/register/configuration.ex

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ defmodule VEML7700.Register.Configuration do
5656
@doc """
5757
Sets configuration values with one or more setting name atoms
5858
"""
59-
@spec set(map, atom | [atom]) :: map
59+
@spec set(struct, atom | [atom]) :: struct
6060
def set(t, setting_name) when is_atom(setting_name) do
6161
set(t, [setting_name])
6262
end
@@ -74,15 +74,15 @@ defmodule VEML7700.Register.Configuration do
7474
@doc """
7575
Gets configuration values with one or more setting name atoms
7676
"""
77-
@spec to_list(map) :: [atom]
77+
@spec to_list(struct) :: [atom]
7878
def to_list(t), do: get(t, @register_names)
7979

80-
@spec get(map, atom) :: atom
80+
@spec get(struct, atom) :: atom
8181
def get(t, register_name) when is_atom(register_name) do
8282
get(t, [register_name]) |> List.first()
8383
end
8484

85-
@spec get(map, [atom]) :: [atom]
85+
@spec get(struct, [atom]) :: [atom]
8686
def get(t, register_names) when is_list(register_names) do
8787
Enum.reduce(@possible_settings, [], fn {setting_name, register_name, value}, acc ->
8888
if register_name in register_names and value == Map.fetch!(t, register_name) do
@@ -120,7 +120,7 @@ defmodule VEML7700.Register.Configuration do
120120
uint16 >>> position &&& mask
121121
end
122122

123-
@spec resolution(map) :: float
123+
@spec resolution(struct) :: float
124124
def resolution(t) do
125125
als_gain = get(t, :als_gain)
126126
als_integration_time = get(t, :als_integration_time)

lib/veml7700/register/interrupt_status.ex

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,22 +5,33 @@ defmodule VEML7700.Register.InterruptStatus do
55
import Bitwise
66

77
# interrupt flags (bits 15:14)
8-
@interrupt_high 0x4000
9-
@interrupt_low 0x8000
8+
@interrupt_high_crossed 0x4000
9+
@interrupt_low_crossed 0x8000
10+
11+
@doc """
12+
Converts 16-bit integer to list
13+
"""
14+
@spec from_integer(0..0xFFFF) :: [:low_threshold_crossed | :high_threshold_crossed]
15+
def from_integer(uint16) do
16+
result = []
17+
result = if(low_threshold?(uint16), do: [:low_threshold_crossed | result], else: result)
18+
result = if(high_threshold?(uint16), do: [:high_threshold_crossed | result], else: result)
19+
result
20+
end
1021

1122
@doc """
1223
Returns true when low threshold exceeded.
1324
"""
1425
@spec low_threshold?(0..0xFFFF) :: boolean
1526
def low_threshold?(uint16) do
16-
(uint16 &&& @interrupt_low) > 0
27+
(uint16 &&& @interrupt_low_crossed) > 0
1728
end
1829

1930
@doc """
2031
Returns true when high threshold exceeded.
2132
"""
2233
@spec high_threshold?(0..0xFFFF) :: boolean
2334
def high_threshold?(uint16) do
24-
(uint16 &&& @interrupt_high) > 0
35+
(uint16 &&& @interrupt_high_crossed) > 0
2536
end
2637
end
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
defmodule VEML7700.Register.PowerSaving do
2+
@moduledoc false
3+
# The configuration register (0x03)
4+
5+
defstruct mode: 0, enabled: 0, reserved1: 0, reserved2: 0
6+
7+
@spec new(keyword) :: struct
8+
def new(kv \\ []), do: struct!(__MODULE__, kv)
9+
10+
@spec set_enabled(struct, boolean) :: struct
11+
def set_enabled(t, true), do: struct!(t, enabled: 1)
12+
def set_enabled(t, false), do: struct!(t, enabled: 0)
13+
14+
@spec set_mode(struct, 0..3) :: struct
15+
def set_mode(t, mode) when is_integer(mode) and mode in 0..3 do
16+
struct!(t, mode: mode)
17+
end
18+
19+
@doc """
20+
Converts struct to 16-bit integer
21+
"""
22+
@spec to_integer(struct) :: 0..0xFFFF
23+
def to_integer(t) do
24+
<<value::little-16>> = <<t.reserved1::5, t.mode::2, t.enabled::1, t.reserved2::8>>
25+
value
26+
end
27+
28+
@doc """
29+
Converts 16-bit integer to struct
30+
"""
31+
@spec from_integer(0..0xFFFF) :: struct
32+
def from_integer(value) do
33+
<<reserved1::5, mode::2, enabled::1, reserved2::8>> = <<value::little-16>>
34+
new(reserved1: reserved1, mode: mode, enabled: enabled, reserved2: reserved2)
35+
end
36+
37+
@spec to_tuple(struct) :: {0..3, boolean}
38+
def to_tuple(t), do: {t.mode, enabled?(t)}
39+
40+
@spec enabled?(struct) :: boolean
41+
def enabled?(%{enabled: 1}), do: true
42+
def enabled?(%{enabled: 0}), do: false
43+
end

0 commit comments

Comments
 (0)