first commit
This commit is contained in:
Executable
+861
@@ -0,0 +1,861 @@
|
||||
/*
|
||||
* Functions for using SX127x in FSK mode (mainly receive)
|
||||
* Copyright (C) 2019 Hansi Reiser, dl9rdz
|
||||
*
|
||||
* Partially based on the SX1278 libraray for managing Semtech modules
|
||||
* Copyright (C) 2015 Wireless Open Source
|
||||
* http://wirelessopensource.com
|
||||
*
|
||||
* SPDX-License-Identifier: LGPL-2.1+
|
||||
*/
|
||||
|
||||
#include "SX1278FSK.h"
|
||||
#include "SPI.h"
|
||||
#include <Sonde.h>
|
||||
#include <Display.h>
|
||||
|
||||
SX1278FSK::SX1278FSK()
|
||||
{
|
||||
// Initialize class variables
|
||||
};
|
||||
|
||||
|
||||
static SPISettings spiset = SPISettings(40000000L, MSBFIRST, SPI_MODE0);
|
||||
|
||||
/*
|
||||
Function: Turns the module ON.
|
||||
Returns: 0 on success, 1 otherwise
|
||||
*/
|
||||
uint8_t SX1278FSK::ON()
|
||||
{
|
||||
uint8_t state = 2;
|
||||
#if (SX1278FSK_debug_mode > 1)
|
||||
Serial.println();
|
||||
Serial.println(F("Starting 'ON'"));
|
||||
#endif
|
||||
|
||||
// Powering the module
|
||||
pinMode(SX1278_SS, OUTPUT);
|
||||
digitalWrite(SX1278_SS, HIGH);
|
||||
|
||||
//Configure the MISO, MOSI, CS, SPCR.
|
||||
SPI.begin();
|
||||
//Set most significant bit first
|
||||
SPI.setBitOrder(MSBFIRST);
|
||||
//Divide the clock frequency
|
||||
SPI.setClockDivider(SPI_CLOCK_DIV2);
|
||||
//Set data mode
|
||||
SPI.setDataMode(SPI_MODE0);
|
||||
|
||||
// Set Maximum Over Current Protection
|
||||
state = setMaxCurrent(0x1B);
|
||||
if( state == 0 )
|
||||
{
|
||||
#if (SX1278FSK_debug_mode > 1)
|
||||
Serial.println(F("## Setting ON with maximum current supply ##"));
|
||||
Serial.println();
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
// set FSK mode
|
||||
state = setFSK();
|
||||
return state;
|
||||
}
|
||||
|
||||
/*
|
||||
Function: Turn the module OFF.
|
||||
Returns: Nothing
|
||||
*/
|
||||
void SX1278FSK::OFF()
|
||||
{
|
||||
#if (SX1278FSK_debug_mode > 1)
|
||||
Serial.println();
|
||||
Serial.println(F("Starting 'OFF'"));
|
||||
#endif
|
||||
|
||||
SPI.end();
|
||||
// Powering the module
|
||||
pinMode(SX1278_SS,OUTPUT);
|
||||
digitalWrite(SX1278_SS,LOW);
|
||||
|
||||
#if (SX1278FSK_debug_mode > 1)
|
||||
Serial.println(F("## Setting OFF ##"));
|
||||
Serial.println();
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
Function: Reads the indicated register.
|
||||
Returns: The content of the register
|
||||
Parameters:
|
||||
address: address register to read from
|
||||
*/
|
||||
byte SX1278FSK::readRegister(byte address)
|
||||
{
|
||||
byte value = 0x00;
|
||||
|
||||
SPI.beginTransaction(spiset);
|
||||
digitalWrite(SX1278_SS,LOW);
|
||||
|
||||
//delay(1);
|
||||
bitClear(address, 7); // Bit 7 cleared to write in registers
|
||||
SPI.transfer(address);
|
||||
value = SPI.transfer(0x00);
|
||||
digitalWrite(SX1278_SS,HIGH);
|
||||
SPI.endTransaction();
|
||||
|
||||
#if (SX1278FSK_debug_mode > 1)
|
||||
if(address!=0x3F) {
|
||||
Serial.print(F("## Reading: ##\t"));
|
||||
Serial.print(F("Register "));
|
||||
Serial.print(address, HEX);
|
||||
Serial.print(F(": "));
|
||||
Serial.print(value, HEX);
|
||||
Serial.println();
|
||||
}
|
||||
#endif
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
/*
|
||||
Function: Writes on the indicated register.
|
||||
Returns: Nothing
|
||||
Parameters:
|
||||
address: address register to write in
|
||||
data: value to write in the register
|
||||
*/
|
||||
void SX1278FSK::writeRegister(byte address, byte data)
|
||||
{
|
||||
SPI.beginTransaction(spiset);
|
||||
digitalWrite(SX1278_SS,LOW);
|
||||
|
||||
//delay(1);
|
||||
bitSet(address, 7); // Bit 7 set to read from registers
|
||||
SPI.transfer(address);
|
||||
SPI.transfer(data);
|
||||
digitalWrite(SX1278_SS,HIGH);
|
||||
SPI.endTransaction();
|
||||
|
||||
#if (SX1278FSK_debug_mode > 1)
|
||||
Serial.print(F("## Writing: ##\t"));
|
||||
Serial.print(F("Register "));
|
||||
bitClear(address, 7);
|
||||
Serial.print(address, HEX);
|
||||
Serial.print(F(": "));
|
||||
Serial.print(data, HEX);
|
||||
Serial.println();
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Function: Clears the IRQ flags
|
||||
*
|
||||
* Configuration registers are accessed through the SPI interface.
|
||||
* Registers are readable in all device mode including Sleep. However, they
|
||||
* should be written only in Sleep and Stand-by modes.
|
||||
*
|
||||
* Returns: Nothing
|
||||
*/
|
||||
void SX1278FSK::clearIRQFlags()
|
||||
{
|
||||
byte st0;
|
||||
|
||||
// Save the previous status
|
||||
st0 = readRegister(REG_OP_MODE);
|
||||
// Stdby mode to write in registers
|
||||
writeRegister(REG_OP_MODE, FSK_STANDBY_MODE);
|
||||
// FSK mode flags1 register
|
||||
writeRegister(REG_IRQ_FLAGS1, 0xFF);
|
||||
// FSK mode flags2 register
|
||||
writeRegister(REG_IRQ_FLAGS2, 0xFF);
|
||||
// Getting back to previous status
|
||||
if(st0 != FSK_STANDBY_MODE) {
|
||||
writeRegister(REG_OP_MODE, st0);
|
||||
}
|
||||
#if (SX1278FSK_debug_mode > 1)
|
||||
Serial.println(F("## FSK flags cleared ##"));
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
Function: Sets the module in FSK mode.
|
||||
Returns: Integer that determines if there has been any error
|
||||
state = 2 --> The command has not been executed
|
||||
state = 1 --> There has been an error while executing the command
|
||||
state = 0 --> The command has been executed with no errors
|
||||
*/
|
||||
uint8_t SX1278FSK::setFSK()
|
||||
{
|
||||
uint8_t state = 2;
|
||||
byte st0;
|
||||
byte config1;
|
||||
|
||||
#if (SX1278FSK_debug_mode > 1)
|
||||
Serial.println();
|
||||
Serial.println(F("Starting 'setFSK'"));
|
||||
#endif
|
||||
|
||||
writeRegister(REG_OP_MODE, FSK_SLEEP_MODE); // Sleep mode (mandatory to change mode)
|
||||
// If we are in LORA mode, above line activate Sleep mode, but does not change mode to FSK
|
||||
// as mode change is only allowed in sleep mode. Next line changes to FSK
|
||||
writeRegister(REG_OP_MODE, FSK_SLEEP_MODE);
|
||||
|
||||
writeRegister(REG_OP_MODE, FSK_STANDBY_MODE); // FSK standby mode
|
||||
|
||||
//writeRegister(REG_FIFO_THRESH, 0x80); // condition to start packet tx
|
||||
//config1 = readRegister(REG_SYNC_CONFIG);
|
||||
//config1 = config1 & B00111111;
|
||||
//writeRegister(REG_SYNC_CONFIG,config1);
|
||||
|
||||
delay(100);
|
||||
|
||||
st0 = readRegister(REG_OP_MODE); // Reading config mode
|
||||
if( st0 == FSK_STANDBY_MODE )
|
||||
{ // FSK mode
|
||||
state = 0;
|
||||
#if (SX1278FSK_debug_mode > 1)
|
||||
Serial.println(F("## FSK set with success ##"));
|
||||
Serial.println();
|
||||
#endif
|
||||
} else { // LoRa mode
|
||||
state = 1;
|
||||
Serial.println( st0 );
|
||||
#if (SX1278FSK_debug_mode > 1)
|
||||
Serial.println(F("** There has been an error while setting FSK **"));
|
||||
Serial.println();
|
||||
#endif
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
||||
|
||||
/* Function: Sets FSK bitrate
|
||||
* Returns: 0 for success, >0 in case of error
|
||||
* Parameters: bps: requested bitrate
|
||||
* (raw data rate, for Mancester encoding, the effective bitrate is bps/2)
|
||||
*/
|
||||
|
||||
uint8_t SX1278FSK::setBitrate(float bps)
|
||||
{
|
||||
// TODO: Check if FSK mode is active
|
||||
|
||||
// check if bitrate is allowed allowed bitrate
|
||||
if((bps < 1200) || (bps > 300000)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
// set mode to FSK STANDBY
|
||||
writeRegister(REG_OP_MODE, FSK_STANDBY_MODE);
|
||||
|
||||
// set bit rate
|
||||
uint16_t bitRate = (SX127X_CRYSTAL_FREQ * 1.0) / bps;
|
||||
writeRegister(REG_BITRATE_MSB, (bitRate & 0xFF00) >> 8);
|
||||
writeRegister(REG_BITRATE_LSB, (bitRate & 0x00FF));
|
||||
|
||||
// also set fractional part
|
||||
uint16_t fracRate = (SX127X_CRYSTAL_FREQ * 16.0) / bps - bitRate * 16 + 0.5;
|
||||
writeRegister(REG_BIT_RATE_FRAC, fracRate&0x0F);
|
||||
return 0;
|
||||
}
|
||||
/* Function: Gets configured bitrate
|
||||
* Returns bitrate in bit/second
|
||||
*/
|
||||
float SX1278FSK::getBitrate()
|
||||
{
|
||||
uint8_t fmsb = readRegister(REG_BITRATE_MSB);
|
||||
uint8_t flsb = readRegister(REG_BITRATE_LSB);
|
||||
uint8_t ffrac = readRegister(REG_BIT_RATE_FRAC) & 0x0F;
|
||||
return SX127X_CRYSTAL_FREQ / ( (fmsb<<8) + flsb + ffrac / 16.0 );
|
||||
}
|
||||
|
||||
//typedef struct rxbwset { float bw; uint8_t mant; uint8_t rxp; } st_rxbwsettings;
|
||||
|
||||
uint8_t SX1278FSK::setRxBandwidth(float bw)
|
||||
{
|
||||
// TODO: Check if in FSK mode
|
||||
//
|
||||
if(bw<2600 || bw>250000) { return 1; /* invalid */ }
|
||||
|
||||
uint8_t rxbwexp = 1;
|
||||
bw = SX127X_CRYSTAL_FREQ / bw / 8;
|
||||
while(bw>31) { rxbwexp++; bw/=2.0; }
|
||||
uint8_t rxbwmant = bw<17?0 : bw<21? 1:2;
|
||||
|
||||
// set mode to FSK STANDBY
|
||||
writeRegister(REG_OP_MODE, FSK_STANDBY_MODE);
|
||||
|
||||
writeRegister(REG_RX_BW, rxbwexp | (rxbwmant<<3));
|
||||
return 0;
|
||||
}
|
||||
|
||||
float SX1278FSK::getRxBandwidth()
|
||||
{
|
||||
uint8_t rxbw = readRegister(REG_RX_BW);
|
||||
uint8_t rxbwexp = rxbw&0x07;
|
||||
uint8_t rxbwmant = (rxbw>>3)&0x03;
|
||||
rxbwmant = 16 + 4*rxbwmant;
|
||||
return SX127X_CRYSTAL_FREQ / ( rxbwmant << (rxbwexp+2));
|
||||
}
|
||||
|
||||
uint8_t SX1278FSK::setAFCBandwidth(float bw)
|
||||
{
|
||||
// TODO: Check if in FSK mode
|
||||
//
|
||||
if(bw<2600 || bw>250000) { return 1; /* invalid */ }
|
||||
|
||||
uint8_t rxbwexp = 1;
|
||||
bw = SX127X_CRYSTAL_FREQ / bw / 8;
|
||||
while(bw>31) { rxbwexp++; bw/=2.0; }
|
||||
uint8_t rxbwmant = bw<17?0 : bw<21? 1:2;
|
||||
|
||||
// set mode to FSK STANDBY
|
||||
writeRegister(REG_OP_MODE, FSK_STANDBY_MODE);
|
||||
|
||||
writeRegister(REG_AFC_BW, rxbwexp | (rxbwmant<<3));
|
||||
return 0;
|
||||
}
|
||||
|
||||
float SX1278FSK::getAFCBandwidth()
|
||||
{
|
||||
uint8_t rxbw = readRegister(REG_AFC_BW);
|
||||
uint8_t rxbwexp = rxbw&0x07;
|
||||
uint8_t rxbwmant = (rxbw>>3)&0x03;
|
||||
rxbwmant = 16 + 4*rxbwmant;
|
||||
return SX127X_CRYSTAL_FREQ / ( rxbwmant << (rxbwexp+2));
|
||||
}
|
||||
|
||||
|
||||
uint8_t SX1278FSK::setFrequency(float freq) {
|
||||
|
||||
// set mode to FSK STANDBY
|
||||
writeRegister(REG_OP_MODE, FSK_STANDBY_MODE);
|
||||
freq += sonde.config.freqofs; // manual frequency correction
|
||||
|
||||
uint32_t frf = freq * 1.0 * (1<<19) / SX127X_CRYSTAL_FREQ;
|
||||
writeRegister(REG_FRF_MSB, (frf&0xff0000)>>16);
|
||||
writeRegister(REG_FRF_MID, (frf&0x00ff00)>>8);
|
||||
writeRegister(REG_FRF_LSB, (frf&0x0000ff));
|
||||
return 0;
|
||||
}
|
||||
|
||||
float SX1278FSK::getFrequency() {
|
||||
uint8_t fmsb = readRegister(REG_FRF_MSB);
|
||||
uint8_t fmid = readRegister(REG_FRF_MID);
|
||||
uint8_t flsb = readRegister(REG_FRF_LSB);
|
||||
return ((fmsb<<16)|(fmid<<8)|flsb) * 1.0 / (1<<19) * SX127X_CRYSTAL_FREQ;
|
||||
}
|
||||
|
||||
|
||||
static int gaintab[]={-999,0,-6,-12,-24,-36,-48,-999};
|
||||
int SX1278FSK::getLNAGain() {
|
||||
int gain = (readRegister(REG_LNA)>>5)&0x07;
|
||||
return gaintab[gain];
|
||||
}
|
||||
uint8_t SX1278FSK::setLNAGain(int gain) {
|
||||
uint8_t g=1;
|
||||
while(gain<gaintab[g] && g<6) {g++; }
|
||||
writeRegister(REG_LNA, g<<5);
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t SX1278FSK::getRxConf() {
|
||||
return readRegister(REG_RX_CONFIG);
|
||||
}
|
||||
uint8_t SX1278FSK::setRxConf(uint8_t conf) {
|
||||
writeRegister(REG_RX_CONFIG, conf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t SX1278FSK::setSyncConf(uint8_t conf, int len, const uint8_t *syncpattern) {
|
||||
int res=0;
|
||||
writeRegister(REG_SYNC_CONFIG, conf);
|
||||
if(len>8) return 1;
|
||||
for(int i=0; i<len; i++) {
|
||||
writeRegister(REG_SYNC_VALUE1+i, syncpattern[i]);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
uint8_t SX1278FSK::getSyncConf() {
|
||||
return sx1278.readRegister(REG_SYNC_CONFIG);
|
||||
}
|
||||
|
||||
uint8_t SX1278FSK::setPreambleDetect(uint8_t conf) {
|
||||
sx1278.writeRegister(REG_PREAMBLE_DETECT, conf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t SX1278FSK::getPreambleDetect() {
|
||||
return sx1278.readRegister(REG_PREAMBLE_DETECT);
|
||||
}
|
||||
|
||||
uint8_t SX1278FSK::setPacketConfig(uint8_t conf1, uint8_t conf2)
|
||||
{
|
||||
uint8_t ret=0;
|
||||
sx1278.writeRegister(REG_PACKET_CONFIG1, conf1);
|
||||
sx1278.writeRegister(REG_PACKET_CONFIG2, conf2);
|
||||
return ret;
|
||||
};
|
||||
uint16_t SX1278FSK::getPacketConfig() {
|
||||
uint8_t c1 = sx1278.readRegister(REG_PACKET_CONFIG1);
|
||||
uint8_t c2 = sx1278.readRegister(REG_PACKET_CONFIG2);
|
||||
return (c2<<8)|c1;
|
||||
}
|
||||
|
||||
/*
|
||||
Function: Gets the preamble length from the module.
|
||||
Returns: preamble length
|
||||
*/
|
||||
uint16_t SX1278FSK::getPreambleLength()
|
||||
{
|
||||
uint16_t p_length;
|
||||
|
||||
#if (SX1278FSK_debug_mode > 1)
|
||||
Serial.println();
|
||||
Serial.println(F("Starting 'getPreambleLength'"));
|
||||
#endif
|
||||
|
||||
p_length = readRegister(REG_PREAMBLE_MSB_FSK);
|
||||
p_length = (p_length<<8) | readRegister(REG_PREAMBLE_LSB_FSK);
|
||||
#if (SX1278FSK_debug_mode > 1)
|
||||
Serial.print(F("## Preamble length configured is "));
|
||||
Serial.print(p_length, HEX);
|
||||
Serial.print(F(" ##"));
|
||||
Serial.println();
|
||||
#endif
|
||||
return p_length;
|
||||
}
|
||||
|
||||
/*
|
||||
Function: Sets the preamble length in the module
|
||||
Returns: Integer that determines if there has been any error
|
||||
state = 2 --> The command has not been executed
|
||||
state = 1 --> There has been an error while executing the command
|
||||
state = 0 --> The command has been executed with no errors
|
||||
Parameters:
|
||||
l: length value to set as preamble length.
|
||||
*/
|
||||
uint8_t SX1278FSK::setPreambleLength(uint16_t l)
|
||||
{
|
||||
byte st0;
|
||||
int8_t state = 2;
|
||||
|
||||
#if (SX1278FSK_debug_mode > 1)
|
||||
Serial.println();
|
||||
Serial.println(F("Starting 'setPreambleLength'"));
|
||||
#endif
|
||||
|
||||
st0 = readRegister(REG_OP_MODE); // Save the previous status
|
||||
|
||||
writeRegister(REG_OP_MODE, FSK_STANDBY_MODE); // Set Standby mode to write in registers
|
||||
// Storing MSB preamble length in FSK mode
|
||||
writeRegister(REG_PREAMBLE_MSB_FSK, l>>8);
|
||||
writeRegister(REG_PREAMBLE_LSB_FSK, l&0xFF);
|
||||
|
||||
state = 0;
|
||||
#if (SX1278FSK_debug_mode > 1)
|
||||
Serial.print(F("## Preamble length "));
|
||||
Serial.print(l, HEX);
|
||||
Serial.println(F(" has been successfully set ##"));
|
||||
Serial.println();
|
||||
#endif
|
||||
|
||||
if(st0 != FSK_STANDBY_MODE) {
|
||||
writeRegister(REG_OP_MODE, st0); // Getting back to previous status
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
||||
/*
|
||||
Function: Gets the payload length from the module.
|
||||
Returns: configured length; -1 on error
|
||||
*/
|
||||
int SX1278FSK::getPayloadLength()
|
||||
{
|
||||
int length;
|
||||
#if (SX1278FSK_debug_mode > 1)
|
||||
Serial.println();
|
||||
Serial.println(F("Starting 'getPayloadLength'"));
|
||||
#endif
|
||||
length = readRegister(REG_PAYLOAD_LENGTH_FSK);
|
||||
|
||||
#if (SX1278FSK_debug_mode > 1)
|
||||
Serial.print(F("## Payload length configured is "));
|
||||
Serial.print(length);
|
||||
Serial.println(F(" ##"));
|
||||
#endif
|
||||
return length;
|
||||
}
|
||||
|
||||
/*
|
||||
Function: Sets the payload length from the module.
|
||||
Returns: 0 for ok, otherwise error
|
||||
// TODO: Larger than 255 bytes?
|
||||
*/
|
||||
uint8_t SX1278FSK::setPayloadLength(int len)
|
||||
{
|
||||
#if (SX1278FSK_debug_mode > 1)
|
||||
Serial.print(F("Starting 'setPayloadLength'"));
|
||||
Serial.println(len);
|
||||
#endif
|
||||
uint8_t conf2 = readRegister(REG_PACKET_CONFIG2);
|
||||
conf2 = (conf2 & 0xF8) | ( (len>>8)&0x7 );
|
||||
writeRegister(REG_PACKET_CONFIG2, conf2);
|
||||
writeRegister(REG_PAYLOAD_LENGTH_FSK, len&0xFF);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
Function: Gets the current value of RSSI.
|
||||
Returns: RSSI value
|
||||
*/
|
||||
int16_t SX1278FSK::getRSSI()
|
||||
{
|
||||
int16_t RSSI;
|
||||
//int rssi_mean = 0;
|
||||
int total = 1;
|
||||
|
||||
/// FSK mode
|
||||
// get mean value of RSSI
|
||||
for(int i = 0; i < total; i++)
|
||||
{
|
||||
RSSI = readRegister(REG_RSSI_VALUE_FSK);
|
||||
//rssi_mean += _RSSI;
|
||||
}
|
||||
//rssi_mean = rssi_mean / total;
|
||||
//RSSI = rssi_mean;
|
||||
|
||||
#if (SX1278FSK_debug_mode > 0)
|
||||
Serial.print(F("## RSSI value is "));
|
||||
Serial.print(RSSI);
|
||||
Serial.println(F(" ##"));
|
||||
#endif
|
||||
return RSSI;
|
||||
}
|
||||
|
||||
/*
|
||||
Function: Gets the current value of FEI (frequency error indication)
|
||||
Returns: FEI value in Hz
|
||||
*/
|
||||
int32_t SX1278FSK::getFEI()
|
||||
{
|
||||
int32_t FEI;
|
||||
int16_t regval = (readRegister(REG_FEI_MSB)<<8) | readRegister(REG_FEI_LSB);
|
||||
//Serial.printf("feireg: %04x\n", regval);
|
||||
FEI = (int32_t)(regval * SX127X_FSTEP);
|
||||
return FEI;
|
||||
}
|
||||
/*
|
||||
Function: Gets the current value of AFC (automated frequency correction)
|
||||
Returns: AFC value in Hz
|
||||
*/
|
||||
int32_t SX1278FSK::getAFC()
|
||||
{
|
||||
int32_t AFC;
|
||||
int16_t regval = (readRegister(REG_AFC_MSB)<<8) | readRegister(REG_AFC_LSB);
|
||||
//Serial.printf("afcreg: %04x\n", regval);
|
||||
AFC = (int32_t)(regval * SX127X_FSTEP);
|
||||
return AFC;
|
||||
}
|
||||
|
||||
/*
|
||||
Function: Gets the current supply limit of the power amplifier, protecting battery chemistries.
|
||||
Returns: Integer that determines if there has been any error
|
||||
state = 2 --> The command has not been executed
|
||||
state = 1 --> There has been an error while executing the command
|
||||
state = 0 --> The command has been executed with no errors
|
||||
Parameters:
|
||||
rate: value to compute the maximum current supply. Maximum current is 45+5*'rate' [mA]
|
||||
*/
|
||||
int SX1278FSK::getMaxCurrent()
|
||||
{
|
||||
int value;
|
||||
|
||||
#if (SX1278FSK_debug_mode > 1)
|
||||
Serial.println();
|
||||
Serial.println(F("Starting 'getMaxCurrent'"));
|
||||
#endif
|
||||
|
||||
value = readRegister(REG_OCP);
|
||||
|
||||
// extract only the OcpTrim value from the OCP register
|
||||
value &= B00011111;
|
||||
|
||||
if( value <= 15 ) {
|
||||
value = (45 + (5 * value));
|
||||
} else if( value <= 27 ) {
|
||||
value = (-30 + (10 * value));
|
||||
} else {
|
||||
value = 240;
|
||||
}
|
||||
#if (SX1278FSK_debug_mode > 1)
|
||||
Serial.print(F("## Maximum current supply configured is "));
|
||||
Serial.print(value, DEC);
|
||||
Serial.println(F(" mA ##"));
|
||||
Serial.println();
|
||||
#endif
|
||||
return value;
|
||||
}
|
||||
|
||||
/*
|
||||
Function: Limits the current supply of the power amplifier, protecting battery chemistries.
|
||||
Returns: Integer that determines if there has been any error
|
||||
state = 2 --> The command has not been executed
|
||||
state = 1 --> There has been an error while executing the command
|
||||
state = 0 --> The command has been executed with no errors
|
||||
state = -1 --> Forbidden parameter value for this function
|
||||
Parameters:
|
||||
rate: value to compute the maximum current supply. Range: 0x00 to 0x1B. The
|
||||
Maximum current is:
|
||||
Imax = 45+5*OcpTrim [mA] if OcpTrim <= 15 (120 mA) /
|
||||
Imax = -30+10*OcpTrim [mA] if 15 < OcpTrim <= 27 (130 to 240 mA)
|
||||
Imax = 240mA for higher settings
|
||||
*/
|
||||
int8_t SX1278FSK::setMaxCurrent(uint8_t rate)
|
||||
{
|
||||
int8_t state = 2;
|
||||
byte st0;
|
||||
|
||||
#if (SX1278FSK_debug_mode > 1)
|
||||
Serial.println();
|
||||
Serial.println(F("Starting 'setMaxCurrent'"));
|
||||
#endif
|
||||
|
||||
// Maximum rate value = 0x1B, because maximum current supply = 240 mA
|
||||
if (rate > 0x1B)
|
||||
{
|
||||
state = -1;
|
||||
#if (SX1278FSK_debug_mode > 1)
|
||||
Serial.print(F("** Maximum current supply is 240 mA, "));
|
||||
Serial.println(F("so maximum parameter value must be 27 (DEC) or 0x1B (HEX) **"));
|
||||
Serial.println();
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
// Enable Over Current Protection
|
||||
rate |= B00100000;
|
||||
|
||||
state = 1;
|
||||
st0 = readRegister(REG_OP_MODE); // Save the previous status
|
||||
writeRegister(REG_OP_MODE, FSK_STANDBY_MODE); // Set FSK Standby mode to write in registers
|
||||
writeRegister(REG_OCP, rate); // Modifying maximum current supply
|
||||
if(st0 != FSK_STANDBY_MODE) {
|
||||
writeRegister(REG_OP_MODE, st0); // Getting back to previous status
|
||||
}
|
||||
state = 0;
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Function: Configures the module to receive information.
|
||||
Returns: Integer that determines if there has been any error
|
||||
state = 2 --> The command has not been executed
|
||||
state = 1 --> There has been an error while executing the command
|
||||
state = 0 --> The command has been executed with no errors
|
||||
*/
|
||||
uint8_t SX1278FSK::receive()
|
||||
{
|
||||
uint8_t state = 1;
|
||||
#if (SX1278FSK_debug_mode > 1)
|
||||
Serial.println();
|
||||
Serial.println(F("Starting 'receive'"));
|
||||
#endif
|
||||
// TODO: Is there anything else to be done?
|
||||
//
|
||||
writeRegister(REG_OP_MODE, FSK_RX_MODE);
|
||||
state = 0;
|
||||
#if (SX1278FSK_debug_mode > 1)
|
||||
Serial.println(F("## Receiving FSK mode activated with success ##"));
|
||||
#endif
|
||||
return state;
|
||||
}
|
||||
|
||||
/*
|
||||
Function: Configures the module to receive a packet
|
||||
Returns: Integer that determines if there has been any error
|
||||
state = 2 --> The command has not been executed
|
||||
state = 1 --> There has been an error while executing the command
|
||||
state = 0 --> The command has been executed with no errors
|
||||
Parameters:
|
||||
wait: timeout in ms
|
||||
data: memory where to place received data
|
||||
*/
|
||||
uint8_t SX1278FSK::receivePacketTimeout(uint32_t wait, byte *data)
|
||||
{
|
||||
int di=0;
|
||||
uint8_t state = 2;
|
||||
unsigned long previous;
|
||||
byte value = 0x00;
|
||||
#if (SX1278FSK_debug_mode > 1)
|
||||
Serial.println();
|
||||
Serial.println(F("Starting 'receivePacketTimeout'"));
|
||||
#endif
|
||||
// set RX mode
|
||||
state = receive();
|
||||
if(state != 0) { return state; }
|
||||
|
||||
#if (SX1278FSK_debug_mode > 0)
|
||||
Serial.println(F("RX mode sucessfully activated"));
|
||||
#endif
|
||||
previous = millis();
|
||||
/// FSK mode
|
||||
value = readRegister(REG_IRQ_FLAGS2);
|
||||
byte ready=0;
|
||||
// while not yet done or FIFO not yet empty
|
||||
while( (!ready || bitRead(value,6)==0) && (millis() - previous < wait) )
|
||||
{
|
||||
if( bitRead(value,2)==1 ) ready=1;
|
||||
if( bitRead(value, 6) == 0 ) { // FIFO not empty
|
||||
data[di++] = readRegister(REG_FIFO);
|
||||
// It's a bit of a hack.... get RSSI and AFC (a) at beginning of packet and
|
||||
// for RS41 after about 0.5 sec. It might be more logical to put this decoder-specific
|
||||
// code into RS41.cpp instead of this file... (maybe TODO?)
|
||||
|
||||
if(di==1 || di==290 ) {
|
||||
int rssi=getRSSI();
|
||||
int afc=getAFC();
|
||||
#if 0
|
||||
Serial.printf("Test(%d): RSSI=%d", rxtask.currentSonde, rssi/2);
|
||||
Serial.print("Test: AFC="); Serial.println(afc);
|
||||
#endif
|
||||
sonde.sondeList[rxtask.currentSonde].rssi = rssi;
|
||||
sonde.sondeList[rxtask.currentSonde].afc = afc;
|
||||
if(rxtask.receiveResult==0xFFFF)
|
||||
rxtask.receiveResult = RX_UPDATERSSI;
|
||||
//sonde.si()->rssi = rssi;
|
||||
//sonde.si()->afc = afc;
|
||||
}
|
||||
if(di>520) {
|
||||
// TODO
|
||||
Serial.println("TOO MUCH DATA");
|
||||
break;
|
||||
}
|
||||
previous = millis(); // reset timeout after receiving data
|
||||
} else {
|
||||
delay(10);
|
||||
}
|
||||
value = readRegister(REG_IRQ_FLAGS2);
|
||||
}
|
||||
if( !ready || bitRead(value, 6)==0) {
|
||||
#if 1&&(SX1278FSK_debug_mode > 0)
|
||||
Serial.println(F("** The timeout has expired **"));
|
||||
Serial.println();
|
||||
#endif
|
||||
sonde.si()->rssi = getRSSI();
|
||||
writeRegister(REG_OP_MODE, FSK_STANDBY_MODE); // Setting standby FSK mode
|
||||
return 1; // TIMEOUT
|
||||
}
|
||||
|
||||
#if (SX1278FSK_debug_mode > 0)
|
||||
Serial.println(F("## Packet received:"));
|
||||
for(unsigned int i = 0; i < di; i++)
|
||||
{
|
||||
Serial.print(data[i], HEX); // Printing payload
|
||||
Serial.print("|");
|
||||
}
|
||||
Serial.println(F(" ##"));
|
||||
#endif
|
||||
state = 0;
|
||||
// Initializing flags
|
||||
clearIRQFlags();
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
/*
|
||||
Function: It gets the temperature from the measurement block module.
|
||||
Returns: Integer that determines if there has been any error
|
||||
state = 2 --> The command has not been executed
|
||||
state = 1 --> There has been an error while executing the command
|
||||
state = 0 --> The command has been executed with no errors
|
||||
*/
|
||||
uint8_t SX1278FSK::getTemp()
|
||||
{
|
||||
byte st0;
|
||||
uint8_t state = 2;
|
||||
|
||||
#if (SX1278FSK_debug_mode > 1)
|
||||
Serial.println();
|
||||
Serial.println(F("Starting 'getTemp'"));
|
||||
#endif
|
||||
|
||||
st0 = readRegister(REG_OP_MODE); // Save the previous status
|
||||
|
||||
if( _modem == LORA )
|
||||
{ // Allowing access to FSK registers while in LoRa standby mode
|
||||
writeRegister(REG_OP_MODE, LORA_STANDBY_FSK_REGS_MODE);
|
||||
}
|
||||
|
||||
state = 1;
|
||||
// Saving temperature value
|
||||
_temp = readRegister(REG_TEMP);
|
||||
if( _temp & 0x80 ) // The SNR sign bit is 1
|
||||
{
|
||||
// Invert and divide by 4
|
||||
_temp = ( ( ~_temp + 1 ) & 0xFF );
|
||||
}
|
||||
else
|
||||
{
|
||||
// Divide by 4
|
||||
_temp = ( _temp & 0xFF );
|
||||
}
|
||||
|
||||
|
||||
#if (SX1278FSK_debug_mode > 1)
|
||||
Serial.print(F("## Temperature is: "));
|
||||
Serial.print(_temp);
|
||||
Serial.println(F(" ##"));
|
||||
Serial.println();
|
||||
#endif
|
||||
|
||||
if( _modem == LORA )
|
||||
{
|
||||
writeRegister(REG_OP_MODE, st0); // Getting back to previous status
|
||||
}
|
||||
|
||||
state = 0;
|
||||
return state;
|
||||
}
|
||||
|
||||
/*
|
||||
Function: It prints the registers related to RX
|
||||
Returns: Integer that determines if there has been any error
|
||||
state = 2 --> The command has not been executed
|
||||
state = 1 --> There has been an error while executing the command
|
||||
state = 0 --> The command has been executed with no errors
|
||||
*/
|
||||
void SX1278FSK::showRxRegisters()
|
||||
{
|
||||
Serial.println(F("\n--- Show RX register ---"));
|
||||
|
||||
// variable
|
||||
byte reg;
|
||||
|
||||
for(int i = 0x00; i < 0x80; i++)
|
||||
{
|
||||
reg = readRegister(i);
|
||||
Serial.print(F("Reg 0x"));
|
||||
Serial.print(i, HEX);
|
||||
Serial.print(F(":"));
|
||||
Serial.print(reg, HEX);
|
||||
Serial.println();
|
||||
delay(100);
|
||||
}
|
||||
|
||||
Serial.println(F("------------------------"));
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
SX1278FSK sx1278 = SX1278FSK();
|
||||
Executable
+278
@@ -0,0 +1,278 @@
|
||||
/*
|
||||
* Functions for using SX127x in FSK mode (mainly receive)
|
||||
* Copyright (C) 2019 Hansi Reiser, dl9rdz
|
||||
*
|
||||
* Partially based on the SX1278 libraray for managing Semtech modules
|
||||
* Copyright (C) 2015 Wireless Open Source
|
||||
* http://wirelessopensource.com
|
||||
*
|
||||
* SPDX-License-Identifier: LGPL-2.1+
|
||||
*/
|
||||
|
||||
#ifndef SX1278FSK_h
|
||||
#define SX1278FSK_h
|
||||
|
||||
/******************************************************************************
|
||||
* Includes
|
||||
******************************************************************************/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <Arduino.h>
|
||||
#include <SPI.h>
|
||||
|
||||
#ifndef inttypes_h
|
||||
#include <inttypes.h>
|
||||
#endif
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* Definitions & Declarations
|
||||
*****************************************************************************/
|
||||
|
||||
#define SX127X_CRYSTAL_FREQ 32000000
|
||||
#define SX127X_FSTEP (SX127X_CRYSTAL_FREQ*1.0/(1<<19))
|
||||
|
||||
#define SX1278FSK_debug_mode 0
|
||||
|
||||
#define SX1278_SS SS
|
||||
|
||||
//! MACROS //
|
||||
#define bitRead(value, bit) (((value) >> (bit)) & 0x01) // read a bit
|
||||
#define bitSet(value, bit) ((value) |= (1UL << (bit))) // set bit to '1'
|
||||
#define bitClear(value, bit) ((value) &= ~(1UL << (bit))) // set bit to '0'
|
||||
|
||||
|
||||
//! REGISTERS //
|
||||
// FSK Commun LORA
|
||||
#define REG_FIFO 0x00
|
||||
#define REG_OP_MODE 0x01
|
||||
#define REG_BITRATE_MSB 0x02
|
||||
#define REG_BITRATE_LSB 0x03
|
||||
#define REG_FDEV_MSB 0x04
|
||||
#define REG_FDEV_LSB 0x05
|
||||
#define REG_FRF_MSB 0x06
|
||||
#define REG_FRF_MID 0x07
|
||||
#define REG_FRF_LSB 0x08
|
||||
#define REG_PA_CONFIG 0x09
|
||||
#define REG_PA_RAMP 0x0A
|
||||
#define REG_OCP 0x0B
|
||||
#define REG_LNA 0x0C
|
||||
#define REG_RX_CONFIG 0x0D
|
||||
#define REG_FIFO_ADDR_PTR 0x0D
|
||||
#define REG_RSSI_CONFIG 0x0E
|
||||
#define REG_FIFO_TX_BASE_ADDR 0x0E
|
||||
#define REG_RSSI_COLLISION 0x0F
|
||||
#define REG_FIFO_RX_BASE_ADDR 0x0F
|
||||
#define REG_RSSI_THRESH 0x10
|
||||
#define REG_FIFO_RX_CURRENT_ADDR 0x10
|
||||
#define REG_RSSI_VALUE_FSK 0x11
|
||||
#define REG_IRQ_FLAGS_MASK 0x11
|
||||
#define REG_RX_BW 0x12
|
||||
#define REG_IRQ_FLAGS 0x12
|
||||
#define REG_AFC_BW 0x13
|
||||
#define REG_RX_NB_BYTES 0x13
|
||||
#define REG_OOK_PEAK 0x14
|
||||
#define REG_RX_HEADER_CNT_VALUE_MSB 0x14
|
||||
#define REG_OOK_FIX 0x15
|
||||
#define REG_RX_HEADER_CNT_VALUE_LSB 0x15
|
||||
#define REG_OOK_AVG 0x16
|
||||
#define REG_RX_PACKET_CNT_VALUE_MSB 0x16
|
||||
#define REG_RX_PACKET_CNT_VALUE_LSB 0x17
|
||||
#define REG_MODEM_STAT 0x18
|
||||
#define REG_PKT_SNR_VALUE 0x19
|
||||
#define REG_AFC_FEI 0x1A
|
||||
#define REG_PKT_RSSI_VALUE 0x1A
|
||||
#define REG_AFC_MSB 0x1B
|
||||
#define REG_RSSI_VALUE_LORA 0x1B
|
||||
#define REG_AFC_LSB 0x1C
|
||||
#define REG_HOP_CHANNEL 0x1C
|
||||
#define REG_FEI_MSB 0x1D
|
||||
#define REG_MODEM_CONFIG1 0x1D
|
||||
#define REG_FEI_LSB 0x1E
|
||||
#define REG_MODEM_CONFIG2 0x1E
|
||||
#define REG_PREAMBLE_DETECT 0x1F
|
||||
#define REG_SYMB_TIMEOUT_LSB 0x1F
|
||||
#define REG_RX_TIMEOUT1 0x20
|
||||
#define REG_PREAMBLE_MSB_LORA 0x20
|
||||
#define REG_RX_TIMEOUT2 0x21
|
||||
#define REG_PREAMBLE_LSB_LORA 0x21
|
||||
#define REG_RX_TIMEOUT3 0x22
|
||||
#define REG_PAYLOAD_LENGTH_LORA 0x22
|
||||
#define REG_RX_DELAY 0x23
|
||||
#define REG_MAX_PAYLOAD_LENGTH 0x23
|
||||
#define REG_OSC 0x24
|
||||
#define REG_HOP_PERIOD 0x24
|
||||
#define REG_PREAMBLE_MSB_FSK 0x25
|
||||
#define REG_FIFO_RX_BYTE_ADDR 0x25
|
||||
#define REG_PREAMBLE_LSB_FSK 0x26
|
||||
#define REG_MODEM_CONFIG3 0x26
|
||||
#define REG_SYNC_CONFIG 0x27
|
||||
#define REG_SYNC_VALUE1 0x28
|
||||
#define REG_LORA_FEI_MSB 0x28
|
||||
#define REG_SYNC_VALUE2 0x29
|
||||
#define REG_LORA_FEI_MID 0x29
|
||||
#define REG_SYNC_VALUE3 0x2A
|
||||
#define REG_LORA_FEI_LSB 0x2A
|
||||
#define REG_SYNC_VALUE4 0x2B
|
||||
#define REG_SYNC_VALUE5 0x2C
|
||||
#define REG_RSSI_WIDEBAND 0x2C
|
||||
#define REG_SYNC_VALUE6 0x2D
|
||||
#define REG_SYNC_VALUE7 0x2E
|
||||
#define REG_SYNC_VALUE8 0x2F
|
||||
#define REG_PACKET_CONFIG1 0x30
|
||||
#define REG_PACKET_CONFIG2 0x31
|
||||
#define REG_DETECT_OPTIMIZE 0x31
|
||||
#define REG_PAYLOAD_LENGTH_FSK 0x32
|
||||
#define REG_NODE_ADRS 0x33
|
||||
#define REG_INVERT_IQ 0x33
|
||||
#define REG_BROADCAST_ADRS 0x34
|
||||
#define REG_FIFO_THRESH 0x35
|
||||
#define REG_SEQ_CONFIG1 0x36
|
||||
#define REG_SEQ_CONFIG2 0x37
|
||||
#define REG_DETECTION_THRESHOLD 0x37
|
||||
#define REG_TIMER_RESOL 0x38
|
||||
#define REG_TIMER1_COEF 0x39
|
||||
#define REG_SYNC_WORD 0x39
|
||||
#define REG_TIMER2_COEF 0x3A
|
||||
#define REG_IMAGE_CAL 0x3B
|
||||
#define REG_TEMP 0x3C
|
||||
#define REG_LOW_BAT 0x3D
|
||||
#define REG_IRQ_FLAGS1 0x3E
|
||||
#define REG_IRQ_FLAGS2 0x3F
|
||||
#define REG_DIO_MAPPING1 0x40
|
||||
#define REG_DIO_MAPPING2 0x41
|
||||
#define REG_VERSION 0x42
|
||||
#define REG_PLL_HOP 0x44
|
||||
#define REG_TCXO 0x4B
|
||||
#define REG_PA_DAC 0x4D
|
||||
#define REG_FORMER_TEMP 0x5B
|
||||
#define REG_BIT_RATE_FRAC 0x5D
|
||||
#define REG_AGC_REF 0x61
|
||||
#define REG_AGC_THRESH1 0x62
|
||||
#define REG_AGC_THRESH2 0x63
|
||||
#define REG_AGC_THRESH3 0x64
|
||||
#define REG_PLL 0x70
|
||||
|
||||
|
||||
//FSK MODES:
|
||||
const uint8_t FSK_SLEEP_MODE = 0x00;
|
||||
const uint8_t FSK_STANDBY_MODE = 0x01;
|
||||
const uint8_t FSK_TX_MODE = 0x03;
|
||||
const uint8_t FSK_RX_MODE = 0x05;
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* SX1278FSK Class
|
||||
* Functions and variables for managing SX127x transceiver chips in FSK mode,
|
||||
* mainly for receiving radiosonde transmissions
|
||||
******************************************************************************/
|
||||
class SX1278FSK
|
||||
{
|
||||
public:
|
||||
// class constructor
|
||||
SX1278FSK();
|
||||
|
||||
// Turn on SX1278 module (return 0 on sucess, 1 otherwise)
|
||||
uint8_t ON();
|
||||
|
||||
// Turn off SX1278 module
|
||||
void OFF();
|
||||
|
||||
// Read internal register
|
||||
byte readRegister(byte address);
|
||||
|
||||
// Write internal register
|
||||
void writeRegister(byte address, byte data);
|
||||
|
||||
// Clear IRQ flags
|
||||
void clearIRQFlags();
|
||||
|
||||
// Activate FSK mode (return 0 on success, 1 otherwise)
|
||||
uint8_t setFSK();
|
||||
|
||||
// Configures bitrate register (closest approximation to requested bitrate)
|
||||
uint8_t setBitrate(float bps);
|
||||
float getBitrate();
|
||||
|
||||
// Configures RX bandwidth (next largest supported bandwith if exact value not possible)
|
||||
uint8_t setRxBandwidth(float bps);
|
||||
float getRxBandwidth();
|
||||
|
||||
// Configures AFC bandwidth (next largest supported bandwith if exact value not possible)
|
||||
uint8_t setAFCBandwidth(float bps);
|
||||
float getAFCBandwidth();
|
||||
|
||||
// Configures RX frequency (closest approximation to requested frequency)
|
||||
uint8_t setFrequency(float freq);
|
||||
float getFrequency();
|
||||
|
||||
int getLNAGain();
|
||||
uint8_t setLNAGain(int gain);
|
||||
|
||||
uint8_t getRxConf();
|
||||
uint8_t setRxConf(uint8_t conf);
|
||||
|
||||
uint8_t setSyncConf(uint8_t conf, int len, const uint8_t *syncpattern);
|
||||
uint8_t getSyncConf();
|
||||
|
||||
uint8_t setPreambleDetect(uint8_t conf);
|
||||
uint8_t getPreambleDetect();
|
||||
|
||||
uint8_t setPacketConfig(uint8_t conf1, uint8_t conf2);
|
||||
uint16_t getPacketConfig();
|
||||
|
||||
// Get configured preamble length (used for TX only?)
|
||||
uint16_t getPreambleLength();
|
||||
|
||||
// Sets the preamble length.
|
||||
uint8_t setPreambleLength(uint16_t l);
|
||||
|
||||
// Gets the payload length (expected length for receive)
|
||||
int getPayloadLength();
|
||||
uint8_t setPayloadLength(int len);
|
||||
|
||||
// Get current RSSI value
|
||||
int16_t getRSSI();
|
||||
|
||||
// Get current FEI (frequency error indication) value
|
||||
int32_t getFEI();
|
||||
|
||||
// Get current AFC value
|
||||
int32_t getAFC();
|
||||
|
||||
// Get the maximum current supply by the module.
|
||||
int getMaxCurrent();
|
||||
|
||||
// Set the maximum current supply by the module.
|
||||
int8_t setMaxCurrent(uint8_t rate);
|
||||
|
||||
// Put the module in reception mode.
|
||||
//return '0' on success, '1' otherwise
|
||||
uint8_t receive();
|
||||
|
||||
// Receive a packet
|
||||
uint8_t receivePacketTimeout(uint32_t wait, byte *data);
|
||||
|
||||
|
||||
|
||||
#if 0
|
||||
//! It gets the internal temperature of the module.
|
||||
/*!
|
||||
It stores in global '_temp' variable the module temperature.
|
||||
\return '0' on success, '1' otherwise
|
||||
*/
|
||||
uint8_t getTemp();
|
||||
|
||||
//! It prints the registers related to RX via USB
|
||||
/*!
|
||||
* \return void
|
||||
*/
|
||||
void showRxRegisters();
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
extern SX1278FSK sx1278;
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user