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 + + + + + + + +
+ +
+

RETEKESS T119

+
+ +
+
+

SIGNAL

+
+
+
+
+ + +
+
+
+
+
+ +
+
+
+ Put here the hex key you got from the read. +
+
+ +
+
+

KEY FILE

+
+
+
+ + +
+
+ + +
+
+ + +
+
+
+
+ +
+
+
+ This single key file will call a single pager. +
+
+ +
+
+

RAW FILE

+
+
+
+
+ + +
+
+ + +
+
+
+
+ + +
+
+ + +
+
+
+
+ + +
+
+
+
+
+ +
+
+
+ This combo raw file will call multiple pagers. +
+
+ +
+
+

TURN-OFF FILE

+
+
+
+
+ + + +
+
+
+
+ This special action file will turn off all the pagers of a given station. +
+
+ +
+
+

BRUTEFORCE FILES

+
+
+
+ +
+
+
+ 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