inital draft
This commit is contained in:
		
				commit
				
					
						8491fc7308
					
				
			
		
					 7 changed files with 1037 additions and 0 deletions
				
			
		
							
								
								
									
										119
									
								
								HackZurich_LoraWan.ino
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										119
									
								
								HackZurich_LoraWan.ino
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,119 @@
 | 
			
		|||
#include "Sodaq_RN2483.h"
 | 
			
		||||
#include "Arduino.h"
 | 
			
		||||
 | 
			
		||||
#define debugSerial SerialUSB
 | 
			
		||||
#define loraSerial Serial1
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void RED() {
 | 
			
		||||
  digitalWrite(LED_RED, LOW);
 | 
			
		||||
  digitalWrite(LED_GREEN, HIGH);
 | 
			
		||||
  digitalWrite(LED_BLUE, HIGH);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void CLEAR() {
 | 
			
		||||
  digitalWrite(LED_RED, HIGH);
 | 
			
		||||
  digitalWrite(LED_GREEN, HIGH);
 | 
			
		||||
  digitalWrite(LED_BLUE, HIGH);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// OTAA
 | 
			
		||||
// I took 0x02 here as device Id...
 | 
			
		||||
uint8_t DevEUI[8] = { 0x9c, 0xd9, 0x0b, 0xb5, 0x2b, 0x6a, 0x1d, 0x02 };
 | 
			
		||||
uint8_t AppEUI[8] = { 0xd4, 0x16, 0xcd, 0x0b, 0x7b, 0xcf, 0x2d, 0x5c };
 | 
			
		||||
uint8_t AppKey[16] = {0xa9, 0xbc, 0x8b, 0x6a, 0x81, 0x75, 0xf6, 0x33,
 | 
			
		||||
0xe0, 0xd6, 0x64, 0xd9, 0x2b, 0xcb, 0x13, 0x78 };
 | 
			
		||||
 | 
			
		||||
void setupLoRaOTAA(){
 | 
			
		||||
  if (LoRaBee.initOTA(loraSerial, DevEUI, AppEUI, AppKey, true))
 | 
			
		||||
  {
 | 
			
		||||
    debugSerial.println("Communication to LoRaBEE successful.");
 | 
			
		||||
  }
 | 
			
		||||
  else
 | 
			
		||||
  {
 | 
			
		||||
    debugSerial.println("OTAA Setup failed!");
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void setup() {
 | 
			
		||||
  //Power up the LoRaBEE
 | 
			
		||||
  pinMode(ENABLE_PIN_IO, OUTPUT); // ONE
 | 
			
		||||
  digitalWrite(ENABLE_PIN_IO, HIGH); // ONE
 | 
			
		||||
  pinMode(LED_RED, OUTPUT);
 | 
			
		||||
  pinMode(LED_GREEN, OUTPUT);
 | 
			
		||||
  pinMode(LED_BLUE, OUTPUT);
 | 
			
		||||
  delay(3000);
 | 
			
		||||
 | 
			
		||||
  while ((!SerialUSB) && (millis() < 10000)){
 | 
			
		||||
    // Wait 10 seconds for the Serial Monitor
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  //Set baud rate
 | 
			
		||||
  debugSerial.begin(57600);
 | 
			
		||||
  loraSerial.begin(LoRaBee.getDefaultBaudRate());
 | 
			
		||||
 | 
			
		||||
  // Debug output from LoRaBee
 | 
			
		||||
  // LoRaBee.setDiag(debugSerial); // optional
 | 
			
		||||
 | 
			
		||||
  //connect to the LoRa Network
 | 
			
		||||
  setupLoRa();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void setupLoRa(){
 | 
			
		||||
  // ABP
 | 
			
		||||
//  setupLoRaABP();
 | 
			
		||||
  // OTAA
 | 
			
		||||
  setupLoRaOTAA();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void sendPacket(String packet){
 | 
			
		||||
  switch (LoRaBee.sendReqAck(1, (uint8_t*)packet.c_str(), packet.length(), 8))
 | 
			
		||||
    {
 | 
			
		||||
    case NoError:
 | 
			
		||||
      debugSerial.println("Successful transmission.");
 | 
			
		||||
      break;
 | 
			
		||||
    case NoResponse:
 | 
			
		||||
      debugSerial.println("There was no response from the device.");
 | 
			
		||||
      setupLoRa();
 | 
			
		||||
      break;
 | 
			
		||||
    case Timeout:
 | 
			
		||||
      debugSerial.println("Connection timed-out. Check your serial connection to the device! Sleeping for 20sec.");
 | 
			
		||||
      delay(20000);
 | 
			
		||||
      break;
 | 
			
		||||
    case PayloadSizeError:
 | 
			
		||||
      debugSerial.println("The size of the payload is greater than allowed. Transmission failed!");
 | 
			
		||||
      break;
 | 
			
		||||
    case InternalError:
 | 
			
		||||
      debugSerial.println("Oh No! This shouldn't happen. Something is really wrong! Try restarting the device!\r\nThe network connection will reset.");
 | 
			
		||||
      setupLoRa();
 | 
			
		||||
      break;
 | 
			
		||||
    case Busy:
 | 
			
		||||
      debugSerial.println("The device is busy. Sleeping for 10 extra seconds.");
 | 
			
		||||
      delay(10000);
 | 
			
		||||
      break;
 | 
			
		||||
    case NetworkFatalError:
 | 
			
		||||
      debugSerial.println("There is a non-recoverable error with the network connection. You should re-connect.\r\nThe network connection will reset.");
 | 
			
		||||
      setupLoRa();
 | 
			
		||||
      break;
 | 
			
		||||
    case NotConnected:
 | 
			
		||||
      debugSerial.println("The device is not connected to the network. Please connect to the network before attempting to send data.\r\nThe network connection will reset.");
 | 
			
		||||
      setupLoRa();
 | 
			
		||||
      break;
 | 
			
		||||
    case NoAcknowledgment:
 | 
			
		||||
      debugSerial.println("There was no acknowledgment sent back!");
 | 
			
		||||
      // When you this message you are probaly out of range of the network.
 | 
			
		||||
      break;
 | 
			
		||||
    default:
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void loop() {
 | 
			
		||||
  // put your main code here, to run repeatedly:
 | 
			
		||||
  String packet = "SODAQ";
 | 
			
		||||
  sendPacket(packet);
 | 
			
		||||
RED();
 | 
			
		||||
  delay(5000);
 | 
			
		||||
  CLEAR();
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										535
									
								
								Sodaq_RN2483.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										535
									
								
								Sodaq_RN2483.cpp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,535 @@
 | 
			
		|||
/*
 | 
			
		||||
* 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
 | 
			
		||||
* <http://www.gnu.org/licenses/>.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
#include "Sodaq_RN2483.h"
 | 
			
		||||
#include "StringLiterals.h"
 | 
			
		||||
#include "Utils.h"
 | 
			
		||||
 | 
			
		||||
#ifdef DEBUG
 | 
			
		||||
#define debugPrintLn(...) { if (this->diagStream) this->diagStream->println(__VA_ARGS__); }
 | 
			
		||||
#define debugPrint(...) { if (this->diagStream) this->diagStream->print(__VA_ARGS__); }
 | 
			
		||||
#warning "Debug mode is ON"
 | 
			
		||||
#else
 | 
			
		||||
#define debugPrintLn(...)
 | 
			
		||||
#define debugPrint(...)
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
// Structure for mapping error response strings and error codes.
 | 
			
		||||
typedef struct StringEnumPair
 | 
			
		||||
{
 | 
			
		||||
    const char* stringValue;
 | 
			
		||||
    uint8_t enumValue;
 | 
			
		||||
} StringEnumPair_t;
 | 
			
		||||
 | 
			
		||||
Sodaq_RN2483 LoRaBee;
 | 
			
		||||
 | 
			
		||||
// Creates a new Sodaq_RN2483 instance.
 | 
			
		||||
Sodaq_RN2483::Sodaq_RN2483() :
 | 
			
		||||
        loraStream(0),
 | 
			
		||||
        diagStream(0),
 | 
			
		||||
        inputBufferSize(DEFAULT_INPUT_BUFFER_SIZE),
 | 
			
		||||
        receivedPayloadBufferSize(DEFAULT_RECEIVED_PAYLOAD_BUFFER_SIZE),
 | 
			
		||||
        packetReceived(false)
 | 
			
		||||
{
 | 
			
		||||
#ifdef USE_DYNAMIC_BUFFER
 | 
			
		||||
    this->isBufferInitialized = false;
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Takes care of the init tasks common to both initOTA() and initABP.
 | 
			
		||||
void Sodaq_RN2483::init(Stream& stream)
 | 
			
		||||
{
 | 
			
		||||
    debugPrintLn("[init]");
 | 
			
		||||
 | 
			
		||||
    this->loraStream = &stream;
 | 
			
		||||
 | 
			
		||||
#ifdef USE_DYNAMIC_BUFFER
 | 
			
		||||
    // make sure the buffers are only initialized once
 | 
			
		||||
    if (!isBufferInitialized) {
 | 
			
		||||
        this->inputBuffer = static_cast<char*>(malloc(this->inputBufferSize));
 | 
			
		||||
        this->receivedPayloadBuffer = static_cast<char*>(malloc(this->receivedPayloadBufferSize));
 | 
			
		||||
 | 
			
		||||
        isBufferInitialized = true;
 | 
			
		||||
    }
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Initializes the device and connects to the network using Over-The-Air Activation.
 | 
			
		||||
// Returns true on successful connection.
 | 
			
		||||
bool Sodaq_RN2483::initOTA(Stream& stream, const uint8_t devEUI[8], const uint8_t appEUI[8], const uint8_t appKey[16], bool adr)
 | 
			
		||||
{
 | 
			
		||||
    debugPrintLn("[initOTA]");
 | 
			
		||||
 | 
			
		||||
    init(stream);
 | 
			
		||||
 | 
			
		||||
    return resetDevice() &&
 | 
			
		||||
        setMacParam(STR_DEV_EUI, devEUI, 8) &&
 | 
			
		||||
        setMacParam(STR_APP_EUI, appEUI, 8) &&
 | 
			
		||||
        setMacParam(STR_APP_KEY, appKey, 16) &&
 | 
			
		||||
        setMacParam(STR_ADR, BOOL_TO_ONOFF(adr)) &&
 | 
			
		||||
        joinNetwork(STR_OTAA);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Initializes the device and connects to the network using Activation By Personalization.
 | 
			
		||||
// Returns true on successful connection.
 | 
			
		||||
bool Sodaq_RN2483::initABP(Stream& stream, const uint8_t devAddr[4], const uint8_t appSKey[16], const uint8_t nwkSKey[16], bool adr)
 | 
			
		||||
{
 | 
			
		||||
    debugPrintLn("[initABP]");
 | 
			
		||||
 | 
			
		||||
    init(stream);
 | 
			
		||||
 | 
			
		||||
    return resetDevice() &&
 | 
			
		||||
        setMacParam(STR_DEV_ADDR, devAddr, 4) &&
 | 
			
		||||
        setMacParam(STR_APP_SESSION_KEY, appSKey, 16) &&
 | 
			
		||||
        setMacParam(STR_NETWORK_SESSION_KEY, nwkSKey, 16) &&
 | 
			
		||||
        setMacParam(STR_ADR, BOOL_TO_ONOFF(adr)) &&
 | 
			
		||||
        joinNetwork(STR_ABP);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Sends the given payload without acknowledgement.
 | 
			
		||||
// Returns 0 (NoError) when transmission is successful or one of the MacTransmitErrorCodes otherwise.
 | 
			
		||||
uint8_t Sodaq_RN2483::send(uint8_t port, const uint8_t* payload, uint8_t size)
 | 
			
		||||
{
 | 
			
		||||
    debugPrintLn("[send]");
 | 
			
		||||
 | 
			
		||||
    return macTransmit(STR_UNCONFIRMED, port, payload, size);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Sends the given payload with acknowledgement.
 | 
			
		||||
// Returns 0 (NoError) when transmission is successful or one of the MacTransmitErrorCodes otherwise.
 | 
			
		||||
uint8_t Sodaq_RN2483::sendReqAck(uint8_t port, const uint8_t* payload,
 | 
			
		||||
        uint8_t size, uint8_t maxRetries)
 | 
			
		||||
{
 | 
			
		||||
    debugPrintLn("[sendReqAck]");
 | 
			
		||||
 | 
			
		||||
    if (!setMacParam(STR_RETRIES, maxRetries)) {
 | 
			
		||||
        // not a fatal error -just show a debug message
 | 
			
		||||
        debugPrintLn("[sendReqAck] Non-fatal error: setting number of retries failed.");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return macTransmit(STR_CONFIRMED, port, payload, size);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 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 Sodaq_RN2483::receive(uint8_t* buffer, uint16_t size,
 | 
			
		||||
        uint16_t payloadStartPosition)
 | 
			
		||||
{
 | 
			
		||||
    debugPrintLn("[receive]");
 | 
			
		||||
 | 
			
		||||
    if (!this->packetReceived) {
 | 
			
		||||
        debugPrintLn("[receive]: There is no packet received!");
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    uint16_t inputIndex = payloadStartPosition * 2; // payloadStartPosition is in bytes, not hex char pairs
 | 
			
		||||
    uint16_t outputIndex = 0;
 | 
			
		||||
 | 
			
		||||
    // check that the asked starting position is within bounds
 | 
			
		||||
    if (inputIndex >= this->receivedPayloadBufferSize) {
 | 
			
		||||
        debugPrintLn("[receive]: Out of bounds start position!");
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // stop at the first string termination char, or if output buffer is over, or if payload buffer is over
 | 
			
		||||
    while (outputIndex < size
 | 
			
		||||
            && inputIndex + 1 < this->receivedPayloadBufferSize
 | 
			
		||||
            && this->receivedPayloadBuffer[inputIndex] != 0
 | 
			
		||||
            && this->receivedPayloadBuffer[inputIndex + 1] != 0) {
 | 
			
		||||
        buffer[outputIndex] = HEX_PAIR_TO_BYTE(
 | 
			
		||||
                this->receivedPayloadBuffer[inputIndex],
 | 
			
		||||
                this->receivedPayloadBuffer[inputIndex + 1]);
 | 
			
		||||
 | 
			
		||||
        inputIndex += 2;
 | 
			
		||||
        outputIndex++;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Note: if the payload has an odd length, the last char is discarded
 | 
			
		||||
 | 
			
		||||
    buffer[outputIndex] = 0; // terminate the string
 | 
			
		||||
 | 
			
		||||
    debugPrintLn("[receive]: Done");
 | 
			
		||||
    return outputIndex;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 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 Sodaq_RN2483::readLn(char* buffer, uint16_t size, uint16_t start)
 | 
			
		||||
{
 | 
			
		||||
    int len = this->loraStream->readBytesUntil('\n', buffer + start, size);
 | 
			
		||||
    this->inputBuffer[start + len - 1] = 0; // bytes until \n always end with \r, so get rid of it (-1)
 | 
			
		||||
 | 
			
		||||
    return len;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 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 Sodaq_RN2483::expectString(const char* str, uint16_t timeout)
 | 
			
		||||
{
 | 
			
		||||
    debugPrint("[expectString] expecting "); debugPrint(str);
 | 
			
		||||
 | 
			
		||||
    unsigned long start = millis();
 | 
			
		||||
    while (millis() < start + timeout) {
 | 
			
		||||
        debugPrint(".");
 | 
			
		||||
 | 
			
		||||
        if (readLn() > 0) {
 | 
			
		||||
            debugPrint("("); debugPrint(this->inputBuffer); debugPrint(")");
 | 
			
		||||
 | 
			
		||||
            if (strstr(this->inputBuffer, str) != NULL) {
 | 
			
		||||
                debugPrintLn(" found a match!");
 | 
			
		||||
 | 
			
		||||
                return true;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool Sodaq_RN2483::expectOK()
 | 
			
		||||
{
 | 
			
		||||
    return expectString(STR_RESULT_OK);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Sends a reset command to the module and waits for the success response (or timeout).
 | 
			
		||||
// Returns true on success.
 | 
			
		||||
bool Sodaq_RN2483::resetDevice()
 | 
			
		||||
{
 | 
			
		||||
    debugPrintLn("[resetDevice]");
 | 
			
		||||
 | 
			
		||||
    this->loraStream->print(STR_CMD_RESET);
 | 
			
		||||
    this->loraStream->print(CRLF);
 | 
			
		||||
 | 
			
		||||
    return expectString(STR_DEVICE_TYPE);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Sends a join network command to the device and waits for the response (or timeout).
 | 
			
		||||
// Returns true on success.
 | 
			
		||||
bool Sodaq_RN2483::joinNetwork(const char* type)
 | 
			
		||||
{
 | 
			
		||||
    debugPrintLn("[joinNetwork]");
 | 
			
		||||
 | 
			
		||||
    this->loraStream->print(STR_CMD_JOIN);
 | 
			
		||||
    this->loraStream->print(type);
 | 
			
		||||
    this->loraStream->print(CRLF);
 | 
			
		||||
 | 
			
		||||
    return expectOK() && expectString(STR_ACCEPTED, 30000);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 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 Sodaq_RN2483::setMacParam(const char* paramName, const uint8_t* paramValue, uint16_t size)
 | 
			
		||||
{
 | 
			
		||||
    debugPrint("[setMacParam] "); debugPrint(paramName); debugPrint("= [array]");
 | 
			
		||||
 | 
			
		||||
    this->loraStream->print(STR_CMD_SET);
 | 
			
		||||
    this->loraStream->print(paramName);
 | 
			
		||||
 | 
			
		||||
    for (uint16_t i = 0; i < size; ++i) {
 | 
			
		||||
        this->loraStream->print(static_cast<char>(NIBBLE_TO_HEX_CHAR(HIGH_NIBBLE(paramValue[i]))));
 | 
			
		||||
        this->loraStream->print(static_cast<char>(NIBBLE_TO_HEX_CHAR(LOW_NIBBLE(paramValue[i]))));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    this->loraStream->print(CRLF);
 | 
			
		||||
 | 
			
		||||
    return expectOK();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 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 Sodaq_RN2483::setMacParam(const char* paramName, uint8_t paramValue)
 | 
			
		||||
{
 | 
			
		||||
    debugPrint("[setMacParam] ");
 | 
			
		||||
    debugPrint(paramName);
 | 
			
		||||
    debugPrint("= ");
 | 
			
		||||
    debugPrintLn(paramValue);
 | 
			
		||||
 | 
			
		||||
    this->loraStream->print(STR_CMD_SET);
 | 
			
		||||
    this->loraStream->print(paramName);
 | 
			
		||||
    this->loraStream->print(paramValue);
 | 
			
		||||
    this->loraStream->print(CRLF);
 | 
			
		||||
 | 
			
		||||
    return expectOK();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 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 Sodaq_RN2483::setMacParam(const char* paramName, const char* paramValue)
 | 
			
		||||
{
 | 
			
		||||
    debugPrint("[setMacParam] ");
 | 
			
		||||
    debugPrint(paramName);
 | 
			
		||||
    debugPrint("= ");
 | 
			
		||||
    debugPrintLn(paramValue);
 | 
			
		||||
 | 
			
		||||
    this->loraStream->print(STR_CMD_SET);
 | 
			
		||||
    this->loraStream->print(paramName);
 | 
			
		||||
    this->loraStream->print(paramValue);
 | 
			
		||||
    this->loraStream->print(CRLF);
 | 
			
		||||
 | 
			
		||||
    return expectOK();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Returns the enum that is mapped to the given "error" message.
 | 
			
		||||
uint8_t Sodaq_RN2483::lookupMacTransmitError(const char* error)
 | 
			
		||||
{
 | 
			
		||||
    debugPrint("[lookupMacTransmitError]: ");
 | 
			
		||||
    debugPrintLn(error);
 | 
			
		||||
 | 
			
		||||
    if (error[0] == 0) {
 | 
			
		||||
        debugPrintLn("[lookupMacTransmitError]: The string is empty!");
 | 
			
		||||
        return NoResponse;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    StringEnumPair_t errorTable[] =
 | 
			
		||||
    {
 | 
			
		||||
        { STR_RESULT_INVALID_PARAM, InternalError },
 | 
			
		||||
        { STR_RESULT_NOT_JOINED, NotConnected },
 | 
			
		||||
        { STR_RESULT_NO_FREE_CHANNEL, Busy },
 | 
			
		||||
        { STR_RESULT_SILENT, Busy },
 | 
			
		||||
        { STR_RESULT_FRAME_COUNTER_ERROR, NetworkFatalError },
 | 
			
		||||
        { STR_RESULT_BUSY, Busy },
 | 
			
		||||
        { STR_RESULT_MAC_PAUSED, InternalError },
 | 
			
		||||
        { STR_RESULT_INVALID_DATA_LEN, PayloadSizeError },
 | 
			
		||||
        { STR_RESULT_MAC_ERROR, NoAcknowledgment },
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    for (StringEnumPair_t * p = errorTable; p->stringValue != NULL; ++p) {
 | 
			
		||||
        if (strcmp(p->stringValue, error) == 0) {
 | 
			
		||||
            debugPrint("[lookupMacTransmitError]: found ");
 | 
			
		||||
            debugPrintLn(p->enumValue);
 | 
			
		||||
 | 
			
		||||
            return p->enumValue;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    debugPrintLn("[lookupMacTransmitError]: not found!");
 | 
			
		||||
    return NoResponse;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
uint8_t Sodaq_RN2483::macTransmit(const char* type, uint8_t port, const uint8_t* payload, uint8_t size)
 | 
			
		||||
{
 | 
			
		||||
    debugPrintLn("[macTransmit]");
 | 
			
		||||
 | 
			
		||||
    this->loraStream->print(STR_CMD_MAC_TX);
 | 
			
		||||
    this->loraStream->print(type);
 | 
			
		||||
    this->loraStream->print(port);
 | 
			
		||||
    this->loraStream->print(" ");
 | 
			
		||||
 | 
			
		||||
    for (int i = 0; i < size; ++i) {
 | 
			
		||||
        this->loraStream->print(static_cast<char>(NIBBLE_TO_HEX_CHAR(HIGH_NIBBLE(payload[i]))));
 | 
			
		||||
        this->loraStream->print(static_cast<char>(NIBBLE_TO_HEX_CHAR(LOW_NIBBLE(payload[i]))));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    this->loraStream->print(CRLF);
 | 
			
		||||
 | 
			
		||||
    if (!expectOK()) {
 | 
			
		||||
        return lookupMacTransmitError(this->inputBuffer); // inputBuffer still has the last line read
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    this->packetReceived = false; // prepare for receiving a new packet
 | 
			
		||||
 | 
			
		||||
    debugPrint("Waiting for server response");
 | 
			
		||||
    unsigned long timeout = millis() + RECEIVE_TIMEOUT; // hard timeout
 | 
			
		||||
    while (millis() < timeout) {
 | 
			
		||||
        debugPrint(".");
 | 
			
		||||
        if (readLn() > 0) {
 | 
			
		||||
            debugPrintLn(".");debugPrint("(");debugPrint(this->inputBuffer);debugPrintLn(")");
 | 
			
		||||
 | 
			
		||||
            if (strstr(this->inputBuffer, " ") != NULL) // to avoid double delimiter search
 | 
			
		||||
            {
 | 
			
		||||
                // there is a splittable line -only case known is mac_rx
 | 
			
		||||
                debugPrintLn("Splittable response found");
 | 
			
		||||
                return onMacRX();
 | 
			
		||||
            } else if (strstr(this->inputBuffer, STR_RESULT_MAC_TX_OK)) {
 | 
			
		||||
                // done
 | 
			
		||||
                debugPrintLn("Received mac_tx_ok");
 | 
			
		||||
                return NoError;
 | 
			
		||||
            } else {
 | 
			
		||||
                // lookup the error message
 | 
			
		||||
                debugPrintLn("Some other string received (error)");
 | 
			
		||||
                return lookupMacTransmitError(this->inputBuffer);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    debugPrintLn("Timed-out waiting for a response!");
 | 
			
		||||
    return Timeout;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 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 Sodaq_RN2483::onMacRX()
 | 
			
		||||
{
 | 
			
		||||
    debugPrintLn("[onMacRX]");
 | 
			
		||||
 | 
			
		||||
    // parse inputbuffer, put payload into packet buffer
 | 
			
		||||
    char* token = strtok(this->inputBuffer, " ");
 | 
			
		||||
 | 
			
		||||
    // sanity check
 | 
			
		||||
    if (strcmp(token, STR_RESULT_MAC_RX) != 0) {
 | 
			
		||||
        debugPrintLn("[onMacRX]: mac_rx keyword not found!");
 | 
			
		||||
        return InternalError;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // port
 | 
			
		||||
    token = strtok(NULL, " ");
 | 
			
		||||
 | 
			
		||||
    // payload
 | 
			
		||||
    token = strtok(NULL, " "); // until end of string
 | 
			
		||||
 | 
			
		||||
    uint16_t len = strlen(token) + 1; // include termination char
 | 
			
		||||
    memcpy(this->receivedPayloadBuffer, token, len <= this->receivedPayloadBufferSize ? len : this->receivedPayloadBufferSize);
 | 
			
		||||
 | 
			
		||||
    this->packetReceived = true; // enable receive() again
 | 
			
		||||
    return NoError;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#ifdef DEBUG
 | 
			
		||||
// Provides a quick test of several methods as a pseudo-unit test.
 | 
			
		||||
void Sodaq_RN2483::runTestSequence(Stream& stream)
 | 
			
		||||
{
 | 
			
		||||
    debugPrint("free ram: ");
 | 
			
		||||
    debugPrintLn(freeRam());
 | 
			
		||||
 | 
			
		||||
    init(stream);
 | 
			
		||||
 | 
			
		||||
    this->loraStream = &stream;
 | 
			
		||||
    this->diagStream = &stream;
 | 
			
		||||
 | 
			
		||||
    // expectString
 | 
			
		||||
    debugPrintLn("write \"testString\" and then CRLF");
 | 
			
		||||
    if (expectString("testString", 5000)) {
 | 
			
		||||
        debugPrintLn("[expectString] positive case works!");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    debugPrintLn("");
 | 
			
		||||
    debugPrintLn("write something other than \"testString\" and then CRLF");
 | 
			
		||||
    if (!expectString("testString", 5000)) {
 | 
			
		||||
        debugPrintLn("[expectString] negative case works!");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    debugPrint("free ram: ");
 | 
			
		||||
    debugPrintLn(freeRam());
 | 
			
		||||
 | 
			
		||||
    // setMacParam(array)
 | 
			
		||||
    debugPrintLn("");
 | 
			
		||||
    debugPrintLn("");
 | 
			
		||||
    uint8_t testValue[] = {0x01, 0x02, 0xDE, 0xAD, 0xBE, 0xEF};
 | 
			
		||||
    setMacParam("testParam ", testValue, ARRAY_SIZE(testValue));
 | 
			
		||||
 | 
			
		||||
    // macTransmit
 | 
			
		||||
    debugPrintLn("");
 | 
			
		||||
    debugPrintLn("");
 | 
			
		||||
    uint8_t testValue2[] = {0x01, 0x02, 0xDE, 0xAD, 0xBE, 0xEF};
 | 
			
		||||
    macTransmit(STR_CONFIRMED, 1, testValue2, ARRAY_SIZE(testValue2));
 | 
			
		||||
 | 
			
		||||
    debugPrint("free ram: ");
 | 
			
		||||
    debugPrintLn(freeRam());
 | 
			
		||||
 | 
			
		||||
    // receive
 | 
			
		||||
    debugPrintLn("");
 | 
			
		||||
    debugPrintLn("==== receive");
 | 
			
		||||
    char mockResult[] = "303132333435363738";
 | 
			
		||||
    memcpy(this->receivedPayloadBuffer, mockResult, strlen(mockResult) + 1);
 | 
			
		||||
    uint8_t payload[64];
 | 
			
		||||
    debugPrintLn("* without having received packet");
 | 
			
		||||
    uint8_t length = receive(payload, sizeof(payload));
 | 
			
		||||
    debugPrintLn(reinterpret_cast<char*>(payload));
 | 
			
		||||
    debugPrint("Length: ");
 | 
			
		||||
    debugPrintLn(length);
 | 
			
		||||
    debugPrintLn("* having received packet");
 | 
			
		||||
    this->packetReceived = true;
 | 
			
		||||
    length = receive(payload, sizeof(payload));
 | 
			
		||||
    debugPrintLn(reinterpret_cast<char*>(payload));
 | 
			
		||||
    debugPrint("Length: ");
 | 
			
		||||
    debugPrintLn(length);
 | 
			
		||||
 | 
			
		||||
    // onMacRX
 | 
			
		||||
    debugPrintLn("");
 | 
			
		||||
    debugPrintLn("==== onMacRX");
 | 
			
		||||
    char mockRx[] = "mac_rx 1 303132333435363738";
 | 
			
		||||
    memcpy(this->inputBuffer, mockRx, strlen(mockRx) + 1);
 | 
			
		||||
    this->packetReceived = false;// reset
 | 
			
		||||
    debugPrint("Input buffer now is: ");
 | 
			
		||||
    debugPrintLn(this->inputBuffer);
 | 
			
		||||
    debugPrint("onMacRX result code: ");
 | 
			
		||||
    debugPrintLn(onMacRX());
 | 
			
		||||
    uint8_t payload2[64];
 | 
			
		||||
    if (receive(payload2, sizeof(payload2)) != 9) {
 | 
			
		||||
        debugPrintLn("len is wrong!");
 | 
			
		||||
    }
 | 
			
		||||
    debugPrintLn(reinterpret_cast<char*>(payload2));
 | 
			
		||||
    if (receive(payload2, sizeof(payload2), 2) != 7) {
 | 
			
		||||
        debugPrintLn("len is wrong!");
 | 
			
		||||
    }
 | 
			
		||||
    debugPrintLn(reinterpret_cast<char*>(payload2));
 | 
			
		||||
    if (receive(payload2, sizeof(payload2), 3) != 6) {
 | 
			
		||||
        debugPrintLn("len is wrong!");
 | 
			
		||||
    }
 | 
			
		||||
    debugPrintLn(reinterpret_cast<char*>(payload2));
 | 
			
		||||
 | 
			
		||||
    debugPrint("free ram: ");
 | 
			
		||||
    debugPrintLn(freeRam());
 | 
			
		||||
 | 
			
		||||
    // lookup error
 | 
			
		||||
    debugPrintLn("");
 | 
			
		||||
    debugPrintLn("");
 | 
			
		||||
 | 
			
		||||
    debugPrint("empty string: ");
 | 
			
		||||
    debugPrintLn((lookupMacTransmitError("") == NoResponse) ? "passed" : "wrong");
 | 
			
		||||
 | 
			
		||||
    debugPrint("\"random\": ");
 | 
			
		||||
    debugPrintLn((lookupMacTransmitError("random") == NoResponse) ? "passed" : "wrong");
 | 
			
		||||
 | 
			
		||||
    debugPrint("\"invalid_param\": ");
 | 
			
		||||
    debugPrintLn((lookupMacTransmitError("invalid_param") == InternalError) ? "passed" : "wrong");
 | 
			
		||||
 | 
			
		||||
    debugPrint("\"not_joined\": ");
 | 
			
		||||
    debugPrintLn((lookupMacTransmitError("not_joined") == NotConnected) ? "passed" : "wrong");
 | 
			
		||||
 | 
			
		||||
    debugPrint("\"busy\": ");
 | 
			
		||||
    debugPrintLn((lookupMacTransmitError("busy") == Busy) ? "passed" : "wrong");
 | 
			
		||||
 | 
			
		||||
    debugPrint("\"invalid_param\": ");
 | 
			
		||||
    debugPrintLn((lookupMacTransmitError("invalid_param") == InternalError) ? "passed" : "wrong");
 | 
			
		||||
 | 
			
		||||
    debugPrint("free ram: ");
 | 
			
		||||
    debugPrintLn(freeRam());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int Sodaq_RN2483::freeRam()
 | 
			
		||||
{
 | 
			
		||||
    extern int __heap_start;
 | 
			
		||||
    extern int *__brkval;
 | 
			
		||||
    int v;
 | 
			
		||||
    return (int)&v - (__brkval == 0 ? (int)&__heap_start : (int)__brkval);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										199
									
								
								Sodaq_RN2483.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										199
									
								
								Sodaq_RN2483.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,199 @@
 | 
			
		|||
/*
 | 
			
		||||
* 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
 | 
			
		||||
* <http://www.gnu.org/licenses/>.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
#ifndef _Sodaq_RN2483_h
 | 
			
		||||
#define _Sodaq_RN2483_h
 | 
			
		||||
 | 
			
		||||
#include <Arduino.h>
 | 
			
		||||
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
#include <Stream.h>
 | 
			
		||||
#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
 | 
			
		||||
							
								
								
									
										63
									
								
								StringLiterals.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								StringLiterals.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,63 @@
 | 
			
		|||
/*
 | 
			
		||||
* Copyright (c) 2015 SODAQ. All rights reserved.
 | 
			
		||||
*
 | 
			
		||||
* This file is part of MicrochipLoRaWAN.
 | 
			
		||||
*
 | 
			
		||||
* MicrochipLoRaWAN 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.
 | 
			
		||||
*
 | 
			
		||||
* MicrochipLoRaWAN 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 MicrochipLoRaWAN.  If not, see
 | 
			
		||||
* <http://www.gnu.org/licenses/>.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
#ifndef _STRINGLITERALS_h
 | 
			
		||||
#define _STRINGLITERALS_h
 | 
			
		||||
 | 
			
		||||
#define CRLF "\r\n"
 | 
			
		||||
 | 
			
		||||
#define STR_RESULT_OK "ok"
 | 
			
		||||
#define STR_RESULT_INVALID_PARAM "invalid_param"
 | 
			
		||||
#define STR_RESULT_MAC_ERROR "mac_err"
 | 
			
		||||
#define STR_RESULT_MAC_RX "mac_rx"
 | 
			
		||||
#define STR_RESULT_MAC_TX_OK "mac_tx_ok"
 | 
			
		||||
 | 
			
		||||
#define STR_RESULT_NOT_JOINED "not_joined"
 | 
			
		||||
#define STR_RESULT_NO_FREE_CHANNEL "no_free_ch"
 | 
			
		||||
#define STR_RESULT_SILENT "silent"
 | 
			
		||||
#define STR_RESULT_FRAME_COUNTER_ERROR "frame_counter_err_rejoin_needed"
 | 
			
		||||
#define STR_RESULT_BUSY "busy"
 | 
			
		||||
#define STR_RESULT_MAC_PAUSED "mac_paused"
 | 
			
		||||
#define STR_RESULT_INVALID_DATA_LEN "invalid_data_len"
 | 
			
		||||
 | 
			
		||||
#define STR_CMD_RESET "sys reset"
 | 
			
		||||
#define STR_DEVICE_TYPE "RN2483"
 | 
			
		||||
 | 
			
		||||
#define STR_CMD_SET "mac set "
 | 
			
		||||
#define STR_RETRIES "retx "
 | 
			
		||||
#define STR_DEV_ADDR "devaddr "
 | 
			
		||||
#define STR_APP_SESSION_KEY "appskey "
 | 
			
		||||
#define STR_NETWORK_SESSION_KEY "nwkskey "
 | 
			
		||||
#define STR_DEV_EUI "deveui "
 | 
			
		||||
#define STR_APP_EUI "appeui "
 | 
			
		||||
#define STR_APP_KEY "appkey "
 | 
			
		||||
#define STR_ADR "adr "
 | 
			
		||||
 | 
			
		||||
#define STR_CMD_JOIN "mac join "
 | 
			
		||||
#define STR_OTAA "otaa"
 | 
			
		||||
#define STR_ABP "abp"
 | 
			
		||||
#define STR_ACCEPTED "accepted"
 | 
			
		||||
 | 
			
		||||
#define STR_CMD_MAC_TX "mac tx "
 | 
			
		||||
#define STR_CONFIRMED "cnf "
 | 
			
		||||
#define STR_UNCONFIRMED "uncnf "
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										63
									
								
								Switchable_Device.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								Switchable_Device.cpp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,63 @@
 | 
			
		|||
/*
 | 
			
		||||
* Copyright (c) 2015 SODAQ. All rights reserved.
 | 
			
		||||
*
 | 
			
		||||
* This file is part of MicrochipLoRaWAN.
 | 
			
		||||
*
 | 
			
		||||
* MicrochipLoRaWAN 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.
 | 
			
		||||
*
 | 
			
		||||
* MicrochipLoRaWAN 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 MicrochipLoRaWAN.  If not, see
 | 
			
		||||
* <http://www.gnu.org/licenses/>.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
#include "Switchable_Device.h"
 | 
			
		||||
 | 
			
		||||
SwitchableDevice::SwitchableDevice()
 | 
			
		||||
{
 | 
			
		||||
	clearSwitchMethods();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void SwitchableDevice::setOnMethod(voidFuncPtr onMethod)
 | 
			
		||||
{
 | 
			
		||||
	_onMethod = onMethod;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void SwitchableDevice::setOffMethod(voidFuncPtr offMethod)
 | 
			
		||||
{
 | 
			
		||||
	_offMethod = offMethod;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void SwitchableDevice::setSwitchMethods(voidFuncPtr onMethod, voidFuncPtr offMethod)
 | 
			
		||||
{
 | 
			
		||||
	_onMethod = onMethod;
 | 
			
		||||
	_offMethod = offMethod;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void SwitchableDevice::clearSwitchMethods()
 | 
			
		||||
{
 | 
			
		||||
	_onMethod = _offMethod = 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void SwitchableDevice::on()
 | 
			
		||||
{
 | 
			
		||||
	if (_onMethod != 0)
 | 
			
		||||
	{
 | 
			
		||||
		_onMethod();
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void SwitchableDevice::off()
 | 
			
		||||
{
 | 
			
		||||
	if (_offMethod != 0)
 | 
			
		||||
	{
 | 
			
		||||
		_offMethod();
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										24
									
								
								Switchable_Device.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								Switchable_Device.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,24 @@
 | 
			
		|||
#ifndef SWITCHABLE_DEVICE_H
 | 
			
		||||
#define SWITCHABLE_DEVICE_H
 | 
			
		||||
 | 
			
		||||
typedef void(*voidFuncPtr)(void); 
 | 
			
		||||
 | 
			
		||||
class SwitchableDevice {
 | 
			
		||||
private:
 | 
			
		||||
  voidFuncPtr _onMethod;
 | 
			
		||||
  voidFuncPtr _offMethod;
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
  SwitchableDevice();
 | 
			
		||||
 | 
			
		||||
  void setOnMethod(voidFuncPtr onMethod);
 | 
			
		||||
  void setOffMethod(voidFuncPtr offMethod);
 | 
			
		||||
 | 
			
		||||
  void setSwitchMethods(voidFuncPtr onMethod, voidFuncPtr offMethod);
 | 
			
		||||
  void clearSwitchMethods();
 | 
			
		||||
 | 
			
		||||
  void on();
 | 
			
		||||
  void off();
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif // SWITCHABLE_DEVICE_H
 | 
			
		||||
							
								
								
									
										34
									
								
								Utils.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								Utils.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,34 @@
 | 
			
		|||
/*
 | 
			
		||||
* Copyright (c) 2015 SODAQ. All rights reserved.
 | 
			
		||||
*
 | 
			
		||||
* This file is part of MicrochipLoRaWAN.
 | 
			
		||||
*
 | 
			
		||||
* MicrochipLoRaWAN 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.
 | 
			
		||||
*
 | 
			
		||||
* MicrochipLoRaWAN 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 MicrochipLoRaWAN.  If not, see
 | 
			
		||||
* <http://www.gnu.org/licenses/>.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
#ifndef _UTILS_h
 | 
			
		||||
#define _UTILS_h
 | 
			
		||||
 | 
			
		||||
#define BOOL_TO_ONOFF(b) (b ? "on" : "off")
 | 
			
		||||
#define NIBBLE_TO_HEX_CHAR(i) ((i <= 9) ? ('0' + i) : ('A' - 10 + i))
 | 
			
		||||
#define HIGH_NIBBLE(i) ((i >> 4) & 0x0F)
 | 
			
		||||
#define LOW_NIBBLE(i) (i & 0x0F)
 | 
			
		||||
 | 
			
		||||
#define HEX_CHAR_TO_NIBBLE(c) ((c >= 'A') ? (c - 'A' + 0x0A) : (c - '0'))
 | 
			
		||||
#define HEX_PAIR_TO_BYTE(h, l) ((HEX_CHAR_TO_NIBBLE(h) << 4) + HEX_CHAR_TO_NIBBLE(l))
 | 
			
		||||
 | 
			
		||||
#define ARRAY_SIZE(a) (sizeof(a)/sizeof(a[0]))
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue