mirror of
https://github.com/DarkFlippers/unleashed-firmware.git
synced 2025-12-13 05:06:30 +04:00
Update LightMeter
This commit is contained in:
@@ -6,9 +6,9 @@ App(
|
||||
requires=[
|
||||
"gui",
|
||||
],
|
||||
stack_size=1 * 1024,
|
||||
stack_size= 4 * 1024,
|
||||
order=90,
|
||||
fap_version=(1, 1),
|
||||
fap_version=(1, 2),
|
||||
fap_icon="lightmeter.png",
|
||||
fap_category="GPIO",
|
||||
fap_private_libs=[
|
||||
|
||||
17
applications/external/lightmeter/docs/README.md
vendored
Normal file
17
applications/external/lightmeter/docs/README.md
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
## Lightmeter app for photography
|
||||
|
||||
An application that suggests settings for your manual camera based on the reading of the ambient light sensor. Can also be used in a pure lux meter mode.
|
||||
|
||||
## Supported sensors
|
||||
|
||||
- BH1750
|
||||
- MAX44009
|
||||
|
||||
## Wiring
|
||||
|
||||
| Sensor | Flipper Zero |
|
||||
| ------ | ------------ |
|
||||
| VCC | 3.3V |
|
||||
| GND | GND |
|
||||
| SCL | C0 |
|
||||
| SDA | C1 |
|
||||
15
applications/external/lightmeter/docs/changelog.md
vendored
Normal file
15
applications/external/lightmeter/docs/changelog.md
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
## v1.2
|
||||
|
||||
* Lux only screen now has statistics
|
||||
* Settings are now stored on SD card
|
||||
* You can choose the resolution (BH1750 only) and address for sensor
|
||||
|
||||
(thanks to @danielskowronski for contributing to this update)
|
||||
|
||||
## v1.1
|
||||
|
||||
Added support for MAX44009 sensor (thanks to @wosk)
|
||||
|
||||
## v1.0
|
||||
|
||||
Initial release for Flipper Application Catalog
|
||||
@@ -56,6 +56,22 @@ static const char* sensor_type[] = {
|
||||
[SENSOR_MAX44009] = "MAX44009",
|
||||
};
|
||||
|
||||
static const char* measurement_resolution[] = {
|
||||
[LOW_RES] = "Low",
|
||||
[HIGH_RES] = "High",
|
||||
[HIGH_RES2] = "High2",
|
||||
};
|
||||
|
||||
static const char* device_addr_bh1750[] = {
|
||||
[ADDR_LOW] = "0x23",
|
||||
[ADDR_HIGH] = "0x5C",
|
||||
};
|
||||
|
||||
static const char* device_addr_max44009[] = {
|
||||
[ADDR_LOW] = "0x4A",
|
||||
[ADDR_HIGH] = "0x4B",
|
||||
};
|
||||
|
||||
enum LightMeterSubmenuIndex {
|
||||
LightMeterSubmenuIndexISO,
|
||||
LightMeterSubmenuIndexND,
|
||||
@@ -63,6 +79,8 @@ enum LightMeterSubmenuIndex {
|
||||
LightMeterSubmenuIndexBacklight,
|
||||
LightMeterSubmenuIndexLuxMeter,
|
||||
LightMeterSubmenuIndexSensorType,
|
||||
LightMeterSubmenuIndexMeasurementResolution,
|
||||
LightMeterSubmenuIndexI2CAddress,
|
||||
LightMeterSubmenuIndexHelp,
|
||||
LightMeterSubmenuIndexAbout,
|
||||
};
|
||||
@@ -133,6 +151,60 @@ static void lux_only_cb(VariableItem* item) {
|
||||
lightmeter_app_set_config(app, config);
|
||||
}
|
||||
|
||||
static void measurement_resolution_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, measurement_resolution[index]);
|
||||
|
||||
LightMeterConfig* config = app->config;
|
||||
config->measurement_resolution = index;
|
||||
lightmeter_app_set_config(app, config);
|
||||
|
||||
lightmeter_app_i2c_init_sensor(app);
|
||||
}
|
||||
|
||||
static void update_item_addr(LightMeterApp* app) {
|
||||
VariableItem* item = app->var_item_addr;
|
||||
switch(app->config->sensor_type) {
|
||||
case SENSOR_BH1750:
|
||||
variable_item_set_current_value_index(item, app->config->device_addr);
|
||||
variable_item_set_current_value_text(item, device_addr_bh1750[app->config->device_addr]);
|
||||
break;
|
||||
case SENSOR_MAX44009:
|
||||
variable_item_set_current_value_index(item, app->config->device_addr);
|
||||
variable_item_set_current_value_text(item, device_addr_max44009[app->config->device_addr]);
|
||||
break;
|
||||
default:
|
||||
FURI_LOG_E(TAG, "Invalid sensor type %ld", app->config->sensor_type);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void device_addr_cb(VariableItem* item) {
|
||||
LightMeterApp* app = variable_item_get_context(item);
|
||||
uint8_t index = variable_item_get_current_value_index(item);
|
||||
|
||||
switch(app->config->sensor_type) {
|
||||
case SENSOR_BH1750:
|
||||
variable_item_set_current_value_text(item, device_addr_bh1750[index]);
|
||||
break;
|
||||
case SENSOR_MAX44009:
|
||||
variable_item_set_current_value_text(item, device_addr_max44009[index]);
|
||||
break;
|
||||
default:
|
||||
FURI_LOG_E(TAG, "Invalid sensor type %ld", app->config->sensor_type);
|
||||
return;
|
||||
}
|
||||
// variable_item_set_current_value_text(item, device_addr[index]);
|
||||
|
||||
LightMeterConfig* config = app->config;
|
||||
config->device_addr = index;
|
||||
lightmeter_app_set_config(app, config);
|
||||
|
||||
lightmeter_app_i2c_init_sensor(app);
|
||||
}
|
||||
|
||||
static void sensor_type_cb(VariableItem* item) {
|
||||
LightMeterApp* app = variable_item_get_context(item);
|
||||
uint8_t index = variable_item_get_current_value_index(item);
|
||||
@@ -141,6 +213,9 @@ static void sensor_type_cb(VariableItem* item) {
|
||||
|
||||
LightMeterConfig* config = app->config;
|
||||
config->sensor_type = index;
|
||||
|
||||
update_item_addr(app);
|
||||
|
||||
lightmeter_app_set_config(app, config);
|
||||
}
|
||||
|
||||
@@ -195,6 +270,36 @@ void lightmeter_scene_config_on_enter(void* context) {
|
||||
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,
|
||||
"Resolution",
|
||||
COUNT_OF(measurement_resolution),
|
||||
measurement_resolution_cb,
|
||||
app);
|
||||
variable_item_set_current_value_index(item, config->measurement_resolution);
|
||||
variable_item_set_current_value_text(
|
||||
item, measurement_resolution[config->measurement_resolution]);
|
||||
|
||||
switch(config->sensor_type) {
|
||||
case SENSOR_BH1750:
|
||||
item = variable_item_list_add(
|
||||
var_item_list, "I2C address", COUNT_OF(device_addr_bh1750), device_addr_cb, app);
|
||||
variable_item_set_current_value_index(item, config->device_addr);
|
||||
variable_item_set_current_value_text(item, device_addr_bh1750[config->device_addr]);
|
||||
break;
|
||||
case SENSOR_MAX44009:
|
||||
item = variable_item_list_add(
|
||||
var_item_list, "I2C address", COUNT_OF(device_addr_max44009), device_addr_cb, app);
|
||||
variable_item_set_current_value_index(item, config->device_addr);
|
||||
variable_item_set_current_value_text(item, device_addr_max44009[config->device_addr]);
|
||||
break;
|
||||
default:
|
||||
FURI_LOG_E(TAG, "Invalid sensor type %ld", config->sensor_type);
|
||||
return;
|
||||
}
|
||||
app->var_item_addr = item;
|
||||
update_item_addr(app);
|
||||
|
||||
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);
|
||||
|
||||
@@ -235,4 +340,5 @@ void lightmeter_scene_config_on_exit(void* context) {
|
||||
main_view_set_nd(app->main_view, app->config->nd);
|
||||
main_view_set_dome(app->main_view, app->config->dome);
|
||||
main_view_set_lux_only(app->main_view, app->config->lux_only);
|
||||
main_view_set_measurement_resolution(app->main_view, app->config->measurement_resolution);
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ void lightmeter_scene_help_on_enter(void* context) {
|
||||
temp_str = furi_string_alloc();
|
||||
furi_string_printf(
|
||||
temp_str,
|
||||
"App works with BH1750 and MAX44409 ambient light sensor connected via I2C interface\n\n");
|
||||
"App works with BH1750/MAX44009\nambient light sensor\nconnected via I2C interface\n\n");
|
||||
furi_string_cat(temp_str, "\e#Pinout:\r\n");
|
||||
furi_string_cat(
|
||||
temp_str,
|
||||
@@ -15,6 +15,12 @@ void lightmeter_scene_help_on_enter(void* context) {
|
||||
" GND: GND\r\n"
|
||||
" SDA: 15 [C1]\r\n"
|
||||
" SCL: 16 [C0]\r\n");
|
||||
furi_string_cat(temp_str, "\r\n\e#Resolutions:\r\n");
|
||||
furi_string_cat(
|
||||
temp_str,
|
||||
"Low: 4.0lx (16ms, 0-54k)\r\n"
|
||||
"High: 1.0lx (120ms, 0-54k)\r\n"
|
||||
"High2: 0.5lx (120ms, 0-27k)\r\n");
|
||||
|
||||
widget_add_text_scroll_element(app->widget, 0, 0, 128, 64, furi_string_get_cstr(temp_str));
|
||||
furi_string_free(temp_str);
|
||||
|
||||
@@ -6,11 +6,24 @@ static void lightmeter_scene_main_on_left(void* context) {
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, LightMeterAppCustomEventConfig);
|
||||
}
|
||||
|
||||
static void lightmeter_scene_main_on_right(void* context) {
|
||||
LightMeterApp* app = context;
|
||||
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, LightMeterAppCustomEventReset);
|
||||
}
|
||||
|
||||
void lightmeter_scene_main_on_enter(void* context) {
|
||||
LightMeterApp* app = context;
|
||||
|
||||
lightmeter_app_i2c_init_sensor(context);
|
||||
variable_item_list_reset(app->var_item_list);
|
||||
main_view_set_iso(app->main_view, app->config->iso);
|
||||
main_view_set_nd(app->main_view, app->config->nd);
|
||||
main_view_set_dome(app->main_view, app->config->dome);
|
||||
main_view_set_lux_only(app->main_view, app->config->lux_only);
|
||||
main_view_set_measurement_resolution(app->main_view, app->config->measurement_resolution);
|
||||
|
||||
lightmeter_main_view_set_left_callback(app->main_view, lightmeter_scene_main_on_left, app);
|
||||
lightmeter_main_view_set_right_callback(app->main_view, lightmeter_scene_main_on_right, app);
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, LightMeterAppViewMainView);
|
||||
}
|
||||
|
||||
@@ -24,6 +37,9 @@ bool lightmeter_scene_main_on_event(void* context, SceneManagerEvent event) {
|
||||
if(event.event == LightMeterAppCustomEventConfig) {
|
||||
scene_manager_next_scene(app->scene_manager, LightMeterAppSceneConfig);
|
||||
response = true;
|
||||
} else if(event.event == LightMeterAppCustomEventReset) {
|
||||
lightmeter_app_reset_callback(app);
|
||||
response = true;
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -40,5 +56,5 @@ bool lightmeter_scene_main_on_event(void* context, SceneManagerEvent event) {
|
||||
}
|
||||
|
||||
void lightmeter_scene_main_on_exit(void* context) {
|
||||
lightmeter_app_i2c_deinit_sensor(context);
|
||||
UNUSED(context);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#include "main_view.h"
|
||||
#include <math.h>
|
||||
#include <furi.h>
|
||||
#include <furi_hal.h>
|
||||
#include <gui/elements.h>
|
||||
@@ -72,6 +73,7 @@ const float speed_numbers[] = {
|
||||
struct MainView {
|
||||
View* view;
|
||||
LightMeterMainViewButtonCallback cb_left;
|
||||
LightMeterMainViewButtonCallback cb_right;
|
||||
void* cb_context;
|
||||
};
|
||||
|
||||
@@ -90,6 +92,21 @@ void lightmeter_main_view_set_left_callback(
|
||||
true);
|
||||
}
|
||||
|
||||
void lightmeter_main_view_set_right_callback(
|
||||
MainView* lightmeter_main_view,
|
||||
LightMeterMainViewButtonCallback callback,
|
||||
void* context) {
|
||||
with_view_model(
|
||||
lightmeter_main_view->view,
|
||||
MainViewModel * model,
|
||||
{
|
||||
UNUSED(model);
|
||||
lightmeter_main_view->cb_right = callback;
|
||||
lightmeter_main_view->cb_context = context;
|
||||
},
|
||||
true);
|
||||
}
|
||||
|
||||
static void main_view_draw_callback(Canvas* canvas, void* context) {
|
||||
furi_assert(context);
|
||||
MainViewModel* model = context;
|
||||
@@ -125,6 +142,7 @@ static void main_view_draw_callback(Canvas* canvas, void* context) {
|
||||
// draw mode indicator
|
||||
draw_mode_indicator(canvas, model);
|
||||
} else {
|
||||
elements_button_right(canvas, "Reset");
|
||||
draw_lux_only_mode(canvas, model);
|
||||
}
|
||||
}
|
||||
@@ -190,6 +208,11 @@ static bool main_view_input_callback(InputEvent* event, void* context) {
|
||||
main_view->cb_left(main_view->cb_context);
|
||||
}
|
||||
consumed = true;
|
||||
} else if(event->type == InputTypeShort && event->key == InputKeyRight) {
|
||||
if(main_view->cb_right) {
|
||||
main_view->cb_right(main_view->cb_context);
|
||||
}
|
||||
consumed = true;
|
||||
} else if(event->type == InputTypeShort && event->key == InputKeyBack) {
|
||||
} else {
|
||||
main_view_process(main_view, event);
|
||||
@@ -224,7 +247,22 @@ View* main_view_get_view(MainView* main_view) {
|
||||
void main_view_set_lux(MainView* main_view, float val) {
|
||||
furi_assert(main_view);
|
||||
with_view_model(
|
||||
main_view->view, MainViewModel * model, { model->lux = val; }, true);
|
||||
main_view->view,
|
||||
MainViewModel * model,
|
||||
{
|
||||
model->lux = val;
|
||||
model->peakLux = fmax(model->peakLux, val);
|
||||
|
||||
model->luxHistogram[model->luxHistogramIndex++] = val;
|
||||
model->luxHistogramIndex %= LUX_HISTORGRAM_LENGTH;
|
||||
},
|
||||
true);
|
||||
}
|
||||
|
||||
void main_view_reset_lux(MainView* main_view) {
|
||||
furi_assert(main_view);
|
||||
with_view_model(
|
||||
main_view->view, MainViewModel * model, { model->peakLux = 0; }, true);
|
||||
}
|
||||
|
||||
void main_view_set_EV(MainView* main_view, float val) {
|
||||
@@ -275,6 +313,27 @@ void main_view_set_lux_only(MainView* main_view, bool lux_only) {
|
||||
main_view->view, MainViewModel * model, { model->lux_only = lux_only; }, true);
|
||||
}
|
||||
|
||||
void main_view_set_measurement_resolution(MainView* main_view, int measurement_resolution) {
|
||||
furi_assert(main_view);
|
||||
with_view_model(
|
||||
main_view->view,
|
||||
MainViewModel * model,
|
||||
{ model->measurement_resolution = measurement_resolution; },
|
||||
true);
|
||||
}
|
||||
|
||||
void main_view_set_device_addr(MainView* main_view, int device_addr) {
|
||||
furi_assert(main_view);
|
||||
with_view_model(
|
||||
main_view->view, MainViewModel * model, { model->device_addr = device_addr; }, true);
|
||||
}
|
||||
|
||||
void main_view_set_sensor_type(MainView* main_view, int sensor_type) {
|
||||
furi_assert(main_view);
|
||||
with_view_model(
|
||||
main_view->view, MainViewModel * model, { model->sensor_type = sensor_type; }, true);
|
||||
}
|
||||
|
||||
bool main_view_get_dome(MainView* main_view) {
|
||||
furi_assert(main_view);
|
||||
bool val = false;
|
||||
@@ -462,9 +521,28 @@ void draw_lux_only_mode(Canvas* canvas, MainViewModel* context) {
|
||||
|
||||
canvas_set_font(canvas, FontBigNumbers);
|
||||
snprintf(str, sizeof(str), "%.0f", (double)model->lux);
|
||||
canvas_draw_str_aligned(canvas, 80, 32, AlignRight, AlignCenter, str);
|
||||
canvas_draw_str_aligned(canvas, 80, 22, AlignRight, AlignCenter, str);
|
||||
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
canvas_draw_str_aligned(canvas, 85, 39, AlignLeft, AlignBottom, "Lux");
|
||||
canvas_draw_str_aligned(canvas, 85, 29, AlignLeft, AlignBottom, "Lux now");
|
||||
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
snprintf(str, sizeof(str), "%.0f", (double)model->peakLux);
|
||||
canvas_draw_str_aligned(canvas, 80, 39, AlignRight, AlignCenter, str);
|
||||
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
canvas_draw_str_aligned(canvas, 85, 43, AlignLeft, AlignBottom, "Lux peak");
|
||||
|
||||
for(int i = 0; i < LUX_HISTORGRAM_LENGTH; i++) {
|
||||
float lux =
|
||||
model->luxHistogram[(i + model->luxHistogramIndex) % LUX_HISTORGRAM_LENGTH];
|
||||
int barHeight = log10(lux) / log10(LUX_HISTORGRAM_LOGBASE);
|
||||
canvas_draw_line(
|
||||
canvas,
|
||||
LUX_HISTORGRAM_LEFT + i,
|
||||
LUX_HISTORGRAM_BOTTOM,
|
||||
LUX_HISTORGRAM_LEFT + i,
|
||||
LUX_HISTORGRAM_BOTTOM - barHeight);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,18 @@
|
||||
#include "lightmeter_icons.h"
|
||||
#include "../../lightmeter_config.h"
|
||||
|
||||
/* log base 1.4 and 12 pixels cut off
|
||||
makes it show values approx 65-65k
|
||||
with reasonable resolution in 1-10k range
|
||||
on 20px of screen height */
|
||||
#define LUX_HISTORGRAM_LOGBASE 1.4
|
||||
#define LUX_HISTORGRAM_BOTTOM 64 + 12
|
||||
|
||||
/* 40 pixels between 45th and 85th
|
||||
between left and right button labels */
|
||||
#define LUX_HISTORGRAM_LEFT 45
|
||||
#define LUX_HISTORGRAM_LENGTH 40
|
||||
|
||||
typedef struct MainView MainView;
|
||||
|
||||
typedef enum {
|
||||
@@ -17,6 +29,7 @@ typedef struct {
|
||||
uint8_t recv[2];
|
||||
MainViewMode current_mode;
|
||||
float lux;
|
||||
float peakLux;
|
||||
float EV;
|
||||
float aperture_val;
|
||||
float speed_val;
|
||||
@@ -28,6 +41,12 @@ typedef struct {
|
||||
int speed;
|
||||
bool dome;
|
||||
bool lux_only;
|
||||
int measurement_resolution;
|
||||
int device_addr;
|
||||
int sensor_type;
|
||||
|
||||
float luxHistogram[LUX_HISTORGRAM_LENGTH];
|
||||
int luxHistogramIndex;
|
||||
} MainViewModel;
|
||||
|
||||
typedef void (*LightMeterMainViewButtonCallback)(void* context);
|
||||
@@ -37,6 +56,11 @@ void lightmeter_main_view_set_left_callback(
|
||||
LightMeterMainViewButtonCallback callback,
|
||||
void* context);
|
||||
|
||||
void lightmeter_main_view_set_right_callback(
|
||||
MainView* lightmeter_main_view,
|
||||
LightMeterMainViewButtonCallback callback,
|
||||
void* context);
|
||||
|
||||
MainView* main_view_alloc();
|
||||
|
||||
void main_view_free(MainView* main_view);
|
||||
@@ -45,6 +69,8 @@ View* main_view_get_view(MainView* main_view);
|
||||
|
||||
void main_view_set_lux(MainView* main_view, float val);
|
||||
|
||||
void main_view_reset_lux(MainView* main_view);
|
||||
|
||||
void main_view_set_EV(MainView* main_view_, float val);
|
||||
|
||||
void main_view_set_response(MainView* main_view_, bool val);
|
||||
@@ -61,6 +87,12 @@ void main_view_set_dome(MainView* main_view, bool val);
|
||||
|
||||
void main_view_set_lux_only(MainView* main_view, bool val);
|
||||
|
||||
void main_view_set_measurement_resolution(MainView* main_view, int val);
|
||||
|
||||
void main_view_set_device_addr(MainView* main_view, int addr);
|
||||
|
||||
void main_view_set_sensor_type(MainView* main_view, int sensor_type);
|
||||
|
||||
bool main_view_get_dome(MainView* main_view);
|
||||
|
||||
void draw_top_row(Canvas* canvas, MainViewModel* context);
|
||||
|
||||
@@ -2,13 +2,20 @@
|
||||
#include <math.h>
|
||||
#include <furi.h>
|
||||
|
||||
uint8_t max44009_addr = MAX44009_ADDR;
|
||||
|
||||
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_write_reg_8(
|
||||
I2C_BUS, max44009_addr, MAX44009_REG_CONFIG, MAX44009_REG_CONFIG_CONT_MODE, I2C_TIMEOUT);
|
||||
furi_hal_i2c_release(I2C_BUS);
|
||||
}
|
||||
|
||||
void max44009_init_with_addr(uint8_t addr) {
|
||||
max44009_addr = (addr << 1);
|
||||
return max44009_init();
|
||||
}
|
||||
|
||||
int max44009_read_light(float* result) {
|
||||
uint8_t data_one = 0;
|
||||
uint8_t exp, mantissa;
|
||||
@@ -18,10 +25,11 @@ int max44009_read_light(float* result) {
|
||||
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);
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,4 +23,5 @@
|
||||
#define MAX44009_REG_INT_TIME 0x07
|
||||
|
||||
void max44009_init();
|
||||
void max44009_init_with_addr(uint8_t addr);
|
||||
int max44009_read_light(float* result);
|
||||
|
||||
79
applications/external/lightmeter/lightmeter.c
vendored
79
applications/external/lightmeter/lightmeter.c
vendored
@@ -34,11 +34,35 @@ LightMeterApp* lightmeter_app_alloc(uint32_t first_scene) {
|
||||
app->config->aperture = DEFAULT_APERTURE;
|
||||
app->config->dome = DEFAULT_DOME;
|
||||
app->config->backlight = DEFAULT_BACKLIGHT;
|
||||
app->config->measurement_resolution = HIGH_RES;
|
||||
app->config->device_addr = ADDR_LOW;
|
||||
app->config->lux_only = LUX_ONLY_OFF;
|
||||
|
||||
// Records
|
||||
app->gui = furi_record_open(RECORD_GUI);
|
||||
app->storage = furi_record_open(RECORD_STORAGE);
|
||||
app->notifications = furi_record_open(RECORD_NOTIFICATION);
|
||||
|
||||
app->cfg_path = furi_string_alloc();
|
||||
furi_string_printf(app->cfg_path, "%s/%s", APP_PATH_DIR, APP_PATH_CFG);
|
||||
|
||||
FlipperFormat* cfg_fmt = flipper_format_file_alloc(app->storage);
|
||||
if(flipper_format_file_open_existing(cfg_fmt, furi_string_get_cstr(app->cfg_path))) {
|
||||
flipper_format_read_int32(cfg_fmt, "iso", &app->config->iso, 1);
|
||||
flipper_format_read_int32(cfg_fmt, "aperture", &app->config->aperture, 1);
|
||||
flipper_format_read_int32(cfg_fmt, "dome", &app->config->dome, 1);
|
||||
flipper_format_read_int32(cfg_fmt, "backlight", &app->config->backlight, 1);
|
||||
flipper_format_read_int32(
|
||||
cfg_fmt, "measurement_resolution", &app->config->measurement_resolution, 1);
|
||||
flipper_format_read_int32(cfg_fmt, "lux_only", &app->config->lux_only, 1);
|
||||
flipper_format_read_int32(cfg_fmt, "device_addr", &app->config->device_addr, 1);
|
||||
flipper_format_read_int32(cfg_fmt, "sensor_type", &app->config->sensor_type, 1);
|
||||
}
|
||||
flipper_format_free(cfg_fmt);
|
||||
|
||||
// Sensor
|
||||
lightmeter_app_i2c_init_sensor(app);
|
||||
|
||||
// View dispatcher
|
||||
app->view_dispatcher = view_dispatcher_alloc();
|
||||
app->scene_manager = scene_manager_alloc(&lightmeter_scene_handlers, app);
|
||||
@@ -110,8 +134,11 @@ void lightmeter_app_free(LightMeterApp* app) {
|
||||
app->notifications,
|
||||
&sequence_display_backlight_enforce_auto); // set backlight back to auto
|
||||
}
|
||||
furi_record_close(RECORD_STORAGE);
|
||||
furi_record_close(RECORD_NOTIFICATION);
|
||||
|
||||
bh1750_set_power_state(0);
|
||||
|
||||
free(app->config);
|
||||
free(app);
|
||||
}
|
||||
@@ -129,6 +156,24 @@ void lightmeter_app_set_config(LightMeterApp* context, LightMeterConfig* config)
|
||||
LightMeterApp* app = context;
|
||||
|
||||
app->config = config;
|
||||
storage_common_mkdir(app->storage, APP_PATH_DIR);
|
||||
|
||||
FlipperFormat* cfg_fmt = flipper_format_file_alloc(app->storage);
|
||||
if(flipper_format_file_open_always(cfg_fmt, furi_string_get_cstr(app->cfg_path))) {
|
||||
flipper_format_write_header_cstr(cfg_fmt, "lightmeter", 1);
|
||||
|
||||
flipper_format_write_int32(cfg_fmt, "iso", &(app->config->iso), 1);
|
||||
flipper_format_write_int32(cfg_fmt, "nd", &(app->config->nd), 1);
|
||||
flipper_format_write_int32(cfg_fmt, "aperture", &(app->config->aperture), 1);
|
||||
flipper_format_write_int32(cfg_fmt, "dome", &(app->config->dome), 1);
|
||||
flipper_format_write_int32(cfg_fmt, "backlight", &(app->config->backlight), 1);
|
||||
flipper_format_write_int32(
|
||||
cfg_fmt, "measurement_resolution", &(app->config->measurement_resolution), 1);
|
||||
flipper_format_write_int32(cfg_fmt, "lux_only", &(app->config->lux_only), 1);
|
||||
flipper_format_write_int32(cfg_fmt, "device_addr", &(app->config->device_addr), 1);
|
||||
flipper_format_write_int32(cfg_fmt, "sensor_type", &(app->config->sensor_type), 1);
|
||||
}
|
||||
flipper_format_free(cfg_fmt);
|
||||
}
|
||||
|
||||
void lightmeter_app_i2c_init_sensor(LightMeterApp* context) {
|
||||
@@ -136,14 +181,34 @@ void lightmeter_app_i2c_init_sensor(LightMeterApp* context) {
|
||||
switch(app->config->sensor_type) {
|
||||
case SENSOR_BH1750:
|
||||
bh1750_set_power_state(1);
|
||||
bh1750_init();
|
||||
switch(app->config->device_addr) {
|
||||
case ADDR_HIGH:
|
||||
bh1750_init_with_addr(0x5C);
|
||||
break;
|
||||
case ADDR_LOW:
|
||||
bh1750_init_with_addr(0x23);
|
||||
break;
|
||||
default:
|
||||
bh1750_init_with_addr(0x23);
|
||||
break;
|
||||
}
|
||||
bh1750_set_mode(ONETIME_HIGH_RES_MODE);
|
||||
break;
|
||||
case SENSOR_MAX44009:
|
||||
max44009_init();
|
||||
switch(app->config->device_addr) {
|
||||
case ADDR_HIGH:
|
||||
max44009_init_with_addr(0x4B);
|
||||
break;
|
||||
case ADDR_LOW:
|
||||
max44009_init_with_addr(0x4A);
|
||||
break;
|
||||
default:
|
||||
max44009_init_with_addr(0x4A);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
FURI_LOG_E(TAG, "Invalid sensor type %d", app->config->sensor_type);
|
||||
FURI_LOG_E(TAG, "Invalid sensor type %ld", app->config->sensor_type);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -158,7 +223,7 @@ void lightmeter_app_i2c_deinit_sensor(LightMeterApp* context) {
|
||||
// nothing
|
||||
break;
|
||||
default:
|
||||
FURI_LOG_E(TAG, "Invalid sensor type %d", app->config->sensor_type);
|
||||
FURI_LOG_E(TAG, "Invalid sensor type %ld", app->config->sensor_type);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -186,3 +251,9 @@ void lightmeter_app_i2c_callback(LightMeterApp* context) {
|
||||
main_view_set_EV(app->main_view, EV);
|
||||
main_view_set_response(app->main_view, response);
|
||||
}
|
||||
|
||||
void lightmeter_app_reset_callback(LightMeterApp* context) {
|
||||
LightMeterApp* app = context;
|
||||
|
||||
main_view_reset_lux(app->main_view);
|
||||
}
|
||||
|
||||
31
applications/external/lightmeter/lightmeter.h
vendored
31
applications/external/lightmeter/lightmeter.h
vendored
@@ -3,6 +3,9 @@
|
||||
#include <furi.h>
|
||||
#include <furi_hal.h>
|
||||
|
||||
#include <stream/stream.h>
|
||||
#include <flipper_format/flipper_format_i.h>
|
||||
|
||||
#include <gui/gui.h>
|
||||
#include <gui/view.h>
|
||||
#include <gui/view_dispatcher.h>
|
||||
@@ -20,14 +23,19 @@
|
||||
#include <BH1750.h>
|
||||
#include <MAX44009.h>
|
||||
|
||||
#define APP_PATH_DIR STORAGE_APP_DATA_PATH_PREFIX
|
||||
#define APP_PATH_CFG "config.txt"
|
||||
|
||||
typedef struct {
|
||||
int iso;
|
||||
int nd;
|
||||
int aperture;
|
||||
int dome;
|
||||
int backlight;
|
||||
int lux_only;
|
||||
int sensor_type;
|
||||
int32_t iso;
|
||||
int32_t nd;
|
||||
int32_t aperture;
|
||||
int32_t dome;
|
||||
int32_t backlight;
|
||||
int32_t lux_only;
|
||||
int32_t sensor_type;
|
||||
int32_t measurement_resolution;
|
||||
int32_t device_addr;
|
||||
} LightMeterConfig;
|
||||
|
||||
typedef struct {
|
||||
@@ -36,9 +44,13 @@ typedef struct {
|
||||
ViewDispatcher* view_dispatcher;
|
||||
MainView* main_view;
|
||||
VariableItemList* var_item_list;
|
||||
VariableItem* var_item_addr;
|
||||
LightMeterConfig* config;
|
||||
NotificationApp* notifications;
|
||||
Widget* widget;
|
||||
|
||||
Storage* storage;
|
||||
FuriString* cfg_path;
|
||||
} LightMeterApp;
|
||||
|
||||
typedef enum {
|
||||
@@ -50,6 +62,7 @@ typedef enum {
|
||||
} LightMeterAppView;
|
||||
|
||||
typedef enum {
|
||||
LightMeterAppCustomEventReset,
|
||||
LightMeterAppCustomEventConfig,
|
||||
LightMeterAppCustomEventHelp,
|
||||
LightMeterAppCustomEventAbout,
|
||||
@@ -58,5 +71,9 @@ typedef enum {
|
||||
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_reset_callback(LightMeterApp* context);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#define LM_VERSION_APP "1.1"
|
||||
#define LM_VERSION_APP "1.2"
|
||||
#define LM_DEVELOPED "Oleksii Kutuzov"
|
||||
#define LM_GITHUB "https://github.com/oleksiikutuzov/flipperzero-lightmeter"
|
||||
|
||||
@@ -105,6 +105,17 @@ typedef enum {
|
||||
LUX_ONLY_ON,
|
||||
} LightMeterLuxOnlyMode;
|
||||
|
||||
typedef enum {
|
||||
LOW_RES,
|
||||
HIGH_RES,
|
||||
HIGH_RES2,
|
||||
} LightMeterMeterMode;
|
||||
|
||||
typedef enum {
|
||||
ADDR_LOW,
|
||||
ADDR_HIGH,
|
||||
} LightMeterMeterAddr;
|
||||
|
||||
typedef enum {
|
||||
SENSOR_BH1750,
|
||||
SENSOR_MAX44009,
|
||||
|
||||
Reference in New Issue
Block a user