Driver library for SX1272/SX1276 transceivers

Dependents:   LORA_RX LORA_TX WindConcentrator hid_test ... more

/media/uploads/dudmuck/lora.png

Driver library for SX1272 and SX1276 radio transceivers.

This device uses CSS modulation to provide much improved link budget. The RF hardware is same as in FSK devices, just with added LoRa spread-spectrum modem.

This library provides functions to configure radio chip and transmit & receive packets.

Using This Library

Library function service_radio() must be called continuously from main loop, to service interrupts from radio.

/media/uploads/dudmuck/sx1272rf1_connector_300.jpg

Board Specific implementation

FunctionPointer for rf_switch callback allows the program to implement control of RF switch unique to their board. Example options are:

  • SKY13373 for external power amplifier implementation. Requires two DigitalOut pins.
  • SKY13350 using PA_BOOST. requires two DigitalOut pins.
  • PE4259-63: controlled directly by radio chip, no software function needed. However, in the case of SX1276MB1xAS, the RXTX pin on IO2 should be driven by this callback function when R16 is installed (without R15) on this shield board.

Some configurations may need to force the use of RFO or PA_BOOST, or a board could offer both options. The rf_switch function pointer callback should support the implementation choice on the board.

further reading

Committer:
dudmuck
Date:
Tue Jun 02 01:25:47 2015 +0000
Revision:
18:0ecb6adb7c0b
Parent:
17:59279bc8cdab
Child:
19:1ee6ef1ab73f
sx1276 optimization for frequency error with 500KHz bw

Who changed what in which revision?

UserRevisionLine numberNew contents of line
dudmuck 2:fdae76e1215e 1 #include "sx127x_lora.h"
dudmuck 2:fdae76e1215e 2
dudmuck 2:fdae76e1215e 3 /* SX127x driver
dudmuck 2:fdae76e1215e 4 * Copyright (c) 2013 Semtech
dudmuck 2:fdae76e1215e 5 *
dudmuck 2:fdae76e1215e 6 * Licensed under the Apache License, Version 2.0 (the "License");
dudmuck 2:fdae76e1215e 7 * you may not use this file except in compliance with the License.
dudmuck 2:fdae76e1215e 8 * You may obtain a copy of the License at
dudmuck 2:fdae76e1215e 9 *
dudmuck 2:fdae76e1215e 10 * http://www.apache.org/licenses/LICENSE-2.0
dudmuck 2:fdae76e1215e 11 *
dudmuck 2:fdae76e1215e 12 * Unless required by applicable law or agreed to in writing, software
dudmuck 2:fdae76e1215e 13 * distributed under the License is distributed on an "AS IS" BASIS,
dudmuck 2:fdae76e1215e 14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
dudmuck 2:fdae76e1215e 15 * See the License for the specific language governing permissions and
dudmuck 2:fdae76e1215e 16 * limitations under the License.
dudmuck 2:fdae76e1215e 17 */
dudmuck 2:fdae76e1215e 18
dudmuck 3:3bf2515b1eed 19 SX127x_lora::SX127x_lora(SX127x& r) : m_xcvr(r)
dudmuck 2:fdae76e1215e 20 {
dudmuck 2:fdae76e1215e 21 RegModemConfig.octet = m_xcvr.read_reg(REG_LR_MODEMCONFIG);
dudmuck 2:fdae76e1215e 22 RegModemConfig2.octet = m_xcvr.read_reg(REG_LR_MODEMCONFIG2);
dudmuck 2:fdae76e1215e 23 RegTest31.octet = m_xcvr.read_reg(REG_LR_TEST31);
dudmuck 17:59279bc8cdab 24 RegTest33.octet = m_xcvr.read_reg(REG_LR_TEST33); // invert_i_q
dudmuck 17:59279bc8cdab 25 RegDriftInvert.octet = m_xcvr.read_reg(REG_LR_DRIFT_INVERT);
dudmuck 2:fdae76e1215e 26
dudmuck 2:fdae76e1215e 27 // CRC for TX is disabled by default
dudmuck 2:fdae76e1215e 28 setRxPayloadCrcOn(true);
dudmuck 2:fdae76e1215e 29 }
dudmuck 2:fdae76e1215e 30
dudmuck 2:fdae76e1215e 31 SX127x_lora::~SX127x_lora()
dudmuck 2:fdae76e1215e 32 {
dudmuck 2:fdae76e1215e 33 }
dudmuck 2:fdae76e1215e 34
dudmuck 2:fdae76e1215e 35 void SX127x_lora::write_fifo(uint8_t len)
dudmuck 2:fdae76e1215e 36 {
dudmuck 2:fdae76e1215e 37 int i;
dudmuck 2:fdae76e1215e 38
dudmuck 2:fdae76e1215e 39 m_xcvr.m_cs = 0;
dudmuck 2:fdae76e1215e 40 m_xcvr.m_spi.write(REG_FIFO | 0x80); // bit7 is high for writing to radio
dudmuck 2:fdae76e1215e 41
dudmuck 2:fdae76e1215e 42 for (i = 0; i < len; i++) {
dudmuck 2:fdae76e1215e 43 m_xcvr.m_spi.write(m_xcvr.tx_buf[i]);
dudmuck 2:fdae76e1215e 44 }
dudmuck 2:fdae76e1215e 45 m_xcvr.m_cs = 1;
dudmuck 2:fdae76e1215e 46 }
dudmuck 2:fdae76e1215e 47
dudmuck 2:fdae76e1215e 48 void SX127x_lora::read_fifo(uint8_t len)
dudmuck 2:fdae76e1215e 49 {
dudmuck 2:fdae76e1215e 50 int i;
dudmuck 2:fdae76e1215e 51
dudmuck 2:fdae76e1215e 52 m_xcvr.m_cs = 0;
dudmuck 2:fdae76e1215e 53 m_xcvr.m_spi.write(REG_FIFO); // bit7 is low for reading from radio
dudmuck 2:fdae76e1215e 54 for (i = 0; i < len; i++) {
dudmuck 2:fdae76e1215e 55 m_xcvr.rx_buf[i] = m_xcvr.m_spi.write(0);
dudmuck 2:fdae76e1215e 56 }
dudmuck 2:fdae76e1215e 57 m_xcvr.m_cs = 1;
dudmuck 2:fdae76e1215e 58 }
dudmuck 2:fdae76e1215e 59
dudmuck 2:fdae76e1215e 60 void SX127x_lora::enable()
dudmuck 2:fdae76e1215e 61 {
dudmuck 2:fdae76e1215e 62 m_xcvr.set_opmode(RF_OPMODE_SLEEP);
dudmuck 2:fdae76e1215e 63
dudmuck 2:fdae76e1215e 64 m_xcvr.RegOpMode.bits.LongRangeMode = 1;
dudmuck 2:fdae76e1215e 65 m_xcvr.write_reg(REG_OPMODE, m_xcvr.RegOpMode.octet);
dudmuck 2:fdae76e1215e 66
dudmuck 2:fdae76e1215e 67 /*RegOpMode.octet = read_reg(REG_OPMODE);
dudmuck 2:fdae76e1215e 68 printf("setloraon:%02x\r\n", RegOpMode.octet);*/
dudmuck 2:fdae76e1215e 69
dudmuck 2:fdae76e1215e 70
dudmuck 2:fdae76e1215e 71 /* // RxDone RxTimeout FhssChangeChannel CadDone
dudmuck 2:fdae76e1215e 72 SX1272LR->RegDioMapping1 = RFLR_DIOMAPPING1_DIO0_00 | RFLR_DIOMAPPING1_DIO1_00 | RFLR_DIOMAPPING1_DIO2_00 | RFLR_DIOMAPPING1_DIO3_00;
dudmuck 2:fdae76e1215e 73 // CadDetected ModeReady
dudmuck 2:fdae76e1215e 74 SX1272LR->RegDioMapping2 = RFLR_DIOMAPPING2_DIO4_00 | RFLR_DIOMAPPING2_DIO5_00;
dudmuck 2:fdae76e1215e 75 SX1272WriteBuffer( REG_LR_DIOMAPPING1, &SX1272LR->RegDioMapping1, 2 );*/
dudmuck 2:fdae76e1215e 76 m_xcvr.RegDioMapping1.bits.Dio0Mapping = 0; // DIO0 to RxDone
dudmuck 2:fdae76e1215e 77 m_xcvr.RegDioMapping1.bits.Dio1Mapping = 0;
dudmuck 2:fdae76e1215e 78 m_xcvr.write_reg(REG_DIOMAPPING1, m_xcvr.RegDioMapping1.octet);
dudmuck 2:fdae76e1215e 79
dudmuck 2:fdae76e1215e 80 // todo: read LoRa regsiters
dudmuck 2:fdae76e1215e 81 //SX1272ReadBuffer( REG_LR_OPMODE, SX1272Regs + 1, 0x70 - 1 );
dudmuck 2:fdae76e1215e 82
dudmuck 2:fdae76e1215e 83 m_xcvr.set_opmode(RF_OPMODE_STANDBY);
dudmuck 2:fdae76e1215e 84 }
dudmuck 2:fdae76e1215e 85
dudmuck 2:fdae76e1215e 86 uint8_t SX127x_lora::getCodingRate(bool from_rx)
dudmuck 2:fdae76e1215e 87 {
dudmuck 2:fdae76e1215e 88 if (from_rx) {
dudmuck 2:fdae76e1215e 89 // expected RegModemStatus was read on RxDone interrupt
dudmuck 2:fdae76e1215e 90 return RegModemStatus.bits.RxCodingRate;
dudmuck 2:fdae76e1215e 91 } else { // transmitted coding rate...
dudmuck 2:fdae76e1215e 92 if (m_xcvr.type == SX1276)
dudmuck 2:fdae76e1215e 93 return RegModemConfig.sx1276bits.CodingRate;
dudmuck 2:fdae76e1215e 94 else if (m_xcvr.type == SX1272)
dudmuck 2:fdae76e1215e 95 return RegModemConfig.sx1272bits.CodingRate;
dudmuck 2:fdae76e1215e 96 else
dudmuck 2:fdae76e1215e 97 return 0;
dudmuck 2:fdae76e1215e 98 }
dudmuck 2:fdae76e1215e 99 }
dudmuck 2:fdae76e1215e 100
dudmuck 2:fdae76e1215e 101
dudmuck 2:fdae76e1215e 102
dudmuck 2:fdae76e1215e 103 void SX127x_lora::setCodingRate(uint8_t cr)
dudmuck 2:fdae76e1215e 104 {
dudmuck 2:fdae76e1215e 105 if (!m_xcvr.RegOpMode.bits.LongRangeMode)
dudmuck 2:fdae76e1215e 106 return;
dudmuck 2:fdae76e1215e 107
dudmuck 2:fdae76e1215e 108 if (m_xcvr.type == SX1276)
dudmuck 2:fdae76e1215e 109 RegModemConfig.sx1276bits.CodingRate = cr;
dudmuck 2:fdae76e1215e 110 else if (m_xcvr.type == SX1272)
dudmuck 2:fdae76e1215e 111 RegModemConfig.sx1272bits.CodingRate = cr;
dudmuck 2:fdae76e1215e 112 else
dudmuck 2:fdae76e1215e 113 return;
dudmuck 2:fdae76e1215e 114
dudmuck 2:fdae76e1215e 115 m_xcvr.write_reg(REG_LR_MODEMCONFIG, RegModemConfig.octet);
dudmuck 2:fdae76e1215e 116 }
dudmuck 2:fdae76e1215e 117
dudmuck 2:fdae76e1215e 118
dudmuck 2:fdae76e1215e 119
dudmuck 2:fdae76e1215e 120 bool SX127x_lora::getHeaderMode(void)
dudmuck 2:fdae76e1215e 121 {
dudmuck 2:fdae76e1215e 122 if (m_xcvr.type == SX1276)
dudmuck 2:fdae76e1215e 123 return RegModemConfig.sx1276bits.ImplicitHeaderModeOn;
dudmuck 2:fdae76e1215e 124 else if (m_xcvr.type == SX1272)
dudmuck 2:fdae76e1215e 125 return RegModemConfig.sx1272bits.ImplicitHeaderModeOn;
dudmuck 2:fdae76e1215e 126 else
dudmuck 2:fdae76e1215e 127 return false;
dudmuck 2:fdae76e1215e 128 }
dudmuck 2:fdae76e1215e 129
dudmuck 2:fdae76e1215e 130 void SX127x_lora::setHeaderMode(bool hm)
dudmuck 2:fdae76e1215e 131 {
dudmuck 2:fdae76e1215e 132 if (m_xcvr.type == SX1276)
dudmuck 2:fdae76e1215e 133 RegModemConfig.sx1276bits.ImplicitHeaderModeOn = hm;
dudmuck 2:fdae76e1215e 134 else if (m_xcvr.type == SX1272)
dudmuck 2:fdae76e1215e 135 RegModemConfig.sx1272bits.ImplicitHeaderModeOn = hm;
dudmuck 2:fdae76e1215e 136 else
dudmuck 2:fdae76e1215e 137 return;
dudmuck 2:fdae76e1215e 138
dudmuck 2:fdae76e1215e 139 m_xcvr.write_reg(REG_LR_MODEMCONFIG, RegModemConfig.octet);
dudmuck 2:fdae76e1215e 140 }
dudmuck 2:fdae76e1215e 141
dudmuck 2:fdae76e1215e 142
dudmuck 2:fdae76e1215e 143 uint8_t SX127x_lora::getBw(void)
dudmuck 2:fdae76e1215e 144 {
dudmuck 2:fdae76e1215e 145 if (m_xcvr.type == SX1276)
dudmuck 2:fdae76e1215e 146 return RegModemConfig.sx1276bits.Bw;
dudmuck 2:fdae76e1215e 147 else if (m_xcvr.type == SX1272)
dudmuck 2:fdae76e1215e 148 return RegModemConfig.sx1272bits.Bw;
dudmuck 2:fdae76e1215e 149 else
dudmuck 2:fdae76e1215e 150 return 0;
dudmuck 2:fdae76e1215e 151 }
dudmuck 15:3f3fc6792f97 152
dudmuck 15:3f3fc6792f97 153 int SX127x_lora::get_freq_error_Hz()
dudmuck 15:3f3fc6792f97 154 {
dudmuck 15:3f3fc6792f97 155 int freq_error;
dudmuck 15:3f3fc6792f97 156 float f, khz = 0;
dudmuck 15:3f3fc6792f97 157 freq_error = m_xcvr.read_reg(REG_LR_TEST28);
dudmuck 15:3f3fc6792f97 158 freq_error <<= 8;
dudmuck 15:3f3fc6792f97 159 freq_error += m_xcvr.read_reg(REG_LR_TEST29);
dudmuck 15:3f3fc6792f97 160 freq_error <<= 8;
dudmuck 15:3f3fc6792f97 161 freq_error += m_xcvr.read_reg(REG_LR_TEST2A);
dudmuck 15:3f3fc6792f97 162 if (freq_error & 0x80000) { // 20bit value is negative
dudmuck 15:3f3fc6792f97 163 //signed 20bit to 32bit
dudmuck 15:3f3fc6792f97 164 freq_error |= 0xfff00000;
dudmuck 15:3f3fc6792f97 165 }
dudmuck 15:3f3fc6792f97 166 f = freq_error / (float)XTAL_FREQ;
dudmuck 15:3f3fc6792f97 167 f *= (float)0x1000000; // 2^24
dudmuck 15:3f3fc6792f97 168 if (m_xcvr.type == SX1272) {
dudmuck 15:3f3fc6792f97 169 switch (RegModemConfig.sx1272bits.Bw) {
dudmuck 15:3f3fc6792f97 170 case 0: khz = 125; break;
dudmuck 15:3f3fc6792f97 171 case 1: khz = 250; break;
dudmuck 15:3f3fc6792f97 172 case 2: khz = 500; break;
dudmuck 15:3f3fc6792f97 173 }
dudmuck 15:3f3fc6792f97 174 } else if (m_xcvr.type == SX1276) {
dudmuck 15:3f3fc6792f97 175 switch (RegModemConfig.sx1276bits.Bw) {
dudmuck 15:3f3fc6792f97 176 case 0: khz = 7.8; break;
dudmuck 15:3f3fc6792f97 177 case 1: khz = 10.4; break;
dudmuck 15:3f3fc6792f97 178 case 2: khz = 15.6; break;
dudmuck 15:3f3fc6792f97 179 case 3: khz = 20.8; break;
dudmuck 15:3f3fc6792f97 180 case 4: khz = 31.25; break;
dudmuck 15:3f3fc6792f97 181 case 5: khz = 41.7; break;
dudmuck 15:3f3fc6792f97 182 case 6: khz = 62.5; break;
dudmuck 15:3f3fc6792f97 183 case 7: khz = 125; break;
dudmuck 15:3f3fc6792f97 184 case 8: khz = 250; break;
dudmuck 15:3f3fc6792f97 185 case 9: khz = 500; break;
dudmuck 15:3f3fc6792f97 186 }
dudmuck 15:3f3fc6792f97 187 }
dudmuck 15:3f3fc6792f97 188 f *= khz / 500;
dudmuck 15:3f3fc6792f97 189 return (int)f;
dudmuck 15:3f3fc6792f97 190 }
dudmuck 15:3f3fc6792f97 191
dudmuck 10:7382c260c4b1 192 float SX127x_lora::get_symbol_period()
dudmuck 10:7382c260c4b1 193 {
dudmuck 10:7382c260c4b1 194 float khz = 0;
dudmuck 10:7382c260c4b1 195
dudmuck 10:7382c260c4b1 196 if (m_xcvr.type == SX1276) {
dudmuck 10:7382c260c4b1 197 switch (RegModemConfig.sx1276bits.Bw) {
dudmuck 10:7382c260c4b1 198 case 0: khz = 7.8; break;
dudmuck 10:7382c260c4b1 199 case 1: khz = 10.4; break;
dudmuck 10:7382c260c4b1 200 case 2: khz = 15.6; break;
dudmuck 10:7382c260c4b1 201 case 3: khz = 20.8; break;
dudmuck 10:7382c260c4b1 202 case 4: khz = 31.25; break;
dudmuck 10:7382c260c4b1 203 case 5: khz = 41.7; break;
dudmuck 10:7382c260c4b1 204 case 6: khz = 62.5; break;
dudmuck 10:7382c260c4b1 205 case 7: khz = 125; break;
dudmuck 10:7382c260c4b1 206 case 8: khz = 250; break;
dudmuck 10:7382c260c4b1 207 case 9: khz = 500; break;
dudmuck 10:7382c260c4b1 208 }
dudmuck 10:7382c260c4b1 209 } else if (m_xcvr.type == SX1272) {
dudmuck 10:7382c260c4b1 210 switch (RegModemConfig.sx1272bits.Bw) {
dudmuck 10:7382c260c4b1 211 case 0: khz = 125; break;
dudmuck 10:7382c260c4b1 212 case 1: khz = 250; break;
dudmuck 10:7382c260c4b1 213 case 2: khz = 500; break;
dudmuck 10:7382c260c4b1 214 }
dudmuck 10:7382c260c4b1 215 }
dudmuck 10:7382c260c4b1 216
dudmuck 10:7382c260c4b1 217 // return symbol duration in milliseconds
dudmuck 10:7382c260c4b1 218 return (1 << RegModemConfig2.sx1276bits.SpreadingFactor) / khz;
dudmuck 10:7382c260c4b1 219 }
dudmuck 2:fdae76e1215e 220
dudmuck 16:3de8e1c465eb 221 void SX127x_lora::setBw_KHz(int khz)
dudmuck 16:3de8e1c465eb 222 {
dudmuck 16:3de8e1c465eb 223 uint8_t bw = 0;
dudmuck 16:3de8e1c465eb 224
dudmuck 16:3de8e1c465eb 225 if (m_xcvr.type == SX1276) {
dudmuck 16:3de8e1c465eb 226 if (khz <= 8) bw = 0;
dudmuck 16:3de8e1c465eb 227 else if (khz <= 11) bw = 1;
dudmuck 16:3de8e1c465eb 228 else if (khz <= 16) bw = 2;
dudmuck 16:3de8e1c465eb 229 else if (khz <= 21) bw = 3;
dudmuck 16:3de8e1c465eb 230 else if (khz <= 32) bw = 4;
dudmuck 16:3de8e1c465eb 231 else if (khz <= 42) bw = 5;
dudmuck 16:3de8e1c465eb 232 else if (khz <= 63) bw = 6;
dudmuck 16:3de8e1c465eb 233 else if (khz <= 125) bw = 7;
dudmuck 16:3de8e1c465eb 234 else if (khz <= 250) bw = 8;
dudmuck 16:3de8e1c465eb 235 else if (khz <= 500) bw = 9;
dudmuck 16:3de8e1c465eb 236 } else if (m_xcvr.type == SX1272) {
dudmuck 16:3de8e1c465eb 237 if (khz <= 125) bw = 0;
dudmuck 16:3de8e1c465eb 238 else if (khz <= 250) bw = 1;
dudmuck 16:3de8e1c465eb 239 else if (khz <= 500) bw = 2;
dudmuck 16:3de8e1c465eb 240 }
dudmuck 16:3de8e1c465eb 241
dudmuck 16:3de8e1c465eb 242 setBw(bw);
dudmuck 16:3de8e1c465eb 243 }
dudmuck 16:3de8e1c465eb 244
dudmuck 2:fdae76e1215e 245 void SX127x_lora::setBw(uint8_t bw)
dudmuck 2:fdae76e1215e 246 {
dudmuck 2:fdae76e1215e 247 if (!m_xcvr.RegOpMode.bits.LongRangeMode)
dudmuck 2:fdae76e1215e 248 return;
dudmuck 2:fdae76e1215e 249
dudmuck 10:7382c260c4b1 250 if (m_xcvr.type == SX1276) {
dudmuck 18:0ecb6adb7c0b 251 RegAutoDrift_t auto_drift;
dudmuck 18:0ecb6adb7c0b 252
dudmuck 2:fdae76e1215e 253 RegModemConfig.sx1276bits.Bw = bw;
dudmuck 10:7382c260c4b1 254 if (get_symbol_period() > 16)
dudmuck 10:7382c260c4b1 255 RegModemConfig3.sx1276bits.LowDataRateOptimize = 1;
dudmuck 10:7382c260c4b1 256 else
dudmuck 10:7382c260c4b1 257 RegModemConfig3.sx1276bits.LowDataRateOptimize = 0;
dudmuck 18:0ecb6adb7c0b 258 m_xcvr.write_reg(REG_LR_MODEMCONFIG3, RegModemConfig3.octet);
dudmuck 18:0ecb6adb7c0b 259
dudmuck 18:0ecb6adb7c0b 260 auto_drift.octet = m_xcvr.read_reg(REG_LR_SX1276_AUTO_DRIFT);
dudmuck 18:0ecb6adb7c0b 261 if (bw == 9) { // if 500KHz bw
dudmuck 18:0ecb6adb7c0b 262 RegGainDrift_t gd;
dudmuck 18:0ecb6adb7c0b 263 gd.octet = m_xcvr.read_reg(REG_LR_GAIN_DRIFT);
dudmuck 18:0ecb6adb7c0b 264 auto_drift.bits.freq_to_time_drift_auto = 0;
dudmuck 18:0ecb6adb7c0b 265 if (m_xcvr.HF) {
dudmuck 18:0ecb6adb7c0b 266 // > 525MHz
dudmuck 18:0ecb6adb7c0b 267 gd.bits.freq_to_time_drift = 0x24;
dudmuck 18:0ecb6adb7c0b 268 } else {
dudmuck 18:0ecb6adb7c0b 269 // < 525MHz
dudmuck 18:0ecb6adb7c0b 270 gd.bits.freq_to_time_drift = 0x3f;
dudmuck 18:0ecb6adb7c0b 271 }
dudmuck 18:0ecb6adb7c0b 272 m_xcvr.write_reg(REG_LR_GAIN_DRIFT, gd.octet);
dudmuck 18:0ecb6adb7c0b 273 } else {
dudmuck 18:0ecb6adb7c0b 274 auto_drift.bits.freq_to_time_drift_auto = 1;
dudmuck 18:0ecb6adb7c0b 275 }
dudmuck 18:0ecb6adb7c0b 276 m_xcvr.write_reg(REG_LR_SX1276_AUTO_DRIFT, auto_drift.octet);
dudmuck 18:0ecb6adb7c0b 277
dudmuck 10:7382c260c4b1 278 } else if (m_xcvr.type == SX1272) {
dudmuck 2:fdae76e1215e 279 RegModemConfig.sx1272bits.Bw = bw;
dudmuck 10:7382c260c4b1 280 if (get_symbol_period() > 16)
dudmuck 2:fdae76e1215e 281 RegModemConfig.sx1272bits.LowDataRateOptimize = 1;
dudmuck 2:fdae76e1215e 282 else
dudmuck 2:fdae76e1215e 283 RegModemConfig.sx1272bits.LowDataRateOptimize = 0;
dudmuck 2:fdae76e1215e 284 } else
dudmuck 2:fdae76e1215e 285 return;
dudmuck 2:fdae76e1215e 286
dudmuck 2:fdae76e1215e 287 m_xcvr.write_reg(REG_LR_MODEMCONFIG, RegModemConfig.octet);
dudmuck 2:fdae76e1215e 288 }
dudmuck 2:fdae76e1215e 289
dudmuck 2:fdae76e1215e 290
dudmuck 2:fdae76e1215e 291
dudmuck 2:fdae76e1215e 292 uint8_t SX127x_lora::getSf(void)
dudmuck 2:fdae76e1215e 293 {
dudmuck 2:fdae76e1215e 294 // spreading factor same between sx127[26]
dudmuck 2:fdae76e1215e 295 return RegModemConfig2.sx1276bits.SpreadingFactor;
dudmuck 2:fdae76e1215e 296 }
dudmuck 2:fdae76e1215e 297
dudmuck 2:fdae76e1215e 298 void SX127x_lora::set_nb_trig_peaks(int n)
dudmuck 2:fdae76e1215e 299 {
dudmuck 13:1953e70522aa 300 /* TODO: different requirements for RX_CONTINUOUS vs RX_SINGLE */
dudmuck 2:fdae76e1215e 301 RegTest31.bits.detect_trig_same_peaks_nb = n;
dudmuck 2:fdae76e1215e 302 m_xcvr.write_reg(REG_LR_TEST31, RegTest31.octet);
dudmuck 2:fdae76e1215e 303 }
dudmuck 2:fdae76e1215e 304
dudmuck 2:fdae76e1215e 305
dudmuck 2:fdae76e1215e 306 void SX127x_lora::setSf(uint8_t sf)
dudmuck 2:fdae76e1215e 307 {
dudmuck 2:fdae76e1215e 308 if (!m_xcvr.RegOpMode.bits.LongRangeMode)
dudmuck 2:fdae76e1215e 309 return;
dudmuck 2:fdae76e1215e 310
dudmuck 2:fdae76e1215e 311 // false detections vs missed detections tradeoff
dudmuck 2:fdae76e1215e 312 switch (sf) {
dudmuck 2:fdae76e1215e 313 case 6:
dudmuck 2:fdae76e1215e 314 set_nb_trig_peaks(3);
dudmuck 2:fdae76e1215e 315 break;
dudmuck 2:fdae76e1215e 316 case 7:
dudmuck 2:fdae76e1215e 317 set_nb_trig_peaks(4);
dudmuck 2:fdae76e1215e 318 break;
dudmuck 2:fdae76e1215e 319 default:
dudmuck 2:fdae76e1215e 320 set_nb_trig_peaks(5);
dudmuck 2:fdae76e1215e 321 break;
dudmuck 2:fdae76e1215e 322 }
dudmuck 2:fdae76e1215e 323
dudmuck 2:fdae76e1215e 324 // write register at 0x37 with value 0xc if at SF6
dudmuck 2:fdae76e1215e 325 if (sf < 7)
dudmuck 2:fdae76e1215e 326 m_xcvr.write_reg(REG_LR_DETECTION_THRESHOLD, 0x0c);
dudmuck 2:fdae76e1215e 327 else
dudmuck 2:fdae76e1215e 328 m_xcvr.write_reg(REG_LR_DETECTION_THRESHOLD, 0x0a);
dudmuck 2:fdae76e1215e 329
dudmuck 2:fdae76e1215e 330 RegModemConfig2.sx1276bits.SpreadingFactor = sf; // spreading factor same between sx127[26]
dudmuck 2:fdae76e1215e 331 m_xcvr.write_reg(REG_LR_MODEMCONFIG2, RegModemConfig2.octet);
dudmuck 2:fdae76e1215e 332
dudmuck 2:fdae76e1215e 333 if (m_xcvr.type == SX1272) {
dudmuck 10:7382c260c4b1 334 if (get_symbol_period() > 16)
dudmuck 2:fdae76e1215e 335 RegModemConfig.sx1272bits.LowDataRateOptimize = 1;
dudmuck 2:fdae76e1215e 336 else
dudmuck 2:fdae76e1215e 337 RegModemConfig.sx1272bits.LowDataRateOptimize = 0;
dudmuck 2:fdae76e1215e 338 m_xcvr.write_reg(REG_LR_MODEMCONFIG, RegModemConfig.octet);
dudmuck 2:fdae76e1215e 339 } else if (m_xcvr.type == SX1276) {
dudmuck 10:7382c260c4b1 340 if (get_symbol_period() > 16)
dudmuck 2:fdae76e1215e 341 RegModemConfig3.sx1276bits.LowDataRateOptimize = 1;
dudmuck 2:fdae76e1215e 342 else
dudmuck 2:fdae76e1215e 343 RegModemConfig3.sx1276bits.LowDataRateOptimize = 0;
dudmuck 2:fdae76e1215e 344 m_xcvr.write_reg(REG_LR_MODEMCONFIG3, RegModemConfig3.octet);
dudmuck 2:fdae76e1215e 345 }
dudmuck 2:fdae76e1215e 346 }
dudmuck 2:fdae76e1215e 347
dudmuck 2:fdae76e1215e 348
dudmuck 2:fdae76e1215e 349
dudmuck 2:fdae76e1215e 350 bool SX127x_lora::getRxPayloadCrcOn(void)
dudmuck 2:fdae76e1215e 351 {
dudmuck 2:fdae76e1215e 352 if (m_xcvr.type == SX1276)
dudmuck 2:fdae76e1215e 353 return RegModemConfig2.sx1276bits.RxPayloadCrcOn;
dudmuck 2:fdae76e1215e 354 else if (m_xcvr.type == SX1272)
dudmuck 2:fdae76e1215e 355 return RegModemConfig.sx1272bits.RxPayloadCrcOn;
dudmuck 2:fdae76e1215e 356 else
dudmuck 2:fdae76e1215e 357 return 0;
dudmuck 2:fdae76e1215e 358 }
dudmuck 2:fdae76e1215e 359
dudmuck 2:fdae76e1215e 360
dudmuck 2:fdae76e1215e 361 void SX127x_lora::setRxPayloadCrcOn(bool on)
dudmuck 2:fdae76e1215e 362 {
dudmuck 2:fdae76e1215e 363 if (m_xcvr.type == SX1276) {
dudmuck 2:fdae76e1215e 364 RegModemConfig2.sx1276bits.RxPayloadCrcOn = on;
dudmuck 2:fdae76e1215e 365 m_xcvr.write_reg(REG_LR_MODEMCONFIG2, RegModemConfig2.octet);
dudmuck 2:fdae76e1215e 366 } else if (m_xcvr.type == SX1272) {
dudmuck 2:fdae76e1215e 367 RegModemConfig.sx1272bits.RxPayloadCrcOn = on;
dudmuck 2:fdae76e1215e 368 m_xcvr.write_reg(REG_LR_MODEMCONFIG, RegModemConfig.octet);
dudmuck 2:fdae76e1215e 369 }
dudmuck 2:fdae76e1215e 370 }
dudmuck 2:fdae76e1215e 371
dudmuck 2:fdae76e1215e 372
dudmuck 2:fdae76e1215e 373
dudmuck 2:fdae76e1215e 374 bool SX127x_lora::getAgcAutoOn(void)
dudmuck 2:fdae76e1215e 375 {
dudmuck 2:fdae76e1215e 376 if (m_xcvr.type == SX1276) {
dudmuck 2:fdae76e1215e 377 RegModemConfig3.octet = m_xcvr.read_reg(REG_LR_MODEMCONFIG3);
dudmuck 2:fdae76e1215e 378 return RegModemConfig3.sx1276bits.AgcAutoOn;
dudmuck 2:fdae76e1215e 379 } else if (m_xcvr.type == SX1272) {
dudmuck 2:fdae76e1215e 380 RegModemConfig2.octet = m_xcvr.read_reg(REG_LR_MODEMCONFIG2);
dudmuck 2:fdae76e1215e 381 return RegModemConfig2.sx1272bits.AgcAutoOn;
dudmuck 2:fdae76e1215e 382 } else
dudmuck 2:fdae76e1215e 383 return 0;
dudmuck 2:fdae76e1215e 384 }
dudmuck 2:fdae76e1215e 385
dudmuck 2:fdae76e1215e 386 void SX127x_lora::setAgcAutoOn(bool on)
dudmuck 2:fdae76e1215e 387 {
dudmuck 2:fdae76e1215e 388 if (m_xcvr.type == SX1276) {
dudmuck 2:fdae76e1215e 389 RegModemConfig3.sx1276bits.AgcAutoOn = on;
dudmuck 2:fdae76e1215e 390 m_xcvr.write_reg(REG_LR_MODEMCONFIG3, RegModemConfig3.octet);
dudmuck 2:fdae76e1215e 391 } else if (m_xcvr.type == SX1272) {
dudmuck 2:fdae76e1215e 392 RegModemConfig2.sx1272bits.AgcAutoOn = on;
dudmuck 2:fdae76e1215e 393 m_xcvr.write_reg(REG_LR_MODEMCONFIG2, RegModemConfig2.octet);
dudmuck 2:fdae76e1215e 394 }
dudmuck 2:fdae76e1215e 395
dudmuck 2:fdae76e1215e 396 }
dudmuck 2:fdae76e1215e 397
dudmuck 17:59279bc8cdab 398 void SX127x_lora::invert_tx(bool inv)
dudmuck 17:59279bc8cdab 399 {
dudmuck 17:59279bc8cdab 400 RegTest33.bits.chirp_invert_tx = !inv;
dudmuck 17:59279bc8cdab 401 m_xcvr.write_reg(REG_LR_TEST33, RegTest33.octet);
dudmuck 17:59279bc8cdab 402 }
dudmuck 17:59279bc8cdab 403
dudmuck 17:59279bc8cdab 404 void SX127x_lora::invert_rx(bool inv)
dudmuck 17:59279bc8cdab 405 {
dudmuck 17:59279bc8cdab 406 RegTest33.bits.invert_i_q = inv;
dudmuck 17:59279bc8cdab 407 m_xcvr.write_reg(REG_LR_TEST33, RegTest33.octet);
dudmuck 17:59279bc8cdab 408 /**/
dudmuck 17:59279bc8cdab 409 RegDriftInvert.bits.invert_timing_error_per_symbol = !RegTest33.bits.invert_i_q;
dudmuck 17:59279bc8cdab 410 m_xcvr.write_reg(REG_LR_DRIFT_INVERT, RegDriftInvert.octet);
dudmuck 17:59279bc8cdab 411 }
dudmuck 17:59279bc8cdab 412
dudmuck 2:fdae76e1215e 413 void SX127x_lora::start_tx(uint8_t len)
dudmuck 7:927a05f84ede 414 {
dudmuck 2:fdae76e1215e 415 // DIO0 to TxDone
dudmuck 2:fdae76e1215e 416 if (m_xcvr.RegDioMapping1.bits.Dio0Mapping != 1) {
dudmuck 2:fdae76e1215e 417 m_xcvr.RegDioMapping1.bits.Dio0Mapping = 1;
dudmuck 2:fdae76e1215e 418 m_xcvr.write_reg(REG_DIOMAPPING1, m_xcvr.RegDioMapping1.octet);
dudmuck 2:fdae76e1215e 419 }
dudmuck 2:fdae76e1215e 420
dudmuck 2:fdae76e1215e 421 // set FifoPtrAddr to FifoTxPtrBase
dudmuck 2:fdae76e1215e 422 m_xcvr.write_reg(REG_LR_FIFOADDRPTR, m_xcvr.read_reg(REG_LR_FIFOTXBASEADDR));
dudmuck 2:fdae76e1215e 423
dudmuck 2:fdae76e1215e 424 // write PayloadLength bytes to fifo
dudmuck 2:fdae76e1215e 425 write_fifo(len);
dudmuck 7:927a05f84ede 426
dudmuck 2:fdae76e1215e 427 m_xcvr.set_opmode(RF_OPMODE_TRANSMITTER);
dudmuck 2:fdae76e1215e 428 }
dudmuck 2:fdae76e1215e 429
dudmuck 2:fdae76e1215e 430 void SX127x_lora::start_rx()
dudmuck 2:fdae76e1215e 431 {
dudmuck 2:fdae76e1215e 432 if (!m_xcvr.RegOpMode.bits.LongRangeMode)
dudmuck 12:bda42457c34a 433 return; // fsk mode
dudmuck 12:bda42457c34a 434 if (m_xcvr.RegOpMode.sx1276LORAbits.AccessSharedReg)
dudmuck 12:bda42457c34a 435 return; // fsk page
dudmuck 13:1953e70522aa 436
dudmuck 13:1953e70522aa 437 m_xcvr.set_opmode(RF_OPMODE_RECEIVER);
dudmuck 2:fdae76e1215e 438
dudmuck 2:fdae76e1215e 439 if (m_xcvr.RegDioMapping1.bits.Dio0Mapping != 0) {
dudmuck 2:fdae76e1215e 440 m_xcvr.RegDioMapping1.bits.Dio0Mapping = 0; // DIO0 to RxDone
dudmuck 2:fdae76e1215e 441 m_xcvr.write_reg(REG_DIOMAPPING1, m_xcvr.RegDioMapping1.octet);
dudmuck 2:fdae76e1215e 442 }
dudmuck 2:fdae76e1215e 443
dudmuck 2:fdae76e1215e 444 m_xcvr.write_reg(REG_LR_FIFOADDRPTR, m_xcvr.read_reg(REG_LR_FIFORXBASEADDR));
dudmuck 2:fdae76e1215e 445 }
dudmuck 2:fdae76e1215e 446
dudmuck 2:fdae76e1215e 447 float SX127x_lora::get_pkt_rssi()
dudmuck 2:fdae76e1215e 448 {
dudmuck 2:fdae76e1215e 449 /* TODO: calculating with pktSNR to give meaningful result below noise floor */
dudmuck 2:fdae76e1215e 450 if (m_xcvr.type == SX1276)
dudmuck 2:fdae76e1215e 451 return RegPktRssiValue - 137;
dudmuck 2:fdae76e1215e 452 else
dudmuck 2:fdae76e1215e 453 return RegPktRssiValue - 125;
dudmuck 2:fdae76e1215e 454 }
dudmuck 2:fdae76e1215e 455
dudmuck 2:fdae76e1215e 456 service_action_e SX127x_lora::service()
dudmuck 2:fdae76e1215e 457 {
dudmuck 2:fdae76e1215e 458 if (m_xcvr.RegOpMode.bits.Mode == RF_OPMODE_RECEIVER) {
dudmuck 2:fdae76e1215e 459 if (poll_vh) {
dudmuck 2:fdae76e1215e 460 RegIrqFlags.octet = m_xcvr.read_reg(REG_LR_IRQFLAGS);
dudmuck 2:fdae76e1215e 461 if (RegIrqFlags.bits.ValidHeader) {
dudmuck 2:fdae76e1215e 462 RegIrqFlags.octet = 0;
dudmuck 2:fdae76e1215e 463 RegIrqFlags.bits.ValidHeader = 1;
dudmuck 2:fdae76e1215e 464 m_xcvr.write_reg(REG_LR_IRQFLAGS, RegIrqFlags.octet);
dudmuck 2:fdae76e1215e 465 printf("VH\r\n");
dudmuck 2:fdae76e1215e 466 }
dudmuck 2:fdae76e1215e 467 }
dudmuck 2:fdae76e1215e 468 }
dudmuck 7:927a05f84ede 469
dudmuck 2:fdae76e1215e 470 if (m_xcvr.dio0 == 0)
dudmuck 2:fdae76e1215e 471 return SERVICE_NONE;
dudmuck 2:fdae76e1215e 472
dudmuck 2:fdae76e1215e 473 switch (m_xcvr.RegDioMapping1.bits.Dio0Mapping) {
dudmuck 2:fdae76e1215e 474 case 0: // RxDone
dudmuck 2:fdae76e1215e 475 /* user checks for CRC error in IrqFlags */
dudmuck 2:fdae76e1215e 476 RegIrqFlags.octet = m_xcvr.read_reg(REG_LR_IRQFLAGS); // save flags
dudmuck 2:fdae76e1215e 477 RegHopChannel.octet = m_xcvr.read_reg(REG_LR_HOPCHANNEL);
dudmuck 2:fdae76e1215e 478 //printf("[%02x]", RegIrqFlags.octet);
dudmuck 2:fdae76e1215e 479 m_xcvr.write_reg(REG_LR_IRQFLAGS, RegIrqFlags.octet); // clear flags in radio
dudmuck 2:fdae76e1215e 480
dudmuck 2:fdae76e1215e 481 /* any register of interest on received packet is read(saved) here */
dudmuck 2:fdae76e1215e 482 RegModemStatus.octet = m_xcvr.read_reg(REG_LR_MODEMSTAT);
dudmuck 2:fdae76e1215e 483 RegPktSnrValue = m_xcvr.read_reg(REG_LR_PKTSNRVALUE);
dudmuck 2:fdae76e1215e 484 RegPktRssiValue = m_xcvr.read_reg(REG_LR_PKTRSSIVALUE);
dudmuck 2:fdae76e1215e 485 RegRxNbBytes = m_xcvr.read_reg(REG_LR_RXNBBYTES);
dudmuck 2:fdae76e1215e 486
dudmuck 2:fdae76e1215e 487 m_xcvr.write_reg(REG_LR_FIFOADDRPTR, m_xcvr.read_reg(REG_LR_FIFORXCURRENTADDR));
dudmuck 2:fdae76e1215e 488 read_fifo(RegRxNbBytes);
dudmuck 2:fdae76e1215e 489 return SERVICE_READ_FIFO;
dudmuck 2:fdae76e1215e 490 case 1: // TxDone
dudmuck 2:fdae76e1215e 491 RegIrqFlags.octet = 0;
dudmuck 2:fdae76e1215e 492 RegIrqFlags.bits.TxDone = 1;
dudmuck 2:fdae76e1215e 493 m_xcvr.write_reg(REG_LR_IRQFLAGS, RegIrqFlags.octet);
dudmuck 2:fdae76e1215e 494 return SERVICE_TX_DONE;
dudmuck 2:fdae76e1215e 495 } // ...switch (RegDioMapping1.bits.Dio0Mapping)
dudmuck 2:fdae76e1215e 496
dudmuck 2:fdae76e1215e 497 return SERVICE_ERROR;
dudmuck 12:bda42457c34a 498 }
dudmuck 12:bda42457c34a 499