#include "sx127x_registers.h" #include "sx127x_internal.h" #include esp_err_t sx127x_read_register(sx127x_t *handle, uint8_t reg, uint8_t *value) { return sx127x_single_transfer(handle, reg & 0x7f, 0x00, value); } esp_err_t sx127x_write_register(sx127x_t *handle, uint8_t reg, uint8_t value) { return sx127x_single_transfer(handle, reg | 0x80, value, NULL); } esp_err_t sx127x_single_transfer(sx127x_t *handle, uint8_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; esp_err_t ret = spi_device_transmit(handle->device_handle, &trans); 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 *handle) { return sx127x_write_register(handle, REG_OP_MODE, SX127X_LONG_RANGE | SX127X_MODE_SLEEP); } esp_err_t sx127x_standby(sx127x_t *handle) { return sx127x_write_register(handle, REG_OP_MODE, SX127X_LONG_RANGE | SX127X_MODE_STDBY); } esp_err_t sx127x_set_frequency(sx127x_t *handle, uint64_t frequency) { uint64_t frf = ((uint64_t)frequency << 19) / 32000000; esp_err_t ret; ret = sx127x_write_register(handle, REG_FRF_MSB, (uint8_t)(frf)); SX127X_ERROR_CHECK(ret); frf >>= 8; ret = sx127x_write_register(handle, REG_FRF_MID, (uint8_t)(frf)); SX127X_ERROR_CHECK(ret); frf >>= 8; ret = sx127x_write_register(handle, REG_FRF_LSB, (uint8_t)(frf)); SX127X_ERROR_CHECK(ret); handle->config.frequency = frequency; return ESP_OK; } esp_err_t sx127x_set_tx_power(sx127x_t *handle, 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(handle, REG_PA_CONFIG, 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(handle, REG_PA_CONFIG, 0x70 | tx_power); } SX127X_ERROR_CHECK(ret); handle->config.tx_power = tx_power; return ESP_OK; } esp_err_t sx127x_set_spreading_factor(sx127x_t *handle, 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(handle, REG_DETECTION_OPTIMIZE, detection_optimize)); SX127X_ERROR_CHECK(sx127x_write_register(handle, REG_DETECTION_THRESHOLD, detection_threshold)); uint8_t modem_config_3; SX127X_ERROR_CHECK(sx127x_read_register(handle, REG_MODEM_CONFIG_3, &modem_config_3)); modem_config_3 = (modem_config_3 & 0x03) | ((spreading_factor << 4) & 0xf0); SX127X_ERROR_CHECK(sx127x_write_register(handle, REG_MODEM_CONFIG_3, modem_config_3)); handle->config.spreading_factor = spreading_factor; return ESP_OK; } esp_err_t sx127x_set_signal_bandwidth(sx127x_t *handle, 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(handle, REG_MODEM_CONFIG_1, &modem_config_1)); modem_config_1 = (modem_config_1 & 0x0f) | (bw_reg << 4); SX127X_ERROR_CHECK(sx127x_write_register(handle, REG_MODEM_CONFIG_1, modem_config_1)); handle->config.signal_bandwidth = signal_bandwidth; // set low data rate optimization flag uint64_t bw = sx127x_reg_to_bw(bw_reg); uint8_t sf = handle->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 || (handle->config.ldo == SX127X_LDO_ENABLED); uint8_t modem_config_3; SX127X_ERROR_CHECK(sx127x_read_register(handle, 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(handle, 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 *handle, uint8_t sync_word) { SX127X_ERROR_CHECK(sx127x_write_register(handle, REG_SYNC_WORD, sync_word)); handle->config.sync_word = sync_word; return ESP_OK; } esp_err_t sx127x_set_crc(sx127x_t *handle, sx127x_crc_t crc) { uint8_t modem_config_2; SX127X_ERROR_CHECK(sx127x_read_register(handle, REG_MODEM_CONFIG_2, &modem_config_2)); if (crc == SX127X_CRC_ENABLED) { modem_config_2 |= CONFIG2_CRC; } else { modem_config_2 &= ~CONFIG2_CRC; } SX127X_ERROR_CHECK(sx127x_write_register(handle, REG_MODEM_CONFIG_2, modem_config_2)); handle->config.crc = crc; return ESP_OK; } esp_err_t sx127x_write_fifo(sx127x_t *handle, char *data, size_t data_len) { spi_transaction_t trans; memset(&trans, 0, sizeof(trans)); trans.flags = SPI_TRANS_USE_RXDATA; trans.addr = REG_FIFO; trans.length = 8 * data_len; trans.rxlength = 0; trans.tx_buffer = data; esp_err_t ret = spi_device_transmit(handle->device_handle, &trans); SX127X_ERROR_CHECK2(ret, spi_device_transmit); ESP_LOGV(SX127X_TAG, "sx127x_write_fifo(%.*s)", data_len, data); return ESP_OK; }