Quick & dirty port of the RadioHead library with minimal support for the RF95 radio. It is designed to be used with the swspi library which in turn is designed to be used on the MAX32630FTHR board.

Dependents:   Rocket

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