RadioHead
RH_RF95.h@0:e69d086cb053, 2017-06-11 (annotated)
- Committer:
- danjulio
- Date:
- Sun Jun 11 04:05:05 2017 +0000
- Revision:
- 0:e69d086cb053
Initial commit of minimally ported Radiohead library using swspi
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
danjulio | 0:e69d086cb053 | 1 | // RH_RF95.h |
danjulio | 0:e69d086cb053 | 2 | // |
danjulio | 0:e69d086cb053 | 3 | // Definitions for HopeRF LoRa radios per: |
danjulio | 0:e69d086cb053 | 4 | // http://www.hoperf.com/upload/rf/RFM95_96_97_98W.pdf |
danjulio | 0:e69d086cb053 | 5 | // http://www.hoperf.cn/upload/rfchip/RF96_97_98.pdf |
danjulio | 0:e69d086cb053 | 6 | // |
danjulio | 0:e69d086cb053 | 7 | // Author: Mike McCauley (mikem@airspayce.com) |
danjulio | 0:e69d086cb053 | 8 | // Copyright (C) 2014 Mike McCauley |
danjulio | 0:e69d086cb053 | 9 | // $Id: RH_RF95.h,v 1.16 2017/03/04 00:59:41 mikem Exp $ |
danjulio | 0:e69d086cb053 | 10 | // |
danjulio | 0:e69d086cb053 | 11 | // Ported to mbed - support only a single radio - Dan Julio - 5/2017 |
danjulio | 0:e69d086cb053 | 12 | // |
danjulio | 0:e69d086cb053 | 13 | |
danjulio | 0:e69d086cb053 | 14 | #ifndef RH_RF95_h |
danjulio | 0:e69d086cb053 | 15 | #define RH_RF95_h |
danjulio | 0:e69d086cb053 | 16 | |
danjulio | 0:e69d086cb053 | 17 | #include <RHGenericDriver.h> |
danjulio | 0:e69d086cb053 | 18 | #include "swspi.h" |
danjulio | 0:e69d086cb053 | 19 | |
danjulio | 0:e69d086cb053 | 20 | // Max number of octets the LORA Rx/Tx FIFO can hold |
danjulio | 0:e69d086cb053 | 21 | #define RH_RF95_FIFO_SIZE 255 |
danjulio | 0:e69d086cb053 | 22 | |
danjulio | 0:e69d086cb053 | 23 | // This is the maximum number of bytes that can be carried by the LORA. |
danjulio | 0:e69d086cb053 | 24 | // We use some for headers, keeping fewer for RadioHead messages |
danjulio | 0:e69d086cb053 | 25 | #define RH_RF95_MAX_PAYLOAD_LEN RH_RF95_FIFO_SIZE |
danjulio | 0:e69d086cb053 | 26 | |
danjulio | 0:e69d086cb053 | 27 | // The length of the headers we add. |
danjulio | 0:e69d086cb053 | 28 | // The headers are inside the LORA's payload |
danjulio | 0:e69d086cb053 | 29 | #define RH_RF95_HEADER_LEN 4 |
danjulio | 0:e69d086cb053 | 30 | |
danjulio | 0:e69d086cb053 | 31 | // This is the maximum message length that can be supported by this driver. |
danjulio | 0:e69d086cb053 | 32 | // Can be pre-defined to a smaller size (to save SRAM) prior to including this header |
danjulio | 0:e69d086cb053 | 33 | // Here we allow for 1 byte message length, 4 bytes headers, user data and 2 bytes of FCS |
danjulio | 0:e69d086cb053 | 34 | #ifndef RH_RF95_MAX_MESSAGE_LEN |
danjulio | 0:e69d086cb053 | 35 | #define RH_RF95_MAX_MESSAGE_LEN (RH_RF95_MAX_PAYLOAD_LEN - RH_RF95_HEADER_LEN) |
danjulio | 0:e69d086cb053 | 36 | #endif |
danjulio | 0:e69d086cb053 | 37 | |
danjulio | 0:e69d086cb053 | 38 | // The crystal oscillator frequency of the module |
danjulio | 0:e69d086cb053 | 39 | #define RH_RF95_FXOSC 32000000.0 |
danjulio | 0:e69d086cb053 | 40 | |
danjulio | 0:e69d086cb053 | 41 | // The Frequency Synthesizer step = RH_RF95_FXOSC / 2^^19 |
danjulio | 0:e69d086cb053 | 42 | #define RH_RF95_FSTEP (RH_RF95_FXOSC / 524288) |
danjulio | 0:e69d086cb053 | 43 | |
danjulio | 0:e69d086cb053 | 44 | |
danjulio | 0:e69d086cb053 | 45 | // Register names (LoRa Mode, from table 85) |
danjulio | 0:e69d086cb053 | 46 | #define RH_RF95_REG_00_FIFO 0x00 |
danjulio | 0:e69d086cb053 | 47 | #define RH_RF95_REG_01_OP_MODE 0x01 |
danjulio | 0:e69d086cb053 | 48 | #define RH_RF95_REG_02_RESERVED 0x02 |
danjulio | 0:e69d086cb053 | 49 | #define RH_RF95_REG_03_RESERVED 0x03 |
danjulio | 0:e69d086cb053 | 50 | #define RH_RF95_REG_04_RESERVED 0x04 |
danjulio | 0:e69d086cb053 | 51 | #define RH_RF95_REG_05_RESERVED 0x05 |
danjulio | 0:e69d086cb053 | 52 | #define RH_RF95_REG_06_FRF_MSB 0x06 |
danjulio | 0:e69d086cb053 | 53 | #define RH_RF95_REG_07_FRF_MID 0x07 |
danjulio | 0:e69d086cb053 | 54 | #define RH_RF95_REG_08_FRF_LSB 0x08 |
danjulio | 0:e69d086cb053 | 55 | #define RH_RF95_REG_09_PA_CONFIG 0x09 |
danjulio | 0:e69d086cb053 | 56 | #define RH_RF95_REG_0A_PA_RAMP 0x0a |
danjulio | 0:e69d086cb053 | 57 | #define RH_RF95_REG_0B_OCP 0x0b |
danjulio | 0:e69d086cb053 | 58 | #define RH_RF95_REG_0C_LNA 0x0c |
danjulio | 0:e69d086cb053 | 59 | #define RH_RF95_REG_0D_FIFO_ADDR_PTR 0x0d |
danjulio | 0:e69d086cb053 | 60 | #define RH_RF95_REG_0E_FIFO_TX_BASE_ADDR 0x0e |
danjulio | 0:e69d086cb053 | 61 | #define RH_RF95_REG_0F_FIFO_RX_BASE_ADDR 0x0f |
danjulio | 0:e69d086cb053 | 62 | #define RH_RF95_REG_10_FIFO_RX_CURRENT_ADDR 0x10 |
danjulio | 0:e69d086cb053 | 63 | #define RH_RF95_REG_11_IRQ_FLAGS_MASK 0x11 |
danjulio | 0:e69d086cb053 | 64 | #define RH_RF95_REG_12_IRQ_FLAGS 0x12 |
danjulio | 0:e69d086cb053 | 65 | #define RH_RF95_REG_13_RX_NB_BYTES 0x13 |
danjulio | 0:e69d086cb053 | 66 | #define RH_RF95_REG_14_RX_HEADER_CNT_VALUE_MSB 0x14 |
danjulio | 0:e69d086cb053 | 67 | #define RH_RF95_REG_15_RX_HEADER_CNT_VALUE_LSB 0x15 |
danjulio | 0:e69d086cb053 | 68 | #define RH_RF95_REG_16_RX_PACKET_CNT_VALUE_MSB 0x16 |
danjulio | 0:e69d086cb053 | 69 | #define RH_RF95_REG_17_RX_PACKET_CNT_VALUE_LSB 0x17 |
danjulio | 0:e69d086cb053 | 70 | #define RH_RF95_REG_18_MODEM_STAT 0x18 |
danjulio | 0:e69d086cb053 | 71 | #define RH_RF95_REG_19_PKT_SNR_VALUE 0x19 |
danjulio | 0:e69d086cb053 | 72 | #define RH_RF95_REG_1A_PKT_RSSI_VALUE 0x1a |
danjulio | 0:e69d086cb053 | 73 | #define RH_RF95_REG_1B_RSSI_VALUE 0x1b |
danjulio | 0:e69d086cb053 | 74 | #define RH_RF95_REG_1C_HOP_CHANNEL 0x1c |
danjulio | 0:e69d086cb053 | 75 | #define RH_RF95_REG_1D_MODEM_CONFIG1 0x1d |
danjulio | 0:e69d086cb053 | 76 | #define RH_RF95_REG_1E_MODEM_CONFIG2 0x1e |
danjulio | 0:e69d086cb053 | 77 | #define RH_RF95_REG_1F_SYMB_TIMEOUT_LSB 0x1f |
danjulio | 0:e69d086cb053 | 78 | #define RH_RF95_REG_20_PREAMBLE_MSB 0x20 |
danjulio | 0:e69d086cb053 | 79 | #define RH_RF95_REG_21_PREAMBLE_LSB 0x21 |
danjulio | 0:e69d086cb053 | 80 | #define RH_RF95_REG_22_PAYLOAD_LENGTH 0x22 |
danjulio | 0:e69d086cb053 | 81 | #define RH_RF95_REG_23_MAX_PAYLOAD_LENGTH 0x23 |
danjulio | 0:e69d086cb053 | 82 | #define RH_RF95_REG_24_HOP_PERIOD 0x24 |
danjulio | 0:e69d086cb053 | 83 | #define RH_RF95_REG_25_FIFO_RX_BYTE_ADDR 0x25 |
danjulio | 0:e69d086cb053 | 84 | #define RH_RF95_REG_26_MODEM_CONFIG3 0x26 |
danjulio | 0:e69d086cb053 | 85 | |
danjulio | 0:e69d086cb053 | 86 | #define RH_RF95_REG_27_PPM_CORRECTION 0x27 |
danjulio | 0:e69d086cb053 | 87 | #define RH_RF95_REG_28_FEI_MSB 0x28 |
danjulio | 0:e69d086cb053 | 88 | #define RH_RF95_REG_29_FEI_MID 0x29 |
danjulio | 0:e69d086cb053 | 89 | #define RH_RF95_REG_2A_FEI_LSB 0x2a |
danjulio | 0:e69d086cb053 | 90 | #define RH_RF95_REG_2C_RSSI_WIDEBAND 0x2c |
danjulio | 0:e69d086cb053 | 91 | #define RH_RF95_REG_31_DETECT_OPTIMIZ 0x31 |
danjulio | 0:e69d086cb053 | 92 | #define RH_RF95_REG_33_INVERT_IQ 0x33 |
danjulio | 0:e69d086cb053 | 93 | #define RH_RF95_REG_37_DETECTION_THRESHOLD 0x37 |
danjulio | 0:e69d086cb053 | 94 | #define RH_RF95_REG_39_SYNC_WORD 0x39 |
danjulio | 0:e69d086cb053 | 95 | |
danjulio | 0:e69d086cb053 | 96 | #define RH_RF95_REG_40_DIO_MAPPING1 0x40 |
danjulio | 0:e69d086cb053 | 97 | #define RH_RF95_REG_41_DIO_MAPPING2 0x41 |
danjulio | 0:e69d086cb053 | 98 | #define RH_RF95_REG_42_VERSION 0x42 |
danjulio | 0:e69d086cb053 | 99 | |
danjulio | 0:e69d086cb053 | 100 | #define RH_RF95_REG_4B_TCXO 0x4b |
danjulio | 0:e69d086cb053 | 101 | #define RH_RF95_REG_4D_PA_DAC 0x4d |
danjulio | 0:e69d086cb053 | 102 | #define RH_RF95_REG_5B_FORMER_TEMP 0x5b |
danjulio | 0:e69d086cb053 | 103 | #define RH_RF95_REG_61_AGC_REF 0x61 |
danjulio | 0:e69d086cb053 | 104 | #define RH_RF95_REG_62_AGC_THRESH1 0x62 |
danjulio | 0:e69d086cb053 | 105 | #define RH_RF95_REG_63_AGC_THRESH2 0x63 |
danjulio | 0:e69d086cb053 | 106 | #define RH_RF95_REG_64_AGC_THRESH3 0x64 |
danjulio | 0:e69d086cb053 | 107 | |
danjulio | 0:e69d086cb053 | 108 | // RH_RF95_REG_01_OP_MODE 0x01 |
danjulio | 0:e69d086cb053 | 109 | #define RH_RF95_LONG_RANGE_MODE 0x80 |
danjulio | 0:e69d086cb053 | 110 | #define RH_RF95_ACCESS_SHARED_REG 0x40 |
danjulio | 0:e69d086cb053 | 111 | #define RH_RF95_LOW_FREQUENCY_MODE 0x08 |
danjulio | 0:e69d086cb053 | 112 | #define RH_RF95_MODE 0x07 |
danjulio | 0:e69d086cb053 | 113 | #define RH_RF95_MODE_SLEEP 0x00 |
danjulio | 0:e69d086cb053 | 114 | #define RH_RF95_MODE_STDBY 0x01 |
danjulio | 0:e69d086cb053 | 115 | #define RH_RF95_MODE_FSTX 0x02 |
danjulio | 0:e69d086cb053 | 116 | #define RH_RF95_MODE_TX 0x03 |
danjulio | 0:e69d086cb053 | 117 | #define RH_RF95_MODE_FSRX 0x04 |
danjulio | 0:e69d086cb053 | 118 | #define RH_RF95_MODE_RXCONTINUOUS 0x05 |
danjulio | 0:e69d086cb053 | 119 | #define RH_RF95_MODE_RXSINGLE 0x06 |
danjulio | 0:e69d086cb053 | 120 | #define RH_RF95_MODE_CAD 0x07 |
danjulio | 0:e69d086cb053 | 121 | |
danjulio | 0:e69d086cb053 | 122 | // RH_RF95_REG_09_PA_CONFIG 0x09 |
danjulio | 0:e69d086cb053 | 123 | #define RH_RF95_PA_SELECT 0x80 |
danjulio | 0:e69d086cb053 | 124 | #define RH_RF95_MAX_POWER 0x70 |
danjulio | 0:e69d086cb053 | 125 | #define RH_RF95_OUTPUT_POWER 0x0f |
danjulio | 0:e69d086cb053 | 126 | |
danjulio | 0:e69d086cb053 | 127 | // RH_RF95_REG_0A_PA_RAMP 0x0a |
danjulio | 0:e69d086cb053 | 128 | #define RH_RF95_LOW_PN_TX_PLL_OFF 0x10 |
danjulio | 0:e69d086cb053 | 129 | #define RH_RF95_PA_RAMP 0x0f |
danjulio | 0:e69d086cb053 | 130 | #define RH_RF95_PA_RAMP_3_4MS 0x00 |
danjulio | 0:e69d086cb053 | 131 | #define RH_RF95_PA_RAMP_2MS 0x01 |
danjulio | 0:e69d086cb053 | 132 | #define RH_RF95_PA_RAMP_1MS 0x02 |
danjulio | 0:e69d086cb053 | 133 | #define RH_RF95_PA_RAMP_500US 0x03 |
danjulio | 0:e69d086cb053 | 134 | #define RH_RF95_PA_RAMP_250US 0x0 |
danjulio | 0:e69d086cb053 | 135 | #define RH_RF95_PA_RAMP_125US 0x05 |
danjulio | 0:e69d086cb053 | 136 | #define RH_RF95_PA_RAMP_100US 0x06 |
danjulio | 0:e69d086cb053 | 137 | #define RH_RF95_PA_RAMP_62US 0x07 |
danjulio | 0:e69d086cb053 | 138 | #define RH_RF95_PA_RAMP_50US 0x08 |
danjulio | 0:e69d086cb053 | 139 | #define RH_RF95_PA_RAMP_40US 0x09 |
danjulio | 0:e69d086cb053 | 140 | #define RH_RF95_PA_RAMP_31US 0x0a |
danjulio | 0:e69d086cb053 | 141 | #define RH_RF95_PA_RAMP_25US 0x0b |
danjulio | 0:e69d086cb053 | 142 | #define RH_RF95_PA_RAMP_20US 0x0c |
danjulio | 0:e69d086cb053 | 143 | #define RH_RF95_PA_RAMP_15US 0x0d |
danjulio | 0:e69d086cb053 | 144 | #define RH_RF95_PA_RAMP_12US 0x0e |
danjulio | 0:e69d086cb053 | 145 | #define RH_RF95_PA_RAMP_10US 0x0f |
danjulio | 0:e69d086cb053 | 146 | |
danjulio | 0:e69d086cb053 | 147 | // RH_RF95_REG_0B_OCP 0x0b |
danjulio | 0:e69d086cb053 | 148 | #define RH_RF95_OCP_ON 0x20 |
danjulio | 0:e69d086cb053 | 149 | #define RH_RF95_OCP_TRIM 0x1f |
danjulio | 0:e69d086cb053 | 150 | |
danjulio | 0:e69d086cb053 | 151 | // RH_RF95_REG_0C_LNA 0x0c |
danjulio | 0:e69d086cb053 | 152 | #define RH_RF95_LNA_GAIN 0xe0 |
danjulio | 0:e69d086cb053 | 153 | #define RH_RF95_LNA_GAIN_G1 0x20 |
danjulio | 0:e69d086cb053 | 154 | #define RH_RF95_LNA_GAIN_G2 0x40 |
danjulio | 0:e69d086cb053 | 155 | #define RH_RF95_LNA_GAIN_G3 0x60 |
danjulio | 0:e69d086cb053 | 156 | #define RH_RF95_LNA_GAIN_G4 0x80 |
danjulio | 0:e69d086cb053 | 157 | #define RH_RF95_LNA_GAIN_G5 0xa0 |
danjulio | 0:e69d086cb053 | 158 | #define RH_RF95_LNA_GAIN_G6 0xc0 |
danjulio | 0:e69d086cb053 | 159 | #define RH_RF95_LNA_BOOST_LF 0x18 |
danjulio | 0:e69d086cb053 | 160 | #define RH_RF95_LNA_BOOST_LF_DEFAULT 0x00 |
danjulio | 0:e69d086cb053 | 161 | #define RH_RF95_LNA_BOOST_HF 0x03 |
danjulio | 0:e69d086cb053 | 162 | #define RH_RF95_LNA_BOOST_HF_DEFAULT 0x00 |
danjulio | 0:e69d086cb053 | 163 | #define RH_RF95_LNA_BOOST_HF_150PC 0x11 |
danjulio | 0:e69d086cb053 | 164 | |
danjulio | 0:e69d086cb053 | 165 | // RH_RF95_REG_11_IRQ_FLAGS_MASK 0x11 |
danjulio | 0:e69d086cb053 | 166 | #define RH_RF95_RX_TIMEOUT_MASK 0x80 |
danjulio | 0:e69d086cb053 | 167 | #define RH_RF95_RX_DONE_MASK 0x40 |
danjulio | 0:e69d086cb053 | 168 | #define RH_RF95_PAYLOAD_CRC_ERROR_MASK 0x20 |
danjulio | 0:e69d086cb053 | 169 | #define RH_RF95_VALID_HEADER_MASK 0x10 |
danjulio | 0:e69d086cb053 | 170 | #define RH_RF95_TX_DONE_MASK 0x08 |
danjulio | 0:e69d086cb053 | 171 | #define RH_RF95_CAD_DONE_MASK 0x04 |
danjulio | 0:e69d086cb053 | 172 | #define RH_RF95_FHSS_CHANGE_CHANNEL_MASK 0x02 |
danjulio | 0:e69d086cb053 | 173 | #define RH_RF95_CAD_DETECTED_MASK 0x01 |
danjulio | 0:e69d086cb053 | 174 | |
danjulio | 0:e69d086cb053 | 175 | // RH_RF95_REG_12_IRQ_FLAGS 0x12 |
danjulio | 0:e69d086cb053 | 176 | #define RH_RF95_RX_TIMEOUT 0x80 |
danjulio | 0:e69d086cb053 | 177 | #define RH_RF95_RX_DONE 0x40 |
danjulio | 0:e69d086cb053 | 178 | #define RH_RF95_PAYLOAD_CRC_ERROR 0x20 |
danjulio | 0:e69d086cb053 | 179 | #define RH_RF95_VALID_HEADER 0x10 |
danjulio | 0:e69d086cb053 | 180 | #define RH_RF95_TX_DONE 0x08 |
danjulio | 0:e69d086cb053 | 181 | #define RH_RF95_CAD_DONE 0x04 |
danjulio | 0:e69d086cb053 | 182 | #define RH_RF95_FHSS_CHANGE_CHANNEL 0x02 |
danjulio | 0:e69d086cb053 | 183 | #define RH_RF95_CAD_DETECTED 0x01 |
danjulio | 0:e69d086cb053 | 184 | |
danjulio | 0:e69d086cb053 | 185 | // RH_RF95_REG_18_MODEM_STAT 0x18 |
danjulio | 0:e69d086cb053 | 186 | #define RH_RF95_RX_CODING_RATE 0xe0 |
danjulio | 0:e69d086cb053 | 187 | #define RH_RF95_MODEM_STATUS_CLEAR 0x10 |
danjulio | 0:e69d086cb053 | 188 | #define RH_RF95_MODEM_STATUS_HEADER_INFO_VALID 0x08 |
danjulio | 0:e69d086cb053 | 189 | #define RH_RF95_MODEM_STATUS_RX_ONGOING 0x04 |
danjulio | 0:e69d086cb053 | 190 | #define RH_RF95_MODEM_STATUS_SIGNAL_SYNCHRONIZED 0x02 |
danjulio | 0:e69d086cb053 | 191 | #define RH_RF95_MODEM_STATUS_SIGNAL_DETECTED 0x01 |
danjulio | 0:e69d086cb053 | 192 | |
danjulio | 0:e69d086cb053 | 193 | // RH_RF95_REG_1C_HOP_CHANNEL 0x1c |
danjulio | 0:e69d086cb053 | 194 | #define RH_RF95_PLL_TIMEOUT 0x80 |
danjulio | 0:e69d086cb053 | 195 | #define RH_RF95_RX_PAYLOAD_CRC_IS_ON 0x40 |
danjulio | 0:e69d086cb053 | 196 | #define RH_RF95_FHSS_PRESENT_CHANNEL 0x3f |
danjulio | 0:e69d086cb053 | 197 | |
danjulio | 0:e69d086cb053 | 198 | // RH_RF95_REG_1D_MODEM_CONFIG1 0x1d |
danjulio | 0:e69d086cb053 | 199 | #define RH_RF95_BW 0xf0 |
danjulio | 0:e69d086cb053 | 200 | |
danjulio | 0:e69d086cb053 | 201 | #define RH_RF95_BW_7_8KHZ 0x00 |
danjulio | 0:e69d086cb053 | 202 | #define RH_RF95_BW_10_4KHZ 0x10 |
danjulio | 0:e69d086cb053 | 203 | #define RH_RF95_BW_15_6KHZ 0x20 |
danjulio | 0:e69d086cb053 | 204 | #define RH_RF95_BW_20_8KHZ 0x30 |
danjulio | 0:e69d086cb053 | 205 | #define RH_RF95_BW_31_25KHZ 0x40 |
danjulio | 0:e69d086cb053 | 206 | #define RH_RF95_BW_41_7KHZ 0x50 |
danjulio | 0:e69d086cb053 | 207 | #define RH_RF95_BW_62_5KHZ 0x60 |
danjulio | 0:e69d086cb053 | 208 | #define RH_RF95_BW_125KHZ 0x70 |
danjulio | 0:e69d086cb053 | 209 | #define RH_RF95_BW_250KHZ 0x80 |
danjulio | 0:e69d086cb053 | 210 | #define RH_RF95_BW_500KHZ 0x90 |
danjulio | 0:e69d086cb053 | 211 | #define RH_RF95_CODING_RATE 0x0e |
danjulio | 0:e69d086cb053 | 212 | #define RH_RF95_CODING_RATE_4_5 0x02 |
danjulio | 0:e69d086cb053 | 213 | #define RH_RF95_CODING_RATE_4_6 0x04 |
danjulio | 0:e69d086cb053 | 214 | #define RH_RF95_CODING_RATE_4_7 0x06 |
danjulio | 0:e69d086cb053 | 215 | #define RH_RF95_CODING_RATE_4_8 0x08 |
danjulio | 0:e69d086cb053 | 216 | #define RH_RF95_IMPLICIT_HEADER_MODE_ON 0x01 |
danjulio | 0:e69d086cb053 | 217 | |
danjulio | 0:e69d086cb053 | 218 | // RH_RF95_REG_1E_MODEM_CONFIG2 0x1e |
danjulio | 0:e69d086cb053 | 219 | #define RH_RF95_SPREADING_FACTOR 0xf0 |
danjulio | 0:e69d086cb053 | 220 | #define RH_RF95_SPREADING_FACTOR_64CPS 0x60 |
danjulio | 0:e69d086cb053 | 221 | #define RH_RF95_SPREADING_FACTOR_128CPS 0x70 |
danjulio | 0:e69d086cb053 | 222 | #define RH_RF95_SPREADING_FACTOR_256CPS 0x80 |
danjulio | 0:e69d086cb053 | 223 | #define RH_RF95_SPREADING_FACTOR_512CPS 0x90 |
danjulio | 0:e69d086cb053 | 224 | #define RH_RF95_SPREADING_FACTOR_1024CPS 0xa0 |
danjulio | 0:e69d086cb053 | 225 | #define RH_RF95_SPREADING_FACTOR_2048CPS 0xb0 |
danjulio | 0:e69d086cb053 | 226 | #define RH_RF95_SPREADING_FACTOR_4096CPS 0xc0 |
danjulio | 0:e69d086cb053 | 227 | #define RH_RF95_TX_CONTINUOUS_MOE 0x08 |
danjulio | 0:e69d086cb053 | 228 | |
danjulio | 0:e69d086cb053 | 229 | #define RH_RF95_PAYLOAD_CRC_ON 0x04 |
danjulio | 0:e69d086cb053 | 230 | #define RH_RF95_SYM_TIMEOUT_MSB 0x03 |
danjulio | 0:e69d086cb053 | 231 | |
danjulio | 0:e69d086cb053 | 232 | // RH_RF95_REG_4B_TCXO 0x4b |
danjulio | 0:e69d086cb053 | 233 | #define RH_RF95_TCXO_TCXO_INPUT_ON 0x10 |
danjulio | 0:e69d086cb053 | 234 | |
danjulio | 0:e69d086cb053 | 235 | // RH_RF95_REG_4D_PA_DAC 0x4d |
danjulio | 0:e69d086cb053 | 236 | #define RH_RF95_PA_DAC_DISABLE 0x04 |
danjulio | 0:e69d086cb053 | 237 | #define RH_RF95_PA_DAC_ENABLE 0x07 |
danjulio | 0:e69d086cb053 | 238 | |
danjulio | 0:e69d086cb053 | 239 | ///////////////////////////////////////////////////////////////////// |
danjulio | 0:e69d086cb053 | 240 | /// \class RH_RF95 RH_RF95.h <RH_RF95.h> |
danjulio | 0:e69d086cb053 | 241 | /// \brief Driver to send and receive unaddressed, unreliable datagrams via a LoRa |
danjulio | 0:e69d086cb053 | 242 | /// capable radio transceiver. |
danjulio | 0:e69d086cb053 | 243 | /// |
danjulio | 0:e69d086cb053 | 244 | /// For Semtech SX1276/77/78/79 and HopeRF RF95/96/97/98 and other similar LoRa capable radios. |
danjulio | 0:e69d086cb053 | 245 | /// Based on http://www.hoperf.com/upload/rf/RFM95_96_97_98W.pdf |
danjulio | 0:e69d086cb053 | 246 | /// and http://www.hoperf.cn/upload/rfchip/RF96_97_98.pdf |
danjulio | 0:e69d086cb053 | 247 | /// and http://www.semtech.com/images/datasheet/LoraDesignGuide_STD.pdf |
danjulio | 0:e69d086cb053 | 248 | /// and http://www.semtech.com/images/datasheet/sx1276.pdf |
danjulio | 0:e69d086cb053 | 249 | /// and http://www.semtech.com/images/datasheet/sx1276_77_78_79.pdf |
danjulio | 0:e69d086cb053 | 250 | /// FSK/GFSK/OOK modes are not (yet) supported. |
danjulio | 0:e69d086cb053 | 251 | /// |
danjulio | 0:e69d086cb053 | 252 | /// Works with |
danjulio | 0:e69d086cb053 | 253 | /// - the excellent MiniWirelessLoRa from Anarduino http://www.anarduino.com/miniwireless |
danjulio | 0:e69d086cb053 | 254 | /// - The excellent Modtronix inAir4 http://modtronix.com/inair4.html |
danjulio | 0:e69d086cb053 | 255 | /// and inAir9 modules http://modtronix.com/inair9.html. |
danjulio | 0:e69d086cb053 | 256 | /// - the excellent Rocket Scream Mini Ultra Pro with the RFM95W |
danjulio | 0:e69d086cb053 | 257 | /// http://www.rocketscream.com/blog/product/mini-ultra-pro-with-radio/ |
danjulio | 0:e69d086cb053 | 258 | /// - Lora1276 module from NiceRF http://www.nicerf.com/product_view.aspx?id=99 |
danjulio | 0:e69d086cb053 | 259 | /// - Adafruit Feather M0 with RFM95 |
danjulio | 0:e69d086cb053 | 260 | /// |
danjulio | 0:e69d086cb053 | 261 | /// \par Overview |
danjulio | 0:e69d086cb053 | 262 | /// |
danjulio | 0:e69d086cb053 | 263 | /// This class provides basic functions for sending and receiving unaddressed, |
danjulio | 0:e69d086cb053 | 264 | /// unreliable datagrams of arbitrary length to 251 octets per packet. |
danjulio | 0:e69d086cb053 | 265 | /// |
danjulio | 0:e69d086cb053 | 266 | /// Manager classes may use this class to implement reliable, addressed datagrams and streams, |
danjulio | 0:e69d086cb053 | 267 | /// mesh routers, repeaters, translators etc. |
danjulio | 0:e69d086cb053 | 268 | /// |
danjulio | 0:e69d086cb053 | 269 | /// Naturally, for any 2 radios to communicate that must be configured to use the same frequency and |
danjulio | 0:e69d086cb053 | 270 | /// modulation scheme. |
danjulio | 0:e69d086cb053 | 271 | /// |
danjulio | 0:e69d086cb053 | 272 | /// This Driver provides an object-oriented interface for sending and receiving data messages with Hope-RF |
danjulio | 0:e69d086cb053 | 273 | /// RFM95/96/97/98(W), Semtech SX1276/77/78/79 and compatible radio modules in LoRa mode. |
danjulio | 0:e69d086cb053 | 274 | /// |
danjulio | 0:e69d086cb053 | 275 | /// The Hope-RF (http://www.hoperf.com) RFM95/96/97/98(W) and Semtech SX1276/77/78/79 is a low-cost ISM transceiver |
danjulio | 0:e69d086cb053 | 276 | /// chip. It supports FSK, GFSK, OOK over a wide range of frequencies and |
danjulio | 0:e69d086cb053 | 277 | /// programmable data rates, and it also supports the proprietary LoRA (Long Range) mode, which |
danjulio | 0:e69d086cb053 | 278 | /// is the only mode supported in this RadioHead driver. |
danjulio | 0:e69d086cb053 | 279 | /// |
danjulio | 0:e69d086cb053 | 280 | /// This Driver provides functions for sending and receiving messages of up |
danjulio | 0:e69d086cb053 | 281 | /// to 251 octets on any frequency supported by the radio, in a range of |
danjulio | 0:e69d086cb053 | 282 | /// predefined Bandwidths, Spreading Factors and Coding Rates. Frequency can be set with |
danjulio | 0:e69d086cb053 | 283 | /// 61Hz precision to any frequency from 240.0MHz to 960.0MHz. Caution: most modules only support a more limited |
danjulio | 0:e69d086cb053 | 284 | /// range of frequencies due to antenna tuning. |
danjulio | 0:e69d086cb053 | 285 | /// |
danjulio | 0:e69d086cb053 | 286 | /// Up to 2 modules can be connected to an Arduino (3 on a Mega), |
danjulio | 0:e69d086cb053 | 287 | /// permitting the construction of translators and frequency changers, etc. |
danjulio | 0:e69d086cb053 | 288 | /// |
danjulio | 0:e69d086cb053 | 289 | /// Support for other features such as transmitter power control etc is |
danjulio | 0:e69d086cb053 | 290 | /// also provided. |
danjulio | 0:e69d086cb053 | 291 | /// |
danjulio | 0:e69d086cb053 | 292 | /// Tested on MinWirelessLoRa with arduino-1.0.5 |
danjulio | 0:e69d086cb053 | 293 | /// on OpenSuSE 13.1. |
danjulio | 0:e69d086cb053 | 294 | /// Also tested with Teensy3.1, Modtronix inAir4 and Arduino 1.6.5 on OpenSuSE 13.1 |
danjulio | 0:e69d086cb053 | 295 | /// |
danjulio | 0:e69d086cb053 | 296 | /// \par Packet Format |
danjulio | 0:e69d086cb053 | 297 | /// |
danjulio | 0:e69d086cb053 | 298 | /// All messages sent and received by this RH_RF95 Driver conform to this packet format: |
danjulio | 0:e69d086cb053 | 299 | /// |
danjulio | 0:e69d086cb053 | 300 | /// - LoRa mode: |
danjulio | 0:e69d086cb053 | 301 | /// - 8 symbol PREAMBLE |
danjulio | 0:e69d086cb053 | 302 | /// - Explicit header with header CRC (handled internally by the radio) |
danjulio | 0:e69d086cb053 | 303 | /// - 4 octets HEADER: (TO, FROM, ID, FLAGS) |
danjulio | 0:e69d086cb053 | 304 | /// - 0 to 251 octets DATA |
danjulio | 0:e69d086cb053 | 305 | /// - CRC (handled internally by the radio) |
danjulio | 0:e69d086cb053 | 306 | /// |
danjulio | 0:e69d086cb053 | 307 | /// \par Connecting RFM95/96/97/98 and Semtech SX1276/77/78/79 to Arduino |
danjulio | 0:e69d086cb053 | 308 | /// |
danjulio | 0:e69d086cb053 | 309 | /// We tested with Anarduino MiniWirelessLoRA, which is an Arduino Duemilanove compatible with a RFM96W |
danjulio | 0:e69d086cb053 | 310 | /// module on-board. Therefore it needs no connections other than the USB |
danjulio | 0:e69d086cb053 | 311 | /// programming connection and an antenna to make it work. |
danjulio | 0:e69d086cb053 | 312 | /// |
danjulio | 0:e69d086cb053 | 313 | /// If you have a bare RFM95/96/97/98 that you want to connect to an Arduino, you |
danjulio | 0:e69d086cb053 | 314 | /// might use these connections (untested): CAUTION: you must use a 3.3V type |
danjulio | 0:e69d086cb053 | 315 | /// Arduino, otherwise you will also need voltage level shifters between the |
danjulio | 0:e69d086cb053 | 316 | /// Arduino and the RFM95. CAUTION, you must also ensure you connect an |
danjulio | 0:e69d086cb053 | 317 | /// antenna. |
danjulio | 0:e69d086cb053 | 318 | /// |
danjulio | 0:e69d086cb053 | 319 | /// \code |
danjulio | 0:e69d086cb053 | 320 | /// Arduino RFM95/96/97/98 |
danjulio | 0:e69d086cb053 | 321 | /// GND----------GND (ground in) |
danjulio | 0:e69d086cb053 | 322 | /// 3V3----------3.3V (3.3V in) |
danjulio | 0:e69d086cb053 | 323 | /// interrupt 0 pin D2-----------DIO0 (interrupt request out) |
danjulio | 0:e69d086cb053 | 324 | /// SS pin D10----------NSS (CS chip select in) |
danjulio | 0:e69d086cb053 | 325 | /// SCK pin D13----------SCK (SPI clock in) |
danjulio | 0:e69d086cb053 | 326 | /// MOSI pin D11----------MOSI (SPI Data in) |
danjulio | 0:e69d086cb053 | 327 | /// MISO pin D12----------MISO (SPI Data out) |
danjulio | 0:e69d086cb053 | 328 | /// \endcode |
danjulio | 0:e69d086cb053 | 329 | /// With these connections, you can then use the default constructor RH_RF95(). |
danjulio | 0:e69d086cb053 | 330 | /// You can override the default settings for the SS pin and the interrupt in |
danjulio | 0:e69d086cb053 | 331 | /// the RH_RF95 constructor if you wish to connect the slave select SS to other |
danjulio | 0:e69d086cb053 | 332 | /// than the normal one for your Arduino (D10 for Diecimila, Uno etc and D53 |
danjulio | 0:e69d086cb053 | 333 | /// for Mega) or the interrupt request to other than pin D2 (Caution, |
danjulio | 0:e69d086cb053 | 334 | /// different processors have different constraints as to the pins available |
danjulio | 0:e69d086cb053 | 335 | /// for interrupts). |
danjulio | 0:e69d086cb053 | 336 | /// |
danjulio | 0:e69d086cb053 | 337 | /// You can connect a Modtronix inAir4 or inAir9 directly to a 3.3V part such as a Teensy 3.1 like |
danjulio | 0:e69d086cb053 | 338 | /// this (tested). |
danjulio | 0:e69d086cb053 | 339 | /// \code |
danjulio | 0:e69d086cb053 | 340 | /// Teensy inAir4 inAir9 |
danjulio | 0:e69d086cb053 | 341 | /// GND----------GND (ground in) |
danjulio | 0:e69d086cb053 | 342 | /// 3V3----------3.3V (3.3V in) |
danjulio | 0:e69d086cb053 | 343 | /// interrupt 0 pin D2-----------D00 (interrupt request out) |
danjulio | 0:e69d086cb053 | 344 | /// SS pin D10----------CS (CS chip select in) |
danjulio | 0:e69d086cb053 | 345 | /// SCK pin D13----------CK (SPI clock in) |
danjulio | 0:e69d086cb053 | 346 | /// MOSI pin D11----------SI (SPI Data in) |
danjulio | 0:e69d086cb053 | 347 | /// MISO pin D12----------SO (SPI Data out) |
danjulio | 0:e69d086cb053 | 348 | /// \endcode |
danjulio | 0:e69d086cb053 | 349 | /// With these connections, you can then use the default constructor RH_RF95(). |
danjulio | 0:e69d086cb053 | 350 | /// you must also set the transmitter power with useRFO: |
danjulio | 0:e69d086cb053 | 351 | /// driver.setTxPower(13, true); |
danjulio | 0:e69d086cb053 | 352 | /// |
danjulio | 0:e69d086cb053 | 353 | /// Note that if you are using Modtronix inAir4 or inAir9,or any other module which uses the |
danjulio | 0:e69d086cb053 | 354 | /// transmitter RFO pins and not the PA_BOOST pins |
danjulio | 0:e69d086cb053 | 355 | /// that you must configure the power transmitter power for -1 to 14 dBm and with useRFO true. |
danjulio | 0:e69d086cb053 | 356 | /// Failure to do that will result in extremely low transmit powers. |
danjulio | 0:e69d086cb053 | 357 | /// |
danjulio | 0:e69d086cb053 | 358 | /// If you have an Arduino M0 Pro from arduino.org, |
danjulio | 0:e69d086cb053 | 359 | /// you should note that you cannot use Pin 2 for the interrupt line |
danjulio | 0:e69d086cb053 | 360 | /// (Pin 2 is for the NMI only). The same comments apply to Pin 4 on Arduino Zero from arduino.cc. |
danjulio | 0:e69d086cb053 | 361 | /// Instead you can use any other pin (we use Pin 3) and initialise RH_RF69 like this: |
danjulio | 0:e69d086cb053 | 362 | /// \code |
danjulio | 0:e69d086cb053 | 363 | /// // Slave Select is pin 10, interrupt is Pin 3 |
danjulio | 0:e69d086cb053 | 364 | /// RH_RF95 driver(10, 3); |
danjulio | 0:e69d086cb053 | 365 | /// \endcode |
danjulio | 0:e69d086cb053 | 366 | /// |
danjulio | 0:e69d086cb053 | 367 | /// If you have a Rocket Scream Mini Ultra Pro with the RFM95W: |
danjulio | 0:e69d086cb053 | 368 | /// - Ensure you have Arduino SAMD board support 1.6.5 or later in Arduino IDE 1.6.8 or later. |
danjulio | 0:e69d086cb053 | 369 | /// - The radio SS is hardwired to pin D5 and the DIO0 interrupt to pin D2, |
danjulio | 0:e69d086cb053 | 370 | /// so you need to initialise the radio like this: |
danjulio | 0:e69d086cb053 | 371 | /// \code |
danjulio | 0:e69d086cb053 | 372 | /// RH_RF95 driver(5, 2); |
danjulio | 0:e69d086cb053 | 373 | /// \endcode |
danjulio | 0:e69d086cb053 | 374 | /// - The name of the serial port on that board is 'SerialUSB', not 'Serial', so this may be helpful at the top of our |
danjulio | 0:e69d086cb053 | 375 | /// sample sketches: |
danjulio | 0:e69d086cb053 | 376 | /// \code |
danjulio | 0:e69d086cb053 | 377 | /// #define Serial SerialUSB |
danjulio | 0:e69d086cb053 | 378 | /// \endcode |
danjulio | 0:e69d086cb053 | 379 | /// - You also need this in setup before radio initialisation |
danjulio | 0:e69d086cb053 | 380 | /// \code |
danjulio | 0:e69d086cb053 | 381 | /// // Ensure serial flash is not interfering with radio communication on SPI bus |
danjulio | 0:e69d086cb053 | 382 | /// pinMode(4, OUTPUT); |
danjulio | 0:e69d086cb053 | 383 | /// digitalWrite(4, HIGH); |
danjulio | 0:e69d086cb053 | 384 | /// \endcode |
danjulio | 0:e69d086cb053 | 385 | /// - and if you have a 915MHz part, you need this after driver/manager intitalisation: |
danjulio | 0:e69d086cb053 | 386 | /// \code |
danjulio | 0:e69d086cb053 | 387 | /// rf95.setFrequency(915.0); |
danjulio | 0:e69d086cb053 | 388 | /// \endcode |
danjulio | 0:e69d086cb053 | 389 | /// which adds up to modifying sample sketches something like: |
danjulio | 0:e69d086cb053 | 390 | /// \code |
danjulio | 0:e69d086cb053 | 391 | /// #include <SPI.h> |
danjulio | 0:e69d086cb053 | 392 | /// #include <RH_RF95.h> |
danjulio | 0:e69d086cb053 | 393 | /// RH_RF95 rf95(5, 2); // Rocket Scream Mini Ultra Pro with the RFM95W |
danjulio | 0:e69d086cb053 | 394 | /// #define Serial SerialUSB |
danjulio | 0:e69d086cb053 | 395 | /// |
danjulio | 0:e69d086cb053 | 396 | /// void setup() |
danjulio | 0:e69d086cb053 | 397 | /// { |
danjulio | 0:e69d086cb053 | 398 | /// // Ensure serial flash is not interfering with radio communication on SPI bus |
danjulio | 0:e69d086cb053 | 399 | /// pinMode(4, OUTPUT); |
danjulio | 0:e69d086cb053 | 400 | /// digitalWrite(4, HIGH); |
danjulio | 0:e69d086cb053 | 401 | /// |
danjulio | 0:e69d086cb053 | 402 | /// Serial.begin(9600); |
danjulio | 0:e69d086cb053 | 403 | /// while (!Serial) ; // Wait for serial port to be available |
danjulio | 0:e69d086cb053 | 404 | /// if (!rf95.init()) |
danjulio | 0:e69d086cb053 | 405 | /// Serial.println("init failed"); |
danjulio | 0:e69d086cb053 | 406 | /// rf95.setFrequency(915.0); |
danjulio | 0:e69d086cb053 | 407 | /// } |
danjulio | 0:e69d086cb053 | 408 | /// ... |
danjulio | 0:e69d086cb053 | 409 | /// \endcode |
danjulio | 0:e69d086cb053 | 410 | /// |
danjulio | 0:e69d086cb053 | 411 | /// For Adafruit Feather M0 with RFM95, construct the driver like this: |
danjulio | 0:e69d086cb053 | 412 | /// \code |
danjulio | 0:e69d086cb053 | 413 | /// RH_RF95 rf95(8, 3); |
danjulio | 0:e69d086cb053 | 414 | /// \endcode |
danjulio | 0:e69d086cb053 | 415 | /// |
danjulio | 0:e69d086cb053 | 416 | /// It is possible to have 2 or more radios connected to one Arduino, provided |
danjulio | 0:e69d086cb053 | 417 | /// each radio has its own SS and interrupt line (SCK, SDI and SDO are common |
danjulio | 0:e69d086cb053 | 418 | /// to all radios) |
danjulio | 0:e69d086cb053 | 419 | /// |
danjulio | 0:e69d086cb053 | 420 | /// Caution: on some Arduinos such as the Mega 2560, if you set the slave |
danjulio | 0:e69d086cb053 | 421 | /// select pin to be other than the usual SS pin (D53 on Mega 2560), you may |
danjulio | 0:e69d086cb053 | 422 | /// need to set the usual SS pin to be an output to force the Arduino into SPI |
danjulio | 0:e69d086cb053 | 423 | /// master mode. |
danjulio | 0:e69d086cb053 | 424 | /// |
danjulio | 0:e69d086cb053 | 425 | /// Caution: Power supply requirements of the RFM module may be relevant in some circumstances: |
danjulio | 0:e69d086cb053 | 426 | /// RFM95/96/97/98 modules are capable of pulling 120mA+ at full power, where Arduino's 3.3V line can |
danjulio | 0:e69d086cb053 | 427 | /// give 50mA. You may need to make provision for alternate power supply for |
danjulio | 0:e69d086cb053 | 428 | /// the RFM module, especially if you wish to use full transmit power, and/or you have |
danjulio | 0:e69d086cb053 | 429 | /// other shields demanding power. Inadequate power for the RFM is likely to cause symptoms such as: |
danjulio | 0:e69d086cb053 | 430 | /// - reset's/bootups terminate with "init failed" messages |
danjulio | 0:e69d086cb053 | 431 | /// - random termination of communication after 5-30 packets sent/received |
danjulio | 0:e69d086cb053 | 432 | /// - "fake ok" state, where initialization passes fluently, but communication doesn't happen |
danjulio | 0:e69d086cb053 | 433 | /// - shields hang Arduino boards, especially during the flashing |
danjulio | 0:e69d086cb053 | 434 | /// |
danjulio | 0:e69d086cb053 | 435 | /// \par Interrupts |
danjulio | 0:e69d086cb053 | 436 | /// |
danjulio | 0:e69d086cb053 | 437 | /// The RH_RF95 driver uses interrupts to react to events in the RFM module, |
danjulio | 0:e69d086cb053 | 438 | /// such as the reception of a new packet, or the completion of transmission |
danjulio | 0:e69d086cb053 | 439 | /// of a packet. The RH_RF95 driver interrupt service routine reads status from |
danjulio | 0:e69d086cb053 | 440 | /// and writes data to the the RFM module via the SPI interface. It is very |
danjulio | 0:e69d086cb053 | 441 | /// important therefore, that if you are using the RH_RF95 driver with another |
danjulio | 0:e69d086cb053 | 442 | /// SPI based deviced, that you disable interrupts while you transfer data to |
danjulio | 0:e69d086cb053 | 443 | /// and from that other device. Use cli() to disable interrupts and sei() to |
danjulio | 0:e69d086cb053 | 444 | /// reenable them. |
danjulio | 0:e69d086cb053 | 445 | /// |
danjulio | 0:e69d086cb053 | 446 | /// \par Memory |
danjulio | 0:e69d086cb053 | 447 | /// |
danjulio | 0:e69d086cb053 | 448 | /// The RH_RF95 driver requires non-trivial amounts of memory. The sample |
danjulio | 0:e69d086cb053 | 449 | /// programs all compile to about 8kbytes each, which will fit in the |
danjulio | 0:e69d086cb053 | 450 | /// flash proram memory of most Arduinos. However, the RAM requirements are |
danjulio | 0:e69d086cb053 | 451 | /// more critical. Therefore, you should be vary sparing with RAM use in |
danjulio | 0:e69d086cb053 | 452 | /// programs that use the RH_RF95 driver. |
danjulio | 0:e69d086cb053 | 453 | /// |
danjulio | 0:e69d086cb053 | 454 | /// It is often hard to accurately identify when you are hitting RAM limits on Arduino. |
danjulio | 0:e69d086cb053 | 455 | /// The symptoms can include: |
danjulio | 0:e69d086cb053 | 456 | /// - Mysterious crashes and restarts |
danjulio | 0:e69d086cb053 | 457 | /// - Changes in behaviour when seemingly unrelated changes are made (such as adding print() statements) |
danjulio | 0:e69d086cb053 | 458 | /// - Hanging |
danjulio | 0:e69d086cb053 | 459 | /// - Output from Serial.print() not appearing |
danjulio | 0:e69d086cb053 | 460 | /// |
danjulio | 0:e69d086cb053 | 461 | /// \par Range |
danjulio | 0:e69d086cb053 | 462 | /// |
danjulio | 0:e69d086cb053 | 463 | /// We have made some simple range tests under the following conditions: |
danjulio | 0:e69d086cb053 | 464 | /// - rf95_client base station connected to a VHF discone antenna at 8m height above ground |
danjulio | 0:e69d086cb053 | 465 | /// - rf95_server mobile connected to 17.3cm 1/4 wavelength antenna at 1m height, no ground plane. |
danjulio | 0:e69d086cb053 | 466 | /// - Both configured for 13dBm, 434MHz, Bw = 125 kHz, Cr = 4/8, Sf = 4096chips/symbol, CRC on. Slow+long range |
danjulio | 0:e69d086cb053 | 467 | /// - Minimum reported RSSI seen for successful comms was about -91 |
danjulio | 0:e69d086cb053 | 468 | /// - Range over flat ground through heavy trees and vegetation approx 2km. |
danjulio | 0:e69d086cb053 | 469 | /// - At 20dBm (100mW) otherwise identical conditions approx 3km. |
danjulio | 0:e69d086cb053 | 470 | /// - At 20dBm, along salt water flat sandy beach, 3.2km. |
danjulio | 0:e69d086cb053 | 471 | /// |
danjulio | 0:e69d086cb053 | 472 | /// It should be noted that at this data rate, a 12 octet message takes 2 seconds to transmit. |
danjulio | 0:e69d086cb053 | 473 | /// |
danjulio | 0:e69d086cb053 | 474 | /// At 20dBm (100mW) with Bw = 125 kHz, Cr = 4/5, Sf = 128chips/symbol, CRC on. |
danjulio | 0:e69d086cb053 | 475 | /// (Default medium range) in the conditions described above. |
danjulio | 0:e69d086cb053 | 476 | /// - Range over flat ground through heavy trees and vegetation approx 2km. |
danjulio | 0:e69d086cb053 | 477 | /// |
danjulio | 0:e69d086cb053 | 478 | /// Caution: the performance of this radio, especially with narrow bandwidths is strongly dependent on the |
danjulio | 0:e69d086cb053 | 479 | /// accuracy and stability of the chip clock. HopeRF and Semtech do not appear to |
danjulio | 0:e69d086cb053 | 480 | /// recommend bandwidths of less than 62.5 kHz |
danjulio | 0:e69d086cb053 | 481 | /// unless you have the optional Temperature Compensated Crystal Oscillator (TCXO) installed and |
danjulio | 0:e69d086cb053 | 482 | /// enabled on your radio module. See the refernece manual for more data. |
danjulio | 0:e69d086cb053 | 483 | /// Also https://lowpowerlab.com/forum/rf-range-antennas-rfm69-library/lora-library-experiences-range/15/ |
danjulio | 0:e69d086cb053 | 484 | /// and http://www.semtech.com/images/datasheet/an120014-xo-guidance-lora-modulation.pdf |
danjulio | 0:e69d086cb053 | 485 | /// |
danjulio | 0:e69d086cb053 | 486 | /// \par Transmitter Power |
danjulio | 0:e69d086cb053 | 487 | /// |
danjulio | 0:e69d086cb053 | 488 | /// You can control the transmitter power on the RF transceiver |
danjulio | 0:e69d086cb053 | 489 | /// with the RH_RF95::setTxPower() function. The argument can be any of |
danjulio | 0:e69d086cb053 | 490 | /// +5 to +23 (for modules that use PA_BOOST) |
danjulio | 0:e69d086cb053 | 491 | /// -1 to +14 (for modules that use RFO transmitter pin) |
danjulio | 0:e69d086cb053 | 492 | /// The default is 13. Eg: |
danjulio | 0:e69d086cb053 | 493 | /// \code |
danjulio | 0:e69d086cb053 | 494 | /// driver.setTxPower(10); // use PA_BOOST transmitter pin |
danjulio | 0:e69d086cb053 | 495 | /// driver.setTxPower(10, true); // use PA_RFO pin transmitter pin |
danjulio | 0:e69d086cb053 | 496 | /// \endcode |
danjulio | 0:e69d086cb053 | 497 | /// |
danjulio | 0:e69d086cb053 | 498 | /// We have made some actual power measurements against |
danjulio | 0:e69d086cb053 | 499 | /// programmed power for Anarduino MiniWirelessLoRa (which has RFM96W-433Mhz installed) |
danjulio | 0:e69d086cb053 | 500 | /// - MiniWirelessLoRa RFM96W-433Mhz, USB power |
danjulio | 0:e69d086cb053 | 501 | /// - 30cm RG316 soldered direct to RFM96W module ANT and GND |
danjulio | 0:e69d086cb053 | 502 | /// - SMA connector |
danjulio | 0:e69d086cb053 | 503 | /// - 12db attenuator |
danjulio | 0:e69d086cb053 | 504 | /// - SMA connector |
danjulio | 0:e69d086cb053 | 505 | /// - MiniKits AD8307 HF/VHF Power Head (calibrated against Rohde&Schwartz 806.2020 test set) |
danjulio | 0:e69d086cb053 | 506 | /// - Tektronix TDS220 scope to measure the Vout from power head |
danjulio | 0:e69d086cb053 | 507 | /// \code |
danjulio | 0:e69d086cb053 | 508 | /// Program power Measured Power |
danjulio | 0:e69d086cb053 | 509 | /// dBm dBm |
danjulio | 0:e69d086cb053 | 510 | /// 5 5 |
danjulio | 0:e69d086cb053 | 511 | /// 7 7 |
danjulio | 0:e69d086cb053 | 512 | /// 9 8 |
danjulio | 0:e69d086cb053 | 513 | /// 11 11 |
danjulio | 0:e69d086cb053 | 514 | /// 13 13 |
danjulio | 0:e69d086cb053 | 515 | /// 15 15 |
danjulio | 0:e69d086cb053 | 516 | /// 17 16 |
danjulio | 0:e69d086cb053 | 517 | /// 19 18 |
danjulio | 0:e69d086cb053 | 518 | /// 20 20 |
danjulio | 0:e69d086cb053 | 519 | /// 21 21 |
danjulio | 0:e69d086cb053 | 520 | /// 22 22 |
danjulio | 0:e69d086cb053 | 521 | /// 23 23 |
danjulio | 0:e69d086cb053 | 522 | /// \endcode |
danjulio | 0:e69d086cb053 | 523 | /// |
danjulio | 0:e69d086cb053 | 524 | /// We have also measured the actual power output from a Modtronix inAir4 http://modtronix.com/inair4.html |
danjulio | 0:e69d086cb053 | 525 | /// connected to a Teensy 3.1: |
danjulio | 0:e69d086cb053 | 526 | /// Teensy 3.1 this is a 3.3V part, connected directly to: |
danjulio | 0:e69d086cb053 | 527 | /// Modtronix inAir4 with SMA antenna connector, connected as above: |
danjulio | 0:e69d086cb053 | 528 | /// 10cm SMA-SMA cable |
danjulio | 0:e69d086cb053 | 529 | /// - MiniKits AD8307 HF/VHF Power Head (calibrated against Rohde&Schwartz 806.2020 test set) |
danjulio | 0:e69d086cb053 | 530 | /// - Tektronix TDS220 scope to measure the Vout from power head |
danjulio | 0:e69d086cb053 | 531 | /// \code |
danjulio | 0:e69d086cb053 | 532 | /// Program power Measured Power |
danjulio | 0:e69d086cb053 | 533 | /// dBm dBm |
danjulio | 0:e69d086cb053 | 534 | /// -1 0 |
danjulio | 0:e69d086cb053 | 535 | /// 1 2 |
danjulio | 0:e69d086cb053 | 536 | /// 3 4 |
danjulio | 0:e69d086cb053 | 537 | /// 5 7 |
danjulio | 0:e69d086cb053 | 538 | /// 7 10 |
danjulio | 0:e69d086cb053 | 539 | /// 9 13 |
danjulio | 0:e69d086cb053 | 540 | /// 11 14.2 |
danjulio | 0:e69d086cb053 | 541 | /// 13 15 |
danjulio | 0:e69d086cb053 | 542 | /// 14 16 |
danjulio | 0:e69d086cb053 | 543 | /// \endcode |
danjulio | 0:e69d086cb053 | 544 | /// (Caution: we dont claim laboratory accuracy for these power measurements) |
danjulio | 0:e69d086cb053 | 545 | /// You would not expect to get anywhere near these powers to air with a simple 1/4 wavelength wire antenna. |
danjulio | 0:e69d086cb053 | 546 | class RH_RF95 : public RHGenericDriver |
danjulio | 0:e69d086cb053 | 547 | { |
danjulio | 0:e69d086cb053 | 548 | public: |
danjulio | 0:e69d086cb053 | 549 | /// \brief Defines register values for a set of modem configuration registers |
danjulio | 0:e69d086cb053 | 550 | /// |
danjulio | 0:e69d086cb053 | 551 | /// Defines register values for a set of modem configuration registers |
danjulio | 0:e69d086cb053 | 552 | /// that can be passed to setModemRegisters() if none of the choices in |
danjulio | 0:e69d086cb053 | 553 | /// ModemConfigChoice suit your need setModemRegisters() writes the |
danjulio | 0:e69d086cb053 | 554 | /// register values from this structure to the appropriate registers |
danjulio | 0:e69d086cb053 | 555 | /// to set the desired spreading factor, coding rate and bandwidth |
danjulio | 0:e69d086cb053 | 556 | typedef struct |
danjulio | 0:e69d086cb053 | 557 | { |
danjulio | 0:e69d086cb053 | 558 | uint8_t reg_1d; ///< Value for register RH_RF95_REG_1D_MODEM_CONFIG1 |
danjulio | 0:e69d086cb053 | 559 | uint8_t reg_1e; ///< Value for register RH_RF95_REG_1E_MODEM_CONFIG2 |
danjulio | 0:e69d086cb053 | 560 | uint8_t reg_26; ///< Value for register RH_RF95_REG_26_MODEM_CONFIG3 |
danjulio | 0:e69d086cb053 | 561 | } ModemConfig; |
danjulio | 0:e69d086cb053 | 562 | |
danjulio | 0:e69d086cb053 | 563 | /// Choices for setModemConfig() for a selected subset of common |
danjulio | 0:e69d086cb053 | 564 | /// data rates. If you need another configuration, |
danjulio | 0:e69d086cb053 | 565 | /// determine the necessary settings and call setModemRegisters() with your |
danjulio | 0:e69d086cb053 | 566 | /// desired settings. It might be helpful to use the LoRa calculator mentioned in |
danjulio | 0:e69d086cb053 | 567 | /// http://www.semtech.com/images/datasheet/LoraDesignGuide_STD.pdf |
danjulio | 0:e69d086cb053 | 568 | /// These are indexes into MODEM_CONFIG_TABLE. We strongly recommend you use these symbolic |
danjulio | 0:e69d086cb053 | 569 | /// definitions and not their integer equivalents: its possible that new values will be |
danjulio | 0:e69d086cb053 | 570 | /// introduced in later versions (though we will try to avoid it). |
danjulio | 0:e69d086cb053 | 571 | /// Caution: if you are using slow packet rates and long packets with RHReliableDatagram or subclasses |
danjulio | 0:e69d086cb053 | 572 | /// you may need to change the RHReliableDatagram timeout for reliable operations. |
danjulio | 0:e69d086cb053 | 573 | /// Caution: for some slow rates nad with ReliableDatagrams youi may need to increase the reply timeout |
danjulio | 0:e69d086cb053 | 574 | /// with manager.setTimeout() to |
danjulio | 0:e69d086cb053 | 575 | /// deal with the long transmission times. |
danjulio | 0:e69d086cb053 | 576 | typedef enum |
danjulio | 0:e69d086cb053 | 577 | { |
danjulio | 0:e69d086cb053 | 578 | Bw125Cr45Sf128 = 0, ///< Bw = 125 kHz, Cr = 4/5, Sf = 128chips/symbol, CRC on. Default medium range |
danjulio | 0:e69d086cb053 | 579 | Bw500Cr45Sf128, ///< Bw = 500 kHz, Cr = 4/5, Sf = 128chips/symbol, CRC on. Fast+short range |
danjulio | 0:e69d086cb053 | 580 | Bw31_25Cr48Sf512, ///< Bw = 31.25 kHz, Cr = 4/8, Sf = 512chips/symbol, CRC on. Slow+long range |
danjulio | 0:e69d086cb053 | 581 | Bw125Cr48Sf4096, ///< Bw = 125 kHz, Cr = 4/8, Sf = 4096chips/symbol, CRC on. Slow+long range |
danjulio | 0:e69d086cb053 | 582 | } ModemConfigChoice; |
danjulio | 0:e69d086cb053 | 583 | |
danjulio | 0:e69d086cb053 | 584 | /// Constructor. You can have multiple instances, but each instance must have its own |
danjulio | 0:e69d086cb053 | 585 | /// interrupt and slave select pin. After constructing, you must call init() to initialise the interface |
danjulio | 0:e69d086cb053 | 586 | /// and the radio module. A maximum of 3 instances can co-exist on one processor, provided there are sufficient |
danjulio | 0:e69d086cb053 | 587 | /// distinct interrupt lines, one for each instance. |
danjulio | 0:e69d086cb053 | 588 | /// \param[in] slaveSelectPin the Arduino pin number of the output to use to select the RH_RF22 before |
danjulio | 0:e69d086cb053 | 589 | /// accessing it. Defaults to the normal SS pin for your Arduino (D10 for Diecimila, Uno etc, D53 for Mega, D10 for Maple) |
danjulio | 0:e69d086cb053 | 590 | /// \param[in] interruptPin The interrupt Pin number that is connected to the RFM DIO0 interrupt line. |
danjulio | 0:e69d086cb053 | 591 | /// Defaults to pin 2, as required by Anarduino MinWirelessLoRa module. |
danjulio | 0:e69d086cb053 | 592 | /// Caution: You must specify an interrupt capable pin. |
danjulio | 0:e69d086cb053 | 593 | /// On many Arduino boards, there are limitations as to which pins may be used as interrupts. |
danjulio | 0:e69d086cb053 | 594 | /// On Leonardo pins 0, 1, 2 or 3. On Mega2560 pins 2, 3, 18, 19, 20, 21. On Due and Teensy, any digital pin. |
danjulio | 0:e69d086cb053 | 595 | /// On Arduino Zero from arduino.cc, any digital pin other than 4. |
danjulio | 0:e69d086cb053 | 596 | /// On Arduino M0 Pro from arduino.org, any digital pin other than 2. |
danjulio | 0:e69d086cb053 | 597 | /// On other Arduinos pins 2 or 3. |
danjulio | 0:e69d086cb053 | 598 | /// See http://arduino.cc/en/Reference/attachInterrupt for more details. |
danjulio | 0:e69d086cb053 | 599 | /// On Chipkit Uno32, pins 38, 2, 7, 8, 35. |
danjulio | 0:e69d086cb053 | 600 | /// On other boards, any digital pin may be used. |
danjulio | 0:e69d086cb053 | 601 | /// \param[in] spi Pointer to the SPI interface object to use. |
danjulio | 0:e69d086cb053 | 602 | /// \param[in] ssNum the swspi slave select number to use |
danjulio | 0:e69d086cb053 | 603 | RH_RF95(swspi& spi, int ssNum); |
danjulio | 0:e69d086cb053 | 604 | |
danjulio | 0:e69d086cb053 | 605 | /// Initialise the Driver transport hardware and software. |
danjulio | 0:e69d086cb053 | 606 | /// Make sure the Driver is properly configured before calling init(). |
danjulio | 0:e69d086cb053 | 607 | /// \return true if initialisation succeeded. |
danjulio | 0:e69d086cb053 | 608 | virtual bool init(); |
danjulio | 0:e69d086cb053 | 609 | |
danjulio | 0:e69d086cb053 | 610 | /// Prints the value of all chip registers |
danjulio | 0:e69d086cb053 | 611 | /// to the Serial device if RH_HAVE_SERIAL is defined for the current platform |
danjulio | 0:e69d086cb053 | 612 | /// For debugging purposes only. |
danjulio | 0:e69d086cb053 | 613 | /// \return true on success |
danjulio | 0:e69d086cb053 | 614 | bool printRegisters(); |
danjulio | 0:e69d086cb053 | 615 | |
danjulio | 0:e69d086cb053 | 616 | /// Sets all the registered required to configure the data modem in the RF95/96/97/98, including the bandwidth, |
danjulio | 0:e69d086cb053 | 617 | /// spreading factor etc. You can use this to configure the modem with custom configurations if none of the |
danjulio | 0:e69d086cb053 | 618 | /// canned configurations in ModemConfigChoice suit you. |
danjulio | 0:e69d086cb053 | 619 | /// \param[in] config A ModemConfig structure containing values for the modem configuration registers. |
danjulio | 0:e69d086cb053 | 620 | void setModemRegisters(const ModemConfig* config); |
danjulio | 0:e69d086cb053 | 621 | |
danjulio | 0:e69d086cb053 | 622 | /// Select one of the predefined modem configurations. If you need a modem configuration not provided |
danjulio | 0:e69d086cb053 | 623 | /// here, use setModemRegisters() with your own ModemConfig. |
danjulio | 0:e69d086cb053 | 624 | /// \param[in] index The configuration choice. |
danjulio | 0:e69d086cb053 | 625 | /// \return true if index is a valid choice. |
danjulio | 0:e69d086cb053 | 626 | bool setModemConfig(ModemConfigChoice index); |
danjulio | 0:e69d086cb053 | 627 | |
danjulio | 0:e69d086cb053 | 628 | /// Tests whether a new message is available |
danjulio | 0:e69d086cb053 | 629 | /// from the Driver. |
danjulio | 0:e69d086cb053 | 630 | /// On most drivers, this will also put the Driver into RHModeRx mode until |
danjulio | 0:e69d086cb053 | 631 | /// a message is actually received by the transport, when it wil be returned to RHModeIdle. |
danjulio | 0:e69d086cb053 | 632 | /// This can be called multiple times in a timeout loop |
danjulio | 0:e69d086cb053 | 633 | /// \return true if a new, complete, error-free uncollected message is available to be retreived by recv() |
danjulio | 0:e69d086cb053 | 634 | virtual bool available(); |
danjulio | 0:e69d086cb053 | 635 | |
danjulio | 0:e69d086cb053 | 636 | /// Turns the receiver on if it not already on. |
danjulio | 0:e69d086cb053 | 637 | /// If there is a valid message available, copy it to buf and return true |
danjulio | 0:e69d086cb053 | 638 | /// else return false. |
danjulio | 0:e69d086cb053 | 639 | /// If a message is copied, *len is set to the length (Caution, 0 length messages are permitted). |
danjulio | 0:e69d086cb053 | 640 | /// You should be sure to call this function frequently enough to not miss any messages |
danjulio | 0:e69d086cb053 | 641 | /// It is recommended that you call it in your main loop. |
danjulio | 0:e69d086cb053 | 642 | /// \param[in] buf Location to copy the received message |
danjulio | 0:e69d086cb053 | 643 | /// \param[in,out] len Pointer to available space in buf. Set to the actual number of octets copied. |
danjulio | 0:e69d086cb053 | 644 | /// \return true if a valid message was copied to buf |
danjulio | 0:e69d086cb053 | 645 | virtual bool recv(uint8_t* buf, uint8_t* len); |
danjulio | 0:e69d086cb053 | 646 | |
danjulio | 0:e69d086cb053 | 647 | /// Waits until any previous transmit packet is finished being transmitted with waitPacketSent(). |
danjulio | 0:e69d086cb053 | 648 | /// Then optionally waits for Channel Activity Detection (CAD) |
danjulio | 0:e69d086cb053 | 649 | /// to show the channnel is clear (if the radio supports CAD) by calling waitCAD(). |
danjulio | 0:e69d086cb053 | 650 | /// Then loads a message into the transmitter and starts the transmitter. Note that a message length |
danjulio | 0:e69d086cb053 | 651 | /// of 0 is permitted. |
danjulio | 0:e69d086cb053 | 652 | /// \param[in] data Array of data to be sent |
danjulio | 0:e69d086cb053 | 653 | /// \param[in] len Number of bytes of data to send |
danjulio | 0:e69d086cb053 | 654 | /// specify the maximum time in ms to wait. If 0 (the default) do not wait for CAD before transmitting. |
danjulio | 0:e69d086cb053 | 655 | /// \return true if the message length was valid and it was correctly queued for transmit. Return false |
danjulio | 0:e69d086cb053 | 656 | /// if CAD was requested and the CAD timeout timed out before clear channel was detected. |
danjulio | 0:e69d086cb053 | 657 | virtual bool send(const uint8_t* data, uint8_t len); |
danjulio | 0:e69d086cb053 | 658 | |
danjulio | 0:e69d086cb053 | 659 | /// Sets the length of the preamble |
danjulio | 0:e69d086cb053 | 660 | /// in bytes. |
danjulio | 0:e69d086cb053 | 661 | /// Caution: this should be set to the same |
danjulio | 0:e69d086cb053 | 662 | /// value on all nodes in your network. Default is 8. |
danjulio | 0:e69d086cb053 | 663 | /// Sets the message preamble length in RH_RF95_REG_??_PREAMBLE_?SB |
danjulio | 0:e69d086cb053 | 664 | /// \param[in] bytes Preamble length in bytes. |
danjulio | 0:e69d086cb053 | 665 | void setPreambleLength(uint16_t bytes); |
danjulio | 0:e69d086cb053 | 666 | |
danjulio | 0:e69d086cb053 | 667 | /// Returns the maximum message length |
danjulio | 0:e69d086cb053 | 668 | /// available in this Driver. |
danjulio | 0:e69d086cb053 | 669 | /// \return The maximum legal message length |
danjulio | 0:e69d086cb053 | 670 | virtual uint8_t maxMessageLength(); |
danjulio | 0:e69d086cb053 | 671 | |
danjulio | 0:e69d086cb053 | 672 | /// Sets the transmitter and receiver |
danjulio | 0:e69d086cb053 | 673 | /// centre frequency. |
danjulio | 0:e69d086cb053 | 674 | /// \param[in] centre Frequency in MHz. 137.0 to 1020.0. Caution: RFM95/96/97/98 comes in several |
danjulio | 0:e69d086cb053 | 675 | /// different frequency ranges, and setting a frequency outside that range of your radio will probably not work |
danjulio | 0:e69d086cb053 | 676 | /// \return true if the selected frquency centre is within range |
danjulio | 0:e69d086cb053 | 677 | bool setFrequency(float centre); |
danjulio | 0:e69d086cb053 | 678 | |
danjulio | 0:e69d086cb053 | 679 | /// If current mode is Rx or Tx changes it to Idle. If the transmitter or receiver is running, |
danjulio | 0:e69d086cb053 | 680 | /// disables them. |
danjulio | 0:e69d086cb053 | 681 | void setModeIdle(); |
danjulio | 0:e69d086cb053 | 682 | |
danjulio | 0:e69d086cb053 | 683 | /// If current mode is Tx or Idle, changes it to Rx. |
danjulio | 0:e69d086cb053 | 684 | /// Starts the receiver in the RF95/96/97/98. |
danjulio | 0:e69d086cb053 | 685 | void setModeRx(); |
danjulio | 0:e69d086cb053 | 686 | |
danjulio | 0:e69d086cb053 | 687 | /// If current mode is Rx or Idle, changes it to Rx. F |
danjulio | 0:e69d086cb053 | 688 | /// Starts the transmitter in the RF95/96/97/98. |
danjulio | 0:e69d086cb053 | 689 | void setModeTx(); |
danjulio | 0:e69d086cb053 | 690 | |
danjulio | 0:e69d086cb053 | 691 | /// Sets the transmitter power output level, and configures the transmitter pin. |
danjulio | 0:e69d086cb053 | 692 | /// Be a good neighbour and set the lowest power level you need. |
danjulio | 0:e69d086cb053 | 693 | /// Some SX1276/77/78/79 and compatible modules (such as RFM95/96/97/98) |
danjulio | 0:e69d086cb053 | 694 | /// use the PA_BOOST transmitter pin for high power output (and optionally the PA_DAC) |
danjulio | 0:e69d086cb053 | 695 | /// while some (such as the Modtronix inAir4 and inAir9) |
danjulio | 0:e69d086cb053 | 696 | /// use the RFO transmitter pin for lower power but higher efficiency. |
danjulio | 0:e69d086cb053 | 697 | /// You must set the appropriate power level and useRFO argument for your module. |
danjulio | 0:e69d086cb053 | 698 | /// Check with your module manufacturer which transmtter pin is used on your module |
danjulio | 0:e69d086cb053 | 699 | /// to ensure you are setting useRFO correctly. |
danjulio | 0:e69d086cb053 | 700 | /// Failure to do so will result in very low |
danjulio | 0:e69d086cb053 | 701 | /// transmitter power output. |
danjulio | 0:e69d086cb053 | 702 | /// Caution: legal power limits may apply in certain countries. |
danjulio | 0:e69d086cb053 | 703 | /// After init(), the power will be set to 13dBm, with useRFO false (ie PA_BOOST enabled). |
danjulio | 0:e69d086cb053 | 704 | /// \param[in] power Transmitter power level in dBm. For RFM95/96/97/98 LORA with useRFO false, |
danjulio | 0:e69d086cb053 | 705 | /// valid values are from +5 to +23. |
danjulio | 0:e69d086cb053 | 706 | /// For Modtronix inAir4 and inAir9 with useRFO true (ie RFO pins in use), |
danjulio | 0:e69d086cb053 | 707 | /// valid values are from -1 to 14. |
danjulio | 0:e69d086cb053 | 708 | /// \param[in] useRFO If true, enables the use of the RFO transmitter pins instead of |
danjulio | 0:e69d086cb053 | 709 | /// the PA_BOOST pin (false). Choose the correct setting for your module. |
danjulio | 0:e69d086cb053 | 710 | void setTxPower(int8_t power, bool useRFO = false); |
danjulio | 0:e69d086cb053 | 711 | |
danjulio | 0:e69d086cb053 | 712 | /// Sets the radio into low-power sleep mode. |
danjulio | 0:e69d086cb053 | 713 | /// If successful, the transport will stay in sleep mode until woken by |
danjulio | 0:e69d086cb053 | 714 | /// changing mode it idle, transmit or receive (eg by calling send(), recv(), available() etc) |
danjulio | 0:e69d086cb053 | 715 | /// Caution: there is a time penalty as the radio takes a finite time to wake from sleep mode. |
danjulio | 0:e69d086cb053 | 716 | /// \return true if sleep mode was successfully entered. |
danjulio | 0:e69d086cb053 | 717 | virtual bool sleep(); |
danjulio | 0:e69d086cb053 | 718 | |
danjulio | 0:e69d086cb053 | 719 | // Bent G Christensen (bentor@gmail.com), 08/15/2016 |
danjulio | 0:e69d086cb053 | 720 | /// Use the radio's Channel Activity Detect (CAD) function to detect channel activity. |
danjulio | 0:e69d086cb053 | 721 | /// Sets the RF95 radio into CAD mode and waits until CAD detection is complete. |
danjulio | 0:e69d086cb053 | 722 | /// To be used in a listen-before-talk mechanism (Collision Avoidance) |
danjulio | 0:e69d086cb053 | 723 | /// with a reasonable time backoff algorithm. |
danjulio | 0:e69d086cb053 | 724 | /// This is called automatically by waitCAD(). |
danjulio | 0:e69d086cb053 | 725 | /// \return true if channel is in use. |
danjulio | 0:e69d086cb053 | 726 | virtual bool isChannelActive(); |
danjulio | 0:e69d086cb053 | 727 | |
danjulio | 0:e69d086cb053 | 728 | /// Enable TCXO mode |
danjulio | 0:e69d086cb053 | 729 | /// Call this immediately after init(), to force your radio to use an external |
danjulio | 0:e69d086cb053 | 730 | /// frequency source, such as a Temperature Compensated Crystal Oscillator (TCXO). |
danjulio | 0:e69d086cb053 | 731 | /// See the comments in the main documentation about the sensitivity of this radio to |
danjulio | 0:e69d086cb053 | 732 | /// clock frequency especially when using narrow bandwidths. |
danjulio | 0:e69d086cb053 | 733 | /// Leaves the module in sleep mode. |
danjulio | 0:e69d086cb053 | 734 | /// Caution, this function has not been tested by us. |
danjulio | 0:e69d086cb053 | 735 | void enableTCXO(); |
danjulio | 0:e69d086cb053 | 736 | |
danjulio | 0:e69d086cb053 | 737 | /// Returns the last measured frequency error. |
danjulio | 0:e69d086cb053 | 738 | /// The LoRa receiver estimates the frequency offset between the receiver centre frequency |
danjulio | 0:e69d086cb053 | 739 | /// and that of the received LoRa signal. This function returns the estimates offset (in Hz) |
danjulio | 0:e69d086cb053 | 740 | /// of the last received message. Caution: this measurement is not absolute, but is measured |
danjulio | 0:e69d086cb053 | 741 | /// relative to the local receiver's oscillator. |
danjulio | 0:e69d086cb053 | 742 | /// Apparent errors may be due to the transmitter, the receiver or both. |
danjulio | 0:e69d086cb053 | 743 | /// \return The estimated centre frequency offset in Hz of the last received message. |
danjulio | 0:e69d086cb053 | 744 | /// If the modem bandwidth selector in |
danjulio | 0:e69d086cb053 | 745 | /// register RH_RF95_REG_1D_MODEM_CONFIG1 is invalid, returns 0. |
danjulio | 0:e69d086cb053 | 746 | int frequencyError(); |
danjulio | 0:e69d086cb053 | 747 | |
danjulio | 0:e69d086cb053 | 748 | /// Returns the Signal-to-noise ratio (SNR) of the last received message, as measured |
danjulio | 0:e69d086cb053 | 749 | /// by the receiver. |
danjulio | 0:e69d086cb053 | 750 | /// \return SNR of the last received message in dB |
danjulio | 0:e69d086cb053 | 751 | int lastSNR(); |
danjulio | 0:e69d086cb053 | 752 | |
danjulio | 0:e69d086cb053 | 753 | /// This is a low level function to handle the interrupts for one instance of RH_RF95. |
danjulio | 0:e69d086cb053 | 754 | /// Must be called from user code in mbed because the swspi library mutex cannot be |
danjulio | 0:e69d086cb053 | 755 | /// executed in an ISR. It should be executed when the ISR pin is seen low. |
danjulio | 0:e69d086cb053 | 756 | void handleInterrupt(); |
danjulio | 0:e69d086cb053 | 757 | |
danjulio | 0:e69d086cb053 | 758 | protected: |
danjulio | 0:e69d086cb053 | 759 | /// Examine the revceive buffer to determine whether the message is for this node |
danjulio | 0:e69d086cb053 | 760 | void validateRxBuf(); |
danjulio | 0:e69d086cb053 | 761 | |
danjulio | 0:e69d086cb053 | 762 | /// Clear our local receive buffer |
danjulio | 0:e69d086cb053 | 763 | void clearRxBuf(); |
danjulio | 0:e69d086cb053 | 764 | |
danjulio | 0:e69d086cb053 | 765 | private: |
danjulio | 0:e69d086cb053 | 766 | /// SPI |
danjulio | 0:e69d086cb053 | 767 | swspi& _spi; |
danjulio | 0:e69d086cb053 | 768 | int _ssn; |
danjulio | 0:e69d086cb053 | 769 | |
danjulio | 0:e69d086cb053 | 770 | /// Number of octets in the buffer |
danjulio | 0:e69d086cb053 | 771 | volatile uint8_t _bufLen; |
danjulio | 0:e69d086cb053 | 772 | |
danjulio | 0:e69d086cb053 | 773 | /// The receiver/transmitter buffer |
danjulio | 0:e69d086cb053 | 774 | uint8_t _buf[RH_RF95_MAX_PAYLOAD_LEN]; |
danjulio | 0:e69d086cb053 | 775 | |
danjulio | 0:e69d086cb053 | 776 | /// True when there is a valid message in the buffer |
danjulio | 0:e69d086cb053 | 777 | volatile bool _rxBufValid; |
danjulio | 0:e69d086cb053 | 778 | |
danjulio | 0:e69d086cb053 | 779 | // True if we are using the HF port (779.0 MHz and above) |
danjulio | 0:e69d086cb053 | 780 | bool _usingHFport; |
danjulio | 0:e69d086cb053 | 781 | |
danjulio | 0:e69d086cb053 | 782 | // Last measured SNR, dB |
danjulio | 0:e69d086cb053 | 783 | int8_t _lastSNR; |
danjulio | 0:e69d086cb053 | 784 | }; |
danjulio | 0:e69d086cb053 | 785 | |
danjulio | 0:e69d086cb053 | 786 | /// @example rf95_client.pde |
danjulio | 0:e69d086cb053 | 787 | /// @example rf95_server.pde |
danjulio | 0:e69d086cb053 | 788 | /// @example rf95_reliable_datagram_client.pde |
danjulio | 0:e69d086cb053 | 789 | /// @example rf95_reliable_datagram_server.pde |
danjulio | 0:e69d086cb053 | 790 | |
danjulio | 0:e69d086cb053 | 791 | #endif |
danjulio | 0:e69d086cb053 | 792 |