RadioHead

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?

UserRevisionLine numberNew 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