├── .gitignore ├── library.properties ├── LICENSE ├── src ├── SX127x_driver.cpp ├── BaseLoRa.h ├── SX127x.h ├── SX126x.h ├── SX127x_driver.h ├── SX126x_driver.cpp ├── SX126x_driver.h ├── SX127x.cpp └── SX126x.cpp ├── examples ├── SX127x │ ├── SX127x_LoRa_receiver_callback │ │ └── SX127x_LoRa_receiver_callback.ino │ ├── SX127x_LoRa_receiver_timeout │ │ └── SX127x_LoRa_receiver_timeout.ino │ ├── SX127x_LoRa_transmitter │ │ └── SX127x_LoRa_transmitter.ino │ ├── SX127x_LoRa_receiver │ │ └── SX127x_LoRa_receiver.ino │ ├── SX127x_driver_tx │ │ └── SX127x_driver_tx.ino │ └── SX127x_driver_rx │ │ └── SX127x_driver_rx.ino ├── SX126x │ ├── SX126x_LoRa_receiver_continuous │ │ └── SX126x_LoRa_receiver_continuous.ino │ ├── SX126x_LoRa_receiver_listen │ │ └── SX126x_LoRa_receiver_listen.ino │ ├── SX126x_LoRa_transmitter │ │ └── SX126x_LoRa_transmitter.ino │ ├── SX126x_LoRa_receiver │ │ └── SX126x_LoRa_receiver.ino │ ├── SX126x_driver_tx │ │ └── SX126x_driver_tx.ino │ └── SX126x_driver_rx │ │ └── SX126x_driver_rx.ino └── Network │ ├── LoRa_simple_node │ └── LoRa_simple_node.ino │ └── LoRa_simple_gateway │ └── LoRa_simple_gateway.ino ├── keywords.txt └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | ### VisualStudioCode ### 2 | .vscode/* 3 | !.vscode/tasks.json 4 | !.vscode/launch.json 5 | *.code-workspace -------------------------------------------------------------------------------- /library.properties: -------------------------------------------------------------------------------- 1 | # library.properties 2 | name=LoRaRF 3 | version=2.1.1 4 | author=Chandra Wijaya Sentosa 5 | maintainer=Chandra Wijaya Sentosa 6 | sentence=Arduino LoRa-RF library used for transmitting and receiving data using LoRa module with Semtech SX126x series, SX127x series, or LLCC68. 7 | paragraph=The library works by interfacing SPI port and some I/O pins. Support for configuring frequency, modulation parameter, transmit power, receive gain and other RF parameters on both LoRa and FSK modulation also support for handling transmit and receive using interrupt signal. 8 | category=Communication 9 | url=https://github.com/chandrawi/LoRaRF-Arduino 10 | architectures=* 11 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Chandra Wijaya Sentosa 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/SX127x_driver.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | SPIClass* sx127x_spi = &SX127X_SPI; 4 | uint32_t sx127x_spiFrequency = SX127X_SPI_FREQUENCY; 5 | int8_t sx127x_nss = SX127X_PIN_NSS; 6 | 7 | void sx127x_setSPI(SPIClass &SpiObject, uint32_t frequency) 8 | { 9 | sx127x_spi = &SpiObject; 10 | sx127x_spiFrequency = frequency ? frequency : sx127x_spiFrequency; 11 | } 12 | 13 | void sx127x_setPins(int8_t nss) 14 | { 15 | sx127x_nss = nss; 16 | } 17 | 18 | void sx127x_reset(int8_t reset) 19 | { 20 | pinMode(reset, OUTPUT); 21 | digitalWrite(reset, LOW); 22 | delay(1); 23 | digitalWrite(reset, HIGH); 24 | delay(5); 25 | } 26 | 27 | void sx127x_begin() 28 | { 29 | pinMode(sx127x_nss, OUTPUT); 30 | sx127x_spi->begin(); 31 | } 32 | 33 | void sx127x_writeBits(uint8_t address, uint8_t data, uint8_t position, uint8_t length) 34 | { 35 | uint8_t read = sx127x_transfer(address & 0x7F, 0x00); 36 | uint8_t mask = (0xFF >> (8 - length)) << position; 37 | uint8_t write = (data << position) | (read & ~mask); 38 | sx127x_transfer(address | 0x80, write); 39 | } 40 | 41 | void sx127x_writeRegister(uint8_t address, uint8_t data) 42 | { 43 | sx127x_transfer(address | 0x80, data); 44 | } 45 | 46 | uint8_t sx127x_readRegister(uint8_t address) 47 | { 48 | return sx127x_transfer(address & 0x7F, 0x00); 49 | } 50 | 51 | uint8_t sx127x_transfer(uint8_t address, uint8_t data) 52 | { 53 | digitalWrite(sx127x_nss, LOW); 54 | 55 | sx127x_spi->beginTransaction(SPISettings(sx127x_spiFrequency, MSBFIRST, SPI_MODE0)); 56 | sx127x_spi->transfer(address); 57 | uint8_t response = sx127x_spi->transfer(data); 58 | sx127x_spi->endTransaction(); 59 | 60 | digitalWrite(sx127x_nss, HIGH); 61 | 62 | return response; 63 | } 64 | -------------------------------------------------------------------------------- /src/BaseLoRa.h: -------------------------------------------------------------------------------- 1 | #ifndef _BASE_LORA_H_ 2 | #define _BASE_LORA_H_ 3 | 4 | #include 5 | 6 | // Modem options 7 | #define FSK_MODEM 0x00 // GFSK packet type 8 | #define LORA_MODEM 0x01 // LoRa packet type 9 | 10 | // RX gain options 11 | #define LORA_RX_GAIN_POWER_SAVING 0x00 // gain used in Rx mode: power saving gain 12 | #define LORA_RX_GAIN_BOOSTED 0x01 // boosted gain 13 | 14 | // Header type 15 | #define LORA_HEADER_EXPLICIT 0x00 // explicit header mode 16 | #define LORA_HEADER_IMPLICIT 0x01 // implicit header mode 17 | 18 | // TX and RX operation mode 19 | #define LORA_TX_SINGLE 0x000000 // Tx timeout duration: no timeout (Rx single mode) 20 | #define LORA_RX_SINGLE 0x000000 // Rx timeout duration: no timeout (Rx single mode) 21 | #define LORA_RX_CONTINUOUS 0xFFFFFF // infinite (Rx continuous mode) 22 | 23 | // Status TX and RX operation 24 | #define LORA_STATUS_DEFAULT 0 // default status (false) 25 | #define LORA_STATUS_TX_WAIT 1 26 | #define LORA_STATUS_TX_TIMEOUT 2 27 | #define LORA_STATUS_TX_DONE 3 28 | #define LORA_STATUS_RX_WAIT 4 29 | #define LORA_STATUS_RX_CONTINUOUS 5 30 | #define LORA_STATUS_RX_TIMEOUT 6 31 | #define LORA_STATUS_RX_DONE 7 32 | #define LORA_STATUS_HEADER_ERR 8 33 | #define LORA_STATUS_CRC_ERR 9 34 | #define LORA_STATUS_CAD_WAIT 10 35 | #define LORA_STATUS_CAD_DETECTED 11 36 | #define LORA_STATUS_CAD_DONE 12 37 | 38 | // Uncomment one of line below to use one or more LoRa model for a network library 39 | #define USE_LORA_SX126X 40 | #define USE_LORA_SX127X 41 | 42 | class BaseLoRa 43 | { 44 | 45 | public: 46 | 47 | virtual void beginPacket(); 48 | virtual bool endPacket(uint32_t timeout); 49 | virtual void write(uint8_t data); 50 | virtual void write(uint8_t* data, uint8_t length); 51 | 52 | virtual bool request(uint32_t timeout); 53 | virtual uint8_t available(); 54 | virtual uint8_t read(); 55 | virtual uint8_t read(uint8_t* data, uint8_t length); 56 | 57 | virtual bool wait(uint32_t timeout); 58 | virtual uint8_t status(); 59 | 60 | }; 61 | 62 | #endif -------------------------------------------------------------------------------- /examples/SX127x/SX127x_LoRa_receiver_callback/SX127x_LoRa_receiver_callback.ino: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | SX127x LoRa; 4 | 5 | // receive data container and length 6 | const uint8_t maxLength = 15; 7 | volatile uint8_t packetLength = 0; 8 | uint8_t packetData[maxLength]; 9 | 10 | void setup() { 11 | 12 | // Begin serial communication 13 | Serial.begin(38400); 14 | 15 | // Begin LoRa radio and set NSS, reset, txen, and rxen pin with connected arduino pins 16 | Serial.println("Begin LoRa radio"); 17 | int8_t nssPin = 10, resetPin = 9, irqPin = 2, txenPin = 8, rxenPin = 7; 18 | if (!LoRa.begin(nssPin, resetPin, irqPin, txenPin, rxenPin)){ 19 | Serial.println("Something wrong, can't begin LoRa radio"); 20 | while(1); 21 | } 22 | 23 | // Set frequency to 915 Mhz 24 | Serial.println("Set frequency to 915 Mhz"); 25 | LoRa.setFrequency(915E6); 26 | 27 | // Set RX gain to boosted gain 28 | Serial.println("Set RX gain to boosted gain"); 29 | LoRa.setRxGain(SX127X_RX_GAIN_BOOSTED); 30 | 31 | // Configure modulation parameter including spreading factor (SF), bandwidth (BW), and coding rate (CR) 32 | Serial.println("Set modulation parameters:\n\tSpreading factor = 7\n\tBandwidth = 125 kHz\n\tCoding rate = 4/5"); 33 | LoRa.setSpreadingFactor(7); 34 | LoRa.setBandwidth(125000); 35 | LoRa.setCodeRate(5); 36 | 37 | // Configure packet parameter including header type, preamble length, payload length, and CRC type 38 | Serial.println("Set packet parameters:\n\tExplicit header type\n\tPreamble length = 12\n\tPayload Length = 15\n\tCRC on"); 39 | LoRa.setHeaderType(SX127X_HEADER_EXPLICIT); 40 | LoRa.setPreambleLength(12); 41 | LoRa.setPayloadLength(15); 42 | LoRa.setCrcEnable(true); 43 | 44 | // Set syncronize word 45 | Serial.println("Set syncronize word to 0x34"); 46 | LoRa.setSyncWord(0x34); 47 | 48 | Serial.println("\n-- LORA RECEIVER CALLBACK --\n"); 49 | 50 | // Register callback function to be called every RX done 51 | LoRa.onReceive(getReceiveData); 52 | 53 | // Begin request LoRa packet in continuous mode 54 | LoRa.request(SX127X_RX_CONTINUOUS); 55 | } 56 | 57 | void loop() { 58 | 59 | if (packetLength) { 60 | // Print received package 61 | Serial.write(packetData, packetLength - 1); 62 | Serial.print(" "); 63 | Serial.println(packetData[packetLength - 1]); 64 | 65 | // Print packet/signal status including RSSI, SNR, and signalRSSI 66 | Serial.print("Packet status: RSSI = "); 67 | Serial.print(LoRa.packetRssi()); 68 | Serial.print(" dBm | SNR = "); 69 | Serial.print(LoRa.snr()); 70 | Serial.println(" dB"); 71 | Serial.println(); 72 | 73 | // Reset receive data container length 74 | packetLength = 0; 75 | } 76 | } 77 | 78 | void getReceiveData() { 79 | 80 | // set received length 81 | packetLength = LoRa.available(); 82 | if (packetLength > maxLength) { 83 | packetLength = maxLength; 84 | } 85 | // Store received data 86 | LoRa.read(packetData, packetLength); 87 | } 88 | -------------------------------------------------------------------------------- /examples/SX127x/SX127x_LoRa_receiver_timeout/SX127x_LoRa_receiver_timeout.ino: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | SX127x LoRa; 4 | 5 | void setup() { 6 | 7 | // Begin serial communication 8 | Serial.begin(38400); 9 | 10 | // Begin LoRa radio and set NSS, reset, txen, and rxen pin with connected arduino pins 11 | Serial.println("Begin LoRa radio"); 12 | int8_t nssPin = 10, resetPin = 9, irqPin = -1, txenPin = 8, rxenPin = 7; 13 | if (!LoRa.begin(nssPin, resetPin, irqPin, txenPin, rxenPin)){ 14 | Serial.println("Something wrong, can't begin LoRa radio"); 15 | while(1); 16 | } 17 | 18 | // Set frequency to 915 Mhz 19 | Serial.println("Set frequency to 915 Mhz"); 20 | LoRa.setFrequency(915E6); 21 | 22 | // Set RX gain to boosted gain 23 | Serial.println("Set RX gain to boosted gain"); 24 | LoRa.setRxGain(SX127X_RX_GAIN_BOOSTED); 25 | 26 | // Configure modulation parameter including spreading factor (SF), bandwidth (BW), and coding rate (CR) 27 | Serial.println("Set modulation parameters:\n\tSpreading factor = 7\n\tBandwidth = 125 kHz\n\tCoding rate = 4/5"); 28 | LoRa.setSpreadingFactor(7); 29 | LoRa.setBandwidth(125000); 30 | LoRa.setCodeRate(5); 31 | 32 | // Configure packet parameter including header type, preamble length, payload length, and CRC type 33 | Serial.println("Set packet parameters:\n\tExplicit header type\n\tPreamble length = 12\n\tPayload Length = 15\n\tCRC on"); 34 | LoRa.setHeaderType(SX127X_HEADER_EXPLICIT); 35 | LoRa.setPreambleLength(12); 36 | LoRa.setPayloadLength(15); 37 | LoRa.setCrcEnable(true); 38 | 39 | // Set syncronize word 40 | Serial.println("Set syncronize word to 0x34"); 41 | LoRa.setSyncWord(0x34); 42 | 43 | Serial.println("\n-- LORA RECEIVER TIMEOUT --\n"); 44 | 45 | } 46 | 47 | void loop() { 48 | 49 | // Request for receiving new LoRa packet within 1000 ms 50 | LoRa.request(1000); 51 | // Wait for incoming LoRa packet 52 | LoRa.wait(); 53 | 54 | // Only show message if receive process is done 55 | uint8_t status = LoRa.status(); 56 | if (status == SX127X_STATUS_RX_DONE) { 57 | 58 | // Put received packet to message and counter variable 59 | const uint8_t msgLen = LoRa.available() - 1; 60 | char message[msgLen]; 61 | LoRa.read(message, msgLen); 62 | uint8_t counter = LoRa.read(); 63 | 64 | // Print received message and counter in serial 65 | Serial.write(message, msgLen); 66 | Serial.print(" "); 67 | Serial.println(counter); 68 | 69 | // Print packet / signal status 70 | Serial.print("RSSI: "); 71 | Serial.print(LoRa.packetRssi()); 72 | Serial.print(" dBm | SNR: "); 73 | Serial.print(LoRa.snr()); 74 | Serial.println(" dB"); 75 | Serial.println(); 76 | 77 | } else { 78 | 79 | // Show received status 80 | if (status == SX127X_STATUS_RX_TIMEOUT) Serial.println("Receive timeout"); 81 | else if (status == SX127X_STATUS_CRC_ERR) Serial.println("CRC error"); 82 | else if (status == SX127X_STATUS_HEADER_ERR) Serial.println("Packet header error"); 83 | Serial.println(); 84 | 85 | } 86 | 87 | } 88 | -------------------------------------------------------------------------------- /examples/SX126x/SX126x_LoRa_receiver_continuous/SX126x_LoRa_receiver_continuous.ino: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | SX126x LoRa; 4 | 5 | void setup() { 6 | 7 | // Begin serial communication 8 | Serial.begin(38400); 9 | 10 | // Begin LoRa radio and set NSS, reset, busy, txen, and rxen pin with connected arduino pins 11 | Serial.println("Begin LoRa radio"); 12 | int8_t nssPin = 10, resetPin = 9, busyPin = 4, irqPin = 2, txenPin = 8, rxenPin = 7; 13 | if (!LoRa.begin(nssPin, resetPin, busyPin, irqPin, txenPin, rxenPin)){ 14 | Serial.println("Something wrong, can't begin LoRa radio"); 15 | while(1); 16 | } 17 | 18 | // Configure TCXO or XTAL used in RF module 19 | Serial.println("Set RF module to use TCXO as clock reference"); 20 | uint8_t dio3Voltage = SX126X_DIO3_OUTPUT_1_8; 21 | uint32_t tcxoDelay = SX126X_TCXO_DELAY_10; 22 | LoRa.setDio3TcxoCtrl(dio3Voltage, tcxoDelay); 23 | 24 | // Set frequency to 915 Mhz 25 | Serial.println("Set frequency to 915 Mhz"); 26 | LoRa.setFrequency(915000000); 27 | 28 | // Set RX gain to boosted gain 29 | Serial.println("Set RX gain to boosted gain"); 30 | LoRa.setRxGain(SX126X_RX_GAIN_BOOSTED); 31 | 32 | // Configure modulation parameter including spreading factor (SF), bandwidth (BW), and coding rate (CR) 33 | Serial.println("Set modulation parameters:\n\tSpreading factor = 7\n\tBandwidth = 125 kHz\n\tCoding rate = 4/5"); 34 | uint8_t sf = 7; 35 | uint32_t bw = 125000; 36 | uint8_t cr = 5; 37 | LoRa.setLoRaModulation(sf, bw, cr); 38 | 39 | // Configure packet parameter including header type, preamble length, payload length, and CRC type 40 | Serial.println("Set packet parameters:\n\tExplicit header type\n\tPreamble length = 12\n\tPayload Length = 15\n\tCRC on"); 41 | uint8_t headerType = SX126X_HEADER_EXPLICIT; 42 | uint16_t preambleLength = 12; 43 | uint8_t payloadLength = 15; 44 | bool crcType = true; 45 | LoRa.setLoRaPacket(headerType, preambleLength, payloadLength, crcType); 46 | 47 | // Set syncronize word for public network (0x3444) 48 | Serial.println("Set syncronize word to 0x3444"); 49 | LoRa.setSyncWord(0x3444); 50 | 51 | Serial.println("\n-- LORA RECEIVER CONTINUOUS --\n"); 52 | 53 | // Request for receiving new LoRa packet in RX continuous mode 54 | LoRa.request(SX126X_RX_CONTINUOUS); 55 | 56 | } 57 | 58 | void loop() { 59 | 60 | // Check for incoming LoRa packet 61 | const uint8_t msgLen = LoRa.available(); 62 | if (msgLen) { 63 | 64 | // Put received packet to message and counter variable 65 | char message[msgLen-1]; 66 | uint8_t counter; 67 | uint8_t i=0; 68 | while (LoRa.available() > 1){ 69 | message[i++] = LoRa.read(); 70 | } 71 | counter = LoRa.read(); 72 | 73 | // Print received message and counter in serial 74 | Serial.print(message); 75 | Serial.print(" "); 76 | Serial.println(counter); 77 | 78 | // Print packet/signal status including package RSSI and SNR 79 | Serial.print("Packet status: RSSI = "); 80 | Serial.print(LoRa.packetRssi()); 81 | Serial.print(" dBm | SNR = "); 82 | Serial.print(LoRa.snr()); 83 | Serial.println(" dB"); 84 | 85 | // Show received status in case CRC or header error occur 86 | uint8_t status = LoRa.status(); 87 | if (status == SX126X_STATUS_CRC_ERR) Serial.println("CRC error"); 88 | else if (status == SX126X_STATUS_HEADER_ERR) Serial.println("Packet header error"); 89 | Serial.println(); 90 | 91 | } 92 | 93 | } 94 | -------------------------------------------------------------------------------- /examples/SX126x/SX126x_LoRa_receiver_listen/SX126x_LoRa_receiver_listen.ino: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | SX126x LoRa; 4 | 5 | void setup() { 6 | 7 | // Begin serial communication 8 | Serial.begin(38400); 9 | 10 | // Begin LoRa radio and set NSS, reset, busy, txen, and rxen pin with connected arduino pins 11 | Serial.println("Begin LoRa radio"); 12 | int8_t nssPin = 10, resetPin = 9, busyPin = 4, irqPin = 2, txenPin = 8, rxenPin = 7; 13 | if (!LoRa.begin(nssPin, resetPin, busyPin, irqPin, txenPin, rxenPin)){ 14 | Serial.println("Something wrong, can't begin LoRa radio"); 15 | while(1); 16 | } 17 | 18 | // Configure TCXO or XTAL used in RF module 19 | Serial.println("Set RF module to use TCXO as clock reference"); 20 | uint8_t dio3Voltage = SX126X_DIO3_OUTPUT_1_8; 21 | uint32_t tcxoDelay = SX126X_TCXO_DELAY_10; 22 | LoRa.setDio3TcxoCtrl(dio3Voltage, tcxoDelay); 23 | 24 | // Set frequency to 915 Mhz 25 | Serial.println("Set frequency to 915 Mhz"); 26 | LoRa.setFrequency(915000000); 27 | 28 | // Set RX gain to boosted gain 29 | Serial.println("Set RX gain to boosted gain"); 30 | LoRa.setRxGain(SX126X_RX_GAIN_BOOSTED); 31 | 32 | // Configure modulation parameter including spreading factor (SF), bandwidth (BW), and coding rate (CR) 33 | Serial.println("Set modulation parameters:\n\tSpreading factor = 7\n\tBandwidth = 125 kHz\n\tCoding rate = 4/5"); 34 | uint8_t sf = 7; 35 | uint32_t bw = 125000; 36 | uint8_t cr = 5; 37 | LoRa.setLoRaModulation(sf, bw, cr); 38 | 39 | // Configure packet parameter including header type, preamble length, payload length, and CRC type 40 | Serial.println("Set packet parameters:\n\tExplicit header type\n\tPreamble length = 12\n\tPayload Length = 15\n\tCRC on"); 41 | uint8_t headerType = SX126X_HEADER_EXPLICIT; 42 | uint16_t preambleLength = 12; 43 | uint8_t payloadLength = 15; 44 | bool crcType = true; 45 | LoRa.setLoRaPacket(headerType, preambleLength, payloadLength, crcType); 46 | 47 | // Set syncronize word for public network (0x3444) 48 | Serial.println("Set syncronize word to 0x3444"); 49 | LoRa.setSyncWord(0x3444); 50 | 51 | Serial.println("\n-- LORA RECEIVER LISTEN --\n"); 52 | 53 | } 54 | 55 | void loop() { 56 | 57 | // Listen for a LoRa packet in 10 ms and sleep in 10 ms 58 | uint32_t rxPeriod = 10; 59 | uint32_t sleepPeriod = 10; 60 | LoRa.listen(rxPeriod, sleepPeriod); 61 | 62 | // Check for incoming LoRa packet 63 | const uint8_t msgLen = LoRa.available(); 64 | if (msgLen) { 65 | 66 | // Put received packet to message and counter variable 67 | const uint8_t msgLen = LoRa.available() - 1; 68 | char message[msgLen]; 69 | uint8_t counter; 70 | uint8_t i=0; 71 | while (LoRa.available() > 1){ 72 | message[i++] = LoRa.read(); 73 | } 74 | counter = LoRa.read(); 75 | 76 | // Print received message and counter in serial 77 | Serial.print(message); 78 | Serial.print(" "); 79 | Serial.println(counter); 80 | 81 | // Print packet/signal status including package RSSI and SNR 82 | Serial.print("Packet status: RSSI = "); 83 | Serial.print(LoRa.packetRssi()); 84 | Serial.print(" dBm | SNR = "); 85 | Serial.print(LoRa.snr()); 86 | Serial.println(" dB"); 87 | 88 | // Show received status in case CRC or header error occur 89 | uint8_t status = LoRa.status(); 90 | if (status == SX126X_STATUS_RX_TIMEOUT) Serial.println("Receive timeout"); 91 | else if (status == SX126X_STATUS_CRC_ERR) Serial.println("CRC error"); 92 | else if (status == SX126X_STATUS_HEADER_ERR) Serial.println("Packet header error"); 93 | Serial.println(); 94 | 95 | } 96 | 97 | } 98 | -------------------------------------------------------------------------------- /examples/SX127x/SX127x_LoRa_transmitter/SX127x_LoRa_transmitter.ino: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | SX127x LoRa; 4 | 5 | // Message to transmit 6 | char message[] = "HeLoRa World!"; 7 | uint8_t nBytes = sizeof(message); 8 | uint8_t counter = 0; 9 | 10 | void setup() { 11 | 12 | // Begin serial communication 13 | Serial.begin(38400); 14 | 15 | // Uncomment below to use non default SPI port 16 | //SPIClass SPI_2(PB15, PB14, PB13); 17 | //LoRa.setSPI(SPI_2, 16000000); 18 | 19 | // Begin LoRa radio and set NSS, reset, txen, and rxen pin with connected arduino pins 20 | // IRQ pin not used in this example (set to -1). Set txen and rxen pin to -1 if RF module doesn't have one 21 | Serial.println("Begin LoRa radio"); 22 | int8_t nssPin = 10, resetPin = 9, irqPin = -1, txenPin = 8, rxenPin = 7; 23 | if (!LoRa.begin(nssPin, resetPin, irqPin, txenPin, rxenPin)){ 24 | Serial.println("Something wrong, can't begin LoRa radio"); 25 | while(1); 26 | } 27 | 28 | // Set frequency to 915 Mhz 29 | Serial.println("Set frequency to 915 Mhz"); 30 | LoRa.setFrequency(915E6); 31 | 32 | // Set TX power, this function will set PA config with optimal setting for requested TX power 33 | Serial.println("Set TX power to +17 dBm"); 34 | LoRa.setTxPower(17, SX127X_TX_POWER_PA_BOOST); // TX power +17 dBm using PA boost pin 35 | 36 | // Configure modulation parameter including spreading factor (SF), bandwidth (BW), and coding rate (CR) 37 | // Transmitter must have same SF and BW setting so receiver can receive LoRa packet 38 | Serial.println("Set modulation parameters:\n\tSpreading factor = 7\n\tBandwidth = 125 kHz\n\tCoding rate = 4/5"); 39 | LoRa.setSpreadingFactor(7); // LoRa spreading factor: 7 40 | LoRa.setBandwidth(125000); // Bandwidth: 125 kHz 41 | LoRa.setCodeRate(5); // Coding rate: 4/5 42 | 43 | // Configure packet parameter including header type, preamble length, payload length, and CRC type 44 | // The explicit packet includes header contain CR, number of byte, and CRC type 45 | // Packet with explicit header can't be received by receiver with implicit header mode 46 | Serial.println("Set packet parameters:\n\tExplicit header type\n\tPreamble length = 12\n\tPayload Length = 15\n\tCRC on"); 47 | LoRa.setHeaderType(SX127X_HEADER_EXPLICIT); // Explicit header mode 48 | LoRa.setPreambleLength(12); // Set preamble length to 12 49 | LoRa.setPayloadLength(15); // Initialize payloadLength to 15 50 | LoRa.setCrcEnable(true); // Set CRC enable 51 | 52 | // Set syncronize word 53 | Serial.println("Set syncronize word to 0x34"); 54 | LoRa.setSyncWord(0x34); 55 | 56 | Serial.println("\n-- LORA TRANSMITTER --\n"); 57 | 58 | } 59 | 60 | void loop() { 61 | 62 | // Transmit message and counter 63 | // write() method must be placed between beginPacket() and endPacket() 64 | LoRa.beginPacket(); 65 | LoRa.write(message, nBytes); 66 | LoRa.write(counter); 67 | LoRa.endPacket(); 68 | 69 | // Print message and counter in serial 70 | Serial.write(message, nBytes); 71 | Serial.print(" "); 72 | Serial.println(counter++); 73 | 74 | // Wait until modulation process for transmitting packet finish 75 | LoRa.wait(); 76 | 77 | // Print transmit time 78 | Serial.print("Transmit time: "); 79 | Serial.print(LoRa.transmitTime()); 80 | Serial.println(" ms"); 81 | Serial.println(); 82 | 83 | // Don't load RF module with continous transmit 84 | delay(5000); 85 | 86 | } 87 | -------------------------------------------------------------------------------- /examples/SX127x/SX127x_LoRa_receiver/SX127x_LoRa_receiver.ino: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | SX127x LoRa; 4 | 5 | void setup() { 6 | 7 | // Begin serial communication 8 | Serial.begin(38400); 9 | 10 | // Uncomment below to use non default SPI port 11 | //SPIClass SPI_2(PB15, PB14, PB13); 12 | //LoRa.setSPI(SPI_2, 16000000); 13 | 14 | // Begin LoRa radio and set NSS, reset, txen, and rxen pin with connected arduino pins 15 | // IRQ pin not used in this example (set to -1). Set txen and rxen pin to -1 if RF module doesn't have one 16 | Serial.println("Begin LoRa radio"); 17 | int8_t nssPin = 10, resetPin = 9, irqPin = -1, txenPin = 8, rxenPin = 7; 18 | if (!LoRa.begin(nssPin, resetPin, irqPin, txenPin, rxenPin)){ 19 | Serial.println("Something wrong, can't begin LoRa radio"); 20 | while(1); 21 | } 22 | 23 | // Set frequency to 915 Mhz 24 | Serial.println("Set frequency to 915 Mhz"); 25 | LoRa.setFrequency(915E6); 26 | 27 | // Set RX gain. RX gain option are power saving gain or boosted gain 28 | Serial.println("Set RX gain to power saving gain"); 29 | LoRa.setRxGain(SX127X_RX_GAIN_POWER_SAVING, SX127X_RX_GAIN_AUTO); // AGC on, Power saving gain 30 | 31 | // Configure modulation parameter including spreading factor (SF), bandwidth (BW), and coding rate (CR) 32 | // Transmitter must have same SF and BW setting so receiver can receive LoRa packet 33 | Serial.println("Set modulation parameters:\n\tSpreading factor = 7\n\tBandwidth = 125 kHz\n\tCoding rate = 4/5"); 34 | LoRa.setSpreadingFactor(7); // LoRa spreading factor: 7 35 | LoRa.setBandwidth(125000); // Bandwidth: 125 kHz 36 | LoRa.setCodeRate(5); // Coding rate: 4/5 37 | 38 | // Configure packet parameter including header type, preamble length, payload length, and CRC type 39 | // The explicit packet includes header contain CR, number of byte, and CRC type 40 | // Packet with explicit header can't be received by receiver with implicit header mode 41 | Serial.println("Set packet parameters:\n\tExplicit header type\n\tPreamble length = 12\n\tPayload Length = 15\n\tCRC on"); 42 | LoRa.setHeaderType(SX127X_HEADER_EXPLICIT); // Explicit header mode 43 | LoRa.setPreambleLength(12); // Set preamble length to 12 44 | LoRa.setPayloadLength(15); // Initialize payloadLength to 15 45 | LoRa.setCrcEnable(true); // Set CRC enable 46 | 47 | // Set syncronize word 48 | Serial.println("Set syncronize word to 0x34"); 49 | LoRa.setSyncWord(0x34); 50 | 51 | Serial.println("\n-- LORA RECEIVER --\n"); 52 | 53 | } 54 | 55 | void loop() { 56 | 57 | // Request for receiving new LoRa packet 58 | LoRa.request(); 59 | // Wait for incoming LoRa packet 60 | LoRa.wait(); 61 | 62 | // Put received packet to message and counter variable 63 | // read() and available() method must be called after request() method 64 | const uint8_t msgLen = LoRa.available() - 1; 65 | char message[msgLen]; 66 | LoRa.read(message, msgLen); 67 | uint8_t counter = LoRa.read(); 68 | 69 | // Print received message and counter in serial 70 | Serial.write(message, msgLen); 71 | Serial.print(" "); 72 | Serial.println(counter); 73 | 74 | // Print packet / signal status 75 | Serial.print("RSSI: "); 76 | Serial.print(LoRa.packetRssi()); 77 | Serial.print(" dBm | SNR: "); 78 | Serial.print(LoRa.snr()); 79 | Serial.println(" dB"); 80 | 81 | // Show received status in case CRC or header error occur 82 | uint8_t status = LoRa.status(); 83 | if (status == SX127X_STATUS_CRC_ERR) Serial.println("CRC error"); 84 | else if (status == SX127X_STATUS_HEADER_ERR) Serial.println("Packet header error"); 85 | Serial.println(); 86 | 87 | } 88 | -------------------------------------------------------------------------------- /examples/Network/LoRa_simple_node/LoRa_simple_node.ino: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | // #define SX126X 5 | #define SX127X 6 | 7 | #if defined(SX126X) 8 | SX126x LoRa; 9 | #elif defined(SX127X) 10 | SX127x LoRa; 11 | #endif 12 | 13 | // gateway ID and node ID 14 | uint8_t gatewayId = 0xCC; 15 | uint8_t nodeId = 0x77; 16 | 17 | // Message structure to transmit 18 | struct dataObject { 19 | uint8_t gatewayId; 20 | uint8_t nodeId; 21 | uint16_t messageId; 22 | uint32_t time; 23 | int32_t data; 24 | }; 25 | dataObject message; 26 | uint8_t messageLen = sizeof(dataObject); 27 | 28 | void setup() { 29 | 30 | // Begin serial communication 31 | Serial.begin(38400); 32 | 33 | #if defined(SX126X) 34 | // Begin LoRa radio and set NSS, reset, busy, IRQ, txen, and rxen pin with connected arduino pins 35 | Serial.println("Begin LoRa radio"); 36 | int8_t nssPin = 10, resetPin = 9, busyPin = 4, irqPin = 2, txenPin = 8, rxenPin = 7; 37 | if (!LoRa.begin(nssPin, resetPin, busyPin, irqPin, txenPin, rxenPin)){ 38 | Serial.println("Something wrong, can't begin LoRa radio"); 39 | while(1); 40 | } 41 | // Configure TCXO used in RF module 42 | Serial.println("Set RF module to use TCXO as clock reference"); 43 | LoRa.setDio3TcxoCtrl(SX126X_DIO3_OUTPUT_1_8, SX126X_TCXO_DELAY_10); 44 | #elif defined(SX127X) 45 | // Begin LoRa radio and set NSS, reset, IRQ, txen, and rxen pin with connected arduino pins 46 | Serial.println("Begin LoRa radio"); 47 | int8_t nssPin = 10, resetPin = 9, irqPin = 2, txenPin = 8, rxenPin = 7; 48 | if (!LoRa.begin(nssPin, resetPin, irqPin, txenPin, rxenPin)){ 49 | Serial.println("Something wrong, can't begin LoRa radio"); 50 | while(1); 51 | } 52 | #endif 53 | 54 | // Set frequency to 915 Mhz 55 | Serial.println("Set frequency to 915 Mhz"); 56 | LoRa.setFrequency(915000000); 57 | 58 | // Set TX power to 17 dBm 59 | Serial.println("Set TX power to +17 dBm"); 60 | LoRa.setTxPower(17); 61 | 62 | // Configure modulation parameter including spreading factor (SF), bandwidth (BW), and coding rate (CR) 63 | Serial.println("Set modulation parameters:\n\tSpreading factor = 7\n\tBandwidth = 125 kHz\n\tCoding rate = 4/5"); 64 | uint8_t sf = 7; 65 | uint32_t bw = 125000; 66 | uint8_t cr = 5; 67 | LoRa.setLoRaModulation(sf, bw, cr); 68 | 69 | // Configure packet parameter including header type, preamble length, payload length, and CRC type 70 | Serial.println("Set packet parameters:\n\tImplicit header type\n\tPreamble length = 12\n\tPayload Length = message length\n\tCRC on"); 71 | uint8_t headerType = LORA_HEADER_IMPLICIT; 72 | uint16_t preambleLength = 12; 73 | uint8_t payloadLength = messageLen; 74 | bool crcType = true; 75 | LoRa.setLoRaPacket(headerType, preambleLength, payloadLength, crcType); 76 | 77 | // Set syncronize word for private network (0x3444) 78 | Serial.println("Set syncronize word to 0x3444"); 79 | LoRa.setSyncWord(0x3444); 80 | 81 | Serial.println("\n-- LORA NODE --\n"); 82 | 83 | // Assign gateway Id and node Id to message object 84 | message.gatewayId = gatewayId; 85 | message.nodeId = nodeId; 86 | message.messageId = 0; 87 | 88 | } 89 | 90 | void loop() { 91 | 92 | // Assign data with random value and time with current time 93 | message.data = random(-1073741824, 1073741824); 94 | message.time = millis(); 95 | message.messageId++; 96 | 97 | // Transmit message object 98 | LoRa.beginPacket(); 99 | LoRa.put(message); 100 | LoRa.endPacket(); 101 | 102 | // Print message in serial 103 | Serial.print("Gateway ID : 0x"); 104 | if (message.gatewayId < 0x10) Serial.print("0"); 105 | Serial.println(message.gatewayId, HEX); 106 | Serial.print("Node ID : 0x"); 107 | if (message.nodeId < 0x10) Serial.print("0"); 108 | Serial.println(message.nodeId, HEX); 109 | Serial.print("Message ID : "); 110 | Serial.println(message.messageId); 111 | Serial.print("Time : "); 112 | Serial.println(message.time); 113 | Serial.print("Data : "); 114 | Serial.println(message.data); 115 | 116 | // Wait until modulation process for transmitting packet finish 117 | LoRa.wait(); 118 | 119 | // Print transmit time 120 | Serial.print("Transmit time : "); 121 | Serial.print(LoRa.transmitTime()); 122 | Serial.println(" ms"); 123 | Serial.println(); 124 | 125 | // Put RF module to sleep in a few seconds 126 | LoRa.sleep(); 127 | delay(5000); 128 | LoRa.wake(); 129 | 130 | } 131 | -------------------------------------------------------------------------------- /examples/SX126x/SX126x_LoRa_transmitter/SX126x_LoRa_transmitter.ino: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | SX126x LoRa; 4 | 5 | // Message to transmit 6 | char message[] = "HeLoRa World!"; 7 | uint8_t nBytes = sizeof(message); 8 | uint8_t counter = 0; 9 | 10 | void setup() { 11 | 12 | // Begin serial communication 13 | Serial.begin(38400); 14 | 15 | // Uncomment below to use non default SPI port 16 | //SPIClass SPI_2(PB15, PB14, PB13); 17 | //LoRa.setSPI(SPI_2, 16000000); 18 | 19 | // Begin LoRa radio and set NSS, reset, busy, IRQ, txen, and rxen pin with connected arduino pins 20 | // IRQ pin not used in this example (set to -1). Set txen and rxen pin to -1 if RF module doesn't have one 21 | Serial.println("Begin LoRa radio"); 22 | int8_t nssPin = 10, resetPin = 9, busyPin = 4, irqPin = -1, txenPin = 8, rxenPin = 7; 23 | if (!LoRa.begin(nssPin, resetPin, busyPin, irqPin, txenPin, rxenPin)){ 24 | Serial.println("Something wrong, can't begin LoRa radio"); 25 | while(1); 26 | } 27 | 28 | // Optionally configure TCXO or XTAL used in RF module 29 | // Different RF module can have different clock, so make sure clock source is configured correctly 30 | // uncomment code below to use TCXO 31 | Serial.println("Set RF module to use TCXO as clock reference"); 32 | uint8_t dio3Voltage = SX126X_DIO3_OUTPUT_1_8; 33 | uint32_t tcxoDelay = SX126X_TCXO_DELAY_10; 34 | LoRa.setDio3TcxoCtrl(dio3Voltage, tcxoDelay); 35 | // uncomment code below to use XTAL 36 | //uint8_t xtalA = 0x12; 37 | //uint8_t xtalB = 0x12; 38 | //Serial.println("Set RF module to use XTAL as clock reference"); 39 | //LoRa.setXtalCap(xtalA, xtalB); 40 | 41 | // Optionally configure DIO2 as RF switch control 42 | // This is usually used for a LoRa module without TXEN and RXEN pins 43 | //LoRa.setDio2RfSwitch(true); 44 | 45 | // Set frequency to 915 Mhz 46 | Serial.println("Set frequency to 915 Mhz"); 47 | LoRa.setFrequency(915000000); 48 | 49 | // Set TX power, default power for SX1262 and SX1268 are +22 dBm and for SX1261 is +14 dBm 50 | // This function will set PA config with optimal setting for requested TX power 51 | Serial.println("Set TX power to +17 dBm"); 52 | LoRa.setTxPower(17, SX126X_TX_POWER_SX1262); // TX power +17 dBm for SX1262 53 | 54 | // Configure modulation parameter including spreading factor (SF), bandwidth (BW), and coding rate (CR) 55 | // Receiver must have same SF and BW setting with transmitter to be able to receive LoRa packet 56 | Serial.println("Set modulation parameters:\n\tSpreading factor = 7\n\tBandwidth = 125 kHz\n\tCoding rate = 4/5"); 57 | uint8_t sf = 7; // LoRa spreading factor: 7 58 | uint32_t bw = 125000; // Bandwidth: 125 kHz 59 | uint8_t cr = 5; // Coding rate: 4/5 60 | LoRa.setLoRaModulation(sf, bw, cr); 61 | 62 | // Configure packet parameter including header type, preamble length, payload length, and CRC type 63 | // The explicit packet includes header contain CR, number of byte, and CRC type 64 | // Receiver can receive packet with different CR and packet parameters in explicit header mode 65 | Serial.println("Set packet parameters:\n\tExplicit header type\n\tPreamble length = 12\n\tPayload Length = 15\n\tCRC on"); 66 | uint8_t headerType = SX126X_HEADER_EXPLICIT; // Explicit header mode 67 | uint16_t preambleLength = 12; // Set preamble length to 12 68 | uint8_t payloadLength = 15; // Initialize payloadLength to 15 69 | bool crcType = true; // Set CRC enable 70 | LoRa.setLoRaPacket(headerType, preambleLength, payloadLength, crcType); 71 | 72 | // Set syncronize word for public network (0x3444) 73 | Serial.println("Set syncronize word to 0x3444"); 74 | LoRa.setSyncWord(0x3444); 75 | 76 | Serial.println("\n-- LORA TRANSMITTER --\n"); 77 | 78 | } 79 | 80 | void loop() { 81 | 82 | // Transmit message and counter 83 | // write() method must be placed between beginPacket() and endPacket() 84 | LoRa.beginPacket(); 85 | LoRa.write(message, nBytes); 86 | LoRa.write(counter); 87 | LoRa.endPacket(); 88 | 89 | // Print message and counter in serial 90 | Serial.print(message); 91 | Serial.print(" "); 92 | Serial.println(counter++); 93 | 94 | // Wait until modulation process for transmitting packet finish 95 | LoRa.wait(); 96 | 97 | // Print transmit time 98 | Serial.print("Transmit time: "); 99 | Serial.print(LoRa.transmitTime()); 100 | Serial.println(" ms"); 101 | Serial.println(); 102 | 103 | // Don't load RF module with continous transmit 104 | delay(5000); 105 | 106 | } 107 | -------------------------------------------------------------------------------- /examples/Network/LoRa_simple_gateway/LoRa_simple_gateway.ino: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | // #define SX126X 5 | #define SX127X 6 | 7 | #if defined(SX126X) 8 | SX126x LoRa; 9 | #elif defined(SX127X) 10 | SX127x LoRa; 11 | #endif 12 | 13 | // gateway ID 14 | uint8_t gatewayId = 0xCC; 15 | 16 | // Message structure to transmit 17 | struct dataObject { 18 | uint8_t gatewayId; 19 | uint8_t nodeId; 20 | uint16_t messageId; 21 | uint32_t time; 22 | int32_t data; 23 | }; 24 | dataObject message; 25 | uint8_t messageLen = sizeof(dataObject); 26 | 27 | void setup() { 28 | 29 | // Begin serial communication 30 | Serial.begin(38400); 31 | 32 | #if defined(SX126X) 33 | // Begin LoRa radio and set NSS, reset, busy, IRQ, txen, and rxen pin with connected arduino pins 34 | Serial.println("Begin LoRa radio"); 35 | int8_t nssPin = 10, resetPin = 9, busyPin = 4, irqPin = 2, txenPin = 8, rxenPin = 7; 36 | if (!LoRa.begin(nssPin, resetPin, busyPin, irqPin, txenPin, rxenPin)){ 37 | Serial.println("Something wrong, can't begin LoRa radio"); 38 | while(1); 39 | } 40 | // Configure TCXO used in RF module 41 | Serial.println("Set RF module to use TCXO as clock reference"); 42 | LoRa.setDio3TcxoCtrl(SX126X_DIO3_OUTPUT_1_8, SX126X_TCXO_DELAY_10); 43 | #elif defined(SX127X) 44 | // Begin LoRa radio and set NSS, reset, IRQ, txen, and rxen pin with connected arduino pins 45 | Serial.println("Begin LoRa radio"); 46 | int8_t nssPin = 10, resetPin = 9, irqPin = 2, txenPin = 8, rxenPin = 7; 47 | if (!LoRa.begin(nssPin, resetPin, irqPin, txenPin, rxenPin)){ 48 | Serial.println("Something wrong, can't begin LoRa radio"); 49 | while(1); 50 | } 51 | #endif 52 | 53 | // Set frequency to 915 Mhz 54 | Serial.println("Set frequency to 915 Mhz"); 55 | LoRa.setFrequency(915000000); 56 | 57 | // Set RX gain to boosted gain 58 | Serial.println("Set RX gain to boosted gain"); 59 | LoRa.setRxGain(LORA_RX_GAIN_BOOSTED); 60 | 61 | // Configure modulation parameter including spreading factor (SF), bandwidth (BW), and coding rate (CR) 62 | Serial.println("Set modulation parameters:\n\tSpreading factor = 7\n\tBandwidth = 125 kHz\n\tCoding rate = 4/5"); 63 | uint8_t sf = 7; 64 | uint32_t bw = 125000; 65 | uint8_t cr = 5; 66 | LoRa.setLoRaModulation(sf, bw, cr); 67 | 68 | // Configure packet parameter including header type, preamble length, payload length, and CRC type 69 | Serial.println("Set packet parameters:\n\tImplicit header type\n\tPreamble length = 12\n\tPayload Length = message length\n\tCRC on"); 70 | uint8_t headerType = LORA_HEADER_IMPLICIT; 71 | uint16_t preambleLength = 12; 72 | uint8_t payloadLength = messageLen; 73 | bool crcType = true; 74 | LoRa.setLoRaPacket(headerType, preambleLength, payloadLength, crcType); 75 | 76 | // Set syncronize word for public network (0x3444) 77 | Serial.println("Set syncronize word to 0x3444"); 78 | LoRa.setSyncWord(0x3444); 79 | 80 | Serial.print("\nGateway ID : 0x"); 81 | if (gatewayId < 0x10) Serial.print("0"); 82 | Serial.println(gatewayId, HEX); 83 | Serial.println("-- LORA GATEWAY --\n"); 84 | 85 | } 86 | 87 | void loop() { 88 | 89 | // Set RF module to receive mode 90 | LoRa.request(); 91 | 92 | // Wait incoming signal and demodulation process for receiving packet finish 93 | LoRa.wait(); 94 | 95 | // Get received message object 96 | LoRa.get(message); 97 | 98 | // Print received message in serial only if gateway ID is match 99 | if (message.gatewayId == gatewayId){ 100 | Serial.print("Gateway ID : 0x"); 101 | if (message.gatewayId < 0x10) Serial.print("0"); 102 | Serial.println(message.gatewayId, HEX); 103 | Serial.print("Node ID : 0x"); 104 | if (message.nodeId < 0x10) Serial.print("0"); 105 | Serial.println(message.nodeId, HEX); 106 | Serial.print("Message ID : "); 107 | Serial.println(message.messageId); 108 | Serial.print("Time : "); 109 | Serial.println(message.time); 110 | Serial.print("Data : "); 111 | Serial.println(message.data); 112 | } 113 | else { 114 | Serial.print("Received message with wrong gateway ID (0x"); 115 | if (message.gatewayId < 0x10) Serial.print("0"); 116 | Serial.print(message.gatewayId, HEX); 117 | Serial.println(")"); 118 | } 119 | 120 | // Print packet/signal status including RSSI and SNR 121 | Serial.print("Packet status : RSSI = "); 122 | Serial.print(LoRa.packetRssi()); 123 | Serial.print(" dBm | SNR = "); 124 | Serial.print(LoRa.snr()); 125 | Serial.println(" dB"); 126 | 127 | // Show received status in case CRC or header error occur 128 | uint8_t status = LoRa.status(); 129 | if (status == LORA_STATUS_CRC_ERR) Serial.println("CRC error"); 130 | if (status == LORA_STATUS_HEADER_ERR) Serial.println("Packet header error"); 131 | Serial.println(); 132 | 133 | } 134 | -------------------------------------------------------------------------------- /examples/SX126x/SX126x_LoRa_receiver/SX126x_LoRa_receiver.ino: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | SX126x LoRa; 4 | 5 | void setup() { 6 | 7 | // Begin serial communication 8 | Serial.begin(38400); 9 | 10 | // Uncomment below to use non default SPI port 11 | //SPIClass SPI_2(PB15, PB14, PB13); 12 | //LoRa.setSPI(SPI_2, 16000000); 13 | 14 | // Begin LoRa radio and set NSS, reset, busy, txen, and rxen pin with connected arduino pins 15 | // IRQ pin not used in this example (set to -1). Set txen and rxen pin to -1 if RF module doesn't have one 16 | Serial.println("Begin LoRa radio"); 17 | int8_t nssPin = 10, resetPin = 9, busyPin = 4, irqPin = -1, txenPin = 8, rxenPin = 7; 18 | if (!LoRa.begin(nssPin, resetPin, busyPin, irqPin, txenPin, rxenPin)){ 19 | Serial.println("Something wrong, can't begin LoRa radio"); 20 | while(1); 21 | } 22 | 23 | // Optionally configure TCXO or XTAL used in RF module 24 | // Different RF module can have different clock, so make sure clock source is configured correctly 25 | // uncomment code below to use TCXO 26 | Serial.println("Set RF module to use TCXO as clock reference"); 27 | uint8_t dio3Voltage = SX126X_DIO3_OUTPUT_1_8; 28 | uint32_t tcxoDelay = SX126X_TCXO_DELAY_10; 29 | LoRa.setDio3TcxoCtrl(dio3Voltage, tcxoDelay); 30 | // uncomment code below to use XTAL 31 | //uint8_t xtalA = 0x12; 32 | //uint8_t xtalB = 0x12; 33 | //Serial.println("Set RF module to use XTAL as clock reference"); 34 | //LoRa.setXtalCap(xtalA, xtalB); 35 | 36 | // Optionally configure DIO2 as RF switch control 37 | // This is usually used for a LoRa module without TXEN and RXEN pins 38 | //LoRa.setDio2RfSwitch(true); 39 | 40 | // Set frequency to 915 Mhz 41 | Serial.println("Set frequency to 915 Mhz"); 42 | LoRa.setFrequency(915000000); 43 | 44 | // Set RX gain. RX gain option are power saving gain or boosted gain 45 | Serial.println("Set RX gain to power saving gain"); 46 | LoRa.setRxGain(SX126X_RX_GAIN_POWER_SAVING); // Power saving gain 47 | 48 | // Configure modulation parameter including spreading factor (SF), bandwidth (BW), and coding rate (CR) 49 | // Transmitter must have same SF and BW setting so receiver can receive LoRa packet 50 | Serial.println("Set modulation parameters:\n\tSpreading factor = 7\n\tBandwidth = 125 kHz\n\tCoding rate = 4/5"); 51 | uint8_t sf = 7; // LoRa spreading factor: 7 52 | uint32_t bw = 125000; // Bandwidth: 125 kHz 53 | uint8_t cr = 5; // Coding rate: 4/5 54 | LoRa.setLoRaModulation(sf, bw, cr); 55 | 56 | // Configure packet parameter including header type, preamble length, payload length, and CRC type 57 | // The explicit packet includes header contain CR, number of byte, and CRC type 58 | // Packet with explicit header can't be received by receiver with implicit header mode 59 | Serial.println("Set packet parameters:\n\tExplicit header type\n\tPreamble length = 12\n\tPayload Length = 15\n\tCRC on"); 60 | uint8_t headerType = SX126X_HEADER_EXPLICIT; // Explicit header mode 61 | uint16_t preambleLength = 12; // Set preamble length to 12 62 | uint8_t payloadLength = 15; // Initialize payloadLength to 15 63 | bool crcType = true; // Set CRC enable 64 | LoRa.setLoRaPacket(headerType, preambleLength, payloadLength, crcType); 65 | 66 | // Set syncronize word for public network (0x3444) 67 | Serial.println("Set syncronize word to 0x3444"); 68 | LoRa.setSyncWord(0x3444); 69 | 70 | Serial.println("\n-- LORA RECEIVER --\n"); 71 | 72 | } 73 | 74 | void loop() { 75 | 76 | // Request for receiving new LoRa packet 77 | LoRa.request(); 78 | // Wait for incoming LoRa packet 79 | LoRa.wait(); 80 | 81 | // Put received packet to message and counter variable 82 | // read() and available() method must be called after request() or listen() method 83 | const uint8_t msgLen = LoRa.available() - 1; 84 | char message[msgLen]; 85 | uint8_t counter; 86 | // available() method return remaining received payload length and will decrement each read() or get() method called 87 | uint8_t i=0; 88 | while (LoRa.available() > 1){ 89 | message[i++] = LoRa.read(); 90 | } 91 | counter = LoRa.read(); 92 | 93 | // Print received message and counter in serial 94 | Serial.print(message); 95 | Serial.print(" "); 96 | Serial.println(counter); 97 | 98 | // Print packet/signal status including package RSSI and SNR 99 | Serial.print("Packet status: RSSI = "); 100 | Serial.print(LoRa.packetRssi()); 101 | Serial.print(" dBm | SNR = "); 102 | Serial.print(LoRa.snr()); 103 | Serial.println(" dB"); 104 | 105 | // Show received status in case CRC or header error occur 106 | uint8_t status = LoRa.status(); 107 | if (status == SX126X_STATUS_CRC_ERR) Serial.println("CRC error"); 108 | else if (status == SX126X_STATUS_HEADER_ERR) Serial.println("Packet header error"); 109 | Serial.println(); 110 | 111 | } 112 | -------------------------------------------------------------------------------- /src/SX127x.h: -------------------------------------------------------------------------------- 1 | #ifndef _SX127X_H_ 2 | #define _SX127X_H_ 3 | 4 | #include 5 | #include 6 | 7 | // TX and RX operation status 8 | #define SX127X_STATUS_DEFAULT LORA_STATUS_DEFAULT 9 | #define SX127X_STATUS_TX_WAIT LORA_STATUS_TX_WAIT 10 | #define SX127X_STATUS_TX_TIMEOUT LORA_STATUS_TX_TIMEOUT 11 | #define SX127X_STATUS_TX_DONE LORA_STATUS_TX_DONE 12 | #define SX127X_STATUS_RX_WAIT LORA_STATUS_RX_WAIT 13 | #define SX127X_STATUS_RX_CONTINUOUS LORA_STATUS_RX_CONTINUOUS 14 | #define SX127X_STATUS_RX_TIMEOUT LORA_STATUS_RX_TIMEOUT 15 | #define SX127X_STATUS_RX_DONE LORA_STATUS_RX_DONE 16 | #define SX127X_STATUS_HEADER_ERR LORA_STATUS_HEADER_ERR 17 | #define SX127X_STATUS_CRC_ERR LORA_STATUS_CRC_ERR 18 | #define SX127X_STATUS_CAD_WAIT LORA_STATUS_CAD_WAIT 19 | #define SX127X_STATUS_CAD_DETECTED LORA_STATUS_CAD_DETECTED 20 | #define SX127X_STATUS_CAD_DONE LORA_STATUS_CAD_DONE 21 | 22 | #if defined(USE_LORA_SX126X) && defined(USE_LORA_SX127X) 23 | class SX127x : public BaseLoRa 24 | #else 25 | class SX127x 26 | #endif 27 | { 28 | public: 29 | 30 | SX127x(); 31 | 32 | // Common Operational methods 33 | bool begin(); 34 | bool begin(int8_t nss, int8_t reset, int8_t irq=-1, int8_t txen=-1, int8_t rxen=-1); 35 | void end(); 36 | bool reset(); 37 | void sleep(); 38 | void wake(); 39 | void standby(); 40 | void setActive(); 41 | 42 | // Hardware configuration methods 43 | void setSPI(SPIClass &SpiObject, uint32_t frequency=SX127X_SPI_FREQUENCY); 44 | void setPins(int8_t nss, int8_t reset, int8_t irq=-1, int8_t txen=-1, int8_t rxen=-1); 45 | void setCurrentProtection(uint8_t current); 46 | void setOscillator(uint8_t option); 47 | 48 | // Modem, modulation parameter, and packet parameter setup methods 49 | uint8_t getModem(); 50 | void setModem(uint8_t modem=SX127X_LORA_MODEM); 51 | void setFrequency(uint32_t frequency); 52 | void setTxPower(uint8_t txPower, uint8_t paPin=SX127X_TX_POWER_PA_BOOST); 53 | void setRxGain(uint8_t boost, uint8_t level=SX127X_RX_GAIN_AUTO); 54 | void setLoRaModulation(uint8_t sf, uint32_t bw, uint8_t cr, bool ldro=false); 55 | void setLoRaPacket(uint8_t headerType, uint16_t preambleLength, uint8_t payloadLength, bool crcType=false, bool invertIq=false); 56 | void setSpreadingFactor(uint8_t sf); 57 | void setBandwidth(uint32_t bw); 58 | void setCodeRate(uint8_t cr); 59 | void setLdroEnable(bool ldro=true); 60 | void setHeaderType(uint8_t headerType); 61 | void setPreambleLength(uint16_t preambleLength); 62 | void setPayloadLength(uint8_t payloadLength); 63 | void setCrcEnable(bool crcType=true); 64 | void setInvertIq(bool invertIq=true); 65 | void setSyncWord(uint16_t syncWord); 66 | 67 | // Transmit related methods 68 | void beginPacket(); 69 | bool endPacket(uint32_t timeout=0); 70 | void write(uint8_t data); 71 | void write(uint8_t* data, uint8_t length); 72 | void write(char* data, uint8_t length); 73 | template void put(T data) 74 | { 75 | const uint8_t length = sizeof(T); 76 | union conv { 77 | T Data; 78 | uint8_t Binary[length]; 79 | }; 80 | union conv u; 81 | u.Data = data; 82 | write(u.Binary, length); 83 | } 84 | void onTransmit(void(&callback)()); 85 | 86 | // Receive related methods 87 | bool request(uint32_t timeout=SX127X_RX_SINGLE); 88 | uint8_t available(); 89 | uint8_t read(); 90 | uint8_t read(uint8_t* data, uint8_t length); 91 | uint8_t read(char* data, uint8_t length); 92 | void purge(uint8_t length=0); 93 | template uint8_t get(T &data) 94 | { 95 | const uint8_t length = sizeof(T); 96 | union conv { 97 | T Data; 98 | uint8_t Binary[length]; 99 | }; 100 | union conv u; 101 | uint8_t len = read(u.Binary, length); 102 | data = u.Data; 103 | return len; 104 | } 105 | void onReceive(void(&callback)()); 106 | 107 | // Wait, operation status, and packet status methods 108 | bool wait(uint32_t timeout=0); 109 | uint8_t status(); 110 | uint32_t transmitTime(); 111 | float dataRate(); 112 | int16_t packetRssi(); 113 | float snr(); 114 | int16_t rssi(); 115 | uint32_t random(); 116 | 117 | protected: 118 | 119 | uint8_t _modem; 120 | uint32_t _frequency; 121 | uint8_t _sf = 7; 122 | uint32_t _bw = 125000; 123 | uint8_t _headerType; 124 | uint8_t _payloadLength; 125 | static void (*_onTransmit)(); 126 | static void (*_onReceive)(); 127 | 128 | private: 129 | 130 | SPIClass* _spi; 131 | int8_t _nss, _reset, _irq, _txen, _rxen; 132 | uint8_t _statusWait; 133 | volatile static uint8_t _statusIrq; 134 | static uint32_t _transmitTime; 135 | static uint8_t _payloadTxRx; 136 | static int8_t _irqStatic; 137 | static int8_t _pinToLow; 138 | uint16_t _random; 139 | 140 | // Interrupt handler methods 141 | #ifdef ESP8266 142 | static void ICACHE_RAM_ATTR _interruptTx(); 143 | static void ICACHE_RAM_ATTR _interruptRx(); 144 | static void ICACHE_RAM_ATTR _interruptRxContinuous(); 145 | #else 146 | static void _interruptTx(); 147 | static void _interruptRx(); 148 | static void _interruptRxContinuous(); 149 | #endif 150 | 151 | }; 152 | 153 | #endif -------------------------------------------------------------------------------- /examples/SX127x/SX127x_driver_tx/SX127x_driver_tx.ino: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | // Pin setting 4 | int8_t nssPin = 10, resetPin = 9, irqPin = 2, rxenPin = -1, txenPin = -1; 5 | 6 | // RF frequency setting 7 | uint32_t frequency = 915000000; 8 | 9 | // PA and TX power setting 10 | uint8_t paConfig = 0xC0; 11 | uint8_t txPower = 17; 12 | uint8_t paPin = SX127X_TX_POWER_PA_BOOST; 13 | 14 | // Define modulation parameters setting 15 | uint8_t sf = 7; 16 | uint8_t bw = 7; // 125 khz 17 | uint8_t cr = 1; // 5/4 18 | 19 | // Define packet parameters setting 20 | uint8_t headerType = SX127X_HEADER_EXPLICIT; 21 | uint16_t preambleLen = 12; 22 | uint8_t crcEn = 1; 23 | 24 | // SyncWord setting 25 | uint8_t syncword = 0x12; 26 | 27 | volatile bool transmitted = false; 28 | 29 | void checkTransmitDone() { 30 | transmitted = true; 31 | } 32 | 33 | void settingFunction() { 34 | 35 | Serial.println("-- SETTING FUNCTION --"); 36 | 37 | // Pin setting 38 | Serial.println("Setting pins"); 39 | sx127x_setPins(nssPin); 40 | pinMode(irqPin, INPUT); 41 | if (txenPin != -1 && rxenPin != -1) { 42 | pinMode(txenPin, OUTPUT); 43 | pinMode(rxenPin, OUTPUT); 44 | } 45 | 46 | // Reset RF module by setting resetPin to LOW and begin SPI communication 47 | sx127x_reset(resetPin); 48 | sx127x_begin(); 49 | uint8_t version = sx127x_readRegister(SX127X_REG_VERSION); 50 | if (version == 0x12 || version == 0x22) { 51 | Serial.println("Resetting RF module"); 52 | } else { 53 | Serial.println("Something wrong, can't reset LoRa radio"); 54 | } 55 | 56 | // Set modem type to LoRa and put device to standby mode 57 | sx127x_writeRegister(SX127X_REG_OP_MODE, SX127X_MODE_SLEEP); 58 | sx127x_writeRegister(SX127X_REG_OP_MODE, SX127X_LONG_RANGE_MODE); 59 | sx127x_writeRegister(SX127X_REG_OP_MODE, SX127X_LONG_RANGE_MODE | SX127X_MODE_STDBY); 60 | Serial.println("Going to standby mode"); 61 | Serial.println("Set packet type to LoRa"); 62 | 63 | // Set frequency 64 | uint64_t frf = ((uint64_t) frequency << 19) / 32000000; 65 | sx127x_writeRegister(SX127X_REG_FRF_MSB, (uint8_t) (frf >> 16)); 66 | sx127x_writeRegister(SX127X_REG_FRF_MID, (uint8_t) (frf >> 8)); 67 | sx127x_writeRegister(SX127X_REG_FRF_LSB, (uint8_t) frf); 68 | Serial.print("Set frequency to "); 69 | Serial.print(frequency / 1000000); 70 | Serial.println(" MHz"); 71 | 72 | // Set tx power to selected TX power 73 | Serial.print("Set TX power to "); 74 | Serial.print(txPower, DEC); 75 | Serial.println(" dBm"); 76 | uint8_t outputPower = txPower - 2; 77 | uint8_t paDac = txPower > 17 ? 0x07 : 0x04; 78 | sx127x_writeRegister(SX127X_REG_PA_DAC, paDac); 79 | sx127x_writeRegister(SX127X_REG_PA_CONFIG, paConfig | outputPower); 80 | 81 | // Set modulation param and packet param 82 | Serial.println("Set modulation with predefined parameters"); 83 | Serial.println("Set packet with predefined parameters"); 84 | sx127x_writeBits(SX127X_REG_MODEM_CONFIG_2, sf, 4, 4); 85 | sx127x_writeBits(SX127X_REG_MODEM_CONFIG_1, bw, 4, 4); 86 | sx127x_writeBits(SX127X_REG_MODEM_CONFIG_1, cr, 1, 3); 87 | sx127x_writeBits(SX127X_REG_MODEM_CONFIG_1, headerType, 0, 1); 88 | sx127x_writeBits(SX127X_REG_MODEM_CONFIG_2, crcEn, 2, 1); 89 | sx127x_writeRegister(SX127X_REG_PREAMBLE_MSB, preambleLen >> 8); 90 | sx127x_writeRegister(SX127X_REG_PREAMBLE_LSB, preambleLen); 91 | 92 | // Show modulation param and packet param registers 93 | uint8_t reg, reg_; 94 | reg = sx127x_readRegister(SX127X_REG_MODEM_CONFIG_1); 95 | Serial.print("Modem config 1 : 0x"); 96 | Serial.println(reg, HEX); 97 | reg = sx127x_readRegister(SX127X_REG_MODEM_CONFIG_2); 98 | Serial.print("Modem config 2 : 0x"); 99 | Serial.println(reg, HEX); 100 | reg = sx127x_readRegister(SX127X_REG_PREAMBLE_MSB); 101 | reg_ = sx127x_readRegister(SX127X_REG_PREAMBLE_LSB); 102 | Serial.print("Preamble length : 0x"); 103 | Serial.println(reg * 256 + reg_, HEX); 104 | 105 | // Set synchronize word 106 | sx127x_writeRegister(SX127X_REG_SYNC_WORD, syncword); 107 | reg = sx127x_readRegister(SX127X_REG_SYNC_WORD); 108 | Serial.print("Set syncWord to 0x"); 109 | Serial.println(reg, HEX); 110 | } 111 | 112 | uint8_t transmitFunction(char* message, uint8_t length) { 113 | 114 | Serial.println("\n-- TRANSMIT FUNCTION --"); 115 | uint8_t reg, reg_; 116 | 117 | // Configure FIFO address and address pointer for TX operation 118 | sx127x_writeRegister(SX127X_REG_FIFO_TX_BASE_ADDR, 0x00); 119 | reg = sx127x_readRegister(SX127X_REG_FIFO_TX_BASE_ADDR); 120 | sx127x_writeRegister(SX127X_REG_FIFO_ADDR_PTR, 0x00); 121 | reg_ = sx127x_readRegister(SX127X_REG_FIFO_ADDR_PTR); 122 | Serial.print("Set FIFO TX base address and address pointer (0x"); 123 | Serial.print(reg, HEX); 124 | Serial.print(" | 0x"); 125 | Serial.print(reg_, HEX); 126 | Serial.println(")"); 127 | 128 | // Write message to FIFO 129 | Serial.print("Write message \'"); 130 | Serial.print(message); 131 | Serial.println("\' in buffer"); 132 | Serial.print("Message in bytes : [ "); 133 | for (uint8_t i = 0; i < length; i++) { 134 | sx127x_writeRegister(SX127X_REG_FIFO, message[i]); 135 | Serial.print((uint8_t) message[i]); 136 | Serial.print(" "); 137 | } 138 | Serial.println("]"); 139 | 140 | // Set payload length 141 | sx127x_writeRegister(SX127X_REG_PAYLOAD_LENGTH, length); 142 | reg = sx127x_readRegister(SX127X_REG_PAYLOAD_LENGTH); 143 | Serial.print("Set payload length same as message length ("); 144 | Serial.print(reg); 145 | Serial.println(")"); 146 | 147 | // Activate interrupt when transmit done on DIO0 148 | Serial.println("Set TX done and timeout IRQ on DIO0"); 149 | sx127x_writeRegister(SX127X_REG_DIO_MAPPING_1, SX127X_DIO0_TX_DONE); 150 | // Attach irqPin to DIO0 151 | Serial.println("Attach interrupt on IRQ pin"); 152 | attachInterrupt(digitalPinToInterrupt(irqPin), checkTransmitDone, RISING); 153 | 154 | // Set txen and rxen pin state for transmitting packet 155 | if (txenPin != -1 && rxenPin != -1) { 156 | digitalWrite(txenPin, HIGH); 157 | digitalWrite(rxenPin, LOW); 158 | } 159 | 160 | // Transmit message 161 | Serial.println("Transmitting message..."); 162 | sx127x_writeRegister(SX127X_REG_OP_MODE, SX127X_LORA_MODEM | SX127X_MODE_TX); 163 | uint32_t tStart = millis(), tTrans = 0; 164 | 165 | // Wait for TX done interrupt and calcualte transmit time 166 | Serial.println("Wait for TX done interrupt"); 167 | while (!transmitted) delayMicroseconds(4); 168 | tTrans = millis() - tStart; 169 | // Clear transmit interrupt flag 170 | transmitted = false; 171 | Serial.println("Transmit done"); 172 | 173 | // Display transmit time 174 | Serial.print("Transmit time = "); 175 | Serial.print(tTrans); 176 | Serial.println(" ms"); 177 | 178 | // Show IRQ flag and Clear interrupt 179 | uint8_t irqStat = sx127x_readRegister(SX127X_REG_IRQ_FLAGS); 180 | sx127x_writeRegister(SX127X_REG_IRQ_FLAGS, 0xFF); 181 | Serial.println("Clear IRQ status"); 182 | if (txenPin != -1) { 183 | digitalWrite(txenPin, LOW); 184 | } 185 | 186 | // return interrupt status 187 | return irqStat; 188 | } 189 | 190 | void setup() { 191 | 192 | // Begin serial communication 193 | Serial.begin(38400); 194 | 195 | // Seetings for LoRa communication 196 | settingFunction(); 197 | } 198 | 199 | void loop() { 200 | 201 | // Message to transmit 202 | char message[] = "HeLoRa World"; 203 | uint8_t length = sizeof(message); 204 | 205 | // Transmit message 206 | uint8_t status = transmitFunction(message, length); 207 | 208 | // Don't load RF module with continous transmit 209 | delay(10000); 210 | } 211 | -------------------------------------------------------------------------------- /src/SX126x.h: -------------------------------------------------------------------------------- 1 | #ifndef _SX126X_H_ 2 | #define _SX126X_H_ 3 | 4 | #include 5 | #include 6 | 7 | // Status TX and RX operation 8 | #define SX126X_STATUS_DEFAULT LORA_STATUS_DEFAULT 9 | #define SX126X_STATUS_TX_WAIT LORA_STATUS_TX_WAIT 10 | #define SX126X_STATUS_TX_TIMEOUT LORA_STATUS_TX_TIMEOUT 11 | #define SX126X_STATUS_TX_DONE LORA_STATUS_TX_DONE 12 | #define SX126X_STATUS_RX_WAIT LORA_STATUS_RX_WAIT 13 | #define SX126X_STATUS_RX_CONTINUOUS LORA_STATUS_RX_CONTINUOUS 14 | #define SX126X_STATUS_RX_TIMEOUT LORA_STATUS_RX_TIMEOUT 15 | #define SX126X_STATUS_RX_DONE LORA_STATUS_RX_DONE 16 | #define SX126X_STATUS_HEADER_ERR LORA_STATUS_HEADER_ERR 17 | #define SX126X_STATUS_CRC_ERR LORA_STATUS_CRC_ERR 18 | #define SX126X_STATUS_CAD_WAIT LORA_STATUS_CAD_WAIT 19 | #define SX126X_STATUS_CAD_DETECTED LORA_STATUS_CAD_DETECTED 20 | #define SX126X_STATUS_CAD_DONE LORA_STATUS_CAD_DONE 21 | 22 | // Default Hardware Configuration 23 | #define SX126X_PIN_RF_IRQ 1 24 | 25 | #if defined(USE_LORA_SX126X) && defined(USE_LORA_SX127X) 26 | class SX126x : public BaseLoRa 27 | #else 28 | class SX126x 29 | #endif 30 | { 31 | 32 | public: 33 | 34 | SX126x(); 35 | 36 | // Common Operational methods 37 | bool begin(); 38 | bool begin(int8_t nss, int8_t reset, int8_t busy, int8_t irq=-1, int8_t txen=-1, int8_t rxen=-1); 39 | void end(); 40 | bool reset(); 41 | void sleep(uint8_t option=SX126X_SLEEP_WARM_START); 42 | void wake(); 43 | void standby(uint8_t option=SX126X_STANDBY_RC); 44 | void setActive(); 45 | bool busyCheck(uint32_t timeout=SX126X_BUSY_TIMEOUT); 46 | void setFallbackMode(uint8_t fallbackMode); 47 | uint8_t getMode(); 48 | 49 | // Hardware configuration methods 50 | void setSPI(SPIClass &SpiObject, uint32_t frequency=SX126X_SPI_FREQUENCY); 51 | void setPins(int8_t nss, int8_t reset, int8_t busy, int8_t irq=-1, int8_t txen=-1, int8_t rxen=-1); 52 | void setRfIrqPin(int8_t dioPinSelect); 53 | void setDio2RfSwitch(bool enable=true); 54 | void setDio3TcxoCtrl(uint8_t tcxoVoltage, uint32_t delayTime); 55 | void setXtalCap(uint8_t xtalA, uint8_t xtalB); 56 | void setRegulator(uint8_t regMode); 57 | void setCurrentProtection(uint8_t current); 58 | 59 | // Modem, modulation parameter, and packet parameter setup methods 60 | uint8_t getModem(); 61 | void setModem(uint8_t modem=SX126X_LORA_MODEM); 62 | void setFrequency(uint32_t frequency); 63 | void setTxPower(uint8_t txPower, uint8_t version=SX126X_TX_POWER_SX1262); 64 | void setRxGain(uint8_t boost); 65 | void setLoRaModulation(uint8_t sf, uint32_t bw, uint8_t cr, bool ldro=false); 66 | void setLoRaPacket(uint8_t headerType, uint16_t preambleLength, uint8_t payloadLength, bool crcType=false, bool invertIq=false); 67 | void setSpreadingFactor(uint8_t sf); 68 | void setBandwidth(uint32_t bw); 69 | void setCodeRate(uint8_t cr); 70 | void setLdroEnable(bool ldro=true); 71 | void setHeaderType(uint8_t headerType); 72 | void setPreambleLength(uint16_t preambleLength); 73 | void setPayloadLength(uint8_t payloadLength); 74 | void setCrcEnable(bool crcType=true); 75 | void setInvertIq(bool invertIq=true); 76 | void setSyncWord(uint16_t syncWord); 77 | void setFskModulation(uint32_t br, uint8_t pulseShape, uint8_t bandwidth, uint32_t Fdev); 78 | void setFskPacket(uint16_t preambleLength, uint8_t preambleDetector, uint8_t syncWordLength, uint8_t addrComp, uint8_t packetType, uint8_t payloadLength, uint8_t crcType, uint8_t whitening); 79 | void setFskSyncWord(uint8_t* sw, uint8_t swLen); 80 | void setFskAdress(uint8_t nodeAddr, uint8_t broadcastAddr); 81 | void setFskCrc(uint16_t crcInit, uint16_t crcPolynom); 82 | void setFskWhitening(uint16_t whitening); 83 | 84 | // Transmit related methods 85 | void beginPacket(); 86 | bool endPacket(uint32_t timeout=SX126X_TX_SINGLE); 87 | void write(uint8_t data); 88 | void write(uint8_t* data, uint8_t length); 89 | void write(char* data, uint8_t length); 90 | template void put(T data) 91 | { 92 | const uint8_t length = sizeof(T); 93 | union conv { 94 | T Data; 95 | uint8_t Binary[length]; 96 | }; 97 | union conv u; 98 | u.Data = data; 99 | sx126x_writeBuffer(_bufferIndex, u.Binary, length); 100 | _bufferIndex += length; 101 | _payloadTxRx += length; 102 | } 103 | void onTransmit(void(&callback)()); 104 | 105 | // Receive related methods 106 | bool request(uint32_t timeout=SX126X_RX_SINGLE); 107 | bool listen(uint32_t rxPeriod, uint32_t sleepPeriod); 108 | uint8_t available(); 109 | uint8_t read(); 110 | uint8_t read(uint8_t* data, uint8_t length); 111 | uint8_t read(char* data, uint8_t length); 112 | void purge(uint8_t length=0); 113 | template uint8_t get(T &data) 114 | { 115 | const uint8_t length = sizeof(T); 116 | union conv { 117 | T Data; 118 | uint8_t Binary[length]; 119 | }; 120 | union conv u; 121 | sx126x_readBuffer(_bufferIndex, u.Binary, length); 122 | data = u.Data; 123 | _bufferIndex += length; 124 | _payloadTxRx = _payloadTxRx > length ? _payloadTxRx - length : 0; 125 | return _payloadTxRx > length ? length : _payloadTxRx; 126 | } 127 | void onReceive(void(&callback)()); 128 | 129 | // Wait, operation status, and packet status methods 130 | bool wait(uint32_t timeout=0); 131 | uint8_t status(); 132 | uint32_t transmitTime(); 133 | float dataRate(); 134 | int16_t packetRssi(); 135 | float snr(); 136 | int16_t signalRssi(); 137 | int16_t rssiInst(); 138 | uint16_t getError(); 139 | uint32_t random(); 140 | 141 | protected: 142 | 143 | uint8_t _modem; 144 | uint8_t _sf = 7; 145 | uint32_t _bw = 125000; 146 | uint8_t _cr = 4; 147 | bool _ldro; 148 | uint8_t _headerType = SX126X_HEADER_EXPLICIT; 149 | uint16_t _preambleLength = 12; 150 | uint8_t _payloadLength; 151 | bool _crcType; 152 | bool _invertIq; 153 | static void (*_onTransmit)(); 154 | static void (*_onReceive)(); 155 | 156 | private: 157 | 158 | SPIClass* _spi; 159 | int8_t _nss, _reset, _busy, _irq, _txen, _rxen; 160 | int8_t _dio; 161 | uint8_t _statusWait; 162 | volatile static uint16_t _statusIrq; 163 | static uint32_t _transmitTime; 164 | static uint8_t _bufferIndex; 165 | static uint8_t _payloadTxRx; 166 | static int8_t _irqStatic; 167 | static int8_t _pinToLow; 168 | uint16_t _random; 169 | 170 | // Interrupt handler methods 171 | void _irqSetup(uint16_t irqMask); 172 | #ifdef ESP8266 173 | static void ICACHE_RAM_ATTR _interruptTx(); 174 | static void ICACHE_RAM_ATTR _interruptRx(); 175 | static void ICACHE_RAM_ATTR _interruptRxContinuous(); 176 | #else 177 | static void _interruptTx(); 178 | static void _interruptRx(); 179 | static void _interruptRxContinuous(); 180 | #endif 181 | 182 | }; 183 | 184 | #endif -------------------------------------------------------------------------------- /keywords.txt: -------------------------------------------------------------------------------- 1 | # Syntax Coloring Map For LoRaRF Library 2 | 3 | # Datatypes (KEYWORD1) 4 | BaseLoRa KEYWORD1 5 | SX126x KEYWORD1 6 | SX126x_API KEYWORD1 7 | SX127x KEYWORD1 8 | LoRa KEYWORD1 9 | Fsk KEYWORD1 10 | Api KEYWORD1 11 | 12 | # Methods and Functions (KEYWORD2) 13 | begin KEYWORD2 14 | end KEYWORD2 15 | reset KEYWORD2 16 | sleep KEYWORD2 17 | wake KEYWORD2 18 | standby KEYWORD2 19 | setActive KEYWORD2 20 | busyCheck KEYWORD2 21 | setFallbackMode KEYWORD2 22 | getMode KEYWORD2 23 | setSPI KEYWORD2 24 | setPins KEYWORD2 25 | setRfIrqPin KEYWORD2 26 | setDio2RfSwitch KEYWORD2 27 | setDio3TcxoCtrl KEYWORD2 28 | setXtalCap KEYWORD2 29 | setRegulator KEYWORD2 30 | setCurrentProtection KEYWORD2 31 | setModem KEYWORD2 32 | setFrequency KEYWORD2 33 | setTxPower KEYWORD2 34 | setRxGain KEYWORD2 35 | setLoRaModulation KEYWORD2 36 | setLoRaPacket KEYWORD2 37 | setSpreadingFactor KEYWORD2 38 | setBandwidth KEYWORD2 39 | setCodeRate KEYWORD2 40 | setLdroEnable KEYWORD2 41 | setHeaderType KEYWORD2 42 | setPreambleLength KEYWORD2 43 | setPayloadLength KEYWORD2 44 | setCrcEnable KEYWORD2 45 | setInvertIq KEYWORD2 46 | setSyncWord KEYWORD2 47 | setFskModulation KEYWORD2 48 | setFskPacket KEYWORD2 49 | setFskSyncWord KEYWORD2 50 | setFskAdress KEYWORD2 51 | setFskCrc KEYWORD2 52 | setFskWhitening KEYWORD2 53 | beginPacket KEYWORD2 54 | endPacket KEYWORD2 55 | write KEYWORD2 56 | put KEYWORD2 57 | onTransmit KEYWORD2 58 | request KEYWORD2 59 | listen KEYWORD2 60 | available KEYWORD2 61 | read KEYWORD2 62 | purge KEYWORD2 63 | get KEYWORD2 64 | onReceive KEYWORD2 65 | status KEYWORD2 66 | wait KEYWORD2 67 | transmitTime KEYWORD2 68 | dataRate KEYWORD2 69 | packetRssi KEYWORD2 70 | snr KEYWORD2 71 | signalRssi KEYWORD2 72 | rssiInst KEYWORD2 73 | rssi KEYWORD2 74 | getError KEYWORD2 75 | random KEYWORD2 76 | 77 | # Instances (KEYWORD2) 78 | 79 | # Constants (LITERAL1) 80 | FSK_MODEM LITERAL1 81 | LORA_MODEM LITERAL1 82 | LORA_RX_GAIN_POWER_SAVING LITERAL1 83 | LORA_RX_GAIN_BOOSTED LITERAL1 84 | LORA_HEADER_EXPLICIT LITERAL1 85 | LORA_HEADER_IMPLICIT LITERAL1 86 | LORA_TX_SINGLE LITERAL1 87 | LORA_RX_SINGLE LITERAL1 88 | LORA_RX_CONTINUOUS LITERAL1 89 | LORA_STATUS_DEFAULT LITERAL1 90 | LORA_STATUS_TX_WAIT LITERAL1 91 | LORA_STATUS_TX_TIMEOUT LITERAL1 92 | LORA_STATUS_TX_DONE LITERAL1 93 | LORA_STATUS_RX_WAIT LITERAL1 94 | LORA_STATUS_RX_CONTINUOUS LITERAL1 95 | LORA_STATUS_RX_TIMEOUT LITERAL1 96 | LORA_STATUS_RX_DONE LITERAL1 97 | LORA_STATUS_HEADER_ERR LITERAL1 98 | LORA_STATUS_CRC_ERR LITERAL1 99 | LORA_STATUS_CAD_WAIT LITERAL1 100 | LORA_STATUS_CAD_DETECTED LITERAL1 101 | LORA_STATUS_CAD_DONE LITERAL1 102 | SX126X_SLEEP_COLD_START LITERAL1 103 | SX126X_SLEEP_WARM_START LITERAL1 104 | SX126X_SLEEP_COLD_START_RTC LITERAL1 105 | SX126X_SLEEP_WARM_START_RTC LITERAL1 106 | SX126X_STANDBY_RC LITERAL1 107 | SX126X_STANDBY_XOSC LITERAL1 108 | SX126X_FALLBACK_FS LITERAL1 109 | SX126X_FALLBACK_STDBY_XOSC LITERAL1 110 | SX126X_FALLBACK_STDBY_RC LITERAL1 111 | SX126X_STATUS_DATA_AVAILABLE LITERAL1 112 | SX126X_STATUS_CMD_TIMEOUT LITERAL1 113 | SX126X_STATUS_CMD_ERROR LITERAL1 114 | SX126X_STATUS_CMD_FAILED LITERAL1 115 | SX126X_STATUS_CMD_TX_DONE LITERAL1 116 | SX126X_STATUS_MODE_STDBY_RC LITERAL1 117 | SX126X_STATUS_MODE_STDBY_XOSC LITERAL1 118 | SX126X_STATUS_MODE_FS LITERAL1 119 | SX126X_STATUS_MODE_RX LITERAL1 120 | SX126X_STATUS_MODE_TX LITERAL1 121 | SX126X_DIO3_OUTPUT_1_6 LITERAL1 122 | SX126X_DIO3_OUTPUT_1_7 LITERAL1 123 | SX126X_DIO3_OUTPUT_1_8 LITERAL1 124 | SX126X_DIO3_OUTPUT_2_2 LITERAL1 125 | SX126X_DIO3_OUTPUT_2_4 LITERAL1 126 | SX126X_DIO3_OUTPUT_2_7 LITERAL1 127 | SX126X_DIO3_OUTPUT_3_0 LITERAL1 128 | SX126X_DIO3_OUTPUT_3_3 LITERAL1 129 | SX126X_TCXO_DELAY_2_5 LITERAL1 130 | SX126X_TCXO_DELAY_5 LITERAL1 131 | SX126X_TCXO_DELAY_10 LITERAL1 132 | SX126X_REGULATOR_LDO LITERAL1 133 | SX126X_REGULATOR_DC_DC LITERAL1 134 | SX126X_FSK_MODEM LITERAL1 135 | SX126X_LORA_MODEM LITERAL1 136 | SX126X_TX_POWER_SX1261 LITERAL1 137 | SX126X_TX_POWER_SX1262 LITERAL1 138 | SX126X_TX_POWER_SX1268 LITERAL1 139 | SX126X_RX_GAIN_POWER_SAVING LITERAL1 140 | SX126X_RX_GAIN_BOOSTED LITERAL1 141 | SX126X_BW_7800 LITERAL1 142 | SX126X_BW_10400 LITERAL1 143 | SX126X_BW_15600 LITERAL1 144 | SX126X_BW_20800 LITERAL1 145 | SX126X_BW_31250 LITERAL1 146 | SX126X_BW_41700 LITERAL1 147 | SX126X_BW_62500 LITERAL1 148 | SX126X_BW_125000 LITERAL1 149 | SX126X_BW_250000 LITERAL1 150 | SX126X_BW_500000 LITERAL1 151 | SX126X_CR_4_4 LITERAL1 152 | SX126X_CR_4_5 LITERAL1 153 | SX126X_CR_4_6 LITERAL1 154 | SX126X_CR_4_7 LITERAL1 155 | SX126X_CR_4_8 LITERAL1 156 | SX126X_LDRO_OFF LITERAL1 157 | SX126X_LDRO_ON LITERAL1 158 | SX126X_HEADER_EXPLICIT LITERAL1 159 | SX126X_HEADER_IMPLICIT LITERAL1 160 | SX126X_CRC_OFF LITERAL1 161 | SX126X_CRC_ON LITERAL1 162 | SX126X_IQ_STANDARD LITERAL1 163 | SX126X_IQ_INVERTED LITERAL1 164 | SX126X_LORA_SYNC_WORD_PUBLIC LITERAL1 165 | SX126X_LORA_SYNC_WORD_PRIVATE LITERAL1 166 | SX126X_PULSE_NO_FILTER LITERAL1 167 | SX126X_PULSE_GAUSSIAN_BT_0_3 LITERAL1 168 | SX126X_PULSE_GAUSSIAN_BT_0_5 LITERAL1 169 | SX126X_PULSE_GAUSSIAN_BT_0_7 LITERAL1 170 | SX126X_PULSE_GAUSSIAN_BT_1 LITERAL1 171 | SX126X_BW_4800 LITERAL1 172 | SX126X_BW_5800 LITERAL1 173 | SX126X_BW_7300 LITERAL1 174 | SX126X_BW_9700 LITERAL1 175 | SX126X_BW_11700 LITERAL1 176 | SX126X_BW_14600 LITERAL1 177 | SX126X_BW_19500 LITERAL1 178 | SX126X_BW_23400 LITERAL1 179 | SX126X_BW_29300 LITERAL1 180 | SX126X_BW_39000 LITERAL1 181 | SX126X_BW_46900 LITERAL1 182 | SX126X_BW_58600 LITERAL1 183 | SX126X_BW_78200 LITERAL1 184 | SX126X_BW_93800 LITERAL1 185 | SX126X_BW_117300 LITERAL1 186 | SX126X_BW_156200 LITERAL1 187 | SX126X_BW_187200 LITERAL1 188 | SX126X_BW_234300 LITERAL1 189 | SX126X_BW_312000 LITERAL1 190 | SX126X_BW_373600 LITERAL1 191 | SX126X_BW_467000 LITERAL1 192 | SX126X_PREAMBLE_DET_LEN_OFF LITERAL1 193 | SX126X_PREAMBLE_DET_LEN_8 LITERAL1 194 | SX126X_PREAMBLE_DET_LEN_16 LITERAL1 195 | SX126X_PREAMBLE_DET_LEN_24 LITERAL1 196 | SX126X_PREAMBLE_DET_LEN_32 LITERAL1 197 | SX126X_ADDR_COMP_OFF LITERAL1 198 | SX126X_ADDR_COMP_NODE LITERAL1 199 | SX126X_ADDR_COMP_ALL LITERAL1 200 | SX126X_PACKET_KNOWN LITERAL1 201 | SX126X_PACKET_VARIABLE LITERAL1 202 | SX126X_CRC_0 LITERAL1 203 | SX126X_CRC_1 LITERAL1 204 | SX126X_CRC_2 LITERAL1 205 | SX126X_CRC_1_INV LITERAL1 206 | SX126X_CRC_2_INV LITERAL1 207 | SX126X_WHITENING_OFF LITERAL1 208 | SX126X_WHITENING_ON LITERAL1 209 | SX126X_TX_SINGLE LITERAL1 210 | SX126X_RX_SINGLE LITERAL1 211 | SX126X_RX_CONTINUOUS LITERAL1 212 | SX126X_STATUS_DEFAULT LITERAL1 213 | SX126X_STATUS_TX_WAIT LITERAL1 214 | SX126X_STATUS_TX_TIMEOUT LITERAL1 215 | SX126X_STATUS_TX_DONE LITERAL1 216 | SX126X_STATUS_RX_WAIT LITERAL1 217 | SX126X_STATUS_RX_CONTINUOUS LITERAL1 218 | SX126X_STATUS_RX_TIMEOUT LITERAL1 219 | SX126X_STATUS_RX_DONE LITERAL1 220 | SX126X_STATUS_HEADER_ERR LITERAL1 221 | SX126X_STATUS_CRC_ERR LITERAL1 222 | SX126X_STATUS_CAD_WAIT LITERAL1 223 | SX126X_STATUS_CAD_DETECTED LITERAL1 224 | SX126X_STATUS_CAD_DONE LITERAL1 225 | SX127X_OSC_CRYSTAL LITERAL1 226 | SX127X_OSC_TCXO LITERAL1 227 | SX127X_FSK_MODEM LITERAL1 228 | SX127X_OOK_MODEM LITERAL1 229 | SX127X_LORA_MODEM LITERAL1 230 | SX127X_TX_POWER_RFO LITERAL1 231 | SX127X_TX_POWER_PA_BOOST LITERAL1 232 | SX127X_RX_GAIN_POWER_SAVING LITERAL1 233 | SX127X_RX_GAIN_BOOSTED LITERAL1 234 | SX127X_RX_GAIN_AUTO LITERAL1 235 | SX127X_HEADER_EXPLICIT LITERAL1 236 | SX127X_HEADER_IMPLICIT LITERAL1 237 | SX127X_SYNCWORD_LORAWAN LITERAL1 238 | SX127X_RX_SINGLE LITERAL1 239 | SX127X_RX_CONTINUOUS LITERAL1 240 | SX127X_STATUS_DEFAULT LITERAL1 241 | SX127X_STATUS_TX_WAIT LITERAL1 242 | SX127X_STATUS_TX_TIMEOUT LITERAL1 243 | SX127X_STATUS_TX_DONE LITERAL1 244 | SX127X_STATUS_RX_WAIT LITERAL1 245 | SX127X_STATUS_RX_CONTINUOUS LITERAL1 246 | SX127X_STATUS_RX_TIMEOUT LITERAL1 247 | SX127X_STATUS_RX_DONE LITERAL1 248 | SX127X_STATUS_HEADER_ERR LITERAL1 249 | SX127X_STATUS_CRC_ERR LITERAL1 250 | SX127X_STATUS_CAD_WAIT LITERAL1 251 | SX127X_STATUS_CAD_DETECTED LITERAL1 252 | SX127X_STATUS_CAD_DONE LITERAL1 253 | -------------------------------------------------------------------------------- /examples/SX127x/SX127x_driver_rx/SX127x_driver_rx.ino: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | // Pin setting 4 | int8_t nssPin = 10, resetPin = 9, irqPin = 2, rxenPin = -1, txenPin = -1; 5 | 6 | // RF frequency setting 7 | uint32_t frequency = 915000000; 8 | 9 | // RX gain setting 10 | uint8_t boost = SX127X_RX_GAIN_POWER_SAVING; 11 | uint8_t level = SX127X_RX_GAIN_AUTO; 12 | 13 | // Define modulation parameters setting 14 | uint8_t sf = 7; 15 | uint8_t bw = 7; // 125 khz 16 | uint8_t cr = 1; // 5/4 17 | 18 | // Define packet parameters setting 19 | uint8_t headerType = SX127X_HEADER_EXPLICIT; 20 | uint16_t preambleLen = 12; 21 | uint8_t crcEn = 1; 22 | 23 | // SyncWord setting 24 | uint8_t syncword = 0x12; 25 | 26 | volatile bool received = false; 27 | 28 | void checkReceiveDone() { 29 | received = true; 30 | } 31 | 32 | void settingFunction() { 33 | 34 | Serial.println("-- SETTING FUNCTION --"); 35 | 36 | // Pin setting 37 | Serial.println("Setting pins"); 38 | sx127x_setPins(nssPin); 39 | pinMode(irqPin, INPUT); 40 | if (txenPin != -1 && rxenPin != -1) { 41 | pinMode(txenPin, OUTPUT); 42 | pinMode(rxenPin, OUTPUT); 43 | } 44 | 45 | // Reset RF module by setting resetPin to LOW and begin SPI communication 46 | sx127x_reset(resetPin); 47 | sx127x_begin(); 48 | uint8_t version = sx127x_readRegister(SX127X_REG_VERSION); 49 | if (version == 0x12 || version == 0x22) { 50 | Serial.println("Resetting RF module"); 51 | } else { 52 | Serial.println("Something wrong, can't reset LoRa radio"); 53 | } 54 | 55 | // Set modem type to LoRa and put device to standby mode 56 | sx127x_writeRegister(SX127X_REG_OP_MODE, SX127X_MODE_SLEEP); 57 | sx127x_writeRegister(SX127X_REG_OP_MODE, SX127X_LONG_RANGE_MODE); 58 | sx127x_writeRegister(SX127X_REG_OP_MODE, SX127X_LONG_RANGE_MODE | SX127X_MODE_STDBY); 59 | Serial.println("Going to standby mode"); 60 | Serial.println("Set packet type to LoRa"); 61 | 62 | // Set frequency 63 | uint64_t frf = ((uint64_t) frequency << 19) / 32000000; 64 | sx127x_writeRegister(SX127X_REG_FRF_MSB, (uint8_t) (frf >> 16)); 65 | sx127x_writeRegister(SX127X_REG_FRF_MID, (uint8_t) (frf >> 8)); 66 | sx127x_writeRegister(SX127X_REG_FRF_LSB, (uint8_t) frf); 67 | Serial.print("Set frequency to "); 68 | Serial.print(frequency / 1000000); 69 | Serial.println(" MHz"); 70 | 71 | // Set rx gain to selected gain 72 | Serial.print("Set RX gain to "); 73 | if (boost == SX127X_RX_GAIN_POWER_SAVING) Serial.println("power saving gain"); 74 | else if (boost == SX127X_RX_GAIN_BOOSTED) Serial.println("boosted gain"); 75 | uint8_t LnaBoostHf = boost ? 0x03 : 0x00; 76 | uint8_t AgcOn = level == SX127X_RX_GAIN_AUTO ? 0x01 : 0x00; 77 | sx127x_writeRegister(SX127X_REG_LNA, LnaBoostHf | (level << 5)); 78 | sx127x_writeBits(SX127X_REG_MODEM_CONFIG_3, AgcOn, 2, 1); 79 | 80 | // Set modulation param and packet param 81 | Serial.println("Set modulation with predefined parameters"); 82 | Serial.println("Set packet with predefined parameters"); 83 | sx127x_writeBits(SX127X_REG_MODEM_CONFIG_2, sf, 4, 4); 84 | sx127x_writeBits(SX127X_REG_MODEM_CONFIG_1, bw, 4, 4); 85 | sx127x_writeBits(SX127X_REG_MODEM_CONFIG_1, cr, 1, 3); 86 | sx127x_writeBits(SX127X_REG_MODEM_CONFIG_1, headerType, 0, 1); 87 | sx127x_writeBits(SX127X_REG_MODEM_CONFIG_2, crcEn, 2, 1); 88 | sx127x_writeRegister(SX127X_REG_PREAMBLE_MSB, preambleLen >> 8); 89 | sx127x_writeRegister(SX127X_REG_PREAMBLE_LSB, preambleLen); 90 | 91 | // Show modulation param and packet param registers 92 | uint8_t reg, reg_; 93 | reg = sx127x_readRegister(SX127X_REG_MODEM_CONFIG_1); 94 | Serial.print("Modem config 1 : 0x"); 95 | Serial.println(reg, HEX); 96 | reg = sx127x_readRegister(SX127X_REG_MODEM_CONFIG_2); 97 | Serial.print("Modem config 2 : 0x"); 98 | Serial.println(reg, HEX); 99 | reg = sx127x_readRegister(SX127X_REG_PREAMBLE_MSB); 100 | reg_ = sx127x_readRegister(SX127X_REG_PREAMBLE_LSB); 101 | Serial.print("Preamble length : 0x"); 102 | Serial.println(reg * 256 + reg_, HEX); 103 | 104 | // Set synchronize word 105 | sx127x_writeRegister(SX127X_REG_SYNC_WORD, syncword); 106 | reg = sx127x_readRegister(SX127X_REG_SYNC_WORD); 107 | Serial.print("Set syncWord to 0x"); 108 | Serial.println(reg, HEX); 109 | } 110 | 111 | uint8_t receiveFunction(char* message, uint8_t &length) { 112 | 113 | Serial.println("\n-- RECEIVE FUNCTION --"); 114 | uint8_t reg, reg_; 115 | 116 | // Activate interrupt when transmit done on DIO0 117 | Serial.println("Set RX done IRQ on DIO0"); 118 | sx127x_writeRegister(SX127X_REG_DIO_MAPPING_1, SX127X_DIO0_RX_DONE); 119 | // Attach irqPin to DIO0 120 | Serial.println("Attach interrupt on IRQ pin"); 121 | attachInterrupt(digitalPinToInterrupt(irqPin), checkReceiveDone, RISING); 122 | 123 | // Set txen and rxen pin state for receiving packet 124 | if (txenPin != -1 && rxenPin != -1) { 125 | digitalWrite(txenPin, LOW); 126 | digitalWrite(rxenPin, HIGH); 127 | } 128 | 129 | // Receive message 130 | Serial.println("Receiving message..."); 131 | sx127x_writeRegister(SX127X_REG_OP_MODE, SX127X_LORA_MODEM | SX127X_MODE_RX_CONTINUOUS); 132 | 133 | // Wait for RX done interrupt 134 | Serial.println("Wait for RX done interrupt"); 135 | while (!received) delayMicroseconds(4); 136 | Serial.println("Receive done"); 137 | // Clear transmit interrupt flag 138 | received = false; 139 | 140 | // Set mode to standby to end RX mode 141 | sx127x_writeBits(SX127X_REG_OP_MODE, SX127X_MODE_STDBY, 0, 3); 142 | Serial.println("Going to standby mode"); 143 | 144 | // Clear the interrupt status 145 | uint8_t irqStat = sx127x_readRegister(SX127X_REG_IRQ_FLAGS); 146 | sx127x_writeRegister(SX127X_REG_IRQ_FLAGS, SX127X_IRQ_RX_DONE); 147 | Serial.println("Clear IRQ status"); 148 | if (rxenPin != -1) { 149 | digitalWrite(rxenPin, LOW); 150 | } 151 | 152 | // Get FIFO address of received message and configure address pointer 153 | reg = sx127x_readRegister(SX127X_REG_FIFO_RX_CURRENT_ADDR); 154 | sx127x_writeRegister(SX127X_REG_FIFO_ADDR_PTR, reg); 155 | Serial.print("Set FIFO address pointer to FIFO RX base address (0x"); 156 | Serial.print(reg); 157 | Serial.println(")"); 158 | 159 | // Get payload length 160 | length = sx127x_readRegister(SX127X_REG_RX_NB_BYTES); 161 | Serial.print("Get message length ("); 162 | Serial.print(length); 163 | Serial.println(")"); 164 | 165 | // Get and display packet status 166 | Serial.println("Get received packet status"); 167 | float rssi = ((int16_t) sx127x_readRegister(SX127X_REG_PKT_RSSI_VALUE) - SX127X_RSSI_OFFSET_HF); 168 | float snr = (int8_t) sx127x_readRegister(SX127X_REG_PKT_SNR_VALUE) / 4.0; 169 | Serial.print("Packet status: RSSI = "); 170 | Serial.print(rssi); 171 | Serial.print(" | SNR = "); 172 | Serial.println(snr); 173 | 174 | // Read message from buffer 175 | Serial.print("Message in bytes : [ "); 176 | for (uint8_t i = 0; i < length; i++) { 177 | reg = sx127x_readRegister(SX127X_REG_FIFO); 178 | message[i] = (char) reg; 179 | Serial.print(reg); 180 | Serial.print(" "); 181 | } 182 | Serial.println("]"); 183 | 184 | // return interrupt status 185 | return irqStat; 186 | } 187 | 188 | void setup() { 189 | 190 | // Begin serial communication 191 | Serial.begin(38400); 192 | 193 | // Seetings for LoRa communication 194 | settingFunction(); 195 | } 196 | 197 | void loop() { 198 | 199 | // Receive message 200 | char message[13]; 201 | uint8_t length; 202 | uint8_t status = receiveFunction(message, length); 203 | 204 | // Display message if receive success or display status if error 205 | if (status & SX127X_IRQ_RX_DONE){ 206 | Serial.print("Message: \'"); 207 | for (uint8_t i=0; i< length; i++){ 208 | Serial.print(message[i]); 209 | } 210 | Serial.println("\'"); 211 | } 212 | else if(status & SX127X_IRQ_CRC_ERR){ 213 | Serial.println("CRC error"); 214 | } 215 | } 216 | -------------------------------------------------------------------------------- /examples/SX126x/SX126x_driver_tx/SX126x_driver_tx.ino: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | // Pin setting 4 | int8_t nssPin = 10, resetPin = 9, busyPin = 4, irqPin = 2, rxenPin = 7, txenPin = 8; 5 | 6 | // Clock reference setting. RF module using either TCXO or XTAL as clock reference 7 | // uncomment code below to use XTAL 8 | //#define SX126X_XTAL 9 | //uint8_t xtalCap[2] = {0x12, 0x12}; 10 | // uncomment code below to use TCXO 11 | #define SX126X_TCXO 12 | uint8_t dio3Voltage = SX126X_DIO3_OUTPUT_1_8; 13 | uint32_t tcxoDelay = SX126X_TCXO_DELAY_10; 14 | 15 | // Configure DIO2 as RF switch control or using TXEN and RXEN pin 16 | #define SX126X_USING_TXEN_RXEN 17 | 18 | // RF frequency setting 19 | uint32_t rfFrequency = 915000000UL; 20 | 21 | // PA and TX power setting 22 | uint8_t paDutyCycle = 0x02; 23 | uint8_t hpMax = 0x03; 24 | uint8_t deviceSel = 0x00; 25 | uint8_t power = 0x16; 26 | 27 | // Define modulation parameters setting 28 | uint8_t sf = 7; // spreading factor 7 29 | uint8_t bw = SX126X_BW_125000; // 125 kHz 30 | uint8_t cr = SX126X_CR_4_5; // 4/5 code rate 31 | uint8_t ldro = SX126X_LDRO_OFF; // low data rate optimize off 32 | 33 | // Define packet parameters setting 34 | uint16_t preambleLength = 12; // 12 bytes preamble 35 | uint8_t headerType = SX126X_HEADER_EXPLICIT; // explicit packet header 36 | uint8_t payloadLength = 64; // 64 bytes payload 37 | uint8_t crcType = SX126X_CRC_ON; // cyclic redundancy check (CRC) on 38 | uint8_t invertIq = SX126X_IQ_STANDARD; // standard IQ setup 39 | 40 | // SyncWord setting 41 | uint8_t sw[2] = {0x34, 0x44}; 42 | 43 | volatile bool transmitted = false; 44 | 45 | void checkTransmitDone() { 46 | transmitted = true; 47 | } 48 | 49 | void settingFunction() { 50 | 51 | Serial.println("-- SETTING FUNCTION --"); 52 | 53 | // Pin setting 54 | Serial.println("Setting pins"); 55 | sx126x_setPins(nssPin, busyPin); 56 | pinMode(irqPin, INPUT); 57 | 58 | // Reset RF module by setting resetPin to LOW and begin SPI communication 59 | Serial.println("Resetting RF module"); 60 | sx126x_reset(resetPin); 61 | sx126x_begin(); 62 | 63 | // Set to standby mode 64 | sx126x_setStandby(SX126X_STANDBY_RC); 65 | if (!sx126x_busyCheck()) { 66 | Serial.println("Going to standby mode"); 67 | } else { 68 | Serial.println("Something wrong, can't set to standby mode"); 69 | } 70 | 71 | // Optionally configure TCXO or XTAL used in RF module 72 | #ifdef SX126X_TCXO 73 | Serial.println("Set RF module to use TCXO as clock reference"); 74 | sx126x_setDio3AsTcxoCtrl(dio3Voltage, tcxoDelay); 75 | #endif 76 | #ifdef SX126X_XTAL 77 | Serial.println("Set RF module to use XTAL as clock reference"); 78 | sx126x_writeRegister(SX126X_REG_XTA_TRIM, xtalCap, 2); 79 | #endif 80 | 81 | // Optionally configure DIO2 as RF switch control 82 | #ifdef SX126X_USING_TXEN_RXEN 83 | pinMode(txenPin, OUTPUT); 84 | pinMode(rxenPin, OUTPUT); 85 | #else 86 | Serial.println("Set RF switch is controlled by DIO2"); 87 | sx126x_setDio2AsRfSwitchCtrl(SX126X_DIO2_AS_RF_SWITCH); 88 | #endif 89 | 90 | // Set packet type to LoRa 91 | Serial.println("Set packet type to LoRa"); 92 | sx126x_setPacketType(SX126X_LORA_MODEM); 93 | 94 | // Set frequency to selected frequency (rfFrequency = rfFreq * 32000000 / 2 ^ 25) 95 | Serial.print("Set frequency to "); 96 | Serial.print(rfFrequency / 1000000); 97 | Serial.println(" Mhz"); 98 | uint32_t rfFreq = ((uint64_t) rfFrequency * 33554432UL) / 32000000UL; 99 | sx126x_setRfFrequency(rfFreq); 100 | 101 | // Set tx power to selected TX power 102 | Serial.print("Set TX power to "); 103 | Serial.print(power, DEC); 104 | Serial.println(" dBm"); 105 | sx126x_setPaConfig(paDutyCycle, hpMax, deviceSel, 0x01); 106 | sx126x_setTxParams(power, SX126X_PA_RAMP_200U); 107 | 108 | // Configure modulation parameter with predefined spreading factor, bandwidth, coding rate, and low data rate optimize setting 109 | Serial.println("Set modulation with predefined parameters"); 110 | sx126x_setModulationParamsLoRa(sf, bw, cr, ldro); 111 | 112 | // Configure packet parameter with predefined preamble length, header mode type, payload length, crc type, and invert iq option 113 | Serial.println("Set packet with predefined parameters"); 114 | sx126x_setPacketParamsLoRa(preambleLength, headerType, payloadLength, crcType, invertIq); 115 | 116 | // Set predefined syncronize word 117 | Serial.print("Set syncWord to 0x"); 118 | Serial.println((sw[0] << 8) + sw[1], HEX); 119 | sx126x_writeRegister(SX126X_REG_LORA_SYNC_WORD_MSB, sw, 2); 120 | } 121 | 122 | uint16_t transmitFunction(char* message, uint8_t length, uint32_t timeout) { 123 | 124 | Serial.println("\n-- TRANSMIT FUNCTION --"); 125 | 126 | // Set buffer base address 127 | Serial.println("Mark a pointer in buffer for transmit message"); 128 | sx126x_setBufferBaseAddress(0x00, 0x80); 129 | 130 | // Write the message to buffer 131 | uint8_t* msgUint8 = (uint8_t*) message; 132 | Serial.print("Write message \'"); 133 | Serial.print(message); 134 | Serial.println("\' in buffer"); 135 | Serial.print("Message in bytes : [ "); 136 | sx126x_writeBuffer(0x00, msgUint8, length); 137 | for (uint8_t i = 0; i < length; i++) { 138 | Serial.print((uint8_t) message[i]); 139 | Serial.print(" "); 140 | } 141 | Serial.println("]"); 142 | 143 | // Set payload length same as message length 144 | Serial.print("Set payload length same as message length ("); 145 | Serial.print(length); 146 | Serial.println(")"); 147 | sx126x_setPacketParamsLoRa(preambleLength, headerType, length, crcType, invertIq); 148 | 149 | // Activate interrupt when transmit done on DIO1 150 | Serial.println("Set TX done and timeout IRQ on DIO1"); 151 | uint16_t mask = SX126X_IRQ_TX_DONE | SX126X_IRQ_TIMEOUT; 152 | sx126x_setDioIrqParams(mask, mask, SX126X_IRQ_NONE, SX126X_IRQ_NONE); 153 | // Attach irqPin to DIO1 154 | Serial.println("Attach interrupt on IRQ pin"); 155 | attachInterrupt(digitalPinToInterrupt(irqPin), checkTransmitDone, RISING); 156 | // Set txen and rxen pin state for transmitting packet 157 | #ifdef SX126X_USING_TXEN_RXEN 158 | digitalWrite(txenPin, HIGH); 159 | digitalWrite(rxenPin, LOW); 160 | #endif 161 | 162 | // Calculate timeout (timeout duration = timeout * 15.625 us) 163 | uint32_t tOut = timeout * 64; 164 | // Set RF module to TX mode to transmit message 165 | Serial.println("Transmitting LoRa packet"); 166 | sx126x_setTx(tOut); 167 | uint32_t tStart = millis(), tTrans = 0; 168 | 169 | // Wait for TX done interrupt and calcualte transmit time 170 | Serial.println("Wait for TX done interrupt"); 171 | while (!transmitted) delayMicroseconds(4); 172 | tTrans = millis() - tStart; 173 | // Clear transmit interrupt flag 174 | transmitted = false; 175 | Serial.println("Packet transmitted!"); 176 | 177 | // Display transmit time 178 | Serial.print("Transmit time = "); 179 | Serial.print(tTrans); 180 | Serial.println(" ms"); 181 | 182 | // Clear the interrupt status 183 | uint16_t irqStat; 184 | sx126x_getIrqStatus(&irqStat); 185 | Serial.println("Clear IRQ status"); 186 | sx126x_clearIrqStatus(irqStat); 187 | #ifdef SX126X_USING_TXEN_RXEN 188 | digitalWrite(txenPin, LOW); 189 | #endif 190 | 191 | // return interrupt status 192 | return irqStat; 193 | } 194 | 195 | void setup() { 196 | 197 | // Begin serial communication 198 | Serial.begin(38400); 199 | 200 | // Settings for LoRa communication 201 | settingFunction(); 202 | } 203 | 204 | void loop() { 205 | 206 | // Message to transmit 207 | char message[] = "HeLoRa World"; 208 | uint8_t nBytes = sizeof(message); 209 | 210 | // Transmit message 211 | uint32_t timeout = 1000; // 1000 ms timeout 212 | uint16_t status = transmitFunction(message, nBytes, timeout); 213 | 214 | // Display status if error 215 | if (status & SX126X_IRQ_TIMEOUT){ 216 | Serial.println("Transmit timeout"); 217 | } 218 | 219 | // Don't load RF module with continous transmit 220 | delay(10000); 221 | } 222 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | [![GitHub release (latest SemVer)](https://img.shields.io/github/v/release/chandrawi/LoRaRF-Arduino)](https://github.com/chandrawi/LoRaRF-Arduino/releases) 3 | [![GitHub license](https://img.shields.io/github/license/chandrawi/LoRaRF-Arduino)](https://github.com/chandrawi/LoRaRF-Arduino/blob/main/LICENSE) 4 | 5 | # LoRa-RF Arduino Library 6 | 7 | Arduino LoRa-RF library used for transmitting and receiving data using LoRa module with Semtech SX126x series, SX127x series, or LLCC68. The library works by interfacing SPI port and some I/O pins. Support for configuring frequency, modulation parameter, transmit power, receive gain and other RF parameters on both LoRa and FSK modulation also support for handling transmit and receive using interrupt signal. 8 | 9 | This readme is written for quick start guide. Visit this [link](https://github.com/chandrawi/LoRaRF-Arduino/wiki) for complete documentation. 10 | 11 | ## Hardware Compatibility 12 | 13 | Theoritically all LoRa modules using SX126x series (SX1261, SX1262, SX1268), SX127x series (SX1272, SX1276, SX1277, SX1278, SX1279), or LLCC68 will compatible using this library. Arduino LoRa development board which interfaced using SPI to a LoRa module also theoritically compatible. 14 | 15 | Some LoRa module which already tested and confirmed compatible are: 16 | * Ebyte: E19-433M20SC, E19-915M20S, E19-433M30S, E19-915M30S, E22-400M22S, E22-900M22S, E22-400M30S, E22-900M30S 17 | * HopeRF: RFM95W, RFM96W, RFM98W 18 | 19 | Please note that LoRa modules use 3.3V for power supply and I/O ports. Care must me taken for connecting 5V arduino to LoRa module. 20 | 21 | ## Installation 22 | 23 | ### Using the Arduino IDE Library Manager 24 | 25 | 1. Choose `Sketch` -> `Include Library` -> `Manage Libraries...` 26 | 2. Type `LoRaRF` into the search box. 27 | 3. Search a row with title `LoRaRF` by Chandra Wijaya. 28 | 4. Click the `Install` button to install the library. 29 | 30 | ### Using Git 31 | 32 | Open terminal, Git bash, or command prompt in Arduino library folder then run following command. Default library folder for windows is `C:\Users\{username}\Documents\Arduino` and for linux is `~/Documents/Arduino/libraries/`. 33 | ```sh 34 | git clone https://github.com/chandrawi/LoRaRF-Arduino.git 35 | ``` 36 | 37 | ## Initialization 38 | 39 | To work with the library, first you must include `SX126x` header or `SX127x` header depending LoRa module you use. For LLCC68 include SX126x header. Then initialize class in the header by creating an object. 40 | 41 | ```c++ 42 | // for SX126x series or LLCC68 43 | #include 44 | SX126x LoRa; 45 | 46 | // for SX127x series 47 | #include 48 | SX127x LoRa; 49 | ``` 50 | 51 | Before calling any configuration methods, doing transmit or receive operation you must call `begin()` method. You can call `begin()` method inside Arduino `setup()` function. 52 | 53 | ```c++ 54 | void setup() { 55 | LoRa.begin(); 56 | // configuration code goes here 57 | } 58 | 59 | void loop() { 60 | // transmit and receive operation goes here 61 | } 62 | ``` 63 | 64 | ## Hardware Configuration 65 | 66 | ### Wiring Connections 67 | 68 | Power pins, SPI pins, and `RESET` pin must be connected between arduino and LoRa module. For SX126x series and LLCC68, a `BUSY` pin also must be connected. If you want to use interrupt operation, you can connect `DIO0` for SX127x series and one of `DIO1`, `DIO2`, or `DIO3` pin for SX126x series. You also should connect `TXEN` and `RXEN` pins if your LoRa module have those pins. 69 | 70 | The default Arduino pins used for connecting to SX126x and SX127x are as follows. 71 | 72 | | Semtech SX126x | Semtech SX127x | Arduino | 73 | | :------------: | :-------------:| :------:| 74 | | VCC | VCC | 3.3V | 75 | | GND | GND | GND | 76 | | SCK | SCK | SCK | 77 | | MISO | MISO | MISO | 78 | | MOSI | MOSI | MOSI | 79 | | NSS | NSS | 10 | 80 | | RESET | RESET | 9 | 81 | | BUSY | | 4| 82 | | DIO1 | DIO0 | -1 (unused) | 83 | | TXEN | TXEN | -1 (unused) | 84 | | RXEN | RXEN | -1 (unused) | 85 | 86 | ### SPI Port Configuration 87 | 88 | To change Arduino default SPI port or SPI frequency call `setSPI()` method before `begin()` method. 89 | ```c++ 90 | LoRa.setSPI(SPI2, 16000000); 91 | LoRa.begin(); 92 | ``` 93 | 94 | ### I/O Pins Configuration 95 | 96 | To configure I/O pins (NSS, RESET, BUSY, IRQ, TXEN, RXEN pin) call `setPins()` before `begin()` method. 97 | ```c++ 98 | // set NSS->10, RESET->9, BUSY->4, DIO1->2, TXEN->8, RXEN->7 for SX126x series 99 | LoRa.setPins(10, 9, 2, 4, 8, 7); 100 | // set NSS->10, RESET->9, DIO0->2, TXEN->8, RXEN->7 for SX127x series 101 | LoRa.setPins(10, 9, 2, 8, 7); 102 | LoRa.begin(); 103 | ``` 104 | 105 | ## Modem Configuration 106 | 107 | Before transmit or receive operation you can configure transmit power and receive gain or matching frequency, modulation parameter, packet parameter, and synchronize word with other LoRa device you want communicate. 108 | 109 | ### Transmit Power 110 | 111 | ```c++ 112 | // set transmit power to +22 dBm for SX1262 113 | LoRa.setTxPower(22, SX126X_TX_POWER_SX1262); 114 | // set transmit power to +20 dBm for SX127x series using boost pin 115 | LoRa.setTxPower(20, SX127X_TX_POWER_PA_BOOST); 116 | ``` 117 | 118 | ### Receive Gain 119 | 120 | ```c++ 121 | // set receive gain to power saving 122 | LoRa.setRxGain(LORA_RX_GAIN_POWER_SAVING); 123 | // set receive gain to boosted and AGC on for SX127x series 124 | LoRa.setRxGain(LORA_RX_GAIN_BOOSTED, true); 125 | ``` 126 | 127 | ### Frequency 128 | 129 | ```c++ 130 | // Set frequency to 915 Mhz 131 | LoRa.setFrequency(915000000); 132 | ``` 133 | 134 | ### Modulation Parameter 135 | 136 | ```c++ 137 | // set spreading factor 8, bandwidth 125 kHz, coding rate 4/5, and low data rate optimization off 138 | LoRa.setLoRaModulation(8, 125000, 5, false); 139 | ``` 140 | 141 | ### Packet Parameter 142 | 143 | ```c++ 144 | // set explicit header mode, preamble length 12, payload length 15, CRC on and no invert IQ operation 145 | LoRa.setLoRaPacket(LORA_HEADER_EXPLICIT, 12, 15, true, false); 146 | ``` 147 | 148 | ### Synchronize Word 149 | 150 | ```c++ 151 | // Set syncronize word for public network (0x3444) 152 | LoRa.setSyncWord(0x3444); 153 | ``` 154 | 155 | ## Transmit Operation 156 | 157 | Transmit operation begin with calling `beginPacket()` method following by `write()` method to write package to be tansmitted and ended with calling `endPacket()` method. For example, to transmit "HeLoRa World!" message and an increment counter you can use following code. 158 | 159 | ```c++ 160 | // message and counter to transmit 161 | char message[] = "HeLoRa World!"; 162 | uint8_t counter = 0; 163 | 164 | LoRa.beginPacket(); 165 | LoRa.write(message, sizeof(message)); // write multiple bytes 166 | LoRa.write(counter++); // write single byte 167 | LoRa.endPacket(); 168 | LoRa.wait(); 169 | ``` 170 | 171 | For more detail about transmit operation, please visit this [link](https://github.com/chandrawi/LoRaRF-Arduino/wiki/Transmit-Operation). 172 | 173 | ## Receive Operation 174 | 175 | Receive operation begin with calling `request()` method following by `read()` method to read received package. `available()` method can be used to get length of remaining package. For example, to receive message and a counter in last byte you can use following code. 176 | 177 | ```c++ 178 | LoRa.request(); 179 | LoRa.wait(); 180 | 181 | // get message and counter in last byte 182 | const uint8_t length = LoRa.available() - 1; 183 | char message[length]; 184 | uint8_t i=0; 185 | while (LoRa.available() > 1){ 186 | message[i++] = LoRa.read(); // read multiple bytes 187 | } 188 | uint8_t counter = LoRa.read(); // read single byte 189 | ``` 190 | 191 | For more detail about receive operation, please visit this [link](https://github.com/chandrawi/LoRaRF-Arduino/wiki/Receive-Operation). 192 | 193 | ## Examples 194 | 195 | See examples for [SX126x](https://github.com/chandrawi/LoRaRF-Arduino/tree/main/examples/SX126x), [SX127x](https://github.com/chandrawi/LoRaRF-Arduino/tree/main/examples/SX127x), and [simple network implementation](https://github.com/chandrawi/LoRaRF-Arduino/tree/main/examples/Network). 196 | 197 | ## Contributor 198 | 199 | [Chandra Wijaya Sentosa](https://github.com/chandrawi) <> 200 | -------------------------------------------------------------------------------- /src/SX127x_driver.h: -------------------------------------------------------------------------------- 1 | #ifndef _SX127X_DRIVER_H_ 2 | #define _SX127X_DRIVER_H_ 3 | 4 | #include 5 | #include 6 | 7 | // SX127X register map 8 | #define SX127X_REG_FIFO 0x00 9 | #define SX127X_REG_OP_MODE 0x01 10 | #define SX127X_REG_FRF_MSB 0x06 11 | #define SX127X_REG_FRF_MID 0x07 12 | #define SX127X_REG_FRF_LSB 0x08 13 | #define SX127X_REG_PA_CONFIG 0x09 14 | #define SX127X_REG_OCP 0x0B 15 | #define SX127X_REG_LNA 0x0C 16 | #define SX127X_REG_FIFO_ADDR_PTR 0x0D 17 | #define SX127X_REG_FIFO_TX_BASE_ADDR 0x0E 18 | #define SX127X_REG_FIFO_RX_BASE_ADDR 0x0F 19 | #define SX127X_REG_FIFO_RX_CURRENT_ADDR 0x10 20 | #define SX127X_REG_IRQ_FLAGS 0x12 21 | #define SX127X_REG_RX_NB_BYTES 0x13 22 | #define SX127X_REG_PKT_SNR_VALUE 0x19 23 | #define SX127X_REG_PKT_RSSI_VALUE 0x1A 24 | #define SX127X_REG_RSSI_VALUE 0x1B 25 | #define SX127X_REG_MODEM_CONFIG_1 0x1D 26 | #define SX127X_REG_MODEM_CONFIG_2 0x1E 27 | #define SX127X_REG_SYMB_TIMEOUT 0x1F 28 | #define SX127X_REG_PREAMBLE_MSB 0x20 29 | #define SX127X_REG_PREAMBLE_LSB 0x21 30 | #define SX127X_REG_PAYLOAD_LENGTH 0x22 31 | #define SX127X_REG_MODEM_CONFIG_3 0x26 32 | #define SX127X_REG_FREQ_ERROR_MSB 0x28 33 | #define SX127X_REG_FREQ_ERROR_MID 0x29 34 | #define SX127X_REG_FREQ_ERROR_LSB 0x2A 35 | #define SX127X_REG_RSSI_WIDEBAND 0x2C 36 | #define SX127X_REG_DETECTION_OPTIMIZE 0x31 37 | #define SX127X_REG_INVERTIQ 0x33 38 | #define SX127X_REG_DETECTION_THRESHOLD 0x37 39 | #define SX127X_REG_SYNC_WORD 0x39 40 | #define SX127X_REG_INVERTIQ2 0x3B 41 | #define SX127X_REG_DIO_MAPPING_1 0x40 42 | #define SX127X_REG_VERSION 0x42 43 | #define SX127X_REG_TCXO 0x4B 44 | #define SX127X_REG_PA_DAC 0x4D 45 | 46 | // Modem options 47 | #define SX127X_FSK_MODEM 0x00 // GFSK packet type 48 | #define SX127X_LORA_MODEM 0x01 // LoRa packet type 49 | #define SX127X_OOK_MODEM 0x02 // OOK packet type 50 | 51 | // Long range mode and Modulation type 52 | #define SX127X_LONG_RANGE_MODE 0x80 // GFSK packet type 53 | #define SX127X_MODULATION_OOK 0x20 // OOK packet type 54 | #define SX127X_MODULATION_FSK 0x00 // LoRa packet type 55 | 56 | // Devices modes 57 | #define SX127X_MODE_SLEEP 0x00 // sleep 58 | #define SX127X_MODE_STDBY 0x01 // standby 59 | #define SX127X_MODE_TX 0x03 // transmit 60 | #define SX127X_MODE_RX_CONTINUOUS 0x05 // continuous receive 61 | #define SX127X_MODE_RX_SINGLE 0x06 // single receive 62 | #define SX127X_MODE_CAD 0x07 // channel activity detection (CAD) 63 | 64 | // Rx operation mode 65 | #define SX127X_RX_SINGLE 0x000000 // Rx timeout duration: no timeout (Rx single mode) 66 | #define SX127X_RX_CONTINUOUS 0xFFFFFF // infinite (Rx continuous mode) 67 | 68 | // TX power options 69 | #define SX127X_TX_POWER_RFO 0x00 // output power is limited to +14 dBm 70 | #define SX127X_TX_POWER_PA_BOOST 0x80 // output power is limited to +20 dBm 71 | 72 | // RX gain options 73 | #define SX127X_RX_GAIN_POWER_SAVING 0x00 // gain used in Rx mode: power saving gain (default) 74 | #define SX127X_RX_GAIN_BOOSTED 0x01 // boosted gain 75 | #define SX127X_RX_GAIN_AUTO 0x00 // option enable auto gain controller (AGC) 76 | 77 | // Header type 78 | #define SX127X_HEADER_EXPLICIT 0x00 // explicit header mode 79 | #define SX127X_HEADER_IMPLICIT 0x01 // implicit header mode 80 | 81 | // LoRa syncword 82 | #define SX127X_SYNCWORD_LORAWAN 0x34 // reserved LoRaWAN syncword 83 | 84 | // Oscillator options 85 | #define SX127X_OSC_CRYSTAL 0x00 // crystal oscillator with external crystal 86 | #define SX127X_OSC_TCXO 0x10 // external clipped sine TCXO AC-connected to XTA pin 87 | 88 | // DIO mapping 89 | #define SX127X_DIO0_RX_DONE 0x00 // set DIO0 interrupt for: RX done 90 | #define SX127X_DIO0_TX_DONE 0x40 // TX done 91 | #define SX127X_DIO0_CAD_DONE 0x80 // CAD done 92 | 93 | // IRQ flags 94 | #define SX127X_IRQ_CAD_DETECTED 0x01 // Valid Lora signal detected during CAD operation 95 | #define SX127X_IRQ_FHSS_CHANGE 0x02 // FHSS change channel interrupt 96 | #define SX127X_IRQ_CAD_DONE 0x04 // channel activity detection finished 97 | #define SX127X_IRQ_TX_DONE 0x08 // packet transmission completed 98 | #define SX127X_IRQ_HEADER_VALID 0x10 // valid LoRa header received 99 | #define SX127X_IRQ_CRC_ERR 0x20 // wrong CRC received 100 | #define SX127X_IRQ_RX_DONE 0x40 // packet received 101 | #define SX127X_IRQ_RX_TIMEOUT 0x80 // waiting packet received timeout 102 | 103 | // Rssi offset 104 | #define SX127X_RSSI_OFFSET_LF 164 // low band frequency RSSI offset 105 | #define SX127X_RSSI_OFFSET_HF 157 // high band frequency RSSI offset 106 | #define SX1272_RSSI_OFFSET 139 // frequency RSSI offset for SX1272 107 | #define SX127X_BAND_THRESHOLD 525E6 // threshold between low and high band frequency 108 | 109 | // TX and RX operation status 110 | #define SX127X_STATUS_DEFAULT LORA_STATUS_DEFAULT 111 | #define SX127X_STATUS_TX_WAIT LORA_STATUS_TX_WAIT 112 | #define SX127X_STATUS_TX_TIMEOUT LORA_STATUS_TX_TIMEOUT 113 | #define SX127X_STATUS_TX_DONE LORA_STATUS_TX_DONE 114 | #define SX127X_STATUS_RX_WAIT LORA_STATUS_RX_WAIT 115 | #define SX127X_STATUS_RX_CONTINUOUS LORA_STATUS_RX_CONTINUOUS 116 | #define SX127X_STATUS_RX_TIMEOUT LORA_STATUS_RX_TIMEOUT 117 | #define SX127X_STATUS_RX_DONE LORA_STATUS_RX_DONE 118 | #define SX127X_STATUS_HEADER_ERR LORA_STATUS_HEADER_ERR 119 | #define SX127X_STATUS_CRC_ERR LORA_STATUS_CRC_ERR 120 | #define SX127X_STATUS_CAD_WAIT LORA_STATUS_CAD_WAIT 121 | #define SX127X_STATUS_CAD_DETECTED LORA_STATUS_CAD_DETECTED 122 | #define SX127X_STATUS_CAD_DONE LORA_STATUS_CAD_DONE 123 | 124 | // Default Hardware Configuration 125 | #define SX127X_PIN_NSS 10 126 | #define SX127X_PIN_RESET 4 127 | #define SX127X_SPI SPI 128 | #ifdef __AVR__ 129 | #define SX127X_SPI_FREQUENCY F_CPU / 2 // SPI speed set to half of CPU frequency for AVR processor 130 | #else 131 | #define SX127X_SPI_FREQUENCY 16000000 // Maximum LoRa SPI frequency 132 | #endif 133 | 134 | void sx127x_setSPI(SPIClass &SpiObject, uint32_t frequency); 135 | void sx127x_setPins(int8_t nss); 136 | void sx127x_reset(int8_t reset); 137 | void sx127x_begin(); 138 | 139 | // SX126x driver: Register access functions 140 | void sx127x_writeBits(uint8_t address, uint8_t data, uint8_t position, uint8_t length); 141 | void sx127x_writeRegister(uint8_t address, uint8_t data); 142 | uint8_t sx127x_readRegister(uint8_t address); 143 | uint8_t sx127x_transfer(uint8_t address, uint8_t data); 144 | 145 | #endif -------------------------------------------------------------------------------- /examples/SX126x/SX126x_driver_rx/SX126x_driver_rx.ino: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | // Pin setting 4 | int8_t nssPin = 10, resetPin = 9, busyPin = 4, irqPin = 2, rxenPin = 7, txenPin = 8; 5 | 6 | // Clock reference setting. RF module using either TCXO or XTAL as clock reference 7 | // uncomment code below to use XTAL 8 | //#define SX126X_XTAL 9 | //uint8_t xtalCap[2] = {0x12, 0x12}; 10 | // uncomment code below to use TCXO 11 | #define SX126X_TCXO 12 | uint8_t dio3Voltage = SX126X_DIO3_OUTPUT_1_8; 13 | uint32_t tcxoDelay = SX126X_TCXO_DELAY_10; 14 | 15 | // Configure DIO2 as RF switch control or using TXEN and RXEN pin 16 | #define SX126X_USING_TXEN_RXEN 17 | 18 | // RF frequency setting 19 | uint32_t rfFrequency = 915000000UL; 20 | 21 | // RX gain setting 22 | uint8_t gain = SX126X_POWER_SAVING_GAIN; 23 | 24 | // Define modulation parameters setting 25 | uint8_t sf = 7; // spreading factor 7 26 | uint8_t bw = SX126X_BW_125000; // 125 kHz 27 | uint8_t cr = SX126X_CR_4_5; // 4/5 code rate 28 | uint8_t ldro = SX126X_LDRO_OFF; // low data rate optimize off 29 | 30 | // Define packet parameters setting 31 | uint16_t preambleLength = 12; // 12 bytes preamble 32 | uint8_t headerType = SX126X_HEADER_EXPLICIT; // explicit packet header 33 | uint8_t payloadLength = 64; // 64 bytes payload 34 | uint8_t crcType = SX126X_CRC_ON; // cyclic redundancy check (CRC) on 35 | uint8_t invertIq = SX126X_IQ_STANDARD; // standard IQ setup 36 | 37 | // SyncWord setting 38 | uint8_t sw[2] = {0x34, 0x44}; 39 | 40 | volatile bool received = false; 41 | 42 | void checkReceiveDone() { 43 | received = true; 44 | } 45 | 46 | void settingFunction() { 47 | 48 | Serial.println("-- SETTING FUNCTION --"); 49 | 50 | // Pin setting 51 | Serial.println("Setting pins"); 52 | sx126x_setPins(nssPin, busyPin); 53 | pinMode(irqPin, INPUT); 54 | 55 | // Reset RF module by setting resetPin to LOW and begin SPI communication 56 | Serial.println("Resetting RF module"); 57 | sx126x_reset(resetPin); 58 | sx126x_begin(); 59 | 60 | // Set to standby mode 61 | sx126x_setStandby(SX126X_STANDBY_RC); 62 | if (!sx126x_busyCheck()) { 63 | Serial.println("Going to standby mode"); 64 | } else { 65 | Serial.println("Something wrong, can't set to standby mode"); 66 | } 67 | 68 | // Optionally configure TCXO or XTAL used in RF module 69 | #ifdef SX126X_TCXO 70 | Serial.println("Set RF module to use TCXO as clock reference"); 71 | sx126x_setDio3AsTcxoCtrl(dio3Voltage, tcxoDelay); 72 | #endif 73 | #ifdef SX126X_XTAL 74 | Serial.println("Set RF module to use XTAL as clock reference"); 75 | sx126x_writeRegister(SX126X_REG_XTA_TRIM, xtalCap, 2); 76 | #endif 77 | 78 | // Optionally configure DIO2 as RF switch control 79 | #ifdef SX126X_USING_TXEN_RXEN 80 | pinMode(txenPin, OUTPUT); 81 | pinMode(rxenPin, OUTPUT); 82 | #else 83 | Serial.println("Set RF switch is controlled by DIO2"); 84 | sx126x_setDio2AsRfSwitchCtrl(SX126X_DIO2_AS_RF_SWITCH); 85 | #endif 86 | 87 | // Set packet type to LoRa 88 | Serial.println("Set packet type to LoRa"); 89 | sx126x_setPacketType(SX126X_LORA_MODEM); 90 | 91 | // Set frequency to selected frequency (rfFrequency = rfFreq * 32000000 / 2 ^ 25) 92 | Serial.print("Set frequency to "); 93 | Serial.print(rfFrequency / 1000000); 94 | Serial.println(" Mhz"); 95 | uint32_t rfFreq = ((uint64_t) rfFrequency * 33554432UL) / 32000000UL; 96 | sx126x_setRfFrequency(rfFreq); 97 | 98 | // Set rx gain to selected gain 99 | Serial.print("Set RX gain to "); 100 | if (gain == SX126X_POWER_SAVING_GAIN) Serial.println("power saving gain"); 101 | else if (gain == SX126X_BOOSTED_GAIN) Serial.println("boosted gain"); 102 | sx126x_writeRegister(SX126X_REG_RX_GAIN, &gain, 1); 103 | 104 | // Configure modulation parameter with predefined spreading factor, bandwidth, coding rate, and low data rate optimize setting 105 | Serial.println("Set modulation with predefined parameters"); 106 | sx126x_setModulationParamsLoRa(sf, bw, cr, ldro); 107 | 108 | // Configure packet parameter with predefined preamble length, header mode type, payload length, crc type, and invert iq option 109 | Serial.println("Set packet with predefined parameters"); 110 | sx126x_setPacketParamsLoRa(preambleLength, headerType, payloadLength, crcType, invertIq); 111 | 112 | // Set predefined syncronize word 113 | Serial.print("Set syncWord to 0x"); 114 | Serial.println((sw[0] << 8) + sw[1], HEX); 115 | sx126x_writeRegister(SX126X_REG_LORA_SYNC_WORD_MSB, sw, 2); 116 | } 117 | 118 | uint16_t receiveFunction(char* message, uint8_t &len, uint32_t timeout) { 119 | 120 | Serial.println("\n-- RECEIVE FUNCTION --"); 121 | 122 | // Activate interrupt when receive done on DIO1 123 | Serial.println("Set RX done, timeout, and CRC error IRQ on DIO1"); 124 | uint16_t mask = SX126X_IRQ_RX_DONE | SX126X_IRQ_TIMEOUT | SX126X_IRQ_CRC_ERR; 125 | sx126x_setDioIrqParams(mask, mask, SX126X_IRQ_NONE, SX126X_IRQ_NONE); 126 | // Attach irqPin to DIO1 127 | Serial.println("Attach interrupt on IRQ pin"); 128 | attachInterrupt(digitalPinToInterrupt(irqPin), checkReceiveDone, RISING); 129 | // Set txen and rxen pin state for receiving packet 130 | #ifdef SX126X_USING_TXEN_RXEN 131 | digitalWrite(txenPin, LOW); 132 | digitalWrite(rxenPin, HIGH); 133 | #endif 134 | 135 | // Calculate timeout (timeout duration = timeout * 15.625 us) 136 | uint32_t tOut = timeout * 64; 137 | if (timeout == SX126X_RX_CONTINUOUS) tOut = SX126X_RX_CONTINUOUS; 138 | // Set RF module to RX mode to receive message 139 | Serial.println("Receiving LoRa packet within predefined timeout"); 140 | sx126x_setRx(tOut); 141 | 142 | // Wait for RX done interrupt 143 | Serial.println("Wait for RX done interrupt"); 144 | while (!received) delayMicroseconds(4); 145 | // Clear transmit interrupt flag 146 | received = false; 147 | 148 | // Clear the interrupt status 149 | uint16_t irqStat; 150 | sx126x_getIrqStatus(&irqStat); 151 | Serial.println("Clear IRQ status"); 152 | sx126x_clearIrqStatus(irqStat); 153 | #ifdef SX126X_USING_TXEN_RXEN 154 | digitalWrite(rxenPin, LOW); 155 | #endif 156 | 157 | // Exit function if timeout reached 158 | if (irqStat & SX126X_IRQ_TIMEOUT) return irqStat; 159 | Serial.println("Packet received!"); 160 | 161 | // Get last received length and buffer base address 162 | Serial.println("Get received length and buffer base address"); 163 | uint8_t payloadLengthRx, rxStartBufferPointer; 164 | sx126x_getRxBufferStatus(&payloadLengthRx, &rxStartBufferPointer); 165 | uint8_t msgUint8[payloadLengthRx]; 166 | 167 | // Get and display packet status 168 | Serial.println("Get received packet status"); 169 | uint8_t rssiPkt, snrPkt, signalRssiPkt; 170 | sx126x_getPacketStatus(&rssiPkt, &snrPkt, &signalRssiPkt); 171 | float rssi = rssiPkt / -2; 172 | float snr = snrPkt / 4; 173 | float signalRssi = signalRssiPkt / -2; 174 | Serial.print("Packet status: RSSI = "); 175 | Serial.print(rssi); 176 | Serial.print(" | SNR = "); 177 | Serial.print(snr); 178 | Serial.print(" | signalRSSI = "); 179 | Serial.println(signalRssi); 180 | 181 | // Read message from buffer 182 | Serial.println("Read message from buffer"); 183 | Serial.print("Message in bytes : [ "); 184 | sx126x_readBuffer(rxStartBufferPointer, msgUint8, payloadLengthRx); 185 | len = payloadLengthRx; 186 | for (uint8_t i=0; i 2 | 3 | SPIClass* sx126x_spi = &SX126X_SPI; 4 | uint32_t sx126x_spiFrequency = SX126X_SPI_FREQUENCY; 5 | int8_t sx126x_nss = SX126X_PIN_NSS; 6 | int8_t sx126x_busy = SX126X_PIN_BUSY; 7 | 8 | void sx126x_setSPI(SPIClass &SpiObject, uint32_t frequency) 9 | { 10 | sx126x_spi = &SpiObject; 11 | sx126x_spiFrequency = frequency ? frequency : sx126x_spiFrequency; 12 | } 13 | 14 | void sx126x_setPins(int8_t nss, int8_t busy) 15 | { 16 | sx126x_nss = nss; 17 | sx126x_busy = busy; 18 | } 19 | 20 | void sx126x_reset(int8_t reset) 21 | { 22 | pinMode(reset, OUTPUT); 23 | digitalWrite(reset, LOW); 24 | delayMicroseconds(500); 25 | digitalWrite(reset, HIGH); 26 | delayMicroseconds(100); 27 | } 28 | 29 | void sx126x_begin() 30 | { 31 | pinMode(sx126x_nss, OUTPUT); 32 | pinMode(sx126x_busy, INPUT); 33 | sx126x_spi->begin(); 34 | } 35 | 36 | bool sx126x_busyCheck(uint32_t timeout) 37 | { 38 | uint32_t t = millis(); 39 | while (digitalRead(sx126x_busy) == HIGH) if (millis() - t > timeout) return true; 40 | return false; 41 | } 42 | 43 | void sx126x_setSleep(uint8_t sleepConfig) 44 | { 45 | sx126x_transfer(0x84, &sleepConfig, 1); 46 | } 47 | 48 | void sx126x_setStandby(uint8_t standbyConfig) 49 | { 50 | sx126x_transfer(0x80, &standbyConfig, 1); 51 | } 52 | 53 | void sx126x_setFs() 54 | { 55 | sx126x_transfer(0xC1, NULL, 0); 56 | } 57 | 58 | void sx126x_setTx(uint32_t timeout) 59 | { 60 | uint8_t buf[3]; 61 | buf[0] = timeout >> 16; 62 | buf[1] = timeout >> 8; 63 | buf[2] = timeout; 64 | sx126x_transfer(0x83, buf, 3); 65 | } 66 | 67 | void sx126x_setRx(uint32_t timeout) 68 | { 69 | uint8_t buf[3]; 70 | buf[0] = timeout >> 16; 71 | buf[1] = timeout >> 8; 72 | buf[2] = timeout; 73 | sx126x_transfer(0x82, buf, 3); 74 | } 75 | 76 | void sx126x_stopTimerOnPreamble(uint8_t enable) 77 | { 78 | sx126x_transfer(0x9F, &enable, 1); 79 | } 80 | 81 | void sx126x_setRxDutyCycle(uint32_t rxPeriod, uint32_t sleepPeriod) 82 | { 83 | uint8_t buf[6]; 84 | buf[0] = rxPeriod >> 16; 85 | buf[1] = rxPeriod >> 8; 86 | buf[2] = rxPeriod; 87 | buf[3] = sleepPeriod >> 16; 88 | buf[4] = sleepPeriod >> 8; 89 | buf[5] = sleepPeriod; 90 | sx126x_transfer(0x94, buf, 6); 91 | } 92 | 93 | void sx126x_setCad() 94 | { 95 | sx126x_transfer(0xC5, NULL, 0); 96 | } 97 | 98 | void sx126x_setTxContinuousWave() 99 | { 100 | sx126x_transfer(0xD1, NULL, 0); 101 | } 102 | 103 | void sx126x_setTxInfinitePreamble() 104 | { 105 | sx126x_transfer(0xD2, NULL, 0); 106 | } 107 | 108 | void sx126x_setRegulatorMode(uint8_t modeParam) 109 | { 110 | sx126x_transfer(0x96, &modeParam, 1); 111 | } 112 | 113 | void sx126x_calibrate(uint8_t calibParam) 114 | { 115 | sx126x_transfer(0x89, &calibParam, 1); 116 | } 117 | 118 | void sx126x_calibrateImage(uint8_t freq1, uint8_t freq2) 119 | { 120 | uint8_t buf[2]; 121 | buf[0] = freq1; 122 | buf[1] = freq2; 123 | sx126x_transfer(0x98, buf, 2); 124 | } 125 | 126 | void sx126x_setPaConfig(uint8_t paDutyCycle, uint8_t hpMax, uint8_t deviceSel, uint8_t paLut) 127 | { 128 | uint8_t buf[4]; 129 | buf[0] = paDutyCycle; 130 | buf[1] = hpMax; 131 | buf[2] = deviceSel; 132 | buf[3] = paLut; 133 | sx126x_transfer(0x95, buf, 4); 134 | } 135 | 136 | void sx126x_setRxTxFallbackMode(uint8_t fallbackMode) 137 | { 138 | sx126x_transfer(0x93, &fallbackMode, 1); 139 | } 140 | 141 | void sx126x_writeRegister(uint16_t address, uint8_t* data, uint8_t nData) 142 | { 143 | uint8_t bufAdr[2] = {address >> 8, address}; 144 | sx126x_transfer(0x0D, data, nData, bufAdr, 2, false); 145 | } 146 | 147 | void sx126x_readRegister(uint16_t address, uint8_t* data, uint8_t nData) 148 | { 149 | uint8_t bufAdr[3] = {address >> 8, address, 0x00}; 150 | sx126x_transfer(0x1D, data, nData, bufAdr, 3, true); 151 | } 152 | 153 | void sx126x_writeBuffer(uint8_t offset, uint8_t* data, uint8_t nData) 154 | { 155 | uint8_t bufOfs[1] = {offset}; 156 | sx126x_transfer(0x0E, data, nData, bufOfs, 1, false); 157 | } 158 | 159 | void sx126x_readBuffer(uint8_t offset, uint8_t* data, uint8_t nData) 160 | { 161 | uint8_t bufOfs[2] = {offset, 0x00}; 162 | sx126x_transfer(0x1E, data, nData, bufOfs, 2, true); 163 | } 164 | 165 | void sx126x_setDioIrqParams(uint16_t irqMask, uint16_t dio1Mask, uint16_t dio2Mask, uint16_t dio3Mask) 166 | { 167 | uint8_t buf[8]; 168 | buf[0] = irqMask >> 8; 169 | buf[1] = irqMask; 170 | buf[2] = dio1Mask >> 8; 171 | buf[3] = dio1Mask; 172 | buf[4] = dio2Mask >> 8; 173 | buf[5] = dio2Mask; 174 | buf[6] = dio3Mask >> 8; 175 | buf[7] = dio3Mask; 176 | sx126x_transfer(0x08, buf, 8); 177 | } 178 | 179 | void sx126x_getIrqStatus(uint16_t* irqStatus) 180 | { 181 | uint8_t buf[3]; 182 | sx126x_transfer(0x12, buf, 3); 183 | *irqStatus = (buf[1] << 8) | buf[2]; 184 | } 185 | 186 | void sx126x_clearIrqStatus(uint16_t clearIrqParam) 187 | { 188 | uint8_t buf[2]; 189 | buf[0] = clearIrqParam >> 8; 190 | buf[1] = clearIrqParam; 191 | sx126x_transfer(0x02, buf, 2); 192 | } 193 | 194 | void sx126x_setDio2AsRfSwitchCtrl(uint8_t enable) 195 | { 196 | sx126x_transfer(0x9D, &enable, 1); 197 | } 198 | 199 | void sx126x_setDio3AsTcxoCtrl(uint8_t tcxoVoltage, uint32_t delay) 200 | { 201 | uint8_t buf[4]; 202 | buf[0] = tcxoVoltage; 203 | buf[1] = delay >> 16; 204 | buf[2] = delay >> 8; 205 | buf[3] = delay; 206 | sx126x_transfer(0x97, buf, 4); 207 | } 208 | 209 | void sx126x_setRfFrequency(uint32_t rfFreq) 210 | { 211 | uint8_t buf[4]; 212 | buf[0] = rfFreq >> 24; 213 | buf[1] = rfFreq >> 16; 214 | buf[2] = rfFreq >> 8; 215 | buf[3] = rfFreq; 216 | sx126x_transfer(0x86, buf, 4); 217 | } 218 | 219 | void sx126x_setPacketType(uint8_t packetType) 220 | { 221 | sx126x_transfer(0x8A, &packetType, 1); 222 | } 223 | 224 | void sx126x_getPacketType(uint8_t* packetType) 225 | { 226 | uint8_t buf[2]; 227 | sx126x_transfer(0x11, buf, 2); 228 | *packetType = buf[1]; 229 | } 230 | 231 | void sx126x_setTxParams(uint8_t power, uint8_t rampTime) 232 | { 233 | uint8_t buf[2]; 234 | buf[0] = power; 235 | buf[1] = rampTime; 236 | sx126x_transfer(0x8E, buf, 2); 237 | } 238 | 239 | void sx126x_setModulationParamsLoRa(uint8_t sf, uint8_t bw, uint8_t cr, uint8_t ldro) 240 | { 241 | uint8_t buf[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; 242 | buf[0] = sf; 243 | buf[1] = bw; 244 | buf[2] = cr; 245 | buf[3] = ldro; 246 | sx126x_transfer(0x8B, buf, 8); 247 | } 248 | 249 | void sx126x_setModulationParamsFSK(uint32_t br, uint8_t pulseShape, uint8_t bandwidth, uint32_t Fdev) 250 | { 251 | uint8_t buf[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; 252 | buf[0] = br >> 16; 253 | buf[1] = br >> 8; 254 | buf[2] = br; 255 | buf[3] = pulseShape; 256 | buf[4] = bandwidth; 257 | buf[5] = Fdev >> 16; 258 | buf[6] = Fdev >> 8; 259 | buf[7] = Fdev; 260 | sx126x_transfer(0x8B, buf, 8); 261 | } 262 | 263 | void sx126x_setPacketParamsLoRa(uint16_t preambleLength, uint8_t headerType, uint8_t payloadLength, uint8_t crcType, uint8_t invertIq) 264 | { 265 | uint8_t buf[9] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; 266 | buf[0] = preambleLength >> 8; 267 | buf[1] = preambleLength; 268 | buf[2] = headerType; 269 | buf[3] = payloadLength; 270 | buf[4] = crcType; 271 | buf[5] = invertIq; 272 | sx126x_transfer(0x8C, buf, 9); 273 | } 274 | 275 | void sx126x_setPacketParamsFSK(uint16_t preambleLength, uint8_t preambleDetector, uint8_t syncWordLength, uint8_t addrComp, uint8_t packetType, uint8_t payloadLength, uint8_t crcType, uint8_t whitening) 276 | { 277 | uint8_t buf[9] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; 278 | buf[0] = preambleLength >> 8; 279 | buf[1] = preambleLength; 280 | buf[2] = preambleDetector; 281 | buf[3] = syncWordLength; 282 | buf[4] = addrComp; 283 | buf[5] = packetType; 284 | buf[6] = payloadLength; 285 | buf[7] = crcType; 286 | buf[8] = whitening; 287 | sx126x_transfer(0x8C, buf, 9); 288 | } 289 | 290 | void sx126x_setCadParams(uint8_t cadSymbolNum, uint8_t cadDetPeak, uint8_t cadDetMin, uint8_t cadExitMode, uint32_t cadTimeout) 291 | { 292 | uint8_t buf[7]; 293 | buf[0] = cadSymbolNum; 294 | buf[1] = cadDetPeak; 295 | buf[2] = cadDetMin; 296 | buf[3] = cadExitMode; 297 | buf[4] = cadTimeout >> 16; 298 | buf[5] = cadTimeout >> 8; 299 | buf[6] = cadTimeout; 300 | sx126x_transfer(0x88, buf, 7); 301 | } 302 | 303 | void sx126x_setBufferBaseAddress(uint8_t txBaseAddress, uint8_t rxBaseAddress) 304 | { 305 | uint8_t buf[2]; 306 | buf[0] = txBaseAddress; 307 | buf[1] = rxBaseAddress; 308 | sx126x_transfer(0x8F, buf, 2); 309 | } 310 | 311 | void sx126x_setLoRaSymbNumTimeout(uint8_t symbnum) 312 | { 313 | sx126x_transfer(0xA0, &symbnum, 1); 314 | } 315 | 316 | void sx126x_getStatus(uint8_t* status) 317 | { 318 | uint8_t buf; 319 | sx126x_transfer(0xC0, &buf, 1); 320 | *status = buf; 321 | } 322 | 323 | void sx126x_getRxBufferStatus(uint8_t* payloadLengthRx, uint8_t* rxStartBufferPointer) 324 | { 325 | uint8_t buf[3]; 326 | sx126x_transfer(0x13, buf, 3); 327 | *payloadLengthRx = buf[1]; 328 | *rxStartBufferPointer = buf[2]; 329 | } 330 | 331 | void sx126x_getPacketStatus(uint8_t* rssiPkt, uint8_t* snrPkt, uint8_t* signalRssiPkt) 332 | { 333 | uint8_t buf[4]; 334 | sx126x_transfer(0x14, buf, 4); 335 | *rssiPkt = buf[1]; 336 | *snrPkt = buf[2]; 337 | *signalRssiPkt = buf[3]; 338 | } 339 | 340 | void sx126x_getRssiInst(uint8_t* rssiInst) 341 | { 342 | uint8_t buf[2]; 343 | sx126x_transfer(0x15, buf, 2); 344 | *rssiInst = buf[1]; 345 | } 346 | 347 | void sx126x_getStats(uint16_t* nbPktReceived, uint16_t* nbPktCrcError, uint16_t* nbPktHeaderErr) 348 | { 349 | uint8_t buf[7]; 350 | sx126x_transfer(0x10, buf, 7); 351 | *nbPktReceived = (buf[1] << 8) | buf[2]; 352 | *nbPktCrcError = (buf[3] << 8) | buf[4]; 353 | *nbPktHeaderErr = (buf[5] << 8) | buf[6]; 354 | } 355 | 356 | void sx126x_resetStats() 357 | { 358 | uint8_t buf[6] = {0, 0, 0, 0, 0, 0}; 359 | sx126x_transfer(0x00, buf, 6); 360 | } 361 | 362 | void sx126x_getDeviceErrors(uint16_t* opError) 363 | { 364 | uint8_t buf[3]; 365 | sx126x_transfer(0x17, buf, 3); 366 | *opError = buf[2]; 367 | } 368 | 369 | void sx126x_clearDeviceErrors() 370 | { 371 | uint8_t buf[2] = {0, 0}; 372 | sx126x_transfer(0x07, buf, 2); 373 | } 374 | 375 | void sx126x_fixLoRaBw500(uint32_t bw) 376 | { 377 | uint8_t packetType; 378 | sx126x_getPacketType(&packetType); 379 | uint8_t value; 380 | sx126x_readRegister(SX126X_REG_TX_MODULATION, &value, 1); 381 | if ((packetType == SX126X_LORA_MODEM) && (bw == 500000)) value &= 0xFB; 382 | else value |= 0x04; 383 | sx126x_writeRegister(SX126X_REG_TX_MODULATION, &value, 1); 384 | } 385 | 386 | void sx126x_fixResistanceAntenna() 387 | { 388 | uint8_t value; 389 | sx126x_readRegister(SX126X_REG_TX_CLAMP_CONFIG, &value, 1); 390 | value |= 0x1E; 391 | sx126x_writeRegister(SX126X_REG_TX_CLAMP_CONFIG, &value, 1); 392 | } 393 | 394 | void sx126x_fixRxTimeout() 395 | { 396 | uint8_t value = 0x00; 397 | sx126x_writeRegister(SX126X_REG_RTC_CONTROL, &value, 1); 398 | sx126x_readRegister(SX126X_REG_EVENT_MASK, &value, 1); 399 | value = value | 0x02; 400 | sx126x_writeRegister(SX126X_REG_EVENT_MASK, &value, 1); 401 | } 402 | 403 | void sx126x_fixInvertedIq(uint8_t invertIq) 404 | { 405 | uint8_t value; 406 | sx126x_readRegister(SX126X_REG_IQ_POLARITY_SETUP, &value, 1); 407 | if (invertIq) value |= 0x04; 408 | else value &= 0xFB; 409 | sx126x_writeRegister(SX126X_REG_IQ_POLARITY_SETUP, &value, 1); 410 | } 411 | 412 | void sx126x_transfer(uint8_t opCode, uint8_t* data, uint8_t nData) 413 | { 414 | sx126x_transfer(opCode, data, nData, NULL, 0, true); 415 | } 416 | 417 | void sx126x_transfer(uint8_t opCode, uint8_t* data, uint8_t nData, uint8_t* address, uint8_t nAddress, bool read) 418 | { 419 | if (sx126x_busyCheck(SX126X_BUSY_TIMEOUT)) return; 420 | 421 | digitalWrite(sx126x_nss, LOW); 422 | sx126x_spi->beginTransaction(SPISettings(sx126x_spiFrequency, MSBFIRST, SPI_MODE0)); 423 | sx126x_spi->transfer(opCode); 424 | for (int8_t i=0; itransfer(address[i]); 425 | for (int8_t i=0; itransfer(data[i]); 427 | else sx126x_spi->transfer(data[i]); 428 | } 429 | sx126x_spi->endTransaction(); 430 | digitalWrite(sx126x_nss, HIGH); 431 | } 432 | -------------------------------------------------------------------------------- /src/SX126x_driver.h: -------------------------------------------------------------------------------- 1 | #ifndef _SX126X_DRIVER_H_ 2 | #define _SX126X_DRIVER_H_ 3 | 4 | #include 5 | #include 6 | 7 | // SX126X register map 8 | #define SX126X_REG_FSK_WHITENING_INITIAL_MSB 0x06B8 9 | #define SX126X_REG_FSK_CRC_INITIAL_MSB 0x06BC 10 | #define SX126X_REG_FSK_SYNC_WORD_0 0x06C0 11 | #define SX126X_REG_FSK_NODE_ADDRESS 0x06CD 12 | #define SX126X_REG_IQ_POLARITY_SETUP 0x0736 13 | #define SX126X_REG_LORA_SYNC_WORD_MSB 0x0740 14 | #define SX126X_REG_RANDOM_NUMBER_GEN 0x0819 15 | #define SX126X_REG_TX_MODULATION 0x0889 16 | #define SX126X_REG_RX_GAIN 0x08AC 17 | #define SX126X_REG_TX_CLAMP_CONFIG 0x08D8 18 | #define SX126X_REG_OCP_CONFIGURATION 0x08E7 19 | #define SX126X_REG_RTC_CONTROL 0x0902 20 | #define SX126X_REG_XTA_TRIM 0x0911 21 | #define SX126X_REG_XTB_TRIM 0x0912 22 | #define SX126X_REG_EVENT_MASK 0x0944 23 | 24 | // SetSleep 25 | #define SX126X_SLEEP_COLD_START 0x00 // sleep mode: cold start, configuration is lost (default) 26 | #define SX126X_SLEEP_WARM_START 0x04 // warm start, configuration is retained 27 | #define SX126X_SLEEP_COLD_START_RTC 0x01 // cold start and wake on RTC timeout 28 | #define SX126X_SLEEP_WARM_START_RTC 0x05 // warm start and wake on RTC timeout 29 | 30 | // SetStandby 31 | #define SX126X_STANDBY_RC 0x00 // standby mode: using 13 MHz RC oscillator 32 | #define SX126X_STANDBY_XOSC 0x01 // using 32 MHz crystal oscillator 33 | 34 | // SetTx 35 | #define SX126X_TX_SINGLE 0x000000 // Tx timeout duration: no timeout (Rx single mode) 36 | 37 | // SetRx 38 | #define SX126X_RX_SINGLE 0x000000 // Rx timeout duration: no timeout (Rx single mode) 39 | #define SX126X_RX_CONTINUOUS 0xFFFFFF // infinite (Rx continuous mode) 40 | 41 | // SetRegulatorMode 42 | #define SX126X_REGULATOR_LDO 0x00 // set regulator mode: LDO (default) 43 | #define SX126X_REGULATOR_DC_DC 0x01 // DC-DC 44 | 45 | // CalibrateImage 46 | #define SX126X_CAL_IMG_430 0x6B // ISM band: 430-440 Mhz Freq1 47 | #define SX126X_CAL_IMG_440 0x6F // 430-440 Mhz Freq2 48 | #define SX126X_CAL_IMG_470 0x75 // 470-510 Mhz Freq1 49 | #define SX126X_CAL_IMG_510 0x81 // 470-510 Mhz Freq2 50 | #define SX126X_CAL_IMG_779 0xC1 // 779-787 Mhz Freq1 51 | #define SX126X_CAL_IMG_787 0xC5 // 779-787 Mhz Freq2 52 | #define SX126X_CAL_IMG_863 0xD7 // 863-870 Mhz Freq1 53 | #define SX126X_CAL_IMG_870 0xDB // 863-870 Mhz Freq2 54 | #define SX126X_CAL_IMG_902 0xE1 // 902-928 Mhz Freq1 55 | #define SX126X_CAL_IMG_928 0xE9 // 902-928 Mhz Freq2 56 | 57 | // SetPaConfig 58 | #define SX126X_TX_POWER_SX1261 0x01 // device version for TX power: SX1261 59 | #define SX126X_TX_POWER_SX1262 0x02 // : SX1262 60 | #define SX126X_TX_POWER_SX1268 0x08 // : SX1268 61 | 62 | // SetRxTxFallbackMode 63 | #define SX126X_FALLBACK_FS 0x40 // after Rx/Tx go to: FS mode 64 | #define SX126X_FALLBACK_STDBY_XOSC 0x30 // standby mode with crystal oscillator 65 | #define SX126X_FALLBACK_STDBY_RC 0x20 // standby mode with RC oscillator (default) 66 | 67 | // SetDioIrqParams 68 | #define SX126X_IRQ_TX_DONE 0x0001 // packet transmission completed 69 | #define SX126X_IRQ_RX_DONE 0x0002 // packet received 70 | #define SX126X_IRQ_PREAMBLE_DETECTED 0x0004 // preamble detected 71 | #define SX126X_IRQ_SYNC_WORD_VALID 0x0008 // valid sync word detected 72 | #define SX126X_IRQ_HEADER_VALID 0x0010 // valid LoRa header received 73 | #define SX126X_IRQ_HEADER_ERR 0x0020 // LoRa header CRC error 74 | #define SX126X_IRQ_CRC_ERR 0x0040 // wrong CRC received 75 | #define SX126X_IRQ_CAD_DONE 0x0080 // channel activity detection finished 76 | #define SX126X_IRQ_CAD_DETECTED 0x0100 // channel activity detected 77 | #define SX126X_IRQ_TIMEOUT 0x0200 // Rx or Tx timeout 78 | #define SX126X_IRQ_ALL 0x03FF // all interrupts 79 | #define SX126X_IRQ_NONE 0x0000 // no interrupts 80 | 81 | // SetDio2AsRfSwitch 82 | #define SX126X_DIO2_AS_IRQ 0x00 // DIO2 configuration: IRQ 83 | #define SX126X_DIO2_AS_RF_SWITCH 0x01 // RF switch control 84 | 85 | // SetDio3AsTcxoCtrl 86 | #define SX126X_DIO3_OUTPUT_1_6 0x00 // DIO3 voltage output for TCXO: 1.6 V 87 | #define SX126X_DIO3_OUTPUT_1_7 0x01 // 1.7 V 88 | #define SX126X_DIO3_OUTPUT_1_8 0x02 // 1.8 V 89 | #define SX126X_DIO3_OUTPUT_2_2 0x03 // 2.2 V 90 | #define SX126X_DIO3_OUTPUT_2_4 0x04 // 2.4 V 91 | #define SX126X_DIO3_OUTPUT_2_7 0x05 // 2.7 V 92 | #define SX126X_DIO3_OUTPUT_3_0 0x06 // 3.0 V 93 | #define SX126X_DIO3_OUTPUT_3_3 0x07 // 3.3 V 94 | #define SX126X_TCXO_DELAY_1 0x0040 // TCXO delay time: 1 ms 95 | #define SX126X_TCXO_DELAY_2 0x0080 // 2 ms 96 | #define SX126X_TCXO_DELAY_5 0x0140 // 5 ms 97 | #define SX126X_TCXO_DELAY_10 0x0280 // 10 ms 98 | 99 | // SetRfFrequency 100 | #define SX126X_RF_FREQUENCY_XTAL 32000000 // XTAL frequency used for RF frequency calculation 101 | #define SX126X_RF_FREQUENCY_SHIFT 25 // RfFreq = Frequency * 2^25 / 32000000 102 | 103 | // SetPacketType 104 | #define SX126X_FSK_MODEM 0x00 // GFSK packet type 105 | #define SX126X_LORA_MODEM 0x01 // LoRa packet type 106 | 107 | // SetTxParams 108 | #define SX126X_PA_RAMP_10U 0x00 // ramp time: 10 us 109 | #define SX126X_PA_RAMP_20U 0x01 // 20 us 110 | #define SX126X_PA_RAMP_40U 0x02 // 40 us 111 | #define SX126X_PA_RAMP_80U 0x03 // 80 us 112 | #define SX126X_PA_RAMP_200U 0x04 // 200 us 113 | #define SX126X_PA_RAMP_800U 0x05 // 800 us 114 | #define SX126X_PA_RAMP_1700U 0x06 // 1700 us 115 | #define SX126X_PA_RAMP_3400U 0x07 // 3400 us 116 | 117 | // SetModulationParams for LoRa packet type 118 | #define SX126X_BW_7800 0x00 // LoRa bandwidth: 7.8 kHz 119 | #define SX126X_BW_10400 0x08 // 10.4 kHz 120 | #define SX126X_BW_15600 0x01 // 15.6 kHz 121 | #define SX126X_BW_20800 0x09 // 20.8 kHz 122 | #define SX126X_BW_31250 0x02 // 31.25 kHz 123 | #define SX126X_BW_41700 0x0A // 41.7 kHz 124 | #define SX126X_BW_62500 0x03 // 62.5 kHz 125 | #define SX126X_BW_125000 0x04 // 125 kHz 126 | #define SX126X_BW_250000 0x05 // 250 kHz 127 | #define SX126X_BW_500000 0x06 // 500 kHz 128 | #define SX126X_CR_4_4 0x00 // LoRa coding rate: 4/4 (no coding rate) 129 | #define SX126X_CR_4_5 0x01 // 4/5 130 | #define SX126X_CR_4_6 0x02 // 4/6 131 | #define SX126X_CR_4_7 0x03 // 4/7 132 | #define SX126X_CR_4_8 0x04 // 4/8 133 | #define SX126X_LDRO_OFF 0x00 // LoRa low data rate optimization: disabled 134 | #define SX126X_LDRO_ON 0x00 // enabled 135 | 136 | // SetModulationParams for FSK packet type 137 | #define SX126X_PULSE_NO_FILTER 0x00 // FSK pulse shape: no filter applied 138 | #define SX126X_PULSE_GAUSSIAN_BT_0_3 0x08 // Gaussian BT 0.3 139 | #define SX126X_PULSE_GAUSSIAN_BT_0_5 0x09 // Gaussian BT 0.5 140 | #define SX126X_PULSE_GAUSSIAN_BT_0_7 0x0A // Gaussian BT 0.7 141 | #define SX126X_PULSE_GAUSSIAN_BT_1 0x0B // Gaussian BT 1 142 | #define SX126X_BW_4800 0x1F // FSK bandwidth: 4.8 kHz DSB 143 | #define SX126X_BW_5800 0x17 // 5.8 kHz DSB 144 | #define SX126X_BW_7300 0x0F // 7.3 kHz DSB 145 | #define SX126X_BW_9700 0x1E // 9.7 kHz DSB 146 | #define SX126X_BW_11700 0x16 // 11.7 kHz DSB 147 | #define SX126X_BW_14600 0x0E // 14.6 kHz DSB 148 | #define SX126X_BW_19500 0x1D // 19.5 kHz DSB 149 | #define SX126X_BW_23400 0x15 // 23.4 kHz DSB 150 | #define SX126X_BW_29300 0x0D // 29.3 kHz DSB 151 | #define SX126X_BW_39000 0x1C // 39 kHz DSB 152 | #define SX126X_BW_46900 0x14 // 46.9 kHz DSB 153 | #define SX126X_BW_58600 0x0C // 58.6 kHz DSB 154 | #define SX126X_BW_78200 0x1B // 78.2 kHz DSB 155 | #define SX126X_BW_93800 0x13 // 93.8 kHz DSB 156 | #define SX126X_BW_117300 0x0B // 117.3 kHz DSB 157 | #define SX126X_BW_156200 0x1A // 156.2 kHz DSB 158 | #define SX126X_BW_187200 0x12 // 187.2 kHz DSB 159 | #define SX126X_BW_234300 0x0A // 232.3 kHz DSB 160 | #define SX126X_BW_312000 0x19 // 312 kHz DSB 161 | #define SX126X_BW_373600 0x11 // 373.6 kHz DSB 162 | #define SX126X_BW_467000 0x09 // 476 kHz DSB 163 | 164 | // SetPacketParams for LoRa packet type 165 | #define SX126X_HEADER_EXPLICIT 0x00 // LoRa header mode: explicit 166 | #define SX126X_HEADER_IMPLICIT 0x01 // implicit 167 | #define SX126X_CRC_OFF 0x00 // LoRa CRC mode: disabled 168 | #define SX126X_CRC_ON 0x01 // enabled 169 | #define SX126X_IQ_STANDARD 0x00 // LoRa IQ setup: standard 170 | #define SX126X_IQ_INVERTED 0x01 // inverted 171 | 172 | // SetPacketParams for FSK packet type 173 | #define SX126X_PREAMBLE_DET_LEN_OFF 0x00 // FSK preamble detector length: off 174 | #define SX126X_PREAMBLE_DET_LEN_8 0x04 // 8-bit 175 | #define SX126X_PREAMBLE_DET_LEN_16 0x05 // 16-bit 176 | #define SX126X_PREAMBLE_DET_LEN_24 0x06 // 24-bit 177 | #define SX126X_PREAMBLE_DET_LEN_32 0x07 // 32-bit 178 | #define SX126X_ADDR_COMP_OFF 0x00 // FSK address filtering: off 179 | #define SX126X_ADDR_COMP_NODE 0x01 // filtering on node address 180 | #define SX126X_ADDR_COMP_ALL 0x02 // filtering on node and broadcast address 181 | #define SX126X_PACKET_KNOWN 0x00 // FSK packet type: the packet length known on both side 182 | #define SX126X_PACKET_VARIABLE 0x01 // the packet length on variable size 183 | #define SX126X_CRC_0 0x01 // FSK CRC type: no CRC 184 | #define SX126X_CRC_1 0x00 // CRC computed on 1 byte 185 | #define SX126X_CRC_2 0x02 // CRC computed on 2 byte 186 | #define SX126X_CRC_1_INV 0x04 // CRC computed on 1 byte and inverted 187 | #define SX126X_CRC_2_INV 0x06 // CRC computed on 2 byte and inverted 188 | #define SX126X_WHITENING_OFF 0x00 // FSK whitening: no encoding 189 | #define SX126X_WHITENING_ON 0x01 // whitening enable 190 | 191 | // SetCadParams 192 | #define SX126X_CAD_ON_1_SYMB 0x00 // number of symbols used for CAD: 1 193 | #define SX126X_CAD_ON_2_SYMB 0x01 // 2 194 | #define SX126X_CAD_ON_4_SYMB 0x02 // 4 195 | #define SX126X_CAD_ON_8_SYMB 0x03 // 8 196 | #define SX126X_CAD_ON_16_SYMB 0x04 // 16 197 | #define SX126X_CAD_EXIT_STDBY 0x00 // after CAD is done, always exit to STDBY_RC mode 198 | #define SX126X_CAD_EXIT_RX 0x01 // after CAD is done, exit to Rx mode if activity is detected 199 | 200 | // GetStatus 201 | #define SX126X_STATUS_DATA_AVAILABLE 0x04 // command status: packet received and data can be retrieved 202 | #define SX126X_STATUS_CMD_TIMEOUT 0x06 // SPI command timed out 203 | #define SX126X_STATUS_CMD_ERROR 0x08 // invalid SPI command 204 | #define SX126X_STATUS_CMD_FAILED 0x0A // SPI command failed to execute 205 | #define SX126X_STATUS_CMD_TX_DONE 0x0C // packet transmission done 206 | #define SX126X_STATUS_MODE_STDBY_RC 0x20 // current chip mode: STDBY_RC 207 | #define SX126X_STATUS_MODE_STDBY_XOSC 0x30 // STDBY_XOSC 208 | #define SX126X_STATUS_MODE_FS 0x40 // FS 209 | #define SX126X_STATUS_MODE_RX 0x50 // RX 210 | #define SX126X_STATUS_MODE_TX 0x60 // TX 211 | 212 | // GetDeviceErrors 213 | #define SX126X_RC64K_CALIB_ERR 0x0001 // device errors: RC64K calibration failed 214 | #define SX126X_RC13M_CALIB_ERR 0x0002 // RC13M calibration failed 215 | #define SX126X_PLL_CALIB_ERR 0x0004 // PLL calibration failed 216 | #define SX126X_ADC_CALIB_ERR 0x0008 // ADC calibration failed 217 | #define SX126X_IMG_CALIB_ERR 0x0010 // image calibration failed 218 | #define SX126X_XOSC_START_ERR 0x0020 // crystal oscillator failed to start 219 | #define SX126X_PLL_LOCK_ERR 0x0040 // PLL failed to lock 220 | #define SX126X_PA_RAMP_ERR 0x0100 // PA ramping failed 221 | 222 | // LoraSyncWord 223 | #define SX126X_LORA_SYNC_WORD_PUBLIC 0x3444 // LoRa SyncWord for public network 224 | #define SX126X_LORA_SYNC_WORD_PRIVATE 0x0741 // LoRa SyncWord for private network (default) 225 | 226 | // RxGain 227 | #define SX126X_RX_GAIN_POWER_SAVING 0x00 // gain used in Rx mode: power saving gain (default) 228 | #define SX126X_RX_GAIN_BOOSTED 0x01 // boosted gain 229 | #define SX126X_POWER_SAVING_GAIN 0x94 // power saving gain register value 230 | #define SX126X_BOOSTED_GAIN 0x96 // boosted gain register value 231 | 232 | // Default Hardware Configuration 233 | #define SX126X_PIN_NSS 10 234 | #define SX126X_PIN_RESET 4 235 | #define SX126X_PIN_BUSY 5 236 | #define SX126X_SPI SPI 237 | #ifdef __AVR__ 238 | #define SX126X_SPI_FREQUENCY F_CPU / 2 // SPI speed set to half of CPU frequency for AVR processor 239 | #else 240 | #define SX126X_SPI_FREQUENCY 16000000 // Maximum LoRa SPI frequency 241 | #endif 242 | #define SX126X_BUSY_TIMEOUT 5000 // Default timeout for checking busy pin 243 | 244 | void sx126x_setSPI(SPIClass &SpiObject, uint32_t frequency); 245 | void sx126x_setPins(int8_t nss, int8_t busy); 246 | void sx126x_reset(int8_t reset); 247 | void sx126x_begin(); 248 | bool sx126x_busyCheck(uint32_t timeout=SX126X_BUSY_TIMEOUT); 249 | 250 | // SX126x driver: Operational Modes Commands 251 | void sx126x_setSleep(uint8_t sleepConfig); 252 | void sx126x_setStandby(uint8_t standbyMode); 253 | void sx126x_setFs(); 254 | void sx126x_setTx(uint32_t timeout); 255 | void sx126x_setRx(uint32_t timeout); 256 | void sx126x_stopTimerOnPreamble(uint8_t enable); 257 | void sx126x_setRxDutyCycle(uint32_t rxPeriod, uint32_t sleepPeriod); 258 | void sx126x_setCad(); 259 | void sx126x_setTxContinuousWave(); 260 | void sx126x_setTxInfinitePreamble(); 261 | void sx126x_setRegulatorMode(uint8_t modeParam); 262 | void sx126x_calibrate(uint8_t calibParam); 263 | void sx126x_calibrateImage(uint8_t freq1, uint8_t freq2); 264 | void sx126x_setPaConfig(uint8_t paDutyCycle, uint8_t hpMax, uint8_t deviceSel, uint8_t paLut); 265 | void sx126x_setRxTxFallbackMode(uint8_t fallbackMode); 266 | 267 | // SX126x driver: Register and Buffer Access Commands 268 | void sx126x_writeRegister(uint16_t address, uint8_t* data, uint8_t nData); 269 | void sx126x_readRegister(uint16_t address, uint8_t* data, uint8_t nData); 270 | void sx126x_writeBuffer(uint8_t offset, uint8_t* data, uint8_t nData); 271 | void sx126x_readBuffer(uint8_t offset, uint8_t* data, uint8_t nData); 272 | 273 | // SX126x driver: DIO and IRQ Control 274 | void sx126x_setDioIrqParams(uint16_t irqMask, uint16_t dio1Mask, uint16_t dio2Mask, uint16_t dio3Mask); 275 | void sx126x_getIrqStatus(uint16_t* irqStatus); 276 | void sx126x_clearIrqStatus(uint16_t clearIrqParam); 277 | void sx126x_setDio2AsRfSwitchCtrl(uint8_t enable); 278 | void sx126x_setDio3AsTcxoCtrl(uint8_t tcxoVoltage, uint32_t delay); 279 | 280 | // SX126x driver: RF, Modulation and Packet Commands 281 | void sx126x_setRfFrequency(uint32_t rfFrequency); 282 | void sx126x_setPacketType(uint8_t packetType); 283 | void sx126x_getPacketType(uint8_t* packetType); 284 | void sx126x_setTxParams(uint8_t power, uint8_t rampTime); 285 | void sx126x_setModulationParamsLoRa(uint8_t sf, uint8_t bw, uint8_t cr, uint8_t ldro); 286 | void sx126x_setModulationParamsFSK(uint32_t br, uint8_t pulseShape, uint8_t bandwidth, uint32_t Fdev); 287 | void sx126x_setPacketParamsLoRa(uint16_t preambleLength, uint8_t headerType, uint8_t payloadLength, uint8_t crcType, uint8_t invertIq); 288 | void sx126x_setPacketParamsFSK(uint16_t preambleLength, uint8_t preambleDetector, uint8_t syncWordLength, uint8_t addrComp, uint8_t packetType, uint8_t payloadLength, uint8_t crcType, uint8_t whitening); 289 | void sx126x_setCadParams(uint8_t cadSymbolNum, uint8_t cadDetPeak, uint8_t cadDetMin, uint8_t cadExitMode, uint32_t cadTimeout); 290 | void sx126x_setBufferBaseAddress(uint8_t txBaseAddress, uint8_t rxBaseAddress); 291 | void sx126x_setLoRaSymbNumTimeout(uint8_t symbnum); 292 | 293 | // SX126x driver: Status Commands 294 | void sx126x_getStatus(uint8_t* status); 295 | void sx126x_getRxBufferStatus(uint8_t* payloadLengthRx, uint8_t* rxStartBufferPointer); 296 | void sx126x_getPacketStatus(uint8_t* rssiPkt, uint8_t* snrPkt, uint8_t* signalRssiPkt); 297 | void sx126x_getRssiInst(uint8_t* rssiInst); 298 | void sx126x_getStats(uint16_t* nbPktReceived, uint16_t* nbPktCrcError, uint16_t* nbPktHeaderErr); 299 | void sx126x_resetStats(); 300 | void sx126x_getDeviceErrors(uint16_t* opError); 301 | void sx126x_clearDeviceErrors(); 302 | 303 | // SX126x driver: Workaround functions 304 | void sx126x_fixLoRaBw500(uint32_t bw); 305 | void sx126x_fixResistanceAntenna(); 306 | void sx126x_fixRxTimeout(); 307 | void sx126x_fixInvertedIq(uint8_t invertIq); 308 | 309 | // Utilities 310 | void sx126x_transfer(uint8_t opCode, uint8_t* data, uint8_t nData); 311 | void sx126x_transfer(uint8_t opCode, uint8_t* data, uint8_t nData, uint8_t* address, uint8_t nAddress, bool read); 312 | 313 | #endif -------------------------------------------------------------------------------- /src/SX127x.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void (*SX127x::_onTransmit)(); 4 | 5 | void (*SX127x::_onReceive)(); 6 | 7 | volatile uint8_t SX127x::_statusIrq = 0xFF; 8 | 9 | uint32_t SX127x::_transmitTime = 0; 10 | 11 | uint8_t SX127x::_payloadTxRx = 0; 12 | 13 | int8_t SX127x::_irqStatic = -1; 14 | 15 | int8_t SX127x::_pinToLow = -1; 16 | 17 | SX127x::SX127x() 18 | { 19 | _spi = &SX127X_SPI; 20 | setPins(SX127X_PIN_NSS, SX127X_PIN_RESET); 21 | } 22 | 23 | bool SX127x::begin() 24 | { 25 | // set pins as input or output 26 | if (_irq != -1) pinMode(_irq, INPUT); 27 | if (_txen != -1) pinMode(_txen, OUTPUT); 28 | if (_rxen != -1) pinMode(_rxen, OUTPUT); 29 | 30 | // begin spi and perform device reset 31 | sx127x_begin(); 32 | if (!SX127x::reset()) return false; 33 | 34 | // set modem to LoRa 35 | setModem(SX127X_LORA_MODEM); 36 | // set tx power and rx gain 37 | setTxPower(17, SX127X_TX_POWER_PA_BOOST); 38 | setRxGain(SX127X_RX_GAIN_BOOSTED, SX127X_RX_GAIN_AUTO); 39 | return true; 40 | } 41 | 42 | bool SX127x::begin(int8_t nss, int8_t reset, int8_t irq, int8_t txen, int8_t rxen) 43 | { 44 | setPins(nss, reset, irq, txen, rxen); 45 | return begin(); 46 | } 47 | 48 | void SX127x::end() 49 | { 50 | sleep(); 51 | _spi->end(); 52 | } 53 | 54 | bool SX127x::reset() 55 | { 56 | sx127x_reset(_reset); 57 | // wait until device connected, return false when device too long to respond 58 | uint32_t t = millis(); 59 | uint8_t version = 0x00; 60 | while (version != 0x12 && version != 0x22) { 61 | version = sx127x_readRegister(SX127X_REG_VERSION); 62 | if (millis() - t > 1000) return false; 63 | } 64 | return true; 65 | } 66 | 67 | void SX127x::sleep() 68 | { 69 | // put device in sleep mode 70 | sx127x_writeRegister(SX127X_REG_OP_MODE, _modem | SX127X_MODE_SLEEP); 71 | } 72 | 73 | void SX127x::wake() 74 | { 75 | // wake device by put in standby mode 76 | sx127x_writeRegister(SX127X_REG_OP_MODE, _modem | SX127X_MODE_STDBY); 77 | } 78 | 79 | void SX127x::standby() 80 | { 81 | sx127x_writeRegister(SX127X_REG_OP_MODE, _modem | SX127X_MODE_STDBY); 82 | } 83 | 84 | void SX127x::setActive() 85 | { 86 | // override spi, nss, and busy static property in SX127x driver with object property 87 | sx127x_setSPI(*_spi, 0); 88 | sx127x_setPins(_nss); 89 | } 90 | 91 | void SX127x::setSPI(SPIClass &SpiObject, uint32_t frequency) 92 | { 93 | sx127x_setSPI(SpiObject, frequency); 94 | 95 | _spi = &SpiObject; 96 | } 97 | 98 | void SX127x::setPins(int8_t nss, int8_t reset, int8_t irq, int8_t txen, int8_t rxen) 99 | { 100 | sx127x_setPins(nss); 101 | 102 | _nss = nss; 103 | _reset = reset; 104 | _irq = irq; 105 | _txen = txen; 106 | _rxen = rxen; 107 | _irqStatic = digitalPinToInterrupt(_irq); 108 | } 109 | 110 | void SX127x::setCurrentProtection(uint8_t current) 111 | { 112 | // calculate ocp trim 113 | uint8_t ocpTrim = 27; 114 | if (current <= 120) { 115 | ocpTrim = (current - 45) / 5; 116 | } else if (current <=240) { 117 | ocpTrim = (current + 30) / 10; 118 | } 119 | // set over current protection config 120 | sx127x_writeRegister(SX127X_REG_OCP, 0x20 | ocpTrim); 121 | } 122 | 123 | void SX127x::setOscillator(uint8_t option) 124 | { 125 | uint8_t cfg = option == SX127X_OSC_TCXO ? SX127X_OSC_TCXO : SX127X_OSC_CRYSTAL; 126 | sx127x_writeRegister(SX127X_REG_TCXO, cfg); 127 | } 128 | 129 | uint8_t SX127x::getModem() 130 | { 131 | uint8_t modem = sx127x_readRegister(SX127X_REG_OP_MODE); 132 | if (modem & 0x20) { 133 | return SX127X_OOK_MODEM; 134 | } 135 | return modem >> 7; 136 | } 137 | 138 | void SX127x::setModem(uint8_t modem) 139 | { 140 | if (modem == SX127X_LORA_MODEM) _modem = SX127X_LONG_RANGE_MODE; 141 | else if (modem == SX127X_FSK_MODEM) _modem = SX127X_MODULATION_FSK; 142 | else _modem = SX127X_MODULATION_OOK; 143 | sleep(); 144 | sx127x_writeRegister(SX127X_REG_OP_MODE, _modem); 145 | standby(); 146 | } 147 | 148 | void SX127x::setFrequency(uint32_t frequency) 149 | { 150 | _frequency = frequency; 151 | // calculate frequency 152 | uint64_t frf = ((uint64_t) frequency << 19) / 32000000; 153 | sx127x_writeRegister(SX127X_REG_FRF_MSB, (uint8_t) (frf >> 16)); 154 | sx127x_writeRegister(SX127X_REG_FRF_MID, (uint8_t) (frf >> 8)); 155 | sx127x_writeRegister(SX127X_REG_FRF_LSB, (uint8_t) frf); 156 | } 157 | 158 | void SX127x::setTxPower(uint8_t txPower, uint8_t paPin) 159 | { 160 | // maximum TX power is 20 dBm and 14 dBm for RFO pin 161 | if (txPower > 20) txPower = 20; 162 | else if (txPower > 14 && paPin == SX127X_TX_POWER_RFO) txPower = 14; 163 | 164 | uint8_t paConfig, outputPower; 165 | if (paPin == SX127X_TX_POWER_RFO) { 166 | // txPower = Pmax - (15 - outputPower) 167 | if (txPower == 14) { 168 | // max power (Pmax) 14.4 dBm 169 | paConfig = 0x60; 170 | outputPower = txPower + 1; 171 | } else { 172 | // max power (Pmax) 13.2 dBm 173 | paConfig = 0x40; 174 | outputPower = txPower + 2; 175 | } 176 | } else { 177 | paConfig = 0xC0; 178 | uint8_t paDac = 0x04; 179 | // txPower = 17 - (15 - outputPower) 180 | if (txPower > 17) { 181 | outputPower = 15; 182 | paDac = 0x07; 183 | setCurrentProtection(100); // max current 100 mA 184 | } else { 185 | if (txPower < 2) txPower = 2; 186 | outputPower = txPower - 2; 187 | setCurrentProtection(140); // max current 140 mA 188 | } 189 | // enable or disable +20 dBm option on PA_BOOST pin 190 | sx127x_writeRegister(SX127X_REG_PA_DAC, paDac); 191 | } 192 | // set PA config 193 | sx127x_writeRegister(SX127X_REG_PA_CONFIG, paConfig | outputPower); 194 | } 195 | 196 | void SX127x::setRxGain(uint8_t boost, uint8_t level) 197 | { 198 | // valid RX gain level 0 - 6 (0 -> AGC on) 199 | if (level > 6) level = 6; 200 | // boost LNA and automatic gain controller config 201 | uint8_t LnaBoostHf = boost ? 0x03 : 0x00; 202 | uint8_t AgcOn = level == SX127X_RX_GAIN_AUTO ? 0x01 : 0x00; 203 | // set gain and boost LNA config 204 | sx127x_writeRegister(SX127X_REG_LNA, LnaBoostHf | (level << 5)); 205 | // enable or disable AGC 206 | sx127x_writeBits(SX127X_REG_MODEM_CONFIG_3, AgcOn, 2, 1); 207 | } 208 | 209 | void SX127x::setLoRaModulation(uint8_t sf, uint32_t bw, uint8_t cr, bool ldro) 210 | { 211 | setSpreadingFactor(sf); 212 | setBandwidth(bw); 213 | setCodeRate(cr); 214 | setLdroEnable(ldro); 215 | } 216 | 217 | void SX127x::setLoRaPacket(uint8_t headerType, uint16_t preambleLength, uint8_t payloadLength, bool crcType, bool invertIq) 218 | { 219 | setHeaderType(headerType); 220 | setPreambleLength(preambleLength); 221 | setPayloadLength(payloadLength); 222 | setCrcEnable(crcType); 223 | // setInvertIq(invertIq); 224 | } 225 | 226 | void SX127x::setSpreadingFactor(uint8_t sf) 227 | { 228 | _sf = sf; 229 | // valid spreading factor is 6 - 12 230 | if (sf < 6) sf = 6; 231 | else if (sf > 12) sf = 12; 232 | // set appropriate signal detection optimize and threshold 233 | uint8_t optimize = sf == 6 ? 0x05 : 0x03; 234 | uint8_t threshold = sf == 6 ? 0x0C : 0x0A; 235 | sx127x_writeRegister(SX127X_REG_DETECTION_OPTIMIZE, optimize); 236 | sx127x_writeRegister(SX127X_REG_DETECTION_THRESHOLD, threshold); 237 | // set spreading factor config 238 | sx127x_writeBits(SX127X_REG_MODEM_CONFIG_2, sf, 4, 4); 239 | } 240 | 241 | void SX127x::setBandwidth(uint32_t bw) 242 | { 243 | _bw = bw; 244 | uint8_t bwCfg; 245 | if (bw < 9100) bwCfg = 0; // 7.8 kHz 246 | else if (bw < 13000) bwCfg = 1; // 10.4 kHz 247 | else if (bw < 18200) bwCfg = 2; // 15.6 kHz 248 | else if (bw < 26000) bwCfg = 3; // 20.8 kHz 249 | else if (bw < 36500) bwCfg = 4; // 31.25 kHz 250 | else if (bw < 52100) bwCfg = 5; // 41.7 kHz 251 | else if (bw < 93800) bwCfg = 6; // 62.5 kHz 252 | else if (bw < 187500) bwCfg = 7; // 125 kHz 253 | else if (bw < 375000) bwCfg = 8; // 250 kHz 254 | else bwCfg = 9; // 500 kHz 255 | sx127x_writeBits(SX127X_REG_MODEM_CONFIG_1, bwCfg, 4, 4); 256 | } 257 | 258 | void SX127x::setCodeRate(uint8_t cr) 259 | { 260 | // valid code rate denominator is 5 - 8 261 | if (cr < 5) cr = 4; 262 | else if (cr > 8) cr = 8; 263 | uint8_t crCfg = cr - 4; 264 | sx127x_writeBits(SX127X_REG_MODEM_CONFIG_1, crCfg, 1, 3); 265 | } 266 | 267 | void SX127x::setLdroEnable(bool ldro) 268 | { 269 | uint8_t ldroCfg = ldro ? 0x01 : 0x00; 270 | sx127x_writeBits(SX127X_REG_MODEM_CONFIG_3, ldroCfg, 3, 1); 271 | } 272 | 273 | void SX127x::setHeaderType(uint8_t headerType) 274 | { 275 | _headerType = headerType; 276 | uint8_t headerTypeCfg = headerType == SX127X_HEADER_IMPLICIT ? SX127X_HEADER_IMPLICIT : SX127X_HEADER_EXPLICIT; 277 | sx127x_writeBits(SX127X_REG_MODEM_CONFIG_1, headerTypeCfg, 0, 1); 278 | } 279 | 280 | void SX127x::setPreambleLength(uint16_t preambleLength) 281 | { 282 | sx127x_writeRegister(SX127X_REG_PREAMBLE_MSB, (uint8_t) (preambleLength >> 8)); 283 | sx127x_writeRegister(SX127X_REG_PREAMBLE_LSB, (uint8_t) preambleLength); 284 | } 285 | 286 | void SX127x::setPayloadLength(uint8_t payloadLength) 287 | { 288 | _payloadLength = payloadLength; 289 | sx127x_writeRegister(SX127X_REG_PAYLOAD_LENGTH, payloadLength); 290 | } 291 | 292 | void SX127x::setCrcEnable(bool crcType) 293 | { 294 | uint8_t crcTypeCfg = crcType ? 0x01 : 0x00; 295 | sx127x_writeBits(SX127X_REG_MODEM_CONFIG_2, crcTypeCfg, 2, 1); 296 | } 297 | 298 | void SX127x::setInvertIq(bool invertIq) 299 | { 300 | uint8_t invertIqCfg1 = invertIq ? 0x01 : 0x00; 301 | uint8_t invertIqCfg2 = invertIq ? 0x19 : 0x1D; 302 | sx127x_writeBits(SX127X_REG_INVERTIQ, invertIqCfg1, 0, 1); 303 | sx127x_writeBits(SX127X_REG_INVERTIQ, invertIqCfg1, 6, 1); 304 | sx127x_writeRegister(SX127X_REG_INVERTIQ2, invertIqCfg2); 305 | } 306 | 307 | void SX127x::setSyncWord(uint16_t syncWord) 308 | { 309 | uint8_t sw = syncWord; 310 | // keep compatibility between 1 and 2 bytes synchronize word 311 | if (syncWord > 0xFF) { 312 | sw = ((syncWord >> 8) & 0xF0) | (syncWord & 0x0F); 313 | } 314 | sx127x_writeRegister(SX127X_REG_SYNC_WORD, sw); 315 | } 316 | 317 | void SX127x::beginPacket() 318 | { 319 | // reset TX buffer base address, FIFO address pointer and payload length 320 | sx127x_writeRegister(SX127X_REG_FIFO_TX_BASE_ADDR, sx127x_readRegister(SX127X_REG_FIFO_ADDR_PTR)); 321 | _payloadTxRx = 0; 322 | 323 | // set txen pin to high and rxen pin to low 324 | if ((_rxen != -1) && (_txen != -1)){ 325 | digitalWrite(_rxen, LOW); 326 | digitalWrite(_txen, HIGH); 327 | _pinToLow = _txen; 328 | } 329 | } 330 | 331 | bool SX127x::endPacket(uint32_t timeout) 332 | { 333 | // skip to enter TX mode when previous TX operation incomplete 334 | if (sx127x_readRegister(SX127X_REG_OP_MODE) & 0x07 == SX127X_MODE_TX) return false; 335 | 336 | // clear IRQ flag from last TX or RX operation 337 | sx127x_writeRegister(SX127X_REG_IRQ_FLAGS, 0xFF); 338 | 339 | // set packet payload length 340 | sx127x_writeRegister(SX127X_REG_PAYLOAD_LENGTH, _payloadTxRx); 341 | 342 | // set status to TX wait 343 | _statusWait = SX127X_STATUS_TX_WAIT; 344 | _statusIrq = 0x00; 345 | 346 | // set device to transmit mode 347 | sx127x_writeRegister(SX127X_REG_OP_MODE, _modem | SX127X_MODE_TX); 348 | _transmitTime = millis(); 349 | 350 | // set TX done interrupt on DIO0 and attach TX interrupt handler 351 | if (_irq != -1) { 352 | sx127x_writeRegister(SX127X_REG_DIO_MAPPING_1, SX127X_DIO0_TX_DONE); 353 | attachInterrupt(_irqStatic, SX127x::_interruptTx, RISING); 354 | } 355 | return true; 356 | } 357 | 358 | void SX127x::write(uint8_t data) 359 | { 360 | // write single byte of package to be transmitted 361 | write(&data, 1); 362 | } 363 | 364 | void SX127x::write(uint8_t* data, uint8_t length) 365 | { 366 | // write multiple bytes of package to be transmitted in FIFO buffer 367 | for (uint8_t i = 0; i < length; i++) { 368 | sx127x_writeRegister(SX127X_REG_FIFO, data[i]); 369 | } 370 | // increasing payload length 371 | _payloadTxRx += length; 372 | } 373 | 374 | void SX127x::write(char* data, uint8_t length) 375 | { 376 | // write multiple bytes of package to be transmitted for char type 377 | uint8_t* data_ = (uint8_t*) data; 378 | write(data_, length); 379 | } 380 | 381 | bool SX127x::request(uint32_t timeout) 382 | { 383 | // skip to enter RX mode when previous RX operation incomplete 384 | uint8_t rxMode = sx127x_readRegister(SX127X_REG_OP_MODE) & 0x07; 385 | if (rxMode == SX127X_MODE_RX_SINGLE || rxMode == SX127X_MODE_RX_CONTINUOUS) return false; 386 | 387 | // clear IRQ flag from last TX or RX operation 388 | sx127x_writeRegister(SX127X_REG_IRQ_FLAGS, 0xFF); 389 | 390 | // set txen pin to low and rxen pin to high 391 | if ((_rxen != -1) && (_txen != -1)){ 392 | digitalWrite(_rxen, HIGH); 393 | digitalWrite(_txen, LOW); 394 | _pinToLow = _rxen; 395 | } 396 | 397 | // set status to RX wait 398 | _statusWait = SX127X_STATUS_RX_WAIT; 399 | _statusIrq = 0x00; 400 | // select RX mode to RX continuous mode for RX single and continuos operation 401 | rxMode = SX127X_MODE_RX_CONTINUOUS; 402 | if (timeout == SX127X_RX_CONTINUOUS) { 403 | _statusWait = SX127X_STATUS_RX_CONTINUOUS; 404 | } else if (timeout > 0) { 405 | // Select RX mode to single mode for RX operation with timeout 406 | rxMode = SX127X_MODE_RX_SINGLE; 407 | // calculate and set symbol timeout 408 | uint16_t symbTimeout = (timeout * _bw / 1000) >> _sf; // devided by 1000, ms to s 409 | symbTimeout = symbTimeout < 0x03FF ? symbTimeout : 0x03FF; 410 | sx127x_writeBits(SX127X_REG_MODEM_CONFIG_2, (symbTimeout >> 8) & 0x03, 0, 2); 411 | sx127x_writeRegister(SX127X_REG_SYMB_TIMEOUT, symbTimeout); 412 | } 413 | 414 | // set device to receive mode 415 | sx127x_writeRegister(SX127X_REG_OP_MODE, _modem | rxMode); 416 | 417 | // set RX done interrupt on DIO0 and attach RX interrupt handler 418 | if (_irq != -1) { 419 | sx127x_writeRegister(SX127X_REG_DIO_MAPPING_1, SX127X_DIO0_RX_DONE); 420 | if (timeout == SX127X_RX_CONTINUOUS) { 421 | attachInterrupt(_irqStatic, SX127x::_interruptRxContinuous, RISING); 422 | } else { 423 | attachInterrupt(_irqStatic, SX127x::_interruptRx, RISING); 424 | } 425 | } 426 | return true; 427 | } 428 | 429 | uint8_t SX127x::available() 430 | { 431 | // get size of package still available to read 432 | return _payloadTxRx; 433 | } 434 | 435 | uint8_t SX127x::read() 436 | { 437 | // read single byte of received package 438 | uint8_t data; 439 | read(&data, 1); 440 | return data; 441 | } 442 | 443 | uint8_t SX127x::read(uint8_t* data, uint8_t length) 444 | { 445 | // calculate actual read length and remaining payload length 446 | if (_payloadTxRx > length) { 447 | _payloadTxRx -= length; 448 | } 449 | else { 450 | length = _payloadTxRx; 451 | _payloadTxRx = 0; 452 | } 453 | // read multiple bytes of received package in FIFO buffer 454 | for (uint8_t i = 0; i < length; i++) { 455 | data[i] = sx127x_readRegister(SX127X_REG_FIFO); 456 | } 457 | return length; 458 | } 459 | 460 | uint8_t SX127x::read(char* data, uint8_t length) 461 | { 462 | // read multiple bytes of received package for char type 463 | uint8_t* data_ = (uint8_t*) data; 464 | return read(data_, length); 465 | } 466 | 467 | void SX127x::purge(uint8_t length) 468 | { 469 | // subtract or reset received payload length 470 | _payloadTxRx = (_payloadTxRx > length) && length ? _payloadTxRx - length : 0; 471 | } 472 | 473 | bool SX127x::wait(uint32_t timeout) 474 | { 475 | // immediately return when currently not waiting transmit or receive process 476 | if (_statusIrq) return true; 477 | 478 | // wait transmit or receive process finish by checking interrupt status or IRQ status 479 | uint8_t irqFlag = 0x00; 480 | uint8_t irqFlagMask = _statusWait == SX127X_STATUS_TX_WAIT 481 | ? SX127X_IRQ_TX_DONE 482 | : SX127X_IRQ_RX_DONE | SX127X_IRQ_RX_TIMEOUT | SX127X_IRQ_CRC_ERR 483 | ; 484 | uint32_t t = millis(); 485 | while (!(irqFlag & irqFlagMask) && _statusIrq == 0x00) { 486 | // only check IRQ status register for non interrupt operation 487 | if (_irq == -1) irqFlag = sx127x_readRegister(SX127X_REG_IRQ_FLAGS); 488 | // return when timeout reached 489 | if (millis() - t > timeout && timeout != 0) return false; 490 | yield(); 491 | } 492 | 493 | if (_statusIrq) { 494 | // immediately return when interrupt signal hit 495 | return true; 496 | 497 | } else if (_statusWait == SX127X_STATUS_TX_WAIT) { 498 | // calculate transmit time and set back txen pin to low 499 | _transmitTime = millis() - _transmitTime; 500 | if (_txen != -1) digitalWrite(_txen, LOW); 501 | 502 | } else if (_statusWait == SX127X_STATUS_RX_WAIT) { 503 | // terminate receive mode by setting mode to standby 504 | standby(); 505 | // set pointer to RX buffer base address and get packet payload length 506 | sx127x_writeRegister(SX127X_REG_FIFO_ADDR_PTR, sx127x_readRegister(SX127X_REG_FIFO_RX_CURRENT_ADDR)); 507 | _payloadTxRx = sx127x_readRegister(SX127X_REG_RX_NB_BYTES); 508 | // set back rxen pin to low 509 | if (_rxen != -1) digitalWrite(_rxen, LOW); 510 | 511 | } else if (_statusWait == SX127X_STATUS_RX_CONTINUOUS) { 512 | // set pointer to RX buffer base address and get packet payload length 513 | sx127x_writeRegister(SX127X_REG_FIFO_ADDR_PTR, sx127x_readRegister(SX127X_REG_FIFO_RX_CURRENT_ADDR)); 514 | _payloadTxRx = sx127x_readRegister(SX127X_REG_RX_NB_BYTES); 515 | // clear IRQ flag 516 | sx127x_writeRegister(SX127X_REG_IRQ_FLAGS, 0xFF); 517 | } 518 | 519 | // store IRQ status 520 | _statusIrq = irqFlag; 521 | return true; 522 | } 523 | 524 | uint8_t SX127x::status() 525 | { 526 | // set back status IRQ for RX continuous operation 527 | uint8_t statusIrq = _statusIrq; 528 | if (_statusWait == SX127X_STATUS_RX_CONTINUOUS) { 529 | _statusIrq = 0x00; 530 | } 531 | 532 | // get status for transmit and receive operation based on status IRQ 533 | if (statusIrq & SX127X_IRQ_RX_TIMEOUT) return SX127X_STATUS_RX_TIMEOUT; 534 | else if (statusIrq & SX127X_IRQ_CRC_ERR) return SX127X_STATUS_CRC_ERR; 535 | else if (statusIrq & SX127X_IRQ_TX_DONE) return SX127X_STATUS_TX_DONE; 536 | else if (statusIrq & SX127X_IRQ_RX_DONE) return SX127X_STATUS_RX_DONE; 537 | 538 | // return TX or RX wait status 539 | return _statusWait; 540 | } 541 | 542 | uint32_t SX127x::transmitTime() 543 | { 544 | // get transmit time in millisecond (ms) 545 | return _transmitTime; 546 | } 547 | 548 | float SX127x::dataRate() 549 | { 550 | // get data rate last transmitted package in kbps 551 | return 1000.0 * _payloadTxRx / _transmitTime; 552 | } 553 | 554 | int16_t SX127x::packetRssi() 555 | { 556 | // get relative signal strength index (RSSI) of last incoming package 557 | int16_t offset = _frequency < SX127X_BAND_THRESHOLD ? SX127X_RSSI_OFFSET_LF : SX127X_RSSI_OFFSET_HF; 558 | if (sx127x_readRegister(SX127X_REG_VERSION) == 0x22) { 559 | offset = SX1272_RSSI_OFFSET; 560 | } 561 | return (int16_t) sx127x_readRegister(SX127X_REG_PKT_RSSI_VALUE) - offset; 562 | } 563 | 564 | int16_t SX127x::rssi() 565 | { 566 | int16_t offset = _frequency < SX127X_BAND_THRESHOLD ? SX127X_RSSI_OFFSET_LF : SX127X_RSSI_OFFSET_HF; 567 | if (sx127x_readRegister(SX127X_REG_VERSION) == 0x22) { 568 | offset = SX1272_RSSI_OFFSET; 569 | } 570 | return (int16_t) sx127x_readRegister(SX127X_REG_RSSI_VALUE) - offset; 571 | } 572 | 573 | float SX127x::snr() 574 | { 575 | // get signal to noise ratio (SNR) of last incoming package 576 | return (int8_t) sx127x_readRegister(SX127X_REG_PKT_SNR_VALUE) / 4.0; 577 | } 578 | 579 | uint32_t SX127x::random() 580 | { 581 | // generate random number from register and previous random number 582 | uint32_t n = sx127x_readRegister(SX127X_REG_RSSI_WIDEBAND); 583 | uint32_t number = (n << 24) | ((~n & 0xFF) << 16) | (n << 8) | (~n & 0xFF); 584 | n = _random; 585 | number = number ^ ((~n << 16) | n); 586 | // combine random number with random number seeded by time 587 | srand(millis()); 588 | number = number ^ (((uint32_t) rand() << 16) | rand()); 589 | _random = number >> 8; 590 | return number; 591 | } 592 | 593 | void SX127x::_interruptTx() 594 | { 595 | // calculate transmit time 596 | _transmitTime = millis() - _transmitTime; 597 | 598 | // store IRQ status as TX done 599 | _statusIrq = SX127X_IRQ_TX_DONE; 600 | 601 | // set back txen pin to low and detach interrupt 602 | if (_pinToLow != -1) digitalWrite(_pinToLow, LOW); 603 | detachInterrupt(_irqStatic); 604 | 605 | // call onTransmit function 606 | if (_onTransmit) { 607 | _onTransmit(); 608 | } 609 | } 610 | 611 | void SX127x::_interruptRx() 612 | { 613 | // store IRQ status 614 | _statusIrq = sx127x_readRegister(SX127X_REG_IRQ_FLAGS); 615 | // set IRQ status to RX done when interrupt occured before register updated 616 | if (!(_statusIrq & 0xF0)) _statusIrq = SX127X_IRQ_RX_DONE; 617 | 618 | // terminate receive mode by setting mode to standby 619 | sx127x_writeBits(SX127X_REG_OP_MODE, SX127X_MODE_STDBY, 0, 3); 620 | 621 | // set back rxen pin to low and detach interrupt 622 | if (_pinToLow != -1) digitalWrite(_pinToLow, LOW); 623 | detachInterrupt(_irqStatic); 624 | 625 | // set pointer to RX buffer base address and get packet payload length 626 | sx127x_writeRegister(SX127X_REG_FIFO_ADDR_PTR, sx127x_readRegister(SX127X_REG_FIFO_RX_CURRENT_ADDR)); 627 | _payloadTxRx = sx127x_readRegister(SX127X_REG_RX_NB_BYTES); 628 | 629 | // call onReceive function 630 | if (_onReceive) { 631 | _onReceive(); 632 | } 633 | } 634 | 635 | void SX127x::_interruptRxContinuous() 636 | { 637 | // store IRQ status 638 | _statusIrq = sx127x_readRegister(SX127X_REG_IRQ_FLAGS); 639 | // set IRQ status to RX done when interrupt occured before register updated 640 | if (!(_statusIrq & 0xF0)) _statusIrq = SX127X_IRQ_RX_DONE; 641 | 642 | // clear IRQ flag from last TX or RX operation 643 | sx127x_writeRegister(SX127X_REG_IRQ_FLAGS, 0xFF); 644 | 645 | // set pointer to RX buffer base address and get packet payload length 646 | sx127x_writeRegister(SX127X_REG_FIFO_ADDR_PTR, sx127x_readRegister(SX127X_REG_FIFO_RX_CURRENT_ADDR)); 647 | _payloadTxRx = sx127x_readRegister(SX127X_REG_RX_NB_BYTES); 648 | 649 | // call onReceive function 650 | if (_onReceive) { 651 | _onReceive(); 652 | } 653 | } 654 | 655 | void SX127x::onTransmit(void(&callback)()) 656 | { 657 | // register onTransmit function to call every transmit done 658 | _onTransmit = &callback; 659 | } 660 | 661 | void SX127x::onReceive(void(&callback)()) 662 | { 663 | // register onReceive function to call every receive done 664 | _onReceive = &callback; 665 | } 666 | -------------------------------------------------------------------------------- /src/SX126x.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void (*SX126x::_onTransmit)(); 4 | 5 | void (*SX126x::_onReceive)(); 6 | 7 | volatile uint16_t SX126x::_statusIrq = 0xFFFF; 8 | 9 | uint32_t SX126x::_transmitTime = 0; 10 | 11 | uint8_t SX126x::_bufferIndex = 0; 12 | 13 | uint8_t SX126x::_payloadTxRx = 0; 14 | 15 | int8_t SX126x::_irqStatic = -1; 16 | 17 | int8_t SX126x::_pinToLow = -1; 18 | 19 | SX126x::SX126x() 20 | { 21 | _spi = &SX126X_SPI; 22 | _dio = SX126X_PIN_RF_IRQ; 23 | setPins(SX126X_PIN_NSS, SX126X_PIN_RESET, SX126X_PIN_BUSY); 24 | } 25 | 26 | bool SX126x::begin() 27 | { 28 | // set pins as input or output 29 | if (_irq != -1) pinMode(_irq, INPUT); 30 | if (_txen != -1) pinMode(_txen, OUTPUT); 31 | if (_rxen != -1) pinMode(_rxen, OUTPUT); 32 | 33 | // begin spi and perform device reset 34 | sx126x_begin(); 35 | sx126x_reset(_reset); 36 | 37 | // check if device connect and set modem to LoRa 38 | sx126x_setStandby(SX126X_STANDBY_RC); 39 | if (getMode() != SX126X_STATUS_MODE_STDBY_RC) return false; 40 | sx126x_setPacketType(SX126X_LORA_MODEM); 41 | 42 | sx126x_fixResistanceAntenna(); 43 | return true; 44 | } 45 | 46 | bool SX126x::begin(int8_t nss, int8_t reset, int8_t busy, int8_t irq, int8_t txen, int8_t rxen) 47 | { 48 | setPins(nss, reset, busy, irq, txen, rxen); 49 | return begin(); 50 | } 51 | 52 | void SX126x::end() 53 | { 54 | sleep(SX126X_SLEEP_COLD_START); 55 | _spi->end(); 56 | } 57 | 58 | bool SX126x::reset() 59 | { 60 | // put reset pin to low then wait busy pin to low 61 | sx126x_reset(_reset); 62 | return !sx126x_busyCheck(); 63 | } 64 | 65 | void SX126x::sleep(uint8_t option) 66 | { 67 | // put device in sleep mode, wait for 500 us to enter sleep mode 68 | standby(); 69 | sx126x_setSleep(option); 70 | delayMicroseconds(500); 71 | } 72 | 73 | void SX126x::wake() 74 | { 75 | // wake device by set nss to low and put device in standby mode 76 | digitalWrite(_nss, LOW); 77 | standby(); 78 | sx126x_fixResistanceAntenna(); 79 | } 80 | 81 | void SX126x::standby(uint8_t option) 82 | { 83 | sx126x_setStandby(option); 84 | } 85 | 86 | void SX126x::setActive() 87 | { 88 | // override spi, nss, and busy static property in SX126x driver with object property 89 | sx126x_setSPI(*_spi, 0); 90 | sx126x_setPins(_nss, _busy); 91 | } 92 | 93 | bool SX126x::busyCheck(uint32_t timeout) 94 | { 95 | return sx126x_busyCheck(timeout); 96 | } 97 | 98 | void SX126x::setFallbackMode(uint8_t fallbackMode) 99 | { 100 | sx126x_setRxTxFallbackMode(fallbackMode); 101 | } 102 | 103 | uint8_t SX126x::getMode() 104 | { 105 | uint8_t mode; 106 | sx126x_getStatus(&mode); 107 | return mode & 0x70; 108 | } 109 | 110 | void SX126x::setSPI(SPIClass &SpiObject, uint32_t frequency) 111 | { 112 | sx126x_setSPI(SpiObject, frequency); 113 | 114 | _spi = &SpiObject; 115 | } 116 | 117 | void SX126x::setPins(int8_t nss, int8_t reset, int8_t busy, int8_t irq, int8_t txen, int8_t rxen) 118 | { 119 | sx126x_setPins(nss, busy); 120 | 121 | _nss = nss; 122 | _reset = reset; 123 | _busy = busy; 124 | _irq = irq; 125 | _txen = txen; 126 | _rxen = rxen; 127 | _irqStatic = digitalPinToInterrupt(_irq); 128 | } 129 | 130 | void SX126x::setRfIrqPin(int8_t dioPinSelect) 131 | { 132 | if ((dioPinSelect == 2) || (dioPinSelect == 3)) _dio = dioPinSelect; 133 | else _dio = 1; 134 | } 135 | 136 | void SX126x::setDio2RfSwitch(bool enable) 137 | { 138 | if (enable) sx126x_setDio2AsRfSwitchCtrl(SX126X_DIO2_AS_RF_SWITCH); 139 | else sx126x_setDio2AsRfSwitchCtrl(SX126X_DIO2_AS_IRQ); 140 | } 141 | 142 | void SX126x::setDio3TcxoCtrl(uint8_t tcxoVoltage, uint32_t delayTime) 143 | { 144 | sx126x_setDio3AsTcxoCtrl(tcxoVoltage, delayTime); 145 | sx126x_setStandby(SX126X_STANDBY_RC); 146 | sx126x_calibrate(0xFF); 147 | } 148 | 149 | void SX126x::setXtalCap(uint8_t xtalA, uint8_t xtalB) 150 | { 151 | sx126x_setStandby(SX126X_STANDBY_XOSC); 152 | uint8_t buf[2] = {xtalA, xtalB}; 153 | sx126x_writeRegister(SX126X_REG_XTA_TRIM, buf, 2); 154 | sx126x_setStandby(SX126X_STANDBY_RC); 155 | sx126x_calibrate(0xFF); 156 | } 157 | 158 | void SX126x::setRegulator(uint8_t regMode) 159 | { 160 | sx126x_setRegulatorMode(regMode); 161 | } 162 | 163 | void SX126x::setCurrentProtection(uint8_t current) 164 | { 165 | uint8_t currentmA = current * 2 / 5; 166 | sx126x_writeRegister(SX126X_REG_OCP_CONFIGURATION, ¤tmA, 1); 167 | } 168 | 169 | uint8_t SX126x::getModem() 170 | { 171 | uint8_t modem; 172 | sx126x_getPacketType(&modem); 173 | return modem; 174 | } 175 | 176 | void SX126x::setModem(uint8_t modem) 177 | { 178 | _modem = modem; 179 | sx126x_setStandby(SX126X_STANDBY_RC); 180 | sx126x_setPacketType(modem); 181 | } 182 | 183 | void SX126x::setFrequency(uint32_t frequency) 184 | { 185 | uint8_t calFreq[2]; 186 | if (frequency < 446000000) { // 430 - 440 Mhz 187 | calFreq[0] = SX126X_CAL_IMG_430; 188 | calFreq[1] = SX126X_CAL_IMG_440; 189 | } 190 | else if (frequency < 734000000) { // 470 - 510 Mhz 191 | calFreq[0] = SX126X_CAL_IMG_470; 192 | calFreq[1] = SX126X_CAL_IMG_510; 193 | } 194 | else if (frequency < 828000000) { // 779 - 787 Mhz 195 | calFreq[0] = SX126X_CAL_IMG_779; 196 | calFreq[1] = SX126X_CAL_IMG_787; 197 | } 198 | else if (frequency < 877000000) { // 863 - 870 Mhz 199 | calFreq[0] = SX126X_CAL_IMG_863; 200 | calFreq[1] = SX126X_CAL_IMG_870; 201 | } 202 | else if (frequency < 1100000000) { // 902 - 928 Mhz 203 | calFreq[0] = SX126X_CAL_IMG_902; 204 | calFreq[1] = SX126X_CAL_IMG_928; 205 | } 206 | // calculate frequency for setting configuration 207 | uint32_t rfFreq = ((uint64_t) frequency << SX126X_RF_FREQUENCY_SHIFT) / SX126X_RF_FREQUENCY_XTAL; 208 | 209 | // perform image calibration before set frequency 210 | sx126x_calibrateImage(calFreq[0], calFreq[1]); 211 | sx126x_setRfFrequency(rfFreq); 212 | } 213 | 214 | void SX126x::setTxPower(uint8_t txPower, uint8_t version) 215 | { 216 | // maximum TX power is 22 dBm and 15 dBm for SX1261 217 | if (txPower > 22) txPower = 22; 218 | else if (txPower > 15 && version == SX126X_TX_POWER_SX1261) txPower = 15; 219 | 220 | uint8_t paDutyCycle = 0x00; 221 | uint8_t hpMax = 0x00; 222 | uint8_t deviceSel = version == SX126X_TX_POWER_SX1261 ? 0x01 : 0x00; 223 | uint8_t power = 0x0E; 224 | // set parameters for PA config and TX params configuration 225 | if (txPower == 22) { 226 | paDutyCycle = 0x04; 227 | hpMax = 0x07; 228 | power = 0x16; 229 | } else if (txPower >= 20) { 230 | paDutyCycle = 0x03; 231 | hpMax = 0x05; 232 | power = 0x16; 233 | } else if (txPower >= 17) { 234 | paDutyCycle = 0x02; 235 | hpMax = 0x03; 236 | power = 0x16; 237 | } else if (txPower >= 14 && version == SX126X_TX_POWER_SX1261) { 238 | paDutyCycle = 0x04; 239 | hpMax = 0x00; 240 | power = 0x0E; 241 | } else if (txPower >= 14 && version == SX126X_TX_POWER_SX1262) { 242 | paDutyCycle = 0x02; 243 | hpMax = 0x02; 244 | power = 0x16; 245 | } else if (txPower >= 14 && version == SX126X_TX_POWER_SX1268) { 246 | paDutyCycle = 0x04; 247 | hpMax = 0x06; 248 | power = 0x0F; 249 | } else if (txPower >= 10 && version == SX126X_TX_POWER_SX1261) { 250 | paDutyCycle = 0x01; 251 | hpMax = 0x00; 252 | power = 0x0D; 253 | } else if (txPower >= 10 && version == SX126X_TX_POWER_SX1268) { 254 | paDutyCycle = 0x00; 255 | hpMax = 0x03; 256 | power = 0x0F; 257 | } else { 258 | return; 259 | } 260 | 261 | // set power amplifier and TX power configuration 262 | sx126x_setPaConfig(paDutyCycle, hpMax, deviceSel, 0x01); 263 | sx126x_setTxParams(power, SX126X_PA_RAMP_800U); 264 | } 265 | 266 | void SX126x::setRxGain(uint8_t boost) 267 | { 268 | // set power saving or boosted gain in register 269 | uint8_t gain = boost ? SX126X_BOOSTED_GAIN : SX126X_POWER_SAVING_GAIN; 270 | sx126x_writeRegister(SX126X_REG_RX_GAIN, &gain, 1); 271 | if (boost){ 272 | // set certain register to retain configuration after wake from sleep mode 273 | uint8_t buf[3] = {0x01, 0x08, 0xAC}; 274 | sx126x_writeRegister(0x029F, buf, 3); 275 | } 276 | } 277 | 278 | void SX126x::setLoRaModulation(uint8_t sf, uint32_t bw, uint8_t cr, bool ldro) 279 | { 280 | _sf = sf; 281 | _bw = bw; 282 | _cr = cr; 283 | _ldro = ldro; 284 | 285 | // valid spreading factor is between 5 and 12 286 | if (sf > 12) sf = 12; 287 | else if (sf < 5) sf = 5; 288 | // select bandwidth options 289 | if (bw < 9100) bw = SX126X_BW_7800; // 7.8 kHz 290 | else if (bw < 13000) bw = SX126X_BW_10400; // 10.4 kHz 291 | else if (bw < 18200) bw = SX126X_BW_15600; // 15.6 kHz 292 | else if (bw < 26000) bw = SX126X_BW_20800; // 20.8 kHz 293 | else if (bw < 36500) bw = SX126X_BW_31250; // 31.25 kHz 294 | else if (bw < 52100) bw = SX126X_BW_41700; // 41.7 kHz 295 | else if (bw < 93800) bw = SX126X_BW_62500; // 62.5 kHz 296 | else if (bw < 187500) bw = SX126X_BW_125000; // 125 kHz 297 | else if (bw < 375000) bw = SX126X_BW_250000; // 250 kHz 298 | else bw = SX126X_BW_500000; // 500 kHz 299 | // valid code rate denominator is between 4 and 8 300 | cr -= 4; 301 | if (cr > 4) cr = 0; 302 | 303 | sx126x_setModulationParamsLoRa(sf, (uint8_t) bw, cr, (uint8_t) ldro); 304 | } 305 | 306 | void SX126x::setLoRaPacket(uint8_t headerType, uint16_t preambleLength, uint8_t payloadLength, bool crcType, bool invertIq) 307 | { 308 | _headerType = headerType; 309 | _preambleLength = preambleLength; 310 | _payloadLength = payloadLength; 311 | _crcType = crcType; 312 | _invertIq = invertIq; 313 | 314 | // filter valid header type config 315 | if (headerType != SX126X_HEADER_IMPLICIT) headerType = SX126X_HEADER_EXPLICIT; 316 | 317 | sx126x_setPacketParamsLoRa(preambleLength, headerType, payloadLength, (uint8_t) crcType, (uint8_t) invertIq); 318 | sx126x_fixInvertedIq((uint8_t) invertIq); 319 | } 320 | 321 | void SX126x::setSpreadingFactor(uint8_t sf) 322 | { 323 | setLoRaModulation(sf, _bw, _cr, _ldro); 324 | } 325 | 326 | void SX126x::setBandwidth(uint32_t bw) 327 | { 328 | setLoRaModulation(_sf, bw, _cr, _ldro); 329 | } 330 | 331 | void SX126x::setCodeRate(uint8_t cr) 332 | { 333 | setLoRaModulation(_sf, _bw, cr, _ldro); 334 | } 335 | 336 | void SX126x::setLdroEnable(bool ldro) 337 | { 338 | setLoRaModulation(_sf, _bw, _cr, ldro); 339 | } 340 | 341 | void SX126x::setHeaderType(uint8_t headerType) 342 | { 343 | setLoRaPacket(headerType, _preambleLength, _payloadLength, _crcType, _invertIq); 344 | } 345 | 346 | void SX126x::setPreambleLength(uint16_t preambleLength) 347 | { 348 | setLoRaPacket(_headerType, preambleLength, _payloadLength, _crcType, _invertIq); 349 | } 350 | 351 | void SX126x::setPayloadLength(uint8_t payloadLength) 352 | { 353 | setLoRaPacket(_headerType, _preambleLength, payloadLength, _crcType, _invertIq); 354 | } 355 | 356 | void SX126x::setCrcEnable(bool crcType) 357 | { 358 | setLoRaPacket(_headerType, _preambleLength, _payloadLength, crcType, _invertIq); 359 | } 360 | 361 | void SX126x::setInvertIq(bool invertIq) 362 | { 363 | setLoRaPacket(_headerType, _preambleLength, _payloadLength, _crcType, invertIq); 364 | } 365 | 366 | void SX126x::setSyncWord(uint16_t syncWord) 367 | { 368 | uint8_t buf[2]; 369 | buf[0] = syncWord >> 8; 370 | buf[1] = syncWord & 0xFF; 371 | if (syncWord <= 0xFF) { 372 | buf[0] = (syncWord & 0xF0) | 0x04; 373 | buf[1] = (syncWord << 4) | 0x04; 374 | } 375 | sx126x_writeRegister(SX126X_REG_LORA_SYNC_WORD_MSB, buf, 2); 376 | } 377 | 378 | void SX126x::setFskModulation(uint32_t br, uint8_t pulseShape, uint8_t bandwidth, uint32_t Fdev) 379 | { 380 | sx126x_setModulationParamsFSK(br, pulseShape, bandwidth, Fdev); 381 | } 382 | 383 | void SX126x::setFskPacket(uint16_t preambleLength, uint8_t preambleDetector, uint8_t syncWordLength, uint8_t addrComp, uint8_t packetType, uint8_t payloadLength, uint8_t crcType, uint8_t whitening) 384 | { 385 | sx126x_setPacketParamsFSK(preambleLength, preambleDetector, syncWordLength, addrComp, packetType, payloadLength, crcType, whitening); 386 | } 387 | 388 | void SX126x::setFskSyncWord(uint8_t* sw, uint8_t swLen) 389 | { 390 | sx126x_writeRegister(SX126X_REG_FSK_SYNC_WORD_0, sw, swLen); 391 | } 392 | 393 | void SX126x::setFskAdress(uint8_t nodeAddr, uint8_t broadcastAddr) 394 | { 395 | uint8_t buf[2] = {nodeAddr, broadcastAddr}; 396 | sx126x_writeRegister(SX126X_REG_FSK_NODE_ADDRESS, buf, 2); 397 | } 398 | 399 | void SX126x::setFskCrc(uint16_t crcInit, uint16_t crcPolynom) 400 | { 401 | uint8_t buf[4]; 402 | buf[0] = crcInit >> 8; 403 | buf[1] = crcInit & 0xFF; 404 | buf[2] = crcPolynom >> 8; 405 | buf[3] = crcPolynom & 0xFF; 406 | sx126x_writeRegister(SX126X_REG_FSK_CRC_INITIAL_MSB, buf, 4); 407 | } 408 | 409 | void SX126x::setFskWhitening(uint16_t whitening) 410 | { 411 | uint8_t buf[2]; 412 | buf[0] = whitening >> 8; 413 | buf[1] = whitening & 0xFF; 414 | sx126x_writeRegister(SX126X_REG_FSK_WHITENING_INITIAL_MSB, buf, 2); 415 | } 416 | 417 | void SX126x::beginPacket() 418 | { 419 | // reset payload length and buffer index 420 | _payloadTxRx = 0; 421 | sx126x_setBufferBaseAddress(_bufferIndex, _bufferIndex + 0xFF); 422 | 423 | // set txen pin to low and rxen pin to high 424 | if ((_rxen != -1) && (_txen != -1)) { 425 | digitalWrite(_rxen, LOW); 426 | digitalWrite(_txen, HIGH); 427 | _pinToLow = _txen; 428 | } 429 | 430 | sx126x_fixLoRaBw500(_bw); 431 | } 432 | 433 | bool SX126x::endPacket(uint32_t timeout) 434 | { 435 | // skip to enter TX mode when previous TX operation incomplete 436 | if (getMode() == SX126X_STATUS_MODE_TX) return false; 437 | 438 | // clear previous interrupt and set TX done, and TX timeout as interrupt source 439 | _irqSetup(SX126X_IRQ_TX_DONE | SX126X_IRQ_TIMEOUT); 440 | 441 | // set packet payload length 442 | setLoRaPacket(_headerType, _preambleLength, _payloadTxRx, _crcType, _invertIq); 443 | 444 | // set status to TX wait 445 | _statusWait = SX126X_STATUS_TX_WAIT; 446 | _statusIrq = 0x0000; 447 | // calculate TX timeout config 448 | uint32_t txTimeout = timeout << 6; 449 | if (txTimeout > 0x00FFFFFF) txTimeout = SX126X_TX_SINGLE; 450 | 451 | // set device to transmit mode with configured timeout or single operation 452 | sx126x_setTx(txTimeout); 453 | _transmitTime = millis(); 454 | 455 | // set operation status to wait and attach TX interrupt handler 456 | if (_irq != -1) { 457 | attachInterrupt(_irqStatic, SX126x::_interruptTx, RISING); 458 | } 459 | return true; 460 | } 461 | 462 | void SX126x::write(uint8_t data) 463 | { 464 | // write single byte of package to be transmitted 465 | sx126x_writeBuffer(_bufferIndex, &data, 1); 466 | _bufferIndex++; 467 | _payloadTxRx++; 468 | } 469 | 470 | void SX126x::write(uint8_t* data, uint8_t length) 471 | { 472 | // write multiple bytes of package to be transmitted 473 | sx126x_writeBuffer(_bufferIndex, data, length); 474 | _bufferIndex += length; 475 | _payloadTxRx += length; 476 | } 477 | 478 | void SX126x::write(char* data, uint8_t length) 479 | { 480 | // write multiple bytes of package to be transmitted for char type 481 | uint8_t* data_ = (uint8_t*) data; 482 | sx126x_writeBuffer(_bufferIndex, data_, length); 483 | _bufferIndex += length; 484 | _payloadTxRx += length; 485 | } 486 | 487 | bool SX126x::request(uint32_t timeout) 488 | { 489 | // skip to enter RX mode when previous RX operation incomplete 490 | if (getMode() == SX126X_STATUS_MODE_RX) return false; 491 | 492 | // clear previous interrupt and set RX done, RX timeout, header error, and CRC error as interrupt source 493 | _irqSetup(SX126X_IRQ_RX_DONE | SX126X_IRQ_TIMEOUT | SX126X_IRQ_HEADER_ERR | SX126X_IRQ_CRC_ERR); 494 | 495 | // set status to RX wait or RX continuous wait 496 | _statusWait = SX126X_STATUS_RX_WAIT; 497 | _statusIrq = 0x0000; 498 | // calculate RX timeout config 499 | uint32_t rxTimeout = timeout << 6; 500 | if (rxTimeout > 0x00FFFFFF) rxTimeout = SX126X_RX_SINGLE; 501 | if (timeout == SX126X_RX_CONTINUOUS) { 502 | rxTimeout = SX126X_RX_CONTINUOUS; 503 | _statusWait = SX126X_STATUS_RX_CONTINUOUS; 504 | } 505 | 506 | // set txen pin to low and rxen pin to high 507 | if ((_rxen != -1) && (_txen != -1)) { 508 | digitalWrite(_rxen, HIGH); 509 | digitalWrite(_txen, LOW); 510 | _pinToLow = _rxen; 511 | } 512 | 513 | // set device to receive mode with configured timeout, single, or continuous operation 514 | sx126x_setRx(rxTimeout); 515 | 516 | // set operation status to wait and attach RX interrupt handler 517 | if (_irq != -1) { 518 | if (timeout == SX126X_RX_CONTINUOUS) { 519 | attachInterrupt(_irqStatic, SX126x::_interruptRxContinuous, RISING); 520 | } else { 521 | attachInterrupt(_irqStatic, SX126x::_interruptRx, RISING); 522 | } 523 | } 524 | return true; 525 | } 526 | 527 | bool SX126x::listen(uint32_t rxPeriod, uint32_t sleepPeriod) 528 | { 529 | // skip to enter RX mode when previous RX operation incomplete 530 | if (getMode() == SX126X_STATUS_MODE_RX) return false; 531 | 532 | // clear previous interrupt and set RX done, RX timeout, header error, and CRC error as interrupt source 533 | _irqSetup(SX126X_IRQ_RX_DONE | SX126X_IRQ_TIMEOUT | SX126X_IRQ_HEADER_ERR | SX126X_IRQ_CRC_ERR); 534 | 535 | // set status to RX wait 536 | _statusWait = SX126X_STATUS_RX_WAIT; 537 | _statusIrq = 0x0000; 538 | // calculate RX period and sleep period config 539 | rxPeriod = rxPeriod << 6; 540 | sleepPeriod = sleepPeriod << 6; 541 | if (rxPeriod > 0x00FFFFFF) rxPeriod = 0x00FFFFFF; 542 | if (sleepPeriod > 0x00FFFFFF) sleepPeriod = 0x00FFFFFF; 543 | 544 | // set txen pin to low and rxen pin to high 545 | if ((_rxen != -1) && (_txen != -1)) { 546 | digitalWrite(_rxen, HIGH); 547 | digitalWrite(_txen, LOW); 548 | _pinToLow = _rxen; 549 | } 550 | 551 | // set device to receive mode with configured receive and sleep period 552 | sx126x_setRxDutyCycle(rxPeriod, sleepPeriod); 553 | 554 | // set operation status to wait and attach RX interrupt handler 555 | if (_irq != -1) { 556 | attachInterrupt(_irqStatic, SX126x::_interruptRx, RISING); 557 | } 558 | return true; 559 | } 560 | 561 | uint8_t SX126x::available() 562 | { 563 | // get size of package still available to read 564 | return _payloadTxRx; 565 | } 566 | 567 | uint8_t SX126x::read() 568 | { 569 | // read single byte of received package 570 | uint8_t buf; 571 | sx126x_readBuffer(_bufferIndex, &buf, 1); 572 | _bufferIndex++; 573 | if (_payloadTxRx > 0) _payloadTxRx--; 574 | return buf; 575 | } 576 | 577 | uint8_t SX126x::read(uint8_t* data, uint8_t length) 578 | { 579 | // read multiple bytes of received package 580 | sx126x_readBuffer(_bufferIndex, data, length); 581 | // return smallest between read length and size of package available 582 | _bufferIndex += length; 583 | _payloadTxRx = _payloadTxRx > length ? _payloadTxRx - length : 0; 584 | return _payloadTxRx > length ? length : _payloadTxRx; 585 | } 586 | 587 | uint8_t SX126x::read(char* data, uint8_t length) 588 | { 589 | // read multiple bytes of received package for char type 590 | uint8_t* data_ = (uint8_t*) data; 591 | sx126x_readBuffer(_bufferIndex, data_, length); 592 | _bufferIndex += length; 593 | _payloadTxRx = _payloadTxRx > length ? _payloadTxRx - length : 0; 594 | return _payloadTxRx > length ? length : _payloadTxRx; 595 | } 596 | 597 | void SX126x::purge(uint8_t length) 598 | { 599 | // subtract or reset received payload length 600 | _payloadTxRx = (_payloadTxRx > length) && length ? _payloadTxRx - length : 0; 601 | _bufferIndex += length; 602 | } 603 | 604 | bool SX126x::wait(uint32_t timeout) 605 | { 606 | // immediately return when currently not waiting transmit or receive process 607 | if (_statusIrq) return true; 608 | 609 | // wait transmit or receive process finish by checking interrupt status or IRQ status 610 | uint16_t irqStat = 0x0000; 611 | uint32_t t = millis(); 612 | while (irqStat == 0x0000 && _statusIrq == 0x0000) { 613 | // only check IRQ status register for non interrupt operation 614 | if (_irq == -1) sx126x_getIrqStatus(&irqStat); 615 | // return when timeout reached 616 | if (millis() - t > timeout && timeout != 0) return false; 617 | yield(); 618 | } 619 | 620 | if (_statusIrq) { 621 | // immediately return when interrupt signal hit 622 | return true; 623 | } else if (_statusWait == SX126X_STATUS_TX_WAIT) { 624 | // for transmit, calculate transmit time and set back txen pin to low 625 | _transmitTime = millis() - _transmitTime; 626 | if (_txen != -1) digitalWrite(_txen, LOW); 627 | } else if (_statusWait == SX126X_STATUS_RX_WAIT) { 628 | // for receive, get received payload length and buffer index and set back rxen pin to low 629 | sx126x_getRxBufferStatus(&_payloadTxRx, &_bufferIndex); 630 | if (_rxen != -1) digitalWrite(_rxen, LOW); 631 | sx126x_fixRxTimeout(); 632 | } else if (_statusWait == SX126X_STATUS_RX_CONTINUOUS) { 633 | // for receive continuous, get received payload length and buffer index and clear IRQ status 634 | sx126x_getRxBufferStatus(&_payloadTxRx, &_bufferIndex); 635 | sx126x_clearIrqStatus(0x03FF); 636 | } 637 | 638 | // store IRQ status 639 | _statusIrq = irqStat; 640 | return true; 641 | } 642 | 643 | uint8_t SX126x::status() 644 | { 645 | // set back status IRQ for RX continuous operation 646 | uint16_t statusIrq = _statusIrq; 647 | if (_statusWait == SX126X_STATUS_RX_CONTINUOUS) { 648 | _statusIrq = 0x0000; 649 | } 650 | 651 | // get status for transmit and receive operation based on status IRQ 652 | if (statusIrq & SX126X_IRQ_TIMEOUT) { 653 | if (_statusWait == SX126X_STATUS_TX_WAIT) return SX126X_STATUS_TX_TIMEOUT; 654 | else return SX126X_STATUS_RX_TIMEOUT; 655 | } 656 | else if (statusIrq & SX126X_IRQ_HEADER_ERR) return SX126X_STATUS_HEADER_ERR; 657 | else if (statusIrq & SX126X_IRQ_CRC_ERR) return SX126X_STATUS_CRC_ERR; 658 | else if (statusIrq & SX126X_IRQ_TX_DONE) return SX126X_STATUS_TX_DONE; 659 | else if (statusIrq & SX126X_IRQ_RX_DONE) return SX126X_STATUS_RX_DONE; 660 | 661 | // return TX or RX wait status 662 | return _statusWait; 663 | } 664 | 665 | uint32_t SX126x::transmitTime() 666 | { 667 | // get transmit time in millisecond (ms) 668 | return _transmitTime; 669 | } 670 | 671 | float SX126x::dataRate() 672 | { 673 | // get data rate last transmitted package in kbps 674 | return 1000.0 * _payloadTxRx / _transmitTime; 675 | } 676 | 677 | int16_t SX126x::packetRssi() 678 | { 679 | // get relative signal strength index (RSSI) of last incoming package 680 | uint8_t rssiPkt, snrPkt, signalRssiPkt; 681 | sx126x_getPacketStatus(&rssiPkt, &snrPkt, &signalRssiPkt); 682 | return (rssiPkt / -2); 683 | } 684 | 685 | float SX126x::snr() 686 | { 687 | // get signal to noise ratio (SNR) of last incoming package 688 | uint8_t rssiPkt, snrPkt, signalRssiPkt; 689 | sx126x_getPacketStatus(&rssiPkt, &snrPkt, &signalRssiPkt); 690 | return ((int8_t) snrPkt / 4.0); 691 | } 692 | 693 | int16_t SX126x::signalRssi() 694 | { 695 | uint8_t rssiPkt, snrPkt, signalRssiPkt; 696 | sx126x_getPacketStatus(&rssiPkt, &snrPkt, &signalRssiPkt); 697 | return (signalRssiPkt / -2); 698 | } 699 | 700 | int16_t SX126x::rssiInst() 701 | { 702 | uint8_t rssiInst; 703 | sx126x_getRssiInst(&rssiInst); 704 | return (rssiInst / -2); 705 | } 706 | 707 | uint16_t SX126x::getError() 708 | { 709 | uint16_t error; 710 | sx126x_getDeviceErrors(&error); 711 | sx126x_clearDeviceErrors(); 712 | return error; 713 | } 714 | 715 | uint32_t SX126x::random() 716 | { 717 | // generate random number from register and previous random number 718 | uint8_t buf[4]; 719 | sx126x_readRegister(SX126X_REG_RANDOM_NUMBER_GEN, buf, 4); 720 | uint32_t number = ((uint32_t) buf[0] << 24) | ((uint32_t) buf[1] << 16) | ((uint32_t) buf[2] << 8) | ((uint32_t) buf[0]); 721 | uint32_t n = _random; 722 | number = number ^ ((~n << 16) | n); 723 | // combine random number with random number seeded by time 724 | srand(millis()); 725 | number = number ^ (((uint32_t) rand() << 16) | rand()); 726 | _random = number >> 8; 727 | return number; 728 | } 729 | 730 | void SX126x::_irqSetup(uint16_t irqMask) 731 | { 732 | // clear IRQ status of previous transmit or receive operation 733 | sx126x_clearIrqStatus(0x03FF); 734 | 735 | // set selected interrupt source 736 | uint16_t dio1Mask = 0x0000; 737 | uint16_t dio2Mask = 0x0000; 738 | uint16_t dio3Mask = 0x0000; 739 | if (_dio == 2) dio2Mask = irqMask; 740 | else if (_dio == 3) dio3Mask = irqMask; 741 | else dio1Mask = irqMask; 742 | sx126x_setDioIrqParams(irqMask, dio1Mask, dio2Mask, dio3Mask); 743 | } 744 | 745 | void SX126x::_interruptTx() 746 | { 747 | // calculate transmit time 748 | _transmitTime = millis() - _transmitTime; 749 | 750 | // set back txen pin to low and detach interrupt 751 | if (_pinToLow != -1) digitalWrite(_pinToLow, LOW); 752 | detachInterrupt(_irqStatic); 753 | 754 | // store IRQ status 755 | uint16_t buf; 756 | sx126x_getIrqStatus(&buf); 757 | _statusIrq = buf; 758 | 759 | // call onTransmit function 760 | if (_onTransmit) { 761 | _onTransmit(); 762 | } 763 | } 764 | 765 | void SX126x::_interruptRx() 766 | { 767 | // set back rxen pin to low and detach interrupt 768 | if (_pinToLow != -1) digitalWrite(_pinToLow, LOW); 769 | detachInterrupt(_irqStatic); 770 | sx126x_fixRxTimeout(); 771 | 772 | // store IRQ status 773 | uint16_t buf; 774 | sx126x_getIrqStatus(&buf); 775 | _statusIrq = buf; 776 | 777 | // get received payload length and buffer index 778 | sx126x_getRxBufferStatus(&_payloadTxRx, &_bufferIndex); 779 | 780 | // call onReceive function 781 | if (_onReceive) { 782 | _onReceive(); 783 | } 784 | } 785 | 786 | void SX126x::_interruptRxContinuous() 787 | { 788 | // store IRQ status 789 | uint16_t buf; 790 | sx126x_getIrqStatus(&buf); 791 | _statusIrq = buf; 792 | 793 | // clear IRQ status 794 | sx126x_clearIrqStatus(0x03FF); 795 | 796 | // get received payload length and buffer index 797 | sx126x_getRxBufferStatus(&_payloadTxRx, &_bufferIndex); 798 | 799 | // call onReceive function 800 | if (_onReceive) { 801 | _onReceive(); 802 | } 803 | } 804 | 805 | void SX126x::onTransmit(void(&callback)()) 806 | { 807 | // register onTransmit function to call every transmit done 808 | _onTransmit = &callback; 809 | } 810 | 811 | void SX126x::onReceive(void(&callback)()) 812 | { 813 | // register onReceive function to call every receive done 814 | _onReceive = &callback; 815 | } 816 | --------------------------------------------------------------------------------