From 2736551c76c0e76cbd68b4b7ac65638326b5cc8a Mon Sep 17 00:00:00 2001 From: richonguzman Date: Wed, 25 Jan 2023 00:42:51 -0300 Subject: [PATCH] first upload of beta version --- .gitignore | 5 + .vscode/extensions.json | 10 ++ include/README | 39 +++++++ lib/README | 46 ++++++++ platformio.ini | 20 ++++ src/.DS_Store | Bin 0 -> 6148 bytes src/Lora_1W_APRS_Tracker.cpp | 218 +++++++++++++++++++++++++++++++++++ src/beacon_config.h | 15 +++ src/lora_config.h | 13 +++ src/pins.h | 41 +++++++ src/user_config.h | 9 ++ test/README | 11 ++ 12 files changed, 427 insertions(+) create mode 100644 .gitignore create mode 100644 .vscode/extensions.json create mode 100644 include/README create mode 100644 lib/README create mode 100644 platformio.ini create mode 100644 src/.DS_Store create mode 100644 src/Lora_1W_APRS_Tracker.cpp create mode 100644 src/beacon_config.h create mode 100644 src/lora_config.h create mode 100644 src/pins.h create mode 100644 src/user_config.h create mode 100644 test/README diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..89cc49c --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +.pio +.vscode/.browse.c_cpp.db* +.vscode/c_cpp_properties.json +.vscode/launch.json +.vscode/ipch diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 0000000..080e70d --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,10 @@ +{ + // See http://go.microsoft.com/fwlink/?LinkId=827846 + // for the documentation about the extensions.json format + "recommendations": [ + "platformio.platformio-ide" + ], + "unwantedRecommendations": [ + "ms-vscode.cpptools-extension-pack" + ] +} diff --git a/include/README b/include/README new file mode 100644 index 0000000..194dcd4 --- /dev/null +++ b/include/README @@ -0,0 +1,39 @@ + +This directory is intended for project header files. + +A header file is a file containing C declarations and macro definitions +to be shared between several project source files. You request the use of a +header file in your project source file (C, C++, etc) located in `src` folder +by including it, with the C preprocessing directive `#include'. + +```src/main.c + +#include "header.h" + +int main (void) +{ + ... +} +``` + +Including a header file produces the same results as copying the header file +into each source file that needs it. Such copying would be time-consuming +and error-prone. With a header file, the related declarations appear +in only one place. If they need to be changed, they can be changed in one +place, and programs that include the header file will automatically use the +new version when next recompiled. The header file eliminates the labor of +finding and changing all the copies as well as the risk that a failure to +find one copy will result in inconsistencies within a program. + +In C, the usual convention is to give header files names that end with `.h'. +It is most portable to use only letters, digits, dashes, and underscores in +header file names, and at most one dot. + +Read more about using header files in official GCC documentation: + +* Include Syntax +* Include Operation +* Once-Only Headers +* Computed Includes + +https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html diff --git a/lib/README b/lib/README new file mode 100644 index 0000000..6debab1 --- /dev/null +++ b/lib/README @@ -0,0 +1,46 @@ + +This directory is intended for project specific (private) libraries. +PlatformIO will compile them to static libraries and link into executable file. + +The source code of each library should be placed in a an own separate directory +("lib/your_library_name/[here are source files]"). + +For example, see a structure of the following two libraries `Foo` and `Bar`: + +|--lib +| | +| |--Bar +| | |--docs +| | |--examples +| | |--src +| | |- Bar.c +| | |- Bar.h +| | |- library.json (optional, custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html +| | +| |--Foo +| | |- Foo.c +| | |- Foo.h +| | +| |- README --> THIS FILE +| +|- platformio.ini +|--src + |- main.c + +and a contents of `src/main.c`: +``` +#include +#include + +int main (void) +{ + ... +} + +``` + +PlatformIO Library Dependency Finder will find automatically dependent +libraries scanning project source files. + +More information about PlatformIO Library Dependency Finder +- https://docs.platformio.org/page/librarymanager/ldf.html diff --git a/platformio.ini b/platformio.ini new file mode 100644 index 0000000..8501153 --- /dev/null +++ b/platformio.ini @@ -0,0 +1,20 @@ +; PlatformIO Project Configuration File +; +; Build options: build flags, source filter +; Upload options: custom upload port, speed and extra flags +; Library options: dependencies, extra library storages +; Advanced options: extra scripting +; +; Please visit documentation for the other options and examples +; https://docs.platformio.org/page/projectconf.html + +[env:esp32dev] +platform = espressif32 +board = esp32dev +framework = arduino +lib_deps = + mikalhart/TinyGPSPlus@^1.0.3 + jgromes/RadioLib@^5.5.0 + paulstoffregen/Time@^1.6.1 + mathertel/OneButton@^2.0.3 +monitor_speed = 115200 diff --git a/src/.DS_Store b/src/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..67154f3411252c57a066105ef8782a91979d4e71 GIT binary patch literal 6148 zcmeHKO-}+b5Pd}sYrJsexWB*+|6nEPi5Me(91(#Sg34yuJ?LqFx^JcvlzU zYKB{mC5Ko`ESPCRoYDV@{_l*K;8i0ea>=L_*UG-^O@3ATc9qe;WWMZ&XSuYqB)W$M zcVXu|#0&F1IRnmsGw=%xux5)SClS4M2AlzBV8eiXA5yAdZrDWBPX`-)0ub9YtFSL` z35iJ!bHgSgXDA_t5@TqvCq{_jw5R5m8#WPRID)RsJhpPM7fR68X;0N1A&=;-GvEwt zGjJ4#9jX84-@pI2gM8!+I0OHRfzTd|27MmMYU|G7q}Ha?2daqpH4!%<>}V;buax30 aRfYCcI>g+tiAW2@{|G1z-Z%q)%D@L_pF%1C literal 0 HcmV?d00001 diff --git a/src/Lora_1W_APRS_Tracker.cpp b/src/Lora_1W_APRS_Tracker.cpp new file mode 100644 index 0000000..06d6db1 --- /dev/null +++ b/src/Lora_1W_APRS_Tracker.cpp @@ -0,0 +1,218 @@ +/* +LORA (1 Watt Module) APRS Tracker +https://github.com/richonguzman/LoRa_1W_APRS_Tracker +written by Ricardo Guzman ( CD2RXU-7 ) +based on lots of other Lora APRS Tracker ideas like: +https://github.com/lora-aprs/LoRa_APRS_Tracker +https://github.com/aprs434/lora.tracker +https://github.com/Mane76/lora.tracker +https://github.com/sh123/esp32_loraprs +*/ + +#include +#include +#include +#include +#include +#include "user_config.h" +#include "pins.h" +#include "lora_config.h" +#include "beacon_config.h" + +#define VERSION "2023.01.24" // BETA!!! + +SX1268 radio = new Module(NSS, DIO1, NRST, BUSY); +HardwareSerial neo6m_gps(1); +TinyGPSPlus gps; +OneButton UserButton1 = OneButton(BUTTON1_PIN, true, true); + +static bool send_update = true; + +void setup_lora_module() { + int state = radio.begin(LoraFreqTx, LoraBandWidth, LoraSpreadingFactor, LoraCodingRate, LoraSyncWord, LoraOutro, LoraPreampbleLenght); + radio.setOutputPower(Lora_Power); + radio.setRfSwitchPins(RXEN, TXEN); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("LORA (1 Watt) MODULE Ready (Radiolib success!)")); + } else { + Serial.println(F("Lora Module Setup failed, code ")); + Serial.println(state); + } +} + +void setup_gps_module() { + neo6m_gps.begin(9600, SERIAL_8N1, GPS_TXD, GPS_RXD); +} + +static void ForcedBeaconTx() { + Serial.println("Forced Beacon Tx"); + send_update = true; +} + +void setup() { + Serial.begin(115200); + Serial.println(F("LoRa tracker " __DATE__ " " __TIME__ " / Callsign ------> " SRC_CALLSIGN)); + pinMode(LED_BUILTIN, OUTPUT); + digitalWrite(LED_BUILTIN, LOW); + setup_lora_module(); + setup_gps_module(); + UserButton1.attachClick(ForcedBeaconTx); + WiFi.mode(WIFI_OFF); + btStop(); + Serial.print("Version = "); + Serial.println(VERSION); + Serial.println("Transmission Start ---->"); +} + +uint8_t tx_buffer[256]; +uint32_t lastTxTime = 0; + +char *ax25_base91enc(char *s, uint8_t n, uint32_t v) { + /* Creates a Base-91 representation of the value in v in the string */ + /* pointed to by s, n-characters long. String length should be n+1. */ + for(s += n, *s = '\0'; n; n--) { + *(--s) = v % 91 + 33; + v /= 91; + } + return(s); +} + +void loop() { + UserButton1.tick(); + + while (neo6m_gps.available() > 0) { + gps.encode(neo6m_gps.read()); + } + bool gps_loc_update = gps.location.isUpdated(); + bool gps_time_update = gps.time.isUpdated(); + //static time_t nextBeaconTimeStamp = -1; + static double currentHeading = 0; + static double previousHeading = 0; + //static unsigned int rate_limit_message_text = 0; + + static double lastTxLatitude = 0.0; + static double lastTxLongitude = 0.0; + static double lastTxDistance = 0.0; + static uint32_t txInterval = 60000L; + //static int speed_zero_sent = 0; + + if (!send_update && gps_loc_update) { + uint32_t lastTx = millis() - lastTxTime; + currentHeading = gps.course.deg(); + lastTxDistance = TinyGPSPlus::distanceBetween(gps.location.lat(), gps.location.lng(), lastTxLatitude, lastTxLongitude); + if (lastTx >= txInterval) { + if (lastTxDistance > MinimumDistanceTx) { + send_update = true; + } + } + if (!send_update) { + double headingDelta = abs(previousHeading - currentHeading); + if (lastTx > MinimumTimeDeltaBeacon * 1000) { + if (headingDelta > TurnDegrees && lastTxDistance > MinimumDistanceTx) { + send_update = true; + } + } + } + } + + if (send_update && gps_loc_update) { + float Tlat, Tlon; + float Tspeed=0, Tcourse=0; + Tlat = gps.location.lat(); + Tlon = gps.location.lng(); + Tcourse = gps.course.deg(); + Tspeed = gps.speed.knots(); + + uint32_t aprs_lat, aprs_lon; + aprs_lat = 900000000 - Tlat * 10000000; + aprs_lat = aprs_lat / 26 - aprs_lat / 2710 + aprs_lat / 15384615; + aprs_lon = 900000000 + Tlon * 10000000 / 2; + aprs_lon = aprs_lon / 26 - aprs_lon / 2710 + aprs_lon / 15384615; + + String Ns, Ew, helper; + if(Tlat < 0) { Ns = "S"; } else { Ns = "N"; } + if(Tlat < 0) { Tlat= -Tlat; } + + if(Tlon < 0) { Ew = "W"; } else { Ew = "E"; } + if(Tlon < 0) { Tlon= -Tlon; } + + String AprsPacketMsg = "!"; + AprsPacketMsg += "/"; + char helper_base91[] = {"0000\0"}; + int i; + ax25_base91enc(helper_base91, 4, aprs_lat); + for (i=0; i<4; i++) { + AprsPacketMsg += helper_base91[i]; + } + ax25_base91enc(helper_base91, 4, aprs_lon); + for (i=0; i<4; i++) { + AprsPacketMsg += helper_base91[i]; + } + + AprsPacketMsg += SYMBOL; + + if (SendAltitude) { // Send Altitude or... (APRS calculates Speed also) + int Alt1, Alt2; + int Talt; + Talt = gps.altitude.feet(); + if(Talt>0){ + double ALT=log(Talt)/log(1.002); + Alt1= int(ALT/91); + Alt2=(int)ALT%91; + }else{ + Alt1=0; + Alt2=0; + } + AprsPacketMsg +=char(Alt1+33); + AprsPacketMsg +=char(Alt2+33); + AprsPacketMsg +=char(0x30+33); + } else { // ... just send Course and Speed + ax25_base91enc(helper_base91, 1, (uint32_t) Tcourse/4 ); + AprsPacketMsg += helper_base91[0]; + ax25_base91enc(helper_base91, 1, (uint32_t) (log1p(Tspeed)/0.07696)); + AprsPacketMsg += helper_base91[0]; + AprsPacketMsg += "\x47"; + } + + if (SendComment) { + AprsPacketMsg += APRS_COMMENT; + } + + Serial.print(F("GPS coordinates: ")); // Only for Serial Monitor + Serial.print(Tlat, 6); + Serial.print(F(", ")); + Serial.println(Tlon, 6); + + memset(tx_buffer, 0x00, sizeof tx_buffer); + uint16_t size = 0; + + size = snprintf(reinterpret_cast(tx_buffer), sizeof tx_buffer, "\x3c\xff\x01%s>%s:%s", SRC_CALLSIGN, DST_CALLSIGN, AprsPacketMsg.c_str()); + + Serial.print(millis()); // Only for Serial Monitor + Serial.print(F(" transmitting: ")); + Serial.println(reinterpret_cast(tx_buffer)); + + digitalWrite(LED_BUILTIN, HIGH); + radio.transmit(tx_buffer, size); + radio.finishTransmit(); + digitalWrite(LED_BUILTIN, LOW); + + lastTxLatitude = gps.location.lat(); + lastTxLongitude = gps.location.lng(); + previousHeading = currentHeading; + lastTxDistance = 0.0; + lastTxTime = millis(); + send_update = false; + } + + if (gps_time_update) { // updating txInterval between Slow and FastRate or in between + int curr_speed = (int)gps.speed.kmph(); + if (curr_speed < SlowSpeed) { + txInterval = SlowRate * 1000; + } else if (curr_speed > FastSpeed) { + txInterval = FastRate * 1000; + } else { + txInterval = min(SlowRate, (FastSpeed * FastRate / curr_speed)) * 1000; + } + } +} \ No newline at end of file diff --git a/src/beacon_config.h b/src/beacon_config.h new file mode 100644 index 0000000..7263aa7 --- /dev/null +++ b/src/beacon_config.h @@ -0,0 +1,15 @@ +#ifndef BEACON_CONFIG_H_ +#define BEACON_CONFIG_H_ + +#define SlowRate 120 // Seg +#define SlowSpeed 10 // Km/h (3 Runner , 5 Bike, 10 Car) +#define FastRate 60 // Seg +#define FastSpeed 20 // Km/h (20 Runner y Bike, 70 Car) +#define TurnDegrees 20 // Degrees before Forced Beacon Tx (20 Car , 15 Bike/Runner) +#define MinimumDistanceTx 30 // Mts (20 Runner, 100 Car/Bike) +#define MinimumTimeDeltaBeacon 5 // Seg between Tx + +#define SendAltitude true // "true" adds Altitude to the APRS packet/message, "false" add Course+Speed +#define SendComment false // "true" adds comment to the APRS packet/message + +#endif \ No newline at end of file diff --git a/src/lora_config.h b/src/lora_config.h new file mode 100644 index 0000000..5ccf404 --- /dev/null +++ b/src/lora_config.h @@ -0,0 +1,13 @@ +#ifndef LORA_CONFIG_H_ +#define LORA_CONFIG_H_ + +#define LoraFreqTx 433.775 +#define LoraBandWidth 125.0 +#define LoraSpreadingFactor 12 +#define LoraCodingRate 5 +#define LoraSyncWord 0x12 +#define LoraOutro 5 +#define LoraPreampbleLenght 8 +#define Lora_Power 20 // Tx Power, 8=100mW, 20=1000mW + +#endif \ No newline at end of file diff --git a/src/pins.h b/src/pins.h new file mode 100644 index 0000000..34011db --- /dev/null +++ b/src/pins.h @@ -0,0 +1,41 @@ +#ifndef PINS_H_ +#define PINS_H_ + +#define GPS_TXD 16 // Conection Pinout for GPS +#define GPS_RXD 17 +/* +GPS NEO-6M v.2----> ESP32 +VCC 3.3V +GND GND +TXD 16 +RXD 17 +*/ + +#define NSS 5 // Conection Pinout Ebyte E22 400M30S LoRa Module +#define DIO1 12 +#define NRST 27 +#define BUSY 14 +#define RXEN 32 +#define TXEN 25 +/* +400M30S-------------------> ESP32 +1-2-3-4-5-11-12-20-22 GND +6 RXEN 32 +7 TXEN 25 +8 X (not connected) - +9-10 5V add 100uf (electro) + 100nF (polyester) from 5V to ground near pin 9-10 +13 DIO1 12 +14 BUSY 14 +15 NRST 27 +16 MISO 19 +17 MOSI 23 +18 SCK 18 +19 NSS 5 +21 ANTENA +*/ + +#define LED_BUILTIN 2 // Blue Led ESP32 Pin + +#define BUTTON1_PIN 15 // Forced Beacon Tx (Switch pin1 to pin 15 , Swith pin2 to 220 ohms resistor to GND) + +#endif \ No newline at end of file diff --git a/src/user_config.h b/src/user_config.h new file mode 100644 index 0000000..ac58bee --- /dev/null +++ b/src/user_config.h @@ -0,0 +1,9 @@ +#ifndef USER_CONFIG_H_ +#define USER_CONFIG_H_ + +#define SRC_CALLSIGN "CD2RXU-7" // Change "NOCALL-10 to your APRS Callsign +#define DST_CALLSIGN "AP" // APRS Destination (could be also "WIDE1-1") +#define SYMBOL "[" // APRS Symbol: "[" Runner, "b" Bike, ">" Auto/Car +#define APRS_COMMENT "Lora Tracker 1W" // if you want to send any comment change the APRS_COMMENT + // and also beacon_config.h > SendComment = true +#endif \ No newline at end of file diff --git a/test/README b/test/README new file mode 100644 index 0000000..9b1e87b --- /dev/null +++ b/test/README @@ -0,0 +1,11 @@ + +This directory is intended for PlatformIO Test Runner and project tests. + +Unit Testing is a software testing method by which individual units of +source code, sets of one or more MCU program modules together with associated +control data, usage procedures, and operating procedures, are tested to +determine whether they are fit for use. Unit testing finds problems early +in the development cycle. + +More information about PlatformIO Unit Testing: +- https://docs.platformio.org/en/latest/advanced/unit-testing/index.html