Merge branch 'analyzer-decoder' of https://github.com/ALEEF02/unleashed-firmware-subghz-analyzer into analyzer-decoder

This commit is contained in:
ALEEF02
2023-07-24 17:11:11 -04:00
40 changed files with 581 additions and 289 deletions

4
applications/external/doom/.gitignore vendored Normal file
View File

@@ -0,0 +1,4 @@
dist/*
.vscode
.clang-format
.editorconfig

View File

@@ -1,68 +1,10 @@
# Doom Flipper Zero edition
<div style="text-align:center"><img src="assets/logo_inv.png"/></div>
## Will it run Doom?
As tradition goes, Doom is being ported to almost every possible embedded electronic device. Therefore I did an attempt to come up with something close to Doom and still compatible on the Flipper Zero's hardware.<br> This is not the actual Doom game but a port made from yet another Doom port to the Arduino Nano (https://github.com/daveruiz/doom-nano/). This port is basically a raycasting engine, using Doom sprites.<br>
As tradition goes, Doom is being ported to almost every possible embedded electronic device. Therefore I did an attempt to come up with something close to Doom and still compatible on the Flipper Zero's hardware. This is not the actual Doom game but a port made from yet another Doom port to the Arduino Nano - https://github.com/daveruiz/doom-nano/. This port is basically a raycasting engine, using Doom sprites.
This version is very basic and might be improved over time.
## How to install on Flipper Zero
During the porting process, minor changes were made to the workings (and build options) of the current firmware. These changes are documented here and are necessary in order to get a working firmware build that contains this Doom port.
### Modifying the firmware & build options
* In the `sites/cc.scons` add the following values to the `CCFLAGS` section:
```
...
"-Wno-unused-parameter",
"-Wno-type-limits",
"-Wno-unused-variable",
...
```
* In `applications/gui/canvas_i.h` comment out the following line:<br>
`uint8_t* canvas_get_buffer(Canvas* canvas);` --> `//uint8_t* canvas_get_buffer(Canvas* canvas);`
* In `applications/gui/canvas.h` add the following lines:
```
uint8_t* canvas_get_buffer(Canvas* canvas);
void canvas_draw_icon_bitmap(Canvas* canvas, uint8_t x, uint8_t y, int16_t w, int16_t h, const Icon* icon);
```
* In `applications/gui/canvas.c` add the following function:
```
void canvas_draw_icon_bitmap(Canvas* canvas, uint8_t x, uint8_t y, int16_t w, int16_t h, const Icon* icon){
furi_assert(canvas);
furi_assert(icon);
x += canvas->offset_x;
y += canvas->offset_y;
uint8_t* icon_data = NULL;
furi_hal_compress_icon_decode(icon_get_data(icon), &icon_data);
u8g2_DrawXBM(&canvas->fb, x, y, w, h, icon_data);
}
```
### Installing the plugin in the firmware
* Make a folder called Doom in the applications folder. Add all the source files (also the compiled folder and it's files) in the Doom folder.
* Make the `applications/meta/application.fam` look like the following:
```
App(
appid="basic_plugins",
name="Basic applications for plug-in menu",
apptype=FlipperAppType.METAPACKAGE,
provides=[
...
"doom_game",
...
],
)
```
If all went well the only thing left to do is building the firmware and installing it to the Flipper.
## Screenshots
![Intro screen](assets/screenshot-intro2.jpg)
![Start screen](assets/screenshot-start2.jpg)
![Imp](assets/screenshot-imp2.jpg)
![Medkit](assets/screenshot-medkit2.jpg)
## Credits
@xMasterX - Porting to latest firmware using new plugins system, fixing many issues, adding sound
@Svaarich - New logo screen and cool icon
@hedger - uFBT fixes and some bugfixes
@p4nic4ttack - First raw implementation based on doom-nano

View File

@@ -11,4 +11,8 @@ App(
order=75,
fap_icon="doom_10px.png",
fap_category="Games",
fap_icon_assets="assets",
fap_author="@xMasterX & @Svarich & @hedger (original code by @p4nic4ttack)",
fap_version="1.0",
fap_description="Will it run Doom?",
)

View File

@@ -1,78 +1,4 @@
#include "assets_icons.h"
#include <gui/icon_i.h>
// Inverted icons
const uint8_t _I_fire_inv_0[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x30, 0x00, 0x40, 0xee, 0x00, 0x80, 0xe6, 0x00,
0x80, 0xa7, 0x01, 0x80, 0xc7, 0x03, 0x40, 0x45, 0x03, 0xe0, 0x41, 0x07, 0xf8, 0x82, 0x9f, 0xb9,
0x01, 0x3e, 0x7c, 0x00, 0x7a, 0x6e, 0x00, 0x56, 0x1c, 0x00, 0x6c, 0xf4, 0x01, 0x3a, 0x6c, 0x00,
0x7e, 0xfc, 0x00, 0x1a, 0x08, 0x00, 0x3c, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00,
};
const uint8_t* const _I_fire_inv[] = {_I_fire_inv_0};
const uint8_t _I_gun_inv_0[] = {
0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x80, 0x23, 0x00, 0x00, 0x40,
0x20, 0x00, 0x00, 0x40, 0x40, 0x00, 0x00, 0x40, 0x57, 0x00, 0x00, 0x20, 0x8b, 0x00, 0x00,
0x90, 0x11, 0x01, 0x00, 0x98, 0x00, 0x00, 0x00, 0xb0, 0x43, 0x01, 0x00, 0x94, 0x81, 0x03,
0x00, 0xd0, 0x45, 0x04, 0x00, 0x8c, 0x02, 0x02, 0x00, 0xc4, 0x00, 0x03, 0x00, 0xc8, 0x00,
0x02, 0x00, 0x4e, 0x40, 0x00, 0x00, 0x92, 0x00, 0x02, 0x80, 0x07, 0x15, 0x04, 0xe0, 0x8f,
0x00, 0x0c, 0xd0, 0x9d, 0x07, 0x17, 0xe0, 0x3a, 0xc0, 0x3f, 0xe0, 0xf7, 0xff, 0x77, 0xe0,
0xae, 0xfe, 0x4b, 0xd8, 0xdd, 0xff, 0x4d, 0x88, 0xea, 0xbe, 0x26, 0x4c, 0xf5, 0xff, 0x17,
0xc8, 0xfa, 0xae, 0x0b, 0xcc, 0xff, 0xdf, 0x19, 0xe8, 0xeb, 0xa7, 0x00, 0xd8, 0xf1, 0x4d,
0x0c, 0xc0, 0xbe, 0x1a, 0x08, 0xf6, 0xfd, 0x37, 0x04,
};
const uint8_t* const _I_gun_inv[] = {_I_gun_inv_0};
const uint8_t _I_gun_mask_inv_0[] = {
0x01, 0x00, 0x53, 0x00, 0x00, 0x0c, 0x38, 0x04, 0x38, 0x09, 0xf8, 0x0c, 0x78, 0x17, 0xf0,
0x18, 0xf8, 0x00, 0x67, 0xff, 0x01, 0xaf, 0xc3, 0xff, 0x01, 0x80, 0x7e, 0x3f, 0xf0, 0x38,
0x07, 0xf0, 0x0e, 0x40, 0x31, 0x03, 0x8f, 0xfb, 0xff, 0x07, 0x01, 0x94, 0x3c, 0x0e, 0xc0,
0x35, 0xff, 0x85, 0xc8, 0x06, 0x30, 0x7e, 0x00, 0x0c, 0x61, 0xe2, 0xe1, 0xff, 0xc7, 0xc5,
0xc3, 0xff, 0x9f, 0x80, 0xca, 0xfe, 0x03, 0x2f, 0xf8, 0x0c, 0xc6, 0xc2, 0x03, 0x4b, 0xf8,
0xa8, 0x42, 0xe2, 0x03, 0x28, 0xf8, 0x1e, 0x80, 0x68, 0x1e, 0x28, 0x78,
};
const uint8_t* const _I_gun_mask_inv[] = {_I_gun_mask_inv_0};
const uint8_t _I_logo_inv_0[] = {
0x01, 0x00, 0x92, 0x01, 0x00, 0x78, 0x03, 0xc0, 0x03, 0xfc, 0xff, 0xff, 0xfc, 0x1f, 0xf9, 0xff,
0xe3, 0xff, 0x0f, 0x8f, 0xfc, 0x2f, 0xe0, 0xf3, 0xdc, 0x6e, 0xf7, 0x7b, 0x1d, 0xdd, 0xef, 0x79,
0xbb, 0xcd, 0xce, 0xf7, 0x13, 0xb0, 0x79, 0xfc, 0x03, 0xe3, 0xfb, 0x01, 0x0f, 0xfb, 0xff, 0xbf,
0x11, 0x8c, 0x7c, 0x1e, 0x7e, 0x0f, 0x77, 0xbb, 0xd4, 0x02, 0x10, 0x00, 0xeb, 0xad, 0xde, 0xc8,
0x70, 0x3c, 0xf8, 0x01, 0xf7, 0xbf, 0xff, 0x20, 0xe0, 0xf3, 0xc0, 0x6e, 0x80, 0x0d, 0x7a, 0xde,
0x40, 0x83, 0xf8, 0x03, 0x10, 0xfa, 0x70, 0x07, 0xee, 0x02, 0x18, 0x30, 0x3d, 0x0a, 0xe3, 0xfb,
0x83, 0x86, 0xc7, 0x82, 0x1f, 0x1f, 0xf8, 0xfd, 0x61, 0x5a, 0x0d, 0x54, 0x0b, 0x55, 0xaa, 0xc0,
0x00, 0x84, 0x0c, 0x21, 0xf4, 0x8f, 0xf4, 0x3b, 0x70, 0x3e, 0xf7, 0x7b, 0x01, 0x9f, 0xef, 0xf7,
0xc3, 0xfe, 0x1f, 0x6f, 0x87, 0xee, 0x07, 0xfe, 0xff, 0x60, 0x07, 0xfe, 0x1f, 0x88, 0xef, 0xc3,
0xf3, 0x01, 0xfe, 0x7f, 0x30, 0x1b, 0xdf, 0xef, 0xf6, 0x0a, 0x1f, 0xf0, 0x79, 0xd0, 0x22, 0xf7,
0x0b, 0x9c, 0x0e, 0xed, 0x76, 0x80, 0x4d, 0xee, 0xf7, 0x71, 0xff, 0x87, 0xd6, 0x2b, 0x50, 0xa8,
0xc0, 0x6a, 0x95, 0x48, 0x04, 0x56, 0xab, 0x55, 0x1f, 0xf8, 0xff, 0xc7, 0xfe, 0x3f, 0xaa, 0xe4,
0x02, 0x3b, 0x55, 0xae, 0x8f, 0xfc, 0xbf, 0xe1, 0xff, 0x0f, 0xf8, 0x7d, 0x61, 0x18, 0x0c, 0x44,
0x03, 0x11, 0x88, 0x02, 0x0e, 0x23, 0x04, 0x0e, 0x30, 0xfa, 0x41, 0x43, 0xe2, 0x06, 0x18, 0xa8,
0x18, 0x43, 0xe9, 0x02, 0xd0, 0x68, 0xa1, 0x5a, 0x2d, 0x51, 0x10, 0x70, 0x5a, 0x21, 0xfc, 0x45,
0x43, 0xe3, 0x50, 0x0f, 0xc4, 0x20, 0x72, 0x20, 0x22, 0x02, 0x16, 0x00, 0x7e, 0xd5, 0x4a, 0x8d,
0x54, 0x3e, 0x35, 0x40, 0xfb, 0x80, 0x3c, 0x3e, 0x35, 0x5a, 0x09, 0xe8, 0x6a, 0x87, 0xc1, 0x23,
0x88, 0xfd, 0x40, 0x0c, 0x09, 0x20, 0xfa, 0x87, 0x06, 0x00, 0x1f, 0x38, 0x0c, 0x50, 0x3e, 0xa0,
0x0f, 0x0f, 0x8c, 0x56, 0x00, 0x5c, 0x1a, 0x80, 0x90, 0x62, 0x03, 0xf6, 0x80, 0x42, 0x17, 0xc2,
0x7b, 0x10, 0x20, 0x87, 0xde, 0xa9, 0x04, 0x80, 0x54, 0x20, 0x94, 0x08, 0xa0, 0x24, 0x47, 0xf5,
0x01, 0x20, 0x54, 0x44, 0x18, 0x80, 0x42, 0x88, 0x17, 0xfc, 0x7e, 0xb4, 0x40, 0x4c, 0x12, 0x04,
0x01, 0xe3, 0xf4, 0x2a, 0xf8, 0x03, 0xc0, 0x1f, 0xe0, 0xbc, 0xcf, 0xb8, 0xf8, 0x1e, 0xbf, 0xcc,
0x5b, 0x12, 0x0c, 0x56, 0x0a, 0x51, 0x82, 0xa8, 0x28, 0x08, 0x1f, 0x32, 0x0c, 0x00, 0x3e, 0x85,
0xe3, 0x1e, 0x17, 0x8f, 0x4f, 0xe6, 0x1f, 0x99, 0x44, 0x0a, 0x10, 0x2f, 0x13, 0xb4, 0xc8, 0x29,
0x03, 0xf3, 0x89, 0x03, 0xe7, 0x10, 0x5f, 0x2a, 0x87, 0xd1, 0x1b, 0xe0, 0x0f, 0x00, 0x78, 0x03,
0xc0, 0x1e, 0x00, 0xf0, 0x02, 0x00,
};
const uint8_t* const _I_logo_inv[] = {_I_logo_inv_0};
const Icon I_fire_inv =
{.width = 24, .height = 20, .frame_count = 1, .frame_rate = 0, .frames = _I_fire_inv};
const Icon I_gun_inv =
{.width = 32, .height = 32, .frame_count = 1, .frame_rate = 0, .frames = _I_gun_inv};
const Icon I_gun_mask_inv =
{.width = 32, .height = 32, .frame_count = 1, .frame_rate = 0, .frames = _I_gun_mask_inv};
const Icon I_logo_inv =
{.width = 128, .height = 64, .frame_count = 1, .frame_rate = 0, .frames = _I_logo_inv};
#include "assets.h"
const uint8_t space[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
const uint8_t zero[] = {0x00, 0x60, 0x90, 0x90, 0x90, 0x60};

View File

@@ -41,12 +41,6 @@
#define GRADIENT_WHITE 7
#define GRADIENT_BLACK 0
// Inverted icons
extern const Icon I_fire_inv;
extern const Icon I_gun_inv;
extern const Icon I_gun_mask_inv;
extern const Icon I_logo_inv;
// Fonts
extern const uint8_t zero[];
extern const uint8_t one[];

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 MiB

View File

@@ -1,9 +1,8 @@
#include <gui/gui.h>
#include <gui/canvas_i.h>
#include <furi_hal.h>
#include <u8g2_glue.h>
#include "constants.h"
#include "compiled/assets_icons.h"
#include <doom_icons.h>
#include "assets.h"
#define CHECK_BIT(var, pos) ((var) & (1 << (pos)))
@@ -50,14 +49,12 @@ void fadeScreen(uint8_t intensity, bool color, Canvas* const canvas);
bool getGradientPixel(uint8_t x, uint8_t y, uint8_t i);
double getActualFps();
void fps();
void setupDisplay(Canvas* canvas);
uint8_t reverse_bits(uint8_t num);
// FPS control
double delta = 1;
uint32_t lastFrameTime = 0;
uint8_t zbuffer[128]; /// 128 = screen width & REMOVE WHEN DISPLAY.H IMPLEMENTED
uint8_t* display_buf = NULL;
void drawGun(
int16_t x,
@@ -88,12 +85,6 @@ void drawVLine(uint8_t x, int8_t start_y, int8_t end_y, uint8_t intensity, Canva
}
}
void setupDisplay(Canvas* canvas) {
memset(zbuffer, 0xff, 128);
display_buf = (uint8_t*)canvas->fb.tile_buf_ptr;
//display_buf = u8g2_GetBufferPtr(&canvas->fb);
}
void drawBitmap(
int16_t x,
int16_t y,
@@ -102,13 +93,20 @@ void drawBitmap(
int16_t h,
uint16_t color,
Canvas* const canvas) {
UNUSED(color);
canvas_draw_icon_bitmap(canvas, x, y, w, h, i);
UNUSED(w);
UNUSED(h);
if(!color) {
canvas_invert_color(canvas);
}
canvas_draw_icon(canvas, x, y, i);
if(!color) {
canvas_invert_color(canvas);
}
}
void drawText(uint8_t x, uint8_t y, uint8_t num, Canvas* const canvas) {
char buf[4];
itoa(num, buf, 10);
snprintf(buf, 4, "%d", num);
drawTextSpace(x, y, buf, 1, canvas);
}

View File

@@ -6,7 +6,7 @@
#include <sys/time.h>
#include "sound.h"
#include "display.h"
#include "compiled/assets_icons.h"
#include "assets.h"
#include "constants.h"
#include "entities.h"
#include "types.h"
@@ -226,12 +226,12 @@ UID detectCollision(
bool only_walls,
PluginState* const plugin_state) {
// Wall collision
uint8_t round_x = (int)pos->x + (int)relative_x;
uint8_t round_y = (int)pos->y + (int)relative_y;
uint8_t round_x = (int)(pos->x + relative_x);
uint8_t round_y = (int)(pos->y + relative_y);
uint8_t block = getBlockAt(level, round_x, round_y);
if(block == E_WALL) {
//playSound(hit_wall_snd, HIT_WALL_SND_LEN);
// playSound(hit_wall_snd, HIT_WALL_SND_LEN);
return create_uid(block, round_x, round_y);
}
@@ -769,7 +769,6 @@ static void render_callback(Canvas* const canvas, void* ctx) {
furi_assert(ctx);
PluginState* plugin_state = ctx;
furi_mutex_acquire(plugin_state->mutex, FuriWaitForever);
if(plugin_state->init) setupDisplay(canvas);
canvas_set_font(canvas, FontPrimary);
@@ -855,7 +854,6 @@ static void doom_game_update_timer_callback(FuriMessageQueue* event_queue) {
static void doom_game_tick(PluginState* const plugin_state) {
if(plugin_state->scene == GAME_PLAY) {
//fps();
memset(display_buf, 0, SCREEN_WIDTH * (RENDER_HEIGHT / 8));
//player is alive
if(plugin_state->player.health > 0) {
if(plugin_state->up) {
@@ -983,7 +981,7 @@ int32_t doom_app() {
gui_add_view_port(gui, view_port, GuiLayerFullscreen);
//////////////////////////////////
if(display_buf != NULL) plugin_state->init = false;
plugin_state->init = false;
PluginEvent event;
#ifdef SOUND

View File

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

@@ -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=[

View 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 |

View 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

View File

@@ -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);
}

View File

@@ -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);

View File

@@ -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);
}

View File

@@ -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);
}
}
}

View File

@@ -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);

View File

@@ -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;
}
}

View File

@@ -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);

View File

@@ -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);
}

View File

@@ -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);

View File

@@ -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,

View File

@@ -1,4 +1,4 @@
#include <cc1101.h>
#include <cc1101_regs.h>
/* ========================== DATA RATE SETTINGS ===============================
*
* This is how to configure registers MDMCFG3 and MDMCFG4.

View File

@@ -2,7 +2,7 @@
* See the LICENSE file for information about the license. */
#include "app.h"
#include <cc1101.h>
#include <cc1101_regs.h>
static void direct_sampling_timer_start(ProtoViewApp* app);
static void direct_sampling_timer_stop(ProtoViewApp* app);

View File

@@ -8,7 +8,7 @@ App(
order=12,
fap_icon="spectrum_10px.png",
fap_category="Sub-GHz",
fap_author="@xMasterX & @theY4Kman (original by @jolcese)",
fap_version="1.0",
fap_description="Shows received signals on spectrum, not actual analyzer, more like a demo app",
fap_author="@xMasterX & @theY4Kman & @ALEEF02 (original by @jolcese)",
fap_version="1.1",
fap_description="Displays a spectrogram chart to visually represent RF signals around you.",
)