Files
ESPEasy/lib/RN2483-Arduino-Library/src/rn2xx3_handler.h
T

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