EByte RF E70 CC1310: andiamo ad esplorare la libreria (esp32, esp8266, STM32, Arduino, Raspberry Pi Pico)


Ebyte LoRa E70 CC1310: esplorazione della libreria (esp32, STM32, Arduino, Raspberry Pi Pico)
Ebyte RF E70 CC1310: esplorazione della libreria (esp32, STM32, Arduino, Raspberry Pi Pico)

Il mondo della comunicazione wireless è stato rivoluzionato dall’avvento delle tecnologie RF a lunga distanza, che offrono una combinazione di capacità a lungo raggio e basso consumo energetico. Il modulo EByte RF E70 si distingue come un attore prominente tra i vari moduli emergenti. Questo articolo esplora le caratteristiche, le applicazioni e le modalità operative dell’EByte E70, fornendo approfondimenti sulle sue capacità e sui suoi potenziali utilizzi.

L’E70 è basato sul dispositivo della serie CC1310. Questo dispositivo non è solo un microcontrollore (MCU); è un MCU wireless completamente integrato progettato specificamente per applicazioni wireless a basso consumo e lungo raggio. Il CC1310 combina un potente processore ARM Cortex-M3 con una radio sub-1 GHz altamente efficiente, rendendolo una soluzione ideale per una vasta gamma di applicazioni, dai contatori intelligenti all’automazione industriale e al monitoraggio ambientale.

Introduzione all’EByte RF E70

L’EByte E70 è un modulo RF progettato per la comunicazione wireless a lungo raggio. Opera nelle bande di frequenza sub-gigahertz, rendendolo ideale per varie applicazioni che richiedono comunicazioni a lungo raggio e basso consumo energetico. La sua versatilità ed efficienza lo hanno reso una scelta popolare nelle applicazioni IoT (Internet of Things), nei progetti di città intelligenti e nell’automazione industriale.

Caratteristiche principali dell’EByte E70

  1. Comunicazione a lungo raggio: Il modulo E70 è noto per il suo raggio d’azione eccezionale, in grado di trasmettere dati su diversi chilometri, a seconda delle condizioni ambientali.
  2. Basso consumo energetico: È ottimizzato per un basso consumo energetico, prolungando la durata della batteria dei dispositivi, cruciale per le applicazioni IoT.
  3. Modalità operative multiple: L’E70 supporta diverse modalità come la modalità trasparente, modalità fissa, modalità continua e modalità sub-pacchetto, offrendo flessibilità in diversi casi d’uso.
  4. Parametri configurabili: Gli utenti possono configurare parametri come frequenza, potenza di uscita e velocità di trasmissione dati, rendendoli adattabili a varie esigenze di comunicazione.
  5. Correzione d’errore in avanti (FEC): La FEC è un metodo per il controllo degli errori nella trasmissione dei dati. Aggiunge ridondanza alle informazioni trasmesse utilizzando un algoritmo predefinito. Questa ridondanza consente al ricevitore di rilevare e correggere gli errori senza la necessità di una ritrasmissione.

Specifiche del dispositivo

  • Distanza di comunicazione testata fino a 1.5/6 km
  • Potenza massima di trasmissione di 1W, regolabile su più livelli tramite software
  • Supporto di velocità di trasmissione via aria da 2,5 kbps a 168 kbps
  • Basso consumo energetico per applicazioni alimentate a batteria
  • Può raggiungere una trasmissione continua di frame a 115200bps con lunghezza di pacchetto illimitata
  • Supporto di alimentazione a 2,6~5,5 V, con più di 5V per garantire le migliori prestazioni
  • Progettazione secondo lo standard industriale, supporto per temperature di lavoro da -40 a 85 °C per lunghi periodi

Installazione della libreria

Puoi trovare la libreria su GitHub.

Per semplicità, l’ho anche aggiunta al gestore delle librerie di Arduino.

Varianti RF E70

L’E70 è disponibile in vari formati, con design e specifiche che cambiano.

Dimensioni del Modulo EByte LoRa E70 xxxTxxS

E70-433T30S:

  • Tensione di livello logico: supporto 3.3v e 5v
  • Potenza di trasmissione: 30dBm (maggiore potenza, capace di trasmissione a lunga distanza)
  • Sensibilità di ricezione: -107 a -109 dBm
  • Distanza di riferimento: 6000m

Dimensioni del Modulo EByte LoRa E70 xxxTxxS

E70-433T14S:

  • Tensione di livello logico: solo 3.3v
  • Potenza di trasmissione: 14dBm (potenza inferiore rispetto al T30S)
  • Sensibilità di ricezione: -109 a -111 dBm per T14S e -108 dBm per T14S2 (leggermente migliore per il T14S)
  • Distanza di riferimento: 1500m

Dimensioni del Modulo EByte LoRa E70 xxxT1xxS2

E70-433T14S2:

  • Tensione di livello logico: solo 3.3v
  • Aggiornamento della versione S.
  • Sensibilità di ricezione: -109 a -111 dBm per T14S e -108 dBm per T14S2 (leggermente migliore per il T14S)
  • I fattori di forma sono più semplici da gestire.
Dimensioni del Modulo EByte LoRa e70 xxxMTxxS

E70-433MT14S:

  • Tensione di livello logico: solo 3.3v
  • Potenza di trasmissione: 14dBm (come T14S e T14S2)
  • Sensibilità di ricezione: -108 dBm (come T14S2)
  • Distanza di riferimento: 1500m (come T14S e T14S2)

Parametri RF

Parametri RFUnitàModelloOsservazioni
E70-433T30SE70-433T14SE70-433T14S2E70-433MT14S
Potenza di trasmissionedBm30141414
Sensibilità di ricezionedBm-107~-109-109~-111-108-108La velocità dell’aria è 2.5kbps
Distanza di riferimentom6000m1500m1500m1500mLa probabilità di danneggiamento è minore quando usato a breve distanza
Antenna 5dBi, altezza 2.5 metri, velocità dell’aria 2.5kbps
Banda di frequenza operativaMHz425~450.5La frequenza predefinita di fabbrica è 433MHz e supporta la banda ISM
Velocità di trasmissionebps2.5k~168kControllo programmabile dall’utente
Potenza di bloccodBm10Vedi dettagli nei modi di trasferimento
Lunghezza della trasmissione/Specificata in modalità di trasmissioneVedi dettagli nei modi di trasferimento

Parametro elettrico

Parametri hardware

Pinout E70 xxxT14S2

Per il mio test, utilizzerò una versione E70 S2 perché ha un fattore di forma comodo con un’antenna SMA integrata.

Note sulle connessioni

Come puoi vedere, ho anche collegato i pin M0, M1 e M2, ma non sono necessari; puoi selezionare una modalità operativa impostando i valori su questi pin.

Modalità (0-7)M2M1M0Descrizione modalitàOsservazione
0 Modalità RSSI000Il modulo emette il valore RSSI ogni 100ms tramite UART.La velocità di trasmissione aerea può essere regolata automaticamente in base alla velocità di baud. La velocità di baud deve essere la stessa sia sul ricevitore che sul trasmettitore. È applicabile per la trasmissione continua di dati ad alta velocità.
1 Modalità continua001UART aperta. Wireless chiuso e disponibile la trasmissione trasparente a pacchetto.UART aperta. Wireless chiuso e disponibile la trasmissione trasparente continua.
2 Modalità a pacchetto010UART aperta. Wireless chiuso e parametri configurabili.La velocità dell’aria e la velocità di baud possono essere regolate separatamente. È applicabile per la trasmissione di pacchetti di dati.
3 Modalità configurazione011La velocità di baud è fissata a 9600 8N1.UART aperta. Wireless chiuso e disponibile la trasmissione trasparente a pacchetto.
4 Modalità WOR100La trasmissione non è disponibile in questa modalità. Può essere risvegliato da un trasmettitore in modalità 4 per ottenere una ricezione a basso consumo energetico.La ricezione non è disponibile in questa modalità. Un codice di preambolo sarà aggiunto proattivamente prima della trasmissione per risvegliare il ricevitore in modalità 6.
5 Modalità configurazione (Come modalità 3)101
6 Modalità risparmio energetico110Qualsiasi bordo di discesa di M2, M1 o M0 può risvegliarlo.UART chiuso. Il wireless funziona in modalità di risparmio energetico WOR. Sono configurabili più gradi di tempo.
7 Modalità sleep111Qualsiasi bordo di discesa di M2, M1 o M0 può risvegliarlo.UART chiuso, disponibile la trasmissione wireless, e la modalità sleep è attiva.

Per questo esperimento, devi impostare i dispositivi in modalità a pacchetto.

  • M0: BASSO
  • M1: ALTO
  • M2: BASSO

Costruttore

Ho creato una serie di costruttori perché possiamo avere più opzioni e situazioni da gestire.

		RF_E70(byte txE70pin, byte rxE70pin, UART_BPS_RATE bpsRate = UART_BPS_RATE_9600);
		RF_E70(byte txE70pin, byte rxE70pin, byte auxPin, UART_BPS_RATE bpsRate = UART_BPS_RATE_9600);
		RF_E70(byte txE70pin, byte rxE70pin, byte auxPin, byte m0Pin, byte m1Pin, byte m2Pin, UART_BPS_RATE bpsRate = UART_BPS_RATE_9600);

La prima serie di costruttori è stata creata per delegare la gestione dei pin Serial e altri alla libreria.

  • txE70pin e rxE70pin sono i pin da collegare all’UART. Sono obbligatori.
  • auxPin è un pin che verifica lo stato di funzionamento, trasmissione e ricezione (spiegheremo meglio in seguito). Questo pin non è obbligatorio; se non lo imposti, applico un ritardo per permettere l’operazione di completarsi (con latenza, se hai problemi, come un dispositivo che si blocca, devi mettere una resistenza pull-up da 4.7k o, meglio ancora, collegarla al dispositivo).
  • m0pin, m1Pin e m2Pin sono i pin per cambiare la modalità operativa (vedi tabella sopra); credo che questi pin in “produzione” verranno collegati direttamente a HIGH o LOW. Tuttavia, per il test, sono utili per la libreria per la gestione.
  • bpsRate è il baud rate di SoftwareSerial, solitamente 9600 (l’unico baud rate in modalità programmazione/sleep).

Ecco un semplice esempio:

#include "RF_E70.h"

RF_E70 e70ttl(2, 3);  // e70 TX e70 RX
// RF_E70 e70ttl(2, 3, 5, 6, 7);  // e70 TX e70 RX

Possiamo usare un SoftwareSerial direttamente con un altro costruttore:

		RF_E70(HardwareSerial* serial, UART_BPS_RATE bpsRate = UART_BPS_RATE_9600);
		RF_E70(HardwareSerial* serial, byte auxPin, UART_BPS_RATE bpsRate = UART_BPS_RATE_9600);
		RF_E70(HardwareSerial* serial, byte auxPin, byte m0Pin, byte m1Pin, byte m2Pin, UART_BPS_RATE bpsRate = UART_BPS_RATE_9600);

L’esempio precedente con questo costruttore può essere realizzato così:

#include <SoftwareSerial.h>
#include "RF_E70.h"

SoftwareSerial mySerial(2, 3); // e70 TX e70 RX
RF_E70 e70ttl(&mySerial);
// RF_E70 e70ttl(&mySerial, 5, 6, 7, 8);

L’ultima serie di costruttori è per consentire l’utilizzo di un HardwareSerial invece di un SoftwareSerial.

		RF_E70(SoftwareSerial* serial, UART_BPS_RATE bpsRate = UART_BPS_RATE_9600);
		RF_E70(SoftwareSerial* serial, byte auxPin, UART_BPS_RATE bpsRate = UART_BPS_RATE_9600);
		RF_E70(SoftwareSerial* serial, byte auxPin, byte m0Pin, byte m1Pin, byte m2Pin, UART_BPS_RATE bpsRate = UART_BPS_RATE_9600);

Per esp32, ci sono tre costruttori aggiuntivi che consentono la gestione dei pin per HardWare serial:

			RF_E70(byte txE70pin, byte rxE70pin, HardwareSerial* serial, UART_BPS_RATE bpsRate = UART_BPS_RATE_9600, uint32_t serialConfig = SERIAL_8N1);
			RF_E70(byte txE70pin, byte rxE70pin, HardwareSerial* serial, byte auxPin, UART_BPS_RATE bpsRate = UART_BPS_RATE_9600, uint32_t serialConfig = SERIAL_8N1);
			RF_E70(byte txE70pin, byte rxE70pin, HardwareSerial* serial, byte auxPin, byte m0Pin, byte m1Pin, byte m2Pin, UART_BPS_RATE bpsRate = UART_BPS_RATE_9600, uint32_t serialConfig = SERIAL_8N1);

Inizializzazione

Il comando begin() viene utilizzato per avviare Serial e impostare i pin in modalità input e output.

void begin();

Ecco come viene eseguito:

	// Startup all pins and UART
	e70ttl.begin();

Configurazione e metodi per ottenere informazioni

Esistono molti metodi per gestire la configurazione e ottenere informazioni sul dispositivo.

		ResponseStructContainer getConfiguration();
		ResponseStatus setConfiguration(Configuration configuration, PROGRAM_COMMAND saveType = WRITE_CFG_PWR_DWN_LOSE);

		ResponseStructContainer getModuleInformation();
        void printParameters(struct Configuration configuration);
        ResponseStatus resetModule();

Contenitori di risposta

Per semplificare la gestione delle risposte, ho creato una serie di contenitori che sono molto utili per gestire gli errori e restituire dati generici.

ResponseStatus

ResponseStatus è un contenitore di stato e ha due semplici punti di accesso. Con questo è possibile ottenere il codice di stato e la descrizione del codice di stato.

	Serial.println(c.getResponseDescription()); // Description of code
	Serial.println(c.code); // 1 if Success

Il codice è:

  E70_SUCCESS = 1,
  ERR_E70_UNKNOWN,	/* something shouldn't happened */
  ERR_E70_NOT_SUPPORT,
  ERR_E70_NOT_IMPLEMENT,
  ERR_E70_NOT_INITIAL,
  ERR_E70_INVALID_PARAM,
  ERR_E70_DATA_SIZE_NOT_MATCH,
  ERR_E70_BUF_TOO_SMALL,
  ERR_E70_TIMEOUT,
  ERR_E70_HARDWARE,
  ERR_E70_HEAD_NOT_RECOGNIZED,
  ERR_E70_NO_RESPONSE_FROM_DEVICE,
  ERR_E70_WRONG_UART_CONFIG,
  ERR_E70_WRONG_FORMAT,
  ERR_E70_PACKET_TOO_BIG,
  ERR_E70_NO_STREAM_FOUND

ResponseContainer

Questo contenitore è stato creato per gestire le risposte sotto forma di stringhe e ha due punti di accesso: data, che contiene la stringa restituita dal messaggio, e status, che è un’istanza di ResponseStatus.

		ResponseContainer rs = e70ttl.receiveMessage();
		String message = rs.data;

		Serial.println(rs.status.getResponseDescription());
		Serial.println(message);

Ma questo comando legge tutti i dati nel buffer. Se ricevi tre messaggi, li leggerai tutti in una volta. Una soluzione semplice è usare un carattere di fine da inviare alla fine del messaggio, per impostazione predefinita uso \0 (carattere nullo).

		ResponseContainer rs = e70ttl.receiveMessageUntil();
                // You can specify a custom delimiter also
		// ResponseContainer rs = e70ttl.receiveMessageUntil('|');

		String message = rs.data;

		Serial.println(rs.status.getResponseDescription());
		Serial.println(message);

ResponseStructContainer

ResponseStructContainer è il contenitore più “complesso” che utilizzo per gestire le strutture. Ha gli stessi punti di accesso di ResponseContainer, ma data è un puntatore void per gestire strutture complesse.

	ResponseStructContainer c;
	c = e70ttl.getConfiguration();
	// It's important get configuration pointer before all other operation
	Configuration configuration = *(Configuration*) c.data;
	Serial.println(c.status.getResponseDescription());
	Serial.println(c.status.code);
    c.close();

Ogni volta che usi un ResponseStructContainer, devi chiuderlo con close().

getConfiguration e setConfiguration

Il primo metodo è getConfiguration, che puoi utilizzare per recuperare tutti i dati memorizzati sul dispositivo.

		ResponseStructContainer getConfiguration();

Qui un esempio di utilizzo:

	ResponseStructContainer c;
	c = e70ttl.getConfiguration();
	// It's important get configuration pointer before all other operation
	Configuration configuration = *(Configuration*) c.data;
	Serial.println(c.status.getResponseDescription());
	Serial.println(c.status.code);
    Serial.println(configuration.SPED.getUARTBaudRate());
    c.close();

La struttura della configurazione contiene tutti i dati relativi alle impostazioni, e ho aggiunto una serie di funzioni per ottenere tutte le descrizioni di un singolo dato.

	configuration.ADDL = 0x00;  // First part of address
	configuration.ADDH = 0x00; // Second part


	configuration.SPED.uartBaudRate = UART_BPS_9600; // Serial baud rate
	configuration.SPED.airDataRate = AIR_DATA_RATE_000_025; // Air baud rate
	configuration.SPED.uartParity = MODE_00_8N1; // Parity bit

	configuration.CHAN.CHAN = 4;
	configuration.CHAN.subPacketSetting = SPS_0064_010;

	configuration.OPTION.fec = FEC_1_ON; // Packet size
	configuration.OPTION.fixedTransmission = FT_TRANSPARENT_TRANSMISSION; // Need to send special command
	configuration.OPTION.transmissionPower = POWER_30; // Device power
	configuration.OPTION.ioDriveMode = IO_D_MODE_PUSH_PULLS_PULL_UPS; // IO Drive
	configuration.OPTION.wirelessWakeupTime = WAKE_UP_1000; // Wake up time

Hai funzioni equivalenti per tutti gli attributi per ottenere tutte le descrizioni:

void printParameters(struct Configuration configuration) {
	Serial.println("----------------------------------------");

	Serial.print(F("Configuration packet: "));
    byte* byteArray = (byte*)&configuration;  // Cast the address of config to a byte pointer
    for (int i = 0; i < sizeof(Configuration); i++) {
        if (byteArray[i] < 16) {
            Serial.print('0');  // Print a leading zero for single-digit hex values
        }
        Serial.print(byteArray[i], HEX);  // Print each byte of the struct in hexadecimal
        Serial.print(" ");
    }
    Serial.println(F(" "));

	Serial.print(F("HEAD : "));  Serial.print(configuration.COMMAND, HEX);Serial.print(" ");
	Serial.println(F(" "));
	Serial.print(F("AddH : "));  Serial.println(configuration.ADDH, HEX);
	Serial.print(F("AddL : "));  Serial.println(configuration.ADDL, HEX);
	Serial.println(F(" "));
	Serial.print(F("Chan : "));  Serial.print(configuration.CHAN.CHAN, DEC); Serial.print(" -> "); Serial.println(configuration.CHAN.getChannelDescription());
	Serial.print(F("Packet size : "));  Serial.print(configuration.CHAN.subPacketSetting, BIN); Serial.print(" -> "); Serial.println(configuration.CHAN.getSubPacketSetting());
	Serial.println(F(" "));
	Serial.print(F("SpeedParityBit     : "));  Serial.print(configuration.SPED.uartParity, BIN);Serial.print(" -> "); Serial.println(configuration.SPED.getUARTParityDescription());
	Serial.print(F("SpeedUARTDatte     : "));  Serial.print(configuration.SPED.uartBaudRate, BIN);Serial.print(" -> "); Serial.println(configuration.SPED.getUARTBaudRateDescription());
	Serial.print(F("SpeedAirDataRate   : "));  Serial.print(configuration.SPED.airDataRate, BIN);Serial.print(" -> "); Serial.println(configuration.SPED.getAirDataRateDescription());
	Serial.println(F(" "));
	Serial.print(F("OptionFECPacketSett: "));  Serial.print(configuration.OPTION.fec, BIN);Serial.print(" -> "); Serial.println(configuration.OPTION.getFECDescription());
	Serial.print(F("OptionTranPower    : "));  Serial.print(configuration.OPTION.transmissionPower, BIN);Serial.print(" -> "); Serial.println(configuration.OPTION.getTransmissionPowerDescription());
	Serial.print(F("OptionIODrive: "));  Serial.print(configuration.OPTION.ioDriveMode, BIN);Serial.print(" -> "); Serial.println(configuration.OPTION.getIODroveModeDescription());
	Serial.print(F("OptionFixedTransmission: "));  Serial.print(configuration.OPTION.fixedTransmission, BIN);Serial.print(" -> "); Serial.println(configuration.OPTION.getFixedTransmissionDescription());
	Serial.print(F("OptionWirelessWakeUPTime: "));  Serial.print(configuration.OPTION.wirelessWakeupTime, BIN);Serial.print(" -> "); Serial.println(configuration.OPTION.getWirelessWakeUPTimeDescription());


	Serial.println("----------------------------------------");
}

Allo stesso modo, setConfiguration richiede una struttura di configurazione, quindi il modo migliore per gestire la configurazione è recuperare quella corrente, applicare solo le modifiche necessarie e impostarla nuovamente.

		ResponseStatus setConfiguration(Configuration configuration, PROGRAM_COMMAND saveType = WRITE_CFG_PWR_DWN_LOSE);

configuration è la struttura mostrata in precedenza, saveType ti consente di scegliere se il cambiamento diventa permanente o solo per la sessione corrente.

	ResponseStructContainer c;
	c = e70ttl.getConfiguration();
	// It's important get configuration pointer before all other operation
	Configuration configuration = *(Configuration*) c.data;
	Serial.println(c.status.getResponseDescription());
	Serial.println(c.status.code);

	printParameters(configuration);
	configuration.ADDL = 0x00;  // First part of address
	configuration.ADDH = 0x00; // Second part


	configuration.SPED.uartBaudRate = UART_BPS_9600; // Serial baud rate
	configuration.SPED.airDataRate = AIR_DATA_RATE_000_025; // Air baud rate
	configuration.SPED.uartParity = MODE_00_8N1; // Parity bit

	configuration.CHAN.CHAN = 4;
	configuration.CHAN.subPacketSetting = SPS_0064_010;

	configuration.OPTION.fec = FEC_1_ON; // Packet size
	configuration.OPTION.fixedTransmission = FT_TRANSPARENT_TRANSMISSION; // Need to send special command
	configuration.OPTION.transmissionPower = POWER_30; // Device power
	configuration.OPTION.ioDriveMode = IO_D_MODE_PUSH_PULLS_PULL_UPS; // IO Drive
	configuration.OPTION.wirelessWakeupTime = WAKE_UP_1000; // Wake up time

	// Set configuration changed and set to not hold the configuration
	ResponseStatus rs = e70ttl.setConfiguration(configuration, WRITE_CFG_PWR_DWN_LOSE);
	Serial.println(rs.getResponseDescription());
	Serial.println(rs.code);
	printParameters(configuration);
    c.close()

Opzioni di configurazione di base

NomeDescrizioneIndirizzo
ADDHByte dell’indirizzo alto del modulo (di default 00H)00H
ADDLByte dell’indirizzo basso del modulo (di default 00H)01H
SPEDInformazioni sulla velocità dei dati, bit di parità e velocità dell’aria02H
OPTIONTipo di trasmissione e velocità03H
CHANCanale di comunicazione (410M + CHAN*1M), di default 17H (433 MHz),valido solo per il dispositivo a 433 MHz04H

Dettaglio SPED

Bit di parità UART: La modalità UART può essere diversa tra le parti comunicanti

Bit di parità UARTValore costante
8N1 (default)MODE_00_8N1
8O1MODE_01_8O1
8E1MODE_10_8E1
8N1 (equivalente a 00)MODE_11_8N1

Velocità baud UART: La velocità baud UART può essere diversa tra le parti comunicanti (ma non raccomandato). La velocità baud UART non ha nulla a che fare con i parametri di trasmissione wireless e non influenzerà le caratteristiche di trasmissione/ricezione wireless.

Velocità baud UART TTL (bps)Valore costante
1200UART_BPS_1200
2400UART_BPS_2400
4800UART_BPS_4800
9600 (default)UART_BPS_9600
19200UART_BPS_19200
38400UART_BPS_38400
57600UART_BPS_57600
115200UART_BPS_115200

Velocità dei dati dell’aria: Più bassa è la velocità dei dati dell’aria, maggiore sarà la distanza di trasmissione, migliore la prestazione anti-interferenza, ma maggiore sarà il tempo di trasmissione. La velocità dei dati dell’aria deve essere costante per entrambe le parti di comunicazione.

Velocità dei dati dell’aria (bps)Valore costante
2.5k (default)AIR_DATA_RATE_000_025
5kAIR_DATA_RATE_001_050
12kAIR_DATA_RATE_010_120
28kAIR_DATA_RATE_011_280
64kAIR_DATA_RATE_100_640
168kAIR_DATA_RATE_101_168
168kAIR_DATA_RATE_110_168
168kAIR_DATA_RATE_111_168

Dettaglio CHAN

Canale

Puoi vedere il CANALE

Impostazione del pacchetto secondario

Questa è la lunghezza massima del pacchetto.

Quando i dati sono inferiori alla lunghezza del pacchetto secondario, l’uscita seriale del lato ricevente è un’uscita continua senza interruzioni. Il lato ricevente seriale emetterà il pacchetto secondario quando i dati sono superiori alla lunghezza del pacchetto secondario.

Dimensione pacchettoValore costante
16 byteSPS_0016_000
32 byteSPS_0032_001
64 byte (default)SPS_0064_010
128 byteSPS_0128_011
256 byteSPS_0256_100
512 byteSPS_0512_101
1024 byteSPS_1024_110
2048 byteSPS_2048_111

FEC

FEC: dopo aver disattivato FEC, aumenta il tasso di trasmissione effettivo dei dati, ma la capacità anti-interferenza diminuisce. Anche la distanza di trasmissione è relativamente breve, e entrambe le parti di comunicazione devono concordare sul fatto di attivare o disattivare FEC.

Bit di abilitazione FECValore costante
Disattiva FECFEC_0_OFF
Attiva FEC (default)FEC_1_ON

Modalità di pilotaggio IO

La modalità di pilotaggio IO è utilizzata per la resistenza di pull-up interna del modulo. Aumenta anche l’adattabilità del livello in caso di drain aperto. Tuttavia, in alcuni casi, potrebbe essere necessaria una resistenza pull-up esterna.

Modalità pilotaggio IO (default 1)Valore costante
TXD e AUX push-pull outputs, RXD pull-up inputsIO_D_MODE_PUSH_PULLS_PULL_UPS
TXD, AUX open-collector outputs, RXD open-collector inputsIO_D_MODE_OPEN_COLLECTOR
Ciclo WOR

Se WOR è in trasmissione: dopo che il ricevitore WOR ha ricevuto i dati wireless e li ha emessi tramite la porta seriale, attenderà 1000ms prima di entrare nuovamente in WOR. Gli utenti possono inserire i dati della porta seriale e restituirli via wireless durante questo periodo. Ogni byte seriale aggiornerà l’intervallo di 1000ms. Gli utenti devono trasmettere il primo byte entro 1000ms.

  • Periodo T = (1 + WOR) * 500ms, massimo 4000ms, minimo 500ms
  • Più lungo è il periodo di monitoraggio WOR, minore è il consumo medio di energia, ma maggiore è il ritardo dei dati.
  • Entrambi, il trasmettitore e il ricevitore, devono essere sincronizzati (molto importante).
Tempo di risveglio wirelessValore costante
500msWAKE_UP_500
1000msWAKE_UP_1000
1500msWAKE_UP_1500
2000ms (default)WAKE_UP_2000
2500msWAKE_UP_2500
3000msWAKE_UP_3000
3500msWAKE_UP_3500
4000msWAKE_UP_4000

Potenza di trasmissione

Puoi cambiare questo set di costanti applicando una define come segue:

#define E70_22 // valore predefinito senza impostazione

Applicabile per E70 con 22dBm come potenza massima.
La trasmissione a bassa potenza non è raccomandata a causa della bassa efficienza dell’alimentazione.

Potenza di trasmissione (approssimativa)Valore costante
22dBm (default)POWER_22
17dBmPOWER_17
13dBmPOWER_13
10dBmPOWER_10

Applicabile per E70 con 30dBm come potenza massima.
La trasmissione a bassa potenza non è raccomandata a causa della bassa efficienza dell’alimentazione.

#define E70_30
Potenza di trasmissione (approssimativa)Valore costante
30dBm (default)POWER_30
27dBmPOWER_27
24dBmPOWER_24
21dBmPOWER_21

Puoi configurare anche la frequenza del canale con questa define:

// One of 
#define FREQUENCY_433 
#define FREQUENCY_868
#define FREQUENCY_900
#define FREQUENCY_915

Verifica del buffer

Prima dobbiamo introdurre un metodo semplice ma pratico per controllare se qualcosa è nel buffer di ricezione.

int available();

Restituisce semplicemente il numero di byte presenti nello stream corrente.

Invio e ricezione dei messaggi

Modalità di trasmissione normale

La modalità di trasmissione normale/trasparente invia messaggi a tutti i dispositivi con lo stesso indirizzo e canale.

Esistono molti metodi per inviare/ricevere messaggi, che spiegheremo in dettaglio:

        ResponseStatus sendMessage(const String message);
        ResponseContainer receiveMessage();

Il primo metodo è sendMessage, che invia una stringa a un dispositivo in modalità Normale.

	ResponseStatus rs = e70ttl.sendMessage("Prova");
	Serial.println(rs.getResponseDescription());

Dall’altra parte, il dispositivo esegue nel loop:

       if (e70ttl.available()  > 1){
		ResponseContainer rs = e70ttl.receiveMessage();
		String message = rs.data; // First ever get the data
		Serial.println(rs.status.getResponseDescription());
		Serial.println(message);
	}

Fai attenzione: se ricevi più messaggi nel buffer e non vuoi leggerli tutti in una volta, devi usare ResponseContainer rs = e70ttl.receiveMessageUntil(); con un delimitatore inserito alla fine del messaggio inviato.

Gestire le strutture

Se vuoi inviare una struttura complessa, puoi usare questo metodo:

        ResponseStatus sendMessage(const void *message, const uint8_t size);
        ResponseStructContainer receiveMessage(const uint8_t size);

Viene utilizzato per inviare strutture, ad esempio:

	struct Messaggione {
		char type[5];
		char message[8];
		bool mitico;
	};
        struct Messaggione messaggione = {"TEMP", "Peple", true};
        ResponseStatus rs = e70ttl.sendMessage(&messaggione, sizeof(Messaggione));
	Serial.println(rs.getResponseDescription());

E dall’altro lato, puoi ricevere il messaggio così:

		ResponseStructContainer rsc = e70ttl.receiveMessage(sizeof(Messaggione));
		struct Messaggione messaggione = *(Messaggione*) rsc.data;
		Serial.println(messaggione.message);
		Serial.println(messaggione.mitico);
        rsc.close();

Leggere una struttura parziale

Se desideri leggere la prima parte del messaggio per gestire più tipi di strutture, puoi utilizzare questo metodo:

ResponseContainer receiveInitialMessage(const uint8_t size);

L’ho creato per ricevere una stringa con il tipo o altre informazioni per identificare la struttura da caricare.

		struct Messaggione { // Partial structure without type
			char message[8];
			bool mitico;
		};

		char type[5]; // first part of structure
		ResponseContainer rs = e70ttl.receiveInitialMessage(sizeof(type));
                // Put string in a char array (not needed)
		memcpy ( type, rs.data.c_str(), sizeof(type) );

		Serial.println("READ TYPE: ");
		Serial.println(rs.status.getResponseDescription());
		Serial.println(type);

                // Read the rest of structure
		ResponseStructContainer rsc = e70ttl.receiveMessage(sizeof(Messaggione));
		struct Messaggione messaggione = *(Messaggione*) rsc.data;
        rsc.close();

Modalità fissa invece di modalità normale

Allo stesso modo, ho creato una serie di metodi per utilizzare con la trasmissione fissa.

Trasmissione fissa

Devi cambiare solo il metodo di invio, poiché il dispositivo destinatario non riceverà il preambolo con indirizzo e canale quando imposti la modalità fissa.

Quindi, per il messaggio stringa, hai:

        ResponseStatus sendFixedMessage(byte ADDH, byte ADDL, byte CHAN, const String message);
        ResponseStatus sendBroadcastFixedMessage(byte CHAN, const String message);

E per la struttura, hai:

        ResponseStatus sendFixedMessage(byte ADDH, byte ADDL, byte CHAN, const void *message, const uint8_t size);
        ResponseStatus sendBroadcastFixedMessage(byte CHAN, const void *message, const uint8_t size );

Ecco un semplice esempio:

	ResponseStatus rs = e70ttl.sendFixedMessage(0, 0, 0x17, &messaggione, sizeof(Messaggione));
//	ResponseStatus rs = e70ttl.sendFixedMessage(0, 0, 0x17, "Ciao");

La trasmissione fissa ha più scenari:

Se invii a un dispositivo specifico (secondo scenario Trasmissione fissa), devi aggiungere ADDL, ADDH e CHAN per identificarlo direttamente.

ResponseStatus rs = e70ttl.sendFixedMessage(2, 2, 0x17, "Messaggio a un dispositivo");

Se vuoi inviare un messaggio a tutti i dispositivi su un canale specifico, puoi usare questo metodo:

ResponseStatus rs = e70ttl.sendBroadcastFixedMessage(0x17, "Messaggio a tutti i dispositivi su un canale");

Se desideri ricevere tutti i messaggi broadcast nella rete, devi impostare i tuoi ADDH e ADDL su BROADCAST_ADDRESS.

        ResponseStructContainer c;
	c = e70ttl.getConfiguration();
	// It's important get configuration pointer before all other operation
	Configuration configuration = *(Configuration*) c.data;
	Serial.println(c.status.getResponseDescription());
	Serial.println(c.status.code);

	printParameters(configuration);
	configuration.ADDL = BROADCAST_ADDRESS;
	configuration.ADDH = BROADCAST_ADDRESS;

	// Set configuration changed and set to not hold the configuration
	ResponseStatus rs = e70ttl.setConfiguration(configuration, WRITE_CFG_PWR_DWN_LOSE);
	Serial.println(rs.getResponseDescription());
	Serial.println(rs.code);
	printParameters(configuration);
        c.close();

Modalità continua

L’E70 offre la modalità continua impostando lo stesso ADDH, ADDL e CHAN. Puoi trasmettere una grande quantità di dati o dati continui.

Modalità Continua

  1. Operazione: In modalità continua, il modulo EByte E70 invia o riceve dati in un flusso continuo. Ciò significa che, una volta avviata la trasmissione, continuerà a inviare dati fino a quando non verrà fermata. È simile a una trasmissione radio tradizionale.
  2. Utilizzo: Questa modalità è utile per applicazioni in cui è necessario un flusso costante di informazioni, senza interruzioni. È ideale per la trasmissione di dati in tempo reale, come lo streaming audio o la telemetria.
  3. Vantaggi:
    • Trasmissione dati in tempo reale: Utile per applicazioni che richiedono aggiornamenti in tempo reale.
    • Nessuna interruzione: Flusso continuo di dati senza la necessità di riassemblare i pacchetti o gestirli.
  4. Sfide:
    • Consumo energetico: La modalità continua consuma generalmente più energia a causa della trasmissione costante.
    • Utilizzo della larghezza di banda: Può utilizzare più larghezza di banda, il che potrebbe non essere ideale in ambienti RF affollati.

Modalità a Pacchetti

  1. Operazione: Nella modalità a pacchetti, i dati vengono suddivisi in pacchetti più piccoli prima della trasmissione. Ogni pacchetto viene inviato separatamente e quindi riassemblato dal ricevitore.
  2. Utilizzo: Questa modalità è ideale per applicazioni che non richiedono trasmissioni in tempo reale e possono tollerare un certo ritardo, come l’invio di dati sensoriali a intervalli.
  3. Vantaggi:
    • Efficienza energetica: Più efficiente dal punto di vista energetico, poiché il modulo può andare in modalità a basso consumo tra le trasmissioni.
    • Gestione degli errori: Più facile implementare il controllo e la correzione degli errori, poiché viene fatto su base per pacchetto.
    • Velocità di trasmissione adattativa: Può regolare la velocità dei dati per ogni pacchetto a seconda delle condizioni della rete.
  4. Sfide:
    • Latenza: C’è un ritardo nell’assemblaggio dei dati, che potrebbe non essere adatto per applicazioni in tempo reale.
    • Complessità: Richiede una logica più complessa per la gestione e l’assemblaggio dei pacchetti.

Differenze Chiave

  • Metodo di trasmissione dei dati: La modalità continua trasmette dati in un flusso costante, mentre la modalità a pacchetti suddivide i dati in pacchetti più piccoli.
  • Consumo energetico: La modalità continua generalmente consuma più energia a causa della trasmissione costante.
  • Capacità in tempo reale: La modalità continua è migliore per esigenze di dati in tempo reale, mentre la modalità a pacchetti è adatta per trasmissioni di dati ritardati o periodici.
  • Gestione degli errori e flessibilità: La modalità a pacchetti offre maggiore flessibilità nella gestione degli errori e nell’adattarsi alle condizioni di rete.

Quando utilizzi la modalità di trasmissione continua, il modulo invia un flusso continuo di dati. Per indirizzare questi dati a un indirizzo specifico, di solito configureresti il mittente e il ricevitore con indirizzi corrispondenti. Ciò significa che sia il modulo trasmittente che quello ricevente devono essere configurati per riconoscere e utilizzare questi indirizzi specificati.

Flusso semplice

Per inviare un flusso semplice (senza preambolo) puoi usare:

ResponseStatus RF_E70::streamMessage(Stream *streamLocal)

Una possibile implementazione potrebbe essere il flusso di un file.

			File inputFile = SPIFFS.open(input);

			if (!inputFile) {
			    Serial.println("There was an error opening the file for reading");
			} else  {
				ResponseStatus rs = e70ttl.streamMessage(&inputFile);
				// Check If there is some problem of succesfully send
				Serial.println(rs.getResponseDescription());
			}

Prende un flusso come parametro. Per riceverlo, puoi attendere i dati.

    if (e70ttl.available()>0) {
    	Serial.println("Start!");

  	  // open file in write 
    	File output = SPIFFS.open("/tmp.png", FTP_FILE_WRITE_CREATE);

    	while (e70ttl.available()>0) {
			while (e70ttl.available()>0) {
				if (output.write(e70ttl.read())==0) {Serial.println("ERROR WRITE!"); };
			}
	    	delay(10);
    	}

    	output.close();

    	Serial.println("Complete!");
    }

Come puoi vedere, puoi usare read, che è un classico stream.read().

Flusso con preambolo

Non tutte le situazioni possono essere un flusso continuo; a volte abbiamo bisogno di inviare dati come un array di byte; in questa situazione, hai bisogno di un preambolo con le informazioni sul file, e puoi usare il comando:

ResponseStatus RF_E70::streamStructMessage(const void *message, const uint8_t size, Stream *streamLocal)

Puoi identificare che la prima parte del metodo di invio è la stessa del send struct descritto prima; l’ultimo parametro è il flusso da inviare.

Per riceverlo tutto, prima devi chiamare il comando per ottenere la struttura (preambolo).

ResponseStructContainer RF_E70::receiveStreamMessage(const uint8_t size)

Quindi, ricevi il flusso come descritto in precedenza.

Grazie


Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *