/* * Copyright (c) 2015 SODAQ. All rights reserved. * * This file is part of Sodaq_RN2483. * * Sodaq_RN2483 is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation, either version 3 of * the License, or(at your option) any later version. * * Sodaq_RN2483 is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with Sodaq_RN2483. If not, see * . */ #ifndef _Sodaq_RN2483_h #define _Sodaq_RN2483_h #include #include #include #include "Switchable_Device.h" /** Notes: - uint16_t is preferred over size_t because long is never needed by the size of the packets or the buffers of this application. (Kees Bakker does not agree with this. size_t is not the same as long. On AVR a size_t is uint16_t. On SAMD we don't care too much about the data size, a long is fine.) - Currently, only one received packet is supported. Every time a packet is received, the previous one is overwritten. - Also multiple responses from the server (with Frame Pending Bit set) are not supported. - The port of the received packet is not returned. */ //#define USE_DYNAMIC_BUFFER //#define DEBUG #define DEFAULT_INPUT_BUFFER_SIZE 64 #define DEFAULT_RECEIVED_PAYLOAD_BUFFER_SIZE 32 #define DEFAULT_TIMEOUT 120 #define RECEIVE_TIMEOUT 60000 // Available error codes. enum MacTransmitErrorCodes { NoError = 0, NoResponse = 1, Timeout = 2, PayloadSizeError = 3, InternalError = 4, Busy = 5, NetworkFatalError = 6, NotConnected = 7, NoAcknowledgment = 8, }; // Provides a simple, abstracted interface to Microchip's RN2483 LoRaWAN module. // Implements SwitchableDevice for turning the device On/Off on supported boards. // // It is strongly suggested to use the static instance that is included with the library (LoRaBee) // and not to create a new instance. class Sodaq_RN2483 : public SwitchableDevice { public: // Creates a new Sodaq_RN2483 instance. Sodaq_RN2483(); // Returns the correct baudrate for the serial port that connects to the device. uint32_t getDefaultBaudRate() { return 57600; }; // Initializes the device and connects to the network using Over-The-Air Activation. // Returns true on successful connection. bool initOTA(Stream& stream, const uint8_t devEUI[8], const uint8_t appEUI[8], const uint8_t appKey[16], bool adr = true); // Initializes the device and connects to the network using Activation By Personalization. // Returns true on successful connection. bool initABP(Stream& stream, const uint8_t devAddr[4], const uint8_t appSKey[16], const uint8_t nwkSKey[16], bool adr = true); // Sets the optional "Diagnostics and Debug" stream. void setDiag(Stream& stream) { diagStream = &stream; }; // Sends the given payload without acknowledgement. // Returns 0 (NoError) when transmission is successful or one of the MacTransmitErrorCodes otherwise. uint8_t send(uint8_t port, const uint8_t* payload, uint8_t size); // Sends the given payload with acknowledgement. // Returns 0 (NoError) when transmission is successful or one of the MacTransmitErrorCodes otherwise. uint8_t sendReqAck(uint8_t port, const uint8_t* payload, uint8_t size, uint8_t maxRetries); // Copies the latest received packet (optionally starting from the "payloadStartPosition" // position of the payload) into the given "buffer", up to "size" number of bytes. // Returns the number of bytes written or 0 if no packet is received since last transmission. uint16_t receive(uint8_t* buffer, uint16_t size, uint16_t payloadStartPosition = 0); #ifdef USE_DYNAMIC_BUFFER // Sets the size of the input buffer. // Needs to be called before initOTA()/initABP(). void setInputBufferSize(uint16_t value) { this->inputBufferSize = value; }; // Sets the size of the "Received Payload" buffer. // Needs to be called before initOTA()/initABP(). void setReceivedPayloadBufferSize(uint16_t value) { this->receivedPayloadBufferSize = value; }; #endif #ifdef DEBUG // Provides a quick test of several methods as a pseudo-unit test. void runTestSequence(Stream& stream); int freeRam(); #endif private: // The stream that communicates with the device. Stream* loraStream; // The (optional) stream to show debug information. Stream* diagStream; // The size of the input buffer. Equals DEFAULT_INPUT_BUFFER_SIZE // by default or (optionally) a user-defined value when using USE_DYNAMIC_BUFFER. uint16_t inputBufferSize; // The size of the received payload buffer. Equals DEFAULT_RECEIVED_PAYLOAD_BUFFER_SIZE // by default or (optionally) a user-defined value when using USE_DYNAMIC_BUFFER. uint16_t receivedPayloadBufferSize; // Flag used to make sure the received payload buffer is // current with the latest transmission. bool packetReceived; #ifdef USE_DYNAMIC_BUFFER // Flag to make sure the buffers are not allocated more than once. bool isBufferInitialized; char* inputBuffer; char* receivedPayloadBuffer; #else char inputBuffer[DEFAULT_INPUT_BUFFER_SIZE]; char receivedPayloadBuffer[DEFAULT_RECEIVED_PAYLOAD_BUFFER_SIZE]; #endif // Takes care of the init tasks common to both initOTA() and initABP. inline void init(Stream& stream); // Reads a line from the device stream into the "buffer" starting at the "start" position of the buffer. // Returns the number of bytes read. uint16_t readLn(char* buffer, uint16_t size, uint16_t start = 0); // Reads a line from the device stream into the input buffer. // Returns the number of bytes read. uint16_t readLn() { return readLn(this->inputBuffer, this->inputBufferSize); }; // Waits for the given string. Returns true if the string is received before a timeout. // Returns false if a timeout occurs or if another string is received. bool expectString(const char* str, uint16_t timeout = DEFAULT_TIMEOUT); bool expectOK(); // Sends a reset command to the module and waits for the success response (or timeout). // Returns true on success. bool resetDevice(); // Sends a join network command to the device and waits for the response (or timeout). // Returns true on success. bool joinNetwork(const char* type); // Sends the given mac command together with the given paramValue // to the device and awaits for the response. // Returns true on success. // NOTE: paramName should include a trailing space bool setMacParam(const char* paramName, const uint8_t* paramValue, uint16_t size); bool setMacParam(const char* paramName, uint8_t paramValue); bool setMacParam(const char* paramName, const char* paramValue); // Returns the enum that is mapped to the given "error" message. uint8_t lookupMacTransmitError(const char* error); // Sends a a payload and blocks until there is a response back, or the receive windows have closed, // or the hard timeout has passed. uint8_t macTransmit(const char* type, uint8_t port, const uint8_t* payload, uint8_t size); // Parses the input buffer and copies the received payload into the "received payload" buffer // when a "mac rx" message has been received. It is called internally by macTransmit(). // Returns 0 (NoError) or otherwise one of the MacTransmitErrorCodes. uint8_t onMacRX(); }; extern Sodaq_RN2483 LoRaBee; #endif // Sodaq_RN2483