[FL-3375] SubGhz: add CC1101 module external (#2747)

* SubGhz: add CC1101 Ext driver
* SubGhz:  move TIM2 -> TIM17 use cc1101_ext
* FuriHal: SPI move channel DMA 3,4 -> 6.7
* Documentation: fix font
* SubGhz: add work with SubGhz devices by link to device
* SubGhz: add support switching external/internal cc1101 "subghz chat"
* SubGhz: add support switching external/internal cc1101 "subghz tx" and "subghz rx"
* SubGhz: add "Radio Settings" scene
* SubGhz: add icon
* SubGhz: add supported CC1101 external module in SubGhz app
* SubGhz: fix check frequency supported radio device
* SubGhz: fix clang-formatted
* Sughz: move dirver CC1101_Ext to lib , compile cmd ./fbt launch_app APPSRC=radio_device_cc1101_ext
* SubGhz: fix CLI
* SubGhz: fix PVS
* SubGhz: delete comments
* SubGhz: fix unit_test
* Format sources
* Update api symbols and drivers targets
* Drivers: find proper place for target option
* SubGhz: external device connected method naming
* Format sources
* SubGhz:  fix module selection menu, when external is not connected
* SubGhz: fix furi_assert(device);
* SubGhz: fix split h and c
* SubGhz: furi_hal_subghz remove preset load function by name
* SubGhz: deleted comments
* Format Sources
* SubGhz: add some consts and fix unit tests
* Sync API Symbols

Co-authored-by: Aleksandr Kutuzov <alleteam@gmail.com>
This commit is contained in:
Skorpionm
2023-06-30 23:03:36 +09:00
committed by GitHub
co-authored by Aleksandr Kutuzov
parent 6d9de25494
commit 8c93695d01
67 changed files with 2932 additions and 651 deletions
@@ -76,12 +76,15 @@ void subghz_chat_worker_free(SubGhzChatWorker* instance) {
free(instance);
}
bool subghz_chat_worker_start(SubGhzChatWorker* instance, uint32_t frequency) {
bool subghz_chat_worker_start(
SubGhzChatWorker* instance,
const SubGhzDevice* device,
uint32_t frequency) {
furi_assert(instance);
furi_assert(!instance->worker_running);
bool res = false;
if(subghz_tx_rx_worker_start(instance->subghz_txrx, frequency)) {
if(subghz_tx_rx_worker_start(instance->subghz_txrx, device, frequency)) {
furi_message_queue_reset(instance->event_queue);
subghz_tx_rx_worker_set_callback_have_read(
instance->subghz_txrx, subghz_chat_worker_update_rx_event_chat, instance);
@@ -1,5 +1,6 @@
#pragma once
#include "../subghz_i.h"
#include <lib/subghz/devices/devices.h>
#include <cli/cli.h>
typedef struct SubGhzChatWorker SubGhzChatWorker;
@@ -20,7 +21,10 @@ typedef struct {
SubGhzChatWorker* subghz_chat_worker_alloc(Cli* cli);
void subghz_chat_worker_free(SubGhzChatWorker* instance);
bool subghz_chat_worker_start(SubGhzChatWorker* instance, uint32_t frequency);
bool subghz_chat_worker_start(
SubGhzChatWorker* instance,
const SubGhzDevice* device,
uint32_t frequency);
void subghz_chat_worker_stop(SubGhzChatWorker* instance);
bool subghz_chat_worker_is_running(SubGhzChatWorker* instance);
SubGhzChatEvent subghz_chat_worker_get_event_chat(SubGhzChatWorker* instance);
@@ -32,9 +32,8 @@ float subghz_threshold_rssi_get(SubGhzThresholdRssi* instance) {
return instance->threshold_rssi;
}
SubGhzThresholdRssiData subghz_threshold_get_rssi_data(SubGhzThresholdRssi* instance) {
SubGhzThresholdRssiData subghz_threshold_get_rssi_data(SubGhzThresholdRssi* instance, float rssi) {
furi_assert(instance);
float rssi = furi_hal_subghz_get_rssi();
SubGhzThresholdRssiData ret = {.rssi = rssi, .is_above = false};
if(float_is_equal(instance->threshold_rssi, SUBGHZ_RAW_THRESHOLD_MIN)) {
@@ -38,6 +38,7 @@ float subghz_threshold_rssi_get(SubGhzThresholdRssi* instance);
/** Check threshold
*
* @param instance Pointer to a SubGhzThresholdRssi
* @param rssi Current RSSI
* @return SubGhzThresholdRssiData
*/
SubGhzThresholdRssiData subghz_threshold_get_rssi_data(SubGhzThresholdRssi* instance);
SubGhzThresholdRssiData subghz_threshold_get_rssi_data(SubGhzThresholdRssi* instance, float rssi);
+124 -42
View File
@@ -1,9 +1,26 @@
#include "subghz_txrx_i.h"
#include <lib/subghz/protocols/protocol_items.h>
#include <applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.h>
#include <lib/subghz/devices/cc1101_int/cc1101_int_interconnect.h>
#define TAG "SubGhz"
static void subghz_txrx_radio_device_power_on(SubGhzTxRx* instance) {
UNUSED(instance);
uint8_t attempts = 0;
while(!furi_hal_power_is_otg_enabled() && attempts++ < 5) {
furi_hal_power_enable_otg();
//CC1101 power-up time
furi_delay_ms(10);
}
}
static void subghz_txrx_radio_device_power_off(SubGhzTxRx* instance) {
UNUSED(instance);
if(furi_hal_power_is_otg_enabled()) furi_hal_power_disable_otg();
}
SubGhzTxRx* subghz_txrx_alloc() {
SubGhzTxRx* instance = malloc(sizeof(SubGhzTxRx));
instance->setting = subghz_setting_alloc();
@@ -23,16 +40,15 @@ SubGhzTxRx* subghz_txrx_alloc() {
instance->fff_data = flipper_format_string_alloc();
instance->environment = subghz_environment_alloc();
instance->is_database_loaded = subghz_environment_load_keystore(
instance->environment, EXT_PATH("subghz/assets/keeloq_mfcodes"));
subghz_environment_load_keystore(
instance->environment, EXT_PATH("subghz/assets/keeloq_mfcodes_user"));
instance->is_database_loaded =
subghz_environment_load_keystore(instance->environment, SUBGHZ_KEYSTORE_DIR_NAME);
subghz_environment_load_keystore(instance->environment, SUBGHZ_KEYSTORE_DIR_USER_NAME);
subghz_environment_set_came_atomo_rainbow_table_file_name(
instance->environment, EXT_PATH("subghz/assets/came_atomo"));
instance->environment, SUBGHZ_CAME_ATOMO_DIR_NAME);
subghz_environment_set_alutech_at_4n_rainbow_table_file_name(
instance->environment, EXT_PATH("subghz/assets/alutech_at_4n"));
instance->environment, SUBGHZ_ALUTECH_AT_4N_DIR_NAME);
subghz_environment_set_nice_flor_s_rainbow_table_file_name(
instance->environment, EXT_PATH("subghz/assets/nice_flor_s"));
instance->environment, SUBGHZ_NICE_FLOR_S_DIR_NAME);
subghz_environment_set_protocol_registry(
instance->environment, (void*)&subghz_protocol_registry);
instance->receiver = subghz_receiver_alloc_init(instance->environment);
@@ -43,18 +59,32 @@ SubGhzTxRx* subghz_txrx_alloc() {
instance->worker, (SubGhzWorkerPairCallback)subghz_receiver_decode);
subghz_worker_set_context(instance->worker, instance->receiver);
//set default device External
subghz_devices_init();
instance->radio_device_type = SubGhzRadioDeviceTypeInternal;
instance->radio_device_type =
subghz_txrx_radio_device_set(instance, SubGhzRadioDeviceTypeExternalCC1101);
return instance;
}
void subghz_txrx_free(SubGhzTxRx* instance) {
furi_assert(instance);
if(instance->radio_device_type != SubGhzRadioDeviceTypeInternal) {
subghz_txrx_radio_device_power_off(instance);
subghz_devices_end(instance->radio_device);
}
subghz_devices_deinit();
subghz_worker_free(instance->worker);
subghz_receiver_free(instance->receiver);
subghz_environment_free(instance->environment);
flipper_format_free(instance->fff_data);
furi_string_free(instance->preset->name);
subghz_setting_free(instance->setting);
free(instance->preset);
free(instance);
}
@@ -122,29 +152,26 @@ void subghz_txrx_get_frequency_and_modulation(
static void subghz_txrx_begin(SubGhzTxRx* instance, uint8_t* preset_data) {
furi_assert(instance);
furi_hal_subghz_reset();
furi_hal_subghz_idle();
furi_hal_subghz_load_custom_preset(preset_data);
furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeInput, GpioPullNo, GpioSpeedLow);
subghz_devices_reset(instance->radio_device);
subghz_devices_idle(instance->radio_device);
subghz_devices_load_preset(instance->radio_device, FuriHalSubGhzPresetCustom, preset_data);
instance->txrx_state = SubGhzTxRxStateIDLE;
}
static uint32_t subghz_txrx_rx(SubGhzTxRx* instance, uint32_t frequency) {
furi_assert(instance);
if(!furi_hal_subghz_is_frequency_valid(frequency)) {
furi_crash("SubGhz: Incorrect RX frequency.");
}
furi_assert(
instance->txrx_state != SubGhzTxRxStateRx && instance->txrx_state != SubGhzTxRxStateSleep);
furi_hal_subghz_idle();
uint32_t value = furi_hal_subghz_set_frequency_and_path(frequency);
furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeInput, GpioPullNo, GpioSpeedLow);
furi_hal_subghz_flush_rx();
subghz_txrx_speaker_on(instance);
furi_hal_subghz_rx();
subghz_devices_idle(instance->radio_device);
furi_hal_subghz_start_async_rx(subghz_worker_rx_callback, instance->worker);
uint32_t value = subghz_devices_set_frequency(instance->radio_device, frequency);
subghz_devices_flush_rx(instance->radio_device);
subghz_txrx_speaker_on(instance);
subghz_devices_start_async_rx(
instance->radio_device, subghz_worker_rx_callback, instance->worker);
subghz_worker_start(instance->worker);
instance->txrx_state = SubGhzTxRxStateRx;
return value;
@@ -153,7 +180,7 @@ static uint32_t subghz_txrx_rx(SubGhzTxRx* instance, uint32_t frequency) {
static void subghz_txrx_idle(SubGhzTxRx* instance) {
furi_assert(instance);
furi_assert(instance->txrx_state != SubGhzTxRxStateSleep);
furi_hal_subghz_idle();
subghz_devices_idle(instance->radio_device);
subghz_txrx_speaker_off(instance);
instance->txrx_state = SubGhzTxRxStateIDLE;
}
@@ -164,30 +191,26 @@ static void subghz_txrx_rx_end(SubGhzTxRx* instance) {
if(subghz_worker_is_running(instance->worker)) {
subghz_worker_stop(instance->worker);
furi_hal_subghz_stop_async_rx();
subghz_devices_stop_async_rx(instance->radio_device);
}
furi_hal_subghz_idle();
subghz_devices_idle(instance->radio_device);
subghz_txrx_speaker_off(instance);
instance->txrx_state = SubGhzTxRxStateIDLE;
}
void subghz_txrx_sleep(SubGhzTxRx* instance) {
furi_assert(instance);
furi_hal_subghz_sleep();
subghz_devices_sleep(instance->radio_device);
instance->txrx_state = SubGhzTxRxStateSleep;
}
static bool subghz_txrx_tx(SubGhzTxRx* instance, uint32_t frequency) {
furi_assert(instance);
if(!furi_hal_subghz_is_frequency_valid(frequency)) {
furi_crash("SubGhz: Incorrect TX frequency.");
}
furi_assert(instance->txrx_state != SubGhzTxRxStateSleep);
furi_hal_subghz_idle();
furi_hal_subghz_set_frequency_and_path(frequency);
furi_hal_gpio_write(&gpio_cc1101_g0, false);
furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow);
bool ret = furi_hal_subghz_tx();
subghz_devices_idle(instance->radio_device);
subghz_devices_set_frequency(instance->radio_device, frequency);
bool ret = subghz_devices_set_tx(instance->radio_device);
if(ret) {
subghz_txrx_speaker_on(instance);
instance->txrx_state = SubGhzTxRxStateTx;
@@ -249,8 +272,8 @@ SubGhzTxRxStartTxState subghz_txrx_tx_start(SubGhzTxRx* instance, FlipperFormat*
if(ret == SubGhzTxRxStartTxStateOk) {
//Start TX
furi_hal_subghz_start_async_tx(
subghz_transmitter_yield, instance->transmitter);
subghz_devices_start_async_tx(
instance->radio_device, subghz_transmitter_yield, instance->transmitter);
}
} else {
ret = SubGhzTxRxStartTxStateErrorParserOthers;
@@ -293,7 +316,7 @@ static void subghz_txrx_tx_stop(SubGhzTxRx* instance) {
furi_assert(instance);
furi_assert(instance->txrx_state == SubGhzTxRxStateTx);
//Stop TX
furi_hal_subghz_stop_async_tx();
subghz_devices_stop_async_tx(instance->radio_device);
subghz_transmitter_stop(instance->transmitter);
subghz_transmitter_free(instance->transmitter);
@@ -306,7 +329,6 @@ static void subghz_txrx_tx_stop(SubGhzTxRx* instance) {
subghz_txrx_idle(instance);
subghz_txrx_speaker_off(instance);
//Todo: Show message
// notification_message(notifications, &sequence_reset_red);
}
FlipperFormat* subghz_txrx_get_fff_data(SubGhzTxRx* instance) {
@@ -356,7 +378,7 @@ void subghz_txrx_hopper_update(SubGhzTxRx* instance) {
float rssi = -127.0f;
if(instance->hopper_state != SubGhzHopperStateRSSITimeOut) {
// See RSSI Calculation timings in CC1101 17.3 RSSI
rssi = furi_hal_subghz_get_rssi();
rssi = subghz_devices_get_rssi(instance->radio_device);
// Stay if RSSI is high enough
if(rssi > -90.0f) {
@@ -414,7 +436,7 @@ void subghz_txrx_speaker_on(SubGhzTxRx* instance) {
furi_assert(instance);
if(instance->speaker_state == SubGhzSpeakerStateEnable) {
if(furi_hal_speaker_acquire(30)) {
furi_hal_subghz_set_async_mirror_pin(&gpio_speaker);
subghz_devices_set_async_mirror_pin(instance->radio_device, &gpio_speaker);
} else {
instance->speaker_state = SubGhzSpeakerStateDisable;
}
@@ -425,7 +447,7 @@ void subghz_txrx_speaker_off(SubGhzTxRx* instance) {
furi_assert(instance);
if(instance->speaker_state != SubGhzSpeakerStateDisable) {
if(furi_hal_speaker_is_mine()) {
furi_hal_subghz_set_async_mirror_pin(NULL);
subghz_devices_set_async_mirror_pin(instance->radio_device, NULL);
furi_hal_speaker_release();
if(instance->speaker_state == SubGhzSpeakerStateShutdown)
instance->speaker_state = SubGhzSpeakerStateDisable;
@@ -437,7 +459,7 @@ void subghz_txrx_speaker_mute(SubGhzTxRx* instance) {
furi_assert(instance);
if(instance->speaker_state == SubGhzSpeakerStateEnable) {
if(furi_hal_speaker_is_mine()) {
furi_hal_subghz_set_async_mirror_pin(NULL);
subghz_devices_set_async_mirror_pin(instance->radio_device, NULL);
}
}
}
@@ -446,7 +468,7 @@ void subghz_txrx_speaker_unmute(SubGhzTxRx* instance) {
furi_assert(instance);
if(instance->speaker_state == SubGhzSpeakerStateEnable) {
if(furi_hal_speaker_is_mine()) {
furi_hal_subghz_set_async_mirror_pin(&gpio_speaker);
subghz_devices_set_async_mirror_pin(instance->radio_device, &gpio_speaker);
}
}
}
@@ -519,3 +541,63 @@ void subghz_txrx_set_raw_file_encoder_worker_callback_end(
callback,
context);
}
bool subghz_txrx_radio_device_is_external_connected(SubGhzTxRx* instance, const char* name) {
furi_assert(instance);
bool is_connect = false;
bool is_otg_enabled = furi_hal_power_is_otg_enabled();
if(!is_otg_enabled) {
subghz_txrx_radio_device_power_on(instance);
}
is_connect = subghz_devices_is_connect(subghz_devices_get_by_name(name));
if(!is_otg_enabled) {
subghz_txrx_radio_device_power_off(instance);
}
return is_connect;
}
SubGhzRadioDeviceType
subghz_txrx_radio_device_set(SubGhzTxRx* instance, SubGhzRadioDeviceType radio_device_type) {
furi_assert(instance);
if(radio_device_type == SubGhzRadioDeviceTypeExternalCC1101 &&
subghz_txrx_radio_device_is_external_connected(instance, SUBGHZ_DEVICE_CC1101_EXT_NAME)) {
subghz_txrx_radio_device_power_on(instance);
instance->radio_device = subghz_devices_get_by_name(SUBGHZ_DEVICE_CC1101_EXT_NAME);
subghz_devices_begin(instance->radio_device);
instance->radio_device_type = SubGhzRadioDeviceTypeExternalCC1101;
} else {
subghz_txrx_radio_device_power_off(instance);
if(instance->radio_device_type != SubGhzRadioDeviceTypeInternal) {
subghz_devices_end(instance->radio_device);
}
instance->radio_device = subghz_devices_get_by_name(SUBGHZ_DEVICE_CC1101_INT_NAME);
instance->radio_device_type = SubGhzRadioDeviceTypeInternal;
}
return instance->radio_device_type;
}
SubGhzRadioDeviceType subghz_txrx_radio_device_get(SubGhzTxRx* instance) {
furi_assert(instance);
return instance->radio_device_type;
}
float subghz_txrx_radio_device_get_rssi(SubGhzTxRx* instance) {
furi_assert(instance);
return subghz_devices_get_rssi(instance->radio_device);
}
const char* subghz_txrx_radio_device_get_name(SubGhzTxRx* instance) {
furi_assert(instance);
return subghz_devices_get_name(instance->radio_device);
}
bool subghz_txrx_radio_device_is_frequecy_valid(SubGhzTxRx* instance, uint32_t frequency) {
furi_assert(instance);
return subghz_devices_is_frequency_valid(instance->radio_device, frequency);
}
@@ -7,6 +7,7 @@
#include <lib/subghz/receiver.h>
#include <lib/subghz/transmitter.h>
#include <lib/subghz/protocols/raw.h>
#include <lib/subghz/devices/devices.h>
typedef struct SubGhzTxRx SubGhzTxRx;
@@ -288,3 +289,48 @@ void subghz_txrx_set_raw_file_encoder_worker_callback_end(
SubGhzTxRx* instance,
SubGhzProtocolEncoderRAWCallbackEnd callback,
void* context);
/* Checking if an external radio device is connected
*
* @param instance Pointer to a SubGhzTxRx
* @param name Name of external radio device
* @return bool True if is connected to the external radio device
*/
bool subghz_txrx_radio_device_is_external_connected(SubGhzTxRx* instance, const char* name);
/* Set the selected radio device to use
*
* @param instance Pointer to a SubGhzTxRx
* @param radio_device_type Radio device type
* @return SubGhzRadioDeviceType Type of installed radio device
*/
SubGhzRadioDeviceType
subghz_txrx_radio_device_set(SubGhzTxRx* instance, SubGhzRadioDeviceType radio_device_type);
/* Get the selected radio device to use
*
* @param instance Pointer to a SubGhzTxRx
* @return SubGhzRadioDeviceType Type of installed radio device
*/
SubGhzRadioDeviceType subghz_txrx_radio_device_get(SubGhzTxRx* instance);
/* Get RSSI the selected radio device to use
*
* @param instance Pointer to a SubGhzTxRx
* @return float RSSI
*/
float subghz_txrx_radio_device_get_rssi(SubGhzTxRx* instance);
/* Get name the selected radio device to use
*
* @param instance Pointer to a SubGhzTxRx
* @return const char* Name of installed radio device
*/
const char* subghz_txrx_radio_device_get_name(SubGhzTxRx* instance);
/* Get get intelligence whether frequency the selected radio device to use
*
* @param instance Pointer to a SubGhzTxRx
* @return bool True if the frequency is valid
*/
bool subghz_txrx_radio_device_is_frequecy_valid(SubGhzTxRx* instance, uint32_t frequency);
@@ -21,6 +21,8 @@ struct SubGhzTxRx {
SubGhzTxRxState txrx_state;
SubGhzSpeakerState speaker_state;
const SubGhzDevice* radio_device;
SubGhzRadioDeviceType radio_device_type;
SubGhzTxRxNeedSaveCallback need_save_callback;
void* need_save_context;
@@ -35,6 +35,13 @@ typedef enum {
SubGhzSpeakerStateEnable,
} SubGhzSpeakerState;
/** SubGhzRadioDeviceType */
typedef enum {
SubGhzRadioDeviceTypeAuto,
SubGhzRadioDeviceTypeInternal,
SubGhzRadioDeviceTypeExternalCC1101,
} SubGhzRadioDeviceType;
/** SubGhzRxKeyState state */
typedef enum {
SubGhzRxKeyStateIDLE,