297 lines
9.6 KiB
C
297 lines
9.6 KiB
C
#include "sx127x_registers.h"
|
|
#include "sx127x_internal.h"
|
|
|
|
#include <string.h>
|
|
|
|
esp_err_t sx127x_read_register(sx127x_t *hndl, sx127x_reg_t reg,
|
|
uint8_t *value) {
|
|
return sx127x_single_transfer(hndl, reg & 0x7f, 0x00, value);
|
|
}
|
|
|
|
esp_err_t sx127x_write_register(sx127x_t *hndl, sx127x_reg_t reg,
|
|
uint8_t value) {
|
|
return sx127x_single_transfer(hndl, reg | 0x80, value, NULL);
|
|
}
|
|
|
|
esp_err_t sx127x_single_transfer(sx127x_t *hndl, sx127x_reg_t addr,
|
|
uint8_t to_slave, uint8_t *from_slave) {
|
|
spi_transaction_t trans;
|
|
memset(&trans, 0, sizeof(trans));
|
|
trans.flags = SPI_TRANS_USE_RXDATA | SPI_TRANS_USE_TXDATA;
|
|
trans.addr = addr;
|
|
trans.length = 8;
|
|
trans.rxlength = 8;
|
|
trans.tx_data[0] = to_slave;
|
|
|
|
BaseType_t pdRet = xSemaphoreTake(hndl->spi_mutex, SX127X_MUTEX_TIMOUT);
|
|
if (pdRet != pdTRUE) {
|
|
ESP_LOGE(SX127X_TAG, "timeout on spi_mutex");
|
|
return ESP_ERR_TIMEOUT;
|
|
}
|
|
esp_err_t ret = spi_device_transmit(hndl->device_handle, &trans);
|
|
xSemaphoreGive(hndl->spi_mutex);
|
|
SX127X_ERROR_CHECK2(ret, spi_device_transmit);
|
|
if (from_slave) {
|
|
*from_slave = trans.rx_data[0];
|
|
}
|
|
ESP_LOGV(SX127X_TAG, "sx127x_single_transfer(%#x, %#x, %#x)", addr,
|
|
trans.tx_data[0], trans.rx_data[0]);
|
|
return ESP_OK;
|
|
}
|
|
|
|
esp_err_t sx127x_sleep(sx127x_t *hndl) {
|
|
return sx127x_write_register(hndl, SX127X_REG_OP_MODE,
|
|
SX127X_LONG_RANGE | SX127X_MODE_SLEEP);
|
|
}
|
|
|
|
esp_err_t sx127x_standby(sx127x_t *hndl) {
|
|
return sx127x_write_register(hndl, SX127X_REG_OP_MODE,
|
|
SX127X_LONG_RANGE | SX127X_MODE_STDBY);
|
|
}
|
|
|
|
esp_err_t sx127x_set_frequency(sx127x_t *hndl, uint64_t frequency) {
|
|
uint64_t frf = ((uint64_t)frequency << 19) / 32000000;
|
|
esp_err_t ret;
|
|
|
|
ret = sx127x_write_register(hndl, SX127X_REG_FRF_MSB, (uint8_t)(frf));
|
|
SX127X_ERROR_CHECK(ret);
|
|
frf >>= 8;
|
|
ret = sx127x_write_register(hndl, SX127X_REG_FRF_MID, (uint8_t)(frf));
|
|
SX127X_ERROR_CHECK(ret);
|
|
frf >>= 8;
|
|
ret = sx127x_write_register(hndl, SX127X_REG_FRF_LSB, (uint8_t)(frf));
|
|
SX127X_ERROR_CHECK(ret);
|
|
|
|
hndl->config.frequency = frequency;
|
|
return ESP_OK;
|
|
}
|
|
|
|
esp_err_t sx127x_set_tx_power(sx127x_t *hndl, uint8_t tx_power,
|
|
sx127x_pa_boost_t pa_boost) {
|
|
esp_err_t ret;
|
|
if (pa_boost == SX127X_PA_BOOST_ENABLED) {
|
|
// PA BOOST
|
|
SX127X_CHECK(tx_power >= 2 && tx_power <= 20, "invalid tx_power: %d",
|
|
ESP_ERR_INVALID_ARG, tx_power);
|
|
ret = sx127x_write_register(hndl, SX127X_REG_PA_CONFIG,
|
|
SX127X_PA_BOOST | (tx_power - 2));
|
|
} else {
|
|
// RFO
|
|
SX127X_CHECK(tx_power <= 14, "invalid tx_power: %d", ESP_ERR_INVALID_ARG,
|
|
tx_power);
|
|
ret = sx127x_write_register(hndl, SX127X_REG_PA_CONFIG, 0x70 | tx_power);
|
|
}
|
|
SX127X_ERROR_CHECK(ret);
|
|
|
|
hndl->config.tx_power = tx_power;
|
|
return ESP_OK;
|
|
}
|
|
|
|
esp_err_t sx127x_set_spreading_factor(sx127x_t *hndl,
|
|
uint8_t spreading_factor) {
|
|
SX127X_CHECK(spreading_factor >= 6 && spreading_factor <= 12,
|
|
"invalid spreading_factor", ESP_ERR_INVALID_ARG);
|
|
// section 4.1.1.2 in SX1276 datasheet
|
|
uint8_t detection_optimize, detection_threshold;
|
|
if (spreading_factor == 6) {
|
|
detection_optimize = 0xc5;
|
|
detection_threshold = 0x0c;
|
|
} else {
|
|
detection_optimize = 0xc3;
|
|
detection_threshold = 0x0a;
|
|
}
|
|
SX127X_ERROR_CHECK(sx127x_write_register(hndl, SX127X_REG_DETECTION_OPTIMIZE,
|
|
detection_optimize));
|
|
SX127X_ERROR_CHECK(sx127x_write_register(hndl, SX127X_REG_DETECTION_THRESHOLD,
|
|
detection_threshold));
|
|
|
|
uint8_t modem_config_3;
|
|
SX127X_ERROR_CHECK(
|
|
sx127x_read_register(hndl, SX127X_REG_MODEM_CONFIG_3, &modem_config_3));
|
|
modem_config_3 = (modem_config_3 & 0x03) | ((spreading_factor << 4) & 0xf0);
|
|
SX127X_ERROR_CHECK(
|
|
sx127x_write_register(hndl, SX127X_REG_MODEM_CONFIG_3, modem_config_3));
|
|
|
|
hndl->config.spreading_factor = spreading_factor;
|
|
return ESP_OK;
|
|
}
|
|
|
|
esp_err_t sx127x_set_signal_bandwidth(sx127x_t *hndl,
|
|
uint64_t signal_bandwidth) {
|
|
uint8_t bw_reg = sx127x_bw_to_reg(signal_bandwidth);
|
|
uint8_t modem_config_1;
|
|
SX127X_ERROR_CHECK(
|
|
sx127x_read_register(hndl, SX127X_REG_MODEM_CONFIG_1, &modem_config_1));
|
|
modem_config_1 = (modem_config_1 & 0x0f) | (bw_reg << 4);
|
|
SX127X_ERROR_CHECK(
|
|
sx127x_write_register(hndl, SX127X_REG_MODEM_CONFIG_1, modem_config_1));
|
|
hndl->config.signal_bandwidth = signal_bandwidth;
|
|
|
|
// set low data rate optimization flag
|
|
uint64_t bw = sx127x_reg_to_bw(bw_reg);
|
|
uint8_t sf = hndl->config.spreading_factor;
|
|
// section 4.1.1.5
|
|
uint64_t symbol_duration_ms = 1000 / (bw / (1L << sf));
|
|
|
|
// section 4.1.1.6
|
|
bool must_have_ldo = (symbol_duration_ms > 16);
|
|
bool ldo = must_have_ldo || (hndl->config.ldo == SX127X_LDO_ENABLED);
|
|
|
|
uint8_t modem_config_3;
|
|
SX127X_ERROR_CHECK(
|
|
sx127x_read_register(hndl, SX127X_REG_MODEM_CONFIG_3, &modem_config_3));
|
|
if (ldo) {
|
|
modem_config_3 |= (1 << 3);
|
|
} else {
|
|
modem_config_3 &= ~(1 << 3);
|
|
}
|
|
SX127X_ERROR_CHECK(
|
|
sx127x_write_register(hndl, SX127X_REG_MODEM_CONFIG_3, modem_config_3));
|
|
|
|
return ESP_OK;
|
|
}
|
|
|
|
uint8_t sx127x_bw_to_reg(uint64_t bandwidth) {
|
|
if (bandwidth <= 7.8E3) {
|
|
return 0;
|
|
} else if (bandwidth <= 10.4E3) {
|
|
return 1;
|
|
} else if (bandwidth <= 15.6E3) {
|
|
return 2;
|
|
} else if (bandwidth <= 20.8E3) {
|
|
return 3;
|
|
} else if (bandwidth <= 31.25E3) {
|
|
return 4;
|
|
} else if (bandwidth <= 41.7E3) {
|
|
return 5;
|
|
} else if (bandwidth <= 62.5E3) {
|
|
return 6;
|
|
} else if (bandwidth <= 125E3) {
|
|
return 7;
|
|
} else if (bandwidth <= 250E3) {
|
|
return 8;
|
|
} else /* if (bandwidth <= 500E3) */ {
|
|
return 9;
|
|
}
|
|
}
|
|
|
|
uint64_t sx127x_reg_to_bw(uint8_t bandwidth_reg) {
|
|
switch (bandwidth_reg) {
|
|
case 0: return 7.8E3;
|
|
case 1: return 10.4E3;
|
|
case 2: return 15.6E3;
|
|
case 3: return 20.8E3;
|
|
case 4: return 31.25E3;
|
|
case 5: return 41.7E3;
|
|
case 6: return 62.5E3;
|
|
case 7: return 125E3;
|
|
case 8: return 250E3;
|
|
default:
|
|
case 9: return 500E3;
|
|
}
|
|
}
|
|
|
|
esp_err_t sx127x_set_sync_word(sx127x_t *hndl, uint8_t sync_word) {
|
|
SX127X_ERROR_CHECK(
|
|
sx127x_write_register(hndl, SX127X_REG_SYNC_WORD, sync_word));
|
|
hndl->config.sync_word = sync_word;
|
|
return ESP_OK;
|
|
}
|
|
|
|
esp_err_t sx127x_set_crc(sx127x_t *hndl, sx127x_crc_t crc) {
|
|
uint8_t modem_config_2;
|
|
SX127X_ERROR_CHECK(
|
|
sx127x_read_register(hndl, SX127X_REG_MODEM_CONFIG_2, &modem_config_2));
|
|
if (crc == SX127X_CRC_ENABLED) {
|
|
modem_config_2 |= SX127X_CONFIG2_CRC;
|
|
} else {
|
|
modem_config_2 &= ~SX127X_CONFIG2_CRC;
|
|
}
|
|
SX127X_ERROR_CHECK(
|
|
sx127x_write_register(hndl, SX127X_REG_MODEM_CONFIG_2, modem_config_2));
|
|
hndl->config.crc = crc;
|
|
return ESP_OK;
|
|
}
|
|
|
|
esp_err_t sx127x_read_pkt_rssi(sx127x_t *hndl, int32_t *rssi) {
|
|
SX127X_CHECK(rssi != NULL, "rssi can not be NULL", ESP_ERR_INVALID_ARG);
|
|
uint8_t rssi_val;
|
|
uint64_t freq = hndl->config.frequency;
|
|
int32_t min_rssi = (freq < 868E6) ? -164 : -157;
|
|
SX127X_ERROR_CHECK(
|
|
sx127x_read_register(hndl, SX127X_REG_PKT_RSSI_VALUE, &rssi_val))
|
|
*rssi = min_rssi + rssi_val;
|
|
return ESP_OK;
|
|
}
|
|
|
|
esp_err_t sx127x_read_pkt_snr(sx127x_t *hndl, int8_t *snr) {
|
|
SX127X_CHECK(snr != NULL, "rssi can not be NULL", ESP_ERR_INVALID_ARG);
|
|
int8_t snr_val;
|
|
SX127X_ERROR_CHECK(
|
|
sx127x_read_register(hndl, SX127X_REG_PKT_SNR_VALUE, (uint8_t *)&snr_val))
|
|
*snr = snr_val;
|
|
return ESP_OK;
|
|
}
|
|
|
|
esp_err_t sx127x_read_rssi(sx127x_t *hndl, int32_t *rssi) {
|
|
SX127X_CHECK(rssi != NULL, "rssi can not be NULL", ESP_ERR_INVALID_ARG);
|
|
uint8_t rssi_val;
|
|
uint64_t freq = hndl->config.frequency;
|
|
int32_t min_rssi = (freq < 868E6) ? -164 : -157;
|
|
SX127X_ERROR_CHECK(
|
|
sx127x_read_register(hndl, SX127X_REG_RSSI_VALUE, &rssi_val))
|
|
*rssi = min_rssi + rssi_val;
|
|
return ESP_OK;
|
|
}
|
|
|
|
esp_err_t sx127x_read_lna_gain(sx127x_t *hndl, uint8_t *lna_gain) {
|
|
SX127X_CHECK(lna_gain != NULL, "rssi can not be NULL", ESP_ERR_INVALID_ARG);
|
|
uint8_t lna_val;
|
|
SX127X_ERROR_CHECK(sx127x_read_register(hndl, SX127X_REG_LNA, &lna_val))
|
|
*lna_gain = (lna_val >> 4) & 0x07;
|
|
return ESP_OK;
|
|
}
|
|
|
|
esp_err_t sx127x_write_fifo(sx127x_t *hndl, const uint8_t *data, size_t data_len) {
|
|
spi_transaction_t trans;
|
|
memset(&trans, 0, sizeof(trans));
|
|
trans.flags = 0;
|
|
trans.addr = SX127X_REG_FIFO | 0x80;
|
|
trans.length = 8 * data_len;
|
|
trans.tx_buffer = data;
|
|
trans.rxlength = 0;
|
|
trans.rx_buffer = NULL;
|
|
|
|
BaseType_t pdRet = xSemaphoreTake(hndl->spi_mutex, SX127X_MUTEX_TIMOUT);
|
|
if (pdRet != pdTRUE) {
|
|
ESP_LOGE(SX127X_TAG, "timeout on spi_mutex");
|
|
return ESP_ERR_TIMEOUT;
|
|
}
|
|
esp_err_t ret = spi_device_transmit(hndl->device_handle, &trans);
|
|
xSemaphoreGive(hndl->spi_mutex);
|
|
SX127X_ERROR_CHECK2(ret, spi_device_transmit);
|
|
ESP_LOGV(SX127X_TAG, "sx127x_write_fifo(%.*s)", data_len, data);
|
|
return ESP_OK;
|
|
}
|
|
|
|
esp_err_t sx127x_read_fifo(sx127x_t *hndl, uint8_t *data_out, size_t data_len) {
|
|
spi_transaction_t trans;
|
|
memset(&trans, 0, sizeof(trans));
|
|
trans.flags = 0;
|
|
trans.addr = SX127X_REG_FIFO;
|
|
trans.length = 8 * data_len;
|
|
trans.tx_buffer = NULL;
|
|
trans.rxlength = 8 * data_len;
|
|
trans.rx_buffer = data_out;
|
|
|
|
BaseType_t pdRet = xSemaphoreTake(hndl->spi_mutex, SX127X_MUTEX_TIMOUT);
|
|
if (pdRet != pdTRUE) {
|
|
ESP_LOGE(SX127X_TAG, "timeout on spi_mutex");
|
|
return ESP_ERR_TIMEOUT;
|
|
}
|
|
esp_err_t ret = spi_device_transmit(hndl->device_handle, &trans);
|
|
xSemaphoreGive(hndl->spi_mutex);
|
|
SX127X_ERROR_CHECK2(ret, spi_device_transmit);
|
|
ESP_LOGV(SX127X_TAG, "sx127x_read_fifo(%.*s)", data_len, data_out);
|
|
return ESP_OK;
|
|
} |