Refactor sx127x_driver into a component
This commit is contained in:
		
							parent
							
								
									1c5fbd725a
								
							
						
					
					
						commit
						85f816850b
					
				
							
								
								
									
										8
									
								
								components/sx127x_driver/CMakeLists.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								components/sx127x_driver/CMakeLists.txt
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,8 @@ | |||||||
|  | set(COMPONENT_SRCS | ||||||
|  |     "sx127x_driver.c" | ||||||
|  |     "sx127x_registers.c") | ||||||
|  | set(COMPONENT_ADD_INCLUDEDIRS ".") | ||||||
|  | 
 | ||||||
|  | register_component() | ||||||
|  | 
 | ||||||
|  | component_compile_options("-Werror=incompatible-pointer-types") | ||||||
							
								
								
									
										175
									
								
								components/sx127x_driver/sx127x_driver.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										175
									
								
								components/sx127x_driver/sx127x_driver.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,175 @@ | |||||||
|  | #include "sx127x_driver.h" | ||||||
|  | #include "sx127x_internal.h" | ||||||
|  | #include "sx127x_registers.h" | ||||||
|  | 
 | ||||||
|  | #include <esp_log.h> | ||||||
|  | #include <string.h> | ||||||
|  | 
 | ||||||
|  | const char *SX127X_TAG = "sx127x"; | ||||||
|  | 
 | ||||||
|  | esp_err_t sx127x_init(sx127x_config_t *config, sx127x_t **handle_ptr) { | ||||||
|  |   esp_err_t ret; | ||||||
|  |   sx127x_t *handle = malloc(sizeof(sx127x_t)); | ||||||
|  |   SX127X_CHECK(handle != NULL, "malloc error", ESP_ERR_NO_MEM); | ||||||
|  | 
 | ||||||
|  |   handle->task_handle = NULL; | ||||||
|  |   memcpy(&handle->config, config, sizeof(sx127x_config_t)); | ||||||
|  | 
 | ||||||
|  |   ret = gpio_set_direction(config->rst_io_num, GPIO_MODE_OUTPUT); | ||||||
|  |   SX127X_ERROR_CHECK2(ret, gpio_set_direction) | ||||||
|  | 
 | ||||||
|  |   // perform reset
 | ||||||
|  |   gpio_set_level(config->rst_io_num, 0); | ||||||
|  |   vTaskDelay(RESET_DELAY); | ||||||
|  |   gpio_set_level(config->rst_io_num, 1); | ||||||
|  |   vTaskDelay(RESET_DELAY); | ||||||
|  | 
 | ||||||
|  |   spi_bus_config_t bus_config = {.mosi_io_num     = config->mosi_io_num, | ||||||
|  |                                  .miso_io_num     = config->miso_io_num, | ||||||
|  |                                  .sclk_io_num     = config->sck_io_num, | ||||||
|  |                                  .quadhd_io_num   = -1, | ||||||
|  |                                  .quadwp_io_num   = -1, | ||||||
|  |                                  .max_transfer_sz = SX127X_MAX_TRANSFER}; | ||||||
|  |   ret                         = spi_bus_initialize(config->spi_host, &bus_config, 1); | ||||||
|  |   SX127X_ERROR_CHECK2(ret, spi_bus_initialize) | ||||||
|  | 
 | ||||||
|  |   spi_device_interface_config_t device_config = { | ||||||
|  |       .command_bits     = 0, | ||||||
|  |       .address_bits     = 8, | ||||||
|  |       .dummy_bits       = 0, | ||||||
|  |       .mode             = 0, | ||||||
|  |       .duty_cycle_pos   = 0, | ||||||
|  |       .cs_ena_pretrans  = 0, | ||||||
|  |       .cs_ena_posttrans = 0, | ||||||
|  |       .clock_speed_hz   = SPI_CLOCK_HZ, // 8mhz
 | ||||||
|  |       .input_delay_ns   = 0, | ||||||
|  |       .spics_io_num     = config->cs_io_num, | ||||||
|  |       .flags            = 0, | ||||||
|  |       .queue_size       = 8, | ||||||
|  |       .pre_cb           = NULL, | ||||||
|  |       .post_cb          = NULL, | ||||||
|  |   }; | ||||||
|  |   ret = spi_bus_add_device(config->spi_host, &device_config, &handle->device_handle); | ||||||
|  |   SX127X_ERROR_CHECK2(ret, spi_bus_add_device) | ||||||
|  | 
 | ||||||
|  |   // read version and check that it is compatible
 | ||||||
|  |   uint8_t version; | ||||||
|  |   ret = sx127x_read_register(handle, REG_VERSION, &version); | ||||||
|  |   SX127X_ERROR_CHECK2(ret, sx127x_read_register); | ||||||
|  |   SX127X_CHECK(version == 0x12, "unsupported version %#x", ESP_ERR_INVALID_VERSION, version); | ||||||
|  | 
 | ||||||
|  |   ret = sx127x_sleep(handle); | ||||||
|  |   SX127X_ERROR_CHECK(ret); | ||||||
|  | 
 | ||||||
|  |   ret = sx127x_set_frequency(handle, config->frequency); | ||||||
|  |   SX127X_ERROR_CHECK(ret); | ||||||
|  | 
 | ||||||
|  |   ret = sx127x_write_register(handle, REG_FIFO_TX_BASE_ADDR, 0); | ||||||
|  |   SX127X_ERROR_CHECK(ret); | ||||||
|  |   sx127x_write_register(handle, REG_FIFO_RX_BASE_ADDR, 0); | ||||||
|  |   SX127X_ERROR_CHECK(ret); | ||||||
|  | 
 | ||||||
|  |   uint8_t reg_lna; | ||||||
|  |   ret = sx127x_read_register(handle, REG_LNA, ®_lna); | ||||||
|  |   SX127X_ERROR_CHECK(ret); | ||||||
|  |   reg_lna |= 0x03; // set LNA boost
 | ||||||
|  |   ret = sx127x_write_register(handle, REG_LNA, reg_lna); | ||||||
|  |   SX127X_ERROR_CHECK(ret); | ||||||
|  | 
 | ||||||
|  |   // set auto AGC
 | ||||||
|  |   ret = sx127x_write_register(handle, REG_MODEM_CONFIG_3, CONFIG3_AUTO_AGC); | ||||||
|  |   SX127X_ERROR_CHECK(ret); | ||||||
|  | 
 | ||||||
|  |   ret = sx127x_set_tx_power(handle, config->tx_power, true); | ||||||
|  |   SX127X_ERROR_CHECK(ret); | ||||||
|  | 
 | ||||||
|  |   ret = sx127x_set_spreading_factor(handle, config->spreading_factor); | ||||||
|  |   SX127X_ERROR_CHECK(ret); | ||||||
|  | 
 | ||||||
|  |   ret = sx127x_set_sync_word(handle, config->sync_word); | ||||||
|  |   SX127X_ERROR_CHECK(ret); | ||||||
|  | 
 | ||||||
|  |   ret = sx127x_set_crc(handle, config->crc); | ||||||
|  |   SX127X_ERROR_CHECK(ret); | ||||||
|  | 
 | ||||||
|  |   ret = sx127x_standby(handle); | ||||||
|  |   ESP_ERROR_CHECK(ret); | ||||||
|  | 
 | ||||||
|  |   *handle_ptr = handle; | ||||||
|  |   return ESP_OK; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | esp_err_t sx127x_free(sx127x_t *handle) { | ||||||
|  |   esp_err_t ret; | ||||||
|  | 
 | ||||||
|  |   if (handle->task_handle) { | ||||||
|  |     ret = sx127x_stop(handle); | ||||||
|  |     SX127X_ERROR_CHECK(ret); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   ret = spi_bus_remove_device(handle->device_handle); | ||||||
|  |   SX127X_ERROR_CHECK2(ret, spi_bus_remove_device) | ||||||
|  | 
 | ||||||
|  |   ret = spi_bus_free(handle->config.spi_host); | ||||||
|  |   SX127X_ERROR_CHECK2(ret, spi_bus_free) | ||||||
|  | 
 | ||||||
|  |   free(handle); | ||||||
|  | 
 | ||||||
|  |   return ESP_OK; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void sx127x_isr(void *arg) { | ||||||
|  |   sx127x_t *handle = (sx127x_t *)arg; | ||||||
|  |   ESP_LOGI(SX127X_TAG, "sx127x_isr"); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void sx127x_task(void *arg) { | ||||||
|  |   sx127x_t *handle = (sx127x_t *)arg; | ||||||
|  |   while (handle->task_running) { | ||||||
|  |     vTaskDelay(pdMS_TO_TICKS(10)); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | esp_err_t sx127x_start(sx127x_t *handle) { | ||||||
|  |   esp_err_t ret; | ||||||
|  | 
 | ||||||
|  |   SX127X_CHECK(handle->task_handle == NULL, "task already running", ESP_ERR_INVALID_STATE); | ||||||
|  | 
 | ||||||
|  |   ret = sx127x_write_register(handle, REG_DIO_MAPPING_1, 0x00); | ||||||
|  |   SX127X_ERROR_CHECK(ret); | ||||||
|  | 
 | ||||||
|  |   gpio_config_t irq_io_config; | ||||||
|  |   irq_io_config.intr_type    = GPIO_INTR_POSEDGE; | ||||||
|  |   irq_io_config.mode         = GPIO_MODE_INPUT; | ||||||
|  |   irq_io_config.pin_bit_mask = (1ULL << handle->config.irq_io_num); | ||||||
|  |   irq_io_config.pull_down_en = 0; | ||||||
|  |   irq_io_config.pull_up_en   = 0; | ||||||
|  |   ret                        = gpio_config(&irq_io_config); | ||||||
|  |   SX127X_ERROR_CHECK2(ret, gpio_config) | ||||||
|  | 
 | ||||||
|  |   ret = gpio_install_isr_service(ESP_INTR_FLAG_LEVEL1); | ||||||
|  |   SX127X_ERROR_CHECK2(ret, gpio_install_isr_service); | ||||||
|  |   ret = gpio_isr_handler_add(handle->config.irq_io_num, sx127x_isr, (void *)handle); | ||||||
|  |   SX127X_ERROR_CHECK2(ret, gpio_isr_handler_add); | ||||||
|  | 
 | ||||||
|  |   handle->task_running = true; | ||||||
|  | 
 | ||||||
|  |   BaseType_t pdRet = | ||||||
|  |       xTaskCreate(sx127x_task, "sx127x_task", TASK_STACK_SIZE, (void *)handle, TASK_PRIORITY, &handle->task_handle); | ||||||
|  |   SX127X_CHECK(pdRet == pdPASS, "failed to create task", ESP_FAIL); | ||||||
|  |   return ESP_OK; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | esp_err_t sx127x_stop(sx127x_t *handle) { | ||||||
|  |   esp_err_t ret; | ||||||
|  | 
 | ||||||
|  |   SX127X_CHECK(handle->task_handle != NULL, "task has not been started", ESP_ERR_INVALID_STATE); | ||||||
|  |   handle->task_running = false; | ||||||
|  |   xTaskNotify(handle->task_handle, 0, eNoAction); | ||||||
|  | 
 | ||||||
|  |   ret = gpio_isr_handler_remove(handle->config.irq_io_num); | ||||||
|  |   SX127X_ERROR_CHECK2(ret, gpio_isr_handler_remove); | ||||||
|  |   gpio_uninstall_isr_service(); | ||||||
|  | 
 | ||||||
|  |   return ESP_OK; | ||||||
|  | } | ||||||
| @ -76,18 +76,6 @@ esp_err_t sx127x_init(sx127x_config_t *config, sx127x_t **handle_ptr); | |||||||
| 
 | 
 | ||||||
| esp_err_t sx127x_free(sx127x_t *handle); | esp_err_t sx127x_free(sx127x_t *handle); | ||||||
| 
 | 
 | ||||||
| esp_err_t sx127x_set_frequency(sx127x_t *handle, uint64_t frequency); |  | ||||||
| 
 |  | ||||||
| esp_err_t sx127x_set_tx_power(sx127x_t *handle, uint8_t tx_power, sx127x_pa_boost_t pa_boost); |  | ||||||
| 
 |  | ||||||
| esp_err_t sx127x_set_spreading_factor(sx127x_t *handle, uint8_t spreading_factor); |  | ||||||
| 
 |  | ||||||
| esp_err_t sx127x_set_signal_bandwidth(sx127x_t *handle, uint64_t signal_bandwidth); |  | ||||||
| 
 |  | ||||||
| esp_err_t sx127x_set_sync_word(sx127x_t *handle, uint8_t sync_word); |  | ||||||
| 
 |  | ||||||
| esp_err_t sx127x_set_crc(sx127x_t *handle, sx127x_crc_t crc); |  | ||||||
| 
 |  | ||||||
| esp_err_t sx127x_sleep(sx127x_t *handle); | esp_err_t sx127x_sleep(sx127x_t *handle); | ||||||
| 
 | 
 | ||||||
| esp_err_t sx127x_standby(sx127x_t *handle); | esp_err_t sx127x_standby(sx127x_t *handle); | ||||||
							
								
								
									
										112
									
								
								components/sx127x_driver/sx127x_internal.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										112
									
								
								components/sx127x_driver/sx127x_internal.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,112 @@ | |||||||
|  | #include <esp_log.h> | ||||||
|  | #include <freertos/task.h> | ||||||
|  | 
 | ||||||
|  | #define MAX_PKT_LENGTH 255 | ||||||
|  | #define RESET_DELAY (pdMS_TO_TICKS(15)) | ||||||
|  | // 8mhz
 | ||||||
|  | #define SPI_CLOCK_HZ (8 * 1000 * 1000) | ||||||
|  | #define TASK_STACK_SIZE (2 * 1024) | ||||||
|  | #define TASK_PRIORITY 3 | ||||||
|  | 
 | ||||||
|  | #define REG_FIFO 0x00 | ||||||
|  | #define REG_OP_MODE 0x01 | ||||||
|  | #define REG_FRF_MSB 0x06 | ||||||
|  | #define REG_FRF_MID 0x07 | ||||||
|  | #define REG_FRF_LSB 0x08 | ||||||
|  | #define REG_PA_CONFIG 0x09 | ||||||
|  | #define REG_OCP 0x0b | ||||||
|  | #define REG_LNA 0x0c | ||||||
|  | #define REG_FIFO_ADDR_PTR 0x0d | ||||||
|  | #define REG_FIFO_TX_BASE_ADDR 0x0e | ||||||
|  | #define REG_FIFO_RX_BASE_ADDR 0x0f | ||||||
|  | #define REG_FIFO_RX_CURRENT_ADDR 0x10 | ||||||
|  | #define REG_IRQ_FLAGS 0x12 | ||||||
|  | #define REG_RX_NB_BYTES 0x13 | ||||||
|  | #define REG_PKT_SNR_VALUE 0x19 | ||||||
|  | #define REG_PKT_RSSI_VALUE 0x1a | ||||||
|  | #define REG_MODEM_CONFIG_1 0x1d | ||||||
|  | #define REG_MODEM_CONFIG_2 0x1e | ||||||
|  | #define REG_PREAMBLE_MSB 0x20 | ||||||
|  | #define REG_PREAMBLE_LSB 0x21 | ||||||
|  | #define REG_PAYLOAD_LENGTH 0x22 | ||||||
|  | #define REG_MODEM_CONFIG_3 0x26 | ||||||
|  | #define REG_FREQ_ERROR_MSB 0x28 | ||||||
|  | #define REG_FREQ_ERROR_MID 0x29 | ||||||
|  | #define REG_FREQ_ERROR_LSB 0x2a | ||||||
|  | #define REG_RSSI_WIDEBAND 0x2c | ||||||
|  | #define REG_DETECTION_OPTIMIZE 0x31 | ||||||
|  | #define REG_INVERTIQ 0x33 | ||||||
|  | #define REG_DETECTION_THRESHOLD 0x37 | ||||||
|  | #define REG_SYNC_WORD 0x39 | ||||||
|  | #define REG_INVERTIQ2 0x3b | ||||||
|  | #define REG_DIO_MAPPING_1 0x40 | ||||||
|  | #define REG_VERSION 0x42 | ||||||
|  | #define REG_PA_DAC 0x4d | ||||||
|  | 
 | ||||||
|  | // modes
 | ||||||
|  | #define MODE_LONG_RANGE_MODE 0x80 | ||||||
|  | #define MODE_SLEEP 0x00 | ||||||
|  | #define MODE_STDBY 0x01 | ||||||
|  | #define MODE_TX 0x03 | ||||||
|  | #define MODE_RX_CONTINUOUS 0x05 | ||||||
|  | #define MODE_RX_SINGLE 0x06 | ||||||
|  | 
 | ||||||
|  | #define CONFIG2_CRC 0x04 | ||||||
|  | #define CONFIG3_AUTO_AGC 0x04 | ||||||
|  | 
 | ||||||
|  | // PA config
 | ||||||
|  | #define PA_BOOST 0x80 | ||||||
|  | 
 | ||||||
|  | // IRQ masks
 | ||||||
|  | #define IRQ_TX_DONE_MASK 0x08 | ||||||
|  | #define IRQ_PAYLOAD_CRC_ERROR_MASK 0x20 | ||||||
|  | #define IRQ_RX_DONE_MASK 0x40 | ||||||
|  | 
 | ||||||
|  | #ifdef NODEBUG | ||||||
|  | #define SX127X_CHECK(check, str, ret_val, ...)                                                                         \ | ||||||
|  |   if (!(check)) {                                                                                                      \ | ||||||
|  |     ESP_LOGE(SX127X_TAG, "%s(%d): " str, __FUNCTION__, __LINE__, ##__VA_ARGS__);                                              \ | ||||||
|  |     return (ret_val);                                                                                                  \ | ||||||
|  |   } | ||||||
|  | #define SX127X_ERROR_CHECK(ret)                                                                                        \ | ||||||
|  |   {                                                                                                                    \ | ||||||
|  |     esp_err_t _error_code = (ret);                                                                                     \ | ||||||
|  |     if (_error_code != ESP_OK) {                                                                                       \ | ||||||
|  |       return _error_code;                                                                                              \ | ||||||
|  |     }                                                                                                                  \ | ||||||
|  |   } | ||||||
|  | #define SX127X_ERROR_CHECK2(ret, fun) SX127X_CHECK(ret) | ||||||
|  | #else | ||||||
|  | #define SX127X_CHECK(check, str, ret_val, ...)                                                                         \ | ||||||
|  |   if (!(check)) {                                                                                                      \ | ||||||
|  |     ESP_LOGE(SX127X_TAG, "%s(%d): " #check ": " str, __FUNCTION__, __LINE__, ##__VA_ARGS__);                                  \ | ||||||
|  |     return (ret_val);                                                                                                  \ | ||||||
|  |   } | ||||||
|  | #define SX127X_ERROR_CHECK(ret)                                                                                        \ | ||||||
|  |   {                                                                                                                    \ | ||||||
|  |     esp_err_t _error_code = (ret);                                                                                     \ | ||||||
|  |     if (_error_code != ESP_OK) {                                                                                       \ | ||||||
|  |       const char *_error_name = esp_err_to_name(_error_code);                                                          \ | ||||||
|  |       ESP_LOGE(SX127X_TAG, "%s(%d): %s (%d)", __FUNCTION__, __LINE__, _error_name, _error_code);                              \ | ||||||
|  |       return _error_code;                                                                                              \ | ||||||
|  |     }                                                                                                                  \ | ||||||
|  |   } | ||||||
|  | #define SX127X_ERROR_CHECK2(ret, fun)                                                                                  \ | ||||||
|  |   {                                                                                                                    \ | ||||||
|  |     esp_err_t _error_code = (ret);                                                                                     \ | ||||||
|  |     if (_error_code != ESP_OK) {                                                                                       \ | ||||||
|  |       const char *_error_name = esp_err_to_name(_error_code);                                                          \ | ||||||
|  |       ESP_LOGE(SX127X_TAG, "%s(%d): " #fun ": %s (%d)", __FUNCTION__, __LINE__, _error_name, _error_code);                    \ | ||||||
|  |       return _error_code;                                                                                              \ | ||||||
|  |     }                                                                                                                  \ | ||||||
|  |   } | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | struct sx127x { | ||||||
|  |   sx127x_config_t     config; | ||||||
|  |   spi_device_handle_t device_handle; | ||||||
|  |   TaskHandle_t        task_handle; | ||||||
|  |   bool                task_running; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | const char *SX127X_TAG; | ||||||
							
								
								
									
										184
									
								
								components/sx127x_driver/sx127x_registers.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										184
									
								
								components/sx127x_driver/sx127x_registers.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,184 @@ | |||||||
|  | #include "sx127x_registers.h" | ||||||
|  | #include "sx127x_internal.h" | ||||||
|  | 
 | ||||||
|  | #include <string.h> | ||||||
|  | 
 | ||||||
|  | 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, MODE_LONG_RANGE_MODE | MODE_SLEEP); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | esp_err_t sx127x_standby(sx127x_t *handle) { | ||||||
|  |   return sx127x_write_register(handle, REG_OP_MODE, MODE_LONG_RANGE_MODE | 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; | ||||||
|  | } | ||||||
							
								
								
									
										20
									
								
								components/sx127x_driver/sx127x_registers.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								components/sx127x_driver/sx127x_registers.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,20 @@ | |||||||
|  | #include "sx127x_driver.h" | ||||||
|  | 
 | ||||||
|  | esp_err_t sx127x_read_register(sx127x_t *handle, uint8_t reg, uint8_t *value); | ||||||
|  | esp_err_t sx127x_write_register(sx127x_t *handle, uint8_t reg, uint8_t value); | ||||||
|  | esp_err_t sx127x_single_transfer(sx127x_t *handle, uint8_t addr, uint8_t to_slave, uint8_t *from_slave); | ||||||
|  | 
 | ||||||
|  | uint8_t  sx127x_bw_to_reg(uint64_t bandwidth); | ||||||
|  | uint64_t sx127x_reg_to_bw(uint8_t bandwidth_reg); | ||||||
|  | 
 | ||||||
|  | esp_err_t sx127x_set_frequency(sx127x_t *handle, uint64_t frequency); | ||||||
|  | 
 | ||||||
|  | esp_err_t sx127x_set_tx_power(sx127x_t *handle, uint8_t tx_power, sx127x_pa_boost_t pa_boost); | ||||||
|  | 
 | ||||||
|  | esp_err_t sx127x_set_spreading_factor(sx127x_t *handle, uint8_t spreading_factor); | ||||||
|  | 
 | ||||||
|  | esp_err_t sx127x_set_signal_bandwidth(sx127x_t *handle, uint64_t signal_bandwidth); | ||||||
|  | 
 | ||||||
|  | esp_err_t sx127x_set_sync_word(sx127x_t *handle, uint8_t sync_word); | ||||||
|  | 
 | ||||||
|  | esp_err_t sx127x_set_crc(sx127x_t *handle, sx127x_crc_t crc); | ||||||
| @ -1,9 +1,7 @@ | |||||||
| set(COMPONENT_SRCS "ugv_main.c" | set(COMPONENT_SRCS "ugv_main.c" | ||||||
|     "u8g2_esp32_hal.c" |     "u8g2_esp32_hal.c") | ||||||
|     "sx127x_driver/sx127x_driver.c") | set(COMPONENT_ADD_INCLUDEDIRS ".") | ||||||
| set(COMPONENT_ADD_INCLUDEDIRS "." | set(COMPONENT_REQUIRES "u8g2" "sx127x_driver") | ||||||
|     "./sx127x_driver") |  | ||||||
| set(COMPONENT_REQUIRES "u8g2") |  | ||||||
| 
 | 
 | ||||||
| register_component() | register_component() | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -1,468 +0,0 @@ | |||||||
| #include "sx127x_driver.h" |  | ||||||
| 
 |  | ||||||
| #include <esp_log.h> |  | ||||||
| #include <freertos/task.h> |  | ||||||
| #include <string.h> |  | ||||||
| 
 |  | ||||||
| static const char *TAG = "sx127x"; |  | ||||||
| 
 |  | ||||||
| #define MAX_PKT_LENGTH 255 |  | ||||||
| #define RESET_DELAY (pdMS_TO_TICKS(15)) |  | ||||||
| // 8mhz
 |  | ||||||
| #define SPI_CLOCK_HZ (8 * 1000 * 1000) |  | ||||||
| #define TASK_STACK_SIZE (2 * 1024) |  | ||||||
| #define TASK_PRIORITY 3 |  | ||||||
| 
 |  | ||||||
| #define REG_FIFO 0x00 |  | ||||||
| #define REG_OP_MODE 0x01 |  | ||||||
| #define REG_FRF_MSB 0x06 |  | ||||||
| #define REG_FRF_MID 0x07 |  | ||||||
| #define REG_FRF_LSB 0x08 |  | ||||||
| #define REG_PA_CONFIG 0x09 |  | ||||||
| #define REG_OCP 0x0b |  | ||||||
| #define REG_LNA 0x0c |  | ||||||
| #define REG_FIFO_ADDR_PTR 0x0d |  | ||||||
| #define REG_FIFO_TX_BASE_ADDR 0x0e |  | ||||||
| #define REG_FIFO_RX_BASE_ADDR 0x0f |  | ||||||
| #define REG_FIFO_RX_CURRENT_ADDR 0x10 |  | ||||||
| #define REG_IRQ_FLAGS 0x12 |  | ||||||
| #define REG_RX_NB_BYTES 0x13 |  | ||||||
| #define REG_PKT_SNR_VALUE 0x19 |  | ||||||
| #define REG_PKT_RSSI_VALUE 0x1a |  | ||||||
| #define REG_MODEM_CONFIG_1 0x1d |  | ||||||
| #define REG_MODEM_CONFIG_2 0x1e |  | ||||||
| #define REG_PREAMBLE_MSB 0x20 |  | ||||||
| #define REG_PREAMBLE_LSB 0x21 |  | ||||||
| #define REG_PAYLOAD_LENGTH 0x22 |  | ||||||
| #define REG_MODEM_CONFIG_3 0x26 |  | ||||||
| #define REG_FREQ_ERROR_MSB 0x28 |  | ||||||
| #define REG_FREQ_ERROR_MID 0x29 |  | ||||||
| #define REG_FREQ_ERROR_LSB 0x2a |  | ||||||
| #define REG_RSSI_WIDEBAND 0x2c |  | ||||||
| #define REG_DETECTION_OPTIMIZE 0x31 |  | ||||||
| #define REG_INVERTIQ 0x33 |  | ||||||
| #define REG_DETECTION_THRESHOLD 0x37 |  | ||||||
| #define REG_SYNC_WORD 0x39 |  | ||||||
| #define REG_INVERTIQ2 0x3b |  | ||||||
| #define REG_DIO_MAPPING_1 0x40 |  | ||||||
| #define REG_VERSION 0x42 |  | ||||||
| #define REG_PA_DAC 0x4d |  | ||||||
| 
 |  | ||||||
| // modes
 |  | ||||||
| #define MODE_LONG_RANGE_MODE 0x80 |  | ||||||
| #define MODE_SLEEP 0x00 |  | ||||||
| #define MODE_STDBY 0x01 |  | ||||||
| #define MODE_TX 0x03 |  | ||||||
| #define MODE_RX_CONTINUOUS 0x05 |  | ||||||
| #define MODE_RX_SINGLE 0x06 |  | ||||||
| 
 |  | ||||||
| #define CONFIG2_CRC 0x04 |  | ||||||
| #define CONFIG3_AUTO_AGC 0x04 |  | ||||||
| 
 |  | ||||||
| // PA config
 |  | ||||||
| #define PA_BOOST 0x80 |  | ||||||
| 
 |  | ||||||
| // IRQ masks
 |  | ||||||
| #define IRQ_TX_DONE_MASK 0x08 |  | ||||||
| #define IRQ_PAYLOAD_CRC_ERROR_MASK 0x20 |  | ||||||
| #define IRQ_RX_DONE_MASK 0x40 |  | ||||||
| 
 |  | ||||||
| #ifdef NODEBUG |  | ||||||
| #define SX127X_CHECK(check, str, ret_val, ...)                                                                         \ |  | ||||||
|   if (!(check)) {                                                                                                      \ |  | ||||||
|     ESP_LOGE(TAG, "%s(%d): " str, __FUNCTION__, __LINE__, ##__VA_ARGS__);                                              \ |  | ||||||
|     return (ret_val);                                                                                                  \ |  | ||||||
|   } |  | ||||||
| #define SX127X_ERROR_CHECK(ret)                                                                                        \ |  | ||||||
|   {                                                                                                                    \ |  | ||||||
|     esp_err_t _error_code = (ret);                                                                                     \ |  | ||||||
|     if (_error_code != ESP_OK) {                                                                                       \ |  | ||||||
|       return _error_code;                                                                                              \ |  | ||||||
|     }                                                                                                                  \ |  | ||||||
|   } |  | ||||||
| #define SX127X_ERROR_CHECK2(ret, fun) SX127X_CHECK(ret) |  | ||||||
| #else |  | ||||||
| #define SX127X_CHECK(check, str, ret_val, ...)                                                                         \ |  | ||||||
|   if (!(check)) {                                                                                                      \ |  | ||||||
|     ESP_LOGE(TAG, "%s(%d): " #check ": " str, __FUNCTION__, __LINE__, ##__VA_ARGS__);                                  \ |  | ||||||
|     return (ret_val);                                                                                                  \ |  | ||||||
|   } |  | ||||||
| #define SX127X_ERROR_CHECK(ret)                                                                                        \ |  | ||||||
|   {                                                                                                                    \ |  | ||||||
|     esp_err_t _error_code = (ret);                                                                                     \ |  | ||||||
|     if (_error_code != ESP_OK) {                                                                                       \ |  | ||||||
|       const char *_error_name = esp_err_to_name(_error_code);                                                          \ |  | ||||||
|       ESP_LOGE(TAG, "%s(%d): %s (%d)", __FUNCTION__, __LINE__, _error_name, _error_code);                              \ |  | ||||||
|       return _error_code;                                                                                              \ |  | ||||||
|     }                                                                                                                  \ |  | ||||||
|   } |  | ||||||
| #define SX127X_ERROR_CHECK2(ret, fun)                                                                                  \ |  | ||||||
|   {                                                                                                                    \ |  | ||||||
|     esp_err_t _error_code = (ret);                                                                                     \ |  | ||||||
|     if (_error_code != ESP_OK) {                                                                                       \ |  | ||||||
|       const char *_error_name = esp_err_to_name(_error_code);                                                          \ |  | ||||||
|       ESP_LOGE(TAG, "%s(%d): " #fun ": %s (%d)", __FUNCTION__, __LINE__, _error_name, _error_code);                    \ |  | ||||||
|       return _error_code;                                                                                              \ |  | ||||||
|     }                                                                                                                  \ |  | ||||||
|   } |  | ||||||
| #endif |  | ||||||
| 
 |  | ||||||
| struct sx127x { |  | ||||||
|   sx127x_config_t     config; |  | ||||||
|   spi_device_handle_t device_handle; |  | ||||||
|   TaskHandle_t        task_handle; |  | ||||||
|   bool                task_running; |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| static esp_err_t sx127x_read_register(sx127x_t *handle, uint8_t reg, uint8_t *value); |  | ||||||
| static esp_err_t sx127x_write_register(sx127x_t *handle, uint8_t reg, uint8_t value); |  | ||||||
| static esp_err_t sx127x_single_transfer(sx127x_t *handle, uint8_t addr, uint8_t to_slave, uint8_t *from_slave); |  | ||||||
| 
 |  | ||||||
| static uint8_t  sx127x_bw_to_reg(uint64_t bandwidth); |  | ||||||
| static uint64_t sx127x_reg_to_bw(uint8_t bandwidth_reg); |  | ||||||
| 
 |  | ||||||
| esp_err_t sx127x_init(sx127x_config_t *config, sx127x_t **handle_ptr) { |  | ||||||
|   esp_err_t ret; |  | ||||||
|   sx127x_t *handle = malloc(sizeof(sx127x_t)); |  | ||||||
|   SX127X_CHECK(handle != NULL, "malloc error", ESP_ERR_NO_MEM); |  | ||||||
| 
 |  | ||||||
|   handle->task_handle = NULL; |  | ||||||
|   memcpy(&handle->config, config, sizeof(sx127x_config_t)); |  | ||||||
| 
 |  | ||||||
|   ret = gpio_set_direction(config->rst_io_num, GPIO_MODE_OUTPUT); |  | ||||||
|   SX127X_ERROR_CHECK2(ret, gpio_set_direction) |  | ||||||
| 
 |  | ||||||
|   // perform reset
 |  | ||||||
|   gpio_set_level(config->rst_io_num, 0); |  | ||||||
|   vTaskDelay(RESET_DELAY); |  | ||||||
|   gpio_set_level(config->rst_io_num, 1); |  | ||||||
|   vTaskDelay(RESET_DELAY); |  | ||||||
| 
 |  | ||||||
|   spi_bus_config_t bus_config = {.mosi_io_num     = config->mosi_io_num, |  | ||||||
|                                  .miso_io_num     = config->miso_io_num, |  | ||||||
|                                  .sclk_io_num     = config->sck_io_num, |  | ||||||
|                                  .quadhd_io_num   = -1, |  | ||||||
|                                  .quadwp_io_num   = -1, |  | ||||||
|                                  .max_transfer_sz = SX127X_MAX_TRANSFER}; |  | ||||||
|   ret                         = spi_bus_initialize(config->spi_host, &bus_config, 1); |  | ||||||
|   SX127X_ERROR_CHECK2(ret, spi_bus_initialize) |  | ||||||
| 
 |  | ||||||
|   spi_device_interface_config_t device_config = { |  | ||||||
|       .command_bits     = 0, |  | ||||||
|       .address_bits     = 8, |  | ||||||
|       .dummy_bits       = 0, |  | ||||||
|       .mode             = 0, |  | ||||||
|       .duty_cycle_pos   = 0, |  | ||||||
|       .cs_ena_pretrans  = 0, |  | ||||||
|       .cs_ena_posttrans = 0, |  | ||||||
|       .clock_speed_hz   = SPI_CLOCK_HZ, // 8mhz
 |  | ||||||
|       .input_delay_ns   = 0, |  | ||||||
|       .spics_io_num     = config->cs_io_num, |  | ||||||
|       .flags            = 0, |  | ||||||
|       .queue_size       = 8, |  | ||||||
|       .pre_cb           = NULL, |  | ||||||
|       .post_cb          = NULL, |  | ||||||
|   }; |  | ||||||
|   ret = spi_bus_add_device(config->spi_host, &device_config, &handle->device_handle); |  | ||||||
|   SX127X_ERROR_CHECK2(ret, spi_bus_add_device) |  | ||||||
| 
 |  | ||||||
|   // read version and check that it is compatible
 |  | ||||||
|   uint8_t version; |  | ||||||
|   ret = sx127x_read_register(handle, REG_VERSION, &version); |  | ||||||
|   SX127X_ERROR_CHECK2(ret, sx127x_read_register); |  | ||||||
|   SX127X_CHECK(version == 0x12, "unsupported version %#x", ESP_ERR_INVALID_VERSION, version); |  | ||||||
| 
 |  | ||||||
|   ret = sx127x_sleep(handle); |  | ||||||
|   SX127X_ERROR_CHECK(ret); |  | ||||||
| 
 |  | ||||||
|   ret = sx127x_set_frequency(handle, config->frequency); |  | ||||||
|   SX127X_ERROR_CHECK(ret); |  | ||||||
| 
 |  | ||||||
|   ret = sx127x_write_register(handle, REG_FIFO_TX_BASE_ADDR, 0); |  | ||||||
|   SX127X_ERROR_CHECK(ret); |  | ||||||
|   sx127x_write_register(handle, REG_FIFO_RX_BASE_ADDR, 0); |  | ||||||
|   SX127X_ERROR_CHECK(ret); |  | ||||||
| 
 |  | ||||||
|   uint8_t reg_lna; |  | ||||||
|   ret = sx127x_read_register(handle, REG_LNA, ®_lna); |  | ||||||
|   SX127X_ERROR_CHECK(ret); |  | ||||||
|   reg_lna |= 0x03; // set LNA boost
 |  | ||||||
|   ret = sx127x_write_register(handle, REG_LNA, reg_lna); |  | ||||||
|   SX127X_ERROR_CHECK(ret); |  | ||||||
| 
 |  | ||||||
|   // set auto AGC
 |  | ||||||
|   ret = sx127x_write_register(handle, REG_MODEM_CONFIG_3, CONFIG3_AUTO_AGC); |  | ||||||
|   SX127X_ERROR_CHECK(ret); |  | ||||||
| 
 |  | ||||||
|   ret = sx127x_set_tx_power(handle, config->tx_power, true); |  | ||||||
|   SX127X_ERROR_CHECK(ret); |  | ||||||
| 
 |  | ||||||
|   ret = sx127x_set_spreading_factor(handle, config->spreading_factor); |  | ||||||
|   SX127X_ERROR_CHECK(ret); |  | ||||||
| 
 |  | ||||||
|   ret = sx127x_set_sync_word(handle, config->sync_word); |  | ||||||
|   SX127X_ERROR_CHECK(ret); |  | ||||||
| 
 |  | ||||||
|   ret = sx127x_set_crc(handle, config->crc); |  | ||||||
|   SX127X_ERROR_CHECK(ret); |  | ||||||
| 
 |  | ||||||
|   ret = sx127x_standby(handle); |  | ||||||
|   ESP_ERROR_CHECK(ret); |  | ||||||
| 
 |  | ||||||
|   *handle_ptr = handle; |  | ||||||
|   return ESP_OK; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| esp_err_t sx127x_free(sx127x_t *handle) { |  | ||||||
|   esp_err_t ret; |  | ||||||
| 
 |  | ||||||
|   if (handle->task_handle) { |  | ||||||
|     ret = sx127x_stop(handle); |  | ||||||
|     SX127X_ERROR_CHECK(ret); |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   ret = spi_bus_remove_device(handle->device_handle); |  | ||||||
|   SX127X_ERROR_CHECK2(ret, spi_bus_remove_device) |  | ||||||
| 
 |  | ||||||
|   ret = spi_bus_free(handle->config.spi_host); |  | ||||||
|   SX127X_ERROR_CHECK2(ret, spi_bus_free) |  | ||||||
| 
 |  | ||||||
|   free(handle); |  | ||||||
| 
 |  | ||||||
|   return ESP_OK; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static esp_err_t sx127x_read_register(sx127x_t *handle, uint8_t reg, uint8_t *value) { |  | ||||||
|   return sx127x_single_transfer(handle, reg & 0x7f, 0x00, value); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static esp_err_t sx127x_write_register(sx127x_t *handle, uint8_t reg, uint8_t value) { |  | ||||||
|   return sx127x_single_transfer(handle, reg | 0x80, value, NULL); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static 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(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, MODE_LONG_RANGE_MODE | MODE_SLEEP); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| esp_err_t sx127x_standby(sx127x_t *handle) { |  | ||||||
|   return sx127x_write_register(handle, REG_OP_MODE, MODE_LONG_RANGE_MODE | 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; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static 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; |  | ||||||
|   } |  | ||||||
| } |  | ||||||
| static 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; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void sx127x_isr(void *arg) { |  | ||||||
|   sx127x_t *handle = (sx127x_t *)arg; |  | ||||||
|   ESP_LOGI(TAG, "sx127x_isr"); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void sx127x_task(void *arg) { |  | ||||||
|   sx127x_t *handle = (sx127x_t *)arg; |  | ||||||
|   while (handle->task_running) { |  | ||||||
|     vTaskDelay(pdMS_TO_TICKS(10)); |  | ||||||
|   } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| esp_err_t sx127x_start(sx127x_t *handle) { |  | ||||||
|   esp_err_t ret; |  | ||||||
| 
 |  | ||||||
|   SX127X_CHECK(handle->task_handle == NULL, "task already running", ESP_ERR_INVALID_STATE); |  | ||||||
| 
 |  | ||||||
|   ret = sx127x_write_register(handle, REG_DIO_MAPPING_1, 0x00); |  | ||||||
|   SX127X_ERROR_CHECK(ret); |  | ||||||
| 
 |  | ||||||
|   gpio_config_t irq_io_config; |  | ||||||
|   irq_io_config.intr_type    = GPIO_INTR_POSEDGE; |  | ||||||
|   irq_io_config.mode         = GPIO_MODE_INPUT; |  | ||||||
|   irq_io_config.pin_bit_mask = (1ULL << handle->config.irq_io_num); |  | ||||||
|   irq_io_config.pull_down_en = 0; |  | ||||||
|   irq_io_config.pull_up_en   = 0; |  | ||||||
|   ret                        = gpio_config(&irq_io_config); |  | ||||||
|   SX127X_ERROR_CHECK2(ret, gpio_config) |  | ||||||
| 
 |  | ||||||
|   ret = gpio_install_isr_service(ESP_INTR_FLAG_LEVEL1); |  | ||||||
|   SX127X_ERROR_CHECK2(ret, gpio_install_isr_service); |  | ||||||
|   ret = gpio_isr_handler_add(handle->config.irq_io_num, sx127x_isr, (void *)handle); |  | ||||||
|   SX127X_ERROR_CHECK2(ret, gpio_isr_handler_add); |  | ||||||
| 
 |  | ||||||
|   handle->task_running = true; |  | ||||||
| 
 |  | ||||||
|   BaseType_t pdRet = |  | ||||||
|       xTaskCreate(sx127x_task, "sx127x_task", TASK_STACK_SIZE, (void *)handle, TASK_PRIORITY, &handle->task_handle); |  | ||||||
|   SX127X_CHECK(pdRet == pdPASS, "failed to create task", ESP_FAIL); |  | ||||||
|   return ESP_OK; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| esp_err_t sx127x_stop(sx127x_t *handle) { |  | ||||||
|   esp_err_t ret; |  | ||||||
| 
 |  | ||||||
|   SX127X_CHECK(handle->task_handle != NULL, "task has not been started", ESP_ERR_INVALID_STATE); |  | ||||||
|   handle->task_running = false; |  | ||||||
|   xTaskNotify(handle->task_handle, 0, eNoAction); |  | ||||||
| 
 |  | ||||||
|   ret = gpio_isr_handler_remove(handle->config.irq_io_num); |  | ||||||
|   SX127X_ERROR_CHECK2(ret, gpio_isr_handler_remove); |  | ||||||
|   gpio_uninstall_isr_service(); |  | ||||||
| 
 |  | ||||||
|   return ESP_OK; |  | ||||||
| } |  | ||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user