-
Notifications
You must be signed in to change notification settings - Fork 7
Narrowband Transport Layer #55
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Draft
tillx4
wants to merge
23
commits into
bears-space:main
Choose a base branch
from
bears-space:feature/narrowband
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Draft
Changes from all commits
Commits
Show all changes
23 commits
Select commit
Hold shift + click to select a range
e254b7a
added narrowband radiolib interface
tillx4 215438a
fixing cmake needing requirement
tillx4 c646b4d
added some reasonable init parameters, implemented narrowband_thread …
tillx4 6dba473
upadte header file
tillx4 44af46d
implemented basic thread safe command queue, refractored narrowband m…
tillx4 d7bea1f
fix: interrupt handler for receiving narrowband packets is now ISR an…
tillx4 10c0e3f
fixed narroband header file
tillx4 8302c01
refractored narrowband class, better interface using freertos queues …
tillx4 dc5f49e
implemented interrupt based receive via freertos task notifications (…
tillx4 8a0ee6c
finished sketch for interrupt based send and receive with freeRTOS no…
tillx4 b00b9c4
implemented freertos queues for sensor data and received commands
tillx4 5bc1582
Merge branch 'bears-space:main' into narrowband
tillx4 0cc1259
start rxtx task in nb_radio.init()
tillx4 5286e2f
added init code to main to start nb module
tillx4 5fee59c
started working on fragmentation, UNFINSIHED
tillx4 8c0e225
comments
tillx4 2ea2262
finished pack_message for narrowband tp
tillx4 088b1d1
added narrowband to the correct module
tillx4 b923912
implemented pack and unpack message functions for transport layer
tillx4 aba95f0
added some todo comments
tillx4 1254aec
Merge remote-tracking branch 'comms/narrowband' into feature/narrowband
tillx4 7758fa4
refractored unpack and pack to use span instead of std::array, pack i…
tillx4 5faa49b
implemented message fragmentation
tillx4 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,322 @@ | ||
| #ifndef ESP_HAL_H | ||
| #define ESP_HAL_H | ||
|
|
||
| // include RadioLib | ||
| #include <RadioLib.h> | ||
|
|
||
| // this example only works on ESP32 and is unlikely to work on ESP32S2/S3 etc. | ||
| // if you need high portability, you should probably use Arduino anyway ... | ||
| #if CONFIG_IDF_TARGET_ESP32 == 0 | ||
| #error This example HAL only supports ESP32 targets. Support for ESP32S2/S3 etc. can be added by adjusting this file to user needs. | ||
| #endif | ||
|
|
||
| // include all the dependencies | ||
| #include "freertos/FreeRTOS.h" | ||
| #include "freertos/task.h" | ||
| #include "esp32/rom/gpio.h" | ||
| #include "soc/rtc.h" | ||
| #include "soc/dport_reg.h" | ||
| #include "soc/spi_reg.h" | ||
| #include "soc/spi_struct.h" | ||
| #include "driver/gpio.h" | ||
| #include "hal/gpio_hal.h" | ||
| #include "esp_timer.h" | ||
| #include "esp_log.h" | ||
|
|
||
| // define Arduino-style macros | ||
| #define LOW (0x0) | ||
| #define HIGH (0x1) | ||
| #define INPUT (0x01) | ||
| #define OUTPUT (0x03) | ||
| #define RISING (0x01) | ||
| #define FALLING (0x02) | ||
| #define NOP() asm volatile ("nop") | ||
|
|
||
| #define MATRIX_DETACH_OUT_SIG (0x100) | ||
| #define MATRIX_DETACH_IN_LOW_PIN (0x30) | ||
|
|
||
| // all of the following is needed to calculate SPI clock divider | ||
| #define ClkRegToFreq(reg) (apb_freq / (((reg)->clkdiv_pre + 1) * ((reg)->clkcnt_n + 1))) | ||
|
|
||
| typedef union { | ||
| uint32_t value; | ||
| struct { | ||
| uint32_t clkcnt_l: 6; | ||
| uint32_t clkcnt_h: 6; | ||
| uint32_t clkcnt_n: 6; | ||
| uint32_t clkdiv_pre: 13; | ||
| uint32_t clk_equ_sysclk: 1; | ||
| }; | ||
| } spiClk_t; | ||
|
|
||
| uint32_t getApbFrequency() { | ||
| rtc_cpu_freq_config_t conf; | ||
| rtc_clk_cpu_freq_get_config(&conf); | ||
|
|
||
| if(conf.freq_mhz >= 80) { | ||
| return(80 * MHZ); | ||
| } | ||
|
|
||
| return((conf.source_freq_mhz * MHZ) / conf.div); | ||
| } | ||
|
|
||
| uint32_t spiFrequencyToClockDiv(uint32_t freq) { | ||
| uint32_t apb_freq = getApbFrequency(); | ||
| if(freq >= apb_freq) { | ||
| return SPI_CLK_EQU_SYSCLK; | ||
| } | ||
|
|
||
| const spiClk_t minFreqReg = { 0x7FFFF000 }; | ||
| uint32_t minFreq = ClkRegToFreq((spiClk_t*) &minFreqReg); | ||
| if(freq < minFreq) { | ||
| return minFreqReg.value; | ||
| } | ||
|
|
||
| uint8_t calN = 1; | ||
| spiClk_t bestReg = { 0 }; | ||
| int32_t bestFreq = 0; | ||
| while(calN <= 0x3F) { | ||
| spiClk_t reg = { 0 }; | ||
| int32_t calFreq; | ||
| int32_t calPre; | ||
| int8_t calPreVari = -2; | ||
|
|
||
| reg.clkcnt_n = calN; | ||
|
|
||
| while(calPreVari++ <= 1) { | ||
| calPre = (((apb_freq / (reg.clkcnt_n + 1)) / freq) - 1) + calPreVari; | ||
| if(calPre > 0x1FFF) { | ||
| reg.clkdiv_pre = 0x1FFF; | ||
| } else if(calPre <= 0) { | ||
| reg.clkdiv_pre = 0; | ||
| } else { | ||
| reg.clkdiv_pre = calPre; | ||
| } | ||
| reg.clkcnt_l = ((reg.clkcnt_n + 1) / 2); | ||
| calFreq = ClkRegToFreq(®); | ||
| if(calFreq == (int32_t) freq) { | ||
| memcpy(&bestReg, ®, sizeof(bestReg)); | ||
| break; | ||
| } else if(calFreq < (int32_t) freq) { | ||
| if(RADIOLIB_ABS(freq - calFreq) < RADIOLIB_ABS(freq - bestFreq)) { | ||
| bestFreq = calFreq; | ||
| memcpy(&bestReg, ®, sizeof(bestReg)); | ||
| } | ||
| } | ||
| } | ||
| if(calFreq == (int32_t) freq) { | ||
| break; | ||
| } | ||
| calN++; | ||
| } | ||
| return(bestReg.value); | ||
| } | ||
|
|
||
| // create a new ESP-IDF hardware abstraction layer | ||
| // the HAL must inherit from the base RadioLibHal class | ||
| // and implement all of its virtual methods | ||
| // this is pretty much just copied from Arduino ESP32 core | ||
| class EspHal : public RadioLibHal { | ||
| public: | ||
| // default constructor - initializes the base HAL and any needed private members | ||
| EspHal(int8_t sck, int8_t miso, int8_t mosi) | ||
| : RadioLibHal(INPUT, OUTPUT, LOW, HIGH, RISING, FALLING), | ||
| spiSCK(sck), spiMISO(miso), spiMOSI(mosi) { | ||
| } | ||
|
|
||
| void init() override { | ||
| // we only need to init the SPI here | ||
| spiBegin(); | ||
| } | ||
|
|
||
| void term() override { | ||
| // we only need to stop the SPI here | ||
| spiEnd(); | ||
| } | ||
|
|
||
| // GPIO-related methods (pinMode, digitalWrite etc.) should check | ||
| // RADIOLIB_NC as an alias for non-connected pins | ||
| void pinMode(uint32_t pin, uint32_t mode) override { | ||
| if(pin == RADIOLIB_NC) { | ||
| return; | ||
| } | ||
|
|
||
| gpio_hal_context_t gpiohal; | ||
| gpiohal.dev = GPIO_LL_GET_HW(GPIO_PORT_0); | ||
|
|
||
| gpio_config_t conf = { | ||
| .pin_bit_mask = (1ULL<<pin), | ||
| .mode = (gpio_mode_t)mode, | ||
| .pull_up_en = GPIO_PULLUP_DISABLE, | ||
| .pull_down_en = GPIO_PULLDOWN_DISABLE, | ||
| .intr_type = (gpio_int_type_t)gpiohal.dev->pin[pin].int_type, | ||
| }; | ||
| gpio_config(&conf); | ||
| } | ||
|
|
||
| void digitalWrite(uint32_t pin, uint32_t value) override { | ||
| if(pin == RADIOLIB_NC) { | ||
| return; | ||
| } | ||
|
|
||
| gpio_set_level((gpio_num_t)pin, value); | ||
| } | ||
|
|
||
| uint32_t digitalRead(uint32_t pin) override { | ||
| if(pin == RADIOLIB_NC) { | ||
| return(0); | ||
| } | ||
|
|
||
| return(gpio_get_level((gpio_num_t)pin)); | ||
| } | ||
|
|
||
| void attachInterrupt(uint32_t interruptNum, void (*interruptCb)(void), uint32_t mode) override { | ||
| if(interruptNum == RADIOLIB_NC) { | ||
| return; | ||
| } | ||
|
|
||
| gpio_install_isr_service((int)ESP_INTR_FLAG_IRAM); | ||
| gpio_set_intr_type((gpio_num_t)interruptNum, (gpio_int_type_t)(mode & 0x7)); | ||
|
|
||
| // this uses function typecasting, which is not defined when the functions have different signatures | ||
| // untested and might not work | ||
| gpio_isr_handler_add((gpio_num_t)interruptNum, (void (*)(void*))interruptCb, NULL); | ||
| } | ||
|
|
||
| void detachInterrupt(uint32_t interruptNum) override { | ||
| if(interruptNum == RADIOLIB_NC) { | ||
| return; | ||
| } | ||
|
|
||
| gpio_isr_handler_remove((gpio_num_t)interruptNum); | ||
| gpio_wakeup_disable((gpio_num_t)interruptNum); | ||
| gpio_set_intr_type((gpio_num_t)interruptNum, GPIO_INTR_DISABLE); | ||
| } | ||
|
|
||
| void delay(unsigned long ms) override { | ||
| vTaskDelay(ms / portTICK_PERIOD_MS); | ||
| } | ||
|
|
||
| void delayMicroseconds(unsigned long us) override { | ||
| uint64_t m = (uint64_t)esp_timer_get_time(); | ||
| if(us) { | ||
| uint64_t e = (m + us); | ||
| if(m > e) { // overflow | ||
| while((uint64_t)esp_timer_get_time() > e) { | ||
| NOP(); | ||
| } | ||
| } | ||
| while((uint64_t)esp_timer_get_time() < e) { | ||
| NOP(); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| unsigned long millis() override { | ||
| return((unsigned long)(esp_timer_get_time() / 1000ULL)); | ||
| } | ||
|
|
||
| unsigned long micros() override { | ||
| return((unsigned long)(esp_timer_get_time())); | ||
| } | ||
|
|
||
| long pulseIn(uint32_t pin, uint32_t state, unsigned long timeout) override { | ||
| if(pin == RADIOLIB_NC) { | ||
| return(0); | ||
| } | ||
|
|
||
| this->pinMode(pin, INPUT); | ||
| uint32_t start = this->micros(); | ||
| uint32_t curtick = this->micros(); | ||
|
|
||
| while(this->digitalRead(pin) == state) { | ||
| if((this->micros() - curtick) > timeout) { | ||
| return(0); | ||
| } | ||
| } | ||
|
|
||
| return(this->micros() - start); | ||
| } | ||
|
|
||
| void spiBegin() { | ||
| // enable peripheral | ||
| DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_SPI2_CLK_EN); | ||
| DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_SPI2_RST); | ||
|
|
||
| // reset the control struct | ||
| this->spi->slave.trans_done = 0; | ||
| this->spi->slave.val = 0; | ||
| this->spi->pin.val = 0; | ||
| this->spi->user.val = 0; | ||
| this->spi->user1.val = 0; | ||
| this->spi->ctrl.val = 0; | ||
| this->spi->ctrl1.val = 0; | ||
| this->spi->ctrl2.val = 0; | ||
| this->spi->clock.val = 0; | ||
| this->spi->user.usr_mosi = 1; | ||
| this->spi->user.usr_miso = 1; | ||
| this->spi->user.doutdin = 1; | ||
| for(uint8_t i = 0; i < 16; i++) { | ||
| this->spi->data_buf[i] = 0x00000000; | ||
| } | ||
|
|
||
| // set SPI mode 0 | ||
| this->spi->pin.ck_idle_edge = 0; | ||
| this->spi->user.ck_out_edge = 0; | ||
|
|
||
| // set bit order to MSB first | ||
| this->spi->ctrl.wr_bit_order = 0; | ||
| this->spi->ctrl.rd_bit_order = 0; | ||
|
|
||
| // set the clock | ||
| this->spi->clock.val = spiFrequencyToClockDiv(2000000); | ||
|
|
||
| // initialize pins | ||
| this->pinMode(this->spiSCK, OUTPUT); | ||
| this->pinMode(this->spiMISO, INPUT); | ||
| this->pinMode(this->spiMOSI, OUTPUT); | ||
| gpio_matrix_out(this->spiSCK, HSPICLK_OUT_IDX, false, false); | ||
| gpio_matrix_in(this->spiMISO, HSPIQ_OUT_IDX, false); | ||
| gpio_matrix_out(this->spiMOSI, HSPID_IN_IDX, false, false); | ||
| } | ||
|
|
||
| void spiBeginTransaction() { | ||
| // not needed - in ESP32 Arduino core, this function | ||
| // repeats clock div, mode and bit order configuration | ||
| } | ||
|
|
||
| uint8_t spiTransferByte(uint8_t b) { | ||
| this->spi->mosi_dlen.usr_mosi_dbitlen = 7; | ||
| this->spi->miso_dlen.usr_miso_dbitlen = 7; | ||
| this->spi->data_buf[0] = b; | ||
| this->spi->cmd.usr = 1; | ||
| while(this->spi->cmd.usr); | ||
| return(this->spi->data_buf[0] & 0xFF); | ||
| } | ||
|
|
||
| void spiTransfer(uint8_t* out, size_t len, uint8_t* in) { | ||
| for(size_t i = 0; i < len; i++) { | ||
| in[i] = this->spiTransferByte(out[i]); | ||
| } | ||
| } | ||
|
|
||
| void spiEndTransaction() { | ||
| // nothing needs to be done here | ||
| } | ||
|
|
||
| void spiEnd() { | ||
| // detach pins | ||
| gpio_matrix_out(this->spiSCK, MATRIX_DETACH_OUT_SIG, false, false); | ||
| gpio_matrix_in(this->spiMISO, MATRIX_DETACH_IN_LOW_PIN, false); | ||
| gpio_matrix_out(this->spiMOSI, MATRIX_DETACH_OUT_SIG, false, false); | ||
| } | ||
|
|
||
| private: | ||
| // the HAL can contain any additional private members | ||
| int8_t spiSCK; | ||
| int8_t spiMISO; | ||
| int8_t spiMOSI; | ||
| spi_dev_t * spi = (volatile spi_dev_t *)(DR_REG_SPI2_BASE); | ||
| }; | ||
|
|
||
| #endif |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| ## IDF Component Manager Manifest File | ||
| dependencies: | ||
| ## Required IDF version | ||
| idf: | ||
| version: '>=4.1.0' | ||
| # # Put list of dependencies here | ||
| # # For components maintained by Espressif: | ||
| # component: "~1.0.0" | ||
| # # For 3rd party components: | ||
| # username/component: ">=1.0.0,<2.0.0" | ||
| # username2/component2: | ||
| # version: "~1.0.0" | ||
| # # For transient dependencies `public` flag can be set. | ||
| # # `public` flag doesn't have an effect dependencies of the `main` component. | ||
| # # All dependencies of `main` are public by default. | ||
| # public: true | ||
| jgromes/radiolib: ^7.6.0 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| #pragma once | ||
| #ifdef __cplusplus | ||
| extern "C" { | ||
| #endif | ||
|
|
||
| #include <stdint.h> | ||
|
|
||
| struct message_t { | ||
| uint8_t *data; // max packet size for LLCC68 is 255 bytes, and 254 with address filtering, but we don't use address filtering | ||
| size_t length; | ||
| }; | ||
|
|
||
| #ifdef __cplusplus | ||
| } | ||
| #endif |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You might want to set the idf version >6.0.0
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
oh yeah, that's an artifact because the branch is based on an old version of vigilant engine.
all of this is work in progress btw, just wanted to create a PR to have some overview of my changes
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yea no worries, i thought that ^^