Compare commits

..

4 Commits

Author SHA1 Message Date
Ricardo Guzman (Richonguzman)
0eec028c5d update SENSOR BUS 2026-02-23 12:00:55 -03:00
Ricardo Guzman (Richonguzman)
c48dd15bd6 better ADC and VEXT control 2026-02-23 11:14:42 -03:00
Ricardo Guzman (Richonguzman)
f26ded5b5c less memory fixes too 2026-02-20 17:36:26 -03:00
Ricardo Guzman (Richonguzman)
c887689406 indexOf transformation 2026-02-20 17:03:39 -03:00
27 changed files with 234 additions and 232 deletions

View File

@@ -1,17 +1,17 @@
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
*
*
* This file is part of LoRa APRS iGate.
*
*
* LoRa APRS iGate is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
*
* LoRa APRS iGate is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*
* You should have received a copy of the GNU General Public License
* along with LoRa APRS iGate. If not, see <https://www.gnu.org/licenses/>.
*/
@@ -26,7 +26,7 @@
#ifdef HAS_A7670
#define TINY_GSM_MODEM_SIM7600 //The AT instruction of A7670 is compatible with SIM7600
#define TINY_GSM_MODEM_SIM7600 //The AT instruction of A7670 is compatible with SIM7600
#define TINY_GSM_RX_BUFFER 1024 // Set RX buffer to 1Kb
#define SerialAT Serial1
#include <TinyGsmClient.h>
@@ -115,6 +115,8 @@
if (SerialAT.available()) {
String response = SerialAT.readString();
//Serial.println(response); // DEBUG of Modem AT message
int responseOKIndex = response.indexOf("OK");
int callsignIndex = ATMessage.indexOf(Config.callsign);
if(response.indexOf("verified") >= 0) {
Serial.println("Logged! (User Validated)\n");
displayShow(firstLine, "Connecting APRS-IS...", "---> Logged!", " ", 1000);
@@ -122,7 +124,7 @@
validAT = true;
i = 1;
delayATMessage = 0;
} else if (ATMessage == "AT+NETOPEN" && response.indexOf("OK") >= 0) {
} else if (ATMessage == "AT+NETOPEN" && responseOKIndex >= 0) {
Serial.println("Port Open!");
displayShow(firstLine, "Opening Port...", "---> Port Open", " ", 0);
validAT = true;
@@ -145,14 +147,14 @@
validAT = true;
i = 1;
delayATMessage = 0;
} else if (ATMessage.indexOf(Config.callsign) >= 3 && !modemLoggedToAPRSIS && response.indexOf("OK") >= 0 && !stationBeacon) { // login info
} else if (callsignIndex >= 3 && !modemLoggedToAPRSIS && responseOKIndex >= 0 && !stationBeacon) { // login info
validAT = true;
delayATMessage = 0;
} else if (ATMessage.indexOf(Config.callsign) == 0 && !beaconSent && response.indexOf("OK") >= 0 && !stationBeacon) { // self beacon or querys
} else if (callsignIndex == 0 && !beaconSent && responseOKIndex >= 0 && !stationBeacon) { // self beacon or querys
validAT = true;
i = 1;
delayATMessage = 0;
} else if (stationBeacon && response.indexOf("OK") >= 0) { //upload others beacons
} else if (stationBeacon && responseOKIndex >= 0) { //upload others beacons
validAT = true;
i = 1;
delayATMessage = 0;
@@ -200,7 +202,7 @@
if (beaconBytesSent) {
Serial.print(".");
beaconSent = checkATResponse(packet);
}
}
if (!beaconSent) {
Serial.println("------------------------------------> UPLOAD FAILED!!!");
} else {
@@ -221,5 +223,5 @@
delay(1);
}
}
#endif

View File

@@ -1,17 +1,17 @@
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
*
*
* This file is part of LoRa APRS iGate.
*
*
* LoRa APRS iGate is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
*
* LoRa APRS iGate is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*
* You should have received a copy of the GNU General Public License
* along with LoRa APRS iGate. If not, see <https://www.gnu.org/licenses/>.
*/
@@ -24,7 +24,7 @@
██║ ██║ ██║██╔══██╗██╔══██║ ██╔══██║██╔═══╝ ██╔══██╗╚════██║
███████╗╚██████╔╝██║ ██║██║ ██║ ██║ ██║██║ ██║ ██║███████║
╚══════╝ ╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═╝ ╚═╝ ╚═╝╚═╝ ╚═╝ ╚═╝╚══════╝
██╗ ██████╗ █████╗ ████████╗███████╗
██║██╔════╝ ██╔══██╗╚══██╔══╝██╔════╝
██║██║ ███╗███████║ ██║ █████╗
@@ -67,7 +67,7 @@ ___________________________________________________________________*/
#endif
String versionDate = "2026-02-16";
String versionDate = "2026-02-20";
String versionNumber = "3.2";
Configuration Config;
WiFiClient aprsIsClient;
@@ -138,7 +138,7 @@ void loop() {
ElegantOTA.loop();
return; // Don't process IGate and Digi during OTA update
}
#ifdef HAS_GPS
if (Config.beacon.gpsActive) {
if (millis() - gpsSatelliteTime > 5000) {
@@ -174,7 +174,7 @@ void loop() {
Utils::checkDisplayInterval();
Utils::checkBeaconInterval();
APRS_IS_Utils::checkStatus(); // Need that to update display, maybe split this and send APRSIS status to display func?
String packet = "";

View File

@@ -1,17 +1,17 @@
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
*
*
* This file is part of LoRa APRS iGate.
*
*
* LoRa APRS iGate is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
*
* LoRa APRS iGate is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*
* You should have received a copy of the GNU General Public License
* along with LoRa APRS iGate. If not, see <https://www.gnu.org/licenses/>.
*/
@@ -105,9 +105,9 @@ namespace BATTERY_Utils {
void getI2CVoltageSensorAddress() {
uint8_t err, addr;
for(addr = 1; addr < 0x7F; addr++) {
#if defined(HELTEC_V3) || defined(HELTEC_V3_2) || defined(HELTEC_WSL_V3) || defined(HELTEC_WSL_V3_DISPLAY)
Wire1.beginTransmission(addr);
err = Wire1.endTransmission();
#ifdef SENSOR_I2C_BUS
SENSOR_I2C_BUS.beginTransmission(addr);
err = SENSOR_I2C_BUS.endTransmission();
#else
Wire.beginTransmission(addr);
err = Wire.endTransmission();
@@ -145,7 +145,7 @@ namespace BATTERY_Utils {
}
}
float checkInternalVoltage() {
float checkInternalVoltage() {
#if defined(HAS_AXP192) || defined(HAS_AXP2101)
if(POWER_Utils::isBatteryConnected()) {
return POWER_Utils::getBatteryVoltage();
@@ -153,7 +153,7 @@ namespace BATTERY_Utils {
return 0.0;
}
#else
#ifdef ADC_CTRL
POWER_Utils::adc_ctrl_ON();
#endif
@@ -177,7 +177,7 @@ namespace BATTERY_Utils {
#endif
#endif
#endif
delay(3);
delay(3);
}
#ifdef ADC_CTRL
@@ -241,7 +241,7 @@ namespace BATTERY_Utils {
#else
extVoltage = ((((sampleSum/100.0)* adcReadingTransformation) + readingCorrection) * voltageDividerTransformation) - multiplyCorrection;
#endif
return extVoltage; // raw voltage without mapping
// return mapVoltage(voltage, 5.05, 6.32, 4.5, 5.5); // mapped voltage

View File

@@ -44,37 +44,38 @@ extern bool backupDigiMode;
namespace DIGI_Utils {
String buildPacket(const String& path, const String& packet, bool thirdParty, bool crossFreq) {
String stationCallsign = (Config.tacticalCallsign == "" ? Config.callsign : Config.tacticalCallsign);
if (!crossFreq) {
String packetToRepeat = packet.substring(0, packet.indexOf(",") + 1);
String tempPath = path;
int digiMode = Config.digi.mode;
if (path.indexOf("WIDE1-1") != -1 && (Config.digi.mode == 2 || Config.digi.mode == 3)) {
tempPath.replace("WIDE1-1", (Config.tacticalCallsign == "" ? Config.callsign : Config.tacticalCallsign) + "*");
} else if (path.indexOf("WIDE2-") != -1 && Config.digi.mode == 3) {
if (path.indexOf(",WIDE1*") != -1) {
tempPath.remove(path.indexOf(",WIDE1*"), 7);
if (path.indexOf("WIDE1-1") != -1 && (digiMode == 2 || digiMode == 3)) {
tempPath.replace("WIDE1-1", stationCallsign + "*");
} else if (path.indexOf("WIDE2-") != -1 && digiMode == 3) {
int wide1AsteriskIndex = path.indexOf(",WIDE1*"); // less memory than: tempPath.replace(",WIDE1*", "");
if (wide1AsteriskIndex != -1) {
tempPath.remove(wide1AsteriskIndex, 7);
}
if (path.indexOf("*") != -1) {
tempPath.remove(path.indexOf("*"), 1);
int asteriskIndex = path.indexOf("*"); // less memory than: tempPath.replace("*", "");
if (asteriskIndex != -1) {
tempPath.remove(asteriskIndex, 1);
}
if (path.indexOf("WIDE2-1") != -1) {
tempPath.replace("WIDE2-1", (Config.tacticalCallsign == "" ? Config.callsign : Config.tacticalCallsign) + "*");
tempPath.replace("WIDE2-1", stationCallsign + "*");
} else if (path.indexOf("WIDE2-2") != -1) {
tempPath.replace("WIDE2-2", (Config.tacticalCallsign == "" ? Config.callsign : Config.tacticalCallsign) + "*,WIDE2-1");
tempPath.replace("WIDE2-2", stationCallsign + "*,WIDE2-1");
} else {
return "";
}
}
packetToRepeat += tempPath;
if (thirdParty) {
packetToRepeat += APRS_IS_Utils::checkForStartingBytes(packet.substring(packet.indexOf(":}")));
} else {
packetToRepeat += APRS_IS_Utils::checkForStartingBytes(packet.substring(packet.indexOf(":")));
}
packetToRepeat += APRS_IS_Utils::checkForStartingBytes(packet.substring(packet.indexOf(thirdParty ? ":}" : ":")));
return packetToRepeat;
} else { // CrossFreq Digipeater
String suffix = thirdParty ? ":}" : ":";
String packetToRepeat = packet.substring(0, packet.indexOf(suffix));
String suffix = thirdParty ? ":}" : ":";
int suffixIndex = packet.indexOf(suffix);
String packetToRepeat = packet.substring(0, suffixIndex);
String terms[] = {",WIDE1*", ",WIDE2*", "*"};
for (String term : terms) {
@@ -84,9 +85,9 @@ namespace DIGI_Utils {
}
}
packetToRepeat += ",";
packetToRepeat += (Config.tacticalCallsign == "" ? Config.callsign : Config.tacticalCallsign);
packetToRepeat += stationCallsign;
packetToRepeat += "*";
packetToRepeat += APRS_IS_Utils::checkForStartingBytes(packet.substring(packet.indexOf(suffix)));
packetToRepeat += APRS_IS_Utils::checkForStartingBytes(packet.substring(suffixIndex));
return packetToRepeat;
}
}
@@ -99,39 +100,39 @@ namespace DIGI_Utils {
} else {
temp = packet.substring(packet.indexOf(">") + 1, packet.indexOf(":"));
}
if (temp.indexOf(",") > 2) { // checks for path in temp
const String& path = temp.substring(temp.indexOf(",") + 1); // extract path after tocall
if (Config.digi.mode == 2 || backupDigiMode) {
if (path.indexOf("WIDE1-1") != - 1) {
return buildPacket(path, packet, thirdParty, false);
} else if (path.indexOf("WIDE1-1") == -1 && (abs(Config.loramodule.txFreq - Config.loramodule.rxFreq) >= 125000)) { // CrossFreq Digi
return buildPacket(path, packet, thirdParty, true);
} else {
return "";
}
} else if (Config.digi.mode == 3) {
if (path.indexOf("WIDE1-1") != -1 || path.indexOf("WIDE2-") != -1) {
int wide1Index = path.indexOf("WIDE1-1");
int wide2Index = path.indexOf("WIDE2-");
int commaIndex = temp.indexOf(",");
int digiMode = Config.digi.mode;
bool crossFreq = abs(Config.loramodule.txFreq - Config.loramodule.rxFreq) >= 125000; // CrossFreq Digi
// WIDE1-1 && WIDE2-n / only WIDE1-1 / only WIDE2-n
if ((wide1Index != -1 && wide2Index != -1 && wide1Index < wide2Index) || (wide1Index != -1 && wide2Index == -1) || (wide1Index == -1 && wide2Index != -1)) {
return buildPacket(path, packet, thirdParty, false);
}
return "";
} else if (path.indexOf("WIDE1-1") == -1 && path.indexOf("WIDE2-") == -1 && (abs(Config.loramodule.txFreq - Config.loramodule.rxFreq) >= 125000)) { // CrossFreq Digi
return buildPacket(path, packet, thirdParty, true);
} else {
return "";
if (commaIndex > 2) { // Packet has "path"
const String& path = temp.substring(commaIndex + 1);
if (digiMode == 2 || backupDigiMode) {
bool hasWide = path.indexOf("WIDE1-1") != -1;
if (hasWide || crossFreq) {
return buildPacket(path, packet, thirdParty, !hasWide);
}
} else {
return "";
}
} else if (temp.indexOf(",") == -1 && (Config.digi.mode == 2 || backupDigiMode || Config.digi.mode == 3) && (abs(Config.loramodule.txFreq - Config.loramodule.rxFreq) >= 125000)) {
return buildPacket("", packet, thirdParty, true);
} else {
if (digiMode == 3) {
int wide1Index = path.indexOf("WIDE1-1");
int wide2Index = path.indexOf("WIDE2-");
bool hasWide1 = wide1Index != -1;
bool hasWide2 = wide2Index != -1;
if (hasWide1 && hasWide2 && wide2Index < wide1Index) return ""; // check that WIDE1 before WIDE2
if (hasWide1 || hasWide2) return buildPacket(path, packet, thirdParty, false); // regular APRS with WIDEn-N
if (crossFreq) return buildPacket(path, packet, thirdParty, true); // CrossFreq (without WIDE)
return "";
}
return "";
}
if (commaIndex == -1 && (digiMode == 2 || backupDigiMode || digiMode == 3) && crossFreq) return buildPacket("", packet, thirdParty, true); // no "path" but is CrossFreq Digi
return "";
}
void processLoRaPacket(const String& packet) {
@@ -149,18 +150,20 @@ namespace DIGI_Utils {
Sender = packet.substring(3, packet.indexOf(">"));
}
if (Sender == (Config.tacticalCallsign == "" ? Config.callsign : Config.tacticalCallsign)) return; // Avoid listening to self packets
String stationCallsign = Config.tacticalCallsign == "" ? Config.callsign : Config.tacticalCallsign;
if (Sender == stationCallsign) return; // Avoid listening to self packets
if (!thirdPartyPacket && Config.tacticalCallsign == "" && !Utils::callsignIsValid(Sender)) return; // No thirdParty + no tactical y no valid callsign
if (STATION_Utils::check25SegBuffer(Sender, temp.substring(temp.indexOf(":") + 2))) {
STATION_Utils::updateLastHeard(Sender);
Utils::typeOfPacket(temp, 2); // Digi
Utils::typeOfPacket(temp, 2); // Digi
bool queryMessage = false;
if (temp.indexOf("::") > 10) { // it's a message
String AddresseeAndMessage = temp.substring(temp.indexOf("::") + 2);
int doubleColonIndex = temp.indexOf("::");
if (doubleColonIndex > 10) { // it's a message
String AddresseeAndMessage = temp.substring(doubleColonIndex + 2);
String Addressee = AddresseeAndMessage.substring(0, AddresseeAndMessage.indexOf(":"));
Addressee.trim();
if (Addressee == (Config.tacticalCallsign == "" ? Config.callsign : Config.tacticalCallsign)) { // it's a message for me!
if (Addressee == stationCallsign) { // it's a message for me!
queryMessage = APRS_IS_Utils::processReceivedLoRaMessage(Sender, AddresseeAndMessage, thirdPartyPacket);
}
}
@@ -173,7 +176,6 @@ namespace DIGI_Utils {
}
}
}
//}
}
}

View File

@@ -134,15 +134,17 @@ namespace GPS_Utils {
}
String Latitude = infoGPS.substring(0,8); // First 8 characters are Latitude
int latitudeColonIndex = Latitude.indexOf(".");
float convertedLatitude = Latitude.substring(0,2).toFloat(); // First 2 digits (Degrees)
convertedLatitude += Latitude.substring(2,4).toFloat() / 60; // Next 2 digits (Minutes)
convertedLatitude += Latitude.substring(Latitude.indexOf(".") + 1, Latitude.indexOf(".") + 3).toFloat() / (60*100);
convertedLatitude += Latitude.substring(latitudeColonIndex + 1, latitudeColonIndex + 3).toFloat() / (60*100);
if (Latitude.endsWith("S")) convertedLatitude = -convertedLatitude; // Handle Southern Hemisphere
String Longitude = infoGPS.substring(9,18); // Next 9 characters are Longitude
int longitudeColonIndex = Longitude.indexOf(".");
float convertedLongitude = Longitude.substring(0,3).toFloat(); // First 3 digits (Degrees)
convertedLongitude += Longitude.substring(3,5).toFloat() / 60; // Next 2 digits (Minutes)
convertedLongitude += Longitude.substring(Longitude.indexOf(".") + 1, Longitude.indexOf(".") + 3).toFloat() / (60*100);
convertedLongitude += Longitude.substring(longitudeColonIndex + 1, longitudeColonIndex + 3).toFloat() / (60*100);
if (Longitude.endsWith("W")) convertedLongitude = -convertedLongitude; // Handle Western Hemisphere
return buildDistanceAndComment(convertedLatitude, convertedLongitude, infoGPS.substring(19));

View File

@@ -1,17 +1,17 @@
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
*
*
* This file is part of LoRa APRS iGate.
*
*
* LoRa APRS iGate is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
*
* LoRa APRS iGate is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*
* You should have received a copy of the GNU General Public License
* along with LoRa APRS iGate. If not, see <https://www.gnu.org/licenses/>.
*/
@@ -29,17 +29,16 @@ bool validateKISSFrame(const String& kissFormattedFrame) {
}
String encodeAddressAX25(String tnc2Address) {
bool hasBeenDigipited = tnc2Address.indexOf('*') != -1;
if (tnc2Address.indexOf('-') == -1) {
bool hasBeenDigipited = tnc2Address.indexOf('*') != -1;
int tnc2AddressIndex = tnc2Address.indexOf('-');
if (tnc2AddressIndex == -1) {
if (hasBeenDigipited) {
tnc2Address = tnc2Address.substring(0, tnc2Address.length() - 1);
}
tnc2Address += "-0";
}
int separatorIndex = tnc2Address.indexOf('-');
int separatorIndex = tnc2AddressIndex;
int ssid = tnc2Address.substring(separatorIndex + 1).toInt();
String kissAddress = "";
@@ -131,8 +130,9 @@ String encodeKISS(const String& frame) {
if (validateTNC2Frame(frame)) {
String address = "";
bool dstAddresWritten = false;
for (int p = 0; p <= frame.indexOf(':'); p++) {
bool dstAddresWritten = false;
int colonFrameIndex = frame.indexOf(':');
for (int p = 0; p <= colonFrameIndex; p++) {
char currentChar = frame.charAt(p);
if (currentChar == ':' || currentChar == '>' || currentChar == ',') {
if (!dstAddresWritten && (currentChar == ',' || currentChar == ':')) {
@@ -151,7 +151,7 @@ String encodeKISS(const String& frame) {
ax25Frame.setCharAt(ax25Frame.length() - 1, (char)(lastAddressChar | IS_LAST_ADDRESS_POSITION_MASK));
ax25Frame += (char)APRS_CONTROL_FIELD;
ax25Frame += (char)APRS_INFORMATION_FIELD;
ax25Frame += frame.substring(frame.indexOf(':') + 1);
ax25Frame += frame.substring(colonFrameIndex + 1);
}
String kissFrame = encapsulateKISS(ax25Frame, CMD_DATA);

View File

@@ -49,40 +49,23 @@ extern bool stationCallsignIsValid;
namespace POWER_Utils {
#ifdef VEXT_CTRL
void vext_ctrl_ON() {
#if VEXT_CTRL_INVERTED == 1
digitalWrite(VEXT_CTRL, Config.digi.ecoMode == 1 ? HIGH : LOW);
#else
digitalWrite(VEXT_CTRL, Config.digi.ecoMode == 1 ? LOW : HIGH);
#endif
}
void vext_ctrl_OFF() {
#if VEXT_CTRL_INVERTED == 1
digitalWrite(VEXT_CTRL, Config.digi.ecoMode == 1 ? LOW : HIGH);
#else
digitalWrite(VEXT_CTRL, Config.digi.ecoMode == 1 ? HIGH : LOW);
#endif
}
#endif
#ifdef ADC_CTRL
#ifdef ADC_CTRL_PIN
void adc_ctrl_ON() {
#if ADC_CTRL_INVERTED == 1
digitalWrite(ADC_CTRL, LOW);
#else
digitalWrite(ADC_CTRL, HIGH);
#endif
digitalWrite(ADC_CTRL_PIN, ADC_CTRL_ON_STATE);
}
void adc_ctrl_OFF() {
#if ADC_CTRL_INVERTED == 1
digitalWrite(ADC_CTRL, HIGH);
#else
digitalWrite(ADC_CTRL, LOW);
#endif
digitalWrite(ADC_CTRL_PIN, !ADC_CTRL_ON_STATE);
}
#endif
#ifdef VEXT_CTRL_PIN
void vext_ctrl_ON() {
digitalWrite(VEXT_CTRL_PIN, Config.digi.ecoMode == 1 ? !VEXT_CTRL_ON_STATE : VEXT_CTRL_ON_STATE);
}
void vext_ctrl_OFF() {
digitalWrite(VEXT_CTRL_PIN, Config.digi.ecoMode == 1 ? VEXT_CTRL_ON_STATE : !VEXT_CTRL_ON_STATE);
}
#endif
@@ -313,12 +296,8 @@ namespace POWER_Utils {
Wire.begin(OLED_SDA, OLED_SCL);
#endif
#ifdef USE_WIRE_WITH_BOARD_I2C_PINS
Wire.begin(BOARD_I2C_SDA, BOARD_I2C_SCL);
#endif
#ifdef USE_WIRE1_WITH_BOARD_I2C_PINS
Wire1.begin(BOARD_I2C_SDA, BOARD_I2C_SCL);
#ifdef SENSOR_I2C_BUS
SENSOR_I2C_BUS.begin(BOARD_I2C_SDA, BOARD_I2C_SCL);
#endif
delay(1000);

View File

@@ -77,10 +77,14 @@ namespace QUERY_Utils {
answer.concat("?WHERE on development 73!");
} */
else if (STATION_Utils::isManager(station) && (!queryFromAPRSIS || !Config.remoteManagement.rfOnly)) {
if (queryQuestion.indexOf("?EM=OFF") == 0) {
if ((Config.digi.mode == 2 || Config.digi.mode == 3) && Config.loramodule.txActive && Config.loramodule.rxActive && !Config.aprs_is.active) {
if (Config.digi.ecoMode == 1 || Config.digi.ecoMode == 2) { // Exit Digipeater EcoMode or Digipeater without WiFiAP
answer = (Config.digi.ecoMode == 1) ? "DigiEcoMode:OFF" : "Digipeater + WiFiAP enabled";
int digiMode = Config.digi.mode;
int digiEcoMode = Config.digi.ecoMode;
int radioTxActive = Config.loramodule.txActive;
bool onlyRadioActive = radioTxActive && Config.loramodule.rxActive && !Config.aprs_is.active;
if (queryQuestion.startsWith("?EM=OFF")) {
if ((digiMode == 2 || digiMode == 3) && onlyRadioActive) {
if (digiEcoMode == 1 || digiEcoMode == 2) { // Exit Digipeater EcoMode or Digipeater without WiFiAP
answer = (digiEcoMode == 1) ? "DigiEcoMode:OFF" : "Digipeater + WiFiAP enabled";
Config.digi.ecoMode = 0;
Config.display.alwaysOn = true;
Config.display.timeout = 10;
@@ -92,9 +96,9 @@ namespace QUERY_Utils {
} else {
answer = "Digipeater Mode control not possible";
}
} else if (queryQuestion.indexOf("?EM=ON") == 0) {
if ((Config.digi.mode == 2 || Config.digi.mode == 3) && Config.loramodule.txActive && Config.loramodule.rxActive && !Config.aprs_is.active) {
if (Config.digi.ecoMode == 0) { // Start Digipeater EcoMode
} else if (queryQuestion.startsWith("?EM=ON")) {
if ((digiMode == 2 || digiMode == 3) && onlyRadioActive) {
if (digiEcoMode == 0) { // Start Digipeater EcoMode
answer = "DigiEcoMode:ON";
Config.digi.ecoMode = 1;
shouldSleepLowVoltage = true; // to make sure all packets in outputPacketBuffer are sent before restart.
@@ -105,31 +109,29 @@ namespace QUERY_Utils {
} else {
answer = "Digipeater Mode control not possible";
}
} else if (queryQuestion.indexOf("?EM=?") == 0) { // Digipeater EcoMode Status
if (Config.digi.ecoMode == 0) {
answer = "DigiEcoMode:OFF";
} else if (Config.digi.ecoMode == 1) {
answer = "DigiEcoMode:ON";
} else {
answer = "DigiEcoMode:OFF/Only Serial Output";
} else if (queryQuestion.startsWith("?EM=?")) { // Digipeater EcoMode Status
switch (digiEcoMode) {
case 0: answer = "DigiEcoMode:OFF"; break;
case 1: answer = "DigiEcoMode:ON"; break;
default: answer = "DigiEcoMode:OFF/Only Serial Output";
}
} else if (queryQuestion.indexOf("?TX=ON") == 0) {
if (Config.loramodule.txActive) {
} else if (queryQuestion.startsWith("?TX=ON")) {
if (radioTxActive) {
answer = "TX was ON";
} else {
Config.loramodule.txActive = true;
answer = "TX=ON";
}
} else if (queryQuestion.indexOf("?TX=OFF") == 0) {
if (!Config.loramodule.txActive) {
} else if (queryQuestion.startsWith("?TX=OFF")) {
if (!radioTxActive) {
answer = "TX was OFF";
} else {
Config.loramodule.txActive = false;
answer = "TX=OFF";
}
} else if (queryQuestion.indexOf("?TX=?") == 0) {
answer = (Config.loramodule.txActive) ? "TX=ON" : "TX=OFF";
} else if (queryQuestion.indexOf("?COMMIT") == 0) { // saving for next reboot
} else if (queryQuestion.startsWith("?TX=?")) {
answer = (radioTxActive) ? "TX=ON" : "TX=OFF";
} else if (queryQuestion.startsWith("?COMMIT")) { // saving for next reboot
answer = "New Config Saved";
Config.writeFile();
}

View File

@@ -1,17 +1,17 @@
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
*
*
* This file is part of LoRa APRS iGate.
*
*
* LoRa APRS iGate is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
*
* LoRa APRS iGate is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*
* You should have received a copy of the GNU General Public License
* along with LoRa APRS iGate. If not, see <https://www.gnu.org/licenses/>.
*/
@@ -43,9 +43,11 @@ namespace SYSLOG_Utils {
char signalData[35];
snprintf(signalData, sizeof(signalData), " / %ddBm / %.2fdB / %dHz", rssi, snr, freqError);
int colonIndex = packet.indexOf(":");
char nextChar = packet[colonIndex + 1];
String sender = packet.substring(3, packet.indexOf(">"));
int colonIndex = packet.indexOf(":");
char nextChar = packet[colonIndex + 1];
int greaterThanIndex = packet.indexOf(">");
int telemetryPacketIndex = packet.indexOf(":T#");
String sender = packet.substring(3, greaterThanIndex);
switch (type) {
case 0: // CRC
@@ -58,13 +60,12 @@ namespace SYSLOG_Utils {
if (nextChar == ':') {
syslogPacket.concat("MESSAGE / ");
syslogPacket.concat(sender);
syslogPacket.concat(" ---> ");
syslogPacket.concat(" ---> ");
syslogPacket.concat(packet.substring(colonIndex + 2));
} else if (nextChar == '!' || nextChar == '=' || nextChar == '@') {
syslogPacket.concat("GPS / ");
syslogPacket.concat(sender);
syslogPacket.concat(" / ");
int greaterThanIndex = packet.indexOf(">");
if (packet.indexOf("WIDE1-1") > 10) {
syslogPacket.concat(packet.substring(greaterThanIndex + 1, packet.indexOf(",")));
syslogPacket.concat(" / WIDE1-1");
@@ -87,11 +88,11 @@ namespace SYSLOG_Utils {
syslogPacket.concat(sender);
syslogPacket.concat(" ---> ");
syslogPacket.concat(packet.substring(colonIndex + 2));
} else if (packet.indexOf(":T#") >= 10 && packet.indexOf(":=/") == -1) {
} else if (telemetryPacketIndex >= 10 && packet.indexOf(":=/") == -1) {
syslogPacket.concat("TELEMETRY / ");
syslogPacket.concat(sender);
syslogPacket.concat(" ---> ");
syslogPacket.concat(packet.substring(packet.indexOf(":T#") + 3));
syslogPacket.concat(packet.substring(telemetryPacketIndex + 3));
} else {
syslogPacket.concat(packet);
}

View File

@@ -312,7 +312,6 @@ namespace Utils {
}
void typeOfPacket(const String& packet, const uint8_t packetType) {
String sender = packet.substring(0,packet.indexOf(">"));
switch (packetType) {
case 0: // LoRa-APRS
fifthLine = "LoRa Rx ----> APRS-IS";
@@ -328,6 +327,7 @@ namespace Utils {
int firstColonIndex = packet.indexOf(":");
char nextChar = packet[firstColonIndex + 1];
String sender = packet.substring(0,packet.indexOf(">"));
for (int i = sender.length(); i < 9; i++) {
sender += " ";
}
@@ -419,9 +419,10 @@ namespace Utils {
if (callsign == "WLNK-1") return true;
String cleanCallsign;
if (callsign.indexOf("-") > 0) { // SSID Validation
cleanCallsign = callsign.substring(0, callsign.indexOf("-"));
String ssid = callsign.substring(callsign.indexOf("-") + 1);
int hypenCallsignIndex = callsign.indexOf("-");
if (hypenCallsignIndex > 0) { // SSID Validation
cleanCallsign = callsign.substring(0, hypenCallsignIndex);
String ssid = callsign.substring(hypenCallsignIndex + 1);
if (ssid.indexOf("-") != -1 || ssid.length() > 2) return false;
if (ssid.length() == 2 && ssid[0] == '0') return false;
for (int i = 0; i < ssid.length(); i++) {

View File

@@ -61,9 +61,9 @@ namespace WX_Utils {
void getWxModuleAddres() {
uint8_t err, addr;
for(addr = 1; addr < 0x7F; addr++) {
#if defined(HELTEC_V3) || defined(HELTEC_V3_2) || defined(HELTEC_WSL_V3) || defined(HELTEC_WSL_V3_DISPLAY)
Wire1.beginTransmission(addr);
err = Wire1.endTransmission();
#ifdef SENSOR_I2C_BUS
SENSOR_I2C_BUS.beginTransmission(addr);
err = SENSOR_I2C_BUS.endTransmission();
#else
Wire.beginTransmission(addr);
#ifdef LIGHTGATEWAY_PLUS_1_0

View File

@@ -31,7 +31,7 @@
#define GPIO_WAKEUP_PIN GPIO_SEL_38
// I2C
#define USE_WIRE_WITH_BOARD_I2C_PINS
#define SENSOR_I2C_BUS Wire
#define BOARD_I2C_SDA 11
#define BOARD_I2C_SCL 12

View File

@@ -39,8 +39,8 @@
#define INTERNAL_LED_PIN 48
// I2C
#define USE_WIRE_WITH_OLED_PINS
#define OLED_SDA 5
#define OLED_SCL 6
#define SENSOR_I2C_BUS Wire
#define BOARD_I2C_SDA 5
#define BOARD_I2C_SCL 6
#endif

View File

@@ -48,7 +48,8 @@
// Aditional Config
#define INTERNAL_LED_PIN 25
#define BATTERY_PIN 37
#define ADC_CTRL 21
#define ADC_CTRL_INVERTED 1
#define ADC_CTRL_PIN 21
#define ADC_CTRL_ON_STATE LOW
#endif

View File

@@ -48,7 +48,8 @@
// Aditional Config
#define INTERNAL_LED_PIN 25
#define BATTERY_PIN 37
#define ADC_CTRL 21
#define ADC_CTRL_INVERTED 1
#define ADC_CTRL_ON_STATE LOW
#endif

View File

@@ -33,7 +33,7 @@
#define GPIO_WAKEUP_PIN GPIO_SEL_14
// I2C
#define USE_WIRE1_WITH_BOARD_I2C_PINS
#define SENSOR_I2C_BUS Wire1
#define BOARD_I2C_SDA 39
#define BOARD_I2C_SCL 38
@@ -50,9 +50,10 @@
// Aditional Config
#define INTERNAL_LED_PIN 45
#define BATTERY_PIN 7
#define ADC_CTRL 46
#define ADC_CTRL_INVERTED 0
#define VEXT_CTRL 18
#define VEXT_CTRL_INVERTED 0
#define ADC_CTRL_PIN 46
#define ADC_CTRL_ON_STATE HIGH
#define VEXT_CTRL_PIN 18
#define VEXT_CTRL_ON_STATE HIGH
#endif

View File

@@ -34,7 +34,7 @@
// I2C
#define USE_WIRE_WITH_OLED_PINS
#define USE_WIRE1_WITH_BOARD_I2C_PINS
#define SENSOR_I2C_BUS Wire1
#define BOARD_I2C_SDA 41
#define BOARD_I2C_SCL 42
@@ -53,9 +53,10 @@
// Aditional Config
#define INTERNAL_LED_PIN 35
#define BATTERY_PIN 1
#define VEXT_CTRL 36
#define VEXT_CTRL_INVERTED 0
#define ADC_CTRL 37
#define ADC_CTRL_INVERTED 1
#define ADC_CTRL_PIN 37
#define ADC_CTRL_ON_STATE LOW
#define VEXT_CTRL_PIN 36
#define VEXT_CTRL_ON_STATE HIGH
#endif

View File

@@ -34,7 +34,7 @@
// I2C
#define USE_WIRE_WITH_OLED_PINS
#define USE_WIRE1_WITH_BOARD_I2C_PINS
#define SENSOR_I2C_BUS Wire1
#define BOARD_I2C_SDA 41
#define BOARD_I2C_SCL 42
@@ -53,9 +53,10 @@
// Aditional Config
#define INTERNAL_LED_PIN 35
#define BATTERY_PIN 1
#define VEXT_CTRL 36
#define VEXT_CTRL_INVERTED 1
#define ADC_CTRL 37
#define ADC_CTRL_INVERTED 0
#define ADC_CTRL_PIN 37
#define ADC_CTRL_ON_STATE HIGH
#define VEXT_CTRL_PIN 36
#define VEXT_CTRL_ON_STATE LOW
#endif

View File

@@ -34,7 +34,7 @@
// I2C
#define USE_WIRE_WITH_OLED_PINS
#define USE_WIRE1_WITH_BOARD_I2C_PINS
#define SENSOR_I2C_BUS Wire1
#define BOARD_I2C_SDA 41
#define BOARD_I2C_SCL 42
@@ -53,10 +53,11 @@
// Aditional Config
#define INTERNAL_LED_PIN 35
#define BATTERY_PIN 1
#define VEXT_CTRL 36
#define VEXT_CTRL_INVERTED 1
#define ADC_CTRL 37
#define ADC_CTRL_INVERTED 0
#define ADC_CTRL_PIN 37
#define ADC_CTRL_ON_STATE HIGH
#define VEXT_CTRL_PIN 36
#define VEXT_CTRL_ON_STATE LOW
// GPS ??
#define VGNS_CTRL 34 // cambiar nombre para prender GPS ?

View File

@@ -33,7 +33,7 @@
#define GPIO_WAKEUP_PIN GPIO_SEL_14
// I2C
#define USE_WIRE1_WITH_BOARD_I2C_PINS
#define SENSOR_I2C_BUS Wire1
#define BOARD_I2C_SDA 37
#define BOARD_I2C_SCL 36
@@ -50,9 +50,10 @@
// Aditional Config
#define INTERNAL_LED_PIN 18
#define BATTERY_PIN 20
#define ADC_CTRL 19
#define ADC_CTRL_INVERTED 1
#define VEXT_CTRL 45
#define VEXT_CTRL_INVERTED 1
#define ADC_CTRL_PIN 19
#define ADC_CTRL_ON_STATE LOW
#define VEXT_CTRL_PIN 45
#define VEXT_CTRL_ON_STATE LOW
#endif

View File

@@ -33,7 +33,7 @@
#define GPIO_WAKEUP_PIN GPIO_SEL_14
// I2C
#define USE_WIRE1_WITH_BOARD_I2C_PINS
#define SENSOR_I2C_BUS Wire1
#define BOARD_I2C_SDA 37
#define BOARD_I2C_SCL 36
@@ -50,9 +50,10 @@
// Aditional Config
#define INTERNAL_LED_PIN 18
#define BATTERY_PIN 20
#define ADC_CTRL 19
#define ADC_CTRL_INVERTED 1
#define VEXT_CTRL 45
#define VEXT_CTRL_INVERTED 1
#define ADC_CTRL_PIN 19
#define ADC_CTRL_ON_STATE LOW
#define VEXT_CTRL_PIN 45
#define VEXT_CTRL_ON_STATE LOW
#endif

View File

@@ -50,9 +50,11 @@
// Aditional Config
#define INTERNAL_LED_PIN 35
#define BATTERY_PIN 1
#define ADC_CTRL 37
#define VEXT_CTRL 36
#define VEXT_CTRL_INVERTED 1
#define ADC_CTRL_PIN 37
#define ADC_CTRL_ON_STATE LOW
#define VEXT_CTRL_PIN 36
#define VEXT_CTRL_ON_STATE LOW
#define BOARD_I2C_SDA 41
#define BOARD_I2C_SCL 42

View File

@@ -33,16 +33,17 @@
#define GPIO_WAKEUP_PIN GPIO_SEL_14
// I2C
#define USE_WIRE1_WITH_BOARD_I2C_PINS
#define SENSOR_I2C_BUS Wire1
#define BOARD_I2C_SDA 41
#define BOARD_I2C_SCL 42
// Aditional Config
#define INTERNAL_LED_PIN 35
#define BATTERY_PIN 1
#define ADC_CTRL 37
#define ADC_CTRL_INVERTED 1
#define VEXT_CTRL 36
#define VEXT_CTRL_INVERTED 1
#define ADC_CTRL_PIN 37
#define ADC_CTRL_ON_STATE LOW
#define VEXT_CTRL_PIN 36
#define VEXT_CTRL_ON_STATE LOW
#endif

View File

@@ -33,7 +33,7 @@
#define GPIO_WAKEUP_PIN GPIO_SEL_14
// I2C
#define USE_WIRE1_WITH_BOARD_I2C_PINS
#define SENSOR_I2C_BUS Wire1
#define BOARD_I2C_SDA 41
#define BOARD_I2C_SCL 42
@@ -44,9 +44,10 @@
// Aditional Config
#define INTERNAL_LED_PIN 35
#define BATTERY_PIN 1
#define ADC_CTRL 37
#define ADC_CTRL_INVERTED 1
#define VEXT_CTRL 36
#define VEXT_CTRL_INVERTED 1
#define ADC_CTRL_PIN 37
#define ADC_CTRL_ON_STATE LOW
#define VEXT_CTRL_PIN 36
#define VEXT_CTRL_ON_STATE LOW
#endif

View File

@@ -33,7 +33,7 @@
#define GPIO_WAKEUP_PIN GPIO_SEL_14
// I2C
#define USE_WIRE_WITH_BOARD_I2C_PINS
#define SENSOR_I2C_BUS Wire
#define BOARD_I2C_SDA 7
#define BOARD_I2C_SCL 6
@@ -44,10 +44,11 @@
// Aditional Config
#define INTERNAL_LED_PIN 18
#define BATTERY_PIN 1
#define VEXT_CTRL 3 // To turn on GPS and TFT
#define VEXT_CTRL_INVERTED 0
#define ADC_CTRL 2 // HELTEC Wireless Tracker ADC_CTRL = HIGH powers the voltage divider to read BatteryPin. Only on V05 = V1.1
#define ADC_CTRL_INVERTED 0
#define ADC_CTRL_PIN 2 // HELTEC Wireless Tracker ADC_CTRL = HIGH powers the voltage divider to read BatteryPin. Only on V05 = V1.1
#define ADC_CTRL_ON_STATE HIGH
#define VEXT_CTRL_PIN 3 // To turn on GPS and TFT
#define VEXT_CTRL_ON_STATE HIGH
// GPS
#define HAS_GPS

View File

@@ -33,7 +33,7 @@
#define GPIO_WAKEUP_PIN GPIO_SEL_45
// I2C
#define USE_WIRE_WITH_BOARD_I2C_PINS
#define SENSOR_I2C_BUS Wire
#define BOARD_I2C_SDA 18
#define BOARD_I2C_SCL 8

View File

@@ -33,7 +33,7 @@
#define GPIO_WAKEUP_PIN GPIO_SEL_45
// I2C
#define USE_WIRE_WITH_BOARD_I2C_PINS
#define SENSOR_I2C_BUS Wire
#define BOARD_I2C_SDA 18
#define BOARD_I2C_SCL 8