blob: a60188fc7db259e6f7a21bfeeccd52ee2a373d36 [file] [log] [blame]
// Copyright 2024 The Pigweed Authors
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not
// use this file except in compliance with the License. You may obtain a copy of
// the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations under
// the License.
#define PW_LOG_MODULE_NAME "LTR559"
#define PW_LOG_LEVEL PW_LOG_LEVEL_INFO
#include "device/ltr559_light_and_prox_sensor.h"
#include "pw_log/log.h"
namespace sense {
namespace {
// Constants from the manufacturer used to convert the ambient light sensor's
// two ADC channels to lux values.
constexpr int kChannel0Constants[] = {17743, 42785, 5926, 0};
constexpr int kChannel1Constants[] = {-11059, 19548, -1185, 0};
} // namespace
Ltr559LightAndProxSensor::Ltr559LightAndProxSensor(
pw::i2c::Initiator& i2c_initiator,
pw::chrono::SystemClock::duration timeout)
: i2c_initiator_(i2c_initiator),
device_(i2c_initiator_,
pw::i2c::Address::SevenBit<0x23>(),
pw::endian::little,
pw::endian::little,
pw::i2c::RegisterAddressSize::k1Byte),
timeout_(timeout) {}
pw::Result<uint16_t> Ltr559LightAndProxSensor::ReadProximitySample() {
// 11-bit samples in PS_DATA_0 (0x8D) and PS_DATA_1 (0x8E), little-endian.
static constexpr uint8_t kPsData0 = 0x8D;
PW_TRY_ASSIGN(uint16_t sample, device_.ReadRegister16(kPsData0, timeout_));
return sample & 0x3FFu; // mask to the 11-bit sample
}
pw::Result<float> Ltr559LightAndProxSensor::ReadLightSampleLux() {
uint16_t channels_1_0_samples[2] = {};
const auto& [channel_1, channel_0] = channels_1_0_samples;
PW_TRY(device_.ReadRegisters16(
kAlsDataCh1Address, channels_1_0_samples, timeout_));
// Calculate the lux from the two channels based on a formula from the
// manufacturer.
const int ratio = (channel_1 + channel_0 == 0)
? 101
: (channel_1 * 100 / (channel_1 + channel_0));
const int index = ratio < 45 ? 0 : ratio < 64 ? 1 : ratio < 85 ? 2 : 3;
float lux = channel_0 * kChannel0Constants[index] -
channel_1 * kChannel1Constants[index];
lux /= (kDefaultIntegrationTimeMillis / 100);
lux /= kDefaultGain;
lux /= 10000;
return lux;
}
pw::Result<Ltr559LightAndProxSensor::Info> Ltr559LightAndProxSensor::ReadIds() {
uint8_t ids[2];
PW_TRY(device_.ReadRegisters8(kPartIdAddress, ids, timeout_));
return Info{.part_id = ids[0], .manufacturer_id = ids[1]};
}
pw::Result<uint16_t> Ltr559ProxAndLightSensorImpl::DoReadProxSample() {
// Readings are 11-bit unsigned integers. Scale them to 16 bits.
PW_TRY_ASSIGN(uint16_t raw_sample, sensor_.ReadProximitySample());
PW_LOG_DEBUG("LTR-559 sample: %4hu (0x%4hx), scaled: %5u",
raw_sample,
raw_sample,
(raw_sample << 5));
return raw_sample << 5;
}
} // namespace sense