Merge branch 'UNLEASHED' into 420

This commit is contained in:
RogueMaster
2022-11-02 18:13:43 -04:00
110 changed files with 1459 additions and 487 deletions
@@ -0,0 +1,14 @@
App(
appid="am2320_temp_sensor",
name="[AM2320] Temp. Sensor",
apptype=FlipperAppType.EXTERNAL,
entry_point="am_temperature_sensor_app",
cdefines=["APP_AM_TEMPERATURE_SENSOR"],
requires=[
"gui",
],
stack_size=2 * 1024,
order=90,
fap_icon="temperature_sensor.png",
fap_category="GPIO",
)
@@ -0,0 +1,336 @@
/* Flipper Plugin to read the values from a AM2320/AM2321 Sensor */
/* Created by @xMasterX, original app (was used as template) by Mywk - https://github.com/Mywk */
/* Lib used as reference: https://github.com/Gozem/am2320/blob/master/am2321.c*/
#include <furi.h>
#include <furi_hal.h>
#include <furi_hal_i2c.h>
#include <math.h>
#include <gui/gui.h>
#include <input/input.h>
#include <notification/notification_messages.h>
#include <string.h>
#define TS_DEFAULT_VALUE 0xFFFF
#define AM2320_ADDRESS (0x5C << 1)
#define DATA_BUFFER_SIZE 8
// External I2C BUS
#define I2C_BUS &furi_hal_i2c_handle_external
typedef enum {
TSSInitializing,
TSSNoSensor,
TSSPendingUpdate,
} TSStatus;
typedef enum {
TSEventTypeTick,
TSEventTypeInput,
} TSEventType;
typedef struct {
TSEventType type;
InputEvent input;
} TSEvent;
extern const NotificationSequence sequence_blink_red_100;
extern const NotificationSequence sequence_blink_blue_100;
static TSStatus temperature_sensor_current_status = TSSInitializing;
// Temperature and Humidity data buffers, ready to print
char ts_data_buffer_temperature_c[DATA_BUFFER_SIZE];
char ts_data_buffer_temperature_f[DATA_BUFFER_SIZE];
char ts_data_buffer_relative_humidity[DATA_BUFFER_SIZE];
char ts_data_buffer_absolute_humidity[DATA_BUFFER_SIZE];
// CRC16 calculation
static uint16_t get_crc16(const uint8_t* buf, size_t len) {
uint16_t crc = 0xFFFF;
while(len--) {
crc ^= (uint16_t)*buf++;
for(unsigned i = 0; i < 8; i++) {
if(crc & 0x0001) {
crc >>= 1;
crc ^= 0xA001;
} else {
crc >>= 1;
}
}
}
return crc;
}
// Combine bytes
static uint16_t combine_bytes(uint8_t msb, uint8_t lsb) {
return ((uint16_t)msb << 8) | (uint16_t)lsb;
}
// Executes an I2C wake up, sends command and reads result
// true if fetch was successful, false otherwise
static bool temperature_sensor_get_data(uint8_t* buffer, uint8_t size) {
uint32_t timeout = furi_ms_to_ticks(100);
uint8_t cmdbuffer[3] = {0, 0, 0};
bool ret = false;
// Aquire I2C bus
furi_hal_i2c_acquire(I2C_BUS);
// Wake UP AM2320 (sensor goes to sleep to not warm up and affect the humidity sensor)
furi_hal_i2c_is_device_ready(I2C_BUS, (uint8_t)AM2320_ADDRESS, timeout);
// Check if device woken up then we do next stuff
if(furi_hal_i2c_is_device_ready(I2C_BUS, (uint8_t)AM2320_ADDRESS, timeout)) {
// Wait a bit
furi_delay_us(1000);
// Prepare command: Addr 0x03, start register = 0x00, number of registers to read = 0x04
cmdbuffer[0] = 0x03;
cmdbuffer[1] = 0x00;
cmdbuffer[2] = 0x04;
// Transmit command to read registers
ret = furi_hal_i2c_tx(I2C_BUS, (uint8_t)AM2320_ADDRESS, cmdbuffer, 3, timeout);
// Wait a bit
furi_delay_us(1600);
if(ret) {
/*
* Read out 8 bytes of data
* Byte 0: Should be Modbus function code 0x03
* Byte 1: Should be number of registers to read (0x04)
* Byte 2: Humidity msb
* Byte 3: Humidity lsb
* Byte 4: Temperature msb
* Byte 5: Temperature lsb
* Byte 6: CRC lsb byte
* Byte 7: CRC msb byte
*/
ret = furi_hal_i2c_rx(I2C_BUS, (uint8_t)AM2320_ADDRESS, buffer, size, timeout);
}
}
// Release i2c bus
furi_hal_i2c_release(I2C_BUS);
return ret;
}
// Fetches temperature and humidity from sensor
// Temperature and humidity must be preallocated
// true if fetch was successful, false otherwise
static bool temperature_sensor_fetch_info(double* temperature, double* humidity) {
*humidity = (float)0;
bool ret = false;
uint8_t buffer[8] = {0, 0, 0, 0, 0, 0, 0, 0};
// Fetch data from sensor
ret = temperature_sensor_get_data(buffer, 8);
// If we got no result
if(!ret) return false;
if(buffer[0] != 0x03) return false; // must be 0x03 modbus reply
if(buffer[1] != 0x04) return false; // must be 0x04 number of registers reply
// Check CRC16 sum, if not correct - return false
uint16_t crcdata = get_crc16(buffer, 6);
uint16_t crcread = combine_bytes(buffer[7], buffer[6]);
if(crcdata != crcread) return false;
// Combine bytes for temp and humidity
uint16_t temp16 = combine_bytes(buffer[4], buffer[5]);
uint16_t humi16 = combine_bytes(buffer[2], buffer[3]);
/* Temperature resolution is 16Bit,
* temperature highest bit (Bit15) is equal to 1 indicates a
* negative temperature, the temperature highest bit (Bit15)
* is equal to 0 indicates a positive temperature;
* temperature in addition to the most significant bit (Bit14 ~ Bit0)
* indicates the temperature sensor string value.
* Temperature sensor value is a string of 10 times the
* actual temperature value.
*/
if(temp16 & 0x8000) {
temp16 = -(temp16 & 0x7FFF);
}
// Prepare output data
*temperature = (float)temp16 / 10.0;
*humidity = (float)humi16 / 10.0;
return true;
}
// Draw callback
static void temperature_sensor_draw_callback(Canvas* canvas, void* ctx) {
UNUSED(ctx);
canvas_clear(canvas);
canvas_set_font(canvas, FontPrimary);
canvas_draw_str(canvas, 2, 10, "AM2320/AM2321 Sensor");
canvas_set_font(canvas, FontSecondary);
canvas_draw_str(canvas, 2, 62, "Press back to exit.");
switch(temperature_sensor_current_status) {
case TSSInitializing:
canvas_draw_str(canvas, 2, 30, "Initializing..");
break;
case TSSNoSensor:
canvas_draw_str(canvas, 2, 30, "No sensor found!");
break;
case TSSPendingUpdate: {
canvas_draw_str(canvas, 3, 24, "Temperature");
canvas_draw_str(canvas, 68, 24, "Humidity");
// Draw vertical lines
canvas_draw_line(canvas, 61, 16, 61, 50);
canvas_draw_line(canvas, 62, 16, 62, 50);
// Draw horizontal line
canvas_draw_line(canvas, 2, 27, 122, 27);
// Draw temperature and humidity values
canvas_draw_str(canvas, 8, 38, ts_data_buffer_temperature_c);
canvas_draw_str(canvas, 42, 38, "C");
canvas_draw_str(canvas, 8, 48, ts_data_buffer_temperature_f);
canvas_draw_str(canvas, 42, 48, "F");
canvas_draw_str(canvas, 68, 38, ts_data_buffer_relative_humidity);
canvas_draw_str(canvas, 100, 38, "%");
canvas_draw_str(canvas, 68, 48, ts_data_buffer_absolute_humidity);
canvas_draw_str(canvas, 100, 48, "g/m3");
} break;
default:
break;
}
}
// Input callback
static void temperature_sensor_input_callback(InputEvent* input_event, void* ctx) {
furi_assert(ctx);
FuriMessageQueue* event_queue = ctx;
TSEvent event = {.type = TSEventTypeInput, .input = *input_event};
furi_message_queue_put(event_queue, &event, FuriWaitForever);
}
// Timer callback
static void temperature_sensor_timer_callback(FuriMessageQueue* event_queue) {
furi_assert(event_queue);
TSEvent event = {.type = TSEventTypeTick};
furi_message_queue_put(event_queue, &event, 0);
}
// App entry point
int32_t am_temperature_sensor_app(void* p) {
UNUSED(p);
furi_hal_power_suppress_charge_enter();
// Declare our variables and assign variables a default value
TSEvent tsEvent;
bool sensorFound = false;
double celsius, fahrenheit, rel_humidity, abs_humidity = TS_DEFAULT_VALUE;
// Used for absolute humidity calculation
double vapour_pressure = 0;
FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(TSEvent));
// Register callbacks
ViewPort* view_port = view_port_alloc();
view_port_draw_callback_set(view_port, temperature_sensor_draw_callback, NULL);
view_port_input_callback_set(view_port, temperature_sensor_input_callback, event_queue);
// Create timer and register its callback
FuriTimer* timer =
furi_timer_alloc(temperature_sensor_timer_callback, FuriTimerTypePeriodic, event_queue);
furi_timer_start(timer, furi_kernel_get_tick_frequency());
// Register viewport
Gui* gui = furi_record_open(RECORD_GUI);
gui_add_view_port(gui, view_port, GuiLayerFullscreen);
// Used to notify the user by blinking red (error) or blue (fetch successful)
NotificationApp* notifications = furi_record_open(RECORD_NOTIFICATION);
while(1) {
furi_check(furi_message_queue_get(event_queue, &tsEvent, FuriWaitForever) == FuriStatusOk);
// Handle events
if(tsEvent.type == TSEventTypeInput) {
// Exit on back key
if(tsEvent.input.key ==
InputKeyBack) // We dont check for type here, we can check the type of keypress like: (event.input.type == InputTypeShort)
break;
} else if(tsEvent.type == TSEventTypeTick) {
// Update sensor data
// Fetch data and set the sensor current status accordingly
sensorFound = temperature_sensor_fetch_info(&celsius, &rel_humidity);
temperature_sensor_current_status = (sensorFound ? TSSPendingUpdate : TSSNoSensor);
if(sensorFound) {
// Blink blue
notification_message(notifications, &sequence_blink_blue_100);
if(celsius != TS_DEFAULT_VALUE && rel_humidity != TS_DEFAULT_VALUE) {
// Convert celsius to fahrenheit
fahrenheit = (celsius * 9 / 5) + 32;
// Calculate absolute humidity - For more info refer to https://github.com/Mywk/FlipperTemperatureSensor/issues/1
// Calculate saturation vapour pressure first
vapour_pressure =
(double)6.11 *
pow(10, (double)(((double)7.5 * celsius) / ((double)237.3 + celsius)));
// Then the vapour pressure in Pa
vapour_pressure = vapour_pressure * rel_humidity;
// Calculate absolute humidity
abs_humidity =
(double)2.16679 * (double)(vapour_pressure / ((double)273.15 + celsius));
// Fill our buffers here, not on the canvas draw callback
snprintf(ts_data_buffer_temperature_c, DATA_BUFFER_SIZE, "%.2f", celsius);
snprintf(ts_data_buffer_temperature_f, DATA_BUFFER_SIZE, "%.2f", fahrenheit);
snprintf(
ts_data_buffer_relative_humidity, DATA_BUFFER_SIZE, "%.2f", rel_humidity);
snprintf(
ts_data_buffer_absolute_humidity, DATA_BUFFER_SIZE, "%.2f", abs_humidity);
}
} else {
// Reset our variables to their default values
celsius = fahrenheit = rel_humidity = abs_humidity = TS_DEFAULT_VALUE;
// Blink red
notification_message(notifications, &sequence_blink_red_100);
}
}
uint32_t wait_ticks = furi_ms_to_ticks(!sensorFound ? 100 : 500);
furi_delay_tick(wait_ticks);
}
furi_hal_power_suppress_charge_exit();
// Dobby is freee (free our variables, Flipper will crash if we don't do this!)
furi_timer_free(timer);
gui_remove_view_port(gui, view_port);
view_port_free(view_port);
furi_message_queue_free(event_queue);
furi_record_close(RECORD_NOTIFICATION);
furi_record_close(RECORD_GUI);
return 0;
}

Before

Width:  |  Height:  |  Size: 181 B

After

Width:  |  Height:  |  Size: 181 B

@@ -448,14 +448,13 @@ int32_t arkanoid_game_app(void* p) {
arkanoid_state->ball_state.dy = -1;
//start the game flag
arkanoid_state->gameStarted = true;
break;
}
break;
default:
break;
}
}
}
} else {
// Event timeout
FURI_LOG_D(TAG, "furi_message_queue: Event timeout");
}
view_port_update(view_port);
@@ -523,12 +523,11 @@ int32_t barcode_UPCA_generator_app(void* p) {
plugin_state->modeIndex = 0;
}
break;
default:
break;
}
}
}
} else {
FURI_LOG_D("barcode_UPCA_generator", "osMessageQueue: event timeout");
// event timeout
}
view_port_update(view_port);
@@ -442,6 +442,8 @@ int32_t quenon_dht_mon_app() {
case InputKeyBack:
processing = false;
break;
default:
break;
}
}
}
@@ -93,6 +93,9 @@ void sensorEdit_scene(PluginData* app) {
app->item, DHTMon_GPIO_getName(app->currentSensorEdit->GPIO));
variable_item_list_add(variable_item_list, "Save", 1, NULL, app);
//Сброс выбранного пункта в ноль
variable_item_list_set_selected_item(variable_item_list, 0);
view_dispatcher_switch_to_view(app->view_dispatcher, ADDSENSOR_MENU_VIEW);
}
void sensorEdit_sceneRemove(void) {
@@ -350,14 +350,13 @@ int32_t flappy_game_app(void* p) {
case InputKeyBack:
processing = false;
break;
default:
break;
}
}
} else if(event.type == EventTypeTick) {
flappy_game_tick(game_state);
}
} else {
// FURI_LOG_D(TAG, "osMessageQueue: event timeout");
// event timeout
}
view_port_update(view_port);
@@ -134,6 +134,8 @@ void flipfrid_scene_entrypoint_on_event(FlipFridEvent event, FlipFridState* cont
case InputKeyBack:
context->is_running = false;
break;
default:
break;
}
}
}
@@ -72,6 +72,8 @@ void flipfrid_scene_load_custom_uids_on_event(FlipFridEvent event, FlipFridState
case InputKeyBack:
context->current_scene = SceneEntryPoint;
break;
default:
break;
}
}
}
@@ -159,6 +159,8 @@ void flipfrid_scene_load_file_on_event(FlipFridEvent event, FlipFridState* conte
case InputKeyBack:
context->current_scene = SceneEntryPoint;
break;
default:
break;
}
}
}
@@ -546,6 +546,8 @@ void flipfrid_scene_run_attack_on_event(FlipFridEvent event, FlipFridState* cont
notification_message(context->notify, &sequence_blink_stop);
context->current_scene = SceneEntryPoint;
break;
default:
break;
}
}
}
@@ -129,6 +129,8 @@ void flipfrid_scene_select_field_on_event(FlipFridEvent event, FlipFridState* co
furi_string_reset(context->notification_msg);
context->current_scene = SceneSelectFile;
break;
default:
break;
}
FURI_LOG_D(TAG, "Position: %d/%d", context->key_index, nb_bytes);
}
+2 -1
View File
@@ -1,6 +1,8 @@
# Game "15" for Flipper Zero
[Original link](https://github.com/x27/flipperzero-game15)
Logic game [Wikipedia](https://en.wikipedia.org/wiki/15_puzzle)
![Game screen](images/Game15.png)
@@ -9,4 +11,3 @@ Logic game [Wikipedia](https://en.wikipedia.org/wiki/15_puzzle)
![Popoup](images/Game15Popup.png)
FAP file for firmware 0.69.1
+2
View File
@@ -426,6 +426,8 @@ static void game_event_handler(GameEvent const event) {
sandbox_loop_exit();
}
break;
default:
break;
}
}
} else if(event.type == EventTypeTick) {
@@ -1,6 +1,8 @@
# GPS for Flipper Zero
A simple Flipper Zero application for NMEA 0183 serial GPS modules, such as the
[Original link](https://github.com/ezod/flipperzero-gps)
[Adafruit Ultimate GPS Breakout].
[Original link](https://github.com/ezod/flipperzero-gps)
+2 -2
View File
@@ -110,11 +110,11 @@ int32_t gps_app(void* p) {
case InputKeyBack:
processing = false;
break;
default:
break;
}
}
}
} else {
FURI_LOG_D("GPS", "FuriMessageQueue: event timeout");
}
view_port_update(view_port);
+2
View File
@@ -230,6 +230,8 @@ int32_t hc_sr04_app() {
case InputKeyBack:
processing = false;
break;
default:
break;
}
}
}

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 2.0 KiB

Before

Width:  |  Height:  |  Size: 274 KiB

After

Width:  |  Height:  |  Size: 274 KiB

Before

Width:  |  Height:  |  Size: 914 KiB

After

Width:  |  Height:  |  Size: 914 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 181 B

@@ -320,6 +320,8 @@ int32_t metronome_app() {
case InputKeyBack:
processing = false;
break;
default:
break;
}
} else if(event.input.type == InputTypeLong) {
// hold events
@@ -340,6 +342,8 @@ int32_t metronome_app() {
case InputKeyBack:
processing = false;
break;
default:
break;
}
} else if(event.input.type == InputTypeRepeat) {
// repeat events
@@ -359,6 +363,8 @@ int32_t metronome_app() {
case InputKeyBack:
processing = false;
break;
default:
break;
}
}
}
@@ -476,6 +476,8 @@ int32_t minesweeper_app(void* p) {
// Exit the plugin
processing = false;
break;
default:
break;
}
} else if(event.input.type == InputTypeLong) {
// hold events
@@ -493,6 +495,8 @@ int32_t minesweeper_app(void* p) {
case InputKeyBack:
processing = false;
break;
default:
break;
}
}
}
+50 -47
View File
@@ -27,7 +27,6 @@ typedef struct {
MorseCodeWorker* worker;
} MorseCode;
static void render_callback(Canvas* const canvas, void* ctx) {
MorseCode* morse_code = ctx;
furi_check(furi_mutex_acquire(morse_code->model_mutex, FuriWaitForever) == FuriStatusOk);
@@ -35,20 +34,26 @@ static void render_callback(Canvas* const canvas, void* ctx) {
canvas_set_font(canvas, FontPrimary);
//write words
elements_multiline_text_aligned(canvas, 64, 30, AlignCenter, AlignCenter, furi_string_get_cstr(morse_code->model->words));
// volume view_port
elements_multiline_text_aligned(
canvas, 64, 30, AlignCenter, AlignCenter, furi_string_get_cstr(morse_code->model->words));
// volume view_port
uint8_t vol_bar_x_pos = 124;
uint8_t vol_bar_y_pos = 0;
const uint8_t volume_h =
(64 / (COUNT_OF(MORSE_CODE_VOLUMES) - 1)) * morse_code->model->volume;
const uint8_t volume_h = (64 / (COUNT_OF(MORSE_CODE_VOLUMES) - 1)) * morse_code->model->volume;
canvas_draw_frame(canvas, vol_bar_x_pos, vol_bar_y_pos, 4, 64);
canvas_draw_box(canvas, vol_bar_x_pos, vol_bar_y_pos + (64 - volume_h), 4, volume_h);
//dit bpm
canvas_draw_str_aligned(
canvas, 0, 10, AlignLeft, AlignCenter, furi_string_get_cstr(furi_string_alloc_printf("Dit: %ld ms", morse_code->model->dit_delta)));
canvas,
0,
10,
AlignLeft,
AlignCenter,
furi_string_get_cstr(
furi_string_alloc_printf("Dit: %ld ms", morse_code->model->dit_delta)));
//button info
elements_button_center(canvas, "Press/Hold");
furi_mutex_release(morse_code->model_mutex);
@@ -59,9 +64,7 @@ static void input_callback(InputEvent* input_event, void* ctx) {
furi_message_queue_put(morse_code->input_queue, input_event, FuriWaitForever);
}
static void morse_code_worker_callback(
FuriString* words,
void* context) {
static void morse_code_worker_callback(FuriString* words, void* context) {
MorseCode* morse_code = context;
furi_check(furi_mutex_acquire(morse_code->model_mutex, FuriWaitForever) == FuriStatusOk);
morse_code->model->words = words;
@@ -115,45 +118,45 @@ int32_t morse_code_app() {
InputEvent input;
morse_code_worker_start(morse_code->worker);
morse_code_worker_set_volume(
morse_code->worker, MORSE_CODE_VOLUMES[morse_code->model->volume]);
morse_code_worker_set_dit_delta(morse_code->worker, morse_code->model->dit_delta);
while(furi_message_queue_get(morse_code->input_queue, &input, FuriWaitForever) == FuriStatusOk){
morse_code->worker, MORSE_CODE_VOLUMES[morse_code->model->volume]);
morse_code_worker_set_dit_delta(morse_code->worker, morse_code->model->dit_delta);
while(furi_message_queue_get(morse_code->input_queue, &input, FuriWaitForever) ==
FuriStatusOk) {
furi_check(furi_mutex_acquire(morse_code->model_mutex, FuriWaitForever) == FuriStatusOk);
if(input.key == InputKeyBack) {
furi_mutex_release(morse_code->model_mutex);
break;
}else if(input.key == InputKeyOk){
if(input.type == InputTypePress)
morse_code_worker_play(morse_code->worker, true);
else if(input.type == InputTypeRelease)
morse_code_worker_play(morse_code->worker, false);
}else if(input.key == InputKeyUp && input.type == InputTypePress){
if(morse_code->model->volume < COUNT_OF(MORSE_CODE_VOLUMES) - 1)
morse_code->model->volume++;
morse_code_worker_set_volume(
morse_code->worker, MORSE_CODE_VOLUMES[morse_code->model->volume]);
}else if(input.key == InputKeyDown && input.type == InputTypePress){
if(morse_code->model->volume > 0)
morse_code->model->volume--;
morse_code_worker_set_volume(
morse_code->worker, MORSE_CODE_VOLUMES[morse_code->model->volume]);
}else if(input.key == InputKeyLeft && input.type == InputTypePress){
if(morse_code->model->dit_delta > 10)
morse_code->model->dit_delta-=10;
morse_code_worker_set_dit_delta(
morse_code->worker, morse_code->model->dit_delta);
}
else if(input.key == InputKeyRight && input.type == InputTypePress){
if(morse_code->model->dit_delta >= 10)
morse_code->model->dit_delta+=10;
morse_code_worker_set_dit_delta(
morse_code->worker, morse_code->model->dit_delta);
}
FURI_LOG_D("Input", "%s %s %ld", input_get_key_name(input.key), input_get_type_name(input.type), input.sequence);
furi_mutex_release(morse_code->model_mutex);
break;
} else if(input.key == InputKeyOk) {
if(input.type == InputTypePress)
morse_code_worker_play(morse_code->worker, true);
else if(input.type == InputTypeRelease)
morse_code_worker_play(morse_code->worker, false);
} else if(input.key == InputKeyUp && input.type == InputTypePress) {
if(morse_code->model->volume < COUNT_OF(MORSE_CODE_VOLUMES) - 1)
morse_code->model->volume++;
morse_code_worker_set_volume(
morse_code->worker, MORSE_CODE_VOLUMES[morse_code->model->volume]);
} else if(input.key == InputKeyDown && input.type == InputTypePress) {
if(morse_code->model->volume > 0) morse_code->model->volume--;
morse_code_worker_set_volume(
morse_code->worker, MORSE_CODE_VOLUMES[morse_code->model->volume]);
} else if(input.key == InputKeyLeft && input.type == InputTypePress) {
if(morse_code->model->dit_delta > 10) morse_code->model->dit_delta -= 10;
morse_code_worker_set_dit_delta(morse_code->worker, morse_code->model->dit_delta);
} else if(input.key == InputKeyRight && input.type == InputTypePress) {
if(morse_code->model->dit_delta >= 10) morse_code->model->dit_delta += 10;
morse_code_worker_set_dit_delta(morse_code->worker, morse_code->model->dit_delta);
}
FURI_LOG_D(
"Input",
"%s %s %ld",
input_get_key_name(input.key),
input_get_type_name(input.type),
input.sequence);
furi_mutex_release(morse_code->model_mutex);
view_port_update(morse_code->view_port);
view_port_update(morse_code->view_port);
}
morse_code_worker_stop(morse_code->worker);
morse_code_free(morse_code);
@@ -2,19 +2,20 @@
#include <furi_hal.h>
#include <lib/flipper_format/flipper_format.h>
#define TAG "MorseCodeWorker"
#define MORSE_CODE_VERSION 0
//A-Z0-1
const char morse_array[36][6] ={
".-", "-...", "-.-.", "-..", ".", "..-.", "--.", "....", "..", ".---", "-.-", ".-..", "--", "-.", "---", ".--.",
"--.-", ".-.", "...", "-", "..-", "...-", ".--", "-..-", "-.--", "--..", ".----", "..---", "...--", "....-", ".....",
"-....", "--...", "---..", "----.", "-----"
};
const char symbol_array[36] = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
'U', 'V', 'W', 'X', 'Y', 'Z', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0'};
const char morse_array[36][6] = {".-", "-...", "-.-.", "-..", ".", "..-.",
"--.", "....", "..", ".---", "-.-", ".-..",
"--", "-.", "---", ".--.", "--.-", ".-.",
"...", "-", "..-", "...-", ".--", "-..-",
"-.--", "--..", ".----", "..---", "...--", "....-",
".....", "-....", "--...", "---..", "----.", "-----"};
const char symbol_array[36] = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L',
'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
'Y', 'Z', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0'};
struct MorseCodeWorker {
FuriThread* thread;
@@ -28,31 +29,28 @@ struct MorseCodeWorker {
FuriString* words;
};
void morse_code_worker_fill_buffer(MorseCodeWorker* instance, uint32_t duration){
void morse_code_worker_fill_buffer(MorseCodeWorker* instance, uint32_t duration) {
FURI_LOG_D("MorseCode: Duration", "%ld", duration);
if( duration <= instance->dit_delta)
if(duration <= instance->dit_delta)
furi_string_push_back(instance->buffer, *DOT);
else if(duration <= (instance->dit_delta * 3))
furi_string_push_back(instance->buffer, *LINE);
if(furi_string_size(instance->buffer) > 5)
furi_string_reset(instance->buffer);
if(furi_string_size(instance->buffer) > 5) furi_string_reset(instance->buffer);
FURI_LOG_D("MorseCode: Buffer", "%s", furi_string_get_cstr(instance->buffer));
}
void morse_code_worker_fill_letter(MorseCodeWorker* instance){
if(furi_string_size(instance->words) > 63)
furi_string_reset(instance->words);
for (size_t i = 0; i < sizeof(morse_array); i++){
if(furi_string_cmp_str(instance->buffer, morse_array[i]) == 0){
furi_string_push_back(instance->words, symbol_array[i]);
furi_string_reset(instance->buffer);
break;
}
void morse_code_worker_fill_letter(MorseCodeWorker* instance) {
if(furi_string_size(instance->words) > 63) furi_string_reset(instance->words);
for(size_t i = 0; i < sizeof(morse_array); i++) {
if(furi_string_cmp_str(instance->buffer, morse_array[i]) == 0) {
furi_string_push_back(instance->words, symbol_array[i]);
furi_string_reset(instance->buffer);
break;
}
}
FURI_LOG_D("MorseCode: Words", "%s", furi_string_get_cstr(instance->words));
}
static int32_t morse_code_worker_thread_callback(void* context) {
furi_assert(context);
MorseCodeWorker* instance = context;
@@ -61,16 +59,16 @@ static int32_t morse_code_worker_thread_callback(void* context) {
uint32_t end_tick = 0;
bool pushed = true;
bool spaced = true;
while(instance->is_running){
while(instance->is_running) {
furi_delay_ms(SLEEP);
if(instance->play){
if(!was_playing){
if(instance->play) {
if(!was_playing) {
start_tick = furi_get_tick();
furi_hal_speaker_start(FREQUENCY, instance->volume);
was_playing = true;
}
}else{
if(was_playing){
} else {
if(was_playing) {
pushed = false;
spaced = false;
furi_hal_speaker_stop();
@@ -80,21 +78,21 @@ static int32_t morse_code_worker_thread_callback(void* context) {
start_tick = 0;
}
}
if(!pushed){
if(end_tick + (instance->dit_delta * 3) < furi_get_tick()){
if(!pushed) {
if(end_tick + (instance->dit_delta * 3) < furi_get_tick()) {
//NEW LETTER
morse_code_worker_fill_letter(instance);
if(instance->callback)
instance->callback(instance->words, instance->callback_context);
instance->callback(instance->words, instance->callback_context);
pushed = true;
}
}
if(!spaced){
if(end_tick + (instance->dit_delta * 7) < furi_get_tick()){
if(!spaced) {
if(end_tick + (instance->dit_delta * 7) < furi_get_tick()) {
//NEW WORD
furi_string_push_back(instance->words, *SPACE);
if(instance->callback)
instance->callback(instance->words, instance->callback_context);
instance->callback(instance->words, instance->callback_context);
spaced = true;
}
}
@@ -132,17 +130,17 @@ void morse_code_worker_set_callback(
instance->callback_context = context;
}
void morse_code_worker_play(MorseCodeWorker* instance, bool play){
void morse_code_worker_play(MorseCodeWorker* instance, bool play) {
furi_assert(instance);
instance->play = play;
}
void morse_code_worker_set_volume(MorseCodeWorker* instance, float level){
void morse_code_worker_set_volume(MorseCodeWorker* instance, float level) {
furi_assert(instance);
instance->volume = level;
}
void morse_code_worker_set_dit_delta(MorseCodeWorker* instance, uint32_t delta){
void morse_code_worker_set_dit_delta(MorseCodeWorker* instance, uint32_t delta) {
furi_assert(instance);
instance->dit_delta = delta;
}
@@ -10,9 +10,7 @@
#define LINE "-"
#define SPACE " "
typedef void (*MorseCodeWorkerCallback)(
FuriString* buffer,
void* context);
typedef void (*MorseCodeWorkerCallback)(FuriString* buffer, void* context);
typedef struct MorseCodeWorker MorseCodeWorker;
@@ -34,9 +32,3 @@ void morse_code_worker_play(MorseCodeWorker* instance, bool play);
void morse_code_worker_set_volume(MorseCodeWorker* instance, float level);
void morse_code_worker_set_dit_delta(MorseCodeWorker* instance, uint32_t delta);
@@ -374,6 +374,8 @@ int32_t mousejacker_app(void* p) {
plugin_state->close_thread_please = false;
processing = false;
break;
default:
break;
}
}
}
@@ -384,7 +386,7 @@ int32_t mousejacker_app(void* p) {
}
furi_thread_free(plugin_state->mjthread);
furi_hal_spi_release(nrf24_HANDLE);
nrf24_deinit();
view_port_enabled_set(view_port, false);
gui_remove_view_port(gui, view_port);
furi_record_close(RECORD_GUI);
+3 -1
View File
@@ -400,6 +400,8 @@ int32_t nrfsniff_app(void* p) {
case InputKeyBack:
if(event.input.type == InputTypeLong) processing = false;
break;
default:
break;
}
}
}
@@ -444,7 +446,7 @@ int32_t nrfsniff_app(void* p) {
sample_time = DEFAULT_SAMPLE_TIME;
target_rate = 8; // rate can be either 8 (2Mbps) or 0 (1Mbps)
sniffing_state = false;
furi_hal_spi_release(nrf24_HANDLE);
nrf24_deinit();
view_port_enabled_set(view_port, false);
gui_remove_view_port(gui, view_port);
furi_record_close(RECORD_GUI);
Binary file not shown.

After

Width:  |  Height:  |  Size: 308 B

@@ -9,7 +9,8 @@ App(
],
stack_size=4 * 1024,
order=175,
fap_icon="../../../assets/icons/Archive/125_10px.png",
order=30,
fap_icon="125_10px.png",
fap_category="Tools",
fap_libs=["mbedtls"],
fap_private_libs=[
@@ -9,8 +9,6 @@
#include <furi_hal.h>
#include <stdlib.h>
#include <st25r3916.h>
#include <rfal_analogConfig.h>
#include <rfal_rf.h>
#include <platform.h>
@@ -1,5 +1,4 @@
#include "rfal_picopass.h"
#include "utils.h"
#define RFAL_PICOPASS_TXRX_FLAGS \
(FURI_HAL_NFC_LL_TXRX_FLAGS_CRC_TX_MANUAL | FURI_HAL_NFC_LL_TXRX_FLAGS_AGC_ON | \
@@ -97,7 +96,7 @@ FuriHalNfcReturn rfalPicoPassPollerSelect(uint8_t* csn, rfalPicoPassSelectRes* s
rfalPicoPassSelectReq selReq;
selReq.CMD = RFAL_PICOPASS_CMD_SELECT;
ST_MEMCPY(selReq.CSN, csn, RFAL_PICOPASS_UID_LEN);
memcpy(selReq.CSN, csn, RFAL_PICOPASS_UID_LEN);
uint16_t recvLen = 0;
uint32_t flags = RFAL_PICOPASS_TXRX_FLAGS;
uint32_t fwt = furi_hal_nfc_ll_ms2fc(20);
@@ -146,8 +145,8 @@ FuriHalNfcReturn rfalPicoPassPollerCheck(uint8_t* mac, rfalPicoPassCheckRes* chk
FuriHalNfcReturn ret;
rfalPicoPassCheckReq chkReq;
chkReq.CMD = RFAL_PICOPASS_CMD_CHECK;
ST_MEMCPY(chkReq.mac, mac, 4);
ST_MEMSET(chkReq.null, 0, 4);
memcpy(chkReq.mac, mac, 4);
memset(chkReq.null, 0, 4);
uint16_t recvLen = 0;
uint32_t flags = RFAL_PICOPASS_TXRX_FLAGS;
uint32_t fwt = furi_hal_nfc_ll_ms2fc(20);
@@ -143,6 +143,8 @@ int32_t sentry_safe_app(void* p) {
case InputKeyBack:
processing = false;
break;
default:
break;
}
}
}
+4 -2
View File
@@ -167,8 +167,8 @@ static Point snake_game_get_new_fruit(SnakeState const* const snake_state) {
if((buffer[y] & mask) == 0) {
if(newFruit == 0) {
Point p = {
.x = x,
.y = y,
.x = x * 2,
.y = y * 2,
};
return p;
}
@@ -361,6 +361,8 @@ int32_t snake_game_app(void* p) {
snake_game_save_game_to_file(snake_state);
processing = false;
break;
default:
break;
}
}
} else if(event.type == EventTypeTick) {
@@ -496,6 +496,8 @@ int32_t spectrum_analyzer_app(void* p) {
case InputKeyBack:
exit_loop = true;
break;
default:
break;
}
furi_mutex_release(spectrum_analyzer->model_mutex);
@@ -442,6 +442,8 @@ int32_t tetris_game_app() {
case InputKeyBack:
processing = false;
break;
default:
break;
}
}
} else if(event.type == EventTypeTick) {
@@ -358,12 +358,11 @@ int32_t tictactoe_game_app(void* p) {
case InputKeyOk:
tictactoe_state->button_state = true;
break;
default:
break;
}
}
}
} else {
// Event timeout
FURI_LOG_D(TAG, "furi_message_queue: Event timeout");
}
view_port_update(view_port);
@@ -282,6 +282,8 @@ bool totp_scene_add_new_token_handle_event(PluginEvent* const event, PluginState
totp_scene_director_activate_scene(plugin_state, TotpSceneGenerateToken, NULL);
}
break;
default:
break;
}
}
}
@@ -158,6 +158,8 @@ bool totp_scene_app_settings_handle_event(PluginEvent* const event, PluginState*
}
break;
}
default:
break;
}
}
}
@@ -143,6 +143,8 @@ bool totp_scene_authenticate_handle_event(PluginEvent* const event, PluginState*
scene_state->code_length--;
}
break;
default:
break;
}
}
}
@@ -303,6 +303,8 @@ bool totp_scene_generate_token_handle_event(PluginEvent* const event, PluginStat
break;
case InputKeyBack:
break;
default:
break;
}
}
}
@@ -179,6 +179,8 @@ bool totp_scene_token_menu_handle_event(PluginEvent* const event, PluginState* p
}
break;
}
default:
break;
}
}
}
@@ -1064,6 +1064,8 @@ int32_t unirfremix_app(void* p) {
unirfremix_tx_stop(app);
exit_loop = true;
break;
default:
break;
}
if(app->processing == 0) {
@@ -1135,6 +1137,8 @@ int32_t unirfremix_app(void* p) {
case InputKeyBack:
exit_loop = true;
break;
default:
break;
}
if(exit_loop == true) {
@@ -3,7 +3,7 @@
#include <furi.h>
#include <furi_hal.h>
#define WS_VERSION_APP "0.3.1"
#define WS_VERSION_APP "0.4"
#define WS_DEVELOPED "SkorP"
#define WS_GITHUB "https://github.com/flipperdevices/flipperzero-firmware"
@@ -4,7 +4,7 @@
/*
* Help
* https://github.com/merbanan/rtl_433/blob/5bef4e43133ac4c0e2d18d36f87c52b4f9458453/src/devices/acurite.c
* https://github.com/merbanan/rtl_433/blob/master/src/devices/acurite.c
*
* Acurite 592TXR Temperature Humidity sensor decoder
* Message Type 0x04, 7 bytes
@@ -0,0 +1,278 @@
#include "ambient_weather.h"
#include <lib/toolbox/manchester_decoder.h>
#define TAG "WSProtocolAmbient_Weather"
/*
* Help
* https://github.com/merbanan/rtl_433/blob/master/src/devices/ambient_weather.c
*
* Decode Ambient Weather F007TH, F012TH, TF 30.3208.02, SwitchDoc F016TH.
* Devices supported:
* - Ambient Weather F007TH Thermo-Hygrometer.
* - Ambient Weather F012TH Indoor/Display Thermo-Hygrometer.
* - TFA senders 30.3208.02 from the TFA "Klima-Monitor" 30.3054,
* - SwitchDoc Labs F016TH.
* This decoder handles the 433mhz/868mhz thermo-hygrometers.
* The 915mhz (WH*) family of devices use different modulation/encoding.
* Byte 0 Byte 1 Byte 2 Byte 3 Byte 4 Byte 5
* xxxxMMMM IIIIIIII BCCCTTTT TTTTTTTT HHHHHHHH MMMMMMMM
* - x: Unknown 0x04 on F007TH/F012TH
* - M: Model Number?, 0x05 on F007TH/F012TH/SwitchDocLabs F016TH
* - I: ID byte (8 bits), volatie, changes at power up,
* - B: Battery Low
* - C: Channel (3 bits 1-8) - F007TH set by Dip switch, F012TH soft setting
* - T: Temperature 12 bits - Fahrenheit * 10 + 400
* - H: Humidity (8 bits)
* - M: Message integrity check LFSR Digest-8, gen 0x98, key 0x3e, init 0x64
*
* three repeats without gap
* full preamble is 0x00145 (the last bits might not be fixed, e.g. 0x00146)
* and on decoding also 0xffd45
*/
#define AMBIENT_WEATHER_PACKET_HEADER_1 0xFFD440000000000 //0xffd45 .. 0xffd46
#define AMBIENT_WEATHER_PACKET_HEADER_2 0x001440000000000 //0x00145 .. 0x00146
#define AMBIENT_WEATHER_PACKET_HEADER_MASK 0xFFFFC0000000000
static const SubGhzBlockConst ws_protocol_ambient_weather_const = {
.te_short = 500,
.te_long = 1000,
.te_delta = 120,
.min_count_bit_for_found = 48,
};
struct WSProtocolDecoderAmbient_Weather {
SubGhzProtocolDecoderBase base;
SubGhzBlockDecoder decoder;
WSBlockGeneric generic;
ManchesterState manchester_saved_state;
uint16_t header_count;
};
struct WSProtocolEncoderAmbient_Weather {
SubGhzProtocolEncoderBase base;
SubGhzProtocolBlockEncoder encoder;
WSBlockGeneric generic;
};
const SubGhzProtocolDecoder ws_protocol_ambient_weather_decoder = {
.alloc = ws_protocol_decoder_ambient_weather_alloc,
.free = ws_protocol_decoder_ambient_weather_free,
.feed = ws_protocol_decoder_ambient_weather_feed,
.reset = ws_protocol_decoder_ambient_weather_reset,
.get_hash_data = ws_protocol_decoder_ambient_weather_get_hash_data,
.serialize = ws_protocol_decoder_ambient_weather_serialize,
.deserialize = ws_protocol_decoder_ambient_weather_deserialize,
.get_string = ws_protocol_decoder_ambient_weather_get_string,
};
const SubGhzProtocolEncoder ws_protocol_ambient_weather_encoder = {
.alloc = NULL,
.free = NULL,
.deserialize = NULL,
.stop = NULL,
.yield = NULL,
};
const SubGhzProtocol ws_protocol_ambient_weather = {
.name = WS_PROTOCOL_AMBIENT_WEATHER_NAME,
.type = SubGhzProtocolWeatherStation,
.flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_315 | SubGhzProtocolFlag_868 |
SubGhzProtocolFlag_AM | SubGhzProtocolFlag_Decodable,
.decoder = &ws_protocol_ambient_weather_decoder,
.encoder = &ws_protocol_ambient_weather_encoder,
};
void* ws_protocol_decoder_ambient_weather_alloc(SubGhzEnvironment* environment) {
UNUSED(environment);
WSProtocolDecoderAmbient_Weather* instance = malloc(sizeof(WSProtocolDecoderAmbient_Weather));
instance->base.protocol = &ws_protocol_ambient_weather;
instance->generic.protocol_name = instance->base.protocol->name;
return instance;
}
void ws_protocol_decoder_ambient_weather_free(void* context) {
furi_assert(context);
WSProtocolDecoderAmbient_Weather* instance = context;
free(instance);
}
void ws_protocol_decoder_ambient_weather_reset(void* context) {
furi_assert(context);
WSProtocolDecoderAmbient_Weather* instance = context;
manchester_advance(
instance->manchester_saved_state,
ManchesterEventReset,
&instance->manchester_saved_state,
NULL);
}
static bool ws_protocol_ambient_weather_check_crc(WSProtocolDecoderAmbient_Weather* instance) {
uint8_t msg[] = {
instance->decoder.decode_data >> 40,
instance->decoder.decode_data >> 32,
instance->decoder.decode_data >> 24,
instance->decoder.decode_data >> 16,
instance->decoder.decode_data >> 8};
uint8_t crc = subghz_protocol_blocks_lfsr_digest8(msg, 5, 0x98, 0x3e) ^ 0x64;
return (crc == (uint8_t)(instance->decoder.decode_data & 0xFF));
}
/**
* Analysis of received data
* @param instance Pointer to a WSBlockGeneric* instance
*/
static void ws_protocol_ambient_weather_remote_controller(WSBlockGeneric* instance) {
instance->id = (instance->data >> 32) & 0xFF;
instance->battery_low = (instance->data >> 31) & 1;
instance->channel = ((instance->data >> 28) & 0x07) + 1;
instance->temp = ws_block_generic_fahrenheit_to_celsius(
((float)((instance->data >> 16) & 0x0FFF) - 400.0f) / 10.0f);
instance->humidity = (instance->data >> 8) & 0xFF;
instance->btn = WS_NO_BTN;
// ToDo maybe it won't be needed
/*
Sanity checks to reduce false positives and other bad data
Packets with Bad data often pass the MIC check.
- humidity > 100 (such as 255) and
- temperatures > 140 F (such as 369.5 F and 348.8 F
Specs in the F007TH and F012TH manuals state the range is:
- Temperature: -40 to 140 F
- Humidity: 10 to 99%
@todo - sanity check b[0] "model number"
- 0x45 - F007TH and F012TH
- 0x?5 - SwitchDocLabs F016TH temperature sensor (based on comment b[0] & 0x0f == 5)
- ? - TFA 30.3208.02
if (instance->humidity < 0 || instance->humidity > 100) {
ERROR;
}
if (instance->temp < -40.0 || instance->temp > 140.0) {
ERROR;
}
*/
}
void ws_protocol_decoder_ambient_weather_feed(void* context, bool level, uint32_t duration) {
furi_assert(context);
WSProtocolDecoderAmbient_Weather* instance = context;
ManchesterEvent event = ManchesterEventReset;
if(!level) {
if(DURATION_DIFF(duration, ws_protocol_ambient_weather_const.te_short) <
ws_protocol_ambient_weather_const.te_delta) {
event = ManchesterEventShortLow;
} else if(
DURATION_DIFF(duration, ws_protocol_ambient_weather_const.te_long) <
ws_protocol_ambient_weather_const.te_delta * 2) {
event = ManchesterEventLongLow;
}
} else {
if(DURATION_DIFF(duration, ws_protocol_ambient_weather_const.te_short) <
ws_protocol_ambient_weather_const.te_delta) {
event = ManchesterEventShortHigh;
} else if(
DURATION_DIFF(duration, ws_protocol_ambient_weather_const.te_long) <
ws_protocol_ambient_weather_const.te_delta * 2) {
event = ManchesterEventLongHigh;
}
}
if(event != ManchesterEventReset) {
bool data;
bool data_ok = manchester_advance(
instance->manchester_saved_state, event, &instance->manchester_saved_state, &data);
if(data_ok) {
instance->decoder.decode_data = (instance->decoder.decode_data << 1) | !data;
}
if(((instance->decoder.decode_data & AMBIENT_WEATHER_PACKET_HEADER_MASK) ==
AMBIENT_WEATHER_PACKET_HEADER_1) ||
((instance->decoder.decode_data & AMBIENT_WEATHER_PACKET_HEADER_MASK) ==
AMBIENT_WEATHER_PACKET_HEADER_2)) {
if(ws_protocol_ambient_weather_check_crc(instance)) {
instance->decoder.decode_data = instance->decoder.decode_data;
instance->generic.data = instance->decoder.decode_data;
instance->generic.data_count_bit =
ws_protocol_ambient_weather_const.min_count_bit_for_found;
ws_protocol_ambient_weather_remote_controller(&instance->generic);
if(instance->base.callback)
instance->base.callback(&instance->base, instance->base.context);
instance->decoder.decode_data = 0;
instance->decoder.decode_count_bit = 0;
}
}
} else {
instance->decoder.decode_data = 0;
instance->decoder.decode_count_bit = 0;
manchester_advance(
instance->manchester_saved_state,
ManchesterEventReset,
&instance->manchester_saved_state,
NULL);
}
}
uint8_t ws_protocol_decoder_ambient_weather_get_hash_data(void* context) {
furi_assert(context);
WSProtocolDecoderAmbient_Weather* instance = context;
return subghz_protocol_blocks_get_hash_data(
&instance->decoder, (instance->decoder.decode_count_bit / 8) + 1);
}
bool ws_protocol_decoder_ambient_weather_serialize(
void* context,
FlipperFormat* flipper_format,
SubGhzRadioPreset* preset) {
furi_assert(context);
WSProtocolDecoderAmbient_Weather* instance = context;
return ws_block_generic_serialize(&instance->generic, flipper_format, preset);
}
bool ws_protocol_decoder_ambient_weather_deserialize(void* context, FlipperFormat* flipper_format) {
furi_assert(context);
WSProtocolDecoderAmbient_Weather* instance = context;
bool ret = false;
do {
if(!ws_block_generic_deserialize(&instance->generic, flipper_format)) {
break;
}
if(instance->generic.data_count_bit !=
ws_protocol_ambient_weather_const.min_count_bit_for_found) {
FURI_LOG_E(TAG, "Wrong number of bits in key");
break;
}
ret = true;
} while(false);
return ret;
}
void ws_protocol_decoder_ambient_weather_get_string(void* context, FuriString* output) {
furi_assert(context);
WSProtocolDecoderAmbient_Weather* instance = context;
furi_string_printf(
output,
"%s %dbit\r\n"
"Key:0x%lX%08lX\r\n"
"Sn:0x%lX Ch:%d Bat:%d\r\n"
"Temp:%d.%d C Hum:%d%%",
instance->generic.protocol_name,
instance->generic.data_count_bit,
(uint32_t)(instance->generic.data >> 32),
(uint32_t)(instance->generic.data),
instance->generic.id,
instance->generic.channel,
instance->generic.battery_low,
(int16_t)instance->generic.temp,
abs(((int16_t)(instance->generic.temp * 10) - (((int16_t)instance->generic.temp) * 10))),
instance->generic.humidity);
}
@@ -0,0 +1,79 @@
#pragma once
#include <lib/subghz/protocols/base.h>
#include <lib/subghz/blocks/const.h>
#include <lib/subghz/blocks/decoder.h>
#include <lib/subghz/blocks/encoder.h>
#include "ws_generic.h"
#include <lib/subghz/blocks/math.h>
#define WS_PROTOCOL_AMBIENT_WEATHER_NAME "Ambient_Weather"
typedef struct WSProtocolDecoderAmbient_Weather WSProtocolDecoderAmbient_Weather;
typedef struct WSProtocolEncoderAmbient_Weather WSProtocolEncoderAmbient_Weather;
extern const SubGhzProtocolDecoder ws_protocol_ambient_weather_decoder;
extern const SubGhzProtocolEncoder ws_protocol_ambient_weather_encoder;
extern const SubGhzProtocol ws_protocol_ambient_weather;
/**
* Allocate WSProtocolDecoderAmbient_Weather.
* @param environment Pointer to a SubGhzEnvironment instance
* @return WSProtocolDecoderAmbient_Weather* pointer to a WSProtocolDecoderAmbient_Weather instance
*/
void* ws_protocol_decoder_ambient_weather_alloc(SubGhzEnvironment* environment);
/**
* Free WSProtocolDecoderAmbient_Weather.
* @param context Pointer to a WSProtocolDecoderAmbient_Weather instance
*/
void ws_protocol_decoder_ambient_weather_free(void* context);
/**
* Reset decoder WSProtocolDecoderAmbient_Weather.
* @param context Pointer to a WSProtocolDecoderAmbient_Weather instance
*/
void ws_protocol_decoder_ambient_weather_reset(void* context);
/**
* Parse a raw sequence of levels and durations received from the air.
* @param context Pointer to a WSProtocolDecoderAmbient_Weather instance
* @param level Signal level true-high false-low
* @param duration Duration of this level in, us
*/
void ws_protocol_decoder_ambient_weather_feed(void* context, bool level, uint32_t duration);
/**
* Getting the hash sum of the last randomly received parcel.
* @param context Pointer to a WSProtocolDecoderAmbient_Weather instance
* @return hash Hash sum
*/
uint8_t ws_protocol_decoder_ambient_weather_get_hash_data(void* context);
/**
* Serialize data WSProtocolDecoderAmbient_Weather.
* @param context Pointer to a WSProtocolDecoderAmbient_Weather instance
* @param flipper_format Pointer to a FlipperFormat instance
* @param preset The modulation on which the signal was received, SubGhzRadioPreset
* @return true On success
*/
bool ws_protocol_decoder_ambient_weather_serialize(
void* context,
FlipperFormat* flipper_format,
SubGhzRadioPreset* preset);
/**
* Deserialize data WSProtocolDecoderAmbient_Weather.
* @param context Pointer to a WSProtocolDecoderAmbient_Weather instance
* @param flipper_format Pointer to a FlipperFormat instance
* @return true On success
*/
bool ws_protocol_decoder_ambient_weather_deserialize(void* context, FlipperFormat* flipper_format);
/**
* Getting a textual representation of the received data.
* @param context Pointer to a WSProtocolDecoderAmbient_Weather instance
* @param output Resulting text
*/
void ws_protocol_decoder_ambient_weather_get_string(void* context, FuriString* output);
@@ -4,7 +4,7 @@
/*
* Help
* https://github.com/merbanan/rtl_433/blob/5f0ff6db624270a4598958ab9dd79bb385ced3ef/src/devices/gt_wt_03.c
* https://github.com/merbanan/rtl_433/blob/master/src/devices/gt_wt_03.c
*
*
* Globaltronics GT-WT-03 sensor on 433.92MHz.
@@ -4,7 +4,7 @@
/*
* Help
* https://github.com/merbanan/rtl_433/blob/7e83cfd27d14247b6c3c81732bfe4a4f9a974d30/src/devices/lacrosse_tx141x.c
* https://github.com/merbanan/rtl_433/blob/master/src/devices/lacrosse_tx141x.c
*
* iiii iiii | bkcc tttt | tttt tttt | hhhh hhhh | cccc cccc | u
* - i: identification; changes on battery switch
@@ -4,7 +4,7 @@
/*
* Help
* https://github.com/merbanan/rtl_433/blob/ef2d37cf51e3264d11cde9149ef87de2f0a4d37a/src/devices/nexus.c
* https://github.com/merbanan/rtl_433/blob/master/src/devices/nexus.c
*
* Nexus sensor protocol with ID, temperature and optional humidity
* also FreeTec (Pearl) NC-7345 sensors for FreeTec Weatherstation NC-7344,
@@ -9,6 +9,7 @@ const SubGhzProtocol* weather_station_protocol_registry_items[] = {
&ws_protocol_lacrosse_tx141thbv2,
&ws_protocol_oregon2,
&ws_protocol_acurite_592txr,
&ws_protocol_ambient_weather,
};
const SubGhzProtocolRegistry weather_station_protocol_registry = {
@@ -9,5 +9,6 @@
#include "lacrosse_tx141thbv2.h"
#include "oregon2.h"
#include "acurite_592txr.h"
#include "ambient_weather.h"
extern const SubGhzProtocolRegistry weather_station_protocol_registry;