diff --git a/.clang-format b/.clang-format new file mode 100644 index 00000000000..4b76f7fa43b --- /dev/null +++ b/.clang-format @@ -0,0 +1,191 @@ +--- +Language: Cpp +AccessModifierOffset: -4 +AlignAfterOpenBracket: AlwaysBreak +AlignArrayOfStructures: None +AlignConsecutiveMacros: None +AlignConsecutiveAssignments: None +AlignConsecutiveBitFields: None +AlignConsecutiveDeclarations: None +AlignEscapedNewlines: Left +AlignOperands: Align +AlignTrailingComments: false +AllowAllArgumentsOnNextLine: true +AllowAllParametersOfDeclarationOnNextLine: false +AllowShortEnumsOnASingleLine: true +AllowShortBlocksOnASingleLine: Never +AllowShortCaseLabelsOnASingleLine: false +AllowShortFunctionsOnASingleLine: None +AllowShortLambdasOnASingleLine: All +AllowShortIfStatementsOnASingleLine: WithoutElse +AllowShortLoopsOnASingleLine: true +AlwaysBreakAfterDefinitionReturnType: None +AlwaysBreakAfterReturnType: None +AlwaysBreakBeforeMultilineStrings: false +AlwaysBreakTemplateDeclarations: Yes +AttributeMacros: + - __capability +BinPackArguments: false +BinPackParameters: false +BraceWrapping: + AfterCaseLabel: false + AfterClass: false + AfterControlStatement: Never + AfterEnum: false + AfterFunction: false + AfterNamespace: false + AfterObjCDeclaration: false + AfterStruct: false + AfterUnion: false + AfterExternBlock: false + BeforeCatch: false + BeforeElse: false + BeforeLambdaBody: false + BeforeWhile: false + IndentBraces: false + SplitEmptyFunction: true + SplitEmptyRecord: true + SplitEmptyNamespace: true +BreakBeforeBinaryOperators: None +BreakBeforeConceptDeclarations: true +BreakBeforeBraces: Attach +BreakBeforeInheritanceComma: false +BreakInheritanceList: BeforeColon +BreakBeforeTernaryOperators: false +BreakConstructorInitializersBeforeComma: false +BreakConstructorInitializers: BeforeComma +BreakAfterJavaFieldAnnotations: false +BreakStringLiterals: false +ColumnLimit: 99 +CommentPragmas: '^ IWYU pragma:' +QualifierAlignment: Leave +CompactNamespaces: false +ConstructorInitializerIndentWidth: 4 +ContinuationIndentWidth: 4 +Cpp11BracedListStyle: true +DeriveLineEnding: true +DerivePointerAlignment: false +DisableFormat: false +EmptyLineAfterAccessModifier: Never +EmptyLineBeforeAccessModifier: LogicalBlock +ExperimentalAutoDetectBinPacking: false +PackConstructorInitializers: BinPack +BasedOnStyle: '' +ConstructorInitializerAllOnOneLineOrOnePerLine: false +AllowAllConstructorInitializersOnNextLine: true +FixNamespaceComments: false +ForEachMacros: + - foreach + - Q_FOREACH + - BOOST_FOREACH +IfMacros: + - KJ_IF_MAYBE +IncludeBlocks: Preserve +IncludeCategories: + - Regex: '.*' + Priority: 1 + SortPriority: 0 + CaseSensitive: false + - Regex: '^(<|"(gtest|gmock|isl|json)/)' + Priority: 3 + SortPriority: 0 + CaseSensitive: false + - Regex: '.*' + Priority: 1 + SortPriority: 0 + CaseSensitive: false +IncludeIsMainRegex: '(Test)?$' +IncludeIsMainSourceRegex: '' +IndentAccessModifiers: false +IndentCaseLabels: false +IndentCaseBlocks: false +IndentGotoLabels: true +IndentPPDirectives: None +IndentExternBlock: AfterExternBlock +IndentRequires: false +IndentWidth: 4 +IndentWrappedFunctionNames: true +InsertTrailingCommas: None +JavaScriptQuotes: Leave +JavaScriptWrapImports: true +KeepEmptyLinesAtTheStartOfBlocks: false +LambdaBodyIndentation: Signature +MacroBlockBegin: '' +MacroBlockEnd: '' +MaxEmptyLinesToKeep: 1 +NamespaceIndentation: None +ObjCBinPackProtocolList: Auto +ObjCBlockIndentWidth: 4 +ObjCBreakBeforeNestedBlockParam: true +ObjCSpaceAfterProperty: true +ObjCSpaceBeforeProtocolList: true +PenaltyBreakAssignment: 10 +PenaltyBreakBeforeFirstCallParameter: 30 +PenaltyBreakComment: 10 +PenaltyBreakFirstLessLess: 0 +PenaltyBreakOpenParenthesis: 0 +PenaltyBreakString: 10 +PenaltyBreakTemplateDeclaration: 10 +PenaltyExcessCharacter: 100 +PenaltyReturnTypeOnItsOwnLine: 60 +PenaltyIndentedWhitespace: 0 +PointerAlignment: Left +PPIndentWidth: -1 +ReferenceAlignment: Pointer +ReflowComments: false +RemoveBracesLLVM: false +SeparateDefinitionBlocks: Leave +ShortNamespaceLines: 1 +SortIncludes: Never +SortJavaStaticImport: Before +SortUsingDeclarations: false +SpaceAfterCStyleCast: false +SpaceAfterLogicalNot: false +SpaceAfterTemplateKeyword: true +SpaceBeforeAssignmentOperators: true +SpaceBeforeCaseColon: false +SpaceBeforeCpp11BracedList: false +SpaceBeforeCtorInitializerColon: true +SpaceBeforeInheritanceColon: true +SpaceBeforeParens: Never +SpaceBeforeParensOptions: + AfterControlStatements: false + AfterForeachMacros: false + AfterFunctionDefinitionName: false + AfterFunctionDeclarationName: false + AfterIfMacros: false + AfterOverloadedOperator: false + BeforeNonEmptyParentheses: false +SpaceAroundPointerQualifiers: Default +SpaceBeforeRangeBasedForLoopColon: true +SpaceInEmptyBlock: false +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 1 +SpacesInAngles: Never +SpacesInConditionalStatement: false +SpacesInContainerLiterals: false +SpacesInCStyleCastParentheses: false +SpacesInLineCommentPrefix: + Minimum: 1 + Maximum: -1 +SpacesInParentheses: false +SpacesInSquareBrackets: false +SpaceBeforeSquareBrackets: false +BitFieldColonSpacing: Both +Standard: c++03 +StatementAttributeLikeMacros: + - Q_EMIT +StatementMacros: + - Q_UNUSED + - QT_REQUIRE_VERSION +TabWidth: 4 +UseCRLF: false +UseTab: Never +WhitespaceSensitiveMacros: + - STRINGIZE + - PP_STRINGIZE + - BOOST_PP_STRINGIZE + - NS_SWIFT_NAME + - CF_SWIFT_NAME +... + diff --git a/.flipcorg/gallery/gui_config_2.png b/.flipcorg/gallery/gui_config_2.png new file mode 100644 index 00000000000..497c55d34c6 Binary files /dev/null and b/.flipcorg/gallery/gui_config_2.png differ diff --git a/.flipcorg/gallery/gui_lux_meter.png b/.flipcorg/gallery/gui_lux_meter.png index f7159e6711b..e27a2ed8f07 100644 Binary files a/.flipcorg/gallery/gui_lux_meter.png and b/.flipcorg/gallery/gui_lux_meter.png differ diff --git a/application.fam b/application.fam index ce343db4ea8..7bbfd88b582 100644 --- a/application.fam +++ b/application.fam @@ -7,9 +7,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=[ diff --git a/README.md b/docs/README.md similarity index 100% rename from README.md rename to docs/README.md diff --git a/docs/changelog.md b/docs/changelog.md index 4b0d28dea8e..a891921c775 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -1,3 +1,11 @@ +## 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) diff --git a/gui/scenes/lightmeter_scene_config.c b/gui/scenes/lightmeter_scene_config.c index aafa1f84330..c6f23818ef4 100644 --- a/gui/scenes/lightmeter_scene_config.c +++ b/gui/scenes/lightmeter_scene_config.c @@ -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); } diff --git a/gui/scenes/lightmeter_scene_help.c b/gui/scenes/lightmeter_scene_help.c index a5688ee2fba..8a40b6d3d45 100644 --- a/gui/scenes/lightmeter_scene_help.c +++ b/gui/scenes/lightmeter_scene_help.c @@ -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); diff --git a/gui/scenes/lightmeter_scene_main.c b/gui/scenes/lightmeter_scene_main.c index 3b4789e993c..94e26b420dc 100644 --- a/gui/scenes/lightmeter_scene_main.c +++ b/gui/scenes/lightmeter_scene_main.c @@ -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); } diff --git a/gui/views/main_view.c b/gui/views/main_view.c index 8b3e2989f22..3ae431cda10 100644 --- a/gui/views/main_view.c +++ b/gui/views/main_view.c @@ -1,4 +1,5 @@ #include "main_view.h" +#include #include #include #include @@ -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); + } } } diff --git a/gui/views/main_view.h b/gui/views/main_view.h index 038cd306581..e05860eefae 100644 --- a/gui/views/main_view.h +++ b/gui/views/main_view.h @@ -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); diff --git a/lib/MAX44009/MAX44009.c b/lib/MAX44009/MAX44009.c index 211f6a9bac3..1e8794724d6 100644 --- a/lib/MAX44009/MAX44009.c +++ b/lib/MAX44009/MAX44009.c @@ -2,13 +2,20 @@ #include #include +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; -} \ No newline at end of file +} diff --git a/lib/MAX44009/MAX44009.h b/lib/MAX44009/MAX44009.h index fb350653d10..c09838fc2d1 100644 --- a/lib/MAX44009/MAX44009.h +++ b/lib/MAX44009/MAX44009.h @@ -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); diff --git a/lightmeter.c b/lightmeter.c index b128e334f33..9589e025b4d 100644 --- a/lightmeter.c +++ b/lightmeter.c @@ -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); +} diff --git a/lightmeter.h b/lightmeter.h index 75bc09b0261..de0a6a3fb92 100644 --- a/lightmeter.h +++ b/lightmeter.h @@ -3,6 +3,9 @@ #include #include +#include +#include + #include #include #include @@ -20,14 +23,19 @@ #include #include +#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); diff --git a/lightmeter_config.h b/lightmeter_config.h index d46f0cd3866..e97464ab1ef 100644 --- a/lightmeter_config.h +++ b/lightmeter_config.h @@ -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,