From 3f379d04e76f72eefa817aa314a171e74065d267 Mon Sep 17 00:00:00 2001 From: ZodiusInfuser Date: Thu, 6 May 2021 09:48:17 +0100 Subject: [PATCH] C++ and MP support and example for LTR559 breakout (#135) * C driver and example for LTR559 breakout * Micropython bindings and example for LTR559 --- drivers/CMakeLists.txt | 1 + drivers/ltr559/CMakeLists.txt | 1 + drivers/ltr559/ltr559.cmake | 10 + drivers/ltr559/ltr559.cpp | 289 ++++++++++++++ drivers/ltr559/ltr559.hpp | 199 ++++++++++ examples/CMakeLists.txt | 1 + examples/breakout_ltr559/CMakeLists.txt | 16 + examples/breakout_ltr559/demo.cpp | 26 ++ libraries/CMakeLists.txt | 1 + libraries/breakout_ltr559/CMakeLists.txt | 1 + .../breakout_ltr559/breakout_ltr559.cmake | 11 + libraries/breakout_ltr559/breakout_ltr559.cpp | 5 + libraries/breakout_ltr559/breakout_ltr559.hpp | 8 + micropython/examples/breakout_ltr559/demo.py | 14 + .../modules/breakout_ltr559/breakout_ltr559.c | 77 ++++ .../breakout_ltr559/breakout_ltr559.cpp | 357 ++++++++++++++++++ .../modules/breakout_ltr559/breakout_ltr559.h | 34 ++ .../modules/breakout_ltr559/micropython.cmake | 20 + .../modules/breakout_ltr559/micropython.mk | 13 + micropython/modules/micropython.cmake | 1 + 20 files changed, 1085 insertions(+) create mode 100644 drivers/ltr559/CMakeLists.txt create mode 100644 drivers/ltr559/ltr559.cmake create mode 100644 drivers/ltr559/ltr559.cpp create mode 100644 drivers/ltr559/ltr559.hpp create mode 100644 examples/breakout_ltr559/CMakeLists.txt create mode 100644 examples/breakout_ltr559/demo.cpp create mode 100644 libraries/breakout_ltr559/CMakeLists.txt create mode 100644 libraries/breakout_ltr559/breakout_ltr559.cmake create mode 100644 libraries/breakout_ltr559/breakout_ltr559.cpp create mode 100644 libraries/breakout_ltr559/breakout_ltr559.hpp create mode 100644 micropython/examples/breakout_ltr559/demo.py create mode 100644 micropython/modules/breakout_ltr559/breakout_ltr559.c create mode 100644 micropython/modules/breakout_ltr559/breakout_ltr559.cpp create mode 100644 micropython/modules/breakout_ltr559/breakout_ltr559.h create mode 100644 micropython/modules/breakout_ltr559/micropython.cmake create mode 100755 micropython/modules/breakout_ltr559/micropython.mk diff --git a/drivers/CMakeLists.txt b/drivers/CMakeLists.txt index 0f1b0573..c5d753d3 100644 --- a/drivers/CMakeLists.txt +++ b/drivers/CMakeLists.txt @@ -1,5 +1,6 @@ add_subdirectory(esp32spi) add_subdirectory(ltp305) +add_subdirectory(ltr559) add_subdirectory(st7789) add_subdirectory(msa301) add_subdirectory(rv3028) diff --git a/drivers/ltr559/CMakeLists.txt b/drivers/ltr559/CMakeLists.txt new file mode 100644 index 00000000..ef82bf3a --- /dev/null +++ b/drivers/ltr559/CMakeLists.txt @@ -0,0 +1 @@ +include(ltr559.cmake) \ No newline at end of file diff --git a/drivers/ltr559/ltr559.cmake b/drivers/ltr559/ltr559.cmake new file mode 100644 index 00000000..0debe482 --- /dev/null +++ b/drivers/ltr559/ltr559.cmake @@ -0,0 +1,10 @@ +set(DRIVER_NAME ltr559) +add_library(${DRIVER_NAME} INTERFACE) + +target_sources(${DRIVER_NAME} INTERFACE + ${CMAKE_CURRENT_LIST_DIR}/${DRIVER_NAME}.cpp) + +target_include_directories(${DRIVER_NAME} INTERFACE ${CMAKE_CURRENT_LIST_DIR}) + +# Pull in pico libraries that we need +target_link_libraries(${DRIVER_NAME} INTERFACE pico_stdlib hardware_i2c) diff --git a/drivers/ltr559/ltr559.cpp b/drivers/ltr559/ltr559.cpp new file mode 100644 index 00000000..04779e59 --- /dev/null +++ b/drivers/ltr559/ltr559.cpp @@ -0,0 +1,289 @@ +#include "ltr559.hpp" +#include + +namespace pimoroni { + lookup::lookup(std::initializer_list values) : lut(values) { + } + + uint8_t lookup::index(uint16_t value) { + auto it = find(lut.begin(), lut.end(), value); + + if(it == lut.end()) + return 0; + + return it - lut.begin(); + } + + uint16_t lookup::value(uint8_t index) { + return lut[index]; + } + + pimoroni::lookup LTR559::lookup_led_current({5, 10, 20, 50, 100}); + pimoroni::lookup LTR559::lookup_led_duty_cycle({25, 50, 75, 100}); + pimoroni::lookup LTR559::lookup_led_pulse_freq({30, 40, 50, 60, 70, 80, 90, 100}); + pimoroni::lookup LTR559::lookup_proximity_meas_rate({10, 50, 70, 100, 200, 500, 1000, 2000}); + pimoroni::lookup LTR559::lookup_light_integration_time({100, 50, 200, 400, 150, 250, 300, 350}); + pimoroni::lookup LTR559::lookup_light_repeat_rate({50, 100, 200, 500, 1000, 2000}); + pimoroni::lookup LTR559::lookup_light_gain({1, 2, 4, 8, 0, 0, 48, 96}); + + bool LTR559::init() { + i2c_init(i2c, 400000); + + gpio_set_function(sda, GPIO_FUNC_I2C); gpio_pull_up(sda); + gpio_set_function(scl, GPIO_FUNC_I2C); gpio_pull_up(scl); + + if(interrupt != PIN_UNUSED) { + gpio_set_function(interrupt, GPIO_FUNC_SIO); + gpio_set_dir(interrupt, GPIO_IN); + gpio_pull_up(interrupt); + } + + reset(); + interrupts(true, true); + + // 50mA, 1.0 duty cycle, 30Hz, 1 pulse + proximity_led(50, 1.0, 30, 1); + + // enabled, gain 4x + light_control(true, 4); + + // enabled, saturation indicator enabled + proximity_control(true, true); + + // 100ms measurement rate + proximity_measurement_rate(100); + + // 50ms integration time and repeat rate + light_measurement_rate(50, 50); + + light_threshold(0xFFFF, 0x0000); + proximity_threshold(0x7FFF, 0x7FFF); + proximity_offset(0); + + return true; + } + + void LTR559::reset() { + set_bits(LTR559_ALS_CONTROL, LTR559_ALS_CONTROL_SW_RESET_BIT); + + while(get_bits(LTR559_ALS_CONTROL, LTR559_ALS_CONTROL_SW_RESET_BIT)) { + sleep_ms(100); + } + } + + i2c_inst_t* LTR559::get_i2c() const { + return i2c; + } + + int LTR559::get_sda() const { + return sda; + } + + int LTR559::get_scl() const { + return scl; + } + + int LTR559::get_int() const { + return interrupt; + } + + + uint8_t LTR559::part_id() { + uint8_t part_id; + read_bytes(LTR559_PART_ID, &part_id, 1); + return (part_id >> LTR559_PART_ID_PART_NUMBER_SHIFT) & LTR559_PART_ID_PART_NUMBER_MASK; + } + + uint8_t LTR559::revision_id() { + uint8_t revision_id; + read_bytes(LTR559_PART_ID, &revision_id, 1); + return revision_id & LTR559_PART_ID_REVISION_MASK; + } + + uint8_t LTR559::manufacturer_id() { + uint8_t manufacturer; + read_bytes(LTR559_MANUFACTURER_ID, &manufacturer, 1); + return manufacturer; + } + + bool LTR559::get_reading() { + bool has_updated = false; + uint8_t status; + this->read_bytes(LTR559_ALS_PS_STATUS, &status, 1); + bool als_int = (status >> LTR559_ALS_PS_STATUS_ALS_INTERRUPT_BIT) & 0b1; + bool ps_int = (status >> LTR559_ALS_PS_STATUS_PS_INTERRUPT_BIT) & 0b1; + bool als_data = (status >> LTR559_ALS_PS_STATUS_ALS_DATA_BIT) & 0b1; + bool ps_data = (status >> LTR559_ALS_PS_STATUS_PS_DATA_BIT) & 0b1; + + if(ps_int || ps_data) { + has_updated = true; + uint16_t ps0; + read_bytes(LTR559_PS_DATA, (uint8_t *)&ps0, 2); + ps0 &= LTR559_PS_DATA_MASK; + + data.proximity = ps0; + } + + if(als_int || als_data) { + has_updated = true; + uint16_t als[2]; + read_bytes(LTR559_ALS_DATA_CH1, (uint8_t *)&als, 4); + data.als0 = als[1]; + data.als1 = als[0]; + data.gain = this->lookup_light_gain.value((status >> LTR559_ALS_PS_STATUS_ALS_GAIN_SHIFT) & LTR559_ALS_PS_STATUS_ALS_GAIN_MASK); + + data.ratio = 101.0f; + + if((uint32_t)data.als0 + data.als1 > 0) { + data.ratio = (float)data.als1 * 100.0f / ((float)data.als1 + data.als0); + } + + uint8_t ch_idx = 3; + if(this->data.ratio < 45) + ch_idx = 0; + else if(data.ratio < 64) + ch_idx = 1; + else if (data.ratio < 85) + ch_idx = 2; + + float lux = ((int32_t)data.als0 * ch0_c[ch_idx]) - ((int32_t)data.als1 * ch1_c[ch_idx]); + lux /= (float)this->data.integration_time / 100.0f; + lux /= (float)this->data.gain; + data.lux = (uint16_t)(lux / 10000.0f); + } + + return has_updated; + } + + void LTR559::interrupts(bool light, bool proximity) { + uint8_t buf = 0; + buf |= 0b1 << LTR559_INTERRUPT_POLARITY_BIT; + buf |= (uint8_t)light << LTR559_INTERRUPT_ALS_BIT; + buf |= (uint8_t)proximity << LTR559_INTERRUPT_PS_BIT; + write_bytes(LTR559_INTERRUPT, &buf, 1); + } + + void LTR559::proximity_led(uint8_t current, uint8_t duty_cycle, uint8_t pulse_freq, uint8_t num_pulses) { + current = lookup_led_current.index(current); + + duty_cycle = lookup_led_duty_cycle.index(duty_cycle); + duty_cycle <<= LTR559_PS_LED_DUTY_CYCLE_SHIFT; + + pulse_freq = lookup_led_pulse_freq.index(pulse_freq); + pulse_freq <<= LTR559_PS_LED_PULSE_FREQ_SHIFT; + + uint8_t buf = current | duty_cycle | pulse_freq; + write_bytes(LTR559_PS_LED, &buf, 1); + + buf = num_pulses & LTR559_PS_N_PULSES_MASK; + write_bytes(LTR559_PS_N_PULSES, &buf, 1); + } + + void LTR559::light_control(bool active, uint8_t gain) { + uint8_t buf = 0; + gain = lookup_light_gain.index(gain); + buf |= gain << LTR559_ALS_CONTROL_GAIN_SHIFT; + + if(active) + buf |= (0b1 << LTR559_ALS_CONTROL_MODE_BIT); + else + buf &= ~(0b1 << LTR559_ALS_CONTROL_MODE_BIT); + + write_bytes(LTR559_ALS_CONTROL, &buf, 1); + } + + void LTR559::proximity_control(bool active, bool saturation_indicator) { + uint8_t buf = 0; + read_bytes(LTR559_PS_CONTROL, &buf, 1); + if(active) + buf |= LTR559_PS_CONTROL_ACTIVE_MASK; + else + buf &= ~LTR559_PS_CONTROL_ACTIVE_MASK; + + if(saturation_indicator) + buf |= 0b1 << LTR559_PS_CONTROL_SATURATION_INDICATOR_ENABLE_BIT; + else + buf &= ~(0b1 << LTR559_PS_CONTROL_SATURATION_INDICATOR_ENABLE_BIT); + + write_bytes(LTR559_PS_CONTROL, &buf, 1); + } + + void LTR559::light_threshold(uint16_t lower, uint16_t upper) { + lower = __builtin_bswap16(lower); + upper = __builtin_bswap16(upper); + write_bytes(LTR559_ALS_THRESHOLD_LOWER, (uint8_t *)&lower, 2); + write_bytes(LTR559_ALS_THRESHOLD_UPPER, (uint8_t *)&upper, 2); + } + + void LTR559::proximity_threshold(uint16_t lower, uint16_t upper) { + lower = uint16_to_bit12(lower); + upper = uint16_to_bit12(upper); + write_bytes(LTR559_PS_THRESHOLD_LOWER, (uint8_t *)&lower, 2); + write_bytes(LTR559_PS_THRESHOLD_UPPER, (uint8_t *)&upper, 2); + } + + void LTR559::light_measurement_rate(uint16_t integration_time, uint16_t rate) { + data.integration_time = integration_time; + integration_time = lookup_light_integration_time.index(integration_time); + rate = lookup_light_repeat_rate.index(rate); + uint8_t buf = 0; + buf |= rate; + buf |= integration_time << LTR559_ALS_MEAS_RATE_INTEGRATION_TIME_SHIFT; + write_bytes(LTR559_ALS_MEAS_RATE, &buf, 1); + } + + void LTR559::proximity_measurement_rate(uint16_t rate) { + uint8_t buf = lookup_proximity_meas_rate.index(rate); + write_bytes(LTR559_PS_MEAS_RATE, &buf, 1); + } + + void LTR559::proximity_offset(uint16_t offset) { + offset &= LTR559_PS_OFFSET_MASK; + write_bytes(LTR559_PS_OFFSET, (uint8_t *)&offset, 1); + } + + uint16_t LTR559::bit12_to_uint16(uint16_t value) { + return ((value & 0xFF00) >> 8) | ((value & 0x000F) << 8); + } + + uint16_t LTR559::uint16_to_bit12(uint16_t value) { + return ((value & 0xFF) << 8) | ((value & 0xF00) >> 8); + } + + // i2c functions + + int LTR559::write_bytes(uint8_t reg, uint8_t *buf, int len) { + uint8_t buffer[len + 1]; + buffer[0] = reg; + for(int x = 0; x < len; x++) { + buffer[x + 1] = buf[x]; + } + return i2c_write_blocking(i2c, address, buffer, len + 1, false); + }; + + int LTR559::read_bytes(uint8_t reg, uint8_t *buf, int len) { + i2c_write_blocking(i2c, address, ®, 1, true); + i2c_read_blocking(i2c, address, buf, len, false); + return len; + }; + + uint8_t LTR559::get_bits(uint8_t reg, uint8_t shift, uint8_t mask) { + uint8_t value; + read_bytes(reg, &value, 1); + return value & (mask << shift); + } + + void LTR559::set_bits(uint8_t reg, uint8_t shift, uint8_t mask) { + uint8_t value; + read_bytes(reg, &value, 1); + value |= mask << shift; + write_bytes(reg, &value, 1); + } + + void LTR559::clear_bits(uint8_t reg, uint8_t shift, uint8_t mask) { + uint8_t value; + read_bytes(reg, &value, 1); + value &= ~(mask << shift); + write_bytes(reg, &value, 1); + } +} \ No newline at end of file diff --git a/drivers/ltr559/ltr559.hpp b/drivers/ltr559/ltr559.hpp new file mode 100644 index 00000000..7f232073 --- /dev/null +++ b/drivers/ltr559/ltr559.hpp @@ -0,0 +1,199 @@ +#pragma once + +#include "hardware/i2c.h" +#include "hardware/gpio.h" +#include +#include + +#define LTR559_ALS_CONTROL 0x80 +#define LTR559_ALS_CONTROL_GAIN_MASK 0b111 +#define LTR559_ALS_CONTROL_GAIN_SHIFT 2 +#define LTR559_ALS_CONTROL_SW_RESET_BIT 1 +#define LTR559_ALS_CONTROL_MODE_BIT 0 + +#define LTR559_PS_CONTROL 0x81 +#define LTR559_PS_CONTROL_SATURATION_INDICATOR_ENABLE_BIT 5 +#define LTR559_PS_CONTROL_ACTIVE_MASK 0b11 + +#define LTR559_PS_LED 0x82 +#define LTR559_PS_LED_PULSE_FREQ_MASK 0b111 +#define LTR559_PS_LED_PULSE_FREQ_SHIFT 5 +#define LTR559_PS_LED_DUTY_CYCLE_MASK 0b11 +#define LTR559_PS_LED_DUTY_CYCLE_SHIFT 3 +#define LTR559_PS_LED_CURRENT_MASK 0b111 + +#define LTR559_PS_N_PULSES 0x83 +#define LTR559_PS_N_PULSES_MASK 0b1111 + +#define LTR559_PS_MEAS_RATE 0x84 +#define LTR559_PS_MEAS_RATE_RATE_MS_MASK 0b1111 + +#define LTR559_ALS_MEAS_RATE 0x85 +#define LTR559_ALS_MEAS_RATE_INTEGRATION_TIME_MASK 0b111 +#define LTR559_ALS_MEAS_RATE_INTEGRATION_TIME_SHIFT 3 +#define LTR559_ALS_MEAS_RATE_REPEAT_RATE_MASK 0b111 + +#define LTR559_PART_ID 0x86 +#define LTR559_PART_ID_PART_NUMBER_MASK 0b1111 +#define LTR559_PART_ID_PART_NUMBER_SHIFT 4 +#define LTR559_PART_ID_REVISION_MASK 0b1111 + +#define LTR559_MANUFACTURER_ID 0x87 + +#define LTR559_ALS_DATA 0x88 +#define LTR559_ALS_DATA_CH1 0x88 +#define LTR559_ALS_DATA_CH0 0x8a + +#define LTR559_ALS_PS_STATUS 0x8c +#define LTR559_ALS_PS_STATUS_INTERRUPT_MASK 0b00001010 +#define LTR559_ALS_PS_STATUS_ALS_DATA_VALID_BIT 7 +#define LTR559_ALS_PS_STATUS_ALS_GAIN_MASK 0b111 +#define LTR559_ALS_PS_STATUS_ALS_GAIN_SHIFT 4 +#define LTR559_ALS_PS_STATUS_ALS_INTERRUPT_BIT 3 +#define LTR559_ALS_PS_STATUS_ALS_DATA_BIT 2 +#define LTR559_ALS_PS_STATUS_PS_INTERRUPT_BIT 1 +#define LTR559_ALS_PS_STATUS_PS_DATA_BIT 0 + +#define LTR559_PS_DATA 0x8d +#define LTR559_PS_DATA_MASK 0x07FF + +#define LTR559_PS_DATA_SATURATION 0x8e +#define LTR559_PS_DATA_SATURATION_SHIFT 4 + +#define LTR559_INTERRUPT 0x8f +#define LTR559_INTERRUPT_POLARITY_BIT 2 +#define LTR559_INTERRUPT_ALS_PS_MASK 0b11 +#define LTR559_INTERRUPT_PS_BIT 0 +#define LTR559_INTERRUPT_ALS_BIT 1 + +#define LTR559_PS_THRESHOLD_UPPER 0x90 +#define LTR559_PS_THRESHOLD_LOWER 0x92 + +#define LTR559_PS_OFFSET 0x94 +#define LTR559_PS_OFFSET_MASK 0x03FF + +#define LTR559_ALS_THRESHOLD_UPPER 0x97 +#define LTR559_ALS_THRESHOLD_LOWER 0x99 + +#define LTR559_INTERRUPT_PERSIST 0x9e +#define LTR559_INTERRUPT_PERSIST_PS_MASK 0b1111 +#define LTR559_INTERRUPT_PERSIST_PS_SHIFT 4 +#define LTR559_INTERRUPT_PERSIST_ALS_MASK 0b1111 + +#define LTR559_VALID_PART_ID 0x09 +#define LTR559_VALID_REVISION_ID 0x02 + + +namespace pimoroni { + typedef struct { + uint16_t proximity; + uint16_t als0; + uint16_t als1; + uint16_t integration_time; + uint16_t gain; + float ratio; + uint16_t lux; + } ltr559_reading; + + class lookup { + private: + std::vector lut; + public: + lookup(std::initializer_list values); + uint8_t index(uint16_t value); + uint16_t value(uint8_t index); + }; + + class LTR559 { + //-------------------------------------------------- + // Constants + //-------------------------------------------------- + public: + static const uint8_t DEFAULT_I2C_ADDRESS = 0x23; + static const uint8_t DEFAULT_SDA_PIN = 20; + static const uint8_t DEFAULT_SCL_PIN = 21; + static const uint8_t DEFAULT_INT_PIN = 22; + static const uint8_t PIN_UNUSED = UINT8_MAX; + + private: + const int ch0_c[4] = {17743, 42785, 5926, 0}; + const int ch1_c[4] = {-11059, 19548, -1185, 0}; + + + //-------------------------------------------------- + // Variables + //-------------------------------------------------- + public: + ltr559_reading data; + + private: + i2c_inst_t *i2c = i2c0; + + // interface pins with our standard defaults where appropriate + int8_t address = DEFAULT_I2C_ADDRESS; + int8_t sda = DEFAULT_SDA_PIN; + int8_t scl = DEFAULT_SCL_PIN; + int8_t interrupt = DEFAULT_INT_PIN; + + static pimoroni::lookup lookup_led_current; + static pimoroni::lookup lookup_led_duty_cycle; + static pimoroni::lookup lookup_led_pulse_freq; + static pimoroni::lookup lookup_proximity_meas_rate; + static pimoroni::lookup lookup_light_integration_time; + static pimoroni::lookup lookup_light_repeat_rate; + static pimoroni::lookup lookup_light_gain; + + + //-------------------------------------------------- + // Constructors/Destructor + //-------------------------------------------------- + public: + LTR559() {} + + LTR559(uint8_t address) : + address(address) {} + + LTR559(i2c_inst_t *i2c, uint8_t address, uint8_t sda, uint8_t scl, uint8_t interrupt = PIN_UNUSED) : + i2c(i2c), address(address), sda(sda), scl(scl), interrupt(interrupt) {} + + + //-------------------------------------------------- + // Methods + //-------------------------------------------------- + public: + bool init(); + void reset(); + + i2c_inst_t* get_i2c() const; + int get_sda() const; + int get_scl() const; + int get_int() const; + + uint8_t part_id(); + uint8_t revision_id(); + uint8_t manufacturer_id(); + + bool get_reading(); + void interrupts(bool light, bool proximity); + void proximity_led(uint8_t current, uint8_t duty_cycle, uint8_t pulse_freq, uint8_t num_pulses); + void light_control(bool active, uint8_t gain); + void proximity_control(bool active, bool saturation_indicator); + void light_threshold(uint16_t lower, uint16_t upper); + void proximity_threshold(uint16_t lower, uint16_t upper); + void light_measurement_rate(uint16_t integration_time, uint16_t rate); + void proximity_measurement_rate(uint16_t rate); + void proximity_offset(uint16_t offset); + + private: + uint16_t bit12_to_uint16(uint16_t value); + uint16_t uint16_to_bit12(uint16_t value); + + // From i2cdevice + int write_bytes(uint8_t reg, uint8_t *buf, int len); + int read_bytes(uint8_t reg, uint8_t *buf, int len); + uint8_t get_bits(uint8_t reg, uint8_t shift, uint8_t mask=0b1); + void set_bits(uint8_t reg, uint8_t shift, uint8_t mask=0b1); + void clear_bits(uint8_t reg, uint8_t shift, uint8_t mask=0b1); + }; + +} \ No newline at end of file diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index aa7f2580..c7fdf442 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -1,4 +1,5 @@ add_subdirectory(breakout_dotmatrix) +add_subdirectory(breakout_ltr559) add_subdirectory(breakout_roundlcd) add_subdirectory(breakout_rgbmatrix5x5) add_subdirectory(breakout_matrix11x7) diff --git a/examples/breakout_ltr559/CMakeLists.txt b/examples/breakout_ltr559/CMakeLists.txt new file mode 100644 index 00000000..97656ca3 --- /dev/null +++ b/examples/breakout_ltr559/CMakeLists.txt @@ -0,0 +1,16 @@ +set(OUTPUT_NAME ltr559_demo) + +add_executable( + ${OUTPUT_NAME} + demo.cpp +) + +# enable usb output, disable uart output +pico_enable_stdio_usb(${OUTPUT_NAME} 1) +pico_enable_stdio_uart(${OUTPUT_NAME} 0) + +# Pull in pico libraries that we need +target_link_libraries(${OUTPUT_NAME} pico_stdlib breakout_ltr559) + +# create map/bin/hex file etc. +pico_add_extra_outputs(${OUTPUT_NAME}) diff --git a/examples/breakout_ltr559/demo.cpp b/examples/breakout_ltr559/demo.cpp new file mode 100644 index 00000000..5eeb9e8a --- /dev/null +++ b/examples/breakout_ltr559/demo.cpp @@ -0,0 +1,26 @@ +#include +#include "pico/stdlib.h" + +#include "breakout_ltr559.hpp" + +using namespace pimoroni; + +BreakoutLTR559 ltr559; + +int main() { + stdio_init_all(); + + ltr559.init(); + + uint8_t part_id = ltr559.part_id(); + printf("Found LTR559. Part ID: 0x%02x\n", part_id); + + while(true){ + bool new_data = ltr559.get_reading(); + if(new_data) { + printf("Lux: %d Prox: %d\n", ltr559.data.lux, ltr559.data.proximity); + } + sleep_ms(100); + }; + return 0; +} diff --git a/libraries/CMakeLists.txt b/libraries/CMakeLists.txt index 1b342892..b0aef6c9 100644 --- a/libraries/CMakeLists.txt +++ b/libraries/CMakeLists.txt @@ -1,4 +1,5 @@ add_subdirectory(breakout_dotmatrix) +add_subdirectory(breakout_ltr559) add_subdirectory(breakout_roundlcd) add_subdirectory(breakout_rgbmatrix5x5) add_subdirectory(breakout_matrix11x7) diff --git a/libraries/breakout_ltr559/CMakeLists.txt b/libraries/breakout_ltr559/CMakeLists.txt new file mode 100644 index 00000000..8c723e06 --- /dev/null +++ b/libraries/breakout_ltr559/CMakeLists.txt @@ -0,0 +1 @@ +include(breakout_ltr559.cmake) diff --git a/libraries/breakout_ltr559/breakout_ltr559.cmake b/libraries/breakout_ltr559/breakout_ltr559.cmake new file mode 100644 index 00000000..b21335f9 --- /dev/null +++ b/libraries/breakout_ltr559/breakout_ltr559.cmake @@ -0,0 +1,11 @@ +set(LIB_NAME breakout_ltr559) +add_library(${LIB_NAME} INTERFACE) + +target_sources(${LIB_NAME} INTERFACE + ${CMAKE_CURRENT_LIST_DIR}/${LIB_NAME}.cpp +) + +target_include_directories(${LIB_NAME} INTERFACE ${CMAKE_CURRENT_LIST_DIR}) + +# Pull in pico libraries that we need +target_link_libraries(${LIB_NAME} INTERFACE pico_stdlib ltr559) diff --git a/libraries/breakout_ltr559/breakout_ltr559.cpp b/libraries/breakout_ltr559/breakout_ltr559.cpp new file mode 100644 index 00000000..005284fc --- /dev/null +++ b/libraries/breakout_ltr559/breakout_ltr559.cpp @@ -0,0 +1,5 @@ +#include "breakout_ltr559.hpp" + +namespace pimoroni { + +} diff --git a/libraries/breakout_ltr559/breakout_ltr559.hpp b/libraries/breakout_ltr559/breakout_ltr559.hpp new file mode 100644 index 00000000..e50f792e --- /dev/null +++ b/libraries/breakout_ltr559/breakout_ltr559.hpp @@ -0,0 +1,8 @@ +#pragma once + +#include "../../drivers/ltr559/ltr559.hpp" + +namespace pimoroni { + + typedef LTR559 BreakoutLTR559; +} diff --git a/micropython/examples/breakout_ltr559/demo.py b/micropython/examples/breakout_ltr559/demo.py new file mode 100644 index 00000000..7f79f67d --- /dev/null +++ b/micropython/examples/breakout_ltr559/demo.py @@ -0,0 +1,14 @@ +import time +from breakout_ltr559 import BreakoutLTR559 + +ltr = BreakoutLTR559() + +part_id = ltr.part_id() +print("Found LTR559. Part ID: 0x", '{:02x}'.format(part_id), sep="") + +while True: + reading = ltr.get_reading() + if reading is not None: + print("Lux:", reading[BreakoutLTR559.LUX], "Prox:", reading[BreakoutLTR559.PROXIMITY]) + + time.sleep(0.1) diff --git a/micropython/modules/breakout_ltr559/breakout_ltr559.c b/micropython/modules/breakout_ltr559/breakout_ltr559.c new file mode 100644 index 00000000..352e17d0 --- /dev/null +++ b/micropython/modules/breakout_ltr559/breakout_ltr559.c @@ -0,0 +1,77 @@ +#include "breakout_ltr559.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// BreakoutLTR559 Class +//////////////////////////////////////////////////////////////////////////////////////////////////// + +/***** Methods *****/ +MP_DEFINE_CONST_FUN_OBJ_1(BreakoutLTR559_part_id_obj, BreakoutLTR559_part_id); +MP_DEFINE_CONST_FUN_OBJ_1(BreakoutLTR559_revision_id_obj, BreakoutLTR559_revision_id); +MP_DEFINE_CONST_FUN_OBJ_1(BreakoutLTR559_manufacturer_id_obj, BreakoutLTR559_manufacturer_id); +MP_DEFINE_CONST_FUN_OBJ_1(BreakoutLTR559_get_reading_obj, BreakoutLTR559_get_reading); +MP_DEFINE_CONST_FUN_OBJ_KW(BreakoutLTR559_interrupts_obj, 3, BreakoutLTR559_interrupts); +MP_DEFINE_CONST_FUN_OBJ_KW(BreakoutLTR559_proximity_led_obj, 5, BreakoutLTR559_proximity_led); +MP_DEFINE_CONST_FUN_OBJ_KW(BreakoutLTR559_light_control_obj, 3, BreakoutLTR559_light_control); +MP_DEFINE_CONST_FUN_OBJ_KW(BreakoutLTR559_proximity_control_obj, 3, BreakoutLTR559_proximity_control); +MP_DEFINE_CONST_FUN_OBJ_KW(BreakoutLTR559_light_threshold_obj, 3, BreakoutLTR559_light_threshold); +MP_DEFINE_CONST_FUN_OBJ_KW(BreakoutLTR559_proximity_threshold_obj, 3, BreakoutLTR559_proximity_threshold); +MP_DEFINE_CONST_FUN_OBJ_KW(BreakoutLTR559_light_measurement_rate_obj, 3, BreakoutLTR559_light_measurement_rate); +MP_DEFINE_CONST_FUN_OBJ_KW(BreakoutLTR559_proximity_measurement_rate_obj, 2, BreakoutLTR559_proximity_measurement_rate); +MP_DEFINE_CONST_FUN_OBJ_KW(BreakoutLTR559_proximity_offset_obj, 2, BreakoutLTR559_proximity_offset); + +/***** Binding of Methods *****/ +STATIC const mp_rom_map_elem_t BreakoutLTR559_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_part_id), MP_ROM_PTR(&BreakoutLTR559_part_id_obj) }, + { MP_ROM_QSTR(MP_QSTR_revision_id), MP_ROM_PTR(&BreakoutLTR559_revision_id_obj) }, + { MP_ROM_QSTR(MP_QSTR_manufacturer_id), MP_ROM_PTR(&BreakoutLTR559_manufacturer_id_obj) }, + { MP_ROM_QSTR(MP_QSTR_get_reading), MP_ROM_PTR(&BreakoutLTR559_get_reading_obj) }, + { MP_ROM_QSTR(MP_QSTR_interrupts), MP_ROM_PTR(&BreakoutLTR559_interrupts_obj) }, + { MP_ROM_QSTR(MP_QSTR_proximity_led), MP_ROM_PTR(&BreakoutLTR559_proximity_led_obj) }, + { MP_ROM_QSTR(MP_QSTR_light_control), MP_ROM_PTR(&BreakoutLTR559_light_control_obj) }, + { MP_ROM_QSTR(MP_QSTR_proximity_control), MP_ROM_PTR(&BreakoutLTR559_proximity_control_obj) }, + { MP_ROM_QSTR(MP_QSTR_light_threshold), MP_ROM_PTR(&BreakoutLTR559_light_threshold_obj) }, + { MP_ROM_QSTR(MP_QSTR_proximity_threshold), MP_ROM_PTR(&BreakoutLTR559_proximity_threshold_obj) }, + { MP_ROM_QSTR(MP_QSTR_light_measurement_rate), MP_ROM_PTR(&BreakoutLTR559_light_measurement_rate_obj) }, + { MP_ROM_QSTR(MP_QSTR_proximity_measurement_rate), MP_ROM_PTR(&BreakoutLTR559_proximity_measurement_rate_obj) }, + { MP_ROM_QSTR(MP_QSTR_proximity_offset), MP_ROM_PTR(&BreakoutLTR559_proximity_offset_obj) }, + { MP_ROM_QSTR(MP_QSTR_PROXIMITY), MP_ROM_INT(PROXIMITY) }, + { MP_ROM_QSTR(MP_QSTR_ALS_0), MP_ROM_INT(ALS_0) }, + { MP_ROM_QSTR(MP_QSTR_ALS_1), MP_ROM_INT(ALS_1) }, + { MP_ROM_QSTR(MP_QSTR_INTEGRATION_TIME), MP_ROM_INT(INTEGRATION_TIME) }, + { MP_ROM_QSTR(MP_QSTR_GAIN), MP_ROM_INT(GAIN) }, + { MP_ROM_QSTR(MP_QSTR_RATIO), MP_ROM_INT(RATIO) }, + { MP_ROM_QSTR(MP_QSTR_LUX), MP_ROM_INT(LUX) }, +}; +STATIC MP_DEFINE_CONST_DICT(BreakoutLTR559_locals_dict, BreakoutLTR559_locals_dict_table); + +/***** Class Definition *****/ +const mp_obj_type_t breakout_ltr559_BreakoutLTR559_type = { + { &mp_type_type }, + .name = MP_QSTR_breakout_ltr559, + .print = BreakoutLTR559_print, + .make_new = BreakoutLTR559_make_new, + .locals_dict = (mp_obj_dict_t*)&BreakoutLTR559_locals_dict, +}; + + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// breakout_ltr559 Module +//////////////////////////////////////////////////////////////////////////////////////////////////// + +/***** Globals Table *****/ +STATIC const mp_map_elem_t breakout_ltr559_globals_table[] = { + { MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_breakout_ltr559) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_BreakoutLTR559), (mp_obj_t)&breakout_ltr559_BreakoutLTR559_type }, +}; +STATIC MP_DEFINE_CONST_DICT(mp_module_breakout_ltr559_globals, breakout_ltr559_globals_table); + +/***** Module Definition *****/ +const mp_obj_module_t breakout_ltr559_user_cmodule = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&mp_module_breakout_ltr559_globals, +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////// +MP_REGISTER_MODULE(MP_QSTR_breakout_ltr559, breakout_ltr559_user_cmodule, MODULE_BREAKOUT_LTR559_ENABLED); +//////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////// \ No newline at end of file diff --git a/micropython/modules/breakout_ltr559/breakout_ltr559.cpp b/micropython/modules/breakout_ltr559/breakout_ltr559.cpp new file mode 100644 index 00000000..0001c2cb --- /dev/null +++ b/micropython/modules/breakout_ltr559/breakout_ltr559.cpp @@ -0,0 +1,357 @@ +#include "../../../libraries/breakout_ltr559/breakout_ltr559.hpp" + +#define MP_OBJ_TO_PTR2(o, t) ((t *)(uintptr_t)(o)) + +// SDA/SCL on even/odd pins, I2C0/I2C1 on even/odd pairs of pins. +#define IS_VALID_SCL(i2c, pin) (((pin) & 1) == 1 && (((pin) & 2) >> 1) == (i2c)) +#define IS_VALID_SDA(i2c, pin) (((pin) & 1) == 0 && (((pin) & 2) >> 1) == (i2c)) + + +using namespace pimoroni; + +extern "C" { +#include "breakout_ltr559.h" + +/***** Variables Struct *****/ +typedef struct _breakout_ltr559_BreakoutLTR559_obj_t { + mp_obj_base_t base; + BreakoutLTR559 *breakout; +} breakout_ltr559_BreakoutLTR559_obj_t; + +/***** Print *****/ +void BreakoutLTR559_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + (void)kind; //Unused input parameter + breakout_ltr559_BreakoutLTR559_obj_t *self = MP_OBJ_TO_PTR2(self_in, breakout_ltr559_BreakoutLTR559_obj_t); + BreakoutLTR559* breakout = self->breakout; + mp_print_str(print, "BreakoutLTR559("); + + mp_print_str(print, "i2c = "); + mp_obj_print_helper(print, mp_obj_new_int((breakout->get_i2c() == i2c0) ? 0 : 1), PRINT_REPR); + + mp_print_str(print, ", sda = "); + mp_obj_print_helper(print, mp_obj_new_int(breakout->get_sda()), PRINT_REPR); + + mp_print_str(print, ", scl = "); + mp_obj_print_helper(print, mp_obj_new_int(breakout->get_scl()), PRINT_REPR); + + mp_print_str(print, ", int = "); + mp_obj_print_helper(print, mp_obj_new_int(breakout->get_int()), PRINT_REPR); + + mp_print_str(print, ")"); +} + +/***** Constructor *****/ +mp_obj_t BreakoutLTR559_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { + breakout_ltr559_BreakoutLTR559_obj_t *self = nullptr; + + if(n_args == 0) { + mp_arg_check_num(n_args, n_kw, 0, 0, true); + self = m_new_obj(breakout_ltr559_BreakoutLTR559_obj_t); + self->base.type = &breakout_ltr559_BreakoutLTR559_type; + self->breakout = new BreakoutLTR559(); + } + else if(n_args == 1) { + enum { ARG_address }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_address, MP_ARG_REQUIRED | MP_ARG_INT }, + }; + + // Parse args. + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + self = m_new_obj(breakout_ltr559_BreakoutLTR559_obj_t); + self->base.type = &breakout_ltr559_BreakoutLTR559_type; + + self->breakout = new BreakoutLTR559(args[ARG_address].u_int); + } + else { + enum { ARG_i2c, ARG_address, ARG_sda, ARG_scl, ARG_interrupt }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_i2c, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_address, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_sda, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_scl, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_interrupt, MP_ARG_INT, {.u_int = BreakoutLTR559::PIN_UNUSED} }, + }; + + // Parse args. + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + // Get I2C bus. + int i2c_id = args[ARG_i2c].u_int; + if(i2c_id < 0 || i2c_id > 1) { + mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("I2C(%d) doesn't exist"), i2c_id); + } + + int sda = args[ARG_sda].u_int; + if (!IS_VALID_SDA(i2c_id, sda)) { + mp_raise_ValueError(MP_ERROR_TEXT("bad SDA pin")); + } + + int scl = args[ARG_scl].u_int; + if (!IS_VALID_SCL(i2c_id, scl)) { + mp_raise_ValueError(MP_ERROR_TEXT("bad SCL pin")); + } + + self = m_new_obj(breakout_ltr559_BreakoutLTR559_obj_t); + self->base.type = &breakout_ltr559_BreakoutLTR559_type; + + i2c_inst_t *i2c = (i2c_id == 0) ? i2c0 : i2c1; + self->breakout = new BreakoutLTR559(i2c, args[ARG_address].u_int, sda, scl, args[ARG_interrupt].u_int); + } + + self->breakout->init(); + + return MP_OBJ_FROM_PTR(self); +} + +mp_obj_t BreakoutLTR559_part_id(mp_obj_t self_in) { + breakout_ltr559_BreakoutLTR559_obj_t *self = MP_OBJ_TO_PTR2(self_in, breakout_ltr559_BreakoutLTR559_obj_t); + return mp_obj_new_int(self->breakout->part_id()); +} + +mp_obj_t BreakoutLTR559_revision_id(mp_obj_t self_in) { + breakout_ltr559_BreakoutLTR559_obj_t *self = MP_OBJ_TO_PTR2(self_in, breakout_ltr559_BreakoutLTR559_obj_t); + return mp_obj_new_int(self->breakout->revision_id()); +} + +mp_obj_t BreakoutLTR559_manufacturer_id(mp_obj_t self_in) { + breakout_ltr559_BreakoutLTR559_obj_t *self = MP_OBJ_TO_PTR2(self_in, breakout_ltr559_BreakoutLTR559_obj_t); + return mp_obj_new_int(self->breakout->manufacturer_id()); +} + +mp_obj_t BreakoutLTR559_get_reading(mp_obj_t self_in) { + breakout_ltr559_BreakoutLTR559_obj_t *self = MP_OBJ_TO_PTR2(self_in, breakout_ltr559_BreakoutLTR559_obj_t); + if(self->breakout->get_reading()) { + const ltr559_reading& data = self->breakout->data; + + mp_obj_t tuple[7]; + tuple[PROXIMITY] = mp_obj_new_int(data.proximity); + tuple[ALS_0] = mp_obj_new_int(data.als0); + tuple[ALS_1] = mp_obj_new_int(data.als1); + tuple[INTEGRATION_TIME] = mp_obj_new_int(data.integration_time); + tuple[GAIN] = mp_obj_new_int(data.gain); + tuple[RATIO] = mp_obj_new_float(data.ratio); + tuple[LUX] = mp_obj_new_int(data.lux); + + return mp_obj_new_tuple(7, tuple); + } + + return mp_const_none; +} + +mp_obj_t BreakoutLTR559_interrupts(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_self, ARG_light, ARG_proximity }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_light, MP_ARG_REQUIRED | MP_ARG_BOOL }, + { MP_QSTR_proximity, MP_ARG_REQUIRED | MP_ARG_BOOL }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + breakout_ltr559_BreakoutLTR559_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, breakout_ltr559_BreakoutLTR559_obj_t); + self->breakout->interrupts(args[ARG_light].u_bool, args[ARG_proximity].u_bool); + + return mp_const_none; +} + +mp_obj_t BreakoutLTR559_proximity_led(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_self, ARG_current, ARG_duty_cycle, ARG_pulse_freq, ARG_num_pulses }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_current, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_duty_cycle, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_pulse_freq, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_num_pulses, MP_ARG_REQUIRED | MP_ARG_INT }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + breakout_ltr559_BreakoutLTR559_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, breakout_ltr559_BreakoutLTR559_obj_t); + + int current = args[ARG_current].u_int; + int duty_cycle = args[ARG_duty_cycle].u_int; + int pulse_freq = args[ARG_pulse_freq].u_int; + int num_pulses = args[ARG_num_pulses].u_int; + + if(current < 0 || current > 255) + mp_raise_ValueError("current out of range. Expected 0 to 255"); + else if(duty_cycle < 0 || duty_cycle > 255) + mp_raise_ValueError("duty_cycle out of range. Expected 0 to 255"); + else if(pulse_freq < 0 || pulse_freq > 255) + mp_raise_ValueError("pulse_freq out of range. Expected 0 to 255"); + else if(num_pulses < 0 || num_pulses > 255) + mp_raise_ValueError("num_pulses out of range. Expected 0 to 255"); + else + self->breakout->proximity_led(current, duty_cycle, pulse_freq, num_pulses); + + return mp_const_none; +} + +mp_obj_t BreakoutLTR559_light_control(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_self, ARG_active, ARG_gain }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_active, MP_ARG_REQUIRED | MP_ARG_BOOL }, + { MP_QSTR_gain, MP_ARG_REQUIRED | MP_ARG_INT }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + breakout_ltr559_BreakoutLTR559_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, breakout_ltr559_BreakoutLTR559_obj_t); + + int gain = args[ARG_gain].u_int; + + if(gain < 0 || gain > 255) + mp_raise_ValueError("gain out of range. Expected 0 to 255"); + else + self->breakout->light_control(args[ARG_active].u_bool, gain); + + return mp_const_none; +} + +mp_obj_t BreakoutLTR559_proximity_control(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_self, ARG_active, ARG_saturation_indicator }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_active, MP_ARG_REQUIRED | MP_ARG_BOOL }, + { MP_QSTR_saturation_indicator, MP_ARG_REQUIRED | MP_ARG_BOOL }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + breakout_ltr559_BreakoutLTR559_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, breakout_ltr559_BreakoutLTR559_obj_t); + self->breakout->proximity_control(args[ARG_active].u_bool, args[ARG_saturation_indicator].u_bool); + + return mp_const_none; +} + +mp_obj_t BreakoutLTR559_light_threshold(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_self, ARG_lower, ARG_upper }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_lower, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_upper, MP_ARG_REQUIRED | MP_ARG_INT }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + breakout_ltr559_BreakoutLTR559_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, breakout_ltr559_BreakoutLTR559_obj_t); + + int lower = args[ARG_lower].u_int; + int upper = args[ARG_upper].u_int; + + if(lower < 0 || lower > 65535) + mp_raise_ValueError("lower out of range. Expected 0 to 65535"); + else if(upper < 0 || upper > 65535) + mp_raise_ValueError("upper out of range. Expected 0 to 65535"); + else + self->breakout->light_threshold(lower, upper); + + return mp_const_none; +} + +mp_obj_t BreakoutLTR559_proximity_threshold(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_self, ARG_lower, ARG_upper }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_lower, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_upper, MP_ARG_REQUIRED | MP_ARG_INT }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + breakout_ltr559_BreakoutLTR559_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, breakout_ltr559_BreakoutLTR559_obj_t); + + int lower = args[ARG_lower].u_int; + int upper = args[ARG_upper].u_int; + + if(lower < 0 || lower > 65535) + mp_raise_ValueError("lower out of range. Expected 0 to 65535"); + else if(upper < 0 || upper > 65535) + mp_raise_ValueError("upper out of range. Expected 0 to 65535"); + else + self->breakout->proximity_threshold(lower, upper); + + return mp_const_none; +} + +mp_obj_t BreakoutLTR559_light_measurement_rate(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_self, ARG_integration_time, ARG_rate }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_integration_time, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_rate, MP_ARG_REQUIRED | MP_ARG_INT }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + breakout_ltr559_BreakoutLTR559_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, breakout_ltr559_BreakoutLTR559_obj_t); + + int integration_time = args[ARG_integration_time].u_int; + int rate = args[ARG_rate].u_int; + + if(integration_time < 0 || integration_time > 65535) + mp_raise_ValueError("integration_time out of range. Expected 0 to 65535"); + else if(rate < 0 || rate > 65535) + mp_raise_ValueError("rate out of range. Expected 0 to 65535"); + else + self->breakout->light_measurement_rate(integration_time, rate); + + return mp_const_none; +} + +mp_obj_t BreakoutLTR559_proximity_measurement_rate(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_self, ARG_rate }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_rate, MP_ARG_REQUIRED | MP_ARG_INT }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + breakout_ltr559_BreakoutLTR559_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, breakout_ltr559_BreakoutLTR559_obj_t); + + int rate = args[ARG_rate].u_int; + + if(rate < 0 || rate > 65535) + mp_raise_ValueError("rate out of range. Expected 0 to 65535"); + else + self->breakout->proximity_measurement_rate(rate); + + return mp_const_none; +} + +mp_obj_t BreakoutLTR559_proximity_offset(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_self, ARG_offset }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_offset, MP_ARG_REQUIRED | MP_ARG_INT }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + breakout_ltr559_BreakoutLTR559_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, breakout_ltr559_BreakoutLTR559_obj_t); + + int offset = args[ARG_offset].u_int; + + if(offset < 0 || offset > 65535) + mp_raise_ValueError("offset out of range. Expected 0 to 65535"); + else + self->breakout->proximity_offset(offset); + + return mp_const_none; +} +} \ No newline at end of file diff --git a/micropython/modules/breakout_ltr559/breakout_ltr559.h b/micropython/modules/breakout_ltr559/breakout_ltr559.h new file mode 100644 index 00000000..456254f3 --- /dev/null +++ b/micropython/modules/breakout_ltr559/breakout_ltr559.h @@ -0,0 +1,34 @@ +// Include MicroPython API. +#include "py/runtime.h" +#include "py/objstr.h" + +/***** Constants *****/ +enum { + PROXIMITY = 0, + ALS_0, + ALS_1, + INTEGRATION_TIME, + GAIN, + RATIO, + LUX +}; + +/***** Extern of Class Definition *****/ +extern const mp_obj_type_t breakout_ltr559_BreakoutLTR559_type; + +/***** Extern of Class Methods *****/ +extern void BreakoutLTR559_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind); +extern mp_obj_t BreakoutLTR559_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args); +extern mp_obj_t BreakoutLTR559_part_id(mp_obj_t self_in); +extern mp_obj_t BreakoutLTR559_revision_id(mp_obj_t self_in); +extern mp_obj_t BreakoutLTR559_manufacturer_id(mp_obj_t self_in); +extern mp_obj_t BreakoutLTR559_get_reading(mp_obj_t self_in); +extern mp_obj_t BreakoutLTR559_interrupts(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); +extern mp_obj_t BreakoutLTR559_proximity_led(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); +extern mp_obj_t BreakoutLTR559_light_control(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); +extern mp_obj_t BreakoutLTR559_proximity_control(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); +extern mp_obj_t BreakoutLTR559_light_threshold(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); +extern mp_obj_t BreakoutLTR559_proximity_threshold(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); +extern mp_obj_t BreakoutLTR559_light_measurement_rate(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); +extern mp_obj_t BreakoutLTR559_proximity_measurement_rate(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); +extern mp_obj_t BreakoutLTR559_proximity_offset(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); \ No newline at end of file diff --git a/micropython/modules/breakout_ltr559/micropython.cmake b/micropython/modules/breakout_ltr559/micropython.cmake new file mode 100644 index 00000000..12465d3a --- /dev/null +++ b/micropython/modules/breakout_ltr559/micropython.cmake @@ -0,0 +1,20 @@ +set(MOD_NAME breakout_ltr559) +string(TOUPPER ${MOD_NAME} MOD_NAME_UPPER) +add_library(usermod_${MOD_NAME} INTERFACE) + +target_sources(usermod_${MOD_NAME} INTERFACE + ${CMAKE_CURRENT_LIST_DIR}/${MOD_NAME}.c + ${CMAKE_CURRENT_LIST_DIR}/${MOD_NAME}.cpp + ${CMAKE_CURRENT_LIST_DIR}/../../../libraries/${MOD_NAME}/${MOD_NAME}.cpp + ${CMAKE_CURRENT_LIST_DIR}/../../../drivers/ltr559/ltr559.cpp +) + +target_include_directories(usermod_${MOD_NAME} INTERFACE + ${CMAKE_CURRENT_LIST_DIR} +) + +target_compile_definitions(usermod_${MOD_NAME} INTERFACE + -DMODULE_${MOD_NAME_UPPER}_ENABLED=1 +) + +target_link_libraries(usermod INTERFACE usermod_${MOD_NAME}) \ No newline at end of file diff --git a/micropython/modules/breakout_ltr559/micropython.mk b/micropython/modules/breakout_ltr559/micropython.mk new file mode 100755 index 00000000..1ef65a12 --- /dev/null +++ b/micropython/modules/breakout_ltr559/micropython.mk @@ -0,0 +1,13 @@ +set(MOD_NAME breakout_ltr559) +BREAKOUT_MOD_DIR := $(USERMOD_DIR) + +# Add our source files to the respective variables. +SRC_USERMOD += $(BREAKOUT_MOD_DIR)/${MOD_NAME}.c +SRC_USERMOD_CXX += $(BREAKOUT_MOD_DIR)/${MOD_NAME}.cpp + +# Add our module directory to the include path. +CFLAGS_USERMOD += -I$(BREAKOUT_MOD_DIR) +CXXFLAGS_USERMOD += -I$(BREAKOUT_MOD_DIR) + +# We use C++ features so have to link against the standard library. +LDFLAGS_USERMOD += -lstdc++ \ No newline at end of file diff --git a/micropython/modules/micropython.cmake b/micropython/modules/micropython.cmake index d1426537..072448b0 100644 --- a/micropython/modules/micropython.cmake +++ b/micropython/modules/micropython.cmake @@ -1,4 +1,5 @@ include(${CMAKE_CURRENT_LIST_DIR}/breakout_dotmatrix/micropython.cmake) +include(${CMAKE_CURRENT_LIST_DIR}/breakout_ltr559/micropython.cmake) include(${CMAKE_CURRENT_LIST_DIR}/breakout_roundlcd/micropython.cmake) include(${CMAKE_CURRENT_LIST_DIR}/breakout_rgbmatrix5x5/micropython.cmake) include(${CMAKE_CURRENT_LIST_DIR}/breakout_matrix11x7/micropython.cmake)