Explorar o código

Support MAX44009 i2c sensor (#47)

* Support MAX44009 i2c sensor

* Fix conversion factor

---------

Co-authored-by: wosk <nikita.vostokov@auriga.com>
Co-authored-by: Oleksii Kutuzov <oleksii.kutuzov@icloud.com>
Nikita Vostokov %!s(int64=2) %!d(string=hai) anos
pai
achega
5de076ea39

+ 1 - 1
README.md

@@ -1,6 +1,6 @@
 ## Lightmeter for Flipper Zero
 ## Lightmeter for Flipper Zero
 
 
-Lightmeter app for photography based on BH1750 sensor
+Lightmeter app for photography based on BH1750/MAX44009 sensor
 
 
 ## Support
 ## Support
 
 

+ 8 - 1
application.fam

@@ -20,8 +20,15 @@ App(
                 "BH1750.c",
                 "BH1750.c",
             ],
             ],
         ),
         ),
+        Lib(
+            name="MAX44009",
+            cincludes=["."],
+            sources=[
+                "MAX44009.c",
+            ],
+        ),
     ],
     ],
-    fap_description="Lightmeter app for photography based on BH1750 sensor",
+    fap_description="Lightmeter app for photography based on BH1750/MAX44009 sensor",
     fap_author="Oleksii Kutuzov",
     fap_author="Oleksii Kutuzov",
     fap_weburl="https://github.com/oleksiikutuzov/flipperzero-lightmeter",
     fap_weburl="https://github.com/oleksiikutuzov/flipperzero-lightmeter",
     fap_icon_assets="icons",
     fap_icon_assets="icons",

+ 22 - 0
gui/scenes/lightmeter_scene_config.c

@@ -51,12 +51,18 @@ static const char* lux_only[] = {
     [LUX_ONLY_ON] = "On",
     [LUX_ONLY_ON] = "On",
 };
 };
 
 
+static const char* sensor_type[] = {
+    [SENSOR_BH1750] = "BH1750",
+    [SENSOR_MAX44009] = "MAX44009",
+};
+
 enum LightMeterSubmenuIndex {
 enum LightMeterSubmenuIndex {
     LightMeterSubmenuIndexISO,
     LightMeterSubmenuIndexISO,
     LightMeterSubmenuIndexND,
     LightMeterSubmenuIndexND,
     LightMeterSubmenuIndexDome,
     LightMeterSubmenuIndexDome,
     LightMeterSubmenuIndexBacklight,
     LightMeterSubmenuIndexBacklight,
     LightMeterSubmenuIndexLuxMeter,
     LightMeterSubmenuIndexLuxMeter,
+    LightMeterSubmenuIndexSensorType,
     LightMeterSubmenuIndexHelp,
     LightMeterSubmenuIndexHelp,
     LightMeterSubmenuIndexAbout,
     LightMeterSubmenuIndexAbout,
 };
 };
@@ -127,6 +133,17 @@ static void lux_only_cb(VariableItem* item) {
     lightmeter_app_set_config(app, config);
     lightmeter_app_set_config(app, config);
 }
 }
 
 
+static void sensor_type_cb(VariableItem* item) {
+    LightMeterApp* app = variable_item_get_context(item);
+    uint8_t index = variable_item_get_current_value_index(item);
+
+    variable_item_set_current_value_text(item, sensor_type[index]);
+
+    LightMeterConfig* config = app->config;
+    config->sensor_type = index;
+    lightmeter_app_set_config(app, config);
+}
+
 static void ok_cb(void* context, uint32_t index) {
 static void ok_cb(void* context, uint32_t index) {
     LightMeterApp* app = context;
     LightMeterApp* app = context;
     UNUSED(app);
     UNUSED(app);
@@ -173,6 +190,11 @@ void lightmeter_scene_config_on_enter(void* context) {
     variable_item_set_current_value_index(item, config->lux_only);
     variable_item_set_current_value_index(item, config->lux_only);
     variable_item_set_current_value_text(item, lux_only[config->lux_only]);
     variable_item_set_current_value_text(item, lux_only[config->lux_only]);
 
 
+    item = variable_item_list_add(
+        var_item_list, "Sensor", COUNT_OF(sensor_type), sensor_type_cb, app);
+    variable_item_set_current_value_index(item, config->sensor_type);
+    variable_item_set_current_value_text(item, sensor_type[config->sensor_type]);
+
     item = variable_item_list_add(var_item_list, "Help and Pinout", 0, NULL, NULL);
     item = variable_item_list_add(var_item_list, "Help and Pinout", 0, NULL, NULL);
     item = variable_item_list_add(var_item_list, "About", 0, NULL, NULL);
     item = variable_item_list_add(var_item_list, "About", 0, NULL, NULL);
 
 

+ 2 - 1
gui/scenes/lightmeter_scene_help.c

@@ -6,7 +6,8 @@ void lightmeter_scene_help_on_enter(void* context) {
     FuriString* temp_str;
     FuriString* temp_str;
     temp_str = furi_string_alloc();
     temp_str = furi_string_alloc();
     furi_string_printf(
     furi_string_printf(
-        temp_str, "App works with BH1750\nambient light sensor\nconnected via I2C interface\n\n");
+        temp_str,
+        "App works with BH1750 and MAX44409 ambient light sensor connected via I2C interface\n\n");
     furi_string_cat(temp_str, "\e#Pinout:\r\n");
     furi_string_cat(temp_str, "\e#Pinout:\r\n");
     furi_string_cat(
     furi_string_cat(
         temp_str,
         temp_str,

+ 2 - 1
gui/scenes/lightmeter_scene_main.c

@@ -9,6 +9,7 @@ static void lightmeter_scene_main_on_left(void* context) {
 void lightmeter_scene_main_on_enter(void* context) {
 void lightmeter_scene_main_on_enter(void* context) {
     LightMeterApp* app = context;
     LightMeterApp* app = context;
 
 
+    lightmeter_app_i2c_init_sensor(context);
     lightmeter_main_view_set_left_callback(app->main_view, lightmeter_scene_main_on_left, app);
     lightmeter_main_view_set_left_callback(app->main_view, lightmeter_scene_main_on_left, app);
     view_dispatcher_switch_to_view(app->view_dispatcher, LightMeterAppViewMainView);
     view_dispatcher_switch_to_view(app->view_dispatcher, LightMeterAppViewMainView);
 }
 }
@@ -39,5 +40,5 @@ bool lightmeter_scene_main_on_event(void* context, SceneManagerEvent event) {
 }
 }
 
 
 void lightmeter_scene_main_on_exit(void* context) {
 void lightmeter_scene_main_on_exit(void* context) {
-    UNUSED(context);
+    lightmeter_app_i2c_deinit_sensor(context);
 }
 }

+ 27 - 0
lib/MAX44009/MAX44009.c

@@ -0,0 +1,27 @@
+#include <MAX44009.h>
+#include <math.h>
+#include <furi.h>
+
+void max44009_init() {
+    furi_hal_i2c_acquire(I2C_BUS);
+    furi_hal_i2c_write_reg_8(I2C_BUS, MAX44009_ADDR,
+        MAX44009_REG_CONFIG, MAX44009_REG_CONFIG_CONT_MODE, I2C_TIMEOUT);
+    furi_hal_i2c_release(I2C_BUS);
+}
+
+int max44009_read_light(float* result) {
+    uint8_t data_one = 0;
+    uint8_t exp, mantissa;
+    int status;
+
+    furi_hal_i2c_acquire(I2C_BUS);
+    furi_hal_i2c_read_reg_8(I2C_BUS, MAX44009_ADDR, MAX44009_REG_LUX_HI, &data_one, I2C_TIMEOUT);
+    exp = (data_one & MAX44009_REG_LUX_HI_EXP_MASK) >> 4;
+    mantissa = (data_one & MAX44009_REG_LUX_HI_MANT_HI_MASK) << 4;
+    status = furi_hal_i2c_read_reg_8(I2C_BUS, MAX44009_ADDR, MAX44009_REG_LUX_LO, &data_one, I2C_TIMEOUT);
+    mantissa |= (data_one & MAX44009_REG_LUX_LO_MANT_LO_MASK);
+    furi_hal_i2c_release(I2C_BUS);
+    *result = (float)pow(2, exp) * mantissa * 0.045;
+    FURI_LOG_D("MAX44009", "exp %d, mant %d, lux %f", exp, mantissa, (double)*result);
+    return status;
+}

+ 26 - 0
lib/MAX44009/MAX44009.h

@@ -0,0 +1,26 @@
+#include <furi.h>
+#include <furi_hal.h>
+
+#pragma once
+
+// I2C BUS
+#define I2C_BUS &furi_hal_i2c_handle_external
+#define I2C_TIMEOUT 10
+
+#define MAX44009_ADDR (0x4A << 1)
+
+#define MAX44009_REG_INT_STATUS 0x00
+#define MAX44009_REG_INT_EN 0x01
+#define MAX44009_REG_CONFIG 0x02
+#define MAX44009_REG_CONFIG_CONT_MODE (1 << 7)
+#define MAX44009_REG_LUX_HI 0x03
+#define MAX44009_REG_LUX_HI_EXP_MASK 0xF0
+#define MAX44009_REG_LUX_HI_MANT_HI_MASK 0x0F
+#define MAX44009_REG_LUX_LO 0x04
+#define MAX44009_REG_LUX_LO_MANT_LO_MASK 0x0F
+#define MAX44009_REG_THRESH_HI 0x05
+#define MAX44009_REG_THRESH_LO 0x06
+#define MAX44009_REG_INT_TIME 0x07
+
+void max44009_init();
+int max44009_read_light(float* result);

+ 42 - 15
lightmeter.c

@@ -27,11 +27,6 @@ static void lightmeter_tick_event_callback(void* context) {
 LightMeterApp* lightmeter_app_alloc(uint32_t first_scene) {
 LightMeterApp* lightmeter_app_alloc(uint32_t first_scene) {
     LightMeterApp* app = malloc(sizeof(LightMeterApp));
     LightMeterApp* app = malloc(sizeof(LightMeterApp));
 
 
-    // Sensor
-    bh1750_set_power_state(1);
-    bh1750_init();
-    bh1750_set_mode(ONETIME_HIGH_RES_MODE);
-
     // Set default values to config
     // Set default values to config
     app->config = malloc(sizeof(LightMeterConfig));
     app->config = malloc(sizeof(LightMeterConfig));
     app->config->iso = DEFAULT_ISO;
     app->config->iso = DEFAULT_ISO;
@@ -117,8 +112,6 @@ void lightmeter_app_free(LightMeterApp* app) {
     }
     }
     furi_record_close(RECORD_NOTIFICATION);
     furi_record_close(RECORD_NOTIFICATION);
 
 
-    bh1750_set_power_state(0);
-
     free(app->config);
     free(app->config);
     free(app);
     free(app);
 }
 }
@@ -138,6 +131,38 @@ void lightmeter_app_set_config(LightMeterApp* context, LightMeterConfig* config)
     app->config = config;
     app->config = config;
 }
 }
 
 
+void lightmeter_app_i2c_init_sensor(LightMeterApp* context) {
+    LightMeterApp* app = context;
+    switch(app->config->sensor_type) {
+    case SENSOR_BH1750:
+        bh1750_set_power_state(1);
+        bh1750_init();
+        bh1750_set_mode(ONETIME_HIGH_RES_MODE);
+        break;
+    case SENSOR_MAX44009:
+        max44009_init();
+        break;
+    default:
+        FURI_LOG_E(TAG, "Invalid sensor type %d", app->config->sensor_type);
+        return;
+    }
+}
+
+void lightmeter_app_i2c_deinit_sensor(LightMeterApp* context) {
+    LightMeterApp* app = context;
+    switch(app->config->sensor_type) {
+    case SENSOR_BH1750:
+        bh1750_set_power_state(0);
+        break;
+    case SENSOR_MAX44009:
+        // nothing
+        break;
+    default:
+        FURI_LOG_E(TAG, "Invalid sensor type %d", app->config->sensor_type);
+        return;
+    }
+}
+
 void lightmeter_app_i2c_callback(LightMeterApp* context) {
 void lightmeter_app_i2c_callback(LightMeterApp* context) {
     LightMeterApp* app = context;
     LightMeterApp* app = context;
 
 
@@ -145,16 +170,18 @@ void lightmeter_app_i2c_callback(LightMeterApp* context) {
     float lux = 0;
     float lux = 0;
     bool response = 0;
     bool response = 0;
 
 
-    if(bh1750_trigger_manual_conversion() == BH1750_OK) response = 1;
-
-    if(response) {
-        bh1750_read_light(&lux);
-
-        if(main_view_get_dome(app->main_view)) lux *= DOME_COEFFICIENT;
-
-        EV = lux2ev(lux);
+    if(app->config->sensor_type == SENSOR_BH1750) {
+        if(bh1750_trigger_manual_conversion() == BH1750_OK) {
+            bh1750_read_light(&lux);
+            response = 1;
+        }
+    } else if(app->config->sensor_type == SENSOR_MAX44009) {
+        if(max44009_read_light(&lux)) response = 1;
     }
     }
 
 
+    if(main_view_get_dome(app->main_view)) lux *= DOME_COEFFICIENT;
+    EV = lux2ev(lux);
+
     main_view_set_lux(app->main_view, lux);
     main_view_set_lux(app->main_view, lux);
     main_view_set_EV(app->main_view, EV);
     main_view_set_EV(app->main_view, EV);
     main_view_set_response(app->main_view, response);
     main_view_set_response(app->main_view, response);

+ 4 - 0
lightmeter.h

@@ -18,6 +18,7 @@
 
 
 #include "lightmeter_config.h"
 #include "lightmeter_config.h"
 #include <BH1750.h>
 #include <BH1750.h>
+#include <MAX44009.h>
 
 
 typedef struct {
 typedef struct {
     int iso;
     int iso;
@@ -26,6 +27,7 @@ typedef struct {
     int dome;
     int dome;
     int backlight;
     int backlight;
     int lux_only;
     int lux_only;
+    int sensor_type;
 } LightMeterConfig;
 } LightMeterConfig;
 
 
 typedef struct {
 typedef struct {
@@ -55,4 +57,6 @@ typedef enum {
 
 
 void lightmeter_app_set_config(LightMeterApp* context, LightMeterConfig* config);
 void lightmeter_app_set_config(LightMeterApp* context, LightMeterConfig* config);
 
 
+void lightmeter_app_i2c_init_sensor(LightMeterApp* context);
+void lightmeter_app_i2c_deinit_sensor(LightMeterApp* context);
 void lightmeter_app_i2c_callback(LightMeterApp* context);
 void lightmeter_app_i2c_callback(LightMeterApp* context);

+ 5 - 0
lightmeter_config.h

@@ -105,4 +105,9 @@ typedef enum {
     LUX_ONLY_ON,
     LUX_ONLY_ON,
 } LightMeterLuxOnlyMode;
 } LightMeterLuxOnlyMode;
 
 
+typedef enum {
+    SENSOR_BH1750,
+    SENSOR_MAX44009,
+} LightMeterSensorType;
+
 typedef enum { BACKLIGHT_AUTO, BACKLIGHT_ON } LightMeterBacklight;
 typedef enum { BACKLIGHT_AUTO, BACKLIGHT_ON } LightMeterBacklight;