rn2903: Initial implementation; C; C++ wraps C; examples

This requires a new MRAA with UART sendbreak support.

Signed-off-by: Jon Trulson <jtrulson@ics.com>
This commit is contained in:
Jon Trulson
2017-04-28 18:33:34 -06:00
parent c78da687d4
commit 21a1860ec2
26 changed files with 4918 additions and 0 deletions

View File

@ -0,0 +1,8 @@
upm_mixed_module_init (NAME rn2903
DESCRIPTION "LoRaWAN transceiver"
C_HDR rn2903.h rn2903_defs.h
C_SRC rn2903.c
CPP_HDR rn2903.hpp
CPP_SRC rn2903.cxx
CPP_WRAPS_C
REQUIRES mraa utilities-c)

View File

@ -0,0 +1,22 @@
%module javaupm_rn2903
%include "../upm.i"
%include "std_string.i"
%include "stdint.i"
%include "typemaps.i"
%include "rn2903_defs.h"
%include "rn2903.hpp"
%{
#include "rn2903.hpp"
%}
%pragma(java) jniclasscode=%{
static {
try {
System.loadLibrary("javaupm_rn2903");
} catch (UnsatisfiedLinkError e) {
System.err.println("Native code library failed to load. \n" + e);
System.exit(1);
}
}
%}

View File

@ -0,0 +1,9 @@
%module jsupm_rn2903
%include "../upm.i"
%include "std_string.i"
%include "rn2903_defs.h"
%include "rn2903.hpp"
%{
#include "rn2903.hpp"
%}

13
src/rn2903/pyupm_rn2903.i Normal file
View File

@ -0,0 +1,13 @@
// Include doxygen-generated documentation
%include "pyupm_doxy2swig.i"
%module pyupm_rn2903
%include "../upm.i"
%include "std_string.i"
%feature("autodoc", "3");
%include "rn2903_defs.h"
%include "rn2903.hpp"
%{
#include "rn2903.hpp"
%}

1163
src/rn2903/rn2903.c Normal file

File diff suppressed because it is too large Load Diff

334
src/rn2903/rn2903.cxx Normal file
View File

@ -0,0 +1,334 @@
/*
* Author: Jon Trulson <jtrulson@ics.com>
* Copyright (c) 2017 Intel Corporation.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in 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:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* 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 AUTHORS 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 IN THE SOFTWARE.
*/
#include <iostream>
#include <stdexcept>
#include <string.h>
#include "rn2903.hpp"
using namespace upm;
using namespace std;
RN2903::RN2903(unsigned int uart, unsigned int baudrate) :
m_rn2903(rn2903_init(uart, baudrate))
{
if (!m_rn2903)
throw std::runtime_error(string(__FUNCTION__)
+ ": rn2903_init() failed");
}
RN2903::RN2903(string uart_path, unsigned int baudrate) :
m_rn2903(rn2903_init_tty(uart_path.c_str(), baudrate))
{
if (!m_rn2903)
throw std::runtime_error(string(__FUNCTION__)
+ ": rn2903_init_tty() failed");
}
RN2903::~RN2903()
{
rn2903_close(m_rn2903);
}
std::string RN2903::read(int size)
{
char buffer[size];
int rv;
if ((rv = rn2903_read(m_rn2903, buffer, (size_t)size)) < 0)
throw std::runtime_error(string(__FUNCTION__)
+ ": rn2903_read() failed");
return string(buffer, rv);
}
int RN2903::write(std::string buffer)
{
int rv;
if ((rv = rn2903_write(m_rn2903, (char*)buffer.data(),
buffer.size())) < 0)
throw std::runtime_error(string(__FUNCTION__)
+ ": rn2903_write() failed");
return rv;
}
void RN2903::setResponseWaitTime(unsigned int wait_time)
{
rn2903_set_response_wait_time(m_rn2903, wait_time);
}
void RN2903::setResponse2WaitTime(unsigned int wait_time)
{
rn2903_set_response2_wait_time(m_rn2903, wait_time);
}
bool RN2903::dataAvailable(unsigned int millis)
{
return rn2903_data_available(m_rn2903, millis);
}
void RN2903::drain()
{
rn2903_drain(m_rn2903);
return;
}
RN2903_RESPONSE_T RN2903::command(const std::string cmd)
{
return rn2903_command(m_rn2903, cmd.c_str());
}
RN2903_RESPONSE_T RN2903::commandWithArg(const std::string cmd,
const std::string arg)
{
return rn2903_command_with_arg(m_rn2903, cmd.c_str(), arg.c_str());
}
RN2903_RESPONSE_T RN2903::waitForResponse(int wait_ms)
{
return rn2903_waitfor_response(m_rn2903, wait_ms);
}
std::string RN2903::getResponse()
{
return string(rn2903_get_response(m_rn2903),
rn2903_get_response_len(m_rn2903));
}
int RN2903::getResponseLen()
{
return rn2903_get_response_len(m_rn2903);
}
void RN2903::setDeviceEUI(const std::string str)
{
if (rn2903_set_device_eui(m_rn2903, str.c_str()))
throw std::runtime_error(string(__FUNCTION__)
+ ": rn2903_set_device_eui() failed");
}
void RN2903::getDeviceEUI()
{
if (rn2903_get_device_eui(m_rn2903))
throw std::runtime_error(string(__FUNCTION__)
+ ": rn2903_get_device_eui() failed");
}
void RN2903::setNetworkSessionKey(const std::string str)
{
if (rn2903_set_network_session_key(m_rn2903, str.c_str()))
throw std::runtime_error(string(__FUNCTION__)
+ ": rn2903_set_network_session_key() failed");
}
void RN2903::setApplicationSessionKey(const std::string str)
{
if (rn2903_set_application_session_key(m_rn2903, str.c_str()))
throw std::runtime_error(string(__FUNCTION__)
+ ": rn2903_set_application_session_key() failed");
}
void RN2903::setApplicationEUI(const std::string str)
{
if (rn2903_set_application_eui(m_rn2903, str.c_str()))
throw std::runtime_error(string(__FUNCTION__)
+ ": rn2903_set_application_eui() failed");
}
void RN2903::getApplicationEUI()
{
if (rn2903_get_application_eui(m_rn2903))
throw std::runtime_error(string(__FUNCTION__)
+ ": rn2903_get_application_eui() failed");
}
void RN2903::setApplicationKey(const std::string str)
{
if (rn2903_set_application_key(m_rn2903, str.c_str()))
throw std::runtime_error(string(__FUNCTION__)
+ ": rn2903_set_application_key() failed");
}
void RN2903::getApplicationKey()
{
if (rn2903_get_application_key(m_rn2903))
throw std::runtime_error(string(__FUNCTION__)
+ ": rn2903_get_application_key() failed");
}
void RN2903::setDeviceAddr(const std::string str)
{
if (rn2903_set_device_addr(m_rn2903, str.c_str()))
throw std::runtime_error(string(__FUNCTION__)
+ ": rn2903_set_device_addr() failed");
}
void RN2903::getDeviceAddr()
{
if (rn2903_get_device_addr(m_rn2903))
throw std::runtime_error(string(__FUNCTION__)
+ ": rn2903_get_device_addr() failed");
}
std::string RN2903::toHex(const std::string src)
{
const char *buf = rn2903_to_hex(m_rn2903, src.c_str(), src.size());
if (!buf)
return string("");
else
return string(buf);
}
std::string RN2903::fromHex(const std::string src)
{
const char *buf = rn2903_from_hex(m_rn2903, src.c_str());
if (!buf)
return string("");
else
return string(buf);
}
RN2903_JOIN_STATUS_T RN2903::join(RN2903_JOIN_TYPE_T type)
{
return rn2903_join(m_rn2903, type);
}
RN2903_MAC_TX_STATUS_T RN2903::macTx(RN2903_MAC_MSG_TYPE_T type, int port,
std::string payload)
{
return rn2903_mac_tx(m_rn2903, type, port, payload.c_str());
}
RN2903_RESPONSE_T RN2903::radioTx(const std::string payload)
{
return rn2903_radio_tx(m_rn2903, payload.c_str());
}
RN2903_RESPONSE_T RN2903::radioRx(int window_size)
{
return rn2903_radio_rx(m_rn2903, window_size);
}
std::string RN2903::getHardwareEUI()
{
return string(rn2903_get_hardware_eui(m_rn2903));
}
void RN2903::updateMacStatus()
{
if (rn2903_update_mac_status(m_rn2903))
throw std::runtime_error(string(__FUNCTION__)
+ ": rn2903_update_mac_status() failed");
}
int RN2903::getMacStatusWord()
{
return int(rn2903_get_mac_status_word(m_rn2903));
}
RN2903_MAC_STATUS_T RN2903::getMacStatus()
{
return rn2903_get_mac_status(m_rn2903);
}
void RN2903::macSave()
{
if (rn2903_mac_save(m_rn2903))
throw std::runtime_error(string(__FUNCTION__)
+ ": rn2903_mac_save() failed");
}
void RN2903::macPause()
{
if (rn2903_mac_pause(m_rn2903))
throw std::runtime_error(string(__FUNCTION__)
+ ": rn2903_mac_pause() failed");
}
void RN2903::macResume()
{
if (rn2903_mac_resume(m_rn2903))
throw std::runtime_error(string(__FUNCTION__)
+ ": rn2903_mac_resume() failed");
}
void RN2903::reset()
{
if (rn2903_reset(m_rn2903))
throw std::runtime_error(string(__FUNCTION__)
+ ": rn2903_reset() failed");
}
void RN2903::macSetBattery(int level)
{
if (rn2903_mac_set_battery(m_rn2903, level))
throw std::runtime_error(string(__FUNCTION__)
+ ": rn2903_mac_set_battery() failed");
}
void RN2903::setDebug(bool enable)
{
rn2903_set_debug(m_rn2903, enable);
}
void RN2903::setBaudrate(unsigned int baudrate)
{
if (rn2903_set_baudrate(m_rn2903, baudrate))
throw std::runtime_error(string(__FUNCTION__)
+ ": rn2903_set_baudrate() failed");
}
void RN2903::setFlowControl(RN2903_FLOW_CONTROL_T fc)
{
if (rn2903_set_flow_control(m_rn2903, fc))
throw std::runtime_error(string(__FUNCTION__)
+ ": rn2903_set_flow_control() failed");
}
bool RN2903::find(const std::string str)
{
return rn2903_find(m_rn2903, str.c_str());
}
std::string RN2903::getRadioRxPayload()
{
const char *payload = rn2903_get_radio_rx_payload(m_rn2903);
if (!payload)
return string("");
else
return string(payload);
}
bool RN2903::autobaud(int retries)
{
return rn2903_autobaud(m_rn2903, retries);
}

718
src/rn2903/rn2903.h Normal file
View File

@ -0,0 +1,718 @@
/*
* Author: Jon Trulson <jtrulson@ics.com>
* Copyright (c) 2017 Intel Corporation.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in 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:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* 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 AUTHORS 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 IN THE SOFTWARE.
*/
#pragma once
#include <stdint.h>
#include <stdlib.h>
#include <unistd.h>
#include <upm.h>
#include <mraa/uart.h>
#include "rn2903_defs.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @file rn2903.h
* @library rn2903
* @brief Generic API for the Microchip RN2903 LoRa Radio
*
*/
/**
* Device context
*/
typedef struct _rn2903_context {
mraa_uart_context uart;
// store the baudrate
int baudrate;
// response data buffer, stripped of CR/LF
char resp_data[RN2903_MAX_BUFFER];
// length of response data
size_t resp_len;
// these are allocated buffers we use manage and reuse
// internally to store conversions from/to hex and back
char *to_hex_buf;
char *from_hex_buf;
// maximum time to wait for a response after a command is
// submitted
int cmd_resp_wait_ms;
// maximum time to wait for a second response after a command is
// submitted
int cmd_resp2_wait_ms;
// debugging output
bool debug;
// our hardware hex encoded EUI + terminating NULL
char hardware_eui[RN2903_MAX_HEX_EUI64 + 1];
// 16b mac status word
uint16_t mac_status_word;
// this is the mac_status bitfield of the mac status word
RN2903_MAC_STATUS_T mac_mac_status;
} *rn2903_context;
/**
* RN2903 Initializer for UART operation using a UART index
*
* @param uart Specify which uart to use
* @param baudrate Specify the baudrate to use. 57600 is the
* default baudrate of this device.
* @return an initialized device context on success, NULL on error
*/
rn2903_context rn2903_init(unsigned int uart, unsigned int baudrate);
/**
* RN2903 Initializer for UART operation using a filesystem tty
* path (eg. /dev/ttyUSB0)
*
* @param uart_tty character string representing a filesystem path to a
* serial tty device
* @param baudrate Specify the baudrate to use. 57600 is the
* default baudrate of this device.
* @return an initialized device context on success, NULL on error
*/
rn2903_context rn2903_init_tty(const char *uart_tty, unsigned int baudrate);
/**
* RN2903 sensor close function
*
* @param dev Device context
*/
void rn2903_close(rn2903_context dev);
/**
* Set the default time, in milliseconds, to wait for a response
* after sending a command. All commands return at least one
* response immediately after issuing the command. This delay
* sets the maximum amount of time to wait for it.
*
* @param dev Device context
* @param wait_ms The response delay to set, in milliseconds.
*/
void rn2903_set_response_wait_time(const rn2903_context dev,
unsigned int wait_ms);
/**
* Set the default time, in milliseconds, to wait for the second
* response data to arrive. Some commands will have a second
* response emitted after the first response. This delay sets the
* maximum amount of time to wait for it.
*
* @param dev Device context
* @param wait_ms The response delay to set, in milliseconds.
*/
void rn2903_set_response2_wait_time(const rn2903_context dev,
unsigned int wait_ms);
/**
* Determine whether there is data available to be read. This
* function will wait up to "millis" milliseconds for data to
* become available.
*
* @param dev Device context
* @param millis The number of milliseconds to wait for data to
* become available
* @return true if data is available to be read, false otherwise
*/
bool rn2903_data_available(const rn2903_context dev,
unsigned int millis);
/**
* Read and throw away any data currently available to be read.
* This is useful to avoid reading data that might have been the
* result of a previous command interfering with data you
* currently want to read.
*
* @param dev Device context
*/
void rn2903_drain(const rn2903_context dev);
/**
* Send a command, wait for a response using
* rn2903_waitfor_response(), and return the status. The response
* itself will be stored internally, and can be retrieved using
* rm2903_get_response() and rn2903_get_response_len(). Every
* command will return at least one response, and this function
* will always wait for it and store it after sending the command.
*
* @param dev Device context
* @param cmd A character string containing the command to
* send
* @return One of the RN2903_RESPONSE_T values
*/
RN2903_RESPONSE_T rn2903_command(const rn2903_context dev,
const char *cmd);
/**
* Build a command string with the supplied command and string
* argument. Then call rn2903_command() with the result, and
* return the result. This is just a convenience function.
*
* @param dev Device context
* @param cmd A character string containing the command to
* send
* @param arg A string argument for the command
* @return One of the RN2903_RESPONSE_T values
*/
RN2903_RESPONSE_T rn2903_command_with_arg(const rn2903_context dev,
const char *cmd,
const char *arg);
/**
* Wait up to wait_ms milliseconds for a response.
*
* In the case of errors ("invalid_param" received, timeout
* occurred, or other UPM specific error), this will be indicated
* by the return value.
*
* Otherwise, an "ok" or other data value will not be considered
* an error and will return RN2903_RESPONSE_OK. The response
* itself will be stored internally, and can be retrieved using
* rm2903_get_response() and rn2903_get_response_len().
*
* NOTE: the response buffer is overwritten whenever this function
* is called, so if there is data in there that you need to save,
* copy it somewhere else before calling any other functions in
* this driver to be safe.
*
* @param dev Device context
* @param wait_ms The maximum number of milliseconds to wait for a
* response.
* @return One of the RN2903_RESPONSE_T values
*/
RN2903_RESPONSE_T rn2903_waitfor_response(const rn2903_context dev,
int wait_ms);
/**
* Return a pointer to a string containing the last response. If
* you wish to save the response for later, you will need to copy
* it somewhere before calling rn2903_command(),
* rn2903_command_with_arg() or rn2903_waitfor_response(), as
* these functions will overwrite the internally stored response
* buffer each time they are called.
*
* @param dev Device context
* @return A const pointer to a string containing the last response.
*/
const char *rn2903_get_response(const rn2903_context dev);
/**
* Return the length in bytes of the string containing the last
* response. If you wish to save the response length for later,
* you will need to copy it somewhere before calling
* rn2903_command() or rn2903_waitfor_respnse(), as these
* functions will overwrite the internally stored response length
* each time they are called.
*
* @param dev Device context
* @return The length of the last response in bytes
*/
size_t rn2903_get_response_len(const rn2903_context dev);
/**
* Set the MAC device EUI for LoRaWAN communications. The device
* EUI must be a hex encoded string of 16 bytes. This value must
* be set for LoRaWAN OTAA joining.
*
* @param dev Device context
* @param str The 16-byte hex encoded device EUI
* @return UPM result
*/
upm_result_t rn2903_set_device_eui(const rn2903_context dev,
const char *str);
/**
* Retrieve the device EUI from the device. If this function
* succeeds, you can then use rn2903_get_response() to get the
* value.
*
* @param dev Device context
* @return UPM result
*/
upm_result_t rn2903_get_device_eui(const rn2903_context dev);
/**
* Set the MAC application EUI for LoRaWAN communications. The
* application EUI must be a hex encoded string of 16 bytes. This
* value must be set for LoRaWAN OTAA joining.
*
* @param dev Device context
* @param str The 16-byte hex encoded application EUI
* @return UPM result
*/
upm_result_t rn2903_set_application_eui(const rn2903_context dev,
const char *str);
/**
* Retrieve the application EUI from the device. If this function
* succeeds, you can then use rn2903_get_response() to get the
* value.
*
* @param dev Device context
* @return UPM result
*/
upm_result_t rn2903_get_application_eui(const rn2903_context dev);
/**
* Set the MAC application key for LoRaWAN communications. The
* application key must be a hex encoded string of 32 bytes. This
* value must be set for LoRaWAN OTAA joining.
*
* @param dev Device context
* @param str The 32-byte hex encoded application key
* @return UPM result
*/
upm_result_t rn2903_set_application_key(const rn2903_context dev,
const char *str);
/**
* Retrieve the application key from the device. If this function
* succeeds, you can then use rn2903_get_response() to get the
* value.
*
* @param dev Device context
* @return UPM result
*/
upm_result_t rn2903_get_application_key(const rn2903_context dev);
/**
* Set the MAC device address for LoRaWAN communications. The
* device address must be a hex encoded string of 8 bytes. This
* value must be set for LoRaWAN ABP joining.
*
* For OTAA joining, this value will be overwritten once the join
* has completed, and therefore must not be set if performing an
* OTAA join.
*
* @param dev Device context
* @param str The 8-byte hex encoded device address
* @return UPM result
*/
upm_result_t rn2903_set_device_addr(const rn2903_context dev,
const char *str);
/**
* Retrieve the device address from the device. If this function
* succeeds, you can then use rn2903_get_response() to get the
* value.
*
* @param dev Device context
* @return UPM result
*/
upm_result_t rn2903_get_device_addr(const rn2903_context dev);
/**
* Set the MAC network session key for LoRaWAN communications.
* The network session key must be a hex encoded string of 32
* bytes. This value must be set for LoRaWAN ABP joining. It it
* not possible to retrieve this key.
*
* For OTAA joining, this value will be overwritten once the join
* has completed, and therefore must not be set if performing an
* OTAA join.
*
* @param dev Device context
* @param str The 32-byte hex encoded network session key
* @return UPM result
*/
upm_result_t rn2903_set_network_session_key(const rn2903_context dev,
const char *str);
/**
* Set the MAC application session key for LoRaWAN communications.
* The application session key must be a hex encoded string of 32
* bytes. This value must be set for LoRaWAN ABP joining. It it
* not possible to retrieve this key.
*
* For OTAA joining, this value will be overwritten once the join
* has completed, and therefore must not be set if performing an
* OTAA join.
*
* @param dev Device context
* @param str The 32-byte hex encoded application session key
* @return UPM result
*/
upm_result_t rn2903_set_application_session_key(const rn2903_context dev,
const char *str);
/**
* Convert src into a hex byte string. All non-command related
* data such as keys, and payload sent to the device must be hex
* encoded. The buffers used for this conversion are managed
* internally, so do not call free() on the returned pointer. If
* you need to keep a copy of the resulting hex string, copy it
* somewhere before calling this function again.
*
* @param dev Device context
* @param src A char pointer pointing to the byte array to encode
* @param len The length in bytes of the data to encode
* @return A const pointer to the resulting hex string, or NULL if
* there was an error.
*/
const char *rn2903_to_hex(const rn2903_context dev,
const char *src, int len);
/**
* Convert a hex byte string into an array of bytes. The hex
* string must have a length (not including the 0 terminator) that
* is a multiple of two, and all characters in the string must be
* valid hex characters. The buffers used for this conversion are
* managed internally, so do not call free() on the returned
* pointer. If you need to keep a copy of the resulting data byte
* array, copy it somewhere before calling this function again.
* The length of the returned data will be the length of the hex
* source string divided by 2, with a 0 byte terminator at the end
* in case a text string is being decoded.
*
* @param dev Device context
* @return A const pointer to the resulting data string, or NULL if
* there was an error
*/
const char *rn2903_from_hex(const rn2903_context dev,
const char *src);
/**
* Join a LoRaWAN network. There are two types of joins possible
* - Over The Air Activation (OTAA) and Activation by
* Personalization (ABP). Each join method requires that certain
* items have been configured first.
*
* For OTAA activation, the Device Extended Unique Identifier
* (EUI), the Application EUI, and Application Key must be set.
*
* For ABP activation, The Device Address, Network Session Key,
* and the Application Session Key must be set.
*
* @param dev Device context
* @param type The LoRaWAN activation type, one of the
* RN2903_JOIN_TYPE_T values
* @return The status of the join, one of the RN2903_JOIN_STATUS_T
* values
*/
RN2903_JOIN_STATUS_T rn2903_join(const rn2903_context dev,
RN2903_JOIN_TYPE_T type);
/**
* Transmit a packet in a LoRaWAN network. You must
* already be joined to a LoRaWAN network for this command to
* succeed, and the MAC stack must be in the idle
* (RN2903_MAC_STAT_IDLE) state.
*
* The packet payload must be a valid 0-terminated hex encoded
* string.
*
* There is the possibility of receiving a downlink message after
* transmitting a packet. If this occurs, this function will
* return RN2903_MAC_TX_STATUS_RX_RECEIVED, and the returned data
* will be stored in the response buffer. NOTE: calling pretty
* much any function that issues commands to the device will
* overwrite the response buffer, so save a copy of it if you need
* it before calling other functions.
*
* @param dev Device context
* @param type The type of message to send - confirmed or
* unconfirmed. One of the RN2903_MAC_MSG_TYPE_T values.
* @param port An integer in the range 1-223
* @param payload A 0-terminated, hex encoded string that makes up
* the payload of the message
* @return The status of the transmit request, one of the
* RN2903_MAC_TX_STATUS_T values
*/
RN2903_MAC_TX_STATUS_T rn2903_mac_tx(const rn2903_context dev,
RN2903_MAC_MSG_TYPE_T type,
int port, const char *payload);
/**
* Transmit a packet. This method uses the radio directly without
* the LoRaWAN stack running. For this reason, you must call
* rn2903_mac_pause() before trying to transmit using this
* function. You should also configure any parameters (frequency,
* etc), before calling this function.
*
* @param dev Device context
* @param payload A 0-terminated, hex encoded string that makes up
* the payload of the message
* @return The status of the transmit request, one of the
* RN2903_RESPONSE_T values
*/
RN2903_RESPONSE_T rn2903_radio_tx(const rn2903_context dev,
const char *payload);
/**
* Receive a packet. This method uses the radio directly without
* the LoRaWAN stack running. For this reason, you must call
* rn2903_mac_pause() before trying to receive using this
* function. You should also configure any parameters (frequency,
* etc) to match the transmitter before calling this function.
*
* @param dev Device context
* @param window_size An integer that represents the number of
* symbols to wait for (lora) or the maximum number of
* milliseconds to wait (fsk). This parameter is passed to the "radio
* rx" command. Passing 0 causes the radio to enter continuous
* receive mode which will return when either a packet is
* received, or the radio watchdog timer expires. See the RN2903
* Command Reference for details.
* @return The status of the transmit request, one of the
* RN2903_RESPONSE_T values
*/
RN2903_RESPONSE_T rn2903_radio_rx(const rn2903_context dev,
int window_size);
/**
* Return the Hardware Extended Unique Identifier. The is a 16
* byte hex encoded string representing the 64b hardware EUI.
* This value cannot be changed, and is globally unique to each
* device. It is obtained from the device at initialization time.
*
* @param dev Device context
* @return A const string pointer to the hex encoded Hardware EUI
*/
const char *rn2903_get_hardware_eui(const rn2903_context dev);
/**
* Retrieve the device MAC status, decode it, and store it
* internally. This function must be called prior to calling
* rn2903_get_mac_status_word() or rn2903_get_mac_status().
*
* @param dev Device context
* @return UPM result
*/
upm_result_t rn2903_update_mac_status(const rn2903_context dev);
/**
* Retrieve the MAC status word. rn2903_update_mac_status() must
* have been called prior to calling this function.
*
* @param dev Device context
* @return The MAC status word. This is a bitmask of
* RN2903_MAC_STATUS_BITS_T bits.
*/
uint16_t rn2903_get_mac_status_word(const rn2903_context dev);
/**
* Retrieve the MAC status. rn2903_update_mac_status() must have
* been called prior to calling this function. The MAC status is
* a bitfield embedded in the mac_status_word. It provides
* information on the status of the internal MAC state machine.
*
* @param dev Device context
* @return The MAC status, one of the RN2903_MAC_STATUS_T values.
*/
RN2903_MAC_STATUS_T rn2903_get_mac_status(const rn2903_context dev);
/**
* Save the configurable device values to EEPROM. These values
* will be reloaded automatically on a reset or power up.
*
* The data that can be saved are: deveui, appeui, appkey, nwkskey
* (Network Session Key), appskey, devaddr, channels, upctr
* (Uplink Counter), dnctr (Downlink Counter), adr (automatic
* data-rate) state, and rx2 (the RX2 receive window parameters).
*
* @param dev Device context
* @return UPM result
*/
upm_result_t rn2903_mac_save(const rn2903_context dev);
/**
* Pause the MAC LoRaWAN stack. This device can operate in one of
* two modes.
*
* The most common mode is used to join and participate in a LoRaWAN
* network as a Class A End Device. This is handled by the MAC
* LoRaWAN stack on the device dealing with the details of
* LoRaWAN participation automatically.
*
* The other mode disables MAC LoRaWAN stack functionality and
* allows you to issue commands directly to the radio to set
* frequencies, data rates, modulation and many other parameters.
*
* Calling this function disables the MAC LoRaWAN stack and allows
* you to issue radio commands that are otherwise handled
* automatically.
*
* When pausing, the maximum allowable pause time in milliseconds
* will be returned in the response buffer. You can grab this
* value by calling rn2903_get_response() after this function
* completes successfully.
*
* When the MAC is idle (rn2903_get_mac_status()), you can pause
* indefinitely.
*
* @param dev Device context
* @return UPM result
*/
upm_result_t rn2903_mac_pause(const rn2903_context dev);
/**
* Resume the MAC LoRaWAN stack. Call this to resume MAC LoRaWAN
* operation after having called rn2903_mac_pause(), to resume
* participation in a LoRaWAN network.
*
* @param dev Device context
* @return UPM result
*/
upm_result_t rn2903_mac_resume(const rn2903_context dev);
/**
* Reset the device. Any configuration is lost, as well as
* the current join status. This method also calls
* rn2903_set_baudrate() after the reset to re-establish
* communications with the device in the event you are not
* using the default baudrate (which the device will revert to
* after a reset).
*
* @param dev Device context
* @return UPM result
*/
upm_result_t rn2903_reset(const rn2903_context dev);
/**
* LoRaWAN communications allows for the reporting of current
* battery charge remaining to the LoRaWAN gateway/network server.
* This function allows you to specify the value that should be
* reported.
*
* The valid values are from 0 to 255.
* 0 = using external power
* 1(low) to 254(high) = battery power
* 255 = unable to measure battery level
*
* @param dev Device context
* @param level The battery level value from 0-255
* @return UPM result
*/
upm_result_t rn2903_mac_set_battery(const rn2903_context dev, int level);
/**
* Enable debugging. If enabled, commands will be printed out
* before being sent to the device. Any responses will be printed
* out after retrieval. Other miscellaneous debug output will
* also be printed.
*
* @param dev Device context
* @param enable true to enable debugging, false otherwise
*/
void rn2903_set_debug(const rn2903_context dev, bool enable);
/**
* Read character data from the device
*
* @param dev Device context
* @param buffer The character buffer to read data into
* @param len The maximum size of the buffer
* @return The number of bytes successfully read, or -1 on error
*/
int rn2903_read(const rn2903_context dev, char *buffer, size_t len);
/**
* Write character data to the device
*
* @param dev Device context
* @param buffer The character buffer containing data to write
* @param len The number of bytes to write
* @return The number of bytes successfully written, or -1 on error
*/
int rn2903_write(const rn2903_context dev, const char *buffer, size_t len);
/**
* Set the baudrate of the device. Auto-bauding is currently only
* supported on Linux (due to the need to send a break signal) and
* only on a recent MRAA which supports it (> 1.6.1). If on a
* non-linux OS, you should not try to change the baudrate to
* anything other than the default 57600 or you will lose control
* of the device.
*
* @param dev Device context
* @param baudrate The baud rate to set for the device
* @return UPM result
*/
upm_result_t rn2903_set_baudrate(const rn2903_context dev,
unsigned int baudrate);
/**
* Set a flow control method for the UART. By default, during
* initialization, flow control is disabled. The device MAY
* support hardware flow control, but MRAA does not (at least for
* UART numbers), so we can't either. We leave the option here
* though so that if you are using a TTY (as opposed to a UART
* instance) it might work if the device is also configured to use
* hardware flow control.
*
* @param dev Device context
* @param fc One of the RN2903_FLOW_CONTROL_T values
* @return the UPM result
*/
upm_result_t rn2903_set_flow_control(const rn2903_context dev,
RN2903_FLOW_CONTROL_T fc);
/**
* This is a utility function that can be used to indicate if a
* given string is present at the beginning of the response
* buffer. The search is case sensitive.
*
* @param dev Device context
* @param str The 0 teminated string to search for
* @return true if the string was found at the beginning of the
* response buffer, false otherwise
*/
bool rn2903_find(const rn2903_context dev, const char *str);
/**
* This is a utility function that can be used to return a pointer
* to the location in the response buffer where the hex encoded
* payload starts for radio_rx messages received.
*
* @param dev Device context
* @return A pointer to the start of the hex payload in the
* response buffer, or NULL if the response buffer does not
* contain a radio_rx sentence.
*/
const char *rn2903_get_radio_rx_payload(const rn2903_context dev);
/**
* This function attempts to sync the device to the current
* baudrate. It tries retries times, to send an autobaud
* sequence to the device and run a test command.
*
* @param dev Device context
* @param retries The number of times to retry autobaud detection
* @return true if the test command succeeded, false otherwise
*/
bool rn2903_autobaud(const rn2903_context dev, int retries);
#ifdef __cplusplus
}
#endif

636
src/rn2903/rn2903.hpp Normal file
View File

@ -0,0 +1,636 @@
/*
* Author: Jon Trulson <jtrulson@ics.com>
* Copyright (c) 2017 Intel Corporation.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in 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:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* 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 AUTHORS 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 IN THE SOFTWARE.
*/
#pragma once
#include <string>
#include <iostream>
#include "rn2903.h"
namespace upm {
/**
* @brief API for the Microchip RN2903 LoRa radio
* @defgroup rn2903 libupm-rn2903
* @ingroup uart wifi
*/
/**
* @library rn2903
* @sensor rn2903
* @comname Microchip RN2903 LoRa radio
* @type wifi
* @con uart
* @snippet rn2903.cxx Interesting
* @snippet rn2903-p2p-tx.cxx Interesting
* @snippet rn2903-p2p-rx.cxx Interesting
*
* @brief API for the Microchip RN2903 LoRa radio
*
* Microchips RN2903 Low-Power Long Range LoRa Technology
* Transceiver module provides an easy to use, low-power solution
* for long range wireless data transmission. The advanced command
* interface offers rapid time to market.
*
* The RN2903 module complies with the LoRaWAN Class A protocol
* specifications. It integrates RF, a baseband controller, and a
* command Application Programming Interface (API) processor,
* making it a complete long range solution.
*
* Most of the effort in this driver has been geared to supporting
* operation within a LoRaWAN network, however methods are
* provided to allow you to control the device directly so that
* you can implement whatever solution you require.
*/
class RN2903 {
public:
/**
* RN2903 object constructor for a UART specified by MRAA number.
*
* @param uart Specify which uart to use.
* @param baudrate Specify the baudrate to use. The default
* is 57600.
*/
RN2903(unsigned int uart,
unsigned int baudrate=RN2903_DEFAULT_BAUDRATE);
/**
* RN2903 object constructor for a UART specified by PATH (ex:
* /dev/ttyUSB0)
*
* @param uart_path Specify path of UART device.
* @param baudrate Specify the baudrate to use. The default
* is 57600.
*/
RN2903(std::string uart_path,
unsigned int baudrate=RN2903_DEFAULT_BAUDRATE);
/**
* RN2903 object destructor
*/
virtual ~RN2903();
/**
* Set the default time, in milliseconds, to wait for a response
* after sending a command. All commands return at least one
* response immediately after issuing the command. This delay
* sets the maximum amount of time to wait for it.
*
* @param wait_ms The response delay to set, in milliseconds.
* The default is 1 second (1000ms).
*/
void setResponseWaitTime(
unsigned int wait_ms=RN2903_DEFAULT_RESP_DELAY);
/**
* Set the default time, in milliseconds, to wait for the second
* response data to arrive. Some commands will have a second
* response emitted after the first response. This delay sets the
* maximum amount of time to wait for it.
*
* @param wait_ms The response delay to set, in milliseconds.
* The default is 60 seconds (60000ms).
*/
void setResponse2WaitTime(
unsigned int wait_ms=RN2903_DEFAULT_RESP2_DELAY);
/**
* Determine whether there is data available to be read. This
* function will wait up to "millis" milliseconds for data to
* become available.
*
* @param millis The number of milliseconds to wait for data to
* become available.
* @return true if data is available to be read, false otherwise.
*/
bool dataAvailable(unsigned int millis);
/**
* Read and throw away any data currently available to be
* read. This is useful to avoid reading data that might have
* been the result of a previous command interfering with data
* you currently want to read.
*/
void drain();
/**
* Send a command, wait for a response using
* waitForResponse(), and return the status. The response
* itself will be stored internally, and can be retrieved
* using getResponse() and getResponseLen(). Every command
* will return at least one response, and this function will
* always wait for it and store it into the internal response
* buffer after sending the command.
*
* @param cmd A character string containing the command to
* send
* @return One of the RN2903_RESPONSE_T values
*/
RN2903_RESPONSE_T command(const std::string cmd);
/**
* Build a command string with the supplied command and string
* argument. Then call command() with the result, and
* return the result. This is just a convenience function.
*
* @param cmd A character string containing the command to
* send
* @param arg A string argument for the command
* @return One of the RN2903_RESPONSE_T values
*/
RN2903_RESPONSE_T commandWithArg(const std::string cmd,
const std::string arg);
/**
* Wait up to wait_ms milliseconds for a response.
*
* In the case of errors ("invalid_param" received, timeout
* occurred, or other UPM specific error), this will be indicated
* by the return value.
*
* Otherwise, an "ok" or other data value will not be considered
* an error and will return RN2903_RESPONSE_OK. The response
* itself will be stored internally, and can be retrieved using
* getResponse() and getResponseLen().
*
* NOTE: the response buffer is overwritten whenever this function
* is called, so if there is data in there that you need to save,
* copy it somewhere else before calling any other methods in
* this driver to be safe.
*
* @param wait_ms The maximum number of milliseconds to wait for a
* response.
* @return One of the RN2903_RESPONSE_T values
*/
RN2903_RESPONSE_T waitForResponse(int wait_ms);
/**
* Return a string containing a copy of the last response
* saved in the response buffer
*
* @return A string containing a copy of the response buffer
*/
std::string getResponse();
/**
* Return the length in bytes of the string containing the
* last response.
*
* @return The length of the last response in bytes
*/
int getResponseLen();
/**
* Set the MAC device EUI for LoRaWAN communications. The device
* EUI must be a hex encoded string of 16 bytes. This value must
* be set for LoRaWAN OTAA joining.
*
* @param str The 16-byte hex encoded device EUI
* @throws std::runtime_error if the EUI is invalid or the mac
* set command failed
*/
void setDeviceEUI(const std::string str);
/**
* Retrieve the device EUI from the device. If this function
* succeeds, you can then use getResponse() to get the value.
*
* @return UPM result
* @throws std::runtime_error if the mac get command failed
*/
void getDeviceEUI();
/**
* Set the MAC device address for LoRaWAN communications. The
* device address must be a hex encoded string of 8 bytes. This
* value must be set for LoRaWAN ABP joining.
*
* For OTAA joining, this value will be overwritten once the join
* has completed, and therefore must not be set if performing an
* OTAA join.
*
* @param str The 8-byte hex encoded device address
* @throws std::runtime_error if the mac set command failed or
* the hex string is invalid
*/
void setDeviceAddr(std::string str);
/**
* Retrieve the device address from the device. If this
* function succeeds, you can then use getResponse() to get
* the value.
*
* @throws std::runtime_error if the mac get failed
*/
void getDeviceAddr();
/**
* Set the MAC network session key for LoRaWAN communications.
* The network session key must be a hex encoded string of 32
* bytes. This value must be set for LoRaWAN ABP joining. It it
* not possible to retrieve this key.
*
* For OTAA joining, this value will be overwritten once the join
* has completed, and therefore must not be set if performing an
* OTAA join.
*
* @param str The 32-byte hex encoded network session key
* @throws std::runtime_error if the mac set command failed or
* the hex string is invalid
*/
void setNetworkSessionKey(std::string str);
/**
* Set the MAC application session key for LoRaWAN communications.
* The application session key must be a hex encoded string of 32
* bytes. This value must be set for LoRaWAN ABP joining. It it
* not possible to retrieve this key.
*
* For OTAA joining, this value will be overwritten once the join
* has completed, and therefore must not be set if performing an
* OTAA join.
*
* @param str The 32-byte hex encoded application session key
* @throws std::runtime_error if the mac set command failed or
* the hex string is invalid
*/
void setApplicationSessionKey(std::string str);
/**
* Set the MAC application EUI for LoRaWAN communications. The
* application EUI must be a hex encoded string of 16 bytes. This
* value must be set for LoRaWAN OTAA joining.
*
* @param str The 16-byte hex encoded application EUI
* @throws std::runtime_error if the EUI is invalid, or if the
* mac set command failed
*/
void setApplicationEUI(const std::string str);
/**
* Retrieve the application EUI from the device. If this
* function succeeds, you can then use getResponse() to get
* the value.
*
* @throws std::runtime_error if the mac get command failed
*/
void getApplicationEUI();
/**
* Set the MAC application key for LoRaWAN communications.
* The application key must be a hex encoded string of 32
* bytes. This value must be set for LoRaWAN OTAA joining.
*
* @param str The 32-byte hex encoded application key
* @throws std::runtime_error if the key is invalid, or if the
* mac set command failed
*/
void setApplicationKey(const std::string str);
/**
* Retrieve the application key from the device. If this function
* succeeds, you can then use rn2903_get_response() to get the
* value.
*
* @throws std::runtime_error if the mac get command failed
*/
void getApplicationKey();
/**
* Convert src into a hex byte string. All non-command
* related data such as keys, and payload sent to the device
* must be hex encoded.
*
* @param src A string to encode
* @return A string containing the hex encoded version of str.
* In the event of an error, the return string will be empty.
*/
std::string toHex(const std::string src);
/**
* Decode a hex byte string into the original string. The hex
* string must have a length that is a multiple of two, and
* all characters in the string must be valid hex characters.
*
* @return A string containing the decoded contents of the hex
* string passed, or an empty string if there was an error.
*/
std::string fromHex(const std::string src);
/**
* Join a LoRaWAN network. There are two types of joins
* possible - Over The Air Activation (OTAA) and Activation by
* Personalization (ABP). Each join method requires that
* certain items have been configured first.
*
* For OTAA activation, the Device Extended Unique Identifier
* (EUI), the Application EUI, and Application Key must be
* set.
*
* For ABP activation, The Device Address, Network Session
* Key, and the Application Session Key must be set.
*
* @param type The LoRaWAN join activation type, one of the
* RN2903_JOIN_TYPE_T values
* @return The status of the join, one of the RN2903_JOIN_STATUS_T
* values
*/
RN2903_JOIN_STATUS_T join(RN2903_JOIN_TYPE_T type);
/**
* Transmit a packet in a LoRaWAN network. You must
* already be joined to a LoRaWAN network for this command to
* succeed, and the MAC stack must be in the idle
* (RN2903_MAC_STAT_IDLE) state.
*
* The packet payload must be a valid hex encoded string.
*
* There is the possibility of receiving a downlink message after
* transmitting a packet. If this occurs, this function will
* return RN2903_MAC_TX_STATUS_RX_RECEIVED, and the returned data
* will be stored in the response buffer.
*
* @param type The type of message to send - confirmed or
* unconfirmed. One of the RN2903_MAC_MSG_TYPE_T values.
* @param port An integer in the range 1-223
* @param payload A valid hex encoded string that makes up the
* payload of the message
* @return The status of the transmit request, one of the
* RN2903_MAC_TX_STATUS_T values
*/
RN2903_MAC_TX_STATUS_T macTx(RN2903_MAC_MSG_TYPE_T type,
int port, std::string payload);
/**
* Transmit a packet. This method uses the radio directly
* without the LoRaWAN stack running. For this reason, you
* must call macPause() before trying to transmit using this
* function. You should also configure any radio parameters
* (frequency, etc), before calling this function.
*
* @param payload A valid hex encoded string that makes up
* the payload of the message
* @return The status of the transmit request, one of the
* RN2903_RESPONSE_T values
*/
RN2903_RESPONSE_T radioTx(const std::string payload);
/**
* Receive a packet. This method uses the radio directly
* without the LoRaWAN stack running. For this reason, you
* must call macPause() before trying to receive using this
* function. You should also configure any parameters
* (frequency, etc) to match the transmitter before calling
* this function.
*
* @param window_size An integer that represents the number of
* symbols to wait for (lora) or the maximum number of
* milliseconds to wait (fsk). This parameter is passed to
* the "radio rx" command. Passing 0 causes the radio to
* enter continuous receive mode which will return when either
* a packet is received, or the radio watchdog timer expires.
* See the RN2903 Command Reference for details.
* @return The status of the transmit request, one of the
* RN2903_RESPONSE_T values
*/
RN2903_RESPONSE_T radioRx(int window_size);
/**
* Return the Hardware Extended Unique Identifier (EUI). The
* is a 16 byte hex encoded string representing the 64b
* hardware EUI. This value cannot be changed, and is
* globally unique to each device. It is obtained from the
* device at initialization time.
*
* @return A const string pointer to the hex encoded Hardware EUI
*/
std::string getHardwareEUI();
/**
* Retrieve the device MAC status, decode it, and store it
* internally. This function must be called prior to calling
* getMacStatusWord() or getMacStatus().
*
* @throws std::runtime_error if the mac get command failed
*/
void updateMacStatus();
/**
* Retrieve the MAC status word. updateMacStatus() must have
* been called prior to calling this function.
*
* @return The MAC status word. This is a bitmask of
* RN2903_MAC_STATUS_BITS_T bits.
*/
int getMacStatusWord();
/**
* Retrieve the MAC status. updateMacStatus() must have been
* called prior to calling this function. The MAC status is a
* bitfield embedded in the mac status word. It provides
* information on the status of the internal MAC state
* machine.
*
* @return The MAC status, one of the RN2903_MAC_STATUS_T values.
*/
RN2903_MAC_STATUS_T getMacStatus();
/**
* Save the configurable device values to EEPROM. These
* values will be reloaded automatically on a reset or power
* up.
*
* The data that can be saved are: deveui, appeui, appkey,
* nwkskey (Network Session Key), appskey, devaddr, channels,
* upctr (Uplink Counter), dnctr (Downlink Counter), adr
* (automatic data-rate) state, and rx2 (the RX2 receive
* window parameters).
*
* @throws std::runtime_error if the mac save command failed
*/
void macSave();
/**
* Pause the MAC LoRaWAN stack. This device can operate in
* one of two modes.
*
* The most common mode is used to join and participate in a
* LoRaWAN network as a Class A End Device. This is handled
* by the MAC LoRaWAN stack on the device dealing with the
* details of LoRaWAN participation automatically.
*
* The other mode disables MAC LoRaWAN stack functionality and
* allows you to issue commands directly to the radio to set
* frequencies, data rates, modulation and many other
* parameters.
*
* Calling this function disables the MAC LoRaWAN stack and
* allows you to issue radio commands that are otherwise
* handled automatically.
*
* When pausing, the maximum allowable pause time in
* milliseconds will be returned in the response buffer. You
* can grab this value by calling getResponse() after this
* function completes successfully.
*
* When the MAC is idle (getMacStatus()), you can pause
* the stack indefinitely.
*
* @throws std::runtime_error if the mac pause command failed
*/
void macPause();
/**
* Resume the MAC LoRaWAN stack. Call this to resume MAC
* LoRaWAN operation after having called macPause(), to resume
* participation in a LoRaWAN network.
*
* @param dev Device context
* @return UPM result
* @throws std::runtime_error if the mac resume command failed
*/
void macResume();
/**
* Reset the device. Any configuration is lost, as well as
* the current join status. This method also calls
* setBaudrate() after the reset to re-establish
* communications with the device in the event you are not
* using the default baudrate (which the device will revert to
* after a reset).
*
* @throws std::runtime_error if the mac reset, or
* setBaudrate() command fails
*/
void reset();
/**
* LoRaWAN communications allows for the reporting of current
* battery charge remaining to the LoRaWAN gateway/network server.
* This function allows you to specify the value that should be
* reported.
*
* The valid values are from 0 to 255.
* 0 = using external power
* 1(low) to 254(high) = battery power
* 255 = unable to measure battery level
*
* @param level The battery level value from 0-255
* @throws std::runtime_error if the mac set bat command
* failed, or if the battery level is invalid
*/
void macSetBattery(int level);
/**
* Enable debugging. If enabled, commands will be printed out
* before being sent to the device. Any responses will be printed
* out after retrieval. Other miscellaneous debug output will
* also be printed.
*
* @param enable true to enable debugging, false otherwise
*/
void setDebug(bool enable);
/**
* Set the baudrate of the device. Auto-bauding is currently only
* supported on Linux (due to the need to send a break signal) and
* only on a recent MRAA which supports it (> 1.6.1). If on a
* non-linux OS, you should not try to change the baudrate to
* anything other than the default 57600 or you will lose control
* of the device.
*
* @param baudrate The baud rate to set for the device
* @throws std::runtime_error if the autobaud test command failed
*/
void setBaudrate(unsigned int baudrate);
/**
* Set a flow control method for the UART. By default, during
* initialization, flow control is disabled. The device MAY
* support hardware flow control, but MRAA does not (at least for
* UART numbers), so we can't either. We leave the option here
* though so that if you are using a TTY (as opposed to a UART
* instance) it might work if the device is also configured to use
* hardware flow control.
*
* @param fc One of the RN2903_FLOW_CONTROL_T values
* @throws std::runtime_error on failure
*/
void setFlowControl(RN2903_FLOW_CONTROL_T fc);
/**
* This is a utility function that can be used to indicate if a
* given string is present at the beginning of the response
* buffer. The search is case sensitive.
*
* @param str The string to search for
* @return true if the string was found at the beginning of the
* response buffer, false otherwise
*/
bool find(const std::string str);
/**
* This is a utility function that can be used to return the
* hex encoded payload string for radio_rx messages received.
*
* @return A string representing the hex encoded payload, or
* an empty string if there was an error
*/
std::string getRadioRxPayload();
/**
* This function attempts to sync the device to the current
* baudrate. It tries retries times, to send an autobaud
* sequence to the device and run a test command.
*
* @param retries The number of times to retry autobaud detection
* @return true if the test command succeeded, false otherwise
*/
bool autobaud(int retries);
protected:
// rn2903 device context
rn2903_context m_rn2903;
/**
* Read character data from the device
*
* @param size The maximum number of characters to read
* @return string containing the data read
*/
std::string read(int size);
/**
* Write character data to the device
*
* @param buffer The string containing the data to write
* @return The number of bytes written
*/
int write(std::string buffer);
private:
};
}

147
src/rn2903/rn2903_defs.h Normal file
View File

@ -0,0 +1,147 @@
/*
* Author: Jon Trulson <jtrulson@ics.com>
* Copyright (c) 2017 Intel Corporation.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in 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:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* 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 AUTHORS 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 IN THE SOFTWARE.
*/
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
// maximum buffer size
#define RN2903_MAX_BUFFER (512)
// size of hex encoded 64b EUI (IPV6 Extended Unique Identifier)
#define RN2903_MAX_HEX_EUI64 (16)
// default baudrate
#define RN2903_DEFAULT_BAUDRATE (57600)
// response wait times in milliseconds
#define RN2903_DEFAULT_RESP_DELAY (1000) // 1 second
#define RN2903_DEFAULT_RESP2_DELAY (60000) // 60 seconds
// This byte sequence must follow all commands. All responses
// will also be followed by these bytes (\r\n - CR LF).
#define RN2903_PHRASE_TERM "\r\n"
#define RN2903_PHRASE_TERM_LEN (2)
// invalid parameter
#define RN2903_PHRASE_INV_PARAM "invalid_param"
// ok
#define RN2903_PHRASE_OK "ok"
// RN2903_MAC_STATUS_BITS_T from "mac get status" cmd
typedef enum {
RN2903_MAC_STATUS_JOINED = 0x0001,
RN2903_MAC_STATUS_MAC_STATUS0 = 0x0002,
RN2903_MAC_STATUS_MAC_STATUS1 = 0x0004,
RN2903_MAC_STATUS_MAC_STATUS2 = 0x0008,
_RN2903_MAC_STATUS_MAC_STATUS_MASK = 7,
_RN2903_MAC_STATUS_MAC_STATUS_SHIFT = 1,
RN2903_MAC_STATUS_AUTO_REPLY = 0x0010,
RN2903_MAC_STATUS_ADR = 0x0020,
RN2903_MAC_STATUS_SILENT = 0x0040,
RN2903_MAC_STATUS_PAUSED = 0x0080,
RN2903_MAC_STATUS_RFU = 0x0100,
RN2903_MAC_STATUS_LINK_CHK = 0x0200,
RN2903_MAC_STATUS_CHAN_UPD = 0x0400,
RN2903_MAC_STATUS_OUT_PWR_UPD = 0x0800,
RN2903_MAC_STATUS_NBREP_UPD = 0x1000,
RN2903_MAC_STATUS_PRESCALER_UPD = 0x2000,
RN2903_MAC_STATUS_SECOND_RX_UPD = 0x4000,
RN2903_MAC_STATUS_TX_TIMING_UPD = 0x8000,
} RN2903_MAC_STATUS_BITS_T;
// RN2903_MAC_STATUS_MAC_STATUS values
typedef enum {
RN2903_MAC_STAT_IDLE = 0,
RN2903_MAC_STAT_TX_IN_PROGESS = 1,
RN2903_MAC_STAT_BEFORE_RX_WIN1 = 2,
RN2903_MAC_STAT_RX_WIN1_OPEN = 3,
RN2903_MAC_STAT_BETWEEN_RX_WIN1_WIN2 = 4,
RN2903_MAC_STAT_RX_WIN2_OPEN = 5,
RN2903_MAC_STAT_ACK_TIMEOUT = 6,
} RN2903_MAC_STATUS_T;
// Join types
typedef enum {
RN2903_JOIN_TYPE_OTAA = 0, // over-the-air-activation
RN2903_JOIN_TYPE_ABP = 1, // activation-by
// personalization
} RN2903_JOIN_TYPE_T;
// Join status
typedef enum {
RN2903_JOIN_STATUS_ACCEPTED = 0,
RN2903_JOIN_STATUS_BAD_KEYS = 1,
RN2903_JOIN_STATUS_NO_CHAN = 2,
RN2903_JOIN_STATUS_SILENT = 3,
RN2903_JOIN_STATUS_BUSY = 4,
RN2903_JOIN_STATUS_MAC_PAUSED = 5,
RN2903_JOIN_STATUS_DENIED = 6,
RN2903_JOIN_STATUS_ALREADY_JOINED = 7,
RN2903_JOIN_STATUS_UPM_ERROR = 8,
} RN2903_JOIN_STATUS_T;
// possible flow control methods
typedef enum {
RN2903_FLOW_CONTROL_NONE = 0,
RN2903_FLOW_CONTROL_HARD, // hardware flow control
} RN2903_FLOW_CONTROL_T;
// MAC TX message types
typedef enum {
RN2903_MAC_MSG_TYPE_UNCONFIRMED = 0,
RN2903_MAC_MSG_TYPE_CONFIRMED = 1,
} RN2903_MAC_MSG_TYPE_T;
// MAC TX status
typedef enum {
RN2903_MAC_TX_STATUS_TX_OK = 0, // tx was sent successfully
RN2903_MAC_TX_STATUS_NOT_JOINED = 1,
RN2903_MAC_TX_STATUS_NO_CHAN = 2,
RN2903_MAC_TX_STATUS_SILENT = 3,
RN2903_MAC_TX_STATUS_FC_NEED_REJOIN = 4, // frame counter overflow
RN2903_MAC_TX_STATUS_BUSY = 5,
RN2903_MAC_TX_STATUS_MAC_PAUSED = 6,
RN2903_MAC_TX_STATUS_BAD_DATA_LEN = 7,
RN2903_MAC_TX_STATUS_RX_RECEIVED = 8, // received a packet
RN2903_MAC_TX_STATUS_MAC_ERR = 9, // error during tx
RN2903_MAC_TX_STATUS_UPM_ERROR = 10, // error during tx
} RN2903_MAC_TX_STATUS_T;
// last command status
typedef enum {
RN2903_RESPONSE_OK = 0, // "ok", or data
RN2903_RESPONSE_INVALID_PARAM = 1, // "invalid_param"
RN2903_RESPONSE_TIMEOUT = 3,
RN2903_RESPONSE_UPM_ERROR = 4,
} RN2903_RESPONSE_T;
#ifdef __cplusplus
}
#endif