Skip to content

Commit 79ec5c3

Browse files
mnishiguchifhunleth
authored andcommitted
add VEML7700 sim
1 parent df3774e commit 79ec5c3

3 files changed

Lines changed: 173 additions & 0 deletions

File tree

config/config.exs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ config :circuits_sim,
1010
{CircuitsSim.Device.MCP23008, bus_name: "i2c-1", address: 0x21},
1111
{CircuitsSim.Device.AHT20, bus_name: "i2c-1", address: 0x38},
1212
{CircuitsSim.Device.SHT4X, bus_name: "i2c-1", address: 0x44},
13+
{CircuitsSim.Device.VEML7700, bus_name: "i2c-1", address: 0x48},
1314
{CircuitsSim.Device.SGP30, bus_name: "i2c-1", address: 0x58},
1415
{CircuitsSim.Device.BMP280, bus_name: "i2c-1", address: 0x76},
1516
{CircuitsSim.Device.BMP280, bus_name: "i2c-1", address: 0x77},
Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
defmodule CircuitsSim.Device.VEML7700 do
2+
@moduledoc """
3+
Vishay VEML7700 ambient light sensors. This sim works for VEML6030 as well.
4+
5+
VEML7700 sensors are at address 0x10; VEML6030 typically at 0x48.
6+
See the [datasheet](https://www.vishay.com/docs/84286/veml7700.pdf) for details.
7+
8+
Call `set_state/3` to change the state of the sensor.
9+
"""
10+
alias CircuitsSim.I2C.I2CDevice
11+
alias CircuitsSim.I2C.I2CServer
12+
13+
defstruct als_config: 0x0000,
14+
als_threshold_high: 0x0000,
15+
als_threshold_low: 0x0000,
16+
als_power_saving: 0x0000,
17+
als_output: 0x0000,
18+
white_output: 0x0000,
19+
interrupt_status: 0x0000
20+
21+
@type t() :: %__MODULE__{
22+
als_config: 0..0xFFFF,
23+
als_threshold_high: 0..0xFFFF,
24+
als_threshold_low: 0..0xFFFF,
25+
als_power_saving: 0..0xFFFF,
26+
als_output: 0..0xFFFF,
27+
white_output: 0..0xFFFF,
28+
interrupt_status: 0..0xFFFF
29+
}
30+
31+
@spec child_spec(keyword()) :: Supervisor.child_spec()
32+
def child_spec(args) do
33+
device = __MODULE__.new()
34+
I2CServer.child_spec_helper(device, args)
35+
end
36+
37+
@spec new(keyword) :: t()
38+
def new(_options \\ []) do
39+
%__MODULE__{}
40+
end
41+
42+
@spec set_state(String.t(), Circuits.I2C.address(), keyword()) :: :ok
43+
def set_state(bus_name, address, kv) do
44+
I2CServer.send_message(bus_name, address, {:set_state, kv})
45+
end
46+
47+
## protocol implementation
48+
49+
defimpl I2CDevice do
50+
@cmd_als_config 0
51+
@cmd_als_threshold_high 1
52+
@cmd_als_threshold_low 2
53+
@cmd_als_power_saving 3
54+
@cmd_als_output 4
55+
@cmd_white_output 5
56+
@cmd_interrupt_status 6
57+
58+
@impl I2CDevice
59+
def read(state, count) do
60+
{:binary.copy(<<0>>, count), state}
61+
end
62+
63+
@impl I2CDevice
64+
def write(state, <<@cmd_als_config, value::little-16>>) do
65+
%{state | als_config: value}
66+
end
67+
68+
def write(state, <<@cmd_als_threshold_high, data::little-16>>) do
69+
%{state | als_threshold_high: data}
70+
end
71+
72+
def write(state, <<@cmd_als_threshold_low, data::little-16>>) do
73+
%{state | als_threshold_low: data}
74+
end
75+
76+
def write(state, <<@cmd_als_power_saving, data::little-16>>) do
77+
%{state | als_power_saving: data}
78+
end
79+
80+
def write(state, _), do: state
81+
82+
@impl I2CDevice
83+
def write_read(state, <<@cmd_als_config>>, read_count) do
84+
result = <<state.als_config::little-16>> |> trim_pad(read_count)
85+
{result, state}
86+
end
87+
88+
def write_read(state, <<@cmd_als_threshold_high>>, read_count) do
89+
result = <<state.als_threshold_high>> |> trim_pad(read_count)
90+
{result, state}
91+
end
92+
93+
def write_read(state, <<@cmd_als_threshold_low>>, read_count) do
94+
result = <<state.als_threshold_low::little-16>> |> trim_pad(read_count)
95+
{result, state}
96+
end
97+
98+
def write_read(state, <<@cmd_als_power_saving>>, read_count) do
99+
result = <<state.als_power_saving::little-16>> |> trim_pad(read_count)
100+
{result, state}
101+
end
102+
103+
def write_read(state, <<@cmd_als_output>>, read_count) do
104+
result = <<state.als_output::little-16>> |> trim_pad(read_count)
105+
{result, state}
106+
end
107+
108+
def write_read(state, <<@cmd_white_output>>, read_count) do
109+
result = <<state.white_output::little-16>> |> trim_pad(read_count)
110+
{result, state}
111+
end
112+
113+
def write_read(state, <<@cmd_interrupt_status>>, read_count) do
114+
result = <<state.interrupt_status::little-16>> |> trim_pad(read_count)
115+
{result, state}
116+
end
117+
118+
def write_read(state, _to_write, read_count) do
119+
{:binary.copy(<<0>>, read_count), state}
120+
end
121+
122+
defp trim_pad(x, count) when byte_size(x) >= count, do: :binary.part(x, 0, count)
123+
defp trim_pad(x, count), do: x <> :binary.copy(<<0>>, count - byte_size(x))
124+
125+
@impl I2CDevice
126+
def render(state) do
127+
light_lux = Float.round(state.light_lux * 1.0, 3)
128+
"Light: #{light_lux} lux"
129+
end
130+
131+
@impl I2CDevice
132+
@spec handle_message(struct, {:set_state, keyword}) :: {:ok, struct}
133+
def handle_message(state, {:set_state, kv}) do
134+
{:ok, struct!(state, kv)}
135+
end
136+
end
137+
end
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
defmodule CircuitsSim.Device.VEML7700Test do
2+
use ExUnit.Case
3+
4+
alias CircuitsSim.I2C.I2CServer
5+
alias CircuitsSim.Device.VEML7700, as: VEML7700Sim
6+
7+
@i2c_address 0x48
8+
@cmd_config 0x00
9+
@cmd_light 0x04
10+
11+
setup context do
12+
i2c_bus = to_string(context.test)
13+
start_supervised!({VEML7700Sim, bus_name: i2c_bus, address: @i2c_address})
14+
15+
[i2c_bus: i2c_bus]
16+
end
17+
18+
test "reads and writes registers", %{i2c_bus: i2c_bus} do
19+
VEML7700Sim.set_state(i2c_bus, @i2c_address, als_config: 0, als_output: 440)
20+
21+
# read ambient light sensor settings
22+
assert {:ok, <<0, 0>>} = I2CServer.write_read(i2c_bus, @i2c_address, <<@cmd_config>>, 2)
23+
24+
# write ambient light sensor settings
25+
config = 0b0001100000000000
26+
assert :ok = I2CServer.write(i2c_bus, @i2c_address, <<@cmd_config, config::little-16>>)
27+
28+
# read ambient light sensor settings
29+
assert {:ok, <<0, 24>>} = I2CServer.write_read(i2c_bus, @i2c_address, <<@cmd_config>>, 2)
30+
31+
# read ambient light sensor output data
32+
assert {:ok, <<440::little-16>>} =
33+
I2CServer.write_read(i2c_bus, @i2c_address, <<@cmd_light>>, 2)
34+
end
35+
end

0 commit comments

Comments
 (0)