mirror of
https://github.com/richonguzman/LoRa_APRS_iGate.git
synced 2026-07-15 14:21:30 +02:00
Compare commits
9 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f7c9201830 | |||
| 1a042b7d0e | |||
| aaa44200b5 | |||
| c17ad32650 | |||
| 26b5df1bd7 | |||
| 0c3555bdbe | |||
| cf858ffad2 | |||
| cbac8b0365 | |||
| b76aed4d57 |
@@ -51,6 +51,7 @@ ____________________________________________________
|
||||
<br />
|
||||
|
||||
# Timeline (Versions):
|
||||
- 2026-06-29 New UI (Web) and also Live View over a Map to see Rx stations.
|
||||
- 2026-06-10 CAD (Channel Activity Detection) and DIFS (Distributed Inter-Frame Space) added.
|
||||
- 2026-03-25 More Boards, SDK update, OTA fix, GPS process update.
|
||||
- 2026-02-26 9M2IBR ESP32 1W (400M30S) + GPS board added.
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<title>LoRa iGate & Digi software − Ricardo Guzman CA2RXU</title>
|
||||
<link rel="stylesheet" href="/bootstrap.css" />
|
||||
<link rel="stylesheet" href="/style.css" />
|
||||
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" integrity="sha256-p4NxAoJBhIIN+hmNHrzRCf9tD/miZyoHS5obTRR9BMY=" crossorigin="" />
|
||||
<link rel="stylesheet" href="/leaflet.css" />
|
||||
<link rel="icon" href="/favicon.png" type="image/x-icon">
|
||||
<script>(function(){try{var t=localStorage.getItem("igateTheme");if(!t)t=window.matchMedia&&window.matchMedia("(prefers-color-scheme: light)").matches?"light":"dark";var r=document.documentElement;if(t==="night"){r.setAttribute("data-bs-theme","dark");r.setAttribute("data-variant","night");}else{r.setAttribute("data-bs-theme",t);}}catch(e){}})();</script>
|
||||
<style>
|
||||
@@ -1007,10 +1007,14 @@ body{background:var(--msh-bg);color:var(--msh-text);font-family:"Inter",system-u
|
||||
id="digi.mode"
|
||||
>
|
||||
<option value="0" selected>OFF</option>
|
||||
<option value="2">WIDE1 (fill-in) Digi</option>
|
||||
<option value="3">WIDE2 (+WIDE1) Digi</option>
|
||||
<option value="1">WIDE1 (fill-in) Digi</option>
|
||||
<option value="2">WIDE2 (+WIDE1) Digi</option>
|
||||
<option value="3">Own Callsign Path Digi</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-12 mt-2">
|
||||
+ <small class="text-muted">Mode 4 digipeats packets whose path already contains your callsign, preserving the path and appending a * to your callsign.</small>
|
||||
+ </div>
|
||||
<div class="col-12 mt-3">
|
||||
<label
|
||||
for="digi.ecoMode"
|
||||
@@ -2382,7 +2386,7 @@ body{background:var(--msh-bg);color:var(--msh-text);font-family:"Inter",system-u
|
||||
</div>
|
||||
</body>
|
||||
<script src="/bootstrap.js"></script>
|
||||
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js" integrity="sha256-20nQCchB9co0qIjJZRGuk2/Z9VM+kNiyxNV1lvTlZBo=" crossorigin=""></script>
|
||||
<script src="/leaflet.js"></script>
|
||||
<script src="/script.js"></script>
|
||||
</html>
|
||||
<script>
|
||||
|
||||
@@ -0,0 +1,661 @@
|
||||
/* required styles */
|
||||
|
||||
.leaflet-pane,
|
||||
.leaflet-tile,
|
||||
.leaflet-marker-icon,
|
||||
.leaflet-marker-shadow,
|
||||
.leaflet-tile-container,
|
||||
.leaflet-pane > svg,
|
||||
.leaflet-pane > canvas,
|
||||
.leaflet-zoom-box,
|
||||
.leaflet-image-layer,
|
||||
.leaflet-layer {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
}
|
||||
.leaflet-container {
|
||||
overflow: hidden;
|
||||
}
|
||||
.leaflet-tile,
|
||||
.leaflet-marker-icon,
|
||||
.leaflet-marker-shadow {
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
user-select: none;
|
||||
-webkit-user-drag: none;
|
||||
}
|
||||
/* Prevents IE11 from highlighting tiles in blue */
|
||||
.leaflet-tile::selection {
|
||||
background: transparent;
|
||||
}
|
||||
/* Safari renders non-retina tile on retina better with this, but Chrome is worse */
|
||||
.leaflet-safari .leaflet-tile {
|
||||
image-rendering: -webkit-optimize-contrast;
|
||||
}
|
||||
/* hack that prevents hw layers "stretching" when loading new tiles */
|
||||
.leaflet-safari .leaflet-tile-container {
|
||||
width: 1600px;
|
||||
height: 1600px;
|
||||
-webkit-transform-origin: 0 0;
|
||||
}
|
||||
.leaflet-marker-icon,
|
||||
.leaflet-marker-shadow {
|
||||
display: block;
|
||||
}
|
||||
/* .leaflet-container svg: reset svg max-width decleration shipped in Joomla! (joomla.org) 3.x */
|
||||
/* .leaflet-container img: map is broken in FF if you have max-width: 100% on tiles */
|
||||
.leaflet-container .leaflet-overlay-pane svg {
|
||||
max-width: none !important;
|
||||
max-height: none !important;
|
||||
}
|
||||
.leaflet-container .leaflet-marker-pane img,
|
||||
.leaflet-container .leaflet-shadow-pane img,
|
||||
.leaflet-container .leaflet-tile-pane img,
|
||||
.leaflet-container img.leaflet-image-layer,
|
||||
.leaflet-container .leaflet-tile {
|
||||
max-width: none !important;
|
||||
max-height: none !important;
|
||||
width: auto;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.leaflet-container img.leaflet-tile {
|
||||
/* See: https://bugs.chromium.org/p/chromium/issues/detail?id=600120 */
|
||||
mix-blend-mode: plus-lighter;
|
||||
}
|
||||
|
||||
.leaflet-container.leaflet-touch-zoom {
|
||||
-ms-touch-action: pan-x pan-y;
|
||||
touch-action: pan-x pan-y;
|
||||
}
|
||||
.leaflet-container.leaflet-touch-drag {
|
||||
-ms-touch-action: pinch-zoom;
|
||||
/* Fallback for FF which doesn't support pinch-zoom */
|
||||
touch-action: none;
|
||||
touch-action: pinch-zoom;
|
||||
}
|
||||
.leaflet-container.leaflet-touch-drag.leaflet-touch-zoom {
|
||||
-ms-touch-action: none;
|
||||
touch-action: none;
|
||||
}
|
||||
.leaflet-container {
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
}
|
||||
.leaflet-container a {
|
||||
-webkit-tap-highlight-color: rgba(51, 181, 229, 0.4);
|
||||
}
|
||||
.leaflet-tile {
|
||||
filter: inherit;
|
||||
visibility: hidden;
|
||||
}
|
||||
.leaflet-tile-loaded {
|
||||
visibility: inherit;
|
||||
}
|
||||
.leaflet-zoom-box {
|
||||
width: 0;
|
||||
height: 0;
|
||||
-moz-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
z-index: 800;
|
||||
}
|
||||
/* workaround for https://bugzilla.mozilla.org/show_bug.cgi?id=888319 */
|
||||
.leaflet-overlay-pane svg {
|
||||
-moz-user-select: none;
|
||||
}
|
||||
|
||||
.leaflet-pane { z-index: 400; }
|
||||
|
||||
.leaflet-tile-pane { z-index: 200; }
|
||||
.leaflet-overlay-pane { z-index: 400; }
|
||||
.leaflet-shadow-pane { z-index: 500; }
|
||||
.leaflet-marker-pane { z-index: 600; }
|
||||
.leaflet-tooltip-pane { z-index: 650; }
|
||||
.leaflet-popup-pane { z-index: 700; }
|
||||
|
||||
.leaflet-map-pane canvas { z-index: 100; }
|
||||
.leaflet-map-pane svg { z-index: 200; }
|
||||
|
||||
.leaflet-vml-shape {
|
||||
width: 1px;
|
||||
height: 1px;
|
||||
}
|
||||
.lvml {
|
||||
behavior: url(#default#VML);
|
||||
display: inline-block;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
|
||||
/* control positioning */
|
||||
|
||||
.leaflet-control {
|
||||
position: relative;
|
||||
z-index: 800;
|
||||
pointer-events: visiblePainted; /* IE 9-10 doesn't have auto */
|
||||
pointer-events: auto;
|
||||
}
|
||||
.leaflet-top,
|
||||
.leaflet-bottom {
|
||||
position: absolute;
|
||||
z-index: 1000;
|
||||
pointer-events: none;
|
||||
}
|
||||
.leaflet-top {
|
||||
top: 0;
|
||||
}
|
||||
.leaflet-right {
|
||||
right: 0;
|
||||
}
|
||||
.leaflet-bottom {
|
||||
bottom: 0;
|
||||
}
|
||||
.leaflet-left {
|
||||
left: 0;
|
||||
}
|
||||
.leaflet-control {
|
||||
float: left;
|
||||
clear: both;
|
||||
}
|
||||
.leaflet-right .leaflet-control {
|
||||
float: right;
|
||||
}
|
||||
.leaflet-top .leaflet-control {
|
||||
margin-top: 10px;
|
||||
}
|
||||
.leaflet-bottom .leaflet-control {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.leaflet-left .leaflet-control {
|
||||
margin-left: 10px;
|
||||
}
|
||||
.leaflet-right .leaflet-control {
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
|
||||
/* zoom and fade animations */
|
||||
|
||||
.leaflet-fade-anim .leaflet-popup {
|
||||
opacity: 0;
|
||||
-webkit-transition: opacity 0.2s linear;
|
||||
-moz-transition: opacity 0.2s linear;
|
||||
transition: opacity 0.2s linear;
|
||||
}
|
||||
.leaflet-fade-anim .leaflet-map-pane .leaflet-popup {
|
||||
opacity: 1;
|
||||
}
|
||||
.leaflet-zoom-animated {
|
||||
-webkit-transform-origin: 0 0;
|
||||
-ms-transform-origin: 0 0;
|
||||
transform-origin: 0 0;
|
||||
}
|
||||
svg.leaflet-zoom-animated {
|
||||
will-change: transform;
|
||||
}
|
||||
|
||||
.leaflet-zoom-anim .leaflet-zoom-animated {
|
||||
-webkit-transition: -webkit-transform 0.25s cubic-bezier(0,0,0.25,1);
|
||||
-moz-transition: -moz-transform 0.25s cubic-bezier(0,0,0.25,1);
|
||||
transition: transform 0.25s cubic-bezier(0,0,0.25,1);
|
||||
}
|
||||
.leaflet-zoom-anim .leaflet-tile,
|
||||
.leaflet-pan-anim .leaflet-tile {
|
||||
-webkit-transition: none;
|
||||
-moz-transition: none;
|
||||
transition: none;
|
||||
}
|
||||
|
||||
.leaflet-zoom-anim .leaflet-zoom-hide {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
|
||||
/* cursors */
|
||||
|
||||
.leaflet-interactive {
|
||||
cursor: pointer;
|
||||
}
|
||||
.leaflet-grab {
|
||||
cursor: -webkit-grab;
|
||||
cursor: -moz-grab;
|
||||
cursor: grab;
|
||||
}
|
||||
.leaflet-crosshair,
|
||||
.leaflet-crosshair .leaflet-interactive {
|
||||
cursor: crosshair;
|
||||
}
|
||||
.leaflet-popup-pane,
|
||||
.leaflet-control {
|
||||
cursor: auto;
|
||||
}
|
||||
.leaflet-dragging .leaflet-grab,
|
||||
.leaflet-dragging .leaflet-grab .leaflet-interactive,
|
||||
.leaflet-dragging .leaflet-marker-draggable {
|
||||
cursor: move;
|
||||
cursor: -webkit-grabbing;
|
||||
cursor: -moz-grabbing;
|
||||
cursor: grabbing;
|
||||
}
|
||||
|
||||
/* marker & overlays interactivity */
|
||||
.leaflet-marker-icon,
|
||||
.leaflet-marker-shadow,
|
||||
.leaflet-image-layer,
|
||||
.leaflet-pane > svg path,
|
||||
.leaflet-tile-container {
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.leaflet-marker-icon.leaflet-interactive,
|
||||
.leaflet-image-layer.leaflet-interactive,
|
||||
.leaflet-pane > svg path.leaflet-interactive,
|
||||
svg.leaflet-image-layer.leaflet-interactive path {
|
||||
pointer-events: visiblePainted; /* IE 9-10 doesn't have auto */
|
||||
pointer-events: auto;
|
||||
}
|
||||
|
||||
/* visual tweaks */
|
||||
|
||||
.leaflet-container {
|
||||
background: #ddd;
|
||||
outline-offset: 1px;
|
||||
}
|
||||
.leaflet-container a {
|
||||
color: #0078A8;
|
||||
}
|
||||
.leaflet-zoom-box {
|
||||
border: 2px dotted #38f;
|
||||
background: rgba(255,255,255,0.5);
|
||||
}
|
||||
|
||||
|
||||
/* general typography */
|
||||
.leaflet-container {
|
||||
font-family: "Helvetica Neue", Arial, Helvetica, sans-serif;
|
||||
font-size: 12px;
|
||||
font-size: 0.75rem;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
|
||||
/* general toolbar styles */
|
||||
|
||||
.leaflet-bar {
|
||||
box-shadow: 0 1px 5px rgba(0,0,0,0.65);
|
||||
border-radius: 4px;
|
||||
}
|
||||
.leaflet-bar a {
|
||||
background-color: #fff;
|
||||
border-bottom: 1px solid #ccc;
|
||||
width: 26px;
|
||||
height: 26px;
|
||||
line-height: 26px;
|
||||
display: block;
|
||||
text-align: center;
|
||||
text-decoration: none;
|
||||
color: black;
|
||||
}
|
||||
.leaflet-bar a,
|
||||
.leaflet-control-layers-toggle {
|
||||
background-position: 50% 50%;
|
||||
background-repeat: no-repeat;
|
||||
display: block;
|
||||
}
|
||||
.leaflet-bar a:hover,
|
||||
.leaflet-bar a:focus {
|
||||
background-color: #f4f4f4;
|
||||
}
|
||||
.leaflet-bar a:first-child {
|
||||
border-top-left-radius: 4px;
|
||||
border-top-right-radius: 4px;
|
||||
}
|
||||
.leaflet-bar a:last-child {
|
||||
border-bottom-left-radius: 4px;
|
||||
border-bottom-right-radius: 4px;
|
||||
border-bottom: none;
|
||||
}
|
||||
.leaflet-bar a.leaflet-disabled {
|
||||
cursor: default;
|
||||
background-color: #f4f4f4;
|
||||
color: #bbb;
|
||||
}
|
||||
|
||||
.leaflet-touch .leaflet-bar a {
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
line-height: 30px;
|
||||
}
|
||||
.leaflet-touch .leaflet-bar a:first-child {
|
||||
border-top-left-radius: 2px;
|
||||
border-top-right-radius: 2px;
|
||||
}
|
||||
.leaflet-touch .leaflet-bar a:last-child {
|
||||
border-bottom-left-radius: 2px;
|
||||
border-bottom-right-radius: 2px;
|
||||
}
|
||||
|
||||
/* zoom control */
|
||||
|
||||
.leaflet-control-zoom-in,
|
||||
.leaflet-control-zoom-out {
|
||||
font: bold 18px 'Lucida Console', Monaco, monospace;
|
||||
text-indent: 1px;
|
||||
}
|
||||
|
||||
.leaflet-touch .leaflet-control-zoom-in, .leaflet-touch .leaflet-control-zoom-out {
|
||||
font-size: 22px;
|
||||
}
|
||||
|
||||
|
||||
/* layers control */
|
||||
|
||||
.leaflet-control-layers {
|
||||
box-shadow: 0 1px 5px rgba(0,0,0,0.4);
|
||||
background: #fff;
|
||||
border-radius: 5px;
|
||||
}
|
||||
.leaflet-control-layers-toggle {
|
||||
background-image: url(images/layers.png);
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
}
|
||||
.leaflet-retina .leaflet-control-layers-toggle {
|
||||
background-image: url(images/layers-2x.png);
|
||||
background-size: 26px 26px;
|
||||
}
|
||||
.leaflet-touch .leaflet-control-layers-toggle {
|
||||
width: 44px;
|
||||
height: 44px;
|
||||
}
|
||||
.leaflet-control-layers .leaflet-control-layers-list,
|
||||
.leaflet-control-layers-expanded .leaflet-control-layers-toggle {
|
||||
display: none;
|
||||
}
|
||||
.leaflet-control-layers-expanded .leaflet-control-layers-list {
|
||||
display: block;
|
||||
position: relative;
|
||||
}
|
||||
.leaflet-control-layers-expanded {
|
||||
padding: 6px 10px 6px 6px;
|
||||
color: #333;
|
||||
background: #fff;
|
||||
}
|
||||
.leaflet-control-layers-scrollbar {
|
||||
overflow-y: scroll;
|
||||
overflow-x: hidden;
|
||||
padding-right: 5px;
|
||||
}
|
||||
.leaflet-control-layers-selector {
|
||||
margin-top: 2px;
|
||||
position: relative;
|
||||
top: 1px;
|
||||
}
|
||||
.leaflet-control-layers label {
|
||||
display: block;
|
||||
font-size: 13px;
|
||||
font-size: 1.08333em;
|
||||
}
|
||||
.leaflet-control-layers-separator {
|
||||
height: 0;
|
||||
border-top: 1px solid #ddd;
|
||||
margin: 5px -10px 5px -6px;
|
||||
}
|
||||
|
||||
/* Default icon URLs */
|
||||
.leaflet-default-icon-path { /* used only in path-guessing heuristic, see L.Icon.Default */
|
||||
background-image: url(images/marker-icon.png);
|
||||
}
|
||||
|
||||
|
||||
/* attribution and scale controls */
|
||||
|
||||
.leaflet-container .leaflet-control-attribution {
|
||||
background: #fff;
|
||||
background: rgba(255, 255, 255, 0.8);
|
||||
margin: 0;
|
||||
}
|
||||
.leaflet-control-attribution,
|
||||
.leaflet-control-scale-line {
|
||||
padding: 0 5px;
|
||||
color: #333;
|
||||
line-height: 1.4;
|
||||
}
|
||||
.leaflet-control-attribution a {
|
||||
text-decoration: none;
|
||||
}
|
||||
.leaflet-control-attribution a:hover,
|
||||
.leaflet-control-attribution a:focus {
|
||||
text-decoration: underline;
|
||||
}
|
||||
.leaflet-attribution-flag {
|
||||
display: inline !important;
|
||||
vertical-align: baseline !important;
|
||||
width: 1em;
|
||||
height: 0.6669em;
|
||||
}
|
||||
.leaflet-left .leaflet-control-scale {
|
||||
margin-left: 5px;
|
||||
}
|
||||
.leaflet-bottom .leaflet-control-scale {
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
.leaflet-control-scale-line {
|
||||
border: 2px solid #777;
|
||||
border-top: none;
|
||||
line-height: 1.1;
|
||||
padding: 2px 5px 1px;
|
||||
white-space: nowrap;
|
||||
-moz-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
background: rgba(255, 255, 255, 0.8);
|
||||
text-shadow: 1px 1px #fff;
|
||||
}
|
||||
.leaflet-control-scale-line:not(:first-child) {
|
||||
border-top: 2px solid #777;
|
||||
border-bottom: none;
|
||||
margin-top: -2px;
|
||||
}
|
||||
.leaflet-control-scale-line:not(:first-child):not(:last-child) {
|
||||
border-bottom: 2px solid #777;
|
||||
}
|
||||
|
||||
.leaflet-touch .leaflet-control-attribution,
|
||||
.leaflet-touch .leaflet-control-layers,
|
||||
.leaflet-touch .leaflet-bar {
|
||||
box-shadow: none;
|
||||
}
|
||||
.leaflet-touch .leaflet-control-layers,
|
||||
.leaflet-touch .leaflet-bar {
|
||||
border: 2px solid rgba(0,0,0,0.2);
|
||||
background-clip: padding-box;
|
||||
}
|
||||
|
||||
|
||||
/* popup */
|
||||
|
||||
.leaflet-popup {
|
||||
position: absolute;
|
||||
text-align: center;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.leaflet-popup-content-wrapper {
|
||||
padding: 1px;
|
||||
text-align: left;
|
||||
border-radius: 12px;
|
||||
}
|
||||
.leaflet-popup-content {
|
||||
margin: 13px 24px 13px 20px;
|
||||
line-height: 1.3;
|
||||
font-size: 13px;
|
||||
font-size: 1.08333em;
|
||||
min-height: 1px;
|
||||
}
|
||||
.leaflet-popup-content p {
|
||||
margin: 17px 0;
|
||||
margin: 1.3em 0;
|
||||
}
|
||||
.leaflet-popup-tip-container {
|
||||
width: 40px;
|
||||
height: 20px;
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
margin-top: -1px;
|
||||
margin-left: -20px;
|
||||
overflow: hidden;
|
||||
pointer-events: none;
|
||||
}
|
||||
.leaflet-popup-tip {
|
||||
width: 17px;
|
||||
height: 17px;
|
||||
padding: 1px;
|
||||
|
||||
margin: -10px auto 0;
|
||||
pointer-events: auto;
|
||||
|
||||
-webkit-transform: rotate(45deg);
|
||||
-moz-transform: rotate(45deg);
|
||||
-ms-transform: rotate(45deg);
|
||||
transform: rotate(45deg);
|
||||
}
|
||||
.leaflet-popup-content-wrapper,
|
||||
.leaflet-popup-tip {
|
||||
background: white;
|
||||
color: #333;
|
||||
box-shadow: 0 3px 14px rgba(0,0,0,0.4);
|
||||
}
|
||||
.leaflet-container a.leaflet-popup-close-button {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
border: none;
|
||||
text-align: center;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
font: 16px/24px Tahoma, Verdana, sans-serif;
|
||||
color: #757575;
|
||||
text-decoration: none;
|
||||
background: transparent;
|
||||
}
|
||||
.leaflet-container a.leaflet-popup-close-button:hover,
|
||||
.leaflet-container a.leaflet-popup-close-button:focus {
|
||||
color: #585858;
|
||||
}
|
||||
.leaflet-popup-scrolled {
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.leaflet-oldie .leaflet-popup-content-wrapper {
|
||||
-ms-zoom: 1;
|
||||
}
|
||||
.leaflet-oldie .leaflet-popup-tip {
|
||||
width: 24px;
|
||||
margin: 0 auto;
|
||||
|
||||
-ms-filter: "progid:DXImageTransform.Microsoft.Matrix(M11=0.70710678, M12=0.70710678, M21=-0.70710678, M22=0.70710678)";
|
||||
filter: progid:DXImageTransform.Microsoft.Matrix(M11=0.70710678, M12=0.70710678, M21=-0.70710678, M22=0.70710678);
|
||||
}
|
||||
|
||||
.leaflet-oldie .leaflet-control-zoom,
|
||||
.leaflet-oldie .leaflet-control-layers,
|
||||
.leaflet-oldie .leaflet-popup-content-wrapper,
|
||||
.leaflet-oldie .leaflet-popup-tip {
|
||||
border: 1px solid #999;
|
||||
}
|
||||
|
||||
|
||||
/* div icon */
|
||||
|
||||
.leaflet-div-icon {
|
||||
background: #fff;
|
||||
border: 1px solid #666;
|
||||
}
|
||||
|
||||
|
||||
/* Tooltip */
|
||||
/* Base styles for the element that has a tooltip */
|
||||
.leaflet-tooltip {
|
||||
position: absolute;
|
||||
padding: 6px;
|
||||
background-color: #fff;
|
||||
border: 1px solid #fff;
|
||||
border-radius: 3px;
|
||||
color: #222;
|
||||
white-space: nowrap;
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
pointer-events: none;
|
||||
box-shadow: 0 1px 3px rgba(0,0,0,0.4);
|
||||
}
|
||||
.leaflet-tooltip.leaflet-interactive {
|
||||
cursor: pointer;
|
||||
pointer-events: auto;
|
||||
}
|
||||
.leaflet-tooltip-top:before,
|
||||
.leaflet-tooltip-bottom:before,
|
||||
.leaflet-tooltip-left:before,
|
||||
.leaflet-tooltip-right:before {
|
||||
position: absolute;
|
||||
pointer-events: none;
|
||||
border: 6px solid transparent;
|
||||
background: transparent;
|
||||
content: "";
|
||||
}
|
||||
|
||||
/* Directions */
|
||||
|
||||
.leaflet-tooltip-bottom {
|
||||
margin-top: 6px;
|
||||
}
|
||||
.leaflet-tooltip-top {
|
||||
margin-top: -6px;
|
||||
}
|
||||
.leaflet-tooltip-bottom:before,
|
||||
.leaflet-tooltip-top:before {
|
||||
left: 50%;
|
||||
margin-left: -6px;
|
||||
}
|
||||
.leaflet-tooltip-top:before {
|
||||
bottom: 0;
|
||||
margin-bottom: -12px;
|
||||
border-top-color: #fff;
|
||||
}
|
||||
.leaflet-tooltip-bottom:before {
|
||||
top: 0;
|
||||
margin-top: -12px;
|
||||
margin-left: -6px;
|
||||
border-bottom-color: #fff;
|
||||
}
|
||||
.leaflet-tooltip-left {
|
||||
margin-left: -6px;
|
||||
}
|
||||
.leaflet-tooltip-right {
|
||||
margin-left: 6px;
|
||||
}
|
||||
.leaflet-tooltip-left:before,
|
||||
.leaflet-tooltip-right:before {
|
||||
top: 50%;
|
||||
margin-top: -6px;
|
||||
}
|
||||
.leaflet-tooltip-left:before {
|
||||
right: 0;
|
||||
margin-right: -12px;
|
||||
border-left-color: #fff;
|
||||
}
|
||||
.leaflet-tooltip-right:before {
|
||||
left: 0;
|
||||
margin-left: -12px;
|
||||
border-right-color: #fff;
|
||||
}
|
||||
|
||||
/* Printing */
|
||||
|
||||
@media print {
|
||||
/* Prevent printers from removing background-images of controls. */
|
||||
.leaflet-control {
|
||||
-webkit-print-color-adjust: exact;
|
||||
print-color-adjust: exact;
|
||||
}
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
|
||||
/* Copyright (C) 2026 Ricardo Guzman - CA2RXU
|
||||
*
|
||||
* This file is part of LoRa APRS iGate.
|
||||
*
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
|
||||
/* Copyright (C) 2026 Ricardo Guzman - CA2RXU
|
||||
*
|
||||
* This file is part of LoRa APRS iGate.
|
||||
*
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
|
||||
/* Copyright (C) 2026 Ricardo Guzman - CA2RXU
|
||||
*
|
||||
* This file is part of LoRa APRS iGate.
|
||||
*
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
|
||||
/* Copyright (C) 2026 Ricardo Guzman - CA2RXU
|
||||
*
|
||||
* This file is part of LoRa APRS iGate.
|
||||
*
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
|
||||
/* Copyright (C) 2026 Ricardo Guzman - CA2RXU
|
||||
*
|
||||
* This file is part of LoRa APRS iGate.
|
||||
*
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
|
||||
/* Copyright (C) 2026 Ricardo Guzman - CA2RXU
|
||||
*
|
||||
* This file is part of LoRa APRS iGate.
|
||||
*
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
|
||||
/* Copyright (C) 2026 Ricardo Guzman - CA2RXU
|
||||
*
|
||||
* This file is part of LoRa APRS iGate.
|
||||
*
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
|
||||
/* Copyright (C) 2026 Ricardo Guzman - CA2RXU
|
||||
*
|
||||
* This file is part of LoRa APRS iGate.
|
||||
*
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
|
||||
/* Copyright (C) 2026 Ricardo Guzman - CA2RXU
|
||||
*
|
||||
* This file is part of LoRa APRS iGate.
|
||||
*
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
|
||||
/* Copyright (C) 2026 Ricardo Guzman - CA2RXU
|
||||
*
|
||||
* This file is part of LoRa APRS iGate.
|
||||
*
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
|
||||
/* Copyright (C) 2026 Ricardo Guzman - CA2RXU
|
||||
*
|
||||
* This file is part of LoRa APRS iGate.
|
||||
*
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
|
||||
/* Copyright (C) 2026 Ricardo Guzman - CA2RXU
|
||||
*
|
||||
* This file is part of LoRa APRS iGate.
|
||||
*
|
||||
|
||||
@@ -1,3 +1,21 @@
|
||||
/* Copyright (C) 2026 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
|
||||
* (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/>.
|
||||
*/
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <SPI.h>
|
||||
#include <WiFi.h>
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
|
||||
/* Copyright (C) 2026 Ricardo Guzman - CA2RXU
|
||||
*
|
||||
* This file is part of LoRa APRS iGate.
|
||||
*
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
|
||||
/* Copyright (C) 2026 Ricardo Guzman - CA2RXU
|
||||
*
|
||||
* This file is part of LoRa APRS iGate.
|
||||
*
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
|
||||
/* Copyright (C) 2026 Ricardo Guzman - CA2RXU
|
||||
*
|
||||
* This file is part of LoRa APRS iGate.
|
||||
*
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
|
||||
/* Copyright (C) 2026 Ricardo Guzman - CA2RXU
|
||||
*
|
||||
* This file is part of LoRa APRS iGate.
|
||||
*
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
|
||||
/* Copyright (C) 2026 Ricardo Guzman - CA2RXU
|
||||
*
|
||||
* This file is part of LoRa APRS iGate.
|
||||
*
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
|
||||
/* Copyright (C) 2026 Ricardo Guzman - CA2RXU
|
||||
*
|
||||
* This file is part of LoRa APRS iGate.
|
||||
*
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
|
||||
/* Copyright (C) 2026 Ricardo Guzman - CA2RXU
|
||||
*
|
||||
* This file is part of LoRa APRS iGate.
|
||||
*
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
|
||||
/* Copyright (C) 2026 Ricardo Guzman - CA2RXU
|
||||
*
|
||||
* This file is part of LoRa APRS iGate.
|
||||
*
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
|
||||
/* Copyright (C) 2026 Ricardo Guzman - CA2RXU
|
||||
*
|
||||
* This file is part of LoRa APRS iGate.
|
||||
*
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
|
||||
/* Copyright (C) 2026 Ricardo Guzman - CA2RXU
|
||||
*
|
||||
* This file is part of LoRa APRS iGate.
|
||||
*
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
|
||||
/* Copyright (C) 2026 Ricardo Guzman - CA2RXU
|
||||
*
|
||||
* This file is part of LoRa APRS iGate.
|
||||
*
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
|
||||
/* Copyright (C) 2026 Ricardo Guzman - CA2RXU
|
||||
*
|
||||
* This file is part of LoRa APRS iGate.
|
||||
*
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
|
||||
/* Copyright (C) 2026 Ricardo Guzman - CA2RXU
|
||||
*
|
||||
* This file is part of LoRa APRS iGate.
|
||||
*
|
||||
|
||||
@@ -26,6 +26,8 @@ board_build.embed_files =
|
||||
data_embed/script.js.gz
|
||||
data_embed/bootstrap.css.gz
|
||||
data_embed/bootstrap.js.gz
|
||||
data_embed/leaflet.css.gz
|
||||
data_embed/leaflet.js.gz
|
||||
data_embed/favicon.png.gz
|
||||
extra_scripts =
|
||||
pre:tools/compress.py
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
|
||||
/* Copyright (C) 2026 Ricardo Guzman - CA2RXU
|
||||
*
|
||||
* This file is part of LoRa APRS iGate.
|
||||
*
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
|
||||
/* Copyright (C) 2026 Ricardo Guzman - CA2RXU
|
||||
*
|
||||
* This file is part of LoRa APRS iGate.
|
||||
*
|
||||
@@ -68,7 +68,7 @@ ___________________________________________________________________*/
|
||||
#endif
|
||||
|
||||
|
||||
String versionDate = "2026-06-12";
|
||||
String versionDate = "2026-07-14";
|
||||
String versionNumber = "4.0.0";
|
||||
Configuration Config;
|
||||
WiFiClient aprsIsClient;
|
||||
@@ -196,7 +196,7 @@ void loop() {
|
||||
APRS_IS_Utils::processLoRaPacket(packet); // Send received packet to APRSIS
|
||||
}
|
||||
|
||||
if (Config.loramodule.txActive && (Config.digi.mode == 2 || Config.digi.mode == 3 || backupDigiMode)) { // If Digi enabled
|
||||
if (Config.loramodule.txActive && (Config.digi.mode == 1 || Config.digi.mode == 2 || Config.digi.mode == 3 || backupDigiMode)) { // If Digi enabled
|
||||
DIGI_Utils::processLoRaPacket(packet); // Send received packet to Digi
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
|
||||
/* Copyright (C) 2026 Ricardo Guzman - CA2RXU
|
||||
*
|
||||
* This file is part of LoRa APRS iGate.
|
||||
*
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
|
||||
/* Copyright (C) 2026 Ricardo Guzman - CA2RXU
|
||||
*
|
||||
* This file is part of LoRa APRS iGate.
|
||||
*
|
||||
|
||||
+11
-8
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
|
||||
/* Copyright (C) 2026 Ricardo Guzman - CA2RXU
|
||||
*
|
||||
* This file is part of LoRa APRS iGate.
|
||||
*
|
||||
@@ -570,14 +570,17 @@ void Configuration::setDefaultValues() {
|
||||
|
||||
void Configuration::setup() {
|
||||
if (!SPIFFS.begin(false)) {
|
||||
Serial.println("SPIFFS Mount Failed");
|
||||
return;
|
||||
} else {
|
||||
Serial.println("SPIFFS Mounted");
|
||||
}
|
||||
Serial.println("SPIFFS Mount Failed, formatting...");
|
||||
|
||||
bool exists = SPIFFS.exists("/igate_conf.json");
|
||||
if (!exists) {
|
||||
if (!SPIFFS.begin(true)) {
|
||||
Serial.println("SPIFFS Format Failed");
|
||||
return;
|
||||
}
|
||||
}
|
||||
Serial.println("SPIFFS Ready");
|
||||
|
||||
if (!SPIFFS.exists("/igate_conf.json")) {
|
||||
Serial.println("Config not found, creating default...");
|
||||
setDefaultValues();
|
||||
writeFile();
|
||||
delay(1000);
|
||||
|
||||
+48
-10
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
|
||||
/* Copyright (C) 2026 Ricardo Guzman - CA2RXU
|
||||
*
|
||||
* This file is part of LoRa APRS iGate.
|
||||
*
|
||||
@@ -42,8 +42,8 @@ extern bool backupDigiMode;
|
||||
|
||||
namespace DIGI_Utils {
|
||||
|
||||
String cleanPathAsterisks(String path) {
|
||||
String terms[] = {",WIDE1*", ",WIDE2*", "*"};
|
||||
String cleanPath(String path) {
|
||||
String terms[] = {"WIDE1*,", "WIDE2*,", "*"};
|
||||
for (String term : terms) {
|
||||
int index = path.indexOf(term);
|
||||
if (index != -1) path.remove(index, term.length()); // less memory than: tempPath.replace("*", "");
|
||||
@@ -51,6 +51,35 @@ namespace DIGI_Utils {
|
||||
return path;
|
||||
}
|
||||
|
||||
String processMode3Path(const String& path, const String& stationCallsign) {
|
||||
int start = 0;
|
||||
bool prevTokensAllStar = true;
|
||||
int ownTokenEnd = -1;
|
||||
|
||||
while (start < path.length()) {
|
||||
int delim = path.indexOf(',', start);
|
||||
if (delim == -1) delim = path.length(); // busca todo hasta lograr encontra una coma o el final del string
|
||||
|
||||
String token = path.substring(start, delim);
|
||||
bool tokenIsOwn = (token == stationCallsign) || (token == stationCallsign + "*");
|
||||
bool tokenStar = token.endsWith("*");
|
||||
|
||||
if (tokenIsOwn) {
|
||||
if (tokenStar) return ""; // already digipeated
|
||||
if (!prevTokensAllStar) return ""; // earlier tokens must be marked
|
||||
ownTokenEnd = delim;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!tokenStar) prevTokensAllStar = false;
|
||||
start = delim + 1;
|
||||
}
|
||||
|
||||
if (ownTokenEnd == -1) return "";
|
||||
String tempPacket = cleanPath(path.substring(0, ownTokenEnd));
|
||||
return tempPacket + "*" + path.substring(ownTokenEnd);
|
||||
}
|
||||
|
||||
String buildPacket(const String& path, const String& packet, bool thirdParty, bool crossFreq) {
|
||||
String stationCallsign = (Config.tacticalCallsign == "" ? Config.callsign : Config.tacticalCallsign);
|
||||
String suffix = thirdParty ? ":}" : ":";
|
||||
@@ -60,11 +89,11 @@ namespace DIGI_Utils {
|
||||
int digiMode = Config.digi.mode;
|
||||
String tempPath = path;
|
||||
|
||||
if (tempPath.indexOf("WIDE1-1") != -1 && (digiMode == 2 || digiMode == 3)) { // WIDE1-1
|
||||
if (tempPath.indexOf("WIDE1-1") != -1 && (digiMode == 1 || digiMode == 2)) { // WIDE1-1
|
||||
if (tempPath.indexOf("*") != -1 ) return ""; // "*" shouldn't be in WIDE1-1 (only) type of packet
|
||||
tempPath.replace("WIDE1-1", stationCallsign + "*");
|
||||
} else if (tempPath.indexOf("WIDE2-") != -1 && digiMode == 3) { // WIDE2-n Digipeater
|
||||
tempPath = cleanPathAsterisks(path);
|
||||
} else if (tempPath.indexOf("WIDE2-") != -1 && digiMode == 2) { // WIDE2-n Digipeater
|
||||
tempPath = cleanPath(path);
|
||||
if (tempPath.indexOf("WIDE2-1") != -1) {
|
||||
tempPath.replace("WIDE2-1", stationCallsign + "*");
|
||||
} else if (tempPath.indexOf("WIDE2-2") != -1) {
|
||||
@@ -72,11 +101,14 @@ namespace DIGI_Utils {
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
} else if (digiMode == 3) { // Repeat if station callsign is in path (free to repeat).
|
||||
tempPath = processMode3Path(tempPath, stationCallsign);
|
||||
if (tempPath == "") return "";
|
||||
}
|
||||
packetToRepeat = packet.substring(0, packet.indexOf(",") + 1);
|
||||
packetToRepeat += tempPath;
|
||||
} else { // CrossFreq Digipeater
|
||||
packetToRepeat = cleanPathAsterisks(packet.substring(0, suffixIndex));
|
||||
packetToRepeat = cleanPath(packet.substring(0, suffixIndex));
|
||||
if (packetToRepeat.indexOf(stationCallsign) != -1) return ""; // stationCallsign shouldn't be in path
|
||||
packetToRepeat += ",";
|
||||
packetToRepeat += stationCallsign;
|
||||
@@ -100,14 +132,14 @@ namespace DIGI_Utils {
|
||||
|
||||
if (commaIndex > 2) { // "path" found
|
||||
const String& path = temp.substring(commaIndex + 1);
|
||||
if (digiMode == 2 || backupDigiMode) {
|
||||
if (digiMode == 1 || backupDigiMode) {
|
||||
bool hasWide = path.indexOf("WIDE1-1") != -1;
|
||||
if (hasWide || crossFreq) {
|
||||
return buildPacket(path, packet, thirdParty, !hasWide);
|
||||
}
|
||||
return "";
|
||||
}
|
||||
if (digiMode == 3) {
|
||||
if (digiMode == 2) {
|
||||
int wide1Index = path.indexOf("WIDE1-1");
|
||||
int wide2Index = path.indexOf("WIDE2-");
|
||||
bool hasWide1 = wide1Index != -1;
|
||||
@@ -121,10 +153,16 @@ namespace DIGI_Utils {
|
||||
|
||||
return "";
|
||||
}
|
||||
if (digiMode == 3) {
|
||||
String stationCallsign = (Config.tacticalCallsign == "" ? Config.callsign : Config.tacticalCallsign);
|
||||
bool containsOwnCall = path.indexOf(stationCallsign) != -1;
|
||||
if (containsOwnCall) return buildPacket(path, packet, thirdParty, false);
|
||||
return "";
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
if (commaIndex == -1 && (digiMode == 2 || backupDigiMode || digiMode == 3) && crossFreq) return buildPacket("", packet, thirdParty, true); // no "path" but is CrossFreq Digi
|
||||
if (commaIndex == -1 && (digiMode == 1 || backupDigiMode || digiMode == 2) && crossFreq) return buildPacket("", packet, thirdParty, true); // no "path" but is CrossFreq Digi
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
|
||||
/* Copyright (C) 2026 Ricardo Guzman - CA2RXU
|
||||
*
|
||||
* This file is part of LoRa APRS iGate.
|
||||
*
|
||||
|
||||
+11
-1
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
|
||||
/* Copyright (C) 2026 Ricardo Guzman - CA2RXU
|
||||
*
|
||||
* This file is part of LoRa APRS iGate.
|
||||
*
|
||||
@@ -185,6 +185,16 @@ namespace GPS_Utils {
|
||||
return " _ / _ / _ ";
|
||||
}
|
||||
|
||||
/*String getDistanceAndCommentFromMicE(const String& packet) {
|
||||
int indexOfMicE1 = packet.indexOf(":`");
|
||||
int indexOfMicE2 = packet.indexOf(":\'");
|
||||
|
||||
if (indexOfMicE1 > 10 || indexOfMicE2 > 10) {
|
||||
return decodeEncodedGPS(packet);
|
||||
}
|
||||
return " _ / _ / _ ";
|
||||
}*/
|
||||
|
||||
void setup() {
|
||||
#ifdef HAS_GPS
|
||||
if (Config.beacon.gpsActive && Config.digi.ecoMode != 1) {
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
|
||||
/* Copyright (C) 2026 Ricardo Guzman - CA2RXU
|
||||
*
|
||||
* This file is part of LoRa APRS iGate.
|
||||
*
|
||||
|
||||
+11
-2
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
|
||||
/* Copyright (C) 2026 Ricardo Guzman - CA2RXU
|
||||
*
|
||||
* This file is part of LoRa APRS iGate.
|
||||
*
|
||||
@@ -69,6 +69,15 @@ float snr;
|
||||
|
||||
namespace LoRa_Utils {
|
||||
|
||||
static String sanitizeForWeb(const String& s) { // replaces non-printable ASCII with '.' for WebUI display
|
||||
String out = s;
|
||||
for (int i = 0; i < (int)out.length(); i++) {
|
||||
uint8_t c = (uint8_t)out[i];
|
||||
if (c < 32 || c == 127) out.setCharAt(i, '.');
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
void setFlag(void) {
|
||||
operationDone = true;
|
||||
}
|
||||
@@ -276,7 +285,7 @@ namespace LoRa_Utils {
|
||||
}
|
||||
ReceivedPacket receivedPacket;
|
||||
receivedPacket.rxTime = NTP_Utils::getFormatedTime();
|
||||
receivedPacket.packet = packet.substring(3);
|
||||
receivedPacket.packet = sanitizeForWeb(packet.substring(3));
|
||||
receivedPacket.RSSI = rssi;
|
||||
receivedPacket.SNR = snr;
|
||||
receivedPackets.push_back(receivedPacket);
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
|
||||
/* Copyright (C) 2026 Ricardo Guzman - CA2RXU
|
||||
*
|
||||
* This file is part of LoRa APRS iGate.
|
||||
*
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
|
||||
/* Copyright (C) 2026 Ricardo Guzman - CA2RXU
|
||||
*
|
||||
* This file is part of LoRa APRS iGate.
|
||||
*
|
||||
|
||||
@@ -1,3 +1,21 @@
|
||||
/* Copyright (C) 2026 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
|
||||
* (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/>.
|
||||
*/
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
#include "network_manager.h"
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
|
||||
/* Copyright (C) 2026 Ricardo Guzman - CA2RXU
|
||||
*
|
||||
* This file is part of LoRa APRS iGate.
|
||||
*
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
|
||||
/* Copyright (C) 2026 Ricardo Guzman - CA2RXU
|
||||
*
|
||||
* This file is part of LoRa APRS iGate.
|
||||
*
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
|
||||
/* Copyright (C) 2026 Ricardo Guzman - CA2RXU
|
||||
*
|
||||
* This file is part of LoRa APRS iGate.
|
||||
*
|
||||
|
||||
+4
-4
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
|
||||
/* Copyright (C) 2026 Ricardo Guzman - CA2RXU
|
||||
*
|
||||
* This file is part of LoRa APRS iGate.
|
||||
*
|
||||
@@ -82,7 +82,7 @@ namespace QUERY_Utils {
|
||||
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 ((digiMode == 1 || 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;
|
||||
@@ -97,7 +97,7 @@ namespace QUERY_Utils {
|
||||
answer = "Digipeater Mode control not possible";
|
||||
}
|
||||
} else if (queryQuestion.startsWith("?EM=ON")) {
|
||||
if ((digiMode == 2 || digiMode == 3) && onlyRadioActive) {
|
||||
if ((digiMode == 1 || digiMode == 2 || digiMode == 3) && onlyRadioActive) {
|
||||
if (digiEcoMode == 0) { // Start Digipeater EcoMode
|
||||
answer = "DigiEcoMode:ON";
|
||||
Config.digi.ecoMode = 1;
|
||||
@@ -139,7 +139,7 @@ namespace QUERY_Utils {
|
||||
|
||||
if (answer == "") return "";
|
||||
|
||||
String queryAnswer = Config.callsign;
|
||||
String queryAnswer = (Config.tacticalCallsign == "" ? Config.callsign : Config.tacticalCallsign);
|
||||
queryAnswer += ">APLRG1";
|
||||
if (queryFromAPRSIS) {
|
||||
queryAnswer += ",TCPIP,qAC";
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
|
||||
/* Copyright (C) 2026 Ricardo Guzman - CA2RXU
|
||||
*
|
||||
* This file is part of LoRa APRS iGate.
|
||||
*
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
|
||||
/* Copyright (C) 2026 Ricardo Guzman - CA2RXU
|
||||
*
|
||||
* This file is part of LoRa APRS iGate.
|
||||
*
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
|
||||
/* Copyright (C) 2026 Ricardo Guzman - CA2RXU
|
||||
*
|
||||
* This file is part of LoRa APRS iGate.
|
||||
*
|
||||
@@ -79,11 +79,15 @@ namespace SYSLOG_Utils {
|
||||
syslogPacket.concat(sender);
|
||||
syslogPacket.concat(" ---> ");
|
||||
syslogPacket.concat(packet.substring(colonIndex + 2));
|
||||
} else if (nextChar == '`') {
|
||||
} else if (nextChar == '`' || nextChar == '\'') { // both Mic-E DTIs are valid
|
||||
syslogPacket.concat("MIC-E / ");
|
||||
syslogPacket.concat(sender);
|
||||
syslogPacket.concat(" ---> ");
|
||||
syslogPacket.concat(String(nextChar)); // restore the actual indicator received
|
||||
syslogPacket.concat(packet.substring(colonIndex + 2));
|
||||
// append distance for Mic-E, same as the GPS path
|
||||
//syslogPacket.concat(" / ");
|
||||
//syslogPacket.concat(GPS_Utils::getDistanceAndComment(packet));
|
||||
} else if (nextChar == ';') {
|
||||
syslogPacket.concat("OBJECT / ");
|
||||
syslogPacket.concat(sender);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
|
||||
/* Copyright (C) 2026 Ricardo Guzman - CA2RXU
|
||||
*
|
||||
* This file is part of LoRa APRS iGate.
|
||||
*
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
|
||||
/* Copyright (C) 2026 Ricardo Guzman - CA2RXU
|
||||
*
|
||||
* This file is part of LoRa APRS iGate.
|
||||
*
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
|
||||
/* Copyright (C) 2026 Ricardo Guzman - CA2RXU
|
||||
*
|
||||
* This file is part of LoRa APRS iGate.
|
||||
*
|
||||
|
||||
+25
-1
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
|
||||
/* Copyright (C) 2026 Ricardo Guzman - CA2RXU
|
||||
*
|
||||
* This file is part of LoRa APRS iGate.
|
||||
*
|
||||
@@ -49,6 +49,14 @@ extern const char web_bootstrap_js[] asm("_binary_data_embed_bootstrap_js_gz_sta
|
||||
extern const char web_bootstrap_js_end[] asm("_binary_data_embed_bootstrap_js_gz_end");
|
||||
extern const size_t web_bootstrap_js_len = web_bootstrap_js_end - web_bootstrap_js;
|
||||
|
||||
extern const char web_leaflet_css[] asm("_binary_data_embed_leaflet_css_gz_start");
|
||||
extern const char web_leaflet_css_end[] asm("_binary_data_embed_leaflet_css_gz_end");
|
||||
extern const size_t web_leaflet_css_len = web_leaflet_css_end - web_leaflet_css;
|
||||
|
||||
extern const char web_leaflet_js[] asm("_binary_data_embed_leaflet_js_gz_start");
|
||||
extern const char web_leaflet_js_end[] asm("_binary_data_embed_leaflet_js_gz_end");
|
||||
extern const size_t web_leaflet_js_len = web_leaflet_js_end - web_leaflet_js;
|
||||
|
||||
// Declare external symbols for the embedded image data
|
||||
extern const unsigned char favicon_data[] asm("_binary_data_embed_favicon_png_gz_start");
|
||||
extern const unsigned char favicon_data_end[] asm("_binary_data_embed_favicon_png_gz_end");
|
||||
@@ -363,6 +371,20 @@ namespace WEB_Utils {
|
||||
request->send(response);
|
||||
}
|
||||
|
||||
void handleLeafletStyle(AsyncWebServerRequest *request) {
|
||||
AsyncWebServerResponse *response = request->beginResponse(200, "text/css", (const uint8_t*)web_leaflet_css, web_leaflet_css_len);
|
||||
response->addHeader("Content-Encoding", "gzip");
|
||||
response->addHeader("Cache-Control", "max-age=3600");
|
||||
request->send(response);
|
||||
}
|
||||
|
||||
void handleLeafletScript(AsyncWebServerRequest *request) {
|
||||
AsyncWebServerResponse *response = request->beginResponse(200, "text/javascript", (const uint8_t*)web_leaflet_js, web_leaflet_js_len);
|
||||
response->addHeader("Content-Encoding", "gzip");
|
||||
response->addHeader("Cache-Control", "max-age=3600");
|
||||
request->send(response);
|
||||
}
|
||||
|
||||
void setup() {
|
||||
if (Config.digi.ecoMode == 0) {
|
||||
server.on("/", HTTP_GET, handleHome);
|
||||
@@ -376,6 +398,8 @@ namespace WEB_Utils {
|
||||
server.on("/script.js", HTTP_GET, handleScript);
|
||||
server.on("/bootstrap.css", HTTP_GET, handleBootstrapStyle);
|
||||
server.on("/bootstrap.js", HTTP_GET, handleBootstrapScript);
|
||||
server.on("/leaflet.css", HTTP_GET, handleLeafletStyle);
|
||||
server.on("/leaflet.js", HTTP_GET, handleLeafletScript);
|
||||
server.on("/favicon.png", HTTP_GET, handleFavicon);
|
||||
|
||||
OTA_Utils::setup(&server); // Include OTA Updater for WebServer
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
|
||||
/* Copyright (C) 2026 Ricardo Guzman - CA2RXU
|
||||
*
|
||||
* This file is part of LoRa APRS iGate.
|
||||
*
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
|
||||
/* Copyright (C) 2026 Ricardo Guzman - CA2RXU
|
||||
*
|
||||
* This file is part of LoRa APRS iGate.
|
||||
*
|
||||
|
||||
+14
-12
@@ -1,17 +1,17 @@
|
||||
# Copyright (C) 2025 Ricardo Guzman - CA2RXU
|
||||
#
|
||||
# Copyright (C) 2026 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,6 +26,8 @@ files = [
|
||||
'data_embed/style.css',
|
||||
'data_embed/bootstrap.js',
|
||||
'data_embed/bootstrap.css',
|
||||
'data_embed/leaflet.js',
|
||||
'data_embed/leaflet.css',
|
||||
'data_embed/favicon.png',
|
||||
]
|
||||
|
||||
@@ -40,20 +42,20 @@ with open('src/LoRa_APRS_iGate.cpp', encoding='utf-8') as cpp_file:
|
||||
if start > 0 and end > start:
|
||||
versionDate = line[start:end]
|
||||
break
|
||||
|
||||
|
||||
for src in files:
|
||||
out = src + ".gz"
|
||||
|
||||
|
||||
|
||||
|
||||
with open(src, 'rb') as f:
|
||||
content = f.read()
|
||||
|
||||
|
||||
if src == 'data_embed/index.html':
|
||||
env_vars = env["BOARD"] + "<br>" + ','.join(env["BUILD_FLAGS"]).replace('-Werror -Wall,', '').replace(',-DELEGANTOTA_USE_ASYNC_WEBSERVER=1', '') + "<br>" + "Version date: " + versionDate
|
||||
current_date = datetime.datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S') + " UTC"
|
||||
build_info = f'{env_vars}<br>Build date: {current_date}'.encode()
|
||||
|
||||
|
||||
content = content.replace(b'%BUILD_INFO%', build_info)
|
||||
|
||||
|
||||
with open(out, 'wb') as f:
|
||||
f.write(gzip.compress(content, compresslevel=9))
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
|
||||
/* Copyright (C) 2026 Ricardo Guzman - CA2RXU
|
||||
*
|
||||
* This file is part of LoRa APRS iGate.
|
||||
*
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
|
||||
/* Copyright (C) 2026 Ricardo Guzman - CA2RXU
|
||||
*
|
||||
* This file is part of LoRa APRS iGate.
|
||||
*
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
|
||||
/* Copyright (C) 2026 Ricardo Guzman - CA2RXU
|
||||
*
|
||||
* This file is part of LoRa APRS iGate.
|
||||
*
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
|
||||
/* Copyright (C) 2026 Ricardo Guzman - CA2RXU
|
||||
*
|
||||
* This file is part of LoRa APRS iGate.
|
||||
*
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
|
||||
/* Copyright (C) 2026 Ricardo Guzman - CA2RXU
|
||||
*
|
||||
* This file is part of LoRa APRS iGate.
|
||||
*
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
|
||||
/* Copyright (C) 2026 Ricardo Guzman - CA2RXU
|
||||
*
|
||||
* This file is part of LoRa APRS iGate.
|
||||
*
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
|
||||
/* Copyright (C) 2026 Ricardo Guzman - CA2RXU
|
||||
*
|
||||
* This file is part of LoRa APRS iGate.
|
||||
*
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
|
||||
/* Copyright (C) 2026 Ricardo Guzman - CA2RXU
|
||||
*
|
||||
* This file is part of LoRa APRS iGate.
|
||||
*
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
|
||||
/* Copyright (C) 2026 Ricardo Guzman - CA2RXU
|
||||
*
|
||||
* This file is part of LoRa APRS iGate.
|
||||
*
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
|
||||
/* Copyright (C) 2026 Ricardo Guzman - CA2RXU
|
||||
*
|
||||
* This file is part of LoRa APRS iGate.
|
||||
*
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
|
||||
/* Copyright (C) 2026 Ricardo Guzman - CA2RXU
|
||||
*
|
||||
* This file is part of LoRa APRS iGate.
|
||||
*
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
|
||||
/* Copyright (C) 2026 Ricardo Guzman - CA2RXU
|
||||
*
|
||||
* This file is part of LoRa APRS iGate.
|
||||
*
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
|
||||
/* Copyright (C) 2026 Ricardo Guzman - CA2RXU
|
||||
*
|
||||
* This file is part of LoRa APRS iGate.
|
||||
*
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
|
||||
/* Copyright (C) 2026 Ricardo Guzman - CA2RXU
|
||||
*
|
||||
* This file is part of LoRa APRS iGate.
|
||||
*
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
|
||||
/* Copyright (C) 2026 Ricardo Guzman - CA2RXU
|
||||
*
|
||||
* This file is part of LoRa APRS iGate.
|
||||
*
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
|
||||
/* Copyright (C) 2026 Ricardo Guzman - CA2RXU
|
||||
*
|
||||
* This file is part of LoRa APRS iGate.
|
||||
*
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
|
||||
/* Copyright (C) 2026 Ricardo Guzman - CA2RXU
|
||||
*
|
||||
* This file is part of LoRa APRS iGate.
|
||||
*
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
|
||||
/* Copyright (C) 2026 Ricardo Guzman - CA2RXU
|
||||
*
|
||||
* This file is part of LoRa APRS iGate.
|
||||
*
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
|
||||
/* Copyright (C) 2026 Ricardo Guzman - CA2RXU
|
||||
*
|
||||
* This file is part of LoRa APRS iGate.
|
||||
*
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
|
||||
/* Copyright (C) 2026 Ricardo Guzman - CA2RXU
|
||||
*
|
||||
* This file is part of LoRa APRS iGate.
|
||||
*
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
|
||||
/* Copyright (C) 2026 Ricardo Guzman - CA2RXU
|
||||
*
|
||||
* This file is part of LoRa APRS iGate.
|
||||
*
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
|
||||
/* Copyright (C) 2026 Ricardo Guzman - CA2RXU
|
||||
*
|
||||
* This file is part of LoRa APRS iGate.
|
||||
*
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
|
||||
/* Copyright (C) 2026 Ricardo Guzman - CA2RXU
|
||||
*
|
||||
* This file is part of LoRa APRS iGate.
|
||||
*
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
|
||||
/* Copyright (C) 2026 Ricardo Guzman - CA2RXU
|
||||
*
|
||||
* This file is part of LoRa APRS iGate.
|
||||
*
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
|
||||
/* Copyright (C) 2026 Ricardo Guzman - CA2RXU
|
||||
*
|
||||
* This file is part of LoRa APRS iGate.
|
||||
*
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
|
||||
/* Copyright (C) 2026 Ricardo Guzman - CA2RXU
|
||||
*
|
||||
* This file is part of LoRa APRS iGate.
|
||||
*
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
|
||||
/* Copyright (C) 2026 Ricardo Guzman - CA2RXU
|
||||
*
|
||||
* This file is part of LoRa APRS iGate.
|
||||
*
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
|
||||
/* Copyright (C) 2026 Ricardo Guzman - CA2RXU
|
||||
*
|
||||
* This file is part of LoRa APRS iGate.
|
||||
*
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
|
||||
/* Copyright (C) 2026 Ricardo Guzman - CA2RXU
|
||||
*
|
||||
* This file is part of LoRa APRS iGate.
|
||||
*
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
|
||||
/* Copyright (C) 2026 Ricardo Guzman - CA2RXU
|
||||
*
|
||||
* This file is part of LoRa APRS iGate.
|
||||
*
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
|
||||
/* Copyright (C) 2026 Ricardo Guzman - CA2RXU
|
||||
*
|
||||
* This file is part of LoRa APRS iGate.
|
||||
*
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
|
||||
/* Copyright (C) 2026 Ricardo Guzman - CA2RXU
|
||||
*
|
||||
* This file is part of LoRa APRS iGate.
|
||||
*
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
|
||||
/* Copyright (C) 2026 Ricardo Guzman - CA2RXU
|
||||
*
|
||||
* This file is part of LoRa APRS iGate.
|
||||
*
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
|
||||
/* Copyright (C) 2026 Ricardo Guzman - CA2RXU
|
||||
*
|
||||
* This file is part of LoRa APRS iGate.
|
||||
*
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
|
||||
/* Copyright (C) 2026 Ricardo Guzman - CA2RXU
|
||||
*
|
||||
* This file is part of LoRa APRS iGate.
|
||||
*
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
|
||||
/* Copyright (C) 2026 Ricardo Guzman - CA2RXU
|
||||
*
|
||||
* This file is part of LoRa APRS iGate.
|
||||
*
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
|
||||
/* Copyright (C) 2026 Ricardo Guzman - CA2RXU
|
||||
*
|
||||
* This file is part of LoRa APRS iGate.
|
||||
*
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
|
||||
/* Copyright (C) 2026 Ricardo Guzman - CA2RXU
|
||||
*
|
||||
* This file is part of LoRa APRS iGate.
|
||||
*
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
|
||||
/* Copyright (C) 2026 Ricardo Guzman - CA2RXU
|
||||
*
|
||||
* This file is part of LoRa APRS iGate.
|
||||
*
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
|
||||
/* Copyright (C) 2026 Ricardo Guzman - CA2RXU
|
||||
*
|
||||
* This file is part of LoRa APRS iGate.
|
||||
*
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
|
||||
/* Copyright (C) 2026 Ricardo Guzman - CA2RXU
|
||||
*
|
||||
* This file is part of LoRa APRS iGate.
|
||||
*
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
|
||||
/* Copyright (C) 2026 Ricardo Guzman - CA2RXU
|
||||
*
|
||||
* This file is part of LoRa APRS iGate.
|
||||
*
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user