This commit is contained in:
Willy-JL
2023-05-14 19:46:20 +01:00
41 changed files with 871 additions and 1083 deletions

View File

@@ -12,7 +12,9 @@
#include <flipper_format/flipper_format_i.h>
#include <lib/toolbox/path.h>
#include <applications/main/subghz/subghz_i.h>
#include <lib/subghz/receiver.h>
#include <lib/subghz/transmitter.h>
#include <lib/subghz/subghz_setting.h>
#include <lib/subghz/protocols/raw.h>
#include <lib/subghz/protocols/protocol_items.h>
@@ -355,7 +357,7 @@ bool subghz_remote_key_load(
bool res = false;
subghz_custom_btn_set(0);
subghz_custom_btn_set(SUBGHZ_CUSTOM_BTN_OK);
keeloq_reset_original_btn();
subghz_custom_btns_reset();

View File

@@ -11,6 +11,4 @@
// End of list
// Target firmware to build for
#ifndef TOTP_TARGET_FIRMWARE
#define TOTP_TARGET_FIRMWARE TOTP_FIRMWARE_XTREME
#endif

View File

@@ -104,6 +104,13 @@ const WifiMarauderItem items[NUM_MENU_ITEMS] = {
INPUT_ARGS,
FOCUS_CONSOLE_END,
SHOW_STOPSCAN_TIP},
{"Sniff pmkid on selected aps",
{""},
1,
{"sniffpmkid -d -l"},
NO_ARGS,
FOCUS_CONSOLE_END,
NO_TIP},
{"Channel",
{"get", "set"},
2,

View File

@@ -4,7 +4,7 @@
extern "C" {
#endif
#define WIFI_MARAUDER_APP_VERSION "v0.3.4"
#define WIFI_MARAUDER_APP_VERSION "v0.3.5"
typedef struct WifiMarauderApp WifiMarauderApp;

View File

@@ -26,7 +26,7 @@
#include <lib/toolbox/path.h>
#include <dialogs/dialogs.h>
#define NUM_MENU_ITEMS (18)
#define NUM_MENU_ITEMS (19)
#define WIFI_MARAUDER_TEXT_BOX_STORE_SIZE (4096)
#define WIFI_MARAUDER_TEXT_INPUT_STORE_SIZE (512)

View File

@@ -91,3 +91,9 @@ typedef enum {
SubGhzViewReceiverModeLive,
SubGhzViewReceiverModeFile,
} SubGhzViewReceiverMode;
typedef enum {
SubGhzDecodeRawStateStart,
SubGhzDecodeRawStateLoading,
SubGhzDecodeRawStateLoaded,
} SubGhzDecodeRawState;

View File

@@ -120,7 +120,8 @@ bool subghz_scene_decode_raw_next(SubGhz* subghz) {
uint32_t duration = level_duration_get_duration(level_duration);
subghz_receiver_decode(receiver, level, duration);
} else {
subghz->decode_raw_state = SubGhzDecodeRawStateLoaded;
scene_manager_set_scene_state(
subghz->scene_manager, SubGhzSceneDecodeRAW, SubGhzDecodeRawStateLoaded);
subghz->state_notifications = SubGhzNotificationStateIDLE;
subghz_view_receiver_add_data_progress(subghz->subghz_receiver, "Done!");
@@ -155,11 +156,13 @@ void subghz_scene_decode_raw_on_enter(void* context) {
subghz_txrx_receiver_set_filter(subghz->txrx, SubGhzProtocolFlag_Decodable);
if(subghz->decode_raw_state == SubGhzDecodeRawStateStart) {
if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneDecodeRAW) ==
SubGhzDecodeRawStateStart) {
//Decode RAW to history
subghz_history_reset(subghz->history);
if(subghz_scene_decode_raw_start(subghz)) {
subghz->decode_raw_state = SubGhzDecodeRawStateLoading;
scene_manager_set_scene_state(
subghz->scene_manager, SubGhzSceneDecodeRAW, SubGhzDecodeRawStateLoading);
subghz->state_notifications = SubGhzNotificationStateRx;
}
} else {
@@ -192,10 +195,9 @@ bool subghz_scene_decode_raw_on_event(void* context, SceneManagerEvent event) {
if(event.type == SceneManagerEventTypeCustom) {
switch(event.event) {
case SubGhzCustomEventViewReceiverBack:
subghz->decode_raw_state = SubGhzDecodeRawStateStart;
scene_manager_set_scene_state(
subghz->scene_manager, SubGhzSceneDecodeRAW, SubGhzDecodeRawStateStart);
subghz->idx_menu_chosen = 0;
subghz->in_decoder_scene = false;
subghz->in_decoder_scene_skip = false;
subghz_txrx_set_rx_calback(subghz->txrx, NULL, subghz);
@@ -214,7 +216,6 @@ bool subghz_scene_decode_raw_on_event(void* context, SceneManagerEvent event) {
case SubGhzCustomEventViewReceiverOK:
subghz->idx_menu_chosen = subghz_view_receiver_get_idx_menu(subghz->subghz_receiver);
subghz->state_notifications = SubGhzNotificationStateIDLE;
subghz->in_decoder_scene = true;
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneReceiverInfo);
consumed = true;
break;
@@ -242,7 +243,7 @@ bool subghz_scene_decode_raw_on_event(void* context, SceneManagerEvent event) {
break;
}
switch(subghz->decode_raw_state) {
switch(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneDecodeRAW)) {
case SubGhzDecodeRawStateLoading:
subghz_scene_decode_raw_next(subghz);
break;

View File

@@ -141,7 +141,7 @@ bool subghz_scene_receiver_info_on_event(void* context, SceneManagerEvent event)
subghz_scene_receiver_info_draw_widget(subghz);
subghz_txrx_stop(subghz->txrx);
if(!subghz->in_decoder_scene) {
if(!scene_manager_has_previous_scene(subghz->scene_manager, SubGhzSceneDecodeRAW)) {
subghz_txrx_rx_start(subghz->txrx);
subghz_txrx_hopper_unpause(subghz->txrx);
@@ -161,9 +161,6 @@ bool subghz_scene_receiver_info_on_event(void* context, SceneManagerEvent event)
if(subghz_txrx_protocol_is_serializable(subghz->txrx)) {
subghz_file_name_clear(subghz);
if(subghz->in_decoder_scene) {
subghz->in_decoder_scene_skip = true;
}
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSaveName);
}
return true;
@@ -192,9 +189,7 @@ bool subghz_scene_receiver_info_on_event(void* context, SceneManagerEvent event)
void subghz_scene_receiver_info_on_exit(void* context) {
SubGhz* subghz = context;
if(subghz->in_decoder_scene && !subghz->in_decoder_scene_skip) {
subghz->in_decoder_scene = false;
}
widget_reset(subghz->widget);
keeloq_reset_mfname();
keeloq_reset_kl_type();

View File

@@ -127,7 +127,7 @@ bool subghz_scene_save_name_on_event(void* context, SceneManagerEvent event) {
if(!(strcmp(subghz->file_name_tmp, "") == 0) ||
scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneReadRAW) !=
SubGhzCustomEventManagerNoSet) {
if(!subghz->in_decoder_scene) {
if(!scene_manager_has_previous_scene(subghz->scene_manager, SubGhzSceneDecodeRAW)) {
furi_string_set(subghz->file_path, subghz->file_path_tmp);
}
}

View File

@@ -25,7 +25,7 @@ bool subghz_scene_save_success_on_event(void* context, SceneManagerEvent event)
SubGhz* subghz = context;
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == SubGhzCustomEventSceneSaveSuccess) {
if(!subghz->in_decoder_scene) {
if(!scene_manager_has_previous_scene(subghz->scene_manager, SubGhzSceneDecodeRAW)) {
if(!scene_manager_search_and_switch_to_previous_scene(
subghz->scene_manager, SubGhzSceneReceiver)) {
subghz_rx_key_state_set(subghz, SubGhzRxKeyStateRAWSave);
@@ -39,7 +39,9 @@ bool subghz_scene_save_success_on_event(void* context, SceneManagerEvent event)
}
}
} else {
subghz->decode_raw_state = SubGhzDecodeRawStateStart;
scene_manager_set_scene_state(
subghz->scene_manager, SubGhzSceneDecodeRAW, SubGhzDecodeRawStateStart);
subghz->idx_menu_chosen = 0;
subghz_txrx_set_rx_calback(subghz->txrx, NULL, subghz);
@@ -65,11 +67,6 @@ bool subghz_scene_save_success_on_event(void* context, SceneManagerEvent event)
void subghz_scene_save_success_on_exit(void* context) {
SubGhz* subghz = context;
if(subghz->in_decoder_scene) {
subghz->in_decoder_scene = false;
subghz->in_decoder_scene_skip = false;
}
// Clear view
Popup* popup = subghz->popup;

View File

@@ -100,8 +100,8 @@ bool subghz_scene_transmitter_on_event(void* context, SceneManagerEvent event) {
} else if(event.event == SubGhzCustomEventViewTransmitterSendStop) {
subghz->state_notifications = SubGhzNotificationStateIDLE;
subghz_txrx_stop(subghz->txrx);
if(subghz_custom_btn_get() != 0) {
subghz_custom_btn_set(0);
if(subghz_custom_btn_get() != SUBGHZ_CUSTOM_BTN_OK) {
subghz_custom_btn_set(SUBGHZ_CUSTOM_BTN_OK);
uint8_t tmp_counter = furi_hal_subghz_get_rolling_counter_mult();
furi_hal_subghz_set_rolling_counter_mult(0);
// Calling restore!

View File

@@ -62,9 +62,6 @@ SubGhz* subghz_alloc(bool alloc_for_tx_only) {
// GUI
subghz->gui = furi_record_open(RECORD_GUI);
subghz->in_decoder_scene = false;
subghz->in_decoder_scene_skip = false;
// View Dispatcher
subghz->view_dispatcher = view_dispatcher_alloc();
view_dispatcher_enable_queue(subghz->view_dispatcher);

View File

@@ -54,12 +54,6 @@ typedef struct {
uint8_t seed[4];
} SecureData;
typedef enum {
SubGhzDecodeRawStateStart,
SubGhzDecodeRawStateLoading,
SubGhzDecodeRawStateLoaded,
} SubGhzDecodeRawState;
struct SubGhz {
Gui* gui;
NotificationApp* notifications;
@@ -98,16 +92,12 @@ struct SubGhz {
FuriString* error_str;
SubGhzLock lock;
bool in_decoder_scene;
bool in_decoder_scene_skip;
bool ignore_starline;
bool ignore_auto_alarms;
bool ignore_magellan;
SecureData* secure_data;
SubGhzDecodeRawState decode_raw_state;
SubGhzFileEncoderWorker* decode_raw_file_worker_encoder;
SubGhzThresholdRssi* threshold_rssi;

View File

@@ -109,7 +109,7 @@ bool subghz_view_transmitter_input(InputEvent* event, void* context) {
},
false);
return false;
}
} // Finish "Back" key processing
with_view_model(
subghz_transmitter->view,
@@ -121,124 +121,67 @@ bool subghz_view_transmitter_input(InputEvent* event, void* context) {
},
true);
if(can_be_sent && event->key == InputKeyOk && event->type == InputTypePress) {
subghz_custom_btn_set(0);
with_view_model(
subghz_transmitter->view,
SubGhzViewTransmitterModel * model,
{
furi_string_reset(model->temp_button_id);
model->draw_temp_button = false;
},
true);
subghz_transmitter->callback(
SubGhzCustomEventViewTransmitterSendStart, subghz_transmitter->context);
return true;
} else if(can_be_sent && event->key == InputKeyOk && event->type == InputTypeRelease) {
subghz_transmitter->callback(
SubGhzCustomEventViewTransmitterSendStop, subghz_transmitter->context);
return true;
}
if(can_be_sent) {
if(event->key == InputKeyOk && event->type == InputTypePress) {
subghz_custom_btn_set(SUBGHZ_CUSTOM_BTN_OK);
with_view_model(
subghz_transmitter->view,
SubGhzViewTransmitterModel * model,
{
furi_string_reset(model->temp_button_id);
model->draw_temp_button = false;
},
true);
subghz_transmitter->callback(
SubGhzCustomEventViewTransmitterSendStart, subghz_transmitter->context);
return true;
} else if(event->key == InputKeyOk && event->type == InputTypeRelease) {
subghz_transmitter->callback(
SubGhzCustomEventViewTransmitterSendStop, subghz_transmitter->context);
return true;
} // Finish "OK" key processing
// Temp Buttons (UP)
if(can_be_sent && event->key == InputKeyUp && event->type == InputTypePress) {
subghz_custom_btn_set(1);
with_view_model(
subghz_transmitter->view,
SubGhzViewTransmitterModel * model,
{
furi_string_reset(model->temp_button_id);
if(subghz_custom_btn_get_original() != 0) {
if(subghz_custom_btn_get() == 1) {
furi_string_printf(
model->temp_button_id, "%01X", subghz_custom_btn_get_original());
model->draw_temp_button = true;
}
}
},
true);
subghz_transmitter->callback(
SubGhzCustomEventViewTransmitterSendStart, subghz_transmitter->context);
return true;
} else if(can_be_sent && event->key == InputKeyUp && event->type == InputTypeRelease) {
subghz_transmitter->callback(
SubGhzCustomEventViewTransmitterSendStop, subghz_transmitter->context);
return true;
}
// Down
if(can_be_sent && event->key == InputKeyDown && event->type == InputTypePress) {
subghz_custom_btn_set(2);
with_view_model(
subghz_transmitter->view,
SubGhzViewTransmitterModel * model,
{
furi_string_reset(model->temp_button_id);
if(subghz_custom_btn_get_original() != 0) {
if(subghz_custom_btn_get() == 2) {
furi_string_printf(
model->temp_button_id, "%01X", subghz_custom_btn_get_original());
model->draw_temp_button = true;
}
}
},
true);
subghz_transmitter->callback(
SubGhzCustomEventViewTransmitterSendStart, subghz_transmitter->context);
return true;
} else if(can_be_sent && event->key == InputKeyDown && event->type == InputTypeRelease) {
subghz_transmitter->callback(
SubGhzCustomEventViewTransmitterSendStop, subghz_transmitter->context);
return true;
}
// Left
if(can_be_sent && event->key == InputKeyLeft && event->type == InputTypePress) {
subghz_custom_btn_set(3);
with_view_model(
subghz_transmitter->view,
SubGhzViewTransmitterModel * model,
{
furi_string_reset(model->temp_button_id);
if(subghz_custom_btn_get_original() != 0) {
if(subghz_custom_btn_get() == 3) {
furi_string_printf(
model->temp_button_id, "%01X", subghz_custom_btn_get_original());
model->draw_temp_button = true;
}
}
},
true);
subghz_transmitter->callback(
SubGhzCustomEventViewTransmitterSendStart, subghz_transmitter->context);
return true;
} else if(can_be_sent && event->key == InputKeyLeft && event->type == InputTypeRelease) {
subghz_transmitter->callback(
SubGhzCustomEventViewTransmitterSendStop, subghz_transmitter->context);
return true;
}
// Right
if(can_be_sent && event->key == InputKeyRight && event->type == InputTypePress) {
subghz_custom_btn_set(4);
with_view_model(
subghz_transmitter->view,
SubGhzViewTransmitterModel * model,
{
furi_string_reset(model->temp_button_id);
if(subghz_custom_btn_get_original() != 0) {
if(subghz_custom_btn_get() == 4) {
furi_string_printf(
model->temp_button_id, "%01X", subghz_custom_btn_get_original());
model->draw_temp_button = true;
}
}
},
true);
subghz_transmitter->callback(
SubGhzCustomEventViewTransmitterSendStart, subghz_transmitter->context);
return true;
} else if(can_be_sent && event->key == InputKeyRight && event->type == InputTypeRelease) {
subghz_transmitter->callback(
SubGhzCustomEventViewTransmitterSendStop, subghz_transmitter->context);
return true;
if(subghz_custom_btn_is_allowed()) {
uint8_t temp_btn_id;
if(event->key == InputKeyUp) {
temp_btn_id = SUBGHZ_CUSTOM_BTN_UP;
} else if(event->key == InputKeyDown) {
temp_btn_id = SUBGHZ_CUSTOM_BTN_DOWN;
} else if(event->key == InputKeyLeft) {
temp_btn_id = SUBGHZ_CUSTOM_BTN_LEFT;
} else if(event->key == InputKeyRight) {
temp_btn_id = SUBGHZ_CUSTOM_BTN_RIGHT;
} else {
// Finish processing if the button is different
return true;
}
if(event->type == InputTypePress) {
with_view_model(
subghz_transmitter->view,
SubGhzViewTransmitterModel * model,
{
furi_string_reset(model->temp_button_id);
if(subghz_custom_btn_get_original() != 0) {
if(subghz_custom_btn_set(temp_btn_id)) {
furi_string_printf(
model->temp_button_id,
"%01X",
subghz_custom_btn_get_original());
model->draw_temp_button = true;
}
}
},
true);
subghz_transmitter->callback(
SubGhzCustomEventViewTransmitterSendStart, subghz_transmitter->context);
return true;
} else if(event->type == InputTypeRelease) {
subghz_transmitter->callback(
SubGhzCustomEventViewTransmitterSendStop, subghz_transmitter->context);
return true;
}
}
}
return true;

View File

@@ -389,7 +389,7 @@ static inline FuriHalBtProfile get_hal_bt_profile(BtProfile profile) {
}
}
static void bt_restart(Bt* bt) {
void bt_restart(Bt* bt) {
furi_hal_bt_change_app(get_hal_bt_profile(bt->profile), bt_on_gap_event_callback, bt);
furi_hal_bt_start_advertising();
}

View File

@@ -41,28 +41,6 @@ typedef void (*BtStatusChangedCallback)(BtStatus status, void* context);
*/
bool bt_set_profile(Bt* bt, BtProfile profile);
void bt_set_profile_adv_name(Bt* bt, const char* fmt, ...);
const char* bt_get_profile_adv_name(Bt* bt);
void bt_set_profile_mac_address(Bt* bt, const uint8_t mac[6]);
const uint8_t* bt_get_profile_mac_address(Bt* bt);
bool bt_remote_rssi(Bt* bt, uint8_t* rssi);
void bt_set_profile_pairing_method(Bt* bt, GapPairing pairing_method);
GapPairing bt_get_profile_pairing_method(Bt* bt);
/** Stop saving new peer key to flash (in .bt.keys file)
*
*/
void bt_disable_peer_key_update(Bt* bt);
/** Enable saving peer key to internal flash (enable by default)
*
* @note This function should be called if bt_disable_peer_key_update was called before
*/
void bt_enable_peer_key_update(Bt* bt);
/** Disconnect from Central
*
* @param bt Bt instance
@@ -97,6 +75,30 @@ void bt_keys_storage_set_storage_path(Bt* bt, const char* keys_storage_path);
*/
void bt_keys_storage_set_default_path(Bt* bt);
void bt_set_profile_adv_name(Bt* bt, const char* fmt, ...);
const char* bt_get_profile_adv_name(Bt* bt);
void bt_set_profile_mac_address(Bt* bt, const uint8_t mac[6]);
const uint8_t* bt_get_profile_mac_address(Bt* bt);
bool bt_remote_rssi(Bt* bt, uint8_t* rssi);
void bt_set_profile_pairing_method(Bt* bt, GapPairing pairing_method);
GapPairing bt_get_profile_pairing_method(Bt* bt);
/** Stop saving new peer key to flash (in .bt.keys file)
*
*/
void bt_disable_peer_key_update(Bt* bt);
/** Enable saving peer key to internal flash (enable by default)
*
* @note This function should be called if bt_disable_peer_key_update was called before
*/
void bt_enable_peer_key_update(Bt* bt);
#ifdef __cplusplus
}
#endif

View File

@@ -41,7 +41,7 @@ void popup_free(Popup* popup);
*/
View* popup_get_view(Popup* popup);
/** Set popup header text
/** Set popup callback function
*
* @param popup Popup instance
* @param callback PopupCallback

View File

@@ -467,12 +467,13 @@ static void text_input_handle_ok(TextInput* text_input, TextInputModel* model, I
if(shift != (text_length == 0)) {
selected = char_to_uppercase(selected);
}
const char replace[2] = {selected, 0};
if(model->clear_default_text) {
furi_string_set_str(model->temp_str, &selected);
furi_string_set_str(model->temp_str, replace);
model->cursor_pos = 1;
} else {
furi_string_set_str(model->temp_str, model->text_buffer);
furi_string_replace_at(model->temp_str, model->cursor_pos, 0, &selected);
furi_string_replace_at(model->temp_str, model->cursor_pos, 0, replace);
model->cursor_pos++;
}
strcpy(model->text_buffer, furi_string_get_cstr(model->temp_str));
@@ -602,6 +603,9 @@ TextInput* text_input_alloc() {
{
model->validator_text = furi_string_alloc();
model->temp_str = furi_string_alloc();
model->minimum_length = 1;
model->cursor_pos = 0;
model->cursor_select = false;
},
false);

View File

@@ -39,6 +39,7 @@ bool bt_settings_scene_forget_dev_confirm_on_event(void* context, SceneManagerEv
storage_simply_remove(storage, BAD_KB_KEYS_PATH);
storage_simply_remove(
storage, EXT_PATH("apps_data/hid_ble/") HID_BT_KEYS_STORAGE_NAME);
storage_simply_remove(storage, EXT_PATH("authenticator/.bt_hid.keys"));
furi_record_close(RECORD_STORAGE);
scene_manager_next_scene(app->scene_manager, BtSettingsAppSceneForgetDevSuccess);

View File

@@ -2773,7 +2773,8 @@ Function,+,subghz_block_generic_get_preset_name,void,"const char*, FuriString*"
Function,+,subghz_block_generic_serialize,SubGhzProtocolStatus,"SubGhzBlockGeneric*, FlipperFormat*, SubGhzRadioPreset*"
Function,-,subghz_custom_btn_get,uint8_t,
Function,-,subghz_custom_btn_get_original,uint8_t,
Function,+,subghz_custom_btn_set,void,uint8_t
Function,-,subghz_custom_btn_is_allowed,_Bool,
Function,+,subghz_custom_btn_set,_Bool,uint8_t
Function,-,subghz_custom_btn_set_max,void,uint8_t
Function,-,subghz_custom_btn_set_original,void,uint8_t
Function,+,subghz_custom_btns_reset,void,
1 entry status name type params
2773 Function + subghz_block_generic_serialize SubGhzProtocolStatus SubGhzBlockGeneric*, FlipperFormat*, SubGhzRadioPreset*
2774 Function - subghz_custom_btn_get uint8_t
2775 Function - subghz_custom_btn_get_original uint8_t
2776 Function + - subghz_custom_btn_set subghz_custom_btn_is_allowed void _Bool uint8_t
2777 Function + subghz_custom_btn_set _Bool uint8_t
2778 Function - subghz_custom_btn_set_max void uint8_t
2779 Function - subghz_custom_btn_set_original void uint8_t
2780 Function + subghz_custom_btns_reset void

View File

@@ -54,6 +54,9 @@ static const uint8_t gap_erk[16] =
static Gap* gap = NULL;
static void gap_advertise_start(GapState new_state);
static int32_t gap_app(void* context);
/** function for updating rssi informations in global Gap object
*
*/
@@ -67,9 +70,6 @@ static inline void fetch_rssi() {
FURI_LOG_D(TAG, "Failed to read RSSI");
}
static void gap_advertise_start(GapState new_state);
static int32_t gap_app(void* context);
static void gap_verify_connection_parameters(Gap* gap) {
furi_assert(gap);
@@ -143,7 +143,7 @@ SVCCTL_UserEvtFlowStatus_t SVCCTL_App_Notification(void* pckt) {
FURI_LOG_I(TAG, "Connection parameters event complete");
gap_verify_connection_parameters(gap);
// save rssi for current connection
// Save rssi for current connection
fetch_rssi();
break;
}
@@ -180,8 +180,8 @@ SVCCTL_UserEvtFlowStatus_t SVCCTL_App_Notification(void* pckt) {
gap_verify_connection_parameters(gap);
// Save rssi for current connection
fetch_rssi();
// Start pairing by sending security request
aci_gap_slave_security_req(event->Connection_Handle);
} break;
@@ -266,6 +266,7 @@ SVCCTL_UserEvtFlowStatus_t SVCCTL_App_Notification(void* pckt) {
pairing_complete->Status);
aci_gap_terminate(gap->service.connection_handle, 5);
} else {
// Save RSSI
fetch_rssi();
FURI_LOG_I(TAG, "Pairing complete");
@@ -371,9 +372,11 @@ static void gap_init_svc(Gap* gap) {
hci_le_set_default_phy(ALL_PHYS_PREFERENCE, TX_2M_PREFERRED, RX_2M_PREFERRED);
// Set I/O capability
bool keypress_supported = false;
// New things below
uint8_t conf_mitm = CFG_MITM_PROTECTION;
uint8_t conf_used_fixed_pin = CFG_USED_FIXED_PIN;
bool conf_bonding = gap->config->bonding_mode;
if(gap->config->pairing_method == GapPairingPinCodeShow) {
aci_gap_set_io_capability(IO_CAP_DISPLAY_ONLY);
} else if(gap->config->pairing_method == GapPairingPinCodeVerifyYesNo) {
@@ -558,6 +561,7 @@ bool gap_init(GapConfig* config, GapEventCallback on_event_cb, void* context) {
return true;
}
// Get RSSI
uint32_t gap_get_remote_conn_rssi(int8_t* rssi) {
if(gap && gap->state == GapStateConnected) {
fetch_rssi();

View File

@@ -229,7 +229,7 @@ void hid_svc_start() {
}
}
#endif
// add led state output report
// Add led state output report
char_uuid.Char_UUID_16 = REPORT_CHAR_UUID;
status = aci_gatt_add_char(
hid_svc->svc_handle,
@@ -246,7 +246,7 @@ void hid_svc_start() {
FURI_LOG_E(TAG, "Failed to add led state characteristic: %d", status);
}
// add led state char descriptor specifying it is an output report
// Add led state char descriptor specifying it is an output report
uint8_t buf[2] = {HID_SVC_REPORT_COUNT + 1, 2};
desc_uuid.Char_UUID_16 = REPORT_REFERENCE_DESCRIPTOR_UUID;
status = aci_gatt_add_char_desc(
@@ -266,7 +266,6 @@ void hid_svc_start() {
if(status) {
FURI_LOG_E(TAG, "Failed to add led state descriptor: %d", status);
}
// Add Report Map characteristic
char_uuid.Char_UUID_16 = REPORT_MAP_CHAR_UUID;
status = aci_gatt_add_char(

View File

@@ -29,4 +29,4 @@ bool hid_svc_update_input_report(uint8_t input_report_num, uint8_t* data, uint16
bool hid_svc_update_info(uint8_t* data, uint16_t len);
void hid_svc_register_led_state_callback(HidLedStateEventCallback callback, void* context);
void hid_svc_register_led_state_callback(HidLedStateEventCallback callback, void* context);

View File

@@ -164,7 +164,7 @@ FuriHalBtHidLedState hid_host_led_state = {.s_value = 0};
uint16_t furi_hal_bt_hid_led_state_cb(uint8_t state, void* ctx) {
FuriHalBtHidLedState* led_state = (FuriHalBtHidLedState*)ctx;
FURI_LOG_D("HalBtHid", "LED state updated !");
//FURI_LOG_D("HalBtHid", "LED state updated !");
led_state->s_value = state;
@@ -172,7 +172,7 @@ uint16_t furi_hal_bt_hid_led_state_cb(uint8_t state, void* ctx) {
}
uint8_t furi_hal_bt_hid_get_led_state(void) {
FURI_LOG_D(
/*FURI_LOG_D(
"HalBtHid",
"LED state: RFU=%d NUMLOCK=%d CAPSLOCK=%d SCROLLLOCK=%d COMPOSE=%d KANA=%d POWER=%d SHIFT=%d",
hid_host_led_state.s_undefined,
@@ -183,6 +183,7 @@ uint8_t furi_hal_bt_hid_get_led_state(void) {
hid_host_led_state.s_kana,
hid_host_led_state.s_power,
hid_host_led_state.s_shift);
*/
return (hid_host_led_state.s_value >> 1); // bit 0 is undefined (after shift bit location
// match with HID led state bits defines)
@@ -203,7 +204,6 @@ void furi_hal_bt_hid_start() {
hid_svc_start();
}
// Configure HID Keyboard
hid_svc_register_led_state_callback(furi_hal_bt_hid_led_state_cb, &hid_host_led_state);
kb_report = malloc(sizeof(FuriHalBtHidKbReport));

View File

@@ -218,25 +218,6 @@ float furi_hal_bt_get_rssi();
*/
uint32_t furi_hal_bt_get_transmitted_packets();
/** Check & switch C2 to given mode
*
* @param[in] mode mode to switch into
*/
bool furi_hal_bt_ensure_c2_mode(BleGlueC2Mode mode);
typedef struct {
uint32_t magic;
uint32_t source_pc;
uint32_t source_lr;
uint32_t source_sp;
} FuriHalBtHardfaultInfo;
/** Get hardfault info
*
* @return hardfault info. NULL if no hardfault
*/
const FuriHalBtHardfaultInfo* furi_hal_bt_get_hardfault_info();
/** Modify profile advertisement name and restart bluetooth
* @param[in] profile profile type
* @param[in] name new adv name
@@ -265,6 +246,25 @@ GapPairing furi_hal_bt_get_profile_pairing_method(FuriHalBtProfile profile);
bool furi_hal_bt_is_connected(void);
/** Check & switch C2 to given mode
*
* @param[in] mode mode to switch into
*/
bool furi_hal_bt_ensure_c2_mode(BleGlueC2Mode mode);
typedef struct {
uint32_t magic;
uint32_t source_pc;
uint32_t source_lr;
uint32_t source_sp;
} FuriHalBtHardfaultInfo;
/** Get hardfault info
*
* @return hardfault info. NULL if no hardfault
*/
const FuriHalBtHardfaultInfo* furi_hal_bt_get_hardfault_info();
#ifdef __cplusplus
}
#endif

View File

@@ -158,9 +158,6 @@ FuriHalVersionDisplay furi_hal_version_get_hw_display();
*/
uint32_t furi_hal_version_get_hw_timestamp();
// Set custom name
void furi_hal_version_set_name(const char* name);
/** Get pointer to target name
*
* @return Hardware Name C-string
@@ -179,6 +176,10 @@ const char* furi_hal_version_get_device_name_ptr();
*/
const char* furi_hal_version_get_ble_local_device_name_ptr();
/** Set flipper name
*/
void furi_hal_version_set_name(const char* name);
/** Get BLE MAC address
*
* @return pointer to BLE MAC address

View File

@@ -54,8 +54,7 @@ struct ReaderAnalyzer {
NfcDebugPcap* pcap;
};
static FuriHalNfcDevData reader_analyzer_nfc_data[] = {
//XXX
const FuriHalNfcDevData reader_analyzer_nfc_data[] = {
[ReaderAnalyzerNfcDataMfClassic] =
{.interface = FuriHalNfcInterfaceRf,
.type = FuriHalNfcTypeA,

View File

@@ -1,14 +1,16 @@
#include "custom_btn.h"
static uint8_t custom_btn_id = 0;
static uint8_t custom_btn_id = SUBGHZ_CUSTOM_BTN_OK;
static uint8_t custom_btn_original = 0;
static uint8_t custom_btn_max_btns = 0;
void subghz_custom_btn_set(uint8_t b) {
if(b > custom_btn_max_btns) {
custom_btn_id = 0;
bool subghz_custom_btn_set(uint8_t btn_id) {
if(btn_id > custom_btn_max_btns) {
custom_btn_id = SUBGHZ_CUSTOM_BTN_OK;
return false;
} else {
custom_btn_id = b;
custom_btn_id = btn_id;
return true;
}
}
@@ -16,8 +18,8 @@ uint8_t subghz_custom_btn_get() {
return custom_btn_id;
}
void subghz_custom_btn_set_original(uint8_t b) {
custom_btn_original = b;
void subghz_custom_btn_set_original(uint8_t btn_code) {
custom_btn_original = btn_code;
}
uint8_t subghz_custom_btn_get_original() {
@@ -31,4 +33,8 @@ void subghz_custom_btn_set_max(uint8_t b) {
void subghz_custom_btns_reset() {
custom_btn_original = 0;
custom_btn_max_btns = 0;
}
bool subghz_custom_btn_is_allowed() {
return custom_btn_max_btns != 0;
}

View File

@@ -8,11 +8,18 @@
extern "C" {
#endif
void subghz_custom_btn_set(uint8_t b);
// Default btn ID
#define SUBGHZ_CUSTOM_BTN_OK (0U)
#define SUBGHZ_CUSTOM_BTN_UP (1U)
#define SUBGHZ_CUSTOM_BTN_DOWN (2U)
#define SUBGHZ_CUSTOM_BTN_LEFT (3U)
#define SUBGHZ_CUSTOM_BTN_RIGHT (4U)
bool subghz_custom_btn_set(uint8_t btn_id);
uint8_t subghz_custom_btn_get();
void subghz_custom_btn_set_original(uint8_t b);
void subghz_custom_btn_set_original(uint8_t btn_code);
uint8_t subghz_custom_btn_get_original();
@@ -20,6 +27,8 @@ void subghz_custom_btn_set_max(uint8_t b);
void subghz_custom_btns_reset();
bool subghz_custom_btn_is_allowed();
#ifdef __cplusplus
}
#endif

View File

@@ -308,8 +308,8 @@ bool subghz_protocol_alutech_at_4n_create_data(
instance->generic.data_count_bit = 72;
bool res = subghz_protocol_alutech_at_4n_gen_data(instance, btn);
if(res) {
res = subghz_block_generic_serialize(&instance->generic, flipper_format, preset);
if((res == SubGhzProtocolStatusOk) &&
if((subghz_block_generic_serialize(&instance->generic, flipper_format, preset) !=
SubGhzProtocolStatusOk) ||
!flipper_format_write_uint32(flipper_format, "CRC", &instance->crc, 1)) {
FURI_LOG_E(TAG, "Unable to add CRC");
res = false;
@@ -318,6 +318,13 @@ bool subghz_protocol_alutech_at_4n_create_data(
return res;
}
/**
* Defines the button value for the current btn_id
* Basic set | 0x11 | 0x22 | 0xFF | 0x44 | 0x33 |
* @return Button code
*/
static uint8_t subghz_protocol_alutech_at_4n_get_btn_code();
/**
* Generating an upload from data.
* @param instance Pointer to a SubGhzProtocolEncoderAlutech instance
@@ -333,102 +340,8 @@ static bool subghz_protocol_encoder_alutech_at_4n_get_upload(
subghz_custom_btn_set_original(btn);
}
uint8_t custom_btn_id = subghz_custom_btn_get();
uint8_t original_btn_num = subghz_custom_btn_get_original();
btn = subghz_protocol_alutech_at_4n_get_btn_code();
// Set custom button
if(custom_btn_id == 1) {
switch(original_btn_num) {
case 0x11:
btn = 0x22;
break;
case 0x22:
btn = 0x11;
break;
case 0xFF:
btn = 0x11;
break;
case 0x44:
btn = 0x11;
break;
case 0x33:
btn = 0x11;
break;
default:
break;
}
}
if(custom_btn_id == 2) {
switch(original_btn_num) {
case 0x11:
btn = 0x44;
break;
case 0x22:
btn = 0x44;
break;
case 0xFF:
btn = 0x44;
break;
case 0x44:
btn = 0xFF;
break;
case 0x33:
btn = 0x44;
break;
default:
break;
}
}
if(custom_btn_id == 3) {
switch(original_btn_num) {
case 0x11:
btn = 0x33;
break;
case 0x22:
btn = 0x33;
break;
case 0xFF:
btn = 0x33;
break;
case 0x44:
btn = 0x33;
break;
case 0x33:
btn = 0x22;
break;
default:
break;
}
}
if(custom_btn_id == 4) {
switch(original_btn_num) {
case 0x11:
btn = 0xFF;
break;
case 0x22:
btn = 0xFF;
break;
case 0xFF:
btn = 0x22;
break;
case 0x44:
btn = 0x22;
break;
case 0x33:
btn = 0xFF;
break;
default:
break;
}
}
if((custom_btn_id == 0) && (original_btn_num != 0)) {
btn = original_btn_num;
}
// Gen new key
if(!subghz_protocol_alutech_at_4n_gen_data(instance, btn)) {
return false;
@@ -788,6 +701,104 @@ SubGhzProtocolStatus subghz_protocol_decoder_alutech_at_4n_deserialize(
return ret;
}
static uint8_t subghz_protocol_alutech_at_4n_get_btn_code() {
uint8_t custom_btn_id = subghz_custom_btn_get();
uint8_t original_btn_code = subghz_custom_btn_get_original();
uint8_t btn = original_btn_code;
// Set custom button
if((custom_btn_id == SUBGHZ_CUSTOM_BTN_OK) && (original_btn_code != 0)) {
// Restore original button code
btn = original_btn_code;
} else if(custom_btn_id == SUBGHZ_CUSTOM_BTN_UP) {
switch(original_btn_code) {
case 0x11:
btn = 0x22;
break;
case 0x22:
btn = 0x11;
break;
case 0xFF:
btn = 0x11;
break;
case 0x44:
btn = 0x11;
break;
case 0x33:
btn = 0x11;
break;
default:
break;
}
} else if(custom_btn_id == SUBGHZ_CUSTOM_BTN_DOWN) {
switch(original_btn_code) {
case 0x11:
btn = 0x44;
break;
case 0x22:
btn = 0x44;
break;
case 0xFF:
btn = 0x44;
break;
case 0x44:
btn = 0xFF;
break;
case 0x33:
btn = 0x44;
break;
default:
break;
}
} else if(custom_btn_id == SUBGHZ_CUSTOM_BTN_LEFT) {
switch(original_btn_code) {
case 0x11:
btn = 0x33;
break;
case 0x22:
btn = 0x33;
break;
case 0xFF:
btn = 0x33;
break;
case 0x44:
btn = 0x33;
break;
case 0x33:
btn = 0x22;
break;
default:
break;
}
} else if(custom_btn_id == SUBGHZ_CUSTOM_BTN_RIGHT) {
switch(original_btn_code) {
case 0x11:
btn = 0xFF;
break;
case 0x22:
btn = 0xFF;
break;
case 0xFF:
btn = 0x22;
break;
case 0x44:
btn = 0x22;
break;
case 0x33:
btn = 0xFF;
break;
default:
break;
}
}
return btn;
}
void subghz_protocol_decoder_alutech_at_4n_get_string(void* context, FuriString* output) {
furi_assert(context);
SubGhzProtocolDecoderAlutech_at_4n* instance = context;

View File

@@ -14,6 +14,10 @@
#define TAG "SubGhzProtocolKeeloq"
#define KEELOQ_PROG_MODE_OFF (0U)
#define KEELOQ_PROG_MODE_BFT (1U)
#define KEELOQ_PROG_MODE_APRIMATIC (2U)
static const SubGhzBlockConst subghz_protocol_keeloq_const = {
.te_short = 400,
.te_long = 800,
@@ -92,10 +96,9 @@ static uint8_t klq_prog_mode;
static uint16_t temp_counter;
void keeloq_reset_original_btn() {
subghz_custom_btn_set_original(0);
subghz_custom_btn_set_max(0);
subghz_custom_btns_reset();
temp_counter = 0;
klq_prog_mode = 0;
klq_prog_mode = KEELOQ_PROG_MODE_OFF;
}
void keeloq_reset_mfname() {
@@ -146,6 +149,7 @@ void subghz_protocol_encoder_keeloq_free(void* context) {
* Key generation from simple data
* @param instance Pointer to a SubGhzProtocolEncoderKeeloq* instance
* @param btn Button number, 4 bit
* @param counter_up increasing the counter if the value is true
*/
static bool subghz_protocol_keeloq_gen_data(
SubGhzProtocolEncoderKeeloq* instance,
@@ -160,29 +164,30 @@ static bool subghz_protocol_keeloq_gen_data(
instance->manufacture_name = "";
}
// BFT programming mode on / off conditions
if((strcmp(instance->manufacture_name, "BFT") == 0) && (btn == 0xF)) {
klq_prog_mode = 1;
}
if((strcmp(instance->manufacture_name, "BFT") == 0) && (btn != 0xF) && (klq_prog_mode == 1)) {
klq_prog_mode = 0;
}
// Aprimatic programming mode on / off conditions
if((strcmp(instance->manufacture_name, "Aprimatic") == 0) && (btn == 0xF)) {
klq_prog_mode = 2;
}
if((strcmp(instance->manufacture_name, "Aprimatic") == 0) && (btn != 0xF) &&
(klq_prog_mode == 2)) {
klq_prog_mode = 0;
// programming mode on / off conditions
if(strcmp(instance->manufacture_name, "BFT") == 0) {
// BFT programming mode on / off conditions
if(btn == 0xF) {
klq_prog_mode = KEELOQ_PROG_MODE_BFT;
} else if(klq_prog_mode == KEELOQ_PROG_MODE_BFT) {
klq_prog_mode = KEELOQ_PROG_MODE_OFF;
}
} else if(strcmp(instance->manufacture_name, "Aprimatic") == 0) {
// Aprimatic programming mode on / off conditions
if(btn == 0xF) {
klq_prog_mode = KEELOQ_PROG_MODE_APRIMATIC;
} else if(klq_prog_mode == KEELOQ_PROG_MODE_APRIMATIC) {
klq_prog_mode = KEELOQ_PROG_MODE_OFF;
}
}
// If we using BFT programming mode we will trasmit its seed in hop part like original remote
if(klq_prog_mode == 1) {
if(klq_prog_mode == KEELOQ_PROG_MODE_BFT) {
hop = instance->generic.seed;
} else if(klq_prog_mode == 2) {
} else if(klq_prog_mode == KEELOQ_PROG_MODE_APRIMATIC) {
// If we using Aprimatic programming mode we will trasmit some strange looking hop value, why? cuz manufacturer did it this way :)
hop = 0x1A2B3C4D;
}
if(counter_up && klq_prog_mode == 0) {
if(counter_up && klq_prog_mode == KEELOQ_PROG_MODE_OFF) {
if(instance->generic.cnt < 0xFFFF) {
if((instance->generic.cnt + furi_hal_subghz_get_rolling_counter_mult()) >= 0xFFFF) {
instance->generic.cnt = 0;
@@ -193,50 +198,8 @@ static bool subghz_protocol_keeloq_gen_data(
instance->generic.cnt = 0;
}
}
if(klq_prog_mode == 0) {
uint32_t decrypt = (uint32_t)btn << 28 |
(instance->generic.serial & 0x3FF)
<< 16 | //ToDo in some protocols the discriminator is 0
instance->generic.cnt;
if(strcmp(instance->manufacture_name, "Aprimatic") == 0) {
// Aprimatic uses 12bit serial number + 2bit APR1 "parity" bit in front of it replacing first 2 bits of serial
// Thats in theory! We need to check if this is true for all Aprimatic remotes but we got only 3 recordings to test
// For now lets assume that this is true for all Aprimatic remotes, if not we will need to add some more code here
uint32_t apri_serial = instance->generic.serial;
uint8_t apr1 = 0;
for(uint16_t i = 1; i != 0b10000000000; i <<= 1) {
if(apri_serial & i) apr1++;
}
apri_serial &= 0b00001111111111;
if(apr1 % 2 == 0) {
apri_serial |= 0b110000000000;
}
decrypt = btn << 28 | (apri_serial & 0xFFF) << 16 | instance->generic.cnt;
}
// DTM Neo, Came_Space uses 12bit -> simple learning -- FAAC_RC,XT , Mutanco_Mutancode, Stilmatic(Schellenberg) -> 12bit normal learning
if((strcmp(instance->manufacture_name, "DTM_Neo") == 0) ||
(strcmp(instance->manufacture_name, "FAAC_RC,XT") == 0) ||
(strcmp(instance->manufacture_name, "Mutanco_Mutancode") == 0) ||
(strcmp(instance->manufacture_name, "Stilmatic") == 0) ||
(strcmp(instance->manufacture_name, "Came_Space") == 0)) {
decrypt = btn << 28 | (instance->generic.serial & 0xFFF) << 16 | instance->generic.cnt;
}
// Nice Smilo, MHouse, JCM, Normstahl -> 8bit serial - simple learning
if((strcmp(instance->manufacture_name, "NICE_Smilo") == 0) ||
(strcmp(instance->manufacture_name, "NICE_MHOUSE") == 0) ||
(strcmp(instance->manufacture_name, "JCM_Tech") == 0) ||
(strcmp(instance->manufacture_name, "Normstahl") == 0)) {
decrypt = btn << 28 | (instance->generic.serial & 0xFF) << 16 | instance->generic.cnt;
}
// Beninca / Allmatic -> no serial - simple XOR
if(strcmp(instance->manufacture_name, "Beninca") == 0) {
decrypt = btn << 28 | (0x000) << 16 | instance->generic.cnt;
}
if(klq_prog_mode == KEELOQ_PROG_MODE_OFF) {
// Protocols that do not use encryption
if(strcmp(instance->manufacture_name, "Unknown") == 0) {
code_found_reverse = subghz_protocol_blocks_reverse_key(
instance->generic.data, instance->generic.data_count_bit);
@@ -247,72 +210,120 @@ static bool subghz_protocol_keeloq_gen_data(
} else if(strcmp(instance->manufacture_name, "HCS101") == 0) {
hop = instance->generic.cnt << 16 | (btn & 0xF) << 12 | 0x000;
} else {
for
M_EACH(manufacture_code, *subghz_keystore_get_data(instance->keystore), SubGhzKeyArray_t) {
res = strcmp(furi_string_get_cstr(manufacture_code->name), instance->manufacture_name);
if(res == 0) {
switch(manufacture_code->type) {
case KEELOQ_LEARNING_SIMPLE:
//Simple Learning
hop = subghz_protocol_keeloq_common_encrypt(decrypt, manufacture_code->key);
break;
case KEELOQ_LEARNING_NORMAL:
//Simple Learning
man =
subghz_protocol_keeloq_common_normal_learning(fix, manufacture_code->key);
hop = subghz_protocol_keeloq_common_encrypt(decrypt, man);
break;
case KEELOQ_LEARNING_SECURE:
//Secure Learning
man = subghz_protocol_keeloq_common_secure_learning(
fix, instance->generic.seed, manufacture_code->key);
hop = subghz_protocol_keeloq_common_encrypt(decrypt, man);
break;
case KEELOQ_LEARNING_MAGIC_XOR_TYPE_1:
//Magic XOR type-1 Learning
man = subghz_protocol_keeloq_common_magic_xor_type1_learning(
instance->generic.serial, manufacture_code->key);
hop = subghz_protocol_keeloq_common_encrypt(decrypt, man);
break;
case KEELOQ_LEARNING_MAGIC_SERIAL_TYPE_1:
//Magic Serial Type 1 learning
man = subghz_protocol_keeloq_common_magic_serial_type1_learning(
fix, manufacture_code->key);
hop = subghz_protocol_keeloq_common_encrypt(decrypt, man);
break;
case KEELOQ_LEARNING_UNKNOWN:
if(kl_type == 1) {
hop =
subghz_protocol_keeloq_common_encrypt(decrypt, manufacture_code->key);
}
if(kl_type == 2) {
man = subghz_protocol_keeloq_common_normal_learning(
fix, manufacture_code->key);
hop = subghz_protocol_keeloq_common_encrypt(decrypt, man);
}
if(kl_type == 3) {
man = subghz_protocol_keeloq_common_secure_learning(
fix, instance->generic.seed, manufacture_code->key);
hop = subghz_protocol_keeloq_common_encrypt(decrypt, man);
}
if(kl_type == 4) {
man = subghz_protocol_keeloq_common_magic_xor_type1_learning(
instance->generic.serial, manufacture_code->key);
hop = subghz_protocol_keeloq_common_encrypt(decrypt, man);
}
break;
// Protocols that use encryption
uint32_t decrypt = (uint32_t)btn << 28 |
(instance->generic.serial & 0x3FF)
<< 16 | //ToDo in some protocols the discriminator is 0
instance->generic.cnt;
if(strcmp(instance->manufacture_name, "Aprimatic") == 0) {
// Aprimatic uses 12bit serial number + 2bit APR1 "parity" bit in front of it replacing first 2 bits of serial
// Thats in theory! We need to check if this is true for all Aprimatic remotes but we got only 3 recordings to test
// For now lets assume that this is true for all Aprimatic remotes, if not we will need to add some more code here
uint32_t apri_serial = instance->generic.serial;
uint8_t apr1 = 0;
for(uint16_t i = 1; i != 0b10000000000; i <<= 1) {
if(apri_serial & i) apr1++;
}
break;
apri_serial &= 0b00001111111111;
if(apr1 % 2 == 0) {
apri_serial |= 0b110000000000;
}
decrypt = btn << 28 | (apri_serial & 0xFFF) << 16 | instance->generic.cnt;
} else if(
(strcmp(instance->manufacture_name, "DTM_Neo") == 0) ||
(strcmp(instance->manufacture_name, "FAAC_RC,XT") == 0) ||
(strcmp(instance->manufacture_name, "Mutanco_Mutancode") == 0) ||
(strcmp(instance->manufacture_name, "Stilmatic") == 0) ||
(strcmp(instance->manufacture_name, "Came_Space") == 0)) {
// DTM Neo, Came_Space uses 12bit serial -> simple learning
// FAAC_RC,XT , Mutanco_Mutancode, Stilmatic(Schellenberg) 12bit serial -> normal learning
decrypt = btn << 28 | (instance->generic.serial & 0xFFF) << 16 |
instance->generic.cnt;
} else if(
(strcmp(instance->manufacture_name, "NICE_Smilo") == 0) ||
(strcmp(instance->manufacture_name, "NICE_MHOUSE") == 0) ||
(strcmp(instance->manufacture_name, "JCM_Tech") == 0) ||
(strcmp(instance->manufacture_name, "Normstahl") == 0)) {
// Nice Smilo, MHouse, JCM, Normstahl -> 8bit serial - simple learning
decrypt = btn << 28 | (instance->generic.serial & 0xFF) << 16 |
instance->generic.cnt;
} else if(strcmp(instance->manufacture_name, "Beninca") == 0) {
decrypt = btn << 28 | (0x000) << 16 | instance->generic.cnt;
// Beninca / Allmatic -> no serial - simple XOR
}
}
for
M_EACH(
manufacture_code,
*subghz_keystore_get_data(instance->keystore),
SubGhzKeyArray_t) {
res = strcmp(
furi_string_get_cstr(manufacture_code->name), instance->manufacture_name);
if(res == 0) {
switch(manufacture_code->type) {
case KEELOQ_LEARNING_SIMPLE:
//Simple Learning
hop = subghz_protocol_keeloq_common_encrypt(
decrypt, manufacture_code->key);
break;
case KEELOQ_LEARNING_NORMAL:
//Simple Learning
man = subghz_protocol_keeloq_common_normal_learning(
fix, manufacture_code->key);
hop = subghz_protocol_keeloq_common_encrypt(decrypt, man);
break;
case KEELOQ_LEARNING_SECURE:
//Secure Learning
man = subghz_protocol_keeloq_common_secure_learning(
fix, instance->generic.seed, manufacture_code->key);
hop = subghz_protocol_keeloq_common_encrypt(decrypt, man);
break;
case KEELOQ_LEARNING_MAGIC_XOR_TYPE_1:
//Magic XOR type-1 Learning
man = subghz_protocol_keeloq_common_magic_xor_type1_learning(
instance->generic.serial, manufacture_code->key);
hop = subghz_protocol_keeloq_common_encrypt(decrypt, man);
break;
case KEELOQ_LEARNING_MAGIC_SERIAL_TYPE_1:
//Magic Serial Type 1 learning
man = subghz_protocol_keeloq_common_magic_serial_type1_learning(
fix, manufacture_code->key);
hop = subghz_protocol_keeloq_common_encrypt(decrypt, man);
break;
case KEELOQ_LEARNING_UNKNOWN:
if(kl_type == 1) {
hop = subghz_protocol_keeloq_common_encrypt(
decrypt, manufacture_code->key);
}
if(kl_type == 2) {
man = subghz_protocol_keeloq_common_normal_learning(
fix, manufacture_code->key);
hop = subghz_protocol_keeloq_common_encrypt(decrypt, man);
}
if(kl_type == 3) {
man = subghz_protocol_keeloq_common_secure_learning(
fix, instance->generic.seed, manufacture_code->key);
hop = subghz_protocol_keeloq_common_encrypt(decrypt, man);
}
if(kl_type == 4) {
man = subghz_protocol_keeloq_common_magic_xor_type1_learning(
instance->generic.serial, manufacture_code->key);
hop = subghz_protocol_keeloq_common_encrypt(decrypt, man);
}
break;
}
break;
}
}
}
}
if(hop) {
uint64_t yek = (uint64_t)fix << 32 | hop;
instance->generic.data =
subghz_protocol_blocks_reverse_key(yek, instance->generic.data_count_bit);
}
return true;
} // What should happen if seed = 0 in bft programming mode
return true; // Always return true
}
bool subghz_protocol_keeloq_create_data(
@@ -363,6 +374,14 @@ bool subghz_protocol_keeloq_bft_create_data(
return res;
}
/**
* Defines the button value for the current btn_id
* Basic set | 0x1 | 0x2 | 0x4 | 0x8 | 0xA or Special Learning Code |
* @param last_btn_code Candidate for the last button
* @return Button code
*/
static uint8_t subghz_protocol_keeloq_get_btn_code(uint8_t last_btn_code);
/**
* Generating an upload from data.
* @param instance Pointer to a SubGhzProtocolEncoderKeeloq instance
@@ -380,9 +399,9 @@ static bool
if(instance->manufacture_name == 0x0) {
instance->manufacture_name = "";
}
if(klq_prog_mode == 1) {
if(klq_prog_mode == KEELOQ_PROG_MODE_BFT) {
instance->manufacture_name = "BFT";
} else if(klq_prog_mode == 2) {
} else if(klq_prog_mode == KEELOQ_PROG_MODE_APRIMATIC) {
instance->manufacture_name = "Aprimatic";
}
uint8_t klq_last_custom_btn = 0xA;
@@ -391,118 +410,9 @@ static bool
klq_last_custom_btn = 0xF;
}
uint8_t custom_btn_id = subghz_custom_btn_get();
uint8_t original_btn_num = subghz_custom_btn_get_original();
// Set custom button
if(custom_btn_id == 1) {
switch(original_btn_num) {
case 0x1:
btn = 0x2;
break;
case 0x2:
btn = 0x1;
break;
case 0xA:
btn = 0x1;
break;
case 0x4:
btn = 0x1;
break;
case 0x8:
btn = 0x1;
break;
case 0xF:
btn = 0x1;
break;
btn = subghz_protocol_keeloq_get_btn_code(klq_last_custom_btn);
default:
btn = 0x1;
break;
}
}
if(custom_btn_id == 2) {
switch(original_btn_num) {
case 0x1:
btn = 0x4;
break;
case 0x2:
btn = 0x4;
break;
case 0xA:
btn = 0x4;
break;
case 0x4:
btn = klq_last_custom_btn;
break;
case 0x8:
btn = 0x4;
break;
case 0xF:
btn = 0x4;
break;
default:
btn = 0x4;
break;
}
}
if(custom_btn_id == 3) {
switch(original_btn_num) {
case 0x1:
btn = 0x8;
break;
case 0x2:
btn = 0x8;
break;
case 0xA:
btn = 0x8;
break;
case 0x4:
btn = 0x8;
break;
case 0x8:
btn = 0x2;
break;
case 0xF:
btn = 0x8;
break;
default:
btn = 0x8;
break;
}
}
if(custom_btn_id == 4) {
switch(original_btn_num) {
case 0x1:
btn = klq_last_custom_btn;
break;
case 0x2:
btn = klq_last_custom_btn;
break;
case 0xA:
btn = 0x2;
break;
case 0x4:
btn = 0x2;
break;
case 0x8:
btn = klq_last_custom_btn;
break;
case 0xF:
btn = 0x2;
break;
default:
btn = 0x2;
break;
}
}
if((custom_btn_id == 0) && (original_btn_num != 0)) {
btn = original_btn_num;
}
// Generate new key
if(subghz_protocol_keeloq_gen_data(instance, btn, true)) {
// OK
} else {
@@ -669,7 +579,7 @@ void* subghz_protocol_decoder_keeloq_alloc(SubGhzEnvironment* environment) {
instance->keystore = subghz_environment_get_keystore(environment);
instance->manufacture_from_file = furi_string_alloc();
klq_prog_mode = 0;
klq_prog_mode = KEELOQ_PROG_MODE_OFF;
return instance;
}
@@ -829,185 +739,19 @@ static uint8_t subghz_protocol_keeloq_check_remote_controller_selector(
uint8_t btn = (uint8_t)(fix >> 28);
uint32_t decrypt = 0;
uint64_t man;
int res = 0;
bool mf_not_set = false;
if(mfname == 0x0) {
mfname = "";
}
if(strcmp(mfname, "") == 0) {
for
M_EACH(manufacture_code, *subghz_keystore_get_data(keystore), SubGhzKeyArray_t) {
switch(manufacture_code->type) {
case KEELOQ_LEARNING_SIMPLE:
// Simple Learning
decrypt = subghz_protocol_keeloq_common_decrypt(hop, manufacture_code->key);
if(subghz_protocol_keeloq_check_decrypt(instance, decrypt, btn, end_serial)) {
*manufacture_name = furi_string_get_cstr(manufacture_code->name);
mfname = *manufacture_name;
return 1;
}
break;
case KEELOQ_LEARNING_NORMAL:
// Normal Learning
// https://phreakerclub.com/forum/showpost.php?p=43557&postcount=37
man = subghz_protocol_keeloq_common_normal_learning(fix, manufacture_code->key);
decrypt = subghz_protocol_keeloq_common_decrypt(hop, man);
if(subghz_protocol_keeloq_check_decrypt(instance, decrypt, btn, end_serial)) {
*manufacture_name = furi_string_get_cstr(manufacture_code->name);
mfname = *manufacture_name;
return 1;
}
break;
case KEELOQ_LEARNING_SECURE:
man = subghz_protocol_keeloq_common_secure_learning(
fix, instance->seed, manufacture_code->key);
decrypt = subghz_protocol_keeloq_common_decrypt(hop, man);
if(subghz_protocol_keeloq_check_decrypt(instance, decrypt, btn, end_serial)) {
*manufacture_name = furi_string_get_cstr(manufacture_code->name);
mfname = *manufacture_name;
return 1;
}
break;
case KEELOQ_LEARNING_MAGIC_XOR_TYPE_1:
man = subghz_protocol_keeloq_common_magic_xor_type1_learning(
fix, manufacture_code->key);
decrypt = subghz_protocol_keeloq_common_decrypt(hop, man);
if(subghz_protocol_keeloq_check_decrypt(instance, decrypt, btn, end_serial)) {
*manufacture_name = furi_string_get_cstr(manufacture_code->name);
mfname = *manufacture_name;
return 1;
}
break;
case KEELOQ_LEARNING_MAGIC_SERIAL_TYPE_1:
man = subghz_protocol_keeloq_common_magic_serial_type1_learning(
fix, manufacture_code->key);
decrypt = subghz_protocol_keeloq_common_decrypt(hop, man);
if(subghz_protocol_keeloq_check_decrypt(instance, decrypt, btn, end_serial)) {
*manufacture_name = furi_string_get_cstr(manufacture_code->name);
mfname = *manufacture_name;
return 1;
}
break;
case KEELOQ_LEARNING_MAGIC_SERIAL_TYPE_2:
man = subghz_protocol_keeloq_common_magic_serial_type2_learning(
fix, manufacture_code->key);
decrypt = subghz_protocol_keeloq_common_decrypt(hop, man);
if(subghz_protocol_keeloq_check_decrypt(instance, decrypt, btn, end_serial)) {
*manufacture_name = furi_string_get_cstr(manufacture_code->name);
mfname = *manufacture_name;
return 1;
}
break;
case KEELOQ_LEARNING_MAGIC_SERIAL_TYPE_3:
man = subghz_protocol_keeloq_common_magic_serial_type3_learning(
fix, manufacture_code->key);
decrypt = subghz_protocol_keeloq_common_decrypt(hop, man);
if(subghz_protocol_keeloq_check_decrypt(instance, decrypt, btn, end_serial)) {
*manufacture_name = furi_string_get_cstr(manufacture_code->name);
mfname = *manufacture_name;
return 1;
}
break;
case KEELOQ_LEARNING_UNKNOWN:
// Simple Learning
decrypt = subghz_protocol_keeloq_common_decrypt(hop, manufacture_code->key);
if(subghz_protocol_keeloq_check_decrypt(instance, decrypt, btn, end_serial)) {
*manufacture_name = furi_string_get_cstr(manufacture_code->name);
mfname = *manufacture_name;
kl_type = 1;
return 1;
}
// Check for mirrored man
uint64_t man_rev = 0;
uint64_t man_rev_byte = 0;
for(uint8_t i = 0; i < 64; i += 8) {
man_rev_byte = (uint8_t)(manufacture_code->key >> i);
man_rev = man_rev | man_rev_byte << (56 - i);
}
decrypt = subghz_protocol_keeloq_common_decrypt(hop, man_rev);
if(subghz_protocol_keeloq_check_decrypt(instance, decrypt, btn, end_serial)) {
*manufacture_name = furi_string_get_cstr(manufacture_code->name);
mfname = *manufacture_name;
kl_type = 1;
return 1;
}
//###########################
// Normal Learning
// https://phreakerclub.com/forum/showpost.php?p=43557&postcount=37
man = subghz_protocol_keeloq_common_normal_learning(fix, manufacture_code->key);
decrypt = subghz_protocol_keeloq_common_decrypt(hop, man);
if(subghz_protocol_keeloq_check_decrypt(instance, decrypt, btn, end_serial)) {
*manufacture_name = furi_string_get_cstr(manufacture_code->name);
mfname = *manufacture_name;
kl_type = 2;
return 1;
}
// Check for mirrored man
man = subghz_protocol_keeloq_common_normal_learning(fix, man_rev);
decrypt = subghz_protocol_keeloq_common_decrypt(hop, man);
if(subghz_protocol_keeloq_check_decrypt(instance, decrypt, btn, end_serial)) {
*manufacture_name = furi_string_get_cstr(manufacture_code->name);
mfname = *manufacture_name;
kl_type = 2;
return 1;
}
// Secure Learning
man = subghz_protocol_keeloq_common_secure_learning(
fix, instance->seed, manufacture_code->key);
decrypt = subghz_protocol_keeloq_common_decrypt(hop, man);
if(subghz_protocol_keeloq_check_decrypt(instance, decrypt, btn, end_serial)) {
*manufacture_name = furi_string_get_cstr(manufacture_code->name);
mfname = *manufacture_name;
kl_type = 3;
return 1;
}
// Check for mirrored man
man = subghz_protocol_keeloq_common_secure_learning(fix, instance->seed, man_rev);
decrypt = subghz_protocol_keeloq_common_decrypt(hop, man);
if(subghz_protocol_keeloq_check_decrypt(instance, decrypt, btn, end_serial)) {
*manufacture_name = furi_string_get_cstr(manufacture_code->name);
mfname = *manufacture_name;
kl_type = 3;
return 1;
}
// Magic xor type1 learning
man = subghz_protocol_keeloq_common_magic_xor_type1_learning(
fix, manufacture_code->key);
decrypt = subghz_protocol_keeloq_common_decrypt(hop, man);
if(subghz_protocol_keeloq_check_decrypt(instance, decrypt, btn, end_serial)) {
*manufacture_name = furi_string_get_cstr(manufacture_code->name);
mfname = *manufacture_name;
kl_type = 4;
return 1;
}
// Check for mirrored man
man = subghz_protocol_keeloq_common_magic_xor_type1_learning(fix, man_rev);
decrypt = subghz_protocol_keeloq_common_decrypt(hop, man);
if(subghz_protocol_keeloq_check_decrypt(instance, decrypt, btn, end_serial)) {
*manufacture_name = furi_string_get_cstr(manufacture_code->name);
mfname = *manufacture_name;
kl_type = 4;
return 1;
}
break;
}
}
} else if(strcmp(mfname, "Unknown") == 0) {
if(strcmp(mfname, "Unknown") == 0) {
return 1;
} else {
} else if(strcmp(mfname, "") == 0) {
mf_not_set = true;
}
for
M_EACH(manufacture_code, *subghz_keystore_get_data(keystore), SubGhzKeyArray_t) {
res = strcmp(furi_string_get_cstr(manufacture_code->name), mfname);
if(res == 0) {
if(mf_not_set || (strcmp(furi_string_get_cstr(manufacture_code->name), mfname) == 0)) {
switch(manufacture_code->type) {
case KEELOQ_LEARNING_SIMPLE:
// Simple Learning
@@ -1060,6 +804,26 @@ static uint8_t subghz_protocol_keeloq_check_remote_controller_selector(
return 1;
}
break;
case KEELOQ_LEARNING_MAGIC_SERIAL_TYPE_2:
man = subghz_protocol_keeloq_common_magic_serial_type2_learning(
fix, manufacture_code->key);
decrypt = subghz_protocol_keeloq_common_decrypt(hop, man);
if(subghz_protocol_keeloq_check_decrypt(instance, decrypt, btn, end_serial)) {
*manufacture_name = furi_string_get_cstr(manufacture_code->name);
mfname = *manufacture_name;
return 1;
}
break;
case KEELOQ_LEARNING_MAGIC_SERIAL_TYPE_3:
man = subghz_protocol_keeloq_common_magic_serial_type3_learning(
fix, manufacture_code->key);
decrypt = subghz_protocol_keeloq_common_decrypt(hop, man);
if(subghz_protocol_keeloq_check_decrypt(instance, decrypt, btn, end_serial)) {
*manufacture_name = furi_string_get_cstr(manufacture_code->name);
mfname = *manufacture_name;
return 1;
}
break;
case KEELOQ_LEARNING_UNKNOWN:
// Simple Learning
decrypt = subghz_protocol_keeloq_common_decrypt(hop, manufacture_code->key);
@@ -1069,6 +833,7 @@ static uint8_t subghz_protocol_keeloq_check_remote_controller_selector(
kl_type = 1;
return 1;
}
// Check for mirrored man
uint64_t man_rev = 0;
uint64_t man_rev_byte = 0;
@@ -1076,6 +841,7 @@ static uint8_t subghz_protocol_keeloq_check_remote_controller_selector(
man_rev_byte = (uint8_t)(manufacture_code->key >> i);
man_rev = man_rev | man_rev_byte << (56 - i);
}
decrypt = subghz_protocol_keeloq_common_decrypt(hop, man_rev);
if(subghz_protocol_keeloq_check_decrypt(instance, decrypt, btn, end_serial)) {
*manufacture_name = furi_string_get_cstr(manufacture_code->name);
@@ -1083,6 +849,7 @@ static uint8_t subghz_protocol_keeloq_check_remote_controller_selector(
kl_type = 1;
return 1;
}
//###########################
// Normal Learning
// https://phreakerclub.com/forum/showpost.php?p=43557&postcount=37
@@ -1153,7 +920,6 @@ static uint8_t subghz_protocol_keeloq_check_remote_controller_selector(
}
}
}
}
*manufacture_name = "Unknown";
mfname = "Unknown";
@@ -1170,8 +936,8 @@ static void subghz_protocol_keeloq_check_remote_controller(
uint32_t key_fix = key >> 32;
uint32_t key_hop = key & 0x00000000ffffffff;
// If we are in BFT programming mode we will set previous remembered counter and skip mf keys check
if(klq_prog_mode == 0) {
// If we are in BFT / Aprimatic programming mode we will set previous remembered counter and skip mf keys check
if(klq_prog_mode == KEELOQ_PROG_MODE_OFF) {
// Check key AN-Motors
if((key_hop >> 24) == ((key_hop >> 16) & 0x00ff) &&
(key_fix >> 28) == ((key_hop >> 12) & 0x0f) && (key_hop & 0xFFF) == 0x404) {
@@ -1188,11 +954,11 @@ static void subghz_protocol_keeloq_check_remote_controller(
}
temp_counter = instance->cnt;
} else if(klq_prog_mode == 1) {
} else if(klq_prog_mode == KEELOQ_PROG_MODE_BFT) {
*manufacture_name = "BFT";
mfname = *manufacture_name;
instance->cnt = temp_counter;
} else if(klq_prog_mode == 2) {
} else if(klq_prog_mode == KEELOQ_PROG_MODE_APRIMATIC) {
*manufacture_name = "Aprimatic";
mfname = *manufacture_name;
instance->cnt = temp_counter;
@@ -1302,6 +1068,125 @@ SubGhzProtocolStatus
return res;
}
static uint8_t subghz_protocol_keeloq_get_btn_code(uint8_t last_btn_code) {
uint8_t custom_btn_id = subghz_custom_btn_get();
uint8_t original_btn_code = subghz_custom_btn_get_original();
uint8_t btn = original_btn_code;
if(last_btn_code == 0) {
last_btn_code = 0xA;
}
// Set custom button
// Basic set | 0x1 | 0x2 | 0x4 | 0x8 | 0xA or Special Learning Code |
if((custom_btn_id == SUBGHZ_CUSTOM_BTN_OK) && (original_btn_code != 0)) {
// Restore original button code
btn = original_btn_code;
} else if(custom_btn_id == SUBGHZ_CUSTOM_BTN_UP) {
switch(original_btn_code) {
case 0x1:
btn = 0x2;
break;
case 0x2:
btn = 0x1;
break;
case 0xA:
btn = 0x1;
break;
case 0x4:
btn = 0x1;
break;
case 0x8:
btn = 0x1;
break;
case 0xF:
btn = 0x1;
break;
default:
btn = 0x1;
break;
}
} else if(custom_btn_id == SUBGHZ_CUSTOM_BTN_DOWN) {
switch(original_btn_code) {
case 0x1:
btn = 0x4;
break;
case 0x2:
btn = 0x4;
break;
case 0xA:
btn = 0x4;
break;
case 0x4:
btn = last_btn_code;
break;
case 0x8:
btn = 0x4;
break;
case 0xF:
btn = 0x4;
break;
default:
btn = 0x4;
break;
}
} else if(custom_btn_id == SUBGHZ_CUSTOM_BTN_LEFT) {
switch(original_btn_code) {
case 0x1:
btn = 0x8;
break;
case 0x2:
btn = 0x8;
break;
case 0xA:
btn = 0x8;
break;
case 0x4:
btn = 0x8;
break;
case 0x8:
btn = 0x2;
break;
case 0xF:
btn = 0x8;
break;
default:
btn = 0x8;
break;
}
} else if(custom_btn_id == SUBGHZ_CUSTOM_BTN_RIGHT) {
switch(original_btn_code) {
case 0x1:
btn = last_btn_code;
break;
case 0x2:
btn = last_btn_code;
break;
case 0xA:
btn = 0x2;
break;
case 0x4:
btn = 0x2;
break;
case 0x8:
btn = last_btn_code;
break;
case 0xF:
btn = 0x2;
break;
default:
btn = 0x2;
break;
}
}
return btn;
}
void subghz_protocol_decoder_keeloq_get_string(void* context, FuriString* output) {
furi_assert(context);
SubGhzProtocolDecoderKeeloq* instance = context;

View File

@@ -117,6 +117,13 @@ void subghz_protocol_encoder_nice_flor_s_free(void* context) {
static void subghz_protocol_nice_one_get_data(uint8_t* p, uint8_t num_parcel, uint8_t hold_bit);
/**
* Defines the button value for the current btn_id
* Basic set | 0x1 | 0x2 | 0x4 | 0x8 |
* @return Button code
*/
static uint8_t subghz_protocol_nice_flor_s_get_btn_code();
/**
* Generating an upload from data.
* @param instance Pointer to a SubGhzProtocolEncoderNiceFlorS instance
@@ -135,71 +142,7 @@ static void subghz_protocol_encoder_nice_flor_s_get_upload(
subghz_custom_btn_set_original(btn);
}
uint8_t custom_btn_id = subghz_custom_btn_get();
uint8_t original_btn_num = subghz_custom_btn_get_original();
// Set custom button
if(custom_btn_id == 1) {
switch(original_btn_num) {
case 0x1:
btn = 0x2;
break;
case 0x2:
btn = 0x1;
break;
case 0x4:
btn = 0x1;
break;
case 0x8:
btn = 0x1;
break;
default:
break;
}
}
if(custom_btn_id == 2) {
switch(original_btn_num) {
case 0x1:
btn = 0x4;
break;
case 0x2:
btn = 0x4;
break;
case 0x4:
btn = 0x2;
break;
case 0x8:
btn = 0x4;
break;
default:
break;
}
}
if(custom_btn_id == 3) {
switch(original_btn_num) {
case 0x1:
btn = 0x8;
break;
case 0x2:
btn = 0x8;
break;
case 0x4:
btn = 0x8;
break;
case 0x8:
btn = 0x2;
break;
default:
break;
}
}
if((custom_btn_id == 0) && (original_btn_num != 0)) {
btn = original_btn_num;
}
btn = subghz_protocol_nice_flor_s_get_btn_code();
size_t size_upload = ((instance->generic.data_count_bit * 2) + ((37 + 2 + 2) * 2) * 16);
if(size_upload > instance->encoder.size_upload) {
@@ -808,6 +751,74 @@ SubGhzProtocolStatus
return ret;
}
static uint8_t subghz_protocol_nice_flor_s_get_btn_code() {
uint8_t custom_btn_id = subghz_custom_btn_get();
uint8_t original_btn_code = subghz_custom_btn_get_original();
uint8_t btn = original_btn_code;
// Set custom button
if((custom_btn_id == SUBGHZ_CUSTOM_BTN_OK) && (original_btn_code != 0)) {
// Restore original button code
btn = original_btn_code;
} else if(custom_btn_id == SUBGHZ_CUSTOM_BTN_UP) {
switch(original_btn_code) {
case 0x1:
btn = 0x2;
break;
case 0x2:
btn = 0x1;
break;
case 0x4:
btn = 0x1;
break;
case 0x8:
btn = 0x1;
break;
default:
break;
}
} else if(custom_btn_id == SUBGHZ_CUSTOM_BTN_DOWN) {
switch(original_btn_code) {
case 0x1:
btn = 0x4;
break;
case 0x2:
btn = 0x4;
break;
case 0x4:
btn = 0x2;
break;
case 0x8:
btn = 0x4;
break;
default:
break;
}
} else if(custom_btn_id == SUBGHZ_CUSTOM_BTN_LEFT) {
switch(original_btn_code) {
case 0x1:
btn = 0x8;
break;
case 0x2:
btn = 0x8;
break;
case 0x4:
btn = 0x8;
break;
case 0x8:
btn = 0x2;
break;
default:
break;
}
}
return btn;
}
void subghz_protocol_decoder_nice_flor_s_get_string(void* context, FuriString* output) {
furi_assert(context);
SubGhzProtocolDecoderNiceFlorS* instance = context;

View File

@@ -375,6 +375,13 @@ static uint64_t subghz_protocol_secplus_v2_encode_half(uint8_t roll_array[], uin
return data;
}
/**
* Defines the button value for the current btn_id
* Basic set | 0x68 | 0x80 | 0x81 | 0xE2 |
* @return Button code
*/
static uint8_t subghz_protocol_secplus_v2_get_btn_code();
/**
* Security+ 2.0 message encoding
* @param instance SubGhzProtocolEncoderSecPlus_v2*
@@ -386,70 +393,8 @@ static void subghz_protocol_secplus_v2_encode(SubGhzProtocolEncoderSecPlus_v2* i
subghz_custom_btn_set_original(instance->generic.btn);
}
uint8_t custom_btn_id = subghz_custom_btn_get();
uint8_t original_btn_num = subghz_custom_btn_get_original();
instance->generic.btn = subghz_protocol_secplus_v2_get_btn_code();
// Set custom button
if(custom_btn_id == 1) {
switch(original_btn_num) {
case 0x68:
instance->generic.btn = 0x80;
break;
case 0x80:
instance->generic.btn = 0x68;
break;
case 0x81:
instance->generic.btn = 0x80;
break;
case 0xE2:
instance->generic.btn = 0x80;
break;
default:
break;
}
}
if(custom_btn_id == 2) {
switch(original_btn_num) {
case 0x68:
instance->generic.btn = 0x81;
break;
case 0x80:
instance->generic.btn = 0x81;
break;
case 0x81:
instance->generic.btn = 0x68;
break;
case 0xE2:
instance->generic.btn = 0x81;
break;
default:
break;
}
}
if(custom_btn_id == 3) {
switch(original_btn_num) {
case 0x68:
instance->generic.btn = 0xE2;
break;
case 0x80:
instance->generic.btn = 0xE2;
break;
case 0x81:
instance->generic.btn = 0xE2;
break;
case 0xE2:
instance->generic.btn = 0x68;
break;
default:
break;
}
}
if((custom_btn_id == 0) && (original_btn_num != 0)) {
instance->generic.btn = original_btn_num;
}
uint32_t fixed_1[1] = {instance->generic.btn << 12 | instance->generic.serial >> 20};
uint32_t fixed_2[1] = {instance->generic.serial & 0xFFFFF};
uint8_t rolling_digits[18] = {0};
@@ -888,6 +833,74 @@ SubGhzProtocolStatus
return ret;
}
static uint8_t subghz_protocol_secplus_v2_get_btn_code() {
uint8_t custom_btn_id = subghz_custom_btn_get();
uint8_t original_btn_code = subghz_custom_btn_get_original();
uint8_t btn = original_btn_code;
// Set custom button
if((custom_btn_id == SUBGHZ_CUSTOM_BTN_OK) && (original_btn_code != 0)) {
// Restore original button code
btn = original_btn_code;
} else if(custom_btn_id == SUBGHZ_CUSTOM_BTN_UP) {
switch(original_btn_code) {
case 0x68:
btn = 0x80;
break;
case 0x80:
btn = 0x68;
break;
case 0x81:
btn = 0x80;
break;
case 0xE2:
btn = 0x80;
break;
default:
break;
}
} else if(custom_btn_id == SUBGHZ_CUSTOM_BTN_DOWN) {
switch(original_btn_code) {
case 0x68:
btn = 0x81;
break;
case 0x80:
btn = 0x81;
break;
case 0x81:
btn = 0x68;
break;
case 0xE2:
btn = 0x81;
break;
default:
break;
}
} else if(custom_btn_id == SUBGHZ_CUSTOM_BTN_LEFT) {
switch(original_btn_code) {
case 0x68:
btn = 0xE2;
break;
case 0x80:
btn = 0xE2;
break;
case 0x81:
btn = 0xE2;
break;
case 0xE2:
btn = 0x68;
break;
default:
break;
}
}
return btn;
}
void subghz_protocol_decoder_secplus_v2_get_string(void* context, FuriString* output) {
furi_assert(context);
SubGhzProtocolDecoderSecPlus_v2* instance = context;

View File

@@ -97,6 +97,13 @@ void subghz_protocol_encoder_somfy_telis_free(void* context) {
free(instance);
}
/**
* Defines the button value for the current btn_id
* Basic set | 0x1 | 0x2 | 0x4 | 0x8 |
* @return Button code
*/
static uint8_t subghz_protocol_somfy_telis_get_btn_code();
static bool subghz_protocol_somfy_telis_gen_data(
SubGhzProtocolEncoderSomfyTelis* instance,
uint8_t btn,
@@ -115,71 +122,7 @@ static bool subghz_protocol_somfy_telis_gen_data(
subghz_custom_btn_set_original(btn);
}
uint8_t custom_btn_id = subghz_custom_btn_get();
uint8_t original_btn_num = subghz_custom_btn_get_original();
// Set custom button
if(custom_btn_id == 1) {
switch(original_btn_num) {
case 0x1:
btn = 0x2;
break;
case 0x2:
btn = 0x1;
break;
case 0x4:
btn = 0x1;
break;
case 0x8:
btn = 0x1;
break;
default:
break;
}
}
if(custom_btn_id == 2) {
switch(original_btn_num) {
case 0x1:
btn = 0x4;
break;
case 0x2:
btn = 0x4;
break;
case 0x4:
btn = 0x2;
break;
case 0x8:
btn = 0x4;
break;
default:
break;
}
}
if(custom_btn_id == 3) {
switch(original_btn_num) {
case 0x1:
btn = 0x8;
break;
case 0x2:
btn = 0x8;
break;
case 0x4:
btn = 0x8;
break;
case 0x8:
btn = 0x2;
break;
default:
break;
}
}
if((custom_btn_id == 0) && (original_btn_num != 0)) {
btn = original_btn_num;
}
btn = subghz_protocol_somfy_telis_get_btn_code();
if(instance->generic.cnt < 0xFFFF) {
if((instance->generic.cnt + furi_hal_subghz_get_rolling_counter_mult()) >= 0xFFFF) {
@@ -725,6 +668,74 @@ SubGhzProtocolStatus
subghz_protocol_somfy_telis_const.min_count_bit_for_found);
}
static uint8_t subghz_protocol_somfy_telis_get_btn_code() {
uint8_t custom_btn_id = subghz_custom_btn_get();
uint8_t original_btn_code = subghz_custom_btn_get_original();
uint8_t btn = original_btn_code;
// Set custom button
if((custom_btn_id == SUBGHZ_CUSTOM_BTN_OK) && (original_btn_code != 0)) {
// Restore original button code
btn = original_btn_code;
} else if(custom_btn_id == SUBGHZ_CUSTOM_BTN_UP) {
switch(original_btn_code) {
case 0x1:
btn = 0x2;
break;
case 0x2:
btn = 0x1;
break;
case 0x4:
btn = 0x1;
break;
case 0x8:
btn = 0x1;
break;
default:
break;
}
} else if(custom_btn_id == SUBGHZ_CUSTOM_BTN_DOWN) {
switch(original_btn_code) {
case 0x1:
btn = 0x4;
break;
case 0x2:
btn = 0x4;
break;
case 0x4:
btn = 0x2;
break;
case 0x8:
btn = 0x4;
break;
default:
break;
}
} else if(custom_btn_id == SUBGHZ_CUSTOM_BTN_LEFT) {
switch(original_btn_code) {
case 0x1:
btn = 0x8;
break;
case 0x2:
btn = 0x8;
break;
case 0x4:
btn = 0x8;
break;
case 0x8:
btn = 0x2;
break;
default:
break;
}
}
return btn;
}
void subghz_protocol_decoder_somfy_telis_get_string(void* context, FuriString* output) {
furi_assert(context);
SubGhzProtocolDecoderSomfyTelis* instance = context;

View File

@@ -163,36 +163,41 @@ static bool
instance->generic.data, instance->generic.data_count_bit);
hop = code_found_reverse & 0x00000000ffffffff;
} else {
for
M_EACH(manufacture_code, *subghz_keystore_get_data(instance->keystore), SubGhzKeyArray_t) {
res = strcmp(furi_string_get_cstr(manufacture_code->name), instance->manufacture_name);
if(res == 0) {
switch(manufacture_code->type) {
case KEELOQ_LEARNING_SIMPLE:
//Simple Learning
hop = subghz_protocol_keeloq_common_encrypt(decrypt, manufacture_code->key);
break;
case KEELOQ_LEARNING_NORMAL:
//Normal Learning
man =
subghz_protocol_keeloq_common_normal_learning(fix, manufacture_code->key);
hop = subghz_protocol_keeloq_common_encrypt(decrypt, man);
break;
case KEELOQ_LEARNING_UNKNOWN:
if(kl_type == 1) {
for
M_EACH(
manufacture_code,
*subghz_keystore_get_data(instance->keystore),
SubGhzKeyArray_t) {
res = strcmp(
furi_string_get_cstr(manufacture_code->name), instance->manufacture_name);
if(res == 0) {
switch(manufacture_code->type) {
case KEELOQ_LEARNING_SIMPLE:
//Simple Learning
hop =
subghz_protocol_keeloq_common_encrypt(decrypt, manufacture_code->key);
}
if(kl_type == 2) {
break;
case KEELOQ_LEARNING_NORMAL:
//Normal Learning
man = subghz_protocol_keeloq_common_normal_learning(
fix, manufacture_code->key);
hop = subghz_protocol_keeloq_common_encrypt(decrypt, man);
break;
case KEELOQ_LEARNING_UNKNOWN:
if(kl_type == 1) {
hop = subghz_protocol_keeloq_common_encrypt(
decrypt, manufacture_code->key);
}
if(kl_type == 2) {
man = subghz_protocol_keeloq_common_normal_learning(
fix, manufacture_code->key);
hop = subghz_protocol_keeloq_common_encrypt(decrypt, man);
}
break;
}
break;
}
break;
}
}
}
if(hop) {
uint64_t yek = (uint64_t)fix << 32 | hop;
@@ -517,90 +522,19 @@ static uint8_t subghz_protocol_star_line_check_remote_controller_selector(
uint8_t btn = (uint8_t)(fix >> 24);
uint32_t decrypt = 0;
uint64_t man_normal_learning;
int res = 0;
bool mf_not_set = false;
if(mfname == 0x0) {
mfname = "";
}
if(strcmp(mfname, "") == 0) {
for
M_EACH(manufacture_code, *subghz_keystore_get_data(keystore), SubGhzKeyArray_t) {
switch(manufacture_code->type) {
case KEELOQ_LEARNING_SIMPLE:
// Simple Learning
decrypt = subghz_protocol_keeloq_common_decrypt(hop, manufacture_code->key);
if(subghz_protocol_star_line_check_decrypt(instance, decrypt, btn, end_serial)) {
*manufacture_name = furi_string_get_cstr(manufacture_code->name);
mfname = *manufacture_name;
return 1;
}
break;
case KEELOQ_LEARNING_NORMAL:
// Normal Learning
// https://phreakerclub.com/forum/showpost.php?p=43557&postcount=37
man_normal_learning =
subghz_protocol_keeloq_common_normal_learning(fix, manufacture_code->key);
decrypt = subghz_protocol_keeloq_common_decrypt(hop, man_normal_learning);
if(subghz_protocol_star_line_check_decrypt(instance, decrypt, btn, end_serial)) {
*manufacture_name = furi_string_get_cstr(manufacture_code->name);
mfname = *manufacture_name;
return 1;
}
break;
case KEELOQ_LEARNING_UNKNOWN:
// Simple Learning
decrypt = subghz_protocol_keeloq_common_decrypt(hop, manufacture_code->key);
if(subghz_protocol_star_line_check_decrypt(instance, decrypt, btn, end_serial)) {
*manufacture_name = furi_string_get_cstr(manufacture_code->name);
mfname = *manufacture_name;
kl_type = 1;
return 1;
}
// Check for mirrored man
uint64_t man_rev = 0;
uint64_t man_rev_byte = 0;
for(uint8_t i = 0; i < 64; i += 8) {
man_rev_byte = (uint8_t)(manufacture_code->key >> i);
man_rev = man_rev | man_rev_byte << (56 - i);
}
decrypt = subghz_protocol_keeloq_common_decrypt(hop, man_rev);
if(subghz_protocol_star_line_check_decrypt(instance, decrypt, btn, end_serial)) {
*manufacture_name = furi_string_get_cstr(manufacture_code->name);
mfname = *manufacture_name;
kl_type = 1;
return 1;
}
//###########################
// Normal Learning
// https://phreakerclub.com/forum/showpost.php?p=43557&postcount=37
man_normal_learning =
subghz_protocol_keeloq_common_normal_learning(fix, manufacture_code->key);
decrypt = subghz_protocol_keeloq_common_decrypt(hop, man_normal_learning);
if(subghz_protocol_star_line_check_decrypt(instance, decrypt, btn, end_serial)) {
*manufacture_name = furi_string_get_cstr(manufacture_code->name);
mfname = *manufacture_name;
kl_type = 2;
return 1;
}
// Check for mirrored man
man_normal_learning = subghz_protocol_keeloq_common_normal_learning(fix, man_rev);
decrypt = subghz_protocol_keeloq_common_decrypt(hop, man_normal_learning);
if(subghz_protocol_star_line_check_decrypt(instance, decrypt, btn, end_serial)) {
*manufacture_name = furi_string_get_cstr(manufacture_code->name);
mfname = *manufacture_name;
kl_type = 2;
return 1;
}
break;
}
}
} else if(strcmp(mfname, "Unknown") == 0) {
if(strcmp(mfname, "Unknown") == 0) {
return 1;
} else {
} else if(strcmp(mfname, "") == 0) {
mf_not_set = true;
}
for
M_EACH(manufacture_code, *subghz_keystore_get_data(keystore), SubGhzKeyArray_t) {
res = strcmp(furi_string_get_cstr(manufacture_code->name), mfname);
if(res == 0) {
if(mf_not_set || (strcmp(furi_string_get_cstr(manufacture_code->name), mfname) == 0)) {
switch(manufacture_code->type) {
case KEELOQ_LEARNING_SIMPLE:
// Simple Learning
@@ -663,7 +597,6 @@ static uint8_t subghz_protocol_star_line_check_remote_controller_selector(
kl_type = 2;
return 1;
}
// Check for mirrored man
man_normal_learning =
subghz_protocol_keeloq_common_normal_learning(fix, man_rev);
@@ -679,7 +612,6 @@ static uint8_t subghz_protocol_star_line_check_remote_controller_selector(
}
}
}
}
*manufacture_name = "Unknown";
mfname = "Unknown";

View File

@@ -31,11 +31,7 @@ static Version version = {
.git_hash = GIT_COMMIT,
.git_branch = GIT_BRANCH,
.build_date = BUILD_DATE,
#ifdef FURI_CUSTOM_FLIPPER_NAME
.custom_flipper_name = FURI_CUSTOM_FLIPPER_NAME,
#else
.custom_flipper_name = NULL,
#endif
.version = VERSION
#ifdef FURI_RAM_EXEC
" (RAM)"

View File

@@ -65,7 +65,7 @@ const char* version_get_builddate(const Version* v);
*/
const char* version_get_version(const Version* v);
/** Get custom flipper name if set in ENV
/** Get custom flipper name if set in version_set_custom_name
*
* @param v pointer to Version data. NULL for currently running
* software.
@@ -74,11 +74,11 @@ const char* version_get_version(const Version* v);
*/
const char* version_get_custom_name(const Version* v);
/** Get custom flipper name if set in ENV
/** Set custom flipper name
*
* @param v pointer to Version data. NULL for currently running
* software.
* @param custom name or NULL
* @param name Custom name or NULL
*/
void version_set_custom_name(Version* v, const char* name);

View File

@@ -249,18 +249,7 @@ class Main(App):
)
)
bundle_args.extend(self.other_args)
log_custom_fz_name = environ.get("CUSTOM_FLIPPER_NAME", None) or ""
if (
(log_custom_fz_name != "")
and (len(log_custom_fz_name) <= 8)
and (log_custom_fz_name.isalnum())
and (log_custom_fz_name.isascii())
):
self.logger.info(
f"Flipper Custom Name is set:\n\tName: {log_custom_fz_name} : length - {len(log_custom_fz_name)} chars"
)
if (bundle_result := UpdateMain(no_exit=True)(bundle_args)) == 0:
self.note_dist_component("update", "dir", bundle_dir)
self.logger.info(

View File

@@ -41,32 +41,16 @@ class GitVersion:
version = os.environ.get("DIST_SUFFIX", None) or VERSION or "unknown"
custom_fz_name = os.environ.get("CUSTOM_FLIPPER_NAME", None) or ""
force_no_dirty = os.environ.get("FORCE_NO_DIRTY", None) or ""
if force_no_dirty != "":
dirty = False
if (
(custom_fz_name != "")
and (len(custom_fz_name) <= 8)
and (custom_fz_name.isalnum())
and (custom_fz_name.isascii())
):
return {
"GIT_COMMIT": commit,
"GIT_BRANCH": branch,
"FURI_CUSTOM_FLIPPER_NAME": custom_fz_name,
"VERSION": version,
"BUILD_DIRTY": dirty and 1 or 0,
}
else:
return {
"GIT_COMMIT": commit,
"GIT_BRANCH": branch,
"VERSION": version,
"BUILD_DIRTY": dirty and 1 or 0,
}
return {
"GIT_COMMIT": commit,
"GIT_BRANCH": branch,
"VERSION": version,
"BUILD_DIRTY": dirty and 1 or 0,
}
def _exec_git(self, args):
cmd = ["git"]

View File

@@ -100,11 +100,6 @@ vars.AddVariables(
"Version string for updater package",
"${DIST_SUFFIX}",
),
(
"CUSTOM_FLIPPER_NAME",
"Replaces OTP flipper name with custom string of 8 chars",
"",
),
(
"FORCE_NO_DIRTY",
"Force disable dirty status of the build",

View File

@@ -20,7 +20,6 @@ variables_to_forward = [
# CI/CD variables
"WORKFLOW_BRANCH_OR_TAG",
"DIST_SUFFIX",
"CUSTOM_FLIPPER_NAME",
"FORCE_NO_DIRTY",
# Python & other tools
"HOME",