Merge remote-tracking branch 'mntm/dev' into kiisu-mntm

This commit is contained in:
WillyJL
2025-08-05 01:12:18 +02:00
33 changed files with 1789 additions and 1192 deletions
+1 -1
View File
@@ -61,7 +61,7 @@ if __name__ == "__main__":
"name": "Firmware Artifacts:",
"value": "\n".join(
[
f"- [🖥️ Install with Web Updater](https://momentum-fw.dev/update)",
f"- [🖥️ Install with Web Updater](https://momentum-fw.dev/update?version={os.environ['VERSION_TAG'].removeprefix('mntm-dev-')})",
f"- [☁️ Open in Flipper Lab/App]({artifact_lab})",
f"- [🐬 Download Firmware TGZ]({artifact_tgz})",
f"- [🛠️ SDK (for development)]({artifact_sdk})",
+1 -1
View File
@@ -1,5 +1,5 @@
## ⬇️ Download
>### [🖥️ Web Updater (chrome)](https://momentum-fw.dev/update) [recommended]
>### [🖥️ Web Updater (chrome)](https://momentum-fw.dev/update?version={VERSION_TAG}) [recommended]
>### [☁️ Flipper Lab/App (chrome/mobile)](https://lab.flipper.net/?url=https://up.momentum-fw.dev/builds/firmware/{VERSION_TAG}/flipper-z-f7-update-{VERSION_TAG}.tgz&channel=release-cfw&version={VERSION_TAG})
+28 -13
View File
@@ -20,13 +20,15 @@ if __name__ == "__main__":
webhook = "BUILD_WEBHOOK"
count = len(event["commits"])
if count == 20:
count = int(requests.get(
event["compare"].replace("github.com", "api.github.com/repos"),
headers={
"Accept": "application/vnd.github.v3+json",
"Authorization": f"token {os.environ['GITHUB_TOKEN']}"
}
).json()["total_commits"])
count = int(
requests.get(
event["compare"].replace("github.com", "api.github.com/repos"),
headers={
"Accept": "application/vnd.github.v3+json",
"Authorization": f"token {os.environ['GITHUB_TOKEN']}",
},
).json()["total_commits"]
)
branch = event["ref"].removeprefix("refs/heads/")
change = (
"Force Push"
@@ -35,7 +37,12 @@ if __name__ == "__main__":
)
desc = f"[**{change}**]({event['compare']}) | [{branch}]({event['repository']['html_url']}/tree/{branch})\n"
for i, commit in enumerate(event["commits"]):
msg = commit['message'].splitlines()[0].replace("`", "").replace("_", "\_")
msg = (
commit["message"]
.splitlines()[0]
.replace("`", "")
.replace("_", "\_")
)
msg = msg[:50] + ("..." if len(msg) > 50 else "")
desc += f"\n[`{commit['id'][:8]}`]({commit['url']}): {msg} - [__{commit['author'].get('username')}__](https://github.com/{commit['author'].get('username')})"
if len(desc) > 2020:
@@ -47,9 +54,9 @@ if __name__ == "__main__":
case "release":
webhook = "RELEASE_WEBHOOK"
color = 9471191
version_tag = event['release']['tag_name']
version_tag = event["release"]["tag_name"]
title = f"New Release: `{version_tag}`!"
desc += f"> 💻 [**Web Installer**](https://momentum-fw.dev/update)\n\n"
desc += f"> 💻 [**Web Installer**](https://momentum-fw.dev/update?version={version_tag})\n\n"
desc += f"> 🐬 [**Changelog & Download**](https://github.com/Next-Flip/Momentum-Firmware/releases/tag/{version_tag})\n\n"
desc += f"> 🛞 [**Project Page**](https://github.com/Next-Flip/Momentum-Firmware)"
@@ -75,7 +82,11 @@ if __name__ == "__main__":
title = f"Issue {event['action'].title()}: {name}"
match event["action"]:
case "opened":
desc = (issue["body"][:2045] + "...") if len(issue["body"]) > 2048 else issue["body"]
desc = (
(issue["body"][:2045] + "...")
if len(issue["body"]) > 2048
else issue["body"]
)
color = 3669797
case "closed":
color = 16723712
@@ -90,7 +101,11 @@ if __name__ == "__main__":
url = comment["html_url"]
title = f"New Comment on Issue: {issue['title']}"
color = 3669797
desc = (comment["body"][:2045] + "...") if len(comment["body"]) > 2048 else comment["body"]
desc = (
(comment["body"][:2045] + "...")
if len(comment["body"]) > 2048
else comment["body"]
)
case _:
sys.exit(1)
@@ -112,7 +127,7 @@ if __name__ == "__main__":
"url": event["sender"]["html_url"],
"icon_url": event["sender"]["avatar_url"],
},
"timestamp": dt.datetime.utcnow().isoformat()
"timestamp": dt.datetime.utcnow().isoformat(),
}
],
"attachments": [],
+39 -20
View File
@@ -76,6 +76,29 @@ jobs:
exit 1
fi
- name: "Configure for Devbuild/PR/Upload"
run: |
if ${{ secrets.INDEXER_URL == '' }} ; then
exit
fi
if ${{ github.event_name == 'push' }} ; then
if ${{ github.ref_name == 'dev' }} ; then
SHOULD_DEVBUILD=${{ !contains(github.event.head_commit.message, '--nobuild') }}
SHOULD_UPLOAD=$SHOULD_DEVBUILD
elif ${{ startsWith(github.ref, 'refs/tags/') }} ; then
SHOULD_UPLOAD=true
fi
elif ${{ !!github.event.pull_request }} ; then
SHOULD_PRCOMMENT=${{ matrix.target == env.DEFAULT_TARGET }}
SHOULD_UPLOAD=true
else
echo "What?"
exit 1
fi
echo "SHOULD_DEVBUILD=$SHOULD_DEVBUILD" >> $GITHUB_ENV
echo "SHOULD_PRCOMMENT=$SHOULD_PRCOMMENT" >> $GITHUB_ENV
echo "SHOULD_UPLOAD=$SHOULD_UPLOAD" >> $GITHUB_ENV
- name: "Build the firmware and apps"
id: build-fw
run: |
@@ -94,9 +117,7 @@ jobs:
dist/${{ env.TARGET }}-*/flipper-z-${{ env.TARGET }}-sdk-*
- name: "Copy build output"
env:
INDEXER_URL: ${{ secrets.INDEXER_URL }}
if: ${{ env.INDEXER_URL != '' && (github.event.pull_request || (github.event_name == 'push' && ((github.ref_name == 'dev' && !contains(github.event.head_commit.message, '--nobuild')) || startsWith(github.ref, 'refs/tags/')))) }}
if: ${{ env.SHOULD_UPLOAD == 'true' }}
run: |
set -e
rm -rf artifacts || true
@@ -112,17 +133,13 @@ jobs:
echo "VERSION_TAG=$VERSION_TAG" >> $GITHUB_ENV
- name: "Copy universal artifacts"
env:
INDEXER_URL: ${{ secrets.INDEXER_URL }}
if: ${{ env.INDEXER_URL != '' && (github.event.pull_request || (github.event_name == 'push' && ((github.ref_name == 'dev' && !contains(github.event.head_commit.message, '--nobuild')) || startsWith(github.ref, 'refs/tags/')))) }}
if: ${{ env.SHOULD_UPLOAD == 'true' }}
run: |
tar czpf "artifacts/flipper-z-any-scripts-${SUFFIX}.tgz" scripts
cp build/core2_firmware.tgz "artifacts/flipper-z-any-core2_firmware-${SUFFIX}.tgz"
- name: "Calculate DFU sizes"
env:
INDEXER_URL: ${{ secrets.INDEXER_URL }}
if: ${{ env.INDEXER_URL != '' && github.event.pull_request && matrix.target == env.DEFAULT_TARGET }}
if: ${{ env.SHOULD_PRCOMMENT == 'true' }}
run: |
curl -L "${{ secrets.INDEXER_URL }}"/firmware/development/f7/full_dfu -o dev.dfu
dfu_size_new=$(du --apparent-size -B 1 artifacts/flipper-z-${TARGET}-full-*.dfu | cut -f1)
@@ -145,9 +162,7 @@ jobs:
echo "FLASH_USABLE=$FLASH_USABLE" >> $GITHUB_ENV
- name: "Upload artifacts to update server"
env:
INDEXER_URL: ${{ secrets.INDEXER_URL }}
if: ${{ env.INDEXER_URL != '' && (github.event.pull_request || (github.event_name == 'push' && ((github.ref_name == 'dev' && !contains(github.event.head_commit.message, '--nobuild')) || startsWith(github.ref, 'refs/tags/')))) }}
if: ${{ env.SHOULD_UPLOAD == 'true' }}
run: |
curl "${{ secrets.INDEXER_URL }}"/firmware/directory.json > previndex.json
FILES=$(for ARTIFACT in $(find artifacts -maxdepth 1 -not -type d); do echo "-F files=@${ARTIFACT}"; done)
@@ -157,10 +172,16 @@ jobs:
${FILES[@]} \
"${{ secrets.INDEXER_URL }}"/firmware/uploadfiles
- name: "Force deploy website to refresh devbuilds"
if: ${{ env.SHOULD_DEVBUILD == 'true' }}
uses: peter-evans/repository-dispatch@v3
with:
token: ${{ secrets.REPO_DISPATCH_TOKEN }}
repository: Next-Flip/v2.momentum-fw.dev
event-type: force-deploy
- name: "Find previous comment"
env:
INDEXER_URL: ${{ secrets.INDEXER_URL }}
if: ${{ env.INDEXER_URL != '' && github.event.pull_request && matrix.target == env.DEFAULT_TARGET }}
if: ${{ env.SHOULD_PRCOMMENT == 'true' }}
uses: peter-evans/find-comment@v3
id: find-comment
with:
@@ -169,9 +190,7 @@ jobs:
body-includes: "Compiled ${{ matrix.target }} firmware for commit"
- name: "Create or update comment"
env:
INDEXER_URL: ${{ secrets.INDEXER_URL }}
if: ${{ env.INDEXER_URL != '' && github.event.pull_request && matrix.target == env.DEFAULT_TARGET }}
if: ${{ env.SHOULD_PRCOMMENT == 'true' }}
uses: peter-evans/create-or-update-comment@v4
with:
comment-id: ${{ steps.find-comment.outputs.comment-id }}
@@ -184,10 +203,10 @@ jobs:
- Free Flash: `${{ env.FLASH_FREE }}` (`${{ env.FLASH_USABLE }}` usable)
edit-mode: replace
- name: Send devbuild webhook
- name: "Send devbuild webhook"
env:
INDEXER_URL: ${{ secrets.INDEXER_URL }}
BUILD_WEBHOOK: ${{ secrets.BUILD_WEBHOOK }}
if: ${{ env.INDEXER_URL != '' && github.event_name == 'push' && github.ref_name == 'dev' && !contains(github.event.head_commit.message, '--nobuild') }}
if: ${{ env.SHOULD_DEVBUILD == 'true' }}
run: |
python .github/workflow_data/devbuild.py
+7
View File
@@ -45,6 +45,13 @@ jobs:
curl --fail -L -H "Token: ${{ secrets.INDEXER_TOKEN }}" \
"${{ secrets.INDEXER_URL }}"/firmware/reindex;
- name: "Force deploy website to refresh releases"
uses: peter-evans/repository-dispatch@v3
with:
token: ${{ secrets.REPO_DISPATCH_TOKEN }}
repository: Next-Flip/v2.momentum-fw.dev
event-type: force-deploy
- name: "Send release notification"
env:
RELEASE_WEBHOOK: ${{ secrets.RELEASE_WEBHOOK }}
+11
View File
@@ -1,4 +1,8 @@
### Added:
- Apps:
- GPIO/GPS: [NMEA] Nearby Files (by @Stichoza)
- NFC: NFC-Eink (by @RebornedBrain)
- Sub-GHz: Sub Analyzer (by @RocketGod-git)
- SubGHz:
- UL: Roger (static 28 bit) with add manually support (by @xMasterX & @mishamyte)
- UL: V2 Phoenix full support (button switch, add manually, counter decrypt/encrypt) (by @xMasterX & @RocketGod-git, original code by @Skorpionm)
@@ -6,6 +10,7 @@
- UL: Nero Radio static parse and display more data (by @xMasterX)
- UL: Marantec protocol implement CRC verification display and add manually support (by @xMasterX & @li0ard, original code by @Skorpionm)
- UL: Keeloq Comunello add manually support (by @xMasterX)
- UL: Add variant of 'Add Manually' menu with manual editing for each value (by @MrLego8-9)
- RFID: Support writing Securakey, Jablotron and FDX-B to EM4305 cards (#434 by @jamisonderek)
- BT Remote: Add Rename Option, simplify Bad KB BLE profile (#439 by @aaronjamt & @WillyJL)
- MNTM Settings:
@@ -13,16 +18,21 @@
- Add Skip Sliding Animations option for Lockscreen (#436 by @aaronjamt)
- Desktop: Add Keybinds support for directories (#331 by @956MB & @WillyJL)
- Input Settings: Add Vibro Trigger option (#429 by @956MB)
- Archive: Support opening and favoriting Picopass files (by @WillyJL)
### Updated:
- Apps:
- Asteroids: Bugfixes, title screen, Drone Buddy power-up (by @SimplyMinimal)
- Combo Cracker: Allow press and hold to change values, add tutorial (by @TAxelAnderson)
- ESP Flasher: Bump Marauder 1.8.3 (by @justcallmekoko)
- FlipDownloader: Added a new option to download GitHub repositories (by @jblanked)
- FlipSocial: C++ rewrite, comments on feed posts, simpler logic and registration (by @jblanked)
- Flipper Blackhat: Add Deauth Broadcast command (by @o7-machinehum)
- KeyCopier: Added Weiser WR3 key format (by @lightos)
- Metroflip: Fix unsupported card crash, RENFE Suma 10 support, GEG Connect AID added, Top Up log parsing and animations, 16 new rail lines, support for parsing area codes, saving function for Suica/Japan Rail IC, bugfixes (by @luu176)
- NFC Playlist: Refactor playlist worker, new settings layout, loop setting, controls to move between items (by @acegoal07)
- Sentry Safe: New interface, settings & help page (by @H4ckd4ddy)
- WiFi Marauder: Support for ESP32Marauder 1.8.x (by @justcallmekoko)
- Sub-GHz:
- UL: Add 868.46 MHz to default subghz freqs list (by @xMasterX)
- UL: Reduce less popular freqs in default hopper preset, make it faster (by @xMasterX)
@@ -34,6 +44,7 @@
- Bad KB: Fix modifier keys with HOLD/RELEASE commands (by @WillyJL)
- Desktop: Fix lock screen hang (#438 by @aaronjamt)
- NFC: Fix incorrect Saflok year formula (#433 by @Eltrick)
- FBT: Fix redundant decl for apps using an icon disabled in API (by @WillyJL)
### Removed:
- Nothing
+3 -2
View File
@@ -86,7 +86,7 @@ In USB mode it also enables additional functionality to spoof the manufacturer a
<h2 align="center">List of changes</h2>
There are too many to name them all, this is a **non-comprehensive** list of the **most notable from an end-user perspective**. For a more detailed list, you can read through the [**changelogs**](https://github.com/Next-Flip/Momentum-Firmware/releases) and commits/code. Also, you can find a **feature comparison with other firmwares** on [our website](https://momentum-fw.dev/#features).
There are too many to name them all, this is a **non-comprehensive** list of the **most notable from an end-user perspective**. For a more detailed list, you can read through the [**changelogs**](https://github.com/Next-Flip/Momentum-Firmware/releases) and commits/code. Also, you can find a **feature comparison with other firmwares** on [our website](https://momentum-fw.dev/).
Note that this repo is always updated with the great work from our friends at [Unleashed](https://github.com/DarkFlippers/unleashed-firmware) and the latest changes from [OFW](https://github.com/flipperdevices/flipperzero-firmware). Below are mentioned only **our** changes that we can actually be credited for, so make sure to check their fantastic additions aswell. And a huge thank you to both teams!
@@ -143,7 +143,8 @@ There are 4 methods to install Momentum, we recommend you use the **Web Updater*
> <li>Make sure qFlipper is closed</li>
> <li>Open the <a href="https://momentum-fw.dev/update">Web Updater</a></li>
> <li>Click <code>Connect</code> and select your Flipper from the list</li>
> <li>Click <code>Flash</code> and wait for the update to complete</li>
> <li>Select which update <code>Channel</code> you prefer from the dropdown</li>
> <li>Click <code>Install</code> and wait for the update to complete</li>
> </ul></details>
> <details><summary><code>Flipper Lab/App (chrome/mobile)</code></summary><ul>
@@ -24,6 +24,7 @@ static const char* const tab_default_paths[] = {
};
static const char* const known_ext[] = {
// clang-format off
[ArchiveFileTypeIButton] = ".ibtn",
[ArchiveFileTypeNFC] = ".nfc",
[ArchiveFileTypeSubGhz] = ".sub",
@@ -36,6 +37,7 @@ static const char* const known_ext[] = {
[ArchiveFileTypeWAV] = ".wav",
[ArchiveFileTypeMag] = ".mag",
[ArchiveFileTypeCrossRemote] = ".xr",
[ArchiveFileTypePicopass] = ".picopass",
[ArchiveFileTypeU2f] = "?",
[ArchiveFileTypeApplication] = ".fap",
[ArchiveFileTypeJS] = ".js",
@@ -46,6 +48,7 @@ static const char* const known_ext[] = {
[ArchiveFileTypeUnknown] = "*",
[ArchiveFileTypeAppOrJs] = ".fap|.js",
[ArchiveFileTypeSetting] = "?",
// clang-format on
};
static const ArchiveFileTypeEnum known_type[] = {
@@ -22,6 +22,7 @@ typedef enum {
ArchiveFileTypeWAV,
ArchiveFileTypeMag,
ArchiveFileTypeCrossRemote,
ArchiveFileTypePicopass,
ArchiveFileTypeU2f,
ArchiveFileTypeUpdateManifest,
ArchiveFileTypeApplication,
@@ -39,6 +39,8 @@ const char* archive_get_flipper_app_name(ArchiveFileTypeEnum file_type) {
return EXT_PATH("apps/GPIO/magspoof.fap");
case ArchiveFileTypeCrossRemote:
return EXT_PATH("apps/Infrared/xremote.fap");
case ArchiveFileTypePicopass:
return EXT_PATH("apps/NFC/picopass.fap");
case ArchiveFileTypeU2f:
return "U2F";
case ArchiveFileTypeUpdateManifest:
@@ -37,6 +37,7 @@ static const Icon* ArchiveItemIcons[] = {
[ArchiveFileTypeWAV] = &I_music_10px,
[ArchiveFileTypeMag] = &I_mag_card_10px,
[ArchiveFileTypeCrossRemote] = &I_xremote_10px,
[ArchiveFileTypePicopass] = &I_125_10px,
[ArchiveFileTypeU2f] = &I_u2f_10px,
[ArchiveFileTypeSetting] = &I_settings_10px,
[ArchiveFileTypeApplication] = &I_Apps_10px,
@@ -73,9 +73,6 @@ typedef enum {
} SubGhzCustomEvent;
typedef enum {
SetTypeFaacSLH_Manual_868,
SetTypeFaacSLH_Manual_433,
SetTypeBFTClone,
SetTypeFaacSLH_868,
SetTypeFaacSLH_433,
SetTypeBFTMitto,
@@ -0,0 +1,723 @@
#include "subghz_gen_info.h"
#include "../helpers/subghz_txrx_create_protocol_key.h"
#include <lib/subghz/protocols/protocol_items.h>
void subghz_gen_info_reset(GenInfo* gen_info) {
furi_assert(gen_info);
memset(gen_info, 0, sizeof(GenInfo));
}
void subghz_scene_set_type_fill_generation_infos(GenInfo* infos_dest, SetType type) {
GenInfo gen_info = {0};
uint64_t key = (uint64_t)rand();
uint64_t gangqi_key;
subghz_txrx_gen_serial_gangqi(&gangqi_key);
uint64_t marantec_key;
subghz_txrx_gen_key_marantec(&marantec_key);
switch(type) {
case SetTypePricenton433:
gen_info = (GenInfo){
.type = GenData,
.mod = "AM650",
.freq = 433920000,
.data.name = SUBGHZ_PROTOCOL_PRINCETON_NAME,
.data.key = (key & 0x00FFFFF0) | 0x4, // btn 0x1, 0x2, 0x4, 0x8
.data.bits = 24,
.data.te = 400};
break;
case SetTypePricenton315:
gen_info = (GenInfo){
.type = GenData,
.mod = "AM650",
.freq = 315000000,
.data.name = SUBGHZ_PROTOCOL_PRINCETON_NAME,
.data.key = (key & 0x00FFFFF0) | 0x4, // btn 0x1, 0x2, 0x4, 0x8
.data.bits = 24,
.data.te = 400};
break;
case SetTypeNiceFlo12bit:
gen_info = (GenInfo){
.type = GenData,
.mod = "AM650",
.freq = 433920000,
.data.name = SUBGHZ_PROTOCOL_NICE_FLO_NAME,
.data.key = (key & 0x00000FF0) | 0x1, // btn 0x1, 0x2, 0x4
.data.bits = 12,
.data.te = 0};
break;
case SetTypeNiceFlo24bit:
gen_info = (GenInfo){
.type = GenData,
.mod = "AM650",
.freq = 433920000,
.data.name = SUBGHZ_PROTOCOL_NICE_FLO_NAME,
.data.key = (key & 0x00FFFFF0) | 0x4, // btn 0x1, 0x2, 0x4, 0x8
.data.bits = 24,
.data.te = 0};
break;
case SetTypeCAME12bit:
gen_info = (GenInfo){
.type = GenData,
.mod = "AM650",
.freq = 433920000,
.data.name = SUBGHZ_PROTOCOL_CAME_NAME,
.data.key = (key & 0x00000FF0) | 0x1, // btn 0x1, 0x2, 0x4
.data.bits = 12,
.data.te = 0};
break;
case SetTypeCAME24bit:
gen_info = (GenInfo){
.type = GenData,
.mod = "AM650",
.freq = 433920000,
.data.name = SUBGHZ_PROTOCOL_CAME_NAME,
.data.key = (key & 0x00FFFFF0) | 0x4, // btn 0x1, 0x2, 0x4, 0x8
.data.bits = 24,
.data.te = 0};
break;
case SetTypeCAME12bit868:
gen_info = (GenInfo){
.type = GenData,
.mod = "AM650",
.freq = 868350000,
.data.name = SUBGHZ_PROTOCOL_CAME_NAME,
.data.key = (key & 0x00000FF0) | 0x1, // btn 0x1, 0x2, 0x4
.data.bits = 12,
.data.te = 0};
break;
case SetTypeCAME24bit868:
gen_info = (GenInfo){
.type = GenData,
.mod = "AM650",
.freq = 868350000,
.data.name = SUBGHZ_PROTOCOL_CAME_NAME,
.data.key = (key & 0x00FFFFF0) | 0x4, // btn 0x1, 0x2, 0x4, 0x8
.data.bits = 24,
.data.te = 0};
break;
case SetTypeRoger_433:
gen_info = (GenInfo){
.type = GenData,
.mod = "AM650",
.freq = 433920000,
.data.name = SUBGHZ_PROTOCOL_ROGER_NAME,
.data.key = (key & 0xFFFF000) | 0x0000101, // button code 0x1 and (crc?) is 0x01
.data.bits = 28,
.data.te = 0};
break;
case SetTypeLinear_300_00:
gen_info = (GenInfo){
.type = GenData,
.mod = "AM650",
.freq = 300000000,
.data.name = SUBGHZ_PROTOCOL_LINEAR_NAME,
.data.key = (key & 0x3FF),
.data.bits = 10,
.data.te = 0};
break;
case SetTypeBETT_433:
gen_info = (GenInfo){
.type = GenData,
.mod = "AM650",
.freq = 433920000,
.data.name = SUBGHZ_PROTOCOL_BETT_NAME,
.data.key = (key & 0x0000FFF0),
.data.bits = 18,
.data.te = 0};
break;
case SetTypeCAMETwee:
gen_info = (GenInfo){
.type = GenData,
.mod = "AM650",
.freq = 433920000,
.data.name = SUBGHZ_PROTOCOL_CAME_TWEE_NAME,
.data.key = 0x003FFF7200000000 | ((key & 0x0FFFFFF0) ^ 0xE0E0E0EE), // ????
.data.bits = 54,
.data.te = 0};
break;
case SetTypeGateTX:
gen_info = (GenInfo){
.type = GenData,
.mod = "AM650",
.freq = 433920000,
.data.name = SUBGHZ_PROTOCOL_GATE_TX_NAME, // btn 0xF, 0xC, 0xA, 0x6 (?)
.data.key = subghz_protocol_blocks_reverse_key((key & 0x00F0FF00) | 0xF0040, 24),
.data.bits = 24,
.data.te = 0};
break;
case SetTypeGangQi_433:
gen_info = (GenInfo){
.type = GenData,
.mod = "AM650",
.freq = 433920000,
.data.name = SUBGHZ_PROTOCOL_GANGQI_NAME, // Add button 0xD arm and crc sum to the end
.data.key = gangqi_key,
.data.bits = 34,
.data.te = 0};
break;
case SetTypeHollarm_433:
gen_info = (GenInfo){
.type = GenData,
.mod = "AM650",
.freq = 433920000,
.data.name = SUBGHZ_PROTOCOL_HOLLARM_NAME, // Add button 0x2 and crc sum to the end
.data.key = (key & 0x000FFF0000) | 0xF0B0002200 |
((((((key & 0x000FFF0000) | 0xF0B0002200) >> 32) & 0xFF) +
((((key & 0x000FFF0000) | 0xF0B0002200) >> 24) & 0xFF) +
((((key & 0x000FFF0000) | 0xF0B0002200) >> 16) & 0xFF) +
((((key & 0x000FFF0000) | 0xF0B0002200) >> 8) & 0xFF)) &
0xFF),
.data.bits = 42,
.data.te = 0};
break;
case SetTypeReversRB2_433:
gen_info = (GenInfo){
.type = GenData,
.mod = "AM650",
.freq = 433920000,
.data.name = SUBGHZ_PROTOCOL_REVERSRB2_NAME, // 64bits no buttons
.data.key = (key & 0x00000FFFFFFFF000) | 0xFFFFF00000000000 | 0x0000000000000A00,
.data.bits = 64,
.data.te = 0};
break;
case SetTypeMarantec24_868:
gen_info = (GenInfo){
.type = GenData,
.mod = "AM650",
.freq = 868350000,
.data.name = SUBGHZ_PROTOCOL_MARANTEC24_NAME, // Add button code 0x8 to the end
.data.key = (key & 0xFFFFF0) | 0x000008,
.data.bits = 24,
.data.te = 0};
break;
case SetTypeMarantec_433:
gen_info = (GenInfo){
.type = GenData,
.mod = "AM650",
.freq = 433920000,
.data.name =
SUBGHZ_PROTOCOL_MARANTEC_NAME, // Button code is 0x4 and crc sum to the end
.data.key = marantec_key,
.data.bits = 49,
.data.te = 0};
break;
case SetTypeMarantec_868:
gen_info = (GenInfo){
.type = GenData,
.mod = "AM650",
.freq = 868350000,
.data.name =
SUBGHZ_PROTOCOL_MARANTEC_NAME, // Button code is 0x4 and crc sum to the end
.data.key = marantec_key,
.data.bits = 49,
.data.te = 0};
break;
case SetTypeFaacSLH_433:
gen_info = (GenInfo){
.type = GenFaacSLH,
.mod = "AM650",
.freq = 433920000,
.faac_slh.serial = ((key & 0x00FFFFF0) | 0xA0000006) >> 4,
.faac_slh.btn = 0x06,
.faac_slh.cnt = 0x02,
.faac_slh.seed = key,
.faac_slh.manuf = "FAAC_SLH"};
break;
case SetTypeFaacSLH_868:
gen_info = (GenInfo){
.type = GenFaacSLH,
.mod = "AM650",
.freq = 868350000,
.faac_slh.serial = ((key & 0x00FFFFF0) | 0xA0000006) >> 4,
.faac_slh.btn = 0x06,
.faac_slh.cnt = 0x02,
.faac_slh.seed = (key & 0x0FFFFFFF),
.faac_slh.manuf = "FAAC_SLH"};
break;
case SetTypeBeninca433:
gen_info = (GenInfo){
.type = GenKeeloq,
.mod = "AM650",
.freq = 433920000,
.keeloq.serial = (key & 0x000FFF00) | 0x00800080,
.keeloq.btn = 0x01,
.keeloq.cnt = 0x05,
.keeloq.manuf = "Beninca"};
break;
case SetTypeBeninca868:
gen_info = (GenInfo){
.type = GenKeeloq,
.mod = "AM650",
.freq = 868350000,
.keeloq.serial = (key & 0x000FFF00) | 0x00800080,
.keeloq.btn = 0x01,
.keeloq.cnt = 0x05,
.keeloq.manuf = "Beninca"};
break;
case SetTypeComunello433:
gen_info = (GenInfo){
.type = GenKeeloq,
.mod = "AM650",
.freq = 433920000,
.keeloq.serial = key & 0x00FFFFFF,
.keeloq.btn = 0x08,
.keeloq.cnt = 0x05,
.keeloq.manuf = "Comunello"};
break;
case SetTypeComunello868:
gen_info = (GenInfo){
.type = GenKeeloq,
.mod = "AM650",
.freq = 868460000,
.keeloq.serial = key & 0x00FFFFFF,
.keeloq.btn = 0x08,
.keeloq.cnt = 0x05,
.keeloq.manuf = "Comunello"};
break;
case SetTypeAllmatic433:
gen_info = (GenInfo){
.type = GenKeeloq,
.mod = "AM650",
.freq = 433920000,
.keeloq.serial = (key & 0x00FFFF00) | 0x01000011,
.keeloq.btn = 0x0C,
.keeloq.cnt = 0x05,
.keeloq.manuf = "Beninca"};
break;
case SetTypeAllmatic868:
gen_info = (GenInfo){
.type = GenKeeloq,
.mod = "AM650",
.freq = 868350000,
.keeloq.serial = (key & 0x00FFFF00) | 0x01000011,
.keeloq.btn = 0x0C,
.keeloq.cnt = 0x05,
.keeloq.manuf = "Beninca"};
break;
case SetTypeCenturion433:
gen_info = (GenInfo){
.type = GenKeeloq,
.mod = "AM650",
.freq = 433920000,
.keeloq.serial = (key & 0x0000FFFF),
.keeloq.btn = 0x02,
.keeloq.cnt = 0x03,
.keeloq.manuf = "Centurion"};
break;
case SetTypeMonarch433:
gen_info = (GenInfo){
.type = GenKeeloq,
.mod = "AM650",
.freq = 433920000,
.keeloq.serial = (key & 0x0000FFFF),
.keeloq.btn = 0x0A,
.keeloq.cnt = 0x03,
.keeloq.manuf = "Monarch"};
break;
case SetTypeJollyMotors433:
gen_info = (GenInfo){
.type = GenKeeloq,
.mod = "AM650",
.freq = 433920000,
.keeloq.serial = (key & 0x000FFFFF),
.keeloq.btn = 0x02,
.keeloq.cnt = 0x03,
.keeloq.manuf = "Jolly_Motors"};
break;
case SetTypeElmesElectronic:
gen_info = (GenInfo){
.type = GenKeeloq,
.mod = "AM650",
.freq = 433920000,
.keeloq.serial = (key & 0x00FFFFFF) | 0x02000000,
.keeloq.btn = 0x02,
.keeloq.cnt = 0x03,
.keeloq.manuf = "Elmes_Poland"};
break;
case SetTypeANMotorsAT4:
gen_info = (GenInfo){
.type = GenKeeloq,
.mod = "AM650",
.freq = 433920000,
.keeloq.serial = (key & 0x000FFFFF) | 0x04700000,
.keeloq.btn = 0x02,
.keeloq.cnt = 0x21,
.keeloq.manuf = "AN-Motors"};
break;
case SetTypeAprimatic:
gen_info = (GenInfo){
.type = GenKeeloq,
.mod = "AM650",
.freq = 433920000,
.keeloq.serial = (key & 0x000FFFFF) | 0x00600000,
.keeloq.btn = 0x08,
.keeloq.cnt = 0x03,
.keeloq.manuf = "Aprimatic"};
break;
case SetTypeGibidi433:
gen_info = (GenInfo){
.type = GenKeeloq,
.mod = "AM650",
.freq = 433920000,
.keeloq.serial = key & 0x00FFFFFF,
.keeloq.btn = 0x02,
.keeloq.cnt = 0x03,
.keeloq.manuf = "Gibidi"};
break;
case SetTypeGSN:
gen_info = (GenInfo){
.type = GenKeeloq,
.mod = "AM650",
.freq = 433920000,
.keeloq.serial = key & 0x0FFFFFFF,
.keeloq.btn = 0x02,
.keeloq.cnt = 0x03,
.keeloq.manuf = "GSN"};
break;
case SetTypeIronLogic:
gen_info = (GenInfo){
.type = GenKeeloq,
.mod = "AM650",
.freq = 433920000,
.keeloq.serial = key & 0x00FFFFF0,
.keeloq.btn = 0x04,
.keeloq.cnt = 0x05,
.keeloq.manuf = "IronLogic"};
break;
case SetTypeStilmatic:
gen_info = (GenInfo){
.type = GenKeeloq,
.mod = "AM650",
.freq = 433920000,
.keeloq.serial = key & 0x0FFFFFFF,
.keeloq.btn = 0x01,
.keeloq.cnt = 0x03,
.keeloq.manuf = "Stilmatic"};
break;
case SetTypeSommer_FM_434:
gen_info = (GenInfo){
.type = GenKeeloq,
.mod = "FM476",
.freq = 434420000,
.keeloq.serial = (key & 0x0000FFFF) | 0x01700000,
.keeloq.btn = 0x02,
.keeloq.cnt = 0x03,
.keeloq.manuf = "Sommer(fsk476)"};
break;
case SetTypeSommer_FM_868:
gen_info = (GenInfo){
.type = GenKeeloq,
.mod = "FM476",
.freq = 868800000,
.keeloq.serial = (key & 0x0000FFFF) | 0x01700000,
.keeloq.btn = 0x02,
.keeloq.cnt = 0x03,
.keeloq.manuf = "Sommer(fsk476)"};
break;
case SetTypeSommer_FM238_434:
gen_info = (GenInfo){
.type = GenKeeloq,
.mod = "FM238",
.freq = 434420000,
.keeloq.serial = key & 0x0000FFFF,
.keeloq.btn = 0x02,
.keeloq.cnt = 0x03,
.keeloq.manuf = "Sommer(fsk476)"};
break;
case SetTypeSommer_FM238_868:
gen_info = (GenInfo){
.type = GenKeeloq,
.mod = "FM238",
.freq = 868800000,
.keeloq.serial = key & 0x0000FFFF,
.keeloq.btn = 0x02,
.keeloq.cnt = 0x03,
.keeloq.manuf = "Sommer(fsk476)"};
break;
case SetTypeDTMNeo433:
gen_info = (GenInfo){
.type = GenKeeloq,
.mod = "AM650",
.freq = 433920000,
.keeloq.serial = key & 0x000FFFFF,
.keeloq.btn = 0x02,
.keeloq.cnt = 0x05,
.keeloq.manuf = "DTM_Neo"};
break;
case SetTypeCAMESpace:
gen_info = (GenInfo){
.type = GenKeeloq,
.mod = "AM650",
.freq = 433920000,
.keeloq.serial = key & 0x00FFFFFF,
.keeloq.btn = 0x04,
.keeloq.cnt = 0x03,
.keeloq.manuf = "Came_Space"};
break;
case SetTypeCameAtomo433:
gen_info = (GenInfo){
.type = GenCameAtomo,
.mod = "AM650",
.freq = 433920000,
.came_atomo.serial = (key & 0x0FFFFFFF) | 0x10000000,
.came_atomo.cnt = 0x03};
break;
case SetTypeCameAtomo868:
gen_info = (GenInfo){
.type = GenCameAtomo,
.mod = "AM650",
.freq = 868350000,
.came_atomo.serial = (key & 0x0FFFFFFF) | 0x10000000,
.came_atomo.cnt = 0x03};
break;
case SetTypeBFTMitto:
gen_info = (GenInfo){
.type = GenKeeloqBFT,
.mod = "AM650",
.freq = 433920000,
.keeloq_bft.serial = key & 0x000FFFFF,
.keeloq_bft.btn = 0x02,
.keeloq_bft.cnt = 0x02,
.keeloq_bft.seed = key & 0x000FFFFF,
.keeloq_bft.manuf = "BFT"};
break;
case SetTypeAlutechAT4N:
gen_info = (GenInfo){
.type = GenAlutechAt4n,
.mod = "AM650",
.freq = 433920000,
.alutech_at_4n.serial = (key & 0x000FFFFF) | 0x00100000,
.alutech_at_4n.btn = 0x44,
.alutech_at_4n.cnt = 0x03};
break;
case SetTypeSomfyTelis:
gen_info = (GenInfo){
.type = GenSomfyTelis,
.mod = "AM650",
.freq = 433420000,
.somfy_telis.serial = key & 0x00FFFFFF,
.somfy_telis.btn = 0x02,
.somfy_telis.cnt = 0x03};
break;
case SetTypeMotorline433:
gen_info = (GenInfo){
.type = GenKeeloq,
.mod = "AM650",
.freq = 433920000,
.keeloq.serial = key & 0x0FFFFFFF,
.keeloq.btn = 0x01,
.keeloq.cnt = 0x03,
.keeloq.manuf = "Motorline"};
break;
case SetTypeDoorHan_433_92:
gen_info = (GenInfo){
.type = GenKeeloq,
.mod = "AM650",
.freq = 433920000,
.keeloq.serial = key & 0x0FFFFFFF,
.keeloq.btn = 0x02,
.keeloq.cnt = 0x03,
.keeloq.manuf = "DoorHan"};
break;
case SetTypeDoorHan_315_00:
gen_info = (GenInfo){
.type = GenKeeloq,
.mod = "AM650",
.freq = 315000000,
.keeloq.serial = key & 0x0FFFFFFF,
.keeloq.btn = 0x02,
.keeloq.cnt = 0x03,
.keeloq.manuf = "DoorHan"};
break;
case SetTypeNiceFlorS_433_92:
gen_info = (GenInfo){
.type = GenNiceFlorS,
.mod = "AM650",
.freq = 433920000,
.nice_flor_s.serial = key & 0x0FFFFFFF,
.nice_flor_s.btn = 0x01,
.nice_flor_s.cnt = 0x03,
.nice_flor_s.nice_one = false};
break;
case SetTypeNiceOne_433_92:
gen_info = (GenInfo){
.type = GenNiceFlorS,
.mod = "AM650",
.freq = 433920000,
.nice_flor_s.serial = key & 0x0FFFFFFF,
.nice_flor_s.btn = 0x01,
.nice_flor_s.cnt = 0x03,
.nice_flor_s.nice_one = true};
break;
case SetTypeNiceSmilo_433_92:
gen_info = (GenInfo){
.type = GenKeeloq,
.mod = "AM650",
.freq = 433920000,
.keeloq.serial = key & 0x00FFFFFF,
.keeloq.btn = 0x02,
.keeloq.cnt = 0x03,
.keeloq.manuf = "NICE_Smilo"};
break;
case SetTypeNiceMHouse_433_92:
gen_info = (GenInfo){
.type = GenKeeloq,
.mod = "AM650",
.freq = 433920000,
.keeloq.serial = key & 0x00FFFFFF,
.keeloq.btn = 0x09,
.keeloq.cnt = 0x03,
.keeloq.manuf = "NICE_MHOUSE"};
break;
case SetTypeDeaMio433:
gen_info = (GenInfo){
.type = GenKeeloq,
.mod = "AM650",
.freq = 433920000,
.keeloq.serial = (key & 0x0FFFF000) | 0x00000869,
.keeloq.btn = 0x02,
.keeloq.cnt = 0x03,
.keeloq.manuf = "Dea_Mio"};
break;
case SetTypeGeniusBravo433:
gen_info = (GenInfo){
.type = GenKeeloq,
.mod = "AM650",
.freq = 433920000,
.keeloq.serial = key & 0x00FFFFFF,
.keeloq.btn = 0x06,
.keeloq.cnt = 0x03,
.keeloq.manuf = "Genius_Bravo"};
break;
case SetTypeJCM_433_92:
gen_info = (GenInfo){
.type = GenKeeloq,
.mod = "AM650",
.freq = 433920000,
.keeloq.serial = key & 0x00FFFFFF,
.keeloq.btn = 0x02,
.keeloq.cnt = 0x03,
.keeloq.manuf = "JCM_Tech"};
break;
case SetTypeNovoferm_433_92:
gen_info = (GenInfo){
.type = GenKeeloq,
.mod = "AM650",
.freq = 433920000,
.keeloq.serial = (key & 0x0000FFFF) | 0x018F0000,
.keeloq.btn = 0x01,
.keeloq.cnt = 0x03,
.keeloq.manuf = "Novoferm"};
break;
case SetTypeHormannEcoStar_433_92:
gen_info = (GenInfo){
.type = GenKeeloq,
.mod = "AM650",
.freq = 433920000,
.keeloq.serial = (key & 0x000FFFFF) | 0x02200000,
.keeloq.btn = 0x04,
.keeloq.cnt = 0x03,
.keeloq.manuf = "EcoStar"};
break;
case SetTypeFAACRCXT_433_92:
gen_info = (GenInfo){
.type = GenKeeloq,
.mod = "AM650",
.freq = 433920000,
.keeloq.serial = (key & 0x0000FFFF) | 0x00100000,
.keeloq.btn = 0x02,
.keeloq.cnt = 0x03,
.keeloq.manuf = "FAAC_RC,XT"};
break;
case SetTypeFAACRCXT_868:
gen_info = (GenInfo){
.type = GenKeeloq,
.mod = "AM650",
.freq = 868350000,
.keeloq.serial = (key & 0x0000FFFF) | 0x00100000,
.keeloq.btn = 0x02,
.keeloq.cnt = 0x03,
.keeloq.manuf = "FAAC_RC,XT"};
break;
case SetTypeNormstahl_433_92:
gen_info = (GenInfo){
.type = GenKeeloq,
.mod = "AM650",
.freq = 433920000,
.keeloq.serial = key & 0x0000FFFF,
.keeloq.btn = 0x04,
.keeloq.cnt = 0x03,
.keeloq.manuf = "Normstahl"};
break;
case SetTypeHCS101_433_92:
gen_info = (GenInfo){
.type = GenKeeloq,
.mod = "AM650",
.freq = 433920000,
.keeloq.serial = key & 0x000FFFFF,
.keeloq.btn = 0x02,
.keeloq.cnt = 0x03,
.keeloq.manuf = "HCS101"};
break;
case SetTypeSecPlus_v1_315_00:
gen_info = (GenInfo){.type = GenSecPlus1, .mod = "AM650", .freq = 315000000};
break;
case SetTypeSecPlus_v1_390_00:
gen_info = (GenInfo){.type = GenSecPlus1, .mod = "AM650", .freq = 390000000};
break;
case SetTypeSecPlus_v1_433_00:
gen_info = (GenInfo){.type = GenSecPlus1, .mod = "AM650", .freq = 433920000};
break;
case SetTypeSecPlus_v2_310_00:
gen_info = (GenInfo){
.type = GenSecPlus2,
.mod = "AM650",
.freq = 310000000,
.sec_plus_2.serial = (key & 0x7FFFF3FC), // 850LM pairing
.sec_plus_2.btn = 0x68,
.sec_plus_2.cnt = 0xE500000};
break;
case SetTypeSecPlus_v2_315_00:
gen_info = (GenInfo){
.type = GenSecPlus2,
.mod = "AM650",
.freq = 315000000,
.sec_plus_2.serial = (key & 0x7FFFF3FC), // 850LM pairing
.sec_plus_2.btn = 0x68,
.sec_plus_2.cnt = 0xE500000};
break;
case SetTypeSecPlus_v2_390_00:
gen_info = (GenInfo){
.type = GenSecPlus2,
.mod = "AM650",
.freq = 390000000,
.sec_plus_2.serial = (key & 0x7FFFF3FC), // 850LM pairing
.sec_plus_2.btn = 0x68,
.sec_plus_2.cnt = 0xE500000};
break;
case SetTypeSecPlus_v2_433_00:
gen_info = (GenInfo){
.type = GenSecPlus2,
.mod = "AM650",
.freq = 433920000,
.sec_plus_2.serial = (key & 0x7FFFF3FC), // 850LM pairing
.sec_plus_2.btn = 0x68,
.sec_plus_2.cnt = 0xE500000};
break;
case SetTypePhoenix_V2_433:
gen_info = (GenInfo){
.type = GenPhoenixV2,
.mod = "AM650",
.freq = 433920000,
.phoenix_v2.serial = (key & 0x0FFFFFFF) | 0xB0000000,
.phoenix_v2.cnt = 0x025D};
break;
default:
furi_crash("Not implemented");
break;
}
*infos_dest = gen_info;
}
@@ -0,0 +1,84 @@
#pragma once
#include "subghz_types.h"
#include "subghz_custom_event.h"
typedef enum {
GenData,
GenFaacSLH,
GenKeeloq,
GenCameAtomo,
GenKeeloqBFT,
GenAlutechAt4n,
GenSomfyTelis,
GenNiceFlorS,
GenSecPlus1,
GenSecPlus2,
GenPhoenixV2,
} GenType;
typedef struct {
GenType type;
const char* mod;
uint32_t freq;
union {
struct {
const char* name;
uint64_t key;
uint8_t bits;
uint32_t te;
} data;
struct {
uint32_t serial;
uint8_t btn;
uint32_t cnt;
uint32_t seed;
const char* manuf;
} faac_slh;
struct {
uint32_t serial;
uint8_t btn;
uint16_t cnt;
const char* manuf;
} keeloq;
struct {
uint32_t serial;
uint16_t cnt;
} came_atomo;
struct {
uint32_t serial;
uint8_t btn;
uint16_t cnt;
uint32_t seed;
const char* manuf;
} keeloq_bft;
struct {
uint32_t serial;
uint8_t btn;
uint16_t cnt;
} alutech_at_4n;
struct {
uint32_t serial;
uint8_t btn;
uint16_t cnt;
} somfy_telis;
struct {
uint32_t serial;
uint8_t btn;
uint16_t cnt;
bool nice_one;
} nice_flor_s;
struct {
uint32_t serial;
uint8_t btn;
uint32_t cnt;
} sec_plus_2;
struct {
uint32_t serial;
uint16_t cnt;
} phoenix_v2;
};
} GenInfo;
void subghz_gen_info_reset(GenInfo* gen_info);
void subghz_scene_set_type_fill_generation_infos(GenInfo* infos_dest, SetType type);
@@ -12,8 +12,10 @@ ADD_SCENE(subghz, saved_menu, SavedMenu)
ADD_SCENE(subghz, delete, Delete)
ADD_SCENE(subghz, delete_success, DeleteSuccess)
ADD_SCENE(subghz, set_type, SetType)
ADD_SCENE(subghz, set_fix, SetFix)
ADD_SCENE(subghz, set_cnt, SetCnt)
ADD_SCENE(subghz, set_key, SetKey)
ADD_SCENE(subghz, set_serial, SetSerial)
ADD_SCENE(subghz, set_button, SetButton)
ADD_SCENE(subghz, set_counter, SetCounter)
ADD_SCENE(subghz, set_seed, SetSeed)
ADD_SCENE(subghz, frequency_analyzer, FrequencyAnalyzer)
ADD_SCENE(subghz, radio_settings, ExtModuleSettings)
@@ -96,12 +96,8 @@ bool subghz_scene_save_name_on_event(void* context, SceneManagerEvent event) {
furi_string_set(subghz->file_path, subghz->file_path_tmp);
}
}
if(scene_manager_has_previous_scene(subghz->scene_manager, SubGhzSceneSetSeed)) {
scene_manager_search_and_switch_to_previous_scene(
subghz->scene_manager, SubGhzSceneSetType);
} else {
scene_manager_previous_scene(subghz->scene_manager);
}
scene_manager_previous_scene(subghz->scene_manager);
return true;
} else if(event.type == SceneManagerEventTypeCustom) {
@@ -0,0 +1,111 @@
#include "../subghz_i.h"
#include "../helpers/subghz_txrx_create_protocol_key.h"
#define TAG "SubGhzSetButton"
void subghz_scene_set_button_byte_input_callback(void* context) {
SubGhz* subghz = context;
view_dispatcher_send_custom_event(subghz->view_dispatcher, SubGhzCustomEventByteInputDone);
}
void subghz_scene_set_button_on_enter(void* context) {
SubGhz* subghz = context;
uint8_t* byte_ptr = NULL;
uint8_t byte_count = 0;
switch(subghz->gen_info->type) {
case GenFaacSLH:
byte_ptr = &subghz->gen_info->faac_slh.btn;
byte_count = sizeof(subghz->gen_info->faac_slh.btn);
break;
case GenKeeloq:
byte_ptr = &subghz->gen_info->keeloq.btn;
byte_count = sizeof(subghz->gen_info->keeloq.btn);
break;
case GenKeeloqBFT:
byte_ptr = &subghz->gen_info->keeloq_bft.btn;
byte_count = sizeof(subghz->gen_info->keeloq_bft.btn);
break;
case GenAlutechAt4n:
byte_ptr = &subghz->gen_info->alutech_at_4n.btn;
byte_count = sizeof(subghz->gen_info->alutech_at_4n.btn);
break;
case GenSomfyTelis:
byte_ptr = &subghz->gen_info->somfy_telis.btn;
byte_count = sizeof(subghz->gen_info->somfy_telis.btn);
break;
case GenNiceFlorS:
byte_ptr = &subghz->gen_info->nice_flor_s.btn;
byte_count = sizeof(subghz->gen_info->nice_flor_s.btn);
break;
case GenSecPlus2:
byte_ptr = &subghz->gen_info->sec_plus_2.btn;
byte_count = sizeof(subghz->gen_info->sec_plus_2.btn);
break;
// Not needed for these types
case GenPhoenixV2:
case GenData:
case GenSecPlus1:
case GenCameAtomo:
default:
furi_crash("Not implemented");
break;
}
furi_assert(byte_ptr);
furi_assert(byte_count > 0);
// Setup view
ByteInput* byte_input = subghz->byte_input;
byte_input_set_header_text(byte_input, "Enter BUTTON in hex");
byte_input_set_result_callback(
byte_input,
subghz_scene_set_button_byte_input_callback,
NULL,
subghz,
byte_ptr,
byte_count);
view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdByteInput);
}
bool subghz_scene_set_button_on_event(void* context, SceneManagerEvent event) {
SubGhz* subghz = context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == SubGhzCustomEventByteInputDone) {
switch(subghz->gen_info->type) {
case GenFaacSLH:
case GenKeeloq:
case GenKeeloqBFT:
case GenAlutechAt4n:
case GenSomfyTelis:
case GenNiceFlorS:
case GenSecPlus2:
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSetCounter);
break;
// Not needed for these types
case GenCameAtomo:
case GenPhoenixV2:
case GenData:
case GenSecPlus1:
default:
furi_crash("Not implemented");
break;
}
consumed = true;
}
}
return consumed;
}
void subghz_scene_set_button_on_exit(void* context) {
SubGhz* subghz = context;
// Clear view
byte_input_set_result_callback(subghz->byte_input, NULL, NULL, NULL, NULL, 0);
byte_input_set_header_text(subghz->byte_input, "");
}
@@ -1,66 +0,0 @@
#include "../subghz_i.h"
#define TAG "SubGhzSetCnt"
void subghz_scene_set_cnt_byte_input_callback(void* context) {
SubGhz* subghz = context;
view_dispatcher_send_custom_event(subghz->view_dispatcher, SubGhzCustomEventByteInputDone);
}
void subghz_scene_set_cnt_on_enter(void* context) {
SubGhz* subghz = context;
// Setup view
ByteInput* byte_input = subghz->byte_input;
SubGhzCustomEvent state =
scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneSetType);
switch(state) {
case SetTypeBFTClone:
byte_input_set_header_text(byte_input, "Enter COUNTER in hex");
byte_input_set_result_callback(
byte_input,
subghz_scene_set_cnt_byte_input_callback,
NULL,
subghz,
subghz->secure_data->cnt,
2);
break;
case SetTypeFaacSLH_Manual_433:
case SetTypeFaacSLH_Manual_868:
byte_input_set_header_text(byte_input, "Enter COUNTER in hex 20 bits");
byte_input_set_result_callback(
byte_input,
subghz_scene_set_cnt_byte_input_callback,
NULL,
subghz,
subghz->secure_data->cnt,
3);
break;
default:
break;
}
view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdByteInput);
}
bool subghz_scene_set_cnt_on_event(void* context, SceneManagerEvent event) {
SubGhz* subghz = context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == SubGhzCustomEventByteInputDone) {
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSetSeed);
consumed = true;
}
}
return consumed;
}
void subghz_scene_set_cnt_on_exit(void* context) {
SubGhz* subghz = context;
// Clear view
byte_input_set_result_callback(subghz->byte_input, NULL, NULL, NULL, NULL, 0);
byte_input_set_header_text(subghz->byte_input, "");
}
@@ -0,0 +1,232 @@
#include "../subghz_i.h"
#include "../helpers/subghz_txrx_create_protocol_key.h"
#include <machine/endian.h>
#define TAG "SubGhzSetCounter"
void subghz_scene_set_counter_byte_input_callback(void* context) {
SubGhz* subghz = context;
view_dispatcher_send_custom_event(subghz->view_dispatcher, SubGhzCustomEventByteInputDone);
}
void subghz_scene_set_counter_on_enter(void* context) {
SubGhz* subghz = context;
uint8_t* byte_ptr = NULL;
uint8_t byte_count = 0;
switch(subghz->gen_info->type) {
case GenFaacSLH:
byte_ptr = (uint8_t*)&subghz->gen_info->faac_slh.cnt;
byte_count = sizeof(subghz->gen_info->faac_slh.cnt);
break;
case GenKeeloq:
byte_ptr = (uint8_t*)&subghz->gen_info->keeloq.cnt;
byte_count = sizeof(subghz->gen_info->keeloq.cnt);
break;
case GenCameAtomo:
byte_ptr = (uint8_t*)&subghz->gen_info->came_atomo.cnt;
byte_count = sizeof(subghz->gen_info->came_atomo.cnt);
break;
case GenKeeloqBFT:
byte_ptr = (uint8_t*)&subghz->gen_info->keeloq_bft.cnt;
byte_count = sizeof(subghz->gen_info->keeloq_bft.cnt);
break;
case GenAlutechAt4n:
byte_ptr = (uint8_t*)&subghz->gen_info->alutech_at_4n.cnt;
byte_count = sizeof(subghz->gen_info->alutech_at_4n.cnt);
break;
case GenSomfyTelis:
byte_ptr = (uint8_t*)&subghz->gen_info->somfy_telis.cnt;
byte_count = sizeof(subghz->gen_info->somfy_telis.cnt);
break;
case GenNiceFlorS:
byte_ptr = (uint8_t*)&subghz->gen_info->nice_flor_s.cnt;
byte_count = sizeof(subghz->gen_info->nice_flor_s.cnt);
break;
case GenSecPlus2:
byte_ptr = (uint8_t*)&subghz->gen_info->sec_plus_2.cnt;
byte_count = sizeof(subghz->gen_info->sec_plus_2.cnt);
break;
case GenPhoenixV2:
byte_ptr = (uint8_t*)&subghz->gen_info->phoenix_v2.cnt;
byte_count = sizeof(subghz->gen_info->phoenix_v2.cnt);
break;
// Not needed for these types
case GenData:
case GenSecPlus1:
default:
furi_crash("Not implemented");
break;
}
furi_assert(byte_ptr);
furi_assert(byte_count > 0);
if(byte_count == 2) {
*((uint16_t*)byte_ptr) = __bswap16(*((uint16_t*)byte_ptr)); // Convert
} else if(byte_count == 4) {
*((uint32_t*)byte_ptr) = __bswap32(*((uint32_t*)byte_ptr)); // Convert
}
// Setup view
ByteInput* byte_input = subghz->byte_input;
byte_input_set_header_text(byte_input, "Enter COUNTER in hex");
byte_input_set_result_callback(
byte_input,
subghz_scene_set_counter_byte_input_callback,
NULL,
subghz,
byte_ptr,
byte_count);
view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdByteInput);
}
bool subghz_scene_set_counter_on_event(void* context, SceneManagerEvent event) {
SubGhz* subghz = context;
bool consumed = false;
bool generated_protocol = false;
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == SubGhzCustomEventByteInputDone) {
// Swap bytes
switch(subghz->gen_info->type) {
case GenFaacSLH:
subghz->gen_info->faac_slh.cnt = __bswap32(subghz->gen_info->faac_slh.cnt);
break;
case GenKeeloq:
subghz->gen_info->keeloq.cnt = __bswap16(subghz->gen_info->keeloq.cnt);
break;
case GenCameAtomo:
subghz->gen_info->came_atomo.cnt = __bswap16(subghz->gen_info->came_atomo.cnt);
break;
case GenKeeloqBFT:
subghz->gen_info->keeloq_bft.cnt = __bswap16(subghz->gen_info->keeloq_bft.cnt);
break;
case GenAlutechAt4n:
subghz->gen_info->alutech_at_4n.cnt = __bswap16(subghz->gen_info->alutech_at_4n.cnt);
break;
case GenSomfyTelis:
subghz->gen_info->somfy_telis.cnt = __bswap16(subghz->gen_info->somfy_telis.cnt);
break;
case GenNiceFlorS:
subghz->gen_info->nice_flor_s.cnt = __bswap16(subghz->gen_info->nice_flor_s.cnt);
break;
case GenSecPlus2:
subghz->gen_info->sec_plus_2.cnt = __bswap32(subghz->gen_info->sec_plus_2.cnt);
break;
case GenPhoenixV2:
subghz->gen_info->phoenix_v2.cnt = __bswap16(subghz->gen_info->phoenix_v2.cnt);
break;
// Not needed for these types
case GenData:
case GenSecPlus1:
default:
furi_crash("Not implemented");
break;
}
switch(subghz->gen_info->type) {
case GenFaacSLH:
case GenKeeloqBFT:
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSetSeed);
return true;
case GenKeeloq:
generated_protocol = subghz_txrx_gen_keeloq_protocol(
subghz->txrx,
subghz->gen_info->mod,
subghz->gen_info->freq,
subghz->gen_info->keeloq.serial,
subghz->gen_info->keeloq.btn,
subghz->gen_info->keeloq.cnt,
subghz->gen_info->keeloq.manuf);
break;
case GenCameAtomo:
generated_protocol = subghz_txrx_gen_came_atomo_protocol(
subghz->txrx,
subghz->gen_info->mod,
subghz->gen_info->freq,
subghz->gen_info->came_atomo.serial,
subghz->gen_info->came_atomo.cnt);
break;
case GenAlutechAt4n:
generated_protocol = subghz_txrx_gen_alutech_at_4n_protocol(
subghz->txrx,
subghz->gen_info->mod,
subghz->gen_info->freq,
subghz->gen_info->alutech_at_4n.serial,
subghz->gen_info->alutech_at_4n.btn,
subghz->gen_info->alutech_at_4n.cnt);
break;
case GenSomfyTelis:
generated_protocol = subghz_txrx_gen_somfy_telis_protocol(
subghz->txrx,
subghz->gen_info->mod,
subghz->gen_info->freq,
subghz->gen_info->somfy_telis.serial,
subghz->gen_info->somfy_telis.btn,
subghz->gen_info->somfy_telis.cnt);
break;
case GenNiceFlorS:
generated_protocol = subghz_txrx_gen_nice_flor_s_protocol(
subghz->txrx,
subghz->gen_info->mod,
subghz->gen_info->freq,
subghz->gen_info->nice_flor_s.serial,
subghz->gen_info->nice_flor_s.btn,
subghz->gen_info->nice_flor_s.cnt,
subghz->gen_info->nice_flor_s.nice_one);
break;
case GenSecPlus2:
generated_protocol = subghz_txrx_gen_secplus_v2_protocol(
subghz->txrx,
subghz->gen_info->mod,
subghz->gen_info->freq,
subghz->gen_info->sec_plus_2.serial,
subghz->gen_info->sec_plus_2.btn,
subghz->gen_info->sec_plus_2.cnt);
break;
case GenPhoenixV2:
generated_protocol = subghz_txrx_gen_phoenix_v2_protocol(
subghz->txrx,
subghz->gen_info->mod,
subghz->gen_info->freq,
subghz->gen_info->phoenix_v2.serial,
subghz->gen_info->phoenix_v2.cnt);
break;
// Not needed for these types
case GenData:
case GenSecPlus1:
default:
furi_crash("Not implemented");
break;
}
consumed = true;
if(!generated_protocol) {
furi_string_set(
subghz->error_str, "Function requires\nan SD card with\nfresh databases.");
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowError);
} else {
subghz_file_name_clear(subghz);
scene_manager_set_scene_state(
subghz->scene_manager, SubGhzSceneSetType, SubGhzCustomEventManagerSet);
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSaveName);
}
}
}
return consumed;
}
void subghz_scene_set_counter_on_exit(void* context) {
SubGhz* subghz = context;
// Clear view
byte_input_set_result_callback(subghz->byte_input, NULL, NULL, NULL, NULL, 0);
byte_input_set_header_text(subghz->byte_input, "");
}
@@ -1,46 +0,0 @@
#include "../subghz_i.h"
#define TAG "SubGhzSetFix"
void subghz_scene_set_fix_byte_input_callback(void* context) {
SubGhz* subghz = context;
view_dispatcher_send_custom_event(subghz->view_dispatcher, SubGhzCustomEventByteInputDone);
}
void subghz_scene_set_fix_on_enter(void* context) {
SubGhz* subghz = context;
// Setup view
ByteInput* byte_input = subghz->byte_input;
byte_input_set_header_text(byte_input, "Enter FIX in hex");
byte_input_set_result_callback(
byte_input,
subghz_scene_set_fix_byte_input_callback,
NULL,
subghz,
subghz->secure_data->fix,
4);
view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdByteInput);
}
bool subghz_scene_set_fix_on_event(void* context, SceneManagerEvent event) {
SubGhz* subghz = context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == SubGhzCustomEventByteInputDone) {
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSetCnt);
consumed = true;
}
}
return consumed;
}
void subghz_scene_set_fix_on_exit(void* context) {
SubGhz* subghz = context;
// Clear view
byte_input_set_result_callback(subghz->byte_input, NULL, NULL, NULL, NULL, 0);
byte_input_set_header_text(subghz->byte_input, "");
}
@@ -0,0 +1,95 @@
#include "../subghz_i.h"
#include "../helpers/subghz_txrx_create_protocol_key.h"
#include <machine/endian.h>
#define TAG "SubGhzSetKey"
void subghz_scene_set_key_byte_input_callback(void* context) {
SubGhz* subghz = context;
view_dispatcher_send_custom_event(subghz->view_dispatcher, SubGhzCustomEventByteInputDone);
}
void subghz_scene_set_key_on_enter(void* context) {
SubGhz* subghz = context;
uint8_t* byte_ptr = NULL;
uint8_t byte_count = 0;
if(subghz->gen_info->type == GenData) {
byte_ptr = (uint8_t*)&subghz->gen_info->data.key;
byte_count = sizeof(subghz->gen_info->data.key);
} else {
furi_crash("Not implemented");
}
furi_assert(byte_ptr);
furi_assert(byte_count > 0);
*((uint64_t*)byte_ptr) = __bswap64(*((uint64_t*)byte_ptr)); // Convert
// Setup view
ByteInput* byte_input = subghz->byte_input;
byte_input_set_header_text(byte_input, "Enter KEY in hex");
byte_input_set_result_callback(
byte_input, subghz_scene_set_key_byte_input_callback, NULL, subghz, byte_ptr, byte_count);
view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdByteInput);
}
bool subghz_scene_set_key_on_event(void* context, SceneManagerEvent event) {
SubGhz* subghz = context;
bool consumed = false;
bool generated_protocol = false;
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == SubGhzCustomEventByteInputDone) {
if(subghz->gen_info->type == GenData) {
subghz->gen_info->data.key = __bswap64(subghz->gen_info->data.key);
if(subghz->gen_info->data.te) {
generated_protocol = subghz_txrx_gen_data_protocol_and_te(
subghz->txrx,
subghz->gen_info->mod,
subghz->gen_info->freq,
subghz->gen_info->data.name,
subghz->gen_info->data.key,
subghz->gen_info->data.bits,
subghz->gen_info->data.te);
} else {
generated_protocol = subghz_txrx_gen_data_protocol(
subghz->txrx,
subghz->gen_info->mod,
subghz->gen_info->freq,
subghz->gen_info->data.name,
subghz->gen_info->data.key,
subghz->gen_info->data.bits);
}
}
consumed = true;
if(!generated_protocol) {
furi_string_set(
subghz->error_str, "Function requires\nan SD card with\nfresh databases.");
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowError);
} else {
subghz_file_name_clear(subghz);
scene_manager_set_scene_state(
subghz->scene_manager, SubGhzSceneSetType, SubGhzCustomEventManagerSet);
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSaveName);
}
}
}
return consumed;
}
void subghz_scene_set_key_on_exit(void* context) {
SubGhz* subghz = context;
// Clear view
byte_input_set_result_callback(subghz->byte_input, NULL, NULL, NULL, NULL, 0);
byte_input_set_header_text(subghz->byte_input, "");
}
@@ -1,6 +1,8 @@
#include "../subghz_i.h"
#include "../helpers/subghz_txrx_create_protocol_key.h"
#include <machine/endian.h>
#define TAG "SubGhzSetSeed"
void subghz_scene_set_seed_byte_input_callback(void* context) {
@@ -12,16 +14,43 @@ void subghz_scene_set_seed_byte_input_callback(void* context) {
void subghz_scene_set_seed_on_enter(void* context) {
SubGhz* subghz = context;
uint8_t* byte_ptr = NULL;
uint8_t byte_count = 0;
switch(subghz->gen_info->type) {
case GenFaacSLH:
byte_ptr = (uint8_t*)&subghz->gen_info->faac_slh.seed;
byte_count = sizeof(subghz->gen_info->faac_slh.seed);
break;
case GenKeeloqBFT:
byte_ptr = (uint8_t*)&subghz->gen_info->keeloq_bft.seed;
byte_count = sizeof(subghz->gen_info->keeloq_bft.seed);
break;
// Not needed for these types
case GenKeeloq:
case GenAlutechAt4n:
case GenSomfyTelis:
case GenNiceFlorS:
case GenSecPlus2:
case GenPhoenixV2:
case GenData:
case GenSecPlus1:
case GenCameAtomo:
default:
furi_crash("Not implemented");
break;
}
furi_assert(byte_ptr);
furi_assert(byte_count > 0);
*((uint32_t*)byte_ptr) = __bswap32(*((uint32_t*)byte_ptr)); // Convert
// Setup view
ByteInput* byte_input = subghz->byte_input;
byte_input_set_header_text(byte_input, "Enter SEED in hex");
byte_input_set_result_callback(
byte_input,
subghz_scene_set_seed_byte_input_callback,
NULL,
subghz,
subghz->secure_data->seed,
4);
byte_input, subghz_scene_set_seed_byte_input_callback, NULL, subghz, byte_ptr, byte_count);
view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdByteInput);
}
@@ -29,97 +58,62 @@ bool subghz_scene_set_seed_on_event(void* context, SceneManagerEvent event) {
SubGhz* subghz = context;
bool consumed = false;
bool generated_protocol = false;
uint32_t fix_part, cnt, seed;
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == SubGhzCustomEventByteInputDone) {
SetType state =
scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneSetType);
switch(state) {
case SetTypeBFTClone:
fix_part = subghz->secure_data->fix[0] << 24 | subghz->secure_data->fix[1] << 16 |
subghz->secure_data->fix[2] << 8 | subghz->secure_data->fix[3];
cnt = subghz->secure_data->cnt[0] << 8 | subghz->secure_data->cnt[1];
seed = subghz->secure_data->seed[0] << 24 | subghz->secure_data->seed[1] << 16 |
subghz->secure_data->seed[2] << 8 | subghz->secure_data->seed[3];
switch(subghz->gen_info->type) {
case GenFaacSLH:
subghz->gen_info->faac_slh.seed = __bswap32(subghz->gen_info->faac_slh.seed);
generated_protocol = subghz_txrx_gen_faac_slh_protocol(
subghz->txrx,
subghz->gen_info->mod,
subghz->gen_info->freq,
subghz->gen_info->faac_slh.serial,
subghz->gen_info->faac_slh.btn,
subghz->gen_info->faac_slh.cnt,
subghz->gen_info->faac_slh.seed,
subghz->gen_info->faac_slh.manuf);
break;
case GenKeeloqBFT:
subghz->gen_info->keeloq_bft.seed = __bswap32(subghz->gen_info->keeloq_bft.seed);
generated_protocol = subghz_txrx_gen_keeloq_bft_protocol(
subghz->txrx,
"AM650",
433920000,
fix_part & 0x0FFFFFFF,
fix_part >> 28,
cnt,
seed,
"BFT");
if(!generated_protocol) {
furi_string_set(
subghz->error_str, "Function requires\nan SD card with\nfresh databases.");
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowError);
}
consumed = true;
subghz->gen_info->mod,
subghz->gen_info->freq,
subghz->gen_info->keeloq_bft.serial,
subghz->gen_info->keeloq_bft.btn,
subghz->gen_info->keeloq_bft.cnt,
subghz->gen_info->keeloq_bft.seed,
subghz->gen_info->keeloq_bft.manuf);
break;
case SetTypeFaacSLH_Manual_433:
case SetTypeFaacSLH_Manual_868:
fix_part = subghz->secure_data->fix[0] << 24 | subghz->secure_data->fix[1] << 16 |
subghz->secure_data->fix[2] << 8 | subghz->secure_data->fix[3];
cnt = subghz->secure_data->cnt[0] << 16 | subghz->secure_data->cnt[1] << 8 |
subghz->secure_data->cnt[2];
seed = subghz->secure_data->seed[0] << 24 | subghz->secure_data->seed[1] << 16 |
subghz->secure_data->seed[2] << 8 | subghz->secure_data->seed[3];
if(state == SetTypeFaacSLH_Manual_433) {
generated_protocol = subghz_txrx_gen_faac_slh_protocol(
subghz->txrx,
"AM650",
433920000,
fix_part >> 4,
fix_part & 0xf,
(cnt & 0xFFFFF),
seed,
"FAAC_SLH");
} else if(state == SetTypeFaacSLH_Manual_868) {
generated_protocol = subghz_txrx_gen_faac_slh_protocol(
subghz->txrx,
"AM650",
868350000,
fix_part >> 4,
fix_part & 0xf,
(cnt & 0xFFFFF),
seed,
"FAAC_SLH");
}
if(!generated_protocol) {
furi_string_set(
subghz->error_str, "Function requires\nan SD card with\nfresh databases.");
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowError);
}
consumed = true;
break;
// Not needed for these types
case GenKeeloq:
case GenAlutechAt4n:
case GenSomfyTelis:
case GenNiceFlorS:
case GenSecPlus2:
case GenPhoenixV2:
case GenData:
case GenSecPlus1:
case GenCameAtomo:
default:
furi_crash("Not implemented");
break;
}
}
// Reset Seed, Fix, Cnt in secure data after successful or unsuccessful generation
memset(subghz->secure_data->seed, 0, sizeof(subghz->secure_data->seed));
memset(subghz->secure_data->cnt, 0, sizeof(subghz->secure_data->cnt));
memset(subghz->secure_data->fix, 0, sizeof(subghz->secure_data->fix));
consumed = true;
if(generated_protocol) {
subghz_file_name_clear(subghz);
if(!generated_protocol) {
furi_string_set(
subghz->error_str, "Function requires\nan SD card with\nfresh databases.");
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowError);
} else {
subghz_file_name_clear(subghz);
scene_manager_set_scene_state(
subghz->scene_manager, SubGhzSceneSetType, SubGhzCustomEventManagerSet);
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSaveName);
return true;
scene_manager_set_scene_state(
subghz->scene_manager, SubGhzSceneSetType, SubGhzCustomEventManagerSet);
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSaveName);
}
}
}
return consumed;
@@ -0,0 +1,160 @@
#include "../subghz_i.h"
#include "../helpers/subghz_txrx_create_protocol_key.h"
#include <machine/endian.h>
#define TAG "SubGhzSetSerial"
void subghz_scene_set_serial_byte_input_callback(void* context) {
SubGhz* subghz = context;
view_dispatcher_send_custom_event(subghz->view_dispatcher, SubGhzCustomEventByteInputDone);
}
void subghz_scene_set_serial_on_enter(void* context) {
SubGhz* subghz = context;
uint8_t* byte_ptr = NULL;
uint8_t byte_count = 0;
switch(subghz->gen_info->type) {
case GenFaacSLH:
byte_ptr = (uint8_t*)&subghz->gen_info->faac_slh.serial;
byte_count = sizeof(subghz->gen_info->faac_slh.serial);
break;
case GenKeeloq:
byte_ptr = (uint8_t*)&subghz->gen_info->keeloq.serial;
byte_count = sizeof(subghz->gen_info->keeloq.serial);
break;
case GenCameAtomo:
byte_ptr = (uint8_t*)&subghz->gen_info->came_atomo.serial;
byte_count = sizeof(subghz->gen_info->came_atomo.serial);
break;
case GenKeeloqBFT:
byte_ptr = (uint8_t*)&subghz->gen_info->keeloq_bft.serial;
byte_count = sizeof(subghz->gen_info->keeloq_bft.serial);
break;
case GenAlutechAt4n:
byte_ptr = (uint8_t*)&subghz->gen_info->alutech_at_4n.serial;
byte_count = sizeof(subghz->gen_info->alutech_at_4n.serial);
break;
case GenSomfyTelis:
byte_ptr = (uint8_t*)&subghz->gen_info->somfy_telis.serial;
byte_count = sizeof(subghz->gen_info->somfy_telis.serial);
break;
case GenNiceFlorS:
byte_ptr = (uint8_t*)&subghz->gen_info->nice_flor_s.serial;
byte_count = sizeof(subghz->gen_info->nice_flor_s.serial);
break;
case GenSecPlus2:
byte_ptr = (uint8_t*)&subghz->gen_info->sec_plus_2.serial;
byte_count = sizeof(subghz->gen_info->sec_plus_2.serial);
break;
case GenPhoenixV2:
byte_ptr = (uint8_t*)&subghz->gen_info->phoenix_v2.serial;
byte_count = sizeof(subghz->gen_info->phoenix_v2.serial);
break;
// Not needed for these types
case GenData:
case GenSecPlus1:
default:
furi_crash("Not implemented");
break;
}
furi_assert(byte_ptr);
furi_assert(byte_count > 0);
*((uint32_t*)byte_ptr) = __bswap32(*((uint32_t*)byte_ptr)); // Convert
// Setup view
ByteInput* byte_input = subghz->byte_input;
byte_input_set_header_text(byte_input, "Enter SERIAL in hex");
byte_input_set_result_callback(
byte_input,
subghz_scene_set_serial_byte_input_callback,
NULL,
subghz,
byte_ptr,
byte_count);
view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdByteInput);
}
bool subghz_scene_set_serial_on_event(void* context, SceneManagerEvent event) {
SubGhz* subghz = context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == SubGhzCustomEventByteInputDone) {
// Swap bytes
switch(subghz->gen_info->type) {
case GenFaacSLH:
subghz->gen_info->faac_slh.serial = __bswap32(subghz->gen_info->faac_slh.serial);
break;
case GenKeeloq:
subghz->gen_info->keeloq.serial = __bswap32(subghz->gen_info->keeloq.serial);
break;
case GenCameAtomo:
subghz->gen_info->came_atomo.serial = __bswap32(subghz->gen_info->came_atomo.serial);
break;
case GenKeeloqBFT:
subghz->gen_info->keeloq_bft.serial = __bswap32(subghz->gen_info->keeloq_bft.serial);
break;
case GenAlutechAt4n:
subghz->gen_info->alutech_at_4n.serial = __bswap32(subghz->gen_info->alutech_at_4n.serial);
break;
case GenSomfyTelis:
subghz->gen_info->somfy_telis.serial = __bswap32(subghz->gen_info->somfy_telis.serial);
break;
case GenNiceFlorS:
subghz->gen_info->nice_flor_s.serial = __bswap32(subghz->gen_info->nice_flor_s.serial);
break;
case GenSecPlus2:
subghz->gen_info->sec_plus_2.serial = __bswap32(subghz->gen_info->sec_plus_2.serial);
break;
case GenPhoenixV2:
subghz->gen_info->phoenix_v2.serial = __bswap32(subghz->gen_info->phoenix_v2.serial);
break;
// Not needed for these types
case GenData:
case GenSecPlus1:
default:
furi_crash("Not implemented");
break;
}
switch(subghz->gen_info->type) {
case GenFaacSLH:
case GenKeeloq:
case GenKeeloqBFT:
case GenAlutechAt4n:
case GenSomfyTelis:
case GenNiceFlorS:
case GenSecPlus2:
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSetButton);
break;
case GenCameAtomo:
case GenPhoenixV2:
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSetCounter);
break;
// Not needed for these types
case GenData:
case GenSecPlus1:
default:
furi_crash("Not implemented");
break;
}
consumed = true;
}
}
return consumed;
}
void subghz_scene_set_serial_on_exit(void* context) {
SubGhz* subghz = context;
// Clear view
byte_input_set_result_callback(subghz->byte_input, NULL, NULL, NULL, NULL, 0);
byte_input_set_header_text(subghz->byte_input, "");
}
File diff suppressed because it is too large Load Diff
@@ -1,18 +1,9 @@
#include "../subghz_i.h"
#include "subghz_scene_start.h"
#include <dolphin/dolphin.h>
#include <lib/subghz/protocols/raw.h>
enum SubmenuIndex {
SubmenuIndexRead = 10,
SubmenuIndexSaved,
SubmenuIndexAddManually,
SubmenuIndexFrequencyAnalyzer,
SubmenuIndexReadRAW,
SubmenuIndexExtSettings,
SubmenuIndexRadioSetting,
};
void subghz_scene_start_submenu_callback(void* context, uint32_t index) {
SubGhz* subghz = context;
view_dispatcher_send_custom_event(subghz->view_dispatcher, index);
@@ -40,6 +31,12 @@ void subghz_scene_start_on_enter(void* context) {
SubmenuIndexAddManually,
subghz_scene_start_submenu_callback,
subghz);
submenu_add_item(
subghz->submenu,
"Add Manually [Advanced]",
SubmenuIndexAddManuallyAdvanced,
subghz_scene_start_submenu_callback,
subghz);
submenu_add_item(
subghz->submenu,
"Frequency Analyzer",
@@ -88,6 +85,11 @@ bool subghz_scene_start_on_event(void* context, SceneManagerEvent event) {
subghz->scene_manager, SubGhzSceneStart, SubmenuIndexAddManually);
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSetType);
return true;
} else if(event.event == SubmenuIndexAddManuallyAdvanced) {
scene_manager_set_scene_state(
subghz->scene_manager, SubGhzSceneStart, SubmenuIndexAddManuallyAdvanced);
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSetType);
return true;
} else if(event.event == SubmenuIndexFrequencyAnalyzer) {
scene_manager_set_scene_state(
subghz->scene_manager, SubGhzSceneStart, SubmenuIndexFrequencyAnalyzer);
@@ -0,0 +1,12 @@
#pragma once
enum SubmenuIndex {
SubmenuIndexRead = 10,
SubmenuIndexSaved,
SubmenuIndexAddManually,
SubmenuIndexAddManuallyAdvanced,
SubmenuIndexFrequencyAnalyzer,
SubmenuIndexReadRAW,
SubmenuIndexExtSettings,
SubmenuIndexRadioSetting,
};
+2 -2
View File
@@ -235,7 +235,7 @@ SubGhz* subghz_alloc(bool alloc_for_tx_only) {
subghz_rx_key_state_set(subghz, SubGhzRxKeyStateIDLE);
subghz->secure_data = malloc(sizeof(SecureData));
subghz->gen_info = malloc(sizeof(GenInfo));
if(!alloc_for_tx_only) {
subghz->remove_duplicates = subghz->last_settings->remove_duplicates;
@@ -346,7 +346,7 @@ void subghz_free(SubGhz* subghz, bool alloc_for_tx_only) {
subghz_history_free(subghz->history);
}
free(subghz->secure_data);
free(subghz->gen_info);
//TxRx
subghz_txrx_free(subghz->txrx);
+2 -7
View File
@@ -1,6 +1,7 @@
#pragma once
#include "helpers/subghz_types.h"
#include "helpers/subghz_gen_info.h"
#include <lib/subghz/types.h>
#include "subghz.h"
#include "views/receiver.h"
@@ -46,12 +47,6 @@
#define SUBGHZ_EXT_PRESET_NAME true
#define SUBGHZ_MEASURE_LOADING false
typedef struct {
uint8_t fix[4];
uint8_t cnt[4];
uint8_t seed[4];
} SecureData;
struct SubGhz {
Gui* gui;
NotificationApp* notifications;
@@ -91,7 +86,7 @@ struct SubGhz {
FuriString* error_str;
SubGhzLock lock;
SecureData* secure_data;
GenInfo* gen_info;
SubGhzFileEncoderWorker* decode_raw_file_worker_encoder;
+1 -1
View File
@@ -54,7 +54,7 @@ void input_settings_load(InputSettings* settings) {
FURI_LOG_W(TAG, "Failed to load file, using defaults");
memset(settings, 0, sizeof(InputSettings));
settings->vibro_touch_trigger_mask = INPUT_SETTINGS_VIBRO_TOUCH_TRIGGER_MASK_DEFAULT;
// input_settings_save(settings);
//input_settings_save(settings);
}
}
+11 -8
View File
@@ -16,7 +16,8 @@
#define TAG "CliShell"
#define ANSI_TIMEOUT_MS 10
#define ANSI_TIMEOUT_MS 10
#define TRANSIENT_SESSION_WINDOW_MS 100
typedef enum {
CliShellComponentCompletions,
@@ -461,13 +462,15 @@ static void cli_shell_deinit(CliShell* shell) {
static int32_t cli_shell_thread(void* context) {
CliShell* shell = context;
// Give qFlipper a chance to close and re-open the session
furi_delay_ms(100);
// Sometimes, the other side closes the pipe even before our thread is started. Although the
// rest of the code will eventually find this out if this check is removed, there's no point in
// wasting time.
if(pipe_state(shell->pipe) == PipeStateBroken) return 0;
// Sometimes, the other side (e.g. qFlipper) closes the pipe even before our thread is started.
// Although the rest of the code will eventually find this out if this check is removed,
// there's no point in wasting time. This gives qFlipper a chance to quickly close and re-open
// the session.
const size_t delay_step = 10;
for(size_t i = 0; i < TRANSIENT_SESSION_WINDOW_MS / delay_step; i++) {
furi_delay_ms(delay_step);
if(pipe_state(shell->pipe) == PipeStateBroken) return 0;
}
cli_shell_init(shell);
FURI_LOG_D(TAG, "Started");
+6
View File
@@ -177,6 +177,7 @@ class Main(App):
symbols /= "sdk_headers/f7_sdk"
symbols = (symbols / "targets/f7/api_symbols.csv").read_text()
api_has_icon = lambda name: f"Variable,+,{name},const Icon," in symbols
api_has_icon_disabled = lambda name: f"Variable,-,{name},const Icon," in symbols
# Traverse icons tree, append image data to source file
for dirpath, dirnames, filenames in os.walk(self.args.input_directory):
self.logger.debug(f"Processing directory {dirpath}")
@@ -294,6 +295,11 @@ class Main(App):
)
icons_h.write(ICONS_TEMPLATE_H_HEADER)
for name, width, height, frame_rate, frame_count in icons:
if self.args.add_include and api_has_icon_disabled(name):
self.logger.info(
f"{self.args.filename}: skipping duplicate decl {icon_name}"
)
continue
icons_h.write(ICONS_TEMPLATE_H_ICON_NAME.format(name=name))
if self.args.fw_bundle:
icons_h.write(ICONS_TEMPLATE_H_ICON_PATHS)
+1
View File
@@ -322,6 +322,7 @@ def _validate_app_imports(target, source, env):
"metromoney_plugin",
"myki_plugin",
"opal_plugin",
"renfe_sum10_plugin",
"smartrider_plugin",
"suica_plugin",
"troika_plugin",