Added support for all Semtech LoRa modules (SX1272/73/76/77/78/79)

This commit is contained in:
Jan Gromeš 2018-07-03 09:58:29 +02:00
parent c2b1826410
commit 8d8ab76f5a
20 changed files with 1272 additions and 1139 deletions

View file

@ -14,7 +14,11 @@ ESP8266 KEYWORD1
HC05 KEYWORD1
RF69 KEYWORD1
SX1272 KEYWORD1
SX1273 KEYWORD1
SX1276 KEYWORD1
SX1277 KEYWORD1
SX1278 KEYWORD1
SX1279 KEYWORD1
XBee KEYWORD1
Bandwidth KEYWORD1
@ -39,8 +43,9 @@ getDestinationStr KEYWORD2
setSourceStr KEYWORD2
setDestinationStr KEYWORD2
copyInto KEYWORD2
setPacketData KEYWORD2
# SX1278/SX1272 + RF69
# SX1272/73/76/77/78/79 + RF69
dataRate KEYWORD2
lastPacketRSSI KEYWORD2
begin KEYWORD2
@ -51,6 +56,9 @@ standby KEYWORD2
setBandwidth KEYWORD2
setSpreadingFactor KEYWORD2
setCodingRate KEYWORD2
setFrequency KEYWORD2
setSyncWord KEYWORD2
setOutputPower KEYWORD2
# ESP8266
join KEYWORD2
@ -74,31 +82,9 @@ setPanId KEYWORD2
# Constants (LITERAL1)
#######################################
BW_7_80_KHZ LITERAL1
BW_10_40_KHZ LITERAL1
BW_15_60_KHZ LITERAL1
BW_20_80_KHZ LITERAL1
BW_31_25_KHZ LITERAL1
BW_41_70_KHZ LITERAL1
BW_62_50_KHZ LITERAL1
BW_125_00_KHZ LITERAL1
BW_250_00_KHZ LITERAL1
BW_500_00_KHZ LITERAL1
SF_6 LITERAL1
SF_7 LITERAL1
SF_8 LITERAL1
SF_9 LITERAL1
SF_10 LITERAL1
SF_11 LITERAL1
SF_12 LITERAL1
CR_4_5 LITERAL1
CR_4_6 LITERAL1
CR_4_7 LITERAL1
CR_4_8 LITERAL1
ERR_NONE LITERAL1
ERR_UNKNOWN LITERAL1
ERR_CHIP_NOT_FOUND LITERAL1
ERR_EEPROM_NOT_INITIALIZED LITERAL1
ERR_PACKET_TOO_LONG LITERAL1
@ -109,10 +95,19 @@ ERR_INVALID_BANDWIDTH LITERAL1
ERR_INVALID_SPREADING_FACTOR LITERAL1
ERR_INVALID_CODING_RATE LITERAL1
ERR_INVALID_BIT_RANGE LITERAL1
ERR_INVALID_FREQUENCY LITERAL1
ERR_INVALID_OUTPUT_POWER LITERAL1
PREAMBLE_DETECTED LITERAL1
CHANNEL_FREE LITERAL1
ERR_AT_FAILED LITERAL1
ERR_URL_MALFORMED LITERAL1
ERR_RESPONSE_MALFORMED_AT LITERAL1
ERR_RESPONSE_MALFORMED LITERAL1
ERR_MQTT_CONN_VERSION_REJECTED LITERAL1
ERR_MQTT_CONN_ID_REJECTED LITERAL1
ERR_MQTT_CONN_SERVER_UNAVAILABLE LITERAL1
ERR_MQTT_CONN_BAD_USERNAME_PASSWORD LITERAL1
ERR_MQTT_CONN_NOT_AUTHORIZED LITERAL1
ERR_CMD_MODE_FAILED LITERAL1

View file

@ -8,7 +8,11 @@
#include "modules/HC05.h"
#include "modules/RF69.h"
#include "modules/SX1272.h"
#include "modules/SX1273.h"
#include "modules/SX1276.h"
#include "modules/SX1277.h"
#include "modules/SX1278.h"
#include "modules/SX1279.h"
#include "modules/XBee.h"
#define KITE_CS_A 10

View file

@ -136,8 +136,9 @@ uint8_t Module::SPIsetRegValue(uint8_t reg, uint8_t value, uint8_t msb, uint8_t
}
uint8_t currentValue = SPIreadRegister(reg);
uint8_t newValue = currentValue & ((0b11111111 << (msb + 1)) & (0b11111111 >> (8 - lsb)));
SPIwriteRegister(reg, newValue | value);
uint8_t mask = ~((0b11111111 << (msb + 1)) | (0b11111111 >> (8 - lsb)));
uint8_t newValue = (currentValue & ~mask) | (value & mask);
SPIwriteRegister(reg, newValue);
return(ERR_NONE);
}

View file

@ -5,174 +5,177 @@ Packet::Packet(void) {
getLoRaAddress(src);
uint8_t dest[8] = {0, 0, 0, 0, 0, 0, 0, 0};
uint8_t dat[240];
uint8_t* dat;
uint8_t len = 0;
init(src, dest, dat, len);
}
Packet::Packet(const char dest[24], const char dat[240]) {
Packet::Packet(const char* dest, const char* dat) {
uint8_t src[8] = {0, 0, 0, 0, 0, 0, 0, 0};
getLoRaAddress(src);
uint8_t destTmp[8];
for(uint8_t i = 0; i < 8; i++) {
destTmp[i] = (parseByte(dest[3*i]) << 4) | parseByte(dest[3*i + 1]);
char str[] = {dest[3*i], dest[3*i + 1]};
destTmp[i] = strtoul(str, NULL, 16);
}
init(src, destTmp, dat);
}
Packet::Packet(uint8_t dest[8], const char dat[240]) {
Packet::Packet(uint8_t* dest, const char* dat) {
uint8_t src[8] = {0, 0, 0, 0, 0, 0, 0, 0};
getLoRaAddress(src);
init(src, dest, dat);
}
Packet::Packet(const char src[24], const char dest[24], const char dat[240]) {
Packet::Packet(const char* src, const char* dest, const char* dat) {
uint8_t srcTmp[8];
for(uint8_t i = 0; i < 8; i++) {
srcTmp[i] = (parseByte(src[3*i]) << 4) | parseByte(src[3*i + 1]);
char str[] = {src[3*i], src[3*i + 1]};
srcTmp[i] = strtoul(str, NULL, 16);
}
uint8_t destTmp[8];
for(uint8_t i = 0; i < 8; i++) {
destTmp[i] = (parseByte(dest[3*i]) << 4) | parseByte(dest[3*i + 1]);
char str[] = {dest[3*i], dest[3*i + 1]};
destTmp[i] = strtoul(str, NULL, 16);
}
init(srcTmp, destTmp, dat);
}
Packet::Packet(uint8_t src[8], uint8_t dest[8], const char dat[240]) {
Packet::Packet(uint8_t* src, uint8_t* dest, const char* dat) {
init(src, dest, dat);
}
Packet::Packet(const char dest[24], uint8_t* dat, uint8_t len) {
Packet::Packet(const char* dest, uint8_t* dat, uint8_t len) {
uint8_t src[8] = {0, 0, 0, 0, 0, 0, 0, 0};
getLoRaAddress(src);
uint8_t destTmp[8];
for(uint8_t i = 0; i < 8; i++) {
destTmp[i] = (parseByte(dest[3*i]) << 4) | parseByte(dest[3*i + 1]);
char str[] = {dest[3*i], dest[3*i + 1]};
destTmp[i] = strtoul(str, NULL, 16);
}
init(src, destTmp, dat, len);
}
Packet::Packet(uint8_t dest[8], uint8_t* dat, uint8_t len) {
Packet::Packet(uint8_t* dest, uint8_t* dat, uint8_t len) {
uint8_t src[8] = {0, 0, 0, 0, 0, 0, 0, 0};
getLoRaAddress(src);
init(src, dest, dat, len);
}
Packet::Packet(const char src[24], const char dest[24], uint8_t* dat, uint8_t len) {
Packet::Packet(const char* src, const char* dest, uint8_t* dat, uint8_t len) {
uint8_t srcTmp[8];
for(uint8_t i = 0; i < 8; i++) {
srcTmp[i] = (parseByte(src[3*i]) << 4) | parseByte(src[3*i + 1]);
char str[] = {src[3*i], src[3*i + 1]};
srcTmp[i] = strtoul(str, NULL, 16);
}
uint8_t destTmp[8];
for(uint8_t i = 0; i < 8; i++) {
destTmp[i] = (parseByte(dest[3*i]) << 4) | parseByte(dest[3*i + 1]);
char str[] = {dest[3*i], dest[3*i + 1]};
destTmp[i] = strtoul(str, NULL, 16);
}
init(srcTmp, destTmp, dat, len);
}
Packet::Packet(uint8_t src[8], uint8_t dest[8], uint8_t* dat, uint8_t len) {
Packet::Packet(uint8_t* src, uint8_t* dest, uint8_t* dat, uint8_t len) {
init(src, dest, dat, len);
}
void Packet::init(uint8_t src[8], uint8_t dest[8], const char dat[240]) {
for(uint8_t i = 0; i < 8; i++) {
source[i] = src[i];
destination[i] = dest[i];
}
length = 0;
for(uint8_t i = 0; i < 240; i++) {
data[i] = dat[i];
if(data[i] == '\0') {
length = i + 16;
break;
}
}
void Packet::init(uint8_t* src, uint8_t* dest, const char* dat) {
init(src, dest, (uint8_t*)dat, strlen(dat));
}
void Packet::init(uint8_t src[8], uint8_t dest[8], uint8_t* dat, uint8_t len) {
void Packet::init(uint8_t* src, uint8_t* dest, uint8_t* dat, uint8_t len) {
memcpy(source, src, 8);
memcpy(destination, dest, 8);
length = len + 16;
for(uint8_t i = 0; i < 8; i++) {
source[i] = src[i];
destination[i] = dest[i];
}
data = new char[len + 1];
memcpy(data, dat, len + 1);
}
for(uint8_t i = 0; i < length; i++) {
data[i] = dat[i];
String Packet::getSourceStr() {
char charArray[24];
for(uint8_t i = 0; i < 8; i++) {
sprintf(charArray + 3*i, "%02X", source[i]);
charArray[3*i+2] = ':';
}
charArray[23] = '\0';
String str(charArray);
return(str);
}
String Packet::getDestinationStr() {
char charArray[24];
for(uint8_t i = 0; i < 8; i++) {
sprintf(charArray + 3*i, "%02X", destination[i]);
charArray[3*i+2] = ':';
}
charArray[23] = '\0';
String str(charArray);
return(str);
}
void Packet::setSourceStr(const char* src) {
for(uint8_t i = 0; i < 8; i++) {
char str[] = {src[3*i], src[3*i + 1]};
source[i] = strtoul(str, NULL, 16);
}
}
void Packet::getSourceStr(char src[24]) {
void Packet::setDestinationStr(const char* dest) {
for(uint8_t i = 0; i < 8; i++) {
src[3*i] = reparseChar(source[i] >> 4);
src[3*i+1] = reparseChar(source[i] & 0x0F);
src[3*i+2] = ':';
}
src[23] = '\0';
}
void Packet::getDestinationStr(char dest[24]) {
for(uint8_t i = 0; i < 8; i++) {
dest[3*i] = reparseChar(destination[i] >> 4);
dest[3*i+1] = reparseChar(destination[i] & 0x0F);
dest[3*i+2] = ':';
}
dest[23] = '\0';
}
void Packet::setSourceStr(const char src[24]) {
for(uint8_t i = 0; i < 8; i++) {
source[i] = (parseByte(src[3*i]) << 4) | parseByte(src[3*i + 1]);
}
}
void Packet::setDestinationStr(const char dest[24]) {
for(uint8_t i = 0; i < 8; i++) {
destination[i] = (parseByte(dest[3*i]) << 4) | parseByte(dest[3*i + 1]);
char str[] = {dest[3*i], dest[3*i + 1]};
destination[i] = strtoul(str, NULL, 16);
}
}
void Packet::copyInto(Packet& pack) {
for(uint8_t i = 0; i < 8; i++) {
pack.source[i] = source[i];
pack.destination[i] = destination[i];
}
memcpy(pack.source, source, 8);
memcpy(pack.destination, destination, 8);
strcpy(pack.data, data);
}
void Packet::getLoRaAddress(uint8_t addr[8]) {
void Packet::setPacketData(char* charArray) {
char* newData = new char[strlen(charArray)];
length = strlen(charArray) + 16;
strcpy(newData, charArray);
delete[] data;
data = newData;
}
void Packet::setPacketData(String str) {
setPacketData((char*)str.c_str());
}
void Packet::setPacketData(float f, uint8_t decimals) {
int i = f;
float res = f - i;
if (res == 0) {
char charArray[16];
itoa(i, charArray, 10);
setPacketData(charArray);
} else {
String floatString = String(f, decimals);
setPacketData(floatString);
}
}
void Packet::getLoRaAddress(uint8_t* addr) {
for(uint8_t i = 0; i < 8; i++) {
addr[i] = EEPROM.read(i);
}
}
uint8_t Packet::parseByte(char c) {
if((c >= 48) && (c <= 57)) {
return(c - 48);
} else if((c >= 65) && (c <= 70)) {
return(c - 55);
} else if((c >= 97) && (c <= 102)) {
return(c - 87);
}
return(0);
}
char Packet::reparseChar(uint8_t b) {
if(b <= 9) {
return(b + 48);
} else if((b >= 10) && (b <= 16)) {
return(b + 55);
}
return(0);
}

View file

@ -1,5 +1,5 @@
#ifndef _LORALIB_PACKET_H
#define _LORALIB_PACKET_H
#ifndef _KITELIB_PACKET_H
#define _KITELIB_PACKET_H
#if ARDUINO >= 100
#include "Arduino.h"
@ -12,36 +12,37 @@
class Packet {
public:
Packet(void);
Packet(const char dest[24], const char dat[240]);
Packet(uint8_t dest[8], const char dat[240]);
Packet(const char src[24], const char dest[24], const char dat[240]);
Packet(uint8_t src[8], uint8_t dest[8], const char dat[240]);
Packet(const char* dest, const char* dat);
Packet(uint8_t* dest, const char* dat);
Packet(const char* src, const char* dest, const char* dat);
Packet(uint8_t* src, uint8_t* dest, const char* dat);
Packet(const char dest[24], uint8_t* dat, uint8_t len);
Packet(uint8_t dest[8], uint8_t* dat, uint8_t len);
Packet(const char src[24], const char dest[24], uint8_t* dat, uint8_t len);
Packet(uint8_t src[8], uint8_t dest[8], uint8_t* dat, uint8_t len);
Packet(const char* dest, uint8_t* dat, uint8_t len);
Packet(uint8_t* dest, uint8_t* dat, uint8_t len);
Packet(const char* src, const char* dest, uint8_t* dat, uint8_t len);
Packet(uint8_t* src, uint8_t* dest, uint8_t* dat, uint8_t len);
uint8_t source[8] = {0, 0, 0, 0, 0, 0, 0, 0};
uint8_t destination[8] = {0, 0, 0, 0, 0, 0, 0, 0};
char data[240];
char* data;
uint8_t length = 0;
void getSourceStr(char src[24]);
void getDestinationStr(char dest[24]);
String getSourceStr();
String getDestinationStr();
void setSourceStr(const char src[24]);
void setDestinationStr(const char dest[24]);
void setSourceStr(const char* src);
void setDestinationStr(const char* dest);
void copyInto(Packet& pack);
private:
void init(uint8_t src[8], uint8_t dest[8], const char dat[240]);
void init(uint8_t src[8], uint8_t dest[8], uint8_t* dat, uint8_t len);
void getLoRaAddress(uint8_t addr[8]);
void setPacketData(char* charArray);
void setPacketData(String str);
void setPacketData(float f, uint8_t decimals = 3);
uint8_t parseByte(char c);
char reparseChar(uint8_t b);
private:
void init(uint8_t* src, uint8_t* dest, const char* dat);
void init(uint8_t* src, uint8_t* dest, uint8_t* dat, uint8_t len);
void getLoRaAddress(uint8_t* addr);
};
#endif

View file

@ -7,9 +7,9 @@
#include "WProgram.h"
#endif
//#define DEBUG
//#define KITELIB_DEBUG
/*#ifdef DEBUG
#ifdef KITELIB_DEBUG
#define DEBUG_BEGIN(x) Serial.begin (x)
#define DEBUG_PRINT(x) Serial.print (x)
#define DEBUG_PRINT_DEC(x) Serial.print (x, DEC)
@ -17,7 +17,7 @@
#define DEBUG_PRINTLN(x) Serial.println (x)
#define DEBUG_PRINT_STR(x) Serial.print (F(x))
#define DEBUG_PRINTLN_STR(x) Serial.println (F(x))
#else*/
#else
#define DEBUG_BEGIN(x)
#define DEBUG_PRINT(x)
#define DEBUG_PRINT_DEC(x)
@ -25,58 +25,62 @@
#define DEBUG_PRINTLN(x)
#define DEBUG_PRINT_STR(x)
#define DEBUG_PRINTLN_STR(x)
//#endif
#endif
// Shield configuration
#define USE_SPI 0x00
#define USE_UART 0x01
#define USE_I2C 0x02
#define INT_NONE 0x00
#define INT_0 0x01
#define INT_1 0x02
#define INT_BOTH 0x03
#define USE_SPI 0x00
#define USE_UART 0x01
#define USE_I2C 0x02
#define INT_NONE 0x00
#define INT_0 0x01
#define INT_1 0x02
#define INT_BOTH 0x03
// UART configuration
#define UART_STOPBIT_1 0x01
#define UART_STOPBIT_1_5 0x02
#define UART_STOPBIT_2 0x03
#define UART_PARITY_NONE 0x00
#define UART_PARITY_ODD 0x01
#define UART_PARITY_EVEN 0x02
#define UART_FLOW_NONE 0x00
#define UART_FLOW_RTS 0x01
#define UART_FLOW_CTS 0x02
#define UART_FLOW_BOTH 0x03
#define UART_STOPBIT_1 0x01
#define UART_STOPBIT_1_5 0x02
#define UART_STOPBIT_2 0x03
#define UART_PARITY_NONE 0x00
#define UART_PARITY_ODD 0x01
#define UART_PARITY_EVEN 0x02
#define UART_FLOW_NONE 0x00
#define UART_FLOW_RTS 0x01
#define UART_FLOW_CTS 0x02
#define UART_FLOW_BOTH 0x03
// Common error codes
#define ERR_NONE 0x00
#define ERR_UNKNOWN 0x63 // maximum error code value is 99, so that it does not interfere with HTTP status codes
// Common status codes
#define ERR_NONE 0x00
#define ERR_UNKNOWN 0x63 // maximum status code value is 99 DEC, so that it does not interfere with HTTP status codes
// SX1278/SX1272/RF69 error codes
#define ERR_CHIP_NOT_FOUND 0x01
#define ERR_EEPROM_NOT_INITIALIZED 0x02
#define ERR_PACKET_TOO_LONG 0x03
#define ERR_TX_TIMEOUT 0x04
#define ERR_RX_TIMEOUT 0x05
#define ERR_CRC_MISMATCH 0x06
#define ERR_INVALID_BANDWIDTH 0x07
#define ERR_INVALID_SPREADING_FACTOR 0x08
#define ERR_INVALID_CODING_RATE 0x09
#define ERR_INVALID_BIT_RANGE 0x10
// SX1278/SX1272/RF69 status codes
#define ERR_CHIP_NOT_FOUND 0x01
#define ERR_EEPROM_NOT_INITIALIZED 0x02
#define ERR_PACKET_TOO_LONG 0x03
#define ERR_TX_TIMEOUT 0x04
#define ERR_RX_TIMEOUT 0x05
#define ERR_CRC_MISMATCH 0x06
#define ERR_INVALID_BANDWIDTH 0x07
#define ERR_INVALID_SPREADING_FACTOR 0x08
#define ERR_INVALID_CODING_RATE 0x09
#define ERR_INVALID_BIT_RANGE 0x0A
#define ERR_INVALID_FREQUENCY 0x0B
#define ERR_INVALID_OUTPUT_POWER 0x0C
#define PREAMBLE_DETECTED 0x0D
#define CHANNEL_FREE 0x0E
// ESP8266 error codes
#define ERR_AT_FAILED 0x01
#define ERR_URL_MALFORMED 0x02
#define ERR_RESPONSE_MALFORMED_AT 0x03
#define ERR_RESPONSE_MALFORMED 0x04
#define ERR_MQTT_CONN_VERSION_REJECTED 0x05
#define ERR_MQTT_CONN_ID_REJECTED 0x06
#define ERR_MQTT_CONN_SERVER_UNAVAILABLE 0x07
#define MQTT_CONN_BAD_USERNAME_PASSWORD 0x08
#define ERR_MQTT_CONN_NOT_AUTHORIZED 0x09
// ESP8266 status codes
#define ERR_AT_FAILED 0x01
#define ERR_URL_MALFORMED 0x02
#define ERR_RESPONSE_MALFORMED_AT 0x03
#define ERR_RESPONSE_MALFORMED 0x04
#define ERR_MQTT_CONN_VERSION_REJECTED 0x05
#define ERR_MQTT_CONN_ID_REJECTED 0x06
#define ERR_MQTT_CONN_SERVER_UNAVAILABLE 0x07
#define ERR_MQTT_CONN_BAD_USERNAME_PASSWORD 0x08
#define ERR_MQTT_CONN_NOT_AUTHORIZED 0x09
// XBee error codes
#define ERR_CMD_MODE_FAILED 0x02
// XBee status codes
#define ERR_CMD_MODE_FAILED 0x02
enum Slot {SlotA, SlotB};

View file

@ -1,262 +1,55 @@
#include "SX1272.h"
SX1272::SX1272(Module* module) {
_mod = module;
SX1272::SX1272(Module* mod) : SX127x(mod) {
}
uint8_t SX1272::begin(Bandwidth bw, SpreadingFactor sf, CodingRate cr, uint16_t addrEeprom) {
// copy LoRa modem settings
_bw = bw;
_sf = sf;
_cr = cr;
// ESP32-only: initialize EEPROM
#ifdef ESP32
if(!EEPROM.begin(9)) {
DEBUG_PRINTLN_STR("Unable to initialize EEPROM");
return(ERR_EEPROM_NOT_INITIALIZED);
}
#endif
// copy EEPROM start address
_addrEeprom = addrEeprom;
// check if the node has address
bool hasAddress = false;
for(uint16_t i = 0; i < 8; i++) {
if(EEPROM.read(_addrEeprom + i) != 255) {
hasAddress = true;
break;
}
uint8_t SX1272::begin(float freq, uint32_t bw, uint8_t sf, uint8_t cr, uint8_t syncWord, uint16_t addrEeprom) {
uint8_t state = SX127x::begin(freq, bw, sf, cr, syncWord, addrEeprom);
if(state != ERR_NONE) {
return(state);
}
// generate new address
if(!hasAddress) {
randomSeed(analogRead(5));
generateLoRaAdress();
}
#ifdef DEBUG
Serial.print("LoRa node address string: ");
#endif
for(uint8_t i = 0; i < 8; i++) {
_address[i] = EEPROM.read(i);
#ifdef DEBUG
Serial.print(_address[i], HEX);
if(i < 7) {
Serial.print(":");
} else {
Serial.println();
}
#endif
}
// set module properties
_mod->init(USE_SPI, INT_BOTH);
// try to find the SX1272 chip
uint8_t i = 0;
bool flagFound = false;
while((i < 10) && !flagFound) {
uint8_t version = _mod->SPIreadRegister(SX1272_REG_VERSION);
if(version == 0x22) {
flagFound = true;
} else {
#ifdef DEBUG
Serial.print("SX1272 not found! (");
Serial.print(i + 1);
Serial.print(" of 10 tries) SX1272_REG_VERSION == ");
char buffHex[5];
sprintf(buffHex, "0x%02X", version);
Serial.print(buffHex);
Serial.println();
#endif
delay(1000);
i++;
}
}
if(!flagFound) {
DEBUG_PRINTLN_STR("No SX1272 found!");
SPI.end();
return(ERR_CHIP_NOT_FOUND);
} else {
DEBUG_PRINTLN_STR("Found SX1272! (match by SX1272_REG_VERSION == 0x12)");
}
// configure LoRa modem
return(config(_bw, _sf, _cr));
return(config(freq, bw, sf, cr, syncWord));
}
uint8_t SX1272::transmit(Packet& pack) {
char buffer[256];
// copy packet source and destination addresses into buffer
for(uint8_t i = 0; i < 8; i++) {
buffer[i] = pack.source[i];
buffer[i+8] = pack.destination[i];
}
// copy packet data into buffer
for(uint8_t i = 0; i < pack.length; i++) {
buffer[i+16] = pack.data[i];
}
// set mode to standby
setMode(SX1272_STANDBY);
// set DIO pin mapping
_mod->SPIsetRegValue(SX1272_REG_DIO_MAPPING_1, SX1272_DIO0_TX_DONE, 7, 6);
// clear interrupt flags
clearIRQFlags();
// check overall packet length
if(pack.length > 256) {
return(ERR_PACKET_TOO_LONG);
}
// write packet to FIFO
_mod->SPIsetRegValue(SX1272_REG_PAYLOAD_LENGTH, pack.length);
_mod->SPIsetRegValue(SX1272_REG_FIFO_TX_BASE_ADDR, SX1272_FIFO_TX_BASE_ADDR_MAX);
_mod->SPIsetRegValue(SX1272_REG_FIFO_ADDR_PTR, SX1272_FIFO_TX_BASE_ADDR_MAX);
_mod->SPIwriteRegisterBurstStr(SX1272_REG_FIFO, buffer, pack.length);
// set mode to transmit
setMode(SX1272_TX);
// wait for transmission end
unsigned long start = millis();
while(!_mod->getInt0State()) {
DEBUG_PRINT('.');
}
// clear interrupt flags
clearIRQFlags();
return(ERR_NONE);
}
uint8_t SX1272::receive(Packet& pack) {
char buffer[256];
uint32_t startTime = millis();
// set mode to standby
setMode(SX1272_STANDBY);
// set DIO pin mapping
_mod->SPIsetRegValue(SX1272_REG_DIO_MAPPING_1, SX1272_DIO0_RX_DONE | SX1272_DIO1_RX_TIMEOUT, 7, 4);
// clear interrupt flags
clearIRQFlags();
// set FIFO address pointers
_mod->SPIsetRegValue(SX1272_REG_FIFO_RX_BASE_ADDR, SX1272_FIFO_RX_BASE_ADDR_MAX);
_mod->SPIsetRegValue(SX1272_REG_FIFO_ADDR_PTR, SX1272_FIFO_RX_BASE_ADDR_MAX);
// set mode to receive
setMode(SX1272_RXSINGLE);
// wait for packet reception or timeout
while(!_mod->getInt0State()) {
if(_mod->getInt1State()) {
clearIRQFlags();
return(ERR_RX_TIMEOUT);
}
}
// check received packet CRC
if(_mod->SPIgetRegValue(SX1272_REG_IRQ_FLAGS, 5, 5) == SX1272_CLEAR_IRQ_FLAG_PAYLOAD_CRC_ERROR) {
return(ERR_CRC_MISMATCH);
}
// get header type
uint8_t headerMode = _mod->SPIgetRegValue(SX1272_REG_MODEM_CONFIG_1, 0, 0);
if(headerMode == SX1272_HEADER_EXPL_MODE) {
pack.length = _mod->SPIgetRegValue(SX1272_REG_RX_NB_BYTES);
}
// read packet from FIFO
_mod->SPIreadRegisterBurstStr(SX1272_REG_FIFO, pack.length, buffer);
// clear interrupt flags
clearIRQFlags();
// get packet source and destination addresses from buffer
for(uint8_t i = 0; i < 8; i++) {
pack.source[i] = buffer[i];
pack.destination[i] = buffer[i+8];
}
// get packet source and destination addresses from buffer
for(uint8_t i = 16; i < pack.length; i++) {
pack.data[i-16] = buffer[i];
}
pack.data[pack.length-16] = 0;
// measure overall datarate
uint32_t elapsedTime = millis() - startTime;
dataRate = (pack.length*8.0)/((float)elapsedTime/1000.0);
// get packet RSSI
lastPacketRSSI = getLastPacketRSSI();
return(ERR_NONE);
}
uint8_t SX1272::sleep() {
return(setMode(0b00000000));
}
uint8_t SX1272::standby() {
return(setMode(0b00000001));
}
uint8_t SX1272::setBandwidth(Bandwidth bw) {
uint8_t state = config(bw, _sf, _cr);
uint8_t SX1272::setBandwidth(uint32_t bw) {
uint8_t state = SX1272::config(bw, _sf, _cr, _freq, _syncWord);
if(state == ERR_NONE) {
_bw = bw;
}
return(state);
}
uint8_t SX1272::setSpreadingFactor(SpreadingFactor sf) {
uint8_t state = config(_bw, sf, _cr);
uint8_t SX1272::setSpreadingFactor(uint8_t sf) {
uint8_t state = SX1272::config(_bw, sf, _cr, _freq, _syncWord);
if(state == ERR_NONE) {
_sf = sf;
}
return(state);
}
uint8_t SX1272::setCodingRate(CodingRate cr) {
uint8_t state = config(_bw, _sf, cr);
uint8_t SX1272::setCodingRate(uint8_t cr) {
uint8_t state = SX1272::config(_bw, _sf, cr, _freq, _syncWord);
if(state == ERR_NONE) {
_cr = cr;
}
return(state);
}
void SX1272::generateLoRaAdress() {
for(uint8_t i = _addrEeprom; i < (_addrEeprom + 8); i++) {
EEPROM.write(i, (uint8_t)random(0, 256));
}
}
uint8_t SX1272::config(Bandwidth bw, SpreadingFactor sf, CodingRate cr) {
uint8_t SX1272::config(float freq, uint32_t bw, uint8_t sf, uint8_t cr, uint8_t syncWord) {
uint8_t status = ERR_NONE;
uint8_t newBandwidth, newSpreadingFactor, newCodingRate;
//check the supplied bw, cr and sf values
// check the supplied BW, CR and SF values
switch(bw) {
case BW_125_00_KHZ:
case 125000:
newBandwidth = SX1272_BW_125_00_KHZ;
break;
case BW_250_00_KHZ:
case 250000:
newBandwidth = SX1272_BW_250_00_KHZ;
break;
case BW_500_00_KHZ:
case 500000:
newBandwidth = SX1272_BW_500_00_KHZ;
break;
default:
@ -264,130 +57,107 @@ uint8_t SX1272::config(Bandwidth bw, SpreadingFactor sf, CodingRate cr) {
}
switch(sf) {
case SF_6:
newSpreadingFactor = SX1272_SF_6;
case 6:
newSpreadingFactor = SX127X_SF_6;
break;
case SF_7:
newSpreadingFactor = SX1272_SF_7;
case 7:
newSpreadingFactor = SX127X_SF_7;
break;
case SF_8:
newSpreadingFactor = SX1272_SF_8;
case 8:
newSpreadingFactor = SX127X_SF_8;
break;
case SF_9:
newSpreadingFactor = SX1272_SF_9;
case 9:
newSpreadingFactor = SX127X_SF_9;
break;
case SF_10:
newSpreadingFactor = SX1272_SF_10;
case 10:
newSpreadingFactor = SX127X_SF_10;
break;
case SF_11:
newSpreadingFactor = SX1272_SF_11;
case 11:
newSpreadingFactor = SX127X_SF_11;
break;
case SF_12:
newSpreadingFactor = SX1272_SF_12;
case 12:
newSpreadingFactor = SX127X_SF_12;
break;
default:
return(ERR_INVALID_SPREADING_FACTOR);
}
switch(cr) {
case CR_4_5:
case 5:
newCodingRate = SX1272_CR_4_5;
break;
case CR_4_6:
case 6:
newCodingRate = SX1272_CR_4_6;
break;
case CR_4_7:
case 7:
newCodingRate = SX1272_CR_4_7;
break;
case CR_4_8:
case 8:
newCodingRate = SX1272_CR_4_8;
break;
default:
return(ERR_INVALID_CODING_RATE);
}
// set mode to SLEEP
status = setMode(SX1272_SLEEP);
if((freq < 137.0) || (freq > 525.0)) {
return(ERR_INVALID_FREQUENCY);
}
// execute common part
status = SX1272::configCommon(newBandwidth, newSpreadingFactor, newCodingRate, freq, syncWord);
if(status != ERR_NONE) {
return(status);
}
// set LoRa mode
status = _mod->SPIsetRegValue(SX1272_REG_OP_MODE, SX1272_LORA, 7, 7);
if(status != ERR_NONE) {
return(status);
}
// configuration successful, save the new settings
_bw = bw;
_sf = sf;
_cr = cr;
_freq = freq;
// set carrier frequency
status = _mod->SPIsetRegValue(SX1272_REG_FRF_MSB, SX1272_FRF_MSB);
status = _mod->SPIsetRegValue(SX1272_REG_FRF_MID, SX1272_FRF_MID);
status = _mod->SPIsetRegValue(SX1272_REG_FRF_LSB, SX1272_FRF_LSB);
return(ERR_NONE);
}
uint8_t SX1272::configCommon(uint8_t bw, uint8_t sf, uint8_t cr, float freq, uint8_t syncWord) {
// configure common registers
uint8_t status = SX127x::config(bw, sf, cr, freq, syncWord);
if(status != ERR_NONE) {
return(status);
}
// output power configuration
status = _mod->SPIsetRegValue(SX1272_REG_PA_CONFIG, SX1272_PA_SELECT_BOOST | SX1272_OUTPUT_POWER);
status = _mod->SPIsetRegValue(SX1272_REG_OCP, SX1272_OCP_ON | SX1272_OCP_TRIM, 5, 0);
status = _mod->SPIsetRegValue(SX1272_REG_LNA, SX1272_LNA_GAIN_1 | SX1272_LNA_BOOST_ON);
status = _mod->SPIsetRegValue(SX1272_REG_PA_DAC, SX1272_PA_BOOST_ON, 2, 0);
status = _mod->SPIsetRegValue(SX1272_REG_PA_DAC, SX127X_PA_BOOST_ON, 2, 0);
if(status != ERR_NONE) {
return(status);
}
// turn off frequency hopping
status = _mod->SPIsetRegValue(SX1272_REG_HOP_PERIOD, SX1272_HOP_PERIOD_OFF);
// enable LNA gain setting by register
status = _mod->SPIsetRegValue(SX127X_REG_MODEM_CONFIG_2, SX1272_AGC_AUTO_OFF, 2, 2);
if(status != ERR_NONE) {
return(status);
}
// basic setting (bw, cr, sf, header mode and CRC)
if(newSpreadingFactor == SX1272_SF_6) {
status = _mod->SPIsetRegValue(SX1272_REG_MODEM_CONFIG_2, SX1272_SF_6 | SX1272_TX_MODE_SINGLE | SX1272_RX_CRC_MODE_OFF, 7, 2);
status = _mod->SPIsetRegValue(SX1272_REG_MODEM_CONFIG_1, newBandwidth | newCodingRate | SX1272_HEADER_IMPL_MODE);
status = _mod->SPIsetRegValue(SX1272_REG_DETECT_OPTIMIZE, SX1272_DETECT_OPTIMIZE_SF_6, 2, 0);
status = _mod->SPIsetRegValue(SX1272_REG_DETECTION_THRESHOLD, SX1272_DETECTION_THRESHOLD_SF_6);
// set SF6 optimizations
if(sf == SX127X_SF_6) {
status = _mod->SPIsetRegValue(SX127X_REG_MODEM_CONFIG_1, bw | cr | SX1272_HEADER_IMPL_MODE | SX1272_RX_CRC_MODE_OFF, 7, 1);
} else {
status = _mod->SPIsetRegValue(SX1272_REG_MODEM_CONFIG_2, newSpreadingFactor | SX1272_TX_MODE_SINGLE | SX1272_RX_CRC_MODE_ON, 7, 2);
status = _mod->SPIsetRegValue(SX1272_REG_MODEM_CONFIG_1, newBandwidth | newCodingRate | SX1272_HEADER_EXPL_MODE);
status = _mod->SPIsetRegValue(SX1272_REG_DETECT_OPTIMIZE, SX1272_DETECT_OPTIMIZE_SF_7_12, 2, 0);
status = _mod->SPIsetRegValue(SX1272_REG_DETECTION_THRESHOLD, SX1272_DETECTION_THRESHOLD_SF_7_12);
status = _mod->SPIsetRegValue(SX127X_REG_MODEM_CONFIG_1, bw | cr | SX1272_HEADER_EXPL_MODE | SX1272_RX_CRC_MODE_ON, 7, 1);
}
if(status != ERR_NONE) {
return(status);
}
// set default preamble length
status = _mod->SPIsetRegValue(SX1272_REG_PREAMBLE_MSB, SX1272_PREAMBLE_LENGTH_MSB);
status = _mod->SPIsetRegValue(SX1272_REG_PREAMBLE_LSB, SX1272_PREAMBLE_LENGTH_LSB);
// calculate symbol length and set low datarate optimization, if needed
uint16_t base = 1;
float symbolLength = (float)(base << _sf) / (float)_bw;
if(symbolLength >= 0.016) {
status = _mod->SPIsetRegValue(SX127X_REG_MODEM_CONFIG_1, SX1272_LOW_DATA_RATE_OPT_ON, 0, 0);
} else {
status = _mod->SPIsetRegValue(SX127X_REG_MODEM_CONFIG_1, SX1272_LOW_DATA_RATE_OPT_OFF, 0, 0);
}
if(status != ERR_NONE) {
return(status);
}
// set mode to STANDBY
status = setMode(SX1272_STANDBY);
if(status != ERR_NONE) {
return(status);
}
// save the new settings
_bw = bw;
_sf = sf;
_cr = cr;
return(ERR_NONE);
}
uint8_t SX1272::setMode(uint8_t mode) {
_mod->SPIsetRegValue(SX1272_REG_OP_MODE, mode, 2, 0);
return(ERR_NONE);
}
void SX1272::clearIRQFlags() {
_mod->SPIwriteRegister(SX1272_REG_IRQ_FLAGS, 0b11111111);
}
int8_t SX1272::getLastPacketRSSI() {
return(-164 + _mod->SPIgetRegValue(SX1272_REG_PKT_RSSI_VALUE));
return(status);
}

View file

@ -1,58 +1,11 @@
#ifndef _KITELIB_SX1272_H
#define _KITELIB_SX1272_H
#include <EEPROM.h>
#include "TypeDef.h"
#include "Module.h"
#include "Packet.h"
#include "SX127x.h"
//SX1272 register map
#define SX1272_REG_FIFO 0x00
#define SX1272_REG_OP_MODE 0x01
#define SX1272_REG_FRF_MSB 0x06
#define SX1272_REG_FRF_MID 0x07
#define SX1272_REG_FRF_LSB 0x08
#define SX1272_REG_PA_CONFIG 0x09
#define SX1272_REG_PA_RAMP 0x0A
#define SX1272_REG_OCP 0x0B
#define SX1272_REG_LNA 0x0C
#define SX1272_REG_FIFO_ADDR_PTR 0x0D
#define SX1272_REG_FIFO_TX_BASE_ADDR 0x0E
#define SX1272_REG_FIFO_RX_BASE_ADDR 0x0F
#define SX1272_REG_FIFO_RX_CURRENT_ADDR 0x10
#define SX1272_REG_IRQ_FLAGS_MASK 0x11
#define SX1272_REG_IRQ_FLAGS 0x12
#define SX1272_REG_RX_NB_BYTES 0x13
#define SX1272_REG_RX_HEADER_CNT_VALUE_MSB 0x14
#define SX1272_REG_RX_HEADER_CNT_VALUE_LSB 0x15
#define SX1272_REG_RX_PACKET_CNT_VALUE_MSB 0x16
#define SX1272_REG_RX_PACKET_CNT_VALUE_LSB 0x17
#define SX1272_REG_MODEM_STAT 0x18
#define SX1272_REG_PKT_SNR_VALUE 0x19
#define SX1272_REG_PKT_RSSI_VALUE 0x1A
#define SX1272_REG_RSSI_VALUE 0x1B
#define SX1272_REG_HOP_CHANNEL 0x1C
#define SX1272_REG_MODEM_CONFIG_1 0x1D
#define SX1272_REG_MODEM_CONFIG_2 0x1E
#define SX1272_REG_SYMB_TIMEOUT_LSB 0x1F
#define SX1272_REG_PREAMBLE_MSB 0x20
#define SX1272_REG_PREAMBLE_LSB 0x21
#define SX1272_REG_PAYLOAD_LENGTH 0x22
#define SX1272_REG_MAX_PAYLOAD_LENGTH 0x23
#define SX1272_REG_HOP_PERIOD 0x24
#define SX1272_REG_FIFO_RX_BYTE_ADDR 0x25
#define SX1272_REG_FEI_MSB 0x28
#define SX1272_REG_FEI_MID 0x29
#define SX1272_REG_FEI_LSB 0x2A
#define SX1272_REG_RSSI_WIDEBAND 0x2C
#define SX1272_REG_DETECT_OPTIMIZE 0x31
#define SX1272_REG_INVERT_IQ 0x33
#define SX1272_REG_DETECTION_THRESHOLD 0x37
#define SX1272_REG_SYNC_WORD 0x39
#define SX1272_REG_DIO_MAPPING_1 0x40
#define SX1272_REG_DIO_MAPPING_2 0x41
#define SX1272_REG_VERSION 0x42
//SX1272 specific register map
#define SX1272_REG_AGC_REF 0x43
#define SX1272_REG_AGC_THRESH_1 0x44
#define SX1272_REG_AGC_THRESH_2 0x45
@ -66,47 +19,11 @@
#define SX1272_REG_BIT_RATE_FRAC 0x70
//SX1272 LoRa modem settings
//SX1272_REG_OP_MODE MSB LSB DESCRIPTION
#define SX1272_FSK_OOK 0b00000000 // 7 7 FSK/OOK mode
#define SX1272_LORA 0b10000000 // 7 7 LoRa mode
#define SX1272_ACCESS_SHARED_REG_OFF 0b00000000 // 6 6 access LoRa registers (0x0D:0x3F) in LoRa mode
#define SX1272_ACCESS_SHARED_REG_ON 0b01000000 // 6 6 access FSK registers (0x0D:0x3F) in LoRa mode
#define SX1272_SLEEP 0b00000000 // 2 0 sleep
#define SX1272_STANDBY 0b00000001 // 2 0 standby
#define SX1272_FSTX 0b00000010 // 2 0 frequency synthesis TX
#define SX1272_TX 0b00000011 // 2 0 transmit
#define SX1272_FSRX 0b00000100 // 2 0 frequency synthesis RX
#define SX1272_RXCONTINUOUS 0b00000101 // 2 0 receive continuous
#define SX1272_RXSINGLE 0b00000110 // 2 0 receive single
#define SX1272_CAD 0b00000111 // 2 0 channel activity detection
//SX1272_REG_FRF_MSB + REG_FRF_MID + REG_FRF_LSB
#define SX1272_FRF_MSB 0xE4 // 7 0 carrier frequency setting: f_RF = (F(XOSC) * FRF)/2^19
#define SX1272_FRF_MID 0xC0 // 7 0 where F(XOSC) = 32 MHz
#define SX1272_FRF_LSB 0x00 // 7 0 FRF = 3 byte value of FRF registers
//SX1272_REG_PA_CONFIG
#define SX1272_PA_SELECT_RFO 0b00000000 // 7 7 RFIO pin output, power limited to +13 dBm
#define SX1272_PA_SELECT_BOOST 0b10000000 // 7 7 PA_BOOST pin output, power limited to +20 dBm
#define SX1272_OUTPUT_POWER 0b00001111 // 3 0 output power: P_out = -1 + OUTPUT_POWER [dBm] for PA_SELECT_BOOST
//SX1272_REG_OCP
#define SX1272_OCP_OFF 0b00000000 // 5 5 PA overload current protection disabled
#define SX1272_OCP_ON 0b00100000 // 5 5 PA overload current protection enabled
#define SX1272_OCP_TRIM 0b00001011 // 4 0 OCP current: I_max(OCP_TRIM = 0b1011) = 100 mA
//SX1272_REG_LNA
#define SX1272_LNA_GAIN_0 0b00000000 // 7 5 LNA gain setting: not used
#define SX1272_LNA_GAIN_1 0b00100000 // 7 5 max gain
#define SX1272_LNA_GAIN_2 0b01000000 // 7 5 .
#define SX1272_LNA_GAIN_3 0b01100000 // 7 5 .
#define SX1272_LNA_GAIN_4 0b10000000 // 7 5 .
#define SX1272_LNA_GAIN_5 0b10100000 // 7 5 .
#define SX1272_LNA_GAIN_6 0b11000000 // 7 5 min gain
#define SX1272_LNA_GAIN_7 0b11100000 // 7 5 not used
#define SX1272_LNA_BOOST_OFF 0b00000000 // 1 0 default LNA current
#define SX1272_LNA_BOOST_ON 0b00000011 // 1 0 150% LNA current
//SX1272_REG_MODEM_CONFIG_1
#define SX1272_BW_125_00_KHZ 0b00000000 // 7 6 bandwidth: 125 kHz
#define SX1272_BW_250_00_KHZ 0b01000000 // 7 6 250 kHz
@ -123,109 +40,25 @@
#define SX1272_LOW_DATA_RATE_OPT_ON 0b00000001 // 0 0 low data rate optimization enabled, mandatory for SF 11 and 12 with BW 125 kHz
//SX1272_REG_MODEM_CONFIG_2
#define SX1272_SF_6 0b01100000 // 7 4 spreading factor: 64 chips/bit
#define SX1272_SF_7 0b01110000 // 7 4 128 chips/bit
#define SX1272_SF_8 0b10000000 // 7 4 256 chips/bit
#define SX1272_SF_9 0b10010000 // 7 4 512 chips/bit
#define SX1272_SF_10 0b10100000 // 7 4 1024 chips/bit
#define SX1272_SF_11 0b10110000 // 7 4 2048 chips/bit
#define SX1272_SF_12 0b11000000 // 7 4 4096 chips/bit
#define SX1272_TX_MODE_SINGLE 0b00000000 // 3 3 single TX
#define SX1272_TX_MODE_CONT 0b00001000 // 3 3 continuous TX
#define SX1272_AGC_AUTO_OFF 0b00000000 // 2 2 LNA gain set by REG_LNA
#define SX1272_AGC_AUTO_ON 0b00000100 // 2 2 LNA gain set by internal AGC loop
#define SX1272_RX_TIMEOUT_MSB 0b00000000 // 1 0
//SX1272_REG_SYMB_TIMEOUT_LSB
#define SX1272_RX_TIMEOUT_LSB 0b01100100 // 7 0 10 bit RX operation timeout
//SX1272_REG_PREAMBLE_MSB + REG_PREAMBLE_LSB
#define SX1272_PREAMBLE_LENGTH_MSB 0b00000000 // 7 0 2 byte preamble length setting: l_P = PREAMBLE_LENGTH + 4.25
#define SX1272_PREAMBLE_LENGTH_LSB 0b00001000 // 7 0 where l_p = preamble length
//SX1272_REG_DETECT_OPTIMIZE
#define SX1272_DETECT_OPTIMIZE_SF_6 0b00000101 // 2 0 SF6 detection optimization
#define SX1272_DETECT_OPTIMIZE_SF_7_12 0b00000011 // 2 0 SF7 to SF12 detection optimization
//SX1272_REG_DETECTION_THRESHOLD
#define SX1272_DETECTION_THRESHOLD_SF_6 0b00001100 // 7 0 SF6 detection threshold
#define SX1272_DETECTION_THRESHOLD_SF_7_12 0b00001010 // 7 0 SF7 to SF12 detection threshold
//SX1272_REG_PA_DAC
#define SX1272_PA_BOOST_OFF 0b00000100 // 2 0 PA_BOOST disabled
#define SX1272_PA_BOOST_ON 0b00000111 // 2 0 +20 dBm on PA_BOOST when OUTPUT_POWER = 0b1111
//SX1272_REG_HOP_PERIOD
#define SX1272_HOP_PERIOD_OFF 0b00000000 // 7 0 number of periods between frequency hops; 0 = disabled
#define SX1272_HOP_PERIOD_MAX 0b11111111 // 7 0
//SX1272_REG_DIO_MAPPING_1
#define SX1272_DIO0_RX_DONE 0b00000000 // 7 6
#define SX1272_DIO0_TX_DONE 0b01000000 // 7 6
#define SX1272_DIO0_CAD_DONE 0b10000000 // 7 6
#define SX1272_DIO1_RX_TIMEOUT 0b00000000 // 5 4
#define SX1272_DIO1_FHSS_CHANGE_CHANNEL 0b00010000 // 5 4
#define SX1272_DIO1_CAD_DETECTED 0b00100000 // 5 4
//SX1272_REG_IRQ_FLAGS
#define SX1272_CLEAR_IRQ_FLAG_RX_TIMEOUT 0b10000000 // 7 7 timeout
#define SX1272_CLEAR_IRQ_FLAG_RX_DONE 0b01000000 // 6 6 packet reception complete
#define SX1272_CLEAR_IRQ_FLAG_PAYLOAD_CRC_ERROR 0b00100000 // 5 5 payload CRC error
#define SX1272_CLEAR_IRQ_FLAG_VALID_HEADER 0b00010000 // 4 4 valid header received
#define SX1272_CLEAR_IRQ_FLAG_TX_DONE 0b00001000 // 3 3 payload transmission complete
#define SX1272_CLEAR_IRQ_FLAG_CAD_DONE 0b00000100 // 2 2 CAD complete
#define SX1272_CLEAR_IRQ_FLAG_FHSS_CHANGE_CHANNEL 0b00000010 // 1 1 FHSS change channel
#define SX1272_CLEAR_IRQ_FLAG_CAD_DETECTED 0b00000001 // 0 0 valid LoRa signal detected during CAD operation
//SX1272_REG_IRQ_FLAGS_MASK
#define SX1272_MASK_IRQ_FLAG_RX_TIMEOUT 0b01111111 // 7 7 timeout
#define SX1272_MASK_IRQ_FLAG_RX_DONE 0b10111111 // 6 6 packet reception complete
#define SX1272_MASK_IRQ_FLAG_PAYLOAD_CRC_ERROR 0b11011111 // 5 5 payload CRC error
#define SX1272_MASK_IRQ_FLAG_VALID_HEADER 0b11101111 // 4 4 valid header received
#define SX1272_MASK_IRQ_FLAG_TX_DONE 0b11110111 // 3 3 payload transmission complete
#define SX1272_MASK_IRQ_FLAG_CAD_DONE 0b11111011 // 2 2 CAD complete
#define SX1272_MASK_IRQ_FLAG_FHSS_CHANGE_CHANNEL 0b11111101 // 1 1 FHSS change channel
#define SX1272_MASK_IRQ_FLAG_CAD_DETECTED 0b11111110 // 0 0 valid LoRa signal detected during CAD operation
//SX1272_REG_FIFO_TX_BASE_ADDR
#define SX1272_FIFO_TX_BASE_ADDR_MAX 0b00000000 // 7 0 allocate the entire FIFO buffer for TX only
//SX1272_REG_FIFO_RX_BASE_ADDR
#define SX1272_FIFO_RX_BASE_ADDR_MAX 0b00000000 // 7 0 allocate the entire FIFO buffer for RX only
class SX1272 {
class SX1272: public SX127x {
public:
SX1272(Module* module);
SX1272(Module* mod);
float dataRate;
int8_t lastPacketRSSI;
uint8_t begin(float freq = 434.0, uint32_t bw = 125000, uint8_t sf = 9, uint8_t cr = 7, uint8_t syncWord = SX127X_SYNC_WORD, uint16_t addrEeprom = 0);
uint8_t begin(Bandwidth bw = BW_125_00_KHZ, SpreadingFactor sf = SF_9, CodingRate cr = CR_4_7, uint16_t addrEeprom = 0);
uint8_t transmit(Packet& pack);
uint8_t receive(Packet& pack);
uint8_t sleep();
uint8_t standby();
uint8_t setBandwidth(Bandwidth bw);
uint8_t setSpreadingFactor(SpreadingFactor sf);
uint8_t setCodingRate(CodingRate cr);
uint8_t setBandwidth(uint32_t bw);
uint8_t setSpreadingFactor(uint8_t sf);
uint8_t setCodingRate(uint8_t cr);
protected:
uint8_t configCommon(uint8_t bw, uint8_t sf, uint8_t cr, float freq, uint8_t syncWord); // common for SX1272/73
private:
Module* _mod;
uint8_t config(float freq, uint32_t bw, uint8_t sf, uint8_t cr, uint8_t syncWord); // specific to SX1272
Bandwidth _bw;
SpreadingFactor _sf;
CodingRate _cr;
uint8_t _address[8] = {0, 0, 0, 0, 0, 0, 0, 0};
uint16_t _addrEeprom;
void generateLoRaAdress();
uint8_t config(Bandwidth bw, SpreadingFactor sf, CodingRate cr);
uint8_t setMode(uint8_t mode);
void clearIRQFlags();
int8_t getLastPacketRSSI();
};
#endif

76
src/modules/SX1273.cpp Normal file
View file

@ -0,0 +1,76 @@
#include "SX1273.h"
SX1273::SX1273(Module* mod) : SX1272(mod) {
}
uint8_t SX1273::config(uint32_t bw, uint8_t sf, uint8_t cr, float freq, uint8_t syncWord) {
uint8_t status = ERR_NONE;
uint8_t newBandwidth, newSpreadingFactor, newCodingRate;
// check the supplied BW, CR and SF values
switch(bw) {
case 125000:
newBandwidth = SX1272_BW_125_00_KHZ;
break;
case 250000:
newBandwidth = SX1272_BW_250_00_KHZ;
break;
case 500000:
newBandwidth = SX1272_BW_500_00_KHZ;
break;
default:
return(ERR_INVALID_BANDWIDTH);
}
switch(sf) {
case 6:
newSpreadingFactor = SX127X_SF_6;
break;
case 7:
newSpreadingFactor = SX127X_SF_7;
break;
case 8:
newSpreadingFactor = SX127X_SF_8;
break;
case 9:
newSpreadingFactor = SX127X_SF_9;
break;
default:
return(ERR_INVALID_SPREADING_FACTOR);
}
switch(cr) {
case 5:
newCodingRate = SX1272_CR_4_5;
break;
case 6:
newCodingRate = SX1272_CR_4_6;
break;
case 7:
newCodingRate = SX1272_CR_4_7;
break;
case 8:
newCodingRate = SX1272_CR_4_8;
break;
default:
return(ERR_INVALID_CODING_RATE);
}
if((freq < 860.0) || (freq > 1020.0)) {
return(ERR_INVALID_FREQUENCY);
}
// execute common part
status = configCommon(newBandwidth, newSpreadingFactor, newCodingRate, freq, syncWord);
if(status != ERR_NONE) {
return(status);
}
// configuration successful, save the new settings
_bw = bw;
_sf = sf;
_cr = cr;
return(ERR_NONE);
}

15
src/modules/SX1273.h Normal file
View file

@ -0,0 +1,15 @@
#ifndef _KITELIB_SX1273_H
#define _KITELIB_SX1273_H
#include "TypeDef.h"
#include "SX1272.h"
class SX1273: public SX1272 {
public:
SX1273(Module* mod);
private:
uint8_t config(uint32_t bw, uint8_t sf, uint8_t cr, float freq, uint8_t syncWord);
};
#endif

85
src/modules/SX1276.cpp Normal file
View file

@ -0,0 +1,85 @@
#include "SX1276.h"
SX1276::SX1276(Module* mod) : SX1278(mod) {
}
uint8_t SX1276::config(uint32_t bw, uint8_t sf, uint8_t cr, float freq, uint8_t syncWord) {
uint8_t status = ERR_NONE;
uint8_t newBandwidth, newSpreadingFactor, newCodingRate;
// check the supplied BW, CR and SF values
switch(bw) {
case 125000:
newBandwidth = SX1278_BW_125_00_KHZ;
break;
case 250000:
newBandwidth = SX1278_BW_250_00_KHZ;
break;
case 500000:
newBandwidth = SX1278_BW_500_00_KHZ;
break;
default:
return(ERR_INVALID_BANDWIDTH);
}
switch(sf) {
case 6:
newSpreadingFactor = SX127X_SF_6;
break;
case 7:
newSpreadingFactor = SX127X_SF_7;
break;
case 8:
newSpreadingFactor = SX127X_SF_8;
break;
case 9:
newSpreadingFactor = SX127X_SF_9;
break;
case 10:
newSpreadingFactor = SX127X_SF_10;
break;
case 11:
newSpreadingFactor = SX127X_SF_11;
break;
case 12:
newSpreadingFactor = SX127X_SF_12;
break;
default:
return(ERR_INVALID_SPREADING_FACTOR);
}
switch(cr) {
case 5:
newCodingRate = SX1278_CR_4_5;
break;
case 6:
newCodingRate = SX1278_CR_4_6;
break;
case 7:
newCodingRate = SX1278_CR_4_7;
break;
case 8:
newCodingRate = SX1278_CR_4_8;
break;
default:
return(ERR_INVALID_CODING_RATE);
}
if((freq < 137.0) || (freq > 1020.0)) {
return(ERR_INVALID_FREQUENCY);
}
// execute common part
status = configCommon(newBandwidth, newSpreadingFactor, newCodingRate, freq, syncWord);
if(status != ERR_NONE) {
return(status);
}
// configuration successful, save the new settings
_bw = bw;
_sf = sf;
_cr = cr;
return(ERR_NONE);
}

15
src/modules/SX1276.h Normal file
View file

@ -0,0 +1,15 @@
#ifndef _KITELIB_SX1276_H
#define _KITELIB_SX1276_H
#include "TypeDef.h"
#include "SX1278.h"
class SX1276: public SX1278 {
public:
SX1276(Module* mod);
private:
uint8_t config(uint32_t bw, uint8_t sf, uint8_t cr, float freq, uint8_t syncWord);
};
#endif

76
src/modules/SX1277.cpp Normal file
View file

@ -0,0 +1,76 @@
#include "SX1277.h"
SX1277::SX1277(Module* mod) : SX1278(mod) {
}
uint8_t SX1277::config(uint32_t bw, uint8_t sf, uint8_t cr, float freq, uint8_t syncWord) {
uint8_t status = ERR_NONE;
uint8_t newBandwidth, newSpreadingFactor, newCodingRate;
// check the supplied BW, CR and SF values
switch(bw) {
case 125000:
newBandwidth = SX1278_BW_125_00_KHZ;
break;
case 250000:
newBandwidth = SX1278_BW_250_00_KHZ;
break;
case 500000:
newBandwidth = SX1278_BW_500_00_KHZ;
break;
default:
return(ERR_INVALID_BANDWIDTH);
}
switch(sf) {
case 6:
newSpreadingFactor = SX127X_SF_6;
break;
case 7:
newSpreadingFactor = SX127X_SF_7;
break;
case 8:
newSpreadingFactor = SX127X_SF_8;
break;
case 9:
newSpreadingFactor = SX127X_SF_9;
break;
default:
return(ERR_INVALID_SPREADING_FACTOR);
}
switch(cr) {
case 5:
newCodingRate = SX1278_CR_4_5;
break;
case 6:
newCodingRate = SX1278_CR_4_6;
break;
case 7:
newCodingRate = SX1278_CR_4_7;
break;
case 8:
newCodingRate = SX1278_CR_4_8;
break;
default:
return(ERR_INVALID_CODING_RATE);
}
if((freq < 137.0) || (freq > 1020.0)) {
return(ERR_INVALID_FREQUENCY);
}
// execute common part
status = configCommon(newBandwidth, newSpreadingFactor, newCodingRate, freq, syncWord);
if(status != ERR_NONE) {
return(status);
}
// configuration successful, save the new settings
_bw = bw;
_sf = sf;
_cr = cr;
return(ERR_NONE);
}

15
src/modules/SX1277.h Normal file
View file

@ -0,0 +1,15 @@
#ifndef _KITELIB_SX1277_H
#define _KITELIB_SX1277_H
#include "TypeDef.h"
#include "SX1278.h"
class SX1277: public SX1278 {
public:
SX1277(Module* mod);
private:
uint8_t config(uint32_t bw, uint8_t sf, uint8_t cr, float freq, uint8_t syncWord);
};
#endif

View file

@ -1,280 +1,76 @@
#include "SX1278.h"
SX1278::SX1278(Module* module) {
_mod = module;
SX1278::SX1278(Module* mod) : SX127x(mod) {
}
uint8_t SX1278::begin(Bandwidth bw, SpreadingFactor sf, CodingRate cr, uint16_t addrEeprom) {
// copy LoRa modem settings
_bw = bw;
_sf = sf;
_cr = cr;
// ESP32-only: initialize EEPROM
#ifdef ESP32
if(!EEPROM.begin(9)) {
DEBUG_PRINTLN_STR("Unable to initialize EEPROM");
return(ERR_EEPROM_NOT_INITIALIZED);
}
#endif
// copy EEPROM start address
_addrEeprom = addrEeprom;
// check if the node has address
bool hasAddress = false;
for(uint16_t i = 0; i < 8; i++) {
if(EEPROM.read(_addrEeprom + i) != 255) {
hasAddress = true;
break;
}
uint8_t SX1278::begin(float freq, uint32_t bw, uint8_t sf, uint8_t cr, uint8_t syncWord, uint16_t addrEeprom) {
uint8_t state = SX127x::begin(freq, bw, sf, cr, syncWord, addrEeprom);
if(state != ERR_NONE) {
return(state);
}
// generate new address
if(!hasAddress) {
randomSeed(analogRead(5));
generateLoRaAdress();
}
DEBUG_PRINTLN_STR("LoRa node address string: ");
for(uint8_t i = 0; i < 8; i++) {
_address[i] = EEPROM.read(i);
#ifdef DEBUG
Serial.print(_address[i], HEX);
if(i < 7) {
Serial.print(":");
} else {
Serial.println();
}
#endif
}
// set module properties
_mod->init(USE_SPI, INT_BOTH);
// try to find the SX1278 chip
uint8_t i = 0;
bool flagFound = false;
while((i < 10) && !flagFound) {
uint8_t version = _mod->SPIreadRegister(SX1278_REG_VERSION);
if(version == 0x12) {
flagFound = true;
} else {
#ifdef DEBUG
Serial.print("SX1278 not found! (");
Serial.print(i + 1);
Serial.print(" of 10 tries) SX1278_REG_VERSION == ");
char buffHex[5];
sprintf(buffHex, "0x%02X", version);
Serial.print(buffHex);
Serial.println();
#endif
delay(1000);
i++;
}
}
if(!flagFound) {
DEBUG_PRINTLN_STR("No SX1278 found!");
SPI.end();
return(ERR_CHIP_NOT_FOUND);
} else {
DEBUG_PRINTLN_STR("Found SX1278! (match by SX1278_REG_VERSION == 0x12)");
}
// configure LoRa modem
return(config(_bw, _sf, _cr));
return(config(freq, bw, sf, cr, syncWord));
}
uint8_t SX1278::transmit(Packet& pack) {
char buffer[256];
// copy packet source and destination addresses into buffer
for(uint8_t i = 0; i < 8; i++) {
buffer[i] = pack.source[i];
buffer[i+8] = pack.destination[i];
}
// copy packet data into buffer
for(uint8_t i = 0; i < pack.length; i++) {
buffer[i+16] = pack.data[i];
}
// set mode to standby
setMode(SX1278_STANDBY);
// set DIO pin mapping
_mod->SPIsetRegValue(SX1278_REG_DIO_MAPPING_1, SX1278_DIO0_TX_DONE, 7, 6);
// clear interrupt flags
clearIRQFlags();
// check overall packet length
if(pack.length > 256) {
return(ERR_PACKET_TOO_LONG);
}
// write packet to FIFO
_mod->SPIsetRegValue(SX1278_REG_PAYLOAD_LENGTH, pack.length);
_mod->SPIsetRegValue(SX1278_REG_FIFO_TX_BASE_ADDR, SX1278_FIFO_TX_BASE_ADDR_MAX);
_mod->SPIsetRegValue(SX1278_REG_FIFO_ADDR_PTR, SX1278_FIFO_TX_BASE_ADDR_MAX);
_mod->SPIwriteRegisterBurstStr(SX1278_REG_FIFO, buffer, pack.length);
// set mode to transmit
setMode(SX1278_TX);
// wait for transmission end
unsigned long start = millis();
while(!_mod->getInt0State()) {
DEBUG_PRINT('.');
}
// clear interrupt flags
clearIRQFlags();
return(ERR_NONE);
}
uint8_t SX1278::receive(Packet& pack) {
char buffer[256];
uint32_t startTime = millis();
// set mode to standby
setMode(SX1278_STANDBY);
// set DIO pin mapping
_mod->SPIsetRegValue(SX1278_REG_DIO_MAPPING_1, SX1278_DIO0_RX_DONE | SX1278_DIO1_RX_TIMEOUT, 7, 4);
// clear interrupt flags
clearIRQFlags();
// set FIFO address pointers
_mod->SPIsetRegValue(SX1278_REG_FIFO_RX_BASE_ADDR, SX1278_FIFO_RX_BASE_ADDR_MAX);
_mod->SPIsetRegValue(SX1278_REG_FIFO_ADDR_PTR, SX1278_FIFO_RX_BASE_ADDR_MAX);
// set mode to receive
setMode(SX1278_RXSINGLE);
// wait for packet reception or timeout
while(!_mod->getInt0State()) {
if(_mod->getInt1State()) {
clearIRQFlags();
return(ERR_RX_TIMEOUT);
}
}
// check received packet CRC
if(_mod->SPIgetRegValue(SX1278_REG_IRQ_FLAGS, 5, 5) == SX1278_CLEAR_IRQ_FLAG_PAYLOAD_CRC_ERROR) {
return(ERR_CRC_MISMATCH);
}
// get header type
uint8_t headerMode = _mod->SPIgetRegValue(SX1278_REG_MODEM_CONFIG_1, 0, 0);
if(headerMode == SX1278_HEADER_EXPL_MODE) {
pack.length = _mod->SPIgetRegValue(SX1278_REG_RX_NB_BYTES);
}
// read packet from FIFO
_mod->SPIreadRegisterBurstStr(SX1278_REG_FIFO, pack.length, buffer);
// clear interrupt flags
clearIRQFlags();
// get packet source and destination addresses from buffer
for(uint8_t i = 0; i < 8; i++) {
pack.source[i] = buffer[i];
pack.destination[i] = buffer[i+8];
}
// get packet source and destination addresses from buffer
for(uint8_t i = 16; i < pack.length; i++) {
pack.data[i-16] = buffer[i];
}
pack.data[pack.length-16] = 0;
// measure overall datarate
uint32_t elapsedTime = millis() - startTime;
dataRate = (pack.length*8.0)/((float)elapsedTime/1000.0);
// get packet RSSI
lastPacketRSSI = getLastPacketRSSI();
return(ERR_NONE);
}
uint8_t SX1278::sleep() {
return(setMode(0b00000000));
}
uint8_t SX1278::standby() {
return(setMode(0b00000001));
}
uint8_t SX1278::setBandwidth(Bandwidth bw) {
uint8_t state = config(bw, _sf, _cr);
uint8_t SX1278::setBandwidth(uint32_t bw) {
uint8_t state = SX1278::config(bw, _sf, _cr, _freq, _syncWord);
if(state == ERR_NONE) {
_bw = bw;
}
return(state);
}
uint8_t SX1278::setSpreadingFactor(SpreadingFactor sf) {
uint8_t state = config(_bw, sf, _cr);
uint8_t SX1278::setSpreadingFactor(uint8_t sf) {
uint8_t state = SX1278::config(_bw, sf, _cr, _freq, _syncWord);
if(state == ERR_NONE) {
_sf = sf;
}
return(state);
}
uint8_t SX1278::setCodingRate(CodingRate cr) {
uint8_t state = config(_bw, _sf, cr);
uint8_t SX1278::setCodingRate(uint8_t cr) {
uint8_t state = SX1278::config(_bw, _sf, cr, _freq, _syncWord);
if(state == ERR_NONE) {
_cr = cr;
}
return(state);
}
void SX1278::generateLoRaAdress() {
for(uint8_t i = _addrEeprom; i < (_addrEeprom + 8); i++) {
EEPROM.write(i, (uint8_t)random(0, 256));
}
}
uint8_t SX1278::config(Bandwidth bw, SpreadingFactor sf, CodingRate cr) {
uint8_t SX1278::config(float freq, uint32_t bw, uint8_t sf, uint8_t cr, uint8_t syncWord) {
uint8_t status = ERR_NONE;
uint8_t newBandwidth, newSpreadingFactor, newCodingRate;
//check the supplied bw, cr and sf values
// check the supplied BW, CR and SF values
switch(bw) {
case BW_7_80_KHZ:
case 7800:
newBandwidth = SX1278_BW_7_80_KHZ;
break;
case BW_10_40_KHZ:
case 10400:
newBandwidth = SX1278_BW_10_40_KHZ;
break;
case BW_15_60_KHZ:
case 15600:
newBandwidth = SX1278_BW_15_60_KHZ;
break;
case BW_20_80_KHZ:
case 20800:
newBandwidth = SX1278_BW_20_80_KHZ;
break;
case BW_31_25_KHZ:
case 31250:
newBandwidth = SX1278_BW_31_25_KHZ;
break;
case BW_41_70_KHZ:
case 41700:
newBandwidth = SX1278_BW_41_70_KHZ;
break;
case BW_62_50_KHZ:
case 62500:
newBandwidth = SX1278_BW_62_50_KHZ;
break;
case BW_125_00_KHZ:
case 125000:
newBandwidth = SX1278_BW_125_00_KHZ;
break;
case BW_250_00_KHZ:
case 250000:
newBandwidth = SX1278_BW_250_00_KHZ;
break;
case BW_500_00_KHZ:
case 500000:
newBandwidth = SX1278_BW_500_00_KHZ;
break;
default:
@ -282,130 +78,107 @@ uint8_t SX1278::config(Bandwidth bw, SpreadingFactor sf, CodingRate cr) {
}
switch(sf) {
case SF_6:
newSpreadingFactor = SX1278_SF_6;
case 6:
newSpreadingFactor = SX127X_SF_6;
break;
case SF_7:
newSpreadingFactor = SX1278_SF_7;
case 7:
newSpreadingFactor = SX127X_SF_7;
break;
case SF_8:
newSpreadingFactor = SX1278_SF_8;
case 8:
newSpreadingFactor = SX127X_SF_8;
break;
case SF_9:
newSpreadingFactor = SX1278_SF_9;
case 9:
newSpreadingFactor = SX127X_SF_9;
break;
case SF_10:
newSpreadingFactor = SX1278_SF_10;
case 10:
newSpreadingFactor = SX127X_SF_10;
break;
case SF_11:
newSpreadingFactor = SX1278_SF_11;
case 11:
newSpreadingFactor = SX127X_SF_11;
break;
case SF_12:
newSpreadingFactor = SX1278_SF_12;
case 12:
newSpreadingFactor = SX127X_SF_12;
break;
default:
return(ERR_INVALID_SPREADING_FACTOR);
}
switch(cr) {
case CR_4_5:
case 5:
newCodingRate = SX1278_CR_4_5;
break;
case CR_4_6:
case 6:
newCodingRate = SX1278_CR_4_6;
break;
case CR_4_7:
case 7:
newCodingRate = SX1278_CR_4_7;
break;
case CR_4_8:
case 8:
newCodingRate = SX1278_CR_4_8;
break;
default:
return(ERR_INVALID_CODING_RATE);
}
// set mode to SLEEP
status = setMode(SX1278_SLEEP);
if((freq < 137.0) || (freq > 525.0)) {
return(ERR_INVALID_FREQUENCY);
}
// execute common part
status = SX1278::configCommon(newBandwidth, newSpreadingFactor, newCodingRate, freq, syncWord);
if(status != ERR_NONE) {
return(status);
}
// set LoRa mode
status = _mod->SPIsetRegValue(SX1278_REG_OP_MODE, SX1278_LORA, 7, 7);
if(status != ERR_NONE) {
return(status);
}
// configuration successful, save the new settings
_bw = bw;
_sf = sf;
_cr = cr;
_freq = freq;
// set carrier frequency
status = _mod->SPIsetRegValue(SX1278_REG_FRF_MSB, SX1278_FRF_MSB);
status = _mod->SPIsetRegValue(SX1278_REG_FRF_MID, SX1278_FRF_MID);
status = _mod->SPIsetRegValue(SX1278_REG_FRF_LSB, SX1278_FRF_LSB);
return(ERR_NONE);
}
uint8_t SX1278::configCommon(uint8_t bw, uint8_t sf, uint8_t cr, float freq, uint8_t syncWord) {
// configure common registers
uint8_t status = SX127x::config(bw, sf, cr, freq, syncWord);
if(status != ERR_NONE) {
return(status);
}
// output power configuration
status = _mod->SPIsetRegValue(SX1278_REG_PA_CONFIG, SX1278_PA_SELECT_BOOST | SX1278_MAX_POWER | SX1278_OUTPUT_POWER);
status = _mod->SPIsetRegValue(SX1278_REG_OCP, SX1278_OCP_ON | SX1278_OCP_TRIM, 5, 0);
status = _mod->SPIsetRegValue(SX1278_REG_LNA, SX1278_LNA_GAIN_1 | SX1278_LNA_BOOST_HF_ON);
status = _mod->SPIsetRegValue(SX1278_REG_PA_DAC, SX1278_PA_BOOST_ON, 2, 0);
status = _mod->SPIsetRegValue(SX127X_REG_PA_CONFIG, SX1278_MAX_POWER, 6, 4);
status = _mod->SPIsetRegValue(SX1278_REG_PA_DAC, SX127X_PA_BOOST_ON, 2, 0);
if(status != ERR_NONE) {
return(status);
}
// turn off frequency hopping
status = _mod->SPIsetRegValue(SX1278_REG_HOP_PERIOD, SX1278_HOP_PERIOD_OFF);
// enable LNA gain setting by register
status = _mod->SPIsetRegValue(SX1278_REG_MODEM_CONFIG_3, SX1278_AGC_AUTO_OFF, 2, 2);
if(status != ERR_NONE) {
return(status);
}
// basic setting (bw, cr, sf, header mode and CRC)
if(newSpreadingFactor == SX1278_SF_6) {
status = _mod->SPIsetRegValue(SX1278_REG_MODEM_CONFIG_2, SX1278_SF_6 | SX1278_TX_MODE_SINGLE | SX1278_RX_CRC_MODE_OFF, 7, 2);
status = _mod->SPIsetRegValue(SX1278_REG_MODEM_CONFIG_1, newBandwidth | newCodingRate | SX1278_HEADER_IMPL_MODE);
status = _mod->SPIsetRegValue(SX1278_REG_DETECT_OPTIMIZE, SX1278_DETECT_OPTIMIZE_SF_6, 2, 0);
status = _mod->SPIsetRegValue(SX1278_REG_DETECTION_THRESHOLD, SX1278_DETECTION_THRESHOLD_SF_6);
// calculate symbol length and set low datarate optimization, if needed
uint16_t base = 1;
float symbolLength = (float)(base << _sf) / (float)_bw;
if(symbolLength >= 0.016) {
status = _mod->SPIsetRegValue(SX1278_REG_MODEM_CONFIG_3, SX1278_LOW_DATA_RATE_OPT_ON, 0, 0);
} else {
status = _mod->SPIsetRegValue(SX1278_REG_MODEM_CONFIG_2, newSpreadingFactor | SX1278_TX_MODE_SINGLE | SX1278_RX_CRC_MODE_ON, 7, 2);
status = _mod->SPIsetRegValue(SX1278_REG_MODEM_CONFIG_1, newBandwidth | newCodingRate | SX1278_HEADER_EXPL_MODE);
status = _mod->SPIsetRegValue(SX1278_REG_DETECT_OPTIMIZE, SX1278_DETECT_OPTIMIZE_SF_7_12, 2, 0);
status = _mod->SPIsetRegValue(SX1278_REG_DETECTION_THRESHOLD, SX1278_DETECTION_THRESHOLD_SF_7_12);
status = _mod->SPIsetRegValue(SX1278_REG_MODEM_CONFIG_3, SX1278_LOW_DATA_RATE_OPT_OFF, 0, 0);
}
if(status != ERR_NONE) {
return(status);
}
// set default preamble length
status = _mod->SPIsetRegValue(SX1278_REG_PREAMBLE_MSB, SX1278_PREAMBLE_LENGTH_MSB);
status = _mod->SPIsetRegValue(SX1278_REG_PREAMBLE_LSB, SX1278_PREAMBLE_LENGTH_LSB);
if(status != ERR_NONE) {
return(status);
// set SF6 optimizations
if(sf == SX127X_SF_6) {
status = _mod->SPIsetRegValue(SX127X_REG_MODEM_CONFIG_2, SX1278_RX_CRC_MODE_OFF, 2, 2);
status = _mod->SPIsetRegValue(SX127X_REG_MODEM_CONFIG_1, bw | cr | SX1278_HEADER_IMPL_MODE);
} else {
status = _mod->SPIsetRegValue(SX127X_REG_MODEM_CONFIG_2, SX1278_RX_CRC_MODE_ON, 2, 2);
status = _mod->SPIsetRegValue(SX127X_REG_MODEM_CONFIG_1, bw | cr | SX1278_HEADER_EXPL_MODE);
}
// set mode to STANDBY
status = setMode(SX1278_STANDBY);
if(status != ERR_NONE) {
return(status);
}
// save the new settings
_bw = bw;
_sf = sf;
_cr = cr;
return(ERR_NONE);
}
uint8_t SX1278::setMode(uint8_t mode) {
_mod->SPIsetRegValue(SX1278_REG_OP_MODE, mode, 2, 0);
return(ERR_NONE);
}
void SX1278::clearIRQFlags() {
_mod->SPIwriteRegister(SX1278_REG_IRQ_FLAGS, 0b11111111);
}
int8_t SX1278::getLastPacketRSSI() {
return(-164 + _mod->SPIgetRegValue(SX1278_REG_PKT_RSSI_VALUE));
return(status);
}

View file

@ -1,59 +1,12 @@
#ifndef _KITELIB_SX1278_H
#define _KITELIB_SX1278_H
#include <EEPROM.h>
#include "TypeDef.h"
#include "Module.h"
#include "Packet.h"
#include "SX127x.h"
//SX1278 register map
#define SX1278_REG_FIFO 0x00
#define SX1278_REG_OP_MODE 0x01
#define SX1278_REG_FRF_MSB 0x06
#define SX1278_REG_FRF_MID 0x07
#define SX1278_REG_FRF_LSB 0x08
#define SX1278_REG_PA_CONFIG 0x09
#define SX1278_REG_PA_RAMP 0x0A
#define SX1278_REG_OCP 0x0B
#define SX1278_REG_LNA 0x0C
#define SX1278_REG_FIFO_ADDR_PTR 0x0D
#define SX1278_REG_FIFO_TX_BASE_ADDR 0x0E
#define SX1278_REG_FIFO_RX_BASE_ADDR 0x0F
#define SX1278_REG_FIFO_RX_CURRENT_ADDR 0x10
#define SX1278_REG_IRQ_FLAGS_MASK 0x11
#define SX1278_REG_IRQ_FLAGS 0x12
#define SX1278_REG_RX_NB_BYTES 0x13
#define SX1278_REG_RX_HEADER_CNT_VALUE_MSB 0x14
#define SX1278_REG_RX_HEADER_CNT_VALUE_LSB 0x15
#define SX1278_REG_RX_PACKET_CNT_VALUE_MSB 0x16
#define SX1278_REG_RX_PACKET_CNT_VALUE_LSB 0x17
#define SX1278_REG_MODEM_STAT 0x18
#define SX1278_REG_PKT_SNR_VALUE 0x19
#define SX1278_REG_PKT_RSSI_VALUE 0x1A
#define SX1278_REG_RSSI_VALUE 0x1B
#define SX1278_REG_HOP_CHANNEL 0x1C
#define SX1278_REG_MODEM_CONFIG_1 0x1D
#define SX1278_REG_MODEM_CONFIG_2 0x1E
#define SX1278_REG_SYMB_TIMEOUT_LSB 0x1F
#define SX1278_REG_PREAMBLE_MSB 0x20
#define SX1278_REG_PREAMBLE_LSB 0x21
#define SX1278_REG_PAYLOAD_LENGTH 0x22
#define SX1278_REG_MAX_PAYLOAD_LENGTH 0x23
#define SX1278_REG_HOP_PERIOD 0x24
#define SX1278_REG_FIFO_RX_BYTE_ADDR 0x25
//SX1278 specific register map
#define SX1278_REG_MODEM_CONFIG_3 0x26
#define SX1278_REG_FEI_MSB 0x28
#define SX1278_REG_FEI_MID 0x29
#define SX1278_REG_FEI_LSB 0x2A
#define SX1278_REG_RSSI_WIDEBAND 0x2C
#define SX1278_REG_DETECT_OPTIMIZE 0x31
#define SX1278_REG_INVERT_IQ 0x33
#define SX1278_REG_DETECTION_THRESHOLD 0x37
#define SX1278_REG_SYNC_WORD 0x39
#define SX1278_REG_DIO_MAPPING_1 0x40
#define SX1278_REG_DIO_MAPPING_2 0x41
#define SX1278_REG_VERSION 0x42
#define SX1278_REG_TCXO 0x4B
#define SX1278_REG_PA_DAC 0x4D
#define SX1278_REG_FORMER_TEMP 0x5D
@ -65,20 +18,8 @@
//SX1278 LoRa modem settings
//SX1278_REG_OP_MODE MSB LSB DESCRIPTION
#define SX1278_FSK_OOK 0b00000000 // 7 7 FSK/OOK mode
#define SX1278_LORA 0b10000000 // 7 7 LoRa mode
#define SX1278_ACCESS_SHARED_REG_OFF 0b00000000 // 6 6 access LoRa registers (0x0D:0x3F) in LoRa mode
#define SX1278_ACCESS_SHARED_REG_ON 0b01000000 // 6 6 access FSK registers (0x0D:0x3F) in LoRa mode
#define SX1278_HIGH_FREQ 0b00000000 // 3 3 access HF test registers
#define SX1278_LOW_FREQ 0b00001000 // 3 3 access LF test registers
#define SX1278_SLEEP 0b00000000 // 2 0 sleep
#define SX1278_STANDBY 0b00000001 // 2 0 standby
#define SX1278_FSTX 0b00000010 // 2 0 frequency synthesis TX
#define SX1278_TX 0b00000011 // 2 0 transmit
#define SX1278_FSRX 0b00000100 // 2 0 frequency synthesis RX
#define SX1278_RXCONTINUOUS 0b00000101 // 2 0 receive continuous
#define SX1278_RXSINGLE 0b00000110 // 2 0 receive single
#define SX1278_CAD 0b00000111 // 2 0 channel activity detection
//SX1278_REG_FRF_MSB + REG_FRF_MID + REG_FRF_LSB
#define SX1278_FRF_MSB 0x6C // 7 0 carrier frequency setting: f_RF = (F(XOSC) * FRF)/2^19
@ -86,28 +27,10 @@
#define SX1278_FRF_LSB 0x00 // 7 0 FRF = 3 byte value of FRF registers
//SX1278_REG_PA_CONFIG
#define SX1278_PA_SELECT_RFO 0b00000000 // 7 7 RFO pin output, power limited to +14 dBm
#define SX1278_PA_SELECT_BOOST 0b10000000 // 7 7 PA_BOOST pin output, power limited to +20 dBm
#define SX1278_MAX_POWER 0b01110000 // 6 4 max power: P_max = 10.8 + 0.6*MAX_POWER [dBm]; P_max(MAX_POWER = 0b111) = 15 dBm
#define SX1278_OUTPUT_POWER 0b00001111 // 3 0 output power: P_out = 17 - (15 - OUTPUT_POWER) [dBm] for PA_SELECT_BOOST
//SX1278_REG_OCP
#define SX1278_OCP_OFF 0b00000000 // 5 5 PA overload current protection disabled
#define SX1278_OCP_ON 0b00100000 // 5 5 PA overload current protection enabled
#define SX1278_OCP_TRIM 0b00001011 // 4 0 OCP current: I_max(OCP_TRIM = 0b1011) = 100 mA
//SX1278_REG_LNA
#define SX1278_LNA_GAIN_0 0b00000000 // 7 5 LNA gain setting: not used
#define SX1278_LNA_GAIN_1 0b00100000 // 7 5 max gain
#define SX1278_LNA_GAIN_2 0b01000000 // 7 5 .
#define SX1278_LNA_GAIN_3 0b01100000 // 7 5 .
#define SX1278_LNA_GAIN_4 0b10000000 // 7 5 .
#define SX1278_LNA_GAIN_5 0b10100000 // 7 5 .
#define SX1278_LNA_GAIN_6 0b11000000 // 7 5 min gain
#define SX1278_LNA_GAIN_7 0b11100000 // 7 5 not used
#define SX1278_LNA_BOOST_LF_OFF 0b00000000 // 4 3 default LNA current
#define SX1278_LNA_BOOST_HF_OFF 0b00000000 // 1 0 default LNA current
#define SX1278_LNA_BOOST_HF_ON 0b00000011 // 1 0 150% LNA current
//SX1278_REG_MODEM_CONFIG_1
#define SX1278_BW_7_80_KHZ 0b00000000 // 7 4 bandwidth: 7.80 kHz
@ -128,25 +51,8 @@
#define SX1278_HEADER_IMPL_MODE 0b00000001 // 0 0 implicit header mode
//SX1278_REG_MODEM_CONFIG_2
#define SX1278_SF_6 0b01100000 // 7 4 spreading factor: 64 chips/bit
#define SX1278_SF_7 0b01110000 // 7 4 128 chips/bit
#define SX1278_SF_8 0b10000000 // 7 4 256 chips/bit
#define SX1278_SF_9 0b10010000 // 7 4 512 chips/bit
#define SX1278_SF_10 0b10100000 // 7 4 1024 chips/bit
#define SX1278_SF_11 0b10110000 // 7 4 2048 chips/bit
#define SX1278_SF_12 0b11000000 // 7 4 4096 chips/bit
#define SX1278_TX_MODE_SINGLE 0b00000000 // 3 3 single TX
#define SX1278_TX_MODE_CONT 0b00001000 // 3 3 continuous TX
#define SX1278_RX_CRC_MODE_OFF 0b00000000 // 2 2 CRC disabled
#define SX1278_RX_CRC_MODE_ON 0b00000100 // 2 2 CRC enabled
#define SX1278_RX_TIMEOUT_MSB 0b00000000 // 1 0
//SX1278_REG_SYMB_TIMEOUT_LSB
#define SX1278_RX_TIMEOUT_LSB 0b01100100 // 7 0 10 bit RX operation timeout
//SX1278_REG_PREAMBLE_MSB + REG_PREAMBLE_LSB
#define SX1278_PREAMBLE_LENGTH_MSB 0b00000000 // 7 0 2 byte preamble length setting: l_P = PREAMBLE_LENGTH + 4.25
#define SX1278_PREAMBLE_LENGTH_LSB 0b00001000 // 7 0 where l_p = preamble length
//SX1278_REG_MODEM_CONFIG_3
#define SX1278_LOW_DATA_RATE_OPT_OFF 0b00000000 // 3 3 low data rate optimization disabled
@ -154,89 +60,21 @@
#define SX1278_AGC_AUTO_OFF 0b00000000 // 2 2 LNA gain set by REG_LNA
#define SX1278_AGC_AUTO_ON 0b00000100 // 2 2 LNA gain set by internal AGC loop
//SX1278_REG_DETECT_OPTIMIZE
#define SX1278_DETECT_OPTIMIZE_SF_6 0b00000101 // 2 0 SF6 detection optimization
#define SX1278_DETECT_OPTIMIZE_SF_7_12 0b00000011 // 2 0 SF7 to SF12 detection optimization
//SX1278_REG_DETECTION_THRESHOLD
#define SX1278_DETECTION_THRESHOLD_SF_6 0b00001100 // 7 0 SF6 detection threshold
#define SX1278_DETECTION_THRESHOLD_SF_7_12 0b00001010 // 7 0 SF7 to SF12 detection threshold
//SX1278_REG_PA_DAC
#define SX1278_PA_BOOST_OFF 0b00000100 // 2 0 PA_BOOST disabled
#define SX1278_PA_BOOST_ON 0b00000111 // 2 0 +20 dBm on PA_BOOST when OUTPUT_POWER = 0b1111
//SX1278_REG_HOP_PERIOD
#define SX1278_HOP_PERIOD_OFF 0b00000000 // 7 0 number of periods between frequency hops; 0 = disabled
#define SX1278_HOP_PERIOD_MAX 0b11111111 // 7 0
//SX1278_REG_DIO_MAPPING_1
#define SX1278_DIO0_RX_DONE 0b00000000 // 7 6
#define SX1278_DIO0_TX_DONE 0b01000000 // 7 6
#define SX1278_DIO0_CAD_DONE 0b10000000 // 7 6
#define SX1278_DIO1_RX_TIMEOUT 0b00000000 // 5 4
#define SX1278_DIO1_FHSS_CHANGE_CHANNEL 0b00010000 // 5 4
#define SX1278_DIO1_CAD_DETECTED 0b00100000 // 5 4
//SX1278_REG_IRQ_FLAGS
#define SX1278_CLEAR_IRQ_FLAG_RX_TIMEOUT 0b10000000 // 7 7 timeout
#define SX1278_CLEAR_IRQ_FLAG_RX_DONE 0b01000000 // 6 6 packet reception complete
#define SX1278_CLEAR_IRQ_FLAG_PAYLOAD_CRC_ERROR 0b00100000 // 5 5 payload CRC error
#define SX1278_CLEAR_IRQ_FLAG_VALID_HEADER 0b00010000 // 4 4 valid header received
#define SX1278_CLEAR_IRQ_FLAG_TX_DONE 0b00001000 // 3 3 payload transmission complete
#define SX1278_CLEAR_IRQ_FLAG_CAD_DONE 0b00000100 // 2 2 CAD complete
#define SX1278_CLEAR_IRQ_FLAG_FHSS_CHANGE_CHANNEL 0b00000010 // 1 1 FHSS change channel
#define SX1278_CLEAR_IRQ_FLAG_CAD_DETECTED 0b00000001 // 0 0 valid LoRa signal detected during CAD operation
//SX1278_REG_IRQ_FLAGS_MASK
#define SX1278_MASK_IRQ_FLAG_RX_TIMEOUT 0b01111111 // 7 7 timeout
#define SX1278_MASK_IRQ_FLAG_RX_DONE 0b10111111 // 6 6 packet reception complete
#define SX1278_MASK_IRQ_FLAG_PAYLOAD_CRC_ERROR 0b11011111 // 5 5 payload CRC error
#define SX1278_MASK_IRQ_FLAG_VALID_HEADER 0b11101111 // 4 4 valid header received
#define SX1278_MASK_IRQ_FLAG_TX_DONE 0b11110111 // 3 3 payload transmission complete
#define SX1278_MASK_IRQ_FLAG_CAD_DONE 0b11111011 // 2 2 CAD complete
#define SX1278_MASK_IRQ_FLAG_FHSS_CHANGE_CHANNEL 0b11111101 // 1 1 FHSS change channel
#define SX1278_MASK_IRQ_FLAG_CAD_DETECTED 0b11111110 // 0 0 valid LoRa signal detected during CAD operation
//SX1278_REG_FIFO_TX_BASE_ADDR
#define SX1278_FIFO_TX_BASE_ADDR_MAX 0b00000000 // 7 0 allocate the entire FIFO buffer for TX only
//SX1278_REG_FIFO_RX_BASE_ADDR
#define SX1278_FIFO_RX_BASE_ADDR_MAX 0b00000000 // 7 0 allocate the entire FIFO buffer for RX only
class SX1278 {
class SX1278: public SX127x {
public:
SX1278(Module* module);
SX1278(Module* mod);
float dataRate;
int8_t lastPacketRSSI;
uint8_t begin(float freq = 434.0, uint32_t bw = 125000, uint8_t sf = 9, uint8_t cr = 7, uint8_t syncWord = SX127X_SYNC_WORD, uint16_t addrEeprom = 0);
uint8_t begin(Bandwidth bw = BW_125_00_KHZ, SpreadingFactor sf = SF_9, CodingRate cr = CR_4_7, uint16_t addrEeprom = 0);
uint8_t transmit(Packet& pack);
uint8_t receive(Packet& pack);
uint8_t sleep();
uint8_t standby();
uint8_t setBandwidth(Bandwidth bw);
uint8_t setSpreadingFactor(SpreadingFactor sf);
uint8_t setCodingRate(CodingRate cr);
uint8_t setBandwidth(uint32_t bw);
uint8_t setSpreadingFactor(uint8_t sf);
uint8_t setCodingRate(uint8_t cr);
protected:
uint8_t configCommon(uint8_t bw, uint8_t sf, uint8_t cr, float freq, uint8_t syncWord); // common for SX1276/77/78/79
private:
Module* _mod;
Bandwidth _bw;
SpreadingFactor _sf;
CodingRate _cr;
uint16_t _addrEeprom;
uint8_t _address[8] = {0, 0, 0, 0, 0, 0, 0, 0};
void generateLoRaAdress();
uint8_t config(Bandwidth bw, SpreadingFactor sf, CodingRate cr);
uint8_t setMode(uint8_t mode);
void clearIRQFlags();
int8_t getLastPacketRSSI();
uint8_t config(float freq, uint32_t bw, uint8_t sf, uint8_t cr, uint8_t syncWord); // specific to SX1278
};
#endif

76
src/modules/SX1279.cpp Normal file
View file

@ -0,0 +1,76 @@
#include "SX1279.h"
SX1279::SX1279(Module* mod) : SX1278(mod) {
}
uint8_t SX1279::config(uint32_t bw, uint8_t sf, uint8_t cr, float freq, uint8_t syncWord) {
uint8_t status = ERR_NONE;
uint8_t newBandwidth, newSpreadingFactor, newCodingRate;
// check the supplied BW, CR and SF values
switch(bw) {
case 125000:
newBandwidth = SX1278_BW_125_00_KHZ;
break;
case 250000:
newBandwidth = SX1278_BW_250_00_KHZ;
break;
case 500000:
newBandwidth = SX1278_BW_500_00_KHZ;
break;
default:
return(ERR_INVALID_BANDWIDTH);
}
switch(sf) {
case 6:
newSpreadingFactor = SX127X_SF_6;
break;
case 7:
newSpreadingFactor = SX127X_SF_7;
break;
case 8:
newSpreadingFactor = SX127X_SF_8;
break;
case 9:
newSpreadingFactor = SX127X_SF_9;
break;
default:
return(ERR_INVALID_SPREADING_FACTOR);
}
switch(cr) {
case 5:
newCodingRate = SX1278_CR_4_5;
break;
case 6:
newCodingRate = SX1278_CR_4_6;
break;
case 7:
newCodingRate = SX1278_CR_4_7;
break;
case 8:
newCodingRate = SX1278_CR_4_8;
break;
default:
return(ERR_INVALID_CODING_RATE);
}
if((freq < 137.0) || (freq > 960.0)) {
return(ERR_INVALID_FREQUENCY);
}
// execute common part
status = configCommon(newBandwidth, newSpreadingFactor, newCodingRate, freq, syncWord);
if(status != ERR_NONE) {
return(status);
}
// configuration successful, save the new settings
_bw = bw;
_sf = sf;
_cr = cr;
return(ERR_NONE);
}

15
src/modules/SX1279.h Normal file
View file

@ -0,0 +1,15 @@
#ifndef _KITELIB_SX1279_H
#define _KITELIB_SX1279_H
#include "TypeDef.h"
#include "SX1278.h"
class SX1279: public SX1278 {
public:
SX1279(Module* mod);
private:
uint8_t config(uint32_t bw, uint8_t sf, uint8_t cr, float freq, uint8_t syncWord);
};
#endif

327
src/modules/SX127x.cpp Normal file
View file

@ -0,0 +1,327 @@
#include "SX127x.h"
SX127x::SX127x(Module* mod) {
_mod = mod;
}
uint8_t SX127x::begin(float freq, uint32_t bw, uint8_t sf, uint8_t cr, uint8_t syncWord, uint16_t addrEeprom) {
// copy LoRa modem settings
_freq = freq;
_bw = bw;
_sf = sf;
_cr = cr;
_syncWord = syncWord;
// ESP32-only: initialize EEPROM
#ifdef ESP32
if(!EEPROM.begin(9)) {
DEBUG_PRINTLN_STR("Unable to initialize EEPROM");
return(ERR_EEPROM_NOT_INITIALIZED);
}
#endif
// copy EEPROM start address
_addrEeprom = addrEeprom;
// check if the node has address
bool hasAddress = false;
for(uint16_t i = 0; i < 8; i++) {
if(EEPROM.read(_addrEeprom + i) != 255) {
hasAddress = true;
break;
}
}
// generate new address
if(!hasAddress) {
randomSeed(analogRead(5));
generateNodeAdress();
}
DEBUG_PRINTLN_STR("LoRa node address string: ");
for(uint8_t i = 0; i < 8; i++) {
_address[i] = EEPROM.read(i);
#ifdef KITELIB_DEBUG
Serial.print(_address[i], HEX);
if(i < 7) {
Serial.print(":");
} else {
Serial.println();
}
#endif
}
// set module properties
_mod->init(USE_SPI, INT_BOTH);
// try to find the SX127x chip
uint8_t i = 0;
bool flagFound = false;
while((i < 10) && !flagFound) {
uint8_t version = _mod->SPIreadRegister(SX127X_REG_VERSION);
if(version == 0x12) {
flagFound = true;
} else {
#ifdef KITELIB_DEBUG
Serial.print("SX127x not found! (");
Serial.print(i + 1);
Serial.print(" of 10 tries) SX127X_REG_VERSION == ");
char buffHex[5];
sprintf(buffHex, "0x%02X", version);
Serial.print(buffHex);
Serial.println();
#endif
delay(1000);
i++;
}
}
if(!flagFound) {
DEBUG_PRINTLN_STR("No SX127x found!");
SPI.end();
return(ERR_CHIP_NOT_FOUND);
} else {
DEBUG_PRINTLN_STR("Found SX127x! (match by SX127X_REG_VERSION == 0x12)");
}
return(ERR_NONE);
}
uint8_t SX127x::transmit(Packet& pack) {
// check packet length
if(pack.length >= 256) {
return(ERR_PACKET_TOO_LONG);
}
// calculate timeout
uint16_t base = 1;
float symbolLength = (float)(base << _sf) / (float)_bw;
float de = 0;
if(symbolLength >= 0.016) {
de = 1;
}
float ih = (float)_mod->SPIgetRegValue(SX127X_REG_MODEM_CONFIG_1, 0, 0);
float crc = (float)(_mod->SPIgetRegValue(SX127X_REG_MODEM_CONFIG_2, 2, 2) >> 2);
float n_pre = (float)_mod->SPIgetRegValue(SX127X_REG_PREAMBLE_LSB);
float n_pay = 8.0 + max(ceil((8.0 * (float)pack.length - 4.0 * (float)_sf + 28.0 + 16.0 * crc - 20.0 * ih)/(4.0 * (float)_sf - 8.0 * de)) * (float)_cr, 0);
uint32_t timeout = ceil(symbolLength * (n_pre + n_pay + 4.25) * 1000.0);
// write packet to FIFO
setMode(SX127X_STANDBY);
_mod->SPIsetRegValue(SX127X_REG_DIO_MAPPING_1, SX127X_DIO0_TX_DONE, 7, 6);
clearIRQFlags();
_mod->SPIsetRegValue(SX127X_REG_PAYLOAD_LENGTH, pack.length);
_mod->SPIsetRegValue(SX127X_REG_FIFO_TX_BASE_ADDR, SX127X_FIFO_TX_BASE_ADDR_MAX);
_mod->SPIsetRegValue(SX127X_REG_FIFO_ADDR_PTR, SX127X_FIFO_TX_BASE_ADDR_MAX);
_mod->SPIwriteRegisterBurstStr(SX127X_REG_FIFO, pack.source, 8);
_mod->SPIwriteRegisterBurstStr(SX127X_REG_FIFO, pack.destination, 8);
_mod->SPIwriteRegisterBurstStr(SX127X_REG_FIFO, pack.data, pack.length - 16);
// start transmission
setMode(SX127X_TX);
// check for timeout
uint32_t start = millis();
while(!_mod->getInt0State()) {
if(millis() - start > timeout) {
clearIRQFlags();
return(ERR_TX_TIMEOUT);
}
}
clearIRQFlags();
return(ERR_NONE);
}
uint8_t SX127x::receive(Packet& pack) {
// prepare for packet reception
setMode(SX127X_STANDBY);
_mod->SPIsetRegValue(SX127X_REG_DIO_MAPPING_1, SX127X_DIO0_RX_DONE | SX127X_DIO1_RX_TIMEOUT, 7, 4);
clearIRQFlags();
_mod->SPIsetRegValue(SX127X_REG_FIFO_RX_BASE_ADDR, SX127X_FIFO_RX_BASE_ADDR_MAX);
_mod->SPIsetRegValue(SX127X_REG_FIFO_ADDR_PTR, SX127X_FIFO_RX_BASE_ADDR_MAX);
// start receiving
setMode(SX127X_RXSINGLE);
uint32_t start = millis();
while(!_mod->getInt0State()) {
if(_mod->getInt1State()) {
clearIRQFlags();
return(ERR_RX_TIMEOUT);
}
}
uint32_t elapsed = millis() - start;
if(_mod->SPIgetRegValue(SX127X_REG_IRQ_FLAGS, 5, 5) == SX127X_CLEAR_IRQ_FLAG_PAYLOAD_CRC_ERROR) {
return(ERR_CRC_MISMATCH);
}
if(_sf != 6) {
pack.length = _mod->SPIgetRegValue(SX127X_REG_RX_NB_BYTES);
}
_mod->SPIreadRegisterBurstStr(SX127X_REG_FIFO, 8, pack.source);
_mod->SPIreadRegisterBurstStr(SX127X_REG_FIFO, 8, pack.destination);
delete[] pack.data;
pack.data = new char[pack.length - 15];
_mod->SPIreadRegisterBurstStr(SX127X_REG_FIFO, pack.length - 16, pack.data);
pack.data[pack.length - 16] = 0;
dataRate = (pack.length*8.0)/((float)elapsed/1000.0);
lastPacketRSSI = -157 + _mod->SPIgetRegValue(SX127X_REG_PKT_RSSI_VALUE);
int8_t rawSNR = (int8_t)_mod->SPIgetRegValue(SX127X_REG_PKT_SNR_VALUE);
lastPacketSNR = rawSNR / 4.0;
clearIRQFlags();
return(ERR_NONE);
}
uint8_t SX127x::scanChannel() {
setMode(SX127X_STANDBY);
_mod->SPIsetRegValue(SX127X_REG_DIO_MAPPING_1, SX127X_DIO0_CAD_DONE | SX127X_DIO1_CAD_DETECTED, 7, 4);
clearIRQFlags();
setMode(SX127X_CAD);
while(!_mod->getInt0State()) {
if(_mod->getInt1State()) {
clearIRQFlags();
return(PREAMBLE_DETECTED);
}
}
clearIRQFlags();
return(CHANNEL_FREE);
}
uint8_t SX127x::sleep() {
return(setMode(SX127X_SLEEP));
}
uint8_t SX127x::standby() {
return(setMode(SX127X_STANDBY));
}
uint8_t SX127x::setFrequency(float freq) {
uint8_t state = config(_bw, _sf, _cr, freq, _syncWord);
if(state == ERR_NONE) {
_freq = freq;
}
return(state);
}
uint8_t SX127x::setSyncWord(uint8_t syncWord) {
uint8_t state = config(_bw, _sf, _cr, _freq, syncWord);
if(state == ERR_NONE) {
_syncWord = syncWord;
}
return(state);
}
uint8_t SX127x::setOutputPower(int8_t power) {
setMode(SX127X_STANDBY);
if((power < 2) || (power > 17)) {
return(ERR_INVALID_OUTPUT_POWER);
}
return(_mod->SPIsetRegValue(SX127X_REG_PA_CONFIG, power - 2, 3, 0));
}
uint8_t SX127x::config(uint8_t bw, uint8_t sf, uint8_t cr, float freq, uint8_t syncWord) {
uint8_t status = ERR_NONE;
// set mode to SLEEP
status = setMode(SX127X_SLEEP);
if(status != ERR_NONE) {
return(status);
}
// set LoRa mode
status = _mod->SPIsetRegValue(SX127X_REG_OP_MODE, SX127X_LORA, 7, 7);
if(status != ERR_NONE) {
return(status);
}
// set carrier frequency
uint32_t base = 1;
uint32_t FRF = (freq * (base << 19)) / 32.0;
status = _mod->SPIsetRegValue(SX127X_REG_FRF_MSB, (FRF & 0xFF0000) >> 16);
status = _mod->SPIsetRegValue(SX127X_REG_FRF_MID, (FRF & 0x00FF00) >> 8);
status = _mod->SPIsetRegValue(SX127X_REG_FRF_LSB, FRF & 0x0000FF);
if(status != ERR_NONE) {
return(status);
}
// output power configuration
status = _mod->SPIsetRegValue(SX127X_REG_PA_CONFIG, SX127X_PA_SELECT_BOOST | SX127X_OUTPUT_POWER);
status = _mod->SPIsetRegValue(SX127X_REG_OCP, SX127X_OCP_ON | SX127X_OCP_TRIM, 5, 0);
status = _mod->SPIsetRegValue(SX127X_REG_LNA, SX127X_LNA_GAIN_1 | SX127X_LNA_BOOST_ON);
if(status != ERR_NONE) {
return(status);
}
// turn off frequency hopping
status = _mod->SPIsetRegValue(SX127X_REG_HOP_PERIOD, SX127X_HOP_PERIOD_OFF);
if(status != ERR_NONE) {
return(status);
}
// basic setting (bw, cr, sf, header mode and CRC)
if(sf == SX127X_SF_6) {
status = _mod->SPIsetRegValue(SX127X_REG_MODEM_CONFIG_2, SX127X_SF_6 | SX127X_TX_MODE_SINGLE, 7, 3);
status = _mod->SPIsetRegValue(SX127X_REG_DETECT_OPTIMIZE, SX127X_DETECT_OPTIMIZE_SF_6, 2, 0);
status = _mod->SPIsetRegValue(SX127X_REG_DETECTION_THRESHOLD, SX127X_DETECTION_THRESHOLD_SF_6);
} else {
status = _mod->SPIsetRegValue(SX127X_REG_MODEM_CONFIG_2, sf | SX127X_TX_MODE_SINGLE, 7, 3);
status = _mod->SPIsetRegValue(SX127X_REG_DETECT_OPTIMIZE, SX127X_DETECT_OPTIMIZE_SF_7_12, 2, 0);
status = _mod->SPIsetRegValue(SX127X_REG_DETECTION_THRESHOLD, SX127X_DETECTION_THRESHOLD_SF_7_12);
}
if(status != ERR_NONE) {
return(status);
}
// set the sync word
status = _mod->SPIsetRegValue(SX127X_REG_SYNC_WORD, syncWord);
if(status != ERR_NONE) {
return(status);
}
// set default preamble length
status = _mod->SPIsetRegValue(SX127X_REG_PREAMBLE_MSB, SX127X_PREAMBLE_LENGTH_MSB);
status = _mod->SPIsetRegValue(SX127X_REG_PREAMBLE_LSB, SX127X_PREAMBLE_LENGTH_LSB);
if(status != ERR_NONE) {
return(status);
}
// set mode to STANDBY
status = setMode(SX127X_STANDBY);
return(status);
}
void SX127x::generateNodeAdress() {
for(uint8_t i = _addrEeprom; i < (_addrEeprom + 8); i++) {
EEPROM.write(i, (uint8_t)random(0, 256));
}
}
uint8_t SX127x::setMode(uint8_t mode) {
_mod->SPIsetRegValue(SX127X_REG_OP_MODE, mode, 2, 0);
return(ERR_NONE);
}
void SX127x::clearIRQFlags() {
_mod->SPIwriteRegister(SX127X_REG_IRQ_FLAGS, 0b11111111);
}

211
src/modules/SX127x.h Normal file
View file

@ -0,0 +1,211 @@
#ifndef _KITELIB_SX127X_H
#define _KITELIB_SX127X_H
#include <EEPROM.h>
#include "TypeDef.h"
#include "Module.h"
#include "Packet.h"
// SX127x series common registers
#define SX127X_REG_FIFO 0x00
#define SX127X_REG_OP_MODE 0x01
#define SX127X_REG_FRF_MSB 0x06
#define SX127X_REG_FRF_MID 0x07
#define SX127X_REG_FRF_LSB 0x08
#define SX127X_REG_PA_CONFIG 0x09
#define SX127X_REG_PA_RAMP 0x0A
#define SX127X_REG_OCP 0x0B
#define SX127X_REG_LNA 0x0C
#define SX127X_REG_FIFO_ADDR_PTR 0x0D
#define SX127X_REG_FIFO_TX_BASE_ADDR 0x0E
#define SX127X_REG_FIFO_RX_BASE_ADDR 0x0F
#define SX127X_REG_FIFO_RX_CURRENT_ADDR 0x10
#define SX127X_REG_IRQ_FLAGS_MASK 0x11
#define SX127X_REG_IRQ_FLAGS 0x12
#define SX127X_REG_RX_NB_BYTES 0x13
#define SX127X_REG_RX_HEADER_CNT_VALUE_MSB 0x14
#define SX127X_REG_RX_HEADER_CNT_VALUE_LSB 0x15
#define SX127X_REG_RX_PACKET_CNT_VALUE_MSB 0x16
#define SX127X_REG_RX_PACKET_CNT_VALUE_LSB 0x17
#define SX127X_REG_MODEM_STAT 0x18
#define SX127X_REG_PKT_SNR_VALUE 0x19
#define SX127X_REG_PKT_RSSI_VALUE 0x1A
#define SX127X_REG_RSSI_VALUE 0x1B
#define SX127X_REG_HOP_CHANNEL 0x1C
#define SX127X_REG_MODEM_CONFIG_1 0x1D
#define SX127X_REG_MODEM_CONFIG_2 0x1E
#define SX127X_REG_SYMB_TIMEOUT_LSB 0x1F
#define SX127X_REG_PREAMBLE_MSB 0x20
#define SX127X_REG_PREAMBLE_LSB 0x21
#define SX127X_REG_PAYLOAD_LENGTH 0x22
#define SX127X_REG_MAX_PAYLOAD_LENGTH 0x23
#define SX127X_REG_HOP_PERIOD 0x24
#define SX127X_REG_FIFO_RX_BYTE_ADDR 0x25
#define SX127X_REG_FEI_MSB 0x28
#define SX127X_REG_FEI_MID 0x29
#define SX127X_REG_FEI_LSB 0x2A
#define SX127X_REG_RSSI_WIDEBAND 0x2C
#define SX127X_REG_DETECT_OPTIMIZE 0x31
#define SX127X_REG_INVERT_IQ 0x33
#define SX127X_REG_DETECTION_THRESHOLD 0x37
#define SX127X_REG_SYNC_WORD 0x39
#define SX127X_REG_DIO_MAPPING_1 0x40
#define SX127X_REG_DIO_MAPPING_2 0x41
#define SX127X_REG_VERSION 0x42
// SX127x common modem settings
// SX127X_REG_OP_MODE MSB LSB DESCRIPTION
#define SX127X_FSK_OOK 0b00000000 // 7 7 FSK/OOK mode
#define SX127X_LORA 0b10000000 // 7 7 LoRa mode
#define SX127X_ACCESS_SHARED_REG_OFF 0b00000000 // 6 6 access LoRa registers (0x0D:0x3F) in LoRa mode
#define SX127X_ACCESS_SHARED_REG_ON 0b01000000 // 6 6 access FSK registers (0x0D:0x3F) in LoRa mode
#define SX127X_SLEEP 0b00000000 // 2 0 sleep
#define SX127X_STANDBY 0b00000001 // 2 0 standby
#define SX127X_FSTX 0b00000010 // 2 0 frequency synthesis TX
#define SX127X_TX 0b00000011 // 2 0 transmit
#define SX127X_FSRX 0b00000100 // 2 0 frequency synthesis RX
#define SX127X_RXCONTINUOUS 0b00000101 // 2 0 receive continuous
#define SX127X_RXSINGLE 0b00000110 // 2 0 receive single
#define SX127X_CAD 0b00000111 // 2 0 channel activity detection
// SX127X_REG_PA_CONFIG
#define SX127X_PA_SELECT_RFO 0b00000000 // 7 7 RFO pin output, power limited to +14 dBm
#define SX127X_PA_SELECT_BOOST 0b10000000 // 7 7 PA_BOOST pin output, power limited to +20 dBm
#define SX127X_OUTPUT_POWER 0b00001111 // 3 0 output power: P_out = 2 + OUTPUT_POWER [dBm] for PA_SELECT_BOOST
// P_out = -1 + OUTPUT_POWER [dBm] for PA_SELECT_RFO
// SX127X_REG_OCP
#define SX127X_OCP_OFF 0b00000000 // 5 5 PA overload current protection disabled
#define SX127X_OCP_ON 0b00100000 // 5 5 PA overload current protection enabled
#define SX127X_OCP_TRIM 0b00001011 // 4 0 OCP current: I_max(OCP_TRIM = 0b1011) = 100 mA
// SX127X_REG_LNA
#define SX127X_LNA_GAIN_0 0b00000000 // 7 5 LNA gain setting: not used
#define SX127X_LNA_GAIN_1 0b00100000 // 7 5 max gain
#define SX127X_LNA_GAIN_2 0b01000000 // 7 5 .
#define SX127X_LNA_GAIN_3 0b01100000 // 7 5 .
#define SX127X_LNA_GAIN_4 0b10000000 // 7 5 .
#define SX127X_LNA_GAIN_5 0b10100000 // 7 5 .
#define SX127X_LNA_GAIN_6 0b11000000 // 7 5 min gain
#define SX127X_LNA_GAIN_7 0b11100000 // 7 5 not used
#define SX127X_LNA_BOOST_OFF 0b00000000 // 1 0 default LNA current
#define SX127X_LNA_BOOST_ON 0b00000011 // 1 0 150% LNA current
// SX127X_REG_MODEM_CONFIG_2
#define SX127X_SF_6 0b01100000 // 7 4 spreading factor: 64 chips/bit
#define SX127X_SF_7 0b01110000 // 7 4 128 chips/bit
#define SX127X_SF_8 0b10000000 // 7 4 256 chips/bit
#define SX127X_SF_9 0b10010000 // 7 4 512 chips/bit
#define SX127X_SF_10 0b10100000 // 7 4 1024 chips/bit
#define SX127X_SF_11 0b10110000 // 7 4 2048 chips/bit
#define SX127X_SF_12 0b11000000 // 7 4 4096 chips/bit
#define SX127X_TX_MODE_SINGLE 0b00000000 // 3 3 single TX
#define SX127X_TX_MODE_CONT 0b00001000 // 3 3 continuous TX
#define SX127X_RX_TIMEOUT_MSB 0b00000000 // 1 0
// SX127X_REG_SYMB_TIMEOUT_LSB
#define SX127X_RX_TIMEOUT_LSB 0b01100100 // 7 0 10 bit RX operation timeout
// SX127X_REG_PREAMBLE_MSB + REG_PREAMBLE_LSB
#define SX127X_PREAMBLE_LENGTH_MSB 0b00000000 // 7 0 2 byte preamble length setting: l_P = PREAMBLE_LENGTH + 4.25
#define SX127X_PREAMBLE_LENGTH_LSB 0b00001000 // 7 0 where l_p = preamble length
// SX127X_REG_DETECT_OPTIMIZE
#define SX127X_DETECT_OPTIMIZE_SF_6 0b00000101 // 2 0 SF6 detection optimization
#define SX127X_DETECT_OPTIMIZE_SF_7_12 0b00000011 // 2 0 SF7 to SF12 detection optimization
// SX127X_REG_DETECTION_THRESHOLD
#define SX127X_DETECTION_THRESHOLD_SF_6 0b00001100 // 7 0 SF6 detection threshold
#define SX127X_DETECTION_THRESHOLD_SF_7_12 0b00001010 // 7 0 SF7 to SF12 detection threshold
// SX127X_REG_PA_DAC
#define SX127X_PA_BOOST_OFF 0b00000100 // 2 0 PA_BOOST disabled
#define SX127X_PA_BOOST_ON 0b00000111 // 2 0 +20 dBm on PA_BOOST when OUTPUT_POWER = 0b1111
// SX127X_REG_HOP_PERIOD
#define SX127X_HOP_PERIOD_OFF 0b00000000 // 7 0 number of periods between frequency hops; 0 = disabled
#define SX127X_HOP_PERIOD_MAX 0b11111111 // 7 0
// SX127X_REG_DIO_MAPPING_1
#define SX127X_DIO0_RX_DONE 0b00000000 // 7 6
#define SX127X_DIO0_TX_DONE 0b01000000 // 7 6
#define SX127X_DIO0_CAD_DONE 0b10000000 // 7 6
#define SX127X_DIO1_RX_TIMEOUT 0b00000000 // 5 4
#define SX127X_DIO1_FHSS_CHANGE_CHANNEL 0b00010000 // 5 4
#define SX127X_DIO1_CAD_DETECTED 0b00100000 // 5 4
// SX127X_REG_IRQ_FLAGS
#define SX127X_CLEAR_IRQ_FLAG_RX_TIMEOUT 0b10000000 // 7 7 timeout
#define SX127X_CLEAR_IRQ_FLAG_RX_DONE 0b01000000 // 6 6 packet reception complete
#define SX127X_CLEAR_IRQ_FLAG_PAYLOAD_CRC_ERROR 0b00100000 // 5 5 payload CRC error
#define SX127X_CLEAR_IRQ_FLAG_VALID_HEADER 0b00010000 // 4 4 valid header received
#define SX127X_CLEAR_IRQ_FLAG_TX_DONE 0b00001000 // 3 3 payload transmission complete
#define SX127X_CLEAR_IRQ_FLAG_CAD_DONE 0b00000100 // 2 2 CAD complete
#define SX127X_CLEAR_IRQ_FLAG_FHSS_CHANGE_CHANNEL 0b00000010 // 1 1 FHSS change channel
#define SX127X_CLEAR_IRQ_FLAG_CAD_DETECTED 0b00000001 // 0 0 valid LoRa signal detected during CAD operation
// SX127X_REG_IRQ_FLAGS_MASK
#define SX127X_MASK_IRQ_FLAG_RX_TIMEOUT 0b01111111 // 7 7 timeout
#define SX127X_MASK_IRQ_FLAG_RX_DONE 0b10111111 // 6 6 packet reception complete
#define SX127X_MASK_IRQ_FLAG_PAYLOAD_CRC_ERROR 0b11011111 // 5 5 payload CRC error
#define SX127X_MASK_IRQ_FLAG_VALID_HEADER 0b11101111 // 4 4 valid header received
#define SX127X_MASK_IRQ_FLAG_TX_DONE 0b11110111 // 3 3 payload transmission complete
#define SX127X_MASK_IRQ_FLAG_CAD_DONE 0b11111011 // 2 2 CAD complete
#define SX127X_MASK_IRQ_FLAG_FHSS_CHANGE_CHANNEL 0b11111101 // 1 1 FHSS change channel
#define SX127X_MASK_IRQ_FLAG_CAD_DETECTED 0b11111110 // 0 0 valid LoRa signal detected during CAD operation
// SX127X_REG_FIFO_TX_BASE_ADDR
#define SX127X_FIFO_TX_BASE_ADDR_MAX 0b00000000 // 7 0 allocate the entire FIFO buffer for TX only
// SX127X_REG_FIFO_RX_BASE_ADDR
#define SX127X_FIFO_RX_BASE_ADDR_MAX 0b00000000 // 7 0 allocate the entire FIFO buffer for RX only
// SX127X_REG_SYNC_WORD
#define SX127X_SYNC_WORD 0x12 // 7 0 default LoRa sync word
#define SX127X_SYNC_WORD_LORAWAN 0x34 // 7 0 sync word reserved for LoRaWAN networks
class SX127x {
public:
SX127x(Module* mod);
float dataRate;
int8_t lastPacketRSSI;
float lastPacketSNR;
uint8_t begin(float freq, uint32_t bw, uint8_t sf, uint8_t cr, uint8_t syncWord, uint16_t addrEeprom);
uint8_t transmit(Packet& pack);
uint8_t receive(Packet& pack);
uint8_t scanChannel();
uint8_t sleep();
uint8_t standby();
uint8_t setFrequency(float freq);
uint8_t setSyncWord(uint8_t syncWord);
uint8_t setOutputPower(int8_t power);
protected:
Module* _mod;
uint32_t _bw;
uint8_t _sf;
uint8_t _cr;
float _freq;
uint8_t _syncWord;
uint8_t tx(char* data, uint8_t length);
uint8_t rxSingle(char* data, uint8_t* length);
uint8_t config(uint8_t bw, uint8_t sf, uint8_t cr, float freq, uint8_t syncWord);
private:
uint8_t _address[8] = {0, 0, 0, 0, 0, 0, 0, 0};
uint16_t _addrEeprom;
void generateNodeAdress();
uint8_t setMode(uint8_t mode);
void clearIRQFlags();
};
#endif