diff --git a/platformio.ini b/platformio.ini index 35d3a61d..c6ed2aae 100644 --- a/platformio.ini +++ b/platformio.ini @@ -22,7 +22,6 @@ build_flags = -DLH=8 -DLW=6 -DCONFIG_FILE='"/config.conf"' - lib_deps = WireGuard-ESP32 IRremoteESP8266 @@ -34,6 +33,8 @@ lib_deps = Timezone ESP32Time bblanchon/ArduinoJson + rc-switch + ;https://github.com/Martin-Laclaustra/rc-switch.git#transmittimingsarray [env:m5stack-cplus2] diff --git a/src/core/main_menu.cpp b/src/core/main_menu.cpp index 5d47c981..0f8d3244 100644 --- a/src/core/main_menu.cpp +++ b/src/core/main_menu.cpp @@ -87,6 +87,7 @@ void rfOptions(){ options = { //{"Scan/copy", [=]() { displayRedStripe("Scan/Copy"); }}, //{"Replay", [=]() { displayRedStripe("Replay"); }}, + {"Custom SubGhz", [=]() { otherRFcodes(); }}, {"Spectrum", [=]() { rf_spectrum(); }}, //@IncursioHack {"Jammer Itmt", [=]() { rf_jammerIntermittent(); }}, //@IncursioHack {"Jammer Full", [=]() { rf_jammerFull(); }}, //@IncursioHack diff --git a/src/modules/rf/rf.cpp b/src/modules/rf/rf.cpp index 914a9dd6..caa3c345 100644 --- a/src/modules/rf/rf.cpp +++ b/src/modules/rf/rf.cpp @@ -151,4 +151,282 @@ void rf_jammerIntermittent() { //@IncursioHack - https://github.com/IncursioHack } +struct RfCodes { + uint32_t frequency = 0; + String protocol = ""; + String preset = ""; + String data = ""; + int te = 0; + String filepath = ""; +}; + + +#include + +void RCSwitch_send(uint64_t data, unsigned int bits, int pulse, int protocol, int repeat) +{ + RCSwitch mySwitch = RCSwitch(); + mySwitch.enableTransmit(RfTx); + mySwitch.setProtocol(protocol); + if (pulse) { mySwitch.setPulseLength(pulse); } + mySwitch.setPulseLength(pulse); + mySwitch.setRepeatTransmit(repeat); + mySwitch.send(data, bits); +} + +struct HighLow { + uint8_t high; // 1 + uint8_t low; //31 +}; + +struct Protocol { + uint16_t pulseLength; // base pulse length in microseconds, e.g. 350 + HighLow syncFactor; + HighLow zero; + HighLow one; + bool invertedSignal; +}; + +// ported from https://github.com/sui77/rc-switch/blob/3a536a172ab752f3c7a58d831c5075ca24fd920b/RCSwitch.cpp + +void RCSwitch_RAW_send(int nTransmitterPin, int * ptrtransmittimings, struct Protocol protocol) { + if (nTransmitterPin == -1) + return; + + if (!ptrtransmittimings) + return; + + bool currentlogiclevel = true; + int nRepeatTransmit = 1; + //HighLow pulses ; + + for (int nRepeat = 0; nRepeat < nRepeatTransmit; nRepeat++) { + unsigned int currenttiming = 0; + while( ptrtransmittimings[currenttiming] ) { // && currenttiming < RCSWITCH_MAX_CHANGES + if(ptrtransmittimings[currenttiming] >= 0) { + currentlogiclevel = true; + //pulses = protocol.one; + } else { + // negative value + currentlogiclevel = false; + ptrtransmittimings[currenttiming] = (-1) * ptrtransmittimings[currenttiming]; // invert sign + //pulses = protocol.zero; + } + + digitalWrite(nTransmitterPin, currentlogiclevel ? HIGH : LOW); + delayMicroseconds( ptrtransmittimings[currenttiming] ); + + /* + uint8_t firstLogicLevel = (protocol.invertedSignal) ? LOW : HIGH; + uint8_t secondLogicLevel = (protocol.invertedSignal) ? HIGH : LOW; + + digitalWrite(nTransmitterPin, firstLogicLevel); + delayMicroseconds( protocol.pulseLength * pulses.high); + digitalWrite(nTransmitterPin, secondLogicLevel); + delayMicroseconds( protocol.pulseLength * pulses.low); + * */ + + Serial.print(ptrtransmittimings[currenttiming]); + Serial.print("="); + Serial.println(currentlogiclevel); + + currenttiming++; + } + digitalWrite(nTransmitterPin, LOW); + } // end for +} + + +void sendRfCommand(struct RfCodes rfcode) { + uint32_t frequency = rfcode.frequency; + String protocol = rfcode.protocol; + String preset = rfcode.preset; + String data = rfcode.data; +/* + Serial.println("sendRawRfCommand"); + Serial.println(data); + Serial.println(frequency); + Serial.println(preset); + Serial.println(protocol); + */ + if(frequency != 433920000) { + Serial.print("unsupported frequency: "); + Serial.println(frequency); + return; + } + // MEMO: frequency is fixed with some transmitters https://github.com/sui77/rc-switch/issues/256 + // TODO: add frequency switching via CC1101 https://github.com/LSatan/SmartRC-CC1101-Driver-Lib + + // Radio preset name (configures modulation, bandwidth, filters, etc.). + struct Protocol rcswitch_protocol; + int rcswitch_protocol_no = 1; + if(preset == "FuriHalSubGhzPresetOok270Async") { + rcswitch_protocol_no = 1; + // pulseLength , syncFactor , zero , one, invertedSignal + rcswitch_protocol = { 350, { 1, 31 }, { 1, 3 }, { 3, 1 }, false }; + } + else if(preset == "FuriHalSubGhzPresetOok650Async") { + rcswitch_protocol_no = 2; + rcswitch_protocol = { 650, { 1, 10 }, { 1, 2 }, { 2, 1 }, false }; + } + else { + Serial.print("unsupported preset: "); + Serial.println(preset); + return; + } + /* supported flipper presets: + FuriHalSubGhzPresetIDLE, // < default configuration + FuriHalSubGhzPresetOok270Async, ///< OOK, bandwidth 270kHz, asynchronous + FuriHalSubGhzPresetOok650Async, ///< OOK, bandwidth 650kHz, asynchronous + FuriHalSubGhzPreset2FSKDev238Async, //< FM, deviation 2.380371 kHz, asynchronous + FuriHalSubGhzPreset2FSKDev476Async, //< FM, deviation 47.60742 kHz, asynchronous + FuriHalSubGhzPresetMSK99_97KbAsync, //< MSK, deviation 47.60742 kHz, 99.97Kb/s, asynchronous + FuriHalSubGhzPresetGFSK9_99KbAsync, //< GFSK, deviation 19.042969 kHz, 9.996Kb/s, asynchronous + FuriHalSubGhzPresetCustom, //Custom Preset + */ + + // init output pin + digitalWrite(RfTx, LED_OFF); + if(RfTx==0) RfTx=GROVE_SDA; // quick fix + pinMode(RfTx, OUTPUT); + + if(protocol == "RAW") { + // alloc buffer for transmittimings + int* transmittimings = (int *) calloc(sizeof(int), data.length()); // should be smaller the data.length() + size_t transmittimings_idx = 0; + + // split data into words, convert to int, and store them in transmittimings + String curr_word = ""; + int curr_val = 0; + for(int i=0; i recent_rfcodes[recent_rfcodes_last_used] + recent_rfcodes[recent_rfcodes_last_used] = rfcode; + recent_rfcodes_last_used += 1; + if(recent_rfcodes_last_used == 16) recent_rfcodes_last_used = 0; // cycle +} + +struct RfCodes selectRecentRfMenu() { + // show menu with filenames + options = { }; + bool exit = false; + struct RfCodes selected_code; + for(int i=0; i<16; i++) { + if(recent_rfcodes[i].filepath=="") continue; // not inited + // else + options.push_back({ recent_rfcodes[i].filepath.c_str(), [i, &selected_code](){ selected_code = recent_rfcodes[i]; }}); + } + options.push_back({ "Main Menu" , [&](){ exit=true; }}); + delay(200); + loopOptions(options); + return(selected_code); +} + +void otherRFcodes() { + File databaseFile; + FS *fs = NULL; + String filepath = ""; + struct RfCodes selected_code; + options = { + {"Recent", [&]() { selected_code = selectRecentRfMenu(); }}, + {"LittleFS", [&]() { fs=&LittleFS; }}, + }; + if(setupSdCard()) options.push_back({"SD Card", [&]() { fs=&SD; }}); + + delay(200); + loopOptions(options); + delay(200); + + if(fs == NULL) { // recent menu was selected + if(selected_code.filepath!="") sendRfCommand(selected_code); // a code was selected + return; + // no need to proceed, go back + } + + //filepath = loopSD(*fs, true, "SUB"); + filepath = loopSD(*fs, true); + databaseFile = fs->open(filepath, FILE_READ); + drawMainBorder(); + + if (!databaseFile) { + Serial.println("Failed to open database file."); + displayError("Fail to open file"); + delay(2000); + return; + } + Serial.println("Opened sub file."); + selected_code.filepath = filepath.substring( 1 + filepath.lastIndexOf("/") ); + + // format specs: https://github.com/flipperdevices/flipperzero-firmware/blob/dev/documentation/file_formats/SubGhzFileFormats.md + String line; + String txt; + while (databaseFile.available() ) { + line = databaseFile.readStringUntil('\n'); + txt=line.substring(line.indexOf(":") + 1); + txt.trim(); + if(line.startsWith("Protocol:")) selected_code.protocol = txt; + if(line.startsWith("Preset:")) selected_code.preset = txt; + if(line.startsWith("Frequency:")) selected_code.frequency = txt.toInt(); + if(line.startsWith("TE:")) selected_code.te = txt.toInt(); + if(line.startsWith("RAW_Data:") || line.startsWith("Key:")) { selected_code.data += txt; } + } + databaseFile.close(); + + addToRecentCodes(selected_code); + sendRfCommand(selected_code); + + // TODO: menu to resend command/pick another file from the same dir? + + digitalWrite(RfTx, LED_OFF); +} diff --git a/src/modules/rf/rf.h b/src/modules/rf/rf.h index a5116b51..75053a86 100644 --- a/src/modules/rf/rf.h +++ b/src/modules/rf/rf.h @@ -15,4 +15,7 @@ const int PCA9554TRX_PIN = 0; void rf_spectrum(); void rf_jammerIntermittent(); -void rf_jammerFull(); \ No newline at end of file +void rf_jammerFull(); +void otherRFcodes(); + +void RCSwitch_send(uint64_t data, unsigned int bits, int pulse=0, int protocol=1, int repeat=10);