Merge branch 'dev' into skorp/subghz_nice_flo_20bit

This commit is contained in:
Skorpionm
2022-11-10 18:12:33 +04:00
committed by GitHub
24 changed files with 470 additions and 48 deletions
+7 -2
View File
@@ -18,7 +18,7 @@
/applications/main/gpio/ @skotopes @DrZlo13 @hedger @nminaylov
/applications/main/ibutton/ @skotopes @DrZlo13 @hedger @gsurkov
/applications/main/infrared/ @skotopes @DrZlo13 @hedger @gsurkov
/applications/main/nfc/ @skotopes @DrZlo13 @hedger @gornekich
/applications/main/nfc/ @skotopes @DrZlo13 @hedger @gornekich @Astrrra
/applications/main/subghz/ @skotopes @DrZlo13 @hedger @Skorpionm
/applications/main/u2f/ @skotopes @DrZlo13 @hedger @nminaylov
@@ -40,6 +40,8 @@
/applications/system/storage_move_to_sd/ @skotopes @DrZlo13 @hedger @nminaylov
/applications/debug/unit_tests/ @skotopes @DrZlo13 @hedger @nminaylov @gornekich @Astrrra @gsurkov @Skorpionm
# Documentation
/documentation/ @skotopes @DrZlo13 @hedger @drunkbatya
/scripts/toolchain/ @skotopes @DrZlo13 @hedger @drunkbatya
@@ -54,6 +56,9 @@
/lib/mbedtls/ @skotopes @DrZlo13 @hedger @nminaylov
/lib/micro-ecc/ @skotopes @DrZlo13 @hedger @nminaylov
/lib/nanopb/ @skotopes @DrZlo13 @hedger @nminaylov
/lib/nfc/ @skotopes @DrZlo13 @hedger @gornekich
/lib/nfc/ @skotopes @DrZlo13 @hedger @gornekich @Astrrra
/lib/one_wire/ @skotopes @DrZlo13 @hedger @gsurkov
/lib/subghz/ @skotopes @DrZlo13 @hedger @Skorpionm
# CI/CD
/.github/workflows/ @skotopes @DrZlo13 @hedger @drunkbatya
+1 -1
View File
@@ -91,7 +91,7 @@ jobs:
export RODATA_SIZE="$(get_size ".rodata")"
export DATA_SIZE="$(get_size ".data")"
export FREE_FLASH_SIZE="$(get_size ".free_flash")"
python3 -m pip install mariadb
python3 -m pip install mariadb==1.1.4
python3 scripts/amap_mariadb_insert.py \
${{ secrets.AMAP_MARIADB_USER }} \
${{ secrets.AMAP_MARIADB_PASSWORD }} \
+3 -6
View File
@@ -7,6 +7,7 @@
# construction of certain targets behind command-line options.
import os
from fbt.util import path_as_posix
DefaultEnvironment(tools=[])
@@ -200,9 +201,7 @@ firmware_debug = distenv.PhonyTarget(
source=firmware_env["FW_ELF"],
GDBOPTS="${GDBOPTS_BASE}",
GDBREMOTE="${OPENOCD_GDB_PIPE}",
FBT_FAP_DEBUG_ELF_ROOT=firmware_env.subst("$FBT_FAP_DEBUG_ELF_ROOT").replace(
"\\", "/"
),
FBT_FAP_DEBUG_ELF_ROOT=path_as_posix(firmware_env.subst("$FBT_FAP_DEBUG_ELF_ROOT")),
)
distenv.Depends(firmware_debug, firmware_flash)
@@ -212,9 +211,7 @@ distenv.PhonyTarget(
source=firmware_env["FW_ELF"],
GDBOPTS="${GDBOPTS_BASE} ${GDBOPTS_BLACKMAGIC}",
GDBREMOTE="${BLACKMAGIC_ADDR}",
FBT_FAP_DEBUG_ELF_ROOT=firmware_env.subst("$FBT_FAP_DEBUG_ELF_ROOT").replace(
"\\", "/"
),
FBT_FAP_DEBUG_ELF_ROOT=path_as_posix(firmware_env.subst("$FBT_FAP_DEBUG_ELF_ROOT")),
)
# Debug alien elf
@@ -0,0 +1,247 @@
#include "acurite_609txc.h"
#define TAG "WSProtocolAcurite_609TXC"
/*
* Help
* https://github.com/merbanan/rtl_433/blob/5bef4e43133ac4c0e2d18d36f87c52b4f9458453/src/devices/acurite.c#L216
*
* 0000 1111 | 0011 0000 | 0101 1100 | 0000 0000 | 1110 0111
* iiii iiii | buuu tttt | tttt tttt | hhhh hhhh | cccc cccc
* - i: identification; changes on battery switch
* - c: checksum (sum of previous by bytes)
* - u: unknown
* - b: battery low; flag to indicate low battery voltage
* - t: temperature; in °C * 10, 12 bit with complement
* - h: humidity
*
*/
static const SubGhzBlockConst ws_protocol_acurite_609txc_const = {
.te_short = 500,
.te_long = 1000,
.te_delta = 150,
.min_count_bit_for_found = 40,
};
struct WSProtocolDecoderAcurite_609TXC {
SubGhzProtocolDecoderBase base;
SubGhzBlockDecoder decoder;
WSBlockGeneric generic;
};
struct WSProtocolEncoderAcurite_609TXC {
SubGhzProtocolEncoderBase base;
SubGhzProtocolBlockEncoder encoder;
WSBlockGeneric generic;
};
typedef enum {
Acurite_609TXCDecoderStepReset = 0,
Acurite_609TXCDecoderStepSaveDuration,
Acurite_609TXCDecoderStepCheckDuration,
} Acurite_609TXCDecoderStep;
const SubGhzProtocolDecoder ws_protocol_acurite_609txc_decoder = {
.alloc = ws_protocol_decoder_acurite_609txc_alloc,
.free = ws_protocol_decoder_acurite_609txc_free,
.feed = ws_protocol_decoder_acurite_609txc_feed,
.reset = ws_protocol_decoder_acurite_609txc_reset,
.get_hash_data = ws_protocol_decoder_acurite_609txc_get_hash_data,
.serialize = ws_protocol_decoder_acurite_609txc_serialize,
.deserialize = ws_protocol_decoder_acurite_609txc_deserialize,
.get_string = ws_protocol_decoder_acurite_609txc_get_string,
};
const SubGhzProtocolEncoder ws_protocol_acurite_609txc_encoder = {
.alloc = NULL,
.free = NULL,
.deserialize = NULL,
.stop = NULL,
.yield = NULL,
};
const SubGhzProtocol ws_protocol_acurite_609txc = {
.name = WS_PROTOCOL_ACURITE_609TXC_NAME,
.type = SubGhzProtocolWeatherStation,
.flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_315 | SubGhzProtocolFlag_868 |
SubGhzProtocolFlag_AM | SubGhzProtocolFlag_Decodable,
.decoder = &ws_protocol_acurite_609txc_decoder,
.encoder = &ws_protocol_acurite_609txc_encoder,
};
void* ws_protocol_decoder_acurite_609txc_alloc(SubGhzEnvironment* environment) {
UNUSED(environment);
WSProtocolDecoderAcurite_609TXC* instance = malloc(sizeof(WSProtocolDecoderAcurite_609TXC));
instance->base.protocol = &ws_protocol_acurite_609txc;
instance->generic.protocol_name = instance->base.protocol->name;
return instance;
}
void ws_protocol_decoder_acurite_609txc_free(void* context) {
furi_assert(context);
WSProtocolDecoderAcurite_609TXC* instance = context;
free(instance);
}
void ws_protocol_decoder_acurite_609txc_reset(void* context) {
furi_assert(context);
WSProtocolDecoderAcurite_609TXC* instance = context;
instance->decoder.parser_step = Acurite_609TXCDecoderStepReset;
}
static bool ws_protocol_acurite_609txc_check(WSProtocolDecoderAcurite_609TXC* instance) {
if(!instance->decoder.decode_data) return false;
uint8_t crc = (uint8_t)(instance->decoder.decode_data >> 32) +
(uint8_t)(instance->decoder.decode_data >> 24) +
(uint8_t)(instance->decoder.decode_data >> 16) +
(uint8_t)(instance->decoder.decode_data >> 8);
return (crc == (instance->decoder.decode_data & 0xFF));
}
/**
* Analysis of received data
* @param instance Pointer to a WSBlockGeneric* instance
*/
static void ws_protocol_acurite_609txc_remote_controller(WSBlockGeneric* instance) {
instance->id = (instance->data >> 32) & 0xFF;
instance->battery_low = (instance->data >> 31) & 1;
instance->channel = WS_NO_CHANNEL;
// Temperature in Celsius is encoded as a 12 bit integer value
// multiplied by 10 using the 4th - 6th nybbles (bytes 1 & 2)
// negative values are recovered by sign extend from int16_t.
int16_t temp_raw =
(int16_t)(((instance->data >> 12) & 0xf000) | ((instance->data >> 16) << 4));
instance->temp = (temp_raw >> 4) * 0.1f;
instance->humidity = (instance->data >> 8) & 0xff;
instance->btn = WS_NO_BTN;
}
void ws_protocol_decoder_acurite_609txc_feed(void* context, bool level, uint32_t duration) {
furi_assert(context);
WSProtocolDecoderAcurite_609TXC* instance = context;
switch(instance->decoder.parser_step) {
case Acurite_609TXCDecoderStepReset:
if((!level) && (DURATION_DIFF(duration, ws_protocol_acurite_609txc_const.te_short * 17) <
ws_protocol_acurite_609txc_const.te_delta * 8)) {
//Found syncPrefix
instance->decoder.parser_step = Acurite_609TXCDecoderStepSaveDuration;
instance->decoder.decode_data = 0;
instance->decoder.decode_count_bit = 0;
}
break;
case Acurite_609TXCDecoderStepSaveDuration:
if(level) {
instance->decoder.te_last = duration;
instance->decoder.parser_step = Acurite_609TXCDecoderStepCheckDuration;
} else {
instance->decoder.parser_step = Acurite_609TXCDecoderStepReset;
}
break;
case Acurite_609TXCDecoderStepCheckDuration:
if(!level) {
if(DURATION_DIFF(instance->decoder.te_last, ws_protocol_acurite_609txc_const.te_short) <
ws_protocol_acurite_609txc_const.te_delta) {
if((DURATION_DIFF(duration, ws_protocol_acurite_609txc_const.te_short) <
ws_protocol_acurite_609txc_const.te_delta) ||
(duration > ws_protocol_acurite_609txc_const.te_long * 3)) {
//Found syncPostfix
instance->decoder.parser_step = Acurite_609TXCDecoderStepReset;
if((instance->decoder.decode_count_bit ==
ws_protocol_acurite_609txc_const.min_count_bit_for_found) &&
ws_protocol_acurite_609txc_check(instance)) {
instance->generic.data = instance->decoder.decode_data;
instance->generic.data_count_bit = instance->decoder.decode_count_bit;
ws_protocol_acurite_609txc_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 if(
DURATION_DIFF(duration, ws_protocol_acurite_609txc_const.te_long) <
ws_protocol_acurite_609txc_const.te_delta * 2) {
subghz_protocol_blocks_add_bit(&instance->decoder, 0);
instance->decoder.parser_step = Acurite_609TXCDecoderStepSaveDuration;
} else if(
DURATION_DIFF(duration, ws_protocol_acurite_609txc_const.te_long * 2) <
ws_protocol_acurite_609txc_const.te_delta * 4) {
subghz_protocol_blocks_add_bit(&instance->decoder, 1);
instance->decoder.parser_step = Acurite_609TXCDecoderStepSaveDuration;
} else {
instance->decoder.parser_step = Acurite_609TXCDecoderStepReset;
}
} else {
instance->decoder.parser_step = Acurite_609TXCDecoderStepReset;
}
} else {
instance->decoder.parser_step = Acurite_609TXCDecoderStepReset;
}
break;
}
}
uint8_t ws_protocol_decoder_acurite_609txc_get_hash_data(void* context) {
furi_assert(context);
WSProtocolDecoderAcurite_609TXC* instance = context;
return subghz_protocol_blocks_get_hash_data(
&instance->decoder, (instance->decoder.decode_count_bit / 8) + 1);
}
bool ws_protocol_decoder_acurite_609txc_serialize(
void* context,
FlipperFormat* flipper_format,
SubGhzRadioPreset* preset) {
furi_assert(context);
WSProtocolDecoderAcurite_609TXC* instance = context;
return ws_block_generic_serialize(&instance->generic, flipper_format, preset);
}
bool ws_protocol_decoder_acurite_609txc_deserialize(void* context, FlipperFormat* flipper_format) {
furi_assert(context);
WSProtocolDecoderAcurite_609TXC* instance = context;
bool ret = false;
do {
if(!ws_block_generic_deserialize(&instance->generic, flipper_format)) {
break;
}
if(instance->generic.data_count_bit !=
ws_protocol_acurite_609txc_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_acurite_609txc_get_string(void* context, FuriString* output) {
furi_assert(context);
WSProtocolDecoderAcurite_609TXC* 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:%3.1f C Hum:%d%%",
instance->generic.protocol_name,
instance->generic.data_count_bit,
(uint32_t)(instance->generic.data >> 40),
(uint32_t)(instance->generic.data),
instance->generic.id,
instance->generic.channel,
instance->generic.battery_low,
(double)instance->generic.temp,
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_ACURITE_609TXC_NAME "Acurite-609TXC"
typedef struct WSProtocolDecoderAcurite_609TXC WSProtocolDecoderAcurite_609TXC;
typedef struct WSProtocolEncoderAcurite_609TXC WSProtocolEncoderAcurite_609TXC;
extern const SubGhzProtocolDecoder ws_protocol_acurite_609txc_decoder;
extern const SubGhzProtocolEncoder ws_protocol_acurite_609txc_encoder;
extern const SubGhzProtocol ws_protocol_acurite_609txc;
/**
* Allocate WSProtocolDecoderAcurite_609TXC.
* @param environment Pointer to a SubGhzEnvironment instance
* @return WSProtocolDecoderAcurite_609TXC* pointer to a WSProtocolDecoderAcurite_609TXC instance
*/
void* ws_protocol_decoder_acurite_609txc_alloc(SubGhzEnvironment* environment);
/**
* Free WSProtocolDecoderAcurite_609TXC.
* @param context Pointer to a WSProtocolDecoderAcurite_609TXC instance
*/
void ws_protocol_decoder_acurite_609txc_free(void* context);
/**
* Reset decoder WSProtocolDecoderAcurite_609TXC.
* @param context Pointer to a WSProtocolDecoderAcurite_609TXC instance
*/
void ws_protocol_decoder_acurite_609txc_reset(void* context);
/**
* Parse a raw sequence of levels and durations received from the air.
* @param context Pointer to a WSProtocolDecoderAcurite_609TXC instance
* @param level Signal level true-high false-low
* @param duration Duration of this level in, us
*/
void ws_protocol_decoder_acurite_609txc_feed(void* context, bool level, uint32_t duration);
/**
* Getting the hash sum of the last randomly received parcel.
* @param context Pointer to a WSProtocolDecoderAcurite_609TXC instance
* @return hash Hash sum
*/
uint8_t ws_protocol_decoder_acurite_609txc_get_hash_data(void* context);
/**
* Serialize data WSProtocolDecoderAcurite_609TXC.
* @param context Pointer to a WSProtocolDecoderAcurite_609TXC 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_acurite_609txc_serialize(
void* context,
FlipperFormat* flipper_format,
SubGhzRadioPreset* preset);
/**
* Deserialize data WSProtocolDecoderAcurite_609TXC.
* @param context Pointer to a WSProtocolDecoderAcurite_609TXC instance
* @param flipper_format Pointer to a FlipperFormat instance
* @return true On success
*/
bool ws_protocol_decoder_acurite_609txc_deserialize(void* context, FlipperFormat* flipper_format);
/**
* Getting a textual representation of the received data.
* @param context Pointer to a WSProtocolDecoderAcurite_609TXC instance
* @param output Resulting text
*/
void ws_protocol_decoder_acurite_609txc_get_string(void* context, FuriString* output);
@@ -6,6 +6,7 @@ const SubGhzProtocol* weather_station_protocol_registry_items[] = {
&ws_protocol_nexus_th,
&ws_protocol_gt_wt_03,
&ws_protocol_acurite_606tx,
&ws_protocol_acurite_609txc,
&ws_protocol_lacrosse_tx141thbv2,
&ws_protocol_oregon2,
&ws_protocol_acurite_592txr,
@@ -6,6 +6,7 @@
#include "nexus_th.h"
#include "gt_wt_03.h"
#include "acurite_606tx.h"
#include "acurite_609txc.h"
#include "lacrosse_tx141thbv2.h"
#include "oregon2.h"
#include "acurite_592txr.h"
+1 -5
View File
@@ -273,11 +273,7 @@ static void loader_thread_state_callback(FuriThreadState thread_state, void* con
furi_hal_power_insomnia_enter();
}
} else if(thread_state == FuriThreadStateStopped) {
FURI_LOG_I(
TAG,
"Application thread stopped. Free heap: %d. Thread allocation balance: %d.",
memmgr_get_free_heap(),
furi_thread_get_heap_size(instance->application_thread));
FURI_LOG_I(TAG, "Application stopped. Free heap: %d", memmgr_get_free_heap());
if(loader_instance->application_arguments) {
free(loader_instance->application_arguments);
+1 -1
View File
@@ -372,7 +372,7 @@ RpcSession* rpc_session_open(Rpc* rpc) {
session->thread = furi_thread_alloc();
furi_thread_set_name(session->thread, "RpcSessionWorker");
furi_thread_set_stack_size(session->thread, 2048);
furi_thread_set_stack_size(session->thread, 3072);
furi_thread_set_context(session->thread, session);
furi_thread_set_callback(session->thread, rpc_session_worker);
+1
View File
@@ -40,6 +40,7 @@ Only 2 parameters are mandatory: ***appid*** and ***apptype***, others are optio
* **icon**: Animated icon name from built-in assets to be used when building app as a part of firmware.
* **order**: Order of an application within its group when sorting entries in it. The lower the order is, the closer to the start of the list the item is placed. *Used for ordering startup hooks and menu entries.*
* **sdk_headers**: List of C header files from this app's code to include in API definitions for external applications.
* **targets**: list of strings, target names, which this application is compatible with. If not specified, application is built for all targets. Default value is `["all"]`.
#### Parameters for external applications
+49
View File
@@ -0,0 +1,49 @@
# Unit tests
## Intro
Unit tests are special pieces of code that apply known inputs to the feature code and check the results to see if they were correct.
They are crucial for writing robust, bug-free code.
Flipper Zero firmware includes a separate application called [unit_tests](/applications/debug/unit_tests).
It is run directly on the Flipper Zero in order to employ its hardware features and to rule out any platform-related differences.
When contributing code to the Flipper Zero firmware, it is highly desirable to supply unit tests along with the proposed features.
Running existing unit tests is useful to ensure that the new code doesn't introduce any regressions.
## Running unit tests
In order to run the unit tests, follow these steps:
1. Compile the firmware with the tests enabled: `./fbt FIRMWARE_APP_SET=unit_tests`.
2. Flash the firmware using your preferred method.
3. Copy the [assets/unit_tests](assets/unit_tests) folder to the root your Flipper Zero's SD card.
4. Launch the CLI session and run the `unit_tests` command.
**NOTE:** To run a particular test (and skip all others), specify its name as the command argument.
See [test_index.c](applications/debug/unit_tests/test_index.c) for the complete list of test names.
## Adding unit tests
### General
#### Entry point
The common entry point for all tests it the [unit_tests](applications/debug/unit_tests) application. Test-specific code is placed into an arbitrarily named subdirectory and is then called from the [test_index.c](applications/debug/unit_tests/test_index.c) source file.
#### Test assets
Some unit tests require external data in order to function. These files (commonly called assets) reside in the [assets/unit_tests](/assets/unit_tests) directory in their respective subdirectories. Asset files can be of any type (plain text, FlipperFormat(FFF), binary etc).
### Application-specific
#### Infrared
Each infrared protocol has a corresponding set of unit tests, so it makes sense to implement one when adding support for a new protocol.
In order to add unit tests for your protocol, follow these steps:
1. Create a file named `test_<your_protocol_name>.irtest` in the [assets](assets/unit_tests/infrared) directory.
2. Fill it with the test data (more on it below).
3. Add the test code to [infrared_test.c](applications/debug/unit_tests/infrared/infrared_test.c).
4. Update the [assets](assets/unit_tests/infrared) on your Flipper Zero and run the tests to see if they pass.
##### Test data format
Each unit test has 3 sections:
1. `decoder` - takes in raw signal and outputs decoded messages.
2. `encoder` - takes in decoded messages and outputs raw signal.
3. `encoder_decoder` - takes in decoded messages, turns them into raw signal and then decodes again.
Infrared test asset files have an `.irtest` extension and are regular `.ir` files with a few additions.
Decoder input data has signal names `decoder_input_N`, where N is a test sequence number. Expected data goes under the name `decoder_expected_N`. When testing the encoder these two are switched.
Decoded data is represented in arrays (since a single raw signal may decode to several messages). If there is only one signal, then it has to be an array of size 1. Use the existing files as syntax examples.
##### Getting raw signals
Recording raw IR signals is possible using Flipper Zero. Launch the CLI session, run `ir rx raw`, then point the remote towards Flipper's receiver and send the signals. The raw signal data will be printed to the console in a convenient format.
+2 -2
View File
@@ -40,11 +40,11 @@ env = ENV.Clone(
FW_LIB_OPTS={
"Default": {
"CCFLAGS": [
"-Os",
"-Og" if ENV["LIB_DEBUG"] else "-Os",
],
"CPPDEFINES": [
"NDEBUG",
"FURI_NDEBUG",
"FURI_DEBUG" if ENV["LIB_DEBUG"] else "FURI_NDEBUG",
],
# You can add other entries named after libraries
# If they are present, they have precedence over Default
+10 -2
View File
@@ -12,6 +12,8 @@
#include <furi_hal_rtc.h>
#include <furi_hal_console.h>
#define TAG "FuriThread"
#define THREAD_NOTIFY_INDEX 1 // Index 0 is used for stream buffers
typedef struct FuriThreadStdout FuriThreadStdout;
@@ -82,6 +84,12 @@ static void furi_thread_body(void* context) {
if(thread->heap_trace_enabled == true) {
furi_delay_ms(33);
thread->heap_size = memmgr_heap_get_thread_memory((FuriThreadId)task_handle);
furi_log_print_format(
thread->heap_size ? FuriLogLevelError : FuriLogLevelInfo,
TAG,
"%s allocation balance: %d",
thread->name ? thread->name : "Thread",
thread->heap_size);
memmgr_heap_disable_thread_trace((FuriThreadId)task_handle);
}
@@ -89,8 +97,8 @@ static void furi_thread_body(void* context) {
if(thread->is_service) {
FURI_LOG_E(
"Service",
"%s thread exited. Thread memory cannot be reclaimed.",
TAG,
"%s service thread exited. Thread memory cannot be reclaimed.",
thread->name ? thread->name : "<unknown service>");
}
+5 -5
View File
@@ -70,12 +70,12 @@ void nfc_worker_start(
void nfc_worker_stop(NfcWorker* nfc_worker) {
furi_assert(nfc_worker);
if(nfc_worker->state == NfcWorkerStateBroken || nfc_worker->state == NfcWorkerStateReady) {
return;
furi_assert(nfc_worker->thread);
if(furi_thread_get_state(nfc_worker->thread) != FuriThreadStateStopped) {
furi_hal_nfc_stop();
nfc_worker_change_state(nfc_worker, NfcWorkerStateStop);
furi_thread_join(nfc_worker->thread);
}
furi_hal_nfc_stop();
nfc_worker_change_state(nfc_worker, NfcWorkerStateStop);
furi_thread_join(nfc_worker->thread);
}
void nfc_worker_change_state(NfcWorker* nfc_worker, NfcWorkerState state) {
-1
View File
@@ -7,7 +7,6 @@ typedef struct NfcWorker NfcWorker;
typedef enum {
// Init states
NfcWorkerStateNone,
NfcWorkerStateBroken,
NfcWorkerStateReady,
// Main worker states
NfcWorkerStateRead,
+17 -3
View File
@@ -52,6 +52,8 @@ class FlipperApplication:
icon: Optional[str] = None
order: int = 0
sdk_headers: List[str] = field(default_factory=list)
targets: List[str] = field(default_factory=lambda: ["all"])
# .fap-specific
sources: List[str] = field(default_factory=lambda: ["*.c*"])
fap_version: Tuple[int] = field(default_factory=lambda: (0, 1))
@@ -135,8 +137,8 @@ class AppManager:
raise FlipperManifestException(f"Duplicate app declaration: {app.appid}")
self.known_apps[app.appid] = app
def filter_apps(self, applist: List[str]):
return AppBuildset(self, applist)
def filter_apps(self, applist: List[str], hw_target: str):
return AppBuildset(self, applist, hw_target)
class AppBuilderException(Exception):
@@ -155,11 +157,13 @@ class AppBuildset:
FlipperAppType.STARTUP,
)
def __init__(self, appmgr: AppManager, appnames: List[str]):
def __init__(self, appmgr: AppManager, appnames: List[str], hw_target: str):
self.appmgr = appmgr
self.appnames = set(appnames)
self.hw_target = hw_target
self._orig_appnames = appnames
self._process_deps()
self._filter_by_target()
self._check_conflicts()
self._check_unsatisfied() # unneeded?
self.apps = sorted(
@@ -170,6 +174,16 @@ class AppBuildset:
def _is_missing_dep(self, dep_name: str):
return dep_name not in self.appnames
def _filter_by_target(self):
for appname in self.appnames.copy():
app = self.appmgr.get(appname)
# if app.apptype not in self.BUILTIN_APP_TYPES:
if not any(map(lambda t: t in app.targets, ["all", self.hw_target])):
print(
f"Removing {appname} due to target mismatch (building for {self.hw_target}, app supports {app.targets}"
)
self.appnames.remove(appname)
def _process_deps(self):
while True:
provided = []
+6 -1
View File
@@ -1,7 +1,6 @@
import SCons
from SCons.Subst import quote_spaces
from SCons.Errors import StopError
from SCons.Node.FS import _my_normcase
import re
import os
@@ -58,3 +57,9 @@ def extract_abs_dir_path(node):
raise StopError(f"Can't find absolute path for {node.name}")
return abs_dir_node.abspath
def path_as_posix(path):
if SCons.Platform.platform_default() == "win32":
return path.replace(os.path.sep, os.path.altsep)
return path
+7 -6
View File
@@ -1,7 +1,6 @@
from SCons.Builder import Builder
from SCons.Action import Action
from SCons.Warnings import warn, WarningOnByDefault
import SCons
from ansi.color import fg
from fbt.appmanifest import (
@@ -33,14 +32,12 @@ def LoadAppManifest(env, entry):
def PrepareApplicationsBuild(env):
appbuild = env["APPBUILD"] = env["APPMGR"].filter_apps(env["APPS"])
appbuild = env["APPBUILD"] = env["APPMGR"].filter_apps(
env["APPS"], env.subst("f${TARGET_HW}")
)
env.Append(
SDK_HEADERS=appbuild.get_sdk_headers(),
)
env["APPBUILD_DUMP"] = env.Action(
DumpApplicationConfig,
"\tINFO\t",
)
def DumpApplicationConfig(target, source, env):
@@ -68,6 +65,10 @@ def generate(env):
env.AddMethod(PrepareApplicationsBuild)
env.SetDefault(
APPMGR=AppManager(),
APPBUILD_DUMP=env.Action(
DumpApplicationConfig,
"\tINFO\t",
),
)
env.Append(
+2 -2
View File
@@ -41,12 +41,12 @@ def generate(env, **kw):
"|openocd -c 'gdb_port pipe; log_output ${FBT_DEBUG_DIR}/openocd.log' ${[SINGLEQUOTEFUNC(OPENOCD_OPTS)]}"
],
GDBOPTS_BASE=[
"-ex",
"set pagination off",
"-ex",
"target extended-remote ${GDBREMOTE}",
"-ex",
"set confirm off",
"-ex",
"set pagination off",
],
GDBOPTS_BLACKMAGIC=[
"-ex",
+14 -8
View File
@@ -14,6 +14,7 @@ import json
from fbt.sdk.collector import SdkCollector
from fbt.sdk.cache import SdkCache
from fbt.util import path_as_posix
def ProcessSdkDepends(env, filename):
@@ -52,6 +53,8 @@ def prebuild_sdk_create_origin_file(target, source, env):
class SdkMeta:
MAP_FILE_SUBST = "SDK_MAP_FILE_SUBST"
def __init__(self, env, tree_builder: "SdkTreeBuilder"):
self.env = env
self.treebuilder = tree_builder
@@ -67,6 +70,7 @@ class SdkMeta:
"linker_libs": self.env.subst("${LIBS}"),
"app_ep_subst": self.env.subst("${APP_ENTRY}"),
"sdk_path_subst": self.env.subst("${SDK_DIR_SUBST}"),
"map_file_subst": self.MAP_FILE_SUBST,
"hardware": self.env.subst("${TARGET_HW}"),
}
with open(json_manifest_path, "wt") as f:
@@ -75,9 +79,9 @@ class SdkMeta:
def _wrap_scons_vars(self, vars: str):
expanded_vars = self.env.subst(
vars,
target=Entry("dummy"),
target=Entry(self.MAP_FILE_SUBST),
)
return expanded_vars.replace("\\", "/")
return path_as_posix(expanded_vars)
class SdkTreeBuilder:
@@ -142,13 +146,15 @@ class SdkTreeBuilder:
meta.save_to(self.target[0].path)
def build_sdk_file_path(self, orig_path: str) -> str:
return posixpath.normpath(
posixpath.join(
self.SDK_DIR_SUBST,
self.target_sdk_dir_name,
orig_path,
return path_as_posix(
posixpath.normpath(
posixpath.join(
self.SDK_DIR_SUBST,
self.target_sdk_dir_name,
orig_path,
)
)
).replace("\\", "/")
)
def emitter(self, target, source, env):
target_folder = target[0]
+1 -1
View File
@@ -13,7 +13,7 @@ if not [%FBT_NOENV%] == [] (
exit /b 0
)
set "FLIPPER_TOOLCHAIN_VERSION=17"
set "FLIPPER_TOOLCHAIN_VERSION=19"
if [%FBT_TOOLCHAIN_ROOT%] == [] (
set "FBT_TOOLCHAIN_ROOT=%FBT_ROOT%\toolchain\x86_64-windows"
+1 -1
View File
@@ -5,7 +5,7 @@
# public variables
DEFAULT_SCRIPT_PATH="$(pwd -P)";
SCRIPT_PATH="${SCRIPT_PATH:-$DEFAULT_SCRIPT_PATH}";
FBT_TOOLCHAIN_VERSION="${FBT_TOOLCHAIN_VERSION:-"17"}";
FBT_TOOLCHAIN_VERSION="${FBT_TOOLCHAIN_VERSION:-"19"}";
FBT_TOOLCHAIN_PATH="${FBT_TOOLCHAIN_PATH:-$SCRIPT_PATH}";
fbtenv_show_usage()
+5
View File
@@ -63,6 +63,11 @@ vars.AddVariables(
help="Enable debug build",
default=True,
),
BoolVariable(
"LIB_DEBUG",
help="Enable debug build for libraries",
default=False,
),
BoolVariable(
"COMPACT",
help="Optimize for size",
+9 -1
View File
@@ -1,6 +1,6 @@
from dataclasses import dataclass, field
from SCons.Errors import UserError
from SCons.Node import NodeList
from SCons.Warnings import warn, WarningOnByDefault
Import("ENV")
@@ -80,6 +80,14 @@ if extra_app_list := GetOption("extra_ext_apps"):
known_extapps.extend(map(appenv["APPMGR"].get, extra_app_list.split(",")))
for app in known_extapps:
if not any(map(lambda t: t in app.targets, ["all", appenv.subst("f${TARGET_HW}")])):
warn(
WarningOnByDefault,
f"Can't build '{app.name}' (id '{app.appid}'): target mismatch"
f" (building for {appenv.subst('f${TARGET_HW}')}, app supports {app.targets}",
)
continue
appenv.BuildAppElf(app)