diff --git a/.DS_Store b/.DS_Store
new file mode 100644
index 00000000000..4dac4903cb3
Binary files /dev/null and b/.DS_Store differ
diff --git a/1-2-0.sub b/1-2-0.sub
new file mode 100644
index 00000000000..f1cd0a60c05
--- /dev/null
+++ b/1-2-0.sub
@@ -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 80 02 00
+TE: 271
diff --git a/1-3-0.sub b/1-3-0.sub
new file mode 100644
index 00000000000..b2f98a2e1ea
--- /dev/null
+++ b/1-3-0.sub
@@ -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 80 06 00
+TE: 271
diff --git a/1-4-0.sub b/1-4-0.sub
new file mode 100644
index 00000000000..95fb4167c77
--- /dev/null
+++ b/1-4-0.sub
@@ -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 80 01 00
+TE: 271
diff --git a/1_1-1_1-0.sub b/1_1-1_1-0.sub
new file mode 100644
index 00000000000..46f8f30157a
--- /dev/null
+++ b/1_1-1_1-0.sub
@@ -0,0 +1,6 @@
+Filetype: Flipper SubGhz RAW File
+Version: 1
+Frequency: 433920000
+Preset: FuriHalSubGhzPresetOok650Async
+Protocol: RAW
+RAW_Data: -6000 600 -200 200 -600 200 -600 200 -600 200 -600 200 -600 200 -600 200 -600 200 -600 200 -600 200 -600 200 -600 200 -600 600 -200 200 -600 200 -600 200 -600 200 -600 200 -600 200 -600 200 -600 200 -600 200 -600 200 -600 200 -6000
diff --git a/1_1-1_4-0.sub b/1_1-1_4-0.sub
new file mode 100644
index 00000000000..71085566a2f
--- /dev/null
+++ b/1_1-1_4-0.sub
@@ -0,0 +1,9 @@
+Filetype: Flipper SubGhz RAW File
+Version: 1
+Frequency: 433920000
+Preset: FuriHalSubGhzPresetOok650Async
+Protocol: RAW
+RAW_Data: -6000 600 -200 200 -600 200 -600 200 -600 200 -600 200 -600 200 -600 200 -600 200 -600 200 -600 200 -600 200 -600 200 -600 600 -200 200 -600 200 -600 200 -600 200 -600 200 -600 200 -600 200 -600 200 -600 200 -600 200 -600 200 -6000
+RAW_Data: -6000 600 -200 200 -600 200 -600 200 -600 200 -600 200 -600 200 -600 200 -600 200 -600 200 -600 200 -600 200 -600 200 -600 200 -600 600 -200 200 -600 200 -600 200 -600 200 -600 200 -600 200 -600 200 -600 200 -600 200 -600 200 -6000
+RAW_Data: -6000 600 -200 200 -600 200 -600 200 -600 200 -600 200 -600 200 -600 200 -600 200 -600 200 -600 200 -600 200 -600 200 -600 600 -200 600 -200 200 -600 200 -600 200 -600 200 -600 200 -600 200 -600 200 -600 200 -600 200 -600 200 -6000
+RAW_Data: -6000 600 -200 200 -600 200 -600 200 -600 200 -600 200 -600 200 -600 200 -600 200 -600 200 -600 200 -600 200 -600 200 -600 200 -600 200 -600 600 -200 200 -600 200 -600 200 -600 200 -600 200 -600 200 -600 200 -600 200 -600 200 -6000
diff --git a/8191_8191-1_4-0.sub b/8191_8191-1_4-0.sub
new file mode 100644
index 00000000000..56db63cf3bc
--- /dev/null
+++ b/8191_8191-1_4-0.sub
@@ -0,0 +1,9 @@
+Filetype: Flipper SubGhz RAW File
+Version: 1
+Frequency: 433920000
+Preset: FuriHalSubGhzPresetOok650Async
+Protocol: RAW
+RAW_Data: -6000 600 -200 600 -200 600 -200 600 -200 600 -200 600 -200 600 -200 600 -200 600 -200 600 -200 600 -200 600 -200 600 -200 600 -200 200 -600 200 -600 200 -600 200 -600 200 -600 200 -600 200 -600 200 -600 200 -600 200 -600 200 -6000
+RAW_Data: -6000 600 -200 600 -200 600 -200 600 -200 600 -200 600 -200 600 -200 600 -200 600 -200 600 -200 600 -200 600 -200 600 -200 200 -600 600 -200 200 -600 200 -600 200 -600 200 -600 200 -600 200 -600 200 -600 200 -600 200 -600 200 -6000
+RAW_Data: -6000 600 -200 600 -200 600 -200 600 -200 600 -200 600 -200 600 -200 600 -200 600 -200 600 -200 600 -200 600 -200 600 -200 600 -200 600 -200 200 -600 200 -600 200 -600 200 -600 200 -600 200 -600 200 -600 200 -600 200 -600 200 -6000
+RAW_Data: -6000 600 -200 600 -200 600 -200 600 -200 600 -200 600 -200 600 -200 600 -200 600 -200 600 -200 600 -200 600 -200 600 -200 200 -600 200 -600 600 -200 200 -600 200 -600 200 -600 200 -600 200 -600 200 -600 200 -600 200 -600 200 -6000
diff --git a/Pagger - Retekess T119.html b/Pagger - Retekess T119.html
new file mode 100644
index 00000000000..acac93c0108
--- /dev/null
+++ b/Pagger - Retekess T119.html
@@ -0,0 +1,514 @@
+
+
+
+
+
+
+
+
+
+ Pagger - Retekess T119
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Put here the hex key you got from the read.
+
+
+
+
+
+
+
+ Station:
+
+
+
+ Pager:
+
+
+
+ Action:
+
+
+
+
+
+ This single key file will call a single pager.
+
+
+
+
+
+
+
+
+
+ Pager (from):
+
+
+
+ Pager (to):
+
+
+
+
+
+
+
+ This combo raw file will call multiple pagers.
+
+
+
+
+
+
+
+
+ Station:
+
+ Download
+
+
+
+
+ This special action file will turn off all the pagers of a given station.
+
+
+
+
+
+
+
+ As explained here I don't think the
+ bruteforce is a viable approach... Anyway if you wanted to try it, these are the files to call the first 10
+ pagers for all stations.
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/README.md b/README.md
new file mode 100644
index 00000000000..fd97db30eda
--- /dev/null
+++ b/README.md
@@ -0,0 +1,31 @@
+# Flipper Zero Meal Pager Tool
+
+## What this is?
+This app triggers restaurant pagers in a brute force manner, useful to test if devices are still functional.
+
+
+## Supported Pagers
+- Retekess T119
+- Retekess TD157
+- Retekess TD165
+- Retekess TD174
+
+### Features
+- Select range of stations
+- Select range of pagers
+
+## How to install on Flipper Zero
+- If you do not have one, download a firmware
+- Plug your Flipper Zero in via USB.
+- Copy the contents of this folder into the applications_user folder of your firmware.
+
+Then run the command:
+ ```
+.\fbt launch APPSRC=applications_user/meal_pager
+ ```
+The application will be compiled and copied onto your device.
+
+## Thank you notes
+- [Moeker](https://github.com/moeker) and his awesome [pagger tool](https://github.com/meoker/pagger), couldn't have done this without
+- [xb8](https://github.com/xb8/t119bruteforcer) for the useful data collected
+- [Xenobyte, ShotokanZH](https://twitter.com/xenobyte_/status/1558123251276070912) for their super interesting research
\ No newline at end of file
diff --git a/application.fam b/application.fam
new file mode 100644
index 00000000000..005a4d587a3
--- /dev/null
+++ b/application.fam
@@ -0,0 +1,17 @@
+App(
+ appid="meal_pager",
+ name="Restaurant Pager Trigger",
+ apptype=FlipperAppType.EXTERNAL,
+ entry_point="meal_pager_app",
+ cdefines=["APP_MEAL_PAGER"],
+ requires=[
+ "gui",
+ "storage",
+ ],
+ stack_size=2 * 1024,
+ order=10,
+ fap_libs=["assets"],
+ fap_icon="icons/meal_pager_10px.png",
+ fap_icon_assets="icons",
+ fap_category="Sub-Ghz",
+)
\ No newline at end of file
diff --git a/helpers/meal_pager_custom_event.h b/helpers/meal_pager_custom_event.h
new file mode 100644
index 00000000000..053b1e96191
--- /dev/null
+++ b/helpers/meal_pager_custom_event.h
@@ -0,0 +1,60 @@
+#pragma once
+
+typedef enum {
+ Meal_PagerCustomEventStartscreenUp,
+ Meal_PagerCustomEventStartscreenDown,
+ Meal_PagerCustomEventStartscreenLeft,
+ Meal_PagerCustomEventStartscreenRight,
+ Meal_PagerCustomEventStartscreenOk,
+ Meal_PagerCustomEventStartscreenBack,
+ Meal_PagerCustomEventTransmitUp,
+ Meal_PagerCustomEventTransmitDown,
+ Meal_PagerCustomEventTransmitLeft,
+ Meal_PagerCustomEventTransmitRight,
+ Meal_PagerCustomEventTransmitOk,
+ Meal_PagerCustomEventTransmitBack,
+ Meal_PagerCustomEventScene2Up,
+ Meal_PagerCustomEventScene2Down,
+ Meal_PagerCustomEventScene2Left,
+ Meal_PagerCustomEventScene2Right,
+ Meal_PagerCustomEventScene2Ok,
+ Meal_PagerCustomEventScene2Back,
+} Meal_PagerCustomEvent;
+
+enum Meal_PagerCustomEventType {
+ // Reserve first 100 events for button types and indexes, starting from 0
+ Meal_PagerCustomEventMenuVoid,
+ Meal_PagerCustomEventMenuSelected,
+};
+
+#pragma pack(push, 1)
+typedef union {
+ uint32_t packed_value;
+ struct {
+ uint16_t type;
+ int16_t value;
+ } content;
+} Meal_PagerCustomEventMenu;
+#pragma pack(pop)
+
+static inline uint32_t meal_pager_custom_menu_event_pack(uint16_t type, int16_t value) {
+ Meal_PagerCustomEventMenu event = {.content = {.type = type, .value = value}};
+ return event.packed_value;
+}
+static inline void meal_pager_custom_menu_event_unpack(uint32_t packed_value, uint16_t* type, int16_t* value) {
+ Meal_PagerCustomEventMenu event = {.packed_value = packed_value};
+ if(type) *type = event.content.type;
+ if(value) *value = event.content.value;
+}
+
+static inline uint16_t meal_pager_custom_menu_event_get_type(uint32_t packed_value) {
+ uint16_t type;
+ meal_pager_custom_menu_event_unpack(packed_value, &type, NULL);
+ return type;
+}
+
+static inline int16_t meal_pager_custom_menu_event_get_value(uint32_t packed_value) {
+ int16_t value;
+ meal_pager_custom_menu_event_unpack(packed_value, NULL, &value);
+ return value;
+}
\ No newline at end of file
diff --git a/helpers/meal_pager_haptic.c b/helpers/meal_pager_haptic.c
new file mode 100644
index 00000000000..5310d2b770c
--- /dev/null
+++ b/helpers/meal_pager_haptic.c
@@ -0,0 +1,36 @@
+#include "meal_pager_haptic.h"
+#include "../meal_pager.h"
+
+
+void meal_pager_play_happy_bump(void* context) {
+ Meal_Pager* app = context;
+ if (app->haptic != 1) {
+ return;
+ }
+ notification_message(app->notification, &sequence_set_vibro_on);
+ furi_thread_flags_wait(0, FuriFlagWaitAny, 20);
+ notification_message(app->notification, &sequence_reset_vibro);
+}
+
+void meal_pager_play_bad_bump(void* context) {
+ Meal_Pager* app = context;
+ if (app->haptic != 1) {
+ return;
+ }
+ notification_message(app->notification, &sequence_set_vibro_on);
+ furi_thread_flags_wait(0, FuriFlagWaitAny, 100);
+ notification_message(app->notification, &sequence_reset_vibro);
+}
+
+void meal_pager_play_long_bump(void* context) {
+ Meal_Pager* app = context;
+ if (app->haptic != 1) {
+ return;
+ }
+ for (int i = 0; i < 4; i++) {
+ notification_message(app->notification, &sequence_set_vibro_on);
+ furi_thread_flags_wait(0, FuriFlagWaitAny, 50);
+ notification_message(app->notification, &sequence_reset_vibro);
+ furi_thread_flags_wait(0, FuriFlagWaitAny, 100);
+ }
+}
diff --git a/helpers/meal_pager_haptic.h b/helpers/meal_pager_haptic.h
new file mode 100644
index 00000000000..4e862706d90
--- /dev/null
+++ b/helpers/meal_pager_haptic.h
@@ -0,0 +1,8 @@
+#include
+
+void meal_pager_play_happy_bump(void* context);
+
+void meal_pager_play_bad_bump(void* context);
+
+void meal_pager_play_long_bump(void* context);
+
diff --git a/helpers/meal_pager_led.c b/helpers/meal_pager_led.c
new file mode 100644
index 00000000000..9c49e32d768
--- /dev/null
+++ b/helpers/meal_pager_led.c
@@ -0,0 +1,39 @@
+#include "meal_pager_led.h"
+#include "../meal_pager.h"
+
+
+
+void meal_pager_led_set_rgb(void* context, int red, int green, int blue) {
+ Meal_Pager* app = context;
+ if (app->led != 1) {
+ return;
+ }
+ NotificationMessage notification_led_message_1;
+ notification_led_message_1.type = NotificationMessageTypeLedRed;
+ NotificationMessage notification_led_message_2;
+ notification_led_message_2.type = NotificationMessageTypeLedGreen;
+ NotificationMessage notification_led_message_3;
+ notification_led_message_3.type = NotificationMessageTypeLedBlue;
+
+ notification_led_message_1.data.led.value = red;
+ notification_led_message_2.data.led.value = green;
+ notification_led_message_3.data.led.value = blue;
+ const NotificationSequence notification_sequence = {
+ ¬ification_led_message_1,
+ ¬ification_led_message_2,
+ ¬ification_led_message_3,
+ &message_do_not_reset,
+ NULL,
+ };
+ notification_message(app->notification, ¬ification_sequence);
+ furi_thread_flags_wait(0, FuriFlagWaitAny, 10); //Delay, prevent removal from RAM before LED value set
+}
+
+void meal_pager_led_reset(void* context) {
+ Meal_Pager* app = context;
+ notification_message(app->notification, &sequence_reset_red);
+ notification_message(app->notification, &sequence_reset_green);
+ notification_message(app->notification, &sequence_reset_blue);
+
+ furi_thread_flags_wait(0, FuriFlagWaitAny, 300); //Delay, prevent removal from RAM before LED value set
+}
diff --git a/helpers/meal_pager_led.h b/helpers/meal_pager_led.h
new file mode 100644
index 00000000000..e90f41d4766
--- /dev/null
+++ b/helpers/meal_pager_led.h
@@ -0,0 +1,6 @@
+
+
+void meal_pager_led_set_rgb(void* context, int red, int green, int blue);
+
+void meal_pager_led_reset(void* context);
+
diff --git a/helpers/meal_pager_speaker.c b/helpers/meal_pager_speaker.c
new file mode 100644
index 00000000000..4b9ec1b9ef1
--- /dev/null
+++ b/helpers/meal_pager_speaker.c
@@ -0,0 +1,27 @@
+#include "meal_pager_speaker.h"
+#include "../meal_pager.h"
+
+#define NOTE_INPUT 587.33f
+
+void meal_pager_play_input_sound(void* context) {
+ Meal_Pager* app = context;
+ if (app->speaker != 1) {
+ return;
+ }
+ float volume = 1.0f;
+ if(furi_hal_speaker_is_mine() || furi_hal_speaker_acquire(30)) {
+ furi_hal_speaker_start(NOTE_INPUT, volume);
+ }
+
+}
+
+void meal_pager_stop_all_sound(void* context) {
+ Meal_Pager* app = context;
+ if (app->speaker != 1) {
+ return;
+ }
+ if(furi_hal_speaker_is_mine()) {
+ furi_hal_speaker_stop();
+ furi_hal_speaker_release();
+ }
+}
diff --git a/helpers/meal_pager_speaker.h b/helpers/meal_pager_speaker.h
new file mode 100644
index 00000000000..67597d9c67e
--- /dev/null
+++ b/helpers/meal_pager_speaker.h
@@ -0,0 +1,4 @@
+#define NOTE_INPUT 587.33f
+
+void meal_pager_play_input_sound(void* context);
+void meal_pager_stop_all_sound(void* context);
diff --git a/helpers/meal_pager_storage.c b/helpers/meal_pager_storage.c
new file mode 100644
index 00000000000..028bc8504b9
--- /dev/null
+++ b/helpers/meal_pager_storage.c
@@ -0,0 +1,136 @@
+#include "meal_pager_storage.h"
+
+
+static Storage* meal_pager_open_storage() {
+ return furi_record_open(RECORD_STORAGE);
+}
+
+static void meal_pager_close_storage() {
+ furi_record_close(RECORD_STORAGE);
+}
+
+static void meal_pager_close_config_file(FlipperFormat* file) {
+ if (file == NULL) return;
+ flipper_format_file_close(file);
+ flipper_format_free(file);
+}
+
+void meal_pager_save_settings(void* context) {
+ Meal_Pager* app = context;
+ if (app->save_settings == 0) {
+ FURI_LOG_D(TAG, "Skipping Save because Disabled");
+ return;
+ }
+
+ FURI_LOG_D(TAG, "Saving Settings to File");
+ Storage* storage = meal_pager_open_storage();
+ FlipperFormat* fff_file = flipper_format_file_alloc(storage);
+
+ // Overwrite wont work, so delete first
+ if(storage_file_exists(storage, MEAL_PAGER_SETTINGS_SAVE_PATH)) {
+ storage_simply_remove(storage, MEAL_PAGER_SETTINGS_SAVE_PATH);
+ }
+
+ // Open File, create if not exists
+ if(!storage_common_stat(storage, MEAL_PAGER_SETTINGS_SAVE_PATH, NULL) == FSE_OK) {
+ FURI_LOG_D(TAG, "Config file %s is not found. Will create new.", MEAL_PAGER_SETTINGS_SAVE_PATH);
+ if(storage_common_stat(storage, CONFIG_FILE_DIRECTORY_PATH, NULL) == FSE_NOT_EXIST) {
+ FURI_LOG_D(
+ TAG,
+ "Directory %s doesn't exist. Will create new.",
+ CONFIG_FILE_DIRECTORY_PATH);
+ if(!storage_simply_mkdir(storage, CONFIG_FILE_DIRECTORY_PATH)) {
+ FURI_LOG_E(TAG, "Error creating directory %s", CONFIG_FILE_DIRECTORY_PATH);
+ }
+ }
+ }
+
+ if(!flipper_format_file_open_new(fff_file, MEAL_PAGER_SETTINGS_SAVE_PATH)) {
+ //totp_close_config_file(fff_file);
+ FURI_LOG_E(TAG, "Error creating new file %s", MEAL_PAGER_SETTINGS_SAVE_PATH);
+ meal_pager_close_storage();
+ return;
+ }
+
+ // Store Settings
+ flipper_format_write_header_cstr(
+ fff_file, MEAL_PAGER_SETTINGS_HEADER, MEAL_PAGER_SETTINGS_FILE_VERSION);
+ flipper_format_write_uint32(
+ fff_file, MEAL_PAGER_SETTINGS_KEY_PAGER_TYPE, &app->pager_type, 1);
+ flipper_format_write_uint32(
+ fff_file, MEAL_PAGER_SETTINGS_KEY_FIRST_STATION, &app->first_station, 1);
+ flipper_format_write_uint32(
+ fff_file, MEAL_PAGER_SETTINGS_KEY_LAST_STATION, &app->last_station, 1);
+ flipper_format_write_uint32(
+ fff_file, MEAL_PAGER_SETTINGS_KEY_FIRST_PAGER, &app->first_pager, 1);
+ flipper_format_write_uint32(
+ fff_file, MEAL_PAGER_SETTINGS_KEY_LAST_PAGER, &app->last_pager, 1);
+ flipper_format_write_uint32(
+ fff_file, MEAL_PAGER_SETTINGS_KEY_HAPTIC, &app->haptic, 1);
+ flipper_format_write_uint32(
+ fff_file, MEAL_PAGER_SETTINGS_KEY_SPEAKER, &app->speaker, 1);
+ flipper_format_write_uint32(
+ fff_file, MEAL_PAGER_SETTINGS_KEY_LED, &app->led, 1);
+ flipper_format_write_uint32(
+ fff_file, MEAL_PAGER_SETTINGS_KEY_SAVE_SETTINGS, &app->save_settings, 1);
+
+ if(!flipper_format_rewind(fff_file)) {
+ meal_pager_close_config_file(fff_file);
+ FURI_LOG_E(TAG, "Rewind error");
+ meal_pager_close_storage();
+ return;
+ }
+
+ meal_pager_close_config_file(fff_file);
+ meal_pager_close_storage();
+}
+
+void meal_pager_read_settings(void* context) {
+ Meal_Pager* app = context;
+ Storage* storage = meal_pager_open_storage();
+ FlipperFormat* fff_file = flipper_format_file_alloc(storage);
+
+ if(storage_common_stat(storage, MEAL_PAGER_SETTINGS_SAVE_PATH, NULL) != FSE_OK) {
+ meal_pager_close_config_file(fff_file);
+ meal_pager_close_storage();
+ return;
+ }
+ uint32_t file_version;
+ FuriString* temp_str = furi_string_alloc();
+
+ if (!flipper_format_file_open_existing(fff_file, MEAL_PAGER_SETTINGS_SAVE_PATH)) {
+ FURI_LOG_E(TAG, "Cannot open file %s", MEAL_PAGER_SETTINGS_SAVE_PATH);
+ meal_pager_close_config_file(fff_file);
+ meal_pager_close_storage();
+ return;
+ }
+
+ if(!flipper_format_read_header(fff_file, temp_str, &file_version)) {
+ FURI_LOG_E(TAG, "Missing Header Data");
+ meal_pager_close_config_file(fff_file);
+ meal_pager_close_storage();
+ return;
+ }
+
+ if(file_version < MEAL_PAGER_SETTINGS_FILE_VERSION) {
+ FURI_LOG_I(TAG, "old config version, will be removed.");
+ meal_pager_close_config_file(fff_file);
+ meal_pager_close_storage();
+ return;
+ }
+
+ flipper_format_read_uint32(fff_file, MEAL_PAGER_SETTINGS_KEY_PAGER_TYPE, &app->pager_type, 1);
+ flipper_format_read_uint32(fff_file, MEAL_PAGER_SETTINGS_KEY_FIRST_STATION, &app->first_station, 1);
+ flipper_format_read_uint32(fff_file, MEAL_PAGER_SETTINGS_KEY_LAST_STATION, &app->last_station, 1);
+ flipper_format_read_uint32(fff_file, MEAL_PAGER_SETTINGS_KEY_FIRST_PAGER, &app->first_pager, 1);
+ flipper_format_read_uint32(fff_file, MEAL_PAGER_SETTINGS_KEY_LAST_PAGER, &app->last_pager, 1);
+ flipper_format_read_uint32(fff_file, MEAL_PAGER_SETTINGS_KEY_HAPTIC, &app->haptic, 1);
+ flipper_format_read_uint32(fff_file, MEAL_PAGER_SETTINGS_KEY_SPEAKER, &app->speaker, 1);
+ flipper_format_read_uint32(fff_file, MEAL_PAGER_SETTINGS_KEY_LED, &app->led, 1);
+ flipper_format_read_uint32(fff_file, MEAL_PAGER_SETTINGS_KEY_SAVE_SETTINGS, &app->save_settings, 1);
+
+ flipper_format_rewind(fff_file);
+
+ meal_pager_close_config_file(fff_file);
+ meal_pager_close_storage();
+}
\ No newline at end of file
diff --git a/helpers/meal_pager_storage.h b/helpers/meal_pager_storage.h
new file mode 100644
index 00000000000..c609266f7c1
--- /dev/null
+++ b/helpers/meal_pager_storage.h
@@ -0,0 +1,25 @@
+#pragma once
+
+#include
+#include
+#include
+#include
+#include "../meal_pager.h"
+
+#define MEAL_PAGER_SETTINGS_FILE_VERSION 1
+#define CONFIG_FILE_DIRECTORY_PATH EXT_PATH("apps_data/meal_pager")
+#define MEAL_PAGER_SETTINGS_SAVE_PATH CONFIG_FILE_DIRECTORY_PATH "/meal_pager.conf"
+#define MEAL_PAGER_SETTINGS_SAVE_PATH_TMP MEAL_PAGER_SETTINGS_SAVE_PATH ".tmp"
+#define MEAL_PAGER_SETTINGS_HEADER "Meal_Pager Config File"
+#define MEAL_PAGER_SETTINGS_KEY_PAGER_TYPE "Pager Type"
+#define MEAL_PAGER_SETTINGS_KEY_FIRST_STATION "First Station"
+#define MEAL_PAGER_SETTINGS_KEY_LAST_STATION "Last Station"
+#define MEAL_PAGER_SETTINGS_KEY_FIRST_PAGER "First Pager"
+#define MEAL_PAGER_SETTINGS_KEY_LAST_PAGER "Last Pager"
+#define MEAL_PAGER_SETTINGS_KEY_HAPTIC "Haptic"
+#define MEAL_PAGER_SETTINGS_KEY_LED "Led"
+#define MEAL_PAGER_SETTINGS_KEY_SPEAKER "Speaker"
+#define MEAL_PAGER_SETTINGS_KEY_SAVE_SETTINGS "SaveSettings"
+
+void meal_pager_save_settings(void* context);
+void meal_pager_read_settings(void* context);
\ No newline at end of file
diff --git a/helpers/retekess/meal_pager_retekess_t119.c b/helpers/retekess/meal_pager_retekess_t119.c
new file mode 100644
index 00000000000..21e8a3bf896
--- /dev/null
+++ b/helpers/retekess/meal_pager_retekess_t119.c
@@ -0,0 +1,190 @@
+
+#include "meal_pager_retekess_t119.h"
+
+void customConcat(char* dest, const char* src) {
+ //FURI_LOG_D(TAG, "adding %s to %s", src, dest);
+ // Find the end of the destination string
+ while (*dest != '\0') {
+ dest++;
+ }
+
+ // Copy characters from src to dest
+ while (*src != '\0') {
+ *dest = *src;
+ dest++;
+ src++;
+ }
+
+ // Null-terminate the concatenated string
+ *dest = '\0';
+}
+
+char* genRawData(int zero, int one, const char* bits) {
+ int bitsLen = strlen(bits);
+ int lineLen = 256; // Adjust the line length as needed
+ char* line = (char*)malloc(lineLen * sizeof(char));
+
+ //FURI_LOG_D(TAG, "bitLen = %u", bitsLen);
+ // Initialize the line with the first part
+ //snprintf(line, lineLen, "-6000");
+
+ //char* res = (char*)malloc((bitsLen * 4) * sizeof(char));
+ char* res = (char*)malloc(lineLen * sizeof(char));
+ res[0] = '\0'; // Null-terminate the result string
+
+ //customConcat(res, line);
+ customConcat(res, "-6000");
+
+ // Append bits and create the line
+ for (int i = 0; i < bitsLen; i++) {
+ char c = bits[i];
+ //char p = (i > 0) ? bits[i - 1] : '0';
+ int t = (c == '0') ? zero : one;
+
+ if (i % 2 == 0) {
+ snprintf(line, lineLen, " %d", t);
+ } else {
+ snprintf(line, lineLen, " -%d", t);
+ }
+
+ // Concatenate the line to the result string
+ //strncat(res, line, bitsLen * 4);
+ customConcat(res, line);
+ }
+
+ // Append the closing part to the line
+ //strncat(line, " -6000\n", lineLen);
+ customConcat(res, " 200 -6000");
+ //FURI_LOG_D(TAG, "res is: %s", res);
+
+ free(line); // Free memory allocated for the line
+
+ return res;
+}
+
+char* encManchester(const char* bits, int mode) {
+ // Allocate memory for the result string
+ char* res = (char*)malloc((strlen(bits) * 2 + 1) * sizeof(char));
+
+ int index = 0;
+ for (int i = 0; bits[i] != '\0'; i++) {
+ char c = bits[i];
+ if (c == '0') {
+ if (mode) {
+ res[index++] = '1';
+ res[index++] = '0';
+ } else {
+ res[index++] = '0';
+ res[index++] = '1';
+ }
+ } else if (c == '1') {
+ if (mode) {
+ res[index++] = '0';
+ res[index++] = '1';
+ } else {
+ res[index++] = '1';
+ res[index++] = '0';
+ }
+ } else {
+ // Handle 'EE' case (error)
+ res[index++] = 'E';
+ res[index++] = 'E';
+ }
+ }
+
+ // Null-terminate the result string
+ res[index] = '\0';
+
+ return res;
+}
+
+void uint32ToBinaray(uint32_t number, char* str, int8_t length) {
+ int i = 0;
+ length--; // count length without 0
+ for (i = length; i >= 0; i--) {
+ // Bitwise AND extration of the i-th bit
+ int bit = (number >> i) & 1;
+ // convert the bit to a character of 1 or 0
+ str[length - i] = bit + '0';
+ }
+ // Terminate the string
+ str[length+1] = '\0';
+}
+
+void reverse(char* str) {
+ int length = strlen(str);
+ int start = 0;
+ int end = length - 1;
+ while (start < end) {
+ char temp = str[start];
+ str[start] = str[end];
+ str[end] = temp;
+ start++;
+ end--;
+ }
+}
+
+void meal_pager_retekess_t119_generate_pager(void* context, char* stationId, uint32_t pager) {
+ Meal_Pager* app = context;
+ char pagerId[11];
+ //char stationPagerId[25];
+ //char fullId[25];
+ char* fullId = (char*)malloc(25 * sizeof(char));
+ uint32_t action = 0; // 0 = ring, 1 = mute
+ char actionId[2];
+ //char action[2];
+ //action[0] = '0'; // 0 = ring, 1 = mute
+ //action[1] = '\0';
+ FURI_LOG_D(TAG, "Generating T119 Data for Pager %lu", pager);
+ app->current_pager = pager;
+ meal_pager_transmit_model_set_pager(app->meal_pager_transmit, app->current_pager);
+ uint32ToBinaray(pager, pagerId, 10);
+ uint32ToBinaray(action, actionId, 1);
+ reverse(pagerId);
+ reverse(actionId);
+ //FURI_LOG_D(TAG, "Station Bin: %s", stationId);
+ //FURI_LOG_D(TAG, "Pager Bin: %s", pagerId);
+ //FURI_LOG_D(TAG, "Action Bin: %s", actionId);
+ customConcat(fullId, stationId);
+ customConcat(fullId, pagerId);
+ FURI_LOG_D(TAG, "Result %s", fullId);
+ //FURI_LOG_D(TAG, "Station & Pager: %s", stationPagerId);
+ //FURI_LOG_D(TAG, "Station & Pager: %s", stationPagerId);
+ customConcat(fullId, actionId);
+ FURI_LOG_D(TAG, "CustomConcat: %s", fullId);
+ //FURI_LOG_D(TAG, "Station & Pager & Action: %s", fullId);
+ char* manchester = encManchester(fullId, 0);
+ FURI_LOG_D(TAG, "Manchester: %s", manchester);
+ char* rawSignal = genRawData(200, 600, manchester);
+ FURI_LOG_D(TAG, "Raw Data: %s", rawSignal);
+ free(manchester);
+ free(rawSignal);
+}
+
+void meal_pager_retekess_t119_generate_station(void* context, uint32_t station) {
+ Meal_Pager* app = context;
+ FURI_LOG_D(TAG, "Generating T119 Data for Station %lu", station);
+ app->current_station = station;
+ app->current_pager = app->first_pager;
+ char stationId[14];
+ uint32ToBinaray(station, stationId, 13);
+ reverse(stationId);
+ meal_pager_transmit_model_set_station(app->meal_pager_transmit, app->current_station);
+ for (u_int32_t i = app->current_pager;i <= app->last_pager; i++) {
+ meal_pager_retekess_t119_generate_pager(app, stationId, i);
+ //furi_thread_flags_wait(0, FuriFlagWaitAny, 1);
+ }
+}
+
+void meal_pager_retekess_t119_generate_all(void* context) {
+ Meal_Pager* app = context;
+
+ app->current_pager = 1;
+ app->current_station = app->first_station;
+
+ for (u_int32_t i = app->current_station;i <= app->last_station; i++) {
+ meal_pager_retekess_t119_generate_station(app, i);
+ //furi_thread_flags_wait(0, FuriFlagWaitAny, 100);
+ }
+}
+
diff --git a/helpers/retekess/meal_pager_retekess_t119.h b/helpers/retekess/meal_pager_retekess_t119.h
new file mode 100644
index 00000000000..5f735af8ac2
--- /dev/null
+++ b/helpers/retekess/meal_pager_retekess_t119.h
@@ -0,0 +1,18 @@
+
+#pragma once
+
+#include "../../meal_pager.h"
+
+char* encManchester(const char* bits, int mode);
+
+void uint32ToBinaray(uint32_t number, char* str, int8_t length);
+
+void reverse(char* str);
+
+void customConcat(char* dest, const char* src);
+
+void meal_pager_retekess_t119_generate_pager(void* context, char* stationId, uint32_t pager);
+
+void meal_pager_retekess_t119_generate_station(void* context, uint32_t station);
+
+void meal_pager_retekess_t119_generate_all(void* context);
\ No newline at end of file
diff --git a/icons/meal_pager_10px.png b/icons/meal_pager_10px.png
new file mode 100644
index 00000000000..0519f7a9a86
Binary files /dev/null and b/icons/meal_pager_10px.png differ
diff --git a/meal_pager.c b/meal_pager.c
new file mode 100644
index 00000000000..efb91e4d5a8
--- /dev/null
+++ b/meal_pager.c
@@ -0,0 +1,127 @@
+#include "meal_pager.h"
+
+bool meal_pager_custom_event_callback(void* context, uint32_t event) {
+ furi_assert(context);
+ Meal_Pager* app = context;
+ return scene_manager_handle_custom_event(app->scene_manager, event);
+}
+
+void meal_pager_tick_event_callback(void* context) {
+ furi_assert(context);
+ Meal_Pager* app = context;
+ scene_manager_handle_tick_event(app->scene_manager);
+}
+
+//leave app if back button pressed
+bool meal_pager_navigation_event_callback(void* context) {
+ furi_assert(context);
+ Meal_Pager* app = context;
+ return scene_manager_handle_back_event(app->scene_manager);
+}
+
+Meal_Pager* meal_pager_app_alloc() {
+ Meal_Pager* app = malloc(sizeof(Meal_Pager));
+ app->gui = furi_record_open(RECORD_GUI);
+ app->notification = furi_record_open(RECORD_NOTIFICATION);
+
+ //Turn backlight on, believe me this makes testing your app easier
+ notification_message(app->notification, &sequence_display_backlight_on);
+
+ //Scene additions
+ app->view_dispatcher = view_dispatcher_alloc();
+ view_dispatcher_enable_queue(app->view_dispatcher);
+
+ app->scene_manager = scene_manager_alloc(&meal_pager_scene_handlers, app);
+ view_dispatcher_set_event_callback_context(app->view_dispatcher, app);
+ view_dispatcher_set_navigation_event_callback(app->view_dispatcher, meal_pager_navigation_event_callback);
+ view_dispatcher_set_tick_event_callback(app->view_dispatcher, meal_pager_tick_event_callback, 100);
+ view_dispatcher_set_custom_event_callback(app->view_dispatcher, meal_pager_custom_event_callback);
+ app->submenu = submenu_alloc();
+
+ // Set defaults, in case no config loaded
+ app->haptic = 1;
+ app->speaker = 1;
+ app->led = 1;
+ app->save_settings = 1;
+ app->pager_type = 0;
+ app->first_station = 0;
+ app->first_station_char = "0";
+ app->last_station = 255;
+ app->last_station_char = "255";
+ app->first_pager = 0;
+ app->first_pager_char = "0";
+ app->last_pager = 31;
+ app->last_pager_char = "31";
+
+ // Used for File Browser
+ app->dialogs = furi_record_open(RECORD_DIALOGS);
+ app->file_path = furi_string_alloc();
+
+ // Load configs
+ meal_pager_read_settings(app);
+
+ view_dispatcher_add_view(app->view_dispatcher, Meal_PagerViewIdMenu, submenu_get_view(app->submenu));
+ app->meal_pager_startscreen = meal_pager_startscreen_alloc();
+ view_dispatcher_add_view(app->view_dispatcher, Meal_PagerViewIdStartscreen, meal_pager_startscreen_get_view(app->meal_pager_startscreen));
+ app->meal_pager_transmit = meal_pager_transmit_alloc(app);
+ view_dispatcher_add_view(app->view_dispatcher, Meal_PagerViewIdTransmit, meal_pager_transmit_get_view(app->meal_pager_transmit));
+
+ app->variable_item_list = variable_item_list_alloc();
+ view_dispatcher_add_view(app->view_dispatcher, Meal_PagerViewIdSettings, variable_item_list_get_view(app->variable_item_list));
+
+ //End Scene Additions
+
+ return app;
+}
+
+void meal_pager_app_free(Meal_Pager* app) {
+ furi_assert(app);
+
+ // Scene manager
+ scene_manager_free(app->scene_manager);
+
+ // View Dispatcher
+ view_dispatcher_remove_view(app->view_dispatcher, Meal_PagerViewIdMenu);
+ view_dispatcher_remove_view(app->view_dispatcher, Meal_PagerViewIdTransmit);
+ view_dispatcher_remove_view(app->view_dispatcher, Meal_PagerViewIdSettings);
+ submenu_free(app->submenu);
+
+ view_dispatcher_free(app->view_dispatcher);
+ furi_record_close(RECORD_GUI);
+
+ app->gui = NULL;
+ app->notification = NULL;
+
+ // Close File Browser
+ furi_record_close(RECORD_DIALOGS);
+ furi_string_free(app->file_path);
+
+ //Remove whatever is left
+ free(app);
+}
+
+int32_t meal_pager_app(void* p) {
+ UNUSED(p);
+ FURI_LOG_D(TAG, "Started Meal Pager");
+
+ Meal_Pager* app = meal_pager_app_alloc();
+
+ view_dispatcher_attach_to_gui(app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen);
+
+ scene_manager_next_scene(app->scene_manager, Meal_PagerSceneStartscreen); //Start with start screen
+ //scene_manager_next_scene(app->scene_manager, Meal_PagerSceneMenu); //if you want to directly start with Menu
+
+ furi_hal_power_suppress_charge_enter();
+
+ view_dispatcher_run(app->view_dispatcher);
+
+ meal_pager_save_settings(app);
+
+ furi_hal_power_suppress_charge_exit();
+ meal_pager_app_free(app);
+
+ return 0;
+}
+
+
+
diff --git a/meal_pager.h b/meal_pager.h
new file mode 100644
index 00000000000..38385971fd8
--- /dev/null
+++ b/meal_pager.h
@@ -0,0 +1,89 @@
+#pragma once
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include "scenes/meal_pager_scene.h"
+#include "views/meal_pager_startscreen.h"
+#include "views/meal_pager_transmit.h"
+#include "helpers/meal_pager_storage.h"
+
+#define TAG "Meal_Pager"
+
+#define SUBGHZ_APP_EXTENSION ".sub"
+#define SUBGHZ_APP_FOLDER ANY_PATH("subghz")
+
+typedef struct {
+ Gui* gui;
+ NotificationApp* notification;
+ ViewDispatcher* view_dispatcher;
+ Submenu* submenu;
+ SceneManager* scene_manager;
+ VariableItemList* variable_item_list;
+ Meal_PagerStartscreen* meal_pager_startscreen;
+ Meal_PagerTransmit* meal_pager_transmit;
+ DialogsApp* dialogs; // File Browser
+ FuriString* file_path; // File Browser
+ uint32_t haptic;
+ uint32_t speaker;
+ uint32_t led;
+ uint32_t save_settings;
+ uint32_t pager_type;
+ uint32_t first_station;
+ char* first_station_char;
+ uint32_t last_station;
+ char* last_station_char;
+ uint32_t first_pager;
+ char* first_pager_char;
+ uint32_t last_pager;
+ char* last_pager_char;
+ uint32_t current_station;
+ uint32_t current_pager;
+} Meal_Pager;
+
+typedef enum {
+ Meal_PagerViewIdStartscreen,
+ Meal_PagerViewIdMenu,
+ Meal_PagerViewIdTransmit,
+ Meal_PagerViewIdSettings,
+} Meal_PagerViewId;
+
+typedef enum {
+ Meal_PagerPagerTypeT119,
+ Meal_PagerPagerTypeTD157,
+ Meal_PagerPagerTypeTD165,
+ Meal_PagerPagerTypeTD174,
+} Meal_PagerPagerType;
+
+
+
+typedef enum {
+ Meal_PagerHapticOff,
+ Meal_PagerHapticOn,
+} Meal_PagerHapticState;
+
+typedef enum {
+ Meal_PagerSpeakerOff,
+ Meal_PagerSpeakerOn,
+} Meal_PagerSpeakerState;
+
+typedef enum {
+ Meal_PagerLedOff,
+ Meal_PagerLedOn,
+} Meal_PagerLedState;
+
+typedef enum {
+ Meal_PagerSettingsOff,
+ Meal_PagerSettingsOn,
+} Meal_PagerSettingsStoreState;
diff --git a/scenes/meal_pager_scene.c b/scenes/meal_pager_scene.c
new file mode 100644
index 00000000000..91ce9200f6e
--- /dev/null
+++ b/scenes/meal_pager_scene.c
@@ -0,0 +1,30 @@
+#include "meal_pager_scene.h"
+
+// Generate scene on_enter handlers array
+#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_enter,
+void (*const meal_pager_on_enter_handlers[])(void*) = {
+#include "meal_pager_scene_config.h"
+};
+#undef ADD_SCENE
+
+// Generate scene on_event handlers array
+#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_event,
+bool (*const meal_pager_on_event_handlers[])(void* context, SceneManagerEvent event) = {
+#include "meal_pager_scene_config.h"
+};
+#undef ADD_SCENE
+
+// Generate scene on_exit handlers array
+#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_exit,
+void (*const meal_pager_on_exit_handlers[])(void* context) = {
+#include "meal_pager_scene_config.h"
+};
+#undef ADD_SCENE
+
+// Initialize scene handlers configuration structure
+const SceneManagerHandlers meal_pager_scene_handlers = {
+ .on_enter_handlers = meal_pager_on_enter_handlers,
+ .on_event_handlers = meal_pager_on_event_handlers,
+ .on_exit_handlers = meal_pager_on_exit_handlers,
+ .scene_num = Meal_PagerSceneNum,
+};
diff --git a/scenes/meal_pager_scene.h b/scenes/meal_pager_scene.h
new file mode 100644
index 00000000000..86d0fe3e054
--- /dev/null
+++ b/scenes/meal_pager_scene.h
@@ -0,0 +1,29 @@
+#pragma once
+
+#include
+
+// Generate scene id and total number
+#define ADD_SCENE(prefix, name, id) Meal_PagerScene##id,
+typedef enum {
+#include "meal_pager_scene_config.h"
+ Meal_PagerSceneNum,
+} Meal_PagerScene;
+#undef ADD_SCENE
+
+extern const SceneManagerHandlers meal_pager_scene_handlers;
+
+// Generate scene on_enter handlers declaration
+#define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_enter(void*);
+#include "meal_pager_scene_config.h"
+#undef ADD_SCENE
+
+// Generate scene on_event handlers declaration
+#define ADD_SCENE(prefix, name, id) \
+ bool prefix##_scene_##name##_on_event(void* context, SceneManagerEvent event);
+#include "meal_pager_scene_config.h"
+#undef ADD_SCENE
+
+// Generate scene on_exit handlers declaration
+#define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_exit(void* context);
+#include "meal_pager_scene_config.h"
+#undef ADD_SCENE
diff --git a/scenes/meal_pager_scene_config.h b/scenes/meal_pager_scene_config.h
new file mode 100644
index 00000000000..9fb8580cfc2
--- /dev/null
+++ b/scenes/meal_pager_scene_config.h
@@ -0,0 +1,4 @@
+ADD_SCENE(meal_pager, startscreen, Startscreen)
+ADD_SCENE(meal_pager, menu, Menu)
+ADD_SCENE(meal_pager, transmit, Transmit)
+ADD_SCENE(meal_pager, settings, Settings)
\ No newline at end of file
diff --git a/scenes/meal_pager_scene_menu.c b/scenes/meal_pager_scene_menu.c
new file mode 100644
index 00000000000..be1123cae28
--- /dev/null
+++ b/scenes/meal_pager_scene_menu.c
@@ -0,0 +1,55 @@
+#include "../meal_pager.h"
+
+enum SubmenuIndex {
+ SubmenuIndexTransmit = 10,
+ SubmenuIndexScene2,
+ SubmenuIndexScene3,
+ SubmenuIndexScene4,
+ SubmenuIndexScene5,
+ SubmenuIndexSettings,
+};
+
+void meal_pager_scene_menu_submenu_callback(void* context, uint32_t index) {
+ Meal_Pager* app = context;
+ view_dispatcher_send_custom_event(app->view_dispatcher, index);
+}
+
+void meal_pager_scene_menu_on_enter(void* context) {
+ Meal_Pager* app = context;
+
+ submenu_add_item(app->submenu, "Scene 1 (empty)", SubmenuIndexTransmit, meal_pager_scene_menu_submenu_callback, app);
+ submenu_add_item(app->submenu, "Settings", SubmenuIndexSettings, meal_pager_scene_menu_submenu_callback, app);
+
+ submenu_set_selected_item(app->submenu, scene_manager_get_scene_state(app->scene_manager, Meal_PagerSceneMenu));
+
+ view_dispatcher_switch_to_view(app->view_dispatcher, Meal_PagerViewIdMenu);
+}
+
+bool meal_pager_scene_menu_on_event(void* context, SceneManagerEvent event) {
+ Meal_Pager* app = context;
+ UNUSED(app);
+ if(event.type == SceneManagerEventTypeBack) {
+ //exit app
+ scene_manager_stop(app->scene_manager);
+ view_dispatcher_stop(app->view_dispatcher);
+ return true;
+ } else if(event.type == SceneManagerEventTypeCustom) {
+ if(event.event == SubmenuIndexTransmit) {
+ scene_manager_set_scene_state(
+ app->scene_manager, Meal_PagerSceneMenu, SubmenuIndexTransmit);
+ scene_manager_next_scene(app->scene_manager, Meal_PagerSceneTransmit);
+ return true;
+ } else if (event.event == SubmenuIndexSettings) {
+ scene_manager_set_scene_state(
+ app->scene_manager, Meal_PagerSceneMenu, SubmenuIndexSettings);
+ scene_manager_next_scene(app->scene_manager, Meal_PagerSceneSettings);
+ return true;
+ }
+ }
+ return false;
+}
+
+void meal_pager_scene_menu_on_exit(void* context) {
+ Meal_Pager* app = context;
+ submenu_reset(app->submenu);
+}
\ No newline at end of file
diff --git a/scenes/meal_pager_scene_settings.c b/scenes/meal_pager_scene_settings.c
new file mode 100644
index 00000000000..76690350b9c
--- /dev/null
+++ b/scenes/meal_pager_scene_settings.c
@@ -0,0 +1,261 @@
+#include "../meal_pager.h"
+#include
+
+enum SettingsIndex {
+ SettingsIndexHaptic = 10,
+ SettingsIndexValue1,
+ SettingsIndexValue2,
+};
+
+const char* const haptic_text[2] = {
+ "OFF",
+ "ON",
+};
+const uint32_t haptic_value[2] = {
+ Meal_PagerHapticOff,
+ Meal_PagerHapticOn,
+};
+
+const char* const pager_type_text[4] = {
+ "T119",
+ "TD157",
+ "TD165",
+ "TD174",
+};
+
+const uint32_t pager_type_value[4] = {
+ Meal_PagerPagerTypeT119,
+ Meal_PagerPagerTypeTD157,
+ Meal_PagerPagerTypeTD165,
+ Meal_PagerPagerTypeTD174,
+};
+
+const char* const speaker_text[2] = {
+ "OFF",
+ "ON",
+};
+const uint32_t speaker_value[2] = {
+ Meal_PagerSpeakerOff,
+ Meal_PagerSpeakerOn,
+};
+
+const char* const led_text[2] = {
+ "OFF",
+ "ON",
+};
+const uint32_t led_value[2] = {
+ Meal_PagerLedOff,
+ Meal_PagerLedOn,
+};
+
+const char* const settings_text[2] = {
+ "OFF",
+ "ON",
+};
+const uint32_t settings_value[2] = {
+ Meal_PagerSettingsOff,
+ Meal_PagerSettingsOn,
+};
+
+static void meal_pager_scene_settings_set_pager_type(VariableItem* item) {
+ Meal_Pager* app = variable_item_get_context(item);
+ uint8_t index = variable_item_get_current_value_index(item);
+
+ variable_item_set_current_value_text(item, pager_type_text[index]);
+ app->pager_type = pager_type_value[index];
+}
+
+static void meal_pager_scene_settings_set_first_station(VariableItem* item) {
+ Meal_Pager* app = variable_item_get_context(item);
+ uint32_t index = variable_item_get_current_value_index(item);
+
+ snprintf(app->first_station_char, 20, "%lu", index);
+ variable_item_set_current_value_text(item, app->first_station_char);
+ app->first_station = index;
+}
+
+static void meal_pager_scene_settings_set_last_station(VariableItem* item) {
+ Meal_Pager* app = variable_item_get_context(item);
+ uint32_t index = variable_item_get_current_value_index(item);
+
+ snprintf(app->last_station_char, 20, "%lu", index);
+ variable_item_set_current_value_text(item, app->last_station_char);
+ app->last_station = index;
+}
+
+static void meal_pager_scene_settings_set_first_pager(VariableItem* item) {
+ Meal_Pager* app = variable_item_get_context(item);
+ uint32_t index = variable_item_get_current_value_index(item);
+
+ snprintf(app->first_pager_char, 20, "%lu", index);
+ variable_item_set_current_value_text(item, app->first_pager_char);
+ app->first_pager = index;
+}
+
+static void meal_pager_scene_settings_set_last_pager(VariableItem* item) {
+ Meal_Pager* app = variable_item_get_context(item);
+ uint32_t index = variable_item_get_current_value_index(item);
+
+ snprintf(app->last_pager_char, 20, "%lu", index);
+ variable_item_set_current_value_text(item, app->last_pager_char);
+ app->last_pager = index;
+}
+
+static void meal_pager_scene_settings_set_haptic(VariableItem* item) {
+ Meal_Pager* app = variable_item_get_context(item);
+ uint8_t index = variable_item_get_current_value_index(item);
+
+ variable_item_set_current_value_text(item, haptic_text[index]);
+ app->haptic = haptic_value[index];
+}
+
+static void meal_pager_scene_settings_set_speaker(VariableItem* item) {
+ Meal_Pager* app = variable_item_get_context(item);
+ uint8_t index = variable_item_get_current_value_index(item);
+ variable_item_set_current_value_text(item, speaker_text[index]);
+ app->speaker = speaker_value[index];
+}
+
+static void meal_pager_scene_settings_set_led(VariableItem* item) {
+ Meal_Pager* app = variable_item_get_context(item);
+ uint8_t index = variable_item_get_current_value_index(item);
+ variable_item_set_current_value_text(item, led_text[index]);
+ app->led = led_value[index];
+}
+
+static void meal_pager_scene_settings_set_save_settings(VariableItem* item) {
+ Meal_Pager* app = variable_item_get_context(item);
+ uint8_t index = variable_item_get_current_value_index(item);
+ variable_item_set_current_value_text(item, settings_text[index]);
+ app->save_settings = settings_value[index];
+}
+
+void meal_pager_scene_settings_submenu_callback(void* context, uint32_t index) {
+ Meal_Pager* app = context;
+ view_dispatcher_send_custom_event(app->view_dispatcher, index);
+}
+
+void meal_pager_scene_settings_on_enter(void* context) {
+ Meal_Pager* app = context;
+ VariableItem* item;
+ uint8_t value_index;
+
+ // Pager Type
+ item = variable_item_list_add(
+ app->variable_item_list,
+ "Pager Type:",
+ 4,
+ meal_pager_scene_settings_set_pager_type,
+ app);
+ value_index = value_index_uint32(app->pager_type, pager_type_value, 4);
+ variable_item_set_current_value_index(item, value_index);
+ variable_item_set_current_value_text(item, pager_type_text[value_index]);
+
+ // First Station
+ item = variable_item_list_add(
+ app->variable_item_list,
+ "First Station",
+ 255,
+ meal_pager_scene_settings_set_first_station,
+ app);
+ variable_item_set_current_value_index(item, app->first_station);
+ snprintf(app->first_pager_char, 20, "%lu", app->first_station);
+ variable_item_set_current_value_text(item, app->first_station_char);
+
+ // Last Station
+ item = variable_item_list_add(
+ app->variable_item_list,
+ "Last Station",
+ 255,
+ meal_pager_scene_settings_set_last_station,
+ app);
+ variable_item_set_current_value_index(item, app->last_station);
+ snprintf(app->last_station_char, 20, "%lu", app->last_station);
+ variable_item_set_current_value_text(item, app->last_station_char);
+
+ // First Pager
+ item = variable_item_list_add(
+ app->variable_item_list,
+ "First Pager",
+ 99,
+ meal_pager_scene_settings_set_first_pager,
+ app);
+ variable_item_set_current_value_index(item, app->first_pager);
+ snprintf(app->first_pager_char, 20, "%lu", app->first_pager);
+ variable_item_set_current_value_text(item, app->first_pager_char);
+
+ // Last Pager
+ item = variable_item_list_add(
+ app->variable_item_list,
+ "Last Pager",
+ 99,
+ meal_pager_scene_settings_set_last_pager,
+ app);
+ variable_item_set_current_value_index(item, app->last_pager);
+ snprintf(app->last_pager_char, 20, "%lu", app->last_pager);
+ variable_item_set_current_value_text(item, app->last_pager_char);
+
+ // Repeat Attacks
+
+ // Vibro on/off
+ item = variable_item_list_add(
+ app->variable_item_list,
+ "Vibro/Haptic:",
+ 2,
+ meal_pager_scene_settings_set_haptic,
+ app);
+ value_index = value_index_uint32(app->haptic, haptic_value, 2);
+ variable_item_set_current_value_index(item, value_index);
+ variable_item_set_current_value_text(item, haptic_text[value_index]);
+
+ // Sound on/off
+ item = variable_item_list_add(
+ app->variable_item_list,
+ "Sound:",
+ 2,
+ meal_pager_scene_settings_set_speaker,
+ app);
+ value_index = value_index_uint32(app->speaker, speaker_value, 2);
+ variable_item_set_current_value_index(item, value_index);
+ variable_item_set_current_value_text(item, speaker_text[value_index]);
+
+ // LED Effects on/off
+ item = variable_item_list_add(
+ app->variable_item_list,
+ "LED FX:",
+ 2,
+ meal_pager_scene_settings_set_led,
+ app);
+ value_index = value_index_uint32(app->led, led_value, 2);
+ variable_item_set_current_value_index(item, value_index);
+ variable_item_set_current_value_text(item, led_text[value_index]);
+
+ // Save Settings to File
+ item = variable_item_list_add(
+ app->variable_item_list,
+ "Save Settings",
+ 2,
+ meal_pager_scene_settings_set_save_settings,
+ app);
+ value_index = value_index_uint32(app->save_settings, settings_value, 2);
+ variable_item_set_current_value_index(item, value_index);
+ variable_item_set_current_value_text(item, settings_text[value_index]);
+
+ view_dispatcher_switch_to_view(app->view_dispatcher, Meal_PagerViewIdSettings);
+}
+
+bool meal_pager_scene_settings_on_event(void* context, SceneManagerEvent event) {
+ Meal_Pager* app = context;
+ UNUSED(app);
+ bool consumed = false;
+ if(event.type == SceneManagerEventTypeCustom) {
+
+ }
+ return consumed;
+}
+
+void meal_pager_scene_settings_on_exit(void* context) {
+ Meal_Pager* app = context;
+ variable_item_list_set_selected_item(app->variable_item_list, 0);
+ variable_item_list_reset(app->variable_item_list);
+}
\ No newline at end of file
diff --git a/scenes/meal_pager_scene_startscreen.c b/scenes/meal_pager_scene_startscreen.c
new file mode 100644
index 00000000000..7580a65b4b2
--- /dev/null
+++ b/scenes/meal_pager_scene_startscreen.c
@@ -0,0 +1,54 @@
+#include "../meal_pager.h"
+#include "../helpers/meal_pager_custom_event.h"
+#include "../views/meal_pager_startscreen.h"
+
+void meal_pager_scene_startscreen_callback(Meal_PagerCustomEvent event, void* context) {
+ furi_assert(context);
+ Meal_Pager* app = context;
+ view_dispatcher_send_custom_event(app->view_dispatcher, event);
+}
+
+void meal_pager_scene_startscreen_on_enter(void* context) {
+ furi_assert(context);
+ Meal_Pager* app = context;
+ meal_pager_startscreen_set_callback(app->meal_pager_startscreen, meal_pager_scene_startscreen_callback, app);
+ view_dispatcher_switch_to_view(app->view_dispatcher, Meal_PagerViewIdStartscreen);
+}
+
+bool meal_pager_scene_startscreen_on_event(void* context, SceneManagerEvent event) {
+ Meal_Pager* app = context;
+ bool consumed = false;
+
+ if(event.type == SceneManagerEventTypeCustom) {
+ switch(event.event) {
+ case Meal_PagerCustomEventStartscreenLeft:
+ case Meal_PagerCustomEventStartscreenRight:
+ break;
+ case Meal_PagerCustomEventStartscreenUp:
+ case Meal_PagerCustomEventStartscreenDown:
+ break;
+ case Meal_PagerCustomEventStartscreenOk:
+ scene_manager_next_scene(app->scene_manager, Meal_PagerSceneMenu);
+ consumed = true;
+ break;
+ case Meal_PagerCustomEventStartscreenBack:
+ notification_message(app->notification, &sequence_reset_red);
+ notification_message(app->notification, &sequence_reset_green);
+ notification_message(app->notification, &sequence_reset_blue);
+ if(!scene_manager_search_and_switch_to_previous_scene(
+ app->scene_manager, Meal_PagerSceneStartscreen)) {
+ scene_manager_stop(app->scene_manager);
+ view_dispatcher_stop(app->view_dispatcher);
+ }
+ consumed = true;
+ break;
+ }
+ }
+
+ return consumed;
+}
+
+void meal_pager_scene_startscreen_on_exit(void* context) {
+ Meal_Pager* app = context;
+ UNUSED(app);
+}
\ No newline at end of file
diff --git a/scenes/meal_pager_scene_transmit.c b/scenes/meal_pager_scene_transmit.c
new file mode 100644
index 00000000000..eab069af465
--- /dev/null
+++ b/scenes/meal_pager_scene_transmit.c
@@ -0,0 +1,57 @@
+#include "../meal_pager.h"
+#include "../helpers/meal_pager_custom_event.h"
+#include "../helpers/retekess/meal_pager_retekess_t119.h"
+#include "../views/meal_pager_transmit.h"
+
+void meal_pager_transmit_callback(Meal_PagerCustomEvent event, void* context) {
+ furi_assert(context);
+ Meal_Pager* app = context;
+ view_dispatcher_send_custom_event(app->view_dispatcher, event);
+}
+
+void meal_pager_scene_transmit_on_enter(void* context) {
+ furi_assert(context);
+ Meal_Pager* app = context;
+ FURI_LOG_D(TAG, "Type is %lu", app->pager_type);
+
+ meal_pager_transmit_model_set_type(app->meal_pager_transmit, app->pager_type);
+ meal_pager_transmit_model_set_station(app->meal_pager_transmit, app->current_station);
+ meal_pager_transmit_model_set_pager(app->meal_pager_transmit, app->current_pager);
+ meal_pager_transmit_set_callback(app->meal_pager_transmit, meal_pager_transmit_callback, app);
+ view_dispatcher_switch_to_view(app->view_dispatcher, Meal_PagerViewIdTransmit);
+ meal_pager_retekess_t119_generate_all(app);
+}
+
+bool meal_pager_scene_transmit_on_event(void* context, SceneManagerEvent event) {
+ Meal_Pager* app = context;
+ bool consumed = false;
+
+ if(event.type == SceneManagerEventTypeCustom) {
+ switch(event.event) {
+ case Meal_PagerCustomEventTransmitLeft:
+ case Meal_PagerCustomEventTransmitRight:
+ break;
+ case Meal_PagerCustomEventTransmitUp:
+ case Meal_PagerCustomEventTransmitDown:
+ break;
+ case Meal_PagerCustomEventTransmitBack:
+ notification_message(app->notification, &sequence_reset_red);
+ notification_message(app->notification, &sequence_reset_green);
+ notification_message(app->notification, &sequence_reset_blue);
+ if(!scene_manager_search_and_switch_to_previous_scene(
+ app->scene_manager, Meal_PagerSceneMenu)) {
+ scene_manager_stop(app->scene_manager);
+ view_dispatcher_stop(app->view_dispatcher);
+ }
+ consumed = true;
+ break;
+ }
+ }
+
+ return consumed;
+}
+
+void meal_pager_scene_transmit_on_exit(void* context) {
+ Meal_Pager* app = context;
+ UNUSED(app);
+}
\ No newline at end of file
diff --git a/views/meal_pager_startscreen.c b/views/meal_pager_startscreen.c
new file mode 100644
index 00000000000..1e26b56707e
--- /dev/null
+++ b/views/meal_pager_startscreen.c
@@ -0,0 +1,136 @@
+#include "../meal_pager.h"
+#include
+#include
+#include
+#include
+
+struct Meal_PagerStartscreen {
+ View* view;
+ Meal_PagerStartscreenCallback callback;
+ void* context;
+};
+
+
+typedef struct {
+ int some_value;
+} Meal_PagerStartscreenModel;
+
+void meal_pager_startscreen_set_callback(
+ Meal_PagerStartscreen* instance,
+ Meal_PagerStartscreenCallback callback,
+ void* context) {
+ furi_assert(instance);
+ furi_assert(callback);
+ instance->callback = callback;
+ instance->context = context;
+}
+
+void meal_pager_startscreen_draw(Canvas* canvas, Meal_PagerStartscreenModel* model) {
+ UNUSED(model);
+ canvas_clear(canvas);
+ canvas_set_color(canvas, ColorBlack);
+ canvas_set_font(canvas, FontPrimary);
+ canvas_draw_str_aligned(canvas, 64, 10, AlignCenter, AlignTop, "Restaurant Pager");
+ canvas_set_font(canvas, FontSecondary);
+ canvas_draw_str_aligned(canvas, 64, 22, AlignCenter, AlignTop, "Trigger Tool");
+ elements_button_center(canvas, "Start");
+}
+
+static void meal_pager_startscreen_model_init(Meal_PagerStartscreenModel* const model) {
+ model->some_value = 1;
+}
+
+bool meal_pager_startscreen_input(InputEvent* event, void* context) {
+ furi_assert(context);
+ Meal_PagerStartscreen* instance = context;
+ if (event->type == InputTypeRelease) {
+ switch(event->key) {
+ case InputKeyBack:
+ with_view_model(
+ instance->view,
+ Meal_PagerStartscreenModel * model,
+ {
+ UNUSED(model);
+ instance->callback(Meal_PagerCustomEventStartscreenBack, instance->context);
+ },
+ true);
+ break;
+ case InputKeyLeft:
+ case InputKeyRight:
+ case InputKeyUp:
+ case InputKeyDown:
+ case InputKeyOk:
+ with_view_model(
+ instance->view,
+ Meal_PagerStartscreenModel* model,
+ {
+ UNUSED(model);
+ instance->callback(Meal_PagerCustomEventStartscreenOk, instance->context);
+ },
+ true);
+ break;
+ case InputKeyMAX:
+ break;
+ }
+ }
+ return true;
+}
+
+void meal_pager_startscreen_exit(void* context) {
+ furi_assert(context);
+}
+
+void meal_pager_startscreen_enter(void* context) {
+ furi_assert(context);
+ Meal_PagerStartscreen* instance = (Meal_PagerStartscreen*)context;
+ with_view_model(
+ instance->view,
+ Meal_PagerStartscreenModel * model,
+ {
+ meal_pager_startscreen_model_init(model);
+ },
+ true
+ );
+}
+
+Meal_PagerStartscreen* meal_pager_startscreen_alloc() {
+ Meal_PagerStartscreen* instance = malloc(sizeof(Meal_PagerStartscreen));
+ instance->view = view_alloc();
+ view_allocate_model(instance->view, ViewModelTypeLocking, sizeof(Meal_PagerStartscreenModel));
+ view_set_context(instance->view, instance); // furi_assert crashes in events without this
+ view_set_draw_callback(instance->view, (ViewDrawCallback)meal_pager_startscreen_draw);
+ view_set_input_callback(instance->view, meal_pager_startscreen_input);
+ //view_set_enter_callback(instance->view, meal_pager_startscreen_enter);
+ //view_set_exit_callback(instance->view, meal_pager_startscreen_exit);
+
+ with_view_model(
+ instance->view,
+ Meal_PagerStartscreenModel * model,
+ {
+ meal_pager_startscreen_model_init(model);
+ },
+ true
+ );
+
+ return instance;
+}
+
+void meal_pager_startscreen_free(Meal_PagerStartscreen* instance) {
+ furi_assert(instance);
+
+ with_view_model(
+ instance->view,
+ Meal_PagerStartscreenModel * model,
+ {
+ UNUSED(model);
+ },
+ true);
+ view_free(instance->view);
+ free(instance);
+}
+
+View* meal_pager_startscreen_get_view(Meal_PagerStartscreen* instance) {
+ furi_assert(instance);
+ return instance->view;
+}
+
diff --git a/views/meal_pager_startscreen.h b/views/meal_pager_startscreen.h
new file mode 100644
index 00000000000..32bf6f57e28
--- /dev/null
+++ b/views/meal_pager_startscreen.h
@@ -0,0 +1,19 @@
+#pragma once
+
+#include
+#include "../helpers/meal_pager_custom_event.h"
+
+typedef struct Meal_PagerStartscreen Meal_PagerStartscreen;
+
+typedef void (*Meal_PagerStartscreenCallback)(Meal_PagerCustomEvent event, void* context);
+
+void meal_pager_startscreen_set_callback(
+ Meal_PagerStartscreen* meal_pager_startscreen,
+ Meal_PagerStartscreenCallback callback,
+ void* context);
+
+View* meal_pager_startscreen_get_view(Meal_PagerStartscreen* meal_pager_static);
+
+Meal_PagerStartscreen* meal_pager_startscreen_alloc();
+
+void meal_pager_startscreen_free(Meal_PagerStartscreen* meal_pager_static);
\ No newline at end of file
diff --git a/views/meal_pager_transmit.c b/views/meal_pager_transmit.c
new file mode 100644
index 00000000000..26a0a1630a1
--- /dev/null
+++ b/views/meal_pager_transmit.c
@@ -0,0 +1,195 @@
+#include "../meal_pager.h"
+#include
+#include
+#include
+#include
+#include
+
+const char* const pager_type_text_long[4] = {
+ "Retekess T119",
+ "Retekess TD157",
+ "Retekess TD165",
+ "Retekess TD174",
+};
+
+struct Meal_PagerTransmit {
+ View* view;
+ Meal_PagerTransmitCallback callback;
+ void* context;
+};
+
+
+typedef struct {
+ uint32_t pager_type;
+ uint32_t station;
+ uint32_t pager;
+} Meal_PagerTransmitModel;
+
+void meal_pager_transmit_set_callback(
+ Meal_PagerTransmit* instance,
+ Meal_PagerTransmitCallback callback,
+ void* context) {
+ furi_assert(instance);
+ furi_assert(callback);
+ instance->callback = callback;
+ instance->context = context;
+}
+
+void meal_pager_transmit_draw(Canvas* canvas, Meal_PagerTransmitModel* model) {
+ UNUSED(model);
+ canvas_clear(canvas);
+ canvas_set_color(canvas, ColorBlack);
+ canvas_set_font(canvas, FontPrimary);
+ //char* test = "";
+ //snprintf(test, 20, "%lu", model->pager_type);
+ char stationText[20] = "";
+ char pagerText[20] = "";
+ snprintf(stationText, 20, "Station: %lu", model->station);
+ snprintf(pagerText, 20, "Pager: %lu", model->pager);
+ canvas_draw_str_aligned(canvas, 0, 10, AlignLeft, AlignTop, pager_type_text_long[model->pager_type]);
+ canvas_set_font(canvas, FontSecondary);
+ canvas_draw_str_aligned(canvas, 0, 22, AlignLeft, AlignTop, stationText);
+ canvas_draw_str_aligned(canvas, 0, 32, AlignLeft, AlignTop, pagerText);
+}
+
+static void meal_pager_transmit_model_init(Meal_PagerTransmitModel* const model) {
+ FURI_LOG_D(TAG, "Scene 1 Model Init");
+ model->pager_type = 0;
+ model->station = 0;
+ model->pager = 0;
+}
+
+void meal_pager_transmit_model_set_type(Meal_PagerTransmit* instance, uint32_t type) {
+ furi_assert(instance);
+ Meal_PagerTransmitModel* model = view_get_model(instance->view);
+ model->pager_type = type;
+ view_commit_model(instance->view, false);
+}
+
+void meal_pager_transmit_model_set_station(Meal_PagerTransmit* instance, uint32_t station) {
+ furi_assert(instance);
+ Meal_PagerTransmitModel* model = view_get_model(instance->view);
+ model->station = station;
+ view_commit_model(instance->view, false);
+ with_view_model(
+ instance->view,
+ Meal_PagerTransmitModel* model,
+ {
+ UNUSED(model);
+ },
+ true);
+}
+
+void meal_pager_transmit_model_set_pager(Meal_PagerTransmit* instance, uint32_t pager) {
+ furi_assert(instance);
+ Meal_PagerTransmitModel* model = view_get_model(instance->view);
+ model->pager = pager;
+ view_commit_model(instance->view, false);
+ with_view_model(
+ instance->view,
+ Meal_PagerTransmitModel* model,
+ {
+ UNUSED(model);
+ },
+ true);
+}
+
+bool meal_pager_transmit_input(InputEvent* event, void* context) {
+ furi_assert(context);
+ Meal_PagerTransmit* instance = context;
+ if (event->type == InputTypeRelease) {
+ switch(event->key) {
+ case InputKeyBack:
+ with_view_model(
+ instance->view,
+ Meal_PagerTransmitModel * model,
+ {
+ UNUSED(model);
+ instance->callback(Meal_PagerCustomEventTransmitBack, instance->context);
+ },
+ true);
+ break;
+ case InputKeyLeft:
+ case InputKeyRight:
+ case InputKeyUp:
+ case InputKeyDown:
+ case InputKeyOk:
+ with_view_model(
+ instance->view,
+ Meal_PagerTransmitModel* model,
+ {
+ UNUSED(model);
+ },
+ true);
+ break;
+ case InputKeyMAX:
+ break;
+ }
+ }
+ return true;
+}
+
+void meal_pager_transmit_exit(void* context) {
+ furi_assert(context);
+ FURI_LOG_D(TAG, "Scene 1 Exit");
+}
+
+void meal_pager_transmit_enter(void* context) {
+ FURI_LOG_D(TAG, "Scene 1 Enter");
+ furi_assert(context);
+ Meal_PagerTransmit* instance = (Meal_PagerTransmit*)context;
+ with_view_model(
+ instance->view,
+ Meal_PagerTransmitModel * model,
+ {
+ UNUSED(model);
+ },
+ true
+ );
+}
+
+Meal_PagerTransmit* meal_pager_transmit_alloc(void* context) {
+ FURI_LOG_D(TAG, "Scene 1 Alloc");
+ furi_assert(context);
+ Meal_PagerTransmit* instance = malloc(sizeof(Meal_PagerTransmit));
+ instance->view = view_alloc();
+ view_allocate_model(instance->view, ViewModelTypeLocking, sizeof(Meal_PagerTransmitModel));
+ view_set_context(instance->view, instance); // furi_assert crashes in events without this
+ view_set_draw_callback(instance->view, (ViewDrawCallback)meal_pager_transmit_draw);
+ view_set_input_callback(instance->view, meal_pager_transmit_input);
+ view_set_enter_callback(instance->view, meal_pager_transmit_enter);
+ view_set_exit_callback(instance->view, meal_pager_transmit_exit);
+
+ with_view_model(
+ instance->view,
+ Meal_PagerTransmitModel * model,
+ {
+ meal_pager_transmit_model_init(model);
+ //meal_pager_transmit_model_set_type(instance, 0);
+ },
+ true
+ );
+
+ return instance;
+}
+
+void meal_pager_transmit_free(Meal_PagerTransmit* instance) {
+ FURI_LOG_D(TAG, "Transmit Free");
+ furi_assert(instance);
+
+ with_view_model(
+ instance->view,
+ Meal_PagerTransmitModel * model,
+ {
+ UNUSED(model);
+ },
+ true);
+ view_free(instance->view);
+ free(instance);
+}
+
+View* meal_pager_transmit_get_view(Meal_PagerTransmit* instance) {
+ furi_assert(instance);
+ return instance->view;
+}
+
diff --git a/views/meal_pager_transmit.h b/views/meal_pager_transmit.h
new file mode 100644
index 00000000000..d7f930d0737
--- /dev/null
+++ b/views/meal_pager_transmit.h
@@ -0,0 +1,24 @@
+#pragma once
+
+#include
+#include "../helpers/meal_pager_custom_event.h"
+
+typedef struct Meal_PagerTransmit Meal_PagerTransmit;
+
+typedef void (*Meal_PagerTransmitCallback)(Meal_PagerCustomEvent event, void* context);
+
+void meal_pager_transmit_set_callback(
+ Meal_PagerTransmit* meal_pager_transmit,
+ Meal_PagerTransmitCallback callback,
+ void* context);
+
+void meal_pager_transmit_model_set_type(Meal_PagerTransmit* instance, uint32_t type);
+void meal_pager_transmit_model_set_station(Meal_PagerTransmit* instance, uint32_t station);
+void meal_pager_transmit_model_set_pager(Meal_PagerTransmit* instance, uint32_t pager);
+
+
+View* meal_pager_transmit_get_view(Meal_PagerTransmit* meal_pager_static);
+
+Meal_PagerTransmit* meal_pager_transmit_alloc();
+
+void meal_pager_transmit_free(Meal_PagerTransmit* meal_pager_static);
\ No newline at end of file