SubGhz: support for custom frequencies for SubGhz (#1108)
* SubGhz: add load setting * SubGhz: add support file upload with custom frequencies * SubGhz: add load region setting * SubGhz: fix syntax * SubGhz: fix furi_halt error * Desktop: hide dolphin controls in production build * Notification: fix crash on NotificationMessageTypeLedDisplayUnlock message Co-authored-by: あく <alleteam@gmail.com>
This commit is contained in:
		
							parent
							
								
									8cc3fd579c
								
							
						
					
					
						commit
						a5cc3453c8
					
				@ -114,14 +114,8 @@ bool desktop_debug_input(InputEvent* event, void* context) {
 | 
			
		||||
    DesktopViewStatsScreens current = 0;
 | 
			
		||||
    with_view_model(
 | 
			
		||||
        debug_view->view, (DesktopDebugViewModel * model) {
 | 
			
		||||
#if SRV_DOLPHIN_STATE_DEBUG == 1
 | 
			
		||||
            if(event->key == InputKeyDown) {
 | 
			
		||||
                model->screen = (model->screen + 1) % DesktopViewStatsTotalCount;
 | 
			
		||||
            } else if(event->key == InputKeyUp) {
 | 
			
		||||
                model->screen = ((model->screen - 1) + DesktopViewStatsTotalCount) %
 | 
			
		||||
                                DesktopViewStatsTotalCount;
 | 
			
		||||
            }
 | 
			
		||||
#else
 | 
			
		||||
 | 
			
		||||
#ifdef SRV_DOLPHIN_STATE_DEBUG
 | 
			
		||||
            if((event->key == InputKeyDown) || (event->key == InputKeyUp)) {
 | 
			
		||||
                model->screen = !model->screen;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
@ -164,7 +164,6 @@ void notification_process_notification_message(
 | 
			
		||||
    notification_message = (*message->sequence)[notification_message_index];
 | 
			
		||||
 | 
			
		||||
    bool led_active = false;
 | 
			
		||||
    uint8_t display_led_lock = 0;
 | 
			
		||||
    uint8_t led_values[NOTIFICATION_LED_COUNT] = {0x00, 0x00, 0x00};
 | 
			
		||||
    bool reset_notifications = true;
 | 
			
		||||
    float speaker_volume_setting = app->settings.speaker_volume;
 | 
			
		||||
@ -192,18 +191,18 @@ void notification_process_notification_message(
 | 
			
		||||
            reset_mask |= reset_display_mask;
 | 
			
		||||
            break;
 | 
			
		||||
        case NotificationMessageTypeLedDisplayLock:
 | 
			
		||||
            furi_assert(display_led_lock < UINT8_MAX);
 | 
			
		||||
            display_led_lock++;
 | 
			
		||||
            if(display_led_lock == 1) {
 | 
			
		||||
            furi_assert(app->display_led_lock < UINT8_MAX);
 | 
			
		||||
            app->display_led_lock++;
 | 
			
		||||
            if(app->display_led_lock == 1) {
 | 
			
		||||
                notification_apply_internal_led_layer(
 | 
			
		||||
                    &app->display,
 | 
			
		||||
                    notification_message->data.led.value * display_brightness_setting);
 | 
			
		||||
            }
 | 
			
		||||
            break;
 | 
			
		||||
        case NotificationMessageTypeLedDisplayUnlock:
 | 
			
		||||
            furi_assert(display_led_lock > 0);
 | 
			
		||||
            display_led_lock--;
 | 
			
		||||
            if(display_led_lock == 0) {
 | 
			
		||||
            furi_assert(app->display_led_lock > 0);
 | 
			
		||||
            app->display_led_lock--;
 | 
			
		||||
            if(app->display_led_lock == 0) {
 | 
			
		||||
                notification_apply_internal_led_layer(
 | 
			
		||||
                    &app->display,
 | 
			
		||||
                    notification_message->data.led.value * display_brightness_setting);
 | 
			
		||||
 | 
			
		||||
@ -49,6 +49,7 @@ struct NotificationApp {
 | 
			
		||||
 | 
			
		||||
    NotificationLedLayer display;
 | 
			
		||||
    NotificationLedLayer led[NOTIFICATION_LED_COUNT];
 | 
			
		||||
    uint8_t display_led_lock;
 | 
			
		||||
 | 
			
		||||
    NotificationSettings settings;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@ -29,6 +29,7 @@ struct SubGhzFrequencyAnalyzerWorker {
 | 
			
		||||
    volatile bool worker_running;
 | 
			
		||||
    uint8_t count_repet;
 | 
			
		||||
    FrequencyRSSI frequency_rssi_buf;
 | 
			
		||||
    SubGhzSetting* setting;
 | 
			
		||||
 | 
			
		||||
    float filVal;
 | 
			
		||||
 | 
			
		||||
@ -77,10 +78,12 @@ static int32_t subghz_frequency_analyzer_worker_thread(void* context) {
 | 
			
		||||
        frequency_rssi.rssi = -127.0f;
 | 
			
		||||
        furi_hal_subghz_idle();
 | 
			
		||||
        furi_hal_subghz_load_registers(subghz_preset_ook_650khz);
 | 
			
		||||
        for(size_t i = 0; i < subghz_frequencies_count; i++) {
 | 
			
		||||
            if(furi_hal_subghz_is_frequency_valid(subghz_frequencies[i])) {
 | 
			
		||||
        for(size_t i = 0; i < subghz_setting_get_frequency_count(instance->setting); i++) {
 | 
			
		||||
            if(furi_hal_subghz_is_frequency_valid(
 | 
			
		||||
                   subghz_setting_get_frequency(instance->setting, i))) {
 | 
			
		||||
                furi_hal_subghz_idle();
 | 
			
		||||
                frequency = furi_hal_subghz_set_frequency(subghz_frequencies[i]);
 | 
			
		||||
                frequency = furi_hal_subghz_set_frequency(
 | 
			
		||||
                    subghz_setting_get_frequency(instance->setting, i));
 | 
			
		||||
                furi_hal_subghz_rx();
 | 
			
		||||
                osDelay(3);
 | 
			
		||||
                rssi = furi_hal_subghz_get_rssi();
 | 
			
		||||
@ -150,6 +153,8 @@ SubGhzFrequencyAnalyzerWorker* subghz_frequency_analyzer_worker_alloc() {
 | 
			
		||||
    furi_thread_set_context(instance->thread, instance);
 | 
			
		||||
    furi_thread_set_callback(instance->thread, subghz_frequency_analyzer_worker_thread);
 | 
			
		||||
 | 
			
		||||
    instance->setting = subghz_setting_alloc();
 | 
			
		||||
    subghz_setting_load(instance->setting, "/ext/subghz/assets/setting_frequency_analyzer_user");
 | 
			
		||||
    return instance;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -157,7 +162,7 @@ void subghz_frequency_analyzer_worker_free(SubGhzFrequencyAnalyzerWorker* instan
 | 
			
		||||
    furi_assert(instance);
 | 
			
		||||
 | 
			
		||||
    furi_thread_free(instance->thread);
 | 
			
		||||
 | 
			
		||||
    subghz_setting_free(instance->setting);
 | 
			
		||||
    free(instance);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -127,7 +127,8 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) {
 | 
			
		||||
                scene_manager_next_scene(subghz->scene_manager, SubGhzSceneNeedSaving);
 | 
			
		||||
            } else {
 | 
			
		||||
                //Restore default setting
 | 
			
		||||
                subghz->txrx->frequency = subghz_frequencies[subghz_frequencies_433_92];
 | 
			
		||||
                subghz->txrx->frequency = subghz_setting_get_frequency(
 | 
			
		||||
                    subghz->setting, subghz_setting_get_frequency_default_index(subghz->setting));
 | 
			
		||||
                subghz->txrx->preset = FuriHalSubGhzPresetOok650Async;
 | 
			
		||||
                if(!scene_manager_search_and_switch_to_previous_scene(
 | 
			
		||||
                       subghz->scene_manager, SubGhzSceneSaved)) {
 | 
			
		||||
 | 
			
		||||
@ -120,7 +120,8 @@ bool subghz_scene_receiver_on_event(void* context, SceneManagerEvent event) {
 | 
			
		||||
                subghz_sleep(subghz);
 | 
			
		||||
            };
 | 
			
		||||
            subghz->txrx->hopper_state = SubGhzHopperStateOFF;
 | 
			
		||||
            subghz->txrx->frequency = subghz_frequencies[subghz_frequencies_433_92];
 | 
			
		||||
            subghz->txrx->frequency = subghz_setting_get_frequency(
 | 
			
		||||
                subghz->setting, subghz_setting_get_frequency_default_index(subghz->setting));
 | 
			
		||||
            subghz->txrx->preset = FuriHalSubGhzPresetOok650Async;
 | 
			
		||||
            subghz->txrx->idx_menu_chosen = 0;
 | 
			
		||||
            subghz_receiver_set_rx_callback(subghz->txrx->receiver, NULL, subghz);
 | 
			
		||||
 | 
			
		||||
@ -40,6 +40,21 @@ uint8_t subghz_scene_receiver_config_uint32_value_index(
 | 
			
		||||
    return index;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
uint8_t subghz_scene_receiver_config_next_frequency(const uint32_t value, void* context) {
 | 
			
		||||
    furi_assert(context);
 | 
			
		||||
    SubGhz* subghz = context;
 | 
			
		||||
    int64_t last_value = INT64_MIN;
 | 
			
		||||
    uint8_t index = 0;
 | 
			
		||||
    for(uint8_t i = 0; i < subghz_setting_get_frequency_count(subghz->setting); i++) {
 | 
			
		||||
        if((value >= last_value) && (value <= subghz_setting_get_frequency(subghz->setting, i))) {
 | 
			
		||||
            index = i;
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
        last_value = subghz_setting_get_frequency(subghz->setting, i);
 | 
			
		||||
    }
 | 
			
		||||
    return index;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
uint8_t subghz_scene_receiver_config_hopper_value_index(
 | 
			
		||||
    const uint32_t value,
 | 
			
		||||
    const uint32_t values[],
 | 
			
		||||
@ -64,10 +79,17 @@ static void subghz_scene_receiver_config_set_frequency(VariableItem* item) {
 | 
			
		||||
    uint8_t index = variable_item_get_current_value_index(item);
 | 
			
		||||
 | 
			
		||||
    if(subghz->txrx->hopper_state == SubGhzHopperStateOFF) {
 | 
			
		||||
        variable_item_set_current_value_text(item, subghz_frequencies_text[index]);
 | 
			
		||||
        subghz->txrx->frequency = subghz_frequencies[index];
 | 
			
		||||
        char text_buf[10] = {0};
 | 
			
		||||
        sprintf(
 | 
			
		||||
            text_buf,
 | 
			
		||||
            "%lu.%02lu",
 | 
			
		||||
            subghz_setting_get_frequency(subghz->setting, index) / 1000000,
 | 
			
		||||
            (subghz_setting_get_frequency(subghz->setting, index) % 1000000) / 10000);
 | 
			
		||||
        variable_item_set_current_value_text(item, text_buf);
 | 
			
		||||
        subghz->txrx->frequency = subghz_setting_get_frequency(subghz->setting, index);
 | 
			
		||||
    } else {
 | 
			
		||||
        variable_item_set_current_value_index(item, subghz_frequencies_433_92);
 | 
			
		||||
        variable_item_set_current_value_index(
 | 
			
		||||
            item, subghz_setting_get_frequency_default_index(subghz->setting));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -85,15 +107,27 @@ static void subghz_scene_receiver_config_set_hopping_runing(VariableItem* item)
 | 
			
		||||
 | 
			
		||||
    variable_item_set_current_value_text(item, hopping_text[index]);
 | 
			
		||||
    if(hopping_value[index] == SubGhzHopperStateOFF) {
 | 
			
		||||
        char text_buf[10] = {0};
 | 
			
		||||
        sprintf(
 | 
			
		||||
            text_buf,
 | 
			
		||||
            "%lu.%02lu",
 | 
			
		||||
            subghz_setting_get_frequency(
 | 
			
		||||
                subghz->setting, subghz_setting_get_frequency_default_index(subghz->setting)) /
 | 
			
		||||
                1000000,
 | 
			
		||||
            (subghz_setting_get_frequency(
 | 
			
		||||
                 subghz->setting, subghz_setting_get_frequency_default_index(subghz->setting)) %
 | 
			
		||||
             1000000) /
 | 
			
		||||
                10000);
 | 
			
		||||
        variable_item_set_current_value_text(
 | 
			
		||||
            (VariableItem*)scene_manager_get_scene_state(
 | 
			
		||||
                subghz->scene_manager, SubGhzSceneReceiverConfig),
 | 
			
		||||
            subghz_frequencies_text[subghz_frequencies_433_92]);
 | 
			
		||||
        subghz->txrx->frequency = subghz_frequencies[subghz_frequencies_433_92];
 | 
			
		||||
            text_buf);
 | 
			
		||||
        subghz->txrx->frequency = subghz_setting_get_frequency(
 | 
			
		||||
            subghz->setting, subghz_setting_get_frequency_default_index(subghz->setting));
 | 
			
		||||
        variable_item_set_current_value_index(
 | 
			
		||||
            (VariableItem*)scene_manager_get_scene_state(
 | 
			
		||||
                subghz->scene_manager, SubGhzSceneReceiverConfig),
 | 
			
		||||
            subghz_frequencies_433_92);
 | 
			
		||||
            subghz_setting_get_frequency_default_index(subghz->setting));
 | 
			
		||||
    } else {
 | 
			
		||||
        variable_item_set_current_value_text(
 | 
			
		||||
            (VariableItem*)scene_manager_get_scene_state(
 | 
			
		||||
@ -102,7 +136,7 @@ static void subghz_scene_receiver_config_set_hopping_runing(VariableItem* item)
 | 
			
		||||
        variable_item_set_current_value_index(
 | 
			
		||||
            (VariableItem*)scene_manager_get_scene_state(
 | 
			
		||||
                subghz->scene_manager, SubGhzSceneReceiverConfig),
 | 
			
		||||
            subghz_frequencies_433_92);
 | 
			
		||||
            subghz_setting_get_frequency_default_index(subghz->setting));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    subghz->txrx->hopper_state = hopping_value[index];
 | 
			
		||||
@ -116,15 +150,20 @@ void subghz_scene_receiver_config_on_enter(void* context) {
 | 
			
		||||
    item = variable_item_list_add(
 | 
			
		||||
        subghz->variable_item_list,
 | 
			
		||||
        "Frequency:",
 | 
			
		||||
        subghz_frequencies_count,
 | 
			
		||||
        subghz_setting_get_frequency_count(subghz->setting),
 | 
			
		||||
        subghz_scene_receiver_config_set_frequency,
 | 
			
		||||
        subghz);
 | 
			
		||||
    value_index = subghz_scene_receiver_config_uint32_value_index(
 | 
			
		||||
        subghz->txrx->frequency, subghz_frequencies, subghz_frequencies_count);
 | 
			
		||||
    value_index = subghz_scene_receiver_config_next_frequency(subghz->txrx->frequency, subghz);
 | 
			
		||||
    scene_manager_set_scene_state(
 | 
			
		||||
        subghz->scene_manager, SubGhzSceneReceiverConfig, (uint32_t)item);
 | 
			
		||||
    variable_item_set_current_value_index(item, value_index);
 | 
			
		||||
    variable_item_set_current_value_text(item, subghz_frequencies_text[value_index]);
 | 
			
		||||
    char text_buf[10] = {0};
 | 
			
		||||
    sprintf(
 | 
			
		||||
        text_buf,
 | 
			
		||||
        "%lu.%02lu",
 | 
			
		||||
        subghz_setting_get_frequency(subghz->setting, value_index) / 1000000,
 | 
			
		||||
        (subghz_setting_get_frequency(subghz->setting, value_index) % 1000000) / 10000);
 | 
			
		||||
    variable_item_set_current_value_text(item, text_buf);
 | 
			
		||||
 | 
			
		||||
    if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneReadRAW) !=
 | 
			
		||||
       SubGhzCustomEventManagerSet) {
 | 
			
		||||
 | 
			
		||||
@ -46,7 +46,7 @@ bool subghz_scene_set_type_submenu_gen_data_protocol(
 | 
			
		||||
        if(!subghz_protocol_decoder_base_serialize(
 | 
			
		||||
               subghz->txrx->decoder_result,
 | 
			
		||||
               subghz->txrx->fff_data,
 | 
			
		||||
               subghz_frequencies[subghz_frequencies_433_92],
 | 
			
		||||
               subghz_setting_get_frequency_default_index(subghz->setting),
 | 
			
		||||
               FuriHalSubGhzPresetOok650Async)) {
 | 
			
		||||
            FURI_LOG_E(TAG, "Unable to serialize");
 | 
			
		||||
            break;
 | 
			
		||||
@ -213,7 +213,7 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) {
 | 
			
		||||
                    0x2,
 | 
			
		||||
                    0x0003,
 | 
			
		||||
                    "DoorHan",
 | 
			
		||||
                    subghz_frequencies[subghz_frequencies_433_92],
 | 
			
		||||
                    subghz_setting_get_frequency_default_index(subghz->setting),
 | 
			
		||||
                    FuriHalSubGhzPresetOok650Async);
 | 
			
		||||
                generated_protocol = true;
 | 
			
		||||
            } else {
 | 
			
		||||
@ -237,7 +237,7 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) {
 | 
			
		||||
                    0x2,
 | 
			
		||||
                    0x0003,
 | 
			
		||||
                    "DoorHan",
 | 
			
		||||
                    subghz_frequencies[subghz_frequencies_315_00],
 | 
			
		||||
                    315000000,
 | 
			
		||||
                    FuriHalSubGhzPresetOok650Async);
 | 
			
		||||
                generated_protocol = true;
 | 
			
		||||
            } else {
 | 
			
		||||
 | 
			
		||||
@ -3,68 +3,6 @@
 | 
			
		||||
#include "subghz_i.h"
 | 
			
		||||
#include <lib/toolbox/path.h>
 | 
			
		||||
 | 
			
		||||
const char* const subghz_frequencies_text[] = {
 | 
			
		||||
 | 
			
		||||
    "300.00",
 | 
			
		||||
    "303.88",
 | 
			
		||||
    "304.25",
 | 
			
		||||
    "315.00",
 | 
			
		||||
    "318.00",
 | 
			
		||||
 | 
			
		||||
    "390.00",
 | 
			
		||||
    "418.00",
 | 
			
		||||
    "433.08",
 | 
			
		||||
    "433.42",
 | 
			
		||||
    "433.92",
 | 
			
		||||
    "434.42",
 | 
			
		||||
    "434.78",
 | 
			
		||||
    "438.90",
 | 
			
		||||
 | 
			
		||||
    "868.35",
 | 
			
		||||
    "915.00",
 | 
			
		||||
    "925.00",
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const uint32_t subghz_frequencies[] = {
 | 
			
		||||
 | 
			
		||||
    /* 300 - 348 */
 | 
			
		||||
    300000000,
 | 
			
		||||
    303875000,
 | 
			
		||||
    304250000,
 | 
			
		||||
    315000000,
 | 
			
		||||
    318000000,
 | 
			
		||||
 | 
			
		||||
    /* 387 - 464 */
 | 
			
		||||
    390000000,
 | 
			
		||||
    418000000,
 | 
			
		||||
    433075000, /* LPD433 first */
 | 
			
		||||
    433420000,
 | 
			
		||||
    433920000, /* LPD433 mid */
 | 
			
		||||
    434420000,
 | 
			
		||||
    434775000, /* LPD433 last channels */
 | 
			
		||||
    438900000,
 | 
			
		||||
 | 
			
		||||
    /* 779 - 928 */
 | 
			
		||||
    868350000,
 | 
			
		||||
    915000000,
 | 
			
		||||
    925000000,
 | 
			
		||||
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const uint32_t subghz_hopper_frequencies[] = {
 | 
			
		||||
    315000000,
 | 
			
		||||
    318000000,
 | 
			
		||||
    390000000,
 | 
			
		||||
    433920000,
 | 
			
		||||
    868350000,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const uint32_t subghz_frequencies_count = sizeof(subghz_frequencies) / sizeof(uint32_t);
 | 
			
		||||
const uint32_t subghz_hopper_frequencies_count =
 | 
			
		||||
    sizeof(subghz_hopper_frequencies) / sizeof(uint32_t);
 | 
			
		||||
const uint32_t subghz_frequencies_433_92 = 9;
 | 
			
		||||
const uint32_t subghz_frequencies_315_00 = 3;
 | 
			
		||||
 | 
			
		||||
bool subghz_custom_event_callback(void* context, uint32_t event) {
 | 
			
		||||
    furi_assert(context);
 | 
			
		||||
    SubGhz* subghz = context;
 | 
			
		||||
@ -186,9 +124,14 @@ SubGhz* subghz_alloc() {
 | 
			
		||||
        SubGhzViewIdStatic,
 | 
			
		||||
        subghz_test_static_get_view(subghz->subghz_test_static));
 | 
			
		||||
 | 
			
		||||
    //init setting
 | 
			
		||||
    subghz->setting = subghz_setting_alloc();
 | 
			
		||||
    subghz_setting_load(subghz->setting, "/ext/subghz/assets/setting_user");
 | 
			
		||||
 | 
			
		||||
    //init Worker & Protocol & History
 | 
			
		||||
    subghz->txrx = malloc(sizeof(SubGhzTxRx));
 | 
			
		||||
    subghz->txrx->frequency = subghz_frequencies[subghz_frequencies_433_92];
 | 
			
		||||
    subghz->txrx->frequency = subghz_setting_get_frequency(
 | 
			
		||||
        subghz->setting, subghz_setting_get_frequency_default_index(subghz->setting));
 | 
			
		||||
    subghz->txrx->preset = FuriHalSubGhzPresetOok650Async;
 | 
			
		||||
    subghz->txrx->txrx_state = SubGhzTxRxStateSleep;
 | 
			
		||||
    subghz->txrx->hopper_state = SubGhzHopperStateOFF;
 | 
			
		||||
@ -281,6 +224,9 @@ void subghz_free(SubGhz* subghz) {
 | 
			
		||||
    furi_record_close("gui");
 | 
			
		||||
    subghz->gui = NULL;
 | 
			
		||||
 | 
			
		||||
    //setting
 | 
			
		||||
    subghz_setting_free(subghz->setting);
 | 
			
		||||
 | 
			
		||||
    //Worker & Protocol & History
 | 
			
		||||
    subghz_receiver_free(subghz->txrx->receiver);
 | 
			
		||||
    subghz_environment_free(subghz->txrx->environment);
 | 
			
		||||
 | 
			
		||||
@ -514,9 +514,9 @@ void subghz_hopper_update(SubGhz* subghz) {
 | 
			
		||||
    } else {
 | 
			
		||||
        subghz->txrx->hopper_state = SubGhzHopperStateRunnig;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Select next frequency
 | 
			
		||||
    if(subghz->txrx->hopper_idx_frequency < subghz_hopper_frequencies_count - 1) {
 | 
			
		||||
    if(subghz->txrx->hopper_idx_frequency <
 | 
			
		||||
       subghz_setting_get_hopper_frequency_count(subghz->setting) - 1) {
 | 
			
		||||
        subghz->txrx->hopper_idx_frequency++;
 | 
			
		||||
    } else {
 | 
			
		||||
        subghz->txrx->hopper_idx_frequency = 0;
 | 
			
		||||
@ -527,7 +527,8 @@ void subghz_hopper_update(SubGhz* subghz) {
 | 
			
		||||
    };
 | 
			
		||||
    if(subghz->txrx->txrx_state == SubGhzTxRxStateIDLE) {
 | 
			
		||||
        subghz_receiver_reset(subghz->txrx->receiver);
 | 
			
		||||
        subghz->txrx->frequency = subghz_hopper_frequencies[subghz->txrx->hopper_idx_frequency];
 | 
			
		||||
        subghz->txrx->frequency = subghz_setting_get_hopper_frequency(
 | 
			
		||||
            subghz->setting, subghz->txrx->hopper_idx_frequency);
 | 
			
		||||
        subghz_rx(subghz, subghz->txrx->frequency);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -30,19 +30,12 @@
 | 
			
		||||
#include <lib/subghz/transmitter.h>
 | 
			
		||||
 | 
			
		||||
#include "subghz_history.h"
 | 
			
		||||
#include "subghz_setting.h"
 | 
			
		||||
 | 
			
		||||
#include <gui/modules/variable_item_list.h>
 | 
			
		||||
 | 
			
		||||
#define SUBGHZ_MAX_LEN_NAME 40
 | 
			
		||||
 | 
			
		||||
extern const char* const subghz_frequencies_text[];
 | 
			
		||||
extern const uint32_t subghz_frequencies[];
 | 
			
		||||
extern const uint32_t subghz_hopper_frequencies[];
 | 
			
		||||
extern const uint32_t subghz_frequencies_count;
 | 
			
		||||
extern const uint32_t subghz_hopper_frequencies_count;
 | 
			
		||||
extern const uint32_t subghz_frequencies_433_92;
 | 
			
		||||
extern const uint32_t subghz_frequencies_315_00;
 | 
			
		||||
 | 
			
		||||
/** SubGhzNotification state */
 | 
			
		||||
typedef enum {
 | 
			
		||||
    SubGhzNotificationStateStarting,
 | 
			
		||||
@ -137,6 +130,7 @@ struct SubGhz {
 | 
			
		||||
    SubGhzTestCarrier* subghz_test_carrier;
 | 
			
		||||
    SubGhzTestPacket* subghz_test_packet;
 | 
			
		||||
    string_t error_str;
 | 
			
		||||
    SubGhzSetting* setting;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
typedef enum {
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										361
									
								
								applications/subghz/subghz_setting.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										361
									
								
								applications/subghz/subghz_setting.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,361 @@
 | 
			
		||||
#include "subghz_setting.h"
 | 
			
		||||
#include "subghz_i.h"
 | 
			
		||||
 | 
			
		||||
#include <furi.h>
 | 
			
		||||
#include <m-list.h>
 | 
			
		||||
#include <lib/flipper_format/flipper_format.h>
 | 
			
		||||
 | 
			
		||||
#define TAG "SubGhzSetting"
 | 
			
		||||
 | 
			
		||||
#define SUBGHZ_SETTING_FILE_VERSION 1
 | 
			
		||||
#define SUBGHZ_SETTING_FILE_TYPE "Flipper SubGhz Setting File"
 | 
			
		||||
 | 
			
		||||
typedef enum {
 | 
			
		||||
    SubGhzSettingStateNoLoad = 0,
 | 
			
		||||
    SubGhzSettingStateLoadFrequencyDefault,
 | 
			
		||||
    SubGhzSettingStateOkLoad,
 | 
			
		||||
} SubGhzSettingState;
 | 
			
		||||
 | 
			
		||||
static const uint32_t subghz_frequencies[] = {
 | 
			
		||||
    /* 300 - 348 */
 | 
			
		||||
    300000000,
 | 
			
		||||
    303875000,
 | 
			
		||||
    304250000,
 | 
			
		||||
    315000000,
 | 
			
		||||
    318000000,
 | 
			
		||||
 | 
			
		||||
    /* 387 - 464 */
 | 
			
		||||
    390000000,
 | 
			
		||||
    418000000,
 | 
			
		||||
    433075000, /* LPD433 first */
 | 
			
		||||
    433420000,
 | 
			
		||||
    433920000, /* LPD433 mid */
 | 
			
		||||
    434420000,
 | 
			
		||||
    434775000, /* LPD433 last channels */
 | 
			
		||||
    438900000,
 | 
			
		||||
 | 
			
		||||
    /* 779 - 928 */
 | 
			
		||||
    868350000,
 | 
			
		||||
    915000000,
 | 
			
		||||
    925000000,
 | 
			
		||||
    0,
 | 
			
		||||
};
 | 
			
		||||
static const uint32_t subghz_hopper_frequencies[] = {
 | 
			
		||||
    315000000,
 | 
			
		||||
    318000000,
 | 
			
		||||
    390000000,
 | 
			
		||||
    433920000,
 | 
			
		||||
    868350000,
 | 
			
		||||
    0,
 | 
			
		||||
};
 | 
			
		||||
static const uint32_t subghz_frequency_default_index = 9;
 | 
			
		||||
 | 
			
		||||
static const uint32_t subghz_frequencies_region_eu_ru[] = {
 | 
			
		||||
    /* 300 - 348 */
 | 
			
		||||
    300000000,
 | 
			
		||||
    303875000,
 | 
			
		||||
    304250000,
 | 
			
		||||
    315000000,
 | 
			
		||||
    318000000,
 | 
			
		||||
 | 
			
		||||
    /* 387 - 464 */
 | 
			
		||||
    390000000,
 | 
			
		||||
    418000000,
 | 
			
		||||
    433075000, /* LPD433 first */
 | 
			
		||||
    433420000,
 | 
			
		||||
    433920000, /* LPD433 mid */
 | 
			
		||||
    434420000,
 | 
			
		||||
    434775000, /* LPD433 last channels */
 | 
			
		||||
    438900000,
 | 
			
		||||
 | 
			
		||||
    /* 779 - 928 */
 | 
			
		||||
    868350000,
 | 
			
		||||
    915000000,
 | 
			
		||||
    925000000,
 | 
			
		||||
    0,
 | 
			
		||||
};
 | 
			
		||||
static const uint32_t subghz_hopper_frequencies_region_eu_ru[] = {
 | 
			
		||||
    315000000,
 | 
			
		||||
    318000000,
 | 
			
		||||
    390000000,
 | 
			
		||||
    433920000,
 | 
			
		||||
    868350000,
 | 
			
		||||
    0,
 | 
			
		||||
};
 | 
			
		||||
static const uint32_t subghz_frequency_default_index_region_eu_ru = 9;
 | 
			
		||||
 | 
			
		||||
static const uint32_t subghz_frequencies_region_us_ca_au[] = {
 | 
			
		||||
    /* 300 - 348 */
 | 
			
		||||
    300000000,
 | 
			
		||||
    303875000,
 | 
			
		||||
    304250000,
 | 
			
		||||
    315000000,
 | 
			
		||||
    318000000,
 | 
			
		||||
 | 
			
		||||
    /* 387 - 464 */
 | 
			
		||||
    390000000,
 | 
			
		||||
    418000000,
 | 
			
		||||
    433075000, /* LPD433 first */
 | 
			
		||||
    433420000,
 | 
			
		||||
    433920000, /* LPD433 mid */
 | 
			
		||||
    434420000,
 | 
			
		||||
    434775000, /* LPD433 last channels */
 | 
			
		||||
    438900000,
 | 
			
		||||
 | 
			
		||||
    /* 779 - 928 */
 | 
			
		||||
    868350000,
 | 
			
		||||
    915000000,
 | 
			
		||||
    925000000,
 | 
			
		||||
    0,
 | 
			
		||||
};
 | 
			
		||||
static const uint32_t subghz_hopper_frequencies_region_us_ca_au[] = {
 | 
			
		||||
    315000000,
 | 
			
		||||
    318000000,
 | 
			
		||||
    390000000,
 | 
			
		||||
    433920000,
 | 
			
		||||
    868350000,
 | 
			
		||||
    0,
 | 
			
		||||
};
 | 
			
		||||
static const uint32_t subghz_frequency_default_index_region_us_ca_au = 9;
 | 
			
		||||
 | 
			
		||||
static const uint32_t subghz_frequencies_region_jp[] = {
 | 
			
		||||
    /* 300 - 348 */
 | 
			
		||||
    300000000,
 | 
			
		||||
    303875000,
 | 
			
		||||
    304250000,
 | 
			
		||||
    315000000,
 | 
			
		||||
    318000000,
 | 
			
		||||
 | 
			
		||||
    /* 387 - 464 */
 | 
			
		||||
    390000000,
 | 
			
		||||
    418000000,
 | 
			
		||||
    433075000, /* LPD433 first */
 | 
			
		||||
    433420000,
 | 
			
		||||
    433920000, /* LPD433 mid */
 | 
			
		||||
    434420000,
 | 
			
		||||
    434775000, /* LPD433 last channels */
 | 
			
		||||
    438900000,
 | 
			
		||||
 | 
			
		||||
    /* 779 - 928 */
 | 
			
		||||
    868350000,
 | 
			
		||||
    915000000,
 | 
			
		||||
    925000000,
 | 
			
		||||
    0,
 | 
			
		||||
};
 | 
			
		||||
static const uint32_t subghz_hopper_frequencies_region_jp[] = {
 | 
			
		||||
    315000000,
 | 
			
		||||
    318000000,
 | 
			
		||||
    390000000,
 | 
			
		||||
    433920000,
 | 
			
		||||
    868350000,
 | 
			
		||||
    0,
 | 
			
		||||
};
 | 
			
		||||
static const uint32_t subghz_frequency_default_index_region_jp = 9;
 | 
			
		||||
 | 
			
		||||
LIST_DEF(frequencies_list, uint32_t)
 | 
			
		||||
LIST_DEF(hopper_frequencies_list, uint32_t)
 | 
			
		||||
 | 
			
		||||
struct SubGhzSetting {
 | 
			
		||||
    frequencies_list_t frequencies;
 | 
			
		||||
    hopper_frequencies_list_t hopper_frequencies;
 | 
			
		||||
    size_t frequencies_count;
 | 
			
		||||
    size_t hopper_frequencies_count;
 | 
			
		||||
    uint32_t frequency_default_index;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
SubGhzSetting* subghz_setting_alloc(void) {
 | 
			
		||||
    SubGhzSetting* instance = malloc(sizeof(SubGhzSetting));
 | 
			
		||||
    frequencies_list_init(instance->frequencies);
 | 
			
		||||
    hopper_frequencies_list_init(instance->hopper_frequencies);
 | 
			
		||||
    return instance;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void subghz_setting_free(SubGhzSetting* instance) {
 | 
			
		||||
    furi_assert(instance);
 | 
			
		||||
    frequencies_list_clear(instance->frequencies);
 | 
			
		||||
    hopper_frequencies_list_clear(instance->hopper_frequencies);
 | 
			
		||||
    free(instance);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void subghz_setting_load_default(
 | 
			
		||||
    SubGhzSetting* instance,
 | 
			
		||||
    const uint32_t frequencies[],
 | 
			
		||||
    const uint32_t hopper_frequencies[],
 | 
			
		||||
    const uint32_t frequency_default_index) {
 | 
			
		||||
    furi_assert(instance);
 | 
			
		||||
    size_t i = 0;
 | 
			
		||||
    frequencies_list_clear(instance->frequencies);
 | 
			
		||||
    hopper_frequencies_list_clear(instance->hopper_frequencies);
 | 
			
		||||
    i = 0;
 | 
			
		||||
    while(frequencies[i]) {
 | 
			
		||||
        frequencies_list_push_back(instance->frequencies, frequencies[i]);
 | 
			
		||||
        i++;
 | 
			
		||||
    }
 | 
			
		||||
    instance->frequencies_count = i;
 | 
			
		||||
 | 
			
		||||
    i = 0;
 | 
			
		||||
    while(hopper_frequencies[i]) {
 | 
			
		||||
        hopper_frequencies_list_push_back(instance->hopper_frequencies, hopper_frequencies[i]);
 | 
			
		||||
        i++;
 | 
			
		||||
    }
 | 
			
		||||
    instance->hopper_frequencies_count = i;
 | 
			
		||||
 | 
			
		||||
    instance->frequency_default_index = frequency_default_index;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void subghz_setting_load(SubGhzSetting* instance, const char* file_path) {
 | 
			
		||||
    furi_assert(instance);
 | 
			
		||||
 | 
			
		||||
    frequencies_list_clear(instance->frequencies);
 | 
			
		||||
    hopper_frequencies_list_clear(instance->hopper_frequencies);
 | 
			
		||||
 | 
			
		||||
    Storage* storage = furi_record_open("storage");
 | 
			
		||||
    FlipperFormat* fff_data_file = flipper_format_file_alloc(storage);
 | 
			
		||||
 | 
			
		||||
    string_t temp_str;
 | 
			
		||||
    string_init(temp_str);
 | 
			
		||||
    uint32_t temp_data32;
 | 
			
		||||
    SubGhzSettingState loading = SubGhzSettingStateNoLoad;
 | 
			
		||||
    uint16_t i = 0;
 | 
			
		||||
 | 
			
		||||
    if(file_path) {
 | 
			
		||||
        do {
 | 
			
		||||
            if(!flipper_format_file_open_existing(fff_data_file, file_path)) {
 | 
			
		||||
                FURI_LOG_E(TAG, "Error open file %s", file_path);
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if(!flipper_format_read_header(fff_data_file, temp_str, &temp_data32)) {
 | 
			
		||||
                FURI_LOG_E(TAG, "Missing or incorrect header");
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if((!strcmp(string_get_cstr(temp_str), SUBGHZ_SETTING_FILE_TYPE)) &&
 | 
			
		||||
               temp_data32 == SUBGHZ_SETTING_FILE_VERSION) {
 | 
			
		||||
            } else {
 | 
			
		||||
                FURI_LOG_E(TAG, "Type or version mismatch");
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if(!flipper_format_rewind(fff_data_file)) {
 | 
			
		||||
                FURI_LOG_E(TAG, "Rewind error");
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
            i = 0;
 | 
			
		||||
            while(flipper_format_read_uint32(
 | 
			
		||||
                fff_data_file, "Frequency", (uint32_t*)&temp_data32, 1)) {
 | 
			
		||||
                if(furi_hal_subghz_is_frequency_valid(temp_data32)) {
 | 
			
		||||
                    FURI_LOG_I(TAG, "Frequency loaded %lu", temp_data32);
 | 
			
		||||
                    frequencies_list_push_back(instance->frequencies, temp_data32);
 | 
			
		||||
                    i++;
 | 
			
		||||
                } else {
 | 
			
		||||
                    FURI_LOG_E(TAG, "Frequency not supported %lu", temp_data32);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            instance->frequencies_count = i;
 | 
			
		||||
 | 
			
		||||
            if(!flipper_format_rewind(fff_data_file)) {
 | 
			
		||||
                FURI_LOG_E(TAG, "Rewind error");
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
            i = 0;
 | 
			
		||||
            while(flipper_format_read_uint32(
 | 
			
		||||
                fff_data_file, "Hopper_frequency", (uint32_t*)&temp_data32, 1)) {
 | 
			
		||||
                if(furi_hal_subghz_is_frequency_valid(temp_data32)) {
 | 
			
		||||
                    FURI_LOG_I(TAG, "Hopper frequency loaded %lu", temp_data32);
 | 
			
		||||
                    hopper_frequencies_list_push_back(instance->hopper_frequencies, temp_data32);
 | 
			
		||||
                    i++;
 | 
			
		||||
                } else {
 | 
			
		||||
                    FURI_LOG_E(TAG, "Hopper frequency not supported %lu", temp_data32);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            instance->hopper_frequencies_count = i;
 | 
			
		||||
 | 
			
		||||
            if(!flipper_format_rewind(fff_data_file)) {
 | 
			
		||||
                FURI_LOG_E(TAG, "Rewind error");
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
            if(!flipper_format_read_uint32(
 | 
			
		||||
                   fff_data_file, "Frequency_default", (uint32_t*)&temp_data32, 1)) {
 | 
			
		||||
                FURI_LOG_E(TAG, "Frequency default missing");
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            for(i = 0; i < instance->frequencies_count; i++) {
 | 
			
		||||
                if(subghz_setting_get_frequency(instance, i) == temp_data32) {
 | 
			
		||||
                    instance->frequency_default_index = i;
 | 
			
		||||
                    FURI_LOG_I(TAG, "Frequency default index %lu", i);
 | 
			
		||||
                    loading = SubGhzSettingStateLoadFrequencyDefault;
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if(loading == SubGhzSettingStateLoadFrequencyDefault) {
 | 
			
		||||
                loading = SubGhzSettingStateOkLoad;
 | 
			
		||||
            } else {
 | 
			
		||||
                FURI_LOG_E(TAG, "Frequency default index missing");
 | 
			
		||||
            }
 | 
			
		||||
        } while(false);
 | 
			
		||||
    }
 | 
			
		||||
    flipper_format_free(fff_data_file);
 | 
			
		||||
    furi_record_close("storage");
 | 
			
		||||
 | 
			
		||||
    if(loading != SubGhzSettingStateOkLoad) {
 | 
			
		||||
        switch(furi_hal_version_get_hw_region()) {
 | 
			
		||||
        case FuriHalVersionRegionEuRu:
 | 
			
		||||
            subghz_setting_load_default(
 | 
			
		||||
                instance,
 | 
			
		||||
                subghz_frequencies_region_eu_ru,
 | 
			
		||||
                subghz_hopper_frequencies_region_eu_ru,
 | 
			
		||||
                subghz_frequency_default_index_region_eu_ru);
 | 
			
		||||
            break;
 | 
			
		||||
        case FuriHalVersionRegionUsCaAu:
 | 
			
		||||
            subghz_setting_load_default(
 | 
			
		||||
                instance,
 | 
			
		||||
                subghz_frequencies_region_us_ca_au,
 | 
			
		||||
                subghz_hopper_frequencies_region_us_ca_au,
 | 
			
		||||
                subghz_frequency_default_index_region_us_ca_au);
 | 
			
		||||
            break;
 | 
			
		||||
        case FuriHalVersionRegionJp:
 | 
			
		||||
            subghz_setting_load_default(
 | 
			
		||||
                instance,
 | 
			
		||||
                subghz_frequencies_region_jp,
 | 
			
		||||
                subghz_hopper_frequencies_region_jp,
 | 
			
		||||
                subghz_frequency_default_index_region_jp);
 | 
			
		||||
            break;
 | 
			
		||||
 | 
			
		||||
        default:
 | 
			
		||||
            subghz_setting_load_default(
 | 
			
		||||
                instance,
 | 
			
		||||
                subghz_frequencies,
 | 
			
		||||
                subghz_hopper_frequencies,
 | 
			
		||||
                subghz_frequency_default_index);
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
size_t subghz_setting_get_frequency_count(SubGhzSetting* instance) {
 | 
			
		||||
    furi_assert(instance);
 | 
			
		||||
    return instance->frequencies_count;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
size_t subghz_setting_get_hopper_frequency_count(SubGhzSetting* instance) {
 | 
			
		||||
    furi_assert(instance);
 | 
			
		||||
    return instance->hopper_frequencies_count;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
uint32_t subghz_setting_get_frequency(SubGhzSetting* instance, size_t idx) {
 | 
			
		||||
    furi_assert(instance);
 | 
			
		||||
    return *frequencies_list_get(instance->frequencies, idx);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
uint32_t subghz_setting_get_hopper_frequency(SubGhzSetting* instance, size_t idx) {
 | 
			
		||||
    furi_assert(instance);
 | 
			
		||||
    return *hopper_frequencies_list_get(instance->hopper_frequencies, idx);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
uint32_t subghz_setting_get_frequency_default_index(SubGhzSetting* instance) {
 | 
			
		||||
    furi_assert(instance);
 | 
			
		||||
    return instance->frequency_default_index;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										17
									
								
								applications/subghz/subghz_setting.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								applications/subghz/subghz_setting.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,17 @@
 | 
			
		||||
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <math.h>
 | 
			
		||||
#include <furi.h>
 | 
			
		||||
#include <furi_hal.h>
 | 
			
		||||
 | 
			
		||||
typedef struct SubGhzSetting SubGhzSetting;
 | 
			
		||||
 | 
			
		||||
SubGhzSetting* subghz_setting_alloc(void);
 | 
			
		||||
void subghz_setting_free(SubGhzSetting* instance);
 | 
			
		||||
void subghz_setting_load(SubGhzSetting* instance, const char* file_path);
 | 
			
		||||
size_t subghz_setting_get_frequency_count(SubGhzSetting* instance);
 | 
			
		||||
size_t subghz_setting_get_hopper_frequency_count(SubGhzSetting* instance);
 | 
			
		||||
uint32_t subghz_setting_get_frequency(SubGhzSetting* instance, size_t idx);
 | 
			
		||||
uint32_t subghz_setting_get_hopper_frequency(SubGhzSetting* instance, size_t idx);
 | 
			
		||||
uint32_t subghz_setting_get_frequency_default_index(SubGhzSetting* instance);
 | 
			
		||||
@ -0,0 +1,19 @@
 | 
			
		||||
Filetype: Flipper SubGhz Setting File
 | 
			
		||||
Version: 1
 | 
			
		||||
Frequency_default: 433920000
 | 
			
		||||
Frequency: 300000000
 | 
			
		||||
Frequency: 303875000
 | 
			
		||||
Frequency: 304250000
 | 
			
		||||
Frequency: 315000000
 | 
			
		||||
Frequency: 318000000
 | 
			
		||||
Frequency: 390000000
 | 
			
		||||
Frequency: 418000000
 | 
			
		||||
Frequency: 433075000
 | 
			
		||||
Frequency: 433420000
 | 
			
		||||
Frequency: 433920000
 | 
			
		||||
Frequency: 434420000
 | 
			
		||||
Frequency: 434775000
 | 
			
		||||
Frequency: 438900000
 | 
			
		||||
Frequency: 868350000
 | 
			
		||||
Frequency: 915000000
 | 
			
		||||
Frequency: 925000000
 | 
			
		||||
							
								
								
									
										24
									
								
								assets/resources/subghz/assets/setting_user
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								assets/resources/subghz/assets/setting_user
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,24 @@
 | 
			
		||||
Filetype: Flipper SubGhz Setting File
 | 
			
		||||
Version: 1
 | 
			
		||||
Frequency_default: 433920000
 | 
			
		||||
Frequency: 300000000
 | 
			
		||||
Frequency: 303875000
 | 
			
		||||
Frequency: 304250000
 | 
			
		||||
Frequency: 315000000
 | 
			
		||||
Frequency: 318000000
 | 
			
		||||
Frequency: 390000000
 | 
			
		||||
Frequency: 418000000
 | 
			
		||||
Frequency: 433075000
 | 
			
		||||
Frequency: 433420000
 | 
			
		||||
Frequency: 433920000
 | 
			
		||||
Frequency: 434420000
 | 
			
		||||
Frequency: 434775000
 | 
			
		||||
Frequency: 438900000
 | 
			
		||||
Frequency: 868350000
 | 
			
		||||
Frequency: 915000000
 | 
			
		||||
Frequency: 925000000
 | 
			
		||||
Hopper_frequency: 315000000
 | 
			
		||||
Hopper_frequency: 318000000
 | 
			
		||||
Hopper_frequency: 390000000
 | 
			
		||||
Hopper_frequency: 433920000
 | 
			
		||||
Hopper_frequency: 868350000
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user