Signal send demo - Aug 22, 2023 session
This commit is contained in:
parent
568f74348f
commit
26104939ab
25
subghz/apps/signal_send_demo/README.md
Normal file
25
subghz/apps/signal_send_demo/README.md
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
# start_here
|
||||||
|
You can use this application as a starting point for creating your own application. We updated it to send some Sub-GHz signals.
|
||||||
|
|
||||||
|
# Overview
|
||||||
|
This application has the following submenu items:
|
||||||
|
* Config
|
||||||
|
* Send Princeton
|
||||||
|
* Send Nice FLO
|
||||||
|
* Flip the world
|
||||||
|
* About
|
||||||
|
|
||||||
|
# Config
|
||||||
|
The "Config" menu item currently has 1 setting. You can modify the menu to contain multiple settings if needed.
|
||||||
|
|
||||||
|
# Send Princeton
|
||||||
|
This sends a Princeton signal with a hard-coded SN+Button. The app.c file sets the value with ``send_princeton(0x967AB4, freq);`` It currently is the same as this [princeton.sub](./princeton.sub) file.
|
||||||
|
|
||||||
|
# Send Nice FLO
|
||||||
|
This sends a Nice FLO signal with a hard-coded value. The app.c file sets the value with ``send_nice_flo(0xDA1, freq);`` It currently is the same as this [nice_flo.sub](./nice_flo.sub) file.
|
||||||
|
|
||||||
|
# Flip the world
|
||||||
|
The "Flip the world" is where you would put your primary application. It currently just renders the UI. The back button goes back to the main menu.
|
||||||
|
|
||||||
|
# About
|
||||||
|
The "About" menu item contains information about your application, so people know what to do with it & how to contact you.
|
290
subghz/apps/signal_send_demo/app.c
Normal file
290
subghz/apps/signal_send_demo/app.c
Normal file
@ -0,0 +1,290 @@
|
|||||||
|
#include <furi.h>
|
||||||
|
#include <furi_hal.h>
|
||||||
|
#include <gui/gui.h>
|
||||||
|
#include <gui/view.h>
|
||||||
|
#include <gui/view_dispatcher.h>
|
||||||
|
#include <gui/modules/submenu.h>
|
||||||
|
#include <gui/modules/widget.h>
|
||||||
|
#include <gui/modules/variable_item_list.h>
|
||||||
|
#include <notification/notification.h>
|
||||||
|
#include <notification/notification_messages.h>
|
||||||
|
#include "my_app_aug_22_2023_icons.h"
|
||||||
|
|
||||||
|
#include "./tag.h"
|
||||||
|
#include "./princeton.h"
|
||||||
|
#include "./nice_flo.h"
|
||||||
|
|
||||||
|
// Comment this line if you don't want the backlight to be continuously on.
|
||||||
|
#define BACKLIGHT_ALWAYS_ON yep
|
||||||
|
|
||||||
|
uint32_t setting_1_values[] = {315000000, 433920000, 915000000};
|
||||||
|
char* setting_1_names[] = {"315.00", "433.92", "915.00"};
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
MyAppSubmenuIndexConfigure,
|
||||||
|
MyAppSubmenuIndexSendPricetonSignal,
|
||||||
|
MyAppSubmenuIndexSendNiceFloSignal,
|
||||||
|
MyAppSubmenuIndexFlipTheWorld,
|
||||||
|
MyAppSubmenuIndexAbout,
|
||||||
|
} MyAppSubmenuIndex;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
MyAppViewSubmenu,
|
||||||
|
MyAppViewConfigure,
|
||||||
|
MyAppViewSendSignal,
|
||||||
|
MyAppViewFlipTheWorld,
|
||||||
|
MyAppViewAbout,
|
||||||
|
} MyAppView;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint32_t setting_1_index;
|
||||||
|
} MyModel;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
ViewDispatcher* view_dispatcher;
|
||||||
|
NotificationApp* notifications;
|
||||||
|
Submenu* submenu;
|
||||||
|
VariableItemList* variable_item_list_config;
|
||||||
|
View* view_flip_the_world;
|
||||||
|
Widget* widget_about;
|
||||||
|
Widget* widget_send_signal;
|
||||||
|
MyModel* model;
|
||||||
|
} MyApp;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Callback for navigation events
|
||||||
|
* @details This function is called when user press back button. We return VIEW_NONE to
|
||||||
|
* indicate that we want to exit the application.
|
||||||
|
* @param context The context
|
||||||
|
* @return next view id
|
||||||
|
*/
|
||||||
|
static uint32_t my_app_navigation_exit_callback(void* context) {
|
||||||
|
UNUSED(context);
|
||||||
|
return VIEW_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Callback for navigation events
|
||||||
|
* @details This function is called when user press back button. We return VIEW_NONE to
|
||||||
|
* indicate that we want to exit the application.
|
||||||
|
* @param context The context
|
||||||
|
* @return next view id
|
||||||
|
*/
|
||||||
|
static uint32_t my_app_navigation_submenu_callback(void* context) {
|
||||||
|
UNUSED(context);
|
||||||
|
return MyAppViewSubmenu;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Callback for most of the submenu events (About, Configure, etc.)
|
||||||
|
* @details This function is called when user press a submenu item. We switch to the
|
||||||
|
* appropriate view.
|
||||||
|
* @param context The context
|
||||||
|
* @param[in] index The index of the menu item.
|
||||||
|
*/
|
||||||
|
static void my_app_submenu_callback(void* context, uint32_t index) {
|
||||||
|
MyApp* app = (MyApp*)context;
|
||||||
|
|
||||||
|
switch(index) {
|
||||||
|
case MyAppSubmenuIndexConfigure:
|
||||||
|
view_dispatcher_switch_to_view(app->view_dispatcher, MyAppViewConfigure);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MyAppSubmenuIndexFlipTheWorld: {
|
||||||
|
// Copy our model data to the view.
|
||||||
|
MyModel* model = view_get_model(app->view_flip_the_world);
|
||||||
|
model->setting_1_index = app->model->setting_1_index;
|
||||||
|
|
||||||
|
view_dispatcher_switch_to_view(app->view_dispatcher, MyAppViewFlipTheWorld);
|
||||||
|
} break;
|
||||||
|
case MyAppSubmenuIndexAbout:
|
||||||
|
view_dispatcher_switch_to_view(app->view_dispatcher, MyAppViewAbout);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
FURI_LOG_E(TAG, "Unknown submenu index %lu", index);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Callback for submenu events that send a signal
|
||||||
|
* @details This function is called when user press a submenu item. We send the signal,
|
||||||
|
* show a "sending signal" screen, and then switch back to the submenu.
|
||||||
|
* @param context The context
|
||||||
|
* @param[in] index The index of the menu item.
|
||||||
|
*/
|
||||||
|
static void my_app_submenu_send_signal_callback(void* context, uint32_t index) {
|
||||||
|
MyApp* app = (MyApp*)context;
|
||||||
|
uint32_t freq = setting_1_values[app->model->setting_1_index];
|
||||||
|
|
||||||
|
// Show a "sending signal" screen while we send the signal.
|
||||||
|
view_dispatcher_switch_to_view(app->view_dispatcher, MyAppViewSendSignal);
|
||||||
|
|
||||||
|
switch(index) {
|
||||||
|
case MyAppSubmenuIndexSendPricetonSignal: {
|
||||||
|
// Send Princeton signal
|
||||||
|
send_princeton(0x967AB4, freq);
|
||||||
|
} break;
|
||||||
|
case MyAppSubmenuIndexSendNiceFloSignal: {
|
||||||
|
// Send Nice FLO signal
|
||||||
|
send_nice_flo(0xDA1, freq);
|
||||||
|
} break;
|
||||||
|
default:
|
||||||
|
FURI_LOG_E(TAG, "Unknown submenu index %lu", index);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Small delay of a few milliseconds so people can read the screen, before we switch back.
|
||||||
|
furi_delay_ms(400);
|
||||||
|
view_dispatcher_switch_to_view(app->view_dispatcher, MyAppViewSubmenu);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void my_app_setting_1_change(VariableItem* item) {
|
||||||
|
MyApp* app = variable_item_get_context(item);
|
||||||
|
uint8_t index = variable_item_get_current_value_index(item);
|
||||||
|
variable_item_set_current_value_text(item, setting_1_names[index]);
|
||||||
|
MyModel* model = app->model;
|
||||||
|
model->setting_1_index = index;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void my_app_view_draw_callback(Canvas* canvas, void* model) {
|
||||||
|
MyModel* my_model = (MyModel*)model;
|
||||||
|
canvas_draw_str(canvas, 25, 15, "FLIP THE WORLD!!!");
|
||||||
|
canvas_draw_icon(canvas, 64, 32, &I_glyph_1_7x9);
|
||||||
|
canvas_draw_str(canvas, 64, 60, setting_1_names[my_model->setting_1_index]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool my_app_view_input_callback(InputEvent* event, void* context) {
|
||||||
|
UNUSED(context);
|
||||||
|
UNUSED(event);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static MyApp* my_app_alloc() {
|
||||||
|
MyApp* app = (MyApp*)malloc(sizeof(MyApp));
|
||||||
|
|
||||||
|
Gui* gui = furi_record_open(RECORD_GUI);
|
||||||
|
|
||||||
|
app->model = (MyModel*)malloc(sizeof(MyModel));
|
||||||
|
app->model->setting_1_index = 0;
|
||||||
|
|
||||||
|
app->view_dispatcher = view_dispatcher_alloc();
|
||||||
|
view_dispatcher_enable_queue(app->view_dispatcher);
|
||||||
|
view_dispatcher_attach_to_gui(app->view_dispatcher, gui, ViewDispatcherTypeFullscreen);
|
||||||
|
|
||||||
|
app->submenu = submenu_alloc();
|
||||||
|
submenu_set_header(app->submenu, "Signal Send Demo");
|
||||||
|
submenu_add_item(
|
||||||
|
app->submenu, "Config", MyAppSubmenuIndexConfigure, my_app_submenu_callback, app);
|
||||||
|
submenu_add_item(
|
||||||
|
app->submenu,
|
||||||
|
"Send Princeton",
|
||||||
|
MyAppSubmenuIndexSendPricetonSignal,
|
||||||
|
my_app_submenu_send_signal_callback,
|
||||||
|
app);
|
||||||
|
submenu_add_item(
|
||||||
|
app->submenu,
|
||||||
|
"Send Nice FLO",
|
||||||
|
MyAppSubmenuIndexSendNiceFloSignal,
|
||||||
|
my_app_submenu_send_signal_callback,
|
||||||
|
app);
|
||||||
|
submenu_add_item(
|
||||||
|
app->submenu,
|
||||||
|
"Flip the world",
|
||||||
|
MyAppSubmenuIndexFlipTheWorld,
|
||||||
|
my_app_submenu_callback,
|
||||||
|
app);
|
||||||
|
submenu_add_item(app->submenu, "About", MyAppSubmenuIndexAbout, my_app_submenu_callback, app);
|
||||||
|
view_set_previous_callback(submenu_get_view(app->submenu), my_app_navigation_exit_callback);
|
||||||
|
view_dispatcher_add_view(
|
||||||
|
app->view_dispatcher, MyAppViewSubmenu, submenu_get_view(app->submenu));
|
||||||
|
view_dispatcher_switch_to_view(app->view_dispatcher, MyAppViewSubmenu);
|
||||||
|
|
||||||
|
app->variable_item_list_config = variable_item_list_alloc();
|
||||||
|
variable_item_list_reset(app->variable_item_list_config);
|
||||||
|
VariableItem* item = variable_item_list_add(
|
||||||
|
app->variable_item_list_config,
|
||||||
|
"Frequency",
|
||||||
|
COUNT_OF(setting_1_values),
|
||||||
|
my_app_setting_1_change,
|
||||||
|
app);
|
||||||
|
uint8_t setting_1_index = 1;
|
||||||
|
variable_item_set_current_value_index(item, setting_1_index);
|
||||||
|
variable_item_set_current_value_text(item, setting_1_names[setting_1_index]);
|
||||||
|
view_set_previous_callback(
|
||||||
|
variable_item_list_get_view(app->variable_item_list_config),
|
||||||
|
my_app_navigation_submenu_callback);
|
||||||
|
view_dispatcher_add_view(
|
||||||
|
app->view_dispatcher,
|
||||||
|
MyAppViewConfigure,
|
||||||
|
variable_item_list_get_view(app->variable_item_list_config));
|
||||||
|
|
||||||
|
app->view_flip_the_world = view_alloc();
|
||||||
|
view_set_draw_callback(app->view_flip_the_world, my_app_view_draw_callback);
|
||||||
|
view_set_input_callback(app->view_flip_the_world, my_app_view_input_callback);
|
||||||
|
view_set_previous_callback(app->view_flip_the_world, my_app_navigation_submenu_callback);
|
||||||
|
view_allocate_model(app->view_flip_the_world, ViewModelTypeLockFree, sizeof(MyModel));
|
||||||
|
|
||||||
|
MyModel* model = app->model;
|
||||||
|
model->setting_1_index = setting_1_index;
|
||||||
|
view_dispatcher_add_view(
|
||||||
|
app->view_dispatcher, MyAppViewFlipTheWorld, app->view_flip_the_world);
|
||||||
|
|
||||||
|
app->widget_about = widget_alloc();
|
||||||
|
widget_add_text_scroll_element(
|
||||||
|
app->widget_about,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
128,
|
||||||
|
64,
|
||||||
|
"Signal Send Demo\n---\nThis is a sample application\nthat sends some protocols.\nReplace with your code to do something interesting!\n\nauthor: @codeallnight\nhttps://discord.com/invite/NsjCvqwPAd\nhttps://youtube.com/@MrDerekJamison");
|
||||||
|
view_set_previous_callback(
|
||||||
|
widget_get_view(app->widget_about), my_app_navigation_submenu_callback);
|
||||||
|
view_dispatcher_add_view(
|
||||||
|
app->view_dispatcher, MyAppViewAbout, widget_get_view(app->widget_about));
|
||||||
|
|
||||||
|
app->widget_send_signal = widget_alloc();
|
||||||
|
widget_add_text_scroll_element(app->widget_send_signal, 0, 0, 128, 64, "Sending signal");
|
||||||
|
view_dispatcher_add_view(
|
||||||
|
app->view_dispatcher, MyAppViewSendSignal, widget_get_view(app->widget_send_signal));
|
||||||
|
|
||||||
|
app->notifications = furi_record_open(RECORD_NOTIFICATION);
|
||||||
|
|
||||||
|
#ifdef BACKLIGHT_ALWAYS_ON
|
||||||
|
notification_message(app->notifications, &sequence_display_backlight_enforce_on);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return app;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void my_app_free(MyApp* app) {
|
||||||
|
#ifdef BACKLIGHT_ALWAYS_ON
|
||||||
|
notification_message(app->notifications, &sequence_display_backlight_enforce_auto);
|
||||||
|
#endif
|
||||||
|
furi_record_close(RECORD_NOTIFICATION);
|
||||||
|
|
||||||
|
view_dispatcher_remove_view(app->view_dispatcher, MyAppViewSendSignal);
|
||||||
|
widget_free(app->widget_send_signal);
|
||||||
|
view_dispatcher_remove_view(app->view_dispatcher, MyAppViewAbout);
|
||||||
|
widget_free(app->widget_about);
|
||||||
|
view_dispatcher_remove_view(app->view_dispatcher, MyAppViewFlipTheWorld);
|
||||||
|
view_free(app->view_flip_the_world);
|
||||||
|
view_dispatcher_remove_view(app->view_dispatcher, MyAppViewConfigure);
|
||||||
|
variable_item_list_free(app->variable_item_list_config);
|
||||||
|
view_dispatcher_remove_view(app->view_dispatcher, MyAppViewSubmenu);
|
||||||
|
submenu_free(app->submenu);
|
||||||
|
view_dispatcher_free(app->view_dispatcher);
|
||||||
|
furi_record_close(RECORD_GUI);
|
||||||
|
|
||||||
|
free(app);
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t signal_send_demo_app(void* p) {
|
||||||
|
UNUSED(p);
|
||||||
|
|
||||||
|
MyApp* app = my_app_alloc();
|
||||||
|
view_dispatcher_run(app->view_dispatcher);
|
||||||
|
|
||||||
|
my_app_free(app);
|
||||||
|
return 0;
|
||||||
|
}
|
BIN
subghz/apps/signal_send_demo/app.png
Normal file
BIN
subghz/apps/signal_send_demo/app.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.5 KiB |
15
subghz/apps/signal_send_demo/application.fam
Normal file
15
subghz/apps/signal_send_demo/application.fam
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
App(
|
||||||
|
appid="my_app_aug_22_2023",
|
||||||
|
name="Signal Send Demo",
|
||||||
|
apptype=FlipperAppType.EXTERNAL,
|
||||||
|
entry_point="signal_send_demo_app",
|
||||||
|
stack_size=4 * 1024,
|
||||||
|
requires=[
|
||||||
|
"gui",
|
||||||
|
"subghz",
|
||||||
|
],
|
||||||
|
order=10,
|
||||||
|
fap_icon="app.png",
|
||||||
|
fap_category="Sub-GHz",
|
||||||
|
fap_icon_assets="assets",
|
||||||
|
)
|
BIN
subghz/apps/signal_send_demo/assets/glyph_1_7x9.png
Normal file
BIN
subghz/apps/signal_send_demo/assets/glyph_1_7x9.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.6 KiB |
98
subghz/apps/signal_send_demo/nice_flo.c
Normal file
98
subghz/apps/signal_send_demo/nice_flo.c
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
#include "./nice_flo.h"
|
||||||
|
#include "./tag.h"
|
||||||
|
|
||||||
|
#include <lib/subghz/transmitter.h>
|
||||||
|
#include <lib/subghz/devices/cc1101_int/cc1101_int_interconnect.h>
|
||||||
|
//#include <applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.h>
|
||||||
|
#include <lib/subghz/protocols/protocol_items.h>
|
||||||
|
#include <lib/subghz/devices/devices.h>
|
||||||
|
|
||||||
|
static void set_nice_flo(FlipperFormat* flipper_format, uint32_t key, uint32_t repeat) {
|
||||||
|
uint32_t bits = 12;
|
||||||
|
uint8_t data[8] = {0};
|
||||||
|
data[6] = (uint8_t)((key >> 8) & 0xFFU);
|
||||||
|
data[7] = (uint8_t)(key & 0xFFU);
|
||||||
|
|
||||||
|
flipper_format_insert_or_update_string_cstr(flipper_format, "Protocol", "Princeton");
|
||||||
|
flipper_format_insert_or_update_uint32(flipper_format, "Bit", &bits, 1);
|
||||||
|
flipper_format_insert_or_update_hex(flipper_format, "Key", data, COUNT_OF(data));
|
||||||
|
flipper_format_insert_or_update_uint32(flipper_format, "Repeat", &repeat, 1);
|
||||||
|
flipper_format_rewind(flipper_format);
|
||||||
|
}
|
||||||
|
|
||||||
|
void send_nice_flo(uint32_t key, uint32_t frequency) {
|
||||||
|
// 'repeat' is the number of times to repeat the signal.
|
||||||
|
uint32_t repeat = 5;
|
||||||
|
|
||||||
|
if(!furi_hal_region_is_frequency_allowed(frequency)) {
|
||||||
|
// TODO: Show friendly UI message if frequency is not allowed.
|
||||||
|
FURI_LOG_E(TAG, "Frequency %lu is not allowed in this region.", frequency);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
FURI_LOG_I(TAG, "Sending signal on frequency %lu", frequency);
|
||||||
|
|
||||||
|
// Populate the CC101 device list.
|
||||||
|
subghz_devices_init();
|
||||||
|
|
||||||
|
// Get the internal radio device.
|
||||||
|
const SubGhzDevice* device = subghz_devices_get_by_name(SUBGHZ_DEVICE_CC1101_INT_NAME);
|
||||||
|
|
||||||
|
// Get the Nice FLO SubGhzTransmitter (for decoding our file format).
|
||||||
|
SubGhzEnvironment* environment = subghz_environment_alloc();
|
||||||
|
subghz_environment_set_protocol_registry(environment, (void*)&subghz_protocol_registry);
|
||||||
|
SubGhzTransmitter* transmitter = subghz_transmitter_alloc_init(environment, "Nice FLO");
|
||||||
|
|
||||||
|
// Load the payload we want to send into flipper_format.
|
||||||
|
FlipperFormat* flipper_format = flipper_format_string_alloc();
|
||||||
|
set_nice_flo(flipper_format, key, repeat);
|
||||||
|
|
||||||
|
// Fill out the SubGhzProtocolDecoderPrinceton (which includes SubGhzBlockGeneric data) in our transmitter based on parsing flipper_format.
|
||||||
|
// initance->encoder.upload[] gets filled out with duration and level information (You can think of this as the RAW data).
|
||||||
|
SubGhzProtocolStatus status = subghz_transmitter_deserialize(transmitter, flipper_format);
|
||||||
|
furi_assert(status == SubGhzProtocolStatusOk);
|
||||||
|
|
||||||
|
// Currently unused for internal radio, but good idea to still invoke it.
|
||||||
|
subghz_devices_begin(device);
|
||||||
|
|
||||||
|
// Initializes the CC1101 SPI bus
|
||||||
|
subghz_devices_reset(device);
|
||||||
|
|
||||||
|
// Use one of the presets in subghz_device_cc1101_int_interconnect_load_preset. If the first argument is FuriHalSubGhzPresetCustom, then the second argument is
|
||||||
|
// a custom register table (Reg, value, reg, value, ...,0, 0, PATable [0..7] entries).
|
||||||
|
subghz_devices_load_preset(device, FuriHalSubGhzPresetOok650Async, NULL);
|
||||||
|
|
||||||
|
// Set the frequency, RF switch path (band), calibrates the oscillator on the CC1101.
|
||||||
|
frequency = subghz_devices_set_frequency(device, frequency);
|
||||||
|
|
||||||
|
// Stop charging the battery while transmitting.
|
||||||
|
furi_hal_power_suppress_charge_enter();
|
||||||
|
|
||||||
|
// Start transmitting (keeps the DMA buffer filled with the encoder.upload[] data)
|
||||||
|
if(subghz_devices_start_async_tx(device, subghz_transmitter_yield, transmitter)) {
|
||||||
|
// Wait for the transmission to complete.
|
||||||
|
while(!(subghz_devices_is_async_complete_tx(device))) {
|
||||||
|
furi_delay_ms(100);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stop transmitting, debug log (tag="FuriHalSubGhz") the duty cycle information.
|
||||||
|
subghz_devices_stop_async_tx(device);
|
||||||
|
}
|
||||||
|
|
||||||
|
// clean up and shutdown cc1101
|
||||||
|
subghz_devices_sleep(device);
|
||||||
|
|
||||||
|
// also does a shutdown of cc1101
|
||||||
|
subghz_devices_end(device);
|
||||||
|
|
||||||
|
// remove the devices from the registry
|
||||||
|
subghz_devices_deinit();
|
||||||
|
|
||||||
|
// Allow the battery to charge again.
|
||||||
|
furi_hal_power_suppress_charge_exit();
|
||||||
|
|
||||||
|
// Free resources we allocated.
|
||||||
|
flipper_format_free(flipper_format);
|
||||||
|
subghz_transmitter_free(transmitter);
|
||||||
|
subghz_environment_free(environment);
|
||||||
|
}
|
4
subghz/apps/signal_send_demo/nice_flo.h
Normal file
4
subghz/apps/signal_send_demo/nice_flo.h
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <furi.h>
|
||||||
|
|
||||||
|
void send_nice_flo(uint32_t key, uint32_t frequency);
|
7
subghz/apps/signal_send_demo/nice_flo.sub
Normal file
7
subghz/apps/signal_send_demo/nice_flo.sub
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
Filetype: Flipper SubGhz Key File
|
||||||
|
Version: 1
|
||||||
|
Frequency: 433920000
|
||||||
|
Preset: FuriHalSubGhzPresetOok650Async
|
||||||
|
Protocol: Nice FLO
|
||||||
|
Bit: 12
|
||||||
|
Key: 00 00 00 00 00 00 0D A1
|
105
subghz/apps/signal_send_demo/princeton.c
Normal file
105
subghz/apps/signal_send_demo/princeton.c
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
#include "./princeton.h"
|
||||||
|
#include "./tag.h"
|
||||||
|
|
||||||
|
#include <lib/subghz/transmitter.h>
|
||||||
|
#include <lib/subghz/devices/cc1101_int/cc1101_int_interconnect.h>
|
||||||
|
//#include <applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.h>
|
||||||
|
#include <lib/subghz/protocols/protocol_items.h>
|
||||||
|
#include <lib/subghz/devices/devices.h>
|
||||||
|
|
||||||
|
static void
|
||||||
|
set_princeton(FlipperFormat* flipper_format, uint32_t key, uint32_t te, uint32_t repeat) {
|
||||||
|
uint32_t bits = 24;
|
||||||
|
uint8_t data[8] = {0};
|
||||||
|
data[5] = (uint8_t)((key >> 16) & 0xFFU);
|
||||||
|
data[6] = (uint8_t)((key >> 8) & 0xFFU);
|
||||||
|
data[7] = (uint8_t)(key & 0xFFU);
|
||||||
|
|
||||||
|
flipper_format_insert_or_update_string_cstr(flipper_format, "Protocol", "Princeton");
|
||||||
|
flipper_format_insert_or_update_uint32(flipper_format, "Bit", &bits, 1);
|
||||||
|
flipper_format_insert_or_update_hex(flipper_format, "Key", data, COUNT_OF(data));
|
||||||
|
flipper_format_insert_or_update_uint32(flipper_format, "TE", &te, 1);
|
||||||
|
flipper_format_insert_or_update_uint32(flipper_format, "Repeat", &repeat, 1);
|
||||||
|
flipper_format_rewind(flipper_format);
|
||||||
|
}
|
||||||
|
|
||||||
|
void send_princeton(uint32_t key, uint32_t frequency) {
|
||||||
|
// 'TE' is the microsecond (us) duration of the smallest pulse (effectively a bit in the BIN_RAW signal).
|
||||||
|
// NOTE: If we wanted the Princeton signal to NOT be detected by FZ we could add +300+50, but receiver might still work (values from te_short+te_delta+50 from princeton.c)
|
||||||
|
uint32_t te = 390;
|
||||||
|
|
||||||
|
// 'repeat' is the number of times to repeat the signal.
|
||||||
|
uint32_t repeat = 5;
|
||||||
|
|
||||||
|
if(!furi_hal_region_is_frequency_allowed(frequency)) {
|
||||||
|
// TODO: Show friendly UI message if frequency is not allowed.
|
||||||
|
FURI_LOG_E(TAG, "Frequency %lu is not allowed in this region.", frequency);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
FURI_LOG_I(TAG, "Sending signal on frequency %lu", frequency);
|
||||||
|
|
||||||
|
// Populate the CC101 device list.
|
||||||
|
subghz_devices_init();
|
||||||
|
|
||||||
|
// Get the internal radio device.
|
||||||
|
const SubGhzDevice* device = subghz_devices_get_by_name(SUBGHZ_DEVICE_CC1101_INT_NAME);
|
||||||
|
|
||||||
|
// Get the Princeton SubGhzTransmitter (for decoding our file format).
|
||||||
|
SubGhzEnvironment* environment = subghz_environment_alloc();
|
||||||
|
subghz_environment_set_protocol_registry(environment, (void*)&subghz_protocol_registry);
|
||||||
|
SubGhzTransmitter* transmitter = subghz_transmitter_alloc_init(environment, "Princeton");
|
||||||
|
|
||||||
|
// Load the payload we want to send into flipper_format.
|
||||||
|
FlipperFormat* flipper_format = flipper_format_string_alloc();
|
||||||
|
set_princeton(flipper_format, key, te, repeat);
|
||||||
|
|
||||||
|
// Fill out the SubGhzProtocolDecoderPrinceton (which includes SubGhzBlockGeneric data) in our transmitter based on parsing flipper_format.
|
||||||
|
// initance->encoder.upload[] gets filled out with duration and level information (You can think of this as the RAW data).
|
||||||
|
SubGhzProtocolStatus status = subghz_transmitter_deserialize(transmitter, flipper_format);
|
||||||
|
furi_assert(status == SubGhzProtocolStatusOk);
|
||||||
|
|
||||||
|
// Currently unused for internal radio, but good idea to still invoke it.
|
||||||
|
subghz_devices_begin(device);
|
||||||
|
|
||||||
|
// Initializes the CC1101 SPI bus
|
||||||
|
subghz_devices_reset(device);
|
||||||
|
|
||||||
|
// Use one of the presets in subghz_device_cc1101_int_interconnect_load_preset. If the first argument is FuriHalSubGhzPresetCustom, then the second argument is
|
||||||
|
// a custom register table (Reg, value, reg, value, ...,0, 0, PATable [0..7] entries).
|
||||||
|
subghz_devices_load_preset(device, FuriHalSubGhzPresetOok650Async, NULL);
|
||||||
|
|
||||||
|
// Set the frequency, RF switch path (band), calibrates the oscillator on the CC1101.
|
||||||
|
frequency = subghz_devices_set_frequency(device, frequency);
|
||||||
|
|
||||||
|
// Stop charging the battery while transmitting.
|
||||||
|
furi_hal_power_suppress_charge_enter();
|
||||||
|
|
||||||
|
// Start transmitting (keeps the DMA buffer filled with the encoder.upload[] data)
|
||||||
|
if(subghz_devices_start_async_tx(device, subghz_transmitter_yield, transmitter)) {
|
||||||
|
// Wait for the transmission to complete.
|
||||||
|
while(!(subghz_devices_is_async_complete_tx(device))) {
|
||||||
|
furi_delay_ms(100);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stop transmitting, debug log (tag="FuriHalSubGhz") the duty cycle information.
|
||||||
|
subghz_devices_stop_async_tx(device);
|
||||||
|
}
|
||||||
|
|
||||||
|
// clean up and shutdown cc1101
|
||||||
|
subghz_devices_sleep(device);
|
||||||
|
|
||||||
|
// also does a shutdown of cc1101
|
||||||
|
subghz_devices_end(device);
|
||||||
|
|
||||||
|
// remove the devices from the registry
|
||||||
|
subghz_devices_deinit();
|
||||||
|
|
||||||
|
// Allow the battery to charge again.
|
||||||
|
furi_hal_power_suppress_charge_exit();
|
||||||
|
|
||||||
|
// Free resources we allocated.
|
||||||
|
flipper_format_free(flipper_format);
|
||||||
|
subghz_transmitter_free(transmitter);
|
||||||
|
subghz_environment_free(environment);
|
||||||
|
}
|
5
subghz/apps/signal_send_demo/princeton.h
Normal file
5
subghz/apps/signal_send_demo/princeton.h
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <furi.h>
|
||||||
|
|
||||||
|
void send_princeton(uint32_t key, uint32_t frequency);
|
8
subghz/apps/signal_send_demo/princeton.sub
Normal file
8
subghz/apps/signal_send_demo/princeton.sub
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
Filetype: Flipper SubGhz Key File
|
||||||
|
Version: 1
|
||||||
|
Frequency: 433920000
|
||||||
|
Preset: FuriHalSubGhzPresetOok650Async
|
||||||
|
Protocol: Princeton
|
||||||
|
Bit: 24
|
||||||
|
Key: 00 00 00 00 00 96 7A B4
|
||||||
|
TE: 390
|
3
subghz/apps/signal_send_demo/tag.h
Normal file
3
subghz/apps/signal_send_demo/tag.h
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#define TAG "MyAppId"
|
Loading…
Reference in New Issue
Block a user