mirror of
https://github.com/DarkFlippers/unleashed-firmware
synced 2024-11-14 16:57:22 +00:00
SubGhz: add function description
This commit is contained in:
parent
def4ae395e
commit
e817a4cdba
3 changed files with 273 additions and 5 deletions
|
@ -7,20 +7,47 @@
|
||||||
#include <lib/subghz/transmitter.h>
|
#include <lib/subghz/transmitter.h>
|
||||||
#include <lib/subghz/protocols/raw.h>
|
#include <lib/subghz/protocols/raw.h>
|
||||||
|
|
||||||
typedef void (*SubGhzTxRxNeedSaveCallback)(void* context);
|
|
||||||
|
|
||||||
typedef struct SubGhzTxRx SubGhzTxRx;
|
typedef struct SubGhzTxRx SubGhzTxRx;
|
||||||
|
|
||||||
|
typedef void (*SubGhzTxRxNeedSaveCallback)(void* context);
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
SubGhzTxRxStartTxStateOk,
|
SubGhzTxRxStartTxStateOk,
|
||||||
SubGhzTxRxStartTxStateErrorOnlyRx,
|
SubGhzTxRxStartTxStateErrorOnlyRx,
|
||||||
SubGhzTxRxStartTxStateErrorParserOthers,
|
SubGhzTxRxStartTxStateErrorParserOthers,
|
||||||
} SubGhzTxRxStartTxState;
|
} SubGhzTxRxStartTxState;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allocate SubGhzTxRx
|
||||||
|
*
|
||||||
|
* @return SubGhzTxRx* pointer to SubGhzTxRx
|
||||||
|
*/
|
||||||
SubGhzTxRx* subghz_txrx_alloc();
|
SubGhzTxRx* subghz_txrx_alloc();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Free SubGhzTxRx
|
||||||
|
*
|
||||||
|
* @param instance Pointer to a SubGhzTxRx
|
||||||
|
*/
|
||||||
void subghz_txrx_free(SubGhzTxRx* instance);
|
void subghz_txrx_free(SubGhzTxRx* instance);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the database is loaded
|
||||||
|
*
|
||||||
|
* @param instance Pointer to a SubGhzTxRx
|
||||||
|
* @return bool True if the database is loaded
|
||||||
|
*/
|
||||||
bool subghz_txrx_is_load_database(SubGhzTxRx* instance);
|
bool subghz_txrx_is_load_database(SubGhzTxRx* instance);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set preset
|
||||||
|
*
|
||||||
|
* @param instance Pointer to a SubGhzTxRx
|
||||||
|
* @param preset_name Name of preset
|
||||||
|
* @param frequency Frequency in Hz
|
||||||
|
* @param preset_data Data of preset
|
||||||
|
* @param preset_data_size Size of preset data
|
||||||
|
*/
|
||||||
void subghz_txrx_set_preset(
|
void subghz_txrx_set_preset(
|
||||||
SubGhzTxRx* instance,
|
SubGhzTxRx* instance,
|
||||||
const char* preset_name,
|
const char* preset_name,
|
||||||
|
@ -28,50 +55,235 @@ void subghz_txrx_set_preset(
|
||||||
uint8_t* preset_data,
|
uint8_t* preset_data,
|
||||||
size_t preset_data_size);
|
size_t preset_data_size);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get name of preset
|
||||||
|
*
|
||||||
|
* @param instance Pointer to a SubGhzTxRx
|
||||||
|
* @param preset String of preset
|
||||||
|
* @return const char* Name of preset
|
||||||
|
*/
|
||||||
const char* subghz_txrx_get_name_preset(SubGhzTxRx* instance, const char* preset);
|
const char* subghz_txrx_get_name_preset(SubGhzTxRx* instance, const char* preset);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get of preset
|
||||||
|
*
|
||||||
|
* @param instance Pointer to a SubGhzTxRx
|
||||||
|
* @return SubGhzRadioPreset Preset
|
||||||
|
*/
|
||||||
SubGhzRadioPreset subghz_txrx_get_preset(SubGhzTxRx* instance);
|
SubGhzRadioPreset subghz_txrx_get_preset(SubGhzTxRx* instance);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get string frequency and modulation
|
||||||
|
*
|
||||||
|
* @param instance Pointer to a SubGhzTxRx
|
||||||
|
* @param frequency Pointer to a string frequency
|
||||||
|
* @param modulation Pointer to a string modulation
|
||||||
|
*/
|
||||||
void subghz_txrx_get_frequency_modulation(
|
void subghz_txrx_get_frequency_modulation(
|
||||||
SubGhzTxRx* instance,
|
SubGhzTxRx* instance,
|
||||||
FuriString* frequency,
|
FuriString* frequency,
|
||||||
FuriString* modulation,
|
FuriString* modulation,
|
||||||
bool long_name);
|
bool long_name);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start TX CC1101
|
||||||
|
*
|
||||||
|
* @param instance Pointer to a SubGhzTxRx
|
||||||
|
* @param flipper_format Pointer to a FlipperFormat
|
||||||
|
* @return SubGhzTxRxStartTxState
|
||||||
|
*/
|
||||||
SubGhzTxRxStartTxState subghz_txrx_tx_start(SubGhzTxRx* instance, FlipperFormat* flipper_format);
|
SubGhzTxRxStartTxState subghz_txrx_tx_start(SubGhzTxRx* instance, FlipperFormat* flipper_format);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start RX CC1101
|
||||||
|
*
|
||||||
|
* @param instance Pointer to a SubGhzTxRx
|
||||||
|
*/
|
||||||
void subghz_txrx_rx_start(SubGhzTxRx* instance);
|
void subghz_txrx_rx_start(SubGhzTxRx* instance);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stop TX/RX CC1101
|
||||||
|
*
|
||||||
|
* @param instance Pointer to a SubGhzTxRx
|
||||||
|
*/
|
||||||
void subghz_txrx_stop(SubGhzTxRx* instance);
|
void subghz_txrx_stop(SubGhzTxRx* instance);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set sleep mode CC1101
|
||||||
|
*
|
||||||
|
* @param instance Pointer to a SubGhzTxRx
|
||||||
|
*/
|
||||||
void subghz_txrx_sleep(SubGhzTxRx* instance);
|
void subghz_txrx_sleep(SubGhzTxRx* instance);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update frequency CC1101 in automatic mode (hopper)
|
||||||
|
*
|
||||||
|
* @param instance Pointer to a SubGhzTxRx
|
||||||
|
*/
|
||||||
void subghz_txrx_hopper_update(SubGhzTxRx* instance);
|
void subghz_txrx_hopper_update(SubGhzTxRx* instance);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get state hopper
|
||||||
|
*
|
||||||
|
* @param instance Pointer to a SubGhzTxRx
|
||||||
|
* @return SubGhzHopperState
|
||||||
|
*/
|
||||||
SubGhzHopperState subghz_txrx_hopper_get_state(SubGhzTxRx* instance);
|
SubGhzHopperState subghz_txrx_hopper_get_state(SubGhzTxRx* instance);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set state hopper
|
||||||
|
*
|
||||||
|
* @param instance Pointer to a SubGhzTxRx
|
||||||
|
* @param state State hopper
|
||||||
|
*/
|
||||||
void subghz_txrx_hopper_set_state(SubGhzTxRx* instance, SubGhzHopperState state);
|
void subghz_txrx_hopper_set_state(SubGhzTxRx* instance, SubGhzHopperState state);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unpause hopper
|
||||||
|
*
|
||||||
|
* @param instance Pointer to a SubGhzTxRx
|
||||||
|
*/
|
||||||
void subghz_txrx_hopper_remove_pause(SubGhzTxRx* instance);
|
void subghz_txrx_hopper_remove_pause(SubGhzTxRx* instance);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set pause hopper
|
||||||
|
*
|
||||||
|
* @param instance Pointer to a SubGhzTxRx
|
||||||
|
*/
|
||||||
void subghz_txrx_hopper_pause(SubGhzTxRx* instance);
|
void subghz_txrx_hopper_pause(SubGhzTxRx* instance);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Speaker on
|
||||||
|
*
|
||||||
|
* @param instance Pointer to a SubGhzTxRx
|
||||||
|
*/
|
||||||
void subghz_txrx_speaker_on(SubGhzTxRx* instance);
|
void subghz_txrx_speaker_on(SubGhzTxRx* instance);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Speaker off
|
||||||
|
*
|
||||||
|
* @param instance Pointer to a SubGhzTxRx
|
||||||
|
*/
|
||||||
void subghz_txrx_speaker_off(SubGhzTxRx* instance);
|
void subghz_txrx_speaker_off(SubGhzTxRx* instance);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Speaker mute
|
||||||
|
*
|
||||||
|
* @param instance Pointer to a SubGhzTxRx
|
||||||
|
*/
|
||||||
void subghz_txrx_speaker_mute(SubGhzTxRx* instance);
|
void subghz_txrx_speaker_mute(SubGhzTxRx* instance);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Speaker unmute
|
||||||
|
*
|
||||||
|
* @param instance Pointer to a SubGhzTxRx
|
||||||
|
*/
|
||||||
void subghz_txrx_speaker_unmute(SubGhzTxRx* instance);
|
void subghz_txrx_speaker_unmute(SubGhzTxRx* instance);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set state speaker
|
||||||
|
*
|
||||||
|
* @param instance Pointer to a SubGhzTxRx
|
||||||
|
* @param state State speaker
|
||||||
|
*/
|
||||||
void subghz_txrx_speaker_set_state(SubGhzTxRx* instance, SubGhzSpeakerState state);
|
void subghz_txrx_speaker_set_state(SubGhzTxRx* instance, SubGhzSpeakerState state);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get state speaker
|
||||||
|
*
|
||||||
|
* @param instance Pointer to a SubGhzTxRx
|
||||||
|
* @return SubGhzSpeakerState
|
||||||
|
*/
|
||||||
SubGhzSpeakerState subghz_txrx_speaker_get_state(SubGhzTxRx* instance);
|
SubGhzSpeakerState subghz_txrx_speaker_get_state(SubGhzTxRx* instance);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* load decoder by name protocol
|
||||||
|
*
|
||||||
|
* @param instance Pointer to a SubGhzTxRx
|
||||||
|
* @param name_protocol Name protocol
|
||||||
|
* @return bool True if the decoder is loaded
|
||||||
|
*/
|
||||||
bool subghz_txrx_load_decoder_by_name_protocol(SubGhzTxRx* instance, const char* name_protocol);
|
bool subghz_txrx_load_decoder_by_name_protocol(SubGhzTxRx* instance, const char* name_protocol);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get decoder
|
||||||
|
*
|
||||||
|
* @param instance Pointer to a SubGhzTxRx
|
||||||
|
* @return SubGhzProtocolDecoderBase* Pointer to a SubGhzProtocolDecoderBase
|
||||||
|
*/
|
||||||
SubGhzProtocolDecoderBase* subghz_txrx_get_decoder(SubGhzTxRx* instance);
|
SubGhzProtocolDecoderBase* subghz_txrx_get_decoder(SubGhzTxRx* instance);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set callback for save data
|
||||||
|
*
|
||||||
|
* @param instance Pointer to a SubGhzTxRx
|
||||||
|
* @param callback Callback for save data
|
||||||
|
* @param context Context for callback
|
||||||
|
*/
|
||||||
void subghz_txrx_need_save_callback_set(
|
void subghz_txrx_need_save_callback_set(
|
||||||
SubGhzTxRx* instance,
|
SubGhzTxRx* instance,
|
||||||
SubGhzTxRxNeedSaveCallback callback,
|
SubGhzTxRxNeedSaveCallback callback,
|
||||||
void* context);
|
void* context);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get pointer to a load data key
|
||||||
|
*
|
||||||
|
* @param instance Pointer to a SubGhzTxRx
|
||||||
|
* @return FlipperFormat*
|
||||||
|
*/
|
||||||
FlipperFormat* subghz_txtx_get_fff_data(SubGhzTxRx* instance);
|
FlipperFormat* subghz_txtx_get_fff_data(SubGhzTxRx* instance);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get pointer to a SugGhzSetting
|
||||||
|
*
|
||||||
|
* @param instance Pointer to a SubGhzTxRx
|
||||||
|
* @return SubGhzSetting*
|
||||||
|
*/
|
||||||
SubGhzSetting* subghz_txrx_get_setting(SubGhzTxRx* instance);
|
SubGhzSetting* subghz_txrx_get_setting(SubGhzTxRx* instance);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is it possible to save this protocol
|
||||||
|
*
|
||||||
|
* @param instance Pointer to a SubGhzTxRx
|
||||||
|
* @return bool True if it is possible to save this protocol
|
||||||
|
*/
|
||||||
bool subghz_txrx_protocol_is_preserved(SubGhzTxRx* instance);
|
bool subghz_txrx_protocol_is_preserved(SubGhzTxRx* instance);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is it possible to send this protocol
|
||||||
|
*
|
||||||
|
* @param instance Pointer to a SubGhzTxRx
|
||||||
|
* @return bool True if it is possible to send this protocol
|
||||||
|
*/
|
||||||
bool subghz_txrx_protocol_is_send(SubGhzTxRx* instance, bool check_type);
|
bool subghz_txrx_protocol_is_send(SubGhzTxRx* instance, bool check_type);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set filter, what types of decoder to use
|
||||||
|
*
|
||||||
|
* @param instance Pointer to a SubGhzTxRx
|
||||||
|
* @param filter Filter
|
||||||
|
*/
|
||||||
void subghz_txrx_receiver_set_filter(SubGhzTxRx* instance, SubGhzProtocolFlag filter);
|
void subghz_txrx_receiver_set_filter(SubGhzTxRx* instance, SubGhzProtocolFlag filter);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set callback for receive data
|
||||||
|
*
|
||||||
|
* @param instance Pointer to a SubGhzTxRx
|
||||||
|
* @param callback Callback for receive data
|
||||||
|
* @param context Context for callback
|
||||||
|
*/
|
||||||
void subghz_txrx_set_rx_calback(
|
void subghz_txrx_set_rx_calback(
|
||||||
SubGhzTxRx* instance,
|
SubGhzTxRx* instance,
|
||||||
SubGhzReceiverCallback callback,
|
SubGhzReceiverCallback callback,
|
||||||
void* context);
|
void* context);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set callback for Raw decoder, end of data transfer
|
||||||
|
*
|
||||||
|
* @param instance Pointer to a SubGhzTxRx
|
||||||
|
* @param callback Callback for Raw decoder, end of data transfer
|
||||||
|
* @param context Context for callback
|
||||||
|
*/
|
||||||
void subghz_txrx_set_raw_file_encoder_worker_set_callback_end(
|
void subghz_txrx_set_raw_file_encoder_worker_set_callback_end(
|
||||||
SubGhzTxRx* instance,
|
SubGhzTxRx* instance,
|
||||||
SubGhzProtocolEncoderRAWCallbackEnd callback,
|
SubGhzProtocolEncoderRAWCallbackEnd callback,
|
||||||
|
|
|
@ -2,6 +2,17 @@
|
||||||
#include "subghz_types.h"
|
#include "subghz_types.h"
|
||||||
#include "subghz_txrx.h"
|
#include "subghz_txrx.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate data for protocol
|
||||||
|
*
|
||||||
|
* @param instance Pointer to a SubGhzTxRx
|
||||||
|
* @param preset_name Name of preset
|
||||||
|
* @param frequency Frequency in Hz
|
||||||
|
* @param protocol_name Name of protocol
|
||||||
|
* @param key Key
|
||||||
|
* @param bit Bit
|
||||||
|
* @return bool True if success
|
||||||
|
*/
|
||||||
bool subghz_txrx_gen_data_protocol(
|
bool subghz_txrx_gen_data_protocol(
|
||||||
void* context,
|
void* context,
|
||||||
const char* preset_name,
|
const char* preset_name,
|
||||||
|
@ -10,6 +21,18 @@ bool subghz_txrx_gen_data_protocol(
|
||||||
uint64_t key,
|
uint64_t key,
|
||||||
uint32_t bit);
|
uint32_t bit);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate data for protocol and te
|
||||||
|
*
|
||||||
|
* @param instance Pointer to a SubGhzTxRx
|
||||||
|
* @param preset_name Name of preset
|
||||||
|
* @param frequency Frequency in Hz
|
||||||
|
* @param protocol_name Name of protocol
|
||||||
|
* @param key Key
|
||||||
|
* @param bit Bit
|
||||||
|
* @param te Te
|
||||||
|
* @return bool True if success
|
||||||
|
*/
|
||||||
bool subghz_txrx_gen_data_protocol_and_te(
|
bool subghz_txrx_gen_data_protocol_and_te(
|
||||||
SubGhzTxRx* instance,
|
SubGhzTxRx* instance,
|
||||||
const char* preset_name,
|
const char* preset_name,
|
||||||
|
@ -19,6 +42,18 @@ bool subghz_txrx_gen_data_protocol_and_te(
|
||||||
uint32_t bit,
|
uint32_t bit,
|
||||||
uint32_t te);
|
uint32_t te);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate data Keeloq protocol
|
||||||
|
*
|
||||||
|
* @param instance Pointer to a SubGhzTxRx
|
||||||
|
* @param preset_name Name of preset
|
||||||
|
* @param frequency Frequency in Hz
|
||||||
|
* @param serial Serial number
|
||||||
|
* @param btn Button
|
||||||
|
* @param cnt Counter
|
||||||
|
* @param manufacture_name Name of Keeloq sysmem
|
||||||
|
* @return bool True if success
|
||||||
|
*/
|
||||||
bool subghz_txrx_gen_keelog_protocol(
|
bool subghz_txrx_gen_keelog_protocol(
|
||||||
SubGhzTxRx* instance,
|
SubGhzTxRx* instance,
|
||||||
const char* preset_name,
|
const char* preset_name,
|
||||||
|
@ -73,6 +108,17 @@ bool subghz_scene_set_type_submenu_gen_data_somfy_telis( //TODO rename
|
||||||
uint8_t btn,
|
uint8_t btn,
|
||||||
uint16_t cnt);
|
uint16_t cnt);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate data SecPlus v2 protocol
|
||||||
|
*
|
||||||
|
* @param instance Pointer to a SubGhzTxRx
|
||||||
|
* @param name_preset Name of preset
|
||||||
|
* @param frequency Frequency in Hz
|
||||||
|
* @param serial Serial number
|
||||||
|
* @param btn Button
|
||||||
|
* @param cnt Counter
|
||||||
|
* @return bool True if success
|
||||||
|
*/
|
||||||
bool subghz_txrx_gen_secplus_v2_protocol(
|
bool subghz_txrx_gen_secplus_v2_protocol(
|
||||||
SubGhzTxRx* instance,
|
SubGhzTxRx* instance,
|
||||||
const char* name_preset,
|
const char* name_preset,
|
||||||
|
@ -81,6 +127,14 @@ bool subghz_txrx_gen_secplus_v2_protocol(
|
||||||
uint8_t btn,
|
uint8_t btn,
|
||||||
uint32_t cnt);
|
uint32_t cnt);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate data SecPlus v1 protocol
|
||||||
|
*
|
||||||
|
* @param instance Pointer to a SubGhzTxRx
|
||||||
|
* @param name_preset Name of preset
|
||||||
|
* @param frequency Frequency in Hz
|
||||||
|
* @return bool True if success
|
||||||
|
*/
|
||||||
bool subghz_txrx_gen_secplus_v1_protocol(
|
bool subghz_txrx_gen_secplus_v1_protocol(
|
||||||
SubGhzTxRx* instance,
|
SubGhzTxRx* instance,
|
||||||
const char* name_preset,
|
const char* name_preset,
|
||||||
|
|
|
@ -163,21 +163,23 @@ bool subghz_key_load(SubGhz* subghz, const char* file_path, bool show_dialog) {
|
||||||
FURI_LOG_E(TAG, "Missing Protocol");
|
FURI_LOG_E(TAG, "Missing Protocol");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FlipperFormat* fff_data = subghz_txtx_get_fff_data(subghz->txrx);
|
||||||
if(!strcmp(furi_string_get_cstr(temp_str), "RAW")) {
|
if(!strcmp(furi_string_get_cstr(temp_str), "RAW")) {
|
||||||
//if RAW
|
//if RAW
|
||||||
subghz->load_type_file = SubGhzLoadTypeFileRaw;
|
subghz->load_type_file = SubGhzLoadTypeFileRaw;
|
||||||
subghz_protocol_raw_gen_fff_data(subghz_txtx_get_fff_data(subghz->txrx), file_path);
|
subghz_protocol_raw_gen_fff_data(fff_data, file_path);
|
||||||
} else {
|
} else {
|
||||||
subghz->load_type_file = SubGhzLoadTypeFileKey;
|
subghz->load_type_file = SubGhzLoadTypeFileKey;
|
||||||
stream_copy_full(
|
stream_copy_full(
|
||||||
flipper_format_get_raw_stream(fff_data_file),
|
flipper_format_get_raw_stream(fff_data_file),
|
||||||
flipper_format_get_raw_stream(subghz_txtx_get_fff_data(subghz->txrx)));
|
flipper_format_get_raw_stream(fff_data));
|
||||||
}
|
}
|
||||||
|
|
||||||
if(subghz_txrx_load_decoder_by_name_protocol(
|
if(subghz_txrx_load_decoder_by_name_protocol(
|
||||||
subghz->txrx, furi_string_get_cstr(temp_str))) {
|
subghz->txrx, furi_string_get_cstr(temp_str))) {
|
||||||
SubGhzProtocolStatus status = subghz_protocol_decoder_base_deserialize(
|
SubGhzProtocolStatus status = subghz_protocol_decoder_base_deserialize(
|
||||||
subghz_txrx_get_decoder(subghz->txrx), subghz_txtx_get_fff_data(subghz->txrx));
|
subghz_txrx_get_decoder(subghz->txrx), fff_data);
|
||||||
if(status != SubGhzProtocolStatusOk) {
|
if(status != SubGhzProtocolStatusOk) {
|
||||||
load_key_state = SubGhzLoadKeyStateProtocolDescriptionErr;
|
load_key_state = SubGhzLoadKeyStateProtocolDescriptionErr;
|
||||||
break;
|
break;
|
||||||
|
|
Loading…
Reference in a new issue