domingo, 27 de novembro de 2022

LOM204A - Criando uma REDE LoRa MESH com Library RADIOHEAD - Gateway

O objetivo deste BLOG é demonstrar como é possível utilizar o ARDUINO para programação do WISOL LOM204A e assim criar uma rede MESH. 

Dados do Nós ("Hello World!") serão enviados para a Bridge->Gateway (LOM204A conectado ao U-blox NINA W106) e este conectado à nuvem fará os envio dos mesmos à um Servidor TCP na porta 8090.

Foram utilizados o 3 KITS LOM204A para os testes e um BREAKOUT U-blox NINA W106.

BETA - EM TESTES - APENAS PARA PROGRAMADORES ARDUINO QUE CONHEÇAM A LIBRARY RADIOHEAD e REDE LoRa MESH

Baseado no cmwx1zzabz

LOM204A (MESH) e u-BLOX NINA W106 (Gateway)

U-blox NINA W106 
Deve ser teu conhecimento que a ESPRESSIF tem um firmware que permite "programar" o ESP32 (NINA W102) via comandos AT e ter acesso ao WIFI 802.11 e BT 4.2


Para o LOM204A ter acesso aos comandos AT do U-blox NINA W106, foi utilizada a LIB 


Rede LoRa MESH

Num mundo perfeito tudo é fácil, num mundo real...

... mesmo um rádio de longo alcance pode não ser suficiente: quando há obstáculos, paredes, colocação não ideal de nós.

Seus nós estão fora do alcance do seu gateway? Você precisa adicionar um nó, mas...? Você precisa de um repetidor?

Não, você precisa de uma malha (e talvez mais alguns nós)!
Principais Dúvidas

Tenho 3 módulos para testar LoRa MESH!  As principais dúvidas são:

-E necessário ter uma Bridge?
-Os outros 2 devem ser nós?
-Cada nó deve ter o seu ID (0,1,..)?
-O único que pode transmitir dados deve ser os nós? E todos vão transmitir para o servidor/bridge?
-Ou a transmissão de dados é bidirecional?

Respostas

-Bridges não são obrigatórias, você pode ter quantos nós ou bridges quiser (por exemplo, sua rede pode ser composta de 3 nós)
-Uma bridge é um nó com recursos adicionais (por exemplo, encaminhando as mensagens recebidas dos nós para um servidor na Internet)
-Sim, cada nó/bridge tem que ter um ID diferente (0-254)
-Cada nó pode transmitir para outro nó ou para uma bridge e cada nó ou bridge pode responder ao remetente
-A comunicação é bidirecional

RADIOHEAD

É uma biblioteca completa orientada a objetos para enviar e receber pacotes de mensagens por meio de uma variedade de rádios de dados e outros transportes em uma variedade de microprocessadores.

DRIVER

Neste caso, será utilizado com o SX1276 o driver RH_ABZ da RADIOHEAD, incorporado no LOM204A

Veja

MANAGER

RHDatagram Addressed
RHReliableDatagram Addressed
RHRouter Multi-hop
RHMesh Multi-hop 

Descoberta de rota

Quando um nó de malha RHMesh é inicializado, ele não conhece nenhuma rota para nenhum outro nó (consulte RHRouter para obter detalhes sobre a rota e a tabela de roteamento). Quando você tenta enviar uma mensagem com sendtoWait, primeiro verifica se há uma rota para o nó de destino na tabela de roteamento. Caso contrário, inicializará 'Route Discovery'. Quando um nó precisa descobrir uma rota para outro nó, ele transmite MeshRouteDiscoveryMessage com um tipo de mensagem RH_MESH_MESSAGE_TYPE_ROUTE_DISCOVERY_REQUEST. Qualquer nodo que receba tal requisição verifica se é uma requisição para uma rota para si mesmo (neste caso ele faz uma resposta unicast para o nodo de origem com uma MeshRouteDiscoveryMessage com tipo de mensagem RH_MESH_MESSAGE_TYPE_ROUTE_DISCOVERY_RESPONSE) caso contrário retransmite a requisição, após adicionar-se à lista de nodos visitados até então pela requisição.

Se um nodo recebe um RH_MESH_MESSAGE_TYPE_ROUTE_DISCOVERY_REQUEST que já está listado nos nodos visitados, ele sabe que já viu e retransmitiu esta requisição, portanto a ignora. Isso evita tempestades de transmissão. Quando um nodo recebe um RH_MESH_MESSAGE_TYPE_ROUTE_DISCOVERY_REQUEST, ele pode usar a lista de nodos já visitados para deduzir rotas de volta ao originador (nodo solicitante). Isso também significa que, quando o nó de destino da solicitação for alcançado, ele (e todos os nós anteriores que a solicitação visitou) terá uma rota de volta ao nó de origem. Isso significa que a resposta unicast RH_MESH_MESSAGE_TYPE_ROUTE_DISCOVERY_RESPONSE será roteada com sucesso de volta ao solicitante da rota original.

O RH_MESH_MESSAGE_TYPE_ROUTE_DISCOVERY_RESPONSE enviado de volta pelo nó de destino contém a lista completa de nós que foram visitados no caminho para o destino. Portanto, nós intermediários que roteiam a resposta de volta para o nó de origem podem usar a lista de nós na resposta para deduzir rotas para todos os nós entre ele e o nó de destino.

Portanto, RH_MESH_MESSAGE_TYPE_ROUTE_DISCOVERY_REQUEST e RH_MESH_MESSAGE_TYPE_ROUTE_DISCOVERY_RESPONSE juntos garantem que o solicitante original e todos os nós intermediários saibam como rotear para os nós de origem e destino e todos os nós ao longo do caminho.

Observe que há uma condição de corrida aqui que pode afetar o roteamento em rotas multipath. Por exemplo, se a rota para o destino puder percorrer vários caminhos, a última resposta do destino será a usada.

Falha na rota

O RHRouter (e, portanto, o RHMesh ) usa a entrega confiável de mensagens salto a salto usando confirmações de salto a salto, mas não confirmações de ponta a ponta. Quando sendtoWait() retorna, você sabe que a mensagem foi entregue ao próximo salto, mas não se ela foi (ou mesmo se pode ser) entregue ao nó de destino. Se durante o roteamento hop-to-hop de uma mensagem, um dos nós RHMesh intermediários descobrir que não pode entregar para o próximo salto (por exemplo, devido a uma rota perdida ou nenhum reconhecimento do próximo salto), ele responde ao originador com uma MeshRouteFailureMessage unicastMensagem RH_MESH_MESSAGE_TYPE_ROUTE_FAILURE. Os nós intermediários (no caminho de volta ao originador) e o nó de origem usam esta mensagem para excluir a rota para o nó de destino da mensagem original. Isso significa que se uma rota para um destino se tornar inutilizável (porque um nó intermediário está fora do ar ou saiu do alcance), uma nova rota será estabelecida na próxima vez que uma mensagem for enviada.

Memória

Os programas RHMesh requerem uma quantidade significativa de SRAM, muitas vezes aproximando-se de 2kbytes, o que está além ou nos limites de alguns Arduinos e outros processadores. Programas com software adicional além dos programas RHMesh básicos podem exigir ainda mais. Se você tiver SRAM insuficiente para o seu programa, isso pode resultar em falha na execução ou travamentos estranhos e outros comportamentos difíceis de rastrear. Neste caso você deve considerar um processador com mais SRAM.

PRIMEIROS PASSOS
CONFIGURAÇÕES PARA SEREM COMPATÍVEIS COM LOM204A

NO ARDUINO, ESCOLHA NUCLEO-L073RZ


CRIE O EXEMPLO EXEMPLO NODE_4 E ALTERE O CÓDIGO PARA 

// node // -*- mode: C++ -*- // Example sketch showing how to create a simple addressed, routed reliable messaging client // with the RHMesh class. // It is designed to work with the other examples abz_mesh_server* // Hint: you can simulate other network topologies by setting the // RH_TEST_NETWORK define in RHRouter.h // Mesh has much greater memory requirements, and you may need to limit the // max message length to prevent wierd crashes #define RH_MESH_MAX_MESSAGE_LEN 50 #include <RHMesh.h> #include <RH_ABZ.h> #include <SPI.h> // In this small artifical network of 4 nodes, #define BRIDGE_ADDRESS 1 // address of the bridge ( we send our data to, hopefully the bridge knows what to do with our data ) #define NODE_ADDRESS 4 // address of this node #define RXTIMEOUT 3000 // it is roughly the delay between successive transmissions // Singleton instance of the radio driver RH_ABZ abz; // Class to manage message delivery and receipt, using the driver declared above RHMesh manager(abz, NODE_ADDRESS); void setup() { //MIGUEL //TCXO - ENABLE pinMode(24, OUTPUT); digitalWrite(24, HIGH); Serial.begin(115200); Serial.print(F("initializing node ")); Serial.print(NODE_ADDRESS); if (!manager.init()) {Serial.println(" init failed");} else {Serial.println(" done");} // Defaults after init are 434.0MHz, 0.05MHz AFC pull-in, modulation FSK_Rb2_4Fd36 abz.setTxPower(10, false); // with false output is on PA_BOOST, power from 2 to 20 dBm, use this setting for high power demos/real usage //abz.setTxPower(1, true); // true output is on RFO, power from 0 to 15 dBm, use this setting for low power demos ( does not work on lilygo lora32 ) abz.setFrequency(868.0); abz.setCADTimeout(500); // long range configuration requires for on-air time boolean longRange = false; if (longRange) { // custom configuration RH_ABZ::ModemConfig modem_config = { 0x78, // Reg 0x1D: BW=125kHz, Coding=4/8, Header=explicit 0xC4, // Reg 0x1E: Spread=4096chips/symbol, CRC=enable 0x08 // Reg 0x26: LowDataRate=On, Agc=Off. 0x0C is LowDataRate=ON, ACG=ON }; abz.setModemRegisters(&modem_config); } else { // Predefined configurations( bandwidth, coding rate, spread factor ): // Bw125Cr45Sf128 Bw = 125 kHz, Cr = 4/5, Sf = 128chips/symbol, CRC on. Default medium range // Bw500Cr45Sf128 Bw = 500 kHz, Cr = 4/5, Sf = 128chips/symbol, CRC on. Fast+short range // Bw31_25Cr48Sf512 Bw = 31.25 kHz, Cr = 4/8, Sf = 512chips/symbol, CRC on. Slow+long range // Bw125Cr48Sf4096 Bw = 125 kHz, Cr = 4/8, Sf = 4096chips/symbol, low data rate, CRC on. Slow+long range // Bw125Cr45Sf2048 Bw = 125 kHz, Cr = 4/5, Sf = 2048chips/symbol, CRC on. Slow+long range if (!abz.setModemConfig(RH_ABZ::Bw125Cr45Sf128)) {Serial.println(F("set config failed"));} } Serial.println("ABZ ready"); } uint8_t data[] = "Hello World!"; // Dont put this on the stack: uint8_t buf[RH_MESH_MAX_MESSAGE_LEN]; uint8_t res; void loop() { Serial.print("Sending to bridge n."); Serial.print(BRIDGE_ADDRESS); Serial.print(" res="); // Send a message to a abz_mesh_server // A route to the destination will be automatically discovered. res = manager.sendtoWait(data, sizeof(data), BRIDGE_ADDRESS); Serial.println(res); if (res == RH_ROUTER_ERROR_NONE) { // Data has been reliably delivered to the next node. // now we do... delay(RXTIMEOUT); // ...nothing in this minimal example, only wait before next transmission } else { Serial.println("sendtoWait failed. Are the bridge/intermediate mesh nodes running?"); } }

CRIE O EXEMPLO EXEMPLO NODE_2 E ALTERE O CÓDIGO PARA 

// node // -*- mode: C++ -*- // Example sketch showing how to create a simple addressed, routed reliable messaging client // with the RHMesh class. // It is designed to work with the other examples abz_mesh_server* // Hint: you can simulate other network topologies by setting the // RH_TEST_NETWORK define in RHRouter.h // Mesh has much greater memory requirements, and you may need to limit the // max message length to prevent wierd crashes #define RH_MESH_MAX_MESSAGE_LEN 50 #include <RHMesh.h> #include <RH_ABZ.h> #include <SPI.h> // In this small artifical network of 4 nodes, #define BRIDGE_ADDRESS 1 // address of the bridge ( we send our data to, hopefully the bridge knows what to do with our data ) #define NODE_ADDRESS 2 // address of this node #define RXTIMEOUT 3000 // it is roughly the delay between successive transmissions // Singleton instance of the radio driver RH_ABZ abz; // Class to manage message delivery and receipt, using the driver declared above RHMesh manager(abz, NODE_ADDRESS); void setup() { //MIGUEL //TCXO - ENABLE pinMode(24, OUTPUT); digitalWrite(24, HIGH); Serial.begin(115200); Serial.print(F("initializing node ")); Serial.print(NODE_ADDRESS); if (!manager.init()) {Serial.println(" init failed");} else {Serial.println(" done");} // Defaults after init are 434.0MHz, 0.05MHz AFC pull-in, modulation FSK_Rb2_4Fd36 abz.setTxPower(10, false); // with false output is on PA_BOOST, power from 2 to 20 dBm, use this setting for high power demos/real usage //abz.setTxPower(1, true); // true output is on RFO, power from 0 to 15 dBm, use this setting for low power demos ( does not work on lilygo lora32 ) abz.setFrequency(868.0); abz.setCADTimeout(500); // long range configuration requires for on-air time boolean longRange = false; if (longRange) { // custom configuration RH_ABZ::ModemConfig modem_config = { 0x78, // Reg 0x1D: BW=125kHz, Coding=4/8, Header=explicit 0xC4, // Reg 0x1E: Spread=4096chips/symbol, CRC=enable 0x08 // Reg 0x26: LowDataRate=On, Agc=Off. 0x0C is LowDataRate=ON, ACG=ON }; abz.setModemRegisters(&modem_config); } else { // Predefined configurations( bandwidth, coding rate, spread factor ): // Bw125Cr45Sf128 Bw = 125 kHz, Cr = 4/5, Sf = 128chips/symbol, CRC on. Default medium range // Bw500Cr45Sf128 Bw = 500 kHz, Cr = 4/5, Sf = 128chips/symbol, CRC on. Fast+short range // Bw31_25Cr48Sf512 Bw = 31.25 kHz, Cr = 4/8, Sf = 512chips/symbol, CRC on. Slow+long range // Bw125Cr48Sf4096 Bw = 125 kHz, Cr = 4/8, Sf = 4096chips/symbol, low data rate, CRC on. Slow+long range // Bw125Cr45Sf2048 Bw = 125 kHz, Cr = 4/5, Sf = 2048chips/symbol, CRC on. Slow+long range if (!abz.setModemConfig(RH_ABZ::Bw125Cr45Sf128)) {Serial.println(F("set config failed"));} } Serial.println("ABZ ready"); } uint8_t data[] = "Hello World!"; // Dont put this on the stack: uint8_t buf[RH_MESH_MAX_MESSAGE_LEN]; uint8_t res; void loop() { Serial.print("Sending to bridge n."); Serial.print(BRIDGE_ADDRESS); Serial.print(" res="); // Send a message to a abz_mesh_server // A route to the destination will be automatically discovered. res = manager.sendtoWait(data, sizeof(data), BRIDGE_ADDRESS); Serial.println(res); if (res == RH_ROUTER_ERROR_NONE) { // Data has been reliably delivered to the next node. // now we do... delay(RXTIMEOUT); // ...nothing in this minimal example, only wait before next transmission } else { Serial.println("sendtoWait failed. Are the bridge/intermediate mesh nodes running?"); } }

CRIE O EXEMPLO EXEMPLO NODE_2 E ALTERE O CÓDIGO PARA 

// bridge // -*- mode: C++ -*- // Example sketch showing how to create a simple addressed, routed reliable messaging client // with the RHMesh class. // It is designed to work with the other examples abz_mesh_server* // Hint: you can simulate other network topologies by setting the // RH_TEST_NETWORK define in RHRouter.h // Mesh has much greater memory requirements, and you may need to limit the // max message length to prevent wierd crashes #define RH_MESH_MAX_MESSAGE_LEN 50 #include <RHMesh.h> #include <RH_ABZ.h> #include <SPI.h> // In this small artifical network of 4 nodes, #define BRIDGE_ADDRESS 1 // address of the bridge ( we send our data to, hopefully the bridge knows what to do with our data ) #define RXTIMEOUT 3000 // it is roughly the delay between successive transmissions // Singleton instance of the radio driver RH_ABZ abz; // Class to manage message delivery and receipt, using the driver declared above RHMesh manager(abz, BRIDGE_ADDRESS); void setup() { //MIGUEL //TCXO - ENABLE pinMode(24, OUTPUT); digitalWrite(24, HIGH); Serial.begin(115200); Serial.print(F("initializing node ")); Serial.print(BRIDGE_ADDRESS); if (!manager.init()) {Serial.println(" init failed");} else {Serial.println(" done");} // Defaults after init are 434.0MHz, 0.05MHz AFC pull-in, modulation FSK_Rb2_4Fd36 abz.setTxPower(2, false); // with false output is on PA_BOOST, power from 2 to 20 dBm, use this setting for high power demos/real usage //abz.setTxPower(1, true); // true output is on RFO, power from 0 to 15 dBm, use this setting for low power demos ( does not work on lilygo lora32 ) abz.setFrequency(868.0); abz.setCADTimeout(500); // long range configuration requires for on-air time boolean longRange = false; if (longRange) { // custom configuration RH_ABZ::ModemConfig modem_config = { 0x78, // Reg 0x1D: BW=125kHz, Coding=4/8, Header=explicit 0xC4, // Reg 0x1E: Spread=4096chips/symbol, CRC=enable 0x08 // Reg 0x26: LowDataRate=On, Agc=Off. 0x0C is LowDataRate=ON, ACG=ON }; abz.setModemRegisters(&modem_config); } else { // Predefined configurations( bandwidth, coding rate, spread factor ): // Bw125Cr45Sf128 Bw = 125 kHz, Cr = 4/5, Sf = 128chips/symbol, CRC on. Default medium range // Bw500Cr45Sf128 Bw = 500 kHz, Cr = 4/5, Sf = 128chips/symbol, CRC on. Fast+short range // Bw31_25Cr48Sf512 Bw = 31.25 kHz, Cr = 4/8, Sf = 512chips/symbol, CRC on. Slow+long range // Bw125Cr48Sf4096 Bw = 125 kHz, Cr = 4/8, Sf = 4096chips/symbol, low data rate, CRC on. Slow+long range // Bw125Cr45Sf2048 Bw = 125 kHz, Cr = 4/5, Sf = 2048chips/symbol, CRC on. Slow+long range if (!abz.setModemConfig(RH_ABZ::Bw125Cr45Sf128)) {Serial.println(F("set config failed"));} } Serial.println("ABZ ready"); } uint8_t data[] = "Hello back from bridge"; // Dont put this on the stack: uint8_t buf[RH_MESH_MAX_MESSAGE_LEN]; uint8_t res; void loop() { uint8_t len = sizeof(buf); uint8_t from; if (manager.recvfromAck(buf, &len, &from)) { Serial.print("request from node n."); Serial.print(from); Serial.print(": "); Serial.print((char*)buf); Serial.print(" rssi: "); Serial.println(abz.lastRssi()); } }

ALTERE VARIANT.H PARA 


/* * Copyright (c) 2017-2018 Thomas Roell. All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal with the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimers. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimers in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of Thomas Roell, nor the names of its contributors * may be used to endorse or promote products derived from this Software * without specific prior written permission. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * WITH THE SOFTWARE. */ #ifndef _VARIANT_NUCLEO_STM32L073RZ_ #define _VARIANT_NUCLEO_STM32L073RZ_ /*---------------------------------------------------------------------------- * Definitions *----------------------------------------------------------------------------*/ #define STM32L0_CONFIG_LSECLK 32768 #define STM32L0_CONFIG_HSECLK 0 #define STM32L0_CONFIG_SYSOPT 0 /** Master clock frequency */ #define VARIANT_MCK F_CPU /*---------------------------------------------------------------------------- * Headers *----------------------------------------------------------------------------*/ #ifdef __cplusplus #include "Uart.h" #endif // __cplusplus #ifdef __cplusplus extern "C" { #endif // __cplusplus /*---------------------------------------------------------------------------- * Pins *----------------------------------------------------------------------------*/ // Number of pins defined in PinDescription array //MIGUEL #define PINS_COUNT (25u) #define NUM_DIGITAL_PINS (16u) #define NUM_ANALOG_INPUTS (6u) #define NUM_ANALOG_OUTPUTS (0u) // LEDs #define PIN_LED (13ul) #define LED_BUILTIN PIN_LED /* * Analog pins */ #define PIN_A0 (16ul) #define PIN_A1 (17ul) #define PIN_A2 (18ul) #define PIN_A3 (19ul) #define PIN_A4 (20ul) #define PIN_A5 (21ul) static const uint8_t A0 = PIN_A0; static const uint8_t A1 = PIN_A1; static const uint8_t A2 = PIN_A2; static const uint8_t A3 = PIN_A3; static const uint8_t A4 = PIN_A4; static const uint8_t A5 = PIN_A5; #define ADC_RESOLUTION 12 /* * Other pins */ #define PIN_BUTTON (22l) static const uint8_t BUTTON = PIN_BUTTON; /* * Serial interfaces */ #define SERIAL_INTERFACES_COUNT 2 #define PIN_SERIAL_RX (0ul) #define PIN_SERIAL_TX (1ul) #define PIN_SERIAL_RX (0ul) #define PIN_SERIAL_TX (1ul) #define PIN_SERIAL1_RX (2ul) #define PIN_SERIAL1_TX (8ul) /* * SPI Interfaces */ #define SPI_INTERFACES_COUNT 1 #define PIN_SPI_MISO (12u) #define PIN_SPI_MOSI (11u) #define PIN_SPI_SCK (13u) //MIGUEL static const uint8_t SS = (18u); static const uint8_t MOSI = PIN_SPI_MOSI; static const uint8_t MISO = PIN_SPI_MISO; static const uint8_t SCK = PIN_SPI_SCK; /* * Wire Interfaces */ #define WIRE_INTERFACES_COUNT 1 #define PIN_WIRE_SDA (14u) #define PIN_WIRE_SCL (15u) static const uint8_t SDA = PIN_WIRE_SDA; static const uint8_t SCL = PIN_WIRE_SCL; #define PWM_INSTANCE_COUNT 2 #ifdef __cplusplus } #endif /*---------------------------------------------------------------------------- * Arduino objects - C++ only *----------------------------------------------------------------------------*/ #ifdef __cplusplus extern Uart Serial; extern Uart Serial1; #endif // These serial port names are intended to allow libraries and architecture-neutral // sketches to automatically default to the correct port name for a particular type // of use. For example, a GPS module would normally connect to SERIAL_PORT_HARDWARE_OPEN, // the first hardware serial port whose RX/TX pins are not dedicated to another use. // // SERIAL_PORT_MONITOR Port which normally prints to the Arduino Serial Monitor // // SERIAL_PORT_USBVIRTUAL Port which is USB virtual serial // // SERIAL_PORT_LINUXBRIDGE Port which connects to a Linux system via Bridge library // // SERIAL_PORT_HARDWARE Hardware serial port, physical RX & TX pins. // // SERIAL_PORT_HARDWARE_OPEN Hardware serial ports which are open for use. Their RX & TX // pins are NOT connected to anything by default. #define SERIAL_PORT_MONITOR Serial #define SERIAL_PORT_HARDWARE1 Serial #define SERIAL_PORT_HARDWARE2 Serial1 #define SERIAL_PORT_HARDWARE_OPEN2 Serial1 #endif /*_VARIANT_NUCLEO_STM32L073RZ_ */

ALTERE RH_ABZ.CPP PARA


// RH_ABZ.cpp // // Copyright (C) 2020 Mike McCauley // $Id: RH_ABZ.cpp,v 1.1 2020/06/15 23:39:39 mikem Exp $ #if (RH_PLATFORM == RH_PLATFORM_STM32L0) && (defined STM32L082xx || defined STM32L072xx) #include <RH_ABZ.h> // Pointer to the _only_ permitted ABZ instance (there is only one radio connected to this device) RH_ABZ* RH_ABZ::_thisDevice; // The muRata cmwx1zzabz module has its builtin SX1276 radio connected to the processor's SPI1 port, // but the Arduino compatible SPI interface in Grumpy Pizzas Arduino Core is configured for SPI1 or SPI2 // depending on the exact board variant selected. // So here we define our own Arduino compatible SPI interface // so we are _sure_ to get the one connected to the radio, independent of the board variant selected #include <stm32l0_spi.h> static const stm32l0_spi_params_t RADIO_SPI_PARAMS = { STM32L0_SPI_INSTANCE_SPI1, 0, STM32L0_DMA_CHANNEL_NONE, STM32L0_DMA_CHANNEL_NONE, { STM32L0_GPIO_PIN_PA7_SPI1_MOSI, STM32L0_GPIO_PIN_PA6_SPI1_MISO, STM32L0_GPIO_PIN_PA5_SPI1_SCK, STM32L0_GPIO_PIN_NONE, }, }; // Create and configure an Arduino compatible SPI interface. This will be referred to in RHHardwareSPI.cpp // and used as the SPI interface to the radio. static stm32l0_spi_t RADIO_SPI; SPIClass radio_spi(&RADIO_SPI, &RADIO_SPI_PARAMS); // Glue code between the 'C' DIO0 interrupt and the C++ interrupt handler in RH_RF95 void RH_INTERRUPT_ATTR RH_ABZ::isr() { _thisDevice->handleInterrupt(); } RH_ABZ::RH_ABZ(): RH_RF95(RH_INVALID_PIN, RH_INVALID_PIN) { } bool RH_ABZ::init() { _thisDevice = this; // REVISIT: RESET THE RADIO??? // The SX1276 radio DIO0 is connected to STM32 pin PB4 // It will later be configured as an interrupt //MIGUEL stm32l0_gpio_pin_configure(STM32L0_GPIO_PIN_PA12, (STM32L0_GPIO_PARK_NONE | STM32L0_GPIO_PUPD_PULLDOWN | STM32L0_GPIO_OSPEED_HIGH | STM32L0_GPIO_OTYPE_PUSHPULL | STM32L0_GPIO_MODE_INPUT)); // Here we configure the interrupt handler for DIO0 to call the C++ // interrupt handler in RH_RF95, in a roundabout way #ifdef STM32L0_EXTI_CONTROL_PRIORITY_CRITICAL //MIGUEL stm32l0_exti_attach(STM32L0_GPIO_PIN_PA12, (STM32L0_EXTI_CONTROL_PRIORITY_CRITICAL | STM32L0_EXTI_CONTROL_EDGE_RISING), (stm32l0_exti_callback_t)isr, NULL); // STM32L0_EXTI_CONTROL_PRIORITY_CRITICAL not in 0.0.10 #else //MIGUEL stm32l0_exti_attach(STM32L0_GPIO_PIN_PA12, STM32L0_EXTI_CONTROL_EDGE_RISING, (stm32l0_exti_callback_t)isr, NULL); #endif //MIGUEL // The SX1276 radio slave select (NSS) is connected to STM32 pin PA15 stm32l0_gpio_pin_configure(STM32L0_GPIO_PIN_PA4, (STM32L0_GPIO_PARK_HIZ | STM32L0_GPIO_PUPD_NONE | STM32L0_GPIO_OSPEED_HIGH | STM32L0_GPIO_OTYPE_PUSHPULL | STM32L0_GPIO_MODE_OUTPUT)); // muRata cmwx1zzabz module has an antenna switch which must be driven the right way to connect the antenna // to the appropriate SX1276 pins. // Antenna switch might be something like NJG180K64, but not sure. // See Application note: AN-ZZABZ-001 P. 20/20 // in typeABZ_hardware_design_guide_revC.pdf // with 3 pins connected to STM32L0_GPIO_PIN_PA1, STM32L0_GPIO_PIN_PC2, STM32L0_GPIO_PIN_PC1 // which select RX, RFO or PA_BOOST respecitvely // See modeWillChange() for implementation of pin twiddling when the transmitter is on // // We use native STM32 calls because the various different variants in the Grumpy Pizza // Arduino core and various forks of that core have inconsistent definitions of the Arduino compatible // pins. We want to be sure we get the right ones for the muRata modules connections to the Radio //MIGUEL* stm32l0_gpio_pin_configure(STM32L0_GPIO_PIN_PA15, (STM32L0_GPIO_PARK_NONE | STM32L0_GPIO_PUPD_NONE | STM32L0_GPIO_OSPEED_LOW | STM32L0_GPIO_OTYPE_PUSHPULL | STM32L0_GPIO_MODE_OUTPUT)); //MIGUEL* stm32l0_gpio_pin_configure(STM32L0_GPIO_PIN_PC2, (STM32L0_GPIO_PARK_NONE | STM32L0_GPIO_PUPD_NONE | STM32L0_GPIO_OSPEED_LOW | STM32L0_GPIO_OTYPE_PUSHPULL | STM32L0_GPIO_MODE_OUTPUT)); //MIGUEL* stm32l0_gpio_pin_configure(STM32L0_GPIO_PIN_PC1, (STM32L0_GPIO_PARK_NONE | STM32L0_GPIO_PUPD_NONE | STM32L0_GPIO_OSPEED_LOW | STM32L0_GPIO_OTYPE_PUSHPULL | STM32L0_GPIO_MODE_OUTPUT)); return RH_RF95::init(); } void RH_ABZ::selectSlave() { //MIGUEL stm32l0_gpio_pin_write(STM32L0_GPIO_PIN_PA4, 0); } void RH_ABZ::deselectSlave() { //MIGUEL stm32l0_gpio_pin_write(STM32L0_GPIO_PIN_PA4, 1); } bool RH_ABZ::modeWillChange(RHMode mode) { if (mode == RHModeTx) { // Tell the antenna switch to connect to one of thetransmoitter output pins //MIGUEL - medir sinal do RF.. stm32l0_gpio_pin_write(STM32L0_GPIO_PIN_PA15, 0); // RX stm32l0_gpio_pin_write(STM32L0_GPIO_PIN_PC2, _useRFO ? 1 : 0); // RFO stm32l0_gpio_pin_write(STM32L0_GPIO_PIN_PC1, _useRFO ? 0 : 1); // BOOST } else { // Enabling the RX from the antenna switch improves reception RSSI by about 5 //MIGUEL stm32l0_gpio_pin_write(STM32L0_GPIO_PIN_PA15, 1); // RX stm32l0_gpio_pin_write(STM32L0_GPIO_PIN_PC2, 0); // RFO stm32l0_gpio_pin_write(STM32L0_GPIO_PIN_PC1, 0); // BOOST } return true; } #endif

ALTERE VARIANT.CPP PARA


/* * Copyright (c) 2017-2018 Thomas Roell. All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal with the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimers. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimers in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of Thomas Roell, nor the names of its contributors * may be used to endorse or promote products derived from this Software * without specific prior written permission. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * WITH THE SOFTWARE. */ #include "Arduino.h" #include "wiring_private.h" #define PWM_INSTANCE_TIM2 0 #define PWM_INSTANCE_TIM3 1 /* * Pins descriptions */ extern const PinDescription g_APinDescription[PINS_COUNT] = { // 0..13 - Digital pins { GPIOA, STM32L0_GPIO_PIN_MASK(STM32L0_GPIO_PIN_PA3), STM32L0_GPIO_PIN_PA3, 0, PWM_INSTANCE_NONE, PWM_CHANNEL_NONE, ADC_CHANNEL_NONE }, { GPIOA, STM32L0_GPIO_PIN_MASK(STM32L0_GPIO_PIN_PA2), STM32L0_GPIO_PIN_PA2, 0, PWM_INSTANCE_NONE, PWM_CHANNEL_NONE, ADC_CHANNEL_NONE }, { GPIOA, STM32L0_GPIO_PIN_MASK(STM32L0_GPIO_PIN_PA10), STM32L0_GPIO_PIN_PA10, (PIN_ATTR_EXTI), PWM_INSTANCE_NONE, PWM_CHANNEL_NONE, ADC_CHANNEL_NONE }, { GPIOB, STM32L0_GPIO_PIN_MASK(STM32L0_GPIO_PIN_PB3), STM32L0_GPIO_PIN_PB3_TIM2_CH2, (PIN_ATTR_EXTI), PWM_INSTANCE_TIM2, PWM_CHANNEL_2, ADC_CHANNEL_NONE }, { GPIOB, STM32L0_GPIO_PIN_MASK(STM32L0_GPIO_PIN_PB5), STM32L0_GPIO_PIN_PB5, (PIN_ATTR_EXTI), PWM_INSTANCE_NONE, PWM_CHANNEL_NONE, ADC_CHANNEL_NONE }, { GPIOB, STM32L0_GPIO_PIN_MASK(STM32L0_GPIO_PIN_PB4), STM32L0_GPIO_PIN_PB4_TIM3_CH1, 0, PWM_INSTANCE_TIM3, PWM_CHANNEL_1, ADC_CHANNEL_NONE }, { GPIOB, STM32L0_GPIO_PIN_MASK(STM32L0_GPIO_PIN_PB10), STM32L0_GPIO_PIN_PB10_TIM2_CH3, 0, PWM_INSTANCE_TIM2, PWM_CHANNEL_3, ADC_CHANNEL_NONE }, { GPIOA, STM32L0_GPIO_PIN_MASK(STM32L0_GPIO_PIN_PA8), STM32L0_GPIO_PIN_PA8, (PIN_ATTR_EXTI), PWM_INSTANCE_NONE, PWM_CHANNEL_NONE, ADC_CHANNEL_NONE }, { GPIOA, STM32L0_GPIO_PIN_MASK(STM32L0_GPIO_PIN_PA9), STM32L0_GPIO_PIN_PA9, (PIN_ATTR_EXTI), PWM_INSTANCE_NONE, PWM_CHANNEL_NONE, ADC_CHANNEL_NONE }, { GPIOC, STM32L0_GPIO_PIN_MASK(STM32L0_GPIO_PIN_PC7), STM32L0_GPIO_PIN_PC7_TIM3_CH2, (PIN_ATTR_EXTI), PWM_INSTANCE_TIM3, PWM_CHANNEL_2, ADC_CHANNEL_NONE }, { GPIOB, STM32L0_GPIO_PIN_MASK(STM32L0_GPIO_PIN_PB6), STM32L0_GPIO_PIN_PB6, (PIN_ATTR_EXTI), PWM_INSTANCE_NONE, PWM_CHANNEL_NONE, ADC_CHANNEL_NONE }, { GPIOA, STM32L0_GPIO_PIN_MASK(STM32L0_GPIO_PIN_PA7), STM32L0_GPIO_PIN_PA7, 0, PWM_INSTANCE_NONE, PWM_CHANNEL_NONE, ADC_CHANNEL_NONE }, { GPIOA, STM32L0_GPIO_PIN_MASK(STM32L0_GPIO_PIN_PA6), STM32L0_GPIO_PIN_PA6, 0, PWM_INSTANCE_NONE, PWM_CHANNEL_NONE, ADC_CHANNEL_NONE }, { GPIOA, STM32L0_GPIO_PIN_MASK(STM32L0_GPIO_PIN_PA5), STM32L0_GPIO_PIN_PA5, 0, PWM_INSTANCE_NONE, PWM_CHANNEL_NONE, ADC_CHANNEL_NONE }, // 14..15 - I2C pins (SDA,SCL) { GPIOB, STM32L0_GPIO_PIN_MASK(STM32L0_GPIO_PIN_PB9), STM32L0_GPIO_PIN_PB9, 0, PWM_INSTANCE_NONE, PWM_CHANNEL_NONE, ADC_CHANNEL_NONE }, { GPIOB, STM32L0_GPIO_PIN_MASK(STM32L0_GPIO_PIN_PB8), STM32L0_GPIO_PIN_PB8, 0, PWM_INSTANCE_NONE, PWM_CHANNEL_NONE, ADC_CHANNEL_NONE }, // 16..21 - Analog pins { GPIOA, STM32L0_GPIO_PIN_MASK(STM32L0_GPIO_PIN_PA0), STM32L0_GPIO_PIN_PA0, 0, PWM_INSTANCE_NONE, PWM_CHANNEL_NONE, ADC_CHANNEL_0 }, { GPIOA, STM32L0_GPIO_PIN_MASK(STM32L0_GPIO_PIN_PA1), STM32L0_GPIO_PIN_PA1, 0, PWM_INSTANCE_NONE, PWM_CHANNEL_NONE, ADC_CHANNEL_1 }, { GPIOA, STM32L0_GPIO_PIN_MASK(STM32L0_GPIO_PIN_PA4), STM32L0_GPIO_PIN_PA4, (PIN_ATTR_EXTI), PWM_INSTANCE_NONE, PWM_CHANNEL_NONE, ADC_CHANNEL_4 }, { GPIOB, STM32L0_GPIO_PIN_MASK(STM32L0_GPIO_PIN_PB0), STM32L0_GPIO_PIN_PB0, (PIN_ATTR_EXTI), PWM_INSTANCE_NONE, PWM_CHANNEL_NONE, ADC_CHANNEL_8 }, { GPIOC, STM32L0_GPIO_PIN_MASK(STM32L0_GPIO_PIN_PC1), STM32L0_GPIO_PIN_PC1, (PIN_ATTR_EXTI), PWM_INSTANCE_NONE, PWM_CHANNEL_NONE, ADC_CHANNEL_11 }, { GPIOC, STM32L0_GPIO_PIN_MASK(STM32L0_GPIO_PIN_PC0), STM32L0_GPIO_PIN_PC0, 0, PWM_INSTANCE_NONE, PWM_CHANNEL_NONE, ADC_CHANNEL_10 }, // 22 - Button { GPIOC, STM32L0_GPIO_PIN_MASK(STM32L0_GPIO_PIN_PC13), STM32L0_GPIO_PIN_PC13, (PIN_ATTR_EXTI | PIN_ATTR_WKUP1), PWM_INSTANCE_NONE, PWM_CHANNEL_NONE, ADC_CHANNEL_NONE }, //MIGUEL - DIO0 - INTERRUPT { GPIOA, STM32L0_GPIO_PIN_MASK(STM32L0_GPIO_PIN_PA12), STM32L0_GPIO_PIN_PA12, 0, PWM_INSTANCE_NONE, PWM_CHANNEL_NONE, ADC_CHANNEL_NONE },     //TCXO { GPIOB, STM32L0_GPIO_PIN_MASK(STM32L0_GPIO_PIN_PB1), STM32L0_GPIO_PIN_PB1, 0, PWM_INSTANCE_NONE, PWM_CHANNEL_NONE, ADC_CHANNEL_NONE }, }; extern const unsigned int g_PWMInstances[PWM_INSTANCE_COUNT] = { STM32L0_TIMER_INSTANCE_TIM2, STM32L0_TIMER_INSTANCE_TIM3, }; static uint8_t stm32l0_usart2_rx_fifo[32]; extern const stm32l0_uart_params_t g_SerialParams = { STM32L0_UART_INSTANCE_USART2, STM32L0_UART_IRQ_PRIORITY, STM32L0_DMA_CHANNEL_DMA1_CH6_USART2_RX, STM32L0_DMA_CHANNEL_DMA1_CH4_USART2_TX, &stm32l0_usart2_rx_fifo[0], sizeof(stm32l0_usart2_rx_fifo), { STM32L0_GPIO_PIN_PA3_USART2_RX, STM32L0_GPIO_PIN_PA2_USART2_TX, STM32L0_GPIO_PIN_NONE, STM32L0_GPIO_PIN_NONE, }, }; static uint8_t stm32l0_usart1_rx_fifo[32]; extern const stm32l0_uart_params_t g_Serial1Params = { STM32L0_UART_INSTANCE_USART1, STM32L0_UART_IRQ_PRIORITY, STM32L0_DMA_CHANNEL_DMA1_CH5_USART1_RX, STM32L0_DMA_CHANNEL_NONE, &stm32l0_usart1_rx_fifo[0], sizeof(stm32l0_usart1_rx_fifo), { STM32L0_GPIO_PIN_PA10_USART1_RX, STM32L0_GPIO_PIN_PA9_USART1_TX, STM32L0_GPIO_PIN_NONE, STM32L0_GPIO_PIN_NONE, }, }; extern const stm32l0_spi_params_t g_SPIParams = { STM32L0_SPI_INSTANCE_SPI1, STM32L0_SPI_IRQ_PRIORITY, STM32L0_DMA_CHANNEL_DMA1_CH2_SPI1_RX, STM32L0_DMA_CHANNEL_DMA1_CH3_SPI1_TX, { STM32L0_GPIO_PIN_PA7_SPI1_MOSI, STM32L0_GPIO_PIN_PA6_SPI1_MISO, STM32L0_GPIO_PIN_PA5_SPI1_SCK, STM32L0_GPIO_PIN_NONE, }, }; extern const stm32l0_i2c_params_t g_WireParams = { STM32L0_I2C_INSTANCE_I2C1, STM32L0_I2C_IRQ_PRIORITY, STM32L0_DMA_CHANNEL_DMA1_CH7_I2C1_RX, STM32L0_DMA_CHANNEL_NONE, { STM32L0_GPIO_PIN_PB8_I2C1_SCL, STM32L0_GPIO_PIN_PB9_I2C1_SDA, }, }; void initVariant() { }

GRAVANDO (ST-LINK V2)

PRESSIONE O RESET ASSIM QUE O ARDUINO ACIONAR O OPENOCD

RESULTADOS (UART PA2/PA3 (USART))

Node 4

Node 2


Bridge

VÍDEO


MONTAGEM


COMANDOS AT APÓS RESET DA BRIDGE 



LIGAÇÕES ENTRE LOM204A E U-blox NINA W106 (VER VARIANT.CPP)

LOM204A                        U-BLOX
PA9                                   RX
PA10                                 TX
GND                                 GND

VÍDEO


MONTAGEM 


ALGUNS TESTES EXTRAS

Agora você sabe que os nós (a alguns centímetros de distância) em sua mesa são capazes de se comunicar.

Então, vamos espaçar um nó até que esteja fora do intervalo de malha (até que o log serial do servidor pare de relatar as mensagens do nó) neste ponto, adicione um novo nó 'no meio' (vamos chamá-lo de 'o nó no meio') e depois de um pequeno atraso... o nó original é automaticamente reconectado.

Se você achar isso um pouco impraticável (quero dizer, mover os nós a algumas centenas de metros de distância), aqui estão algumas dicas:

abaixe a potência dos nós (definindo a potência para 2 dBm, por exemplo) para que algumas paredes dentro de sua casa sejam suficientes (bem... algumas paredes)
use a função 'test network' da biblioteca radiohead, no arquivo RHRouter.h perto da linha 33, descomente um dos quatro #defines RH_TEST_NETWORK 1-4, cada um define simula uma rede conforme mostrado na imagem a seguir (na qual alguns nós são mutuamente invisíveis), simples assim... mas lembre-se de comentar a definição quando seus testes terminarem.

NOTA Nunca é uma boa ideia manter os nós muito próximos uns dos outros.

DICAS

A biblioteca mesh radiohead não garante a entrega da mensagem ao destino final (o ACK recebido após cada transmissão significa apenas que a mensagem viajou até o primeiro salto). E em muitos casos isso é o suficiente.
Se você deseja uma prova de que a mensagem foi entregue, pode adicionar uma resposta no código da bridge (e um recebimento da resposta no código do nó). Você pode encontrar esta pequena adição nos últimos exemplos de código.

DÚVIDAS

FORUMS RADIOHEAD

REFERÊNCIAS
 

Sobre a SMARTCORE

A SmartCore fornece módulos para comunicação wireless, biometria, conectividade, rastreamento e automação.
Nosso portfólio inclui modem 2G/3G/4G/NB-IoT/Cat.M, satelital, módulos WiFi, Bluetooth, GNSS / GPS, Sigfox, LoRa, leitor de cartão, leitor QR code, mecanismo de impressão, mini-board PC, antena, pigtail, LCD, bateria, repetidor GPS e sensores.

Mais detalhes em www.smartcore.com.br 

Nenhum comentário:

Postar um comentário