mirror of
https://github.com/letscontrolit/ESPEasy.git
synced 2026-09-12 09:36:59 +00:00
344 lines
11 KiB
C++
344 lines
11 KiB
C++
#ifndef RN2XX3_TX_STATE_H
|
|
#define RN2XX3_TX_STATE_H
|
|
|
|
#include <Arduino.h>
|
|
|
|
#include "rn2xx3_status.h"
|
|
|
|
// State machine for the RN2483/RN2903 modules
|
|
class rn2xx3_handler {
|
|
public:
|
|
|
|
enum RN_state {
|
|
idle,
|
|
command_set_to_send,
|
|
wait_for_reply,
|
|
wait_for_reply_rx2,
|
|
reply_received,
|
|
reply_received_rx2,
|
|
tx_success,
|
|
tx_success_with_rx,
|
|
reply_received_finished,
|
|
join_accepted,
|
|
timeout,
|
|
duty_cycle_exceeded,
|
|
max_attempt_reached,
|
|
error,
|
|
invalid_char_read,
|
|
must_perform_init,
|
|
must_pause
|
|
};
|
|
|
|
rn2xx3_handler(Stream& serial);
|
|
|
|
String sendRawCommand(const __FlashStringHelper* command);
|
|
String sendRawCommand(const String& command);
|
|
|
|
bool prepare_raw_command(const String& command);
|
|
|
|
bool prepare_tx_command(const String& command,
|
|
const String& data,
|
|
bool shouldEncode,
|
|
uint8_t port);
|
|
|
|
bool prepare_join(bool useOTAA);
|
|
|
|
RN_state async_loop();
|
|
|
|
// Wait for the command to be handled completely (including reply in RX2 window)
|
|
RN_state wait_command_finished(unsigned long timeout = 10000);
|
|
|
|
// Shorter wait, to be used in async mode.
|
|
// This will return early when the message cannot be sent (e.g. due to duty cycle exceeded)
|
|
// It will return when the state waiting for reply_received_rx2 has been reached, or the command has finished (due to error)
|
|
RN_state wait_command_accepted(unsigned long timeout = 10000);
|
|
|
|
// Check whether a command has finished.
|
|
bool command_finished() const;
|
|
|
|
|
|
/*
|
|
* Initialise the RN2xx3 and join the LoRa network (if applicable).
|
|
* This function can only be called after calling initABP() or initOTAA().
|
|
* The sole purpose of this function is to re-initialise the radio if it
|
|
* is in an unknown state.
|
|
*/
|
|
bool init();
|
|
|
|
/*
|
|
* Initialise the RN2xx3 and join a network using personalization.
|
|
*
|
|
* addr: The device address as a HEX string.
|
|
* Example "0203FFEE"
|
|
* AppSKey: Application Session Key as a HEX string.
|
|
* Example "8D7FFEF938589D95AAD928C2E2E7E48F"
|
|
* NwkSKey: Network Session Key as a HEX string.
|
|
* Example "AE17E567AECC8787F749A62F5541D522"
|
|
*/
|
|
bool initABP(const String& addr,
|
|
const String& AppSKey,
|
|
const String& NwkSKey);
|
|
|
|
// TODO: initABP(uint8_t * addr, uint8_t * AppSKey, uint8_t * NwkSKey)
|
|
|
|
/*
|
|
* Initialise the RN2xx3 and join a network using over the air activation.
|
|
*
|
|
* AppEUI: Application EUI as a HEX string.
|
|
* Example "70B3D57ED00001A6"
|
|
* AppKey: Application key as a HEX string.
|
|
* Example "A23C96EE13804963F8C2BD6285448198"
|
|
* DevEUI: Device EUI as a HEX string.
|
|
* Example "0011223344556677"
|
|
* If the DevEUI parameter is omitted, the Hardware EUI from module will be used
|
|
* If no keys, or invalid length keys, are provided, no keys
|
|
* will be configured. If the module is already configured with some keys
|
|
* they will be used. Otherwise the join will fail and this function
|
|
* will return false.
|
|
*/
|
|
bool initOTAA(const String& AppEUI = "",
|
|
const String& AppKey = "",
|
|
const String& DevEUI = "");
|
|
|
|
/*
|
|
* Initialise the RN2xx3 and join a network using over the air activation,
|
|
* using byte arrays. This is useful when storing the keys in eeprom or flash
|
|
* and reading them out in runtime.
|
|
*
|
|
* AppEUI: Application EUI as a uint8_t buffer
|
|
* AppKey: Application key as a uint8_t buffer
|
|
* DevEui: Device EUI as a uint8_t buffer (optional - set to 0 to use Hardware EUI)
|
|
*/
|
|
bool initOTAA(uint8_t *AppEUI,
|
|
uint8_t *AppKey,
|
|
uint8_t *DevEui);
|
|
|
|
|
|
RN2xx3_datatypes::TX_return_type txCommand(const __FlashStringHelper* command,
|
|
const String& data,
|
|
bool shouldEncode,
|
|
uint8_t port);
|
|
|
|
|
|
RN2xx3_datatypes::TX_return_type txCommand(const String&,
|
|
const String&,
|
|
bool,
|
|
uint8_t port = 1);
|
|
|
|
bool setSF(uint8_t sf);
|
|
uint8_t getSF(int& dr);
|
|
|
|
|
|
/*
|
|
* Change the datarate at which the RN2xx3 transmits.
|
|
* A value of between 0 and 5 can be specified,
|
|
* as is defined in the LoRaWan specs.
|
|
* This can be overwritten by the network when using OTAA.
|
|
* So to force a datarate, call this function after initOTAA().
|
|
*/
|
|
bool setDR(int dr);
|
|
|
|
void setAsyncMode(bool enabled);
|
|
|
|
bool getAsyncMode() const;
|
|
|
|
bool useOTAA() const;
|
|
|
|
void setLastUsedJoinMode(bool isOTAA);
|
|
|
|
// We can't read back from module, we send the one
|
|
// we have memorized if it has been set
|
|
String appkey() const {
|
|
return _appkey;
|
|
}
|
|
|
|
String appskey() const {
|
|
return _appskey;
|
|
}
|
|
|
|
RN2xx3_datatypes::Model moduleType()
|
|
{
|
|
return _moduleType;
|
|
}
|
|
|
|
bool setFrequencyPlan(RN2xx3_datatypes::Freq_plan fp, uint32_t rx2_freq = 0);
|
|
|
|
bool setTTNstack(RN2xx3_datatypes::TTN_stack_version version);
|
|
|
|
private:
|
|
|
|
// Return the data to send
|
|
const String& get_send_data() const;
|
|
|
|
public:
|
|
|
|
// Get the received data
|
|
const String& get_received_data() const;
|
|
|
|
const String& get_received_data(unsigned long& duration) const;
|
|
|
|
// Get the downlink message, received during RX2 after TX command.
|
|
const String& get_rx_message() const;
|
|
|
|
// Look at the last error, without clearing it.
|
|
String peekLastError() const;
|
|
|
|
// get and clear the last error.
|
|
String getLastError();
|
|
|
|
// Set specific error string.
|
|
void setLastError(const __FlashStringHelper* error);
|
|
void setLastError(const String& error);
|
|
|
|
RN_state get_state() const;
|
|
|
|
uint8_t get_busy_count() const;
|
|
|
|
String sysver();
|
|
|
|
// delay from last moment of sending to receive RX1 and RX2 window
|
|
bool getRxDelayValues(uint32_t& rxdelay1,
|
|
uint32_t& rxdelay2);
|
|
|
|
// Compute the air time for a packet in msec.
|
|
// Formula used from https://www.loratools.nl/#/airtime
|
|
// @param pl Payload length in bytes
|
|
float getLoRaAirTime(uint8_t pl) const;
|
|
|
|
|
|
private:
|
|
|
|
RN2xx3_datatypes::Model configureModuleType();
|
|
|
|
|
|
bool resetModule();
|
|
|
|
// Check to see if the set activation values are of the right size and in HEX notation.
|
|
bool check_set_keys();
|
|
|
|
void set_state(RN_state state);
|
|
|
|
// read all available data from serial until '\n'
|
|
bool read_line();
|
|
|
|
void set_timeout(unsigned long timeout);
|
|
|
|
bool time_out_reached() const;
|
|
|
|
void handle_reply_received();
|
|
|
|
void clearSerialBuffer();
|
|
|
|
// Read the internal status of the module
|
|
// @retval true when update was successful
|
|
bool updateStatus();
|
|
|
|
bool saveUpdatedStatus();
|
|
|
|
|
|
enum Active_cmd {
|
|
none,
|
|
TX,
|
|
join,
|
|
other
|
|
};
|
|
|
|
|
|
// OTAA values:
|
|
String _deveui;
|
|
String _appeui;
|
|
String _appkey;
|
|
|
|
// ABP values:
|
|
String _nwkskey;
|
|
String _appskey;
|
|
String _devaddr;
|
|
|
|
|
|
String _receivedData; // Used as a receive buffer to collect replies from the module
|
|
String _sendData; // Complete command to send to the module
|
|
String _rxMessenge; // Message received (during RX2 window) after a TX
|
|
String _lastError; // Last error message received from module (or set by user)
|
|
unsigned long _start_prep = 0; // timestamp of preparing command
|
|
unsigned long _start = 0; // timestamp of last set timeout
|
|
unsigned long _timeout = 100; // timeout duration
|
|
uint32_t _rxdelay1 = 5000; // delay from last moment of sending to receive RX1 window
|
|
uint32_t _rxdelay2 = 6000; // delay from last moment of sending to receive RX2 window
|
|
uint8_t _busy_count = 0; // Number of times the module replied with "busy"
|
|
uint8_t _retry_count = 0; // Number of retries of current TX command
|
|
RN_state _state = RN_state::idle;
|
|
Active_cmd _processing_cmd = Active_cmd::none;
|
|
bool _invalid_char_read = false;
|
|
bool _extensive_debug = false; // Set this to true to log all steps in _lastError
|
|
uint16_t _max_received_length = 0;
|
|
|
|
|
|
RN2xx3_datatypes::Firmware _firmware = RN2xx3_datatypes::Firmware::unknown;
|
|
RN2xx3_datatypes::Model _moduleType = RN2xx3_datatypes::Model::RN_NA;
|
|
RN2xx3_datatypes::Freq_plan _fp = RN2xx3_datatypes::Freq_plan::TTN_EU;
|
|
uint32_t _rx2_frequency = 0;
|
|
uint8_t _sf = 7;
|
|
uint8_t _dr = 5;
|
|
|
|
bool _otaa = true; // Switch between OTAA or ABP activation (default OTAA)
|
|
bool _asyncMode = false; // When set, the user must call async_loop() frequently
|
|
|
|
public:
|
|
|
|
RN2xx3_status Status; // Cached result of "mac get status"
|
|
Stream& _serial; // The serial port used for this module.
|
|
|
|
|
|
// Convenience functions
|
|
|
|
int readIntValue(const __FlashStringHelper* command);
|
|
int readIntValue(const String& command);
|
|
|
|
|
|
bool readUIntMacGet(const __FlashStringHelper* param,
|
|
uint32_t & value);
|
|
bool readUIntMacGet(const String& param,
|
|
uint32_t & value);
|
|
|
|
// All "mac set ..." commands return either "ok" or "invalid_param"
|
|
bool sendMacSet(const __FlashStringHelper* param,
|
|
const String& value);
|
|
bool sendMacSet(const String& param,
|
|
const String& value);
|
|
bool sendMacSetEnabled(const __FlashStringHelper* param,
|
|
bool enabled);
|
|
bool sendMacSetCh(const String& param,
|
|
unsigned int channel,
|
|
const String& value);
|
|
bool sendMacSetCh(const String& param,
|
|
unsigned int channel,
|
|
uint32_t value);
|
|
bool sendMacSetCh(const __FlashStringHelper* param,
|
|
unsigned int channel,
|
|
uint32_t value);
|
|
bool setChannelDutyCycle(unsigned int channel,
|
|
unsigned int dutyCycle);
|
|
bool setChannelFrequency(unsigned int channel,
|
|
uint32_t frequency);
|
|
bool setChannelDataRateRange(unsigned int channel,
|
|
unsigned int minRange,
|
|
unsigned int maxRange);
|
|
|
|
// Set channel enabled/disabled.
|
|
// Frequency, data range, duty cycle must be issued prior to enabling the status of that channel
|
|
bool setChannelEnabled(unsigned int channel,
|
|
bool enabled);
|
|
|
|
bool set2ndRecvWindow(unsigned int dataRate,
|
|
uint32_t frequency);
|
|
bool setAdaptiveDataRate(bool enabled);
|
|
bool setAutomaticReply(bool enabled);
|
|
bool setTXoutputPower(int pwridx);
|
|
|
|
// Send the autobaud sequence to try and wake the module.
|
|
void sendWakeSequence();
|
|
};
|
|
|
|
|
|
#endif // RN2XX3_TX_STATE_H
|