/* * Copyright (c) 2017-2020 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 LORAWAN_H #define LORAWAN_H #include #define LORAWAN_DEFAULT_PORT 1 #define LORAWAN_MAX_PAYLOAD_SIZE 242 #define LORAWAN_TX_BUFFER_SIZE LORAWAN_MAX_PAYLOAD_SIZE #define LORAWAN_RX_BUFFER_SIZE (2 * (2 + LORAWAN_MAX_PAYLOAD_SIZE) + 1) #define LORAWAN_ACTIVATION_NONE 0 #define LORAWAN_ACTIVATION_OTAA 1 #define LORAWAN_ACTIVATION_ABP 2 #define LORAWAN_REGION_NONE 0 #define LORAWAN_REGION_AS923 1 #define LORAWAN_REGION_AU915 2 #define LORAWAN_REGION_CN470 3 #define LORAWAN_REGION_CN779 4 #define LORAWAN_REGION_EU433 5 #define LORAWAN_REGION_EU868 6 #define LORAWAN_REGION_IN865 7 #define LORAWAN_REGION_KR920 8 #define LORAWAN_REGION_US915 9 #define LORAWAN_BATTERY_LEVEL_EXTERNAL 0 #define LORAWAN_BATTERY_LEVEL_EMPTY 1 #define LORAWAN_BATTERY_LEVEL_FULL 254 #define LORAWAN_BATTERY_LEVEL_UNKNOWN 255 typedef struct { uint32_t Header; uint8_t AppEui[8]; uint8_t AppKey[16]; uint8_t DevEui[8]; uint32_t DevAddr; uint8_t NwkSKey[16]; uint8_t AppSKey[16]; uint32_t Crc32; } LoRaWANCommissioning; typedef struct { uint32_t Header; uint8_t Activation; uint8_t Reserved; uint8_t DevEui[8]; uint8_t AppEui[8]; uint8_t AppKey[16]; uint16_t DevNonce0; uint32_t AppNonce; uint32_t NetID; uint32_t DevAddr; uint8_t NwkSKey[16]; uint8_t AppSKey[16]; uint32_t Crc32; } LoRaWANSession; typedef struct { uint32_t Header; uint16_t ReceiveDelay; /* JOIN_ACCEPT, RX_TIMING_SETUP */ uint8_t RX1DrOffset; /* JOIN_ACCEPT, RX_PARAM_SETUP */ uint8_t RX2DataRate; /* JOIN_ACCEPT, RX_PARAM_SETUP */ uint32_t RX2Frequency; /* RX_PARAM_SETUP */ uint8_t Region; uint8_t Network; /* (_SubBand & 0x0F) | (_PublicNetwork << 7) */ uint8_t UpLinkDwellTime; /* TX_PARAM_SETUP */ uint8_t DownLinkDwellTime; /* TX_PARAM_SETUP */ float MaxEIRP; /* TX_PARAM_SETUP */ uint16_t ChannelsMask[6]; /* JOIN_ACCEPT, ADR */ uint32_t ChannelsFrequency[16]; /* NEW_CHANNEL */ uint8_t ChannelsDrRange[16]; /* NEW_CHANNEL, 4 MSBs is MAX, 4 LSBs is MIN */ uint32_t ChannelsRX1Frequency[16]; /* DL_CHANNEL */ uint32_t Crc32; } LoRaWANParams; extern const struct LoRaWANBand AS923; extern const struct LoRaWANBand AU915; extern const struct LoRaWANBand EU868; extern const struct LoRaWANBand IN865; extern const struct LoRaWANBand KR920; extern const struct LoRaWANBand US915; class LoRaWANClass : public Stream { public: LoRaWANClass(); int begin(const struct LoRaWANBand &band); int joinOTAA(); int joinOTAA(const char *appEui, const char *appKey, const char *devEui = nullptr); int rejoinOTAA(); int joinABP(); int joinABP(const char *devAddr, const char *nwkSKey, const char *appSKey); bool joined(); // true == joined, false == non-joined bool confirmed(); // last message was confired bool pending(); // more downlink data pending bool busy(); // true == busy, false == ready operator bool() { return joined(); } int beginPacket(uint8_t port = LORAWAN_DEFAULT_PORT); int endPacket(bool confirm = false); int sendPacket(const uint8_t *buffer, size_t size, bool confirmed = false); int sendPacket(uint8_t port, const uint8_t *buffer, size_t size, bool confirmed = false); int linkCheck(); int ping(); virtual int availableForWrite(); virtual size_t write(uint8_t data); virtual size_t write(const uint8_t *buffer, size_t size); inline size_t write(unsigned long n) { return write((uint8_t)n); } inline size_t write(long n) { return write((uint8_t)n); } inline size_t write(unsigned int n) { return write((uint8_t)n); } inline size_t write(int n) { return write((uint8_t)n); } using Print::write; int parsePacket(); virtual int available(); virtual int read(); virtual int read(uint8_t *buffer, size_t size); virtual int peek(); virtual void flush(); uint8_t remotePort(); int lastRSSI() { return _RSSI; } int lastSNR() { return _SNR; } unsigned int linkMargin() { return _LinkCheckMargin; } unsigned int linkGateways() { return _LinkCheckGateways; } void onJoin(void(*callback)(void)); void onJoin(Callback callback); void onLinkCheck(void(*callback)(void)); void onLinkCheck(Callback callback); void onReceive(void(*callback)(void)); void onReceive(Callback callback); void onTransmit(void(*callback)(void)); void onTransmit(Callback callback); void enableWakeup(); void disableWakeup(); int setAppEui(const char *appEui); int setAppKey(const char *appKey); int setDevEui(const char *devEui); int setDevAddr(const char *devAddr); int setNwkSKey(const char *nwkSKey); int setAppSKey(const char *appSKey); int getDevEui(char *buffer, size_t size); int getNextTxTime(); int getMaxPayloadSize(); int getDataRate(); float getTxPower(); int getRepeat(); unsigned long getTimeOnAir() { return _TimeOnAir; } unsigned long getUpLinkCounter() { return _UpLinkCounter; } unsigned long getDownLinkCounter() { return _DownLinkCounter; } int setSaveSession(bool enable); int setJoinDelay1(unsigned int delay); int setJoinDelay2(unsigned int delay); int setJoinRetries(unsigned int n); int setLinkCheckLimit(unsigned int n); int setLinkCheckDelay(unsigned int n); int setLinkCheckThreshold(unsigned int n); int setADR(bool enable); int setDataRate(unsigned int datarate); int setTxPower(float power); // 2dm to 20dbm int setRepeat(unsigned int n); int setRetries(unsigned int n); int setPublicNetwork(bool enable); int setSubBand(unsigned int subband); int setReceiveDelay(unsigned int delay); int setRX1DrOffset(unsigned int offset); int setRX2Channel(unsigned long frequency, unsigned int datarate); int addChannel(unsigned int index, unsigned long frequency, unsigned int drMin, unsigned int drMax); int removeChannel(unsigned int index); int enableChannel(unsigned int index); int disableChannel(unsigned int index); int setDownLinkChannel(unsigned int index, unsigned long frequency); int setUpLinkDwellTime(bool enable); int setDownLinkDwellTime(bool enable); int setMaxEIRP(float eirp); int setAntennaGain(float gain); int setSystemMaxRxError(unsigned int error); int setDutyCycle(bool enable); int setRxWindows(bool enable); int setTxContinuousWave(unsigned long frequency, float power, unsigned long seconds); int setComplianceTest(bool enable); int setBatteryLevel(unsigned int level); private: uint8_t *_rx_data; volatile uint16_t _rx_read; volatile uint16_t _rx_write; uint16_t _rx_index; uint16_t _rx_next; uint8_t _rx_size; uint8_t _rx_port; volatile uint8_t _rx_pending; uint8_t *_tx_data; uint8_t _tx_size; uint8_t _tx_port; uint8_t _tx_confirmed; volatile uint8_t _tx_join; volatile uint8_t _tx_active; volatile uint8_t _tx_pending; volatile uint8_t _tx_ack; volatile uint8_t _tx_busy; const struct LoRaWANBand *_Band; volatile uint8_t _Joined; uint8_t _Save; uint8_t _BatteryLevel; uint8_t _DutyCycle; uint8_t _PublicNetwork; uint8_t _SubBand; uint8_t _DataRate; uint8_t _Retries; uint8_t _ComplianceTest; uint16_t _JoinRetries; volatile uint16_t _JoinTrials; uint8_t _AdrEnable; volatile uint8_t _AdrWait; uint8_t _AdrLastDataRate; uint8_t _AdrLastTxPower; uint8_t _LinkCheckLimit; uint8_t _LinkCheckDelay; uint8_t _LinkCheckThreshold; volatile uint8_t _LinkCheckCount; volatile uint8_t _LinkCheckWait; volatile uint8_t _LinkCheckFail; volatile uint8_t _LinkCheckGateways; volatile uint8_t _LinkCheckMargin; volatile int16_t _RSSI; volatile int8_t _SNR; volatile uint16_t _DevNonce; volatile uint32_t _TimeOnAir; volatile uint32_t _UpLinkCounter; volatile uint32_t _DownLinkCounter; LoRaWANSession _session; LoRaWANParams _params; Callback _joinCallback; Callback _linkCheckCallback; Callback _receiveCallback; Callback _transmitCallback; bool _wakeup; void _saveSession(); bool _restoreSession(); void _saveADR(); bool _restoreADR(); void _saveParams(); bool _restoreParams(); bool _getParams(); bool _setParams(); void _saveDevNonce(); void _saveUpLinkCounter(); void _saveDownLinkCounter(); bool _loadCommissioning(LoRaWANCommissioning *commissioning); bool _storeCommissioning(LoRaWANCommissioning *commissioning); int _joinOTAA(LoRaWANCommissioning *commissioning); int _joinABP(LoRaWANCommissioning *commissioning); int _rejoinOTAA(); int _rejoinABP(); bool _send(); static bool _eepromProgram(uint32_t address, const uint8_t *data, uint32_t size); static bool _eepromRead(uint32_t address, uint8_t *data, uint32_t size); static void _eepromSync(class LoRaWANClass *self); static void _eepromDone(class LoRaWANClass *self); static uint8_t __GetBatteryLevel(); static void __McpsJoin(void); static void __McpsSend(void); static void __McpsConfirm(struct sMcpsConfirm*); static void __McpsIndication(struct sMcpsIndication*); static void __MlmeJoin(void); static void __MlmeConfirm(struct sMlmeConfirm*); static void __MlmeIndication(struct sMlmeIndication*); }; extern LoRaWANClass LoRaWAN; #endif // LORAWAN_H