diff --git a/docs/_static/e32-443t37s-wiring.png b/docs/_static/e32-443t37s-wiring.png index 62da154..0d67711 100644 Binary files a/docs/_static/e32-443t37s-wiring.png and b/docs/_static/e32-443t37s-wiring.png differ diff --git a/docs/_static/ebyte-graph-tx-modes.jpg b/docs/_static/ebyte-graph-tx-modes.jpg new file mode 100644 index 0000000..b783b5b Binary files /dev/null and b/docs/_static/ebyte-graph-tx-modes.jpg differ diff --git a/docs/_static/lora-phy-size-limit-mention.png b/docs/_static/lora-phy-size-limit-mention.png new file mode 100644 index 0000000..d0a2c3f Binary files /dev/null and b/docs/_static/lora-phy-size-limit-mention.png differ diff --git a/docs/_static/wiring_blackpill.png b/docs/_static/wiring_blackpill.png new file mode 100644 index 0000000..9cd9afa Binary files /dev/null and b/docs/_static/wiring_blackpill.png differ diff --git a/docs/_static/wiring_esp32s3.png b/docs/_static/wiring_esp32s3.png new file mode 100644 index 0000000..9f86954 Binary files /dev/null and b/docs/_static/wiring_esp32s3.png differ diff --git a/docs/conf.py b/docs/conf.py index 63bacaa..bd357b1 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -40,6 +40,6 @@ html_css_files = ["extra_styles.css"] # The short X.Y version. -version = "0.7" +version = "0.8" # The full version, including alpha/beta/rc tags. -release = "0.7.0" +release = "0.8.0" diff --git a/docs/examples_error_handling.rst b/docs/examples_error_handling.rst new file mode 100644 index 0000000..cdfa154 --- /dev/null +++ b/docs/examples_error_handling.rst @@ -0,0 +1,35 @@ +Error Handling ⚠️ Must-read ⚠️ +------------------------------ +These examples will show you how to recover from errors returned by the ``E32Device`` class. + +Config Changes +^^^^^^^^^^^^^^ +If you get an ``E32GenericError`` exception when changing the module's config, you will need to follow this procedure. + +**Expected error:** + + ``E32GenericError: The module didn't return the new config !`` + +**Resolution procedure:** + +* Catch error in a ``try except`` block. + +* Reset the module via ``E32Device.reset()``. + +* Wait some time for it to restart. + +* Re-apply the config with ``E32Device.update_config()``. + +* Go back into the original mode. + +* Retry the code that raised the error + +**Warning:** + + Failure to follow the procedure WILL result in a module that no longer applies new operating parameters + given to it ! + +.. literalinclude:: ../examples/error_handling.py + :caption: examples/error_handling.py + :emphasize-lines: 24-45 + :linenos: diff --git a/docs/examples_transmit_transparent.rst b/docs/examples_transmit_transparent.rst index 31a3faa..9cff040 100644 --- a/docs/examples_transmit_transparent.rst +++ b/docs/examples_transmit_transparent.rst @@ -16,6 +16,18 @@ due to RF regulations.** :emphasize-lines: 19,22,26-40 :linenos: +Monitor +^^^^^^^ +Monitors channel `4` for messages by using the `0xFFFF` address. + +⚠️ **Received messages may be truncated at specific lengths depending on the frequencies and operating parameters used +due to RF regulations.** + +.. literalinclude:: ../examples/transmit_transparent/monitor.py + :caption: examples/transmit_transparent/monitor.py + :emphasize-lines: 19,22,26-40 + :linenos: + Sender ^^^^^^ Sends a message to any modules on channel `4` with the `0x1337` address. @@ -27,3 +39,16 @@ due to RF regulations.** :caption: examples/transmit_transparent/sender.py :emphasize-lines: 19,22,27,30,35-38 :linenos: + + +Broadcast +^^^^^^^^^ +Broadcasts a messages to all modules on channel `4` by using the `0xFFFF` address. + +⚠️ **Sent messages may be truncated at specific lengths depending on the frequencies and operating parameters used +due to RF regulations.** + +.. literalinclude:: ../examples/transmit_transparent/broadcast.py + :caption: examples/transmit_transparent/broadcast.py + :emphasize-lines: 19,22,27,30,35-38 + :linenos: diff --git a/docs/examples_wiring.rst b/docs/examples_wiring.rst index 3708758..fc3b090 100644 --- a/docs/examples_wiring.rst +++ b/docs/examples_wiring.rst @@ -7,18 +7,22 @@ The pictures in this section will be changed to better ones soon. ESP32-S3 ^^^^^^^^ -TODO +In this example, the E32-433T20DC module is connected to a ESP32-S3. -.. image:: _static/wiring_esp32s3_temp.jpg - :width: 80% - :alt: Picture of a E32-433T20D connected to an ESP32-S3. +This MCU serves as an example for MCU's that don't restrict certain functionalities such as UART to specific pins. + +The only issue that could be pointed out is the fact it is powered by 3.3V which could cause power dips more easily. + +.. image:: _static/wiring_esp32s3.png + :width: 90% + :alt: Schematic of an E32-433T20D connected to an ESP32-S3. :align: center -:raw-html:`[Insert caption here...]` +:raw-html:`Configuration used in all sender examples.` STM32 Black Pill ^^^^^^^^^^^^^^^^ -In this example, E32 module is connected to a STM32F411CE Black Pill. +In this example, the E32-433T20DC module is connected to a STM32F411CE Black Pill. This MCU requires the some specific pins to be used for the UART bus. :raw-html:`
` @@ -38,12 +42,12 @@ The MCU's `USART1` pins are both used out-of-the-box, so we'll need to use the ` | **AUX** | ``board.B7`` | ``PB7`` | Generic I/O | Any input pin | +---------+--------------+-----------+---------------+------------------+ -.. image:: _static/wiring_blackpill_temp.jpg - :width: 80% - :alt: Picture of a E32-433T20D connected to a STM32F411CE Black Pill. +.. image:: _static/wiring_blackpill.png + :width: 90% + :alt: Schematic of an E32-433T20D connected to a STM32F411CE Black Pill. :align: center -:raw-html:`[Insert caption here...]` +:raw-html:`Configuration used in all receiver examples.` Other boards ^^^^^^^^^^^^ diff --git a/docs/index.rst b/docs/index.rst index dcd9017..6c03533 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -27,6 +27,7 @@ Table of Contents examples_uart examples_transmit_fixed examples_transmit_transparent + examples_error_handling .. toctree:: :maxdepth: 2 diff --git a/docs/introduction.rst b/docs/introduction.rst index 9151054..a426001 100644 --- a/docs/introduction.rst +++ b/docs/introduction.rst @@ -8,7 +8,7 @@ CircuitPython Ebyte E32 Library =============================== -CircuitPython driver for Ebyte's E32 LoRa modules. +CircuitPython driver for Ebyte's E32 UART LoRa modules that use the SX1278/SX1276 chipsets. Legal Preamble ^^^^^^^^^^^^^^ @@ -23,7 +23,6 @@ Features - Extra support on a per-frequency and per-power basis: - More descriptive constants for TX power. - - Channel <-> frequency converters. - Maximum packet size calculators. (TODO) - Entirely optional via separate modules. @@ -44,9 +43,9 @@ Limitations - All LoRa packets are glued back-to-back when received. - **No LoraWAN support** -- Missing extra support for some modules: +- Missing support for some modules: - - Modules with `170`, `400`, `868`, `900`, and `915` prefix. *(Will improve overtime)* + - Modules with ``170``, ``400`` and ``900`` prefix. *(Will improve overtime)* Dependencies ^^^^^^^^^^^^ diff --git a/docs/technical_details_e32.rst b/docs/technical_details_e32.rst index 702f659..2dd41e4 100644 --- a/docs/technical_details_e32.rst +++ b/docs/technical_details_e32.rst @@ -178,6 +178,25 @@ The ``E32-433T27D`` variant is mentioned in the `E32 V1.30 User Manual and on its `product page `_ but no proper datasheet could be found for it. +Transmission Modes +^^^^^^^^^^^^^^^^^^ +The E32 modules support 2 modes of communication named `"Transparent"` and `"Fixed"`. + +The main characteristic of `"Fixed"` mode is that it requires you to prepend you message with a target +address and channel. + +And for `"Transparent"` mode, you can broadcast as well as monitor. + +Please note that Ebyte's infographic shown below doesn't state that modules in `"Transparent"` modes needs +to be set on the same channel and address, but you absolutely need to. + +.. image:: _static/ebyte-graph-tx-modes.jpg + :width: 80% + :alt: Ebyte E32 modules transmissions modes infographic + :align: center + +:raw-html:`E32 Transmission modes. Credit: Ebyte's official store on aliexpress.com` + Datasheets ^^^^^^^^^^ All datasheets are hosted by Ebyte on *ebyte.com* and *cdebyte.com* unless specified otherwise. diff --git a/docs/technical_details_lora.rst b/docs/technical_details_lora.rst index d1c7c69..fa75e61 100644 --- a/docs/technical_details_lora.rst +++ b/docs/technical_details_lora.rst @@ -1,7 +1,77 @@ -LoRa (TODO) ------------ -TODO +.. role:: raw-html(raw) + :format: html -Spreading Factor -^^^^^^^^^^^^^^^^ -TODO +LoRa +---- +LoRa is a RF modulation technology engineered to be quite resilient to allow long-distance communications with a +relatively low power-consumption. + +It is also referred to as `LoRa PHY`. + +Max Message Length +^^^^^^^^^^^^^^^^^^ +⚠️ **Do not confuse with LoRaWAN limits** ⚠️ + +Due to some legal limitations regarding the maximum RF air-time that can be used by LoRa, there is a limit to how +long each packet can be. + +If given more data than what should be transmitted in a single packet, the E32 modules will segment that data +and transfer it as individual packets. + +This automatic segmentation can be a problem in fixed transmissions since it completely erase the target address and +channel from any subsequent packet. + +This limit can be **somewhat** ignored when using transparent communications since the message doesn't +contain the target address and channel, but steps should be taken to not rely on this behaviour. + +Official limits +""""""""""""""" +I couldn't find any concrete limits for packet size on LoRa PHY. + +All I know is that is depends on a maximum air-time limit enforced by local RF laws which is defined by the +air data rate and some other parameters. + +As of now, you should try different sizes at your desired operating settings in fixed mode to find that limit. + +Here is an excerpt from the `"LoraWAN Regional Parameters RP002-1.0.4"` document: + +.. image:: _static/lora-phy-size-limit-mention.png + :width: 80% + :alt: Mention of PHY restrictions influencing LoRaWAN max packet size. + :align: center + +:raw-html:`Mention of PHY restrictions finfluencing LoRaWAN max packet size.` + +Observed limits +""""""""""""""" +TODO: Check if it depends on the spread factor or just operating parameters and region. + +If you can, please contribute to these tables by raising an issue. + +Documentation +""""""""""""" + +* `LoRaWAN Packet Size Considerations (By The Things Network) `_ + +Spreading Factor (SF) +^^^^^^^^^^^^^^^^^^^^^ +The spreading factor is a mechanism that influence the air data rate, time-on-air and the receiver's sensitivity. +:raw-html:`
` +It can be one of 6 values between ``SF7`` and ``SF12``. + +I can't for the life of me give you a clear and concise explanation or table of these values and their effect +as well as the operating parameters that would be appropriate for them. +:raw-html:`
` +**Absolutely nobody who should be able to** can make a document that is concise, complete and +doesn't expect the reader to glue bits and pieces from 20+ different documents to get a complete view that +doesn't only cover part of these SF values because of some arcane reasons. + +Here are some links to documentation I'd recommend on the subject: + +* `Spreading Factors (By The Things Network) `_ + +* `Spreading Factor (By iotjourney.orange.com) `_ + +* `LoRa SF explained (By blog.ttulka.com) `_ + +Good luck. diff --git a/docs/technical_details_lorawan.rst b/docs/technical_details_lorawan.rst index f60aa5a..11d8116 100644 --- a/docs/technical_details_lorawan.rst +++ b/docs/technical_details_lorawan.rst @@ -3,6 +3,10 @@ LoRaWAN ------- +⚠️ **LoRaWAN isn't supported by this project !** ⚠️ + +Technical details +^^^^^^^^^^^^^^^^^ This section will only contain some basic information about some of LoRaWAN's mechanisms. We strongly recommend you consult the documentation provided by `The Things Network` and `LoRa Alliance` diff --git a/docs/technical_details_preamble.rst b/docs/technical_details_preamble.rst index 43cd2f5..01d4976 100644 --- a/docs/technical_details_preamble.rst +++ b/docs/technical_details_preamble.rst @@ -27,6 +27,8 @@ If you need a simple example to motivate you into ready this section, read the f Depending on the frequencies, region and data rates, **a LoRa packet cannot be larger than 11 bytes** under unfavorable conditions, **or 250 bytes** under favorable ones. +You can go to ??? for more information on this limitation. + .. _ref-legal-aside: Legal Aside diff --git a/ebyte_e32/__init__.py b/ebyte_e32/__init__.py index a3041db..c88d6c9 100644 --- a/ebyte_e32/__init__.py +++ b/ebyte_e32/__init__.py @@ -296,22 +296,9 @@ class E32Device: """ _m0: DigitalInOut - """M0 pin used to set the module's mode.""" - _m1: DigitalInOut - """M1 pin used to set the module's mode.""" - _aux: Optional[DigitalInOut] - """ - AUX pin used by the module to indicate its working status or to wake up the MCU. - - May be left floating and ignored during normal operations. - """ - _uart: UART - """ - UART connection to the E32 module. - """ _uart_pin_tx: Pin _uart_pin_rx: Pin @@ -424,7 +411,7 @@ def flush_uart(self): """ self._uart.reset_input_buffer() - def wait_aux(self, max_wait_ms: int = 150): + def wait_aux(self, max_wait_ms: int = 250): """ Wait for the `AUX` pin to go high meaning that the module is ready for communications. diff --git a/ebyte_e32/__version__.py b/ebyte_e32/__version__.py index a8378e8..8487d20 100644 --- a/ebyte_e32/__version__.py +++ b/ebyte_e32/__version__.py @@ -6,6 +6,6 @@ """ MAJOR = 0 -MINOR = 7 +MINOR = 8 PATCH = 0 VERSION = f"{MAJOR}.{MINOR}.{PATCH}" diff --git a/examples/error_handling.py b/examples/error_handling.py new file mode 100644 index 0000000..d2620ad --- /dev/null +++ b/examples/error_handling.py @@ -0,0 +1,56 @@ +# SPDX-FileCopyrightText: 2023 Herwin Bozet +# +# SPDX-License-Identifier: Unlicense + +import board +import time + +import ebyte_e32 +import ebyte_e32.exceptions + +PIN_M0 = board.B3 +PIN_M1 = board.B4 +PIN_RXD = board.A2 # Pin marked as RX on the module +PIN_TXD = board.A3 # Pin marked as TX on the module +PIN_AUX = board.B7 + +e32 = ebyte_e32.E32Device(PIN_M0, PIN_M1, PIN_AUX, PIN_TXD, PIN_RXD, address=0x1337, channel=0) + +# We'll be iterating over each channel +channel = 0 +while True: + print(f"Moving to channel {channel}") + + try: + # Can cause errors if the module fails to respond to config request when validating it. + e32.channel = channel + e32.wait_aux() + except ebyte_e32.exceptions.E32GenericError: + print("Failed to change !") + + # We reset it and wait more than what AUX indicates. + e32.reset(True) + time.sleep(2) + + # We re-apply the `E32Device` class' config + e32.update_config() + e32.wait_aux() + + # Going back to the appropriate mode + e32.mode = ebyte_e32.Modes.MODE_NORMAL + e32.wait_aux() + + # Retrying to change channels and send the message. + time.sleep(1) + continue + + e32.send(b'Hello World !') + e32.wait_aux() + + time.sleep(2.5) + + channel = channel + 1 + if channel > ebyte_e32.CHANNEL_MAX: + channel = ebyte_e32.CHANNEL_MIN + + time.sleep(2.5) diff --git a/examples/transmit_transparent/broadcast.py b/examples/transmit_transparent/broadcast.py new file mode 100644 index 0000000..57b14ce --- /dev/null +++ b/examples/transmit_transparent/broadcast.py @@ -0,0 +1,41 @@ +# SPDX-FileCopyrightText: 2023 Herwin Bozet +# +# SPDX-License-Identifier: Unlicense + +import board +import time + +import ebyte_e32 + +PIN_M0 = board.IO13 +PIN_M1 = board.IO12 +PIN_RXD = board.IO11 # Pin marked as RX on the module +PIN_TXD = board.IO10 # Pin marked as TX on the module +PIN_AUX = board.IO9 + +e32 = ebyte_e32.E32Device(PIN_M0, PIN_M1, PIN_AUX, PIN_TXD, PIN_RXD, address=0xFFFF, channel=4) + +# Switching to transparent transmission mode. +e32.tx_mode = ebyte_e32.TransmissionMode.TRANSMISSION_TRANSPARENT + +# Switching to mode 0. (Normal mode) +e32.mode = ebyte_e32.Modes.MODE_NORMAL + +# Message content: +# * Message: b'Hello World !' +# The target channel is the same as the module's. +message = b'Hello World !' + +# Sending with helper +e32.send(message) + +time.sleep(0.5) # Waiting to prevent RF spamming + +# Switching to an empty channel and sending another message. +e32.channel = 5 +message = b'You shouldn\'t receive this !' +e32.send(message) +e32.wait_aux() + +# The message may be truncated at specific lengths depending on the frequencies used. +# Please check the documentation for more information ! diff --git a/examples/transmit_transparent/monitor.py b/examples/transmit_transparent/monitor.py new file mode 100644 index 0000000..fb8276f --- /dev/null +++ b/examples/transmit_transparent/monitor.py @@ -0,0 +1,44 @@ +# SPDX-FileCopyrightText: 2023 Herwin Bozet +# +# SPDX-License-Identifier: Unlicense + +import board +import time + +import ebyte_e32 + +PIN_M0 = board.B3 +PIN_M1 = board.B4 +PIN_RXD = board.A2 # Pin marked as RX on the module +PIN_TXD = board.A3 # Pin marked as TX on the module +PIN_AUX = board.B7 + +e32 = ebyte_e32.E32Device(PIN_M0, PIN_M1, PIN_AUX, PIN_TXD, PIN_RXD, address=0xFFFF, channel=4) + +# Switching to transparent transmission mode. (Default) +e32.tx_mode = ebyte_e32.TransmissionMode.TRANSMISSION_TRANSPARENT + +# Switching to mode 0. (Normal mode) +e32.mode = ebyte_e32.Modes.MODE_NORMAL + +print(f"Monitoring messages on channel {e32.channel} ...") + +while True: + # Checking if the module sent us some data + if e32.in_buffer > 0: + # Wait for the module to finish receiving data + e32.wait_aux() + + # We grab the data, and can process it here + data = e32.read() + + # We print it and exit + print(f"We received a {len(data)} byte(s) long message:") + print(data) + + # If nothing was received, we wait. + time.sleep(0.1) + +print() +print("Now exiting...") +e32.deinit() diff --git a/examples/transmit_transparent/receiver.py b/examples/transmit_transparent/receiver.py index cf4d46b..a5ba2a7 100644 --- a/examples/transmit_transparent/receiver.py +++ b/examples/transmit_transparent/receiver.py @@ -21,7 +21,7 @@ # Switching to mode 0. (Normal mode) e32.mode = ebyte_e32.Modes.MODE_NORMAL -print(f"Waiting for messages... on channel {e32.channel} between devices with the 0x{e32.address:x} address ...") +print(f"Waiting for messages on channel {e32.channel} between devices with the 0x{e32.address:x} address ...") while True: # Checking if the module sent us some data diff --git a/examples/transmit_transparent/sender.py b/examples/transmit_transparent/sender.py index 014b845..6914831 100644 --- a/examples/transmit_transparent/sender.py +++ b/examples/transmit_transparent/sender.py @@ -15,7 +15,7 @@ e32 = ebyte_e32.E32Device(PIN_M0, PIN_M1, PIN_AUX, PIN_TXD, PIN_RXD, address=0x1337, channel=4) -# Switching to fixed transmission mode. +# Switching to transparent transmission mode. e32.tx_mode = ebyte_e32.TransmissionMode.TRANSMISSION_TRANSPARENT # Switching to mode 0. (Normal mode) diff --git a/readme.md b/readme.md index 8cd5690..8ad93e7 100644 --- a/readme.md +++ b/readme.md @@ -1,11 +1,10 @@ # CircuitPython Ebyte E32 Library -CircuitPython driver for Ebyte's E32 UART LoRa modules. +CircuitPython driver for Ebyte's E32 UART LoRa modules that use the SX1278/SX1276 chipsets. ## Features * Supports all standard E32 UART modules. * Extra support on a per-frequency and per-power basis: * More descriptive constants for TX power. - * Channel <-> frequency converters. * ~~Maximum packet size calculators~~. (TODO) * Entirely optional via separate modules. * Minified versions for devices with tiny storage space: @@ -67,6 +66,7 @@ The same error may be raised when you change any operating setting. ## Links ### Resources +* [xreef's E32 driver for Arduino](https://github.com/xreef/LoRa_E32_Series_Library) * [Effevee's E32 driver for MicroPython](https://github.com/effevee/loraE32/) * [LoRa and LoRaWAN quick overview (By SemTech)](https://lora-developers.semtech.com/documentation/tech-papers-and-guides/lora-and-lorawan) * [LoRa frequency plan by country (By The Things Network)](https://www.thethingsnetwork.org/docs/lorawan/frequencies-by-country/)