lightmeter upd
@@ -25,6 +25,7 @@ Thank you to all the supporters!
|
||||
- Updated: [Intravelometer (By theageoflove)](https://github.com/theageoflove/flipperzero-zeitraffer)
|
||||
- Added: [IR Remote (By Hong5489)](https://github.com/Hong5489/ir_remote)
|
||||
- Removed: [POCSAG (By Shmuma)](https://github.com/Shmuma/flipper-zero-pocsag)
|
||||
- Updated: [Lightmeter (By oleksiikutuzov)](https://github.com/oleksiikutuzov/flipperzero-lightmeter) `Req: BH1750`
|
||||
|
||||
## Install from Release
|
||||
FLASH STOCK FIRST BEFORE UPDATING TO CUSTOM FIRMWARE!
|
||||
|
||||
@@ -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
|
||||
...
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
# flipperzero-lightmeter
|
||||
# flipperzero-lightmeter
|
||||
|
||||
[Original link](https://github.com/oleksiikutuzov/flipperzero-lightmeter)
|
||||
[](https://github.com/oleksiikutuzov/flipperzero-lightmeter/actions/workflows/build.yml)
|
||||
|
||||
<img src="images/framed_gui_main.png" width="500px">
|
||||
|
||||
<img src="images/framed_gui_main.png" width="500px">
|
||||
<img src="images/framed_gui_lux_meter.png" width="500px">
|
||||
|
||||
## Wiring
|
||||
|
||||
@@ -14,6 +15,19 @@ SCL -> C0
|
||||
SDA -> C1
|
||||
```
|
||||
|
||||
## Sensor module
|
||||
|
||||
<img src="module/back.jpg" width="500px">
|
||||
|
||||
### If you want to build this module, you'll need (it's quite over-engineered, sorry :D)
|
||||
1. [Module PCB](https://github.com/oleksiikutuzov/flipperzero-lightmeter/blob/main/module/module_v2_gerber.zip)
|
||||
2. [Enclosure](https://github.com/oleksiikutuzov/flipperzero-lightmeter/blob/main/module/module_v2_enclosure.stl)
|
||||
3. 4-pin female header
|
||||
4. 10-pin male header
|
||||
5. 2x M3 threaded inserts (max diameter 5.3 mm, max height 4 mm)
|
||||
6. 2x M3x5 screws
|
||||
|
||||
|
||||
## TODO
|
||||
- [ ] Save settings to sd card
|
||||
|
||||
|
||||
@@ -21,4 +21,7 @@ App(
|
||||
),
|
||||
],
|
||||
fap_icon_assets="icons",
|
||||
fap_description="Lightmeter app for photography based on BH1750 sensor",
|
||||
fap_author="Oleksii Kutuzov",
|
||||
fap_weburl="https://github.com/oleksiikutuzov/flipperzero-lightmeter",
|
||||
)
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
#include "../../lightmeter.h"
|
||||
|
||||
#define TAG "Scene Config"
|
||||
|
||||
static const char* iso_numbers[] = {
|
||||
[ISO_6] = "6",
|
||||
[ISO_12] = "12",
|
||||
@@ -39,10 +41,24 @@ static const char* diffusion_dome[] = {
|
||||
[WITH_DOME] = "Yes",
|
||||
};
|
||||
|
||||
static const char* backlight[] = {
|
||||
[BACKLIGHT_AUTO] = "Auto",
|
||||
[BACKLIGHT_ON] = "On",
|
||||
};
|
||||
|
||||
static const char* lux_only[] = {
|
||||
[LUX_ONLY_OFF] = "Off",
|
||||
[LUX_ONLY_ON] = "On",
|
||||
};
|
||||
|
||||
enum LightMeterSubmenuIndex {
|
||||
LightMeterSubmenuIndexISO,
|
||||
LightMeterSubmenuIndexND,
|
||||
LightMeterSubmenuIndexDome,
|
||||
LightMeterSubmenuIndexBacklight,
|
||||
LightMeterSubmenuIndexLuxMeter,
|
||||
LightMeterSubmenuIndexHelp,
|
||||
LightMeterSubmenuIndexAbout,
|
||||
};
|
||||
|
||||
static void iso_numbers_cb(VariableItem* item) {
|
||||
@@ -78,14 +94,47 @@ static void dome_presence_cb(VariableItem* item) {
|
||||
lightmeter_app_set_config(app, config);
|
||||
}
|
||||
|
||||
static void backlight_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, backlight[index]);
|
||||
|
||||
LightMeterConfig* config = app->config;
|
||||
if(index != config->backlight) {
|
||||
if(index == BACKLIGHT_ON) {
|
||||
notification_message(
|
||||
app->notifications,
|
||||
&sequence_display_backlight_enforce_on); // force on backlight
|
||||
} else {
|
||||
notification_message(
|
||||
app->notifications,
|
||||
&sequence_display_backlight_enforce_auto); // force auto backlight
|
||||
}
|
||||
}
|
||||
config->backlight = index;
|
||||
lightmeter_app_set_config(app, config);
|
||||
}
|
||||
|
||||
static void lux_only_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, lux_only[index]);
|
||||
|
||||
LightMeterConfig* config = app->config;
|
||||
config->lux_only = index;
|
||||
lightmeter_app_set_config(app, config);
|
||||
}
|
||||
|
||||
static void ok_cb(void* context, uint32_t index) {
|
||||
LightMeterApp* app = context;
|
||||
UNUSED(app);
|
||||
switch(index) {
|
||||
case 3:
|
||||
case LightMeterSubmenuIndexHelp:
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, LightMeterAppCustomEventHelp);
|
||||
break;
|
||||
case 4:
|
||||
case LightMeterSubmenuIndexAbout:
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, LightMeterAppCustomEventAbout);
|
||||
break;
|
||||
default:
|
||||
@@ -114,6 +163,16 @@ void lightmeter_scene_config_on_enter(void* context) {
|
||||
variable_item_set_current_value_index(item, config->dome);
|
||||
variable_item_set_current_value_text(item, diffusion_dome[config->dome]);
|
||||
|
||||
item =
|
||||
variable_item_list_add(var_item_list, "Backlight", COUNT_OF(backlight), backlight_cb, app);
|
||||
variable_item_set_current_value_index(item, config->backlight);
|
||||
variable_item_set_current_value_text(item, backlight[config->backlight]);
|
||||
|
||||
item = variable_item_list_add(
|
||||
var_item_list, "Lux meter only", COUNT_OF(lux_only), lux_only_cb, app);
|
||||
variable_item_set_current_value_index(item, config->lux_only);
|
||||
variable_item_set_current_value_text(item, lux_only[config->lux_only]);
|
||||
|
||||
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);
|
||||
|
||||
@@ -153,4 +212,5 @@ void lightmeter_scene_config_on_exit(void* context) {
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -10,6 +10,8 @@ void lightmeter_scene_help_on_enter(void* context) {
|
||||
furi_string_cat(temp_str, "\e#Pinout:\r\n");
|
||||
furi_string_cat(
|
||||
temp_str,
|
||||
" VCC: 3.3V\r\n"
|
||||
" GND: GND\r\n"
|
||||
" SDA: 15 [C1]\r\n"
|
||||
" SCL: 16 [C0]\r\n");
|
||||
|
||||
|
||||
@@ -41,7 +41,7 @@ static const int nd_numbers[] = {
|
||||
[ND_4096] = 4096,
|
||||
};
|
||||
|
||||
static const float aperture_numbers[] = {
|
||||
const float aperture_numbers[] = {
|
||||
[AP_1] = 1.0,
|
||||
[AP_1_4] = 1.4,
|
||||
[AP_2] = 2.0,
|
||||
@@ -59,7 +59,7 @@ static const float aperture_numbers[] = {
|
||||
[AP_128] = 128,
|
||||
};
|
||||
|
||||
static const float speed_numbers[] = {
|
||||
const float speed_numbers[] = {
|
||||
[SPEED_8000] = 1.0 / 8000, [SPEED_4000] = 1.0 / 4000, [SPEED_2000] = 1.0 / 2000,
|
||||
[SPEED_1000] = 1.0 / 1000, [SPEED_500] = 1.0 / 500, [SPEED_250] = 1.0 / 250,
|
||||
[SPEED_125] = 1.0 / 125, [SPEED_60] = 1.0 / 60, [SPEED_30] = 1.0 / 30,
|
||||
@@ -94,37 +94,39 @@ static void main_view_draw_callback(Canvas* canvas, void* context) {
|
||||
furi_assert(context);
|
||||
MainViewModel* model = context;
|
||||
|
||||
// FURI_LOG_D("MAIN VIEW", "Drawing");
|
||||
|
||||
canvas_clear(canvas);
|
||||
|
||||
// top row
|
||||
draw_top_row(canvas, model);
|
||||
|
||||
// add f, T values
|
||||
canvas_set_font(canvas, FontBigNumbers);
|
||||
|
||||
// draw f icon and number
|
||||
canvas_draw_icon(canvas, 15, 17, &I_f_10x14);
|
||||
draw_aperture(canvas, model);
|
||||
|
||||
// draw T icon and number
|
||||
canvas_draw_icon(canvas, 15, 34, &I_T_10x14);
|
||||
draw_speed(canvas, model);
|
||||
|
||||
// draw button
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
elements_button_left(canvas, "Config");
|
||||
|
||||
// draw ND number
|
||||
draw_nd_number(canvas, model);
|
||||
if(!model->lux_only) {
|
||||
// top row
|
||||
draw_top_row(canvas, model);
|
||||
|
||||
// draw EV number
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
draw_EV_number(canvas, model);
|
||||
// add f, T values
|
||||
canvas_set_font(canvas, FontBigNumbers);
|
||||
|
||||
// draw mode indicator
|
||||
draw_mode_indicator(canvas, model);
|
||||
// draw f icon and number
|
||||
canvas_draw_icon(canvas, 15, 17, &I_f_10x14);
|
||||
draw_aperture(canvas, model);
|
||||
|
||||
// draw T icon and number
|
||||
canvas_draw_icon(canvas, 15, 34, &I_T_10x14);
|
||||
draw_speed(canvas, model);
|
||||
|
||||
// draw ND number
|
||||
draw_nd_number(canvas, model);
|
||||
|
||||
// draw EV number
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
draw_EV_number(canvas, model);
|
||||
|
||||
// draw mode indicator
|
||||
draw_mode_indicator(canvas, model);
|
||||
} else {
|
||||
draw_lux_only_mode(canvas, model);
|
||||
}
|
||||
}
|
||||
|
||||
static void main_view_process(MainView* main_view, InputEvent* event) {
|
||||
@@ -267,6 +269,12 @@ void main_view_set_dome(MainView* main_view, bool dome) {
|
||||
main_view->view, MainViewModel * model, { model->dome = dome; }, true);
|
||||
}
|
||||
|
||||
void main_view_set_lux_only(MainView* main_view, bool lux_only) {
|
||||
furi_assert(main_view);
|
||||
with_view_model(
|
||||
main_view->view, MainViewModel * model, { model->lux_only = lux_only; }, true);
|
||||
}
|
||||
|
||||
bool main_view_get_dome(MainView* main_view) {
|
||||
furi_assert(main_view);
|
||||
bool val = false;
|
||||
@@ -307,7 +315,7 @@ void draw_top_row(Canvas* canvas, MainViewModel* context) {
|
||||
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
// metering mode A – ambient, F – flash
|
||||
canvas_draw_str_aligned(canvas, 1, 1, AlignLeft, AlignTop, "A");
|
||||
// canvas_draw_str_aligned(canvas, 1, 1, AlignLeft, AlignTop, "A");
|
||||
|
||||
snprintf(str, sizeof(str), "ISO: %d", iso_numbers[model->iso]);
|
||||
canvas_draw_str_aligned(canvas, 19, 1, AlignLeft, AlignTop, str);
|
||||
@@ -412,6 +420,8 @@ void draw_nd_number(Canvas* canvas, MainViewModel* context) {
|
||||
|
||||
char str[9];
|
||||
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
|
||||
if(model->response) {
|
||||
snprintf(str, sizeof(str), "ND: %d", nd_numbers[model->nd]);
|
||||
} else {
|
||||
@@ -432,3 +442,29 @@ void draw_EV_number(Canvas* canvas, MainViewModel* context) {
|
||||
canvas_draw_str_aligned(canvas, 87, 29, AlignLeft, AlignBottom, "EV: --");
|
||||
}
|
||||
}
|
||||
|
||||
void draw_lux_only_mode(Canvas* canvas, MainViewModel* context) {
|
||||
MainViewModel* model = context;
|
||||
|
||||
if(!model->response) {
|
||||
canvas_draw_box(canvas, 0, 0, 128, 12);
|
||||
canvas_set_color(canvas, ColorWhite);
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
canvas_draw_str(canvas, 24, 10, "No sensor found");
|
||||
canvas_set_color(canvas, ColorBlack);
|
||||
} else {
|
||||
char str[12];
|
||||
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
|
||||
canvas_draw_line(canvas, 0, 10, 128, 10);
|
||||
canvas_draw_str_aligned(canvas, 64, 1, AlignCenter, AlignTop, "Lux meter mode");
|
||||
|
||||
canvas_set_font(canvas, FontBigNumbers);
|
||||
snprintf(str, sizeof(str), "%.0f", (double)model->lux);
|
||||
canvas_draw_str_aligned(canvas, 80, 32, AlignRight, AlignCenter, str);
|
||||
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
canvas_draw_str_aligned(canvas, 85, 39, AlignLeft, AlignBottom, "Lux");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@ typedef struct {
|
||||
int aperture;
|
||||
int speed;
|
||||
bool dome;
|
||||
bool lux_only;
|
||||
} MainViewModel;
|
||||
|
||||
typedef void (*LightMeterMainViewButtonCallback)(void* context);
|
||||
@@ -58,6 +59,8 @@ void main_view_set_speed(MainView* main_view, int val);
|
||||
|
||||
void main_view_set_dome(MainView* main_view, bool val);
|
||||
|
||||
void main_view_set_lux_only(MainView* main_view, bool val);
|
||||
|
||||
bool main_view_get_dome(MainView* main_view);
|
||||
|
||||
void draw_top_row(Canvas* canvas, MainViewModel* context);
|
||||
@@ -71,3 +74,5 @@ void draw_mode_indicator(Canvas* canvas, MainViewModel* context);
|
||||
void draw_nd_number(Canvas* canvas, MainViewModel* context);
|
||||
|
||||
void draw_EV_number(Canvas* canvas, MainViewModel* context);
|
||||
|
||||
void draw_lux_only_mode(Canvas* canvas, MainViewModel* context);
|
||||
|
||||
|
Before Width: | Height: | Size: 200 KiB |
|
Before Width: | Height: | Size: 245 KiB After Width: | Height: | Size: 244 KiB |
|
After Width: | Height: | Size: 230 KiB |
|
Before Width: | Height: | Size: 246 KiB After Width: | Height: | Size: 240 KiB |
|
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 1.8 KiB |
|
After Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 1.9 KiB |
@@ -1,144 +0,0 @@
|
||||
/**
|
||||
* @file BH1750.h
|
||||
* @author Oleksii Kutuzov (oleksii.kutuzov@icloud.com)
|
||||
* @brief
|
||||
* @version 0.1
|
||||
* @date 2022-11-06
|
||||
*
|
||||
* @copyright Copyright (c) 2022
|
||||
*
|
||||
* Ported from:
|
||||
* https://github.com/lamik/Light_Sensors_STM32
|
||||
*/
|
||||
|
||||
#include "BH1750.h"
|
||||
|
||||
BH1750_mode bh1750_mode = BH1750_DEFAULT_MODE; // Current sensor mode
|
||||
uint8_t bh1750_mt_reg = BH1750_DEFAULT_MTREG; // Current MT register value
|
||||
|
||||
BH1750_STATUS bh1750_init() {
|
||||
if(BH1750_OK == bh1750_reset()) {
|
||||
if(BH1750_OK == bh1750_set_mt_reg(BH1750_DEFAULT_MTREG)) {
|
||||
return BH1750_OK;
|
||||
}
|
||||
}
|
||||
return BH1750_ERROR;
|
||||
}
|
||||
|
||||
BH1750_STATUS bh1750_reset() {
|
||||
uint8_t command = 0x07;
|
||||
bool status;
|
||||
|
||||
furi_hal_i2c_acquire(I2C_BUS);
|
||||
status = furi_hal_i2c_tx(I2C_BUS, BH1750_ADDRESS, &command, 1, I2C_TIMEOUT);
|
||||
furi_hal_i2c_release(I2C_BUS);
|
||||
|
||||
if(status) {
|
||||
return BH1750_OK;
|
||||
}
|
||||
|
||||
return BH1750_ERROR;
|
||||
}
|
||||
|
||||
BH1750_STATUS bh1750_set_power_state(uint8_t PowerOn) {
|
||||
PowerOn = (PowerOn ? 1 : 0);
|
||||
bool status;
|
||||
|
||||
furi_hal_i2c_acquire(I2C_BUS);
|
||||
status = furi_hal_i2c_tx(I2C_BUS, BH1750_ADDRESS, &PowerOn, 1, I2C_TIMEOUT);
|
||||
furi_hal_i2c_release(I2C_BUS);
|
||||
|
||||
if(status) {
|
||||
return BH1750_OK;
|
||||
}
|
||||
|
||||
return BH1750_ERROR;
|
||||
}
|
||||
|
||||
BH1750_STATUS bh1750_set_mode(BH1750_mode mode) {
|
||||
if(!((mode >> 4) || (mode >> 5))) {
|
||||
return BH1750_ERROR;
|
||||
}
|
||||
|
||||
if((mode & 0x0F) > 3) {
|
||||
return BH1750_ERROR;
|
||||
}
|
||||
|
||||
bool status;
|
||||
|
||||
bh1750_mode = mode;
|
||||
|
||||
furi_hal_i2c_acquire(I2C_BUS);
|
||||
status = furi_hal_i2c_tx(I2C_BUS, BH1750_ADDRESS, &mode, 1, I2C_TIMEOUT);
|
||||
furi_hal_i2c_release(I2C_BUS);
|
||||
|
||||
if(status) {
|
||||
return BH1750_OK;
|
||||
}
|
||||
|
||||
return BH1750_ERROR;
|
||||
}
|
||||
|
||||
BH1750_STATUS bh1750_set_mt_reg(uint8_t mt_reg) {
|
||||
if(mt_reg < 31 || mt_reg > 254) {
|
||||
return BH1750_ERROR;
|
||||
}
|
||||
|
||||
bh1750_mt_reg = mt_reg;
|
||||
|
||||
uint8_t tmp[2];
|
||||
bool status;
|
||||
|
||||
tmp[0] = (0x40 | (mt_reg >> 5));
|
||||
tmp[1] = (0x60 | (mt_reg & 0x1F));
|
||||
|
||||
furi_hal_i2c_acquire(I2C_BUS);
|
||||
status = furi_hal_i2c_tx(I2C_BUS, BH1750_ADDRESS, &tmp[0], 1, I2C_TIMEOUT);
|
||||
furi_hal_i2c_release(I2C_BUS);
|
||||
if(!status) {
|
||||
return BH1750_ERROR;
|
||||
}
|
||||
|
||||
furi_hal_i2c_acquire(I2C_BUS);
|
||||
status = furi_hal_i2c_tx(I2C_BUS, BH1750_ADDRESS, &tmp[1], 1, I2C_TIMEOUT);
|
||||
furi_hal_i2c_release(I2C_BUS);
|
||||
if(status) {
|
||||
return BH1750_OK;
|
||||
}
|
||||
|
||||
return BH1750_ERROR;
|
||||
}
|
||||
|
||||
BH1750_STATUS bh1750_trigger_manual_conversion() {
|
||||
if(BH1750_OK == bh1750_set_mode(bh1750_mode)) {
|
||||
return BH1750_OK;
|
||||
}
|
||||
return BH1750_ERROR;
|
||||
}
|
||||
|
||||
BH1750_STATUS bh1750_read_light(float* result) {
|
||||
float result_tmp;
|
||||
uint8_t rcv[2];
|
||||
bool status;
|
||||
|
||||
furi_hal_i2c_acquire(I2C_BUS);
|
||||
status = furi_hal_i2c_rx(I2C_BUS, BH1750_ADDRESS, rcv, 2, I2C_TIMEOUT);
|
||||
furi_hal_i2c_release(I2C_BUS);
|
||||
|
||||
if(status) {
|
||||
result_tmp = (rcv[0] << 8) | (rcv[1]);
|
||||
|
||||
if(bh1750_mt_reg != BH1750_DEFAULT_MTREG) {
|
||||
result_tmp *= (float)((uint8_t)BH1750_DEFAULT_MTREG / (float)bh1750_mt_reg);
|
||||
}
|
||||
|
||||
if(bh1750_mode == ONETIME_HIGH_RES_MODE_2 || bh1750_mode == CONTINUOUS_HIGH_RES_MODE_2) {
|
||||
result_tmp /= 2.0;
|
||||
}
|
||||
|
||||
*result = result_tmp / BH1750_CONVERSION_FACTOR;
|
||||
|
||||
return BH1750_OK;
|
||||
}
|
||||
return BH1750_ERROR;
|
||||
}
|
||||
@@ -1,103 +0,0 @@
|
||||
/**
|
||||
* @file BH1750.h
|
||||
* @author Oleksii Kutuzov (oleksii.kutuzov@icloud.com)
|
||||
* @brief
|
||||
* @version 0.1
|
||||
* @date 2022-11-06
|
||||
*
|
||||
* @copyright Copyright (c) 2022
|
||||
*
|
||||
* Ported from:
|
||||
* https://github.com/lamik/Light_Sensors_STM32
|
||||
*/
|
||||
|
||||
#include <furi.h>
|
||||
#include <furi_hal.h>
|
||||
|
||||
#ifndef BH1750_H_
|
||||
#define BH1750_H_
|
||||
|
||||
// I2C BUS
|
||||
#define I2C_BUS &furi_hal_i2c_handle_external
|
||||
#define I2C_TIMEOUT 10
|
||||
|
||||
#define BH1750_ADDRESS (0x23 << 1)
|
||||
|
||||
#define BH1750_POWER_DOWN 0x00
|
||||
#define BH1750_POWER_ON 0x01
|
||||
#define BH1750_RESET 0x07
|
||||
#define BH1750_DEFAULT_MTREG 69
|
||||
#define BH1750_DEFAULT_MODE ONETIME_HIGH_RES_MODE
|
||||
|
||||
#define BH1750_CONVERSION_FACTOR 1.2
|
||||
|
||||
typedef enum { BH1750_OK = 0, BH1750_ERROR = 1 } BH1750_STATUS;
|
||||
|
||||
typedef enum {
|
||||
CONTINUOUS_HIGH_RES_MODE = 0x10,
|
||||
CONTINUOUS_HIGH_RES_MODE_2 = 0x11,
|
||||
CONTINUOUS_LOW_RES_MODE = 0x13,
|
||||
ONETIME_HIGH_RES_MODE = 0x20,
|
||||
ONETIME_HIGH_RES_MODE_2 = 0x21,
|
||||
ONETIME_LOW_RES_MODE = 0x23
|
||||
} BH1750_mode;
|
||||
|
||||
/**
|
||||
* @brief Initialize the sensor. Sends the reset command and sets the measurement register to the default value.
|
||||
*
|
||||
* @return BH1750_STATUS
|
||||
*/
|
||||
BH1750_STATUS bh1750_init();
|
||||
|
||||
/**
|
||||
* @brief Reset all registers to the default value.
|
||||
*
|
||||
* @return BH1750_STATUS
|
||||
*/
|
||||
BH1750_STATUS bh1750_reset();
|
||||
|
||||
/**
|
||||
* @brief Sets the power state. 1 - running; 0 - sleep, low power.
|
||||
*
|
||||
* @param PowerOn sensor state.
|
||||
* @return BH1750_STATUS
|
||||
*/
|
||||
BH1750_STATUS bh1750_set_power_state(uint8_t PowerOn);
|
||||
|
||||
/**
|
||||
* @brief Set the Measurement Time register. It allows to increase or decrease the sensitivity.
|
||||
*
|
||||
* @param MTreg value from 31 to 254, defaults to 69.
|
||||
*
|
||||
* @return BH1750_STATUS
|
||||
*/
|
||||
BH1750_STATUS bh1750_set_mt_reg(uint8_t MTreg);
|
||||
|
||||
/**
|
||||
* @brief Set the mode of converting. Look into the bh1750_mode enum.
|
||||
*
|
||||
* @param Mode mode enumerator
|
||||
* @return BH1750_STATUS
|
||||
*/
|
||||
BH1750_STATUS bh1750_set_mode(BH1750_mode Mode);
|
||||
|
||||
/**
|
||||
* @brief Trigger the conversion in manual modes.
|
||||
*
|
||||
* @details a low-resolution mode, the conversion time is typically 16 ms, and for a high-resolution
|
||||
* mode is 120 ms. You need to wait until reading the measurement value. There is no need
|
||||
* to exit low-power mode for manual conversion. It makes automatically.
|
||||
*
|
||||
* @return BH1750_STATUS
|
||||
*/
|
||||
BH1750_STATUS bh1750_trigger_manual_conversion();
|
||||
|
||||
/**
|
||||
* @brief Read the converted value and calculate the result.
|
||||
*
|
||||
* @param Result stores received value to this variable.
|
||||
* @return BH1750_STATUS
|
||||
*/
|
||||
BH1750_STATUS bh1750_read_light(float* Result);
|
||||
|
||||
#endif /* BH1750_H_ */
|
||||
@@ -1,21 +0,0 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2022 Oleksii Kutuzov
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -1,2 +0,0 @@
|
||||
# flipperzero-BH1750
|
||||
BH1750 light sensor library for Flipper Zero
|
||||
@@ -1,7 +1,7 @@
|
||||
#include "lightmeter.h"
|
||||
#include "lightmeter_helper.h"
|
||||
|
||||
#define WORKER_TAG "MAIN APP"
|
||||
#define TAG "MAIN APP"
|
||||
|
||||
static bool lightmeter_custom_event_callback(void* context, uint32_t event) {
|
||||
furi_assert(context);
|
||||
@@ -31,7 +31,6 @@ LightMeterApp* lightmeter_app_alloc(uint32_t first_scene) {
|
||||
bh1750_set_power_state(1);
|
||||
bh1750_init();
|
||||
bh1750_set_mode(ONETIME_HIGH_RES_MODE);
|
||||
bh1750_set_mt_reg(100);
|
||||
|
||||
// Set default values to config
|
||||
app->config = malloc(sizeof(LightMeterConfig));
|
||||
@@ -39,12 +38,11 @@ LightMeterApp* lightmeter_app_alloc(uint32_t first_scene) {
|
||||
app->config->nd = DEFAULT_ND;
|
||||
app->config->aperture = DEFAULT_APERTURE;
|
||||
app->config->dome = DEFAULT_DOME;
|
||||
app->config->backlight = DEFAULT_BACKLIGHT;
|
||||
|
||||
// Records
|
||||
app->gui = furi_record_open(RECORD_GUI);
|
||||
app->notifications = furi_record_open(RECORD_NOTIFICATION);
|
||||
notification_message(
|
||||
app->notifications, &sequence_display_backlight_enforce_on); // force on backlight
|
||||
|
||||
// View dispatcher
|
||||
app->view_dispatcher = view_dispatcher_alloc();
|
||||
@@ -112,9 +110,11 @@ void lightmeter_app_free(LightMeterApp* app) {
|
||||
|
||||
// Records
|
||||
furi_record_close(RECORD_GUI);
|
||||
notification_message(
|
||||
app->notifications,
|
||||
&sequence_display_backlight_enforce_auto); // set backlight back to auto
|
||||
if(app->config->backlight != BACKLIGHT_AUTO) {
|
||||
notification_message(
|
||||
app->notifications,
|
||||
&sequence_display_backlight_enforce_auto); // set backlight back to auto
|
||||
}
|
||||
furi_record_close(RECORD_NOTIFICATION);
|
||||
|
||||
bh1750_set_power_state(0);
|
||||
|
||||
@@ -24,6 +24,8 @@ typedef struct {
|
||||
int nd;
|
||||
int aperture;
|
||||
int dome;
|
||||
int backlight;
|
||||
int lux_only;
|
||||
} LightMeterConfig;
|
||||
|
||||
typedef struct {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#define LM_VERSION_APP "0.5"
|
||||
#define LM_VERSION_APP "0.7"
|
||||
#define LM_DEVELOPED "Oleksii Kutuzov"
|
||||
#define LM_GITHUB "https://github.com/oleksiikutuzov/flipperzero-lightmeter"
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#define DEFAULT_APERTURE AP_2_8
|
||||
#define DEFAULT_SPEED SPEED_125
|
||||
#define DEFAULT_DOME WITHOUT_DOME
|
||||
#define DEFAULT_BACKLIGHT BACKLIGHT_AUTO
|
||||
|
||||
typedef enum {
|
||||
ISO_6,
|
||||
@@ -97,3 +98,10 @@ typedef enum {
|
||||
WITHOUT_DOME,
|
||||
WITH_DOME,
|
||||
} LightMeterDomePresence;
|
||||
|
||||
typedef enum {
|
||||
LUX_ONLY_OFF,
|
||||
LUX_ONLY_ON,
|
||||
} LightMeterLuxOnlyMode;
|
||||
|
||||
typedef enum { BACKLIGHT_AUTO, BACKLIGHT_ON } LightMeterBacklight;
|
||||
|
||||
@@ -1,33 +1,8 @@
|
||||
#include "lightmeter_helper.h"
|
||||
#include "lightmeter_config.h"
|
||||
|
||||
static const float aperture_numbers[] = {
|
||||
[AP_1] = 1.0,
|
||||
[AP_1_4] = 1.4,
|
||||
[AP_2] = 2.0,
|
||||
[AP_2_8] = 2.8,
|
||||
[AP_4] = 4.0,
|
||||
[AP_5_6] = 5.6,
|
||||
[AP_8] = 8,
|
||||
[AP_11] = 11,
|
||||
[AP_16] = 16,
|
||||
[AP_22] = 22,
|
||||
[AP_32] = 32,
|
||||
[AP_45] = 45,
|
||||
[AP_64] = 64,
|
||||
[AP_90] = 90,
|
||||
[AP_128] = 128,
|
||||
};
|
||||
|
||||
static const float time_numbers[] = {
|
||||
[SPEED_8000] = 1.0 / 8000, [SPEED_4000] = 1.0 / 4000, [SPEED_2000] = 1.0 / 2000,
|
||||
[SPEED_1000] = 1.0 / 1000, [SPEED_500] = 1.0 / 500, [SPEED_250] = 1.0 / 250,
|
||||
[SPEED_125] = 1.0 / 125, [SPEED_60] = 1.0 / 60, [SPEED_30] = 1.0 / 30,
|
||||
[SPEED_15] = 1.0 / 15, [SPEED_8] = 1.0 / 8, [SPEED_4] = 1.0 / 4,
|
||||
[SPEED_2] = 1.0 / 2, [SPEED_1S] = 1.0, [SPEED_2S] = 2.0,
|
||||
[SPEED_4S] = 4.0, [SPEED_8S] = 8.0, [SPEED_15S] = 15.0,
|
||||
[SPEED_30S] = 30.0,
|
||||
};
|
||||
extern const float aperture_numbers[];
|
||||
extern const float speed_numbers[];
|
||||
|
||||
float lux2ev(float lux) {
|
||||
return log2(lux / 2.5);
|
||||
@@ -41,7 +16,6 @@ float getMinDistance(float x, float v1, float v2) {
|
||||
return v1;
|
||||
}
|
||||
|
||||
// Convert calculated aperture value to photography style aperture value.
|
||||
float normalizeAperture(float a) {
|
||||
for(int i = 0; i < AP_NUM; i++) {
|
||||
float a1 = aperture_numbers[i];
|
||||
@@ -57,8 +31,8 @@ float normalizeAperture(float a) {
|
||||
|
||||
float normalizeTime(float a) {
|
||||
for(int i = 0; i < SPEED_NUM; i++) {
|
||||
float a1 = time_numbers[i];
|
||||
float a2 = time_numbers[i + 1];
|
||||
float a1 = speed_numbers[i];
|
||||
float a2 = speed_numbers[i + 1];
|
||||
|
||||
if(a1 < a && a2 >= a) {
|
||||
return getMinDistance(a, a1, a2);
|
||||
|
||||
|
After Width: | Height: | Size: 2.2 MiB |
|
After Width: | Height: | Size: 1.9 MiB |
|
After Width: | Height: | Size: 2.1 MiB |