mirror of
https://github.com/DarkFlippers/unleashed-firmware.git
synced 2025-12-12 04:34:43 +04:00
Merge branch 'dev' into release
This commit is contained in:
29
CHANGELOG.md
29
CHANGELOG.md
@@ -1,28 +1,9 @@
|
||||
### New changes
|
||||
* SubGHz: **Somfy Telis Encoder** (PR #289 | by @assasinfil & @TQMatvey)
|
||||
* SubGHz: Add 350Mhz to default range
|
||||
* Plugins -> Solitaire: Fix for solitaire card placement bug (PR #253 | by @teeebor)
|
||||
* Plugins -> UniTemp (New sensors added), TOTP - Updated to latest commits
|
||||
* Plugins -> Added Text Viewer [(by kowalski7cc & kyhwana)](https://github.com/kowalski7cc/flipper-zero-text-viewer/tree/refactor-text-app)
|
||||
* Plugins -> Added **UART Terminal** [(by cool4uma)](https://github.com/cool4uma/UART_Terminal/tree/main)
|
||||
* Plugins -> Added **ProtoView** [(by antirez)](https://github.com/antirez/protoview)
|
||||
* Plugins -> WAV Player - Replaced with fixed and improved version by [@LTVA1](https://github.com/LTVA1/wav_player)
|
||||
* Clock: Fix 12AM was displaying as 00 AM (PR #288 | by @Smileycathy1128)
|
||||
* Infrared: Allow disabling automatic signal decoding (aka Learn RAW) - works only when debug enabled (PR #273 | by @darmiel)
|
||||
* Infrared: Update universal remote assets (by @amec0e)
|
||||
* Desktop: New battery display (Bar %) - (PR #278 | by @Fasjeit)
|
||||
* BadUSB: Adding CZ keyboard layout (PR #255 | by @peoblouk)
|
||||
* OFW: Various improvements: Toolbox, Updater and Unit Tests.
|
||||
* OFW: Fix typos in source code
|
||||
* OFW: Add the sleigh ride animation
|
||||
* OFW: Documentation: edit texts, markdown linting
|
||||
* OFW: Change broken BadUSB link to Hak5 duckyscript quick reference webpage
|
||||
* OFW: **Per protocol signal repeat count** - **Fixes issues with Sony remotes with SIRC protocol (bruteforce also fixed now!)**
|
||||
* OFW: Add the ability to turn pages in infrared
|
||||
* OFW: **BadUSB backspace/delete fix**
|
||||
* OFW: relocate R_ARM_CALL
|
||||
* OFW: fbt: PVS support
|
||||
* OFW: fbt: removed DEBUG_TOOLS & FAP_EXAMPLES flags
|
||||
* SubGHz: **Somfy Keytis Encoder** and Somfy Telis fixes (PR #297 | by @assasinfil)
|
||||
* SubGHz: Change hopping frequency list to have only most used frequencies
|
||||
* SubGHz: Block usage of hopping with detect raw at same time (its efficiency is almost 0, it looses signals and all that you can capture is a micro part of end of the signal) (Detect raw also will be removed in a future (and replaced with more correct solution))
|
||||
* Plugins -> Updated **ProtoView** [(by antirez)](https://github.com/antirez/protoview)
|
||||
* Infrared: Update universal remote assets (by @amec0e) (PR #298)
|
||||
|
||||
#### [🎲 Download latest extra apps pack](https://download-directory.github.io/?url=https://github.com/xMasterX/unleashed-extra-pack/tree/main/apps)
|
||||
|
||||
|
||||
@@ -72,6 +72,7 @@ Also check the changelog in releases for latest updates!
|
||||
- Security+ v1 & v2
|
||||
- Star Line
|
||||
- Somfy Telis (by @assasinfil & @TQMatvey)
|
||||
- Somfy Keytis (by @assasinfil)
|
||||
|
||||
## Please support development of the project
|
||||
The majority of this project is developed and maintained by me, @xMasterX.
|
||||
|
||||
@@ -173,7 +173,6 @@ bool subghz_scene_receiver_on_event(void* context, SceneManagerEvent event) {
|
||||
subghz_sleep(subghz);
|
||||
}
|
||||
subghz->txrx->hopper_state = SubGhzHopperStateOFF;
|
||||
subghz_history_set_hopper_state(subghz->txrx->history, false);
|
||||
subghz->txrx->idx_menu_chosen = 0;
|
||||
subghz_receiver_set_rx_callback(subghz->txrx->receiver, NULL, subghz);
|
||||
|
||||
|
||||
@@ -231,64 +231,64 @@ static void subghz_scene_receiver_config_set_detect_raw(VariableItem* item) {
|
||||
SubGhz* subghz = variable_item_get_context(item);
|
||||
uint8_t index = variable_item_get_current_value_index(item);
|
||||
|
||||
//if(subghz->txrx->hopper_state == 0) {
|
||||
variable_item_set_current_value_text(item, detect_raw_text[index]);
|
||||
if(subghz->txrx->hopper_state == 0) {
|
||||
variable_item_set_current_value_text(item, detect_raw_text[index]);
|
||||
#ifdef SUBGHZ_SAVE_DETECT_RAW_SETTING
|
||||
subghz->last_settings->detect_raw = index;
|
||||
subghz->last_settings->detect_raw = index;
|
||||
|
||||
subghz_last_settings_set_detect_raw_values(subghz);
|
||||
subghz_last_settings_set_detect_raw_values(subghz);
|
||||
#else
|
||||
subghz_receiver_set_filter(subghz->txrx->receiver, detect_raw_value[index]);
|
||||
subghz_receiver_set_filter(subghz->txrx->receiver, detect_raw_value[index]);
|
||||
|
||||
subghz_protocol_decoder_raw_set_auto_mode(
|
||||
subghz_receiver_search_decoder_base_by_name(
|
||||
subghz->txrx->receiver, SUBGHZ_PROTOCOL_RAW_NAME),
|
||||
(index == 1));
|
||||
subghz_protocol_decoder_raw_set_auto_mode(
|
||||
subghz_receiver_search_decoder_base_by_name(
|
||||
subghz->txrx->receiver, SUBGHZ_PROTOCOL_RAW_NAME),
|
||||
(index == 1));
|
||||
#endif
|
||||
/*} else {
|
||||
} else {
|
||||
variable_item_set_current_value_index(item, 0);
|
||||
}*/
|
||||
}
|
||||
}
|
||||
|
||||
static void subghz_scene_receiver_config_set_hopping_running(VariableItem* item) {
|
||||
SubGhz* subghz = variable_item_get_context(item);
|
||||
uint8_t index = variable_item_get_current_value_index(item);
|
||||
|
||||
//if(subghz_receiver_get_filter(subghz->txrx->receiver) == SubGhzProtocolFlag_Decodable) {
|
||||
variable_item_set_current_value_text(item, hopping_text[index]);
|
||||
if(hopping_value[index] == SubGhzHopperStateOFF) {
|
||||
char text_buf[10] = {0};
|
||||
snprintf(
|
||||
text_buf,
|
||||
sizeof(text_buf),
|
||||
"%lu.%02lu",
|
||||
subghz_setting_get_default_frequency(subghz->setting) / 1000000,
|
||||
(subghz_setting_get_default_frequency(subghz->setting) % 1000000) / 10000);
|
||||
variable_item_set_current_value_text(
|
||||
(VariableItem*)scene_manager_get_scene_state(
|
||||
subghz->scene_manager, SubGhzSceneReceiverConfig),
|
||||
text_buf);
|
||||
subghz->txrx->preset->frequency = subghz_setting_get_default_frequency(subghz->setting);
|
||||
variable_item_set_current_value_index(
|
||||
(VariableItem*)scene_manager_get_scene_state(
|
||||
subghz->scene_manager, SubGhzSceneReceiverConfig),
|
||||
subghz_setting_get_frequency_default_index(subghz->setting));
|
||||
} else {
|
||||
variable_item_set_current_value_text(
|
||||
(VariableItem*)scene_manager_get_scene_state(
|
||||
subghz->scene_manager, SubGhzSceneReceiverConfig),
|
||||
" -----");
|
||||
variable_item_set_current_value_index(
|
||||
(VariableItem*)scene_manager_get_scene_state(
|
||||
subghz->scene_manager, SubGhzSceneReceiverConfig),
|
||||
subghz_setting_get_frequency_default_index(subghz->setting));
|
||||
}
|
||||
if(subghz_receiver_get_filter(subghz->txrx->receiver) == SubGhzProtocolFlag_Decodable) {
|
||||
variable_item_set_current_value_text(item, hopping_text[index]);
|
||||
if(hopping_value[index] == SubGhzHopperStateOFF) {
|
||||
char text_buf[10] = {0};
|
||||
snprintf(
|
||||
text_buf,
|
||||
sizeof(text_buf),
|
||||
"%lu.%02lu",
|
||||
subghz_setting_get_default_frequency(subghz->setting) / 1000000,
|
||||
(subghz_setting_get_default_frequency(subghz->setting) % 1000000) / 10000);
|
||||
variable_item_set_current_value_text(
|
||||
(VariableItem*)scene_manager_get_scene_state(
|
||||
subghz->scene_manager, SubGhzSceneReceiverConfig),
|
||||
text_buf);
|
||||
subghz->txrx->preset->frequency =
|
||||
subghz_setting_get_default_frequency(subghz->setting);
|
||||
variable_item_set_current_value_index(
|
||||
(VariableItem*)scene_manager_get_scene_state(
|
||||
subghz->scene_manager, SubGhzSceneReceiverConfig),
|
||||
subghz_setting_get_frequency_default_index(subghz->setting));
|
||||
} else {
|
||||
variable_item_set_current_value_text(
|
||||
(VariableItem*)scene_manager_get_scene_state(
|
||||
subghz->scene_manager, SubGhzSceneReceiverConfig),
|
||||
" -----");
|
||||
variable_item_set_current_value_index(
|
||||
(VariableItem*)scene_manager_get_scene_state(
|
||||
subghz->scene_manager, SubGhzSceneReceiverConfig),
|
||||
subghz_setting_get_frequency_default_index(subghz->setting));
|
||||
}
|
||||
|
||||
subghz->txrx->hopper_state = hopping_value[index];
|
||||
subghz_history_set_hopper_state(subghz->txrx->history, (index == 1));
|
||||
/*} else {
|
||||
subghz->txrx->hopper_state = hopping_value[index];
|
||||
} else {
|
||||
variable_item_set_current_value_index(item, 0);
|
||||
}*/
|
||||
}
|
||||
}
|
||||
|
||||
static void subghz_scene_receiver_config_set_speaker(VariableItem* item) {
|
||||
|
||||
@@ -46,7 +46,6 @@ struct SubGhzHistory {
|
||||
uint8_t code_last_hash_data;
|
||||
FuriString* tmp_string;
|
||||
bool write_tmp_files;
|
||||
bool is_hopper_running;
|
||||
Storage* storage;
|
||||
SubGhzHistoryStruct* history;
|
||||
};
|
||||
@@ -140,8 +139,6 @@ SubGhzHistory* subghz_history_alloc(void) {
|
||||
instance->storage = furi_record_open(RECORD_STORAGE);
|
||||
instance->write_tmp_files = subghz_history_check_sdcard(instance);
|
||||
|
||||
instance->is_hopper_running = false;
|
||||
|
||||
if(!instance->write_tmp_files) {
|
||||
FURI_LOG_E(TAG, "Unstable work! Cannot use SD Card!");
|
||||
}
|
||||
@@ -217,12 +214,6 @@ void subghz_history_reset(SubGhzHistory* instance) {
|
||||
instance->code_last_hash_data = 0;
|
||||
}
|
||||
|
||||
void subghz_history_set_hopper_state(SubGhzHistory* instance, bool hopper_state) {
|
||||
furi_assert(instance);
|
||||
|
||||
instance->is_hopper_running = hopper_state;
|
||||
}
|
||||
|
||||
uint16_t subghz_history_get_item(SubGhzHistory* instance) {
|
||||
furi_assert(instance);
|
||||
return instance->last_index_write;
|
||||
@@ -372,10 +363,6 @@ bool subghz_history_add_to_history(
|
||||
item->protocol_name, "%s", furi_string_get_cstr(instance->tmp_string));
|
||||
}
|
||||
if(!strcmp(furi_string_get_cstr(instance->tmp_string), "RAW")) {
|
||||
// Check if hopper enabled we need to add little delay
|
||||
if(instance->is_hopper_running) {
|
||||
furi_delay_ms(40);
|
||||
}
|
||||
// Enable writing temp files to micro sd
|
||||
tmp_file_for_raw = true;
|
||||
// Write display name
|
||||
|
||||
@@ -110,10 +110,3 @@ bool subghz_history_add_to_history(
|
||||
* @return SubGhzProtocolCommonLoad*
|
||||
*/
|
||||
FlipperFormat* subghz_history_get_raw_data(SubGhzHistory* instance, uint16_t idx);
|
||||
|
||||
/** Set hopper state for internal usage in history
|
||||
*
|
||||
* @param instance - SubGhzHistory instance
|
||||
* @param hopper_state - bool is hopper running?
|
||||
*/
|
||||
void subghz_history_set_hopper_state(SubGhzHistory* instance, bool hopper_state);
|
||||
|
||||
@@ -125,6 +125,7 @@ ProtoViewApp* protoview_app_alloc() {
|
||||
|
||||
// GUI
|
||||
app->gui = furi_record_open(RECORD_GUI);
|
||||
app->notification = furi_record_open(RECORD_NOTIFICATION);
|
||||
app->view_port = view_port_alloc();
|
||||
view_port_draw_callback_set(app->view_port, render_callback, app);
|
||||
view_port_input_callback_set(app->view_port, input_callback, app);
|
||||
@@ -185,7 +186,7 @@ ProtoViewApp* protoview_app_alloc() {
|
||||
void protoview_app_free(ProtoViewApp* app) {
|
||||
furi_assert(app);
|
||||
|
||||
// Put CC1101 on sleep.
|
||||
// Put CC1101 on sleep, this also restores charging.
|
||||
radio_sleep(app);
|
||||
|
||||
// View related.
|
||||
@@ -193,6 +194,7 @@ void protoview_app_free(ProtoViewApp* app) {
|
||||
gui_remove_view_port(app->gui, app->view_port);
|
||||
view_port_free(app->view_port);
|
||||
furi_record_close(RECORD_GUI);
|
||||
furi_record_close(RECORD_NOTIFICATION);
|
||||
furi_message_queue_free(app->event_queue);
|
||||
app->gui = NULL;
|
||||
|
||||
|
||||
@@ -36,6 +36,7 @@ typedef struct ProtoViewApp ProtoViewApp;
|
||||
typedef enum {
|
||||
TxRxStateIDLE,
|
||||
TxRxStateRx,
|
||||
TxRxStateTx,
|
||||
TxRxStateSleep,
|
||||
} TxRxState;
|
||||
|
||||
@@ -112,9 +113,11 @@ typedef struct ProtoViewMsgInfo {
|
||||
integer. */
|
||||
} ProtoViewMsgInfo;
|
||||
|
||||
/* Our main application context. */
|
||||
struct ProtoViewApp {
|
||||
/* GUI */
|
||||
Gui* gui;
|
||||
NotificationApp* notification;
|
||||
ViewPort* view_port; /* We just use a raw viewport and we render
|
||||
everything into the low level canvas. */
|
||||
ProtoViewCurrentView current_view; /* Active left-right view ID. */
|
||||
@@ -182,6 +185,7 @@ void radio_rx_end(ProtoViewApp* app);
|
||||
void radio_sleep(ProtoViewApp* app);
|
||||
void raw_sampling_worker_start(ProtoViewApp* app);
|
||||
void raw_sampling_worker_stop(ProtoViewApp* app);
|
||||
void radio_tx_signal(ProtoViewApp* app, FuriHalSubGhzAsyncTxCallback data_feeder, void* ctx);
|
||||
|
||||
/* signal.c */
|
||||
uint32_t duration_delta(uint32_t a, uint32_t b);
|
||||
|
||||
@@ -39,6 +39,10 @@ void radio_begin(ProtoViewApp* app) {
|
||||
furi_hal_subghz_reset();
|
||||
furi_hal_subghz_idle();
|
||||
|
||||
/* Power circuits are noisy. Suppressing the charge while we use
|
||||
* ProtoView will improve the RF performances. */
|
||||
furi_hal_power_suppress_charge_enter();
|
||||
|
||||
/* The CC1101 preset can be either one of the standard presets, if
|
||||
* the modulation "custom" field is NULL, or a custom preset we
|
||||
* defined in custom_presets.h. */
|
||||
@@ -50,6 +54,8 @@ void radio_begin(ProtoViewApp* app) {
|
||||
app->txrx->txrx_state = TxRxStateIDLE;
|
||||
}
|
||||
|
||||
/* ================================= Reception ============================== */
|
||||
|
||||
/* Setup subghz to start receiving using a background worker. */
|
||||
uint32_t radio_rx(ProtoViewApp* app) {
|
||||
furi_assert(app);
|
||||
@@ -78,6 +84,7 @@ uint32_t radio_rx(ProtoViewApp* app) {
|
||||
/* Stop subghz worker (if active), put radio on idle state. */
|
||||
void radio_rx_end(ProtoViewApp* app) {
|
||||
furi_assert(app);
|
||||
|
||||
if(app->txrx->txrx_state == TxRxStateRx) {
|
||||
if(!app->txrx->debug_timer_sampling) {
|
||||
if(subghz_worker_is_running(app->txrx->worker)) {
|
||||
@@ -102,6 +109,33 @@ void radio_sleep(ProtoViewApp* app) {
|
||||
}
|
||||
furi_hal_subghz_sleep();
|
||||
app->txrx->txrx_state = TxRxStateSleep;
|
||||
furi_hal_power_suppress_charge_exit();
|
||||
}
|
||||
|
||||
/* =============================== Transmission ============================= */
|
||||
|
||||
/* This function suspends the current RX state, switches to TX mode,
|
||||
* transmits the signal provided by the callback data_feeder, and later
|
||||
* restores the RX state if there was one. */
|
||||
void radio_tx_signal(ProtoViewApp* app, FuriHalSubGhzAsyncTxCallback data_feeder, void* ctx) {
|
||||
TxRxState oldstate = app->txrx->txrx_state;
|
||||
|
||||
if(oldstate == TxRxStateRx) radio_rx_end(app);
|
||||
radio_begin(app);
|
||||
|
||||
furi_hal_subghz_idle();
|
||||
uint32_t value = furi_hal_subghz_set_frequency_and_path(app->frequency);
|
||||
FURI_LOG_E(TAG, "Switched to frequency: %lu", value);
|
||||
furi_hal_gpio_write(&gpio_cc1101_g0, false);
|
||||
furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow);
|
||||
|
||||
furi_hal_subghz_start_async_tx(data_feeder, ctx);
|
||||
while(!furi_hal_subghz_is_async_tx_complete()) furi_delay_ms(10);
|
||||
furi_hal_subghz_stop_async_tx();
|
||||
furi_hal_subghz_idle();
|
||||
|
||||
radio_begin(app);
|
||||
if(oldstate == TxRxStateRx) radio_rx(app);
|
||||
}
|
||||
|
||||
/* ============================= Raw sampling mode =============================
|
||||
|
||||
@@ -118,6 +118,26 @@ uint32_t search_coherent_signal(RawSamplesBuffer* s, uint32_t idx) {
|
||||
return len;
|
||||
}
|
||||
|
||||
/* Called when we detect a message. Just blinks when the message was
|
||||
* not decoded. Vibrates, too, when the message was correctly decoded. */
|
||||
void notify_signal_detected(ProtoViewApp* app, bool decoded) {
|
||||
static const NotificationSequence decoded_seq = {
|
||||
&message_vibro_on,
|
||||
&message_green_255,
|
||||
&message_delay_50,
|
||||
&message_green_0,
|
||||
&message_vibro_off,
|
||||
NULL};
|
||||
|
||||
static const NotificationSequence unknown_seq = {
|
||||
&message_red_255, &message_delay_50, &message_red_0, NULL};
|
||||
|
||||
if(decoded)
|
||||
notification_message(app->notification, &decoded_seq);
|
||||
else
|
||||
notification_message(app->notification, &unknown_seq);
|
||||
}
|
||||
|
||||
/* Search the buffer with the stored signal (last N samples received)
|
||||
* in order to find a coherent signal. If a signal that does not appear to
|
||||
* be just noise is found, it is set in DetectedSamples global signal
|
||||
@@ -179,6 +199,7 @@ void scan_for_signal(ProtoViewApp* app) {
|
||||
app->us_scale = 10;
|
||||
else if(DetectedSamples->short_pulse_dur < 145)
|
||||
app->us_scale = 30;
|
||||
notify_signal_detected(app, decoded);
|
||||
} else {
|
||||
/* If the structure was not filled, discard it. Otherwise
|
||||
* now the owner is app->msg_info. */
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
#include <gui/view_i.h>
|
||||
#include <lib/toolbox/random_name.h>
|
||||
|
||||
/* This view has subviews accessible navigating up/down. This
|
||||
* enumaration is used to track the currently active subview. */
|
||||
enum {
|
||||
SubViewInfoMain,
|
||||
SubViewInfoSave,
|
||||
@@ -90,7 +92,7 @@ static void render_subview_save(Canvas* const canvas, ProtoViewApp* app) {
|
||||
}
|
||||
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
canvas_draw_str(canvas, 0, 6, "ok: save, < >: slide rows");
|
||||
canvas_draw_str(canvas, 0, 6, "ok: send, long ok: save");
|
||||
}
|
||||
|
||||
/* Render the selected subview of this view. */
|
||||
@@ -147,6 +149,116 @@ void set_signal_random_filename(ProtoViewApp* app, char* buf, size_t buflen) {
|
||||
str_replace(buf, '/', '_');
|
||||
}
|
||||
|
||||
/* ========================== Signal transmission =========================== */
|
||||
|
||||
/* This is the context we pass to the data yield callback for
|
||||
* asynchronous tx. */
|
||||
typedef enum {
|
||||
SendSignalSendStartGap,
|
||||
SendSignalSendBits,
|
||||
SendSignalSendEndGap,
|
||||
SendSignalEndTransmission
|
||||
} SendSignalState;
|
||||
|
||||
#define PROTOVIEW_SENDSIGNAL_START_GAP 10000 /* microseconds. */
|
||||
#define PROTOVIEW_SENDSIGNAL_END_GAP 10000 /* microseconds. */
|
||||
|
||||
typedef struct {
|
||||
SendSignalState state; // Current state.
|
||||
uint32_t curpos; // Current bit position of data to send.
|
||||
ProtoViewApp* app; // App reference.
|
||||
uint32_t start_gap_dur; // Gap to send at the start.
|
||||
uint32_t end_gap_dur; // Gap to send at the end.
|
||||
} SendSignalCtx;
|
||||
|
||||
/* Setup the state context for the callback responsible to feed data
|
||||
* to the subghz async tx system. */
|
||||
static void send_signal_init(SendSignalCtx* ss, ProtoViewApp* app) {
|
||||
ss->state = SendSignalSendStartGap;
|
||||
ss->curpos = 0;
|
||||
ss->app = app;
|
||||
ss->start_gap_dur = PROTOVIEW_SENDSIGNAL_START_GAP;
|
||||
ss->end_gap_dur = PROTOVIEW_SENDSIGNAL_END_GAP;
|
||||
}
|
||||
|
||||
/* Send signal data feeder callback. When the asynchronous transmission is
|
||||
* active, this function is called to return new samples from the currently
|
||||
* decoded signal in app->msg_info. The subghz subsystem aspects this function,
|
||||
* that is the data feeder, to return LevelDuration types (that is a structure
|
||||
* with level, that is pulse or gap, and duration in microseconds).
|
||||
*
|
||||
* The position into the transmission is stored in the context 'ctx', that
|
||||
* references a SendSignalCtx structure.
|
||||
*
|
||||
* In the SendSignalCtx structure 'ss' we remember at which bit of the
|
||||
* message we are, in ss->curoff. We also send a start and end gap in order
|
||||
* to make sure the transmission is clear.
|
||||
*/
|
||||
LevelDuration radio_tx_feed_data(void* ctx) {
|
||||
SendSignalCtx* ss = ctx;
|
||||
|
||||
/* Send start gap. */
|
||||
if(ss->state == SendSignalSendStartGap) {
|
||||
ss->state = SendSignalSendBits;
|
||||
return level_duration_make(0, ss->start_gap_dur);
|
||||
}
|
||||
|
||||
/* Send data. */
|
||||
if(ss->state == SendSignalSendBits) {
|
||||
uint32_t dur = 0, j;
|
||||
uint32_t level = 0;
|
||||
|
||||
/* Let's see how many consecutive bits we have with the same
|
||||
* level. */
|
||||
for(j = 0; ss->curpos + j < ss->app->msg_info->pulses_count; j++) {
|
||||
uint32_t l =
|
||||
bitmap_get(ss->app->msg_info->bits, ss->app->msg_info->bits_bytes, ss->curpos + j);
|
||||
if(j == 0) {
|
||||
/* At the first bit of this sequence, we store the
|
||||
* level of the sequence. */
|
||||
level = l;
|
||||
dur += ss->app->msg_info->short_pulse_dur;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* As long as the level is the same, we update the duration.
|
||||
* Otherwise stop the loop and return this sample. */
|
||||
if(l != level) break;
|
||||
dur += ss->app->msg_info->short_pulse_dur;
|
||||
}
|
||||
ss->curpos += j;
|
||||
|
||||
/* If this was the last set of bits, change the state to
|
||||
* send the final gap. */
|
||||
if(ss->curpos >= ss->app->msg_info->pulses_count) ss->state = SendSignalSendEndGap;
|
||||
return level_duration_make(level, dur);
|
||||
}
|
||||
|
||||
/* Send end gap. */
|
||||
if(ss->state == SendSignalSendEndGap) {
|
||||
ss->state = SendSignalEndTransmission;
|
||||
return level_duration_make(0, ss->end_gap_dur);
|
||||
}
|
||||
|
||||
/* End transmission. Here state is guaranteed
|
||||
* to be SendSignalEndTransmission */
|
||||
return level_duration_reset();
|
||||
}
|
||||
|
||||
/* Vibrate and produce a click sound when a signal is sent. */
|
||||
void notify_signal_sent(ProtoViewApp* app) {
|
||||
static const NotificationSequence sent_seq = {
|
||||
&message_blue_255,
|
||||
&message_vibro_on,
|
||||
&message_note_g1,
|
||||
&message_delay_10,
|
||||
&message_sound_off,
|
||||
&message_vibro_off,
|
||||
&message_blue_0,
|
||||
NULL};
|
||||
notification_message(app->notification, &sent_seq);
|
||||
}
|
||||
|
||||
/* Handle input for the info view. */
|
||||
void process_input_info(ProtoViewApp* app, InputEvent input) {
|
||||
if(process_subview_updown(app, input, SubViewInfoLast)) return;
|
||||
@@ -165,10 +277,15 @@ void process_input_info(ProtoViewApp* app, InputEvent input) {
|
||||
privdata->signal_display_start_row++;
|
||||
} else if(input.type == InputTypePress && input.key == InputKeyLeft) {
|
||||
if(privdata->signal_display_start_row != 0) privdata->signal_display_start_row--;
|
||||
} else if(input.type == InputTypePress && input.key == InputKeyOk) {
|
||||
} else if(input.type == InputTypeLong && input.key == InputKeyOk) {
|
||||
privdata->filename = malloc(SAVE_FILENAME_LEN);
|
||||
set_signal_random_filename(app, privdata->filename, SAVE_FILENAME_LEN);
|
||||
show_keyboard(app, privdata->filename, SAVE_FILENAME_LEN, text_input_done_callback);
|
||||
} else if(input.type == InputTypeShort && input.key == InputKeyOk) {
|
||||
SendSignalCtx send_state;
|
||||
send_signal_init(&send_state, app);
|
||||
radio_tx_signal(app, radio_tx_feed_data, &send_state);
|
||||
notify_signal_sent(app);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
Filetype: IR library file
|
||||
Version: 1
|
||||
# Last Updated 13th Jan, 2023
|
||||
# Last Checked 13th Jan, 2023
|
||||
# Last Checked 19th Jan, 2023
|
||||
#
|
||||
name: POWER
|
||||
type: raw
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
Filetype: IR library file
|
||||
Version: 1
|
||||
# Last Updated 13th Jan, 2023
|
||||
# Last Checked 13th Jan, 2023
|
||||
# Last Updated 19th Jan, 2023
|
||||
# Last Checked 19th Jan, 2023
|
||||
#
|
||||
name: POWER
|
||||
type: parsed
|
||||
@@ -2002,3 +2002,15 @@ type: parsed
|
||||
protocol: NEC
|
||||
address: 20 00 00 00
|
||||
command: 50 00 00 00
|
||||
#
|
||||
name: VOL-
|
||||
type: parsed
|
||||
protocol: NEC
|
||||
address: 00 00 00 00
|
||||
command: 0C 00 00 00
|
||||
#
|
||||
name: MUTE
|
||||
type: parsed
|
||||
protocol: NEC
|
||||
address: 00 00 00 00
|
||||
command: 47 00 00 00
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
Filetype: IR library file
|
||||
Version: 1
|
||||
# Last Updated 13th Jan, 2023
|
||||
# Last Checked 13th Jan, 2023
|
||||
# Last Updated 19th Jan, 2023
|
||||
# Last Checked 19th Jan, 2023
|
||||
#
|
||||
name: POWER
|
||||
type: raw
|
||||
@@ -1287,3 +1287,39 @@ type: parsed
|
||||
protocol: NEC
|
||||
address: 01 00 00 00
|
||||
command: 8B 00 00 00
|
||||
#
|
||||
name: POWER
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 2256 695 788 1354 789 1349 789 1340 792 702 762 697 763 692 789 661 788 720 786 693 786 689 785 685 784 681 784 676 784 1334 784 1330 783 102265 2255 695 787 1356 786 1352 785 1348 785 681 783 676 783 671 784 666 784 724 784 696 783 691 784 686 784 681 783 676 784 1335 783 1330 783
|
||||
# OSC
|
||||
name: ROTATE
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 2227 749 733 1382 761 1379 866 1292 841 566 898 591 868 588 866 582 760 1412 867 612 866 576 898 603 867 598 866 1256 759 695 867 1246 759 101611 2335 615 868 1245 899 1268 869 1266 867 566 898 591 760 694 761 689 760 1411 760 720 760 715 759 710 759 705 759 1363 760 696 758 1352 761
|
||||
#
|
||||
name: ROTATE
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 2224 708 755 1419 757 1443 756 685 756 1470 757 709 758 710 784 657 836 708 756 763 785 1468 782 1444 755 737 756 712 754 1471 781 1419 780 101298 2250 656 778 1420 809 1391 753 686 755 1472 779 687 779 687 752 688 831 714 778 741 750 1502 776 1422 752 740 752 741 751 1448 751 1475 749
|
||||
#
|
||||
name: POWER
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 2203 675 786 1388 867 1361 786 678 786 1444 758 708 759 707 760 707 786 735 757 760 786 735 757 736 781 711 757 734 759 733 785 734 758 101185 2198 708 757 1416 757 1442 756 685 755 1445 780 685 780 662 776 689 803 742 778 740 753 766 779 715 777 714 779 714 778 690 776 742 752
|
||||
# StrengthUp
|
||||
name: SPEED+
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 2224 685 782 1419 808 1418 779 687 757 1470 757 710 757 684 809 657 809 736 758 1469 758 736 756 1470 757 762 755 1446 782 1418 781 712 755 101352 2223 707 758 1417 834 1392 781 685 781 1446 780 687 754 687 754 713 804 741 779 1447 779 715 778 1447 779 740 752 1448 778 1422 779 690 775
|
||||
# StrengthDown
|
||||
name: SPEED-
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 2222 685 781 1419 808 1419 780 686 755 1447 781 684 783 686 780 686 807 1470 757 1470 756 1471 756 1497 756 1445 780 1447 780 1421 779 1421 754 101509 2250 684 777 1421 781 1444 754 687 754 1472 779 687 779 688 753 688 830 1448 777 1449 778 1448 752 1501 752 1450 773 1451 778 1422 778 1423 777
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
Filetype: IR library file
|
||||
Version: 1
|
||||
# Last Updated 13th Jan, 2023
|
||||
# Last Checked 13th Jan, 2023
|
||||
# Last Checked 19th Jan, 2023
|
||||
#
|
||||
# ON
|
||||
name: POWER
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
Filetype: IR library file
|
||||
Version: 1
|
||||
# Last Updated 13th Jan, 2023
|
||||
# Last Checked 13th Jan, 2023
|
||||
# Last Updated 19th Jan, 2023
|
||||
# Last Checked 19th Jan, 2023
|
||||
#
|
||||
name: POWER
|
||||
type: parsed
|
||||
@@ -1821,3 +1821,21 @@ type: parsed
|
||||
protocol: NEC
|
||||
address: 28 00 00 00
|
||||
command: 10 00 00 00
|
||||
#
|
||||
name: CH+
|
||||
type: parsed
|
||||
protocol: RC5
|
||||
address: 01 00 00 00
|
||||
command: 14 00 00 00
|
||||
#
|
||||
name: CH+
|
||||
type: parsed
|
||||
protocol: SIRC20
|
||||
address: 5A 0E 00 00
|
||||
command: 10 00 00 00
|
||||
#
|
||||
name: CH-
|
||||
type: parsed
|
||||
protocol: SIRC20
|
||||
address: 5A 0E 00 00
|
||||
command: 11 00 00 00
|
||||
|
||||
@@ -88,10 +88,10 @@ Your frequencies will be added after default ones
|
||||
|
||||
### Default hopper list
|
||||
```
|
||||
310000000,
|
||||
315000000,
|
||||
318000000,
|
||||
330000000,
|
||||
390000000,
|
||||
433420000,
|
||||
433920000,
|
||||
868350000,
|
||||
```
|
||||
@@ -3062,6 +3062,11 @@ Function,-,subghz_protocol_encoder_smc5326_deserialize,_Bool,"void*, FlipperForm
|
||||
Function,-,subghz_protocol_encoder_smc5326_free,void,void*
|
||||
Function,-,subghz_protocol_encoder_smc5326_stop,void,void*
|
||||
Function,-,subghz_protocol_encoder_smc5326_yield,LevelDuration,void*
|
||||
Function,-,subghz_protocol_encoder_somfy_keytis_alloc,void*,SubGhzEnvironment*
|
||||
Function,-,subghz_protocol_encoder_somfy_keytis_deserialize,_Bool,"void*, FlipperFormat*"
|
||||
Function,-,subghz_protocol_encoder_somfy_keytis_free,void,void*
|
||||
Function,-,subghz_protocol_encoder_somfy_keytis_stop,void,void*
|
||||
Function,-,subghz_protocol_encoder_somfy_keytis_yield,LevelDuration,void*
|
||||
Function,-,subghz_protocol_encoder_somfy_telis_alloc,void*,SubGhzEnvironment*
|
||||
Function,-,subghz_protocol_encoder_somfy_telis_deserialize,_Bool,"void*, FlipperFormat*"
|
||||
Function,-,subghz_protocol_encoder_somfy_telis_free,void,void*
|
||||
@@ -3088,6 +3093,7 @@ Function,+,subghz_protocol_registry_get_by_index,const SubGhzProtocol*,"const Su
|
||||
Function,+,subghz_protocol_registry_get_by_name,const SubGhzProtocol*,"const SubGhzProtocolRegistry*, const char*"
|
||||
Function,-,subghz_protocol_secplus_v1_check_fixed,_Bool,uint32_t
|
||||
Function,-,subghz_protocol_secplus_v2_create_data,_Bool,"void*, FlipperFormat*, uint32_t, uint8_t, uint32_t, SubGhzRadioPreset*"
|
||||
Function,-,subghz_protocol_somfy_keytis_create_data,_Bool,"void*, FlipperFormat*, uint32_t, uint8_t, uint16_t, SubGhzRadioPreset*"
|
||||
Function,-,subghz_protocol_somfy_telis_create_data,_Bool,"void*, FlipperFormat*, uint32_t, uint8_t, uint16_t, SubGhzRadioPreset*"
|
||||
Function,-,subghz_protocol_star_line_create_data,_Bool,"void*, FlipperFormat*, uint32_t, uint8_t, uint16_t, const char*, SubGhzRadioPreset*"
|
||||
Function,+,subghz_receiver_alloc_init,SubGhzReceiver*,SubGhzEnvironment*
|
||||
|
||||
|
@@ -55,25 +55,40 @@ const SubGhzProtocolDecoder subghz_protocol_somfy_keytis_decoder = {
|
||||
.get_string = subghz_protocol_decoder_somfy_keytis_get_string,
|
||||
};
|
||||
|
||||
const SubGhzProtocolEncoder subghz_protocol_somfy_keytis_encoder = {
|
||||
.alloc = NULL,
|
||||
.free = NULL,
|
||||
|
||||
.deserialize = NULL,
|
||||
.stop = NULL,
|
||||
.yield = NULL,
|
||||
};
|
||||
|
||||
const SubGhzProtocol subghz_protocol_somfy_keytis = {
|
||||
.name = SUBGHZ_PROTOCOL_SOMFY_KEYTIS_NAME,
|
||||
.type = SubGhzProtocolTypeDynamic,
|
||||
.flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_868 | SubGhzProtocolFlag_AM |
|
||||
SubGhzProtocolFlag_Decodable | SubGhzProtocolFlag_Save,
|
||||
SubGhzProtocolFlag_Decodable | SubGhzProtocolFlag_Save | SubGhzProtocolFlag_Send,
|
||||
|
||||
.decoder = &subghz_protocol_somfy_keytis_decoder,
|
||||
.encoder = &subghz_protocol_somfy_keytis_encoder,
|
||||
};
|
||||
|
||||
const SubGhzProtocolEncoder subghz_protocol_somfy_keytis_encoder = {
|
||||
.alloc = subghz_protocol_encoder_somfy_keytis_alloc,
|
||||
.free = subghz_protocol_encoder_somfy_keytis_free,
|
||||
|
||||
.deserialize = subghz_protocol_encoder_somfy_keytis_deserialize,
|
||||
.stop = subghz_protocol_encoder_somfy_keytis_stop,
|
||||
.yield = subghz_protocol_encoder_somfy_keytis_yield,
|
||||
};
|
||||
|
||||
void* subghz_protocol_encoder_somfy_keytis_alloc(SubGhzEnvironment* environment) {
|
||||
UNUSED(environment);
|
||||
SubGhzProtocolEncoderSomfyKeytis* instance = malloc(sizeof(SubGhzProtocolEncoderSomfyKeytis));
|
||||
|
||||
instance->base.protocol = &subghz_protocol_somfy_keytis;
|
||||
instance->generic.protocol_name = instance->base.protocol->name;
|
||||
|
||||
instance->encoder.repeat = 10;
|
||||
instance->encoder.size_upload = 512;
|
||||
instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration));
|
||||
instance->encoder.is_running = false;
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
void* subghz_protocol_decoder_somfy_keytis_alloc(SubGhzEnvironment* environment) {
|
||||
UNUSED(environment);
|
||||
SubGhzProtocolDecoderSomfyKeytis* instance = malloc(sizeof(SubGhzProtocolDecoderSomfyKeytis));
|
||||
@@ -83,6 +98,13 @@ void* subghz_protocol_decoder_somfy_keytis_alloc(SubGhzEnvironment* environment)
|
||||
return instance;
|
||||
}
|
||||
|
||||
void subghz_protocol_encoder_somfy_keytis_free(void* context) {
|
||||
furi_assert(context);
|
||||
SubGhzProtocolEncoderSomfyKeytis* instance = context;
|
||||
free(instance->encoder.upload);
|
||||
free(instance);
|
||||
}
|
||||
|
||||
void subghz_protocol_decoder_somfy_keytis_free(void* context) {
|
||||
furi_assert(context);
|
||||
SubGhzProtocolDecoderSomfyKeytis* instance = context;
|
||||
@@ -100,6 +122,330 @@ void subghz_protocol_decoder_somfy_keytis_reset(void* context) {
|
||||
NULL);
|
||||
}
|
||||
|
||||
static bool
|
||||
subghz_protocol_somfy_keytis_gen_data(SubGhzProtocolEncoderSomfyKeytis* instance, uint8_t btn) {
|
||||
UNUSED(btn);
|
||||
uint64_t data = instance->generic.data ^ (instance->generic.data >> 8);
|
||||
instance->generic.btn = (data >> 48) & 0xF;
|
||||
instance->generic.cnt = (data >> 24) & 0xFFFF;
|
||||
instance->generic.serial = data & 0xFFFFFF;
|
||||
|
||||
if(instance->generic.cnt < 0xFFFF) {
|
||||
instance->generic.cnt++;
|
||||
} else if(instance->generic.cnt >= 0xFFFF) {
|
||||
instance->generic.cnt = 0;
|
||||
}
|
||||
|
||||
uint8_t frame[10];
|
||||
frame[0] = (0xA << 4) | instance->generic.btn;
|
||||
frame[1] = 0xF << 4;
|
||||
frame[2] = instance->generic.cnt >> 8;
|
||||
frame[3] = instance->generic.cnt;
|
||||
frame[4] = instance->generic.serial >> 16;
|
||||
frame[5] = instance->generic.serial >> 8;
|
||||
frame[6] = instance->generic.serial;
|
||||
frame[7] = 0xC4;
|
||||
frame[8] = 0x00;
|
||||
frame[9] = 0x19;
|
||||
|
||||
uint8_t checksum = 0;
|
||||
for(uint8_t i = 0; i < 7; i++) {
|
||||
checksum = checksum ^ frame[i] ^ (frame[i] >> 4);
|
||||
}
|
||||
checksum &= 0xF;
|
||||
|
||||
frame[1] |= checksum;
|
||||
|
||||
for(uint8_t i = 1; i < 7; i++) {
|
||||
frame[i] ^= frame[i - 1];
|
||||
}
|
||||
data = 0;
|
||||
for(uint8_t i = 0; i < 7; ++i) {
|
||||
data <<= 8;
|
||||
data |= frame[i];
|
||||
}
|
||||
instance->generic.data = data;
|
||||
data = 0;
|
||||
for(uint8_t i = 7; i < 10; ++i) {
|
||||
data <<= 8;
|
||||
data |= frame[i];
|
||||
}
|
||||
instance->generic.data_2 = data;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool subghz_protocol_somfy_keytis_create_data(
|
||||
void* context,
|
||||
FlipperFormat* flipper_format,
|
||||
uint32_t serial,
|
||||
uint8_t btn,
|
||||
uint16_t cnt,
|
||||
SubGhzRadioPreset* preset) {
|
||||
furi_assert(context);
|
||||
SubGhzProtocolEncoderSomfyKeytis* instance = context;
|
||||
instance->generic.serial = serial;
|
||||
instance->generic.cnt = cnt;
|
||||
instance->generic.data_count_bit = 80;
|
||||
bool res = subghz_protocol_somfy_keytis_gen_data(instance, btn);
|
||||
if(res) {
|
||||
res = subghz_block_generic_serialize(&instance->generic, flipper_format, preset);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generating an upload from data.
|
||||
* @param instance Pointer to a SubGhzProtocolEncoderKeeloq instance
|
||||
* @return true On success
|
||||
*/
|
||||
static bool subghz_protocol_encoder_somfy_keytis_get_upload(
|
||||
SubGhzProtocolEncoderSomfyKeytis* instance,
|
||||
uint8_t btn) {
|
||||
furi_assert(instance);
|
||||
|
||||
//gen new key
|
||||
if(subghz_protocol_somfy_keytis_gen_data(instance, btn)) {
|
||||
//ToDo if you need to add a callback to automatically update the data on the display
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t index = 0;
|
||||
|
||||
//Send header
|
||||
//Wake up
|
||||
instance->encoder.upload[index++] = level_duration_make(true, (uint32_t)9415); // 1
|
||||
instance->encoder.upload[index++] = level_duration_make(false, (uint32_t)89565); // 0
|
||||
//Hardware sync
|
||||
for(uint8_t i = 0; i < 12; ++i) {
|
||||
instance->encoder.upload[index++] = level_duration_make(
|
||||
true, (uint32_t)subghz_protocol_somfy_keytis_const.te_short * 4); // 1
|
||||
instance->encoder.upload[index++] = level_duration_make(
|
||||
false, (uint32_t)subghz_protocol_somfy_keytis_const.te_short * 4); // 0
|
||||
}
|
||||
//Software sync
|
||||
instance->encoder.upload[index++] = level_duration_make(true, (uint32_t)4550); // 1
|
||||
instance->encoder.upload[index++] =
|
||||
level_duration_make(false, (uint32_t)subghz_protocol_somfy_keytis_const.te_short); // 0
|
||||
|
||||
//Send key data MSB manchester
|
||||
|
||||
for(uint8_t i = instance->generic.data_count_bit - 24; i > 0; i--) {
|
||||
if(bit_read(instance->generic.data, i - 1)) {
|
||||
if(instance->encoder.upload[index - 1].level == LEVEL_DURATION_LEVEL_LOW) {
|
||||
instance->encoder.upload[index - 1].duration *= 2; // 00
|
||||
instance->encoder.upload[index++] = level_duration_make(
|
||||
true, (uint32_t)subghz_protocol_somfy_keytis_const.te_short); // 1
|
||||
} else {
|
||||
instance->encoder.upload[index++] = level_duration_make(
|
||||
false, (uint32_t)subghz_protocol_somfy_keytis_const.te_short); // 0
|
||||
instance->encoder.upload[index++] = level_duration_make(
|
||||
true, (uint32_t)subghz_protocol_somfy_keytis_const.te_short); // 1
|
||||
}
|
||||
|
||||
} else {
|
||||
if(instance->encoder.upload[index - 1].level == LEVEL_DURATION_LEVEL_HIGH) {
|
||||
instance->encoder.upload[index - 1].duration *= 2; // 11
|
||||
instance->encoder.upload[index++] = level_duration_make(
|
||||
false, (uint32_t)subghz_protocol_somfy_keytis_const.te_short); // 0
|
||||
} else {
|
||||
instance->encoder.upload[index++] = level_duration_make(
|
||||
true, (uint32_t)subghz_protocol_somfy_keytis_const.te_short); // 1
|
||||
instance->encoder.upload[index++] = level_duration_make(
|
||||
false, (uint32_t)subghz_protocol_somfy_keytis_const.te_short); // 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for(uint8_t i = 24; i > 0; i--) {
|
||||
if(bit_read(instance->generic.data_2, i - 1)) {
|
||||
if(instance->encoder.upload[index - 1].level == LEVEL_DURATION_LEVEL_LOW) {
|
||||
instance->encoder.upload[index - 1].duration *= 2; // 00
|
||||
instance->encoder.upload[index++] = level_duration_make(
|
||||
true, (uint32_t)subghz_protocol_somfy_keytis_const.te_short); // 1
|
||||
} else {
|
||||
instance->encoder.upload[index++] = level_duration_make(
|
||||
false, (uint32_t)subghz_protocol_somfy_keytis_const.te_short); // 0
|
||||
instance->encoder.upload[index++] = level_duration_make(
|
||||
true, (uint32_t)subghz_protocol_somfy_keytis_const.te_short); // 1
|
||||
}
|
||||
|
||||
} else {
|
||||
if(instance->encoder.upload[index - 1].level == LEVEL_DURATION_LEVEL_HIGH) {
|
||||
instance->encoder.upload[index - 1].duration *= 2; // 11
|
||||
instance->encoder.upload[index++] = level_duration_make(
|
||||
false, (uint32_t)subghz_protocol_somfy_keytis_const.te_short); // 0
|
||||
} else {
|
||||
instance->encoder.upload[index++] = level_duration_make(
|
||||
true, (uint32_t)subghz_protocol_somfy_keytis_const.te_short); // 1
|
||||
instance->encoder.upload[index++] = level_duration_make(
|
||||
false, (uint32_t)subghz_protocol_somfy_keytis_const.te_short); // 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Inter-frame silence
|
||||
if(instance->encoder.upload[index - 1].level == LEVEL_DURATION_LEVEL_LOW) {
|
||||
instance->encoder.upload[index - 1].duration +=
|
||||
(uint32_t)subghz_protocol_somfy_keytis_const.te_short * 3;
|
||||
} else {
|
||||
instance->encoder.upload[index++] =
|
||||
level_duration_make(false, (uint32_t)subghz_protocol_somfy_keytis_const.te_short * 3);
|
||||
}
|
||||
|
||||
for(uint8_t i = 0; i < 2; ++i) {
|
||||
//Hardware sync
|
||||
for(uint8_t i = 0; i < 6; ++i) {
|
||||
instance->encoder.upload[index++] = level_duration_make(
|
||||
true, (uint32_t)subghz_protocol_somfy_keytis_const.te_short * 4); // 1
|
||||
instance->encoder.upload[index++] = level_duration_make(
|
||||
false, (uint32_t)subghz_protocol_somfy_keytis_const.te_short * 4); // 0
|
||||
}
|
||||
//Software sync
|
||||
instance->encoder.upload[index++] = level_duration_make(true, (uint32_t)4550); // 1
|
||||
instance->encoder.upload[index++] =
|
||||
level_duration_make(false, (uint32_t)subghz_protocol_somfy_keytis_const.te_short); // 0
|
||||
|
||||
//Send key data MSB manchester
|
||||
|
||||
for(uint8_t i = instance->generic.data_count_bit - 24; i > 0; i--) {
|
||||
if(bit_read(instance->generic.data, i - 1)) {
|
||||
if(instance->encoder.upload[index - 1].level == LEVEL_DURATION_LEVEL_LOW) {
|
||||
instance->encoder.upload[index - 1].duration *= 2; // 00
|
||||
instance->encoder.upload[index++] = level_duration_make(
|
||||
true, (uint32_t)subghz_protocol_somfy_keytis_const.te_short); // 1
|
||||
} else {
|
||||
instance->encoder.upload[index++] = level_duration_make(
|
||||
false, (uint32_t)subghz_protocol_somfy_keytis_const.te_short); // 0
|
||||
instance->encoder.upload[index++] = level_duration_make(
|
||||
true, (uint32_t)subghz_protocol_somfy_keytis_const.te_short); // 1
|
||||
}
|
||||
|
||||
} else {
|
||||
if(instance->encoder.upload[index - 1].level == LEVEL_DURATION_LEVEL_HIGH) {
|
||||
instance->encoder.upload[index - 1].duration *= 2; // 11
|
||||
instance->encoder.upload[index++] = level_duration_make(
|
||||
false, (uint32_t)subghz_protocol_somfy_keytis_const.te_short); // 0
|
||||
} else {
|
||||
instance->encoder.upload[index++] = level_duration_make(
|
||||
true, (uint32_t)subghz_protocol_somfy_keytis_const.te_short); // 1
|
||||
instance->encoder.upload[index++] = level_duration_make(
|
||||
false, (uint32_t)subghz_protocol_somfy_keytis_const.te_short); // 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for(uint8_t i = 24; i > 0; i--) {
|
||||
if(bit_read(instance->generic.data_2, i - 1)) {
|
||||
if(instance->encoder.upload[index - 1].level == LEVEL_DURATION_LEVEL_LOW) {
|
||||
instance->encoder.upload[index - 1].duration *= 2; // 00
|
||||
instance->encoder.upload[index++] = level_duration_make(
|
||||
true, (uint32_t)subghz_protocol_somfy_keytis_const.te_short); // 1
|
||||
} else {
|
||||
instance->encoder.upload[index++] = level_duration_make(
|
||||
false, (uint32_t)subghz_protocol_somfy_keytis_const.te_short); // 0
|
||||
instance->encoder.upload[index++] = level_duration_make(
|
||||
true, (uint32_t)subghz_protocol_somfy_keytis_const.te_short); // 1
|
||||
}
|
||||
|
||||
} else {
|
||||
if(instance->encoder.upload[index - 1].level == LEVEL_DURATION_LEVEL_HIGH) {
|
||||
instance->encoder.upload[index - 1].duration *= 2; // 11
|
||||
instance->encoder.upload[index++] = level_duration_make(
|
||||
false, (uint32_t)subghz_protocol_somfy_keytis_const.te_short); // 0
|
||||
} else {
|
||||
instance->encoder.upload[index++] = level_duration_make(
|
||||
true, (uint32_t)subghz_protocol_somfy_keytis_const.te_short); // 1
|
||||
instance->encoder.upload[index++] = level_duration_make(
|
||||
false, (uint32_t)subghz_protocol_somfy_keytis_const.te_short); // 0
|
||||
}
|
||||
}
|
||||
}
|
||||
//Inter-frame silence
|
||||
if(instance->encoder.upload[index - 1].level == LEVEL_DURATION_LEVEL_LOW) {
|
||||
instance->encoder.upload[index - 1].duration +=
|
||||
(uint32_t)subghz_protocol_somfy_keytis_const.te_short * 3;
|
||||
} else {
|
||||
instance->encoder.upload[index++] = level_duration_make(
|
||||
false, (uint32_t)subghz_protocol_somfy_keytis_const.te_short * 3);
|
||||
}
|
||||
}
|
||||
|
||||
//Inter-frame silence
|
||||
instance->encoder.upload[index - 1].duration +=
|
||||
(uint32_t)30415 - (uint32_t)subghz_protocol_somfy_keytis_const.te_short * 3;
|
||||
|
||||
size_t size_upload = index;
|
||||
|
||||
if(size_upload > instance->encoder.size_upload) {
|
||||
FURI_LOG_E(TAG, "Size upload exceeds allocated encoder buffer.");
|
||||
return false;
|
||||
} else {
|
||||
instance->encoder.size_upload = size_upload;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool subghz_protocol_encoder_somfy_keytis_deserialize(void* context, FlipperFormat* flipper_format) {
|
||||
furi_assert(context);
|
||||
SubGhzProtocolEncoderSomfyKeytis* instance = context;
|
||||
bool res = false;
|
||||
do {
|
||||
if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) {
|
||||
FURI_LOG_E(TAG, "Deserialize error");
|
||||
break;
|
||||
}
|
||||
|
||||
//optional parameter parameter
|
||||
flipper_format_read_uint32(
|
||||
flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1);
|
||||
|
||||
subghz_protocol_encoder_somfy_keytis_get_upload(instance, instance->generic.btn);
|
||||
|
||||
if(!flipper_format_rewind(flipper_format)) {
|
||||
FURI_LOG_E(TAG, "Rewind error");
|
||||
break;
|
||||
}
|
||||
uint8_t key_data[sizeof(uint64_t)] = {0};
|
||||
for(size_t i = 0; i < sizeof(uint64_t); i++) {
|
||||
key_data[sizeof(uint64_t) - i - 1] = (instance->generic.data >> i * 8) & 0xFF;
|
||||
}
|
||||
if(!flipper_format_update_hex(flipper_format, "Key", key_data, sizeof(uint64_t))) {
|
||||
FURI_LOG_E(TAG, "Unable to add Key");
|
||||
break;
|
||||
}
|
||||
|
||||
instance->encoder.is_running = true;
|
||||
|
||||
res = true;
|
||||
} while(false);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
void subghz_protocol_encoder_somfy_keytis_stop(void* context) {
|
||||
SubGhzProtocolEncoderSomfyKeytis* instance = context;
|
||||
instance->encoder.is_running = false;
|
||||
}
|
||||
|
||||
LevelDuration subghz_protocol_encoder_somfy_keytis_yield(void* context) {
|
||||
SubGhzProtocolEncoderSomfyKeytis* instance = context;
|
||||
|
||||
if(instance->encoder.repeat == 0 || !instance->encoder.is_running) {
|
||||
instance->encoder.is_running = false;
|
||||
return level_duration_reset();
|
||||
}
|
||||
|
||||
LevelDuration ret = instance->encoder.upload[instance->encoder.front];
|
||||
|
||||
if(++instance->encoder.front == instance->encoder.size_upload) {
|
||||
instance->encoder.repeat--;
|
||||
instance->encoder.front = 0;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Сhecksum calculation.
|
||||
* @param data Вata for checksum calculation
|
||||
|
||||
@@ -11,6 +11,58 @@ extern const SubGhzProtocolDecoder subghz_protocol_somfy_keytis_decoder;
|
||||
extern const SubGhzProtocolEncoder subghz_protocol_somfy_keytis_encoder;
|
||||
extern const SubGhzProtocol subghz_protocol_somfy_keytis;
|
||||
|
||||
/**
|
||||
* Allocate SubGhzProtocolEncoderSomfyKeytis.
|
||||
* @param environment Pointer to a SubGhzEnvironment instance
|
||||
* @return SubGhzProtocolEncoderSomfyKeytis* pointer to a SubGhzProtocolEncoderSomfyKeytis instance
|
||||
*/
|
||||
void* subghz_protocol_encoder_somfy_keytis_alloc(SubGhzEnvironment* environment);
|
||||
|
||||
/**
|
||||
* Free SubGhzProtocolEncoderSomfyKeytis.
|
||||
* @param context Pointer to a SubGhzProtocolEncoderSomfyKeytis instance
|
||||
*/
|
||||
void subghz_protocol_encoder_somfy_keytis_free(void* context);
|
||||
|
||||
/**
|
||||
* Key generation from simple data.
|
||||
* @param context Pointer to a SubGhzProtocolEncoderSomfyKeytis instance
|
||||
* @param flipper_format Pointer to a FlipperFormat instance
|
||||
* @param serial Serial number, 24 bit
|
||||
* @param btn Button number, 8 bit
|
||||
* @param cnt Counter value, 16 bit
|
||||
* @param preset Modulation, SubGhzRadioPreset
|
||||
* @return true On success
|
||||
*/
|
||||
bool subghz_protocol_somfy_keytis_create_data(
|
||||
void* context,
|
||||
FlipperFormat* flipper_format,
|
||||
uint32_t serial,
|
||||
uint8_t btn,
|
||||
uint16_t cnt,
|
||||
SubGhzRadioPreset* preset);
|
||||
|
||||
/**
|
||||
* Deserialize and generating an upload to send.
|
||||
* @param context Pointer to a SubGhzProtocolEncoderSomfyKeytis instance
|
||||
* @param flipper_format Pointer to a FlipperFormat instance
|
||||
* @return true On success
|
||||
*/
|
||||
bool subghz_protocol_encoder_somfy_keytis_deserialize(void* context, FlipperFormat* flipper_format);
|
||||
|
||||
/**
|
||||
* Forced transmission stop.
|
||||
* @param context Pointer to a SubGhzProtocolEncoderSomfyKeytis instance
|
||||
*/
|
||||
void subghz_protocol_encoder_somfy_keytis_stop(void* context);
|
||||
|
||||
/**
|
||||
* Getting the level and duration of the upload to be loaded into DMA.
|
||||
* @param context Pointer to a SubGhzProtocolEncoderSomfyKeytis instance
|
||||
* @return LevelDuration
|
||||
*/
|
||||
LevelDuration subghz_protocol_encoder_somfy_keytis_yield(void* context);
|
||||
|
||||
/**
|
||||
* Allocate SubGhzProtocolDecoderSomfyKeytis.
|
||||
* @param environment Pointer to a SubGhzEnvironment instance
|
||||
|
||||
@@ -222,7 +222,12 @@ static bool subghz_protocol_encoder_somfy_telis_get_upload(
|
||||
}
|
||||
|
||||
//Inter-frame silence
|
||||
instance->encoder.upload[index++] = level_duration_make(false, 30415);
|
||||
if(instance->encoder.upload[index - 1].level == LEVEL_DURATION_LEVEL_LOW) {
|
||||
instance->encoder.upload[index - 1].duration += (uint32_t)30415;
|
||||
} else {
|
||||
instance->encoder.upload[index++] = level_duration_make(false, (uint32_t)30415);
|
||||
}
|
||||
|
||||
//Retransmission
|
||||
for(uint8_t i = 0; i < 2; i++) {
|
||||
//Hardware sync
|
||||
@@ -267,7 +272,11 @@ static bool subghz_protocol_encoder_somfy_telis_get_upload(
|
||||
}
|
||||
|
||||
//Inter-frame silence
|
||||
instance->encoder.upload[index++] = level_duration_make(false, 30415);
|
||||
if(instance->encoder.upload[index - 1].level == LEVEL_DURATION_LEVEL_LOW) {
|
||||
instance->encoder.upload[index - 1].duration += (uint32_t)30415;
|
||||
} else {
|
||||
instance->encoder.upload[index++] = level_duration_make(false, (uint32_t)30415);
|
||||
}
|
||||
}
|
||||
|
||||
size_t size_upload = index;
|
||||
|
||||
@@ -76,10 +76,10 @@ static const uint32_t subghz_frequency_list[] = {
|
||||
};
|
||||
|
||||
static const uint32_t subghz_hopper_frequency_list[] = {
|
||||
310000000,
|
||||
315000000,
|
||||
318000000,
|
||||
330000000,
|
||||
390000000,
|
||||
433420000,
|
||||
433920000,
|
||||
868350000,
|
||||
0,
|
||||
|
||||
Reference in New Issue
Block a user