Compare commits

...

20 Commits

Author SHA1 Message Date
US1GHQ e6576de2ab Revert "Upload LIB"
1 year ago
US1GHQ 74442ebf12 Upload LIB
1 year ago
US1GHQ 2a46d4d438 Reduce SPI speed for more stability 1W Modules (TEST)
1 year ago
US1GHQ 04a705520e More chnges from DL9SAU
1 year ago
US1GHQ 05abffafe3 BBS support via KISS
1 year ago
US1GHQ 0cae1f75cf Some changes
1 year ago
US1GHQ 0f3df6df71 Some changes
1 year ago
US1GHQ 6f02517eff Disable digi by default
1 year ago
US1GHQ 0ad9aed5d5 Some fixes
1 year ago
US1GHQ 24719c759f Remove code for calculate RSSI and SNR, because we using newest lib of RadioHead
1 year ago
US1GHQ 3fc013ea64 Fix TX PIN for PA LNA
1 year ago
US1GHQ b8a2c5b5d6 Fix ESP32 Working
1 year ago
US1GHQ c0275e1946 Correct BATT READ on the TTGO LoRa v2.1.6
1 year ago
US1GHQ f964289f6d Almost Done
1 year ago
US1GHQ ce8b02cabd Disable SNR Report to KISS
1 year ago
US1GHQ 5fdc8b10bb Fix KISS LIB
1 year ago
US1GHQ 3ae7e9ab89 Changes
1 year ago
US1GHQ 713614ec11 Forgot for ESP32-DEV-V1
1 year ago
US1GHQ b558cc1243 Start add packet mode and other feauters from previous version
1 year ago
US1GHQ d1e51d8039 DIGI_IGATE feauters from dl9sau
1 year ago

@ -4,7 +4,7 @@ Tracker can be used on its own.
You can also connect it via blueetooth with APRSdroid.
After connection with APRX based DIGI it can be used as KISS-TNC
![diagram](http://git.mis.ks.ua/US1GHQ/TTGO-T-Beam-LoRa-APRS/raw/branch/lora-esp32-dev/img/digi-schemat.png)
![diagram](https://github.com/SQ9MDD/TTGO-T-Beam-LoRa-APRS/blob/master/img/digi-schemat.png)
## Contributors
* Initial work: OE1ACM, OE3CJB

@ -39,27 +39,23 @@
</div>
<div class="grid-container full">
<input class="button-primary" type="submit" value="Save">
</div>
</div>
</form>
</article>
</section>
<section>
<div class="grid-container full">
<h2 class="u-full-width">APRS Settings</h2>
</div>
<article>
<div class="grid-container full">
<h2 class="u-full-width">APRS Settings</h2>
</div>
<form action="/save_aprs_cfg" method="post">
<div class="grid-container full">
<h5 class="u-full-width">Transmission Settings</h5>
</div>
<div class="grid-container 3 columns">
<div>
<label for="lora_freq">Frequency [MHz]</label>
<input name="lora_freq" id="lora_freq" type="number" min="144.000" max="928.000" step="0.001" title="LoRa center frequency between 433.001 and 928.000">
</div>
<div class="grid-container halves">
<div>
<label for="txPower">dBm</label>
<input name="txPower" id="txPower" type="number" min="0" max="23" title="LoRa TX Power. Range 0 to 23dBm">
<label for="lora_freq">Main Frequency [MHz]</label>
<input name="lora_freq" id="lora_freq" type="number" min="144.0000" max="928.0000" step="0.0001" title="LoRa center frequency between 144.0001 and 928.0000. I.e. 433.775">
</div>
<div>
<label for="lora_speed">Speed</label>
@ -71,11 +67,42 @@
<option value="210">BW 125khz CR 4:7 SF 12 (209bps)</option>
<option value="180">BW 125khz CR 4:8 SF 12 (183bps)</option>
<option value="610">BW 125khz CR 4:8 SF 10 (610bps)</option>
<option value="1200">BW 125khz CR 4:5 SF 9 (PL,UA, 1200bps)</option>
<option value="1200">BW 125khz CR 4:5 SF 9 (1200bps)</option>
<option value="6000">BW 125khz CR 4:5 SF 7 (BBS, 6000bps)</option>
<option value="21000">BW 500khz CR 4:5 SF 7 (BBS, 21000bps)</option>
</select>
</div>
<div>
<label for="lora_tx_en">Enable LoRa transmitter</label>
<input name="lora_tx_en" id="lora_tx_en" type="checkbox" value="1" title="Allow TX on LoRa. Disable this if you like to prevent TX under all circumstances (i.e. if your tracker is behind an rx-amplifier)">
</div>
<div>
<label for="txPower">TX power [dBm]</label>
<input name="txPower" id="txPower" type="number" min="0" max="23" title="LoRa TX Power. Range 0 to 23dBm">
</div>
<div>
<label for="lora_cradapt">Automatic CodeRate adaption on TX</label>
<input name="lora_cradapt" id="lora_cradapt" type="checkbox" value="1" title="Enable automatic CR adaption. Use this only if you are not a WIDE1 or WIDE2 digi. Still testing, if it behaves good to our network. Currently works only for SF12 modes, because for SF 10 and lower the code for programming CR+SF+BW-combination has not been written yet">
</div>
</div>
<div class="grid-container halves">
<div>
<label for="lora_rssi2p">Add SNR and RSSI to path</label>
<select id="lora_rssi2p" name="lora_rssi2p">
<option value="0">off</option>
<option value="1">To RF during digipeating</option>
<option value="2">To KISS</option>
<option value="4">To APRSIS</option>
<option value="3">To RF and KISS</option>
<option value="5">To RF and APRSIS</option>
<option value="6">To KISS and APRSIS</option>
<option value="7">To RF and KISS and APRSIS</option>
</select>
</div>
<div>
<label for="snraprsis">SNR/RSSI-encoding on kiss: compatible to APRS-IS?</label>
<input name="snraprsis" id="snraprsis" type="checkbox" value=1 title="Add snr+rssi at last digipeater, without digipeated flag. Use this for APRSIS connections. If you have connected a digipeater software to kiss, this option has to be switched off">
</div>
</div>
<div class="grid-container full">
<h5 class="u-full-width">Station Settings</h5>
@ -83,11 +110,11 @@
<div class="grid-container quarters">
<div>
<label for="aprs_callsign">Callsign and SSID</label>
<input class="u-full-width" type="text" minlength="3" name="aprs_callsign" placeholder="NOCALL-1" id="aprs_callsign" title="your callsign with SSID">
<input class="u-full-width" type="text" minlength="3" maxlength="9" name="aprs_callsign" placeholder="NOCALL-1" id="aprs_callsign" title="your callsign with SSID">
</div>
<div>
<label for="aprs_relay_path">Relay Path</label>
<input class="u-full-width" type="text" minlength="0" name="aprs_relay_path" id="aprs_relay_path" title="APRS path, use the shortest as possible, ECHO or WIDE1-1">
<input class="u-full-width" type="text" minlength="0" name="aprs_relay_path" id="aprs_relay_path" title="APRS path, use the shortest as possible, ECHO or WIDE1-1. Only value '1' enables dest-path-digi-notation (like DL9SAU>APRS-1:..) instead of Path ..,WIDE1-1:..">
</div>
<div>
<label for="aprs_s_table">Symbol Table</label>
@ -95,20 +122,24 @@
</div>
<div>
<label for="aprs_symbol">Symbol</label>
<input class="u-full-width" type="text" minlength="1" maxlength="1" name="aprs_symbol" id="aprs_symbol" title="select an icon, for example: [ - jogger, Y - jacht, > - car, b - bike ">
<input class="u-full-width" type="text" minlength="1" maxlength="1" name="aprs_symbol" id="aprs_symbol" title="select an icon, for example: [ - jogger, Y - jacht, > - car, b - bike">
</div>
<div>
<label for="aprs_alt">Show Altitude</label>
<input name="aprs_alt" id="aprs_alt" type="checkbox" value="1" title=" show altitude as frame part">
</div>
</div>
<div>
<label for="show_cmt">Show Comment</label>
<input name="show_cmt" id="show_cmt" type="checkbox" value="1" title=" show comment text">
</div>
</div>
<div>
<label for="aprs_comment">Comment</label>
<input class="u-full-width" type="text" minlength="0" maxlength="64" name="aprs_comment" id="aprs_comment" title=" personal comment">
</div>
<div>
<label for="aprs_comm_rt">Ratelimit adding comment text</label>
<input name="aprs_comm_rt" id="aprs_comm_rt" type="checkbox" value="1" title="If enabled, comment text is sent only every tenth's transmission. Saves airtime.">
</div>
<div>
<label for="aprs_batt">Show Battery</label>
<input name="aprs_batt" id="aprs_batt" type="checkbox" value="1" title=" show battery voltage after personal comment">
@ -124,7 +155,7 @@
</div>
<div>
<label for="tnc_tel_int">Self Telemetry Interval [s]</label>
<input name="tnc_tel_int" id="tnc_tel_int" type="number" min="10" title="time between sending telemetry if Enable Self Telemetry option is selected ">
<input name="tnc_tel_int" id="tnc_tel_int" type="number" min="10" title="time between sending telemetry if Enable Self Telemetry option is selected">
</div>
<div>
<label for="tnc_tel_mic">Self Telemetry Sequence</label>
@ -144,11 +175,11 @@
<div class="grid-container quarters">
<div>
<label for="aprs_fixed_beac">Fixed Beacon</label>
<input name="aprs_fixed_beac" id="aprs_fixed_beac" type="checkbox" value="1" title="enable fixed beacon when GPS is disabled or no fix">
<input name="aprs_fixed_beac" id="aprs_fixed_beac" type="checkbox" value="1" title="enable fixed beacon when GPS is disabled or no fix">
</div>
<div>
<label for="aprs_fb_interv">Fixed Beacon Interval [s]</label>
<input name="aprs_fb_interv" id="aprs_fb_interv" type="number" min="120" title="time between sending a beacon if Fixed Beacon option is selected ">
<input name="aprs_fb_interv" id="aprs_fb_interv" type="number" min="120" title="time between sending a beacon if Fixed Beacon option is selected">
</div>
<div>
<label for="aprs_lat_p">Latitude Preset</label>
@ -165,31 +196,168 @@
<div class="grid-container quarters">
<div>
<label for="sb_min_interv">Min interval [s]</label>
<input name="sb_min_interv" id="sb_min_interv" size="10" type="number" min="10" title="Minimal time for Smart Beaconing">
<input name="sb_min_interv" id="sb_min_interv" type="number" min="10" title="Minimal time for Smart Beaconing">
</div>
<div>
<label for="sb_max_interv">Max interval [s]</label>
<input name="sb_max_interv" id="sb_max_interv" size="10" type="number" min="120" title="Maximal time for Smart Beaconing">
<input name="sb_max_interv" id="sb_max_interv" type="number" min="120" title="Maximal time for Smart Beaconing">
</div>
</div>
<div class="grid-container quarters">
<div>
<label for="sb_min_speed">Min speed [km/h]</label>
<input name="sb_min_speed" id="sb_min_speed" size="10" type="number" min="0" title="Minimal speed for Smart Beaconing">
<input name="sb_min_speed" id="sb_min_speed" type="number" min="0" title="Minimal speed for Smart Beaconing">
</div>
<div>
<label for="sb_max_speed">Max speed [km/h]</label>
<input name="sb_max_speed" id="sb_max_speed" size="10" type="number" min="1" title="Maximal speed for Smart Beaconing">
<input name="sb_max_speed" id="sb_max_speed" type="number" min="1" title="Maximal speed for Smart Beaconing">
</div>
</div>
<div class="grid-container quarters">
<div>
<label for="sb_angle">Course change [degrees]</label>
<input name="sb_angle" id="sb_angle" size="10" type="number" min="1" max="360" title="Angle of course change to speed up beacon transmission">
<input name="sb_angle" id="sb_angle" type="number" min="5" max="360" title="Angle of course change to speed up beacon transmission. Recommended value: 28">
</div>
<div>
<label for="sb_turn_slope">Turn Slope [degrees]</label>
<input name="sb_turn_slope" id="sb_turn_slope" type="number" min="5" max="255" title="Smart beaconing turn slope. Use 7 for pedestrian, 11 for low/mid speed and 26 for high speed. Recommended value: 26">
</div>
<div>
<label for="sb_turn_time">Turn Time [seconds]</label>
<input name="sb_turn_time" id="sb_turn_time" type="number" min="5", title="Smart beaconing turn time. Wait at least this amount of seconds for next beacon. Recommended value: 30">
</div>
</div>
<div class="grid-container quarters">
<div>
<label for="gps_enabled">GPS enabled</label>
<input name="gps_enabled" id="gps_enabled" type="checkbox" value="1" title="enable or disable GPS">
</div>
</div>
<div>
<label for="kiss_myloc_ok">Accept own positions via KISS</label>
<input name="kiss_myloc_ok" id="kiss_myloc_ok" type="checkbox" value="1" title="If set to true, we'll stop sending own position beacons if we heard a position from our call via kiss. Uncheck this, if you like to filter out those positions and keep sending it by this device.">
</div>
<div>
<label for="gps_sleep_ok">Allow GPS sleep while own positions received via KISS</label>
<input name="gps_sleep_ok" id="gps_sleep_ok" type="checkbox" value="1" title="If we have a kiss client like aprsdroid, or a digipeater software, which sends own positions (with same call as ours), we pause sending own positions (neither fixed nor smart beaconing). Uncheck, if you have a display attached and still like to see your current GPS position. This option is only honored if configuration 'Accept own positions via KISS' enabled. Why? If your filter out own positions from and this device sends on it's own, it needs gps running ;)">
</div>
</div>
<div class="grid-container full">
<h6 class="u-full-width">Additional settings for secondary frequency:<br/>EXPERIMANTAL - USE WITH CARE!</h6>
</div>
<div class="grid-container halves">
<div>
<label for="lora_freq_x">Secondary Frequency [MHz]</label>
(for cross-repeating or listening transmissions from igates)</label>
<input name="lora_freq_x" id="lora_freq_x" type="number" min="0.0000" max="928.0000" step="0.0001" title="LoRa center frequency - must be different from main frequency and between 433.0001 and 928.0000 or 0 if not needed. I.e. 433.900">
</div>
<div>
<label for="txPower_x">TX power on secondary frequency [dBm]</label>
<input name="txPower_x" id="txPower_x" type="number" min="0" max="23" title="LoRa TX Power on secondary frequency. Range 0 to 23dBm">
</div>
</div>
<div class="grid-container halves">
<div>
<label for="lora_speed_x">Speed on secondary frequency</label>
<select id="lora_speed_x" name="lora_speed_x">
<option value="1200">BW 125khz CR 4:7 SF 9 (Fast Standard. default; use high speeds on the secondary frequency)</option>
<option value="439">BW 31.25khz CR 4:5 SF 9 (300bps)</option>
<option value="1367">BW 31.25khz CR 4:5 SF 7 (1200bps)</option>
<option value="300">BW 125khz CR 4:5 SF 12 (default, 300bps)</option>
<option value="240">BW 125khz CR 4:6 SF 12 (244bps)</option>
<option value="210">BW 125khz CR 4:7 SF 12 (209bps)</option>
<option value="180">BW 125khz CR 4:8 SF 12 (183bps)</option>
<option value="610">BW 125khz CR 4:8 SF 10 (610bps)</option>
<option value="6000">BW 125khz CR 4:5 SF 7 (BBS, 6000bps)</option>
<option value="21000">BW 500khz CR 4:5 SF 7 (BBS, 21000bps)</option>
</select>
</div>
</div>
<div class="grid-container halves">
<div>
<label for="rx_qrg">RX on frequencies</label>
(Only honored, if we are NOT configured as WIDE1 or WIDE2 digi. If set to both frequencies: Ratio depends on how many packets are received on each qrg in a 10min window; we stay 20s on one qrg.)
<select id="rx_qrg" name="rx_qrg">
<option value="1">RX on main frequency</option>
<option value="2">RX on secondary frequency</option>
<option value="3">RX on both frequencies</option>
</select>
</div>
<div>
<label for="lora_freq_rx_curr">Current RX Frequency:</label>
<input name="lora_freq_rx_curr" id="lora_freq_rx_curr" type="number" readonly title="Nothing to enter here"</input>
</div>
</div>
<div class="grid-container full">
<h6 class="u-full-width">Additional settings for mode repater:<br/>EXPERIMANTAL - USE WITH CARE!</h6>
</div>
<div class="grid-container halves">
<div>
<label for="lora_dig_mode">LoRa Repater Mode</label>
<select id="lora_dig_mode" name="lora_dig_mode">
<option value="0">off. This device does not do any repeating decision.</option>
<option value="1">Repeat if own call is addressed (recommended for normal users). default.</option>
<option value="2">Act as WIDE1 (fill-in) digi</option>
<option value="3">Act as a simple WIDE2 digi (consider to instead attach a real aprs-digipeater software via KISS)</option>
</select>
</div>
</div>
<div class="grid-container halves">
<div>
<label for="lora_dig_x_m">Digipeat heard stations on which frequencies</label>
(If LoRa Repeater Mode has not been set to off)
<select id="lora_dig_x_m" name="lora_dig_x_m">
<option value="0">Repeat only to main frequency (default)</option>
<option value="1">Repeat to both frequencies</option>
<option value="2">Repeat only to cross-digi frequency</option>
</select>
</div>
<div>
<label for="tx_qrg_bc">TX beacon or from-kiss on frequencies</label>
(Only honored, if we are configured as WIDE1 or WIDE2 digi)
<select id="tx_qrg_bc" name="tx_qrg_bc">
<option value="1">TX on main frequency</option>
<option value="2">TX on secondary frequency</option>
<option value="3">TX on both frequencies</option>
</select>
</div>
</div>
<div class="grid-container full">
<h5 class="u-full-width">APRS-IS settings</h5>
</div>
<div class="grid-container halves">
<div>
<label for="aprsis_en">Enable APRS-IS connection</label>
<input name="aprsis_en" id="aprsis_en" type="checkbox" value="1" title="If we are configured as WIFI client, connet to the APRS-IS net">
</div>
<div>
<label for="aprsis_srv_h">Server Name</label>
<input type="text" name="aprsis_srv_h" id="aprsis_srv_h" title="Server name or IP Address. I.e. euro.aprs2.net">
</div>
<div>
<label for="aprsis_srv_p">TCP Port</label>
<input type="number" name="aprsis_srv_p" id="aprsis_srv_p" min="1" max="65535" title="TCP Port, i.e. 14580">
</div>
<div>
<label for="aprsis_fltr">Filter (optional)</label>
<input type="text" name="aprsis_fltr" id="aprsis_fltr" title="Request server-site filter (may be left empty). See http://www.aprs-is.net/javAPRSFilter.aspx" placeholder="may be left blank">
</div>
<div>
<label for="aprsis_call">Callsign (optional)</label>
<input type="text" name="aprsis_call" id="aprsis_call" minlength="3" maxlength="9" title="Use this callsign for the APRS-IS connection. If not configured, your default callsign is used." placeholder="may be left blank">
</div>
<div>
<label for="aprsis_pw">Password (required)</label>
<input type="password" name="aprsis_pw" id="aprsis_pw" title="Your password for the APRS-IS connection.">
</div>
<div>
<label for="aprsis_2rf">Allow traffic from inet to rf</label>
<input name="aprsis_2rf" id="aprsis_2rf" type="checkbox" value="1" title="Gate APRS-IS traffic to rf (will be encoded in 3rd-party format)">
</div>
<div>
<label for"aprsis_status">Connection status</label>
<input type="text" name="aprsis_status" id="aprsis_status" readonly title="Connection status. Nothing to enter here">
</div>
</div>
<div class="grid-container full">
<div>
<input class="button-primary u-full-width" type="submit" value="Save" title="save settings, remember reboot tracker after save">
@ -208,25 +376,25 @@
<div>
<label for="oled_enabled">OLED Display enabled</label>
<input name="oled_enabled" id="oled_enabled" type="checkbox" value="1" title="Enables or disables OLED">
</div>
</div>
<div>
<label for="bt_enabled">Bluetooth enabled</label>
<input name="bt_enabled" id="bt_enabled" type="checkbox" value="1" title="enable or disable bluetooth">
</div>
</div>
<div>
<label for="led_enable">LED signaling</label>
<input name="led_enable" id="led_enable" type="checkbox" value="1" title="enable or disable LED" DISABLED>
</div>
</div>
<div>
<label for="shutdown_act">Auto power off</label>
<input name="shutdown_act" id="shutdown_act" type="checkbox" value="1" title="activate auto shutdown after usb plug off (not for T-BEAM 0.7)">
</div>
</div>
</div>
</div>
<div class="grid-container quarters">
<div>
<label for="sh_rxtime">Display show RX time [s]</label>
<input name="sh_rxtime" id="sh_rxtime" type="number" min="0" max="45" title="show RX packet for seconds">
</div>
</div>
<div>
<label for="sh_oledtime">Display timeout [s]</label>
<input name="sh_oledtime" id="sh_oledtime" type="number" min="0" max="60" title="Turn OFF OLED after X seconds. Set 0 to disable">
@ -237,16 +405,16 @@
<div>
<label for="shutdown_dt">Auto power off delay [s]</label>
<input name="shutdown_dt" id="shutdown_dt" type="number" min="3" max="3600" title="auto shutdown delay in seconds">
</div>
</div>
</div>
</div>
<div class="grid-container full">
<div>
<input class="button-primary u-full-width" type="submit" value="Save" title="save settings, remember reboot tracker after save">
</div>
</div>
</form>
</form>
</article>
</section>
</section>
<section>
<div class="grid-container full">
<h2 class="u-full-width">Received</h2>
@ -311,12 +479,15 @@
</div>
</form>
</div>
<div class="grid-container full">
Click <a href="/cfg">here</a> to view your configuration.
</div>
</article>
</section>
</div>
<footer>
<center><b>Contributors in order of appearance:</b><br> OE1ACM, OE3CJB, SQ9MDD, SQ5RWU, DJ1AN, M0IGA, SQ5WPR, DO2JMG, SP6VWX, SQ2WB, IU2FRL, DO3BOX, US1GHQ</center>
<center><b>Latest stable version:</b> <a href=https://github.com/SQ9MDD/TTGO-T-Beam-LoRa-APRS>https://github.com/SQ9MDD/TTGO-T-Beam-LoRa-APRS</a></center>
<center><b>Contributors in order of appearance:</b><br> OE1ACM, OE3CJB, SQ9MDD, SQ5RWU, DJ1AN, M0IGA, SQ5WPR, DO2JMG, SP6VWX, SQ2WB, IU2FRL, DO3BOX, DL9SAU</center>
<center><b>Latest stable version:</b> <a href=https://github.com/SQ9MDD/TTGO-T-Beam-LoRa-APRS>https://github.com/SQ9MDD/TTGO-T-Beam-LoRa-APRS</a></center>
<center><b>Licensed under:</b> CC BY-NC-SA</center>
<center><!--VERSION--></center>
</footer>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 172 KiB

After

Width:  |  Height:  |  Size: 148 KiB

@ -10,13 +10,37 @@ extern Preferences preferences;
static const char *const PREF_WIFI_SSID = "wifi_ssid";
static const char *const PREF_WIFI_PASSWORD = "wifi_password";
static const char *const PREF_AP_PASSWORD = "ap_password";
// LoRa settings
static const char *const PREF_LORA_FREQ_PRESET_INIT = "lora_freq_i";
static const char *const PREF_LORA_FREQ_PRESET = "lora_freq";
static const char *const PREF_LORA_SPEED_PRESET_INIT = "lora_speed_i";
static const char *const PREF_LORA_SPEED_PRESET = "lora_speed";
static const char *const PREF_LORA_TX_ENABLE_INIT = "lora_tx_en_i";
static const char *const PREF_LORA_TX_ENABLE = "lora_tx_en";
static const char *const PREF_LORA_TX_POWER_INIT = "txPower_i";
static const char *const PREF_LORA_TX_POWER = "txPower";
static const char *const PREF_LORA_ADD_SNR_RSSI_TO_PATH_PRESET_INIT = "lora_rssi2p_i";
static const char *const PREF_LORA_ADD_SNR_RSSI_TO_PATH_PRESET = "lora_rssi2p";
static const char *const PREF_LORA_ADD_SNR_RSSI_TO_PATH_END_AT_KISS_PRESET_INIT = "snraprsis_i";
static const char *const PREF_LORA_ADD_SNR_RSSI_TO_PATH_END_AT_KISS_PRESET = "snraprsis";
static const char *const PREF_LORA_FREQ_CROSSDIGI_PRESET_INIT = "lora_freq_x_i";
static const char *const PREF_LORA_FREQ_CROSSDIGI_PRESET = "lora_freq_x";
static const char *const PREF_LORA_TX_BEACON_AND_KISS_ON_FREQUENCIES_PRESET_INIT = "tx_qrg_bc_i";
static const char *const PREF_LORA_TX_BEACON_AND_KISS_ON_FREQUENCIES_PRESET = "tx_qrg_bc";
static const char *const PREF_LORA_SPEED_CROSSDIGI_PRESET_INIT = "lora_speed_x_i";
static const char *const PREF_LORA_SPEED_CROSSDIGI_PRESET = "lora_speed_x";
static const char *const PREF_LORA_TX_POWER_CROSSDIGI_PRESET_INIT = "txPower_x_i";
static const char *const PREF_LORA_TX_POWER_CROSSDIGI_PRESET = "txPower_x";
static const char *const PREF_LORA_RX_ON_FREQUENCIES_PRESET_INIT = "rx_qrg_i";
static const char *const PREF_LORA_RX_ON_FREQUENCIES_PRESET = "rx_qrg";
static const char *const PREF_LORA_AUTOMATIC_CR_ADAPTION_PRESET_INIT = "lora_cradapt_i";
static const char *const PREF_LORA_AUTOMATIC_CR_ADAPTION_PRESET = "lora_cradapt";
static const char *const PREF_APRS_DIGIPEATING_MODE_PRESET_INIT = "lora_dig_mode_i";
static const char *const PREF_APRS_DIGIPEATING_MODE_PRESET = "lora_dig_mode";
static const char *const PREF_APRS_CROSS_DIGIPEATING_MODE_PRESET_INIT = "lora_dig_x_m_i";
static const char *const PREF_APRS_CROSS_DIGIPEATING_MODE_PRESET = "lora_dig_x_m";
// Station settings
static const char *const PREF_APRS_CALLSIGN = "aprs_callsign";
static const char *const PREF_APRS_RELAY_PATH = "aprs_relay_path";
@ -25,6 +49,8 @@ static const char *const PREF_APRS_SYMBOL_TABLE = "aprs_s_table";
static const char *const PREF_APRS_SYMBOL = "aprs_symbol";
static const char *const PREF_APRS_COMMENT = "aprs_comment";
static const char *const PREF_APRS_COMMENT_INIT = "aprs_comm_init";
static const char *const PREF_APRS_COMMENT_RATELIMIT_PRESET = "aprs_comm_rt";
static const char *const PREF_APRS_COMMENT_RATELIMIT_PRESET_INIT = "aprs_comm_rt_i";
static const char *const PREF_APRS_SHOW_ALTITUDE = "aprs_alt";
static const char *const PREF_APRS_SHOW_ALTITUDE_INIT = "aprs_alt_init";
static const char *const PREF_APRS_SHOW_BATTERY = "aprs_batt";
@ -47,6 +73,7 @@ static const char *const PREF_TNC_SELF_TELEMETRY_MIC = "tnc_tel_mic";
static const char *const PREF_TNC_SELF_TELEMETRY_MIC_INIT = "tnc_tel_mic_i";
static const char *const PREF_TNC_SELF_TELEMETRY_PATH = "tnc_tel_path";
static const char *const PREF_TNC_SELF_TELEMETRY_PATH_INIT = "tnc_tel_path_i";
// SMART BEACONING
static const char *const PREF_APRS_SB_MIN_INTERVAL_PRESET = "sb_min_interv";
static const char *const PREF_APRS_SB_MIN_INTERVAL_PRESET_INIT = "sb_min_interv_i";
@ -58,10 +85,18 @@ static const char *const PREF_APRS_SB_MAX_SPEED_PRESET = "sb_max_speed";
static const char *const PREF_APRS_SB_MAX_SPEED_PRESET_INIT = "sb_max_speed_i";
static const char *const PREF_APRS_SB_ANGLE_PRESET = "sb_angle";
static const char *const PREF_APRS_SB_ANGLE_PRESET_INIT = "sb_angle_i";
static const char *const PREF_APRS_SB_TURN_SLOPE_PRESET = "sb_turn_slope";
static const char *const PREF_APRS_SB_TURN_SLOPE_PRESET_INIT = "sb_turn_slope_i";
static const char *const PREF_APRS_SB_TURN_TIME_PRESET = "sb_turn_time";
static const char *const PREF_APRS_SB_TURN_TIME_PRESET_INIT = "sb_turn_time_i";
// Device settings
static const char *const PREF_APRS_GPS_EN = "gps_enabled";
static const char *const PREF_APRS_GPS_EN_INIT = "gps_state_init";
static const char *const PREF_ACCEPT_OWN_POSITION_REPORTS_VIA_KISS = "kiss_myloc_ok";
static const char *const PREF_ACCEPT_OWN_POSITION_REPORTS_VIA_KISS_INIT = "kiss_myloc_ok_i";
static const char *const PREF_GPS_ALLOW_SLEEP_WHILE_KISS = "gps_sleep_ok";
static const char *const PREF_GPS_ALLOW_SLEEP_WHILE_KISS_INIT = "gps_sleep_ok_i";
static const char *const PREF_APRS_SHOW_CMT = "show_cmt";
static const char *const PREF_APRS_SHOW_CMT_INIT = "show_cmt_init";
static const char *const PREF_DEV_BT_EN = "bt_enabled";
@ -77,4 +112,20 @@ static const char *const PREF_DEV_AUTO_SHUT_PRESET_INIT = "shutdown_dtini";
static const char *const PREF_DEV_SHOW_OLED_TIME = "sh_oledtime"; // set OLED timeout
static const char *const PREF_DEV_SHOW_OLED_TIME_INIT = "sh_oledtime_i";
// APRSIS settings
static const char *const PREF_APRSIS_EN_INIT = "aprsis_en_i";
static const char *const PREF_APRSIS_EN = "aprsis_en";
static const char *const PREF_APRSIS_SERVER_NAME_INIT = "aprsis_srv_h_i";
static const char *const PREF_APRSIS_SERVER_NAME = "aprsis_srv_h";
static const char *const PREF_APRSIS_SERVER_PORT_INIT = "aprsis_srv_p_i";
static const char *const PREF_APRSIS_SERVER_PORT = "aprsis_srv_p";
static const char *const PREF_APRSIS_FILTER_INIT = "aprsis_fltr_i";
static const char *const PREF_APRSIS_FILTER = "aprsis_fltr";
static const char *const PREF_APRSIS_CALLSIGN_INIT = "aprsis_call_i";
static const char *const PREF_APRSIS_CALLSIGN = "aprsis_call";
static const char *const PREF_APRSIS_PASSWORD_INIT = "aprsis_pw_i";
static const char *const PREF_APRSIS_PASSWORD = "aprsis_pw";
static const char *const PREF_APRSIS_ALLOW_INET_TO_RF_INIT = "aprsis_2rf_i";
static const char *const PREF_APRSIS_ALLOW_INET_TO_RF = "aprsis_2rf";
#endif

@ -1,10 +0,0 @@
#ifndef BUILD_NUMBER
#define BUILD_NUMBER "17"
#endif
#ifndef VERSION
#define VERSION "v0.4.6.17-0a01171 - 2021-12-28 21:20:22.015464"
#endif
#ifndef VERSION_SHORT
#define VERSION_SHORT "v0.4.6.17-0a01171"
#endif

@ -27,6 +27,8 @@ RadioHead/RH_CC110.cpp
RadioHead/RH_CC110.h
RadioHead/RH_E32.cpp
RadioHead/RH_E32.h
RadioHead/RH_LoRaFileOps.cpp
RadioHead/RH_LoRaFileOps.h
RadioHead/RH_NRF24.cpp
RadioHead/RH_NRF24.h
RadioHead/RH_NRF51.cpp
@ -163,6 +165,8 @@ RadioHead/examples/raspi/rf95/rf95_router_server1/rf95_router_server1.cpp
RadioHead/examples/raspi/rf95/rf95_router_server1/Makefile
RadioHead/examples/raspi/rf95/rf95_mesh_server1/Makefile
RadioHead/examples/raspi/rf95/rf95_mesh_server1/rf95_mesh_server1.cpp
RadioHead/examples/lorafileops/lorafileops_client/lorafileops_client.cpp
RadioHead/examples/lorafileops/lorafileops_server/lorafileops_server.cpp
RadioHead/tools/etherSimulator.pl
RadioHead/tools/chain.conf
RadioHead/tools/simMain.cpp

@ -1,12 +0,0 @@
# RadioHead
This is the RadioHead Packet Radio library for embedded microprocessors. It provides a complete object-oriented library for sending and receiving packetized messages via a variety of common data radios and other transports on a range of embedded microprocessors.
The version of the package that this documentation refers to can be downloaded from http://www.airspayce.com/mikem/arduino/RadioHead/RadioHead-1.119.zip You can find the latest version of the documentation at http://www.airspayce.com/mikem/arduino/RadioHead
You can also find online help and discussion at http://groups.google.com/group/radiohead-arduino Please use that group for all questions and discussions on this topic. Do not contact the author directly, unless it is to discuss commercial licensing. Before asking a question or reporting a bug, please read
http://en.wikipedia.org/wiki/Wikipedia:Reference_desk/How_to_ask_a_software_question
http://www.catb.org/esr/faqs/smart-questions.html
http://www.chiark.greenend.org.uk/~shgtatham/bugs.html
Caution: Developing this type of software and using data radios successfully is challenging and requires a substantial knowledge base in software and radio and data transmission technologies and theory. It may not be an appropriate project for beginners. If you are a beginner, you will need to spend some time gaining knowledge in these areas first.

@ -23,6 +23,9 @@ HardwareSPI SPI(1);
#elif (RH_PLATFORM == RH_PLATFORM_STM32L0) && (defined STM32L082xx || defined STM32L072xx)
extern SPIClass radio_spi; // Created in RH_ABZ.cpp
#define SPI radio_spi
#elif (RH_PLATFORM == RH_PLATFORM_ESP32 && defined(RH_ESP32_USE_HSPI))
SPIClass SPI_HSPI(HSPI);
#define SPI SPI_HSPI
#endif
@ -99,11 +102,12 @@ void RHHardwareSPI::begin()
else
frequency = 1000000;
#if ((RH_PLATFORM == RH_PLATFORM_ARDUINO) && defined (__arm__) && (defined(ARDUINO_SAM_DUE) || defined(ARDUINO_ARCH_SAMD))) || defined(ARDUINO_ARCH_NRF52) || defined(ARDUINO_ARCH_STM32) || defined(ARDUINO_ARCH_STM32L0) || defined(NRF52)
#if ((RH_PLATFORM == RH_PLATFORM_ARDUINO) && defined (__arm__) && (defined(ARDUINO_SAM_DUE) || defined(ARDUINO_ARCH_SAMD))) || defined(ARDUINO_ARCH_NRF52) || defined(ARDUINO_ARCH_STM32) || defined(ARDUINO_ARCH_STM32L0) || defined(NRF52) || defined (ARDUINO_ARCH_RP2040)
// Arduino Due in 1.5.5 has its own BitOrder :-(
// So too does Arduino Zero
// So too does rogerclarkmelbourne/Arduino_STM32
// So too does GrumpyOldPizza/ArduinoCore-stm32l0
// So too does GrumpyOldPizza/ArduinoCore-stm32l0
// So too does RPI Pico
::BitOrder bitOrder;
// This no longer relevant: new versions is uint8_t
//#elif (RH_PLATFORM == RH_PLATFORM_ATTINY_MEGA)

@ -11,6 +11,7 @@
#if (RH_PLATFORM == RH_PLATFORM_STM32)
// Maple etc
HardwareTimer timer(MAPLE_TIMER);
#elif defined(ARDUINO_ARCH_RP2040)
#elif defined(BOARD_NAME)
// ST's Arduino Core STM32, https://github.com/stm32duino/Arduino_Core_STM32
@ -125,7 +126,7 @@ bool RH_ASK::init()
// returns 0 & nticks = 0 on fault
uint8_t RH_ASK::timerCalc(uint16_t speed, uint16_t max_ticks, uint16_t *nticks)
{
#if (RH_PLATFORM == RH_PLATFORM_ARDUINO) || (RH_PLATFORM == RH_PLATFORM_GENERIC_AVR8) || (RH_PLATFORM == RH_PLATFORM_ATTINY)
#if (RH_PLATFORM == RH_PLATFORM_ARDUINO && !defined(ARDUINO_ARCH_RP2040)) || (RH_PLATFORM == RH_PLATFORM_GENERIC_AVR8) || (RH_PLATFORM == RH_PLATFORM_ATTINY)
// Clock divider (prescaler) values - 0/3333: error flag
uint8_t prescaler; // index into array & return bit value
unsigned long ulticks; // calculate by ntick overflow
@ -174,6 +175,15 @@ uint8_t RH_ASK::timerCalc(uint16_t speed, uint16_t max_ticks, uint16_t *nticks)
#endif
}
#if defined(RH_PLATFORM_ARDUINO) && defined(ARDUINO_ARCH_RP2040)
void set_pico_alarm(uint32_t speed)
{
uint32_t period = (1000000 / 8) / speed; // In microseconds
uint64_t target = timer_hw->timerawl + period;
timer_hw->alarm[RH_ASK_PICO_ALARM_NUM] = (uint32_t) target;
}
#endif
// The idea here is to get 8 timer interrupts per bit period
void RH_ASK::timerSetup()
{
@ -207,25 +217,25 @@ void RH_ASK::timerSetup()
// Pause the timer while we're configuring it
timer.pause();
#ifdef BOARD_NAME
#ifdef BOARD_NAME
// ST's Arduino Core STM32, https://github.com/stm32duino/Arduino_Core_STM32
// Declaration of the callback function changed in 1.9. Sigh
#if (STM32_CORE_VERSION >= 0x01090000)
#if (STM32_CORE_VERSION >= 0x01090000)
void interrupt();
#else
#else
void interrupt(HardwareTimer*); // defined below
#endif
#endif
uint16_t us=(1000000/8)/_speed;
timer.setMode(1, TIMER_OUTPUT_COMPARE);
timer.setOverflow(us, MICROSEC_FORMAT);
timer.setCaptureCompare(1, us - 1, MICROSEC_COMPARE_FORMAT);
#if (STM32_CORE_VERSION >= 0x01090000)
#if (STM32_CORE_VERSION >= 0x01090000)
timer.attachInterrupt(interrupt);
#else
#else
timer.attachInterrupt(1, interrupt);
#endif
#endif
#else
#else
void interrupt(); // defined below
// Roger Clark Arduino STM32, https://github.com/rogerclarkmelbourne/Arduino_STM32
timer.setPeriod((1000000/8)/_speed);
@ -234,7 +244,7 @@ void RH_ASK::timerSetup()
timer.setCompare(TIMER_CH1, 1); // Interrupt 1 count after each update
void interrupt(); // defined below
timer.attachCompare1Interrupt(interrupt);
#endif
#endif
// Refresh the timer's count, prescale, and overflow
timer.refresh();
@ -333,8 +343,6 @@ void RH_ASK::timerSetup()
timer->CTRLA |= TCB_ENABLE_bm;
#elif (RH_PLATFORM == RH_PLATFORM_ARDUINO) // Arduino specific
uint16_t nticks; // number of prescaled ticks needed
uint8_t prescaler; // Bit values for CS0[2:0]
#if defined(__arm__) && defined(CORE_TEENSY)
@ -408,8 +416,18 @@ void RH_ASK::timerSetup()
NVIC_ClearPendingIRQ(RH_ASK_DUE_TIMER_IRQ);
NVIC_EnableIRQ(RH_ASK_DUE_TIMER_IRQ);
TC_Start(RH_ASK_DUE_TIMER, RH_ASK_DUE_TIMER_CHANNEL);
#elif defined(ARDUINO_ARCH_RP2040)
// Per https://emalliab.wordpress.com/2021/04/18/raspberry-pi-pico-arduino-core-and-timers/
hw_set_bits(&timer_hw->inte, 1u << RH_ASK_PICO_ALARM_NUM);
void picoInterrupt(); // Forward declaration of interrupt handler
irq_set_exclusive_handler(RH_ASK_PICO_ALARM_IRQ, picoInterrupt);
irq_set_enabled(RH_ASK_PICO_ALARM_IRQ, true);
set_pico_alarm(_speed);
#else
uint16_t nticks; // number of prescaled ticks needed
uint8_t prescaler; // Bit values for CS0[2:0]
// This is the path for most Arduinos
// figure out prescaler value and counter match value
#if defined(RH_ASK_ARDUINO_USE_TIMER2)
@ -739,6 +757,15 @@ void TC1_Handler()
TC_GetStatus(RH_ASK_DUE_TIMER, 1);
thisASKDriver->handleTimerInterrupt();
}
#elif (RH_PLATFORM == RH_PLATFORM_ARDUINO) && defined(ARDUINO_ARCH_RP2040)
void picoInterrupt()
{
hw_clear_bits(&timer_hw->intr, 1u << RH_ASK_PICO_ALARM_NUM);
set_pico_alarm(thisASKDriver->speed());
thisASKDriver->handleTimerInterrupt();
}
#elif defined(BOARD_NAME)
// ST's Arduino Core STM32, https://github.com/stm32duino/Arduino_Core_STM32
// Declaration of the callback function changed in 1.9
@ -752,7 +779,7 @@ void interrupt(HardwareTimer*)
{
thisASKDriver->handleTimerInterrupt();
}
#elif (RH_PLATFORM == RH_PLATFORM_ARDUINO) && (defined(ARDUINO_ARCH_STM32) || defined(ARDUINO_ARCH_STM32F1) || defined(ARDUINO_ARCH_STM32F3) || defined(ARDUINO_ARCH_STM32F4))
#elif (RH_PLATFORM == RH_PLATFORM_ARDUINO) && (defined(ARDUINO_ARCH_STM32) || defined(ARDUINO_ARCH_STM32F1) || defined(ARDUINO_ARCH_STM32F3) || defined(ARDUINO_ARCH_STM32F4) || defined(ARDUINO_ARCH_RP2040))
// Roger Clark Arduino STM32, https://github.com/rogerclarkmelbourne/Arduino_STM32
void interrupt()
{

@ -129,7 +129,7 @@ bool RH_CC110::init()
spiWriteRegister(RH_CC110_REG_02_IOCFG0, RH_CC110_GDO_CFG_CRC_OK_AUTORESET); // gdo0 interrupt on CRC_OK
spiWriteRegister(RH_CC110_REG_06_PKTLEN, RH_CC110_MAX_PAYLOAD_LEN); // max packet length
spiWriteRegister(RH_CC110_REG_07_PKTCTRL1, RH_CC110_CRC_AUTOFLUSH); // no append status, crc autoflush, no addr check
spiWriteRegister(RH_CC110_REG_07_PKTCTRL1, RH_CC110_CRC_AUTOFLUSH | RH_CC110_APPEND_STATUS); // append status, crc autoflush, no addr check
spiWriteRegister(RH_CC110_REG_08_PKTCTRL0, RH_CC110_PKT_FORMAT_NORMAL | RH_CC110_CRC_EN | RH_CC110_LENGTH_CONFIG_VARIABLE);
spiWriteRegister(RH_CC110_REG_13_MDMCFG1, RH_CC110_NUM_PREAMBLE_4); // 4 preamble bytes, chan spacing not used
spiWriteRegister(RH_CC110_REG_17_MCSM1, RH_CC110_CCA_MODE_RSSI_PACKET | RH_CC110_RXOFF_MODE_RX | RH_CC110_TXOFF_MODE_IDLE);
@ -163,13 +163,17 @@ void RH_CC110::handleInterrupt()
// Radio is configured to stay in RX until we move it to IDLE after a CRC_OK message for us
// We only get interrupts in RX mode, on CRC_OK
#if 0
// SIGH: reading RH_CC110_REG_34_RSSI here does not yield the RSSI of when the packet was received
// Must get it from the end of the packet read
uint8_t raw_rssi = spiBurstReadRegister(RH_CC110_REG_34_RSSI); // Was set when sync word was detected
// Conversion of RSSI value to received power level in dBm per TI section 5.18.2
if (raw_rssi >= 128)
_lastRssi = (((int16_t)raw_rssi - 256) / 2) - 74;
else
_lastRssi = ((int16_t)raw_rssi / 2) - 74;
#endif
_bufLen = spiReadRegister(RH_CC110_REG_3F_FIFO);
if (_bufLen < 4)
{
@ -178,7 +182,16 @@ void RH_CC110::handleInterrupt()
clearRxBuf();
return;
}
spiBurstRead(RH_CC110_REG_3F_FIFO | RH_CC110_SPI_BURST_MASK | RH_CC110_SPI_READ_MASK, _buf, _bufLen);
// Because we have RH_CC110_APPEND_STATUS set, we can read another 2 octets, the RSSI and the CRC state
spiBurstRead(RH_CC110_REG_3F_FIFO | RH_CC110_SPI_BURST_MASK | RH_CC110_SPI_READ_MASK, _buf, _bufLen + 2);
// And then decode the RSSI
int raw_rssi = _buf[_bufLen];
if (raw_rssi >= 128)
_lastRssi = (((int16_t)raw_rssi - 256) / 2) - 74;
else
_lastRssi = ((int16_t)raw_rssi / 2) - 74;
// All good so far. See if its for us
validateRxBuf();
if (_rxBufValid)

@ -880,7 +880,8 @@ private:
volatile uint8_t _bufLen;
/// The receiver/transmitter buffer
uint8_t _buf[RH_CC110_MAX_PAYLOAD_LEN];
/// Allow for 2 status bytes so we can read packet RSSI
uint8_t _buf[RH_CC110_MAX_PAYLOAD_LEN + 2];
/// True when there is a valid message in the buffer
volatile bool _rxBufValid;

@ -0,0 +1,279 @@
// RH_LoRaFileOpscpp
//
// Copyright (C) 2021 Mike McCauley
#include <RH_LoRaFileOps.h>
// This can only build on Linux and compatible systems
// Caution also requires Lora-file-ops driver to be installed
// See https://github.com/starnight/LoRa/tree/file-ops
#if (RH_PLATFORM == RH_PLATFORM_UNIX)
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/select.h>
RH_LoRaFileOps::RH_LoRaFileOps(const char* port)
:
_port(port),
_fd(-1)
{
}
bool RH_LoRaFileOps::init()
{
if (!RHGenericDriver::init())
return false;
_fd = open(_port, O_RDWR);
if (_fd == -1)
{
Serial.print("RH_LoRaFileOps::init LORA device port open failed: ");
Serial.println(strerror(errno));
return false;
}
// These settings are compatible with RH_RF95::Bw125Cr45Sf2048 and the other defaults
// for RH_RF95
setFrequency(434000000);
setTxPower(13);
setSpreadingFactor(2048);
setBW(125000);
setCRC(true);
setLNA(0);
return true;
}
bool RH_LoRaFileOps::available()
{
// Test if the port can be read
fd_set read_fds;
struct timeval tv = {.tv_sec = 0, .tv_usec = 0};
FD_ZERO(&read_fds);
FD_SET(_fd, &read_fds);
if (select(_fd+1, &read_fds, NULL, NULL, &tv) == -1)
{
Serial.println("Select failed");
return false;
}
return FD_ISSET(_fd, &read_fds) ? true : false;
}
bool RH_LoRaFileOps::recv(uint8_t* buf, uint8_t* len)
{
if (_fd == -1) return false;
if (!available()) return false;
// Read the available packet from the driver
uint8_t readbuf[RH_LORAFILEOPS_MAX_PAYLOAD_LEN];
ssize_t sz;
sz = read(_fd, readbuf, RH_LORAFILEOPS_MAX_PAYLOAD_LEN);
// Remember the last signal to noise ratio, LORA mode
// Per page 111, SX1276/77/78/79 datasheet
_lastSNR = getSNR();
// Remember the RSSI of this packet, LORA mode
// This figure has already been massaged by the driver
_lastRssi = getRSSI();
// Test if its really for us
if (sz < 4)
return false; // Too short to be a real message
// Extract the 4 headers
_rxHeaderTo = readbuf[0];
_rxHeaderFrom = readbuf[1];
_rxHeaderId = readbuf[2];
_rxHeaderFlags = readbuf[3];
if (_promiscuous ||
_rxHeaderTo == _thisAddress ||
_rxHeaderTo == RH_BROADCAST_ADDRESS)
{
// Yes its for us
// Skip the 4 headers that are at the beginning of the rxBuf
if (*len > (sz - RH_LORAFILEOPS_HEADER_LEN))
*len = sz - RH_LORAFILEOPS_HEADER_LEN;
memcpy(buf, readbuf + RH_LORAFILEOPS_HEADER_LEN, *len);
Serial.println("recv OK");
return true;
}
// Not for us
return false;
}
bool RH_LoRaFileOps::send(const uint8_t* data, uint8_t len)
{
if (_fd == -1) return false;
if (len > RH_LORAFILEOPS_MAX_MESSAGE_LEN)
return false;
// Should never need to wait for a packet to be sent since the driver always
// waits before returning from write
// Assemble the entire message, including RadioHead header
// Header bytes, total size of RH_LORAFILEOPS_HEADER_LEN
uint8_t buf[RH_LORAFILEOPS_MAX_PAYLOAD_LEN];
buf[0] = _txHeaderTo;
buf[1] = _txHeaderFrom;
buf[2] = _txHeaderId;
buf[3] = _txHeaderFlags;
memcpy(buf+4, data, len);
// Send the message to the driver
ssize_t sz;
// Returns when the packet has been transmtted:
sz = write(_fd, buf, len+RH_LORAFILEOPS_HEADER_LEN);
return sz == len+RH_LORAFILEOPS_HEADER_LEN;
}
uint8_t RH_LoRaFileOps::maxMessageLength()
{
return RH_LORAFILEOPS_MAX_MESSAGE_LEN;
}
bool RH_LoRaFileOps::setFrequency(uint32_t centre)
{
if (_fd == -1) return false;
ioctl(_fd, LORA_SET_FREQUENCY, &centre);
return true; // FIXME??
}
uint32_t RH_LoRaFileOps::getFrequency()
{
if (_fd == -1) return 0;
uint32_t freq;
ioctl(_fd, LORA_GET_FREQUENCY, &freq);
return freq;
}
void RH_LoRaFileOps::setTxPower(int32_t power)
{
if (_fd == -1) return;
ioctl(_fd, LORA_SET_POWER, &power);
}
int32_t RH_LoRaFileOps::getTxPower()
{
if (_fd == -1) return 0;
int32_t power;
ioctl(_fd, LORA_GET_POWER, &power);
return power;
}
void RH_LoRaFileOps::setState(uint32_t state)
{
if (_fd == -1) return;
ioctl(_fd, LORA_SET_STATE, &state);
}
uint32_t RH_LoRaFileOps::getState()
{
if (_fd == -1) return LORA_STATE_SLEEP;
uint32_t state;
ioctl(_fd, LORA_GET_STATE, &state);
return state;
}
void RH_LoRaFileOps::setSpreadingFactor(int32_t sf)
{
ioctl(_fd, LORA_SET_SPRFACTOR, &sf);
}
int32_t RH_LoRaFileOps::getSpreadingFactor()
{
if (_fd == -1) return 0;
uint32_t sprf;
ioctl(_fd, LORA_GET_SPRFACTOR, &sprf);
return sprf;
}
// This gets the raw RSSI figure. Its not adjusted to dBm
int32_t RH_LoRaFileOps::getRSSI()
{
if (_fd == -1) return 0;
int32_t rssi;
ioctl(_fd, LORA_GET_RSSI, &rssi);
return rssi;
}
// Last packet SNR
int32_t RH_LoRaFileOps::getSNR()
{
if (_fd == -1) return 0;
int32_t snr;
ioctl(_fd, LORA_GET_SNR, &snr);
return snr;
}
void RH_LoRaFileOps::setLNA(int32_t lna)
{
if (_fd == -1) return;
ioctl(_fd, LORA_SET_LNA, &lna);
}
int32_t RH_LoRaFileOps::getLNA()
{
if (_fd == -1) return 0;
int32_t lna;
ioctl(_fd, LORA_GET_LNA, &lna);
return lna;
}
void RH_LoRaFileOps::setLNAAGC(int32_t lnaagc)
{
if (_fd == -1) return;
ioctl(_fd, LORA_SET_LNAAGC, &lnaagc);
}
void RH_LoRaFileOps::setBW(int32_t bw)
{
if (_fd == -1) return;
ioctl(_fd, LORA_SET_BANDWIDTH, &bw);
}
int32_t RH_LoRaFileOps::getBW()
{
if (_fd == -1) return 0;
uint32_t bw;
ioctl(_fd, LORA_GET_BANDWIDTH, &bw);
return bw;
}
void RH_LoRaFileOps::setCRC(uint32_t crc)
{
if (_fd == -1) return;
ioctl(_fd, LORA_SET_CRC, &crc);
}
int RH_LoRaFileOps::lastSNR()
{
return _lastSNR;
}
#endif

@ -0,0 +1,368 @@
// RH_LoRaFileOps.h
//
// Definitions for RadioHead driver on RPi+Linux
// and using LoRa-file-ops Linux driver ioctls to
// transmit and receive RadioHead compatible messages via SX1276/77/78/79
// and compatible radios.
// Requires a modified version of LoRa-file-ops driver to be installed,
// and a compatible radio to be connected
// appropriately
// https://github.com/starnight/LoRa/tree/file-ops
//
// Tested with:
// RPi 2 + Debian 2021-03-04 (kernel 5.10.17-v7+ #1403)
// Dragino LoRa/GPS HAT, https://wiki.dragino.com/index.php?title=Lora/GPS_HAT
// modified so RFM95 pin 5 NSS was no longer connected to RPi
// pin P1-22 (GPIO6), but is instead connected to RPi Pin P1-24 (CE0) which
// is the one used by /dev/loraSPI0.0
//
// Author: Mike McCauley (mikem@airspayce.com)
// Copyright (C) 2021 Mike McCauley
//
#ifndef RH_LORAFILEOPS_h
#define RH_LORAFILEOPS_h
#include <RHGenericDriver.h>
#warning RH_LoRaFileOps unfinished
// This can only build on Linux and compatible systems
// Caution also requires Lora-file-ops driver to be installed
// See https://github.com/starnight/LoRa/tree/file-ops
#if (RH_PLATFORM == RH_PLATFORM_UNIX) || defined(DOXYGEN)
// Driver constant definitions
// These are copied from LoRa file-ops branch pull request #16
// See the instructions in the RH_LoRaFileOps documentation for getting that version from github
// which is absolutely necessary if you want to support RadioHead messages with CRC enabled,
// which we strongly recommend.
// since they are not necessarily available in the compile host file
// system.
// CAUTION: these must be kept in sync with LoRa-file-ops if it changes
/* I/O control by each command. */
#include <sys/ioctl.h>
#define LORA_IOC_MAGIC '\x74'
#define LORA_SET_STATE (_IOW(LORA_IOC_MAGIC, 0, int))
#define LORA_GET_STATE (_IOR(LORA_IOC_MAGIC, 1, int))
#define LORA_SET_FREQUENCY (_IOW(LORA_IOC_MAGIC, 2, int))
#define LORA_GET_FREQUENCY (_IOR(LORA_IOC_MAGIC, 3, int))
#define LORA_SET_POWER (_IOW(LORA_IOC_MAGIC, 4, int))
#define LORA_GET_POWER (_IOR(LORA_IOC_MAGIC, 5, int))
#define LORA_SET_LNA (_IOW(LORA_IOC_MAGIC, 6, int))
#define LORA_GET_LNA (_IOR(LORA_IOC_MAGIC, 7, int))
#define LORA_SET_LNAAGC (_IOR(LORA_IOC_MAGIC, 8, int))
#define LORA_SET_SPRFACTOR (_IOW(LORA_IOC_MAGIC, 9, int))
#define LORA_GET_SPRFACTOR (_IOR(LORA_IOC_MAGIC, 10, int))
#define LORA_SET_BANDWIDTH (_IOW(LORA_IOC_MAGIC, 11, int))
#define LORA_GET_BANDWIDTH (_IOR(LORA_IOC_MAGIC, 12, int))
#define LORA_GET_RSSI (_IOR(LORA_IOC_MAGIC, 13, int))
#define LORA_GET_SNR (_IOR(LORA_IOC_MAGIC, 14, int))
/* Mikem added 2021-04-19 fro pull request 16: */
#define LORA_SET_CRC (_IOW(LORA_IOC_MAGIC, 15, int))
#define LORA_SET_CODINGRATE (_IOW(LORA_IOC_MAGIC, 16, int))
#define LORA_GET_CODINGRATE (_IOR(LORA_IOC_MAGIC, 17, int))
#define LORA_SET_IMPLICIT (_IOW(LORA_IOC_MAGIC, 18, int))
#define LORA_SET_LDRO (_IOW(LORA_IOC_MAGIC, 19, int))
#define LORA_SET_PREAMBLE (_IOW(LORA_IOC_MAGIC, 20, int))
#define LORA_GET_PREAMBLE (_IOR(LORA_IOC_MAGIC, 21, int))
#define LORA_SET_PARAMP (_IOW(LORA_IOC_MAGIC, 22, int))
#define LORA_GET_PARAMP (_IOR(LORA_IOC_MAGIC, 23, int))
#define LORA_SET_OCPIMAX (_IOW(LORA_IOC_MAGIC, 24, int))
#define LORA_GET_OCPIMAX (_IOR(LORA_IOC_MAGIC, 25, int))
#define LORA_SET_LNABOOSTHF (_IOW(LORA_IOC_MAGIC, 26, int))
#define LORA_SET_PMAX20DBM (_IOW(LORA_IOC_MAGIC, 27, int))
/* List the state of the LoRa device. */
#define LORA_STATE_SLEEP 0
#define LORA_STATE_STANDBY 1
#define LORA_STATE_TX 2
#define LORA_STATE_RX 3
#define LORA_STATE_CAD 4
// Max number of octets the SX1278 LORA Rx/Tx FIFO can hold
#define RH_LORAFILEOPS_FIFO_SIZE 255
// This is the maximum number of bytes that can be carried by the LORA.
// We use some for headers, keeping fewer for RadioHead messages
#define RH_LORAFILEOPS_MAX_PAYLOAD_LEN RH_LORAFILEOPS_FIFO_SIZE
// The length of the headers we add.
// The headers are inside the LORA's payload
#define RH_LORAFILEOPS_HEADER_LEN 4
// This is the maximum message length that can be supported by this driver.
// Can be pre-defined to a smaller size (to save SRAM) prior to including this header
// Here we allow for 1 byte message length, 4 bytes headers, user data and 2 bytes of FCS
#ifndef RH_LORAFILEOPS_MAX_MESSAGE_LEN
#define RH_LORAFILEOPS_MAX_MESSAGE_LEN (RH_LORAFILEOPS_MAX_PAYLOAD_LEN - RH_LORAFILEOPS_HEADER_LEN)
#endif
/////////////////////////////////////////////////////////////////////
/// \class RH_LoRaFileOps RH_LoRaFileOps.h <RH_LoRaFileOps.h>
/// \brief Driver to send and receive unaddressed, unreliable datagrams via a LoRa
/// capable radio transceiver on a Linux platform (possibly Raspberry Pi), using the
/// lora-file-ops driver by Jian-Hong Pan (starnight):
/// https://github.com/starnight/LoRa/tree/file-ops
///
/// This RadioHead driver is only available to Commercial licensees. Apply to info@airspayce.com.
///
/// For an excellent discussion of LoRa range and modulations, see
/// https://medium.com/home-wireless/testing-lora-radios-with-the-limesdr-mini-part-2-37fa481217ff
/// Works with Dragino LoRa/GPS HAT, https://wiki.dragino.com/index.php?title=Lora/GPS_HAT
/// modified so RFM95 pin 5 NSS was no longer connected to RPi
/// pin P1-22 (GPIO6), but is instead connected to RPi Pin P1-24 (CE0) which
/// is the one used by /dev/loraSPI0.0. Interoperates with RH_RF95
/// with modem config RH_RF95::Bw125Cr45Sf2048
///
/// \par Overview
///
/// This class provides basic functions for sending and receiving unaddressed,
/// unreliable datagrams of arbitrary length up to 251 octets per packet.
///
/// Manager classes may use this class to implement reliable, addressed datagrams and streams,
/// mesh routers, repeaters, translators etc.
///
/// Naturally, for any 2 radios to communicate that must be configured to use the same frequency and
/// modulation scheme.
///
/// This RadioHead Driver provides an object-oriented interface for sending and receiving
/// data messages with Semtech SX1276/77/78/79
/// and compatible radio modules in LoRa mode, using the lora-file-ops Linux driver. It only runs on Linux
/// such as Raspberry Pi Debian etc.is a low-cost ISM transceiver
/// chip. It supports FSK, GFSK, OOK over a wide range of frequencies and
/// programmable data rates, and it also supports the proprietary LoRA (Long Range) mode, which
/// is the only mode supported in this RadioHead driver (because that is the only mode supported by the
/// underlying lora-file-ops Linux driver.
///
/// This Driver provides functions for sending and receiving messages of up
/// to 251 octets on any frequency supported by the radio, in a range of
/// predefined Bandwidths, Spreading Factors and Coding Rates. Frequency can be set with
/// 61Hz precision to any frequency from 240.0MHz to 960.0MHz. Caution: most modules only support a more limited
/// range of frequencies due to antenna tuning.
///
/// Up to 2 modules are supported by lora-file-ops
/// permitting the construction of translators and frequency changers, etc.
///
/// Support for other features such as transmitter power control etc is
/// also provided.
///
/// Tested with:
/// RPi 2 + Debian 2021-03-04 (kernel 5.10.17-v7+ #1403)
/// Dragino LoRa/GPS HAT, https://wiki.dragino.com/index.php?title=Lora/GPS_HAT
/// modified so RFM95 pin 5 NSS was no longer connected to RPi
/// pin P1-22 (GPIO6), but is instead connected to RPi Pin P1-24 (CE0) which
/// is the one used by /dev/loraSPI0.0
/// \par Packet Format
///
/// All messages sent and received by this RH_RF95 Driver conform to this packet format:
///
/// - LoRa mode:
/// - 8 symbol PREAMBLE
/// - Explicit header with header CRC (default CCITT, handled internally by the radio)
/// - 4 octets HEADER: (TO, FROM, ID, FLAGS)
/// - 0 to 251 octets DATA
/// - CRC (default CCITT, handled internally by the radio)
///
/// This format is compatible with the one used by RH_RF95 by default.
///
/// \par Modulation
///
/// The default modulation scheme implemented by this driver is:
/// 434.0MHz, 13dBm, Bw = 125 kHz, Cr = 4/5, Sf = 128chips/symbol, CRC on
/// which is compatible withthe RH_RF95 modem config RH_RF95::Bw125Cr45Sf2048 and so this RadioHead driver will
/// interoperate with RH_RF95.
///
/// \par Installing lora-file-ops
/// For this driver to work on a Linux platform such as Raspberry Pi, it is absolutely necessary to install the
/// LoRa-file-ops Linux driver written by starnight, and which is available from github.
/// The version currently available (2021-04-19) does not support enabling CRCs in the radio, which is
/// strongly recommended, and necessary to work with any other RadioHead lora driver/
/// At this date, code to add CRC suport to the driver is avalable as a pull request on github
/// as a Git pull request #16 from flyskywhy. We strongly recommend using it as described below.
///
/// To get LoRa-file-ops from starnight, plus the necessary patches and fixes from pull request #16 from flyskywhy
/// and to build it and install it and load it into the kernel for testing:
/// \code
/// # ON a recent Debian kernel:
/// sudo apt-get install linux-headers-rpi raspberrypi-kernel-headers
/// # Enable the SPI interface in the kernel
/// sudo raspi-config:
/// -> 3 Interface Options
/// -> P4 SPI
/// -> Would you like the SPI interface to be enabled? select Yes, press Return, Return, Select Finish
/// # in a working directory, not as root:
/// git clone https://github.com/starnight/LoRa.git
/// cd LoRa/
/// git checkout file-ops
/// git fetch origin pull/16/head:file-ops-patched # only until pull #16 is not merged into master
/// git checkout file-ops-patched # only until pull #16 is not merged into master
/// cd LoRa/
/// make
/// make install
/// cd ../dts-overlay
/// make
/// cd ../
/// # and after every reboot:
/// sudo dtoverlay rpi-lora-spi
/// sudo modprobe sx1278
/// \endcode
///
/// If you want to permanently add the LoRa-file-ops Linux driver so it loads automatically
/// on every boot, add this to /boot/config.txt
/// \code
/// dtparam=rpi-lora-spi=on
/// \endcode
///
/// Note: it may be the case in the future that pull request 16 is merged into the master of LoRa-File-Ops
/// in which case 2 steps are not needed above
class RH_LoRaFileOps : public RHGenericDriver
{
public:
/// Constructor. You can have multiple instances each connected to a different LoRa port
/// \param[in] port Name of the lora-file-ops port, typically something like /dev/loraSPI0.0
RH_LoRaFileOps(const char* port);
/// Initialise the Driver transport hardware and software.
/// Opens the LorFileOps driver port and initalises the radio to default settings
/// Leaves the radio in receive mode,
/// with default configuration of: 434.0MHz, 13dBm, Bw = 125 kHz, Cr = 4/5, Sf = 2048chips/symbol, CRC on
/// which is compatible with RH_RF95::Bw125Cr45Sf2048
/// \return true if initialisation succeeded.