diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..955bc7f --- /dev/null +++ b/.clang-format @@ -0,0 +1,118 @@ +--- +Language: Cpp +# BasedOnStyle: LLVM +AccessModifierOffset: -2 +AlignAfterOpenBracket: Align +AlignConsecutiveAssignments: true +AlignConsecutiveDeclarations: true +AlignEscapedNewlines: Right +AlignOperands: true +AlignTrailingComments: true +AllowAllParametersOfDeclarationOnNextLine: true +AllowShortBlocksOnASingleLine: false +AllowShortCaseLabelsOnASingleLine: true +AllowShortFunctionsOnASingleLine: All +AllowShortIfStatementsOnASingleLine: true +AllowShortLoopsOnASingleLine: false +AlwaysBreakAfterDefinitionReturnType: None +AlwaysBreakAfterReturnType: None +AlwaysBreakBeforeMultilineStrings: false +AlwaysBreakTemplateDeclarations: MultiLine +BinPackArguments: false +BinPackParameters: false +BraceWrapping: + AfterClass: false + AfterControlStatement: false + AfterEnum: false + AfterFunction: false + AfterNamespace: false + AfterObjCDeclaration: false + AfterStruct: false + AfterUnion: false + AfterExternBlock: false + BeforeCatch: false + BeforeElse: false + IndentBraces: false + SplitEmptyFunction: true + SplitEmptyRecord: true + SplitEmptyNamespace: true +BreakBeforeBinaryOperators: None +BreakBeforeBraces: Attach +BreakBeforeInheritanceComma: false +BreakInheritanceList: BeforeColon +BreakBeforeTernaryOperators: true +BreakConstructorInitializersBeforeComma: false +BreakConstructorInitializers: BeforeColon +BreakAfterJavaFieldAnnotations: false +BreakStringLiterals: true +ColumnLimit: 120 +CommentPragmas: '^ IWYU pragma:' +CompactNamespaces: false +ConstructorInitializerAllOnOneLineOrOnePerLine: false +ConstructorInitializerIndentWidth: 4 +ContinuationIndentWidth: 4 +Cpp11BracedListStyle: true +DerivePointerAlignment: false +DisableFormat: false +ExperimentalAutoDetectBinPacking: false +FixNamespaceComments: true +ForEachMacros: + - foreach + - Q_FOREACH + - BOOST_FOREACH +IncludeBlocks: Preserve +IncludeCategories: + - Regex: '^"(llvm|llvm-c|clang|clang-c)/' + Priority: 2 + - Regex: '^(<|"(gtest|gmock|isl|json)/)' + Priority: 3 + - Regex: '.*' + Priority: 1 +IncludeIsMainRegex: '(Test)?$' +IndentCaseLabels: false +IndentPPDirectives: None +IndentWidth: 2 +IndentWrappedFunctionNames: false +JavaScriptQuotes: Leave +JavaScriptWrapImports: true +KeepEmptyLinesAtTheStartOfBlocks: true +MacroBlockBegin: '' +MacroBlockEnd: '' +MaxEmptyLinesToKeep: 1 +NamespaceIndentation: None +ObjCBinPackProtocolList: Auto +ObjCBlockIndentWidth: 2 +ObjCSpaceAfterProperty: false +ObjCSpaceBeforeProtocolList: true +PenaltyBreakAssignment: 2 +PenaltyBreakBeforeFirstCallParameter: 1 +PenaltyBreakComment: 300 +PenaltyBreakFirstLessLess: 120 +PenaltyBreakString: 1000 +PenaltyBreakTemplateDeclaration: 10 +PenaltyExcessCharacter: 1000000 +PenaltyReturnTypeOnItsOwnLine: 60 +PointerAlignment: Right +ReflowComments: true +SortIncludes: true +SortUsingDeclarations: true +SpaceAfterCStyleCast: false +SpaceAfterTemplateKeyword: true +SpaceBeforeAssignmentOperators: true +SpaceBeforeCpp11BracedList: false +SpaceBeforeCtorInitializerColon: true +SpaceBeforeInheritanceColon: true +SpaceBeforeParens: ControlStatements +SpaceBeforeRangeBasedForLoopColon: true +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 1 +SpacesInAngles: false +SpacesInContainerLiterals: true +SpacesInCStyleCastParentheses: false +SpacesInParentheses: false +SpacesInSquareBrackets: false +Standard: Cpp11 +TabWidth: 8 +UseTab: Never +... + diff --git a/main/CMakeLists.txt b/main/CMakeLists.txt index c9aa810..7accae5 100644 --- a/main/CMakeLists.txt +++ b/main/CMakeLists.txt @@ -5,4 +5,6 @@ set(COMPONENT_ADD_INCLUDEDIRS "." "./sx127x_driver") set(COMPONENT_REQUIRES "u8g2") -register_component() \ No newline at end of file +register_component() + +component_compile_options("-Werror=incompatible-pointer-types") diff --git a/main/sx127x_driver/sx127x_driver.c b/main/sx127x_driver/sx127x_driver.c index e17bc47..45dd557 100644 --- a/main/sx127x_driver/sx127x_driver.c +++ b/main/sx127x_driver/sx127x_driver.c @@ -1,101 +1,468 @@ #include "sx127x_driver.h" -#include -#include #include +#include +#include + +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 -const char *SX127X_TAG = "sx127x"; +#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 -#define SX127X_CHECK(check, str, ret_val, ...) \ - if (!(check)) \ - { \ - ESP_LOGE(SX127X_TAG, "%s(%d): " str, __FUNCTION__, __LINE__, ##__VA_ARGS__); \ - return (ret_val); \ - } +// 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_ERROR_CHECK(ret, fun) \ - { \ - esp_err_t _error_code = (ret); \ - if (_error_code != ESP_OK) \ - { \ - return _error_code; \ - } \ - } +#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_ERROR_CHECK(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; \ - } \ - } +#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 -esp_err_t sx127x_init(sx127x_config_t *config, sx127x_t *handle) -{ - esp_err_t ret; +struct sx127x { + sx127x_config_t config; + spi_device_handle_t device_handle; + TaskHandle_t task_handle; + bool task_running; +}; - memcpy(&handle->config, config, sizeof(sx127x_config_t)); +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); - ret = gpio_set_direction(config->rst_io_num, GPIO_MODE_OUTPUT); - SX127X_ERROR_CHECK(ret, "gpio_set_direction") - ret = gpio_set_direction(config->irq_io_num, GPIO_MODE_OUTPUT); - SX127X_ERROR_CHECK(ret, "gpio_set_direction") +static uint8_t sx127x_bw_to_reg(uint64_t bandwidth); +static uint64_t sx127x_reg_to_bw(uint8_t bandwidth_reg); - gpio_set_level(config->cs_io_num, 1); +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); - // perform reset - gpio_set_level(config->rst_io_num, 0); - vTaskDelay(pdMS_TO_TICKS(10)); - gpio_set_level(config->rst_io_num, 1); + 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)); + } +} - 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_CHECK(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 = 2, - .cs_ena_posttrans = 2, - .clock_speed_hz = 8, // 80mhz / 8 = 10mhz - .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_CHECK(ret, "spi_bus_add_device") - - return ESP_OK; -} - -esp_err_t sx127x_free(sx127x_t *handle) -{ - esp_err_t ret; - - ret = spi_bus_remove_device(handle->device_handle); - SX127X_ERROR_CHECK(ret, "spi_bus_remove_device") - - ret = spi_bus_free(handle->config.spi_host); - SX127X_ERROR_CHECK(ret, "spi_bus_free") - - return ESP_OK; +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; +} \ No newline at end of file diff --git a/main/sx127x_driver/sx127x_driver.h b/main/sx127x_driver/sx127x_driver.h index d7cddc6..47fe9f9 100644 --- a/main/sx127x_driver/sx127x_driver.h +++ b/main/sx127x_driver/sx127x_driver.h @@ -1,40 +1,97 @@ #pragma once -#include "driver/spi_master.h" - -const char *SX127X_TAG; - -#define SX127X_MAX_TRANSFER (1024) - -#define SX127X_CONFIG_DEFAULT \ - sx127x_config_t \ - { \ - .spi_host = VSPI_HOST, \ - .mosi_io_num = 19, \ - .miso_io_num = 27, \ - .sck_io_num = 5, \ - .cs_io_num = 18, \ - .rst_io_num = 14, \ - .irq_io_num = 26 \ - } - -typedef struct sx127x_config -{ - spi_host_device_t spi_host; - gpio_num_t mosi_io_num; - gpio_num_t miso_io_num; - gpio_num_t sck_io_num; - gpio_num_t cs_io_num; - gpio_num_t rst_io_num; - gpio_num_t irq_io_num; +#include +#include +#include + +#define SX127X_MAX_TRANSFER (256) + +// carrier frequency type +typedef uint64_t sx127x_freq_t; + +#define SX127X_FREQ_433 ((sx127x_freq_t)433E6) +#define SX127X_FREQ_915 ((sx127x_freq_t)915E6) + +// signal bandwidth type +typedef uint64_t sx127x_bw_t; +// spreading factor type +typedef uint8_t sx127x_sf_t; + +typedef enum sx127x_pa_boost { + SX127X_PA_BOOST_DISABLED = 0, + SX127X_PA_BOOST_ENABLED = 1, +} sx127x_pa_boost_t; + +typedef enum sx127x_crc { + SX127X_CRC_DISABLED = 0, + SX127X_CRC_ENABLED = 1, +} sx127x_crc_t; + +// low data rate optimization +typedef enum sx127x_ldo { + SX127X_LDO_DISABLED = 0, + SX127X_LDO_ENABLED = 1, +} sx127x_ldo_t; + +typedef struct sx127x_config { + spi_host_device_t spi_host; + gpio_num_t mosi_io_num; + gpio_num_t miso_io_num; + gpio_num_t sck_io_num; + gpio_num_t cs_io_num; + gpio_num_t rst_io_num; + gpio_num_t irq_io_num; + uint8_t tx_power; + sx127x_freq_t frequency; + sx127x_bw_t signal_bandwidth; + sx127x_sf_t spreading_factor; + uint8_t sync_word; + sx127x_crc_t crc; + sx127x_ldo_t ldo; } sx127x_config_t; -typedef struct sx127x -{ - sx127x_config_t config; - spi_device_handle_t device_handle; -} sx127x_t; +// clang-format off +#define SX127X_CONFIG_DEFAULT \ + { \ + .spi_host = VSPI_HOST, \ + .mosi_io_num = 27, \ + .miso_io_num = 19, \ + .sck_io_num = 5, \ + .cs_io_num = 18, \ + .rst_io_num = 14, \ + .irq_io_num = 26, \ + .tx_power = 17, \ + .frequency = SX127X_FREQ_433, \ + .signal_bandwidth = 125E3, \ + .spreading_factor = 11, \ + .sync_word = 0x34, \ + .crc = SX127X_CRC_ENABLED, \ + .ldo = SX127X_LDO_DISABLED \ + } +// clang-format on -esp_err_t sx127x_init(sx127x_config_t *config, sx127x_t *handle); +typedef struct sx127x sx127x_t; + +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_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_standby(sx127x_t *handle); + +esp_err_t sx127x_start(sx127x_t *handle); + +esp_err_t sx127x_stop(sx127x_t *handle); diff --git a/main/u8g2_esp32_hal.c b/main/u8g2_esp32_hal.c index a580dcd..1f2a633 100644 --- a/main/u8g2_esp32_hal.c +++ b/main/u8g2_esp32_hal.c @@ -1,8 +1,8 @@ #include #include -#include "sdkconfig.h" #include "esp_log.h" +#include "sdkconfig.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" @@ -17,264 +17,234 @@ static i2c_cmd_handle_t handle_i2c; // I2C handle. static u8g2_esp32_hal_t u8g2_esp32_hal; // HAL state data. #undef ESP_ERROR_CHECK -#define ESP_ERROR_CHECK(x) \ - do \ - { \ - esp_err_t rc = (x); \ - if (rc != ESP_OK) \ - { \ - ESP_LOGE("err", "esp_err_t = %d", rc); \ - assert(0 && #x); \ - } \ - } while (0); +#define ESP_ERROR_CHECK(x) \ + do { \ + esp_err_t rc = (x); \ + if (rc != ESP_OK) { \ + ESP_LOGE("err", "esp_err_t = %d", rc); \ + assert(0 && #x); \ + } \ + } while (0); /* * Initialze the ESP32 HAL. */ -void u8g2_esp32_hal_init(u8g2_esp32_hal_t u8g2_esp32_hal_param) -{ - u8g2_esp32_hal = u8g2_esp32_hal_param; +void u8g2_esp32_hal_init(u8g2_esp32_hal_t u8g2_esp32_hal_param) { + u8g2_esp32_hal = u8g2_esp32_hal_param; } // u8g2_esp32_hal_init /* - * HAL callback function as prescribed by the U8G2 library. This callback is invoked - * to handle SPI communications. + * HAL callback function as prescribed by the U8G2 library. This callback is + * invoked to handle SPI communications. */ -uint8_t u8g2_esp32_spi_byte_cb(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr) -{ - ESP_LOGV(TAG, "spi_byte_cb: Received a msg: %d, arg_int: %d, arg_ptr: %p", msg, arg_int, arg_ptr); - switch (msg) - { - case U8X8_MSG_BYTE_SET_DC: - if (u8g2_esp32_hal.dc != U8G2_ESP32_HAL_UNDEFINED) - { - gpio_set_level(u8g2_esp32_hal.dc, arg_int); - } - break; - - case U8X8_MSG_BYTE_INIT: - { - if (u8g2_esp32_hal.clk == U8G2_ESP32_HAL_UNDEFINED || - u8g2_esp32_hal.mosi == U8G2_ESP32_HAL_UNDEFINED || - u8g2_esp32_hal.cs == U8G2_ESP32_HAL_UNDEFINED) - { - break; - } - - spi_bus_config_t bus_config; - memset(&bus_config, 0, sizeof(spi_bus_config_t)); - bus_config.sclk_io_num = u8g2_esp32_hal.clk; // CLK - bus_config.mosi_io_num = u8g2_esp32_hal.mosi; // MOSI - bus_config.miso_io_num = -1; // MISO - bus_config.quadwp_io_num = -1; // Not used - bus_config.quadhd_io_num = -1; // Not used - //ESP_LOGI(TAG, "... Initializing bus."); - ESP_ERROR_CHECK(spi_bus_initialize(HSPI_HOST, &bus_config, 1)); - - spi_device_interface_config_t dev_config; - dev_config.address_bits = 0; - dev_config.command_bits = 0; - dev_config.dummy_bits = 0; - dev_config.mode = 0; - dev_config.duty_cycle_pos = 0; - dev_config.cs_ena_posttrans = 0; - dev_config.cs_ena_pretrans = 0; - dev_config.clock_speed_hz = 10000; - dev_config.spics_io_num = u8g2_esp32_hal.cs; - dev_config.flags = 0; - dev_config.queue_size = 200; - dev_config.pre_cb = NULL; - dev_config.post_cb = NULL; - //ESP_LOGI(TAG, "... Adding device bus."); - ESP_ERROR_CHECK(spi_bus_add_device(HSPI_HOST, &dev_config, &handle_spi)); - - break; +uint8_t u8g2_esp32_spi_byte_cb(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr) { + ESP_LOGV(TAG, "spi_byte_cb: Received a msg: %d, arg_int: %d, arg_ptr: %p", msg, arg_int, arg_ptr); + switch (msg) { + case U8X8_MSG_BYTE_SET_DC: + if (u8g2_esp32_hal.dc != U8G2_ESP32_HAL_UNDEFINED) { + gpio_set_level(u8g2_esp32_hal.dc, arg_int); } + break; - case U8X8_MSG_BYTE_SEND: - { - spi_transaction_t trans_desc; - trans_desc.addr = 0; - trans_desc.cmd = 0; - trans_desc.flags = 0; - trans_desc.length = 8 * arg_int; // Number of bits NOT number of bytes. - trans_desc.rxlength = 0; - trans_desc.tx_buffer = arg_ptr; - trans_desc.rx_buffer = NULL; - - //ESP_LOGI(TAG, "... Transmitting %d bytes.", arg_int); - ESP_ERROR_CHECK(spi_device_transmit(handle_spi, &trans_desc)); - break; + case U8X8_MSG_BYTE_INIT: { + if (u8g2_esp32_hal.clk == U8G2_ESP32_HAL_UNDEFINED || u8g2_esp32_hal.mosi == U8G2_ESP32_HAL_UNDEFINED || + u8g2_esp32_hal.cs == U8G2_ESP32_HAL_UNDEFINED) { + break; } - } - return 0; -} // u8g2_esp32_spi_byte_cb + spi_bus_config_t bus_config; + memset(&bus_config, 0, sizeof(spi_bus_config_t)); + bus_config.sclk_io_num = u8g2_esp32_hal.clk; // CLK + bus_config.mosi_io_num = u8g2_esp32_hal.mosi; // MOSI + bus_config.miso_io_num = -1; // MISO + bus_config.quadwp_io_num = -1; // Not used + bus_config.quadhd_io_num = -1; // Not used + // ESP_LOGI(TAG, "... Initializing bus."); + ESP_ERROR_CHECK(spi_bus_initialize(HSPI_HOST, &bus_config, 1)); + + spi_device_interface_config_t dev_config; + dev_config.address_bits = 0; + dev_config.command_bits = 0; + dev_config.dummy_bits = 0; + dev_config.mode = 0; + dev_config.duty_cycle_pos = 0; + dev_config.cs_ena_posttrans = 0; + dev_config.cs_ena_pretrans = 0; + dev_config.clock_speed_hz = 10000; + dev_config.spics_io_num = u8g2_esp32_hal.cs; + dev_config.flags = 0; + dev_config.queue_size = 200; + dev_config.pre_cb = NULL; + dev_config.post_cb = NULL; + // ESP_LOGI(TAG, "... Adding device bus."); + ESP_ERROR_CHECK(spi_bus_add_device(HSPI_HOST, &dev_config, &handle_spi)); + + break; + } + + case U8X8_MSG_BYTE_SEND: { + spi_transaction_t trans_desc; + trans_desc.addr = 0; + trans_desc.cmd = 0; + trans_desc.flags = 0; + trans_desc.length = 8 * arg_int; // Number of bits NOT number of bytes. + trans_desc.rxlength = 0; + trans_desc.tx_buffer = arg_ptr; + trans_desc.rx_buffer = NULL; + + // ESP_LOGI(TAG, "... Transmitting %d bytes.", arg_int); + ESP_ERROR_CHECK(spi_device_transmit(handle_spi, &trans_desc)); + break; + } + } + return 0; +} // u8g2_esp32_spi_byte_cb /* - * HAL callback function as prescribed by the U8G2 library. This callback is invoked - * to handle I2C communications. + * HAL callback function as prescribed by the U8G2 library. This callback is + * invoked to handle I2C communications. */ -uint8_t u8g2_esp32_i2c_byte_cb(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr) -{ - #define TXBUF_SIZE 32 - static uint8_t txbuf[TXBUF_SIZE]; - static uint8_t *txbuf_ptr; - // ESP_LOGV(TAG, "i2c_cb: Received a msg: %d, arg_int: %d, arg_ptr: %p", msg, arg_int, arg_ptr); - switch (msg) - { - case U8X8_MSG_BYTE_SET_DC: - { - if (u8g2_esp32_hal.dc != U8G2_ESP32_HAL_UNDEFINED) - { - gpio_set_level(u8g2_esp32_hal.dc, arg_int); - } - break; - } - - case U8X8_MSG_BYTE_INIT: - { - if (u8g2_esp32_hal.sda == U8G2_ESP32_HAL_UNDEFINED || - u8g2_esp32_hal.scl == U8G2_ESP32_HAL_UNDEFINED) - { - break; - } - - i2c_config_t conf; - conf.mode = I2C_MODE_MASTER; - ESP_LOGD(TAG, "sda_io_num %d", u8g2_esp32_hal.sda); - conf.sda_io_num = u8g2_esp32_hal.sda; - conf.sda_pullup_en = GPIO_PULLUP_ENABLE; - ESP_LOGD(TAG, "scl_io_num %d", u8g2_esp32_hal.scl); - conf.scl_io_num = u8g2_esp32_hal.scl; - conf.scl_pullup_en = GPIO_PULLUP_ENABLE; - ESP_LOGD(TAG, "clk_speed %d", I2C_MASTER_FREQ_HZ); - conf.master.clk_speed = I2C_MASTER_FREQ_HZ; - ESP_LOGD(TAG, "i2c_param_config %d", conf.mode); - ESP_ERROR_CHECK(i2c_param_config(I2C_MASTER_NUM, &conf)); - ESP_LOGD(TAG, "i2c_driver_install %d", I2C_MASTER_NUM); - ESP_ERROR_CHECK(i2c_driver_install(I2C_MASTER_NUM, conf.mode, I2C_MASTER_RX_BUF_DISABLE, I2C_MASTER_TX_BUF_DISABLE, 0)); - break; +uint8_t u8g2_esp32_i2c_byte_cb(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr) { +#define TXBUF_SIZE 32 + static uint8_t txbuf[TXBUF_SIZE]; + static uint8_t *txbuf_ptr; + // ESP_LOGV(TAG, "i2c_cb: Received a msg: %d, arg_int: %d, arg_ptr: %p", msg, + // arg_int, arg_ptr); + switch (msg) { + case U8X8_MSG_BYTE_SET_DC: { + if (u8g2_esp32_hal.dc != U8G2_ESP32_HAL_UNDEFINED) { + gpio_set_level(u8g2_esp32_hal.dc, arg_int); } + break; + } - case U8X8_MSG_BYTE_SEND: - { - uint8_t *data_ptr = (uint8_t *)arg_ptr; - size_t data_len = (size_t) arg_int; - // ESP_LOGV(TAG, "U8x8_MSG_BYTE_SEND. txbuf len: %d", txbuf_ptr - txbuf); - // ESP_LOG_BUFFER_HEXDUMP(TAG, data_ptr, data_len, ESP_LOG_VERBOSE); - - if (txbuf_ptr + data_len >= txbuf_ptr + TXBUF_SIZE) { - ESP_LOGE(TAG, "txbuf overflow"); - return 0; - } - memcpy(txbuf_ptr, data_ptr, data_len); - txbuf_ptr += data_len; - break; - } - - case U8X8_MSG_BYTE_START_TRANSFER: - { - uint8_t i2c_address = u8x8_GetI2CAddress(u8x8); - handle_i2c = i2c_cmd_link_create(); - // ESP_LOGV(TAG, "Start I2C transfer to %02X.", i2c_address >> 1); - ESP_ERROR_CHECK(i2c_master_start(handle_i2c)); - ESP_ERROR_CHECK(i2c_master_write_byte(handle_i2c, i2c_address | I2C_MASTER_WRITE, ACK_CHECK_EN)); - txbuf_ptr = txbuf; - break; + case U8X8_MSG_BYTE_INIT: { + if (u8g2_esp32_hal.sda == U8G2_ESP32_HAL_UNDEFINED || u8g2_esp32_hal.scl == U8G2_ESP32_HAL_UNDEFINED) { + break; } - case U8X8_MSG_BYTE_END_TRANSFER: - { - // ESP_LOGV(TAG, "End I2C transfer. txbuf len: %d", txbuf_ptr - txbuf); - // ESP_LOG_BUFFER_HEXDUMP(TAG, txbuf, txbuf_ptr - txbuf, ESP_LOG_VERBOSE); - ESP_ERROR_CHECK(i2c_master_write(handle_i2c, txbuf, txbuf_ptr - txbuf, ACK_CHECK_EN)); - ESP_ERROR_CHECK(i2c_master_stop(handle_i2c)); - ESP_ERROR_CHECK(i2c_master_cmd_begin(I2C_MASTER_NUM, handle_i2c, I2C_TIMEOUT_MS / portTICK_RATE_MS)); - i2c_cmd_link_delete(handle_i2c); - break; - } + i2c_config_t conf; + conf.mode = I2C_MODE_MASTER; + ESP_LOGD(TAG, "sda_io_num %d", u8g2_esp32_hal.sda); + conf.sda_io_num = u8g2_esp32_hal.sda; + conf.sda_pullup_en = GPIO_PULLUP_ENABLE; + ESP_LOGD(TAG, "scl_io_num %d", u8g2_esp32_hal.scl); + conf.scl_io_num = u8g2_esp32_hal.scl; + conf.scl_pullup_en = GPIO_PULLUP_ENABLE; + ESP_LOGD(TAG, "clk_speed %d", I2C_MASTER_FREQ_HZ); + conf.master.clk_speed = I2C_MASTER_FREQ_HZ; + ESP_LOGD(TAG, "i2c_param_config %d", conf.mode); + ESP_ERROR_CHECK(i2c_param_config(I2C_MASTER_NUM, &conf)); + ESP_LOGD(TAG, "i2c_driver_install %d", I2C_MASTER_NUM); + ESP_ERROR_CHECK( + i2c_driver_install(I2C_MASTER_NUM, conf.mode, I2C_MASTER_RX_BUF_DISABLE, I2C_MASTER_TX_BUF_DISABLE, 0)); + break; + } + + case U8X8_MSG_BYTE_SEND: { + uint8_t *data_ptr = (uint8_t *)arg_ptr; + size_t data_len = (size_t)arg_int; + // ESP_LOGV(TAG, "U8x8_MSG_BYTE_SEND. txbuf len: %d", txbuf_ptr - txbuf); + // ESP_LOG_BUFFER_HEXDUMP(TAG, data_ptr, data_len, ESP_LOG_VERBOSE); + + if (txbuf_ptr + data_len >= txbuf_ptr + TXBUF_SIZE) { + ESP_LOGE(TAG, "txbuf overflow"); + return 0; } - return 0; + memcpy(txbuf_ptr, data_ptr, data_len); + txbuf_ptr += data_len; + break; + } + + case U8X8_MSG_BYTE_START_TRANSFER: { + uint8_t i2c_address = u8x8_GetI2CAddress(u8x8); + handle_i2c = i2c_cmd_link_create(); + // ESP_LOGV(TAG, "Start I2C transfer to %02X.", i2c_address >> 1); + ESP_ERROR_CHECK(i2c_master_start(handle_i2c)); + ESP_ERROR_CHECK(i2c_master_write_byte(handle_i2c, i2c_address | I2C_MASTER_WRITE, ACK_CHECK_EN)); + txbuf_ptr = txbuf; + break; + } + + case U8X8_MSG_BYTE_END_TRANSFER: { + // ESP_LOGV(TAG, "End I2C transfer. txbuf len: %d", txbuf_ptr - txbuf); + // ESP_LOG_BUFFER_HEXDUMP(TAG, txbuf, txbuf_ptr - txbuf, ESP_LOG_VERBOSE); + ESP_ERROR_CHECK(i2c_master_write(handle_i2c, txbuf, txbuf_ptr - txbuf, ACK_CHECK_EN)); + ESP_ERROR_CHECK(i2c_master_stop(handle_i2c)); + ESP_ERROR_CHECK(i2c_master_cmd_begin(I2C_MASTER_NUM, handle_i2c, I2C_TIMEOUT_MS / portTICK_RATE_MS)); + i2c_cmd_link_delete(handle_i2c); + break; + } + } + return 0; } // u8g2_esp32_i2c_byte_cb /* - * HAL callback function as prescribed by the U8G2 library. This callback is invoked - * to handle callbacks for GPIO and delay functions. + * HAL callback function as prescribed by the U8G2 library. This callback is + * invoked to handle callbacks for GPIO and delay functions. */ -uint8_t u8g2_esp32_gpio_and_delay_cb(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr) -{ - ESP_LOGV(TAG, "gpio_and_delay_cb: Received a msg: %d, arg_int: %d, arg_ptr: %p", msg, arg_int, arg_ptr); - - switch (msg) - { - // Initialize the GPIO and DELAY HAL functions. If the pins for DC and RESET have been - // specified then we define those pins as GPIO outputs. - case U8X8_MSG_GPIO_AND_DELAY_INIT: - { - uint64_t bitmask = 0; - if (u8g2_esp32_hal.dc != U8G2_ESP32_HAL_UNDEFINED) - { - bitmask = bitmask | (1ull << u8g2_esp32_hal.dc); - } - if (u8g2_esp32_hal.reset != U8G2_ESP32_HAL_UNDEFINED) - { - bitmask = bitmask | (1ull << u8g2_esp32_hal.reset); - } - if (u8g2_esp32_hal.cs != U8G2_ESP32_HAL_UNDEFINED) - { - bitmask = bitmask | (1ull << u8g2_esp32_hal.cs); - } - - if (bitmask == 0) - { - break; - } - gpio_config_t gpioConfig; - gpioConfig.pin_bit_mask = bitmask; - gpioConfig.mode = GPIO_MODE_OUTPUT; - gpioConfig.pull_up_en = GPIO_PULLUP_DISABLE; - gpioConfig.pull_down_en = GPIO_PULLDOWN_ENABLE; - gpioConfig.intr_type = GPIO_INTR_DISABLE; - gpio_config(&gpioConfig); - break; +uint8_t u8g2_esp32_gpio_and_delay_cb(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr) { + ESP_LOGV(TAG, "gpio_and_delay_cb: Received a msg: %d, arg_int: %d, arg_ptr: %p", msg, arg_int, arg_ptr); + + switch (msg) { + // Initialize the GPIO and DELAY HAL functions. If the pins for DC and + // RESET have been specified then we define those pins as GPIO outputs. + case U8X8_MSG_GPIO_AND_DELAY_INIT: { + uint64_t bitmask = 0; + if (u8g2_esp32_hal.dc != U8G2_ESP32_HAL_UNDEFINED) { + bitmask = bitmask | (1ull << u8g2_esp32_hal.dc); + } + if (u8g2_esp32_hal.reset != U8G2_ESP32_HAL_UNDEFINED) { + bitmask = bitmask | (1ull << u8g2_esp32_hal.reset); + } + if (u8g2_esp32_hal.cs != U8G2_ESP32_HAL_UNDEFINED) { + bitmask = bitmask | (1ull << u8g2_esp32_hal.cs); } - // Set the GPIO reset pin to the value passed in through arg_int. - case U8X8_MSG_GPIO_RESET: - if (u8g2_esp32_hal.reset != U8G2_ESP32_HAL_UNDEFINED) - { - gpio_set_level(u8g2_esp32_hal.reset, arg_int); - } - break; - // Set the GPIO client select pin to the value passed in through arg_int. - case U8X8_MSG_GPIO_CS: - if (u8g2_esp32_hal.cs != U8G2_ESP32_HAL_UNDEFINED) - { - gpio_set_level(u8g2_esp32_hal.cs, arg_int); - } - break; - // Set the Software I²C pin to the value passed in through arg_int. - case U8X8_MSG_GPIO_I2C_CLOCK: - if (u8g2_esp32_hal.scl != U8G2_ESP32_HAL_UNDEFINED) - { - gpio_set_level(u8g2_esp32_hal.scl, arg_int); - // printf("%c",(arg_int==1?'C':'c')); - } - break; - // Set the Software I²C pin to the value passed in through arg_int. - case U8X8_MSG_GPIO_I2C_DATA: - if (u8g2_esp32_hal.sda != U8G2_ESP32_HAL_UNDEFINED) - { - gpio_set_level(u8g2_esp32_hal.sda, arg_int); - // printf("%c",(arg_int==1?'D':'d')); - } - break; - - // Delay for the number of milliseconds passed in through arg_int. - case U8X8_MSG_DELAY_MILLI: - vTaskDelay(arg_int / portTICK_PERIOD_MS); - break; + if (bitmask == 0) { + break; + } + gpio_config_t gpioConfig; + gpioConfig.pin_bit_mask = bitmask; + gpioConfig.mode = GPIO_MODE_OUTPUT; + gpioConfig.pull_up_en = GPIO_PULLUP_DISABLE; + gpioConfig.pull_down_en = GPIO_PULLDOWN_ENABLE; + gpioConfig.intr_type = GPIO_INTR_DISABLE; + gpio_config(&gpioConfig); + break; + } + + // Set the GPIO reset pin to the value passed in through arg_int. + case U8X8_MSG_GPIO_RESET: + if (u8g2_esp32_hal.reset != U8G2_ESP32_HAL_UNDEFINED) { + gpio_set_level(u8g2_esp32_hal.reset, arg_int); + } + break; + // Set the GPIO client select pin to the value passed in through arg_int. + case U8X8_MSG_GPIO_CS: + if (u8g2_esp32_hal.cs != U8G2_ESP32_HAL_UNDEFINED) { + gpio_set_level(u8g2_esp32_hal.cs, arg_int); + } + break; + // Set the Software I²C pin to the value passed in through arg_int. + case U8X8_MSG_GPIO_I2C_CLOCK: + if (u8g2_esp32_hal.scl != U8G2_ESP32_HAL_UNDEFINED) { + gpio_set_level(u8g2_esp32_hal.scl, arg_int); + // printf("%c",(arg_int==1?'C':'c')); + } + break; + // Set the Software I²C pin to the value passed in through arg_int. + case U8X8_MSG_GPIO_I2C_DATA: + if (u8g2_esp32_hal.sda != U8G2_ESP32_HAL_UNDEFINED) { + gpio_set_level(u8g2_esp32_hal.sda, arg_int); + // printf("%c",(arg_int==1?'D':'d')); } - return 0; + break; + + // Delay for the number of milliseconds passed in through arg_int. + case U8X8_MSG_DELAY_MILLI: + vTaskDelay(arg_int / portTICK_PERIOD_MS); + break; + } + return 0; } // u8g2_esp32_gpio_and_delay_cb \ No newline at end of file diff --git a/main/u8g2_esp32_hal.h b/main/u8g2_esp32_hal.h index e22a06d..515a3b4 100644 --- a/main/u8g2_esp32_hal.h +++ b/main/u8g2_esp32_hal.h @@ -10,33 +10,33 @@ #include "u8g2.h" #include "driver/gpio.h" -#include "driver/spi_master.h" #include "driver/i2c.h" +#include "driver/spi_master.h" #define U8G2_ESP32_HAL_UNDEFINED (-1) #define I2C_MASTER_NUM I2C_NUM_1 // I2C port number for master dev #define I2C_MASTER_TX_BUF_DISABLE 0 // I2C master do not need buffer #define I2C_MASTER_RX_BUF_DISABLE 0 // I2C master do not need buffer -#define I2C_MASTER_FREQ_HZ 400000 // I2C master clock frequency +#define I2C_MASTER_FREQ_HZ 400000 // I2C master clock frequency #define ACK_CHECK_EN 0x1 // I2C master will check ack from slave #define ACK_CHECK_DIS 0x0 // I2C master will not check ack from slave -typedef struct -{ - gpio_num_t clk; - gpio_num_t mosi; - gpio_num_t sda; // data for I²C - gpio_num_t scl; // clock for I²C - gpio_num_t cs; - gpio_num_t reset; - gpio_num_t dc; +typedef struct { + gpio_num_t clk; + gpio_num_t mosi; + gpio_num_t sda; // data for I²C + gpio_num_t scl; // clock for I²C + gpio_num_t cs; + gpio_num_t reset; + gpio_num_t dc; } u8g2_esp32_hal_t; -#define U8G2_ESP32_HAL_DEFAULT \ - { \ - U8G2_ESP32_HAL_UNDEFINED, U8G2_ESP32_HAL_UNDEFINED, U8G2_ESP32_HAL_UNDEFINED, U8G2_ESP32_HAL_UNDEFINED, U8G2_ESP32_HAL_UNDEFINED, U8G2_ESP32_HAL_UNDEFINED, U8G2_ESP32_HAL_UNDEFINED \ - } +#define U8G2_ESP32_HAL_DEFAULT \ + { \ + U8G2_ESP32_HAL_UNDEFINED, U8G2_ESP32_HAL_UNDEFINED, U8G2_ESP32_HAL_UNDEFINED, U8G2_ESP32_HAL_UNDEFINED, \ + U8G2_ESP32_HAL_UNDEFINED, U8G2_ESP32_HAL_UNDEFINED, U8G2_ESP32_HAL_UNDEFINED \ + } void u8g2_esp32_hal_init(u8g2_esp32_hal_t u8g2_esp32_hal_param); uint8_t u8g2_esp32_spi_byte_cb(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr); diff --git a/main/ugv_main.c b/main/ugv_main.c index 9e1e766..b841968 100644 --- a/main/ugv_main.c +++ b/main/ugv_main.c @@ -1,14 +1,12 @@ #define U8X8_USE_PINS -// #include -#include -// #include -// #include +#include +#include #include #include -#include -#include #include +#include +#include "sx127x_driver.h" #include "u8g2_esp32_hal.h" const char *TAG = "uas-ugv"; @@ -31,12 +29,11 @@ u8g2_t u8g2; #define OLED_H 64 #define OLED_W 128 -struct Packet -{ - int rssi; +struct Packet { + int rssi; double snr; size_t buffer_len; - char buffer[LORA_BUF_LEN]; + char buffer[LORA_BUF_LEN]; }; uint16_t packet_num; @@ -45,46 +42,42 @@ void loraTask(void *params); void loraOnReceive(int packetSize); TaskHandle_t lora_task_hndl; -QueueHandle_t lora_packet_recv_queue; // packets recieved (type Packet) -QueueHandle_t lora_packet_isr_queue; // packet lengths from the recieve isr (type int) +// packets recieved (type Packet) +QueueHandle_t lora_packet_recv_queue; +// packet lengths from the recieve isr (type int) +QueueHandle_t lora_packet_isr_queue; struct Packet packet; -void setup_serial(void) -{ - const uart_port_t uart_num = UART_NUM_2; - uart_config_t uart_config = { - .baud_rate = 115200, - .data_bits = UART_DATA_8_BITS, - .parity = UART_PARITY_DISABLE, - .stop_bits = UART_STOP_BITS_1, - .flow_ctrl = UART_HW_FLOWCTRL_CTS_RTS, +void setup_serial(void) { + const uart_port_t uart_num = UART_NUM_2; + uart_config_t uart_config = { + .baud_rate = 115200, + .data_bits = UART_DATA_8_BITS, + .parity = UART_PARITY_DISABLE, + .stop_bits = UART_STOP_BITS_1, + .flow_ctrl = UART_HW_FLOWCTRL_CTS_RTS, .rx_flow_ctrl_thresh = 122, }; // Configure UART parameters ESP_ERROR_CHECK(uart_param_config(uart_num, &uart_config)); } -void setup_oled(void) -{ +void setup_oled(void) { u8g2_esp32_hal_t u8g2_hal_config = { - .scl = 15, - .sda = 4, + .scl = 15, + .sda = 4, .reset = 16, }; u8g2_esp32_hal_init(u8g2_hal_config); - u8g2_Setup_ssd1306_i2c_128x64_noname_f(&u8g2, - U8G2_R0, - u8g2_esp32_i2c_byte_cb, - u8g2_esp32_gpio_and_delay_cb); + u8g2_Setup_ssd1306_i2c_128x64_noname_f(&u8g2, U8G2_R0, u8g2_esp32_i2c_byte_cb, u8g2_esp32_gpio_and_delay_cb); u8g2_InitDisplay(&u8g2); u8g2_ClearDisplay(&u8g2); u8g2_SetPowerSave(&u8g2, false); } -void setup(void) -{ +void setup(void) { setup_serial(); ESP_LOGI(TAG, "setup"); @@ -92,28 +85,32 @@ void setup(void) setup_oled(); lora_packet_recv_queue = xQueueCreate(4, sizeof(struct Packet)); - lora_packet_isr_queue = xQueueCreate(4, sizeof(int)); + lora_packet_isr_queue = xQueueCreate(4, sizeof(int)); configASSERT(lora_packet_recv_queue != 0); configASSERT(lora_packet_isr_queue != 0); - // lora_spi.begin(LORA_SCK, LORA_MISO, LORA_MOSI, LORA_CS); - // LoRa.setSPI(lora_spi); - // LoRa.setPins(LORA_CS, LORA_RST, LORA_IRQ); - // int res = LoRa.begin(LORA_FREQ); // 433MHz - // if (!res) - // { - ESP_LOGE(TAG, "LoRa init failed"); - // } - // LoRa.setTxPower(17); - // LoRa.setSpreadingFactor(11); - // LoRa.setSignalBandwidth(125E3); - // LoRa.setSyncWord(0x34); - // LoRa.enableCrc(); + sx127x_config_t lora_config = SX127X_CONFIG_DEFAULT; + lora_config.tx_power = 17; + lora_config.spreading_factor = 11; + lora_config.signal_bandwidth = 125E3; + lora_config.sync_word = 0x34; + lora_config.crc = SX127X_CRC_ENABLED; + + sx127x_t* lora; + esp_err_t ret = sx127x_init(&lora_config, &lora); + if (ret != ESP_OK) { + const char *err_name = esp_err_to_name(ret); + ESP_LOGE(TAG, "LoRa init failed: %s", err_name); + } else { + ESP_LOGI(TAG, "LoRa initialized"); + ret = sx127x_start(lora); + if (ret != ESP_OK) { + ESP_LOGI(TAG, "LoRa start failed: %d", ret); + } + } // LoRa.onReceive(loraOnReceive); // LoRa.receive(0); - // LoRa.dumpRegisters(Serial); - packet_num = 0; xTaskCreate(loraTask, "loraTask", 1024 * 10, NULL, 2, &lora_task_hndl); @@ -122,33 +119,28 @@ void setup(void) #define XO 10 -void loraOnReceive(int packetSize) -{ - if (packetSize == 0) - return; +void loraOnReceive(int packetSize) { + if (packetSize == 0) return; ESP_LOGV(TAG, "loraOnReceive"); xQueueSendFromISR(lora_packet_isr_queue, &packetSize, NULL); } -void loraTask(void *params) -{ - char outBuf[20]; - const size_t outBufLen = (sizeof(outBuf) / sizeof(uint8_t)); - int packet_len; - TickType_t send_period = pdMS_TO_TICKS(2000); - TickType_t current_time = xTaskGetTickCount(); - TickType_t next_send = current_time + send_period; +void loraTask(void *params) { + char outBuf[20]; + const size_t outBufLen = (sizeof(outBuf) / sizeof(uint8_t)); + int packet_len; + TickType_t send_period = pdMS_TO_TICKS(2000); + TickType_t current_time = xTaskGetTickCount(); + TickType_t next_send = current_time + send_period; struct Packet recvd_packet; - while (true) - { + while (true) { TickType_t delay_ticks = next_send - current_time; - BaseType_t didReceive = xQueueReceive(lora_packet_isr_queue, &packet_len, delay_ticks); - if (didReceive) - { + BaseType_t didReceive = xQueueReceive(lora_packet_isr_queue, &packet_len, delay_ticks); + if (didReceive) { int packetSize = (packet_len > LORA_BUF_LEN - 1) ? (LORA_BUF_LEN - 1) : (packet_len); // LoRa.setTimeout(50); // LoRa.readBytes(recvd_packet.buffer, packetSize); - recvd_packet.buffer_len = packetSize; + recvd_packet.buffer_len = packetSize; recvd_packet.buffer[packetSize - 1] = '\0'; // recvd_packet.rssi = LoRa.packetRssi(); // recvd_packet.snr = LoRa.packetSnr(); @@ -156,8 +148,7 @@ void loraTask(void *params) xQueueSend(lora_packet_recv_queue, &recvd_packet, 10); } current_time = xTaskGetTickCount(); - if (current_time >= next_send) - { + if (current_time >= next_send) { sprintf(outBuf, "hello world %d", packet_num); packet_num++; // LoRa.beginPacket(); @@ -167,18 +158,16 @@ void loraTask(void *params) // LoRa.receive(0); // go back to receive mode current_time = xTaskGetTickCount(); - next_send = current_time + send_period; + next_send = current_time + send_period; } } } -void loop(void) -{ +void loop(void) { ESP_LOGI(TAG, "loop"); u8g2_FirstPage(&u8g2); bool recieved_packet = xQueueReceive(lora_packet_recv_queue, &packet, 10); - do - { + do { u8g2_DrawRFrame(&u8g2, 0, 0, OLED_W, OLED_H, 4); uint32_t free_heap = xPortGetFreeHeapSize(); @@ -188,10 +177,9 @@ void loop(void) snprintf(buf, 40, "free heap: %d", free_heap); u8g2_DrawStr(&u8g2, 4, 8 + 8, buf); - if (packet.buffer_len) - { - ESP_LOGI(TAG, "lora received packet (len %d, rssi: %d, snr: %f): %s\n", - packet.buffer_len, packet.rssi, packet.snr, packet.buffer); + if (packet.buffer_len) { + ESP_LOGI(TAG, "lora received packet (len %d, rssi: %d, snr: %f): %s\n", packet.buffer_len, packet.rssi, + packet.snr, packet.buffer); u8g2_SetFont(&u8g2, u8g2_font_4x6_mf); snprintf(buf, 40, "lora pkt(rssi: %d, snr: %f)", packet.rssi, packet.snr); u8g2_DrawStr(&u8g2, 4, 8 + 8 + 8, buf); @@ -202,16 +190,11 @@ void loop(void) vTaskDelay(pdMS_TO_TICKS(1000)); } -void loopTask(void *pvUser) -{ +void loopTask(void *pvUser) { setup(); - while (1) - { + while (1) { loop(); } } -void app_main() -{ - xTaskCreatePinnedToCore(loopTask, "loopTask", 8192, NULL, 1, NULL, 1); -} +void app_main() { xTaskCreatePinnedToCore(loopTask, "loopTask", 8192, NULL, 1, NULL, 1); }