diff --git a/platformio.ini b/platformio.ini index f7a01c72..96b98807 100644 --- a/platformio.ini +++ b/platformio.ini @@ -310,9 +310,8 @@ build_flags = ;Radio Frequency (one pin modules) pin setting -DRF_TX_PINS='{ {"M5 RF433T", GROVE_SDA}, {"Groove W", GROVE_SCL}, {"GROVE Y", GROVE_SDA}}' -DRF_RX_PINS='{ {"M5 RF433R", GROVE_SCL}, {"Groove W", GROVE_SCL}, {"GROVE Y", GROVE_SDA}}' - -DUSE_CC1101_VIA_SPI ; connection pins using microSD sniffer module https://www.sparkfun.com/products/9419 https://docs.m5stack.com/en/core/Cardputer - -DUSE_CC1101_VIA_SPI + ;-DUSE_CC1101_VIA_SPI -DCC1101_GDO0_PIN=GROVE_SDA -DCC1101_SS_PIN=GROVE_SCL ; chip select -DCC1101_MOSI_PIN=14 diff --git a/src/core/serialcmds.cpp b/src/core/serialcmds.cpp index fa454794..2a125690 100644 --- a/src/core/serialcmds.cpp +++ b/src/core/serialcmds.cpp @@ -5,7 +5,7 @@ //#include #include "cJSON.h" #include // for PRIu64 - +#include #include "sd_functions.h" #include "settings.h" @@ -47,6 +47,29 @@ void startSerialCommandsHandlerTask() { } +bool is_free_gpio_pin(int pin_no ){ + // check if pin_no is usable for general GPIO + std::vector usable_pins = {GROVE_SDA, GROVE_SCL}; + + #if defined(STICK_C_PLUS2) || defined(STICK_C_PLUS) + usable_pins.insert(usable_pins.end(), { 25, 26, 32, 33, 0 }); + #elif defined(ESP32S3DEVKITC1) + usable_pins.insert(usable_pins.end(), { + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, // GPIO1 to GPIO25 + 33, // GPIO33 + 38, 39, 40, 41, 42, 43, 44, // GPIO38 to GPIO44 + 47, 48 // GPIO47 to GPIO48 + }); + #endif + + for (int usable_pin : usable_pins) + if (pin_no == usable_pin ) + return true; + // else + return false; +} + + void SerialPrintHexString(uint64_t val) { char s[18] = {0}; //snprintf(s, 10, "%x", val); @@ -229,7 +252,7 @@ bool processSerialCommand(String cmd_str) { // flipperzero-like cmd https://docs.flipper.net/development/cli/#wLVht // e.g. subghz tx 0000000000200001 868250000 403 10 // https://forum.flipper.net/t/friedland-libra-48249sl-wireless-doorbell-request/4528/20 // {hex_key} {frequency} {te} {count} - // subghz tx 000000000044553C 433920000 174 10 + // subghz tx 445533 433920000 174 10 const char* args = cmd_str.c_str() + strlen("subghz tx"); uint64_t key=0; unsigned long frequency=433920000; @@ -237,10 +260,10 @@ bool processSerialCommand(String cmd_str) { unsigned int count=10; if(strlen(args)<=1) return false; if(sscanf(args, " %llx %lu %u %u", &key, &frequency, &te, &count)<=0) return false; // missing 1 req arg + unsigned int bits=24; // TODO: compute from key if(!initRfModule("tx", float(frequency/1000000.0))) return false; // check valid frequency and init the rf module - unsigned int bits=64; // TODO: compute from key - //RCSwitch_send( hexStringToDecimal(txt.c_str()) , bits, pulse, protocol, repeat); RCSwitch_send( key, bits, te, 1, count ); + deinitRfModule(); return true; } @@ -424,11 +447,161 @@ bool processSerialCommand(String cmd_str) { //esp_timer_stop(screensaver_timer); return true; } + + // gpio cmds https://docs.flipper.net/development/cli/#aqA4b + if(cmd_str.startsWith("gpio mode ")) { + const char* args = cmd_str.c_str() + strlen("gpio mode "); + int pin_number=-1; + int mode=0; + if (sscanf(args, "%d %d", &pin_number, &mode) == 2) { + // check usable pins according to the env + if(mode>=0 && mode<=1 && is_free_gpio_pin(pin_number)) { + pinMode(pin_number, mode); + return true; + } + } + // else + Serial.print("invalid args: "); + Serial.println(args); + return false; + } + if(cmd_str.startsWith("gpio set ")) { + const char* args = cmd_str.c_str() + strlen("gpio set "); + int pin_number=-1; + int value=0; + if (sscanf(args, "%d %d", &pin_number, &value) == 2) { + // check usable pins according to the env + if(value>=0 && value<=1 && is_free_gpio_pin(pin_number)) { + digitalWrite(pin_number, value); + return true; + } + } + // else + Serial.print("invalid args: "); + Serial.println(args); + return false; + } + if(cmd_str.startsWith("gpio read ")) { + const char* args = cmd_str.c_str() + strlen("gpio read "); + int pin_number=-1; + if (sscanf(args, "%d", &pin_number) == 1) { + // check usable pins according to the env + if(is_free_gpio_pin(pin_number)) { + Serial.println(digitalRead(pin_number)); + return true; + } + } + // else + Serial.print("invalid args: "); + Serial.println(args); + return false; + } - // TODO: "storage" cmd to manage files https://docs.flipper.net/development/cli/#Xgais - - // TODO: "gpio" cmds https://docs.flipper.net/development/cli/#aqA4b - + if(cmd_str == "factory_reset") { + // remove config file and recreate + if(SD.exists(CONFIG_FILE)) SD.remove(CONFIG_FILE); + if(LittleFS.exists(CONFIG_FILE)) LittleFS.remove(CONFIG_FILE); + // TODO: need to reset EEPROM too? + getConfigs(); // recreate config file if it does not exists + return true; + } + + if(cmd_str == "settings") { + // view current settings + JsonObject setting = settings[0]; + serializeJsonPretty(settings, Serial); + Serial.println(""); + return true; + } + if(cmd_str == "info device" || cmd_str == "!") { + Serial.print("Bruce v"); + Serial.println(BRUCE_VERSION); + // https://github.com/espressif/arduino-esp32/blob/master/libraries/ESP32/examples/ChipID/GetChipID/GetChipID.ino + Serial.printf("Chip is %s (revision v%d)\n", ESP.getChipModel(), ESP.getChipRevision()); + Serial.printf("Detected flash size: %d\n", ESP.getFlashChipSize()); + //Serial.printf("This chip has %d cores\n", ESP.getChipCores()); + //Serial.printf("CPU Freq is %d\n", ESP.getCpuFreqMHz()); + // Features: WiFi, BLE, Embedded Flash 8MB (GD) + // Crystal is 40MHz + // MAC: 24:58:7c:5b:24:5c + return true; + } + + if(cmd_str == "free") { + // report free memory + Serial.print("Total heap: "); + Serial.println(ESP.getHeapSize()); + Serial.print("Free heap: "); + Serial.println(ESP.getFreeHeap()); + if(psramFound()) { + Serial.print("Total PSRAM: "); + Serial.println(ESP.getPsramSize()); + Serial.print("Free PSRAM: "); + Serial.println(ESP.getFreePsram()); + } + return true; + } + + if(cmd_str == "i2c") { + // scan for connected i2c modules + // derived from https://learn.adafruit.com/scanning-i2c-addresses/arduino + Wire.begin(GROVE_SDA, GROVE_SCL); + byte error, address; + int nDevices; + Serial.println("Scanning..."); + nDevices = 0; + for(address = 1; address < 127; address++ ) + { + // The i2c_scanner uses the return value of + // the Write.endTransmisstion to see if + // a device did acknowledge to the address. + Wire.beginTransmission(address); + error = Wire.endTransmission(); + if (error == 0) + { + Serial.print("I2C device found at address 0x"); + if (address<16) + Serial.print("0"); + Serial.print(address,HEX); + Serial.println(" !"); + nDevices++; + } + else if (error==4) + { + Serial.print("Unknown error at address 0x"); + if (address<16) + Serial.print("0"); + Serial.println(address,HEX); + } + } // end for + if (nDevices == 0) { + Serial.println("No I2C devices found\n"); + return false; + } else { + Serial.println("done\n"); + return true; + } + } + + /* WIP + // "storage" cmd to manage files https://docs.flipper.net/development/cli/#Xgais + if(cmd_str.startsWith("storage read ")) { + String txt = ""; + String filepath = cmd_str.substring(strlen("storage read "), cmd_str.length()); + filepath.trim(); + if(!filepath.startsWith("/")) filepath = "/" + filepath; // add "/" if missing + if(SD.exists(filepath)) txt = readSmallFile(SD, filepath);; + if(LittleFS.exists(filepath)) txt = readSmallFile(LittleFS, filepath); + if(txt.length()!=0) { + Serial.println(txt); + return true; + } else return false; + }*/ + + // TODO: date + // TODO: uptime + // TODO: help + // TODO: more commands https://docs.flipper.net/development/cli#0Z9fs Serial.println("unsupported serial command: " + cmd_str); diff --git a/src/core/settings.cpp b/src/core/settings.cpp index 97795c4d..ff05f149 100644 --- a/src/core/settings.cpp +++ b/src/core/settings.cpp @@ -283,11 +283,12 @@ void setRFModuleMenu() { */ }; delay(200); - loopOptions(options); // TODO: pre-select current value of RfModule + loopOptions(options, idx); // 2fix: idx highlight not working? delay(200); EEPROM.begin(EEPROMSIZE); // open eeprom if(result == 1) { - #ifdef USE_CC1101_VIA_SPI + #ifdef USE_CC1101_VIA_SPI + ELECHOUSE_cc1101.Init(); if (ELECHOUSE_cc1101.getCC1101()){ RfModule=1; EEPROM.write(13, RfModule); //set the byte diff --git a/src/modules/rf/rf.cpp b/src/modules/rf/rf.cpp index e4742c62..960e30af 100644 --- a/src/modules/rf/rf.cpp +++ b/src/modules/rf/rf.cpp @@ -70,6 +70,10 @@ void initRMT() { rxconfig.rmt_mode = RMT_MODE_RX; rxconfig.channel = RMT_RX_CHANNEL; rxconfig.gpio_num = gpio_num_t(RfRx); + #ifdef USE_CC1101_VIA_SPI + if(RfModule==1) + rxconfig.gpio_num = gpio_num_t(CC1101_GDO0_PIN); + #endif rxconfig.clk_div = RMT_CLK_DIV; // RMT_DEFAULT_CLK_DIV=32 rxconfig.mem_block_num = 1; rxconfig.flags = 0; @@ -90,8 +94,8 @@ void rf_spectrum() { //@IncursioHack - https://github.com/IncursioHack ----thank tft.fillScreen(TFT_BLACK); tft.setTextSize(1); tft.println(""); - tft.println(" RF433 - Spectrum"); - pinMode(RfRx, INPUT); + tft.println(" RF - Spectrum"); + if(!initRfModule("rx", RfFreq)) return; initRMT(); RingbufHandle_t rb = nullptr; @@ -128,15 +132,25 @@ void rf_spectrum() { //@IncursioHack - https://github.com/IncursioHack ----thank void rf_jammerFull() { //@IncursioHack - https://github.com/IncursioHack - thanks @EversonPereira - rfcardputer - pinMode(RfTx, OUTPUT); + // init rf module + int nTransmitterPin = RfTx; + if(!initRfModule("tx")) return; + if(RfModule == 1) { // CC1101 in use + #ifdef USE_CC1101_VIA_SPI + nTransmitterPin = CC1101_GDO0_PIN; + #else + return; + #endif + } + tft.fillScreen(TFT_BLACK); tft.println(""); - tft.println(" RF433 - Jammer Full"); + tft.println(" RF - Jammer Full"); tft.println(""); tft.println(""); tft.setTextSize(2); sendRF = true; - digitalWrite(RfTx, HIGH); // Turn on Jammer + digitalWrite(nTransmitterPin, HIGH); // Turn on Jammer int tmr0=millis(); // control total jammer time; tft.println("Sending... Press ESC to stop."); while (sendRF) { @@ -146,15 +160,24 @@ void rf_jammerFull() { //@IncursioHack - https://github.com/IncursioHack - than break; } } - digitalWrite(RfTx, LOW); // Turn Jammer OFF + deinitRfModule(); // Turn Jammer OFF } void rf_jammerIntermittent() { //@IncursioHack - https://github.com/IncursioHack - thanks @EversonPereira - rfcardputer - pinMode(RfTx, OUTPUT); + int nTransmitterPin = RfTx; + if(!initRfModule("tx")) return; + if(RfModule == 1) { // CC1101 in use + #ifdef USE_CC1101_VIA_SPI + nTransmitterPin = CC1101_GDO0_PIN; + #else + return; + #endif + } + tft.fillScreen(TFT_BLACK); tft.println(""); - tft.println(" RF433 - Jammer Intermittent"); + tft.println(" RF - Jammer Intermittent"); tft.println(""); tft.println(""); tft.setTextSize(2); @@ -170,13 +193,13 @@ void rf_jammerIntermittent() { //@IncursioHack - https://github.com/IncursioHack returnToMenu=true; break; } - digitalWrite(RfTx, HIGH); // Ativa o pino + digitalWrite(nTransmitterPin, HIGH); // Ativa o pino // keeps the pin active for a while and increase increase for (int widthsize = 1; widthsize <= (1 + sequence); widthsize++) { delayMicroseconds(50); } - digitalWrite(RfTx, LOW); // Desativa o pino + digitalWrite(nTransmitterPin, LOW); // Desativa o pino // keeps the pin inactive for the same time as before for (int widthsize = 1; widthsize <= (1 + sequence); widthsize++) { delayMicroseconds(50); @@ -185,7 +208,7 @@ void rf_jammerIntermittent() { //@IncursioHack - https://github.com/IncursioHack } } - digitalWrite(RfTx, LOW); // Deactivate pin + deinitRfModule(); } @@ -197,10 +220,7 @@ void RCSwitch_send(uint64_t data, unsigned int bits, int pulse, int protocol, in if(RfModule==1) { #ifdef USE_CC1101_VIA_SPI - pinMode(CC1101_GDO0_PIN, OUTPUT); mySwitch.enableTransmit(CC1101_GDO0_PIN); - ELECHOUSE_cc1101.setPA(12); // set TxPower. The following settings are possible depending on the frequency band. (-30 -20 -15 -10 -6 0 5 7 10 11 12) Default is max! - ELECHOUSE_cc1101.SetTx(); #else Serial.println("USE_CC1101_VIA_SPI not defined"); return; // not enabled for this board @@ -220,7 +240,7 @@ void RCSwitch_send(uint64_t data, unsigned int bits, int pulse, int protocol, in Serial.println(pulse); Serial.println(protocol); Serial.println(repeat); - * */ + */ mySwitch.disableTransmit(); @@ -345,8 +365,6 @@ static char * dec2binWzerofill(unsigned long Dec, unsigned int bitLength) { return bin; } - - void initCC1101once() { // the init (); command may only be executed once in the entire program sequence. Otherwise problems can arise. https://github.com/LSatan/SmartRC-CC1101-Driver-Lib/issues/65 @@ -390,8 +408,13 @@ void deinitRfModule() { bool initRfModule(String mode, float frequency) { + // use default frequency if no one is passed + if(!frequency) frequency = RfFreq; + if(RfModule == 1) { // CC1101 in use - #ifdef USE_CC1101_VIA_SPI + #ifdef USE_CC1101_VIA_SPI + ELECHOUSE_cc1101.Init(); + if (ELECHOUSE_cc1101.getCC1101()){ // Check the CC1101 Spi connection. Serial.println("cc1101 Connection OK"); } else { @@ -399,27 +422,27 @@ bool initRfModule(String mode, float frequency) { return false; } - ELECHOUSE_cc1101.Init(); - // make sure it is in idle state when changing frequency and other parameters // "If any frequency programming register is altered when the frequency synthesizer is running, the synthesizer may give an undesired response. Hence, the frequency programming should only be updated when the radio is in the IDLE state." https://github.com/LSatan/SmartRC-CC1101-Driver-Lib/issues/65 ELECHOUSE_cc1101.setSidle(); - - // use default frequency if no one is passed - if(!frequency) frequency = RfFreq; - + if(!(frequency>=300 && frequency<=928)) // TODO: check all supported subranges: 300-348 MHZ, 387-464MHZ and 779-928MHZ. return false; // else ELECHOUSE_cc1101.setMHZ(frequency); - /* MEMO: cannot change other params after this is executed -> moved in the caller func - if(mode=="tx") + /* MEMO: cannot change other params after this is executed */ + if(mode=="tx") { + pinMode(CC1101_GDO0_PIN, OUTPUT); ELECHOUSE_cc1101.setPA(12); // set TxPower. The following settings are possible depending ELECHOUSE_cc1101.SetTx(); - else + } + else if(mode=="rx") { + pinMode(CC1101_GDO0_PIN, INPUT); ELECHOUSE_cc1101.SetRx(); - */ + } + // else if mode is unspecified wont start TX/RX mode here -> done by the caller + #else // TODO: PCA9554-based implmentation return false; @@ -437,7 +460,8 @@ bool initRfModule(String mode, float frequency) { //if(RfTx==0) RfTx=GROVE_SDA; // quick fix pinMode(RfTx, OUTPUT); digitalWrite(RfTx, LED_OFF); - } else { + } + else if(mode=="rx") { // Rx Mode gsetRfRxPin(false); //if(RfRx==0) RfRx=GROVE_SCL; // quick fix @@ -469,10 +493,8 @@ bool RCSwitch_Read_Raw(float frequency) { #ifdef CC1101_GDO2_PIN rcswitch.enableReceive(CC1101_GDO2_PIN); #else - pinMode(CC1101_GDO0_PIN, INPUT); rcswitch.enableReceive(CC1101_GDO0_PIN); #endif - ELECHOUSE_cc1101.SetRx(); #else return false; #endif @@ -601,9 +623,16 @@ bool RCSwitch_Read_Raw(float frequency) { // ported from https://github.com/sui77/rc-switch/blob/3a536a172ab752f3c7a58d831c5075ca24fd920b/RCSwitch.cpp -void RCSwitch_RAW_Bit_send(int nTransmitterPin, RfCodes data) { - if (nTransmitterPin == -1) - return; +void RCSwitch_RAW_Bit_send(RfCodes data) { + int nTransmitterPin = RfTx; + if(RfModule==1) { + #ifdef USE_CC1101_VIA_SPI + nTransmitterPin = CC1101_GDO0_PIN; + #else + return; + #endif + } + if (data.data == "") return; bool currentlogiclevel = false; @@ -626,19 +655,27 @@ void RCSwitch_RAW_Bit_send(int nTransmitterPin, RfCodes data) { digitalWrite(nTransmitterPin, currentlogiclevel ? HIGH : LOW); delayMicroseconds(data.te); - Serial.print(currentBit); - Serial.print("="); - Serial.println(currentlogiclevel); + //Serial.print(currentBit); + //Serial.print("="); + //Serial.println(currentlogiclevel); currentBit--; } digitalWrite(nTransmitterPin, LOW); } } -void RCSwitch_RAW_send(int nTransmitterPin, int * ptrtransmittimings) { - if (nTransmitterPin == -1) - return; + +void RCSwitch_RAW_send(int * ptrtransmittimings) { + int nTransmitterPin = RfTx; + if(RfModule==1) { + #ifdef USE_CC1101_VIA_SPI + nTransmitterPin = CC1101_GDO0_PIN; + #else + return; + #endif + } + if (!ptrtransmittimings) return; @@ -744,7 +781,7 @@ void sendRfCommand(struct RfCodes rfcode) { } // init transmitter - if(!initRfModule("tx", frequency/1000000.0)) return; + if(!initRfModule("", frequency/1000000.0)) return; if(RfModule == 1) { // CC1101 in use #ifdef USE_CC1101_VIA_SPI // derived from https://github.com/LSatan/SmartRC-CC1101-Driver-Lib/blob/master/examples/Rc-Switch%20examples%20cc1101/SendDemo_cc1101/SendDemo_cc1101.ino @@ -752,7 +789,11 @@ void sendRfCommand(struct RfCodes rfcode) { if(deviation) ELECHOUSE_cc1101.setDeviation(deviation); if(rxBW) ELECHOUSE_cc1101.setRxBW(rxBW); // Set the Receive Bandwidth in kHz. Value from 58.03 to 812.50. Default is 812.50 kHz. if(dataRate) ELECHOUSE_cc1101.setDRate(dataRate); + pinMode(CC1101_GDO0_PIN, OUTPUT); + ELECHOUSE_cc1101.setPA(12); // set TxPower. The following settings are possible depending on the frequency band. (-30 -20 -15 -10 -6 0 5 7 10 11 12) Default is max! + ELECHOUSE_cc1101.SetTx(); #else + Serial.println("USE_CC1101_VIA_SPI not defined"); return; #endif } else { @@ -762,6 +803,7 @@ void sendRfCommand(struct RfCodes rfcode) { Serial.println(modulation); return; } + initRfModule("tx", frequency/1000000.0); } if(protocol == "RAW") { @@ -792,14 +834,14 @@ void sendRfCommand(struct RfCodes rfcode) { // send rf command displayRedStripe("Sending..",TFT_WHITE,FGCOLOR); - RCSwitch_RAW_send(RfTx, transmittimings); + RCSwitch_RAW_send(transmittimings); free(transmittimings); } else if (protocol == "BinRAW") { rfcode.data = hexStrToBinStr(rfcode.data); // transform from "00 01 02 ... FF" into "00000000 00000001 00000010 .... 11111111" - Serial.println(rfcode.data); + //Serial.println(rfcode.data); rfcode.data.trim(); - RCSwitch_RAW_Bit_send(RfTx,rfcode); + RCSwitch_RAW_Bit_send(rfcode); } else if(protocol == "RcSwitch") { diff --git a/src/modules/rf/rf.h b/src/modules/rf/rf.h index 2aab46a0..951b18a2 100644 --- a/src/modules/rf/rf.h +++ b/src/modules/rf/rf.h @@ -22,6 +22,6 @@ bool RCSwitch_Read_Raw(float frequency=0); void RCSwitch_send(uint64_t data, unsigned int bits, int pulse=0, int protocol=1, int repeat=10); void addToRecentCodes(struct RfCodes rfcode); void sendRfCommand(struct RfCodes rfcode); -bool initRfModule(String mode, float frequency=0); +bool initRfModule(String mode="", float frequency=0); void initCC1101once(); void deinitRfModule(); \ No newline at end of file